1 1.42 rillig /* $NetBSD: output.c,v 1.42 2024/10/03 20:14:01 rillig Exp $ */ 2 1.13 cgd 3 1.1 cgd /*- 4 1.7 jtc * Copyright (c) 1991, 1993 5 1.7 jtc * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * This code is derived from software contributed to Berkeley by 8 1.1 cgd * Kenneth Almquist. 9 1.1 cgd * 10 1.1 cgd * Redistribution and use in source and binary forms, with or without 11 1.1 cgd * modification, are permitted provided that the following conditions 12 1.1 cgd * are met: 13 1.1 cgd * 1. Redistributions of source code must retain the above copyright 14 1.1 cgd * notice, this list of conditions and the following disclaimer. 15 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 cgd * notice, this list of conditions and the following disclaimer in the 17 1.1 cgd * documentation and/or other materials provided with the distribution. 18 1.28 agc * 3. Neither the name of the University nor the names of its contributors 19 1.1 cgd * may be used to endorse or promote products derived from this software 20 1.1 cgd * without specific prior written permission. 21 1.1 cgd * 22 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 1.1 cgd * SUCH DAMAGE. 33 1.1 cgd */ 34 1.1 cgd 35 1.19 christos #include <sys/cdefs.h> 36 1.1 cgd #ifndef lint 37 1.13 cgd #if 0 38 1.14 christos static char sccsid[] = "@(#)output.c 8.2 (Berkeley) 5/4/95"; 39 1.13 cgd #else 40 1.42 rillig __RCSID("$NetBSD: output.c,v 1.42 2024/10/03 20:14:01 rillig Exp $"); 41 1.13 cgd #endif 42 1.1 cgd #endif /* not lint */ 43 1.1 cgd 44 1.1 cgd /* 45 1.1 cgd * Shell output routines. We use our own output routines because: 46 1.1 cgd * When a builtin command is interrupted we have to discard 47 1.1 cgd * any pending output. 48 1.1 cgd * When a builtin command appears in back quotes, we want to 49 1.1 cgd * save the output of the command in a region obtained 50 1.1 cgd * via malloc, rather than doing a fork and reading the 51 1.1 cgd * output of the command via a pipe. 52 1.1 cgd * Our output routines may be smaller than the stdio routines. 53 1.1 cgd */ 54 1.1 cgd 55 1.20 christos #include <sys/types.h> /* quad_t */ 56 1.20 christos #include <sys/param.h> /* BSD4_4 */ 57 1.11 cgd #include <sys/ioctl.h> 58 1.11 cgd 59 1.1 cgd #include <stdio.h> /* defines BUFSIZ */ 60 1.12 cgd #include <string.h> 61 1.1 cgd #include <errno.h> 62 1.9 jtc #include <unistd.h> 63 1.14 christos #include <stdlib.h> 64 1.14 christos 65 1.14 christos #include "shell.h" 66 1.14 christos #include "syntax.h" 67 1.14 christos #include "output.h" 68 1.14 christos #include "memalloc.h" 69 1.14 christos #include "error.h" 70 1.39 kre #include "redir.h" 71 1.39 kre #include "options.h" 72 1.39 kre #include "show.h" 73 1.1 cgd 74 1.1 cgd 75 1.1 cgd #define OUTBUFSIZ BUFSIZ 76 1.1 cgd #define BLOCK_OUT -2 /* output to a fixed block of memory */ 77 1.1 cgd #define MEM_OUT -3 /* output to dynamically allocated memory */ 78 1.1 cgd 79 1.40 kre #ifdef SMALL 80 1.40 kre #define CHAIN 81 1.40 kre #else 82 1.40 kre #define CHAIN ,NULL 83 1.40 kre #endif 84 1.40 kre 85 1.1 cgd 86 1.39 kre /* nextc nleft bufsize buf fd flags chain */ 87 1.40 kre struct output output = {NULL, 0, OUTBUFSIZ, NULL, 1, 0 CHAIN }; 88 1.40 kre struct output errout = {NULL, 0, 100, NULL, 2, 0 CHAIN }; 89 1.40 kre struct output memout = {NULL, 0, 0, NULL, MEM_OUT, 0 CHAIN }; 90 1.1 cgd struct output *out1 = &output; 91 1.1 cgd struct output *out2 = &errout; 92 1.40 kre #ifndef SMALL 93 1.39 kre struct output *outx = &errout; 94 1.39 kre struct output *outxtop = NULL; 95 1.40 kre #endif 96 1.1 cgd 97 1.1 cgd 98 1.1 cgd #ifdef mkinit 99 1.1 cgd 100 1.1 cgd INCLUDE "output.h" 101 1.1 cgd INCLUDE "memalloc.h" 102 1.1 cgd 103 1.1 cgd RESET { 104 1.1 cgd out1 = &output; 105 1.1 cgd out2 = &errout; 106 1.1 cgd if (memout.buf != NULL) { 107 1.1 cgd ckfree(memout.buf); 108 1.1 cgd memout.buf = NULL; 109 1.1 cgd } 110 1.1 cgd } 111 1.1 cgd 112 1.1 cgd #endif 113 1.1 cgd 114 1.1 cgd 115 1.1 cgd #ifdef notdef /* no longer used */ 116 1.1 cgd /* 117 1.1 cgd * Set up an output file to write to memory rather than a file. 118 1.1 cgd */ 119 1.1 cgd 120 1.1 cgd void 121 1.27 christos open_mem(char *block, int length, struct output *file) 122 1.27 christos { 123 1.1 cgd file->nextc = block; 124 1.1 cgd file->nleft = --length; 125 1.1 cgd file->fd = BLOCK_OUT; 126 1.1 cgd file->flags = 0; 127 1.1 cgd } 128 1.1 cgd #endif 129 1.1 cgd 130 1.1 cgd 131 1.1 cgd void 132 1.27 christos out1str(const char *p) 133 1.27 christos { 134 1.1 cgd outstr(p, out1); 135 1.1 cgd } 136 1.1 cgd 137 1.1 cgd 138 1.1 cgd void 139 1.27 christos out2str(const char *p) 140 1.27 christos { 141 1.1 cgd outstr(p, out2); 142 1.1 cgd } 143 1.1 cgd 144 1.40 kre #ifndef SMALL 145 1.39 kre void 146 1.39 kre outxstr(const char *p) 147 1.39 kre { 148 1.39 kre outstr(p, outx); 149 1.39 kre } 150 1.40 kre #endif 151 1.39 kre 152 1.1 cgd 153 1.1 cgd void 154 1.27 christos outstr(const char *p, struct output *file) 155 1.27 christos { 156 1.39 kre char c = 0; 157 1.39 kre 158 1.1 cgd while (*p) 159 1.39 kre outc((c = *p++), file); 160 1.39 kre if (file == out2 || (file == outx && c == '\n')) 161 1.7 jtc flushout(file); 162 1.1 cgd } 163 1.1 cgd 164 1.1 cgd 165 1.31 christos void 166 1.31 christos out2shstr(const char *p) 167 1.31 christos { 168 1.31 christos outshstr(p, out2); 169 1.31 christos } 170 1.31 christos 171 1.40 kre #ifndef SMALL 172 1.39 kre void 173 1.39 kre outxshstr(const char *p) 174 1.39 kre { 175 1.39 kre outshstr(p, outx); 176 1.39 kre } 177 1.40 kre #endif 178 1.31 christos 179 1.37 kre /* 180 1.37 kre * ' is in this list, not because it does not require quoting 181 1.37 kre * (which applies to all the others) but because '' quoting cannot 182 1.37 kre * be used to quote it. 183 1.37 kre */ 184 1.35 christos static const char norm_chars [] = \ 185 1.36 kre "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/+-=_,.'"; 186 1.35 christos 187 1.35 christos static int 188 1.35 christos inquote(const char *p) 189 1.35 christos { 190 1.35 christos size_t l = strspn(p, norm_chars); 191 1.42 rillig const char *s = strchr(p, '\''); 192 1.35 christos 193 1.35 christos return s == NULL ? p[l] != '\0' : s - p > (off_t)l; 194 1.35 christos } 195 1.35 christos 196 1.31 christos void 197 1.31 christos outshstr(const char *p, struct output *file) 198 1.31 christos { 199 1.37 kre int need_q; 200 1.35 christos int inq; 201 1.31 christos char c; 202 1.31 christos 203 1.37 kre if (strchr(p, '\'') != NULL && p[1] != '\0') { 204 1.37 kre /* 205 1.37 kre * string contains ' in it, and is not only the ' 206 1.37 kre * see if " quoting will work 207 1.37 kre */ 208 1.37 kre size_t i = strcspn(p, "\\\"$`"); 209 1.37 kre 210 1.37 kre if (p[i] == '\0') { 211 1.37 kre /* 212 1.37 kre * string contains no $ ` \ or " chars, perfect... 213 1.37 kre * 214 1.37 kre * We know it contains ' so needs quoting, so 215 1.37 kre * this is easy... 216 1.37 kre */ 217 1.37 kre outc('"', file); 218 1.37 kre outstr(p, file); 219 1.37 kre outc('"', file); 220 1.37 kre return; 221 1.37 kre } 222 1.37 kre } 223 1.37 kre 224 1.37 kre need_q = p[0] == 0 || p[strspn(p, norm_chars)] != 0; 225 1.37 kre 226 1.35 christos /* 227 1.35 christos * Don't emit ' unless something needs quoting before closing ' 228 1.35 christos */ 229 1.37 kre if (need_q && (p[0] == 0 || inquote(p) != 0)) { 230 1.37 kre outc('\'', file); 231 1.37 kre inq = 1; 232 1.35 christos } else 233 1.35 christos inq = 0; 234 1.31 christos 235 1.35 christos while ((c = *p++) != '\0') { 236 1.35 christos if (c != '\'') { 237 1.31 christos outc(c, file); 238 1.35 christos continue; 239 1.31 christos } 240 1.35 christos 241 1.35 christos if (inq) 242 1.35 christos outc('\'', file); /* inq = 0, implicit */ 243 1.35 christos outc('\\', file); 244 1.35 christos outc(c, file); 245 1.35 christos if (need_q && *p != '\0') { 246 1.35 christos if ((inq = inquote(p)) != 0) 247 1.35 christos outc('\'', file); 248 1.35 christos } else 249 1.35 christos inq = 0; 250 1.31 christos } 251 1.31 christos 252 1.35 christos if (inq) 253 1.31 christos outc('\'', file); 254 1.31 christos 255 1.31 christos if (file == out2) 256 1.31 christos flushout(file); 257 1.31 christos } 258 1.31 christos 259 1.31 christos 260 1.1 cgd char out_junk[16]; 261 1.1 cgd 262 1.1 cgd 263 1.1 cgd void 264 1.27 christos emptyoutbuf(struct output *dest) 265 1.27 christos { 266 1.1 cgd int offset; 267 1.1 cgd 268 1.1 cgd if (dest->fd == BLOCK_OUT) { 269 1.1 cgd dest->nextc = out_junk; 270 1.1 cgd dest->nleft = sizeof out_junk; 271 1.1 cgd dest->flags |= OUTPUT_ERR; 272 1.1 cgd } else if (dest->buf == NULL) { 273 1.1 cgd INTOFF; 274 1.1 cgd dest->buf = ckmalloc(dest->bufsize); 275 1.1 cgd dest->nextc = dest->buf; 276 1.1 cgd dest->nleft = dest->bufsize; 277 1.1 cgd INTON; 278 1.39 kre VTRACE(DBG_OUTPUT, ("emptyoutbuf now %d @%p for fd %d\n", 279 1.39 kre dest->nleft, dest->buf, dest->fd)); 280 1.1 cgd } else if (dest->fd == MEM_OUT) { 281 1.1 cgd offset = dest->bufsize; 282 1.1 cgd INTOFF; 283 1.1 cgd dest->bufsize <<= 1; 284 1.1 cgd dest->buf = ckrealloc(dest->buf, dest->bufsize); 285 1.1 cgd dest->nleft = dest->bufsize - offset; 286 1.1 cgd dest->nextc = dest->buf + offset; 287 1.1 cgd INTON; 288 1.1 cgd } else { 289 1.1 cgd flushout(dest); 290 1.1 cgd } 291 1.1 cgd dest->nleft--; 292 1.1 cgd } 293 1.1 cgd 294 1.1 cgd 295 1.1 cgd void 296 1.27 christos flushall(void) 297 1.27 christos { 298 1.1 cgd flushout(&output); 299 1.1 cgd flushout(&errout); 300 1.1 cgd } 301 1.1 cgd 302 1.1 cgd 303 1.1 cgd void 304 1.27 christos flushout(struct output *dest) 305 1.27 christos { 306 1.1 cgd 307 1.1 cgd if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0) 308 1.1 cgd return; 309 1.39 kre VTRACE(DBG_OUTPUT, ("flushout fd=%d %zd to write\n", dest->fd, 310 1.39 kre (size_t)(dest->nextc - dest->buf))); 311 1.1 cgd if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0) 312 1.1 cgd dest->flags |= OUTPUT_ERR; 313 1.1 cgd dest->nextc = dest->buf; 314 1.1 cgd dest->nleft = dest->bufsize; 315 1.1 cgd } 316 1.1 cgd 317 1.1 cgd 318 1.1 cgd void 319 1.27 christos freestdout(void) 320 1.27 christos { 321 1.1 cgd INTOFF; 322 1.1 cgd if (output.buf) { 323 1.1 cgd ckfree(output.buf); 324 1.1 cgd output.buf = NULL; 325 1.1 cgd output.nleft = 0; 326 1.1 cgd } 327 1.1 cgd INTON; 328 1.1 cgd } 329 1.1 cgd 330 1.1 cgd 331 1.21 christos void 332 1.21 christos outfmt(struct output *file, const char *fmt, ...) 333 1.21 christos { 334 1.1 cgd va_list ap; 335 1.1 cgd 336 1.21 christos va_start(ap, fmt); 337 1.1 cgd doformat(file, fmt, ap); 338 1.1 cgd va_end(ap); 339 1.1 cgd } 340 1.1 cgd 341 1.1 cgd 342 1.1 cgd void 343 1.21 christos out1fmt(const char *fmt, ...) 344 1.21 christos { 345 1.1 cgd va_list ap; 346 1.1 cgd 347 1.21 christos va_start(ap, fmt); 348 1.1 cgd doformat(out1, fmt, ap); 349 1.1 cgd va_end(ap); 350 1.1 cgd } 351 1.1 cgd 352 1.33 christos #ifdef DEBUG 353 1.7 jtc void 354 1.33 christos debugprintf(const char *fmt, ...) 355 1.21 christos { 356 1.7 jtc va_list ap; 357 1.7 jtc 358 1.21 christos va_start(ap, fmt); 359 1.7 jtc doformat(out2, fmt, ap); 360 1.7 jtc va_end(ap); 361 1.7 jtc flushout(out2); 362 1.7 jtc } 363 1.33 christos #endif 364 1.1 cgd 365 1.1 cgd void 366 1.21 christos fmtstr(char *outbuf, size_t length, const char *fmt, ...) 367 1.21 christos { 368 1.1 cgd va_list ap; 369 1.1 cgd struct output strout; 370 1.26 wiz 371 1.21 christos va_start(ap, fmt); 372 1.1 cgd strout.nextc = outbuf; 373 1.1 cgd strout.nleft = length; 374 1.1 cgd strout.fd = BLOCK_OUT; 375 1.1 cgd strout.flags = 0; 376 1.1 cgd doformat(&strout, fmt, ap); 377 1.1 cgd outc('\0', &strout); 378 1.1 cgd if (strout.flags & OUTPUT_ERR) 379 1.1 cgd outbuf[length - 1] = '\0'; 380 1.24 wiz va_end(ap); 381 1.1 cgd } 382 1.1 cgd 383 1.1 cgd /* 384 1.1 cgd * Formatted output. This routine handles a subset of the printf formats: 385 1.21 christos * - Formats supported: d, u, o, p, X, s, and c. 386 1.1 cgd * - The x format is also accepted but is treated like X. 387 1.22 lukem * - The l, ll and q modifiers are accepted. 388 1.1 cgd * - The - and # flags are accepted; # only works with the o format. 389 1.1 cgd * - Width and precision may be specified with any format except c. 390 1.1 cgd * - An * may be given for the width or precision. 391 1.1 cgd * - The obsolete practice of preceding the width with a zero to get 392 1.1 cgd * zero padding is not supported; use the precision field. 393 1.1 cgd * - A % may be printed by writing %% in the format string. 394 1.1 cgd */ 395 1.1 cgd 396 1.1 cgd #define TEMPSIZE 24 397 1.1 cgd 398 1.23 lukem #ifdef BSD4_4 399 1.23 lukem #define HAVE_VASPRINTF 1 400 1.23 lukem #endif 401 1.23 lukem 402 1.1 cgd void 403 1.27 christos doformat(struct output *dest, const char *f, va_list ap) 404 1.23 lukem { 405 1.23 lukem #if HAVE_VASPRINTF 406 1.23 lukem char *s; 407 1.23 lukem 408 1.23 lukem vasprintf(&s, f, ap); 409 1.29 rumble if (s == NULL) 410 1.29 rumble error("Could not allocate formatted output buffer"); 411 1.23 lukem outstr(s, dest); 412 1.41 kre free(s); 413 1.23 lukem #else /* !HAVE_VASPRINTF */ 414 1.25 thorpej static const char digit[] = "0123456789ABCDEF"; 415 1.17 tls char c; 416 1.1 cgd char temp[TEMPSIZE]; 417 1.1 cgd int flushleft; 418 1.1 cgd int sharp; 419 1.1 cgd int width; 420 1.1 cgd int prec; 421 1.1 cgd int islong; 422 1.15 jtc int isquad; 423 1.1 cgd char *p; 424 1.1 cgd int sign; 425 1.18 christos #ifdef BSD4_4 426 1.15 jtc quad_t l; 427 1.15 jtc u_quad_t num; 428 1.18 christos #else 429 1.18 christos long l; 430 1.18 christos u_long num; 431 1.18 christos #endif 432 1.1 cgd unsigned base; 433 1.1 cgd int len; 434 1.1 cgd int size; 435 1.1 cgd int pad; 436 1.1 cgd 437 1.1 cgd while ((c = *f++) != '\0') { 438 1.1 cgd if (c != '%') { 439 1.1 cgd outc(c, dest); 440 1.1 cgd continue; 441 1.1 cgd } 442 1.1 cgd flushleft = 0; 443 1.1 cgd sharp = 0; 444 1.1 cgd width = 0; 445 1.1 cgd prec = -1; 446 1.1 cgd islong = 0; 447 1.15 jtc isquad = 0; 448 1.1 cgd for (;;) { 449 1.1 cgd if (*f == '-') 450 1.1 cgd flushleft++; 451 1.1 cgd else if (*f == '#') 452 1.1 cgd sharp++; 453 1.1 cgd else 454 1.1 cgd break; 455 1.1 cgd f++; 456 1.1 cgd } 457 1.1 cgd if (*f == '*') { 458 1.1 cgd width = va_arg(ap, int); 459 1.1 cgd f++; 460 1.1 cgd } else { 461 1.1 cgd while (is_digit(*f)) { 462 1.1 cgd width = 10 * width + digit_val(*f++); 463 1.1 cgd } 464 1.1 cgd } 465 1.1 cgd if (*f == '.') { 466 1.1 cgd if (*++f == '*') { 467 1.1 cgd prec = va_arg(ap, int); 468 1.1 cgd f++; 469 1.1 cgd } else { 470 1.1 cgd prec = 0; 471 1.1 cgd while (is_digit(*f)) { 472 1.1 cgd prec = 10 * prec + digit_val(*f++); 473 1.1 cgd } 474 1.1 cgd } 475 1.1 cgd } 476 1.1 cgd if (*f == 'l') { 477 1.1 cgd f++; 478 1.22 lukem if (*f == 'l') { 479 1.22 lukem isquad++; 480 1.22 lukem f++; 481 1.22 lukem } else 482 1.22 lukem islong++; 483 1.15 jtc } else if (*f == 'q') { 484 1.15 jtc isquad++; 485 1.15 jtc f++; 486 1.1 cgd } 487 1.1 cgd switch (*f) { 488 1.1 cgd case 'd': 489 1.18 christos #ifdef BSD4_4 490 1.15 jtc if (isquad) 491 1.15 jtc l = va_arg(ap, quad_t); 492 1.18 christos else 493 1.18 christos #endif 494 1.18 christos if (islong) 495 1.1 cgd l = va_arg(ap, long); 496 1.1 cgd else 497 1.1 cgd l = va_arg(ap, int); 498 1.1 cgd sign = 0; 499 1.1 cgd num = l; 500 1.1 cgd if (l < 0) { 501 1.1 cgd num = -l; 502 1.1 cgd sign = 1; 503 1.1 cgd } 504 1.1 cgd base = 10; 505 1.1 cgd goto number; 506 1.1 cgd case 'u': 507 1.1 cgd base = 10; 508 1.1 cgd goto uns_number; 509 1.1 cgd case 'o': 510 1.1 cgd base = 8; 511 1.1 cgd goto uns_number; 512 1.21 christos case 'p': 513 1.21 christos outc('0', dest); 514 1.21 christos outc('x', dest); 515 1.21 christos /*FALLTHROUGH*/ 516 1.1 cgd case 'x': 517 1.1 cgd /* we don't implement 'x'; treat like 'X' */ 518 1.1 cgd case 'X': 519 1.1 cgd base = 16; 520 1.1 cgd uns_number: /* an unsigned number */ 521 1.1 cgd sign = 0; 522 1.18 christos #ifdef BSD4_4 523 1.15 jtc if (isquad) 524 1.15 jtc num = va_arg(ap, u_quad_t); 525 1.18 christos else 526 1.18 christos #endif 527 1.18 christos if (islong) 528 1.1 cgd num = va_arg(ap, unsigned long); 529 1.1 cgd else 530 1.1 cgd num = va_arg(ap, unsigned int); 531 1.1 cgd number: /* process a number */ 532 1.1 cgd p = temp + TEMPSIZE - 1; 533 1.1 cgd *p = '\0'; 534 1.1 cgd while (num) { 535 1.1 cgd *--p = digit[num % base]; 536 1.1 cgd num /= base; 537 1.1 cgd } 538 1.1 cgd len = (temp + TEMPSIZE - 1) - p; 539 1.1 cgd if (prec < 0) 540 1.1 cgd prec = 1; 541 1.1 cgd if (sharp && *f == 'o' && prec <= len) 542 1.1 cgd prec = len + 1; 543 1.1 cgd pad = 0; 544 1.1 cgd if (width) { 545 1.1 cgd size = len; 546 1.1 cgd if (size < prec) 547 1.1 cgd size = prec; 548 1.1 cgd size += sign; 549 1.1 cgd pad = width - size; 550 1.1 cgd if (flushleft == 0) { 551 1.1 cgd while (--pad >= 0) 552 1.1 cgd outc(' ', dest); 553 1.1 cgd } 554 1.1 cgd } 555 1.1 cgd if (sign) 556 1.1 cgd outc('-', dest); 557 1.1 cgd prec -= len; 558 1.1 cgd while (--prec >= 0) 559 1.1 cgd outc('0', dest); 560 1.1 cgd while (*p) 561 1.1 cgd outc(*p++, dest); 562 1.1 cgd while (--pad >= 0) 563 1.1 cgd outc(' ', dest); 564 1.1 cgd break; 565 1.1 cgd case 's': 566 1.1 cgd p = va_arg(ap, char *); 567 1.1 cgd pad = 0; 568 1.1 cgd if (width) { 569 1.1 cgd len = strlen(p); 570 1.1 cgd if (prec >= 0 && len > prec) 571 1.1 cgd len = prec; 572 1.1 cgd pad = width - len; 573 1.1 cgd if (flushleft == 0) { 574 1.1 cgd while (--pad >= 0) 575 1.1 cgd outc(' ', dest); 576 1.1 cgd } 577 1.1 cgd } 578 1.1 cgd prec++; 579 1.1 cgd while (--prec != 0 && *p) 580 1.1 cgd outc(*p++, dest); 581 1.1 cgd while (--pad >= 0) 582 1.1 cgd outc(' ', dest); 583 1.1 cgd break; 584 1.1 cgd case 'c': 585 1.1 cgd c = va_arg(ap, int); 586 1.1 cgd outc(c, dest); 587 1.1 cgd break; 588 1.1 cgd default: 589 1.1 cgd outc(*f, dest); 590 1.1 cgd break; 591 1.1 cgd } 592 1.1 cgd f++; 593 1.1 cgd } 594 1.23 lukem #endif /* !HAVE_VASPRINTF */ 595 1.1 cgd } 596 1.1 cgd 597 1.1 cgd 598 1.1 cgd 599 1.1 cgd /* 600 1.1 cgd * Version of write which resumes after a signal is caught. 601 1.1 cgd */ 602 1.1 cgd 603 1.1 cgd int 604 1.27 christos xwrite(int fd, char *buf, int nbytes) 605 1.27 christos { 606 1.1 cgd int ntry; 607 1.1 cgd int i; 608 1.1 cgd int n; 609 1.1 cgd 610 1.1 cgd n = nbytes; 611 1.1 cgd ntry = 0; 612 1.34 christos while (n > 0) { 613 1.1 cgd i = write(fd, buf, n); 614 1.1 cgd if (i > 0) { 615 1.1 cgd if ((n -= i) <= 0) 616 1.1 cgd return nbytes; 617 1.1 cgd buf += i; 618 1.1 cgd ntry = 0; 619 1.1 cgd } else if (i == 0) { 620 1.1 cgd if (++ntry > 10) 621 1.1 cgd return nbytes - n; 622 1.1 cgd } else if (errno != EINTR) { 623 1.1 cgd return -1; 624 1.1 cgd } 625 1.1 cgd } 626 1.34 christos return nbytes; 627 1.1 cgd } 628 1.1 cgd 629 1.40 kre #ifndef SMALL 630 1.39 kre static void 631 1.39 kre xtrace_fd_swap(int from, int to) 632 1.39 kre { 633 1.39 kre struct output *o = outxtop; 634 1.39 kre 635 1.39 kre while (o != NULL) { 636 1.39 kre if (o->fd == from) 637 1.39 kre o->fd = to; 638 1.39 kre o = o->chain; 639 1.39 kre } 640 1.39 kre } 641 1.39 kre 642 1.39 kre /* 643 1.39 kre * the -X flag is to be set or reset (not necessarily changed) 644 1.39 kre * Do what is needed to make tracing go to where it should 645 1.39 kre * 646 1.39 kre * Note: Xflag has not yet been altered, "on" indicates what it will become 647 1.39 kre */ 648 1.39 kre 649 1.39 kre void 650 1.39 kre xtracefdsetup(int on) 651 1.39 kre { 652 1.39 kre if (!on) { 653 1.39 kre flushout(outx); 654 1.39 kre 655 1.39 kre if (Xflag != 1) /* Was already +X */ 656 1.39 kre return; /* so nothing to do */ 657 1.39 kre 658 1.39 kre outx = out2; 659 1.39 kre CTRACE(DBG_OUTPUT, ("Tracing to stderr\n")); 660 1.39 kre return; 661 1.39 kre } 662 1.39 kre 663 1.39 kre if (Xflag == 1) { /* was already set */ 664 1.39 kre /* 665 1.39 kre * This is a change of output file only 666 1.39 kre * Just close the current one, and reuse the struct output 667 1.39 kre */ 668 1.39 kre if (!(outx->flags & OUTPUT_CLONE)) 669 1.39 kre sh_close(outx->fd); 670 1.39 kre } else if (outxtop == NULL) { 671 1.39 kre /* 672 1.39 kre * -X is just turning on, for the forst time, 673 1.39 kre * need a new output struct to become outx 674 1.39 kre */ 675 1.39 kre xtrace_clone(1); 676 1.39 kre } else 677 1.39 kre outx = outxtop; 678 1.39 kre 679 1.39 kre if (outx != out2) { 680 1.39 kre outx->flags &= ~OUTPUT_CLONE; 681 1.39 kre outx->fd = to_upper_fd(dup(out2->fd)); 682 1.39 kre register_sh_fd(outx->fd, xtrace_fd_swap); 683 1.39 kre } 684 1.39 kre 685 1.39 kre CTRACE(DBG_OUTPUT, ("Tracing now to fd %d (from %d)\n", 686 1.39 kre outx->fd, out2->fd)); 687 1.39 kre } 688 1.39 kre 689 1.39 kre void 690 1.39 kre xtrace_clone(int new) 691 1.39 kre { 692 1.39 kre struct output *o; 693 1.39 kre 694 1.39 kre CTRACE(DBG_OUTPUT, 695 1.39 kre ("xtrace_clone(%d): %sfd=%d buf=%p nleft=%d flags=%x ", 696 1.39 kre new, (outx == out2 ? "out2: " : ""), 697 1.39 kre outx->fd, outx->buf, outx->nleft, outx->flags)); 698 1.39 kre 699 1.39 kre flushout(outx); 700 1.39 kre 701 1.39 kre if (!new && outxtop == NULL && Xflag == 0) { 702 1.39 kre /* following stderr, nothing to save */ 703 1.39 kre CTRACE(DBG_OUTPUT, ("+X\n")); 704 1.39 kre return; 705 1.39 kre } 706 1.39 kre 707 1.39 kre o = ckmalloc(sizeof(*o)); 708 1.39 kre o->fd = outx->fd; 709 1.39 kre o->flags = OUTPUT_CLONE; 710 1.39 kre o->bufsize = outx->bufsize; 711 1.39 kre o->nleft = 0; 712 1.39 kre o->buf = NULL; 713 1.39 kre o->nextc = NULL; 714 1.39 kre o->chain = outxtop; 715 1.39 kre outx = o; 716 1.39 kre outxtop = o; 717 1.39 kre 718 1.39 kre CTRACE(DBG_OUTPUT, ("-> fd=%d flags=%x[CLONE]\n", outx->fd, o->flags)); 719 1.39 kre } 720 1.39 kre 721 1.39 kre void 722 1.39 kre xtrace_pop(void) 723 1.39 kre { 724 1.39 kre struct output *o; 725 1.39 kre 726 1.39 kre CTRACE(DBG_OUTPUT, ("trace_pop: fd=%d buf=%p nleft=%d flags=%x ", 727 1.39 kre outx->fd, outx->buf, outx->nleft, outx->flags)); 728 1.39 kre 729 1.39 kre flushout(outx); 730 1.39 kre 731 1.39 kre if (outxtop == NULL) { 732 1.39 kre /* 733 1.39 kre * No -X has been used, so nothing much to do 734 1.39 kre */ 735 1.39 kre CTRACE(DBG_OUTPUT, ("+X\n")); 736 1.39 kre return; 737 1.39 kre } 738 1.39 kre 739 1.39 kre o = outxtop; 740 1.39 kre outx = o->chain; 741 1.39 kre if (outx == NULL) 742 1.39 kre outx = &errout; 743 1.39 kre outxtop = o->chain; 744 1.39 kre if (o != &errout) { 745 1.39 kre if (o->fd >= 0 && !(o->flags & OUTPUT_CLONE)) 746 1.39 kre sh_close(o->fd); 747 1.39 kre if (o->buf) 748 1.39 kre ckfree(o->buf); 749 1.39 kre ckfree(o); 750 1.39 kre } 751 1.39 kre 752 1.39 kre CTRACE(DBG_OUTPUT, ("-> fd=%d buf=%p nleft=%d flags=%x\n", 753 1.39 kre outx->fd, outx->buf, outx->nleft, outx->flags)); 754 1.39 kre } 755 1.40 kre #endif /* SMALL */ 756