smallC V2 CP/M runtime support - (nf)

utzoo!decvax!harpo!npoiv!npois!wbux5!wb2!houxz!ihnp4!ixn5c!inuxc!pur-ee!uiucdcs!schrein utzoo!decvax!harpo!npoiv!npois!wbux5!wb2!houxz!ihnp4!ixn5c!inuxc!pur-ee!uiucdcs!schrein
Sun Mar 13 22:47:05 AEST 1983


#R:uiucdcs:12600001:uiucdcs:12600004:000:44609
uiucdcs!schrein    Mar 12 09:23:00 1983

(smallC V2 CP/M runtime support continued)
(part 4)

%%%%%%%%%% scc/scc/READ_ME %%%%%%%%%%
This directory contains a slightly modified version of the original
smallC V2 compiler obtained from 'net.sources'.

Changes are generally noted; the header file 'smallc.h' is arranged
so as to allow separate compilation of each source file.

	[1234][123].c	the smallc V2 compiler
	misc.c		a small amount of fudging the runtime routines
	smallc.c	static (!!) allocation of global variables

	smallc.h	header file, to allow separate compilation
	c.h		header file, to be used with C/80

Now for the bad news: this has not compiled itself -- but that has not
even been tried. Nor has it compiled on a UN*X system. It has been compiled
using Software Toolwork's C/80 system and Microsoft's MACRO-80.
The result was used to compile utilities and runtime support.

Major bugs (as far as they have been noted) are listed elsewhere.
A major fix is contained in 42.c -- the optimizer has been cleaned up.
Since 'calloc' is now part of the runtime support, work could start
on making it compile itself, while allocating tables dynamically.

The 'wc' utility noted the following:

	0xD9E1	  4735	   572	   222	11.c
	0x7E6A	  6309	   780	   272	12.c
	0x500B	  6855	   765	   314	13.c
	0x5A14	  5159	   729	   293	21.c
	0x0B7A	  7051	   782	   413	22.c
	0x1D8C	  6730	   882	   280	31.c
	0x7B5F	  4613	   505	   230	32.c
	0x6363	  4249	   540	   224	33.c
	0xC33F	  4710	   806	   322	41.c
	0x81F7	  6150	  1037	   430	42.c
	0x2E43	  1073	   192	    53	c.h
	0x169C	  1041	   191	    68	misc.c
	0x982B	  1429	   249	    72	smallc.c
	0x84D0	 10594	  1702	   530	smallc.h
%%%%%%%%%% scc/scc/c.h %%%%%%%%%%
/*
 *	c.h -- CP/M C/80 M80 header file
 *	ats 1/83
 */

#ifndef cpm
#define	cpm		/* signal CP/M system */

	/*
	 *	coding standards
	 */

#define	HALT	exit()	/* bad end */
#define	EXIT	exit()	/* good end */

	/*
	 *	important constants
	 */

#define	TRUE	1	/* active truth values */
#define	FALSE	0
#define	EOF	(-1)	/* end of file getchar() */
#define	NIL	(-1)	/* null pointer from alloc() */
#define	NULL	0	/* no file from fopen() */

	/*
	 *	bug fixes and kludges
	 */

#define	AUTO	auto	/* locals under recursion */
#define	FILE	int	/* fopen et alia */
#define	getc	getch	/* re-route getc to work right */
#define	getchar	_getch	/* re-route getchar to work right */
#define	putc	putch	/* re-route putc to work right */

	/*
	 *	standard i/o support
	 */

extern FILE * fin, * fout;
#define	stdin	fin	/* standard input */
#define	stdout	fout	/* standard output */
extern FILE * stderr;	/* diagnostic output */

	/*
	 *	printf support
	 */

#define printf	prnt_1(),prnt_2
#define fprintf	prnt_1(),prnt_3
#define sprintf	prnt_1(),prnt_4

#endif	/* will be included once */
%%%%%%%%%% scc/scc/misc.c %%%%%%%%%%
/*
 *	smallC C/80 runtime routines
 *	ats 1/83
 */

/*
 *	getarg
 *		as described by Hendrix
 *
 *	fgetc
 *		alias for getch -- getchar() or getc()
 *
 *	fgets
 *		fetch a string using getch()
 *
 *	fputc
 *		alias for putch -- putchar() or putc()
 */

#include <c.h>		/* C/80 system stuff */

getarg(n, str, maxsz, argc, argv)
	int n;		/* argument index */
	char *str;	/* argument text */
	int maxsz;	/* max length */
	int argc,*argv; /* from main() */
{	register char *dptr, *sptr;
	register int cnt;

	if ((n > argc-1) | (n<0))
	{	str[0] = NULL;
		return EOF;
	}
	cnt=0;
	dptr=str;
	sptr=argv[n];
	while (*dptr++ = *sptr++)
		if (++cnt >= maxsz-1)
		{	*dptr = NULL;
			break;
		}
	return cnt;
}

fgetc(fd)
	FILE *fd;
{
#asm
	JMP	getch##
fputc:: JMP	putch##
#endasm
}

fgets(string, size, fd)
	char *string;
	int size;
	int fd;
{	register int ch;
	register char * cp;

	cp = string;
	while(--size && (ch = fgetc(fd)) != '\n' && ch != EOF)
		*cp++ = ch;
	*cp = '\0';
	if (size && ch == EOF && cp == string)
		return NULL;
	return string;
}
%%%%%%%%%% scc/scc/smallc.c %%%%%%%%%%
/*
 *	Small-C Compiler Version 2.0
 *
 *	Copyright 1982 J. E. Hendrix
 *	rev (adaption to cp/m, macro-80) ats 1/83
 */

/*
 *	major changes:
 *
 *	SEPARATE
 *		eliminated; all parts compile separately
 *		all functions are declared in header file
 *
 *	LINK
 *	PDS
 *	CMD_LINE
 *	TAB
 *	PHASE2
 *	OPTIMIZE
 *	COL
 *	UPPER
 *	SMALL_VM
 *	POLL
 *		eliminated; environment is MACRO-80, CP/M
 *
 *	EXTERN
 *		define it once to allocate global variables
 *
 *	C80	to enable C/80 specific code:
 *		abort	alias for exit
 *		added relevant part of stdio.h here
 *
 *	CCDDPDP[CI] are too long for preprocessor
 *	rename plunge[12] to plung[12] for MACRO-80
 */

/*
 *	major bugs:
 *
 *	HASH	can't define -- eliminates nextsym needed by STGOTO
 *
 *	must `extern' external functions for MACRO-80
 *
 *	very permissive about syntax like `int f*;'
 *
 *	generates char [10] for char *[10] w/out warning
 *
 *	doesn't notice lots of duplicate definitions
 *
 *	very ungraceful about overrunning tables
 *	like switch table or literal pool
 *
 *	complains about multiple externs to same name
 *
 *	should not allow MACRO-80 reserved names as global
 */

/*
 *	major fixes:
 *
 *	CCDDPDP[CI] are too long for preprocessor
 *	rename plunge[12] to plung[12] for MACRO-80
 *
 *	maps \-escapes correctly now
 *
 *	no longer creates undefined first label
 *	on pure data file
 */

#define EXTERN		/* define globale variables */
#include "smallc.h"
%%%%%%%%%% scc/scc/smallc.h %%%%%%%%%%
/*
 *	smallc.h -- header file	Small-C Compiler Version 2.0
 */

