DataMuseum.dk

Presents historical artifacts from the history of:

RegneCentralen RC700 "Piccolo"

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about RegneCentralen RC700 "Piccolo"

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download

⟦8de5c68bb⟧ TextFile

    Length: 22400 (0x5780)
    Types: TextFile
    Names: »L2.C«

Derivation

└─⟦b35f94715⟧ Bits:30003295 BDS C version 1.50 arbejdsdiskette til RC703 Piccolo
└─⟦b35f94715⟧ Bits:30005324 BDS C version 1.50 arbejdsdiskette til RC703 Piccolo
    └─ ⟦this⟧ »L2.C« 

TextFile

/*      ********
	* L2.C *	New linker for BDS C
	********
			Written 1980 by Scott W. Layson
			Modified 1982 by David Kirkland
			This code is in the public domain.

	This is an improved linker for BDS C CRL format.
	It supports the c debugger.

	Compilation instructions:
		cc l2.c -e4C00	     (use -e4900 if linking with L2.COM)
		cc chario.c

		clink l2 chario -ns
	  (or)	l2 l2 chario -ns
*/


/**************** Globals ****************/

/* The DEF_DRIVE macro is used to define the drive from which L2 will
 * load C.CCC, DEFF.CRL, DEFF2.CRL, and DEFF3.CRL (if it exists). The 
 * macro takes as an argument the filename and extension, and "returns"
 * the name with whatever drive designator is needed.  The macro also
 * encloses the name in quotes; thus, the argument when the macro is
 * invoked must NOT be within quotes.
 * That is, to open C.CCC on the proper drive, we use the C code
 *	if (ERROR==fopen(DEF_DRIVE(C.CCC), iobuf)) .....
 */
 
#define DEF_DRIVE(fn) "fn"    /* Make this "0/A:fn" for, say, user 0 on A */

#define SUB_FILE   "$$$.SUB"	/* submit file to delete on error exit...
				 * if you use SDOS, use "a:$$$$.sub"; if you've
				 * hacked your CCP, you may need to change the
				 * drive designator letter */

#define RST_NUM      	6	/* C debugger RST number. Should be identical
				   to the RSTNUM symbol in CCC.ASM      */

#define OVERLAYS		/* comment this out for shorter version */

/*
#define MARC			/* for MARC cross-linker version 
					(enables the "-marc" option) */
*/

#include <bdscio.h>	      /* for i/o buffer defs */

#define NUL		0
#define FLAG		char
#define repeat 	while (1)

#define STDOUT		1

/* Phase control */
#define INMEM		1	/* while everything still fits */
#define DISK1		2	/* overflow; finish building table */
#define DISK2		3	/* use table to do window link */
int phase;


/* function table */
struct funct æ
	char fnameÆ9Å;
	FLAG flinkedp;		/* in memory already? */
	FLAG fdebug; 		/* TRUE unless this routine required
				   only by a lib function after -s */
	char *faddr;		/* address of first ref link if not linked */
	å *ftab;
int nfuncts;			/* no. of functions in  table */
int maxfuncts;			/* table size */

#define LINKED		1	/* (flinkedp) function really here */
#define EXTERNAL	2	/* function defined in separate symbol table */

char fdir Æ512Å;		/* CRL file function directory */

/* command line parameters etc. */
int nprogs, nlibs;
char progfiles Æ30Å Æ15Å;	/* program file names */
char libfiles Æ20Å Æ15Å;	/* library file names */
int deflibindex;		/* index of first default (DEFF*) library */
FLAG symsp,			/* write symbols to .sym file? */
	appstatsp,		/* append stats to .sym file? */
	sepstatsp;		/* write stats to .lnk file? */

#ifdef MARC
FLAG maxmemp,			/* punt MARC shell? */
	marcp;			/* uses CM.CCC */
#endif

