#

/* RELLD: .rel to a.out converter
   Program converts files in .rel format to files in a.out format
   It expects two arguments, the first is a file in .rel format
   and the second is a filename for the resulting a.out format
   file.
 */


/* Define the .rel commands */

#define	CMD_CS		1
#define	CMD_ST		2
#define	CMD_SYM		3
#define	CMD_ENTRY	4
#define	CMD_END		5
#define	CMD_MIXID	6
#define	CMD_TXT		21
#define	CMD_TXTR	22
#define	CMD_ABS		23
#define	CMD_REL		24
#define	CMD_ABSX	25
#define	CMD_RELX	26
#define	CMD_LCS		27
#define	CMD_LCSX	28


/* Define the command attribute bits */

#define	A_EXT		01	/*  external variable */
#define	A_ISPC		02	/* csect in i space */
#define	A_PURE		04	/* csect is pure */
#define	A_ABS		010	/* absolute csect, used only for symbols */
#define	A_DEF		020	/* symbol is defined */


/* Define the relocation bits for a.out files */

#define	R_ABS		00	/* absolute reference */
#define R_RELOC		01	/* pc relative reference */
#define R_TEXT		02	/* text segment reference */
#define R_DATA		04	/* data segment reference */
#define R_EXT		010	/* external reference */


/* Define a.out symbol types */

#define	S_EXTERN	040	/* external symbol */
#define S_UNDEF		00	/* undefined symbol */
#define S_ABS		01	/* absolute symbol */
#define S_TEXT		02	/* text segment symbol */
#define S_DATA		03	/* data segment symbol */
#define S_CSECT		06	/* csect symbol */
#define S_ST		07	/* symbol table symbol */
#define S_ENTRY		010	/* entry symbol */


/* Define some miscellanious parameters */

#define	nsymbols	1000	/* number of entries in symbol table */
#define RELFLG		01	/* flag indicates relative rather than abs */



/* Define the major data structures */

/* Symbol Table Entries */

struct symbol {
	char type;		/* type from command type */
	char attributes;	/* attributes depending on type */
	int value;		/* value depending on type */
	int csect;		/* csect id of csect containing symbol */
	int table;		/* tbl id of symbol table containing symbol */
	char *name;		/* pointer to asciz string name */
	int newnum;		/* number in new numbering scheme */
};


/* Symbol Table and related data */

struct {
	char mixid;		/* flag indicating I=D loading */
	int next;		/* next free symbol table entry */
	int num;		/* total number of symbols output */
	struct symbol tbl[nsymbols];	/* actual symbol table */
} sym;


/* Define the header data structures */

struct header {
	int magic;		/* magic number to specify how to load */
	int txtsiz;		/* size of the text segment */
	int datsiz;		/* size of the tata segment*/
	int bsssiz;		/* size of the bss segment */
	int symsiz;		/* size of the symbol table */
	int entry;		/* entry location */
	int unused;		/* unused slot */
	int relflg;		/* flag which specifies surpress relocation */
} hdr;


/* Define storage for a.out symbols. */

struct {
	char aname[8];		/* name of the symbol */
	int atype;		/* type of the symbol */
	int aval;		/* value of the symbol */
} asym;


/* A few useful macros to do things with symbols */

#define symval(symb)	(((sym.tbl)[symb]).value)
#define	symatr(symb)	(((sym.tbl)[symb]).attributes)
#define	symtyp(symb)	(((sym.tbl)[symb]).type)
#define	symnam(symb)	(((sym.tbl)[symb]).name)



/* Main is the top level routine.  It processes the arguments by
	opening the input and output files, then calls
	symbld to build the symbol table, txtbld to process the text
	and symput to output any symbols. */

char rflag,sflag,mflag,aflag,lflag;	/* storage for the options flags */
int p 1;			/* current argument number */

