home *** CD-ROM | disk | FTP | other *** search
/ PC-Online 1996 May / PCOnline_05_1996.bin / linux / source / ap / ash / ash-linu.2 / ash-linu / ash-linux-0.2 / output.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-09-06  |  10.1 KB  |  532 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. void
  178. flushall() {
  179.     flushout(&output);
  180.     flushout(&errout);
  181. }
  182.  
  183.  
  184. void
  185. flushout(dest)
  186.     struct output *dest;
  187.     {
  188.  
  189.     if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0)
  190.         return;
  191.     if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0)
  192.         dest->flags |= OUTPUT_ERR;
  193.     dest->nextc = dest->buf;
  194.     dest->nleft = dest->bufsize;
  195. }
  196.  
  197.  
  198. void
  199. freestdout() {
  200.     INTOFF;
  201.     if (output.buf) {
  202.         ckfree(output.buf);
  203.         output.buf = NULL;
  204.         output.nleft = 0;
  205.     }
  206.     INTON;
  207. }
  208.  
  209.  
  210. #ifdef __STDC__
  211. void
  212. outfmt(struct output *file, char *fmt, ...) {
  213.     va_list ap;
  214.  
  215.     va_start(ap, fmt);
  216.     doformat(file, fmt, ap);
  217.     va_end(ap);
  218. }
  219.  
  220.  
  221. void
  222. out1fmt(char *fmt, ...) {
  223.     va_list ap;
  224.  
  225.     va_start(ap, fmt);
  226.     doformat(out1, fmt, ap);
  227.     va_end(ap);
  228. }
  229.  
  230.  
  231. void
  232. fmtstr(char *outbuf, int length, char *fmt, ...) {
  233.     va_list ap;
  234.     struct output strout;
  235.  
  236.     va_start(ap, fmt);
  237.     strout.nextc = outbuf;
  238.     strout.nleft = length;
  239.     strout.fd = BLOCK_OUT;
  240.     strout.flags = 0;
  241.     doformat(&strout, fmt, ap);
  242.     outc('\0', &strout);
  243.     if (strout.flags & OUTPUT_ERR)
  244.         outbuf[length - 1] = '\0';
  245. }
  246.  
  247. #else /* not __STDC__ */
  248.  
  249. void
  250. outfmt(va_alist)
  251.     va_dcl
  252.     {
  253.     va_list ap;
  254.     struct output *file;
  255.     char *fmt;
  256.  
  257.     va_start(ap);
  258.     file = va_arg(ap, struct output *);
  259.     fmt = va_arg(ap, char *);
  260.     doformat(file, fmt, ap);
  261.     va_end(ap);
  262. }
  263.  
  264.  
  265. void
  266. out1fmt(va_alist)
  267.     va_dcl
  268.     {
  269.     va_list ap;
  270.     char *fmt;
  271.  
  272.     va_start(ap);
  273.     fmt = va_arg(ap, char *);
  274.     doformat(out1, fmt, ap);
  275.     va_end(ap);
  276. }
  277.  
  278.  
  279. void
  280. fmtstr(va_alist)
  281.     va_dcl
  282.     {
  283.     va_list ap;
  284.     struct output strout;
  285.     char *outbuf;
  286.     int length;
  287.     char *fmt;
  288.  
  289.     va_start(ap);
  290.     outbuf = va_arg(ap, char *);
  291.     length = va_arg(ap, int);
  292.     fmt = va_arg(ap, char *);
  293.     strout.nextc = outbuf;
  294.     strout.nleft = length;
  295.     strout.fd = BLOCK_OUT;
  296.     strout.flags = 0;
  297.     doformat(&strout, fmt, ap);
  298.     outc('\0', &strout);
  299.     if (strout.flags & OUTPUT_ERR)
  300.         outbuf[length - 1] = '\0';
  301. }
  302. #endif /* __STDC__ */
  303.  
  304.  
  305. /*
  306.  * Formatted output.  This routine handles a subset of the printf formats:
  307.  * - Formats supported: d, u, o, X, s, and c.
  308.  * - The x format is also accepted but is treated like X.
  309.  * - The l modifier is accepted.
  310.  * - The - and # flags are accepted; # only works with the o format.
  311.  * - Width and precision may be specified with any format except c.
  312.  * - An * may be given for the width or precision.
  313.  * - The obsolete practice of preceding the width with a zero to get
  314.  *   zero padding is not supported; use the precision field.
  315.  * - A % may be printed by writing %% in the format string.
  316.  */
  317.  
  318. #define TEMPSIZE 24
  319.  
  320. #ifdef __STDC__
  321. static const char digit[16] = "0123456789ABCDEF";
  322. #else
  323. static const char digit[17] = "0123456789ABCDEF";
  324. #endif
  325.  
  326.  
  327. void
  328. doformat(dest, f, ap)
  329.     register struct output *dest;
  330.     register char *f;        /* format string */
  331.     va_list ap;
  332.     {
  333.     register char c;
  334.     char temp[TEMPSIZE];
  335.     int flushleft;
  336.     int sharp;
  337.     int width;
  338.     int prec;
  339.     int islong;
  340.     char *p;
  341.     int sign;
  342.     long l;
  343.     unsigned long num;
  344.     unsigned base;
  345.     int len;
  346.     int size;
  347.     int pad;
  348.  
  349.     while ((c = *f++) != '\0') {
  350.         if (c != '%') {
  351.             outc(c, dest);
  352.             continue;
  353.         }
  354.         flushleft = 0;
  355.         sharp = 0;
  356.         width = 0;
  357.         prec = -1;
  358.         islong = 0;
  359.         for (;;) {
  360.             if (*f == '-')
  361.                 flushleft++;
  362.             else if (*f == '#')
  363.                 sharp++;
  364.             else
  365.                 break;
  366.             f++;
  367.         }
  368.         if (*f == '*') {
  369.             width = va_arg(ap, int);
  370.             f++;
  371.         } else {
  372.             while (is_digit(*f)) {
  373.                 width = 10 * width + digit_val(*f++);
  374.             }
  375.         }
  376.         if (*f == '.') {
  377.             if (*++f == '*') {
  378.                 prec = va_arg(ap, int);
  379.                 f++;
  380.             } else {
  381.                 prec = 0;
  382.                 while (is_digit(*f)) {
  383.                     prec = 10 * prec + digit_val(*f++);
  384.                 }
  385.             }
  386.         }
  387.         if (*f == 'l') {
  388.             islong++;
  389.             f++;
  390.         }
  391.         switch (*f) {
  392.         case 'd':
  393.             if (islong)
  394.                 l = va_arg(ap, long);
  395.             else
  396.                 l = va_arg(ap, int);
  397.             sign = 0;
  398.             num = l;
  399.             if (l < 0) {
  400.                 num = -l;
  401.                 sign = 1;
  402.             }
  403.             base = 10;
  404.             goto number;
  405.         case 'u':
  406.             base = 10;
  407.             goto uns_number;
  408.         case 'o':
  409.             base = 8;
  410.             goto uns_number;
  411.         case 'x':
  412.             /* we don't implement 'x'; treat like 'X' */
  413.         case 'X':
  414.             base = 16;
  415. uns_number:      /* an unsigned number */
  416.             sign = 0;
  417.             if (islong)
  418.                 num = va_arg(ap, unsigned long);
  419.             else
  420.                 num = va_arg(ap, unsigned int);
  421. number:          /* process a number */
  422.             p = temp + TEMPSIZE - 1;
  423.             *p = '\0';
  424.             while (num) {
  425.                 *--p = digit[num % base];
  426.                 num /= base;
  427.             }
  428.             len = (temp + TEMPSIZE - 1) - p;
  429.             if (prec < 0)
  430.                 prec = 1;
  431.             if (sharp && *f == 'o' && prec <= len)
  432.                 prec = len + 1;
  433.             pad = 0;
  434.             if (width) {
  435.                 size = len;
  436.                 if (size < prec)
  437.                     size = prec;
  438.                 size += sign;
  439.                 pad = width - size;
  440.                 if (flushleft == 0) {
  441.                     while (--pad >= 0)
  442.                         outc(' ', dest);
  443.                 }
  444.             }
  445.             if (sign)
  446.                 outc('-', dest);
  447.             prec -= len;
  448.             while (--prec >= 0)
  449.                 outc('0', dest);
  450.             while (*p)
  451.                 outc(*p++, dest);
  452.             while (--pad >= 0)
  453.                 outc(' ', dest);
  454.             break;
  455.         case 's':
  456.             p = va_arg(ap, char *);
  457.             pad = 0;
  458.             if (width) {
  459.                 len = strlen(p);
  460.                 if (prec >= 0 && len > prec)
  461.                     len = prec;
  462.                 pad = width - len;
  463.                 if (flushleft == 0) {
  464.                     while (--pad >= 0)
  465.                         outc(' ', dest);
  466.                 }
  467.             }
  468.             prec++;
  469.             while (--prec != 0 && *p)
  470.                 outc(*p++, dest);
  471.             while (--pad >= 0)
  472.                 outc(' ', dest);
  473.             break;
  474.         case 'c':
  475.             c = va_arg(ap, int);
  476.             outc(c, dest);
  477.             break;
  478.         default:
  479.             outc(*f, dest);
  480.             break;
  481.         }
  482.         f++;
  483.     }
  484. }
  485.  
  486.  
  487.  
  488. /*
  489.  * Version of write which resumes after a signal is caught.
  490.  */
  491.  
  492. int
  493. xwrite(fd, buf, nbytes)
  494.     int fd;
  495.     char *buf;
  496.     int nbytes;
  497.     {
  498.     int ntry;
  499.     int i;
  500.     int n;
  501.  
  502.     n = nbytes;
  503.     ntry = 0;
  504.     for (;;) {
  505.         i = write(fd, buf, n);
  506.         if (i > 0) {
  507.             if ((n -= i) <= 0)
  508.                 return nbytes;
  509.             buf += i;
  510.             ntry = 0;
  511.         } else if (i == 0) {
  512.             if (++ntry > 10)
  513.                 return nbytes - n;
  514.         } else if (errno != EINTR) {
  515.             return -1;
  516.         }
  517.     }
  518. }
  519.  
  520.  
  521. /*
  522.  * Version of ioctl that retries after a signal is caught.
  523.  */
  524.  
  525. int
  526. xioctl(fd, request, arg) {
  527.     int i;
  528.  
  529.     while ((i = ioctl(fd, request, arg)) == -1 && errno == EINTR);
  530.     return i;
  531. }
  532.