home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / bin / sh / output.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-15  |  10.0 KB  |  531 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[] = "@(#)output.c    5.1 (Berkeley) 3/7/91";
  39. #endif /* not lint */
  40.  
  41. /*
  42.  * Shell output routines.  We use our own output routines because:
  43.  *    When a builtin command is interrupted we have to discard
  44.  *        any pending output.
  45.  *    When a builtin command appears in back quotes, we want to
  46.  *        save the output of the command in a region obtained
  47.  *        via malloc, rather than doing a fork and reading the
  48.  *        output of the command via a pipe.
  49.  *    Our output routines may be smaller than the stdio routines.
  50.  */
  51.  
  52. #include <stdio.h>    /* defines BUFSIZ */
  53. #include "shell.h"
  54. #include "syntax.h"
  55. #include "output.h"
  56. #include "memalloc.h"
  57. #include "error.h"
  58. #ifdef __STDC__
  59. #include "stdarg.h"
  60. #else
  61. #include <varargs.h>
  62. #endif
  63. #include <errno.h>
  64.  
  65.  
  66. #define OUTBUFSIZ BUFSIZ
  67. #define BLOCK_OUT -2        /* output to a fixed block of memory */
  68. #define MEM_OUT -3        /* output to dynamically allocated memory */
  69. #define OUTPUT_ERR 01        /* error occurred on output */
  70.  
  71.  
  72. struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0};
  73. struct output errout = {NULL, 0, NULL, 100, 2, 0};;
  74. struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0};
  75. struct output *out1 = &output;
  76. struct output *out2 = &errout;
  77.  
  78.  
  79.  
  80. #ifdef mkinit
  81.  
  82. INCLUDE "output.h"
  83. INCLUDE "memalloc.h"
  84.  
  85. RESET {
  86.     out1 = &output;
  87.     out2 = &errout;
  88.     if (memout.buf != NULL) {
  89.         ckfree(memout.buf);
  90.         memout.buf = NULL;
  91.     }
  92. }
  93.  
  94. #endif
  95.  
  96.  
  97. #ifdef notdef    /* no longer used */
  98. /*
  99.  * Set up an output file to write to memory rather than a file.
  100.  */
  101.  
  102. void
  103. open_mem(block, length, file)
  104.     char *block;
  105.     int length;
  106.     struct output *file;
  107.     {
  108.     file->nextc = block;
  109.     file->nleft = --length;
  110.     file->fd = BLOCK_OUT;
  111.     file->flags = 0;
  112. }
  113. #endif
  114.  
  115.  
  116. void
  117. out1str(p)
  118.     char *p;
  119.     {
  120.     outstr(p, out1);
  121. }
  122.  
  123.  
  124. void
  125. out2str(p)
  126.     char *p;
  127.     {
  128.     outstr(p, out2);
  129. }
  130.  
  131.  
  132. void
  133. outstr(p, file)
  134.     register char *p;
  135.     register struct output *file;
  136.     {
  137.     while (*p)
  138.         outc(*p++, file);
  139. }
  140.  
  141.  
  142. char out_junk[16];
  143.  
  144.  
  145. void
  146. emptyoutbuf(dest)
  147.     struct output *dest;
  148.     {
  149.     int offset;
  150.  
  151.     if (dest->fd == BLOCK_OUT) {
  152.         dest->nextc = out_junk;
  153.         dest->nleft = sizeof out_junk;
  154.         dest->flags |= OUTPUT_ERR;
  155.     } else if (dest->buf == NULL) {
  156.         INTOFF;
  157.         dest->buf = ckmalloc(dest->bufsize);
  158.         dest->nextc = dest->buf;
  159.         dest->nleft = dest->bufsize;
  160.         INTON;
  161.     } else if (dest->fd == MEM_OUT) {
  162.         offset = dest->bufsize;
  163.         INTOFF;
  164.         dest->bufsize <<= 1;
  165.         dest->buf = ckrealloc(dest->buf, dest->bufsize);
  166.         dest->nleft = dest->bufsize - offset;
  167.         dest->nextc = dest->buf + offset;
  168.         INTON;
  169.     } else {
  170.         flushout(dest);
  171.     }
  172.     dest->nleft--;
  173. }
  174.  
  175.  
  176. void
  177. flushall() {
  178.     flushout(&output);
  179.     flushout(&errout);
  180. }
  181.  
  182.  
  183. void
  184. flushout(dest)
  185.     struct output *dest;
  186.     {
  187.  
  188.     if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0)
  189.         return;
  190.     if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0)
  191.         dest->flags |= OUTPUT_ERR;
  192.     dest->nextc = dest->buf;
  193.     dest->nleft = dest->bufsize;
  194. }
  195.  
  196.  
  197. void
  198. freestdout() {
  199.     INTOFF;
  200.     if (output.buf) {
  201.         ckfree(output.buf);
  202.         output.buf = NULL;
  203.         output.nleft = 0;
  204.     }
  205.     INTON;
  206. }
  207.  
  208.  
  209. #ifdef __STDC__
  210. void
  211. outfmt(struct output *file, char *fmt, ...) {
  212.     va_list ap;
  213.  
  214.     va_start(ap, fmt);
  215.     doformat(file, fmt, ap);
  216.     va_end(ap);
  217. }
  218.  
  219.  
  220. void
  221. out1fmt(char *fmt, ...) {
  222.     va_list ap;
  223.  
  224.     va_start(ap, fmt);
  225.     doformat(out1, fmt, ap);
  226.     va_end(ap);
  227. }
  228.  
  229.  
  230. void
  231. fmtstr(char *outbuf, int length, char *fmt, ...) {
  232.     va_list ap;
  233.     struct output strout;
  234.  
  235.     va_start(ap, fmt);
  236.     strout.nextc = outbuf;
  237.     strout.nleft = length;
  238.     strout.fd = BLOCK_OUT;
  239.     strout.flags = 0;
  240.     doformat(&strout, fmt, ap);
  241.     outc('\0', &strout);
  242.     if (strout.flags & OUTPUT_ERR)
  243.         outbuf[length - 1] = '\0';
  244. }
  245.  
  246. #else /* not __STDC__ */
  247.  
  248. void
  249. outfmt(va_alist)
  250.     va_dcl
  251.     {
  252.     va_list ap;
  253.     struct output *file;
  254.     char *fmt;
  255.  
  256.     va_start(ap);
  257.     file = va_arg(ap, struct output *);
  258.     fmt = va_arg(ap, char *);
  259.     doformat(file, fmt, ap);
  260.     va_end(ap);
  261. }
  262.  
  263.  
  264. void
  265. out1fmt(va_alist)
  266.     va_dcl
  267.     {
  268.     va_list ap;
  269.     char *fmt;
  270.  
  271.     va_start(ap);
  272.     fmt = va_arg(ap, char *);
  273.     doformat(out1, fmt, ap);
  274.     va_end(ap);
  275. }
  276.  
  277.  
  278. void
  279. fmtstr(va_alist)
  280.     va_dcl
  281.     {
  282.     va_list ap;
  283.     struct output strout;
  284.     char *outbuf;
  285.     int length;
  286.     char *fmt;
  287.  
  288.     va_start(ap);
  289.     outbuf = va_arg(ap, char *);
  290.     length = va_arg(ap, int);
  291.     fmt = va_arg(ap, char *);
  292.     strout.nextc = outbuf;
  293.     strout.nleft = length;
  294.     strout.fd = BLOCK_OUT;
  295.     strout.flags = 0;
  296.     doformat(&strout, fmt, ap);
  297.     outc('\0', &strout);
  298.     if (strout.flags & OUTPUT_ERR)
  299.         outbuf[length - 1] = '\0';
  300. }
  301. #endif /* __STDC__ */
  302.  
  303.  
  304. /*
  305.  * Formatted output.  This routine handles a subset of the printf formats:
  306.  * - Formats supported: d, u, o, X, s, and c.
  307.  * - The x format is also accepted but is treated like X.
  308.  * - The l modifier is accepted.
  309.  * - The - and # flags are accepted; # only works with the o format.
  310.  * - Width and precision may be specified with any format except c.
  311.  * - An * may be given for the width or precision.
  312.  * - The obsolete practice of preceding the width with a zero to get
  313.  *   zero padding is not supported; use the precision field.
  314.  * - A % may be printed by writing %% in the format string.
  315.  */
  316.  
  317. #define TEMPSIZE 24
  318.  
  319. #ifdef __STDC__
  320. static const char digit[16] = "0123456789ABCDEF";
  321. #else
  322. static const char digit[17] = "0123456789ABCDEF";
  323. #endif
  324.  
  325.  
  326. void
  327. doformat(dest, f, ap)
  328.     register struct output *dest;
  329.     register char *f;        /* format string */
  330.     va_list ap;
  331.     {
  332.     register char c;
  333.     char temp[TEMPSIZE];
  334.     int flushleft;
  335.     int sharp;
  336.     int width;
  337.     int prec;
  338.     int islong;
  339.     char *p;
  340.     int sign;
  341.     long l;
  342.     unsigned long num;
  343.     unsigned base;
  344.     int len;
  345.     int size;
  346.     int pad;
  347.  
  348.     while ((c = *f++) != '\0') {
  349.         if (c != '%') {
  350.             outc(c, dest);
  351.             continue;
  352.         }
  353.         flushleft = 0;
  354.         sharp = 0;
  355.         width = 0;
  356.         prec = -1;
  357.         islong = 0;
  358.         for (;;) {
  359.             if (*f == '-')
  360.                 flushleft++;
  361.             else if (*f == '#')
  362.                 sharp++;
  363.             else
  364.                 break;
  365.             f++;
  366.         }
  367.         if (*f == '*') {
  368.             width = va_arg(ap, int);
  369.             f++;
  370.         } else {
  371.             while (is_digit(*f)) {
  372.                 width = 10 * width + digit_val(*f++);
  373.             }
  374.         }
  375.         if (*f == '.') {
  376.             if (*++f == '*') {
  377.                 prec = va_arg(ap, int);
  378.                 f++;
  379.             } else {
  380.                 prec = 0;
  381.                 while (is_digit(*f)) {
  382.                     prec = 10 * prec + digit_val(*f++);
  383.                 }
  384.             }
  385.         }
  386.         if (*f == 'l') {
  387.             islong++;
  388.             f++;
  389.         }
  390.         switch (*f) {
  391.         case 'd':
  392.             if (islong)
  393.                 l = va_arg(ap, long);
  394.             else
  395.                 l = va_arg(ap, int);
  396.             sign = 0;
  397.             num = l;
  398.             if (l < 0) {
  399.                 num = -l;
  400.                 sign = 1;
  401.             }
  402.             base = 10;
  403.             goto number;
  404.         case 'u':
  405.             base = 10;
  406.             goto uns_number;
  407.         case 'o':
  408.             base = 8;
  409.             goto uns_number;
  410.         case 'x':
  411.             /* we don't implement 'x'; treat like 'X' */
  412.         case 'X':
  413.             base = 16;
  414. uns_number:      /* an unsigned number */
  415.             sign = 0;
  416.             if (islong)
  417.                 num = va_arg(ap, unsigned long);
  418.             else
  419.                 num = va_arg(ap, unsigned int);
  420. number:          /* process a number */
  421.             p = temp + TEMPSIZE - 1;
  422.             *p = '\0';
  423.             while (num) {
  424.                 *--p = digit[num % base];
  425.                 num /= base;
  426.             }
  427.             len = (temp + TEMPSIZE - 1) - p;
  428.             if (prec < 0)
  429.                 prec = 1;
  430.             if (sharp && *f == 'o' && prec <= len)
  431.                 prec = len + 1;
  432.             pad = 0;
  433.             if (width) {
  434.                 size = len;
  435.                 if (size < prec)
  436.                     size = prec;
  437.                 size += sign;
  438.                 pad = width - size;
  439.                 if (flushleft == 0) {
  440.                     while (--pad >= 0)
  441.                         outc(' ', dest);
  442.                 }
  443.             }
  444.             if (sign)
  445.                 outc('-', dest);
  446.             prec -= len;
  447.             while (--prec >= 0)
  448.                 outc('0', dest);
  449.             while (*p)
  450.                 outc(*p++, dest);
  451.             while (--pad >= 0)
  452.                 outc(' ', dest);
  453.             break;
  454.         case 's':
  455.             p = va_arg(ap, char *);
  456.             pad = 0;
  457.             if (width) {
  458.                 len = strlen(p);
  459.                 if (prec >= 0 && len > prec)
  460.                     len = prec;
  461.                 pad = width - len;
  462.                 if (flushleft == 0) {
  463.                     while (--pad >= 0)
  464.                         outc(' ', dest);
  465.                 }
  466.             }
  467.             prec++;
  468.             while (--prec != 0 && *p)
  469.                 outc(*p++, dest);
  470.             while (--pad >= 0)
  471.                 outc(' ', dest);
  472.             break;
  473.         case 'c':
  474.             c = va_arg(ap, int);
  475.             outc(c, dest);
  476.             break;
  477.         default:
  478.             outc(*f, dest);
  479.             break;
  480.         }
  481.         f++;
  482.     }
  483. }
  484.  
  485.  
  486.  
  487. /*
  488.  * Version of write which resumes after a signal is caught.
  489.  */
  490.  
  491. int
  492. xwrite(fd, buf, nbytes)
  493.     int fd;
  494.     char *buf;
  495.     int nbytes;
  496.     {
  497.     int ntry;
  498.     int i;
  499.     int n;
  500.  
  501.     n = nbytes;
  502.     ntry = 0;
  503.     for (;;) {
  504.         i = write(fd, buf, n);
  505.         if (i > 0) {
  506.             if ((n -= i) <= 0)
  507.                 return nbytes;
  508.             buf += i;
  509.             ntry = 0;
  510.         } else if (i == 0) {
  511.             if (++ntry > 10)
  512.                 return nbytes - n;
  513.         } else if (errno != EINTR) {
  514.             return -1;
  515.         }
  516.     }
  517. }
  518.  
  519.  
  520. /*
  521.  * Version of ioctl that retries after a signal is caught.
  522.  */
  523.  
  524. int
  525. xioctl(fd, request, arg) {
  526.     int i;
  527.  
  528.     while ((i = ioctl(fd, request, arg)) == -1 && errno == EINTR);
  529.     return i;
  530. }
  531.