windows-nt/Source/XPSP1/NT/base/ntsetup/legacy/dll/inf1.c
2020-09-26 16:20:57 +08:00

1040 lines
28 KiB
C

#include "precomp.h"
#pragma hdrstop
/**************************************************************************/
/***** Common Library Component - INF File Handling Routines 1 ***********/
/**************************************************************************/
BOOL APIENTRY FMatchPrefix(PSZ, SZ, BOOL);
GRC APIENTRY GrcHandleSfdOption(INT, POER, UINT);
/*
** Purpose:
** Allocates an Object Element Record and initializes it as empty.
** Arguments:
** none
** Returns:
** NULL if allocation fails.
** non-NULL pointer to the empty (initialized) Object Element Record.
**
**************************************************************************/
POER APIENTRY PoerAlloc(VOID)
{
POER poer;
AssertDataSeg();
if ((poer = (POER)SAlloc((CB)sizeof(OER))) != (POER)NULL)
{
poer->oef = oefNone;
poer->ctuCopyTime = (CTU)0;
poer->owm = owmAlways;
poer->lSize = 0L;
poer->szRename = (SZ)NULL;
poer->szAppend = (SZ)NULL;
poer->szBackup = (SZ)NULL;
poer->szDescription = (SZ)NULL;
poer->ulVerMS = 0L;
poer->ulVerLS = 0L;
poer->szDate = (SZ)NULL;
poer->szDest = (SZ)NULL; /* REVIEW EBU */
}
return(poer);
}
/*
** Purpose:
** Free an Object Element Record and any non-empty string fields.
** Arguments:
** poer: non-NULL Object Element Record to be freed.
** Returns:
** fFalse if a freeing error occurs.
** fTrue for success.
**
**************************************************************************/
BOOL APIENTRY FFreePoer(poer)
POER poer;
{
AssertDataSeg();
ChkArg(poer != (POER)NULL, 1, fFalse);
if (poer->szRename != (SZ)NULL)
SFree(poer->szRename);
if (poer->szAppend != (SZ)NULL)
SFree(poer->szAppend);
if (poer->szBackup != (SZ)NULL)
SFree(poer->szBackup);
if (poer->szDescription != (SZ)NULL)
SFree(poer->szDescription);
if (poer->szDate != (SZ)NULL)
SFree(poer->szDate);
if (poer->szDest != (SZ)NULL) /* REVIEW EBU */
SFree(poer->szDest);
SFree(poer);
return(fTrue);
}
/*
** Purpose:
** Validates an Option Element Record.
** Arguments:
** poer: non-Null pointer to OER to validate.
** Returns:
** fFalse if not valid.
** fTrue if valid.
**
**************************************************************************/
BOOL APIENTRY FValidPoer(poer)
POER poer;
{
AssertDataSeg();
ChkArg(poer != (POER)NULL, 1, fFalse);
if (poer->szBackup != (SZ)NULL &&
poer->szAppend != (SZ)NULL)
return(fFalse);
if (poer->szRename != (SZ)NULL &&
poer->szAppend != (SZ)NULL)
return(fFalse);
if (poer->szRename != (SZ)NULL &&
poer->oef & oefRoot)
return(fFalse);
if (poer->szAppend != (SZ)NULL &&
poer->oef & oefRoot)
return(fFalse);
if (poer->szRename != (SZ)NULL &&
CchlValidSubPath(poer->szRename) == (CCHL)0)
return(fFalse);
if (poer->szAppend != (SZ)NULL &&
CchlValidSubPath(poer->szAppend) == (CCHL)0)
return(fFalse);
if (poer->szBackup != (SZ)NULL &&
(*(poer->szBackup) != '*' ||
*(poer->szBackup + 1) != '\0') &&
CchlValidSubPath(poer->szBackup) == (CCHL)0)
return(fFalse);
if (poer->szDate != (SZ)NULL &&
!FValidOerDate(poer->szDate))
return(fFalse);
if (poer->lSize < 0L)
return(fFalse);
if (poer->owm != owmNever &&
poer->owm != owmAlways &&
poer->owm != owmUnprotected &&
poer->owm != owmOlder &&
poer->owm != owmVerifySourceOlder)
return(fFalse);
/* REVIEW EBU - no checking for szDest field */
return(fTrue);
}
/*
** Purpose:
** Allocates a Section File Descriptor and initializes it as empty.
** Arguments:
** none
** Returns:
** NULL if allocation fails.
** non-NULL pointer to the empty (initialized) Section File Descriptor.
**
**************************************************************************/
PSFD APIENTRY PsfdAlloc(VOID)
{
PSFD psfd;
AssertDataSeg();
if ((psfd = (PSFD)SAlloc((CB)sizeof(SFD))) != (PSFD)NULL)
{
POER poer = &(psfd->oer);
psfd->did = didMin;
psfd->szFile = (SZ)NULL;
poer->oef = oefNone;
poer->ctuCopyTime = (CTU)0;
poer->owm = owmAlways;
poer->lSize = 0L;
poer->szRename = (SZ)NULL;
poer->szAppend = (SZ)NULL;
poer->szBackup = (SZ)NULL;
poer->szDescription = (SZ)NULL;
poer->ulVerMS = 0L;
poer->ulVerLS = 0L;
poer->szDate = (SZ)NULL;
poer->szDest = (SZ)NULL; /* REVIEW EBU */
}
return(psfd);
}
/*
** Purpose:
** Free a Section File Descriptor and any non-empty string fields.
** Arguments:
** psfd: non-NULL Section File Descriptor to be freed.
** Returns:
** fFalse if a freeing error occurs.
** fTrue for success.
**
**************************************************************************/
BOOL APIENTRY FFreePsfd(psfd)
PSFD psfd;
{
AssertDataSeg();
ChkArg(psfd != (PSFD)NULL, 1, fFalse);
if (psfd->szFile != (SZ)NULL)
SFree(psfd->szFile);
if ((psfd->oer).szRename != (SZ)NULL)
SFree((psfd->oer).szRename);
if ((psfd->oer).szAppend != (SZ)NULL)
SFree((psfd->oer).szAppend);
if ((psfd->oer).szBackup != (SZ)NULL)
SFree((psfd->oer).szBackup);
if ((psfd->oer).szDescription != (SZ)NULL)
SFree((psfd->oer).szDescription);
if ((psfd->oer).szDate != (SZ)NULL)
SFree((psfd->oer).szDate);
if ((psfd->oer).szDest != (SZ)NULL)
SFree((psfd->oer).szDest);
SFree(psfd);
return(fTrue);
}
#if DBG
/*
** Purpose:
** Validates a Section File Descriptor.
** Arguments:
** psfd: non-Null pointer to SFD to validate.
** Returns:
** fFalse if not valid.
** fTrue if valid.
**
**************************************************************************/
BOOL APIENTRY FValidPsfd(psfd)
PSFD psfd;
{
AssertDataSeg();
ChkArg(psfd != (PSFD)NULL, 1, fFalse);
if (psfd->did < didMin ||
psfd->did > didMost ||
psfd->szFile == (SZ)NULL ||
CchlValidSubPath(psfd->szFile) == (CCHP)0)
return(fFalse);
return(FValidPoer(&(psfd->oer)));
}
#endif
/*
** Purpose:
** Validates a Section File Descriptor Date string of the form
** "YYYY-MM-DD" where YYYY is >= 1980 and <= 2099, MM in [01..12],
** and DD in [01..31].
** Arguments:
** sz: non-Null Date string to validate.
** Returns:
** fFalse if invalid.
** fTrue if valid.
**
**************************************************************************/
BOOL APIENTRY FValidOerDate(sz)
SZ sz;
{
AssertDataSeg();
ChkArg(sz != (SZ)NULL, 1, fFalse);
if (*sz == '\0' ||
strlen(sz) != (CCHP)10 ||
!isdigit(*(sz + 0)) ||
!isdigit(*(sz + 1)) ||
!isdigit(*(sz + 2)) ||
!isdigit(*(sz + 3)) ||
!isdigit(*(sz + 5)) ||
!isdigit(*(sz + 6)) ||
!isdigit(*(sz + 8)) ||
!isdigit(*(sz + 9)) ||
*(sz + 4) != '-' ||
*(sz + 7) != '-')
return(fFalse);
if (*sz == '0' ||
*sz > '2' ||
(*sz == '1' &&
(*(sz + 1) != '9' ||
*(sz + 2) < '8')) ||
(*sz == '2' &&
*(sz + 1) != '0'))
return(fFalse);
if (*(sz + 5) > '1' ||
(*(sz + 5) == '0' &&
*(sz + 6) == '0') ||
(*(sz + 5) == '1' &&
*(sz + 6) > '2'))
return(fFalse);
if (*(sz + 8) > '3' ||
(*(sz + 8) == '0' &&
*(sz + 9) == '0') ||
(*(sz + 8) == '3' &&
*(sz + 9) > '1'))
return(fFalse);
return(fTrue);
}
/*
** Purpose:
** Ensures rest of SFD option string matches (case insensitive compare)
** and consumes option string through matching portion and a trailing
** equals sign (if required).
** Arguments:
** psz: non-NULL pointer to non-NULL option string to match.
** szToMatch: non-Null uppercase string to match.
** fEquals: whether string must be terminated by an equals sign.
** Returns:
** fFalse for mismatch or bad format of option.
** fTrue otherwise.
**
**************************************************************************/
BOOL APIENTRY FMatchPrefix(PSZ psz,SZ szToMatch,BOOL fEquals)
{
AssertDataSeg();
ChkArg(psz != (PSZ)NULL &&
*psz != (SZ)NULL, 1, fFalse);
ChkArg(szToMatch != (SZ)NULL &&
*szToMatch >= 'A' &&
*szToMatch <= 'Z', 2, fFalse);
while (**psz != '\0' &&
**psz != '=' &&
!FWhiteSpaceChp(**psz) &&
*szToMatch != '\0')
{
if (**psz != *szToMatch)
return(fFalse);
(*psz)++;
szToMatch++;
}
if (fEquals)
{
if (**psz != '=')
return(fFalse);
else
(*psz)++;
}
else if (**psz != '\0')
return(fFalse);
return(fTrue);
}
/*
** Purpose:
** Parses a string representation of a version into two unsigned
** long values - the most significant and the least significant.
** Arguments:
** szVer: non-Null SZ of the form "a,b,c,d" where each field is
** an unsigned word. Omitted fields are assumed to be the least
** significant (eg d then c then b then a) and are parsed as zeros.
** So "a,b" is equivalent to "a,b,0,0".
** pulMS: non-Null location to store the Most Significant long value
** built from a,b
** pulLS: non-Null location to store the Least Significant long value
** built from c,d
** Returns:
** fFalse if szVer is of a bad format.
** fTrue otherwise.
**
**************************************************************************/
BOOL APIENTRY FParseVersion(szVer, pulMS, pulLS)
SZ szVer;
PULONG pulMS;
PULONG pulLS;
{
USHORT rgus[4];
USHORT ius;
ULONG ulTmp;
AssertDataSeg();
ChkArg(szVer != (SZ)NULL, 1, fFalse);
ChkArg(pulMS != (PULONG)NULL, 2, fFalse);
ChkArg(pulLS != (PULONG)NULL, 3, fFalse);
*pulMS = *pulLS = 0L;
for (ius = 0; ius < 4; ius++) {
rgus[ius] = (USHORT) atoi(szVer);
while (*szVer != '\0' && *szVer != ',') {
if (!isdigit(*szVer++)) {
return(fFalse);
}
}
if (*szVer == ',') {
szVer++;
}
}
ulTmp = rgus[0];
*pulMS = (ulTmp << 16) + rgus[1];
ulTmp = rgus[2];
*pulLS = (ulTmp << 16) + rgus[3];
return(fTrue);
// // no versioning in WIN32
// Unused(szVer);
// Unused(pulMS);
// Unused(pulLS);
// return(fTrue);
}
/*
** Purpose:
** Handles one option field from a file description line.
** Arguments:
** poer: non-NULL valid OER to fill.
** iField: index of existing field to read.
** Notes:
** Requires that the current INF structure was initialized with a
** successful call to GrcOpenInf() and that the current Read location
** is valid.
** Returns:
** grcOkay for success.
** grcOutOfMemory for out of memory.
** grcINFBadFDLine for bad format.
** grcNotOkay otherwise.
**
**************************************************************************/
GRC APIENTRY GrcHandleSfdOption(INT Line,POER poer,UINT iField)
{
SZ sz, szCur;
GRC grc = grcOkay;
BOOL fNot = fFalse;
AssertDataSeg();
PreCondInfOpen(grcNotOkay);
ChkArg(poer != (POER)NULL, 1, grcNotOkay);
ChkArg(FValidPoer(poer), 1, grcNotOkay);
ChkArg(iField >= 1 && CFieldsInInfLine(Line) >= iField, 2, grcNotOkay);
if ((szCur = sz = SzGetNthFieldFromInfLine(Line,iField)) == (SZ)NULL)
return(grcOutOfMemory);
if (*szCur == '!')
{
fNot = fTrue;
szCur++;
}
switch (*szCur)
{
case 'A':
if (!FMatchPrefix(&szCur, "APPEND", !fNot))
grc = grcINFBadFDLine;
else if (fNot)
poer->szAppend = (SZ)NULL;
else if ((poer->szAppend = SzDupl(szCur)) == (SZ)NULL)
grc = grcOutOfMemory;
else if (CchlValidSubPath(poer->szAppend) == (CCHP)0 ||
poer->szBackup != (SZ)NULL ||
poer->szRename != (SZ)NULL ||
(poer->oef & oefRoot) == oefRoot)
grc = grcINFBadFDLine;
break;
case 'B':
if (!FMatchPrefix(&szCur, "BACKUP", !fNot))
grc = grcINFBadFDLine;
else if (fNot)
poer->szBackup = (SZ)NULL;
else if ((poer->szBackup = SzDupl(szCur)) == (SZ)NULL)
grc = grcOutOfMemory;
else if ((*(poer->szBackup) != '*' ||
*(poer->szBackup + 1) != '\0') &&
CchlValidSubPath(poer->szBackup) == (CCHP)0)
grc = grcINFBadFDLine;
else if (poer->szAppend != (SZ)NULL)
grc = grcINFBadFDLine;
break;
case 'C':
if (!FMatchPrefix(&szCur, "COPY", fFalse))
grc = grcINFBadFDLine;
else if (fNot)
poer->oef &= ~oefCopy;
else
poer->oef |= oefCopy;
break;
case 'D': /* Date, Decompress, Description */
if (*(szCur + 1) == 'A')
{
if (!FMatchPrefix(&szCur, "DATE", !fNot))
grc = grcINFBadFDLine;
else if (fNot)
poer->szDate = (SZ)NULL;
else if ((poer->szDate = SzDupl(szCur)) == (SZ)NULL)
grc = grcOutOfMemory;
else if (!FValidOerDate(poer->szDate))
grc = grcINFBadFDLine;
}
else if (*(szCur + 1) == 'E')
{
if (*(szCur + 2) == 'C')
{
if (!FMatchPrefix(&szCur, "DECOMPRESS", fFalse))
grc = grcINFBadFDLine;
else if (fNot)
poer->oef &= ~oefDecompress;
else
poer->oef |= oefDecompress;
}
else if (*(szCur + 2) == 'S')
{
if (*(szCur + 3) == 'C')
{
if (!FMatchPrefix(&szCur, "DESCRIPTION", !fNot))
grc = grcINFBadFDLine;
else if (fNot)
poer->szDescription = (SZ)NULL;
else if ((poer->szDescription = SzDupl(szCur)) == (SZ)NULL)
grc = grcOutOfMemory;
}
else if (*(szCur + 3) == 'T') /* REVIEW EBU */
{
if (!FMatchPrefix(&szCur, "DESTINATION", !fNot))
grc = grcINFBadFDLine;
else if (fNot)
poer->szDest = (SZ)NULL;
else if ((poer->szDest = SzDupl(szCur)) == (SZ)NULL)
grc = grcOutOfMemory;
}
else
grc = grcINFBadFDLine;
}
else
grc = grcINFBadFDLine;
}
else
grc = grcINFBadFDLine;
break;
case 'N': /* NoDeleteSource, NoLog */
if(*(szCur + 1) == 'O') {
if(*(szCur + 2) == 'D') {
if(!FMatchPrefix(&szCur, "NODELETESOURCE", fFalse)) {
grc = grcINFBadFDLine;
} else if (fNot) {
poer->oef &= ~oefNoDeleteSource;
} else {
poer->oef |= oefNoDeleteSource;
}
} else if(*(szCur + 2) == 'L') {
if(!FMatchPrefix(&szCur, "NOLOG", fFalse)) {
grc = grcINFBadFDLine;
} else if (fNot) {
poer->oef &= ~oefNoLog;
} else {
poer->oef |= oefNoLog;
}
}
} else {
grc = grcINFBadFDLine;
}
break;
case 'O':
if (!FMatchPrefix(&szCur, "OVERWRITE", !fNot))
grc = grcINFBadFDLine;
else if (fNot)
poer->owm = owmNever;
else
{
switch (*szCur)
{
case 'A':
if (!FMatchPrefix(&szCur, "ALWAYS", fFalse))
grc = grcINFBadFDLine;
poer->owm = owmAlways;
break;
case 'N':
if (!FMatchPrefix(&szCur, "NEVER", fFalse))
grc = grcINFBadFDLine;
poer->owm = owmNever;
break;
case 'O':
if (!FMatchPrefix(&szCur, "OLDER", fFalse))
grc = grcINFBadFDLine;
poer->owm = owmOlder;
break;
case 'V':
if (!FMatchPrefix(&szCur, "VERIFYSOURCEOLDER", fFalse))
grc = grcINFBadFDLine;
poer->owm = owmVerifySourceOlder;
break;
case 'U':
if (!FMatchPrefix(&szCur, "UNPROTECTED", fFalse))
grc = grcINFBadFDLine;
poer->owm = owmUnprotected;
break;
default:
grc = grcINFBadFDLine;
}
}
break;
case 'R': /* ReadOnly, Rename, Root */
if (*(szCur + 1) == 'E')
{
if (*(szCur + 2) == 'A')
{
if (!FMatchPrefix(&szCur, "READONLY", fFalse))
grc = grcINFBadFDLine;
else if (fNot)
poer->oef &= ~oefReadOnly;
else
poer->oef |= oefReadOnly;
}
else if (*(szCur + 2) == 'N')
{
if (!FMatchPrefix(&szCur, "RENAME", !fNot))
grc = grcINFBadFDLine;
else if (fNot)
poer->szRename = (SZ)NULL;
else if ((poer->szRename = SzDupl(szCur)) == (SZ)NULL)
grc = grcOutOfMemory;
else if (CchlValidSubPath(poer->szRename) == (CCHP)0 ||
poer->szAppend != (SZ)NULL ||
(poer->oef & oefRoot) == oefRoot)
grc = grcINFBadFDLine;
}
else
grc = grcINFBadFDLine;
}
else if (*(szCur + 1) == 'O')
{
if (!FMatchPrefix(&szCur, "ROOT", fFalse))
grc = grcINFBadFDLine;
else if (fNot)
poer->oef &= ~oefRoot;
else if (poer->szAppend != (SZ)NULL ||
poer->szRename != (SZ)NULL)
grc = grcINFBadFDLine;
else
poer->oef |= oefRoot;
}
else
grc = grcINFBadFDLine;
break;
case 'S': /* SetTimeStamp, Size */
if (*(szCur + 1) == 'E')
{
if (!FMatchPrefix(&szCur, "SETTIMESTAMP", fFalse))
grc = grcINFBadFDLine;
else if (fNot)
poer->oef &= ~oefTimeStamp;
else
poer->oef |= oefTimeStamp;
}
else if (*(szCur + 1) == 'I')
{
if (!FMatchPrefix(&szCur, "SIZE", !fNot))
grc = grcINFBadFDLine;
else if (fNot)
poer->lSize = 0L;
else if ((poer->lSize = ((LONG)atol(szCur) / 100 )) < 0L)
grc = grcINFBadFDLine;
else
poer->lSize = poer->lSize + 1; // make size atleast one
}
else
grc = grcINFBadFDLine;
break;
case 'T':
if (!FMatchPrefix(&szCur, "TIME", !fNot))
grc = grcINFBadFDLine;
else if (fNot)
poer->ctuCopyTime = (CTU)0;
else
{
LONG l = (LONG)atol(szCur);
if (l < 0L)
grc = grcINFBadFDLine;
else
poer->ctuCopyTime = (CTU)l;
}
break;
case 'U':
if (FMatchPrefix(&szCur, "UNDO", fFalse)) {
if (fNot) {
poer->oef &= ~oefUndo;
}
else {
poer->oef |= oefUndo;
}
}
else if (FMatchPrefix(&szCur, "UPGRADEONLY", fFalse)) {
if (fNot) {
poer->oef &= ~oefUpgradeOnly;
}
else {
poer->oef |= oefUpgradeOnly;
}
}
else {
grc = grcINFBadFDLine;
}
break;
case 'V': /* Version, Vital */
if (*(szCur + 1) == 'E')
{
if (!FMatchPrefix(&szCur, "VERSION", !fNot))
grc = grcINFBadFDLine;
else if (fNot)
{
poer->ulVerMS = 0L;
poer->ulVerLS = 0L;
}
else if (!FParseVersion(szCur, &(poer->ulVerMS), &(poer->ulVerLS)))
grc = grcINFBadFDLine;
}
else if (*(szCur + 1) == 'I')
{
if (!FMatchPrefix(&szCur, "VITAL", fFalse))
grc = grcINFBadFDLine;
else if (fNot)
poer->oef &= ~oefVital;
else
poer->oef |= oefVital;
}
else
grc = grcINFBadFDLine;
break;
default:
grc = grcINFBadFDLine;
}
SFree(sz);
Assert(grc != grcOkay || FValidPoer(poer));
return(grc);
}
/*
** Purpose:
** Allocates a new Section File Descriptor and fills it by reading and
** parsing the given INF read line.
** Arguments:
** ppsfd: non-Null location to store PSFD if successful.
** poer: non-Null valid filled OER pointer.
** Notes:
** Requires that the current INF structure was initialized with a
** successful call to GrcOpenInf().
** Returns:
** grcOkay if successful.
** grcOutOfMemory if out of memory.
** grcINFBadFDLine if the current line has a bad format.
** grcNotOkay otherwise.
**
**************************************************************************/
GRC APIENTRY GrcGetSectionFileLine(INT Line,PPSFD ppsfd,POER poer)
{
PSFD psfd;
UINT cFields, iField;
SZ sz;
AssertDataSeg();
PreCondInfOpen(grcNotOkay);
ChkArg(ppsfd != (PPSFD)NULL, 1, grcNotOkay);
ChkArg(poer != (POER)NULL, 2, grcNotOkay);
ChkArg(FValidPoer(poer), 2, grcNotOkay);
*ppsfd = (PSFD)NULL;
if ((cFields = CFieldsInInfLine(Line)) < 2)
return(grcINFBadFDLine);
if ((psfd = PsfdAlloc()) == (PSFD)NULL)
return(grcOutOfMemory);
if ((sz = SzGetNthFieldFromInfLine(Line,1)) == (SZ)NULL)
{
EvalAssert(FFreePsfd(psfd));
return(grcOutOfMemory);
}
if ((psfd->did = (DID)atoi(sz)) < didMin ||
psfd->did > didMost)
{
SFree(sz);
EvalAssert(FFreePsfd(psfd));
return(grcINFBadFDLine);
}
psfd->InfId = pLocalInfPermInfo()->InfId;
SFree(sz);
if ((psfd->szFile = SzGetNthFieldFromInfLine(Line,2)) == (SZ)NULL)
{
EvalAssert(FFreePsfd(psfd));
return(grcOutOfMemory);
}
if (CchlValidSubPath(psfd->szFile) == (CCHP)0)
{
EvalAssert(FFreePsfd(psfd));
return(grcINFBadFDLine);
}
psfd->oer = *poer;
for (iField = 3; iField <= cFields; iField++)
{
GRC grc;
if ((grc = GrcHandleSfdOption(Line, &(psfd->oer), iField)) != grcOkay)
{
/* REVIEW - could just reset all and leave a few strings! */
if ((psfd->oer).szAppend == poer->szAppend)
(psfd->oer).szAppend = (SZ)NULL;
if ((psfd->oer).szBackup == poer->szBackup)
(psfd->oer).szBackup = (SZ)NULL;
if ((psfd->oer).szDate == poer->szDate)
(psfd->oer).szDate = (SZ)NULL;
if ((psfd->oer).szDescription == poer->szDescription)
(psfd->oer).szDescription = (SZ)NULL;
if ((psfd->oer).szDest == poer->szDest) /* REVIEW EBU */
(psfd->oer).szDest = (SZ)NULL;
if ((psfd->oer).szRename == poer->szRename)
(psfd->oer).szRename = (SZ)NULL;
EvalAssert(FFreePsfd(psfd));
return(grc);
}
}
AssertRet(FValidPsfd(psfd), grcNotOkay);
*ppsfd = psfd;
return(grcOkay);
}
/*
** Purpose:
** Determines if the given INF line is a list-include statement of
** the form: [ <Key> = ] @( <Section> ) [, @( <Key> ) ]
** Arguments:
** none
** Notes:
** Requires that the current INF structure was initialized with a
** successful call to GrcOpenInf() and that the current Read location
** is valid.
** Returns:
** fTrue if current INF line conforms to above format.
** fFalse if it does not.
**
**************************************************************************/
BOOL APIENTRY FListIncludeStatementLine(INT Line)
{
UINT cFields;
SZ sz, szLast;
AssertDataSeg();
PreCondInfOpen(fFalse);
if ((cFields = CFieldsInInfLine(Line)) < 1 ||
cFields > 2 ||
(sz = SzGetNthFieldFromInfLine(Line,1)) == (SZ)NULL)
return(fFalse);
if (*sz != '@' ||
*(sz + 1) != '(' ||
(szLast = SzLastChar(sz)) == (SZ)NULL ||
*szLast != ')')
goto L_FLISL_ERROR;
SFree(sz);
if (cFields == 1)
return(fTrue);
if ((sz = SzGetNthFieldFromInfLine(Line,2)) == (SZ)NULL)
return(fFalse);
if (*sz != '@' ||
*(sz + 1) != '(' ||
(szLast = SzLastChar(sz)) == (SZ)NULL ||
*szLast != ')')
goto L_FLISL_ERROR;
SFree(sz);
return(fTrue);
L_FLISL_ERROR:
if (sz != (SZ)NULL)
SFree(sz);
return(fFalse);
}
/*
** Purpose:
** Parses a list-include-statement from an INF file description section.
** Arguments:
** pszSection: non-Null pointer to a currently Null string which this
** routine will replace with a pointer to an allocated buffer
** containing the section name on the line.
** pszKey: non-Null pointer to a currently Null string which this
** routine will replace with a pointer to an allocated buffer
** containing the key name on the line if one exists.
** Notes:
** Requires that the current INF structure was initialized with a
** successful call to GrcOpenInf() and that the current Read location
** is valid and that it points to a valid list-include statement.
** Returns:
** grcOkay if successful.
** grcOutOfMemory if out of memory.
** grcNotOkay otherwise.
**
**************************************************************************/
GRC APIENTRY GrcGetListIncludeSectionLine(INT Line,
PSZ pszSection,
PSZ pszKey)
{
UINT cFields;
SZ sz, szLast;
AssertDataSeg();
PreCondInfOpen(grcNotOkay);
PreCondition(FListIncludeStatementLine(Line), grcNotOkay);
ChkArg(pszSection != (PSZ)NULL && *pszSection == (SZ)NULL, 1, grcNotOkay);
ChkArg(pszKey != (PSZ)NULL && *pszKey == (SZ)NULL, 2, grcNotOkay);
EvalAssert((cFields = CFieldsInInfLine(Line)) == 1 || cFields == 2);
if ((sz = SzGetNthFieldFromInfLine(Line,1)) == (SZ)NULL)
return(grcOutOfMemory);
Assert(*sz == '@' && *(sz + 1) == '(');
EvalAssert((szLast = SzLastChar(sz)) != (SZ)NULL);
Assert(*szLast == ')');
*szLast = '\0';
*pszSection = SzDupl(sz + 2);
*szLast = ')';
if (*pszSection == (SZ)NULL)
goto L_GGLISL_ERROR;
SFree(sz);
sz = (SZ)NULL;
if (cFields == 1)
return(grcOkay);
Assert(cFields == 2);
if ((sz = SzGetNthFieldFromInfLine(Line,2)) == (SZ)NULL)
goto L_GGLISL_ERROR;
Assert(*sz == '@' && *(sz + 1) == '(');
EvalAssert((szLast = SzLastChar(sz)) != (SZ)NULL);
Assert(*szLast == ')');
*szLast = '\0';
*pszKey = SzDupl(sz + 2);
*szLast = ')';
if (*pszKey == (SZ)NULL)
goto L_GGLISL_ERROR;
SFree(sz);
return(grcOkay);
L_GGLISL_ERROR:
if (sz != (SZ)NULL)
SFree(sz);
if (*pszSection != (SZ)NULL)
SFree(*pszSection);
if (*pszKey != (SZ)NULL)
SFree(*pszKey);
return(grcOutOfMemory);
}