#!/bin/sh
# This is a shar archive.
# The rest of this file is a shell script which will extract:
#
# gslist.h line.h main.c makefile myshape.c myshape.h put_line.c rectangle.h screen.c screen.h shape.c shape.h slist.c slist.h
#
# 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:09:55 EDT 1990
#
echo x - gslist.h
sed 's/^X//' > gslist.h << '~FUNKY STUFF~'
#ifndef GSLIST_H
#define GSLIST_H
#include "slist.h"
#include <generic.h>

#define gslist(type) name2(type,gslist)
#define gslist_iterator(type) name2(type,gslist_iterator)

#define gslistdeclare(type)				\
	struct gslist(type) : slist {			\
	    int insert(type a)				\
		{ return slist::insert(ent(a)); }	\
	    int append(type a)				\
		{ return slist::append(ent(a)); }	\
	    type get() { return type(slist::get()); }	\
	    gslist(type)() { }				\
	    gslist(type)(type a) : (ent(a)) {}		\
	    ~gslist(type)() { clear(); }		\
	};						\
							\
	struct gslist_iterator(type) : slist_iterator {	\
	    gslist_iterator(type)(gslist(type)& s)	\
	        : ((slist&)s) {}			\
	    type operator()()				\
	        { return type(slist_iterator::operator()()); } \
	};
#endif
~FUNKY STUFF~
ls -l gslist.h
echo x - line.h
sed 's/^X//' > line.h << '~FUNKY STUFF~'
#ifndef LINE_H
#define LINE_H

class line : public shape
{
/*
    line from "w" to "e"

    north() is defined as `above the middle as
    far north as the northernmost point'

    nw ---- n ---- ne    nw ---- n ---- ne
    |            *  |    |  *            |
    |         *     |    |    *          |
    w       m       e    w       m       e
    |    *          |    |         *     |
    | *             |    |            *  |
    sw ---- s ---- se    sw ---- s ---- se
*/
    point w, e;

public:
    point north() { return point((w.x+e.x)/2, e.y<w.y?w.y:e.y); }
    point neast() { return point(e.x, e.y<w.y?w.y:e.y); }
    point east()  { return point(e.x, (w.y+e.y)/2); }
    point seast() { return point(e.x, e.y<w.y?e.y:w.y); }
    point south() { return point((w.x+e.x)/2, e.y<w.y?e.y:w.y); }
    point swest() { return point(w.x, e.y<w.y?e.y:w.y); }
    point west()  { return point(w.x, (w.y+e.y)/2); }
    point nwest() { return point(w.x,  e.y<w.y?w.y:e.y); }
    point middle() { return point((w.x+e.x)/2, (w.y+e.y)/2); }

    void move(int a, int b)
    { w.x += a; w.y += b; e.x += a; e.y += b; }
    void draw() { put_line(w, e); }

    line(point a, point b)
    {
	if (a.x < b.x) {
	    w = a;
	    e = b;
	} else {
	    w = b;
	    e = a;
	}
    }

    line(point a, int len)
    {
	if (len >= 0) {
	    w = point(a.x+len-1,a.y);
	    e = a;
	} else {
	    w = a;
	    e = point(a.x+len-1,a.y);
	}
    }
};
#endif
~FUNKY STUFF~
ls -l line.h
echo x - main.c
sed 's/^X//' > main.c << '~FUNKY STUFF~'
#include "myshape.h"

main()
{
    screen_init();
    shape* p1 = new rectangle(point(0,0),point(10,10));
    shape* p2 = new line(point(0,15),17);
    shape* p3 = new myshape(point(15,10),point(27,18));
    shape_refresh();
    p3->move(-10,-10);
    stack(p2, p3);
    stack(p1, p2);
    shape_refresh();
    screen_end();
    return 0;
}
~FUNKY STUFF~
ls -l main.c
echo x - makefile
sed 's/^X//' > makefile << '~FUNKY STUFF~'
CC= CC -I. -I../../CC
CFLAGS= +i -g

OBJ= screen.o shape.o myshape.o slist.o put_line.o main.o

all: shape.a

shape.a: $(OBJ)
	rm -f shape.a
	ar qc shape.a $(OBJ)

screen.o: screen.c screen.h
	$(CC) $(CFLAGS) -c screen.c

shape.o: shape.c shape.h line.h rectangle.h screen.h slist.h gslist.h
	$(CC) $(CFLAGS) -c shape.c

myshape.o: myshape.c myshape.h shape.h line.h rectangle.h screen.h slist.h gslist.h
	$(CC) $(CFLAGS) -c myshape.c

slist.o: slist.c slist.h
	$(CC) $(CFLAGS) -c slist.c

put_line.o: put_line.c screen.h
	$(CC) $(CFLAGS) -c put_line.c

main.o: main.c myshape.h shape.h line.h rectangle.h screen.h gslist.h slist.h
	$(CC) $(CFLAGS) -c main.c
~FUNKY STUFF~
ls -l makefile
echo x - myshape.c
sed 's/^X//' > myshape.c << '~FUNKY STUFF~'
#include "myshape.h"

