Path: utzoo!attcan!uunet!cs.utexas.edu!rutgers!njin!princeton!notecnirp!nfs
From: nfs@notecnirp.Princeton.EDU (Norbert Schlenker)
Newsgroups: comp.os.minix
Subject: Another new stdio (part 3 of 4)
Summary: Stdio routines
Message-ID: <19737@princeton.Princeton.EDU>
Date: 30 Sep 89 16:22:19 GMT
Sender: news@princeton.Princeton.EDU
Reply-To: nfs@notecnirp.UUCP (Norbert Schlenker)
Organization: Dept. of Computer Science, Princeton University
Lines: 2762

echo x - _bufproc.c
sed '/^X/s///' > _bufproc.c << '/'
X/* --- _bufproc.c --- */
X/* Manages buffers for stdio */
X
X#include 
X#include 
X#include "stdiolib.h"
X
X/* _bufalloc - allocate a new buffer				*/
X/* Input:  A valid stream with _io_bufsiz appropriately set	*/
X/* Output: Maybe a buffer, maybe not				*/
X
Xvoid _bufalloc(stream)
Xregister FILE *stream;
X{
X  if (stream->_io_bufsiz > 0 &&
X     (stream->_io_buf = (unsigned char *) malloc(stream->_io_bufsiz)) != NULL) {
X	_io_setflag(stream, _IO_MYBUF);
X	stream->_io._io_ptr = stream->_io_buf;
X  } else {
X	stream->_io_bufsiz = 0;
X	stream->_io._io_char = EOF;
X  }
X}
X
X/* _buffree - free an existing buffer if allocated by _bufalloc	*/
X/* Input:  A valid stream					*/
X/* Output: A valid unbuffered stream				*/
X
Xvoid _buffree(stream)
Xregister FILE *stream;
X{
X  if (stream->_io_buf != NULL && _io_testflag(stream, _IO_MYBUF)) {
X	free(stream->_io_buf);
X	stream->_io_buf = NULL;
X	stream->_io_count = stream->_io_bufsiz = 0;
X	stream->_io._io_char = EOF;
X	_io_clearflag(stream, (_IO_LBUF | _IO_MYBUF));
X  }
X}
/
echo x - _cleanup.c
sed '/^X/s///' > _cleanup.c << '/'
X/* --- _cleanup.c --- */
X/* Flushes all buffers at program exit */
X/* Notes:  exit() knows about this through __cleanup	*/
X
X#include 
X#include "stdiolib.h"
X
Xvoid _cleanup()
X{
X  fflush(NULL);
X}
/
echo x - _doprnt.c
sed '/^X/s///' > _doprnt.c << '/'
X/* --- _doprnt.c --- */
X/* Formatted printing workhorse */
X/* Notes:  By default, this source compiles into _doprnt()		*/
X/*	   Floating point support is nominal				*/
X/*	   Cheap and nasty imitations of character type macros		*/
X/*	   Defining the symbol _KERNEL_ results in a routine named	*/
X/*	   printk() with the following differences:			*/
X/*		No floating point support				*/
X/*		An abbreviated version of the macro PUTC		*/
X
X#include 
X
X#ifndef _KERNEL_
X#include 
X#include 
X#include 
X#include "stdiolib.h"
X#else
Xextern int putc();
X#endif
X
X/* --- Constants --- */
X#define MAX_CONVERSION	512	/* largest possible conversion */
X
X#define LEFT_JUSTIFY	0x0001	/* conversion flags */
X#define ALWAYS_SIGN	0x0002
X#define PREFIX_SPACE	0x0004
X#define ALTERNATE_FORM	0x0008
X#define ZERO_FILL	0x0010
X#define SHORT		0x0100	/* length modifiers */
X#define LONG		0x0200
X#define LONGDOUBLE	0x0400
X#define SIGNED		0x1000	/* signed integer argument */
X#define UPPER_CASE	0x4000	/* %X, %E, %G */
X
X#define UNSPECIFIED	(-1)	/* for precision */
X
X#define POINTER_BASE	16	/* constant for %p conversion */
X
X/* --- Global state --- */
Xstatic struct {
X#ifndef _KERNEL_
X  FILE *stream;			/* destination file */
X#endif
X  const char *fp;		/* format pointer */
X  va_list ap;			/* argument pointer */
X  int chars_written;		/* number of characters written to the stream */
X} gs;
X
X/* --- Macros --- */
X#define TESTFLAG(x)	(flags & (x))
X#define CLEARFLAG(x)	(flags &= ~(x))
X#define SETFLAG(x)	(flags |= (x))
X#define isdigit(c)	((c) >= '0' && (c) <= '9')
X#define _tolower(c)	((c) - 'A' + 'a')
X
X#ifdef _KERNEL_
X#define EOF		(-1)
X#define PUTC(c, f)	putc(c)
X#else
X/* --- Local unsafe fast version of putc: ignores line buffering;	--- */
X/* --- has no rvalue; returns EOF from including routine on failure	--- */
X#define PUTC(c, f) {			\
X  if (--(f)->_io_count >= 0)		\
X	*(f)->_io._io_ptr++ = c;	\
X  else					\
X	if (_flsbuf(c, f) == EOF)	\
X		return EOF;		\
X  }
X#endif
X
X/* --- Format processors --- */
Xstatic int _parse_format();	/* parse formats */
Xstatic int _iconvert();		/* convert integers */
X#ifndef _KERNEL_
Xstatic int _fconvert();		/* convert floating point */
X#endif
Xstatic int _sconvert();		/* convert strings */
Xstatic int _outcnvrt();		/* writes converted output to the stream */
X
X#ifdef _KERNEL_
Xint printk(format, arg)
X#else
Xint _doprnt(stream, format, arg)
XFILE *stream;
X#endif
Xregister const char *format;
Xva_list arg;
X{
X#ifndef _KERNEL_
X  gs.stream = stream;
X#endif
X  gs.fp = format;
X  gs.ap = arg;
X  gs.chars_written = 0;
X
X  while (*format) {
X	if (*format != '%') {
X		PUTC(*format, stream);
X		format++;
X		gs.chars_written++;
X	} else {
X		gs.fp = ++format;
X		if (_parse_format() == EOF)
X			return EOF;
X		format = gs.fp;
X	}
X  }
X
X#ifndef _KERNEL_
X  if (_io_testflag(stream, _IO_LBUF))
X	_flspbuf(stream);
X#endif
X  return gs.chars_written;
X}
X
Xstatic int _parse_format()
X{
X  register const char *fp = gs.fp;
X  register int c;
X  int width;
X  int precision;
X  int flags;
X  union {
X    unsigned long l;
X    double d;
X    char c;
X    char *s;
X  } arg;
X
X  if (*fp == '%') {
X	PUTC(*fp, gs.stream);
X	gs.fp++;
X	gs.chars_written++;
X	return 0;
X  }
X
X  precision = UNSPECIFIED;
X  flags = 0;
X
X/* --- Extract the flags --- */
X  c = *fp;
X  while (1) {
X	if (c == '-')
X		SETFLAG(LEFT_JUSTIFY);
X	else
X	if (c == '+')
X		SETFLAG(ALWAYS_SIGN);
X	else
X	if (c == ' ')
X		SETFLAG(PREFIX_SPACE);
X	else
X	if (c == '#')
X		SETFLAG(ALTERNATE_FORM);
X	else
X	if (c == '0')
X		SETFLAG(ZERO_FILL);
X	else
X		break;
X	c = *++fp;
X  }
X
X/* --- Extract the width --- */
X  if (c == '*') {
X	width = va_arg(gs.ap, int);
X	++fp;
X  }
X  else {
X	width = 0;
X	while (isdigit(*fp))
X		width = 10 * width + *fp++ - '0';
X  }
X  if (width < 0) {
X	SETFLAG(LEFT_JUSTIFY);
X	width = 0 - width;
X  }
X
X/* --- Extract the precision --- */
X  if (*fp == '.') {
X	if (*++fp == '*') {
X		precision = va_arg(gs.ap, int);
X		++fp;
X	}
X	else {			/* PENDING - this should handle +/- signs */
X		precision = 0;
X		while (isdigit(*fp))
X			precision = 10 * precision + *fp++ - '0';
X	}
X	if (precision < 0)
X		precision = UNSPECIFIED;
X  }
X
X/* --- Extract the length modifiers --- */
X  if ((c = *fp) == 'h') {
X	SETFLAG(SHORT);
X	++fp;
X  } else
X  if (c == 'l') {
X	SETFLAG(LONG);
X	++fp;
X  } else
X  if (c == 'L') {
X	SETFLAG(LONGDOUBLE);
X	++fp;
X  }
X
X/* --- Fetch argument type and save global format pointer --- */
X  c = *fp;
X  gs.fp = ++fp;
X  if (c == 'D' || c == 'O' || c == 'U') {	/* not ANSI */
X	SETFLAG(LONG);
X	c = _tolower(c);
X  }
X
X/* --- Fetch the argument --- */
X  switch (c) {
X  case 'd':
X  case 'i':
X	if (TESTFLAG(SHORT))
X		arg.l = (long) va_arg(gs.ap, short);
X	else
X	if (TESTFLAG(LONG))
X		arg.l = va_arg(gs.ap, long);
X	else
X		arg.l = (long) va_arg(gs.ap, int);
X	break;
X  case 'o':
X  case 'u':
X  case 'X':
X  case 'x':
X	if (TESTFLAG(SHORT))
X		arg.l = (unsigned long) va_arg(gs.ap, unsigned short);
X	else
X	if (TESTFLAG(LONG))
X		arg.l = va_arg(gs.ap, unsigned long);
X	else
X		arg.l = (unsigned long) va_arg(gs.ap, unsigned int);
X	break;
X#ifndef _KERNEL_
X	/* PENDING - This is probably wrong (due to argument widening). */
X  case 'f':
X  case 'E':
X  case 'e':
X  case 'G':
X  case 'g':
X	if (TESTFLAG(LONG))
X		arg.d = va_arg(gs.ap, double);
X#ifdef __STDC__
X	else
X	if (TESTFLAG(LONGDOUBLE))
X		arg.d = (double) va_arg(gs.ap, long double);
X#endif
X	else
X		arg.d = va_arg(gs.ap, float);
X	break;
X#endif
X  case 'c':
X	arg.c = va_arg(gs.ap, int);
X	break;
X  case 's':
X	arg.s = va_arg(gs.ap, char *);
X	break;
X  case 'p':
X	arg.l = (unsigned long) va_arg(gs.ap, void *);
X	break;
X  default:
X	break;
X  }
X
X/* --- Resolve mutually exclusive flags --- */
X  if (TESTFLAG(ALWAYS_SIGN))
X	CLEARFLAG(PREFIX_SPACE);
X  if (TESTFLAG(LEFT_JUSTIFY))
X	CLEARFLAG(ZERO_FILL);
X
X/* --- Produce some output (finally!) --- */
X  switch (c) {
X  case 'd':
X  case 'i':
X	SETFLAG(SIGNED);
X	CLEARFLAG(ALTERNATE_FORM);
X	return _iconvert(arg.l, 10, width, precision, flags);
X  case 'o':
X	return _iconvert(arg.l, 8, width, precision, flags);
X  case 'u':
X	CLEARFLAG(ALTERNATE_FORM);
X	return _iconvert(arg.l, 10, width, precision, flags);
X  case 'X':
X	SETFLAG(UPPER_CASE);
X  case 'x':
X	return _iconvert(arg.l, 16, width, precision, flags);
X#ifndef _KERNEL_
X  case 'f':
X	return _fconvert(arg.d, width, precision, flags);
X  case 'E':
X	SETFLAG(UPPER_CASE);
X  case 'e':
X	return _fconvert(arg.d, width, precision, flags);
X  case 'G':
X	SETFLAG(UPPER_CASE);
X  case 'g':
X	return _fconvert(arg.d, width, precision, flags);
X#endif
X  case 'c':
X	return _outcnvrt(&(arg.c), 1, width, flags);
X  case 's':
X	return _sconvert(arg.s, width, precision, flags);
X  case 'p':
X	SETFLAG(ALTERNATE_FORM);
X	return _iconvert(arg.l, POINTER_BASE, width, precision, flags);
X  case 'n':
X	*va_arg(gs.ap, int *) = gs.chars_written;
X	return 0;
X  default:
X	return EOF;
X  }
X}
X
Xstatic int _iconvert(number, base, width, precision, flags)
Xunsigned long number;
Xint base;
Xint width;
Xint precision;
Xint flags;
X{
X  char buf[MAX_CONVERSION];
X  register char *p = &buf[MAX_CONVERSION - 1];
X  register int digit;
X  int negative = 0;
X
X/* --- Set default precision (and annul zero fill if precision set) --- */
X  if (precision == UNSPECIFIED)
X	precision = 1;
X  else
X	CLEARFLAG(ZERO_FILL);
X
X/* --- Get the sign right --- */
X  if (TESTFLAG(SIGNED))
X	if ((long) number < 0L) {
X		negative = 1;
X		number = (unsigned long) (0L - (long) number);
X	}
X
X/* --- Build the number back to front (at the back of the buffer) --- */
X  while (--precision >= 0 || number != 0) {
X	digit = number % base;
X	if (digit < 10)
X		digit += '0';
X	else
X		digit += (TESTFLAG(UPPER_CASE) ? 'A' : 'a') - 10;
X	*p-- = digit;
X	number /= base;
X  }
X
X/* --- Ensure enough precision --- */
X  while (--precision >= 0)
X	*p-- = '0';
X
X/* --- Zero fill if needed (but leave room for prefix and sign) --- */
X  if (TESTFLAG(ZERO_FILL)) {
X	precision = width - (&buf[MAX_CONVERSION - 1] - p);
X	if (TESTFLAG(ALTERNATE_FORM))
X		if (base == 8 && *(p+1) != '0')
X			precision--;
X		else
X		if (base == 16)
X			precision -= 2;
X	if (TESTFLAG(SIGNED))
X		if (negative || TESTFLAG(ALWAYS_SIGN | PREFIX_SPACE))
X			precision--;
X	while (--precision >= 0)
X		*p-- = '0';
X  }
X
X/* --- Generate alternate forms for %o and %x --- */
X  if (TESTFLAG(ALTERNATE_FORM)) {
X	if (base == 8 && *(p+1) != '0')
X		*p-- = '0';
X	else
X	if (base == 16) {
X		*p-- = TESTFLAG(UPPER_CASE) ? 'X' : 'x';
X		*p-- = '0';
X	}
X  }
X
X/* --- Generate signs --- */
X  if (TESTFLAG(SIGNED)) {
X	if (negative)
X		*p-- = '-';
X	else {
X		if (TESTFLAG(ALWAYS_SIGN))
X			*p-- = '+';
X		else
X		if (TESTFLAG(PREFIX_SPACE))
X			*p-- = ' ';
X	}
X  }
X
X  p++;
X  return _outcnvrt(p, &buf[MAX_CONVERSION] - p, width, flags);
X}
X
X#ifndef _KERNEL_
X
Xstatic int _fconvert(arg, width, precision, flags)	/* PENDING */
Xdouble arg;
Xint width;
Xint precision;
Xint flags;
X{
X/* --- Set default precision --- */
X  if (precision == UNSPECIFIED)
X	precision = 6;
X
X/* --- What do you expect? --- */
X  PUTC(' ', gs.stream);
X  PUTC('*', gs.stream);
X  PUTC('F', gs.stream);
X  PUTC('P', gs.stream);
X  PUTC('*', gs.stream);
X  PUTC(' ', gs.stream);
X  gs.chars_written += 6;
X  return 0;
X}
X
X#endif
X
Xstatic int _sconvert(s, width, precision, flags)
Xchar *s;
Xint width;
Xregister int precision;
Xint flags;
X{
X  register char *p = s;
X
X  if (precision == UNSPECIFIED)
X	precision = MAX_CONVERSION;
X  while (--precision >= 0 && *p)
X	p++;
X  return _outcnvrt(s, p - s, width, flags);
X}
X
Xstatic int _outcnvrt(p, n, width, flags)
Xregister char *p;		/* start of converted field */
Xint n;				/* number of characters in field */
Xint width;
Xint flags;
X{
X#ifndef _KERNEL_
X  register FILE *stream = gs.stream;
X#endif
X  int i;
X
X  if (!TESTFLAG(LEFT_JUSTIFY))			/* pad to right justify */
X	for (i = width - n ; --i >= 0; )
X		PUTC(' ', stream);
X
X  for (i = n; --i >= 0; p++)			/* copy conversion result */
X	PUTC(*p, stream);
X
X  if (TESTFLAG(LEFT_JUSTIFY))			/* pad to left justify */
X	for (i = width - n ; --i >= 0; )
X		PUTC(' ', stream);
X
X  gs.chars_written += (n > width) ? n : width;
X  return 0;
X}
/
echo x - _doscan.c
sed '/^X/s///' > _doscan.c << '/'
X/* --- _doscan.c --- */
X/* Formatted input workhorse */
X/* Notes:  Floating point support is nonexistent			*/
X
X#include 
X#include 
X#include 
X#include 
X#include 
X#include "stdiolib.h"
X
X/* --- Constants --- */
X#define OK			0	/* return values from input eaters */
X#define INPUT_FAILURE		EOF
X#define MATCHING_FAILURE	1 
X#define UNIMPLEMENTED		2
X
X#define POINTER_BASE		16	/* constants for %p conversion */
X#define POINTER_TYPE		'\0'
X
X#define SIGNED			0	/* constants for _strtol() */
X#define UNSIGNED		1
X
X#define NO_NULL			0	/* constants for _strtostr() */
X#define ADD_NULL		1
X#define NO_COMPARE		0
X#define WHITE_COMPARE		1
X#define SET_COMPARE		2
X#define CHAR_SET_SIZE		128
X
X/* --- Global state --- */
Xstatic struct {
X  int (*next_char)();	/* pointer to input function */
X  union {
X    unsigned char *s;	/* pointer to input string */
X    FILE *f;		/* pointer to input file */
X  } src;
X  int input_char;	/* buffer for next input character */
X  const char *fp;	/* format pointer */
X  va_list ap;		/* argument pointer */
X  int chars_read;	/* number of characters read from the stream (%n) */
X  int items_converted;	/* successful conversions */
X  int items_assigned;	/* successful assignments */
X  int no_assign;	/* if set, conversion is done but not assignment */
X  int width;		/* maximum input field width */
X  char modifier;	/* short/long modifier */
X} gs;
X
Xstatic char valid_char[CHAR_SET_SIZE];
X
X/* --- Macros --- */
X#define BACKUP_INPUT(c)	((gs.input_char = (c)), (gs.chars_read--))
X
X/* --- Input functions --- */
Xstatic int _i_string();
Xstatic int _i_stream();
X
X/* --- Input processors --- */
Xstatic int _eat_white(),	/* ' ' */
X	   _eat_one(),		/* any literal character */
X	   _parse_format(),	/* parse formats */
X	   _strtol(),		/* convert integer formats */
X	   _strtod(),		/* convert floating formats */
X	   _strtostr();		/* convert string formats */
X
X	    
Xint _doscan(is_string, source, format, arg)
Xint is_string;
Xvoid *source;
Xconst char *format;
Xva_list arg;
X{
X  register int c;
X  register int error = OK;
X
X  gs.next_char = (is_string) ? _i_string : _i_stream;
X  gs.src.s = (unsigned char *) source;
X  gs.input_char = EOF;
X  gs.fp = format;
X  gs.ap = arg;
X  gs.items_converted = 0;
X  gs.items_assigned = 0;
X
X  while ((c = (int) *gs.fp++) && (error == OK)) {
X	if (isspace(c))
X		error = _eat_white();
X	else
X	if (c == '%')
X		error = _parse_format();
X	else
X		error = _eat_one(c);
X  }
X  if (gs.input_char != EOF && !is_string)
X	ungetc(gs.input_char, gs.src.f);
X  return (error == INPUT_FAILURE && gs.items_converted == 0)
X	? EOF : gs.items_assigned;
X}
X
Xstatic int _i_stream()
X{
X  int rc;
X
X  gs.chars_read++;
X  if ((rc = gs.input_char) != EOF) {
X	gs.input_char = EOF;
X	return rc;
X  }
X  return getc(gs.src.f);
X}
X
Xstatic int _i_string()
X{
X  int rc;
X  gs.chars_read++;
X  if ((rc = gs.input_char) != EOF) {
X	gs.input_char = EOF;
X	return rc;
X  }
X  if (*gs.src.s == '\0')
X	return EOF;
X  return (int) *gs.src.s++;
X}
X
Xstatic int _parse_format()
X{
X  register int c;
X
X  if ((c = *gs.fp++) == '%')
X	return _eat_one(c);
X
X  gs.no_assign = 0;		/* default: assign converted value */
X  gs.width = INT_MAX;		/* default: enormous maximum width */
X  gs.modifier = '\0';		/* default: no long/short modifier */
X
X  if (c == '*') {
X	gs.no_assign = 1;
X	c = *gs.fp++;
X  }
X  if (isdigit(c)) {
X	gs.width = 0;
X	while (isdigit(c)) {	/* PENDING - this should handle +/- signs */
X		gs.width = 10 * gs.width + c - '0';
X		c = *gs.fp++;
X	}
X  }
X  if (c == 'h' || c == 'l' || c == 'L') {
X	gs.modifier = c;
X	c = *gs.fp++;
X  }
X  if (c == 'D' || c == 'O' || c == 'U') {	/* not ANSI */
X	gs.modifier = 'l';
X	c = _tolower(c);
X  }
X  switch (c) {
X  case 'd':
X	return _strtol(10, SIGNED);
X  case 'i':
X	return _strtol(0, SIGNED);
X  case 'o':
X	return _strtol(8, UNSIGNED);
X  case 'u':
X	return _strtol(10, UNSIGNED);
X  case 'x':
X  case 'X':
X	return _strtol(16, UNSIGNED);
X  case 'f':
X  case 'e':
X  case 'E':
X  case 'g':
X  case 'G':
X	return _strtod();
X  case 's':
X	return _strtostr(WHITE_COMPARE, ADD_NULL);
X  case '[':
X	return _strtostr(SET_COMPARE, ADD_NULL);
X  case 'c':
X	if (gs.width == INT_MAX)
X		gs.width = 1;
X	return _strtostr(NO_COMPARE, NO_NULL);
X  case 'p':
X	return _strtol(POINTER_BASE, UNSIGNED);
X  case 'n':
X	if (!gs.no_assign)
X		*va_arg(gs.ap, int *) = gs.chars_read;
X	return OK;
X  default:
X	return MATCHING_FAILURE;
X  }
X}
X
X/* --- Input processors --- */
Xstatic int _eat_white()
X{
X  register int c;
X
X  while ((c = (*gs.next_char)()) != EOF && isspace(c)) ;
X  BACKUP_INPUT(c);
X  return (c == EOF) ? INPUT_FAILURE : OK;
X}
X
Xstatic int _eat_one(c)
Xint c;
X{
X  register int i;
X
X  if ((i = (*gs.next_char)()) == EOF)
X	return INPUT_FAILURE;
X  return (i == c) ? OK : MATCHING_FAILURE;
X}
X
Xstatic int _strtol(base, is_unsigned)
Xint base;
Xint is_unsigned;
X{
X  register int c;
X  long result = 0L;
X  int negative = 0;
X  int original_width = gs.width;
X  int digit;
X
X  if (_eat_white() == INPUT_FAILURE)
X	return INPUT_FAILURE;
X
X/* --- Handle signs --- */
X  c = (*gs.next_char)();
X  if (c == '+' || c == '-') {
X	negative = (c == '-');
X	gs.width--;
X	c = (*gs.next_char)();
X  }
X
X/* --- Determine base if unknown --- */
X  if (base == 0) {
X	base = 10;
X	if (c == '0') {
X		base = 8;
X		gs.width--;
X		c = (*gs.next_char)();
X		if (c == 'x' || c == 'X') {
X			base = 16;
X			gs.width--;
X			c = (*gs.next_char)();
X		}
X	}
X  }
X
X/* --- Discard 0x or 0X prefix if hexadecimal --- */
X  else
X  if (base == 16 && c == '0') {
X	gs.width--;
X	c = (*gs.next_char)();
X	if (c == 'x' || c == 'X') {
X		gs.width--;
X		c = (*gs.next_char)();
X	}
X  }
X
X/* --- Convert the number --- */
X  while (gs.width-- > 0 && c != EOF) {
X	if (isdigit(c))
X		digit = c - '0';
X	else
X		digit = c - (isupper(c) ? 'A' : 'a') + 10;
X	if (digit < 0 || digit >= base)
X		break;
X	result = base * result + digit;
X	c = (*gs.next_char)();
X  }
X  gs.width++;
X  BACKUP_INPUT(c);
X  gs.items_converted++;
X
X/* --- Sign the result --- */
X  if (negative)
X	result = 0L - result;
X
X/* --- Stash the result --- */
X  if (gs.width == original_width)
X	return (c == EOF) ? INPUT_FAILURE : MATCHING_FAILURE;
X  if (!gs.no_assign) {
X    if (is_unsigned) {
X	if (gs.modifier == 'l')
X		*va_arg(gs.ap, unsigned long *)  = (unsigned long)  result;
X	else
X	if (gs.modifier == 'h')
X		*va_arg(gs.ap, unsigned short *) = (unsigned short) result;
X	else
X		*va_arg(gs.ap, unsigned int *)   = (unsigned int)   result;
X    } else {
X	if (gs.modifier == 'l')
X		*va_arg(gs.ap, long *)  = (long)  result;
X	else
X	if (gs.modifier == 'h')
X		*va_arg(gs.ap, short *) = (short) result;
X	else
X		*va_arg(gs.ap, int *)   = (int)   result;
X    }
X    gs.items_assigned++;
X  }
X  return OK;
X}
X
Xstatic int _strtod()				/* PENDING */
X{
X  return UNIMPLEMENTED;
X}
X
Xstatic int _strtostr(method, string_end)
Xint method;
Xint string_end;
X{
X  int negated;
X  register int c;
X  register unsigned char *target;
X  int original_width = gs.width;
X
X/* --- Set up for comparisons --- */
X  if (method == WHITE_COMPARE) {
X	if (_eat_white() == INPUT_FAILURE)
X		return INPUT_FAILURE;
X  } else
X  if (method == SET_COMPARE) {
X	negated = 0;
X	if (*gs.fp == '^') {
X		negated = 1;
X		gs.fp++;
X	}
X	memset(valid_char, negated, CHAR_SET_SIZE);
X	negated = !negated;
X	c = EOF;
X	do {
X		register int next = gs.fp[1];
X
X		if (c != EOF && *gs.fp == '-' && next != ']') {
X			for (c++ ; c <= next; c++)
X				valid_char[c] = negated;
X			gs.fp++;
X			c = EOF;
X		}
X		else
X			valid_char[c = *gs.fp] = negated;
X	} while (*++gs.fp != ']');
X	gs.fp++;
X  }
X
X/* --- Copy the string --- */
X  if (!gs.no_assign)
X	target = va_arg(gs.ap, unsigned char *);
X  c = (*gs.next_char)();
X  while (gs.width-- > 0 && c != EOF) {
X	if (method == WHITE_COMPARE && isspace(c))
X		break;
X	else
X	if (method == SET_COMPARE && !valid_char[c])
X		break;
X	if (!gs.no_assign)
X		*target++ = c;
X	c = (*gs.next_char)();
X  }
X  gs.width++;
X  BACKUP_INPUT(c);
X  gs.items_converted++;
X
X/* --- Finish up --- */
X  if (!gs.no_assign) {
X	if (string_end == ADD_NULL)
X		*target = '\0';
X	gs.items_assigned++;
X  }
X  if (gs.width == original_width)
X	return (c == EOF) ? INPUT_FAILURE : MATCHING_FAILURE;
X  return OK;
X}
/
echo x - _filbuf.c
sed '/^X/s///' > _filbuf.c << '/'
X/* --- _filbuf.c --- */
X/* Read from the file associated with a stream */
X/* Notes:  Will flush stdout if reading stdin and both are tty's	*/
X
X#include 
X#include 
X#include 
X#include "stdiolib.h"
X
Xint _filbuf(stream)
Xregister FILE *stream;
X{
X  int c;
X
X/* --- Virgin stream: set things up --- */
X  if (stream->_io_count < _IO_NEVER)
X	_i_init(stream);
X
X/* --- Read a bufferful --- */
X  if (stream->_io_bufsiz == 0) {	/* unbuffered */
X	if (stream->_io._io_char != EOF) {	/* check for ungetc()ed char */
X		c = stream->_io._io_char;
X		stream->_io._io_char = EOF;
X		return c;
X	}
X	stream->_io_count = read(stream->_io_fd, (char *) &c, 1);
X  } else {
X	stream->_io_count =
X		read(stream->_io_fd, (char *) stream->_io_buf, stream->_io_bufsiz);
X	stream->_io._io_ptr = stream->_io_buf;
X  }
X  if (stream->_io_count < 0) {
X	_io_setflag(stream, _IO_ERR);
X	return EOF;
X  }
X  if (stream->_io_count == 0) {
X	_io_setflag(stream, _IO_EOF);
X	if (_io_testflag(stream, _IO_UPDATE))
X		_io_clearflag(stream, (_IO_READ | _IO_WRITE));
X	return EOF;
X  }
X  stream->_io_count--;
X  return (stream->_io_bufsiz == 0)
X	? c
X	: *stream->_io._io_ptr++;
X}
/
echo x - _flsbuf.c
sed '/^X/s///' > _flsbuf.c << '/'
X/* --- _flsbuf.c --- */
X/* Flushes full stream buffers */
X/* Notes:  #define _V7 gives support for append mode when kernel doesn't*/
X
X#include 
X#include 
X#include 
X#include "stdiolib.h"
X
Xint _flsbuf(c, stream)		/* stream must be valid, writable */
Xint c;
Xregister FILE *stream;
X{
X/* --- Virgin stream: set things up --- */
X  if (++stream->_io_count == _IO_NEVER)
X	_o_init(stream);
X
X#ifdef _V7
X/* --- Append kludge --- */
X  if (_io_testflag(stream, _IO_APPEND) && _io_testflag(stream, _IO_NEEDSEEK)) {
X	lseek(stream->_io_fd, 0L, SEEK_END);
X	_io_clearflag(stream, _IO_NEEDSEEK);
X  }
X#endif
X
X/* --- Unbuffered stream: write one character --- */
X  if (stream->_io_bufsiz == 0) {
X	stream->_io_count = 0;
X	if (write(stream->_io_fd, (char *) &c, 1) != 1) {
X		_io_setflag(stream, _IO_ERR);
X		return EOF;
X	}
X	return c;
X  }
X
X/* --- Buffered stream: write out a full buffer --- */
X  if (stream->_io_count == 0) {
X	if (write(stream->_io_fd, (char *) stream->_io_buf, stream->_io_bufsiz)
X							!= stream->_io_bufsiz) {
X		_io_setflag(stream, _IO_ERR);
X		return EOF;
X	}
X	stream->_io._io_ptr = stream->_io_buf;
X	stream->_io_count = stream->_io_bufsiz;
X  }
X
X/* --- Buffered stream: start filling new buffer --- */
X  --stream->_io_count;
X  *stream->_io._io_ptr++ = c;
X
X/* --- Line buffered stream: flush a partial buffer --- */
X  if (_io_testflag(stream, _IO_LBUF) && c == '\n' && _flspbuf(stream) != 0)
X	return EOF;
X
X  return c;
X}
/
echo x - _flspbuf.c
sed '/^X/s///' > _flspbuf.c << '/'
X/* --- _flspbuf.c --- */
X/* Flushes partially full stream buffers */
X/* Notes:  #define _V7 gives support for append mode when kernel doesn't*/
X
X#include 
X#include 
X#include 
X#include "stdiolib.h"
X
Xint _flspbuf(stream)
Xregister FILE *stream;
X{
X  register int bytes = stream->_io_bufsiz - stream->_io_count;
X
X#ifdef _V7
X  if (_io_testflag(stream, _IO_APPEND) && _io_testflag(stream, _IO_NEEDSEEK)) {
X	lseek(stream->_io_fd, 0L, SEEK_END);
X	_io_clearflag(stream, _IO_NEEDSEEK);
X  }
X#endif
X
X  if (write(stream->_io_fd, stream->_io_buf, bytes) != bytes) {
X	_io_setflag(stream, _IO_ERR);
X	return EOF;
X  }
X  stream->_io._io_ptr = stream->_io_buf;
X  stream->_io_count = stream->_io_bufsiz;
X  return 0;
X}
/
echo x - _iobdata.c
sed '/^X/s///' > _iobdata.c << '/'
X/* --- _iobdata.c --- */
X/* Data structures for stdio */
X
X#include 
X#include "stdiolib.h"
X
X#define STDIN	{0, _IO_READ  | _IO_LBUF | _IO_TTY, _IO_NEVER, BUFSIZ, NULL}
X#define STDOUT	{1, _IO_WRITE | _IO_LBUF | _IO_TTY, _IO_NEVER, BUFSIZ, NULL}
X#define STDERR	{2, _IO_WRITE,                      _IO_NEVER, 0,      NULL}
X
XFILE _iob[FOPEN_MAX] = {STDIN,	STDOUT,	STDERR	};
Xchar _iov[FOPEN_MAX] = {1,	1,	1	};
X
XFILE *_io_f;		/* for fgetc()/fputc() macros */
Xint _io_c;
X
Xint (*__tmprm)();	/* pointer for cleaning up tmpfile()'s trash */
/
echo x - _iobproc.c
sed '/^X/s///' > _iobproc.c << '/'
X/* --- _iobproc.c --- */
X/* Manages allocation of FILEs */
X/* Notes:  Includes _ioballoc(), _iobfree(), and _iobindex()	*/
X
X#include 
X#include "stdiolib.h"
X
X#define INVALID (-1)
X
Xextern char _iov[];
X
X/* _ioballoc - allocates an i/o block (FILE)	*/
X/* Input:  none					*/
X/* Output: Pointer to a currently free FILE	*/
X
XFILE *_ioballoc()
X{
X  register int i;
X
X  for (i = 0; i < FOPEN_MAX; i++)
X	if (_iov[i] == 0) {
X		_iov[i] = 1;
X		return &_iob[i];
X	}
X  return NULL;
X}
X
X/* _iobfree - frees an i/o block (FILE)	*/
X/* Input:  A stream			*/
X/* Output: None	(but FILE is freed)	*/
X
Xvoid _iobfree(stream)
XFILE *stream;
X{
X  register int i;
X
X  if ((i = _iobindex(stream)) != INVALID)
X	_iov[i] = 0;
X}
X
X/* _iobindex - finds the index of a given stream	*/
X/* Input:  A stream					*/
X/* Output: Index of the stream if valid, -1 otherwise	*/
X
Xint _iobindex(stream)
Xregister FILE *stream;
X{
X  register FILE *f;
X  register int i;
X
X  for (i = 0, f = _iob; i < FOPEN_MAX; i++, f++)
X	if (stream == f)
X		return _iov[i] ? i : INVALID;
X  return INVALID;
X}
/
echo x - _ioinit.c
sed '/^X/s///' > _ioinit.c << '/'
X/* --- _ioinit.c --- */
X/* Checks for a whole bunch of initial conditions on i/o */
X/* Notes:  Includes _i_init() and _o_init() */
X
X#include 
X#include 
X#include 
X#include "stdiolib.h"
X
Xvoid _i_init(stream)
Xregister FILE *stream;
X{
X/* --- Allocate a buffer if necessary --- */
X  if (stream->_io_buf == NULL && stream->_io_bufsiz != 0)
X	_bufalloc(stream);
X  stream->_io_count = 0;
X  _io_setflag(stream, _IO_READ);
X
X/* --- Line buffering: check once and turn it off if stream is not a tty --- */
X  if (_io_testflag(stream, _IO_TTY)) {
X	if (_io_testflag(stream, _IO_LBUF) && !isatty(stream->_io_fd))
X		_io_clearflag(stream, _IO_LBUF);
X	_io_clearflag(stream, _IO_TTY);
X  }
X
X/* --- Flush stdout (if _IOLBF) when reading from _IONBF/_IOLBF stream --- */
X  if (stream->_io_bufsiz == 0 || _io_testflag(stream, _IO_LBUF))
X	if (_io_testflag(stdout, _IO_LBUF))
X		fflush(stdout);
X}
X
Xvoid _o_init(stream)
Xregister FILE *stream;
X{
X/* --- Register _cleanup() so that exit() can find it --- */
X  if (__cleanup == NULL)
X	__cleanup = _cleanup;
X
X/* --- Allocate a buffer if necessary --- */
X  if (stream->_io_buf == NULL && stream->_io_bufsiz != 0)
X	_bufalloc(stream);
X  stream->_io_count = stream->_io_bufsiz;
X  _io_setflag(stream, _IO_WRITE);
X
X/* --- Line buffering: check once and turn it off if stream is not a tty --- */
X  if (_io_testflag(stream, _IO_TTY)) {
X	if (_io_testflag(stream, _IO_LBUF) && !isatty(stream->_io_fd))
X		_io_clearflag(stream, _IO_LBUF);
X	_io_clearflag(stream, _IO_TTY);
X  }
X}
/
echo x - _valmode.c
sed '/^X/s///' > _valmode.c << '/'
X/* --- _valmode.c --- */
X/* Validates mode for stream opening functions	*/
X
X/* Input:  mode - a mode string for fopen()		*/
X/* Output: EOF for a bad string				*/
X/*	   0 for a good string without a '+'		*/
X/*	   _IO_UPDATE for a good string with a '+'	*/
X
X#include 
X#include "stdiolib.h"
X
Xint _valmode(mode)
Xregister const char *mode;
X{
X  register int rc = 0;
X
X/* --- Check basic mode --- */
X  if (*mode != 'r' && *mode != 'w' && *mode != 'a')
X	return EOF;
X  if (*++mode == '\0')
X	return rc;
X
X/* --- Check second character of mode string --- */
X  if (*mode == '+')
X	rc = _IO_UPDATE;
X  else
X  if (*mode == 'b')			/* ANSI mandated - of no use here */
X	;
X  else
X	return EOF;
X  if (*++mode == '\0')
X	return rc;
X
X/* --- Check third character of mode string --- */
X  if (*mode == '+' && rc != _IO_UPDATE)
X	rc = _IO_UPDATE;
X  else
X  if (*mode == 'b' && rc == _IO_UPDATE)
X	;
X  else
X	return EOF;
X  if (*++mode == '\0')
X	return rc;
X
X/* --- Mode string too long --- */
X  return EOF;
X}
/
echo x - atexit.c
sed '/^X/s///' > atexit.c << '/'
X/* Copyright 1988 Frank Wortner
X**	You may reproduce and use this software as long as you
X**	do not delete this notice from the source code.
X*/
X
X#define MAXFN 33	/* Maximum number of functions registerable
X			   (includes 1 for __cleanup)			*/
X
Xtypedef void (*PFN)();	/* Pointer to FuNction */
X
Xextern PFN __cleanup;	/* imported from exit.c */
X
Xstatic PFN fn[MAXFN];	/* addresses of functions stored here */
Xstatic int nfn = -1;	/* number of functions registered less one */
X
Xstatic void checkcleanup(), run_atexit();
X
Xint atexit(fun)
XPFN fun;
X{
X	if (nfn == -1)			/* Do we need to check for stdio? */
X		checkcleanup();
X	if (nfn >= MAXFN)		/* Run out of room yet? */
X		return (-1);
X	fn[++nfn] = fun;		/* Save the address of the subr. */
X	return (0);
X}
X
X/* Check to see if stdio is used.  If yes register stdio's cleanup routine
X** with the atexit() system and then force stdio to call run_atexit().
X*/
Xstatic void checkcleanup()
X{
X	if (__cleanup)			/* stdio used ? */
X		fn[++nfn] = __cleanup;
X	__cleanup = run_atexit;
X}
X
X/* Run the requested subroutines */
Xstatic void run_atexit()
X{
X	while (nfn >= 0) {
X		(*fn[nfn--])();
X	}
X}
/
echo x - exit.c
sed '/^X/s///' > exit.c << '/'
X#include 
X#include "lib.h"
X
XPUBLIC void (*__cleanup)() = NULL;
X
XPUBLIC int exit(status)
Xint status;
X{
X  if (__cleanup != NULL)
X	(*__cleanup)();
X  return callm1(MM, EXIT, status, 0, 0, NIL_PTR, NIL_PTR, NIL_PTR);
X}
X
XPUBLIC int _exit(status)
Xint status;
X{
X  return callm1(MM, EXIT, status, 0, 0, NIL_PTR, NIL_PTR, NIL_PTR);
X}
/
echo x - fclose.c
sed '/^X/s///' > fclose.c << '/'
X/* --- fclose.c --- */
X/* Closes a stream and its associated file */
X
X#include 
X#include 
X#include 
X#include "stdiolib.h"
X#undef fclose
X
X#define _IO_ERRVAL EOF
X
Xextern int (*__tmprm)();
X
Xint fclose(stream)
Xregister FILE *stream;
X{
X  _io_assert(_io_valid(stream));
X
X  if (fflush(stream))
X	return _IO_ERRVAL;
X  _buffree(stream);
X  if (close(stream->_io_fd))
X	return _IO_ERRVAL;
X  if (_io_testflag(stream, _IO_TEMP))
X	if (__tmprm) (*__tmprm)(_iobindex(stream));
X  _iobfree(stream);
X  return 0;
X}
/
echo x - fdopen.c
sed '/^X/s///' > fdopen.c << '/'
X/* --- fdopen.c --- */
X/* Associates a stream with an already open file */
X/* Notes:  Open mode of file must agree with open mode specified	*/
X/*	   #define _V7 gives support for append mode when kernel doesn't*/
X/*	   POSIX function						*/
X
X#include 
X#include 
X#include 
X#include "stdiolib.h"
X#undef fdopen
X
X#define _IO_ERRVAL NULL
X
X
XFILE *fdopen(fd, mode)
Xint fd;
Xconst char *mode;
X{
X  int flags;
X  register FILE *stream;
X
X  _io_assert(fd >= 0);
X
X  if ((flags = _valmode(mode)) < 0)
X	return _IO_ERRVAL;
X  if ((stream = _ioballoc()) == NULL)
X	return _IO_ERRVAL;
X
X  switch (*mode) {
X	case 'r':
X		flags |= _IO_READ;
X		break;
X	case 'w':
X		flags |= _IO_WRITE;
X		break;
X	case 'a':
X#ifdef _V7
X		flags |= _IO_WRITE | _IO_APPEND;
X		lseek(fd, 0L, SEEK_END);
X#else
X		flags |= _IO_WRITE;
X#endif
X		break;
X	default:
X		_iobfree(stream);
X		return _IO_ERRVAL;
X  }
X
X  if (isatty(fd))
X	flags |= _IO_LBUF;
X  stream->_io_fd = fd;
X  stream->_io_flags = flags;
X  stream->_io_count = _IO_NEVER;
X  stream->_io_bufsiz = BUFSIZ;
X  return stream;
X}
/
echo x - fflush.c
sed '/^X/s///' > fflush.c << '/'
X/* --- fflush.c --- */
X/* Flushes a stream's buffer */
X/* Notes:  Given a NULL pointer as a stream, fflush() flushes all streams. */
X/*	   Flushing a readable stream discards the buffer contents	   */
X/*		and lseek()'s the underlying file to meet expectations.    */
X
X#include 
X#include 
X#include 
X#include "stdiolib.h"
X#undef fflush
X
X#define _IO_ERRVAL EOF
X
Xextern char _iov[];
Xstatic int _fflush	_PROTO((FILE *stream));
X
Xint fflush(stream)
Xregister FILE *stream;
X{
X  register int i;
X  register int rc;
X
X  if (stream == NULL) {
X	rc = 0;
X	for (i = 0, stream = _iob; i < FOPEN_MAX; i++, stream++) {
X		if (_iov[i])
X			rc |= _fflush(stream);
X	}
X	return rc;
X  } else {
X	_io_assert(_io_valid(stream));
X	return _fflush(stream);
X  }
X}
X
Xstatic int _fflush(stream)
Xregister FILE *stream;
X{
X  register int rc = 0;
X
X  if (stream->_io_count == _IO_NEVER)
X	return rc;
X  if (stream->_io_bufsiz != 0) {
X	if (_io_testflag(stream, _IO_WRITE))
X		rc = _flspbuf(stream);
X	else
X	if (_io_testflag(stream, _IO_READ) && !feof(stream))
X		if (lseek(stream->_io_fd, 0L - stream->_io_count, SEEK_CUR) < 0L)
X			rc = EOF;
X  }
X  stream->_io_count = _IO_NEVER;
X  if (stream->_io_bufsiz == 0)
X	stream->_io._io_char = EOF;
X  else
X	stream->_io._io_ptr = stream->_io_buf;
X  if (_io_testflag(stream, _IO_UPDATE))
X	_io_clearflag(stream, (_IO_READ | _IO_WRITE));
X  return rc;
X}
/
echo x - fgetc.c
sed '/^X/s///' > fgetc.c << '/'
X/* --- fgetc.c --- */
X/* Retrieves the next character from a stream */
X/* Notes:  Includes getc() and getchar(), backstops for macros in  */
X
X#include 
X#include "stdiolib.h"
X#undef fgetc
X#undef getc
X#undef getchar
X
X#define _IO_ERRVAL EOF
X
Xint fgetc(stream)
Xregister FILE *stream;
X{
X  _io_assert(_io_valid(stream));
X  _io_assert(!_io_testflag(stream, _IO_WRITE));
X  _io_assert(!_io_testflag(stream, (_IO_EOF | _IO_ERR)));
X
X  return (--stream->_io_count >= 0) ?
X	*stream->_io._io_ptr++ : _filbuf(stream);
X}
X
Xint getc(stream)
XFILE *stream;
X{
X  return fgetc(stream);
X}
X
Xint getchar()
X{
X  return fgetc(stdin);
X}
/
echo x - fgets.c
sed '/^X/s///' > fgets.c << '/'
X/* --- fgets.c --- */
X/* Reads limited number of characters from a stream, up to a newline */
X/* Notes:  Returns EOF only if no characters read before end of file	*/
X
X#include 
X#include "stdiolib.h"
X#undef fgets
X
X#define _IO_ERRVAL NULL
X
Xchar *fgets(s, n, stream)
Xchar *s;
Xregister int n;
XFILE *stream;
X{
X  register int c;
X  register char *p = s;
X
X  _io_assert(s);
X  _io_assert(n > 0);
X  _io_assert(_io_valid(stream));
X  _io_assert(!_io_testflag(stream, _IO_WRITE));
X  _io_assert(!_io_testflag(stream, (_IO_EOF | _IO_ERR)));
X
X  while (--n > 0 && (c = getc(stream)) != EOF) {
X	*p++ = c;
X	if (c == '\n')
X		break;
X  }
X  *p = '\0';
X  return (p == s && c == EOF) ? NULL : s;
X}
/
echo x - fopen.c
sed '/^X/s///' > fopen.c << '/'
X/* --- fopen.c --- */
X/* Opens a file and associates a stream with it */
X/* Notes:  #define _V7 gives support for append mode when kernel doesn't*/
X
X#include 
X#include 
X#include 
X#include 
X#include "stdiolib.h"
X#undef fopen
X
X#define _IO_ERRVAL NULL
X#define PMODE	0666
X
XFILE *fopen(filename, mode)
Xconst char *filename;
Xconst char *mode;
X{
X  int fd;
X  int flags;
X  register FILE *stream;
X
X  _io_assert(filename);
X  _io_assert(mode);
X
X  if ((flags = _valmode(mode)) < 0)
X	return _IO_ERRVAL;
X  if ((stream = _ioballoc()) == NULL)
X	return _IO_ERRVAL;
X
X  switch (*mode) {
X	case 'r':
X		fd = open(filename, flags ? O_RDWR : O_RDONLY);
X		flags |= _IO_READ;
X		break;
X	case 'w':
X#ifdef _V7
X		if ((fd = creat(filename, PMODE)) >= 0 && flags) {
X			close(fd);
X			fd = open(filename, O_RDWR);
X		}
X#else
X		fd = open(filename, O_CREAT | O_TRUNC | (flags ? O_RDWR : O_WRONLY), PMODE);
X#endif
X		flags |= _IO_WRITE;
X		break;
X	case 'a':
X#ifdef _V7
X		if ((fd = open(filename, flags ? O_RDWR : O_WRONLY)) >= 0) {
X			lseek(fd, 0L, SEEK_END);
X		}
X		else
X		if ((fd = creat(filename, PMODE)) >= 0 && flags) {
X			close(fd);
X			fd = open(filename, O_RDWR);
X		}
X		flags |= (_IO_WRITE | _IO_APPEND);
X#else
X		fd = open(filename, O_CREAT | O_APPEND | (flags ? O_RDWR : O_WRONLY), PMODE);
X		flags |= _IO_WRITE;
X#endif
X		break;
X	default:
X		fd = -1;
X  }
X  if (fd < 0) {
X	_iobfree(stream);
X	return _IO_ERRVAL;
X  }
X
X  if (isatty(fd))
X	flags |= _IO_LBUF;
X  stream->_io_fd = fd;
X  stream->_io_flags = flags;
X  stream->_io_count = _IO_NEVER;
X  stream->_io_bufsiz = BUFSIZ;
X  return stream;
X}
/
echo x - fputc.c
sed '/^X/s///' > fputc.c << '/'
X/* --- fputc.c --- */
X/* Writes a single character onto a stream */
X/* Notes:  Includes putc() and putchar(), macro backstops for 	*/
X
X#include 
X#include "stdiolib.h"
X#undef fputc
X#undef putc
X#undef putchar
X
X#define _IO_ERRVAL EOF
X
X
Xint fputc(c, stream)
Xregister int c;
Xregister FILE *stream;
X{
X  _io_assert(_io_valid(stream));
X  _io_assert(!_io_testflag(stream, _IO_READ));
X  _io_assert(!_io_testflag(stream, (_IO_EOF | _IO_ERR)));
X
X#ifndef NDEBUG
X  if (_io_testflag(stream, _IO_STRING))
X	return (int) (*stream->_io._io_ptr++ = c);
X#endif
X
X  return ((--stream->_io_count < 0) ||
X	  (_io_testflag(stream, _IO_LBUF) && c == '\n'))
X	? _flsbuf(c, stream)
X	: (int) (*stream->_io._io_ptr++ = c);
X}
X
Xint putc(c, stream)
Xint c;
Xregister FILE *stream;
X{
X  return fputc(c, stream);
X}
X
Xint putchar(c)
Xint c;
X{
X  return fputc(c, stdout);
X}
/
echo x - fputs.c
sed '/^X/s///' > fputs.c << '/'
X/* --- fputs.c --- */
X/* Writes a string to a stream */
X/* Notes:  Includes puts(), which backstops a macro in 	*/
X
X#include 
X#include "stdiolib.h"
X#undef fputs
X#undef puts
X
X#define _IO_ERRVAL EOF
X
X
Xint fputs(s, stream)
Xregister const char *s;
Xregister FILE *stream;
X{
X  _io_assert(s);
X  _io_assert(_io_valid(stream));
X  _io_assert(!_io_testflag(stream, _IO_READ));
X  _io_assert(!_io_testflag(stream, _IO_ERR));
X
X  while (*s) {
X	if (putc(*s, stream) == EOF)
X		return EOF;
X	s++;
X  }
X  return 0;
X}
X
Xint puts(s)
Xconst char *s;
X{
X  return (fputs(s, stdout) >= 0) ? ((putchar('\n') == '\n') ? 0 : EOF) : EOF;
X}
X
/
echo x - fread.c
sed '/^X/s///' > fread.c << '/'
X/* --- fread.c --- */
X/* Reads directly from a stream into a buffer */
X/* Notes:  Attempts to buffer requests but reads directly if impossible	*/
X
X#include 
X#include 
X#include 
X#include 
X#include 
X#include "stdiolib.h"
X#undef fread
X
X#define _IO_ERRVAL 0
X
X/* --- The following value determines whether fread() requests go	--- */
X/* --- through the buffer or are done directly.  As set, the limit	--- */
X/* --- means that small requests (less than half the stream's buffer	--- */
X/* --- size) will use buffering; larger requests are done directly.	--- */
X/* --- Empirical testing shows this is reasonable; more should be done.	--- */
X#define BUFFER_LIMIT	(stream->_io_bufsiz >> 1)
X
X#define FROM_IO(bytes) {			\
X	memcpy(p, stream->_io._io_ptr, bytes);	\
X	p += bytes;				\
X	stream->_io._io_ptr += bytes;		\
X	stream->_io_count -= bytes;		\
X	}
X#define FROM_FS(bytes)	read(stream->_io_fd, (char *) p, bytes)
X
Xsize_t fread(ptr, size, nmemb, stream)
Xvoid *ptr;
Xsize_t size;
Xsize_t nmemb;
XFILE *stream;
X{
X  long total_size;
X  long bytes_left;
X  register unsigned char *p = (unsigned char *) ptr;
X  register int bytes;
X  int c;
X  int n;
X
X  _io_assert(p != NULL);
X  _io_assert(_io_valid(stream));
X  _io_assert(!_io_testflag(stream, _IO_WRITE));
X  _io_assert(!_io_testflag(stream, (_IO_EOF | _IO_ERR)));
X
X  if ((total_size = (long) nmemb * (long) size) == 0)
X	return 0;
X
X/* --- Virgin stream: set things up --- */
X  if (stream->_io_count == _IO_NEVER)
X	_i_init(stream);
X
X/* --- Most common case(?): from the buffer --- */
X  if (total_size <= stream->_io_count) {
X	bytes = total_size;
X	FROM_IO(bytes);
X	return nmemb;
X  }
X
X/* --- Empty the buffer --- */
X  bytes_left = total_size;
X  if (stream->_io_count > 0) {
X	bytes_left -= stream->_io_count;
X	FROM_IO(stream->_io_count);
X  }
X
X/* --- Small objects: try filling the stdio buffer ONCE --- */
X  if (bytes_left <= BUFFER_LIMIT) {
X	if ((c = _filbuf(stream)) == EOF)
X		return (total_size - bytes_left) / size;
X	*p++ = c;
X	if ((bytes = --bytes_left) <= stream->_io_count) {
X		FROM_IO(bytes);
X		return nmemb;
X	}
X  }
X
X/* --- Buffering failed: read() directly --- */
X  if (stream->_io_count > 0) {
X	bytes_left -= stream->_io_count;
X	FROM_IO(stream->_io_count);
X  }
X  for ( ; bytes_left > INT_MAX; bytes_left -= n) {
X	if ((n = FROM_FS(INT_MAX)) <= 0) {
X		if (n < 0) {
X			_io_setflag(stream, _IO_ERR);
X		} else {
X			_io_setflag(stream, _IO_EOF);
X			if (_io_testflag(stream, _IO_UPDATE))
X				_io_clearflag(stream, (_IO_READ | _IO_WRITE));
X		}
X		return (total_size - bytes_left) / size;
X	}
X	p += n;
X  }
X  for (bytes = bytes_left; bytes > 0; bytes -= n) {
X	if ((n = FROM_FS(bytes)) <= 0) {
X		if (n < 0) {
X			_io_setflag(stream, _IO_ERR);
X		} else {
X			_io_setflag(stream, _IO_EOF);
X			if (_io_testflag(stream, _IO_UPDATE))
X				_io_clearflag(stream, (_IO_READ | _IO_WRITE));
X		}
X		return (total_size - bytes) / size;
X	}
X	p += n;
X  }
X  return nmemb;
X}
/
echo x - freopen.c
sed '/^X/s///' > freopen.c << '/'
X/* --- freopen.c --- */
X/* Closes the file associated with a stream and then opens a new file */
X/* Notes:  #define _V7 gives support for append mode when kernel doesn't*/
X/*	   Maintains buffer and buffering mode on stream.		*/
X
X#include 
X#include 
X#include 
X#include 
X#include "stdiolib.h"
X#undef freopen
X
X#define _IO_ERRVAL ((FILE *) NULL)
X#define PMODE	0666
X
X 
XFILE *freopen(filename, mode, stream)
Xconst char *filename;
Xconst char *mode;
Xregister FILE *stream;
X{
X  int fd;
X  int flags;
X
X  _io_assert(_io_valid(stream));
X
X  if (fflush(stream) || close(stream->_io_fd))
X	return _IO_ERRVAL;
X  if ((flags = _valmode(mode)) < 0)
X	return _IO_ERRVAL;
X
X  switch (*mode) {
X	case 'r':
X		fd = open(filename, flags ? O_RDWR : O_RDONLY);
X		flags |= _IO_READ;
X		break;
X	case 'w':
X#ifdef _V7
X		if ((fd = creat(filename, PMODE)) >= 0 && flags) {
X			close(fd);
X			fd = open(filename, O_RDWR);
X		}
X#else
X		fd = open(filename, O_CREAT | O_TRUNC | (flags ? O_RDWR : O_WRONLY), PMODE);
X#endif
X		flags |= _IO_WRITE;
X		break;
X	case 'a':
X#ifdef _V7
X		if ((fd = open(filename, flags ? O_RDWR : O_WRONLY)) >= 0) {
X			lseek(fd, 0L, SEEK_END);
X		}
X		else
X		if ((fd = creat(filename, PMODE)) >= 0 && flags) {
X			close(fd);
X			fd = open(filename, O_RDWR);
X		}
X		flags |= (_IO_WRITE | _IO_APPEND);
X#else
X		fd = open(filename, O_CREAT | O_APPEND | (flags ? O_RDWR : O_WRONLY), PMODE);
X		flags |= _IO_WRITE;
X#endif
X		break;
X	default:
X		fd = -1;
X  }
X
X  if (fd < 0) {
X	_buffree(stream);
X	_iobfree(stream);
X	return _IO_ERRVAL;
X  }
X
X  if (isatty(fd))
X	flags |= _IO_LBUF;
X  stream->_io_fd = fd;
X  _io_clearflag(stream, ~(_IO_LBUF | _IO_MYBUF));
X  _io_setflag(stream, flags);
X  stream->_io_count = _IO_NEVER;
X  return stream;
X}
/
echo x - fseek.c
sed '/^X/s///' > fseek.c << '/'
X/* --- fseek.c --- */
X/* Sets the position of a stream */
X/* Notes:  Always flushes a stream's buffer				*/
X/*	   Includes fsetpos() and rewind()				*/
X/*	   fsetpos() is a backstop for a macro in 		*/
X/*	   #define _V7 gives support for append mode when kernel doesn't*/
X
X#include 
X#include 
X#include 
X#include "stdiolib.h"
X#undef fseek
X#undef fsetpos
X#undef rewind
X
X#define _IO_ERRVAL EOF
X
Xint fseek(stream, offset, whence)
Xregister FILE *stream;
Xlong int offset;
Xregister int whence;
X{
X  _io_assert(_io_valid(stream));
X  _io_assert(whence == SEEK_SET || whence == SEEK_CUR || whence == SEEK_END);
X
X  fflush(stream);
X  _io_clearflag(stream, _IO_EOF);
X
X#ifdef _V7
X  if (_io_testflag(stream, _IO_APPEND)) {
X	if (!_io_testflag(stream, _IO_UPDATE))
X		return 0;
X	if (whence != SEEK_END || offset != 0L)
X		_io_setflag(stream, _IO_NEEDSEEK);
X  }
X#endif
X
X  return (lseek(stream->_io_fd, offset, whence) < 0L) ? _IO_ERRVAL : 0;
X}
X
Xint fsetpos(stream, pos)
XFILE *stream;
Xconst fpos_t *pos;
X{
X  return fseek(stream, *pos, SEEK_SET);
X}
X
Xvoid rewind(stream)
XFILE *stream;
X{
X  (void) fseek(stream, 0L, SEEK_SET);
X  clearerr(stream);
X}
/
echo x - ftell.c
sed '/^X/s///' > ftell.c << '/'
X/* --- ftell.c --- */
X/* Returns the position of a stream */
X/* Notes:  Includes fgetpos(), which backstops a macro in 	*/
X
X#include 
X#include 
X#include 
X#include 
X#include "stdiolib.h"
X#undef ftell
X#undef fgetpos
X
X#define _IO_ERRVAL -1L
X
X
Xlong ftell(stream)
Xregister FILE *stream;
X{
X  extern int errno;
X  int adjustment;
X  long position;
X  long lseek();
X
X  errno = EBADF;
X  if (!_io_valid(stream))
X	return _IO_ERRVAL;
X  errno = 0;
X
X  if (stream->_io_count == _IO_NEVER)
X	adjustment = 0;
X  else
X  if (_io_testflag(stream, _IO_READ))
X	adjustment = -stream->_io_count;
X  else
X  if (_io_testflag(stream, _IO_WRITE))
X	adjustment = stream->_io_bufsiz - stream->_io_count;
X
X  return ((position = lseek(stream->_io_fd, 0L, SEEK_CUR)) >= 0L)
X	? position + (long) adjustment
X	: _IO_ERRVAL;
X}
X
Xint fgetpos(stream, position)
XFILE *stream;
Xfpos_t *position;
X{
X  return (*position = (fpos_t) ftell(stream)) >= 0L ? 0 : EOF;
X}
/
echo x - fwrite.c
sed '/^X/s///' > fwrite.c << '/'
X/* --- fwrite.c --- */
X/* Writes directly from a buffer into a stream */
X/* Notes:  Attempts to buffer requests but writes directly if impossible*/
X/*	   #define _V7 gives support for append mode when kernel doesn't*/
X
X#include 
X#include 
X#include 
X#include 
X#include 
X#include "stdiolib.h"
X#undef fwrite
X
X#define _IO_ERRVAL 0
X
X/* --- The following value determines whether fwrite() requests go	--- */
X/* --- through the buffer or are done directly.  As set, the limit	--- */
X/* --- means that small requests (less than half the stream's buffer	--- */
X/* --- size) will use buffering; larger requests are done directly.	--- */
X/* --- Empirical testing shows this is reasonable; more should be done.	--- */
X#define BUFFER_LIMIT	(stream->_io_bufsiz >> 1)
X
X#define TO_IO(bytes) {				\
X	memcpy(stream->_io._io_ptr, p, bytes);	\
X	stream->_io._io_ptr += bytes;		\
X	stream->_io_count -= bytes;		\
X	}
X#define TO_FS(bytes)	write(stream->_io_fd, (char *) p, bytes)
X
Xsize_t fwrite(ptr, size, nmemb, stream)
Xconst void *ptr;
Xsize_t size;
Xsize_t nmemb;
XFILE *stream;
X{
X  register unsigned char *p = (unsigned char *) ptr;
X  long total_size;
X  int buffer_limit;
X  size_t items;
X  int n;
X
X  _io_assert(p != NULL);
X  _io_assert(_io_valid(stream));
X  _io_assert(!_io_testflag(stream, _IO_READ));
X  _io_assert(!_io_testflag(stream, _IO_ERR));
X
X  if ((total_size = (long) nmemb * (long) size) == 0)
X	return 0;
X
X/* --- Virgin stream: set things up --- */
X  if (stream->_io_count == _IO_NEVER)
X	_o_init(stream);
X
X#ifdef _V7
X/* --- Append kludge --- */
X  if (_io_testflag(stream, _IO_APPEND) && _io_testflag(stream, _IO_NEEDSEEK)) {
X	lseek(stream->_io_fd, 0L, SEEK_END);
X	_io_clearflag(stream, _IO_NEEDSEEK);
X  }
X#endif
X
X/* --- Most common case(?): into the buffer --- */
X  buffer_limit = (stream->_io_count < BUFFER_LIMIT)
X	? stream->_io_count : BUFFER_LIMIT;
X  if (total_size <= buffer_limit) {
X	register int bytes = (int) total_size;
X
X	TO_IO(bytes);
X	return nmemb;
X  }
X
X/* --- Doesn't fit: flush what we've accumulated --- */
X  _flspbuf(stream);
X
X/* --- Huge objects: write() in manageable sections --- */
X  items = 0;
X  if (size > INT_MAX) {
X	while (nmemb-- > 0) {
X		register size_t obj_size = size;
X
X		while (obj_size > INT_MAX) {
X			if ((n = TO_FS(INT_MAX)) != INT_MAX) {
X				_io_setflag(stream, _IO_ERR);
X				return items;
X			}
X			obj_size -= INT_MAX;
X			p += INT_MAX;
X		}
X		if ((n = TO_FS(obj_size)) != obj_size) {
X			_io_setflag(stream, _IO_ERR);
X			return items;
X		}
X		p += obj_size;
X		items++;
X	}
X	return items;
X  }
X
X/* --- Lots of small objects: write() in chunks --- */
X  {
X	size_t items_per_chunk;
X	register int chunk_size;
X	long cutoff = stream->_io_count;
X
X	items_per_chunk = INT_MAX / size;
X	if ((chunk_size = size * items_per_chunk) > cutoff)
X		cutoff = chunk_size;
X	while (total_size > cutoff) {
X		if ((n = TO_FS(chunk_size)) != chunk_size) {
X			_io_setflag(stream, _IO_ERR);
X			return items + n / size;
X		} else {
X			items += items_per_chunk;
X		}
X		total_size -= chunk_size;
X		p += chunk_size;
X	}
X	if ((chunk_size = (int) total_size) > BUFFER_LIMIT) {
X		if ((n = TO_FS(chunk_size)) != chunk_size)
X			_io_setflag(stream, _IO_ERR);
X		return items + n / size;
X	}
X	TO_IO(chunk_size);
X	return nmemb;
X  }
X}
/
echo x - gets.c
sed '/^X/s///' > gets.c << '/'
X/* --- gets.c --- */
X/* Reads characters from stdin, up to a newline */
X/* Notes:  Returns EOF only if no characters read before end of file	*/
X
X#include "stdio.h"
X#include "stdiolib.h"
X#undef gets
X
X#define _IO_ERRVAL NULL
X
Xchar *gets(s)
Xchar *s;
X{
X  register char *p = s;
X  register int c;
X
X  _io_assert(s);
X
X  while ((c = getchar()) != EOF && c != '\n')
X	*p++ = c;
X  *p = '\0';
X  return (p == s && c == EOF) ? NULL : s;
X}
/
echo x - perror.c
sed '/^X/s///' > perror.c << '/'
X/* --- perror.c --- */
X/* Prints the current error message */
X/* Notes:  Only minor changes from standard Minix issue	*/
X
X#include 
X#include 
X#include 
X#include 
X#include 
X
Xchar *sys_errlist[] = {
X        "Error 0",
X        "Not owner",
X        "No such file or directory",
X        "No such process",
X        "Interrupted system call",
X        "I/O error",
X        "No such device or address",
X        "Arg list too long",
X        "Exec format error",
X        "Bad file number",
X        "No children",
X        "No more processes",
X        "Not enough core",
X        "Permission denied",
X        "Bad address",
X        "Block device required",
X        "Mount device busy",
X        "File exists",
X        "Cross-device link",
X        "No such device",
X        "Not a directory",
X        "Is a directory",
X        "Invalid argument",
X        "File table overflow",
X        "Too many open files",
X        "Not a typewriter",
X        "Text file busy",
X        "File too large",
X        "No space left on device",
X        "Illegal seek",
X        "Read-only file system",
X        "Too many links",
X        "Broken pipe",
X        "Math argument",
X        "Result too large"
X};
X
Xint sys_nerr = sizeof(sys_errlist)/sizeof(char *);
X
Xvoid perror(s)
Xconst char *s;
X{
X  if (errno < 0 || errno >= sizeof(sys_errlist)/sizeof(char *)) {
X	write(2, "Invalid errno\n", 14);
X  } else {
X	write(2, s, strlen(s));
X	write(2, ": ", 2);
X	write(2, sys_errlist[errno], strlen(sys_errlist[errno]));
X	write(2, "\n", 1);
X  }
X}
/
echo x - printf.c
sed '/^X/s///' > printf.c << '/'
X/* --- printf.c --- */
X/* Formatted printing functions */
X/* Notes:  Includes fprintf(), printf(), vfprintf(), and vprintf();	*/
X/*	   All are front ends for _doprnt()				*/
X/*	   vfprintf() and vprintf() backstop macros in 	*/
X
X#include 
X#include 
X#include "stdiolib.h"
X#undef fprintf
X#undef printf
X#undef vfprintf
X#undef vprintf
X
X
X#define _IO_ERRVAL 0
X
Xint fprintf(stream, format /*, ... */)
XFILE *stream;
Xconst char *format;
X{
X  va_list arg;
X  int n;
X
X  _io_assert(_io_valid(stream));
X  _io_assert(!_io_testflag(stream, _IO_READ));
X  _io_assert(!_io_testflag(stream, _IO_ERR));
X  _io_assert(format);
X
X  va_start(arg, format);
X  n = _doprnt(stream, format, arg);
X  va_end(arg);
X  return n;
X}
X
Xint printf(format /*, ... */)
Xconst char *format;
X{
X  va_list arg;
X  int n;
X
X  _io_assert(_io_valid(stdout));
X  _io_assert(!_io_testflag(stdout, _IO_READ));
X  _io_assert(!_io_testflag(stdout, _IO_ERR));
X  _io_assert(format);
X
X  va_start(arg, format);
X  n = _doprnt(stdout, format, arg);
X  va_end(arg);
X  return n;
X}
X
Xint vfprintf(stream, format, arg)
XFILE *stream;
Xconst char *format;
Xva_list arg;
X{
X  _io_assert(_io_valid(stream));
X  _io_assert(!_io_testflag(stream, _IO_READ));
X  _io_assert(!_io_testflag(stream, _IO_ERR));
X  _io_assert(format);
X
X  return _doprnt(stream, format, arg);
X}
X
Xint vprintf(format, arg)
Xconst char *format;
Xva_list arg;
X{
X  return _doprnt(stdout, format, arg);
X}
/
echo x - remove.c
sed '/^X/s///' > remove.c << '/'
X/* --- remove.c --- */
X/* Removes a file from the file system */
X/* Notes:  Backstops a macro in  */
X
X#include 
X#include 
X#include 
X#undef remove
X
Xint remove(filename)
Xconst char *filename;
X{
X  return unlink(filename);
X}
/
echo x - rename.c
sed '/^X/s///' > rename.c << '/'
X/* --- rename.c --- */
X/* Renames a file in the file system */
X/* Author: Freeman Pascal */
X
X#include 
X#include 
X#include 
X#include 
X#include 
X#include 
X#undef rename
X
X/*========================================================================*\
X**				rename()				  **
X\*========================================================================*/
Xint rename(old, new)
Xconst char *old;
Xconst char *new;
X{
X/*
X *	Attempts new link 'old' as 'new'.  If 'new' exists it is unlinked.
X *
X *	NOTE:  	'rename()' will not rename across file systems or 
X *		file types.  Also, if an attempt is made to copy across
X *		file systems both files will be left intact and an
X *		error will be returned.
X */
X  struct stat	s_new, s_old;
X  void		(*s_int)(), (*s_hup)(), (*s_quit)();
X  int		ret = 0;
X  
X  /*
X   *	Get status of 'old' and 'new'; if either attempt fails we know 
X   *	one of the files doesn't exist.  If 'old' doesn't exist, then
X   *	return an error condition.  If both files exist, then test if
X   *	they are both on the same file system.  If 'new' doesn't exist,
X   *	then don't worry about it - it soon will.
X   */
X  if (stat(old, &s_old) == 0) {
X	if (stat(new, &s_new) == 0) {
X		if (s_new.st_dev == s_old.st_dev) {
X			errno = EXDEV;
X			return -1;
X		}
X	}
X	/* Ignore SIGINT, SIGHUP, and SIGQUIT until we're finished. */
X	s_int  = signal(SIGINT,  SIG_IGN);
X	s_hup  = signal(SIGHUP,  SIG_IGN);
X	s_quit = signal(SIGQUIT, SIG_IGN);  
X	/* Does 'new' exist? If so, remove it. */
X	ret = unlink(new);
X	if ((ret = link(old, new)) == 0) 
X		ret = unlink(old);
X	/* Restore signals. */
X	signal(SIGINT,  s_int );
X	signal(SIGHUP,  s_hup );
X	signal(SIGQUIT, s_quit);
X	return ret;
X  }
X  return -1;
X}
/
echo x - scanf.c
sed '/^X/s///' > scanf.c << '/'
X/* --- scanf.c --- */
X/* Formatted input functions */
X/* Notes:  Includes fscanf() and scanf(), front ends for _doscan()	*/
X
X#include 
X#include 
X#include "stdiolib.h"
X#undef fscanf
X#undef scanf
X
X#define _IO_ERRVAL EOF
X
Xint fscanf(stream, format /*, ... */)
XFILE *stream;
Xconst char *format;
X{
X  va_list arg;
X  int n;
X
X  _io_assert(_io_valid(stream));
X  _io_assert(!_io_testflag(stream, _IO_WRITE));
X  _io_assert(!_io_testflag(stream, (_IO_EOF | _IO_ERR)));
X  _io_assert(format);
X
X  va_start(arg, format);
X  n = _doscan(0, (void *) stream, format, arg);
X  va_end(arg);
X  return n;
X}
X
X
Xint scanf(format /*, ... */)
Xconst char *format;
X{
X  va_list arg;
X  int n;
X
X  _io_assert(_io_valid(stdin));
X  _io_assert(!_io_testflag(stdin, _IO_WRITE));
X  _io_assert(!_io_testflag(stdin, (_IO_EOF | _IO_ERR)));
X  _io_assert(format);
X
X  va_start(arg, format);
X  n = _doscan(0, (void *) stdin, format, arg);
X  va_end(arg);
X  return n;
X}
/
echo x - setvbuf.c
sed '/^X/s///' > setvbuf.c << '/'
X/* --- setvbuf.c --- */
X/* Associates a buffer with a stream and sets buffering modes */
X/* Notes:  Does not actually allocate a buffer; just sets things up	*/
X/*	   Includes setbuf(), which backstops a macro in 	*/
X
X#include 
X#include "stdiolib.h"
X#undef setvbuf
X#undef setbuf
X
X#define _IO_ERRVAL EOF
X
X
Xint setvbuf(stream, buffer, type, size)
Xregister FILE *stream;
Xchar *buffer;
Xint type;
Xsize_t size;
X{
X  _io_assert(_io_valid(stream));
X  _io_assert(type == _IONBF || size != 0);
X  _io_assert(stream->_io_count == _IO_NEVER);
X
X  fflush(stream);
X  _buffree(stream);
X  _io_clearflag(stream, (_IO_LBUF | _IO_MYBUF));
X  switch (type) {
X	case _IONBF:
X		stream->_io_bufsiz = 0;
X		stream->_io_buf = NULL;
X		stream->_io._io_char = EOF;
X		stream->_io_count = _IO_NEVER;
X		return 0;
X	case _IOLBF:
X	case _IOFBF:
X		stream->_io_bufsiz = size;
X		stream->_io._io_ptr = stream->_io_buf = (unsigned char *) buffer;
X		stream->_io_count = _IO_NEVER;
X		_io_setflag(stream, type);
X		return 0;
X	default:
X		return _IO_ERRVAL;
X  }
X}
X
X
Xvoid setbuf(stream, buffer)	/* ANSI requires function definition */
XFILE *stream;			/* (even if the default is a macro)  */
Xchar *buffer;
X{
X  (void) setvbuf(stream, buffer, (buffer == NULL) ? _IONBF : _IOFBF, BUFSIZ);
X}
/
echo x - sprintf.c
sed '/^X/s///' > sprintf.c << '/'
X/* --- sprintf.c --- */
X/* Formatted printing functions for strings */
X/* Notes:  Includes sprintf() and vsprintf()	*/
X/*	   Both are front ends for _doprnt()	*/
X
X#include 
X#include 
X#include 
X#include "stdiolib.h"
X#undef sprintf
X#undef vsprintf
X
X#define _IO_ERRVAL 0
X
X
Xint sprintf(s, format /*, ... */)
Xchar *s;
Xconst char *format;
X{
X  FILE fake;
X  va_list arg;
X  int n;
X
X  _io_assert(s);
X  _io_assert(format);
X
X  fake._io_fd = -1;
X  fake._io_flags = _IO_WRITE | _IO_STRING;
X  fake._io_bufsiz = fake._io_count = INT_MAX;
X  fake._io._io_ptr = fake._io_buf = (unsigned char *) s;
X  va_start(arg, format);
X  n = _doprnt(&fake, format, arg);
X  putc('\0', &fake);
X  va_end(arg);
X  return n;
X}
X
Xint vsprintf(s, format, arg)
Xchar *s;
Xconst char *format;
Xva_list arg;
X{
X  FILE fake;
X  int n;
X
X  _io_assert(s);
X  _io_assert(format);
X
X  fake._io_fd = -1;
X  fake._io_flags = _IO_WRITE | _IO_STRING;
X  fake._io_bufsiz = fake._io_count = INT_MAX;
X  fake._io._io_ptr = fake._io_buf = (unsigned char *) s;
X  n = _doprnt(&fake, format, arg);
X  putc('\0', &fake);
X  return n;
X}
/
echo x - sscanf.c
sed '/^X/s///' > sscanf.c << '/'
X/* --- sscanf.c --- */
X/* Formatted input function for strings */
X/* Notes:  Front end for _doscan()	*/
X
X#include 
X#include 
X#include "stdiolib.h"
X#undef sscanf
X
X#define _IO_ERRVAL EOF
X
Xint sscanf(s, format /*, ... */)
Xconst char *s;
Xconst char *format;
X{
X  va_list arg;
X  int n;
X
X  _io_assert(s);
X  _io_assert(format);
X
X  va_start(arg, format);
X  n = _doscan(1, (void *) s, format, arg);
X  va_end(arg);
X  return n;
X}
/
echo x - stdio_misc.c
sed '/^X/s///' > stdio_misc.c << '/'
X/* --- stdio_misc.c --- */
X/* Miscellaneous stream functions */
X/* Notes:  Includes clearerr(), feof(), ferror(), and (POSIX) fileno()	*/
X/*	   All functions backstop macros in 			*/
X
X#include 
X#include "stdiolib.h"
X#undef clearerr
X#undef feof
X#undef ferror
X#undef fileno
X
X#define _IO_ERRVAL EOF
X
Xvoid clearerr(stream)
XFILE *stream;
X{
X  _io_assert(_io_valid(stream));
X  _io_clearflag(stream, (_IO_EOF | _IO_ERR));
X}
X
Xint feof(stream)
XFILE *stream;
X{
X  _io_assert(_io_valid(stream));
X  return _io_testflag(stream, _IO_EOF);
X}
X
Xint ferror(stream)
XFILE *stream;
X{
X  _io_assert(_io_valid(stream));
X  return _io_testflag(stream, _IO_ERR);
X}
X
Xint fileno(stream)		/* Posix */
XFILE *stream;
X{
X  _io_assert(_io_valid(stream));
X  return stream->_io_fd;
X}
/
echo x - tmpfile.c
sed '/^X/s///' > tmpfile.c << '/'
X/* --- tmpfile.c --- */
X/* Opens a temporary file which will be deleted on close or exit */
X/* Notes:  Also includes two cleanup routines:				*/
X/*	   _tmp_cleanup - registered with atexit() if tmpfile() is used */
X/*	   _tmp_remove  - removes one temporary file			*/
X
X#include 
X#include 
X#include 
X#include 
X#include "stdiolib.h"
X#undef tmpfile
X
Xstatic void _tmp_cleanup();
Xstatic int _tmp_remove();
X
Xextern int (*__tmprm)();
Xstatic char* tmp_name[FOPEN_MAX];
X
XFILE *tmpfile()
X{
X  register char *name;
X  register FILE *stream;
X
X  if ((name = (char *) malloc(L_tmpnam)) == NULL)
X	return NULL;
X
X  (void) tmpnam(name);
X  if (stream = fopen(name, "w+b")) {
X	_io_setflag(stream, _IO_TEMP);
X	tmp_name[_iobindex(stream)] = name;
X	if (!__tmprm) {
X		__tmprm = _tmp_remove;
X		atexit(_tmp_cleanup);
X	}
X  } else {
X	free(name);
X  }
X  return stream;
X}
X
Xstatic void _tmp_cleanup()
X{
X  register int i;
X
X  for (i = 0; i < FOPEN_MAX; i++)
X	_tmp_remove(i);
X}
X
Xstatic int _tmp_remove(i)
Xregister int i;
X{
X  int rc = -1;
X
X  if (tmp_name[i]) {
X	rc = unlink(tmp_name[i]);
X	free(tmp_name[i]);
X	tmp_name[i] = NULL;
X  }
X  return rc;
X}
/
echo x - tmpnam.c
sed '/^X/s///' > tmpnam.c << '/'
X/* --- tmpnam.c --- */
X/* Generates a unique file name */
X/* Notes:  File name is of the form Tmpxxxxx.yyyyy	*/
X/*	   Not reentrant				*/
X
X#include 
X#include 
X#include 
X#include 
X#include "stdiolib.h"
X#undef tmpnam
X
X#define DIGITS	5		/* maximum digits converted */
X
Xchar *tmpnam(s)
Xchar *s;
X{
X  static char buf[L_tmpnam];
X  static int pid = 0;
X  static int suffix = 1;
X  int length;
X  register int width;
X  register char *p;
X  int k;
X
X  if (s == NULL)
X	s = buf;
X  if (suffix >= TMP_MAX) {
X	*s = '\0';
X	return NULL;
X  }
X  if (pid == 0)
X	pid = getpid();
X
X  strcpy(s, P_tmpdir);
X  strcat(s, "/Tmp00000.00000");
X  length = strlen(s);
X  p = s + (length - 1 - DIGITS - 1);	/* pid ends here */
X  width = DIGITS;
X  k = pid;
X  do {
X	*p-- = k % 10 + '0';
X  } while ((k /= 10) && (--width > 0));
X  p = s + (length - 1);			/* suffix ends here */
X  width = DIGITS;
X  k = suffix++;
X  do {
X	*p-- = k % 10 + '0';
X  } while ((k /= 10) && (--width > 0));
X  return s;
X}
/
echo x - ungetc.c
sed '/^X/s///' > ungetc.c << '/'
X/* --- ungetc.c --- */
X/* Pushes one character back into an input stream */
X/* Notes:  Will not push back EOF					*/
X/*	   Can fail if tried too many times				*/
X
X#include 
X#include "stdiolib.h"
X#undef ungetc
X
X#define _IO_ERRVAL EOF
X
Xint ungetc(c, stream)
Xregister int c;
Xregister FILE *stream;
X{
X  _io_assert(_io_valid(stream));
X  _io_assert(!_io_testflag(stream, _IO_WRITE));
X
X  if (c == EOF || stream->_io_count == _IO_NEVER)
X	return _IO_ERRVAL;
X
X  if (stream->_io_bufsiz == 0) {
X	if (stream->_io._io_char == EOF) {
X		stream->_io._io_char = c;
X		_io_clearflag(stream, _IO_EOF);
X	} else {
X		c = _IO_ERRVAL;
X	}
X  } else {
X	if (stream->_io._io_ptr != stream->_io_buf) {
X		stream->_io_count++;
X		*--stream->_io._io_ptr = c;
X		_io_clearflag(stream, _IO_EOF);
X	} else {
X		c = _IO_ERRVAL;
X	}
X  }
X  return c;
X}
/