2141 lines
70 KiB
C
2141 lines
70 KiB
C
/*** 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 <string.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
|
|
#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 <eos>
|
|
// ^
|
|
pchEnd = strpbrk(pch,szDF_SET_CMD_DELIM); // Point after var name
|
|
|
|
// Var = Value <eos>
|
|
// ^
|
|
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 <eos>
|
|
// ^
|
|
pch = pchEnd + strspn(pchEnd,szDF_WHITE_SPACE);
|
|
// Var = Value <eos>
|
|
// ^
|
|
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 <eos>
|
|
// ^
|
|
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<option>
|
|
pcmd->opt.ofMask = 0; // No options specified
|
|
|
|
//** Construct negated string
|
|
strcpy(psess->achMsg,pszOPTION_NEG_PREFIX);
|
|
strcat(psess->achMsg,pszOPTION_EXPLICIT);
|
|
|
|
if (_stricmp(pch,pszOPTION_EXPLICIT) == 0) {
|
|
pcmd->opt.of |= optEXPLICIT; // Explicit is on
|
|
pcmd->opt.ofMask |= optEXPLICIT; // Explicit was set
|
|
}
|
|
else if (_stricmp(pch,psess->achMsg) == 0) {
|
|
pcmd->opt.of &= ~optEXPLICIT; // Explicit is off
|
|
pcmd->opt.ofMask |= optEXPLICIT; // Explicit was set
|
|
}
|
|
else {
|
|
ErrSet(perr,pszDFPERR_UNKNOWN_KEYWORD,"%s%s",pszCMD_OPTION,pch);
|
|
pcmd->new.nt = newBAD;
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
|
|
case ctSET:
|
|
return parseSetCommand(pcmd,psess,pch,perr);
|
|
|
|
case ctBAD: // Bad command
|
|
case ctFILE: // Caller handles file copy lines
|
|
case ctREFERENCE: // Caller handles reference lines
|
|
default:
|
|
Assert(0); // Should never get here
|
|
return FALSE;
|
|
} /* switch (ct) */
|
|
|
|
Assert(0); // Should never get here
|
|
} /* getCommand */
|
|
|
|
|
|
/*** parseSetCommand - Parse arguments to .SET command
|
|
*
|
|
* Entry:
|
|
* pcmd - Command to fill in after line is parsed
|
|
* psess - Session state
|
|
* pszArg - Start of argument string (var=value or var="value")
|
|
* perr - ERROR structure
|
|
*
|
|
* Exit-Success:
|
|
* Returns TRUE; pcmd filled in
|
|
*
|
|
* Exit-Failure:
|
|
* Returns FALSE; perr filled in with error.
|
|
*
|
|
* Syntax:
|
|
* .SET var=value
|
|
* .SET var="value"
|
|
*/
|
|
BOOL parseSetCommand(PCOMMAND pcmd, PSESSION psess, char *pszArg, PERROR perr)
|
|
{
|
|
|
|
//** Parse var=value
|
|
if (!DFPParseVarAssignment(pcmd,psess,pszArg,perr)) {
|
|
return FALSE;
|
|
}
|
|
|
|
//** Show parsed var name and value
|
|
if (psess->levelVerbose >= vbFULL) {
|
|
MsgSet(psess->achMsg,pszDFP_PARSED_SET_CMD,
|
|
"%s%s",pcmd->set.achVarName,pcmd->set.achValue);
|
|
printf("%s\n",psess->achMsg);
|
|
}
|
|
|
|
//** Success
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*** processLineWithQuotes - Run getQuotedString over the entire line
|
|
*
|
|
* Entry:
|
|
* pszDst - Buffer to receive parsed value
|
|
* cbDst - Size of pszDst buffer
|
|
* pszSrc - String to parse
|
|
* pszQuotes - String of characters that act as quote characters
|
|
* pszFieldName - Name of field being parsed (for error message)
|
|
* perr - ERROR structure
|
|
*
|
|
* Exit-Success:
|
|
* Returns TRUE; pszDst filled in with processed string version of pszSrc
|
|
* -- quote characters are processed and removed as appropriate, and
|
|
* trailing blanks (outside of quotes) are removed.
|
|
*
|
|
* Exit-Failure:
|
|
* Returns FALSE; perr filled in with error.
|
|
* Possible errors: Incorrect delimiter format;
|
|
* String too large for pszDst buffer
|
|
*
|
|
* Syntax of pszSrc is:
|
|
* See getQuotedString for details, but essentially this function
|
|
* permits the following sorts of effects:
|
|
* " foo " => < foo >
|
|
* foo => <foo>
|
|
* " "foo => < foo>
|
|
*/
|
|
BOOL processLineWithQuotes(char *pszDst,
|
|
int cbDst,
|
|
char *pszSrc,
|
|
char *pszDelim,
|
|
char *pszFieldName,
|
|
PERROR perr)
|
|
{
|
|
int cch;
|
|
int cchValue;
|
|
char *pch;
|
|
char *pchValue;
|
|
|
|
*pszDst = '\0';
|
|
pch = pszSrc;
|
|
|
|
while (*pch) {
|
|
//** Point at end of value gathered so far
|
|
cchValue = strlen(pszDst);
|
|
pchValue = pszDst + cchValue;
|
|
|
|
//** Copy (possibly quoted) token
|
|
pch = getQuotedString(pchValue,
|
|
cbDst - cchValue,
|
|
pch,
|
|
szDF_QUOTE_SET,
|
|
pszDFP_INF_WRITE_STRING, // Name of field
|
|
perr);
|
|
//** Value More <eos>
|
|
// ^
|
|
if (pch == NULL) {
|
|
return FALSE; // Syntax error or buffer overflow
|
|
}
|
|
|
|
//** Update current position in destination and size
|
|
cchValue = strlen(pszDst);
|
|
pchValue = pszDst + cchValue;
|
|
|
|
//** Count white space, but copy only if it doesn't end string
|
|
cch = strspn(pch,szDF_WHITE_SPACE);
|
|
if (*(pch+cch) != '\0') { // Have to copy white space
|
|
while ((cch>0) && (cchValue<cbDst)) {
|
|
*pchValue++ = *pch++; // Copy character
|
|
cchValue++; // Count for buffer overflow test
|
|
cch--;
|
|
}
|
|
if (cchValue >= cbDst) {
|
|
ErrSet(perr,pszDFPERR_STRING_TOO_LONG,"%s%d",
|
|
pszDFP_INF_WRITE_STRING,cbDst-1);
|
|
return FALSE;
|
|
}
|
|
*pchValue = '\0'; // Keep string well-formed
|
|
}
|
|
else {
|
|
pch += cch; // Make sure we terminate loop
|
|
}
|
|
}
|
|
|
|
//** Success
|
|
return TRUE;
|
|
} /* processLineWithQuotes() */
|
|
|
|
|
|
/*** getQuotedString - Parse value that may be delimited
|
|
*
|
|
* Entry:
|
|
* pszDst - Buffer to receive parsed value
|
|
* cbDst - Size of pszDst buffer
|
|
* pszSrc - String to parse
|
|
* pszQuotes - String of characters that act as quote characters
|
|
* pszFieldName - Name of field being parsed (for error message)
|
|
* perr - ERROR structure
|
|
*
|
|
* Exit-Success:
|
|
* Returns pointer to first character after parsed string in pszSrc;
|
|
* pszDst filled in with null-terminated string
|
|
*
|
|
* Exit-Failure:
|
|
* Returns NULL; perr filled in with error.
|
|
* Possible errors: Incorrect delimiter format;
|
|
* String too large for pszDst buffer
|
|
*
|
|
* Notes:
|
|
* (1) If the first character of the string is in the set pszDelim,
|
|
* then that character is taken to be the *quote* character, and
|
|
* is used to find the end of the string. The leading and trailing
|
|
* quote characters are not copied to the pszDst buffer.
|
|
* EXAMPLE: <"a phrase"> becomes <a phrase>
|
|
*
|
|
* (2) If the first character is not in the set pszDelim, then whitespace
|
|
* signals the end of the string.
|
|
* EXAMPLE: <two words> becomes <two>
|
|
*
|
|
* (3) If the *quote* character is found immediately following itself
|
|
* inside the string, then it is replaced by a single copy of the
|
|
* *quote* character and copied to pszDst.
|
|
* EXAMPLE: <"He said ""Hi!"" again"> becomes <He said "Hi!" again>
|
|
*/
|
|
char *getQuotedString(char *pszDst,
|
|
int cbDst,
|
|
char *pszSrc,
|
|
char *pszQuotes,
|
|
char *pszFieldName,
|
|
PERROR perr)
|
|
{
|
|
int cch;
|
|
char chQuote; // Quote character
|
|
char *pch; // Start of piece
|
|
char *pchDst; // Current location in pszDst
|
|
char *pchEnd; // End of piece
|
|
|
|
Assert(cbDst>0);
|
|
|
|
//** Early out for empty string
|
|
if (*pszSrc == '\0') {
|
|
*pszDst = *pszSrc; // Store empty string
|
|
return pszSrc; // Success (pointer does not move)
|
|
}
|
|
|
|
//** See if first character of string is a quote
|
|
for (pch=pszQuotes; (*pch != '\0') && (*pch != pszSrc[0]); pch++) {
|
|
//** Scan through pszQuotes looking for a match
|
|
}
|
|
if (*pch == '\0') { // String is not quoted
|
|
//** Get string length
|
|
pchEnd = strpbrk(pszSrc,szDF_WHITE_SPACE);
|
|
if (pchEnd == NULL) {
|
|
cch = strlen(pszSrc);
|
|
pchEnd = pszSrc + cch;
|
|
}
|
|
else {
|
|
cch = pchEnd - pszSrc;
|
|
}
|
|
//** Make sure buffer can hold it
|
|
if (cch >= cbDst) { // Won't fit in buffer (need NUL, still)
|
|
//** Use field name, and show max string length as one less,
|
|
// since that count includes room for a NUL byte.
|
|
ErrSet(perr,pszDFPERR_STRING_TOO_LONG,"%s%d",pszFieldName,cbDst-1);
|
|
return NULL; // FAILURE
|
|
}
|
|
memcpy(pszDst,pszSrc,cch);
|
|
pszDst[cch] = '\0';
|
|
return pchEnd; // SUCCESS
|
|
}
|
|
|
|
//** Handle quoted string
|
|
chQuote = *pszSrc; // Remember the quote character
|
|
pch = pszSrc+1; // Skip over quote character
|
|
pchDst = pszDst; // Location to add chars to pszDst
|
|
|
|
//** Copy characters until end of string or quote error or buffer overflow
|
|
while ((*pch != '\0') && ((pchDst-pszDst) < cbDst)) {
|
|
if (*pch == chQuote) { // Got another quote
|
|
//** Check for "He said ""Hi"" again" case
|
|
if (*(pch+1) == chQuote) { // Need to collapse two quotes
|
|
*pchDst++ = *pch++; // Copy a single quote
|
|
pch++; // Skip the 2nd quote
|
|
}
|
|
else { // String is fine, finish and succeed
|
|
*pchDst++ = '\0'; // Terminate string
|
|
return pch+1; // Return pointer after string
|
|
}
|
|
}
|
|
else { // Normal character
|
|
*pchDst++ = *pch++; // Just copy it
|
|
}
|
|
}
|
|
|
|
//** Either we overflowed the buffer, or we missed a closing quote
|
|
if ((pchDst-pszDst) >= cbDst) {
|
|
ErrSet(perr,pszDFPERR_STRING_TOO_LONG,"%s%d",pszFieldName,cbDst-1);
|
|
}
|
|
else {
|
|
Assert(*pch == '\0');
|
|
ErrSet(perr,pszDFPERR_MISSING_QUOTE,"%c%s",chQuote,pszFieldName);
|
|
}
|
|
return NULL; // FAILURE
|
|
}
|
|
|
|
|
|
/*** ctFromCommandString - Map command string to command type
|
|
*
|
|
* Entry:
|
|
* pszCmd - String to check against command list
|
|
* perr - ERROR structure
|
|
*
|
|
* Exit-Success:
|
|
* Returns COMMANDTYPE corresponding to pszCmd.
|
|
*
|
|
* Exit-Failure:
|
|
* Returns ctBAD; perr filled in with error.
|
|
*/
|
|
COMMANDTYPE ctFromCommandString(char *pszCmd, PERROR perr)
|
|
{
|
|
int i;
|
|
|
|
//** Search for matching command
|
|
for (i=0; acsatMap[i].pszName != NULL; i++) {
|
|
if (!(_stricmp(acsatMap[i].pszName,pszCmd))) {
|
|
//** Found command
|
|
return acsatMap[i].ct; // return command type
|
|
}
|
|
}
|
|
|
|
//** Failure
|
|
ErrSet(perr,pszDFPERR_UNKNOWN_COMMAND,"%s",pszCmd);
|
|
return FALSE;
|
|
} /* ctFromCommandString() */
|
|
|
|
|
|
/*** parseReferenceLine - Parse an INF reference 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.
|
|
*
|
|
* Syntax:
|
|
* dstFile [/x1=y [y2=y...]]
|
|
*
|
|
* NOTES:
|
|
* (1) Quotes are allowed in file specs -- can you say Long File Names!
|
|
*/
|
|
BOOL parseReferenceLine(PCOMMAND pcmd,PSESSION psess,char *pszLine,PERROR perr)
|
|
{
|
|
int cFiles=0; // Count of file specs seen
|
|
char *pch;
|
|
BOOL runflag = FALSE;
|
|
|
|
AssertCmd(pcmd);
|
|
AssertSess(psess);
|
|
Assert(psess->ddfmode == ddfmodeRELATIONAL);
|
|
|
|
//** Set command type and default values
|
|
pcmd->ct = ctREFERENCE;
|
|
pcmd->ref.achDst[0] = '\0';
|
|
pcmd->ref.hglist = NULL; // No parameters
|
|
|
|
//** Process line
|
|
pch = pszLine;
|
|
while (*pch != '\0') {
|
|
//** Skip whitespace
|
|
pch += strspn(pch,szDF_WHITE_SPACE); // Skip over white space
|
|
if (*pch == '\0') { // End of line
|
|
break; // Skip loop so we exit
|
|
}
|
|
|
|
//** Is this a file name or a parameter?
|
|
if (*pch == chDF_MODIFIER) { // A parameter
|
|
pch = parseParameterList(&(pcmd->ref.hglist),pch,perr,&runflag);
|
|
if (runflag) {
|
|
ErrSet(perr,pszDFPERR_RUN_ON_REFERENCE);
|
|
goto done;
|
|
}
|
|
}
|
|
else { // A file
|
|
cFiles++;
|
|
if (cFiles > 1) { // Two many file names
|
|
ErrSet(perr,pszDFPERR_EXTRA_JUNK,"%s",pch);
|
|
goto done;
|
|
}
|
|
pch = getQuotedString(pcmd->ref.achDst,
|
|
sizeof(pcmd->ref.achDst),
|
|
pch,
|
|
szDF_QUOTE_SET,
|
|
pszDFPERR_DST_FILE, // Name of field
|
|
perr);
|
|
}
|
|
//** Check for error
|
|
if (pch == NULL) {
|
|
Assert(ErrIsError(perr));
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
done:
|
|
//** Need a destination file
|
|
if ((cFiles == 0) && !ErrIsError(perr)) { // Don't overwrite existing error
|
|
ErrSet(perr,pszDFPERR_MISSING_DST_NAME);
|
|
return FALSE;
|
|
}
|
|
|
|
//** Clean up and exit if an error occured
|
|
if (ErrIsError(perr)) {
|
|
if (pcmd->ref.hglist) { // Destroy parameter list
|
|
GLDestroyList(pcmd->ref.hglist);
|
|
pcmd->ref.hglist = NULL;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
//** Show parsed dst file name
|
|
if (psess->levelVerbose >= vbFULL) {
|
|
MsgSet(psess->achMsg,pszDFP_PARSED_REF_CMD,"%s",pcmd->ref.achDst);
|
|
printf("%s\n",psess->achMsg);
|
|
}
|
|
|
|
//** Success
|
|
return TRUE;
|
|
} /* parseReferenceLine() */
|
|
|
|
|
|
/*** parseFileLine - Parse a file specification 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.
|
|
*
|
|
* Syntax:
|
|
* srcFile [dstFile] [/x1=y [y2=y...]]
|
|
*
|
|
* NOTES:
|
|
* (1) Quotes are allowed in file specs -- can you say Long File Names!
|
|
*/
|
|
BOOL parseFileLine(PCOMMAND pcmd, PSESSION psess, char *pszLine, PERROR perr)
|
|
{
|
|
int cFiles=0; // Count of file specs seen
|
|
char *pch;
|
|
BOOL runflag = FALSE;
|
|
|
|
AssertCmd(pcmd);
|
|
AssertSess(psess);
|
|
|
|
//** Set command type and default values
|
|
pcmd->ct = ctFILE;
|
|
pcmd->file.achSrc[0] = '\0';
|
|
pcmd->file.achDst[0] = '\0';
|
|
pcmd->file.hglist = NULL; // No parameters
|
|
pcmd->file.fRunFlag = FALSE;
|
|
|
|
//** Process line
|
|
pch = pszLine;
|
|
while (*pch != '\0') {
|
|
//** Skip whitespace
|
|
pch += strspn(pch,szDF_WHITE_SPACE); // Skip over white space
|
|
if (*pch == '\0') { // End of line
|
|
break; // Skip loop so we exit
|
|
}
|
|
|
|
//** Is this a file name or a parameter?
|
|
if (*pch == chDF_MODIFIER) { // A parameter
|
|
pch = parseParameterList(&(pcmd->file.hglist),pch,perr,&runflag);
|
|
if (runflag == TRUE) {
|
|
if (psess->fRunSeen == TRUE) {
|
|
ErrSet(perr, pszDFPERR_MULTIPLE_RUN);
|
|
goto done;
|
|
}
|
|
psess->fRunSeen = TRUE;
|
|
pcmd->file.fRunFlag = TRUE;
|
|
}
|
|
|
|
}
|
|
else { // A file
|
|
cFiles++;
|
|
if (cFiles > 2) { // Two many file names
|
|
ErrSet(perr,pszDFPERR_EXTRA_JUNK,"%s",pch);
|
|
goto done;
|
|
}
|
|
if (cFiles == 1) { // Get SOURCE file name
|
|
pch = getQuotedString(pcmd->file.achSrc,
|
|
sizeof(pcmd->file.achSrc),
|
|
pch,
|
|
szDF_QUOTE_SET,
|
|
pszDFPERR_SRC_FILE, // Name of field
|
|
perr);
|
|
}
|
|
else { // Get DESTINATION file name
|
|
pch = getQuotedString(pcmd->file.achDst,
|
|
sizeof(pcmd->file.achDst),
|
|
pch,
|
|
szDF_QUOTE_SET,
|
|
pszDFPERR_DST_FILE, // Name of field
|
|
perr);
|
|
}
|
|
}
|
|
//** Check for error
|
|
if (pch == NULL) {
|
|
Assert(ErrIsError(perr));
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
done:
|
|
//** Need at least a source file
|
|
if ((cFiles == 0) && !ErrIsError(perr)) { // Don't overwrite existing error
|
|
ErrSet(perr,pszDFPERR_MISSING_SRC_NAME);
|
|
return FALSE;
|
|
}
|
|
|
|
//** Clean up and exit if an error occured
|
|
if (ErrIsError(perr)) {
|
|
if (pcmd->file.hglist) { // Destroy parameter list
|
|
GLDestroyList(pcmd->file.hglist);
|
|
pcmd->file.hglist = NULL;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
//** Show parsed src and dst file names
|
|
if (psess->levelVerbose >= vbFULL) {
|
|
MsgSet(psess->achMsg,pszDFP_PARSED_FILE_CMD,
|
|
"%s%s",pcmd->file.achSrc,pcmd->file.achDst);
|
|
printf("%s\n",psess->achMsg);
|
|
}
|
|
|
|
//** Success
|
|
return TRUE;
|
|
} /* parseFileLine() */
|
|
|
|
|
|
/*** parseParameterList - Parse /X=Y parameter list into an HGENLIST
|
|
*
|
|
* Entry:
|
|
* phglist - Pointer to hglist
|
|
* pch - Pointer to /X=Y string
|
|
* perr - ERROR structure
|
|
*
|
|
* Exit-Success:
|
|
* Returns updated pch, pointing to first character after parsed
|
|
* parameter; *phglist created/updated
|
|
*
|
|
* Exit-Failure;
|
|
* Returns NULL; perr filled in.
|
|
*/
|
|
char *parseParameterList(HGENLIST *phglist, char *pch, PERROR perr, BOOL *runflg)
|
|
{
|
|
char achName[cbPARM_NAME_MAX]; // Name buffer
|
|
char achValue[cbMAX_DF_LINE]; // Value buffer
|
|
int cch;
|
|
char *pchEnd;
|
|
PFILEPARM pfparm;
|
|
|
|
//** Create list if necessary
|
|
if (*phglist == NULL) {
|
|
//** Create parameter list
|
|
*phglist = GLCreateList(NULL, // No default
|
|
DestroyFileParm,
|
|
pszDFP_FILE_PARM,
|
|
perr);
|
|
if (!*phglist) {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
//** Parse name and value
|
|
// /X = Y
|
|
// ^
|
|
Assert(*pch == chDF_MODIFIER); // Must point to '/'
|
|
pch++; // Skip over switch
|
|
|
|
//** Make sure parameter name is present
|
|
if (*pch == '\0') {
|
|
ErrSet(perr,pszDFPERR_MISSING_PARM_NAME);
|
|
return NULL;
|
|
}
|
|
|
|
//** Find end of parameter name
|
|
// /X = Y
|
|
// ^
|
|
pchEnd = strpbrk(pch,szDF_SET_CMD_DELIM); // Point after var name
|
|
|
|
|
|
// /X = Y
|
|
// ^
|
|
if (pchEnd == NULL) { // No assignment operator
|
|
// So, Check for /RUN directive
|
|
if ((strlen(pch) == strlen(pszCMD_RUN))
|
|
&& (strncmp( pch, pszCMD_RUN, strlen(pszCMD_RUN)) == 0)) {
|
|
*runflg = TRUE;
|
|
pch += strlen( pszCMD_RUN );
|
|
return( pch );
|
|
} else {
|
|
ErrSet(perr,pszDFPERR_MISSING_EQUAL,"%c",chDF_EQUAL);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
//** Make sure parameter name is not too long
|
|
cch = pchEnd - pch;
|
|
if (cch >= sizeof(achName)) {
|
|
ErrSet(perr,pszDFPERR_PARM_NAME_TOO_LONG,"%d%s",sizeof(achName)-1,pch);
|
|
return NULL;
|
|
}
|
|
|
|
//** Copy parameter name, NUL terminate string
|
|
memcpy(achName,pch,cch);
|
|
achName[cch] = '\0';
|
|
|
|
//** Make sure assignment operator is present
|
|
// /X = Y
|
|
// ^
|
|
pch = pchEnd + strspn(pchEnd,szDF_WHITE_SPACE);
|
|
// Var = Value <eos>
|
|
// ^
|
|
if (*pch != chDF_EQUAL) {
|
|
ErrSet(perr,pszDFPERR_MISSING_EQUAL,"%c",chDF_EQUAL);
|
|
return NULL;
|
|
}
|
|
|
|
//** Skip to value.
|
|
// /X = Y
|
|
// ^
|
|
// NOTE: Value can be empty, we permit that! We have to distinguish
|
|
// between:
|
|
// /X1= /X2=Y
|
|
// and
|
|
// /X1=/stuff
|
|
//
|
|
pch++; // Skip over assignment operator
|
|
pchEnd = pch; // Remember where we started scanning
|
|
pch += strspn(pch,szDF_WHITE_SPACE); // Skip over white space
|
|
// /X = Y
|
|
// ^
|
|
|
|
if ((*pch == chDF_MODIFIER) && (pch > pchEnd)) {
|
|
//** Got special case of /X1= /X2=Y, value is empty
|
|
achValue[0] = '\0'; // Value is blank
|
|
}
|
|
else {
|
|
pch = getQuotedString(achValue,
|
|
sizeof(achValue),
|
|
pch,
|
|
szDF_QUOTE_SET,
|
|
pszDFP_PARM_VALUE, // Name of field
|
|
perr);
|
|
if (pch == NULL) {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
//** Allocate parameter structure
|
|
if (!(pfparm = MemAlloc(sizeof(FILEPARM)))) {
|
|
ErrSet(perr,pszDFPERR_OUT_OF_MEMORY,"%s",pszDFP_PARM_VALUE);
|
|
return NULL;
|
|
}
|
|
if (!(pfparm->pszValue = MemStrDup(achValue))) {
|
|
ErrSet(perr,pszDFPERR_OUT_OF_MEMORY,"%s",pszDFP_PARM_VALUE);
|
|
MemFree(pfparm);
|
|
return NULL;
|
|
}
|
|
|
|
//** Add parameter to list
|
|
if (!GLAdd(*phglist, // List
|
|
achName, // parameter name
|
|
pfparm, // parameter value structure
|
|
pszDFP_FILE_PARM, // Description for error message
|
|
TRUE, // parameter name must be unique
|
|
perr)) {
|
|
MemFree(pfparm->pszValue);
|
|
MemFree(pfparm);
|
|
return NULL;
|
|
}
|
|
//** Set signature after we get it successfully on the list
|
|
SetAssertSignature(pfparm,sigFILEPARM);
|
|
|
|
//** Return updated parse position
|
|
return pch;
|
|
} /* parseParameterList() */
|
|
|
|
|
|
/*** substituteVariables - Perform variable substitution; strip comments
|
|
*
|
|
* Entry:
|
|
* pszDst - Buffer to receive substituted version of pszSrc
|
|
* cbDst - Size of pszDst
|
|
* pszSrc - String to process
|
|
* hvlist - Variable list
|
|
* perr - ERROR structure
|
|
*
|
|
* Exit-Success:
|
|
* Returns TRUE; pszDst filled in with substituted form
|
|
*
|
|
* Exit-Failure:
|
|
* Returns FALSE; perr filled in with error
|
|
*
|
|
* Substitution rules:
|
|
* (1) Only one level of substitution is performed
|
|
* (2) Variable must be defined in hvlist
|
|
* (3) "%%" is replaced by "%", if the first % is not the end of
|
|
* of a variable substitution.
|
|
* (4) Variable substitution is not performed in quoted strings
|
|
* (5) End-of-line comments are removed
|
|
* (6) Any trailing white space on the line is removed
|
|
*/
|
|
|
|
BOOL substituteVariables(char *pszDst,
|
|
int cbDst,
|
|
char *pszSrc,
|
|
HVARLIST hvlist,
|
|
PERROR perr)
|
|
{
|
|
char achVarName[cbVAR_NAME_MAX];
|
|
int cch;
|
|
char chQuote;
|
|
HVARIABLE hvar;
|
|
char *pch;
|
|
char *pszAfterVar; // Points to first char after var subst.
|
|
char *pszDstSave; // Original pszDst value
|
|
char *pszVarNameStart; // Points to first % in var substitution
|
|
|
|
pszDstSave = pszDst;
|
|
|
|
while (*pszSrc != '\0') {
|
|
switch (*pszSrc) {
|
|
case chDF_QUOTE1:
|
|
case chDF_QUOTE2:
|
|
/*
|
|
* Copy everything up to closing quote, taking care to handle
|
|
* the special case of embedded quotes compatibly with
|
|
* getQuotedString! The main issue is to make sure we
|
|
* correctly determine the end of the quoted string.
|
|
* NOTE: We don't check for quote mismatches here -- we
|
|
* just avoid doing variable substituion of comment
|
|
* character recognition!
|
|
*/
|
|
chQuote = *pszSrc; // Remember the quote character
|
|
pch = pszSrc + 1; // Skip over first quote
|
|
|
|
//** Find end of quoted string
|
|
while (*pch != '\0') {
|
|
if (*pch == chQuote) { // Got a quote
|
|
pch++; // Skip over it
|
|
if (*pch != chQuote) { // Marks the end of quoted str
|
|
break; // Exit loop and copy string
|
|
}
|
|
//** If we didn't break out above, it was because
|
|
// we had an embedded quote (""). The pch++ above
|
|
// skipped over the first quote, and the pch++
|
|
// below skips over the second quote. So, no need
|
|
// for any special code!
|
|
}
|
|
pch++; // Examine next character
|
|
}
|
|
|
|
//** At this point, we've either found the end of the
|
|
// quoted string, or the end of the source buffer.
|
|
// we don't care which, as we don't check for errors
|
|
// in quoted strings. So we just copy what we found
|
|
// and keep going.
|
|
|
|
if (!copyBounded(&pszDst,&cbDst,&pszSrc,pch-pszSrc)) {
|
|
goto error_copying;
|
|
}
|
|
break;
|
|
|
|
case chDF_COMMENT: // Toss rest of line
|
|
goto done; // Finish string and return
|
|
|
|
case chDF_SUBSTITUTE:
|
|
pszVarNameStart = pszSrc; // Save start for error messgages
|
|
pszSrc++; // Skip first %
|
|
if (*pszSrc == chDF_SUBSTITUTE) { // Have "%%"
|
|
//** Collapse two %% into one %
|
|
if (!copyBounded(&pszDst,&cbDst,&pszSrc,1)) {
|
|
goto error_copying;
|
|
}
|
|
}
|
|
else {
|
|
//** Attempt variable substitution
|
|
pch = strchr(pszSrc,chDF_SUBSTITUTE); // Finding ending %
|
|
if (!pch) { // No terminating %
|
|
ErrSet(perr,pszDFPERR_MISSING_SUBST,"%c%s",
|
|
chDF_SUBSTITUTE,pszVarNameStart);
|
|
return FALSE;
|
|
}
|
|
pszAfterVar = pch+1; // Point after ending %
|
|
|
|
//** Extract variable name
|
|
cch = pch - pszSrc; // Length of variable name
|
|
if (cch >= cbVAR_NAME_MAX) {
|
|
ErrSet(perr,pszDFPERR_VAR_NAME_TOO_LONG,"%d%s",
|
|
cbVAR_NAME_MAX-1,pszVarNameStart);
|
|
return FALSE;
|
|
}
|
|
memcpy(achVarName,pszSrc,cch); // Copy it
|
|
achVarName[cch] = '\0'; // Terminate it
|
|
|
|
//** Look up variable
|
|
if (!(hvar = VarFind(hvlist,achVarName,perr))) {
|
|
ErrSet(perr,pszDFPERR_VAR_UNDEFINED,"%s",
|
|
pszVarNameStart);
|
|
return FALSE;
|
|
}
|
|
|
|
//** Substitute variable
|
|
pch = VarGetString(hvar); // Get value
|
|
if (!copyBounded(&pszDst,&cbDst,&pch,0)) {
|
|
ErrSet(perr,pszDFPERR_VAR_SUBST_OVERFLOW,"%s",
|
|
pszVarNameStart);
|
|
return FALSE;
|
|
}
|
|
//** copyBounded appended the NULL byte, but we need to
|
|
// remove that so that any subsequent characters on
|
|
// the line get tacked on!
|
|
pszDst--; // Back up over NULL byte
|
|
cbDst++; // Don't count NULL byte
|
|
|
|
//** Skip over variable name
|
|
pszSrc = pszAfterVar;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
//** Just copy the character
|
|
if (!copyBounded(&pszDst,&cbDst,&pszSrc,1)) {
|
|
goto error_copying;
|
|
}
|
|
break;
|
|
} /* switch */
|
|
} /* while */
|
|
|
|
done:
|
|
//** Terminate processed string
|
|
if (cbDst == 0) { // No room for terminator
|
|
goto error_copying;
|
|
}
|
|
*pszDst++ = '\0'; // Terminate string
|
|
|
|
//** Trim off any trailing white space
|
|
pch = pszDstSave; // Start at front
|
|
while (pch && *pch) { // Process entire string
|
|
//** Skip over non-white space
|
|
pch = strpbrk(pch,szDF_WHITE_SPACE);
|
|
if (pch != NULL) { // Not at the end of the string
|
|
//** Skip over white space
|
|
cch = strspn(pch,szDF_WHITE_SPACE);
|
|
if (*(pch+cch) == '\0') {
|
|
//** We're at the end and we have white space
|
|
*pch = '\0'; // Trim off the white space
|
|
}
|
|
else {
|
|
pch += cch; // Advance to next non-white space
|
|
}
|
|
}
|
|
}
|
|
|
|
//** Success
|
|
return TRUE;
|
|
|
|
error_copying:
|
|
ErrSet(perr,pszDFPERR_COPYING_OVERFLOW,"%s",pszSrc);
|
|
return FALSE;
|
|
} /* substituteVariables */
|
|
|
|
|
|
/*** BOOLfromPSZ - Get boolean from string value
|
|
*
|
|
* NOTE: See dfparse.h for entry/exit conditions.
|
|
*/
|
|
BOOL BOOLfromPSZ(char *psz, PERROR perr)
|
|
{
|
|
if (!strcmp(psz,"0") ||
|
|
!_stricmp(psz,pszVALUE_NO) ||
|
|
!_stricmp(psz,pszVALUE_OFF) ||
|
|
!_stricmp(psz,pszVALUE_FALSE)) {
|
|
return FALSE;
|
|
}
|
|
else if (!strcmp(psz,"1") ||
|
|
!_stricmp(psz,pszVALUE_YES) ||
|
|
!_stricmp(psz,pszVALUE_ON) ||
|
|
!_stricmp(psz,pszVALUE_TRUE)) {
|
|
return TRUE;
|
|
}
|
|
else {
|
|
ErrSet(perr,pszDFPERR_INVALID_BOOL,"%s",psz);
|
|
return -1;
|
|
}
|
|
} /* BOOLfromPSZ() */
|
|
|
|
|
|
/*** ChecksumWidthFromPSZ - Get Checksum Width from a string
|
|
*
|
|
* NOTE: See dfparse.h for entry/exit conditions.
|
|
*/
|
|
int ChecksumWidthFromPSZ(char *psz, PERROR perr)
|
|
{
|
|
int level;
|
|
int levelLo;
|
|
int levelHi;
|
|
|
|
level = atoi(psz);
|
|
levelLo = atoi(pszCW_LOWEST);
|
|
levelHi = atoi(pszCW_HIGHEST);
|
|
|
|
//** Check range
|
|
if ((levelLo <= level) && (level <= levelHi)) {
|
|
return level;
|
|
}
|
|
|
|
//** Level not in valid range
|
|
ErrSet(perr,pszDFPERR_INVALID_CSUM_WIDTH,"%s%s%s",
|
|
pszCW_LOWEST,pszCW_HIGHEST,psz);
|
|
return -1;
|
|
} /* ChecksumWidthFromPSZ() */
|
|
|
|
|
|
/*** CompTypeFromPSZ - Get Compression Type from a string
|
|
*
|
|
* NOTE: See dfparse.h for entry/exit conditions.
|
|
*/
|
|
int CompTypeFromPSZ(char *psz, PERROR perr)
|
|
{
|
|
if (!_stricmp(psz,pszCT_MSZIP)) {
|
|
return tcompTYPE_MSZIP;
|
|
}
|
|
else if (!_stricmp(psz,pszCT_QUANTUM)) {
|
|
#ifdef BIT16
|
|
ErrSet(perr,pszDFPERR_NO_16BIT_QUANTUM);
|
|
return -1;
|
|
#else // !BIT16
|
|
return tcompTYPE_QUANTUM;
|
|
#endif // !BIT16
|
|
}
|
|
else {
|
|
ErrSet(perr,pszDFPERR_INVALID_COMP_TYPE,"%s",psz);
|
|
return -1;
|
|
}
|
|
} /* CompTypeFromPSZ() */
|
|
|
|
|
|
/*** CompLevelFromPSZ - Get Compression Level from a string
|
|
*
|
|
* NOTE: See dfparse.h for entry/exit conditions.
|
|
*/
|
|
int CompLevelFromPSZ(char *psz, PERROR perr)
|
|
{
|
|
int level;
|
|
int levelLo;
|
|
int levelHi;
|
|
|
|
level = atoi(psz);
|
|
levelLo = atoi(pszCL_LOWEST);
|
|
levelHi = atoi(pszCL_HIGHEST);
|
|
|
|
//** Check range
|
|
if ((levelLo <= level) && (level <= levelHi)) {
|
|
return level;
|
|
}
|
|
|
|
//** Level not in valid range
|
|
ErrSet(perr,pszDFPERR_INVALID_COMP_LEVEL,"%s%s%s",
|
|
pszCL_LOWEST,pszCL_HIGHEST,psz);
|
|
return -1;
|
|
} /* CompLevelFromPSZ() */
|
|
|
|
|
|
/*** roundUpToPowerOfTwo - Round up a number to a power of two
|
|
*
|
|
* Entry:
|
|
* x - Number to round up
|
|
*
|
|
* Exit:
|
|
* Returns x rounded up to a power of two:
|
|
* x result
|
|
* ----- ------
|
|
* 0 0 (???)
|
|
* 1 1 (2^0)
|
|
* 2 2 (2^1)
|
|
* 3 4 (2^2)
|
|
* 4 4 (2^2)
|
|
* ... ....
|
|
* 127 128 (2^7)
|
|
* 128 128 (2^7)
|
|
* 129 256 (2^8)
|
|
* ... ...
|
|
*/
|
|
long roundUpToPowerOfTwo(long x)
|
|
{
|
|
int ibit;
|
|
long xSave=x;
|
|
long mask;
|
|
|
|
//** Check if already a power of 2; We use the trick that clears the
|
|
// lowest order 1 bit. If the result is zero, then we know we
|
|
// already have a power of 2, since only one 1 bit was set.
|
|
if (0 == (x&(x-1))) {
|
|
return x;
|
|
}
|
|
|
|
//** Get the index (1-based) of the most significant 1 bit
|
|
for (ibit=0; x; x>>=1, ibit++)
|
|
;
|
|
|
|
//** Round up and return result
|
|
Assert(ibit >= 2); // First test ensures this
|
|
mask = (1 << ibit) - 1;
|
|
return (xSave + mask) & ~mask; // Round up to a power of 2
|
|
} /* roundUpToPowerOfTwo() */
|
|
|
|
|
|
/*** CompMemoryFromPSZ - Get Compression Memory from a string
|
|
*
|
|
* NOTE: See dfparse.h for entry/exit conditions.
|
|
*/
|
|
int CompMemoryFromPSZ(char *psz, PERROR perr)
|
|
{
|
|
long memory;
|
|
long memoryLo; // Lowest 2^n exponent allowed
|
|
long memoryHi; // Highest 2^n exponent allowed
|
|
long cbLo; // Lowest byte count allowed
|
|
long cbHi; // Highest byte count allowed
|
|
int cbits;
|
|
|
|
memory = atoi(psz);
|
|
memoryLo = atoi(pszCM_LOWEST);
|
|
memoryHi = atoi(pszCM_HIGHEST);
|
|
|
|
cbLo = 1L << memoryLo;
|
|
cbHi = 1L << memoryHi;
|
|
|
|
//** Check 2^n exponent range
|
|
if ((memoryLo <= memory) && (memory <= memoryHi)) {
|
|
return (int)memory;
|
|
}
|
|
if (memory < cbLo) {
|
|
//** Assume attempted to specify exponent that was too high
|
|
ErrSet(perr,pszDFPERR_INVALID_COMP_MEM,"%s%s%s",
|
|
pszCM_LOWEST,pszCM_HIGHEST,psz);
|
|
return -1;
|
|
}
|
|
|
|
//** Check byte count range
|
|
memory = roundUpToPowerOfTwo(memory); // Make it a power of two
|
|
if ((cbLo <= memory) && (memory <= cbHi)) {
|
|
//** Take log base 2
|
|
for (cbits=0; memory>>=1; cbits++)
|
|
;
|
|
Assert((memoryLo<=cbits) && (cbits<=memoryHi));
|
|
return cbits;
|
|
}
|
|
|
|
//** Out of range
|
|
ErrSet(perr,pszDFPERR_INVALID_COMP_MEM,"%d%d%s",
|
|
cbLo,cbHi,psz);
|
|
return -1;
|
|
} /* CompMemoryFromPSZ() */
|
|
|
|
|
|
/*** fnvcvBool - validate boolean value
|
|
*
|
|
* NOTE: See variable.h:FNVCVALIDATE for entry/exit conditions.
|
|
*/
|
|
FNVCVALIDATE(fnvcvBool)
|
|
{
|
|
BOOL f;
|
|
|
|
f = BOOLfromPSZ(pszValue,perr);
|
|
if (f == -1) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (f == FALSE) {
|
|
strcpy(pszNewValue,"0");
|
|
}
|
|
else {
|
|
Assert(f == TRUE);
|
|
strcpy(pszNewValue,"1");
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*** fnvcvCabName - Validate CabinetName template
|
|
*
|
|
* NOTE: See variable.h:FNVCVALIDATE for entry/exit conditions.
|
|
*/
|
|
FNVCVALIDATE(fnvcvCabName)
|
|
{
|
|
//BUGBUG 12-Aug-1993 bens Validate CabinetName value
|
|
strcpy(pszNewValue,pszValue);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*** fnvcvChecksumWidth - validate a ChecksumWidth value
|
|
*
|
|
* NOTE: See variable.h:FNVCVALIDATE for entry/exit conditions.
|
|
*/
|
|
FNVCVALIDATE(fnvcvChecksumWidth)
|
|
{
|
|
if (-1 == ChecksumWidthFromPSZ(pszValue,perr)) {
|
|
return FALSE;
|
|
}
|
|
|
|
strcpy(pszNewValue,pszValue);
|
|
return TRUE;
|
|
} /* fnvcvChecksumWidth() */
|
|
|
|
|
|
/*** fnvcvClusterSize - validate a ClusterSize value
|
|
*
|
|
* NOTE: See variable.h:FNVCVALIDATE for entry/exit conditions.
|
|
*
|
|
* We interpret special strings here that correspond to known disk
|
|
* sizes.
|
|
*/
|
|
FNVCVALIDATE(fnvcvClusterSize)
|
|
{
|
|
int i;
|
|
|
|
i = IMDSfromPSZ(pszValue); // See if special value
|
|
if (i != -1) { // Got a special value
|
|
strcpy(pszNewValue,amds[i].pszClusterSize);
|
|
return TRUE;
|
|
}
|
|
else { // Validate long value
|
|
return fnvcvLong(hvlist,pszName,pszValue,pszNewValue,perr);
|
|
}
|
|
}
|
|
|
|
|
|
/*** fnvcvCompType - validate a CompressionType value
|
|
*
|
|
* NOTE: See variable.h:FNVCVALIDATE for entry/exit conditions.
|
|
*/
|
|
FNVCVALIDATE(fnvcvCompType)
|
|
{
|
|
if (-1 == CompTypeFromPSZ(pszValue,perr)) {
|
|
return FALSE;
|
|
}
|
|
|
|
strcpy(pszNewValue,pszValue);
|
|
return TRUE;
|
|
} /* fnvcvCompType() */
|
|
|
|
|
|
/*** fnvcvCompLevel - validate a CompressionLevel value
|
|
*
|
|
* NOTE: See variable.h:FNVCVALIDATE for entry/exit conditions.
|
|
*/
|
|
FNVCVALIDATE(fnvcvCompLevel)
|
|
{
|
|
if (-1 == CompLevelFromPSZ(pszValue,perr)) {
|
|
return FALSE;
|
|
}
|
|
|
|
strcpy(pszNewValue,pszValue);
|
|
return TRUE;
|
|
} /* fnvcvCompLevel() */
|
|
|
|
|
|
/*** fnvcvCompMemory - validate a CompressionMemory value
|
|
*
|
|
* NOTE: See variable.h:FNVCVALIDATE for entry/exit conditions.
|
|
*/
|
|
FNVCVALIDATE(fnvcvCompMemory)
|
|
{
|
|
if (-1 == CompMemoryFromPSZ(pszValue,perr)) {
|
|
return FALSE;
|
|
}
|
|
|
|
strcpy(pszNewValue,pszValue);
|
|
return TRUE;
|
|
} /* fnvcvCompMemory() */
|
|
|
|
|
|
/*** fnvcvDateFmt - Validate InfDateFormat value
|
|
*
|
|
* NOTE: See variable.h:FNVCVALIDATE for entry/exit conditions.
|
|
*/
|
|
FNVCVALIDATE(fnvcvDateFmt)
|
|
{
|
|
if (!_stricmp(pszValue,pszIDF_MMDDYY) ||
|
|
!_stricmp(pszValue,pszIDF_YYYYMMDD) ) {
|
|
//** Valid date format
|
|
strcpy(pszNewValue,pszValue);
|
|
return TRUE;
|
|
}
|
|
//** Unsupported date format
|
|
return FALSE;
|
|
} /* fnvcvDateFmt() */
|
|
|
|
|
|
/*** fnvcvDirDest - Validate DestinationDir value
|
|
*
|
|
* NOTE: See variable.h:FNVCVALIDATE for entry/exit conditions.
|
|
*/
|
|
FNVCVALIDATE(fnvcvDirDest)
|
|
{
|
|
//BUGBUG 12-Aug-1993 bens Validate DestinationDir value
|
|
strcpy(pszNewValue,pszValue);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*** fnvcvDirSrc - Validate SourceDir value
|
|
*
|
|
* NOTE: See variable.h:FNVCVALIDATE for entry/exit conditions.
|
|
*/
|
|
FNVCVALIDATE(fnvcvDirSrc)
|
|
{
|
|
//BUGBUG 12-Aug-1993 bens Validate SourceDir value
|
|
strcpy(pszNewValue,pszValue);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*** fnvcvFile - Validate a file name value
|
|
*
|
|
* NOTE: See variable.h:FNVCVALIDATE for entry/exit conditions.
|
|
*/
|
|
FNVCVALIDATE(fnvcvFile)
|
|
{
|
|
//BUGBUG 08-Feb-1994 bens Validate file name
|
|
strcpy(pszNewValue,pszValue);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*** fnvcvFileChar - Validate a file name character
|
|
*
|
|
* NOTE: See variable.h:FNVCVALIDATE for entry/exit conditions.
|
|
*/
|
|
FNVCVALIDATE(fnvcvFileChar)
|
|
{
|
|
//BUGBUG 08-Feb-1994 bens Validate file name character
|
|
strcpy(pszNewValue,pszValue);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*** fnvcvLong - validate long value
|
|
*
|
|
* NOTE: See variable.h:FNVCVALIDATE for entry/exit conditions.
|
|
*/
|
|
FNVCVALIDATE(fnvcvLong)
|
|
{
|
|
char *psz;
|
|
|
|
for (psz=pszValue; *psz && isdigit(*psz); psz++) {
|
|
; //** Make sure entire value is digits
|
|
}
|
|
if (*psz != '\0') {
|
|
ErrSet(perr,pszDFPERR_NOT_A_NUMBER,"%s%s",pszName,pszValue);
|
|
return FALSE;
|
|
}
|
|
|
|
strcpy(pszNewValue,pszValue);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*** fnvcvMaxDiskFileCount - validate MaxDiskFileCount value
|
|
*
|
|
* NOTE: See variable.h:FNVCVALIDATE for entry/exit conditions.
|
|
*
|
|
* We interpret special strings here that correspond to known disk
|
|
* sizes.
|
|
*/
|
|
FNVCVALIDATE(fnvcvMaxDiskFileCount)
|
|
{
|
|
int i;
|
|
|
|
i = IMDSfromPSZ(pszValue); // See if special value
|
|
if (i != -1) { // Got a special value
|
|
strcpy(pszNewValue,amds[i].pszFilesInRoot);
|
|
return TRUE;
|
|
}
|
|
else { // Validate long value
|
|
return fnvcvLong(hvlist,pszName,pszValue,pszNewValue,perr);
|
|
}
|
|
}
|
|
|
|
|
|
/*** fnvcvMaxDiskSize - validate a MaxDiskSize value
|
|
*
|
|
* NOTE: See variable.h:FNVCVALIDATE for entry/exit conditions.
|
|
*/
|
|
FNVCVALIDATE(fnvcvMaxDiskSize)
|
|
{
|
|
int i;
|
|
|
|
i = IMDSfromPSZ(pszValue); // See if special value
|
|
if (i != -1) { // Got a special value
|
|
strcpy(pszNewValue,amds[i].pszDiskSize);
|
|
return TRUE;
|
|
}
|
|
else { // Validate long value
|
|
return fnvcvLong(hvlist,pszName,pszValue,pszNewValue,perr);
|
|
}
|
|
}
|
|
|
|
|
|
/*** fnvcvSectionOrder - validate InfSectionOrder value
|
|
*
|
|
* NOTE: See variable.h:FNVCVALIDATE for entry/exit conditions.
|
|
*/
|
|
FNVCVALIDATE(fnvcvSectionOrder)
|
|
{
|
|
int bits;
|
|
int bitSection;
|
|
char ch;
|
|
char *psz;
|
|
|
|
//** Check length
|
|
if (strlen(pszValue) > 3) {
|
|
ErrSet(perr,pszDFPERR_BAD_SECTION_ORDER,"%s",pszValue);
|
|
return FALSE;
|
|
}
|
|
|
|
//** Make sure character appears at most once
|
|
bits = 0; // Set 1 bit for each character
|
|
for (psz=pszValue; *psz; psz++) {
|
|
ch = toupper(*psz);
|
|
switch (ch) {
|
|
case pszISO_DISK: bitSection = 1; break;
|
|
case pszISO_CABINET: bitSection = 2; break;
|
|
case pszISO_FILE: bitSection = 4; break;
|
|
|
|
default:
|
|
ErrSet(perr,pszDFPERR_BAD_SECTION_ORDER2,"%c%s",*psz,pszValue);
|
|
return FALSE;
|
|
}
|
|
//** Make sure character is not repeated
|
|
if (bits & bitSection) {
|
|
ErrSet(perr,pszDFPERR_BAD_SECTION_ORDER3,"%c%s",*psz,pszValue);
|
|
return FALSE;
|
|
}
|
|
bits |= bitSection; // Record this section
|
|
}
|
|
|
|
//** Value is OK
|
|
strcpy(pszNewValue,pszValue);
|
|
return TRUE;
|
|
} /* fnvcvSectionOrder() */
|
|
|
|
|
|
/*** fnvcvWildFile - validate filename with possibly single "*" char
|
|
*
|
|
* NOTE: See variable.h:FNVCVALIDATE for entry/exit conditions.
|
|
*/
|
|
FNVCVALIDATE(fnvcvWildFile)
|
|
{
|
|
//BUGBUG 12-Aug-1993 bens Validate Wild Filename
|
|
strcpy(pszNewValue,pszValue);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*** fnvcvWildPath - validate path with possibly single "*" char
|
|
*
|
|
* NOTE: See variable.h:FNVCVALIDATE for entry/exit conditions.
|
|
*/
|
|
FNVCVALIDATE(fnvcvWildPath)
|
|
{
|
|
//BUGBUG 12-Aug-1993 bens Validate Wild Path
|
|
strcpy(pszNewValue,pszValue);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*** IMDSfromPSZ - Look for special disk designator in amds[]
|
|
*
|
|
* Entry:
|
|
* pszValue - Value to compare against amds[].pszDiskSize values
|
|
*
|
|
* Exit-Success:
|
|
* Returns index in amds[] of entry that matches pszValue;
|
|
*
|
|
* Exit-Failure:
|
|
* Returns -1, pszValue not in amds[]
|
|
*/
|
|
int IMDSfromPSZ(char *pszValue)
|
|
{
|
|
int i;
|
|
|
|
for (i=0;
|
|
|
|
(i<nmds) && // More special values to check
|
|
_stricmp(pszValue,amds[i].pszSpecial) && // String not special
|
|
(atol(pszValue) != atol(amds[i].pszDiskSize)); // Value not special
|
|
|
|
i++) {
|
|
; // Check for special value
|
|
}
|
|
|
|
if (i<nmds) { // Got a special value
|
|
return i;
|
|
}
|
|
else {
|
|
return -1;
|
|
}
|
|
} /* IMDSfromPSZ() */
|