myshape::myshape(point a, point b) : (a,b)
{
    int ll = neast().x - swest().x + 1;
    int hh = neast().y - swest().y + 1;
    l_eye = new line(point(swest().x + 2, swest().y + hh * 3 / 4) , 2);
    r_eye = new line(point(swest().x + ll - 4, swest().y + hh * 3 / 4), 2);
    mouth = new line(point(swest().x + 2, swest().y + hh / 4) , ll - 4);
}

void myshape:: draw()
{
    rectangle::draw();
    put_point(point((swest().x + neast().x) / 2, (swest().y + neast().y) / 2));
}

void myshape:: move(int a, int b)
{
    rectangle::move(a,b);
    l_eye->move(a,b);
    r_eye->move(a,b);
    mouth->move(a,b);
}
~FUNKY STUFF~
ls -l myshape.c
echo x - myshape.h
sed 's/^X//' > myshape.h << '~FUNKY STUFF~'
#ifndef MYSHAPE_H
#define MYSHAPE_H

#include "shape.h"

class myshape : public rectangle
{
    line* l_eye;
    line* r_eye;
    line* mouth;

public:
    myshape(point, point);
    void draw();
    void move(int, int);
};
#endif
~FUNKY STUFF~
ls -l myshape.h
echo x - put_line.c
sed 's/^X//' > put_line.c << '~FUNKY STUFF~'
#include "screen.h"

void put_line(point a, point b)
{
    put_line(a.x, a.y, b.x, b.y);
}

void put_line(int x0, int y0, int x1, int y1)
{
    register dx = 1;
    int a = x1 - x0;
    if (a < 0) dx = -1, a = -a;
    register dy = 1;
    int b = y1 - y0;
    if (b < 0) dy = -1, b = -b;
    int two_a = 2 * a;
    int two_b = 2 * b;
    int xcrit = -b + two_a;
    register eps = 0;
    for (;;)
	{
	put_point(x0, y0);
	if (x0 == x1 && y0 == y1) break;
	if (eps <= xcrit) x0 += dx, eps += two_b;
	if (eps>= a || a <= b) y0 += dy, eps -= two_a;
	}
}
~FUNKY STUFF~
ls -l put_line.c
echo x - rectangle.h
sed 's/^X//' > rectangle.h << '~FUNKY STUFF~'
#ifndef RECTANGLE_H
#define RECTANGLE_H

class rectangle : public shape
{
/*
    nw ---- n ---- ne
    |               |
    |               |
    w       m       e
    |               |
    |               |
    sw ---- s ---- se
*/
    point sw, ne;

public:
    point north() { return point((sw.x+ne.x)/2, ne.y); }
    point neast() { return ne; }
    point east()  { return point(ne.x, (sw.y+ne.y)/2); }
    point seast() { return point(ne.x, sw.y); }
    point south() { return point((sw.x+ne.x)/2, sw.y); }
    point swest() { return sw; }
    point west()  { return point(sw.x, (sw.y+ne.y)/2); }
    point nwest() { return point(sw.x, ne.y); }
    point middle(){ return point((sw.x+ne.x)/2, (sw.y+ne.y)/2); }

    void move(int a, int b) { sw.x += a; sw.y += b; ne.x += a; ne.y += b; }
    void draw();

    rectangle(point, point);
};
#endif
~FUNKY STUFF~
ls -l rectangle.h
echo x - screen.c
sed 's/^X//' > screen.c << '~FUNKY STUFF~'
#include "screen.h"

char screen[XMAX][YMAX];

void screen_init()
{
    for (int y = 0; y < YMAX; y++)
	for (int x=0; x < XMAX; x++)
	    screen[x][y] = white;
}

inline int on_screen(int a, int b)
{
    return 0 <= a && a < XMAX && 0 <= b && b < YMAX;
}

void put_point(int a, int b)
{
    if (on_screen(a,b)) screen[a][b] = black;
}

void screen_clear()
{
     screen_init();
}

void screen_refresh()
{
    for (int y=YMAX-1; 0<= y; y--)
	{
	for (int x = 0; x < XMAX; x++)
	    cout.put(screen[x][y]);
	cout.put('\n');
	}
}

void screen_end() { }
~FUNKY STUFF~
ls -l screen.c
echo x - screen.h
sed 's/^X//' > screen.h << '~FUNKY STUFF~'
#ifndef SCREEN_H
#define SCREEN_H
// file screen.h

const XMAX = 80, YMAX = 60;

struct point {
    int x, y;
    point() {}
    point(int a, int b) { x = a; y = b; }
};

overload put_point;
extern void put_point(int a, int b);
inline void put_point(point p) { put_point(p.x, p.y); }

overload put_line;
extern void put_line(int, int, int, int);
extern void put_line(point a, point b);

extern void screen_init();
extern void screen_refresh();
extern void screen_clear();
extern void screen_end();

enum color { black = '*', white = ' ' };

#include <stream.h>
#endif
~FUNKY STUFF~
ls -l screen.h
echo x - shape.c
sed 's/^X//' > shape.c << '~FUNKY STUFF~'
#include "shape.h"
#include "screen.h"

