1 /* $NetBSD: output.c,v 1.30 2008/10/12 01:40:37 dholland 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 #include <sys/cdefs.h>
38 static char sccsid
[] = "@(#)output.c 8.2 (Berkeley) 5/4/95";
40 __RCSID("$NetBSD: output.c,v 1.30 2008/10/12 01:40:37 dholland Exp $");
45 * Shell output routines. We use our own output routines because:
46 * When a builtin command is interrupted we have to discard
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.
55 #include <sys/types.h> /* quad_t */
56 #include <sys/param.h> /* BSD4_4 */
57 #include <sys/ioctl.h>
59 #include <stdio.h> /* defines BUFSIZ */
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 */
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
;
93 if (memout
.buf
!= NULL
) {
102 #ifdef notdef /* no longer used */
104 * Set up an output file to write to memory rather than a file.
108 open_mem(char *block
, int length
, struct output
*file
)
111 file
->nleft
= --length
;
112 file
->fd
= BLOCK_OUT
;
119 out1str(const char *p
)
126 out2str(const char *p
)
133 outstr(const char *p
, struct output
*file
)
143 out2shstr(const char *p
)
150 outshstr(const char *p
, struct output
*file
)
152 static const char norm_chars
[] \
153 = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
154 int need_q
= p
[0] == 0 || p
[strspn(p
, norm_chars
)] != 0;
160 while (c
= *p
++, c
!= 0){
183 emptyoutbuf(struct output
*dest
)
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
) {
193 dest
->buf
= ckmalloc(dest
->bufsize
);
194 dest
->nextc
= dest
->buf
;
195 dest
->nleft
= dest
->bufsize
;
197 } else if (dest
->fd
== MEM_OUT
) {
198 offset
= dest
->bufsize
;
201 dest
->buf
= ckrealloc(dest
->buf
, dest
->bufsize
);
202 dest
->nleft
= dest
->bufsize
- offset
;
203 dest
->nextc
= dest
->buf
+ offset
;
221 flushout(struct output
*dest
)
224 if (dest
->buf
== NULL
|| dest
->nextc
== dest
->buf
|| dest
->fd
< 0)
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
;
247 outfmt(struct output
*file
, const char *fmt
, ...)
252 doformat(file
, fmt
, ap
);
258 out1fmt(const char *fmt
, ...)
263 doformat(out1
, fmt
, ap
);
268 dprintf(const char *fmt
, ...)
273 doformat(out2
, fmt
, ap
);
279 fmtstr(char *outbuf
, size_t length
, const char *fmt
, ...)
282 struct output strout
;
285 strout
.nextc
= outbuf
;
286 strout
.nleft
= length
;
287 strout
.fd
= BLOCK_OUT
;
289 doformat(&strout
, fmt
, ap
);
291 if (strout
.flags
& OUTPUT_ERR
)
292 outbuf
[length
- 1] = '\0';
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.
312 #define HAVE_VASPRINTF 1
316 doformat(struct output
*dest
, const char *f
, va_list ap
)
321 vasprintf(&s
, f
, ap
);
323 error("Could not allocate formatted output buffer");
326 #else /* !HAVE_VASPRINTF */
327 static const char digit
[] = "0123456789ABCDEF";
350 while ((c
= *f
++) != '\0') {
371 width
= va_arg(ap
, int);
374 while (is_digit(*f
)) {
375 width
= 10 * width
+ digit_val(*f
++);
380 prec
= va_arg(ap
, int);
384 while (is_digit(*f
)) {
385 prec
= 10 * prec
+ digit_val(*f
++);
396 } else if (*f
== 'q') {
404 l
= va_arg(ap
, quad_t
);
408 l
= va_arg(ap
, long);
430 /* we don't implement 'x'; treat like 'X' */
433 uns_number
: /* an unsigned number */
437 num
= va_arg(ap
, u_quad_t
);
441 num
= va_arg(ap
, unsigned long);
443 num
= va_arg(ap
, unsigned int);
444 number
: /* process a number */
445 p
= temp
+ TEMPSIZE
- 1;
448 *--p
= digit
[num
% base
];
451 len
= (temp
+ TEMPSIZE
- 1) - p
;
454 if (sharp
&& *f
== 'o' && prec
<= len
)
463 if (flushleft
== 0) {
479 p
= va_arg(ap
, char *);
483 if (prec
>= 0 && len
> prec
)
486 if (flushleft
== 0) {
492 while (--prec
!= 0 && *p
)
507 #endif /* !HAVE_VASPRINTF */
513 * Version of write which resumes after a signal is caught.
517 xwrite(int fd
, char *buf
, int nbytes
)
526 i
= write(fd
, buf
, n
);
535 } else if (errno
!= EINTR
) {
543 * Version of ioctl that retries after a signal is caught.
544 * XXX unused function
548 xioctl(int fd
, unsigned long request
, char *arg
)
552 while ((i
= ioctl(fd
, request
, arg
)) == -1 && errno
== EINTR
);