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
35 #ifdef HAVE_SYS_CDEFS_H
36 #include <sys/cdefs.h>
40 static char sccsid
[] = "@(#)output.c 8.2 (Berkeley) 5/4/95";
42 __RCSID("$NetBSD: output.c,v 1.28 2003/08/07 09:05:36 agc Exp $");
47 * Shell output routines. We use our own output routines because:
48 * When a builtin command is interrupted we have to discard
50 * When a builtin command appears in back quotes, we want to
51 * save the output of the command in a region obtained
52 * via malloc, rather than doing a fork and reading the
53 * output of the command via a pipe.
54 * Our output routines may be smaller than the stdio routines.
57 #include <sys/types.h> /* quad_t */
58 #include <sys/param.h> /* BSD4_4 */
59 #include <sys/ioctl.h>
61 #include <stdio.h> /* defines BUFSIZ */
74 #define OUTBUFSIZ BUFSIZ
75 #define BLOCK_OUT -2 /* output to a fixed block of memory */
76 #define MEM_OUT -3 /* output to dynamically allocated memory */
77 #define OUTPUT_ERR 01 /* error occurred on output */
80 struct output output
= {NULL
, 0, NULL
, OUTBUFSIZ
, 1, 0};
81 struct output errout
= {NULL
, 0, NULL
, 100, 2, 0};
82 struct output memout
= {NULL
, 0, NULL
, 0, MEM_OUT
, 0};
83 struct output
*out1
= &output
;
84 struct output
*out2
= &errout
;
96 if (memout
.buf
!= NULL
) {
105 #ifdef notdef /* no longer used */
107 * Set up an output file to write to memory rather than a file.
111 open_mem(char *block
, int length
, struct output
*file
)
114 file
->nleft
= --length
;
115 file
->fd
= BLOCK_OUT
;
122 out1str(const char *p
)
129 out2str(const char *p
)
136 outstr(const char *p
, struct output
*file
)
149 emptyoutbuf(struct output
*dest
)
153 if (dest
->fd
== BLOCK_OUT
) {
154 dest
->nextc
= out_junk
;
155 dest
->nleft
= sizeof out_junk
;
156 dest
->flags
|= OUTPUT_ERR
;
157 } else if (dest
->buf
== NULL
) {
159 dest
->buf
= ckmalloc(dest
->bufsize
);
160 dest
->nextc
= dest
->buf
;
161 dest
->nleft
= dest
->bufsize
;
163 } else if (dest
->fd
== MEM_OUT
) {
164 offset
= dest
->bufsize
;
167 dest
->buf
= ckrealloc(dest
->buf
, dest
->bufsize
);
168 dest
->nleft
= dest
->bufsize
- offset
;
169 dest
->nextc
= dest
->buf
+ offset
;
179 output_flushall(void)
187 flushout(struct output
*dest
)
190 if (dest
->buf
== NULL
|| dest
->nextc
== dest
->buf
|| dest
->fd
< 0)
192 if (xwrite(dest
->fd
, dest
->buf
, dest
->nextc
- dest
->buf
) < 0)
193 dest
->flags
|= OUTPUT_ERR
;
194 dest
->nextc
= dest
->buf
;
195 dest
->nleft
= dest
->bufsize
;
213 outfmt(struct output
*file
, const char *fmt
, ...)
218 doformat(file
, fmt
, ap
);
224 out1fmt(const char *fmt
, ...)
229 doformat(out1
, fmt
, ap
);
234 dprintf(const char *fmt
, ...)
239 doformat(out2
, fmt
, ap
);
245 fmtstr(char *outbuf
, size_t length
, const char *fmt
, ...)
248 struct output strout
;
251 strout
.nextc
= outbuf
;
252 strout
.nleft
= length
;
253 strout
.fd
= BLOCK_OUT
;
255 doformat(&strout
, fmt
, ap
);
257 if (strout
.flags
& OUTPUT_ERR
)
258 outbuf
[length
- 1] = '\0';
263 * Formatted output. This routine handles a subset of the printf formats:
264 * - Formats supported: d, u, o, p, X, s, and c.
265 * - The x format is also accepted but is treated like X.
266 * - The l, ll and q modifiers are accepted.
267 * - The - and # flags are accepted; # only works with the o format.
268 * - Width and precision may be specified with any format except c.
269 * - An * may be given for the width or precision.
270 * - The obsolete practice of preceding the width with a zero to get
271 * zero padding is not supported; use the precision field.
272 * - A % may be printed by writing %% in the format string.
278 #define HAVE_VASPRINTF 1
282 doformat(struct output
*dest
, const char *f
, va_list ap
)
287 vasprintf(&s
, f
, ap
);
290 #else /* !HAVE_VASPRINTF */
291 static const char digit
[] = "0123456789ABCDEF";
314 while ((c
= *f
++) != '\0') {
335 width
= va_arg(ap
, int);
338 while (is_digit(*f
)) {
339 width
= 10 * width
+ digit_val(*f
++);
344 prec
= va_arg(ap
, int);
348 while (is_digit(*f
)) {
349 prec
= 10 * prec
+ digit_val(*f
++);
360 } else if (*f
== 'q') {
368 l
= va_arg(ap
, quad_t
);
372 l
= va_arg(ap
, long);
394 /* we don't implement 'x'; treat like 'X' */
397 uns_number
: /* an unsigned number */
401 num
= va_arg(ap
, u_quad_t
);
405 num
= va_arg(ap
, unsigned long);
407 num
= va_arg(ap
, unsigned int);
408 number
: /* process a number */
409 p
= temp
+ TEMPSIZE
- 1;
412 *--p
= digit
[num
% base
];
415 len
= (temp
+ TEMPSIZE
- 1) - p
;
418 if (sharp
&& *f
== 'o' && prec
<= len
)
427 if (flushleft
== 0) {
443 p
= va_arg(ap
, char *);
447 if (prec
>= 0 && len
> prec
)
450 if (flushleft
== 0) {
456 while (--prec
!= 0 && *p
)
471 #endif /* !HAVE_VASPRINTF */
477 * Version of write which resumes after a signal is caught.
481 xwrite(int fd
, char *buf
, int nbytes
)
490 i
= write(fd
, buf
, n
);
499 } else if (errno
!= EINTR
) {
507 * Version of ioctl that retries after a signal is caught.
508 * XXX unused function
512 xioctl(int fd
, unsigned long request
, char *arg
)
516 while ((i
= ioctl(fd
, request
, arg
)) == -1 && errno
== EINTR
);