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.

578 lines
21 KiB

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