cechew@bruce.OZ (Earl Chew) (09/29/89)
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 5 (of 6)."
# Contents: config.h stdiolib.h vfprintf.c
# Wrapped by cechew@bruce on Fri Sep 29 16:23:40 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'config.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'config.h'\"
else
echo shar: Extracting \"'config.h'\" \(6632 characters\)
sed "s/^X//" >'config.h' <<'END_OF_FILE'
X/* c o n f i g
X *
X * (C) Copyright C E Chew
X *
X * Feel free to copy, use and distribute this software provided:
X *
X * 1. you do not pretend that you wrote it
X * 2. you leave this copyright notice intact.
X *
X * This file describes the environment under which stdio
X * is to be compiled.
X *
X * Patchlevel 2.0
X *
X * Edit History:
X */
X
X/*
X * The macros that are defined in this file are:
X *
X * _BSD
X * Select BSD environment.
X * _MINIX
X * Selects Minix environment.
X * MANUAL
X * Select code control manually, otherwise it will
X * be selected `automatically' based on __STDC__
X * and operating system selection (defaults to _MINIX
X * if no system selected).
X *
X * Code control:
X *
X * PROTOTYPE
X * Function prototype inclusion.
X * MEMORY
X * Use memory.h. If this is not defined, users must provide
X * definitions for MEMCPY, MEMSET and MEMCHR.
X * MYMEMCPY
X * Use stdio code for memcpy.
X * MYMEMCHR
X * Use stdio code for memchr.
X * MYMEMSET
X * Use stdio code for memset.
X * STDARG
X * Use stdarg.h instead or varargs.h.
X * LIMITS
X * Use limits.h.
X * STRING
X * Use string.h.
X * MEMSTR
X * Use memchr to do fast strlen.
X * OPEN3
X * Use open(2) for three argument opens.
X * RENAME
X * Use rename(2).
X * SYSTYPES
X * Use sys/types.h.
X * TIME
X * Use time.h.
X * UNSIGNEDCHAR
X * Use (int) ((unsigned char) (x)) for unsigned casts instead
X * of (x) & ((1 << CHAR_BIT) - 1).
X *
X * Stdio performance control:
X *
X * FREADTHRESHOLD
X * FWRITETHRESHOLD
X * Threshold beyond which fwrite or fread will use memcpy() to
X * do the transfer instead of PUTC().
X * MEMSET(s,v,n)
X * Set a piece of memory to the specified value.
X * MEMCPY(d,s,n)
X * Copy a piece of memory of length n from s to d. No return
X * value expected.
X * MEMCHR(s,c,n)
X * Look in a piece of memory s of length n for character c. Return
X * a pointer to the c if found, otherwise null.
X * TOLOWER(c)
X * Convert uppercase to lowercase.
X */
X
X/****************************************************************
X * System Configuration *
X ***************************************************************/
X
X#ifndef SOURCE
X
X/*define _BSD*/ /* BSD system */
X/*define _MINIX*/ /* Minix system */
X
X/*define MANUAL*/ /* manual code control */
X
X# define FWRITETHRESHOLD 10 /* fwrite memcpy call threshold */
X# define FREADTHRESHOLD 10 /* fread memcpy call threshold */
X
X/****************************************************************
X * Manual Selection *
X ****************************************************************/
X# ifdef MANUAL
X# include "site.h"
X/* define PROTOTYPE*/ /* use function prototypes */
X/* define UNSIGNEDCHAR*/ /* use (unsigned char) cast */
X/* define MEMORY*/ /* use memory.h */
X/* define STDARG*/ /* use stdarg.h */
X/* define LIMITS*/ /* use limits.h */
X/* define STRING*/ /* use string.h */
X/* define MEMSTR*/ /* use memory for string */
X/* define SYSTYPES*/ /* use sys/types.h */
X/* define TIME*/ /* use time.h */
X/* define TOLOWER tolower*/ /* use tolower */
X/* define OPEN3*/ /* use 3 argument opens */
X
X/****************************************************************
X * Automatic Selection *
X ****************************************************************/
X# else
X# ifndef _BSD
X# ifndef _MINIX
X# define _MINIX
X# endif
X# endif
X# ifdef __STDC__
X# define PROTOTYPE /* use function prototypes */
X# define UNSIGNEDCHAR /* use (unsigned char) cast */
X# endif
X# define MEMORY /* use memory.h */
X# undef MYMEMCPY /* don't use local memcpy */
X# undef MYMEMCHR /* don't use local memchr */
X# undef MYMEMSET /* don't use local memset */
X# define STDARG /* use stdarg.h */
X# define LIMITS /* use limits.h */
X# define STRING /* use string.h */
X# define MEMSTR /* use memory for string */
X# define SYSTYPES /* use sys/types.h */
X# define TIME /* use time.h */
X# define TOLOWER tolower /* use tolower */
X# ifdef O_CREAT
X# ifdef O_TRUNC
X# ifdef O_APPEND
X# define OPEN3 /* use three argument opens */
X# endif
X# endif
X# endif
X# endif
X
X/****************************************************************
X * Hacks for Non Posix/ANSI Environments *
X ****************************************************************/
X
X# ifdef PROTOTYPE
X# define P(x) x
X# else
X# define P(x) ()
X# endif
X
X# ifdef _MINIX
X extern int tolower P((int));
X
X# undef TIME
X typedef long time_t;
X
X# undef SYSTYPES
X typedef long off_t;
X typedef int pid_t;
X typedef int uid_t;
X typedef int mode_t;
X# define _SIZE_T
X typedef unsigned int size_t;
X# endif
X
X# ifdef _BSD
X# undef MEMORY /* don't use memory.h */
X extern void bcopy();
X# define MEMCPY(d,s,n) bcopy((s),(d),(n))
X# undef MYMEMCPY
X# define MYMEMCHR
X# define MYMEMSET
X
X# undef STDARG /* don't use stdarg.h */
X
X# undef LIMITS /* don't use limits.h */
X# include <values.h>
X# define INT_MAX (MAXINT)
X# define USHRT_MAX ((unsigned short) MAXSHORT)
X# define CHAR_BIT (BITSPERBYTE)
X
X# undef STRING /* don't use string.h */
X# include <strings.h>
X# undef MEMSTR /* don't use memory for string */
X
X# define SYSTYPES /* use sys/types.h */
X typedef int pid_t;
X typedef int mode_t;
X# define _SIZE_T /* already defined in sys/types.h */
X
X# undef TIME /* don't use time.h */
X
X# define RENAME /* use rename(2) */
X
X# undef TOLOWER /* don't use tolower */
X# define TOLOWER(c) (isupper((c)) ? tolower((c)) : (c))
X# endif
X
X/****************************************************************
X * System Support Code *
X ****************************************************************/
X
X# ifdef MYMEMCPY
X char *memcpy P((void *, void *, size_t));
X# define MEMCPY(s,c,n) memcpy((s),(c),(n))
X# endif
X# ifdef MYMEMCHR
X char *memchr P((void *, int, size_t));
X# define MEMCHR(s,c,n) memchr((s),(c),(n))
X# endif
X# ifdef MYMEMSET
X void memset P((void *, int, size_t));
X# define MEMSET(d,c,n) memset((d),(c),(n))
X# endif
X
X# undef P
X#endif
X
X#ifdef SOURCE
X# ifdef MYMEMCPY
Xchar *memcpy(T(void *d, d), T(void *s, s), T(size_t n, n))
X
XD(void *d)
XD(void *s)
XD(size_t n)
X
X{
X char *p = (char *) d;
X char *q = (char *) s;
X
X if (n != 0)
X do
X *p++ = *q++;
X while (--n);
X
X return (char *) d;
X}
X# endif
X
X# ifdef MYMEMCHR
Xchar *memchr(T(void *s, s), T(int c, c), T(size_t n, n))
X
XD(void *s)
XD(int c)
XD(size_t n)
X
X{
X char *p = (char *) s;
X
X if (n != 0)
X for (; *p++ != c && --n; )
X ;
X return n != 0 ? p-1 : 0;
X}
X# endif
X
X# ifdef MYMEMSET
Xvoid memset(T(void *d, d), T(int c, c), T(size_t n, n))
X
XD(void *d)
XD(int c)
XD(size_t n)
X
X{
X char *p = (char *) d;
X
X if (n != 0)
X for (; *p++ = c, --n; )
X ;
X}
X# endif
X#endif
END_OF_FILE
if test 6632 -ne `wc -c <'config.h'`; then
echo shar: \"'config.h'\" unpacked with wrong size!
fi
# end of 'config.h'
fi
if test -f 'stdiolib.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'stdiolib.h'\"
else
echo shar: Extracting \"'stdiolib.h'\" \(12113 characters\)
sed "s/^X//" >'stdiolib.h' <<'END_OF_FILE'
X/* s t d i o l i b
X *
X * (C) Copyright C E Chew
X *
X * Feel free to copy, use and distribute this software provided:
X *
X * 1. you do not pretend that you wrote it
X * 2. you leave this copyright notice intact.
X *
X * This include file is used by the stdio code. It provides some
X * useful macro definitions that make the code a bit easier to
X * write.
X *
X * Patchlevel 2.0
X *
X * Edit History:
X */
X
X#include <fcntl.h>
X
X#include "config.h"
X
X/* System types */
X
X#ifdef SYSTYPES
X# include <sys/types.h>
X#endif
X
X/* Time types */
X
X#ifdef TIME
X# include <time.h>
X#endif
X
X/* Rest of includes */
X
X#include <sys/stat.h>
X#include <pwd.h>
X#include <errno.h>
X#include <stdio.h>
X
X/* Limits */
X
X#ifdef LIMITS
X# include <limits.h>
X#endif
X
X/* Variable argument list hiding */
X
X#ifdef STDARG
X# include <stdarg.h>
X# define VA_START(n,l) va_start(n,l)
X# define VA_ALIST ...
X# define VA_LIST va_list
X# define VA_END(n) va_end(n)
X# define VA_ARG(n,t) va_arg(n,t)
X# define VA_DCL
X#else
X# include <varargs.h>
X# define VA_START(n,l) va_start(n)
X# define VA_ALIST va_alist
X# define VA_LIST va_list
X# define VA_END(n) va_end(n)
X# define VA_ARG(n,t) va_arg(n,t)
X# define VA_DCL va_dcl
X#endif
X
X/* Function prototype hiding */
X
X#ifdef PROTOTYPE
X# define P(x) x
X# define T(x,y) x
X# define D(x)
X#else
X# define P(x) ()
X# define T(x,y) y
X# define D(x) x;
X#endif
X
X#ifdef MEMORY
X# include <memory.h>
X# define MEMCPY(d,s,n) ((void) memcpy((d),(s),(n)))
X# define MEMCHR(s,c,n) (memchr((s),(c),(n)))
X# define MEMSET(s,v,n) ((void) memset((s),(v),(n)))
X#endif
X
X/* Strings */
X
X#ifdef STRING
X# include <string.h>
X#endif
X
X/* String functions using memory functions */
X
X#ifdef MEMSTR
X# undef strlen
X# define strlen(s) ((char *) MEMCHR((s),(0),INT_MAX) - (char *) (s))
X#endif
X
X/* Unsigned char casting */
X
X#ifdef UNSIGNEDCHAR
X# define UCHAR(x) ((int) ((unsigned char) (x)))
X#else
X# define UCHAR(x) ((int) (x) & ((1 << CHAR_BIT) - 1))
X#endif
X
X/* Stdio internal types */
X
Xtypedef void (*atexit_t) P((void)); /* exit handlers */
X
X/* Function prototypes */
X
Xint _bfail P((void)); /* fail */
Xint _bsucceed P((void)); /* succeed */
X
Xint _bwrupdate P((int, FILE *)); /* write update */
Xint _bwronly P((int, FILE *)); /* write only */
Xint _bwr P((int, FILE *)); /* write */
Xint _bwrflush P((FILE *)); /* write flush */
X
Xint _brdupdate P((FILE *)); /* read update */
Xint _brdonly P((FILE *)); /* read only */
Xint _brd P((FILE *)); /* read */
Xint _brdflush P((FILE *)); /* read flush */
X
Xint _bstrwr P((int, FILE *)); /* write string */
Xint _bstrrd P((FILE *)); /* read string */
X
Xint _iowrite P((int, char *, int)); /* repeated write */
Xint _ioread P((int, char *, int)); /* repeated read */
Xvoid _ioflush P((void)); /* flush output */
Xint _allocbuf P((FILE *)); /* internal buffering */
Xint _fopen P((const char *,
X const char *,
X int, short *)); /* fopen assist */
XFILE *_file P((FILE *, int, short));/* initialise FILE */
X
X/* Extras not in ANSI but probably could be */
X
Xint _vscanf P((const char *, VA_LIST));
Xint _vfscanf P((FILE *, const char *, VA_LIST));
Xint _vsscanf P((const char *, const char *, VA_LIST));
X
X/* Library globals */
X
Xextern int errno; /* system error number */
Xextern int sys_nerr; /* size of error table */
Xextern char *sys_errlist[]; /* error descriptions */
X
X/* Stdio internal variables */
X
Xextern atexit_t *_exit_hp; /* exit handler list pointer */
Xextern FILE *_iop; /* stream list */
X
X/* Library calls */
X
Xvoid *malloc P((size_t)); /* memory allocator */
Xvoid free P((void *)); /* free memory */
X
X/* System calls */
X
X#ifndef OPEN3
Xint open P((const char *, int)); /* two argument open */
X# define open _open3 /* fake three argument open */
X# undef O_CREAT
X# undef O_APPEND
X# undef O_TRUNC
X# define O_CREAT (~(O_RDONLY|O_WRONLY|O_RDWR) ^ \
X (~(O_RDONLY|O_WRONLY|O_RDWR) & \
X (~(O_RDONLY|O_WRONLY|O_RDWR) - 1)))
X# define O_APPEND (~(O_CREAT|O_RDONLY|O_WRONLY|O_RDWR) ^ \
X (~(O_CREAT|O_RDONLY|O_WRONLY|O_RDWR) & \
X (~(O_CREAT|O_RDONLY|O_WRONLY|O_RDWR) - 1)))
X# define O_TRUNC (~(O_APPEND|O_CREAT|O_RDONLY|O_WRONLY|O_RDWR) ^ \
X (~(O_APPEND|O_CREAT|O_RDONLY|O_WRONLY|O_RDWR) & \
X (~(O_APPEND|O_CREAT|O_RDONLY|O_WRONLY|O_RDWR) - 1)))
X#endif
X
Xvoid _exit P((int)); /* exit to system */
Xint isatty P((int)); /* channel is tty */
Xint close P((int)); /* close channel */
Xint creat P((const char *, mode_t)); /* create a file */
Xint open P((const char *, int, ...)); /* open a file */
Xoff_t lseek P((int, off_t, int)); /* seek within file */
Xint read P((int, char *, unsigned int)); /* read channel */
Xint write P((int, char *, unsigned int)); /* write channel */
Xint unlink P((const char *)); /* unlink a file */
Xint link P((const char *, const char *)); /* link a file */
Xint stat P((const char *, struct stat *)); /* file status */
Xmode_t umask P((mode_t)); /* permission mask */
Xint chmod P((const char *, mode_t)); /* change permission */
Xpid_t getpid P((void)); /* get process id */
Xtime_t time P((time_t *)); /* get time */
Xuid_t geteuid P((void)); /* get effective user id */
Xuid_t getuid P((void)); /* get user id */
Xstruct passwd * getpwuid P((uid_t)); /* get passwd from uid */
X
X/* Size of tty buffers */
X
X#define TTYBUFSIZ 81
X
X/* Flag manipulation macros */
X
X#define TESTFLAG(f,x) (((f)->_flag & (x)) != 0)
X#define SETFLAG(f,x) ((f)->_flag |= (x))
X#define CLEARFLAG(f,x) ((f)->_flag &= ~(x))
X#define GETFLAG(f,x) ((f)->_flag & (x))
X#define TOGGLEFLAG(f,x) ((f)->_flag ^= (x))
X#define SAVEFLAG(f,p) ((p) = (int) ((f)->_flag))
X#define RESTOREFLAG(f,p) ((f)->_flag = (short) (p))
X
X/* Add _ioflush to exit code
X *
X * Check is _ioflush needs to be added to the exit code. If so then
X * add it. This macro is run time system dependent.
X */
X#ifdef MSDOS
X extern int _wrapstdio; /* stdio wrap required */
X# define SETIOFLUSH() { if (_wrapstdio != 0) _wrapstdio = atexit(_ioflush); }
X#endif
X
X#ifndef SETIOFLUSH
X# define SETIOFLUSH()
X#endif
X
X/* Getc with full buffering
X *
X * This version of getc assumes that there is an input buffer
X * that is not empty and simply grabs the character from there.
X */
X#define FGETC(p) ( (int) ((unsigned char) *(p)->_rptr++) )
X
X/* Putc for non buffered streams
X *
X * This version of putc is explicitly for unbuffered streams. A
X * call is made directly to the buffer flushing code.
X */
X#define NPUTC(x,p) ( (*(p)->_flsbuf)((x),(p)) )
X
X/* Putc with full buffering
X *
X * This version of putc() assumes that there is an output buffer
X * that is not full and simply dumps the character in there.
X */
X#define FPUTC(x, p) ( ((int) ((unsigned char) (*(p)->_wptr++ = (x)))) )
X
X/* Flush a stream
X *
X * Call the flush routine to clear the output buffer.
X */
X#define FFLUSH(f) ( (*(f)->_flush)(f) )
X
X/* Set _flsbuf
X *
X * Set the _flsbuf function pointer.
X */
X#define SETFLSBUF(f,p) ( (f)->_flsbuf = (p) )
X
X/* Set _filbuf
X *
X * Set the _filbuf function pointer.
X */
X#define SETFILBUF(f,p) ( (f)->_filbuf = (p) )
X
X/* Set _flush
X *
X * Set the _flush function pointer.
X */
X#define SETFLUSH(f,p) ( (f)->_flush = (p) )
X
X/* Initialise an output buffer
X *
X * This macro uses _base and _bufsiz to initialise _wptr, _scan and
X * _wend. _wptr and _scan will be set to point at the base of the
X * buffer. _wend will be set to point at one past the end of the
X * buffer if the stream is buffered otherwise it will point at
X * the base of the buffer. Line buffered streams are considered to
X * be fully buffered. This macro must not alter _base unless the
X * code in fflush() is changed.
X */
X#define INITWRITEBUFFER(f) ( \
X (f)->_wend = ((f)->_scan = (f)->_wptr = (f)->_base) + \
X (TESTFLAG(f, _IONBF | _IOLBF) ? 0 : (f)->_bufsiz) \
X)
X
X/* Initialise an input buffer
X *
X * This macro empties an input buffer. It uses _base to initialise
X * _rptr and _scan, and sets _rend to point to the high water mark
X * of the buffer.
X */
X#define INITREADBUFFER(f, v) ( \
X (f)->_rend = ((f)->_scan = (f)->_rptr = (f)->_base) + (v) \
X)
X
X/* Flush the next write
X *
X * This macro initialises the buffer by setting _wend and
X * _wptr to nil. This will force the next putc to call
X * _flsbuf.
X */
X#define CHECKNEXTWRITE(f) ( (f)->_wend = (f)->_wptr = 0 )
X
X/* Check a write
X *
X * If _wptr is zero, the write buffer is checked.
X */
X#define CHECKWRITE(f) ( \
X (f)->_wptr == 0 ? ((f)->_wend = &(f)->_buf, (*(f)->_flsbuf)(0, f)) : 0 \
X)
X
X/* Flush the next read
X *
X * This macro initialises the buffer by setting _rend and
X * _rptr to nil. This will force the next next getc to call
X * _filbuf.
X */
X#define CHECKNEXTREAD(f) ( (f)->_rend = (f)->_rptr = 0 )
X
X/* Check a read
X *
X * If _rptr is zero, the read buffer is checked.
X */
X#define CHECKREAD(f) ( \
X (f)->_rptr == 0 ? ((f)->_rend = &(f)->_buf, (*(f)->_filbuf)(f)) : 0 \
X)
X
X/* Test for buffer flush
X *
X * Return true if it is necessary to flush or fill the buffer.
X */
X#define CHECKFLUSH(f) ( \
X (f)->_ptr == 0 \
X)
X
X/* Buffer size
X *
X * Return the size of the buffer. This will return rubbish
X * for unbuffered streams. Line and fully buffered streams will
X * have the true buffer size returned.
X */
X#define BUFFERSIZE(f) ( (f)->_bufsiz )
X
X/* Bytes left in input buffer
X *
X * This macro returns the number of bytes left in an input buffer.
X */
X#define BYTESINREADBUFFER(f) ( (f)->_rend - (f)->_rptr )
X
X/* Bytes written in output buffer
X *
X * This macro returns the number of bytes left in an output buffer.
X */
X#define BYTESINWRITEBUFFER(f) ( (f)->_wptr - (f)->_base )
X
X/* Unused bytes in output buffer
X *
X * This macro returns the number of unused bytes in an output buffer.
X * Unbuffered streams will return rubbish. Line and fully buffered streams
X * will have the amount of space remaining returned.
X */
X#define UNUSEDINWRITEBUFFER(f) ( (f)->_bufsiz - BYTESINWRITEBUFFER(f) )
X
X/* Get pointer into write buffer
X *
X * This macro gets the pointer into the write buffer.
X */
X#define GETWRITEPTR(f) ( (f)->_wptr )
X
X/* Set pointer into write buffer
X *
X * This macro sets the pointer into the write buffer.
X */
X#define SETWRITEPTR(f,p) ( (f)->_wptr = (p) )
X
X/* Get pointer into read buffer
X *
X * This macro gets the pointer into the read buffer.
X */
X#define GETREADPTR(f) ( (f)->_rptr )
X
X/* Set pointer into read buffer
X *
X * This macro sets the pointer into the read buffer.
X */
X#define SETREADPTR(f,p) ( (f)->_rptr = (p) )
X
X/* Check if buffering has been set
X *
X * Return true if buffering has already been set. A stream
X * set for unbuffered output is considered to have had
X * its buffering set.
X */
X#define HASBUFFER(f) ( (f)->_base != 0 )
X
X/* Set the scan point
X *
X * The _scan field is used for line buffered streams. The _scan
X * field remembers the point at which the next write starts. When
X * the write is complete a scan can be made of the buffer from
X * that point to determine whether the buffer should be flushed.
X */
X#define SETSCAN(f) ( (f)->_scan = (f)->_wptr )
X
X/* Conditionally flush line buffered stream
X *
X * Scan the buffer from the last scan point and if a \n is found
X * flush the stream.
X */
X#define FLUSHSCAN(f) ( \
X MEMCHR((f)->_scan, '\n', (f)->_wptr - (f)->_scan) && FFLUSH(f) ? EOF : 0 \
X)
X
X/* Set _wend for line buffering
X *
X * Set _wend for line buffering. This means that _wend is set to
X * point at _base.
X */
X#define SETWRITELINEBUFFERING(f) ( (f)->_wend = (f)->_base )
X
X/* Set _wend for full buffering
X *
X * Set _wend to _base + _bufsiz so that the entire buffer can be
X * used.
X */
X#define SETWRITEFULLBUFFERING(f) ( (f)->_wend = (f)->_base + (f)->_bufsiz )
X
X/* Unroll a loop
X *
X * Assume that the loop must execute at least once. The first argument
X * is the name of the loop control variable. The second argument is the
X * name of the loop control variable. The third argument is the expression
X * to be placed in the loop body. The control variable should be unsigned,
X * otherwise the right shift might propagate the sign bit. The caller must
X * also provide the name of a unique label.
X */
X# define UNROLL_DO(l,v,x) { \
X char t = (v); \
X (v) = ((v)+1) >> 1; \
X if (t & 1) goto l; \
X do { x; l: x; } while (--(v)); \
X}
END_OF_FILE
if test 12113 -ne `wc -c <'stdiolib.h'`; then
echo shar: \"'stdiolib.h'\" unpacked with wrong size!
fi
# end of 'stdiolib.h'
fi
if test -f 'vfprintf.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'vfprintf.c'\"
else
echo shar: Extracting \"'vfprintf.c'\" \(8218 characters\)
sed "s/^X//" >'vfprintf.c' <<'END_OF_FILE'
X/* v f p r i n t f
X *
X * (C) Copyright C E Chew
X *
X * Feel free to copy, use and distribute this software provided:
X *
X * 1. you do not pretend that you wrote it
X * 2. you leave this copyright notice intact.
X *
X * This routine provides the same functionality as fprintf
X * except that it uses varargs.h.
X *
X * In this implementation, this routine is basis for all the
X * formatted output routines. printf, fprintf, and sprintf
X * are all defined in terms of vfprintf.
X *
X * The user is referred to the manual page for a full
X * description of the formats available.
X *
X * The function returns the number of bytes generated, or
X * EOF in the case of an error.
X *
X * Patchlevel 2.0
X *
X * Edit History:
X */
X
X#include "stdiolib.h"
X
X/*LINTLIBRARY*/
X
X#define MINBITS 3 /* least bits required --- octal */
X#define MAXPREFIX 3 /* overhead for prefix */
X
X#define MAXDIGITS ((sizeof(long)*CHAR_BIT+MINBITS-1)/MINBITS*MINBITS)
X#define VBUFFERSIZE MAXDIGITS+MAXPREFIX+1
X
X#define OPTIONAL(p,c,f,v) if(*(p)==(c)){(f)=(v);(p)++;}
X
X/* Get an integer argument
X *
X * Scan the string beginning at the point indicated for an
X * integer argument. If a '*' is found, the argument pointer
X * is used to retrieve a remote integer.
X */
X
Xstatic int integer(T(char **p, p), T(VA_LIST *ap, ap))
X
XD(char **p) /* pointer to string pointer */
XD(VA_LIST *ap) /* pointer to argument list */
X
X{
X char *cp; /* character pointer */
X int v; /* return value */
X
X cp = *p;
X
X if (*cp == '*') {
X v = VA_ARG(*ap, int);
X cp++;
X }
X else {
X for (v = 0; *cp >= '0' && *cp <= '9'; ) {
X v *= 10;
X v += (*cp++ - '0');
X }
X }
X *p = cp;
X return v;
X}
X
Xint vfprintf(T(FILE *fp, fp), T(const char *fmt, fmt), T(VA_LIST args, args))
X
XD(FILE *fp) /* stream for output */
XD(char *fmt) /* format for output */
XD(VA_LIST args) /* argument list */
X
X{
X char buf[VBUFFERSIZE]; /* workspace */
X int bytes; /* bytes output */
X
X char *p, *q; /* pointers into workspace */
X
X _stdiobuf_t *bp, *bq; /* fast copy pointers */
X
X char leftjustify; /* left justify */
X char showsign; /* display a sign */
X char blankprefix; /* prefix with blank */
X char alternate; /* alternate format */
X
X char zerofill; /* fill with zeros */
X char flush; /* flush line buffered stream */
X int width; /* field width */
X
X int precision; /* precision */
X
X char longflag; /* number is long */
X
X char capitals; /* capitals */
X
X char prefix; /* number has prefix -/ /+ */
X
X int radixoffset; /* offset for higher radices */
X unsigned int radix; /* radix for conversion */
X char sign; /* conversion is signed */
X char negative; /* number is negative */
X long vl; /* conversion temporary */
X int vi; /* conversion temporary */
X unsigned short vs; /* conversion temporary */
X char shortint; /* short or long */
X int c; /* conversion temporary */
X int length; /* raw length of output */
X
X int saveflags; /* save flags */
X
X if (CHECKWRITE(fp))
X return 0;
X
X SAVEFLAG(fp, saveflags);
X if (TESTFLAG(fp, _IOLBF)) {
X CLEARFLAG(fp, _IOLBF);
X SETWRITEFULLBUFFERING(fp);
X }
X
X for (flush = bytes = 0; ; ) {
X
X/* Scan for format dumping directly into output buffer */
X for (bp = (_stdiobuf_t *) fmt; ; ) {
X if (TESTFLAG(fp, _IONBF) || (length = UNUSEDINWRITEBUFFER(fp)) == 0)
X c = *bp++;
X else {
X bq = GETWRITEPTR(fp);
X do
X ;
X while ((c = *bp++) != 0 && c != '%' && c != '\n' &&
X (*bq++ = c, --length));
X SETWRITEPTR(fp, bq);
X }
X if (c == 0 || c == '%') break;
X if (putc(c, fp) == '\n') flush = 1;
X }
X
X/* Format or end of format found */
X bytes += (bp - (_stdiobuf_t *) fmt) - 1;
X fmt = bp;
X if (c == 0) break;
X
X/* Initialise conversion variables */
X p = q = &buf[sizeof(buf)-1];
X
X leftjustify = 0;
X showsign = 0;
X blankprefix = 0;
X alternate = 0;
X
X zerofill = ' ';
X width = 0;
X
X precision = -1;
X
X longflag = 0;
X capitals = 0;
X radixoffset = 'a' - '9' - 1;
X
X prefix = 0;
X
X/* Check for optional flags */
X for ( ; ; ) {
X switch (*fmt) {
X case '-': leftjustify = 1; break;
X case '+': showsign = 1; break;
X case ' ': blankprefix = 1; break;
X case '#': alternate = 1; break;
X default: goto DoneFlags;
X }
X fmt++;
X }
XDoneFlags:
X
X/* Check for field width */
X OPTIONAL(fmt, '0', zerofill, '0');
X width = integer((char **) &fmt, &args);
X
X/* Check for precision */
X if (*fmt == '.') {
X fmt++;
X precision = integer((char **) &fmt, &args);
X }
X
X/* Check for longs */
X OPTIONAL(fmt, 'l', longflag, 1);
X
X/* Switch through all the format options */
X switch (*fmt) {
X
X case 'X':
X capitals++;
X radixoffset += 'A' - 'a';
X
X case 'x':
X radix = 16;
X sign = 0;
X goto oxud;
X
X case 'u':
X radix = 10;
X sign = 0;
X goto oxud;
X
X case 'o':
X radix = 8;
X sign = 0;
X goto oxud;
X
X case 'd':
X radix = 10;
X sign = 1;
X
Xoxud:
X vs = shortint = 0;
X if (longflag) {
X if (sign) vl = VA_ARG(args, long);
X else vl = VA_ARG(args, unsigned long);
X if ((negative = sign && vl < 0) != 0)
X vl = -vl;
X if ((unsigned long) vl <= USHRT_MAX) {
X vs = (unsigned short) vl;
X shortint = 1;
X }
X }
X else {
X if (sign) vi = VA_ARG(args, int);
X else vi = VA_ARG(args, unsigned);
X if ((negative = sign && vi < 0) != 0)
X vi = -vi;
X if ((unsigned int) vi > USHRT_MAX)
X vl = (unsigned int) vi;
X else {
X vs = (unsigned short) vi;
X shortint = 1;
X }
X }
X if (! shortint) {
X do {
X c = (int) ((unsigned long) (vl) % radix) + '0';
X vl = (unsigned long) (vl) / radix;
X if (c > '9')
X c += radixoffset;
X *--q = c;
X } while (vl > USHRT_MAX);
X if ((vs = (unsigned short) vl) == 0) goto ConversionDone;
X }
X do {
X c = (int) ((unsigned short) (vs) % radix) + '0';
X vs = (unsigned short) (vs) / radix;
X if (c > '9')
X c += radixoffset;
X *--q = c;
X } while (vs != 0);
X
XConversionDone:
X if (precision > width) {
X width = precision;
X zerofill = '0';
X }
X if (negative) {
X prefix++;
X *--q = '-';
X }
X else if (sign) {
X if (showsign) {
X prefix++;
X *--q = '+';
X }
X else if (blankprefix) {
X prefix++;
X *--q = ' ';
X }
X }
X if (alternate) {
X if (radix == 8) {
X prefix++;
X *--q = '0';
X }
X else if (radix == 16) {
X prefix += 2;
X *--q = capitals ? 'X' : 'x';
X *--q = '0';
X }
X }
X break;
X
X/* Single character format */
X case 'c':
X if ((*--q = VA_ARG(args, int)) == '\n')
X flush = 1;
X break;
X
X/* String format */
X case 's':
X if ((q = VA_ARG(args, char *)) == NULL)
X q = "(null)";
X p = q;
X if (precision < 0) {
X for (; (c = *p) != 0; p++)
X if (c == '\n')
X flush = 1;
X }
X else if (precision > 0) {
X for (; (c = *p) != 0; ) {
X if (c == '\n')
X flush = 1;
X if (p++, --precision)
X break;
X }
X }
X break;
X
X/* Default just print it */
X default:
X if ((*--q = *fmt) == '\n')
X flush = 1;
X break;
X }
X
X/* Scan past conversion character */
X fmt++;
X
X/* Length of string to be printed */
X length = p - q;
X
X/* Subtract to find padding required */
X if ((width -= length) < 0)
X width = 0;
X
X/* Signal left justification */
X if (leftjustify == 0)
X width = -width;
X
X/* Check for left justification */
X if (width < 0) {
X
X/* Check for negative and zero fill */
X if (zerofill == '0') {
X if (prefix != 0) {
X bytes += prefix;
X length -= prefix;
X
X/* Don't unroll this loop since the number of iterations is small */
X do
X (void) putc(*q++, fp);
X while (--prefix);
X }
X }
X
X/* Now output the rest of the padding */
X width = -width;
X bytes += width;
X do
X (void) putc(zerofill, fp);
X while (--width);
X }
X
X/* Output the string proper */
X if (length > 0) {
X bytes += length;
X do
X putc(*q++, fp);
X while (--length);
X }
X
X/* Do right padding */
X if (width != 0) {
X bytes += width;
X do
X putc(' ', fp);
X while (--width);
X }
X }
X
X/* Flush line buffered streams */
X RESTOREFLAG(fp, saveflags);
X if (TESTFLAG(fp, _IOLBF)) {
X SETWRITELINEBUFFERING(fp);
X if (flush)
X (void) FFLUSH(fp);
X }
X
X return ferror(fp) ? EOF : bytes;
X}
END_OF_FILE
if test 8218 -ne `wc -c <'vfprintf.c'`; then
echo shar: \"'vfprintf.c'\" unpacked with wrong size!
fi
# end of 'vfprintf.c'
fi
echo shar: End of archive 5 \(of 6\).
cp /dev/null ark5isdone
MISSING=""
for I in 1 2 3 4 5 6 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 6 archives.
rm -f ark[1-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0
--
Earl Chew, Dept of Computer Science, Monash University, Australia 3168
ARPA: cechew%bruce.cs.monash.oz.au@uunet.uu.net ACS : cechew@bruce.oz