Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 2786 → Rev 2787

/branches/tracing/uspace/app/ash/output.c
0,0 → 1,634
/* $NetBSD: output.c,v 1.23 2001/01/07 23:39:07 lukem Exp $ */
 
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Kenneth Almquist.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
 
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)output.c 8.2 (Berkeley) 5/4/95";
#else
__RCSID("$NetBSD: output.c,v 1.23 2001/01/07 23:39:07 lukem Exp $");
#endif
#endif /* not lint */
 
/*
* Shell output routines. We use our own output routines because:
* When a builtin command is interrupted we have to discard
* any pending output.
* When a builtin command appears in back quotes, we want to
* save the output of the command in a region obtained
* via malloc, rather than doing a fork and reading the
* output of the command via a pipe.
* Our output routines may be smaller than the stdio routines.
*/
 
#include <sys/types.h> /* quad_t */
#include <sys/param.h> /* BSD4_4 */
#include <sys/ioctl.h>
 
#include <stdio.h> /* defines BUFSIZ */
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#if defined(_GNU_SOURCE) && !defined(__UCLIBC__)
#undef CEOF /* get rid of the redefine warning */
#include <fcntl.h>
#endif
 
#include "shell.h"
#include "syntax.h"
#include "output.h"
#include "memalloc.h"
#include "error.h"
 
 
#define OUTBUFSIZ BUFSIZ
#define BLOCK_OUT -2 /* output to a fixed block of memory */
#define MEM_OUT -3 /* output to dynamically allocated memory */
#define OUTPUT_ERR 01 /* error occurred on output */
 
 
#if defined(_GNU_SOURCE) && !defined(__UCLIBC__)
struct output output = {NULL, NULL, 0, NULL, 0, 1, 0};
struct output errout = {NULL, NULL, 0, NULL, 0, 2, 0};
struct output memout = {NULL, NULL, 0, NULL, 0, MEM_OUT, 0};
#else
struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0};
struct output errout = {NULL, 0, NULL, 100, 2, 0};
struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0};
#endif
struct output *out1 = &output;
struct output *out2 = &errout;
 
 
 
#ifdef mkinit
 
INCLUDE "output.h"
INCLUDE "memalloc.h"
 
INIT {
#if defined(_GNU_SOURCE) && !defined(__UCLIBC__)
initstreams();
#endif
}
 
RESET {
out1 = &output;
out2 = &errout;
#if defined(_GNU_SOURCE) && !defined(__UCLIBC__)
if (memout.stream != NULL)
closememout();
#endif
if (memout.buf != NULL) {
ckfree(memout.buf);
memout.buf = NULL;
}
}
 
#endif
 
 
#ifdef notdef /* no longer used */
/*
* Set up an output file to write to memory rather than a file.
*/
 
void
open_mem(block, length, file)
char *block;
int length;
struct output *file;
{
file->nextc = block;
file->nleft = --length;
file->fd = BLOCK_OUT;
file->flags = 0;
}
#endif
 
 
void
outstr(p, file)
const char *p;
struct output *file;
{
#if defined(_GNU_SOURCE) && !defined(__UCLIBC__)
fputs(p, file->stream);
#else
while (*p)
outc(*p++, file);
#endif
if (file == out2)
flushout(file);
}
 
 
#if !defined(_GNU_SOURCE) || defined(__UCLIBC__)
char out_junk[16];
 
 
void
emptyoutbuf(dest)
struct output *dest;
{
int offset;
 
if (dest->fd == BLOCK_OUT) {
dest->nextc = out_junk;
dest->nleft = sizeof out_junk;
dest->flags |= OUTPUT_ERR;
} else if (dest->buf == NULL) {
INTOFF;
dest->buf = ckmalloc(dest->bufsize);
dest->nextc = dest->buf;
dest->nleft = dest->bufsize;
INTON;
} else if (dest->fd == MEM_OUT) {
offset = dest->bufsize;
INTOFF;
dest->bufsize <<= 1;
dest->buf = ckrealloc(dest->buf, dest->bufsize);
dest->nleft = dest->bufsize - offset;
dest->nextc = dest->buf + offset;
INTON;
} else {
flushout(dest);
}
dest->nleft--;
}
#endif
 
 
void
flushall() {
flushout(&output);
flushout(&errout);
}
 
 
#if !defined(_GNU_SOURCE) || defined(__UCLIBC__)
void
flushout(dest)
struct output *dest;
{
if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0)
return;
if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0)
dest->flags |= OUTPUT_ERR;
dest->nextc = dest->buf;
dest->nleft = dest->bufsize;
}
#endif
 
 
void
freestdout() {
INTOFF;
if (output.buf) {
ckfree(output.buf);
output.buf = NULL;
output.nleft = 0;
}
INTON;
}
 
 
void
#ifdef __STDC__
outfmt(struct output *file, const char *fmt, ...)
#else
void
outfmt(va_alist)
va_dcl
#endif
{
va_list ap;
#ifndef __STDC__
struct output *file;
const char *fmt;
 
va_start(ap);
file = va_arg(ap, struct output *);
fmt = va_arg(ap, const char *);
#else
va_start(ap, fmt);
#endif
doformat(file, fmt, ap);
va_end(ap);
}
 
 
void
#ifdef __STDC__
out1fmt(const char *fmt, ...)
#else
out1fmt(va_alist)
va_dcl
#endif
{
va_list ap;
#ifndef __STDC__
const char *fmt;
 
va_start(ap);
fmt = va_arg(ap, const char *);
#else
va_start(ap, fmt);
#endif
doformat(out1, fmt, ap);
va_end(ap);
}
 