char mainfunctÆ10Å;
FLAG ovlp;			/* make overlay? */
char symsfile Æ15Å;		/* file to load symbols from (for overlays) */

/*  C debugger variables  */
FLAG Dflag;
FLAG SysStat;			/* TRUE if "-s" option given & now active */
int  SysNum;			/* index into libfiles of "-s", or -1 if none */

FLAG Tflag;			/* TRUE if "-t" option given	*/
unsigned Tval;			/* arg to "-t", if present	*/

/* useful things to have defined */
struct inst æ
	char opcode;
	char *address;
	å;

union ptr æ
	unsigned u;		/* an int */
	unsigned *w;		/* a word ptr */
	char *b;		/* a byte ptr */
	struct inst *i;		/* an instruction ptr */
	å;


/* Link control variables */

union ptr codend;		/* last used byte of code buffer + 1 */
union ptr exts;			/* start of externals */
union ptr acodend;		/* actual code-end address */
unsigned extspc;		/* size of externals */
unsigned origin;		/* origin of code */
unsigned buforg;		/* origin of code buffer */
unsigned jtsaved;		/* bytes of jump table saved */

char *lspace;			/* space to link in */
char *lspcend;			/* end of link area */
char *lodstart;			/* beginning of current file */


/* i/o buffer */
struct iobuf æ
	int fd;
	int isect;		/* currently buffered sector */
	int nextc;		/* index of next char in buffer */
	char buff Æ128Å;
	å ibuf, obuf;

/* BDS C i/o buffer */
char symbufÆBUFSIZÅ;

/* seek opcodes */
#define ABSOLUTE 0
#define RELATIVE 1

#define INPUT 0

#define TRUE (-1)
#define FALSE 0
#define NULL 0

/* 8080 instructions */
#define LHLD 0x2A
#define LXISP 0x31
#define LXIH 0x21
#define SPHL 0xF9
#define JMP  0xC3
#define CALL 0xCD

/* strcmp7 locals, made global for speed */
char _c1, _c2, _end1, _end2;

/**************** End of Globals ****************/


main (argc, argv)
	int argc;
	char **argv;
æ
	puts ("Mark of the Unicorn Linker ver. 2.2.2Øn");
	setup (argc, argv);
	linkprog();
	linklibs();
	if (phase == DISK1) rescan();
	else wrtcom();
	if (symsp) wrtsyms();
	å


setup (argc, argv)		/* initialize function table, etc. */
	int argc;
	char **argv;
æ
	symsp = appstatsp = sepstatsp = FALSE;	/* default options */
#ifdef MARC
	marcp = maxmemp = FALSE;
#endif
	ovlp = FALSE;
	nprogs = 0;
	nlibs = 0;
	strcpy (&mainfunct, "MAIN");	/* default top-level function */
	origin = 0x100;			/* default origin */
	maxfuncts = 200;		/* default function table size */
	Tflag = FALSE;			/* no "-t" given yet	*/
	SysStat = FALSE;
	SysNum = -1;
	Dflag = FALSE;
	cmdline (argc, argv);
	ftab = endext();
	lspace = ftab + maxfuncts;
	lspcend = topofmem() - (1024 + 2100);
	if (lspace > lspcend)
		Fatal ("Insufficient memory to do anything at all!Øn");
	loadccc();
	nfuncts = 0;
#ifdef OVERLAYS
	if (ovlp) loadsyms();
#endif
	intern (&mainfunct);
	phase = INMEM;
	buforg = origin;
	jtsaved = 0;
	å


cmdline (argc, argv)		/* process command line */
	int argc;
	char **argv;
æ
	int i, progp, syslib;

	if (argc == 1) æ
		puts ("Usage is:Øn");
		puts ("  l2 æprogram fileså Æ-l ælibrary fileså Å ");
		puts ("Æ-s ælibrary fileså ÅØn");
		puts ("ØtÆ-m <main_name>Å Æ-f <maxfuncts>Å Æ-org <addr>Å");
		puts (" Æ-t <addr>ÅØn");
		puts ("ØtÆ-dÅ Æ-nsÅ Æ-w ø -wa ø -wsÅØn");