main(argc, argv)
  int argc;
  char **argv;{
	char *prereq, *title;	/* temporary variable to hold prereq */
	extern char *input;	/* pointer to input buffer */
	extern int output;	/* output file id */

	if (argc == 1) {
		printf("\n>relld {-sralm} infil outfil\n");
		exit();
		}

	optchk(argv);		/* check for options argument */

	if (fopen(argv[p], input) < 0) {
		printf("File not found: %s\n", argv[p]);
		exit(0);
	} else p++;

	optchk(argv);		/* check for options argument again */

	if ((output = creat(argv[p], 0644)) < 0) {
		printf("Cannot open %s for output\n", argv[p]);
		exit(0);
	} else p++;

	optchk(argv);		/* last chance for options */

	skip(6);		/* skip the creation date/time */
	title = gets();		/* get the title */
	free(title);		/* free up the string */
	if ((prereq = gets())[0] != 0) {
		printf("Prereqs not permitted, %s ignored.\n", prereq);
	};
	free(prereq);		/* release the prereq string */

	symbld();		/* build the symbol table from input file */
	txtbld();		/* build the text part of the output file */
	if (sflag) symput();	/* output symbols from the symbol table */
};


/* Subroutine to set option flags and advance arg pointer p, if this was
	an argument of the form -x where x is:
		s for symbols
		r for relocation bits, implies s also
		a for including all symbols
		l for deleting all local symbols
		m for map (outputs relld debugging info) */

optchk(argv) 
char **argv;

{	char *cptr;	/* which option char we are looking at */
	if (argv[p][0] == '-') {
		for (cptr = &argv[p++][1];; cptr++) switch (cptr[0]) {
			case 's':	sflag = 1; break;
			case 'r':	rflag = sflag = 1; break;
			case 'a':	aflag = 1; break;
			case 'l':	lflag = 1; break;
			case 'm':	mflag = 1; break;
			case 0:		return;
			default: printf("Unknown option: %c ignored.\n", cptr[0]);
			}
	}
}


/* Symbld reads in the symbol part of the input file and builds up
	the symbol table.  When the end of the symbol section is
 	found, via the END command, and the csects will be defined. */

symbld(){
	int cmd;		/* type of current command */
	char attrib;		/* attributes byte of command */
	int value;		/* value word of command */
	int cs;			/* csect of symbol */
	int table;		/* symbol table id of symbol */
	char *name;		/* pointer to name string */
	int nentries;		/* number of entry commands seen */
	extern char *input;	/* pointer to input buffer */
	extern int output;	/* output file id */
	nentries = 0;		/* have not seen any so far */
	sym.next = 0;		/* initially symtab empty */
	sym.num = 0;		/* and none selected for output */
	sym.mixid = 0;		/* initially not I=D */


	hdr.magic  = rflag ? 0407 : 0411;	/* magic number */
	hdr.txtsiz = 0;		/* account for ehack */
	hdr.datsiz = 0;		/* or any data csects */
	hdr.bsssiz = 0;		/* bss should always be 0 for now */
	hdr.symsiz = 0;		/* no symbols yet */
	hdr.entry = 0;		/* entry 0 for now */
	hdr.unused = 0;		/* as it says... */
	hdr.relflg = (rflag == 0);	/* suppress relocation if rflag == 0 */



while ((cmd = getcmd()) != CMD_END && cmd != -1) switch (cmd) {


/* Csect commands define new csects.  Their value is the current value
	of hdr.txtsiz or hdr.datsiz depending on the type of the csect.
	The appropriate offset is incremented by the length of the csect. */

case CMD_CS:
	attrib = getc(input);		/* get the attributes byte */
	value = getw(input);		/* get the length of the csect */
	name = gets();			/* get the name of the csect */

	if (attrib & A_ABS) {
		if ((hdr.txtsiz != 0) && (value != 0))
			printf("ASECT not first entry\n");
		symdef(cmd, attrib, 0, 0, 0, name);
		hdr.txtsiz =+ value;
		break;
		}

	if (attrib & A_ISPC) {
		if (hdr.txtsiz & 1) hdr.txtsiz =+ 1;	/* word aligned */
		symdef(cmd, attrib, hdr.txtsiz, 0, 0, name);
		hdr.txtsiz =+ value;
		break;
	}
	else {
		if (hdr.datsiz & 1) hdr.datsiz =+ 1;	/* word aligned */
		symdef(cmd, attrib, hdr.datsiz, 0, 0, name);
		hdr.datsiz =+ value;
		break;
	};


/* ST commands define a new symbol table name.  They have no
	attributes, no value, and no csect. */

case CMD_ST:
	attrib = getc(input);	/* get the attributes byte */
	table = getw(input);	/* get the id of symbol table it belongs to */
	name = gets();	/* get the name of this symbol table */
	symdef(cmd, attrib, 0, 0, table, name);
	break;



/* SYM commands define normal symbols.  They have the full complement
	of attributes, value, csect, table, and name.  Relative symbols
	defined for i space or d space references are relocated. */

case CMD_SYM:
	attrib = getc(input);	/* get the attributes byte */
	value = getw(input);	/* get the value of the symbol */
	cs = getw(input);	/* get the CSECT this symbol belongs to */
	table = getw(input);	/* get the symbol table it belongs to */
	name = gets();		/* get the name of the symbol */
	if ((attrib & A_DEF) && !(attrib & A_ABS) && !(symatr(cs) & A_ABS)) {
		value =+ symval(cs);
		if (rflag && ((symatr(cs) & A_ISPC) == 0)) value =+ hdr.txtsiz;
		}
	symdef(cmd, attrib, value, cs, table, name);
	break;


/* ENTRY commands define entry points into the module.
	Any additional ENTRY commands will cause an 
	error.  They have a csect, a spares field which is skipped,
	and a name. */

case CMD_ENTRY:
	attrib = getc(input);	/* get the attributes byte */
	value = getw(input);	/* get the entry value */
	cs = getw(input);	/* get the csect of this entry */
	skip(10);		/* skip the spares field */
	name = gets();		/* get the name of this entry */
	symdef(cmd, attrib, value, cs, 0, name);
	if ( ++nentries > 1 ) {
		printf("additional entry %s ignored/n", name);
	}
	else {
		hdr.entry = value + symval(cs); /* entry is offset in csect */
	};
	break;


/* MIXID commands simply set the sym.mixid flag. */

case CMD_MIXID:
	++(sym.mixid);		/* increment the flag */
	break;

};


	/* Now write out the header */

	if (sflag)				/* if doing syms, set size */
		hdr.symsiz = sym.num * sizeof(asym);
	if (hdr.txtsiz & 1) hdr.txtsiz =+ 1;	/* text space word aligned */
	if (hdr.datsiz & 1) hdr.datsiz =+ 1;	/* data space word aligned */
	if (rflag == 0) symefix();	/* fill in values for _end etc */
	write(output, &hdr, sizeof hdr);	/* write out the header */
};


