[pe.cust.sources] Little Smalltalk Source, *New* Part 17 of 20

earlw@pesnta.UUCP (Earl Wallace) (06/13/85)

#! /bin/sh 
#
# This is an another posting of the Little Smalltalk source, the last posting
# of this source went out in 5 parts and they were too big (>200k) for most
# sites so I redid the whole mess to keep the files around the 50k range.
#
# The complete set is now 20 parts.
#
# P.S. - If you don't receive all 20 parts within 5 days, drop me a line.
#	 Also, I have the Rand sources of May 1984, if someone has a more
#	 updated copy, I'll be happy to post them (or YOU can post them :-))
# 
# -earlw@pesnta
#
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	sources/primitive.c
#	sources/primitive.h
#	sources/process.c
#	sources/process.h
#	sources/sstr.c
#	sources/string.c
#	sources/string.h
#	sources/symbol.c
# This archive created: Thu Jun 13 11:33:05 1985
# By:	Earl Wallace (Perkin-Elmer Data Systems Group / Customer Service)
export PATH; PATH=/bin:$PATH
if test -f 'sources/primitive.c'
then
	echo shar: will not over-write existing file "'sources/primitive.c'"
else
cat << \SHAR_EOF > 'sources/primitive.c'
/* 
	Little Smalltalk

	Primitive manager
	timothy a. budd
	10/84

		hashcode code written by Robert McConeghy
			(who also wrote classes Dictionary, et al).
*/
/*
	The source code for the Little Smalltalk System may be freely
	copied provided that the source of all files is acknowledged
	and that this condition is copied with each file.

	The Little Smalltalk System is distributed without responsibility
	for the performance of the program and without any guarantee of
	maintenance.

	All questions concerning Little Smalltalk should be addressed to:

		Professor Tim Budd
		Department of Computer Science
		The University of Arizona
		Tucson, Arizona
		85721
		USA
*/
# include <stdio.h>
# include <ctype.h>
# include <math.h>
# include <errno.h>
# include "object.h"
# include "drive.h"
# include "interp.h"
# include "process.h"
# include "block.h"
# include "string.h"
# include "symbol.h"
# include "number.h"
# include "file.h"
# include "byte.h"
# include "primitive.h"

extern int errno;
extern int prntcmd;
extern double modf();
extern long time();
extern object *lookup_class();
extern process *runningProcess;
extern int responds_to(), generality();
extern class  *mk_class();
extern object *o_object, *o_true, *o_false, *o_nil, *o_number, *o_magnitude;

object *primitive(primnumber, numargs, args)
int primnumber, numargs;
object **args;
{	object *resultobj;
	object *leftarg, *rightarg, *fnd_class(), *fnd_super();
	int    leftint, rightint, i, j;
	double leftfloat, rightfloat;
	long   clock;
	char   *leftp, *rightp, *errp;
	class  *aClass;
	bytearray *byarray;
	struct file_struct *phil;
	int    opnumber = primnumber % 10;
	char   strbuffer[300], tempname[100];

	errno = 0;
	/* first do argument type checking */
	switch(i = (primnumber / 10)) {
		case 0: /* misc operations */
			if (opnumber <= 5 && numargs != 1) goto argcerror;
			leftarg = args[0];
			break;

		case 1: /* integer operations */
		case 2: 
			if (numargs != 2) goto argcerror;
			rightarg = args[1];
			if (! is_integer(rightarg)) goto argterror;
			rightint = int_value(rightarg);
		case 3: 
			if (i == 3 && opnumber && numargs != 1) 
				goto argcerror;
			leftarg = args[0];
			if (! is_integer(leftarg)) goto argterror;
			leftint = int_value(leftarg);
			break;

		case 4: /* character operations */
			if (numargs != 2) goto argcerror;
			rightarg = args[1];
			if (! is_character(rightarg)) goto argterror;
			rightint = int_value(rightarg);
		case 5: 
			if (i == 5 && numargs != 1) goto argcerror;
			leftarg = args[0];
			if (! is_character(leftarg)) goto argterror;
			leftint = int_value(leftarg);
			break;

		case 6: /* floating point operations */
			if (numargs != 2) goto argcerror;
			rightarg = args[1];
			if (! is_float(rightarg)) goto argterror;
			rightfloat = float_value(rightarg);
		case 7: 
			if (i == 7 && numargs != 1) goto argcerror;
		case 8:
			if (i == 8 && opnumber < 8 && numargs != 1) 
				goto argcerror;
			leftarg = args[0];
			if (! is_float(leftarg)) goto argterror;
			leftfloat = float_value(leftarg);
			break;

		case 9: /* symbol operations */
			leftarg = args[0];
			if (! is_symbol(leftarg)) goto argterror;
			leftp = symbol_value(leftarg);
			break;

		case 10: /* string operations */
			if (numargs < 1) goto argcerror;
			leftarg = args[0];
			if (! is_string(leftarg)) goto argterror;
			leftp = string_value(leftarg);
			if (opnumber && opnumber <= 3) {
				if (numargs != 2) goto argcerror;
				rightarg = args[1];
				if (! is_string(rightarg)) goto argterror;
				rightp = string_value(rightarg);
				}
			else if ((opnumber >= 4) && (opnumber <= 6)) {
				if (numargs < 2) goto argcerror;
				if (! is_integer(args[1])) goto argterror;
				i = int_value(args[1])-1;
				if ((i < 0) || (i >= strlen(leftp)))
					goto indexerror;
				}
			break;

		case 11: /* misc operations */
			if ((opnumber == 1) || (opnumber == 2)) {
				if (is_bltin(args[0])) goto argterror;
				if (numargs < 2) goto argcerror;
				if (! is_integer(args[1])) goto argterror;
				i = int_value(args[1]);
				if (i < 1 || i > args[0]->size)
					goto indexerror;
				}
			else if ((opnumber >= 4) && (opnumber <= 6)) {
				if (numargs != 1) goto argcerror;
				if (! is_integer(args[0])) goto argterror;
				i = int_value(args[0]);
				if (i < 0) goto indexerror;
				}
			else if (opnumber >= 7) {
				if (numargs < 1) goto argcerror;
				if (! is_bytearray(args[0])) goto argterror;
				byarray = (bytearray *) args[0];
				if (opnumber >= 8) {
					if (numargs < 2) goto argcerror;
					if (! is_integer(args[1]))
						goto argterror;
					i = int_value(args[1]) - 1;
					if (i < 0 || i >= byarray->a_bsize)
						goto indexerror;
					}
				}
			break;

		case 12: /* string i/o operations */
			if (opnumber < 6) {
				if (numargs < 1) goto argcerror;
				leftarg = args[0];
				if (! is_string(leftarg)) goto argterror;
				leftp = string_value(leftarg);
				}
			break;

		case 13: /* operations on file */
			if (numargs < 1) goto argcerror;
			if (! is_file(args[0])) goto argterror;
			phil = (struct file_struct *) args[0];
			if (opnumber && (phil->fp == (FILE *) NULL)) {
				errp = "file must be open for operation";
				goto return_error;
				}
			break;

		case 15: /* operations on classes */
			if (opnumber < 3 && numargs != 1) goto argcerror;
			if (! is_class(args[0])) goto argterror;
			aClass = (class *) args[0];
			break;

		}


