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