Merge branch 'vendor/DIFFUTILS'
[dragonfly.git] / bin / sh / output.c
1 /*-
2  * Copyright (c) 1991, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Kenneth Almquist.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed by the University of
19  *      California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  * @(#)output.c 8.2 (Berkeley) 5/4/95
37  * $FreeBSD: head/bin/sh/output.c 244162 2012-12-12 22:01:10Z jilles $
38  */
39
40 /*
41  * Shell output routines.  We use our own output routines because:
42  *      When a builtin command is interrupted we have to discard
43  *              any pending output.
44  *      When a builtin command appears in back quotes, we want to
45  *              save the output of the command in a region obtained
46  *              via malloc, rather than doing a fork and reading the
47  *              output of the command via a pipe.
48  */
49
50 #include <stdio.h>      /* defines BUFSIZ */
51 #include <string.h>
52 #include <stdarg.h>
53 #include <errno.h>
54 #include <unistd.h>
55 #include <stdlib.h>
56
57 #include "shell.h"
58 #include "syntax.h"
59 #include "output.h"
60 #include "memalloc.h"
61 #include "error.h"
62 #include "var.h"
63
64
65 #define OUTBUFSIZ BUFSIZ
66 #define MEM_OUT -2              /* output to dynamically allocated memory */
67 #define OUTPUT_ERR 01           /* error occurred on output */
68
69 static int doformat_wr(void *, const char *, int);
70
71 struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0};
72 struct output errout = {NULL, 0, NULL, 256, 2, 0};
73 struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0};
74 struct output *out1 = &output;
75 struct output *out2 = &errout;
76
77
78
79 #ifdef mkinit
80
81 INCLUDE "output.h"
82 INCLUDE "memalloc.h"
83
84 RESET {
85         out1 = &output;
86         out2 = &errout;
87         if (memout.buf != NULL) {
88                 ckfree(memout.buf);
89                 memout.buf = NULL;
90         }
91 }
92
93 #endif
94
95
96 void
97 outcslow(int c, struct output *file)
98 {
99         outc(c, file);
100 }
101
102 void
103 out1str(const char *p)
104 {
105         outstr(p, out1);
106 }
107
108 void
109 out1qstr(const char *p)
110 {
111         outqstr(p, out1);
112 }
113
114 void
115 out2str(const char *p)
116 {
117         outstr(p, out2);
118 }
119
120 void
121 out2qstr(const char *p)
122 {
123         outqstr(p, out2);
124 }
125
126 void
127 outstr(const char *p, struct output *file)
128 {
129         outbin(p, strlen(p), file);
130 }
131
132 /* Like outstr(), but quote for re-input into the shell. */
133 void
134 outqstr(const char *p, struct output *file)
135 {
136         char ch;
137         int inquotes;
138
139         if (p[0] == '\0') {
140                 outstr("''", file);
141                 return;
142         }
143         /* Caller will handle '=' if necessary */
144         if (p[strcspn(p, "|&;<>()$`\\\"' \t\n*?[~#")] == '\0' ||
145                         strcmp(p, "[") == 0) {
146                 outstr(p, file);
147                 return;
148         }
149
150         inquotes = 0;
151         while ((ch = *p++) != '\0') {
152                 switch (ch) {
153                 case '\'':
154                         /* Can't quote single quotes inside single quotes. */
155                         if (inquotes)
156                                 outcslow('\'', file);
157                         inquotes = 0;
158                         outstr("\\'", file);
159                         break;
160                 default:
161                         if (!inquotes)
162                                 outcslow('\'', file);
163                         inquotes = 1;
164                         outc(ch, file);
165                 }
166         }
167         if (inquotes)
168                 outcslow('\'', file);
169 }
170
171 void
172 outbin(const void *data, size_t len, struct output *file)
173 {
174         const char *p;
175
176         p = data;
177         while (len-- > 0)
178                 outc(*p++, file);
179 }
180
181 void
182 emptyoutbuf(struct output *dest)
183 {
184         int offset;
185
186         if (dest->buf == NULL) {
187                 INTOFF;
188                 dest->buf = ckmalloc(dest->bufsize);
189                 dest->nextc = dest->buf;
190                 dest->nleft = dest->bufsize;
191                 INTON;
192         } else if (dest->fd == MEM_OUT) {
193                 offset = dest->bufsize;
194                 INTOFF;
195                 dest->bufsize <<= 1;
196                 dest->buf = ckrealloc(dest->buf, dest->bufsize);
197                 dest->nleft = dest->bufsize - offset;
198                 dest->nextc = dest->buf + offset;
199                 INTON;
200         } else {
201                 flushout(dest);
202         }
203         dest->nleft--;
204 }
205
206
207 void
208 flushall(void)
209 {
210         flushout(&output);
211         flushout(&errout);
212 }
213
214
215 void
216 flushout(struct output *dest)
217 {
218
219         if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0)
220                 return;
221         if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0)
222                 dest->flags |= OUTPUT_ERR;
223         dest->nextc = dest->buf;
224         dest->nleft = dest->bufsize;
225 }
226
227
228 void
229 freestdout(void)
230 {
231         INTOFF;
232         if (output.buf) {
233                 ckfree(output.buf);
234                 output.buf = NULL;
235                 output.nleft = 0;
236         }
237         INTON;
238 }
239
240
241 int
242 outiserror(struct output *file)
243 {
244         return (file->flags & OUTPUT_ERR);
245 }
246
247
248 void
249 outclearerror(struct output *file)
250 {
251         file->flags &= ~OUTPUT_ERR;
252 }
253
254
255 void
256 outfmt(struct output *file, const char *fmt, ...)
257 {
258         va_list ap;
259
260         va_start(ap, fmt);
261         doformat(file, fmt, ap);
262         va_end(ap);
263 }
264
265
266 void
267 out1fmt(const char *fmt, ...)
268 {
269         va_list ap;
270
271         va_start(ap, fmt);
272         doformat(out1, fmt, ap);
273         va_end(ap);
274 }
275
276 void
277 out2fmt_flush(const char *fmt, ...)
278 {
279         va_list ap;
280
281         va_start(ap, fmt);
282         doformat(out2, fmt, ap);
283         va_end(ap);
284         flushout(out2);
285 }
286
287 void
288 fmtstr(char *outbuf, int length, const char *fmt, ...)
289 {
290         va_list ap;
291
292         INTOFF;
293         va_start(ap, fmt);
294         vsnprintf(outbuf, length, fmt, ap);
295         va_end(ap);
296         INTON;
297 }
298
299 static int
300 doformat_wr(void *cookie, const char *buf, int len)
301 {
302         struct output *o;
303
304         o = (struct output *)cookie;
305         outbin(buf, len, o);
306
307         return (len);
308 }
309
310 void
311 doformat(struct output *dest, const char *f, va_list ap)
312 {
313         FILE *fp;
314
315         if ((fp = fwopen(dest, doformat_wr)) != NULL) {
316                 vfprintf(fp, f, ap);
317                 fclose(fp);
318         }
319 }
320
321 /*
322  * Version of write which resumes after a signal is caught.
323  */
324
325 int
326 xwrite(int fd, const char *buf, int nbytes)
327 {
328         int ntry;
329         int i;
330         int n;
331
332         n = nbytes;
333         ntry = 0;
334         for (;;) {
335                 i = write(fd, buf, n);
336                 if (i > 0) {
337                         if ((n -= i) <= 0)
338                                 return nbytes;
339                         buf += i;
340                         ntry = 0;
341                 } else if (i == 0) {
342                         if (++ntry > 10)
343                                 return nbytes - n;
344                 } else if (errno != EINTR) {
345                         return -1;
346                 }
347         }
348 }