output.c revision 1.15 1 /* $NetBSD: output.c,v 1.15 1995/09/14 16:19:06 jtc 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.15 1995/09/14 16:19:06 jtc 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 #ifdef __STDC__
357 static const char digit[16] = "0123456789ABCDEF";
358 #else
359 static const char digit[17] = "0123456789ABCDEF";
360 #endif
361
362
363 void
364 doformat(dest, f, ap)
365 register struct output *dest;
366 register char *f; /* format string */
367 va_list ap;
368 {
369 register char c;
370 char temp[TEMPSIZE];
371 int flushleft;
372 int sharp;
373 int width;
374 int prec;
375 int islong;
376 int isquad;
377 char *p;
378 int sign;
379 quad_t l;
380 u_quad_t num;
381 unsigned base;
382 int len;
383 int size;
384 int pad;
385
386 while ((c = *f++) != '\0') {
387 if (c != '%') {
388 outc(c, dest);
389 continue;
390 }
391 flushleft = 0;
392 sharp = 0;
393 width = 0;
394 prec = -1;
395 islong = 0;
396 isquad = 0;
397 for (;;) {
398 if (*f == '-')
399 flushleft++;
400 else if (*f == '#')
401 sharp++;
402 else
403 break;
404 f++;
405 }
406 if (*f == '*') {
407 width = va_arg(ap, int);
408 f++;
409 } else {
410 while (is_digit(*f)) {
411 width = 10 * width + digit_val(*f++);
412 }
413 }
414 if (*f == '.') {
415 if (*++f == '*') {
416 prec = va_arg(ap, int);
417 f++;
418 } else {
419 prec = 0;
420 while (is_digit(*f)) {
421 prec = 10 * prec + digit_val(*f++);
422 }
423 }
424 }
425 if (*f == 'l') {
426 islong++;
427 f++;
428 } else if (*f == 'q') {
429 isquad++;
430 f++;
431 }
432 switch (*f) {
433 case 'd':
434 if (isquad)
435 l = va_arg(ap, quad_t);
436 else if (islong)
437 l = va_arg(ap, long);
438 else
439 l = va_arg(ap, int);
440 sign = 0;
441 num = l;
442 if (l < 0) {
443 num = -l;
444 sign = 1;
445 }
446 base = 10;
447 goto number;
448 case 'u':
449 base = 10;
450 goto uns_number;
451 case 'o':
452 base = 8;
453 goto uns_number;
454 case 'x':
455 /* we don't implement 'x'; treat like 'X' */
456 case 'X':
457 base = 16;
458 uns_number: /* an unsigned number */
459 sign = 0;
460 if (isquad)
461 num = va_arg(ap, u_quad_t);
462 else if (islong)
463 num = va_arg(ap, unsigned long);
464 else
465 num = va_arg(ap, unsigned int);
466 number: /* process a number */
467 p = temp + TEMPSIZE - 1;
468 *p = '\0';
469 while (num) {
470 *--p = digit[num % base];
471 num /= base;
472 }
473 len = (temp + TEMPSIZE - 1) - p;
474 if (prec < 0)
475 prec = 1;
476 if (sharp && *f == 'o' && prec <= len)
477 prec = len + 1;
478 pad = 0;
479 if (width) {
480 size = len;
481 if (size < prec)
482 size = prec;
483 size += sign;
484 pad = width - size;
485 if (flushleft == 0) {
486 while (--pad >= 0)
487 outc(' ', dest);
488 }
489 }
490 if (sign)
491 outc('-', dest);
492 prec -= len;
493 while (--prec >= 0)
494 outc('0', dest);
495 while (*p)
496 outc(*p++, dest);
497 while (--pad >= 0)
498 outc(' ', dest);
499 break;
500 case 's':
501 p = va_arg(ap, char *);
502 pad = 0;
503 if (width) {
504 len = strlen(p);
505 if (prec >= 0 && len > prec)
506 len = prec;
507 pad = width - len;
508 if (flushleft == 0) {
509 while (--pad >= 0)
510 outc(' ', dest);
511 }
512 }
513 prec++;
514 while (--prec != 0 && *p)
515 outc(*p++, dest);
516 while (--pad >= 0)
517 outc(' ', dest);
518 break;
519 case 'c':
520 c = va_arg(ap, int);
521 outc(c, dest);
522 break;
523 default:
524 outc(*f, dest);
525 break;
526 }
527 f++;
528 }
529 }
530
531
532
533 /*
534 * Version of write which resumes after a signal is caught.
535 */
536
537 int
538 xwrite(fd, buf, nbytes)
539 int fd;
540 char *buf;
541 int nbytes;
542 {
543 int ntry;
544 int i;
545 int n;
546
547 n = nbytes;
548 ntry = 0;
549 for (;;) {
550 i = write(fd, buf, n);
551 if (i > 0) {
552 if ((n -= i) <= 0)
553 return nbytes;
554 buf += i;
555 ntry = 0;
556 } else if (i == 0) {
557 if (++ntry > 10)
558 return nbytes - n;
559 } else if (errno != EINTR) {
560 return -1;
561 }
562 }
563 }
564
565
566 /*
567 * Version of ioctl that retries after a signal is caught.
568 * XXX unused function
569 */
570
571 int
572 xioctl(fd, request, arg)
573 int fd;
574 unsigned long request;
575 char * arg;
576 {
577 int i;
578
579 while ((i = ioctl(fd, request, arg)) == -1 && errno == EINTR);
580 return i;
581 }
582