/* arg_parse.h:  defs for expr eval, arg parsing */

#ifndef ARGPARSE_HDR
#define ARGPARSE_HDR

/* system include */
#include <stdio.h>
#include <varargs.h>
#include <stdlib.h>
#include <assert.h>

/* better than standard assert.h: doesn't gag on 'if (p) assert(q); else r;' */
/* #define assert(p) if (!(p)) \
   { \
   fprintf(stderr, "Assertion failed: %s line %d\n", __FILE__, __LINE__); \
   exit(1); \
   } \
   else */

#define str_eq(a, b)	(strcmp(a, b) == 0)
#define MIN(a, b)	((a)<(b) ? (a) : (b))
#define MAX(a, b)	((a)>(b) ? (a) : (b))
#define ABS(a)		((a)>=0 ? (a) : -(a))
#define SWAP(a, b, t)	{t = a; a = b; b = t;}
#define LERP(t, a, b)	((a)+(t)*((b)-(a)))
/* #define ALLOC(ptr, type, n)  ptr = (type *)malloc((n)*sizeof(type)) */
#define ALLOC(ptr, type, n)  assert(ptr = (type *)malloc((n)*sizeof(type)))
#define ALLOC_ZERO(ptr, type, n)  assert(ptr = (type *)calloc(n, sizeof(type)))

#define PI 3.14159265358979323846264338
#define RAD_TO_DEG(x) ((x)*(180./PI))
#define DEG_TO_RAD(x) ((x)*(PI/180.))
#define rad 2*PI

/* note: the following are machine dependent! (ifdef them if possible) */
#define MINSHORT -32768
#define MINLONG -2147483648
#define MININT MINLONG
#ifndef MAXINT	/* sgi has these in values.h */
#   define MAXSHORT 32767
#   define MAXLONG 2147483647
#   define MAXINT MAXLONG
#endif

#ifdef hpux	/* hp's unix doesn't have bzero */
#   define bzero(a, n) memset(a, 0, n)
#endif

/* error codes */
#define EXPR_GOOD	0	/* expression totally good */
#define EXPR_SOSO	-1	/* expression partially good */
#define EXPR_BAD	-2	/* expression totally bad */

extern int expr_error;		/* holds error code after expr_eval */

#ifdef __cplusplus
    extern "C" {
	int expr_eval_int(char *str);
	long expr_eval_long(char *str);
	double expr_eval(char *str);
    }
#else
    int expr_eval_int();
    long expr_eval_long();
    double expr_eval();
#endif

typedef struct arg_form {	/* ARGUMENT FORM */

    /* a "form" contains the format, doc string, and miscellaneous internal */
    /* info about an argument.  It's an argument descriptor, basically */

    struct arg_form *next;	/* next in linked list */
    char *format;		/* scanf-style format:    "-size %d %F" */
    char *flag;			/* flag portion of format:"-size" */
    char *code;			/* just the format codes: "dF" */
    char *doc;			/* documentation string:  "set widget size" */
    short type;			/* REGULAR | SIMPFLAG | PARAMFLAG |
					SUBRFLAG | SUBLISTFLAG | NOP */
    short nparam;		/* number of parameters to flag */
    int parammask;		/* bit i says ok to stop before param i, i=0..*/
    int **param; 		/* parameter pointer list */
    int (*subr)();		/* subroutine to call for action (if any) */
    struct arg_form *sublist;	/* subordinate list (if any) */
    short rep;			/* # times this flag repeated in arglist */
} Arg_form;

/* form type values */
#define ARG_REGULAR	1	/* a regular argument */
#define ARG_SIMPFLAG	2	/* a simple flag (no parameters) */
#define ARG_PARAMFLAG	3	/* a flag with parameters */
#define ARG_SUBRFLAG	4	/* a flag with subroutine action */
#define ARG_SUBLISTFLAG	5	/* a sub-formlist */
#define ARG_NOP		6	/* no arg or flag, just a doc string */

/* the following must be impossible pointer values (note: machine-dependent) */
#define ARG_MASKNEXT	0x80000000	/* mask for these NEXT flags */
#define ARG_FLAGNEXT	0x80000001
#define ARG_SUBRNEXT	0x80000002
#define ARG_LISTNEXT	0x80000003

/* varargs tricks */
#define ARG_FLAG(ptr)		ARG_FLAGNEXT, (ptr)	/* for SIMPFLAG */
#define ARG_SUBR(ptr)		ARG_SUBRNEXT, (ptr)	/* for SUBRFLAG */
#define ARG_SUBLIST(ptr)	ARG_LISTNEXT, (ptr)	/* for SUBLISTFLAG */

/* error codes: BADCALL is a programmer error, the others are user errors */
#define ARG_BADCALL	-1	/* arg_parse call itself is bad */
#define ARG_BADARG	-2	/* bad argument given */
#define ARG_MISSING	-3	/* argument or parameter missing */
#define ARG_EXTRA	-4	/* extra argument given */

#define ARG_NARGMAX 10000 /* max number of allowed args */

extern int arg_debug, arg_doccol;
extern int arg_warning;   /* print warnings about repeated flags? */
Arg_form *arg_to_form1(), *arg_find_flag(), *arg_find_reg();

#ifdef __cplusplus
    extern "C" {
	int arg_parse(int ac, char **av ...);
	int arg_parse_argv(int ac, char **av, Arg_form *form);
	int arg_parse_stream(FILE *fp, Arg_form *form);
	Arg_form *arg_to_form(...);
	int arg_form_print(Arg_form *form);
    }
#else
    Arg_form *arg_to_form();
#endif

#endif
