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