848 lines
25 KiB
C
848 lines
25 KiB
C
|
/*
|
||
|
* Copyright (c) 1991 Carnegie Mellon University
|
||
|
* All Rights Reserved.
|
||
|
*
|
||
|
* Permission to use, copy, modify and distribute this software and its
|
||
|
* documentation is hereby granted, provided that both the copyright
|
||
|
* notice and this permission notice appear in all copies of the
|
||
|
* software, derivative works or modified versions, and any portions
|
||
|
* thereof, and that both notices appear in supporting documentation.
|
||
|
*
|
||
|
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
|
||
|
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
|
||
|
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
|
||
|
*
|
||
|
* Carnegie Mellon requests users of this software to return to
|
||
|
*
|
||
|
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
|
||
|
* School of Computer Science
|
||
|
* Carnegie Mellon University
|
||
|
* Pittsburgh PA 15213-3890
|
||
|
*
|
||
|
* any improvements or extensions that they make and grant Carnegie the rights
|
||
|
* to redistribute these changes.
|
||
|
*/
|
||
|
/* ci -- command interpreter
|
||
|
*
|
||
|
* Usage (etc.)
|
||
|
*
|
||
|
* HISTORY
|
||
|
* 22-Nov-85 Glenn Marcy (gm0w) at Carnegie-Mellon University
|
||
|
* Removed checks for VIRTUE window manager. If they don't like
|
||
|
* it then they can fix the more program.
|
||
|
*
|
||
|
* 08-May-85 Steven Shafer (sas) at Carnegie-Mellon University
|
||
|
* Increased MAXENTRIES and MAXHELPS from 200 to 400.
|
||
|
*
|
||
|
* 30-Apr-85 Steven Shafer (sas) at Carnegie-Mellon University
|
||
|
* Adapted for 4.2 UNIX. Added calls to check for
|
||
|
* using window manager of VIRTUE.
|
||
|
*
|
||
|
* 29-Apr-85 Steven Shafer (sas) at Carnegie-Mellon University
|
||
|
* Added two small bug fixes (courtesy of Richard Cohn).
|
||
|
*
|
||
|
* 14-Aug-84 Steven Shafer (sas) at Carnegie-Mellon University
|
||
|
* Added fflush(stdout) after printing prompt, before asking for input line.
|
||
|
*
|
||
|
* 01-Jul-83 Steven Shafer (sas) at Carnegie-Mellon University
|
||
|
* Bug fix: whitespace now required before ">filename" and not permitted
|
||
|
* within or after filename.
|
||
|
*
|
||
|
* 06-Jun-83 Steven Shafer (sas) at Carnegie-Mellon University
|
||
|
* Bug fix: added line to initialize "redirected" to 0.
|
||
|
*
|
||
|
* 20-May-83 Steven Shafer (sas) at Carnegie-Mellon University
|
||
|
* Added quiet bits CINOSEM, CINOFILE, CIFIRSTEQUAL to allow user to
|
||
|
* have special characters ; > = treated as normal data (except =
|
||
|
* after first argument, which still means "variable assignment").
|
||
|
* Also added output redirection via >filename on input line.
|
||
|
*
|
||
|
* 07-Mar-83 Dave McKeown (dmm) at Carnegie-Mellon University
|
||
|
* (Slight alterations by Steve Shafer.)
|
||
|
* Made cidepth a global, used for recursive and nested calls to
|
||
|
* ci(), and accessable to the user. Added '@x' command, similar
|
||
|
* to '^x' except that the previous command interpreter name is
|
||
|
* remembered and after 'x' is executed, the previous command
|
||
|
* interpreter is reinvoked. Users who plan to use this feature
|
||
|
* must save the name of the previous ci in global variable
|
||
|
* 'ciprev' after exit from the ci(). ie.
|
||
|
* ci(.........);
|
||
|
* strcpy(ciprev,"ci-name");
|
||
|
* Added ci state CICMDNOINDENT to allow for no indentation of the
|
||
|
* command line prompt based on cidepth.
|
||
|
* Reduced amount of indentation on source code.
|
||
|
* Bug: the "depth" argument is now a no-op, retained for backward
|
||
|
* compatibility. Cidepth is initialized to zero, and incremented
|
||
|
* upon invocation of a ci(). If cidepth is <1 then you are not
|
||
|
* in a ci() instantiation.
|
||
|
*
|
||
|
* 21-Feb-83 Steven Shafer (sas) at Carnegie-Mellon University
|
||
|
* Added up-arrow (^) command (and variable cinext). ^x is used when
|
||
|
* you have a ci program in which one command invokes ci with a
|
||
|
* new set of commands (i.e. a subsystem of the program). Inside the
|
||
|
* subsystem, ^x will exit the subsystem, and cause the main level
|
||
|
* to execute the command line "x" before reading more input lines.
|
||
|
* The cinext variable is used to implement this. Cinext can also be
|
||
|
* used by any user code which desires to force ci to execute a
|
||
|
* specific command before reading more input from the current file.
|
||
|
*
|
||
|
* 16-Jul-82 Steven Shafer (sas) at Carnegie-Mellon University
|
||
|
* Added extra code in _ci_help to eliminate duplicate help file
|
||
|
* names. This way, if several directories are specified and there
|
||
|
* is are files with the same name in more than one directory, only
|
||
|
* the first of each file will be included in the help list.
|
||
|
*
|
||
|
* It would have been nice to do this after the qsort instead of
|
||
|
* before (in ci_help). However, qsort does not ensure that
|
||
|
* "equivalent" entries are kept in the same relative
|
||
|
* order; thus there would be no way to ensure that the
|
||
|
* file being used was the first such file found.
|
||
|
*
|
||
|
* 07-Jul-82 William Chiles (wpc) at Carnegie-Mellon University
|
||
|
* Modified so that "!" invokes shell commands from the type of
|
||
|
* shell specified by the environment variable SHELL. If SHELL
|
||
|
* is not defined the standard shell is used.
|
||
|
*
|
||
|
* 21-Sep-81 Steven Shafer (sas) at Carnegie-Mellon University
|
||
|
* Increased LINELENGTH (input buffer length) to 1100 to satisfy
|
||
|
* voracious requirements of a certain user whose name I won't mention
|
||
|
* but whose initials are "faa".
|
||
|
*
|
||
|
* 08-Oct-80 Steven Shafer (sas) at Carnegie-Mellon University
|
||
|
* Added class variables: ci_tclass cases in ci_show and ci_set.
|
||
|
* Also added CICMDFPEEK in addition to existing CISETPEEK.
|
||
|
*
|
||
|
* 22-May-80 Steven Shafer (sas) at Carnegie-Mellon University
|
||
|
* Ci now sorts help topics into alphabetical order. Some interrupt
|
||
|
* handling has been added, but there are bugs, for example, when
|
||
|
* you interrupt "*" (the listing of command names). The right thing
|
||
|
* happens, but bogus messages are printed.
|
||
|
*
|
||
|
* 16-Apr-80 Steven Shafer (sas) at Carnegie-Mellon University
|
||
|
* Ci now prints lists of names with prstab(). This uses multiple
|
||
|
* columns when appropriate.
|
||
|
*
|
||
|
* 12-Mar-80 Steven Shafer (sas) at Carnegie-Mellon University
|
||
|
* Added code to skip over leading blanks and tabs in the argument list
|
||
|
* when executing commands, and setting and displaying variables.
|
||
|
* Also fixed meta-help, which mysteriously disappeared.
|
||
|
*
|
||
|
* 19-Feb-80 Steven Shafer (sas) at Carnegie-Mellon University
|
||
|
* Added "if (0) del();" to force del() routine to be loaded. This is
|
||
|
* the safest way I know of to define the external int "_del_". If you
|
||
|
* don't believe it, think again about separately compiled files.
|
||
|
*
|
||
|
* 28-Jan-80 Steven Shafer (sas) at Carnegie-Mellon University
|
||
|
* Created. Patterned (somewhat) after ci() on PDP-11.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
|
||
|
#include <strings.h>
|
||
|
#include <libc.h>
|
||
|
#include <ci.h>
|
||
|
#include <del.h>
|
||
|
|
||
|
char *index(),*getenv(),*rindex();
|
||
|
extern char _argbreak;
|
||
|
long atol();
|
||
|
double atof();
|
||
|
static int ci_help(), ci_show();
|
||
|
static int _ci_sho(), _ci_set(), ci_set();
|
||
|
|
||
|
/*************************
|
||
|
*** M A C R O S ***
|
||
|
*************************/
|
||
|
|
||
|
#define LINELENGTH 1100 /* max length of input line */
|
||
|
#define MAXENTRIES 400 /* max entries in entry list */
|
||
|
#define MAXHELPS 400 /* max help files available */
|
||
|
#define METAHELP "/usr/lib/ci.help" /* standard help file */
|
||
|
|
||
|
/*********************************************
|
||
|
*** G L O B A L V A R I A B L E S ***
|
||
|
*********************************************/
|
||
|
|
||
|
int ciquiet = 0; /* init globals */
|
||
|
int ciexit = 0;
|
||
|
int cidepth = 0;
|
||
|
int ciback = 0; /* for use in '@' command */
|
||
|
FILE *ciinput;
|
||
|
|
||
|
char cinext[LINELENGTH] = "";
|
||
|
char ciprev[LINELENGTH] = "";
|
||
|
|
||
|
static char *delchoice[] = { /* breakpoint choices */
|
||
|
"abort abort command file",
|
||
|
"breakpoint break to tty, then resume command file",
|
||
|
0};
|
||
|
|
||
|
/*************************************
|
||
|
*** M A I N R O U T I N E ***
|
||
|
*************************************/
|
||
|
|
||
|
ci (prompt,fil,depth,list,helppath,cmdfpath)
|
||
|
char *prompt; /* prompt message */
|
||
|
FILE *fil; /* input file */
|
||
|
int depth; /* recursion depth */
|
||
|
CIENTRY *list; /* entry list */
|
||
|
char *helppath; /* search list for help files */
|
||
|
char *cmdfpath; /* search list for command files */
|
||
|
|
||
|
{
|
||
|
|
||
|
FILE *savfile; /* input file for calling instance of ci */
|
||
|
int savquiet, savexit; /* globals for calling instance of ci */
|
||
|
char *p,*q,*cmd,*arg; /* temps for parsing input */
|
||
|
int i; /* temp */
|
||
|
char line[LINELENGTH]; /* input line buffer */
|
||
|
int firststmt; /* temp */
|
||
|
char *equals,*star; /* index of = and * in input line */
|
||
|
char cfnam[200]; /* name of command file */
|
||
|
char *name[MAXENTRIES]; /* name list for entries */
|
||
|
char *vname[MAXENTRIES]; /* name list for just variables */
|
||
|
int vnum[MAXENTRIES]; /* correspondence list for variables */
|
||
|
int nv; /* number of variables */
|
||
|
int helpcmd; /* "help" command index */
|
||
|
FILE *newfile; /* command file just opened */
|
||
|
char bprompt[100]; /* breakpoint prompt */
|
||
|
char *tname[MAXENTRIES]; /* temp name list */
|
||
|
int tnum; /* # entries in tname */
|
||
|
char *Shell; /* holds SHELL value from .login */
|
||
|
int redirected; /* 1 iff currently redirected output */
|
||
|
FILE savestdout; /* place to save normal std. output */
|
||
|
FILE *outfile; /* current output file */
|
||
|
char *outname; /* output file name */
|
||
|
|
||
|
|
||
|
/* force del() routine to be declared */
|
||
|
if (0) del();
|
||
|
/* save globals on stack */
|
||
|
cidepth++; /* bump the global depth, first CI() is 1 */
|
||
|
savquiet = ciquiet;
|
||
|
savexit = ciexit;
|
||
|
savfile = ciinput;
|
||
|
ciexit = 0; /* don't exit until this is set */
|
||
|
ciinput = (fil ? fil : stdin); /* new input file */
|
||
|
|
||
|
/* construct name lists for stablk */
|
||
|
|
||
|
nv = 0;
|
||
|
for (i=0; list[i].ci_etyp != ci_tend; i++) {
|
||
|
name[i] = list[i].ci_enam;
|
||
|
if (list[i].ci_etyp != ci_tcmd) { /* is variable */
|
||
|
vname[nv] = name[i];
|
||
|
vnum[nv] = i;
|
||
|
nv++;
|
||
|
}
|
||
|
}
|
||
|
helpcmd = i++; /* force-feed "help" onto list */
|
||
|
name[helpcmd] = "help";
|
||
|
name[i] = 0;
|
||
|
vname[nv] = 0;
|
||
|
|
||
|
/* loop for input lines */
|
||
|
|
||
|
redirected = 0;
|
||
|
while (!ciexit) {
|
||
|
|
||
|
if (*cinext) { /* get line from ^ command */
|
||
|
if (ciback) {
|
||
|
sprintf(line,"%s;%s",cinext,ciprev);
|
||
|
ciback = 0;
|
||
|
}
|
||
|
else {
|
||
|
strcpy (line,cinext);
|
||
|
}
|
||
|
strcpy (cinext,"");
|
||
|
p = line;
|
||
|
}
|
||
|
else { /* else read file */
|
||
|
if ((ciinput == stderr) || (ciinput == stdin) || (!(ciquiet&CICMDFPROMPT))) {
|
||
|
if (!(ciquiet &CICMDNOINDENT)) {
|
||
|
for (i=1; i<cidepth; i++) {
|
||
|
printf (" ");
|
||
|
}
|
||
|
}
|
||
|
printf ("%s ",prompt);
|
||
|
if ((ciinput == stderr) || (ciinput == stdin)) fflush (stdout);
|
||
|
}
|
||
|
p = fgets (line,LINELENGTH,ciinput); /* read input line */
|
||
|
if (p == 0) { /* EOF */
|
||
|
if (_del_) {
|
||
|
DELCLEAR;
|
||
|
strcpy (line,"");
|
||
|
p = line;
|
||
|
}
|
||
|
else {
|
||
|
ciexit = 1;
|
||
|
if ((ciinput==stdin) || (ciinput==stderr) ||
|
||
|
(!(ciquiet&CICMDFECHO))) printf ("\n");
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
if ((ciinput != stderr) && (ciinput != stdin) &&
|
||
|
(!(ciquiet&CICMDFECHO))) printf ("%s",line);
|
||
|
|
||
|
for (p=line; (*p) && (*p != '\n'); p++) ;
|
||
|
*p = 0; /* kill trailing newline */
|
||
|
p = line; /* points to start of line */
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* check for redirection of output */
|
||
|
|
||
|
if (!ciexit) {
|
||
|
outname = rindex (p,'>');
|
||
|
if (outname) {
|
||
|
if (outname == p || *(outname+1) == 0
|
||
|
|| ((*(outname-1) != ' ') && (*(outname-1) != '\t'))) {
|
||
|
outname = 0;
|
||
|
}
|
||
|
else {
|
||
|
for (q=outname+1; *q && (*q != ' ') && (*q != '\t'); q++) ;
|
||
|
if (*q) outname = 0;
|
||
|
}
|
||
|
}
|
||
|
if (outname && !(ciquiet&CINOFILE)) {
|
||
|
*outname++ = 0;
|
||
|
outfile = fopen (outname,"w");
|
||
|
if (outfile == 0) {
|
||
|
printf ("ci: Can't create output file %s\n",outname);
|
||
|
p = "";
|
||
|
}
|
||
|
else {
|
||
|
fflush (stdout);
|
||
|
savestdout = *stdout;
|
||
|
*stdout = *outfile;
|
||
|
redirected = 1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* loop for each command */
|
||
|
|
||
|
firststmt = 1; /* first time through loop */
|
||
|
while ((!ciexit) && (((ciquiet&CINOSEM) && firststmt) || *(cmd=nxtarg(&p,";")) || _argbreak)) {
|
||
|
|
||
|
if (ciquiet & CINOSEM) {
|
||
|
cmd = p;
|
||
|
firststmt = 0;
|
||
|
}
|
||
|
|
||
|
switch (*cmd) { /* what kind of line? */
|
||
|
|
||
|
case ':': /* : comment */
|
||
|
case 0: /* null line */
|
||
|
break;
|
||
|
|
||
|
case '!': /* ! shell command */
|
||
|
cmd = skipover (cmd+1," ");
|
||
|
if ((Shell = getenv("SHELL")) == 0) Shell = "sh";
|
||
|
if (*cmd) runp (Shell, Shell, "-c", cmd, 0);
|
||
|
else runp (Shell, Shell, 0);
|
||
|
if (!(ciquiet&CISHEXIT)) printf ("Back to %s\n",prompt);
|
||
|
break;
|
||
|
|
||
|
case '?': /* ? help */
|
||
|
cmd = skipover (cmd+1," ");
|
||
|
ci_help (cmd,helppath);
|
||
|
break;
|
||
|
|
||
|
case '<': /* < command file */
|
||
|
arg = cmd + 1;
|
||
|
cmd = nxtarg (&arg,0); /* parse name */
|
||
|
if (*cmd == 0) printf ("ci: missing filename\n");
|
||
|
else {
|
||
|
if (cmdfpath) newfile = fopenp (cmdfpath,cmd,cfnam,"r");
|
||
|
else newfile = fopen (cmd,"r");
|
||
|
|
||
|
if (newfile == 0)
|
||
|
printf ("ci: can't open command file %s\n",cmd);
|
||
|
else {
|
||
|
if (!(ciquiet&CICMDFECHO)) printf ("\n");
|
||
|
ci (prompt,newfile,cidepth,list,helppath,cmdfpath);
|
||
|
fclose (newfile);
|
||
|
if (!(ciquiet&CICMDFEXIT)) printf ("End of file\n\n");
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case '^': /* exit and do command */
|
||
|
case '@':
|
||
|
if (cidepth > 1) {
|
||
|
if (*cmd == '@') ciback = 1;
|
||
|
if (_argbreak == ';') *(cmd+strlen(cmd)) = ';';
|
||
|
ciexit = 1;
|
||
|
cmd = skipover(cmd+1," ");
|
||
|
strcpy (cinext,cmd);
|
||
|
}
|
||
|
else printf ("ci: ^ not allowed at top level of ci\n");
|
||
|
break;
|
||
|
|
||
|
default: /* list cmds, etc. */
|
||
|
equals = index (cmd,'=');
|
||
|
if (equals == cmd) cmd++;
|
||
|
|
||
|
if (equals) {
|
||
|
if (*(equals+1) == 0) *equals = 0;
|
||
|
else *equals = ' ';
|
||
|
}
|
||
|
|
||
|
arg = cmd; /* parse first word */
|
||
|
cmd = nxtarg (&arg,0);
|
||
|
if ((ciquiet&CIFIRSTEQUAL) && equals && equals>arg) {
|
||
|
*equals = '='; /* if user doesn't want extra =, kill */
|
||
|
equals = 0;
|
||
|
}
|
||
|
star = index (cmd,'*');
|
||
|
if (star) *star = 0;
|
||
|
if (star && equals) { /* list vars */
|
||
|
printf ("\n");
|
||
|
for (i=0; vname[i]; i++) {
|
||
|
if (stlmatch (vname[i],cmd)) {
|
||
|
ci_show (list[vnum[i]],arg,CIPEEK);
|
||
|
}
|
||
|
DELBREAK;
|
||
|
}
|
||
|
printf ("\n");
|
||
|
}
|
||
|
else if (star) { /* list cmds */
|
||
|
printf ("\n");
|
||
|
tnum = 0;
|
||
|
for (i=0;name[i]; i++) {
|
||
|
if ((i==helpcmd || list[i].ci_etyp == ci_tcmd) &&
|
||
|
stlmatch (name[i],cmd)) {
|
||
|
tname[tnum++] = name[i];
|
||
|
}
|
||
|
}
|
||
|
tname[tnum] = 0;
|
||
|
prstab (tname);
|
||
|
if (_del_) {_DELNOTE_}
|
||
|
printf ("\n");
|
||
|
}
|
||
|
else if (equals) { /* set var */
|
||
|
i = stablk (cmd,vname,0);
|
||
|
if (i >= 0) ci_set (list[vnum[i]],skipover(arg," \t"));
|
||
|
}
|
||
|
else {
|
||
|
i = stablk (cmd,name,0);
|
||
|
|
||
|
if (i == helpcmd) ci_help (arg,helppath);
|
||
|
else if (i >= 0) {
|
||
|
if (list[i].ci_etyp == ci_tcmd) {
|
||
|
(* (int(*)()) (list[i].ci_eptr)) (skipover(arg," \t"));
|
||
|
}
|
||
|
else ci_show (list[i],skipover(arg," \t"),CISHOW);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* end of command */
|
||
|
|
||
|
/* DEL trapping */
|
||
|
|
||
|
if (_del_) {
|
||
|
if (ciinput == stdin) {
|
||
|
DELCLEAR; /* already at tty level */
|
||
|
}
|
||
|
else {
|
||
|
_del_ = 0;
|
||
|
i = getstab ("INTERRUPT: abort or breakpoint?",delchoice,"abort");
|
||
|
if (i == 0) ciexit = 1; /* abort */
|
||
|
else { /* breakpoint */
|
||
|
sprintf (bprompt,"Breakpoint for %s",prompt);
|
||
|
ci (bprompt,0,cidepth,list,helppath,cmdfpath);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* end of loop for commands */
|
||
|
|
||
|
}
|
||
|
|
||
|
/* end of loop for lines of input file */
|
||
|
|
||
|
if (redirected) {
|
||
|
fflush (stdout);
|
||
|
fclose (stdout);
|
||
|
*stdout = savestdout;
|
||
|
redirected = 0;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
/* restore globals */
|
||
|
cidepth --; /* update current depth */
|
||
|
ciinput = savfile;
|
||
|
ciquiet = savquiet;
|
||
|
ciexit = savexit;
|
||
|
}
|
||
|
|
||
|
/********************************************
|
||
|
*** P R I N T H E L P F I L E ***
|
||
|
********************************************/
|
||
|
|
||
|
static int _h_found; /* how many matching names? */
|
||
|
static char **_h_list; /* list of matching names */
|
||
|
static char (*_h_nlist)[20]; /* list of filename part of names */
|
||
|
|
||
|
static int _ci_help (filspec)
|
||
|
/* called by searchp to expand filspec, adding names to _h_list */
|
||
|
char *filspec;
|
||
|
{
|
||
|
register int i,j,result;
|
||
|
char dir[200];
|
||
|
|
||
|
result = expand (filspec, _h_list + _h_found, MAXHELPS - _h_found);
|
||
|
if (result > 0) {
|
||
|
for (i=0; i<result; ) { /* elim duplicates */
|
||
|
path (_h_list[i+_h_found],dir,_h_nlist[i+_h_found]);
|
||
|
for (j=0;
|
||
|
j<_h_found && strcmp(_h_nlist[j],_h_nlist[i+_h_found]) != 0;
|
||
|
j++) ;
|
||
|
if (j < _h_found) { /* is duplicate */
|
||
|
--result;
|
||
|
strcpy (_h_list[i+_h_found],_h_list[result+_h_found]);
|
||
|
}
|
||
|
else i++; /* isn't duplicate */
|
||
|
}
|
||
|
|
||
|
_h_found += result;
|
||
|
}
|
||
|
|
||
|
return (1); /* keep searching */
|
||
|
}
|
||
|
|
||
|
/* for use in sorting help file names */
|
||
|
static ci_hcomp (p,q)
|
||
|
char **p,**q;
|
||
|
{
|
||
|
char dir[200],file1[20],file2[20];
|
||
|
path ((*p),dir,file1);
|
||
|
path ((*q),dir,file2);
|
||
|
return (strcmp(file1,file2));
|
||
|
}
|
||
|
|
||
|
static ci_help (topic,helppath)
|
||
|
char *topic,*helppath;
|
||
|
{
|
||
|
char *fnames[MAXHELPS]; /* names of matching files */
|
||
|
char names[MAXHELPS][20]; /* stripped filenames */
|
||
|
char *nptr[MAXHELPS+1]; /* list of ptrs for stablk */
|
||
|
char dir[200]; /* temp */
|
||
|
char shstr[300]; /* shell string for system */
|
||
|
int i;
|
||
|
char *star;
|
||
|
FILE *f;
|
||
|
|
||
|
if (*topic == 0) { /* wants meta-help */
|
||
|
f = fopen (METAHELP,"r");
|
||
|
if (f == 0) {
|
||
|
printf ("Yikes!! Can't open standard help file!\n");
|
||
|
}
|
||
|
else {
|
||
|
printf ("\n");
|
||
|
runp("more","more",METAHELP,0);
|
||
|
if (_del_) {_DELNOTE_}
|
||
|
printf ("\n");
|
||
|
fclose (f);
|
||
|
}
|
||
|
if (helppath && (*helppath) && (!getbool("Do you want a list of help topics?",1))) {
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
else { /* chop at * */
|
||
|
star = index (topic,'*');
|
||
|
if (star) *star = 0;
|
||
|
}
|
||
|
|
||
|
if (helppath == 0) { /* no help at all */
|
||
|
printf ("Sorry, no specific help is available for this program.\n");
|
||
|
}
|
||
|
else {
|
||
|
_h_found = 0;
|
||
|
_h_list = fnames;
|
||
|
_h_nlist = names;
|
||
|
searchp (helppath,"*",dir,_ci_help); /* find file names */
|
||
|
qsort (fnames,_h_found,sizeof(char *),ci_hcomp);
|
||
|
|
||
|
for (i=0; i<_h_found; i++) { /* strip pathnames */
|
||
|
path (fnames[i],dir,names[i]);
|
||
|
nptr[i] = names[i];
|
||
|
}
|
||
|
nptr[i] = 0;
|
||
|
|
||
|
if (*topic) { /* request some topic */
|
||
|
if (_h_found == 0) {
|
||
|
printf ("No help for %s. Type '?*' for list of help messages.\n",topic);
|
||
|
}
|
||
|
else {
|
||
|
i = stablk (topic,nptr,1);
|
||
|
if (i < 0) i = stabsearch (topic,nptr,0);
|
||
|
if (i >= 0) {
|
||
|
f = fopen (fnames[i],"r");
|
||
|
if (f == 0)
|
||
|
printf ("Yikes! Can't open help file %s\n",fnames[i]);
|
||
|
else {
|
||
|
printf ("\n");
|
||
|
runp("more","more",fnames[i],0);
|
||
|
if (_del_) {_DELNOTE_}
|
||
|
printf ("\n");
|
||
|
fclose (f);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else { /* request topic list */
|
||
|
printf ("\nHelp is available for these topics:\n");
|
||
|
prstab (nptr);
|
||
|
if (_del_) {_DELNOTE_}
|
||
|
printf ("\n");
|
||
|
}
|
||
|
|
||
|
for (i=0; i<_h_found; i++) free (fnames[i]);
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*********************************************************
|
||
|
*** S H O W V A L U E O F V A R I A B L E ***
|
||
|
*********************************************************/
|
||
|
|
||
|
static ci_show (entry,arg,mode)
|
||
|
CIENTRY entry; /* entry to display */
|
||
|
char *arg; /* arg for variable procedures */
|
||
|
CIMODE mode; /* mode (CIPEEK or CISHOW) */
|
||
|
{
|
||
|
if (entry.ci_etyp == ci_tproc) { /* procedure */
|
||
|
(* (int(*)()) (entry.ci_eptr)) (mode,arg);
|
||
|
}
|
||
|
else if (entry.ci_etyp == ci_tclass) { /* class variable */
|
||
|
(* (int(*)()) (entry.ci_eptr)) (mode,arg,entry.ci_evar,entry.ci_enam);
|
||
|
}
|
||
|
else {
|
||
|
printf ("%-14s \t",entry.ci_enam);
|
||
|
_ci_sho (entry.ci_etyp, entry.ci_eptr);
|
||
|
printf ("\n");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static _ci_sho (etype,eptr)
|
||
|
ci_type etype;
|
||
|
ci_union *eptr;
|
||
|
{
|
||
|
int i;
|
||
|
unsigned int u;
|
||
|
|
||
|
switch (etype) {
|
||
|
|
||
|
case ci_tint:
|
||
|
printf ("%d",eptr->ci_uint);
|
||
|
break;
|
||
|
case ci_tshort:
|
||
|
printf ("%d",eptr->ci_ushort);
|
||
|
break;
|
||
|
case ci_tlong:
|
||
|
printf ("%D",eptr->ci_ulong);
|
||
|
break;
|
||
|
case ci_toct:
|
||
|
if (eptr->ci_uoct) printf ("0");
|
||
|
printf ("%o",eptr->ci_uoct);
|
||
|
break;
|
||
|
case ci_thex:
|
||
|
if (eptr->ci_uhex) printf ("0x");
|
||
|
printf ("%x",eptr->ci_uhex);
|
||
|
break;
|
||
|
case ci_tdouble:
|
||
|
printf ("%g",eptr->ci_udouble);
|
||
|
break;
|
||
|
case ci_tfloat:
|
||
|
printf ("%g",eptr->ci_ufloat);
|
||
|
break;
|
||
|
case ci_tbool:
|
||
|
if (eptr->ci_ubool) printf ("yes");
|
||
|
else printf ("no");
|
||
|
break;
|
||
|
case ci_tstring:
|
||
|
printf ("%s",(char *)eptr);
|
||
|
break;
|
||
|
case ci_tcint:
|
||
|
printf ("%d",*(eptr->ci_ucint.ci_ival));
|
||
|
break;
|
||
|
case ci_tcshort:
|
||
|
printf ("%d",*(eptr->ci_ucshort.ci_sval));
|
||
|
break;
|
||
|
case ci_tclong:
|
||
|
printf ("%D",*(eptr->ci_uclong.ci_lval));
|
||
|
break;
|
||
|
case ci_tcoct:
|
||
|
u = *(eptr->ci_ucoct.ci_uval);
|
||
|
if (u) printf ("0");
|
||
|
printf ("%o",u);
|
||
|
break;
|
||
|
case ci_tchex:
|
||
|
u = *(eptr->ci_uchex.ci_uval);
|
||
|
if (u) printf ("0x");
|
||
|
printf ("%x",u);
|
||
|
break;
|
||
|
case ci_tcdouble:
|
||
|
printf ("%g",*(eptr->ci_ucdouble.ci_dval));
|
||
|
break;
|
||
|
case ci_tcfloat:
|
||
|
printf ("%g",*(eptr->ci_ucfloat.ci_fval));
|
||
|
break;
|
||
|
case ci_tcbool:
|
||
|
i = *(eptr->ci_ucbool.ci_bval);
|
||
|
if (i) printf ("yes");
|
||
|
else printf ("no");
|
||
|
break;
|
||
|
case ci_tcchr:
|
||
|
i = *(eptr->ci_ucchr.ci_cval);
|
||
|
printf ("%c",eptr->ci_ucchr.ci_cleg[i]);
|
||
|
break;
|
||
|
case ci_tcstring:
|
||
|
printf ("%s",eptr->ci_ucstring.ci_pval);
|
||
|
break;
|
||
|
case ci_tctab:
|
||
|
i = *(eptr->ci_ucstab.ci_tval);
|
||
|
printf ("%s",eptr->ci_ucstab.ci_ttab[i]);
|
||
|
break;
|
||
|
case ci_tcsearch:
|
||
|
i = *(eptr->ci_ucsearch.ci_tval);
|
||
|
printf ("%s",eptr->ci_ucsearch.ci_ttab[i]);
|
||
|
break;
|
||
|
default:
|
||
|
printf ("Yeek! Illegal cientry type %d!\n",(int) etype);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*************************************************************
|
||
|
*** A S S I G N V A L U E T O V A R I A B L E ***
|
||
|
*************************************************************/
|
||
|
|
||
|
static ci_set (entry,arg)
|
||
|
CIENTRY entry;
|
||
|
char *arg;
|
||
|
{
|
||
|
if (entry.ci_etyp == ci_tproc) { /* variable procedure */
|
||
|
(* (int(*)()) (entry.ci_eptr)) (CISET,arg);
|
||
|
}
|
||
|
else if (entry.ci_etyp == ci_tclass) { /* class variable */
|
||
|
(* (int(*)()) (entry.ci_eptr)) (CISET,arg,entry.ci_evar,entry.ci_enam);
|
||
|
}
|
||
|
else {
|
||
|
_ci_set (entry.ci_etyp, entry.ci_eptr, arg);
|
||
|
if (!(ciquiet & (((ciinput==stdin)||(ciinput==stderr)) ? CISETPEEK : CICMDFPEEK)))
|
||
|
ci_show (entry,arg,CIPEEK);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static _ci_set (etype,eptr,arg)
|
||
|
ci_type etype;
|
||
|
ci_union *eptr;
|
||
|
char *arg;
|
||
|
{
|
||
|
int i;
|
||
|
unsigned int u;
|
||
|
char *p;
|
||
|
|
||
|
if (etype == ci_tstring) {
|
||
|
strcpy ((char *)eptr,arg);
|
||
|
return;
|
||
|
}
|
||
|
if (etype == ci_tcstring) {
|
||
|
strarg (&arg, ";", eptr->ci_ucstring.ci_pmsg,
|
||
|
eptr->ci_ucstring.ci_pval,eptr->ci_ucstring.ci_pval);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
p = arg; /* parse first word */
|
||
|
arg = nxtarg (&p,0);
|
||
|
|
||
|
switch (etype) {
|
||
|
|
||
|
case ci_tint:
|
||
|
eptr->ci_uint = atoi (arg);
|
||
|
break;
|
||
|
case ci_tshort:
|
||
|
eptr->ci_ushort = atoi (arg);
|
||
|
break;
|
||
|
case ci_tlong:
|
||
|
eptr->ci_ulong = atol (arg);
|
||
|
break;
|
||
|
case ci_toct:
|
||
|
eptr->ci_uoct = atoo (arg);
|
||
|
break;
|
||
|
case ci_thex:
|
||
|
if (stlmatch(arg,"0x") || stlmatch(arg,"0X")) arg += 2;
|
||
|
eptr->ci_uhex = atoh (arg);
|
||
|
break;
|
||
|
case ci_tdouble:
|
||
|
eptr->ci_udouble = atof (arg);
|
||
|
break;
|
||
|
case ci_tfloat:
|
||
|
eptr->ci_ufloat = atof (arg);
|
||
|
break;
|
||
|
case ci_tbool:
|
||
|
eptr->ci_ubool = (index("yYtT",*arg) != 0);
|
||
|
break;
|
||
|
case ci_tcint:
|
||
|
*(eptr->ci_ucint.ci_ival) =
|
||
|
intarg (&arg,0,eptr->ci_ucint.ci_imsg,eptr->ci_ucint.ci_imin,
|
||
|
eptr->ci_ucint.ci_imax,*(eptr->ci_ucint.ci_ival));
|
||
|
break;
|
||
|
case ci_tcshort:
|
||
|
*(eptr->ci_ucshort.ci_sval) =
|
||
|
shortarg (&arg,0,eptr->ci_ucshort.ci_smsg,eptr->ci_ucshort.ci_smin,
|
||
|
eptr->ci_ucshort.ci_smax,*(eptr->ci_ucshort.ci_sval));
|
||
|
break;
|
||
|
case ci_tclong:
|
||
|
*(eptr->ci_uclong.ci_lval) =
|
||
|
longarg (&arg,0,eptr->ci_uclong.ci_lmsg,eptr->ci_uclong.ci_lmin,
|
||
|
eptr->ci_uclong.ci_lmax,*(eptr->ci_uclong.ci_lval));
|
||
|
break;
|
||
|
case ci_tcoct:
|
||
|
*(eptr->ci_ucoct.ci_uval) =
|
||
|
octarg (&arg,0,eptr->ci_ucoct.ci_umsg,eptr->ci_ucoct.ci_umin,
|
||
|
eptr->ci_ucoct.ci_umax,*(eptr->ci_ucoct.ci_uval));
|
||
|
break;
|
||
|
case ci_tchex:
|
||
|
*(eptr->ci_uchex.ci_uval) =
|
||
|
hexarg (&arg,0,eptr->ci_uchex.ci_umsg,eptr->ci_uchex.ci_umin,
|
||
|
eptr->ci_uchex.ci_umax,*(eptr->ci_uchex.ci_uval));
|
||
|
break;
|
||
|
case ci_tcdouble:
|
||
|
*(eptr->ci_ucdouble.ci_dval) =
|
||
|
doublearg (&arg,0,eptr->ci_ucdouble.ci_dmsg,eptr->ci_ucdouble.ci_dmin,
|
||
|
eptr->ci_ucdouble.ci_dmax,*(eptr->ci_ucdouble.ci_dval));
|
||
|
break;
|
||
|
case ci_tcfloat:
|
||
|
*(eptr->ci_ucfloat.ci_fval) =
|
||
|
floatarg (&arg,0,eptr->ci_ucfloat.ci_fmsg,eptr->ci_ucfloat.ci_fmin,
|
||
|
eptr->ci_ucfloat.ci_fmax,*(eptr->ci_ucfloat.ci_fval));
|
||
|
break;
|
||
|
case ci_tcbool:
|
||
|
*(eptr->ci_ucbool.ci_bval) =
|
||
|
boolarg (&arg,0,eptr->ci_ucbool.ci_bmsg,*(eptr->ci_ucbool.ci_bval));
|
||
|
break;
|
||
|
case ci_tcchr:
|
||
|
*(eptr->ci_ucchr.ci_cval) =
|
||
|
chrarg (&arg,0,eptr->ci_ucchr.ci_cmsg,eptr->ci_ucchr.ci_cleg,
|
||
|
eptr->ci_ucchr.ci_cleg[*(eptr->ci_ucchr.ci_cval)]);
|
||
|
break;
|
||
|
case ci_tctab:
|
||
|
*(eptr->ci_ucstab.ci_tval) =
|
||
|
stabarg (&arg,0,eptr->ci_ucstab.ci_tmsg,eptr->ci_ucstab.ci_ttab,
|
||
|
eptr->ci_ucstab.ci_ttab[*(eptr->ci_ucstab.ci_tval)]);
|
||
|
break;
|
||
|
case ci_tcsearch:
|
||
|
*(eptr->ci_ucsearch.ci_tval) =
|
||
|
searcharg (&arg,0,eptr->ci_ucsearch.ci_tmsg,
|
||
|
eptr->ci_ucsearch.ci_ttab,
|
||
|
eptr->ci_ucsearch.ci_ttab[*(eptr->ci_ucsearch.ci_tval)]);
|
||
|
break;
|
||
|
default:;
|
||
|
}
|
||
|
}
|