#define	C80		/* Software Toolworks C/80 V2.0 */

#ifdef C80
#include <c.h>		/* C/80 system stuff */

#define	abort	exit

#define ERR	(-2)	/* extra smallC stdio.h stuff */
#define YES	1
#define NO	0
#endif C80

#ifndef EXTERN
#define EXTERN	extern	/* globals allocated elsewhere */
#else
#undef EXTERN
#define EXTERN		/* globals allocated here */
#endif EXTERN

/*
 *	remaining compile options
 */

#define NOCCARGC	/* no calls to CCARGC */
/* #define HASH		/* use hash search for macros */
/* #define DYNAMIC	/* allocate memory dynamically */

/*
 *	machine dependent parameters
 */

#define BPW	2	/* bytes per word */
#define LBPW	1	/* log2(BPW) */
#define SBPC	1	/* stack bytes per character */

/*
 *	symbol table format
 */

#define IDENT	0
#define TYPE	1
#define CLASS	2
#define OFFSET	3
#define NAME	5
#define OFFSIZE (NAME - OFFSET)
#define SYMAVG	10
#define SYMMAX	14

/*
 *	symbol table parameters
 */

#define NUMLOCS		25
#define STARTLOC	symtab
#define ENDLOC		(symtab + NUMLOCS*SYMAVG)
#define NUMGLBS		180
#define STARTGLB	ENDLOC
#define ENDGLB		(ENDLOC + (NUMGLBS-1)*SYMMAX)
#define SYMTBSZ		(NUMLOCS*SYMAVG + NUMGLBS*SYMMAX)

/*
 *	System wide name size (for symbols)
 */

#define NAMESIZE	9
#define NAMEMAX		8

/*
 *	possible entries for "IDENT"
 */

#define LABEL		0
#define VARIABLE	1
#define ARRAY		2
#define POINTER		3
#define FUNCTION	4

/*
 *	possible entries for "TYPE"
 *	low order 2 bits make type unique within length
 *	high order bits give length of object
 */

/*	LABEL		0 */
#define CCHAR		(1 << 2)
#define CINT		(BPW << 2)

/*
 *	possible entries for "CLASS"
 */

/*	LABEL		0 */
#define STATIC		1
#define AUTOMATIC	2
#define EXTERNAL	3

/*
 *	"switch" table
 */

#define SWSIZ		(2*BPW)
#define SWTABSZ		(25*SWSIZ)

/*
 *	"while" statement queue
 */

#define WQTABSZ		30
#define WQSIZ		3
#define WQMAX		(wq + WQTABSZ-WQSIZ)

/*
 *	entry offsets in while queue
 */

#define WQSP		0
#define WQLOOP		1
#define WQEXIT		2

/*
 *	literal pool
 */

#define LITABSZ		700
#define LITMAX		(LITABSZ-1)

/*
 *	input line
 */

#define LINEMAX		100
#define LINESIZE	(LINEMAX+1)

/*
 *	output staging buffer size
 */

#define STAGESIZE	800
#define STAGELIMIT	(STAGESIZE-1)

/*
 *	macro (define) pool
 */

#ifdef HASH
#define MACNBR		90
#define MACNSIZE	(90 * (NAMESIZE+2))
#define MACNEND		(macn + MACNSIZE)
#define MACQSIZE	(90 * 5)
#else
#define MACQSIZE	950
#endif
#define MACMAX		(MACQSIZE-1)

/*
 *	 statement types
 */

#define STIF		1
#define STWHILE		2
#define STRETURN	3
#define STBREAK		4
#define STCONT		5
#define STASM		6
#define STEXPR		7
#define STDO		8	/* compile "do" logic */
#define STFOR		9	/* compile "for" logic */
#define STSWITCH	10	/* compile "switch/case/default" logic */
#define STCASE		11
#define STDEF		12
#define STGOTO		13	/* compile "goto" logic */

/*
 *	miscellaneous storage
 *	to be allocate once by defining EXTERN
 */

EXTERN char
	optimize,	/* optimize output of staging buffer */
	alarm,		/* audible alarm on errors? */
	monitor,	/* monitor function headers? */
	pause,		/* pause for operator on errors? */
#ifdef DYNAMIC
	*stage,		/* output staging buffer */
	*symtab,	/* symbol table */
	*litq,		/* literal pool */
#ifdef HASH
	*macn,		/* macro name buffer */
#endif
	*macq,		/* macro string buffer */
	*pline,		/* parsing buffer */
	*mline,		/* macro buffer */
#else
	stage[STAGESIZE],
	symtab[SYMTBSZ],
	litq[LITABSZ],
#ifdef HASH
	macn[MACNSIZE],
#endif
	macq[MACQSIZE],
	pline[LINESIZE],
	mline[LINESIZE],
	swq[SWTABSZ],
#endif
	*line,		/* points to pline or mline */
	*lptr,		/* ptr to either */
	*glbptr,	/* ptrs to next entries */
	*locptr,	/* ptr to next local symbol */
	*stagenext,	/* next addr in stage */
	*stagelast,	/* last addr in stage */
	quote[2],	/* literal string for '"' */
	*cptr,		/* work ptrs to any char buffer */
	*cptr2,
	*cptr3,
	msname[NAMESIZE],	/* macro symbol name array */
	ssname[NAMESIZE];	/* static symbol name array */

EXTERN int
#ifdef STGOTO
	nogo,		/* > 0 disables goto statements */
	noloc,		/* > 0 disables block locals */
#endif
	op[16],		/* function addresses of binary operators */
	op2[16],	/* same for unsigned operators */
	opindex,	/* index to matched operator */
	opsize,		/* size of operator in bytes */
	swactive,	/* true inside a switch */
	swdefault,	/* default label #, else 0 */
	*swnext,	/* address of next entry */
	*swend,		/* address of last table entry */
#ifdef DYNAMIC
	*wq,		/* while queue */
#else
	wq[WQTABSZ],
#endif
	argcs,		/* static argc */
	*argvs,		/* static argv */
	*wqptr,		/* ptr to next entry */
	litptr,		/* ptr to next entry */
	macptr,		/* macro buffer index */
#ifndef HASH
	mack,		/* variable k for findmac routine */
#endif
	pptr,		/* ptr to parsing buffer */
	oper,		/* address of binary operator function */
	ch,		/* current character of line being scanned */
	nch,		/* next character of line being scanned */
	declared,	/* # of local bytes declared, else -1 when done */
	iflevel,	/* #if... nest level */
	skiplevel,	/* level at which #if... skipping started */
	nxtlab,		/* next avail label # */
	litlab,		/* label # assigned to literal pool */
	csp,		/* compiler relative stk ptr */
	argstk,		/* function arg sp */
	argtop,
	ncmp,		/* # open compound statements */
	errflag,	/* non-zero after 1st error in statement */
	eof,		/* set non-zero on final input eof */
	input,		/* fd # for input file */
	input2,		/* fd # for "include" file */
	output,		/* fd # for output file */
	files,		/* non-zero if file list specified on cmd line */
	filearg,	/* cur file arg index */
	glbflag,	/* non-zero if internal globals */
	ctext,		/* non-zero to intermix c-source */
	ccode,		/* non-zero while parsing c-code */
			/* zero when passing assembly code */
	listfp,		/* file pointer to list device */
	lastst,		/* last executed statement type */
	*iptr;		/* work ptr to any int buffer */