/* Routine outputs the symbol table in a.out format.  It first seeks
	to the right spot in the output file, which is twice the
	size of txt and data segments (to account for relocation bits),
	plus the size of the header.  Then it outputs symbols in a.out form. */

symput() {
	register int ns,off,sect;	/* symbol, offset and sector vars */
	extern int output;		/* file id of output file */
	sect = (((hdr.txtsiz >> 9) & 0177) + ((hdr.datsiz >> 9) & 0177));
	off = (hdr.txtsiz & 0777) + (hdr.datsiz & 0777);
	if (rflag) {
		sect =* 2;		/* double sizes to include rel bits */
		off =* 2;
	}
	off =+ sizeof hdr;		/* be sure we skip the header */
	seek(output, sect, 3);		/* seek to right block */
	seek(output, off, 1);		/* seek to here plus offset */
	if (mflag) printf(" id     name  type  atrb csect csatr  value\n");
	for (ns = 0; ns < sym.next; ns++) symput1(ns);
}


/* Routine to ouput one symbol in a.out format */

symput1(symb) 
int symb; 			/* ID of current symbol */

{	register struct symbol *ns, *cs; /* pointers to current symb and cs */
	int i;			/* index variable */
	extern int output;	/* file id of output file */

	ns = &sym.tbl[symb];
	if ((aflag == 0) && (ns->type != CMD_SYM) && (ns->type != CMD_ENTRY))
			return;
	if ((lflag != 0) && (((ns->attributes) & A_EXT) == 0))
			return;

	for  ( i = 0; i < 8; i++) 
		if((asym.aname[i] = ns->name[i]) == 0) break;
	if ( i > 8) printf("Symbol %s truncated.\n", ns->name);
	for ( ; i < 8; i++) (asym.aname)[i] = 0;


	asym.atype = 0;		/* initially, undefined, then or in type */
	switch (ns->type) {	/* set up type based on type of symbol */

	case CMD_CS:
		asym.atype = S_CSECT;
		break;

	case CMD_ST:
		asym.atype = S_ST;
		break;

	case CMD_SYM:
		if ((ns->attributes) & A_EXT) asym.atype = S_EXTERN;
		if (((ns->attributes) & A_DEF) == 0) asym.atype =| S_UNDEF;
		else {
			if (symatr(ns->csect) & A_ABS) asym.atype =| S_ABS;
			else if (symatr(ns->csect)&A_ISPC)asym.atype =| S_TEXT;
			else asym.atype =| S_DATA;
		};
		break;

	case CMD_ENTRY:
		asym.atype = S_ENTRY;
		break;

	};					/* close switch */

	asym.aval = ns->value;		/* get value of symbol */

	if (mflag) printf("%3d %8s %5d %5o %5d %5o %6o\n", symb, ns->name, ns->type, ns->attributes, ns->csect, symatr(ns->csect), ns->value);
	write(output, &asym, sizeof asym);	/* write out this symbol */
};						/* close routine */



