PageRenderTime 69ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/utils/msys-here/lib/getopt.c

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