#ifdef OVERLAYS
		puts ("ØtÆ-ovl <rootname> <addr>Å");
#endif
#ifdef MARC
		puts ("ØtÆ-marcÅ");
#endif
		lexit (1);
		å
	syslib = TRUE;
        progp = TRUE;
	for (i=1; i < argc; ++i) æ
		if (argvÆiÅÆ0Å == '-') æ
			if (!strcmp (argvÆiÅ, "-F")) æ
				if (++i>=argc) Fatal ("-f argument missing.Øn");
				sscanf (argvÆiÅ, "%d", &maxfuncts);
				å
			else if (!strcmp (argvÆiÅ, "-L")) progp = FALSE;
			else if (!strcmp (argvÆiÅ, "-S")) æ
				progp = FALSE;
				SysNum = nlibs;
				å
			else if (!strcmp (argvÆiÅ, "-M")) æ
				if (++i>=argc) Fatal ("-m argument missing.Øn");
				strcpy (&mainfunct, argvÆiÅ);
				å
#ifdef MARC
			else if (!strcmp (argvÆiÅ, "-MARC")) æ
				maxmemp = TRUE;
				marcp = TRUE;
				å
#endif
			else if (!strcmp (argvÆiÅ, "-ORG")) æ
				if (++i>=argc) Fatal ("-org argument missing.Øn");
				sscanf (argvÆiÅ, "%x", &origin);
				å
			else if (!strcmp (argvÆiÅ, "-T")) æ
				if (++i >= argc) 
					Fatal ("-t argument missing.Øn");
				Tflag = TRUE;
				sscanf (argvÆiÅ, "%x", &Tval);
				å
#ifdef OVERLAYS
			else if (!strcmp (argvÆiÅ, "-OVL")) æ
				ovlp = TRUE;
				if (i + 2 >= argc) 
					Fatal ("-ovl argument missing.Øn");
				strcpy (&symsfile, argvÆ++iÅ);
				sscanf (argvÆ++iÅ, "%x", &origin);
				å
#endif
			else if (!strcmp (argvÆiÅ, "-D")) Dflag = TRUE; 
			else if (!strcmp (argvÆiÅ, "-W")) symsp = TRUE;
			else if (!strcmp (argvÆiÅ, "-WA")) 
				symsp = appstatsp = TRUE;
			else if (!strcmp (argvÆiÅ, "-WS")) 
				symsp = sepstatsp = TRUE;
			else if (!strcmp (argvÆiÅ, "-NS")) syslib = FALSE;
			else printf ("Unknown option: '%s'Øn", argvÆiÅ);
			å
		else æ
			if (progp) strcpy (&progfilesÆnprogs++Å, argvÆiÅ);
			else strcpy (&libfilesÆnlibs++Å, argvÆiÅ);
			å
		å
	if (ovlp)
		strcpy(&mainfunct, &progfilesÆ0ÅÆ2*(progfilesÆ0ÅÆ1Å==':')Å );
	if (Dflag øø !syslib øø SysNum!=-1)
		Dflag = symsp = TRUE;
	if (syslib && SysNum == -1)
		SysNum = nlibs;
#define NDEFF	3
	deflibindex = nlibs;
#ifdef MARC
	strcpy (&libfilesÆnlibs++Å, marcp ? "DEFFM" : "DEFF");
	strcpy (&libfilesÆnlibs++Å, marcp ? "DEFF2M" : "DEFF2");
	strcpy (&libfilesÆnlibs++Å, marcp ? "DEFF3M" : "DEFF3");
