

/* Copyright (c) 1991, 1992 Greg Klanderman.  All Rights Reserved.
 *
 * Use, reproduction and preparation of derivative works of this software is
 * permitted.  Any copy of this software or of any derivative work must
 * include both the above copyright notices of Greg Klanderman and this
 * paragraph.  This software is made available AS IS, and Greg Klanderman
 * disclaims all warranties, express or implied.
 */



 
#ifndef _INC_CLARG_
#define _INC_CLARG_
 
#if      0
/*

  to do:  rename functions, argument names, and constants
          handle more option kinds:
                 - options which can be specified mult times
                 - sub-options or order dependent
                 - aliases
          clean up parser, use ENVP?
          
  
BEGIN DOCUMENTATION


clarg.h --  Powerful command line argument interface for C programs 
            Written by Greg Klanderman, Summer 1991
 
  
USAGE: 

cl_init(argc, argv, envp, init, require, usage, restrict) must be called to
initialize command line argument processing.  It returns 0 upon successful
completion, 1 if an error occurs.

It must be passed ARGC, ARGV, and ENVP as indicated.  USAGE is a (possibly
long) string containing one and only one "%s".  USAGE is printed if an error
is encountered in command line argument parsing.  The "%s" is replaced by the
program name.  INIT is an array of structures to specify the format of command
line argument processing.

Its fields hold: NAME - the name of the command line option.
                 MIN  - the min # args the option can take if specified.
                 MAX  - the max # args the option can take if specified.
                 TYPE - function to type check the arguments.
                           cl_int          => integer arguments
                           cl_real         => real arguments
                           NULL            => no type checking
                           CL_TYPECHKFN fn => your own type check function
                 KIND - what kind of argument
                           0 => space separated (eg -o foo.out)
                           1 => not (eg -Pprinter)

The array must be terminated with an entry with NAME = NULL.  This entry marks
the end of the list and also tells how processing should proceed for "unnamed"
arguments.  For example, in "cc -o prog prog.c a.c b.c", "prog.c", "a.c", and
"b.c" are unnamed.

For the option names, a period in the string marks the part before the period
as being the shortest prefix required to generate that option.  For example,
"z.oom" says that all of "z", "zo", "zoo", and "zoom" will generate the "zoom"
option.  cl_init() does not check to make sure no two option names have the
same prefix. There is no conflict having "z.oom" and "za.p", but adding "za.t"
would be bad.
 
  eg:  CLINIT init[] = {{"a",  1, 1, NULL,   0},
			{"b",  0, 0, NULL,   0},
		        {"c",  1, 2, cl_int, 0},
		        {"d",  1, 1, cl_int, 1},
		        {NULL, 2, 4, NULL,   0}};

  allows option "-a" to take one and only one argument, "-b" is a switch, and
  "-c" can take one or two arguments. There can be 0, 2, 3, or 4 "unnamed"
  arguments.  Types are as specified.  In addition, "-d" takes one integer
  argument appended to the "-d" switch.

The argument RESTRICT to cl_init()  has 3 possible values:
  CL_NORESTRICT -- No restrictions on option packing
  CL_OPTPACK    -- Only switches (max==min==0) can be packed.  For example, if
                   "a" and "b" are switches, "-a -b" could also be written "-ab"
  CL_NOPACK     -- Neither switch namesnor option names may be packed.

The argument REQUIRE to cl_init() is a NULL terminated array of character
strings.  Each is evaluated in turn and if any returns false, an error is
signalled.  In each string the ordinary C operators are allowed on integers
and booleans.  Option names appearing as "variables" evaluate to whether the
option was specified.  The "#" prefix operator tells how many arguments were
specified for an option name.

For example, with arguments "foo", "bar", and "baz",

   "foo"                  -- says "foo" must be specified.
   "#bar % 2 == 0"        -- says "bar" must be given an even number of arguments.
   "foo + bar + baz == 1" -- says exactly one of the options must be specified. 
  
Requiring the "UNNAMED" argument has slightly different meaning: if not
required, zero unnamed arguments are allowed along with the usual MIN..MAX.

cl_opt(str) is a boolean function that returns 1 iff the option STR was
specified.  if STR == NULL, cl_opt() tells if there were any unnamed
arguments.
 
cl_arg(str, n) returns the Nth argument for option STR. If STR == NULL, the
Nth unnamed argument is returned.  The return is CL_ARGDNE if the argument
specified does not exist.
 
cl_numarg(str) tells how many arguments were specified for option STR, or how
many unnamed arguments there were if STR == NULL.  The return is CL_NUMERR if
the option was not specified.
 
cl_arg1(str), cl_arg2(str), cl_arg3(str), cl_unnamed(), and cl_numunnamed()
are provided for convenience.
 
Typechecking functions take the argument and the argument number and return a
(possibly filtered) string if the argument is OK, or NULL otherwise.

PARSING

Look at ARGV[1..ARGC-1]. Any string starting with '-' specifies one or more
options.  The option name list given in INIT is searched for the longest
matching option name prefix.  When the proper option is matched its arguments
are extracted from the ARGV[]s that follow.  Finding an ARGV[] starting with
'-', exceeding MAX, or finding an argument of the wrong type terminates
extraction of arguments for the current option.  Any remaining characters in
the original string that the option name was found in are now used as the next
option name (more than one option name allowed per option string), and its
args are gotten.  Any ARGV[n] that does not start with '-' and is not used as
an argument is considered "unnamed".  The options "-!" and "-?" are designated
the help options - USAGE is printed with no error message.  Note, you'll
probably have to use "-\!"  and "-\?" to escape the special shell characters.

The option "##" appearing as the first argument turns on verbose reporting of
error messages.

The option "-" alone allows a stop to a variable # of arguments for an option.
eg: "xyz -a 2.0 - 3.0" forces only one argument for "-a" and makes 3.0 unnamed.


END DOCUMENTATION
*/
#endif
 
