source: mainline/uspace/app/ash/output.c@ 8ccd2ea

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 8ccd2ea was c28a023, checked in by Josef Cejka <malyzelenyhnus@…>, 17 years ago

Initial commit of ash shell.
It cannot be compiled yet.

  • Property mode set to 100644
File size: 12.2 KB
RevLine 
[c28a023]1/* $NetBSD: output.c,v 1.23 2001/01/07 23:39:07 lukem Exp $ */
2
3/*-
4 * Copyright (c) 1991, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Kenneth Almquist.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 */
38
39#include <sys/cdefs.h>
40#ifndef lint
41#if 0
42static char sccsid[] = "@(#)output.c 8.2 (Berkeley) 5/4/95";
43#else
44__RCSID("$NetBSD: output.c,v 1.23 2001/01/07 23:39:07 lukem Exp $");
45#endif
46#endif /* not lint */
47
48/*
49 * Shell output routines. We use our own output routines because:
50 * When a builtin command is interrupted we have to discard
51 * any pending output.
52 * When a builtin command appears in back quotes, we want to
53 * save the output of the command in a region obtained
54 * via malloc, rather than doing a fork and reading the
55 * output of the command via a pipe.
56 * Our output routines may be smaller than the stdio routines.
57 */
58
59#include <sys/types.h> /* quad_t */
60#include <sys/param.h> /* BSD4_4 */
61#include <sys/ioctl.h>
62
63#include <stdio.h> /* defines BUFSIZ */
64#include <string.h>
65#include <errno.h>
66#include <unistd.h>
67#include <stdlib.h>
68#if defined(_GNU_SOURCE) && !defined(__UCLIBC__)
69#undef CEOF /* get rid of the redefine warning */
70#include <fcntl.h>
71#endif
72
73#include "shell.h"
74#include "syntax.h"
75#include "output.h"
76#include "memalloc.h"
77#include "error.h"
78
79
80#define OUTBUFSIZ BUFSIZ
81#define BLOCK_OUT -2 /* output to a fixed block of memory */
82#define MEM_OUT -3 /* output to dynamically allocated memory */
83#define OUTPUT_ERR 01 /* error occurred on output */
84
85
86#if defined(_GNU_SOURCE) && !defined(__UCLIBC__)
87struct output output = {NULL, NULL, 0, NULL, 0, 1, 0};
88struct output errout = {NULL, NULL, 0, NULL, 0, 2, 0};
89struct output memout = {NULL, NULL, 0, NULL, 0, MEM_OUT, 0};
90#else
91struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0};
92struct output errout = {NULL, 0, NULL, 100, 2, 0};
93struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0};
94#endif
95struct output *out1 = &output;
96struct output *out2 = &errout;
97
98
99
100#ifdef mkinit
101
102INCLUDE "output.h"
103INCLUDE "memalloc.h"
104
105INIT {
106#if defined(_GNU_SOURCE) && !defined(__UCLIBC__)
107 initstreams();
108#endif
109}
110
111RESET {
112 out1 = &output;
113 out2 = &errout;
114#if defined(_GNU_SOURCE) && !defined(__UCLIBC__)
115 if (memout.stream != NULL)
116 closememout();
117#endif
118 if (memout.buf != NULL) {
119 ckfree(memout.buf);
120 memout.buf = NULL;
121 }
122}
123
124#endif
125
126
127#ifdef notdef /* no longer used */
128/*
129 * Set up an output file to write to memory rather than a file.
130 */
131
132void
133open_mem(block, length, file)
134 char *block;
135 int length;
136 struct output *file;
137 {
138 file->nextc = block;
139 file->nleft = --length;
140 file->fd = BLOCK_OUT;
141 file->flags = 0;
142}
143#endif
144
145
146void
147outstr(p, file)
148 const char *p;
149 struct output *file;
150 {
151#if defined(_GNU_SOURCE) && !defined(__UCLIBC__)
152 fputs(p, file->stream);
153#else
154 while (*p)
155 outc(*p++, file);
156#endif
157 if (file == out2)
158 flushout(file);
159}
160
161
162#if !defined(_GNU_SOURCE) || defined(__UCLIBC__)
163char out_junk[16];
164
165
166void
167emptyoutbuf(dest)
168 struct output *dest;
169 {
170 int offset;
171
172 if (dest->fd == BLOCK_OUT) {
173 dest->nextc = out_junk;
174 dest->nleft = sizeof out_junk;
175 dest->flags |= OUTPUT_ERR;
176 } else if (dest->buf == NULL) {
177 INTOFF;
178 dest->buf = ckmalloc(dest->bufsize);
179 dest->nextc = dest->buf;
180 dest->nleft = dest->bufsize;
181 INTON;
182 } else if (dest->fd == MEM_OUT) {
183 offset = dest->bufsize;
184 INTOFF;
185 dest->bufsize <<= 1;
186 dest->buf = ckrealloc(dest->buf, dest->bufsize);
187 dest->nleft = dest->bufsize - offset;
188 dest->nextc = dest->buf + offset;
189 INTON;
190 } else {
191 flushout(dest);
192 }
193 dest->nleft--;
194}
195#endif
196
197
198void
199flushall() {
200 flushout(&output);
201 flushout(&errout);
202}
203
204
205#if !defined(_GNU_SOURCE) || defined(__UCLIBC__)
206void
207flushout(dest)
208 struct output *dest;
209 {
210 if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0)
211 return;
212 if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0)
213 dest->flags |= OUTPUT_ERR;
214 dest->nextc = dest->buf;
215 dest->nleft = dest->bufsize;
216}
217#endif
218
219
220void
221freestdout() {
222 INTOFF;
223 if (output.buf) {
224 ckfree(output.buf);
225 output.buf = NULL;
226 output.nleft = 0;
227 }
228 INTON;
229}
230
231
232void
233#ifdef __STDC__
234outfmt(struct output *file, const char *fmt, ...)
235#else
236void
237outfmt(va_alist)
238 va_dcl
239#endif
240{
241 va_list ap;
242#ifndef __STDC__
243 struct output *file;
244 const char *fmt;
245
246 va_start(ap);
247 file = va_arg(ap, struct output *);
248 fmt = va_arg(ap, const char *);
249#else
250 va_start(ap, fmt);
251#endif
252 doformat(file, fmt, ap);
253 va_end(ap);
254}
255
256
257void
258#ifdef __STDC__
259out1fmt(const char *fmt, ...)
260#else
261out1fmt(va_alist)
262 va_dcl
263#endif
264{
265 va_list ap;
266#ifndef __STDC__
267 const char *fmt;
268
269 va_start(ap);
270 fmt = va_arg(ap, const char *);
271#else
272 va_start(ap, fmt);
273#endif
274 doformat(out1, fmt, ap);
275 va_end(ap);
276}
277
278#if !defined(__GLIBC__) && !defined(__UCLIBC__)
279void
280#ifdef __STDC__
281dprintf(const char *fmt, ...)
282#else
283dprintf(va_alist)
284 va_dcl
285#endif
286{
287 va_list ap;
288#ifndef __STDC__
289 const char *fmt;
290
291 va_start(ap);
292 fmt = va_arg(ap, const char *);
293#else
294 va_start(ap, fmt);
295#endif
296 doformat(out2, fmt, ap);
297 va_end(ap);
298 flushout(out2);
299}
300#endif
301
302void
303#ifdef __STDC__
304fmtstr(char *outbuf, size_t length, const char *fmt, ...)
305#else
306fmtstr(va_alist)
307 va_dcl
308#endif
309{
310 va_list ap;
311#if !defined(_GNU_SOURCE) || defined(__UCLIBC__)
312 struct output strout;
313#endif
314#ifndef __STDC__
315 char *outbuf;
316 size_t length;
317 const char *fmt;
318
319 va_start(ap);
320 outbuf = va_arg(ap, char *);
321 length = va_arg(ap, size_t);
322 fmt = va_arg(ap, const char *);
323#else
324 va_start(ap, fmt);
325#endif
326#if defined(_GNU_SOURCE) && !defined(__UCLIBC__)
327 vsnprintf(outbuf, length, fmt, ap);
328#else
329 strout.nextc = outbuf;
330 strout.nleft = length;
331 strout.fd = BLOCK_OUT;
332 strout.flags = 0;
333 doformat(&strout, fmt, ap);
334 outc('\0', &strout);
335 if (strout.flags & OUTPUT_ERR)
336 outbuf[length - 1] = '\0';
337#endif
338}
339
340#if !defined(_GNU_SOURCE) || defined(__UCLIBC__)
341/*
342 * Formatted output. This routine handles a subset of the printf formats:
343 * - Formats supported: d, u, o, p, X, s, and c.
344 * - The x format is also accepted but is treated like X.
345 * - The l, ll and q modifiers are accepted.
346 * - The - and # flags are accepted; # only works with the o format.
347 * - Width and precision may be specified with any format except c.
348 * - An * may be given for the width or precision.
349 * - The obsolete practice of preceding the width with a zero to get
350 * zero padding is not supported; use the precision field.
351 * - A % may be printed by writing %% in the format string.
352 */
353
354#define TEMPSIZE 24
355
356static const char digit[] = "0123456789ABCDEF";
357
358#ifdef BSD4_4
359#define HAVE_VASPRINTF 1
360#endif
361
362
363void
364doformat(dest, f, ap)
365 struct output *dest;
366 const char *f; /* format string */
367 va_list ap;
368{
369#if HAVE_VASPRINTF
370 char *s;
371
372 vasprintf(&s, f, ap);
373 outstr(s, dest);
374 free(s);
375#else /* !HAVE_VASPRINTF */
376 char c;
377 char temp[TEMPSIZE];
378 int flushleft;
379 int sharp;
380 int width;
381 int prec;
382 int islong;
383 int isquad;
384 char *p;
385 int sign;
386#ifdef BSD4_4
387 quad_t l;
388 u_quad_t num;
389#else
390 long l;
391 u_long num;
392#endif
393 unsigned base;
394 int len;
395 int size;
396 int pad;
397
398 while ((c = *f++) != '\0') {
399 if (c != '%') {
400 outc(c, dest);
401 continue;
402 }
403 flushleft = 0;
404 sharp = 0;
405 width = 0;
406 prec = -1;
407 islong = 0;
408 isquad = 0;
409 for (;;) {
410 if (*f == '-')
411 flushleft++;
412 else if (*f == '#')
413 sharp++;
414 else
415 break;
416 f++;
417 }
418 if (*f == '*') {
419 width = va_arg(ap, int);
420 f++;
421 } else {
422 while (is_digit(*f)) {
423 width = 10 * width + digit_val(*f++);
424 }
425 }
426 if (*f == '.') {
427 if (*++f == '*') {
428 prec = va_arg(ap, int);
429 f++;
430 } else {
431 prec = 0;
432 while (is_digit(*f)) {
433 prec = 10 * prec + digit_val(*f++);
434 }
435 }
436 }
437 if (*f == 'l') {
438 f++;
439 if (*f == 'l') {
440 isquad++;
441 f++;
442 } else
443 islong++;
444 } else if (*f == 'q') {
445 isquad++;
446 f++;
447 }
448 switch (*f) {
449 case 'd':
450#ifdef BSD4_4
451 if (isquad)
452 l = va_arg(ap, quad_t);
453 else
454#endif
455 if (islong)
456 l = va_arg(ap, long);
457 else
458 l = va_arg(ap, int);
459 sign = 0;
460 num = l;
461 if (l < 0) {
462 num = -l;
463 sign = 1;
464 }
465 base = 10;
466 goto number;
467 case 'u':
468 base = 10;
469 goto uns_number;
470 case 'o':
471 base = 8;
472 goto uns_number;
473 case 'p':
474 outc('0', dest);
475 outc('x', dest);
476 /*FALLTHROUGH*/
477 case 'x':
478 /* we don't implement 'x'; treat like 'X' */
479 case 'X':
480 base = 16;
481uns_number: /* an unsigned number */
482 sign = 0;
483#ifdef BSD4_4
484 if (isquad)
485 num = va_arg(ap, u_quad_t);
486 else
487#endif
488 if (islong)
489 num = va_arg(ap, unsigned long);
490 else
491 num = va_arg(ap, unsigned int);
492number: /* process a number */
493 p = temp + TEMPSIZE - 1;
494 *p = '\0';
495 while (num) {
496 *--p = digit[num % base];
497 num /= base;
498 }
499 len = (temp + TEMPSIZE - 1) - p;
500 if (prec < 0)
501 prec = 1;
502 if (sharp && *f == 'o' && prec <= len)
503 prec = len + 1;
504 pad = 0;
505 if (width) {
506 size = len;
507 if (size < prec)
508 size = prec;
509 size += sign;
510 pad = width - size;
511 if (flushleft == 0) {
512 while (--pad >= 0)
513 outc(' ', dest);
514 }
515 }
516 if (sign)
517 outc('-', dest);
518 prec -= len;
519 while (--prec >= 0)
520 outc('0', dest);
521 while (*p)
522 outc(*p++, dest);
523 while (--pad >= 0)
524 outc(' ', dest);
525 break;
526 case 's':
527 p = va_arg(ap, char *);
528 pad = 0;
529 if (width) {
530 len = strlen(p);
531 if (prec >= 0 && len > prec)
532 len = prec;
533 pad = width - len;
534 if (flushleft == 0) {
535 while (--pad >= 0)
536 outc(' ', dest);
537 }
538 }
539 prec++;
540 while (--prec != 0 && *p)
541 outc(*p++, dest);
542 while (--pad >= 0)
543 outc(' ', dest);
544 break;
545 case 'c':
546 c = va_arg(ap, int);
547 outc(c, dest);
548 break;
549 default:
550 outc(*f, dest);
551 break;
552 }
553 f++;
554 }
555#endif /* !HAVE_VASPRINTF */
556}
557#endif
558
559
560/*
561 * Version of write which resumes after a signal is caught.
562 */
563
564int
565xwrite(fd, buf, nbytes)
566 int fd;
567 const char *buf;
568 int nbytes;
569 {
570 int ntry;
571 int i;
572 int n;
573
574 n = nbytes;
575 ntry = 0;
576 for (;;) {
577 i = write(fd, buf, n);
578 if (i > 0) {
579 if ((n -= i) <= 0)
580 return nbytes;
581 buf += i;
582 ntry = 0;
583 } else if (i == 0) {
584 if (++ntry > 10)
585 return nbytes - n;
586 } else if (errno != EINTR) {
587 return -1;
588 }
589 }
590}
591
592
593
594#ifdef notdef
595/*
596 * Version of ioctl that retries after a signal is caught.
597 * XXX unused function
598 */
599
600int
601xioctl(fd, request, arg)
602 int fd;
603 unsigned long request;
604 char * arg;
605{
606 int i;
607
608 while ((i = ioctl(fd, request, arg)) == -1 && errno == EINTR);
609 return i;
610}
611#endif
612
613
614#if defined(_GNU_SOURCE) && !defined(__UCLIBC__)
615void initstreams() {
616 output.stream = stdout;
617 errout.stream = stderr;
618}
619
620
621void
622openmemout() {
623 memout.stream = open_memstream(&memout.buf, &memout.bufsize);
624}
625
626
627void
628closememout() {
629 INTOFF;
630 fclose(memout.stream);
631 memout.stream = NULL;
632 INTON;
633}
634#endif
Note: See TracBrowser for help on using the repository browser.