#else
	strcpy (&libfilesÆnlibs++Å, DEF_DRIVE(DEFF) );
	strcpy (&libfilesÆnlibs++Å, DEF_DRIVE(DEFF2) );
	strcpy (&libfilesÆnlibs++Å, DEF_DRIVE(DEFF3) );
#endif
	å


loadccc()			/* load C.CCC (runtime library) */
æ
	union ptr temp;
	unsigned len;

	codend.b = lspace;
	if (!ovlp) æ
#ifdef MARC
		if (copen (&ibuf, marcp ? "CM.CCC" : "C.CCC") < 0)
#else
		if (copen (&ibuf, DEF_DRIVE(C.CCC) ) < 0)
#endif
			Fatal ("Can't open %sØn",DEF_DRIVE(C.CCC));
		if (cread (&ibuf, lspace, 128) < 128)	/* read a sector */
			Fatal ("%s: read error!Øn",DEF_DRIVE(C.CCC));
		temp.b = lspace + 0x17;
		len = *temp.w;				/* how long is it? */
		cread (&ibuf, lspace + 128, len - 128);	/* read rest */
		codend.b += len;
		cclose (&ibuf);
		å
	else codend.i++->opcode = JMP;
	å


linkprog()				/* link in all program files */
æ
	int i;
	union ptr dirtmp;
	struct funct *fnct;

	for (i=0; i<nprogs; ++i) æ
		makeext (&progfilesÆiÅ, "CRL");
		if (copen (&ibuf, progfilesÆiÅ) < 0) æ
			printf ("Can't open %sØn", progfilesÆiÅ);
			continue;
			å
		printf ("Loading  %sØn", &progfilesÆiÅ);
		readprog (i==0);
		for (dirtmp.b=&fdir; *dirtmp.b != 0x80;) æ
			fnct = intern (dirtmp.b);	/* for each module */
			skip7 (&dirtmp);		/* in directory */
			if (!fnct->flinkedp)
				linkmod (fnct, lodstart + *dirtmp.w - 0x205);
			else if (phase != DISK2) æ
				puts ("Duplicate program function '");
				puts (&fnct->fname);
				puts ("', not linked.Øn");
				å
			dirtmp.w++;
			å				/* intern & link it */
		cclose (&ibuf);
		å
	å


linklibs()				/* link in library files */
æ
	int ifile;

	for (ifile=0; ifile<nlibs; ++ifile) æ
		if (ifile==SysNum) SysStat = TRUE;
		scanlib (ifile);
		å
	while (missingp()) æ
		puts ("Enter the name of a file to be searched or CR: ");
		gets (&libfilesÆnlibsÅ);
		if (libfilesÆnlibsÅÆ0Å) æ
			SysStat = FALSE;
			scanlib (nlibs);
			å
		else æ
			if (SysNum!=-1)
				SysStat = TRUE;
			for (ifile=0; ifile<NDEFF; ++ifile)
				scanlib (deflibindex + ifile);
			å
		å
	acodend.b = codend.b - lspace + buforg;		/* save that number! */
	if (!exts.b) exts.b = acodend.b;
	å


missingp()		/* are any functions missing?  print them out */
æ
	int i, foundp;

	foundp = FALSE;
	for (i=0; i<nfuncts; ++i)
		if (!ftabÆiÅ.flinkedp) æ
			if (!foundp) puts ("*** Missing functions:Øn");
			puts (&ftabÆiÅ.fname);
			puts ("Øn");
			foundp = TRUE;
			å
	return (foundp);
	å


rescan()		/* perform second disk phase */
æ
	int i;
	
	for (i=0; i < nfuncts; ++i)
		if (ftabÆiÅ.flinkedp == LINKED) ftabÆiÅ.flinkedp = FALSE;
	phase = DISK2;
	buforg = origin;
	puts ("ØnØn**** Beginning second disk pass ****Øn");
	if (!ovlp) makeext (&progfilesÆ0Å, "COM");
	else makeext (&progfilesÆ0Å, "OVL");
	ccreat (&obuf, &progfilesÆ0Å);
	loadccc();
	hackccc();
	linkprog();
	linklibs();
	if (cwrite (&obuf, lspace, codend.b - lspace) == -1
	    øø  cflush (&obuf) < 0) Fatal ("Disk write error!Øn");
	cclose (&obuf);
	stats (STDOUT);
	å



