Source code of Windows XP (NT5)
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.

625 lines
21 KiB

  1. // Copyright (c) 1998-1999 Microsoft Corporation
  2. /*****************************************************************************
  3. *
  4. * PARSE.C
  5. *
  6. * This module contains the code to implement generic parsing routines
  7. * for utilities. There are several parsing routines included here.
  8. *
  9. * External Entry Points: (defined in utilsub.h)
  10. *
  11. * ParseCommandLineW()
  12. * IsTokenPresentW()
  13. * SetTokenPresentW()
  14. * SetTokenNotPresentW()
  15. *
  16. *
  17. ****************************************************************************/
  18. /* Get the standard C includes */
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <windows.h>
  23. #include <winstaw.h>
  24. #include <utilsub.h>
  25. #include <expand.h>
  26. // Verify that these are used internally, and do not rep. OS flags
  27. // usage appears in parse.c and expand.c only
  28. //
  29. #define READ_ONLY 0x0001 /* file is read only */
  30. #define HIDDEN 0x0002 /* file is hidden */
  31. #define SYSTEM 0x0004 /* file is a system file */
  32. #define VOLUME 0x0008 /* file is a volume label */
  33. #define SUBDIR 0x0010 /* file is a subdirectory */
  34. #define ARCHIVE 0x0020 /* file has archive bit on */
  35. /*=============================================================================
  36. == Local Functions Defined
  37. ============================================================================*/
  38. static USHORT StoreArgument(PTOKMAPW, WCHAR *);
  39. /*=============================================================================
  40. == External Functions Used
  41. ============================================================================*/
  42. /*=============================================================================
  43. == Local Variables Used
  44. ============================================================================*/
  45. ARGS arg_data;
  46. /*=============================================================================
  47. == Global Variables Used
  48. ============================================================================*/
  49. VOID
  50. SetBoolean(
  51. PTOKMAPW TokenMap,
  52. BOOL Value
  53. )
  54. {
  55. //
  56. // Folks pass in a variety of types and sizes as "boolean". Carefully
  57. // perform the write based on the size of the token map: first clear the
  58. // entire field, then (if Value != FALSE) set the only the first byte to
  59. // TRUE.
  60. //
  61. ZeroMemory( TokenMap->tmAddr, TokenMap->tmDLen );
  62. if (Value != FALSE) {
  63. *((PCHAR)TokenMap->tmAddr) = TRUE;
  64. }
  65. }
  66. /*****************************************************************************
  67. *
  68. * ParseCommandLineW (UNICODE version)
  69. *
  70. * This is the main function of the ParseCommandLine function. If the
  71. * caller is passing argv from the main() function the caller is
  72. * is responsible for pointing to argv[1], unless he wants this function
  73. * to parse the program name (argv[0]).
  74. *
  75. * If the user wishes to parse an admin file it is necessary to massage
  76. * the data into a form compatible with the command line arguements
  77. * passed to a main() function before calling ParseCommandLine().
  78. *
  79. * ENTRY:
  80. * argc - count of the command line arguments.
  81. * argv - vector of strings containing the
  82. * ptm - pointer to begining of the token map array
  83. * flag - USHORT set of flags (see utilsub.h for flag descriptions).
  84. *
  85. * EXIT:
  86. * Normal: ********** NOTE***********
  87. * PARSE_FLAG_NO_ERROR * All errors returned *
  88. * * from this function are *
  89. * Error: * BIT flags and must be *
  90. * PARSE_FLAG_NO_PARMS * converted by caller to *
  91. * PARSE_FLAG_INVALID_PARM * OS/2+ ERRORS!!!! *
  92. * PARSE_FLAG_TOO_MANY_PARMS ********** NOTE***********
  93. * PARSE_FLAG_MISSING_REQ_FIELD
  94. * ALGORITHM:
  95. *
  96. ****************************************************************************/
  97. USHORT WINAPI
  98. ParseCommandLineW( INT argc,
  99. WCHAR **argv,
  100. PTOKMAPW ptm,
  101. USHORT flag )
  102. {
  103. BOOL everyonespos = FALSE;
  104. WCHAR *pChar;
  105. USHORT rc, argi, found;
  106. size_t tokenlen, arglen;
  107. PTOKMAPW ptmtmp, nextpositional;
  108. PFILELIST pFileList;
  109. rc = PARSE_FLAG_NO_ERROR;
  110. /*--------------------------------------------------------------------------
  111. -- If there are no parameters inform the caller of this fact.
  112. --------------------------------------------------------------------------*/
  113. if(argc == 0) {
  114. rc |= PARSE_FLAG_NO_PARMS;
  115. return(rc);
  116. }
  117. /*--------------------------------------------------------------------------
  118. -- Find the first positional parameter in the token map array, if any.
  119. -- Also set the valid memory locations to '\0'.
  120. --------------------------------------------------------------------------*/
  121. nextpositional = NULL;
  122. for(ptmtmp=ptm; ptmtmp->tmToken != NULL; ptmtmp++) {
  123. if(ptmtmp->tmDLen && !(flag & PCL_FLAG_NO_CLEAR_MEMORY)) {
  124. pChar = (WCHAR *) ptmtmp->tmAddr;
  125. /*
  126. * Clear the 'string' form fields for tmDLen*sizeof(WCHAR) bytes;
  127. * all other forms to tmDLen bytes.
  128. */
  129. if ( (ptmtmp->tmForm == TMFORM_S_STRING) ||
  130. (ptmtmp->tmForm == TMFORM_DATE) ||
  131. (ptmtmp->tmForm == TMFORM_PHONE) ||
  132. (ptmtmp->tmForm == TMFORM_STRING) ||
  133. (ptmtmp->tmForm == TMFORM_X_STRING) )
  134. memset(pChar, L'\0', (ptmtmp->tmDLen*sizeof(WCHAR)));
  135. else
  136. memset(pChar, L'\0', ptmtmp->tmDLen);
  137. }
  138. if(ptmtmp->tmToken[0] != L'/' && ptmtmp->tmToken[0] != L'-' && nextpositional == NULL) {
  139. nextpositional = ptmtmp;
  140. }
  141. }
  142. /*--------------------------------------------------------------------------
  143. -- Scan the argument array looking for /x or -x switches or positional
  144. -- parameters. If a switch is found look it up in the token map array
  145. -- and if found see if it has a trailing parameter of the format:
  146. -- -x:foo || /x:foo || -x foo || /x foo
  147. -- when found set the found flag and if there is a trailing parameter
  148. -- store it at the location the user requested.
  149. --
  150. -- If it is not found in the token map array return the proper error
  151. -- unless the user requests us to ignore it (PCL_FLAG_IGNORE_INVALID).
  152. --
  153. -- If it is a positional parameter enter it into the token map array if
  154. -- there is room for it (i.e. nextpositional != NULL), if there is no
  155. -- room for it then return the proper error.
  156. --------------------------------------------------------------------------*/
  157. for(argi=0; argi<argc;) {
  158. if(everyonespos) {
  159. if( (wcslen(nextpositional->tmAddr) + wcslen(argv[argi]) + 1) > nextpositional->tmDLen) {
  160. rc |= PARSE_FLAG_TOO_MANY_PARMS;
  161. return(rc);
  162. }
  163. wcscat((WCHAR *) nextpositional->tmAddr, L" ");
  164. wcscat((WCHAR *) nextpositional->tmAddr, argv[argi]);
  165. argi++;
  166. }
  167. else if(argv[argi][0] == L'/' || /* argument is a switch (/x or -x) */
  168. argv[argi][0] == L'-') {
  169. found = FALSE;
  170. for(ptmtmp=ptm; ptmtmp->tmToken != NULL; ptmtmp++) {
  171. /*-----------------------------------------------------------------
  172. -- The string is found if a few requirements are met:
  173. -- 1) The first N-1 characters are the same, where N is
  174. -- the length of the string in the token map array.
  175. -- We ignore the first character (could be '-' or '/').
  176. -- 2) If the strings are not the same length, then the only
  177. -- valid character after /x can be ':', this is only true
  178. -- if the switch has a trailing parameter.
  179. ----------------------------------------------------------------*/
  180. tokenlen = wcslen(ptmtmp->tmToken); /* get token length */
  181. arglen = wcslen(argv[argi]); /* get argument length */
  182. if(!(_wcsnicmp(&(ptmtmp->tmToken[1]), &(argv[argi][1]), tokenlen-1))) {
  183. if(tokenlen != arglen) { /* not same length */
  184. if(ptmtmp->tmForm != TMFORM_VOID && /* if trailing parm is */
  185. argv[argi][tokenlen] == L':') {/* delemited with a ':' */
  186. if(ptmtmp->tmFlag & TMFLAG_PRESENT) { /* seen already */
  187. rc |= PARSE_FLAG_DUPLICATE_FIELD;
  188. }
  189. found = TRUE; /* then report it found. */
  190. break;
  191. }
  192. }
  193. else { /* all character same and */
  194. if(ptmtmp->tmFlag & TMFLAG_PRESENT) { /* seen already */
  195. rc |= PARSE_FLAG_DUPLICATE_FIELD;
  196. }
  197. found = TRUE; /* strings are the same */
  198. break; /* len report it found. */
  199. }
  200. }
  201. }
  202. /* switch not found in token map array and not requested to ignore */
  203. if(found != TRUE && !(flag & PCL_FLAG_IGNORE_INVALID)) {
  204. rc |= PARSE_FLAG_INVALID_PARM;
  205. if(!(flag & PCL_FLAG_CONTINUE_ON_ERROR)) {
  206. return(rc);
  207. }
  208. ++argi;
  209. }
  210. else if (!found) {
  211. ++argi;
  212. }
  213. else { /* switch was found in token map array */
  214. if(ptmtmp->tmForm == TMFORM_VOID) { /* no trailing parameter, done */
  215. ptmtmp->tmFlag |= TMFLAG_PRESENT;
  216. ++argi;
  217. }
  218. else if(ptmtmp->tmForm == TMFORM_BOOLEAN) { /* need confirmation */
  219. ptmtmp->tmFlag |= TMFLAG_PRESENT;
  220. SetBoolean(ptmtmp, TRUE);
  221. ++argi;
  222. }
  223. else { /* has a trailing parameter */
  224. if(argv[argi][tokenlen] == L':') { /* all in one switch (i.e. /x:foo) */
  225. if(StoreArgument(ptmtmp, &(argv[argi][tokenlen+1]))) {
  226. ptmtmp->tmFlag |= TMFLAG_PRESENT;
  227. if(flag & PCL_FLAG_RET_ON_FIRST_SUCCESS) {
  228. return(rc);
  229. }
  230. }
  231. else {
  232. rc |= PARSE_FLAG_INVALID_PARM;
  233. if(!(flag & PCL_FLAG_CONTINUE_ON_ERROR)) {
  234. return(rc);
  235. }
  236. }
  237. ++argi; /* bump up to next argument */
  238. }
  239. else { /* two argument switch (i.e. /x foo) */
  240. if ((++argi >= argc) ||
  241. (argv[argi][0] == L'/') ||
  242. (argv[argi][0] == L'-')) { /* bump up to trailing parm */
  243. switch ( ptmtmp->tmForm ) {
  244. case TMFORM_S_STRING:
  245. case TMFORM_STRING:
  246. ptmtmp->tmFlag |= TMFLAG_PRESENT;
  247. pChar = (WCHAR *) ptmtmp->tmAddr;
  248. pChar[0] = (WCHAR)NULL;
  249. break;
  250. default:
  251. rc |= PARSE_FLAG_INVALID_PARM;
  252. if(!(flag & PCL_FLAG_CONTINUE_ON_ERROR)) {
  253. return(rc);
  254. }
  255. break;
  256. }
  257. }
  258. else if(StoreArgument(ptmtmp, argv[argi])) {
  259. ptmtmp->tmFlag |= TMFLAG_PRESENT;
  260. if(flag & PCL_FLAG_RET_ON_FIRST_SUCCESS) {
  261. return(rc);
  262. }
  263. ++argi; /* bump up to next argument */
  264. }
  265. else {
  266. rc |= PARSE_FLAG_INVALID_PARM;
  267. if(!(flag & PCL_FLAG_CONTINUE_ON_ERROR)) {
  268. return(rc);
  269. }
  270. ++argi; /* bump up to next argument */
  271. }
  272. }
  273. }
  274. }
  275. } /* endif - is switch */
  276. else { /* argument is a positional parmater*/
  277. if(nextpositional == NULL) { /* if there are no positional left */
  278. rc |= PARSE_FLAG_TOO_MANY_PARMS;
  279. if(!(flag & PCL_FLAG_CONTINUE_ON_ERROR)) {
  280. return(rc);
  281. }
  282. }
  283. else { /* set positional in token array **/
  284. /*
  285. * Is the current PTM the start of TMFORM_FILES?
  286. */
  287. if (nextpositional->tmForm == TMFORM_FILES) {
  288. nextpositional->tmFlag |= TMFLAG_PRESENT;
  289. args_init(&arg_data, MAX_ARG_ALLOC);
  290. do {
  291. /*
  292. * If no match was found then return the current id.
  293. */
  294. // if (!expand_path(argv[argi], (HIDDEN|SYSTEM), &arg_data)) {
  295. // arg_data.argc--;
  296. // arg_data.argvp--;
  297. // }
  298. expand_path(argv[argi], (HIDDEN|SYSTEM), &arg_data);
  299. } while (++argi<argc);
  300. pFileList = (PFILELIST) nextpositional->tmAddr;
  301. pFileList->argc = arg_data.argc;
  302. pFileList->argv = &arg_data.argv[0];
  303. return (rc);
  304. }
  305. else if(StoreArgument(nextpositional, argv[argi])) {
  306. nextpositional->tmFlag |= TMFLAG_PRESENT;
  307. if(flag & PCL_FLAG_RET_ON_FIRST_SUCCESS) {
  308. return(rc);
  309. }
  310. /*--------------------------------------------------------------
  311. -- if this is an X_STRING then every thing from now on is
  312. -- going to be a concatenated string
  313. --------------------------------------------------------------*/
  314. if(nextpositional->tmForm == TMFORM_X_STRING) {
  315. everyonespos = TRUE;
  316. }
  317. else {
  318. for(++nextpositional; nextpositional->tmToken!=NULL; nextpositional++) {
  319. if(nextpositional->tmToken[0] != L'/' && nextpositional->tmToken[0] != L'-') {
  320. break;
  321. }
  322. }
  323. if(nextpositional->tmToken == NULL) { /* ran out of PP */
  324. nextpositional = NULL;
  325. }
  326. }
  327. }
  328. else { /* invalid PP */
  329. rc |= PARSE_FLAG_INVALID_PARM;
  330. if(!(flag & PCL_FLAG_CONTINUE_ON_ERROR)) {
  331. return(rc);
  332. }
  333. }
  334. }
  335. argi++;
  336. }
  337. }
  338. for(ptmtmp=ptm; ptmtmp->tmToken!=NULL; ptmtmp++) {
  339. if(ptmtmp->tmFlag & TMFLAG_REQUIRED && !(ptmtmp->tmFlag & TMFLAG_PRESENT)) {
  340. rc |= PARSE_FLAG_MISSING_REQ_FIELD;
  341. break;
  342. }
  343. }
  344. return(rc);
  345. } // end ParseCommandLineW
  346. /*****************************************************************************
  347. *
  348. * IsTokenPresentW (UNICODE version)
  349. *
  350. * Determines if a specified command line token (in given TOKMAPW array)
  351. * was present on the command line.
  352. *
  353. * ENTRY:
  354. * ptm (input)
  355. * Points to 0-terminated TOKMAPW array to scan.
  356. * pToken (input)
  357. * The token to scan for.
  358. *
  359. * EXIT:
  360. * TRUE if the specified token was present on the command line;
  361. * FALSE otherwise.
  362. *
  363. ****************************************************************************/
  364. BOOLEAN WINAPI
  365. IsTokenPresentW( PTOKMAPW ptm,
  366. PWCHAR pToken )
  367. {
  368. int i;
  369. for ( i = 0; ptm[i].tmToken; i++ ) {
  370. if ( !wcscmp( ptm[i].tmToken, pToken ) )
  371. return( (ptm[i].tmFlag & TMFLAG_PRESENT) ? TRUE : FALSE );
  372. }
  373. return(FALSE);
  374. } // end IsTokenPresentW
  375. /*****************************************************************************
  376. *
  377. * SetTokenPresentW (UNICODE version)
  378. *
  379. * Forces a specified command line token (in given TOKMAPW array)
  380. * to be flagged as 'present' on the command line.
  381. *
  382. * ENTRY:
  383. * ptm (input)
  384. * Points to 0-terminated TOKMAPW array to scan.
  385. * pToken (input)
  386. * The token to scan for and set flags.
  387. *
  388. * EXIT:
  389. * TRUE if the specified token was found in the TOKMAPW array
  390. * (TMFLAG_PRESENT flag is set). FALSE otherwise.
  391. *
  392. ****************************************************************************/
  393. BOOLEAN WINAPI
  394. SetTokenPresentW( PTOKMAPW ptm,
  395. PWCHAR pToken )
  396. {
  397. int i;
  398. for ( i = 0; ptm[i].tmToken; i++ ) {
  399. if ( !wcscmp( ptm[i].tmToken, pToken ) ) {
  400. ptm[i].tmFlag |= TMFLAG_PRESENT;
  401. return(TRUE);
  402. }
  403. }
  404. return(FALSE);
  405. } // end SetTokenPresentW
  406. /*****************************************************************************
  407. *
  408. * SetTokenNotPresentW (UNICODE version)
  409. *
  410. * Forces a specified command line token (in given TOKMAPW array)
  411. * to be flagged as 'not present' on the command line.
  412. *
  413. * ENTRY:
  414. * ptm (input)
  415. * Points to 0-terminated TOKMAPW array to scan.
  416. * pToken (input)
  417. * The token to scan for and set flags.
  418. *
  419. * EXIT:
  420. * TRUE if the specified token was found in the TOKMAPW array
  421. * (TMFLAG_PRESENT flag is reset). FALSE otherwise.
  422. *
  423. ****************************************************************************/
  424. BOOLEAN WINAPI
  425. SetTokenNotPresentW( PTOKMAPW ptm,
  426. PWCHAR pToken )
  427. {
  428. int i;
  429. for ( i = 0; ptm[i].tmToken; i++ ) {
  430. if ( !wcscmp( ptm[i].tmToken, pToken ) ) {
  431. ptm[i].tmFlag &= ~TMFLAG_PRESENT;
  432. return(TRUE);
  433. }
  434. }
  435. return(FALSE);
  436. } // end SetTokenNotPresentW
  437. /*****************************************************************************
  438. *
  439. * StoreArgument:
  440. *
  441. * ENTRY:
  442. * ptm - a pointer to an entry in the token array map
  443. * s - the argument to be entered into the current token array map entry.
  444. *
  445. * EXIT:
  446. * Normal:
  447. * TRUE
  448. *
  449. * Error:
  450. * FALSE
  451. *
  452. * ALGORITHM:
  453. *
  454. ****************************************************************************/
  455. USHORT
  456. StoreArgument( PTOKMAPW ptm,
  457. WCHAR *s )
  458. {
  459. char *pByte;
  460. WCHAR *pChar;
  461. SHORT *pShort;
  462. USHORT *pUShort;
  463. LONG *pLong;
  464. ULONG *pULong;
  465. WCHAR *pEnd = s; //pointer to end of conversion
  466. /*
  467. * If the string is empty, allow it for real 'strings'!
  468. */
  469. if( !wcslen(s) ) {
  470. switch ( ptm->tmForm ) {
  471. case TMFORM_S_STRING:
  472. case TMFORM_STRING:
  473. pChar = (WCHAR *) ptm->tmAddr;
  474. pChar[0] = (WCHAR)NULL;
  475. return( TRUE );
  476. }
  477. return( FALSE );
  478. }
  479. /*
  480. * Fail if there is no room to store result.
  481. */
  482. if ( ptm->tmDLen == 0) {
  483. return(FALSE);
  484. }
  485. switch(ptm->tmForm) {
  486. case TMFORM_BOOLEAN:
  487. SetBoolean(ptm, TRUE);
  488. break;
  489. case TMFORM_BYTE:
  490. pByte = (BYTE *) ptm->tmAddr;
  491. *pByte = (BYTE) wcstol(s, &pEnd, 10);
  492. if (pEnd == s)
  493. {
  494. return FALSE;
  495. }
  496. break;
  497. case TMFORM_CHAR:
  498. pChar = (WCHAR *) ptm->tmAddr;
  499. *pChar = s[0];
  500. break;
  501. case TMFORM_S_STRING:
  502. if (*s == L'\\') {
  503. ++s;
  504. }
  505. case TMFORM_DATE:
  506. case TMFORM_PHONE:
  507. case TMFORM_STRING:
  508. case TMFORM_X_STRING:
  509. //Added by a-skuzin
  510. //case when we need parameter to start with '-' or '/' and use "\-" or"\/"
  511. if(s[0]==L'\\' && (s[1]==L'-' || s[1]==L'/' || s[1]==L'\\') ) {
  512. ++s;
  513. }
  514. //end of "added by a-skuzin"
  515. pChar = (WCHAR *) ptm->tmAddr;
  516. wcsncpy(pChar, s, ptm->tmDLen);
  517. break;
  518. case TMFORM_SHORT:
  519. pShort = (SHORT *) ptm->tmAddr;
  520. *pShort = (SHORT) wcstol(s, &pEnd, 10);
  521. if (pEnd == s)
  522. {
  523. return FALSE;
  524. }
  525. break;
  526. case TMFORM_USHORT:
  527. if ( s[0] == L'-') { /* no negative numbers! */
  528. return( FALSE );
  529. }
  530. pUShort = (USHORT *) ptm->tmAddr;
  531. *pUShort = (USHORT) wcstol(s, &pEnd, 10);
  532. if (pEnd == s)
  533. {
  534. return FALSE;
  535. }
  536. break;
  537. case TMFORM_LONG:
  538. pLong = (LONG *) ptm->tmAddr;
  539. *pLong = wcstol(s, &pEnd, 10);
  540. if (pEnd == s)
  541. {
  542. return FALSE;
  543. }
  544. break;
  545. case TMFORM_SERIAL:
  546. case TMFORM_ULONG:
  547. if ( s[0] == L'-') { /* no negative numbers! */
  548. return (FALSE);
  549. }
  550. pULong = (ULONG *) ptm->tmAddr;
  551. *pULong = (ULONG) wcstol(s, &pEnd, 10);
  552. if (pEnd == s)
  553. {
  554. return FALSE;
  555. }
  556. break;
  557. case TMFORM_HEX:
  558. if ( s[0] == L'-') { /* no negative numbers! */
  559. return( FALSE );
  560. }
  561. pUShort = (USHORT *) ptm->tmAddr;
  562. *pUShort = (USHORT) wcstoul(s,NULL,16);
  563. break;
  564. case TMFORM_LONGHEX:
  565. if ( s[0] == L'-') { /* no negative numbers! */
  566. return( FALSE );
  567. }
  568. pULong = (ULONG *) ptm->tmAddr;
  569. *pULong = wcstoul(s,NULL,16);
  570. break;
  571. default: /* if invalid format return FALSE */
  572. return(FALSE);
  573. break;
  574. }
  575. return(TRUE);
  576. }