You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
691 lines
17 KiB
691 lines
17 KiB
/*
|
|
* Infparse.c - Setup.inf parsing code.
|
|
* Clark Cyr, Mike Colee, Todd Laney
|
|
* Copyright (C) Microsoft, 1989
|
|
* March 15, 1989
|
|
*
|
|
* Modification History:
|
|
*
|
|
* 3/15/89 CC Clark wrote this code for control Panel. This is windows
|
|
* code.
|
|
*
|
|
* 3/20/89 MC Decided this code would work for Dos and windows portion
|
|
* of setup. take out windows specifc stuff like local alloc's
|
|
* and dialog stuff. Replace it with standard C run time calls.
|
|
*
|
|
* 3/24/89 Toddla TOTAL rewrite! nothing is the same any more.
|
|
*
|
|
* 6/29/89 MC fixed getprofilestring func to not strip quotes if more
|
|
* than one field exists.
|
|
*/
|
|
|
|
#include <windows.h>
|
|
#include <mmsystem.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include "drivers.h"
|
|
#include "sulib.h"
|
|
|
|
/*** hack. to avoid realloc problems we make READ_BUFSIZE
|
|
as big as the inf file, thus avoiding any reallocs */
|
|
|
|
#define READ_BUFSIZE 27000 /* size of inf buffer */
|
|
#define TMP_BUFSIZE 1024 /* size of temp reads */
|
|
|
|
#define EOF 0x1A
|
|
#define ISEOL(c) ((c) == '\n' || (c) == '\r' || (c) == '\0' || (c) == EOF)
|
|
#define ISSEP(c) ((c) == '=' || (c) == ',')
|
|
#define ISWHITE(c) ((c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r')
|
|
#define ISNOISE(c) ((c) == '"')
|
|
|
|
#define QUOTE '"'
|
|
#define EQUAL '='
|
|
|
|
PINF pinfDefault = NULL;
|
|
|
|
static LPSTR pBuf;
|
|
static PINF pInf;
|
|
static UINT iBuf;
|
|
static UINT iInf;
|
|
|
|
/* Globaly used pointers to non-translatable text strings. */
|
|
|
|
extern TCHAR *pszPATH;
|
|
|
|
/* Local prototypes */
|
|
|
|
BOOL multifields(PINF);
|
|
|
|
|
|
static TCHAR GETC(int fh)
|
|
{
|
|
register UINT n;
|
|
|
|
if (!pBuf)
|
|
return EOF;
|
|
|
|
n = iBuf % TMP_BUFSIZE;
|
|
|
|
if (n == 0)
|
|
{
|
|
_lread(fh,pBuf,TMP_BUFSIZE);
|
|
}
|
|
iBuf++;
|
|
return pBuf[n];
|
|
}
|
|
|
|
static void PUTC(TCHAR c)
|
|
{
|
|
if (!pInf)
|
|
return;
|
|
|
|
pInf[iInf++] = c;
|
|
}
|
|
|
|
static void MODIFYC(TCHAR c)
|
|
{
|
|
if (!pInf)
|
|
return;
|
|
|
|
pInf[iInf++ - 1] = c;
|
|
}
|
|
|
|
static TCHAR LASTC(void) {
|
|
if (!pInf) return ' ';
|
|
|
|
if (iInf == 0) {
|
|
return ' ';
|
|
}
|
|
return pInf[iInf - 1];
|
|
}
|
|
|
|
/* int infLoadFile() Load a entire INF file into memory
|
|
* comments are removed, each line is terminated
|
|
* by a \0 each section is terminated by a \0\0
|
|
* ONLY spaces inside of " " are preserved
|
|
* the end of file is marked with a ^Z
|
|
*
|
|
* RETURNS: A pointer to a block of memory containg file, NULL if failure
|
|
*
|
|
*/
|
|
PINF infLoadFile(int fh)
|
|
{
|
|
UINT len;
|
|
TCHAR c;
|
|
BOOL fQuote = FALSE;
|
|
BOOL inSectionName = FALSE;
|
|
|
|
if (fh == -1)
|
|
return NULL;
|
|
|
|
len = (UINT)_llseek(fh,0L,SEEK_END);
|
|
|
|
_llseek(fh,0L,SEEK_SET);
|
|
|
|
iBuf = 0;
|
|
iInf = 0;
|
|
pBuf = ALLOC(TMP_BUFSIZE); // temp buffer
|
|
if (!pBuf)
|
|
return NULL;
|
|
pInf = FALLOC(len*sizeof(TCHAR)); // destination, at least as big as file
|
|
if (!pInf) {
|
|
FREE((HANDLE)pBuf);
|
|
return NULL;
|
|
}
|
|
|
|
while (iBuf < len)
|
|
{
|
|
c = GETC(fh);
|
|
loop:
|
|
if (iBuf >= len)
|
|
break;
|
|
|
|
switch (c)
|
|
{
|
|
case TEXT('['):
|
|
inSectionName = TRUE;
|
|
PUTC(c);
|
|
break;
|
|
|
|
case TEXT(']'):
|
|
if (inSectionName) {
|
|
if (LASTC() == TEXT(' ')) {
|
|
MODIFYC(c);
|
|
} else {
|
|
PUTC(c);
|
|
}
|
|
inSectionName = FALSE;
|
|
} else {
|
|
PUTC(c);
|
|
}
|
|
break;
|
|
|
|
case TEXT('\r'): /* ignore '\r' */
|
|
break;
|
|
|
|
case TEXT('\n'):
|
|
for (; ISWHITE(c); c = GETC(fh))
|
|
;
|
|
if (c != TEXT(';'))
|
|
PUTC(0); /* all lines end in a \0 */
|
|
|
|
if (c == TEXT('[')) {
|
|
PUTC(0); /* all sections end with \0\0 */
|
|
}
|
|
|
|
fQuote = FALSE;
|
|
goto loop;
|
|
break;
|
|
|
|
case TEXT('\t'):
|
|
case TEXT(' '):
|
|
if (inSectionName) {
|
|
if (LASTC() != TEXT(' ') && LASTC() != TEXT(']'))
|
|
PUTC(TEXT(' '));
|
|
} else {
|
|
if (fQuote)
|
|
PUTC(c);
|
|
}
|
|
break;
|
|
|
|
case TEXT('"'):
|
|
fQuote = !fQuote;
|
|
PUTC(c);
|
|
break;
|
|
|
|
case TEXT(';'):
|
|
for (; !ISEOL(c); c = GETC(fh))
|
|
;
|
|
goto loop;
|
|
break;
|
|
|
|
default:
|
|
PUTC(c);
|
|
break;
|
|
}
|
|
}
|
|
|
|
PUTC(0);
|
|
PUTC(0);
|
|
PUTC(EOF);
|
|
FREE((HANDLE)pBuf);
|
|
|
|
// try to shrink this block
|
|
|
|
|
|
// just leave pInf it's original size. don't bother shrinking it
|
|
|
|
return pInf;
|
|
}
|
|
|
|
/* PINF FAR PASCAL infOpen()
|
|
* PARAMETERS
|
|
* szInf - path to inf file to open and load
|
|
*
|
|
* RETURNS: A pointer to the parsed inf file if successful,
|
|
* Null pointer in the case of failure.
|
|
*
|
|
* ENTER:
|
|
* EXIT: To caller
|
|
*/
|
|
|
|
PINF infOpen(LPTSTR szInf)
|
|
{
|
|
TCHAR szBuf[MAX_PATH];
|
|
int fh;
|
|
PINF pinf;
|
|
|
|
fh = -1;
|
|
|
|
if (szInf == NULL)
|
|
szInf = szSetupInf;
|
|
|
|
/*
|
|
* Next try to open passed parameter as is. For Dos half.
|
|
*/
|
|
if (fh == -1)
|
|
{
|
|
fh = HandleToUlong(CreateFile(szInf, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
|
|
}
|
|
/*
|
|
* Next try destination path\system32. for win half.
|
|
*/
|
|
if (fh == -1) {
|
|
lstrcpy(szBuf, szSetupPath);
|
|
catpath(szBuf, TEXT("system32"));
|
|
catpath(szBuf, szInf);
|
|
fh = HandleToUlong(CreateFile(szBuf, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
|
|
}
|
|
/*
|
|
* Next try destination path. for initial setup.
|
|
*/
|
|
if (fh == -1) {
|
|
lstrcpy(szBuf, szSetupPath);
|
|
catpath(szBuf, szInf);
|
|
fh = HandleToUlong(CreateFile(szBuf, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
|
|
}
|
|
if (fh != -1)
|
|
{
|
|
pinf = infLoadFile(fh);
|
|
_lclose(fh);
|
|
|
|
if (pinf && !pinfDefault)
|
|
pinfDefault = pinf;
|
|
|
|
return pinf;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/* void FAR PASCAL infClose(PINF pinf)
|
|
*
|
|
* ENTER:
|
|
* EXIT: To caller
|
|
*/
|
|
void infClose(PINF pinf)
|
|
{
|
|
if (pinf == NULL)
|
|
pinf = pinfDefault;
|
|
|
|
if (pinf != NULL)
|
|
{
|
|
FFREE(pinf);
|
|
|
|
if (pinf == pinfDefault)
|
|
pinfDefault = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
/* FindSection locates a section in Setup.Inf. Sections are
|
|
* assumed to be delimited by a '[' as the first
|
|
* character on a line.
|
|
*
|
|
* Arguments: pInf Pointer to SETUP.INF buffer
|
|
* pszSect LPTSTR to section name
|
|
*
|
|
* Return: UINT file position of the first line in the section
|
|
* 0 if section not found
|
|
*/
|
|
|
|
UINT_PTR FindSection(PINF pInf, LPTSTR pszSect)
|
|
{
|
|
BOOL fFound = FALSE;
|
|
int nLen = lstrlen(pszSect);
|
|
PINF pch;
|
|
|
|
if (!pInf)
|
|
return 0;
|
|
|
|
pch = pInf;
|
|
while (!fFound && *pch != EOF)
|
|
{
|
|
if (*pch++ == TEXT('['))
|
|
{
|
|
fFound = !_wcsnicmp(pszSect, pch, nLen) && pch[nLen] == TEXT(']');
|
|
}
|
|
|
|
/*
|
|
* go to the next line, dont forget to skip over \0 and \0\0
|
|
*/
|
|
while (*pch != EOF && *pch != TEXT('\0'))
|
|
pch++;
|
|
|
|
while (*pch == 0)
|
|
pch++;
|
|
}
|
|
return((fFound && *pch != TEXT('[') && *pch != EOF) ? pch - pInf : 0);
|
|
}
|
|
|
|
/* LONG fnGetDataString(npszData,szDataStr,szBuf,cchBuf)
|
|
*
|
|
* Called by functions that read sections of information from setup.inf
|
|
* to obtain strings that are set equal to keywords. Example:
|
|
*
|
|
* welcome=("Hello There")
|
|
*
|
|
* This function will return a pointer to the null terminated string
|
|
* "Hello There".
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* npszData : pointer to entire section taken from setup.inf
|
|
* szDataStr : pointer to key word to look for (welcome in example above.)
|
|
* szBuf : pointer to a buffer to hold result
|
|
* cchBuf : size of destination buffer (szBuf) in characters.
|
|
* length must be large enough to hold all of the
|
|
* text including the null terminator.
|
|
*
|
|
* EXIT: returns ERROR_SUCCESS if successful, ERROR_NOT_FOUND or ERROR_INSUFFICIENT_BUFFER if failure.
|
|
*
|
|
*/
|
|
LONG fnGetDataString(PINF npszData, LPTSTR szDataStr, LPTSTR szBuf, size_t cchBuf)
|
|
{
|
|
LPTSTR szBufOrig = szBuf;
|
|
int len = lstrlen(szDataStr);
|
|
|
|
while (npszData)
|
|
{
|
|
if (!_wcsnicmp(npszData,szDataStr,len)) // looking for correct prof.
|
|
{
|
|
npszData += len; // found !, look past prof str.
|
|
while (ISWHITE(*npszData)) // pull out the garbage.
|
|
npszData++;
|
|
if (*npszData == EQUAL) // Now we have what were looking for !
|
|
{
|
|
npszData++;
|
|
|
|
if (!multifields(npszData) )
|
|
{
|
|
while (ISWHITE(*npszData) || ISNOISE(*npszData))
|
|
npszData++;
|
|
|
|
while (*npszData)
|
|
{
|
|
*szBuf++ = *npszData++;
|
|
cchBuf--;
|
|
ASSERT( cchBuf > 0 );
|
|
if( cchBuf <= 0 )
|
|
{
|
|
*szBufOrig = TEXT('\0');
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* remove trailing spaces, and those pesky ()'s
|
|
*/
|
|
|
|
while (ISWHITE(szBuf[-1]) || ISNOISE(szBuf[-1]))
|
|
szBuf--;
|
|
|
|
*szBuf = 0;
|
|
return ERROR_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
while (*npszData)
|
|
{
|
|
*szBuf++ = *npszData++;
|
|
cchBuf--;
|
|
ASSERT( cchBuf > 0 );
|
|
if( cchBuf <= 0 )
|
|
{
|
|
*szBufOrig = TEXT('\0');
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
}
|
|
*szBuf = TEXT('\0');
|
|
return ERROR_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
npszData = infNextLine(npszData);
|
|
}
|
|
*szBuf = 0;
|
|
return ERROR_NOT_FOUND;
|
|
}
|
|
|
|
/* PINF FAR PASCAL infSetDefault(pinf)
|
|
*
|
|
* Sets the default INF file
|
|
*
|
|
* ENTRY:
|
|
* pinf : inf file to be new default
|
|
*
|
|
* EXIT: returns old default
|
|
*
|
|
*/
|
|
PINF infSetDefault(PINF pinf)
|
|
{
|
|
PINF pinfT;
|
|
|
|
pinfT = pinfDefault;
|
|
pinfDefault = pinf;
|
|
return pinfT;
|
|
}
|
|
|
|
/* PINF FAR PASCAL infFindSection(pinf,szSection)
|
|
*
|
|
* Reads a entire section into memory and returns a pointer to it
|
|
*
|
|
* ENTRY:
|
|
* pinf : inf file to search for section
|
|
* szSection : section name to read
|
|
*
|
|
* EXIT: returns pointer to section, NULL if error
|
|
*
|
|
*/
|
|
PINF infFindSection(PINF pinf, LPTSTR szSection)
|
|
{
|
|
UINT_PTR pos;
|
|
|
|
if (pinf == NULL)
|
|
pinf = pinfDefault;
|
|
|
|
pos = FindSection(pinf, szSection);
|
|
return pos ? pinf + pos : NULL;
|
|
}
|
|
|
|
/* LONG FAR PASCAL infGetProfileString(szSection,szItem,szBuf,cchBuf)
|
|
*
|
|
* Reads a single string from a section in SETUP.INF
|
|
*
|
|
* [section]
|
|
* item = string
|
|
*
|
|
* ENTRY:
|
|
* szSection : pointer to section name to read.
|
|
* szItem : pointer to item name to read
|
|
* szBuf : pointer to a buffer to hold result
|
|
* cchBuf : size of destination buffer (szBuf) in characters.
|
|
* length must be large enough to hold all of the
|
|
* text including the null terminator.
|
|
*
|
|
* EXIT: returns ERROR_SUCCESS if successful, ERROR_NOT_FOUND or ERROR_INSUFFICIENT_BUFFER if failure.
|
|
*
|
|
*/
|
|
LONG infGetProfileString(PINF pinf, LPTSTR szSection,LPTSTR szItem,LPTSTR szBuf,size_t cchBuf)
|
|
{
|
|
PINF pSection;
|
|
|
|
pSection = infFindSection(pinf,szSection);
|
|
if (pSection )
|
|
return fnGetDataString(pSection,szItem,szBuf,cchBuf);
|
|
else
|
|
*szBuf = 0;
|
|
return ERROR_NOT_FOUND;
|
|
}
|
|
|
|
/* LONG FAR PASCAL infParseField(szData,n,szBuf,cchBuf)
|
|
*
|
|
* Given a line from SETUP.INF, will extract the nth field from the string
|
|
* fields are assumed separated by comma's. Leading and trailing spaces
|
|
* are removed.
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* szData : pointer to line from SETUP.INF
|
|
* n : field to extract. ( 1 based )
|
|
* 0 is field before a '=' sign
|
|
* szBuf : pointer to buffer to hold extracted field
|
|
* cchBuf : size of destination buffer (szBuf) in characters.
|
|
* length must be large enough to hold all of the
|
|
* text including the null terminator.
|
|
*
|
|
* EXIT: returns ERROR_SUCCESS if successful,
|
|
* ERROR_INVALID_PARAMETER, ERROR_NOT_FOUND or ERROR_INSUFFICIENT_BUFFER if failure.
|
|
*
|
|
*/
|
|
LONG infParseField(PINF szData, int n, LPTSTR szBuf, size_t cchBuf)
|
|
{
|
|
BOOL fQuote = FALSE;
|
|
PINF pch;
|
|
LPTSTR ptr;
|
|
|
|
ASSERT(szData != NULL);
|
|
ASSERT(szBuf != NULL);
|
|
if (!szData || !szBuf)
|
|
{
|
|
if( szBuf )
|
|
{
|
|
szBuf[0] = 0; // make szBuf empty
|
|
}
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
/*
|
|
* find the first separator
|
|
*/
|
|
for (pch=szData; *pch && !ISSEP(*pch); pch++) {
|
|
if ( *pch == QUOTE )
|
|
fQuote = !fQuote;
|
|
}
|
|
|
|
if (n == 0 && *pch != TEXT('='))
|
|
{
|
|
szBuf[0] = 0; // make szBuf empty
|
|
return ERROR_NOT_FOUND;
|
|
}
|
|
|
|
if (n > 0 && *pch == TEXT('=') && !fQuote)
|
|
szData = ++pch;
|
|
|
|
/*
|
|
* locate the nth comma, that is not inside of quotes
|
|
*/
|
|
fQuote = FALSE;
|
|
while (n > 1)
|
|
{
|
|
while (*szData)
|
|
{
|
|
if (!fQuote && ISSEP(*szData))
|
|
break;
|
|
|
|
if (*szData == QUOTE)
|
|
fQuote = !fQuote;
|
|
|
|
szData++;
|
|
}
|
|
|
|
if (!*szData) {
|
|
szBuf[0] = 0; // make szBuf empty
|
|
return ERROR_NOT_FOUND;
|
|
}
|
|
|
|
szData++;
|
|
n--;
|
|
}
|
|
/*
|
|
* now copy the field to szBuf
|
|
*/
|
|
while (ISWHITE(*szData))
|
|
szData++;
|
|
|
|
fQuote = FALSE;
|
|
ptr = szBuf; // fill output buffer with this
|
|
while (*szData)
|
|
{
|
|
if (*szData == QUOTE)
|
|
fQuote = !fQuote;
|
|
else if (!fQuote && ISSEP(*szData))
|
|
break;
|
|
else
|
|
{
|
|
*ptr++ = *szData;
|
|
cchBuf--;
|
|
ASSERT( cchBuf > 0 );
|
|
if( cchBuf <= 0 )
|
|
{
|
|
*szBuf = TEXT('\0');
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
}
|
|
szData++;
|
|
}
|
|
/*
|
|
* remove trailing spaces, and those pesky ()'s
|
|
*/
|
|
while ((ptr > szBuf) && (ISWHITE(ptr[-1]) || ISNOISE(ptr[-1])))
|
|
ptr--;
|
|
|
|
*ptr = 0;
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
/* BOOL multifields(LPTSTR npszData);
|
|
*
|
|
* Given a line line from mmdriver.inf that was after a profile
|
|
* string this function will determine if that line has more than one
|
|
* field. ie. Fields are seperated by commas that are NOT contained between
|
|
* quotes.
|
|
*
|
|
* ENYRY:
|
|
*
|
|
* npszData : a line from setup.inf Example "xyz adapter",1:foobar.drv
|
|
*
|
|
* EXIT: This function will return TRUE if the line containes more than
|
|
* one field, ie the function would return TRUE for the example line
|
|
* shown above.
|
|
*
|
|
*/
|
|
BOOL multifields(PINF npszData)
|
|
{
|
|
BOOL fQuote = FALSE;
|
|
|
|
while (*npszData)
|
|
{
|
|
if (!fQuote && ISSEP(*npszData))
|
|
return TRUE;
|
|
|
|
if (*npszData == QUOTE)
|
|
fQuote = !fQuote;
|
|
|
|
npszData++;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/* LPTSTR FAR PASCAL infNextLine(sz)
|
|
*
|
|
* Given a line from SETUP.INF, advance to the next line. will skip past the
|
|
* ending NULL character checking for end of buffer \0\0
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* sz : pointer to line from a SETUP.INF section
|
|
*
|
|
* EXIT: returns pointer to next line if successful, NULL if failure.
|
|
*
|
|
*/
|
|
PINF infNextLine(PINF pinf)
|
|
{
|
|
if (!pinf)
|
|
return NULL;
|
|
|
|
while (*pinf != 0 || *(pinf + 1) == TEXT(' '))
|
|
pinf++;
|
|
|
|
return *++pinf ? pinf : NULL;
|
|
}
|
|
|
|
/* int FAR PASCAL infLineCount(pinf)
|
|
*
|
|
* Given a section from SETUP.INF, returns the number of lines in the section
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* pinf : pointer to a section from SETUP.INF
|
|
*
|
|
* EXIT: returns line count
|
|
*
|
|
*/
|
|
int infLineCount(PINF pinf)
|
|
{
|
|
int n = 0;
|
|
|
|
for (n=0; pinf; pinf = infNextLine(pinf))
|
|
n++;
|
|
|
|
return n;
|
|
}
|