#!/bin/sh
# This is a shar archive.
# The rest of this file is a shell script which will extract:
#
# FILE.c FILE2.c FILE3.c clearerr.c doprint.c doscan.c extbuf.h fclose.c feof.c ferror.c fflush.c fgetc.c fgets.c fopen.c fprintf.c fputc.c fputs.c fread.c freopen.c fscanf.c fwrite.c getc.c getchar.c gets.c makefile nstdio.h printf.c putc.c putchar.c puts.c scanf.c scanset.h scanset1.c setbuf.c sprintf.c sscanf.c stdin.c tst.c tst.cmp tst.ecmp tst.err tst.in ungetc.c vfprintf.c vfscanf.c vprintf.c vscanf.c vsprintf.c vsscanf.c ~FILE.c
#
# To extract the files from this shell archive file simply
# create a directory for this file, move the archive file
# to it and enter the command
#
#	sh filename
# 
# The files will be extracted automatically.
# Note: Do not use csh.
#
# Archive created: Mon Jul 30 23:13:02 EDT 1990
#
echo x - FILE.c
sed 's/^X//' > FILE.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// create a FILE using the given buffer and mode
FILE::FILE(streambuf *st, open_mode m)
{
    sb = st;
    mode = m;

    // create the appropriate stream
    if (mode == input)
	in = new istream(sb);

    else
	out = new ostream(sb);
}
!EOF!
ls -l FILE.c
echo x - FILE2.c
sed 's/^X//' > FILE2.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
FILE::FILE(istream *is)
{
    mode = input;
    in = is;
    sb = 0;
}
!EOF!
ls -l FILE2.c
echo x - FILE3.c
sed 's/^X//' > FILE3.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
FILE::FILE(ostream *os)
{
    mode = output;
    out = os;
    sb = 0;
}
!EOF!
ls -l FILE3.c
echo x - clearerr.c
sed 's/^X//' > clearerr.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// clear out any error indications
void clearerr(FILE *f)
{
    if (f->mode == input)
	f->in->clear();

    else
	f->out->clear();
}
!EOF!
ls -l clearerr.c
echo x - doprint.c
sed 's/^X//' > doprint.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// _doprint(): low level function for doing
// formatted output, to be invoked by the
// v*printf() family of functions
#include <string.h>

// endchar() returns TRUE for those format
// characters which cause output.
int endchar(char c)
{
    switch (c)
	{
	case 'd': case 'i': case 'o': case 'u':
	case 'x': case 'X': case 'f': case 'e':
	case 'E': case 'g': case 'G': case 'c':
	case 's': case 'p': case 'n': case '%':
	case 0:
	    return 1;

	default:
	    return 0;
	}
}

int _doprint(ostream *out, const char *fmt, va_list vl)
{
    if (!fmt)
	return EOF;

    char *cfmt = new char[strlen(fmt)+1];

    while (*fmt)
	{
	char *buf = cfmt;
	int asterisks = 0;
	int shortarg = 0;
	int longarg = 0;
	char c;

	// loop looking for the beginning of a format
	while ((c = *buf++ = *fmt++) && (c != '%'))
	    ;

	// loop looking for the end of the format
	if (c)
	    while (!endchar(c = *buf++ = *fmt++))
		if (c == '*')		asterisks++;
		else if (c == 'h')	shortarg++;
		else if (c == 'l')	longarg++;

	// polish off the buffer. leave fmt
	// pointing at the null if just past it.
	*buf = '\0';
	if (!c)
	    fmt--;

	// pull off the width and precision
	int prec = 0, width = 0;
	switch (asterisks)
	    {
	    case 0: break;
	    case 2: width = va_arg(vl, int); // NO BREAK
	    case 1: prec  = va_arg(vl, int); break;
	    }

// Declare a generic output routine for the type passed
// on the stack and the type used for output. This
// cannot be an inline since the parameters are types.
#define OUTPUT(parmtype, outtype)			\
    do {						\
    outtype val = va_arg(vl, parmtype);			\
    switch (asterisks)					\
	{						\
	case 0: 					\
	    (*out) << form(cfmt, val); break;		\
	case 1:						\
	    (*out) << form(cfmt, prec, val); break;	\
	case 2:						\
	    (*out) << form(cfmt,width,prec,val);break;	\
	}						\
    } while (0)

	// extract the value and output it
	switch (c)
	    {
	    // decimal variables
	    case 'd': case 'i':
		if (longarg)
		    OUTPUT(long, long);

		else if (shortarg)
		    OUTPUT(short, int);

		else
		    OUTPUT(int, int);
		break;

	    // unsigned decimal variables
	    case 'o': case 'u': case 'x': case 'X':
		if (longarg)
		    OUTPUT(unsigned long, unsigned long);

		else if (shortarg)
		    OUTPUT(unsigned short, unsigned int);

		else
		    OUTPUT(unsigned int, unsigned int);
		break;

	    // double variables
	    case 'f': case 'e': case 'E':
	    case 'g': case 'G':
		OUTPUT(double, double);
		break;

	    // character variables
	    case 'c':
		OUTPUT(unsigned char, int);
		break;

	    // string variable
	    case 's':
		OUTPUT(char*, char*);
		break;

	    // nothing much here
	    case '%': case 0:
		(*out) << form(cfmt);
		break;
	    }
	}

    delete cfmt;
    return 1;
}
!EOF!
ls -l doprint.c
echo x - doscan.c
sed 's/^X//' > doscan.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// _doscanf(): low level function for doing formatted
// input, to be invoked by the v*scanf() family
// of functions.
#include <extbuf.h>
#include <scanset.h>
#include <ctype.h>
#include <stdlib.h>