	/* now do operation */
	switch(primnumber) {

		case 1:		/* class of object */
			resultobj = fnd_class(args[0]);
			if (resultobj) goto return_obj;
			else goto return_nil;

		case 2:		/* get super_object */
			resultobj = fnd_super(args[0]);
			if (resultobj) goto return_obj;
			else goto return_nil;

		case 3:		/* see if class responds to new */
			leftint = 0;
			if (! is_class(args[0])) goto return_boolean;
			leftint = responds_to("new", (class *) args[0]);
			goto return_boolean;

		case 4:		/* compute size of object */
			leftint = args[0]->size;
			goto return_integer;

		case 5:		/* return hashnum of object */
			if (is_integer(leftarg))
				leftint = int_value(leftarg);
			else if (is_character(leftarg))
				leftint = int_value(leftarg);
			else if (is_symbol(leftarg))
				leftint = (int) symbol_value(leftarg);
			else if (is_string(leftarg)) {
				leftp = string_value(leftarg);
				leftint = 0;
				for(i = 0; *leftp != 0; leftp++){
					leftint += *leftp;
					i++;
					if(i > 5)
					   break;
					}
				}
			else /* for all other objects return address */
				leftint = (int) &leftarg;
			if (leftint < 0)
				leftint = -leftint;
			goto return_integer;

		case 6:		/* built in object type testing */
			if (numargs != 2) goto argcerror;
			leftint = (args[0]->size == args[1]->size);
			goto return_boolean;

		case 7:		/* object equality testing */
			if (numargs != 2) goto argcerror;
			leftint = (args[0] == args[1]);
			goto return_boolean;

		case 8:		/* toggle debugging flag */
			if (numargs == 0) {
				debug = 1 - debug;
				goto return_nil;
				}
			if (numargs != 2) goto argcerror;
			if (! is_integer(args[0])) goto argterror;
			if (! is_integer(args[1])) goto argterror;
			leftint = int_value(args[0]);
			rightint = int_value(args[1]);
			switch(leftint) {
				case 1: prntcmd = rightint; break;
				case 2: debug = rightint; break;
				}
			goto return_nil;

		case 9:		/* numerical generality comparison */
			if (numargs != 2) goto argcerror;
			leftint = 
				(generality(args[0]) > generality(args[1]));
			goto return_boolean;

		case 10:	/* integer addition */
			leftint += rightint;
			goto return_integer;

		case 11:	/* integer subtraction */
			leftint -= rightint;
			goto return_integer;

		case 12: case 42:
			leftint = (leftint < rightint);
			goto return_boolean;

		case 13: case 43:
			leftint = (leftint > rightint);
			goto return_boolean;

		case 14: case 44:
			leftint = (leftint <= rightint);
			goto return_boolean;

		case 15: case 45:
			leftint = (leftint >= rightint);
			goto return_boolean;

		case 16: case 46:
			leftint = (leftint == rightint);
			goto return_boolean;

		case 17: case 47:
			leftint = (leftint != rightint);
			goto return_boolean;

		case 18:
			leftint *= rightint;
			goto return_integer;

		case 19:	/* // integer */
			if (rightint == 0) goto numerror;
			i  = leftint / rightint;
			if ((leftint < 0) && (leftint % rightint))
				i -= 1;
			leftint = i;
			goto return_integer;

		case 20:	/* gcd of two integers */
			if (leftint == 0 || rightint == 0) goto numerror;
			if (leftint < 0) leftint = -leftint;
			if (rightint < 0) rightint = -rightint;
			if (leftint > rightint) 
				{i = leftint; leftint = rightint; rightint = i;}
			while (i = rightint % leftint)
				{rightint = leftint; leftint = i;}
			goto return_integer;
			
		case 21:	/* bitAt: */
			leftint = (leftint & (1 << rightint)) ? 1 : 0;
			goto return_integer;

		case 22:	/* logical bit-or */
			leftint |= rightint;
			goto return_integer;

		case 23:	/* logical bit-and */
			leftint &= rightint;
			goto return_integer;

		case 24:	/* logical bit-exclusive or */
			leftint ^= rightint;
			goto return_integer;

		case 25:	/* bit shift */
			if (rightint < 0)
				leftint >>= - rightint;
			else
				leftint <<= rightint;
			goto return_integer;

		case 26:	/* integer radix */
			if (rightint < 2 || rightint > 36) goto numerror;
			prnt_radix(leftint, rightint, strbuffer);
			goto return_string;

		case 28:
			if (rightint == 0) goto numerror;
			leftint /= rightint;
			goto return_integer;

		case 29:
			if (rightint == 0) goto numerror;
			leftint %= rightint;
			goto return_integer;

		case 30:	/* doPrimitive:withArguments: */
			if (numargs != 2) goto argcerror;
			resultobj = primitive(leftint, args[1]->size, 
				&args[1]->inst_var[0]);
			goto return_obj;

		case 32:	/* convert random int into random float */
			leftfloat = ((double) ((leftint/10) % 1000)) / 1000.0;
			goto return_float;

		case 33:	/* bit inverse */
			leftint ^= -1;
			goto return_integer;

		case 34:	/* highBit */
			rightint = leftint;
			for (leftint = 32; leftint >= 0; leftint--)
				if (rightint & (1 << leftint))
					goto return_integer;
			goto return_nil;

		case 35:	/* random number */
			srand(leftint);
			leftint = rand();
			goto return_integer;

		case 36:	/* convert integer to character */
			goto return_character;

		case 37:	/* convert integer to string */
			sprintf(strbuffer,"%d", leftint);
			goto return_string;

		case 38:	/* factorial */
			if (leftint < 0) goto numerror;
			if (leftint < FACTMAX) {
				for (i = 1; leftint; leftint--)
					i *= leftint;
				leftint = i;
				goto return_integer;
				}
# ifndef GAMMA
			/* gamma not supported, use float multiply */
			leftfloat = 1.0;
			if (leftint < 30) {
				for (i = 1; leftint; leftint--)
					leftfloat *= leftint;
				}
			goto return_float;
# endif
# ifdef GAMMA
			/* compute gamma */
			leftfloat = (double) (leftint + 1);
			sassign(leftarg, new_float(leftfloat));
			resultobj = primitive(GAMMAFUN, 1, &leftarg);
			obj_dec(leftarg);
			goto return_obj;
# endif

		case 39:	/* convert integer to float */
			leftfloat = (double) leftint;
			goto return_float;

		case 50:	/* digitValue */
			if (isdigit(leftint))
				leftint -= '0';
			else if (isupper(leftint)) {
				leftint -= 'A';
				leftint += 10;
				}
			else goto return_nil;
			goto return_integer;

		case 51:
			if (isupper(leftint)) leftint += 'a' - 'A';
			leftint = (leftint == 'a') || (leftint == 'e') ||
				  (leftint == 'i') || (leftint == 'o') ||
				  (leftint == 'u');
			goto return_boolean;

		case 52:
			leftint = isalpha(leftint);
			goto return_boolean;

		case 53:
			leftint = islower(leftint);
			goto return_boolean;

		case 54:
			leftint = isupper(leftint);
			goto return_boolean;

		case 55:
			leftint = isspace(leftint);
			goto return_boolean;

		case 56:
			leftint = isalnum(leftint);
			goto return_boolean;

		case 57:
			if (isupper(leftint)) leftint += 'a' - 'A';
			else if (islower(leftint)) leftint += 'A' - 'a';
			goto return_character;

		case 58:	/* convert character to string */
			sprintf(strbuffer,"%c", leftint);
			goto return_string;

		case 59:	/* convert character to integer */
			goto return_integer;

		case 60:	/* floating point addition */
			leftfloat += rightfloat;
			goto return_float;

		case 61:	/* floating point subtraction */
			leftfloat -= rightfloat;
			goto return_float;

		case 62:
			leftint = (leftfloat < rightfloat);
			goto return_boolean;

		case 63:
			leftint = (leftfloat > rightfloat);
			goto return_boolean;

		case 64:
			leftint = (leftfloat <= rightfloat);
			goto return_boolean;

		case 65:
			leftint = (leftfloat >= rightfloat);
			goto return_boolean;

		case 66:
			leftint = (leftfloat == rightfloat);
			goto return_boolean;

		case 67:
			leftint = (leftfloat != rightfloat);
			goto return_boolean;

		case 68:
			leftfloat *= rightfloat;
			goto return_float;

		case 69:
			if (rightfloat == 0) goto numerror;
			leftfloat /= rightfloat;
			goto return_float;

		case 70:
			leftfloat = log(leftfloat);
			goto float_check;

		case 71:
			if (leftfloat < 0) goto numerror;
			leftfloat = sqrt(leftfloat);
			goto float_check;

		case 72:
			leftint = (int) floor(leftfloat);
			goto return_integer;

		case 73:	/* ceiling */
			leftint = (int) ceil(leftfloat);
			goto return_integer;

		case 75:	/* integer part */
			leftfloat = modf(leftfloat, &rightfloat);
			leftint = (int) rightfloat;
			goto return_integer;

		case 76:	/* fractional part */
			leftfloat = modf(leftfloat, &rightfloat);
			goto return_float;

		case 77:	/* gamma function */
# ifdef GAMMA
			leftfloat = gamma(leftfloat);
			if (leftfloat > 88.0) goto numerror;
			leftfloat = exp(leftfloat);
			goto float_check;
# endif
# ifndef GAMMA
			errp = "gamma function";
			goto not_implemented;
# endif

		case 78:
			sprintf(strbuffer,"%g", leftfloat);
			goto return_string;

		case 79:
			leftfloat = exp(leftfloat);
			goto return_float;

		case 80:	/* normalize radian value */
# define TWOPI (double) 6.2831853072
			rightfloat = 
			floor(((leftfloat < 0) ? -leftfloat:leftfloat) / TWOPI);
			if (leftfloat < 0)
				leftfloat += (1 + rightfloat) * TWOPI;
			else
				leftfloat -= rightfloat * TWOPI;
			goto return_float;

		case 81:
			leftfloat = sin(leftfloat);
			goto float_check;

		case 82:
			leftfloat = cos(leftfloat);
			goto float_check;

		case 84:
			leftfloat = asin(leftfloat);
			goto float_check;

		case 85:
			leftfloat = acos(leftfloat);
			goto float_check;

		case 86:
			leftfloat = atan(leftfloat);
			goto float_check;

		case 88:
			if (numargs != 2) goto argcerror;
			if (! is_float(args[1])) goto argterror;
			leftfloat = pow(leftfloat, float_value(args[1]));
			goto float_check;

		case 89:	/* floating point radix */
			if (numargs != 2) goto argcerror;
			if (! is_integer(args[1])) goto argterror;
			i = int_value(args[1]); /* base */
			if (i < 2 || i > 36) goto numerror;
			fprnt_radix(leftfloat, i, strbuffer);
			goto return_string;

		case 91:	/* symbol comparison */
			if (numargs != 2) goto argcerror;
			if (! is_symbol(args[1])) goto argterror;
			leftint = (leftp == symbol_value(args[1]));
			goto return_boolean;

		case 92:	/* symbol printString */
			sprintf(strbuffer, "#%s", leftp);
			goto return_string;

		case 93:	/* symbol asString */
			sprintf(strbuffer, "%s", leftp);
			goto return_string;

		case 94:	/* symbol print ( with tabs) */
			if (numargs == 2) {
				if (! is_integer(args[1])) goto argterror;
				for (i = int_value(args[1]); i >= 0; i--)
					putchar('\t');
			}
			printf("%s\n", leftp);
# ifdef FLUSHREQ
			fflush(stdout);
# endif
			goto return_nil;

		case 96:
			goto return_nil;

		case 97:	/* make a new class (generated by parser)*/
			if (numargs != 8) goto argcerror;
			if (! is_symbol(args[1])) goto argterror;
			if (! is_symbol(args[2])) goto argterror;
			if (! is_integer(args[6])) goto argterror;
			if (! is_integer(args[7])) goto argterror;
			resultobj = (object *) mk_class(leftp, args);
			goto return_obj;

		case 98:	/* install class in dictionary */
			if (numargs != 2) goto argcerror;
			if (! is_class(args[1])) goto argterror;
			enter_class(leftp, args[1]);
			goto return_nil;

		case 99:	/* find a class in class dictionary */
			if (numargs != 1) goto argcerror;
			resultobj = lookup_class(leftp);
			if (resultobj == (object *) 0) {
				sprintf(strbuffer,"cannot find class %s",
				leftp);
				sassign(resultobj, new_str(strbuffer));
				primitive(ERRPRINT, 1, &resultobj);
				obj_dec(resultobj);
				resultobj = lookup_class("Object");
				if (! resultobj) cant_happen(7);
				}
			goto return_obj;

		case 100:	/* string length */
			leftint = strlen(leftp);
			goto return_integer;

		case 101: 	/* string compare, case dependent */
			leftint = strcmp(leftp, rightp);
			goto return_integer;

		case 102:	/* string compare, case independent */
			leftint = 1;
			while (*leftp || *rightp) {
				i = *leftp++;
				j = *rightp++;
				if (i >= 'A' && i <= 'Z')
					i = i - 'A' + 'a';
				if (j >= 'A' && j <= 'Z')
					j = j - 'A' + 'a';
				if (i != j) {leftint = 0; break;}
				}
			goto return_boolean;

		case 103: 	/* string catenation */
			for (i = leftint = 0; i < numargs; i++) {
				if (! is_string(args[i])) goto argterror;
				leftint += strlen(string_value(args[i]));
				}
			errp = (char *) o_alloc((unsigned) (1 + leftint));
			*errp = '\0';
			for (i = 0; i < numargs; i++)
				strcat(errp, string_value(args[i]));
			resultobj = (object *) new_istr(errp);
			goto return_obj;

		case 104:	/* string at: */
			if (numargs != 2) goto argcerror;
			leftint = leftp[i];
			goto return_character;

		case 105:	/* string at: put: */
			if (numargs != 3) goto argcerror;
			if (! is_character(args[2])) goto argterror;
			leftp[i] = int_value(args[2]);
			goto return_nil;

		case 106:	/* copyFrom: length: */
			if (numargs != 3) goto argcerror;
			if (! is_integer(args[2])) goto argterror;
			j = int_value(args[2]);
			if (j < 0) goto indexerror;
			for (rightp = strbuffer; j; j--, i++)
				*rightp++ = leftp[i];
			*rightp = '\0';
			goto return_string;

		case 107:	/* string copy */
			if (numargs != 1) goto argcerror;
			resultobj = new_str(leftp);
			goto return_obj;

		case 108:	/* string asSymbol */
			if (numargs != 1) goto argcerror;
			resultobj = new_sym(leftp);
			goto return_obj;

		case 109:	/* string printString */
			if (numargs != 1) goto argcerror;
			sprintf(strbuffer,"\'%s\'", leftp);
			goto return_string;

		case 110:	/* new untyped object */
			if (numargs != 1) goto argcerror;
			if (! is_integer(args[0])) goto argterror;
			leftint = int_value(args[0]);
			if (leftint < 0) goto numerror;
			resultobj = new_obj((class *) 0, leftint, 1);
			goto return_obj;

		case 111:	/* object at: */
			if (numargs != 2) goto argcerror;
			resultobj = args[0]->inst_var[ i - 1 ];
			goto return_obj;

		case 112:	/* object at:put: */
			if (numargs != 3) goto argcerror;
			assign(args[0]->inst_var[i - 1], args[2]);
			goto return_nil;

		case 113:	/*  object grow */
			leftarg = args[0];
			rightarg = args[1];
			if (is_bltin(leftarg)) goto argterror;
			resultobj = new_obj(leftarg->class,
				leftarg->size+1, 0);
			if (leftarg->super_obj)
				sassign(resultobj->super_obj,
					leftarg->super_obj);
			for (i = 0; i < leftarg->size; i++)
				sassign(resultobj->inst_var[i], leftarg->inst_var[i]);
			sassign(resultobj->inst_var[i], rightarg);
			goto return_obj;


		case 114:	/* new array */
			resultobj = new_array(i, 1);
			goto return_obj;

		case 115:	/* new string */
			for (j = 0; j < i; j++)
				strbuffer[j] = ' ';
			strbuffer[j] = '\0';
			goto return_string;

		case 116:	/* bytearray new */
			/* initialize with random garbage */
			resultobj = new_bytearray(strbuffer, i);
			goto return_obj;

		case 117:	/* bytearray size */
			if (numargs != 1) goto argcerror;
			leftint = byarray->a_bsize;
			goto return_integer;

		case 118:	/* bytearray at: */
			if (numargs != 2) goto argcerror;
			leftint = uctoi(byarray->a_bytes[i]);
			goto return_integer;

		case 119:	/* bytearray at:put: */
			if (numargs != 3) goto argcerror;
			if (! int_value(args[2])) goto argterror;
			byarray->a_bytes[i] = itouc(int_value(args[2]));
			goto return_nil;

		case 120:	/* print, no return */
			printf("%s", leftp);
# ifdef FLUSHREQ
			fflush(stdout);
# endif
			goto return_nil;

		case 121:	/* print, with return */
			printf("%s\n", leftp);
# ifdef FLUSHREQ
			fflush(stdout);
# endif
			goto return_nil;

		case 122:	/* format for error printing */
			aClass = (class *) fnd_class(args[1]);
			sprintf(strbuffer,"%s: %s",
				symbol_value(aClass->class_name), leftp);
			leftp = strbuffer;

		case 123:	/* print on error output */
			fprintf(stderr,"%s\n", leftp);
# ifdef FLUSHREQ
			fflush(stderr);
# endif
			goto return_nil;

		case 125:	/* unix system call */
# ifndef NOSYSTEM
			leftint = system(leftp);
			goto return_integer;
# endif
# ifdef NOSYSTEM
			errp = "system()";
			goto not_implemented;
# endif

		case 127:	/* block return */
			errp = "block return without surrounding context";
			goto return_error;

		case 128: /* reference count error */
			if (numargs != 1) goto argcerror;
			sprintf(strbuffer,"object %d reference count %d",
				args[0], args[0]->ref_count);
			errp = strbuffer;
			goto return_error;

		case 129: /* does not respond error */
			if (numargs != 2) goto argcerror;
			if (! is_symbol(args[1])) goto argterror;
			fprintf(stderr,"129 error %s\n",
			symbol_value(args[1]));
			aClass = (class *) fnd_class(args[0]);
			if (! is_class(aClass)) goto argterror;
			sprintf(strbuffer,"%s: does not respond to %s",
				symbol_value(aClass->class_name), 
				symbol_value(args[1]));
			errp = strbuffer;
			goto return_error;

		case 130:	/* file open */
			if (numargs != 3) goto argcerror;
			if (! is_string(args[1])) goto argterror;
			if (! is_string(args[2])) goto argterror;
			file_open(phil, 
				string_value(args[1]), string_value(args[2]));
			goto return_nil;

		case 131:	/* file read */
			if (numargs != 1) goto argcerror;
			resultobj = file_read(phil);
			goto return_obj;

		case 132:	/* file write */
			if (numargs != 2) goto argcerror;
			file_write(phil, args[1]);
			goto return_nil;

		case 133:	/* set file mode */
			if (numargs != 2) goto argcerror;
			if (! is_integer(args[1])) goto argterror;
			phil->file_mode = int_value(args[1]);
			goto return_nil;

		case 134:	/* compute file size */
			fseek(phil->fp, (long) 0, 2);
			leftint = (int) ftell(phil->fp);
			goto return_integer;

		case 135:	/* set file position */
			if (numargs != 2) goto argcerror;
			if (! is_integer(args[1])) goto argterror;
			leftint = fseek(phil->fp, (long) int_value(args[1]), 0);
			goto return_integer;

		case 136:	/* find current position */
			if (numargs != 1) goto argcerror;
			leftint = (int) ftell(phil->fp);
			goto return_integer;

		case 140:
			errp = "block execute should be trapped by interp";
			goto return_error;

		case 141:	/* newProcess (withArguments:) */
			if (numargs < 1) goto argcerror;
			if (! is_block(args[0])) goto argterror;
			if (numargs == 1)
				resultobj = (object *) cr_process(
					block_execute((interpreter *) 0, 
					(block *) args[0], 0, args));
			else if (numargs == 2)
				resultobj = (object *) cr_process(
					block_execute((interpreter *) 0, 
					(block *) args[0], args[1]->size,
					&(args[1]->inst_var[0])));
			else goto argcerror;
			goto return_obj;

		case 142:	/* terminate a process */
			if (numargs != 1) goto argcerror;
			if (! is_process(args[0])) goto argterror;
			terminate_process( (process *) args[0]);
			goto return_nil;

		case 143:	/* perform:withArguments: */
			errp = "perform should be trapped by interpreter";
			goto return_error;

		case 145:	/* set the state of a process */
			if (numargs != 2) goto argcerror;
			if (! is_process(args[0])) goto argterror;
			if (! is_integer(args[1])) goto argterror;
			leftint = int_value(args[1]);
			switch (leftint) {
				case 0:	leftint = READY;
					break;
				case 1:	leftint = SUSPENDED;
					break;
				case 2:	leftint = BLOCKED;
					break;
				case 3:	leftint = UNBLOCKED;
					break;
				default:  errp = "invalid state for process";
					  goto return_error;

				}
			set_state((process *) args[0], leftint);
			goto return_integer;

		case 146:	/* return the state of a process */
			if (numargs != 1) goto argcerror;
			if (! is_process(args[0])) goto argterror;
			leftint = set_state((process *) args[0], CUR_STATE);
			goto return_integer;

		case 148:	/* begin atomic action */
			if (numargs != 0) goto argcerror;
			atomcnt++;
			goto return_nil;

		case 149:	/* end atomic action */
			if (numargs != 0) goto argcerror;
			if (atomcnt == 0) {
				errp = "end atomic attempted while not in atomic action";
				goto return_error;
				}
			atomcnt--;
			goto return_nil;

		case 150:	/* class edit */
			leftp = symbol_value(aClass->file_name);
			if (! writeable(leftp)) {
				gettemp(tempname);
				sprintf(strbuffer,"cp %s %s", leftp, tempname);
# ifndef NOSYSTEM
				system(strbuffer);
# endif
				leftp = tempname;
				}
			if (! lexedit(leftp)) lexinclude(leftp);
			goto return_nil;

		case 151: 	/* superclass of a class */
			if (! aClass->super_class)
				goto return_nil;
			resultobj = (object *) aClass->super_class;
			if (! is_symbol(resultobj)) goto return_nil;
			resultobj = lookup_class(symbol_value(resultobj));
			if (! resultobj) goto return_nil;
			goto return_obj;

		case 152: /* class name */
			resultobj = aClass->class_name;
			leftp = symbol_value(resultobj);
			resultobj = new_str(leftp);
			goto return_obj;

		case 153: /* new */
			if (numargs != 2) goto argcerror;
			if (args[1] == o_nil)
				resultobj = new_inst(aClass);
			else
				resultobj = new_sinst(aClass, args[1]);
			goto return_obj;

		case 154:	/* print message names list */
			prnt_messages(aClass);
			goto return_nil;

		case 155: 	/* respondsTo: aMessage  */
			if (numargs != 2) goto argcerror;
			if (! is_symbol(args[1])) goto argterror;
			leftint = responds_to(symbol_value(args[1]), aClass);
			goto return_boolean;

		case 156:	/* class view */
			leftp = symbol_value(aClass->file_name);
			gettemp(tempname);
# ifndef NOSYSTEM
			sprintf(strbuffer,"cp %s %s", leftp, tempname);
# endif
			system(strbuffer);
			leftp = tempname;
			lexedit(leftp);
			goto return_nil;

		case 157:	/* class list */
			class_list(aClass, 0);
			goto return_nil;


		case 158:	/* variables */
			resultobj = aClass->c_inst_vars;
			goto return_obj;

		case 160:	/* current time */
			time(&clock);
			strcpy(strbuffer, ctime(&clock));
			goto return_string;

		case 161:	/* time, measure in seconds */
			leftint = (int) time((long *) 0);
			goto return_integer;

		default: fprintf(stderr,"Primitive number %d not implemented\n",
						primnumber);
			goto return_nil;
	}

/* return different types of objects */

return_obj:

