Subversion Repositories HelenOS

Rev

Rev 2714 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2714 cejka 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
42
static 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__)
87
struct output output = {NULL, NULL, 0, NULL, 0, 1, 0};
88
struct output errout = {NULL, NULL, 0, NULL, 0, 2, 0};
89
struct output memout = {NULL, NULL, 0, NULL, 0, MEM_OUT, 0};
90
#else
91
struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0};
92
struct output errout = {NULL, 0, NULL, 100, 2, 0};
93
struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0};
94
#endif
95
struct output *out1 = &output;
96
struct output *out2 = &errout;
97
 
98
 
99
 
100
#ifdef mkinit
101
 
102
INCLUDE "output.h"
103
INCLUDE "memalloc.h"
104
 
105
INIT {
106
#if defined(_GNU_SOURCE) && !defined(__UCLIBC__)
107
    initstreams();
108
#endif
109
}
110
 
111
RESET {
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
 
132
void
133
open_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
 
146
void
147
outstr(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__)
163
char out_junk[16];
164
 
165
 
166
void
167
emptyoutbuf(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
 
198
void
199
flushall() {
200
    flushout(&output);
201
    flushout(&errout);
202
}
203
 
204
 
205
#if !defined(_GNU_SOURCE) || defined(__UCLIBC__)
206
void
207
flushout(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
 
220
void
221
freestdout() {
222
    INTOFF;
223
    if (output.buf) {
224
        ckfree(output.buf);
225
        output.buf = NULL;
226
        output.nleft = 0;
227
    }
228
    INTON;
229
}
230
 
231
 
232
void
233
#ifdef __STDC__
234
outfmt(struct output *file, const char *fmt, ...)
235
#else
236
void
237
outfmt(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
 
257
void
258
#ifdef __STDC__
259
out1fmt(const char *fmt, ...)
260
#else
261
out1fmt(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__)
279
void
280
#ifdef __STDC__
281
dprintf(const char *fmt, ...)
282
#else
283
dprintf(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
 
302
void
303
#ifdef __STDC__
304
fmtstr(char *outbuf, size_t length, const char *fmt, ...)
305
#else
306
fmtstr(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
 
356
static const char digit[] = "0123456789ABCDEF";
357
 
358
#ifdef BSD4_4
359
#define HAVE_VASPRINTF 1
360
#endif
361
 
362
 
363
void
364
doformat(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;
481
uns_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);
492
number:       /* 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
 
564
int
565
xwrite(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
 
600
int
601
xioctl(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__)
615
void initstreams() {
616
    output.stream = stdout;
617
    errout.stream = stderr;
618
}
619
 
620
 
621
void
622
openmemout() {
623
    memout.stream = open_memstream(&memout.buf, &memout.bufsize);
624
}
625
 
626
 
627
void
628
closememout() {
629
    INTOFF;
630
    fclose(memout.stream);
631
    memout.stream = NULL;
632
    INTON;
633
}
634
#endif