// get the next character on the input stream,
// adding to charcnt and returning EOF on end-of-file.
inline int nextc(istream *in, int &charcnt)
{
    char c;
    return (!in->get(c)) ?
	EOF :
	(charcnt++, c);
}

/* Define a macro to decrement the fieldwidth	*/
/* and add the character to the buffer.		*/
#define addc()					\
    fieldwidth--, svbuf.add(c)

/* Define a macro to decrement the fieldwidth,	*/
/* add the character to the buffer and get the	*/
/* next character.				*/
#define Nextc()					\
    do { addc(); c = nextc(in, charcnt); } while (0)

/* Define macros to use for assigning the	*/
/* appropriate value to the appropriate pointer	*/
/* type to be pulled off the stack based on the	*/
/* booleans halfsize, longsize and suppress.	*/
/* assign() checks for halfsize, then invokes	*/
/* liassign() below.				*/
#define assign(var, stype, itype, ltype)	\
    if (halfsize)				\
	{					\
	stype *p = va_arg(vl, stype*);		\
	*p = (stype)var;			\
	}					\
						\
    else					\
	liassign(var, itype, ltype)

/* This macro is invoked from assign() above	*/
/* and for %f, which doesn't allow the halfsized*/
/* modifier. It checks for the booleans longsize*/
/* and suppress.				*/
#define liassign(var, itype, ltype)		\
    if (longsize)				\
	{					\
	ltype *p = va_arg(vl, ltype*);		\
	*p = (ltype)var;			\
	}					\
						\
    else if (!suppress)				\
	{					\
	itype *p = va_arg(vl, itype*);		\
	*p = (itype)var;			\
	}

/* define a macro to check for an optional sign	*/
#define checksign()				\
    if ((fieldwidth > 0) &&			\
	((c == '-') || (c == '+')))		\
	{					\
	Nextc();				\
	}

/* This macro will check for one or more	*/
/* characters which have a certain 		*/
/* characteristic checked by the testprog, such */
/* as isdigit. If the sequence is missing, it	*/
/* is an error and the macro will break out of	*/
/* the switch statement.			*/
#define checkfield(testprog)			\
    if ((fieldwidth > 0) && testprog(c))	\
	do  {					\
	    addc();				\
	} while ((fieldwidth > 0) &&		\
	    testprog(c = nextc(in, charcnt)));	\
						\
    else					\
	{					\
	goodformat = 0;				\
	break;					\
	}

/* This macro works just like checkfield()	*/
/* except that it is not an error for the	*/
/* sequence to be missing.			*/
#define checkoptfield(testprog)			\
    for ( ; (fieldwidth > 0) && testprog(c);	\
	  c = nextc(in, charcnt))		\
	{					\
	    addc();				\
	}

