#!/bin/sh
# This is a shar archive.
# The rest of this file is a shell script which will extract:
#
# 6_5.h 6_5srep.h makefile tst.in tst1.c tst1.cmp
#
# 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:08:08 EDT 1990
#
echo x - 6_5.h
sed 's/^X//' > 6_5.h << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// Exercise 6.5
// String class with value semantics
// and delayed copying on assignment.
#ifndef STR_H
# define STR_H
# include <stream.h>
# include <string.h>

#include "6_5srep.h"	/* EXPAND */

// a helper typedef for the cast
// back into a character pointer
typedef const char *charptr;

class string
{
    srep *p;

    char *str()
    { return p->s; }

    int len()
    { return p->size; }

public:
    // string s;
    string()
    { p = new srep; }

    // string s(5);
    string(int sz)
    { p = new srep(sz); }

    // string s("xyz");
    string(char *s)
    { p = new srep(s); }

    // string s = string ...
    string(string &s)
    { s.p->refcnt++; p = s.p; }

    ~string()
    {
	if (--p->refcnt == 0)
	    delete p;
    }

    // s = string
    string& operator=(string &s)
    {
	s.p->refcnt++;
	if (--p->refcnt == 0)
	    delete p;
	p = s.p;
	return *this;
    }

    // s = "xyz";
    string& operator=(char *s)
    {
	if (p->refcnt > 1)
	    {
	    p->refcnt--;
	    p = new srep(s);
	    }

	else
	    *p = s;
	return *this;
    }

    // char *c = s;
    const char *operator charptr()
    {
	return str();
    }

    // x = s[3];
    // s[3] = 'x';
    char &operator[](int i)
    {
	if (i < 0 || i >= len())
	    return str()[0];
	else
	    return str()[i];
    }

    friend ostream& operator<<(ostream&, string&);
    friend istream& operator>>(istream&, string&);

    friend int operator==(string &x, char *s)
    { return strcmp(x.str(), s) == 0; }

    friend int operator==(string &x, string &y)
    { return strcmp(x.str(), y.str()) == 0; }

    friend int operator!=(string &x, char *s)
    { return strcmp(x.str(), s) != 0; }

    friend int operator!=(string &x, string &y)
    { return strcmp(x.str(), y.str()) != 0; }
};

inline ostream& operator<<(ostream &s, string &x)
{
    return s << x.str();
}

inline istream& operator>>(istream &s, string &x)
{
    char buf[1024];
    s >> buf;
    x = buf;
    return s;
}
#endif /* STR_H */
!EOF!
ls -l 6_5.h
echo x - 6_5srep.h
sed 's/^X//' > 6_5srep.h << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
// define the class to manage the
// actual character string
class srep
{
    friend class string;
    char *s;
    int size;
    int refcnt;

    srep()
    {
	refcnt = 1;
	s = new char[size = 1];
	s[0] = 0;
    }

    srep(int sz)
    {
	refcnt = 1;
	s = new char[size = sz];
	s[0] = 0;
    }

    srep(char *x)
    {
	refcnt = 1;
	s = new char[size = strlen(x) + 1];
	strcpy(s, x);
    }

    srep& operator=(char *x)
    {
	delete s;
	refcnt = 1;
	s = new char[size = strlen(x) + 1];
	strcpy(s, x);
	return *this;
    }

    ~srep()
    { delete s; }
};
!EOF!
ls -l 6_5srep.h
echo x - makefile
sed 's/^X//' > makefile << '!EOF!'
CC= CC -I. -I../../CC
CFLAGS=
ERROR= ../../error.o

all: tst1

tst1: tst1.c 6_5.h 6_5srep.h makefile
	$(CC) $(CFLAGS) tst1.c -o tst1 $(ERROR)

CMP= tst1.cmp
OUT= tst1.out

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

test: all $(OUT) $(CMP)
	cmp tst1.out tst1.cmp
	echo tests done
!EOF!
ls -l makefile
echo x - tst.in
sed 's/^X//' > tst.in << '!EOF!'
hello
there
again
done
!EOF!
ls -l tst.in
echo x - tst1.c
sed 's/^X//' > tst1.c << '!EOF!'
/* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */
/* The C++ Answer Book */
/* Tony Hansen */
/* All rights reserved. */
#include <6_5.h>
#include <error.h>

main()
{
    string x[100];
    cout << "here we go\n";
    for (int n = 0; cin>>x[n]; n++) 
	{
	string y;
	if (n == 100) error("too many strings");
	cout << (y = x[n]) << "\n";
	if (y == "done") break;
	}
    cout << "here we go back again\n";
    for (int i = n-1; 0 <= i; i--)
        cout << x[i] << "\n";
    return 0;
}
!EOF!
ls -l tst1.c
echo x - tst1.cmp
sed 's/^X//' > tst1.cmp << '!EOF!'
here we go
hello
there
again
done
here we go back again
again
there
hello
!EOF!
ls -l tst1.cmp
# The following exit is to ensure that extra garbage 
# after the end of the shar file will be ignored.
exit 0
