2 * SPDX-License-Identifier: BSD-3-Clause
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";
40 #include <sys/cdefs.h>
41 __FBSDID("$FreeBSD: head/bin/sh/output.c 344306 2019-02-19 21:27:30Z jilles $");
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.
53 #include <stdio.h> /* defines BUFSIZ */
71 #define OUTBUFSIZ BUFSIZ
72 #define MEM_OUT -2 /* output to dynamically allocated memory */
73 #define OUTPUT_ERR 01 /* error occurred on output */
75 static int doformat_wr(void *, const char *, int);
77 struct output output
= {NULL
, NULL
, NULL
, OUTBUFSIZ
, 1, 0};
78 struct output errout
= {NULL
, NULL
, NULL
, 256, 2, 0};
79 struct output memout
= {NULL
, NULL
, NULL
, 64, MEM_OUT
, 0};
80 struct output
*out1
= &output
;
81 struct output
*out2
= &errout
;
84 outcslow(int c
, struct output
*file
)
90 out1str(const char *p
)
96 out1qstr(const char *p
)
102 out2str(const char *p
)
108 out2qstr(const char *p
)
114 outstr(const char *p
, struct output
*file
)
116 outbin(p
, strlen(p
), file
);
120 byteseq(int ch
, struct output
*file
)
125 seq
[1] = (ch
>> 6 & 0x3) + '0';
126 seq
[2] = (ch
>> 3 & 0x7) + '0';
127 seq
[3] = (ch
& 0x7) + '0';
128 outbin(seq
, 4, file
);
132 outdqstr(const char *p
, struct output
*file
)
139 memset(&mbs
, '\0', sizeof(mbs
));
142 while ((clen
= mbrtowc(&wc
, p
, end
- p
+ 1, &mbs
)) != 0) {
143 if (clen
== (size_t)-2) {
148 if (clen
== (size_t)-1) {
149 memset(&mbs
, '\0', sizeof(mbs
));
154 outcslow('\n', file
), p
++;
155 else if (wc
== L
'\r')
156 outstr("\\r", file
), p
++;
157 else if (wc
== L
'\t')
158 outstr("\\t", file
), p
++;
159 else if (!iswprint(wc
)) {
160 for (; clen
> 0; clen
--)
163 if (wc
== L
'\'' || wc
== L
'\\')
164 outcslow('\\', file
);
165 outbin(p
, clen
, file
);
169 outcslow('\'', file
);
172 /* Like outstr(), but quote for re-input into the shell. */
174 outqstr(const char *p
, struct output
*file
)
182 for (i
= 0; p
[i
] != '\0'; i
++) {
183 if ((p
[i
] > '\0' && p
[i
] < ' ' && p
[i
] != '\n') ||
184 (p
[i
] & 0x80) != 0 || p
[i
] == '\'') {
190 if (p
[strcspn(p
, "|&;<>()$`\\\" \n*?[~#=")] == '\0' ||
191 strcmp(p
, "[") == 0) {
196 outcslow('\'', file
);
198 outcslow('\'', file
);
202 outbin(const void *data
, size_t len
, struct output
*file
)
212 emptyoutbuf(struct output
*dest
)
216 if (dest
->buf
== NULL
) {
218 dest
->buf
= ckmalloc(dest
->bufsize
);
219 dest
->nextc
= dest
->buf
;
220 dest
->bufend
= dest
->buf
+ dest
->bufsize
;
222 } else if (dest
->fd
== MEM_OUT
) {
223 offset
= dest
->nextc
- dest
->buf
;
224 newsize
= dest
->bufsize
<< 1;
226 dest
->buf
= ckrealloc(dest
->buf
, newsize
);
227 dest
->bufsize
= newsize
;
228 dest
->bufend
= dest
->buf
+ newsize
;
229 dest
->nextc
= dest
->buf
+ offset
;
246 flushout(struct output
*dest
)
249 if (dest
->buf
== NULL
|| dest
->nextc
== dest
->buf
|| dest
->fd
< 0)
251 if (xwrite(dest
->fd
, dest
->buf
, dest
->nextc
- dest
->buf
) < 0) {
252 dest
->flags
|= OUTPUT_ERR
;
255 dest
->nextc
= dest
->buf
;
262 output
.nextc
= output
.buf
;
267 outiserror(struct output
*file
)
269 return (file
->flags
& OUTPUT_ERR
);
274 outclearerror(struct output
*file
)
276 file
->flags
&= ~OUTPUT_ERR
;
281 outfmt(struct output
*file
, const char *fmt
, ...)
286 doformat(file
, fmt
, ap
);
292 out1fmt(const char *fmt
, ...)
297 doformat(out1
, fmt
, ap
);
302 out2fmt_flush(const char *fmt
, ...)
307 doformat(out2
, fmt
, ap
);
313 fmtstr(char *outbuf
, int length
, const char *fmt
, ...)
319 vsnprintf(outbuf
, length
, fmt
, ap
);
325 doformat_wr(void *cookie
, const char *buf
, int len
)
329 o
= (struct output
*)cookie
;
336 doformat(struct output
*dest
, const char *f
, va_list ap
)
340 if ((fp
= fwopen(dest
, doformat_wr
)) != NULL
) {
349 return fwopen(out1
, doformat_wr
);
353 * Version of write which resumes after a signal is caught.
357 xwrite(int fd
, const char *buf
, int nbytes
)
366 i
= write(fd
, buf
, n
);
384 * If stdout is non-blocking, use poll
385 * to wait, then retry.
388 pfd
.events
= POLLOUT
;
391 if (pfd
.revents
& (POLLERR
| POLLNVAL
))