Replace a home-grown printf() clone with a fwopen() wrapper around
authorPeter Avalos <pavalos@dragonflybsd.org>
Sun, 14 Jan 2007 05:12:40 +0000 (05:12 +0000)
committerPeter Avalos <pavalos@dragonflybsd.org>
Sun, 14 Jan 2007 05:12:40 +0000 (05:12 +0000)
libc's vfprintf() that writes to a `struct output' instead of a file.

Print empty quotes ('') when an empty string is passed to outqstr().
This makes a difference for the trap builtin, where after "trap '' 0" we
printed "trap -- quit".  This is wrong, because an empty action means to reset
the action to the default.  A side effect of this commit is that empty
variables are now printed as "variable=''" instead of just "variable=".

Obtained-from:  FreeBSD

bin/sh/output.c

index fa9eb14..cc1d728 100644 (file)
@@ -34,8 +34,8 @@
  * SUCH DAMAGE.
  *
  * @(#)output.c        8.2 (Berkeley) 5/4/95
- * $FreeBSD: src/bin/sh/output.c,v 1.10.2.2 2002/07/19 04:38:52 tjr Exp $
- * $DragonFly: src/bin/sh/output.c,v 1.3 2003/08/24 16:26:00 drhodus Exp $
+ * $FreeBSD: src/bin/sh/output.c,v 1.20 2005/12/08 21:00:39 stefanf Exp $
+ * $DragonFly: src/bin/sh/output.c,v 1.4 2007/01/14 05:12:40 pavalos Exp $
  */
 
 /*
  *             save the output of the command in a region obtained
  *             via malloc, rather than doing a fork and reading the
  *             output of the command via a pipe.
- *     Our output routines may be smaller than the stdio routines.
  */
 
-#include <sys/types.h>        /* quad_t */
-#include <sys/ioctl.h>
-
 #include <stdio.h>     /* defines BUFSIZ */
 #include <string.h>
 #include <stdarg.h>
@@ -72,6 +68,7 @@
 #define MEM_OUT -3             /* output to dynamically allocated memory */
 #define OUTPUT_ERR 01          /* error occurred on output */
 
+static int doformat_wr(void *, const char *, int);
 
 struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0};
 struct output errout = {NULL, 0, NULL, 100, 2, 0};