	return(resultobj);

return_nil:

	return(o_nil);

return_integer:

	return(new_int(leftint));

return_character:

	return(new_char(leftint));

return_boolean:

	return(leftint ? o_true : o_false);

float_check:

	if (errno == ERANGE || errno == EDOM) goto numerror;

return_float:

	return(new_float(leftfloat));

return_string:

	return(new_str(strbuffer));

/* error conditions */

not_implemented:
	sprintf(strbuffer,"%s not implemented yet", errp);
	errp = strbuffer;
	goto return_error;

argcerror:
	sprintf(strbuffer,"%d is wrong number of arguments for primitive %d",
		numargs, primnumber);
	errp = strbuffer;
	goto return_error;

argterror:
	sprintf(strbuffer,"argument type not correct for primitive %d",
		primnumber);
	errp = strbuffer;
	goto return_error;

numerror:
	errp = "numerical error in primitive"; 
	goto return_error;

indexerror:
	errp = "primitive index error";
	goto return_error;

return_error:
	sassign(resultobj, new_str(errp));
	primitive(ERRPRINT, 1, &resultobj);
	obj_dec(resultobj);
	goto return_nil;
}

static prnt_radix(n, r, buffer)
int n, r;
char buffer[];
{  char *p, *q, buffer2[60];
   int i, s;

   if (n < 0) {n = - n; s = 1;}
   else s = 0;
   p = buffer2; *p++ = '\0';
   if (n == 0) *p++ = '0';
   while (n) {
      i = n % r;
      *p++ = i + ((i < 10) ?  '0' : ('A' - 10));
      n = n / r;
      }
   sprintf(buffer,"%dr", r);
   for (q = buffer; *q; q++);
   if (s) *q++ = '-';
   for (*p = '0' ; *p ; ) *q++ = *--p;
   *q = '\0';
}

