home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume26 / calc / part08 / input.c
Encoding:
C/C++ Source or Header  |  1992-05-09  |  17.3 KB  |  796 lines

  1. /*
  2.  * Copyright (c) 1992 David I. Bell
  3.  * Permission is granted to use, distribute, or modify this source,
  4.  * provided that this copyright notice remains intact.
  5.  *
  6.  * Nested input source file reader.
  7.  * For terminal input, this also provides a simple command stack.
  8.  */
  9.  
  10. #include <ctype.h>
  11. #include <pwd.h>
  12. #include "calc.h"
  13. #include "config.h"
  14.  
  15. #define MAXSAVE        255    /* number of saved terminal lines */
  16. #define DEFHIST        20    /* default history length display */
  17. #define TTYSIZE        100    /* reallocation size for terminal buffers */
  18. #define DEPTH        10    /* maximum depth of input */
  19. #define IS_READ        1    /* reading normally */
  20. #define IS_REREAD    2    /* reread current character */
  21. #define chartoint(ch)    ((ch) & 0xff)    /* make sure char is not negative */
  22.  
  23.  
  24. typedef struct {
  25.     short i_state;        /* state (read, reread) */
  26.     short i_char;        /* currently read char */
  27.     long i_line;        /* line number */
  28.     char *i_str;        /* current string for input (if not NULL) */
  29.     char *i_origstr;    /* original string so it can be freed */
  30.     char *i_ttystr;        /* current character of tty line (or NULL) */
  31.     FILE *i_fp;        /* current file for input (if not NULL) */
  32.     char *i_name;        /* file name if known */
  33. } INPUT;
  34.  
  35.  
  36. static int stacksize;        /* number of elements in command stack */
  37. static int stackindex;        /* current index into command stack */
  38. static int cmdsize;        /* current max size of terminal buffer */
  39. static int editsize;        /* current max size of edit buffer */
  40. static int linesize;        /* current max size of input line */
  41. static char *linebuf;        /* current input line buffer */
  42. static char *cmdbuf;        /* current command line buffer */
  43. static char *editbuf;        /* edit buffer */
  44. static char **cmdstack;        /* command stack */
  45. static char *prompt;        /* current prompt for terminal */
  46. static BOOL noprompt;        /* TRUE if should not print prompt */
  47.  
  48. static int depth;        /* current input depth */
  49. static INPUT *cip;        /* current input source */
  50. static INPUT inputs[DEPTH];    /* input sources */
  51.  
  52.  
  53. static char *findhistory(), *edithistory();
  54. static int openfile();
  55. static int ttychar();
  56.  
  57. extern struct passwd *getpwnam();
  58.  
  59.  
  60. /*
  61.  * Open an input file by possibly searching through a path list
  62.  * and also possibly applying the specified extension.  For example:
  63.  * opensearchfile("barf", ".:/tmp", ".c") searches in order for the
  64.  * files "./barf", "./barf.c", "/tmp/barf", and "/tmp/barf.c".
  65.  *
  66.  * Returns -1 if all specified files cannot be opened.
  67.  */
  68. opensearchfile(name, pathlist, extension)
  69.     char *name;        /* file name to be read */
  70.     char *pathlist;        /* list of colon separated paths (or NULL) */
  71.     char *extension;    /* extra extension to try (or NULL) */
  72. {
  73.     int i;
  74.     char *cp;
  75.     char path[PATHSIZE+1];    /* name being searched for */
  76.  
  77.     /*
  78.      * Don't try the extension if the filename already contains it.
  79.      */
  80.     if (extension) {
  81.         i = strlen(name) - strlen(extension);
  82.         if ((i >= 0) && (strcmp(&name[i], extension) == 0))
  83.             extension = NULL;
  84.     }
  85.     /*
  86.      * If the name is absolute, or if there is no path list, then
  87.      * make one which just searches for the name straight.  Then
  88.      * search through the path list for the file, without and with
  89.      * the specified extension.
  90.      */
  91.     if (name[0] == PATHCHAR || 
  92.         name[0] == HOMECHAR || 
  93.         (name[0] == DOTCHAR && name[1] == PATHCHAR) || 
  94.         pathlist == NULL) {
  95.         pathlist = "";
  96.     }
  97.     pathlist--;
  98.     do {
  99.         pathlist++;
  100.         cp = path;
  101.         while (*pathlist && (*pathlist != LISTCHAR))
  102.             *cp++ = *pathlist++;
  103.         if (cp != path)
  104.             *cp++ = PATHCHAR;
  105.         strcpy(cp, name);
  106.         i = openfile(path);
  107.         if ((i < 0) && extension) {
  108.             strcat(path, extension);
  109.             i = openfile(path);
  110.         }
  111.     } while ((i < 0) && *pathlist);
  112.     return i;
  113. }
  114.  
  115.  
  116. /*
  117.  * Given a filename with a leading ~, expand it into a home directory for 
  118.  * that user.  This function will malloc the space for the expanded path.
  119.  *
  120.  * If the path is just ~, or begins with ~/, expand it to the home
  121.  * directory of the current user.  If the environment variable $HOME
  122.  * is known, it will be used, otherwise the password file will be
  123.  * consulted.
  124.  *
  125.  * If the path is just ~username, or ~username/, expand it to the home
  126.  * directory of that user by looking it up in the password file.
  127.  *
  128.  * If the password file must be consulted and the username is not found
  129.  * a NULL pointer is returned.
  130.  */
  131. static char *
  132. homeexpand(name)
  133.     char *name;        /* a filename with a leading ~ */
  134. {
  135.     struct passwd *ent;    /* password entry */
  136.     char *home2;        /* fullpath of the home directory */
  137.     char *fullpath;        /* the malloced expanded path */
  138.     char *after;        /* after the ~user or ~ */
  139.     char username[PATHSIZE+1];    /* extratced username */
  140.  
  141.     /* firewall */
  142.     if (name[0] != HOMECHAR)
  143.         return NULL;
  144.  
  145.     /*
  146.      * obtain the home directory component
  147.      */
  148.     switch (name[1]) {
  149.     case PATHCHAR:        /* ~/... */
  150.     case '\0':        /* ~ */
  151.         home2 = home;
  152.         after = name+1;
  153.         break;
  154.     default:        /* ~username or ~username/... */
  155.  
  156.         /* extract the username after the ~ */
  157.         after = (char *)strchr(name+2, PATHCHAR);
  158.         if (after == NULL) {
  159.             /* path is just ~username */
  160.             ent = getpwnam(name+1);
  161.             if (ent == NULL) {
  162.                 /* unknown user */
  163.                 return NULL;
  164.             }
  165.             /* just malloc the home directory and return it */
  166.             fullpath = (char *)malloc(strlen(ent->pw_dir)+1);
  167.             strcpy(fullpath, ent->pw_dir);
  168.             return fullpath;
  169.         }
  170.         if (after-name > PATHSIZE+1) {
  171.             /* username is too big */
  172.             return NULL;
  173.         }
  174.         strncpy(username, name+1, after-name-1);
  175.         username[after-name-1] = '\0';
  176.  
  177.         /* get that user's home directory */
  178.         ent = getpwnam(username);
  179.         if (ent == NULL) {
  180.             /* unknown user */
  181.             return NULL;
  182.         }
  183.         home2 = ent->pw_dir;
  184.         break;
  185.     }
  186.  
  187.     /*
  188.      * build the fullpath given the home directory
  189.      */
  190.     fullpath = (char *)malloc(strlen(home2)+strlen(after)+1);
  191.     sprintf(fullpath, "%s%s", home2, after);
  192.     return fullpath;
  193. }
  194.  
  195.  
  196. /*
  197.  * f_open - ~-expand a filename and fopen() it
  198.  */
  199. FILE *
  200. f_open(name, mode)
  201.     char *name;        /* the filename to open */
  202.     char *mode;        /* the fopen mode to use */
  203. {
  204.     FILE *fp;        /* open file descriptor */
  205.     char *fullname;        /* file name with HOMECHAR expansion */
  206.  
  207.     /*
  208.      * expand ~ if needed
  209.      */
  210.     if (name[0] == HOMECHAR) {
  211.         fullname = homeexpand(name);
  212.         if (fullname == NULL)
  213.             return NULL;
  214.         fp = fopen(fullname, mode);
  215.         free(fullname);
  216.     } else {
  217.         fp = fopen(name, mode);
  218.     }
  219.     return fp;
  220. }
  221.  
  222.  
  223. /*
  224.  * Setup for reading from a input file.
  225.  * Returns -1 if file could not be opened.
  226.  */
  227. static
  228. openfile(name)
  229.     char *name;        /* file name to be read */
  230. {
  231.     FILE *fp;        /* open file descriptor */
  232.  
  233.     if (depth >= DEPTH)
  234.          return -1;
  235.     fp = f_open(name, "r");
  236.     if (fp == NULL)
  237.          return -1;
  238.     cip++;
  239.     cip->i_state = IS_READ;
  240.     cip->i_char = '\0';
  241.     cip->i_str = NULL;
  242.     cip->i_origstr = NULL;
  243.     cip->i_ttystr = NULL;
  244.     cip->i_fp = fp;
  245.     cip->i_line = 1;
  246.     cip->i_name = (char *)malloc(strlen(name) + 1);
  247.     strcpy(cip->i_name, name);
  248.     depth++;
  249.     return 0;
  250. }
  251.  
  252.  
  253. /*
  254.  * Open a string for scanning. String is ended by a null character.
  255.  * String is copied into local memory so it can be trashed afterwards.
  256.  * Returns -1 if cannot open string.
  257.  */
  258. openstring(str)
  259.     char *str;        /* string to be opened */
  260. {
  261.     char *cp;        /* copied string */
  262.  
  263.     if ((depth >= DEPTH) || (str == NULL))
  264.          return -1;
  265.     cp = (char *)malloc(strlen(str) + 1);
  266.     if (cp == NULL)
  267.          return -1;
  268.     strcpy(cp, str);
  269.     cip++;
  270.     cip->i_state = IS_READ;
  271.     cip->i_char = '\0';
  272.     cip->i_str = cp;
  273.     cip->i_origstr = cp;
  274.     cip->i_fp = NULL;
  275.     cip->i_name = NULL;
  276.     cip->i_ttystr = NULL;
  277.     cip->i_line = 1;
  278.     depth++;
  279.     return 0;
  280. }
  281.  
  282.  
  283. /*
  284.  * Set to read input from the terminal.
  285.  * Returns -1 if there is no more depth for input.
  286.  */
  287. openterminal()
  288. {
  289.     if (depth >= DEPTH)
  290.          return -1;
  291.     if (cmdsize == 0) {
  292.         cmdbuf = (char *)malloc(TTYSIZE + 1);
  293.         if (cmdbuf == NULL)
  294.             return -1;
  295.         cmdsize = TTYSIZE;
  296.     }
  297.     if (editsize == 0) {
  298.         editbuf = (char *)malloc(TTYSIZE + 1);
  299.         if (editbuf == NULL)
  300.             return -1;
  301.         editsize = TTYSIZE;
  302.     }
  303.     if (stacksize == 0) {
  304.         cmdstack = (char **) malloc(MAXSAVE * sizeof(char *));
  305.         if (cmdstack == NULL)
  306.             return -1;
  307.         stacksize = MAXSAVE;
  308.         for (stackindex = 0; stackindex < MAXSAVE; stackindex++)
  309.             cmdstack[stackindex] = NULL;
  310.         stackindex = 0;
  311.     }
  312.     cip++;
  313.     cip->i_state = IS_READ;
  314.     cip->i_char = '\0';
  315.     cip->i_str = NULL;
  316.     cip->i_origstr = NULL;
  317.     cip->i_ttystr = NULL;
  318.     cip->i_fp = NULL;
  319.     cip->i_name = NULL;
  320.     cip->i_line = 1;
  321.     depth++;
  322.     return 0;
  323. }
  324.  
  325.  
  326. /*
  327.  * Close the current input source.
  328.  */
  329. static void
  330. closeinput()
  331. {
  332.     if (depth <= 0)
  333.         return;
  334.     if (cip->i_origstr)
  335.         free(cip->i_origstr);
  336.     if (cip->i_fp)
  337.         fclose(cip->i_fp);
  338.     if (cip->i_name)
  339.         free(cip->i_name);
  340.     cip--;
  341.     depth--;
  342. }
  343.  
  344.  
  345. /*
  346.  * Reset the input sources back to the initial state.
  347.  */
  348. void
  349. resetinput()
  350. {
  351.     while (depth > 0)
  352.         closeinput();
  353.     cip = inputs;
  354.     noprompt = FALSE;
  355. }
  356.  
  357.  
  358. /*
  359.  * Set the prompt for terminal input.
  360.  */
  361. void
  362. setprompt(str)
  363.     char *str;
  364. {
  365.     prompt = str;
  366.     noprompt = FALSE;
  367. }
  368.  
  369.  
  370. /*
  371.  * Read the next character from the current input source.
  372.  * End of file returns newline character and closes current input source,
  373.  * except for the last input source, which returns EOF.
  374.  */
  375. int
  376. nextchar()
  377. {
  378.     int ch;            /* current input character */
  379.  
  380.     if (depth == 0)        /* input finished */
  381.          return EOF;
  382.     if (cip->i_state == IS_REREAD) {    /* rereading current char */
  383.          ch = cip->i_char;
  384.          cip->i_state = IS_READ;
  385.          if (ch == '\n')
  386.             cip->i_line++;
  387.          return ch;
  388.     }
  389.     if (cip->i_str) {        /* from string */
  390.         ch = chartoint(*cip->i_str++);
  391.         if (ch == '\0')
  392.             ch = EOF;
  393.     } else if (cip->i_fp) {        /* from file */
  394.         ch = fgetc(cip->i_fp);
  395.     } else {            /* from terminal */
  396.         ch = ttychar();
  397.     }
  398.     if (ch == EOF) {        /* fix up end of file */
  399.         closeinput();
  400.         ch = '\n';
  401.         if (depth <= 0)
  402.             ch = EOF;
  403.     }
  404.     if (depth > 0)
  405.         cip->i_char = (char)ch;    /* save for rereads */
  406.     if (ch == '\n')
  407.         cip->i_line++;
  408.     return ch;
  409. }
  410.  
  411.  
  412. /*
  413.  * Read in the next line of input from the current input source.
  414.  * The line is terminated with a null character, and does not contain
  415.  * the final newline character.  The returned string is only valid
  416.  * until the next such call, and so must be copied if necessary.
  417.  * Returns NULL on end of file.
  418.  */
  419. char *
  420. nextline()
  421. {
  422.     char *cp;
  423.     int ch;
  424.     int len;
  425.  
  426.     cp = linebuf;
  427.     if (linesize == 0) {
  428.         cp = (char *)malloc(TTYSIZE + 1);
  429.         if (cp == NULL)
  430.             error("Cannot allocate line buffer");
  431.         linebuf = cp;
  432.         linesize = TTYSIZE;
  433.     }
  434.     len = 0;
  435.     for (;;) {
  436.         noprompt = TRUE;
  437.         ch = nextchar();
  438.         noprompt = FALSE;
  439.         if (ch == EOF)
  440.             return NULL;
  441.         if (ch == '\0')
  442.             continue;
  443.         if (ch == '\n')
  444.             break;
  445.         if (len >= linesize) {
  446.             cp = (char *)realloc(cp, linesize + TTYSIZE + 1);
  447.             if (cp == NULL)
  448.                 error("Cannot realloc line buffer");
  449.             linebuf = cp;
  450.             linesize += TTYSIZE;
  451.         }
  452.         cp[len++] = (char)ch;
  453.     }
  454.     cp[len] = '\0';
  455.     return linebuf;
  456. }
  457.  
  458.  
  459. /*
  460.  * Read the next character from the terminal.
  461.  * This works by reading in a complete line from the terminal at once,
  462.  * and then returns the characters one by one as required.  If the line
  463.  * begins with the special command stack history character, then it is
  464.  * replaced by some previous command line.  The saved line is then put on
  465.  * the command stack for future reference.
  466.  */
  467. static int
  468. ttychar()
  469. {
  470.     int ch;            /* current char */
  471.     int len;        /* length of current command */
  472.     char *newbuf;        /* new buffer */
  473.  
  474.     /*
  475.      * If we have more to read from the saved command line, then do that.
  476.      * When we see a newline character, then clear the pointer so we will
  477.      * read a new line on the next call.
  478.      */
  479.     if (cip->i_ttystr) {
  480.         ch = chartoint(*cip->i_ttystr++);
  481.         if (ch == '\n')
  482.             cip->i_ttystr = NULL;
  483.         return ch;
  484.     }
  485.     /*
  486.      * We need another complete line.  Print the prompt string, then read
  487.      * in a new command line, expanding the command buffer as necessary.
  488.      */
  489.     if (!noprompt) {
  490.         printf("%02d%s", stackindex + 1, prompt);
  491.         fflush(stdout);
  492.     }
  493.     abortlevel = 0;
  494.     len = 0;
  495.     do {
  496.         if (len >= cmdsize) {
  497.             newbuf = (char *)realloc(cmdbuf, cmdsize + TTYSIZE + 1);
  498.             if (newbuf == NULL) {
  499.                 perror("Cannot reallocate terminal buffer");
  500.                 return EOF;
  501.             }
  502.             cmdbuf = newbuf;
  503.             cmdsize += TTYSIZE;
  504.         }
  505.         inputwait = TRUE;
  506.         ch = getchar();
  507.         inputwait = FALSE;
  508.         if (ch == EOF)
  509.             return EOF;
  510.         ch = chartoint(ch);
  511.         if (ch)
  512.             cmdbuf[len++] = (char)ch;
  513.     } while (ch != '\n');
  514.     cmdbuf[len] = '\0';
  515.     /*
  516.      * If the line was blank, then just return the line feed and do not
  517.      * put the line on the command stack.
  518.      */
  519.     if (len == 1)
  520.         return '\n';
  521.     /*
  522.      * Handle shell escape if present
  523.      */
  524.     if (cmdbuf[0] == '!') {        /* do a shell command */
  525.         char *cmd;
  526.  
  527.         cmd = cmdbuf + 1;
  528.         if (*cmd == '\0' || *cmd == '\n')
  529.             cmd = shell;
  530.         system(cmd);
  531.         return '\n';
  532.     /*
  533.      * Handle history command if present.
  534.      */
  535.     } else if (cmdbuf[0] == '`') {
  536.         cmdbuf[len-1] = '\0';
  537.         newbuf = findhistory(cmdbuf + 1);
  538.         if (newbuf == NULL)
  539.             return '\n';
  540.         strcpy(cmdbuf, newbuf);
  541.     }
  542.     /*
  543.      * Save the line in the command stack.
  544.      */
  545.     newbuf = (char *)malloc(strlen(cmdbuf) + 1);
  546.     if (newbuf == NULL) {
  547.         perror("Cannot save history line");
  548.         return EOF;
  549.     }
  550.     strcpy(newbuf, cmdbuf);
  551.     if (cmdstack[stackindex])
  552.         free(cmdstack[stackindex]);
  553.     cmdstack[stackindex] = newbuf;
  554.     stackindex = (stackindex + 1) % MAXSAVE;
  555.     /*
  556.      * Return the first character of the line, and set up to
  557.      * return the rest of it with later calls.
  558.      */
  559.     cip->i_ttystr = cmdbuf + 1;
  560.     return chartoint(cmdbuf[0]);
  561. }
  562.  
  563.  
  564. /*
  565.  * Parse a history command line, and return the selected command.
  566.  * NULL is returned if the history command is invalid. Legal formats:
  567.  *    ``    The previous command.
  568.  *    `n    Command number n.
  569.  *    `-n    The nth command back.
  570.  *    `h n    List last n history elements.
  571.  *    `e n    Edit command n (last if not given).
  572.  */
  573. static char *
  574. findhistory(cmd)
  575.     char *cmd;        /* history command */
  576. {
  577.     int num;        /* command number */
  578.     int action;        /* action character */
  579.     int back;        /* how much to search backwards */
  580.     char *str;        /* returned string */
  581.  
  582.     num = 0;
  583.     if ((*cmd == '`') && (cmd[1] == '\0')) {
  584.         num = stackindex - 1;
  585.         if (num < 0)
  586.             num += MAXSAVE;
  587.         str = cmdstack[num];
  588.         if (str == NULL)
  589.             fprintf(stderr, "No previous command\n");
  590.         return str;
  591.     }
  592.     action = '\0';
  593.     if (isascii(*cmd) && islower(*cmd))
  594.         action = *cmd++;
  595.     else if (isascii(*cmd) && isupper(*cmd))
  596.         action = tolower(*cmd++);
  597.     while (isascii(*cmd) && isspace(*cmd))
  598.         cmd++;
  599.     back = FALSE;
  600.     if (*cmd == '-') {
  601.         back = TRUE;
  602.         cmd++;
  603.     }
  604.     num = 0;
  605.     while ((*cmd >= '0') && (*cmd <= '9'))
  606.         num = num * 10 + (*cmd++ - '0');
  607.     if (*cmd != '\0' && *cmd != '\n') {
  608.         fprintf(stderr, "Invalid history command format\n");
  609.         return NULL;
  610.     }
  611.     if ((num == 0) && (action == 'h'))
  612.         num = DEFHIST;
  613.     if ((num == 0) && (action == 'e'))
  614.         num = stackindex;
  615.     if ((num <= 0) || (num > MAXSAVE)) {
  616.         fprintf(stderr, "Invalid history command number\n");
  617.         return NULL;
  618.     }
  619.     if (back)
  620.         num = stackindex - num;
  621.     else
  622.         num--;
  623.     if (num < 0)
  624.         num += MAXSAVE;
  625.     switch (action) {
  626.         case '\0':
  627.             str = cmdstack[num];
  628.             if (str == NULL)
  629.                 fprintf(stderr, "History stack element %d is undefined\n", num + 1);
  630.             return str;
  631.  
  632.         case 'e':
  633.             return edithistory(cmdstack[num]);
  634.  
  635.         case 'h':
  636.             num++;
  637.             back = stackindex - num;
  638.             if (back < 0)
  639.                 back += MAXSAVE;
  640.             printf("\n");
  641.             while (num-- > 0) {
  642.                 if (cmdstack[back])
  643.                 printf("%02d: %s", back + 1, cmdstack[back]);
  644.                 back = (back + 1) % MAXSAVE;
  645.             }
  646.             printf("\n");
  647.             return NULL;
  648.  
  649.         default:
  650.             fprintf(stderr, "Invalid history action character");
  651.             return NULL;
  652.     }
  653. }
  654.  
  655.  
  656. /*
  657.  * Edit the specified command string and return the new version of it.
  658.  * The string is safe to reference until the next call to this routine.
  659.  * Returns NULL if the user gives the command to abort the edit.
  660.  */
  661. /*ARGSUSED*/
  662. static char *
  663. edithistory(str)
  664.     char *str;        /* original string */
  665. {
  666. #if 0
  667.     char *tmp;        /* temporary string */
  668.     int len;        /* current length of string */
  669.     int cmd;        /* edit command */
  670. #endif
  671.  
  672.     printf("Editing not implemented\n");
  673.     return NULL;
  674. #if 0
  675.     len = strlen(str);
  676.     if (len >= editsize) {
  677.         tmp = realloc(editbuf, len + TTYSIZE + 1);
  678.         if (tmp == NULL) {
  679.             perror("Cannot grow edit line");
  680.             return NULL;
  681.         }
  682.         free(editbuf);
  683.         editbuf = tmp;
  684.         editsize = len + TTYSIZE;
  685.     }
  686.     strcpy(editbuf, str);
  687.     for (;;) {
  688.         printf(" %s*", editbuf);
  689.         fflush(stdout);
  690.         cmd = getchar();
  691.         switch (cmd) {
  692.             case EOF:
  693.                 return NULL;
  694.             case '\n':
  695.                 return editbuf;
  696.             default:
  697.                 while (getchar() != '\n') ;
  698.                 printf("Bad edit command\n");
  699.         }
  700.     }
  701. #endif
  702. }
  703.  
  704.  
  705. /*
  706.  * Return whether or not the input source is the terminal.
  707.  */
  708. BOOL
  709. inputisterminal()
  710. {
  711.     return ((depth <= 0) || ((cip->i_str == NULL) && (cip->i_fp == NULL)));
  712. }
  713.  
  714.  
  715. /*
  716.  * Return the name of the current input file.
  717.  * Returns NULL for terminal or strings.
  718.  */
  719. char *
  720. inputname()
  721. {
  722.     if (depth <= 0)
  723.         return NULL;
  724.     return cip->i_name;
  725. }
  726.  
  727.  
  728. /*
  729.  * Return the current line number.
  730.  */
  731. long
  732. linenumber()
  733. {
  734.     if (depth > 0)
  735.         return cip->i_line;
  736.     return 1;
  737. }
  738.  
  739.  
  740. /*
  741.  * Restore the next character to be read again on the next nextchar call.
  742.  */
  743. void
  744. reread()
  745. {
  746.     if ((depth <= 0) || (cip->i_state == IS_REREAD))
  747.         return;
  748.     cip->i_state = IS_REREAD;
  749.     if (cip->i_char == '\n')
  750.         cip->i_line--;
  751. }
  752.  
  753.  
  754. /*
  755.  * Process all startup files found in the $CALCRC path.
  756.  */
  757. void
  758. runrcfiles()
  759. {
  760.     char path[PATHSIZE+1];    /* name being searched for */
  761.     char *cp;
  762.     char *newcp;
  763.     char *p;
  764.     int i;
  765.  
  766.     /* execute each file in the list */
  767.     for (cp=calcrc, newcp=(char *)strchr(calcrc, LISTCHAR);
  768.          cp != NULL && *cp;
  769.          cp = newcp, 
  770.          newcp=(newcp) ? (char *)strchr(newcp+1, LISTCHAR) : NULL) {
  771.  
  772.         /* load file name into the path */
  773.         if (newcp == NULL) {
  774.             strcpy(path, cp);
  775.         } else {
  776.             strncpy(path, cp, newcp-cp);
  777.             path[newcp-cp] = '\0';
  778.         }
  779.  
  780.         /* find the start of the path */
  781.         p = (path[0] == ':') ? path+1 : path;
  782.         if (p[0] == '\0') {
  783.             continue;
  784.         }
  785.  
  786.         /* process the current file in the list */
  787.         i = openfile(p);
  788.         if (i < 0)
  789.             continue;
  790.         getcommands();
  791.     }
  792. }
  793.  
  794.  
  795. /* END CODE */
  796.