@@ -137,6 +134,10 @@ outqstr(const char *p, struct output *file)
 {
        char ch;
 
+       if (p[0] == '\0') {
+               outstr("''", file);
+               return;
+       }
        if (p[strcspn(p, "|&;<>()$`\\\"'")] == '\0' && (!ifsset() ||
            p[strcspn(p, ifsval())] == '\0')) {
                outstr(p, file);
@@ -264,202 +265,46 @@ fmtstr(char *outbuf, int length, const char *fmt, ...)
        va_list ap;
        struct output strout;
 
-       va_start(ap, fmt);
        strout.nextc = outbuf;
        strout.nleft = length;
        strout.fd = BLOCK_OUT;
        strout.flags = 0;
+       va_start(ap, fmt);
        doformat(&strout, fmt, ap);
+       va_end(ap);
        outc('\0', &strout);
        if (strout.flags & OUTPUT_ERR)
                outbuf[length - 1] = '\0';
 }
 
-/*
- * Formatted output.  This routine handles a subset of the printf formats:
- * - Formats supported: d, u, o, X, s, and c.
- * - The x format is also accepted but is treated like X.
- * - The l and q modifiers are accepted.
- * - The - and # flags are accepted; # only works with the o format.
- * - Width and precision may be specified with any format except c.
- * - An * may be given for the width or precision.
- * - The obsolete practice of preceding the width with a zero to get
- *   zero padding is not supported; use the precision field.
- * - A % may be printed by writing %% in the format string.
- */
-
-#define TEMPSIZE 24
-
-static const char digit[] = "0123456789ABCDEF";
+static int
+doformat_wr(void *cookie, const char *buf, int len)
+{
+       struct output *o;
+       int origlen;
+       unsigned char c;
+
+       o = (struct output *)cookie;
+       origlen = len;
+       while (len-- != 0) {
+               c = (unsigned char)*buf++;
+               outc(c, o);
+       }
 
+       return (origlen);
+}
 
 void
 doformat(struct output *dest, const char *f, va_list ap)
 {
-       char c;
-       char temp[TEMPSIZE];
-       int flushleft;
-       int sharp;
-       int width;
-       int prec;
-       int islong;
-       int isquad;
-       char *p;
-       int sign;
-       quad_t l;
-       u_quad_t num;
-       unsigned base;
-       int len;
-       int size;
-       int pad;
-
-       while ((c = *f++) != '\0') {
-               if (c != '%') {
-                       outc(c, dest);
-                       continue;
-               }
-               flushleft = 0;
-               sharp = 0;
-               width = 0;
-               prec = -1;
-               islong = 0;
-               isquad = 0;
-               for (;;) {
-                       if (*f == '-')
-                               flushleft++;
-                       else if (*f == '#')
-                               sharp++;
-                       else
-                               break;
-                       f++;
-               }
-               if (*f == '*') {
-                       width = va_arg(ap, int);
-                       f++;
-               } else {
-                       while (is_digit(*f)) {
-                               width = 10 * width + digit_val(*f++);
-                       }
-               }
-               if (*f == '.') {
-                       if (*++f == '*') {
-                               prec = va_arg(ap, int);
-                               f++;
-                       } else {
-                               prec = 0;
-                               while (is_digit(*f)) {
-                                       prec = 10 * prec + digit_val(*f++);
-                               }
-                       }
-               }
-               if (*f == 'l') {
-                       islong++;
-                       f++;
-               } else if (*f == 'q') {
-                       isquad++;
-                       f++;
-               }
-               switch (*f) {
-               case 'd':
-                       if (isquad)
-                               l = va_arg(ap, quad_t);
-                       else if (islong)
-                               l = va_arg(ap, long);
-                       else
-                               l = va_arg(ap, int);
-                       sign = 0;
-                       num = l;
-                       if (l < 0) {
-                               num = -l;
-                               sign = 1;
-                       }
-                       base = 10;
-                       goto number;
-               case 'u':
-                       base = 10;
-                       goto uns_number;
-               case 'o':
-                       base = 8;
-                       goto uns_number;
-               case 'x':
-                       /* we don't implement 'x'; treat like 'X' */
-               case 'X':
-                       base = 16;
-uns_number:      /* an unsigned number */
-                       sign = 0;
-                       if (isquad)
-                               num = va_arg(ap, u_quad_t);
-                       else if (islong)
-                               num = va_arg(ap, unsigned long);
-                       else
-                               num = va_arg(ap, unsigned int);
-number:                  /* process a number */
-                       p = temp + TEMPSIZE - 1;
-                       *p = '\0';
-                       while (num) {
-                               *--p = digit[num % base];
-                               num /= base;
-                       }
-                       len = (temp + TEMPSIZE - 1) - p;
-                       if (prec < 0)
-                               prec = 1;
-                       if (sharp && *f == 'o' && prec <= len)
-                               prec = len + 1;
-                       pad = 0;
-                       if (width) {
-                               size = len;
-                               if (size < prec)
-                                       size = prec;
-                               size += sign;
-                               pad = width - size;
-                               if (flushleft == 0) {
-                                       while (--pad >= 0)
-                                               outc(' ', dest);
-                               }
-                       }
-                       if (sign)
-                               outc('-', dest);
-                       prec -= len;
-                       while (--prec >= 0)
-                               outc('0', dest);
-                       while (*p)
-                               outc(*p++, dest);
-                       while (--pad >= 0)
-                               outc(' ', dest);
-                       break;
-               case 's':
-                       p = va_arg(ap, char *);
-                       pad = 0;
-                       if (width) {
-                               len = strlen(p);
-                               if (prec >= 0 && len > prec)
-                                       len = prec;
-                               pad = width - len;
-                               if (flushleft == 0) {
-                                       while (--pad >= 0)
-                                               outc(' ', dest);
-                               }
-                       }
-                       prec++;
-                       while (--prec != 0 && *p)
-                               outc(*p++, dest);
-                       while (--pad >= 0)
-                               outc(' ', dest);
-                       break;
-               case 'c':
-                       c = va_arg(ap, int);
-                       outc(c, dest);
-                       break;
-               default:
-                       outc(*f, dest);
-                       break;
-               }
-               f++;
+       FILE *fp;
+
+       if ((fp = fwopen(dest, doformat_wr)) != NULL) {
+               vfprintf(fp, f, ap);
+               fclose(fp);
        }
 }
 
-
-
 /*
  * Version of write which resumes after a signal is caught.
  */