/* Subroutine to search the symbol table for the symbols _end, _etext, and
	_edata, and fill in values if these symbols are global and undefined.
	Symbols _end and _edata will give the address of the first location
	after the data segment ie hdr.datsiz.  Symbol _etext will be
	hdr.txtsiz.  */

symefix() {
	register int ns;
	for (ns = 0; ns < sym.next; ns++)
		if (symatr(ns) == A_EXT) {	/* must be extern and undef */
			if (cmpstr(symnam(ns),"_end")||cmpstr(symnam(ns),"_edata"))
				symfix(ns,CMD_SYM,A_EXT|A_DEF,hdr.datsiz,0,0,symnam(ns));
			else if (cmpstr(symnam(ns), "_etext"))
				symfix(ns,CMD_SYM,A_EXT|A_DEF|A_ISPC,hdr.txtsiz,0,0,symnam(ns));
		}
}



/* Subroutine to define a symbol table entry. */

symdef(cmd, attrib, val, cs, tbl, nm)
  int cmd;			/* the command type */
  char attrib;			/* attributes char */
  int val;			/* value word */
  int cs;			/* csect id */
  int tbl;			/* symbol table id */
  char *nm; {			/* pointer to name string */

	symfix((sym.next)++, cmd, attrib, val, cs, tbl, nm);
	if (sym.next >= nsymbols) {
		printf("Symbol table overflow!\n");
		exit(0);
	}
}



/* Subroutine to store the values of a symbol table entry. */

symfix(symid, cmd, attrib, val, cs, tbl, nm)
  int symid;			/* index of symbol in symbol table */
  char attrib;			/* attributes char */
  int val;			/* value word */
  int cs;			/* csect id of csect symbol belongs to */
  int tbl;			/* symbol table id of table of this symbol */
  char *nm; {			/* pointer to name of the symbol */

	register struct symbol *s;	/* pointer to symbol we are defining */
	s = &((sym.tbl)[symid]);
	s->type = cmd;
	s->attributes = attrib;
	s->value = val;
	s->csect = cs;
	s->table = tbl;
	s->name = nm;
	if ((aflag == 0) && (s->type != CMD_SYM) && (s->type != CMD_ENTRY))
		return;
	if ((lflag != 0) && (((s->attributes) & A_EXT) == 0))
			return;
	s->newnum = sym.num++;
};



/* Define txt data structures */

/* txt buffer and associated data */

struct {
	int lc;			/* location counter */
	int rpt;		/* repeat count */
	int csid;		/* csect id (in symbol table) */
	int length;		/* number of bytes in txt buffer */
	char buffer[256];	/* the text buffer */
	char reloc[256];	/* relocation words buffer */
} txt;


/* Routine builds the txt and data parts of the output file by
	reading txt commands from the input file and outputtting
	txt blocks after rel and abs fixups. */