// the input function
int _doscanf(istream *in, const char *fmt, va_list vl)
{
    if (!fmt)
	return EOF;

    int charcnt = 0;
    int fieldcnt = EOF;
    int goodformat = 1;
    int c = nextc(in, charcnt);
    extarray svbuf;

    // loop through the format string
    while (*fmt && (c != EOF) && goodformat)
	{
	switch (*fmt++)
	    {
	    // format specification
	    case '%':
		{
		// '*' means suppress assignment
		int suppress = 0;
		if (*fmt == '*')
		    {
		    suppress = 1;
		    fmt++;
		    }

		// check for a fieldwidth
		int fieldwidth = -1;
		if (isdigit(*fmt))
		    fieldwidth =
			(int)strtol(fmt, (char**)&fmt, 10);

		// Check for size modifiers.
		// Just skip past if assignment
		// is being suppressed.
		int halfsize = 0;
		int longsize = 0;
		switch (*fmt)
		    {
		    case 'h':
			if (!suppress)
			    halfsize = 1;
			fmt++;
			break;

		    case 'l':
			if (!suppress)
			    longsize = 1;
			fmt++;
			break;
		    }

		// set the default field width
		if (fieldwidth == -1)
		    fieldwidth = (*fmt == 'c') ?
				 1 : INT_MAX;

		// check for skipping white space
		switch (*fmt)
		    { // these do not skip white space
		    case '%': case 'n':
		    case '[': case 'c':
			break;

		    default:
			// loop until a non-white-space
			// character is found
			if (isspace(c))
			    do  {
				c = nextc(in, charcnt);
			    } while (isspace(c));
			break;
		    }

		// only return EOF if an error
		// occurred before the first
		// field specifier is reached
		if (fieldcnt == EOF)
		    fieldcnt = 0;

		svbuf.reset();

		// check for assignment type
		switch (*fmt)
		    {
		    // store the number of read chars
		    case 'n':
			assign(charcnt, short, int, long);
			break;

		    // fill svbuf with an integer
		    // or an unsigned integer
		    case 'd':
		    case 'u':
			{
			checksign();
			checkfield(isdigit);

			/* assign to a signed number */
			if (*fmt == 'd')
			    {
			    long i =
				strtol(svbuf.val(),
				    0, 10);
			    assign(i, short, int, long);
			    }

			/* assign to an unsigned number */
			else
			    {
			    unsigned long i =
				strtoul(svbuf.val(),
					0, 10);
			    assign(i, unsigned short,
				unsigned int,
				unsigned long);
			    }

			fieldcnt++;
			break;
			}

		    // fill svbuf with a C++ integer
		    case 'i':
			{
			checksign();

			// check for leading 0 or 0x
			if ((fieldwidth > 0) &&
			    (c == '0'))
			    {
			    Nextc();

			    if ((fieldwidth > 0) &&
				((c == 'x') ||
				 (c == 'X')))
				{
				Nextc();
				checkfield(isxdigit);
				}

			    else
				checkfield(isodigit);
			    }

			else
			    checkfield(isdigit);

			long i =
			    strtol(svbuf.val(), 0, 0);
			assign(i, short, int, long);
			fieldcnt++;
			break;
			}

		    // fill svbuf with an octal integer
		    case 'o':
			{
			checksign();
			checkfield(isodigit);

			unsigned long i =
			    strtoul(svbuf.val(), 0, 8);
			assign(i, unsigned short,
			    unsigned int, unsigned long);
			fieldcnt++;
			break;
			}

		    // fill svbuf with a hex integer
		    case 'x': case 'X':
			{
			checksign();
			checkfield(isxdigit);

			unsigned long i =
			    strtoul(svbuf.val(), 0, 16);
			assign(i, unsigned short,
			    unsigned int, unsigned long);
			fieldcnt++;
			break;
			}

		    // Read in a floating point number
		    case 'e': case 'E':
		    case 'g': case 'G':
		    case 'f':
			{
			checksign();
			checkoptfield(isdigit);

			if ((fieldwidth > 0) &&
			    (c == '.'))
			    {
			    Nextc();
			    checkoptfield(isdigit);
			    }

			if ((fieldwidth > 0) &&
			    ((c == 'e') || (c == 'E')))
			    {
			    Nextc();
			    checksign();
			    checkfield(isdigit);
			    }

			double i =
			    strtod(svbuf.val(), 0);
			liassign(i, float, double);
			fieldcnt++;
			break;
			}

		    // Read up to fieldwidth characters
		    // (minimum of 1) which match the
		    // scanset. Add a null character at
		    // the end of the string.
		    case '[':
			{
			char *p;
			if (c == EOF)
			    break;
			if (!suppress)
			    p = va_arg(vl, char*);

			scanset s(fmt, &fmt);
			for ( ; (fieldwidth-- > 0) &&
				s.match(c) ;
			      c = nextc(in, charcnt))
				if (!suppress)
				    *p++ = c;

			if (!suppress)
			    *p = '\0';
			fieldcnt++;
			break;
			}

		    // Read fieldwidth characters.
		    // Do NOT add a null character after.
		    case 'c':
			{
			char *p;
			if (c == EOF)
			    break;
			if (!suppress)
			    p = va_arg(vl, char*);

			for ( ; (fieldwidth-- > 0) &&
				(c != EOF) ;
			      c = nextc(in, charcnt))
			    if (!suppress)
				*p++ = c;

			fieldcnt++;
			break;
			}

		    // Read a string terminated by
		    // white-space. Add a null character
		    // at the end of the string.
		    case 's':
			{
			char *p;
			if (c == EOF)
			    break;
			if (!suppress)
			    p = va_arg(vl, char*);

			for ( ; (fieldwidth-- > 0) &&
				!isspace(c) ;
			      c = nextc(in, charcnt))
			    if (!suppress)
				*p++ = c;

			if (!suppress)
			    *p = '\0';
			fieldcnt++;
			break;
			}

		    // match a single %
		    case '%':
			if (c == '%')
			    c = nextc(in, charcnt);

			else
			    goodformat = 0;
			break;
		    }
		break;
		}

	    case ' ': // match white-space
	    case '\t': // match white-space
		if (isspace(c))
		    do  {
			svbuf.add(c);
		    } while
			(isspace(c = nextc(in, charcnt)));

		else
		    goodformat = 0;
		break;

	    default: // match character
		if (c == fmt[-1])
		    c = nextc(in, charcnt);

		else
		    goodformat = 0;
		break;
	    }
	}

    if (c != EOF)
	in->putback(c);
    return fieldcnt;
}
!EOF!
ls -l doscan.c
echo x - extbuf.h
sed 's/^X//' > extbuf.h << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// class "extensible array"
// This class maintains a character array
// which dynamically lengthens. The array
// begins with a fixed size allocated statically,
// but goes into the heap when the bounds
// of that array are exceeded.
#include <string.h>

const int extstartsize = 50;	// initial size of buffer

class extarray
{
    char buf[extstartsize];	// starting buffer
    char *base;			// ptr to current buffer
    char *end;			// end of current buffer
    char *p;			// current location
    int cursize;		// size of current buffer

public:
    // Initialize the pointers
    // and the static array.
    extarray()
	{
	base = p = buf;
	end = base + extstartsize;
	cursize = extstartsize;
	}

    // If there is a dynamic
    // array, delete it.
    ~extarray()
	{
	if (base != buf)
	    delete base;
	}