/*
 *	global declarations for all functions
 */

/*
 *	11.c
 */

int	main(),
	parse(),	/* process all input text */
	dumplits(),	/* dump literal pool *l
	dumpzero(),	/* dump zeros for default initial values */
	outside(),	/* verify compile ends outside any function */
	ask(),		/* get runtime options */
	openin(),	/* open next input file */
	setops(),	/* initialize op arrays */

/*
 *	12.c
 */

	doinclude(),	/* open include file */
	dodeclare(),	/* test for global declarations */
	declglb(),	/* declare a static variable */
	declloc(),	/* declare local variables */
	initials(),	/* initialize global objects */
	init(),		/* evaluate one initializer */
	needsub(),	/* get required array size */
	newfunc(),	/* begin a function */
	doargs(),	/* declare argument types */

/*
 *	13.c
 */

	statement(),	/* statement parser */
	ns(),		/* semicolon enforcer */
	compound(),
	doif(),
	doexpr(),
	dowhile(),

#ifdef STDO
	dodo(),
#endif

#ifdef STFOR
	dofor(),
#endif

#ifdef STSWITCH
	doswitch(),
	docase(),
	dodefault(),
#endif

#ifdef STGOTO
	dogoto(),
	dolabel(),
	addlabel(),
#endif

	doreturn(),
	dobreak(),
	docont(),
	doasm(),

/*
 *	21.c
 */

	junk(),
	endst(),
	illname(),
	multidef(),
	needtoken(),
	needlval(),
	findglb(),
	findloc(),
	addsym(),

#ifndef HASH
	nextsym(),
#endif

	getint(),	/* get int from addr */
	putint(),	/* put int to addr */
	symname(),	/* test if next input legal symbol name */
	upper(),	/* force alpha upper case */
	getlabel(),	/* next avail internal label */
	postlabel(),	/* post a label in the program */
	printlabel(),	/* print number as a label */
	alpha(),	/* test if char is alpha */
	numeric(),	/* test if char is numeric */
	an(),		/* test if character is alphanumeric */
	addwhile(),
	delwhile(),
	readwhile(),
	white(),	/* test for stack/program overlap */
	gch(),
	bump(),
	kill(),
	inbyte(),
	inline(),

/*
 *	22.c
 */

	ifline(),
	keepch(),
	preprocess(),
	noiferr(),
	addmac(),
	putmac(),

#ifdef HASH
	search(),
	hash(),
#else
	findmac(),
#endif

	setstage(),
	clearstage(),
	outdec(),
	ol(),
	ot(),
	outstr(),
	outbyte(),
	cout(),
	sout(),
	lout(),
	xout(),
	nl(),
	tab(),
	col(),
	error(),
	errout(),
	streq(),
	astreq(),
	match(),
	amatch(),
	nextop(),
	blanks(),

/*
 *	31.c
 */

	skim(),		/* skim over terms adjoining || and && */
	dropout(),	/* early dropout from || && */
	plunge(),	/* plunge to a lower level */
	plung1(),	/* unary plunge to lower level */
	plung2(),	/* binary plunge to lower level */
	calc(),
	expression(),
	heir1(),
	heir3(),
	heir4(),
	heir5(),
	heir6(),
	heir7(),
	heir8(),
	heir9(),
	heir10(),
	heir11(),
	heir12(),

/*
 *	32.c
 */

	heir13(),
	heir14(),
	primary(),
	experr(),
	callfunction(),

/*
 *	33.c
 */

	dbltest(),	/* true if val1->int ptr or int[], val2 not ptr [] */
	result(),	/* determine type of binary op */
	step(),
	store(),
	rvalue(),
	test(),
	constexpr(),
	const(),
	const2(),
	constant(),
	number(),
	address(),
	pstr(),
	qstr(),
	stowlit(),
	litchar(),	/* return current literal, bump lit ptr */

/*
 *	41.c
 */
	header(),	/* print all assembler info first */
	csect(),	/* code segment */
	dsect(),	/* data segment */
	trailer(),	/* assembler stuff at end */
	loadargc(),	/* load # args before fct call */
	entry(),	/* decl entry */
	external(),	/* decl external reference */
	indirect(),	/* fetch obj indirect to primary reg */
	getmem(),	/* static mem to primary */
	getloc(),	/* symbol addr to primary */
	putmem(),	/* primary to static */
	putstk(),	/* put on stack type obj in primary */
	move(),		/* primary to secondary */
	swap(),		/* swap primary and secondary */
	immed(),	/* partial instr. to get immediate val to primary */
	immed2(),	/* partial instr to get immediate to secondary */
	push(),		/* primary to stack */
	smartpop(),	/* unpush or pop as required */
	unpush(),	/* replace push by swap */
	pop(),		/* pop stack to secondary */
	swapstk(),	/* swap primary and stack */
	sw(),		/* process switch */
	call(),		/* call subroutine */
	ret(),		/* return from subroutine */
	callstk(),	/* subroutine call to val on stack */
	jump(),		/* jump to internal label */
	testjump(),	/* test primary, jump if false */
	zerojump(),	/* test primary against zero, jump if false */
	defstorage(),	/* define storage */
	point(),	/* point to following object */
	modstk(),	/* modify staack pointer to value */
	doublereg(),	/* double primary reg */

/*
 *	42.c
 */

			/* operators */

	add(),	sub(),	mult(),	div(),	mod(),
	or(),	xor(),	and(),	lneg(),	asr(),
	asl(),	neg(),	com(),	inc(),	dec(),
	eq(),	eq0(),	ne(),	ne0(),	lt(),
	lt0(),	le(),	le0(),	gt(),	gt0(),
	ge(),	ge0(),	ult(),	ult0(),	ule(),
	ugt(),	uge(),

	outjmp(),	/* emit jump to internal label */
	peephole(),
	pp1(),
	pp2(),
	pp3();
%%%%%%%%%% scc/status %%%%%%%%%%
3-04-83	Bugs in code generation for pointers.

1)	int *p;		p = p | 1;

	This should actually be illegal (you cannot use OR on a pointer),
	but it is accepted, and the OR is with 2 (two) not 1 (one)!!
	Due, of course, to the fact that arithmetic with pointers is
	meant to be scaled...

2)	int *p, *q;	p-q

	The value 'p-q', assuming that p points to a higher address than q,
	cannot be negative. But since it is computed by first subtracting
	and then arithmetically shifting, it is, sometimes...
	This is a problem, if you try to compute free space between
	the top of the program and the stack.

2-25-83	Bug in function calls.

	int i, v[5];

	f() {	(i)();		LHLD H,i
				call address in HL
		(v[5])();	LXI H,v
				LXI D,10
				DAD D
				call address in HL
		(v+5)();	LXI H,v
				LXI D,10
				CALL CCDDGI
				call address in HL
	}

	Code in the first case is expected (abuse of "int" as "int (*)()"),
	code in the second and third case is reversed. In effect, function
	pointers can only be used from int variables, not from array elements.

2-21-83	Status of smallC under CP/M.