txtbld() {
	int cmd;		/* command type */
	char bytflg;		/* 1=>byte command, 0=>word command */
	int value;		/* temporary used in reading in stuff */
	int offset;		/* temp used to read in buffer offsets */
	extern char *input;	/* input file pointer */
	txt.lc = 0;		/* init location counter at 0 */
	txt.rpt = 0;		/* so our initial txtput won't put anyghing */

/* read a command, set byte flag and dispatch on bits 0-6 as cmd type */

while ((cmd = getcmd()) != -1) {	/* -1 means eof */
	bytflg = ((cmd & 0200) != 0);	/* check high order bit */
	cmd = (cmd & 0177);	/* clear the high order bit to dispatch */
	switch (cmd) {		/* dispatch on command */



/* Txt command, first empties the txt buffer then reads a new block of
	txt into the buffer. Rpt count is set to 1, to output code once. */

case CMD_TXT:
	txtput();		/* empty anything currently in buffer */
	txt.length = getc(input);	/* get the length of the text */
	txt.rpt = 1;		/* set rpt count to 1 */
	txtget();		/* finally, read in the block of txt */
	break;


/* Txtr command is just like txt except that it has a rpt count
	built in so it may output the txt many times. */

case CMD_TXTR:
	txtput();		/* flush anything currently in buffer */
	txt.length = getc(input);	/* get the length of txt in bytes */
	txt.rpt = getw(input);	/* set the rpt count */
	txtget();		/* finally, read in the block of txt */
	break;


/* ABS command adds base address of current CSECT to word/byte at offset */

case CMD_ABS:
	offset = getc(input) & 0377;	/* get offset into current txt blk to fix */
	txtfix(offset, txt.csid, 0, bytflg);	/* fix it in positive */
	txtrel(offset, txt.csid, 0, bytflg);	/* set up relocation */
	break;

/* REL command subtracts base of CSECT to word/byte at offset */

case CMD_REL:
	offset = getc(input) & 0377;		/* get offset */
	txtfix(offset, txt.csid, 1, bytflg);	/* subtract the fix */
	txtrel(offset, txt.csid, 1, bytflg);	/* we want pc relocation */
	break;


/* ABSX command like ABS except has ID argument. */

case CMD_ABSX:
	offset = getc(input) & 0377;	/* get offset */
	value = getw(input);	/* get ID whose value is the fix value */
	txtfix(offset, value, 0, bytflg);	/* fix it positive */
	txtrel(offset, value, 0, bytflg);	/* setup relocation word */
	break;


/* RELX command like REL except has ID argument. */

case CMD_RELX:
	offset = getc(input) & 0377;	/* get offset */
	value = getw(input);	/* get id */
	txtfix(offset, value, 1, bytflg);	/* fix it */
	break;



/* LCS command just moves the location counter. */

case CMD_LCS:
	txtput();		/* flush txt buffer */
	txt.lc = symval(txt.csid) + getw(input);
	break;


/* LCSX command like LCS but with ID argument. */

case CMD_LCSX:
	txtput();		/* flush txt buffer */
	offset = getw(input);	/* the new lc offset */
	txt.csid = getw(input);	/* set this to current CSECT */
	txt.lc = symval(txt.csid) + offset;
	break;



default:
	printf("Unknown txt command!\n");

};				/* close switch */
};				/* close while loop */

txtput();			/* empty anything remaining in buffer */

};

/* Routine to read in a block of txt from input file into txt.buffer.
	Uses txt.length as count. */

txtget() {
	int i;			/* counter */
	extern char *input;	/* pointer to input buffer */
	for ( i = 0; i < txt.length; i++) txt.buffer[i] = getc(input);
	for ( i = 0; i < txt.length; i++) txt.reloc[i] = 0;
};



/* Routine to output the contents of txt.buffer into the right place
	in the file.  Finds offset in file of this CSECT from symspc,
	and finds offset of CSECT in its space, from symoff, and
	uses txt.lc as the final offset for the place to put txt.buffer.
	Updates txt.lc by the length of the stuff in txt.buffer. */

txtput() {
	extern int output;	/* file id of output file */
	register int i,sect,offs;	/* variables */
	for (i = 1 ; i <= txt.rpt; i++ ) {
		sect = (txt.lc >> 9) & 0177;
		offs = txt.lc & 0777;
		offs =+ sizeof hdr;
		if ((symatr(txt.csid) & (A_ISPC | A_ABS)) == 0) {
			sect =+ (hdr.txtsiz >> 9) & 0177;
			offs =+ hdr.txtsiz & 0777;
		};
		seek(output, sect, 3);
		seek(output, offs, 1);
		write(output, txt.buffer, txt.length);
		if (rflag) {
			sect =+ ((hdr.txtsiz >> 9) & 0177)
				 + ((hdr.datsiz >> 9) & 0177);
			offs =+ (hdr.txtsiz & 0777) + (hdr.datsiz & 0777);
			seek(output, sect, 3);
			seek(output, offs, 1);
			write(output, txt.reloc, txt.length);
		};
		txt.lc =+ txt.length;
	};
	txt.rpt = 0;
};

