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