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.

932 lines
27 KiB

  1. // *********************************************************************************
  2. //
  3. // Copyright (c) Microsoft Corporation
  4. //
  5. // Module Name:
  6. //
  7. // CmdLineParser.c
  8. //
  9. // Abstract:
  10. //
  11. // This modules implements parsing of command line arguments for the specified options
  12. //
  13. // Author:
  14. //
  15. // Sunil G.V.N. Murali ([email protected]) 1-Sep-2000
  16. //
  17. // Revision History:
  18. //
  19. // Sunil G.V.N. Murali ([email protected]) 1-Sep-2000 : Created It.
  20. //
  21. // *********************************************************************************
  22. #include "pch.h"
  23. #include "cmdline.h"
  24. #include "CmdLineRes.h"
  25. //
  26. // macros
  27. //
  28. #define CHECK_FLAG( value, mask, flag ) ( ( value & mask ) == flag ? TRUE : FALSE )
  29. #define TYPEIS_NUMERIC( flag ) ( CHECK_FLAG( flag, CP_TYPE_MASK, CP_TYPE_NUMERIC ) )
  30. //
  31. // defines / constants / enumerations
  32. //
  33. #define OPTION_CHARACTERS _T( "-/" )
  34. // error messages
  35. #define ERROR_CMDPARSER_LENGTH_EXCEEDED \
  36. GetResString( IDS_ERROR_CMDPARSER_LENGTH_EXCEEDED )
  37. #define ERROR_CMDPARSER_VALUE_EXPECTED \
  38. GetResString( IDS_ERROR_CMDPARSER_VALUE_EXPECTED )
  39. #define ERROR_CMDPARSER_NOTINLIST \
  40. GetResString( IDS_ERROR_CMDPARSER_NOTINLIST )
  41. #define ERROR_CMDPARSER_INVALID_NUMERIC \
  42. GetResString( IDS_ERROR_CMDPARSER_INVALID_NUMERIC )
  43. #define ERROR_CMDPARSER_INVALID_FLOAT \
  44. GetResString( IDS_ERROR_CMDPARSER_INVALID_FLOAT )
  45. #define ERROR_CMDPARSER_OPTION_REPEATED \
  46. GetResString( IDS_ERROR_CMDPARSER_OPTION_REPEATED )
  47. #define ERROR_CMDPARSER_MANDATORY_OPTION_MISSING \
  48. GetResString( IDS_ERROR_CMDPARSER_MANDATORY_OPTION_MISSING )
  49. #define ERROR_CMDPARSER_INVALID_OPTION \
  50. GetResString( IDS_ERROR_CMDPARSER_INVALID_OPTION )
  51. #define ERROR_CMDPARSER_DEFAULT_OPTION_MISSING \
  52. GetResString( IDS_ERROR_CMDPARSER_DEFAULT_OPTION_MISSING )
  53. #define ERROR_CMDPARSER_DEFAULT_OPTION_REPEATED \
  54. GetResString( IDS_ERROR_CMDPARSER_DEFAULT_OPTION_REPEATED )
  55. #define ERROR_CMDPARSER_DEFAULT_NOTINLIST \
  56. GetResString( IDS_ERROR_CMDPARSER_DEFAULT_NOTINLIST )
  57. //
  58. // private functions ... used only within this file
  59. //
  60. // ***************************************************************************
  61. // Routine Description:
  62. // returns the argument value is option or not
  63. //
  64. // Arguments:
  65. // [ in ] szOption : a pointer to a constant string
  66. //
  67. // Return Value:
  68. // TRUE or FALSE
  69. //
  70. // ***************************************************************************
  71. BOOL __IsOption( LPCTSTR szOption )
  72. {
  73. // check the input value
  74. if ( szOption == NULL )
  75. {
  76. SetLastError( ERROR_INVALID_PARAMETER );
  77. SaveLastError();
  78. return FALSE;
  79. }
  80. // check whether the string starts with '-' or '/' character
  81. if ( lstrlen( szOption ) > 1 && _tcschr( OPTION_CHARACTERS, szOption[ 0 ] ) != NULL )
  82. return TRUE; // string value is an option
  83. // this is not an option
  84. return FALSE;
  85. }
  86. // ***************************************************************************
  87. // Routine Description:
  88. // compares the option value with argument and returns true
  89. // or false accordingly
  90. //
  91. // Arguments:
  92. // [in] szOption : a pointer to a string which specifies the option
  93. // against which the argument is to be compared
  94. // [in] szArgument : a pointer to a string which specifies the argument
  95. // for which the option string is to be compared
  96. // [in] bIgnoreCase : Ignore the case
  97. //
  98. // Return Value:
  99. // TRUE or FALSE
  100. //
  101. // ***************************************************************************
  102. BOOL __CompareArgument( LPCTSTR szOption, LPCTSTR szArgument, BOOL bIgnoreCase )
  103. {
  104. // local variables
  105. BOOL bResult = FALSE;
  106. // check the input value
  107. if ( szOption == NULL || szArgument == NULL )
  108. {
  109. SetLastError( ERROR_INVALID_PARAMETER );
  110. SaveLastError();
  111. return FALSE;
  112. }
  113. // first check whether the argument is an option or not
  114. // if the argument is not an option, return from here itself
  115. if ( __IsOption( szArgument ) == FALSE )
  116. return FALSE;
  117. // do the case-insensitive comparision
  118. // Note: here while comparing ignore the first character in the argument
  119. // this is im-material for us ... 'coz we are comparing the option and the argument
  120. // only after confirming that the argument is starting with the option character
  121. bResult = InString( szArgument + 1, szOption, TRUE );
  122. // return the result
  123. return bResult;
  124. }
  125. // ***************************************************************************
  126. // Routine Description:
  127. // checks the cmdOptions array for the given option and
  128. // returns the index of the cmdOptions array at which the given option
  129. // matches
  130. //
  131. // Arguments:
  132. // [ in ] dwOptions : no. of options in the options array
  133. // [ in ] pcmdOptions : an array of TCMDPARSER structors (i.e. options array)
  134. // [ in ] szOption : a pointer to a string which is the option that is to be
  135. // compared
  136. //
  137. // Return Value:
  138. // The index of the options array at which the given option matches
  139. //
  140. // ***************************************************************************
  141. LONG __MatchOption( DWORD dwOptions, PTCMDPARSER pcmdOptions, LPCTSTR szOption )
  142. {
  143. // local variables
  144. DWORD dwIndex = 0;
  145. BOOL bOption = TRUE;
  146. LONG lDefaultIndex = -1; // holds the default options index
  147. // check the input value
  148. if ( pcmdOptions == NULL || szOption == NULL )
  149. {
  150. SetLastError( ERROR_INVALID_PARAMETER );
  151. SaveLastError();
  152. return -1;
  153. }
  154. // check whether the passed argument is an option or not.
  155. // option : starts with '-' or '/'
  156. bOption = __IsOption( szOption );
  157. // parse thru the list of options and return the appropriate option id to the caller
  158. for( dwIndex = 0; dwIndex < dwOptions; dwIndex++ )
  159. {
  160. // get the
  161. TCMDPARSER cmdparser = pcmdOptions[ dwIndex ];
  162. // check if the current cmdparser option referes to the default option
  163. // if yes, save the index
  164. if ( cmdparser.dwFlags & CP_DEFAULT )
  165. lDefaultIndex = dwIndex;
  166. // based on the argument, if it starts with option character
  167. if ( bOption )
  168. {
  169. // find the appropriate option entry in parser list
  170. if ( __CompareArgument( cmdparser.szOption, szOption, TRUE ) )
  171. return dwIndex; // option matched
  172. }
  173. else
  174. {
  175. // else find the default option entry
  176. if ( cmdparser.dwFlags & CP_DEFAULT )
  177. return dwIndex; // the current entry represents the default
  178. }
  179. }
  180. // here we know that option is not found
  181. return lDefaultIndex;
  182. };
  183. // ***************************************************************************
  184. // Routine Description:
  185. //
  186. // Arguments:
  187. //
  188. // Return Value:
  189. //
  190. // ***************************************************************************
  191. VOID __SplitColon( LPCTSTR pszOption, LPTSTR* ppszOptionArg, LPTSTR* ppszValueArg )
  192. {
  193. // local variables
  194. DWORD dwValueLength = 0;
  195. DWORD dwOptionLength = 0;
  196. LPCTSTR pszTemp = NULL;
  197. // search for ':' seperator
  198. pszTemp = _tcschr( pszOption, _T( ':' ) );
  199. if ( pszTemp == NULL )
  200. return;
  201. // determine the length of option and value arguments
  202. dwValueLength = lstrlen( pszTemp ) - 1;
  203. dwOptionLength = lstrlen( pszOption ) - dwValueLength - 1;
  204. // now allocate buffers for option and value arguments
  205. *ppszValueArg = __calloc( dwValueLength + 5, sizeof( TCHAR ) );
  206. *ppszOptionArg = __calloc( dwOptionLength + 5, sizeof( TCHAR ) );
  207. if ( *ppszValueArg == NULL || *ppszOptionArg == NULL )
  208. {
  209. __free( *ppszValueArg );
  210. __free( *ppszOptionArg );
  211. *ppszValueArg = NULL;
  212. *ppszOptionArg = NULL;
  213. return;
  214. }
  215. // copy the values into appropriate buffers
  216. lstrcpy( *ppszValueArg, pszTemp + 1 );
  217. lstrcpyn( *ppszOptionArg, pszOption, dwOptionLength + 1 ); // +1 for null character
  218. }
  219. //
  220. // public functions ... exposed to external world
  221. //
  222. // ***************************************************************************
  223. // Routine Description:
  224. // The routine will parse the command line arguments for the options
  225. //
  226. // Arguments:
  227. // [ in ] dwCount : an integer variable represents no. of arguments supplied
  228. // through command line
  229. // [ in ] argv : an array of command line arguments
  230. // [ in ] dwOptionsCount : an integer represents the no.of elements in pcmdOptions
  231. // array
  232. // [ in ] pcmdOptions : an array of TCMDPARSER structures (i.e an array of options)
  233. //
  234. // Return Value:
  235. // returns TRUE if parsing done successfully, otherwise returns FALSE
  236. //
  237. // ***************************************************************************
  238. BOOL DoParseParam( DWORD dwCount,
  239. LPCTSTR argv[],
  240. DWORD dwOptionsCount,
  241. PTCMDPARSER pcmdOptions )
  242. {
  243. // local variables
  244. DWORD i = 0;
  245. LONG lTemp = 0;
  246. LONG lIndex = 0;
  247. BOOL bUsage = FALSE;
  248. BOOL bResult = FALSE;
  249. BOOL bDefault = TRUE;
  250. BOOL bProcessValue = FALSE;
  251. BOOL bOptionHasValue = FALSE;
  252. BOOL bValueWithColon = FALSE;
  253. LPCTSTR pszValue = NULL;
  254. LPCTSTR pszOption = NULL;
  255. LPTSTR pszValueArg = NULL;
  256. LPTSTR pszOptionArg = NULL;
  257. PTCMDPARSER pcmdparser = NULL;
  258. __STRING_512 szBuffer = NULL_STRING;
  259. __STRING_512 szUtilityName = NULL_STRING;
  260. BOOL bCheck = FALSE ;
  261. // check the input value
  262. if ( argv == NULL || pcmdOptions == NULL )
  263. {
  264. SetLastError( ERROR_INVALID_PARAMETER );
  265. SaveLastError();
  266. return FALSE;
  267. }
  268. // check for version compatibility
  269. if ( IsWin2KOrLater() == FALSE )
  270. {
  271. SetReason( ERROR_OS_INCOMPATIBLE );
  272. return FALSE;
  273. }
  274. //
  275. // prepare the utility name
  276. {
  277. pszOption = NULL;
  278. for( i = 0; i < dwOptionsCount; i++ )
  279. {
  280. pcmdparser = pcmdOptions + i;
  281. if ( pcmdparser->dwFlags & CP_MAIN_OPTION )
  282. {
  283. pszOption = pcmdparser->szOption;
  284. break;
  285. }
  286. }
  287. //
  288. // strip the utility name
  289. lIndex = 0;
  290. while ( (pszValue = FindOneOf( argv[ 0 ], _T( "\\:" ), lIndex )) != NULL )
  291. {
  292. // determine and save the position
  293. lIndex = lstrlen( argv[ 0 ] ) - lstrlen( pszValue ) + 1;
  294. }
  295. // ...
  296. lstrcpy( szUtilityName, _X( argv[ 0 ] + lIndex ) );
  297. // check whether .EXE is present in the name or not if yes detach it
  298. lIndex = lstrlen( szUtilityName ) - 4; // total length - length of ".EXE"
  299. if ( lIndex <= 0 || StringCompare( szUtilityName + lIndex, _T( ".EXE" ), TRUE, 0 ) == 0 )
  300. {
  301. szUtilityName[ lIndex ] = '\0';
  302. }
  303. // if main option is available, add it
  304. if ( pszOption != NULL )
  305. {
  306. // add one space ( seperation )
  307. lstrcat( szUtilityName, _T( " /" ) );
  308. lstrcat( szUtilityName, pszOption );
  309. }
  310. // now add the help string ( /? )
  311. lstrcat( szUtilityName, _T( " /?" ) );
  312. // convert the string into upper case
  313. CharUpper( szUtilityName );
  314. }
  315. // Note: though the array starts at index 0 in C, the value at the array index 0
  316. // in a command line is the executable name ... so leave and parse the command line
  317. // from the second parameter i.e; array index 1
  318. SetReason( NULL_STRING ); // clear the existing error reason
  319. for( i = 1; i < dwCount; i++ )
  320. {
  321. // reset ...
  322. pszOptionArg = NULL;
  323. pszValueArg = NULL;
  324. bProcessValue = FALSE; // assume no need to process the value
  325. bOptionHasValue = FALSE; // assume that next arg is not a value
  326. bValueWithColon = FALSE;
  327. pszValue = NULL_STRING; // clear the existing contents
  328. // check the length of the value ... it should not exceed
  329. // the value defined with MAX_STRING_LENGTH
  330. if ( lstrlen( argv[ i ] ) > MAX_STRING_LENGTH )
  331. {
  332. SetReason( ERROR_CMDPARSER_LENGTH_EXCEEDED );
  333. SetLastError( MK_E_SYNTAX );
  334. return FALSE;
  335. }
  336. // find the appropriate the option match
  337. pszOption = argv[ i ];
  338. lIndex = __MatchOption( dwOptionsCount, pcmdOptions, pszOption );
  339. // check whether the option was found or not
  340. if ( lIndex == -1 )
  341. {
  342. //
  343. // invalid option ... syntax error
  344. // but as a special case user might have specified the value
  345. // along with the option using ':' as delimiter
  346. __SplitColon( pszOption, &pszOptionArg, &pszValueArg );
  347. if ( pszOptionArg != NULL && pszValueArg != NULL )
  348. lIndex = __MatchOption( dwOptionsCount, pcmdOptions, pszOptionArg );
  349. // check whether option was found atleast now or not
  350. if ( lIndex == -1 )
  351. {
  352. // set the reason for the failure and return
  353. FORMAT_STRING2( szBuffer, ERROR_CMDPARSER_INVALID_OPTION, _X( pszOption ), szUtilityName );
  354. SetLastError( MK_E_SYNTAX );
  355. SetReason( szBuffer );
  356. return FALSE;
  357. }
  358. else
  359. {
  360. pszValue = pszValueArg;
  361. pszOption = pszOptionArg;
  362. bValueWithColon = TRUE;
  363. bProcessValue = TRUE;
  364. bOptionHasValue = TRUE;
  365. }
  366. }
  367. // now get the structure entry representing the current option
  368. // and check the address pValue
  369. pcmdparser = pcmdOptions + lIndex;
  370. if ( pcmdparser->pValue == NULL )
  371. {
  372. SetLastError( ERROR_NOACCESS );
  373. __free( pszOptionArg );
  374. __free( pszValueArg );
  375. SaveLastError();
  376. return FALSE;
  377. }
  378. // now determine whether user has specified default parameter or option
  379. bDefault = FALSE;
  380. if ( pcmdparser->dwFlags & CP_DEFAULT )
  381. {
  382. //
  383. // default option
  384. // but there is twist ... still user might have given default argument
  385. // and again an option ... here there is a twist ... for example
  386. // for some utilities, server names can be given directly without any option
  387. // or else along with the option say -s. We need to handle this carefully
  388. bDefault = ! ( __IsOption( pszOption ) &&
  389. __CompareArgument( pcmdparser->szOption, pszOption, TRUE ) );
  390. }
  391. // do furthur checking on the current option
  392. // this is to determine whether this is a default option
  393. // option which doesn't take any value
  394. // note: checking depends on the type of the current argument
  395. if ( bDefault == FALSE && __IsOption( pszOption ) == TRUE )
  396. {
  397. // check whether next argument is available in array or not
  398. if ( i + 1 < dwCount && bOptionHasValue == FALSE )
  399. {
  400. // check whether the next argument length is greater than 255
  401. if ( lstrlen( argv[ i + 1 ] ) > MAX_STRING_LENGTH )
  402. {
  403. SetReason( ERROR_CMDPARSER_LENGTH_EXCEEDED );
  404. SetLastError( MK_E_SYNTAX );
  405. return FALSE;
  406. }
  407. // check whether next argument starts with option character or not
  408. if ( __IsOption( argv[ i + 1 ] ) == TRUE )
  409. {
  410. // if the option is expecting a numeric value, check if it is a
  411. // numeric value or not. if it is a numeric value
  412. if ( TYPEIS_NUMERIC( pcmdparser->dwFlags ) && IsNumeric( argv[ i+1 ], 10, TRUE ) )
  413. {
  414. // next argument is value ... possibly a -ve value
  415. bOptionHasValue = TRUE;
  416. }
  417. else
  418. {
  419. // check if this is an valid option or value
  420. lTemp = __MatchOption( dwOptionsCount, pcmdOptions, argv[ i + 1 ] );
  421. if ( lTemp == -1 && ( pcmdparser->dwFlags & CP_VALUE_MASK ) )
  422. {
  423. // this is not an option ... it should a value only
  424. bOptionHasValue = TRUE;
  425. }
  426. }
  427. }
  428. else if ( pcmdparser->dwFlags & CP_VALUE_MASK )
  429. bOptionHasValue = TRUE; // next option can store this value
  430. }
  431. // now check whether the next argument is value or not for an option
  432. // who should have value as mandatory
  433. if ( ( pcmdparser->dwFlags & CP_VALUE_MANDATORY ) && bOptionHasValue == FALSE )
  434. {
  435. //
  436. // error ... this option is expecting a value
  437. // set the reason for the failure and return
  438. __free( pszOptionArg );
  439. __free( pszValueArg );
  440. FORMAT_STRING2( szBuffer, ERROR_CMDPARSER_VALUE_EXPECTED, _X( pszOption ), szUtilityName );
  441. SetLastError( MK_E_SYNTAX );
  442. SetReason( szBuffer );
  443. return FALSE;
  444. }
  445. // now, if the next argument is a value for the option
  446. if ( bOptionHasValue )
  447. {
  448. // if value is not specified with colon, then next argument is the
  449. // value for this option
  450. if ( bValueWithColon == FALSE )
  451. pszValue = argv[ i + 1 ];
  452. // check the length of the value ... it should not exceed
  453. // the value defined with MAX_STRING_LENGTH
  454. if ( lstrlen( pszValue ) > MAX_STRING_LENGTH )
  455. {
  456. __free( pszOptionArg );
  457. __free( pszValueArg );
  458. SetReason( ERROR_CMDPARSER_LENGTH_EXCEEDED );
  459. SetLastError( MK_E_SYNTAX );
  460. return FALSE;
  461. }
  462. // indicate that value has to be validated
  463. bProcessValue = TRUE;
  464. }
  465. }
  466. else if ( bDefault == TRUE )
  467. {
  468. // check the length of the value in the argv ... it should not exceed
  469. // the value defined with MAX_STRING_LENGTH
  470. if ( lstrlen( pszOption ) >= MAX_STRING_LENGTH )
  471. {
  472. __free( pszOptionArg );
  473. __free( pszValueArg );
  474. SetReason( ERROR_CMDPARSER_LENGTH_EXCEEDED );
  475. SetLastError( MK_E_SYNTAX );
  476. return FALSE;
  477. }
  478. // this is a default option
  479. bProcessValue = TRUE; // need to process the value
  480. pszValue = pszOption; // current option itself is a value
  481. }
  482. // check whether we need to do the process the value or not
  483. if ( bProcessValue && ( ! ( pcmdparser->dwFlags & CP_IGNOREVALUE ) ) )
  484. {
  485. // check whether this value should be in the list of values
  486. if ( ( pcmdparser->dwFlags & CP_MODE_VALUES ) &&
  487. ( ! InString( pszValue, pcmdparser->szValues, TRUE ) ) )
  488. {
  489. // current option value is not fitting the list of valid values
  490. // set the reason for the failure and return
  491. if ( bDefault == TRUE )
  492. {
  493. FORMAT_STRING2( szBuffer, ERROR_CMDPARSER_DEFAULT_NOTINLIST, _X( argv[ i ] ), szUtilityName );
  494. }
  495. else
  496. {
  497. FORMAT_STRING3( szBuffer,
  498. ERROR_CMDPARSER_NOTINLIST, _X1( argv[ i + 1 ] ), _X2( argv[ i ] ), szUtilityName );
  499. }
  500. // ...
  501. if( bCheck == FALSE )
  502. {
  503. bCheck = TRUE ;
  504. SetLastError( MK_E_SYNTAX );
  505. SetReason( szBuffer );
  506. }
  507. }
  508. // validate and set the value based on the 'type' option is expecting
  509. switch( pcmdparser->dwFlags & CP_TYPE_MASK )
  510. {
  511. case CP_TYPE_TEXT:
  512. {
  513. // check the mode of the input
  514. if ( pcmdparser->dwFlags & CP_MODE_ARRAY )
  515. {
  516. // if the mode is array, add to the array
  517. // but before adding check whether duplicates
  518. // has to be eliminated or not
  519. lIndex = -1;
  520. if ( pcmdparser->dwFlags & CP_VALUE_NODUPLICATES )
  521. {
  522. // check whether current value already exists in the list or not
  523. lIndex = DynArrayFindString(
  524. *((PTARRAY) pcmdparser->pValue), pszValue, TRUE, 0 );
  525. }
  526. // now add the value to array only if the item doesn't exist in list
  527. if ( lIndex == -1 )
  528. DynArrayAppendString( *((PTARRAY) pcmdparser->pValue), pszValue, 0 );
  529. }
  530. else
  531. {
  532. // else just do copy
  533. lstrcpy( ( LPTSTR ) pcmdparser->pValue, pszValue );
  534. }
  535. // break from the switch ... case
  536. break;
  537. }
  538. case CP_TYPE_NUMERIC:
  539. {
  540. // check whether the value is numeric or not
  541. if ( IsNumeric( pszValue, 10, TRUE ) == FALSE )
  542. {
  543. //
  544. // error ... non numeric value
  545. // set the reason for the failure and return
  546. if( bCheck == FALSE )
  547. {
  548. bCheck = TRUE ;
  549. FORMAT_STRING2( szBuffer, ERROR_CMDPARSER_INVALID_NUMERIC, _X( argv[ i ] ), szUtilityName );
  550. SetLastError( MK_E_SYNTAX );
  551. SetReason( szBuffer );
  552. }
  553. break;
  554. }
  555. // check the mode of the input
  556. // if the mode is array, add to the array
  557. if ( pcmdparser->dwFlags & CP_MODE_ARRAY )
  558. {
  559. DynArrayAppendLong(
  560. *((PTARRAY) pcmdparser->pValue), AsLong( pszValue, 10 ) );
  561. }
  562. else // else just do copy
  563. {
  564. *( ( LONG* ) pcmdparser->pValue ) = AsLong( pszValue, 10 );
  565. }
  566. // break from the switch ... case
  567. break;
  568. }
  569. case CP_TYPE_UNUMERIC:
  570. {
  571. // check whether the value is numeric or not
  572. if ( IsNumeric( pszValue, 10, FALSE ) == FALSE )
  573. {
  574. //
  575. // error ... non numeric value
  576. // set the reason for the failure and return
  577. if( bCheck == FALSE )
  578. {
  579. bCheck = TRUE ;
  580. FORMAT_STRING2( szBuffer, ERROR_CMDPARSER_INVALID_NUMERIC, _X( argv[ i ] ), szUtilityName );
  581. SetLastError( MK_E_SYNTAX );
  582. SetReason( szBuffer );
  583. }
  584. break;
  585. }
  586. // check the mode of the input
  587. // if the mode is array, add to the array
  588. if ( pcmdparser->dwFlags & CP_MODE_ARRAY )
  589. {
  590. DynArrayAppendDWORD(
  591. *((PTARRAY) pcmdparser->pValue), (DWORD) AsLong( pszValue, 10 ) );
  592. }
  593. else // else just do copy
  594. {
  595. *( ( DWORD* ) pcmdparser->pValue ) = (DWORD) AsLong( pszValue, 10 );
  596. }
  597. // break from the switch ... case
  598. break;
  599. }
  600. case CP_TYPE_FLOAT:
  601. {
  602. // check whether the value is floating point or not
  603. if ( IsFloatingPoint( pszValue ) == FALSE )
  604. {
  605. //
  606. // error ... non floating point value
  607. // set the reason for the failure and return
  608. if( bCheck == FALSE )
  609. {
  610. bCheck = TRUE ;
  611. FORMAT_STRING2( szBuffer, ERROR_CMDPARSER_INVALID_FLOAT, _X( argv[ i ] ), szUtilityName );
  612. SetLastError( MK_E_SYNTAX );
  613. SetReason( szBuffer );
  614. }
  615. break;
  616. }
  617. // check the mode of the input
  618. // if the mode is array, add to the array
  619. if ( pcmdparser->dwFlags & CP_MODE_ARRAY )
  620. {
  621. DynArrayAppendFloat(
  622. *((PTARRAY) pcmdparser->pValue), (float) AsFloat( pszValue ) );
  623. }
  624. else // else just do copy
  625. {
  626. *( ( float* ) pcmdparser->pValue ) = (float) AsFloat( pszValue );
  627. }
  628. // break from the switch ... case
  629. break;
  630. }
  631. case CP_TYPE_DOUBLE:
  632. {
  633. // check whether the value is floating point or not
  634. if ( IsFloatingPoint( pszValue ) == FALSE )
  635. {
  636. //
  637. // error ... non floating point value
  638. // set the reason for the failure and return
  639. if( bCheck == FALSE )
  640. {
  641. bCheck = TRUE ;
  642. FORMAT_STRING2( szBuffer, ERROR_CMDPARSER_INVALID_FLOAT, _X( argv[ i ] ), szUtilityName );
  643. SetLastError( MK_E_SYNTAX );
  644. SetReason( szBuffer );
  645. }
  646. break;
  647. }
  648. // check the mode of the input
  649. // if the mode is array, add to the array
  650. if ( pcmdparser->dwFlags & CP_MODE_ARRAY )
  651. {
  652. DynArrayAppendDouble( *((PTARRAY) pcmdparser->pValue), AsFloat( pszValue ) );
  653. }
  654. else // else just do copy
  655. {
  656. *( ( double* ) pcmdparser->pValue ) = AsFloat( pszValue );
  657. }
  658. // break from the switch ... case
  659. break;
  660. }
  661. case CP_TYPE_CUSTOM:
  662. {
  663. // check whether function pointer is specified or not
  664. // if not specified, error
  665. if ( pcmdparser->pFunction == NULL )
  666. {
  667. //
  668. // function ptr not specified ... error
  669. // set the reason for the failure and return
  670. if( bCheck == FALSE )
  671. {
  672. bCheck = TRUE ;
  673. SetLastError( STG_E_INVALIDPARAMETER );
  674. SaveLastError();
  675. }
  676. break;
  677. }
  678. // call the custom function
  679. // and result itself is return value of this function
  680. bResult = ( *pcmdparser->pFunction)( argv[ i ], pszValue,
  681. pcmdparser->pFunctionData == NULL ? pcmdparser : pcmdparser->pFunctionData );
  682. // check the result
  683. if ( ( bResult == FALSE ) && (bCheck == FALSE ) )
  684. {
  685. bCheck = TRUE ;
  686. break ;
  687. }
  688. // break from the switch ... case
  689. break;
  690. }
  691. case CP_TYPE_DATE:
  692. case CP_TYPE_TIME:
  693. case CP_TYPE_DATETIME:
  694. {
  695. // break from the switch ... case
  696. break;
  697. }
  698. default:
  699. {
  700. // default is assumed to boolean type
  701. *( ( BOOL* ) pcmdparser->pValue ) = TRUE;
  702. // break from the switch ... case
  703. break;
  704. }
  705. }
  706. }
  707. else
  708. {
  709. // default is assumed to boolean type
  710. // NOTE: only in case the option is not accepting optional value
  711. if ( (pcmdparser->dwFlags & CP_VALUE_MASK) != CP_VALUE_OPTIONAL )
  712. *( ( BOOL* ) pcmdparser->pValue ) = TRUE;
  713. }
  714. // check whether next argument is treated as value or not
  715. // if next argument is treated as value and finished, processing,
  716. // increment the argument index variable so that it will process the next option
  717. if ( bOptionHasValue && bValueWithColon == FALSE )
  718. i++;
  719. // increment the option repetition count at the command prompt
  720. pcmdparser->dwActuals++;
  721. // find out if the current option refers help item
  722. if ( pcmdparser->dwFlags & CP_USAGE )
  723. bUsage = TRUE; // usage is specified
  724. // now check whether option repeated excess no. of times or not
  725. if ( pcmdparser->dwCount != 0 && pcmdparser->dwActuals > pcmdparser->dwCount )
  726. {
  727. //
  728. // syntax error ... option repeatition count exceeded
  729. // set the reason for the failure and return
  730. if ( bDefault == TRUE )
  731. {
  732. // its an default argument
  733. FORMAT_STRING2( szBuffer,
  734. ERROR_CMDPARSER_DEFAULT_OPTION_REPEATED, pcmdparser->dwCount, szUtilityName );
  735. }
  736. else
  737. {
  738. // its an option
  739. FORMAT_STRING3( szBuffer,
  740. ERROR_CMDPARSER_OPTION_REPEATED, _X( pszOption ), pcmdparser->dwCount, szUtilityName );
  741. }
  742. // ...
  743. SetReason( NULL_STRING );
  744. __free( pszOptionArg );
  745. __free( pszValueArg );
  746. SetLastError( MK_E_SYNTAX );
  747. SetReason( szBuffer );
  748. return FALSE;
  749. }
  750. // release memory
  751. __free( pszValueArg );
  752. __free( pszOptionArg );
  753. }
  754. // atlast check whether the mandatory options has come or not
  755. // NOTE: checking of mandatory options will be done only if help is requested
  756. for( i = 0; bUsage == FALSE && i < dwOptionsCount; i++ )
  757. {
  758. // check whether the option has come or not if it is mandatory
  759. pcmdparser = pcmdOptions + i;
  760. if ( ( pcmdparser->dwFlags & CP_MANDATORY ) && pcmdparser->dwActuals == 0 )
  761. {
  762. //
  763. // mandatory option not exist ... fail
  764. // set the reason for the failure and return
  765. if ( lstrlen( pcmdparser->szOption ) != 0 )
  766. {
  767. FORMAT_STRING2( szBuffer,
  768. ERROR_CMDPARSER_MANDATORY_OPTION_MISSING, pcmdparser->szOption, szUtilityName );
  769. }
  770. else
  771. {
  772. FORMAT_STRING( szBuffer, ERROR_CMDPARSER_DEFAULT_OPTION_MISSING, szUtilityName );
  773. }
  774. SetReason( NULL_STRING );
  775. SetLastError( MK_E_SYNTAX );
  776. SetReason( szBuffer );
  777. return FALSE;
  778. }
  779. }
  780. // command line parsing went well ... return success
  781. if( bCheck == TRUE )
  782. {
  783. return FALSE ;
  784. }
  785. else
  786. {
  787. return TRUE;
  788. }
  789. }
  790. // ***************************************************************************
  791. // Routine Description: Counts the no. of times the option is repeated at cmd prompt
  792. //
  793. // Arguments:
  794. // [in] szOption : a pointer to string which is an option for which the search
  795. // is to be made in options array
  796. // [in] dwCount : no. of entries in the cmdOptions array
  797. // [in] pcmdOptions: an array of TCMDPARSER structure (i.e an array of options)
  798. //
  799. // Return Value:
  800. // the count of no. of time the option is repeated at command prompt
  801. //
  802. // ***************************************************************************
  803. DWORD GetOptionCount( LPCTSTR szOption, DWORD dwCount, PTCMDPARSER pcmdOptions )
  804. {
  805. // local variables
  806. DWORD dw;
  807. PTCMDPARSER pcp;
  808. // check the input value
  809. if ( szOption == NULL || pcmdOptions == NULL )
  810. {
  811. SetLastError( ERROR_INVALID_PARAMETER );
  812. SaveLastError();
  813. return -1;
  814. }
  815. // traverse thru the loop and find out how many times, the option has repeated at cmd prompt
  816. for( dw = 0; dw < dwCount; dw++ )
  817. {
  818. // get the option information and check whether we are looking for this option or not
  819. // if the option is matched, return the no. of times the option is repeated at the command prompt
  820. pcp = pcmdOptions + dw;
  821. if ( StringCompare( pcp->szOption, szOption, TRUE, 0 ) == 0 )
  822. return pcp->dwActuals;
  823. }
  824. // this will / shouldn't occur
  825. return -1;
  826. }