/* Routine to fix a word or byte in txt.buffer by adding a value to that wrd. */

txtfix(offset, id, sign, bytflg)
  int offset;			/* offset in txt.buffer to change */
  int id;			/* the id of csect or symbol to fix */
  char sign;			/* 0=> add value of id, 1 => subtract */
  char bytflg; {		/* 0=> word fix, 1 => byte fix */
	register int oldwrd, newwrd;
	char atr,typ;		/* will contain attributes of id */

	if (bytflg) printf("Byte relocation not defined!\n");
	else {
		oldwrd = txt.buffer[offset] & 0377;
		oldwrd =+ txt.buffer[offset + 1] << 8;
		newwrd = symval(id);
		if (rflag && (((atr = symatr(id)) & A_ABS) == 0))
			if ((((typ = symtyp(id))==CMD_SYM) && (atr & A_DEF)) |
				(typ == CMD_CS))
				if  ((atr & A_ISPC) == 0) newwrd =+ hdr.txtsiz;
		if (sign) newwrd = -newwrd;
		oldwrd =+ newwrd;
		txt.buffer[offset] = oldwrd & 0377;
		txt.buffer[offset+1] = (oldwrd >> 8) & 0377;
	}
};


/* Subroutine to put the proper kind of relocation bits in relocation word */

txtrel(offset, id, pc_rel, bytflg)
register  int offset;			/* offset into current block */
register  int id;			/* symbol or csect id */
  char pc_rel;			/* 1 => set the pc rel bit and return */
  char bytflg;	{		/* 1 => the fix should be on a byte */
	int fixval;		/* the value we intend to install */
	if (bytflg) {
		printf("Byte relocation not allowed in a.out files!\n");
		return;
	};
	if (pc_rel) {
		txt.reloc[offset] =| R_RELOC;	/* specify pc relative reloc */
		return;				/* that's all for now */
	}
	switch (symtyp(id)) {	/* switch on the type of symbol */

case CMD_CS:
	if (symatr(id) & A_ISPC) txt.reloc[offset] =| R_TEXT;
	else txt.reloc[offset] =| R_DATA;
	break;

case CMD_SYM:
	fixval = R_EXT | ((sym.tbl)[id].newnum << 4);
	txt.reloc[offset] =| fixval & 0377;
	txt.reloc[offset + 1] =| (fixval >> 8) & 0377;
	break;
};
};

/* io buffer for input file */

struct iobuf {
	int fildef;
	int nleft;
	char *nextp;
	char buff[512];
} in_buf;



/* miscellanious variables */

int output;			/* file id of output file */
char *input &in_buf;		/* pointer to input buffer */



/* Miscellanious Subroutines */

/* Subroutine to get a command byte from input file.  Ignores
	leading bzeros. */

getcmd() {
	int cmd;		/* temporary for value we will return */
	while ((cmd = getc(input)) == 0);	/* get  a non-zero char */
	return (cmd);		/* return the first non-zero command */
};



/* Subroutine to get an asciz string from input file.  It allocates
	a buffer for the string from free storage.  Names have a
	maximum length of namesize characters. */

gets() {
	char string[100];	/* temporary to hold string as we read in */
	char *new_str;		/* temporary pointer to newly allocate string */
	int i;			/* temporary index */

	for ( i = 0; i < 100; i++) 
		if ((string[i] = getc(input)) == 0) {
			new_str = alloc(i + 1); /* allocate a new string */
			for ( ; i >= 0; i--) new_str[i] = string[i];
			return (new_str);
		};

	string[99] = 0;		/* force a zero at end of string */
	printf("Name truncated: %s\n", string);
	new_str = alloc(100);
	for (i = 0; i < 100; i++) new_str[i] = string[i];
	return (new_str);
};



/* Routine to skip chars in the input file */

skip(cnt)
  int cnt; {			/* number of chars to skip */
	int i;			/* temporary for loop */
	for ( i = 1; i <= cnt; i++) getc(input);
};



/* Routine to compare two character strings */

cmpstr(s1, s2)
  register char *s1, *s2; {	/* pointers to strings we are comparing */
	while (*s1 == *s2) {
		if (*s1 == 0) return(1);
		s1++;
		s2++;
	}
	return(0);
}
