2582 lines
55 KiB
C
2582 lines
55 KiB
C
/*
|
|
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 <stdio.h>
|
|
#ifdef convex
|
|
#include <strings.h>
|
|
#else
|
|
#include <string.h>
|
|
#endif
|
|
#ifdef __TURBOC__
|
|
#include <stdlib.h>
|
|
#include <alloc.h>
|
|
#endif
|
|
#include <ctype.h>
|
|
|
|
#if !DISABLE_LONGJUMP
|
|
#include <setjmp.h>
|
|
#endif
|
|
|
|
#if !DISABLE_SIGNAL
|
|
#include <signal.h>
|
|
#endif
|
|
|
|
#if !DISABLE_VARARG
|
|
#ifdef __TURBOC__
|
|
#include <stdarg.h>
|
|
#else
|
|
#include <stdarg.h>
|
|
#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 <stdio.h>
|
|
#ifdef convex
|
|
#include <strings.h>
|
|
#else
|
|
#include <string.h>
|
|
#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; i<ag->c; ++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 <stdio.h>
|
|
#ifdef convex
|
|
#include <strings.h>
|
|
#else
|
|
#include <string.h>
|
|
#endif
|
|
#ifdef __TURBOC__
|
|
#include <alloc.h>
|
|
#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<nregopts)
|
|
optlist[n].help = help;
|
|
else
|
|
sprintf(gstr,"opt_help_set: Unregistered option name \'%c\'",c),
|
|
opt_warning(gstr);
|
|
}
|
|
void
|
|
opt_get_help(c)
|
|
char c;
|
|
{
|
|
int n;
|
|
n = opt_number(c);
|
|
if (n>=0 && n<nregopts && optlist[n].help != NULL)
|
|
sprintf(gstr,"%c: %s\n",c,optlist[n].help),
|
|
opt_message(gstr);
|
|
else
|
|
sprintf(gstr,"Help unavailable for \'%c\'\n",c),
|
|
opt_message(gstr);
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------- */
|
|
/* Get number corresponding to option name */
|
|
/* --------------------------------------- */
|
|
|
|
/* opt_number returns the number of a named option.
|
|
* if c=='\0', signifying an undelimited option,
|
|
* then the number of the FIRST undelimited option is returned
|
|
*/
|
|
int
|
|
opt_number(c)
|
|
char c;
|
|
{
|
|
int i=0; /* see which registered option */
|
|
for(i=0; i<nregopts; ++i)
|
|
{
|
|
if( c == optlist[i].name )
|
|
return(i);
|
|
}
|
|
return(-1); /* to signify not an option */
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
/* Print value of registered option to a string */
|
|
/* -------------------------------------------- */
|
|
|
|
/* optstrval:
|
|
* returns the value of the ith registered option as a string
|
|
* Thus if x = 12.6, this returns the string "12.6"
|
|
* The return value is a pointer to a static string which is
|
|
* overwritten with each call
|
|
* FLAG values are returned as "+" or "-"
|
|
* INTLEVEL values are returned as "- -xxxx..." depending on value
|
|
*/
|
|
char *
|
|
optstrval(i)
|
|
int i;
|
|
{
|
|
int maybe;
|
|
static char stval_buf[80];
|
|
|
|
switch( optlist[i].type )
|
|
{
|
|
case INT:
|
|
sprintf(stval_buf,"%d", OPTVALUE(int,i) );
|
|
break;
|
|
case UNSINT:
|
|
sprintf(stval_buf,"%u", OPTVALUE(unsigned int,i) );
|
|
break;
|
|
case LONG:
|
|
sprintf(stval_buf,"%ld", OPTVALUE(long,i) );
|
|
break;
|
|
case FLOAT:
|
|
sprintf(stval_buf,"%g", OPTVALUE(float,i) );
|
|
break;
|
|
case DOUBLE:
|
|
sprintf(stval_buf,"%lg", OPTVALUE(double,i) );
|
|
break;
|
|
case CHAR:
|
|
sprintf(stval_buf,"%c", OPTVALUE(char,i));
|
|
break;
|
|
case INTLEVEL:
|
|
{
|
|
int j;
|
|
char buff[80];
|
|
strcpy(stval_buf,"-"); /* Begin with level==OFF */
|
|
for(j=0; j< OPTVALUE(int,i); ++j)
|
|
{
|
|
sprintf(buff,(j==0?" -%c":"%c"),optlist[i].name);
|
|
strcat(stval_buf,buff);
|
|
}
|
|
}
|
|
break;
|
|
case FLAG:
|
|
case ABSFLAG:
|
|
maybe = OPTVALUE(int,i);
|
|
sprintf(stval_buf,"%c", (maybe==TRUE ? '+' : '-') );
|
|
break;
|
|
case NEGFLAG:
|
|
case ABSNEGFLAG:
|
|
maybe = OPTVALUE(int,i);
|
|
sprintf(stval_buf,"%c", (maybe==TRUE ? '-' : '+') );
|
|
break;
|
|
case CSTRING:
|
|
case UNDELIMC:
|
|
sprintf(stval_buf,"\"%s\"",optlist[i].value);
|
|
break;
|
|
case VSTRING:
|
|
case UNDELIMV:
|
|
if( optlist[i].value == NULL ) /* this should never happen */
|
|
sprintf(stval_buf,"\"\"");
|
|
else
|
|
if( OPTVALUE(char *,i) == NULL )
|
|
sprintf(stval_buf,"\"\"");
|
|
else
|
|
sprintf(stval_buf,"\"%s\"",OPTVALUE(char *,i));
|
|
break;
|
|
default:
|
|
opt_fatal("optstrval: Undefined o-type");
|
|
break;
|
|
}
|
|
/* ---- Return value is static buffer ---- */
|
|
return(stval_buf);
|
|
}/*optstrval*/
|
|
|
|
|
|
/* optstrtyp:
|
|
* returns the type of the ith registered option as a string
|
|
* Thus if x = 12.6 is a float , this returns the string "<real>"
|
|
* 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,"<integer>");
|
|
break;
|
|
case FLOAT:
|
|
case DOUBLE:
|
|
strcpy(sttyp_buf,"<real>");
|
|
break;
|
|
case CHAR:
|
|
strcpy(sttyp_buf,"<character>");
|
|
break;
|
|
case INTLEVEL:
|
|
case FLAG:
|
|
case NEGFLAG:
|
|
case ABSFLAG:
|
|
case ABSNEGFLAG:
|
|
strcpy(sttyp_buf,"<flag>");
|
|
break;
|
|
case VSTRING:
|
|
case CSTRING:
|
|
case UNDELIMV:
|
|
case UNDELIMC:
|
|
strcpy(sttyp_buf,"<string>");
|
|
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<nregopts; ++i)
|
|
{
|
|
if( OPT_isundelimtype( optlist[i].type ) )
|
|
continue;
|
|
if( OPT_isflagtype( optlist[i].type )
|
|
|| optlist[i].type == INTLEVEL
|
|
|| optlist[i].type == CHAR )
|
|
format = fflgchr;
|
|
else
|
|
format = fnumstr;
|
|
fprintf(fp,format,optlist[i].name,
|
|
optstrval(i),IGNOREEOL,optlist[i].brief);
|
|
}
|
|
}
|
|
void
|
|
opt_fileheader(fp)
|
|
FILE *fp;
|
|
{
|
|
extern char *opt_program_name;
|
|
int i,n;
|
|
char buf[80];
|
|
|
|
sprintf(buf,"Options file created by: [%.30s]",opt_program_name);
|
|
n = strlen(buf);
|
|
|
|
fputc(IGNOREEOL,fp);
|
|
fprintf(fp,"%s",buf);
|
|
fputc(IGNOREEOL,fp); fputc('\n',fp);
|
|
|
|
fputc(IGNOREEOL,fp);
|
|
for(i=0;i<n;++i) fprintf(fp,"-");
|
|
fputc(IGNOREEOL,fp); fputc('\n',fp);
|
|
}
|
|
/* ----------------------------------------- */
|
|
/* write options out to the interactive menu */
|
|
/* ----------------------------------------- */
|
|
|
|
char *
|
|
opt_mstring(i)
|
|
int i;
|
|
{
|
|
static char mstring[180];
|
|
char flgstr[10];
|
|
char *s;
|
|
char *optstrval();
|
|
char *format = "%c %-40s %s";
|
|
|
|
if( OPT_isundelimtype( optlist[i].type ) )
|
|
return(NULL);
|
|
|
|
s = optstrval(i);
|
|
if( optlist[i].type == INTLEVEL )
|
|
{
|
|
int f;
|
|
f = OPTVALUE(int,i);
|
|
if(f==0)
|
|
strcpy(flgstr,"OFF");
|
|
else if (f==1)
|
|
strcpy(flgstr,"ON");
|
|
else
|
|
sprintf(flgstr,"ON:%d",f);
|
|
s=flgstr;
|
|
}
|
|
else
|
|
if( optlist[i].type == CHAR )
|
|
{
|
|
switch (s[0])
|
|
{
|
|
case '\0': sprintf(flgstr,"\'\\0\'"); break;
|
|
case '\n': sprintf(flgstr,"\'\\n\'"); break;
|
|
case '\t': sprintf(flgstr,"\'\\t\'"); break;
|
|
case ' ': sprintf(flgstr,"\' \'"); break;
|
|
default: sprintf(flgstr,"%c",s[0]); break;
|
|
}
|
|
s = flgstr;
|
|
}
|
|
else
|
|
if( OPT_isflagtype( optlist[i].type ) )
|
|
{
|
|
if( *s == '+' )
|
|
strcpy(flgstr,"TRUE");
|
|
if( *s == '-' )
|
|
strcpy(flgstr,"FALSE");
|
|
s=flgstr;
|
|
}
|
|
|
|
sprintf(mstring,format,optlist[i].name,optlist[i].brief,s);
|
|
return(mstring);
|
|
}
|
|
int
|
|
opt_fprint(fp,i)
|
|
FILE *fp;
|
|
int i;
|
|
{
|
|
char *optstrval();
|
|
fprintf(fp,"-%c%-17s %c%s\n",optlist[i].name,
|
|
optstrval(i),IGNOREEOL,optlist[i].brief);
|
|
return(i);
|
|
}
|
|
/* ----------------------------------------------------- */
|
|
/* write a usage statement describing registered options */
|
|
/* ----------------------------------------------------- */
|
|
|
|
void
|
|
opt_usage()
|
|
{
|
|
char buf[100];
|
|
char *dformat = " -%c %-12s\t%s\n";
|
|
char *uformat = " %-12s\t%s\n";
|
|
|
|
int i;
|
|
for(i=0; i<nregopts; ++i)
|
|
{
|
|
if( OPT_isundelimtype( optlist[i].type ) )
|
|
{
|
|
sprintf(buf,uformat,
|
|
optstrtyp(i),optlist[i].brief);
|
|
opt_message(buf);
|
|
}
|
|
else
|
|
{
|
|
sprintf(buf,dformat,optlist[i].name,
|
|
optstrtyp(i),optlist[i].brief);
|
|
opt_message(buf);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ----------------------- */
|
|
/* Get and process options */
|
|
/* ----------------------- */
|
|
|
|
/*
|
|
* The routines below make use of the ARGVECTOR structure
|
|
* defined in "ag.h" to process the command line options
|
|
*/
|
|
|
|
/* -------------------------------------- */
|
|
/* get and process an UN-delimited option */
|
|
/* -------------------------------------- */
|
|
|
|
int
|
|
opt_undelim(ag)
|
|
ARGVECTOR *ag;
|
|
{
|
|
int i;
|
|
char *s;
|
|
|
|
if(1)
|
|
{
|
|
/* This is the hook that the programmer can install
|
|
* to filter undelimited strings from the command line
|
|
*/
|
|
extern PFI ufilter_fcn;
|
|
if( ufilter_fcn != NULL )
|
|
if( (*ufilter_fcn)(ag_s(ag),ag) != 0 )
|
|
return(1);
|
|
}
|
|
|
|
if(DEBUG)
|
|
{
|
|
opt_message("opt_udelim: ");
|
|
ag_fprint(ag);
|
|
}
|
|
|
|
/* Find the first un-initialized undelimited option */
|
|
/* and set that to the argument string */
|
|
/* Note that once an undelimited option has been initialized */
|
|
/* it cannot be reset to a new value unless it is somehow */
|
|
/* set back to NULL or blank */
|
|
|
|
s = ag_s_advance(ag);
|
|
for(i=0; i<nregopts; ++i)
|
|
{
|
|
if( optlist[i].type==UNDELIMC && *(optlist[i].value)=='\0' )
|
|
{
|
|
strcpy( optlist[i].value, s );
|
|
return(1);
|
|
}
|
|
if( optlist[i].type==UNDELIMV && OPTVALUE(char *,i)==NULL )
|
|
{
|
|
SETOPTVALUE(char *,i,(char *)malloc(strlen(s)+1));
|
|
strcpy( OPTVALUE(char *,i), s );/* ?? */
|
|
return(1);
|
|
}
|
|
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
/* ---------------------------------- */
|
|
/* get and process a delimited option */
|
|
/* ---------------------------------- */
|
|
|
|
opt_delim(ag)
|
|
ARGVECTOR *ag;
|
|
{
|
|
int i;
|
|
opt_TYPE o;
|
|
char c;
|
|
char *s;
|
|
int yes,no,maybe,toggle; /* flag values */
|
|
|
|
/**************************************************
|
|
* first, check to see if the programmer wants to
|
|
* interrupt this delimited option: if so, it will
|
|
* be done by the routine (*dfilter_fcn)(), which
|
|
* the programmer has provided and a
|
|
* nonzero value will be returned.
|
|
***************************************************/
|
|
if(1)
|
|
{
|
|
extern PFI dfilter_fcn;
|
|
if( dfilter_fcn != NULL )
|
|
if( (*dfilter_fcn)(ag_s(ag),ag) != 0 )
|
|
return(1);
|
|
}
|
|
|
|
c = ag_c_advance(ag); /* first character gives name of option */
|
|
i = opt_number(c); /* this is number of option w/ name 'c' */
|
|
|
|
if(i<0) /* if invalid option name */
|
|
{
|
|
char s[80];
|
|
sprintf(s,"%c not a registered option name\n",c);
|
|
opt_warning(s);
|
|
return(0);
|
|
}
|
|
|
|
/* ------------- */
|
|
/* act on option */
|
|
/* ------------- */
|
|
switch( o=optlist[i].type )
|
|
{
|
|
case INT:
|
|
SETOPTVALUE(int,i, argnextnum(ag));
|
|
break;
|
|
case UNSINT:
|
|
SETOPTVALUE(unsigned int,i, argnextnum(ag));
|
|
break;
|
|
case LONG:
|
|
SETOPTVALUE(long,i, argnextnum(ag));
|
|
break;
|
|
case FLOAT:
|
|
SETOPTVALUE(float,i, argnextnum(ag));
|
|
break;
|
|
case DOUBLE:
|
|
SETOPTVALUE(double,i, argnextnum(ag));
|
|
break;
|
|
case CHAR:
|
|
SETOPTVALUE(char,i, ag_c_advance(ag));
|
|
break;
|
|
|
|
case FLAG:
|
|
case NEGFLAG:
|
|
case ABSFLAG:
|
|
case ABSNEGFLAG:
|
|
/* define terms:
|
|
* yes: value of flag when ON
|
|
* no: value of flag when OFF
|
|
* maybe: present value of flag
|
|
* toggle: negative of maybe
|
|
*/
|
|
maybe = OPTVALUE(int,i);
|
|
toggle = (maybe==TRUE ? FALSE : TRUE);
|
|
if( o==FLAG || o==ABSFLAG ) yes=TRUE;
|
|
else yes=FALSE;
|
|
no = (yes==TRUE ? FALSE : TRUE);
|
|
c = ag_c(ag); /* character following 'c' */
|
|
switch(c)
|
|
{
|
|
case '+':
|
|
*((int *)(optlist[i].value)) = yes;
|
|
ag_c_advance(ag); /* eat the '+' */
|
|
break;
|
|
case '-':
|
|
*((int *)(optlist[i].value)) = no;
|
|
ag_c_advance(ag); /* eat the '-' */
|
|
break;
|
|
default:
|
|
if( o==ABSFLAG || o==ABSNEGFLAG )
|
|
*((int *)(optlist[i].value)) = maybe;
|
|
else /* otherwise toggle value */
|
|
*((int *)(optlist[i].value)) = toggle;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case INTLEVEL:
|
|
SETOPTVALUE(int,i,OPTVALUE(int,i) + 1); /* default is to increment */
|
|
c = ag_c(ag);
|
|
switch(c)
|
|
{
|
|
case '+':
|
|
/* we've already incremented */
|
|
ag_c_advance(ag);
|
|
break;
|
|
case '-':
|
|
SETOPTVALUE(int,i,0);
|
|
ag_c_advance(ag);
|
|
break;
|
|
case '0': case '1': case '2': case '3': case '4':
|
|
case '5': case '6': case '7': case '8': case '9':
|
|
SETOPTVALUE(int,i,c-'0');
|
|
ag_c_advance(ag);
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case VSTRING:
|
|
s = argnext(ag);
|
|
if( OPTVALUE(char *,i) != NULL )
|
|
free( OPTVALUE(char *,i)); /* if prev. malloc'd */
|
|
*((char **)(optlist[i].value)) = (char *)malloc( strlen(s)+1 );
|
|
strcpy( OPTVALUE(char *,i) , s );
|
|
break;
|
|
case CSTRING:
|
|
strncpy( optlist[i].value , argnext(ag), OPT_MAXSTRLEN );
|
|
break;
|
|
|
|
case UNDELIMC:
|
|
case UNDELIMV:
|
|
opt_fatal("opt_delim: can't process UNDELIM type");
|
|
break;
|
|
|
|
default:
|
|
opt_fatal("opt_delim: don't know this type");
|
|
break;
|
|
}
|
|
return(1);
|
|
}
|
|
/* opt_proc.c */
|
|
/*
|
|
* process options in the OPT package
|
|
*/
|
|
|
|
#ifndef SINGLEFILE
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
#ifdef convex
|
|
#include <strings.h>
|
|
#else
|
|
#include <string.h>
|
|
#endif
|
|
#ifdef __TURBOC__
|
|
#include <alloc.h>
|
|
#include <stdarg.h>
|
|
#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<filename> %-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<filename> %-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 <stdio.h>
|
|
#include <ctype.h>
|
|
#ifdef convex
|
|
#include <strings.h>
|
|
#else
|
|
#include <string.h>
|
|
#endif
|
|
#ifdef __TURBOC__
|
|
#include <alloc.h>
|
|
#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<iopto; ++iop)
|
|
{
|
|
char *s;
|
|
s = opt_mstring(iop);
|
|
if (s!=NULL)
|
|
{
|
|
strcpy( mgstring, s );
|
|
menu_wr_string(mgstring);
|
|
menu_wr_string("\n");
|
|
}
|
|
}
|
|
if (!fullmenu)
|
|
{
|
|
sprintf(mgstring,"%c Additional options\n",ADDITIONAL_OPTS);
|
|
menu_wr_string(mgstring);
|
|
}
|
|
sprintf(mgstring,"(Type %c for Help)\n",HELPCH);
|
|
menu_wr_string(mgstring);
|
|
}
|
|
|
|
/* auto_prefix_delim:
|
|
* this is a fru-fru piece of code that automatically
|
|
* sticks a DELIM character onto the front of a string
|
|
* in cases where it imagines that that is what the user
|
|
* really meant. Thus
|
|
* -> 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 <stdio.h>
|
|
#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 <stdarg.h>
|
|
#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 <stdarg.h>
|
|
#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 <setjmp.h>
|
|
#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 <signal.h>
|
|
#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 */
|
|
|