home *** CD-ROM | disk | FTP | other *** search
/ Shareware Supreme Volume 6 #1 / swsii.zip / swsii / 099 / SH164AS.ZIP / SHELL / SH5.C < prev    next >
C/C++ Source or Header  |  1992-02-28  |  18KB  |  973 lines

  1. /* MS-DOS SHELL - Main I/O Functions
  2.  *
  3.  * MS-DOS SHELL - Copyright (c) 1990 Data Logic Limited and Charles Forsyth
  4.  *
  5.  * This code is based on (in part) the shell program written by Charles
  6.  * Forsyth and is subject to the following copyright restrictions:
  7.  *
  8.  * 1.  Redistribution and use in source and binary forms are permitted
  9.  *     provided that the above copyright notice is duplicated in the
  10.  *     source form and the copyright notice in file sh6.c is displayed
  11.  *     on entry to the program.
  12.  *
  13.  * 2.  The sources (or parts thereof) or objects generated from the sources
  14.  *     (or parts of sources) cannot be sold under any circumstances.
  15.  *
  16.  *    $Header: C:/SRC/SHELL/RCS/sh5.c 1.10 90/08/14 23:30:47 Ian_Stewartson Exp $
  17.  *
  18.  *    $Log:    sh5.c $
  19.  * Revision 1.10  90/08/14  23:30:47  Ian_Stewartson
  20.  * Changes to env structure.
  21.  * 
  22.  * Revision 1.9  90/05/11  18:45:40  MS_user
  23.  * Fix problem when at end of buffer on re-load from file
  24.  * 
  25.  * Revision 1.8  90/04/25  10:58:41  MS_user
  26.  * Fix re-reading re-assigned buffers correctly.
  27.  * 
  28.  * Revision 1.7  90/04/25  09:20:08  MS_user
  29.  * Fix lseek problem and TAG problem on here documents
  30.  * 
  31.  * Revision 1.6  90/04/09  17:04:50  MS_user
  32.  * g_tempname must check for slash or backslash
  33.  * 
  34.  * Revision 1.5  90/03/21  14:03:47  MS_user
  35.  * Add new gravechar procedure for handling here documents
  36.  * 
  37.  * Revision 1.4  90/03/14  19:31:28  MS_user
  38.  * Add buffered output for here document processing.
  39.  * Fix here document processing so it works correctly.
  40.  * Add missing IOTHERE (<<-) processing for here documents.
  41.  * 
  42.  * Revision 1.3  90/03/06  16:49:58  MS_user
  43.  * Add disable history option
  44.  * 
  45.  * Revision 1.2  90/03/05  13:51:45  MS_user
  46.  * Add functionality to readc to support dot command via run function
  47.  * Add $HOME as a temporary file directory
  48.  * 
  49.  * Revision 1.1  90/01/25  13:41:50  MS_user
  50.  * Initial revision
  51.  * 
  52.  */
  53.  
  54. #include <sys/types.h>
  55. #include <stdio.h>
  56. #include <signal.h>
  57. #include <errno.h>
  58. #include <setjmp.h>
  59. #include <stdlib.h>
  60. #include <string.h>
  61. #include <fcntl.h>
  62. #include <io.h>
  63. #include <limits.h>
  64. #include <dirent.h>
  65. #include <unistd.h>
  66. #include "sh.h"
  67.  
  68. /*
  69.  * shell IO
  70.  */
  71.  
  72. static IO_Buf        sharedbuf = {AFID_NOBUF};
  73. static IO_Buf        mainbuf = {AFID_NOBUF};
  74. static unsigned int    bufid = AFID_ID;    /* buffer id counter */
  75.                     /* list of hear docs while parsing */
  76. static Here_D    *inhere = (Here_D *)NULL;
  77.                     /* list of active here documents */
  78. static Here_D    *acthere = (Here_D *)NULL;
  79.  
  80. static int    dol1_char (IO_State *);
  81. static void    readhere (char **, char *, int, int);
  82. static int    herechar (IO_State *);
  83.  
  84. int        Getc (ec)
  85. register int    ec;
  86. {
  87.     register int    c;
  88.  
  89.     if (e.linep > e.eline)
  90.     {
  91.     while (((c = readc ()) != NL) && c)
  92.         ;
  93.  
  94.     print_error ("sh: input line too long\n");
  95.     gflg++;
  96.     return c;
  97.     }
  98.  
  99.     c = readc();
  100.     if ((ec != '\'') && (ec != '`') && (e.iop->task != XGRAVE))
  101.     {
  102.     if (c == '\\')
  103.     {
  104.         if (((c = readc ()) == NL) && (ec != '\"'))
  105.         return Getc (ec);
  106.  
  107.         c |= QUOTE;
  108.     }
  109.     }
  110.  
  111.     return c;
  112. }
  113.  
  114. void    unget (c)
  115. int    c;
  116. {
  117.     if (e.iop >= e.iobase)
  118.     e.iop->peekc = c;
  119. }
  120.  
  121. int    eofc ()
  122. {
  123.     return (e.iop < e.iobase) || ((e.iop->peekc == 0) && (e.iop->prev == 0));
  124. }
  125.  
  126. /* Read the next character */
  127.  
  128. int    readc ()
  129. {
  130.     register int    c;
  131.     char        s_dflag = e.iop->dflag;
  132.  
  133. /* The dflag is transfered from the higher level to the lower level at end
  134.  * of input at the higher level.  This is part of the implementation of
  135.  * $* and $@ processing.
  136.  */
  137.  
  138.     for (; e.iop >= e.iobase; e.iop--)
  139.     {
  140.  
  141. /* Set up the current dflag */
  142.  
  143.     e.iop->dflag = s_dflag;
  144.  
  145. /* If there is an unget character, use it */
  146.  
  147.     if ((c = e.iop->peekc) != '\0')
  148.     {
  149.         e.iop->peekc = 0;
  150.         return c;
  151.     }
  152.  
  153. /* Some special processing for multi-line commands */
  154.  
  155.     else
  156.     {
  157.         if (e.iop->prev != 0)
  158.         {
  159.  
  160. /* Get the next character from the IO function */
  161.  
  162.         if ((c = (*e.iop->iofn)(e.iop)) != '\0')
  163.         {
  164.  
  165. /* End of current level, but continue at this level as another read
  166.  * function has been put on the stack
  167.  */
  168.  
  169.             if (c == -1)
  170.             {
  171.             e.iop++;
  172.             continue;
  173.             }
  174.  
  175. /* If we are at the bottom - echo the character */
  176.  
  177.             if ((e.iop == iostack) && (FL_TEST ('v')))
  178.             S_putc ((char)c);
  179.  
  180. /* Return the current character */
  181.  
  182.             return (e.iop->prev = (char)c);
  183.         }
  184.  
  185.         else if (e.iop->task == XIO && e.iop->prev != NL)
  186.         {
  187.             e.iop->prev = 0;
  188.  
  189.             if ((e.iop == iostack) && (FL_TEST ('v')))
  190.             S_putc (NL);
  191.  
  192.             return NL;
  193.         }
  194.  
  195.         else
  196.             s_dflag = e.iop->dflag;
  197.         }
  198.  
  199.         if (e.iop->task == XIO)
  200.         {
  201.         if (multiline)
  202.             return e.iop->prev = 0;
  203.  
  204.         if (talking && (e.iop == iostack + 1) && !e.eof_p)
  205.             put_prompt (ps1->value);
  206.         }
  207.     }
  208.     }
  209.  
  210. /* End of file detected.  If more data on stack and the special EOF
  211.  * processing is not enabled - return 0
  212.  */
  213.  
  214.     if ((e.iop >= iostack) && !e.eof_p)
  215.     return 0;
  216.  
  217.     leave();
  218.     /* NOTREACHED */
  219. }
  220.  
  221. /* Add an Input channel to the input stack */
  222.  
  223. void        pushio (argp, fn)
  224. IO_Args        *argp;
  225. int        (*fn)(IO_State *);
  226. {
  227.     if (++e.iop >= &iostack[NPUSH])
  228.     {
  229.     e.iop--;
  230.     print_error ("sh: Shell input nested too deeply\n");
  231.     gflg++;
  232.     return;
  233.     }
  234.  
  235.     e.iop->iofn = fn;
  236.  
  237.     if (argp->afid != AFID_NOBUF)
  238.     e.iop->argp = argp;
  239.  
  240.     else
  241.     {
  242.     e.iop->argp  = ioargstack + (e.iop - iostack);
  243.     *e.iop->argp = *argp;
  244.     e.iop->argp->afbuf = e.iop == &iostack[0] ? &mainbuf : &sharedbuf;
  245.  
  246.     if ((isatty (e.iop->argp->afile) == 0) &&
  247.         ((e.iop == &iostack[0]) ||
  248.          (lseek (e.iop->argp->afile, 0L, SEEK_CUR) != -1L)))
  249.     {
  250.         if (++bufid == AFID_NOBUF)
  251.         bufid = AFID_ID;
  252.  
  253.         e.iop->argp->afid  = bufid;
  254.     }
  255.     }
  256.  
  257.     e.iop->prev  = ~NL;
  258.     e.iop->peekc = 0;
  259.     e.iop->xchar = 0;
  260.     e.iop->nlcount = 0;
  261.  
  262.     if ((fn == filechar) || (fn == linechar))
  263.     e.iop->task = XIO;
  264.  
  265.     else if ((fn == gravechar) || (fn == qgravechar) || (fn == sgravechar))
  266.     e.iop->task = XGRAVE;
  267.  
  268.     else
  269.     e.iop->task = XOTHER;
  270. }
  271.  
  272. /*
  273.  * Input generating functions
  274.  */
  275.  
  276. /*
  277.  * Produce the characters of a string, then a newline, then EOF.
  278.  */
  279. int            nlchar (iop)
  280. register IO_State    *iop;
  281. {
  282.     register int    c;
  283.  
  284.     if (iop->argp->aword == (char *)NULL)
  285.     return 0;
  286.  
  287.     if ((c = *iop->argp->aword++) == 0)
  288.     {
  289.     iop->argp->aword = (char *)NULL;
  290.     return NL;
  291.     }
  292.  
  293.     return c;
  294. }
  295.  
  296. /*
  297.  * Given a list of words, produce the characters
  298.  * in them, with a space after each word.
  299.  */
  300.  
  301. int            wdchar (iop)
  302. register IO_State    *iop;
  303. {
  304.     register char    c;
  305.     register char    **wl;
  306.  
  307.     if ((wl = iop->argp->awordlist) == (char **)NULL)
  308.     return 0;
  309.  
  310.     if (*wl != (char *)NULL)
  311.     {
  312.     if ((c = *(*wl)++) != 0)
  313.         return (c & 0177);
  314.  
  315.     iop->argp->awordlist++;
  316.     return SP;
  317.     }
  318.  
  319.     iop->argp->awordlist = (char **)NULL;
  320.     return NL;
  321. }
  322.  
  323. /*
  324.  * Return the characters of a list of words, producing a space between them.
  325.  */
  326.  
  327. int            dol_char (iop)
  328. IO_State        *iop;
  329. {
  330.     register char    *wp;
  331.     char        cflag;
  332.  
  333.     if ((wp = *(iop->argp->awordlist)++) != (char *)NULL)
  334.     {
  335.     if (*iop->argp->awordlist == (char *)NULL)
  336.         iop->dflag |= DSA_END;
  337.  
  338.     cflag = iop->dflag;
  339.     PUSHIO (aword, wp, dol1_char);
  340.     e.iop->dflag = cflag;
  341.     return -1;
  342.     }
  343.  
  344.     return 0;
  345. }
  346.  
  347. /* Return next character from the word with a space at the end */
  348.  
  349. static int        dol1_char (iop)
  350. IO_State        *iop;
  351. {
  352.     register int c;
  353.  
  354.     if ((iop->dflag & DSA_MODE) == DSA_AMP)
  355.     {
  356.     if (!(iop->dflag & DSA_START))
  357.         iop->dflag |= DSA_START;
  358.  
  359. /* Has the previous word ended */
  360.  
  361.     else if (iop->dflag & DSA_START1)
  362.     {
  363.         iop->dflag &= ~DSA_START1;
  364.         return '"';
  365.     }
  366.     }
  367.  
  368.     if (iop->argp->aword == (char *)NULL)
  369.     return 0;
  370.  
  371.     if ((c = *iop->argp->aword) == '\0')
  372.     {
  373.     if ((iop->dflag & DSA_MODE) != DSA_AMP)
  374.     {
  375.         iop->argp->aword = (char *)NULL;
  376.         return (iop->dflag & DSA_END) ? 0 : SP;
  377.     }
  378.  
  379.     if (!(iop->dflag & DSA_END1))
  380.     {
  381.         iop->dflag |= DSA_END1;
  382.         return '"';
  383.     }
  384.  
  385.     iop->argp->aword = (char *)NULL;
  386.     iop->dflag &= ~DSA_END1;
  387.     iop->dflag |= DSA_START1;
  388.     return (iop->dflag & DSA_END) ? 0 : SP;
  389.     }
  390.  
  391.     iop->argp->aword++;
  392.     if ((iop->dflag != DSA_NULL) && any ((char)c, ifs->value))
  393.     c |= QUOTE;
  394.  
  395.     return c;
  396. }
  397.  
  398. /*
  399.  * Produce the characters from a single word (string).
  400.  */
  401.  
  402. int        strchar (iop)
  403. IO_State    *iop;
  404. {
  405.     register int    c;
  406.  
  407.     return ((iop->argp->aword == (char *)NULL) ||
  408.         ((c = *(iop->argp->aword++)) == 0)) ? 0 : c;
  409. }
  410.  
  411. /*
  412.  * Produce quoted characters from a single word (string).
  413.  */
  414.  
  415. int        qstrchar (iop)
  416. IO_State    *iop;
  417. {
  418.     register int    c;
  419.  
  420.     return ((iop->argp->aword == (char *)NULL) ||
  421.         ((c = *(iop->argp->aword++)) == 0)) ? 0 : (c | QUOTE);
  422. }
  423.  
  424. /*
  425.  * Return the characters from a file.
  426.  */
  427.  
  428. int        filechar (iop)
  429. IO_State    *iop;
  430. {
  431.     register IO_Args    *ap = iop->argp;
  432.     register int    i;
  433.     char        c;
  434.     IO_Buf        *bp = ap->afbuf;
  435.  
  436.     if (ap->afid != AFID_NOBUF)
  437.     {
  438.  
  439. /* When we reread a buffer, we need to check to see if we have reached the
  440.  * end.  If we have, we need to read the next buffer.  Hence, this loop for
  441.  * the second read
  442.  */
  443.  
  444.     while (((i = (ap->afid != bp->id)) || (bp->bufp == bp->ebufp)))
  445.     {
  446.  
  447. /* Are we re-reading a corrupted buffer? */
  448.  
  449.         if (i)
  450.         lseek (ap->afile, ap->afpos, SEEK_SET);
  451.  
  452. /* No, filling so set offset to zero */
  453.  
  454.         else
  455.         ap->afoff = 0;
  456.  
  457. /* Save the start of the next buffer */
  458.  
  459.         ap->afpos = lseek (ap->afile, 0L, SEEK_CUR);
  460.  
  461. /* Read in the next buffer */
  462.  
  463.         if ((i = read (ap->afile, bp->buf, sizeof (bp->buf))) <= 0)
  464.         {
  465.         if (ap->afile > STDERR_FILENO)
  466.             S_close (ap->afile, TRUE);
  467.  
  468.         return 0;
  469.         }
  470.  
  471. /* Set up buffer id, start and end */
  472.  
  473.         bp->id    = ap->afid;
  474.         bp->bufp  = bp->buf + ap->afoff;
  475.         bp->ebufp = bp->buf + i;
  476.     }
  477.  
  478. /* Return the next character from the buffer */
  479.  
  480.     ++(ap->afoff);
  481.     return *bp->bufp++ & 0177;
  482.     }
  483.  
  484. /* If this is the terminal, there is special input processing */
  485.  
  486. #ifndef NO_HISTORY
  487.     else if ((ap->afile == 0) && isatty (ap->afile))
  488.         return Get_stdin (ap);
  489. #endif
  490.  
  491.     if ((i = read (ap->afile, &c, sizeof(c))) == sizeof (c))
  492.     return (int)c & 0177;
  493.  
  494.     if (ap->afile > STDERR_FILENO)
  495.     S_close (ap->afile, TRUE);
  496.  
  497.     return 0;
  498. }
  499.  
  500. /*
  501.  * Return the characters from a here temp file.
  502.  */
  503.  
  504. static int        herechar (iop)
  505. register IO_State    *iop;
  506. {
  507.     char            c;
  508.  
  509.     if (read (iop->argp->afile, &c, sizeof(c)) != sizeof(c))
  510.     {
  511.     S_close (iop->argp->afile, TRUE);
  512.     c = 0;
  513.     }
  514.  
  515.     return c;
  516. }
  517.  
  518. /*
  519.  * Return the characters produced by a process (`...`).
  520.  * De-quote them if required.  Use in here documents.
  521.  */
  522.  
  523. int        sgravechar (iop)
  524. IO_State    *iop;
  525. {
  526.     return  qgravechar (iop) & ~QUOTE;
  527. }
  528.  
  529. /*
  530.  * Return the characters produced by a process (`...`).
  531.  * De-quote them if required, and converting NL to space.
  532.  */
  533.  
  534. int        gravechar (iop)
  535. IO_State    *iop;
  536. {
  537.     register int c;
  538.  
  539.     if ((c = qgravechar (iop) & ~QUOTE) == NL)
  540.     c = SP;
  541.  
  542.     return c;
  543. }
  544.  
  545. /*
  546.  * Process input from a `...` string
  547.  */
  548.  
  549. int        qgravechar (iop)
  550. IO_State    *iop;
  551. {
  552.     register int    c;
  553.  
  554.     if (iop->xchar)
  555.     {
  556.     if (iop->nlcount)
  557.     {
  558.         iop->nlcount--;
  559.         return (NL | QUOTE);
  560.     }
  561.  
  562.     c = iop->xchar;
  563.     iop->xchar = 0;
  564.     }
  565.  
  566.     else if ((c = filechar (iop)) == NL)
  567.     {
  568.     iop->nlcount = 1;
  569.  
  570.     while ((c = filechar (iop)) == NL)
  571.         iop->nlcount++;
  572.  
  573.     iop->xchar = (char)c;
  574.  
  575.     if (c == 0)
  576.         return c;
  577.  
  578.     iop->nlcount--;
  579.     c = NL;
  580.     }
  581.  
  582.     return (c != 0) ? (c | QUOTE) : 0;
  583. }
  584.  
  585. /*
  586.  * Return a single command (usually the first line) from a file.
  587.  */
  588.  
  589. int        linechar (iop)
  590. IO_State    *iop;
  591. {
  592.     register int    c;
  593.  
  594.     if ((c = filechar (iop)) == NL)
  595.     {
  596.     if (!multiline)
  597.     {
  598.         if (iop->argp->afile > STDERR_FILENO)
  599.         S_close (iop->argp->afile, TRUE);
  600.  
  601.         iop->argp->afile = -1;    /* illegal value */
  602.     }
  603.     }
  604.  
  605.     return c;
  606. }
  607.  
  608. void    closeall ()
  609. {
  610.     register int    u;
  611.  
  612.     for (u = NUFILE; u < NOFILE;)
  613.     S_close (u++, TRUE);
  614. }
  615.  
  616. /*
  617.  * remap fd into Shell's fd space
  618.  */
  619.  
  620. int        remap (fd)
  621. register int    fd;
  622. {
  623.     register int    i;
  624.     register int    n_io = 0;
  625.     int            map[NOFILE];
  626.     int            o_fd = fd;
  627.  
  628.     if (fd < e.iofd)
  629.     {
  630.     do
  631.     {
  632.         map[n_io++] = fd;
  633.         fd = dup (fd);
  634.  
  635.     } while ((fd >= 0) && (fd < e.iofd));
  636.  
  637.     for (i = 0; i < n_io; i++)
  638.         close (map[i]);
  639.  
  640.     S_Remap (o_fd, fd);
  641.     S_close (o_fd, TRUE);
  642.  
  643.     if (fd < 0)
  644.         print_error ("sh: too many files open\n");
  645.     }
  646.  
  647.     return fd;
  648. }
  649.  
  650. /*
  651.  * here documents
  652.  */
  653.  
  654. void        markhere (s, iop)
  655. register char    *s;
  656. IO_Actions     *iop;
  657. {
  658.     register Here_D    *h, *lh;
  659.  
  660.     if ((h = (Here_D *) space(sizeof(Here_D))) == (Here_D *)NULL)
  661.     return;
  662.  
  663.     if ((h->h_tag = evalstr (s, DOSUB)) == (char *)NULL)
  664.     return;
  665.  
  666.     h->h_iop     = iop;
  667.     iop->io_name = (char *)NULL;
  668.     h->h_next    = (Here_D *)NULL;
  669.  
  670.     if (inhere == (Here_D *)NULL)
  671.     inhere = h;
  672.  
  673.     else
  674.     {
  675.     for (lh = inhere; lh != (Here_D *)NULL; lh = lh->h_next)
  676.     {
  677.         if (lh->h_next == (Here_D *)NULL)
  678.         {
  679.         lh->h_next = h;
  680.         break;
  681.         }
  682.     }
  683.     }
  684.  
  685.     iop->io_flag |= IOHERE|IOXHERE;
  686.  
  687.     for (s = h->h_tag; *s; s++)
  688.     {
  689.     if (*s & QUOTE)
  690.     {
  691.         iop->io_flag &= ~ IOXHERE;
  692.         *s &= ~ QUOTE;
  693.     }
  694.     }
  695.  
  696.     h->h_dosub = iop->io_flag & IOXHERE;
  697. }
  698.  
  699. void    gethere ()
  700. {
  701.     register Here_D    *h, *hp;
  702.  
  703. /* Scan here files first leaving inhere list in place */
  704.  
  705.     for (hp = h = inhere; h != (Here_D *)NULL; hp = h, h = h->h_next)
  706.     readhere (&h->h_iop->io_name, h->h_tag, h->h_dosub ? 0 : '\'',
  707.           h->h_iop->io_flag);
  708.  
  709. /* Make inhere list active - keep list intact for scraphere */
  710.  
  711.     if (hp != (Here_D *)NULL)
  712.     {
  713.     hp->h_next = acthere;
  714.     acthere    = inhere;
  715.     inhere     = (Here_D *)NULL;
  716.     }
  717. }
  718.  
  719. static void    readhere (name, s, ec, ioflag)
  720. char        **name;
  721. register char    *s;
  722. int        ec;
  723. int        ioflag;
  724. {
  725.     int            tf;
  726.     register int    c;
  727.     jmp_buf        ev;
  728.     char        *line;
  729.     char        *next;
  730.     int            stop_len;
  731.     int            c_len;
  732.     Out_Buf        *bp;
  733.  
  734. /* Create a temporary file and open it */
  735.  
  736.     *name = strsave (g_tempname (), areanum);
  737.  
  738.     if ((tf = S_open (FALSE, *name, O_CMASK | O_NOINHERIT, 0600)) < 0)
  739.     return;
  740.  
  741.     if (newenv (setjmp (errpt = ev)) == TRUE)
  742.     S_Delete (tf);
  743.  
  744.     else
  745.     {
  746.     pushio (e.iop->argp, e.iop->iofn);
  747.     e.iobase = e.iop;
  748.  
  749. /* Strip leading tabs? */
  750.  
  751.     if (ioflag & IOTHERE)
  752.     {
  753.         while (*s && (*s == '\t'))
  754.         ++s;
  755.     }
  756.  
  757. /* Open the Output buffer */
  758.  
  759.     line = space ((stop_len = strlen (s) + 2) + 1);
  760.     bp = Open_buffer (tf, TRUE);
  761.  
  762. /* Read in */
  763.  
  764.     while (1)
  765.     {
  766.         next = line;
  767.         c_len = 0;
  768.  
  769.         if (talking && e.iop <= iostack + 1)
  770.         {
  771. #ifndef NO_HISTORY
  772.         Add_History (FALSE);
  773. #endif
  774.         put_prompt (ps2->value);
  775.         }
  776.  
  777. /* Read the here document */
  778.  
  779.         while ((c = Getc (ec)) != NL && c)
  780.         {
  781.  
  782. /* Strip leading tabs? */
  783.  
  784.         if ((ioflag & IOTHERE) && (c == '\t') && (next == line))
  785.             continue;
  786.  
  787.         if (ec == '\'')
  788.             c &= ~ QUOTE;
  789.  
  790. /* If not end of search string, add to search string */
  791.  
  792.         if ((++c_len) < stop_len)
  793.             *(next++) = (char)c;
  794.  
  795. /* If one greater that search string, buffer search string */
  796.  
  797.         else
  798.         {
  799.             if (c_len == stop_len)
  800.             {
  801.             *next = 0;
  802.             Adds_buffer (line, bp);
  803.             }
  804.  
  805. /* Buffer the current character */
  806.  
  807.             Add_buffer ((char)c, bp);
  808.         }
  809.         }
  810.  
  811. /* Check for end of document */
  812.  
  813.         *next = 0;
  814.         if (strcmp (s, line) == 0 || c == 0)
  815.         break;
  816.  
  817.         if (c_len < stop_len)
  818.             Adds_buffer (line, bp);
  819.  
  820.         Add_buffer (NL, bp);
  821.     }
  822.  
  823.     Close_buffer (bp);
  824.  
  825.     if (c == 0)
  826.         print_error ("here document `%s' unclosed\n", s);
  827.  
  828.     quitenv ();
  829.     }
  830.  
  831.     S_close (tf, TRUE);
  832. }
  833.  
  834. /*
  835.  * open here temp file.
  836.  * If unquoted here, expand here temp file into second temp file.
  837.  */
  838.  
  839. int        herein (hname, xdoll)
  840. char        *hname;
  841. int        xdoll;
  842. {
  843.     register int    hf, tf;
  844.  
  845. /* If the here document is invalid or does not exist, return */
  846.  
  847.     if (hname == (char *)NULL)
  848.     return -1;
  849.  
  850.     if ((hf = S_open (FALSE, hname, O_RDONLY)) < 0)
  851.     return -1;
  852.  
  853. /* If processing for $, ` and ' is required, do it */
  854.  
  855.     if (xdoll)
  856.     {
  857.     char        c;
  858.     char        *tname = strsave (g_tempname (), areanum);
  859.     Out_Buf        *bp;
  860.     jmp_buf        ev;
  861.  
  862.     if ((tf = S_open (FALSE, tname, O_CMASK | O_NOINHERIT, 0600)) < 0)
  863.         return -1;
  864.  
  865.     if (newenv (setjmp (errpt = ev)) == FALSE)
  866.     {
  867.         bp = Open_buffer (tf, TRUE);
  868.         PUSHIO (afile, hf, herechar);
  869.         e.iobase = e.iop;
  870.  
  871.         while ((c = (char)subgetc (0, 0)) != 0)
  872.         {
  873.  
  874. /* Determine how many characters to write.  If MSB set, write \x.
  875.  * Otherwise, write x
  876.  */
  877.  
  878.         if ((c & QUOTE) && !any ((c & ~QUOTE), "$`\\"))
  879.             Add_buffer ('\\', bp);
  880.  
  881.         Add_buffer ((char)(c & (~QUOTE)), bp);
  882.         }
  883.  
  884.         quitenv ();
  885.     }
  886.  
  887.     else
  888.         S_Delete (tf);
  889.  
  890.     Close_buffer (bp);
  891.     S_close (tf, TRUE);
  892.     return S_open (TRUE, tname, O_RDONLY);
  893.     }
  894.  
  895.     else
  896.     return hf;
  897. }
  898.  
  899. void    scraphere()
  900. {
  901.     register Here_D    *h;
  902.  
  903.     for (h = inhere; h != (Here_D *)NULL; h = h->h_next)
  904.     {
  905.     if ((h->h_iop != (IO_Actions *)NULL) &&
  906.         (h->h_iop->io_name != (char *)NULL))
  907.         unlink (h->h_iop->io_name);
  908.     }
  909.  
  910.     inhere = (Here_D *)NULL;
  911. }
  912.  
  913. /* unlink here temp files before a freearea (area) */
  914.  
  915. void    freehere (area)
  916. int    area;
  917. {
  918.     register Here_D    *h;
  919.     register Here_D    *hl = (Here_D *)NULL;
  920.  
  921.     for (h = acthere; h != (Here_D *)NULL; hl = h, h = h->h_next)
  922.     {
  923.     if (getarea ((char *)h) >= area)
  924.     {
  925.         if (h->h_iop->io_name != (char *)NULL)
  926.         unlink (h->h_iop->io_name);
  927.  
  928.         if (hl == (Here_D *)NULL)
  929.         acthere = h->h_next;
  930.  
  931.         else
  932.         hl->h_next = h->h_next;
  933.     }
  934.     }
  935. }
  936.  
  937. char    *g_tempname ()
  938. {
  939.     static char    tmpfile[FFNAME_MAX];
  940.     char    *tmpdir;    /* Points to directory prefix of pipe    */
  941.     static int    temp_count = 0;
  942.     char    *sep = "/";
  943.  
  944. /* Find out where we should put temporary files */
  945.  
  946.     if (((tmpdir = lookup ("TMP", FALSE)->value) == null) &&
  947.     ((tmpdir = lookup (home, FALSE)->value) == null))
  948.     tmpdir = lookup ("TMPDIR", FALSE)->value;
  949.     
  950.     if (any (tmpdir[strlen (tmpdir) - 1], "/\\"))
  951.     sep = null;
  952.  
  953. /* Get a unique temporary file name */
  954.  
  955.     while (1)
  956.     {
  957.     sprintf (tmpfile, "%s%ssht%.5u.tmp", tmpdir, sep, temp_count++);
  958.  
  959.     if (access (tmpfile, F_OK) != 0)
  960.         break;
  961.     }
  962.  
  963.     return tmpfile;
  964. }
  965.  
  966. /* Test to see if the current Input device is the console */
  967.  
  968. bool    Interactive ()
  969. {
  970.     return (talking && (e.iop->task == XIO) && isatty (e.iop->argp->afile))
  971.        ? TRUE : FALSE;
  972. }
  973.