home *** CD-ROM | disk | FTP | other *** search
/ Nebula / nebula.bin / SourceCode / libcs / ci.c < prev    next >
C/C++ Source or Header  |  1992-05-15  |  26KB  |  851 lines

  1. /*
  2.  * Copyright (c) 1990 Carnegie Mellon University
  3.  * All Rights Reserved.
  4.  * 
  5.  * Permission to use, copy, modify and distribute this software and its
  6.  * documentation is hereby granted, provided that both the copyright
  7.  * notice and this permission notice appear in all copies of the
  8.  * software, derivative works or modified versions, and any portions
  9.  * thereof, and that both notices appear in supporting documentation.
  10.  *
  11.  * THE SOFTWARE IS PROVIDED "AS IS" AND CARNEGIE MELLON UNIVERSITY
  12.  * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
  13.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT
  14.  * SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR ANY SPECIAL, DIRECT,
  15.  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
  16.  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
  17.  * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  18.  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  19.  *
  20.  * Users of this software agree to return to Carnegie Mellon any
  21.  * improvements or extensions that they make and grant Carnegie the
  22.  * rights to redistribute these changes.
  23.  *
  24.  * Export of this software is permitted only after complying with the
  25.  * regulations of the U.S. Deptartment of Commerce relating to the
  26.  * Export of Technical Data.
  27.  */
  28. /*  ci  -- command interpreter
  29.  *
  30.  *  Usage (etc.)
  31.  *
  32.  * HISTORY
  33.  * $Log:    ci.c,v $
  34.  * Revision 1.2  90/12/11  17:51:01  mja
  35.  *     Add copyright/disclaimer for distribution.
  36.  * 
  37.  * 22-Nov-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  38.  *    Removed checks for VIRTUE window manager.  If they don't like
  39.  *    it then they can fix the more program.
  40.  *
  41.  * 08-May-85  Steven Shafer (sas) at Carnegie-Mellon University
  42.  *    Increased MAXENTRIES and MAXHELPS from 200 to 400.
  43.  *
  44.  * 30-Apr-85  Steven Shafer (sas) at Carnegie-Mellon University
  45.  *    Adapted for 4.2 UNIX.  Added calls to check for
  46.  *    using window manager of VIRTUE.
  47.  *
  48.  * 29-Apr-85  Steven Shafer (sas) at Carnegie-Mellon University
  49.  *    Added two small bug fixes (courtesy of Richard Cohn).
  50.  *
  51.  * 14-Aug-84  Steven Shafer (sas) at Carnegie-Mellon University
  52.  *    Added fflush(stdout) after printing prompt, before asking for input line.
  53.  *
  54.  * 01-Jul-83  Steven Shafer (sas) at Carnegie-Mellon University
  55.  *    Bug fix: whitespace now required before ">filename" and not permitted
  56.  *    within or after filename.
  57.  *
  58.  * 06-Jun-83  Steven Shafer (sas) at Carnegie-Mellon University
  59.  *    Bug fix: added line to initialize "redirected" to 0.
  60.  *
  61.  * 20-May-83  Steven Shafer (sas) at Carnegie-Mellon University
  62.  *    Added quiet bits CINOSEM, CINOFILE, CIFIRSTEQUAL to allow user to
  63.  *    have special characters ; > = treated as normal data (except =
  64.  *    after first argument, which still means "variable assignment").
  65.  *    Also added output redirection via >filename on input line.
  66.  *
  67.  * 07-Mar-83  Dave McKeown (dmm) at Carnegie-Mellon University
  68.  *    (Slight alterations by Steve Shafer.)
  69.  *    Made cidepth a global, used for recursive and nested calls to
  70.  *    ci(), and accessable to the user.  Added '@x' command, similar
  71.  *    to '^x' except that the previous command interpreter name is
  72.  *    remembered and after 'x' is executed, the previous command
  73.  *    interpreter is reinvoked.  Users who plan to use this feature
  74.  *    must save the name of the previous ci in global variable 
  75.  *    'ciprev' after exit from the ci().  ie.  
  76.  *        ci(.........);
  77.  *        strcpy(ciprev,"ci-name");
  78.  *    Added ci state CICMDNOINDENT to allow for no indentation of the
  79.  *    command line prompt based on cidepth.
  80.  *    Reduced amount of indentation on source code.
  81.  *    Bug: the "depth" argument is now a no-op, retained for backward
  82.  *    compatibility.  Cidepth is initialized to zero, and incremented
  83.  *    upon invocation of a ci().  If cidepth is <1 then you are not
  84.  *    in a ci() instantiation.
  85.  *
  86.  * 21-Feb-83  Steven Shafer (sas) at Carnegie-Mellon University
  87.  *    Added up-arrow (^) command (and variable cinext).  ^x is used when
  88.  *    you have a ci program in which one command invokes ci with a
  89.  *    new set of commands (i.e. a subsystem of the program).  Inside the
  90.  *    subsystem, ^x will exit the subsystem, and cause the main level
  91.  *    to execute the command line "x" before reading more input lines.
  92.  *    The cinext variable is used to implement this.  Cinext can also be
  93.  *    used by any user code which desires to force ci to execute a
  94.  *    specific command before reading more input from the current file.
  95.  *
  96.  * 16-Jul-82  Steven Shafer (sas) at Carnegie-Mellon University
  97.  *    Added extra code in _ci_help to eliminate duplicate help file
  98.  *    names.  This way, if several directories are specified and there
  99.  *    is are files with the same name in more than one directory, only
  100.  *    the first of each file will be included in the help list.
  101.  *    
  102.  *    It would have been nice to do this after the qsort instead of
  103.  *    before (in ci_help).  However, qsort does not ensure that
  104.  *    "equivalent" entries are kept in the same relative
  105.  *    order; thus there would be no way to ensure that the
  106.  *    file being used was the first such file found.
  107.  *
  108.  * 07-Jul-82  William Chiles (wpc) at Carnegie-Mellon University
  109.  *    Modified so that "!" invokes shell commands from the type of 
  110.  *      shell specified by the environment variable SHELL.  If SHELL
  111.  *    is not defined the standard shell is used.
  112.  *
  113.  * 21-Sep-81  Steven Shafer (sas) at Carnegie-Mellon University
  114.  *    Increased LINELENGTH (input buffer length) to 1100 to satisfy
  115.  *    voracious requirements of a certain user whose name I won't mention
  116.  *    but whose initials are "faa".
  117.  *
  118.  * 08-Oct-80  Steven Shafer (sas) at Carnegie-Mellon University
  119.  *    Added class variables:  ci_tclass cases in ci_show and ci_set.
  120.  *    Also added CICMDFPEEK in addition to existing CISETPEEK.
  121.  *
  122.  * 22-May-80  Steven Shafer (sas) at Carnegie-Mellon University
  123.  *    Ci now sorts help topics into alphabetical order.  Some interrupt
  124.  *    handling has been added, but there are bugs, for example, when
  125.  *    you interrupt "*" (the listing of command names).  The right thing
  126.  *    happens, but bogus messages are printed.
  127.  *
  128.  * 16-Apr-80  Steven Shafer (sas) at Carnegie-Mellon University
  129.  *    Ci now prints lists of names with prstab().  This uses multiple
  130.  *    columns when appropriate.
  131.  *
  132.  * 12-Mar-80  Steven Shafer (sas) at Carnegie-Mellon University
  133.  *    Added code to skip over leading blanks and tabs in the argument list
  134.  *    when executing commands, and setting and displaying variables.
  135.  *    Also fixed meta-help, which mysteriously disappeared.
  136.  *
  137.  * 19-Feb-80  Steven Shafer (sas) at Carnegie-Mellon University
  138.  *    Added "if (0) del();" to force del() routine to be loaded.  This is
  139.  *    the safest way I know of to define the external int "_del_".  If you
  140.  *    don't believe it, think again about separately compiled files.
  141.  *
  142.  * 28-Jan-80  Steven Shafer (sas) at Carnegie-Mellon University
  143.  *    Created.  Patterned (somewhat) after ci() on PDP-11.
  144.  *
  145.  */
  146.  
  147.  
  148. #include <strings.h>
  149. #include <stdlib.h>
  150. #include <libc.h>
  151. #include <ci.h>
  152. #include <del.h>
  153.  
  154. extern char _argbreak;
  155.  
  156. /*************************
  157.  ***    M A C R O S    ***
  158.  *************************/
  159.  
  160. #define LINELENGTH 1100        /* max length of input line */
  161. #define MAXENTRIES 400        /* max entries in entry list */
  162. #define MAXHELPS 400        /* max help files available */
  163. #define METAHELP "/usr/cs/lib/ci.help"    /* standard help file */
  164.  
  165. /*********************************************
  166.  ***    G L O B A L   V A R I A B L E S    ***
  167.  *********************************************/
  168.  
  169. int ciquiet = 0;        /* init globals */
  170. int ciexit  = 0;
  171. int cidepth = 0;
  172. int ciback  = 0;        /* for use in '@' command */
  173. FILE *ciinput;
  174.  
  175. char cinext[LINELENGTH] = "";
  176. char ciprev[LINELENGTH] = "";
  177.  
  178. static char *delchoice[] = {    /* breakpoint choices */
  179.     "abort        abort command file",
  180.     "breakpoint    break to tty, then resume command file",
  181.     0};
  182.  
  183. /*************************************
  184.  ***    M A I N   R O U T I N E    ***
  185.  *************************************/
  186.  
  187. ci (prompt,fil,depth,list,helppath,cmdfpath)
  188. char *prompt;            /* prompt message */
  189. FILE *fil;            /* input file */
  190. int depth;            /* recursion depth */
  191. CIENTRY *list;            /* entry list */
  192. char *helppath;            /* search list for help files */
  193. char *cmdfpath;            /* search list for command files */
  194.  
  195. {
  196.  
  197.   FILE *savfile;      /* input file for calling instance of ci */
  198.   int savquiet, savexit;  /* globals for calling instance of ci */
  199.   char *p,*q,*cmd,*arg;      /* temps for parsing input */
  200.   int i;            /* temp */
  201.   char line[LINELENGTH];    /* input line buffer */
  202.   int firststmt;    /* temp */
  203.   char *equals,*star;    /* index of = and * in input line */
  204.   char cfnam[200];    /* name of command file */
  205.   char *name[MAXENTRIES];    /* name list for entries */
  206.   char *vname[MAXENTRIES];    /* name list for just variables */
  207.   int vnum[MAXENTRIES];    /* correspondence list for variables */
  208.   int nv;            /* number of variables */
  209.   int helpcmd;        /* "help" command index */
  210.   FILE *newfile;        /* command file just opened */
  211.   char bprompt[100];    /* breakpoint prompt */
  212.   char *tname[MAXENTRIES];    /* temp name list */
  213.   int tnum;        /* # entries in tname */
  214.   char *Shell;            /* holds SHELL value from .login */
  215.   int redirected;    /* 1 iff currently redirected output */
  216.   FILE savestdout;        /* place to save normal std. output */
  217.   FILE *outfile;        /* current output file */
  218.   char *outname;        /* output file name */
  219.   
  220.  
  221.   /* force del() routine to be declared */
  222.   if (0) del();
  223.   /* save globals on stack */
  224.   cidepth++;    /* bump the global depth, first CI() is 1 */
  225.   savquiet = ciquiet;
  226.   savexit = ciexit;
  227.   savfile = ciinput;
  228.   ciexit = 0;        /* don't exit until this is set */
  229.   ciinput = (fil ? fil : stdin);        /* new input file */
  230.  
  231.   /* construct name lists for stablk */
  232.  
  233.   nv = 0;
  234.   for (i=0; list[i].ci_etyp != ci_tend; i++) {
  235.       name[i] = list[i].ci_enam;
  236.       if (list[i].ci_etyp != ci_tcmd) {    /* is variable */
  237.           vname[nv] = name[i];
  238.           vnum[nv] = i;
  239.           nv++;
  240.       }
  241.   }
  242.   helpcmd = i++;        /* force-feed "help" onto list */
  243.   name[helpcmd] = "help";
  244.   name[i] = 0;
  245.   vname[nv] = 0;
  246.  
  247.   /* loop for input lines */
  248.  
  249.   redirected = 0;
  250.   while (!ciexit) {
  251.  
  252.     if (*cinext) {        /* get line from ^ command */
  253.          if (ciback) { 
  254.             sprintf(line,"%s;%s",cinext,ciprev);    
  255.           ciback = 0;
  256.     }
  257.         else {
  258.       strcpy (line,cinext);
  259.     }
  260.         strcpy (cinext,"");
  261.         p = line;
  262.     }
  263.     else {            /* else read file */
  264.         if ((ciinput == stderr) || (ciinput == stdin) || (!(ciquiet&CICMDFPROMPT))) {
  265.           if (!(ciquiet &CICMDNOINDENT)) {
  266.         for (i=1; i<cidepth; i++) {
  267.         printf ("    ");
  268.         }
  269.       }
  270.           printf ("%s ",prompt);
  271.       if ((ciinput == stderr) || (ciinput == stdin))  fflush (stdout);
  272.         }
  273.         p = fgets (line,LINELENGTH,ciinput);    /* read input line */
  274.         if (p == 0) {        /* EOF */
  275.           if (_del_) {
  276.             DELCLEAR;
  277.             strcpy (line,"");
  278.             p = line;
  279.           }
  280.           else {
  281.             ciexit = 1;
  282.             if ((ciinput==stdin) || (ciinput==stderr) || 
  283.           (!(ciquiet&CICMDFECHO))) printf ("\n");
  284.           }
  285.         }
  286.         else {
  287.             if ((ciinput != stderr) && (ciinput != stdin) && 
  288.           (!(ciquiet&CICMDFECHO))) printf ("%s",line);
  289.  
  290.             for (p=line; (*p) && (*p != '\n'); p++) ;
  291.             *p = 0;        /* kill trailing newline */
  292.             p = line;    /* points to start of line */
  293.         }
  294.     }
  295.  
  296.     /* check for redirection of output */
  297.  
  298.     if (!ciexit) {
  299.     outname = rindex (p,'>');
  300.         if (outname) {
  301.             if (outname == p || *(outname+1) == 0
  302.              || ((*(outname-1) != ' ') && (*(outname-1) != '\t'))) {
  303.             outname = 0;
  304.             }
  305.         else {
  306.             for (q=outname+1; *q && (*q != ' ') && (*q != '\t'); q++) ;
  307.             if (*q)  outname = 0;
  308.             }
  309.         }
  310.         if (outname && !(ciquiet&CINOFILE)) {
  311.         *outname++ = 0;
  312.         outfile = fopen (outname,"w");
  313.         if (outfile == 0) {
  314.             printf ("ci: Can't create output file %s\n",outname);
  315.             p = "";
  316.         }
  317.         else {
  318.             fflush (stdout);
  319.             savestdout = *stdout;
  320.             *stdout = *outfile;
  321.             redirected = 1;
  322.         }
  323.         }
  324.     }
  325.  
  326.     /* loop for each command */
  327.  
  328.     firststmt = 1;        /* first time through loop */
  329.     while ((!ciexit) && (((ciquiet&CINOSEM) && firststmt) || *(cmd=nxtarg(&p,";")) || _argbreak)) {
  330.  
  331.     if (ciquiet & CINOSEM) {
  332.         cmd = p;
  333.         firststmt = 0;
  334.     }
  335.  
  336.         switch (*cmd) {        /* what kind of line? */
  337.  
  338.         case ':':        /* :  comment */
  339.         case 0:            /*    null line */
  340.             break;
  341.  
  342.         case '!':        /* !  shell command */
  343.           cmd = skipover (cmd+1," ");
  344.           if ((Shell = getenv("SHELL")) == 0) Shell = "sh";
  345.           if (*cmd)    runp (Shell, Shell, "-c", cmd, 0);
  346.           else        runp (Shell, Shell, 0);
  347.           if (!(ciquiet&CISHEXIT))  printf ("Back to %s\n",prompt);
  348.          break;
  349.  
  350.         case '?':        /* ?  help */
  351.           cmd = skipover (cmd+1," ");
  352.           ci_help (cmd,helppath);
  353.           break;
  354.  
  355.         case '<':        /* <  command file */
  356.           arg = cmd + 1;
  357.           cmd = nxtarg (&arg,0);    /* parse name */
  358.           if (*cmd == 0) printf ("ci: missing filename\n");
  359.           else {
  360.             if (cmdfpath)  newfile = fopenp (cmdfpath,cmd,cfnam,"r");
  361.             else       newfile = fopen (cmd,"r");
  362.  
  363.               if (newfile == 0) 
  364.               printf ("ci: can't open command file %s\n",cmd);
  365.             else {
  366.               if (!(ciquiet&CICMDFECHO))  printf ("\n");
  367.               ci (prompt,newfile,cidepth,list,helppath,cmdfpath);
  368.               fclose (newfile);
  369.               if (!(ciquiet&CICMDFEXIT))  printf ("End of file\n\n");
  370.             }
  371.           }
  372.           break;
  373.         
  374.         case '^':        /* exit and do command */
  375.     case '@':
  376.           if (cidepth > 1) {
  377.             if (*cmd == '@') ciback = 1;
  378.             if (_argbreak == ';')  *(cmd+strlen(cmd)) = ';';
  379.             ciexit = 1;
  380.             cmd = skipover(cmd+1," ");
  381.             strcpy (cinext,cmd);
  382.           }
  383.           else printf ("ci: ^ not allowed at top level of ci\n");
  384.           break;
  385.  
  386.         default:        /* list cmds, etc. */
  387.           equals = index (cmd,'=');
  388.           if (equals == cmd)  cmd++;
  389.  
  390.           if (equals) {
  391.             if (*(equals+1) == 0)  *equals = 0;
  392.             else  *equals = ' ';
  393.           }
  394.  
  395.           arg = cmd;    /* parse first word */
  396.           cmd = nxtarg (&arg,0);
  397.       if ((ciquiet&CIFIRSTEQUAL) && equals && equals>arg) {
  398.         *equals = '=';    /* if user doesn't want extra =, kill */
  399.         equals = 0;
  400.       }
  401.           star = index (cmd,'*');
  402.           if (star)  *star = 0;
  403.           if (star && equals) {    /* list vars */
  404.             printf ("\n");
  405.             for (i=0; vname[i]; i++) {
  406.               if (stlmatch (vname[i],cmd)) {
  407.             ci_show (list[vnum[i]],arg,CIPEEK);
  408.               }
  409.               DELBREAK;
  410.             }
  411.             printf ("\n");
  412.           }
  413.           else if (star) {    /* list cmds */
  414.             printf ("\n");
  415.             tnum = 0;
  416.             for (i=0;name[i]; i++) {
  417.               if ((i==helpcmd || list[i].ci_etyp == ci_tcmd) && 
  418.         stlmatch (name[i],cmd)) {
  419.                   tname[tnum++] = name[i];
  420.               }
  421.             }
  422.             tname[tnum] = 0;
  423.             prstab (tname);
  424.             if (_del_)  {_DELNOTE_}
  425.             printf ("\n");
  426.           }
  427.         else if (equals) {    /* set var */
  428.           i = stablk (cmd,vname,0);
  429.           if (i >= 0)  ci_set (list[vnum[i]],skipover(arg," \t"));
  430.         }
  431.       else {
  432.         i = stablk (cmd,name,0);
  433.  
  434.         if (i == helpcmd) ci_help (arg,helppath);
  435.         else if (i >= 0) {
  436.             if (list[i].ci_etyp == ci_tcmd) {
  437.             (* (int(*)()) (list[i].ci_eptr)) (skipover(arg," \t"));
  438.           }
  439.           else ci_show (list[i],skipover(arg," \t"),CISHOW);
  440.         }
  441.       }
  442.     }
  443.  
  444.         /* end of command */
  445.  
  446.         /* DEL trapping */
  447.  
  448.    if (_del_) {
  449.        if (ciinput == stdin) {
  450.             DELCLEAR;    /* already at tty level */
  451.           }
  452.         else {
  453.            _del_ = 0;
  454.           i = getstab ("INTERRUPT:  abort or breakpoint?",delchoice,"abort");
  455.           if (i == 0) ciexit = 1;     /* abort */
  456.           else {        /* breakpoint */
  457.             sprintf (bprompt,"Breakpoint for %s",prompt);
  458.             ci (bprompt,0,cidepth,list,helppath,cmdfpath);
  459.             }
  460.           }
  461.         }
  462.  
  463.         /* end of loop for commands */
  464.  
  465.     }
  466.  
  467.     /* end of loop for lines of input file */
  468.  
  469.     if (redirected) {
  470.     fflush (stdout);
  471.     fclose (stdout);
  472.     *stdout = savestdout;
  473.     redirected = 0;
  474.     }
  475.  
  476.   }
  477.  
  478.   /* restore globals */
  479.   cidepth --;        /* update current depth */
  480.   ciinput = savfile;
  481.   ciquiet = savquiet;
  482.   ciexit = savexit;
  483. }
  484.  
  485. /********************************************
  486.  ***    P R I N T   H E L P   F I L E     ***
  487.  ********************************************/
  488.  
  489. static int _h_found;      /* how many matching names? */
  490. static char **_h_list;      /* list of matching names */
  491. static char (*_h_nlist)[20];  /* list of filename part of names */
  492.  
  493. static int _ci_help (filspec)
  494. /* called by searchp to expand filspec, adding names to _h_list */
  495. char *filspec;
  496. {
  497.   register int i,j,result;
  498.   char dir[200];
  499.  
  500.   result = expand (filspec, _h_list + _h_found, MAXHELPS - _h_found);
  501.   if (result > 0) { 
  502.     for (i=0; i<result; ) {        /* elim duplicates */
  503.       path (_h_list[i+_h_found],dir,_h_nlist[i+_h_found]);
  504.       for (j=0;
  505.         j<_h_found && strcmp(_h_nlist[j],_h_nlist[i+_h_found]) != 0;
  506.           j++) ;
  507.       if (j < _h_found) {    /* is duplicate */
  508.         --result;
  509.         strcpy (_h_list[i+_h_found],_h_list[result+_h_found]);
  510.         }
  511.       else i++;    /* isn't duplicate */
  512.       }
  513.  
  514.   _h_found += result;
  515.   }
  516.   
  517.   return (1);    /* keep searching */
  518. }
  519.  
  520. /*  for use in sorting help file names */
  521. static ci_hcomp (p,q)
  522. char **p,**q;
  523. {
  524.   char dir[200],file1[20],file2[20];
  525.   path ((*p),dir,file1);
  526.   path ((*q),dir,file2);
  527.   return (strcmp(file1,file2));
  528. }
  529.  
  530. static ci_help (topic,helppath)
  531. char *topic,*helppath;
  532. {
  533.   char *fnames[MAXHELPS];        /* names of matching files */
  534.   char names[MAXHELPS][20];    /* stripped filenames */
  535.   char *nptr[MAXHELPS+1];        /* list of ptrs for stablk */
  536.   char dir[200];            /* temp */
  537.   char shstr[300];        /* shell string for system */
  538.   int i;
  539.   char *star;
  540.   FILE *f;
  541.  
  542.   if (*topic == 0) {        /* wants meta-help */
  543.       f = fopen (METAHELP,"r");
  544.       if (f == 0) {
  545.           printf ("Yikes!!  Can't open standard help file!\n");
  546.       }
  547.       else {
  548.           printf ("\n");
  549.         runp("more","more",METAHELP,0);
  550.           if (_del_)  {_DELNOTE_}
  551.           printf ("\n");
  552.           fclose (f);
  553.       }
  554.       if (helppath && (*helppath) && (!getbool("Do you want a list of help topics?",1))) {
  555.           return;
  556.       }
  557.   }
  558.   else {                /* chop at * */
  559.       star = index (topic,'*');
  560.       if (star)  *star = 0;
  561.   }
  562.  
  563.   if (helppath == 0) {        /* no help at all */
  564.       printf ("Sorry, no specific help is available for this program.\n");
  565.   }
  566.   else {
  567.       _h_found = 0;
  568.       _h_list = fnames;
  569.       _h_nlist = names;
  570.       searchp (helppath,"*",dir,_ci_help);    /* find file names */
  571.       qsort (fnames,_h_found,sizeof(char *),ci_hcomp);
  572.  
  573.       for (i=0; i<_h_found; i++) {    /* strip pathnames */
  574.           path (fnames[i],dir,names[i]);
  575.           nptr[i] = names[i];
  576.       }
  577.       nptr[i] = 0;
  578.  
  579.       if (*topic) {        /* request some topic */
  580.         if (_h_found == 0) {
  581.           printf ("No help for %s.  Type '?*' for list of help messages.\n",topic);
  582.           }
  583.         else {
  584.           i = stablk (topic,nptr,1);
  585.           if (i < 0)  i = stabsearch (topic,nptr,0);
  586.           if (i >= 0) {
  587.             f = fopen (fnames[i],"r");
  588.             if (f == 0) 
  589.           printf ("Yikes!  Can't open help file %s\n",fnames[i]);
  590.             else {
  591.               printf ("\n");
  592.         runp("more","more",fnames[i],0);
  593.           if (_del_)  {_DELNOTE_}
  594.           printf ("\n");
  595.           fclose (f);
  596.           }
  597.             }
  598.           }
  599.       }
  600.       else {            /* request topic list */
  601.         printf ("\nHelp is available for these topics:\n");
  602.         prstab (nptr);
  603.         if (_del_)  {_DELNOTE_}
  604.         printf ("\n");
  605.       }
  606.  
  607.       for (i=0; i<_h_found; i++)  free (fnames[i]);
  608.  
  609.   }
  610. }
  611.  
  612. /*********************************************************
  613.  ***    S H O W   V A L U E   O F   V A R I A B L E    ***
  614.  *********************************************************/
  615.  
  616. static ci_show (entry,arg,mode)
  617. CIENTRY entry;          /* entry to display */
  618. char *arg;          /* arg for variable procedures */
  619. CIMODE mode;          /* mode (CIPEEK or CISHOW) */
  620. {
  621.   if (entry.ci_etyp == ci_tproc) {    /* procedure */
  622.       (* (int(*)()) (entry.ci_eptr)) (mode,arg);
  623.   }
  624.   else if (entry.ci_etyp == ci_tclass) {    /* class variable */
  625.       (* (int(*)()) (entry.ci_eptr)) (mode,arg,entry.ci_evar,entry.ci_enam);
  626.   }
  627.   else {
  628.       printf ("%-14s \t",entry.ci_enam);
  629.       _ci_sho (entry.ci_etyp, entry.ci_eptr);
  630.       printf ("\n");
  631.   }
  632. }
  633.  
  634. static _ci_sho (etype,eptr)
  635. ci_type etype;
  636. ci_union *eptr;
  637. {
  638.   int i;
  639.   unsigned int u;
  640.  
  641.   switch (etype) {
  642.  
  643.   case ci_tint:
  644.       printf ("%d",eptr->ci_uint);
  645.       break;
  646.   case ci_tshort:
  647.       printf ("%d",eptr->ci_ushort);
  648.       break;
  649.   case ci_tlong:
  650.       printf ("%D",eptr->ci_ulong);
  651.       break;
  652.   case ci_toct:
  653.       if (eptr->ci_uoct)  printf ("0");
  654.       printf ("%o",eptr->ci_uoct);
  655.       break;
  656.   case ci_thex:
  657.       if (eptr->ci_uhex)  printf ("0x");
  658.       printf ("%x",eptr->ci_uhex);
  659.       break;
  660.   case ci_tdouble:
  661.       printf ("%g",eptr->ci_udouble);
  662.       break;
  663.   case ci_tfloat:
  664.       printf ("%g",eptr->ci_ufloat);
  665.       break;
  666.   case ci_tbool:
  667.       if (eptr->ci_ubool)    printf ("yes");
  668.       else            printf ("no");
  669.       break;
  670.   case ci_tstring:
  671.       printf ("%s",(char *)eptr);
  672.       break;
  673.   case ci_tcint:
  674.       printf ("%d",*(eptr->ci_ucint.ci_ival));
  675.       break;
  676.   case ci_tcshort:
  677.       printf ("%d",*(eptr->ci_ucshort.ci_sval));
  678.       break;
  679.   case ci_tclong:
  680.       printf ("%D",*(eptr->ci_uclong.ci_lval));
  681.       break;
  682.   case ci_tcoct:
  683.       u = *(eptr->ci_ucoct.ci_uval);
  684.       if (u)  printf ("0");
  685.       printf ("%o",u);
  686.       break;
  687.   case ci_tchex:
  688.       u = *(eptr->ci_uchex.ci_uval);
  689.       if (u)  printf ("0x");
  690.       printf ("%x",u);
  691.       break;
  692.   case ci_tcdouble:
  693.       printf ("%g",*(eptr->ci_ucdouble.ci_dval));
  694.       break;
  695.   case ci_tcfloat:
  696.       printf ("%g",*(eptr->ci_ucfloat.ci_fval));
  697.       break;
  698.   case ci_tcbool:
  699.       i = *(eptr->ci_ucbool.ci_bval);
  700.       if (i)    printf ("yes");
  701.       else    printf ("no");
  702.       break;
  703.   case ci_tcchr:
  704.       i = *(eptr->ci_ucchr.ci_cval);
  705.       printf ("%c",eptr->ci_ucchr.ci_cleg[i]);
  706.       break;
  707.   case ci_tcstring:
  708.       printf ("%s",eptr->ci_ucstring.ci_pval);
  709.       break;
  710.   case ci_tctab:
  711.       i = *(eptr->ci_ucstab.ci_tval);
  712.       printf ("%s",eptr->ci_ucstab.ci_ttab[i]);
  713.       break;
  714.   case ci_tcsearch:
  715.       i = *(eptr->ci_ucsearch.ci_tval);
  716.       printf ("%s",eptr->ci_ucsearch.ci_ttab[i]);
  717.       break;
  718.   default:
  719.       printf ("Yeek!  Illegal cientry type %d!\n",(int) etype);
  720.   }
  721. }
  722.  
  723. /*************************************************************
  724.  ***    A S S I G N   V A L U E   T O   V A R I A B L E    ***
  725.  *************************************************************/
  726.  
  727. static ci_set (entry,arg)
  728. CIENTRY entry;
  729. char *arg;
  730. {
  731.   if (entry.ci_etyp == ci_tproc) {    /* variable procedure */
  732.       (* (int(*)()) (entry.ci_eptr)) (CISET,arg);
  733.   }
  734.   else if (entry.ci_etyp == ci_tclass) {    /* class variable */
  735.       (* (int(*)()) (entry.ci_eptr)) (CISET,arg,entry.ci_evar,entry.ci_enam);
  736.   }
  737.   else {
  738.       _ci_set (entry.ci_etyp, entry.ci_eptr, arg);
  739.       if (!(ciquiet & (((ciinput==stdin)||(ciinput==stderr)) ? CISETPEEK : CICMDFPEEK)))
  740.           ci_show (entry,arg,CIPEEK);
  741.   }
  742. }
  743.  
  744. static _ci_set (etype,eptr,arg)
  745. ci_type etype;
  746. ci_union *eptr;
  747. char *arg;
  748. {
  749.   int i;
  750.   unsigned int u;
  751.   char *p;
  752.  
  753.   if (etype == ci_tstring) {
  754.       strcpy ((char *)eptr,arg);
  755.       return;
  756.   }
  757.   if (etype == ci_tcstring) {
  758.       strarg (&arg, ";", eptr->ci_ucstring.ci_pmsg,
  759.       eptr->ci_ucstring.ci_pval,eptr->ci_ucstring.ci_pval);
  760.       return;
  761.   }
  762.  
  763.   p = arg;        /* parse first word */
  764.   arg = nxtarg (&p,0);
  765.  
  766.   switch (etype) {
  767.  
  768.   case ci_tint:
  769.       eptr->ci_uint = atoi (arg);
  770.       break;
  771.   case ci_tshort:
  772.       eptr->ci_ushort = atoi (arg);
  773.       break;
  774.   case ci_tlong:
  775.       eptr->ci_ulong = atol (arg);
  776.       break;
  777.   case ci_toct:
  778.       eptr->ci_uoct = atoo (arg);
  779.       break;
  780.   case ci_thex:
  781.       if (stlmatch(arg,"0x") || stlmatch(arg,"0X"))  arg += 2;
  782.       eptr->ci_uhex = atoh (arg);
  783.       break;
  784.   case ci_tdouble:
  785.       eptr->ci_udouble = atof (arg);
  786.       break;
  787.   case ci_tfloat:
  788.       eptr->ci_ufloat = atof (arg);
  789.       break;
  790.   case ci_tbool:
  791.       eptr->ci_ubool = (index("yYtT",*arg) != 0);
  792.       break;
  793.   case ci_tcint:
  794.       *(eptr->ci_ucint.ci_ival) =
  795.       intarg (&arg,0,eptr->ci_ucint.ci_imsg,eptr->ci_ucint.ci_imin,
  796.       eptr->ci_ucint.ci_imax,*(eptr->ci_ucint.ci_ival));
  797.       break;
  798.   case ci_tcshort:
  799.       *(eptr->ci_ucshort.ci_sval) =
  800.       shortarg (&arg,0,eptr->ci_ucshort.ci_smsg,eptr->ci_ucshort.ci_smin,
  801.       eptr->ci_ucshort.ci_smax,*(eptr->ci_ucshort.ci_sval));
  802.       break;
  803.   case ci_tclong:
  804.       *(eptr->ci_uclong.ci_lval) =
  805.       longarg (&arg,0,eptr->ci_uclong.ci_lmsg,eptr->ci_uclong.ci_lmin,
  806.       eptr->ci_uclong.ci_lmax,*(eptr->ci_uclong.ci_lval));
  807.       break;
  808.   case ci_tcoct:
  809.       *(eptr->ci_ucoct.ci_uval) =
  810.       octarg (&arg,0,eptr->ci_ucoct.ci_umsg,eptr->ci_ucoct.ci_umin,
  811.       eptr->ci_ucoct.ci_umax,*(eptr->ci_ucoct.ci_uval));
  812.       break;
  813.   case ci_tchex:
  814.       *(eptr->ci_uchex.ci_uval) =
  815.       hexarg (&arg,0,eptr->ci_uchex.ci_umsg,eptr->ci_uchex.ci_umin,
  816.       eptr->ci_uchex.ci_umax,*(eptr->ci_uchex.ci_uval));
  817.       break;
  818.   case ci_tcdouble:
  819.       *(eptr->ci_ucdouble.ci_dval) =
  820.       doublearg (&arg,0,eptr->ci_ucdouble.ci_dmsg,eptr->ci_ucdouble.ci_dmin,
  821.       eptr->ci_ucdouble.ci_dmax,*(eptr->ci_ucdouble.ci_dval));
  822.       break;
  823.   case ci_tcfloat:
  824.       *(eptr->ci_ucfloat.ci_fval) =
  825.       floatarg (&arg,0,eptr->ci_ucfloat.ci_fmsg,eptr->ci_ucfloat.ci_fmin,
  826.       eptr->ci_ucfloat.ci_fmax,*(eptr->ci_ucfloat.ci_fval));
  827.       break;
  828.   case ci_tcbool:
  829.       *(eptr->ci_ucbool.ci_bval) =
  830.       boolarg (&arg,0,eptr->ci_ucbool.ci_bmsg,*(eptr->ci_ucbool.ci_bval));
  831.       break;
  832.   case ci_tcchr:
  833.       *(eptr->ci_ucchr.ci_cval) =
  834.       chrarg (&arg,0,eptr->ci_ucchr.ci_cmsg,eptr->ci_ucchr.ci_cleg,
  835.       eptr->ci_ucchr.ci_cleg[*(eptr->ci_ucchr.ci_cval)]);
  836.       break;
  837.   case ci_tctab:
  838.       *(eptr->ci_ucstab.ci_tval) =
  839.       stabarg (&arg,0,eptr->ci_ucstab.ci_tmsg,eptr->ci_ucstab.ci_ttab,
  840.       eptr->ci_ucstab.ci_ttab[*(eptr->ci_ucstab.ci_tval)]);
  841.       break;
  842.   case ci_tcsearch:
  843.       *(eptr->ci_ucsearch.ci_tval) =
  844.       searcharg (&arg,0,eptr->ci_ucsearch.ci_tmsg,
  845.       eptr->ci_ucsearch.ci_ttab,
  846.       eptr->ci_ucsearch.ci_ttab[*(eptr->ci_ucsearch.ci_tval)]);
  847.       break;
  848.   default:;
  849.   }
  850. }
  851.