home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / swtools / mipsABI / examples / sup / ci.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  24.7 KB  |  848 lines

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