output.c revision 1.9 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
37 #ifndef lint
38 static char sccsid[] = "@(#)output.c 8.1 (Berkeley) 5/31/93";
39 #endif /* not lint */
40
41 /*
42 * Shell output routines. We use our own output routines because:
43 * When a builtin command is interrupted we have to discard
44 * any pending output.
45 * When a builtin command appears in back quotes, we want to
46 * save the output of the command in a region obtained
47 * via malloc, rather than doing a fork and reading the
48 * output of the command via a pipe.
49 * Our output routines may be smaller than the stdio routines.
50 */
51
52 #include <stdio.h> /* defines BUFSIZ */
53 #include "shell.h"
54 #include "syntax.h"
55 #include "output.h"
56 #include "memalloc.h"
57 #include "error.h"
58 #ifdef __STDC__
59 #include "stdarg.h"
60 #else
61 #include <varargs.h>
62 #endif
63 #include <errno.h>
64 #include <unistd.h>
65
66
67 #define OUTBUFSIZ BUFSIZ
68 #define BLOCK_OUT -2 /* output to a fixed block of memory */
69 #define MEM_OUT -3 /* output to dynamically allocated memory */
70 #define OUTPUT_ERR 01 /* error occurred on output */
71
72
73 struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0};
74 struct output errout = {NULL, 0, NULL, 100, 2, 0};;
75 struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0};
76 struct output *out1 = &output;
77 struct output *out2 = &errout;
78
79
80
81 #ifdef mkinit
82
83 INCLUDE "output.h"
84 INCLUDE "memalloc.h"
85
86 RESET {
87 out1 = &output;
88 out2 = &errout;
89 if (memout.buf != NULL) {
90 ckfree(memout.buf);
91 memout.buf = NULL;
92 }
93 }
94
95 #endif
96
97
98 #ifdef notdef /* no longer used */
99 /*
100 * Set up an output file to write to memory rather than a file.
101 */
102
103 void
104 open_mem(block, length, file)
105 char *block;
106 int length;
107 struct output *file;
108 {
109 file->nextc = block;
110 file->nleft = --length;
111 file->fd = BLOCK_OUT;
112 file->flags = 0;
113 }
114 #endif
115
116
117 void
118 out1str(p)
119 const char *p;
120 {
121 outstr(p, out1);
122 }
123
124
125 void
126 out2str(p)
127 const char *p;
128 {
129 outstr(p, out2);
130 }
131
132
133 void
134 outstr(p, file)
135 const register char *p;
136 register struct output *file;
137 {
138 while (*p)
139 outc(*p++, file);
140 if (file == out2)
141 flushout(file);
142 }
143
144
145 char out_junk[16];
146
147
148 void
149 emptyoutbuf(dest)
150 struct output *dest;
151 {
152 int offset;
153
154 if (dest->fd == BLOCK_OUT) {
155 dest->nextc = out_junk;
156 dest->nleft = sizeof out_junk;
157 dest->flags |= OUTPUT_ERR;
158 } else if (dest->buf == NULL) {
159 INTOFF;
160 dest->buf = ckmalloc(dest->bufsize);
161 dest->nextc = dest->buf;
162 dest->nleft = dest->bufsize;
163 INTON;
164 } else if (dest->fd == MEM_OUT) {
165 offset = dest->bufsize;
166 INTOFF;
167 dest->bufsize <<= 1;
168 dest->buf = ckrealloc(dest->buf, dest->bufsize);
169 dest->nleft = dest->bufsize - offset;
170 dest->nextc = dest->buf + offset;
171 INTON;
172 } else {
173 flushout(dest);
174 }
175 dest->nleft--;
176 }
177
178
179 void
180 flushall() {
181 flushout(&output);
182 flushout(&errout);
183 }
184
185
186 void
187 flushout(dest)
188 struct output *dest;
189 {
190
191 if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0)
192 return;
193 if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0)
194 dest->flags |= OUTPUT_ERR;
195 dest->nextc = dest->buf;
196 dest->nleft = dest->bufsize;
197 }
198
199
200 void
201 freestdout() {
202 INTOFF;
203 if (output.buf) {
204 ckfree(output.buf);
205 output.buf = NULL;
206 output.nleft = 0;
207 }
208 INTON;
209 }
210
211
212 #ifdef __STDC__
213 void
214 outfmt(struct output *file, char *fmt, ...) {
215 va_list ap;
216
217 va_start(ap, fmt);
218 doformat(file, fmt, ap);
219 va_end(ap);
220 }
221
222
223 void
224 out1fmt(char *fmt, ...) {
225 va_list ap;
226
227 va_start(ap, fmt);
228 doformat(out1, fmt, ap);
229 va_end(ap);
230 }
231
232 void
233 dprintf(char *fmt, ...) {
234 va_list ap;
235
236 va_start(ap, fmt);
237 doformat(out2, fmt, ap);
238 va_end(ap);
239 flushout(out2);
240 }
241
242 void
243 fmtstr(char *outbuf, int length, char *fmt, ...) {
244 va_list ap;
245 struct output strout;
246
247 va_start(ap, fmt);
248 strout.nextc = outbuf;
249 strout.nleft = length;
250 strout.fd = BLOCK_OUT;
251 strout.flags = 0;
252 doformat(&strout, fmt, ap);
253 outc('\0', &strout);
254 if (strout.flags & OUTPUT_ERR)
255 outbuf[length - 1] = '\0';
256 }
257
258 #else /* not __STDC__ */
259
260 void
261 outfmt(va_alist)
262 va_dcl
263 {
264 va_list ap;
265 struct output *file;
266 char *fmt;
267
268 va_start(ap);
269 file = va_arg(ap, struct output *);
270 fmt = va_arg(ap, char *);
271 doformat(file, fmt, ap);
272 va_end(ap);
273 }
274
275
276 void
277 out1fmt(va_alist)
278 va_dcl
279 {
280 va_list ap;
281 char *fmt;
282
283 va_start(ap);
284 fmt = va_arg(ap, char *);
285 doformat(out1, fmt, ap);
286 va_end(ap);
287 }
288
289 void
290 dprintf(va_alist)
291 va_dcl
292 {
293 va_list ap;
294 char *fmt;
295
296 va_start(ap);
297 fmt = va_arg(ap, char *);
298 doformat(out2, fmt, ap);
299 va_end(ap);
300 flushout(out2);
301 }
302
303 void
304 fmtstr(va_alist)
305 va_dcl
306 {
307 va_list ap;
308 struct output strout;
309 char *outbuf;
310 int length;
311 char *fmt;
312
313 va_start(ap);
314 outbuf = va_arg(ap, char *);
315 length = va_arg(ap, int);
316 fmt = va_arg(ap, char *);
317 strout.nextc = outbuf;
318 strout.nleft = length;
319 strout.fd = BLOCK_OUT;
320 strout.flags = 0;
321 doformat(&strout, fmt, ap);
322 outc('\0', &strout);
323 if (strout.flags & OUTPUT_ERR)
324 outbuf[length - 1] = '\0';
325 }
326 #endif /* __STDC__ */
327
328
329 /*
330 * Formatted output. This routine handles a subset of the printf formats:
331 * - Formats supported: d, u, o, X, s, and c.
332 * - The x format is also accepted but is treated like X.
333 * - The l modifier is accepted.
334 * - The - and # flags are accepted; # only works with the o format.
335 * - Width and precision may be specified with any format except c.
336 * - An * may be given for the width or precision.
337 * - The obsolete practice of preceding the width with a zero to get
338 * zero padding is not supported; use the precision field.
339 * - A % may be printed by writing %% in the format string.
340 */
341
342 #define TEMPSIZE 24
343
344 #ifdef __STDC__
345 static const char digit[16] = "0123456789ABCDEF";
346 #else
347 static const char digit[17] = "0123456789ABCDEF";
348 #endif
349
350
351 void
352 doformat(dest, f, ap)
353 register struct output *dest;
354 register char *f; /* format string */
355 va_list ap;
356 {
357 register char c;
358 char temp[TEMPSIZE];
359 int flushleft;
360 int sharp;
361 int width;
362 int prec;
363 int islong;
364 char *p;
365 int sign;
366 long l;
367 unsigned long num;
368 unsigned base;
369 int len;
370 int size;
371 int pad;
372
373 while ((c = *f++) != '\0') {
374 if (c != '%') {
375 outc(c, dest);
376 continue;
377 }
378 flushleft = 0;
379 sharp = 0;
380 width = 0;
381 prec = -1;
382 islong = 0;
383 for (;;) {
384 if (*f == '-')
385 flushleft++;
386 else if (*f == '#')
387 sharp++;
388 else
389 break;
390 f++;
391 }
392 if (*f == '*') {
393 width = va_arg(ap, int);
394 f++;
395 } else {
396 while (is_digit(*f)) {
397 width = 10 * width + digit_val(*f++);
398 }
399 }
400 if (*f == '.') {
401 if (*++f == '*') {
402 prec = va_arg(ap, int);
403 f++;
404 } else {
405 prec = 0;
406 while (is_digit(*f)) {
407 prec = 10 * prec + digit_val(*f++);
408 }
409 }
410 }
411 if (*f == 'l') {
412 islong++;
413 f++;
414 }
415 switch (*f) {
416 case 'd':
417 if (islong)
418 l = va_arg(ap, long);
419 else
420 l = va_arg(ap, int);
421 sign = 0;
422 num = l;
423 if (l < 0) {
424 num = -l;
425 sign = 1;
426 }
427 base = 10;
428 goto number;
429 case 'u':
430 base = 10;
431 goto uns_number;
432 case 'o':
433 base = 8;
434 goto uns_number;
435 case 'x':
436 /* we don't implement 'x'; treat like 'X' */
437 case 'X':
438 base = 16;
439 uns_number: /* an unsigned number */
440 sign = 0;
441 if (islong)
442 num = va_arg(ap, unsigned long);
443 else
444 num = va_arg(ap, unsigned int);
445 number: /* process a number */
446 p = temp + TEMPSIZE - 1;
447 *p = '\0';
448 while (num) {
449 *--p = digit[num % base];
450 num /= base;
451 }
452 len = (temp + TEMPSIZE - 1) - p;
453 if (prec < 0)
454 prec = 1;
455 if (sharp && *f == 'o' && prec <= len)
456 prec = len + 1;
457 pad = 0;
458 if (width) {
459 size = len;
460 if (size < prec)
461 size = prec;
462 size += sign;
463 pad = width - size;
464 if (flushleft == 0) {
465 while (--pad >= 0)
466 outc(' ', dest);
467 }
468 }
469 if (sign)
470 outc('-', dest);
471 prec -= len;
472 while (--prec >= 0)
473 outc('0', dest);
474 while (*p)
475 outc(*p++, dest);
476 while (--pad >= 0)
477 outc(' ', dest);
478 break;
479 case 's':
480 p = va_arg(ap, char *);
481 pad = 0;
482 if (width) {
483 len = strlen(p);
484 if (prec >= 0 && len > prec)
485 len = prec;
486 pad = width - len;
487 if (flushleft == 0) {
488 while (--pad >= 0)
489 outc(' ', dest);
490 }
491 }
492 prec++;
493 while (--prec != 0 && *p)
494 outc(*p++, dest);
495 while (--pad >= 0)
496 outc(' ', dest);
497 break;
498 case 'c':
499 c = va_arg(ap, int);
500 outc(c, dest);
501 break;
502 default:
503 outc(*f, dest);
504 break;
505 }
506 f++;
507 }
508 }
509
510
511
512 /*
513 * Version of write which resumes after a signal is caught.
514 */
515
516 int
517 xwrite(fd, buf, nbytes)
518 int fd;
519 char *buf;
520 int nbytes;
521 {
522 int ntry;
523 int i;
524 int n;
525
526 n = nbytes;
527 ntry = 0;
528 for (;;) {
529 i = write(fd, buf, n);
530 if (i > 0) {
531 if ((n -= i) <= 0)
532 return nbytes;
533 buf += i;
534 ntry = 0;
535 } else if (i == 0) {
536 if (++ntry > 10)
537 return nbytes - n;
538 } else if (errno != EINTR) {
539 return -1;
540 }
541 }
542 }
543
544
545 /*
546 * Version of ioctl that retries after a signal is caught.
547 */
548
549 int
550 xioctl(fd, request, arg) {
551 int i;
552
553 while ((i = ioctl(fd, request, arg)) == -1 && errno == EINTR);
554 return i;
555 }
556