getargs.c
上传用户:xiejiait
上传日期:2007-01-06
资源大小:881k
文件大小:17k
源码类别:

SCSI/ASPI

开发平台:

MultiPlatform

  1. /* @(#)getargs.c 2.26 99/12/25 Copyright 1985, 1988, 1995 J. Schilling */
  2. #ifndef lint
  3. static char sccsid[] =
  4. "@(#)getargs.c 2.26 99/12/25 Copyright 1985, 1988, 1995 J. Schilling";
  5. #endif
  6. #define NEW
  7. /*
  8.  * Copyright (c) 1985, 1988, 1995 J. Schilling
  9.  *
  10.  * 1.3.88  Start implementation of release 2
  11.  */
  12. /*
  13.  * Parse arguments on a command line.
  14.  * Format string specifier (appearing directly after flag name):
  15.  * '' BOOL
  16.  * '*' string
  17.  * '?' char
  18.  * '#' number
  19.  * '&' call function
  20.  * '+' inctype +++ NEU +++
  21.  */
  22. /*
  23.  * This program is free software; you can redistribute it and/or modify
  24.  * it under the terms of the GNU General Public License as published by
  25.  * the Free Software Foundation; either version 2, or (at your option)
  26.  * any later version.
  27.  *
  28.  * This program is distributed in the hope that it will be useful,
  29.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  30.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  31.  * GNU General Public License for more details.
  32.  *
  33.  * You should have received a copy of the GNU General Public License
  34.  * along with this program; see the file COPYING.  If not, write to
  35.  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  36.  */
  37. /* LINTLIBRARY */
  38. #include <mconfig.h>
  39. #include <standard.h>
  40. #include <getargs.h>
  41. #include <ctype.h>
  42. #include <vadefs.h>
  43. #include <strdefs.h>
  44. #define NOARGS   0 /* No more args */
  45. #define NOTAFLAG   1 /* Not a flag type argument */
  46. #define BADFLAG (-1) /* Not a valid flag argument */
  47. #define BADFMT (-2) /* Error in format string */
  48. #define NOTAFILE (-3) /* Seems to be a flag type arg */
  49. int _getargs __PR((int *, char *const **, const char *,
  50. BOOL, va_list));
  51. LOCAL int dofile __PR((int *, char *const **, const char **));
  52. LOCAL int doflag __PR((int *, char *const **, const char *,
  53. const char *, BOOL, va_list));
  54. LOCAL int dosflags __PR((const char *, const char *, BOOL, va_list));
  55. LOCAL int checkfmt __PR((const char *));
  56. LOCAL int checkeql __PR((const char *));
  57. LOCAL va_list va_dummy;
  58. LOCAL char fmtspecs[] = "#?*&+"; 
  59. #define isfmtspec(c) (strchr(fmtspecs, c) != NULL)
  60. /*---------------------------------------------------------------------------
  61. |
  62. | get flags until a non flag type argument is reached
  63. |
  64. +---------------------------------------------------------------------------*/
  65. /* VARARGS3 */
  66. #ifdef PROTOTYPES
  67. int getargs(int *pac, char *const **pav, const char *fmt, ...)
  68. #else
  69. int getargs(pac, pav, fmt, va_alist)
  70. int *pac;
  71. char **pav[];
  72. char *fmt;
  73. va_dcl
  74. #endif
  75. {
  76. va_list args;
  77. int ret;
  78. #ifdef PROTOTYPES
  79. va_start(args, fmt);
  80. #else
  81. va_start(args);
  82. #endif
  83. ret = _getargs(pac, pav, fmt, TRUE, args);
  84. va_end(args);
  85. return (ret);
  86. }
  87. /*---------------------------------------------------------------------------
  88. |
  89. | get all flags on the command line, do not stop on files
  90. |
  91. +---------------------------------------------------------------------------*/
  92. /* VARARGS3 */
  93. #ifdef PROTOTYPES
  94. int getallargs(int *pac, char *const **pav, const char *fmt, ...)
  95. #else
  96. int getallargs(pac, pav, fmt, va_alist)
  97. int *pac;
  98. char **pav[];
  99. char *fmt;
  100. va_dcl
  101. #endif
  102. {
  103. va_list args;
  104. int ret;
  105. #ifdef PROTOTYPES
  106. va_start(args, fmt);
  107. #else
  108. va_start(args);
  109. #endif
  110. for (;; (*pac)--, (*pav)++) {
  111. if ((ret = _getargs(pac, pav, fmt, TRUE, args)) != NOTAFLAG)
  112. break;
  113. }
  114. va_end(args);
  115. return (ret);
  116. }
  117. /*---------------------------------------------------------------------------
  118. |
  119. | get next non flag type argument (i.e. a file)
  120. |
  121. +---------------------------------------------------------------------------*/
  122. int getfiles(pac, pav, fmt)
  123. int *pac;
  124. char *const *pav[];
  125. const char *fmt;
  126. {
  127. return (_getargs(pac, pav, fmt, FALSE, va_dummy));
  128. }
  129. /*---------------------------------------------------------------------------
  130. |
  131. | check args until the next non flag type argmument is reached
  132. | *pac is decremented, *pav is incremented so that the
  133. | non flag type argument is at *pav[0]
  134. |
  135. | return code:
  136. | NOARGS no more args
  137. | NOTAFLAG not a flag type argument
  138. | BADFLAG a non-matching flag type argument
  139. | BADFMT bad syntax in format string
  140. |
  141. |
  142. +---------------------------------------------------------------------------*/
  143. /*LOCAL*/ int _getargs(pac, pav, fmt, setargs, args)
  144. register int *pac;
  145. register char *const **pav;
  146.  const char *fmt;
  147. BOOL setargs;
  148. va_list args;
  149. {
  150. const  char *argp;
  151.  int ret;
  152. for(; *pac > 0; (*pac)--, (*pav)++) {
  153. argp = **pav;
  154. ret = dofile(pac, pav, &argp);
  155. if (ret != NOTAFILE)
  156. return (ret);
  157. ret = doflag(pac, pav, argp, fmt, setargs, args);
  158. if (ret != NOTAFLAG)
  159. return (ret);
  160. }
  161. return (NOARGS);
  162. }
  163. /*---------------------------------------------------------------------------
  164. |
  165. | check if *pargp is a file type argument
  166. |
  167. +---------------------------------------------------------------------------*/
  168. LOCAL int dofile(pac, pav, pargp)
  169. register int *pac;
  170. register char *const **pav;
  171.  const char **pargp;
  172. {
  173. register const char *argp = *pargp;
  174. if (argp[0] == '-') {
  175. /*
  176.  * "-" is a special non flag type argument
  177.  *     that usually means take stdin instead of a named file
  178.  */
  179. if (argp[1] == '')
  180. return (NOTAFLAG);
  181. /*
  182.  * "--" is a prefix to take the next argument
  183.  * as non flag type argument
  184.  * NOTE: Posix requires "--" to indicate the end of the
  185.  *  flags on the command line. But we are currently not
  186.  *  Posix.
  187.  */
  188. if (argp[1] == '-' && argp[2] == '') {
  189. if (--(*pac) > 0) {
  190. (*pav)++;
  191. return (NOTAFLAG);
  192. } else {
  193. return (NOARGS);
  194. }
  195. }
  196. }
  197. /*
  198.  * now check if it may be flag type argument
  199.  * flag type arguments begin with a '-', a '+' or contain a '='
  200.  * i.e. -flag +flag or flag=
  201.  */
  202. if (argp[0] != '-' && argp[0] != '+' && (!checkeql(argp)))
  203. return (NOTAFLAG);
  204. return (NOTAFILE);
  205. }
  206. /*---------------------------------------------------------------------------
  207. |
  208. | compare argp with the format string
  209. | if a match is found store the result a la scanf in one of the
  210. | arguments pointed to in the va_list
  211. |
  212. | If setargs is FALSE, only check arguments for getfiles()
  213. | in this case, va_list may be a dummy arg.
  214. |
  215. +---------------------------------------------------------------------------*/
  216. LOCAL int doflag(pac, pav, argp, fmt, setargs, oargs)
  217. int *pac;
  218. char *const **pav;
  219. register const char *argp;
  220. register const char *fmt;
  221. BOOL setargs;
  222. va_list oargs;
  223. {
  224. long val;
  225. int singlecharflag = 0;
  226. BOOL isspec;
  227. BOOL hasdash = FALSE;
  228. BOOL doubledash = FALSE;
  229. BOOL haseql = checkeql(argp);
  230. const char *sargp;
  231. const char *sfmt = fmt;
  232. va_list args;
  233. char *const *spav = *pav;
  234. int spac = *pac;
  235. void *curarg = (void *)0;
  236. /*
  237.  * flags beginning with '-' don't have to include the '-' in
  238.  * the format string.
  239.  * flags beginning with '+' have to include it in the format string.
  240.  */
  241. if (argp[0] == '-') {
  242. argp++;
  243. hasdash = TRUE;
  244. /*
  245.  * Implement legacy support for --longopt
  246.  * If we find a double dash, we do not look for combinations
  247.  * of boolean single char flags.
  248.  */
  249. if (argp[0] == '-') {
  250. argp++;
  251. doubledash = TRUE;
  252. /*
  253.  * Allow -- only for long options.
  254.  */
  255. if (argp[1] == '') {
  256. return (BADFLAG);
  257. }
  258. }
  259. }
  260. sargp = argp;
  261. /*
  262.  * Initialize 'args' to the start of the argument list.
  263.  * I don't know any portable way to copy an arbitrary
  264.  * C object so I use a system-specific routine
  265.  * (probably a macro) from stdarg.h.  (Remember that
  266.  * if va_list is an array, 'args' will be a pointer
  267.  * and '&args' won't be what I would need for memcpy.)
  268.  * It is a system requirement for SVr4 compatibility
  269.  * to be able to do this assgignement. If your system
  270.  * defines va_list to be an array but does not define
  271.  * va_copy() you are lost.
  272.  * This is needed to make sure, that 'oargs' will not
  273.  * be clobbered.
  274.  */
  275. va_copy(args, oargs);
  276. if (setargs)
  277. curarg = va_arg(args, void *);
  278. /*
  279.  * check if the first flag in format string is a singlechar flag
  280.  */
  281. if (fmt[1] == ',' || fmt[1] == '+' || fmt[1] == '')
  282. singlecharflag++;
  283. /*
  284.  * check the whole format string for a match
  285.  */
  286. for(;;) {
  287. for(;*fmt; fmt++,argp++) {
  288. if (*fmt == '\') {
  289. /*
  290.  * Allow "#?*&+" to appear inside a flag.
  291.  * NOTE: they must be escaped by '\' only
  292.  *  inside the the format string.
  293.  */
  294. fmt++;
  295. isspec = FALSE;
  296. } else {
  297. isspec = isfmtspec(*fmt);
  298. }
  299. /*
  300.  * If isspec is TRUE, the arg beeing checked starts
  301.  * like a valid flag. Argp now points to the rest.
  302.  */
  303. if (isspec) {
  304. /*
  305.  * If *argp is '+' and we are on the
  306.  * beginning of the arg that is currently
  307.  * checked, this cannot be an inc type flag.
  308.  */
  309. if (*argp == '+' && argp == sargp)
  310. continue;
  311. /*
  312.  * skip over to arg of flag
  313.  */
  314. if (*argp == '=') {
  315. argp++;
  316. } else if (*argp != '' && haseql) {
  317. /*
  318.  * Flag and arg are not separated by a
  319.  * space.
  320.  * Check here for:
  321.  * xxxxx=yyyyy match on '&'
  322.  * Checked before:
  323.  * abc=yyyyy match on 'abc&'
  324.  *  or  'abc*' 
  325.  *  or  'abc#' 
  326.  * We come here if 'argp' starts with
  327.  * the same sequence as a valid flag
  328.  * and contains an equal sign.
  329.  * We have tested before if the text
  330.  * before 'argp' matches exactly.
  331.  * At this point we have no exact match
  332.  * and we only allow to match
  333.  * the special pattern '&'.
  334.  * We need this e.g. for 'make'.
  335.  * We allow any flag type argument to
  336.  * match the format string "&" to set
  337.  * up a function that handles all odd
  338.  * stuff that getargs will not grok.
  339.  * In addition, to allow getargs to be
  340.  * used for CPP type flags we allow to
  341.  * match -Dabc=xyz on 'D&'. Note that
  342.  * Dabc=xyz will not match 'D&'.
  343.  */
  344. if ((!hasdash && argp != sargp) || *fmt != '&')
  345. goto nextarg;
  346. }
  347. /*
  348.  * *arpp == '' || !haseql
  349.  * We come here if 'argp' starts with
  350.  * the same sequence as a valid flag.
  351.  * This will match on the following args:
  352.  * -farg match on 'f*'
  353.  * -f12 match on 'f#'
  354.  * +12 match on '+#'
  355.  * -12 match on '#'
  356.  * and all args that are separated from
  357.  * their flags.
  358.  * In the switch statement below, we check
  359.  * if the text after 'argp' (if *argp != 0) or
  360.  * the next arg is a valid arg for this flag.
  361.    */
  362. break;
  363. } else if (*fmt == *argp) {
  364. if (argp[1] == '' &&
  365.     (fmt[1] == '' || fmt[1] == ',')) {
  366. if (setargs)
  367. *((int *)curarg) = TRUE;
  368. return (checkfmt(fmt));/* XXX */
  369. }
  370. } else {
  371. /*
  372.  * skip over to next format identifier
  373.  * & reset arg pointer
  374.  */
  375. nextarg:
  376. while (*fmt != ',' && *fmt != '') {
  377. /* function has extra arg on stack */
  378. if (*fmt == '&' && setargs)
  379. curarg = va_arg(args, void *);
  380. fmt++;
  381. }
  382. argp = sargp;
  383. break;
  384. }
  385. }
  386. switch(*fmt) {
  387. case '':
  388. /*
  389.  * Boolean type has been tested before.
  390.  */
  391. if (singlecharflag && !doubledash &&
  392.    (val = dosflags(sargp, sfmt, setargs, oargs)) !=
  393. BADFLAG)
  394. return (val);
  395. return (BADFLAG);
  396. case ',':
  397. fmt++;
  398. if (fmt[1] == ',' || fmt[1] == '+' || fmt[1] == '')
  399. singlecharflag++;
  400. if (setargs)
  401. curarg = va_arg(args, void *);
  402. continue;
  403. case '*':
  404. if (*argp == '') {
  405. if (*pac > 1) {
  406. (*pac)--;
  407. (*pav)++;
  408. argp = **pav;
  409. } else {
  410. return (BADFLAG);
  411. }
  412. }
  413. if (setargs)
  414. *((const char **)curarg) = argp;
  415. return (checkfmt(fmt));
  416. case '?':
  417. /*
  418.  * If more than one char arg, it
  419.  * cannot be a character argument.
  420.  */
  421. if (argp[1] != '')
  422. goto nextchance;
  423. if (setargs)
  424. *((char *)curarg) = *argp;
  425. return (checkfmt(fmt));
  426. case '+':
  427. /*
  428.  * inc type is similar to boolean,
  429.  * there is no arg in argp to convert.
  430.  */
  431. if (*argp != '')
  432. goto nextchance;
  433. if (fmt[1] == 'l' || fmt[1] == 'L') {
  434. if (setargs)
  435. *((long *)curarg) += 1;
  436. fmt++;
  437. } else if (fmt[1] == 's' || fmt[1] == 'S') {
  438. if (setargs)
  439. *((short *)curarg) += 1;
  440. fmt++;
  441. } else {
  442. if (fmt[1] == 'i' || fmt[1] == 'I')
  443. fmt++;
  444. if (setargs)
  445. *((int *)curarg) += 1;
  446. }
  447. return (checkfmt(fmt));
  448. case '#':
  449. if (*argp == '') {
  450. if (*pac > 1) {
  451. (*pac)--;
  452. (*pav)++;
  453. argp = **pav;
  454. } else {
  455. return (BADFLAG);
  456. }
  457. }
  458. if (*astol(argp, &val) != '') {
  459. /*
  460.  * arg is not a valid number!
  461.  * go to next format in the format string
  462.  * and check if arg matches any other type
  463.  * in the format specs.
  464.  */
  465. nextchance:
  466. while(*fmt != ',' && *fmt != '') {
  467. if (*fmt == '&' && setargs)
  468. curarg = va_arg(args, void *);
  469. fmt++;
  470. }
  471. argp = sargp;
  472. *pac = spac;
  473. *pav = spav;
  474. continue;
  475. }
  476. if (fmt[1] == 'l' || fmt[1] == 'L') {
  477. if (setargs)
  478. *((long *)curarg) = val;
  479. fmt++;
  480. } else if (fmt[1] == 's' || fmt[1] == 'S') {
  481. if (setargs)
  482. *((short *)curarg) = val;
  483. fmt++;
  484. } else {
  485. if (fmt[1] == 'i' || fmt[1] == 'I')
  486. fmt++;
  487. if (setargs)
  488. *((int *)curarg) = val;
  489. }
  490. return (checkfmt(fmt));
  491. case '&':
  492. if (*argp == '') {
  493. if (*pac > 1) {
  494. (*pac)--;
  495. (*pav)++;
  496. argp = **pav;
  497. } else {
  498. return (BADFLAG);
  499. }
  500. }
  501. if ((val = checkfmt(fmt)) != NOTAFLAG)
  502. return (val);
  503. if (setargs) {
  504. int ret;
  505. void *funarg = va_arg(args, void *);
  506. ret = ((*(getargfun)curarg) (argp, funarg));
  507. if (ret != NOTAFILE)
  508. return (ret);
  509. fmt++;
  510. } else {
  511. return (val);
  512. }
  513. /*
  514.  * Called function returns NOTAFILE: try next format.
  515.  */
  516. }
  517. }
  518. }
  519. /*---------------------------------------------------------------------------
  520. |
  521. | parse args for combined single char flags
  522. |
  523. +---------------------------------------------------------------------------*/
  524. typedef struct {
  525. void *curarg;
  526. short count;
  527. char c;
  528. char type;
  529. } sflags;
  530. LOCAL int dosflags(argp, fmt, setargs, oargs)
  531. register const char *argp;
  532. register const char *fmt;
  533. BOOL setargs;
  534. va_list oargs;
  535. {
  536. #define MAXSF 32
  537.  sflags sf[MAXSF];
  538.  va_list args;
  539. register sflags *rsf = sf;
  540. register int nsf = 0;
  541. register const char *p = argp;
  542. register int i;
  543. register void *curarg = (void *)0;
  544. /*
  545.  * Initialize 'args' to the start of the argument list.
  546.  * I don't know any portable way to copy an arbitrary
  547.  * C object so I use a system-specific routine
  548.  * (probably a macro) from stdarg.h.  (Remember that
  549.  * if va_list is an array, 'args' will be a pointer
  550.  * and '&args' won't be what I would need for memcpy.)
  551.  * It is a system requirement for SVr4 compatibility
  552.  * to be able to do this assgignement. If your system
  553.  * defines va_list to be an array but does not define
  554.  * va_copy() you are lost.
  555.  * This is needed to make sure, that 'oargs' will not
  556.  * be clobbered.
  557.  */
  558. va_copy(args, oargs);
  559. if (setargs)
  560. curarg = va_arg(args, void *);
  561. while (*p) {
  562. for (i=0; i < nsf; i++) {
  563. if (rsf[i].c == *p)
  564. break;
  565. }
  566. if (i >= MAXSF)
  567. return (BADFLAG);
  568. if (i == nsf) {
  569. rsf[i].curarg = (void *)0;
  570. rsf[i].count = 0;
  571. rsf[i].c = *p;
  572. rsf[i].type = (char)-1;
  573. nsf++;
  574. }
  575. rsf[i].count++;
  576. p++;
  577. }
  578. while (*fmt) {
  579. if (!isfmtspec(*fmt) &&
  580.     (fmt[1] == ',' || fmt[1] == '+' || fmt[1] == '') &&
  581.      strchr(argp, *fmt)) {
  582. for (i=0; i < nsf; i++) {
  583. if (rsf[i].c == *fmt) {
  584. if (fmt[1] == '+') {
  585. fmt++;
  586. if (fmt[1] == ',' ||
  587.     fmt[1] == '') {
  588. rsf[i].type = 'i';
  589. } else {
  590. rsf[i].type = fmt[1];
  591. }
  592. } else {
  593. rsf[i].type = fmt[1];
  594. }
  595. rsf[i].curarg = curarg;
  596. break;
  597. }
  598. }
  599. }
  600. while (*fmt != ',' && *fmt != '') {
  601. /* function has extra arg on stack */
  602. if (*fmt == '&' && setargs)
  603. curarg = va_arg(args, void *);
  604. fmt++;
  605. }
  606. if (*fmt != '')
  607. fmt++;
  608. if (setargs)
  609. curarg = va_arg(args, void *);
  610. }
  611. for (i=0; i < nsf; i++) {
  612. if (rsf[i].type == (char)-1)
  613. return (BADFLAG);
  614. if (rsf[i].curarg) {
  615. if (rsf[i].type == ',' || rsf[i].type == '') {
  616. *((int *)rsf[i].curarg) = TRUE;
  617. } else if (rsf[i].type == 'i' || rsf[i].type == 'I') {
  618. *((int *)rsf[i].curarg) += rsf[i].count;
  619. } else if (rsf[i].type == 'l' || rsf[i].type == 'L') {
  620. *((long *)rsf[i].curarg) += rsf[i].count;
  621. } else if (rsf[i].type == 's' || rsf[i].type == 'S') {
  622. *((short *)rsf[i].curarg) += rsf[i].count;
  623. } else {
  624. return (BADFLAG);
  625. }
  626. }
  627. }
  628. return (NOTAFLAG);
  629. }
  630. /*---------------------------------------------------------------------------
  631. |
  632. | If the next format character is a comma or the string delimiter,
  633. | there are no invalid format specifiers. Return success.
  634. | Otherwise raise the getarg_bad_format condition.
  635. |
  636. +---------------------------------------------------------------------------*/
  637. LOCAL int checkfmt(fmt)
  638. const char *fmt;
  639. {
  640. char c;
  641. c = *(++fmt); /* non constant expression */
  642. if (c == ',' || c == '') {
  643. return (NOTAFLAG);
  644. } else {
  645. raisecond("getarg_bad_format", (long)fmt);
  646. return (BADFMT);
  647. }
  648. }
  649. /*---------------------------------------------------------------------------
  650. |
  651. | Parse the string as long as valid characters can be found.
  652. | Valid flag identifiers are chosen from the set of
  653. | alphanumeric characters, '-' and '_'.
  654. | If the next character is an equal sign the string
  655. | contains a valid flag identifier.
  656. |
  657. +---------------------------------------------------------------------------*/
  658. static int checkeql(str)
  659. register const char *str;
  660. {
  661. register unsigned char c;
  662. for (c = (unsigned char)*str;
  663. isalnum(c) || c == '_' || c == '-'; c = *str++)
  664. ;
  665. return (c == '=');
  666. }