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