diff options
Diffstat (limited to 'libc/stdio')
-rw-r--r-- | libc/stdio/Makefile | 53 | ||||
-rw-r--r-- | libc/stdio/printf.c | 387 | ||||
-rw-r--r-- | libc/stdio/scanf.c | 536 | ||||
-rw-r--r-- | libc/stdio/stdio.c | 925 |
4 files changed, 1901 insertions, 0 deletions
diff --git a/libc/stdio/Makefile b/libc/stdio/Makefile new file mode 100644 index 000000000..badf78c56 --- /dev/null +++ b/libc/stdio/Makefile @@ -0,0 +1,53 @@ +# Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk> +# This file is part of the Linux-8086 C library and is distributed +# under the GNU Library General Public License. + +LIBC=../libc.a + +CC=m68k-pic-coff-gcc +AR=m68k-pic-coff-ar +RANLIB=m68k-pic-coff-ranlib + +CCFLAGS= -O2 -m68000 -msoft-float -I../include + +ASRC=stdio.c +AOBJ=_stdio_init.o fputc.o fgetc.o fflush.o fgets.o gets.o fputs.o \ + puts.o fread.o fwrite.o fopen.o fclose.o fseek.o rewind.o ftell.o \ + setbuffer.o setvbuf.o ungetc.o + +PSRC=printf.c +POBJ=printf.o sprintf.o fprintf.o vprintf.o vsprintf.o vfprintf.o + +SSRC=scanf.c +SOBJ=scanf.o sscanf.o fscanf.o vscanf.o vsscanf.o vfscanf.o + +OBJ= $(AOBJ) $(POBJ) $(SOBJ) dputs.o + +CFLAGS=$(ARCH) $(CCFLAGS) $(DEFS) + +all: $(LIBC) + @$(RM) $(OBJ) + +$(LIBC): $(LIBC)($(OBJ)) + +$(LIBC)($(AOBJ)): $(ASRC) + $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o + $(AR) $(ARFLAGS) $@ $*.o + +$(LIBC)($(POBJ)): $(PSRC) + $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o + $(AR) $(ARFLAGS) $@ $*.o + +$(LIBC)($(SOBJ)): $(SSRC) + $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o + $(AR) $(ARFLAGS) $@ $*.o + +transfer: + -@rm -f ../include/stdio.h + cp -p stdio.h ../include/. + +clean: + rm -f *.o libc.a + +$(LIBC)($(OBJ)): stdio.h + diff --git a/libc/stdio/printf.c b/libc/stdio/printf.c new file mode 100644 index 000000000..873f1cb41 --- /dev/null +++ b/libc/stdio/printf.c @@ -0,0 +1,387 @@ +/* + * This file based on printf.c from 'Dlibs' on the atari ST (RdeBath) + * + * + * Dale Schumacher 399 Beacon Ave. + * (alias: Dalnefre') St. Paul, MN 55104 + * dal@syntel.UUCP United States of America + * "It's not reality that's important, but how you perceive things." + */ + +/* Altered to use stdarg, made the core function vfprintf. + * Hooked into the stdio package using 'inside information' + * Altered sizeof() assumptions, now assumes all integers except chars + * will be either + * sizeof(xxx) == sizeof(long) or sizeof(xxx) == sizeof(short) + * + * -RDB + */ + +#include <sys/types.h> +#include <fcntl.h> +#include <string.h> +#include <stdlib.h> + +#ifdef __STDC__ +#include <stdarg.h> +#define va_strt va_start +#else +#include <varargs.h> +#define va_strt(p,i) va_start(p) +#endif + +#include "stdio.h" + +#ifdef L_printf + +#ifdef __STDC__ +int printf(const char * fmt, ...) +#else +int printf(fmt, va_alist) +__const char *fmt; +va_dcl +#endif +{ + va_list ptr; + int rv; + + va_strt(ptr, fmt); + rv = vfprintf(stdout,fmt,ptr); + va_end(ptr); + return rv; +} +#endif + +#ifdef L_sprintf +#ifdef __STDC__ +int sprintf(char * sp, const char * fmt, ...) +#else +int sprintf(sp, fmt, va_alist) +char * sp; +__const char *fmt; +va_dcl +#endif +{ +static FILE string[1] = +{ + {0, 0, (char*)(unsigned) -1, 0, (char*) (unsigned) -1, -1, + _IOFBF | __MODE_WRITE} +}; + + va_list ptr; + int rv; + va_strt(ptr, fmt); + string->bufpos = sp; + rv = vfprintf(string,fmt,ptr); + va_end(ptr); + *(string->bufpos) = 0; + return rv; +} +#endif + +#ifdef L_fprintf +#ifdef __STDC__ +int fprintf(FILE * fp, const char * fmt, ...) +#else +int fprintf(fp, fmt, va_alist) +FILE * fp; +__const char *fmt; +va_dcl +#endif +{ + va_list ptr; + int rv; + va_strt(ptr, fmt); + rv = vfprintf(fp,fmt,ptr); + va_end(ptr); + return rv; +} +#endif + +#ifdef L_vprintf +int vprintf(fmt, ap) +__const char *fmt; +va_list ap; +{ + return vfprintf(stdout,fmt,ap); +} +#endif + +#ifdef L_vsprintf +int vsprintf(sp, fmt, ap) +char * sp; +__const char *fmt; +va_list ap; +{ +static FILE string[1] = +{ + {0, 0, (char*)(unsigned) -1, 0, (char*) (unsigned) -1, -1, + _IOFBF | __MODE_WRITE} +}; + + int rv; + string->bufpos = sp; + rv = vfprintf(string,fmt,ap); + *(string->bufpos) = 0; + return rv; +} +#endif + +#ifdef L_vfprintf + +#if FLOATS +int _vfprintf_fp_ref = 1; +#else +int _vfprintf_fp_ref = 0; +#endif + +static int +prtfld(op, buf, ljustf, sign, pad, width, preci, buffer_mode) +register FILE *op; +register unsigned char *buf; +int ljustf; +register char sign; +char pad; +register int width; +int preci; +int buffer_mode; +/* + * Output the given field in the manner specified by the arguments. Return + * the number of characters output. + */ +{ + register int cnt = 0, len; + register unsigned char ch; + + len = strlen(buf); + + if (*buf == '-') + sign = *buf++; + else if (sign) + len++; + + if ((preci != -1) && (len > preci)) /* limit max data width */ + len = preci; + + if (width < len) /* flexible field width or width overflow */ + width = len; + + /* + * at this point: width = total field width len = actual data width + * (including possible sign character) + */ + cnt = width; + width -= len; + + while (width || len) + { + if (!ljustf && width) /* left padding */ + { + if (len && sign && (pad == '0')) + goto showsign; + ch = pad; + --width; + } + else if (len) + { + if (sign) + { + showsign:ch = sign; /* sign */ + sign = '\0'; + } + else + ch = *buf++; /* main field */ + --len; + } + else + { + ch = pad; /* right padding */ + --width; + } + putc(ch, op); + if( ch == '\n' && buffer_mode == _IOLBF ) fflush(op); + } + + return (cnt); +} + +int +vfprintf(op, fmt, ap) +FILE *op; +register __const char *fmt; +register va_list ap; +{ + register int i, cnt = 0, ljustf, lval; + int preci, dpoint, width; + char pad, sign, radix, hash; + register char *ptmp; + char tmp[64], *ltostr(), *ultostr(); + int buffer_mode; + + /* This speeds things up a bit for unbuffered */ + buffer_mode = (op->mode&__MODE_BUF); + op->mode &= (~__MODE_BUF); + + while (*fmt) + { + if (*fmt == '%') + { + if( buffer_mode == _IONBF ) fflush(op); + ljustf = 0; /* left justify flag */ + sign = '\0'; /* sign char & status */ + pad = ' '; /* justification padding char */ + width = -1; /* min field width */ + dpoint = 0; /* found decimal point */ + preci = -1; /* max data width */ + radix = 10; /* number base */ + ptmp = tmp; /* pointer to area to print */ + hash = 0; + lval = (sizeof(int)==sizeof(long)); /* long value flaged */ + fmtnxt: + i = 0; + for(;;) + { + ++fmt; + if(*fmt < '0' || *fmt > '9' ) break; + i = (i * 10) + (*fmt - '0'); + if (dpoint) + preci = i; + else if (!i && (pad == ' ')) + { + pad = '0'; + goto fmtnxt; + } + else + width = i; + } + + switch (*fmt) + { + case '\0': /* early EOS */ + --fmt; + goto charout; + + case '-': /* left justification */ + ljustf = 1; + goto fmtnxt; + + case ' ': + case '+': /* leading sign flag */ + sign = *fmt; + goto fmtnxt; + + case '*': /* parameter width value */ + i = va_arg(ap, int); + if (dpoint) + preci = i; + else + width = i; + goto fmtnxt; + + case '.': /* secondary width field */ + dpoint = 1; + goto fmtnxt; + + case 'l': /* long data */ + lval = 1; + goto fmtnxt; + + case 'h': /* short data */ + lval = 0; + goto fmtnxt; + + case 'd': /* Signed decimal */ + case 'i': + ptmp = ltostr((long) ((lval) + ? va_arg(ap, long) + : va_arg(ap, short)), + 10, 0); + goto printit; + + case 'b': /* Unsigned binary */ + radix = 2; + goto usproc; + + case 'o': /* Unsigned octal */ + radix = 8; + goto usproc; + + case 'p': /* Pointer */ + lval = (sizeof(char*) == sizeof(long)); + pad = '0'; + width = 6; + preci = 8; + /* fall thru */ + + case 'x': /* Unsigned hexadecimal */ + case 'X': + radix = 16; + /* fall thru */ + + case 'u': /* Unsigned decimal */ + usproc: + ptmp = ultostr((unsigned long) ((lval) + ? va_arg(ap, unsigned long) + : va_arg(ap, unsigned short)), + radix, (*fmt == 'X') ? 1 : 0); + if( hash && radix == 8 ) { width = strlen(ptmp)+1; pad='0'; } + goto printit; + + case '#': + hash=1; + goto fmtnxt; + + case 'c': /* Character */ + ptmp[0] = va_arg(ap, int); + ptmp[1] = '\0'; + goto nopad; + + case 's': /* String */ + ptmp = va_arg(ap, char*); + nopad: + sign = '\0'; + pad = ' '; + printit: + cnt += prtfld(op, ptmp, ljustf, + sign, pad, width, preci, buffer_mode); + break; + +#if FLOATS + case 'e': /* float */ + case 'f': + case 'g': + case 'E': + case 'G': + fprintf(stderr, "LIBM:PRINTF"); + gcvt(va_arg(ap, double), preci, ptmp); + preci = -1; + goto printit; +#else + case 'e': /* float */ + case 'f': + case 'g': + case 'E': + case 'G': + fprintf(stderr, "LIBC:PRINTF"); + exit(-1); +#endif + + default: /* unknown character */ + goto charout; + } + } + else + { + charout: + putc(*fmt, op); /* normal char out */ + ++cnt; + if( *fmt == '\n' && buffer_mode == _IOLBF ) fflush(op); + } + ++fmt; + } + op->mode |= buffer_mode; + if( buffer_mode == _IONBF ) fflush(op); + if( buffer_mode == _IOLBF ) op->bufwrite = op->bufstart; + return (cnt); +} +#endif diff --git a/libc/stdio/scanf.c b/libc/stdio/scanf.c new file mode 100644 index 000000000..7c5f52183 --- /dev/null +++ b/libc/stdio/scanf.c @@ -0,0 +1,536 @@ +#include <stdio.h> +#include <ctype.h> +#include <string.h> + +#ifdef __STDC__ +#include <stdarg.h> +#define va_strt va_start +#else +#include <varargs.h> +#define va_strt(p,i) va_start(p) +#endif + +#ifdef L_scanf +#ifdef __STDC__ +int scanf(const char * fmt, ...) +#else +int scanf(fmt, va_alist) +__const char *fmt; +va_dcl +#endif +{ + va_list ptr; + int rv; + va_strt(ptr, fmt); + rv = vfscanf(stdin,fmt,ptr); + va_end(ptr); + return rv; +} +#endif + +#ifdef L_sscanf +#ifdef __STDC__ +int sscanf(char * sp, const char * fmt, ...) +#else +int sscanf(sp, fmt, va_alist) +char * sp; +__const char *fmt; +va_dcl +#endif +{ +static FILE string[1] = +{ + {0, (char*)(unsigned) -1, 0, 0, (char*) (unsigned) -1, -1, + _IOFBF | __MODE_READ} +}; + + va_list ptr; + int rv; + va_strt(ptr, fmt); + string->bufpos = sp; + rv = vfscanf(string,fmt,ptr); + va_end(ptr); + return rv; +} +#endif + +#ifdef L_fscanf +#ifdef __STDC__ +int fscanf(FILE * fp, const char * fmt, ...) +#else +int fscanf(fp, fmt, va_alist) +FILE * fp; +__const char *fmt; +va_dcl +#endif +{ + va_list ptr; + int rv; + va_strt(ptr, fmt); + rv = vfscanf(fp,fmt,ptr); + va_end(ptr); + return rv; +} +#endif + +#ifdef L_vscanf +int vscanf(fmt, ap) +__const char *fmt; +va_list ap; +{ + return vfscanf(stdin,fmt,ap); +} +#endif + +#ifdef L_vsscanf +int vsscanf(sp, fmt, ap) +char * sp; +__const char *fmt; +{ +static FILE string[1] = +{ + {0, (char*)(unsigned) -1, 0, 0, (char*) (unsigned) -1, -1, + _IOFBF | __MODE_READ} +}; + + string->bufpos = sp; + return vfscanf(string,fmt,ap); +} +#endif + +#ifdef L_vfscanf + +#if FLOATS +int _vfscanf_fp_ref = 1; +#else +int _vfscanf_fp_ref = 0; +#endif + +/* #define skip() do{c=getc(fp); if (c<1) goto done;}while(isspace(c))*/ + +#define skip() while(isspace(c)) { if ((c=getc(fp))<1) goto done; } + +#if FLOATS +/* fp scan actions */ +#define F_NADA 0 /* just change state */ +#define F_SIGN 1 /* set sign */ +#define F_ESIGN 2 /* set exponent's sign */ +#define F_INT 3 /* adjust integer part */ +#define F_FRAC 4 /* adjust fraction part */ +#define F_EXP 5 /* adjust exponent part */ +#define F_QUIT 6 + +#define NSTATE 8 +#define FS_INIT 0 /* initial state */ +#define FS_SIGNED 1 /* saw sign */ +#define FS_DIGS 2 /* saw digits, no . */ +#define FS_DOT 3 /* saw ., no digits */ +#define FS_DD 4 /* saw digits and . */ +#define FS_E 5 /* saw 'e' */ +#define FS_ESIGN 6 /* saw exp's sign */ +#define FS_EDIGS 7 /* saw exp's digits */ + +#define FC_DIG 0 +#define FC_DOT 1 +#define FC_E 2 +#define FC_SIGN 3 + +/* given transition,state do what action? */ +int fp_do[][NSTATE] = { + {F_INT,F_INT,F_INT, + F_FRAC,F_FRAC, + F_EXP,F_EXP,F_EXP}, /* see digit */ + {F_NADA,F_NADA,F_NADA, + F_QUIT,F_QUIT,F_QUIT,F_QUIT,F_QUIT}, /* see '.' */ + {F_QUIT,F_QUIT, + F_NADA,F_QUIT,F_NADA, + F_QUIT,F_QUIT,F_QUIT}, /* see e/E */ + {F_SIGN,F_QUIT,F_QUIT,F_QUIT,F_QUIT, + F_ESIGN,F_QUIT,F_QUIT}, /* see sign */ +}; +/* given transition,state what is new state? */ +int fp_ns[][NSTATE] = { + {FS_DIGS,FS_DIGS,FS_DIGS, + FS_DD,FS_DD, + FS_EDIGS,FS_EDIGS,FS_EDIGS}, /* see digit */ + {FS_DOT,FS_DOT,FS_DD, + }, /* see '.' */ + {0,0, + FS_E,0,FS_E, + }, /* see e/E */ + {FS_SIGNED,0,0,0,0, + FS_ESIGN,0,0}, /* see sign */ +}; +/* which states are valid terminators? */ +int fp_sval[NSTATE] = { + 0,0,1,0,1,0,0,1 +}; +#endif + +int +vfscanf(fp, fmt, ap) +register FILE *fp; +register char *fmt; +va_list ap; + +{ + register long n; + register int c, width, lval, cnt = 0; + int store, neg, base, wide1, endnull, rngflag, c2; + register unsigned char *p; + unsigned char delim[128], digits[17], *q; +#if FLOATS + long frac, expo; + int eneg, fraclen, fstate, trans; + double fx, fp_scan(); +#endif + + if (!*fmt) + return (0); + + c = getc(fp); + while (c > 0) + { + store = 0; + if (*fmt == '%') + { + n = 0; + width = -1; + wide1 = 1; + base = 10; + lval = (sizeof(long) == sizeof(int)); + store = 1; + endnull = 1; + neg = -1; + + strcpy(delim, "\011\012\013\014\015 "); + strcpy(digits, "0123456789ABCDEF"); + + if (fmt[1] == '*') + { + endnull = store = 0; + ++fmt; + } + + while (isdigit(*++fmt))/* width digit(s) */ + { + if (width == -1) + width = 0; + wide1 = width = (width * 10) + (*fmt - '0'); + } + --fmt; + fmtnxt: + ++fmt; + switch (tolower(*fmt)) /* tolower() is a MACRO! */ + { + case '*': + endnull = store = 0; + goto fmtnxt; + + case 'l': /* long data */ + lval = 1; + goto fmtnxt; + case 'h': /* short data */ + lval = 0; + goto fmtnxt; + + case 'i': /* any-base numeric */ + base = 0; + goto numfmt; + + case 'b': /* unsigned binary */ + base = 2; + goto numfmt; + + case 'o': /* unsigned octal */ + base = 8; + goto numfmt; + + case 'x': /* unsigned hexadecimal */ + base = 16; + goto numfmt; + + case 'd': /* SIGNED decimal */ + neg = 0; + /* FALL-THRU */ + + case 'u': /* unsigned decimal */ + numfmt:skip(); + + if (isupper(*fmt)) + lval = 1; + + if (!base) + { + base = 10; + neg = 0; + if (c == '%') + { + base = 2; + goto skip1; + } + else if (c == '0') + { + c = getc(fp); + if (c < 1) + goto savnum; + if ((c != 'x') + && (c != 'X')) + { + base = 8; + digits[8] = '\0'; + goto zeroin; + } + base = 16; + goto skip1; + } + } + + if ((neg == 0) && (base == 10) + && ((neg = (c == '-')) || (c == '+'))) + { + skip1: + c = getc(fp); + if (c < 1) + goto done; + } + + digits[base] = '\0'; + p = ((unsigned char *) + strchr(digits, toupper(c))); + + if ((!c || !p) && width) + goto done; + + while (p && width-- && c) + { + n = (n * base) + (p - digits); + c = getc(fp); + zeroin: + p = ((unsigned char *) + strchr(digits, toupper(c))); + } + savnum: + if (store) + { + if (neg == 1) + n = -n; + if (lval) + *va_arg(ap, long*) = n; + else + *va_arg(ap, short*) = n; + ++cnt; + } + break; + +#if FLOATS + case 'e': /* float */ + case 'f': + case 'g': + skip(); + fprintf(stderr,"LIBM:SCANF"); + + if (isupper(*fmt)) + lval = 1; + + fstate = FS_INIT; + neg = 0; + eneg = 0; + n = 0; + frac = 0; + expo = 0; + fraclen = 0; + + while (c && width--) + { + if (c >= '0' && c <= '9') + trans = FC_DIG; + else if (c == '.') + trans = FC_DOT; + else if (c == '+' || c == '-') + trans = FC_SIGN; + else if (tolower(c) == 'e') + trans = FC_E; + else + goto fdone; + + switch (fp_do[trans][fstate]) + { + case F_SIGN: + neg = (c == '-'); + break; + case F_ESIGN: + eneg = (c == '-'); + break; + case F_INT: + n = 10 * n + (c - '0'); + break; + case F_FRAC: + frac = 10 * frac + (c - '0'); + fraclen++; + break; + case F_EXP: + expo = 10 * expo + (c - '0'); + break; + case F_QUIT: + goto fdone; + } + fstate = fp_ns[trans][fstate]; + c = getc(fp); + } + + fdone: + if (!fp_sval[fstate]) + goto done; + if (store) + { + fx = fp_scan(neg, eneg, n, frac, expo, fraclen); + if (lval) + *va_arg(ap, double *) = fx; + else + *va_arg(ap, float *) = fx; + ++cnt; + } + break; +#else + case 'e': /* float */ + case 'f': + case 'g': + fprintf(stderr, "LIBC:SCANF"); + exit(-1); +#endif + + case 'c': /* character data */ + width = wide1; + lval = endnull = 0; + delim[0] = '\0'; + goto strproc; + + case '[': /* string w/ delimiter set */ + + /* get delimiters */ + p = delim; + + if (*++fmt == '^') + { + fmt++; + lval = 0; + } + else + lval = 1; + + rngflag = 2; + if ((*fmt == ']') || (*fmt == '-')) + { + *p++ = *fmt++; + rngflag = 0; + } + + while (*fmt != ']') + { + if (*fmt == '\0') + goto done; + switch (rngflag) + { + case 1: + c2 = *(p - 2); + if (c2 <= *fmt) + { + p -= 2; + while (c2 < *fmt) + *p++ = c2++; + rngflag = 2; + break; + } + /* fall thru intentional */ + + case 0: + rngflag = (*fmt == '-'); + break; + + case 2: + rngflag = 0; + } + + *p++ = *fmt++; + } + + *p = '\0'; + goto strproc; + + case 's': /* string data */ + lval = 0; + skip(); + strproc: + /* process string */ + p = va_arg(ap, unsigned char *); + + /* if the 1st char fails, match fails */ + if (width) + { + q = ((unsigned char *) + strchr(delim, c)); + if ((c < 1) || lval == (q==0)) + { + if (endnull) + *p = '\0'; + goto done; + } + } + + for (;;) /* FOREVER */ + { + if (store) + *p++ = c; + if (((c = getc(fp)) < 1) || + (--width == 0)) + break; + + q = ((unsigned char *) + strchr(delim, c)); + if (lval == (q==0)) + break; + } + + if (store) + { + if (endnull) + *p = '\0'; + ++cnt; + } + break; + + case '\0': /* early EOS */ + --fmt; + /* FALL THRU */ + + default: + goto cmatch; + } + } + else if (isspace(*fmt)) /* skip whitespace */ + { + skip(); + } + else + { /* normal match char */ + cmatch: + if (c != *fmt) + break; + c = getc(fp); + } + + if (!*++fmt) + break; + } + + done: /* end of scan */ + if ((c == EOF) && (cnt == 0)) + return (EOF); + + if( c != EOF ) + ungetc(c, fp); + return (cnt); +} + +#endif diff --git a/libc/stdio/stdio.c b/libc/stdio/stdio.c new file mode 100644 index 000000000..98d0ba3b4 --- /dev/null +++ b/libc/stdio/stdio.c @@ -0,0 +1,925 @@ +/* Copyright (C) 1996 Robert de Bath <rdebath@cix.compulink.co.uk> + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ + +/* This is an implementation of the C standard IO package. + */ + +#include <stdio.h> + +#include <fcntl.h> +#include <sys/types.h> +#include <malloc.h> +#include <errno.h> + +#undef STUB_FWRITE + +extern FILE *__IO_list; /* For fflush at exit */ + +#define FIXED_BUFFERS 2 +struct fixed_buffer { + unsigned char data[BUFSIZ]; + int used; +}; + +extern struct fixed_buffer _fixed_buffers[2]; + +#define Inline_init __io_init_vars() + +#ifdef L__stdio_init + +#define buferr (stderr->unbuf) /* Stderr is unbuffered */ + +FILE *__IO_list = 0; /* For fflush at exit */ + +#if 0 +static char bufin[BUFSIZ]; +static char bufout[BUFSIZ]; +#ifndef buferr +static char buferr[BUFSIZ]; +#endif + +#else +static char *bufin; +static char *bufout; +#ifndef buferr +static char *buferr; +#endif +#endif + +FILE stdin[1] = +{ +#if 0 + {bufin, bufin, bufin, bufin, bufin + sizeof(bufin), +#else + {0, 0, 0, 0, 0, +#endif + 0, _IOFBF | __MODE_READ | __MODE_IOTRAN} +}; + +FILE stdout[1] = +{ +#if 0 + {bufout, bufout, bufout, bufout, bufout + sizeof(bufout), +#else + {0, 0, 0, 0, 0, +#endif + 1, _IOFBF | __MODE_WRITE | __MODE_IOTRAN} +}; + +FILE stderr[1] = +{ +#if 0 + {buferr, buferr, buferr, buferr, buferr + sizeof(buferr), +#else + {0, 0, 0, 0, 0, +#endif + 2, _IONBF | __MODE_WRITE | __MODE_IOTRAN} +}; + +/* Call the stdio initiliser; it's main job it to call atexit */ + +#define STATIC + +STATIC int +__stdio_close_all() +{ + FILE *fp; + fflush(stdout); + fflush(stderr); + for (fp = __IO_list; fp; fp = fp->next) + { + fflush(fp); + close(fp->fd); + /* Note we're not de-allocating the memory */ + /* There doesn't seem to be much point :-) */ + fp->fd = -1; + } +} + +static int first_time = 0; + +struct fixed_buffer _fixed_buffers[2]; + + +STATIC void +__io_init_vars() +{ + if( first_time ) return; + first_time = 1; + + stdin->bufpos = bufin = _fixed_buffers[0].data; /*(char *)malloc(BUFSIZ)*/; + stdin->bufread = bufin; + stdin->bufwrite = bufin; + stdin->bufstart = bufin; + stdin->bufend = bufin + sizeof(bufin); + stdin->fd = 0; + stdin->mode = _IOFBF | __MODE_READ | __MODE_IOTRAN | __MODE_FREEBUF; + + _fixed_buffers[0].used = 1; + + stdout->bufpos = bufout = _fixed_buffers[1].data; /*(char *)malloc(BUFSIZ);*/ + stdout->bufread = bufout; + stdout->bufwrite = bufout; + stdout->bufstart = bufout; + stdout->bufend = bufout + sizeof(bufout); + stdout->fd = 1; + stdout->mode = _IOFBF | __MODE_WRITE | __MODE_IOTRAN | __MODE_FREEBUF; + + _fixed_buffers[1].used = 1; + +#if 0 + stderr->bufpos = buferr = (char *)malloc(BUFSIZ); +#else + stderr->bufpos = buferr; +#endif + stderr->bufread = buferr; + stderr->bufwrite = buferr; + stderr->bufstart = buferr; + stderr->bufend = buferr + sizeof(buferr); + stderr->fd = 2; + stderr->mode = _IONBF | __MODE_WRITE | __MODE_IOTRAN; + + if (isatty(1)) + stdout->mode |= _IOLBF; + atexit(__stdio_close_all); +} +#endif + +#ifdef L_fputc +int +fputc(ch, fp) +int ch; +FILE *fp; +{ + register int v; + Inline_init; + + v = fp->mode; + /* If last op was a read ... */ + if ((v & __MODE_READING) && fflush(fp)) + return EOF; + + /* Can't write or there's been an EOF or error then return EOF */ + if ((v & (__MODE_WRITE | __MODE_EOF | __MODE_ERR)) != __MODE_WRITE) + return EOF; + + /* In MSDOS translation mode */ +#if __MODE_IOTRAN + if (ch == '\n' && (v & __MODE_IOTRAN) && fputc('\r', fp) == EOF) + return EOF; +#endif + + /* Buffer is full */ + if (fp->bufpos >= fp->bufend && fflush(fp)) + return EOF; + + /* Right! Do it! */ + *(fp->bufpos++) = ch; + fp->mode |= __MODE_WRITING; + + /* Unbuffered or Line buffered and end of line */ + if (((ch == '\n' && (v & _IOLBF)) || (v & _IONBF)) + && fflush(fp)) + return EOF; + + /* Can the macro handle this by itself ? */ + if (v & (__MODE_IOTRAN | _IOLBF | _IONBF)) + fp->bufwrite = fp->bufstart; /* Nope */ + else + fp->bufwrite = fp->bufend; /* Yup */ + + /* Correct return val */ + return (unsigned char) ch; +} +#endif + +#ifdef L_fgetc +int +fgetc(fp) +FILE *fp; +{ + int ch; + Inline_init; + + if (fp->mode & __MODE_WRITING) + fflush(fp); + + try_again: + /* Can't read or there's been an EOF or error then return EOF */ + if ((fp->mode & (__MODE_READ | __MODE_EOF | __MODE_ERR)) != __MODE_READ) + return EOF; + + /* Nothing in the buffer - fill it up */ + if (fp->bufpos >= fp->bufread) + { + fp->bufpos = fp->bufread = fp->bufstart; + ch = fread(fp->bufpos, 1, fp->bufend - fp->bufstart, fp); + if (ch == 0) + return EOF; + fp->bufread += ch; + fp->mode |= __MODE_READING; + fp->mode &= ~__MODE_UNGOT; + } + ch = *(fp->bufpos++); + +#if __MODE_IOTRAN + /* In MSDOS translation mode; WARN: Doesn't work with UNIX macro */ + if (ch == '\r' && (fp->mode & __MODE_IOTRAN)) + goto try_again; +#endif + + return ch; +} +#endif + +#ifdef L_fflush +int +fflush(fp) +FILE *fp; +{ + int len, cc, rv=0; + char * bstart; + if (fp == NULL) /* On NULL flush the lot. */ + { + if (fflush(stdin)) + return EOF; + if (fflush(stdout)) + return EOF; + if (fflush(stderr)) + return EOF; + + for (fp = __IO_list; fp; fp = fp->next) + if (fflush(fp)) + return EOF; + + return 0; + } + + /* If there's output data pending */ + if (fp->mode & __MODE_WRITING) + { + len = fp->bufpos - fp->bufstart; + + if (len) + { + bstart = fp->bufstart; + /* + * The loop is so we don't get upset by signals or partial writes. + */ + do + { + cc = write(fp->fd, bstart, len); + if( cc > 0 ) + { + bstart+=cc; len-=cc; + } + } + while ( cc>0 || (cc == -1 && errno == EINTR)); + /* + * If we get here with len!=0 there was an error, exactly what to + * do about it is another matter ... + * + * I'll just clear the buffer. + */ + if (len) + { + fp->mode |= __MODE_ERR; + rv = EOF; + } + } + } + /* If there's data in the buffer sychronise the file positions */ + else if (fp->mode & __MODE_READING) + { + /* Humm, I think this means sync the file like fpurge() ... */ + /* Anyway the user isn't supposed to call this function when reading */ + + len = fp->bufread - fp->bufpos; /* Bytes buffered but unread */ + /* If it's a file, make it good */ + if (len > 0 && lseek(fp->fd, (long)-len, 1) < 0) + { + /* Hummm - Not certain here, I don't think this is reported */ + /* + * fp->mode |= __MODE_ERR; return EOF; + */ + } + } + + /* All done, no problem */ + fp->mode &= (~(__MODE_READING|__MODE_WRITING|__MODE_EOF|__MODE_UNGOT)); + fp->bufread = fp->bufwrite = fp->bufpos = fp->bufstart; + return rv; +} +#endif + +#ifdef L_fgets +/* Nothing special here ... */ +char * +fgets(s, count, f) +char *s; +size_t count; +FILE *f; +{ + char *ret; + register size_t i; + register int ch; + + ret = s; + for (i = count; i > 0; i--) + { + ch = getc(f); + if (ch == EOF) + { + if (s == ret) + return 0; + break; + } + *s++ = (char) ch; + if (ch == '\n') + break; + } + *s = 0; + + if (ferror(f)) + return 0; + return ret; +} +#endif + +#ifdef L_gets +char * +gets(str) /* BAD function; DON'T use it! */ +char *str; +{ + /* Auwlright it will work but of course _your_ program will crash */ + /* if it's given a too long line */ + register char *p = str; + register int c; + + while (((c = getc(stdin)) != EOF) && (c != '\n')) + *p++ = c; + *p = '\0'; + return (((c == EOF) && (p == str)) ? NULL : str); /* NULL == EOF */ +} +#endif + +#ifdef L_fputs +int +fputs(str, fp) +char *str; +FILE *fp; +{ + register int n = 0; + while (*str) + { + if (putc(*str++, fp) == EOF) + return (EOF); + ++n; + } + return (n); +} +#endif + +#ifdef L_puts +int +puts(str) +char *str; +{ + register int n; + + if (((n = fputs(str, stdout)) == EOF) + || (putc('\n', stdout) == EOF)) + return (EOF); + return (++n); +} +#endif + +#ifdef L_fread +/* + * fread will often be used to read in large chunks of data calling read() + * directly can be a big win in this case. Beware also fgetc calls this + * function to fill the buffer. + * + * This ignores __MODE__IOTRAN; probably exactly what you want. (It _is_ what + * fgetc wants) + */ +int +fread(buf, size, nelm, fp) +char *buf; +int size; +int nelm; +FILE *fp; +{ + int len, v; + unsigned bytes, got = 0; + Inline_init; + + v = fp->mode; + + /* Want to do this to bring the file pointer up to date */ + if (v & __MODE_WRITING) + fflush(fp); + + /* Can't read or there's been an EOF or error then return zero */ + if ((v & (__MODE_READ | __MODE_EOF | __MODE_ERR)) != __MODE_READ) + return 0; + + /* This could be long, doesn't seem much point tho */ + bytes = size * nelm; + + len = fp->bufread - fp->bufpos; + if (len >= bytes) /* Enough buffered */ + { + memcpy(buf, fp->bufpos, (unsigned) bytes); + fp->bufpos += bytes; + return bytes; + } + else if (len > 0) /* Some buffered */ + { + memcpy(buf, fp->bufpos, len); + got = len; + } + + /* Need more; do it with a direct read */ + len = read(fp->fd, buf + got, (unsigned) (bytes - got)); + + /* Possibly for now _or_ later */ + if (len < 0) + { + fp->mode |= __MODE_ERR; + len = 0; + } + else if (len == 0) + fp->mode |= __MODE_EOF; + + return (got + len) / size; +} +#endif + +#ifdef L_fwrite +/* + * Like fread, fwrite will often be used to write out large chunks of + * data; calling write() directly can be a big win in this case. + * + * But first we check to see if there's space in the buffer. + * + * Again this ignores __MODE__IOTRAN. + */ +int +fwrite(buf, size, nelm, fp) +char *buf; +int size; +int nelm; +FILE *fp; +{ + register int v; + int len; + unsigned bytes, put; + +#ifdef STUB_FWRITE + bytes = size * nelm; + while(bytes>0) { + len=write(fp->fd, buf, bytes); + if (len<=0) { + break; + } + bytes -= len; + buf += len; + } + return nelm; +#else + + v = fp->mode; + /* If last op was a read ... */ + if ((v & __MODE_READING) && fflush(fp)) + return 0; + + /* Can't write or there's been an EOF or error then return 0 */ + if ((v & (__MODE_WRITE | __MODE_EOF | __MODE_ERR)) != __MODE_WRITE) + return 0; + + /* This could be long, doesn't seem much point tho */ + bytes = size * nelm; + + len = fp->bufend - fp->bufpos; + + /* Flush the buffer if not enough room */ + if (bytes > len) + if (fflush(fp)) + return 0; + + len = fp->bufend - fp->bufpos; + if (bytes <= len) /* It'll fit in the buffer ? */ + { + fp->mode |= __MODE_WRITING; + memcpy(fp->bufpos, buf, bytes); + fp->bufpos += bytes; + + /* If we're not fully buffered */ + if (v & (_IOLBF | _IONBF)) + fflush(fp); + + return nelm; + } + else + /* Too big for the buffer */ + { + put = bytes; + do + { + len = write(fp->fd, buf, bytes); + if( len > 0 ) + { + buf+=len; bytes-=len; + } + } + while (len > 0 || (len == -1 && errno == EINTR)); + + if (len < 0) + fp->mode |= __MODE_ERR; + + put -= bytes; + } + + return put / size; +#endif +} +#endif + +#ifdef L_rewind +void +rewind(fp) +FILE * fp; +{ + fseek(fp, (long)0, 0); + clearerr(fp); +} +#endif + +#ifdef L_fseek +int +fseek(fp, offset, ref) +FILE *fp; +long offset; +int ref; +{ +#if 0 + /* FIXME: this is broken! BROKEN!!!! */ + /* if __MODE_READING and no ungetc ever done can just move pointer */ + /* This needs testing! */ + + if ( (fp->mode &(__MODE_READING | __MODE_UNGOT)) == __MODE_READING && + ( ref == SEEK_SET || ref == SEEK_CUR )) + { + long fpos = lseek(fp->fd, 0L, SEEK_CUR); + if( fpos == -1 ) return EOF; + + if( ref == SEEK_CUR ) + { + ref = SEEK_SET; + offset = fpos + offset + fp->bufpos - fp->bufread; + } + if( ref == SEEK_SET ) + { + if ( offset < fpos && offset >= fpos + fp->bufstart - fp->bufread ) + { + fp->bufpos = offset - fpos + fp->bufread; + return 0; + } + } + } +#endif + + /* Use fflush to sync the pointers */ + + if (fflush(fp) == EOF) + return EOF; + if (lseek(fp->fd, offset, ref) < 0) + return EOF; + return 0; +} +#endif + +#ifdef L_ftell +long ftell(fp) +FILE * fp; +{ + long rv; + if (fflush(fp) == EOF) + return EOF; + return lseek(fp->fd, 0L, SEEK_CUR); +} +#endif + +#ifdef L_fopen +/* + * This Fopen is all three of fopen, fdopen and freopen. The macros in + * stdio.h show the other names. + */ +FILE * +__fopen(fname, fd, fp, mode) +char *fname; +int fd; +FILE *fp; +char *mode; +{ + int open_mode = 0; +#if __MODE_IOTRAN + int do_iosense = 1; +#endif + int fopen_mode = 0; + FILE *nfp = 0; + + /* If we've got an fp close the old one (freopen) */ + if (fp) + { + /* Careful, don't de-allocate it */ + fopen_mode |= (fp->mode & (__MODE_BUF | __MODE_FREEFIL | __MODE_FREEBUF)); + fp->mode &= ~(__MODE_FREEFIL | __MODE_FREEBUF); + fclose(fp); + } + + /* decode the new open mode */ + while (*mode) + switch (*mode++) + { + case 'r': + fopen_mode |= __MODE_READ; + break; + case 'w': + fopen_mode |= __MODE_WRITE; + open_mode = (O_CREAT | O_TRUNC); + break; + case 'a': + fopen_mode |= __MODE_WRITE; + open_mode = (O_CREAT | O_APPEND); + break; + case '+': + fopen_mode |= __MODE_RDWR; + break; +#if __MODE_IOTRAN + case 'b': /* Binary */ + fopen_mode &= ~__MODE_IOTRAN; + do_iosense=0; + break; + case 't': /* Text */ + fopen_mode |= __MODE_IOTRAN; + do_iosense=0; + break; +#endif + } + + /* Add in the read/write options to mode for open() */ + switch (fopen_mode & (__MODE_READ | __MODE_WRITE)) + { + case 0: + return 0; + case __MODE_READ: + open_mode |= O_RDONLY; + break; + case __MODE_WRITE: + open_mode |= O_WRONLY; + break; + default: + open_mode |= O_RDWR; + break; + } + + /* Allocate the (FILE) before we do anything irreversable */ + if (fp == 0) + { + nfp = malloc(sizeof(FILE)); + if (nfp == 0) + return 0; + } + + /* Open the file itself */ + if (fname) + fd = open(fname, open_mode, 0666); + if (fd < 0) /* Grrrr */ + { + if (nfp) + free(nfp); + return 0; + } + + /* If this isn't freopen create a (FILE) and buffer for it */ + if (fp == 0) + { + int i; + fp = nfp; + fp->next = __IO_list; + __IO_list = fp; + + fp->mode = __MODE_FREEFIL; + if( isatty(fd) ) + { + fp->mode |= _IOLBF; +#if __MODE_IOTRAN + if( do_iosense ) fopen_mode |= __MODE_IOTRAN; +#endif + } + else + fp->mode |= _IOFBF; + + for(i=0;i<FIXED_BUFFERS;i++) + if (!_fixed_buffers[i].used) { + fp->bufstart = _fixed_buffers[i].data; + _fixed_buffers[i].used = 1; + break; + } + + if (i == FIXED_BUFFERS) + fp->bufstart = malloc(BUFSIZ); + + if (fp->bufstart == 0) /* Oops, no mem */ + { /* Humm, full buffering with a two(!) byte + * buffer. */ + fp->bufstart = fp->unbuf; + fp->bufend = fp->unbuf + sizeof(fp->unbuf); + } + else + { + fp->bufend = fp->bufstart + BUFSIZ; + fp->mode |= __MODE_FREEBUF; + } + } + /* Ok, file's ready clear the buffer and save important bits */ + fp->bufpos = fp->bufread = fp->bufwrite = fp->bufstart; + fp->mode |= fopen_mode; + fp->fd = fd; + return fp; +} +#endif + +#ifdef L_fclose +int +fclose(fp) +FILE *fp; +{ + int rv = 0; + + if (fp == 0) + { + errno = EINVAL; + return EOF; + } + if (fflush(fp)) + return EOF; + + if (close(fp->fd)) + rv = EOF; + fp->fd = -1; + + if (fp->mode & __MODE_FREEBUF) + { + int i; + for(i=0;i<FIXED_BUFFERS;i++) + if (fp->bufstart == _fixed_buffers[i].data) { + _fixed_buffers[i].used = 0; + break; + } + if(i==FIXED_BUFFERS) + free(fp->bufstart); + fp->mode &= ~__MODE_FREEBUF; + fp->bufstart = fp->bufend = 0; + } + + if (fp->mode & __MODE_FREEFIL) + { + FILE *prev = 0, *ptr; + fp->mode = 0; + + for (ptr = __IO_list; ptr && ptr != fp; ptr = ptr->next) + ; + if (ptr == fp) + { + if (prev == 0) + __IO_list = fp->next; + else + prev->next = fp->next; + } + free(fp); + } + else + fp->mode = 0; + + return rv; +} +#endif + +#ifdef L_setbuffer +void +setbuffer(fp, buf, size) +FILE * fp; +char * buf; +int size; +{ + fflush(fp); + + if ((fp->bufstart == (unsigned char*)buf) && (fp->bufend == ((unsigned char*)buf + size))) + return; + + if( fp->mode & __MODE_FREEBUF ) { + int i; + for(i=0;i<FIXED_BUFFERS;i++) + if (fp->bufstart == _fixed_buffers[i].data) { + _fixed_buffers[i].used = 0; + break; + } + if(i==FIXED_BUFFERS) + free(fp->bufstart); + } + fp->mode &= ~(__MODE_FREEBUF|__MODE_BUF); + + if( buf == 0 ) + { + fp->bufstart = fp->unbuf; + fp->bufend = fp->unbuf + sizeof(fp->unbuf); + fp->mode |= _IONBF; + } + else + { + fp->bufstart = buf; + fp->bufend = buf+size; + fp->mode |= _IOFBF; + } + fp->bufpos = fp->bufread = fp->bufwrite = fp->bufstart; +} +#endif + +#ifdef L_setvbuf +int setvbuf(fp, buf, mode, size) +FILE * fp; +char * buf; +int mode; +size_t size; +{ + fflush(fp); + if( fp->mode & __MODE_FREEBUF ) { + int i; + for(i=0;i<FIXED_BUFFERS;i++) + if (fp->bufstart == _fixed_buffers[i].data) { + _fixed_buffers[i].used = 0; + break; + } + if(i==FIXED_BUFFERS) + free(fp->bufstart); + } + fp->mode &= ~(__MODE_FREEBUF|__MODE_BUF); + fp->bufstart = fp->unbuf; + fp->bufend = fp->unbuf + sizeof(fp->unbuf); + fp->mode |= _IONBF; + + if( mode == _IOFBF || mode == _IOLBF ) + { + if( size <= 0 ) size = BUFSIZ; + if( buf == 0 ) + if (size == BUFSIZ) { + int i; + for(i=0;i<FIXED_BUFFERS;i++) + if (!_fixed_buffers[i].used) { + _fixed_buffers[i].used = 1; + buf = _fixed_buffers[i].data; + break; + } + if(i==FIXED_BUFFERS) + buf = malloc(size); + } else + buf = malloc(size); + if( buf == 0 ) return EOF; + + fp->bufstart = buf; + fp->bufend = buf+size; + fp->mode |= mode; + } + fp->bufpos = fp->bufread = fp->bufwrite = fp->bufstart; +} +#endif + +#ifdef L_ungetc +int +ungetc(c, fp) +int c; +FILE *fp; +{ + if (fp->mode & __MODE_WRITING) + fflush(fp); + + /* Can't read or there's been an error then return EOF */ + if ((fp->mode & (__MODE_READ | __MODE_ERR)) != __MODE_READ) + return EOF; + + /* Can't do fast fseeks */ + fp->mode |= __MODE_UNGOT; + + if( fp->bufpos > fp->bufstart ) + return *--fp->bufpos = (unsigned char) c; + else if( fp->bufread == fp->bufstart ) + return *fp->bufread++ = (unsigned char) c; + else + return EOF; +} +#endif |