Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/bin/sh/output.c
39564 views
1
/*-
2
* SPDX-License-Identifier: BSD-3-Clause
3
*
4
* Copyright (c) 1991, 1993
5
* The Regents of the University of California. All rights reserved.
6
*
7
* This code is derived from software contributed to Berkeley by
8
* Kenneth Almquist.
9
*
10
* Redistribution and use in source and binary forms, with or without
11
* modification, are permitted provided that the following conditions
12
* are met:
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.
21
*
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
32
* SUCH DAMAGE.
33
*/
34
35
/*
36
* Shell output routines. We use our own output routines because:
37
* When a builtin command is interrupted we have to discard
38
* any pending output.
39
* When a builtin command appears in back quotes, we want to
40
* save the output of the command in a region obtained
41
* via malloc, rather than doing a fork and reading the
42
* output of the command via a pipe.
43
*/
44
45
#include <stdio.h> /* defines BUFSIZ */
46
#include <string.h>
47
#include <stdarg.h>
48
#include <errno.h>
49
#include <unistd.h>
50
#include <stdlib.h>
51
#include <wchar.h>
52
#include <wctype.h>
53
54
#include "shell.h"
55
#include "syntax.h"
56
#include "output.h"
57
#include "memalloc.h"
58
#include "error.h"
59
#include "var.h"
60
61
62
#define OUTBUFSIZ BUFSIZ
63
#define MEM_OUT -2 /* output to dynamically allocated memory */
64
#define OUTPUT_ERR 01 /* error occurred on output */
65
66
static int doformat_wr(void *, const char *, int);
67
68
struct output output = {NULL, NULL, NULL, OUTBUFSIZ, 1, 0};
69
struct output errout = {NULL, NULL, NULL, 256, 2, 0};
70
struct output memout = {NULL, NULL, NULL, 64, MEM_OUT, 0};
71
struct output *out1 = &output;
72
struct output *out2 = &errout;
73
74
void
75
outcslow(int c, struct output *file)
76
{
77
outc(c, file);
78
}
79
80
void
81
out1str(const char *p)
82
{
83
outstr(p, out1);
84
}
85
86
void
87
out1qstr(const char *p)
88
{
89
outqstr(p, out1);
90
}
91
92
void
93
out2str(const char *p)
94
{
95
outstr(p, out2);
96
}
97
98
void
99
out2qstr(const char *p)
100
{
101
outqstr(p, out2);
102
}
103
104
void
105
outstr(const char *p, struct output *file)
106
{
107
outbin(p, strlen(p), file);
108
}
109
110
static void
111
byteseq(int ch, struct output *file)
112
{
113
char seq[4];
114
115
seq[0] = '\\';
116
seq[1] = (ch >> 6 & 0x3) + '0';
117
seq[2] = (ch >> 3 & 0x7) + '0';
118
seq[3] = (ch & 0x7) + '0';
119
outbin(seq, 4, file);
120
}
121
122
static void
123
outdqstr(const char *p, struct output *file)
124
{
125
const char *end;
126
mbstate_t mbs;
127
size_t clen;
128
wchar_t wc;
129
130
memset(&mbs, '\0', sizeof(mbs));
131
end = p + strlen(p);
132
outstr("$'", file);
133
while ((clen = mbrtowc(&wc, p, end - p + 1, &mbs)) != 0) {
134
if (clen == (size_t)-2) {
135
while (p < end)
136
byteseq(*p++, file);
137
break;
138
}
139
if (clen == (size_t)-1) {
140
memset(&mbs, '\0', sizeof(mbs));
141
byteseq(*p++, file);
142
continue;
143
}
144
if (wc == L'\n')
145
outcslow('\n', file), p++;
146
else if (wc == L'\r')
147
outstr("\\r", file), p++;
148
else if (wc == L'\t')
149
outstr("\\t", file), p++;
150
else if (!iswprint(wc)) {
151
for (; clen > 0; clen--)
152
byteseq(*p++, file);
153
} else {
154
if (wc == L'\'' || wc == L'\\')
155
outcslow('\\', file);
156
outbin(p, clen, file);
157
p += clen;
158
}
159
}
160
outcslow('\'', file);
161
}
162
163
/* Like outstr(), but quote for re-input into the shell. */
164
void
165
outqstr(const char *p, struct output *file)
166
{
167
int i;
168
169
if (p[0] == '\0') {
170
outstr("''", file);
171
return;
172
}
173
for (i = 0; p[i] != '\0'; i++) {
174
if ((p[i] > '\0' && p[i] < ' ' && p[i] != '\n') ||
175
(p[i] & 0x80) != 0 || p[i] == '\'') {
176
outdqstr(p, file);
177
return;
178
}
179
}
180
181
if (p[strcspn(p, "|&;<>()$`\\\" \n*?[~#=")] == '\0' ||
182
strcmp(p, "[") == 0) {
183
outstr(p, file);
184
return;
185
}
186
187
outcslow('\'', file);
188
outstr(p, file);
189
outcslow('\'', file);
190
}
191
192
void
193
outbin(const void *data, size_t len, struct output *file)
194
{
195
const char *p;
196
197
p = data;
198
while (len-- > 0)
199
outc(*p++, file);
200
}
201
202
void
203
emptyoutbuf(struct output *dest)
204
{
205
int offset, newsize;
206
207
if (dest->buf == NULL) {
208
INTOFF;
209
dest->buf = ckmalloc(dest->bufsize);
210
dest->nextc = dest->buf;
211
dest->bufend = dest->buf + dest->bufsize;
212
INTON;
213
} else if (dest->fd == MEM_OUT) {
214
offset = dest->nextc - dest->buf;
215
newsize = dest->bufsize << 1;
216
INTOFF;
217
dest->buf = ckrealloc(dest->buf, newsize);
218
dest->bufsize = newsize;
219
dest->bufend = dest->buf + newsize;
220
dest->nextc = dest->buf + offset;
221
INTON;
222
} else {
223
flushout(dest);
224
}
225
}
226
227
228
void
229
flushall(void)
230
{
231
flushout(&output);
232
flushout(&errout);
233
}
234
235
236
void
237
flushout(struct output *dest)
238
{
239
240
if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0)
241
return;
242
if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0)
243
dest->flags |= OUTPUT_ERR;
244
dest->nextc = dest->buf;
245
}
246
247
248
void
249
freestdout(void)
250
{
251
output.nextc = output.buf;
252
}
253
254
255
int
256
outiserror(struct output *file)
257
{
258
return (file->flags & OUTPUT_ERR);
259
}
260
261
262
void
263
outclearerror(struct output *file)
264
{
265
file->flags &= ~OUTPUT_ERR;
266
}
267
268
269
void
270
outfmt(struct output *file, const char *fmt, ...)
271
{
272
va_list ap;
273
274
va_start(ap, fmt);
275
doformat(file, fmt, ap);
276
va_end(ap);
277
}
278
279
280
void
281
out1fmt(const char *fmt, ...)
282
{
283
va_list ap;
284
285
va_start(ap, fmt);
286
doformat(out1, fmt, ap);
287
va_end(ap);
288
}
289
290
void
291
out2fmt_flush(const char *fmt, ...)
292
{
293
va_list ap;
294
295
va_start(ap, fmt);
296
doformat(out2, fmt, ap);
297
va_end(ap);
298
flushout(out2);
299
}
300
301
void
302
fmtstr(char *outbuf, int length, const char *fmt, ...)
303
{
304
va_list ap;
305
306
INTOFF;
307
va_start(ap, fmt);
308
vsnprintf(outbuf, length, fmt, ap);
309
va_end(ap);
310
INTON;
311
}
312
313
static int
314
doformat_wr(void *cookie, const char *buf, int len)
315
{
316
struct output *o;
317
318
o = (struct output *)cookie;
319
outbin(buf, len, o);
320
321
return (len);
322
}
323
324
void
325
doformat(struct output *dest, const char *f, va_list ap)
326
{
327
FILE *fp;
328
329
if ((fp = fwopen(dest, doformat_wr)) != NULL) {
330
vfprintf(fp, f, ap);
331
fclose(fp);
332
}
333
}
334
335
FILE *
336
out1fp(void)
337
{
338
return fwopen(out1, doformat_wr);
339
}
340
341
/*
342
* Version of write which resumes after a signal is caught.
343
*/
344
345
int
346
xwrite(int fd, const char *buf, int nbytes)
347
{
348
int ntry;
349
int i;
350
int n;
351
352
n = nbytes;
353
ntry = 0;
354
for (;;) {
355
i = write(fd, buf, n);
356
if (i > 0) {
357
if ((n -= i) <= 0)
358
return nbytes;
359
buf += i;
360
ntry = 0;
361
} else if (i == 0) {
362
if (++ntry > 10)
363
return nbytes - n;
364
} else if (errno != EINTR) {
365
return -1;
366
}
367
}
368
}
369
370