unstack, sort: cleanup and improvement
[minix.git] / commands / ash / output.c
bloba1e8f2d2feba4923730b080b54d51d52597cd470
1 /*-
2 * Copyright (c) 1991, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Kenneth Almquist.
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 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
33 #ifndef lint
34 static char sccsid[] = "@(#)output.c 8.1 (Berkeley) 5/31/93";
35 #endif /* not lint */
38 * Shell output routines. We use our own output routines because:
39 * When a builtin command is interrupted we have to discard
40 * any pending output.
41 * When a builtin command appears in back quotes, we want to
42 * save the output of the command in a region obtained
43 * via malloc, rather than doing a fork and reading the
44 * output of the command via a pipe.
45 * Our output routines may be smaller than the stdio routines.
48 #include <stdio.h> /* defines BUFSIZ */
49 #include "shell.h"
50 #include "syntax.h"
51 #include "output.h"
52 #include "memalloc.h"
53 #include "error.h"
54 #include "var.h"
55 #ifdef __STDC__
56 #include "stdarg.h"
57 #else
58 #include <varargs.h>
59 #endif
60 #include <errno.h>
61 #include <string.h>
62 #include <stdlib.h>
63 #include <unistd.h>
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 */
72 struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0};
73 struct output errout = {NULL, 0, NULL, 100, 2, 0};
74 struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0};
75 struct output *out1 = &output;
76 struct output *out2 = &errout;
80 #ifdef mkinit
82 INCLUDE "output.h"
83 INCLUDE "memalloc.h"
85 RESET {
86 out1 = &output;
87 out2 = &errout;
88 if (memout.buf != NULL) {
89 ckfree(memout.buf);
90 memout.buf = NULL;
94 #endif
97 #ifdef notdef /* no longer used */
99 * Set up an output file to write to memory rather than a file.
102 void
103 open_mem(block, length, file)
104 char *block;
105 int length;
106 struct output *file;
108 file->nextc = block;
109 file->nleft = --length;
110 file->fd = BLOCK_OUT;
111 file->flags = 0;
113 #endif
116 void
117 out1str(p)
118 const char *p;
120 outstr(p, out1);
123 void
124 out1qstr(const char *p)
126 outqstr(p, out1);
130 void
131 out2str(const char *p)
133 outstr(p, out2);
137 void
138 outstr(p, file)
139 register const char *p;
140 register struct output *file;
142 while (*p)
143 outc(*p++, file);
144 if (file == out2)
145 flushout(file);
148 /* Like outstr(), but quote for re-input into the shell. */
149 void
150 outqstr(const char *p, struct output *file)
152 char ch;
154 if (p[strcspn(p, "|&;<>()$`\\\"'")] == '\0' && (!ifsset() ||
155 p[strcspn(p, ifsval())] == '\0')) {
156 outstr(p, file);
157 return;
160 out1c('\'');
161 while ((ch = *p++) != '\0') {
162 switch (ch) {
163 case '\'':
165 * Can't quote single quotes inside single quotes;
166 * close them, write escaped single quote, open again.
168 outstr("'\\''", file);
169 break;
170 default:
171 outc(ch, file);
174 out1c('\'');
178 char out_junk[16];
181 void
182 emptyoutbuf(dest)
183 struct output *dest;
185 int offset;
187 if (dest->fd == BLOCK_OUT) {
188 dest->nextc = out_junk;
189 dest->nleft = sizeof out_junk;
190 dest->flags |= OUTPUT_ERR;
191 } else if (dest->buf == NULL) {
192 INTOFF;
193 dest->buf = ckmalloc(dest->bufsize);
194 dest->nextc = dest->buf;
195 dest->nleft = dest->bufsize;
196 INTON;
197 } else if (dest->fd == MEM_OUT) {
198 offset = dest->bufsize;
199 INTOFF;
200 dest->bufsize <<= 1;
201 dest->buf = ckrealloc(dest->buf, dest->bufsize);
202 dest->nleft = dest->bufsize - offset;
203 dest->nextc = dest->buf + offset;
204 INTON;
205 } else {
206 flushout(dest);
208 dest->nleft--;
212 void
213 flushall() {
214 flushout(&output);
215 flushout(&errout);
219 void
220 flushout(dest)
221 struct output *dest;
224 if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0)
225 return;
226 if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0)
227 dest->flags |= OUTPUT_ERR;
228 dest->nextc = dest->buf;
229 dest->nleft = dest->bufsize;
233 void
234 freestdout() {
235 INTOFF;
236 if (output.buf) {
237 ckfree(output.buf);
238 output.buf = NULL;
239 output.nleft = 0;
241 INTON;
245 #ifdef __STDC__
246 void
247 outfmt(struct output *file, const char *fmt, ...)
249 va_list ap;
251 va_start(ap, fmt);
252 doformat(file, fmt, ap);
253 va_end(ap);
257 void
258 out1fmt(const char *fmt, ...)
260 va_list ap;
262 va_start(ap, fmt);
263 doformat(out1, fmt, ap);
264 va_end(ap);
267 void
268 dbgprintf(const char *fmt, ...)
270 va_list ap;
272 va_start(ap, fmt);
273 doformat(out2, fmt, ap);
274 va_end(ap);
275 flushout(out2);
278 void
279 fmtstr(char *outbuf, int length, const char *fmt, ...)
281 va_list ap;
282 struct output strout;
284 va_start(ap, fmt);
285 strout.nextc = outbuf;
286 strout.nleft = length;
287 strout.fd = BLOCK_OUT;
288 strout.flags = 0;
289 doformat(&strout, fmt, ap);
290 outc('\0', &strout);
291 if (strout.flags & OUTPUT_ERR)
292 outbuf[length - 1] = '\0';
293 va_end(ap);
296 #else /* not __STDC__ */
298 void
299 outfmt(va_alist)
300 va_dcl
302 va_list ap;
303 struct output *file;
304 char *fmt;
306 va_start(ap);
307 file = va_arg(ap, struct output *);
308 fmt = va_arg(ap, char *);
309 doformat(file, fmt, ap);
310 va_end(ap);
314 void
315 out1fmt(va_alist)
316 va_dcl
318 va_list ap;
319 char *fmt;
321 va_start(ap);
322 fmt = va_arg(ap, char *);
323 doformat(out1, fmt, ap);
324 va_end(ap);
327 void
328 dbgprintf(va_alist)
329 va_dcl
331 va_list ap;
332 char *fmt;
334 va_start(ap);
335 fmt = va_arg(ap, char *);
336 doformat(out2, fmt, ap);
337 va_end(ap);
338 flushout(out2);
341 void
342 fmtstr(va_alist)
343 va_dcl
345 va_list ap;
346 struct output strout;
347 char *outbuf;
348 int length;
349 char *fmt;
351 va_start(ap);
352 outbuf = va_arg(ap, char *);
353 length = va_arg(ap, int);
354 fmt = va_arg(ap, char *);
355 strout.nextc = outbuf;
356 strout.nleft = length;
357 strout.fd = BLOCK_OUT;
358 strout.flags = 0;
359 doformat(&strout, fmt, ap);
360 outc('\0', &strout);
361 if (strout.flags & OUTPUT_ERR)
362 outbuf[length - 1] = '\0';
364 #endif /* __STDC__ */
368 * Formatted output. This routine handles a subset of the printf formats:
369 * - Formats supported: d, u, o, X, s, and c.
370 * - The x format is also accepted but is treated like X.
371 * - The l modifier is accepted.
372 * - The - and # flags are accepted; # only works with the o format.
373 * - Width and precision may be specified with any format except c.
374 * - An * may be given for the width or precision.
375 * - The obsolete practice of preceding the width with a zero to get
376 * zero padding is not supported; use the precision field.
377 * - A % may be printed by writing %% in the format string.
380 #define TEMPSIZE 24
382 #ifdef __STDC__
383 static const char digit[16] = "0123456789ABCDEF";
384 #else
385 static const char digit[17] = "0123456789ABCDEF";
386 #endif
389 void
390 doformat(struct output *dest, const char *f, va_list ap)
392 register char c;
393 char temp[TEMPSIZE];
394 int flushleft;
395 int sharp;
396 int width;
397 int prec;
398 int islong;
399 char *p;
400 int sign;
401 long l;
402 unsigned long num;
403 unsigned base;
404 int len;
405 int size;
406 int pad;
408 while ((c = *f++) != '\0') {
409 if (c != '%') {
410 outc(c, dest);
411 continue;
413 flushleft = 0;
414 sharp = 0;
415 width = 0;
416 prec = -1;
417 islong = 0;
418 for (;;) {
419 if (*f == '-')
420 flushleft++;
421 else if (*f == '#')
422 sharp++;
423 else
424 break;
425 f++;
427 if (*f == '*') {
428 width = va_arg(ap, int);
429 f++;
430 } else {
431 while (is_digit(*f)) {
432 width = 10 * width + digit_val(*f++);
435 if (*f == '.') {
436 if (*++f == '*') {
437 prec = va_arg(ap, int);
438 f++;
439 } else {
440 prec = 0;
441 while (is_digit(*f)) {
442 prec = 10 * prec + digit_val(*f++);
446 if (*f == 'l') {
447 islong++;
448 f++;
450 switch (*f) {
451 case 'd':
452 if (islong)
453 l = va_arg(ap, long);
454 else
455 l = va_arg(ap, int);
456 sign = 0;
457 num = l;
458 if (l < 0) {
459 num = -l;
460 sign = 1;
462 base = 10;
463 goto number;
464 case 'u':
465 base = 10;
466 goto uns_number;
467 case 'o':
468 base = 8;
469 goto uns_number;
470 case 'x':
471 /* we don't implement 'x'; treat like 'X' */
472 case 'X':
473 base = 16;
474 uns_number: /* an unsigned number */
475 sign = 0;
476 if (islong)
477 num = va_arg(ap, unsigned long);
478 else
479 num = va_arg(ap, unsigned int);
480 number: /* process a number */
481 p = temp + TEMPSIZE - 1;
482 *p = '\0';
483 while (num) {
484 *--p = digit[num % base];
485 num /= base;
487 len = (temp + TEMPSIZE - 1) - p;
488 if (prec < 0)
489 prec = 1;
490 if (sharp && *f == 'o' && prec <= len)
491 prec = len + 1;
492 pad = 0;
493 if (width) {
494 size = len;
495 if (size < prec)
496 size = prec;
497 size += sign;
498 pad = width - size;
499 if (flushleft == 0) {
500 while (--pad >= 0)
501 outc(' ', dest);
504 if (sign)
505 outc('-', dest);
506 prec -= len;
507 while (--prec >= 0)
508 outc('0', dest);
509 while (*p)
510 outc(*p++, dest);
511 while (--pad >= 0)
512 outc(' ', dest);
513 break;
514 case 's':
515 p = va_arg(ap, char *);
516 pad = 0;
517 if (width) {
518 len = strlen(p);
519 if (prec >= 0 && len > prec)
520 len = prec;
521 pad = width - len;
522 if (flushleft == 0) {
523 while (--pad >= 0)
524 outc(' ', dest);
527 prec++;
528 while (--prec != 0 && *p)
529 outc(*p++, dest);
530 while (--pad >= 0)
531 outc(' ', dest);
532 break;
533 case 'c':
534 c = va_arg(ap, int);
535 outc(c, dest);
536 break;
537 default:
538 outc(*f, dest);
539 break;
541 f++;
548 * Version of write which resumes after a signal is caught.
552 xwrite(fd, buf, nbytes)
553 int fd;
554 char *buf;
555 int nbytes;
557 int ntry;
558 int i;
559 int n;
561 n = nbytes;
562 ntry = 0;
563 for (;;) {
564 i = write(fd, buf, n);
565 if (i > 0) {
566 if ((n -= i) <= 0)
567 return nbytes;
568 buf += i;
569 ntry = 0;
570 } else if (i == 0) {
571 if (++ntry > 10)
572 return nbytes - n;
573 } else if (errno != EINTR) {
574 return -1;
580 * $PchId: output.c,v 1.6 2006/05/22 12:46:03 philip Exp $