Do not use .Xo/.Xc to work around ancient roff limits.
[netbsd-mini2440.git] / bin / sh / output.c
blob2d732d0edd6f6596696756ac389f72a15f317c96
1 /* $NetBSD: output.c,v 1.30 2008/10/12 01:40:37 dholland Exp $ */
3 /*-
4 * Copyright (c) 1991, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
8 * Kenneth Almquist.
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. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
35 #include <sys/cdefs.h>
36 #ifndef lint
37 #if 0
38 static char sccsid[] = "@(#)output.c 8.2 (Berkeley) 5/4/95";
39 #else
40 __RCSID("$NetBSD: output.c,v 1.30 2008/10/12 01:40:37 dholland Exp $");
41 #endif
42 #endif /* not lint */
45 * Shell output routines. We use our own output routines because:
46 * When a builtin command is interrupted we have to discard
47 * any pending output.
48 * When a builtin command appears in back quotes, we want to
49 * save the output of the command in a region obtained
50 * via malloc, rather than doing a fork and reading the
51 * output of the command via a pipe.
52 * Our output routines may be smaller than the stdio routines.
55 #include <sys/types.h> /* quad_t */
56 #include <sys/param.h> /* BSD4_4 */
57 #include <sys/ioctl.h>
59 #include <stdio.h> /* defines BUFSIZ */
60 #include <string.h>
61 #include <errno.h>
62 #include <unistd.h>
63 #include <stdlib.h>
65 #include "shell.h"
66 #include "syntax.h"
67 #include "output.h"
68 #include "memalloc.h"
69 #include "error.h"
72 #define OUTBUFSIZ BUFSIZ
73 #define BLOCK_OUT -2 /* output to a fixed block of memory */
74 #define MEM_OUT -3 /* output to dynamically allocated memory */
77 struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0};
78 struct output errout = {NULL, 0, NULL, 100, 2, 0};
79 struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0};
80 struct output *out1 = &output;
81 struct output *out2 = &errout;
85 #ifdef mkinit
87 INCLUDE "output.h"
88 INCLUDE "memalloc.h"
90 RESET {
91 out1 = &output;
92 out2 = &errout;
93 if (memout.buf != NULL) {
94 ckfree(memout.buf);
95 memout.buf = NULL;
99 #endif
102 #ifdef notdef /* no longer used */
104 * Set up an output file to write to memory rather than a file.
107 void
108 open_mem(char *block, int length, struct output *file)
110 file->nextc = block;
111 file->nleft = --length;
112 file->fd = BLOCK_OUT;
113 file->flags = 0;
115 #endif
118 void
119 out1str(const char *p)
121 outstr(p, out1);
125 void
126 out2str(const char *p)
128 outstr(p, out2);
132 void
133 outstr(const char *p, struct output *file)
135 while (*p)
136 outc(*p++, file);
137 if (file == out2)
138 flushout(file);
142 void
143 out2shstr(const char *p)
145 outshstr(p, out2);
149 void
150 outshstr(const char *p, struct output *file)
152 static const char norm_chars [] \
153 = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
154 int need_q = p[0] == 0 || p[strspn(p, norm_chars)] != 0;
155 char c;
157 if (need_q)
158 outc('\'', file);
160 while (c = *p++, c != 0){
161 if (c != '\''){
162 outc(c, file);
163 }else{
164 outc('\'', file);
165 outc('\\', file);
166 outc(c, file);
167 outc('\'', file);
171 if (need_q)
172 outc('\'', file);
174 if (file == out2)
175 flushout(file);
179 char out_junk[16];
182 void
183 emptyoutbuf(struct output *dest)
185 int offset;
187 if (dest->fd == BLOCK_OUT) {
188 dest->nextc = out_junk;
189 dest->nleft = sizeof out_junk;
190 dest->flags |= OUTPUT_ERR;
191 } else if (dest->buf == NULL) {
192 INTOFF;
193 dest->buf = ckmalloc(dest->bufsize);
194 dest->nextc = dest->buf;
195 dest->nleft = dest->bufsize;
196 INTON;
197 } else if (dest->fd == MEM_OUT) {
198 offset = dest->bufsize;
199 INTOFF;
200 dest->bufsize <<= 1;
201 dest->buf = ckrealloc(dest->buf, dest->bufsize);
202 dest->nleft = dest->bufsize - offset;
203 dest->nextc = dest->buf + offset;
204 INTON;
205 } else {
206 flushout(dest);
208 dest->nleft--;
212 void
213 flushall(void)
215 flushout(&output);
216 flushout(&errout);
220 void
221 flushout(struct output *dest)
224 if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0)
225 return;
226 if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0)
227 dest->flags |= OUTPUT_ERR;
228 dest->nextc = dest->buf;
229 dest->nleft = dest->bufsize;
233 void
234 freestdout(void)
236 INTOFF;
237 if (output.buf) {
238 ckfree(output.buf);
239 output.buf = NULL;
240 output.nleft = 0;
242 INTON;
246 void
247 outfmt(struct output *file, const char *fmt, ...)
249 va_list ap;
251 va_start(ap, fmt);
252 doformat(file, fmt, ap);
253 va_end(ap);
257 void
258 out1fmt(const char *fmt, ...)
260 va_list ap;
262 va_start(ap, fmt);
263 doformat(out1, fmt, ap);
264 va_end(ap);
267 void
268 dprintf(const char *fmt, ...)
270 va_list ap;
272 va_start(ap, fmt);
273 doformat(out2, fmt, ap);
274 va_end(ap);
275 flushout(out2);
278 void
279 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
281 va_list ap;
282 struct output strout;
284 va_start(ap, fmt);
285 strout.nextc = outbuf;
286 strout.nleft = length;
287 strout.fd = BLOCK_OUT;
288 strout.flags = 0;
289 doformat(&strout, fmt, ap);
290 outc('\0', &strout);
291 if (strout.flags & OUTPUT_ERR)
292 outbuf[length - 1] = '\0';
293 va_end(ap);
297 * Formatted output. This routine handles a subset of the printf formats:
298 * - Formats supported: d, u, o, p, X, s, and c.
299 * - The x format is also accepted but is treated like X.
300 * - The l, ll and q modifiers are accepted.
301 * - The - and # flags are accepted; # only works with the o format.
302 * - Width and precision may be specified with any format except c.
303 * - An * may be given for the width or precision.
304 * - The obsolete practice of preceding the width with a zero to get
305 * zero padding is not supported; use the precision field.
306 * - A % may be printed by writing %% in the format string.
309 #define TEMPSIZE 24
311 #ifdef BSD4_4
312 #define HAVE_VASPRINTF 1
313 #endif
315 void
316 doformat(struct output *dest, const char *f, va_list ap)
318 #if HAVE_VASPRINTF
319 char *s;
321 vasprintf(&s, f, ap);
322 if (s == NULL)
323 error("Could not allocate formatted output buffer");
324 outstr(s, dest);
325 free(s);
326 #else /* !HAVE_VASPRINTF */
327 static const char digit[] = "0123456789ABCDEF";
328 char c;
329 char temp[TEMPSIZE];
330 int flushleft;
331 int sharp;
332 int width;
333 int prec;
334 int islong;
335 int isquad;
336 char *p;
337 int sign;
338 #ifdef BSD4_4
339 quad_t l;
340 u_quad_t num;
341 #else
342 long l;
343 u_long num;
344 #endif
345 unsigned base;
346 int len;
347 int size;
348 int pad;
350 while ((c = *f++) != '\0') {
351 if (c != '%') {
352 outc(c, dest);
353 continue;
355 flushleft = 0;
356 sharp = 0;
357 width = 0;
358 prec = -1;
359 islong = 0;
360 isquad = 0;
361 for (;;) {
362 if (*f == '-')
363 flushleft++;
364 else if (*f == '#')
365 sharp++;
366 else
367 break;
368 f++;
370 if (*f == '*') {
371 width = va_arg(ap, int);
372 f++;
373 } else {
374 while (is_digit(*f)) {
375 width = 10 * width + digit_val(*f++);
378 if (*f == '.') {
379 if (*++f == '*') {
380 prec = va_arg(ap, int);
381 f++;
382 } else {
383 prec = 0;
384 while (is_digit(*f)) {
385 prec = 10 * prec + digit_val(*f++);
389 if (*f == 'l') {
390 f++;
391 if (*f == 'l') {
392 isquad++;
393 f++;
394 } else
395 islong++;
396 } else if (*f == 'q') {
397 isquad++;
398 f++;
400 switch (*f) {
401 case 'd':
402 #ifdef BSD4_4
403 if (isquad)
404 l = va_arg(ap, quad_t);
405 else
406 #endif
407 if (islong)
408 l = va_arg(ap, long);
409 else
410 l = va_arg(ap, int);
411 sign = 0;
412 num = l;
413 if (l < 0) {
414 num = -l;
415 sign = 1;
417 base = 10;
418 goto number;
419 case 'u':
420 base = 10;
421 goto uns_number;
422 case 'o':
423 base = 8;
424 goto uns_number;
425 case 'p':
426 outc('0', dest);
427 outc('x', dest);
428 /*FALLTHROUGH*/
429 case 'x':
430 /* we don't implement 'x'; treat like 'X' */
431 case 'X':
432 base = 16;
433 uns_number: /* an unsigned number */
434 sign = 0;
435 #ifdef BSD4_4
436 if (isquad)
437 num = va_arg(ap, u_quad_t);
438 else
439 #endif
440 if (islong)
441 num = va_arg(ap, unsigned long);
442 else
443 num = va_arg(ap, unsigned int);
444 number: /* process a number */
445 p = temp + TEMPSIZE - 1;
446 *p = '\0';
447 while (num) {
448 *--p = digit[num % base];
449 num /= base;
451 len = (temp + TEMPSIZE - 1) - p;
452 if (prec < 0)
453 prec = 1;
454 if (sharp && *f == 'o' && prec <= len)
455 prec = len + 1;
456 pad = 0;
457 if (width) {
458 size = len;
459 if (size < prec)
460 size = prec;
461 size += sign;
462 pad = width - size;
463 if (flushleft == 0) {
464 while (--pad >= 0)
465 outc(' ', dest);
468 if (sign)
469 outc('-', dest);
470 prec -= len;
471 while (--prec >= 0)
472 outc('0', dest);
473 while (*p)
474 outc(*p++, dest);
475 while (--pad >= 0)
476 outc(' ', dest);
477 break;
478 case 's':
479 p = va_arg(ap, char *);
480 pad = 0;
481 if (width) {
482 len = strlen(p);
483 if (prec >= 0 && len > prec)
484 len = prec;
485 pad = width - len;
486 if (flushleft == 0) {
487 while (--pad >= 0)
488 outc(' ', dest);
491 prec++;
492 while (--prec != 0 && *p)
493 outc(*p++, dest);
494 while (--pad >= 0)
495 outc(' ', dest);
496 break;
497 case 'c':
498 c = va_arg(ap, int);
499 outc(c, dest);
500 break;
501 default:
502 outc(*f, dest);
503 break;
505 f++;
507 #endif /* !HAVE_VASPRINTF */
513 * Version of write which resumes after a signal is caught.
517 xwrite(int fd, char *buf, int nbytes)
519 int ntry;
520 int i;
521 int n;
523 n = nbytes;
524 ntry = 0;
525 for (;;) {
526 i = write(fd, buf, n);
527 if (i > 0) {
528 if ((n -= i) <= 0)
529 return nbytes;
530 buf += i;
531 ntry = 0;
532 } else if (i == 0) {
533 if (++ntry > 10)
534 return nbytes - n;
535 } else if (errno != EINTR) {
536 return -1;
543 * Version of ioctl that retries after a signal is caught.
544 * XXX unused function
548 xioctl(int fd, unsigned long request, char *arg)
550 int i;
552 while ((i = ioctl(fd, request, arg)) == -1 && errno == EINTR);
553 return i;