#!/bin/sh
# This is a shar archive.
# The rest of this file is a shell script which will extract:
#
# 8_2a.c 8_2b.c 8_2c.c 8_2d.c makefile tst.c tst.cmp tst.in
#
# 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:12:33 EDT 1990
#
echo x - 8_2a.c
sed 's/^X//' > 8_2a.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// Exercise 8.2
struct name_and_address
{
    char **name;
    int len;

    name_and_address()
    {
	name = new char*[1];
	name[0] = 0;
	len = 1;
    }

    // construct an address using
    // another as its initializer
    name_and_address(name_and_address &na)
    {
	// init name and pass the buck to op=
	name = 0;
	*this = na;
    }

    // A helper function to remove the strings.
    // This is used by assignment and input.
    void deallocate_name();

    // assign one address to another
    name_and_address& operator=(name_and_address &na)
    {
	// delete any strings already there
        deallocate_name();

	// allocate and copy the strings
	name = new char*[na.len];
	for (char **tmpname = name, **tmpnaname = na.name;
	     *tmpnaname; tmpname++, tmpnaname++)
	    {
	    *tmpname = new char[strlen(*tmpnaname) + 1];
	    strcpy(*tmpname, *tmpnaname);
	    }

	*tmpname = 0;
	len = na.len;
	return *this;
    }

    // remove the parts of an address
    ~name_and_address()
    {
	deallocate_name();
    }

    // input and output
    friend istream& operator>>
	(istream&, name_and_address&);
    friend ostream& operator<<
	(ostream&, name_and_address&);
};

void name_and_address::deallocate_name()
{
    if (name)
	{
	for (char **svname = name; *svname; )
	    delete *svname++;
	delete name;
	name = 0;
	}
}
!EOF!
ls -l 8_2a.c
echo x - 8_2b.c
sed 's/^X//' > 8_2b.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// output the name and address as a series of lines
ostream& operator<<(ostream &out, name_and_address &x)
{
    if (x.name)
	for (char **n = x.name; *n; n++)
	    out << *n << "\n";

    out << "\n";
    return out;
}
!EOF!
ls -l 8_2b.c
echo x - 8_2c.c
sed 's/^X//' > 8_2c.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// check a line to make sure it is made
// up entirely of spaces and tabs
#include <ctype.h>
static int isblankline(char *buf)
{
    for ( ; *buf; buf++)
	if (!isspace(*buf))
	    return 0;

    return 1;
}

// Input a series of lines into a name and address.
istream& operator>>(istream &in, name_and_address &x)
{
    x.deallocate_name();
    x.name = new char*[x.len = 6];

    char **n = x.name;
    for (int curlen = 0; ; curlen++, n++)
	{
	// read in a line
	char buf[256], c;
	in.get(buf, sizeof(buf));
	in.get(c);	// zap the newline
	if (!in)
	    break;

	// did we reach a blank line?
	if (isblankline(buf))
	    break;

	// reallocate if necessary
	if (curlen >= x.len)
	    {
	    const int inc = 4;
	    char **svname = x.name;
	    x.name = new char*[x.len + inc];
	    memcpy((char*)x.name, (char*)svname,
		x.len * sizeof(char*));
	    x.len += inc;
	    }

	// save the line
	*n = new char[strlen(buf) + 1];
	strcpy(*n, buf);
	}

    *n = 0;
    return in;
}

!EOF!
ls -l 8_2c.c
echo x - 8_2d.c
sed 's/^X//' > 8_2d.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// copy a stream of name_and_address objects
#include <error.h>
main(int, char**)
{
    for (;;)
	{
	name_and_address a;
	if (!(cin >> a))
	    break;
	if (!(cout << a))
	    break;
	name_and_address b = a;
	if (!(cout << b))
	    break;
	}

    if (!cin.eof())
	error("error reading input");
    if (cout.bad())
	error("error writing output");
    return 0;
}
!EOF!
ls -l 8_2d.c
echo x - makefile
sed 's/^X//' > makefile << '!EOF!'
CC= CC -I. -I../../CC
ERROR= ../../error.o

all: tst

tst: tst.c 8_2a.c 8_2b.c 8_2c.c 8_2d.c
	$(CC) tst.c -o tst $(ERROR)

CMP= tst.cmp
OUT= tst.out

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

test: all $(CMP) $(OUT)
	cmp tst.out tst.cmp
	@echo test done
!EOF!
ls -l makefile
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 <stream.h>
#include <string.h>
#include "8_2a.c"	/* struct name_and_address */
#include "8_2b.c"	/* operator<<(name_and_address) */
#include "8_2c.c"	/* operator>>(name_and_address) */
#include "8_2d.c"	/* main() */
!EOF!
ls -l tst.c
echo x - tst.cmp
sed 's/^X//' > tst.cmp << '!EOF!'
this is
a test
of

this is
a test
of

how's this?
and
this?

how's this?
and
this?

!EOF!
ls -l tst.cmp
echo x - tst.in
sed 's/^X//' > tst.in << '!EOF!'
this is
a test
of

how's this?
and
this?

!EOF!
ls -l tst.in
# The following exit is to ensure that extra garbage 
# after the end of the shar file will be ignored.
exit 0