    // Add a character to the array.
    // If it won't fit (along with
    // the null byte) lengthen the
    // array, going into heap memory
    // when necessary.
    void add(char c)
	{
	*p++ = c;

	if (p == end)
	    {
	    char *svp = p;
	    char *svbase = base;
	    base = new char[cursize + extstartsize];
	    memcpy(base, svbase, cursize);
	    cursize += extstartsize;
	    end = base + cursize;
	    p = base + (svp - svbase);

	    if (svbase != buf)
		delete svbase;
	    }
	}

    // return the current value
    char *val()
        {
	*p = '\0';
	return base;
	}

    // Reset the current pointer to the 
    // beginning of the array so that it
    // can be reused.
    void reset()
	{
	p = base;
	}
};
!EOF!
ls -l extbuf.h
echo x - fclose.c
sed 's/^X//' > fclose.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// close the file
int fclose(FILE *f)
{
    delete f->sb;
    delete f;
    return 0;
}
!EOF!
ls -l fclose.c
echo x - feof.c
sed 's/^X//' > feof.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// return TRUE if at the end of file
int feof(FILE *f)
{
    if (f->mode == input)
	return f->in->eof();

    else
	return f->out->eof();
}
!EOF!
ls -l feof.c
echo x - ferror.c
sed 's/^X//' > ferror.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// return TRUE if an error condition exists
int ferror(FILE *f)
{
    if (f->mode == input)
	return !f->in->good();

    else
	return !f->out->good();
}
!EOF!
ls -l ferror.c
echo x - fflush.c
sed 's/^X//' > fflush.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// flush out the stream
int fflush(FILE *f)
{
    if (f->mode != input)
	f->out->flush();
    return ferror(f) ? EOF : 0;
}
!EOF!
ls -l fflush.c
echo x - fgetc.c
sed 's/^X//' > fgetc.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// Read in a single character
int fgetc(FILE *f)
{
    return getc(f);
}
!EOF!
ls -l fgetc.c
echo x - fgets.c
sed 's/^X//' > fgets.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// read a string up to and including a newline
#include <string.h>
char *fgets(char *buf, int length, FILE *f)
{
    if ((f->mode == input) &&
	(f->in->get(buf, length-2)))
	{
	char c = 0;
	f->in->get(c);
	if (c == '\n')
	    {
	    char *nl = buf + strlen(buf);
	    *nl++ = '\n';
	    *nl = 0;
	    }
	return buf;
	}

    return NULL;
}
!EOF!
ls -l fgets.c
echo x - fopen.c
sed 's/^X//' > fopen.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// Open a named file.
// The mode can be "r", "w" or "a"
FILE *fopen(const char *file, const char *fmode)
{
    // set the modes up
    open_mode m = (*fmode == 'w') ? output :
		  (*fmode == 'a') ? append :
				    input;

    // open the file
    filebuf *st = new filebuf;
    st->open((char*)file, m);

    return new FILE(st, m);
}
!EOF!
ls -l fopen.c
echo x - fprintf.c
sed 's/^X//' > fprintf.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// write the arguments in a formatted manner
#include <stdarg.h>
int fprintf(FILE *f, const char *fmt, ...)
{
    if (f->mode != input)
	{
	va_list ap;
	va_start(ap, fmt);
	int ret = vfprintf(f, fmt, ap);
	va_end(ap);
	return ret;
	}

    return EOF;
}
!EOF!
ls -l fprintf.c
echo x - fputc.c
sed 's/^X//' > fputc.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// output a character
int fputc(int c, FILE *f)
{
    return putc(c, f);
}
!EOF!
ls -l fputc.c
echo x - fputs.c
sed 's/^X//' > fputs.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// write a string
int fputs(const char *buf, FILE *f)
{
    if (f->mode != input)
	(*f->out) << buf;
    return ferror(stdout) ? EOF : 0;
}
!EOF!
ls -l fputs.c
echo x - fread.c
sed 's/^X//' > fread.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// read in num objects of the given size into the buffer
int fread(void *vbuf, unsigned int size,
    unsigned int num, FILE *f)
{
    char *buf = (char*)vbuf;
    if (f->mode == input)
	{
	// read in num * size bytes
	for (unsigned int n = num; n-- > 0; )
	    for (unsigned int s = size; s-- > 0; )
		{
		char c;
		if (f->in->get(c))
		    *buf++ = c;

		else
		    // The end of the input
		    // partway through an object.
		    // Return the number of complete
		    // objects read so far.
		    return num - n;
		}

	// Return the number of
	// complete objects read.
	return num - n;
	}

    return 0;
}
!EOF!
ls -l fread.c
echo x - freopen.c
sed 's/^X//' > freopen.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// Open a named file on a stdio
// stream which is already active.
FILE *freopen(const char *file,
    const char *fmode, FILE *f)
{
    open_mode svmode = f->mode;

    // set the modes up
    open_mode m = (*fmode == 'w') ? output :
		  (*fmode == 'a') ? append :
				    input;

    // close the old stream
    if (svmode == input) delete f->in;
    else delete f->out;
    delete f->sb;

    // open the file
    delete f->sb;
    filebuf *nsb = new filebuf;
    nsb->open((char*)file, m);
    f->sb = nsb;

    // create the appropriate new stream
    if (f->mode == input)
	f->in = new istream(f->sb);

    else
	f->out = new ostream(f->sb);

    return f;
}
!EOF!
ls -l freopen.c
echo x - fscanf.c
sed 's/^X//' > fscanf.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// read a set of arguments from a file
int fscanf(FILE *f, const char *fmt, ...)
{
    if (f->mode == input)
	{
	va_list ap;
	va_start(ap, fmt);
	int ret = vfscanf(f, fmt, ap);
	va_end(ap);
	return ret;
	}

    return EOF;
}
!EOF!
ls -l fscanf.c
echo x - fwrite.c
sed 's/^X//' > fwrite.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// write out num objects of the given
// size from the named buffer
int fwrite(void *vbuf, unsigned int size,
    unsigned int num, FILE *f)
{
    char *buf = (char*)vbuf;
    if (f->mode != input)
	{
	// read in num * size bytes
	for (unsigned int n = num; n-- > 0; )
	    for (unsigned int s = size; s-- > 0; )
		if (!f->out->put(*buf++))
		    // The end of the output
		    // partway through an object.
		    // Return the number of complete
		    // objects written so far.
		    return num - n;

	// Return the number of
	// complete objects written
	return num - n;
	}

    return 0;
}
!EOF!
ls -l fwrite.c
echo x - getc.c
sed 's/^X//' > getc.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// Read in a single character
// inline
int getc(FILE *f)
{
    unsigned char c;
    if ((f->mode == input) &&
        f->in->get(c))
	return c;

    else
	return EOF;
}
!EOF!
ls -l getc.c
echo x - getchar.c
sed 's/^X//' > getchar.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// get a character from stdin
inline int getchar()
{
    return getc(stdin);
}
!EOF!
ls -l getchar.c
echo x - gets.c
sed 's/^X//' > gets.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// read a string up to a newline, discarding the newline
#include <limits.h>
char *gets(char *buf)
{
    if ((stdin->mode == input) &&
	stdin->in->get(buf, INT_MAX))
	    {
	    char c;
	    stdin->in->get(c);
	    return buf;
	    }

    return NULL;
}
!EOF!
ls -l gets.c
echo x - makefile
sed 's/^X//' > makefile << '!EOF!'
CC= CC -I. -I../../CC
CFLAGS= +i -g