static fprnt_radix(f, n, buffer)
double f;
int n;
char buffer[];
{	int sign, exp, i, j;
	char *p, *q, tempbuffer[60];
	double ip;

	if (f < 0) {
		sign = 1;
		f = - f;
		}
	else sign = 0;
	exp = 0;
	if (f != 0) {
		exp = (int) floor(log(f) / log((double) n));
		if (exp < -4 || 4 < exp) {
			f *= pow((double) n, (double) - exp);
			}
		else exp = 0;
		}
	f = modf(f, &ip);
	if (sign) ip = - ip;
	prnt_radix((int) ip, n, buffer);
	for (p = buffer; *p; p++) ;
	if (f != 0) {
		*p++ = '.';
		for (j = 0; (f != 0) && (j < 6); j++){
			i = (int) (f *= n);
			*p++ = (i < 10) ? '0' + i : 'A' + (i-10) ;
			f -= i;
			}
		}
	if (exp) {
		*p++ = 'e';
		sprintf(tempbuffer,"%d", exp);
		for (q = tempbuffer; *q; )
			*p++ = *q++;
		}
	*p = '\0';
	return;
}

/* generalit - numerical generality */
static int generality(aNumber)
object *aNumber;
{	int i;

	if (is_integer(aNumber)) i = 1;
	else if (is_float(aNumber)) i = 2;
	else i = 3;
	return(i);
}

