source: trunk/minix/commands/ash/output.c@ 20

Last change on this file since 20 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 10.0 KB
Line 
1/*-
2 * Copyright (c) 1991 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Kenneth Almquist.
7 *
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.
35 */
36
37#ifndef lint
38static char sccsid[] = "@(#)output.c 5.1 (Berkeley) 3/7/91";
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);
139}
140
141
142char out_junk[16];
143
144
145void
146emptyoutbuf(dest)
147 struct output *dest;
148 {
149 int offset;
150
151 if (dest->fd == BLOCK_OUT) {
152 dest->nextc = out_junk;
153 dest->nleft = sizeof out_junk;
154 dest->flags |= OUTPUT_ERR;
155 } else if (dest->buf == NULL) {
156 INTOFF;
157 dest->buf = ckmalloc(dest->bufsize);
158 dest->nextc = dest->buf;
159 dest->nleft = dest->bufsize;
160 INTON;
161 } else if (dest->fd == MEM_OUT) {
162 offset = dest->bufsize;
163 INTOFF;
164 dest->bufsize <<= 1;
165 dest->buf = ckrealloc(dest->buf, dest->bufsize);
166 dest->nleft = dest->bufsize - offset;
167 dest->nextc = dest->buf + offset;
168 INTON;
169 } else {
170 flushout(dest);
171 }
172 dest->nleft--;
173}
174
175
176void
177flushall() {
178 flushout(&output);
179 flushout(&errout);
180}
181
182
183void
184flushout(dest)
185 struct output *dest;
186 {
187
188 if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0)
189 return;
190 if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0)
191 dest->flags |= OUTPUT_ERR;
192 dest->nextc = dest->buf;
193 dest->nleft = dest->bufsize;
194}
195
196
197void
198freestdout() {
199 INTOFF;
200 if (output.buf) {
201 ckfree(output.buf);
202 output.buf = NULL;
203 output.nleft = 0;
204 }
205 INTON;
206}
207
208
209#ifdef __STDC__
210void
211outfmt(struct output *file, char *fmt, ...) {
212 va_list ap;
213
214 va_start(ap, fmt);
215 doformat(file, fmt, ap);
216 va_end(ap);
217}
218
219
220void
221out1fmt(char *fmt, ...) {
222 va_list ap;
223
224 va_start(ap, fmt);
225 doformat(out1, fmt, ap);
226 va_end(ap);
227}
228
229
230void
231fmtstr(char *outbuf, int length, char *fmt, ...) {
232 va_list ap;
233 struct output strout;
234
235 va_start(ap, fmt);
236 strout.nextc = outbuf;
237 strout.nleft = length;
238 strout.fd = BLOCK_OUT;
239 strout.flags = 0;
240 doformat(&strout, fmt, ap);
241 outc('\0', &strout);
242 if (strout.flags & OUTPUT_ERR)
243 outbuf[length - 1] = '\0';
244 va_end(ap);
245}
246
247#else /* not __STDC__ */
248
249void
250outfmt(va_alist)
251 va_dcl
252 {
253 va_list ap;
254 struct output *file;
255 char *fmt;
256
257 va_start(ap);
258 file = va_arg(ap, struct output *);
259 fmt = va_arg(ap, char *);
260 doformat(file, fmt, ap);
261 va_end(ap);
262}
263
264
265void
266out1fmt(va_alist)
267 va_dcl
268 {
269 va_list ap;
270 char *fmt;
271
272 va_start(ap);
273 fmt = va_arg(ap, char *);
274 doformat(out1, fmt, ap);
275 va_end(ap);
276}
277
278
279void
280fmtstr(va_alist)
281 va_dcl
282 {
283 va_list ap;
284 struct output strout;
285 char *outbuf;
286 int length;
287 char *fmt;
288
289 va_start(ap);
290 outbuf = va_arg(ap, char *);
291 length = va_arg(ap, int);
292 fmt = va_arg(ap, char *);
293 strout.nextc = outbuf;
294 strout.nleft = length;
295 strout.fd = BLOCK_OUT;
296 strout.flags = 0;
297 doformat(&strout, fmt, ap);
298 outc('\0', &strout);
299 if (strout.flags & OUTPUT_ERR)
300 outbuf[length - 1] = '\0';
301}
302#endif /* __STDC__ */
303
304
305/*
306 * Formatted output. This routine handles a subset of the printf formats:
307 * - Formats supported: d, u, o, X, s, and c.
308 * - The x format is also accepted but is treated like X.
309 * - The l modifier is accepted.
310 * - The - and # flags are accepted; # only works with the o format.
311 * - Width and precision may be specified with any format except c.
312 * - An * may be given for the width or precision.
313 * - The obsolete practice of preceding the width with a zero to get
314 * zero padding is not supported; use the precision field.
315 * - A % may be printed by writing %% in the format string.
316 */
317
318#define TEMPSIZE 24
319
320#ifdef __STDC__
321static const char digit[16] = "0123456789ABCDEF";
322#else
323static const char digit[17] = "0123456789ABCDEF";
324#endif
325
326
327void
328doformat(dest, f, ap)
329 register struct output *dest;
330 register char *f; /* format string */
331 va_list ap;
332 {
333 register char c;
334 char temp[TEMPSIZE];
335 int flushleft;
336 int sharp;
337 int width;
338 int prec;
339 int islong;
340 char *p;
341 int sign;
342 long l;
343 unsigned long num;
344 unsigned base;
345 int len;
346 int size;
347 int pad;
348
349 while ((c = *f++) != '\0') {
350 if (c != '%') {
351 outc(c, dest);
352 continue;
353 }
354 flushleft = 0;
355 sharp = 0;
356 width = 0;
357 prec = -1;
358 islong = 0;
359 for (;;) {
360 if (*f == '-')
361 flushleft++;
362 else if (*f == '#')
363 sharp++;
364 else
365 break;
366 f++;
367 }
368 if (*f == '*') {
369 width = va_arg(ap, int);
370 f++;
371 } else {
372 while (is_digit(*f)) {
373 width = 10 * width + digit_val(*f++);
374 }
375 }
376 if (*f == '.') {
377 if (*++f == '*') {
378 prec = va_arg(ap, int);
379 f++;
380 } else {
381 prec = 0;
382 while (is_digit(*f)) {
383 prec = 10 * prec + digit_val(*f++);
384 }
385 }
386 }
387 if (*f == 'l') {
388 islong++;
389 f++;
390 }
391 switch (*f) {
392 case 'd':
393 if (islong)
394 l = va_arg(ap, long);
395 else
396 l = va_arg(ap, int);
397 sign = 0;
398 num = l;
399 if (l < 0) {
400 num = -l;
401 sign = 1;
402 }
403 base = 10;
404 goto number;
405 case 'u':
406 base = 10;
407 goto uns_number;
408 case 'o':
409 base = 8;
410 goto uns_number;
411 case 'x':
412 /* we don't implement 'x'; treat like 'X' */
413 case 'X':
414 base = 16;
415uns_number: /* an unsigned number */
416 sign = 0;
417 if (islong)
418 num = va_arg(ap, unsigned long);
419 else
420 num = va_arg(ap, unsigned int);
421number: /* process a number */
422 p = temp + TEMPSIZE - 1;
423 *p = '\0';
424 while (num) {
425 *--p = digit[num % base];
426 num /= base;
427 }
428 len = (temp + TEMPSIZE - 1) - p;
429 if (prec < 0)
430 prec = 1;
431 if (sharp && *f == 'o' && prec <= len)
432 prec = len + 1;
433 pad = 0;
434 if (width) {
435 size = len;
436 if (size < prec)
437 size = prec;
438 size += sign;
439 pad = width - size;
440 if (flushleft == 0) {
441 while (--pad >= 0)
442 outc(' ', dest);
443 }
444 }
445 if (sign)
446 outc('-', dest);
447 prec -= len;
448 while (--prec >= 0)
449 outc('0', dest);
450 while (*p)
451 outc(*p++, dest);
452 while (--pad >= 0)
453 outc(' ', dest);
454 break;
455 case 's':
456 p = va_arg(ap, char *);
457 pad = 0;
458 if (width) {
459 len = strlen(p);
460 if (prec >= 0 && len > prec)
461 len = prec;
462 pad = width - len;
463 if (flushleft == 0) {
464 while (--pad >= 0)
465 outc(' ', dest);
466 }
467 }
468 prec++;
469 while (--prec != 0 && *p)
470 outc(*p++, dest);
471 while (--pad >= 0)
472 outc(' ', dest);
473 break;
474 case 'c':
475 c = va_arg(ap, int);
476 outc(c, dest);
477 break;
478 default:
479 outc(*f, dest);
480 break;
481 }
482 f++;
483 }
484}
485
486
487
488/*
489 * Version of write which resumes after a signal is caught.
490 */
491
492int
493xwrite(fd, buf, nbytes)
494 int fd;
495 char *buf;
496 int nbytes;
497 {
498 int ntry;
499 int i;
500 int n;
501
502 n = nbytes;
503 ntry = 0;
504 for (;;) {
505 i = write(fd, buf, n);
506 if (i > 0) {
507 if ((n -= i) <= 0)
508 return nbytes;
509 buf += i;
510 ntry = 0;
511 } else if (i == 0) {
512 if (++ntry > 10)
513 return nbytes - n;
514 } else if (errno != EINTR) {
515 return -1;
516 }
517 }
518}
519
520
521/*
522 * Version of ioctl that retries after a signal is caught.
523 */
524
525int
526xioctl(fd, request, arg) {
527 int i;
528
529 while ((i = ioctl(fd, request, arg)) == -1 && errno == EINTR);
530 return i;
531}
Note: See TracBrowser for help on using the repository browser.