home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 22 gnu / 22-gnu.zip / ash02emx.zip / output.c < prev    next >
C/C++ Source or Header  |  1997-12-26  |  11KB  |  536 lines

  1. /*-
  2.  * Copyright (c) 1991 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * This code is derived from software contributed to Berkeley by
  6.  * Kenneth Almquist.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *    This product includes software developed by the University of
  19.  *    California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  */
  36.  
  37. #ifndef lint
  38. /*static char sccsid[] = "from: @(#)output.c    5.1 (Berkeley) 3/7/91";*/
  39. static char rcsid[] = "output.c,v 1.5 1993/09/05 17:32:08 mycroft Exp";
  40. #endif /* not lint */
  41.  
  42. /*
  43.  * Shell output routines.  We use our own output routines because:
  44.  *    When a builtin command is interrupted we have to discard
  45.  *        any pending output.
  46.  *    When a builtin command appears in back quotes, we want to
  47.  *        save the output of the command in a region obtained
  48.  *        via malloc, rather than doing a fork and reading the
  49.  *        output of the command via a pipe.
  50.  *    Our output routines may be smaller than the stdio routines.
  51.  */
  52.  
  53. #include <stdio.h>    /* defines BUFSIZ */
  54. #include "shell.h"
  55. #include "syntax.h"
  56. #include "output.h"
  57. #include "memalloc.h"
  58. #include "error.h"
  59. #ifdef __STDC__
  60. #include "stdarg.h"
  61. #else
  62. #include <varargs.h>
  63. #endif
  64. #include <errno.h>
  65.  
  66.  
  67. #define OUTBUFSIZ BUFSIZ
  68. #define BLOCK_OUT -2        /* output to a fixed block of memory */
  69. #define MEM_OUT -3        /* output to dynamically allocated memory */
  70. #define OUTPUT_ERR 01        /* error occurred on output */
  71.  
  72.  
  73. struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0};
  74. struct output errout = {NULL, 0, NULL, 100, 2, 0};
  75. struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0};
  76. struct output *out1 = &output;
  77. struct output *out2 = &errout;
  78.  
  79.  
  80.  
  81. #ifdef mkinit
  82.  
  83. INCLUDE "output.h"
  84. INCLUDE "memalloc.h"
  85.  
  86. RESET {
  87.     out1 = &output;
  88.     out2 = &errout;
  89.     if (memout.buf != NULL) {
  90.         ckfree(memout.buf);
  91.         memout.buf = NULL;
  92.     }
  93. }
  94.  
  95. #endif
  96.  
  97.  
  98. #ifdef notdef    /* no longer used */
  99. /*
  100.  * Set up an output file to write to memory rather than a file.
  101.  */
  102.  
  103. void
  104. open_mem(block, length, file)
  105.     char *block;
  106.     int length;
  107.     struct output *file;
  108.     {
  109.     file->nextc = block;
  110.     file->nleft = --length;
  111.     file->fd = BLOCK_OUT;
  112.     file->flags = 0;
  113. }
  114. #endif
  115.  
  116.  
  117. void
  118. out1str(p)
  119.     char *p;
  120.     {
  121.     outstr(p, out1);
  122. }
  123.  
  124.  
  125. void
  126. out2str(p)
  127.     char *p;
  128.     {
  129.     outstr(p, out2);
  130. }
  131.  
  132.  
  133. void
  134. outstr(p, file)
  135.     register char *p;
  136.     register struct output *file;
  137.     {
  138.     while (*p)
  139.         outc(*p++, file);
  140. }
  141.  
  142.  
  143. char out_junk[16];
  144.  
  145.  
  146. void
  147. emptyoutbuf(dest)
  148.     struct output *dest;
  149.     {
  150.     int offset;
  151.  
  152.     if (dest->fd == BLOCK_OUT) {
  153.         dest->nextc = out_junk;
  154.         dest->nleft = sizeof out_junk;
  155.         dest->flags |= OUTPUT_ERR;
  156.     } else if (dest->buf == NULL) {
  157.         INTOFF;
  158.         dest->buf = ckmalloc(dest->bufsize);
  159.         dest->nextc = dest->buf;
  160.         dest->nleft = dest->bufsize;
  161.         INTON;
  162.     } else if (dest->fd == MEM_OUT) {
  163.         offset = dest->bufsize;
  164.         INTOFF;
  165.         dest->bufsize <<= 1;
  166.         dest->buf = ckrealloc(dest->buf, dest->bufsize);
  167.         dest->nleft = dest->bufsize - offset;
  168.         dest->nextc = dest->buf + offset;
  169.         INTON;
  170.     } else {
  171.         flushout(dest);
  172.     }
  173.     dest->nleft--;
  174. }
  175.  
  176.  
  177. #ifdef __EMX__
  178. int
  179. #else
  180. void
  181. #endif
  182. flushall() {
  183.     flushout(&output);
  184.     flushout(&errout);
  185. }
  186.  
  187.  
  188. void
  189. flushout(dest)
  190.     struct output *dest;
  191.     {
  192.  
  193.     if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0)
  194.         return;
  195.     if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0)
  196.         dest->flags |= OUTPUT_ERR;
  197.     dest->nextc = dest->buf;
  198.     dest->nleft = dest->bufsize;
  199. }
  200.  
  201.  
  202. void
  203. freestdout() {
  204.     INTOFF;
  205.     if (output.buf) {
  206.         ckfree(output.buf);
  207.         output.buf = NULL;
  208.         output.nleft = 0;
  209.     }
  210.     INTON;
  211. }
  212.  
  213.  
  214. #ifdef __STDC__
  215. void
  216. outfmt(struct output *file, char *fmt, ...) {
  217.     va_list ap;
  218.  
  219.     va_start(ap, fmt);
  220.     doformat(file, fmt, ap);
  221.     va_end(ap);
  222. }
  223.  
  224.  
  225. void
  226. out1fmt(char *fmt, ...) {
  227.     va_list ap;
  228.  
  229.     va_start(ap, fmt);
  230.     doformat(out1, fmt, ap);
  231.     va_end(ap);
  232. }
  233.  
  234.  
  235. void
  236. fmtstr(char *outbuf, int length, char *fmt, ...) {
  237.     va_list ap;
  238.     struct output strout;
  239.  
  240.     va_start(ap, fmt);
  241.     strout.nextc = outbuf;
  242.     strout.nleft = length;
  243.     strout.fd = BLOCK_OUT;
  244.     strout.flags = 0;
  245.     doformat(&strout, fmt, ap);
  246.     outc('\0', &strout);
  247.     if (strout.flags & OUTPUT_ERR)
  248.         outbuf[length - 1] = '\0';
  249. }
  250.  
  251. #else /* not __STDC__ */
  252.  
  253. void
  254. outfmt(va_alist)
  255.     va_dcl
  256.     {
  257.     va_list ap;
  258.     struct output *file;
  259.     char *fmt;
  260.  
  261.     va_start(ap);
  262.     file = va_arg(ap, struct output *);
  263.     fmt = va_arg(ap, char *);
  264.     doformat(file, fmt, ap);
  265.     va_end(ap);
  266. }
  267.  
  268.  
  269. void
  270. out1fmt(va_alist)
  271.     va_dcl
  272.     {
  273.     va_list ap;
  274.     char *fmt;
  275.  
  276.     va_start(ap);
  277.     fmt = va_arg(ap, char *);
  278.     doformat(out1, fmt, ap);
  279.     va_end(ap);
  280. }
  281.  
  282.  
  283. void
  284. fmtstr(va_alist)
  285.     va_dcl
  286.     {
  287.     va_list ap;
  288.     struct output strout;
  289.     char *outbuf;
  290.     int length;
  291.     char *fmt;
  292.  
  293.     va_start(ap);
  294.     outbuf = va_arg(ap, char *);
  295.     length = va_arg(ap, int);
  296.     fmt = va_arg(ap, char *);
  297.     strout.nextc = outbuf;
  298.     strout.nleft = length;
  299.     strout.fd = BLOCK_OUT;
  300.     strout.flags = 0;
  301.     doformat(&strout, fmt, ap);
  302.     outc('\0', &strout);
  303.     if (strout.flags & OUTPUT_ERR)
  304.         outbuf[length - 1] = '\0';
  305. }
  306. #endif /* __STDC__ */
  307.  
  308.  
  309. /*
  310.  * Formatted output.  This routine handles a subset of the printf formats:
  311.  * - Formats supported: d, u, o, X, s, and c.
  312.  * - The x format is also accepted but is treated like X.
  313.  * - The l modifier is accepted.
  314.  * - The - and # flags are accepted; # only works with the o format.
  315.  * - Width and precision may be specified with any format except c.
  316.  * - An * may be given for the width or precision.
  317.  * - The obsolete practice of preceding the width with a zero to get
  318.  *   zero padding is not supported; use the precision field.
  319.  * - A % may be printed by writing %% in the format string.
  320.  */
  321.  
  322. #define TEMPSIZE 24
  323.  
  324. #ifdef __STDC__
  325. static const char digit[16] = "0123456789ABCDEF";
  326. #else
  327. static const char digit[17] = "0123456789ABCDEF";
  328. #endif
  329.  
  330.  
  331. void
  332. doformat(dest, f, ap)
  333.     register struct output *dest;
  334.     register char *f;        /* format string */
  335.     va_list ap;
  336.     {
  337.     register char c;
  338.     char temp[TEMPSIZE];
  339.     int flushleft;
  340.     int sharp;
  341.     int width;
  342.     int prec;
  343.     int islong;
  344.     char *p;
  345.     int sign;
  346.     long l;
  347.     unsigned long num;
  348.     unsigned base;
  349.     int len;
  350.     int size;
  351.     int pad;
  352.  
  353.     while ((c = *f++) != '\0') {
  354.         if (c != '%') {
  355.             outc(c, dest);
  356.             continue;
  357.         }
  358.         flushleft = 0;
  359.         sharp = 0;
  360.         width = 0;
  361.         prec = -1;
  362.         islong = 0;
  363.         for (;;) {
  364.             if (*f == '-')
  365.                 flushleft++;
  366.             else if (*f == '#')
  367.                 sharp++;
  368.             else
  369.                 break;
  370.             f++;
  371.         }
  372.         if (*f == '*') {
  373.             width = va_arg(ap, int);
  374.             f++;
  375.         } else {
  376.             while (is_digit(*f)) {
  377.                 width = 10 * width + digit_val(*f++);
  378.             }
  379.         }
  380.         if (*f == '.') {
  381.             if (*++f == '*') {
  382.                 prec = va_arg(ap, int);
  383.                 f++;
  384.             } else {
  385.                 prec = 0;
  386.                 while (is_digit(*f)) {
  387.                     prec = 10 * prec + digit_val(*f++);
  388.                 }
  389.             }
  390.         }
  391.         if (*f == 'l') {
  392.             islong++;
  393.             f++;
  394.         }
  395.         switch (*f) {
  396.         case 'd':
  397.             if (islong)
  398.                 l = va_arg(ap, long);
  399.             else
  400.                 l = va_arg(ap, int);
  401.             sign = 0;
  402.             num = l;
  403.             if (l < 0) {
  404.                 num = -l;
  405.                 sign = 1;
  406.             }
  407.             base = 10;
  408.             goto number;
  409.         case 'u':
  410.             base = 10;
  411.             goto uns_number;
  412.         case 'o':
  413.             base = 8;
  414.             goto uns_number;
  415.         case 'x':
  416.             /* we don't implement 'x'; treat like 'X' */
  417.         case 'X':
  418.             base = 16;
  419. uns_number:      /* an unsigned number */
  420.             sign = 0;
  421.             if (islong)
  422.                 num = va_arg(ap, unsigned long);
  423.             else
  424.                 num = va_arg(ap, unsigned int);
  425. number:          /* process a number */
  426.             p = temp + TEMPSIZE - 1;
  427.             *p = '\0';
  428.             while (num) {
  429.                 *--p = digit[num % base];
  430.                 num /= base;
  431.             }
  432.             len = (temp + TEMPSIZE - 1) - p;
  433.             if (prec < 0)
  434.                 prec = 1;
  435.             if (sharp && *f == 'o' && prec <= len)
  436.                 prec = len + 1;
  437.             pad = 0;
  438.             if (width) {
  439.                 size = len;
  440.                 if (size < prec)
  441.                     size = prec;
  442.                 size += sign;
  443.                 pad = width - size;
  444.                 if (flushleft == 0) {
  445.                     while (--pad >= 0)
  446.                         outc(' ', dest);
  447.                 }
  448.             }
  449.             if (sign)
  450.                 outc('-', dest);
  451.             prec -= len;
  452.             while (--prec >= 0)
  453.                 outc('0', dest);
  454.             while (*p)
  455.                 outc(*p++, dest);
  456.             while (--pad >= 0)
  457.                 outc(' ', dest);
  458.             break;
  459.         case 's':
  460.             p = va_arg(ap, char *);
  461.             pad = 0;
  462.             if (width) {
  463.                 len = strlen(p);
  464.                 if (prec >= 0 && len > prec)
  465.                     len = prec;
  466.                 pad = width - len;
  467.                 if (flushleft == 0) {
  468.                     while (--pad >= 0)
  469.                         outc(' ', dest);
  470.                 }
  471.             }
  472.             prec++;
  473.             while (--prec != 0 && *p)
  474.                 outc(*p++, dest);
  475.             while (--pad >= 0)
  476.                 outc(' ', dest);
  477.             break;
  478.         case 'c':
  479.             c = va_arg(ap, int);
  480.             outc(c, dest);
  481.             break;
  482.         default:
  483.             outc(*f, dest);
  484.             break;
  485.         }
  486.         f++;
  487.     }
  488. }
  489.  
  490.  
  491.  
  492. /*
  493.  * Version of write which resumes after a signal is caught.
  494.  */
  495.  
  496. int
  497. xwrite(fd, buf, nbytes)
  498.     int fd;
  499.     char *buf;
  500.     int nbytes;
  501.     {
  502.     int ntry;
  503.     int i;
  504.     int n;
  505.  
  506.     n = nbytes;
  507.     ntry = 0;
  508.     for (;;) {
  509.         i = write(fd, buf, n);
  510.         if (i > 0) {
  511.             if ((n -= i) <= 0)
  512.                 return nbytes;
  513.             buf += i;
  514.             ntry = 0;
  515.         } else if (i == 0) {
  516.             if (++ntry > 10)
  517.                 return nbytes - n;
  518.         } else if (errno != EINTR) {
  519.             return -1;
  520.         }
  521.     }
  522. }
  523.  
  524.  
  525. /*
  526.  * Version of ioctl that retries after a signal is caught.
  527.  */
  528.  
  529. int
  530. xioctl(fd, request, arg) {
  531.     int i;
  532.  
  533.     while ((i = ioctl(fd, request, arg)) == -1 && errno == EINTR);
  534.     return i;
  535. }
  536.