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