Merge branch 'vendor/FLEX'
[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: src/bin/sh/output.c,v 1.28 2010/12/11 17:47:27 jilles Exp $
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 void
242 outfmt(struct output *file, const char *fmt, ...)
243 {
244         va_list ap;
245
246         va_start(ap, fmt);
247         doformat(file, fmt, ap);
248         va_end(ap);
249 }
250
251
252 void
253 out1fmt(const char *fmt, ...)
254 {
255         va_list ap;
256
257         va_start(ap, fmt);
258         doformat(out1, fmt, ap);
259         va_end(ap);
260 }
261
262 void
263 out2fmt_flush(const char *fmt, ...)
264 {
265         va_list ap;
266
267         va_start(ap, fmt);
268         doformat(out2, fmt, ap);
269         va_end(ap);
270         flushout(out2);
271 }
272
273 void
274 fmtstr(char *outbuf, int length, const char *fmt, ...)
275 {
276         va_list ap;
277
278         INTOFF;
279         va_start(ap, fmt);
280         vsnprintf(outbuf, length, fmt, ap);
281         va_end(ap);
282         INTON;
283 }
284
285 static int
286 doformat_wr(void *cookie, const char *buf, int len)
287 {
288         struct output *o;
289
290         o = (struct output *)cookie;
291         outbin(buf, len, o);
292
293         return (len);
294 }
295
296 void
297 doformat(struct output *dest, const char *f, va_list ap)
298 {
299         FILE *fp;
300
301         if ((fp = fwopen(dest, doformat_wr)) != NULL) {
302                 vfprintf(fp, f, ap);
303                 fclose(fp);
304         }
305 }
306
307 /*
308  * Version of write which resumes after a signal is caught.
309  */
310
311 int
312 xwrite(int fd, const char *buf, int nbytes)
313 {
314         int ntry;
315         int i;
316         int n;
317
318         n = nbytes;
319         ntry = 0;
320         for (;;) {
321                 i = write(fd, buf, n);
322                 if (i > 0) {
323                         if ((n -= i) <= 0)
324                                 return nbytes;
325                         buf += i;
326                         ntry = 0;
327                 } else if (i == 0) {
328                         if (++ntry > 10)
329                                 return nbytes - n;
330                 } else if (errno != EINTR) {
331                         return -1;
332                 }
333         }
334 }