1 /* $NetBSD: output.c,v 1.28 2003/08/07 09:05:36 agc Exp $ */
4 * Copyright (c) 1991, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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
37 static char sccsid
[] = "@(#)output.c 8.2 (Berkeley) 5/4/95";
39 __RCSID("$NetBSD: output.c,v 1.28 2003/08/07 09:05:36 agc Exp $");
44 * Shell output routines. We use our own output routines because:
45 * When a builtin command is interrupted we have to discard
47 * When a builtin command appears in back quotes, we want to
48 * save the output of the command in a region obtained
49 * via malloc, rather than doing a fork and reading the
50 * output of the command via a pipe.
51 * Our output routines may be smaller than the stdio routines.
54 #include <sys/types.h>
56 #include <stdio.h> /* defines BUFSIZ */
66 #include "shinstance.h"
68 //#define OUTBUFSIZ BUFSIZ
69 #define BLOCK_OUT -2 /* output to a fixed block of memory */
70 //#define MEM_OUT -3 /* output to dynamically allocated memory */
71 #define OUTPUT_ERR 01 /* error occurred on output */
74 //struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0};
75 //struct output errout = {NULL, 0, NULL, 100, 2, 0};
76 //struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0};
77 //struct output *out1 = &output;
78 //struct output *out2 = &errout;
88 psh
->out1
= &psh
->output
;
89 psh
->out2
= &psh
->errout
;
90 if (psh
->memout
.buf
!= NULL
) {
91 ckfree(psh
->memout
.buf
);
92 psh
->memout
.buf
= NULL
;
99 #ifdef notdef /* no longer used */
101 * Set up an output file to write to memory rather than a file.
105 open_mem(char *block
, int length
, struct output
*file
)
108 file
->nleft
= --length
;
109 file
->fd
= BLOCK_OUT
;
117 out1str(shinstance
*psh
, const char *p
)
119 outstr(p
, psh
->out1
);
124 out2str(shinstance
*psh
, const char *p
)
126 outstr(p
, psh
->out2
);
131 outstr(const char *p
, struct output
*file
)
135 if (file
->psh
&& file
== file
->psh
->out2
)
144 emptyoutbuf(struct output
*dest
)
147 shinstance
*psh
= dest
->psh
;
149 if (dest
->fd
== BLOCK_OUT
) {
150 dest
->nextc
= out_junk
;
151 dest
->nleft
= sizeof out_junk
;
152 dest
->flags
|= OUTPUT_ERR
;
153 } else if (dest
->buf
== NULL
) {
155 dest
->buf
= ckmalloc(dest
->bufsize
);
156 dest
->nextc
= dest
->buf
;
157 dest
->nleft
= dest
->bufsize
;
159 } else if (dest
->fd
== MEM_OUT
) {
160 offset
= dest
->bufsize
;
163 dest
->buf
= ckrealloc(dest
->buf
, dest
->bufsize
);
164 dest
->nleft
= dest
->bufsize
- offset
;
165 dest
->nextc
= dest
->buf
+ offset
;
175 output_flushall(shinstance
*psh
)
177 flushout(&psh
->output
);
178 flushout(&psh
->errout
);
183 flushout(struct output
*dest
)
186 if (dest
->buf
== NULL
|| dest
->nextc
== dest
->buf
|| dest
->fd
< 0)
188 if (xwrite(dest
->psh
, dest
->fd
, dest
->buf
, dest
->nextc
- dest
->buf
) < 0)
189 dest
->flags
|= OUTPUT_ERR
;
190 dest
->nextc
= dest
->buf
;
191 dest
->nleft
= dest
->bufsize
;
196 freestdout(shinstance
*psh
)
199 if (psh
->output
.buf
) {
200 ckfree(psh
->output
.buf
);
201 psh
->output
.buf
= NULL
;
202 psh
->output
.nleft
= 0;
209 outfmt(struct output
*file
, const char *fmt
, ...)
214 doformat(file
, fmt
, ap
);
220 out1fmt(shinstance
*psh
, const char *fmt
, ...)
225 doformat(psh
->out1
, fmt
, ap
);
230 dprintf(shinstance
*psh
, const char *fmt
, ...)
235 doformat(psh
->out2
, fmt
, ap
);
241 fmtstr(char *outbuf
, size_t length
, const char *fmt
, ...)
244 struct output strout
;
247 strout
.nextc
= outbuf
;
248 strout
.nleft
= (int)length
;
249 strout
.fd
= BLOCK_OUT
;
252 doformat(&strout
, fmt
, ap
);
254 if (strout
.flags
& OUTPUT_ERR
)
255 outbuf
[length
- 1] = '\0';
260 * Formatted output. This routine handles a subset of the printf formats:
261 * - Formats supported: d, u, o, p, X, s, and c.
262 * - The x format is also accepted but is treated like X.
263 * - The l, ll and q modifiers are accepted.
264 * - The - and # flags are accepted; # only works with the o format.
265 * - Width and precision may be specified with any format except c.
266 * - An * may be given for the width or precision.
267 * - The obsolete practice of preceding the width with a zero to get
268 * zero padding is not supported; use the precision field.
269 * - A % may be printed by writing %% in the format string.
275 #define HAVE_VASPRINTF 1
279 doformat(struct output
*dest
, const char *f
, va_list ap
)
281 #ifdef HAVE_VASPRINTF
284 vasprintf(&s
, f
, ap
);
287 #else /* !HAVE_VASPRINTF */
288 static const char digit_lower
[] = "0123456789abcdef";
289 static const char digit_upper
[] = "0123456789ABCDEF";
308 while ((c
= *f
++) != '\0') {
329 width
= va_arg(ap
, int);
332 while (is_digit(*f
)) {
333 width
= 10 * width
+ digit_val(*f
++);
338 prec
= va_arg(ap
, int);
342 while (is_digit(*f
)) {
343 prec
= 10 * prec
+ digit_val(*f
++);
354 } else if (*f
== 'q') {
362 l
= va_arg(ap
, int64_t);
364 l
= va_arg(ap
, long);
386 /* we don't implement 'x'; treat like 'X' */
390 uns_number
: /* an unsigned number */
393 num
= va_arg(ap
, uint64_t);
395 num
= va_arg(ap
, unsigned long);
397 num
= va_arg(ap
, unsigned int);
398 number
: /* process a number */
399 p
= temp
+ TEMPSIZE
- 1;
402 *--p
= digit
[num
% base
];
405 len
= (int)((temp
+ TEMPSIZE
- 1) - p
);
408 if (sharp
&& *f
== 'o' && prec
<= len
)
417 if (flushleft
== 0) {
433 p
= va_arg(ap
, char *);
436 len
= (int)strlen(p
);
437 if (prec
>= 0 && len
> prec
)
440 if (flushleft
== 0) {
446 while (--prec
!= 0 && *p
)
461 #endif /* !HAVE_VASPRINTF */
467 * Version of write which resumes after a signal is caught.
471 xwrite(shinstance
*psh
, int fd
, char *buf
, size_t nbytes
)
480 i
= shfile_write(&psh
->fdtab
, fd
, buf
, n
);
488 return (int)(nbytes
- n
);
489 } else if (errno
!= EINTR
) {