#if !defined(__GLIBC__) && !defined(__UCLIBC__)
void
#ifdef __STDC__
dprintf(const char *fmt, ...)
#else
dprintf(va_alist)
va_dcl
#endif
{
va_list ap;
#ifndef __STDC__
const char *fmt;
 
va_start(ap);
fmt = va_arg(ap, const char *);
#else
va_start(ap, fmt);
#endif
doformat(out2, fmt, ap);
va_end(ap);
flushout(out2);
}
#endif
 
void
#ifdef __STDC__
fmtstr(char *outbuf, size_t length, const char *fmt, ...)
#else
fmtstr(va_alist)
va_dcl
#endif
{
va_list ap;
#if !defined(_GNU_SOURCE) || defined(__UCLIBC__)
struct output strout;
#endif
#ifndef __STDC__
char *outbuf;
size_t length;
const char *fmt;
 
va_start(ap);
outbuf = va_arg(ap, char *);
length = va_arg(ap, size_t);
fmt = va_arg(ap, const char *);
#else
va_start(ap, fmt);
#endif
#if defined(_GNU_SOURCE) && !defined(__UCLIBC__)
vsnprintf(outbuf, length, fmt, ap);
#else
strout.nextc = outbuf;
strout.nleft = length;
strout.fd = BLOCK_OUT;
strout.flags = 0;
doformat(&strout, fmt, ap);
outc('\0', &strout);
if (strout.flags & OUTPUT_ERR)
outbuf[length - 1] = '\0';
#endif
}
 
#if !defined(_GNU_SOURCE) || defined(__UCLIBC__)
/*
* Formatted output. This routine handles a subset of the printf formats:
* - Formats supported: d, u, o, p, X, s, and c.
* - The x format is also accepted but is treated like X.
* - The l, ll and q modifiers are accepted.
* - The - and # flags are accepted; # only works with the o format.
* - Width and precision may be specified with any format except c.
* - An * may be given for the width or precision.
* - The obsolete practice of preceding the width with a zero to get
* zero padding is not supported; use the precision field.
* - A % may be printed by writing %% in the format string.
*/
 
#define TEMPSIZE 24
 
static const char digit[] = "0123456789ABCDEF";
 