/* cant_happen - report that an impossible condition has occured */
cant_happen(n) int n;
{   char *s;

# ifdef SMALLDATA
	s = "what a pain!";
# endif
# ifndef SMALLDATA
    switch(n) {
       case 1:  s = "out of memory allocation space"; break;
       case 2:  s = "array size less than zero"; break;
       case 3:  s = "block return from call should not occur"; break;
       case 4:  s = "attempt to make instance of non class"; break;
       case 5:  s = "case error in new integer or string"; break;
       case 6:  s = "decrement on unknown built in object"; break;
       case 7:  s = "cannot find class Object"; break;
       case 8:  s = "primitive free of object of wrong type"; break;
       case 9:  s = "internal interpreter error"; break;
       case 11: s = "block execute on non-block"; break;
       case 12: s = "out of symbol space"; break;
       case 14: s = "out of standard bytecode space"; break;
       case 15: s = "system deadlocked - all processes blocked"; break;
       case 16: s = "attempt to free symbol"; break;
       case 17: s = "invalid process state passed to set_state"; break;
       case 18: s = "internal buffer overflow"; break;
       case 20: s = "can't open prelude file"; break;
       case 22: s = "system file open error"; break;
       case 23: s = "fastsave error"; break;
       default: s = "unknown, but impossible nonetheless, condition"; break;
       }
# endif
   fprintf(stderr,"Can't happen number %d: %s\n", n, s);
   n = n / 0; /* on vax, this will force a core dump */
   exit(1);
}

/* writeable - see if a file can be written to */
int writeable(name)
char *name;
{	char buffer[150];

	sprintf(buffer,"test -w %s", name);
# ifdef NOSYSTEM
	return(0);
# endif
# ifndef NOSYSTEM
	return(! system(buffer));
# endif
}
SHAR_EOF
if test 31094 -ne "`wc -c < 'sources/primitive.c'`"
then
	echo shar: error transmitting "'sources/primitive.c'" '(should have been 31094 characters)'
fi
fi # end of overwriting check
if test -f 'sources/primitive.h'
then
	echo shar: will not over-write existing file "'sources/primitive.h'"
else
cat << \SHAR_EOF > 'sources/primitive.h'
/*
	Little Smalltalk primitive definitions

	(only a subset of primitives are described here, 
	basically those used by the courier and other systems routines.
	All other primitives are known only by number) 

*/
# define EQTEST 7
# define GAMMAFUN 77
# define SYMEQTEST 91
# define SYMPRINT  94
# define FINDCLASS 99
# define GROW 113
# define BLKRETERROR 127
# define REFCOUNTERROR 128
# define NORESPONDERROR 129
# define RAWPRINT 120
# define PRINT 121
# define ERRPRINT 123
# define BLOCKEXECUTE 140
# define DOPERFORM 143
SHAR_EOF
if test 528 -ne "`wc -c < 'sources/primitive.h'`"
then
	echo shar: error transmitting "'sources/primitive.h'" '(should have been 528 characters)'
fi
fi # end of overwriting check
if test -f 'sources/process.c'
then
	echo shar: will not over-write existing file "'sources/process.c'"