readprog (mainp)			/* read in a program file */
	FLAG mainp;
æ
	char extp;				/* was -e used? */
	char *extstmp;
	union ptr dir;
	unsigned len;

	if (cread (&ibuf, &fdir, 512) < 512)		/* read directory */
		Fatal ("-- read error!Øn");
	if (phase == INMEM  &&  mainp) æ
		cread (&ibuf, &extp, 1);
		cread (&ibuf, &extstmp, 2);
		cread (&ibuf, &extspc, 2);
		if (extp) exts.b = extstmp;
		else exts.b = 0;		/* will be set later */
		å
	else cseek (&ibuf, 5, RELATIVE);
	for (dir.b=&fdir; *dir.b != 0x80; nextd (&dir));  /* find end of dir */
	++dir.b;
	len = *dir.w - 0x205;
	readobj (len);
	å


readobj (len)			/* read in an object (program or lib funct) */
	unsigned len;
æ
	if (phase == DISK1  øø  codend.b + len >= lspcend) æ
		if (phase == INMEM) æ
			puts("Øn** Out of memory--switching to disk mode **Øn");
			phase = DISK1;
			å
		if (phase == DISK2) æ
			if (cwrite (&obuf, lspace, codend.b - lspace) == -1)
				Fatal ("Disk write error!Øn");
			å
		buforg += codend.b - lspace;
		codend.b = lspace;
		if (codend.b + len >= lspcend)
			Fatal ("Module won't fit in memory at all!Øn");
		å
	lodstart = codend.b;
	if (cread (&ibuf, lodstart, len) < len) Fatal ("-- read error!Øn");
	å


scanlib (ifile)
	int ifile;
æ
	int i;
	union ptr dirtmp;

	makeext (&libfilesÆifileÅ, "CRL");
	if (copen (&ibuf, libfilesÆifileÅ) < 0) æ
		if (ifile != deflibindex + (NDEFF-1))
			printf ("Can't open %sØn", libfilesÆifileÅ);
		return;
		å
	printf ("Scanning %sØn", &libfilesÆifileÅ);
	if (cread (&ibuf, &fdir, 512) < 512)	/* read directory */
		Fatal ("-- Read error!Øn");
	for (i=0; i<nfuncts; ++i) æ		/* scan needed functions */
		if (!ftabÆiÅ.flinkedp
		    && (dirtmp.b = dirsearch (&ftabÆiÅ.fname))) æ
			readfunct (dirtmp.b);
			linkmod (&ftabÆiÅ, lodstart);
			å
		å
	cclose (&ibuf);
	å


readfunct (direntry)			/* read a function (from a library) */
	union ptr direntry;
æ
	unsigned start, len;

	skip7 (&direntry);
	start = *direntry.w++;
	skip7 (&direntry);
	len = *direntry.w - start;
	if (cseek (&ibuf, start, ABSOLUTE) < 0) Fatal (" -- read error!");
	readobj (len);
	å


linkmod (fnct, modstart)		/* link in a module */
	struct funct *fnct;
	union ptr modstart;		/* loc. of module in memory */

