getopt_long.c
上传用户:sy_wanhua
上传日期:2013-07-25
资源大小:3048k
文件大小:12k
源码类别:

流媒体/Mpeg4/MP4

开发平台:

C/C++

  1. /* $NetBSD: getopt_long.c,v 1.7 2000/07/08 14:58:43 sommerfeld 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 BSD
  38. #include <sys/cdefs.h>
  39. #endif
  40. #if defined(LIBC_SCCS) && !defined(lint)
  41. __RCSID("$NetBSD: getopt_long.c,v 1.7 2000/07/08 14:58:43 sommerfeld Exp $");
  42. #endif /* LIBC_SCCS and not lint */
  43. //#include "namespace.h"
  44. #include <assert.h>
  45. #include <errno.h>
  46. #ifdef BSD
  47. #include <err.h>
  48. #endif
  49. #include <stdlib.h>
  50. #include <string.h>
  51. #include "getopt.h"
  52. #if !defined(_DIAGASSERT)
  53. #define _DIAGASSERT(x)
  54. #endif
  55. #ifdef REPLACE_GETOPT
  56. #ifdef __weak_alias
  57. __weak_alias(getopt,_getopt)
  58. #endif
  59. int opterr = 1; /* if error message should be printed */
  60. int optind = 1; /* index into parent argv vector */
  61. int optopt = '?'; /* character checked for validity */
  62. int optreset; /* reset getopt */
  63. char    *optarg; /* argument associated with option */
  64. #endif
  65. #ifndef BSD
  66. int     optreset = 0;
  67. void warnx(const void * p, ...) { (void)p; }
  68. #endif
  69. #ifdef __weak_alias
  70. __weak_alias(getopt_long,_getopt_long)
  71. #endif
  72. #define IGNORE_FIRST (*options == '-' || *options == '+')
  73. #define PRINT_ERROR ((opterr) && ((*options != ':') 
  74.       || (IGNORE_FIRST && options[1] != ':')))
  75. #define IS_POSIXLY_CORRECT (getenv("POSIXLY_CORRECT") != NULL)
  76. #define PERMUTE         (!IS_POSIXLY_CORRECT && !IGNORE_FIRST)
  77. /* XXX: GNU ignores PC if *options == '-' */
  78. #define IN_ORDER        (!IS_POSIXLY_CORRECT && *options == '-')
  79. /* return values */
  80. #define BADCH (int)'?'
  81. #define BADARG (int)':'
  82. #define INORDER (int)1
  83. #define EMSG ""
  84. static int getopt_internal __P((int, char * const *, const char *));
  85. static int gcd __P((int, int));
  86. static void permute_args __P((int, int, int, char * const *));
  87. static char *place = EMSG; /* option letter processing */
  88. /* XXX: set optreset to 1 rather than these two */
  89. static int nonopt_start = -1; /* first non option argument (for permute) */
  90. static int nonopt_end = -1;   /* first option after non options (for permute) */
  91. /* Error messages */
  92. static const char recargchar[] = "option requires an argument -- %c";
  93. static const char recargstring[] = "option requires an argument -- %s";
  94. static const char ambig[] = "ambiguous option -- %.*s";
  95. static const char noarg[] = "option doesn't take an argument -- %.*s";
  96. static const char illoptchar[] = "illegal option -- %c";
  97. static const char illoptstring[] = "illegal option -- %s";
  98. extern char *__progname;
  99. /*
  100.  * Compute the greatest common divisor of a and b.
  101.  */
  102. static int
  103. gcd(a, b)
  104. int a;
  105. int b;
  106. {
  107. int c;
  108. c = a % b;
  109. while (c != 0) {
  110. a = b;
  111. b = c;
  112. c = a % b;
  113. }
  114.    
  115. return b;
  116. }
  117. /*
  118.  * Exchange the block from nonopt_start to nonopt_end with the block
  119.  * from nonopt_end to opt_end (keeping the same order of arguments
  120.  * in each block).
  121.  */
  122. static void
  123. permute_args(nonopt_start, nonopt_end, opt_end, nargv)
  124. int nonopt_start;
  125. int nonopt_end;
  126. int opt_end;
  127. char * const *nargv;
  128. {
  129. int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
  130. char *swap;
  131. /*
  132.  * compute lengths of blocks and number and size of cycles
  133.  */
  134. nnonopts = nonopt_end - nonopt_start;
  135. nopts = opt_end - nonopt_end;
  136. ncycle = gcd(nnonopts, nopts);
  137. cyclelen = (opt_end - nonopt_start) / ncycle;
  138. for (i = 0; i < ncycle; i++) {
  139. cstart = nonopt_end+i;
  140. pos = cstart;
  141. for (j = 0; j < cyclelen; j++) {
  142. if (pos >= nonopt_end)
  143. pos -= nnonopts;
  144. else
  145. pos += nopts;
  146. swap = nargv[pos];
  147. /* LINTED const cast */
  148. ((char **) nargv)[pos] = nargv[cstart];
  149. /* LINTED const cast */
  150. ((char **)nargv)[cstart] = swap;
  151. }
  152. }
  153. }
  154. /*
  155.  * getopt_internal --
  156.  * Parse argc/argv argument vector.  Called by user level routines.
  157.  *  Returns -2 if -- is found (can be long option or end of options marker).
  158.  */
  159. static int
  160. getopt_internal(nargc, nargv, options)
  161. int nargc;
  162. char * const *nargv;
  163. const char *options;
  164. {
  165. char *oli; /* option letter list index */
  166. int optchar;
  167. _DIAGASSERT(nargv != NULL);
  168. _DIAGASSERT(options != NULL);
  169. optarg = NULL;
  170. if (optreset)
  171. nonopt_start = nonopt_end = -1;
  172. start:
  173. if (optreset || !*place) { /* update scanning pointer */
  174. optreset = 0;
  175. if (optind >= nargc) {          /* end of argument vector */
  176. place = EMSG;
  177. if (nonopt_end != -1) {
  178. /* do permutation, if we have to */
  179. permute_args(nonopt_start, nonopt_end,
  180.     optind, nargv);
  181. optind -= nonopt_end - nonopt_start;
  182. }
  183. else if (nonopt_start != -1) {
  184. /*
  185.  * If we skipped non-options, set optind
  186.  * to the first of them.
  187.  */
  188. optind = nonopt_start;
  189. }
  190. nonopt_start = nonopt_end = -1;
  191. return -1;
  192. }
  193. if (*(place = nargv[optind]) != '-') {  /* found non-option */
  194. place = EMSG;
  195. if (IN_ORDER) {
  196. /*
  197.  * GNU extension: 
  198.  * return non-option as argument to option 1
  199.  */
  200. optarg = nargv[optind++];
  201. return INORDER;
  202. }
  203. if (!PERMUTE) {
  204. /*
  205.  * if no permutation wanted, stop parsing
  206.  * at first non-option
  207.  */
  208. return -1;
  209. }
  210. /* do permutation */
  211. if (nonopt_start == -1)
  212. nonopt_start = optind;
  213. else if (nonopt_end != -1) {
  214. permute_args(nonopt_start, nonopt_end,
  215.     optind, nargv);
  216. nonopt_start = optind -
  217.     (nonopt_end - nonopt_start);
  218. nonopt_end = -1;
  219. }
  220. optind++;
  221. /* process next argument */
  222. goto start;
  223. }
  224. if (nonopt_start != -1 && nonopt_end == -1)
  225. nonopt_end = optind;
  226. if (place[1] && *++place == '-') { /* found "--" */
  227. place++;
  228. return -2;
  229. }
  230. }
  231. if ((optchar = (int)*place++) == (int)':' ||
  232.     (oli = strchr(options + (IGNORE_FIRST ? 1 : 0), optchar)) == NULL) {
  233. /* option letter unknown or ':' */
  234. if (!*place)
  235. ++optind;
  236. if (PRINT_ERROR)
  237. warnx(illoptchar, optchar);
  238. optopt = optchar;
  239. return BADCH;
  240. }
  241. if (optchar == 'W' && oli[1] == ';') { /* -W long-option */
  242. /* XXX: what if no long options provided (called by getopt)? */
  243. if (*place) 
  244. return -2;
  245. if (++optind >= nargc) { /* no arg */
  246. place = EMSG;
  247. if (PRINT_ERROR)
  248. warnx(recargchar, optchar);
  249. optopt = optchar;
  250. /* XXX: GNU returns '?' if options[0] != ':' */
  251. return BADARG;
  252. } else /* white space */
  253. place = nargv[optind];
  254. /*
  255.  * Handle -W arg the same as --arg (which causes getopt to
  256.  * stop parsing).
  257.  */
  258. return -2;
  259. }
  260. if (*++oli != ':') { /* doesn't take argument */
  261. if (!*place)
  262. ++optind;
  263. } else { /* takes (optional) argument */
  264. optarg = NULL;
  265. if (*place) /* no white space */
  266. optarg = place;
  267. /* XXX: disable test for :: if PC? (GNU doesn't) */
  268. else if (oli[1] != ':') { /* arg not optional */
  269. if (++optind >= nargc) { /* no arg */
  270. place = EMSG;
  271. if (PRINT_ERROR)
  272. warnx(recargchar, optchar);
  273. optopt = optchar;
  274. /* XXX: GNU returns '?' if options[0] != ':' */
  275. return BADARG;
  276. } else
  277. optarg = nargv[optind];
  278. }
  279. place = EMSG;
  280. ++optind;
  281. }
  282. /* dump back option letter */
  283. return optchar;
  284. }
  285. #ifdef REPLACE_GETOPT
  286. /*
  287.  * getopt --
  288.  * Parse argc/argv argument vector.
  289.  *
  290.  * [eventually this will replace the real getopt]
  291.  */
  292. int
  293. getopt(nargc, nargv, options)
  294. int nargc;
  295. char * const *nargv;
  296. const char *options;
  297. {
  298. int retval;
  299. if ((retval = getopt_internal(nargc, nargv, options)) == -2) {
  300. ++optind;
  301. /*
  302.  * We found an option (--), so if we skipped non-options,
  303.  * we have to permute.
  304.  */
  305. if (nonopt_end != -1) {
  306. permute_args(nonopt_start, nonopt_end, optind,
  307.        nargv);
  308. optind -= nonopt_end - nonopt_start;
  309. }
  310. nonopt_start = nonopt_end = -1;
  311. retval = -1;
  312. }
  313. return retval;
  314. }
  315. #endif
  316. /*
  317.  * getopt_long --
  318.  * Parse argc/argv argument vector.
  319.  */
  320. int
  321. getopt_long(nargc, nargv, options, long_options, idx)
  322. int nargc;
  323. char * const *nargv;
  324. const char *options;
  325. const struct option *long_options;
  326. int *idx;
  327. {
  328. int retval;
  329. _DIAGASSERT(nargv != NULL);
  330. _DIAGASSERT(options != NULL);
  331. _DIAGASSERT(long_options != NULL);
  332. /* idx may be NULL */
  333. if ((retval = getopt_internal(nargc, nargv, options)) == -2) {
  334. char *current_argv, *has_equal;
  335. size_t current_argv_len;
  336. int i, match;
  337. current_argv = place;
  338. match = -1;
  339. optind++;
  340. place = EMSG;
  341. if (*current_argv == '') { /* found "--" */
  342. /*
  343.  * We found an option (--), so if we skipped
  344.  * non-options, we have to permute.
  345.  */
  346. if (nonopt_end != -1) {
  347. permute_args(nonopt_start, nonopt_end,
  348.     optind, nargv);
  349. optind -= nonopt_end - nonopt_start;
  350. }
  351. nonopt_start = nonopt_end = -1;
  352. return -1;
  353. }
  354. if ((has_equal = strchr(current_argv, '=')) != NULL) {
  355. /* argument found (--option=arg) */
  356. current_argv_len = has_equal - current_argv;
  357. has_equal++;
  358. } else
  359. current_argv_len = strlen(current_argv);
  360.     
  361. for (i = 0; long_options[i].name; i++) {
  362. /* find matching long option */
  363. if (strncmp(current_argv, long_options[i].name,
  364.     current_argv_len))
  365. continue;
  366. if (strlen(long_options[i].name) ==
  367.     (unsigned)current_argv_len) {
  368. /* exact match */
  369. match = i;
  370. break;
  371. }
  372. if (match == -1) /* partial match */
  373. match = i;
  374. else {
  375. /* ambiguous abbreviation */
  376. if (PRINT_ERROR)
  377. warnx(ambig, (int)current_argv_len,
  378.      current_argv);
  379. optopt = 0;
  380. return BADCH;
  381. }
  382. }
  383. if (match != -1) { /* option found */
  384.         if (long_options[match].has_arg == no_argument
  385.     && has_equal) {
  386. if (PRINT_ERROR)
  387. warnx(noarg, (int)current_argv_len,
  388.      current_argv);
  389. /*
  390.  * XXX: GNU sets optopt to val regardless of
  391.  * flag
  392.  */
  393. if (long_options[match].flag == NULL)
  394. optopt = long_options[match].val;
  395. else
  396. optopt = 0;
  397. /* XXX: GNU returns '?' if options[0] != ':' */
  398. return BADARG;
  399. }
  400. if (long_options[match].has_arg == required_argument ||
  401.     long_options[match].has_arg == optional_argument) {
  402. if (has_equal)
  403. optarg = has_equal;
  404. else if (long_options[match].has_arg ==
  405.     required_argument) {
  406. /*
  407.  * optional argument doesn't use
  408.  * next nargv
  409.  */
  410. optarg = nargv[optind++];
  411. }
  412. }
  413. if ((long_options[match].has_arg == required_argument)
  414.     && (optarg == NULL)) {
  415. /*
  416.  * Missing argument; leading ':'
  417.  * indicates no error should be generated
  418.  */
  419. if (PRINT_ERROR)
  420. warnx(recargstring, current_argv);
  421. /*
  422.  * XXX: GNU sets optopt to val regardless
  423.  * of flag
  424.  */
  425. if (long_options[match].flag == NULL)
  426. optopt = long_options[match].val;
  427. else
  428. optopt = 0;
  429. /* XXX: GNU returns '?' if options[0] != ':' */
  430. --optind;
  431. return BADARG;
  432. }
  433. } else { /* unknown option */
  434. if (PRINT_ERROR)
  435. warnx(illoptstring, current_argv);
  436. optopt = 0;
  437. return BADCH;
  438. }
  439. if (long_options[match].flag) {
  440. *long_options[match].flag = long_options[match].val;
  441. retval = 0;
  442. } else 
  443. retval = long_options[match].val;
  444. if (idx)
  445. *idx = match;
  446. }
  447. return retval;
  448. }