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