#ifdef BSD4_4
#define HAVE_VASPRINTF 1
#endif
 
 
void
doformat(dest, f, ap)
struct output *dest;
const char *f; /* format string */
va_list ap;
{
#if HAVE_VASPRINTF
char *s;
 
vasprintf(&s, f, ap);
outstr(s, dest);
free(s);
#else /* !HAVE_VASPRINTF */
char c;
char temp[TEMPSIZE];
int flushleft;
int sharp;
int width;
int prec;
int islong;
int isquad;
char *p;
int sign;
#ifdef BSD4_4
quad_t l;
u_quad_t num;
#else
long l;
u_long num;
#endif
unsigned base;
int len;
int size;
int pad;
 
while ((c = *f++) != '\0') {
if (c != '%') {
outc(c, dest);
continue;
}
flushleft = 0;
sharp = 0;
width = 0;
prec = -1;
islong = 0;
isquad = 0;
for (;;) {
if (*f == '-')
flushleft++;
else if (*f == '#')
sharp++;
else
break;
f++;
}
if (*f == '*') {
width = va_arg(ap, int);
f++;
} else {
while (is_digit(*f)) {
width = 10 * width + digit_val(*f++);
}
}
if (*f == '.') {
if (*++f == '*') {
prec = va_arg(ap, int);
f++;
} else {
prec = 0;
while (is_digit(*f)) {
prec = 10 * prec + digit_val(*f++);
}
}
}
if (*f == 'l') {
f++;
if (*f == 'l') {
isquad++;
f++;
} else
islong++;
} else if (*f == 'q') {
isquad++;
f++;
}
switch (*f) {
case 'd':
#ifdef BSD4_4
if (isquad)
l = va_arg(ap, quad_t);
else
#endif
if (islong)
l = va_arg(ap, long);
else
l = va_arg(ap, int);
sign = 0;
num = l;
if (l < 0) {
num = -l;
sign = 1;
}
base = 10;
goto number;
case 'u':
base = 10;
goto uns_number;
case 'o':
base = 8;
goto uns_number;
case 'p':
outc('0', dest);
outc('x', dest);
/*FALLTHROUGH*/
case 'x':
/* we don't implement 'x'; treat like 'X' */
case 'X':
base = 16;
uns_number: /* an unsigned number */
sign = 0;
#ifdef BSD4_4
if (isquad)
num = va_arg(ap, u_quad_t);
else
#endif
if (islong)
num = va_arg(ap, unsigned long);
else
num = va_arg(ap, unsigned int);
number: /* process a number */
p = temp + TEMPSIZE - 1;
*p = '\0';
while (num) {
*--p = digit[num % base];
num /= base;
}
len = (temp + TEMPSIZE - 1) - p;
if (prec < 0)
prec = 1;
if (sharp && *f == 'o' && prec <= len)
prec = len + 1;
pad = 0;
if (width) {
size = len;
if (size < prec)
size = prec;
size += sign;
pad = width - size;
if (flushleft == 0) {
while (--pad >= 0)
outc(' ', dest);
}
}
if (sign)
outc('-', dest);
prec -= len;
while (--prec >= 0)
outc('0', dest);
while (*p)
outc(*p++, dest);
while (--pad >= 0)
outc(' ', dest);
break;
case 's':
p = va_arg(ap, char *);
pad = 0;
if (width) {
len = strlen(p);
if (prec >= 0 && len > prec)
len = prec;
pad = width - len;
if (flushleft == 0) {
while (--pad >= 0)
outc(' ', dest);
}
}
prec++;
while (--prec != 0 && *p)
outc(*p++, dest);
while (--pad >= 0)
outc(' ', dest);
break;
case 'c':
c = va_arg(ap, int);
outc(c, dest);
break;
default:
outc(*f, dest);
break;
}
f++;
}
#endif /* !HAVE_VASPRINTF */
}
#endif
 
 
/*
* Version of write which resumes after a signal is caught.
*/
 
int
xwrite(fd, buf, nbytes)
int fd;
const char *buf;
int nbytes;
{
int ntry;
int i;
int n;
 
n = nbytes;
ntry = 0;
for (;;) {
i = write(fd, buf, n);
if (i > 0) {
if ((n -= i) <= 0)
return nbytes;
buf += i;
ntry = 0;
} else if (i == 0) {
if (++ntry > 10)
return nbytes - n;
} else if (errno != EINTR) {
return -1;
}
}
}
 
 
 
#ifdef notdef
/*
* Version of ioctl that retries after a signal is caught.
* XXX unused function
*/
 
int
xioctl(fd, request, arg)
int fd;
unsigned long request;
char * arg;
{
int i;
 
while ((i = ioctl(fd, request, arg)) == -1 && errno == EINTR);
return i;
}
#endif
 
 
#if defined(_GNU_SOURCE) && !defined(__UCLIBC__)
void initstreams() {
output.stream = stdout;
errout.stream = stderr;
}
 
 
void
openmemout() {
memout.stream = open_memstream(&memout.buf, &memout.bufsize);
}
 
 
void
closememout() {
INTOFF;
fclose(memout.stream);
memout.stream = NULL;
INTON;
}
#endif