all: tst

tst: extbuf.h nstdio.h scanset.h FILE.c FILE2.c FILE3.c clearerr.c doprint.c doscan.c fclose.c feof.c ferror.c fflush.c fgetc.c fgets.c fopen.c fprintf.c fputc.c fputs.c fread.c freopen.c fscanf.c fwrite.c getc.c getchar.c gets.c printf.c putc.c putchar.c puts.c scanf.c scanset1.c setbuf.c sprintf.c sscanf.c stdin.c sv_8_5.c tst.c ungetc.c vfprintf.c vfscanf.c vprintf.c vscanf.c vsprintf.c vsscanf.c ~FILE.c
	$(CC) $(CFLAGS) tst.c -o tst

OUT= tst.out
CMP= tst.cmp tst.ecmp

tst.out: tst ; tst < tst.in > tst.out 2> tst.err

test: all $(OUT) $(CMP)
	cmp tst.out tst.cmp
	cmp tst.err tst.ecmp
	cmp /etc/termcap /tmp/foo.out
	@echo test done
!EOF!
ls -l makefile
echo x - nstdio.h
sed 's/^X//' > nstdio.h << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// Exercise 8.5
// <stdio.h>
// Implementation of standard I/O
// using the stream I/O functions.
#ifndef STDIO_H
#define STDIO_H
#include <stream.h>
#include <stdarg.h>
#undef FILE			/* DELETE */
#undef _bufend			/* DELETE */
#undef _bufsiz			/* DELETE */
#undef getc			/* DELETE */
#undef putc			/* DELETE */
#undef getchar			/* DELETE */
#undef putchar			/* DELETE */
#undef clearerr			/* DELETE */
#undef feof			/* DELETE */
#undef ferror			/* DELETE */
#undef fileno			/* DELETE */
#undef EOF			/* DELETE */
#undef NULL			/* DELETE */
#undef BUFSIZ			/* DELETE */
#undef stdin			/* DELETE */
#undef stdout			/* DELETE */
#undef stderr			/* DELETE */
#undef L_ctermid		/* DELETE */
#undef L_cuserid		/* DELETE */
#undef P_tmpdir			/* DELETE */
#undef L_tmpnam			/* DELETE */
#undef _NFILE			/* DELETE */
#undef _SBFSIZ			/* DELETE */
#undef _IOFBF			/* DELETE */
#undef _IOREAD			/* DELETE */
#undef _IOWRT			/* DELETE */
#undef _IONBF			/* DELETE */
#undef _IOMYBUF			/* DELETE */
#undef _IOEOF			/* DELETE */
#undef _IOERR			/* DELETE */
#undef _IOLBF			/* DELETE */
#undef _IORW			/* DELETE */
#define FILE xFILE		/* DELETE */
#define BUFSIZ xBUFSIZ		/* DELETE */
#define EOF xEOF		/* DELETE */
#define clearerr xclearerr	/* DELETE */
#define fclose xfclose		/* DELETE */
#define feof xfeof		/* DELETE */
#define ferror xferror		/* DELETE */
#define fflush xfflush		/* DELETE */
#define fgetc xfgetc		/* DELETE */
#define fgets xfgets		/* DELETE */
#define fileno xfileno		/* DELETE */
#define fopen xfopen		/* DELETE */
#define fprintf xfprintf	/* DELETE */
#define fputc xfputc		/* DELETE */
#define fputs xfputs		/* DELETE */
#define fread xfread		/* DELETE */
#define freopen xfreopen	/* DELETE */
#define fscanf xfscanf		/* DELETE */
#define fwrite xfwrite		/* DELETE */
#define getc xgetc		/* DELETE */
#define getchar xgetchar	/* DELETE */
#define gets xgets		/* DELETE */
#define printf xprintf		/* DELETE */
#define putc xputc		/* DELETE */
#define putchar xputchar	/* DELETE */
#define scanf xscanf		/* DELETE */
#define setbuf xsetbuf		/* DELETE */
#define sprintf xsprintf	/* DELETE */
#define sscanf xsscanf		/* DELETE */
#define stderr xstderr		/* DELETE */
#define stdin xstdin		/* DELETE */
#define stdout xstdout		/* DELETE */
#define ungetc xungetc		/* DELETE */
#define vfprintf xvfprintf	/* DELETE */
#define vfscanf xvfscanf	/* DELETE */
#define vprintf xvprintf	/* DELETE */
#define vscanf xvscanf		/* DELETE */
#define vsprintf xvsprintf	/* DELETE */
#define vsscanf xvsscanf	/* DELETE */

