getopt_long.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. /* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */
  2. /* $FreeBSD: src/lib/libc/stdlib/getopt_long.c,v 1.2 2002/10/16 22:18:42 alfred Exp $ */
  3. /*-
  4. * Copyright (c) 2000 The NetBSD Foundation, Inc.
  5. * All rights reserved.
  6. *
  7. * This code is derived from software contributed to The NetBSD Foundation
  8. * by Dieter Baron and Thomas Klausner.
  9. *
  10. * Redistribution and use in source and binary forms, with or without
  11. * modification, are permitted provided that the following conditions
  12. * are met:
  13. * 1. Redistributions of source code must retain the above copyright
  14. * notice, this list of conditions and the following disclaimer.
  15. * 2. Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in the
  17. * documentation and/or other materials provided with the distribution.
  18. * 3. All advertising materials mentioning features or use of this software
  19. * must display the following acknowledgement:
  20. * This product includes software developed by the NetBSD
  21. * Foundation, Inc. and its contributors.
  22. * 4. Neither the name of The NetBSD Foundation nor the names of its
  23. * contributors may be used to endorse or promote products derived
  24. * from this software without specific prior written permission.
  25. *
  26. * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
  27. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  28. * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  29. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
  30. * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  31. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  32. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  33. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  34. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  35. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  36. * POSSIBILITY OF SUCH DAMAGE.
  37. */
  38. #include <getopt.h>
  39. #include <stdlib.h>
  40. #include <string.h>
  41. #ifdef _WIN32
  42. /* Windows needs warnx(). We change the definition though:
  43. * 1. (another) global is defined, opterrmsg, which holds the error message
  44. * 2. errors are always printed out on stderr w/o the program name
  45. * Note that opterrmsg always gets set no matter what opterr is set to. The
  46. * error message will not be printed if opterr is 0 as usual.
  47. */
  48. #include <stdio.h>
  49. #include <stdarg.h>
  50. GETOPT_API extern char opterrmsg[128];
  51. char opterrmsg[128]; /* last error message is stored here */
  52. static void warnx(int print_error, const char *fmt, ...)
  53. {
  54. va_list ap;
  55. va_start(ap, fmt);
  56. if (fmt != NULL)
  57. _vsnprintf(opterrmsg, 128, fmt, ap);
  58. else
  59. opterrmsg[0]='\0';
  60. va_end(ap);
  61. if (print_error) {
  62. fprintf(stderr, opterrmsg);
  63. fprintf(stderr, "\n");
  64. }
  65. }
  66. #endif /*_WIN32*/
  67. /* not part of the original file */
  68. #ifndef _DIAGASSERT
  69. #define _DIAGASSERT(X)
  70. #endif
  71. #if HAVE_CONFIG_H && !HAVE_GETOPT_LONG && !HAVE_DECL_OPTIND
  72. #define REPLACE_GETOPT
  73. #endif
  74. #ifdef REPLACE_GETOPT
  75. #ifdef __weak_alias
  76. __weak_alias(getopt,_getopt)
  77. #endif
  78. int opterr = 1; /* if error message should be printed */
  79. int optind = 1; /* index into parent argv vector */
  80. int optopt = '?'; /* character checked for validity */
  81. int optreset; /* reset getopt */
  82. char *optarg; /* argument associated with option */
  83. #elif HAVE_CONFIG_H && !HAVE_DECL_OPTRESET
  84. static int optreset;
  85. #endif
  86. #ifdef __weak_alias
  87. __weak_alias(getopt_long,_getopt_long)
  88. #endif
  89. #if !HAVE_GETOPT_LONG
  90. #define IGNORE_FIRST (*options == '-' || *options == '+')
  91. #define PRINT_ERROR ((opterr) && ((*options != ':') \
  92. || (IGNORE_FIRST && options[1] != ':')))
  93. #define IS_POSIXLY_CORRECT (getenv("POSIXLY_CORRECT") != NULL)
  94. #define PERMUTE (!IS_POSIXLY_CORRECT && !IGNORE_FIRST)
  95. /* XXX: GNU ignores PC if *options == '-' */
  96. #define IN_ORDER (!IS_POSIXLY_CORRECT && *options == '-')
  97. /* return values */
  98. #define BADCH (int)'?'
  99. #define BADARG ((IGNORE_FIRST && options[1] == ':') \
  100. || (*options == ':') ? (int)':' : (int)'?')
  101. #define INORDER (int)1
  102. #define EMSG ""
  103. static int getopt_internal(int, char * const *, const char *);
  104. static int gcd(int, int);
  105. static void permute_args(int, int, int, char * const *);
  106. static char *place = EMSG; /* option letter processing */
  107. /* XXX: set optreset to 1 rather than these two */
  108. static int nonopt_start = -1; /* first non option argument (for permute) */
  109. static int nonopt_end = -1; /* first option after non options (for permute) */
  110. /* Error messages */
  111. static const char recargchar[] = "option requires an argument -- %c";
  112. static const char recargstring[] = "option requires an argument -- %s";
  113. static const char ambig[] = "ambiguous option -- %.*s";
  114. static const char noarg[] = "option doesn't take an argument -- %.*s";
  115. static const char illoptchar[] = "unknown option -- %c";
  116. static const char illoptstring[] = "unknown option -- %s";
  117. /*
  118. * Compute the greatest common divisor of a and b.
  119. */
  120. static int
  121. gcd(a, b)
  122. int a;
  123. int b;
  124. {
  125. int c;
  126. c = a % b;
  127. while (c != 0) {
  128. a = b;
  129. b = c;
  130. c = a % b;
  131. }
  132. return b;
  133. }
  134. /*
  135. * Exchange the block from nonopt_start to nonopt_end with the block
  136. * from nonopt_end to opt_end (keeping the same order of arguments
  137. * in each block).
  138. */
  139. static void
  140. permute_args(panonopt_start, panonopt_end, opt_end, nargv)
  141. int panonopt_start;
  142. int panonopt_end;
  143. int opt_end;
  144. char * const *nargv;
  145. {
  146. int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
  147. char *swap;
  148. _DIAGASSERT(nargv != NULL);
  149. /*
  150. * compute lengths of blocks and number and size of cycles
  151. */
  152. nnonopts = panonopt_end - panonopt_start;
  153. nopts = opt_end - panonopt_end;
  154. ncycle = gcd(nnonopts, nopts);
  155. cyclelen = (opt_end - panonopt_start) / ncycle;
  156. for (i = 0; i < ncycle; i++) {
  157. cstart = panonopt_end+i;
  158. pos = cstart;
  159. for (j = 0; j < cyclelen; j++) {
  160. if (pos >= panonopt_end)
  161. pos -= nnonopts;
  162. else
  163. pos += nopts;
  164. swap = nargv[pos];
  165. /* LINTED const cast */
  166. ((char **) nargv)[pos] = nargv[cstart];
  167. /* LINTED const cast */
  168. ((char **)nargv)[cstart] = swap;
  169. }
  170. }
  171. }
  172. /*
  173. * getopt_internal --
  174. * Parse argc/argv argument vector. Called by user level routines.
  175. * Returns -2 if -- is found (can be long option or end of options marker).
  176. */
  177. static int
  178. getopt_internal(nargc, nargv, options)
  179. int nargc;
  180. char * const *nargv;
  181. const char *options;
  182. {
  183. char *oli; /* option letter list index */
  184. int optchar;
  185. _DIAGASSERT(nargv != NULL);
  186. _DIAGASSERT(options != NULL);
  187. optarg = NULL;
  188. /*
  189. * XXX Some programs (like rsyncd) expect to be able to
  190. * XXX re-initialize optind to 0 and have getopt_long(3)
  191. * XXX properly function again. Work around this braindamage.
  192. */
  193. if (optind == 0)
  194. optind = 1;
  195. if (optreset)
  196. nonopt_start = nonopt_end = -1;
  197. start:
  198. if (optreset || !*place) { /* update scanning pointer */
  199. optreset = 0;
  200. if (optind >= nargc) { /* end of argument vector */
  201. place = EMSG;
  202. if (nonopt_end != -1) {
  203. /* do permutation, if we have to */
  204. permute_args(nonopt_start, nonopt_end,
  205. optind, nargv);
  206. optind -= nonopt_end - nonopt_start;
  207. }
  208. else if (nonopt_start != -1) {
  209. /*
  210. * If we skipped non-options, set optind
  211. * to the first of them.
  212. */
  213. optind = nonopt_start;
  214. }
  215. nonopt_start = nonopt_end = -1;
  216. return -1;
  217. }
  218. if ((*(place = nargv[optind]) != '-')
  219. || (place[1] == '\0')) { /* found non-option */
  220. place = EMSG;
  221. if (IN_ORDER) {
  222. /*
  223. * GNU extension:
  224. * return non-option as argument to option 1
  225. */
  226. optarg = nargv[optind++];
  227. return INORDER;
  228. }
  229. if (!PERMUTE) {
  230. /*
  231. * if no permutation wanted, stop parsing
  232. * at first non-option
  233. */
  234. return -1;
  235. }
  236. /* do permutation */
  237. if (nonopt_start == -1)
  238. nonopt_start = optind;
  239. else if (nonopt_end != -1) {
  240. permute_args(nonopt_start, nonopt_end,
  241. optind, nargv);
  242. nonopt_start = optind -
  243. (nonopt_end - nonopt_start);
  244. nonopt_end = -1;
  245. }
  246. optind++;
  247. /* process next argument */
  248. goto start;
  249. }
  250. if (nonopt_start != -1 && nonopt_end == -1)
  251. nonopt_end = optind;
  252. if (place[1] && *++place == '-') { /* found "--" */
  253. place++;
  254. return -2;
  255. }
  256. }
  257. if ((optchar = (int)*place++) == (int)':' ||
  258. (oli = strchr(options + (IGNORE_FIRST ? 1 : 0), optchar)) == NULL) {
  259. /* option letter unknown or ':' */
  260. if (!*place)
  261. ++optind;
  262. #ifndef _WIN32
  263. if (PRINT_ERROR)
  264. warnx(illoptchar, optchar);
  265. #else
  266. warnx(PRINT_ERROR, illoptchar, optchar);
  267. #endif
  268. optopt = optchar;
  269. return BADCH;
  270. }
  271. if (optchar == 'W' && oli[1] == ';') { /* -W long-option */
  272. /* XXX: what if no long options provided (called by getopt)? */
  273. if (*place)
  274. return -2;
  275. if (++optind >= nargc) { /* no arg */
  276. place = EMSG;
  277. #ifndef _WIN32
  278. if (PRINT_ERROR)
  279. warnx(recargchar, optchar);
  280. #else
  281. warnx(PRINT_ERROR, recargchar, optchar);
  282. #endif
  283. optopt = optchar;
  284. return BADARG;
  285. } else /* white space */
  286. place = nargv[optind];
  287. /*
  288. * Handle -W arg the same as --arg (which causes getopt to
  289. * stop parsing).
  290. */
  291. return -2;
  292. }
  293. if (*++oli != ':') { /* doesn't take argument */
  294. if (!*place)
  295. ++optind;
  296. } else { /* takes (optional) argument */
  297. optarg = NULL;
  298. if (*place) /* no white space */
  299. optarg = place;
  300. /* XXX: disable test for :: if PC? (GNU doesn't) */
  301. else if (oli[1] != ':') { /* arg not optional */
  302. if (++optind >= nargc) { /* no arg */
  303. place = EMSG;
  304. #ifndef _WIN32
  305. if (PRINT_ERROR)
  306. warnx(recargchar, optchar);
  307. #else
  308. warnx(PRINT_ERROR, recargchar, optchar);
  309. #endif
  310. optopt = optchar;
  311. return BADARG;
  312. } else
  313. optarg = nargv[optind];
  314. }
  315. place = EMSG;
  316. ++optind;
  317. }
  318. /* dump back option letter */
  319. return optchar;
  320. }
  321. #ifdef REPLACE_GETOPT
  322. /*
  323. * getopt --
  324. * Parse argc/argv argument vector.
  325. *
  326. * [eventually this will replace the real getopt]
  327. */
  328. int
  329. getopt(nargc, nargv, options)
  330. int nargc;
  331. char * const *nargv;
  332. const char *options;
  333. {
  334. int retval;
  335. _DIAGASSERT(nargv != NULL);
  336. _DIAGASSERT(options != NULL);
  337. if ((retval = getopt_internal(nargc, nargv, options)) == -2) {
  338. ++optind;
  339. /*
  340. * We found an option (--), so if we skipped non-options,
  341. * we have to permute.
  342. */
  343. if (nonopt_end != -1) {
  344. permute_args(nonopt_start, nonopt_end, optind,
  345. nargv);
  346. optind -= nonopt_end - nonopt_start;
  347. }
  348. nonopt_start = nonopt_end = -1;
  349. retval = -1;
  350. }
  351. return retval;
  352. }
  353. #endif
  354. /*
  355. * getopt_long --
  356. * Parse argc/argv argument vector.
  357. */
  358. int
  359. getopt_long(nargc, nargv, options, long_options, idx)
  360. int nargc;
  361. char * const *nargv;
  362. const char *options;
  363. const struct option *long_options;
  364. int *idx;
  365. {
  366. int retval;
  367. _DIAGASSERT(nargv != NULL);
  368. _DIAGASSERT(options != NULL);
  369. _DIAGASSERT(long_options != NULL);
  370. /* idx may be NULL */
  371. if ((retval = getopt_internal(nargc, nargv, options)) == -2) {
  372. char *current_argv, *has_equal;
  373. size_t current_argv_len;
  374. int i, match;
  375. current_argv = place;
  376. match = -1;
  377. optind++;
  378. place = EMSG;
  379. if (*current_argv == '\0') { /* found "--" */
  380. /*
  381. * We found an option (--), so if we skipped
  382. * non-options, we have to permute.
  383. */
  384. if (nonopt_end != -1) {
  385. permute_args(nonopt_start, nonopt_end,
  386. optind, nargv);
  387. optind -= nonopt_end - nonopt_start;
  388. }
  389. nonopt_start = nonopt_end = -1;
  390. return -1;
  391. }
  392. if ((has_equal = strchr(current_argv, '=')) != NULL) {
  393. /* argument found (--option=arg) */
  394. current_argv_len = has_equal - current_argv;
  395. has_equal++;
  396. } else
  397. current_argv_len = strlen(current_argv);
  398. for (i = 0; long_options[i].name; i++) {
  399. /* find matching long option */
  400. if (strncmp(current_argv, long_options[i].name,
  401. current_argv_len))
  402. continue;
  403. if (strlen(long_options[i].name) ==
  404. (unsigned)current_argv_len) {
  405. /* exact match */
  406. match = i;
  407. break;
  408. }
  409. if (match == -1) /* partial match */
  410. match = i;
  411. else {
  412. /* ambiguous abbreviation */
  413. #ifndef _WIN32
  414. if (PRINT_ERROR)
  415. warnx(ambig, (int)current_argv_len,
  416. current_argv);
  417. #else
  418. warnx(PRINT_ERROR, ambig, (int)current_argv_len,
  419. current_argv);
  420. #endif
  421. optopt = 0;
  422. return BADCH;
  423. }
  424. }
  425. if (match != -1) { /* option found */
  426. if (long_options[match].has_arg == no_argument
  427. && has_equal) {
  428. #ifndef _WIN32
  429. if (PRINT_ERROR)
  430. warnx(noarg, (int)current_argv_len,
  431. current_argv);
  432. #else
  433. warnx(PRINT_ERROR, noarg, (int)current_argv_len,
  434. current_argv);
  435. #endif
  436. /*
  437. * XXX: GNU sets optopt to val regardless of
  438. * flag
  439. */
  440. if (long_options[match].flag == NULL)
  441. optopt = long_options[match].val;
  442. else
  443. optopt = 0;
  444. return BADARG;
  445. }
  446. if (long_options[match].has_arg == required_argument ||
  447. long_options[match].has_arg == optional_argument) {
  448. if (has_equal)
  449. optarg = has_equal;
  450. else if (long_options[match].has_arg ==
  451. required_argument) {
  452. /*
  453. * optional argument doesn't use
  454. * next nargv
  455. */
  456. optarg = nargv[optind++];
  457. }
  458. }
  459. if ((long_options[match].has_arg == required_argument)
  460. && (optarg == NULL)) {
  461. /*
  462. * Missing argument; leading ':'
  463. * indicates no error should be generated
  464. */
  465. #ifndef _WIN32
  466. if (PRINT_ERROR)
  467. warnx(recargstring, current_argv);
  468. #else
  469. warnx(PRINT_ERROR, recargstring, current_argv);
  470. #endif
  471. /*
  472. * XXX: GNU sets optopt to val regardless
  473. * of flag
  474. */
  475. if (long_options[match].flag == NULL)
  476. optopt = long_options[match].val;
  477. else
  478. optopt = 0;
  479. --optind;
  480. return BADARG;
  481. }
  482. } else { /* unknown option */
  483. #ifndef _WIN32
  484. if (PRINT_ERROR)
  485. warnx(illoptstring, current_argv);
  486. #else
  487. warnx(PRINT_ERROR, illoptstring, current_argv);
  488. #endif
  489. optopt = 0;
  490. return BADCH;
  491. }
  492. if (long_options[match].flag) {
  493. *long_options[match].flag = long_options[match].val;
  494. retval = 0;
  495. } else
  496. retval = long_options[match].val;
  497. if (idx)
  498. *idx = match;
  499. }
  500. return retval;
  501. }
  502. #endif /* !GETOPT_LONG */