Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

568 lines
19 KiB

  1. ;/*
  2. ; * Microsoft Confidential
  3. ; * Copyright (C) Microsoft Corporation 1991
  4. ; * All Rights Reserved.
  5. ; */
  6. /***************************************************************************/
  7. /* PARSE.C */
  8. /* */
  9. /* Command line parsing functions for SETVER.C. */
  10. /* */
  11. /* Valid command lines are: */
  12. /* List table: SETVER [D:\path] */
  13. /* Add entry: SETVER [D:\path] name.ext X.XX */
  14. /* Delete entry: SETVER [D:\path] name.ext /DELETE */
  15. /* Display help SETVER /? */
  16. /* Delete entry quietly: SETVER [D:\path] name.ext /DELETE /QUIET */
  17. /* */
  18. /* The following error codes are returned: */
  19. /* */
  20. /* S_INVALID_SWITCH Invalid switch */
  21. /* S_INVALID_FNAME Invalid file name */
  22. /* S_BAD_VERSION_FMT Invalid version number format */
  23. /* S_BAD_DRV_SPEC Invalid drive/path specifier */
  24. /* S_TOO_MANY_PARMS Too many command line parameters */
  25. /* S_MISSING_PARM Missing parameter */
  26. /* S_INVALID_PATH Path specifier is invalid */
  27. /* */
  28. /* johnhe 05-01-90 */
  29. /***************************************************************************/
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <ctype.h>
  33. #include <string.h>
  34. #include <dos.h>
  35. #include <direct.h>
  36. #include <setver.h>
  37. /***************************************************************************/
  38. /* Parses the command line to get the optional drive letter, optional */
  39. /* executable file name and optional switch /DELETE. Also handles a single */
  40. /* "/?" switch for displaying command help. The /DELETE switch will accept */
  41. /* any number of chars in the the word DELETE for the switch. Also */
  42. /* supports a /QUIET switch, similarly handled, but only valid in */
  43. /* combination with the /DELETE switch */
  44. /* */
  45. /* int ParseCmd( int argc, char *argv[], struct TableEntry *Entry ) */
  46. /* */
  47. /* ARGUMENTS: argc - Count of command line arguments */
  48. /* argv - Array of ptrs to command line argments */
  49. /* Entry - Ptr to struct to be filled in */
  50. /* RETURNS: int - Valid function number or parse error code */
  51. /* */
  52. /***************************************************************************/
  53. int ParseCmd( int argc, char *argv[], struct TableEntry *Entry )
  54. {
  55. register Funct;
  56. unsigned uVersion;
  57. int iTmp;
  58. int iStrLen;
  59. strcpy( Entry->Path, argv[0] ); /* Set default setver.exe path */
  60. if ( argc == 1 ) /* Chk for default of 0 parms */
  61. return( DO_LIST ); /* No args so just do a listing */
  62. for ( iTmp = 1; iTmp < argc; iTmp++ )
  63. strupr( argv[ iTmp ] ); /* Convert params to upper case */
  64. /* Chk for help switch */
  65. if ( MatchSwitch( argv[ 1 ], HELP_SWITCH ) )
  66. return( argc > 2 ? S_TOO_MANY_PARMS : DO_HELP);
  67. iTmp = 1;
  68. /* Chk for optional drive:\path spec */
  69. if ( strchr( argv[1], ':' ) )
  70. {
  71. if ( IsValidDrive( (unsigned)argv[1][0] - 0x40 ) && argv[1][1] == ':' )
  72. {
  73. if ( (iStrLen = strlen( argv[1] )) > (MAX_PATH_LEN - 1) )
  74. return( S_INVALID_PATH );
  75. else
  76. {
  77. strcpy( Entry->Path, argv[1] );
  78. #ifdef DBCS
  79. if ( (*(Entry->Path + iStrLen - 1) != '\\' && argv[1][2] != EOL )
  80. || CheckDBCSTailByte(Entry->Path,Entry->Path + iStrLen - 1) )
  81. #else
  82. if ( *(Entry->Path + iStrLen - 1) != '\\' && argv[1][2] != EOL )
  83. #endif
  84. strcat( Entry->Path, "\\" );
  85. strcat( Entry->Path, "SETVER.EXE" );
  86. iTmp++;
  87. }
  88. }
  89. else
  90. return( S_BAD_DRV_SPEC );
  91. }
  92. if ( iTmp >= argc )
  93. Funct = DO_LIST;
  94. else if ( IsValidFileName( argv[ iTmp ] ) )
  95. {
  96. strcpy( Entry->szFileName, argv[ iTmp++ ] );
  97. if ( iTmp >= argc ) /* Version # or /D or /Q must follow */
  98. Funct = S_MISSING_PARM;
  99. /* note that Quiet switch requires Del switch also be supplied */
  100. else if ( MatchSwitch( argv[ iTmp ], DEL_SWITCH ) )
  101. {
  102. if ( ++iTmp < argc ) /* more args left */
  103. {
  104. if (MatchSwitch(argv[iTmp], QUIET_SWITCH))
  105. Funct = (++iTmp < argc ? S_TOO_MANY_PARMS : DO_QUIET);
  106. else
  107. Funct = S_TOO_MANY_PARMS;
  108. }
  109. else
  110. Funct = DO_DELETE;
  111. }
  112. else if ( MatchSwitch( argv[iTmp], QUIET_SWITCH ) )
  113. {
  114. if ( ++iTmp < argc ) /* must find delete switch */
  115. if (MatchSwitch(argv[iTmp], DEL_SWITCH))
  116. Funct = (++iTmp < argc ? S_TOO_MANY_PARMS : DO_QUIET);
  117. else
  118. Funct = S_INVALID_SWITCH;
  119. else
  120. Funct = S_INVALID_SWITCH;
  121. }
  122. else if ( *argv[iTmp] == '/' ) /* Make sure not a bogus switch */
  123. Funct = S_INVALID_SWITCH;
  124. else if ( (uVersion = ParseVersion( argv[ iTmp++ ] )) != 0 )
  125. {
  126. Entry->MajorVer = (char)(uVersion >> 8);
  127. Entry->MinorVer = (char)(uVersion & 0xff);
  128. Funct = (iTmp < argc ? S_TOO_MANY_PARMS : DO_ADD_FILE);
  129. }
  130. else
  131. Funct = S_BAD_VERSION_FMT;
  132. }
  133. else
  134. Funct = S_INVALID_FNAME;
  135. return( Funct );
  136. }
  137. /***************************************************************************/
  138. /* Parses a DOS major and minor version number from an ascii string in the */
  139. /* form of "00.00" where the major number is on the left of the decminal */
  140. /* point and the minor version follows the version number. Valid version */
  141. /* numbers are decimal numbers between 2.00 and 9.99. */
  142. /* */
  143. /* unsigned ParseVersion( char *szDosVer ) */
  144. /* */
  145. /* ARGUMENTS: szDosVer - Ptr to an ascii verion number string */
  146. /* RETURNS: unsigned - Version # in the form (Major << 8) + */
  147. /* Minor or 0 if not valid version string */
  148. /* */
  149. /***************************************************************************/
  150. unsigned ParseVersion( char *szDosVer )
  151. {
  152. unsigned Version = 0;
  153. size_t Len;
  154. char *szMinor;
  155. /* First parse the minor version number */
  156. if ( (szMinor = strchr( szDosVer, '.' )) != NULL )
  157. {
  158. *szMinor = EOL;
  159. szMinor++;
  160. if ( (Len = strlen( szMinor )) > 2 || !IsDigitStr( szMinor ) )
  161. Version = (unsigned) S_ERROR;
  162. else
  163. {
  164. Version = (unsigned)atoi( szMinor );
  165. while( Len++ < 2 ) /* Convert .x to .x0 */
  166. Version *= 10;
  167. }
  168. }
  169. /* Now get the major part of the number */
  170. szDosVer = SkipLeadingChr( szDosVer, '0' );
  171. if ( Version == (unsigned)S_ERROR || strlen( szDosVer ) > 2 ||
  172. !IsDigitStr( szDosVer ) )
  173. Version = 0;
  174. else
  175. Version |= ((unsigned)atoi( szDosVer ) << 8);
  176. /* Check for min and max versions */
  177. if ( Version < MIN_VERSION || Version >= MAX_VERSION )
  178. Version = 0;
  179. return( Version );
  180. }
  181. /***************************************************************************/
  182. /* Checks a string to verify that all characters in the string are decmial */
  183. /* numbers 0-9. */
  184. /* */
  185. /* int IsDigitStr( char *szStr ) */
  186. /* */
  187. /* ARGUMENTS: szStr - Ptr to ascii string to be scanned */
  188. /* RETURNS: int - TRUE if all chars are numbers else FALSE */
  189. /* */
  190. /***************************************************************************/
  191. int IsDigitStr( char *szStr )
  192. {
  193. while( *szStr != EOL )
  194. {
  195. if ( !isdigit( *(szStr++) ) )
  196. return( FALSE );
  197. }
  198. return( TRUE );
  199. }
  200. /***************************************************************************/
  201. /* Accepts a pointer to a string and a single character to match. Returns */
  202. /* a ptr to the first character in the string not matching the specified */
  203. /* character. */
  204. /* */
  205. /* char *SkipLeadingChr( char *szStr, char chChar ) */
  206. /* */
  207. /* ARGUMENTS: szStr - Ptr to an ascii string */
  208. /* chChar - Ascii character to match */
  209. /* RETURNS: char * - Ptr to first char in the string not */
  210. /* matching the specified character */
  211. /***************************************************************************/
  212. char *SkipLeadingChr( char *szStr, char chChar )
  213. {
  214. while( *szStr == chChar )
  215. szStr++;
  216. return( szStr );
  217. }
  218. /***************************************************************************/
  219. /* Compares a cmd line switch against a test string. The test switch is an */
  220. /* ascii string which will be used as a pattern to be matched against the */
  221. /* command string. The command string may be any subset of the test string */
  222. /* which has been prefixed with a switch character. */
  223. /* */
  224. /* int MatchSwitch( char *szCmdParm, char *szTestSwitch ) */
  225. /* */
  226. /* ARGUMENTS: szCmdParm - Command line parameter to be tested */
  227. /* szTestSwitch - Switch to test command line against */
  228. /* RETURN: int - TRUE if there is a match else FALSE */
  229. /* */
  230. /***************************************************************************/
  231. int MatchSwitch( char *szCmdParm, char *szTestSwitch )
  232. {
  233. /* Must have a leading '/' and at least 1 char */
  234. if ( *(szCmdParm++) != SWITCH_CHAR || *szCmdParm == EOL )
  235. return( FALSE );
  236. while ( *szTestSwitch != EOL && *szTestSwitch == *szCmdParm )
  237. szTestSwitch++, szCmdParm++;
  238. return( *szCmdParm == EOL ? TRUE : FALSE );
  239. }
  240. /***************************************************************************/
  241. /* Scans a string to see if the string can be used a valid file name. */
  242. /* The scan checks to be sure each character in the name is a valid */
  243. /* character for a path name. There is also a check to be sure that only */
  244. /* there is not more than 1 decimal in the name and that if there is a */
  245. /* decimal that the primary name and extension do not exceed the maximum */
  246. /* length of 8 chars for primary and 3 for extension. If the name does */
  247. /* not include a decimal the max length is 8 characters. */
  248. /* */
  249. /* int IsValidFileName( char *szPath ) */
  250. /* */
  251. /* ARGUMENTS: szFile - String containing a file name. */
  252. /* RETURNS : int - TRUE if valid name else FALSE. */
  253. /* */
  254. /***************************************************************************/
  255. int IsValidFileName( char *szFile )
  256. {
  257. char *szDecimal;
  258. RemoveTrailing( szFile, '.' );
  259. /*
  260. * Check to be sure length of filename is greater than 0,
  261. * there are no invalid file characters,
  262. * there is no path associated with the filename,
  263. * the filename is not a reserved DOS filename, and
  264. * there are no wildcard characters used in the filename.
  265. */
  266. #ifdef DBCS
  267. if ( strlen( szFile ) > 0 && ValidFileChar( szFile ) &&
  268. ((strchr(szFile, '\\') == NULL) || CheckDBCSTailByte(szFile,strchr(szFile, '\\'))) &&
  269. !IsReservedName( szFile ) && !IsWildCards( szFile ) )
  270. #else
  271. if ( strlen( szFile ) > 0 && ValidFileChar( szFile ) &&
  272. (strchr(szFile, '\\') == NULL) &&
  273. !IsReservedName( szFile ) && !IsWildCards( szFile ) )
  274. #endif
  275. {
  276. /* Check for appropriate 8.3 filename */
  277. if ( (szDecimal = strchr( szFile, '.' )) != NULL )
  278. {
  279. if ( strchr( szDecimal + 1, '.' ) == NULL && /* Chk for more '.'s */
  280. (szDecimal - szFile) <= 8 && /* Chk lengths */
  281. (strchr( szDecimal, EOL ) - szDecimal - 1) <= 3 )
  282. return ( TRUE );
  283. }
  284. else if ( strlen( szFile ) <= 8 )
  285. return ( TRUE );
  286. }
  287. return( FALSE );
  288. }
  289. /***************************************************************************/
  290. /* Checks all of the characters in a string to see if they are vaild path */
  291. /* name characaters. */
  292. /* */
  293. /* int ValidFileChar( char *szFile ) */
  294. /* */
  295. /* ARGUMENTS: szFile - File name string */
  296. /* RETURN: int - TRUE if chars in string are valid else */
  297. /* FALSE */
  298. /* */
  299. /***************************************************************************/
  300. int ValidFileChar( char *szFile )
  301. {
  302. int IsOk = TRUE;
  303. while ( IsOk && *szFile != EOL )
  304. #ifdef DBCS
  305. if (IsDBCSLeadByte(*szFile))
  306. szFile += 2;
  307. else
  308. #endif
  309. IsOk = IsValidFileChr( *(szFile++) );
  310. return( IsOk );
  311. }
  312. /***************************************************************************/
  313. /* Checks a file or path name against a list of reserved DOS filenames and */
  314. /* returns TRUE if the name is a reserved name. The function must first */
  315. /* off any extension from the name. */
  316. /* */
  317. /* int IsReservedName( char *szFile ) */
  318. /* */
  319. /* ARGUMENTS: szFile - File name string */
  320. /* RETURN: int - TRUE if name is reserved DOS name */
  321. /* */
  322. /***************************************************************************/
  323. int IsReservedName( char *szFile )
  324. {
  325. register Status;
  326. register i;
  327. char *szTmp;
  328. static char *apszRes[] = { "AUX", "CLOCK$", "COM1", "COM2",
  329. "COM3", "COM4", "CON", "LPT", "LPT1",
  330. "LPT2", "LPT3", "LST", "NUL", "PRN", NULL };
  331. if ( (szTmp = strchr( szFile, '.' )) != NULL )
  332. *szTmp = EOL;
  333. for ( i = 0, Status = FALSE; Status == FALSE && apszRes[i] != NULL; i++ )
  334. Status = !strcmpi( szFile, apszRes[i] );
  335. if ( szTmp != NULL )
  336. *szTmp = '.';
  337. return( Status );
  338. }
  339. /***************************************************************************/
  340. /* Checks a file or path name for any wildcards (* and ?). If wildcard */
  341. /* characters exist, it returns TRUE. Otherwise, it returns FALSE. */
  342. /* */
  343. /* int IsWildCards( char *szFile ) */
  344. /* */
  345. /* ARGUMENTS: szFile - File name string */
  346. /* RETURN: int - TRUE if wildcards exist in name */
  347. /* */
  348. /***************************************************************************/
  349. int IsWildCards( char *szFile )
  350. {
  351. if ( ((strchr( szFile, '*' )) != NULL) ||
  352. ((strchr( szFile, '?' )) != NULL) )
  353. return( TRUE );
  354. return( FALSE );
  355. }
  356. /***************************************************************************/
  357. /* Validates a character as a valid path and file name character. */
  358. /* */
  359. /* IsValidFileChr( char Char ) */
  360. /* */
  361. /* ARGUMENTS: Char - Character to be tested */
  362. /* RETURNS: int - TRUE if a valid character else FALSE */
  363. /* */
  364. /***************************************************************************/
  365. int IsValidFileChr( char Char )
  366. {
  367. int IsOk;
  368. switch( Char )
  369. {
  370. case ' ' :
  371. case '\t' :
  372. case 0x0d :
  373. case '/' :
  374. case ':' :
  375. case ';' :
  376. case '=' :
  377. case '<' :
  378. case '>' :
  379. case '|' :
  380. IsOk = FALSE;
  381. break;
  382. default :
  383. IsOk = TRUE;
  384. break;
  385. }
  386. return( IsOk );
  387. }
  388. /***************************************************************************/
  389. /* Removes all trailing characters of the type specified from a string. */
  390. /* */
  391. /* void RemoveTrailing( char *String, char Char ) */
  392. /* */
  393. /* ARGUMENTS: String - pointer to a string */
  394. /* Char - ascii char to remove from end of string */
  395. /* RETURNS: void */
  396. /* */
  397. /***************************************************************************/
  398. void RemoveTrailing( char *String, char Char )
  399. {
  400. char *EndOfString;
  401. EndOfString = strchr(String, EOL );
  402. while( EndOfString != String && *(EndOfString-1) == Char )
  403. EndOfString--;
  404. *EndOfString = EOL;
  405. }
  406. /***************************************************************************/
  407. /* Copyright (c) 1989 - Microsoft Corp. */
  408. /* All rights reserved. */
  409. /* */
  410. /* Returns a pointer to the first character in the filename which may or */
  411. /* may not be appended to a path. */
  412. /* */
  413. /* char *ParseFileName( char *szPath ) */
  414. /* */
  415. /* ARGUMENTS: szPath - Ptr to a file path in the form d:\xxxx\xxx.xxx */
  416. /* RETURNS: char * - Ptr to file name or character after last */
  417. /* backslash or ':' in the string if the path did */
  418. /* not contain a file name */
  419. /* */
  420. /***************************************************************************/
  421. char *ParseFileName( char *szPath )
  422. {
  423. char *szPtr;
  424. for ( szPtr = szPath;
  425. *szPtr != EOL && (IsValidFileChr( *szPtr ) || *szPtr == ':');
  426. szPtr++ )
  427. #ifdef DBCS
  428. if (IsDBCSLeadByte(*szPtr))
  429. szPtr++;
  430. #else
  431. ;
  432. #endif
  433. #ifdef DBCS
  434. while(( --szPtr >= szPath && *szPtr != '\\' && *szPtr != ':') ||
  435. (szPtr >= szPath && CheckDBCSTailByte(szPath,szPtr)) )
  436. #else
  437. while( --szPtr >= szPath && *szPtr != '\\' && *szPtr != ':' )
  438. #endif
  439. ;
  440. return( ++szPtr );
  441. }
  442. #ifdef DBCS
  443. /***************************************************************************/
  444. /* Test if the character is DBCS lead byte. */
  445. /* */
  446. /* int IsDBCSLeadByte(char c) */
  447. /* */
  448. /* ARGUMENTS: c - character to test */
  449. /* RETURNS: TRUE if leadbyte */
  450. /* */
  451. /***************************************************************************/
  452. int IsDBCSLeadByte(c)
  453. unsigned char c;
  454. {
  455. static unsigned char far *DBCSLeadByteTable = NULL;
  456. union REGS inregs,outregs;
  457. struct SREGS segregs;
  458. unsigned char far *p;
  459. if (DBCSLeadByteTable == NULL)
  460. {
  461. inregs.x.ax = 0x6300; /* get DBCS lead byte table */
  462. intdosx(&inregs, &outregs, &segregs);
  463. FP_OFF(DBCSLeadByteTable) = outregs.x.si;
  464. FP_SEG(DBCSLeadByteTable) = segregs.ds;
  465. }
  466. p = DBCSLeadByteTable;
  467. while (p[0] || p[1])
  468. {
  469. if (c >= p[0] && c <= p[1])
  470. return TRUE;
  471. p += 2;
  472. }
  473. return ( FALSE );
  474. }
  475. /***************************************************************************/
  476. /*
  477. /* Check if the character point is at tail byte
  478. /*
  479. /* input: *str = strart pointer of the string
  480. /* *point = character pointer to check
  481. /* output: TRUE if at the tail byte
  482. /*
  483. /***************************************************************************/
  484. int CheckDBCSTailByte(str,point)
  485. unsigned char *str,*point;
  486. {
  487. unsigned char *p;
  488. p = point;
  489. while (p != str)
  490. {
  491. p--;
  492. if (!IsDBCSLeadByte(*p))
  493. {
  494. p++;
  495. break;
  496. }
  497. }
  498. return ((point - p) & 1 ? TRUE : FALSE);
  499. }
  500. #endif