getopt.c 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323
  1. /*++
  2. Copyright (c) 2013 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. getopt.c
  9. Abstract:
  10. This module implements support for the getopt family of functions, which is
  11. made for parsing command line arguments.
  12. Author:
  13. Evan Green 21-Aug-2013
  14. Environment:
  15. User Mode C Library
  16. --*/
  17. //
  18. // ------------------------------------------------------------------- Includes
  19. //
  20. #include "libcp.h"
  21. #include <assert.h>
  22. #include <ctype.h>
  23. #include <errno.h>
  24. #include <getopt.h>
  25. #include <libgen.h>
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <string.h>
  29. #include <unistd.h>
  30. //
  31. // ---------------------------------------------------------------- Definitions
  32. //
  33. //
  34. // Define string for the environment variable used to enforce correct POSIX
  35. // behavior.
  36. //
  37. #define GET_OPTION_CORRECT_POSIX_ENVIRONMENT_VARIABLE "POSIXLY_CORRECT"
  38. //
  39. // ------------------------------------------------------ Data Type Definitions
  40. //
  41. typedef enum _GET_OPTION_ERROR_TYPE {
  42. GetOptionErrorNone,
  43. GetOptionErrorMissingArgument,
  44. GetOptionErrorUnknownOption,
  45. GetOptionErrorAmbiguousOption,
  46. GetOptionErrorNoArgumentExpected,
  47. } GET_OPTION_ERROR_TYPE, *PGET_OPTION_ERROR_TYPE;
  48. /*++
  49. Structure Description:
  50. This structure stores the context needed to report a getopt error.
  51. Members:
  52. Type - Stores the error type that occurred.
  53. Option - Stores the short option character that caused the error.
  54. LongOption - Stores a pointer to the long option string that caused the
  55. error.
  56. CommandName - Stores the first command line argument: the command name.
  57. --*/
  58. typedef struct _GET_OPTION_ERROR {
  59. GET_OPTION_ERROR_TYPE Type;
  60. CHAR Option;
  61. const char *LongOption;
  62. PSTR CommandName;
  63. } GET_OPTION_ERROR, *PGET_OPTION_ERROR;
  64. //
  65. // ----------------------------------------------- Internal Function Prototypes
  66. //
  67. int
  68. ClpGetOption (
  69. int ArgumentCount,
  70. char *const Arguments[],
  71. const char *Options,
  72. const struct option *LongOptions,
  73. int *LongIndex,
  74. BOOL ShortLongOptions
  75. );
  76. int
  77. ClpGetShortOption (
  78. int ArgumentCount,
  79. char *const Arguments[],
  80. const char *Options,
  81. const struct option *LongOptions,
  82. int *LongIndex,
  83. PGET_OPTION_ERROR Error
  84. );
  85. int
  86. ClpGetLongOption (
  87. int ArgumentCount,
  88. char *const Arguments[],
  89. const char *Argument,
  90. const char *Options,
  91. const struct option *LongOptions,
  92. int *LongIndex,
  93. PGET_OPTION_ERROR Error
  94. );
  95. int
  96. ClpMatchLongOption (
  97. const char *Argument,
  98. const struct option *Options,
  99. PGET_OPTION_ERROR Error
  100. );
  101. size_t
  102. ClpMatchLongOptionString (
  103. const char *Argument,
  104. const char *OptionName
  105. );
  106. void
  107. ClpPrintGetOptionError (
  108. PGET_OPTION_ERROR Error
  109. );
  110. //
  111. // -------------------------------------------------------------------- Globals
  112. //
  113. //
  114. // Define the global that points to the argument if the getopt function finds
  115. // an option that takes an argument.
  116. //
  117. LIBC_API char *optarg;
  118. //
  119. // Define the global that contains the index of the next argument to be
  120. // processed by the getopt function.
  121. //
  122. LIBC_API int optind = 1;
  123. //
  124. // Define the global that controls whether or not an error message is printed
  125. // to standrad error when the getopt function detects an error. The user can
  126. // set this to 0 to disable such messages.
  127. //
  128. LIBC_API int opterr = 1;
  129. //
  130. // Define the global that is set to the unknown option if an option is passed
  131. // in the arguments that is not in the options string during a call to getopt.
  132. //
  133. LIBC_API int optopt;
  134. //
  135. // Define the global that can be used to reset the option system so that it
  136. // can be called with a different array or called repeatedly on the same array.
  137. // Setting optind to zero has the same effect as setting optreset to non-zero.
  138. //
  139. LIBC_API int optreset;
  140. //
  141. // Define a variable containing the next character index to look in the
  142. // current argument in the getopt function.
  143. //
  144. int ClNextOptionCharacter = 1;
  145. //
  146. // Define a copy of the optind variable that is used to detect if the user
  147. // tried to reset the getopt state.
  148. //
  149. int ClOptionIndexCopy;
  150. //
  151. // Define a variable containing the first non-option string encountered.
  152. //
  153. char *ClFirstNonOption;
  154. //
  155. // Define a variable used to store the index of the option end delimiter "--".
  156. //
  157. int ClOptionEndIndex;
  158. //
  159. // ------------------------------------------------------------------ Functions
  160. //
  161. LIBC_API
  162. int
  163. getopt (
  164. int ArgumentCount,
  165. char *const Arguments[],
  166. const char *Options
  167. )
  168. /*++
  169. Routine Description:
  170. This routine parses command line arguments, successively returning each
  171. passed in argument. This routine is neither reentrant nor thread safe.
  172. Arguments:
  173. ArgumentCount - Supplies the argument count from main.
  174. Arguments - Supplies the argument array from main.
  175. Options - Supplies a pointer to a null terminated string containing the set
  176. of accepted options. Each character represents an allowed option. If
  177. a character is followed by a colon ':', then that option takes an
  178. argument. If an option with an argument is found and there are more
  179. characters in the current string, then the remainder of that string
  180. will be returned. Otherwise, the next argument will be returned. If
  181. there is no next argument, that's considered an error.
  182. Return Value:
  183. Returns the next option character on success. The global variable optind
  184. will be updated to reflect the index of the next argument to be processed.
  185. It will be initialied by the system to 1. If the option takes an argument,
  186. the global variable optarg will be set to point at that argument.
  187. Returns '?' if the option found is not in the recognized option string. The
  188. optopt global variable will be set to the unrecognized option that resulted
  189. in this condition. The '?' character is also returned if the options string
  190. does not begin with a colon ':' and a required argument is not found. If the
  191. opterr global variable has not been set to 0 by the user, then an error
  192. will be printed to standard error.
  193. Returns ':' if the options string begins with a colon and a required
  194. argument is missing. If the opterr global variable has not been set to 0 by
  195. the user, then an error will be printed to standard error.
  196. -1 if a non-option was encountered. In this case the optind global variable
  197. will be set to the first non-option argument.
  198. --*/
  199. {
  200. int Result;
  201. Result = ClpGetOption(ArgumentCount,
  202. Arguments,
  203. Options,
  204. NULL,
  205. NULL,
  206. FALSE);
  207. return Result;
  208. }
  209. LIBC_API
  210. int
  211. getopt_long (
  212. int ArgumentCount,
  213. char *const Arguments[],
  214. const char *ShortOptions,
  215. const struct option *LongOptions,
  216. int *LongIndex
  217. )
  218. /*++
  219. Routine Description:
  220. This routine works just like the getopt function (see that for details),
  221. except it allow allows long options of the form --option=argument or
  222. --option argument.
  223. Arguments:
  224. ArgumentCount - Supplies the argument count from main.
  225. Arguments - Supplies the argument array from main.
  226. ShortOptions - Supplies the short option string. This parameter works the
  227. same way as the Options string of getopt.
  228. LongOptions - Supplies a pointer to an array of long options. The array
  229. must be terminated with a NULLed out option structure. Long option
  230. names can be abbreviated in the argument list provided that the
  231. abbreviation is unique.
  232. LongIndex - Supplies an optional pointer that returns the index into the
  233. long options array of the long option that matched.
  234. Return Value:
  235. Returns the same set of values as the getopt function. If a long option
  236. masked, then either 0 or the value set inside the long option is returned
  237. depending on the flag member of the long option.
  238. --*/
  239. {
  240. int Result;
  241. Result = ClpGetOption(ArgumentCount,
  242. Arguments,
  243. ShortOptions,
  244. LongOptions,
  245. LongIndex,
  246. FALSE);
  247. return Result;
  248. }
  249. LIBC_API
  250. int
  251. getopt_long_only (
  252. int ArgumentCount,
  253. char *const Arguments[],
  254. const char *ShortOptions,
  255. const struct option *LongOptions,
  256. int *LongIndex
  257. )
  258. /*++
  259. Routine Description:
  260. This routine works just like the getopt_long function except it allows
  261. long arguments to have only one dash at the beginning instead of two
  262. (ie -option instead of --option). If an argument does not match for long
  263. options of either --option or -option, the short options will be tried.
  264. Arguments:
  265. ArgumentCount - Supplies the argument count from main.
  266. Arguments - Supplies the argument array from main.
  267. ShortOptions - Supplies the short option string. This parameter works the
  268. same way as the Options string of getopt.
  269. LongOptions - Supplies a pointer to an array of long options. The array
  270. must be terminated with a NULLed out option structure. Long option
  271. names can be abbreviated in the argument list provided that the
  272. abbreviation is unique.
  273. LongIndex - Supplies an optional pointer that returns the index into the
  274. long options array of the long option that matched.
  275. Return Value:
  276. Returns the same set of values as the getopt function. If a long option
  277. masked, then either 0 or the value set inside the long option is returned
  278. depending on the flag member of the long option.
  279. --*/
  280. {
  281. int Result;
  282. Result = ClpGetOption(ArgumentCount,
  283. Arguments,
  284. ShortOptions,
  285. LongOptions,
  286. LongIndex,
  287. TRUE);
  288. return Result;
  289. }
  290. //
  291. // --------------------------------------------------------- Internal Functions
  292. //
  293. int
  294. ClpGetOption (
  295. int ArgumentCount,
  296. char *const Arguments[],
  297. const char *Options,
  298. const struct option *LongOptions,
  299. int *LongIndex,
  300. BOOL ShortLongOptions
  301. )
  302. /*++
  303. Routine Description:
  304. This routine parses command line arguments for the getopt routines.
  305. Arguments:
  306. ArgumentCount - Supplies the argument count from main.
  307. Arguments - Supplies the argument array from main.
  308. Options - Supplies the short options string, which defines the set of legal
  309. short options.
  310. LongOptions - Supplies a pointer to an array of long option structures
  311. containing the long options.
  312. LongIndex - Supplies an optional pointer that if supplied will return the
  313. index into the long options array of the found long option.
  314. ShortLongOptions - Supplies a boolean indicating if long options starting
  315. with only one dash should be recognized.
  316. Return Value:
  317. Returns the option character or 0 if another option was found.
  318. Returns '?' if an unknown option was found, or a required argument is
  319. missing and the options string does not start with a colon.
  320. Returns ':' if a required argument to an option is missing and the options
  321. string starts with a colon.
  322. -1 if no more options were found.
  323. --*/
  324. {
  325. PSTR Argument;
  326. GET_OPTION_ERROR Error;
  327. BOOL FailNonOptions;
  328. ULONG Index;
  329. int Result;
  330. BOOL ReturnNonOptions;
  331. FailNonOptions = FALSE;
  332. ReturnNonOptions = FALSE;
  333. optarg = NULL;
  334. memset(&Error, 0, sizeof(Error));
  335. if (ArgumentCount == 0) {
  336. return -1;
  337. }
  338. Error.CommandName = Arguments[0];
  339. if ((optind <= 0) || (optreset != 0) || (ClOptionEndIndex <= 0) ||
  340. (ClOptionEndIndex >= ArgumentCount)) {
  341. optind = 1;
  342. optreset = 0;
  343. ClOptionIndexCopy = 1;
  344. ClNextOptionCharacter = 1;
  345. ClFirstNonOption = NULL;
  346. optarg = NULL;
  347. ClOptionEndIndex = ArgumentCount - 1;
  348. }
  349. //
  350. // Reset if the caller tried to manipulate the option index.
  351. //
  352. if (ClOptionIndexCopy != optind) {
  353. ClOptionIndexCopy = optind;
  354. ClNextOptionCharacter = 1;
  355. ClOptionEndIndex = ArgumentCount - 1;
  356. ClFirstNonOption = NULL;
  357. }
  358. //
  359. // Don't go off the end of the array.
  360. //
  361. if (optind >= ArgumentCount) {
  362. Result = -1;
  363. goto GetOptionEnd;
  364. }
  365. //
  366. // If there are short options and the first character is a -, then return
  367. // non-options as a option with value 1. If there are short options and
  368. // the first character is +, then fail if a non-option is encountered.
  369. //
  370. if (Options != NULL) {
  371. if (*Options == '-') {
  372. ReturnNonOptions = TRUE;
  373. Options += 1;
  374. } else if (*Options == '+') {
  375. FailNonOptions = TRUE;
  376. Options += 1;
  377. }
  378. }
  379. //
  380. // Check to see if the POSIXLY_CORRECT environment variable is present,
  381. // dictating that non-options should fail.
  382. //
  383. if (getenv(GET_OPTION_CORRECT_POSIX_ENVIRONMENT_VARIABLE) != NULL) {
  384. FailNonOptions = TRUE;
  385. }
  386. Argument = Arguments[optind];
  387. assert(Argument != NULL);
  388. //
  389. // Loop while the argument doesn't start with a '-', or is just a single
  390. // dash.
  391. //
  392. while ((*Argument != '-') || (*(Argument + 1) == '\0')) {
  393. ClNextOptionCharacter = 1;
  394. if (ReturnNonOptions != FALSE) {
  395. optarg = Argument;
  396. optind += 1;
  397. Result = 1;
  398. goto GetOptionEnd;
  399. } else if (FailNonOptions != FALSE) {
  400. Result = -1;
  401. goto GetOptionEnd;
  402. }
  403. //
  404. // If the first argument is reached again, it's time to give up.
  405. //
  406. if (Argument == ClFirstNonOption) {
  407. Result = -1;
  408. goto GetOptionEnd;
  409. }
  410. //
  411. // This non-option needs to be put at the end of the option list.
  412. // Shift everything down and try again with the new argument. Make sure
  413. // that the non-option gets put before any arguments that come after
  414. // the "--" delimiter.
  415. //
  416. // N.B. For legacy reasons - to match default C library behavior that
  417. // pre-dates 'const' - turn a blind eye to the fact that the
  418. // Arguments parameter is an array of constant pointers.
  419. //
  420. for (Index = optind; Index < ClOptionEndIndex; Index += 1) {
  421. if ((ClFirstNonOption == NULL) &&
  422. (strcmp(Arguments[Index + 1], "--") == 0)) {
  423. ClOptionEndIndex = Index + 1;
  424. }
  425. *((PSTR *)&(Arguments[Index])) = Arguments[Index + 1];
  426. }
  427. //
  428. // If this is the first time an argument has been thrown at the end,
  429. // remember it.
  430. //
  431. assert(Index < ArgumentCount);
  432. *((PSTR *)&(Arguments[Index])) = Argument;
  433. if (ClFirstNonOption == NULL) {
  434. ClFirstNonOption = Argument;
  435. }
  436. //
  437. // Get the new argument in the index position.
  438. //
  439. Argument = Arguments[optind];
  440. }
  441. if ((Argument[1] == '-') && (Argument[2] == '\0')) {
  442. optind += 1;
  443. Result = -1;
  444. goto GetOptionEnd;
  445. }
  446. assert(ClNextOptionCharacter <= strlen(Argument));
  447. //
  448. // If there are long options, try to parse them if 1) the argument starts
  449. // with -- or 2) It's a long_only call and either a) there are multiple
  450. // characters in the argument or b) it's not in the short arguments string.
  451. //
  452. if (LongOptions != NULL) {
  453. if ((Argument[1] == '-') ||
  454. ((ShortLongOptions != FALSE) &&
  455. ((Argument[2] != '\0') ||
  456. (strchr(Options, Argument[ClNextOptionCharacter]) == NULL)))) {
  457. if ((ClNextOptionCharacter == 1) && (Argument[1] == '-')) {
  458. ClNextOptionCharacter += 1;
  459. }
  460. Result = ClpGetLongOption(ArgumentCount,
  461. Arguments,
  462. Argument + ClNextOptionCharacter,
  463. Options,
  464. LongOptions,
  465. LongIndex,
  466. &Error);
  467. if (Result != '?') {
  468. ClNextOptionCharacter = 1;
  469. goto GetOptionEnd;
  470. }
  471. if ((Error.Type != GetOptionErrorUnknownOption) ||
  472. (ShortLongOptions == FALSE)) {
  473. goto GetOptionEnd;
  474. }
  475. optind -= 1;
  476. }
  477. }
  478. //
  479. // Try for a short option.
  480. //
  481. Result = ClpGetShortOption(ArgumentCount,
  482. Arguments,
  483. Options,
  484. LongOptions,
  485. LongIndex,
  486. &Error);
  487. GetOptionEnd:
  488. if ((Error.Type != GetOptionErrorNone) &&
  489. (opterr != 0) && ((Options == NULL) || (*Options != ':'))) {
  490. ClpPrintGetOptionError(&Error);
  491. }
  492. ClOptionIndexCopy = optind;
  493. return Result;
  494. }
  495. int
  496. ClpGetShortOption (
  497. int ArgumentCount,
  498. char *const Arguments[],
  499. const char *Options,
  500. const struct option *LongOptions,
  501. int *LongIndex,
  502. PGET_OPTION_ERROR Error
  503. )
  504. /*++
  505. Routine Description:
  506. This routine attempts to parse a single short option at the given location.
  507. Arguments:
  508. ArgumentCount - Supplies the number of arguments in the array.
  509. Arguments - Supplies the array of arguments.
  510. Options - Supplies the short options string, which defines the set of legal
  511. short options.
  512. LongOptions - Supplies a pointer to an array of long option structures
  513. containing the long options.
  514. LongIndex - Supplies an optional pointer that if supplied will return the
  515. index into the long options array of the found long option.
  516. Error - Supplies a pointer where the error information is returned.
  517. Return Value:
  518. Returns the values appropriate to return from the getopt functions.
  519. --*/
  520. {
  521. const char *Argument;
  522. int Option;
  523. BOOL StartsWithColon;
  524. assert(optind < ArgumentCount);
  525. assert(ClNextOptionCharacter != 0);
  526. Argument = Arguments[optind] + ClNextOptionCharacter;
  527. assert(*Argument != '\0');
  528. StartsWithColon = FALSE;
  529. if (*Options == ':') {
  530. StartsWithColon = TRUE;
  531. Options += 1;
  532. }
  533. //
  534. // Loop over every acceptable option.
  535. //
  536. while (*Options != '\0') {
  537. //
  538. // Keep looking if they're not equal.
  539. //
  540. if ((!isalnum(*Options)) || (*Argument != *Options)) {
  541. Options += 1;
  542. continue;
  543. }
  544. //
  545. // They're equal, look to see if the next character is a colon.
  546. //
  547. Option = *Options;
  548. Options += 1;
  549. ClNextOptionCharacter += 1;
  550. Argument += 1;
  551. //
  552. // If the option is W and it's followed by a semicolon, then treat
  553. // -W foo as the long option --foo.
  554. //
  555. if ((Option == 'W') && (*Options == ';') && (LongOptions != NULL)) {
  556. Options += 1;
  557. ClNextOptionCharacter = 1;
  558. //
  559. // Use either the remainder of the argument or the next argument
  560. // as the long option.
  561. //
  562. if (*Argument == '\0') {
  563. optind += 1;
  564. if (optind >= ArgumentCount) {
  565. optopt = Option;
  566. Error->Option = Option;
  567. Error->Type = GetOptionErrorMissingArgument;
  568. return '?';
  569. }
  570. Argument = Arguments[optind];
  571. }
  572. Option = ClpGetLongOption(ArgumentCount,
  573. Arguments,
  574. Argument,
  575. Options,
  576. LongOptions,
  577. LongIndex,
  578. Error);
  579. return Option;
  580. }
  581. //
  582. // If no argument is required, then work here is done.
  583. //
  584. if (*Options != ':') {
  585. //
  586. // If the next character of the argument is the terminator, then
  587. // up the index and reset the option character.
  588. //
  589. if (*Argument == '\0') {
  590. ClNextOptionCharacter = 1;
  591. optind += 1;
  592. }
  593. goto GetShortOptionEnd;
  594. }
  595. Options += 1;
  596. //
  597. // An argument is required or optional. If the next character of the
  598. // argument is not null, then the argument is the remainder.
  599. //
  600. ClNextOptionCharacter = 1;
  601. if (*Argument != '\0') {
  602. optarg = (char *)Argument;
  603. optind += 1;
  604. goto GetShortOptionEnd;
  605. }
  606. //
  607. // If the argument is optional, then the only chance for an argument
  608. // was the remainder of the current argument. Bail out now with no
  609. // argument.
  610. //
  611. if (*Options == ':') {
  612. optind += 1;
  613. goto GetShortOptionEnd;
  614. }
  615. //
  616. // It must be in the next argument. If there is no next argument, that's
  617. // a problem.
  618. //
  619. if (optind >= ArgumentCount - 1) {
  620. optind += 1;
  621. optopt = Option;
  622. if (StartsWithColon != FALSE) {
  623. Option = ':';
  624. goto GetShortOptionEnd;
  625. }
  626. Error->Option = Option;
  627. Error->Type = GetOptionErrorMissingArgument;
  628. Option = '?';
  629. goto GetShortOptionEnd;
  630. }
  631. optind += 1;
  632. optarg = Arguments[optind];
  633. optind += 1;
  634. Error->Type = GetOptionErrorNone;
  635. goto GetShortOptionEnd;
  636. }
  637. //
  638. // The argument doesn't match any of the acceptable options.
  639. //
  640. optopt = *Argument;
  641. if (StartsWithColon == FALSE) {
  642. Error->Option = *Argument;
  643. Error->Type = GetOptionErrorUnknownOption;
  644. }
  645. //
  646. // Advance to the next option, which may require advancing the index.
  647. //
  648. Argument += 1;
  649. if (*Argument == '\0') {
  650. optind += 1;
  651. ClNextOptionCharacter = 1;
  652. } else {
  653. ClNextOptionCharacter += 1;
  654. }
  655. Option = '?';
  656. GetShortOptionEnd:
  657. //
  658. // Clear the error if all is well. Returning ':' is not well, but no error
  659. // should be printed, so it's effectively the same as a success case.
  660. //
  661. if ((Option != -1) && (Option != '?')) {
  662. Error->Type = GetOptionErrorNone;
  663. }
  664. return Option;
  665. }
  666. int
  667. ClpGetLongOption (
  668. int ArgumentCount,
  669. char *const Arguments[],
  670. const char *Argument,
  671. const char *Options,
  672. const struct option *LongOptions,
  673. int *LongIndex,
  674. PGET_OPTION_ERROR Error
  675. )
  676. /*++
  677. Routine Description:
  678. This routine parses attempts to parse a long command line option.
  679. Arguments:
  680. ArgumentCount - Supplies the argument count from main.
  681. Arguments - Supplies the argument array from main.
  682. Argument - Supplies the argument to read, with any leading dashes stripped
  683. away.
  684. Options - Supplies the short options string, which defines the set of legal
  685. short options.
  686. LongOptions - Supplies a pointer to an array of long option structures
  687. containing the long options.
  688. LongIndex - Supplies an optional pointer that if supplied will return the
  689. index into the long options array of the found long option.
  690. Error - Supplies a pointer where the error information will be returned.
  691. Return Value:
  692. Returns value appropriate to be returned to the getopt functions.
  693. --*/
  694. {
  695. PSTR Equals;
  696. const struct option *Option;
  697. int OptionIndex;
  698. if (LongOptions == NULL) {
  699. return -1;
  700. }
  701. assert(optind < ArgumentCount);
  702. //
  703. // The two valid forms are --option argument or --option=argument. Look for
  704. // an equals to terminate the option name.
  705. //
  706. Equals = strchr(Argument, '=');
  707. //
  708. // Get the long option.
  709. //
  710. OptionIndex = ClpMatchLongOption(Argument, LongOptions, Error);
  711. if (OptionIndex == -1) {
  712. optind += 1;
  713. optopt = 0;
  714. return '?';
  715. }
  716. Option = &(LongOptions[OptionIndex]);
  717. optind += 1;
  718. if (LongIndex != NULL) {
  719. *LongIndex = OptionIndex;
  720. }
  721. //
  722. // Get the argument.
  723. //
  724. if (Option->has_arg != no_argument) {
  725. //
  726. // If there's an equals, then take the argument as the part after the
  727. // equals.
  728. //
  729. if (Equals != NULL) {
  730. optarg = Equals + 1;
  731. //
  732. // Continue processing if the argument is required. If the argument is
  733. // optional, then an argument can only be accepted with an equals sign,
  734. // meaning work here is done.
  735. //
  736. } else if (Option->has_arg == required_argument) {
  737. //
  738. // If the argument is required and there isn't one, then that's a
  739. // problem.
  740. //
  741. if (optind >= ArgumentCount) {
  742. optopt = Option->val;
  743. if (*Options == ':') {
  744. return ':';
  745. }
  746. Error->LongOption = Option->name;
  747. Error->Type = GetOptionErrorMissingArgument;
  748. return '?';
  749. //
  750. // Otherwise, use the next argument.
  751. //
  752. } else {
  753. optarg = Arguments[optind];
  754. optind += 1;
  755. }
  756. }
  757. //
  758. // No argument is expected. Fail if there is one.
  759. //
  760. } else {
  761. if (Equals != NULL) {
  762. if (*Options != ':') {
  763. optopt = Option->val;
  764. Error->LongOption = Option->name;
  765. Error->Type = GetOptionErrorNoArgumentExpected;
  766. }
  767. return '?';
  768. }
  769. }
  770. //
  771. // If the flag is non-null, then set *flag to the value. Otherwise, return
  772. // the value.
  773. //
  774. if (Option->flag == NULL) {
  775. return Option->val;
  776. }
  777. *(Option->flag) = Option->val;
  778. return 0;
  779. }
  780. int
  781. ClpMatchLongOption (
  782. const char *Argument,
  783. const struct option *Options,
  784. PGET_OPTION_ERROR Error
  785. )
  786. /*++
  787. Routine Description:
  788. This routine attempts to unambiguously match an option.
  789. Arguments:
  790. Argument - Supplies a pointer to the argument string, without any leading
  791. dashes.
  792. Options - Supplies the option array.
  793. Error - Supplies a pointer where the error will be returned on failure.
  794. Return Value:
  795. Returns an index of a matching option.
  796. -1 if no option unambiguously matches.
  797. --*/
  798. {
  799. size_t MatchCount;
  800. const struct option *Option;
  801. int OptionIndex;
  802. size_t RunnerUpCount;
  803. size_t WinnerCount;
  804. int WinnerIndex;
  805. WinnerCount = 0;
  806. WinnerIndex = -1;
  807. RunnerUpCount = 0;
  808. //
  809. // Loop through looking for the best option and the second best option.
  810. //
  811. Option = Options;
  812. OptionIndex = 0;
  813. while (Option->name != NULL) {
  814. //
  815. // Determine how many characters match in this option, and update the
  816. // new winner and runner up.
  817. //
  818. MatchCount = ClpMatchLongOptionString(Argument, Option->name);
  819. if (MatchCount >= WinnerCount) {
  820. //
  821. // If this match is as good as the winner and the values are the
  822. // same, then don't update the runner up, as these options are
  823. // considered as one.
  824. //
  825. if ((MatchCount != WinnerCount) ||
  826. (WinnerIndex == -1) ||
  827. (Options[WinnerIndex].flag != Option->flag) ||
  828. (Options[WinnerIndex].val != Option->val)) {
  829. RunnerUpCount = WinnerCount;
  830. }
  831. WinnerCount = MatchCount;
  832. WinnerIndex = OptionIndex;
  833. //
  834. // If the option matches exactly, then use it.
  835. //
  836. if ((Option->name[MatchCount] == '\0') &&
  837. ((Argument[MatchCount] == '\0') ||
  838. (Argument[MatchCount] == '='))) {
  839. RunnerUpCount = -1;
  840. break;
  841. }
  842. } else if (MatchCount > RunnerUpCount) {
  843. RunnerUpCount = MatchCount;
  844. }
  845. Option += 1;
  846. OptionIndex += 1;
  847. }
  848. //
  849. // If the winner doesn't match any characters, this is an unknown option.
  850. //
  851. if (WinnerCount == 0) {
  852. Error->Type = GetOptionErrorUnknownOption;
  853. Error->LongOption = Argument;
  854. WinnerIndex = -1;
  855. //
  856. // If the winner and the runner up match the same number of characters,
  857. // the result is ambiguous.
  858. //
  859. } else if (WinnerCount == RunnerUpCount) {
  860. Error->Type = GetOptionErrorAmbiguousOption;
  861. Error->LongOption = Argument;
  862. WinnerIndex = -1;
  863. } else {
  864. Error->Type = GetOptionErrorNone;
  865. }
  866. return WinnerIndex;
  867. }
  868. size_t
  869. ClpMatchLongOptionString (
  870. const char *Argument,
  871. const char *OptionName
  872. )
  873. /*++
  874. Routine Description:
  875. This routine returns the number of characters that match between the two
  876. strings.
  877. Arguments:
  878. Argument - Supplies a pointer to the argument, which is either null
  879. terminated or terminated with an equals. Dashes should have already
  880. been stripped.
  881. OptionName - Supplies a pointer to the option name.
  882. Return Value:
  883. Returns the number of characters that match.
  884. --*/
  885. {
  886. size_t MatchCount;
  887. MatchCount = 0;
  888. while (TRUE) {
  889. //
  890. // If the option name ended, stop. If the argument name keeps going,
  891. // then it doesn't match at all.
  892. //
  893. if (*OptionName == '\0') {
  894. if ((*Argument != '\0') && (*Argument != '=')) {
  895. return 0;
  896. }
  897. break;
  898. //
  899. // If the argument ended, stop.
  900. //
  901. } else if ((*Argument == '\0') || (*Argument == '=')) {
  902. break;
  903. }
  904. //
  905. // If they disagree somewhere they definitely don't match.
  906. //
  907. if (*Argument != *OptionName) {
  908. return 0;
  909. }
  910. MatchCount += 1;
  911. OptionName += 1;
  912. Argument += 1;
  913. }
  914. return MatchCount;
  915. }
  916. void
  917. ClpPrintGetOptionError (
  918. PGET_OPTION_ERROR Error
  919. )
  920. /*++
  921. Routine Description:
  922. This routine prints an error to standard error for the getopt functions if
  923. the user has not set the opterr variable to 0.
  924. Arguments:
  925. Error - Supplies a pointer to the error information.
  926. Return Value:
  927. None.
  928. --*/
  929. {
  930. PSTR BaseName;
  931. PSTR Copy;
  932. PSTR Dashes;
  933. PSTR Equals;
  934. PSTR ErrorString;
  935. PSTR OptionString;
  936. CHAR ShortOption[2];
  937. Copy = NULL;
  938. BaseName = basename(Error->CommandName);
  939. if (Error->LongOption != NULL) {
  940. Copy = strdup(Error->LongOption);
  941. Equals = strchr(Copy, '=');
  942. if (Equals != NULL) {
  943. *Equals = '\0';
  944. }
  945. OptionString = Copy;
  946. Dashes = "--";
  947. } else {
  948. ShortOption[0] = Error->Option;
  949. ShortOption[1] = '\0';
  950. Dashes = "-";
  951. OptionString = ShortOption;
  952. }
  953. switch (Error->Type) {
  954. case GetOptionErrorMissingArgument:
  955. ErrorString = "%s: Option %s%s requires an argument.\n";
  956. break;
  957. case GetOptionErrorUnknownOption:
  958. ErrorString = "%s: Unknown option %s%s.\n";
  959. break;
  960. case GetOptionErrorAmbiguousOption:
  961. ErrorString = "%s: Option %s%s is ambiguous.\n";
  962. break;
  963. case GetOptionErrorNoArgumentExpected:
  964. ErrorString = "%s: Option %s%s does not take an argument.\n";
  965. break;
  966. default:
  967. assert(FALSE);
  968. ErrorString = "%s: An unknown error occurred with %s%s.\n";
  969. }
  970. fprintf(stderr, ErrorString, BaseName, Dashes, OptionString);
  971. if (Copy != NULL) {
  972. free(Copy);
  973. }
  974. return;
  975. }