I now have a runtime support to run smallC programs under CP/M.
This includes interfaces to all BDOS calls, and a very UNIX-compatible
I/O library (FILE * is with us...). Missing at this point is dynamic memory
allocation and seeking in files, both yet to be done.

I have not yet let the compiler compile itself, but I did note the bugs
(and some fixes) as indicated in the following list. I do, therefore,
not share Cain's enthusiasm in the February issue of DDJ.

--- BUG list ---

BUG:	Compiler complains about multiple 'extern' definitions of the
	same name.

IMPACT:	Cosmetic only.

BUG:	Compiler calls external() routine when 'extern' is seen.

IMPACT:	Depends on the assembler used. If it does not like global symbols
	to be defined in a file where they are also made external,
	there will be problems.

BUG:	Compiler transmits global names from source to assembler file.

IMPACT:	Depends on assembler. If it has names (e.g., for registers)
	predefined, or if it silently uses shorter names, there are problems.

BUG:	Switch table and literal pool overruns cause compiler to crash
	very ungracefully.

IMPACT:	Error message (missing token) is quite misleading.

BUG:	Maps escape sequences '\r' silently to 'r', and '\n' to 13,
	i.e., does not know RETURN and maps NEWLINE as RETURN.

IMPACT:	Incompatible with C definition, surprising in the case of '\n'.

FIX:	Obvious in litchar().

BUG:	If source file does not contain a function, a jump to an
	undefined label is generated. This jump is in any case not
	necessary.

IMPACT:	Largely cosmetic, wastes space, however.

FIX:	Eliminate global variables beglab and func1, eliminate
	jump generation in header(), and label generation in newfunc().

BUG:	An array of pointers to character is silently turned into an
	array of character, initialization is 'adjusted' accordingly.
	I.e.,
		char *arr[] ={ "abc", "def", "ghi" };
	will become an array of 12 characters.

IMPACT:	Major, since completely wrong code is generated.

BUG:	Function name cannot be initializer.
	I.e.,
		extern f(); int arr[] ={ f };
	is flagged as not containing a constant.

IMPACT:	Minor - was probably a desing choice.

BUG:	Cannot take address of array name.
	I.e.,
		int arr[10]; ... &arr
	is flagged.

IMPACT:	Minor - the address operator in this case is wrong, but cc and
	pcc were kind enough to forgive.

BUG:	Cannot define HASH feature - eliminates nextsym() routine.

BUG:	Very permissive (without reports) about syntax errors in
	declarations, e.g.,
		int f*;

IMPACT:	Not minor - code stability becomes a problem!

BUG:	Very permissive about duplicate and undefined names.

IMPACT:	Major - possibly compounded by the assembler. E.g., MACRO-80
	has an (unadvertised) feature to turn NUL and NULL into -1.
	Multiply defined names are usually caught by the assembler.

BUG:	The peephole() optimizer demolishes fetches from the stack,
	as indicated by the code sequences below. It only works
	correctly, if a fetch is not followed by a swap (XCHG;;)
	but there are trivial examples, where this is not the case.

IMPACT:	Major - invalidates code generation if OPTIMIZE is included.
	(Note: not specifying the -o switch to smallC will not make
	the problem go away, since this optimization is always performed.)

FIX:	Involved. Basically, all 8 possible patterns from
		[XCHG] LOAD [XCHG]
	can be replaced by PUSH/POP and XCHG sequences individually.
	I revised the optimizer for the case TAB (can only be 9, anyhow),
	using a tree-structured pattern selection path and a simple
	routine to compare pattern and staging buffer.