else
cat << \SHAR_EOF > 'sources/process.c'
/*
	Little Smalltalk

		process manager
		dennis a. vadner and michael t. benhase, 11/84
		modified by timothy a. budd 4/85
*/
/*
	The source code for the Little Smalltalk System may be freely
	copied provided that the source of all files is acknowledged
	and that this condition is copied with each file.

	The Little Smalltalk System is distributed without responsibility
	for the performance of the program and without any guarantee of
	maintenance.

	All questions concerning Little Smalltalk should be addressed to:

		Professor Tim Budd
		Department of Computer Science
		The University of Arizona
		Tucson, Arizona
		85721
		USA
*/

# include <stdio.h>
# include <signal.h>
# include <setjmp.h>

# include "drive.h"
# include "object.h"
# include "interp.h"
# include "process.h"

extern int  test_driver();	/* routine to test for user keystrokes*/

static process  *currentProcess;	/* current process */
static process  *fr_process = 0;	/* process memory free list */

int  atomcnt = 0;			/* atomic action flag */
process  *runningProcess;		/* currently running process,
					   may be different from
					   currentProcess during process
					   termination */

# define PROCINITMAX 6
static process prcinit[PROCINITMAX];	/* initial process free list */


/* init_process - initialize the process module */
init_process ()
{	process *p;
	int i;

	/* first make the initial process free list */
	for (p = prcinit, i = 0; i < PROCINITMAX; i++, p++) {
		p->next = fr_process;
		fr_process = p;
		}

	/* make the process associated with the driver */
	currentProcess = cr_process(o_drive);
	assign(currentProcess->next, currentProcess);
	assign(currentProcess->prev, currentProcess);
	currentProcess->p_state = ACTIVE;
}

/* cr_process - create a new process with the given interpreter */
process  *cr_process (anInterpreter)
interpreter  *anInterpreter;
{	process  *new;

	if (fr_process) {
	    new = (process *) fr_process;
	    fr_process = fr_process->next;
	    }
	else
	    new = structalloc(process);

	new->p_ref_count = 0;
	new->p_size = PROCSIZE;

	sassign(new->interp, anInterpreter);
	new->p_state = SUSPENDED;
	sassign(new->next, (process *) o_nil);
	sassign(new->prev, (process *) o_nil);

	return(new);
}


/* free_process - return an unused process to free list */
free_process (aProcess)
process  *aProcess;
{
	obj_dec((object *) aProcess->interp);
	obj_dec((object *) aProcess->next);
	obj_dec((object *) aProcess->prev);
	aProcess->p_state = TERMINATED;
	aProcess->next = fr_process;
	fr_process = aProcess;
}

/* flush_processes - flush out any remaining process from queue */
flush_processes ()
{
	while (currentProcess != currentProcess->next)
	   remove_process(currentProcess);

	/* prev link and next link should point to the same place now.
	   In order to avoid having memory recovered while we are
	   manipulating pointers, we increment reference count, then change
	   pointers, then decrement reference counts */

	obj_inc((object *) currentProcess);
	safeassign(currentProcess->prev, (process *) o_nil);
	safeassign(currentProcess->next, (process *) o_nil);
	obj_dec((object *) currentProcess);
}


/* link_to_process - change the interpreter for the current process */
link_to_process (anInterpreter)
interpreter  *anInterpreter;
{	object *temp;

	safeassign(runningProcess->interp, anInterpreter);
}


/* remove_process - remove a process from process queue */
static remove_process (aProcess)
process  *aProcess;
{
	if (aProcess == aProcess->next)
	    cant_happen(15);		/* removing last active process */

	/* currentProcess must always point to a process that is on the
	   process queue, make sure this remains true */

	if (aProcess == currentProcess)
	    currentProcess = currentProcess->prev;

	/* In order to avoid having memory recovered while we are changing
	pointers, we increment the reference counts on both processes,
	change pointers, then decrement reference counts */

	obj_inc((object *) currentProcess); obj_inc((object *) aProcess);
	safeassign(aProcess->next->prev, aProcess->prev);
	safeassign(aProcess->prev->next, aProcess->next);
	obj_dec((object *) currentProcess); obj_dec((object *) aProcess);
}


/* schedule_process - add a new process to the process queue */
static schedule_process (aProcess)
process  *aProcess;
{
	safeassign(aProcess->next, currentProcess);
	safeassign(aProcess->prev, currentProcess->prev);
	safeassign(aProcess->prev->next, aProcess);
	safeassign(currentProcess->prev, aProcess);
}

/* set_state - set the state on a process, which may involve inserting or
removing it from the process queue */
int  set_state (aProcess, state)
process  *aProcess;
int  state;
{
	switch (state) {
	    case BLOCKED:
	    case SUSPENDED:
	    case TERMINATED:	if (aProcess->p_state == ACTIVE)
				    remove_process(aProcess);
				aProcess->p_state |= state;
				break;

	    case READY:
	    case UNBLOCKED:	if ((aProcess->p_state ^ state) == ~ACTIVE)
				    schedule_process(aProcess);
				aProcess->p_state &= state;
				break;

	    case CUR_STATE:	break;
	    default:		cant_happen(17);
	    }
	return(aProcess->p_state);
}

# ifdef SETJUMP
static jmp_buf intenv;
# endif

/* brkfun - what to do on a break key */
brkfun()
{	static int warn = 1;

# ifndef SETJUMP
	exit(1);
# endif
	if (warn) {
		fprintf(stderr,"warning: recovery from interrupt may cause\n");
		fprintf(stderr,"reference counts to be incorrect, and\n");
		fprintf(stderr,"some memory to be inaccessible\n");
		warn = 0;
		}
# ifdef SETJUMP
	longjmp(intenv, 1);
# endif
}

/* start_execution - main execution loop */
start_execution ()
{	interpreter  *presentInterpreter;

	atomcnt = 0;

# ifdef SIGS
	/* trap user interrupt signals and recover */
	signal(SIGINT, brkfun);
# endif

# ifdef SETJUMP
	if (setjmp(intenv)) {
		atomcnt = 0;
		link_to_process(o_drive);
		}
# endif

	while (1) {
	    /* unless it is an atomic action get the next process */
	    if (! atomcnt)
		runningProcess = currentProcess = currentProcess->next;

	    if (! is_driver(runningProcess->interp)) {
		sassign(presentInterpreter, runningProcess->interp);
		resume(presentInterpreter);
		obj_dec((object *) presentInterpreter);
		}
	    else if (! test_driver((currentProcess == currentProcess->next) ||
				   (atomcnt > 0)))
		break;
	    }
}
SHAR_EOF
if test 6273 -ne "`wc -c < 'sources/process.c'`"
then
	echo shar: error transmitting "'sources/process.c'" '(should have been 6273 characters)'
fi
fi # end of overwriting check
if test -f 'sources/process.h'
then
	echo shar: will not over-write existing file "'sources/process.h'"
else
cat << \SHAR_EOF > 'sources/process.h'
/*
	Little Smalltalk

		process definitions
		dennis a. vadner and michael t. benhase,  11/84
*/
/*
	the process

		interp = pointer to the head of the process'
			 interpreter chain
		p_state = current state of the process

		next = link to the next process in the active list
		prev = link to the previous process in the active list
*/


struct  process_struct {
	int		p_ref_count;
	int		p_size;
	interpreter	*interp;
	int		p_state;
	struct process_struct  *next;
	struct process_struct  *prev;
	} ;

typedef  struct process_struct  process;

extern int  atomcnt;			/* atomic action flag */
extern process  *runningProcess;	/* currently running process */

extern process  *cr_process();		/* create a new process */
extern int  set_state();		/* set the state on a process */