æ
	union ptr temp,
			jump,		/* jump table temp */
			body,		/* loc. of function in memory */
			code,		/* loc. of code proper in mem. */
			finalloc;	/* runtime loc. of function */
	unsigned flen, nrelocs, jtsiz, offset;

	fnct->flinkedp = LINKED;
	if (phase != DISK2) æ
		finalloc.b = codend.b - lspace + buforg;
		if (phase == INMEM) chase (fnct->faddr, finalloc.b);
		fnct->faddr = finalloc.b;
		å
 	else finalloc.b = fnct->faddr;
	body.b = modstart.b + strlen(modstart.b) + 3; /* loc. of fn body */
	jump.i = body.i + (*modstart.b ? 1 : 0);
	for (temp.b = modstart.b; *temp.b; skip7(&temp)) æ
		jump.i->address = intern (temp.b);
		++jump.i;
		å
	++temp.b;
	flen = *temp.w;
	code.b = jump.b;
	temp.b = body.b + flen;		/* loc. of reloc parameters */
	nrelocs = *temp.w++;
	jtsiz = code.b - body.b;
	if (Dflag && fnct->fdebug) æ
		if (phase!=DISK1) æ
			codend.i->opcode = (0307 + (8*RST_NUM));
			codend.i->address = 0;
			finalloc.b += 3;
			å
		codend.b += 3;
		å
	offset = code.b - codend.b;
	if (phase != DISK1)
		while (nrelocs--) relocate (*temp.w++, body.b, jtsiz,
						   finalloc.b, offset, flen);
	flen -= jtsiz;
	if (phase != DISK2) jtsaved += jtsiz;
	if (phase != DISK1) movmem (code.b, codend.b, flen);
	codend.b += flen;
	å


relocate (param, body, jtsiz, base, offset, flen)	/* do a relocation!! */
	unsigned param, jtsiz, base, offset, flen;
	union ptr body;
æ
	union ptr instr,			/* instruction involved */
			ref;			    /* jump table link */
	struct funct *fnct;

/*	if (param == 1) return;			/* don't reloc jt skip */*/
	instr.b = body.b + param - 1;
	if (instr.i->address >= jtsiz)
		instr.i->address += base - jtsiz;	/* vanilla case */
	else æ
		ref.b = instr.i->address + body.u;
		if (instr.i->opcode == LHLD) æ
			instr.i->opcode = LXIH;
			--ref.b;
			å
		fnct = ref.i->address;
		instr.i->address = fnct->faddr;		/* link in */
		if (!fnct->flinkedp  &&  phase == INMEM)
			fnct->faddr = instr.b + 1 - offset;  /* new list head */
		å
	å


intern (name)			/* intern a function name in the table */
	char *name;
æ
	struct funct *fptr;

	if (*name == 0x9D) name = "MAIN";		/* Why, Leor, WHY??? */
	for (fptr = &ftabÆnfuncts-1Å; fptr >= ftab; --fptr) 
		if (!strcmp7 (name, fptr->fname)) break;
	if (fptr < ftab) æ
		if (nfuncts >= maxfuncts)
			Fatal("Too many functions (limit is %d)!Øn", maxfuncts);
		fptr = &ftabÆnfunctsÅ;
		strcpy7 (fptr->fname, name);
		str7tont (fptr->fname);
		fptr->flinkedp = FALSE;
		fptr->faddr = NULL;
		fptr->fdebug = !SysStat;
		++nfuncts;
		å
	return (fptr);
	å


dirsearch (name)			/* search directory for a function */
	char *name;
æ
	union ptr temp;

	for (temp.b = &fdir; *temp.b != 0x80; nextd (&temp))
		if (!strcmp7 (name, temp.b)) return (temp.b);
	return (NULL);
	å


nextd (ptrp)			/* move this pointer to the next dir entry */
	union ptr *ptrp;
æ
	skip7 (ptrp);
	++(*ptrp).w;
	å


chase (head, loc)		/* chase chain of refs to function */
	union ptr head;
	unsigned loc;
æ
	union ptr temp;

	while (head.w) æ
		temp.w = *head.w;
		*head.w = loc;
		head.u = temp.u;
		å
	å