BAD PATTERNS:			HL	DE
		--------------------------------
		original	x	y
		--------------------------------
		after
		LXI H,#
		DAD SP
		CALL CCGINT	(sp+#)	y
		XCHG		y	(sp+#)
		--------------------------------
		after
		POP D
		PUSH D		x	(sp+0)
		--------------------------------
		after
		POP B
		POP D
		PUSH D
		PUSH B		x	(sp+2)
		--------------------------------
		after
		POP H
		PUSH H		(sp+0)	y
		--------------------------------
		after
		POP B
		POP H
		PUSH H
		PUSH B		(sp+2)	y
		--------------------------------
%%%%%%%%%% scc/uty/READ_ME %%%%%%%%%%
This directory holds some utilities and exercising programs to be
compiled by smallC V2 and run under CP/M with the 'csh' environment.

	bdos	exercise BDOS calls from command line
	bios	exercise BIOS calls from command line
	cat	like UN*X cat, '-h' inserts file names prior to each file
	cmp	like UN*X cmp; conditionalized to also produce 'cp'
	entab	insert \t for multiple spaces
	get	unarchive the runtime library
	hex	dump anything -- including naked disk
	wc	like UN*X wc, '-v' computes sum of non-white-space

See and understand the sources for more information.

Verify numbers produced by 'wc' are as follows:

	0xE460	  7124	   806	   378	bdos.c
	0x932E	  2639	   294	   148	bios.c
	0x45F0	  1221	   185	    73	cat.c
	0xF233	  2853	   435	   172	cmp.c
	0x7F2B	  2493	   403	   139	entab.c
	0x5ED5	  1297	   224	    72	get.c
	0x2D37	  3016	   516	   167	hex.c
	0x8A51	  1534	   255	    95	wc.c
%%%%%%%%%% scc/uty/bdos.c %%%%%%%%%%
/*
 *	bdos.c -- exercise smallC CP/M BDOS calls
 *	ats 2/83
 */

extern	printf(), atoi(), isascii(), isupper(), islower(),
	isdigit(), isspace(), toupper(),
	mkdrive(), mkfilename(), mkfcb(), mkwfcb(),
	dumpbit(), dumpdpb(), dumpfcb(),
	byte(), puthex(),
	_exit(), _end,
	abort(), _getchar(), _putchar(), _rgetchar(), _pputchar(),
	_lputchar(), _dirio(), _giob(), _siob(), _puts(),
	_gets(), _cstat(), _vers(), _reset(), _mount(),
	_open(), _close(), _glob(), _nglob(), _delete(),
	_read(), _write(), _create(), _rename(), _login(),
	_drive(), _setbuf(), _bitmap(), _protect(), _romap(),
	_chmod(), _diskmap(), _uid(), _rread(), _rwrite(),
	_stat(), _record(), _umount(), _rzwrite();

extern char _fbout[];

#define stdout (_fbout)	/* standard output */
#define LEN	128	/* buffer size */
#define	NUL	0	/* null character */
#define ERR	(-2)	/* error return */

char	*f1 = "\n",
	*f2 = " = %x\n",
	*f3 = "\7syntax: %s\n",
	*f4 = " = %x\t";

main(argc,argv)
	int argc;
	int *argv;	/* char ** */
{	char *cp;
	int *ip;
	int i;
	char buf[LEN];
	char fcb[36];

	while (--argc)
	{	i = atoi(*++argv);
		if (0 <= i && i < 20) switch (i) {	/* split switch */
		case 0:
			abort();
		case 1:
			printf("_getchar() ");
			printf("%c\n", _getchar());
			break;
		case 2:
			if (!--argc)
				_exit();
			cp = *++argv;
			printf("_putchar(%c)\n", *cp);
			_putchar(*cp);
			printf(f1);
			break;
		case 3:
			printf("_rgetchar() ");
			printf("%c\n", _rgetchar());
			break;
		case 4:
			if (!--argc)
				_exit();
			cp = *++argv;
			printf("_pputchar(%c)\n", *cp);
			_pputchar(*cp);
			printf(f1);
			break;
		case 5:
			if (!--argc)
				_exit();
			cp = *++argv;
			printf("_lputchar(%c)\n", *cp);
			_lputchar(*cp);
			printf(f1);
			break;
		case 6:
			if (!--argc)
				_exit();
			i = atoi(*++argv);
			printf("_dirio(%d) ", i);
			printf(f2, _dirio(i));
			break;
		case 7:
			printf("_giob()");
			printf(f2, _giob());
			break;
		case 8:
			if (!--argc)
				_exit();
			i = atoi(*++argv);
			printf("_siob(%x)", i);
			_siob(i);
			printf(f1);
			break;
		case 9:
			if (!--argc)
				_exit();
			cp = *++argv;
			printf("_puts(%s)\n", cp);
			_puts(cp);
			printf(f1);
			break;
		case 10:
			printf("_gets() ");
			buf[0] = LEN-3;
			_gets(buf);
			buf[2+buf[1]] = NUL;
			printf("\n%d %d %s\n", buf[0], buf[1], buf+2);
			break;
		case 11:
			printf("_cstat()");
			printf(f2, _cstat());
			break;
		case 12:
			printf("_vers()");
			printf(f2, _vers());
			break;
		case 13:
			printf("_reset()");
			_reset();
			printf(f1);
			break;
		case 14:
			if (!--argc)
				_exit();
			i = mkdrive(*++argv);
			if (i < 0 || i > 1)
				printf(f3,*argv);
			else
			{	printf("_mount(%d)", i);
				printf(f2, _mount(i));
			}
			break;
		case 15:
			if (!--argc)
				_exit();
			if (mkfcb(fcb,*++argv) == ERR)
				printf(f3, *argv);
			else
			{	printf("_open(FCB)");
				printf(f2, i = _open(fcb));
				dumpfcb(fcb);
			}
			break;
		case 16:
			printf("_close(FCB)");
			printf(f2, i = _close(fcb));
			break;
		case 17:
			newbuf(buf,0);
			if (!--argc)
				_exit();
			if (mkwfcb(fcb,*++argv) == ERR)
				printf(f3, *argv);
			else
			{	printf("_glob(FCB)");
				printf(f2, i = _glob(fcb));
				dircode(i,buf);
			}
			break;
		case 18:
			_setbuf(buf);
			printf("_nglob()");
			printf(f2, i = _nglob());
			dircode(i,buf);
			break;
		case 19:
			if (!--argc)
				_exit();
			if (mkwfcb(fcb,*++argv) == ERR)
				printf(f3, *argv);
			else
			{	printf("_delete(FCB)");
				printf(f2, i = _delete(fcb));
			}
			break;
		}
		else if (20 <= i && i < 38 || i == 40) switch(i) {
		case 20:
			if (!--argc)
				_exit();
			for (i = atoi(*++argv); i>0; i--)
			{	newbuf(buf,0);
				printf("_read(FCB)");
				printf(f4, _read(fcb));
				puthex(buf,buf,LEN,stdout);
			}
			dumpfcb(fcb);
			break;
		case 21:
			if (!--argc)
				_exit();
			for (i = atoi(*++argv); i>0; i--)
			{	newbuf(buf, fcb[32]);
				printf("_write(FCB)");
				printf(f4, _write(fcb));
				puthex(buf,buf,LEN,stdout);
			}
			dumpfcb(fcb);
			break;
		case 22:
			if (!--argc)
				_exit();
			if (mkfcb(fcb,*++argv) == ERR)
				printf(f3, *argv);
			else
			{	printf("_create(FCB)");
				printf(f2, i = _create(fcb));
			}
			break;
		case 23:
			if (!--argc)
				_exit();
			if (mkfcb(fcb,*++argv) == ERR)
				printf(f3, *argv);
			else if (!--argc)
				_exit();
			else if (mkfilename(fcb+16,*++argv) == ERR)
				printf(f3, *argv);
			else
			{	printf("_rename(FCB)");
				printf(f2, i = _rename(fcb));
			}
			break;
		case 24:
			printf("_login()");
			printf(f2, _login());
			break;
		case 25:
			printf("_drive()");
			printf(f2, _drive());
			break;
		case 26:
			if (!--argc)
				_exit();
			if ((cp = atoi(*++argv)) < &_end)
				printf("\7overlaps program\n");
			else
			{	printf("_setbuf(%x)", cp);
				_setbuf(cp);
				printf(f1);
			}
			break;
		case 27:
			printf("_bitmap()");
			printf(f2, cp = _bitmap());
			dumpbit(cp);
			break;
		case 28:
			printf("_protect()");
			_protect();
			printf(f1);
			break;
		case 29:
			printf("_romap()");
			printf(f2, _romap());
			break;
		case 30:
			if (!--argc)
				_exit();
			if (mkfcb(fcb,*++argv) == ERR)
				printf(f3, *argv);
			else if (!--argc)
				_exit();
			else
			{	i = atoi(*++argv);
				printf("_chmod(%d)",i);
				if (i&1)
					fcb[9] |= 128;
				else
					fcb[9] &= ~128;
				if (i&2)
					fcb[10] |= 128;
				else
					fcb[10] &= ~128;
				printf(f2, i = _chmod(fcb));
				dumpfcb(fcb);
			}
			break;
		case 31:
			printf("_diskmap()");
			printf(f2, cp = _diskmap());
			dumpdpb(cp);
			break;
		case 32:
			if (!--argc)
				_exit();
			i = atoi(*++argv);
			printf("_uid(%x)", i);
			printf(f2, _uid(i));
			break;
		case 33:
			if (!--argc)
				_exit();
			ip = fcb+33;	/* FCB_RR */
			*ip = atoi(*++argv);
			fcb[35] = 0;	/* FCB_OV */
			newbuf(buf,0);
			printf("_rread(FCB)");
			printf(f4, _rread(fcb));
			puthex(buf,buf,LEN,stdout);
			dumpfcb(fcb);
			break;
		case 34:
			if (!--argc)
				_exit();
			ip = fcb+33;
			*ip = atoi(*++argv);
			fcb[35] = 0;
			newbuf(buf, *ip);
			printf("_rwrite(FCB)");
			printf(f4, _rwrite(fcb));
			puthex(buf,buf,LEN,stdout);
			dumpfcb(fcb);
			break;
		case 35:
			if (!--argc)
				_exit();
			if (mkfcb(fcb,*++argv) == ERR)
				printf(f3, *argv);
			else
			{	printf("_stat(FCB)");
				_stat(fcb);
				printf(f1);
				dumpfcb(fcb);
			}
			break;
		case 36:
			printf("_record(FCB)");
			_record(fcb);
			printf(f1);
			dumpfcb(fcb);
			break;
		case 37:
			if (!--argc)
				_exit();
			i = atoi(*++argv);
			printf("_umount(%x)", i);
			printf(f2, _umount(i));
			break;
		case 40:
			if (!--argc)
				_exit();
			ip = fcb+33;
			*ip = atoi(*++argv);
			fcb[35] = 0;
			newbuf(buf, *ip);
			printf("_rzwrite(FCB)");
			printf(f4, _rzwrite(fcb));
			puthex(buf,buf,LEN,stdout);
			dumpfcb(fcb);
			break;
		}
		else
			printf("\7%d??\n",i);
	}
}

newbuf(buf,v)		/* clear and set buffer for DMA */
	char buf[LEN];	/* buffer */
	int v;		/* value to initial */
{	int i;

	for (i=0; i<LEN; i++)
		buf[i] = v;
	_setbuf(buf);
}

dircode(i,buf)		/* display directory code fcb */
	int i;
	char *buf;
{
	if (0 <= i && i < 4)
		dumpfcb(buf+32*i);
}
%%%%%%%%%% scc/uty/bios.c %%%%%%%%%%
/*
 *	bios.c -- exercise smallC CP/M BIOS calls
 *	ats 2/83
 */

extern	atoi(), printf(), _exit(), _end,
	dumpbit(), dumpdpb(), dumpdhd(), puthex(),
	_wboot(), _const(), _conin(), _conout(), _lstout(),
	_punout(), _rdrin(), _home(), _seldsk(), _settrk(),
	_setsec(), _setdma(), _sread(),
	_swrite(),
	_lstst(), _sectran();
extern char _fbout[];

#define	stdout	(_fbout)	/* standard output */
#define LEN	128		/* buffer size */

char	*f1 = "[done]\n",
	*f2 = " = %x\n";

main(argc,argv)
	int argc;
	int *argv;	/* char ** */
{	char *cp;
	int i,j;
	char buf[LEN];

	while (--argc)
	{	switch(i = atoi(*++argv)) {
		default:
			printf("%d??\n", i);
			break;
		case 3:
			printf("_wboot()");
			_wboot();
			printf(f1);
			break;
		case 6:
			printf("_const()");
			printf(f2, _const());
			break;
		case 9:
			printf("_conin() ");
			printf("%c\n", _conin());
			break;
		case 12:
			if (! --argc)
				_exit();
			cp = *++argv;
			printf("_conout(%c)\n", *cp);
			_conout(*cp);
			printf(f1);
			break;
		case 15:
			if (! --argc)
				_exit();
			cp = *++argv;
			printf("_lstout(%c)\n", *cp);
			_lstout(*cp);
			printf(f1);
			break;
		case 18:
			if (! --argc)
				_exit();
			cp = *++argv;
			printf("_punout(%c)\n", *cp);
			_punout(*cp);
			printf(f1);
			break;
		case 21:
			printf("_rdrin() ");
			printf("%c\n", _rdrin());
			break;
		case 24:
			printf("_home()");
			_home();
			printf(f1);
			break;
		case 27:
			if (! --argc)
				_exit();
			i = atoi(*++argv);
			if (! --argc)
				_exit();
			j = atoi(*++argv);
			printf("_seldsk(%d,%d)",i,j);
			printf(f2, cp = _seldsk(i,j));
			if (cp)
				dumpdhd(cp);
			break;
		case 30:
			if (! --argc)
				_exit();
			i = atoi(*++argv);
			printf("_settrk(%d)", i);
			_settrk(i);
			printf(f1);
			break;
		case 33:
			if (! --argc)
				_exit();
			i = atoi(*++argv);
			printf("_setsec(%d)", i);
			_setsec(i);
			printf(f1);
			break;
		case 36:
			if (!--argc)
				_exit();
			if ((cp = atoi(*++argv)) < &_end)
				printf("%04x overlaps program\n", cp);
			else
			{	printf("_setdma(%x)", cp);
				_setdma(cp);
				printf(f1);
			}
			break;
		case 39:
			_setdma(buf);
			printf("_sread()");
			printf(f2, _sread());
			puthex(buf,buf,LEN,stdout);
			break;
		case 42:
			if (! --argc)
				_exit();
			i = atoi(*++argv);
			_setdma(buf);
			printf("_swrite(%d)",i);
			printf(f2, _swrite(i));
			break;
		case 45:
			printf("_lstst()");
			printf(f2,_lstst());
			break;
		case 48:
			if (! --argc)
				_exit();
			i = atoi(*++argv);
			if (! --argc)
				_exit();
			j = atoi(*++argv);
			printf("_sectran(%d,%04x)", i,j);
			printf(" = %d\n", _sectran(i,j));
			break;
		}
	}
}
%%%%%%%%%% scc/uty/cat.c %%%%%%%%%%
/*
 *	cat.c - file concatenation
 *	ats 3/83
 */

#define	FILE	char
#define	NULL	0
#define	NUL	0
#define EOF	(-1)
#define stdin	(_fbin)
#define stdout	(_fbout)
#define	stderr	(_fberr)
extern char _fbin[], _fbout[], _fberr[];

#define HALT	exit()
#define EXIT	exit()
extern exit();

extern fputs(), fopen(), fclose(), strcmp(), fgetc(), putchar();

char usage[] = "cat [-h] [from]...";
char hflag = 0;

main(argc,argv)
	int argc;
	int *argv;	/* really char ** */
{	char *cp;	/* for casting */
	FILE *in;

	while (--argc)
	{	cp = *++argv;
		if (*cp != '-' || *++cp == NUL)
			break;
		switch(*cp) {
		case 'h':
			++hflag;
			break;
		default:
			fputs(usage, stderr);
			HALT;
		}
	}
	if (argc == 0)
		docat(stdin, stdout, "stdin");
	else
		do
		{	if (strcmp(*argv, "-") == 0)
				docat(stdin, stdout, *argv);
			else if ((in = fopen(*argv, "r")) == NULL)
			{	fputs("cannot read ", stderr);
				fputs(*argv, stderr);
			}
			else
			{	docat(in, stdout, *argv);
				fclose(in);
			}
			++argv;
		} while (--argc);
}

docat(in, out, inn)
	FILE *in, *out;
	char * inn;
{	int ch;

	if (hflag)
	{	fputs("%%%%% ", stdout);
		fputs(inn, stdout);
		fputs(" %%%%%\n", stdout);
	}
	while ((ch = fgetc(in)) != EOF)
		putchar(ch);
}
%%%%%%%%%% scc/uty/cmp.c %%%%%%%%%%
/*
 *	cmp.c - file copy and comparison
 *	rev (smallC) ats 3/83
 */

/*
 *	define...
 *
 *	CP	to make		cp [-v] from to
 */

#define	FILE	char
#define	NULL	0

#define stdin	(_fbin)
#define stdout	(_fbout)
#define	stderr	(_fberr)
extern char _fbin[], _fbout[], _fberr[];

#define HALT	exit()
extern exit();

extern fputs(), freopen(), getw(), feof(), ferror(), fprintf();

#ifdef CP
char usage[] = "cp [-v] from to";
extern putw();
#else
char usage[] = "cmp file1 file2";
#endif

main(argc,argv)
	int argc;
	int *argv;	/* really char ** */
{	char *cp;	/* for casting */
#ifdef CP
	int vflag;

	vflag = 0;
#endif
	while (--argc)
	{	cp = *++argv;
		if (*cp != '-')
			break;
		switch(*++cp) {
#ifdef CP
		case 'v':
			++vflag;
			break;
#endif
		default:
			fputs(usage, stderr);
			HALT;
		}
	}
	if (argc != 2)
	{	fputs(usage, stderr);
		HALT;
	}
#ifdef CP
	if (freopen(argv[0], "r", stdin) == NULL)
	{	fputs("cannot read ", stderr);
		fputs(argv[0], stderr);
		HALT;
	}
	else if (freopen(argv[1], "w", stdout) == NULL)
	{	fputs("cannot write ", stderr);
		fputs(argv[1], stderr);
		HALT;
	}
	else
		docopy(stdin, stdout, argv[0], argv[1]);
	if (vflag)
#endif
		if (freopen(argv[0], "r", stdin) == NULL)
		{	fputs("cannot read ", stderr);
			fputs(argv[0], stderr);
			HALT;
		}
		else if (freopen(argv[1], "r", stdout) == NULL)
		{	fputs("cannot read ", stderr);
			fputs(argv[1], stderr);
			HALT;
		}
		else
			docmp(stdin, stdout, argv[0], argv[1]);
}

#ifdef CP
docopy(in, out, inn, outn)
	FILE *in, *out;
	char * inn, *outn;
{	int word;
	int kb, b;

	for (kb = b = 0; ; )
	{	word = getw(in);
		if (feof(in))
		{	fprintf(stderr, "%d KB", kb);
			if (b)
				fprintf(stderr, " %d bytes", b);
			fputs(" copied\n", stderr);
			return;
		}
		if (ferror(in))
		{	fputs("error reading ", stderr);
			fputs(inn, stderr);
			HALT;
		}
		putw(word, out);
		if (feof(out) || ferror(out))
		{	fputs("error writing ", stderr);
			fputs(outn, stderr);
			HALT;
		}
		if ((b += 2) >= 1024)
		{	++kb;
			b = 0;
		}
	}
}
#endif

docmp(fa,fb,fna,fnb)
	FILE *fa, *fb;
	char *fna, *fnb;
{	int wa, wb;
	int kb, b;

	for(kb = b = 0; ; )
	{	wa = getw(fa);
		wb = getw(fb);
		if (feof(fa))
			if (feof(fb))
			{	fprintf(stderr, "%d KB", kb);
				if (b)
					fprintf(stderr, " %d bytes", b);
				fputs(" verified\n", stderr);
				return;
			}
			else
			{	fputs(fna, stderr);
				fputs(" is short", stderr);
				HALT;
			}
		else if (feof(fb))
		{	fputs(fnb, stderr);
			fputs(" is short", stderr);
			HALT;
		}
		if (ferror(fa))
		{	fputs("error reading ", stderr);
			fputs(fna, stderr);
			HALT;
		}
		if (ferror(fb))
		{	fputs("error reading ", stderr);
			fputs(fnb, stderr);
			HALT;
		}
		if (wa != wb)
		{	fprintf(stderr, "verify error at %d KB", kb);
			if (b)
				fprintf(stderr, " %d bytes", b);
			HALT;
		}
		if ((b += 2) >= 1024)
		{	++kb;
			b = 0;
		}
	}
}
%%%%%%%%%% scc/uty/entab.c %%%%%%%%%%
/*
 *	entab - turn blank series into tabs
 *		eliminate trailing white space
 *
 *		will handle blank/tab mixtures
 *		will not turn single blank into tabs (intentionally)
 *		will not handle backspaces
 *	ats 9/82
 *	cpm ats 1/83
 *	cpm smallC ats 3/83
 */

#define FILE	char
#define stdin	(_fbin)
#define stdout	(_fbout)
#define stderr	(_fberr)
#define NULL	0
#define EOF	(-1)
extern char _fbin[], _fbout[], _fberr[];

#define HALT	exit()
#define EXIT	exit()
extern exit();

extern fputs(), freopen(), getchar(), putchar();

#define TAB	8			/* columns per tab */

char usage[] = "entab [-b] [from [to]]";

main(argc, argv)
	int argc;
	int *argv;	/* really char ** */
{	int tab;		/* stored tabs */
	int blank;		/* additionally stored blanks */
	int delay;		/* ==1 if one blank caused tab stop */
	int col;		/* column modulo 8 */
	int ch;
	int bflag;		/* if set: ^\t only */
	int begin;		/* if set: not yet non-white */
	char *cp;		/* for casting */

	tab = blank = delay = col = bflag = 0;

	while (--argc)
	{	cp = *++argv;
		if (*cp != '-')
			break;
		switch(*++cp) {
		case 'b':
			bflag++;
			break;
		default:
			fputs(usage, stderr);
			HALT;
		}
	}
	switch (argc) {
	case 0:
		break;		/* standard i/o */
	case 1:
		if (freopen(argv[0], "r", stdin) == NULL)
		{	fputs("cannot read ", stderr);
			fputs(argv[0], stderr);
			HALT;
		}
		break;
	case 2:
		if (freopen(argv[0], "r", stdin) == NULL)
		{	fputs("cannot read ", stderr);
			fputs(argv[0], stderr);
			HALT;
		}
		if (freopen(argv[1], "w", stdout) == NULL)
		{	fputs("cannot write ", stderr);
			fputs(argv[1], stderr);
			HALT;
		}
		break;
	default:
		fputs(usage, stderr);
		HALT;
	}
	for (begin = 1;;)
		switch(ch = getchar()) {
		case EOF:
			EXIT;
		case '\n':
			putchar('\n');
			col = blank = delay = tab = 0;
			begin = 1;
			continue;
		case '\t':
			if (! begin)
				goto nope;
			tab++;
			if (delay)
				tab++;
			col = blank = delay = 0;
			continue;
		case ' ':
			if (! begin)
				goto nope;
			if (delay)
			{	delay = 0;
				tab++;
				blank++;
				col++;
			}
			else if (blank == 0 && col+1 >= TAB)
			{	delay++;
				col = 0;
			}
			else
			{	blank++;
				if (++col >= TAB)
				{	tab++;
					col = blank = 0;
				}
			}
			continue;
		default:
			if (begin && bflag)
				begin = 0;
nope:			if (delay)
				putchar(' ');
			else
			{	while (tab--)
					putchar('\t');
				while (blank--)
					putchar(' ');
			}
			tab = delay = blank = 0;
			putchar(ch);
			if (++col >= TAB)
				col = 0;
			continue;
		}
}
%%%%%%%%%% scc/uty/get.c %%%%%%%%%%
/*
 *	get.c -- extract archived text
 *	ats 2/83
 *
 *	used to extract from the libraries:
 *
 *	'flags'	are one or more characters.
 *	Lines are copied from stdin to stdout,
 *	provided they start with a 'flags' character.
 *	The 'flags' character is not copied.
 */

#define	FILE	char
#define	stdout	_fbout
#define	stderr	_fberr
#define	NULL	0
#define	EOF	(-1)

extern char _fbout[], _fberr[];
extern fputs(), abort(), getchar(), fputc(), exit();

char *usage = "usage: get flags";
#define	OOPS	fputs(usage, stderr), abort()

char flags['~'-' '+1];

isflag(ch)		/* return TRUE if... */
	int ch;		/* ...this is a flag */
{
	return ch >= ' ' && ch <= '~';
}

toflag(ch)		/* return position if... */
	char ch;	/* ...this is a flag */
{
	return ch - ' ';
}

main(argc,argv)
	int argc;
	int *argv;	/* really char ** */
{	char *cp;
	int ch;

	while (--argc)
		for (cp = *++argv; ch = *cp; cp++)
			if (isflag(ch))
				flags[toflag(ch)]++;
			else
				OOPS;
	for (;;)
		if ((ch = getchar()) == EOF)
			return;
		else if (isflag(ch) && flags[toflag(ch)])
			doline(stdout);
		else if (ch != '\n')
			doline(NULL);
}

doline(out)
	FILE *out;
{	int ch, eof;

	do
	{	if ((eof = ch = getchar()) == EOF)
			ch = '\n';
		if (out != NULL)
			fputc(ch, out);
	} while (ch != '\n');
	if (eof == EOF)
		exit();
}
%%%%%%%%%% scc/uty/hex.c %%%%%%%%%%
/*
 *	hex.c -- CP/M file dump program
 *	ats 3/83
 */

/*
 *	BUGS:	offsets and addresses are handled in 16 bits,
 *		the displayed address thus will wrap around.
 *		Things are pretty much locked into
 *		CP/M sectors, tracks, and blocks as on the Osborne...
 */

extern _dopen();	/* enable raw disk i/o */

char usage[] = "hex [-b[+][w|s|k|b|t]#] [-l[+][w|s|k|b|t]#]";

#define stdin	(_fbin)
#define stdout	(_fbout)
#define stderr	(_fberr)
extern char _fbin[], _fbout[], _fberr[];

#define	HALT	exit()
extern exit();

extern atoi(), fputs(), feof(), printf(), puthex(), getw(), fseek();

/*
 *	if the following defines are changed,
 *	'getarg' should be reviewed for scale and meaning
 */

#define	SMODE	8	/* fseek measured in sectors */
#define	SLEN	128	/* sector length */
#define	LSLEN	7	/* log2 of SLEN */
#define CPW	2	/* sizeof(int), really */
#define SPT	20	/* sectors/track (Osborne) */

main(argc,argv)
	int argc;
	int *argv;
{	char *cp;	/* for casting */
	int mode, first, offset;
	int lflag, sectors, bytes;

	mode =
	first =
	offset =
	lflag =
	sectors =
	bytes = 0;
	while (--argc)
	{	cp = *++argv;
		if (*cp != '-')
		{	fputs(usage, stderr);
			HALT;
		}
		switch (*++cp) {
		default:
			fputs(usage, stderr);
			HALT;
		case 'b':
			getarg(cp, &mode, &first, &offset);
			continue;
		case 'l':
			getarg(cp, &lflag, &sectors, &bytes);
			lflag = 1;
			continue;
		}
	}
	doseek(mode, first, &offset);
	dohex(first, offset, lflag, sectors, bytes);
}

doseek(mode,first,offset)
	int mode, first, *offset;
{
	if (mode == 0)
		first = first << LSLEN | *offset;
	else
		*offset = 0;
	if (first && fseek(stdin, first, mode) == -1)
	{	fputs("unable to position", stderr);
		HALT;
	}
}

dohex(first, offset, lflag, sectors, bytes)
	int first;		/* # first sector */
	int offset;		/* offset in sector */
	int lflag;		/* 0: to EOF */
	int sectors;		/* sectors to show */
	int bytes;		/* plus bytes to show */
{	char buf[SLEN];
	int *wp;
	int len;

	for ( ; !lflag || sectors; --sectors)
	{	wp = buf;
		for (len = 0; len<SLEN; len += CPW)
		{	*wp++ = getw(stdin);
			if (feof(stdin))
				break;
		}
		if (len)
			puthex(first<<LSLEN | offset, buf, len, stdout);
		if (feof(stdin))
			return;
		++first;
	}
	if (bytes)
	{	wp = buf;
		for (len = 0; len < bytes; len += CPW)
		{	*wp++ = getw(stdin);
			if (feof(stdin))
				break;
		}
		if (len)
			puthex(first<<7 | offset, buf, len, stdout);
	}
}

getarg(cp, mode, sec, off)
	char *cp;
	int *mode, *sec, *off;
{	int m,s,o,plus;

	if (*++cp == '+')
	{	plus = 1;
		++cp;
	}
	else
		plus = 0;
	m = s = o = 0;
	switch (*cp) {
	default:
		o = atoi(cp);
		break;
	case 'w':
		o = atoi(++cp) << 1;
		break;
	case 's':
		m = SMODE;
		s = atoi(++cp);
		break;
	case 'k':
		m = SMODE;
		s = atoi(++cp) << 3;
		break;
	case 'b':
		m = SMODE;
		s = atoi(++cp) << 4;
		break;
	case 't':
		m = SMODE;
		s = atoi(++cp) * SPT;
	}
	if (plus)
	{	*off += o;
		*sec += s + (*off >> LSLEN);
		*off &= SLEN-1;
	}
	else
	{	*mode = m;
		*sec = s + (o >> LSLEN);
		*off = o & SLEN-1;
	}
}
%%%%%%%%%% scc/uty/wc.c %%%%%%%%%%
/*
 *	wc.c -- words, characters, lines in files
 *	ats 3/83
 */

#define	FILE	char
#define	NULL	0
#define	NUL	0
#define EOF	(-1)
#define stdin	(_fbin)
#define stdout	(_fbout)
#define	stderr	(_fberr)
extern char _fbin[], _fbout[], _fberr[];

#define HALT	exit()
#define EXIT	exit()
extern exit();

extern fputs(), fopen(), fclose(), strcmp(), fgetc(), printf();

char usage[] = "wc [-v] [from]...";
char vflag = 0;

int cc = 0, wc = 0, lc = 0;	/* grand total */

main(argc,argv)
	int argc;
	int *argv;	/* really char ** */
{	char *cp;	/* for casting */
	FILE *in;

	while (--argc)
	{	cp = *++argv;
		if (*cp != '-' || *++cp == NUL)
			break;
		switch(*cp) {
		case 'v':
			++vflag;
			break;
		default:
			fputs(usage, stderr);
			HALT;
		}
	}
	if (argc == 0)
		dowc(stdin, "stdin");
	else
	{	do
		{	if (strcmp(*argv, "-") == 0)
				dowc(stdin, "stdin");
			else if ((in = fopen(*argv, "r")) == NULL)
			{	fputs("cannot read ", stderr);
				fputs(*argv, stderr);
			}
			else
			{	dowc(in, *argv);
				fclose(in);
			}
			++argv;
		} while (--argc);
		printf("\t%6d\t%6d\t%6d\ttotal", cc, wc, lc);
	}
}

dowc(in, inn)
	FILE *in;
	char * inn;
{	int ch;
	int c, w, l, sum, inword;

	c = w = l = sum = inword = 0;
	while ((ch = fgetc(in)) != EOF)
	{	++c;
		switch(ch) {
		case '\n':
			++l;
		case ' ':
		case '\t':
			if (inword)
				inword = 0;
			continue;
		}
		if (! inword)
		{	++inword;
			++w;
		}
		sum += ch;
	}
	if (vflag)
		printf("0x%4x", sum);
	printf("\t%6d\t%6d\t%6d\t%s\n", c, w, l, inn);
	cc += c;
	wc += w;
	lc += l;
}
%%%%%%%%%% end of part 4 and of smallC V2 CP/M runtime support %%%%%%%%%%




More information about the Comp.sources.unix mailing list