class FILE
{
    open_mode mode;
    union
	{
	istream *in;
	ostream *out;
	};
    streambuf *sb;
    char unbuf;

public:
    FILE(streambuf *st, open_mode m);
    FILE(istream *is);
    FILE(ostream *os);
    ~FILE();

    // open and close FILEs
    friend FILE *fopen(const char *file,
	const char *mode);
    friend FILE *freopen(const char *file,
	const char *mode, FILE *f);
    friend int fclose(FILE *);

    // input functions
    friend int getc(FILE *);
    friend int ungetc(int const, FILE *);
    friend int fgetc(FILE *);
    friend int getchar();
    friend char *gets(char *buf);
    friend char *fgets(char *buf, int sz, FILE *);
    friend int fread(void *buf, unsigned int sz,
	unsigned int n, FILE *);
    friend int scanf(const char *fmt, ...);
    friend int fscanf(FILE *, const char *fmt, ...);
    friend int sscanf(const char *buf,
	const char *fmt, ...);
    friend int vscanf(const char *fmt, va_list vl);
    friend int vfscanf(FILE *f,
	const char *fmt, va_list vl);
    friend int vsscanf(const char *str,
	const char *fmt, va_list vl);

    // output functions
    friend int putc(int c, FILE *);
    friend int putchar(int c);
    friend int fputc(int c, FILE *);
    friend int puts(const char *buf);
    friend int fputs(const char *buf, FILE *);
    friend int fwrite(void *buf, unsigned int sz,
	unsigned int n, FILE *);
    friend int printf(const char *fmt, ...);
    friend int fprintf(FILE *, const char *fmt, ...);
    friend int sprintf(char *buf, const char *fmt, ...);
    friend int vprintf(const char *fmt, va_list);
    friend int vfprintf(FILE *,
	const char *fmt, va_list);
    friend int vsprintf(char *buf,
	const char *fmt, va_list);

    // status manipulation and checking
    friend int ferror(FILE *);
    friend int feof(FILE *);
    friend void clearerr(FILE *);

    // buffering manipulation
    friend void setbuf(FILE *, char *);
    friend int fflush(FILE *);
};

