]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - bin/sh/output.c
$Id$ -> $FreeBSD$
[FreeBSD/FreeBSD.git] / bin / sh / output.c
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
39 static char sccsid[] = "@(#)output.c    8.2 (Berkeley) 5/4/95";
40 #endif
41 static const char rcsid[] =
42   "$FreeBSD$";
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
83 struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0};
84 struct output errout = {NULL, 0, NULL, 100, 2, 0};
85 struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0};
86 struct output *out1 = &output;
87 struct output *out2 = &errout;
88
89
90
91 #ifdef mkinit
92
93 INCLUDE "output.h"
94 INCLUDE "memalloc.h"
95
96 RESET {
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
113 void
114 open_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
127 void
128 out1str(p)
129         const char *p;
130         {
131         outstr(p, out1);
132 }
133
134
135 void
136 out2str(p)
137         const char *p;
138         {
139         outstr(p, out2);
140 }
141
142
143 void
144 outstr(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
155 char out_junk[16];
156
157
158 void
159 emptyoutbuf(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
189 void
190 flushall() {
191         flushout(&output);
192         flushout(&errout);
193 }
194
195
196 void
197 flushout(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
210 void
211 freestdout() {
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__
223 void
224 outfmt(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
233 void
234 out1fmt(char *fmt, ...) {
235         va_list ap;
236
237         va_start(ap, fmt);
238         doformat(out1, fmt, ap);
239         va_end(ap);
240 }
241
242 void
243 dprintf(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
252 void
253 fmtstr(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
270 void
271 outfmt(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
286 void
287 out1fmt(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
299 void
300 dprintf(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
313 void
314 fmtstr(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
354 static const char digit[] = "0123456789ABCDEF";
355
356
357 void
358 doformat(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;
452 uns_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);
460 number:           /* 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
531 int
532 xwrite(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
565 int
566 xioctl(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 }