shape_lst shape_list;

rectangle::rectangle(point a, point b)
{
    if (a.x <= b.x) {
        if (a.y <= b.y) {
	    sw = a;
	    ne = b;
	} else {
	    sw = point(a.x, b.y);
	    ne = point(b.x, a.y);
	}
    } else {
        if (a.y <= b.y) {
	    sw = point(b.x, a.y);
	    ne = point(a.x, b.y);
	} else {
	    sw = b;
	    ne = a;
	}
    }
}

void rectangle::draw()
{
    point nw(sw.x, ne.y);
    point se(ne.x, sw.y);
    put_line(nw,ne);
    put_line(ne,se);
    put_line(se,sw);
    put_line(sw,nw);
}

void shape_refresh()
{
    screen_clear();
    sl_iterator next(shape_list);
    shape* p;
    while (p = next() ) p->draw();
    screen_refresh();
}

void stack(shape* q, shape* p) // put p on top of q
{
    point n = p->north();
    point s = q->south();
    q->move(n.x-s.x, n.y-s.y+1);
}
~FUNKY STUFF~
ls -l shape.c
echo x - shape.h
sed 's/^X//' > shape.h << '~FUNKY STUFF~'
#ifndef SHAPE_H
#define SHAPE_H
#include "screen.h"

#include "gslist.h"

struct shape;

typedef shape* sp;
declare(gslist,sp);

typedef gslist(sp) shape_lst;
typedef gslist_iterator(sp) sl_iterator;
extern shape_lst shape_list;

struct shape
{
    shape() { shape_list.append(this); }

    virtual point north() { return point(0,0); }
    virtual point neast() { return point(0,0); }
    virtual point east()  { return point(0,0); }
    virtual point seast() { return point(0,0); }
    virtual point south() { return point(0,0); }
    virtual point swest() { return point(0,0); }
    virtual point west()  { return point(0,0); }
    virtual point nwest() { return point(0,0); }
    virtual point middle(){ return point(0,0); }

    virtual void draw() {};
    virtual void move(int, int) {};
    friend void shape_refresh();
    friend void stack(shape*, shape*);
};

extern void shape_refresh();
extern void stack(shape*, shape*);

#ifdef RECTFIRST
# include <rectangle.h>
# include <line.h>
#else
# include <line.h>
# include <rectangle.h>
#endif

#endif
~FUNKY STUFF~
ls -l shape.h
echo x - slist.c
sed 's/^X//' > slist.c << '~FUNKY STUFF~'
#include "slist.h"
#include <stream.h>
#include <stdlib.h>

int slist::insert(ent a)
{
    if (last)
        {
	last->next = new slink(a, last->next);
	}
    else
	{
	last = new slink(a, 0);
	last->next = last;
	}
    return 0;
}

int slist::append(ent a)
{
    if (last)
	{
	last = last->next = new slink(a, last->next);
	}
    else
	{
	last = new slink(a, 0);
	last->next = last;
	}
    return 0;
}

ent slist::get()
{
    if (last == 0)
	slist_handler("get from empty slist");
    slink *f = last->next;
    ent r = f->e;
    if (f == last)
	{
	last = 0;
	}
    else
	{
	last->next = f->next;
	}
    delete f;
    return r;
}

void slist::clear()
{
    slink *l = last;
    if (l == 0) return;
    do {
	slink *ll = last;
	l = l->next;
	delete ll;
    } while (l != last);
    last = 0;
}

static void default_error(char *s)
{
    cerr << s << "\n";
    exit(1);
}

PFC slist_handler = default_error;

PFC set_slist_handler(PFC handler)
{
    PFC rr = slist_handler;
    slist_handler = handler;
    return rr;
}
~FUNKY STUFF~
ls -l slist.c
echo x - slist.h
sed 's/^X//' > slist.h << '~FUNKY STUFF~'
#ifndef SLIST_H
#define SLIST_H

typedef void* ent;

class slink
{
    friend class slist;
    friend class slist_iterator;

    slink *next;
    ent e;
    slink(ent a, slink *p) 
	{
	e = a;
	next = p;
	}
};

class slist
{
    friend class slist_iterator;
    slink *last;
public:
    int insert(ent a);
    int append(ent a);
    ent get();
    void clear();
    slist() 
	{
	last = 0;
	}
    slist(ent a)
	{
	last = new slink(a, 0);
	last->next = last;
	}
    ~slist()
	{
	clear();
	}
};

class slist_iterator
{
    slink *ce;
    slist *cs;

public:
    slist_iterator(slist &s)
	{
	cs = &s;
	ce = cs->last;
	}
    
    ent operator()()
	{
	ent ret = ce ? (ce = ce->next)->e : 0;
	if (ce == cs->last) ce = 0;
	return ret;
	}
};

typedef void (*PFC)(char*);
extern PFC slist_handler;
extern PFC set_slist_handler(PFC);
#endif
~FUNKY STUFF~
ls -l slist.h
# The following exit is to ensure that extra garbage 
# after the end of the shar file will be ignored.
exit 0
