[comp.sys.mac.programmer] THINK C 4.0 Objects/C++ Portability Macros

salzman@randvax.UUCP (Isaac Salzman) (09/18/89)

Well, I've gotten quite a few requests for this stuff, so I'm posting
it here. Enclosed is a shell archive (shar) file, the bulk of which is
the README file. The macros aren't nearly as important as the README
file -- so please read it first. A sample program using the macros
is enclose. It implements a linked list class & sub-classes.

This should be posted to a sources group (i.e. comp.sources.misc), but many
requested it by posted here, and this is where the primary audience for this
stuff is, and it is relatively small (~40k). And, most of it is
documentation anyway. Hope this is usefull to someone. If you have any ideas
on how to implement portable TCO/C++ code better, please pass them along.
Enjoy!!!

**
* Isaac J. Salzman                                            ----     
* The RAND Corporation - Information Sciences Dept.          /o o/  /  
* 1700 Main St., PO Box 2138, Santa Monica, CA 90406-2138    | v |  |  
* AT&T      : +1 213-393-0411 x6421 or x7923 (ISL lab)      _|   |_/   
* Internet  : salzman@rand.org                             / |   |
* UUCP      : !uunet!rand.org!salzman                      | |   |     
* CompuServe: 76167,1046

-------------------------------------------------------------------------
#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  README linktest.c link.c strlink.c intlink.c listlink.c
#   link.h listlink.h strlink.h intlink.h class.h defs.h Makefile
# Wrapped by salzman@iris on Sun Sep 17 15:26:05 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(15093 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
X/*	README - Portable C++/THINK C 4.0 Object programs
X
X	Copyright (C) 1989, Integrity Software
X	Author: Isaac J. Salzman (salzman@rand.org)
X
X	This software may be freely used/modified/distributed
X	as desired so long as this copyright notice remains
X	in tact.
X
X	$Header: /tmp_mnt/amnt/lh/salzman/src/class/RCS/README,v 1.1 89/09/17 15:01:41 salzman Exp Locker: salzman $
X
X	$Log:	README,v $
X	Revision 1.1  89/09/17  15:01:41  salzman
X	Initial revision
X	 
X*/
X
XThe contents of this archive are as follows:
X
X	README		- this file
X	class.h		- macros for portable C++/THINK C object programs
X	
X	link.h		- a Link class for implementing linked lists: header
X	link.c		- and implementation
X	intlink.h	- IntLink class - linked list of int's: header
X	intlink.c	- and implementation
X	strlink.h	- StrLink class - linked list of strings: header
X	strlink.c	- and implementation
X	listlink.h	- ListLink class - linked list of Link's: header
X	listlink.c	- and implementation
X	linktest.c	- a test program for the above classes
X	
XAll documentation is contained in this file. Please read this before
Xattempting to use class.h. The macros are not nearly as important as
Xthe contents of this file.
X
XThe enclosed "class.h" file contains a set of C pre-processor macros to aid
Xin the development of source code that is portable between THINK C 4.0
Xobjects and C++. By using these macros and following certain coding
Xconventions, source code may be compiled and run under THINK C 4.0 or C++
Xwithout modification. These macros have been tested with GNU C++ 1.35,
Xand Oasys C++ (which is basically a port of AT&T cfront 1.2). NOTE: The
XOasys cpp is broken -- use the @n option with Oasys to use the standard
Xcpp.
X
XIf you start with the goal of portability in mind it is quite easy to
Xaccomplish. If you try and apply it to already developed C++ code or THINK
XC object code, you will no doubt encounter difficulties (more so when
Xstarting with C++).
X
XBefore I get in to the macros, I just want to address some general
Xissues of portability between THINK C Objects (TCO) and C++.
X
XFirst off, objects in TCO are always pointers - you can't just
Xdeclare something:
X
X	Class foo;
X
Xyou must declare it as
X
X	Class *foo;
X
Xand then call the initialization method in order to instantiate it:
X
X	foo = MakeObject(Class)( /* args to init method/constructor */ );
X
XIn C++ this is just like saying
X
X	foo = new Class (/* args */ );
X
XDetails on what's done in TCO are in the description of the relevant
Xmacros below. The main point: always use pointers to objects (if you
Xwant to be portable)!
X
XMethod overloading: TCO doesn't have it. Yes, this is a bummer.
XThough it's one of the better ideas in C++, it's something you
Xcan live without if you want portability. Methods of the same name
Xin derived classes must take the same type and number of arguments
Xas defined in the super class in TCO. One way to deal with that is 
Xto use <stdarg.h> and declare things like this:
X
X	#include <stdarg.h>
X	
X
X	int method ( ... );
X	
XOf course you have to deal with parsing the arg's instead of having
Xthe compiler figure out what to do.
X
XComments: only use /* */, TCO doesn't know about //.
X
XHeader files: THINK C has <stdlib.h> which must be included if you're
Xusing routines that are part of the ANSI C defined standard library.
XYou'll have to include different header files for C++ depending on
Ximplementation (<std.h> for g++ for example).
X
XO/S portability is a whole 'nother issue. Real Mac programs don't use
Xstdio. Those are issues which you'll have to deal with. If someone wants
Xto port the THINK C class library to C++ and X11, that would be great!!
X
XI've probably left some stuff out, but those are the important issues.
XAnd now on with the macros....
X
X----------------------------------------------------------------------
X
XDescription
X
XThe definition for each macro is shown for both THINK C Objects (TCO), and
XC++ followed by a brief explanation of its usage.
X
XTCO: #define class struct
XC++: /* none */
X
X     Simply define class to struct for TCO. TCO does not have a "class"
X     keyword, (and in actuality, struct may be used in place of class in C++
X     as well).
X
XTCO: #define virtual
XC++: /* none */
X
X     There is no "virtual" keyword in TCO since all methods are virtual.
X     Simply define this as nothing.
X
XTCO: #define PRIVATE
X     #define PROTECTED
X     #define PUBLIC
X
XC++: #define PROTECTED protected:
X     #define PRIVATE private:
X     #define PUBLIC public:
X
X     TCO makes no distinction between private, public and protected
X     members. All members are public according to TCO. These macros are to
X     be used in place of the labels normally used in C++. Do NOT include
X     the colon ":", it's part of the macro.
X
XTCO: #define ROOT : indirect /* this can also be : direct, read the THINK C
X				manual for a desc. of the difference */
XC++: #define ROOT
X
X     TCO determines if a struct is a class by looking at wether or not it
X     inherits from something. ALL classes in TCO must inherit from
X     *somthing*, otherwise they're just normal C structs. A root class in
X     TCO inherits from either "indirect" or "direct". Details on this
X     are explained in TC manual (it has to do with memory management and
X     wether handles or pointers are used). When declaring a root class,
X     declare as follows:
X
X	 class some_root_class ROOT
X	 {
X		/* variables, method declartions */
X	 };
X
XTCO: #define INHERIT_PUBLIC
XC++: #define INHERIT_PUBLIC public
X
X     C++ requires that you explicitly declare wether or not public members
X     of a base class are to be made public in a derived class. The default
X     (for C++) is that these become private members of the derived class
X     (and therefor can not be called by clients of this class).
X     This does nothing in TCO since everything is essentially public.
X     Example usage:
X
X     class Derived INHERIT_PUBLIC : BaseClass
X     {
X	/* stuff */
X     }
X
XTCO: #define PREDEC_CLASS(Class)
XC++: #define PREDEC_CLASS class Class
X
X     If you're defining classes that need to refer to themselves (common
X     for doing linked lists and such). I don't think you really need this
X     at all (and I haven't tested it really). Instead, just preceed members
X     of a class which will have the same type as the class currently being
X     defined, with "class". [yeah, it's confusing].
X
X[the following macros deal with constructors/initialization]
X
XTCO: #define DECL_INIT(Class) Class *Init##Class
XC++: #define DECL_INIT(Class) Class
X
X     [NOTE: the ## in the macro has the effect of performing string
X     catenation. this is a handy for declaring initialize methods that have
X     unique names for each class, which makes life much easier].
X 
X     These macros are used for DECLaring constructors/initialize methods in
X     C++/TCO respectively. Example usage:
X
X     class Derived INHERIT_PUBLIC : BaseClass
X     {
X
X	/* stuff */
X
X		DECL_INIT(Derived)(/* args */);
X     };
X
X     In C++ this will expand to:
X
X		Derived(/* args	 */);
X
X     In TCO this will be:
X
X	Derived *InitDerived(/* args */);
X
X     There's no special method for doing initialization in TCO. In C++
X     you must declare a constructor which is called everytime you
X     instantiate an object of that class. This happens automatically. We
X     can duplicate this behavior by the use of this macro and others to
X     follow. Also, notice that there is no return type for the C++
X     constructor. It's implicitly defined as returning an object (or
X     pointer to an object) of that class. It can't be redefined. In TCO we
X     need to declare this as always returning a pointer to that object (you
X     can't declare objects in TCO, just pointers to objects). More on this
X     follows.
X
XTCO: #define DEF_INIT(Class) Class *Class::Init##Class
X     #define INIT_SUPER(Class,args) Class::Init##Class args
X     #define SUPER_INIT_ARGS(args)
X     #define RETURN_THIS return this
X
XC++: #define DEF_INIT(Class) Class::Class
X     #define SUPER_INIT_ARGS(args) : args
X     #define INIT_SUPER(Class,args)
X     #define RETURN_THIS
X	 
X     These are used when actually defining the constructor/initialization
X     method. Example:
X
X     DEF_INIT(Derived)( /* args */ ) SUPER_INIT_ARGS(( /* super args */ ))
X     {
X	/* code */
X
X	INIT_SUPER(BaseClass, (/* super args */));
X
X	RETURN_THIS;
X     }
X
X     which ends up to be (for TCO):
X
X     Derived *Derived::InitDerived ( /* args */ )
X     {
X	/* code */
X
X	BaseClass::InitBaseClass (/* super args */);
X	return this;
X     }
X
X     and this (for C++):
X
X     Derived::Derived ( /* args */ ) : ( /* super args */ )
X     {
X	/* code */
X
X	;
X	;
X     }
X
X     Yes this looks kludgy, but it does the job! There are 4 macros
X     involved here: DEF_INIT for defining the constructor/initialization
X     method, SUPER_INIT_ARGS for passing arguments up to the super class
X     (the thing that this inherits from --  only relevant to C++),
X     and INIT_SUPER for calling the super classes's initialize method (only
X     relevant to TCO). RETURN_THIS is needed for TCO since we're going
X     to assign whatever is returned from the initialization method to
X     the pointer to the object we're instantiating. You can just put
X     "return this;" in there, but C++ will complain with a warning
X     message.
X     
X     Initialization is where TCO and C++ diverge the most and where
X     you need to be a bit kludgy and verbose in order to be portable. But,
X     it's worth the effort! Depending on wether you're using C++ or TCO,
X     only one of INIT_SUPER or SUPER_INIT_ARGS will actually result in any
X     code being generated from the macros. 
X
X     Things to be careful about: you must enclose (args) in paren's as
X     shown, or the macros will break. The last line in this method must be
X     "RETURN_THIS;" in order for TCO initialization to work properly. You
X     only need SUPER_INIT_ARGS if the super class takes arguments. This is
X     one of the more arcane constructs of C++. 
X
XTCO: #define MakeObject(Class) ((Class *)new (Class))->Init##Class
XC++: #define MakeObject(Class) new Class
X
X     And here's how to make an instance of the object:
X
X	Derived *dp;  /* declare a ptr to the object */
X
X	dp = MakeObject(Derived)( /* args */ );	     /* instantiate it */
X
X     which will end up as (in TCO):
X
X	dp = ((Derived *) new (Derived))->InitDerived ( /* args */ )
X
X     and (in C++):
X
X	dp = new Derived ( /* args */ );
X
X    TCO does not call any initialization method automatically upon
X    instantiation as C++ does. But we can still do it in the same step, and
X    hide the details in a macro. So as far as you're concerned, it always
X    gets done. The syntax of calling the initialize method at the same
X    time as instantiating the object in TCO is out of the TC User's
X    Manual. But again, it's tucked away in a macro, so how it's done
X    shouldn't really matter, right?
X
X[and now all the destructor/destroy method stuff]
X
XTCO: #define DECL_DEST(Class) void Destroy
X     #define DEF_DEST(Class)  void Class::Destroy
X     #define DestroyObject(Object) { Object->Destroy();delete(Object); }
X     #define DESTROY_SUPER inherited::Destroy()
X	 
XC++: #define DECL_DEST(Class) ~Class
X     #define DEF_DEST(Class) Class::~Class
X     #define DestroyObject(Object) delete Object
X     #define DESTROY_SUPER
X
X     These macros define the destroy/destructor methods for TCO and C++.
X     Example usage:
X
X       class Derived : INHERIT_PUBLIC SuperClass
X       {
X		/* stuff */
X
X		DECL_DEST(Derived)( /* args */ );
X       }
X
X       DEF_DEST(Derived)( /* args */ )
X       {
X		/* code */
X		
X		DESTROY_SUPER;
X       }
X
X       /* and to get rid of something */
X
X       Derived *dp;
X
X       DestroyObject(dp);
X
X     These macros are pretty straight forward. Things to watch out for:
X     I've chosen to call all destroy methods Destroy() in TCO. This means
X     that they must always take the same number of and type of arguments
X     for all derived classes. Since these methods rarely take arguments,
X     I chose to stick with this convention. If you want to append the 
X     class name in TCO, no problem: just use Destroy##Class, but then
X     you'd have to pass the class name as an argument as well....
X     
X     C++ automatically calls destructors up the inheritance hierarchy,
X     TCO doesn't (it's just another method in TCO), therefore you need
X     to use DESTROY_SUPER in TCO -- which just calls the super classes
X     Destroy() method, and does nothing in C++.
X
X------------------------------------------------------------------------
X
XThe Example Program
X
XAs an example, I've created a Link class which is used to create linked
Xlists. This is not intended to be the worlds best or most efficient 
Ximplementation of a linked list class, but I happen to find it useful
Xfor my work, and it serves as a good example for using the class.h macros.
X
XFirst off, the Link class is not to be used by itself, but to be inherited
Xfrom. It implements some basic funtions: append, prepend, insert and find.
XThose names should be self explanitory. These need not be redifined for
Xsub-classes, though you can if you want. There is a compare method which
Xis used by find and insert. For simplicity, it always takes a string  (char *)
Xas an argument and is used to find a link by name. The showval method is also
Xvirtual and defined for sub-classes and is used to print the contents of
Xthe current link.
X
XA link has a next, previous and tail pointer (i.e. it's doubly-linked).
XIn order for prepend to work properly, the first link (the head) never
Xchanges. That would require assigning to "this", which, as far as i'm
Xconcerned, is BAD news (and in fact not supported in cfront 2.0 or current
Xg++ implementations). So the head link doesn't contain any useful data
Xexcept for a pointer to the tail and a pointer to the real first link in
Xthe list (the next pointer).
X
XThere are three sub-classes of Link: IntLink a list of integers, StrLink:
Xa list of strings (char *'s), and ListLink: (which is derived from StrLink),
Xa list of links. The example program creates 2 lists, each containing a
Xmixture of StrLinks and IntLinks, and then creates a ListLink which contains
Xthose 2 lists. The lookup method (only in the ListLink class), is used to
Xsearch for an item by name in any of the lists contained in the ListLink, or
Xto search for the a list with that name. Yes this is confusing -- look at
Xthe source code!!!
X
XTo build the example:
X
X	- Use the Makefile for UNIX and C++.
X
X	- Create a THINK C project with all the .c files and the
X	  ANSI and oops libraries.
X
X----------------------------------------------------------------------------
X
XIf you have any questions, feel free to send me e-mail. And, if you've got
Xsome suggestions and improvements, please send them along!! I hope someone
Xfinds this stuff useful. Enjoy!!
X
X* Isaac J. Salzman					      ----     
X* The RAND Corporation - Information Sciences Dept.	     /o o/  /  
X* 1700 Main St., PO Box 2138, Santa Monica, CA 90406-2138    | v |  |  
X* AT&T	    : +1 213-393-0411 x6421 or x7923 (ISL lab)	    _|	 |_/   
X* Internet  : salzman@rand.org				   / |	 |
X* UUCP	    : !uunet!rand.org!salzman			   | |	 |     
X* CompuServe: 76167,1046
END_OF_FILE
if test 15093 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'linktest.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'linktest.c'\"
else
echo shar: Extracting \"'linktest.c'\" \(2571 characters\)
sed "s/^X//" >'linktest.c' <<'END_OF_FILE'
X/* -*- Emacs Mode: C++ -*- */
X
X/*	linktest.c - test program for Link class & subclasses
X
X	Copyright (C) 1989, Integrity Software
X	Author: Isaac J. Salzman (salzman@rand.org)
X
X	This software may be freely used/modified/distributed
X	as desired so long as this copyright notice remains
X	in tact.
X*/
X
X#ifndef lint
Xstatic char *RcsId = "$Header: /tmp_mnt/amnt/lh/salzman/src/class/RCS/linktest.c,v 1.1 89/09/17 15:01:26 salzman Exp Locker: salzman $";
X#endif
X
X/*
X * $Log:	linktest.c,v $
X * Revision 1.1  89/09/17  15:01:26  salzman
X * Initial revision
X * 
X */
X
X#include <stdio.h>
X#ifdef THINK_C
X#include <stdlib.h>
X#else
X#ifdef __GNUG__
X#include <std.h>
X#endif
X#endif
X
X#include "strlink.h"
X#include "intlink.h"
X#include "listlink.h"
X
Xmain()
X{
X    Link *list1, *list2;
X    ListLink *listlist;
X    
X    char s[100], *gets(char *);
X    
X    /* create the lists */
X    list1 = MakeObject(Link)();
X    list2 = MakeObject(Link)();
X    
X    /* the params to MakeObject are essentially ignored for first link */
X    listlist = MakeObject(ListLink)("a list of lists", (Link *)NULL);
X    
X    /* put some stuff in first list -- mix strings & int's, start with
X       a prepend
X    */
X    
X    list1->prepend(MakeObject(StrLink)("item 0"));
X    list1->prepend(MakeObject(IntLink)(0));
X    list1->append(MakeObject(StrLink)("item 1"));
X    list1->append(MakeObject(IntLink)(1));
X    list1->prepend(MakeObject(StrLink)("item 2"));
X    list1->prepend(MakeObject(IntLink)(2));
X    list1->append(MakeObject(StrLink)("item 3"));
X    list1->append(MakeObject(IntLink)(3));
X
X	/* put stuff in second list -- again mixing srings & int's, but
X	   start with an append
X	*/
X	
X    list2->append(MakeObject(StrLink)("item 4"));
X    list2->append(MakeObject(IntLink)(4));
X    list2->prepend(MakeObject(StrLink)("item 5"));
X    list2->prepend(MakeObject(IntLink)(5));
X    list2->append(MakeObject(StrLink)("item 6"));
X    list2->append(MakeObject(IntLink)(6));
X    list2->prepend(MakeObject(StrLink)("item 7"));
X    list2->prepend(MakeObject(IntLink)(7));
X
X	/* now append the to lists to our list list */
X	
X	listlist->append(MakeObject(ListLink)("list 1", list1));
X	listlist->append(MakeObject(ListLink)("list 2", list2));
X
X	/* and see if we can find anything! */
X	
X    for (;;)
X      {
X	  	printf("enter item to search for: ");
X	  	if (gets(s) == NULL)	/* until ^D */
X	      break;
X	      
X	  	listlist->lookup(s);
X      }
X    
X    printf("\n");
X    
X    listlist->showlist();		/* show entire list */
X    
X    DestroyObject(listlist);
X    DestroyObject(list1);
X    DestroyObject(list2);
X
X    exit(0);
X}
END_OF_FILE
if test 2571 -ne `wc -c <'linktest.c'`; then
    echo shar: \"'linktest.c'\" unpacked with wrong size!
fi
# end of 'linktest.c'
fi
if test -f 'link.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'link.c'\"
else
echo shar: Extracting \"'link.c'\" \(3744 characters\)
sed "s/^X//" >'link.c' <<'END_OF_FILE'
X/* -*- Emacs Mode: C++ -*- */
X
X/*	link.c - Link Class implementation
X
X	Copyright (C) 1989, Integrity Software
X	Author: Isaac J. Salzman (salzman@rand.org)
X
X	This software may be freely used/modified/distributed
X	as desired so long as this copyright notice remains
X	in tact.
X
X*/
X
X#ifndef lint
Xstatic char *RcsId = "$Header: /tmp_mnt/amnt/lh/salzman/src/class/RCS/link.c,v 1.1 89/09/17 15:01:28 salzman Exp Locker: salzman $";
X#endif
X
X/*
X * $Log:	link.c,v $
X * Revision 1.1  89/09/17  15:01:28  salzman
X * Initial revision
X * 
X */
X
X#include <stdio.h>
X
X#include "link.h"
X
X/* just set all ptr's to 0 ... */
X
XDEF_INIT(Link)()
X{
X    nextp = (Link *)0;
X    prevp = (Link *)0;
X    tailp = (Link *)0;
X    
X    RETURN_THIS;
X}
X
X/* DANGER DANGER -- calling a destructor recursively! this starts from the
X   head of the list and deletes all links. the tail link needs to be
X   deleted first, and the work backwards - so we'll use recursion
X*/
X
XDEF_DEST(Link)(void)
X{
X    if (nextp)
X      {
X#ifdef DEBUG
X	  	printf("destroying next object. this is ...\n");
X	 	showval();
X#endif
X	  	DestroyObject(nextp);
X      }
X#ifdef DEBUG
X    else
X      {
X	  	printf("destroy: this is last object...\n");
X	  	showval();
X      }
X#endif
X}
X
X/* return a pointer to the next link */
X
XLink *Link::next(void)
X{
X    return nextp;
X}
X
X/*  return a pointer to the previous link */
X
XLink *Link::prev(void)
X{
X    return prevp;
X}
X
X/* append to tail of list */
X
Xint Link::append(class Link *l)
X{
X    if (! l)
X      {
X		fprintf(stderr,"error - can't append nil link into list\n");
X		return ERROR;
X      }
X    
X    if (! nextp)	/* this is only link in list */
X      {
X      	nextp = l;
X    	tailp = l;
X    	l->prevp = this;
X       }
X     else
X       {
X       	l->prevp = tailp;
X       	tailp->nextp = l; /* this was of course nil, should assert this */
X       	tailp = l;
X       }
X    return OK;
X}
X
X
X/* instert a new link into list at some position determined by
X   the results of the compare method. this is an exercize
X   for the reader (i.e. i'm lazy and haven't done it yet! :-)
X*/
X
Xint Link::insert(class Link *l)
X{
X	return OK;
X}
X
X/* insert a new link at the head of the list */
X
Xint Link::prepend(class Link *l)
X{
X    if (! l)
X      {
X		fprintf(stderr,"error - can't prepend nil link into list\n");
X		return ERROR;
X      }
X 
X    if (!nextp)		/* new head link */
X    {
X		nextp = l;
X		l->prevp = this;
X		tailp = l;
X	}
X	else			/* push some ptr's around... */
X	{
X		l->nextp = nextp;
X		nextp->prevp = l;
X		nextp = l;
X		l->tailp = l->nextp;
X	}
X	
X	return OK;
X}
X
X/* forward traverse list and call showval method for each
X   link. -- head of list is really the first nextp....
X*/
X
Xvoid Link::showlist(void)
X{
X	register class Link *lp;
X	register int i;
X	
X	for(i=0,lp=nextp; lp; lp = lp->nextp, i++)
X	{
X		printf("link %05d: ", i);
X		lp->showval();
X	}
X}
X
X/* same as above in reverse order  */
X
Xvoid Link::rshowlist(void)
X{
X	register class Link *lp;
X	register int i;
X	
X	for(i=0,lp=tailp; lp && lp->prevp ; lp = lp->prevp, i++)
X	{
X		printf("link %05d: ", i);
X		lp->showval();
X	}
X}
X
X/* this be virtual -- redefined for derived classes */
X
Xvoid Link::showval(void)
X{
X	printf("[showval: no value in Link base class]\n");
X}
X
X/* returns 0 if equal, < 0 if item less than this, > 0 if item > this */
X
Xint Link::compare(char *item)
X{
X    printf("[no compare method defined for Link base class]\n");
X    return -1;
X}
X
X/* find an item given some string to look it up by. just calls the compare
X   method -- returns ptr to the link, 0 if not found. linear search to
X   end of list -- yes, inefficient.
X*/
X
XLink *Link::find(char * item)
X{
X    register Link *lp;
X    
X    for (lp=nextp; lp ; lp = lp->nextp)
X      {
X	  if (lp->compare(item) == 0)
X	    {
X			return lp;
X	    }
X      }
X
X    return (Link *) 0;
X}
END_OF_FILE
if test 3744 -ne `wc -c <'link.c'`; then
    echo shar: \"'link.c'\" unpacked with wrong size!
fi
# end of 'link.c'
fi
if test -f 'strlink.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'strlink.c'\"
else
echo shar: Extracting \"'strlink.c'\" \(884 characters\)
sed "s/^X//" >'strlink.c' <<'END_OF_FILE'
X/* -*- Emacs Mode: C++ -*- */
X
X/*	strlink.c - StrLink Class - implementation
X
X	Copyright (C) 1989, Integrity Software
X	Author: Isaac J. Salzman (salzman@rand.org)
X
X	This software may be freely used/modified/distributed
X	as desired so long as this copyright notice remains
X	in tact.
X*/
X
X#ifndef lint
Xstatic char *RcsId = "$Header: /tmp_mnt/amnt/lh/salzman/src/class/RCS/strlink.c,v 1.1 89/09/17 15:01:29 salzman Exp Locker: salzman $";
X#endif
X
X/*
X * $Log:	strlink.c,v $
X * Revision 1.1  89/09/17  15:01:29  salzman
X * Initial revision
X * 
X */
X
X#include <stdio.h>
X#include <string.h>
X
X#include "strlink.h"
X
XDEF_INIT(StrLink)(char *s)
X{
X    string = s;
X
X    INIT_SUPER(Link,());
X    
X    RETURN_THIS;
X}
X
XDEF_DEST(StrLink)(void)
X{
X	DESTROY_SUPER;
X}
X
Xvoid StrLink::showval(void)
X{
X	printf("string = %s\n", string);
X}
X
Xint StrLink::compare(char *item)
X{
X    return(strcmp(string, item));
X}
END_OF_FILE
if test 884 -ne `wc -c <'strlink.c'`; then
    echo shar: \"'strlink.c'\" unpacked with wrong size!
fi
# end of 'strlink.c'
fi
if test -f 'intlink.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'intlink.c'\"
else
echo shar: Extracting \"'intlink.c'\" \(1001 characters\)
sed "s/^X//" >'intlink.c' <<'END_OF_FILE'
X/* -*- Emacs Mode: C++ -*- */
X
X/*	intlink.c - IntLink Class - implementation
X
X	Copyright (C) 1989, Integrity Software
X	Author: Isaac J. Salzman (salzman@rand.org)
X
X	This software may be freely used/modified/distributed
X	as desired so long as this copyright notice remains
X	in tact.
X*/
X
X#ifndef lint
Xstatic char *RcsId = "$Header: /tmp_mnt/amnt/lh/salzman/src/class/RCS/intlink.c,v 1.1 89/09/17 15:01:30 salzman Exp Locker: salzman $";
X#endif
X
X/*
X * $Log:	intlink.c,v $
X * Revision 1.1  89/09/17  15:01:30  salzman
X * Initial revision
X * 
X */
X
X#include <stdio.h>
X#include <string.h>
X#include <ctype.h>
X
X#include "intlink.h"
X
XDEF_INIT(IntLink)(int i)
X{
X    ival = i;
X
X    INIT_SUPER(Link,());
X    
X    RETURN_THIS;
X}
X
XDEF_DEST(IntLink)(void)
X{
X	DESTROY_SUPER;
X}
X
Xvoid IntLink::showval(void)
X{
X	printf("integer = %d\n", ival);
X}
X
Xint IntLink::compare(char *item)
X{
X    int i;
X
X    if (!isdigit (*item))
X		return -1;
X    
X    i = atoi(item);
X    
X    return (( i == ival) ? 0 : (( i < ival) ? -1 : 1));
X}
END_OF_FILE
if test 1001 -ne `wc -c <'intlink.c'`; then
    echo shar: \"'intlink.c'\" unpacked with wrong size!
fi
# end of 'intlink.c'
fi
if test -f 'listlink.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'listlink.c'\"
else
echo shar: Extracting \"'listlink.c'\" \(1858 characters\)
sed "s/^X//" >'listlink.c' <<'END_OF_FILE'
X/* -*- Emacs Mode: C++ -*- */
X
X/*	listlink.c - ListLink Class implementation
X
X	Copyright (C) 1989, Integrity Software
X	Author: Isaac J. Salzman (salzman@rand.org)
X
X	This software may be freely used/modified/distributed
X	as desired so long as this copyright notice remains
X	in tact.
X*/
X
X#ifndef lint
Xstatic char *RcsId = "$Header: /tmp_mnt/amnt/lh/salzman/src/class/RCS/listlink.c,v 1.1 89/09/17 15:01:32 salzman Exp Locker: salzman $";
X#endif
X
X/*
X * $Log:	listlink.c,v $
X * Revision 1.1  89/09/17  15:01:32  salzman
X * Initial revision
X * 
X */
X
X#include <stdio.h>
X#include <string.h>
X
X#include "listlink.h"
X
XDEF_INIT(ListLink)(char *str, Link *lp) SUPER_INIT_ARGS((str))
X{
X    list = lp;
X
X    INIT_SUPER(StrLink,(str));
X    
X    RETURN_THIS;
X}
X
XDEF_DEST(ListLink)(void)
X{
X	/* we *could* destroy all our member lists, but that's not
X	   necessarily a good idea since they should be able to go
X	   on living when this object dies -- and should be destroyed
X	   explicitly.
X	*/
X	   
X	DESTROY_SUPER;
X}
X
Xvoid ListLink::showval(void)
X{
X	printf("list name = %s\n", string);
X	if (list)
X		list->showlist();
X}
X
X/* this method looks for a string in one of our sublists, or looks to
X   see if it's the name of one of our sub lists, in which case it will
X   display the contents of the entire sub list.
X*/
X
Xvoid ListLink::lookup(char *item)
X{
X	register Link *lpp;
X	register ListLink *lp;
X	
X	if (lp = (ListLink *) find(item))
X	  {
X	  	printf("found list called \"%s\"\n", item);
X	  	lp->showval();
X	  	return ;
X	  }
X	else
X	  {
X	  	for (lp=(ListLink *) next();lp;lp = (ListLink *) lp->next())
X	  	{
X	  		if (lpp = lp->list->find(item))
X	  		{
X	  			printf("found item \"%s\" in list \"%s\"\n", item, 
X	  				lp->string);
X	  			lpp->showval();
X	  			return ;
X	  		}
X	  	}
X	}
X	
X	/* this is never reached if something's found */
X	printf("item \"%s\" not found\n", item);
X	
X}
X
END_OF_FILE
if test 1858 -ne `wc -c <'listlink.c'`; then
    echo shar: \"'listlink.c'\" unpacked with wrong size!
fi
# end of 'listlink.c'
fi
if test -f 'link.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'link.h'\"
else
echo shar: Extracting \"'link.h'\" \(1259 characters\)
sed "s/^X//" >'link.h' <<'END_OF_FILE'
X/* -*- Emacs Mode: C++ -*- */
X
X/*	link.h - Link Class header
X
X	Copyright (C) 1989, Integrity Software
X	Author: Isaac J. Salzman (salzman@rand.org)
X
X	This software may be freely used/modified/distributed
X	as desired so long as this copyright notice remains
X	in tact.
X*/
X
X/*
X *------------------------------------------------------------------
X * $Header: /tmp_mnt/amnt/lh/salzman/src/class/RCS/link.h,v 1.1 89/09/17 15:01:33 salzman Exp Locker: salzman $
X *------------------------------------------------------------------
X * $Log:	link.h,v $
X * Revision 1.1  89/09/17  15:01:33  salzman
X * Initial revision
X * 
X*/
X
X/*  linked list class for C++/THINK Object C */
X
X#ifndef _H_link
X#define _H_link
X
X#include "class.h"
X#include "defs.h"
X
XPREDEC_CLASS(Link);
X
Xclass Link ROOT		/* this is a root class! */
X{
X  PRIVATE
X    class Link *nextp;
X    class Link *prevp;
X    class Link *tailp;
X
X  PUBLIC
X    DECL_INIT(Link)();
X    DECL_DEST(Link)(void);
X    
X    int append(Link *);
X    int prepend(Link *);
X    int insert(Link *);
X
X    class Link *next(void);
X    class Link *prev(void);
X
X    void showlist(void);
X    void rshowlist(void);
X
X    class Link *find(char *);
X
X    virtual void showval(void);
X
X    virtual int compare(char *);
X
X    
X};
X
X#endif /* _H_link */
END_OF_FILE
if test 1259 -ne `wc -c <'link.h'`; then
    echo shar: \"'link.h'\" unpacked with wrong size!
fi
# end of 'link.h'
fi
if test -f 'listlink.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'listlink.h'\"
else
echo shar: Extracting \"'listlink.h'\" \(960 characters\)
sed "s/^X//" >'listlink.h' <<'END_OF_FILE'
X/* -*- Emacs Mode: C++ -*- */
X
X/*	listlink.h - ListLink Class header (linked list of linked lists)
X
X	Copyright (C) 1989, Integrity Software
X	Author: Isaac J. Salzman (salzman@rand.org)
X
X	This software may be freely used/modified/distributed
X	as desired so long as this copyright notice remains
X	in tact.
X*/
X
X/*
X *------------------------------------------------------------------
X * $Header: /tmp_mnt/amnt/lh/salzman/src/class/RCS/listlink.h,v 1.1 89/09/17 15:01:34 salzman Exp Locker: salzman $
X *------------------------------------------------------------------
X * $Log:	listlink.h,v $
X * Revision 1.1  89/09/17  15:01:34  salzman
X * Initial revision
X * 
X*/
X
X#ifndef _H_listlink
X#define _H_listlink
X
X#include "strlink.h"
X
X
Xclass ListLink : INHERIT_PUBLIC StrLink
X{
XPRIVATE
X	Link *list;
X	
XPUBLIC	
X	DECL_INIT(ListLink)(char *, Link *);
X	DECL_DEST(ListLink)(void);
X	void showval(void);
X	void lookup(char *); /* uses find -- searches each sublist */
X};
X
X#endif
END_OF_FILE
if test 960 -ne `wc -c <'listlink.h'`; then
    echo shar: \"'listlink.h'\" unpacked with wrong size!
fi
# end of 'listlink.h'
fi
if test -f 'strlink.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'strlink.h'\"
else
echo shar: Extracting \"'strlink.h'\" \(945 characters\)
sed "s/^X//" >'strlink.h' <<'END_OF_FILE'
X/* -*- Emacs Mode: C++ -*- */
X
X/*	strlink.h  - StrLink Class header (linked list of strings)
X
X	Copyright (C) 1989, Integrity Software
X	Author: Isaac J. Salzman (salzman@rand.org)
X
X	This software may be freely used/modified/distributed
X	as desired so long as this copyright notice remains
X	in tact.
X*/
X
X/*
X *------------------------------------------------------------------
X * $Header: /tmp_mnt/amnt/lh/salzman/src/class/RCS/strlink.h,v 1.1 89/09/17 15:01:36 salzman Exp Locker: salzman $
X *------------------------------------------------------------------
X * $Log:	strlink.h,v $
X * Revision 1.1  89/09/17  15:01:36  salzman
X * Initial revision
X * 
X*/
X
X#ifndef _H_strlink
X#define _H_strlink
X
X#include "link.h"
X
Xclass StrLink : INHERIT_PUBLIC Link
X{
XPROTECTED	/* our descendants can access this member */
X	char *string;
X	
XPUBLIC	
X	DECL_INIT(StrLink)(char *);
X	DECL_DEST(StrLink)(void);
X	
X	void showval(void);
X    int compare(char *);
X};
X
X#endif
END_OF_FILE
if test 945 -ne `wc -c <'strlink.h'`; then
    echo shar: \"'strlink.h'\" unpacked with wrong size!
fi
# end of 'strlink.h'
fi
if test -f 'intlink.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'intlink.h'\"
else
echo shar: Extracting \"'intlink.h'\" \(899 characters\)
sed "s/^X//" >'intlink.h' <<'END_OF_FILE'
X/* -*- Emacs Mode: C++ -*- */
X
X/*	intlink.h - IntLink Class header (linked list of integers)
X
X	Copyright (C) 1989, Integrity Software
X	Author: Isaac J. Salzman (salzman@rand.org)
X
X	This software may be freely used/modified/distributed
X	as desired so long as this copyright notice remains
X	in tact.
X*/
X
X/*
X *------------------------------------------------------------------
X * $Header: /tmp_mnt/amnt/lh/salzman/src/class/RCS/intlink.h,v 1.1 89/09/17 15:01:37 salzman Exp Locker: salzman $
X *------------------------------------------------------------------
X * $Log:	intlink.h,v $
X * Revision 1.1  89/09/17  15:01:37  salzman
X * Initial revision
X * 
X */
X
X#ifndef _H_intlink
X#define _H_intlink
X
X#include "link.h"
X
Xclass IntLink : INHERIT_PUBLIC Link
X{
XPRIVATE
X        int ival;
X	
XPUBLIC	
X	DECL_INIT(IntLink)(int);
X	DECL_DEST(IntLink)(void);
X	
X	void showval(void);
X    int compare(char *);
X};
X
X#endif
END_OF_FILE
if test 899 -ne `wc -c <'intlink.h'`; then
    echo shar: \"'intlink.h'\" unpacked with wrong size!
fi
# end of 'intlink.h'
fi
if test -f 'class.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'class.h'\"
else
echo shar: Extracting \"'class.h'\" \(2341 characters\)
sed "s/^X//" >'class.h' <<'END_OF_FILE'
X/* -*-Emacs Mode: C++ -*- */
X
X/*	class.h - Macros for Portable C++/THINK C4.0 Object programs
X
X	Copyright (C) 1989, Integrity Software
X	Author: Isaac J. Salzman (salzman@rand.org)
X
X	This software may be freely used/modified/distributed
X	as desired so long as this copyright notice remains
X	in tact.
X*/
X
X/*
X *------------------------------------------------------------------
X * $Header: /tmp_mnt/amnt/lh/salzman/src/class/RCS/class.h,v 1.1 89/09/17 15:01:38 salzman Exp Locker: salzman $
X *------------------------------------------------------------------
X * $Log:	class.h,v $
X * Revision 1.1  89/09/17  15:01:38  salzman
X * Initial revision
X * 
X */
X
X/*
X	Some pre-processor macros for writing *portable* C++ and THINK C
X	Object programs.
X*/
X
X#ifndef _H_class
X#define _H_class
X
X#ifdef THINK_C
X# include <oops.h>  /* a must for THINK C */
X
X  /* things needed for declaring classes */
X# define class struct
X# define virtual
X# define ROOT : indirect
X# define PROTECTED
X# define PRIVATE
X# define PUBLIC
X# define PREDEC_CLASS(Class)
X# define INHERIT_PUBLIC
X
X  /* things needed for initialization */
X# define DECL_INIT(Class) Class *Init##Class
X# define DEF_INIT(Class) Class *Class::Init##Class
X# define MakeObject(Class) ((Class *)new (Class))->Init##Class
X# define INIT_SUPER(Class,args) Class::Init##Class args
X# define SUPER_INIT_ARGS(args)
X# define RETURN_THIS return this
X
X  /* things needed for destroying objects */
X# define DECL_DEST(Class) void Destroy
X# define DEF_DEST(Class)  void Class::Destroy
X# define DestroyObject(Object) { Object->Destroy();delete(Object); }
X# define DESTROY_SUPER inherited::Destroy()
X
X#else /* C++ */
X  /* things needed for declaring classes */
X  /* class and virtual are keywords */
X# define ROOT
X# define PROTECTED protected:
X# define PRIVATE private:
X# define PUBLIC public:
X# define PREDEC_CLASS(Class) class Class 
X# define INHERIT_PUBLIC public
X
X  /* things needed for initialization */
X# define DECL_INIT(Class) Class
X# define DEF_INIT(Class) Class::Class
X# define MakeObject(Class) new Class
X# define INIT_SUPER(Class,args)
X# define SUPER_INIT_ARGS(args) : args
X# define RETURN_THIS
X
X  /* things needed for destroying objects */
X# define DECL_DEST(Class) ~Class
X# define DEF_DEST(Class) Class::~Class
X# define DestroyObject(Object) delete Object
X# define DESTROY_SUPER
X
X#endif
X
X#endif /* _H_class */
END_OF_FILE
if test 2341 -ne `wc -c <'class.h'`; then
    echo shar: \"'class.h'\" unpacked with wrong size!
fi
# end of 'class.h'
fi
if test -f 'defs.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'defs.h'\"
else
echo shar: Extracting \"'defs.h'\" \(751 characters\)
sed "s/^X//" >'defs.h' <<'END_OF_FILE'
X/* -*- Emacs Mode: C++ -*- */
X
X/*	defs.h - some macro definitions (DEBUG, ERROR, etc.).
X
X	Copyright (C) 1989, Integrity Software
X	Author: Isaac J. Salzman (salzman@rand.org)
X
X	This software may be freely used/modified/distributed
X	as desired so long as this copyright notice remains
X	in tact.
X*/
X
X/*
X *------------------------------------------------------------------
X * $Header: /tmp_mnt/amnt/lh/salzman/src/class/RCS/defs.h,v 1.1 89/09/17 15:01:40 salzman Exp Locker: salzman $
X *------------------------------------------------------------------
X * $Log:	defs.h,v $
X * Revision 1.1  89/09/17  15:01:40  salzman
X * Initial revision
X * 
X */
X
X/* defs.h */
X
X#ifndef _H_defs
X#define _H_defs
X
X#define DEBUG /**/
X
X#define ERROR (-1)
X#define OK 0
X
X#endif
END_OF_FILE
if test 751 -ne `wc -c <'defs.h'`; then
    echo shar: \"'defs.h'\" unpacked with wrong size!
fi
# end of 'defs.h'
fi
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(923 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X# Makefile for Link class example of C++/THINK C object portablity macros
X#
XOBJS=linktest.o link.o strlink.o intlink.o listlink.o
XSRCS=linktest.c link.c strlink.c intlink.c listlink.c
XHDRS=link.h listlink.h strlink.h intlink.h class.h defs.h
X
XCC=g++
XCFLAGS=-g
XLFLAGS=-g
X
XVERSION=
X
X.c.o:
X	${CC} -c ${CFLAGS} $<
X
Xlinktest: ${OBJS}
X	${CC} ${LFLAGS} -o linktest ${OBJS}
X
Xtcoplus.tar: README ${SRCS} ${HDRS} Makefile
X	tar cvf tcoplus.tar README ${SRCS} ${HDRS} Makefile
X
Xtcoplus.shar: README Makefile ${SRCS} ${HDRS}
X	shar README ${SRCS} ${HDRS} Makefile > tcoplus.shar
X
Xtags: ${SRCS} ${HDRS}
X	etags ${SRCS} ${HDRS}
X
Xcheckin: ${SRCS} ${HDRS} README
X	ci -l ${VERSION} ${SRCS} ${HDRS} README
X
Xlinktest.o: class.h defs.h link.h strlink.h intlink.h listlink.h
Xlink.o: class.h  defs.h link.h
Xstrlink.o: class.h defs.h link.h strlink.h
Xintlink.o: class.h defs.h link.h intlink.h
Xlistlink.o: class.h defs.h link.h strlink.h listlink.h
END_OF_FILE
if test 923 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
echo shar: End of shell archive.
exit 0