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