home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / compsrcs / misc / volume02 / argproc < prev    next >
Encoding:
Internet Message Format  |  1991-08-27  |  41.9 KB

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