wrtcom()			/* write out com file (from in-mem link) */
æ
	hackccc();
	if (!ovlp) makeext (&progfilesÆ0Å, "COM");
	else makeext (&progfilesÆ0Å, "OVL");
	if (!ccreat (&obuf, &progfilesÆ0Å) < 0
	    øø  cwrite (&obuf, lspace, codend.b - lspace) == -1
	    øø  cflush (&obuf) < 0)
		Fatal ("Disk write error!Øn");
	cclose (&obuf);
	stats (STDOUT);
	å


hackccc()			/* store various goodies in C.CCC code */
æ
	union ptr temp;
	struct funct *fptr;

	temp.b = lspace;
	fptr = intern (&mainfunct);
	if (!ovlp) æ
#ifdef MARC
		if (!marcp) æ
#endif
		  	if (!Tflag) æ
				temp.i->opcode = LHLD;
				temp.i->address = origin - 0x100 + 6;
				(++temp.i)->opcode = SPHL;
				å
			else æ
				temp.i->opcode = LXISP;
				temp.i->address = Tval;
				å
			temp.b = lspace + 0xF;	    /* main function address */
			temp.i->address = fptr->faddr;
#ifdef MARC
			å
#endif
		temp.b = lspace + 0x15;
		*temp.w++ = exts.u;
		++temp.w;
		*temp.w++ = acodend.u;
		*temp.w++ = exts.u + extspc;
		å
	else temp.i->address = fptr->faddr;		/* that's a JMP */
#ifdef MARC
	if (maxmemp) æ
		temp.b = lspace + 0x258;
		temp.i->opcode = CALL;
		temp.i->address = 0x50;
		å
#endif
	å


wrtsyms()					/* write out symbol table */
æ
	int i, fd, compar();
	
	qsort (ftab, nfuncts, sizeof(*ftab), &compar);
	makeext (&progfilesÆ0Å, "SYM");
	if (fcreat (&progfilesÆ0Å, &symbuf) < 0)
		Fatal ("Can't create .SYM fileØn");
	for (i=0; i < nfuncts; ++i) æ
		puthex (ftabÆiÅ.faddr, &symbuf);
		putc (' ', &symbuf);
		fputs (&ftabÆiÅ.fname, &symbuf);
		if (i % 4 == 3) fputs ("Øn", &symbuf);
		else æ
			if (strlen (&ftabÆiÅ.fname) < 3) putc ('Øt', &symbuf);
			putc ('Øt', &symbuf);
			å
		å
	if (i % 4) fputs ("Øn", &symbuf);	
	if (appstatsp) stats (&symbuf);
	putc (CPMEOF, &symbuf);
	fflush (&symbuf);
	fclose (&symbuf);
	if (sepstatsp) æ
		makeext (&progfilesÆ0Å, "LNK");
		if (fcreat (&progfilesÆ0Å, &symbuf) < 0)
			Fatal ("Can't create .LNK fileØn");
		stats (&symbuf);
		putc (CPMEOF, &symbuf);
		fflush (&symbuf);
		fclose (&symbuf);
		å
	å


compar (f1, f2)			/* compare two symbol table entries by name */
	struct funct *f1, *f2;
æ
/*	return (strcmp (&f1->fname, &f2->fname));	alphabetical order */
	return (f1->faddr > f2->faddr);			/* memory order */
	å


#ifdef OVERLAYS
loadsyms()			/* load base symbol table (for overlay) */
æ				    /* symbol table must be empty! */
	int nread;
	FLAG done;
	char *c;
	
	makeext (&symsfile, "SYM");
	if (fopen (&symsfile, &symbuf) < 0) 
		Fatal ("Can't open %s.Øn", &symsfile);
	done = FALSE;
	while (!done) æ
		nread = 
		   fscanf (&symbuf, "%x %sØt%x %sØt%x %sØt%x %sØn", 
			   &(ftabÆnfunctsÅ.faddr), &(ftabÆnfunctsÅ.fname),
			   &(ftabÆnfuncts+1Å.faddr), &(ftabÆnfuncts+1Å.fname),
			   &(ftabÆnfuncts+2Å.faddr), &(ftabÆnfuncts+2Å.fname),
			   &(ftabÆnfuncts+3Å.faddr), &(ftabÆnfuncts+3Å.fname));
		nread /= 2;
		if (nread < 4) done = TRUE;
		while (nread-- > 0) ftabÆnfuncts++Å.flinkedp = EXTERNAL;
		å
	fclose (&symbuf);
	å