/* process states */

# define  ACTIVE	0
# define  SUSPENDED	1
# define  READY		~SUSPENDED
# define  BLOCKED	2
# define  UNBLOCKED	~BLOCKED
# define  TERMINATED	4

# define  CUR_STATE	10


# define  terminate_process(aProcess)  {set_state(aProcess, TERMINATED); \
					if (aProcess == runningProcess)  \
					    atomcnt = 0;}
SHAR_EOF
if test 1106 -ne "`wc -c < 'sources/process.h'`"
then
	echo shar: error transmitting "'sources/process.h'" '(should have been 1106 characters)'
fi
fi # end of overwriting check
if test -f 'sources/sstr.c'
then
	echo shar: will not over-write existing file "'sources/sstr.c'"
else
cat << \SHAR_EOF > 'sources/sstr.c'
/*
	sstr - find and replace string occurrences
		with common addresses,
		can be used to share strings accross compiled boundaries
		written by tim budd, 9/84
*/
/*
	The source code for the Little Smalltalk System may be freely
	copied provided that the source of all files is acknowledged
	and that this condition is copied with each file.

	The Little Smalltalk System is distributed without responsibility
	for the performance of the program and without any guarantee of
	maintenance.

	All questions concerning Little Smalltalk should be addressed to:

		Professor Tim Budd
		Department of Computer Science
		The University of Arizona
		Tucson, Arizona
		85721
		USA
*/
# include <stdio.h>
# define WORDTABMAX 1000
# define STRTABMAX 10000

int x_cmax = 0;
int x_tmax = -1;
char x_str[STRTABMAX];
char *x_tab[WORDTABMAX];


main(argc, argv)
int argc;
char **argv;
{	int i;
	FILE *fd;

	if (strcmp(argv[1], "-f") == 0) {
		for (i = 2; i < argc; i++) {
			fd = fopen(argv[i], "r");
			if (fd != NULL) {
				findstrs(fd);
				fclose(fd);
				}
			}
		}
	else if (strcmp(argv[1], "-t") == 0) {
		for (i = 4; i < argc; i++)
		   puts(argv[i]);
		fd = fopen(argv[2], "r");
		if (fd == NULL) {
			fprintf(stderr,"can't open string table\n");
			exit(1);
			}
		maketab(fd, stdout, argv[3]);
		}
	else {
		fd = fopen(argv[1], "r");
		if (fd == NULL) {
			fprintf(stderr,"can't open string table\n");
			exit(1);
			}
		maketab(fd, 0, 0);
		printf("extern char x_str[];\n");
		replacestr(stdin);
		}
	exit(0);
}

/* findstrs - find all strings and output them to stdout */
findstrs(fd)
FILE *fd;
{
	char *p, buffer[500];
	int c;

	for (; (c = getc(fd)) != EOF; )
		if (c == '\"') {
			for (p = buffer; (c = getc(fd)) != '\"'; p++)
				if (c == EOF) {
					fprintf(stderr,"unexpected eof\n");
					exit(1);
					}
				else *p = c;
			*p = '\0';
			puts(buffer);
			}
}

/* replacestr - replace strings with their address in x_str */
replacestr(fd)
FILE *fd;
{
	char *p, buffer[500], *w_search();
	int c;

	for (; (c = getc(fd)) != EOF; )
		if (c != '\"') putchar(c);
		else {
			for (p = buffer; (c = getc(fd)) != '\"'; p++)
				if (c == EOF) {
					fprintf(stderr,"unexpected eof\n");
					exit(1);
					}
				else *p = c;
			*p = '\0';
			p = w_search(buffer, 0);
			if (p) printf("&x_str[%d]", p - &x_str[0]);
			else printf("\"%s\"", buffer);
			}
}

maketab(ifd, ofd, itab)
FILE *ifd, *ofd;
char *itab;
{	char wbuf[100], *p;
	int i;

	x_cmax = 0;
	if (ofd)
		fprintf(ofd, "char x_str[] = {");
	while (fgets(wbuf, 100, ifd) != NULL) {
		x_tab[++x_tmax] = &x_str[x_cmax];
		for (p = wbuf; *p; p++) {
			if (*p == '\n') {*p = '\0'; break;}
			if (ofd)
				fprintf(ofd,"0%o, ", *p);
			x_str[x_cmax++] = *p;
			}
		if (ofd)
			fprintf(ofd, "0,   /* %s */\n", wbuf);
		x_str[x_cmax++] = '\0';
		}
	if (ofd) {
		fprintf(ofd, "0 };\n");
		fprintf(ofd, "int x_cmax = %d;\n", x_cmax);
		}
	if (itab) {
		fprintf(ofd, "static symbol x_sytab[] = {\n");
		for (i = 0; i <= x_tmax; i++) {
			fprintf(ofd, "{1, SYMBOLSIZE, &x_str[%d]}, /* ", 
				x_tab[i]-x_tab[0]);
			for (p = x_tab[i]; *p; p++) 
				putc(*p, ofd);
			fprintf(ofd," */\n");
			}
		fprintf(ofd, "0};\n");
		fprintf(ofd, "symbol *x_tab[%s] = {\n", itab);
		for (i = 0; i <= x_tmax; i++) {
			fprintf(ofd, "&x_sytab[%d], /* ",i); 
			for (p = x_tab[i]; *p; p++) 
				putc(*p, ofd);
			fprintf(ofd," */\n");
			}
		fprintf(ofd, "0};\n");
		fprintf(ofd,"int x_tmax = %d;\n", x_tmax);
		}
}

/* 	
	word search for table routines
*/

char *w_search(word, insert)
char *word;
int  insert;
{	int i,j,k;

	for (i=1; i <= x_tmax; i <<= 1);
	for (i >>= 1, j = i >>1, i--; ; j >>= 1) {
		if (! (k = strcmp(word, x_tab[i])))
			return(x_tab[i]);

		if (!j) break;
		if (k < 0) i -= j;
		else {
			if ((i += j) > x_tmax) i = x_tmax;
			}
		}
	if (insert) {
		for (k = ++x_tmax; k > i; k--) {
			x_tab[k] = x_tab[k-1];
			}
		if (!(x_tab[i] = (char *) malloc(1 + strlen(word))))
			return((char *) 0);
		strcpy(x_tab[i], word);
		return(x_tab[i]);
		}
	else return((char *) 0);
}
SHAR_EOF
if test 4018 -ne "`wc -c < 'sources/sstr.c'`"
then
	echo shar: error transmitting "'sources/sstr.c'" '(should have been 4018 characters)'
fi
fi # end of overwriting check
if test -f 'sources/string.c'
then
	echo shar: will not over-write existing file "'sources/string.c'"
else
cat << \SHAR_EOF > 'sources/string.c'
/*
	Little Smalltalk

		string creation and deletion
		timothy a. budd, 10/84
*/
/*
	The source code for the Little Smalltalk System may be freely
	copied provided that the source of all files is acknowledged
	and that this condition is copied with each file.

	The Little Smalltalk System is distributed without responsibility
	for the performance of the program and without any guarantee of
	maintenance.

	All questions concerning Little Smalltalk should be addressed to:

		Professor Tim Budd
		Department of Computer Science
		The University of Arizona
		Tucson, Arizona
		85721
		USA
*/
# include <stdio.h>
# include "object.h"
# include "string.h"

int ca_str = 0;
int ca_wal = 0;

/* walloc allocates a string containing the same chars as the arg */

# define WALLOCINITSIZE 1000

static char wtable[WALLOCINITSIZE];
int wtop = 0;