#define NULL 0
const int EOF = -1;
const int BUFSIZ = 1024;
extern FILE *stdin, *stdout, *stderr;
#endif /* STDIO_H */
!EOF!
ls -l nstdio.h
echo x - printf.c
sed 's/^X//' > printf.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// write the arguments in a formatted manner to stdout
#include <stdarg.h>
int printf(const char *fmt, ...)
{
    if (stdout->mode != input)
	{
	va_list ap;
	va_start(ap, fmt);
	int ret = vprintf(fmt, ap);
	va_end(ap);
	return ret;
	}

    return EOF;
}
!EOF!
ls -l printf.c
echo x - putc.c
sed 's/^X//' > putc.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// output a character
// inline
int putc(int c, FILE *f)
{
    if (f->mode != input)
	f->out->put(c);

    return c;
}
!EOF!
ls -l putc.c
echo x - putchar.c
sed 's/^X//' > putchar.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// output a character to stdout
// inline
int putchar(int c)
{
    return putc(c, stdout);
}
!EOF!
ls -l putchar.c
echo x - puts.c
sed 's/^X//' > puts.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// write a string to stdout, adding a newline
int puts(const char *buf)
{
    if (stdout->mode != input)
	(*stdout->out) << buf << "\n";

    return ferror(stdout) ? EOF : 0;
}
!EOF!
ls -l puts.c
echo x - scanf.c
sed 's/^X//' > scanf.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// read a set of arguments from stdin
int scanf(const char *fmt, ...)
{
    if (stdin->mode == input)
	{
	va_list ap;
	va_start(ap, fmt);
	int ret = vscanf(fmt, ap);
	va_end(ap);
	return ret;
	}

    return EOF;
}
!EOF!
ls -l scanf.c
echo x - scanset.h
sed 's/^X//' > scanset.h << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
/* declare a class for use in manipulating */
/* scansets such as [a-zA-Z] */
#include <limits.h>
class scanset
{
    unsigned char set[UCHAR_MAX + 1];

public:
    scanset(const char *pattern, const char **retpat = 0);
    match(int c)
	{
	return ((c >= 0) && (c <= UCHAR_MAX)) ?
	    set[c] : 0;
	}
};
!EOF!
ls -l scanset.h
echo x - scanset1.c
sed 's/^X//' > scanset1.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// construct the scanset
scanset::scanset(const char *pattern, const char **retpat)
{
    // Set the value which indicates a match based
    // on whether the set is complemented or not.
    int match = 1;
    if (*pattern == '^')
	{
	match = 0;
	pattern++;
	}

    // Initialize the array for all non-matches.
    memset(set, !match, UCHAR_MAX + 1);

    // The first character is special and
    // can contain `]' or `-'.
    if ((*pattern == ']') || (*pattern == '-'))
	set[*pattern++] = match;

    // Run down the pattern looking for the `]',
    // setting appropriate members of the
    // set to match.
    for ( ; *pattern && (*pattern != ']'); pattern++)
	// either a range or trailing `-'
	if (*pattern == '-')
	    {
	    // special case for trailing `-'
	    if (pattern[1] == ']')
		set['-'] = match;

	    // char range, a-z
	    else
		{
		for (int i = pattern[-1] + 1;
		     i <= pattern[1]; i++)
		    set[i] = match;
		pattern++;
		}
	    }

	else
	    set[*pattern] = match;

    // The pattern now points to the `]'.
    // Return the value just beyond it.
    if (retpat)
	*retpat = pattern + 1;
}
!EOF!
ls -l scanset1.c
echo x - setbuf.c
sed 's/^X//' > setbuf.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// change the buffering associated with a stream
void setbuf(FILE *f, char *buf)
{
#undef setbuf			/* DELETE */
    if (f->sb)
	if (buf)
	    f->sb->setbuf(buf, BUFSIZ);
	else
	    f->sb->setbuf(&(f->unbuf), 1);
#define setbuf xsetbuf		/* DELETE */
}
!EOF!
ls -l setbuf.c
echo x - sprintf.c
sed 's/^X//' > sprintf.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// write the arguments in a formatted manner to a string
#include <stdarg.h>
int sprintf(char *s, const char *fmt, ...)
{
    if (s)
	{
	va_list ap;
	va_start(ap, fmt);
	int ret = vsprintf(s, fmt, ap);
	va_end(ap);
	return ret;
	}

    return EOF;
}
!EOF!
ls -l sprintf.c
echo x - sscanf.c
sed 's/^X//' > sscanf.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// read a set of arguments from a string
int sscanf(const char *s, const char *fmt, ...)
{
    if (s)
	{
	va_list ap;
	va_start(ap, fmt);
	int ret = vsscanf(s, fmt, ap);
	va_end(ap);
	return ret;
	}

    return EOF;
}
!EOF!
ls -l sscanf.c
echo x - stdin.c
sed 's/^X//' > stdin.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// define the preopened FILEs and
// tie them to the preopened streams
static FILE fstdin(&cin);
static FILE fstdout(&cout);
static FILE fstderr(&cerr);

FILE *stdin = &fstdin;
FILE *stdout = &fstdout;
FILE *stderr = &fstderr;
!EOF!
ls -l stdin.c
echo x - tst.c
sed 's/^X//' > tst.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
#include "nstdio.h"
#include <stdlib.h>
inline unsigned long strtoul(const char *nptr, char **endptr, int base)
{
    return (unsigned long) strtol(nptr, endptr, base);
}
#include "FILE.c"
#include "FILE2.c"
#include "FILE3.c"
#include "clearerr.c"
#include "doprint.c"
#include "doscan.c"
#include "fclose.c"
#include "feof.c"
#include "ferror.c"
#include "fflush.c"
#include "fgetc.c"
#include "fgets.c"
#include "fopen.c"
#include "fprintf.c"
#include "fputc.c"
#include "fputs.c"
#include "fread.c"
#include "freopen.c"
#include "fscanf.c"
#include "fwrite.c"
#include "getc.c"
#include "getchar.c"
#include "gets.c"
#include "printf.c"
#include "putc.c"
#include "putchar.c"
#include "puts.c"
#include "scanf.c"
#include "scanset1.c"
#include "setbuf.c"
#include "sprintf.c"
#include "sscanf.c"
#include "stdin.c"
#include "ungetc.c"
#include "vfprintf.c"
#include "vfscanf.c"
#include "vprintf.c"
#include "vscanf.c"
#include "vsprintf.c"
#include "vsscanf.c"
#include "~FILE.c"

