#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: [ = ] @(
) [, @( ) ] ** 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); }