/* definitions for command line arg processing */
 
#define TRUE  1
#define FALSE 0
 
 
typedef int bool;
typedef char *(*CL_TYPCHKFN)(char *s, long n);		/* type for a typecheck fn (ptr) */
 
 
typedef struct		/* structure used to initialize clarg */
{
  char *name;		/* name of option:  "-abcd" => name = "abcd" */
  long  min;		/* min number of arguments to this option */
  long  max;		/* max number of arguments to this option */
  CL_TYPCHKFN  typchk;	/* type check fun or NULL for no check */
  long  type; 		/* standard(0) or -Pcalumny(1) */
} CLINIT;
 
 
extern bool  cl_init(long argc, char **argv, char **envp, CLINIT *init,
		     char **depend, char *usage, long restrict);
extern bool  cl_opt(char *str);
extern char *cl_arg(char *str, long n);
extern long  cl_numarg(char *str);
extern char *cl_notype(char *s, long n);
extern char *cl_real(char *s, long n);
extern char *cl_int(char *s, long n);
extern char *argstring(int argc, char **argv);

 
/* get args 1, 2, or 3 for option STR */
 
#define cl_arg1(str)	cl_arg(str, 1)
#define cl_arg2(str)	cl_arg(str, 2)
#define cl_arg3(str)	cl_arg(str, 3)
 
 
/* option name for unnamed arguments */
 
#define CL_UNNAMED NULL
 
 
/* get unnamed argument N */
 
#define cl_unnamed(n)	cl_arg(CL_UNNAMED, n)
#define cl_numunnamed() cl_numarg(CL_UNNAMED)
 
 
/* error returns */
 
#define CL_ARGDNE NULL	/* returned by cl_arg() if arg does not exist */
#define CL_NUMERR (-1)  /* returned by cl_numarg() if option not specified */
 
#define CL_NORESTRICT	0
#define CL_OPTPACK	1
#define CL_NOPACK	2
 
#define CL_STDARG	0
#define CL_XXXARG	1
 
 
#endif
