1*d47295ccSrillig /* $NetBSD: output.c,v 1.42 2024/10/03 20:14:01 rillig Exp $ */ 249f0ad86Scgd 361f28255Scgd /*- 437ed7877Sjtc * Copyright (c) 1991, 1993 537ed7877Sjtc * The Regents of the University of California. All rights reserved. 661f28255Scgd * 761f28255Scgd * This code is derived from software contributed to Berkeley by 861f28255Scgd * Kenneth Almquist. 961f28255Scgd * 1061f28255Scgd * Redistribution and use in source and binary forms, with or without 1161f28255Scgd * modification, are permitted provided that the following conditions 1261f28255Scgd * are met: 1361f28255Scgd * 1. Redistributions of source code must retain the above copyright 1461f28255Scgd * notice, this list of conditions and the following disclaimer. 1561f28255Scgd * 2. Redistributions in binary form must reproduce the above copyright 1661f28255Scgd * notice, this list of conditions and the following disclaimer in the 1761f28255Scgd * documentation and/or other materials provided with the distribution. 18b5b29542Sagc * 3. Neither the name of the University nor the names of its contributors 1961f28255Scgd * may be used to endorse or promote products derived from this software 2061f28255Scgd * without specific prior written permission. 2161f28255Scgd * 2261f28255Scgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2361f28255Scgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2461f28255Scgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2561f28255Scgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2661f28255Scgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2761f28255Scgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2861f28255Scgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2961f28255Scgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3061f28255Scgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3161f28255Scgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3261f28255Scgd * SUCH DAMAGE. 3361f28255Scgd */ 3461f28255Scgd 35cd799663Schristos #include <sys/cdefs.h> 3661f28255Scgd #ifndef lint 3749f0ad86Scgd #if 0 3807bae7edSchristos static char sccsid[] = "@(#)output.c 8.2 (Berkeley) 5/4/95"; 3949f0ad86Scgd #else 40*d47295ccSrillig __RCSID("$NetBSD: output.c,v 1.42 2024/10/03 20:14:01 rillig Exp $"); 4149f0ad86Scgd #endif 4261f28255Scgd #endif /* not lint */ 4361f28255Scgd 4461f28255Scgd /* 4561f28255Scgd * Shell output routines. We use our own output routines because: 4661f28255Scgd * When a builtin command is interrupted we have to discard 4761f28255Scgd * any pending output. 4861f28255Scgd * When a builtin command appears in back quotes, we want to 4961f28255Scgd * save the output of the command in a region obtained 5061f28255Scgd * via malloc, rather than doing a fork and reading the 5161f28255Scgd * output of the command via a pipe. 5261f28255Scgd * Our output routines may be smaller than the stdio routines. 5361f28255Scgd */ 5461f28255Scgd 55d4fe82dfSjtc #include <sys/types.h> /* quad_t */ 56e3f5fb92Schristos #include <sys/param.h> /* BSD4_4 */ 574ce0d34aScgd #include <sys/ioctl.h> 584ce0d34aScgd 5961f28255Scgd #include <stdio.h> /* defines BUFSIZ */ 6042f0dae5Scgd #include <string.h> 6161f28255Scgd #include <errno.h> 62a81e4124Sjtc #include <unistd.h> 6307bae7edSchristos #include <stdlib.h> 6407bae7edSchristos 6507bae7edSchristos #include "shell.h" 6607bae7edSchristos #include "syntax.h" 6707bae7edSchristos #include "output.h" 6807bae7edSchristos #include "memalloc.h" 6907bae7edSchristos #include "error.h" 70ffc64c63Skre #include "redir.h" 71ffc64c63Skre #include "options.h" 72ffc64c63Skre #include "show.h" 7361f28255Scgd 7461f28255Scgd 7561f28255Scgd #define OUTBUFSIZ BUFSIZ 7661f28255Scgd #define BLOCK_OUT -2 /* output to a fixed block of memory */ 7761f28255Scgd #define MEM_OUT -3 /* output to dynamically allocated memory */ 7861f28255Scgd 79ae40879bSkre #ifdef SMALL 80ae40879bSkre #define CHAIN 81ae40879bSkre #else 82ae40879bSkre #define CHAIN ,NULL 83ae40879bSkre #endif 84ae40879bSkre 8561f28255Scgd 86ffc64c63Skre /* nextc nleft bufsize buf fd flags chain */ 87ae40879bSkre struct output output = {NULL, 0, OUTBUFSIZ, NULL, 1, 0 CHAIN }; 88ae40879bSkre struct output errout = {NULL, 0, 100, NULL, 2, 0 CHAIN }; 89ae40879bSkre struct output memout = {NULL, 0, 0, NULL, MEM_OUT, 0 CHAIN }; 9061f28255Scgd struct output *out1 = &output; 9161f28255Scgd struct output *out2 = &errout; 92ae40879bSkre #ifndef SMALL 93ffc64c63Skre struct output *outx = &errout; 94ffc64c63Skre struct output *outxtop = NULL; 95ae40879bSkre #endif 9661f28255Scgd 9761f28255Scgd 9861f28255Scgd #ifdef mkinit 9961f28255Scgd 10061f28255Scgd INCLUDE "output.h" 10161f28255Scgd INCLUDE "memalloc.h" 10261f28255Scgd 10361f28255Scgd RESET { 10461f28255Scgd out1 = &output; 10561f28255Scgd out2 = &errout; 10661f28255Scgd if (memout.buf != NULL) { 10761f28255Scgd ckfree(memout.buf); 10861f28255Scgd memout.buf = NULL; 10961f28255Scgd } 11061f28255Scgd } 11161f28255Scgd 11261f28255Scgd #endif 11361f28255Scgd 11461f28255Scgd 11561f28255Scgd #ifdef notdef /* no longer used */ 11661f28255Scgd /* 11761f28255Scgd * Set up an output file to write to memory rather than a file. 11861f28255Scgd */ 11961f28255Scgd 12061f28255Scgd void 121c02b3bbdSchristos open_mem(char *block, int length, struct output *file) 12261f28255Scgd { 12361f28255Scgd file->nextc = block; 12461f28255Scgd file->nleft = --length; 12561f28255Scgd file->fd = BLOCK_OUT; 12661f28255Scgd file->flags = 0; 12761f28255Scgd } 12861f28255Scgd #endif 12961f28255Scgd 13061f28255Scgd 13161f28255Scgd void 132c02b3bbdSchristos out1str(const char *p) 13361f28255Scgd { 13461f28255Scgd outstr(p, out1); 13561f28255Scgd } 13661f28255Scgd 13761f28255Scgd 13861f28255Scgd void 139c02b3bbdSchristos out2str(const char *p) 14061f28255Scgd { 14161f28255Scgd outstr(p, out2); 14261f28255Scgd } 14361f28255Scgd 144ae40879bSkre #ifndef SMALL 145ffc64c63Skre void 146ffc64c63Skre outxstr(const char *p) 147ffc64c63Skre { 148ffc64c63Skre outstr(p, outx); 149ffc64c63Skre } 150ae40879bSkre #endif 151ffc64c63Skre 15261f28255Scgd 15361f28255Scgd void 154c02b3bbdSchristos outstr(const char *p, struct output *file) 15561f28255Scgd { 156ffc64c63Skre char c = 0; 157ffc64c63Skre 15861f28255Scgd while (*p) 159ffc64c63Skre outc((c = *p++), file); 160ffc64c63Skre if (file == out2 || (file == outx && c == '\n')) 16137ed7877Sjtc flushout(file); 16261f28255Scgd } 16361f28255Scgd 16461f28255Scgd 165bc4eb9bdSchristos void 166bc4eb9bdSchristos out2shstr(const char *p) 167bc4eb9bdSchristos { 168bc4eb9bdSchristos outshstr(p, out2); 169bc4eb9bdSchristos } 170bc4eb9bdSchristos 171ae40879bSkre #ifndef SMALL 172ffc64c63Skre void 173ffc64c63Skre outxshstr(const char *p) 174ffc64c63Skre { 175ffc64c63Skre outshstr(p, outx); 176ffc64c63Skre } 177ae40879bSkre #endif 178bc4eb9bdSchristos 179f5deb3baSkre /* 180f5deb3baSkre * ' is in this list, not because it does not require quoting 181f5deb3baSkre * (which applies to all the others) but because '' quoting cannot 182f5deb3baSkre * be used to quote it. 183f5deb3baSkre */ 184f87bc150Schristos static const char norm_chars [] = \ 185727fae80Skre "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/+-=_,.'"; 186f87bc150Schristos 187f87bc150Schristos static int 188f87bc150Schristos inquote(const char *p) 189f87bc150Schristos { 190f87bc150Schristos size_t l = strspn(p, norm_chars); 191*d47295ccSrillig const char *s = strchr(p, '\''); 192f87bc150Schristos 193f87bc150Schristos return s == NULL ? p[l] != '\0' : s - p > (off_t)l; 194f87bc150Schristos } 195f87bc150Schristos 196bc4eb9bdSchristos void 197bc4eb9bdSchristos outshstr(const char *p, struct output *file) 198bc4eb9bdSchristos { 199f5deb3baSkre int need_q; 200f87bc150Schristos int inq; 201bc4eb9bdSchristos char c; 202bc4eb9bdSchristos 203f5deb3baSkre if (strchr(p, '\'') != NULL && p[1] != '\0') { 204f5deb3baSkre /* 205f5deb3baSkre * string contains ' in it, and is not only the ' 206f5deb3baSkre * see if " quoting will work 207f5deb3baSkre */ 208f5deb3baSkre size_t i = strcspn(p, "\\\"$`"); 209f5deb3baSkre 210f5deb3baSkre if (p[i] == '\0') { 211f5deb3baSkre /* 212f5deb3baSkre * string contains no $ ` \ or " chars, perfect... 213f5deb3baSkre * 214f5deb3baSkre * We know it contains ' so needs quoting, so 215f5deb3baSkre * this is easy... 216f5deb3baSkre */ 217f5deb3baSkre outc('"', file); 218f5deb3baSkre outstr(p, file); 219f5deb3baSkre outc('"', file); 220f5deb3baSkre return; 221f5deb3baSkre } 222f5deb3baSkre } 223f5deb3baSkre 224f5deb3baSkre need_q = p[0] == 0 || p[strspn(p, norm_chars)] != 0; 225f5deb3baSkre 226f87bc150Schristos /* 227f87bc150Schristos * Don't emit ' unless something needs quoting before closing ' 228f87bc150Schristos */ 229f5deb3baSkre if (need_q && (p[0] == 0 || inquote(p) != 0)) { 230bc4eb9bdSchristos outc('\'', file); 231f5deb3baSkre inq = 1; 232f87bc150Schristos } else 233f87bc150Schristos inq = 0; 234bc4eb9bdSchristos 235f87bc150Schristos while ((c = *p++) != '\0') { 236bc4eb9bdSchristos if (c != '\'') { 237bc4eb9bdSchristos outc(c, file); 238f87bc150Schristos continue; 239bc4eb9bdSchristos } 240bc4eb9bdSchristos 241f87bc150Schristos if (inq) 242f87bc150Schristos outc('\'', file); /* inq = 0, implicit */ 243f87bc150Schristos outc('\\', file); 244f87bc150Schristos outc(c, file); 245f87bc150Schristos if (need_q && *p != '\0') { 246f87bc150Schristos if ((inq = inquote(p)) != 0) 247f87bc150Schristos outc('\'', file); 248f87bc150Schristos } else 249f87bc150Schristos inq = 0; 250f87bc150Schristos } 251f87bc150Schristos 252f87bc150Schristos if (inq) 253bc4eb9bdSchristos outc('\'', file); 254bc4eb9bdSchristos 255bc4eb9bdSchristos if (file == out2) 256bc4eb9bdSchristos flushout(file); 257bc4eb9bdSchristos } 258bc4eb9bdSchristos 259bc4eb9bdSchristos 26061f28255Scgd char out_junk[16]; 26161f28255Scgd 26261f28255Scgd 26361f28255Scgd void 264c02b3bbdSchristos emptyoutbuf(struct output *dest) 26561f28255Scgd { 26661f28255Scgd int offset; 26761f28255Scgd 26861f28255Scgd if (dest->fd == BLOCK_OUT) { 26961f28255Scgd dest->nextc = out_junk; 27061f28255Scgd dest->nleft = sizeof out_junk; 27161f28255Scgd dest->flags |= OUTPUT_ERR; 27261f28255Scgd } else if (dest->buf == NULL) { 27361f28255Scgd INTOFF; 27461f28255Scgd dest->buf = ckmalloc(dest->bufsize); 27561f28255Scgd dest->nextc = dest->buf; 27661f28255Scgd dest->nleft = dest->bufsize; 27761f28255Scgd INTON; 278ffc64c63Skre VTRACE(DBG_OUTPUT, ("emptyoutbuf now %d @%p for fd %d\n", 279ffc64c63Skre dest->nleft, dest->buf, dest->fd)); 28061f28255Scgd } else if (dest->fd == MEM_OUT) { 28161f28255Scgd offset = dest->bufsize; 28261f28255Scgd INTOFF; 28361f28255Scgd dest->bufsize <<= 1; 28461f28255Scgd dest->buf = ckrealloc(dest->buf, dest->bufsize); 28561f28255Scgd dest->nleft = dest->bufsize - offset; 28661f28255Scgd dest->nextc = dest->buf + offset; 28761f28255Scgd INTON; 28861f28255Scgd } else { 28961f28255Scgd flushout(dest); 29061f28255Scgd } 29161f28255Scgd dest->nleft--; 29261f28255Scgd } 29361f28255Scgd 29461f28255Scgd 29561f28255Scgd void 296c02b3bbdSchristos flushall(void) 297c02b3bbdSchristos { 29861f28255Scgd flushout(&output); 29961f28255Scgd flushout(&errout); 30061f28255Scgd } 30161f28255Scgd 30261f28255Scgd 30361f28255Scgd void 304c02b3bbdSchristos flushout(struct output *dest) 30561f28255Scgd { 30661f28255Scgd 30761f28255Scgd if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0) 30861f28255Scgd return; 309ffc64c63Skre VTRACE(DBG_OUTPUT, ("flushout fd=%d %zd to write\n", dest->fd, 310ffc64c63Skre (size_t)(dest->nextc - dest->buf))); 31161f28255Scgd if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0) 31261f28255Scgd dest->flags |= OUTPUT_ERR; 31361f28255Scgd dest->nextc = dest->buf; 31461f28255Scgd dest->nleft = dest->bufsize; 31561f28255Scgd } 31661f28255Scgd 31761f28255Scgd 31861f28255Scgd void 319c02b3bbdSchristos freestdout(void) 320c02b3bbdSchristos { 32161f28255Scgd INTOFF; 32261f28255Scgd if (output.buf) { 32361f28255Scgd ckfree(output.buf); 32461f28255Scgd output.buf = NULL; 32561f28255Scgd output.nleft = 0; 32661f28255Scgd } 32761f28255Scgd INTON; 32861f28255Scgd } 32961f28255Scgd 33061f28255Scgd 3312b259b06Schristos void 3322b259b06Schristos outfmt(struct output *file, const char *fmt, ...) 33361f28255Scgd { 33461f28255Scgd va_list ap; 33561f28255Scgd 3362b259b06Schristos va_start(ap, fmt); 33761f28255Scgd doformat(file, fmt, ap); 33861f28255Scgd va_end(ap); 33961f28255Scgd } 34061f28255Scgd 34161f28255Scgd 34261f28255Scgd void 3432b259b06Schristos out1fmt(const char *fmt, ...) 34461f28255Scgd { 34561f28255Scgd va_list ap; 34661f28255Scgd 3472b259b06Schristos va_start(ap, fmt); 34861f28255Scgd doformat(out1, fmt, ap); 34961f28255Scgd va_end(ap); 35061f28255Scgd } 35161f28255Scgd 35242fececdSchristos #ifdef DEBUG 35337ed7877Sjtc void 35442fececdSchristos debugprintf(const char *fmt, ...) 35537ed7877Sjtc { 35637ed7877Sjtc va_list ap; 35737ed7877Sjtc 3582b259b06Schristos va_start(ap, fmt); 35937ed7877Sjtc doformat(out2, fmt, ap); 36037ed7877Sjtc va_end(ap); 36137ed7877Sjtc flushout(out2); 36237ed7877Sjtc } 36342fececdSchristos #endif 36461f28255Scgd 36561f28255Scgd void 3662b259b06Schristos fmtstr(char *outbuf, size_t length, const char *fmt, ...) 36761f28255Scgd { 36861f28255Scgd va_list ap; 36961f28255Scgd struct output strout; 37061f28255Scgd 3712b259b06Schristos va_start(ap, fmt); 37261f28255Scgd strout.nextc = outbuf; 37361f28255Scgd strout.nleft = length; 37461f28255Scgd strout.fd = BLOCK_OUT; 37561f28255Scgd strout.flags = 0; 37661f28255Scgd doformat(&strout, fmt, ap); 37761f28255Scgd outc('\0', &strout); 37861f28255Scgd if (strout.flags & OUTPUT_ERR) 37961f28255Scgd outbuf[length - 1] = '\0'; 3804c999163Swiz va_end(ap); 38161f28255Scgd } 38261f28255Scgd 38361f28255Scgd /* 38461f28255Scgd * Formatted output. This routine handles a subset of the printf formats: 3852b259b06Schristos * - Formats supported: d, u, o, p, X, s, and c. 38661f28255Scgd * - The x format is also accepted but is treated like X. 387dd7296f4Slukem * - The l, ll and q modifiers are accepted. 38861f28255Scgd * - The - and # flags are accepted; # only works with the o format. 38961f28255Scgd * - Width and precision may be specified with any format except c. 39061f28255Scgd * - An * may be given for the width or precision. 39161f28255Scgd * - The obsolete practice of preceding the width with a zero to get 39261f28255Scgd * zero padding is not supported; use the precision field. 39361f28255Scgd * - A % may be printed by writing %% in the format string. 39461f28255Scgd */ 39561f28255Scgd 39661f28255Scgd #define TEMPSIZE 24 39761f28255Scgd 39810fc746eSlukem #ifdef BSD4_4 39910fc746eSlukem #define HAVE_VASPRINTF 1 40010fc746eSlukem #endif 40110fc746eSlukem 40261f28255Scgd void 403c02b3bbdSchristos doformat(struct output *dest, const char *f, va_list ap) 40461f28255Scgd { 40510fc746eSlukem #if HAVE_VASPRINTF 40610fc746eSlukem char *s; 40710fc746eSlukem 40810fc746eSlukem vasprintf(&s, f, ap); 4092174dda2Srumble if (s == NULL) 4102174dda2Srumble error("Could not allocate formatted output buffer"); 41110fc746eSlukem outstr(s, dest); 41210fc746eSlukem free(s); 41310fc746eSlukem #else /* !HAVE_VASPRINTF */ 4143ea17f6cSthorpej static const char digit[] = "0123456789ABCDEF"; 41548250187Stls char c; 41661f28255Scgd char temp[TEMPSIZE]; 41761f28255Scgd int flushleft; 41861f28255Scgd int sharp; 41961f28255Scgd int width; 42061f28255Scgd int prec; 42161f28255Scgd int islong; 422d4fe82dfSjtc int isquad; 42361f28255Scgd char *p; 42461f28255Scgd int sign; 42592cdde85Schristos #ifdef BSD4_4 426d4fe82dfSjtc quad_t l; 427d4fe82dfSjtc u_quad_t num; 42892cdde85Schristos #else 42992cdde85Schristos long l; 43092cdde85Schristos u_long num; 43192cdde85Schristos #endif 43261f28255Scgd unsigned base; 43361f28255Scgd int len; 43461f28255Scgd int size; 43561f28255Scgd int pad; 43661f28255Scgd 43761f28255Scgd while ((c = *f++) != '\0') { 43861f28255Scgd if (c != '%') { 43961f28255Scgd outc(c, dest); 44061f28255Scgd continue; 44161f28255Scgd } 44261f28255Scgd flushleft = 0; 44361f28255Scgd sharp = 0; 44461f28255Scgd width = 0; 44561f28255Scgd prec = -1; 44661f28255Scgd islong = 0; 447d4fe82dfSjtc isquad = 0; 44861f28255Scgd for (;;) { 44961f28255Scgd if (*f == '-') 45061f28255Scgd flushleft++; 45161f28255Scgd else if (*f == '#') 45261f28255Scgd sharp++; 45361f28255Scgd else 45461f28255Scgd break; 45561f28255Scgd f++; 45661f28255Scgd } 45761f28255Scgd if (*f == '*') { 45861f28255Scgd width = va_arg(ap, int); 45961f28255Scgd f++; 46061f28255Scgd } else { 46161f28255Scgd while (is_digit(*f)) { 46261f28255Scgd width = 10 * width + digit_val(*f++); 46361f28255Scgd } 46461f28255Scgd } 46561f28255Scgd if (*f == '.') { 46661f28255Scgd if (*++f == '*') { 46761f28255Scgd prec = va_arg(ap, int); 46861f28255Scgd f++; 46961f28255Scgd } else { 47061f28255Scgd prec = 0; 47161f28255Scgd while (is_digit(*f)) { 47261f28255Scgd prec = 10 * prec + digit_val(*f++); 47361f28255Scgd } 47461f28255Scgd } 47561f28255Scgd } 47661f28255Scgd if (*f == 'l') { 47761f28255Scgd f++; 478dd7296f4Slukem if (*f == 'l') { 479dd7296f4Slukem isquad++; 480dd7296f4Slukem f++; 481dd7296f4Slukem } else 482dd7296f4Slukem islong++; 483d4fe82dfSjtc } else if (*f == 'q') { 484d4fe82dfSjtc isquad++; 485d4fe82dfSjtc f++; 48661f28255Scgd } 48761f28255Scgd switch (*f) { 48861f28255Scgd case 'd': 48992cdde85Schristos #ifdef BSD4_4 490d4fe82dfSjtc if (isquad) 491d4fe82dfSjtc l = va_arg(ap, quad_t); 49292cdde85Schristos else 49392cdde85Schristos #endif 49492cdde85Schristos if (islong) 49561f28255Scgd l = va_arg(ap, long); 49661f28255Scgd else 49761f28255Scgd l = va_arg(ap, int); 49861f28255Scgd sign = 0; 49961f28255Scgd num = l; 50061f28255Scgd if (l < 0) { 50161f28255Scgd num = -l; 50261f28255Scgd sign = 1; 50361f28255Scgd } 50461f28255Scgd base = 10; 50561f28255Scgd goto number; 50661f28255Scgd case 'u': 50761f28255Scgd base = 10; 50861f28255Scgd goto uns_number; 50961f28255Scgd case 'o': 51061f28255Scgd base = 8; 51161f28255Scgd goto uns_number; 5122b259b06Schristos case 'p': 5132b259b06Schristos outc('0', dest); 5142b259b06Schristos outc('x', dest); 5152b259b06Schristos /*FALLTHROUGH*/ 51661f28255Scgd case 'x': 51761f28255Scgd /* we don't implement 'x'; treat like 'X' */ 51861f28255Scgd case 'X': 51961f28255Scgd base = 16; 52061f28255Scgd uns_number: /* an unsigned number */ 52161f28255Scgd sign = 0; 52292cdde85Schristos #ifdef BSD4_4 523d4fe82dfSjtc if (isquad) 524d4fe82dfSjtc num = va_arg(ap, u_quad_t); 52592cdde85Schristos else 52692cdde85Schristos #endif 52792cdde85Schristos if (islong) 52861f28255Scgd num = va_arg(ap, unsigned long); 52961f28255Scgd else 53061f28255Scgd num = va_arg(ap, unsigned int); 53161f28255Scgd number: /* process a number */ 53261f28255Scgd p = temp + TEMPSIZE - 1; 53361f28255Scgd *p = '\0'; 53461f28255Scgd while (num) { 53561f28255Scgd *--p = digit[num % base]; 53661f28255Scgd num /= base; 53761f28255Scgd } 53861f28255Scgd len = (temp + TEMPSIZE - 1) - p; 53961f28255Scgd if (prec < 0) 54061f28255Scgd prec = 1; 54161f28255Scgd if (sharp && *f == 'o' && prec <= len) 54261f28255Scgd prec = len + 1; 54361f28255Scgd pad = 0; 54461f28255Scgd if (width) { 54561f28255Scgd size = len; 54661f28255Scgd if (size < prec) 54761f28255Scgd size = prec; 54861f28255Scgd size += sign; 54961f28255Scgd pad = width - size; 55061f28255Scgd if (flushleft == 0) { 55161f28255Scgd while (--pad >= 0) 55261f28255Scgd outc(' ', dest); 55361f28255Scgd } 55461f28255Scgd } 55561f28255Scgd if (sign) 55661f28255Scgd outc('-', dest); 55761f28255Scgd prec -= len; 55861f28255Scgd while (--prec >= 0) 55961f28255Scgd outc('0', dest); 56061f28255Scgd while (*p) 56161f28255Scgd outc(*p++, dest); 56261f28255Scgd while (--pad >= 0) 56361f28255Scgd outc(' ', dest); 56461f28255Scgd break; 56561f28255Scgd case 's': 56661f28255Scgd p = va_arg(ap, char *); 56761f28255Scgd pad = 0; 56861f28255Scgd if (width) { 56961f28255Scgd len = strlen(p); 57061f28255Scgd if (prec >= 0 && len > prec) 57161f28255Scgd len = prec; 57261f28255Scgd pad = width - len; 57361f28255Scgd if (flushleft == 0) { 57461f28255Scgd while (--pad >= 0) 57561f28255Scgd outc(' ', dest); 57661f28255Scgd } 57761f28255Scgd } 57861f28255Scgd prec++; 57961f28255Scgd while (--prec != 0 && *p) 58061f28255Scgd outc(*p++, dest); 58161f28255Scgd while (--pad >= 0) 58261f28255Scgd outc(' ', dest); 58361f28255Scgd break; 58461f28255Scgd case 'c': 58561f28255Scgd c = va_arg(ap, int); 58661f28255Scgd outc(c, dest); 58761f28255Scgd break; 58861f28255Scgd default: 58961f28255Scgd outc(*f, dest); 59061f28255Scgd break; 59161f28255Scgd } 59261f28255Scgd f++; 59361f28255Scgd } 59410fc746eSlukem #endif /* !HAVE_VASPRINTF */ 59561f28255Scgd } 59661f28255Scgd 59761f28255Scgd 59861f28255Scgd 59961f28255Scgd /* 60061f28255Scgd * Version of write which resumes after a signal is caught. 60161f28255Scgd */ 60261f28255Scgd 60361f28255Scgd int 604c02b3bbdSchristos xwrite(int fd, char *buf, int nbytes) 60561f28255Scgd { 60661f28255Scgd int ntry; 60761f28255Scgd int i; 60861f28255Scgd int n; 60961f28255Scgd 61061f28255Scgd n = nbytes; 61161f28255Scgd ntry = 0; 6120c52b5f1Schristos while (n > 0) { 61361f28255Scgd i = write(fd, buf, n); 61461f28255Scgd if (i > 0) { 61561f28255Scgd if ((n -= i) <= 0) 61661f28255Scgd return nbytes; 61761f28255Scgd buf += i; 61861f28255Scgd ntry = 0; 61961f28255Scgd } else if (i == 0) { 62061f28255Scgd if (++ntry > 10) 62161f28255Scgd return nbytes - n; 62261f28255Scgd } else if (errno != EINTR) { 62361f28255Scgd return -1; 62461f28255Scgd } 62561f28255Scgd } 6260c52b5f1Schristos return nbytes; 62761f28255Scgd } 62861f28255Scgd 629ae40879bSkre #ifndef SMALL 630ffc64c63Skre static void 631ffc64c63Skre xtrace_fd_swap(int from, int to) 632ffc64c63Skre { 633ffc64c63Skre struct output *o = outxtop; 634ffc64c63Skre 635ffc64c63Skre while (o != NULL) { 636ffc64c63Skre if (o->fd == from) 637ffc64c63Skre o->fd = to; 638ffc64c63Skre o = o->chain; 639ffc64c63Skre } 640ffc64c63Skre } 641ffc64c63Skre 642ffc64c63Skre /* 643ffc64c63Skre * the -X flag is to be set or reset (not necessarily changed) 644ffc64c63Skre * Do what is needed to make tracing go to where it should 645ffc64c63Skre * 646ffc64c63Skre * Note: Xflag has not yet been altered, "on" indicates what it will become 647ffc64c63Skre */ 648ffc64c63Skre 649ffc64c63Skre void 650ffc64c63Skre xtracefdsetup(int on) 651ffc64c63Skre { 652ffc64c63Skre if (!on) { 653ffc64c63Skre flushout(outx); 654ffc64c63Skre 655ffc64c63Skre if (Xflag != 1) /* Was already +X */ 656ffc64c63Skre return; /* so nothing to do */ 657ffc64c63Skre 658ffc64c63Skre outx = out2; 659ffc64c63Skre CTRACE(DBG_OUTPUT, ("Tracing to stderr\n")); 660ffc64c63Skre return; 661ffc64c63Skre } 662ffc64c63Skre 663ffc64c63Skre if (Xflag == 1) { /* was already set */ 664ffc64c63Skre /* 665ffc64c63Skre * This is a change of output file only 666ffc64c63Skre * Just close the current one, and reuse the struct output 667ffc64c63Skre */ 668ffc64c63Skre if (!(outx->flags & OUTPUT_CLONE)) 669ffc64c63Skre sh_close(outx->fd); 670ffc64c63Skre } else if (outxtop == NULL) { 671ffc64c63Skre /* 672ffc64c63Skre * -X is just turning on, for the forst time, 673ffc64c63Skre * need a new output struct to become outx 674ffc64c63Skre */ 675ffc64c63Skre xtrace_clone(1); 676ffc64c63Skre } else 677ffc64c63Skre outx = outxtop; 678ffc64c63Skre 679ffc64c63Skre if (outx != out2) { 680ffc64c63Skre outx->flags &= ~OUTPUT_CLONE; 681ffc64c63Skre outx->fd = to_upper_fd(dup(out2->fd)); 682ffc64c63Skre register_sh_fd(outx->fd, xtrace_fd_swap); 683ffc64c63Skre } 684ffc64c63Skre 685ffc64c63Skre CTRACE(DBG_OUTPUT, ("Tracing now to fd %d (from %d)\n", 686ffc64c63Skre outx->fd, out2->fd)); 687ffc64c63Skre } 688ffc64c63Skre 689ffc64c63Skre void 690ffc64c63Skre xtrace_clone(int new) 691ffc64c63Skre { 692ffc64c63Skre struct output *o; 693ffc64c63Skre 694ffc64c63Skre CTRACE(DBG_OUTPUT, 695ffc64c63Skre ("xtrace_clone(%d): %sfd=%d buf=%p nleft=%d flags=%x ", 696ffc64c63Skre new, (outx == out2 ? "out2: " : ""), 697ffc64c63Skre outx->fd, outx->buf, outx->nleft, outx->flags)); 698ffc64c63Skre 699ffc64c63Skre flushout(outx); 700ffc64c63Skre 701ffc64c63Skre if (!new && outxtop == NULL && Xflag == 0) { 702ffc64c63Skre /* following stderr, nothing to save */ 703ffc64c63Skre CTRACE(DBG_OUTPUT, ("+X\n")); 704ffc64c63Skre return; 705ffc64c63Skre } 706ffc64c63Skre 707ffc64c63Skre o = ckmalloc(sizeof(*o)); 708ffc64c63Skre o->fd = outx->fd; 709ffc64c63Skre o->flags = OUTPUT_CLONE; 710ffc64c63Skre o->bufsize = outx->bufsize; 711ffc64c63Skre o->nleft = 0; 712ffc64c63Skre o->buf = NULL; 713ffc64c63Skre o->nextc = NULL; 714ffc64c63Skre o->chain = outxtop; 715ffc64c63Skre outx = o; 716ffc64c63Skre outxtop = o; 717ffc64c63Skre 718ffc64c63Skre CTRACE(DBG_OUTPUT, ("-> fd=%d flags=%x[CLONE]\n", outx->fd, o->flags)); 719ffc64c63Skre } 720ffc64c63Skre 721ffc64c63Skre void 722ffc64c63Skre xtrace_pop(void) 723ffc64c63Skre { 724ffc64c63Skre struct output *o; 725ffc64c63Skre 726ffc64c63Skre CTRACE(DBG_OUTPUT, ("trace_pop: fd=%d buf=%p nleft=%d flags=%x ", 727ffc64c63Skre outx->fd, outx->buf, outx->nleft, outx->flags)); 728ffc64c63Skre 729ffc64c63Skre flushout(outx); 730ffc64c63Skre 731ffc64c63Skre if (outxtop == NULL) { 732ffc64c63Skre /* 733ffc64c63Skre * No -X has been used, so nothing much to do 734ffc64c63Skre */ 735ffc64c63Skre CTRACE(DBG_OUTPUT, ("+X\n")); 736ffc64c63Skre return; 737ffc64c63Skre } 738ffc64c63Skre 739ffc64c63Skre o = outxtop; 740ffc64c63Skre outx = o->chain; 741ffc64c63Skre if (outx == NULL) 742ffc64c63Skre outx = &errout; 743ffc64c63Skre outxtop = o->chain; 744ffc64c63Skre if (o != &errout) { 745ffc64c63Skre if (o->fd >= 0 && !(o->flags & OUTPUT_CLONE)) 746ffc64c63Skre sh_close(o->fd); 747ffc64c63Skre if (o->buf) 748ffc64c63Skre ckfree(o->buf); 749ffc64c63Skre ckfree(o); 750ffc64c63Skre } 751ffc64c63Skre 752ffc64c63Skre CTRACE(DBG_OUTPUT, ("-> fd=%d buf=%p nleft=%d flags=%x\n", 753ffc64c63Skre outx->fd, outx->buf, outx->nleft, outx->flags)); 754ffc64c63Skre } 755ae40879bSkre #endif /* SMALL */ 756