home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume44 / arg_parse / part01 next >
Internet Message Format  |  1994-09-05  |  69KB

  1. From: Paul.Heckbert@hostess.graphics.cs.cmu.edu (Paul Heckbert)
  2. Newsgroups: comp.sources.misc
  3. Subject: v44i050:  arg_parse - simple, powerful argument parser, Part01/01
  4. Date: 5 Sep 1994 11:42:27 -0500
  5. Organization: Sterling Software
  6. Sender: kent@sparky.sterling.com
  7. Approved: kent@sparky.sterling.com
  8. Message-ID: <34fhpj$2kp@sparky.sterling.com>
  9. X-Md4-Signature: e6610ffa95163eabbcc84e048770f37f
  10.  
  11. Submitted-by: Paul.Heckbert@hostess.graphics.cs.cmu.edu (Paul Heckbert)
  12. Posting-number: Volume 44, Issue 50
  13. Archive-name: arg_parse/part01
  14. Environment: Sun, DEC, SGI, HP
  15.  
  16. arg_parse is a subroutine for parsing command-line arguments.  It is
  17. very easy to use, and yields a powerful, consistent command-line
  18. interface to programs. It supports argument conversion and type
  19. checking, arbitrary argument order, multi-character flag names,
  20. automatic usage messages, and expression evaluation.
  21. It is written in C.
  22.  
  23. I've tested it on Sun, DEC, SGI (MIPS), and HP machines and it works perfectly.
  24. I haven't tested it much on other machine types.
  25.  
  26. Paul Heckbert                                               ph@cs.cmu.edu
  27. Computer Science Dept., Carnegie Mellon University
  28. 5000 Forbes Ave, Pittsburgh PA 15213-3891, USA
  29.  
  30.   ============================================================
  31.    Here is a more complete description, from the man page:
  32.   ============================================================
  33.  
  34. DESCRIPTION
  35.  
  36. arg_parse is a subroutine for parsing and conversion of
  37. command-line arguments.     This parser is an alternative to
  38. the common method of argument parsing, which is an ad-hoc
  39. parser in each program, typically written with a large,
  40. cumbersome switch statement.  arg_parse allows a command-
  41. line parser to be described very concisely while retaining
  42. the flexibility to handle a variety of syntaxes.
  43.  
  44. The parser has a number of features:
  45.  
  46.     + arbitrary order of flag arguments
  47.     + automatic argument conversion and type checking
  48.     + multiple-character flag names
  49.     + required, optional, and flag arguments
  50.     + automatic usage message
  51.     + subroutine call for exotic options (variable number of parameters)
  52.     + modularized parsers encourage standardized options
  53.     + expression evaluation
  54.     + works either from argv or in interactive mode, as a primitive
  55.     language parser and interpreter
  56.     + concise specification
  57.     + easy to use
  58.  
  59. It is hoped that use of arg_parse will help standardize
  60. argument conventions and reduce the tedium of adding options
  61. to programs.
  62.  
  63. APPETIZER
  64.  
  65. Here is a simple example:
  66.  
  67.     #include <arg.h>
  68.  
  69.     main(argc, argv)
  70.     int argc;
  71.     char **argv;
  72.     {
  73.     char *file;
  74.     int level = 3, debug;
  75.     double xsize = 20., ysize = 10.;
  76.  
  77.     arg_parse(argc, argv,
  78.          "", "Usage: prog [options]",
  79.          "%S", &file, "set output file",
  80.          "[%d]", &level, "set recursion level [default=%d]", level,
  81.          "-size %F %F", &xsize, &ysize, "set x and y sizes",                 "-debug", ARG_FLAG(&debug), "turn on debugging",
  82.     0);
  83.  
  84. The arg_parse call defines the program's arguments, in this
  85. case: one required argument (a filename), an optional argu-
  86. ment (an integer level number), an optional flag with two
  87. parameters (floating point size), and a simple flag (boolean
  88. debug flag).  If the above program (call it prog) were run
  89. with
  90.  
  91.     prog joe.c
  92.  
  93. it would set file to joe.c, and set debug to 0, and if run with
  94.  
  95.     prog -size 100 400/3 joe.c -debug 5
  96.  
  97. it would set file="joe.c", level=5, xsize=100, ysize=133.33,
  98. and debug=1.  In all programs using arg_parse, a hyphen
  99. arguments elicits a usage message, so the command
  100.  
  101.     prog -
  102.  
  103. results in the printout
  104.  
  105.     Usage: prog [options]
  106.     %S              set output file
  107.     [%d]          set recursion level [default=3]
  108.     -size %F %F          set x and y sizes
  109.     -debug          turn on debugging
  110. ---------
  111. #! /bin/sh
  112. # This is a shell archive.  Remove anything before this line, then feed it
  113. # into a shell via "sh file" or similar.  To overwrite existing files,
  114. # type "sh file -c".
  115. # Contents:  libarg libarg/Makefile libarg/README libarg/arg.c
  116. #   libarg/arg.h libarg/arg_parse.3 libarg/expr.c libarg/expr.h
  117. #   libarg/simple.h libarg/tb.c
  118. # Wrapped by kent@sparky on Mon Sep  5 11:39:15 1994
  119. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin:$PATH ; export PATH
  120. echo If this archive is complete, you will see the following message:
  121. echo '          "shar: End of archive 1 (of 1)."'
  122. if test ! -d 'libarg' ; then
  123.     echo shar: Creating directory \"'libarg'\"
  124.     mkdir 'libarg'
  125. fi
  126. if test -f 'libarg/Makefile' -a "${1}" != "-c" ; then 
  127.   echo shar: Will not clobber existing file \"'libarg/Makefile'\"
  128. else
  129.   echo shar: Extracting \"'libarg/Makefile'\" \(593 characters\)
  130.   sed "s/^X//" >'libarg/Makefile' <<'END_OF_FILE'
  131. X# Makefile for libarg
  132. X# $Header: /gourd/usr2/ph/sys/libsys/libarg/RCS/Makefile,v 4.2 94/08/03 20:09:41 ph Exp Locker: ph $
  133. X
  134. XDEST = /usr/johndoe
  135. XCOPTS = -g
  136. XIPATH = -I.
  137. XCFLAGS = $(COPTS) $(IPATH) $(CONFIG)
  138. XLIB = libarg.a
  139. X
  140. Xall: tb
  141. X
  142. X$(LIB): arg.o expr.o
  143. X    ar rcu $(LIB) arg.o expr.o
  144. X    ranlib $(LIB)
  145. X
  146. Xexpr: expr.c
  147. X    cc $(COPTS) -o expr -DMAIN expr.c -lm
  148. X
  149. Xinstall: all
  150. X    mv $(LIB) $(DEST)/lib
  151. X    cp arg.h expr.h simple.h $(DEST)/include
  152. X
  153. X# test programs
  154. X
  155. Xtb: tb.o $(LIB)
  156. X    cc $(COPTS) -o tb tb.o $(LIB) -lm
  157. X
  158. X# misc
  159. X
  160. Xprint:
  161. X    tbl arg_parse.3 | troff -man
  162. X
  163. Xclean:
  164. X    rm -f $(LIB) *.o tb
  165. X
  166. Xarg.o expr.o: simple.h
  167. END_OF_FILE
  168.   if test 593 -ne `wc -c <'libarg/Makefile'`; then
  169.     echo shar: \"'libarg/Makefile'\" unpacked with wrong size!
  170.   fi
  171.   # end of 'libarg/Makefile'
  172. fi
  173. if test -f 'libarg/README' -a "${1}" != "-c" ; then 
  174.   echo shar: Will not clobber existing file \"'libarg/README'\"
  175. else
  176.   echo shar: Extracting \"'libarg/README'\" \(799 characters\)
  177.   sed "s/^X//" >'libarg/README' <<'END_OF_FILE'
  178. XThis is source code to an argument parser with lots of nifty features.
  179. XIt's written in C (Kernighan and Ritchie, not ANSI).
  180. X
  181. XSee the man page arg_parse.3 for documentation.
  182. XTo test it run "make" and then play with the "tb" command.
  183. X
  184. XThis code is available via anonymous ftp from
  185. Xhostess.graphics.cs.cmu.edu (128.2.206.188) in /usr/ph/ftp/libarg.tar.Z
  186. XAfter you "get" the file, run
  187. X    zcat libarg.tar.Z | tar xvf -
  188. X
  189. XIf you find significant bugs in it, like it a lot, or enhance it significantly,
  190. Xplease send me email.
  191. X
  192. XPaul Heckbert                                               ph@cs.cmu.edu
  193. XComputer Science Dept., Carnegie Mellon University
  194. X5000 Forbes Ave, Pittsburgh PA 15213-3891, USA
  195. X
  196. X3 Aug 94
  197. X
  198. X$Header: /gourd/usr2/ph/sys/libsys/libarg/RCS/README,v 4.2 94/08/03 20:39:58 ph Exp Locker: ph $
  199. END_OF_FILE
  200.   if test 799 -ne `wc -c <'libarg/README'`; then
  201.     echo shar: \"'libarg/README'\" unpacked with wrong size!
  202.   fi
  203.   # end of 'libarg/README'
  204. fi
  205. if test -f 'libarg/arg.c' -a "${1}" != "-c" ; then 
  206.   echo shar: Will not clobber existing file \"'libarg/arg.c'\"
  207. else
  208.   echo shar: Extracting \"'libarg/arg.c'\" \(21871 characters\)
  209.   sed "s/^X//" >'libarg/arg.c' <<'END_OF_FILE'
  210. X/*
  211. X * arg_parse: Command line argument parser.
  212. X *
  213. X * notable features:
  214. X *    arbitrary order of flag arguments
  215. X *    automatic argument conversion and type checking
  216. X *    multiple-character flag names
  217. X *    required, optional, and flag arguments
  218. X *    automatic usage message
  219. X *    subroutine call for exotic options (variable number of parameters)
  220. X *    modularized parsers encourage standardized options
  221. X *    expression evaluation
  222. X *    works either from argv or in interactive mode,
  223. X *        as a primitive language parser and interpreter
  224. X *    concise specification
  225. X *    easy to use
  226. X *
  227. X * Paul Heckbert    ph@cs.cmu.edu
  228. X *
  229. X * 19 April 1988 - written at UC Berkeley
  230. X *
  231. X * simpler version written at Pacific Data Images, Aug 1985.
  232. X * Ideas borrowed from Ned Greene's ARGS at New York Inst. of Tech.
  233. X * and Alvy Ray Smith's AARG at Pixar.
  234. X */
  235. X
  236. Xstatic char rcsid[] = "$Header: /gourd/usr2/ph/sys/libsys/RCS/arg.c,v 4.2 94/08/03 15:41:10 ph Exp Locker: ph $";
  237. X
  238. X#include <varargs.h>
  239. X#include <ctype.h>
  240. X#include <string.h>
  241. X
  242. X#include "simple.h"
  243. X#include "arg.h"
  244. X
  245. X#define CHECKTYPE(form, keyword) \
  246. X    if (form->type!=0) { \
  247. X    fprintf(stderr, "arg: %s doesn't belong in %s paramlist\n", \
  248. X        keyword, form->format); \
  249. X    return 0; \
  250. X    } \
  251. X    else
  252. X
  253. X/* recognize a valid numeric constant or expression by its first char: */
  254. X#define NUMERIC(s) (isdigit(*(s)) || \
  255. X    *(s)=='.' || *(s)=='-' || *(s)=='+' || *(s)=='(')
  256. X
  257. Xint arg_debug = 0;        /* debugging level; 0=none */
  258. Xint arg_doccol = 24;        /* column at which to print doc string*/
  259. Xint arg_warning = 1;        /* print warnings about repeated flags? */
  260. X
  261. Xstatic Arg_form *regf;        /* advancing form ptr used by arg_find_reg */
  262. X
  263. Xva_list arg_doc_parse();
  264. X
  265. X/*
  266. X * arg_parse(ac, av, varargs_list)
  267. X * Parse the arguments in av according to the varargs list, which contains
  268. X * format strings, parameter and subroutine ptrs, and other stuff.
  269. X * The varargs list must be terminated by a 0.
  270. X * Returns an error code.
  271. X */
  272. X
  273. Xarg_parse(va_alist)
  274. Xva_dcl
  275. X{
  276. X    char **av;
  277. X    int ac, ret;
  278. X    va_list ap;
  279. X    Arg_form *form;
  280. X
  281. X    va_start(ap);
  282. X    ac = va_arg(ap, int);
  283. X    av = va_arg(ap, char **);
  284. X    if (ac<1 || ac>ARG_NARGMAX) {
  285. X    fprintf(stderr,
  286. X        "arg_parse: first arg to arg_parse (%d) doesn't look like argc\n",
  287. X        ac);
  288. X    return ARG_BADCALL;
  289. X    }
  290. X
  291. X    /* convert varargs to formlist */
  292. X    form = arg_to_form1(ap);
  293. X    if (!form)
  294. X    return ARG_BADCALL;
  295. X
  296. X    /* parse args according to form */
  297. X    if (ac==2 && str_eq(av[1], "-stdin")) /* no args, run interactive version */
  298. X    ret = arg_parse_stream(stdin, form);
  299. X    else                /* args supplied, parse av */
  300. X    ret = arg_parse_argv(ac, av, form);
  301. X    return ret;
  302. X}
  303. X
  304. X/*----------------------------------------------------------------------*/
  305. X
  306. X/*
  307. X * arg_to_form: convert varargs to formlist
  308. X * not called by arg_parse, but sometimes called from outside to build sublists
  309. X */
  310. X
  311. XArg_form *arg_to_form(va_alist)
  312. Xva_dcl
  313. X{
  314. X    va_list ap;
  315. X
  316. X    va_start(ap);
  317. X    return arg_to_form1(ap);
  318. X}
  319. X
  320. X/*
  321. X * arg_to_form1: convert varargs to formlist recursively.
  322. X * assumes va_start has already been called
  323. X * calls va_end when done to clean up
  324. X * returns 0 on error.
  325. X */
  326. X
  327. XArg_form *arg_to_form1(ap)
  328. Xva_list ap;
  329. X{
  330. X    char *s, *prevs;
  331. X    int pi, t;
  332. X    Arg_form *form, *prevform, *rootform;
  333. X
  334. X    /*
  335. X     * varargs syntax is:
  336. X     *     formatstr [KEYWORD val] paramptr* docstr docargptr*
  337. X     * where there are as many paramptrs as %'s in the format string
  338. X     * and as many docargptrs as %'s in the doc string
  339. X     */
  340. X    rootform = 0;
  341. X    prevs = "";
  342. X    for (prevform=0; (s = va_arg(ap, char *)) != 0; prevform=form) {
  343. X
  344. X    /* first, read the format string */
  345. X    if (checkstr(s, "format string", prevs)) return 0;
  346. X    ALLOC(form, Arg_form, 1);
  347. X    form->next = 0;
  348. X    form->format = s;
  349. X    form->flag = 0;
  350. X    form->type = 0;
  351. X    form->param = 0;
  352. X    form->parammask = 0;
  353. X    form->subr = 0;
  354. X    form->sublist = 0;
  355. X    if (prevform) prevform->next = form;
  356. X    else rootform = form;
  357. X
  358. X    /* parse format to create flag and code strings, compute #params */
  359. X    t = arg_format(form);
  360. X    if (t) return 0;
  361. X
  362. X    /* next, read the parameters and keywords */
  363. X    pi = 0;
  364. X    if (form->nparam>0) {
  365. X        form->type = form->flag[0]=='-' ? ARG_PARAMFLAG : ARG_REGULAR;
  366. X        assert(form->param = (int **)malloc(form->nparam*sizeof(int *)));
  367. X    }
  368. X    for (; (s = va_arg(ap, char *)) != 0;) {
  369. X        /* note that we continue (not break) in all cases except one */
  370. X        switch ((int)s) {
  371. X        case ARG_FLAGNEXT:        /* ptr to flag vbl */
  372. X            CHECKTYPE(form, "FLAG");
  373. X            form->type = ARG_SIMPFLAG;
  374. X            ALLOC(form->param, int *, 1);
  375. X            *form->param = va_arg(ap, int *);
  376. X            continue;
  377. X        case ARG_SUBRNEXT:        /* ptr to action subr */
  378. X            CHECKTYPE(form, "SUBR");
  379. X            form->type = ARG_SUBRFLAG;
  380. X            form->subr = (int (*)())va_arg(ap, int *);
  381. X            /* append dots to end of format string */
  382. X            assert(s = (char *)malloc(strlen(form->format)+5));
  383. X            sprintf(s, "%s ...", form->format);
  384. X            form->format = s;
  385. X            continue;
  386. X        case ARG_LISTNEXT:        /* ptr to sub-formlist */
  387. X            CHECKTYPE(form, "SUBLIST");
  388. X            form->type = ARG_SUBLISTFLAG;
  389. X            form->sublist = va_arg(ap, Arg_form *);
  390. X            continue;
  391. X        default:            /* ptr to param */
  392. X            if (pi>=form->nparam) break;
  393. X            form->param[pi++] = (int *)s;
  394. X            continue;
  395. X        }
  396. X        break;                /* end of params/keywords */
  397. X    }
  398. X
  399. X    if (!form->flag[0] && form->type==ARG_SUBLISTFLAG) {
  400. X        fprintf(stderr, "arg: sublist must be given a flag name\n");
  401. X        return 0;
  402. X    }
  403. X    if (!form->type)            /* just a doc string */
  404. X        form->type = ARG_NOP;
  405. X    /* finally, read the doc string */
  406. X    if (checkstr(s, "doc string", form->format)) return 0;
  407. X    form->doc = prevs = s;
  408. X
  409. X    /* skip over doc args */
  410. X    ap = arg_doc_parse(form, ap);
  411. X    }
  412. X    va_end(ap);
  413. X    return rootform;
  414. X}
  415. X
  416. X/* checkstr: check that s is a valid string */
  417. X
  418. Xstatic checkstr(s, name, prev)
  419. Xchar *s, *name, *prev;
  420. X{
  421. X    char *delim;
  422. X
  423. X    delim = prev ? "\"" : "";
  424. X    if (!s || (int)s&ARG_MASKNEXT) {
  425. X    fprintf(stderr, "bad arg call: missing %s after %s%s%s\n",
  426. X        name, delim, prev, delim);
  427. X    return 1;
  428. X    }
  429. X    return 0;
  430. X}
  431. X
  432. X/*
  433. X * arg_format: parse the format string to create flag string,
  434. X * code string, parammask, and count the number of params.
  435. X * e.g.: format="-size %d %F"  =>  flag="-size", code="dF", nparam=2
  436. X */
  437. X
  438. Xarg_format(f)
  439. XArg_form *f;
  440. X{
  441. X    char *s, *c;
  442. X    int n, np;
  443. X
  444. X    if (f->format[0]=='-') {        /* flag string present */
  445. X    /* find the end of the flag string, put flag string in f->flag */
  446. X    for (s= &f->format[1]; *s && *s!=' ' && *s!='%' && *s!='['; s++);
  447. X    n = s-f->format;
  448. X    assert(f->flag = (char *)malloc(n+1));
  449. X    bcopy(f->format, f->flag, n);
  450. X    f->flag[n] = 0;
  451. X    }
  452. X    else {
  453. X    s = f->format;            /* no flag string: probably a reg arg */
  454. X    f->flag = "";            /* or maybe a flagless subrflag */
  455. X    }
  456. X
  457. X    /* extract scanf codes from remainder of format string, put in f->code */
  458. X    n = (f->format+strlen(f->format)-s)/2;    /* overestimate # of % codes */
  459. X    assert(f->code = (char *)malloc(n+1));
  460. X    for (c=f->code, np=0;; np++, s++) {
  461. X    for (; *s==' ' || *s=='['; s++)
  462. X        if (*s=='[') f->parammask |= 1<<np;
  463. X    if (!*s || *s==']') break;
  464. X    if (*s!='%' || !s[1]) {
  465. X        fprintf(stderr, "arg: bad format string (%s)\n", f->format);
  466. X        return ARG_BADCALL;
  467. X    }
  468. X    *c++ = *++s;
  469. X    }
  470. X    for (; *s; s++)
  471. X    if (*s!=' ' && *s!=']') {
  472. X        fprintf(stderr, "bad format (%s), nothing allowed after ']'s\n",
  473. X        f->format);
  474. X        return ARG_BADCALL;
  475. X    }
  476. X    f->parammask |= 1<<np;
  477. X    if (np>=8*sizeof(int)) {
  478. X    fprintf(stderr, "out of bits in parammask! too many params to %s\n",
  479. X        f->flag);
  480. X    return ARG_BADCALL;
  481. X    }
  482. X
  483. X    /* number of parameters to flag = number of '%'s in format string */
  484. X    f->nparam = np;
  485. X    *c = 0;
  486. X    if (c-f->code!=f->nparam) fprintf(stderr, "OUCH!\n");
  487. X    return 0;
  488. X}
  489. X
  490. X/*
  491. X * arg_doc_parse: Find the '%' format codes in f->doc and increment varargs
  492. X * ptr ap over the doc string parameters.  Updates f->doc to be the formatted
  493. X * documentation string and returns the new ap.
  494. X */
  495. X
  496. Xva_list arg_doc_parse(f, ap)
  497. XArg_form *f;
  498. Xva_list ap;
  499. X{
  500. X    char *s, buf[256];
  501. X    int size, gotparam;
  502. X    va_list ap0;
  503. X
  504. X    ap0 = ap;
  505. X    gotparam = 0;
  506. X    for (s=f->doc; *s; s++) {
  507. X    for (; *s; s++)            /* search for next format code */
  508. X        if (s[0]=='%')
  509. X        if (s[1]=='%') s++;    /* skip over %% */
  510. X        else break;
  511. X    if (!*s) break;
  512. X    /* skip over numerical parameters */
  513. X    for (s++; *s && *s=='-' || *s>'0'&&*s<='9' || *s=='.'; s++);
  514. X    /* now *s points to format code */
  515. X    switch (*s) {
  516. X        case 'h': size = 0; s++; break;    /* half */
  517. X        case 'l': size = 2; s++; break;    /* long */
  518. X        default : size = 1;      break;    /* normal size */
  519. X    }
  520. X    if (!*s) {
  521. X        fprintf(stderr, "arg: premature end of string in (%s)\n", f->doc);
  522. X        break;
  523. X    }
  524. X    gotparam = 1;
  525. X    /*
  526. X     * simulate printf's knowledge of type sizes
  527. X     * (it's too bad we have to do this)
  528. X     */
  529. X    switch (*s) {
  530. X        case 'd': case 'D':
  531. X        case 'o': case 'O':
  532. X        case 'x': case 'X':
  533. X        case 'c':
  534. X        if (size==2 || *s>='A' && *s<='Z') va_arg(ap, long);
  535. X        else va_arg(ap, int);
  536. X        break;
  537. X        case 'e':
  538. X        case 'f':
  539. X        case 'g':
  540. X        /* note: float args are converted to doubles by MOST compilers*/
  541. X        va_arg(ap, double);
  542. X        break;
  543. X        case 's':
  544. X        va_arg(ap, char *);
  545. X        break;
  546. X        default:
  547. X        fprintf(stderr, "arg: unknown format code %%%c in %s\n",
  548. X            *s, f->doc);
  549. X        va_arg(ap, int);
  550. X        break;
  551. X    }
  552. X    }
  553. X    if (gotparam) {    /* there are doc parameters, format a new doc string */
  554. X    vsprintf(buf, f->doc, ap0);
  555. X    assert(f->doc = (char *)malloc(sizeof(buf)+1));
  556. X    strcpy(f->doc, buf);
  557. X    }
  558. X
  559. X    return ap;        /* varargs ptr past end of doc params */
  560. X}
  561. X
  562. X/*----------------------------------------------------------------------*/
  563. X
  564. X#define LINEMAX 256
  565. X#define ACMAX 128
  566. X
  567. Xtypedef enum {SPACE, TOKEN, END} Token_type;
  568. XToken_type token_char();
  569. X
  570. X/*
  571. X * arg_parse_stream: parse from an input stream (not from an arg vector)
  572. X * parse args in stream fp, line by line, according to formlist in form
  573. X * Returns 0 on success, negative on failure.
  574. X */
  575. X
  576. Xarg_parse_stream(fp, form)
  577. XFILE *fp;
  578. XArg_form *form;
  579. X{
  580. X    char c, *av[ACMAX], line[LINEMAX], *p;
  581. X    Token_type type;
  582. X    int i, ac, ret, err;
  583. X    Arg_form *oldregf;
  584. X
  585. X    oldregf = regf;
  586. X    regf = form;
  587. X    arg_init(form);
  588. X
  589. X    av[0] = "hi";
  590. X    ret = 0;
  591. X    for (;;) {                /* read and process line */
  592. X    p = line;
  593. X    while ((type = token_char(fp, &c))==SPACE);
  594. X    for (ac=1; type!=END && ac<ACMAX;) {    /* split line into tokens */
  595. X        av[ac++] = p;        /* save ptr to beginning of token */
  596. X        do {
  597. X        *p++ = c;
  598. X        if (p >= line+LINEMAX) {
  599. X            fprintf(stderr, "input line too long\n");
  600. X            exit(1);
  601. X        }
  602. X        } while ((type = token_char(fp, &c))==TOKEN);
  603. X        *p++ = 0;            /* terminate this token in line[] */
  604. X        if (type==END) break;
  605. X        while ((type = token_char(fp, &c))==SPACE);
  606. X    }
  607. X    if (feof(fp)) break;
  608. X    if (arg_debug) {
  609. X        fprintf(stderr, "ac=%d: ", ac);
  610. X        for (i=1; i<ac; i++) fprintf(stderr, "(%s) ", av[i]);
  611. X        fprintf(stderr, "\n");
  612. X    }
  613. X
  614. X    err = arg_parse_form1(ac, av, form);
  615. X    if (!ret) ret = err;
  616. X    }
  617. X    if (!ret) ret = arg_done();
  618. X    regf = oldregf;
  619. X    return ret;
  620. X}
  621. X
  622. X/*
  623. X * token_char: is next char in stream fp part of a token?
  624. X * returns TOKEN if char in token, SPACE if whitespace, END if end of input line
  625. X * *p gets new char.
  626. X * handles quoted strings and escaped characters.
  627. X */
  628. X
  629. Xstatic Token_type token_char(fp, p)
  630. XFILE *fp;
  631. Xchar *p;
  632. X{
  633. X    int c, old_mode;
  634. X    Token_type type;
  635. X    static int mode = 0;    /* = '"' or '\'' if inside quoted string */
  636. X
  637. X    type = TOKEN;
  638. X    do {
  639. X    old_mode = mode;
  640. X    c = getc(fp);
  641. X    switch (c) {
  642. X        case EOF:
  643. X        type = END;
  644. X        break;
  645. X        case '\\':
  646. X        switch (c = getc(fp)) {
  647. X            case 'b': c = '\b'; break;
  648. X            case 'f': c = '\f'; break;
  649. X            case 'n': c = '\n'; break;
  650. X            case 'r': c = '\r'; break;
  651. X            case 't': c = '\t'; break;
  652. X            case 'v': c = '\v'; break;
  653. X            case '0': c = '\0'; break;
  654. X        }
  655. X        break;
  656. X        case '"':
  657. X        switch (mode) {
  658. X            case 0: mode = '"'; break;        /* begin " */
  659. X            case '"': mode = 0; break;        /* end " */
  660. X        }
  661. X        break;
  662. X        case '\'':
  663. X        switch (mode) {
  664. X            case 0: mode = '\''; break;        /* begin ' */
  665. X            case '\'': mode = 0; break;        /* end ' */
  666. X        }
  667. X        break;
  668. X        case '\n':
  669. X        switch (mode) {
  670. X            case 0: type = END; break;
  671. X        }
  672. X        break;
  673. X    }
  674. X    /* loop until we read a literal character */
  675. X    } while (old_mode != mode);
  676. X    *p = c;
  677. X
  678. X    if (type!=END && mode==0 && (c==' ' || c=='\t' || c=='\n'))
  679. X    type = SPACE;
  680. X    return type;
  681. X}
  682. X
  683. X/*
  684. X * arg_parse_argv: do the actual parsing!
  685. X * parse the arguments in av according to the formlist in form
  686. X * Returns 0 on success, negative on failure.
  687. X */
  688. X
  689. Xarg_parse_argv(ac, av, form)
  690. Xint ac;
  691. Xchar **av;
  692. XArg_form *form;
  693. X{
  694. X    int ret;
  695. X    Arg_form *oldregf;
  696. X
  697. X    oldregf = regf;
  698. X    regf = form;
  699. X    arg_init(form);
  700. X    ret = arg_parse_form1(ac, av, form);
  701. X    if (!ret) ret = arg_done();
  702. X    regf = oldregf;
  703. X    return ret;
  704. X}
  705. X
  706. Xarg_parse_form1(ac, av, form)
  707. Xint ac;
  708. Xchar **av;
  709. XArg_form *form;
  710. X{
  711. X    int i, di;
  712. X    Arg_form *f;
  713. X
  714. X    for (i=1; i<ac; i+=di) {
  715. X    if (arg_debug)
  716. X        fprintf(stderr, "arg %d: (%s)\n", i, av[i]);
  717. X    if (av[i][0]=='-' && !NUMERIC(&av[i][1])) {    /* flag argument */
  718. X        f = arg_find_flag(av[i], form);
  719. X        if (!f) {
  720. X        if (av[i][1])
  721. X            fprintf(stderr, "unrecognized arg: %s\n", av[i]);
  722. X        else        /* arg was "-"; print usage message */
  723. X            arg_form_print(form);
  724. X        return ARG_EXTRA;
  725. X        }
  726. X        di = arg_do(ac-i-1, &av[i+1], f);
  727. X        if (di<0) return di;
  728. X        di++;
  729. X    }
  730. X    else {            /* regular argument */
  731. X        f = arg_find_reg();
  732. X        if (!f) {
  733. X        /* regular args exhausted, see if any flagless subrflags */
  734. X        f = arg_find_flag("", form);
  735. X        if (!f) {
  736. X            fprintf(stderr, "extra arg: %s\n", av[i]);
  737. X            return ARG_EXTRA;
  738. X        }
  739. X        }
  740. X        di = arg_do(ac-i, &av[i], f);
  741. X        if (di<0) return di;
  742. X    }
  743. X    }
  744. X
  745. X    return 0;
  746. X}
  747. X
  748. X/*
  749. X * arg_init: initialize formlist before parsing arguments
  750. X * Set simple flags and repeat counts to 0.
  751. X */
  752. X
  753. Xarg_init(form)
  754. XArg_form *form;
  755. X{
  756. X    Arg_form *f;
  757. X
  758. X    for (f=form; f; f=f->next)
  759. X    if (f->type==ARG_SUBLISTFLAG) arg_init(f->sublist);    /* recurse */
  760. X    else {
  761. X        f->rep = 0;
  762. X        if (f->type==ARG_SIMPFLAG) **f->param = 0;
  763. X    }
  764. X}
  765. X
  766. Xarg_done()
  767. X{
  768. X    for (; regf; regf=regf->next)    /* any required reg args remaining? */
  769. X    if (regf->type==ARG_REGULAR && !(regf->parammask&1)) {
  770. X        fprintf(stderr, "regular arg %s (%s) not set\n",
  771. X        regf->format, regf->doc);
  772. X        return ARG_MISSING;
  773. X    }
  774. X    return 0;
  775. X}
  776. X
  777. X/*
  778. X * arg_find_flag: find the flag matching arg in the form list (tree)
  779. X * returns form ptr if found, else 0
  780. X */
  781. X
  782. XArg_form *arg_find_flag(arg, form)
  783. Xchar *arg;
  784. XArg_form *form;
  785. X{
  786. X    Arg_form *f, *t;
  787. X
  788. X    for (f=form; f; f=f->next) {
  789. X    if (f->type!=ARG_REGULAR && f->type!=ARG_NOP && str_eq(f->flag, arg))
  790. X        return f;
  791. X    if (f->type==ARG_SUBLISTFLAG) {
  792. X        t = arg_find_flag(arg, f->sublist);        /* recurse */
  793. X        if (t) return t;
  794. X    }
  795. X    }
  796. X    return 0;
  797. X}
  798. X
  799. X/*
  800. X * arg_find_reg: find next regular argument
  801. X * each call advances the global pointer regf through the formlist
  802. X */
  803. X
  804. XArg_form *arg_find_reg()
  805. X{
  806. X    Arg_form *f;
  807. X
  808. X    for (; regf; regf=regf->next) {
  809. X    if (regf->type==ARG_REGULAR) {
  810. X        f = regf;
  811. X        regf = regf->next;
  812. X        return f;
  813. X    }
  814. X    }
  815. X    return 0;
  816. X}
  817. X
  818. X/*
  819. X * arg_do: process one form by parsing arguments in av according to the
  820. X * single form in f
  821. X *
  822. X * f was found by arg_find_flag or arg_find_reg,
  823. X *     so if f is a flag then we know av[-1] matches f->flag
  824. X *
  825. X * examine av[0]-av[ac-1] to determine number of parameters supplied
  826. X *     if simpleflag, set flag parameter and read no args
  827. X *     if subrflag, call subroutine on sub-args
  828. X *     if sublist, call arg_parse_form on sub-args
  829. X *     else it's a paramflag or regular arg, do arg-to-param assignments
  830. X * return number of arguments gobbled, or negative error code
  831. X */
  832. X
  833. Xarg_do(ac, av, f)
  834. Xint ac;
  835. Xchar **av;
  836. XArg_form *f;
  837. X{
  838. X    int narg, skip, used, err, i;
  839. X
  840. X    if (arg_debug)
  841. X    av_print("  arg_do", ac, av);
  842. X    if (f->type==ARG_SIMPFLAG || f->type==ARG_PARAMFLAG) {
  843. X    /* don't complain about repeated subrflags or sublists */
  844. X    assert(str_eq(av[-1], f->flag));
  845. X    f->rep++;
  846. X    if (f->rep>1 && arg_warning)
  847. X        fprintf(stderr, "warning: more than one %s flag in arglist\n",
  848. X        f->flag);
  849. X    }
  850. X
  851. X    narg = nargs(ac, av, f, &skip);
  852. X
  853. X    used = 0;
  854. X    switch (f->type) {
  855. X    case ARG_SIMPFLAG:
  856. X        **f->param = 1;
  857. X        break;
  858. X    case ARG_SUBRFLAG:
  859. X        (*f->subr)(narg, av);
  860. X        break;
  861. X    case ARG_SUBLISTFLAG:
  862. X        arg_parse_argv(narg+1, &av[-1], f->sublist);    /* recurse */
  863. X        used = narg;
  864. X        break;
  865. X    default:            /* convert parameters */
  866. X        err = scan(narg, av, f);
  867. X        if (err) return err;
  868. X        used = narg<f->nparam ? narg : f->nparam;
  869. X        break;
  870. X    }
  871. X
  872. X    if ((f->type==ARG_REGULAR || f->type==ARG_PARAMFLAG) && used!=narg) {
  873. X    fprintf(stderr, "warning: %d unused arg%s to %s: ",
  874. X        narg-used, narg-used>1 ? "s" : "", av[-1]);
  875. X    for (i=used; i<narg; i++)
  876. X        fprintf(stderr, "%s ", av[i]);
  877. X    fprintf(stderr, "\n");
  878. X    }
  879. X    return skip;
  880. X}
  881. X
  882. X/*
  883. X * nargs: Count number of parameters in arg vector av before the next flag.
  884. X * Arguments can be grouped and "escaped" using -{ and -}.
  885. X * NOTE: modifies av
  886. X * Returns number of valid args in new av.
  887. X * Sets *skip to number of args to skip in old av to get to next flag.
  888. X *
  889. X * This is the most complex code in arg_parse.
  890. X * Is there a better way?
  891. X *
  892. X * examples:
  893. X *     input:  ac=3, av=(3 4 -go)
  894. X *     output: av unchanged, skip=2, return 2
  895. X *
  896. X *     input:  ac=4, av=(-{ -ch r -})
  897. X *     output: av=(-ch r X X), skip=4, return 2
  898. X *
  899. X *     input:  ac=4, av=(-{ -foo -} -go)
  900. X *     output: av=(-foo X X -go), skip=3, return 1
  901. X *
  902. X *     input:  ac=6, av=(-{ -ch -{ -rgb -} -})
  903. X *     output: av=(-ch -{ -rgb -} X X), skip=6, return 4
  904. X *
  905. X *     where X stands for junk
  906. X */
  907. X
  908. Xstatic nargs(ac, av, f, skip)
  909. Xint ac, *skip;
  910. Xchar **av;
  911. XArg_form *f;
  912. X{
  913. X    char *flag, **au, **av0;
  914. X    int i, j, level, die, np, mask, voracious;
  915. X
  916. X    np = f->nparam;
  917. X    mask = f->parammask;
  918. X    flag = f->type==ARG_REGULAR ? f->format : f->flag;
  919. X    voracious = f->type==ARG_SUBRFLAG || f->type==ARG_SUBLISTFLAG;
  920. X    /* subrs&sublists want all the args they can get */
  921. X
  922. X    level = 0;
  923. X    av0 = au = av;
  924. X    if (voracious) np = 999;
  925. X    for (die=0, i=0; i<np && i<ac && !die; ) {
  926. X    if (voracious) j = 999;
  927. X    else for (j=i+1; !(mask>>j&1); j++);    /* go until we can stop */
  928. X    /* try to grab params i through j-1 */
  929. X    for (; i<j && i<ac || level>0; i++, au++, av++) {
  930. X        if (au!=av) *au = *av;
  931. X        if (str_eq(*av, "-{")) {
  932. X        if (level<=0) au--;        /* skip "-{" in av if level 0 */
  933. X        level++;            /* push a level */
  934. X        }
  935. X        else if (str_eq(*av, "-}")) {
  936. X        level--;            /* pop a level */
  937. X        if (level<=0) au--;        /* skip "-}" in av if level 0 */
  938. X        if (level<0)
  939. X            fprintf(stderr, "ignoring spurious -}\n");
  940. X        }
  941. X        else if (level==0 && av[0][0]=='-' && !NUMERIC(&av[0][1])) {
  942. X        die = 1;        /* break out of both loops */
  943. X        break;            /* encountered flag at level 0 */
  944. X        }
  945. X    }
  946. X    }
  947. X    if (arg_debug) {
  948. X    fprintf(stderr, "    %s: requested %d, got %d args: ",
  949. X        flag, np, au-av0);
  950. X    for (j=0; j<au-av0; j++)
  951. X        fprintf(stderr, "%s ", av0[j]);
  952. X    fprintf(stderr, "\n");
  953. X    }
  954. X    *skip = i;
  955. X    return au-av0;
  956. X}
  957. X
  958. X/*
  959. X * scan: call sscanf to read args into param array and do conversion
  960. X * returns error code (0 on success)
  961. X */
  962. X
  963. Xstatic scan(narg, arg, f)
  964. Xint narg;
  965. Xchar **arg;
  966. XArg_form *f;
  967. X{
  968. X    static char str[]="%X";
  969. X    char *s;
  970. X    int i, **p;
  971. X    double x;
  972. X
  973. X    if (f->nparam<narg) narg = f->nparam;
  974. X    if (!(f->parammask>>narg&1)) {
  975. X    fprintf(stderr, "you can't give %s just %d params\n",
  976. X        f->format, narg);
  977. X    return ARG_MISSING;
  978. X    }
  979. X    for (p=f->param, i=0; i<narg; i++, p++) {
  980. X    str[1] = f->code[i];
  981. X    switch (str[1]) {
  982. X        case 'S':
  983. X        /*
  984. X         * dynamically allocate memory for string
  985. X         * for arg_parse_argv: in case argv gets clobbered (rare)
  986. X         * for arg_parse_stream: since line[] buffer is reused (always)
  987. X         */
  988. X        ALLOC(s, char, strlen(arg[i])+1);
  989. X        strcpy(s, arg[i]);
  990. X        *(char **)*p = s;
  991. X        break;
  992. X        case 's':           /* scanf "%s" strips leading, trailing blanks */
  993. X        strcpy(*p, arg[i]);
  994. X        break;
  995. X        case 'd':
  996. X        *(int *)*p = expr_eval_int(arg[i]);
  997. X        if (expr_error==EXPR_BAD) {    /* expression is garbage */
  998. X            fprintf(stderr, "bad %s param\n", f->flag);
  999. X            return ARG_BADARG;
  1000. X        }
  1001. X        break;
  1002. X        case 'D':
  1003. X        *(long *)*p = expr_eval_long(arg[i]);
  1004. X        if (expr_error==EXPR_BAD) {    /* expression is garbage */
  1005. X            fprintf(stderr, "bad %s param\n", f->flag);
  1006. X            return ARG_BADARG;
  1007. X        }
  1008. X        break;
  1009. X        case 'f': case 'F':
  1010. X        x = expr_eval(arg[i]);
  1011. X        if (expr_error==EXPR_BAD) {    /* expression is garbage */
  1012. X            fprintf(stderr, "bad %s param\n", f->flag);
  1013. X            return ARG_BADARG;
  1014. X        }
  1015. X        if (str[1]=='f') *(float *)*p = x;
  1016. X        else        *(double *)*p = x;
  1017. X        break;
  1018. X        default:
  1019. X        if (sscanf(arg[i], str, *p) != 1) {
  1020. X            fprintf(stderr, "bad %s param: \"%s\" doesn't match %s\n",
  1021. X            f->flag, arg[i], str);
  1022. X            return ARG_BADARG;
  1023. X        }
  1024. X        break;
  1025. X    }
  1026. X    }
  1027. X    return 0;                   /* return 0 on success */
  1028. X}
  1029. X
  1030. Xstatic char *bar = "==================================================\n";
  1031. X
  1032. X/* arg_form_print: print Arg_form as usage message to stderr */
  1033. X
  1034. Xstatic arg_form_print(form)
  1035. XArg_form *form;
  1036. X{
  1037. X    Arg_form *f;
  1038. X
  1039. X    for (f=form; f; f=f->next) {
  1040. X    if (f->type!=ARG_NOP || f->format[0]) {
  1041. X        fprintf(stderr, "%s", f->format);
  1042. X        space(stderr, strlen(f->format), arg_doccol);
  1043. X    }
  1044. X    fprintf(stderr, "%s\n", f->doc);
  1045. X    if (arg_debug)
  1046. X        fprintf(stderr, "   %d (%s) [%s][%s]%x (%s)\n",
  1047. X        f->type, f->format, f->flag, f->code, f->parammask, f->doc);
  1048. X    if (f->type==ARG_SUBLISTFLAG) {
  1049. X        fprintf(stderr, bar);
  1050. X        arg_form_print(f->sublist);
  1051. X        fprintf(stderr, bar);
  1052. X    }
  1053. X    }
  1054. X}
  1055. X
  1056. X/*
  1057. X * space: currently in column c; tab and space over to column c1
  1058. X * assumes 8-space tabs
  1059. X */
  1060. X
  1061. Xstatic space(fp, c, c1)
  1062. XFILE *fp;
  1063. Xint c, c1;
  1064. X{
  1065. X    if (c>=c1) {
  1066. X    putc('\n', fp);
  1067. X    c = 0;
  1068. X    }
  1069. X    for (; c<c1&~7; c=(c+7)&~7) putc('\t', fp);
  1070. X    for (; c<c1; c++) putc(' ', fp);
  1071. X}
  1072. X
  1073. Xav_print(str, ac, av)
  1074. Xint ac;
  1075. Xchar *str, **av;
  1076. X{
  1077. X    int i;
  1078. X
  1079. X    fprintf(stderr, "%s: ", str);
  1080. X    for (i=0; i<ac; i++)
  1081. X    fprintf(stderr, "%s ", av[i]);
  1082. X    fprintf(stderr, "\n");
  1083. X}
  1084. END_OF_FILE
  1085.   if test 21871 -ne `wc -c <'libarg/arg.c'`; then
  1086.     echo shar: \"'libarg/arg.c'\" unpacked with wrong size!
  1087.   fi
  1088.   # end of 'libarg/arg.c'
  1089. fi
  1090. if test -f 'libarg/arg.h' -a "${1}" != "-c" ; then 
  1091.   echo shar: Will not clobber existing file \"'libarg/arg.h'\"
  1092. else
  1093.   echo shar: Extracting \"'libarg/arg.h'\" \(2790 characters\)
  1094.   sed "s/^X//" >'libarg/arg.h' <<'END_OF_FILE'
  1095. X/* arg.h: definitions for argument parsing package */
  1096. X
  1097. X#ifndef ARG_HDR
  1098. X#define ARG_HDR
  1099. X
  1100. X/* $Header: /gourd/usr2/ph/sys/libsys/RCS/arg.h,v 4.2 94/08/03 15:41:11 ph Exp Locker: ph $ */
  1101. X
  1102. X#include <stdio.h>
  1103. X#include <expr.h>
  1104. X
  1105. Xtypedef struct arg_form {    /* ARGUMENT FORM */
  1106. X
  1107. X    /* a "form" contains the format, doc string, and miscellaneous internal */
  1108. X    /* info about an argument.  It's an argument descriptor, basically */
  1109. X
  1110. X    struct arg_form *next;    /* next in linked list */
  1111. X    char *format;        /* scanf-style format:    "-size %d %F" */
  1112. X    char *flag;            /* flag portion of format:"-size" */
  1113. X    char *code;            /* just the format codes: "dF" */
  1114. X    char *doc;            /* documentation string:  "set widget size" */
  1115. X    short type;            /* REGULAR | SIMPFLAG | PARAMFLAG |
  1116. X                    SUBRFLAG | SUBLISTFLAG | NOP */
  1117. X    short nparam;        /* number of parameters to flag */
  1118. X    int parammask;        /* bit i says ok to stop before param i, i=0..*/
  1119. X    int **param;         /* parameter pointer list */
  1120. X    int (*subr)();        /* subroutine to call for action (if any) */
  1121. X    struct arg_form *sublist;    /* subordinate list (if any) */
  1122. X    short rep;            /* # times this flag repeated in arglist */
  1123. X} Arg_form;
  1124. X
  1125. X/* form type values */
  1126. X#define ARG_REGULAR    1    /* a regular argument */
  1127. X#define ARG_SIMPFLAG    2    /* a simple flag (no parameters) */
  1128. X#define ARG_PARAMFLAG    3    /* a flag with parameters */
  1129. X#define ARG_SUBRFLAG    4    /* a flag with subroutine action */
  1130. X#define ARG_SUBLISTFLAG    5    /* a sub-formlist */
  1131. X#define ARG_NOP        6    /* no arg or flag, just a doc string */
  1132. X
  1133. X/* the following must be impossible pointer values (note: machine-dependent) */
  1134. X#define ARG_MASKNEXT    0x80000000    /* mask for these NEXT flags */
  1135. X#define ARG_FLAGNEXT    0x80000001
  1136. X#define ARG_SUBRNEXT    0x80000002
  1137. X#define ARG_LISTNEXT    0x80000003
  1138. X
  1139. X/* varargs tricks */
  1140. X#define ARG_FLAG(ptr)        ARG_FLAGNEXT, (ptr)    /* for SIMPFLAG */
  1141. X#define ARG_SUBR(ptr)        ARG_SUBRNEXT, (ptr)    /* for SUBRFLAG */
  1142. X#define ARG_SUBLIST(ptr)    ARG_LISTNEXT, (ptr)    /* for SUBLISTFLAG */
  1143. X
  1144. X/* error codes: BADCALL is a programmer error, the others are user errors */
  1145. X#define ARG_BADCALL    -1    /* arg_parse call itself is bad */
  1146. X#define ARG_BADARG    -2    /* bad argument given */
  1147. X#define ARG_MISSING    -3    /* argument or parameter missing */
  1148. X#define ARG_EXTRA    -4    /* extra argument given */
  1149. X
  1150. X#define ARG_NARGMAX 10000    /* max number of allowed args */
  1151. X
  1152. Xextern int arg_debug, arg_doccol;
  1153. Xextern int arg_warning;        /* print warnings about repeated flags? */
  1154. XArg_form *arg_to_form1(), *arg_find_flag(), *arg_find_reg();
  1155. X
  1156. X#ifdef __cplusplus
  1157. X    extern "C" {
  1158. X    int arg_parse(int ac, char **av ...);
  1159. X    int arg_parse_argv(int ac, char **av, Arg_form *form);
  1160. X    int arg_parse_stream(FILE *fp, Arg_form *form);
  1161. X    Arg_form *arg_to_form(...);
  1162. X    int arg_form_print(Arg_form *form);
  1163. X    }
  1164. X#else
  1165. X    Arg_form *arg_to_form();
  1166. X#endif
  1167. X
  1168. X#endif
  1169. END_OF_FILE
  1170.   if test 2790 -ne `wc -c <'libarg/arg.h'`; then
  1171.     echo shar: \"'libarg/arg.h'\" unpacked with wrong size!
  1172.   fi
  1173.   # end of 'libarg/arg.h'
  1174. fi
  1175. if test -f 'libarg/arg_parse.3' -a "${1}" != "-c" ; then 
  1176.   echo shar: Will not clobber existing file \"'libarg/arg_parse.3'\"
  1177. else
  1178.   echo shar: Extracting \"'libarg/arg_parse.3'\" \(21195 characters\)
  1179.   sed "s/^X//" >'libarg/arg_parse.3' <<'END_OF_FILE'
  1180. X.\" arg_parse.3: to format, run through tbl and troff -man
  1181. X.\" $Header: /gourd/usr2/ph/sys/libsys/RCS/arg_parse.3,v 4.2 94/08/03 21:20:58 ph Exp Locker: ph $
  1182. X.\" a few macros
  1183. X.de Cs        \" code start
  1184. X.DS
  1185. X.ps 9
  1186. X.vs 11p
  1187. X.ft C
  1188. X.ta 9n,+9n,+9n,+9n,+9n,+9n,+9n,+9n,+9n,+9n,+9n,+9n,+9n
  1189. X..
  1190. X.de Ce        \" code end
  1191. X.ft R
  1192. X.ps 10
  1193. X.vs 12p
  1194. X.DE
  1195. X.fi
  1196. X..
  1197. X.de DS
  1198. X.nf
  1199. X.in +4n
  1200. X.sp .5v
  1201. X..
  1202. X.de DE
  1203. X.sp .5v
  1204. X.in -4n
  1205. X.fi
  1206. X..
  1207. X.TH ARG_PARSE 3  "23 April 1988"
  1208. X.po 1i
  1209. X.SH NAME
  1210. Xarg_parse \- parse arguments to a command
  1211. X.SH SYNOPSIS
  1212. X.nf
  1213. X#include <arg.h>
  1214. X\fBarg_parse\fP(argc, argv, [formatstr, paramptrs, docstr, docparams]*, 0)
  1215. Xint argc;
  1216. Xchar **argv, *formatstr, *docstr;
  1217. X
  1218. Xdouble \fBexpr_eval\fP(str)
  1219. Xchar *str;
  1220. X.fi
  1221. X.SH DESCRIPTION
  1222. X\fIarg_parse\fP is a subroutine for parsing
  1223. Xand conversion of command-line arguments.
  1224. XThis parser is an alternative to the common method of
  1225. Xargument parsing, which is an ad-hoc parser in each program, typically written
  1226. Xwith a large, cumbersome switch statement.
  1227. X\fIarg_parse\fP allows a command-line parser to be described very
  1228. Xconcisely while retaining the flexibility to handle
  1229. Xa variety of syntaxes.
  1230. X.PP
  1231. XThe parser has a number of features:
  1232. X.DS
  1233. X\(bu arbitrary order of flag arguments
  1234. X\(bu automatic argument conversion and type checking
  1235. X\(bu multiple-character flag names
  1236. X\(bu required, optional, and flag arguments
  1237. X\(bu automatic usage message
  1238. X\(bu subroutine call for exotic options (variable number of parameters)
  1239. X\(bu modularized parsers encourage standardized options
  1240. X\(bu expression evaluation
  1241. X\(bu works either from argv or in interactive mode, \
  1242. Xas a primitive language parser and interpreter
  1243. X\(bu concise specification
  1244. X\(bu easy to use
  1245. X.DE
  1246. XIt is hoped that use of \fIarg_parse\fP will help standardize argument
  1247. Xconventions and reduce the tedium of adding options to programs.
  1248. X.SH APPETIZER
  1249. XHere is a simple example:
  1250. X
  1251. X.Cs
  1252. X#include <arg.h>
  1253. X
  1254. Xmain(argc, argv)
  1255. Xint argc;
  1256. Xchar **argv;
  1257. X{
  1258. X    char *file;
  1259. X    int level = 3, debug;
  1260. X    double xsize = 20., ysize = 10.;
  1261. X
  1262. X    arg_parse(argc, argv,
  1263. X    "", "Usage: prog [options]",
  1264. X    "%S", &file, "set output file",
  1265. X    "[%d]", &level, "set recursion level [default=%d]", level,
  1266. X    "-size %F %F", &xsize, &ysize, "set x and y sizes",
  1267. X    "-debug", ARG_FLAG(&debug), "turn on debugging",
  1268. X    0);
  1269. X.Ce
  1270. X
  1271. XThe \fIarg_parse\fP call defines the program's arguments,
  1272. Xin this case:
  1273. Xone required argument (a filename), an optional argument
  1274. X(an integer level number),
  1275. Xan optional flag with two parameters (floating point size),
  1276. Xand a simple flag (boolean debug flag).
  1277. XIf the above program (call it \fIprog\fP) were run with
  1278. X.Cs
  1279. Xprog joe.c
  1280. X.Ce
  1281. Xit would set \fIfile\fP to joe.c, and set \fIdebug\fP to 0,
  1282. Xand if run with
  1283. X.Cs
  1284. Xprog -size 100 400/3 joe.c -debug 5
  1285. X.Ce
  1286. Xit would set \fIfile\fP="joe.c", \fIlevel\fP=5, \fIxsize\fP=100,
  1287. X\fIysize\fP=133.33, and \fIdebug\fP=1.
  1288. XIn all programs using \fIarg_parse\fP,
  1289. Xa hyphen arguments elicits a usage message,
  1290. Xso the command
  1291. X.Cs
  1292. Xprog -
  1293. X.Ce
  1294. Xresults in the printout
  1295. X.Cs
  1296. XUsage: prog [options]
  1297. X%S        set output file
  1298. X[%d]        set recursion level [default=3]
  1299. X-size %F %F    set x and y sizes
  1300. X-debug        turn on debugging
  1301. X.Ce
  1302. X.SH TERMINOLOGY
  1303. XIn order to speak precisely about the description and use of argument
  1304. Xparsers, it helps to define some terminology.
  1305. X
  1306. X.TS
  1307. Xcenter,box;
  1308. Xlt lt lw(2.5i).
  1309. XTERM    EXAMPLES    MEANING
  1310. X=
  1311. X\fBargument\fP    -size    T{
  1312. XAny of the strings in argv, supplied by the user.
  1313. XT}
  1314. X    joe.c
  1315. X_
  1316. X\fBflag arg\fP    -size    T{
  1317. XThe name of an option.
  1318. XT}
  1319. X_
  1320. X\fBparameter arg\fP    100    T{
  1321. XA value (numerical or otherwise) for an option.
  1322. XT}
  1323. X_
  1324. X\fBsimple flag\fP    -debug    T{
  1325. XA flag with no parameters that sets a boolean variable.
  1326. XT}
  1327. X_
  1328. X\fBregular arg\fP    joe.c    T{
  1329. XAn argument that is not a flag or a parameter to a flag.
  1330. XCan be either a required or optional argument.
  1331. XT}
  1332. X=
  1333. X\fBformat string\fP    "-size %F%F"    T{
  1334. XThe character string describing the syntax of an option.
  1335. XT}
  1336. X_
  1337. X\fBparameter ptr\fP    &xsize    T{
  1338. XPointer to a parameter variable through which converted values are stored.
  1339. XT}
  1340. X_
  1341. X\fBdoc string\fP    "set output file"    T{
  1342. XDocumentation string describing the option's effect.
  1343. XT}
  1344. X_
  1345. X\fBform\fP    "-res%d", &r, "set res"    T{
  1346. XFormat string, parameter pointers, and documentation describing
  1347. Xan option.
  1348. XT}
  1349. X    "[%d]", &level, "set level"
  1350. X.TE
  1351. X
  1352. XWe will describe the syntax of formlists first,
  1353. Xthen the method for matching arguments to forms.
  1354. X.SH FORMLIST SYNTAX
  1355. XThe syntax and conversion rules for parsing are specified in
  1356. Xthe \fBformlist\fP following \fIargc\fP and \fIargv\fP in the
  1357. X\fIarg_parse\fP call.
  1358. X\fIarg_parse\fP reads its subroutine parameters using
  1359. Xthe \fIvarargs(3)\fP convention for run-time procedure calls,
  1360. Xso it is crucial that the formlist be terminated with a 0.
  1361. XEach form consists of a \fIscanf\fP-style format string,
  1362. Xa list of parameter pointers, a documentation string, and a list of
  1363. Xdocumentation parameters.
  1364. XIn some cases the paramptr and docparam lists will be empty,
  1365. Xbut the format string and doc string arguments are mandatory.
  1366. X.PP
  1367. X.B Format String
  1368. X.PP
  1369. XThe format string consists of a flag string
  1370. Xfollowed by parameter conversion codes (if any).
  1371. XA flag is a hyphen followed by a string.
  1372. XNone of the characters in the string may be a '%'
  1373. Xand the string must not begin with a numeral.
  1374. XAcceptable conversion codes in the format string are a '%' followed
  1375. Xby any single character codes accepted by \fIscanf\fP plus the new
  1376. Xconversion 'S':
  1377. X.DS
  1378. X.TS
  1379. Xl l.
  1380. XCODE    TYPE
  1381. X%c    char
  1382. X%d    int
  1383. X%f    float
  1384. X%F    double
  1385. X%s    char array
  1386. X%S    char *
  1387. X\&...    (see \fIscanf(3)\fP for a complete list)
  1388. X.TE
  1389. X.DE
  1390. XThe %S conversion is like %s except it copies only a pointer to a string
  1391. X(a \fCchar *\fP), not a whole string.
  1392. XWhen using %s, space must be allocated for the copied string,
  1393. Xbut with %S only room for a pointer is needed.
  1394. XAn example of %S use is given later.
  1395. XA format string with no flag but only conversion codes describes
  1396. Xa \fBregular argument\fP,
  1397. Xwhile a flag followed by conversion codes defines a
  1398. X\fBflag with arguments\fP.
  1399. XBrackets around conversion codes indicate that they are optional,
  1400. Xfor example:
  1401. X.DS
  1402. X.TS
  1403. Xl l.
  1404. X"%S %d"    two required args
  1405. X"%d [%F]"    first arg required, second arg optional
  1406. X"-pt [%F%F%F[%F]]"    a flag with 0, 3, or 4 parameters
  1407. X.TE
  1408. X.DE
  1409. XSince assignments of args to parameter pointers are done left-right
  1410. Xwithin the form, no conversion codes can follow the first ']'.
  1411. XIn fact, the ]'s are optional since they can be inferred to
  1412. Xbe at the end of the format string.
  1413. XSpaces between conversion codes are optional and ignored.
  1414. X.PP
  1415. XFollowing the format string is the list of parameter pointers,
  1416. Xwhose number must match the number of conversion codes in
  1417. Xthe format string, like the arguments to \fIscanf\fP or
  1418. X\fIprintf\fP.
  1419. X.PP
  1420. X.B Form Types
  1421. X.PP
  1422. XThere are six form types.
  1423. XIn addition to the ones we've seen, regular arguments and
  1424. Xflags with parameters, there are several others for more exotic circumstances:
  1425. Xsimple flags, nop forms, subroutine flags, and sublists.
  1426. X.PP
  1427. XA \fBsimple flag\fP is a flag option with no parameters that sets a
  1428. Xboolean variable to 1 if that flag appears in \fIargv\fP, else 0.
  1429. XA pointer to the boolean (int) variable is passed after the
  1430. Xformat string using the \fCARG_FLAG\fP macro.
  1431. XFor example, \fCARG_FLAG(&debug)\fP
  1432. Xwill set the boolean variable \fCdebug\fP.
  1433. X.PP
  1434. XA \fBnop form\fP is a documentation string with no associated flags or
  1435. Xarguments that appears in the usage message but does not affect parsing.
  1436. XNop forms have a format string and a doc string, the former containing
  1437. Xneither a flag nor a conversion code.
  1438. XExample:
  1439. X.Cs
  1440. X"", "This program converts an AIS picture file to PF format",
  1441. X.Ce
  1442. XWhen the usage message is printed,
  1443. Xthe doc string is indented if the format string is non-null.
  1444. X.PP
  1445. XA \fBsubroutine flag\fP is an option that calls a user-supplied
  1446. X\fIaction subroutine\fP every time it is used
  1447. Xrather than using \fIarg_parse\fP's
  1448. Xformat conversion and parameter assignment.
  1449. XSubroutine flags are used just like flags with parameters
  1450. Xin \fIargv\fP, but they are specified and implemented differently internally.
  1451. XFor example, say our program \fIprog\fP needs a variable length
  1452. Xlist of people.
  1453. XWe could add a flag with arguments to handle a few names using the form:
  1454. X.Cs
  1455. Xchar *p1, *p2, *p3, *p4;
  1456. X\&...
  1457. X"-people %S[%S[%S[%S]]]]", &p1, &p2, &p3, &p4, "people names"
  1458. X.Ce
  1459. Xbut this limits the number of possible parameters to four.
  1460. XSubroutine flags provide a trapdoor whereby the programmer can do
  1461. Xcustom conversion or processing of parameters with arbitrary type and number.
  1462. XTo parse our list of people with a subroutine flag instead,
  1463. Xwe use the form:
  1464. X.Cs
  1465. X"-people", ARG_SUBR(arg_people), "people names"
  1466. X.Ce
  1467. Xwhere \fCarg_people\fP is a subroutine to gobble the parameters,
  1468. Xjust like in the example near the end of this document.
  1469. X.PP
  1470. XThe macro \fCARG_SUBR\fP takes the name of a subroutine to call
  1471. Xwhen the flag is encountered.
  1472. XThe parameter arguments following the flag in \fIargv\fP are
  1473. Xpackaged into a new argument vector \fIav\fP along with \fIac\fP,
  1474. Xand the subroutine is called with these two arguments.
  1475. XIn our list-of-people example, the command
  1476. X\fCprog foo -people ned alvy bruce -debug\fP would call \fCarg_people\fP
  1477. Xwith \fIac\fP=3 and \fIav\fP={"ned","alvy","bruce"}.
  1478. X.PP
  1479. XWhereas flags with arguments had the simple side effect of setting
  1480. Xa variable, subroutine flags can have arbitrarily complex
  1481. Xside effects, and can be used multiple times.
  1482. XSubroutine flags can also be flagless;
  1483. Xthat is, they can have null format strings.
  1484. XIn this case, any ``leftover'' regular arguments are passed to the
  1485. Xsupplied action subroutine.
  1486. XFlagless subroutines are useful for reading lists of filenames.
  1487. X.PP
  1488. XThe final form type is a \fBsublist\fP.
  1489. XA sublist is a subordinate parser defined as another formlist.
  1490. XSublists can be used to build a tree of parsers,
  1491. Xfor example a 3-D graphics program might have a standard set of commands
  1492. Xfor controlling the display (setting the output device, screen window,
  1493. Xand colors) and also a standard set of commands for transforming 3-D objects
  1494. X(rotation, scaling, etc.).
  1495. XWithin the display command parser there could well be a standard set of
  1496. Xcommands for each output device (one for Suns, another for Versatec plotters,
  1497. Xetc.).
  1498. XUsing sublists we can prepare a standard parser for display commands
  1499. Xand keep it in the source for the display library,
  1500. Xa parser for the transformation commands in the transformation library,
  1501. Xand so on, so that the parser for each graphics application
  1502. Xcan be very simple, merely listing its own options and then
  1503. Xinvoking the standard parsers for the major libraries it uses to
  1504. Xhandle the bulk of the options.
  1505. XModularizing parsers in this way reduces the redundancy of parsing
  1506. Xcode between similar commands and encourages standardization of options
  1507. Xbetween programs, reducing maintenance work for programmers
  1508. Xand reducing option confusion among users.
  1509. X.PP
  1510. XTo invoke a sublist we use the form:
  1511. X.Cs
  1512. X"-display", ARG_SUBLIST(form), "display commands"
  1513. X.Ce
  1514. XThe \fCARG_SUBLIST\fP macro expects a structure pointer of type
  1515. X\fCArg_form *\fP as returned from the \fCarg_to_form\fP routine.
  1516. XIts use is illustrated in an example later.
  1517. X.SH MATCHING ARGUMENTS TO FORMS
  1518. X\fIarg_parse\fP steps through the arguments in \fIargv\fP from left
  1519. Xto right, matching arguments against the format strings in the formlist.
  1520. XFlag arguments (simple flags or flags with parameters)
  1521. Xcan occur in arbitrary order but regular arguments are matched by
  1522. Xstepping through the formlist in left to right order.
  1523. XFor this reason regular arguments are also known as positional arguments.
  1524. XMatching of parameters within an option is also done in a left-to-right,
  1525. Xgreedy fashion within the form without regard for the parameter types.
  1526. XNo permutation of the matching is done to avoid conversion errors.
  1527. XTo illustrate, in our \fIprog\fP above, if we changed the size option
  1528. Xto make the second parameter optional:
  1529. X.Cs
  1530. X"-size %F[%F]", &xsize, &ysize, "set sizes",
  1531. X.Ce
  1532. Xthen the command:
  1533. X.Cs
  1534. Xprog -size 100 -debug joe.c
  1535. X.Ce
  1536. Xsucceeds because it is clear that only one parameter is being supplied to size,
  1537. Xbut if we try:
  1538. X.Cs
  1539. Xprog -size 100 joe.c -debug
  1540. X.Ce
  1541. Xthen \fIarg_parse\fP will attempt to convert \fC"joe.c"\fP via \fC%F\fP into
  1542. X\fIysize\fP and fail, returning an error code.
  1543. X.PP
  1544. XThe matching algorithm for subroutine flags and sublists varies somewhat
  1545. Xfrom that for the other form types.
  1546. XFor most types,
  1547. X\fIarg_parse\fP grabs as many arguments out of \fIargv\fP as the form can
  1548. Xtake up to the next flag argument (or the end of \fIargv\fP),
  1549. Xbut for subroutine flags and sublists,
  1550. Xall arguments up to the next flag argument
  1551. Xare grabbed and bundled into a smaller argument vector (call it \fIav\fP).
  1552. X(For matching purposes, a flag argument is an argument that begins with
  1553. Xa hyphen followed by any character except digits and '.'.)
  1554. XThe new argument vector is passed to the action routine in the case of
  1555. Xsubroutine flags or recursively to a sub-parser in the case of sublist flags.
  1556. X.PP
  1557. XThe sub-parser invoked by a sublist flag does matching identically.
  1558. XNormally the entire formlist tree is traversed depth-first whenever a search
  1559. Xfor a flag is being made.
  1560. XIf there are no flag duplicates between different levels of the form tree
  1561. Xthen the structure of the tree is irrelevant;
  1562. Xthe user needn't be conscious of the command grouping or of
  1563. Xthe sublist names.
  1564. XBut if there are name duplicates, for example if there were a \fC-window\fP
  1565. Xoption in both the display and transformation parsers,
  1566. Xthen explicit control of search order within the tree is needed.
  1567. XThis disambiguation problem is analogous to pathname specification
  1568. Xof files within a UNIX directory tree.
  1569. XWhen explicit sublist selection is needed it is done using the sublist
  1570. Xflag followed by the arguments for the sub-parser, bracketed with
  1571. X\fC-{\fP and \fC-}\fP flags.
  1572. XFor example, if there were more than one \fCwindow\fP option,
  1573. Xto explicitly select the one in the display parser,
  1574. Xwe type:
  1575. X.Cs
  1576. X-display -{ -window 0 0 639 479 -}
  1577. X.Ce
  1578. XThe brace flags group and quote the arguments so that all of
  1579. Xthe enclosed arguments will be passed to the sub-parser.
  1580. XWithout them the argument matcher would think that \fCdisplay\fP has no
  1581. Xparameters, since it is immediately followed by a flag (\fC-window\fP).
  1582. XNote that in \fIcsh\fP, the braces must be escaped as
  1583. X\fC-\e{\fP and \fC-\e}\fP.
  1584. X.PP
  1585. X[If you can think of a better way to do matching please tell me!  -Paul].
  1586. X.PP
  1587. XThe matching is checked in both directions:
  1588. Xin the formlist, all required arguments must be assigned to and
  1589. Xmost flags can be called at most once,
  1590. Xand in \fIargv\fP, each argument must be recognized.
  1591. XRegular arguments are \fBrequired\fP if they are unbracketed,
  1592. Xand \fBoptional\fP if they are bracketed.
  1593. XUnmatched forms for required arguments
  1594. Xcause an error but unmatched forms for optional
  1595. Xor flag arguments do not; they are skipped.
  1596. XA warning message is printed if a simple flag or flag with parameters
  1597. Xappears more than once in \fIargv\fP.
  1598. XNote that it is not an error for subroutine flags to appear more than once,
  1599. Xso they should be used when repeats of a flag are allowed.
  1600. XUnmatched arguments in \fIargv\fP cause an ``extra argument'' error.
  1601. X.PP
  1602. XA hyphen argument in \fIargv\fP causes \fIarg_parse\fP to print a
  1603. Xusage message constructed from the format and documentation strings,
  1604. Xand return an error code.
  1605. X.SH EXPRESSIONS
  1606. X\fIarg_parse\fP does expression evaluation when converting numerical parameters.
  1607. XThe expression evaluator allows the following operations:
  1608. X+, -, *, /, % (mod), ^ (exponentiation),
  1609. Xunary -, unary +,
  1610. X\fIsqrt\fP,
  1611. X\fIexp\fP,
  1612. X\fIlog\fP,
  1613. X\fIpow\fP,
  1614. X\fIsin\fP,
  1615. X\fIcos\fP,
  1616. X\fItan\fP,
  1617. X\fIasin\fP,
  1618. X\fIacos\fP,
  1619. X\fIatan\fP,
  1620. X\fIatan2\fP (takes 2 args),
  1621. X\fIsind\fP,
  1622. X\fIcosd\fP,
  1623. X\fItand\fP,
  1624. X\fIdasin\fP,
  1625. X\fIdacos\fP,
  1626. X\fIdatan\fP,
  1627. X\fIdatan2\fP (takes 2 args),
  1628. X\fIfloor\fP,
  1629. Xand
  1630. X\fIceil\fP.
  1631. XIt also knows the two constants
  1632. X\fIpi\fP and
  1633. X\fIe\fP.
  1634. XNumerical constants can be integer or scientific notation,
  1635. Xin decimal, octal, hexidecimal, or other base.
  1636. XFor example, 10 = 012 (base 8) = 0xa (base 16) = 0b2:1010 (base 2).
  1637. XThe normal trig functions work in radians, while the versions that begin
  1638. Xor end in the letter 'd' work in degrees.
  1639. XThus, \fC"exp(-.5*2^2)/sqrt(2*pi)"\fP is a legal expression.
  1640. XAll expressions are computed in double-precision floating point.
  1641. XNote that it is often necessary to quote expressions so the shell
  1642. Xwon't get excited about asterisks and parentheses.
  1643. XThe expression evaluator \fIexpr_eval\fP
  1644. Xcan be used independently of \fIarg_parse\fP.
  1645. X.SH INTERACTIVE MODE
  1646. XIf the lone argument \fC-stdin\fP is passed in \fIargv\fP then
  1647. X\fIarg_parse\fP goes into interactive mode.
  1648. XInteractive mode reads its arguments from standard input rather than
  1649. Xgetting them from the argument vector.
  1650. XThis allows programs to be run semi-interactively.
  1651. XTo encourage interactive use of a program, one or more of the options
  1652. Xshould be a subroutine flag.
  1653. XOne could have a \fC-go\fP flag, say, that causes computation to commence.
  1654. XIn interactive mode the hyphens on flags are optional at the beginning
  1655. Xof each line, so the input syntax resembles a programming language.
  1656. XIn fact, scripts of such commands are often saved in files.
  1657. X.SH EXAMPLE
  1658. XThe following example illustrates most of the features of \fIarg_parse\fP.
  1659. X.Cs
  1660. X/* tb.c - arg_parse test program */
  1661. X#include <stdio.h>
  1662. Xdouble atof();
  1663. X
  1664. X#include <arg.h>
  1665. Xstatic double dxs = 1., dys = .75;
  1666. Xstatic int x1 = 0, y1 = 0, x2 = 99, y2 = 99;
  1667. Xstatic char *chanlist = "rgba";
  1668. Xint arg_people(), arg_dsize();
  1669. XArg_form *fb_init();
  1670. X
  1671. Xmain(ac, av)
  1672. Xint ac;
  1673. Xchar **av;
  1674. X{
  1675. X    int fast, xs = 512, ys = 486;
  1676. X    double scale = 1.;
  1677. X    char *fromfile, tofile[80], *child = "jim";
  1678. X    Arg_form *arg_fb;
  1679. X
  1680. X    arg_fb = fb_init();
  1681. X    if (arg_parse(ac, av,
  1682. X    "", "Usage: %s [options]", av[0],
  1683. X    "", "This program does nothing but test arg_parse",
  1684. X    "%S %s", &fromfile, tofile, "fromfile and tofile",
  1685. X    "[%F]", &scale, "set scale [default=%g]", scale,
  1686. X    "", ARG_SUBR(arg_people), "names of people",
  1687. X    "-fast", ARG_FLAG(&fast), "do it faster",
  1688. X    "-ch %S", &child, "set child name",
  1689. X    "-srcsize %d[%d]", &xs, &ys, "set source size [default=%d,%d]", xs, ys,
  1690. X    "-dstsize", ARG_SUBR(arg_dsize), "set dest size",
  1691. X    "-fb", ARG_SUBLIST(arg_fb), "FB COMMANDS",
  1692. X    0) < 0)
  1693. X    exit(1);
  1694. X
  1695. X    printf("from=%s to=%s scale=%g fast=%d child=%s src=%dx%d dst=%gx%g\en",
  1696. X    fromfile, tofile, scale, fast, child, xs, ys, dxs, dys);
  1697. X    printf("window={%d,%d,%d,%d} chan=%s\en", x1, y1, x2, y2, chanlist);
  1698. X}
  1699. X
  1700. Xstatic arg_people(ac, av)
  1701. Xint ac;
  1702. Xchar **av;
  1703. X{
  1704. X    int i;
  1705. X
  1706. X    for (i=0; i<ac; i++)
  1707. X    printf("person[%d]=%s\en", i, av[i]);
  1708. X}
  1709. X
  1710. Xstatic arg_dsize(ac, av)
  1711. Xint ac;
  1712. Xchar **av;
  1713. X{
  1714. X    if (ac<1 || ac>3) {
  1715. X    fprintf(stderr, "-dsize wants 1 or 2 args\en");
  1716. X    exit(1);
  1717. X    }
  1718. X    /* illustrate two methods for argument conversion */
  1719. X    dxs = atof(av[0]);            /* constant conversion */
  1720. X    if (ac>1) dys = expr_eval(av[1]);    /* expression conversion */
  1721. X    else      dys = .75*dxs;
  1722. X}
  1723. X
  1724. XArg_form *fb_init()
  1725. X{
  1726. X    return arg_to_form(
  1727. X    "-w%d%d%d%d", &x1, &y1, &x2, &y2, "set screen window",
  1728. X    "-ch%S", &chanlist, "set channels [default=%s]", chanlist,
  1729. X    0);
  1730. X}
  1731. X.Ce
  1732. XIn this example we have two required arguments, one optional argument,
  1733. Xand a flagless subroutine (arg_people) to gobble the remaining regular
  1734. Xarguments.
  1735. XThe two required arguments illustrate the differences between \fC%S\fP
  1736. Xand \fC%s\fP, and the advantages of the former.
  1737. XThe \fC-srcsize\fP and \fC-dstsize\fP forms illustrate two different
  1738. Xways to get a flag with either one or two parameters.
  1739. XNote in the \fIarg_dsize\fP routine
  1740. Xthat the expression evaluator \fIexpr_eval\fP is just
  1741. Xas easy to use as \fIatof\fP.
  1742. XA small sublist shows an example of command name ambiguity in
  1743. Xthe flag \fC-ch\fP.
  1744. X.PP
  1745. XBelow are the results of several sample runs.
  1746. X.Cs
  1747. X\(bu tb one two
  1748. X    from=one to=two scale=1 fast=0 child=jim src=512x486 dst=1x0.75
  1749. X    window={0,0,99,99} chan=rgba
  1750. X.fi
  1751. X\fIOnly the two required args are specified here and everything
  1752. Xelse defaults.\fP
  1753. X.nf
  1754. X
  1755. X\(bu tb -fast -srcsize 100 1+2 one two -dstsize 2 -ch amy -w 1 2 3 4 "sqrt(2)"
  1756. X    from=one to=two scale=1.41421 fast=1 child=amy src=100x3 dst=2x1.5
  1757. X    window={1,2,3,4} chan=rgba
  1758. X.fi
  1759. X\fIThis illustrates expression evaluation, the precedence of the first\fP
  1760. X-ch \fIflag over the one in the sublist, and easy access to a non-ambiguous
  1761. Xsublist option, \fP-w.
  1762. X.nf
  1763. X
  1764. X\(bu tb -fb -\e{ -ch abc -w 9 8 7 6 -\e} -ch -\e{ -jo -\e} A B 44 larry curly moe
  1765. X    person[0]=larry
  1766. X    person[1]=curly
  1767. X    person[2]=moe
  1768. X    from=A to=B scale=44 fast=0 child=-jo src=512x486 dst=1x0.75
  1769. X    window={9,8,7,6} chan=abc
  1770. X.fi
  1771. X\fIThis shows access to a ``shadowed'' sublist option, \fP-ch\fI, and
  1772. Xescaping a parameter string that happens to begin with a hyphen, \fP-jo\fI,
  1773. Xwith braces, plus the use of a flagless subroutine to pick up extra
  1774. Xregular arguments.\fP
  1775. X.nf
  1776. X.Ce
  1777. X.SH RETURN VALUE
  1778. X\fIarg_parse\fP returns a negative code on error, otherwise 0.
  1779. XThe file \fIarg.h\fP contains definitions for the error codes:
  1780. X.DS
  1781. X.TS
  1782. Xl l.
  1783. XARG_BADCALL    programmer error, bad formlist
  1784. XARG_BADARG    bad argument in \fIargv\fP
  1785. XARG_MISSING    required argument or parameter to flag missing
  1786. XARG_EXTRA    \fIargv\fP contains an extra, unrecognizable argument
  1787. X.TE
  1788. X.DE
  1789. X.SH NOTE
  1790. X\fIarg_parse\fP modifies \fIargv\fP as a side-effect to eliminate
  1791. Xthe \fC-{\fP and \fC-}\fP arguments.
  1792. X.SH COMPILING
  1793. XIf \fIarg_parse\fP is installed in \fIlibarg.a\fP,
  1794. Xcompile with \fCcc ... -larg -lm\fP.
  1795. X.SH SEE ALSO
  1796. Xscanf(3), varargs(3)
  1797. X.SH AUTHOR
  1798. XPaul Heckbert, ph@cs.cmu.edu, April 1988
  1799. END_OF_FILE
  1800.   if test 21195 -ne `wc -c <'libarg/arg_parse.3'`; then
  1801.     echo shar: \"'libarg/arg_parse.3'\" unpacked with wrong size!
  1802.   fi
  1803.   # end of 'libarg/arg_parse.3'
  1804. fi
  1805. if test -f 'libarg/expr.c' -a "${1}" != "-c" ; then 
  1806.   echo shar: Will not clobber existing file \"'libarg/expr.c'\"
  1807. else
  1808.   echo shar: Extracting \"'libarg/expr.c'\" \(6817 characters\)
  1809.   sed "s/^X//" >'libarg/expr.c' <<'END_OF_FILE'
  1810. X/*
  1811. X * expr_eval: expression evaluator - converts ascii string to floating point
  1812. X * Works by top-down predictive parsing.
  1813. X * Most of the routines gobble characters and advance global string pointer s.
  1814. X * Sets global expr_err if an error occurs.
  1815. X *
  1816. X * supports: parentheses, % for mod, ^ for pow, elementary functions,
  1817. X * constants pi and e, variable base constants
  1818. X *
  1819. X * Paul Heckbert    18 April 1988
  1820. X */
  1821. X
  1822. Xstatic char rcsid[] = "$Header: /gourd/usr2/ph/sys/libsys/RCS/expr.c,v 4.2 94/08/03 15:41:17 ph Exp Locker: ph $";
  1823. X
  1824. X#include <ctype.h>
  1825. X#include <math.h>
  1826. X
  1827. X#include "simple.h"
  1828. X#include "expr.h"
  1829. X#define space() for (; isspace(*s); s++)
  1830. X
  1831. Xdouble expr_eval(), expr(), term(), factor(), signednumber(), number(),
  1832. X    paren(), posconst(), expt();
  1833. Xstatic char *s0, *s;
  1834. Xint expr_error;
  1835. X
  1836. X#ifdef MAIN
  1837. Xmain(ac, av)
  1838. Xint ac;
  1839. Xchar **av;
  1840. X{
  1841. X    double x;
  1842. X
  1843. X    if (ac!=2) exit(1);
  1844. X    x = expr_eval(av[1]);
  1845. X    printf(">> %g\n", x);
  1846. X}
  1847. X#endif
  1848. X
  1849. Xint expr_eval_int(str)
  1850. Xchar *str;
  1851. X{
  1852. X    double x;
  1853. X
  1854. X    x = expr_eval(str);
  1855. X    /* do unsigned double to signed int conversion: */
  1856. X    return x>MAXINT ? x+2.*MININT : x;
  1857. X}
  1858. X
  1859. Xlong expr_eval_long(str)
  1860. Xchar *str;
  1861. X{
  1862. X    double x;
  1863. X
  1864. X    x = expr_eval(str);
  1865. X    /* do unsigned double to signed long conversion: */
  1866. X    return x>MAXLONG ? x+2.*MINLONG : x;
  1867. X}
  1868. X
  1869. Xdouble expr_eval(str)
  1870. Xchar *str;
  1871. X{
  1872. X    double x;
  1873. X
  1874. X    s0 = s = str;
  1875. X    expr_error = EXPR_GOOD;
  1876. X    x = expr();
  1877. X    if (*s) {
  1878. X    error(s, 1, "garbage in expression");
  1879. X    expr_error = s==s0 ? EXPR_BAD : EXPR_SOSO;
  1880. X    }
  1881. X    return x;
  1882. X}
  1883. X
  1884. Xstatic double expr()
  1885. X{
  1886. X    double x;
  1887. X
  1888. X    for (x=term();;) {
  1889. X    space();
  1890. X    switch (*s) {
  1891. X        case '+': s++; x += term(); break;
  1892. X        case '-': s++; x -= term(); break;
  1893. X        default: return x;
  1894. X    }
  1895. X    }
  1896. X}
  1897. X
  1898. Xstatic double term()
  1899. X{
  1900. X    double x, y;
  1901. X
  1902. X    for (x=factor();;) {
  1903. X    space();
  1904. X    switch (*s) {
  1905. X        case '*': s++; x *= factor(); break;
  1906. X        case '/': s++; x /= factor(); break;
  1907. X        case '%': s++; y = factor(); x = x-floor(x/y)*y; break;
  1908. X        default: return x;
  1909. X    }
  1910. X    }
  1911. X}
  1912. X
  1913. Xstatic double factor()
  1914. X{
  1915. X    double x;
  1916. X
  1917. X    for (x=signednumber();;) {
  1918. X    space();
  1919. X    switch (*s) {
  1920. X        case '^': s++; return pow(x, factor());    /* right-associative */
  1921. X        default: return x;
  1922. X    }
  1923. X    }
  1924. X}
  1925. X
  1926. Xstatic double signednumber()
  1927. X{
  1928. X    space();
  1929. X    switch (*s) {
  1930. X    case '-': s++; return -signednumber();
  1931. X    case '+': s++; return signednumber();
  1932. X    default: return number();
  1933. X    }
  1934. X}
  1935. X
  1936. Xstatic double number()
  1937. X{
  1938. X    char *func;
  1939. X    int n;
  1940. X    double x, y;
  1941. X
  1942. X    space();
  1943. X    if (isdigit(*s) || *s=='.') return posconst();
  1944. X    if (*s=='(') return paren();
  1945. X
  1946. X    if (isalpha(*s)) {
  1947. X    func = s;
  1948. X    for (s++; isalpha(*s) || isdigit(*s); s++);
  1949. X    n = s-func;    /* length of funcname */
  1950. X
  1951. X    if (eq(n, func, "pi"))        return M_PI;
  1952. X    if (eq(n, func, "e"))        return exp(1.);
  1953. X
  1954. X    if (eq(n, func, "sqrt"))    return sqrt(paren());
  1955. X    if (eq(n, func, "exp"))        return exp(paren());
  1956. X    if (eq(n, func, "log"))        return log(paren());
  1957. X    if (eq(n, func, "pow"))        {paren2(&x, &y); return pow(x, y);}
  1958. X
  1959. X    if (eq(n, func, "sin"))        return sin(paren());
  1960. X    if (eq(n, func, "cos"))        return cos(paren());
  1961. X    if (eq(n, func, "tan"))        return tan(paren());
  1962. X    if (eq(n, func, "asin"))    return asin(paren());
  1963. X    if (eq(n, func, "acos"))    return acos(paren());
  1964. X    if (eq(n, func, "atan"))    return atan(paren());
  1965. X    if (eq(n, func, "atan2"))    {paren2(&x, &y); return atan2(x, y);}
  1966. X
  1967. X    if (eq(n, func, "sind"))    return sin(DEG_TO_RAD(paren()));
  1968. X    if (eq(n, func, "cosd"))    return cos(DEG_TO_RAD(paren()));
  1969. X    if (eq(n, func, "tand"))    return tan(DEG_TO_RAD(paren()));
  1970. X    if (eq(n, func, "dasin"))    return RAD_TO_DEG(asin(paren()));
  1971. X    if (eq(n, func, "dacos"))    return RAD_TO_DEG(acos(paren()));
  1972. X    if (eq(n, func, "datan"))    return RAD_TO_DEG(atan(paren()));
  1973. X    if (eq(n, func, "datan2"))    {paren2(&x, &y);
  1974. X                    return RAD_TO_DEG(atan2(x, y));}
  1975. X
  1976. X    if (eq(n, func, "floor"))    return floor(paren());
  1977. X    if (eq(n, func, "ceil"))    return ceil(paren());
  1978. X
  1979. X    error(func, n, "bad numerical expression");
  1980. X    return 0.;
  1981. X    }
  1982. X
  1983. X    error(s, 1, "syntax error");
  1984. X    return 0.;
  1985. X}
  1986. X
  1987. X/* paren: '(' expr ')' */
  1988. X
  1989. Xstatic double paren()
  1990. X{
  1991. X    double x;
  1992. X
  1993. X    space();
  1994. X    if (*s!='(') error(s, 1, "expected '('");
  1995. X    s++;
  1996. X    x = expr();
  1997. X    space();
  1998. X    if (*s!=')') error(s, 1, "expected ')'");
  1999. X    s++;
  2000. X    return x;
  2001. X}
  2002. X
  2003. X/* paren2: '(' expr ',' expr ')' */
  2004. X
  2005. Xstatic paren2(x, y)
  2006. Xdouble *x, *y;
  2007. X{
  2008. X    space();
  2009. X    if (*s!='(') error(s, 1, "expected '('");
  2010. X    s++;
  2011. X    *x = expr();
  2012. X    space();
  2013. X    if (*s!=',') error(s, 1, "expected ','");
  2014. X    s++;
  2015. X    *y = expr();
  2016. X    space();
  2017. X    if (*s!=')') error(s, 1, "expected ')'");
  2018. X    s++;
  2019. X}
  2020. X
  2021. X/*
  2022. X * posconst: given a string beginning at s, return floating point value.
  2023. X * like atof but it uses and modifies the global ptr s
  2024. X */
  2025. X
  2026. Xstatic double posconst()
  2027. X{
  2028. X    int base, exp, pos, d;
  2029. X    double x, y;
  2030. X
  2031. X    space();
  2032. X    if (*s=='0') {        /* change base: 10 = 012 = 0xa = 0b2:1010 */
  2033. X    s++;
  2034. X    switch (*s) {
  2035. X        case 'b':
  2036. X        s++;
  2037. X        for (base=0; isdigit(*s); s++)
  2038. X            base = base*10+*s-'0';    /* base is in base 10! */
  2039. X        if (*s!=':') error(s, 1, "expecting ':'");
  2040. X        s++;
  2041. X        break;
  2042. X        case 'x': s++; base = 16; break;
  2043. X        case 't': s++; base = 10; break;
  2044. X        case '.': base = 10; break;        /* a float, e.g.: 0.123 */
  2045. X        default:  base = 8; break;
  2046. X    }
  2047. X    }
  2048. X    else base = 10;
  2049. X
  2050. X    x = 0.;
  2051. X    for (; d = digit(*s), d>=0 && d<base; s++)
  2052. X    x = x*base+d;
  2053. X    if (*s=='.') {
  2054. X    s++;
  2055. X    for (y=1.; d = digit(*s), d>=0 && d<base; s++) {
  2056. X        x = x*base+d;        /* fraction is in variable base */
  2057. X        y *= base;
  2058. X    }
  2059. X    x /= y;
  2060. X    }
  2061. X    if (*s=='e' || *s=='E') {
  2062. X    s++;
  2063. X    if (*s=='-')       {s++; pos = 0;}
  2064. X    else if (*s=='+') {s++; pos = 1;}
  2065. X    else pos = 1;
  2066. X    for (exp=0; isdigit(*s); s++)
  2067. X        exp = exp*10+*s-'0';    /* exponent is in base 10 */
  2068. X    y = expt(base, exp);
  2069. X    if (pos) x *= y;
  2070. X    else x /= y;
  2071. X    }
  2072. X    return x;
  2073. X}
  2074. X
  2075. Xstatic digit(c)
  2076. Xint c;
  2077. X{
  2078. X    return isdigit(c) ? c-'0' :
  2079. X    c>='a'&&c<='z' ? c-'a'+10 : c>='A'&&c<='Z' ? c-'A'+10 : -1;
  2080. X}
  2081. X
  2082. X/* expt: a^n for n>=0 */
  2083. X
  2084. Xstatic double expt(a, n)
  2085. Xint a, n;
  2086. X{
  2087. X    double t, x;
  2088. X
  2089. X    if (n<0) {
  2090. X    fprintf(stderr, "expt: can't do negative exponents\n");
  2091. X    return 1.;
  2092. X    }
  2093. X    if (n==0) return 1.;
  2094. X    for (t=a, x=1.; n>0; n>>=1) {
  2095. X    if (n&1) x *= t;
  2096. X    t *= t;
  2097. X    }
  2098. X    return x;
  2099. X}
  2100. X
  2101. X/* eq: test equality of string a, of length n, with null-terminated string b */
  2102. X
  2103. Xstatic eq(n, a, b)
  2104. Xint n;
  2105. Xchar *a, *b;
  2106. X{
  2107. X    char c;
  2108. X    int ret;
  2109. X
  2110. X    c = a[n];
  2111. X    a[n] = 0;
  2112. X    ret = str_eq(a, b);
  2113. X    a[n] = c;
  2114. X    return ret;
  2115. X}
  2116. X
  2117. Xstatic error(s, len, err)
  2118. Xchar *s, *err;
  2119. Xint len;
  2120. X{
  2121. X    if (*s==0) s[len] = 0;    /* just in case */
  2122. X    printf("expr: %s: ", err);
  2123. X    prints(s-s0, s0);
  2124. X    printf("[");
  2125. X    prints(len, s);
  2126. X    printf("]");
  2127. X    prints(s+strlen(s)-s0-len, s+len);
  2128. X    printf("\n");
  2129. X    if (expr_error!=EXPR_BAD)
  2130. X    expr_error = s==s0 ? EXPR_BAD : EXPR_SOSO;
  2131. X}
  2132. X
  2133. X/* prints: print string s of length n */
  2134. X
  2135. Xstatic prints(n, s)
  2136. Xint n;
  2137. Xchar *s;
  2138. X{
  2139. X    char c;
  2140. X
  2141. X    c = s[n];
  2142. X    s[n] = 0;
  2143. X    printf("%s", s);
  2144. X    s[n] = c;
  2145. X}
  2146. END_OF_FILE
  2147.   if test 6817 -ne `wc -c <'libarg/expr.c'`; then
  2148.     echo shar: \"'libarg/expr.c'\" unpacked with wrong size!
  2149.   fi
  2150.   # end of 'libarg/expr.c'
  2151. fi
  2152. if test -f 'libarg/expr.h' -a "${1}" != "-c" ; then 
  2153.   echo shar: Will not clobber existing file \"'libarg/expr.h'\"
  2154. else
  2155.   echo shar: Extracting \"'libarg/expr.h'\" \(652 characters\)
  2156.   sed "s/^X//" >'libarg/expr.h' <<'END_OF_FILE'
  2157. X/* expr.h: definitions for expression evaluator */
  2158. X
  2159. X#ifndef EXPR_HDR
  2160. X#define EXPR_HDR
  2161. X
  2162. X/* $Header: /gourd/usr2/ph/sys/libsys/RCS/expr.h,v 4.2 94/08/03 15:41:19 ph Exp Locker: ph $ */
  2163. X
  2164. X/* error codes */
  2165. X#define EXPR_GOOD    0    /* expression totally good */
  2166. X#define EXPR_SOSO    -1    /* expression partially good */
  2167. X#define EXPR_BAD    -2    /* expression totally bad */
  2168. X
  2169. Xextern int expr_error;        /* holds error code after expr_eval */
  2170. X
  2171. X#ifdef __cplusplus
  2172. X    extern "C" {
  2173. X    int expr_eval_int(char *str);
  2174. X    long expr_eval_long(char *str);
  2175. X    double expr_eval(char *str);
  2176. X    }
  2177. X#else
  2178. X    int expr_eval_int();
  2179. X    long expr_eval_long();
  2180. X    double expr_eval();
  2181. X#endif
  2182. X
  2183. X#endif
  2184. END_OF_FILE
  2185.   if test 652 -ne `wc -c <'libarg/expr.h'`; then
  2186.     echo shar: \"'libarg/expr.h'\" unpacked with wrong size!
  2187.   fi
  2188.   # end of 'libarg/expr.h'
  2189. fi
  2190. if test -f 'libarg/simple.h' -a "${1}" != "-c" ; then 
  2191.   echo shar: Will not clobber existing file \"'libarg/simple.h'\"
  2192. else
  2193.   echo shar: Extracting \"'libarg/simple.h'\" \(1343 characters\)
  2194.   sed "s/^X//" >'libarg/simple.h' <<'END_OF_FILE'
  2195. X/* simple.h: definitions of some simple, common constants and macros */
  2196. X
  2197. X#ifndef SIMPLE_HDR
  2198. X#define SIMPLE_HDR
  2199. X
  2200. X/* $Header: /gourd/usr2/ph/sys/libsys/RCS/simple.h,v 4.2 94/08/03 15:41:23 ph Exp Locker: ph $ */
  2201. X
  2202. X#include <stdio.h>
  2203. X#include <math.h>
  2204. X
  2205. X/* better than standard assert.h: doesn't gag on 'if (p) assert(q); else r;' */
  2206. X#define assert(p) if (!(p)) \
  2207. X    { \
  2208. X    fprintf(stderr, "Assertion failed: %s line %d\n", __FILE__, __LINE__); \
  2209. X    exit(1); \
  2210. X    } \
  2211. X    else
  2212. X
  2213. X#define str_eq(a, b)    (strcmp(a, b) == 0)
  2214. X#define MIN(a, b)    ((a)<(b) ? (a) : (b))
  2215. X#define MAX(a, b)    ((a)>(b) ? (a) : (b))
  2216. X#define ABS(a)        ((a)>=0 ? (a) : -(a))
  2217. X#define SWAP(a, b, t)    {t = a; a = b; b = t;}
  2218. X#define LERP(t, a, b)    ((a)+(t)*((b)-(a)))
  2219. X#define ALLOC(ptr, type, n)  assert(ptr = (type *)malloc((n)*sizeof(type)))
  2220. X#define ALLOC_ZERO(ptr, type, n)  assert(ptr = (type *)calloc(n, sizeof(type)))
  2221. X
  2222. X#define RAD_TO_DEG(x) ((x)*(180./M_PI))
  2223. X#define DEG_TO_RAD(x) ((x)*(M_PI/180.))
  2224. X
  2225. X/* note: the following are machine dependent! (ifdef them if possible) */
  2226. X#define MINSHORT -32768
  2227. X#define MINLONG -2147483648
  2228. X#define MININT MINLONG
  2229. X#ifndef MAXINT    /* sgi has these in values.h */
  2230. X#   define MAXSHORT 32767
  2231. X#   define MAXLONG 2147483647
  2232. X#   define MAXINT MAXLONG
  2233. X#endif
  2234. X
  2235. X
  2236. X#ifdef hpux    /* hp's unix doesn't have bzero */
  2237. X#   define bzero(a, n) memset(a, 0, n)
  2238. X#endif
  2239. X
  2240. X#endif
  2241. END_OF_FILE
  2242.   if test 1343 -ne `wc -c <'libarg/simple.h'`; then
  2243.     echo shar: \"'libarg/simple.h'\" unpacked with wrong size!
  2244.   fi
  2245.   # end of 'libarg/simple.h'
  2246. fi
  2247. if test -f 'libarg/tb.c' -a "${1}" != "-c" ; then 
  2248.   echo shar: Will not clobber existing file \"'libarg/tb.c'\"
  2249. else
  2250.   echo shar: Extracting \"'libarg/tb.c'\" \(1940 characters\)
  2251.   sed "s/^X//" >'libarg/tb.c' <<'END_OF_FILE'
  2252. X/* tb.c - arg_parse test program */
  2253. X
  2254. Xstatic char rcsid[] = "$Header: /gourd/usr2/ph/sys/libsys/libarg/RCS/tb.c,v 4.2 94/08/03 20:09:48 ph Exp Locker: ph $";
  2255. X
  2256. X#include <stdio.h>
  2257. Xdouble atof();
  2258. X
  2259. X#include "arg.h"
  2260. Xstatic double dxs = 1., dys = .75;
  2261. Xstatic int x1 = 0, y1 = 0, x2 = 99, y2 = 99;
  2262. Xstatic char *chanlist = "rgba";
  2263. Xint arg_people(), arg_dsize();
  2264. XArg_form *fb_init();
  2265. X
  2266. Xmain(ac, av)
  2267. Xint ac;
  2268. Xchar **av;
  2269. X{
  2270. X    int fast, xs = 512, ys = 486;
  2271. X    double scale = 1.;
  2272. X    char *fromfile, tofile[80], *child = "jim";
  2273. X    Arg_form *arg_fb;
  2274. X
  2275. X    arg_fb = fb_init();
  2276. X    if (arg_parse(ac, av,
  2277. X    "", "Usage: %s [options]", av[0],
  2278. X    "", "This program does nothing but test arg_parse",
  2279. X    "%S %s", &fromfile, tofile, "fromfile and tofile",
  2280. X    "[%F]", &scale, "set scale [default=%g]", scale,
  2281. X    "", ARG_SUBR(arg_people), "names of people",
  2282. X    "-fast", ARG_FLAG(&fast), "do it faster",
  2283. X    "-ch %S", &child, "set child name",
  2284. X    "-srcsize %d[%d]", &xs, &ys, "set source size [default=%d,%d]", xs, ys,
  2285. X    "-dstsize", ARG_SUBR(arg_dsize), "set dest size",
  2286. X    "-fb", ARG_SUBLIST(arg_fb), "FB COMMANDS",
  2287. X    0) < 0)
  2288. X    exit(1);
  2289. X
  2290. X    printf("from=%s to=%s scale=%g fast=%d child=%s src=%dx%d dst=%gx%g\n",
  2291. X    fromfile, tofile, scale, fast, child, xs, ys, dxs, dys);
  2292. X    printf("window={%d,%d,%d,%d} chan=%s\n", x1, y1, x2, y2, chanlist);
  2293. X}
  2294. X
  2295. Xstatic arg_people(ac, av)
  2296. Xint ac;
  2297. Xchar **av;
  2298. X{
  2299. X    int i;
  2300. X
  2301. X    for (i=0; i<ac; i++)
  2302. X    printf("person[%d]=%s\n", i, av[i]);
  2303. X}
  2304. X
  2305. Xstatic arg_dsize(ac, av)
  2306. Xint ac;
  2307. Xchar **av;
  2308. X{
  2309. X    if (ac<1 || ac>3) {
  2310. X    fprintf(stderr, "-dsize wants 1 or 2 args\n");
  2311. X    exit(1);
  2312. X    }
  2313. X    /* illustrate two methods for argument conversion */
  2314. X    dxs = atof(av[0]);            /* constant conversion */
  2315. X    if (ac>1) dys = expr_eval(av[1]);    /* expression conversion */
  2316. X    else      dys = .75*dxs;
  2317. X}
  2318. X
  2319. XArg_form *fb_init()
  2320. X{
  2321. X    return arg_to_form(
  2322. X    "-w%d%d%d%d", &x1, &y1, &x2, &y2, "set screen window",
  2323. X    "-ch%S", &chanlist, "set channels [default=%s]", chanlist,
  2324. X    0);
  2325. X}
  2326. END_OF_FILE
  2327.   if test 1940 -ne `wc -c <'libarg/tb.c'`; then
  2328.     echo shar: \"'libarg/tb.c'\" unpacked with wrong size!
  2329.   fi
  2330.   # end of 'libarg/tb.c'
  2331. fi
  2332. echo shar: End of archive 1 \(of 1\).
  2333. cp /dev/null ark1isdone
  2334. MISSING=""
  2335. for I in 1 ; do
  2336.     if test ! -f ark${I}isdone ; then
  2337.     MISSING="${MISSING} ${I}"
  2338.     fi
  2339. done
  2340. if test "${MISSING}" = "" ; then
  2341.     echo You have the archive.
  2342.     rm -f ark[1-9]isdone
  2343. else
  2344.     echo You still must unpack the following archives:
  2345.     echo "        " ${MISSING}
  2346. fi
  2347. exit 0
  2348. exit 0 # Just in case...
  2349.