home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume2 / argproc < prev    next >
Encoding:
Internet Message Format  |  1991-08-07  |  41.5 KB

  1. From: dan@srs.UUCP
  2. Newsgroups: comp.sources.misc
  3. Subject: v02i088: argproc(), a command line parser
  4. Message-ID: <8804051530.AA28824@rem.srs.com>
  5. Date: 5 Apr 88 15:30:11 GMT
  6. Approved: allbery@ncoast.UUCP
  7.  
  8. comp.sources.misc: Volume 2, Issue 88
  9. Submitted-By: "A. Nonymous" <dan@srs.UUCP>
  10. Archive-Name: argproc
  11.  
  12. #!/bin/sh
  13. #
  14. # Recently, there's been discussion on comp.lang.c and comp.unix.wizards
  15. # about what a convenient command line option parser should be like.
  16. # By popular demand, here is our contribution to the cause: argproc().
  17. # It has saved us a lot of programming time; perhaps it will help others.
  18. # It isn't getopt compatible, but you can't have everything.
  19. # Perhaps somebody would like to make it conform to getopt()?  Any takers?
  20. #
  21. # Dan Kegel   "... earn it anew if thou wouldst possess it."  - Goethe: Faust
  22. #  srs!dan@cs.rochester.edu  rochester!srs!dan dan%srs.uucp@harvard.harvard.edu
  23. #
  24. # shar archiver, delete everything above the #!/bin/sh line
  25. # and run through sh (not csh)
  26. #
  27. echo 'shar: extracting "argproc.doc" (5442 characters)'
  28. # 'argproc.doc' has a checksum of 29484 on BSD and 54780 on System V.
  29. sed 's/^X//' > argproc.doc << 'XXX_EOF_XXX'
  30. Xargproc - process command line arguments
  31. X
  32. XSYNOPSIS
  33. X     #include "argproc.h"
  34. X
  35. X     long argproc(argc, argv, format [ , pointer ] . . .  )
  36. X     int argc;
  37. X     char *argv[], *format;
  38. X
  39. X     Format string contents:
  40. X    -  introduces one or more switches with single-letter names
  41. X    =  is same as -, but sets a boolean telling whether each switch 
  42. X       actually appeared on the command line
  43. X    {} surround switches with long names
  44. X    %s, %d, %f, %hd, %ld, %lf, etc. may appear alone to indicate 
  45. X       positional parameters, or after a switch name to indicate 
  46. X       arguments to that switch.  These are processed by sscanf().
  47. X    ,  separates arguments of a single switch
  48. X    [] surround optional arguments
  49. X
  50. XNOTICE
  51. X     Argproc is a routine written by Steve Colwell at S.R. Systems.
  52. X     It is being posted to Usenet to stimulate discussion about
  53. X     command line argument parsers, and may be freely used and copied
  54. X     for any purpose.  This routine has been in daily use for over a year
  55. X     now; however, the version being posted was modified to use vsprintf
  56. X     instead of _doprnt, and has been tested only lightly.
  57. X
  58. XDESCRIPTION
  59. X     This routine provides an easy  way  to  parse  command  line
  60. X     arguments.   The  main  routine passes its argc, argv, and a
  61. X     scanf-type format string to argproc, which parses  the  com-
  62. X     mand  line  for  parameters and switches as described below,
  63. X     returning the various values in the pointed-to variables.
  64. X     It does not alter argv[].
  65. X
  66. X     Each entry in the format string has  one  of  the  following
  67. X     forms:
  68. X
  69. X     -XYZ X, Y, and Z are the one-char names of boolean flags.
  70. X
  71. X     -X%s %s is a scanf-type format specification, which is  used
  72. X          only if -X precedes it.
  73. X
  74. X     -X[%s] %s is a optional scanf-type format specification, which 
  75. X     may or may not be supplied after the -X.
  76. X         -X[%d,%s] is allowed, but -X%d[,%s] is not supported.
  77. X
  78. X     =X   X is a boolean flag, a boolean value is put in the associated
  79. X      variable.  The '=' may be used in place of the '-' in any
  80. X      of the above formats.
  81. X
  82. X     {=XYZ}
  83. X      XYZ is a many-char name for a single boolean flag.
  84. X     {-outfile%s}
  85. X      'outfile' is a many-char name for a flag with a string argument.
  86. X
  87. X     %s   the next argument that doesn't start with - is taken as a %s 
  88. X          type.
  89. X
  90. X     Generally, anywhere a "%d" or "%s" is listed above, ANY scanf-style
  91. X     format specifier may appear.
  92. X
  93. X     The only way to have a switch with a greater than  one  char
  94. X     name  is  by  using the braces.  For example, "{-longname}".
  95. X     All other flag names are only one character long.  The flags
  96. X     are  detected anywhere in the argument list, no matter where
  97. X     they appear in the format string.
  98. X
  99. X     A single argument may contain more than one format  command.
  100. X     For  example,  "%d,%d"  gets  two  integers,  seperated by a
  101. X     comma, from one argument.  This form  implies  two  relevant
  102. X     bits in the returned bit map as well as two variables in the
  103. X     variable list.
  104. X
  105. X     A format may use the scanf "%*c" form to throw away an argu-
  106. X     ment  or  a  part  of  an  argument.   In this case a bit is
  107. X     assigned, but no variable is used as there is  no  value  to
  108. X     receive.   This may be used to get two ints separated by any
  109. X     char (ie. "%d%*c%d" to read 5,6 5-6 etc).
  110. X
  111. X     The order of switches in the format string doesn't imply
  112. X     that the switches must be given in any order on the commandline.
  113. X
  114. XRETURN VALUE
  115. X     The return value is -1 for error.
  116. X
  117. X     If there was no error, one bit is set for each unit of the 
  118. X     format string which was successfully parsed.
  119. X     This turns out to be difficult to use in practice, especially when
  120. X     adding new options; I suggest using the = notation instead.
  121. X     (A unit is a flag or argument format command in the format string.
  122. X      For example, "-moyx"  has  four units and "-X%d" has two units.
  123. X      The leftmost unit  is  assigned bit  0,  the  second unit is bit 1, 
  124. X      etc.  If there are more than 32 "units" in the format string,
  125. X      only the first 32 have bits in the return value.
  126. X      This is one reason why the equals sign "=x" notation was added.)
  127. X
  128. XEXAMPLES
  129. X     Always call lose_title(argv[0]) first thing in main().
  130. X
  131. X     boolean x, y, z;
  132. X     argproc(argc,argv,"=xy =z", &x, &y, &z);
  133. X
  134. X     short a = 5;
  135. X     argproc(argc,argv,"-a%hd", &a);
  136. X
  137. X     char infile[100];
  138. X     static char logfile[100] = "";
  139. X     argproc(argc,argv,"{-logfile%s} %s", logfile, infile);
  140. X
  141. X     char ofile[100], pfile[100];
  142. X     boolean pGiven;
  143. X     argproc(argc,argv,"-o%s =p[%s]", ofile, &pGiven, pfile);
  144. X
  145. X     See also demo.c.
  146. X
  147. XDIAGNOSTICS
  148. X     If the user enters an unknown option, argproc usually prints a message to
  149. X     stderr and exits with a status of 1.
  150. X     However, if the first character of the format string is 'W',
  151. X     argproc prints an error message and returns with a value of -1.
  152. X     If the first character of the format string is 'N',
  153. X     argproc places an error message in the global ErrString, and returns 
  154. X     with a value of -1.
  155. X     See 'lose.doc'.
  156. X
  157. XBUGS
  158. X     Longer switch names must occur before shorter ones to override them;
  159. X     that is, the format string "-f {-fc}" will never allow the flag
  160. X     -fc to be found, it will just give the error "no flag -c".
  161. X
  162. X     Does not support the "--" convention.
  163. X
  164. X     Does not allow spaces between an option and its argument
  165. X     (e.g. "-o foo" does NOT match the format "-o%s"; "-ofoo" does).
  166. XXX_EOF_XXX
  167. if test 5442 -ne "`wc -c < argproc.doc`"
  168. then
  169.     echo 'shar: transmission error on "argproc.doc"'
  170. fi
  171. chk=`sum argproc.doc | awk '{print $1}'`
  172. if test 29484 -ne $chk -a 54780 -ne $chk
  173. then
  174.     echo 'shar: checksum error on "argproc.doc"'
  175. fi
  176. echo 'shar: extracting "lose.doc" (1861 characters)'
  177. # 'lose.doc' has a checksum of 29331 on BSD and 17779 on System V.
  178. sed 's/^X//' > lose.doc << 'XXX_EOF_XXX'
  179. Xlose, warn, lose_title - easy routines for printing error messages
  180. X
  181. XSYNOPSIS
  182. X     extern char *ErrStr, *ProgTitle;
  183. X
  184. X     lose_title(title)
  185. X     char *title;
  186. X
  187. X     lose(format [ , pointer ] . . .  )
  188. X     char *format;
  189. X
  190. X     warn(format [ , pointer ] . . .  )
  191. X     char *format;
  192. X
  193. X     #include "lose.h"        /* for values of errMode */
  194. X
  195. X     PrintErr(errMode, format [    , pointer ] . .    .  )
  196. X     int errMode;        /* ERR_FATAL, ERR_WARN, or ERR_NOTE */
  197. X     char *format;
  198. X
  199. XDESCRIPTION
  200. X     These routines provide an easy to use error printing system.
  201. X
  202. X     lose_title    is called at the beginning  of    the  user's  main
  203. X     with  argv[0] as title. This sets ProgTitle with the name of
  204. X     the program.  Errors of various severity levels can  now  be
  205. X     processed with calls to lose, warn or PrintErr.
  206. X
  207. X     lose prints an error message (described below) and    exits the
  208. X     program with value    1.
  209. X
  210. X     warn prints an error message, sets    errno to 0, and    returns.
  211. X
  212. X     PrintErr performs one of the above    depending on the value of
  213. X     errMode;  ERR_FATAL selects lose, ERR_WARN    selects    warn, and
  214. X     ERR_NOTE just places the error message in ErrStr.
  215. X
  216. XERROR MESSAGE CONSTRUCTION
  217. X     The error message is built by calling vsprintf with the given
  218. X     parameters; it is then prefixed with the program name.
  219. X
  220. X     Then, if errno (see man errno) is non-zero, the  appropriate
  221. X     error message (see    sys_nerr in perror(3)) is appended.  Once
  222. X     the error message has been    constructed, errno is reset to 0.
  223. X
  224. XEXAMPLE
  225. X     lose_title(argv[0]);
  226. X     if (argc != 2)
  227. X     Epitaph("Usage: %s filename", argv[0]);
  228. X     ...
  229. X     if ((fp=fopen(argv[1], "r")) == NULL)
  230. X     lose("Can't open source file %s", argv[1]);
  231. X     ...
  232. X     if (line is bad)
  233. X     Epitaph("Badly formatted line %s at line %d of file %s",
  234. X        line, lineNumber, argv[1]);
  235. X
  236. XSEE ALSO
  237. X     perror, argproc, vsprintf, varargs
  238. XXX_EOF_XXX
  239. if test 1861 -ne "`wc -c < lose.doc`"
  240. then
  241.     echo 'shar: transmission error on "lose.doc"'
  242. fi
  243. chk=`sum lose.doc | awk '{print $1}'`
  244. if test 29331 -ne $chk -a 17779 -ne $chk
  245. then
  246.     echo 'shar: checksum error on "lose.doc"'
  247. fi
  248. echo 'shar: extracting "demo.c" (4163 characters)'
  249. # 'demo.c' has a checksum of 42031 on BSD and 5936 on System V.
  250. sed 's/^X//' > demo.c << 'XXX_EOF_XXX'
  251. X/*--------------------------------------------------------------------------
  252. X Demo program for argproc().
  253. X Demonstrates boolean, string, integer, and float argument-getting.
  254. X
  255. X Just about every program written here follows the scheme shown below:
  256. X    #define default values
  257. X    main() {
  258. X    declare all command-line-settable variables and initialize
  259. X    call lose_title() to register the program name for error messages
  260. X    call argproc() to parse the command line
  261. X    if any mistakes, print usage message and abort
  262. X    else loop over argv[] and do the real work.
  263. X    }
  264. X--------------------------------------------------------------------------*/
  265. X
  266. X#include <stdio.h>
  267. X#include <string.h>
  268. X#include "argproc.h"
  269. X
  270. X/* Default values for variables set by command line options */
  271. X#define DEF_X 32
  272. X#define DEF_PI 3.1445
  273. X#define DEF_S "this is a test"
  274. X
  275. Xmain(argc, argv)
  276. X    int argc;
  277. X    char **argv;
  278. X{
  279. X    /* These variables are set according to the command line */
  280. X    boolean b_bool, c_bool, help_bool;
  281. X    static char s_string[256] = DEF_S;
  282. X    boolean s_string_given;    /* TRUE if user gave value for s_string */
  283. X    int     x = DEF_X;
  284. X    double  pi = DEF_PI;
  285. X    char    arg_string[256];
  286. X
  287. X    /* Variables */
  288. X    int i;
  289. X
  290. X    /* Register program name for use in error messages generated by lose() */
  291. X    lose_title(argv[0]);
  292. X
  293. X    /* Parse command-line options.
  294. X     * - and = introduce switches with single-letter names.
  295. X     * {-name...} and {=name...} introduce switches with longer names.
  296. X     * Switches introduced with = set or clear a corresponding boolean 
  297. X     * so you can tell if the user gave them; - is only useful for switches
  298. X     * that take arguments.
  299. X     *
  300. X     * Switch names followed by scanf-style format specifiers separated by 
  301. X     * commas, e.g. "-m%d" or "-m%d,%f" etc., indicate required arguments.
  302. X     * If such a switch appears in argv[i], its arguments must also appear
  303. X     * in argv[i], separated by commas.
  304. X     *
  305. X     * Format specifiers surrounded by square brackets, e.g. "=m[%d]", indicate 
  306. X     * optional arguments; both "... -m " and "... -m546 " are accepted.
  307. X     * To tell if the optional argument was given, you must either
  308. X     * check to see if its value changed during the call to argproc(), or
  309. X     * (yech!) check the bitmask returned by argproc.  Checking the bitmask
  310. X     * is rather difficult; nowadays, I just ignore argproc's return value.
  311. X     */
  312. X    argproc(argc, argv, "=bc {=help} =s%s -x%d {-pi%lf} %s",
  313. X        &b_bool, &c_bool, &help_bool, &s_string_given, s_string, 
  314. X        &x, &pi, arg_string);
  315. X
  316. X    /* If user didn't give a value for arg_string, or if she gave the
  317. X     * -help switch, print a terse usage message.
  318. X     * In a real program, this usage message is very helpful for the user
  319. X     * who just needs a little reminder about which options do what.
  320. X     */
  321. X    if (!arg_string[0] || help_bool)
  322. X    lose("Usage: %s file ...\n\
  323. XDemonstration program for argproc().  Note that no spaces are allowed\n\
  324. Xbetween a switch and its arguments (i.e. -x3 is okay, -x 3 is not allowed).\n\
  325. XOptions:\n\
  326. X    -help    Print this message\n\
  327. X    -b       Set b_bool TRUE\n\
  328. X    -c       Set c_bool TRUE\n\
  329. X    -sSTRING Set string s  [default: %s]\n\
  330. X    -xINT    Set integer x [default: %d]\n\
  331. X    -piFLOAT Set double pi [default: %f]",
  332. X    argv[0], DEF_S, DEF_X, DEF_PI);
  333. X
  334. X    /* argproc() accepts options anywhere on the command line; filenames
  335. X     * and switches may be freely intermixed.  (C'mon, haven't you wished you
  336. X     * could type "ls *.c -l", and have it work?)
  337. X     * Therefore, to handle an arbitrary number of filenames, you must
  338. X     * step through argv[], and treat each string not beginning with a dash
  339. X     * as a filename argument.
  340. X     */
  341. X    for (i=1; i<argc; i++) {
  342. X    if (argv[i][0] != '-') {
  343. X        /* Do something with this argument. */
  344. X        do_file(argv[i], b_bool, c_bool, s_string_given, s_string, x, pi);
  345. X    }
  346. X    }
  347. X
  348. X    exit(0);
  349. X}
  350. X
  351. X/* Dummy routine to do something with each file argument. */
  352. X
  353. Xdo_file(arg, b, c, sGiven, s, x, pi)
  354. X    char *arg;
  355. X    boolean b, c, sGiven;
  356. X    char *s;
  357. X    int x;
  358. X    double pi;
  359. X{
  360. X    (void) printf("arg=%s, b=%d, c=%d, sGiven=%d, s=%s, x=%d, pi=%f\n",
  361. X    arg, b, c, sGiven, s, x, pi);
  362. X}
  363. X
  364. XXX_EOF_XXX
  365. if test 4163 -ne "`wc -c < demo.c`"
  366. then
  367.     echo 'shar: transmission error on "demo.c"'
  368. fi
  369. chk=`sum demo.c | awk '{print $1}'`
  370. if test 42031 -ne $chk -a 5936 -ne $chk
  371. then
  372.     echo 'shar: checksum error on "demo.c"'
  373. fi
  374. echo 'shar: extracting "boolean.h" (328 characters)'
  375. # 'boolean.h' has a checksum of 19429 on BSD and 21422 on System V.
  376. sed 's/^X//' > boolean.h << 'XXX_EOF_XXX'
  377. X/*--------------------------------------------------------------------------
  378. X Local definitions; peoples' preferences for these are hard to predict...
  379. X--------------------------------------------------------------------------*/
  380. X
  381. Xtypedef short boolean;
  382. X
  383. X#ifndef TRUE
  384. X#define TRUE    ((boolean) 1)
  385. X#define FALSE    ((boolean) 0)
  386. X#endif
  387. XXX_EOF_XXX
  388. if test 328 -ne "`wc -c < boolean.h`"
  389. then
  390.     echo 'shar: transmission error on "boolean.h"'
  391. fi
  392. chk=`sum boolean.h | awk '{print $1}'`
  393. if test 19429 -ne $chk -a 21422 -ne $chk
  394. then
  395.     echo 'shar: checksum error on "boolean.h"'
  396. fi
  397. echo 'shar: extracting "Makefile" (119 characters)'
  398. # 'Makefile' has a checksum of 61063 on BSD and 9549 on System V.
  399. sed 's/^X//' > Makefile << 'XXX_EOF_XXX'
  400. X# Makefile for argproc() demo
  401. X
  402. XCFLAGS = -g
  403. Xdemo: demo.o argproc.o lose.o
  404. X    cc $(CFLAGS) demo.o argproc.o lose.o -o demo
  405. XXX_EOF_XXX
  406. if test 119 -ne "`wc -c < Makefile`"
  407. then
  408.     echo 'shar: transmission error on "Makefile"'
  409. fi
  410. chk=`sum Makefile | awk '{print $1}'`
  411. if test 61063 -ne $chk -a 9549 -ne $chk
  412. then
  413.     echo 'shar: checksum error on "Makefile"'
  414. fi
  415. echo 'shar: extracting "argproc.c" (16865 characters)'
  416. # 'argproc.c' has a checksum of 18141 on BSD and 31035 on System V.
  417. sed 's/^X//' > argproc.c << 'XXX_EOF_XXX'
  418. X/*--------------------------------------------------------------------------
  419. X This module defines argproc(), a simple-to-use command line option grabber.
  420. X It was written by Steve Colwell @ srs.uucp.
  421. X--------------------------------------------------------------------------*/
  422. X#include <stdio.h>
  423. X#include <ctype.h>
  424. X#include <string.h>
  425. X#include <varargs.h>
  426. X#include "boolean.h"
  427. X#include "lose.h"
  428. X
  429. X#define ERROR -1
  430. X
  431. X/*LINTLIBRARY*/
  432. X#ifndef lint
  433. Xstatic char Sccs_id[] = "@(#)argproc.c    from 1.19 4/15/87 (C) SRS";
  434. X#endif
  435. X
  436. X/* Dummy function declaration; this is lint's idea of a function prototype.
  437. X * If you don't use lint, you can safely omit this section.
  438. X */
  439. X#ifdef lint
  440. X    /*VARARGS3*/
  441. X    long argproc(argc, argv, format) 
  442. X    int argc;
  443. X    char **argv, *format; 
  444. X    {
  445. X    /* Dummy function body; make lint think all the args were used. */
  446. X    *argv[0]= *format; *format = (char) argc; return 0L; 
  447. X    }
  448. X#else
  449. X
  450. X#define MAX_ARG_NAME_LEN 20
  451. X#define MAX_ARG_FORM_LEN 50
  452. X#define MAX_ARGS     200
  453. X
  454. X#define SWITCH 8
  455. X#define NORM_ARG 4
  456. X#define BOOL_FLAG (SWITCH|1) 
  457. X#define BOOL_VAR_FLAG (SWITCH|2)
  458. X#define VALUE_FLAG (SWITCH|NORM_ARG)
  459. X
  460. X/*----------------------------------------------------------------------
  461. X The format string entry structure.  Holds different information, depending
  462. X on whether the entry is a boolean "-x", and boolean with variable "=x",
  463. X a normal argument "%s", a switched argument "-x%s", or a combination "=x%s".
  464. X----------------------------------------------------------------------*/
  465. Xtypedef
  466. X    struct argpType {
  467. X    /* one of the above defines */
  468. X    int type; 
  469. X    /* the number of the bit in the returned long which this entry
  470. X     * corresponds to */
  471. X    int bitnum;
  472. X
  473. X    /* name of the switch for SWITCH types */
  474. X    char name[MAX_ARG_NAME_LEN];
  475. X
  476. X    /* format reading parameters for NORM_ARG types */
  477. X    /* the scanf format string */
  478. X    char format[MAX_ARG_FORM_LEN];
  479. X    /* the number of format commands in format, e.g. %d,%d gives 2 */
  480. X    int fmt_count;
  481. X    /* Are the values for the flag optional, or must they be present? */
  482. X    boolean optional;
  483. X
  484. X    /* An index into the pointer array for the processed args recipient;
  485. X     * used for NORM_ARG and BOOL_VAR_FLAG */
  486. X    int pnt_index;
  487. X    }
  488. X    argp_t;
  489. X
  490. X
  491. X/*--------------------------------------------------------------------------
  492. X Return pointer to first char in s which matches a char from untilstr.
  493. X--------------------------------------------------------------------------*/
  494. Xchar * 
  495. Xsindex(s, untilstr)
  496. X    register char *s, *untilstr;
  497. X{
  498. X    register char c1, c2, *up;
  499. X
  500. X    while ((c1= *s++) != '\0') {
  501. X    up = untilstr;
  502. X    while ((c2= *up++) != '\0')
  503. X        if (c1 == c2)
  504. X        return(s-1);
  505. X    }
  506. X
  507. X    return(s-1);
  508. X}
  509. X
  510. X/*--------------------------------------------------------------------------
  511. X Copy chars from beg to end-1 into res, add null char.
  512. X--------------------------------------------------------------------------*/
  513. Xstatic void
  514. Xbe_strcpy(res, beg, end)
  515. X    register char *res, *beg, *end;
  516. X{
  517. X    while (beg != end)
  518. X    *res++ = *beg++;
  519. X    *res = '\0';
  520. X}
  521. X
  522. X/*--------------------------------------------------------------------------
  523. X Copy s2 to s1 until a char from untilstr occurs, then null 
  524. X terminate s1 and return a pointer to the terminal char in s2.
  525. X--------------------------------------------------------------------------*/
  526. Xstatic char *
  527. Xcopy_until(s1, s2, untilstr)
  528. X    char *s1, *s2, *untilstr;
  529. X{
  530. X    char *olds2;
  531. X
  532. X    olds2 = s2;
  533. X    s2 = sindex(s2, untilstr);
  534. X    be_strcpy(s1, olds2, s2);
  535. X
  536. X    return(s2);
  537. X}
  538. X
  539. X
  540. X/*----------------------------------------------------------------------
  541. X Count the number of format specifications.
  542. X Ignore literal "%" and dummy field spec "*".
  543. X----------------------------------------------------------------------*/
  544. Xstatic int 
  545. Xformat_count(str)
  546. X    char *str;
  547. X{
  548. X    int count=0;
  549. X
  550. X    str = strchr(str, '%');
  551. X    while (str++ != NULL) {
  552. X    if (*str == '%') 
  553. X        str++;
  554. X    else if (*str != '*')
  555. X        count++;
  556. X
  557. X    str = strchr(str, '%');
  558. X    }
  559. X
  560. X    return count;
  561. X}
  562. X
  563. X
  564. X/*----------------------------------------------------------------------
  565. X Process the format word which started with a '%'.  The whole word should
  566. X look like '%s' or '%*d' or some other scanf format word starting with %.
  567. X It may have multiple entries, for instance '%d%s'.
  568. X-----------------------------------------------------------------------*/
  569. Xstatic char *
  570. XnormArgParse(form, argp, argpcountp, bitnump, pntcountp)
  571. X    char *form;
  572. X    argp_t *argp;
  573. X    int *argpcountp, *bitnump, *pntcountp;
  574. X{
  575. X    int pos = (*argpcountp)++;
  576. X    int fmt_count;
  577. X
  578. X/* copy everything, including the first '%' */
  579. X    form = copy_until(argp[pos].format, form-1, " \t\n");
  580. X
  581. X    argp[pos].type = NORM_ARG;
  582. X    argp[pos].optional = FALSE;
  583. X    argp[pos].bitnum = *bitnump;
  584. X    argp[pos].pnt_index = *pntcountp;
  585. X    argp[pos].fmt_count = fmt_count = format_count(argp[pos].format);
  586. X
  587. X    *pntcountp += fmt_count;
  588. X    *bitnump += fmt_count;
  589. X
  590. X    return form;
  591. X}
  592. X
  593. X
  594. X
  595. X/*----------------------------------------------------------------------
  596. X Make a new entry in the form entry table 'form' for a boolean switch.  It
  597. X may be a boolean variable (according to isBoolVar), and should use the
  598. X specified bit number and name.  If it is boolVar, a pointer to the user
  599. X variables is used up too (pntcountp).
  600. X-----------------------------------------------------------------------*/
  601. Xstatic void
  602. XnewBoolEntry(form, bitnum, name, nameLen, isBoolVar, pntcountp)
  603. X    argp_t *form;
  604. X    char *name;
  605. X    int bitnum, nameLen, *pntcountp;
  606. X    boolean isBoolVar;
  607. X{
  608. X    (void) strncpy(form->name, name, nameLen);
  609. X    form->name[nameLen] = '\0';
  610. X
  611. X    form->bitnum = bitnum;
  612. X
  613. X    if (isBoolVar) {
  614. X    form->type = BOOL_VAR_FLAG;
  615. X    form->pnt_index = (*pntcountp)++;
  616. X    } else
  617. X    form->type = BOOL_FLAG;
  618. X}
  619. X
  620. X
  621. X/*----------------------------------------------------------------------
  622. X Process the format word which started with a dash.  The whole word should
  623. X look like '-xy%s' or '=xy%s' where x is a boolean switch, y is a value switch.
  624. X Also handles the case where there are braces around the switch '{-long%d}'
  625. X which means that the switch has a long name, and the case of optional values
  626. X '-x[%d]', or both '{-longname[%d]}'.  The 'form' always points to the char
  627. X after the '-' or '=', and 'wasBrace' indicates whether there was a left
  628. X brace before that.
  629. X-----------------------------------------------------------------------*/
  630. Xstatic char *
  631. XswitchParse(form, argp, argpcountp, bitnump, pntcountp, wasBrace)
  632. X    char *form;
  633. X    argp_t *argp;
  634. X    int *argpcountp, *bitnump, *pntcountp;
  635. X    boolean wasBrace;
  636. X{
  637. X    char *oldform = form;
  638. X    int pos = *argpcountp;
  639. X    boolean leftBracket, isBoolVar;
  640. X
  641. X/* if switch started with '=', will return result in a boolean variable */
  642. X    isBoolVar = (form[-1] == '=');
  643. X
  644. X    form = sindex(form, "}%[ \t\n");
  645. X    leftBracket = (*form == '[');
  646. X
  647. X    if (oldform == form) 
  648. X    Epitaph("argproc: switch must include 1 char flag name(s)");
  649. X
  650. X    if (wasBrace) {
  651. X    /* Use the entire chunk as one long name since this is in braces.
  652. X     * It may have its type changed, to VALUE for instance if % is the
  653. X     * next char */
  654. X    newBoolEntry(&argp[pos++], (*bitnump)++, oldform, form - oldform,
  655. X                    isBoolVar, pntcountp);
  656. X    } else {
  657. X    /* Assign the one character switch names to individual array places.  
  658. X     * The type of the last one may be changed, to VALUE for instance 
  659. X     * if the next char is a %. */
  660. X    while (oldform != form)
  661. X        newBoolEntry(&argp[pos++], (*bitnump)++, oldform++, 1,
  662. X                        isBoolVar, pntcountp);
  663. X    }
  664. X
  665. X/* skip the left bracket if there is one */
  666. X    if (leftBracket)
  667. X    ++form;
  668. X
  669. X/* if there is a %, set up the last switch as a VALUE, not a BOOL. */
  670. X    if (*form == '%') {
  671. X    int fmt_count;
  672. X
  673. X    --pos;
  674. X    argp[pos].optional = leftBracket;
  675. X    argp[pos].type |= VALUE_FLAG;
  676. X    form = copy_until(argp[pos].format, form, 
  677. X                leftBracket ? "]" : "} \t\n");
  678. X
  679. X    /* figure out how many variables-to-be-filled this will require */
  680. X    argp[pos].fmt_count = fmt_count = format_count(argp[pos].format);
  681. X
  682. X    /* show where the first variable-to-be-filled is unless this switch
  683. X     * also had a boolean variable-to-fill, in which case the position
  684. X     * of the variables is already set. */
  685. X    if (!isBoolVar)
  686. X        argp[pos].pnt_index = *pntcountp;
  687. X    *pntcountp += fmt_count;
  688. X
  689. X    *bitnump += fmt_count;
  690. X
  691. X    ++pos;
  692. X    }
  693. X
  694. X    if (leftBracket)
  695. X    if (*form++ != ']')
  696. X        Epitaph("argproc: missing closing ']' in format string");
  697. X
  698. X    if (wasBrace)
  699. X    if (*form++ != '}')
  700. X        Epitaph("argproc: missing closing '}' in format string");
  701. X
  702. X    *argpcountp = pos;
  703. X    return form;
  704. X}
  705. X
  706. X
  707. X/*----------------------------------------------------------------------
  708. X Analyse the contents of the argproc format string.  The result is an
  709. X array, one element per switch in the format string.  The number of
  710. X elements in the array is returned in *argpcountp.  The number of variables
  711. X needed to receive the values from the string is the return value.  That is,
  712. X if the string were "%f -x%d -q =y" the return value would be 3: 1 each for
  713. X the %f, the %d, and the =y variables.
  714. X-----------------------------------------------------------------------*/
  715. Xstatic int
  716. Xformat_parse(form, argp, argpcountp)
  717. X    char *form;
  718. X    argp_t *argp;
  719. X    int *argpcountp;
  720. X{
  721. X    int pntcount, bitnum;
  722. X
  723. X    *argpcountp = 0;
  724. X
  725. X    /* The position in the argument list of variables-to-be-filled. */
  726. X    pntcount = 0;
  727. X
  728. X    /* The output bit number to be affected by the current format entries */
  729. X    bitnum = 0;
  730. X
  731. X/* skip white space, process the next word of the format string */
  732. X    for (form += strspn(form, " \t\n"); *form; form += strspn(form, " \t\n")) {
  733. X    char c;
  734. X
  735. X    switch(*form++) {
  736. X    case '{': /* A multi-character name switch */
  737. X        if ((c = *form++) != '-' && c != '=')
  738. X        Epitaph("argproc: brace must start with a switch");
  739. X
  740. X        form = switchParse(form, argp, argpcountp, &bitnum, &pntcount, 
  741. X                                    TRUE);
  742. X        break;
  743. X    case '-': /* One or several concatenated switches */
  744. X    case '=': /* same as '-' but returns boolean result variable */
  745. X        form = switchParse(form, argp, argpcountp, &bitnum, &pntcount,
  746. X                                    FALSE);
  747. X        break;
  748. X    case '%': /* A normal scanf type format string argument */
  749. X        form = normArgParse(form, argp, argpcountp, &bitnum, &pntcount);
  750. X        break;
  751. X    default:
  752. X        Epitaph("argproc: invalid char (%c) in format string", *--form);
  753. X    }
  754. X    }
  755. X
  756. X    return pntcount;
  757. X}
  758. X
  759. X
  760. X/*----------------------------------------------------------------------
  761. X Set the variable corresponding to any BOOL_VAR types in the format string
  762. X to an initial value of FALSE; they will be reset to TRUE when the use
  763. X of that switch is discovered in the user argument string.
  764. X----------------------------------------------------------------------*/
  765. Xstatic void
  766. XinitBoolVar(vars, form, formCnt)
  767. X    char *vars[];
  768. X    argp_t *form;
  769. X    int formCnt;
  770. X{
  771. X    int i;
  772. X
  773. X    for (i=0; i<formCnt; ++i)
  774. X    if ((form[i].type & BOOL_VAR_FLAG) == BOOL_VAR_FLAG)
  775. X        *((boolean *)vars[ form[i].pnt_index ]) = FALSE;
  776. X}
  777. X
  778. X
  779. X/*----------------------------------------------------------------------
  780. X Read in up to argp->fmt_count values from indata using sscanf,
  781. X return with bits argp->bitnum+x set if the xth parameter was there.
  782. X----------------------------------------------------------------------*/
  783. Xstatic long 
  784. Xargscanf(indata, argp, ps, errMode)
  785. X    char *indata;
  786. X    argp_t *argp;
  787. X    char **ps;
  788. X    int errMode;
  789. X{
  790. X    long bits;
  791. X    int i, howmany, pos;
  792. X    char *p1, *p2, *p3, *p4;
  793. X
  794. X/* look up the position of the user variable to put the data into; if the
  795. X * format entry has a boolean variable too, skip that to get the position
  796. X * for the scanf. */
  797. X    pos = argp->pnt_index;
  798. X    if ((argp->type & BOOL_VAR_FLAG) == BOOL_VAR_FLAG)
  799. X    ++pos;
  800. X
  801. X/* set up the parameters that are needed for the sscanf. */
  802. X    switch (argp->fmt_count) {
  803. X    case 4: p4 = ps[pos + 3];
  804. X    case 3: p3 = ps[pos + 2];
  805. X    case 2: p2 = ps[pos + 1];
  806. X    case 1: p1 = ps[pos + 0];
  807. X    case 0: break;
  808. X    default:
  809. X    Epitaph("argproc: can only have 4 variables per argument");
  810. X    }
  811. X    howmany = sscanf(indata, argp->format, p1, p2, p3, p4);
  812. X
  813. X/* set the bit in the result for each parameter that was there */
  814. X    bits = 0;
  815. X    for (i=0; i<howmany; i++)
  816. X    bits |= 1 << (argp->bitnum+i);
  817. X    
  818. X    if (!argp->optional && howmany < 1 && argp->fmt_count > 0) {
  819. X    /* This error is caused by the user, not by the programmer,
  820. X     * so let the programmer say whether to abort or not
  821. X     */
  822. X    PrintErr(errMode, "argproc: bad or missing value for flag %s",
  823. X        argp->name);
  824. X    return ERROR;
  825. X    }
  826. X    
  827. X    return bits;
  828. X}
  829. X
  830. X
  831. X/*----------------------------------------------------------------------
  832. X Assign values from the user's switch to the appropriate variables.
  833. X 'str' is the contents of the switch, starting just after the '-'.
  834. X----------------------------------------------------------------------*/
  835. Xstatic long
  836. XprocessSwitch(str, form, formCnt, vars, errMode)
  837. X    char *str, *vars[];
  838. X    argp_t *form;
  839. X    int formCnt, errMode;
  840. X{
  841. X    int offset, j, ty;
  842. X    long found = 0;
  843. X
  844. X/* go through each character of the string looking for multiple switches */
  845. X    for (offset=0; str[offset] != '\0';) {
  846. X    /* check each of the format string entries to see if any match */
  847. X    for (j=0; j<formCnt; j++) {
  848. X        if ( (form[j].type & SWITCH) && strncmp(str+offset, form[j].name, 
  849. X                            strlen(form[j].name))==0) {
  850. X        /* skip over the name of the switch */
  851. X        offset += strlen(form[j].name);
  852. X
  853. X        /* mark that this switch was found */
  854. X        found |= 1 << form[j].bitnum;
  855. X
  856. X        ty = form[j].type;
  857. X
  858. X        if ((ty & BOOL_VAR_FLAG) == BOOL_VAR_FLAG)
  859. X            /* set the boolean variable to show the line had this
  860. X            switch */
  861. X            *((boolean *)vars[ form[j].pnt_index ]) = TRUE;
  862. X
  863. X        if ((ty & VALUE_FLAG) == VALUE_FLAG)
  864. X            /* if VALUE, no more string to examine after argscanf,
  865. X            so return. */
  866. X            return found | 
  867. X            (argscanf(str+offset, &form[j], vars, errMode) << 1);
  868. X
  869. X        /* don't have to do anything for BOOL_FLAG, since the 'found' 
  870. X            bit was already set by the code before this switch. */
  871. X
  872. X        /* go on to any other switches in the string */
  873. X        break;
  874. X        }
  875. X    }
  876. X
  877. X    /* if didn't find switch in format list, it's an error */
  878. X    if (j == formCnt) {
  879. X        PrintErr(errMode,"argproc: invalid flag -%s", str+offset);
  880. X        return ERROR;
  881. X    }
  882. X    }
  883. X
  884. X    return found;
  885. X}
  886. X
  887. X
  888. X/*----------------------------------------------------------------------
  889. X Go through the argument list, assigning values to the user's variables
  890. X as indicated by the format string breakdown.
  891. X----------------------------------------------------------------------*/
  892. Xstatic long
  893. XprocessArgs(form, formCnt, vars, argv, argCnt, errMode)
  894. X    argp_t *form;
  895. X    char *vars[], *argv[];
  896. X    int formCnt, argCnt, errMode;
  897. X{
  898. X    long found;
  899. X    int i, normArgPos;
  900. X
  901. X    found = 0;
  902. X
  903. X    /* go through the normal arguments in the format string in order as they
  904. X     * come off the command line. */
  905. X    normArgPos = 0;
  906. X
  907. X    for (i=1; i<argCnt; i++)
  908. X    /* if argument is a switch... */
  909. X    if (argv[i][0] == '-' && argv[i][1] != '\0')
  910. X        found |= processSwitch(argv[i] + 1, form, formCnt, vars, errMode);
  911. X        else
  912. X        /* argument is not a switch, must be a NORM_ARG */
  913. X        /* look for the next NORM_ARG from the format string */
  914. X        for(; normArgPos < formCnt; ++normArgPos)
  915. X        if (form[normArgPos].type == NORM_ARG) {
  916. X            found |= argscanf(argv[i], &form[normArgPos++], 
  917. X                            vars, errMode);
  918. X            break;
  919. X        }
  920. X
  921. X    return found;
  922. X}
  923. X
  924. X
  925. X/*----------------------------------------------------------------------
  926. X The actual argument list is argproc(argc, argv, format, vars . . .).  The
  927. X argc and argv are from the user's main(), the format is a switch describing
  928. X string, and the vars are pointers to variables like those passed to scanf
  929. X for receiving the values extracted from argv and arranged as indicated in
  930. X the format string.
  931. X----------------------------------------------------------------------*/
  932. Xint argproc(va_alist)
  933. X    va_dcl
  934. X{
  935. X    va_list ap;
  936. X    char **argv, *form;
  937. X    char *vars[MAX_ARGS];
  938. X    int argpcount, varCnt, i, argc, errMode;
  939. X    argp_t argp[MAX_ARGS];
  940. X
  941. X    va_start(ap);
  942. X
  943. X    argc = va_arg(ap, int);
  944. X    argv = va_arg(ap, char **);
  945. X    form = va_arg(ap, char *);
  946. X
  947. X    if (form == NULL)
  948. X    return 0;
  949. X
  950. X    switch (*form++) {
  951. X    case 'N': case 'n': errMode = ERR_NOTE;   break;
  952. X    case 'W': case 'w': errMode = ERR_WARN;   break;
  953. X    case 'F': case 'f': errMode = ERR_FATAL;  break;
  954. X    default : --form;   errMode = ERR_FATAL;  break;
  955. X    }
  956. X
  957. X/* setup argp with contents of format string, get how many arguments should
  958. X * be following the format string */
  959. X    if ((varCnt = format_parse(form, argp, &argpcount)) > MAX_ARGS)
  960. X    Epitaph("too many args. (limit %d)", MAX_ARGS);
  961. X    
  962. X/* load in the pointers for the rest of the args */
  963. X    for (i=0; i<varCnt; i++)
  964. X    vars[i] = va_arg(ap, char *);
  965. X
  966. X    va_end(ap);
  967. X
  968. X/* initialize the boolean variables to FALSE */
  969. X    initBoolVar(vars, argp, argpcount); 
  970. X
  971. X    return processArgs(argp, argpcount, vars, argv, argc, errMode);
  972. X}
  973. X
  974. X#endif        /* "ifndef lint" around real guts of module */
  975. XXX_EOF_XXX
  976. if test 16865 -ne "`wc -c < argproc.c`"
  977. then
  978.     echo 'shar: transmission error on "argproc.c"'
  979. fi
  980. chk=`sum argproc.c | awk '{print $1}'`
  981. if test 18141 -ne $chk -a 31035 -ne $chk
  982. then
  983.     echo 'shar: checksum error on "argproc.c"'
  984. fi
  985. echo 'shar: extracting "argproc.h" (99 characters)'
  986. # 'argproc.h' has a checksum of 55178 on BSD and 8130 on System V.
  987. sed 's/^X//' > argproc.h << 'XXX_EOF_XXX'
  988. X/* Include file for users of argproc(). */
  989. X#include "boolean.h"
  990. X#include "lose.h"
  991. X
  992. Xlong argproc();
  993. XXX_EOF_XXX
  994. if test 99 -ne "`wc -c < argproc.h`"
  995. then
  996.     echo 'shar: transmission error on "argproc.h"'
  997. fi
  998. chk=`sum argproc.h | awk '{print $1}'`
  999. if test 55178 -ne $chk -a 8130 -ne $chk
  1000. then
  1001.     echo 'shar: checksum error on "argproc.h"'
  1002. fi
  1003. echo 'shar: extracting "lose.c" (4704 characters)'
  1004. # 'lose.c' has a checksum of 43151 on BSD and 15971 on System V.
  1005. sed 's/^X//' > lose.c << 'XXX_EOF_XXX'
  1006. X/*--------------------------------------------------------------------------
  1007. X Routines to build and print error messages.
  1008. X Includes:  ErrStr, ProgTitle, lose_title(), lose(), warn(), and PrintErr().
  1009. X--------------------------------------------------------------------------*/
  1010. X
  1011. X#include <stdio.h>
  1012. X#include <string.h>
  1013. X#include <varargs.h>
  1014. X#include <errno.h>
  1015. X#include "lose.h"
  1016. X
  1017. X/*LINTLIBRARY*/
  1018. X#ifndef lint
  1019. Xstatic char Sccs_id[] = "@(#)lose.c    from 1.16 5/31/87 (C) SRS";
  1020. X#endif
  1021. X
  1022. X#define MAX_STR_LEN 200
  1023. X#define MAX_ERR_STR_LEN 1000
  1024. X
  1025. X/* Private variables */
  1026. Xstatic char title[MAX_STR_LEN] = "program_name";
  1027. Xstatic char errorString[MAX_ERR_STR_LEN] = "";
  1028. X
  1029. X/* Public variables */
  1030. Xchar *ProgTitle = title;
  1031. Xchar *ErrStr = errorString;
  1032. X
  1033. X/*--------------------------------------------------------------------------
  1034. X Store the title of the program, initialize errno to zero.
  1035. X--------------------------------------------------------------------------*/
  1036. Xvoid
  1037. Xlose_title(name)
  1038. X    char *name;
  1039. X{
  1040. X    errno = 0;
  1041. X    ProgTitle[MAX_STR_LEN-1] = '\0';
  1042. X    (void) strncpy(ProgTitle, name, MAX_STR_LEN-1);
  1043. X}
  1044. X
  1045. X
  1046. X/*--------------------------------------------------------------------------
  1047. X Build an error message, then maybe print it to stderr and maybe exit,
  1048. X as indicated by errMode.
  1049. X--------------------------------------------------------------------------*/
  1050. X
  1051. Xstatic void
  1052. X_print_error(errMode, format, ap)
  1053. X    int errMode;
  1054. X    char *format;
  1055. X    va_list ap;
  1056. X{
  1057. X    extern int sys_nerr;
  1058. X    extern char *sys_errlist[];
  1059. X
  1060. X    /* Print the program name to the buffer */
  1061. X    (void) sprintf(ErrStr, "%s: ", ProgTitle);
  1062. X
  1063. X    /* Append the message to the buffer */
  1064. X    vsprintf(ErrStr + strlen(ErrStr), format, ap);
  1065. X
  1066. X    /* Append the system error message, if any */
  1067. X    if (errno > 0 && errno < sys_nerr) {
  1068. X    (void) strcat(ErrStr, "-- ");
  1069. X    (void) strcat(ErrStr, sys_errlist[errno]);
  1070. X    }
  1071. X
  1072. X    /* Print the message to the console and/or exit, as indicated by errMode */
  1073. X    switch(errMode) {
  1074. X    case ERR_FATAL: 
  1075. X    (void) fprintf(stderr, "%s\n", ErrStr);
  1076. X    exit(1);
  1077. X    break;
  1078. X    case ERR_WARN: 
  1079. X    (void) fprintf(stderr, "%s\n", ErrStr);
  1080. X    break;
  1081. X    case ERR_NOTE: 
  1082. X    break;
  1083. X    default:
  1084. X    (void) fprintf(stderr, "%s\n", ErrStr);
  1085. X    lose("illegal call to PrintErr with error mode %d\n", errMode);
  1086. X    break;
  1087. X    }
  1088. X}
  1089. X
  1090. X/*--------------------------------------------------------------------------
  1091. X Lint definitions to make lint shut up...
  1092. X you may safely omit this section if you don't use lint.
  1093. X--------------------------------------------------------------------------*/
  1094. X#ifdef lint
  1095. X    /*ARGSUSED*/
  1096. X    /*VARARGS1*/            /* Only check first argument */
  1097. X    void warn(message) char *message;    /* First arg must be char *  */
  1098. X    { message[0]=0; }            /* Dummy function body       */
  1099. X
  1100. X    /*ARGSUSED*/
  1101. X    /*VARARGS1*/            /* Only check first argument */
  1102. X    void lose(message) char *message;    /* First arg must be char *  */
  1103. X    { message[0]=0; }            /* Dummy function body       */
  1104. X
  1105. X    /*ARGSUSED*/
  1106. X    /*VARARGS1*/            /* Only check first argument */
  1107. X    void Epitaph(message) char *message;/* First arg must be char *  */
  1108. X    { message[0]=0; }            /* Dummy function body       */
  1109. X
  1110. X    /*ARGSUSED*/
  1111. X    /*VARARGS2*/            /* Check first 2 arguments   */
  1112. X    void PrintErr(errMode, message)
  1113. X    int errMode;            /* First arg must be int     */
  1114. X    char *message;            /* Second arg must be char * */
  1115. X    { message[0]=(char)errMode; }    /* Dummy function body       */
  1116. X#else
  1117. X
  1118. X/*--------------------------------------------------------------------------
  1119. X Various methods of calling _print_error():
  1120. X
  1121. X For nonfatal errors:
  1122. X    warn(format, ...)    -> _print_error(ERR_WARN,  format, ...)
  1123. X
  1124. X For fatal I/O errors (this one is the most useful):
  1125. X    lose(format, ...)    -> _print_error(ERR_FATAL, format, ...)
  1126. X
  1127. X For fatal non-I/O errors:
  1128. X    Epitaph(format, ...) -> errno=0, _print_error(ERR_FATAL, format, ...)
  1129. X
  1130. X For nonfatal errors when you don't want message printed to stderr:
  1131. X    PrintErr(errMode, format, ...) -> _print_error(errMode, format, ...)
  1132. X--------------------------------------------------------------------------*/
  1133. X/*VARARGS2*/
  1134. Xvoid
  1135. XPrintErr(errMode, format, va_alist)
  1136. X    int errMode;
  1137. X    char *format;
  1138. X    va_dcl
  1139. X{
  1140. X    va_list ap;
  1141. X    va_start(ap);
  1142. X    _print_error(errMode, format, ap);
  1143. X}
  1144. X
  1145. X/*VARARGS1*/
  1146. Xvoid
  1147. Xwarn(format, va_alist)
  1148. X    char *format;
  1149. X    va_dcl
  1150. X{
  1151. X    va_list ap;
  1152. X    va_start(ap);
  1153. X    _print_error(ERR_WARN, format, ap);
  1154. X}
  1155. X
  1156. X/*VARARGS1*/
  1157. Xvoid
  1158. Xlose(format, va_alist)
  1159. X    char *format;
  1160. X    va_dcl
  1161. X{
  1162. X    va_list ap;
  1163. X    va_start(ap);
  1164. X    _print_error(ERR_FATAL, format, ap);
  1165. X}
  1166. X
  1167. X/*VARARGS1*/
  1168. Xvoid
  1169. XEpitaph(format, va_alist)
  1170. X    char *format;
  1171. X    va_dcl
  1172. X{
  1173. X    va_list ap;
  1174. X    va_start(ap);
  1175. X    errno = 0;
  1176. X    _print_error(ERR_FATAL, format, ap);
  1177. X}
  1178. X
  1179. X#endif
  1180. XXX_EOF_XXX
  1181. if test 4704 -ne "`wc -c < lose.c`"
  1182. then
  1183.     echo 'shar: transmission error on "lose.c"'
  1184. fi
  1185. chk=`sum lose.c | awk '{print $1}'`
  1186. if test 43151 -ne $chk -a 15971 -ne $chk
  1187. then
  1188.     echo 'shar: checksum error on "lose.c"'
  1189. fi
  1190. echo 'shar: extracting "lose.h" (123 characters)'
  1191. # 'lose.h' has a checksum of 51399 on BSD and 9611 on System V.
  1192. sed 's/^X//' > lose.h << 'XXX_EOF_XXX'
  1193. X#define ERR_FATAL 1
  1194. X#define ERR_WARN  2
  1195. X#define ERR_NOTE  3
  1196. X
  1197. Xvoid lose_title();
  1198. Xvoid lose();
  1199. Xvoid warn();
  1200. Xvoid PrintErr();
  1201. XXX_EOF_XXX
  1202. if test 123 -ne "`wc -c < lose.h`"
  1203. then
  1204.     echo 'shar: transmission error on "lose.h"'
  1205. fi
  1206. chk=`sum lose.h | awk '{print $1}'`
  1207. if test 51399 -ne $chk -a 9611 -ne $chk
  1208. then
  1209.     echo 'shar: checksum error on "lose.h"'
  1210. fi
  1211. echo 'shar: extracting "makeargv.doc" (965 characters)'
  1212. # 'makeargv.doc' has a checksum of 52222 on BSD and 13347 on System V.
  1213. sed 's/^X//' > makeargv.doc << 'XXX_EOF_XXX'
  1214. Xmakeargv - build an argv-style array from a string
  1215. X
  1216. XSYNOPSIS
  1217. X     int makeargv(str, argvp)
  1218. X     char *str;
  1219. X     char ***argvp;
  1220. X
  1221. XDESCRIPTION
  1222. X    makeargv breaks up an ordinary string into a count and array like
  1223. X    those passed to main() as argc & argv.
  1224. X    Argv is MALLOC'd in makeargv; to free it, call FREE(argv).
  1225. X
  1226. X    The first arg is placed in argv[0].
  1227. X    The original string is peppered with null chars to mark the ends of
  1228. X    the args, and argv[i] is filled with pointers into the original string.
  1229. X    An extra entry of NULL is included in argv, at argv[argc], for routines 
  1230. X    that use a final NULL for loop termination.
  1231. X
  1232. XEXAMPLE
  1233. X    #include "argproc.h"
  1234. X    char **argv;
  1235. X    int argc;
  1236. X    char cmdline[256], arg[256];
  1237. X    boolean xflag;
  1238. X
  1239. X    gets(cmdline);
  1240. X    argc = makeargv(cmdline, &argv);
  1241. X    argproc(argc+1, argv-1, "%s =x", arg, &xflag);
  1242. X
  1243. XBUGS
  1244. X    Perhaps this should set argv[0] to the empty string
  1245. X    to be more compatible with the real argv[].
  1246. XXX_EOF_XXX
  1247. if test 965 -ne "`wc -c < makeargv.doc`"
  1248. then
  1249.     echo 'shar: transmission error on "makeargv.doc"'
  1250. fi
  1251. chk=`sum makeargv.doc | awk '{print $1}'`
  1252. if test 52222 -ne $chk -a 13347 -ne $chk
  1253. then
  1254.     echo 'shar: checksum error on "makeargv.doc"'
  1255. fi
  1256. echo 'shar: extracting "makeargv.c" (1193 characters)'
  1257. # 'makeargv.c' has a checksum of 37514 on BSD and 18775 on System V.
  1258. sed 's/^X//' > makeargv.c << 'XXX_EOF_XXX'
  1259. X#include <string.h>
  1260. X#include <ctype.h>
  1261. X#include "boolean.h"
  1262. X
  1263. X#ifndef NULL
  1264. X#define NULL 0L
  1265. X#endif
  1266. X
  1267. X#define MAX_ARGS 1000
  1268. X
  1269. X/*----------------------------------------------------------------------
  1270. X Given a string, extracts the arguments (separated by white-space) 
  1271. X and creates an argv type array full of pointers to the input string. 
  1272. X Modifies the input string.
  1273. X Returns the count of arguments.
  1274. X----------------------------------------------------------------------*/
  1275. Xint
  1276. Xmakeargv(s, argvp)
  1277. X    char *s, ***argvp;
  1278. X{
  1279. X    int cnt=0;
  1280. X    char *vals[MAX_ARGS];    /* temporary argv until we know argc */
  1281. X
  1282. X    while (TRUE) {
  1283. X    s += strspn(s, " \t\n");
  1284. X    if (*s == '\0')
  1285. X        break;
  1286. X
  1287. X    if (cnt >= MAX_ARGS)
  1288. X        lose("%s: only %d args allowed to makeargv", MAX_ARGS);
  1289. X
  1290. X    if (*s == '"') {
  1291. X    /* if the quote is unmatched, just stop processing */
  1292. X        vals[cnt] = s;
  1293. X        if ((s = strchr(s, '"')) == NULL)
  1294. X        break;
  1295. X
  1296. X        ++cnt;
  1297. X        *s++ = '\0';
  1298. X    } else {
  1299. X        vals[cnt++] = s;
  1300. X        s += strcspn(s, " \n\t");
  1301. X        if (*s == '\0')
  1302. X        break;
  1303. X        else
  1304. X        *s++ = '\0';
  1305. X    }
  1306. X    }
  1307. X
  1308. X    *argvp = malloc(sizeof(char *) * (cnt+1));
  1309. X
  1310. X    vals[cnt] = 0;
  1311. X    bcopy(vals, *argvp, (cnt+1) * sizeof(char *));
  1312. X
  1313. X    return cnt;
  1314. X}
  1315. XXX_EOF_XXX
  1316. if test 1193 -ne "`wc -c < makeargv.c`"
  1317. then
  1318.     echo 'shar: transmission error on "makeargv.c"'
  1319. fi
  1320. chk=`sum makeargv.c | awk '{print $1}'`
  1321. if test 37514 -ne $chk -a 18775 -ne $chk
  1322. then
  1323.     echo 'shar: checksum error on "makeargv.c"'
  1324. fi
  1325.