char *walloc(val)
char *val;
{	char *p;
	int  size;

	size = 1 + strlen(val);
	if ((size < 40) && ((wtop + size) < WALLOCINITSIZE)) {
		p = &wtable[wtop];
		wtop += size;
		}
	else {
		p = o_alloc((unsigned) size);
		ca_wal++;
		}
	strcpy(p, val);
	return(p);
}

/*---------------------------------------*/
extern class *ArrayedCollection;
extern object *o_acollection;

static mstruct *fr_string = 0;

# define STRINITSIZE 50

static string st_init_table[STRINITSIZE];

str_init() {
	string *p;
	mstruct *new;
	int i;

	for (p = st_init_table, i = 0; i < STRINITSIZE; i++, p++) {
		new = (mstruct *) p;
		new->mlink = fr_string;
		fr_string = new;
		}
}

extern int started;
static new_rstr(new)
string *new;
{
	new->s_ref_count = 0;
	new->s_size = STRINGSIZE;
	if (! started)
		sassign(new->s_super_obj, o_acollection);
	else if (ArrayedCollection)
		sassign(new->s_super_obj, new_inst(ArrayedCollection));
	else
		new->s_super_obj = (object *) 0;
}

string *new_istr(text)
char *text;
{	register string *new;

	if (fr_string) {
		new = (string *) fr_string;
		fr_string = fr_string->mlink;
		}
	else {
		ca_str++;
		new = structalloc(string);
		}

	new->s_value = text;
	new_rstr(new);
	return(new);
}

# define STRLISTMAX 100

mstruct *frl_str[STRLISTMAX];

object *new_str(text)
char *text;
{	int size;
	string *new;

	size = 1 + strlen(text);
	if ((size < STRLISTMAX) && frl_str[size]) {
		new = (string *) frl_str[size];
		frl_str[size] = frl_str[size]->mlink;
		strcpy(new->s_value, text);
		new_rstr(new);
		}
	else {
		new = new_istr(walloc(text));
		}
	return((object *) new);
}

free_string(s)
string *s;
{	int size;

	if (s->s_super_obj)
		obj_dec(s->s_super_obj);
	size = 1 + strlen(s->s_value);
	if (size < STRLISTMAX) {
		((mstruct *)s)->mlink = frl_str[size];
		frl_str[size] = (mstruct *) s;
		}
	else {
		((mstruct *)s)->mlink = fr_string;
		fr_string = (mstruct *) s;
		}
}
SHAR_EOF
if test 2734 -ne "`wc -c < 'sources/string.c'`"
then
	echo shar: error transmitting "'sources/string.c'" '(should have been 2734 characters)'
fi
fi # end of overwriting check
if test -f 'sources/string.h'
then
	echo shar: will not over-write existing file "'sources/string.h'"
else
cat << \SHAR_EOF > 'sources/string.h'
/*
	Little Smalltalk string definitions
*/
/*
	for strings s_size = STRINGSIZE

	Unlike other special objects (integers, floats, etc), strings
	must keep their own super_obj pointer, since the class
	ArrayedCollection (a super class of String) contains instance
	variables, and thus each instance of String must have a unique
	super_obj.
*/

struct string_struct {
	int	s_ref_count;
	int	s_size;
	object 	*s_super_obj;
	char	*s_value;
	} ;

typedef struct string_struct string;

extern object *new_str();		/* make a new string object */
extern string *new_istr();		/* internal form of new string */
extern char   *walloc();		/* allocate a copy a word */

# define string_value(x) (((string *) x)->s_value)
SHAR_EOF
if test 706 -ne "`wc -c < 'sources/string.h'`"
then
	echo shar: error transmitting "'sources/string.h'" '(should have been 706 characters)'
fi
fi # end of overwriting check
if test -f 'sources/symbol.c'
then
	echo shar: will not over-write existing file "'sources/symbol.c'"
else
cat << \SHAR_EOF > 'sources/symbol.c'
/*
	Little Smalltalk

		symbol creation - symbols are never deleted once created.
		timothy a. budd, 10/84
*/
/*
	The source code for the Little Smalltalk System may be freely
	copied provided that the source of all files is acknowledged
	and that this condition is copied with each file.

	The Little Smalltalk System is distributed without responsibility
	for the performance of the program and without any guarantee of
	maintenance.

	All questions concerning Little Smalltalk should be addressed to:

		Professor Tim Budd
		Department of Computer Science
		The University of Arizona
		Tucson, Arizona
		85721
		USA
*/
# include <stdio.h>
# include "object.h"
# include "symbol.h"

/*
	only one copy of symbol values are kept.
	multiple copies of the same symbol point to the same
	location.
	sy_search will find, and if necessary insert, a string into
	this common table 
*/

extern char x_str[];		/* initialized common string table */
extern symbol *x_tab[];		/* initialized common symbols table */
extern int x_tmax;		/* top of symbols table */
extern char *walloc();		/* routine to allocate a new word */
int ca_sym = 0;			/* symbol allocation counter */

/* sy_search performs a binary search of a symbol, is the main interface to
the symbols routines */
symbol *sy_search(word, insert)
char *word;
int  insert;
{	register int i;
	register int j;
	register int k;
	char *p;
	symbol *new_y();

	for (i=1; i <= x_tmax; i <<= 1);
	for (i >>= 1, j = i >>1, i--; ; j >>= 1) {
		p = symbol_value(x_tab[i]);
		if (word == p) return(x_tab[i]);
		k = *word - *p;
		if (!k) k = *(word+1) - *(p+1);
		if (!k) k = strcmp(word, p);
		if (!k)
			return(x_tab[i]);
		if (!j) break;
		if (k < 0) i -= j;
		else {
			if ((i += j) > x_tmax) i = x_tmax;
			}
		}
	if (insert) {
		if (k > 0) i++;
		if ((k = ++x_tmax) >= SYMTABMAX)
			cant_happen(12);
		for (; k > i; k--) {
			x_tab[k] = x_tab[k-1];
			}
		/*fprintf(stderr,"adding %s\n", word);*/
		x_tab[i] = new_y(walloc(word));
		x_tab[i]->y_ref_count++; /* make sure not freed */
		return(x_tab[i]);
		}
	else return((symbol *) 0);
}

/* w_search performs a search for a word, not a symbol */
char *w_search(word, insert)
char *word;
int insert;
{	symbol *sym;

	sym = sy_search(word, insert);
	if (sym)
		return(symbol_value(sym));
	else
		return((char *) 0);
}

/*---------------------------------------*/

static mstruct *fr_symbol = 0;		/* symbols free list */
static symbol strspace[SYMINITSIZE];	/* initial symbols free list */

extern object *o_object;		/* common instance of Object */
extern class *ArrayedCollection;

/* sym_init - initialize the symbols routine */
sym_init() {
	int  i;
	symbol *p;
	mstruct   *new;

	p = strspace;
	for (i = 0; i < SYMINITSIZE; i++) {
		new = (mstruct *) p;
		new->mlink = fr_symbol;
		fr_symbol = new;
		p++;
		}
}

/* new_y is the internal routine for making new symbols */
symbol *new_y(text)
char *text;
{	symbol *new;

	if (fr_symbol) {
		new = (symbol *) fr_symbol;
		fr_symbol = fr_symbol->mlink;
		}
	else {
		ca_sym++;
		new = structalloc(symbol);
		}

	new->y_ref_count = 0;
	new->y_size = SYMBOLSIZE;
	new->y_value = text;
	return(new);
}
SHAR_EOF
if test 3138 -ne "`wc -c < 'sources/symbol.c'`"
then
	echo shar: error transmitting "'sources/symbol.c'" '(should have been 3138 characters)'
fi
fi # end of overwriting check
#	End of shell archive
exit 0