Subversion Repositories HelenOS

Rev

Rev 2714 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

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