/*** dfparse.c - Directives File parser * * Microsoft Confidential * Copyright (C) Microsoft Corporation 1993-1994 * All Rights Reserved. * * Author: * Benjamin W. Slivka * * History: * 10-Aug-1993 bens Initial version * 12-Aug-1993 bens Added more entries to aiv[] * 14-Aug-1993 bens Start working on parser proper * 20-Aug-1993 bens Add more standard variables * 22-Aug-1993 bens Do variable substitution in directive lines * 11-Feb-1994 bens Start parsing individual commands (.Set) * 16-Feb-1994 bens Handle ClusterSize; add DiskLabelTemplate * 17-Feb-1994 bens Added 360K/720K disk parms; fixed validaters * 12-Mar-1994 bens Add .Dump and .Define directives * 25-Apr-1994 bens Add customizable INF stuff * 26-May-1994 bens Add CompressionXxxx variables * 03-Jun-1994 bens Implement .Define, .Option, .Dump * 11-Jul-1994 bens Check for blank/comments lines *after* variable * substitution! * 27-Jul-1994 bens Allow leading blanks in .InfWrite[Xxx] * 28-Mar-1995 jeffwe Add ChecksumWidth variable * * Exported Functions: * DFPInit - Initialize directive file parser * DFPParse - Parse a directive file * DFPParseVarAssignment - Parse var=value string */ #include #include #include #include #include "types.h" #include "asrt.h" #include "error.h" #include "variable.h" #include "dfparse.h" #include "inf.h" #include "mem.h" #include "misc.h" #include "dfparse.msg" #include "diamond.msg" FNVCVALIDATE(fnvcvBool); FNVCVALIDATE(fnvcvCabName); FNVCVALIDATE(fnvcvChecksumWidth); FNVCVALIDATE(fnvcvClusterSize); FNVCVALIDATE(fnvcvCompType); FNVCVALIDATE(fnvcvCompLevel); FNVCVALIDATE(fnvcvCompMemory); FNVCVALIDATE(fnvcvDateFmt); FNVCVALIDATE(fnvcvDirDest); FNVCVALIDATE(fnvcvDirSrc); FNVCVALIDATE(fnvcvFile); FNVCVALIDATE(fnvcvFileChar); FNVCVALIDATE(fnvcvLong); FNVCVALIDATE(fnvcvMaxDiskFileCount); FNVCVALIDATE(fnvcvMaxDiskSize); FNVCVALIDATE(fnvcvSectionOrder); FNVCVALIDATE(fnvcvWildFile); FNVCVALIDATE(fnvcvWildPath); COMMANDTYPE ctFromCommandString(char *pszCmd, PERROR perr); BOOL getCmdFromLine(PCOMMAND pcmd, PSESSION psess, char *pszLine, PERROR perr); BOOL getCommand(PCOMMAND pcmd, PSESSION psess, char *pszLine, PERROR perr); char *getQuotedString(char *pszDst, int cbDst, char *pszSrc, char *pszDelim, char *pszFieldName, PERROR perr); int IMDSfromPSZ(char *pszValue); BOOL parseFileLine(PCOMMAND pcmd, PSESSION psess, char *pszLine, PERROR perr); char *parseParameterList(HGENLIST *phglist, char *pch, PERROR perr, BOOL *runflg); BOOL parseReferenceLine(PCOMMAND pcmd,PSESSION psess,char *pszLine,PERROR perr); BOOL parseSetCommand(PCOMMAND pcmd, PSESSION psess, char *pszArg, PERROR perr); BOOL processLineWithQuotes(char *pszDst, int cbDst, char *pszSrc, char *pszDelim, char *pszFieldName, PERROR perr); long roundUpToPowerOfTwo(long x); BOOL substituteVariables(char *pszDst, int cbDst, char *pszSrc, HVARLIST hvlist, PERROR perr); //** aiv - list of predefined variables typedef struct { char *pszName; // Variable name char *pszValue; // Default value VARTYPE vtype; // Variable type VARFLAGS vfl; // Special flags PFNVCVALIDATE pfnvcv; // Validation function } INITVAR; /* iv */ //** NOTE: The vflCOPY flag is used for variables whose *last* value must //** be carried over to the *Pass 2* variable list. At present, the //** variables that control the INF file headers and formats //** require this property! STATIC INITVAR aiv[] = { {pszVAR_CABINET ,pszDEF_CABINET ,vtypeBOOL,vflPERM ,fnvcvBool }, {pszVAR_CABINET_FILE_COUNT_THRESHOLD,pszDEF_CABINET_FILE_COUNT_THRESHOLD,vtypeLONG,vflPERM ,fnvcvLong }, {pszVAR_CAB_NAME ,pszDEF_CAB_NAME ,vtypeSTR ,vflPERM ,fnvcvWildPath}, {pszVAR_CHECKSUM_WIDTH ,pszDEF_CHECKSUM_WIDTH ,vtypeLONG,vflPERM ,fnvcvChecksumWidth}, {pszVAR_CLUSTER_SIZE ,pszDEF_CLUSTER_SIZE ,vtypeLONG,vflPERM ,fnvcvClusterSize}, {pszVAR_COMPRESS ,pszDEF_COMPRESS ,vtypeBOOL,vflPERM ,fnvcvBool }, {pszVAR_COMP_FILE_EXT_CHAR ,pszDEF_COMP_FILE_EXT_CHAR ,vtypeCHAR,vflPERM ,fnvcvFileChar}, {pszVAR_COMPRESSION_TYPE ,pszDEF_COMPRESSION_TYPE ,vtypeSTR ,vflPERM ,fnvcvCompType}, {pszVAR_COMPRESSION_LEVEL ,pszDEF_COMPRESSION_LEVEL ,vtypeLONG,vflPERM ,fnvcvCompLevel}, {pszVAR_COMPRESSION_MEMORY ,pszDEF_COMPRESSION_MEMORY ,vtypeLONG,vflPERM ,fnvcvCompMemory}, {pszVAR_DIR_DEST ,pszDEF_DIR_DEST ,vtypeSTR ,vflPERM ,fnvcvDirDest }, {pszVAR_DISK_DIR_NAME ,pszDEF_DISK_DIR_NAME ,vtypeSTR ,vflPERM ,fnvcvWildPath}, {pszVAR_DISK_LABEL_NAME ,pszDEF_DISK_LABEL_NAME ,vtypeSTR ,vflPERM ,NULL }, {pszVAR_DO_NOT_COPY_FILES ,pszDEF_DO_NOT_COPY_FILES ,vtypeBOOL,vflPERM ,fnvcvBool }, {pszVAR_FOLDER_FILE_COUNT_THRESHOLD ,pszDEF_FOLDER_FILE_COUNT_THRESHOLD ,vtypeLONG,vflPERM ,fnvcvLong }, {pszVAR_FOLDER_SIZE_THRESHOLD ,pszDEF_FOLDER_SIZE_THRESHOLD ,vtypeLONG,vflPERM ,fnvcvLong }, {pszVAR_GENERATE_INF ,pszDEF_GENERATE_INF ,vtypeBOOL,vflPERM ,fnvcvBool }, {pszVAR_INF_CAB_HEADER ,pszDEF_INF_CAB_HEADER ,vtypeSTR ,vflPERM|vflCOPY,NULL }, {pszVAR_INF_CAB_LINE_FMT ,pszDEF_INF_CAB_LINE_FMT ,vtypeSTR ,vflPERM|vflCOPY,NULL }, {pszVAR_INF_COMMENT_STRING ,pszDEF_INF_COMMENT_STRING ,vtypeSTR ,vflPERM|vflCOPY,NULL }, {pszVAR_INF_DATE_FMT ,pszDEF_INF_DATE_FMT ,vtypeSTR ,vflPERM|vflCOPY,fnvcvDateFmt }, {pszVAR_INF_DISK_HEADER ,pszDEF_INF_DISK_HEADER ,vtypeSTR ,vflPERM|vflCOPY,NULL }, {pszVAR_INF_DISK_LINE_FMT ,pszDEF_INF_DISK_LINE_FMT ,vtypeSTR ,vflPERM|vflCOPY,NULL }, {pszVAR_INF_FILE_HEADER ,pszDEF_INF_FILE_HEADER ,vtypeSTR ,vflPERM|vflCOPY,NULL }, {pszVAR_INF_FILE_LINE_FMT ,pszDEF_INF_FILE_LINE_FMT ,vtypeSTR ,vflPERM|vflCOPY,NULL }, {pszVAR_INF_FILE_NAME ,pszDEF_INF_FILE_NAME ,vtypeSTR ,vflPERM ,fnvcvFile }, {pszVAR_INF_FOOTER ,pszDEF_INF_FOOTER ,vtypeSTR ,vflPERM|vflCOPY,NULL }, {pszVAR_INF_FOOTER1 ,pszDEF_INF_FOOTER1 ,vtypeSTR ,vflPERM|vflCOPY,NULL }, {pszVAR_INF_FOOTER2 ,pszDEF_INF_FOOTER2 ,vtypeSTR ,vflPERM|vflCOPY,NULL }, {pszVAR_INF_FOOTER3 ,pszDEF_INF_FOOTER3 ,vtypeSTR ,vflPERM|vflCOPY,NULL }, {pszVAR_INF_FOOTER4 ,pszDEF_INF_FOOTER4 ,vtypeSTR ,vflPERM|vflCOPY,NULL }, {pszVAR_INF_HEADER ,pszDEF_INF_HEADER ,vtypeSTR ,vflPERM|vflCOPY,NULL }, {pszVAR_INF_HEADER1 ,pszDEF_INF_HEADER1 ,vtypeSTR ,vflPERM|vflCOPY,NULL }, {pszVAR_INF_HEADER2 ,pszDEF_INF_HEADER2 ,vtypeSTR ,vflPERM|vflCOPY,NULL }, {pszVAR_INF_HEADER3 ,pszDEF_INF_HEADER3 ,vtypeSTR ,vflPERM|vflCOPY,NULL }, {pszVAR_INF_HEADER4 ,pszDEF_INF_HEADER4 ,vtypeSTR ,vflPERM|vflCOPY,NULL }, {pszVAR_INF_HEADER5 ,pszDEF_INF_HEADER5 ,vtypeSTR ,vflPERM|vflCOPY,NULL }, {pszVAR_INF_HEADER6 ,pszDEF_INF_HEADER6 ,vtypeSTR ,vflPERM|vflCOPY,NULL }, {pszVAR_INF_SECTION_ORDER ,pszDEF_INF_SECTION_ORDER ,vtypeSTR ,vflPERM|vflCOPY,fnvcvSectionOrder}, {pszVAR_MAX_CABINET_SIZE ,pszDEF_MAX_CABINET_SIZE ,vtypeLONG,vflPERM ,fnvcvLong }, {pszVAR_MAX_DISK_FILE_COUNT ,pszDEF_MAX_DISK_FILE_COUNT ,vtypeLONG,vflPERM ,fnvcvMaxDiskFileCount}, {pszVAR_MAX_DISK_SIZE ,pszDEF_MAX_DISK_SIZE ,vtypeLONG,vflPERM ,fnvcvMaxDiskSize}, {pszVAR_MAX_ERRORS ,pszDEF_MAX_ERRORS ,vtypeLONG,vflPERM ,fnvcvLong }, {pszVAR_RESERVE_PER_CABINET ,pszDEF_RESERVE_PER_CABINET ,vtypeLONG,vflPERM ,fnvcvLong }, {pszVAR_RESERVE_PER_DATA_BLOCK ,pszDEF_RESERVE_PER_DATA_BLOCK ,vtypeLONG,vflPERM ,fnvcvLong }, {pszVAR_RESERVE_PER_FOLDER ,pszDEF_RESERVE_PER_FOLDER ,vtypeLONG,vflPERM ,fnvcvLong }, {pszVAR_RPT_FILE_NAME ,pszDEF_RPT_FILE_NAME ,vtypeSTR ,vflPERM ,fnvcvFile }, {pszVAR_DIR_SRC ,pszDEF_DIR_SRC ,vtypeSTR ,vflPERM ,fnvcvDirSrc }, {pszVAR_UNIQUE_FILES ,pszDEF_UNIQUE_FILES ,vtypeBOOL,vflPERM ,fnvcvBool }, }; //** acsatMap -- Map command string to command type typedef struct { char *pszName; // Command string COMMANDTYPE ct; // Command type } COMMAND_STRING_AND_TYPE; /* csat */ COMMAND_STRING_AND_TYPE acsatMap[] = { { pszCMD_DEFINE , ctDEFINE }, // Define { pszCMD_DELETE , ctDELETE }, // Delete { pszCMD_DUMP , ctDUMP }, // Dump { pszCMD_INF_BEGIN , ctINF_BEGIN }, // InfBegin { pszCMD_INF_END , ctINF_END }, // InfEnd { pszCMD_INF_WRITE , ctINF_WRITE }, // InfWrite { pszCMD_INF_WRITE_CAB , ctINF_WRITE_CAB }, // InfWriteCabinet { pszCMD_INF_WRITE_DISK , ctINF_WRITE_DISK }, // InfWriteDisk { pszCMD_NEW , ctNEW }, // New { pszCMD_OPTION , ctOPTION }, // Option { pszCMD_SET , ctSET }, // Set { NULL , ctBAD }, // end of list }; /*** mds -- Map special disk size strings to disk attributes * * Data for the amds[] array was gathered using CHKDSK to report * the cluster size and disk size, and a QBASIC program was used * to fill up the root directory. */ typedef struct { char *pszSpecial; // Name used in directive file char *pszFilesInRoot; // Maximum number of files in root dir char *pszClusterSize; // Cluster size in bytes char *pszDiskSize; // Disk size in bytes } MAP_DISK_SIZE; /* mds */ MAP_DISK_SIZE amds[] = { // tag nFiles cbCluster cbDisk //-------------- ------- --------- ------------ {pszVALUE_360K , "112", "1024", "362496"}, // 360K floppy disk {pszVALUE_720K , "112", "1024", "730112"}, // 720K floppy disk {pszVALUE_120M , "224", "512", "1213952"}, // 1.2M floppy disk {pszVALUE_125M , "192", "1024", "1250304"}, // 1.25M (NEC Japan) {pszVALUE_144M , "224", "512", "1457664"}, // 1.44M floppy disk {pszVALUE_168M , "16", "2048", "1716224"}, // DMF "1.68M" floppy {pszVALUE_DMF168, "16", "2048", "1716224"}, // DMF "1.68M" floppy {pszVALUE_CDROM , "65535", "2048", "681984000"}, // 5 1/4" CD-ROM //NOTE: 12-Mar-1994 bens This info supplied by rickdew (Rick Dewitt) // // Standard CD has 74-minute capacity. // Sector size is 2K. // Sectors per minute is 75. // Number of sectors = 74*60*75 = 333,000 // Total bytes = 333,000*2048 = 681,984,000 // Number of files in the root is unlimited, but MS-DOS limits to 64K }; #define nmds (sizeof(amds)/sizeof(MAP_DISK_SIZE)) //*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* // // Exported Functions // //*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* /*** DFPInit - initialize directive file parser * * NOTE: See dfparse.h for entry/exit conditions. */ HVARLIST DFPInit(PSESSION psess,PERROR perr) { HVARLIST hvlist; int i; // Create variable list if (!(hvlist = VarCreateList(perr))) { return NULL; } //** Define standard variables for (i=0; i<(sizeof(aiv)/sizeof(INITVAR)); i++) { if (!VarCreate(hvlist, aiv[i].pszName, aiv[i].pszValue, aiv[i].vtype, aiv[i].vfl, aiv[i].pfnvcv, perr)) { //** Embellish standard VarCreate error message strcpy(psess->achMsg,perr->ach); // Save error ErrSet(perr,pszDFPERR_CREATE_STD_VAR, "%s%s",aiv[i].pszName,psess->achMsg); return NULL; } } //** Success return hvlist; } /*** DFPParse - Parse a directive file * * NOTE: See dfparse.h for entry/exit conditions. */ BOOL DFPParse(PSESSION psess, HTEXTFILE htfDF, PFNDIRFILEPARSE pfndfp, PERROR perr) { COMMAND cmd; char achLine[cbMAX_DF_LINE]; int iLine; AssertSess(psess); SetAssertSignature((&cmd),sigCOMMAND); iLine = 0; //** Parse directives while (!TFEof(htfDF)) { //** Get a line if (!TFReadLine(htfDF,achLine,sizeof(achLine),perr)) { if (TFEof(htfDF)) { // No Error return TRUE; } else { // Something is amiss return FALSE; } } iLine++; // Count it perr->iLine = iLine; // Set line number for error messages perr->pszLine = achLine; // Set line ptr for error messages //** Echo line to output, if verbosity level high enough if (psess->levelVerbose >= vbMORE) { printf("%d: %s\n",iLine,achLine); } //** Parse it getCmdFromLine(&cmd,psess,achLine,perr); // Note: Errors in perr are handled by the client! //** Give it to client if (!(*pfndfp)(psess,&cmd,htfDF,achLine,iLine,perr)) { ClearAssertSignature((&cmd)); return FALSE; } } //** Clear signature ClearAssertSignature((&cmd)); //** Success return TRUE; } /*** DFPParseVarAssignment - Parse var=value string * * NOTE: See dfparse.h for entry/exit conditions. */ BOOL DFPParseVarAssignment(PCOMMAND pcmd, PSESSION psess, char *pszArg, PERROR perr) { //BUGBUG 11-Feb-1994 bens var1=%var2% broken if var2 has trailing spaces // The problem is that we do variable substitution before any other // parsing takes place, so the following directives: // .set var2="one " // .set var1=%var2% // Cause us to see the second line as: // .set var1=one // and store "one", not "one " as the user might have expected. // int cch; char *pch; char *pchEnd; AssertCmd(pcmd); AssertSess(psess); pch = pszArg; //** Make sure a variable name is present if (*pch == '\0') { ErrSet(perr,pszDFPERR_MISSING_VAR_NAME,"%s",pszCMD_SET); return FALSE; } //** Find end of variable name // Var = Value // ^ pchEnd = strpbrk(pch,szDF_SET_CMD_DELIM); // Point after var name // Var = Value // ^ if (pchEnd == NULL) { // No assignment operator ErrSet(perr,pszDFPERR_MISSING_EQUAL,"%c",chDF_EQUAL); return FALSE; } //** Make sure variable name is not too long cch = pchEnd - pch; if (cch >= cbVAR_NAME_MAX) { ErrSet(perr,pszDFPERR_VAR_NAME_TOO_LONG,"%d%s",cbVAR_NAME_MAX-1,pch); return FALSE; } //** Copy var name to command structure, and NUL terminate string memcpy(pcmd->set.achVarName,pch,cch); pcmd->set.achVarName[cch] = '\0'; //** Make sure assignment operator is present // Var = Value // ^ pch = pchEnd + strspn(pchEnd,szDF_WHITE_SPACE); // Var = Value // ^ if (*pch != chDF_EQUAL) { ErrSet(perr,pszDFPERR_MISSING_EQUAL,"%c",chDF_EQUAL); return FALSE; } //** Skip to value. NOTE: Value can be empty, we permit that! // Var = Value // ^ pch++; // Skip over assignment operator pch += strspn(pch,szDF_WHITE_SPACE); // Skip over white space // Var = Value // ^ //** Now parse through possibly quoted strings, to end of value // REMEMBER: We have to trim trailing whitespace return processLineWithQuotes(pcmd->set.achValue, // destination sizeof(pcmd->set.achValue), // dest size pch, // source szDF_QUOTE_SET, // quoting set pszDFP_VAR_VALUE, // field name perr); } /* DFPParseVarAssignment() */ /*** IsSpecialDiskSize - Check if supplied size is a standard one * * NOTE: See dfparse.h for entry/exit conditions. */ long IsSpecialDiskSize(PSESSION psess,char *pszDiskSize) { int i; i = IMDSfromPSZ(pszDiskSize); // See if special value if (i != -1) { // Got a special value return atol(amds[i].pszDiskSize); // Return disk size } else { // Not special return 0; } } /* IsSpecialDiskSize() */ /*** lineOut - write line to stdout with padding * * NOTE: See dfparse.h for entry/exit conditions. */ void lineOut(PSESSION psess, char *pszLine, BOOL fLineFeed) { int cch; char *pszBlanks; //** Do /P (pause) processing AssertSess(psess); //BUGBUG 21-Feb-1994 bens Do screen pausing (/P) //** Determine how much blank padding, if any, is needed cch = strlen(pszLine); // Length of line to be written if (cch >= psess->cchLastLine) { pszBlanks = psess->achBlanks + cchSCREEN_WIDTH; // Empty } else { pszBlanks = psess->achBlanks + cchSCREEN_WIDTH - (psess->cchLastLine - cch); } //** Print the line if (fLineFeed) { printf("%s%s\n",pszLine,pszBlanks); cch = 0; // Nothing to overwrite next time } else { printf("%s%s\r",pszLine,pszBlanks); } psess->fNoLineFeed = !fLineFeed; //** Remember how much to overwrite for next time psess->cchLastLine = cch; // For overwrite next time } /* lineOut() */ //*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* // // Private Functions // //*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* /*** getCmdFromLine - Construct a command from a directive line * * Entry: * pcmd - Command to fill in after line is parsed * psess - Session state * pszLine - Line to parse * perr - ERROR structure * * Exit-Success: * Returns TRUE; pcmd filled in * * Exit-Failure: * Returns FALSE; perr filled in with error. */ BOOL getCmdFromLine(PCOMMAND pcmd, PSESSION psess, char *pszLine, PERROR perr) { char achLine[cbMAX_DF_LINE]; // Variable-substituted line int cbDst; char *pch; // Used to parse pszLine char *pszSrc; char *pszDst; AssertSess(psess); pch = pszLine + strspn(pszLine,szDF_WHITE_SPACE); // Skip leading space //** Do variable substitution if not in copy to INF mode if (psess->fCopyToInf) { // Don't edit lines going to INF pszDst = achLine; cbDst = sizeof(achLine); pszSrc = pszLine; if (!copyBounded(&pszDst,&cbDst,&pszSrc,0)) { return FALSE; } } else { //** Edit lines that are NOT going straight to an INF area //** Perform variable substitution on line, including stripping // comments and any trailing white space! if (!substituteVariables(achLine,sizeof(achLine), pszLine,psess->hvlist,perr)) { return FALSE; // perr already filled in } } //** Determine the command type, and parse it pcmd->ct = ctBAD; // Catch errors pch = achLine + strspn(achLine,szDF_WHITE_SPACE); // Skip leading space //** Check for comment lines and blank lines if ((*pch == chDF_COMMENT) || // Only a comment on the line (*pch == '\0') ) { // Line is completely blank pcmd->ct = ctCOMMENT; return TRUE; } //** Check for directives, etc. //** JEFFWE - Allow .\file and ..\file even if command prefix is '.' if ((*pch == chDF_CMD_PREFIX) && ((chDF_CMD_PREFIX != '.') || (*(pch+1) != '.') && (*(pch+1) != '\\'))) { if (!getCommand(pcmd,psess,achLine,perr)) { return FALSE; } } else if (psess->fCopyToInf) { //** Copy a line to an area of the INF file pcmd->ct = ctINF_WRITE; // Set command type pcmd->inf.inf = psess->inf; // Use area specified by .InfBegin pszDst = pcmd->inf.achLine; cbDst = sizeof(pcmd->inf.achLine); pszSrc = achLine; if (!copyBounded(&pszDst,&cbDst,&pszSrc,0)) { return FALSE; } } else if (psess->fExpectFileCommand) { //** A file specification if (!parseFileLine(pcmd,psess,achLine,perr)) { return FALSE; } } else { //** An INF file reference if (!parseReferenceLine(pcmd,psess,achLine,perr)) { return FALSE; } } //** Success return TRUE; } /*** getCommand - Parse a directive command line * * Entry: * pcmd - Command to fill in after line is parsed * psess - Session state * pszLine - Line to parse (already known to have command start char) * perr - ERROR structure * * Exit-Success: * Returns TRUE; pcmd filled in * * Exit-Failure: * Returns FALSE; perr filled in with error. */ BOOL getCommand(PCOMMAND pcmd, PSESSION psess, char *pszLine, PERROR perr) { char achCmd[cbMAX_COMMAND_NAME]; // Command name int cbDst; int cch; COMMANDTYPE ct; char *pch; // Used to parse pszLine char *pchEnd; // Used to parse pszLine char *pszSrc; char *pszDst; AssertCmd(pcmd); AssertSess(psess); //** Skip to start of command name pch = pszLine + strspn(pszLine,szDF_WHITE_SPACE); // Skip white space Assert(*pch == chDF_CMD_PREFIX); pch++; // Skip command character //** Find end of command name; // Compute length of command name pchEnd = strpbrk(pch,szDF_WHITE_SPACE); // Point at first char after cmd if (pchEnd == NULL) { // Command name runs to end of line cch = strlen(pch); } else { cch = pchEnd - pch; } //** Copy command name to local buffer if (cch >= cbMAX_COMMAND_NAME) { ErrSet(perr,pszDFPERR_CMD_NAME_TOO_LONG,"%s",pszLine); return FALSE; } memcpy(achCmd,pch,cch); // Copy it achCmd[cch] = '\0'; // Terminate it //** See if it really is a command if (ctBAD == (ct = ctFromCommandString(achCmd,perr))) { return FALSE; // perr has error } //** Set command type pcmd->ct = ct; //** Find start of first argument (if any) // pch = start of command name // cch = length of command name pch += cch; // Point to where argument could start pch += strspn(pch,szDF_WHITE_SPACE); // Skip over white space //** Parse remainder of command, as appropriate // pch = start of first argument (will be '\0' if no arguments present) switch (ct) { case ctCOMMENT: return TRUE; // Nothing to do case ctDEFINE: //** Syntax is identical to .Set command return parseSetCommand(pcmd,psess,pch,perr); case ctDUMP: // Dump variable settings to stdout return TRUE; case ctDELETE: //** Make sure a variable name is present if (*pch == '\0') { ErrSet(perr,pszDFPERR_MISSING_VAR_NAME,"%s",pszCMD_DELETE); return FALSE; } //** Make sure only one variable name is present pchEnd = strpbrk(pch,szDF_WHITE_SPACE); // Skip to end of var name if (pchEnd != NULL) { ErrSet(perr,pszDFPERR_BAD_FORMAT,"%s%s",pszCMD_DELETE,pch); return FALSE; } //** Save variable name pszDst = pcmd->delete.achVarName; cbDst = sizeof(pcmd->delete.achVarName); pszSrc = pch; if (!copyBounded(&pszDst,&cbDst,&pszSrc,0)) { return FALSE; } return TRUE; case ctINF_BEGIN: if (_stricmp(pch,pszBEGIN_FILE) == 0) { psess->inf = infFILE; } else if (_stricmp(pch,pszBEGIN_CAB) == 0) { psess->inf = infCABINET; } else if (_stricmp(pch,pszBEGIN_DISK) == 0) { psess->inf = infDISK; } else { ErrSet(perr,pszDFPERR_UNKNOWN_KEYWORD,"%s%s",pszCMD_INF_BEGIN,pch); return FALSE; } psess->fCopyToInf = TRUE; // Turn on copy mode return TRUE; case ctINF_END: if (!psess->fCopyToInf) { // Not in .InfBegin block ErrSet(perr,pszDFPERR_END_WITHOUT_BEGIN,"%s%s", pszCMD_INF_END,pszCMD_INF_BEGIN); return FALSE; } psess->fCopyToInf = FALSE; // Turn off copy mode psess->inf = infBAD; return TRUE; case ctINF_WRITE: case ctINF_WRITE_CAB: case ctINF_WRITE_DISK: //** Do quote processing and save result in pcmd if (!processLineWithQuotes(pcmd->inf.achLine, // destination sizeof(pcmd->inf.achLine), // dest size pch, // source szDF_QUOTE_SET, // quoting set pszDFP_INF_WRITE_STRING, // field name perr)) { return FALSE; } //** Set are of INF to write switch (ct) { case ctINF_WRITE: pcmd->inf.inf = infFILE; break; case ctINF_WRITE_CAB: pcmd->inf.inf = infCABINET; break; case ctINF_WRITE_DISK: pcmd->inf.inf = infDISK; break; default: Assert(0); } //** Map to single INF write command pcmd->ct = ctINF_WRITE; return TRUE; case ctNEW: if (_stricmp(pch,pszNEW_FOLDER) == 0) { pcmd->new.nt = newFOLDER; } else if (_stricmp(pch,pszNEW_CABINET) == 0) { pcmd->new.nt = newCABINET; } else if (_stricmp(pch,pszNEW_DISK) == 0) { pcmd->new.nt = newDISK; } else { ErrSet(perr,pszDFPERR_UNKNOWN_KEYWORD,"%s%s",pszCMD_NEW,pch); pcmd->new.nt = newBAD; return FALSE; } return TRUE; case ctOPTION: pcmd->opt.of = 0; // Default is NO