[net.sources] smallC V2 CP/M runtime support

schrein (03/14/83)

#N:uiucdcs:12600001:000:65535
uiucdcs!schrein    Mar 11 16:08:00 1983

When I announced this in 'net.micro', I was asked by a number of people
to make it publically available, so....

	smallC V2	a C subset (??) compiler for the 8080 family
	csh		a CP/M MACRO-80 environment for it

As is noted below, this is not complete -- mostly due to the fact that
the compiler still needs a lot of work. The runtime support, however,
is quite compatible with UN*X and thus should be a good starting point
for reworking the compiler.

Good luck to the next author...

Axel Schreiner -- University of Illinois.

%%%%%%%%%% scc/READ_ME %%%%%%%%%%
smallC V2 -- a C subset compiler for the 8080 family

	originally by Ron Cain
	V2 by Jim Hendrix (Dr. Dobb's Journal 12/82, 1/83)
	these sources (slightly modified) from 'net.sources'
	CP/M MACRO-80 runtime support by Axel Schreiner

This directory contains a LIB-80 listing of the runtime library for CP/M,
the announcement placed into 'net.micro', a status report listing some
known problems, and subdirectories with the sources.

	announce	from net.micro
	c.rel		runtime library listing
	rtl		runtime library sources
	scc		slightly modified smallC V2 sources
	status		known problems
	uty		some useful programs

This is not a finished product, but the current author is leaving for
Germany...
%%%%%%%%%% scc/announce %%%%%%%%%%
smallC V2 under CP/M and MACRO-80

I can make a runtime support for Hendrix' smallC V2 available that runs under
CP/M 2.2, likes to be used with Microsoft MACRO-80, and supports the following:

	full BIOS and BDOS interface with exercising programs
	all stdio calls, but for fread, fwrite, ftell, scanf
	string functions, isalpha.. functions
	memory management through calloc and cfree
	CP/M aids, e.g., mkfcb, mkfilename, dumpfcb, ...

	i/o redirection from the command line, including append
	command line in lower case, with \ escapes and '..' ".." strings

	NUL:, DKA:, DKB:, CON:, RDR:, PUN:, and LST: devices

	cat, cp, cmp, entab, hex (dump anything), get (unarchive) utilities

Shortcomings are the multitude of bugs in Hendrix' compiler, the fact that
file i/o is buffered in sectors (i.e., is slow), and that the console
is not buffered (i.e., has no line editing facility), and certain problems
in accessing large files (i.e., arithmetic problems).

If there is sufficient interest, I can place the sources (including a slightly
improved version of smallC) into net.sources -- about 200K.

			Axel Schreiner, University of Illinois.
%%%%%%%%%% scc/c.rel %%%%%%%%%%
Module CRTL      of B:C       REL

Length of Program       757
Length of Data area     0



Entry point(s):

?AND    016C'   ?ASL    01DD'   ?ASR    01CF'   ?COM    01F0'
?DDGC   02B1'   ?DDGI   02BE'   ?DDPPC  02CA'   ?DDPPI  02D1'
?DECC   0281'   ?DECI   0299'   ?DIV    0217'   ?DSGC   02B5'
?DSGI   02C2'   ?EQ     0173'   ?GCHAR  02B8'   ?GE     018D'
?GINT   02C5'   ?GT     017F'   ?INCC   028D'   ?INCI   02A5'
?LE     0186'   ?LNEG   0275'   ?LT     0193'   ?MULT   01F7'
?NE     0179'   ?NEG    01EB'   ?OR     015E'   ?PDPC   02CB'
?PDPI   02D2'   ?PINT   02D5'   ?SMALL  0000'   ?SUB    01E4'
?SWITC  02DB'   ?SXT    02B9'   ?UGE    01AA'   ?UGT    01B6'
?ULE    01BD'   ?ULT    01B0'   ?XOR    0165'   _BITMA  0091'
_CHMOD  00A0'   _CLOSE  005A'   _CONIN  00E8'   _CONOU  00ED'
_CONST  00E3'   _CREAT  0078'   _CSTAT  0041'   _DELET  0069'
_DIRIO  0028'   _DISKM  00A5'   _DRIVE  0087'   _EXIT   0007'
_GETCH  000F'   _GETS   003C'   _GIOB   002D'   _GLOB   005F'
_HOME   0101'   _LOGIN  0082'   _LPUTC  0023'   _LSTOU  00F2'
_LSTST  0124'   _MOUNT  0050'   _NARG   02B9'   _NGLOB  0064'
_OPEN   0055'   _PPUTC  001E'   _PROTE  0096'   _PUNOU  00F7'
_PUTCH  0014'   _PUTS   0037'   _RDRIN  00FC'   _READ   006E'
_RECOR  00BE'   _RENAM  007D'   _RESET  004B'   _RGETC  0019'
_ROMAP  009B'   _RREAD  00AF'   _RWRIT  00B4'   _RZWRI  00C8'
_SECTR  0129'   _SELDS  0106'   _SETBU  008C'   _SETDM  0115'
_SETSE  0110'   _SETTR  010B'   _SIOB   0032'   _SREAD  011A'
_STAT   00B9'   _SWRIT  011F'   _UID    00AA'   _UMOUN  00C3'
_VERS   0046'   _WBOOT  00DE'   _WRITE  0073'   ABORT   000A'


External reference(s):

?30217  0000    _SHELL  0005'   

Module DTAB      of B:C       REL

Length of Program       1289
Length of Data area     158



Entry point(s):

_DBLIN  0255'   _DBLIO  013C'   _DBLOU  028D'   _DBR    005E"
_DBW    006E"   _DCL    008E"   _DCLOS  04B6'   _DNM    0000"
_DOP    002E"   _DOPEN  0000'   _DRD    003E"   _DSEEK  02CA'
_DSK    007E"   _DWR    004E"   

External reference(s):

?30217  0000    ?AND    04C5'   ?ASL    00EB'   ?DDGC   04BE'
?DDPPI  04AC'   ?DIV    0227'   ?DSGI   04DE'   ?EQ     03FC'
?GCHAR  02D8'   ?GE     01D1'   ?GINT   03A8'   ?GT     0411'
?LT     03D2'   ?MULT   036E'   ?NE     04E6'   ?OR     02BD'
?PINT   046C'   ?SMALL  0000    ?SWITC  03BB'   _BGETC  004C"
_BINIT  038B'   _BPUTC  005C"   _FBLIN  005E"   _FBLOU  006E"
_FCLOS  008E"   _FOPEN  002E"   _FSEEK  007E"   _GETCH  0040"
_LPUTC  0056"   _NGETC  0048"   _NOP    0058"   _PPUTC  0054"
_PUTCH  0050"   _RGETC  0042"   _ROMAP  00DB'   _SECTR  0205'
_SELDS  02E0'   _SETDM  024A'   _SETSE  023B'   _SETTR  0234'
_SREAD  0268'   _SWRIT  02A4'   MKDRIV  001B'   WORD    04D6'


Module CSH       of B:C       REL

Length of Program       4986
Length of Data area     751



Entry point(s):

_BGETC  11C5'   _BINIT  1195'   _BPUTC  1292'   _CFP    0283"
_CTYPE  0000"   _FBERR  01D6"   _FBIN   0080"   _FBLOC  0281"
_FBOUT  012B"   _NGETC  1360'   _NOP    1379'   _SHELL  0000'
CALLOC  033F'   CFREE   05A4'   EXIT    0310'   FCLOSE  0F07'
FOPEN   0C08'   FPUTC   1036'   FPUTS   113F'   FREOPE  0C6C'
ISALNU  077C'   ISASCI  0728'   ISLOWE  0767'   ISSPAC  0791'
ISUPPE  0752'   MKARG   082D'   MKDRIV  098C'   MKFCB   0BB8'
MKFIEL  09E1'   MKFILE  0A89'   STRCMP  07CA'   TOLOWE  07A6'
TOUPPE  07B8'   WORD    0825'   

External reference(s):

?30217  0000    ?AND    1289'   ?DDGC   12D1'   ?DDGI   12D6'
?DDPPC  0AF7'   ?DDPPI  132F'   ?DECI   11A5'   ?DSGC   1358'
?DSGI   133F'   ?EQ     117E'   ?GCHAR  1369'   ?GE     0731'
?GINT   1344'   ?GT     042C'   ?INCI   11B7'   ?LNEG   0286'
?LT     0BCB'   ?MULT   0357'   ?OR     1370'   ?PINT   134D'
?SMALL  0000    ?SUB    09DA'   ?SWITC  0EAB'   ?UGE    12BA'
?UGT    0519'   _DBR    1217'   _DBW    12C7'   _DCL    0F47'
_DNM    0D8B'   _DOP    0EC4'   _DRD    0E47'   _DRIVE  0AF1'
_DSK    0000    _DWR    10BF'   _END    05BA'   _EXIT   1091'
MAIN    0303'   

Module FTAB      of B:C       REL

Length of Program       4986
Length of Data area     118



Entry point(s):

_DBR    0046"   _DBW    0052"   _DCL    006A"   _DNM    0000"
_DOP    0022"   _DRD    002E"   _DSK    005E"   _DWR    003A"


External reference(s):

?30217  0000    ?SMALL  0000    _BGETC  002E"   _BINIT  0000 
_BPUTC  003A"   _FBLIN  0046"   _FBLOU  0052"   _FCLOS  006A"
_FOPEN  0022"   _FSEEK  005E"   _GETCH  0030"   _LPUTC  0042"
_NGETC  0038"   _NOP    0044"   _PPUTC  0040"   _PUTCH  003C"
_RGETC  0032"   _ROMAP  0000    MKDRIV  0000    WORD    0000 


Module FIO       of B:C       REL

Length of Program       1749
Length of Data area     0



Entry point(s):

_FBLIN  01A9'   _FBLOU  023A'   _FCLOS  0632'   _FOPEN  0000'
_FSEEK  02CB'   

External reference(s):

?30217  0000    ?AND    0644'   ?ASL    0052'   ?ASR    06AE'
?DDGC   063D'   ?DDPPI  062A'   ?DECI   049D'   ?DSGI   06A2'
?EQ     0580'   ?GCHAR  02A5'   ?GE     04AD'   ?GINT   04F6'
?GT     0595'   ?INCI   04CB'   ?LT     0556'   ?MULT   009E'
?NE     0667'   ?OR     02AD'   ?PINT   069C'   ?SMALL  0000 
?SUB    04C1'   ?SWITC  052F'   _BINIT  0528'   _CLOSE  06A6'
_CREAT  0156'   _DELET  013C'   _GLOB   007C'   _OPEN   00DB'
_ROMAP  003B'   _RREAD  05F7'   _RZWRI  0257'   _SETBU  02D8'
_STAT   02E3'   WORD    0657'   

Module DUMPDH    of B:C       REL

Length of Program       301
Length of Data area     58



Entry point(s):

DUMPDH  0000'   

External reference(s):

?30217  0000    ?DSGI   00DE'   ?SMALL  0000    _FBERR  0000 
_FBIN   0000    _FBOUT  00F1'   DUMPBI  0129'   DUMPDP  0113'
PRINTF  0072'   PUTHEX  00F7'   WORD    0122'   

Module DUMPBI    of B:C       REL

Length of Program       235
Length of Data area     18



Entry point(s):

DUMPBI  0000'   

External reference(s):

?30217  0000    ?AND    0090'   ?ASL    00AB'   ?DECI   00B4'
?DSGC   0089'   ?DSGI   00D4'   ?GCHAR  00A4'   ?INCI   009B'
?LNEG   00B7'   ?LT     0071'   ?PINT   0066'   ?SMALL  0000 
?SUB    00DA'   _FBERR  0000    _FBIN   0000    _FBOUT  0015'
PRINTF  00E0'   PUTBIT  001B'   

Module DUMPDP    of B:C       REL

Length of Program       218
Length of Data area     145



Entry point(s):

DUMPDP  0000'   

External reference(s):

?30217  0000    ?ASL    0036'   ?DSGI   00C4'   ?SMALL  0000 
_FBERR  0000    _FBIN   0000    _FBOUT  0000    BYTE    002F'
PRINTF  00D5'   RWORD   0094'   WORD    00CE'   

Module DUMPFC    of B:C       REL

Length of Program       513
Length of Data area     119



Entry point(s):

DUMPFC  0000'   

External reference(s):

?30217  0000    ?AND    010E'   ?ASR    00B6'   ?DSGI   01D7'
?INCI   01C9'   ?LT     01BB'   ?PINT   01B2'   ?SMALL  0000 
_FBERR  0000    _FBIN   0000    _FBOUT  0000    BYTE    01E7'
PRINTF  01EE'   PUTCHA  01FC'   WORD    0187'   

Module ABS       of B:C       REL

Length of Program       22
Length of Data area     0



Entry point(s):

ABS     0000'   

External reference(s):

?30217  0000    ?NEG    000E'   ?SMALL  0000    

Module ATOI      of B:C       REL

Length of Program       506
Length of Data area     0



Entry point(s):

ATOI    0000'   

External reference(s):

?30217  0000    ?DDPPI  01D6'   ?DSGI   01E5'   ?EQ     00EC'
?GCHAR  0136'   ?GINT   019B'   ?INCI   0133'   ?LT     01B4'
?MULT   01EB'   ?PINT   01A6'   ?SMALL  0000    ?SUB    01A2'
ISDIGI  0145'   ISSPAC  0039'   ISUPPE  0177'   ISXDIG  0169'


Module INDEX     of B:C       REL

Length of Program       53
Length of Data area     0



Entry point(s):

INDEX   0000'   

External reference(s):

?30217  0000    ?DSGC   000E'   ?DSGI   001C'   ?EQ     0011'
?GCHAR  0027'   ?INCI   0023'   ?SMALL  0000    

Module STRCAT    of B:C       REL

Length of Program       79
Length of Data area     0



Entry point(s):

STRCAT  0000'   

External reference(s):

?30217  0000    ?DECI   0025'   ?DSGI   000A'   ?GCHAR  0037'
?INCI   0033'   ?PINT   000D'   ?SMALL  0000    

Module STRCPY    of B:C       REL

Length of Program       49
Length of Data area     0



Entry point(s):

STRCPY  0000'   

External reference(s):

?30217  0000    ?DSGI   000A'   ?GCHAR  001F'   ?INCI   001B'
?PINT   000D'   ?SMALL  0000    

Module STRLEN    of B:C       REL

Length of Program       48
Length of Data area     0



Entry point(s):

STRLEN  0000'   

External reference(s):

?30217  0000    ?GCHAR  0014'   ?INCI   0025'   ?PINT   000A'
?SMALL  0000    

Module PUTBIT    of B:C       REL

Length of Program       314
Length of Data area     6



Entry point(s):

PUTBIT  0000'   

External reference(s):

?30217  0000    ?AND    00D5'   ?ASL    0110'   ?DECI   0119'
?DSGC   00CE'   ?DSGI   0129'   ?GCHAR  0109'   ?INCI   00C5'
?LT     00A9'   ?PINT   0095'   ?SMALL  0000    _FBERR  0000 
_FBIN   0000    _FBOUT  0000    FPRINT  0023'   FPUTC   012F'


Module PUTHEX    of B:C       REL

Length of Program       383
Length of Data area     17



Entry point(s):

PUTHEX  0000'   

External reference(s):

?30217  0000    ?AND    0086'   ?DDGC   007F'   ?DDPPI  015B'
?DSGC   0114'   ?DSGI   0145'   ?GCHAR  00CA'   ?GINT   0163'
?INCI   00C6'   ?LNEG   00FB'   ?LT     00AA'   ?PINT   016E'
?SMALL  0000    ?SUB    016A'   _FBERR  0000    _FBIN   0000 
_FBOUT  0000    FPRINT  008C'   FPUTC   014B'   ISASCI  00D3'
ISCNTR  00F7'   ISPRIN  00E5'   

Module CSHOW     of B:C       REL

Length of Program       318
Length of Data area     44



Entry point(s):

CSHOW   0000'   

External reference(s):

?30217  0000    ?AND    00BD'   ?ASL    00F8'   ?ASR    00A4'
?DSGI   0115'   ?EQ     0032'   ?GINT   0118'   ?INCI   002B'
?PINT   010F'   ?SMALL  0000    ?SUB    009D'   _END    000B'
_FBERR  0123'   CAVAIL  012D'   FPRINT  0133'   FPUTC   0044'


Module CAVAIL    of B:C       REL

Length of Program       104
Length of Data area     0



Entry point(s):

CAVAIL  0000'   

External reference(s):

?30217  0000    ?AND    005C'   ?ASR    0055'   ?PINT   003E'
?SMALL  0000    ?SUB    0063'   _END    0007'   WORD    0032'


Module PRINTF    of B:C       REL

Length of Program       2113
Length of Data area     15



Entry point(s):

_ITOD   0054'   _ITOU   0137'   _ITOX   0206'   _PFEMI  0000'
_PFSTR  0000"   _PRINT  039B'   _UTOI   02E2'   FPRINT  07B1'
PRINTF  0786'   SPRINT  07F6'   

External reference(s):

?30217  0000    ?AND    025D'   ?ASL    01B6'   ?ASR    0256'
?DDGC   0662'   ?DDPPC  02AC'   ?DDPPI  050C'   ?DECI   0751'
?DIV    01D3'   ?DSGC   076B'   ?DSGI   0812'   ?EQ     0689'
?GCHAR  072F'   ?GE     034C'   ?GINT   0824'   ?GT     06BE'
?INCI   072B'   ?LT     0361'   ?MULT   032D'   ?NE     0615'
?NEG    0078'   ?PINT   081F'   ?SMALL  0000    ?SUB    0836'
?SWITC  05CF'   _FBERR  0048'   _FBIN   0000    _FBOUT  0794'
_NARG   07FE'   ABORT   0051'   FPUTC   0033'   FPUTS   004C'
ISDIGI  0307'   

Module MKWFCB    of B:C       REL

Length of Program       80
Length of Data area     0



Entry point(s):

MKWFCB  0000'   

External reference(s):

?30217  0000    ?DSGI   0045'   ?INCI   0021'   ?LT     0013'
?PINT   000A'   ?SMALL  0000    _FBERR  0000    _FBIN   0000 
_FBOUT  0000    MKWFIL  0049'   

Module MKWFIL    of B:C       REL

Length of Program       303
Length of Data area     0



Entry point(s):

MKWFIL  0000'   

External reference(s):

?30217  0000    ?DDGC   000B'   ?DDPPC  006E'   ?DDPPI  005B'
?DSGI   011A'   ?EQ     00A3'   ?GCHAR  011D'   ?GINT   0055'
?INCI   00F6'   ?LT     00E8'   ?PINT   00DF'   ?SMALL  0000 
_DRIVE  0068'   _FBERR  0000    _FBIN   0000    _FBOUT  0000 
MKDRIV  0026'   MKWFIE  00CA'   

Module MKWFIE    of B:C       REL

Length of Program       265
Length of Data area     0



Entry point(s):

MKWFIE  0000'   

External reference(s):

?30217  0000    ?DECI   00EC'   ?EQ     00A6'   ?GCHAR  009F'
?INCI   00F8'   ?SMALL  0000    _FBERR  0000    _FBIN   0000 
_FBOUT  0000    ISASCI  0009'   ISDIGI  002B'   ISLOWE  0075'
ISUPPE  001A'   TOUPPE  0091'   

Module ISPRIN    of B:C       REL

Length of Program       21
Length of Data area     0



Entry point(s):

ISPRIN  0000'   

External reference(s):

?30217  0000    ?AND    0012'   ?DDGC   000B'   ?DSGC   0008'
?SMALL  0000    _CTYPE  0001'   

Module ISCNTR    of B:C       REL

Length of Program       21
Length of Data area     0



Entry point(s):

ISCNTR  0000'   

External reference(s):

?30217  0000    ?AND    0012'   ?DDGC   000B'   ?DSGC   0008'
?SMALL  0000    _CTYPE  0001'   

Module ISALPH    of B:C       REL

Length of Program       21
Length of Data area     0



Entry point(s):

ISALPH  0000'   

External reference(s):

?30217  0000    ?AND    0012'   ?DDGC   000B'   ?DSGC   0008'
?SMALL  0000    _CTYPE  0001'   

Module ISDIGI    of B:C       REL

Length of Program       21
Length of Data area     0



Entry point(s):

ISDIGI  0000'   

External reference(s):

?30217  0000    ?AND    0012'   ?DDGC   000B'   ?DSGC   0008'
?SMALL  0000    _CTYPE  0001'   

Module ISXDIG    of B:C       REL

Length of Program       21
Length of Data area     0



Entry point(s):

ISXDIG  0000'   

External reference(s):

?30217  0000    ?AND    0012'   ?DDGC   000B'   ?DSGC   0008'
?SMALL  0000    _CTYPE  0001'   

Module ISPUNC    of B:C       REL

Length of Program       21
Length of Data area     0



Entry point(s):

ISPUNC  0000'   

External reference(s):

?30217  0000    ?AND    0012'   ?DDGC   000B'   ?DSGC   0008'
?SMALL  0000    _CTYPE  0001'   

Module TOASCI    of B:C       REL

Length of Program       12
Length of Data area     0



Entry point(s):

TOASCI  0000'   

External reference(s):

?30217  0000    ?AND    0009'   ?SMALL  0000    

Module FEOF      of B:C       REL

Length of Program       30
Length of Data area     0



Entry point(s):

FEOF    0000'   

External reference(s):

?30217  0000    ?AND    000F'   ?DDGC   0008'   ?SMALL  0000 
_FBERR  0000    _FBIN   0000    _FBOUT  0000    

Module FERROR    of B:C       REL

Length of Program       18
Length of Data area     0



Entry point(s):

FERROR  0000'   

External reference(s):

?30217  0000    ?AND    000F'   ?DDGC   0008'   ?SMALL  0000 
_FBERR  0000    _FBIN   0000    _FBOUT  0000    

Module CLEARE    of B:C       REL

Length of Program       23
Length of Data area     0



Entry point(s):

CLEARE  0000'   

External reference(s):

?30217  0000    ?AND    0011'   ?GCHAR  000A'   ?SMALL  0000 
_FBERR  0000    _FBIN   0000    _FBOUT  0000    

Module REWIND    of B:C       REL

Length of Program       20
Length of Data area     0



Entry point(s):

REWIND  0000'   

External reference(s):

?30217  0000    ?SMALL  0000    _FBERR  0000    _FBIN   0000 
_FBOUT  0000    FSEEK   000E'   

Module FSEEK     of B:C       REL

Length of Program       807
Length of Data area     0



Entry point(s):

FSEEK   0000'   

External reference(s):

?30217  0000    ?AND    02B4'   ?ASR    00E9'   ?DDGC   02CC'
?DDGI   02D1'   ?DDPPI  01C2'   ?DECI   0155'   ?DSGI   030A'
?EQ     0267'   ?GCHAR  02AD'   ?GE     0161'   ?GINT   01B8'
?INCI   017F'   ?NE     0229'   ?PINT   02D5'   ?SMALL  0000 
?SUB    0175'   ?SWITC  01D6'   _BINIT  0000    _DBW    0244'
_DSK    02BF'   _FBERR  0000    _FBIN   0000    _FBOUT  0000 
_RREAD  0000    _SETBU  0000    _STAT   0000    WORD    0219'


Module GETS      of B:C       REL

Length of Program       111
Length of Data area     0



Entry point(s):

GETS    0000'   

External reference(s):

?30217  0000    ?DSGI   0060'   ?EQ     0036'   ?INCI   004F'
?NE     0026'   ?PINT   0046'   ?SMALL  0000    _FBERR  0000 
_FBIN   0016'   _FBOUT  0000    FGETC   001A'   

Module FGETS     of B:C       REL

Length of Program       152
Length of Data area     0



Entry point(s):

FGETS   0000'   

External reference(s):

?30217  0000    ?DECI   0014'   ?DSGI   0089'   ?EQ     005C'
?INCI   0078'   ?PINT   006C'   ?SMALL  0000    _FBERR  0000 
_FBIN   0000    _FBOUT  0000    FGETC   002C'   

Module GETW      of B:C       REL

Length of Program       359
Length of Data area     17



Entry point(s):

GETW    0000'   

External reference(s):

?30217  0000    ?AND    015C'   ?ASL    014E'   ?DDGC   012F'
?DDGI   0096'   ?DSGC   0155'   ?DSGI   0129'   ?EQ     0032'
?GCHAR  00C0'   ?OR     0160'   ?PINT   009A'   ?SMALL  0000 
_CFP    007C'   _DRD    0084'   _EXIT   0055'   _FBERR  004C'
_FBIN   0000    _FBOUT  0000    FPUTS   0050'   

Module GETCHA    of B:C       REL

Length of Program       9
Length of Data area     0



Entry point(s):

GETCHA  0000'   

External reference(s):

?30217  0000    ?SMALL  0000    _FBERR  0000    _FBIN   0001'
_FBOUT  0000    FGETC   0005'   

Module FGETC     of B:C       REL

Length of Program       417
Length of Data area     17



Entry point(s):

FGETC   0000'   

External reference(s):

?30217  0000    ?AND    00AE'   ?DDGC   0102'   ?DDGI   00DC'
?DSGI   015E'   ?EQ     0109'   ?GCHAR  0166'   ?NE     0128'
?OR     016D'   ?PINT   0121'   ?SMALL  0000    ?SWITC  0183'
_CFP    00C2'   _DRD    00CA'   _EXIT   0055'   _FBERR  004C'
_FBIN   0000    _FBOUT  0000    FPUTS   0050'   UNGETC  014A'


Module UNGETC    of B:C       REL

Length of Program       109
Length of Data area     0



Entry point(s):

UNGETC  0000'   

External reference(s):

?30217  0000    ?AND    0025'   ?DDGC   001E'   ?DSGC   0068'
?EQ     002C'   ?GCHAR  004F'   ?OR     0056'   ?SMALL  0000 
_FBERR  0000    _FBIN   0000    _FBOUT  0000    

Module PUTS      of B:C       REL

Length of Program       114
Length of Data area     0



Entry point(s):

PUTS    0000'   

External reference(s):

?30217  0000    ?DSGC   002B'   ?DSGI   000B'   ?EQ     005E'
?GCHAR  001D'   ?INCI   0019'   ?PINT   000E'   ?SMALL  0000 
_FBERR  0000    _FBIN   0000    _FBOUT  0051'   FPUTC   0055'


Module PUTW      of B:C       REL

Length of Program       276
Length of Data area     17



Entry point(s):

PUTW    0000'   

External reference(s):

?30217  0000    ?AND    00FF'   ?ASR    00E4'   ?DDGC   00F8'
?DDGI   009B'   ?DSGI   010F'   ?EQ     0038'   ?PINT   009F'
?SMALL  0000    _CFP    0081'   _DWR    0089'   _EXIT   005B'
_FBERR  0052'   _FBIN   0000    _FBOUT  0000    FPUTS   0056'


Module PUTCHA    of B:C       REL

Length of Program       17
Length of Data area     0



Entry point(s):

PUTCHA  0000'   

External reference(s):

?30217  0000    ?DSGC   0004'   ?SMALL  0000    _FBERR  0000 
_FBIN   0000    _FBOUT  0008'   FPUTC   000C'   

Module BYTE      of B:C       REL

Length of Program       15
Length of Data area     0



Entry point(s):

BYTE    0000'   

External reference(s):

?30217  0000    ?AND    000C'   ?GCHAR  0005'   ?SMALL  0000 


Module RWORD     of B:C       REL

Length of Program       39
Length of Data area     0



Entry point(s):

RWORD   0000'   

External reference(s):

?30217  0000    ?AND    0020'   ?ASL    000C'   ?DDGC   0019'
?DSGI   0013'   ?GCHAR  0005'   ?OR     0024'   ?SMALL  0000 


Module END       of B:C       REL

Length of Program       6
Length of Data area     6



Entry point(s):

?30217  0000"   _EDATA  0006"   _END    0006'   _EPROG  0006'


Symbol  Value   Defined Referenced

?30217  0000"   END     CRTL    DTAB    CSH     FTAB    FIO
                        DUMPDH  DUMPBI  DUMPDP  DUMPFC  ABS
                        ATOI    INDEX   STRCAT  STRCPY  STRLEN
                        PUTBIT  PUTHEX  CSHOW   CAVAIL  PRINTF
                        MKWFCB  MKWFIL  MKWFIE  ISPRIN  ISCNTR
                        ISALPH  ISDIGI  ISXDIG  ISPUNC  TOASCI
                        FEOF    FERROR  CLEARE  REWIND  FSEEK
                        GETS    FGETS   GETW    GETCHA  FGETC
                        UNGETC  PUTS    PUTW    PUTCHA  BYTE
                        RWORD   
?AND    016C'   CRTL    
                        DTAB    CSH     FIO     DUMPBI  DUMPFC
                        PUTBIT  PUTHEX  CSHOW   CAVAIL  PRINTF
                        ISPRIN  ISCNTR  ISALPH  ISDIGI  ISXDIG
                        ISPUNC  TOASCI  FEOF    FERROR  CLEARE
                        FSEEK   GETW    FGETC   UNGETC  PUTW
                        BYTE    RWORD   
?ASL    01DD'   CRTL    
                        DTAB    FIO     DUMPBI  DUMPDP  PUTBIT
                        CSHOW   PRINTF  GETW    RWORD   
?ASR    01CF'   CRTL    
                        FIO     DUMPFC  CSHOW   CAVAIL  PRINTF
                        FSEEK   PUTW    
?COM    01F0'   CRTL    
?DDGC   02B1'   CRTL    
                        DTAB    CSH     FIO     PUTHEX  PRINTF
                        MKWFIL  ISPRIN  ISCNTR  ISALPH  ISDIGI
                        ISXDIG  ISPUNC  FEOF    FERROR  FSEEK
                        GETW    FGETC   UNGETC  PUTW    RWORD

?DDGI   02BE'   CRTL    
                        CSH     FSEEK   GETW    FGETC   PUTW

?DDPPC  02CA'   CRTL    
                        CSH     PRINTF  MKWFIL  
?DDPPI  02D1'   CRTL    
                        DTAB    CSH     FIO     ATOI    PUTHEX
                        PRINTF  MKWFIL  FSEEK   
?DECC   0281'   CRTL    
?DECI   0299'   CRTL    
                        CSH     FIO     DUMPBI  STRCAT  PUTBIT
                        PRINTF  MKWFIE  FSEEK   FGETS   
?DIV    0217'   CRTL    
                        DTAB    PRINTF  
?DSGC   02B5'   CRTL    
                        CSH     DUMPBI  INDEX   PUTBIT  PUTHEX
                        PRINTF  ISPRIN  ISCNTR  ISALPH  ISDIGI
                        ISXDIG  ISPUNC  GETW    UNGETC  PUTS
                        PUTCHA  
?DSGI   02C2'   CRTL    
                        DTAB    CSH     FIO     DUMPDH  DUMPBI
                        DUMPDP  DUMPFC  ATOI    INDEX   STRCAT
                        STRCPY  PUTBIT  PUTHEX  CSHOW   PRINTF
                        MKWFCB  MKWFIL  FSEEK   GETS    FGETS
                        GETW    FGETC   PUTS    PUTW    RWORD

?EQ     0173'   CRTL    
                        DTAB    CSH     FIO     ATOI    INDEX
                        CSHOW   PRINTF  MKWFIL  MKWFIE  FSEEK
                        GETS    FGETS   GETW    FGETC   UNGETC
                        PUTS    PUTW    
?GCHAR  02B8'   CRTL    
                        DTAB    CSH     FIO     DUMPBI  ATOI
                        INDEX   STRCAT  STRCPY  STRLEN  PUTBIT
                        PUTHEX  PRINTF  MKWFIL  MKWFIE  CLEARE
                        FSEEK   GETW    FGETC   UNGETC  PUTS
                        BYTE    RWORD   
?GE     018D'   CRTL    
                        DTAB    CSH     FIO     PRINTF  FSEEK

?GINT   02C5'   CRTL    
                        DTAB    CSH     FIO     ATOI    PUTHEX
                        CSHOW   PRINTF  MKWFIL  FSEEK   
?GT     017F'   CRTL    
                        DTAB    CSH     FIO     PRINTF  
?INCC   028D'   CRTL    
?INCI   02A5'   CRTL    
                        CSH     FIO     DUMPBI  DUMPFC  ATOI
                        INDEX   STRCAT  STRCPY  STRLEN  PUTBIT
                        PUTHEX  CSHOW   PRINTF  MKWFCB  MKWFIL
                        MKWFIE  FSEEK   GETS    FGETS   PUTS

?LE     0186'   CRTL    
?LNEG   0275'   CRTL    
                        CSH     DUMPBI  PUTHEX  
?LT     0193'   CRTL    
                        DTAB    CSH     FIO     DUMPBI  DUMPFC
                        ATOI    PUTBIT  PUTHEX  PRINTF  MKWFCB
                        MKWFIL  
?MULT   01F7'   CRTL    
                        DTAB    CSH     FIO     ATOI    PRINTF

?NE     0179'   CRTL    
                        DTAB    FIO     PRINTF  FSEEK   GETS
                        FGETC   
?NEG    01EB'   CRTL    
                        ABS     PRINTF  
?OR     015E'   CRTL    
                        DTAB    CSH     FIO     GETW    FGETC
                        UNGETC  RWORD   
?PDPC   02CB'   CRTL    
?PDPI   02D2'   CRTL    
?PINT   02D5'   CRTL    
                        DTAB    CSH     FIO     DUMPBI  DUMPFC
                        ATOI    STRCAT  STRCPY  STRLEN  PUTBIT
                        PUTHEX  CSHOW   CAVAIL  PRINTF  MKWFCB
                        MKWFIL  FSEEK   GETS    FGETS   GETW
                        FGETC   PUTS    PUTW    
?SMALL  0000'   CRTL    
                        DTAB    CSH     FTAB    FIO     DUMPDH
                        DUMPBI  DUMPDP  DUMPFC  ABS     ATOI
                        INDEX   STRCAT  STRCPY  STRLEN  PUTBIT
                        PUTHEX  CSHOW   CAVAIL  PRINTF  MKWFCB
                        MKWFIL  MKWFIE  ISPRIN  ISCNTR  ISALPH
                        ISDIGI  ISXDIG  ISPUNC  TOASCI  FEOF
                        FERROR  CLEARE  REWIND  FSEEK   GETS
                        FGETS   GETW    GETCHA  FGETC   UNGETC
                        PUTS    PUTW    PUTCHA  BYTE    RWORD

?SUB    01E4'   CRTL    
                        CSH     FIO     DUMPBI  ATOI    PUTHEX
                        CSHOW   CAVAIL  PRINTF  FSEEK   
?SWITC  02DB'   CRTL    
                        DTAB    CSH     FIO     PRINTF  FSEEK
                        FGETC   
?SXT    02B9'   CRTL    
?UGE    01AA'   CRTL    
                        CSH     
?UGT    01B6'   CRTL    
                        CSH     
?ULE    01BD'   CRTL    
?ULT    01B0'   CRTL    
?XOR    0165'   CRTL    
_BITMA  0091'   CRTL    
_CHMOD  00A0'   CRTL    
_CLOSE  005A'   CRTL    
                        FIO     
_CONIN  00E8'   CRTL    
_CONOU  00ED'   CRTL    
_CONST  00E3'   CRTL    
_CREAT  0078'   CRTL    
                        FIO     
_CSTAT  0041'   CRTL    
_DELET  0069'   CRTL    
                        FIO     
_DIRIO  0028'   CRTL    
_DISKM  00A5'   CRTL    
_DRIVE  0087'   CRTL    
                        CSH     MKWFIL  
_EXIT   0007'   CRTL    
                        CSH     GETW    FGETC   PUTW    
_GETCH  000F'   CRTL    
                        DTAB    FTAB    
_GETS   003C'   CRTL    
_GIOB   002D'   CRTL    
_GLOB   005F'   CRTL    
                        FIO     
_HOME   0101'   CRTL    
_LOGIN  0082'   CRTL    
_LPUTC  0023'   CRTL    
                        DTAB    FTAB    
_LSTOU  00F2'   CRTL    
_LSTST  0124'   CRTL    
_MOUNT  0050'   CRTL    
_NARG   02B9'   CRTL    
                        PRINTF  
_NGLOB  0064'   CRTL    
_OPEN   0055'   CRTL    
                        FIO     
_PPUTC  001E'   CRTL    
                        DTAB    FTAB    
_PROTE  0096'   CRTL    
_PUNOU  00F7'   CRTL    
_PUTCH  0014'   CRTL    
                        DTAB    FTAB    
_PUTS   0037'   CRTL    
_RDRIN  00FC'   CRTL    
_READ   006E'   CRTL    
_RECOR  00BE'   CRTL    
_RENAM  007D'   CRTL    
_RESET  004B'   CRTL    
_RGETC  0019'   CRTL    
                        DTAB    FTAB    
_ROMAP  009B'   CRTL    
                        DTAB    FTAB    FIO     
_RREAD  00AF'   CRTL    
                        FIO     FSEEK   
_RWRIT  00B4'   CRTL    
_RZWRI  00C8'   CRTL    
                        FIO     
_SECTR  0129'   CRTL    
                        DTAB    
_SELDS  0106'   CRTL    
                        DTAB    
_SETBU  008C'   CRTL    
                        FIO     FSEEK   
_SETDM  0115'   CRTL    
                        DTAB    
_SETSE  0110'   CRTL    
                        DTAB    
_SETTR  010B'   CRTL    
                        DTAB    
_SHELL  0000'   CSH     CRTL    
_SIOB   0032'   CRTL    
_SREAD  011A'   CRTL    
                        DTAB    
_STAT   00B9'   CRTL    
                        FIO     FSEEK   
_SWRIT  011F'   CRTL    
                        DTAB    
_UID    00AA'   CRTL    
_UMOUN  00C3'   CRTL    
_VERS   0046'   CRTL    
_WBOOT  00DE'   CRTL    
_WRITE  0073'   CRTL    
ABORT   000A'   CRTL    
                        PRINTF  
_BGETC  11C5'   CSH     DTAB    FTAB    
_BINIT  1195'   CSH     DTAB    FTAB    FIO     FSEEK   
_BPUTC  1292'   CSH     DTAB    FTAB    
_DBLIN  0255'   DTAB    
_DBLIO  013C'   DTAB    
_DBLOU  028D'   DTAB    
_DBR    005E"   DTAB    
_DBR    0046"   FTAB    CSH     
_DBW    006E"   DTAB    
_DBW    0052"   FTAB    CSH     FSEEK   
_DCL    008E"   DTAB    
_DCL    006A"   FTAB    CSH     
_DCLOS  04B6'   DTAB    
_DNM    0000"   DTAB    
_DNM    0000"   FTAB    CSH     
_DOP    002E"   DTAB    
_DOP    0022"   FTAB    CSH     
_DOPEN  0000'   DTAB    
_DRD    003E"   DTAB    
_DRD    002E"   FTAB    CSH     GETW    FGETC   
_DSEEK  02CA'   DTAB    
_DSK    007E"   DTAB    
_DSK    005E"   FTAB    CSH     FSEEK   
_DWR    004E"   DTAB    
_DWR    003A"   FTAB    CSH     PUTW    
_FBLIN  01A9'   FIO     DTAB    FTAB    
_FBLOU  023A'   FIO     DTAB    FTAB    
_FCLOS  0632'   FIO     DTAB    FTAB    
_FOPEN  0000'   FIO     DTAB    FTAB    
_FSEEK  02CB'   FIO     DTAB    FTAB    
_NGETC  1360'   CSH     DTAB    FTAB    
_NOP    1379'   CSH     DTAB    FTAB    
MKDRIV  098C'   CSH     DTAB    FTAB    MKWFIL  
WORD    0825'   CSH     DTAB    FTAB    FIO     DUMPDH  DUMPDP
                        DUMPFC  CAVAIL  FSEEK   
_CFP    0283"   CSH     
                        GETW    FGETC   PUTW    
_CTYPE  0000"   CSH     
                        ISPRIN  ISCNTR  ISALPH  ISDIGI  ISXDIG
                        ISPUNC  
_END    0006'   END     CSH     CSHOW   CAVAIL  
_FBERR  01D6"   CSH     
                        DUMPDH  DUMPBI  DUMPDP  DUMPFC  PUTBIT
                        PUTHEX  CSHOW   PRINTF  MKWFCB  MKWFIL
                        MKWFIE  FEOF    FERROR  CLEARE  REWIND
                        FSEEK   GETS    FGETS   GETW    GETCHA
                        FGETC   UNGETC  PUTS    PUTW    PUTCHA

_FBIN   0080"   CSH     
                        DUMPDH  DUMPBI  DUMPDP  DUMPFC  PUTBIT
                        PUTHEX  PRINTF  MKWFCB  MKWFIL  MKWFIE
                        FEOF    FERROR  CLEARE  REWIND  FSEEK
                        GETS    FGETS   GETW    GETCHA  FGETC
                        UNGETC  PUTS    PUTW    PUTCHA  
_FBLOC  0281"   CSH     
_FBOUT  012B"   CSH     
                        DUMPDH  DUMPBI  DUMPDP  DUMPFC  PUTBIT
                        PUTHEX  PRINTF  MKWFCB  MKWFIL  MKWFIE
                        FEOF    FERROR  CLEARE  REWIND  FSEEK
                        GETS    FGETS   GETW    GETCHA  FGETC
                        UNGETC  PUTS    PUTW    PUTCHA  
CALLOC  033F'   CSH     
CFREE   05A4'   CSH     
EXIT    0310'   CSH     
FCLOSE  0F07'   CSH     
FOPEN   0C08'   CSH     
FPUTC   1036'   CSH     
                        PUTBIT  PUTHEX  CSHOW   PRINTF  PUTS
                        PUTCHA  
FPUTS   113F'   CSH     
                        PRINTF  GETW    FGETC   PUTW    
FREOPE  0C6C'   CSH     
ISALNU  077C'   CSH     
ISASCI  0728'   CSH     
                        PUTHEX  MKWFIE  
ISLOWE  0767'   CSH     
                        MKWFIE  
ISSPAC  0791'   CSH     
                        ATOI    
ISUPPE  0752'   CSH     
                        ATOI    MKWFIE  
MAIN                    CSH     
MKARG   082D'   CSH     
MKFCB   0BB8'   CSH     
MKFIEL  09E1'   CSH     
MKFILE  0A89'   CSH     
STRCMP  07CA'   CSH     
TOLOWE  07A6'   CSH     
TOUPPE  07B8'   CSH     
                        MKWFIE  
DUMPBI  0000'   DUMPBI  DUMPDH  
DUMPDH  0000'   DUMPDH  
DUMPDP  0000'   DUMPDP  DUMPDH  
PRINTF  0786'   PRINTF  DUMPDH  DUMPBI  DUMPDP  DUMPFC  
PUTHEX  0000'   PUTHEX  DUMPDH  
PUTBIT  0000'   PUTBIT  DUMPBI  
BYTE    0000'   BYTE    DUMPDP  DUMPFC  
RWORD   0000'   RWORD   DUMPDP  
DUMPFC  0000'   DUMPFC  
PUTCHA  0000'   PUTCHA  DUMPFC  
ABS     0000'   ABS     
ATOI    0000'   ATOI    
ISDIGI  0000'   ISDIGI  ATOI    PRINTF  MKWFIE  
ISXDIG  0000'   ISXDIG  ATOI    
INDEX   0000'   INDEX   
STRCAT  0000'   STRCAT  
STRCPY  0000'   STRCPY  
STRLEN  0000'   STRLEN  
FPRINT  07B1'   PRINTF  PUTBIT  PUTHEX  CSHOW   
ISCNTR  0000'   ISCNTR  PUTHEX  
ISPRIN  0000'   ISPRIN  PUTHEX  
CAVAIL  0000'   CAVAIL  CSHOW   
CSHOW   0000'   CSHOW   
_ITOD   0054'   PRINTF  
_ITOU   0137'   PRINTF  
_ITOX   0206'   PRINTF  
_PFEMI  0000'   PRINTF  
_PFSTR  0000"   PRINTF  
_PRINT  039B'   PRINTF  
_UTOI   02E2'   PRINTF  
SPRINT  07F6'   PRINTF  
MKWFCB  0000'   MKWFCB  
MKWFIL  0000'   MKWFIL  MKWFCB  
MKWFIE  0000'   MKWFIE  MKWFIL  
ISALPH  0000'   ISALPH  
ISPUNC  0000'   ISPUNC  
TOASCI  0000'   TOASCI  
FEOF    0000'   FEOF    
FERROR  0000'   FERROR  
CLEARE  0000'   CLEARE  
FSEEK   0000'   FSEEK   REWIND  
REWIND  0000'   REWIND  
FGETC   0000'   FGETC   GETS    FGETS   GETCHA  
GETS    0000'   GETS    
FGETS   0000'   FGETS   
GETW    0000'   GETW    
GETCHA  0000'   GETCHA  
UNGETC  0000'   UNGETC  FGETC   
PUTS    0000'   PUTS    
PUTW    0000'   PUTW    
_EDATA  0006"   END     
_EPROG  0006'   END     



%%%%%%%%%% scc/rtl/2.sub %%%%%%%%%%
;
; putchar
;
$3 #$$p <$1:c0.get >$1:tmp.c
$4 $1:tmp.c >$1:tmp.mac
$5 $2:tmp1=$1:tmp
;
; getw
;
$3 #$$q <$1:c0.get >$1:tmp.c
$4 $1:tmp.c >$1:tmp.mac
$5 $2:tmp2=$1:tmp
;
; putw
;
$3 #$$r <$1:c0.get >$1:tmp.c
$4 $1:tmp.c >$1:tmp.mac
$5 $2:tmp3=$1:tmp
;
; gets		 needs fgetc
;
$3 #$$s <$1:c0.get >$1:tmp.c
$4 $1:tmp.c >$1:tmp.mac
$5 $2:tmp4=$1:tmp
;
; fgets		 needs fgetc
;
$3 #$$t <$1:c0.get >$1:tmp.c
$4 $1:tmp.c >$1:tmp.mac
$5 $2:tmp5=$1:tmp
$6 $2:tmp=$2:clib,$2:tmp1,$2:tmp2,$2:tmp3,$2:tmp4,$2:tmp5/e
era $2:clib.rel
ren $2:clib.rel=$2:tmp.rel
;
; puts
;
$3 #$$u <$1:c0.get >$1:tmp.c
$4 $1:tmp.c >$1:tmp.mac
$5 $2:tmp1=$1:tmp
$6 $2:tmp=$2:clib,$2:tmp1/e
era $2:clib.rel
ren $2:clib.rel=$2:tmp.rel
;
; abs
;
$3 #$$a <$1:c1.get >$1:tmp.c
$4 $1:tmp.c >$1:tmp.mac
$5 $2:tmp1=$1:tmp
;
; atoi		needs is*
;
$3 #$$b <$1:c1.get >$1:tmp.c
$4 $1:tmp.c >$1:tmp.mac
$5 $2:tmp2=$1:tmp
;
; isprint
;
$3 #$$cd <$1:c1.get >$1:tmp.c
$4 $1:tmp.c >$1:tmp.mac
$5 $2:tmp3=$1:tmp
;
; iscntrl
;
$3 #$$ce <$1:c1.get >$1:tmp.c
$4 $1:tmp.c >$1:tmp.mac
$5 $2:tmp4=$1:tmp
;
; isalpha
;
$3 #$$cf <$1:c1.get >$1:tmp.c
$4 $1:tmp.c >$1:tmp.mac
$5 $2:tmp5=$1:tmp
$6 $2:tmp=$2:clib,$2:tmp1,$2:tmp2,$2:tmp3,$2:tmp4,$2:tmp5/e
era $2:clib.rel
ren $2:clib.rel=$2:tmp.rel
submit 3 $1 $2 $3 $4 $5 $6
%%%%%%%%%% scc/rtl/3.sub %%%%%%%%%%
;
; isdigit
;
$3 #$$cg <$1:c1.get >$1:tmp.c
$4 $1:tmp.c >$1:tmp.mac
$5 $2:tmp1=$1:tmp
;
; isxdigit
;
$3 #$$ch <$1:c1.get >$1:tmp.c
$4 $1:tmp.c >$1:tmp.mac
$5 $2:tmp2=$1:tmp
;
; ispunct
;
$3 #$$ci <$1:c1.get >$1:tmp.c
$4 $1:tmp.c >$1:tmp.mac
$5 $2:tmp3=$1:tmp
;
; toascii
;
$3 #$$j <$1:c1.get >$1:tmp.c
$4 $1:tmp.c >$1:tmp.mac
$5 $2:tmp4=$1:tmp
;
; index
;
$3 #$$k <$1:c1.get >$1:tmp.c
$4 $1:tmp.c >$1:tmp.mac
$5 $2:tmp5=$1:tmp
$6 $2:tmp=$2:clib,$2:tmp1,$2:tmp2,$2:tmp3,$2:tmp4,$2:tmp5/e
era $2:clib.rel
ren $2:clib.rel=$2:tmp.rel
;
; strcat
;
$3 #$$m <$1:c1.get >$1:tmp.c
$4 $1:tmp.c >$1:tmp.mac
$5 $2:tmp2=$1:tmp
;
; strcpy
;
$3 #$$p <$1:c1.get >$1:tmp.c
$4 $1:tmp.c >$1:tmp.mac
$5 $2:tmp5=$1:tmp
$6 $2:tmp=$2:clib,$2:tmp2,$2:tmp5/e
era $2:clib.rel
ren $2:clib.rel=$2:tmp.rel
;
; strlen
;
$3 #$$r <$1:c1.get >$1:tmp.c
$4 $1:tmp.c >$1:tmp.mac
$5 $2:tmp2=$1:tmp
;
; byte
;
$3 #$$s <$1:c1.get >$1:tmp.c
$4 $1:tmp.c >$1:tmp.mac
$5 $2:tmp3=$1:tmp
;
; rword
;
$3 #$$t <$1:c1.get >$1:tmp.c
$4 $1:tmp.c >$1:tmp.mac
$5 $2:tmp4=$1:tmp
;
; cshow		needs cavail printf fputc
;
$3 #u <$1:c1.get >$1:tmp.c
$4 $1:tmp.c >$1:tmp.mac
$5 $2:tmp5=$1:tmp
$6 $2:tmp=$2:clib,$2:tmp2,$2:tmp3,$2:tmp4,$2:tmp5/e
era $2:clib.rel
ren $2:clib.rel=$2:tmp.rel
;
; cavail
;
$3 #$$v <$1:c1.get >$1:tmp.c
$4 $1:tmp.c >$1:tmp.mac
$5 $2:tmp1=$1:tmp
;
; dumpdhd	needs printf word puthex dumpbit dumpdpb
;
$3 #\A <$1:c0.get >$1:tmp.c
$4 $1:tmp.c >$1:tmp.mac
$5 $2:tmp2=$1:tmp
;
; putbit	needs fputc fprintf
;
$3 #\B <$1:c0.get >$1:tmp.c
$4 $1:tmp.c >$1:tmp.mac
$5 $2:tmp3=$1:tmp
;
; puthex	needs fputc fprintf is*
;
$3 #\C <$1:c0.get >$1:tmp.c
$4 $1:tmp.c >$1:tmp.mac
$5 $2:tmp4=$1:tmp
$6 $2:tmp=$2:clib,$2:tmp1,$2:tmp2,$2:tmp3,$2:tmp4/e
era $2:clib.rel
ren $2:clib.rel=$2:tmp.rel
era $1:tmp.*
era $2:tmp?.*
%%%%%%%%%% scc/rtl/READ_ME %%%%%%%%%%
This directory contains the 'csh' runtime support for smallC V2.
The files are meant to be processed by the smallC compiler and
by Microsoft's MACRO-80 assembler. A listing of the runtime library
is included -- order is relatively crucial for correct resolution
in one pass. The 'end' module must definitely be linked last.

Most of this has been tested, but...

	make.sub	submit files to process c[01].get
	[23].sub	called by make.sub
	adlib.sub	adds these modules to initial library
	c[01].get	(process using 'get') small auxiliary modules
	crtl.mac	Hendrix' assembler stuff, plus BIOS and BDOS interface
	csh.c		main environment module
	def.h		header file, mostly for c[01].get
	[fd]tab.c	two variants of the driver table
	end.mac		the very last module
	fio.c		file i/o for CP/M
	io.h		actual contents of driver table
	printf.c	Hendrix' printf, extended to [sf]printf

Consult 'c.rel' to see in what order the modules should be in a library.
Consult 'def.h' as well as some utilities to see what a 'stdio.h' header
file should contain...

The 'wc' utility noted the following:

	0x4119	  1260	   175	    76	2.sub
	0xD228	  1770	   240	   104	3.sub
	0x9633	   550	    40	    28	adlib.sub
	0xE80F	 13039	  2381	   628	c0.get
	0xDC08	  4861	   951	   285	c1.get
	0x5260	 14474	  2788	   871	crtl.mac
	0xED52	 14450	  2607	   667	csh.c
	0x1F53	  2990	   553	    92	def.h
	0x55E3	   332	    58	    20	end.mac
	0x9CE8	  4542	   777	   221	fio.c
	0x25E7	   146	    29	     7	ftab.c
	0x7404	  8002	  1341	   423	io.h
	0xC3E9	  1734	   246	    99	make.sub
	0x4D00	  4314	   798	   269	printf.c
%%%%%%%%%% scc/rtl/adlib.sub %%%%%%%%%%
;	smallC runtime support
;
;	c.rel:	indisk($1) outdisk($2)
;		lib-80($3)
;
;	ats 2/83
;
xsub
$3 $1:tmp=$2:c/e
era $2:c.rel
$3
$2:c=$1:tmp<..FIO>
$1:clib<DUMPDH,DUMPBI,DUMPDP,DUMPFC>
$1:clib<ABS,ATOI>
$1:clib<INDEX,STRCAT,STRCPY,STRLEN>
$1:clib<PUTBIT,PUTHEX>
$1:clib<CSHOW,CAVAIL>
$1:printf
$1:clib<MKWFCB,MKWFIL,MKWFIE>
$1:clib<ISPRIN,ISCNTR,ISALPH>
$1:clib<ISDIGI,ISXDIG,ISPUNC,TOASCI>
$1:clib<FEOF,FERROR,CLEARE,REWIND,FSEEK>
$1:clib<GETS,FGETS,GETW,GETCHA,FGETC,UNGETC>
$1:clib<PUTS,PUTW,PUTCHA>
$1:clib<BYTE,RWORD>
$1:tmp<END>
/E
era $1:tmp.rel
%%%%%%%%%% scc/rtl/c0.get %%%%%%%%%%
/*
 *	c?.get -- smallC runtime library for CP/M and MACRO-80
 *	ats 2/83, in part adapted from Jim Hendrix' code
 */

$#define NOCCARGC
##include def.h		/* TO BE FIXED */

/*
 *	module names
 */

##asm
a	NAME	('mkwfield')	; needs is*
b	NAME	('mkwfilename')	; needs mkwfield
c	NAME	('mkwfcb')	; needs mkwfilename
d	NAME	('dumpbit')	; needs putbit printf
e	NAME	('dumpdpb')	; needs putchar printf byte
f	NAME	('dumpfcb')	; needs putchar printf byte
g	NAME	('feof')
h	NAME	('ferror')
i	NAME	('clearerr')
j	NAME	('fseek')
k	NAME	('rewind')	; needs fseek
l
m	NAME	('getchar')	; needs fgetc
n	NAME	('fgetc')	; needs ungetc
o	NAME	('ungetc')
p	NAME	('putchar')
q	NAME	('getw')
r	NAME	('putw')
s	NAME	('gets')	; needs fgetc
t	NAME	('fgets')	; needs fgetc
u	NAME	('puts')

A	NAME	('dumpdhd')	; needs printf, word, dumpdpb, puthex, putbit
B	NAME	('putbit')	; needs fputc, fprintf
C	NAME	('puthex')	; needs fputc, fprintf, is*
##endasm

/*
 *	globally external things (in csh)
 */

#extern char _fbin[];		/* stdin */
#extern char _fbout[];		/* stdout */
#extern char _fberr[];		/* stderr */

/****
 ****	CP/M utility routines
 ****/

/*
 *	wildcard parser routines:
 *
 *	mkwfield(&c,i,&c)	upper-case, copy, pad, return -> next
 *	mkwfilename(&c,&c)	fix-format filename, return success
 *	mkwfcb(&c,&c)		init fcb with file name, return success
 *
 *	all permit '*' for arbitrary tail and '?' for arbitrary letter
 */

aextern isascii(), isupper(), isdigit(), islower(), toupper();
a
aCHAR_P mkwfield(f,l,s)	/* copy isalnum() or ?/* */
a	char *f;	/* upper-cased to this buffer */
a	int l;		/* blank padded to this length */
a	char *s;	/* from this string */
a{
a	do
a		if (isascii(*s))
a			if (isupper(*s) || isdigit(*s) || *s == '?')
a				*f++ = *s++;
a			else if (islower(*s))
a				*f++ = toupper(*s++);
a			else if (*s == '*')
a			{	do
a					*f++ = '?';
a				while (--l);
a				return s+1;
a			}
a			else
a				break;
a		else
a			break;
a	while (--l);
a	while (l--)
a		*f++ = ' ';
a	return s;
a}
	
bextern mkdrive(), mkwfield(), _drive();
b
bINT mkwfilename(fnb, fnm)
b	char fnb[16];	/* to be filled */
b	char *fnm;	/* with this file name/wildcard */
b{	int i;
b
b	if (fnm[1] == ':')
b	{	if ((i = mkdrive(fnm)) == ERR)
b			return ERR;
b		fnb[FCB_ET] = i+1;
b		fnm += 2;
b	}
b	else		/* make sure to set current drive */
b		fnb[FCB_ET] = _drive()+1;
b	fnm = mkwfield(fnb+FCB_FN,8,fnm);
b	if (*fnm == '.')
b		fnm = mkwfield(fnb+FCB_FT,3,fnm+1);
b	else
b		for (i=0; i<3; i++)
b			fnb[FCB_FT+i] = ' ';
b	if (*fnm != NUL)
b		return ERR;
b	return NULL;
b}

cextern mkwfilename();
c
cINT mkwfcb(fcb,fnm)
c	char fcb[FCB_];	/* to be initialized */
c	char *fnm;	/* with this file name/wildcard */
c{	int i;
c
c	for (i=0; i<FCB_; i++)
c		fcb[i] = NUL;
c	return mkwfilename(fcb,fnm);
c}

/*
 *	display routines:
 *
 *	dumpbit(_bitmap())	allocation vector (Osborne-1 size)
 *	dumpdhd(_seldsk())	disk header block
 *	dumpdpb(_diskmap())	disk parameter block
 *	dumpfcb(&fcb)		file control block (Osborne-1 map)
 *
 *	BUG:	dumpbit knows about Osborne-1 disk size
 *		dumpfcb knows about Osborne-1 using 16 byte pointers
 */

d#define BLOCKS		46	/* reservation blocks (Osborne-1) */
d
dextern putbit(), printf();
d
ddumpbit(bitmap)
d	char *bitmap;
d{	char c;
d	int i,j,k;
d
d	putbit(0,bitmap,BLOCKS,stdout);
d	k = 0;
d	for(i=BLOCKS; i; )
d	{	c = *bitmap++;
d		for (j=0; j<8; j++)
d		{	if (c & 128)
d				k++;
d			c <<= 1;
d			if (! --i)
d				break;
d		}
d	}
d	printf("used/free: %d/%d\n", k, BLOCKS-k);
d}

Aextern printf(), word(), puthex(), dumpdpb(), dumpbit();
A
Adumpdhd(dhd)
A	char *dhd;
A{
A	printf("\tXLT  DBF  DPB  CST  RBR\n");
A	printf("%04x:\t%04x %04x %04x %04x %04x\n",
A		dhd,
A		word(dhd+DHD_XLT),
A		word(dhd+DHD_DBF),
A		word(dhd+DHD_DPB),
A		word(dhd+DHD_CST),
A		word(dhd+DHD_RBR));
A	puthex(word(dhd+DHD_XLT), word(dhd+DHD_XLT),
A		word(word(dhd+DHD_DPB)+DPB_SPT), stdout);
A	puthex(word(dhd+DHD_DBF), word(dhd+DHD_DBF), SLEN, stdout);
A	dumpdpb(word(dhd+DHD_DPB));
A	dumpbit(word(dhd+DHD_RBR));
A}

eextern printf(), word(), byte(), rword();
e
edumpdpb(dpb)
e	char *dpb;
e{
e	printf("%6u\tsectors/track\n", word(dpb+DPB_SPT));
e	printf("%6u\tbytes/block\n", SLEN << byte(dpb+DPB_BSH));
e	printf("%6u\tblocks/disk\n", 1 + word(dpb+DPB_DSM));
e	printf("%6u\tdirectory slots\n", 1 + word(dpb+DPB_DRM));
e	printf("directory allocation mask: %04x\n", rword(dpb+DPB_ALB));
e	printf("check area size: %u\n", word(dpb+DPB_CKS));
e	printf("first track: %u\n", word(dpb+DPB_OFF));
e}

fextern printf(), putchar(), byte(), word();
f
fdumpfcb(fcb)
f	char *fcb;
f{	int i;
f
f	printf("%04x ET FILENAME rs EXT EX S1 S2 RC NR RAND OV\n", fcb);
f	printf("     %02x ", byte(fcb+FCB_ET));
f	for (i=0; i<8; i++)
f		printf("%c", byte(fcb+FCB_FN+i));
f	printf(" %d%d ", byte(fcb+FCB_RO)>>7 &1, byte(fcb+FCB_SY)>>7 &1);
f	for (i=0; i<3; i++)
f		printf("%c", byte(fcb+FCB_FT+i)&127);
f	printf(" %02x %02x %02x %02x %02x %04x %02x\n DM:",
f		byte(fcb+FCB_EX),
f		byte(fcb+FCB_S1),
f		byte(fcb+FCB_S2),
f		byte(fcb+FCB_RC),
f		byte(fcb+FCB_NR),
f		word(fcb+FCB_RR),
f		byte(fcb+FCB_OV));
f	for (i=0; i<16; i++)
f		printf(" %02x", byte(fcb+FCB_DM+i));
f	putchar('\n');
f}

/****
 ****	UN*X compatible file management for CP/M
 ****/

/*
 *	file management routines:
 *
 *	feof	return EOF for physical end of file, or NULL
 *	ferror	return last error code (but not EOF), or NULL
 *	clearerr remove error code
 *	fseek	position in (buffered) file
 *	rewind	reposition (buffered) file at beginning
 *
 *	fflush, setbuf
 *		not implemented (not needed??)
 *	fileno, fdopen	
 *		not implemented / not needed
 *	ftell
 *		not implemented / impossible...
 *
 *	BUGS:	fseek has CP/M's idea of end of file for
 *		character files (modes 0,1,2), and does sector
 *		couting on modes 8,9,10. It also cannot handle
 *		unsigned offsets. Any 'ungetc' character is lost.
 *		If seeking is implemented, the file must be buffered.
 *		One may not seek outside the existing file.
 */

gINT feof(fp)
g	FILE *fp;
g{
g	if (fp[FB_FLG] & FB_EOF)
g		return EOF;
g	return NULL;
g}

hINT ferror(fp)
h	FILE *fp;
h{
h	return fp[FB_FLG] & FB_ERM;
h}

iclearerr(fp)
i	FILE *fp;
i{
i	fp[FB_FLG] &= ~FB_ERM;
i}

jextern _dsk[], _dbw[];
jextern word(), _setbuf(), _stat(), _binit(), _rread();
j
jINT fseek(fp, off, mode)
j	FILE *fp;	/* to be positioned */
j	int off;	/* offset */
j	int mode;	/* 0,1,2 or 8,9,10 */
j{	int f;		/* for cuntion call */
j	int csec, cpos;	/* current sector/position */
j	int ssec, spos;	/* seek sector/position */
j
j	if ((fp[FB_FLG] & FB_OPF) == 0 || _dsk[fp[FB_DRV]] == NULL)
j		return -1;		/* unable */
j	csec = word(fp+FCB_RR);
j	cpos = fp;
j	if ((cpos = word(fp+FB_NCP) - (cpos+FB_BUF)) >= SLEN)
j	{	cpos -= SLEN;
j		++csec;
j	}
j	switch(mode) {
j	case 0:			/* char-relative to begin */
j	case 1:			/* char-relative to present-char */
j	case 2:			/* char-relative to char-EOF */
j		ssec = off >> LSLEN;
j		spos = off & SLEN-1;
j		if (mode != 1)
j			break;
j		ssec += csec;
j		if ((spos += cpos) < 0)
j		{	spos += SLEN;
j			--ssec;
j		}
j		else if (spos >= SLEN)
j		{	spos -= SLEN;
j			++ssec;
j		}
j		break;
j	case 8:			/* sector-relative to begin */
j	case 9:			/* sector-relative to present-sector */
j	case 10:		/* sector-relative to sector-EOF */
j		ssec = off;
j		spos = 0;
j		if (mode != 9)
j			break;
j		ssec += csec;
j		break;
j	default:
j		return -1;
j	}
j	if (fp[FB_FLG] & FB_OUF && word(fp+FB_NCP) != fp+FB_BUF)
j	{	f = _dbw[fp[FB_DRV]];
j		if (f == NULL || (f)(fp))
j			return -1;	/* couldn't flush */
j	}
j	fp[FB_FLG] &= ~FB_UNF;		/* drop any FB_UNC */
j	f = _dsk[fp[FB_DRV]];
j	return (f)(fp,mode,csec,cpos,ssec,spos);
j}

kextern fseek();
k
kINT rewind(fp)
k	FILE *fp;
k{
k	return fseek(fp,0,0);
k}

/* l reserved */

/****
 ****	UN*X compatible i/o transfer routines for CP/M
 ****/

/*
 *	character i/o:
 *
 *	getchar()	from stdin
 *	getc(fp)	from fp
 *	fgetc(fp)	from fp
 *		return EOF or character,
 *		return '\n' for RETURN LINEFEED in file,
 *		return '\r' for RETURN in file,
 *		return '\n' for RETURN from device,
 *		return EOF for ^Z or ^D,
 *		set feof() signal only on physical EOF.
 *
 *	ungetc(ch,fp)	push character back, return it or EOF
 *
 *	BUG:	can't push right after '\r' was returned by get
 *
 *	putchar(ch)	to stdout
 *	putc(ch,fp)	to fp (#define as fputc!)
 *		map '\n' to RETURN LINEFEED,
 *		return EOF on hard error.
 */

mextern fgetc();
m
mINT getchar()
m{
m	return fgetc(stdin);
m}

nextern fputs(), _exit(), _cfp, _drd[], ungetc();
n
nINT fgetc(fp)
n	FILE *fp;
n{	int ch;
n	int f;		/* to cast a function call */
n
n	if (fp[FB_FLG] & FB_OUF || (fp[FB_FLG] & FB_OPF) == 0)
n	{	fputs("reading bad file", stderr);
n		_exit();
n	}
n	if (fp[FB_FLG] & FB_UNF)
n	{	fp[FB_FLG] &= ~FB_UNF;
n		return fp[FB_UNC] & 255;
n	}
n	if (fp[FB_FLG] & FB_EOF)
n		return EOF;	/* hard end of file */
n	_cfp = fp;		/* pass to byte driver */
n	f = _drd[fp[FB_DRV]];
n	switch (ch = (f)()) {
n	case CR:
n		if (fp[FB_DRV] == 0 &&
n		    (ch = (f)()) != LF)
n		{	ungetc(ch,fp);
n			return '\r';
n		}
n	case LF:
n		return '\n';
n	case EOF:		/* hard end of file */
n		fp[FB_FLG] |= FB_EOF;
n	case EOT:		/* ^D soft end of file */
n	case SUB:		/* ^Z soft end of file */
n		return EOF;
n	default:
n		return ch;
n	}
n}

oINT ungetc(ch,fp)
o	char ch;
o	FILE *fp;
o{
o	if (fp[FB_FLG] & (FB_OUF | FB_UNF | FB_EOF | FB_OUF) ||
o	    (fp[FB_FLG] & FB_OPF) == 0)
o		return EOF;
o	fp[FB_FLG] |= FB_UNF;
o	return fp[FB_UNC] = ch;
o}

pextern fputc();
p
pINT putchar(ch)
p	char ch;
p{
p	return fputc(ch, stdout);
p}

/*
 *	word i/o:
 *
 *	getw(fp)	return word from fp
 *	putw(w,fp)	write to fp, return word or EOF
 *
 *	always check feof/ferror to discover errors
 */

qextern fputs(), _exit(), _cfp, _drd[];
q
qINT getw(fp)
q	FILE *fp;
q{	char low, high;
q	int f;		/* to cast a function call */
q
q	if (fp[FB_FLG] & FB_OUF || (fp[FB_FLG] & FB_OPF) == 0)
q	{	fputs("reading bad file", stderr);
q		_exit();
q	}
q	if (fp[FB_FLG] & FB_EOF)
q		return EOF;	/* hard end of file */
q	_cfp = fp;		/* pass to _fgetchar() */
q	f = _drd[fp[FB_DRV]];
q	if (fp[FB_FLG] & FB_UNF)
q	{	fp[FB_FLG] &= ~FB_UNF;
q		low = fp[FB_UNC];
q	}
q	else
q		low = (f)();
q	if (fp[FB_FLG] & (FB_EOF | FB_ERM))
q		return EOF;
q	high = (f)();
q	if (fp[FB_FLG] & (FB_EOF | FB_ERM))
q		return EOF;
q	return (high << 8) | (low & 255);
q}

rextern fputs(), _exit(), _cfp, _dwr[];
r
rINT putw(w,fp)
r	int w;
r	FILE *fp;
r{	int f;		/* to cast a function call */
r
r	if ((fp[FB_FLG] & FB_OUF) == 0 || (fp[FB_FLG] & FB_OPF) == 0)
r	{	fputs("writing bad file", stderr);
r		_exit();
r	}
r	if (fp[FB_FLG] & FB_EOF)
r		return EOF;	/* hard end of file */
r	_cfp = fp;		/* pass to _fputchar */
r	f = _dwr[fp[FB_DRV]];
r	(f)(w & 255);		/* low */
r	if (fp[FB_FLG] & (FB_EOF | FB_ERM))
r		return EOF;
r	(f)(w >> 8);		/* high */
r	if (fp[FB_FLG] & (FB_EOF | FB_ERM))
r		return EOF;
r	return w;
r}

/*
 *	other i/o:
 *
 *	gets	string from stdin, '\n' becomes NUL
 *	fgets	string from fp, '\n' is kept
 *	puts	string to stdout, appends '\n'
 *
 *	return NULL on error, else string.
 *
 *	fread, fwrite
 *		to be implemented
 */

sextern fgetc();
s
sCHAR_P gets(s)
s	char *s;
s{	int ch;
s	char *str;
s
s	str = s;
s	while ((ch = fgetc(stdin)) != '\n')
s	{	if (ch == EOF)
s		{	str = NULL;
s			break;
s		}
s		*s++ = ch;
s	}
s	*s = NUL;
s	return str;
s}

textern fgetc();
t
tCHAR_P fgets(s, n, fp)
t	char *s;
t	int n;
t	FILE *fp;
t{	int ch;
t	char *str;
t
t	str = s;
t	while (--n > 0)
t		if ((ch = fgetc(fp)) == '\n')
t		{	*s++ = ch;
t			break;
t		}
t		else if (ch == EOF)
t		{	str = NULL;
t			break;
t		}
t		else
t			*s++ = ch;
t	*s = NUL;
t	return str;
t}

uextern fputc();
u
uCHAR_P puts(s)
u	char *s;
u{	char ch;
u	char *str;
u
u	str = s;
u	while (ch = *s++)
u		if (fputc(ch, stdout) == EOF)
u			return NULL;
u	if (fputc('\n', stdout) == EOF)
u		return NULL;
u	return str;
u}

/****
 ****	memory display routines
 ****/

/*
 *	putbit	show bits in groups of 1 byte
 *	puthex	show bytes in groups of 8 words
 */

Bextern fputc(), fprintf();
B
Bputbit(add, buf, bits, fp)
B	char *add;	/* first address to show */
B	char *buf;	/* -> first byte */
B	int bits;	/* # bits */
B	FILE *fp;	/* for output */
B{	char c;		/* current byte */
B	int i,j;
B
B	while (bits)
B	{	fprintf(fp, "%04x:", add);
B		for (i=0; bits && i<4; ++i)
B		{	fputc(' ',fp);
B			c = *buf++;
B			for (j=0; bits && j<8; ++j)
B			{	if (c & 128)
B					fputc('1',fp);
B				else
B					fputc('0',fp);
B				c <<= 1;
B				--bits;
B			}
B		}
B		fputc('\n',fp);
B	}
B}

Cextern fprintf(), fputc(), isprint(), isascii(), iscntrl();
C
Cputhex(add, buf, bytes, fp)
C	char *add;	/* first address to show */
C	char *buf;	/* -> first byte to show */
C	int bytes;	/* # bytes (minimum) */
C	FILE *fp;	/* for output */
C{	char c;		/* current byte */
C	int i;
C
C	do
C	{	fprintf(fp,"%04x: ", add);
C		for (i=0; i<16; i += 2)
C			fprintf(fp,"%02x%02x ",	buf[i] & 255, buf[i+1] & 255);
C		for (i=0; i<16; ++i)
C			if (isascii(c = *buf++) && isprint(c) && ! iscntrl(c))
C				fputc(c,fp);
C			else
C				fputc('.',fp);
C		fputc('\n',fp);
C		add += 16;
C	} while ((bytes -= 16) > 0);
C}
%%%%%%%%%% scc/rtl/c1.get %%%%%%%%%%
/*
 *	c?.get -- smallC runtime library for CP/M and MACRO-80
 *	ats 2/83, in part adapted from Jim Hendrix' code
 */

$#define NOCCARGC
##include def.h		/* TO BE FIXED */

/*
 *	module names
 */

##asm
a	NAME	('abs')
b	NAME	('atoi')	; needs is*
c				; _ctype external
d	NAME	('isprint')
e	NAME	('iscntrl')
f	NAME	('isalpha')
g	NAME	('isdigit')
h	NAME	('isxdigit')
i	NAME	('ispunct')
c				; end of _ctype needed
j	NAME	('toascii')
k	NAME	('index')
l
m	NAME	('strcat')
n
o
p	NAME	('strcpy')
q
r	NAME	('strlen')
s	NAME	('byte')
t	NAME	('rword')
u	NAME	('cshow')	; needs cavail printf fputs
v	NAME	('cavail')
##endasm

/****
 ****	UN*X compatible math functions
 ****/

/*
 *	abs	absolute value of integer
 */

aINT abs(i)
a	int i;
a{
a	if (i<0)
a		return -i;
a	return i;
a}

/*
 *	atoi	integer value in string
 *
 *		optional sign
 *			0??	base 8
 *			0x??	base 16
 *			other	base 10
 */

bextern isspace(), isdigit(), isxdigit(), isupper();
b
bINT atoi(string)
b	char *string;
b{	int mult;
b	int base;
b	int ch;
b	int atoi;
b
b	mult = 1;
b	base = 10;
b	atoi = 0;
b	while (isspace(ch = *string))
b		string++;
b	if ((ch = *string) == '-')
b	{	mult = -1;
b		ch = *++string;
b	}
b	else if (ch == '+')
b		ch = *++string;
b	if (ch == '0')
b	{	base = 8;
b		if ((ch = *++string) == 'x' || ch == 'X')
b		{	base = 16;
b			ch = *++string;
b		}
b	}
b	for( ; ch; ch = *++string)
b	{	if (isdigit(ch))
b			ch -= '0';
b		else if (isxdigit(ch))
b			if (isupper(ch))
b				ch -= 'A' - 10;
b			else
b				ch -= 'a' - 10;
b		if (ch < base)
b			atoi = atoi*base + ch;
b		else
b			break;
b	}
b	return mult*atoi;
b}

/****
 ****	UN*X compatible character functions
 ****/

/*
 *	character type functions:
 *
 *	isprint(c)	c is printing
 *	iscntrl(c)	c is control character
 *	isalpha(c)	c is alphabetic
 *	isdigit(c)	c is (decimal) digit
 *	isxdigit(c)	c is base 16 digit
 *	ispunct(c)	c is punctuation character
 */

	/* 128     64    32    16  8   4     2     1     */
	/* special upper lower num hex space punct cntrl */

c#define C_PRINT (128+64+32+16  +4    )	/* printing character */
c#define C_CNTRL (                   1)	/* control character */
c#define C_ALPHA (    64+32           )	/* alphabetic */
c#define C_UPPER (    64              )	/* upper case */
c#define C_LOWER (       32           )	/* lower case */
c#define C_DIGIT (          16        )	/* digit */
c#define C_XDIGI (          16+8      )	/* base 16 digit */
c#define C_ALNUM (    64+32+16        )	/* alpha or numeric */
c#define C_SPACE (               4    )	/* white space */
c#define C_PUNCT (                 2  )	/* punctuation */
c
cextern char _ctype[];

dINT isprint(c) char c;  { return _ctype[c] & C_PRINT; }
eINT iscntrl(c) char c;  { return _ctype[c] & C_CNTRL; }
fINT isalpha(c) char c;  { return _ctype[c] & C_ALPHA; }
gINT isdigit(c) char c;  { return _ctype[c] & C_DIGIT; }
hINT isxdigit(c) char c; { return _ctype[c] & C_XDIGI; }
iINT ispunct(c) char c;  { return _ctype[c] & C_PUNCT; }

/*
 *	character conversion functions:
 *
 *	toascii(i)	return i mapped into ASCII character set
 */

jCHAR toascii(i) int i;  { return i & 127; }

/****
 ****	UN*X compatible string functions
 ****/

/*
 *	index	NULL or -> first 'c' in 's'
 */

kCHAR_P index(s,c)
k	char *s;
k	char c;
k{
k	do
k		if (*s == c)
k			return s;
k	while (*s++);
k	return NULL;
k}

/* l reserved */

/*
 *	strcat	copy `v' to end of 'n' including \0
 */

mCHAR_P strcat(n,v)
m	char *n, *v;
m{	char *nach;
m
m	nach = n;
m	while (*n++)
m		;
m	for (--n; *n++ = *v++; )
m		;
m	return nach;
m}

/* no reserved */

/*
 *	strcpy	copy `v' to 'n' including \0
 */

pCHAR_P strcpy(n,v)
p	char *n, *v;
p{	char *nach;
p
p	nach = n;
p	while (*n++ = *v++)
p		;
p	return nach;
p}

/* q reserved */

/*
 *	strlen	length of `s' sans \0
 */

rINT strlen(s)
r	char *s;
r{	int len;
r
r	for (len = 0; *s++; )
r		len++;
r	return len;
r}

/****
 ****	routines to approximate C features
 ****/

/*
 *	byte(&c)	return byte
 *	rword(&i)	return byte-reversed word
 */

sCHAR byte(bp)
s	char *bp;
s{
s	return *bp & 255;
s}

tINT rword(wp)
t	char *wp;
t{
t	return (*wp << 8) | *(wp+1) & 255;
t}

/****
 ****	dynamic memory allocation
 ****/

/*
 *	cavail	return approximate KB still free
 *	cshow	display heap on stderr
 */

uextern fprintf(), cavail(), fputc();
uextern char _fberr[], _end[];
u
ucshow()
u{	int *p, *np, l, i;
u
u	p = _end+1 & ~1;
u	i = 0;
u	do
u	{	if (++i == 6)
u		{	fputc('\n', stderr);
u			i = 1;
u		}
u		np = *p & ~1;
u		fprintf(stderr, "%04x ", p);
u		if (l = np-1 - p)
u			if (*p & 1)
u				fprintf(stderr, "(%u) ", l << 1);
u			else
u				fprintf(stderr, "[%u] ", l << 1);
u		p = np;
u	} while (*np);
u	fprintf(stderr, "\nabout %d KB below stack\n", cavail());
u}

vextern char _end[];
vextern word();
v
vINT cavail()
v{	char *p;
v
v	for (p = _end+1 & ~1; word(p); p = word(p) & ~1)
v		;
v	return ((&p - p) >> 10 & (1 << 6)-1) - 1;
v}
%%%%%%%%%% scc/rtl/crtl.mac %%%%%%%%%%
;	crtl.mac -- smallC runtime environment module
;		for CP/M
;		for MACRO/80

;	ats 2/83
;	in part adapted from Jim Hendrix' code

;	global name conventions:
;	========================
;
;	?	starts an internal routine name
;	_	starts an internal C-callable name
;	other	starts a published C-callable name
;
;	This file is organized so that all references
;	to global symbols are forward.

;	smallC CP/M environment:
;	========================
;
;	Set up stack to run from top of memory downward,
;	and call smallC environment routine _shell().
;
;	Upon return, connect to BIOS warm start.
;
;	_exit	entry point to BIOS warm start,
;		i.e., no file management wrapup.
;
;	If the END module is linked last (and it must be):
;
;	_edata	follows the last static data area,
;		is preceded by the 6 character production date mmddyy
;
;	_eprog	follows the last code area
;		is preceded by the 6 character compiler logo
;
;	_end	follows the end of code and data 
;
;	The smallC compiler is expected to supply a reference
;	to the ?smallC routine to arrange for proper library search.

	ENTRY	?smallC
	ENTRY	_exit
	EXTRN	_shell		; outermost C runtime routine
	EXTRN	?30217		; version reference

V.BIOS	EQU	0		; entry vector for BIOS warm start
V.BDOS	EQU	5		; entry vector for BDOS

	CSEG

?smallC:
	LHLD	V.BDOS+1	; stack starts at top of memory
	SPHL
	CALL	_shell		; call C environment routine
_exit:
	JMP	V.BIOS		; return to system

;	BDOS calls:
;	===========
;
;	BDOS	C call		return	entry	description
;	code			value	value
;	-------------------------------------------------------------
;	0	abort()				system reset
;	1	i = _getchar()	char		console read
;	2	_putchar(c)		char	console write
;	3	i = _rgetchar()	char		reader read
;	4	_pputchar(c)		char	punch write
;	5	_lputchar(c)		char	list write
;	6	i = _dirio(c)	char	0xFF	direct input
;				0=busy	char	direct output
;	7	i = _giob()	byte		get i/o byte
;	8	_siob(c)		byte	set i/o byte
;	9	_puts(&c)		address	print string to next $
;	10	_gets(&buf)		address	read console buffer
;	11	i = _cstat()	0=busy		get console status
;	12	i = _vers()	word		get version number (in hex)
;	13	_reset()			reset disk
;	14	i = _mount(c)	0=ok	drive#	select disk
;	15	i = _open(&f)	dir [1]	address	open file
;	16	i = _close(&f)	dir	address	close file
;	17	i = _glob(&f)	dir [2]	address	search for first file name
;	18	i = _nglob()	dir [2]		search for next file name
;	19	i = _delete(&f)	dir	address	delete file
;	20	i = _read(&f)	err [3]	address	read next record
;	21	i = _write(&f)	err [3]	address	write next record
;	22	i = _create(&f) dir [1]	address	create file
;	23	i = _renam(&fn)	dir	address	rename file
;	24	i = _login()	vector		get login vector
;	25	i = _drive()	drive#		get disk number
;	26	_setbuf(&c)		address set DMA address (of 128 bytes)
;	27	i = _bitmap()	bitmap		get allocate vector
;	28	_protect()			write protect
;	29	i = romap()	vector		get R/O vector
;	30	i = _chmod(&f)	dir	address	set file attributes
;	31	i = _diskmap()	diskmap		get disk header address
;	32	i = _uid(c)	user#	0xFF	get user number
;				0=ok	user#	set user number
;	33	i = _rread(&f)	err [4]	address	read random
;	34	i = _rwrite(&f)	err [4]	address	write random
;	35	_stat(&f)	[5]	address	compute file size
;	36	_record(&f)	[5]	address	set random record
;	37	i = _umount(i)	0=ok	vector	reset selected drives
;	40	i = _rzwrite(&f) err[4]	address	write random zero fill
;	-------------------------------------------------------------
;
;	bitmap	from left to right, set bits indicate allocated
;		reservation blocks
;
;	buf	console buffer has the following format:
;
;		byte	(in)	maximum length available for text
;		byte	(out)	length actually filled
;		byte...	(out)	text read, without trailing newline
;
;	c	character (byte) parameter
;
;	dir	position in directory sector, 0..3
;		not found: 0xFF
;
;	diskmap	CP/M disk description
;
;	drive#	disk drive number, 0==A, 1==B, ...
;
;	err	error code:
;
;		0	ok
;		1	reading unwritten data (end of file)
;
;	f	file control block
;		can usually contain wildcard file name
;
;	fn	file control block,
;		new name begins at offset 17
;
;	i	integer (word) result, possibly byte sign-extended
;
;	vector	bit vector indicating disk drives,
;		least significant bit is drive 0
;
;	[1]	modifies argument file control block
;
;	[2]	requires _setbuf(),
;		result indicates directory entry in this buffer
;
;	[3]	requires _setbuf(),
;		i/o happens from the DMA area set up by _setbuf()
;
;	[4]	[3], additionally, the random record position
;		must have been set in the argument file control block
;
;	[5]	result is returned to the random record position
;		in the file control block

;	macro to dispatch BDOS calls:
;	-----------------------------
;
;	t	action
;	-------------------------------------------------------------
;	0	jump to BDOS
;	1	call BDOS, return HL = (int) A
;	2	DE = parm, call BDOS
;	3	DE = parm, call BDOS, return HL = (int) A

BDOS	MACRO	func,t,code
&func::			;; entry point from C
	MVI	C,&code	;; set BDOS function code
	JMP	?BD&t	;; goto executor
	ENDM

	BDOS	abort,0,0
	BDOS	_getch,1,1
	BDOS	_putch,2,2
	BDOS	_rgetc,1,3
	BDOS	_pputc,2,4
	BDOS	_lputc,2,5
	BDOS	_dirio,3,6
	BDOS	_giob,1,7
	BDOS	_siob,2,8
	BDOS	_puts,2,9
	BDOS	_gets,2,10
	BDOS	_cstat,1,11
	BDOS	_vers,0,12
	BDOS	_reset,0,13
	BDOS	_mount,3,14
	BDOS	_open,3,15
	BDOS	_close,3,16
	BDOS	_glob,3,17
	BDOS	_nglob,1,18
	BDOS	_delete,3,19
	BDOS	_read,3,20
	BDOS	_write,3,21
	BDOS	_create,3,22
	BDOS	_rename,3,23
	BDOS	_login,0,24
	BDOS	_drive,1,25
	BDOS	_setbuf,2,26
	BDOS	_bitmap,0,27
	BDOS	_protect,0,28
	BDOS	_romap,0,29
	BDOS	_chmod,3,30
	BDOS	_diskmap,0,31
	BDOS	_uid,3,32
	BDOS	_rread,3,33
	BDOS	_rwrite,3,34
	BDOS	_stat,2,35
	BDOS	_record,2,36
	BDOS	_umount,3,37
	BDOS	_rzwrite,3,40

;	BDOS interface:
;	---------------

;	type 0:
;
;		jump to BDOS
;		i.e., either no return, or return HL

?BD0	EQU	V.BDOS

;	type 2:
;
;	C	in	BDOS function
;	DE	local	int parameter
;	HL	local

?BD2:	POP	H	; return
	POP	D	; int parameter
	PUSH	D
	PUSH	H
	JMP	V.BDOS	; return through BDOS

;	type 3:
;
;	A	local	from BDOS
;	C	in	BDOS function
;	DE	local	int parameter
;	HL	out	= (int) A

?BD3:	POP	H	; return
	POP	D	; int parameter
	PUSH	D
	PUSH	H
;	JMP	?BD1	; BDOS, return HL = (int) A

;	type 1:
;
;	A	local	from BDOS
;	C	in	BDOS function
;	HL	out	= (int) A

?BD1:	CALL	V.BDOS
	JMP	?SXT	; HL = (int) A

;	BIOS calls:
;	===========
;
;	BIOS	C call		return	entry	description
;	offset			value	value
;	-------------------------------------------------------------
;	0					complete cold start
;	3	_wboot()			warm start
;	6	i = _const()	ff=ready	console status
;	9	c = _conin()	char		console input (no echo)
;	12	_conout(c)		char	console output
;	15	_lstout(c)		char	printer output
;	18	_punout(c)		char	punch output
;	21	c = _rdrin()	char		reader input
;	24	_home()				set track zero
;	27	i = _seldsk(c,b) 0=no	drive#,	select disk
;				diskmap	first
;	30	_settrk(i)		track	select track
;	33	_setsec(i)		sector	set sector
;	36	_setdma(&c)		address	set DMA address
;	39	i = _sread()	0=ok		read CP/M sector
;	42	i = _swrite(c)	0=ok	all	write CP/M sector
;	45	i = _lstst()	ff=ready	printer status
;	48	i = _sectran(i,&c) phys	log,	translate sector
;					ttable
;	-------------------------------------------------------------
;
;	all	0: write to previously allocated block
;		1: write to directory (always to disk)
;		2: write to first sector of unallocated data block
;
;	b	bit parameter
;
;	c	character (byte) parameter
;
;	diskmap	CP/M disk description (0==

schrein (03/14/83)

#R:uiucdcs:12600001:uiucdcs:12600002:000:51453
uiucdcs!schrein    Mar 12 09:22:00 1983

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

%%%%%%%%%% scc/rtl/crtl.mac %%%%%%%%%%
;	crtl.mac -- smallC runtime environment module
;		for CP/M
;		for MACRO/80

;	ats 2/83
;	in part adapted from Jim Hendrix' code

;	global name conventions:
;	========================
;
;	?	starts an internal routine name
;	_	starts an internal C-callable name
;	other	starts a published C-callable name
;
;	This file is organized so that all references
;	to global symbols are forward.

;	smallC CP/M environment:
;	========================
;
;	Set up stack to run from top of memory downward,
;	and call smallC environment routine _shell().
;
;	Upon return, connect to BIOS warm start.
;
;	_exit	entry point to BIOS warm start,
;		i.e., no file management wrapup.
;
;	If the END module is linked last (and it must be):
;
;	_edata	follows the last static data area,
;		is preceded by the 6 character production date mmddyy
;
;	_eprog	follows the last code area
;		is preceded by the 6 character compiler logo
;
;	_end	follows the end of code and data 
;
;	The smallC compiler is expected to supply a reference
;	to the ?smallC routine to arrange for proper library search.

	ENTRY	?smallC
	ENTRY	_exit
	EXTRN	_shell		; outermost C runtime routine
	EXTRN	?30217		; version reference

V.BIOS	EQU	0		; entry vector for BIOS warm start
V.BDOS	EQU	5		; entry vector for BDOS

	CSEG

?smallC:
	LHLD	V.BDOS+1	; stack starts at top of memory
	SPHL
	CALL	_shell		; call C environment routine
_exit:
	JMP	V.BIOS		; return to system

;	BDOS calls:
;	===========
;
;	BDOS	C call		return	entry	description
;	code			value	value
;	-------------------------------------------------------------
;	0	abort()				system reset
;	1	i = _getchar()	char		console read
;	2	_putchar(c)		char	console write
;	3	i = _rgetchar()	char		reader read
;	4	_pputchar(c)		char	punch write
;	5	_lputchar(c)		char	list write
;	6	i = _dirio(c)	char	0xFF	direct input
;				0=busy	char	direct output
;	7	i = _giob()	byte		get i/o byte
;	8	_siob(c)		byte	set i/o byte
;	9	_puts(&c)		address	print string to next $
;	10	_gets(&buf)		address	read console buffer
;	11	i = _cstat()	0=busy		get console status
;	12	i = _vers()	word		get version number (in hex)
;	13	_reset()			reset disk
;	14	i = _mount(c)	0=ok	drive#	select disk
;	15	i = _open(&f)	dir [1]	address	open file
;	16	i = _close(&f)	dir	address	close file
;	17	i = _glob(&f)	dir [2]	address	search for first file name
;	18	i = _nglob()	dir [2]		search for next file name
;	19	i = _delete(&f)	dir	address	delete file
;	20	i = _read(&f)	err [3]	address	read next record
;	21	i = _write(&f)	err [3]	address	write next record
;	22	i = _create(&f) dir [1]	address	create file
;	23	i = _renam(&fn)	dir	address	rename file
;	24	i = _login()	vector		get login vector
;	25	i = _drive()	drive#		get disk number
;	26	_setbuf(&c)		address set DMA address (of 128 bytes)
;	27	i = _bitmap()	bitmap		get allocate vector
;	28	_protect()			write protect
;	29	i = romap()	vector		get R/O vector
;	30	i = _chmod(&f)	dir	address	set file attributes
;	31	i = _diskmap()	diskmap		get disk header address
;	32	i = _uid(c)	user#	0xFF	get user number
;				0=ok	user#	set user number
;	33	i = _rread(&f)	err [4]	address	read random
;	34	i = _rwrite(&f)	err [4]	address	write random
;	35	_stat(&f)	[5]	address	compute file size
;	36	_record(&f)	[5]	address	set random record
;	37	i = _umount(i)	0=ok	vector	reset selected drives
;	40	i = _rzwrite(&f) err[4]	address	write random zero fill
;	-------------------------------------------------------------
;
;	bitmap	from left to right, set bits indicate allocated
;		reservation blocks
;
;	buf	console buffer has the following format:
;
;		byte	(in)	maximum length available for text
;		byte	(out)	length actually filled
;		byte...	(out)	text read, without trailing newline
;
;	c	character (byte) parameter
;
;	dir	position in directory sector, 0..3
;		not found: 0xFF
;
;	diskmap	CP/M disk description
;
;	drive#	disk drive number, 0==A, 1==B, ...
;
;	err	error code:
;
;		0	ok
;		1	reading unwritten data (end of file)
;
;	f	file control block
;		can usually contain wildcard file name
;
;	fn	file control block,
;		new name begins at offset 17
;
;	i	integer (word) result, possibly byte sign-extended
;
;	vector	bit vector indicating disk drives,
;		least significant bit is drive 0
;
;	[1]	modifies argument file control block
;
;	[2]	requires _setbuf(),
;		result indicates directory entry in this buffer
;
;	[3]	requires _setbuf(),
;		i/o happens from the DMA area set up by _setbuf()
;
;	[4]	[3], additionally, the random record position
;		must have been set in the argument file control block
;
;	[5]	result is returned to the random record position
;		in the file control block

;	macro to dispatch BDOS calls:
;	-----------------------------
;
;	t	action
;	-------------------------------------------------------------
;	0	jump to BDOS
;	1	call BDOS, return HL = (int) A
;	2	DE = parm, call BDOS
;	3	DE = parm, call BDOS, return HL = (int) A

BDOS	MACRO	func,t,code
&func::			;; entry point from C
	MVI	C,&code	;; set BDOS function code
	JMP	?BD&t	;; goto executor
	ENDM

	BDOS	abort,0,0
	BDOS	_getch,1,1
	BDOS	_putch,2,2
	BDOS	_rgetc,1,3
	BDOS	_pputc,2,4
	BDOS	_lputc,2,5
	BDOS	_dirio,3,6
	BDOS	_giob,1,7
	BDOS	_siob,2,8
	BDOS	_puts,2,9
	BDOS	_gets,2,10
	BDOS	_cstat,1,11
	BDOS	_vers,0,12
	BDOS	_reset,0,13
	BDOS	_mount,3,14
	BDOS	_open,3,15
	BDOS	_close,3,16
	BDOS	_glob,3,17
	BDOS	_nglob,1,18
	BDOS	_delete,3,19
	BDOS	_read,3,20
	BDOS	_write,3,21
	BDOS	_create,3,22
	BDOS	_rename,3,23
	BDOS	_login,0,24
	BDOS	_drive,1,25
	BDOS	_setbuf,2,26
	BDOS	_bitmap,0,27
	BDOS	_protect,0,28
	BDOS	_romap,0,29
	BDOS	_chmod,3,30
	BDOS	_diskmap,0,31
	BDOS	_uid,3,32
	BDOS	_rread,3,33
	BDOS	_rwrite,3,34
	BDOS	_stat,2,35
	BDOS	_record,2,36
	BDOS	_umount,3,37
	BDOS	_rzwrite,3,40

;	BDOS interface:
;	---------------

;	type 0:
;
;		jump to BDOS
;		i.e., either no return, or return HL

?BD0	EQU	V.BDOS

;	type 2:
;
;	C	in	BDOS function
;	DE	local	int parameter
;	HL	local

?BD2:	POP	H	; return
	POP	D	; int parameter
	PUSH	D
	PUSH	H
	JMP	V.BDOS	; return through BDOS

;	type 3:
;
;	A	local	from BDOS
;	C	in	BDOS function
;	DE	local	int parameter
;	HL	out	= (int) A

?BD3:	POP	H	; return
	POP	D	; int parameter
	PUSH	D
	PUSH	H
;	JMP	?BD1	; BDOS, return HL = (int) A

;	type 1:
;
;	A	local	from BDOS
;	C	in	BDOS function
;	HL	out	= (int) A

?BD1:	CALL	V.BDOS
	JMP	?SXT	; HL = (int) A

;	BIOS calls:
;	===========
;
;	BIOS	C call		return	entry	description
;	offset			value	value
;	-------------------------------------------------------------
;	0					complete cold start
;	3	_wboot()			warm start
;	6	i = _const()	ff=ready	console status
;	9	c = _conin()	char		console input (no echo)
;	12	_conout(c)		char	console output
;	15	_lstout(c)		char	printer output
;	18	_punout(c)		char	punch output
;	21	c = _rdrin()	char		reader input
;	24	_home()				set track zero
;	27	i = _seldsk(c,b) 0=no	drive#,	select disk
;				diskmap	first
;	30	_settrk(i)		track	select track
;	33	_setsec(i)		sector	set sector
;	36	_setdma(&c)		address	set DMA address
;	39	i = _sread()	0=ok		read CP/M sector
;	42	i = _swrite(c)	0=ok	all	write CP/M sector
;	45	i = _lstst()	ff=ready	printer status
;	48	i = _sectran(i,&c) phys	log,	translate sector
;					ttable
;	-------------------------------------------------------------
;
;	all	0: write to previously allocated block
;		1: write to directory (always to disk)
;		2: write to first sector of unallocated data block
;
;	b	bit parameter
;
;	c	character (byte) parameter
;
;	diskmap	CP/M disk description (0==no such drive)
;
;	drive#	disk drive number, 0==A, 1==B, ...
;
;	first	bit 0: 0==first call for this disk
;
;	i	integer (word) result, possibly byte sign-extended
;
;	ttable	translation table address (0==none)

;	macro to dispatch BIOS calls:
;	-----------------------------
;
;	t	action
;	-------------------------------------------------------------
;	0	jump to BIOS
;	1	call BIOS, return HL = (int) A
;	2	BC = parm, call BIOS
;	3	BC = parm, DE = parm, call BIOS
;	4	BC = parm, call BIOS, return HL = (int) A

BIOS	MACRO	func,t,offset
&func::				;; entry point from C
	MVI	A,&offset	;; set BIOS offset
	JMP	?BI&t		;; goto executor
	ENDM

	BIOS	_wboot,0,3
	BIOS	_const,1,6
	BIOS	_conin,1,9
	BIOS	_conou,2,12
	BIOS	_lstou,2,15
	BIOS	_punou,2,18
	BIOS	_rdrin,1,21
	BIOS	_home,0,24
	BIOS	_selds,3,27
	BIOS	_settr,2,30
	BIOS	_setse,2,33
	BIOS	_setdm,2,36
	BIOS	_sread,1,39
	BIOS	_swrit,4,42
	BIOS	_lstst,1,45
	BIOS	_sectr,3,48

;	BIOS interface:
;	---------------

;	type 1:
;
;	A	in	offset in BIOS page
;		local	BIOS return
;	HL	out	= (int) A

?BI1:	LHLD	V.BIOS+1	; H = BIOS page number
	MOV	L,A		; L = BIOS offset
	PUSH H
	LXI H,$+5		; return address
	XTHL			; to stack
	PCHL
	JMP	?SXT		; HL = (int) A

;	type 2:
;
;	A	in	offset in BIOS page
;	BC	local	int parameter
;	HL	local

?BI2:	POP	H		; return
	POP	B		; parameter
	PUSH	B
	PUSH	H
	JMP	?BI0		; go and return through BIOS

;	type 3:
;
;	A	in	offset in BIOS page
;	BC	local	int parameter (first)
;	DE	local	int parameter (second)
;	HL	local

?BI3:	POP	H		; return
	POP	D		; second parameter
	POP	B		; first parameter
	PUSH	B
	PUSH	D
	PUSH	H
;	JMP	?BI0		; go and return through BIOS

;	type 0:
;
;	A	in	offset in BIOS page
;	HL	local

?BI0:	LHLD	V.BIOS+1	; H = BIOS page number
	MOV	L,A		; L = BIOS offset
	PCHL

;	type 4:
;
;	A	in	offset in BIOS page
;		local	BIOS return
;	BC	local	int parameter
;	HL	out	= (int) A

?BI4:	POP	H		; return
	POP	B		; parameter
	PUSH	B
	PUSH	H
	LHLD	V.BIOS+1	; H = BIOS page number
	MOV	L,A		; L = BIOS offset
	PUSH H
	LXI H,$+5		; return address
	XTHL			; to stack
	PCHL
	JMP	?SXT		; HL = (int) A

;	Jim Hendrix' arithmetic and logic library:
;	==========================================

;	routine headers:
;	----------------

	ENTRY	?OR	; hl |= de
	ENTRY	?XOR	; hl ^= de
	ENTRY	?AND	; hl &= de
	ENTRY	?EQ	; hl = hl == de
	ENTRY	?NE	; hl = hl != de
	ENTRY	?GT	; hl = (int) de > hl
	ENTRY	?LE	; hl = (int) de <= hl
	ENTRY	?GE	; hl = (int) de >= hl
	ENTRY	?LT	; hl = (int) de < hl
	ENTRY	?UGE	; hl = (unsigned) de >= hl
	ENTRY	?ULT	; hl = (unsigned) de < hl
	ENTRY	?UGT	; hl = (unsigned) de > hl
	ENTRY	?ULE	; hl = (unsigned) de <= hl
	ENTRY	?ASR	; hl = de >> hl
	ENTRY	?ASL	; hl = de << hl
	ENTRY	?SUB	; hl = de - hl
	ENTRY	?NEG	; hl = - hl
	ENTRY	?COM	; hl = ~ hl
	ENTRY	?MULT	; hl *= de
	ENTRY	?DIV	; hl = de / hl, de %= hl
	ENTRY	?LNEG	; hl = ! hl
	ENTRY	?DECC	; (byte) *(hl+top()) --
	ENTRY	?INCC	; (byte) *(hl+top()) ++
	ENTRY	?DECI	; (word) *(hl+top()) --
	ENTRY	?INCI	; (word) *(hl+top()) ++
	ENTRY	?DDGC	; hl = (int) (byte) *(hl+de)
	ENTRY	?DSGC	; hl = (int) (byte) *(hl+top())
	ENTRY	?GCHAR	; hl = (int) (byte) *hl
	ENTRY	?SXT	; hl = (int) a
	ENTRY	_narg	; hl = (int) a /* number of arguments */
	ENTRY	?DDGI	; hl = (word) *(hl+de)
	ENTRY	?DSGI	; hl = (word) *(hl+top())
	ENTRY	?GINT	; hl = (word) *hl
	ENTRY	?DDPPC	; (byte) *(pop()) = de+hl
	ENTRY	?PDPC	; (byte) *(pop()) = hl
	ENTRY	?DDPPI	; (word) *(pop()) = de+hl
	ENTRY	?PDPI	; (word) *(pop()) = hl
	ENTRY	?PINT	; (word) *de = hl
	ENTRY	?SWITCH	; switch selector execution

;	code region:
;	------------
;
;	Blank lines separate potential modules.

?OR:
	MOV	A,L
	ORA	E
	MOV	L,A
	MOV	A,H
	ORA	D
	MOV	H,A
	RET

?XOR:
	MOV	A,L
	XRA	E
	MOV	L,A
	MOV	A,H
	XRA	D
	MOV	H,A
	RET

?AND:
	MOV	A,L
	ANA	E
	MOV	L,A
	MOV	A,H
	ANA	D
	MOV	H,A
	RET

?EQ:
	CALL	CMP0
	RZ
	DCX	H
	RET

?NE:
	CALL	CMP0
	RNZ
	DCX	H
	RET

?GT:
	XCHG
	CALL	CMP0
	RC
	DCX	H
	RET

?LE:
	CALL	CMP0
	RZ
	RC
	DCX	H
	RET

?GE:
	CALL	CMP0
	RNC
	DCX	H
	RET

?LT:
	CALL	CMP0
	RC
	DCX	H
	RET

CMP0:
	MOV	A,H		; INVERT SIGN OF HL
	XRI	80H
	MOV	H,A
	MOV	A,D		; INVERT SIGN OF DE
	XRI	80H
	CMP	H		; COMPARE MSBS
	JNZ	CMP1		; DONE IF NEQ
	MOV	A,E		; COMPARE LSBS
	CMP	L
CMP1:
	LXI	H,1		; PRESET TRUE COND
	RET

?UGE:
	CALL	UCMP0
	RNC
	DCX	H
	RET

?ULT:
	CALL	UCMP0
	RC
	DCX	H
	RET

?UGT:
	XCHG
	CALL	UCMP0
	RC
	DCX	H
	RET

?ULE:
	CALL	UCMP0
	RZ
	RC
	DCX	H
	RET

UCMP0:
	MOV	A,D
	CMP	H
	JNZ	UCMP1
	MOV	A,E
	CMP	L
UCMP1:
	LXI	H,1
	RET

?ASR:
	XCHG
	DCR	E
	RM
	MOV	A,H
	RAL
	MOV	A,H
	RAR
	MOV	H,A
	MOV	A,L
	RAR
	MOV	L,A
	JMP	?ASR+1

?ASL:
	XCHG
	DCR	E
	RM
	DAD	H
	JMP	?ASL+1

?SUB:
	MOV	A,E
	SUB	L
	MOV	L,A
	MOV	A,D
	SBB	H
	MOV	H,A
	RET

?NEG:
	CALL	?COM
	INX	H
	RET

?COM:
	MOV	A,H
	CMA
	MOV	H,A
	MOV	A,L
	CMA
	MOV	L,A
	RET

?MULT:
	MOV	B,H
	MOV	C,L
	LXI	H,0
MULT1:
	MOV	A,C
	RRC
	JNC	MULT2
	DAD	D
MULT2:
	XRA	A
	MOV	A,B
	RAR
	MOV	B,A
	MOV	A,C
	RAR
	MOV	C,A
	ORA	B
	RZ
	XRA	A
	MOV	A,E
	RAL
	MOV	E,A
	MOV	A,D
	RAL
	MOV	D,A
	ORA	E
	RZ
	JMP	MULT1

?DIV:
	MOV	B,H
	MOV	C,L
	MOV	A,D
	XRA	B
	PUSH	PSW
	MOV	A,D
	ORA	A
	CM	DENEG
	MOV	A,B
	ORA	A
	CM	BCNEG
	MVI	A,16
	PUSH	PSW
	XCHG
	LXI	D,0
DIV1:
	DAD	H
	CALL	RDEL
	JZ	DIV2
	CALL	CMPBCDE
	JM	DIV2
	MOV	A,L
	ORI	1
	MOV	L,A
	MOV	A,E
	SUB	C
	MOV	E,A
	MOV	A,D
	SBB	B
	MOV	D,A
DIV2:
	POP	PSW
	DCR	A
	JZ	DIV3
	PUSH	PSW
	JMP	DIV1
DIV3:
	POP	PSW
	RP
	CALL	DENEG
	XCHG
	CALL	DENEG
	XCHG
	RET
DENEG:			;NEGATE THE INTEGER IN DE
	MOV	A,D
	CMA
	MOV	D,A
	MOV	A,E
	CMA
	MOV	E,A
	INX	D
	RET
BCNEG:			;NEGATE THE INTEGER IN BC
	MOV	A,B
	CMA
	MOV	B,A
	MOV	A,C
	CMA
	MOV	C,A
	INX	B
	RET
RDEL:			;ROTATE DE LEFT ONE BIT
	MOV	A,E
	RAL
	MOV	E,A
	MOV	A,D
	RAL
	MOV	D,A
	ORA	E
	RET
CMPBCDE:		;COMPARE BC TO DE
	MOV	A,E
	SUB	C
	MOV	A,D
	SBB	B
	RET

?LNEG:
	MOV	A,H
	ORA	L
	JNZ	$+6
	MVI	L,1
	RET
	LXI	H,0
	RET

?DECC:
	INX	H
	INX	H
	DAD	SP
	MOV	D,H
	MOV	E,L
	CALL	?GCHAR
	DCX	H
	MOV	A,L
	STAX	D
	RET

?INCC:
	INX	H
	INX	H
	DAD	SP
	MOV	D,H
	MOV	E,L
	CALL	?GCHAR
	INX	H
	MOV	A,L
	STAX	D
	RET

?DECI:
	INX	H
	INX	H
	DAD	SP
	MOV	D,H
	MOV	E,L
	CALL	?GINT
	DCX	H
	JMP	?PINT

?INCI:
	INX	H
	INX	H
	DAD	SP
	MOV	D,H
	MOV	E,L
	CALL	?GINT
	INX	H
	JMP	?PINT

?DDGC:
	DAD	D
	JMP	?GCHAR
?DSGC:
	INX	H
	INX	H
	DAD	SP
?GCHAR:
	MOV	A,M
_narg:
?SXT:
	MOV	L,A
	RLC
	SBB	A
	MOV	H,A
	RET

?DDGI:
	DAD	D
	JMP	?GINT
?DSGI:
	INX	H
	INX	H
	DAD	SP
?GINT:
	MOV	A,M
	INX	H
	MOV	H,M
	MOV	L,A
	RET

?DDPPC:
	DAD	D
?PDPC:
	POP	B		; RET ADDR
	POP	D
	PUSH	B
;PCHAR:
	MOV	A,L
	STAX	D
	RET

?DDPPI:
	DAD	D
?PDPI:
	POP	B		; RET ADDR
	POP	D
	PUSH	B
?PINT:
	MOV	A,L
	STAX	D
	INX	D
	MOV	A,H
	STAX	D
	RET

; EXECUTE "SWITCH" STATEMENT
;
;  HL  =  SWITCH VALUE
; (SP) -> SWITCH TABLE
;         DW ADDR1, VALUE1
;         DW ADDR2, VALUE2
;         ...
;         DW 0
;        [JMP default]
;         continuation
;

?SWITCH:
	XCHG			; DE =  SWITCH VALUE
	POP	H		; HL -> SWITCH TABLE
SWLOOP:
	MOV	C,M
	INX	H
	MOV	B,M		; BC -> CASE ADDR, ELSE 0
	INX	H
	MOV	A,B
	ORA	C
	JZ	SWEND		; DEFAULT OR CONTINUATION CODE
	MOV	A,M
	INX	H
	CMP	E
	MOV	A,M
	INX	H
	JNZ	SWLOOP
	CMP	D
	JNZ	SWLOOP
	MOV	H,B		; CASE MATCHED
	MOV	L,C
SWEND:
	PCHL

	END	?smallC
%%%%%%%%%% scc/rtl/csh.c %%%%%%%%%%
/*
 *	csh.c -- smallC runtime environment for CP/M and MACRO-80
 *	ats 2/83, in part adapted from Jim Hendrix' code
 */

#define	NOCCARGC
#include def.h			/* TO BE FIXED */

/*
 *	external references
 */

extern	_exit();		/* termination point in ?smallC */
extern	main();			/* user's main program */
extern char _end[];		/* begin of heap */
extern	_dnm[], _dop[],		/* CP/M driver table */
	_drd[], _dwr[],
	_dbr[], _dbw[],
	_dsk[], _dcl[];
extern	_drive();	/* BDOS	/* current drive number */

/****
 ****	global data regions
 ****/

/*
 *	character classification table
 */

	/* 128	   64	 32    16  8   4     2	   1	 */
	/* special upper lower num hex space punct cntrl */

#define C_PRINT (128+64+32+16  +4    )	/* printing character */
#define C_CNTRL (		    1)	/* control character */
#define C_ALPHA (    64+32	     )	/* alphabetic */
#define C_UPPER (    64		     )	/* upper case */
#define C_LOWER (	32	     )	/* lower case */
#define C_DIGIT (	   16	     )	/* digit */
#define C_XDIGI (	   16+8	     )	/* base 16 digit */
#define C_ALNUM (    64+32+16	     )	/* alpha or numeric */
#define C_SPACE (		4    )	/* white space */
#define C_PUNCT (		  2  )	/* punctuation */

char _ctype[128] = {
  1,  1,  1,  1,  1,  1,  1,  1,	/* nul soh stx etx eot enq ack bel */
  1,  5,  5,  1,  1,  5,  1,  1,	/* es  ht  lf  vt  ff  cr  so  si  */
  1,  1,  1,  1,  1,  1,  1,  1,	/* dle ^q  ^r  ^s  ^t  nak syn etb */
  1,  1,  1,  1,  1,  1,  1,  1,	/* can em  sub esc fs  gs  rs  us  */
  4,130,130,128,128,128,128,130,	/* sp  !   "   #   $   %   &   '   */
130,130,128,128,130,130,130,128,	/* (   )   *   +   ,   -   .   /   */
 16, 16, 16, 16, 16, 16, 16, 16,	/* 0   1   2   3   4   5   6   7   */
 16, 16,130,130,128,128,128,130,	/* 8   9   :   ;   <   =   >   ?   */
128, 72, 72, 72, 72, 72, 72, 64,	/* \@  A   B   C   D   E   F   G   */
 64, 64, 64, 64, 64, 64, 64, 64,	/* H   I   J   K   L   M   N   O   */
 64, 64, 64, 64, 64, 64, 64, 64,	/* P   Q   R   S   T   U   V   W   */
 64, 64, 64,128,128,128,128,128,	/* X   Y   Z   [   \   ]   ^   _   */
130, 40, 40, 40, 40, 40, 40, 32,	/* `   a   b   c   d   e   f   g   */
 32, 32, 32, 32, 32, 32, 32, 32,	/* h   i   j   k   l   m   n   o   */
 32, 32, 32, 32, 32, 32, 32, 32,	/* p   q   r   s   t   u   v   w   */
 32, 32, 32,128,128,128,128,  1};	/* x   y   z   {   |   }   ~   del */

/*
 *	file blocks:
 *
 *	These are the center of file activity.
 *	'stdin', 'stdout', and 'stderr' are dedicated.
 */

char _fbin[FB_];		/* standard input (first!!) */
char _fbout[FB_];		/* standard output */
char _fberr[FB_];		/* diagnostic output */
STATIC FILE *_fblocks;		/* -> chain of open file blocks */
STATIC FILE *_cfp;		/* i/o transfer: -> current file block */

/****
 ****	smallC MACRO-80 CP/M runtime environment
 ****/

/*
 *	_shell	called from the ?smallC code
 *		sets up environment and calls main()
 *
 *	exit	close all files and terminate program execution.
 *
 *	BUG: more than 19 arguments cause great trouble...
 *		fewer waste space.
 */

_shell()
{	char *cp, *fnp, ch;
	int argc, argv[20];
	int *wp;		/* for casting */

	wp = _end+1 & ~1;	/* even */
	*wp = wp+1;		/* blind heap element */
	*++wp = NULL;		/* terminal heap element */

	_fblocks = NULL;	/* no open file block */
	_fbin[FB_FLG] = 0;	/* stdio closed */
	_fbout[FB_FLG] = 0;
	_fberr[FB_FLG] = 0;
	freopen("con:", "r", stdin);
	freopen("con:", "w", stdout);
	freopen("con:", "w", stderr);

	argv[0] = "*";		/* argument vector passed at 0x81 */
	for (cp = 129, argc=1; ch = *cp++; )
		switch(ch) {
		case '\'':
			cp = mkarg(argv[argc++] = cp, '\'');
			continue;
		case '\"':
			cp = mkarg(argv[argc++] = cp, '\"');
			continue;
		case '>':
			if (*cp == '>')
			{	ch = '+';	/* append */
				cp++;
			}
		case '<':
			while (isspace(*cp))
				cp++;
			if (! *cp)
			{	fputs("bad redirect", stderr);
				_exit();
			}
			cp = mkarg(fnp = cp, 0);
			switch (ch) {
			case '<':
				if (freopen(fnp, "r", stdin) == stdin)
					continue;
				break;
			case '>':
				if (freopen(fnp, "w", stdout) == stdout)
					continue;
				break;
			case '+':
				if (freopen(fnp, "a", stdout) == stdout)
					continue;
			}
			fputs("cannot access ", stderr);
			fputs(fnp, stderr);
			_exit();
		default:
			if (! isspace(ch))
				cp = mkarg(argv[argc++] = cp-1, 0);
			continue;
		}
	argv[argc] = NULL;
	main(argc,argv);
	exit();
}

exit()
{
	while (_fblocks)
		fclose(_fblocks);
	fclose(stdin);
	fclose(stdout);
	fclose(stderr);
	_exit();
}

/****
 ****	UN*X compatible dynamic memory allocation
 ****/

/*
 *	calloc	return pointer to vector of 0, or NULL
 *	cfree	free previously allocated area
 *
 *	The heap starts at _end and runs upward toward the stack.
 *	Each area in the heap is preceded by a word at an even address;
 *	a pointer chain runs from _end through these words to NULL;
 *	The low bit in each word is 1 if the following area is free.
 *	There is a blind, allocated element at the front of the chain.
 *
 *	BUG:	very unreasonable demands (e.g., wraparound)
 *		will corrupt memory.
 */

#define	SLACK	1024	/* at least 1KB stack to be free */

CHAR_P calloc(n,len)
	int n;		/* number of elements */
	int len;	/* length of element */
{	int cell;	/* current allocation chain cell */
	char *p;	/* -> cell */
	char *np;	/* pointer in cell */
	int *ip, *wp;	/* for casting */

	len = (len*n + 1) & ~1;		/* even */
	if (len == 0)
		return NULL;
	for (ip = p = word(_end+1 & ~1) & ~1;
	     np = (cell = *ip) & ~1;
	     ip = p = np)
		if (cell & 1)		/* lowbit == 1 means free */
		{	if ((n = np-p - 2) > len+2)
			{	wp = p + len+2;
				*wp = cell;
				*ip = wp;
			}
			else if (n >= len)
				*ip = np;
			else
				continue;
			for (wp = p+2; len; len -= 2)
				*wp++ = 0;
			return p+2;
		}
	if ((wp = p + len+2) > &n - SLACK)
		return NULL;
	*ip = wp;
	*wp = NULL;
	for (wp = p+2; len; len -= 2)
		*wp++ = 0;
	return p+2;
}

cfree(fp)
	int *fp;	/* to be freed */
{	int *p, *np;

	--fp;				/* to cell */
	for (p = _end+1 & ~1;
	     np = word(p) & ~1;
	     p = np)			/* p-> previous cell */
		if (np == fp)		/* fp-> cell to free */
		{	np = *fp;	/* np-> following cell */
			if ((*fp & 1) || np == NULL)
				break;	/* he does not own it */
			if (*p & 1)
				if (*np & 1)
					*p = *np;
				else if (*np == NULL)
					*p = NULL;
				else
				{	*p = np;
					*p |= 1;
				}
			else if (*np & 1)
				*fp = *np;
			else if (*np == NULL)
				*fp = NULL;
			else
				*fp |= 1;
			return;
		}
	fputs("cfree botch", stderr);
	_exit();
}

/****
 ****	UN*X compatible character functions
 ****/

/*
 *	character type functions:
 *
 *	isascii(i)	i is ASCII character
 *	isupper(c)	c is upper case
 *	islower(c)	c is lower case
 *	isalnum(c)	c is alphabetic or digit
 *	isspace(c)	c is white space
 */

INT isascii(i) int i;	{ return i >= 0 && i < 128; }
INT isupper(c) char c;	{ return _ctype[c] & C_UPPER; }
INT islower(c) char c;	{ return _ctype[c] & C_LOWER; }
INT isalnum(c) char c;	{ return _ctype[c] & C_ALNUM; }
INT isspace(c) char c;	{ return _ctype[c] & C_SPACE; }

/*
 *	character conversion functions:
 *
 *	tolower(u)	return lower case version of u
 *	toupper(l)	return upper case version of l
 */

CHAR tolower(u) char u; { return u + 'a'-'A'; }
CHAR toupper(l) char l; { return l + 'A'-'a'; }

/****
 ****	UN*X compatible string functions
 ****/

/*
 *	strcmp	0 if `a' == `b'
 *		<0 if `a' < `b'
 *		>0 if `a' > `b'
 */

INT strcmp(a,b)
	char *a, *b;
{
	while (*a == *b && *a)
		a++, b++;
	return *a - *b;
}

/****
 ****	routines to approximate C features
 ****/

/*
 *	word(&i)	return word
 */

INT word(wp)
	int *wp;
{
	return *wp;
}

/****
 ****	CP/M utility routines
 ****/

/*
 *	mkarg	massage argument text, return -> unused char
 *
 *		convert upper case to lower, unless preceded by \
 *		terminate on stop character or white space,
 *		append NUL to resulting text.
 *
 *	mkdrive(&c)		return 0.. for A..
 *	mkfield(&c,i,&c)	upper-case, copy, pad, return -> next
 *	mkfilename(&c,&c)	fix-format filename, return success
 *	mkfcb(&c,&c)		init fcb with file name, return success
 */

CHAR_P mkarg(str, stop)
	char *str;		/* -> (first) result character */
	char stop;		/* 0: space, other: terminator */
{	char *cp, ch;

	for(cp = str; ; )
	{	switch (ch = *cp++) {
		case NUL:
			if (stop == 0)
			{	*str = NUL;
				return cp-1;
			}
			fputs("missing ", stderr);
			fputc(stop, stderr);
			_exit();
		case '\\':
			if (*cp)
			{	*str++ = *cp++;
				continue;
			}
			fputs("trailing \\", stderr);
			_exit();
		}
		if (ch == stop || isspace(ch) && stop == 0)
		{	*str = NUL;
			return cp;
		}
		if (isupper(ch))
			*str++ = tolower(ch);
		else
			*str++ = ch;
	}
}

INT mkdrive(cp)
	char *cp;
{
	if (isascii(*cp))
		if (isupper(*cp))
			return *cp - 'A';
		else if (islower(*cp))
			return *cp - 'a';
	return ERR;
}

CHAR_P mkfield(f,l,s)	/* copy isalnum() */
	char *f;	/* upper-cased to this buffer */
	int l;		/* blank padded to this length */
	char *s;	/* from this string */
{
	do
		if (isascii(*s) && isalnum(*s))
			if (islower(*s))
				*f++ = toupper(*s++);
			else
				*f++ = *s++;
		else
			break;
	while (--l);
	while (l--)
		*f++ = ' ';
	return s;
}

INT mkfilename(fnb, fnm)
	char fnb[16];		/* to be filled */
	char *fnm;		/* with this file name */
{	int i;

	if (fnm[1] == ':')
	{	if ((i = mkdrive(fnm)) == ERR)
			return ERR;
		fnb[FCB_ET] = i+1;
		fnm += 2;
	}
	else			/* make sure to set current drive */
		fnb[FCB_ET] = _drive()+1;
	fnm = mkfield(fnb+FCB_FN,8,fnm);
	if (*fnm == '.')
		fnm = mkfield(fnb+FCB_FT,3,fnm+1);
	else
		for (i=0; i<3; i++)
			fnb[FCB_FT+i] = ' ';
	if (*fnm != NUL)
		return ERR;
	return NULL;
}

INT mkfcb(fcb,fnm)
	char fcb[FCB_];		/* to be initialized */
	char *fnm;		/* with this file name */
{	int i;

	for (i=0; i<FCB_; i++)
		fcb[i] = NUL;
	return mkfilename(fcb,fnm);
}

/****
 ****	UN*X compatible file management for CP/M
 ****/

/*
 *	file management routines:
 *
 *	fopen	connect to file or device, return fp, or NULL
 *	freopen	change connection, return given fp, or NULL
 *	fclose	disconnect, return NULL, or EOF
 *
 *	BUG:	< 1<<16 sectors(records) per file
 */

FILE_P fopen(fnm,mode)
	char *fnm;		/* CP/M logical device or file name */
	char *mode;		/* "r", "w", or "a" */
{	FILE *fp;
	int *wp;		/* for casting */

	if ((fp = calloc(1, FB_)) == NULL)
		return NULL;
	wp = fp+FB_NXT;		/* link new block in */
	*wp = _fblocks;
	_fblocks = fp;
	return freopen(fnm, mode, fp);
}

FILE_P freopen(fnm,mode,fp)
	char *fnm;		/* CP/M logical device or file name */
	char *mode;		/* "r", "w", or "a" */
	FILE *fp;		/* -> FB, need not be open */
{	int i;			/* # in driver table */
	int f;			/* for function call */
	int *wp;		/* for casting */

	if (fp[FB_FLG] & FB_OPF && fclose(fp) == EOF)
		return NULL;			/* cannot close */
	if (fnm[0] && fnm[1] && fnm[2] && fnm[3] == ':' && fnm[4] == NUL)
	{	mkfield(fp+FCB_FN,3,fnm);	/* upper-case */
		fp[FCB_FN+3] = NUL;		/* terminate */
		for(i=1; ;i++)
			if (_dnm[i] == 0)
				return NULL;	/* unknown device */
			else if (strcmp(fp+FCB_FN, _dnm[i]) == 0)
				break;
	}
	else if (mkfcb(fp, fnm) == ERR)
		return NULL;			/* bad file name */
	else
		i = 0;
	fp[FB_DRV] = i;				/* point to driver */
	fp[FCB_OV] = 0;				/* set record 0 */
	wp = fp + FCB_RR;
	*wp = 0;
	wp = fp + FB_NCP;			/* set buffer empty */
	*wp = fp + FB_BUF;
	switch (*mode) {
	case 'r':
		if (_drd[i] == NULL)
			return NULL;		/* illegal to read */
		fp[FB_FLG] = FB_OPF;
		break;
	case 'a':
	case 'w':
		if (_dwr[i] == NULL)
			return NULL;		/* illegal to write */
		fp[FB_FLG] = FB_OPF|FB_OUF;
		break;
	default:
		return NULL;			/* illegal mode */
	}
	if (f = _dop[i])
		return (f)(fp,mode);
	return fp;				/* no special open */
}

INT fclose(fp)
	FILE *fp;
{	int f;			/* for function call */
	FILE *p;
	int *wp;		/* for casting */

	if ((fp[FB_FLG] & FB_OPF) == 0)
		return EOF;	/* not open */
	fp[FB_FLG] &= ~FB_OPF;	/* reset open flag */
	if (f = _dcl[fp[FB_DRV]])
		f = (f)(fp);	/* f is NULL or return */
	if (fp == _fblocks)
		_fblocks = word(fp+FB_NXT);
	else
	{	p = _fblocks;
		while (p)
		{	wp = p+FB_NXT;
			if (fp == *wp)
			{	*wp = word(fp+FB_NXT);
				break;
			}
			p = *wp;
		}
		if (p == NULL)
			return f;	/* stdio ?? */
	}
	cfree(fp);
	return f;
}

/****
 ****	UN*X compatible i/o transfer routines for CP/M
 ****/

/*
 *	character i/o:
 *
 *	fputc(ch,fp)	to fp
 *		map '\n' to RETURN LINEFEED,
 *		return EOF on hard error.
 */

INT fputc(ch,fp)
	char ch;
	FILE *fp;
{	int f;		/* to cast a function call */

	if ((fp[FB_FLG] & FB_OUF) == 0 || (fp[FB_FLG] & FB_OPF) == 0)
	{	fputs("writing bad file", stderr);
		_exit();
	}
	if (fp[FB_FLG] & FB_EOF)
		return EOF;	/* hard end of file */
	_cfp = fp;		/* pass to _fputchar */
	f = _dwr[fp[FB_DRV]];
	if (ch == '\n')		/* map '\n' to RETURN LINEFEED */
	{	(f)(CR);
		(f)(LF);
	}
	else
		(f)(ch);
	if (fp[FB_FLG] & (FB_EOF | FB_ERM))
		return EOF;
	return ch;
}

/*
 *	other i/o:
 *
 *	fputs	string to fp
 *
 *	return NULL on error, else string.
 */

CHAR_P fputs(s, fp)
	char *s;
	FILE *fp;
{	char ch;
	char *str;

	str = s;
	while (ch = *s++)
		if (fputc(ch, fp) == EOF)
			return NULL;
	return str;
}

/****
 ****	CP/M drivers to execute i/o operations
 ****/

/*
 *	general routines:
 *
 *	_binit		clear buffer
 *	_bgetchar	return one character from buffer
 *	_bputchar	enter one character to buffer
 *	_ngetchar	return EOF
 *	_nop		do nothing (accept anything)
 *
 *	BUG:	assumes at most 16-bit record address
 *		i.e., FCB_OV is not used.
 */

_binit(cp)			/* initialize buffer */
	char *cp;
{	int len;

	for (len = SLEN; len--; )
		*cp++ = SUB;	/* to end of file character */
}

INT _bgetchar()			/* use _cfp */
{	int *wp;		/* for casting */
	char *cp;		/* for casting */
	int f;			/* for function call */

	wp = _cfp+FB_NCP;
	if (*wp >= _cfp + FB_BUF+SLEN)
	{	wp = _cfp+FCB_RR;
		++*wp;		/* next record */
		f = _dbr[_cfp[FB_DRV]];
		if ((f)(_cfp))
			return EOF;
		wp = _cfp+FB_NCP;
		*wp = _cfp+FB_BUF;	/* at begin */
	}
	cp = (*wp)++;
	return *cp & 255;
}

_bputchar(ch)			/* use _cfp */
	char ch;
{	int *wp;		/* for casting */
	char *cp;		/* for casting */
	int f;			/* for function call */

	wp = _cfp+FB_NCP;
	if (*wp >= _cfp + FB_BUF+SLEN)
	{	f = _dbw[_cfp[FB_DRV]];
		if ((f)(_cfp))
			return EOF;
		wp = _cfp+FCB_RR;
		++*wp;
		wp = _cfp+FB_NCP;
		_binit(*wp = _cfp+FB_BUF);
	}
	cp = (*wp)++;
	*cp = ch;
}

INT _ngetchar()
{
	_cfp[FB_FLG] |= FB_EOF;
	return EOF;
}

_nop()
{
}
%%%%%%%%%% scc/rtl/def.h %%%%%%%%%%
/*
 *	def.h -- definitions for smallC runtime support
 *	ats 3/83, in part adapted from Jim Hendrix' code
 */

/*
 *	return types for functions
 */

#define	STATIC			/* object is internal */
#define INT			/* int */
#define CHAR			/* char */
#define CHAR_P			/* char * */
#define FILE_P			/* FILE * */

/*
 *	constants
 */

#define NULL	0		/* null pointer */
#define NUL	0		/* nul character */
#define EOF	(-1)		/* end of file */
#define ERR	(-2)		/* error return a la Hendrix */

/*
 *	file management
 */

#define FILE	char		/* file pointer is char * */
#define stdin	(_fbin)		/* elsewhere, must be addresses */
#define stdout	(_fbout)
#define stderr	(_fberr)

/*
 *	CP/M related definitions
 */

#define EOT	4		/* ^D marks end of file at console */
#define LF	10		/* line feed */
#define CR	13		/* carriage return */
#define SUB	26		/* ^Z marks end of text */
#define SLEN	128		/* sector length */
#define LSLEN	7		/* log2 of SLEN */

/*				/* offset to... */

#define DHD_	16		/* next disk header block */
#define DHD_XLT	0		/* -> translate table */
#define DHD_DBF	8		/* -> directory buffer */
#define DHD_DPB	10		/* -> disk parameter block */
#define DHD_CST	12		/* -> directory checksum table */
#define DHD_RBR	14		/* -> allocation table */

#define DPB_	15		/* next disk parameter block */
#define DPB_SPT	0		/* sectors per track */
#define DPB_BSH	2		/* block shift */
#define DPB_BLM	3		/* block shift mask */
#define DPB_EXM	4		/* extent mask */
#define DPB_DSM	5		/* disk size - 1 in blocks */
#define DPB_DRM	7		/* directory size - 1 in entries */
#define DPB_ALB	9		/* directory allocation */
#define DPB_CKS	11		/* check area size */
#define DPB_OFF	13		/* offset to first track */

#define FCB_	36		/* next file control block */
#define FCB_ET	0		/* entry type/drive code/user number */
#define FCB_FN	1		/* file name */
#define FCB_FT	9		/* file type (extension) */
#define FCB_RO	9		/* high bit is read only flag */
#define FCB_SY	10		/* high bit is system file flag */
#define FCB_EX	12		/* file extent */
#define FCB_S1	13		/* 00 */
#define FCB_S2	14		/* system use */
#define FCB_RC	15		/* record count in extent */
#define FCB_DM	16		/* 16 record allocation bytes */
#define FCB_NR	32		/* next record number in this extent */
#define FCB_RR	33		/* random record number */
#define FCB_OV	35		/* RR overflow */

/*define FB_FCB	0		/* FCB is first */
#define FB_FLG	(FCB_)		/* (char)	flags */
#define FB_OPF	(1<<7)			/* 0: closed, 1: open */
#define FB_OUF	(1<<6)			/* 0: input, 1: output */
#define FB_EOF	(1<<5)			/* hard end of file */
#define FB_UNF	(1<<4)			/* ungetc buffer full */
#define FB_ERM	(FB_UNF-1)		/* mask to get error code */
#define FB_UNC	(FCB_+1)	/* (char)	ungetc buffer */
#define FB_NXT	(FCB_+2)	/* (FILE *)	-> next file block */
#define FB_DRV	(FCB_+4)	/* (char)	index into driver table */
#define FB_NCP	(FCB_+5)	/* (char *)	-> next character */
#define FB_BUF	(FB_NCP+2)	/* (char[SLEN])	buffer */
#define FB_	(FB_BUF+SLEN)	/* next file block */
%%%%%%%%%% scc/rtl/dtab.c %%%%%%%%%%
/*
 *	dtab.c -- driver table with raw disk interface
 *	ats 3/83
 */

#include def.h		/* TO BE FIXED */
%%%%%%%%%% scc/rtl/end.mac %%%%%%%%%%
;	end.mac -- smallC runtime library - last module
;		for CP/M
;		for MACRO/80

	ENTRY	_edata		; end of all DSEG
	ENTRY	_eprog		; end of all CSEG
	ENTRY	_end		; end of code and data
	ENTRY	?30217		; version reference

	DSEG
?30217:
	DB	"021783"	; production date
_edata:

	CSEG
	DB	115,109,97,108,108,67	; smallC
_eprog:
_end:

	END
%%%%%%%%%% scc/rtl/fio.c %%%%%%%%%%
/*
 *	fio.c -- file driver for CP/M
 *	ats 3/83
 */

#define	NOCCARGC
#include def.h		/* TO BE FIXED */

/*
 *	external references
 */

extern	word(),		/* CSH	/* return word at pointer */
	_binit(),		/* initialize buffer to EOF character */
	_open(),	/* BDOS	/* connect to existing file */
	_romap(),		/* return r/o vector */
	_setbuf(),		/* set DMA address */
	_glob(),		/* search for first name */
	_close(),		/* disconnect from file */
	_delete(),		/* remove file */
	_create(),		/* make file, connect */
	_rread(),		/* read random record */
	_rzwrite(),		/* write random record, zero new block */
	_stat();		/* determine file size */

/****
 ****	CP/M file driver
 ****/

/*
 *	_fopen		connect, get buffer, return given fp or NULL
 *	_fblin		input one CP/M sector
 *	_fblout		output one CP/M sector
 *	_fseek		position to offset, return NULL or -1
 *	_fclose		write last buffer, disconnect, return NULL or EOF
 *
 *	There is a problem in positioning to end of file,
 *	since CP/M marks this using SUB -- see _fseek.
 */

FILE_P _fopen(fp,mode)
	FILE *fp;		/* available file block */
	char *mode;
{	int i;

	switch(*mode) {
	case 'r':
		if (_open(fp) >> 2)
			break;
		_fblin(fp);	/* read first buffer */
		return fp;
	case 'a':
	case 'w':
		if (_romap() & 1 << fp[FCB_ET]-1)
			break;		/* disk read only */
		_setbuf(fp+FB_BUF);
		if ((i = _glob(fp)) >> 2 == 0)
			if (fp[FB_BUF + 32*i + FCB_RO] & 128)
				break;	/* file read only */
			else if (*mode == 'a')
			{	if (_open(fp) >> 2)
					break;
				/*
				 *	issue a trick call to position to
				 *	char-EOF without reading first
				 */
				if (_fseek(fp, 2, -1,-1, 0,0) == -1)
				{	_close(fp);
					break;
				}
				return fp;
			}
			else if (_delete(fp) >> 2)
				break;	/* unable to delete */
		if (_create(fp) >> 2)
			break;		/* unable to create */
		_binit(fp+FB_BUF);
		return fp;
	}
	fp[FB_FLG] = 0;			/* nothing */
	return NULL;
}

INT _fblin(fp)
	FILE *fp;
{	int code;

	_setbuf(fp+FB_BUF);
	switch(code = _rread(fp)) {
	case 0:				/* read ok */
		return NULL;
	case 1:				/* reading unwritten data */
		fp[FB_FLG] |= FB_EOF;
		break;
	default:			/* other error */
		fp[FB_FLG] &= ~FB_ERM;
		fp[FB_FLG] |= code;
	}
	return EOF;
}

INT _fblout(fp)
	FILE *fp;
{	int code;

	_setbuf(fp+FB_BUF);
	switch(code = _rzwrite(fp)) {
	case 0:
		return NULL;
	case 5:				/* directory overflow */
		fp[FB_FLG] |= FB_EOF;
		break;
	default:			/* other error */
		fp[FB_FLG] &= ~FB_ERM;
		fp[FB_FLG] |= code;
	}
	return EOF;
}

INT _fseek(fp,mode,csec,cpos,ssec,spos)
	FILE *fp;	/* to position */
	int mode;	/* checked to be 0,1,2,8,9,10 */
	int csec,cpos;	/* current position */
	int ssec,spos;	/* to be attained,
			   relative for modes 2,10 */
{	int *wp;	/* for casting */

	/*
	 *	csec/cpos is current position,
	 *	current position was flushed,
	 *	now position to end of file
	 *
	 *	note that mode==2, csec==-1 will
	 *	position to char-EOF without worrying
	 *	about buffer contents first.
	 */

	_setbuf(fp+FB_BUF);
	_stat(fp);			/* file size to RR */
	wp = fp+FCB_RR;
	switch(mode) {
	case 0:
	case 1:
	case 2:
		if (*wp == 0)
		{	csec = cpos = 0;
			wp = fp+FB_NCP;
			_binit(*wp = fp+FB_BUF);
			break;
		}
		if (--(*wp) != csec)
			if (_rread(fp))
				return -1;	/* ouch!!! */
		csec = *wp;		/* last sector is buffered */
		for (cpos = 0; cpos < SLEN; cpos++)
			if (fp[FB_BUF+cpos] == SUB)
				break;
		if (cpos >= SLEN)	/* last byte found */
		{	cpos = 0;
			*wp = ++csec;
			wp = fp+FB_NCP;
			_binit(*wp = fp+FB_BUF);
		}
		else
		{	wp = fp+FB_NCP;
			*wp = fp+FB_BUF + cpos;
		}
		if (mode != 2)
			break;
		ssec += csec;		/* make absolute */
		if ((spos += cpos) < 0)
		{	spos += SLEN;
			--ssec;
		}
		else if (spos >= SLEN)
		{	spos -= SLEN;
			++ssec;
		}
		break;
	case 10:
		ssec += *wp;		/* make absolute */
		spos = 0;		/* sector-relative! */
	case 8:
	case 9:
		csec = *wp;		/* buffer end of file */
		cpos = 0;
		wp = fp+FB_NCP;
		_binit(*wp = fp+FB_BUF);
	}

	/*
	 *	csec/cpos is end of file
	 *	buffer contents reflect this
	 *	now position to ssec/spos (absolute)
	 */

	if (ssec < 0 || ssec > csec || ssec == csec && spos > cpos)
		return -1;		/* not inside file */
	if (ssec != csec)		/* i.e., before EOF */
	{	wp = fp+FCB_RR;
		*wp = ssec;
		if (_rread(fp))
			return -1;	/* ouch!!! */
	}
	wp = fp+FB_NCP;
	*wp = fp+FB_BUF + spos;
	return 0;
}

INT _fclose(fp)
	FILE *fp;
{	int result;

	if (fp[FB_FLG] & FB_OUF && word(fp+FB_NCP) != fp+FB_BUF)
		result = _fblout(fp);
	else
		result = 0;
	if (_close(fp) >> 2 || result)
		return EOF;
	return NULL;
}
%%%%%%%%%% scc/rtl/ftab.c %%%%%%%%%%
/*
 *	ftab.c -- driver table without raw disk interface
 *	ats 3/83
 */

#include def.h		/* TO BE FIXED */
#define	FTAB	/**/	/* signal to io.h */
%%%%%%%%%% scc/rtl/io.h %%%%%%%%%%
/*
 *	io.h -- disk and file driver tables for CP/M
 *	ats 3/83
 */

/*
 *	define...
 *
 *	FTAB	to create a driver table without the raw disk interface.
 */

/*
 *	C.REL:	CRTL DTAB CSH FTAB FIO ... END
 *
 *	The first external reference to the driver table
 *	is (officially) in CSH, thus FTAB is the default table.
 *	If the user's program contains a reference like
 *	`extern _dopen();' DTAB will instead be included.
 */

#define	NOCCARGC

/*
 *	external references
 */

extern	mkdrive(),	/* CSH	/* convert letter to drive # */
	word(),			/* return word from pointer */
	_binit(),		/* set buffer to EOF character */
	_bgetchar(),		/* read byte from buffer */
	_bputchar(),		/* write byte to buffer */
	_ngetchar(),		/* set+return end of file */
	_nop(),			/* do nothing */
	_fopen(),	/* FIO	/* complete open */
	_fblin(),		/* read buffer */
	_fblout(),		/* write buffer */
	_fseek(),		/* seek */
	_fclose(),		/* complete close */
	_getchar(),	/* BDOS	/* console read (+echo) */
	_rgetchar(),		/* reader read */
	_putchar(),		/* console write (+tab) */
	_pputchar(),		/* punch write */
	_lputchar(),		/* printer write */
	_romap();		/* return r/o vector */

#ifndef FTAB

extern	_seldsk(),	/* BIOS /* select disk drive */
	_sectran(),		/* translate sector address */
	_settrk(),		/* set track */
	_setsec(),		/* set sector */
	_setdma(),		/* set DMA address */
	_sread(),		/* read sector */
	_swrite();		/* write sector */

			/* special argument to... */
#define	SELDSK2	0	/* _seldsk: ignored by Osborne CBIOS */
#define	SWRITE	0	/* _swrite: regular write */

#endif

/****
 ****	driver table
 ****/

/*
 *	_dnm	permissible device names, 0-terminated
 *	_dop	open		&func, NULL if none needed
 *	_drd	read byte	&func, NULL if not allowed
 *	_dwr	write byte	&func, NULL if not allowed
 *	_dbr	block read	&func, NULL if read byte unbuffered
 *	_dbw	block write	&func, NULL if write byte unbuffered
 *	_dsk	seek		&func, NULL if not permitted
 *	_dcl	close		&func, NULL if none needed
 *
 *	File manager is entry 0, other entries are devices.
 *	Device names are known (in freopen) to be 3 letters.
 *	Disk names are known (in _dopen) to have a legal and
 *	existing drive name as third character.
 *
 *	con:	read/write console, as set by i/o byte
 *	rdr:	read reader, as set by i/o byte
 *	pun:	write punch, as set by i/o byte
 *	lst:	write list device, as set by i/o byte
 *	nul:	EOF on read, no operation on write
 *	dka:	disk A: under BIOS
 *	dkb:	disk B: under BIOS
 */

/*
 *	Due to bugs in smallC, this is done in assembler.

char *_dnm[]	={"",    "CON", "RDR", "PUN", "LST", "NUL", "DKA", "DKB", 0};
int (*_dop[])() ={_fopen,NULL,  NULL,  NULL,  NULL,  NULL,  _dopen,_dopen };
int (*_drd[])() ={_bgetc,_getch,_rgetc,NULL,  NULL,  _ngetc,_bgetc,_bgetc };
int (*_dwr[])() ={_bputc,_putch,NULL,  _pputc,_lputc,_nop,  _bputc,_bputc };
int (*_dbr[])() ={_fblin,NULL,  NULL,  NULL,  NULL,  NULL,  _dblin,_dblin };
int (*_dbw[])()	={_fblou,NULL,  NULL,  NULL,  NULL,  NULL,  _dblou,_dblou };
int (*_dsk[])() ={_fseek,NULL,  NULL,  NULL,  NULL,  NULL,  _dseek,_dseek };
int (*_dcl[])() ={_fclos,NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL   };

 *
 */

STATIC int _dnm[1];
#asm
	DSEG
	ORG	_dnm
	DW	..1
	DW	..2
	DW	..3
	DW	..4
	DW	..5
	DW	..6
#endasm
#ifndef FTAB
#asm
	DW	..7
	DW	..8
#endasm
#endif
#asm
	DW	0
..2:	DB	'CON'
..1:	DB	0
..3:	DB	'RDR',0
..4:	DB	'PUN',0
..5:	DB	'LST',0
..6:	DB	'NUL',0
#endasm
#ifndef FTAB
#asm
..7:	DB	'DKA',0
..8:	DB	'DKB',0
#endasm
#endif

STATIC int _dop[1];
#asm
	DSEG
	ORG	_dop
	DW	_fopen
	DW	0
	DW	0
	DW	0
	DW	0
	DW	0
#endasm
#ifndef FTAB
#asm
	DW	_dopen
	DW	_dopen
#endasm
#endif

int _drd[1];
#asm
	DSEG
	ORG	_drd
	DW	_bgetcha
	DW	_getchar
	DW	_rgetcha
	DW	0
	DW	0
	DW	_ngetcha
#endasm
#ifndef FTAB
#asm
	DW	_bgetcha
	DW	_bgetcha
#endasm
#endif

int _dwr[1];
#asm
	DSEG
	ORG	_dwr
	DW	_bputcha
	DW	_putchar
	DW	0
	DW	_pputcha
	DW	_lputcha
	DW	_nop
#endasm
#ifndef FTAB
#asm
	DW	_bputcha
	DW	_bputcha
#endasm
#endif

STATIC int _dbr[1];
#asm
	DSEG
	ORG	_dbr
	DW	_fblin
	DW	0
	DW	0
	DW	0
	DW	0
	DW	0
#endasm
#ifndef FTAB
#asm
	DW	_dblin
	DW	_dblin
#endasm
#endif

STATIC int _dbw[1];
#asm
	DSEG
	ORG	_dbw
	DW	_fblout
	DW	0
	DW	0
	DW	0
	DW	0
	DW	0
#endasm
#ifndef FTAB
#asm
	DW	_dblout
	DW	_dblout
#endasm
#endif

int _dsk[1];
#asm
	DSEG
	ORG	_dsk
	DW	_fseek
	DW	0
	DW	0
	DW	0
	DW	0
	DW	0
#endasm
#ifndef FTAB
#asm
	DW	_dseek
	DW	_dseek
#endasm
#endif

STATIC int _dcl[1];
#asm
	DSEG
	ORG	_dcl
	DW	_fclose
	DW	0
	DW	0
	DW	0
	DW	0
	DW	0
#endasm
#ifndef FTAB
#asm
	DW	_dclose
	DW	_dclose
#endasm
#endif

#ifndef FTAB

/****
 ****	CP/M raw disk driver
 ****/

/*
 *	_dopen	connect, get buffer, return given fp or NULL
 *	_dblin	input one CP/M sector
 *	_dblout	output one CP/M sector
 *	_dseek	position to offset, return NULL or -1
 *	_dclose	write last buffer, disconnect, return NULL or EOF
 *
 *	BUGS:	<= 127 sectors/track, <=127 first track,
 *		sectors before first directory track are not translated,
 *		<= 32767 sectors/disk,
 *		_dseek only knows sector-EOF
 */

#define	DSK_DR	FCB_ET		/* drive #, 0==A, ... */
#define	DSK_NM	(FCB_FN+2)	/* (existing) drive name */
#define	DSK_ST	FCB_S1		/* sectors/track */
#define	DSK_FT	FCB_S2		/* first directory track */
#define	DSK_XL	FCB_DM		/* (word) -> translate table */
 
FILE_P _dopen(fp,mode)
	FILE *fp;	/* available file block */
	char *mode;
{	int *wp;	/* for casting */
	char *cp;	/* for casting */
	int i;

	if ((cp = _seldsk(fp[DSK_DR] = mkdrive(fp+DSK_NM), SELDSK2)) != NULL)
	{	wp = fp+DSK_XL;
		*wp = word(cp+DHD_XLT);
		cp = word(cp+DHD_DPB);
		fp[DSK_ST] = word(cp+DPB_SPT);
		fp[DSK_FT] = word(cp+DPB_OFF);
		switch(*mode) {
		case 'r':
			if (_dblin(fp))
				break;
			return fp;
		case 'w':
			if (_romap() & 1 << fp[DSK_DR])
				break;
			_binit(fp+FB_BUF);
			return fp;
		}
	}
	fp[FB_FLG] = 0;			/* nothing */
	return NULL;
}

STATIC INT _dblio(fp)	/* setup for disk i/o */
	FILE *fp;
{	int track, sector;

	if (_seldsk(fp[DSK_DR], SELDSK2) == NULL)
	{	fp[FB_FLG] &= ~FB_ERM;
		fp[FB_FLG] |= 1;	/* BUG, really */
		return EOF;
	}
	sector = word(fp+FCB_RR);
	if ((track = sector/fp[DSK_ST]) >= fp[DSK_FT])
		sector = _sectran(sector % fp[DSK_ST], word(fp+DSK_XL));
	else
		sector %= fp[DSK_ST];
	_settrk(track);
	_setsec(sector);
	_setdma(fp+FB_BUF);
	return NULL;
}

INT _dblin(fp)
	FILE *fp;
{
	if (_dblio(fp))
		return EOF;
	if (_sread())
	{	fp[FB_FLG] |= FB_EOF;
		return EOF;
	}
	return NULL;
}

INT _dblout(fp)
	FILE *fp;
{
	if (_dblio(fp))
		return EOF;
	if (_swrite(SWRITE))
	{	fp[FB_FLG] |= FB_EOF;
		return EOF;
	}
	return NULL;
}

INT _dseek(fp,mode,csec,cpos,ssec,spos)
	FILE *fp;	/* to position */
	int mode;	/* checked to be 0,1,2,8,9,10 */
	int csec,cpos;	/* current position */
	int ssec,spos;	/* to be attained,
			   relative for modes 2,10 */
{	int *wp;	/* for casting */
	char *cp;	/* for casting */

	/*
	 *	csec/cpos is current position,
	 *	current position was flushed,
	 *	now position to end of drive
	 */

	if ((cp = _seldsk(fp[DSK_DR], SELDSK2)) == NULL)
		return -1;		/* unknown drive */
	wp = fp+FCB_RR;			/* set RR */
	cp = word(cp+DHD_DPB);		/* point to DPB */
	*wp = csec = (cp[DPB_BLM]+1)	/* sectors/block */
		* (word(cp+DPB_DSM)+1)	/* blocks/disk */
		+ word(cp+DPB_OFF)	/* system tracks */
		* word(cp+DPB_SPT);	/* sectors/track
	cpos = 0;
	wp = fp+FB_NCP;			/* empty buffer */
	_binit(*wp = fp+FB_BUF);
	switch(mode) {
	case 10:
		spos = 0;		/* sector-relative */
	case 2:
		ssec += csec;		/* make absolute */
		break;
	}

	/*
	 *	csec/cpos is end of file
	 *	buffer contents reflect this
	 *	now position to ssec/spos (absolute)
	 */

	if (ssec < 0 || ssec > csec || ssec == csec && spos > cpos)
		return -1;		/* not inside file */
	if (ssec != csec)		/* i.e., before EOF */
	{	wp = fp+FCB_RR;
		*wp = ssec;
		if (_dblin(fp))
			return -1;	/* ouch!!! */
	}
	wp = fp+FB_NCP;
	*wp = fp+FB_BUF + spos;
	return 0;
}

INT _dclose(fp)
	FILE *fp;
{
	if (fp[FB_FLG] & FB_OUF && word(fp+FB_NCP) != fp+FB_BUF)
		return _dblout(fp);
	return NULL;
}

#endif	/* ndef FTAB */
%%%%%%%%%% scc/rtl/make.sub %%%%%%%%%%
;	smallC runtime library
;
;	c?:	source($1) object($2)
;		get($3) smallC($4)
;		macro-80($5) lib-80($6)
;
;	ats 2/83
;
; mkwfield	 needs is*
;
$3 #$$a <$1:c0.get >$1:tmp.c
$4 $1:tmp.c >$1:tmp.mac
$5 $2:tmp1=$1:tmp
;
; mkwfilename	 needs mkwfield
;
$3 #$$b <$1:c0.get >$1:tmp.c
$4 $1:tmp.c >$1:tmp.mac
$5 $2:tmp2=$1:tmp
;
; mkwfcb	 needs mkwfilename
;
$3 #$$c <$1:c0.get >$1:tmp.c
$4 $1:tmp.c >$1:tmp.mac
$5 $2:tmp3=$1:tmp
;
; dumpbit	 needs putbit printf
;
$3 #d <$1:c0.get >$1:tmp.c
$4 $1:tmp.c >$1:tmp.mac
$5 $2:tmp4=$1:tmp
;
; dumpdpb	 needs putchar printf byte
;
$3 #e <$1:c0.get >$1:tmp.c
$4 $1:tmp.c >$1:tmp.mac
$5 $2:tmp5=$1:tmp
$6 $2:clib=$2:tmp1,$2:tmp2,$2:tmp3,$2:tmp4,$2:tmp5/e
;
; dumpfcb	 needs putchar printf byte
;
$3 #f <$1:c0.get >$1:tmp.c
$4 $1:tmp.c >$1:tmp.mac
$5 $2:tmp1=$1:tmp
;
; feof
;
$3 #$$g <$1:c0.get >$1:tmp.c
$4 $1:tmp.c >$1:tmp.mac
$5 $2:tmp2=$1:tmp
;
; ferror
;
$3 #$$h <$1:c0.get >$1:tmp.c
$4 $1:tmp.c >$1:tmp.mac
$5 $2:tmp3=$1:tmp
;
; clearerr
;
$3 #$$i <$1:c0.get >$1:tmp.c
$4 $1:tmp.c >$1:tmp.mac
$5 $2:tmp4=$1:tmp
;
; fseek
;
$3 #$$j <$1:c0.get >$1:tmp.c
$4 $1:tmp.c >$1:tmp.mac
$5 $2:tmp5=$1:tmp
$6 $2:tmp=$2:clib,$2:tmp1,$2:tmp2,$2:tmp3,$2:tmp4,$2:tmp5/e
era $2:clib.rel
ren $2:clib.rel=$2:tmp.rel
;
; rewind	needs fseek
;
$3 #$$k <$1:c0.get >$1:tmp.c
$4 $1:tmp.c >$1:tmp.mac
$5 $2:tmp1=$1:tmp
;
; getchar	 needs fgetc
;
$3 #$$m <$1:c0.get >$1:tmp.c
$4 $1:tmp.c >$1:tmp.mac
$5 $2:tmp3=$1:tmp
;
; fgetc	 needs ungetc
;
$3 #$$n <$1:c0.get >$1:tmp.c
$4 $1:tmp.c >$1:tmp.mac
$5 $2:tmp4=$1:tmp
;
; ungetc
;
$3 #$$o <$1:c0.get >$1:tmp.c
$4 $1:tmp.c >$1:tmp.mac
$5 $2:tmp5=$1:tmp
$6 $2:tmp=$2:clib,$2:tmp1,$2:tmp3,$2:tmp4,$2:tmp5/e
era $2:clib.rel
ren $2:clib.rel=$2:tmp.rel
submit 2 $1 $2 $3 $4 $5 $6
%%%%%%%%%% scc/rtl/printf.c %%%%%%%%%%
/*
 *	printf.c -- smallC runtime library for CP/M and MACRO-80
 *		    UN*X compatible printf routines
 *	ats 2/83, adapted from Jim Hendrix' code
 *	rev (treat %??c like %??s) ats 3/83
 */

#define NOCCARGC
#include def.h		/* TO BE FIXED */

/*
 *	globally external things (in csh)
 */

extern char _fbin[];		/* stdin */
extern char _fbout[];		/* stdout */
extern char _fberr[];		/* stderr */
extern _narg();			/* returns # arguments */
extern abort();			/* terminate on output error */
extern fputc(), fputs();	/* output to file */
extern isdigit();		/* character class */

/*
 *	local definitions
 */

#define	SZ	7	/* output item size */

/*
 *	_pfemit	emit one character
 */

STATIC char *_pfstr;		/* sprintf: -> string */

STATIC _pfemit(c, fp)
	char c;
	FILE *fp;
{
	if (fp == &_pfstr)
		*_pfstr++ = c;	/* sprintf */
	else if (fputc(c, fp) == EOF)
	{	fputs("output error", stderr);
		abort();
	}
}

/*
 *	_itod	nbr to signed decimal string
 *	_itou	nbr to unsigned decimal string
 *	_itox	nbr to hex string
 *
 *	width SZ, right adjusted, blank filled, terminated with null byte
 */

STATIC _itod(nbr, str)
	int nbr;
	char str[];
{	char sgn;
	int sz;

	sz = SZ;
	if (nbr < 0)
	{	nbr = -nbr;
		sgn = '-';
	}
	else
		sgn = ' ';
	str[--sz] = NUL;
	while(sz)
	{	str[--sz] = nbr % 10 + '0';
		if ((nbr /= 10) == 0)
			break;
	}
	if (sz)
		str[--sz] = sgn;
	while (sz > 0)
		str[--sz] = ' ';
}

STATIC _itou(nbr, str)
	int nbr;
	char str[];
{	int lowbit;
	int sz;

	sz = SZ;
	str[--sz] = NUL;
	while (sz)
	{	lowbit = nbr & 1;
		nbr = (nbr >> 1) & 32767;  /* divide by 2 */
		str[--sz] = ((nbr % 5) << 1) + lowbit + '0';
		if ((nbr /= 5) == 0)
			break;
	}
	while (sz)
		str[--sz] = ' ';
}

STATIC _itox(nbr, str)
	int nbr;
	char str[];
{	int digit, offset;
	int sz;

	sz = SZ;
	str[--sz] = NUL;
	while (sz)
	{	digit = nbr & 15;
		nbr = (nbr >> 4) & 4095;
		if (digit < 10)
			offset = '0';
		else
			offset = 'A'-10;
		str[--sz] = digit + offset;
		if (nbr == 0)
			break;
	}
	while (sz)
		str[--sz] = ' ';
}

/*
 *	_utoi	convert unsigned decimal string to integer nbr
 *		returns field size, else ERR on error
 */

STATIC INT _utoi(decstr, nbr)
	char *decstr;
	int *nbr;
{	int d,t;

	d = 0;
	*nbr = 0;
	while (isdigit(*decstr))
	{	t = *nbr;
		t = (10*t) + (*decstr++ - '0');
		if (t >= 0 && *nbr < 0)
			return ERR;
		d++;
		*nbr = t;
	}
	return d;
}

/*
 *	_printf	do the actual formatting
 */

STATIC _printf(fp, nxtarg)
	FILE *fp;		/* may be &_pfstr */
	int *nxtarg;		/* -> format */
{	int i, width, prec, preclen, len;
	char *ctl, *cx, c, right, str[SZ], *sptr, pad;

	ctl = *nxtarg;
	while (c = *ctl++)
	{	if (c != '%')
		{	_pfemit(c, fp);
			continue;
		}
		if (*ctl == '%')
		{	_pfemit(*ctl++, fp);
			continue;
		}
		cx = ctl;
		if (*cx == '-')
		{	right = 0;
			++cx;
		}
		else
			right = 1;
		if (*cx == '0')
		{	pad = '0';
			++cx;
		}
		else
			pad = ' ';
		if ((i = _utoi(cx, &width)) >= 0)
			cx += i;
		else
			continue;
		if (*cx == '.')
		{	if ((preclen = _utoi(++cx, &prec)) >= 0)
				cx += preclen;
			else
				continue;
		}
		else
			preclen = 0;
		sptr = str;
		i = *--nxtarg;
		switch (c = *cx++) {
		case 'c':
			str[0] = i;
			str[1] = NUL;
			break;
		case 'd':
			_itod(i, str);
			break;
		case 's':
			sptr = i;
			break;
		case 'u':
			_itou(i, str);
			break;
		case 'x':
			_itox(i, str);
			break;
		default:
			continue;
		}
		ctl=cx;		/* accept conversion spec */
		if (c != 's' && c != 'c')
			while (*sptr == ' ')
				++sptr;
		len = -1;
		while (sptr[++len])
			;	/* get length */
		if ((c == 's' || c == 'c') && len > prec && preclen > 0)
			len = prec;
		if (right)
			while (width-- - len > 0)
				_pfemit(pad, fp);
		while (len)
		{	_pfemit(*sptr++, fp);
			--len;
			--width;
		}
		while (width-- - len > 0)
			_pfemit(pad, fp);
	}
}

/*
 *	printf(format [, arg, ...] )
 *	fprintf(fp, format [, arg, ...] )
 *	sprintf(string, format [, arg, ...] )
 *
 *	as described by Kernighan and Ritchie
 *	support % [-] [0] [width] [. precision] (c|d|s|u|x)
 *	uses _narg() feature
 */

printf(argc)
	int argc;
{	int i;

	i = _narg();
	_printf(stdout, &argc + i-1);
}

fprintf(argc)
	int argc;
{	int i, *wp;

	i = _narg();
	wp = &argc + i-1;
	_printf(*wp, wp-1);
}

sprintf(argc)
	int argc;
{	int i, *wp;

	i = _narg();
	wp = &argc + i-1;
	_pfstr = *wp;
	_printf(&_pfstr, wp-1);
}
%%%%%%%%%% end of part 2 %%%%%%%%%%

schrein (03/14/83)

#R:uiucdcs:12600001:uiucdcs:12600003:000:56968
uiucdcs!schrein    Mar 12 09:23:00 1983

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

%%%%%%%%%% scc/scc/11.c %%%%%%%%%%
/***
 *	fixes:
 *
 *	= *	not =*
 *	lout has 2 arguments
 *	prompt needs to return 1 for openin... (unused, anyhow)
 *	optimizer by default turned on
 */

#include "smallc.h"	/*** system stuff */

/*
** execution begins here
*/
main(argc, argv) int argc, *argv; {
  argcs=argc;
  argvs=argv;
#ifdef DYNAMIC
  swnext=CCALLOC(SWTABSZ);
  swend=swnext+((SWTABSZ-SWSIZ)>>1);
  stage=CCALLOC(STAGESIZE);
  stagelast=stage+STAGELIMIT;
  wq=CCALLOC(WQTABSZ*BPW);
  litq=CCALLOC(LITABSZ);
#ifdef HASH
  macn=CCALLOC(MACNSIZE);
  cptr=macn-1;
  while(++cptr < MACNEND) *cptr=0;
#endif
  macq=CCALLOC(MACQSIZE);
  pline=CCALLOC(LINESIZE);
  mline=CCALLOC(LINESIZE);
#else
  swend=(swnext=swq)+SWTABSZ-SWSIZ;
  stagelast=stage+STAGELIMIT;
#endif
  swactive=	  /* not in switch */
  stagenext=	  /* direct output mode */
  iflevel=	  /* #if... nesting level = 0 */
  skiplevel=	  /* #if... not encountered */
  macptr=	  /* clear the macro pool */
  csp =		  /* stack ptr (relative) */
  errflag=	  /* not skipping errors till ";" */
  eof=		  /* not eof yet */
  ncmp=		  /* not in compound statement */
  files=
  filearg=
  quote[1]=0;
  ccode=1;	  /* enable preprocessing */
  wqptr=wq;	  /* clear while queue */
  quote[0]='"';	  /* fake a quote literal */
  input=input2=EOF;
  ask();	  /* get user options */
  openin();	  /* and initial input file */
  preprocess();	  /* fetch first line */
#ifdef DYNAMIC
#ifdef HASH
  symtab=CCALLOC(NUMLOCS*SYMAVG + NUMGLBS*SYMMAX);
#else
  symtab=CCALLOC(NUMLOCS*SYMAVG);
  /*  global space is allocated with each new entry  */
#endif
#endif
#ifdef HASH
  cptr=STARTGLB-1;
  while(++cptr < ENDGLB) *cptr=0;
#endif
  glbptr=STARTGLB;
  glbflag=1;
  ctext=0;
  header();	     /* intro code */
  setops();	     /* set values in op arrays */
  parse();	     /* process ALL input */
  outside();	     /* verify outside any function */
  trailer();	     /* follow-up code */
  fclose(output);
  }

/*
** process all input text
**
** At this level, only static declarations,
**	defines, includes and function
**	definitions are legal...
*/
parse() {
  while (eof==0) {
    if(amatch("extern", 6))   dodeclare(EXTERNAL);
    else if(dodeclare(STATIC));
    else if(match("#asm"))    doasm();
    else if(match("#include"))doinclude();
    else if(match("#define")) addmac();
    else		      newfunc();
    blanks();	    /* force eof if pending */
    }
  }

/*
** dump the literal pool
*/
dumplits(size) int size; {
  int j, k;
  k=0;
  while (k<litptr) {
    defstorage(size);
    j=10;
    while(j--) {
      outdec(getint(litq+k, size));
      k=k+size;
      if ((j==0)|(k>=litptr)) {
	nl();
	break;
	}
      outbyte(',');
      }
    }
  }

/*
** dump zeroes for default initial values
*/
dumpzero(size, count) int size, count; {
  int j;
  while (count > 0) {
    defstorage(size);
    j=30;
    while(j--) {
      outdec(0);
      if ((--count <= 0)|(j==0)) {
	nl();
	break;
	}
      outbyte(',');
      }
    }
  }

/*
** verify compile ends outside any function
*/
outside()  {
  if (ncmp) error("no closing bracket");
  }

/*
** get run options
*/
ask() {
  int i;
  i=listfp=nxtlab=0;
  output=stdout;
	optimize=YES;	/* default is to optimize */
  alarm=monitor=pause=NO;
  line=mline;
  while(getarg(++i, line, LINESIZE, argcs, argvs)!=EOF) {
    if(line[0]!='-') continue;
    if((upper(line[1])=='L')&(numeric(line[2]))&(line[3]<=' ')) {
      listfp=line[2]-'0';
      continue;
      }
    if(line[2]<=' ') {
      if(upper(line[1])=='A') {
	alarm=YES;
	continue;
	}
      if(upper(line[1])=='M') {
	monitor=YES;
	continue;
	}
      if(upper(line[1])=='O') {
	optimize=NO;	/* switch turns optimizer off */
	continue;
	}
      if(upper(line[1])=='P') {
	pause=YES;
	continue;
	}
      }
    sout("usage: cc [file]... [-m] [-a] [-p] [-l#] [-o]\n", stderr);
    abort();
    }
  }


/*
** get next input file
*/
openin() {
  input=EOF;
  while(getarg(++filearg, pline, LINESIZE, argcs, argvs)!=EOF) {
    if(pline[0]=='-') continue;
    if((input=fopen(pline,"r"))==NULL) {
      lout("open error", stderr);
      abort();
      }
    files=YES;
    kill();
    return;
    }
  if(files++) eof=YES;
  else input=stdin;
  kill();
  }

setops() {
  op2[00]=     op[00]=	or;  /* heir5 */
  op2[01]=     op[01]= xor;  /* heir6 */
  op2[02]=     op[02]= and;  /* heir7 */
  op2[03]=     op[03]=	eq;  /* heir8 */
  op2[04]=     op[04]=	ne;
  op2[05]=ule; op[05]=	le;  /* heir9 */
  op2[06]=uge; op[06]=	ge;
  op2[07]=ult; op[07]=	lt;
  op2[08]=ugt; op[08]=	gt;
  op2[09]=     op[09]= asr;  /* heir10 */
  op2[10]=     op[10]= asl;
  op2[11]=     op[11]= add;  /* heir11 */
  op2[12]=     op[12]= sub;
  op2[13]=     op[13]=mult;  /* heir12 */
  op2[14]=     op[14]= div;
  op2[15]=     op[15]= mod;
  }
%%%%%%%%%% scc/scc/12.c %%%%%%%%%%
/***
 *	fixes:
 *
 *	eliminate jump to first function
 *	mark code/data sections
 */

#include "smallc.h"

/*
** open an include file
*/
doinclude()  {
  blanks();	  /* skip over to name */
  if((input2=fopen(lptr,"r"))==NULL) {
    input2=EOF;
    error("open failure on include file");
    }
  kill();	  /* clear rest of line */
      /* so next read will come from */
      /* new file (if open */
  }

/*
** test for global declarations
*/
dodeclare(class) int class; {
  if(amatch("char",4)) {
    declglb(CCHAR, class);
    ns();
    return 1;
    }
  else if((amatch("int",3))|(class==EXTERNAL)) {
    declglb(CINT, class);
    ns();
    return 1;
    }
  return 0;
  }

/*
** delcare a static variable
*/
declglb(type, class)  int type, class; {
  int k, j;
  while(1) {
    if(endst()) return;	    /* do line */
    if(match("*")) {
      j=POINTER;
      k=0;
      }
    else {
      j=VARIABLE;
      k=1;
      }
    if (symname(ssname, YES)==0) illname();
    if(findglb(ssname)) multidef(ssname);
    if(match("()")) j=FUNCTION;
    else if (match("[")) {
      k=needsub();    /* get size */
      j=ARRAY;	 /* !0=array */
      }
    if(class==EXTERNAL) external(ssname);
    else j=initials(type>>2, j, k);
    addsym(ssname, j, type, k, &glbptr, class);
    if (match(",")==0) return; /* more? */
    }
  }

/*
** declare local variables
*/
declloc(typ)  int typ;	{
  int k,j;
#ifdef STGOTO
  if(noloc) error("not allowed with goto");
#endif
  if(declared < 0) error("must declare first in block");
  while(1) {
    while(1) {
      if(endst()) return;
      if(match("*")) j=POINTER;
      else j=VARIABLE;
      if (symname(ssname, YES)==0) illname();
      /* no multidef check, block-locals are together */
      k=BPW;
      if (match("[")) {
	k=needsub();
	if(k) {
	  j=ARRAY;
	  if(typ==CINT)k=k<<LBPW;
	  }
	else j=POINTER;
	}
      else if(match("()")) j=FUNCTION;
      else if((typ==CCHAR)&(j==VARIABLE)) k=SBPC;
      declared = declared + k;
      addsym(ssname, j, typ, csp - declared, &locptr, AUTOMATIC);
      break;
      }
    if (match(",")==0) return;
    }
  }

/*
** initialize global objects
*/
initials(size, ident, dim) int size, ident, dim; {
  int savedim;
  litptr=0;
  if(dim==0) dim = -1;
  savedim=dim;
	dsect();
  entry();
  if(match("=")) {
    if(match("{")) {
      while(dim) {
	init(size, ident, &dim);
	if(match(",")==0) break;
	}
      needtoken("}");
      }
    else init(size, ident, &dim);
    }
  if((dim == -1)&(dim==savedim)) {
     stowlit(0, size=BPW);
    ident=POINTER;
    }
  dumplits(size);
  dumpzero(size, dim);
  return ident;
  }

/*
** evaluate one initializer
*/
init(size, ident, dim) int size, ident, *dim; {
  int value;
  if(qstr(&value)) {
    if((ident==VARIABLE)|(size!=1))
      error("must assign to char pointer or array");
    *dim = *dim - (litptr - value);
    if(ident==POINTER) point();
    }
  else if(constexpr(&value)) {
    if(ident==POINTER) error("cannot assign to pointer");
    stowlit(value, size);
    *dim = *dim - 1;
    }
  }

/*
** get required array size
*/
needsub()  {
  int val;
  if(match("]")) return 0; /* null size */
  if (constexpr(&val)==0) val=1;
  if (val<0) {
    error("negative size illegal");
    val = -val;
    }
  needtoken("]");      /* force single dimension */
  return val;	       /* and return size */
  }

/*
** begin a function
**
** called from "parse" and tries to make a function
** out of the following text
**
** Patched per P.L. Woods (DDJ #52)
*/
newfunc()  {
  char *ptr;
#ifdef STGOTO
  nogo	=	      /* enable goto statements */
  noloc = 0;	      /* enable block-local declarations */
#endif
  lastst=	      /* no statement yet */
  litptr=0;	      /* clear lit pool */
  litlab=getlabel();  /* label next lit pool */
  locptr=STARTLOC;    /* clear local variables */
  if(monitor) lout(line, stderr);
  if (symname(ssname, YES)==0) {
    error("illegal function or declaration");
    kill(); /* invalidate line */
    return;
    }
  if(ptr=findglb(ssname)) {	 /* already in symbol table ? */
    if(ptr[IDENT]!=FUNCTION)	   multidef(ssname);
    else if(ptr[OFFSET]==FUNCTION) multidef(ssname);
    else ptr[OFFSET]=FUNCTION;
      /*  earlier assumed to be a function */
    }
  else
    addsym(ssname, FUNCTION, CINT, FUNCTION, &glbptr, STATIC);
  if(match("(")==0) error("no open paren");
	csect();
  entry();
  locptr=STARTLOC;
  argstk=0;		  /* init arg count */
  while(match(")")==0) {  /* then count args */
    /* any legal name bumps arg count */
    if(symname(ssname, YES)) {
      if(findloc(ssname)) multidef(ssname);
      else {
	addsym(ssname, 0, 0, argstk, &locptr, AUTOMATIC);
	argstk=argstk+BPW;
	}
      }
    else {error("illegal argument name");junk();}
    blanks();
    /* if not closing paren, should be comma */
    if(streq(lptr,")")==0) {
      if(match(",")==0) error("no comma");
      }
    if(endst()) break;
    }
  csp=0;	/* preset stack ptr */
  argtop=argstk;
  while(argstk) {
    /* now let user declare what types of things */
    /*	    those arguments were */
    if(amatch("char",4))     {doargs(CCHAR);ns();}
    else if(amatch("int",3)) {doargs(CINT);ns();}
    else {error("wrong number of arguments");break;}
    }
  if(statement()!=STRETURN) ret();
  if(litptr) {
	dsect();
    printlabel(litlab);
    col();
    dumplits(1); /* dump literals */
    }
  }

/*
** declare argument types
**
** called from "newfunc" this routine adds an entry in the
** local symbol table for each named argument
**
** rewritten per P.L. Woods (DDJ #52)
*/
doargs(t) int t; {
  int j, legalname;
  char c, *argptr;
  while(1) {
    if(argstk==0) return; /* no arguments */
    if(match("*")) j=POINTER; else j=VARIABLE;
    if((legalname=symname(ssname, YES))==0) illname();
    if(match("[")) {   /* is it a pointer? */
      /* yes, so skip stuff between "[...]" */
      while(inbyte()!=']') if(endst()) break;
      j=POINTER; /* add entry as pointer */
      }
    if(legalname) {
      if(argptr=findloc(ssname)) {
	/* add details of type and address */
	argptr[IDENT]=j;
	argptr[TYPE]=t;
	putint(argtop-getint(argptr+OFFSET, OFFSIZE), argptr+OFFSET, OFFSIZE);
	}
      else error("not an argument");
      }
    argstk=argstk-BPW;	      /* cnt down */
    if(endst())return;
    if(match(",")==0) error("no comma");
    }
  }
%%%%%%%%%% scc/scc/13.c %%%%%%%%%%
/***
 *	fixes:
 *
 *	continue in switch (net.micro 1/27/83)
 */

#include "smallc.h"

/*
** statement parser
**
** called whenever syntax requires a statement
**  this routine performs that statement
**  and returns a number telling which one
*/
statement() {
  if ((ch==0) & (eof)) return;
  else if(amatch("char",4))  {declloc(CCHAR);ns();}
  else if(amatch("int",3))   {declloc(CINT);ns();}
  else {
    if(declared >= 0) {
#ifdef STGOTO
      if(ncmp > 1) nogo=declared; /* disable goto if any */
#endif
      csp=modstk(csp - declared, NO);
      declared = -1;
      }
    if(match("{"))		 compound();
    else if(amatch("if",2))	 {doif();lastst=STIF;}
    else if(amatch("while",5))	 {dowhile();lastst=STWHILE;}
#ifdef STDO
    else if(amatch("do",2))	 {dodo();lastst=STDO;}
#endif
#ifdef STFOR
    else if(amatch("for",3))	 {dofor();lastst=STFOR;}
#endif
#ifdef STSWITCH
    else if(amatch("switch",6))	 {doswitch();lastst=STSWITCH;}
    else if(amatch("case",4))	 {docase();lastst=STCASE;}
    else if(amatch("default",7)) {dodefault();lastst=STDEF;}
#endif
#ifdef STGOTO
    else if(amatch("goto", 4))	 {dogoto(); lastst=STGOTO;}
    else if(dolabel())		 ;
#endif
    else if(amatch("return",6))	 {doreturn();ns();lastst=STRETURN;}
    else if(amatch("break",5))	 {dobreak();ns();lastst=STBREAK;}
    else if(amatch("continue",8)){docont();ns();lastst=STCONT;}
    else if(match(";"))		 errflag=0;
    else if(match("#asm"))	 {doasm();lastst=STASM;}
    else			 {doexpr();ns();lastst=STEXPR;}
    }
  return lastst;
  }

/*
** semicolon enforcer
**
** called whenever syntax requires a semicolon
*/
ns()  {
  if(match(";")==0) error("no semicolon");
  else errflag=0;
  }

compound()  {
  int savcsp;
  char *savloc;
  savcsp=csp;
  savloc=locptr;
  declared=0;	 /* may now declare local variables */
  ++ncmp;	 /* new level open */
  while (match("}")==0)
    if(eof) {
      error("no final }");
      break;
      }
    else statement();	  /* do one */
  --ncmp;		  /* close current level */
  csp=modstk(savcsp, NO); /* delete local variable space */
#ifdef STGOTO
  cptr=savloc;		  /* retain labels */
  while(cptr < locptr) {
    cptr2=nextsym(cptr);
    if(cptr[IDENT] == LABEL) {
      while(cptr < cptr2) *savloc++ = *cptr++;
      }
    else cptr=cptr2;
    }
#endif
  locptr=savloc;	  /* delete local symbols */
  declared = -1;	  /* may not declare variables */
  }

doif()	{
  int flab1,flab2;
  flab1=getlabel(); /* get label for false branch */
  test(flab1, YES); /* get expression, and branch false */
  statement();	    /* if true, do a statement */
  if (amatch("else",4)==0) {	  /* if...else ? */
    /* simple "if"...print false label */
    postlabel(flab1);
    return;	    /* and exit */
    }
  flab2=getlabel();
#ifdef STGOTO
  if((lastst != STRETURN)&(lastst != STGOTO)) jump(flab2);
#else
  if(lastst != STRETURN) jump(flab2);
#endif
  postlabel(flab1); /* print false label */
  statement();	    /* and do "else" clause */
  postlabel(flab2); /* print true label */
  }

doexpr() {
  int const, val;
  char *before, *start;
  while(1) {
    setstage(&before, &start);
    expression(&const, &val);
    clearstage(before, start);
    if(ch != ',') break;
    bump(1);
    }
  }

dowhile()  {
  int wq[4];		  /* allocate local queue */
  addwhile(wq);		  /* add entry to queue for "break" */
  postlabel(wq[WQLOOP]);  /* loop label */
  test(wq[WQEXIT], YES);  /* see if true */
  statement();		  /* if so, do a statement */
  jump(wq[WQLOOP]);	  /* loop to label */
  postlabel(wq[WQEXIT]);  /* exit label */
  delwhile();		  /* delete queue entry */
  }

#ifdef STDO
dodo() {
  int wq[4], top;
  addwhile(wq);
  postlabel(top=getlabel());
  statement();
  needtoken("while");
  postlabel(wq[WQLOOP]);
  test(wq[WQEXIT], YES);
  jump(top);
  postlabel(wq[WQEXIT]);
  delwhile();
  ns();
  }
#endif

#ifdef STFOR
dofor() {
  int wq[4], lab1, lab2;
  addwhile(wq);
  lab1=getlabel();
  lab2=getlabel();
  needtoken("(");
  if(match(";")==0) {
    doexpr();		 /* expr 1 */
    ns();
    }
  postlabel(lab1);
  if(match(";")==0) {
    test(wq[WQEXIT], NO); /* expr 2 */
    ns();
    }
  jump(lab2);
  postlabel(wq[WQLOOP]);
  if(match(")")==0) {
    doexpr();		 /* expr 3 */
    needtoken(")");
    }
  jump(lab1);
  postlabel(lab2);
  statement();
  jump(wq[WQLOOP]);
  postlabel(wq[WQEXIT]);
  delwhile();
  }
#endif

#ifdef STSWITCH
doswitch() {
  int wq[4], endlab, swact, swdef, *swnex, *swptr;
  swact=swactive;
  swdef=swdefault;
  swnex=swptr=swnext;
  addwhile(wq);
	*(wqptr+WQLOOP-WQSIZ) = 0;
  needtoken("(");
  doexpr();	 /* evaluate switch expression */
  needtoken(")");
  swdefault=0;
  swactive=1;
  jump(endlab=getlabel());
  statement();	 /* cases, etc. */
  jump(wq[WQEXIT]);
  postlabel(endlab);
  sw();		 /* match cases */
  while(swptr < swnext) {
    defstorage(CINT>>2);
    printlabel(*swptr++);  /* case label */
    outbyte(',');
    outdec(*swptr++);	   /* case value */
    nl();
    }
  defstorage(CINT>>2);
  outdec(0);
  nl();
  if(swdefault) jump(swdefault);
  postlabel(wq[WQEXIT]);
  delwhile();
  swnext=swnex;
  swdefault=swdef;
  swactive=swact;
  }

docase() {
  if(swactive==0) error("not in switch");
  if(swnext > swend) {
    error("too many cases");
    return;
    }
  postlabel(*swnext++ = getlabel());
  constexpr(swnext++);
  needtoken(":");
  }

dodefault() {
  if(swactive) {
    if(swdefault) error("multiple defaults");
    }
  else error("not in switch");
  needtoken(":");
  postlabel(swdefault=getlabel());
  }
#endif

#ifdef STGOTO
dogoto() {
  if(nogo > 0) error("not allowed with block-locals");
  else noloc = 1;
  if(symname(ssname, YES)) jump(addlabel());
  else error("bad label");
  ns();
  }

dolabel() {
  char *savelptr;
  blanks();
  savelptr=lptr;
  if(symname(ssname, YES)) {
    if(gch()==':') {
      postlabel(addlabel());
      return 1;
      }
    else bump(savelptr-lptr);
    }
  return 0;
  }

addlabel()  {
  if(cptr=findloc(ssname)) {
    if(cptr[IDENT]!=LABEL) error("not a label");
    }
  else cptr=addsym(ssname, LABEL, LABEL, getlabel(), &locptr, LABEL);
  return (getint(cptr+OFFSET, OFFSIZE));
  }
#endif

doreturn()  {
  if(endst()==0) {
    doexpr();
    modstk(0, YES);
    }
  else modstk(0, NO);
  ret();
  }

dobreak()  {
  int *ptr;
  if ((ptr=readwhile(wqptr))==0) return; /* no loops open */
  modstk((ptr[WQSP]), NO);	    /* clean up stk ptr */
  jump(ptr[WQEXIT]);		    /* jump to exit label */
  }

docont()  {
  int *ptr;
	ptr = wqptr;
	while (1)
	{	if ((ptr = readwhile(ptr)) == 0)
			return;
		if (ptr[WQLOOP])
			break;
	}
  modstk((ptr[WQSP]), NO);	    /* clean up stk ptr */
  jump(ptr[WQLOOP]);		    /* jump to loop label */
  }

doasm()	 {
  ccode=0;		  /* mark mode as "asm" */
  while (1) {
    inline();
    if (match("#endasm")) break;
    if(eof)break;
    lout(line, output);
    }
  kill();
  ccode=1;
  }
%%%%%%%%%% scc/scc/21.c %%%%%%%%%%
/***
 *	fixes:
 *
 *	= *	not =*
 *	internal labels start with "."
 *	it is needed in ask()
 */

#include "smallc.h"

junk() {
  if(an(inbyte())) while(an(ch)) gch();
  else while(an(ch)==0) {
    if(ch==0) break;
    gch();
    }
  blanks();
  }

endst() {
  blanks();
  return ((streq(lptr,";")|(ch==0)));
  }

illname() {
  error("illegal symbol");
  junk();
  }


multidef(sname)	 char *sname; {
  error("already defined");
  }

needtoken(str)	char *str; {
  if (match(str)==0) error("missing token");
  }

needlval() {
  error("must be lvalue");
  }

findglb(sname)	char *sname; {
#ifdef HASH
  if(search(sname, STARTGLB, SYMMAX, ENDGLB, NUMGLBS, NAME))
    return cptr;
#else
  cptr=STARTGLB;
  while(cptr < glbptr) {
    if(astreq(sname, cptr+NAME, NAMEMAX)) return cptr;
    cptr=nextsym(cptr);
    }
#endif
  return 0;
  }

findloc(sname)	char *sname;  {
  cptr = locptr - 1;  /* search backward for block locals */
  while(cptr > STARTLOC) {
    cptr = cptr - *cptr;
    if(astreq(sname, cptr, NAMEMAX)) return (cptr - NAME);
    cptr = cptr - NAME - 1;
    }
  return 0;
  }

addsym(sname, id, typ, value, lgptrptr, class)
  char *sname, id, typ;	 int value, *lgptrptr, class; {
  if(lgptrptr == &glbptr) {
    if(cptr2=findglb(sname)) return cptr2;
#ifdef HASH
    if(cptr==0) {
      error("global symbol table overflow");
      return 0;
      }
#else
#ifndef DYNAMIC
    if(glbptr >= ENDGLB) {
      error("global symbol table overflow");
      return 0;
      }
#endif
    cptr= *lgptrptr;	/*** */
#endif
    }
  else {
    if(locptr > (ENDLOC-SYMMAX)) {
      error("local symbol table overflow");
      abort();
      }
    cptr= *lgptrptr;	/*** */
    }
  cptr[IDENT]=id;
  cptr[TYPE]=typ;
  cptr[CLASS]=class;
  putint(value, cptr+OFFSET, OFFSIZE);
  cptr3 = cptr2 = cptr + NAME;
  while(an(*sname)) *cptr2++ = *sname++;
#ifdef HASH
  if(lgptrptr == &locptr) {
    *cptr2 = cptr2 - cptr3;	    /* set length */
    *lgptrptr = ++cptr2;
    }
#else
  *cptr2 = cptr2 - cptr3;	  /* set length */
  *lgptrptr = ++cptr2;
#ifdef DYNAMIC
  if(lgptrptr == &glbptr) CCALLOC(cptr2 - cptr);
  /*  gets allocation error if no more memory  */
#endif
#endif
  return cptr;
  }

#ifndef HASH
nextsym(entry) char *entry; {
  entry = entry + NAME;
  while(*entry++ >= ' '); /* find length byte */
  return entry;
  }
#endif

/*
** get integer of length len from address addr
** (byte sequence set by "putint")
*/
getint(addr, len) char *addr; int len; {
  int i;
  i = *(addr + --len);	/* high order byte sign extended */
  while(len--) i = (i << 8) | *(addr+len)&255;
  return i;
  }

/*
** put integer i of length len into address addr
** (low byte first)
*/
putint(i, addr, len) char *addr; int i, len; {
  while(len--) {
    *addr++ = i;
    i = i>>8;
    }
  }

/*
** test if next input string is legal symbol name
*/
symname(sname, ucase) char *sname; int ucase; {
  int k;char c;
  blanks();
  if(alpha(ch)==0) return 0;
  k=0;
  while(an(ch)) {
      sname[k]=gch();
    if(k<NAMEMAX) ++k;
    }
  sname[k]=0;
  return 1;
  }

/*
** force upper case alphabetics
*/
upper(c)  char c; {	/*** */
  if((c >= 'a') & (c <= 'z')) return (c - 32);
  else return c;
  }

/*
** return next avail internal label number
*/
getlabel() {
  return(++nxtlab);
  }

/*
** post a label in the program
*/
postlabel(label) int label; {
  printlabel(label);
  col();
  nl();
  }

/*
** print specified number as a label
*/
printlabel(label)  int label; {
  outstr(".");
  outdec(label);
  }

/*
** test if given character is alphabetic
*/
alpha(c)  char c; {
  return (((c>='a')&(c<='z'))|((c>='A')&(c<='Z'))|(c=='_'));
  }

/*
** test if given character is numeric
*/
numeric(c)  char c; {
  return((c>='0')&(c<='9'));
  }

/*
** test if given character is alphanumeric
*/
an(c)  char c; {
  return ((alpha(c))|(numeric(c)));
  }

addwhile(ptr)  int ptr[]; {
  int k;
  ptr[WQSP]=csp;	   /* and stk ptr */
  ptr[WQLOOP]=getlabel();  /* and looping label */
  ptr[WQEXIT]=getlabel();   /* and exit label */
  if (wqptr==WQMAX) {
    error("too many active loops");
    abort();
    }
  k=0;
  while (k<WQSIZ) *wqptr++ = ptr[k++];
  }

delwhile() {
  if(wqptr > wq) wqptr=wqptr-WQSIZ;
  }

readwhile(ptr)
	int *ptr;
{
	if (ptr <= wq)
	{	error("out of context");
		return 0;
	}
	return (ptr-WQSIZ);
}

white() {
  /* test for stack/program overlap */
  /* primary -> symname -> blanks -> white */
#ifdef DYNAMIC
  CCAVAIL();  /* abort on stack/symbol table overflow */
#endif
  if(*lptr==' ') return 1;
  if(*lptr==9)	 return 1;
  return 0;
  }

gch() {
  int c;
  if(c=ch) bump(1);
  return c;
  }

bump(n) int n; {
  if(n) lptr=lptr+n;
  else	lptr=line;
  if(ch=nch= *lptr) nch= *(lptr+1);	/*** */
  }

kill() {
  *line=0;
  bump(0);
  }

inbyte()  {
  while(ch==0) {
    if (eof) return 0;
    preprocess();
    }
  return gch();
  }

inline() {
  int k,unit;
  while(1) {
    if (input==EOF) openin();
    if(eof) return;
    if((unit=input2)==EOF) unit=input;
    if(fgets(line, LINEMAX, unit)==NULL) {
      fclose(unit);
      if(input2!=EOF) input2=EOF;
      else input=EOF;
      }
    else {
      bump(0);
      return;
      }
    }
  }
%%%%%%%%%% scc/scc/22.c %%%%%%%%%%
/***
 *	fixes:
 *
 *	= *	not =*
 */

#include "smallc.h"

ifline() {
  while(1) {
    inline();
    if(eof) return;
    if(match("#ifdef")) {
      ++iflevel;
      if(skiplevel) continue;
      blanks();
#ifdef HASH
      if(search(lptr, macn, NAMESIZE+2, MACNEND, MACNBR, 0)==0)
#else
      if(findmac(lptr)==0)
#endif
	skiplevel=iflevel;
      continue;
      }
    if(match("#ifndef")) {
      ++iflevel;
      if(skiplevel) continue;
      blanks();
#ifdef HASH
      if(search(lptr, macn, NAMESIZE+2, MACNEND, MACNBR, 0))
#else
      if(findmac(lptr))
#endif
	skiplevel=iflevel;
      continue;
      }
    if(match("#else")) {
      if(iflevel) {
	if(skiplevel==iflevel) skiplevel=0;
	else if(skiplevel==0)  skiplevel=iflevel;
	}
      else noiferr();
      continue;
      }
    if(match("#endif")) {
      if(iflevel) {
	if(skiplevel==iflevel) skiplevel=0;
	--iflevel;
	}
      else noiferr();
      continue;
      }
    if(skiplevel) continue;
    if(listfp) {
      if(listfp==output) cout(';', output);
      lout(line, listfp);
      }
    if(ch==0) continue;
    break;
    }
  }

keepch(c)  char c; {
  if(pptr<LINEMAX) pline[++pptr]=c;
  }

preprocess() {
  int k;
  char c;
  if(ccode) {
    line=mline;
    ifline();
    if(eof) return;
    }
  else {
    line=pline;
    inline();
    return;
    }
  pptr = -1;
  while(ch) {
    if(white()) {
      keepch(' ');
      while(white()) gch();
      }
    else if(ch=='"') {
      keepch(ch);
      gch();
      while((ch!='"')|((*(lptr-1)==92)&(*(lptr-2)!=92))) {
	if(ch==0) {
	  error("no quote");
	  break;
	  }
	keepch(gch());
	}
      gch();
      keepch('"');
      }
    else if(ch==39) {
      keepch(39);
      gch();
      while((ch!=39)|((*(lptr-1)==92)&(*(lptr-2)!=92))) {
	if(ch==0) {
	  error("no apostrophe");
	  break;
	  }
	keepch(gch());
	}
      gch();
      keepch(39);
      }
    else if((ch=='/')&(nch=='*')) {
      bump(2);
      while(((ch=='*')&(nch=='/'))==0) {
	if(ch) bump(1);
	else {
	  ifline();
	  if(eof) break;
	  }
	}
      bump(2);
      }
    else if(an(ch)) {
      k=0;
      while(an(ch)) {
	if(k<NAMEMAX) msname[k++]=ch;
	gch();
	}
      msname[k]=0;
#ifdef HASH
      if(search(msname, macn, NAMESIZE+2, MACNEND, MACNBR, 0)) {
	k=getint(cptr+NAMESIZE, 2);
	while(c=macq[k++]) keepch(c);
	}
#else
      if(k=findmac(msname)) while(c=macq[k++]) keepch(c);
#endif
      else {
	k=0;
	while(c=msname[k++]) keepch(c);
	}
      }
    else keepch(gch());
    }
  if(pptr>=LINEMAX) error("line too long");
  keepch(0);
  line=pline;
  bump(0);
  }

noiferr() {
  error("no matching #if...");
  errflag=0;
  }

addmac() {
  int k;
  if(symname(msname, NO)==0) {
    illname();
    kill();
    return;
    }
  k=0;
#ifdef HASH
  if(search(msname, macn, NAMESIZE+2, MACNEND, MACNBR, 0)==0) {
    if(cptr2=cptr) while(*cptr2++ = msname[k++]);
    else {
      error("macro name table full");
      return;
      }
    }
  putint(macptr, cptr+NAMESIZE, 2);
#else
  while(putmac(msname[k++]));
#endif
  while(white()) gch();
  while(putmac(gch()));
  if(macptr>=MACMAX) {
    error("macro string queue full"); abort();
    }
  }

putmac(c)  char c; {
  macq[macptr]=c;
  if(macptr<MACMAX) ++macptr;
  return c;
  }

#ifdef HASH
/*
** search for symbol match
** on return cptr points to slot found or empty slot
*/
search(sname, buf, len, end, max, off)
  char *sname, *buf, *end;  int len, max, off; {
  cptr=cptr2=buf+((hash(sname)%(max-1))*len);
  while(*cptr != 0) {
    if(astreq(sname, cptr+off, NAMEMAX)) return 1;
    if((cptr=cptr+len) >= end) cptr=buf;
    if(cptr == cptr2) return (cptr=0);
    }
  return 0;
  }

hash(sname) char *sname; {
  int i, c;
  i=0;
  while(c= *sname++) i=(i<<1)+c;	/*** */
  return i;
  }

#else

findmac(sname)	char *sname; {
  mack=0;
  while(mack<macptr) {
    if(astreq(sname,macq+mack,NAMEMAX)) {
      while(macq[mack++]);
      return mack;
      }
    while(macq[mack++]);
    while(macq[mack++]);
    }
  return 0;
  }
#endif

setstage(before, start) int *before, *start; {
  if((*before=stagenext)==0) stagenext=stage;
  *start=stagenext;
  }

clearstage(before, start) char *before, *start; {
  *stagenext=0;
  if(stagenext=before) return;
  if(start) {
    peephole(start);
    }
  }

outdec(number)	int number; {
  int k,zs;
  char c;
  zs = 0;
  k=10000;
  if (number<0) {
    number=(-number);
    outbyte('-');
    }
  while (k>=1) {
    c=number/k + '0';
    if ((c!='0')|(k==1)|(zs)) {
      zs=1;
      outbyte(c);
      }
    number=number%k;
    k=k/10;
    }
  }

ol(ptr)	 char ptr[];  {
  ot(ptr);
  nl();
  }

ot(ptr) char ptr[]; {
  tab();
  outstr(ptr);
  }

outstr(ptr) char ptr[]; {
  /* must work with symbol table names terminated by length */
  while(*ptr >= ' ') outbyte(*ptr++);
  }

outbyte(c) char c; {
  if(stagenext) {
    if(stagenext==stagelast) {
      error("staging buffer overflow");
      return 0;
      }
    else *stagenext++ = c;
    }
  else cout(c,output);
  return c;
  }

cout(c, fd) char c; int fd; {
  if(fputc(c, fd)==EOF) xout();
  }

sout(string, fd) char *string; int fd; {
  if(fputs(string, fd)==EOF) xout();
  }

lout(line, fd) char *line; int fd; {
  sout(line, fd);
  cout('\n', fd);
  }

xout() {
  fputs("output error\n", stderr);
  abort();
  }

nl() {
  outbyte('\n');
  }

tab() {
  outbyte('\t');
  }

col() {
  outbyte(':');
  }

error(msg) char msg[]; {
  if(errflag) return; else errflag=1;
  lout(line, stderr);
  errout(msg, stderr);
  if(alarm) fputc(7, stderr);
  if(pause) while(fgetc(stderr)!='\n');
  if(listfp>0) errout(msg, listfp);
  }

errout(msg, fp) char msg[]; int fp; {
  int k; k=line+2;
  while(k++ <= lptr) cout(' ', fp);
  lout("/\\", fp);
  sout("**** ", fp); lout(msg, fp);
  }

streq(str1,str2)  char str1[],str2[]; {
  int k;
  k=0;
  while (str2[k]) {
    if ((str1[k])!=(str2[k])) return 0;
    ++k;
    }
  return k;
 }

astreq(str1,str2,len)  char str1[],str2[];int len; {
  int k;
  k=0;
  while (k<len) {
    if ((str1[k])!=(str2[k]))break;
    /*
    ** must detect end of symbol table names terminated by
    ** symbol length in binary
    */
    if(str1[k] < ' ') break;
    if(str2[k] < ' ') break;
    ++k;
    }
  if (an(str1[k]))return 0;
  if (an(str2[k]))return 0;
  return k;
 }

match(lit)  char *lit; {
  int k;
  blanks();
  if (k=streq(lptr,lit)) {
    bump(k);
    return 1;
    }
  return 0;
  }

amatch(lit,len)	 char *lit;int len; {
  int k;
  blanks();
  if (k=astreq(lptr,lit,len)) {
    bump(k);
    while(an(ch)) inbyte();
    return 1;
    }
  return 0;
 }

nextop(list) char *list; {
  char op[4];
  opindex=0;
  blanks();
  while(1) {
    opsize=0;
    while(*list > ' ') op[opsize++]= *list++;	/*** */
    op[opsize]=0;
    if(opsize=streq(lptr, op))
      if((*(lptr+opsize) != '=')&
	 (*(lptr+opsize) != *(lptr+opsize-1)))
	 return 1;
    if(*list) {
      ++list;
      ++opindex;
      }
    else return 0;
    }
  }

blanks() {
  while(1) {
    while(ch) {
      if(white()) gch();
      else return;
      }
    if(line==mline) return;
    preprocess();
    if(eof)break;
    }
  }
%%%%%%%%%% scc/scc/31.c %%%%%%%%%%
/***
 *	fixes:
 *
 *	testfunc	int (*) ()	not int
 *	oper		int (*) ()	not int
 *	oper2		int (*) ()	not int
 *	heir		int (*) ()	not int
 *	needs external references to heir*()
 *	plung1	not plunge1	(M80 is stupid!!)
 *	plung2	not plunge2
 */

#include "smallc.h"

/*
** lval[0] - symbol table address, else 0 for constant
** lval[1] - type of indirect obj to fetch, else 0 for static
** lval[2] - type of pointer or array, else 0 for all other
** lval[3] - true if constant expression
** lval[4] - value of constant expression
** lval[5] - true if secondary register altered
** lval[6] - function address of highest/last binary operator
** lval[7] - stage address of "oper 0" code, else 0
*/

/*
** skim over terms adjoining || and && operators
*/
skim(opstr, testfunc, dropval, endval, heir, lval)
  char *opstr;
  int (*testfunc)(), dropval, endval, (*heir)(), lval[]; {	/*** */
  int k, hits, droplab, endlab;
  hits=0;
  while(1) {
    k=plung1(heir, lval);
    if(nextop(opstr)) {
      bump(opsize);
      if(hits==0) {
	hits=1;
	droplab=getlabel();
	}
      dropout(k, testfunc, droplab, lval);
      }
    else if(hits) {
      dropout(k, testfunc, droplab, lval);
      const(endval);
      jump(endlab=getlabel());
      postlabel(droplab);
      const(dropval);
      postlabel(endlab);
      lval[1]=lval[2]=lval[3]=lval[7]=0;
      return 0;
      }
    else return k;
    }
  }

/*
** test for early dropout from || or && evaluations
*/
dropout(k, testfunc, exit1, lval)
	int k, (*testfunc)(), exit1, lval[]; {	/*** */
  if(k) rvalue(lval);
  else if(lval[3]) const(lval[4]);
  (*testfunc)(exit1); /* jumps on false */	/*** */
  }

/*
** plunge to a lower level
*/
plunge(opstr, opoff, heir, lval)
  char *opstr;
  int opoff, (*heir)(), lval[]; {	/*** */
  int k, lval2[8];
  k=plung1(heir, lval);
  if(nextop(opstr)==0) return k;
  if(k) rvalue(lval);
  while(1) {
    if(nextop(opstr)) {
      bump(opsize);
      opindex=opindex+opoff;
      plung2(op[opindex], op2[opindex], heir, lval, lval2);
      }
    else return 0;
    }
  }

/*
** unary plunge to lower level
*/
plung1(heir, lval)
	int (*heir)(), lval[]; {	/*** */
  char *before, *start;
  int k;
  setstage(&before, &start);
  k=(*heir)(lval);
  if(lval[3]) clearstage(before,0); /* load constant later */
  return k;
  }

/*
** binary plunge to lower level
*/
plung2(oper, oper2, heir, lval, lval2)
  int (*oper)(), (*oper2)(), (*heir)(), lval[], lval2[]; {	/*** */
  char *before, *start;
  setstage(&before, &start);
  lval[5]=1;	      /* flag secondary register used */
  lval[7]=0;	      /* flag as not "... oper 0" syntax */
  if(lval[3]) {	      /* constant on left side not yet loaded */
    if(plung1(heir, lval2)) rvalue(lval2);
    if(lval[4]==0) lval[7]=stagenext;
    const2(lval[4]<<dbltest(lval2, lval));
    }
  else {	      /* non-constant on left side */
    push();
    if(plung1(heir, lval2)) rvalue(lval2);
    if(lval2[3]) {    /* constant on right side */
      if(lval2[4]==0) lval[7]=start;
      if(oper==add) { /* may test other commutative operators */
	csp=csp+2;
	clearstage(before, 0);
	const2(lval2[4]<<dbltest(lval, lval2));	  /* load secondary */
	}
      else {
	const(lval2[4]<<dbltest(lval, lval2));	  /* load primary */
	smartpop(lval2, start);
	}
      }
    else {	      /* non-constants on both sides */
      smartpop(lval2, start);
      if((oper==add)|(oper==sub)) {
	if(dbltest(lval,lval2)) doublereg();
	if(dbltest(lval2,lval)) {
	  swap();
	  doublereg();
	  if(oper==sub) swap();
	  }
	}
      }
    }
  if(oper) {
    if(lval[3]=lval[3]&lval2[3]) {
      lval[4]=calc(lval[4], oper, lval2[4]);
      clearstage(before, 0);
      lval[5]=0;
      }
    else {
      if((lval[2]==0)&(lval2[2]==0)) {
	(*oper)();	/*** */
	lval[6]=oper;	/* identify the operator */
	}
      else {
	(*oper2)();	/*** */
	lval[6]=oper2;	/* identify the operator */
	}
      }
    if(oper==sub) {
      if((lval[2]==CINT)&(lval2[2]==CINT)) {
	swap();
	const(1);
	asr();	/** div by 2 **/
	}
      }
    if((oper==sub)|(oper==add)) result(lval, lval2);
    }
  }

calc(left, oper, right)
	int left, (*oper)(), right; {	/*** */
       if(oper ==  or) return (left  |	right);
  else if(oper == xor) return (left  ^	right);
  else if(oper == and) return (left  &	right);
  else if(oper ==  eq) return (left  == right);
  else if(oper ==  ne) return (left  != right);
  else if(oper ==  le) return (left  <= right);
  else if(oper ==  ge) return (left  >= right);
  else if(oper ==  lt) return (left  <	right);
  else if(oper ==  gt) return (left  >	right);
  else if(oper == asr) return (left  >> right);
  else if(oper == asl) return (left  << right);
  else if(oper == add) return (left  +	right);
  else if(oper == sub) return (left  -	right);
  else if(oper ==mult) return (left  *	right);
  else if(oper == div) return (left  /	right);
  else if(oper == mod) return (left  %	right);
  else return 0;
  }

expression(const, val) int *const, *val;  {
  int lval[8];
  if(heir1(lval)) rvalue(lval);
  if(lval[3]) {
    *const=1;
    *val=lval[4];
    }
  else *const=0;
  }

heir1(lval)  int lval[];  {
  int k,lval2[8], (*oper)();	/*** */
  k=plung1(heir3, lval);
  if(lval[3]) const(lval[4]);
       if(match("|="))	oper=or;
  else if(match("^="))	oper=xor;
  else if(match("&="))	oper=and;
  else if(match("+="))	oper=add;
  else if(match("-="))	oper=sub;
  else if(match("*="))	oper=mult;
  else if(match("/="))	oper=div;
  else if(match("%="))	oper=mod;
  else if(match(">>=")) oper=asr;
  else if(match("<<=")) oper=asl;
  else if(match("="))	oper=0;
  else return k;
  if(k==0) {
    needlval();
    return 0;
    }
  if(lval[1]) {
    if(oper) {
      push();
      rvalue(lval);
      }
    plung2(oper, oper, heir1, lval, lval2);
    if(oper) pop();
    }
  else {
    if(oper) {
      rvalue(lval);
      plung2(oper, oper, heir1, lval, lval2);
      }
    else {
      if(heir1(lval2)) rvalue(lval2);
      lval[5]=lval2[5];
      }
    }
  store(lval);
  return 0;
  }

heir3(lval)  int lval[]; {
  return skim("||", eq0, 1, 0, heir4, lval);
  }

heir4(lval)  int lval[]; {
  return skim("&&", ne0, 0, 1, heir5, lval);
  }

heir5(lval)  int lval[]; {
  return plunge("|", 0, heir6, lval);
  }

heir6(lval)  int lval[]; {
  return plunge("^", 1, heir7, lval);
  }

heir7(lval)  int lval[]; {
  return plunge("&", 2, heir8, lval);
  }

heir8(lval)  int lval[];  {
  return plunge("== !=", 3, heir9, lval);
  }

heir9(lval)  int lval[];  {
  return plunge("<= >= < >", 5, heir10, lval);
  }

heir10(lval)  int lval[];  {
  return plunge(">> <<", 9, heir11, lval);
  }

heir11(lval)  int lval[];  {
  return plunge("+ -", 11, heir12, lval);
  }

heir12(lval)  int lval[];  {
  return plunge("* / %", 13, heir13, lval);
  }
%%%%%%%%%% scc/scc/32.c %%%%%%%%%%
/***
 *	fixes:
 *
 *	plung2	not plunge2
 *	adapt callfunction(_narg) to MACRO-80 CP/M RTL
 */

#include "smallc.h"

heir13(lval)  int lval[];  {
  int k;
  char *ptr;
  if(match("++")) {		      /* ++lval */
    if(heir13(lval)==0) {
      needlval();
      return 0;
      }
    step(inc, lval);
    return 0;
    }
  else if(match("--")) {	      /* --lval */
    if(heir13(lval)==0) {
      needlval();
      return 0;
      }
    step(dec, lval);
    return 0;
    }
  else if (match("~")) {	      /* ~ */
    if(heir13(lval)) rvalue(lval);
    com();
    lval[4] = ~lval[4];
    return 0;
    }
  else if (match("!")) {	      /* ! */
    if(heir13(lval)) rvalue(lval);
    lneg();
    lval[4] = !lval[4];
    return 0;
    }
  else if (match("-")) {	      /* unary - */
    if(heir13(lval)) rvalue(lval);
    neg();
    lval[4] = -lval[4];
    return 0;
    }
  else if(match("*")) {		      /* unary * */
    if(heir13(lval)) rvalue(lval);
    if(ptr=lval[0])lval[1]=ptr[TYPE];
    else lval[1]=CINT;
    lval[2]=0;	/* flag as not pointer or array */
    lval[3]=0;	/* flag as not constant */
    return 1;
    }
  else if(match("&")) {		      /* unary & */
    if(heir13(lval)==0) {
      error("illegal address");
      return 0;
      }
    ptr=lval[0];
    lval[2]=ptr[TYPE];
    if(lval[1]) return 0;
    /* global & non-array */
    address(ptr);
    lval[1]=ptr[TYPE];
    return 0;
    }
  else {
    k=heir14(lval);
    if(match("++")) {		      /* lval++ */
      if(k==0) {
	needlval();
	return 0;
	}
      step(inc, lval);
      dec(lval[2]>>2);
      return 0;
      }
    else if(match("--")) {	      /* lval-- */
      if(k==0) {
	needlval();
	return 0;
	}
      step(dec, lval);
      inc(lval[2]>>2);
      return 0;
      }
    else return k;
    }
  }

heir14(lval)  int *lval; {
  int k, const, val, lval2[8];
  char *ptr, *before, *start;
  k=primary(lval);
  ptr=lval[0];
  blanks();
  if((ch=='[')|(ch=='(')) {
    lval[5]=1;	  /* secondary register will be used */
    while(1) {
      if(match("[")) {		      /* [subscript] */
	if(ptr==0) {
	  error("can't subscript");
	  junk();
	  needtoken("]");
	  return 0;
	  }
	else if(ptr[IDENT]==POINTER)rvalue(lval);
	else if(ptr[IDENT]!=ARRAY) {
	  error("can't subscript");
	  k=0;
	  }
	setstage(&before, &start);
	lval2[3]=0;
	plung2(0, 0, heir1, lval2, lval2); /* lval2 deadend */
	needtoken("]");
	if(lval2[3]) {
	  clearstage(before, 0);
	  if(lval2[4]) {
	    if(ptr[TYPE]==CINT) const2(lval2[4]<<LBPW);
	    else		const2(lval2[4]);
	    add();
	    }
	  }
	else {
	  if(ptr[TYPE]==CINT) doublereg();
	  add();
	  }
	lval[0]=lval[2]=0;
	lval[1]=ptr[TYPE];
	k=1;
	}
      else if(match("(")) {	      /* function(...) */
	if (ptr==0) callfunction(0);
	else if (ptr[IDENT]!=FUNCTION) {
	  rvalue(lval);
	  callfunction(0);
	  }
	else callfunction(ptr);
	k=lval[0]=lval[3]=0;
	}
      else return k;
      }
    }
  if(ptr==0) return k;
  if(ptr[IDENT]==FUNCTION) {
    address(ptr);
    return 0;
    }
  return k;
  }

primary(lval)  int *lval; {
  char *ptr;
  int k;
  if(match("(")) {		      /* (expression) */
    k=heir1(lval);
    needtoken(")");
    return k;
    }
  putint(0, lval, 8<<LBPW); /* clear lval array */
  if(symname(ssname, YES)) {
    if(ptr=findloc(ssname)) {
#ifdef STGOTO
      if(ptr[IDENT]==LABEL) {
	experr();
	return 0;
	}
#endif
      getloc(ptr);
      lval[0]=ptr;
      lval[1]=ptr[TYPE];
      if(ptr[IDENT]==POINTER) {
	lval[1]=CINT;
	lval[2]=ptr[TYPE];
	}
      if(ptr[IDENT]==ARRAY) {
	lval[2]=ptr[TYPE];
	return 0;
	}
      else return 1;
      }
    if(ptr=findglb(ssname))
      if(ptr[IDENT]!=FUNCTION) {
	lval[0]=ptr;
	lval[1]=0;
	if(ptr[IDENT]!=ARRAY) {
	  if(ptr[IDENT]==POINTER) lval[2]=ptr[TYPE];
	  return 1;
	  }
	address(ptr);
	lval[1]=lval[2]=ptr[TYPE];
	return 0;
	}
    ptr=addsym(ssname, FUNCTION, CINT, 0, &glbptr, STATIC);
    lval[0]=ptr;
    lval[1]=0;
    return 0;
    }
  if(constant(lval)==0) experr();
  return 0;
  }

experr() {
  error("invalid expression");
  const(0);
  junk();
  }

callfunction(ptr)  char *ptr; { /* symbol table entry or 0 */
  int nargs, const, val;
  nargs=0;
  blanks();		  /* already saw open paren */
  if(ptr==0) push();	  /* calling HL */
  while(streq(lptr,")")==0) {
    if(endst()) break;
    expression(&const, &val);
    if(ptr==0) swapstk(); /* don't push addr */
    push();		  /* push argument */
    nargs=nargs+BPW;	  /* count args*BPW */
    if (match(",")==0) break;
    }
  needtoken(")");
	if (! streq(ptr+NAME, "_narg"))
		loadargc(nargs >> LBPW);
	if (ptr)
		call(ptr+NAME);
  else callstk();
  csp=modstk(csp+nargs, YES);
  }
%%%%%%%%%% scc/scc/33.c %%%%%%%%%%
/***
 *	fixes:
 *
 *	oper	int (*) ()	not int
 *	correct escape sequences in strings
 */

#include "smallc.h"

/*
** true if val1 -> int pointer or int array and val2 not ptr or array
*/
dbltest(val1,val2) int val1[], val2[]; {
  if(val1[2]!=CINT) return 0;
  if(val2[2]) return 0;
  return 1;
  }

/*
** determine type of binary operation
*/
result(lval, lval2) int lval[], lval2[]; {
  if((lval[2]!=0)&(lval2[2]!=0)) {
    lval[2]=0;
    }
  else if(lval2[2]) {
    lval[0]=lval2[0];
    lval[1]=lval2[1];
    lval[2]=lval2[2];
    }
  }

step(oper, lval)
	int (*oper)(), lval[]; {	/*** */
  if(lval[1]) {
    if(lval[5]) {
      push();
      rvalue(lval);
      (*oper)(lval[2]>>2);	/*** */
      pop();
      store(lval);
      return;
      }
    else {
      move();
      lval[5]=1;
      }
    }
  rvalue(lval);
  (*oper)(lval[2]>>2);		/*** */
  store(lval);
  }

store(lval)  int lval[]; {
  if(lval[1]) putstk(lval);
  else	      putmem(lval);
  }

rvalue(lval) int lval[]; {
  if ((lval[0]!=0)&(lval[1]==0)) getmem(lval);
  else			       indirect(lval);
  }

test(label, parens)  int label, parens;	 {
  int lval[8];
  char *before, *start;
  if(parens) needtoken("(");
  while(1) {
    setstage(&before, &start);
    if(heir1(lval)) rvalue(lval);
    if(match(",")) clearstage(before, start);
    else break;
    }
  if(parens) needtoken(")");
  if(lval[3]) {	 /* constant expression */
    clearstage(before, 0);
    if(lval[4]) return;
    jump(label);
    return;
    }
  if(lval[7]) {	 /* stage address of "oper 0" code */
    oper=lval[6];/* operator function address */
	 if((oper==eq)|
	    (oper==ule)) zerojump(eq0, label, lval);
    else if((oper==ne)|
	    (oper==ugt)) zerojump(ne0, label, lval);
    else if (oper==gt)	 zerojump(gt0, label, lval);
    else if (oper==ge)	 zerojump(ge0, label, lval);
    else if (oper==uge)	 clearstage(lval[7],0);
    else if (oper==lt)	 zerojump(lt0, label, lval);
    else if (oper==ult)	 zerojump(ult0, label, lval);
    else if (oper==le)	 zerojump(le0, label, lval);
    else		 testjump(label);
    }
  else testjump(label);
  clearstage(before, start);
  }

constexpr(val) int *val; {
  int const;
  char *before, *start;
  setstage(&before, &start);
  expression(&const, val);
  clearstage(before, 0);  /* scratch generated code */
  if(const==0) error("must be constant expression");
  return const;
  }

const(val) int val; {
  immed();
  outdec(val);
  nl();
  }

const2(val) int val; {
  immed2();
  outdec(val);
  nl();
  }

constant(lval)	int lval[]; {
  lval=lval+3;
  *lval=1;	 /* assume it will be a constant */
  if (number(++lval)) immed();
  else if (pstr(lval)) immed();
  else if (qstr(lval)) {
    *(lval-1)=0; /* nope, it's a string address */
    immed();
    printlabel(litlab);
    outbyte('+');
    }
  else return 0;
  outdec(*lval);
  nl();
  return 1;
  }

number(val)  int val[]; {
  int k, minus;
  k=minus=0;
  while(1) {
    if(match("+")) ;
    else if(match("-")) minus=1;
    else break;
    }
  if(numeric(ch)==0)return 0;
  while (numeric(ch)) k=k*10+(inbyte()-'0');
  if (minus) k=(-k);
  val[0]=k;
  return 1;
  }

address(ptr) char *ptr; {
  immed();
  outstr(ptr+NAME);
  nl();
  }

pstr(val)  int val[]; {
  int k;
  k=0;
  if (match("'")==0) return 0;
  while(ch!=39)	   k=(k&255)*256 + (litchar()&255);
  ++lptr;
  val[0]=k;
  return 1;
  }

qstr(val)  int val[]; {
  char c;
  if (match(quote)==0) return 0;
  val[0]=litptr;
  while (ch!='"') {
    if(ch==0) break;
    stowlit(litchar(), 1);
    }
  gch();
  litq[litptr++]=0;
  return 1;
  }

stowlit(value, size) int value, size; {
  if((litptr+size) >= LITMAX) {
    error("literal queue overflow"); abort();
    }
  putint(value, litq+litptr, size);
  litptr=litptr+size;
  }

/*
** return current literal char & bump lptr
*/

litchar()
{	int i, oct;

	if (ch != '\\' || nch == 0)
		return gch();
	gch();
	switch(ch) {
	case 'b':
		gch();
		return 8;	/* BS */
	case 'f':
		gch();
		return 12;	/* FF */
	case 'n':
		gch();
		return 10;	/* LF */
	case 'r':
		gch();
		return 13;	/* CR */
	case 't':
		gch();
		return 9;	/* HT */
	}
	i = 3;
	oct = 0;
	while (i-- > 0 && ch >= '0' && ch <= '7')
		oct = (oct << 3) + gch() - '0';
	if (i == 2)
		return gch();	/* \x is just x */
	return oct;
}
%%%%%%%%%% scc/scc/41.c %%%%%%%%%%
/***
 *	fixes:
 *
 *	= *	not =*
 *	oper	int (*) ()	not int
 *	overhauled for MACRO-80 and CP/M
 */

#include "smallc.h"

header()	/* incantations at begin of module */
{
	ol("EXTRN ?smallC ; smallC for MACRO-80 CP/M");
	ol("EXTRN ?30217 ; ats 02/17/83");

	/*
	 *	linkage boot strap:
	 *
	 *	?smallC is EXTRN in all modules compiled by this compiler
	 *		is ENTRY in the outermost runtime routine
	 *		which is entered from CP/M
	 *
	 *	?ymmdd	is EXTRN in all modules compiled by this compiler
	 *		is ENTRY in ?smallC module and controls version dates
	 *
	 *	_shell	is EXTRN in ?smallC module
	 *		is the outermost runtime routine written in smallC
	 *
	 *	main	is extern in _shell()
	 *		and must be supplied by the user,
	 *		to be called UN*X-style
	 *
	 *	_end	is EXTRN in ?smallC module
	 *		marks the first byte available to a heap
	 *		by being linked absolutely last
	 */
}

csect()		/* incantations at begin of code */
{
	ol("CSEG");
}

dsect()		/* incantations at begin of data */
{
	ol("DSEG");
}

trailer()	/* incantations at end of module */
{
	ol("END");
}

loadargc(val)	/* the great #arguments trick */
	int val;
{
#ifdef HASH
	if (search("NOCCARGC", macn, NAMESIZE+2, MACNEND, MACNBR, 0) == 0)
#else
	if (findmac("NOCCARGC") == 0)
#endif
	{	ot("MVI A,");
		outdec(val);
		nl();
	}
}

entry()		/* define entry point */
{
	outstr(ssname);
	outstr("::");
	nl();
}

external(name)	/* declare external reference */
	char *name;
{
	ot("EXTRN");
	ol(name);
}

indirect(lval)	/* PR = *(PR) */
	int lval[];
{
	if(lval[1] == CCHAR)
		call("?GCHAR##");
	else
		call("?GINT##");
}

getmem(lval)	/* PR = memory */
	int lval[];
{	char *sym;

	sym = lval[0];
	if (sym[IDENT] != POINTER && sym[TYPE] == CCHAR)
	{	ot("LDA ");
		outstr(sym+NAME);
		nl();
		call("?SXT##");
	}
	else
	{	ot("LHLD ");
		outstr(sym+NAME);
		nl();
	}
}

getloc(sym)	/* PR = &symbol */
	char *sym;
{
	const(getint(sym+OFFSET, OFFSIZE) - csp);
	ol("DAD SP");
}

putmem(lval)	/* memory = PR */
	int lval[];
{	char *sym;

	sym = lval[0];
	if (sym[IDENT] != POINTER && sym[TYPE] == CCHAR)
	{	ol("MOV A,L");
		ot("STA ");
	}
	else
		ot("SHLD ");
	outstr(sym+NAME);
	nl();
}

putstk(lval)	/* push = PR */
	int lval[];
{
	if (lval[1] == CCHAR)
	{	ol("MOV A,L");
		ol("STAX D");
	}
	else
		call("?PINT##");
}

move()		/* SE = PR */
{
	ol("MOV D,H");
	ol("MOV E,L");
}

swap()		/* SE = PR and PR = SE */
{
	ol("XCHG;;");	 /* peephole() uses trailing ";;" */
}

immed()		/* PR = value (partial!) */
{
	ot("LXI H,");
}

immed2()	/* SE = value (partial!) */
{
	ot("LXI D,");
}

push()		/* push = PR */
{
	ol("PUSH H");
	csp -= BPW;
}

smartpop(lval, start)	/* unpush or pop as required */
	int lval[];
	char *start;
{
	if (lval[5])
		pop();		/* secondary was used */
	else
		unpush(start);
}

unpush(dest)	/* replace push by swap */
	char *dest;
{	int i;
	char *sour;

	sour = "\tXCHG;;";	/* peephole() uses trailing ";;" */
	while (*sour)
		*dest++ = *sour++;
	sour = stagenext;
	while (--sour > dest)	/* adjust stack references */
		if (streq(sour,"\tDAD SP"))
		{	--sour;
			i = BPW;
			while (numeric(*--sour))
				if ((*sour -= i) < '0')
				{	*sour += 10;
					i = 1;
				}
				else
					i = 0;
		}
	csp += BPW;
}

pop()		/* SE = pop */
{
	ol("POP D");
	csp += BPW;
}

swapstk()	/* stack = PR and PR = stack */
{
	ol("XTHL");
}

sw()		/* switch statement */
{
	call("?SWITCH##");
}

call(sname)	/* subroutine call */
	char *sname;
{
	ot("CALL ");
	outstr(sname);
	nl();
}

ret()		/* subroutine return */
{
	ol("RET");
}

callstk()	/* call subroutine address on stack */
{
	immed();
	outstr("$+5");
	nl();
	swapstk();
	ol("PCHL");
	csp += BPW;
}

jump(label)	/* jump to internal label */
	int label;
{
	outjmp("JMP",label);
}

testjump(label) /* test PR, jump if false */
	int label;
{
	ol("MOV A,H");
	ol("ORA L");
	outjmp("JZ",label);
}

zerojump(oper, label, lval)	/* test PR 0, jump of false */
	int (*oper)(), label, lval[];
{
	clearstage(lval[7], 0);	 /* purge conventional code */
	(*oper)(label);
}

defstorage(size)	/* define storage */
	int size;
{
	if (size == 1)
		ot("DB ");
	else
		ot("DW ");
}

point()		/* point to following objects */
{
	ol("DW $+2");
}

modstk(newsp, save)	/* mod stack pointer to value */
	int newsp, save;
{	int k;

	if ((k = newsp-csp) == 0)
		return newsp;
	if (k >= 0)
	{	if (k < 7)
		{	if (k & 1)
			{	ol("INX SP");
				k--;
			}
			while (k)
			{	ol("POP B");
				k -= BPW;
			}
			return newsp;
		}
	}
	if (k < 0)
	{	if (k > -7)
		{	if (k & 1)
			{	ol("DCX SP");
				k++;
			}
			while (k)
			{	ol("PUSH B");
				k += BPW;
			}
			return newsp;
		}
	}
	if (save)
		swap();
	const(k);
	ol("DAD SP");
	ol("SPHL");
	if (save)
		swap();
	return newsp;
}

doublereg()	/* PR += PR */
{
	ol("DAD H");
}
%%%%%%%%%% scc/scc/42.c %%%%%%%%%%
/***
 *	fixes:
 *
 *	pp	int (*)()	not int
 *	overhauled for MACRO-80 CP/M
 *	optimizer corrected (was very wrong)
 */

#include "smallc.h"

add()		/* PR += SE */
{
	ol("DAD D");
}

sub()		/* PR = SE-PR */
{
	call("?SUB##");
}

mult()		/* PR *= SE */
{
	call("?MULT##");
}

div()		/* SE %= PR and PR = SE/PR */
{
	call("?DIV##");
}

mod()		/* SE /= PR and PR = SE%PR */
{
	div();
	swap();
}

or()		/* PR |= SE */
{
	call("?OR##");
}

xor()		/* PR ^= SE */
{
	call("?XOR##");
}

and()		/* PR &= SE */
{
	call("?AND##");
}

lneg()		/* PR = !PR */
{
	call("?LNEG##");
}

asr()		/* PR = SE >> PR */
{
	call("?ASR##");
}

asl()		/* PR = SE << PR */
{
	call("?ASL##");
}

neg()		/* PR = -PR */
{
	call("?NEG##");
}

com()		/* PR ~PR */
{
	call("?COM##");
}

inc(n)		/* PR += n */
	int n;
{
	while(1)
	{	ol("INX H");
		if (--n < 1)
			break;
	}
}

dec(n)		/* PR -= n */
	int n;
{
	while(1)
	{	ol("DCX H");
		if (--n < 1)
			break;
	}
}

eq()		/* == */
{
	call("?EQ##");
}

eq0(label)	/* == 0 */
	int label;
{
	ol("MOV A,H");
	ol("ORA L");
	outjmp("JNZ", label);
}

ne()		/* != */
{
	call("?NE##");
}

ne0(label)	/* != 0 */
	int label;
{
	ol("MOV A,H");
	ol("ORA L");
	outjmp("JZ", label);
}

lt()		/* (int) < */
{
	call("?LT##");
}

lt0(label)	/* (int) < 0 */
	int label;
{
	ol("XRA A");
	ol("ORA H");
	outjmp("JP", label);
}

le()		/* (int) <= */
{
	call("?LE##");
}

le0(label)	/* (int) <= 0 */
	int label;
{
	ol("MOV A,H");
	ol("ORA L");
	ol("JZ $+8");
	ol("XRA A");
	ol("ORA H");
	outjmp("JP", label);
}

gt()		/* (int) > */
{
	call("?GT##");
}

gt0(label)	/* (int) > 0 */
	int label;
{
	ol("XRA A");
	ol("ORA H");
	outjmp("JM", label);
	ol("ORA L");
	outjmp("JZ", label);
}

ge()		/* (int) >= */
{
	call("?GE##");
}

ge0(label)	/* (int) >= 0 */
	int label;
{
	ol("XRA A");
	ol("ORA H");
	outjmp("JM", label);
}

ult()		/* (unsigned) < */
{
	call("?ULT##");
}

ult0(label)	/* (unsigned) < 0 */
	int label;
{
	outjmp("JMP", label);
}

ule()		/* (unsigned) <= */
{
	call("?ULE##");
}

ugt()		/* (unsigned) > */
{
	call("?UGT##");
}

uge()		/* (unsigned) >= */
{
	call("?UGE##");
}

outjmp(j, l)	/* \t j sp l \n */
	char *j;
	int l;
{
	ot(j);
	outbyte(' ');
	printlabel(l);
	nl();
}

/*
 *	pattern compare:
 *
 *	'*' is a match-all,
 *	first such character matched is returned in 'drop'.
 *
 *	return value is non-matched pattern position
 *	or end of pattern.
 *
 *	non-matched string position is also dropped.
 */

p_eq(str,nstr,pat,drop)
	char *str;	/* to search */
	int *nstr;	/* really char **, return */
	char *pat;	/* pattern to search */
	char *drop;	/* return */
{
	for (*drop = '\0'; *pat; str++,pat++)
		if (*str == *pat)
			continue;
		else if (*pat == '*')
		{	if (*drop == '\0')
				*drop = *str;
			continue;
		}
		else
			break;
	*nstr = str;
	return pat;
}

char p_1[] =
 "XCHG;;\n\tLXI H,*\n\tDAD SP\n\tCALL ?GINT##\n\tXCHG;;\n";
/*	    1				       2	 3 */

char p_2[] =
 "DAD SP\n\tMOV D,H\n\tMOV E,L\n\t";
/*	    1			  2 */

char p_3[] =
 "CALL ?GINT##\n\t**X H\n\tCALL ?PINT##\n";
/*		1	   2		 3 */

char p_4[] =
 "CALL ?GCHAR##\n\t**X H\n\tMOV A,L\n\tSTAX D\n";
/*		 1	    2		       3 */

char p_5[] =
 "DAD D\n\tPOP D\n\t";
/*	   1	    2 */

#define p_1_1	(p_1+8)
#define p_1_2	(p_1+38)
#define p_1_3	(p_1+46)

#define p_2_1	(p_2+8)
#define p_2_2	(p_2+26)

#define _p_3_1	13
#define p_3_1	(p_3+_p_3_1)
#define p_3_2	(p_3+21)
#define p_3_3	(p_3+34)

#define _p_4_1	14
#define p_4_1	(p_4+_p_4_1)
#define p_4_2	(p_4+22)
#define p_4_3	(p_4+38)

#define p_5_1	(p_5+7)
#define p_5_2	(p_5+14)

peephole(ptr)		/* emit stage buffer, replacing some text */
	char *ptr;
{	char ch, *pp, *nptr, *nnptr;

	while (ch = *ptr++)
	{	if (! optimize	/* can turn it totally off */
		|| ch != '\t')	/* \t before ANY mnemonic */
		{	cout(ch, output);
			continue;
		}
		pp = p_eq(ptr, &nptr, p_1, &ch);
		if (ch == '0' || ch == '2')
		{	if (pp == p_1_3)
			{	if (ch == '0')
					pp2();
				else
					pp3(pp2);
				ptr = nptr;
				continue;
			}
			if (pp >= p_1_2)
			{	ol("XCHG");
				if (ch == '0')
					pp1();
				else
					pp3(pp1);
				ptr += p_1_2-p_1;
				continue;
			}
		}
		pp = p_eq(ptr, &nptr, p_1_1, &ch);
		if (ch == '0' || ch == '2')
		{	if (pp == p_1_3)
			{	ol("XCHG");
				if (ch == '0')
					pp2();
				else
					pp3(pp2);
				ptr = nptr;
				continue;
			}
			if (pp >= p_1_2)
			{	if (ch == '0')
					pp1();
				else
					pp3(pp1);
				ptr += p_1_2-p_1_1;
				continue;
			}
		}
		if ((pp = p_eq(ptr, &nptr, p_2, &ch)) == p_2_2)
		{	pp = p_eq(nptr, &nnptr, p_3, &ch);
			if (ch == 'I' || ch == 'D')
				if (pp == p_3_3)
				{	if (ch == 'D')
						call("?DECI##");
					else
						call("?INCI##");
					ptr = nnptr;
					continue;
				}
			pp = p_eq(nptr, &nnptr, p_4, &ch);
			if (ch == 'I' || ch == 'D')
				if (pp == p_4_3)
				{	if (ch == 'D')
						call("?DECC##");
					else
						call("?INCC##");
					ptr = nnptr;
					continue;
				}
		}
		else if (pp == p_2_1)
		{	if (p_eq(nptr, &nnptr, p_3, &ch) >= p_3_1)
			{	call("?DSGI##");
				ptr = nptr + _p_3_1;
				continue;
			}
			if (p_eq(nptr, &nnptr, p_4, &ch) >= p_4_1)
			{	call("?DSGC##");
				ptr = nptr + _p_4_1;
				continue;
			}
		}
		if ((pp = p_eq(ptr, &nptr, p_5, &ch)) == p_5_2)
		{	if (p_eq(nptr, &nnptr, p_3_2, &ch) == p_3_3)
			{	call("?DDPPI##");
				ptr = nnptr;
				continue;
			}
			if (p_eq(nptr, &nnptr, p_4_2, &ch) == p_4_3)
			{	call("?DDPPC##");
				ptr = nnptr;
				continue;
			}
		}
		else if (pp == p_5_1)
		{	if (p_eq(nptr, &nnptr, p_3, &ch) >= p_3_1)
			{	call("?DDGI##");
				ptr = nptr + _p_3_1;
				continue;
			}
			if (p_eq(nptr, &nnptr, p_4, &ch) >= p_4_1)
			{	call("?DDGC##");
				ptr = nptr + _p_4_1;
				continue;
			}
		}
		if ((pp == p_eq(ptr, &nptr, p_5_1, &ch)) == p_5_2)
		{	if (p_eq(nptr, &nnptr, p_3_2, &ch) == p_3_3)
			{	call("?PDPI##");
				ptr = nnptr;
				continue;
			}
			if (p_eq(nptr, &nnptr, p_4_2, &ch) == p_4_3)
			{	call("?PDPC##");
				ptr = nnptr;
				continue;
			}
		}
		cout('\t', output);
	}
}

pp1()		/* PR = top() */
{
	ol("POP H");
	ol("PUSH H");
}

pp2()		/* SE = top() */
{
	ol("POP D");
	ol("PUSH D");
}

pp3(pp)		/* PR or SE = belowtop() */
	int (*pp)();
{
	ol("POP B");
	(*pp)();
	ol("PUSH B");
}
%%%%%%%%%% end of part 3 %%%%%%%%%%

schrein (03/14/83)

#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 %%%%%%%%%%