/* opt.c version 3.17 ... modified for Cygwin windows compatibility (varargs.h replaced by stdarg.h) OPT is a subroutine library which facilitates the convenient input of parameters to a C or C++ program. Parameters are parsed from a command line, with further facilities for reading options from files, from environment strings, or from an interactive environment. The aim of the opt package is to permit programs to be both user- and programmer- friendly. The package attempts to on the one hand provide a direct and relatively full-featured input interface to the ultimate user of the program, and at the same time impose a minimal amount of work on the programmer to "attach" the package to his or her software. A texinfo file is part of the distribution; or you can view the html documentation at: http://nis-www.lanl.gov/~jt/Software/opt/opt_toc.html Download the lastest version of the source code from: http://nis-www.lanl.gov/~jt/Software/ opt is available to the public under the GNU General Public License: http://www.gnu.org/copyleft/gpl.html This SOFTWARE has been authored by an employee of the University of California, operator of the Los Alamos National Laboratory under Contract No. W-7405-ENG-36 with the U.S. Department of Energy. The U.S. Government has rights to use, reproduce, and distribute this SOFTWARE. The public may copy, distribute, prepare derivative works and publicly display this SOFTWARE without charge, provided that this Notice and any statement of authorship are reproduced on all copies. Neither the Government nor the University makes any warranty, express or implied, or assumes any liability or responsibility for the use of this SOFTWARE. If SOFTWARE is modified to produce derivative works, such modified SOFTWARE should be clearly marked, so as not to confuse it with the version available from LANL. */ #define SINGLEFILE 1 #ifndef DISABLE_VARARGS #define DISABLE_VARARGS 0 #endif #ifndef DISABLE_LONGJUMP #define DISABLE_LONGJUMP 0 #endif #ifndef DISABLE_SIGNAL #define DISABLE_SIGNAL 0 #endif #include #ifdef convex #include #else #include #endif #ifdef __TURBOC__ #include #include #endif #include #if !DISABLE_LONGJUMP #include #endif #if !DISABLE_SIGNAL #include #endif #if !DISABLE_VARARG #ifdef __TURBOC__ #include #else #include #endif #endif static char gstr[160]; /* generally useful global string */ /* opt.h */ /* User Include File for options package */ #ifndef _OPT_H #define _OPT_H /* Signal that this header file has been included */ /* * These are delimiter characters */ #define DELIM '-' /* option delimiter character */ #define ALTDELIM '/' /* alternate delimiter character */ #define OPTFROMFILE '@' /* denotes options are in a file */ #define OPTTOFILE '%' /* says to put options in a file */ #define DOCUMENT '-' /* write document to file */ #define INTERACT '$' /* Flags interactive menu */ #define HELPCH '?' /* Help character */ /* * These are not available on command line * But may be invoked from a file */ #define IGNOREEOL ';' /* Ignore until the end of line */ #define RUN '=' /* Says to just run to completion */ #define QUITCH '.' /* Quit character */ /* * These are not available on command line or from a file * But may be invoked from the menu */ #define BANG '!' /* Shell escape character */ #define ADDITIONAL_OPTS '+' /* Additional options */ typedef enum { INT, UNSINT, LONG, CHAR, INTLEVEL, FLOAT, DOUBLE, FLAG, NEGFLAG, ABSFLAG, ABSNEGFLAG, VSTRING, CSTRING, UNDELIMV, UNDELIMC } opt_TYPE; typedef int (*PFI)(); #define OPT_EXT ".opt" /* standard options file extension */ #ifndef TRUE #define TRUE 1 #define FALSE 0 #endif #ifndef ARGCHECK #ifdef __TURBOC__ #define ARGCHECK #endif /* __TURBOC__ */ #ifdef __cplusplus #define ARGCHECK #endif /* __cplusplus */ #endif /* ARGCHECK */ #ifdef ARGCHECK extern int opt_register(char *,opt_TYPE,char,char *); extern void opt_usage_set(char *); extern void opt_title_set(char *); extern void opt_verify_set(PFI); extern void opt_doc_set(PFI); extern void opt_quit_set(PFI); extern void opt_run_set(PFI); extern void opt_help_setf(PFI); extern void opt_help_set(char,char *); extern void opt_ufilter_set(PFI); extern void opt_dfilter_set(PFI); extern void opt_env_set(char *); extern void opt_default_set(char *); #if DISABLE_VARARGS extern void opt_errmess(char *); extern void opt_message(char *); extern void opt_warning(char *); extern void opt_fatal(char *); #else extern void opt_errmess(); extern void opt_message(); extern void opt_warning(); extern void opt_fatal(); #endif /* DISABLE_VARARGS */ extern void opt_abort_run(void); extern int opt_begin_run(PFI); extern int getopts(int,char **); #else extern int opt_register(); extern void opt_usage_set(); extern void opt_title_set(); extern void opt_verify_set(); extern void opt_doc_set(); extern void opt_quit_set(); extern void opt_run_set(); extern void opt_help_setf(); extern void opt_help_set(); extern void opt_help_set(); extern void opt_ufilter_set(); extern void opt_dfilter_set(); extern void opt_env_set(); extern void opt_default_set(); extern void opt_errmess(); extern void opt_message(); extern void opt_warning(); extern void opt_fatal(); extern void opt_abort_run(); extern int opt_begin_run(); extern int getopts(); #endif /* ARGCHECK */ /********************************* * Macro's for registering options */ #define optregister(val,typ,c,str) opt_register((char *)&val,typ,c,str) #define optrunset(r) {int r(); opt_run_set( r );} #endif /* _OPT_H */ /* ag.h */ #ifndef _AG_H #define _AG_H #ifndef TRUE #define TRUE 1 #define FALSE 0 #endif /************************************* * ARGVECTOR structure * Basically, an (argc,argv) construct * with indices to which character of * which word is the current position */ typedef struct { char **v; /* argument vector */ int c; /* argument count */ int iw; /* current word */ int ic; /* current character */ } ARGVECTOR; /* * Function prototypes */ #ifdef ARGCHECK extern ARGVECTOR *ag_new(int,char **,ARGVECTOR *); extern int ag_enstring(char *,ARGVECTOR *,int); extern void ag_reset(ARGVECTOR *); extern int ag_w_number(ARGVECTOR *); extern void ag_w_advance(ARGVECTOR *); extern int ag_eow(ARGVECTOR *); extern int ag_end(ARGVECTOR *); extern char ag_c(ARGVECTOR *); extern char ag_c_next(ARGVECTOR *); extern char ag_cnn_next(ARGVECTOR *); extern char ag_c_advance(ARGVECTOR *); extern char ag_backspace(ARGVECTOR *); extern char *ag_s(ARGVECTOR *); extern char *ag_s_next(ARGVECTOR *); extern char *ag_s_advance(ARGVECTOR *); extern char *argnext(ARGVECTOR *); extern double argnextnum(ARGVECTOR *); #else extern ARGVECTOR *ag_new(); extern int ag_enstring(); extern void ag_reset(); extern int ag_w_number(); extern void ag_w_advance(); extern int ag_eow(); extern int ag_end(); extern char ag_c(); extern char ag_c_next(); extern char ag_cnn_next(); extern char ag_c_advance(); extern char ag_backspace(); extern char *ag_s(); extern char *ag_s_next(); extern char *ag_s_advance(); extern char *argnext(); extern double argnextnum(); #endif /* ARGCHECK */ #endif /* _AG_H */ /* opt_p.h */ /* * Private header file for OPT package. */ #ifndef _OPT_P_H #define _OPT_P_H #define OPT_MAXSTRLEN 80 #ifndef TRUE #define TRUE 1 #define FALSE 0 #endif #ifndef OKAY #define OKAY 0 #define NOT_OKAY (-1) #endif #ifndef DEBUG #define DEBUG 0 #endif typedef enum { False=FALSE, True=TRUE } flag; /****************** * Global variables */ extern int nregopts; /* Number of registered options */ extern flag menuflag; /* Is menu ON? */ extern flag fileflag; /* Are options being read from a file? */ /********************* * Function Prototypes */ #ifndef ARGCHECK #ifdef __TURBOC__ #define ARGCHECK #endif /* __TURBOC__ */ #endif /* ARGCHECK */ #ifdef ARGCHECK extern int opt_register(char *,opt_TYPE,char,char *); extern int opt_number(char); extern int opt_fprint(FILE *,int); extern int opt_tofile(FILE *); extern char *optstrval(int); extern char *optstrtyp(int); extern int opt_undelim(ARGVECTOR *); extern int opt_delim(ARGVECTOR *); extern void opt_get_help(char); #else extern int opt_register(); extern int opt_number(); extern int opt_fprint(); extern int opt_tofile(); extern char *optstrval(); extern char *optstrtyp(); extern int opt_undelim(); extern int opt_delim(); extern void opt_get_help(); #endif /* --------------- */ /* Process Options */ /* --------------- */ extern char *opt_program_name; extern PFI dfilter_fcn, ufilter_fcn, verify_fcn, doc_fcn, quit_fcn, help_fcn, run_fcn; #ifdef ARGCHECK extern void opt_wr_title(void); extern void opt_process(int,char **); extern int opt_fromfname(char *); extern int opt_tofname(char *); extern int opt_getline(char *,FILE *); extern char *opt_mstring(int); extern int opt_number(char); extern char *short_progname(char *); extern int opt_undelim(ARGVECTOR *); extern int opt_delim(ARGVECTOR *); extern void opt_menu(void); extern void usage(char *); extern void opt_help(); extern void opt_quit(); extern void opt_doc(); extern void opt_usage(FILE *); #else extern void opt_wr_title(); extern void opt_process(); extern int opt_fromfname(); extern int opt_getline(); extern int opt_tofname(); extern int opt_delim(); extern int opt_number(); extern int opt_undelim(); extern void opt_menu(); extern char *opt_mstring(); extern void opt_doc(); extern void opt_help(); extern void opt_quit(); extern void usage(); extern void opt_usage(); extern char *short_progname(); extern int ignore_after_char(); #endif /* ARGCHECK */ #endif /* _OPT_P_H */ /* ag.c */ #ifndef SINGLEFILE #include #ifdef convex #include #else #include #endif #include "ag.h" #endif /* primitive routines for manipulation argument vectors */ /* make-new-argvector ag_new() reset-argvector ag_reset() flag-end-of-word ag_eow() what-is-character ag_c() what-is-string ag_s() read-character ag_c() read-next-character ag_c_next() read-next-non-null-character ag_cnn_next() read-character-advance ag_c_advance() read-string ag_s() read-next-string ag_s_next() read-string-advance ag_s_advance() word-number ag_w_number() word-advance ag_w_advance() backspace ag_backspace() clear ag_clear() get-next-argument argnext() get-next-argument-value argnextnum() */ ARGVECTOR * ag_new(argc,argv,ag) int argc; char **argv; ARGVECTOR *ag; { ag->v = argv; ag->c = argc; ag->iw = 0; ag->ic = 0; return(ag); } ag_fprint(fp,ag) FILE *fp; ARGVECTOR *ag; { int i; for(i=0; ic; ++i) fprintf(fp,"[%s]",ag->v[i]); fprintf(fp,"\n"); } void ag_reset(ag) ARGVECTOR *ag; { ag->iw = 0; ag->ic = 0; } int ag_w_number(ag) ARGVECTOR *ag; { return( ag->iw ); } void ag_w_advance(ag) ARGVECTOR *ag; { ++(ag->iw); /* advance to next word */ ag->ic=0; /* beginning of next word */ } /* ag_eow: end of word flag whether current position is at end of word */ int ag_eow(ag) ARGVECTOR *ag; { if( ag->iw >= ag->c ) return(TRUE); if( ag->ic >= strlen(ag->v[ag->iw]) ) return(TRUE); return(FALSE); } /* ag_end: end of command line flag whether current position is at end of command line */ int ag_end(ag) ARGVECTOR *ag; { if( ag->iw >= ag->c ) return(TRUE); if( ag_eow(ag) && ag->iw == (ag->c)-1 ) return(TRUE); return(FALSE); } /* ag_c: return current character do not advance */ char ag_c(ag) ARGVECTOR *ag; { return(ag->v[ag->iw][ag->ic]); } char ag_c_next(ag) ARGVECTOR *ag; { return(ag->v[ag->iw][ag->ic+1]); } char ag_cnn_next(ag) ARGVECTOR *ag; { if( ag_c_next(ag) == '\0' ) { if(ag->iw+1 >= ag->c) return('\0'); else return(ag->v[ag->iw+1][0]); } else return( ag_c_next(ag) ); } /* ag_c_advance: read current character, and advance to next return '\0' if end of word do not advance to next word */ char ag_c_advance(ag) ARGVECTOR *ag; { char c; /* current character */ if( ag_eow(ag) ) return(c='\0'); /* return NULL to signal that current*/ /* character is past end of word */ c = ag->v[ag->iw][ag->ic]; ++(ag->ic); /* advance to next character */ return(c); } char ag_backspace(ag) ARGVECTOR *ag; { if( --(ag->ic) < 0 ) /* if back past beginning of word */ { ag->ic=0; if(--(ag->iw) < 0) /* goto beginning of previous word */ ag_reset(ag); /* if no previous, reset */ else { while( !ag_eow(ag) ) /* goto end of prevous word */ ag_c_advance(ag); ag_backspace(ag); /* back to just before end */ } } return(ag->v[ag->iw][ag->ic]); } /* ag_s: returns current string returns "" if current position is at end of word returns NULL if past end of argument vector */ char * ag_s(ag) ARGVECTOR *ag; { if( ag->iw < ag->c ) return( ag->v[ag->iw]+ag->ic ); else return( NULL ); } char * ag_s_next(ag) ARGVECTOR *ag; { if( ag->v[ag->iw][ag->ic+1] == '\0' ) { if(ag->iw+1 >= ag->c) return(NULL); else return(ag->v[ag->iw+1]); } else return( ag->v[ag->iw]+ag->ic+1 ); } /* ag_s_advance: read current string and advance to next returns NULL if current string is at end does not check advanced string */ char * ag_s_advance(ag) ARGVECTOR *ag; { char *s; /* current string */ if( ag_eow(ag) ) /* if end of word, go to next word */ ag_w_advance(ag); if( ag_eow(ag) ) /* if still at end of word, */ s = NULL; /* signify by returning NULL */ else s = ag->v[ag->iw] + ag->ic; ag_w_advance(ag); /* advance to next word */ return(s); } int ag_clear(ag) ARGVECTOR *ag; { while( !ag_end(ag) ) argnext(ag); return 1; } /* ------------------------ */ /* return the next argument */ /* ------------------------ */ char * argnext(ag) ARGVECTOR *ag; { static char nullchar='\0'; char *s; s = ag_s_advance(ag); if( s==NULL ) s = &nullchar; return(s); } /* ------------------------------------------- */ /* return the numerical value of next argument */ /* ------------------------------------------- */ double argnextnum(ag) ARGVECTOR *ag; { extern double atof(); return( atof(argnext(ag)) ); } /* opt_reg.c */ /************************ register options ******************************** * * options are stored in an array, * each element of which is a structure * * The members of the structure contain information about * 1) the variable which is altered * 2) the type of variable * 3) a character by which the variable is invoked * 4) a brief description of the variable's role in the program * 5) a longer help message * * The structure elements are not assigned directly, but are * "registered" with a call to the function opt_register(). * * In this file are the routines which access the structure of * registered options. * * I) Register options and help strings * II) Get number corresponding to name of option * III) Print options out * a) to a file which can be used as an input command line * b) to the screen as part of a usage message * c) to the screen as part of an interactive menu * IV) Process single delimited and undelimited options */ #ifndef SINGLEFILE #include #ifdef convex #include #else #include #endif #ifdef __TURBOC__ #include #endif #include "ag.h" #include "opt_p.h" static char gstr[160]; /* global string for general use */ #endif /* -------------------------- */ /* List of Registered Options */ /* -------------------------- */ #define MAXOPTS 62 /* one for each upper and lower case letter */ typedef struct { char *value; /* pointer to value of option */ opt_TYPE type; /* will be cast according to type */ char name; /* name by which option is invoked */ char *brief; /* a brief description */ char *help; /* longer help message */ } EACH_OPT; static EACH_OPT optlist[MAXOPTS]; /* array of options */ int nregopts=0; /* number of registered opts */ /* ---------- */ /* OPT macros */ /* ---------- */ #define OPT_isflagtype(o) \ ((o)==FLAG || (o)==NEGFLAG || (o)==ABSFLAG || (o)==ABSNEGFLAG) #define OPT_isundelimtype(o) ((o)==UNDELIMV || (o)==UNDELIMC) /* ----------------------------------------------- */ /* OPTVALUE: a macro to get the value of an option */ /* ----------------------------------------------- */ #define OPTVALUE(typ,i) ((typ)(*((typ *)(optlist[i].value)))) #define SETOPTVALUE(typ,i,val) { typ *xptr; \ xptr = (typ *)(optlist[i].value); \ *xptr = val; \ } /* ------------------------------- */ /* Routine to register each option */ /* ------------------------------- */ int opt_register(val,otype,name,brief) char *val; opt_TYPE otype; char name; char *brief; { if( nregopts >= MAXOPTS ) opt_fatal("opt_register: too many options"); if( name != '\0' && opt_number(name) != -1 ) { char gstr[80]; sprintf(gstr,"opt_register: Duplicate option name \'%c\'",name), opt_warning(gstr); } /* Programmer may specify that an option is to be an * undelimted option by setting the name to '\0' */ if(name=='\0') { if(otype==VSTRING) otype=UNDELIMV; if(otype==CSTRING) otype=UNDELIMC; } /* Having checked for various warnings, now register the options */ optlist[nregopts].value = val; optlist[nregopts].type = otype; optlist[nregopts].name = name; optlist[nregopts].brief = brief; optlist[nregopts].help = NULL; /* UN-delimited strings are set to NULL when registered */ /* This enables them to be invoked on the command line */ if(otype==UNDELIMC) *(optlist[nregopts].value)='\0'; if(otype==UNDELIMV) SETOPTVALUE(char *,nregopts,NULL) ++nregopts; return(nregopts); } void opt_help_set(c,help) char c, *help; { int n; n = opt_number(c); if (n>=0 && n=0 && n" * The return value is a pointer to a static string which is * overwritten with each call */ char * optstrtyp(i) int i; { static char sttyp_buf[80]; switch( optlist[i].type ) { case INT: case UNSINT: case LONG: strcpy(sttyp_buf,""); break; case FLOAT: case DOUBLE: strcpy(sttyp_buf,""); break; case CHAR: strcpy(sttyp_buf,""); break; case INTLEVEL: case FLAG: case NEGFLAG: case ABSFLAG: case ABSNEGFLAG: strcpy(sttyp_buf,""); break; case VSTRING: case CSTRING: case UNDELIMV: case UNDELIMC: strcpy(sttyp_buf,""); break; default: opt_fatal("usage: undefined o-type"); } return(sttyp_buf); } /* ------------------------------ */ /* Put registered options to file */ /* ------------------------------ */ int opt_tofile(fp) FILE *fp; { int i; char *format; char *fnumstr="-%c %-38s %c%s\n"; /* numbers and strings */ char *fflgchr="-%c%-38s %c%s\n"; /* flags and characters */ void opt_fileheader(); opt_fileheader(fp); for(i=0; i #include #ifdef convex #include #else #include #endif #ifdef __TURBOC__ #include #include #endif #include "ag.h" #include "opt_p.h" static char gstr[160]; /* general purpose global string */ #endif /* SINGLEFILE */ /****************** * Global variables */ char *opt_program_name; flag fileflag = False; char *optfile_name; char *opt_envstring=NULL; char *opt_defstring=NULL; PFI dfilter_fcn=NULL, ufilter_fcn=NULL, verify_fcn=NULL, /* NOTE: this has been disabled ! */ doc_fcn=NULL, quit_fcn=NULL, help_fcn=NULL, run_fcn=NULL; /**************************** * Static Function prototypes */ static int line2argv(); static int l2a(); static flag break_word(); static char *Title = NULL; static char *Usage = NULL; /*************************** * set title, usage, etc. * ***************************/ void opt_title_set(s) char *s; { if(Title != NULL) free(Title); Title = (char *)calloc(strlen(s)+1,sizeof(char)); if(Title == NULL) sprintf(gstr,"opt_title_set: cannot allocate for %s",s), opt_fatal(gstr); strcpy(Title,s); } void opt_wr_title() { sprintf(gstr,"%s\n", (Title==NULL ? opt_program_name : Title)); opt_message(gstr); } void opt_usage_set(s) char *s; { if(Usage != NULL) free(Usage); Usage = (char *)calloc(strlen(s)+1,sizeof(char)); if(Usage == NULL) sprintf(gstr,"opt_usage_set: cannot allocate for %s",s), opt_fatal(gstr); strcpy(Usage,s); } void opt_dfilter_set(fcn) PFI fcn; { extern PFI dfilter_fcn; dfilter_fcn = fcn; } void opt_ufilter_set(fcn) PFI fcn; { extern PFI ufilter_fcn; ufilter_fcn = fcn; } void opt_verify_set(fcn) PFI fcn; { extern PFI verify_fcn; opt_warning("The verify facility has been disabled!!"); verify_fcn = fcn; } void opt_quit_set(fcn) PFI fcn; { extern PFI quit_fcn; quit_fcn = fcn; } void opt_doc_set(fcn) PFI fcn; { extern PFI doc_fcn; doc_fcn = fcn; } void opt_help_setf(fcn) PFI fcn; { extern PFI help_fcn; help_fcn = fcn; } void opt_run_set(fcn) PFI fcn; { extern PFI run_fcn; run_fcn = fcn; } void opt_env_set(s) char *s; { extern char *opt_envstring; opt_envstring = s; } void opt_default_set(s) char *s; { extern char *opt_defstring; opt_defstring = s; } /* ------------------------------------------------------------------ */ /* ------- */ /* getopts */ /* ------- */ /* * this is the routine that is called from main(argc,argv). * returns value of argc. */ int getopts(argc,argv) int argc; char *argv[]; { int nargc; char **nargv; char *short_progname(); char *append_string(); /* * Before processing, set the global variables * opt_program_name : name of routine that is running * optfile_name : default name of options file */ opt_program_name = short_progname(argv[0]); optfile_name = append_string(opt_program_name,OPT_EXT); /* Begin options processing */ /* ------------------------ */ /* First process default string */ opt_lineprocess(opt_defstring); /* Second, check environment variable */ if(opt_envstring != NULL) { char *s; char *getenv(); s = getenv(opt_envstring); opt_lineprocess(s); } /* Finally, parse the command line */ opt_process(argc-1,argv+1); return(argc); } char * append_string(s,t) char *s,*t; { /* input two strings "s" and "t": * concatenates them to get string "st" * which it allocates space for and returns */ char *st; st = (char *)malloc( strlen(s)+strlen(t)+1 ); strcpy(st,s); strcat(st,t); return(st); } char * short_progname(pname) char *pname; { char *p; int len; /* * inelegant routine * returns the shortened name of the program named [pname]. * It (recursively) strips off leading directory or drive number * and trailing ".EXE" in the case of MS-DOS executable */ p = pname; while( *p != '/' && *p!='\\' && *p!=':' && *p!='\0' ) ++p; if( *p=='\0') { /* remove .EXE if it exists */ len = strlen(pname); if( len > 4 ) { if( ( 0==strcmp(pname+len-4,".EXE") || 0==strcmp(pname+len-4,".exe") ) ) pname[len-4]='\0'; } return( pname ); } else return( short_progname(++p) ); } /* ----------------------------------------------------------------- */ /* ------- */ /* process */ /* ------- */ /**************************************************************** * opt_process(): * INPUT: * argc, argv; * * this is the central receiving facility for the options package. * opt_process takes an argument list given by (argc,argv) and * and processes it, * Although the input may come from either of * system command line * options file * interactive command line * the behavior is slightly different if the global menuflag is set */ void opt_process(argc,argv) int argc; char *argv[]; { char c; char *s; int iword; ARGVECTOR agvect,*ag; /* * convert the argument vector (argc,argv) into * an ARGVECTOR structure, to ease manipulations */ if( argc==0 ) return; ag = &agvect; ag_new(argc,argv,ag); if(DEBUG) { ag_fprint(stderr,ag); } /* Loop through the options in the argument vector */ while( !ag_end(ag) ) { if( ag_eow(ag) ) /* if necessary... */ ag_w_advance(ag); /* advance to next word */ if(DEBUG) if( ag->ic != 0 ) /* this should never happen */ opt_warning("opt_process: not on first character"); c=ag_c_advance(ag); /* first character of word */ /* ------ */ /* switch */ /* ------ */ switch( c ) { case DELIM: case ALTDELIM: /* if unadorned "-" */ if( ag_eow(ag) ) { if (!menuflag && !fileflag) { usage(""); /* usage message */ opt_abort_run(); } ag_clear(ag); } /* if "--something" */ else if( ag_c(ag) == c ) { if (!menuflag && !fileflag) { usage(argnext(ag)); opt_abort_run(); } } /* if "-something" */ else { iword = ag_w_number(ag); while( iword==ag_w_number(ag) && !ag_eow(ag) ) opt_delim(ag); } break; case OPTFROMFILE: if(1) { flag tmp_fileflag; tmp_fileflag = fileflag; fileflag = True; opt_fromfname(argnext(ag)); fileflag = tmp_fileflag; } break; case OPTTOFILE: opt_tofname(argnext(ag)); break; case HELPCH: if( !fileflag) opt_help(argnext(ag)); break; case INTERACT: if ( !menuflag ) /* If not called already */ opt_menu(); /* Call the menu */ else /* otherwise */ { menuflag=False; /* turn off menu */ ag_clear(ag); } break; case IGNOREEOL: ag_clear(ag); break; case RUN: if( run_fcn != NULL ) opt_begin_run(run_fcn); else { /* if run_fcn is not set, and 'RUN' is called * from the menu, then exit the menu, so that * the routine is run, and then program will exit */ if ( menuflag ) { menuflag=False; /* turn off menu */ ag_clear(ag); } else { /* RUN called from a file or the command line: * There is no reason to be doing this. */ opt_warning("No Run Function has been registered"); } break; case QUITCH: opt_quit(); break; case BANG: if (!menuflag) opt_warning("Shell can only be invoked from the menu"); else { sprintf(gstr,"Shell to system invalid unless \'%c\'",BANG); strcat(gstr," is the first character in the line\n"); opt_warning(gstr); } #if 0 /* bang...shell to system */ if(1) { char s[160]; strcpy(s,argnext(ag)); system(s); break; } #endif case ' ': /* blanks and empty characters, ignore */ case '\t': case '\0': break; default: /* in the default case, option may be undelimited */ /* ---------------------------------------------- */ ag_backspace(ag); if(DEBUG) { sprintf(gstr, "opt_process: in default section [%s]\n",ag_s(ag)); opt_warning(gstr); } if(1) { char s[80]; strcpy(s,ag_s(ag)); if( opt_undelim(ag) == 0) { sprintf(gstr, "%c (in %s) is invalid delimeter\n", c,s); opt_warning(gstr); } } break; } } } }/*opt_process*/ /* opt_lineprocess() * process a string, by converting it first into an argument vector * then calling opt_process * return the number of processed arguments */ int opt_lineprocess(line) char *line; { int nargc; char **nargv; if( line==NULL || *line=='\0') return(0); line2argv(&nargc,&nargv,line); opt_process(nargc,nargv); return(nargc); } /* line2argv(): converts a one-line string into an argument vector */ static int line2argv(pargc,pargv,line) int *pargc; char ***pargv; char *line; { char *lincp; if(line==NULL) { *pargc = 0; **pargv = NULL; return(0); } /* * First thing to do is copy the line into * a buffer ("lincp") so that input line will * not be corrupted -- also so that input line * doesn't have to be double null terminated */ lincp = (char *)calloc(strlen(line)+2,sizeof(char)); strcpy(lincp,line); /* * Next step is to double null terminate * the copied line */ lincp[strlen(line)+1]='\0'; /* count words in line */ *pargc = l2a(lincp,NULL); /* allocate array for arg vector */ *pargv = (char **)malloc(((*pargc)+1)*sizeof(char *)); /* fill arg vector with words in line */ l2a(lincp,*pargv); /* * Note that lincp cannot be freed since * that space is used by pargv */ return(*pargc); } #define QUOTE '\"' #define BKSLASH '\\' /* l2a */ /* l2a() is slave routine to line2argv() */ /* if argv==NULL then count the words in the line */ /* if argv!=NULL then put those words into argv[] */ /* WARNINGS: * l2a assumes that input line is double-null terminated!! * the line buffer is pointed to by argv[]'s so do not * free the input line buffer */ /* quoted material counts as a single word */ /* so that -s"string with spaces"-g is parsed */ /* into -s string with spaces -g */ /* Comment: should be able to escape with backslash */ static int l2a(line,argv) char *line; char **argv; { flag inquote=False; /* flag: inside quotation */ int iarg; for(iarg=0; *line != '\0'; ++iarg) { if(!inquote) { while( isspace(*line) ) ++line; /* skip leading blank spaces */ if( *line == QUOTE ) { inquote=True; ++line; /* skip past leading quote */ } } if(argv!=NULL) /* point to */ argv[iarg] = line; /* first character of line */ while( !break_word(inquote,line) ) ++line; if( *line==QUOTE ) /* toggle quote */ { inquote = (inquote==True ? False : True ); if(argv==NULL) ++line; /* skip past quote */ } if(argv!=NULL) { *line='\0'; /* Null terminate string */ ++line; /* and go to next character */ } else while( isspace(*line) ) ++line; /* skip trailing blanks */ } return(iarg); } static flag break_word(inquote,line) flag inquote; char *line; { if( *line == '\0' || *line==QUOTE ) return(True); if( !inquote && isspace(*line) ) return(True); return(False); } /* --------------------------- */ /* write out a usage statement */ /* --------------------------- */ /* usage("") gives minimal usage message usage("-") gives fuller usage message usage("--") gives output document */ static void short_usage(); static void long_usage(); static void doc_usage(); void usage(s) char *s; { if (s==NULL || *s=='\0') { short_usage(); sprintf(gstr,"For a list of options, type:\n"), opt_message(gstr); sprintf(gstr,"\t%s %c%c\n",opt_program_name,DELIM,DELIM); doc_usage(); return; } else if (*s == DELIM ) { ++s; if (*s=='\0') { short_usage(); doc_usage(); long_usage(); return; } if (*s==DELIM) { opt_doc(); return; } } } static void short_usage() { if(Title != NULL) sprintf(gstr,"%s\n",Title), opt_message(gstr); if(Usage != NULL) sprintf(gstr,"[%s] %s\n",opt_program_name,Usage), opt_message(gstr); sprintf(gstr,"To invoke the menu, type:\n\t%s %c\n", opt_program_name,INTERACT), opt_message(gstr); } static void long_usage() { sprintf(gstr,"The options are:\n"), opt_message(gstr); opt_usage(); } static void doc_usage() { if(doc_fcn != NULL) { sprintf(gstr,"For fuller documentation, type:\n\t"), opt_message(gstr); sprintf(gstr,"%s %c%c%c\n",opt_program_name, DELIM,DELIM,DELIM), opt_message(gstr); } } /* --------------------------------- */ /* put current options in named file */ /* --------------------------------- */ int opt_tofname(fname) char *fname; { FILE *fp; if( *fname != OPTTOFILE ) { free((char *)optfile_name); optfile_name = append_string(fname,""); } if( access(optfile_name,0)==0 ) { sprintf(gstr,"Options file [%s] has been overwritten\n", optfile_name), opt_message(gstr); backup_file(optfile_name); } fp = fopen(optfile_name,"w"); if(fp==NULL) { sprintf(gstr,"cant open file %s\n",fname), opt_message(gstr); return(0); } opt_tofile(fp); fclose(fp); return(1); } #ifdef __TURBOC__ backup_file(fname) char *fname; {} #else backup_file(fname) char *fname; { char fname_backup[80]; sprintf(fname_backup,"%s%s",fname,"~"); sprintf(gstr,"%s %s %s","cp",fname,fname_backup); system(gstr); sprintf(gstr,"File [%s] is backup file\n",fname_backup); opt_message(gstr); } #endif /* ----------------------------------------- */ /* get and process options from a named file */ /* ----------------------------------------- */ #define MAXOPLINE 256 int opt_fromfname(fname) char *fname; { FILE *fp; char line[MAXOPLINE+2]; /* leave room for termination */ if( *fname != OPTFROMFILE ) /* if not default file */ { if( access(fname,0)!=0 ) /* if file doesn't exist */ { sprintf(gstr,"File [%s] does not exist\n",fname); opt_message(gstr); return(0); } else { free((char *)optfile_name); optfile_name = append_string(fname,""); } } fp = fopen(optfile_name,"r"); if(fp==NULL) { sprintf(gstr,"Cannot open options file [%s]\n",optfile_name); opt_warning(gstr); return(0); } while( opt_getline(line,fp) > 0 ) opt_lineprocess(line); fclose(fp); return(1); } int opt_getline(line,fp) char *line; FILE *fp; { int c; int count=0; while( (c=getc(fp)) != '\n' && c!=EOF ) { *line = (char)c; ++line; if( ++count > MAXOPLINE-3 ) { opt_warning("Options line too long"); break; } } *line++ = '\0'; /* double terminate line !! */ *line++ = '\0'; return(count); }/*opt_getline*/ /* ------------------- */ /* basic help function */ /* ------------------- */ void opt_help(s) char *s; { if(s==NULL || *s=='\0') { sprintf(gstr,"\t%c %-20s\n",DELIM,"Options delimiter"), opt_message(gstr); sprintf(gstr,"\t%c %-20s\n",HELPCH,"Help"), opt_message(gstr); sprintf(gstr,"\t%c %-20s\n",RUN,"Run program and return to menu"), opt_message(gstr); sprintf(gstr,"\t%c %-20s\n",BANG,"Shell to Operating System"), opt_message(gstr); if (menuflag) sprintf(gstr,"\t%c %-20s\n",INTERACT,"Exit menu"), opt_message(gstr); else sprintf(gstr,"\t%c %-20s\n",INTERACT,"Invoke menu"), opt_message(gstr); sprintf(gstr,"\t%c %-20s\n",ADDITIONAL_OPTS,"Additional options"), opt_message(gstr); sprintf(gstr,"\t%c %-20s\n",OPTFROMFILE, "Get options from file",optfile_name), opt_message(gstr); sprintf(gstr,"\t%c%c %-2s [%s]\n",OPTFROMFILE,OPTFROMFILE, "Get options from file",optfile_name), opt_message(gstr); sprintf(gstr,"\t%c %-20s\n",OPTTOFILE, "Put options in file"), opt_message(gstr); sprintf(gstr,"\t%c%c %-2s [%s]\n",OPTTOFILE,OPTTOFILE, "Put options in file",optfile_name), opt_message(gstr); sprintf(gstr,"\t%c %-20s\n",QUITCH,"Quit"), opt_message(gstr); } else { /* first check if help is available for single character delimiter */ if( s[1]=='\0' && opt_number(s[0]) >=0 ) opt_get_help(s[0]); else { if( help_fcn==NULL ) sprintf(gstr,"Help unavailable for: [%s]\n",s), opt_message(gstr); else (*help_fcn)(s); } } } /* ------ */ /* quit() */ /* ------ */ void opt_quit() { if( quit_fcn == NULL ) opt_abort_run(); else { (*quit_fcn)(); opt_abort_run(); } } /* ---------- */ /* document() */ /* ---------- */ void opt_doc() { if( doc_fcn == NULL ) return; else (*doc_fcn)(); } /* opt_menu.c */ #ifndef SINGLEFILE #include #include #ifdef convex #include #else #include #endif #ifdef __TURBOC__ #include #endif #include "opt_p.h" #endif /* SINGLEFILE */ /* --------------------- menu flag ------------------- */ flag menuflag=False; static char mgstring[160]; /* global menu string */ #define menu_wr_string(str) opt_message(str) #define menu_getresponse(respond) opt_getline(respond,stdin) static void write_the_menu(); static int auto_prefix_delim(); /* ---------------------------------------------------- */ /* opt_menu: Get options from an interactive menu */ /* ---------------------------------------------------- */ #define MAXRESPONDLINE 280 #ifndef MAXOPTSINMENU #define MAXOPTSINMENU 20 #endif void opt_menu() { char respond[MAXRESPONDLINE+2]; static int maxoptsinmenu=MAXOPTSINMENU; flag fullmenu; int iop,iopfrom,iopto; menuflag=True; /* turn on MENUFLAG in case it is not set already */ iopfrom = 0; iopto = ( nregopts < maxoptsinmenu ? nregopts : maxoptsinmenu ); respond[0]='\0'; opt_wr_title(); write_the_menu(iopfrom,iopto); while( menuflag ) { menu_wr_string("-> "); menu_getresponse(respond); switch(*respond) { case ADDITIONAL_OPTS: if( respond[1] != '\0' && respond[1] != ' ' ) { maxoptsinmenu = atoi(respond+1); if(maxoptsinmenu < 1) maxoptsinmenu = nregopts; sprintf(mgstring,"Scroll %d options\n",maxoptsinmenu); menu_wr_string(mgstring); iopfrom = 0; iopto = ( nregopts < maxoptsinmenu ? nregopts : maxoptsinmenu ); } else { iopfrom += maxoptsinmenu; if( iopfrom > nregopts) iopfrom = 0; iopto = iopfrom + maxoptsinmenu; if( iopto > nregopts ) iopto = nregopts; } write_the_menu(iopfrom,iopto); break; case INTERACT: menuflag=False; break; case BANG: system( respond+1 ); break; case '\0': write_the_menu(iopfrom,iopto); break; case QUITCH: /* only quit if the QUITCH is followed by whitespace */ if ( respond[1]=='\0' || respond[1]==' ' ) opt_abort_run(0); break; case DELIM: case ALTDELIM: opt_lineprocess(respond); break; default: auto_prefix_delim(respond); opt_lineprocess(respond); break; } } }/* opt_menu */ /********** * write_the_menu: * write the menu including options from iopfrom to iopto. */ static void write_the_menu(iopfrom,iopto) int iopfrom,iopto; { int iop; flag fullmenu; fullmenu = ((iopfrom==0 && iopto==nregopts) ? True : False ); if( !fullmenu ) { sprintf(mgstring,"menu: %d->%d [%d]\n",iopfrom,iopto,nregopts); menu_wr_string(mgstring); } for(iop=iopfrom; iop m4 * gives the same effect as * -> -m4 * But be warned that this only applies in limited cases. * Eg., * -> m4 b3 * is not the same as * -> -m4 -b3 * * a '-' will be prepended in the case that * the first character is a registered name */ static int auto_prefix_delim(r) char *r; { if( opt_number( *r ) != -1 ) { int len; len = strlen(r)+1; /* +1 since double terminated */ while(len>=0) { r[len+1]=r[len]; --len; } r[0]=DELIM; return(1); } else return(0); }/* auto_prefix_delim */ /************************** * some useful utilities * **************************/ /* * 1) Variable argument lists: for error messages * opt_errmess(), gives message and then aborts run * 2) Long Jump: for aborting run() without losing the entire job * opt_begin_run() * opt_abort_run() * 3) Signal: trapping ^C so that it aborts run() * */ /* Can be disabled by setting constants * DISABLE_VARARG, * DISABLE_LONGJUMP, * DISABLE_SIGNAL */ #ifndef SINGLEFILE #include #include "opt_p.h" #endif static void set_signal(/* void */); static void unset_signal(/* void */); static void catch_signal(/* void */); void opt_message(s) char *s; { if (s != NULL) fputs(s,stderr); } void opt_warning(s) char *s; { fputs(opt_program_name,stderr); fputs(":: ",stderr); fputs("OPT Warning: ",stderr); fputs(s,stderr); fputs("\n",stderr); } void opt_fatal(s) char *s; { fputs(opt_program_name,stderr); fputs(":: ",stderr); fputs("OPT Fatal error: ",stderr); fputs(s,stderr); exit(1); } /********** * VARARG * **********/ #if DISABLE_VARARG void opt_errmess(s) char *s; { fputs(opt_program_name,stderr); fputs(":: ",stderr); fputs(s,stderr); opt_abort_run(); } #else /* if not DISABLE_VARARGS */ #ifdef __TURBOC__ /* Turbo-C implements variable argument lists differently than SUN */ #ifndef SINGLEFILE #include #endif void opt_errmess(char *format, ...) { va_list argptr; va_start(argptr,format); vfprintf(stderr,format,argptr); va_end(argptr); opt_abort_run(); } #else /* if not __TURBOC__ but default instead */ #ifndef SINGLEFILE #include #endif #endif /* if __TURBOC__ */ #endif /* end VARARGS */ /************ * LONGJUMP * ************/ #if DISABLE_LONGJUMP int opt_begin_run(run) int (*run)(); { return( (*run)() ); } void opt_abort_run() { exit(1); } #else /* if not DISABLE_LONGJUMP */ #ifndef SINGLEFILE #include #endif static jmp_buf opt_jumpstart; static int opt_jump_set=FALSE; void opt_abort_run() { if(opt_jump_set) longjmp(opt_jumpstart,1); else exit(1); } int opt_begin_run(run) int (*run)(); { int value; opt_jump_set=TRUE; set_signal(); value = setjmp(opt_jumpstart); if(value!=0) opt_message("Run aborted...try again\n"); else value = (*run)(); unset_signal(); opt_jump_set=FALSE; return value; } #endif /* end LONGJUMP */ /********** * SIGNAL * **********/ #if DISABLE_SIGNAL static void set_signal() {} static void unset_signal() {} #else #ifndef SINGLEFILE #include #endif static void (*old_catcher)(); static void set_signal() { old_catcher = signal(SIGINT,catch_signal); } static void unset_signal() { signal(SIGINT,old_catcher); } #ifdef __TURBOC__ static void catch_signal(sig) int sig; #else #ifdef convex static void catch_signal(sig,code,scp) int sig, code; struct sigcontext *scp; #else /* default */ static void catch_signal(sig,code,scp,addr) int sig, code; struct sigcontext *scp; char *addr; #endif #endif { opt_message("\nOPT Interrupted:\n"); longjmp(opt_jumpstart,1); perror("Did not long-jump"); exit(0); } #endif /* end SIGNAL */