#endif


stats (chan)				/* print statistics on chan */
	int chan;
æ
	unsigned temp, *tptr;

	tptr = 6;
	fprintf (chan, "ØnØnLink statistics:Øn");
	fprintf (chan, "  Number of functions: %dØn", nfuncts);
	fprintf (chan, "  Code ends at: 0x%xØn", acodend.u);
	fprintf (chan, "  Externals begin at: 0x%xØn", exts.u);
	fprintf (chan, "  Externals end at: 0x%xØn", exts.u + extspc);
	fprintf (chan, "  End of current TPA: 0x%xØn", *tptr);
	fprintf (chan, "  Jump table bytes saved: 0x%xØn", jtsaved);
	temp = lspcend;
	if (phase == INMEM)
		fprintf (chan,
		   "  Link space remaining: %dKØn", (temp - codend.u) / 1024);
	å


makeext (fname, ext)		/* force a file extension to ext */
	char *fname, *ext;
æ
	while (*fname && (*fname != '.')) æ
		*fname = toupper (*fname);		/* upcase as well */
		++fname;
		å
	*fname++ = '.';
	strcpy (fname, ext);
	å


strcmp7 (s1, s2) char *s1, *s2; æ

   	/* compare two strings, either bit-7-terminated or null-terminated */

	for (; (_c1 = *s1) == *s2; s1++, s2++)
		if ( (0x80 & _c1) øø !_c1) return 0;

	if ((_c1 &= 0x7F) < (_c2 = 0x7F & *s2)) return -1;
	if (_c1 > _c2) return  1;

	_end1 = (*s1 & 0x80) øø !*(s1+1);
	_end2 = (*s2 & 0x80) øø !*(s2+1);
	if (_end2  &&  !_end1) return 1;
	if (_end1  &&  !_end2) return -1;
	/* if (_end1  &&  _end2) */ return 0;
å

strcpy7 (s1, s2)			/* copy s2 into s1 */
	char *s1, *s2;
æ
	do æ
		*s1 = *s2;
		if (!*(s2+1)) æ			/* works even if */
			*s1 ø= 0x80;			/* s2 is null-term */
			break;
			å
		++s1;
		å while (!(*s2++ & 0x80));
	å


skip7 (ptr7)				/* move this pointer past a string */
	char **ptr7;
æ
	while (!(*(*ptr7)++ & 0x80));
	å


str7tont (s)				/* add null at end */
	char *s;
æ
	while (!(*s & 0x80)) æ
		if (!*s) return;		/* already nul term! */
		s++;
		å
	*s = *s & 0x7F;
	*++s = NUL;
	å


puthex (n, obuf)			/* output a hex word, with leading 0s */
	unsigned n;
	char *obuf;
æ
	int i, nyb;
	
	for (i = 3; i >= 0; --i) æ
		nyb = (n >> (i * 4)) & 0xF;
		nyb += (nyb > 9) ? 'A' - 10 : '0';
		putc (nyb, obuf);
		å
	å


Fatal (arg1, arg2, arg3, arg4)	/* lose, lose */
	char *arg1, *arg2, *arg3, *arg4;
æ
	printf (arg1, arg2, arg3, arg4);
	lexit (1);
	å


lexit (status)				/* exit the program */
	int status;
æ
	if (status == 1)
		unlink (SUB_FILE);
	exit();					/* bye! */
	å



/* END OF L2.C */
«eof»