;/* ; * Microsoft Confidential ; * Copyright (C) Microsoft Corporation 1991 ; * All Rights Reserved. ; */ /***************************************************************************/ /* PARSE.C */ /* */ /* Command line parsing functions for SETVER.C. */ /* */ /* Valid command lines are: */ /* List table: SETVER [D:\path] */ /* Add entry: SETVER [D:\path] name.ext X.XX */ /* Delete entry: SETVER [D:\path] name.ext /DELETE */ /* Display help SETVER /? */ /* Delete entry quietly: SETVER [D:\path] name.ext /DELETE /QUIET */ /* */ /* The following error codes are returned: */ /* */ /* S_INVALID_SWITCH Invalid switch */ /* S_INVALID_FNAME Invalid file name */ /* S_BAD_VERSION_FMT Invalid version number format */ /* S_BAD_DRV_SPEC Invalid drive/path specifier */ /* S_TOO_MANY_PARMS Too many command line parameters */ /* S_MISSING_PARM Missing parameter */ /* S_INVALID_PATH Path specifier is invalid */ /* */ /* johnhe 05-01-90 */ /***************************************************************************/ #include #include #include #include #include #include #include /***************************************************************************/ /* Parses the command line to get the optional drive letter, optional */ /* executable file name and optional switch /DELETE. Also handles a single */ /* "/?" switch for displaying command help. The /DELETE switch will accept */ /* any number of chars in the the word DELETE for the switch. Also */ /* supports a /QUIET switch, similarly handled, but only valid in */ /* combination with the /DELETE switch */ /* */ /* int ParseCmd( int argc, char *argv[], struct TableEntry *Entry ) */ /* */ /* ARGUMENTS: argc - Count of command line arguments */ /* argv - Array of ptrs to command line argments */ /* Entry - Ptr to struct to be filled in */ /* RETURNS: int - Valid function number or parse error code */ /* */ /***************************************************************************/ int ParseCmd( int argc, char *argv[], struct TableEntry *Entry ) { register Funct; unsigned uVersion; int iTmp; int iStrLen; strcpy( Entry->Path, argv[0] ); /* Set default setver.exe path */ if ( argc == 1 ) /* Chk for default of 0 parms */ return( DO_LIST ); /* No args so just do a listing */ for ( iTmp = 1; iTmp < argc; iTmp++ ) strupr( argv[ iTmp ] ); /* Convert params to upper case */ /* Chk for help switch */ if ( MatchSwitch( argv[ 1 ], HELP_SWITCH ) ) return( argc > 2 ? S_TOO_MANY_PARMS : DO_HELP); iTmp = 1; /* Chk for optional drive:\path spec */ if ( strchr( argv[1], ':' ) ) { if ( IsValidDrive( (unsigned)argv[1][0] - 0x40 ) && argv[1][1] == ':' ) { if ( (iStrLen = strlen( argv[1] )) > (MAX_PATH_LEN - 1) ) return( S_INVALID_PATH ); else { strcpy( Entry->Path, argv[1] ); #ifdef DBCS if ( (*(Entry->Path + iStrLen - 1) != '\\' && argv[1][2] != EOL ) || CheckDBCSTailByte(Entry->Path,Entry->Path + iStrLen - 1) ) #else if ( *(Entry->Path + iStrLen - 1) != '\\' && argv[1][2] != EOL ) #endif strcat( Entry->Path, "\\" ); strcat( Entry->Path, "SETVER.EXE" ); iTmp++; } } else return( S_BAD_DRV_SPEC ); } if ( iTmp >= argc ) Funct = DO_LIST; else if ( IsValidFileName( argv[ iTmp ] ) ) { strcpy( Entry->szFileName, argv[ iTmp++ ] ); if ( iTmp >= argc ) /* Version # or /D or /Q must follow */ Funct = S_MISSING_PARM; /* note that Quiet switch requires Del switch also be supplied */ else if ( MatchSwitch( argv[ iTmp ], DEL_SWITCH ) ) { if ( ++iTmp < argc ) /* more args left */ { if (MatchSwitch(argv[iTmp], QUIET_SWITCH)) Funct = (++iTmp < argc ? S_TOO_MANY_PARMS : DO_QUIET); else Funct = S_TOO_MANY_PARMS; } else Funct = DO_DELETE; } else if ( MatchSwitch( argv[iTmp], QUIET_SWITCH ) ) { if ( ++iTmp < argc ) /* must find delete switch */ if (MatchSwitch(argv[iTmp], DEL_SWITCH)) Funct = (++iTmp < argc ? S_TOO_MANY_PARMS : DO_QUIET); else Funct = S_INVALID_SWITCH; else Funct = S_INVALID_SWITCH; } else if ( *argv[iTmp] == '/' ) /* Make sure not a bogus switch */ Funct = S_INVALID_SWITCH; else if ( (uVersion = ParseVersion( argv[ iTmp++ ] )) != 0 ) { Entry->MajorVer = (char)(uVersion >> 8); Entry->MinorVer = (char)(uVersion & 0xff); Funct = (iTmp < argc ? S_TOO_MANY_PARMS : DO_ADD_FILE); } else Funct = S_BAD_VERSION_FMT; } else Funct = S_INVALID_FNAME; return( Funct ); } /***************************************************************************/ /* Parses a DOS major and minor version number from an ascii string in the */ /* form of "00.00" where the major number is on the left of the decminal */ /* point and the minor version follows the version number. Valid version */ /* numbers are decimal numbers between 2.00 and 9.99. */ /* */ /* unsigned ParseVersion( char *szDosVer ) */ /* */ /* ARGUMENTS: szDosVer - Ptr to an ascii verion number string */ /* RETURNS: unsigned - Version # in the form (Major << 8) + */ /* Minor or 0 if not valid version string */ /* */ /***************************************************************************/ unsigned ParseVersion( char *szDosVer ) { unsigned Version = 0; size_t Len; char *szMinor; /* First parse the minor version number */ if ( (szMinor = strchr( szDosVer, '.' )) != NULL ) { *szMinor = EOL; szMinor++; if ( (Len = strlen( szMinor )) > 2 || !IsDigitStr( szMinor ) ) Version = (unsigned) S_ERROR; else { Version = (unsigned)atoi( szMinor ); while( Len++ < 2 ) /* Convert .x to .x0 */ Version *= 10; } } /* Now get the major part of the number */ szDosVer = SkipLeadingChr( szDosVer, '0' ); if ( Version == (unsigned)S_ERROR || strlen( szDosVer ) > 2 || !IsDigitStr( szDosVer ) ) Version = 0; else Version |= ((unsigned)atoi( szDosVer ) << 8); /* Check for min and max versions */ if ( Version < MIN_VERSION || Version >= MAX_VERSION ) Version = 0; return( Version ); } /***************************************************************************/ /* Checks a string to verify that all characters in the string are decmial */ /* numbers 0-9. */ /* */ /* int IsDigitStr( char *szStr ) */ /* */ /* ARGUMENTS: szStr - Ptr to ascii string to be scanned */ /* RETURNS: int - TRUE if all chars are numbers else FALSE */ /* */ /***************************************************************************/ int IsDigitStr( char *szStr ) { while( *szStr != EOL ) { if ( !isdigit( *(szStr++) ) ) return( FALSE ); } return( TRUE ); } /***************************************************************************/ /* Accepts a pointer to a string and a single character to match. Returns */ /* a ptr to the first character in the string not matching the specified */ /* character. */ /* */ /* char *SkipLeadingChr( char *szStr, char chChar ) */ /* */ /* ARGUMENTS: szStr - Ptr to an ascii string */ /* chChar - Ascii character to match */ /* RETURNS: char * - Ptr to first char in the string not */ /* matching the specified character */ /***************************************************************************/ char *SkipLeadingChr( char *szStr, char chChar ) { while( *szStr == chChar ) szStr++; return( szStr ); } /***************************************************************************/ /* Compares a cmd line switch against a test string. The test switch is an */ /* ascii string which will be used as a pattern to be matched against the */ /* command string. The command string may be any subset of the test string */ /* which has been prefixed with a switch character. */ /* */ /* int MatchSwitch( char *szCmdParm, char *szTestSwitch ) */ /* */ /* ARGUMENTS: szCmdParm - Command line parameter to be tested */ /* szTestSwitch - Switch to test command line against */ /* RETURN: int - TRUE if there is a match else FALSE */ /* */ /***************************************************************************/ int MatchSwitch( char *szCmdParm, char *szTestSwitch ) { /* Must have a leading '/' and at least 1 char */ if ( *(szCmdParm++) != SWITCH_CHAR || *szCmdParm == EOL ) return( FALSE ); while ( *szTestSwitch != EOL && *szTestSwitch == *szCmdParm ) szTestSwitch++, szCmdParm++; return( *szCmdParm == EOL ? TRUE : FALSE ); } /***************************************************************************/ /* Scans a string to see if the string can be used a valid file name. */ /* The scan checks to be sure each character in the name is a valid */ /* character for a path name. There is also a check to be sure that only */ /* there is not more than 1 decimal in the name and that if there is a */ /* decimal that the primary name and extension do not exceed the maximum */ /* length of 8 chars for primary and 3 for extension. If the name does */ /* not include a decimal the max length is 8 characters. */ /* */ /* int IsValidFileName( char *szPath ) */ /* */ /* ARGUMENTS: szFile - String containing a file name. */ /* RETURNS : int - TRUE if valid name else FALSE. */ /* */ /***************************************************************************/ int IsValidFileName( char *szFile ) { char *szDecimal; RemoveTrailing( szFile, '.' ); /* * Check to be sure length of filename is greater than 0, * there are no invalid file characters, * there is no path associated with the filename, * the filename is not a reserved DOS filename, and * there are no wildcard characters used in the filename. */ #ifdef DBCS if ( strlen( szFile ) > 0 && ValidFileChar( szFile ) && ((strchr(szFile, '\\') == NULL) || CheckDBCSTailByte(szFile,strchr(szFile, '\\'))) && !IsReservedName( szFile ) && !IsWildCards( szFile ) ) #else if ( strlen( szFile ) > 0 && ValidFileChar( szFile ) && (strchr(szFile, '\\') == NULL) && !IsReservedName( szFile ) && !IsWildCards( szFile ) ) #endif { /* Check for appropriate 8.3 filename */ if ( (szDecimal = strchr( szFile, '.' )) != NULL ) { if ( strchr( szDecimal + 1, '.' ) == NULL && /* Chk for more '.'s */ (szDecimal - szFile) <= 8 && /* Chk lengths */ (strchr( szDecimal, EOL ) - szDecimal - 1) <= 3 ) return ( TRUE ); } else if ( strlen( szFile ) <= 8 ) return ( TRUE ); } return( FALSE ); } /***************************************************************************/ /* Checks all of the characters in a string to see if they are vaild path */ /* name characaters. */ /* */ /* int ValidFileChar( char *szFile ) */ /* */ /* ARGUMENTS: szFile - File name string */ /* RETURN: int - TRUE if chars in string are valid else */ /* FALSE */ /* */ /***************************************************************************/ int ValidFileChar( char *szFile ) { int IsOk = TRUE; while ( IsOk && *szFile != EOL ) #ifdef DBCS if (IsDBCSLeadByte(*szFile)) szFile += 2; else #endif IsOk = IsValidFileChr( *(szFile++) ); return( IsOk ); } /***************************************************************************/ /* Checks a file or path name against a list of reserved DOS filenames and */ /* returns TRUE if the name is a reserved name. The function must first */ /* off any extension from the name. */ /* */ /* int IsReservedName( char *szFile ) */ /* */ /* ARGUMENTS: szFile - File name string */ /* RETURN: int - TRUE if name is reserved DOS name */ /* */ /***************************************************************************/ int IsReservedName( char *szFile ) { register Status; register i; char *szTmp; static char *apszRes[] = { "AUX", "CLOCK$", "COM1", "COM2", "COM3", "COM4", "CON", "LPT", "LPT1", "LPT2", "LPT3", "LST", "NUL", "PRN", NULL }; if ( (szTmp = strchr( szFile, '.' )) != NULL ) *szTmp = EOL; for ( i = 0, Status = FALSE; Status == FALSE && apszRes[i] != NULL; i++ ) Status = !strcmpi( szFile, apszRes[i] ); if ( szTmp != NULL ) *szTmp = '.'; return( Status ); } /***************************************************************************/ /* Checks a file or path name for any wildcards (* and ?). If wildcard */ /* characters exist, it returns TRUE. Otherwise, it returns FALSE. */ /* */ /* int IsWildCards( char *szFile ) */ /* */ /* ARGUMENTS: szFile - File name string */ /* RETURN: int - TRUE if wildcards exist in name */ /* */ /***************************************************************************/ int IsWildCards( char *szFile ) { if ( ((strchr( szFile, '*' )) != NULL) || ((strchr( szFile, '?' )) != NULL) ) return( TRUE ); return( FALSE ); } /***************************************************************************/ /* Validates a character as a valid path and file name character. */ /* */ /* IsValidFileChr( char Char ) */ /* */ /* ARGUMENTS: Char - Character to be tested */ /* RETURNS: int - TRUE if a valid character else FALSE */ /* */ /***************************************************************************/ int IsValidFileChr( char Char ) { int IsOk; switch( Char ) { case ' ' : case '\t' : case 0x0d : case '/' : case ':' : case ';' : case '=' : case '<' : case '>' : case '|' : IsOk = FALSE; break; default : IsOk = TRUE; break; } return( IsOk ); } /***************************************************************************/ /* Removes all trailing characters of the type specified from a string. */ /* */ /* void RemoveTrailing( char *String, char Char ) */ /* */ /* ARGUMENTS: String - pointer to a string */ /* Char - ascii char to remove from end of string */ /* RETURNS: void */ /* */ /***************************************************************************/ void RemoveTrailing( char *String, char Char ) { char *EndOfString; EndOfString = strchr(String, EOL ); while( EndOfString != String && *(EndOfString-1) == Char ) EndOfString--; *EndOfString = EOL; } /***************************************************************************/ /* Copyright (c) 1989 - Microsoft Corp. */ /* All rights reserved. */ /* */ /* Returns a pointer to the first character in the filename which may or */ /* may not be appended to a path. */ /* */ /* char *ParseFileName( char *szPath ) */ /* */ /* ARGUMENTS: szPath - Ptr to a file path in the form d:\xxxx\xxx.xxx */ /* RETURNS: char * - Ptr to file name or character after last */ /* backslash or ':' in the string if the path did */ /* not contain a file name */ /* */ /***************************************************************************/ char *ParseFileName( char *szPath ) { char *szPtr; for ( szPtr = szPath; *szPtr != EOL && (IsValidFileChr( *szPtr ) || *szPtr == ':'); szPtr++ ) #ifdef DBCS if (IsDBCSLeadByte(*szPtr)) szPtr++; #else ; #endif #ifdef DBCS while(( --szPtr >= szPath && *szPtr != '\\' && *szPtr != ':') || (szPtr >= szPath && CheckDBCSTailByte(szPath,szPtr)) ) #else while( --szPtr >= szPath && *szPtr != '\\' && *szPtr != ':' ) #endif ; return( ++szPtr ); } #ifdef DBCS /***************************************************************************/ /* Test if the character is DBCS lead byte. */ /* */ /* int IsDBCSLeadByte(char c) */ /* */ /* ARGUMENTS: c - character to test */ /* RETURNS: TRUE if leadbyte */ /* */ /***************************************************************************/ int IsDBCSLeadByte(c) unsigned char c; { static unsigned char far *DBCSLeadByteTable = NULL; union REGS inregs,outregs; struct SREGS segregs; unsigned char far *p; if (DBCSLeadByteTable == NULL) { inregs.x.ax = 0x6300; /* get DBCS lead byte table */ intdosx(&inregs, &outregs, &segregs); FP_OFF(DBCSLeadByteTable) = outregs.x.si; FP_SEG(DBCSLeadByteTable) = segregs.ds; } p = DBCSLeadByteTable; while (p[0] || p[1]) { if (c >= p[0] && c <= p[1]) return TRUE; p += 2; } return ( FALSE ); } /***************************************************************************/ /* /* Check if the character point is at tail byte /* /* input: *str = strart pointer of the string /* *point = character pointer to check /* output: TRUE if at the tail byte /* /***************************************************************************/ int CheckDBCSTailByte(str,point) unsigned char *str,*point; { unsigned char *p; p = point; while (p != str) { p--; if (!IsDBCSLeadByte(*p)) { p++; break; } } return ((point - p) & 1 ? TRUE : FALSE); } #endif