main()
{
    FILE *tp = fopen("/etc/termcap", "r");
    if (!tp)
	{
	(void) fprintf (stderr, "cannot open /etc/termcap\n");
	exit(1);
	}
    else
	(void) fprintf (stderr, "openned /etc/termcap\n");

    FILE *op = fopen("/tmp/foo.out", "w");
    if (!op)
	{
	(void) fprintf (stderr, "cannot open /tmp/foo.out\n");
	exit(1);
	}
    else
	(void) fprintf (stderr, "openned /tmp/foo.out\n");

    int c;
    while ((c = getc(tp)) != EOF)
	putc(c, op);

    printf("feof(tp)==%d\n", feof(tp));
    printf("ferror(tp)==%d\n", ferror(tp));
    printf("feof(op)==%d\n", feof(op));
    printf("ferror(op)==%d\n", ferror(op));

    fclose(op);
    fclose(tp);
    (void) fprintf (stderr, "all done\n");

    tp = fopen("/etc/termcap", "r");
    if (!tp)
	{
	(void) fprintf (stderr, "cannot open /etc/termcap\n");
	exit(1);
	}
    else
	(void) fprintf (stderr, "openned /etc/termcap\n");

    op = fopen("/tmp/foo2.out", "w");
    if (!op)
	{
	(void) fprintf (stderr, "cannot open /tmp/foo2.out\n");
	exit(1);
	}
    else
	(void) fprintf (stderr, "openned /tmp/foo2.out\n");

    char buf[BUFSIZ];
    while (fgets(buf, sizeof buf, tp))
	fputs(buf, op);

    printf("feof(tp)==%d\n", feof(tp));
    printf("ferror(tp)==%d\n", ferror(tp));
    printf("feof(op)==%d\n", feof(op));
    printf("ferror(op)==%d\n", ferror(op));

    fclose(op);
    fclose(tp);
    (void) fprintf (stderr, "all done\n");

    int x;
    int ret = scanf("%d", &x);
    (void) printf("scanf returns %d, x = %d\n", ret, x);
    ret = scanf(" %5[a-d]xyz %d", buf, &x);
    (void) printf("scanf returns %d, buf = '%s', x = %d\n", ret, buf, x);
    return 0;
}
!EOF!
ls -l tst.c
echo x - tst.cmp
sed 's/^X//' > tst.cmp << '!EOF!'
feof(tp)==1
ferror(tp)==1
feof(op)==0
ferror(op)==0
feof(tp)==1
ferror(tp)==1
feof(op)==0
ferror(op)==0
scanf returns 1, x = 15
scanf returns 2, buf = 'dcba', x = 27
!EOF!
ls -l tst.cmp
echo x - tst.ecmp
sed 's/^X//' > tst.ecmp << '!EOF!'
openned /etc/termcap
openned /tmp/foo.out
all done
openned /etc/termcap
openned /tmp/foo2.out
all done
!EOF!
ls -l tst.ecmp
echo x - tst.err
sed 's/^X//' > tst.err << '!EOF!'
openned /etc/termcap
openned /tmp/foo.out
all done
openned /etc/termcap
openned /tmp/foo2.out
all done
!EOF!
ls -l tst.err
echo x - tst.in
sed 's/^X//' > tst.in << '!EOF!'
15
dcbaxyz
27
!EOF!
ls -l tst.in
echo x - ungetc.c
sed 's/^X//' > ungetc.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// put back a single character previously read in
inline int ungetc(const int c, FILE *f)
{
    if (f->mode == input)
	f->in->putback(c);

    return c;
}
!EOF!
ls -l ungetc.c
echo x - vfprintf.c
sed 's/^X//' > vfprintf.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// write a variable argument list in a formatted manner
int vfprintf(FILE *f, const char *fmt, va_list vl)
{
    if (f->mode != input)
	return _doprint(f->out, fmt, vl);

    return EOF;
}
!EOF!
ls -l vfprintf.c
echo x - vfscanf.c
sed 's/^X//' > vfscanf.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// read a variable argument list in a
// formatted manner from a given file
int vfscanf(FILE *f, const char *fmt, va_list vl)
{
    if (f->mode == input)
	return _doscanf(f->in, fmt, vl);

    else
	return EOF;
}
!EOF!
ls -l vfscanf.c
echo x - vprintf.c
sed 's/^X//' > vprintf.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// write a variable argument list
// in a formatted manner to stdout
int vprintf(const char *fmt, va_list vl)
{
    if (stdout->mode != input)
	return _doprint(stdout->out, fmt, vl);

    return EOF;
}
!EOF!
ls -l vprintf.c
echo x - vscanf.c
sed 's/^X//' > vscanf.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// read a variable argument list in a
// formatted manner from stdin
int vscanf(const char *fmt, va_list vl)
{
    if (stdin->mode == input)
	return _doscanf(stdin->in, fmt, vl);

    else
	return EOF;
}
!EOF!
ls -l vscanf.c
echo x - vsprintf.c
sed 's/^X//' > vsprintf.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// write a variable argument list
// in a formatted manner to a string
#include <limits.h>
int vsprintf(char *s, const char *fmt, va_list vl)
{
    ostream f(INT_MAX, s);
    return _doprint(&f, fmt, vl);
}
!EOF!
ls -l vsprintf.c
echo x - vsscanf.c
sed 's/^X//' > vsscanf.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// read a variable argument list in a
// formatted manner from a string
int vsscanf(const char *str, const char *fmt, va_list vl)
{
    istream in(strlen(str), (char*)str);
    return _doscanf(&in, fmt, vl);
}
!EOF!
ls -l vsscanf.c
echo x - ~FILE.c
sed 's/^X//' > ~FILE.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// free the stream created for a FILE
FILE::~FILE()
{
    if (sb)
	if (mode == input)
	    delete in;
	else
	    delete out;
}
!EOF!
ls -l ~FILE.c
# The following exit is to ensure that extra garbage 
# after the end of the shar file will be ignored.
exit 0
