TD +   -       NCR F3                                    7   d interrupt vector initialization
clrex:	jmp	vclrex	;routine to clear external data area
	ENDIF

	IF	NOT CPM	;if not under CP/M, file I/O routines
	jmp	verror	;are not used.
	jmp	verror
	jmp	verror
	jmp	verror
	jmp	verror
	jmp	verror
	jmp	verror
	jmp	verror
	jmp	verror
	jmp	verror
	jmp	verror
	ENDIF

	ds	9	;reserved

;
; The following routines fetch a variable value from either
; the local stack frame or the external area, given the relative
; offset of the datum required immediately     
	mov	a,m
	inx	h
	mov	h,m
	mov	l,a
	ret

;
; short-displacement, double-byte local indirection:
;
;	format:		call	sdli		; get 16-bit value in HL
;			db offset_from_BC	; < 256
;

sdli:	pop	h
	mov	e,m
	inx	h
	push	h
	xchg
	mvi	h,0
	dad	b
	mov	a,m
	inx	h
	mov	h,m
	mov	l,a
	ret

;
; Flag conversion routines:
;

pzinh:	lxi	h,1	;return HL = true if Z set
	rz
	dcx	h
	ret

pnzinh:	lxi	h,0	;return HL = false if Z set
	rz
	inx	h
	ret

pcinh:	lxi	h,1	;return HL = true if C set   following the call;
; for the "long displacement" routines, the offset must be 16 bits,
; for the "short displacement" routines, the offset must be 8 bits.
;

;
; long-displacement, double-byte external indirection:
;
;	format:	call ldei		; get 16-bit value in HL
;		dw offset_from_extrns	; >= 256
;

ldei:	pop	h	;get address of offset
	mov	e,m	;put offset in DE
	inx	h
	mov	d,m
	inx	h 		
	push	h	;save return address
	lhld	extrns	;add offset to external area base
	dad	d
	mov	a,m	;and get th   
	rc
	dcx	h
	ret

pncinh:	lxi	h,0	;return HL = false if C set
	rc
	inx	h
	ret

ppinh:	lxi	h,1	;return HL = true if P (plus) flag set
	rp
	dcx	h
	ret

pminh:	lxi	h,1	;return HL = true if M (minus) flag set
	rm
	dcx	h
	ret

pzind:	lxi	d,1	;return DE = true if Z set
	rz
	dcx	d
	ret

pnzind:	lxi	d,0	;return DE = false if Z set
	rz
	inx	d
	ret

pcind:	lxi	d,1	;return DE = true if C set
	rc
	dcx	d
	ret

pncind:	lxi	d,0	;return DE = false if C set
	rc
	inx	d
	ret

ppind:	lxi	  h e value into HL
	inx	h
	mov	h,m
	mov	l,a
	ret

;
; short-displacement, double-byte external indirection:
;
;	format:		call sdei		; get 16-bit value in L
;			db offset_from_extrns	; < 256
;

sdei:	pop	h
	mov	e,m
	inx	h
	push	h
	mvi	d,0
	lhld	extrns
	dad	d
	mov	a,m
	inx	h
	mov	h,m
	mov	l,a
	ret

;
; long-displacement, single-byte external indirection:
;
;	format:		call	lsei		; get 8-bit value in L
;			dw offset_from_extrns	; >= 256
;

lsei:	pop	h
	mov	e,m
	inx	h
	mov	d,m
	  f d,1	;return DE = true if P (plus) flag set
	rp
	dcx	d
	ret

pmind:	lxi	d,1	;return DE = true if M (minus) flag set
	rm
	dcx	d
	ret
	

;	
; Relational operator routines: take args in DE and HL,
; and return a flag bit either set or reset.
;
; ==, >, < :
;

eqwel:	mov	a,l	;return Z if HL == DE, else NZ
	cmp	e
	rnz		;if L <> E, then HL <> DE
	mov	a,h	;else HL == DE only if H == D
	cmp	d
	ret

blau:	xchg		;return C if HL < DE, unsigned
albu:	mov	a,d	;return C if DE < HL, unsigned
	cmp  N inx	h
	push	h
	lhld	extrns
	dad	d
	mov	l,m
	ret

;
; short-displacement, single-byte external indirection:
;
;	format:		call	ssei		; get 8-bit value in L
;			db offset_from_externs	; < 256
;

ssei:	pop	h
	mov	e,m	
	inx	h
	push	h
	mvi	d,0
	lhld	extrns
	dad	d
	mov	l,m
	ret

;
; long-displacement, double-byte local indirection:
;
;	format:		call	ldli		; get 16-bit value in HL
;			dw offset_from_BC	; >= 256
;

ldli:	pop	h
	mov	e,m
	inx	h
	mov	d,m
	inx	h
	push	h
	xchg
	dad	b  t 	h
	rnz		;if D <> H, C is set correctly
	mov	a,e	;else compare E with L
	cmp	l
	ret

bgau:	xchg		;return C if HL > DE, unsigned
agbu:	mov	a,h	;return C if DE > HL, unsigned
	cmp	d
	rnz		;if H <> D, C is set correctly
	mov	a,l	;else compare L with E
	cmp	e
	ret

blas:	xchg		;return C if HL < DE, signed
albs:	mov	a,h	;return C if DE < HL, signed
	xra	d
	jp	albu	;if same sign, do unsigned compare
	mov	a,d
	ora	a
	rp		;else return NC if DE is positive and HL is negative
	stc		;else set carr )                                  y, since DE is negative and HL is pos.
	ret

bgas:	xchg		;return C if HL > DE, signed
agbs:	mov	a,h	;return C if DE > HL, signed
	xra	d
	jp	agbu	;if same sign, go do unsigned compare
	mov	a,h
	ora	a
	rp		;else return NC is HL is positive and DE is negative
	stc
	ret		;else return C, since HL is neg and DE is pos


;
; Multiplicative operators: *, /, and %:
;

smod:	mov	a,d	;signed MOD routine: return (DE % HL) in HL
	push	psw	;save high bit of DE as sign of result
	call	tstn	;get absolut > mov	a,e
	rar
	mov	e,a
	pop	psw
	dcr	a
	rz
	push	psw
	mov	a,c
	ral
	mov	c,a
	mov	a,b
	ral
	mov	b,a
	jmp	usd6

sdiv:	xra	a	;signed divide: return (DE / HL) in HL
	sta	tmp
	call	tstn
	xchg
	call	tstn
	xchg
	call	usdiv
	jmp	smul2

cmphd:	mov	a,h	;this returns C if HL < DE
	cmp	d	; (unsigned compare only used
	rc		;  within C.CCC, not from C)
	rnz
	mov	a,l
	cmp	e
	ret

;
; Shift operators  << and >>:
;

sderbl:	xchg		;shift DE right by L bits
shlrbe:	inr	e	;shift HL right by   e value of args
	xchg
 	call	tstn
	xchg
	call	usmod	;do unsigned mod
	pop	psw	;was DE negative?
	ora	a	;if not,
	rp		;	all done
	mov	a,h	;else make result negative
	cma
	mov	h,a
	mov	a,l
	cma
	mov	l,a
	inx	h
	ret

	nop		;maintain address compatibility with some
	nop		; pre-release v1.4's.

usmod:	mov	a,h	;unsigned MOD: return (DE % HL) in HL
	ora	l
	rz
	push	d
	push	h
	call	usdiv
	pop	d
	call	usmul
	mov	a,h
	cma
	mov	h,a
	mov	a,l
	cma 
	mov	l,a
	inx	h
	pop	d
	dad	d
	ret  E bits
shrbe2:	dcr	e
	rz
	xra	a
	mov	a,h
	rar
	mov	h,a
	mov	a,l	
	rar
	mov	l,a
	jmp	shrbe2

sdelbl:	xchg		;shift DE left by L bits
shllbe:	inr	e	;shift HL left by E bits
shlbe2:	dcr	e
	rz
	dad	h
	jmp	shlbe2


;
; Routines to 2's complement HL and DE:
;

cmh:	mov	a,h
	cma
	mov	h,a
	mov	a,l
	cma
	mov	l,a
	inx	h
	ret

cmd:	mov	a,d
	cma
	mov	d,a
	mov	a,e
	cma
	mov	e,a
	inx	d
	ret


;
; The following routines yank a formal parameter value off the stack
; and place it  B 

smul:	xra	a	;signed multiply: return (DE * HL) in HL
	sta	tmp
	call	tstn
	xchg
	call	tstn
	call	usmul
smul2:	lda	tmp
	rar
	rnc
	mov	a,h
	cma
	mov	h,a
	mov	a,l
	cma
	mov	l,a
	inx	h
	ret

tstn:	mov	a,h
	ora	a
	rp
	cma
	mov	h,a
	mov	a,l
	cma
	mov	l,a
	inx	h
	lda	tmp
	inr	a
	sta	tmp
	ret

usmul:	push	b	;unsigned multiply: return (DE * HL) in HL
	call	usm2
	pop	b
	ret

usm2:	mov	b,h
	mov	c,l
	lxi	h,0
usm3:	mov	a,b
	ora	c
	rz
	mov	a,b
	rar
	mov	b,a
	mov	a,c
	rar
  in both HL and A (low byte), assuming the caller
; hasn't done anything to its stack pointer since IT was called.
;
; The mnemonics are "Move Arg #n To HL",
; where arg #1 is the third thing on the stack (where the first
; and second things are, respectively, the return address of the
; routine making the call	to here, and the previous return
; address to the routine which actually pushed the args on the
; stack.) Thus, a call	to "ma1toh" would return with the first
; passed parameter in HL and A;  & 	mov	c,a
	jnc	usm4
	dad	d
usm4:	xchg
	dad	h
	xchg
	jmp	usm3

usdiv:	mov	a,h	;unsigned divide: return (DE / HL) in HL
	ora	l	;return 0 if HL is 0
	rz
	push	b
	call	usd1
	mov	h,b
	mov	l,c
	pop	b
	ret


usd1:	mvi	b,1
usd2:	mov	a,h
	ora	a
	jm	usd3
	dad	h
	inr	b
	jmp	usd2

usd3:	xchg

usd4:	mov	a,b
	lxi	b,0
usd5:	push	psw
usd6:	call	cmphd
	jc	usd7
	inx	b
	push	d
	mov	a,d
	cma
	mov	d,a
	mov	a,e
	cma
	mov	e,a
	inx	d
	dad	d
	pop	d
usd7:	xra	a
	mov	a,d
	rar
	mov	d,a
	  "ma2toh" would return the second,
; etc. Note that if the caller has pushed [n] items on the stack
; before calling "ma [x] toh", then the [x-n]th formal parameter
; value will be returned, not the [x]th.
;

ma1toh:	lxi	h,4	;get first arg
ma0toh:	dad	sp
	mov	a,m
	inx	h
	mov	h,m
	mov	l,a
	ret

ma2toh:	lxi	h,6	;get 2nd arg
	jmp	ma0toh

ma3toh:	lxi	h,8	;get 3rd arg
	jmp	ma0toh

ma4toh:	lxi	h,10	;get 4th arg
	jmp	ma0toh

ma5toh:	lxi	h,12	;get 5th arg
	jmp	ma0toh

ma6toh:	lxi	h,14	;get                                  %  6th arg
	jmp	ma0toh

ma7toh:	lxi	h,16	;get 7th arg
	jmp	ma0toh

;
; This routine takes the first 7 args on the stack
; and places them contiguously at the "args" ram area.
; This allows a library routine to make one call	to arghak
; and henceforth have all it's args available directly
; through lhld's instead of having to hack the stack as it
; grows and shrinks. Note that arghak should be called as the
; VERY FIRST THING a function does, before even pushing BC.
;

arghak:	lxi	d,args	;destin  1000	;default safety space between stack and
	shld	alocmx	; highest allocatable address in memory 
			; (for use by "sbrk".).

			;Initialize random seed:
	lxi	h,59dch	;let's stick something wierd into the
	shld	rseed	;first 16 bits of the random-number seed

			;Initialize I/O hack locations:
	mvi	a,0dbh		;"in" op, for "in xx; ret" subroutine
	sta	iohack
	mvi	a,0d3h		;"out" op for "out xx; ret" subroutine
	sta	iohack+3
	mvi	a,0c9h		;"ret" for above sobroutines
	sta	iohack+2	;the port number i  ation for block move in DE
	lxi	h,4	;pass over two return address
	dad	sp	;source for block move in HL
	push	b	;save BC
	mvi	b,14	;countdown in B
arghk2:	mov	a,m	;copy loop
	stax	d
	inx	h
	inx	d
	dcr	b
	jnz	arghk2	
	pop	b	;restore BC
	ret

;
; ABSOLUTELY NO CHANGES SHOULD EVER BE MADE TO THE CODE BEFORE
; THIS POINT IN THIS SOURCE FILE (except for customizing the EQU
; statements at the beginning of the file).
;


;
; The following two routines are used when the "-tn" CLINK option
; w  s filled in by the
	sta	iohack+5	;"inp" and "outp" library routines.

	IF	CPM
	call	khack		;initialize Kirkland debugger vector
	ENDIF

	IF 	CPM		;initialize raw I/O parameters
	xra	a
	sta	freeze		;clear freeze (^S) flag
	sta	pending		;no pending input yet
	mvi	a,1fh	
	sta	mode		;tty mode: all features enabled
	mvi	a,'C'-64
	sta	quitc		;this is the standard interrupt char
	ENDIF

				;Initialize DMA video parameters:
	IF	DMAVIO		;if we're using DMA video routines,
	lxi	h,0cc00h	;set up de l as given, in order to preserve the SP value passed to the transient
; command by the CCP and return to the CCP after execution without
; performing a warm-boot.
;

	IF CPM
vsnobsp:
	lxi	h,0		;get CCP's SP value in HL
	dad	sp
	shld	spsav		;save it for later
	lhld	base+6		;get BIOS pointer
	lxi	d,-2100		;subtract size of CCP plus a fudge
	dad	d
	sphl			;make that the new SP value
	jmp	tpa+3		;and get things under way...

vnobret:
	lhld	spsav		;restore CCP's SP
	sphl
	ret			;return to CCP
  fault values (may be changed
	shld	pbase		;to whatever suits). Video board address,
	lxi	h,16
	shld	xsize		;# of lines,
	lxi	h,64
	shld	ysize		;# of columns,
	lxi	h,1024
	shld	psize		;and total # of characters on screen
	ENDIF

	IF	CPM	;under CP/M: clear console, process ARGC & ARGV:
	mvi	c,cstat ;interrogate console status to see if there
	call	bdos	;  happens to be a stray character there...

	ora	a	;(used to be `ani 1'...they tell me this works
	nop		; better for certain bizarre CP/M-"like  
	ENDIF


;
; This routine is called first to do argc & argv processing (if
; running under CP/M) and some odds and ends initializations:
;

init:	pop	h	;store return address
	shld	tmp2	; somewhere safe for the time being

	IF	CPM
	lxi	h,arglst-2	;set up "argv" for the C main program
	ENDIF
	
	IF	NOT CPM
	lxi	h,0
	ENDIF

	push	h

			;Initialize storage allocation pointers:
	lhld	freram	;get address after end of externals
	shld	allocp	;store at allocation pointer (for "sbrk.")
	lxi	h, N " systems)

	jz	initzz
	mvi	c,conin   ;if input present, clear it
	call	bdos

initzz:	lxi	h,tbuff		;if arguments given, process them.
	lxi	d,comlin	;get ready to copy command line
	mov	b,m		;first get length of it from loc. base+80h
	inx	h
	mov	a,b
	ora	a	;if no arguments, don't parse for argv
	jnz	initl
	lxi	d,1	;set argc to 1 in such a case.
	jmp	i5

initl:	mov	a,m	;ok, there are arguments. parse...
	stax	d	;first copy command line to comlin
	inx	h
	inx	d
	dcr	b
	jnz	initl
	xra	a	;pl ;  f  READ    ME         CC      COM   r	
    CC2     COM       CLINK   COM   *   CLIB    COM   *   DEFF    CRL   K   DEFF2   CRL   7 !"    C       CCC   #   BDSCIO  H     $%    HARDWAREH     &'    STDLIB1 C     @()*+    STDLIB2 C     8,-./    BDS     LIB   30123    DEFF2A  CSM   m456789:   DEFF2B  CSM   .;<=   DEFF2C  CSM  >?@ABCDEFG            9= 1 CCC     ASM  nHIJKLMNOPQRSTUV  DIO     H     W   DIO     C     FXYZ[\   WILDEXP C     )]^_   CASM    SUB   `   3CASM    C    +abcdefghijk      FLOAT   C     7lmno    LONG    C     pq    CP      C     #rst   NOBOOT  C     u   DI      C     vw     DEFF2D  CSM  xyz{|}~       @                     > ace zero following line
	stax	d

	lxi	h,comlin	;now compute pointers to each arg
	lxi	d,1		;arg count
	lxi	b,arglst	;where pointers will all go
	xra	a		;clear "in a string" flag
	sta	tmp1
i2:	mov	a,m	;between args...
	inx	h
	cpi	' '
	jz	i2
	ora	a
	jz	i5	;if null byte, done with list
	cpi	'"'
	jnz	i2a	;quote?
	sta	tmp1	;yes. set "in a string" flag
	jmp	i2b	

i2a:	dcx	h
i2b:	mov	a,l	;ok, HL is a pointer to the start
	stax	b	;of an arg string. store it.
	inx	b
	mov	a,h
	stax	b
	inx	b
  i	h,0E1H+2300H	;pop h - inx h
	shld	rstloc		; put at "RST 6" location
	lxi	h,023H+0E900H	;inx h - pchl
	shld	rstloc+2
	ret
	ENDIF

	IF NOT USERST
vkhack:	ret
	ds 12
	ENDIF


;
; General purpose error value return routine:
;

verror:	lxi	h,-1	;general error handler...just
	ret		;returns -1 in HL

;
; Here are file I/O handling routines, only needed under CP/M:
;

;
; Close any open files and reboot:
;

vexit:
	IF	CPM		;if under CP/M, close all open files
	mvi	a,7+nfcbs	;start wi K 	inx	d	;bump arg count
i3:	mov	a,m
	inx	h	;pass over text of this arg
	ora	a	;if at end, all done
	jz	i5
	push	b	;if tmp1 set, in a string 
	mov	b,a	; (so we have to ignore spaces)
	lda	tmp1
	ora	a
	mov	a,b
	pop	b
	jz	i3a
	cpi	'"'	;we are in a string.
	jnz	i3	;check for terminating quote
	xra	a	;if found, reset "in string" flag
	sta	tmp1
	dcx	h
	mov	m,a	;and stick a zero byte after the string
	inx	h	;and go on to next arg
i3a:	cpi	' '	;now find the space between args
	jnz	i3
	dcx	h	;fou  th largest possible fd
exit1:	push	psw		;and scan all fd's for open files
	call	vfgfd		;is file whose fd is in A open?
	jc	exit2		;if not, go on to next fd
	mov	l,a		;else close the associated file
	mvi	h,0
	push	h
	call	vclose
	pop	h
exit2:	pop	psw
	dcr	a		;and go on to next one
	cpi	7
	jnz	exit1
	ENDIF

	jmp	fexitv		;done closing...now return
				; to CP/M or whatever.


;
; Close the file whose fd is 1st arg:
;

	IF	CPM	;here comes a lot of CP/M stuff...
vclose:
	call	ma1toh	;get  nd it. stick in a zero byte
	mvi	m,0
	inx	h
	jmp	i2	;and go on to next arg

i5:	push	d	;all done finding args. Set argc.

	mvi	b,3*nfcbs  ;now initialize all the file info
	lxi	h,fdt	;by zeroing the fd table)
i6:	mvi	m,0
	inx	h
	dcr	b
	jnz	i6
	ENDIF

	IF	NOT CPM	;if not under CP/M, force ARGC value	
	lxi	h,1	; of one.
	push	h
	ENDIF

	call	clrex	;clear externals, if CLINK -z option NOT used

	xra	a
	sta	ungetl	;clear the push-back byte,
	sta	errnum	;and file error code

	lhld	tmp2   fd in A
	call	vfgfd	;see if it is open
	jc	verror	;if not, complain
	mov	a,m
	call	setusr	;set user area to match current fd
	ani	4	;check if open for writing

	ENDIF

	IF CPM AND NOT MPM2	;if not MP/M, and
	jz	close2	;the file isn't open for write, don't bother to close
	ENDIF

	IF CPM AND MPM2		;always close all files under MP/M
	nop
	nop
	nop
	ENDIF

	IF CPM

	push	h	;save fd table entry addr
	call	ma2toh	;get the fd in A again
	push	b
	call	vfgfcb	;get the appropriate fcb addres 
 
	pchl		;all done initializing.

;
; The following routine gets called to clear the external
; data area, unless the CLINK "-z" option is used.
;

vclrex:	lhld	freram	;clear externals
	xchg
	lhld	extrns
	call 	cmh
	dad	d	;HL now holds size of external data area
clrex1:	mov 	a,h	;loop till done
	ora	l
	rz
	dcx	d
	dcx	h
	xra	a
	stax	d
	jmp	clrex1


;
; Initialize Kirkland interrupt vector... enables
; programs compiled with "-k" to run without the debugger:
;

	IF USERST
vkhack:	lx  s
	xchg		;put it in DE
	mvi	c,closec  ;get BDOS function # for close
	call	bdos	;and do it!
	pop	b
	pop	h
close2:	call	rstusr	;reset user number to original state
	mvi	m,0	;close the file logically
	cpi	255	;if 255 came back from bdos, we got problems
	lxi	h,0	
	rnz		;return 0 if OK
	dcx	h	;return -1 on error
	ret

;
; Determine status of file whose fd is in A...if the file
; is open, return Cy clear and with the address of the fd table
; entry for the open file in HL. If the file is not op   o Z


		BDS C v1.50    (c) 1982 by Leor Zolman
		   Description of Package Components
		-- 


Note:   CC.COM will announce version number  "v1.50a" to 
	indicate that this version has some bug fixes which were
	were added since the official v1.50 release. ONLY CC.COM
	announces "1.50a", though;  all other  components of the
	package are  still simply designated "1.50".

BDS C v1.50 is supplied by the author on two eight-inch single-density IBM
disks. One disk co   specific definition file

STDLIB1.C	1		Sources to the C-coded parts of the standard
STDLIB2.C	1		library (object in DEFF.CRL)

BDS.LIB	   *	1		Header file used for assembly-language function
				generation

DEFF2A.CSM 	1		Sources to the assembly-coded parts of the
DEFF2B.CSM	1		standard library (object in DEFF2.CRL)
DEFF2C.CSM	1
DEFF2D.CSM	1		(Contains FP and LONG functions)
CIO.CSM		2		Special Low-level Raw Console I/O package

CCC.ASM		1		Source to the run-time package

DIO.C		1		Directed   I ntains the essential files of the package, and the other
contains auxiliary files and the CDB debugger package. This 2-disk breakdown
applies only to the standard 8" disk format, though; if you obtained the
package on another format, the files might be differently arranged among the
supplied diskettes.

Every standard distribution package should contain a User's Guide, complete
with registration forms and BDS C User's Group application form, and either
two 8" diskettes or however diskettes it takes    I/O library for directed input,
DIO.H	   *	1		directed output and pipes.

WILDEXP.C	1		Command line wild-card expansion utility

CASM.C		1		CSM-to-CRL assembly language preprocessor and
CASM.SUB	1		companion submit-file.

FLOAT.C		1		Bob Mathias's floating point utility package
FLOATSUM.C	2		(Small sample program)

LONG.C		1		Rob Shostak's long integer utility package

CONVERT.C	2		Utilities for using BDS C on upper-case only
CC0T.C		2		terminals (such as the TRS-80 Mod I)

OTHELLO.C	2		A ga  3 in your format to hold the
(approximately) 480K worth of data in the BDS C package.

Files with an asterisk (*) after their names should be placed in the
"Default library directory" on your CP/M system. The default directory is
explained in chapter 1 of the BDS C User's Guide under "Configuration".

Files with a plus (+) after their names should be placed in the currently
logged directory when using the compiler, or else in your standard command file
area if you are running an alternative CCP (such   me program
SIEVE.C		2		Benchmark, from the Jan '83 issue of BYTE 
LPR.C		2		A line-printer driver utility.
NOBOOT.C	1		A utility to make C-generated COM files return
				quickly to the CCP after execution, instead of
				performing a warm-boot.
CP.C g		1		File copy utility
DI.C		1		File comparison utility

TELED.C		2		Telecommunication program


-- -

The Kernighan & Ritchie textbook, "The C Programming Language", should be
available to all BDS C users as a reference and good tutor  n N as "ZCPR" or MicroShell) that
knows about path searching.


-----		----		-- *-
FILES		DISK		DESCRIPTION
-----		----		-- -

READ.ME		1		This file
CC.COM	   +	1		BDS C Compiler (part I)
CC2.COM	   *	1		BDS C Compiler (part II)
CLINK.COM  +	1		BDS C Linker
CLIB.COM   +	1		BDS C Librarian

DEFF.CRL   *	1		BDS C Standard Library object files
DEFF2.CRL  *	1

C.CCC	    u*	1		BDS C Run-time package ojbect code

BDSCIO.H   *	1		Standard C header file
HARDWARE.H *	1		Standard hardware-   ial on the C
language. For most of the first three years of BDS C's distribution, when
Lifeboat was the exclusive distributor, the textbook was distributed with
every copy of the compiler. Nowadays the book is more readily available, and
many users who order BDS C may already own a copy and not want to pay for
another one. Therefore some distributors may choose not to include the
textbook in the standard package; nevertheless, all BDS C users should make
sure to get a copy of the book somehow.
  en,
; return Cy set:
;

vfgfd:	mov	d,a
	sui	8
	rc		;if fd < 8, error
	cpi	nfcbs
	cmc		;don't allow too big an fd either
	rc
	push	d
	mov	e,a	;OK, we have a value in range. Now
	mvi	d,0	;  see if the file is open or not
	lxi	h,fdt
	dad	d	;offset for 3-byte table entries
	dad	d
	dad	d
	mov	a,m
	ani	1	;bit 0 is high if file is open
	stc
	pop	d
	mov	a,d
	rz		;return C set if not open
	cmc
	ret		;else reset C and return

;
; Set up a CP/M file control block at HL with the file whose
; ~ jnz	setnm1	;and go for more if B not yet zero
	pop	b
setnm3:	ldax	d	;skip rest of filename if B chars already found
	call	legfc
	rc
	inx	d
	jmp	setnm3

pad:	mvi	a,' '	;pad with B blanks
pad2:	mov	m,a	;pad with B instances of char in A
	inx	h
	dcr	b
	jnz	pad2
	pop	b
	ret

;
; Process filename having optional user area number prefix of form "<u#>/",
; return the effective user area number of the given filename in the upper
; 5 bits of A, and also store this value at "usrnum". Note that if n K  simple null-terminated name is pointed to by DE:
; Format for filename must be: "[white space][d:]filename.ext"
; The user number prefix hack is NOT recognized by this subroutine.
;

vsetfcb:
	push	b
	call	igwsp	;ignore blanks and tabs	
	push	h	;save fcb ptr
	inx	d	;peek at 2nd char of filename
	ldax	d
	dcx	d
	cpi	':'	;default disk byte value is 0
	mvi	a,0	; (for currently logged disk)
	jnz	setf1
	ldax	d	;oh oh...we have a disk designator
	call	mapuc	;make it upper case
	sui	'A'-1	;and fud  o user
; number is specified, the current user area is presumed by default. After
; the user area prefix is processed, do a regular "setfcb":
;
; Note: a filename is considered to have a user number if the first char
; 	in the name is a decimal digit and the first non-decimal-digit
;	character in the name is a slash (/).

vsetfcu:
	push	b	;save BC
	push	h	;save vcb pointer
	call	igwsp	;ignore blanks and tabs	
	call	isdec	;decimal digit?
	jnc	setfc2	;if so, go process

setfc0:	push	d	;save tex I ge it a bit
	inx	d	;advance DE past disk designator to filename
	inx	d
setf1:	mov	m,a	;set disk byte
	inx	h
	mvi	b,8
	call	setnm	;set filename, pad with blanks
	call	setnm3	;ignore extra characters in filename
	ldax	d
	cpi	'.'	;if an extension is given,
	jnz	setf2
	inx	d	;skip the '.'
setf2:	mvi	b,3
	call	setnm	;set the extension field and pad with blanks
	xra	a	;and zero the appropriate fields of the fcb
	mov	m,a
	lxi	d,20
	dad	d
	mov	m,a
	inx	h
	mov	m,a	;zero random record bytes of fcb  t pointer
	mvi	c,gsuser  ;else get current effective user number
	mvi	e,0ffh
	call	bdos
	pop	d	;restore text pointer

setfc1:	rlc		;rotate into upper 5 bits of A
	rlc
	rlc
	sta	usrnum	;and save
	pop	h	;restore junk
	pop	b
	jmp	setfcb	;and parse rest of filename

setfc2:	mvi	b,0	;clear user number counter
	push	d	;save text pointer in case we invalidate user prefix
setfc3:	sui	'0'	;save next digit value
	mov	c,a	; in C
	mov	a,b	;multiply previous sum by 10
	add	a	;*2
	add	a	;*4
	add	a	;*  
	inx	h
	mov	m,a
	inx	h
	mov	m,a
	pop	d
	pop	b
	ret

;
; This routine copies up to B characters from (DE) to (HL),
; padding with blanks on the right. An asterisk causes the rest
; of the field to be padded with '?' characters:
;

setnm:	push	b
setnm1:	ldax	d
	cpi	'*'	;wild card?
	mvi	a,'?'	;if so, pad with ? characters
	jz	pad2

setnm2:	ldax	d
	call	legfc	;next char legal filename char?
	jc	pad	;if not, go pad for total of B characters
	mov	m,a	;else store
	inx	h
	inx	d
	dcr	b
	  8
	add	b	;*9
	add	b	;*10
	add	c	;add new digit
	mov	b,a	;put sum in B
	inx	d	;look at next char in text
	ldax	d	;is it a digit?	
	call	isdec
	jnc	setfc3	;if so, go on looping and summing digits
	cpi	'/'	;make sure number is terminated by a slash
	jz	setfc4
	pop	d	;if not, entire number prefix is not really a 
	jmp	setfc0	; user number, so just ignore it all.

setfc4:	inx	d	;ok, allow the user number
	pop	h	;get old text pointer off the stack
	mov	a,b	;get user number value
	jmp	setfc1	;and     E]
Copyright (c) 1982 by Leor Zolman

Please don't rip me off.

       !  9"'* "0 2,  2+:U<2-:V:+2.:W< :,<2M1:\ 242  2282t2a2b2=2*22322<2;222522)><2! ("n! "6!#>] }/!#
!"": Ɓo& 6  d!#qd"ʳ-4SY2 b8Kt}i>n428O28P238R¨}44g. "n8AQ2=252-}82.8DQ428X2*8M4"68E284   ng too long (or missing quote)
 Attribute mismatch from previous declaration
 elbowroom unused 
Can't find CC2.COM; writing CCI file to disk
 Include @ Illegal "{" encountered externally Declaration too complex
 Missing from formal parameter list:  Compilation aborted by ^C
 >%
:*4
>H<
M :Y  *':)  >H>
H:Xz
 z
 
! 

*DM!""x
"! w#} 
Ð
:!"*"""!e 6C#6D#6B:2\ ,!"cQ
>*p!  22f   "98C42;8d7ͥ!  ͥ())))O 	>"H*~KH#}=<!Od4@4 d qd d͚> ͚x?ЇGÈ0O
?͚?!"*n"pF$6*:3
22/*34ͳHͮ
ͅ
w:t%
!6K* *|?o& +͑!P	:![	>p<
))))O 	>"H*~ CC2     COM    $$$     SUB     d qd d͚> ͚x?ЇGÈ0O
?͚?!"*n"pF$6*:3
22/*34:  Hͮ
ͅ
w:t%
!6K* *  " .O
O
&\
:ff>2fjf=L*2O

2O
"!  
jWHO2f#
O
:> H> H͑|}Mismatched control structure
 Expecting "while"
 Illegal break or continue
 Bad "for" syntax
 Expecting "{" in switch statement
 Bad "case" constant
 Illegal statement
 Too many cases (200 max per switch)
 Can't have more than one `default:'
 :1=W|ڰ:)¡!f
* "02)Ê!  "!"~!"2*p+:!af!}f͞\
   |?o& +͑!P	:![	>p<
))))O 	>"H*~ CC2     COM    $$$     SUB     d qd d͚> ͚x?ЇGÈ0O
?͚?!"*n"pF$6*:3
22/*34:  Hͮ
ͅ
w:t%
!6K* *|?o& +͑!P	:![Close error
 Error on file output...disk full?
 ": option error
 Encountered EOF unexpectedly
 (check curly-brace balance)
 Unmatched right brace
 Undeclared identifier:  Illegal external statement
 Bad declaration synta  # A zʋʶʈ]]ttt>2a*"_d2a!(fAڌz¥zÒ¹͞zz>zz!͞G2͞2zd*~s#r#s#r#"~:<2+*~++++"~:=2:!> >j> >}|Yc*#"+>ʛ!>z> >^>> >>> d>> >*"i  . x
 Missing legal identifier
 Function definition not external
 Need explicit dimension size
 Too many dimensions
 Bad dimension value
 Bad parameter list element
 Redeclaration of:  Missing semicolon
 Expecting "{" in struct or union def
 Illegal structure or union id
 Undefined structure id
 HarlanE!Expecting "("
 Unmatched left parenthesis
 Sorry; out of memory
 I'm totally confused. Check your control structure!
 Out of symbol table space; specify more...
 Too many functions (63 max) Stri   > >>͞**i}2h"*DM*e-A`i">|= :h/< t>=f8/ >DM"^g
§A
ҧ>%>>>h>^>*"!"
"͞͞*~+++F+Nq#p#"2s#r#"~*<!d*"22]!"!4cTx5zWʌ!r*w#w#AxO®yOØʹ!Æs#r#:]"yO>y ^:]!4~2]5!<T  go store it and parse rest of filename


;
; Test if char in A is legal character to be in a filename:
;

legfc:	call	mapuc
	cpi	'.'	; '.' is illegal in a filename or extension
	stc
	rz
	cpi	':'	;so is ':'
	stc 	
	rz
	cpi	7fh	;delete is no good
	stc
	rz
	cpi	'!'	;if less than exclamation pt, not legal char
	ret		;else good enough

;
; Map character in A to upper case if it is lower case:
;

mapuc:	cpi	'a'
	rc
	cpi	'z'+1
	rnc
	sui	32	;if lower case, map to upper
	ret

;
; Igno r ent CP/M user area for
; user with file I/O:
;

vsetusr:
	push	b	;SET user number to upper bits of A, save current:
	push	h
	push	d
	push	psw	;save A
	mvi	c,gsuser ;get user code
	mvi	e,0ffh
	call	bdos
	sta	curusr	;save current user number
	pop	psw	;get new user number byte
	push	psw
	rar		;shift user number down to low bits
	rar
	rar
	ani	1fh	;and mask off high order garbage
setu0:	mov	e,a
	mvi	c,gsuser  ;set user code
	call	bdos
	pop	psw
	pop	d
	pop	h
	pop	b
	ret

vrstusr:
	pu  re blanks and tabs at text pointed to by DE:
;

igwsp:	dcx	d
igwsp1:	inx	d
	ldax	d
	cpi	' '
	jz	igwsp1
	cpi	9
	jz	igwsp1
	ret

;
; Return Cy if char in A is not a decimal digit:
;

isdec:	cpi	'0'
	rc
	cpi	'9'+1
	cmc
	ret


;
; This routine does one of two things, depending
; on the value passed in A.
;
; If A is zero, then it finds a free file slot
;  (if possible), else returns C set.
;
; If A is non-zero, then it returns the address
; of the fcb corresponding to an open file  sh	b
	push	h
	push	d
	push	psw
	lda	curusr	;get last saved user number
	jmp	setu0	;and go set current user area to that

	ENDIF		;end of CP/M-related file I/O routines


	IF	NOT CPM
main:	equ	$	;where main program resides when not under CP/M
			;(under CP/M, the data area comes first)
	ENDIF


;
; Ram area:
;

	IF 	CPM
ram:	equ	$
	ENDIF

	IF	NOT CPM	;if not under CP/M, use custom ram area address
	org	ram
	ENDIF

	ds	20	;reserved by BDS

errnum:	ds	1	;error code from file I/O o   whose
; fd happens to be the value in A, or C set if there
; is no file associated with fd.
;

vfgfcb:	push	b
	ora	a	;look for free slot?
	mov	c,a
	jnz	fgfc2	;if not, go away
	mvi	b,nfcbs	;yes. do it...
	lxi	d,fdt
	lxi	h,fcbt
	mvi	c,8
fgfc1:	ldax	d
	ani	1
	mov	a,c
	jnz	fgfc1a	;found free slot?
	pop	b	;yes. all done.
	ret

fgfc1a:	push	d
	lxi	d,36	;fcb length to accommodate random I/O
	dad	d
	pop	d
	inx	d	;bump to next 3-byte table entry
	inx	d
	inx	d
	inr	c
	dcr	b
	jnz	fgfc1
f  perations
pbase:	ds	2	;screen-DMA address
ysize:	ds	2	;screen width
xsize:	ds	2	;screen height
psize:	ds	2	;screen length

rseed:	ds	8	;the random generator seed

args:	ds	14	;"arghak" puts args passed on stack here.

iohack:	ds	6	;room for I/O subroutines for use by "inp"
			;and "outp" library routines

allocp:	ds	2	;pointer to free storage for use by "sbrk" func
alocmx:	ds	2	;highest location to be made available to the
			;storage allocator

room:	ds	30	;reserved for use by BDS C system ] gfc1b:	stc
	pop	b
	ret		;return C if no more free slots

fgfc2:	call	vfgfd	;compute fcb address for fd in A:
	jc	fgfc1b	;return C if file isn't open

	sui	8
	mov	l,a	;put (fd-8) in HL
	mvi	h,0
	dad	h	;double it
	dad	h	;4*a
	mov	d,h	;save 4*a in DE
	mov	e,l
	dad	h	;8*a
	dad	h	;16*a
	dad	h	;32*a
	dad	d	;36*a
	xchg		;put 36*a in DE
	lxi	h,fcbt	;add to base of table
	dad	d	;result in HL
	mov	a,c	;and return original fd in A
	pop	b
	ret

;
; The following two subroutines change the curr n  code
uroom:	ds	20	;available for use by user


tmp:	equ	room	;this is misc. garbage space
tmp1:	equ	room+1
tmp2:	equ	room+2
tmp2a:	equ	room+4
ungetl:	equ	room+6	;where characters are "ungotten"
unused:	equ	room+7
curusr:	equ	room+8	;used to save current user number during file I/O
usrnum:	equ	room+9	;set by "setfcu" to user number of given filename

mode:	equ	room+10	;tty mode
freeze:	equ	room+11	;true if output frozen (^S)
pending: equ	room+12	;true if input character waiting
pendch:	equ	r     ³> s":>2!bT:o& ))####͟>:!x`~#S*}|*"Y8͞s͞> >h>Y8s###"!Y͞A#Y8J>*~+~+ngc*"AJ>*~++*""*DM!"xB**p͆!
~S ,`i**s#r#w#k"**""DM**xʛw#Î"DM*	DM"͈xw+÷ *+"2!  "2*#"    :qG|!:2f
 w#p:yp1+~w#>_ J"))))!" ~:2znЯ2z*DM!"x}7ʏ v+}o	 "l~?W:zʬ È*ѯ*nDM!"6 #x~Gѯ<7~#ypp222222y2<2͸!  """!""*p+M:*"z\
:i:o!	"
!  "2!4:´:!f=2::<22*DM*##q#p*":i*"i>>:G:p:`n:> >  	 *#"a{ >2t:3!	>*͑*͑>~H#>_ !dO
pHd*""!"*""*DM*p*w#{z":5!e 6C#6C#6I:2\ ,*"!"cQ>:-2=:._  
:,<2=:+_  6
6-*0=w# +6 !c	>è! Ww#A1 :::*6:8*9*0:)*':**W*Y*0DMÀ     ! Ã ""2"
2""2	"22\ 2>2 V*#*0	DM*~+z   Wy 2:z:"))))~,:*w#6~w#~G:w#:a!d:*͌"WʒʒU͌::bS©Ͳ:UͲ:y2 :w#:!:w#*DM##":<:y 6#:w#*DM#":q#p#####"*#">}|> >a2<2[a'wր2p2͗+#~ʈ6͆*͆ʦ~ʢ6#Ô> >*+:|ʽ*}}|>2*"! "+"p!>` Ͳ   #q#p\ 2h  !+
\  > 2| \ 2h  \  !\  !+
 ~*|y}ʃ#hʏ>Ä7!>ͨ>/H
ҳ0H 

ҵxͭí!  "! 0"#|+!~ >0<:w60+|/g}/o#ɷ/<'=/< 2sS:sbkwyLxL=O+4O2rd>ʪ.dʌ¹\ʹ\ʹ~ny(.ðo& ))##dA~~G>*DM_ "DM*͛""   :z!Xy 22>2k/Q`җ>2͌Y1::>2!  "+"222͟!22*+"}2"͊"Oʿ!d*͌"#####~!X͌Ì:2**::!  "">22:"2Ci=!d"G":Q*"22*"DM"""͊q#p22>2͗2))))"^#V+::::!2Ý:!dɯ222y<2k!  ""*"   ͈G>:2	#`i
wy<x+?*pT]~y#~a"#~#~GxT#~lAڍ#~#~#M#M#~¨#Þo& ))###DMͺM:~#xºA<Gȷ!af*#"A:a**_"!">**"!"> >>?{0:?A[?_a{?pҙÏͤʶ!9d*"*"!If*":ü¼ͼý*   22|4:|̟!: *"::2@!
2T4 !dp4!4~ 	 p|!M`ҙ:c :c !	Xc "}:> :z»:c :c ::' > 2k<2*"*l+"##~#fo"f *l+":' ~' ~G:8 ##N#F*x8 y8 2kf !Xdd!!	1 O"W ~»' %
>2|~wf *͌} :|'  "͞ʑ  "* :ʨ !M>22"!  "*:| *" : =2>2͞>2*"#"͞:2  oom+13	;if pending true, this is the character
quitc:	equ	room+14	;the general system abort character (^C usually)
spsav:	equ	room+15	;saved SP value from CCP
;	equ	room+17	;where next thing goes

echo:	equ	1	;masks for "mode" byte...echo mode
quit: 	equ	2	;quit enabled
flow:	equ	4	;^S/^Q protocol honored
strip:	equ	8	;strip parity
expand:	equ	16	;expand '\n' into CR-LF on output

;
;%-- (
; The following data areas are needed   /*
	External data used by DIO.C for directed I/O simulation:
	(BDSCIO.H must also be #included in the main file.)
*/

#define BUF_CONS 1			/* true if console buffering is
						desired	(see DIO.C)	   */

#define ABORT_CHECK 1			/* true to recognize keyboard abort */

char _diflag, _doflag;			/* flag if directed I/O being used */
char _pipef, *_pipedest;		/* true if a pipe is being filled  */
char **_savei, **_nullpos;		/* used to remember position in
					   command line when piping 	   */
cha  only if running under CP/M:
;
	IF	CPM
;
; The fcb table (fcbt): 36 bytes per file control block
;

fcbt:	ds	36*nfcbs	;reserve room for fcb's (extra byte for IMDOS)


;
; The fd table: one byte per file specifying r/w/open as follows:
; 	bit 0 is high if open, low if closed
; 	bit 1 is high if open for read
; 	bit 2 is high if open for write	 (both b1 and b2 may be high)
;	bits 3-7 contain the user number in which the file is active (0-31)
;

fdt:	ds	3*nfcbs	;3 bytes per fcb: 1 for active,   r _dibuf[BUFSIZ], _dobuf[BUFSIZ];	/* I/O buffers used for direction  */

int  _cungetch;				/* NULL or ungotten character	   */

#if BUF_CONS				/* console buffering data	   */

char _conbuf[MAXLINE + 2];		/* console input buffer used for 
					    non-directed standard input	   */
char *_conbufp;				/* pointer to next character to
						read from console buffer   */
#endif
>   r/w, etc., and
			;		  2 to specify highest sector num seen

;
; The command line is copied here by init:
;

comlin:	ds	131	;copy of the command line pointed to by entries
			;in arglst


;
; This is where "init" places the array of argument p ointers:
;

arglst:	ds	60	;the "argv" paramater points here (well,
			;actually to 2 bytes before arglst). Thus,
			;up to 30 parameters may be passed to "main"
	ENDIF		;(enough for you, Andy?)

;
; End of CP/M-only data area
;
--    X[-- ]-

	IF	CPM
main:	equ	$	;where "main" program will be loaded under CP/M
	ENDIF

	end

6 inters:
;

arglst:	ds	60	;the "argv" paramater points here (well,
			;actually to 2 bytes before arglst). Thus,
			;up to 30 parameters may be passed to "main"
	ENDIF		;(enough for you, Andy?)

;
; End of CP/M-only data area
;
--       y! M!":!:x!!Bh!.!! "M!͑!:x!I!!ah!"2x>2xq!!wdoge!T]!  x!DM*͂!":G:G:G:G:*w#:G:w#*s#r#*s#r#*s#r#:k ""*#": *|!":y!":!"DM`i: t":t":t":^"*DMxt"! t"t"t"t"͂!DM*:ʒ"*͛""!  Ó"	"2yxʤ"`iy`iG:Illegal colon
 Undefined label used
 Syntax error
 Bad constant
 Bad octal dig   O#defin#unde#i#ifde#ifnde#endi#elsWarning: Ignoring unknown preprocessor directive
 String overflow; call BDS
 EOF found when expecting #endif
 Bad parameter list syntax
 Missing parameter list
 Parameter mismatch
 Not in a conditional block
 Conditional expr bad or beyond implemented subset
 !_9"L$2!C"6 22Q$2S$2P$<2R$2j*:Q$!y)"
*"J$|*+"J$*:R$@..#*!);4+!%);47+!);4`+!);4n+!);4}+:R$*!);4J,!	);4=,**!*)*:R$*2*+  6 it
 Bad decimal digit
 Curly-braces mismatched somewhere in this definition
 Disk read error
 Cannot open:  #include files nested too deep
 No user area prefix allowed
 Unclosed comment in:  BD Software C Compiler v1.50a (part I)
 Usage:
cc <source_file> [-p] [-o] [-a <x>] [-d <x>] [-m <addr>] [-e <addr>] [-r <n>]
 !:"]:2a:*p":2v<2/q$%
6 #6""­$:/ʍ$e  $>Cq$!b#>:vʥ$:V:+ĝ͗(*:ɯ2u2:2/<2v! "_:*:>2:ͯ'$(y$\
h%%+~$$6#$>:u>  O +*J$#"Y*+>+:Q$(+!)"
=2Q$2R$2S$*:Q$"+:S$"+X+:R$>U+2R$>2S$*:R$,-.,:R$,-./,:R$,! ͐+,͡+G.x!*"
+ڛ+G.&ʹ+|ʹ+x+͡+oy&x+ɵ.(+͡+G.)7x?!++ط>=ͫ2ͫ2,+ͫ2,<G:Q$<2Q$:S$:R$3,x3,>2R$2S$*-.*6**-.W,,b,*,"6 .¡,.{,>Ç,.x,
`i"L$C͆ڝ,!])
*`iO.{Һ,w#§,Ë,!P#,~#fo,,xð,#,w#p,ç,*"   !#>͗(%
ʄ%
ʄ%$:uh%y/B%::*>/B%:u=$2u$*b%::/>*b%:;$:u<2u$2:$qy#%::2:"b:>##2:$>w}%"°%::%::'&::>ʨ%2:>"&\%::>\&#͢'"%\%$w&*%::/>*&::>*&+>2u$I&::&2:::#&2:#$
2&":#͢'ONh%͢'C&͢'&4&͢'&=&:,2::+2:d:"ʁ&<&2&:Up&:,2::V~&:+2:ͯ'>
ʨ&ʨ&&ʨ&>ʨ&"ʨ&Á&
&&/¨&&*¨&&
&*b:6#"b:ý&*½&&/&è& 	ͯ'>'}  g i& ~(> -@--!)"
w#*L$DMq#p#"*p͆G2 !P#.)X-y.k-:<2X-s#r#x-2T$"-\--"-x-,¢-:T$-ò-)¶-:T$-=2T$x-'-(x-:T$<2T$x-\--'-x-{p-.,-X-)T-7.&!..>&!.i& .Ϳ.*N$>/:P$a.!);4[.#m.a..m.p.:P$ʐ."ʆ.\b.b.:P$/2P$b."ʆ.' .̈́2c.{b..ڴ.2P$@.pҴ.c.!C~7"N$.*N$ 	 	.&.Ϳ.F#~#foxʐ/G͌   '/'x2:'!\ 0(!':&(':\ /'::<2\ =2:_ :,:+::2,::2+_  *b:6#:a:<2a:=g'6#":q$2<:a:=2a:}'6#2+_  2,_ ':<%
$ͯ'ګ'>*_:#}'(! ͈~"_: *]:'"]:*]:]"]:'\ !
( 
(_:
(y(w#(y(*p͆!p#
::47?L(7@w#h(.X(h(6  6 ͋(ځ(w#i(͋(x(> w#(.7ȷ7?:\ ¦( <@H>:H] (>.H(O
H ((\  (7!P#


   .(/!)"
@-/!)"
)/!)"
#~:/>l/~#h/J/:/O !P#	~#fo~~#Y/:/M!#͐/:G/< x>Å/~#/	& 	}/< x~ʽ/#ñ/22"ʃ0>21> 2y/ >}|/x_X0A0[070xO !c0	~#fo~K0A0;4yA0O~/>60~#A0#0X0!"/p/X0N8Q8W8t8888888899(9?9U9}ʄ0*s#r#"d#կO2c0"00
0@1w͈#!c4 0!f"6*d:cwN ͆0} 0++!1>*+} x /*
	Directed I/O package for BDS C v1.50   LZ -- 11/82

	The following functions make up the directed I/O library:

	1. dioinit(&argc,argv)		Make this the first thing you do in
					your "main" function, to process
					redirection commands on the CP/M
					command line.

	2. getchar()			Gets a character from the keyboard,
					or from a directed input file if one
					was specified on the command line.

	3. putchar(c)			Puts a character out to the console,
					or to a directed output file i  *argv;
		{
			...			/* declarations		*/
			dioinit(&argc,argv);	/* initialize redirection */
			.
			.			/* body of program	*/
			.
			dioflush();		/* clean up redirection */
		}
			
	When linking your program, simply make sure to specify DIO on the
	command line during linkage.

	NOTES:

	0. The console input may be raw (unbuffered, one char. at a time) or
	   buffered (entire line must be typed before chars are returned,
	   allowing standard editing features, and characters come back one ; f one
					was specified on the command line.

	4. dioflush()			Flushes directed output file, if open,
					and closes all directed I/O files (if
					any.) This must be called before your
					program exits or returns to CP/M.

	To activate redirection: Four special arguments may be given
	on the command line to the generated COM file...

		>foo	causes "putchar" to place characters into the file
			named "foo" instead of to the console.

		+foo	like >foo except that the characters are ALSO se  
	   at a time AFTER the entire line is typed). The default is raw; for
	   buffered console input, change BUF_CONS definition in DIO.H from
	   0 to 1, then recompile this file and all files in your program.

	1. Redirection and pipes work only for TEXT. This mechanism should
	   not be used for binary data.

	2. Do not define your own "getchar" or "putchar" when using the DIO
	   package, or things will get confused.

	3. Multiple pipes may be chained on one command line. For example,
	   the  T nt
			to the console.

		<foo	causes "getchar" to return characters from the file
			named "foo" instead of from the keyboard.

	 command |prog	causes the standard output of the command specified in
			"command" to be fed into the standard input of another
			program, "prog". (BOTH "command" and "prog" must be
			compiled with DIO)

	(Note that there must never be any spaces between >,+,< or | and the
	 corresponding filename.)

	When no "<" or "|" operator is used, standard input comes from t  following command feeds the output of program "foo" into the
	   input of program "bar", the output of "bar" into the input of
	   program "zot", and the output of "zot" into a file called "output":

		A>foo arg1 |bar |zot arg2 arg3 >output <cr>

	   "arg1" is an actual argument to "foo", and "arg2" and "arg3" are
	   actual arguments to "zot". This illustrates how actual arguments
	   may be interspersed with redirection commands. The programs see
	   the actual arguments, but command line preproc  he
	console and all standard line editing characters are recognized (a 
	new feature of v1.45). To indicate end-of-file, you must type
		^Z <CR>
	(control-Z followed by	a carriage-return.)

	When no ">" or "|" operator is used, standard output goes to the
	console.
	 
	A program allowing redirection must have the following form:

		#include "bdscio.h"		/* standard header file	*/
		#include "dio.h"		/* directed I/O header	*/

		...				/* other externals, if any */

		main(argc,argv)
		char *  essing handled by the
	   "dioinit" function cause the programs to never need to know about
	   the redirection commands. Note that all three programs ("foo", "bar"
	   and "zot") must have been compiled and linked to use the "DIO"
	   package.

	4. The ABORT_CHECK defined symbol in DIO.H controls whether or not
	   keyboard interrupts are to be recognized during operation of DIO.
*/


#include <bdscio.h>
#include <dio.h>

#define CON_INPUT	1		/* BDOS call to read console	   */
#define CON_OU   v | *	"/> >1P ͆:1!1!O !1} \"_1M1U1@1g1\72^N}1>
T1>	B1>R1>F1>\'1ҷ1::^!"2o1g}1|11g}1|g}o'1:1ñ108?0'}2ͫ2 !  [2X#2>2!"7ʹ22ʹ2Y2))))o,2)))o2>2ʹ2Y2!"T])))_ ͫ2[2ʹ2Y2!#V2̈́22 g1O'ʟ2g1G'ʟ27`EiH0
?ͫ2
?ͫ2?!  ""2*p&3722*+"!  "&3  *i ]++||<<<<=--->>>>^޼/Q    	8778|g}o!8|g}o-8|g}o@8|J8}J8! |<8}<8!  ɠ!RETURΎBREAːREGISTEҞBEGIΛCHAҀCONTINUőCASŘSTRUCԋSWITCȗSIZEOƏSHORԀDϕDEFAULԙELSœ%UNSIGNEĂUNIOΌENĜ&&FOҔVOIāWHILŖGOTύIƒINԁ*   ! 32*#"&3G$3\
*#"2*p+!  "W3*"#\3"B4\
5353!_9"]96 2|3*#"!#f3!4ä33!5¤3ʤ3ʤ3i3pj3 pұ33ú3j3կ2y͏43!04!y4*]933w#3 4+~w#*s#r#:y4"]96 y >}|ä3Duplicate label
 2p3Z4!4G4g4!5G4G4͏4҉4!" pڈ4|4ͨ4G4!_9~7;4~#4##Õ4~#foy >}|~G4ѯ<~#44xp4p?44!  "*p      5 +A55858585858557855\
!R#"P#6 !r#"p#͢5_5A55+ m5>}e5|e5>}|y5y/< >55Ͱ5556Y6655555͞7|6͢57͢557͢5!66166+56I6͢57?7ogɯ͹66666ʈ66ʴ6666E76p66ʚ6H6yʢ6ڢ6͹6Y6666E76g66*P##"P#w*P#~+"P#*P#~6DM*p#V+^+"p#*p##s#r"p#	      z C7<ɯY7!  x}7O77!  z}7p7{}7`i#c77^7J77	«7`i¸7x)ð77x|g}oý77|}! +,7xE! +y,77|+##	8778|g}o!8|g}o-8|g}o@8|J8}J8! |<8}<8!  ɠ!RETURΎBREAːREGISTEҞBEGIΛCHAҀCONTINUőCASŘSTRUCԋSWITCȗSIZEOƏSHORԀDϕDEFAULԙELSœ%UNSIGNEĂUNIOΌENĜ&&FOҔVOIāWHILŖGOTύIƒINԁ*      TPUT	2		/* BDOS call to write to console   */
#define CON_STATUS	11		/* BDOS call to interrogate status */

#define CONTROL_C	3		/* Quit character		   */
#define STDERR		4		/* Standard Error descriptor (sorry,
					   Unix fans, 2 was already used.) */
#define INPIPE		2		/* bit setting to indicate directed
					   input from a temp. pipe file    */
#define VERBOSE		2		/* bit setting to indicate output is to
					   go to console AND directed output */

/* 
 *	The "dioinit" function must be calle  TDERR);
				exit();
			}
			_doflag++;

	     movargv:	if (!_pipef) {
				for (j = i; j < argc; j++) argv[j] = argv[j+1];
				(argc)--;
				i--;
				_nullpos--;
			 } else {
				argc = argcount;
				argv[argc] = 0;
			 }
			break;

		    default:	/* handle normal arguments: */
			argcount++;
		}
	}
}


#undef argc

/*
 *	The "dioflush" function must be called before exiting the program:
 */

dioflush()
{
	if (_diflag)
	{
		fclose(_dibuf);
		if (_diflag & INPIPE) unlink("tem  d at the beginning of the
 *	"main" function:
 */

#define argc *argcp

dioinit(argcp,argv)
int *argcp;
char **argv;
{
	int i,j, argcount;

	_diflag = _doflag = _pipef = FALSE;  /* No directed I/O by default   */
	_nullpos = &argv[argc];
	_cungetch = NULL;		/* initialize ungetch		*/

#if BUF_CONS
	_conbuf[0] = 0;			/* no characters in buffer yet	*/
	_conbufp = _conbuf;		/* point to null buffer 	*/
#endif

	argcount = 1;

	for (i = 1; i < argc; i++)	/* Scan the command line for > and <  pin.$$$");
	}

	if (_doflag)
	{
		putc(CPMEOF,_dobuf);
		fflush(_dobuf);
		fclose(_dobuf);
		unlink("tempin.$$$");	/* in case previous pipe was aborted */
		rename("tempout.$$$","tempin.$$$");
		if (_pipef) 
		{
			*_savei = "<TEMPIN.$$$";
			*_nullpos = NULL;
			if (execv(_pipedest,_savei) == ERROR)
			{
				fputs("\7Broken pipe\n",STDERR);
				exit();
			}
		}
	}
}


/*
 *	This version of "getchar" replaces the regular version when using
 *	directed I/O. Note that the "BUF_CONS"    */
	{
		if (_pipef) break;
		switch(*argv[i]) {

		   case '<':		/* Check for directed input:	*/
			if (!argv[i][1]) goto barf;
			if (fopen(&argv[i][1], _dibuf) == ERROR)
			{
				fputs("Can't open " ,STDERR);
				fputs(&argv[i][1],STDERR);
				fputs("\n",STDERR);
				exit();
			}
			_diflag = TRUE;
			if (strcmp(argv[i],"<TEMPIN.$$$") == 0)
				 _diflag |= INPIPE;
			goto movargv;

		   case '|':	/* Check for pipe: */
			_pipef++;
			_pipedest = &argv[i][1]; /* save prog name for exe  defined symbol (in DIO.H)
 *	controls whether the console input is to be raw or buffered (see
 *	item 0. in NOTES above)
 */

int getchar()
{
	int c;

	if (_cungetch) {
		c = _cungetch;
		_cungetch = NULL;
		return c;
	}

	if (_diflag) {
		if ((c = getc(_dibuf)) == '\r') c = getc(_dibuf);
	}
	else

#if BUF_CONS		/* For buffered console input, get a line of text   */
	{		/* from the BDOS (using "gets"), & insert newline:  */
		if (!*_conbufp) {   
			gets(_conbufp = _conbuf);
			_conb  cl */
			if (argv[i][1]) 
			{
				argv[i] = ".TEMPOUT.$$$";  /* temp. output */
				_savei = &argv[i];
			}
			goto foo;

		   case '+': 
			_doflag |= VERBOSE;
			
	     foo:   case '>':	/* Check for directed output	*/
		
			if (!argv[i][1]) 
			{
		    barf:   fputs("Bad redirection/pipe specifier",STDERR);
			    exit();
			}
			unlink(&argv[i][1]);
			if (fcreat(&argv[i][1], _dobuf) == ERROR)
			{
				fputs("Can't create " ,STDERR);
				fputs(&argv[i][1],STDERR);
				fputs("\n",S S uf[strlen(_conbuf) + 1] = '\0';
			_conbuf[strlen(_conbuf)] = '\n';
		}
		c = *_conbufp++;
	}
#else			/* for raw console input, simulate normal "getchar": */
		if ((c = bdos(CON_INPUT) & 0x7f) == CONTROL_C) exit();
#endif

	if (c == CPMEOF) return EOF;	     /* Control-Z is EOF key 	*/

	if (c == '\r') 
	{
		c = '\n';
#if !BUF_CONS
		if (!_diflag) bdos(2,'\n');  /* echo LF after CR to console */
#endif
	}
	return c;
}


/*
 *	This version of "putchar" replaces the regular version when 	 a	  s        !  91Y:<2:37E"
* ">2/7  >2@2T@2@=2S@2l@2H@6T'K"Z@!6B"\@*Y|g}o"`@Y"b@*Y"@%%p7"@X"}@:	6#*s#rw#w#w#*Ys#r#"@!K"@6!  "d@!A"B!B"4B! "h@9*}@ͨ6"}@~!T@4*@+"Z@:S@!B@6K* *@p7|?o& +27):  *
:  p7*Z@#DM*++><wÁw+xw#>:E E$$$     SUB    
copyright (c) 1980
by Leor Zolman
 *Ys#r#"@!K"@6!  "d@!A"B!B"4B! "h@9	  9 7k ͜	:@đ	w ͜	̑		:@:5	:@?	'-4͐8>7:@g	M ͜	:@đ	\ ͜	̑		 ͜	:@đ	 ͜	̑	:@7:@72@{7z7*O2Q@2@2@2@2@2@!  "@"@̓6 		#>͜*	:@'-A
̓6vn̓6
)
'
/ͫ7#͜*8
:@;
'-	̓6AR
̓6	:X@:Q
2X@2Q
:O@*d@7̓6{

:O@2O@>õ
Ͷ¥
ʥ
*>2O@2Q
xõ
& xµ
:O@2O@"d@#"2O@:Q

*+4+2Q
2X@̓6
*d@"d@T0Ϳ7"d@v?#>	  t *}@_ !  ">@! 0"@@#|C+!A@~ 2>0<:=w 60+*>@7:ʀ*~#fo#DM>YҲp7!Y
w#zp"Z@6!e 6C#6C#6Iͻ!Yқ w# :O|ڑ17Ã\  2| +/7Ã\  \  =/7Ã\  7\ 2h  \ 2h  /7Ã!e 6C#6R#6Lͻ*@*@*\@6#s#r!6B͋͋͋͋*@͋m!f 6C#6I: ~*Z@|¡}ʫ#ʷ>ì7:  27Ãɯ2O@͹>2O@*d@"f@T'	  7 2Q@°2@>2@2Q@#^#V#*^@N#F#x-y7^ {K"m@5͐8q6"m@q6"o@5͐8F#xn~7`7*o@l9!@^#V#zp7A|7q6+r+s##q#p#w#w#^#V#"@>2@2@̓60ͫ7͈?͐&"m@"@:@b1Ϳ7:@@)2V@:@	<2@̓6*@#"m@!  "@94͐82V@)6:@<2@>2@:@>
2@:	*"@>2@*m@|k=4͐8>`7>i7ͅ(:@ʵͥ)ʖ:Q@)͛2Q@#:@ʯͥ)¯͛2@)ʻ0Ϳ7*@*@*@*@*@*@:X@2X@.@.\.:@2E@'-2Q@2X@2	  x 2X@2Y@"̓6G:O@2O@x"G2O@xd:X@M̓6A#@."̀. M(07G:O@2O@xdG2O@x}v*͚%&͚*d@ͷͶʖ̓6"d@#ÃңͶ>  ":O@>2O@2O@*d@ͷ"d@G:O@2O@xG2O@x̓6"}@2@̓6U#@.̀.2Q@Eͺ)P)P);'-4͐8P:@PZ)>2O@\Z){>#@.̀.)yͥ)y:@<2@¸#@.̀.ͳ*.¡*@p7"@'-A*585>2@Ð8:@ů2@#̓6:O@>2@:O@*ͥ@.̀.ͥͥ*:O@	  m @*:@*@"K@"@"@"@"@"@"@40Ϳ7#	:E@m̀.:@[*@x*@"@Ó*@x'-͓Ïx4͐8*@%̀..ʥ.>72@#Z)	'-4͐8*@"m@:@¼.ZÊ:@5͐8Ï|..4͐8͓|.Êl*0Ϳ77	2U@:V@Hg4͐8:U@)o& )"m@4͐85G5.+:@2@>2Q@̓6	'-.g:U@<2U@o& )"o@4*@*@*@*@*@:V@#̓6ʬ*d@:U@<2U@̓6#ʊ+*d@"@"@:U@2̓6"d@:O@2O@g̓62O@:@..=ú2Ϳ7͈?+	   *+4+ͳ*.(*@|!#"@2@:@>2@:@gd2@:@d:@2@:O@:@2@͊+'-A*E4z:@<2@})3͐8:@2@2@:O@4͐8:@ 2@>2@*B^#V#^#V#~w+p+q+r+s x#@.̀.ͩ*ͳ*. *@p7+"@'-A*685Ð8Q#:@2@>2@ͅ(*@):! "m@"@! "@%"@>2@@.ͤ	̀.pͅ(:@/ÿ7G:O@:Q@*x=)ʗͥ)ʗS*l*)	ͥ)¯:@ȯ2@	)	2@A*	:@:@64*@"m@͐82@::@'->n72@>	   V6577(#72V@*@"d@"@"@"@"@"s@!  "@*{@"m@q6"q@*@#:X@<2X@:U@*@*@*d@@.*̓6ʞ"d@+*4+̀.:@'-"@"@2U@A*:@4̐84Đ8:X@=2X@#ͅ():@:@%:@A*ͥ):@%:Q@%	%0Ϳ7̓66ͷB1ÿ7͐&:@JB1Ϳ7	ͫ._*@"@	'-͓2@	*z0Ϳ7#̓6-͐&:@A.ʜ'-J*@"@ͫ	:@2@ :@<2@2Q@:O@̓6& xG>2O@2@>2Q@ͅ(:@:@0		  using
 *	directed I/O:
 */

putchar(c)
char c;
{
	char *static;
	static = "";	/* remembers last character sent; start out null */

	if (_doflag)
	{
		if (c == '\n' && *static != '\r') putc('\r',_dobuf);
		*static = c;
		if(putc(c,_dobuf) == ERROR)
		{
			fputs("File output error; disk full?\n",STDERR);
			exit();
		}
		if (!(_doflag & VERBOSE)) return;
	}

#if ABORT_CHECK
	if (bdos(CON_STATUS) && bdos(CON_INPUT) == CONTROL_C) exit();
#endif

	if (c == '\n' && *static != '\r') bdos(	  /*
	WILDEXP.C 	v1.2	9/25/82
	BDS C Command-line Wild-card expansion utility
	Written by Leor Zolman

	Lets ambiguous file names appear on the command line to C programs,
	automatically expanding the parameter list to contain all files that
	fit the afn's. Returns ERROR if something went wrong; usually, this
	is due to MAXITEMS being set too low; the "MAXITEMS" defined constant
	sets the maximum number of matches that WILDEXP can handle. If you
	need to be able to process directories with more entr	  CON_OUTPUT,'\r');
	bdos(CON_OUTPUT,c);
	*static = c;
}

/*
 * Ungetch function to push back a character:
 */

ungetch(c)
char c;
{
	_cungetch = c;
}
. RROR)
		{
			fputs("File output error; disk full?\n",STDERR);
			exit();
		}
		if (!(_doflag & VERBOSE)) return;
	}

#if ABORT_CHECK
	if (bdos(CON_STATUS) && bdos(CON_INPUT) == CONTROL_C) exit();
#endif

	if (c == '\n' && *static != '\r') bdo s(	 @ ies than this,
	be sure to modify MAXITEMS to be bigger than the largest expected
	directory size.

	An afn preceded by a "!" causes all names matching the given afn to
	be EXCLUDED from the resulting expansion list. Thus, to yield a
	command line containing all files except "COM" files, you'd say:

		A>progname !*.com <cr>

	Another example: to get all files on B: except .C files, say:

		A>prognam b:*.* !b:*.c <cr>

	When giving a "!" afn, "*" chars in the string matches to the end of
	eith	   	  er the filename or extension, just like CP/M, but "?" chars match
	ONE and ONLY ONE character in either the filename or extension.

	To use WILDEXP, begin your "main" function as follows:

	-- -
	main(argc,argv)
	char **argv;
	{
		...				   /* local declarations  */
		if (wildexp(&argc,&argv) == ERROR) /* 1st state. in prog. */
		   exit(puts("Wildexp overflow"));
		dioinit(&argc,argv);		   /* if using DIO	  */
		...
	-- -	   	 w-- 

	and link WILDEXP.CRL in with your program. That's all there is to
	it; note that "wildexp" uses the "sbrk" function to obtain storage,
	so don't go playing around with memory that is outside of the
	external or stack areas unless you obtain the me mory through "sbrk"
	or "alloc" calls.
*/

#include	<bdscio.h>
#define		MAXITEMS	200	/* max no. of items after expansion */
#define		SEARCH_FIRST	17	/* BDOS calls */
#define		SEARCH_NEXT	18

wildexp(oargcp, oargvp)
int	*oargcp;		/* point
 
   7:@V2@:@!:O@ YY:@<Y:O@Y>@2@*@"m@Y:O@Y2@:@4͐8:O@v^vY^Y:@=ʯYï*@"m@}2p@|2r@>2o@>2q@Y'4͐8>@2@:O@^YY:@=Y*@"m@64͐8:O@^
Y^Y:@=&Y&*@"o@p7"q@Y4͐82@:O@^@Y	Y:@=	Y:@²):@دOò)333333333333/44/4	4/44/44	4	4444444/4+4/4+43333/44/44/44/44444444#4#4/4-4/4-42W@2R@ͬ.¢.:@.>@.2
   #V# ":@^#V#"<@=D.9x g:@=c.Xx |:@=x.:@=.:@! U":@=®..x m=Ė<..Â*:@|U*@|}}U4:E@4͐8*<@͐8 :9@Oy@yy2@y?y!:#:#@Ė<"@x2@<)  /4  /4	 3	 3	 3	 3	3	3	3	3 3 3 3 3"3!3 33)UU]3*UU]3- U]3 	  /4  /4  t5  y5	 3	 3	 3	 3	3	3	3	3 "3 !3  3 3
   @â:@,:@$$!:@2@,:@ʇ-'-:@:@$$E:@2@:@--:@{.d'-P:@..'-.>@2@:@.-:@..-.>@2@2ͭ/*@"m@*@"o@:W@
ͅ(:@ʋM):@ʋ28@*@o"@
*@o"@":W@zʻû!ʻû5ʻ:ûzi;F»*@*@"@::@?G:@2@:@P:@Pi;Ļ*@p7*@"@:R@«:Y*@"m@+|5;Đ8!  "@2@<2@;>2@ͼ*P;\»*@:@G(|g}
   3333	 U_3
 Ui3UUs3UUy3 U5 U5 !  /4"  /4) /4 /4)t5y5) [3) Z3) Y3) X3* D3* G3* K3* P3 3)UU%5*UU%5- U%5 3)UU*5*UU*5- U*5 !  /4"  /4	 /4 /4	t5y5 	UU/5
UU05UU05UU/5 U05 U/5 	UU55
UU65UU65UU55 U65 U55 !  /4"  /4  /4 /4	UU;5
UU<5UU<5UU;5 U<5 U;5 	UUA5
UUB5UUB5UUA5 UB5 UA5 	  /4  /4	UU5
UU5UU5UU5 U5 U5 	  /4  /4	 [3	 Z3	 Y3	 X3	 W3
 D3
 G3
 K3
 P3
 V3	UU~5
UU5UU5UU~5 U5 U~5 Q  )3R  13  /4  /4 U3 U3 
  O o,ͼ*P;»*@:@<=() "@@ʻûKP_Fʻyûj1ͼ*P;»*@:@o:@g"@´ͼ*P;T»*@:@o:@g"@32ę<ͼ*P;0»*@:@o:@g"@
:@:@2@:@̖<*@|!  #"@P;!*@*@p7:@2E@A*¨J*C4͐82@>2@.*@"@:@:E@>}7>{7:@t>79>7:@79!  "@>2@4:E@̐84Đ8o5͐89J*½:@2E@.Oû͑)):W@ʋͅ(*@"K@*@"m@:@O"@):W@
  b U_3 Ui3 UL5 U[5 T4Q4  T4  Q4 U3 U3 U3 U3 UV5 U`5   /4  /4S  )3T  13 U_3 Ui3 U3 U3 UG5 Ue5   T4  Q4T4Q4 U3 U3 U3 U3 UQ5 Uj5 1  )32  131 (31 '31 &31 %32 032 /32 .32 -31831731632@32?32>31 Uc32 Um35 Uo5 !  /4"  /4)/4/4)UU5*UU5- U5 )  /4  /4/4/4)UU5*UU5- U5 )  /4  /4)UU5*UU5- U5 A*J*4͐8<J*4{#1ÿ7)ʵ)ʵ*4*:@:@2@ɯ̓6#ʷʷʷʷʷʷʷʷ+,̓67
   (*@M)*@|}>2R@M)*@"K@*@"m@:@O"@*@"@*@"@*@"@>2GYx|+|xq͟5͐8:@2@͟2@.͟:W@.2@5͐8|)}=ʾʺy7y7y7y7*@|p7*@p7"@*@p7|`i"@ͼ*P;K͑>7:@>g7>W728@:8@:@4̐84Đ8:@ʲ):@ò):@ʋ:@a͇-K:@t:@ʇ-'-:@..'-.>@2@:@:@ʤ:@--:@..-.>@2@*@"m@p7"q@+"u@:@2E@.*@"m@"@p7"q@+"u@:@2E@~29@G#^
   57#+7?̓6@###&&&0ͫ77*d@#̓6"d@y!d_ ^#V͐8}|&DM*K@!  xʍÃ"K@zª{Ҫz>#7Þ"m@5͐8?֠! _ ~ĵ& :@:P@>2< 2P@2= @. '*Bz ++V+^q6s#r#Ñ ¦ ^#Vs#r#q6s#r##"B:< ¦ > 2< :Q@:P@*:< := 2= G 0x 2< 2P@ 2Q@:P@ 2P@*+4+2O@J'~Ͷ!
m
 S er to old argc */
char	***oargvp;		/* pointer to old argv */
{
	int	nargc;		/* new argc */
	char	**nargv;	/* new argv */
	char	**oargv;	/* old argv */
	int	oargc;		/* old argc */
	char	fcb[36];	/* fcb used for search for first/next calls */
	char	dmapos;		/* value returned by search calls */
	char	first_time;	/* used in search routine */
	char	tmpfn[20],	/* temp filename buffer */
		*tmpfnp;
	char	*notfns[20];	/* list of !<afn> entries */
	int	notcount;	/* count of entries in notfns */
	char	c
  ') break;
		dest[j++] = source[i] & 0x7F;
	}
	if (source[9] != ' ')
		dest[j++] = '.';

	for (i = 9; i < 12; i++)
	{
		if (source[i] == ' ') break;
		dest[j++] = source[i] & 0x7F;
	}
	dest[j] = '\0';
	return dest;
}

int haswild(fname)
char *fname;
{
	char c;

	while (c = *fname++)
		if (c == '*' || c == '?') 
			return TRUE;
	return FALSE;
}

int match(wildnam, filnam, cur_drive)
char *wildnam, *filnam, cur_drive;
{
   char c;

   if (wildnam[1] != ':')
   {
	if (filnam[1] 
 ^ ur_drive;	/* currently logged drive */
	int	i,j,k;

	cur_drive = bdos(25);

	oargv = *oargvp;
	oargc = *oargcp;
	nargc = 1;
	notcount = 0;

	if ((nargv = sbrk(MAXITEMS * 2 + 2)) == ERROR)
		return ERROR;

	for (i = 1; i < oargc; i++)
		if (oargv[i][0] == '!') {
			if (i == 1) {
				oargv[oargc] = "*.*";
				oargc++;
			}				
			notfns[notcount++] = &oargv[i][1];
		}
		else if (!haswild(oargv[i]))
			nargv[nargc++] = oargv[i];
		else {
		   setfcb(fcb,oargv[i]);

		   tmpfnp = tmpfn
 1 == ':')
		if (filnam[0] - 'A' == cur_drive)
			filnam += 2;
		else
			return FALSE;
   }
   else
   {
	if (filnam[1] != ':')
		if (wildnam[0] - 'A' == cur_drive)
			wildnam += 2;
		else
			return FALSE;
   }

   while (c = *wildnam++)
	if (c == '?')
		if ((c = *filnam++) && c != '.')
			continue;
		else
			return FALSE;
	else if (c == '*')
	{
		while (c = *wildnam)
		{ 	wildnam++;
			if (c == '.') break;
		}
		while (c = *filnam)
		{	filnam++;
			if (c == '.') break;
		}
	}
	
  ;
		   if ((tmpfn[1] = oargv[i][1]) == ':') {
			tmpfn[0] = oargv[i][0];
			tmpfnp = tmpfn + 2;
			bdos(14,tmpfn[0] - 'A');
		   }

		   first_time = TRUE;
		   while (1) {			/* find all matching files */
			dmapos = bdos(first_time ? SEARCH_FIRST : SEARCH_NEXT,
									fcb);
			if (dmapos == 255) break;
			first_time = FALSE;
			hackname(tmpfnp,(BASE + 0x80 + dmapos * 32));
			if ((nargv[nargc] = sbrk(strlen(tmpfn) + 1)) == ERROR)
				return ERROR;
			if (nargc >= MAXITEMS)
				return ERR
  else if (c == *filnam++)
	 	continue;
	else return FALSE;

   if (!*filnam)
	return TRUE;
   else
	return FALSE;
}
':')
		if (wildnam[0] - 'A' == cur_drive)
			wildnam += 2;
		else
			return FALSE;
   }

   while (c = *wildnam++)
	if (c == '?')
		if ((c = *filnam++) && c != '.')
			continue;
		else
			return FALSE;
	else if (c == '*')
	{
		while (c = *wildnam)
		{ 	wildnam++;
			if (c == '.') break;
		}
		while (c = *filnam)
		{	filnam++;
			if (c == '.') break;
		}
	}
	
 J OR;
			strcpy(nargv[nargc++], tmpfn);
		   }
		   bdos(14,cur_drive);		/* restore to current drive */
		}

	for (i = 0; i < notcount; i++)
		for (j = 1; j < nargc; j++)
			while (match(notfns[i],nargv[j],cur_drive))
			{
				if(j == --nargc)
					break;
				for (k = j; k < nargc; k++)
					nargv[k] = nargv[k+1];
			}
	*oargcp = nargc;
	*oargvp = nargv;
	return 0;
}

hackname(dest,source)
char *dest, *source;
{
	int i,j;

	j = 0;

	for (i = 1; i < 9; i++)
	{
		if (source[i] == ' 
    s   e'A"̀.+';( !e'"~s!2= ̀.:< _!.@!:< 2< _!:<  M!>2< !j!2@>@2< j!:O@̈"O,*ʹ,!!2= ̀.:< ʶ!.ʗ!:< 2< ö!:<  ¤!>2< !!2@>2< !:O@̈"++,4+#R :@ʲ)*@|:@Ċ+:O@̊+.\.@.p'~ '#̓6U :O@>2O@>2P@U +' 'HͶ32ę<y2"!̀.+';( ̀.:O@\":= Y"͈"\"͊+2P@2@:< ~">2@!  z"#"@/ÿ7:@+:@ʭ"*@|!  ʥ"#"@'-:@ʿ">2@Þ":@"13A*Đ8H4̐8")3A*Đ8E4̐84͐8>$2@>2@̓6   )ͥ)):@)! x9):@/)*@͑7x9)9)! x*K@"@ͥ):@2@p'~(ͅ('`)ͥ)v)ͺ)!  r)! "@)):@@2@2V@l*ʟ))):@=2@{1ÿ7l*ʲ)*@|ʷ)ɯ<ͥ):@ò)ͥ)ʲ)l*ʲ):@ ò)l*ʲ))ͥ):@دp'~()'l*ʲ)ͺ)ʲ)ͥ)):@ͥ)ʲ)l*ʲ))ʲ)S*ʲ):@p'~(*'*:@4*:@ͥ)ʲ):@:@j*<ɯ:@@ò)))ʲ):@ͥ)ʲ))ʲ):@=:@ò)̓*:@)*0ÿ7/Ϳ7**p'~(*'#1ÿ7*Bq6s#r#q6s#r#6 #"B*B+~
   ######~+++#(0Ϳ7@.>̀.ʞ# :@H#%p'2@`#'-p'.4͜*]#04͐8̓*m#:@=2@p'#\.#̀.;(;(ͯ':@#..w('$p'#:@.\.@.#̀.ͬ.¿#Ï#:@#Õ#G#͇-Õ#x..͇-.w(':@?2@$:O@>2O@*O*+4+2O@ͅ(:@($(0Ϳ7:@$:@%:@$'-:O@$͜*_$>67:@7û$*@|p$3͐8û$>67:@7>#7>67:@7û$*@"m@͜*²$>7:@7>s7>@2@û$3͐8ê$̓*$:@=2@ͳ*͜*$>s7ê$J*$3:O@$3͐8ê$4͐8ê$*   ++++V+^l9*B++*B+~(++V+^l9*B+!+*B"B:@:@ c+:@.:@@2@:@_ !+^#V͐8>2@:@`2@:@:@ ʪ+:@.:@?2@:@j+?2@44444555555 5*B+~w+++V+^"m@:@+*@|>,:@ ,:@_ !+~74͐8:@+:@@,]4A*<,i4͐8o4A*<,{4<,*B+~w+V+^"m@:@t,*@|>,:@ʇ,:@,:@:@¥,W4A*¡,c4͐8u4A*¡,4á,*B+~+++++w*B+~ü,"@q6"m@4͐8*@"@l9*@"@  d @"m@*@"o@:@_%:O@@%͜*3%>>7:@73͐8û$3͐82@û$͜*3%>7:@7>{73͐8ê$͜*x%:@Q%>}736%:@.J*%>&7746%:@ʣ%'-D$:@´%0.'-$:@>%>7'->7>@2@$*@"m@64͐8:@2@"m@|&} &4͐8&&5͐8>G>)7&#O,*@."̀.'-̓6M&4+0Ϳ7#A*]&4͐8,+4+@."̀.'-ʌ&A*&4͐8>2@,~Ė<#^#V#͢&̓6)))Y~0̿7G~`2@2@#~2@~?>&=2@#^#V#^#V#"@^#V"@:@  J q6l9*@"@"m@4͐8*@:@G*@"m@xl-xN-4͐82@Ä-xZ-ZG-4͐8*@͓G-xx-͊+G-xʄ-.G-:@G*@"m@x-xʵ-4͐8í-.>@2@-x-Zê-4͐8*@͓ê-x-C+í-xʪ-p'~('-w('p'~(͇-w(':@G-x--:@Gr-x-x-p'~(.w('*4B~G~#T.> w"4B*4B~?s.w#> s.U.G:@x*4B~+Pʢ.~ʚ.~?@U.~U.~w"4B*4B~@ò)F>@.>wx>.>7>7>.>.>.>.:@ò):@   '*{@ !  :@@'"@*@#w"@*@~9'D'/Ϳ7͈?+"@*@+"@!6D"@6!^D"@*@~*@*@s#r#*@s#r#*@s#r#*@s#r#*@s#r#:@w#"@'*@*@s#r#*@s#r#*@s#r#*@s#r#*@s#r#:@w#"@'|E'}X27*@+~2@+V+^+"@V+^+"@V+^+"@V+^+"@V+^"@"@*@+~2@+V+^+"@V+^+"@V+^+"@V+^+"@V+^"@"@p';(ͯ''͋(! "@"K@2@<2@2@2@ͥ)()(*¾(2@2@(S*(#)2@2@)l*H)>2@:@!@4ͺ)(*@"K@:@ ):@   )BD Software C Compiler v1.50 (part II)
 Can't open file
 
Error on file output...disk full?
 CRL Dir overflow: break up source file
 Missing label
 Missing semicolon
 Illegal statement
 Can't create CRL file
 Illegal operator
 Lvalue required
 Lvalue needed with ++ or -- operator
 Bad left operand in assignment expression
 Mismatched parenthesis
 Mismatched square brackets
 Bad expression
 Bad function name
 Bad arg to unary operator
 Expecting ":"
 Bad subscript
 Bad array base
 Bad   casm $1
asm $1.ccz  ;The "cc" should be changed to the proper disk for your system
sid $1.hex
g0
era $1.asm
era $1.hex
; now say "SAVE nn $1.crl", where nn is the decimal equivalent of the
; hex value printed out next to the "S" error in the above  assembly...
:@  /*
	CASM.C	-- written by Leor Zolman, 2/82
	Modified for v1.50 11/14/82

	CP/M ASM preprocessor: renders MAC.COM and CMAC.LIB unnecessary.

	See the CASM Appendix in the User's Guide for complete information.

	Compile and link with:

		cc casm.c -o -e5000

		l2 casm
	(or)	clink casm
*/

#include <bdscio.h>

#define TITLE "BD Software CRL-format ASM Preprocessor v1.50\n"


/*
 *	Customizable definitions:
 */

#define DEFUSER	"2/"		/* default user area for include files	*/
				/* ma     ke this a null string for "current" */

#define DEFDISK "C:"		/* default disk for include files	*/
#define CASMEXT	".CSM"		/* extension on input files 	*/
#define ASMEXT	".ASM"		/* extension on output files	*/
#define SUBFILE "A:$$$.SUB"	/* Submit file to erase on error. To not */
				/* erase any, use a null string ("")	 */

#define CONTROL_C 3		/* Abort character */
#define	EQUMAX	500		/* maximum number of EQU ops	*/
#define FUNCMAX	100		/* maximum number of functions  */
#define NFMAX	100		/*      maximum number of external
				   functions in one function 	*/
#define LABMAX	150		/* max number of local labels in one func */
#define TXTBUFSIZE 2000		/* max # of chars for labels and needed
				   function names for a single function	*/

/*
 *	End of customizable section
 */

#define DIRSIZE	512		/* max # of byte in CRL directory 	*/
#define TPALOC	0x100		/* base of TPA in your system 	*/

		/* Global data used throughout processing
		   of the input file:			*/

char	fbuf[BUFSIZ];		/* I/    Z O buffer for main input file	*/
char	incbuf[BUFSIZ];		/* I/O buffer for included file 	*/
char	obuf[BUFSIZ];		/* I/O buffer for output file		*/

char	*cbufp;			/* pointer to currently active input buf */
char	*cfilnam;		/* pointer to name of current input file */
char	nambuf[30],		/* filenames for current intput */
	nambuf2[30],		/* and output files.		*/
	onambuf[30];

char	*equtab[EQUMAX];	/* table of absolute symbols	*/
int	equcount;		/* # of entries in equtab	*/

char	*fnames[FUNCMAX];	/* li    structure or union specification
 Bad type in binary operation
 Bad structure or union member
 Bad use of member name
 Illegal indirection
 Internal error: garbage in file or bug in C
 Sorry, out of memory. Break it up!
 Encountered EOF unexpectedly
 Bad argument list
 Compilation aborted by ^C
 Expecting binary operator
 Missing or misplaced "("
 Missing or misplaced ")"
 to spare Include @ The function " " is too complex; break it up a bit
 Sub-expression too deeply nested
 Missing "{" in    8G8<x!9!9?;9l9Ý87Ý8G8x771?=_ !m@~#fo*@p7*@*@s#r#"@*@#"@*@s#r#*@*@p7s#r#"@*@#"@!  9*@####:s#r#*@s#r#"@*@#"@!B"4B6 2;;!XE"@!K"@!<R"@!  "@"@"@"@*@"y@##"@g<D:́:q6"@*}@̓6:2Ϳ7͜<"}@ͣ:;::ͷ?*@p7*@*y@s#r@*}@̓6Ė<###̓6#2@̓6u:2@̓6u:#̓6"}@͐&h:#e:*{@|::@ʖ:>7p7"m@3͐8*@"o@*{@"m@3|º:3͐8!@^#V#zl9^#V#G:7:7:K*@:<R*@:|;}  { function def.
 ####88++++88+++++|8z8#####|8z8)8))8)))8))))8)))))888|8!8!|888(8!(8(|8!(|8|8!|8w#w8s#r8s#6 8 s#r828!"8!9DM8!9884n848~4o85n858~5o8^#Vr+s8*#"8^#Vr+s8*+"8^#V8888#88+8!88{_zW88r+s8888n8  8*8*8!	8s#r8}8{8|8z8z8|8|8|8}8}8z8z8{8{8 8 8 8}888~#fo8!88* 8"8 8!!9~#fo8!98& 8 8s#r8s#w8 8 8 8 8   27*F@~$;~#
;27Ã-;7;main *d@*}@̓6Ė<*d@"6@!  "4@#^#V"d@͢&2N@:@r;:@r;<2N@*b@;*\@"F@z7w#;*@*@s#r#"\@3Dͬ;Ҳ;c/7z{`i)))Y~#fo"{@N#F#x;y~#;;!Y"@!XE"@ *`@z<*@~#<:T@O~?6< "@;*@6 #x2@!XEp7DMXE7x*<*`@p7*b@;~`<*@z7w#R<"@<*@"@q6"m@:@ʐ<4͐8:@24͐8=<l917̓6ʬ<·<͖<#^#V#l9Ü<<#̓6<#͜<ý<=#:=7*4@*d@ͬ;> <:3@<23@"4@  t  8 8 8 8 8 8 8 8k8?888)88 8 8 88 88 8 8 888888888|g}o8|g}o8|g}o8k88!8!8}/o,&88!k8)8k8!8|g}o8}/o&8}/o|/g8!8 !6B6 #x6*}@V6@6#̓67~#06^ ### 6"^@̓6j6###I6ͨ6j6c6###V6?*h@#"h@+q6"m@ͨ6:l@ʢ6T0=ʙ6m0*j@"d@717~½6*d@#"d@#è66#^#V#l9è6 6#è662H@*d@+"I@!  "d@#è62H@*I@#"   *6@p7#}7:3@7B=<#̓6Ė<#^#V#"m@4͐8v?=<*#̓6O2ę<#@.̀.j2ę<#O,*͜<̓6ʈ=+4+,+4+#͜<,=#~Ė<#^#V#l9*̓6̓6O2ę<<#@.̀.j2ę<#O,*͜<͜<+4+2>#*+͜<̓6Ė<#̓6>###<@.̀.++4+̓6/<#><#̓6|>*>2O@@.̀.'-*+4+:N@p>4͐8|>A*|>4͐8*@"m@4*{@|>3͐8v?><*@.̀.̓6>0ͫ7͈?v?*+4+#<T'̓6 >2O@@.R
̀.A*>:@>}>>{7~   d@#è6>2l@*d@"j@72l@#c7)7#77+7>2l@*d@"j@L72l@#c7W7#L7L7+L7̓6j6###c7|/g}/o#G͈7Ox怱a{ )))Y~#fo|0Ϳ7*d@*f@"d@Ϳ7"d@>2S@:@:H@727*I@*d@7Ϳ7Ã7 8G:@B8*4B~ķ.*@p#"@:~@o|B8:181Ù<2F8* "x*}@p7*++#DM* +*++><l8v8~+xl8*++p7*}@"}@*^@"^@͖8:@8¦8²8J9Ý88J9(9;9͕9Ý88OG*	}7|7Ý8(99;9}7|7Ý   ?#*d@#"d@>~#<Fxb?.>g"m@g"q@og"s@q6"o@A*M?4>2m@[?:@4[?4͐8?#^#V#"m@4͐8͜<̓6?#/Ϳ7#~ʢ6/ʙ<ʙ<«?*d@#"d@j6#ڈ?##È?*@!Kz^#V#~#fo?#þ?DM*@!<Rz?~#?~?###?o Eg}|"@*@?*@}7|7)XE|
7+'@s@q6"o@A*M?:    "m@4*{@|>3͐8v?><*@.̀.̓6>0ͫ7͈?v?*+4+#<T'̓6 >2O@@.R
̀.A*>:@>}>>{7~[  st of functions in the source file */
int	fcount;			/* # of entries in fnames		*/

int	lino,savlino;		/* line number values used for error 	*/
				/* reporting.				*/

char	doingfunc;		/* true if currently processing a function */

char	errf;			/* true if an error has been detected	*/
char	verbose;		/* true to insert wordy comments in output */
char	careful;		/* true to detect old CMAC.LIB macros   */
char	blankflag;		/* true if last line processed was null */

		/* Global data used during the   ocessed a null line */
	
	while (--aarghc) 
	{
		++aarghv;		/* bump to next arg text */
		if (**aarghv == '-')
		{
		    switch(c = aarghv[0][1])
		    {
			case 'F':
				careful = 1;
				break;

			case 'C':
				verbose = 1;
				break;

			case 'O':
				if (aarghv[0][2])
					outnam = &aarghv[0][2];
				else if (--aarghc)
					outnam = *++aarghv;
				else goto usage;
				break;

			default: goto usage;
		    }
		}
		else
			inpnam = *aarghv;
	}

	if (!inpnam) {
  usage:	put  processing of a
		   single function in the source file:		*/

char	*nflist[NFMAX];		/* list of needed functions for a function */
int	nfcount;		/* number of entries in nflist	*/

struct {
	char *labnam;		/* name of function label */
	char defined;		/* whether it has been defined yet */
} lablist[LABMAX];

int	labcount;		/* number of local labels in a function */

char	txtbuf[TXTBUFSIZE],	/* where text of needed function names	*/
	*txtbufp;		/* and function labels go		*/

char 	linbuf[150],		  s("Usage:\tcasm [-f] [-c] [-o <name>] <filename>\n");
		puts("-F: flag old CMAC.LIB macros if spotted\n");
		puts("-C: don't strip comments from input and output\n");
		puts("-O <name>: Call the output file <name>.ASM\n");
		exit();
	}

				/* set up filenames with proper extensions: */
	for (i = 0; (c = inpnam[i]) && c != '.'; i++)
		nambuf[i] = c;
	nambuf[i] = '\0';

	strcpy(onambuf, outnam ? outnam : nambuf);
	strcat(nambuf,CASMEXT);		/* input filename */
	cbufp = fbuf;			/* buffer pointer   /* text line buffers	*/
	linsav[150],
	workbuf[150],
	pbuf[150], *pbufp;

char	*cfunam;		/* pointer to name of current function */
int	relblc;			/* relocation object count for a function */

char	pastnfs;		/* true if we've passed all needed function */
				/* declarations ("external" pseudo ops)	    */

int	argcnt;			/* values set by the "parse_line" function */
char	*label,
	*op,
	*argsp,
	*args[40];

char 	*gpcptr;		/* general-purpose text pointer	*/

/*
 * Open main input file, open o ^ */
	cfilnam = nambuf;		/* current filename pointer */
	if (fopen(cfilnam,cbufp) == ERROR)
		exit(printf("Can't open %s\n",cfilnam));

	if (!hasdot(onambuf))
		strcat(onambuf,ASMEXT);		/* output filename */
	if (fcreat(onambuf,obuf) == ERROR)
		exit(printf("Can't create %s\n",onambuf));

					/* begin writing output file */
	fprintf2(obuf,"\nTPALOC\t\tEQU\t%04xH\n",TPALOC);

	lino = 1;			/* initialize line count */

	while (get_line()) {		/* main loop */
		if (kbhit() && getchar() == CONTROL_  utput file, initialize needed globals
 * and process the file:
 */

main(aarghc,aarghv)
char **aarghv;
{
	int i,j,k;
	char c, *inpnam, *outnam;

	puts(TITLE);

	initequ();		/* initialize EQU table with reserved words */
	fcount = 0;		/* haven't seen any functions yet */
	doingfunc = FALSE;	/* not currently processing a function */
	errf = FALSE;		/* no errors yet */
	verbose = careful = FALSE;
	inpnam = outnam = NULL;		/* haven't seen any names yet */
	blankflag = FALSE;	/* haven't just pr ~ C)
			abort("Aborted by ^C\n");
		process_line();		/* process lines till EOF */
		lino++;
	}

	if (doingfunc)			/* if ends inside a function, error */
		abort("File ends, but last function is unterminated\n");

	if (errf)
	{
		puts("Fix those errors and try again...");
		unlink(onambuf);
		if (*SUBFILE) 
			unlink(SUBFILE);
	}
	else
	{
							/* end of functions */
		fputs2("\nEND$CRL\t\tEQU\t$-TPALOC\n",obuf);
		fputs2("SECTORS$ EQU ($-TPALOC)/256+1 ;USE FOR \"SAVE\" !.\n",
			obuf);
 E   	   !  9"  2:<2|2m1  !\ D!6C#6O#6M22x22d22n2g2h22222222<2c2s2:\ 2* "e"!"! "t͵!] pڹ~/¹!!"a! F#~#!i#~͚i"a+#~ʩ"#~ʩ"-"#~2}#CYHʘLʟRJ+V#2*6 #
>|;";iͽ2#pl2; i͍> ~͍x?ЇG#{0O
?2;"t;:<2222*+"d ""!6 #xͰ:_  L>2| $* ":   
	>-h͏
ajԵ*k
ܵ>22m:]	!\ D!e 6S#6Y#6M ! "*oDM  ͢	xe	a:Ğ2m:*}ʞ	}ʛ	p#Ð	;!~#fo
!.~#foͭ
:=2	>	ha>2@
  *o+
PY*o+

y

!."q 
!"q 
		xy|}*q		N#F*q^#Vp+qDMq#p!  .~T
`i"o]
!}|~#e
~W#^#I
!.^#V!.		N#F͑

g

7?
Ñ
 ~#h
x>	h
> h
>,h|
}

0:hh!\ D    2h* "i!-!-4͵L>2!>2X>2 :_ :c=_ 2͸u.@C>2:c.ʹ* :s#r:hʥ*i* :¸s#r"k** :s#r:*A 6:@:g5:*6# 68#6 6;#6* "e@*6*# :,Bs#r#6@*e*#s#rh͵* *͏|?o& +͵	:  *:  $$$     SUB                 [COM    BD Software C Linker   v1.50
 Error reading:  No user area prefix allowed on main f   ÷:xu:u͵ :x=A*y! 6 #"Aw#1x2 !X ~#M **DM! w#z {  
*͉;{ ~*|}ʩ#ʵ>ê7\  :̵> 272| \  !h 6 %$\ !h 6  \ !h 6  $\  =7$\  ѷ$ L>h>
G:m{x͍ẍ́_ G:ʙẍ́:*p#}°;! "½hö>:G>2ͷx2!::_<  :_ <2   ilename 
Dir full; 
Error writing:  
Can't close:  No main function in  
Missing function(s):
 
Type the name of a CRL file to scan; 
<CR> to scan all DEFF files, ^Q-<CR> to abort:  MAI  DEFF    CRL  DEFF2   CRL  DEFF3   CRL  C       CCC Can't find  Last code address:  
Externals start at   occupy  bytes, last byte at  
Top of memory:  
Stack space:  
Warning! Externals extend into the BDOS!
 
Warning! Externals overlap code!
 Out of memory K left over Linkage complete
 Bad symbols 
Execut    ͷ!:7͵7!$J$J$J$J!e 6C#6R#6L w#O:sʖ!~ʐ">22n:##b2n!";ڜ>2Ü!"*"~7~~W#^#)~#a{ !~7g&~#fo"#~#fo"##:cO*a~͚C#8g2c::dd:ʃ:ʘ-r#~2}STOWWErZYʃDNF͚88͵ha#82l2l2l2l2s#8>2x#i"C2x#"y~#"m   ing:
 Bad option: - Ref table overflow Missing arg to -SYM file symbol already defined:  Ignoring duplicate function:  ^C
 l Sorry; 255 funcs max :ʸ ʸ ¸x!͚A[د*t*͏*!  "! 0"#|+!~͚>0<:w60+͵:\ 2 <@h>:h] T>.hTah͚Ub	:a1	: 	**kڒ*e
j͵ a͵+
:͵*k
*͵*
3͵+z#
H͵*e+
:aZ͵  x #"e>2g8  iC/(͵aL~C6#*))))_ 0
??#::2i{28#"i>2h8#i!e 6S#6Y#6Mxͷھ! "*>2nҨ"2n*a8-C͏"!Rg>2!!R-w#H8+~w!  ))))_ HCH8-͚
7?*}V$~#}b! "~͚#ix\ pڛ~/X  #2#~+::2~@##~ʿ ~ #"a 6 ~͚.#x  		putdir();			/* now put out CRL directory */
		fputs2("\t\tEND\n",obuf);	/* end of ASM file */
		putc(CPMEOF,obuf);		/* CP/M EOF character */
		fclose(cbufp);			/* close input file */
		fclose(obuf);			/* close output file */
		printf("%s is ready to be assembled.\n",onambuf);
	}
}

/*
 * Get a line of text from input stream, and process
 * "include" ops on the fly:
 */

int get_line()
{
	int i;

top:	if (!fgets(linbuf,cbufp)) {		/* on EOF: */
		if (cbufp == incbuf) {		/* in an "include" o 2) - 1] == '"')
				nambuf2[i] = '\0';
		} else
			strcpy(nambuf2,argsp);

		if (fopen(nambuf2,cbufp) == ERROR) {
			if (!hasdot(nambuf2)) {
				strcat(nambuf2,".LIB");
				if (fopen(nambuf2,cbufp) != ERROR)
					goto ok;
			}			    
			printf("Can't open %s\n",nambuf2);
			abort("Missing include file");
		}

	ok:	lino = 1;
		cfilnam = nambuf2;
		return get_line();
	}
	return 1;
}

parse_line()
{
	int i;
	char c;

	label = op = argsp = NULL;
	argcnt = 0;

	strcpy2(pbuf,linbuf);   file? */
			fabort(cbufp->_fd);		/* close the file */
			cbufp = fbuf;		/* go back to mainline file */
			cfilnam = nambuf;
			lino = savlino + 1;
			return get_line();
		}
		else return NULL;
	}

	if (!verbose)				/* strip commments, default */
	{
		for (i = 0; linbuf[i]; i++)
		{
			if (linbuf[i] == ';')
			{
				while (i && isspace(linbuf[i-1]))
					i--;
				if (!i && blankflag)
				{
					lino++;
					goto top;
				}
				strcpy(&linbuf[i], "\n");
				blankflag = TRUE;
				brea 	 
	strcpy2(linsav,linbuf);
	pbufp = pbuf;

	if (!*pbufp) return;		/* ignore null lines */
	if (!isspace(c = *pbufp)) {
		if (c == ';')
			return;		/* totally ignore comment lines */
		label = pbufp;		/* set pointer to label	*/
		while (isidchr(*pbufp))	/* pass over the label identifier */
			pbufp++;
		*pbufp++ = '\0';	/* place null after the identifier */
	}

	skip_wsp(&pbufp);
	if (!*pbufp || *pbufp == ';')
		return;
	op = pbufp;			/* set pointer to operation mnemonic */
	while (isalpha(* 	 k;
			}
			if (linbuf[i] == '\'' || linbuf[i] == '"')
				break;
		}
		if (!linbuf[i])
			blankflag = FALSE;		
	}

	parse_line();				/* not EOF. Parse line */
	if (streq(op,"INCLUDE")  ||		/* check for file inclusion */
	    streq(op,"MACLIB")) {
		if (cbufp == incbuf)		/* if already in an include, */
		 abort("Only one level of inclusion is supported"); /* error */
		if (!argsp)
		 abort("No filename specified");
		cbufp = incbuf;			/* set up for inclusion */
		savlino = lino;

		for (i   pbufp))
		pbufp++;  		/* skip over the op 		*/
	if (*pbufp) *pbufp++ = '\0';	/* place null after the op	*/


					/* now process arguments	*/
	skip_wsp(&pbufp);
	if (!*pbufp || *pbufp == ';')
		return;
	argsp = linsav + (pbufp - pbuf);	/* set pointer to arg list */

					/* create vector of ptrs to all args
					   that are possibly relocatable */
	for (argcnt = 0; argcnt < 40;) {
		while (!isidstrt(c = *pbufp))
			if (!c || c == ';')
				return;
			else
				pbufp++;

		if (isidchr(*(pbu s = 0; !isspace(argsp[i]); i++)	/* put null after */
			;				/* filename	  */
		argsp[i] = '\0';

		*nambuf2 = '\0';

		if (*argsp == '<') {		/* look for magic delimiters */
			strcpy(nambuf2,DEFUSER);
			if (argsp[2] != ':')	/* if no explicit disk given */
				strcat(nambuf2,DEFDISK); /* then use default */
			strcat(nambuf2,argsp+1);
			if (nambuf2[i = strlen(nambuf2) - 1] == '>')
				nambuf2[i] = '\0';
		} else if (*argsp == '"') {
			strcpy(nambuf2,argsp+1);
			if (nambuf2[i = strlen(nambuf  fp - 1))) {
			pbufp++;
			continue;
		}

		args[argcnt++] = pbufp;			
		while (isidchr(*pbufp)) pbufp++;
		if (*pbufp) *pbufp++ = '\0';
	}
	error("Too many operands in this instruction for me to handle\n");
}

process_line()
{
	char *cptr, c;
	int i,j;

	if (op) {
			/* check for definitions of global data that will be
			   exempt from relocation when encountered in the
			   argument field of assembly instructions: 	   */

	   if (streq(op,"EQU") || streq(op,"SET") ||
		(!doingfunc    > :.>I͵ab͵! 6x
 a! +~<o6 ͚?`| :_  iº2s!\ DͰ222<2d!\ D2<2Ͱ!\ D2<22Ͱ:_  +x>!";~h#a> hh:2!\ DͷL*$J* ^#V*";!\ D!\ D~#F͔:<2d!*DM͏**:o|ڜ:!* "2w\ yo& "$*"+|¹*}~#"$! ~#"`i)|!  w2x!    1H/  	!H/	* 	 	v21H/!,2}:O	FfEADʔRCQʴMTL*	OFEADRCQMTL?Hcopyright (c) 1980by Leor ZolmanBD Software C Librarian  v1.50
Function buffer size =   bytes. 
That command is not recognized
 
C Librarian commands:
   (note: "file#" is a single digit, 0-9)
o[pen] file# [d:]filename 
f[iles]
e[xtract] file# funcname
a[ppend] file# [funcname]
d[elete] file# funcname
r[ename] file# funcname_old func   wͷL:2| O*~###"{:G ~G`i"2)#N#F#*͏͙	N#F#"xʊ^#V#*^#V*r+sj"|/g}/o#DM*z¯{¯á! ~#~G#N#j& )^#V"}xù#n& )^#V~## O !  			#*}s#r!  2~>g\:<2#͊w#>6 #6 #6 ++2n_:~#£:o& )~#fo"}*{: ^+Vr#s# *s#r:n+~#8!R:s>2Z*~M#~A#~I#~͵ͭ
a+~w!		*  o name_new
c[lose] file#
q[uit] [file#]
m[ake] filename
t[ransfer] source_file# dest_file# funcname
h[elp]
l[ist] file#
 
File not found
 
Error in closing file
 
Error in reading file
 
No more directory space
 
file #  size=   bytes; dir space=  /512 bytes 
Function not found
 
Function already exists
 
Function buffer empty
 
Error in writing file
  No functions 
CRL file already exists 
Sorry; only : files (0-9) allowed 
That file# is already in use
 
Not enough room left in CRL file dire   s#r*|}##"*DM͏	#DM*><K~+x>M*~d!M~͊G͊#j#ŷGx 	#r:.   O !  			#*}s#r!  2~>g\:<2#͊w#>6 #6 #6 ++2n_:~#£:o& )~#fo"}*{: ^+Vr#s# *s#r:n+~#8!R:s>2Z*~M#~A#~I#~͵ͭ
a+~w!		*    ctory
 
Not enough room in file (64K max)
 
Function buffer too small
 
Out of disk space
 
That command requires a file#
 
Second file# required
 
Too many file#'s given
 
That command requires a function name argument
 
'Rename' requires a second function name argument
 
Too many names given
 
That file# is not currently assigned to any file
 
(Quit) Are you sure (y/n)?  
Aborting all operations on  .CRL 
 There aren't any files open right now
 
Please don't begin filenames with numbers! I co       nfuse easily.
 
Please wait while this crunches away...
 
A write error occurred while closing. This is bad
news; the original CRL file is intact (unless you
have just created it from scratch) but it may
contain extra invisible functions if you have
transferred any into it before closing. To get
rid of these possible ghosts, open the file again
(after clearing some disk space!) and then close
it immediately.
 
That's a wierd filename, but I'll accept it.
   	,**7I   &&
			(streq(op,"DS") || streq(op,"DB") || streq(op,"DW"))))
	   {
		fputs2(linbuf,obuf);
		cptr = sbrk2(strlen(label) + 1);
		strcpy(cptr,label);
		equtab[equcount++] = cptr;
		if (equcount >= EQUMAX)
			abort(
		  "Too many EQU lines...increase 'EQUMAX' and recompile CASM");
		return;
	   }

	   if (streq(op,"EXTERNAL")) {
		if (!doingfunc) abort(
		 "'External's for a function must appear inside the function");
		if (pastnfs) error(
		 "Externals must all be together at start of functio q t[i].defined) {
			printf("The label %s in function %s is undefined\n",
					lablist[i].labnam,cfunam);
			errf = 1;
		  }
		doingfunc = 0;
		return;
	   }
	}

	if (careful)
	if (streq(op,"RELOC") || streq(op,"DWREL") || streq(op,"DIRECT") ||
	    streq(op,"ENDDIR") || streq(op,"EXREL") || streq(op,"EXDWREL") ||
	    streq(op,"PRELUDE") || streq(op,"POSTLUDE") || streq(op,"DEFINE"))
		error("Old macro '%s' leftover from \"CMAC.LIB\" days...\n",
							op);

				/* No special pseudo ops, so   n\n");
		for (i = 0; i < argcnt; i++) {
			nflist[nfcount++] = txtbufp;
			strcpy(txtbufp,args[i]);
			bumptxtp(args[i]);
		}
		if (nfcount >= NFMAX) {
		  printf("Too many external functions in function \"%s\"\n",
					cfunam);
		  abort("Change the NFMAX constant and recompile CASM");
		}
		return;
	   }

	   if (streq(op,"FUNCTION")) {
		if (!fcount) {
			if (verbose)
			 fputs2("\n; dummy external data information:\n",obuf);

			fputs2("\t\tORG\tTPALOC+200H\n",obuf);
			fputs2("\t\tD  now process
				   the line as a line of assemby code: 	*/

	if (streq(op,"END")) return;		/* don't allow "end" yet     */

	if (!doingfunc || (!label && !op))	/* if nothing interesting on */
		return fputs2(linbuf,obuf);	/* line, ignore it	*/

	if (!pastnfs)				/* if haven't flushed needed */
		flushnfs();			/* function list yet, do it  */

						/* check for possible label  */
	if (label) {
		fprintf2(obuf,"%s$L$%s\t\tEQU\t$-%s$STRT\n",
			cfunam, label, cfunam);
		for (i=0; linbuf[i]; i++)  B\t0, 0\n",obuf);
		}

		if (doingfunc) {
			printf("'Function' op encountered in a function.\n");
			abort("Did you forget an 'endfunc' op?");
		}
		if (!argcnt)
			abort("A name is required for the 'function' op");

		cfunam = sbrk2(strlen(args[0])  i+ 1);
		fnames[fcount++] = cfunam;
		strcpy(cfunam,args[0]);

		printf("Processing the %s function...   \r",cfunam);

		doingfunc = 1;
		txtbufp = txtbuf;
		labcount = 0;
		nfcount = 0;
		pastnfs = 0;

		if (verbose)
			fprint  
			if (isspace(linbuf[i]) || linbuf[i] == ':')
				break;
			else
				linbuf[i] = ' ';
		if (linbuf[i] == ':') linbuf[i] = ' ';
		for (i = 0; i < labcount; i++)	  /* check if in label table */
		  if (streq(label,lablist[i].labnam)) {	        /* if found, */
			if (lablist[i].defined) {  /* check for redefinition */
				error("Re-defined label:");
				printf("%s, in function %s\n",
						lablist[i].labnam,cfunam);
			}
			 else
				lablist[i].defined = 1;
			goto out;
		  }
		lablist[i].la  f2(obuf,"\n\n; The \"%s\" function:\n",cfunam);

		fprintf2(obuf,"%s$BEG\tEQU\t$-TPALOC\n",cfunam);
		return;
	   }

	   if (streq(op,"ENDFUNC") || streq(op,"ENDFUNCTION")) {
		if (!doingfunc)
		  abort("'Endfunc' op encountered while not in a function");

		if (!pastnfs) flushnfs();    /* flush needed function list */
		fprintf2(obuf,"%s$END\tEQU\t$\n",cfunam);
		doreloc();		     /* flush relocation parameters */

		for (i = 0; i < labcount; i++)	/* detect undefined labels */
		  if (!lablis  bnam = txtbufp;	/* add new entry to */
		lablist[i].defined = 1;		/* label list 	    */
		strcpy(txtbufp,label);
		bumptxtp(label);
		labcount++;
	}
out:
	if (!op) return fputs2(linbuf,obuf);	/* if label only, all done   */

						/* if a non-relocatable op,  */
	if (norelop(op)) return fputs2(linbuf,obuf);	/* then we're done   */

	if (argcnt && doingfunc)
	  for (i = 0; i < argcnt; i++) {
		if (gpcptr = isef(args[i]))
		   sprintf(workbuf,"%s$EF$%s-%s$STRT",
				cfunam,gpcptr,cfunam);
		e W  5 <	+	5	##"~#	> !"5	##~#5	w	~
*ʋ	?{	Gw	r	#~
n	*w	#F	7r	#~
n	w	#~
n	<	n	w	Ó	
0:?A_[?0_ ͸		>͸	>
͸	|/g}/o#|	}
	0͸	!
 
	!
 ^
	
`i|%
)
x  W
<
z/W{/_ѯzW{_=yOxG+
z{|}
q
|/g}/o#w
DM!  xxGyO҉
)|
~¤
 <@͸	>:͸	#~ ʿ
͸	#±
	
*?_A[?a{ 0
?0:? ~	     #N#F`i"`++*~
#
++~w#q#p#6#*	}|:2*"*"P**6#s#r,|g###||	,  *~
ʒ#Æ*"*"K*"ͶìG~w*!\ ̓͎\  ~	,!\ ! 6#6#6\ &=%G	.}*	.Et*
G
w#7+~w x	g6 #~
Zo#~
Sɷ/<_ "|G 		$$DM*~#x o&	~+z¶ê*"*"K*"*~**"**  + #

 :_ !6!
o& ))))). g o& <~~7 #F	,
G:MjR>	:Oʈx=2R#
x6 :¢
@w#
.ʻ
ʻw#¥	 6C#6R#6L !  6 ~	, 	, \  	, 4	, ѷR\:}ti:}tJlW	>2}7!<
6 #{6 #6 ####6 #6 #6 *=*%`i)|!  w2x! w!  :w`i	"H/|* 	   "::22""	:͏
>:͸		:2~Dp	S.##ío>M͸	>A͸	>I͸	>N͸	r͸	~#7>:͸	^#V#> ͸	~#~#fo		> ͸	͸	­	~7:f	
Y  ,:=2R6 	͏
	!\ "	̓! ,":  6%! .q!\ W6L+6R+6B6$#6$#6$&=%M! .a=*"! ,"!  "*~£.^#V#".~#fo	*"r*w#N#F#".^#V*		s#r#"BKPr\ <	,#^#V*	*6#s#ry  z -	,*ͷyo& "ͩH/*3+|#<2*}C~#"ͩ! ~#"**	e	7ͷ:*:2*"ͩ"2Ø2yo& "*H/ͽ+|§:͛*w#"}͛! "~####++**~7~###
G~
~)
#
~
#..N#F#.^#V	,#	, ~#g! e*ͨ*a͛,a͛,a͛,a͛,!  6 ! ~6 !  ~5! 5!  6	2>*͸	
2{	  N !\ :=6 *2*e!e 6B\  !e 6C!u 6B\  !e 6$#6$#6$!u 6C\  w#Z+] m >#~#=o£.^#V#".~#fo	*"r*w#N#F#2%   ! ,":  6%! .q!\ W6L+6R+6B6$#6$#6$&=%M! .a=*"! ,"!  "*~£.^#V#".~#fo	*"r*w#N#F#".^#V*		s#r#"BKPr\ <	,#^#V*	*6#s#r y   	>??HF

::FHM6Q6_R~ãX2<2="2"~
k:T~£R:TO~ʣR~X2"2"~
ڣR
:Oº	FLCQAR":MOMF

:RR"M:RR:=	,**̓͎*ͩ:2qͩ qͩ qͩ q6ɯ2~ x=x
l:~ʆ		2~	xͶ	> ͸	>(͸	x͏
>)͸	x2~#fo+				 		tG9:>	,T"     ~ lse if (norel(args[i])) continue;
		else {
			sprintf(workbuf,"%s$L$%s",cfunam,args[i]);
			for (j = 0; j < labcount; j++)
				if (streq(args[i],lablist[j].labnam))
					goto out2;
			lablist[j].labnam = txtbufp;	/* add new entry to */
			lablist[j].defined = 0;		/* label list 	    */
			strcpy(txtbufp,args[i]);
			bumptxtp(txtbufp);
			labcount++;
		}		   

	out2:
		replstr(linbuf, workbuf, args[i] - pbuf, strlen(args[i]));

		if (streq(op,"DW")) {
			fprintf2(obuf,"%s$R%03d\tEQU\t$-%s$STR x gth;

	pastnfs = 1;
	relblc = 0;

	if (verbose)
		fputs2("\n\n; List of needed functions:\n",obuf);

	for (i=0; i < nfcount; i++) {
		strcpy(workbuf,"\t\tDB\t'");
		length = strlen(nflist[i]);
		length = length < 8 ? length : 8;
		for (j = 0; j < length - 1; j++)
			workbuf[6+j] = nflist[i][j];
		workbuf[6+j] = '\0';
		fprintf2(obuf,"%s','%c'+80H\n",workbuf,nflist[i][j]);
	}

	fputs2("\t\tDB\t0\n",obuf);

	if (verbose)
		fputs2("\n; Length of body:\n",obuf);

	fprintf2(obuf,"\t\tDW\t% q T\n",
				cfunam, relblc++, cfunam);
			if (argcnt > 1)
			  error("Only one relocatable value allowed per DW\n");
		}
		else
			fprintf2(obuf,"%s$R%03d\tEQU\t$+1-%s$STRT\n",
				cfunam, relblc++, cfunam);
		break;
	  }
	fputs2(linbuf,obuf);
}


/*
	Test for ops in which there is guanranteed to be no need
	for generation of relocation parameters. Note that the list
	of non-relocatable ops doesn't necessarily have to be complete,
	because for any op that doesn't match, an argument must stil ! s$END-$-2\n",cfunam);

	if (verbose)
		fputs2("\n; Body:\n",obuf);

	fprintf2(obuf,"%s$STRT\tEQU\t$\n",cfunam);
	if (nfcount) {
		fprintf2(obuf,"%s$R%03d\tEQU\t$+1-%s$STRT\n",
			cfunam,relblc++,cfunam);
		fprintf2(obuf,"\t\tJMP\t%s$STRTC-%s$STRT\n",cfunam,cfunam);
	}
	fprintf2(obuf,"%s$EF$%s\tEQU\t%s$STRT\n",cfunam,cfunam,cfunam);
	for (i=0; i < nfcount; i++)
		fprintf2(obuf,"%s$EF$%s\tJMP\t0\n",cfunam,nflist[i]);
	fprintf2(obuf,"\n%s$STRTC\tEQU\t$\n",cfunam);
}


doreloc()
{
	int i;
  l
	pass other tests before it is deemed relocatable. This only
	speeds things up by telling the program not to bother checking
	the arguments.
*/

norelop(op)
char *op;
{
	if (streq(op,"MOV")) return 1;
	if (streq(op,"INR")) return 1;
	if (streq(op,"DCR")) return 1;
	if (streq(op,"INX")) return 1;
	if (streq(op,"DCX")) return 1;
	if (streq(op,"DAD")) return 1;
	if (streq(op,"MVI")) return 1;
	if (streq(op,"DB")) return 1;
	if (streq(op,"DS")) return 1;
	if (op[2] == 'I') {
		if (streq(op,  
	if(verbose)
		fputs2("\n; Relocation parameters:\n",obuf);

	fprintf2(obuf,"\t\tDW\t%d\n",relblc);
	for(i = 0; i < relblc; i++)
		fprintf2(obuf,"\t\tDW\t%s$R%03d\n",cfunam,i);
	fputs2("\n",obuf);
}


putdir()
{
	int i,j, length;
	int bytecount;

	bytecount = 0;

	fputs2("\n\t\tORG\tTPALOC\n\n; Directory:\n",obuf);
	for (i = 0; i < fcount; i++) {
		strcpy(workbuf,"\t\tDB\t'");
		length = strlen(fnames[i]);
		length = length < 8 ? length : 8;
		for (j = 0; j < length - 1; j++)
			work l "CPI")) return 1;
		if (streq(op,"ORI")) return 1;
		if (streq(op,"ANI")) return 1;
		if (streq(op,"ADI")) return 1;
		if (streq(op,"SUI")) return 1;
		if (streq(op,"SBI")) return 1;
		if (streq(op,"XRI")) return 1;
		if (streq(op,"ACI")) return 1;
	}
	if (streq(op,"ORG")) return 1;
	if (streq(op,"TITLE")) return 1;
	if (streq(op,"PAGE")) return 1;
	if (streq(op,"IF")) return 1;
	if (streq(op,"EJECT")) return 1;
	if (streq(op,"MACRO")) return 1;
	return 0;
}


flushnfs()
{
	int i,j, len ( buf[6+j] = fnames[i][j];
		workbuf[6+j] = '\0';
		fprintf2(obuf,"%s','%c'+80H\n",workbuf,fnames[i][j]);
		fprintf2(obuf,"\t\tDW\t%s$BEG\n",fnames[i]);
		bytecount += (length + 2);
	}
	fputs2("\t\tDB\t80H\n\t\tDW\tEND$CRL\n",obuf);

	bytecount += 3;
	if (bytecount > DIRSIZE) {
		printf("CRL Directory size will exceed 512 bytes;\n");
		printf("Break the file up into smaller chunks, please!\n");
		exit(-1);
	}
}


initequ()
{
	equtab[0] = "A";
	equtab[1] = "B";
	equtab[2] = "C";
	equtab[3    FOPEGETdUNGEThGETFCREAdFAPPENPUT×PUTFFLUSlFCLOS
ATO[
STRCA9STRCMШSTRCPFSTRLEΙISALPHISUPPE6ISLOWElISDIGIԢISSPACTOUPPETOLOWEbQSOR԰_SW0INITלINITGETVARALLOFREŤAB:MAfMIΖPRINTLPRINTSPRINT<_SSP}FPRINTƠ_FPUTSCANHSSCANƎFSCANƼ_SP_GV_USP_SC_IG~!_B!PUTӞ"FGET"FPUT$SWAPIΕ$/%xʄ-.G-:@G*@"m@x-xʵ-4͐8í-.>@2@-x-Zê-4͐8*@͓ê-x-C+í-xʪ-p'~('-w('p'~(͇       PUT Q    !  9DM͐͐ ) |J ͐͐ ͉ |J ͐!    ' ; B WRITMOVMESEE j       !9DM͐% !  a͐n&  |g}o|D !  a͐##~#fo |] !  a͐##~#fo  `is#r͐ ͐ ͐~#fo ͐ ʪ !a͐ + ?`is#r͐##~#fo|:! ͐ ͐ ͐  ͐##~#fo͐ s#r͐ ~#fo͐ s#r! !͐~#fo	 a͐##6 #6͐ ͐ s#r!  a! 9   # < B U [        F OPE P    !  9DM͐!  ͐ s#rz0 !͐##w#w͐6͐~#fo   ) GETCHABDOREA         !9DM͐|#   ͐+++|: !   ͐##^#Vr+s|¸ ! ͐ ͐~#fo	 `is#r!|ҋ ͐##^#Vr+s ͐##͐  ?+s#r͐ ͐ s#r͐ ^#Vr+sn&  ! 9    ! - 4 8 L e w   UNGETC t    !  9DM͐|% ! 	n&  ͐C ͐##~#fo |H !͐ ^#Vr+s! 	ns͐##^#Vr+s!       . A GET [      &  28_FFLUSCLOS ; 	     !  9DM͐! !  ͐ ͐~#fo    ' 4 ISDIGI     !9DM`iw#w! 	6#6 ͐	n! 	s{	9 ! 	n} G !	 	^#Vr+s ! 	n}-f ! 	6#6!	 	^#Vr+s!	 	^#Vr+sn! 	s  |ʧ ͐ 
 ?! 	nѯg`is#rf ͐͐ ?÷ ! 9	  , 7 E P ~     b !9DM͐`is#r͐n}* ! 	^#Vr+s ! 	^#Vr+s͐ns! 	^#Vr+sn}* ͐ Y ! 9  ( P W   !9DM`iw#w! 	~#fo͐ n! 	~#fo͐ n}Z ! 	~#fo`i^#Vr+sn}W !     !9DM͐ `is#rzL ͐ ! 	s#rzL ͐ ?͐ R !R ! 9     ( 6 J P CREA b    !  9DM͐͐ s#rz+ !͐ ͐ s#r͐##6 #6͐6͐~#fo   $ OPEFCREACFSIZCLOSSEEREA s             !9DM! ͐ ! 	s#rzK ͐
͐ j͐	 `is#r|{ ͐ ͐
͐ j! !͐ #|ʵ ! ͐
 ͐ | ͐ !j! !͐ `iw#w͐ |͐
 ͐ n}`i^#Vr  D   ! 	~#fo͐ n! 	~#fo͐ nѯgWÆ ! 9 3 O U X   H !9DM͐`is#r! 	^#Vr+s! 	^#Vr+sns{8  ͐ ? ! 9 3 6 =  = !9DM`iw#w! 	^#Vr+sn}- `i^#Vr+s ͐ 4 ! 9  + 2 ISUPPEISLOWE : 	     !  9DM! 	n&  |ͣ6 ! 	n&  |ͣ   # .  / !  9DM! 	n& |ͯ+ ! 	n& |ͩ   / !  9DM! 	n& |ͯ+ ! 	n& |ͩ   / !  9DM! 	n& |ͯ+ ! 	n& |ͩ   3 !  9DM! 	n} ͝/ ! 	n}	͝/ !  $ +s ͐
͐s#r͐
 ͐
 ͐ s#r͐
## ! ?͐ s#r͐
6͐j! 9  ' 7 D I Q ^ f t y          hPUTCHABDOWRIT 4       !  9DM͐ڵ ͐>/ > V >; > d >G > w >S > ʊ õ ! 	n&  ! 	n& !  ! 	n& !  ! 	n}
¢ ! !  ! 	n& !  ͐##^#Vr+s|! ͐ ͐~#fo	 | !͐##6#6͐ ͐ s#r͐ ^#Vr+s! 	ns&    ' - 3 9 ? E K Q T _ q      c  	n}
͝  " ISLOWE :    !  9DM! 	n&  |- ! 	n& 4 ! 	n& &     + ISUPPE :    !  9DM! 	n&  |- ! 	n&   4 ! 	n& &     + _SW a   !9DM͐͐k! 	s#r͐ ͉! 	s#r͐|X͐͐k! 	s#r͐͐! 	s#r͐͐!
 	s#r͐`is#r͐ ͐@͐ ͐! 	s#r͐|*͐͐
͐͐͐! ! 9~#fo| *͐
͐͐͐͐ ! 	~#fo͐s#rê `i~#fo͐s#rÄ ! 	~#fo0  ] = "D";
	equtab[4] = "E";
	equtab[5] = "H";
	equtab[6] = "L";
	equtab[7] = "M";
	equtab[8] = "SP";
	equtab[9] = "PSW";
	equtab[10]= "AND";
	equtab[11]= "OR";
	equtab[12]= "MOD";
	equtab[13]= "NOT";
	equtab[14]= "XOR";
	equtab[15]= "SHL";
	equtab[16]= "SHR";
	equcount = 14;
}


int isidchr(c)	/* return true if c is legal character in identifier */
char c;
{	
	return isalpha(c) || c == '$' || isdigit(c) || c == '.';
}


int isidstrt(c)	/* return true if c is legal as first char of id  r out of space condition */
{
	int i;
	if ((i = sbrk(n)) == ERROR)
		abort("Out of storage allocation space\n");
	return i;
}

bumptxtp(str)	/* bump txtbufp by size of given string + 1 */
char *str;
{
	txtbufp += strlen(str) + 1;
	if (txtbufp >= txtbuf + (TXTBUFSIZE - 8))
	 abort("Out of text space. Increase TXTBUFSIZE and recompile CASM");
}


int norel(id)	/* return true if identifier is exempt from relocatetion */
char *id;
{
	if (isequ(id)) return 1;
	return 0;
}


int isequ(str 6 enfitier */
char c;
{
	return isalpha(c);
}


int streq(s1, s2)	/* return true if the two strings are equal */
char *s1, *s2;
{
	if (*s1 != *s2) return 0;	/* special case for speed */
	while (*s1) if (*s1++ != *s2++) return 0;
	return (*s2) ? 0 : 1;
}


skip_wsp(strptr)	/* skip white space at *strptr and modify the ptr */
char **strptr;
{
	while (isspace(**strptr)) (*strptr)++;
}


strcpy2(s1,s2)	/* copy s2 to s1, converting to upper case as we go */
char *s1, *s2;
{
	while (*s2)
  )	/* return true if given string is in the EQU table */
char *str;
{
	int i;
	for (i = 0; i < equcount; i++)
		if (streq(str,equtab[i]))
			return 1;
	return 0;
}


char *isef(str)	/* return nflist entry if given string is an external */
char *str;	/* function name */
{
	int i;
	for (i = 0; i < nfcount; i++)
		if (streq(str,nflist[i]))
			return nflist[i];
	return 0;
}

int hasdot(str)	/* return true if given string has a dot in it */
char *str;
{
	while (*str)
		if (*str++ == '.') ? 	     *s1++ = toupper(*s2++);
	*s1 = '\0';
}


/*
	General-purpose string-replacement function:
		'string'	is pointer to entire string,
		'insstr'	is pointer to string to be inserted,
		'pos'		is the position in 'string' where 'insstr'
				is to be inserted
		'lenold'	is the length of the substring in 'string'
				that is being replaced.
*/

replstr(string, insstr, pos, lenold)
char *string, *insstr;
{
	int length, i, j, k, x;

	length = strlen(string);
	x = strlen(insstr);
	k = x - le « 
			return TRUE;
	return FALSE;
}

fputs2(arg1,arg2)
{
	if (fputs(arg1,arg2) == ERROR)
		abort("Out of disk space for output file.");
}

fprintf2(arg1,arg2,arg3,arg4,arg5)
{
	if (fprintf(arg1,arg2,arg3,arg4,arg5) == ERROR)
		abort("Out of dis  k space for output file.");
}
0  0;
}

int hasdot(str)	/* return true if given string has a dot in it */
char *str;
{
	while (*str)
		if (*str++ == '.') a nold;
	i = string + pos + lenold;
	if (k) movmem(i, i+k, length - (pos + lenold) + 1);
	for (i = 0, j = pos; i < x; i++, j++)
		string[j] = insstr[i];
}


error(msg,arg1,arg2)
char *msg;
{
	printf("\n\7%s: %d: ",cfilnam,lino);
	printf(msg,arg1,arg2);
	errf = 1;
}


abort(msg,arg1,arg2)
char *msg;
{
	error(msg,arg1,arg2);
	putchar('\n');
	if (cbufp == incbuf) fclose(incbuf);
	fclose(fbuf);
	if (*SUBFILE)
		unlink(SUBFILE);
	exit(-1);
}


sbrk2(n)	/* allocate storage and check fo    .    ͉s#r6 ! 9  =      
(>VMOVME Y    !9DM̓`i̓ ̓̓̓	 ̓̓	`i !9   6 K GETVA J    !9DM! 	 `is#r!|A ! 	^#Vr+s͐ s#r ! 9   $ ? GETVA F    !9DM! 	 `is#r!|= ! 	^#Vr+s͐ s ! 9   $ ; ATO j    !9DM͐~#fon}" !a ͐~#fo `is#r͐~#fon}Z ͐^#Vr+sn},Z 5 ͐ a ! 9     , A U X _ SBRFRE 	     !9DM͐### ͉  a  ! 9   ! ' 2 7 _USPISDIGI_GVTOUPPE          !Y9DM! 	^#Vr+s~#fo! 	s#r͐! 	s#r! 	^#Vr+sn`is{`in}%»! 	! 	s#r! 	6#6 ! 	 s! 	s! 	s͐n}- ! 	^#Vr+s! 	4͐n}0¯ ! 	4͐n&  } ! 		  !  ! 	s#r! 	^#Vr+sn`is{.! 		 ! 	s#r! 	4! 	^#Vr+sn`is`in&  }DHUʄXʍOʖCS ʆÌ͐~#fo|҄! 	^#Vr+s6-͐͐~#fos#r! 	^#Vr+s! 	6
Ü! 	6Ü! 	6! 	~#fo! 	n& ! 	^#Vr+s~#fo! 	     ! 	s#r\! 	s#rzd *! 	s#r* s#r*s#r*##w#w͐~#fo`is#r͐ ##~#fo͐.͐* s#r͐ ##~#fo͐ \͐ ~#fos#r#\͐ ͐))s#r! 	s#r͐͐ ~#fos#r͐##͐ ##~#fo͐s#r͐ ##͐s#r͐ ####á͐ \͐)) ! 	s#rz]!  á͐##͐s#r͐#### \`is#r͐ ! 	s#r͐ ~#fo`is#rr ! 9  :    ,<FU[w {!9DM͐++++`is#r\! 	s#r͐ ͐F ͐ ͐~#foڔ ͐͐~#foځ   gs#rÅ! 	^#Vr+s! 	^#Vr+s~#fos! 	^#Vr+sÅ! 	n} ! 	6#6 ! 	^#Vr+s~#fo! 	s#r͐n}ʅ͐|ʅ! 	^#Vr+s! 	^#Vr+sns! 	^#Vr+s! 	^#Vr+s;͐6 ! 	! 	s#r! 	n}! 	^#Vr+s!|͐͐! 	n}!0 !  !! 9~#fo#|!á͐n}7͐͐! 	^#Vr+sn& !%! 9~#fo#|4!! 	n}ʃ! 	^#Vr+s!|ڃ͐͐!  !q! 9~#fo#|!Aø!  ͐͐`in& !! 9~#fo#|¸!͐͐`in& !  ,  ͐ ͐~ ͐ ͐~#foҁ Ô ͐~#fo! 	s#r" ͐ ͐ ##~#fo))͐~#fo ͐ ##~#fo͐~#fo##~#fos#r͐ ͐~#fo~#fos#r͐ ͐~#fos#r͐͐##~#fo))͐ T͐##~#fo͐ ##~#fos#r͐͐ ~#fos#rb͐͐ s#r͐* s#r! 9 0 D X h |      R # !  9DM͐| ͐ ͐    ' !  9DM͐͐ ͐# ͐    ' !  9DM͐͐ ͐# ͐   PUTCHA_SP # 	     !  9DM* ! 	     _   ! 9~#fo#|!> !  ! 9<  S \         %*/49>CFSCL,25?Tex~ISDIGI c    !9DM`iw#w͐~#fon&  }S ͐ 
 ?͐^#Vr+snѯg`is#r ͐ Z ! 9  ! ' Q X _USP     !9DM͐͐	T ͐^#Vr+s͐A ͐0 I ͐7 s! & ß ͐	͐͐	͉͐ `is͐	͐͐	)͐ `in& #& ß ! 9   4 ? R m   ISSPAC_IGTOUPPE_BPOK     FPUT_SP ( 	     !  9DM! * ! 	     _SSP_SP - 	     !  9DM! 	* ! 	 ͐6        !  9DM͐^#Vr+s͐s  _FPUT_SP ) 	     !  9DM͐* ! 	      PUT U    !  9DM͐|4 ͐!  #|4 !͐͐ #|N !!     % - ? G GET_SC 1 	     !j9DM`i ! 	`i ( ! 9   ! & _SC !    !  9DM! 	͐    FGET_SC B 	     !j9DM͐`i |) !9 ! 	`i 9             !9DM! 	^#Vr+s~#fo! 	s#r͐! 	s#r! 	6 ! 	^#Vr+sn! 	s{! 	n&  |t G ! 	n}%ʲ ! 	n! 	  ʤ ! 	n& ï ! 	^#Vr+s! 	6#6 ! 	6
`i6 ! 	^#Vr+sn! 	s{* `i4! 	^#Vr+sn! 	s! 	n& 	 }X$O-D6U\SC{÷! 	6\! 	6\! 	 |\! 	6#6! 	^#Vr+s!
 	w#w! 	n& ! 	  #|! 	n& ! 	n& ! 	^#Vr+sn&  ! 	s{͐
! 	nѯg?! 	nѯg!
 	s#rË! 	^#Vr+s! 	 ͐~#fo! 	s#r!   

/*
	Floating point package support routines

	Note the "fp" library function, available in DEFF2.CRL,
	is used extensively by all the floating point number
	crunching functions.

	-- ~-
	Usage: After compiling your program, link with this library
	by typing:

	A>clink <your program files> -f float <cr>
	-- K-

	NEW FEATURE: a special "printf" function has been included
		     in   ++s;
	if (*s=='-'){sign_boolean=1;++s;}
	for (;isdigit(*s);++s){
		fpmult(fpno,fpno,FP_10);
		work[0]=*s-'0';
		work[1]=work[2]=work[3]=0;work[4]=31;
		fpadd(fpno,fpno,fpnorm(work));
	}
	if (*s=='.'){
		++s;
		for (;isdigit(*s);--power,++s){
			fpmult(fpno,fpno,FP_10);
			work[0]=*s-'0';
			work[1]=work[2]=work[3]=0;work[4]=31;
			fpadd(fpno,fpno,fpnorm(work));
		}
	}
	if (toupper(*s) == 'E') {++s; power += atoi(s); }
	if (power>0)
		for (;power!=0;--power) fpmult(fpno,fpno,FP_10);
	els   this source file for use with floating point
		     operands, in addition to the normal types. The
		     printf presented here will take precedence over
		     the DEFF.CRL version when "float" is specified
		     on the CLINK command line at linkage time.
		     Note that the "fp" function, needed by most of
		     the functions in this file, resides in DEFF2.CRL
		     and will be automatically collected by CLINK.

	All functions here written by Bob Mathias, except printf and
	_spr (written by  e
	if (power<0)
		for (;power!=0;++power) fpdiv(fpno,fpno,FP_10);
	if (sign_boolean){
		setmem(ZERO,5,0);
		fpsub(fpno,ZERO,fpno);
	}
	return(fpno);
}
ftoa(result,op1)
	char *result,*op1;
{	fp(FTOA_CODE,result,op1);return(result);}

itof(op1,n)
char *op1;
int n;
{
	char temp[20];
	return atof(op1, itoa(temp,n));
}

itoa(str,n)
char *str;
{
	char *sptr;
	sptr = str;
	if (n<0) { *sptr++ = '-'; n = -n; }
	_uspr(&sptr, n, 10);
	*sptr = '\0';
	return str;
}

/*
	This is the speci -  Leor Zolman.)
*/

#include <bdscio.h>

#define NORM_CODE	0
#define ADD_CODE	1
#define SUB_CODE	2
#define MULT_CODE	3
#define DIV_CODE	4
#define FTOA_CODE	5

fpcomp(op1,op2)
	char *op1,*op2;
{
	char work[5];
	fpsub(work,op1,op2);
	if (work[3] > 127) return (-1);
	if (work[0]+work[1]+work[2]+work[3]) return (1);
	return (0);
}

fpnorm(op1) char *op1;
{	fp(NORM_CODE,op1,op1);return(op1);}

fpadd(result,op1,op2)
	char *result,*op1,*op2;
{	fp(ADD_CODE,result,op1,op2);return(result);}  al formatting function, which supports the
	"e" and "f" conversions as well as the normal "d", "s", etc.
	When using "e" or "f" format, the corresponding argument in
	the argument list should be a pointer to one of the five-byte
	strings used as floating point numbers by the floating point
	functions. Note that you don't need to ever use the "ftoa"
	function when using this special printf/sprintf combination;
	to achieve the same result as ftoa, a simple "%e" format
	conversion will do the trick. "% ] 

fpsub(result,op2,op1)
	char *result,*op1,*op2;
	{fp(SUB_CODE,result,op1,op2);return(result);}

fpmult(result,op1,op2)
	char *result,*op1,*op2;
{	fp(MULT_CODE,result,op1,op2);return(result);}

fpdiv(result,op1,op2)
	char *result,*op1,*op2;
{	fp(DIV_CODE,result,op1,op2);return(result);}

atof(fpno,s)
	char fpno[5],*s;
{
	char *fpnorm(),work[5],ZERO[5],FP_10[5];
	int sign_boolean,power;

	initb(FP_10,"0,0,0,80,4");
	setmem(fpno,5,0);
	sign_boolean=power=0;

	while (*s==' ' || *s=='\t') ] f" is used to eliminate the
	scientific notation and set the precision. The only [known]
	difference between the "e" and "f" conversions as used here
	and the ones described in the Kernighan & Ritchie book is that
	ROUNDING does not take place in this version...e.g., printing
	a floating point number which happens to equal exactly 3.999
	using a "%5.2f" format conversion will produce " 3.99" instead
	of " 4.00".
*/

printf(format)
char *format;
{
	int putchar();
	_spr(&format, &putchar);	/* us    	^#Vr+sn! 	s{Y! 	n͐n}9! 	^#Vr+sY`in}V! 	^#Vr+s! 	ns`in}x! 	4͐6 ! 	^#Vr+sG `in}©͐n& ! 	^#Vr+s~#fo ! 	4! 	^#Vr+sG ! 	n& `in}! 	^#Vr+s~#fo͐
͐?s#r! 	4͐n}! 	n& G ! 	n& ! 91  ^ i o r }        "+4<Frw)7?W_y	ISSPAC F    !9DM͐~#fon`is  |5 ͐^#Vr+s `in& = ! 9   % 3 ; ISALPHTOUPPEISDIGI         !  t GETCHAKBHICUNGETC^PUTCHArPUTCȪGETRANSRAN6SRANDNRANCSSETMEMOVME$CAL̄CALLINOUTPEEPOKSLEEPAUSNEXIaBDOiBIOBIOSȪCODENEXTERNENDEXTOPOFMEEXEEXEC(SBR|RSVST˸MEMCMINDEGETLIN6SETJM{LONGJMКSETPLOCLRPLOLINPLO	TXTPLO	SETFC4
OPE]
CLOS
CREA
UNLIN5RENAMaFABORFCBADDREAWRITSEEˠTELCFSIZ)OFLOׄERRNϨERRMSǴEXEĈFLONǿm0H# -(MOVMEMR002+ Q"MOVMEMR0039 &MOVMEMLM8080T? !MOVMEMR0     9DM! 	n&  ! 	s  |D ! 	n& sl ! 	n& 	 }g ! 	n& sl !! 	n! 	n& + ҋ !Ô ! 	n& 
   * 0 B M S e   PUTCHA 2    !  9DM͐n}0 ! 	^#Vr+sn&      * . GETUNGET  	     !9DM`i6#6 ͐
! 	s#r͐ ! 	s#r!|H ͐#|N !   ! 	^#Vr+s͐s{
 ͐͐
#ҕ ͐++n} ! 	^#Vr+s6
 `i^#Vr+sz ͐ ! 	s#rz ͐|N ͐| ͐͐ ͐6 ͐
 ! 9  * < F L f w     CD 5 :no 2n&   !o2 
 .
&   %   :n& o !  ,    :no2n&    / 

  >
_  #    	    
_
  
  
  1 
!j96
 
 #F#x, ~#  " *  ( *H>H  7*J|g}o"Jzg{o"H|g    i 
| "H"JE 	 ! ### "H"J 
  Wait a few seconds, and type a CR: $   ( PUT (    
 !xV ### "H"J    PUT     7*P|& *R"  `         PUT j    !9DM! 	^#Vr+sn`is{[ `in}
< ͐!  ͐`in&  #|X !a  !  a ! 9	  # , 8 H P V Y _ OPEREACLOS t        !9DM!  ͐ `is#rz4 !k ! ͐͐  |\ ͐ 	 !k ͐ 	 !  k ! 9
   , 2 C K S Z b i   !9DM!  ͐ `is#rz4 !k ! ͐͐  |\ ͐ 	 !k+s6
 `i^#Vr+sz ͐ ! 	s#rz ͐|N ͐| ͐͐ ͐6 ͐
 ! 9  * < F L f w    u  *T" *V" |O *R !Z ##7 " " " : 2 ! 6 #\  ! 	~W! ~w#u zҖ !  w# n f !  ?/ w#© +~g: oŇ                # * 1 B E H K P U Z a g p {             o&     7*R*P:TOz q#     Q 7*T|DM*R*P/ ><# ~#x# 		><? ~+x? |}   + 9 G   7*X*VDM:R! *P*T   ! 7*X*VDM:R! *P*To&     
2_^o&     
2ba    
n&            7*P:Rw   0 
#+| 'z       	   .              7:PO*R    $ 7* +++:PG_ *RDM! o&    & 7* +++:PG_ *RDM*TT]!$      *    *    *    * : +  EXEC     
      EXEC >    7*R ^#V#z x2= +V+^+ *P := <o& 9!     % , /  1 
*d& +*f|/g}/o#9* & #"dz{ 
     
"f   $ DMx ! # !      6 7*P*R"  e "_spr" to form the output */
}


_spr(fmt,putcf,arg1)
int (*putcf)();
char **fmt;
{
	char _uspr(), c, base, *sptr, *format;
	char wbuf[MAXLINE], *wptr, pf, ljflag, zfflag;
	int width, precision, exp, *args;

	format = *fmt++;	/* fmt first points to the format string */
	args = fmt;		/* now fmt points to the first arg value */
	while (c = *format++)
	  if (c == '%') {
	    wptr = wbuf;
	    precision = 6;
	    ljflag = pf = zfflag = 0;

	    if (*format == '-') {
		    format++;
		     e = 16; goto val;

		case 'O':  base = 8;

		     val:  width -= _uspr(&wptr,*args++,base);
			   goto pad;

		case 'C':  *wptr++ = *args++;
			   width--;
			   goto pad;

		case 'S':  if (!pf) precision = 200;
			   sptr = *args++;
			   while (*sptr && precision) {
				*wptr++ = *sptr++;
				precision--;
				width--;
			    }

		     pad:  *wptr = '\0';
		     pad2: wptr = wbuf;
			   if (!ljflag)
			    while (width-- > 0)
				if ((*putcf)(zfflag ? '0' : ' ',arg1) == ERROR)
					 v  ljflag++;
	     }

	    if (*format == '0') zfflag++;	/* test for zero fill */

	    width = isdigit(*format) ? _gv2(&format) : 0;

	    if ((c = *format++) == '.') {
		    precision = _gv2(&format);
		    pf++;
		    c = *format++;
	     }

	    switch(toupper(c)) {
		case 'E':  if (precision>7) precision = 7;
			   ftoa(wbuf,*args++);
			   strcpy(wbuf+precision+3, wbuf+10);
			   width -= strlen(wbuf);
			   goto pad2;

		case 'F':  ftoa(&wbuf[60],*args++);
			   sptr = &wbuf[60];
  return ERROR;

			    while (*wptr)
				if ((*putcf)(*wptr++, arg1) == ERROR)
					return ERROR;

			    if (ljflag)
			     while (width-- > 0)
				if ((*putcf)(' ', arg1) == ERROR)
					return ERROR;
			   break;

		 default:  if ((*putcf)(c t, arg1) == ERROR)
				return ERROR;
	     }
	  }
	  else if ((*putcf)(c, arg1) == ERROR)
		return ERROR;
}

   pad2: wptr = wbuf;
			   if (!ljflag)
			    while (width-- > 0)
				if ((*putcf)(zfflag ? '0' : ' ',arg1) == ERROR)
					 ! 			   while ( *sptr++ != 'E')
				;
			   exp = atoi(sptr);
			   sptr = &wbuf[60];
			   if (*sptr == ' ') sptr++;
			   if (*sptr == '-') {
				*wptr++ = '-';
				sptr++;
				width--;
			    }
			   sptr += 2;

			   if (exp < 1) {
				*wptr++ = '0';
				width--;
			    }

			   pf = 7;
			   while (exp > 0 && pf) {
				*wptr++ = *sptr++;
				pf--;
				exp--;
				width--;
			    }

			   while (exp > 0) {
				*wptr++ = '0';
				exp--;
				width--;
			    }

			   *wptr++ = '     .';
			   width--;

			   while (exp < 0 && precision) {
				*wptr++ = '0';
				exp++;
				precision--;
				width--;
			    }

			   while (precision && pf) {
				*wptr++ = *sptr++;
				pf--;
				precision--;
				width--;
			    }

			   while (precision>0) {
				*wptr++ = '0';
				precision--;
				width--;
			    }

			   goto pad;


		case 'D':  if (*args < 0) {
				*wptr++ = '-';
				*args = -*args;
				width--;
			    }
		case 'U':  base = 10; goto val;

		case 'X':  bas    <    !ɾ #~, *P       / 4  < O
 9q
 
 #F#Hx5 ~#( i&  + 3   
q#p#!  9s#r#s#r!       
N#F#^#V#" * ~#fo     7*P"@*T"B*R"Dk"F    *F*@6 #z     7:RO:TGPY| :VO:XG| `i# z͚ 8 {͚ 8 K | PY# # |^ |] ^ %}o }n o -|G}Ox*B*@<=ʏ Ç Y :Pwɷ/<    & + 0 5 9 < B F R W [ c h l    " 7:P*B*@<=  :R_ :Tw    5 7*R*    to "open" Can't create the file Seek past 65535th record Errmsg: error number out of range            " $ & ( * , . 0 2  ,7*P!9/:q2	 	6C#6O#6M 58 *R|N R!\ &` !\ &*T|` !T!l & ! 9 ~#foʐ > + #~~ ##r xS  	 3 EXECL: Command line overflow
$! p! *w# * : 1 * ! !   a{    ѷ    !   1 > L [ y             7!& :P_ ! og( 2 ; D M V ]   Bk*T*@*P :V' ~. ɰ#'  # * 3    7*R~#  	 +*P&!      h 7, >
2h*P/:q2 >_ :h):RK =K =>_ :qw#w#w:ho& 552?  , ; A G   #  UNLINOPE B 	     7*P :q2\  54 >2?! *P    * =  ' 
!\ /:q2 5!  >2?+   l 7*P!7 /:q2*R!G /7  5!  >2?+ Q:zJEËCEQyQxQR 	     
) >2?6 !      
)  i  ͌ ̀ m  . m v. m ́. m . ] ͫ*T!6 #]] *V!6 #]*R]:2 !! ­ 2!)!5: !4+3:!!  !]! :!B/<  !:!]:!G8!d+B!d822!d!d!=͌ 4+~q374! f!U!:<w!U!6!3!3!5¢!3!~!]:͌ !!=>@w#> w! !Uf!U>2    >2?
,    7:P)V>ڣ z>ʣ z2:P,"j!  "l*T|*l; 5*R *j! ѷl 2?f f !6 *l6 *T+"T*R "R*l#"l*j! 	N#Fp+qx+ ##6>2?0 2?
   4 Q Y ^ d j     7:P)"XV>ڮ z>	ʮ z2:P,"j!  "l*T|\ *j! ^#V*X#^#VT r+s*l5*R  "R*j" *lʄ 2?W #"l*T+"T*j! 	N#Fp+qx. ##6>2?T 2?   4 O |    CFSIZ Q    7:P,> 2?! ^#V*R:TE =6 E *P *R! s#r      !:G~<w͐K!]7L!*!*!56͐!=!~3!4!!]!H:*R"6 :6-!*#60#6.#"2! *60#"ù!5
>!~!=!]!6 !)͆!4H!36>2!~p!>0*w#"!5ʹ͆U!5! c2c2!]!)!)!=!)*6E#:/<26-#: 
2>0w#:0w#6 !]́!5!]́!47~/ w#ɯ#!ɧ   , 0 4 <   
, >2?! ~#fo   R 
, >2?)~2#"j!! ~#fo# ^#Vp+q*j~#foL s#r5  E   
, >2?# ~!  #    :?o&    

 >) ~#fo4 K b y      2ATjNo errors occurred yet Reading unwritten data Disk out of data space Can't close current extent Seek to unwritten extent Can't create new extent Seek past end of disk Bad file descriptor File not open for read File not open for write Too many files open File not found Bad mode  W ~w#*ɧ~w+4ɧw#>ɧ#J6 #Uw#]:2x!!:w:!RAR RAL RRC RLC NOP CPI ORI XRI ANI SBI Iffff   P             " $ ) , / 3 6 9 < ? B E H K N Q T W Z b j n u }                                 
!$),/369<@DGJMPSVY^aknsw|$),/7:=@EIMRUZ]adgjmruz  /*	C-Source for Long (32-bit signed) Integer Package
 *	Rob Shostak
 *	August, 1982			
 */
        


char *itol(result,n)			/* integer to long */
char *result;
int n;
{
return(long(0,result,n));
}

int ltoi(l)				/* converts long to integer */
char l[];
{
return(l[3] + (l[2] << 8));
}

lcomp(op1,op2)				/* compares two longs */
char *op1,*op2;
{
return(long(1,op1,op2));
}

char *ladd(result,op1,op2)		/* adds two longs */
char *result,*op1,*op2;
{
return(long(2,result,op1,op2));  rce;
{
*ldest++ = *lsource++;	/* copy first two bytes */
*ldest = *lsource;	/* then last two */
return(ldest);
}

/* ltou(l) converts long l to an unsigned (by truncating) */

unsigned ltou(l)
char l[];
{
return(l[3] + (l[2] << 8));
}

/* u tol(l,u) converts unsigned to long */

utol(l,u)
char l[];
unsigned u;
{
itol(l, u & 0x7FFF);			/* convert integer part */
if(u > 0x7FFF) l[2] += 0x80;		/* take care of leftmost bit */
return(l);
}
   
}

char *lsub(result,op1,op2)		/* subtracts two longs */
char *result,*op1,*op2;
{
return(long(3,result,op1,op2));
}

char *lmul(result,op1,op2)		/* multiplies two longs */
char *result,*op1,*op2;
{
return(long(4,result,op1,op2));
}

char *ldiv(result,op1,op2)		/* "long" division */
char *result,*op1,*op2;
{
return(long(5,result,op1,op2));
}

char *lmod(result,op1,op2)		/* long multiplication */
char *result,*op1,*op2;
{
return(long(6,result,op1,op2));
}


char *atol(result,s)		    ! 	/* ascii to long */
char *result,*s;
{
char ten[4], temp[4], sign;

itol(ten,10); itol(result,0);

if(sign=(*s == '-')) s++;

while(isdigit(*s))
  ladd(result,lmul(result,result,ten),itol(temp,*s++ - '0'));

return(sign? lsub(result,itol(temp,0),result) : result);
}

char *ltoa(result,op1)				/* long to ascii string */
char *result,*op1;
{
char absval[4], temp[4];
char work[15], *workptr, sign;
char ten[4], zero[4], *rptr;

rptr = result;
itol(ten,10); itol(zero,0);			/* init these *     /

if(sign = *op1 & 0x80)				/* negative operand */
  {
  *rptr++ = '-';
  lsub(absval,zero,op1);
  }
else lassign(absval,op1);

*(workptr = work+14) = '\0';		/* generate digits in reverse order */
do					
  *(--workptr) = '0'+ *(lmod(temp,absval,ten) + 3);
while
  (lcomp(ldiv(absval,absval,ten),zero) > 0);

strcpy(rptr,workptr);
return(result);
}


/* lassign(ldest,lsource) assigns long lsource to ldest, returns
   ptr to ldest */

char *lassign(ldest,lsource)
unsigned *ldest, *lsou        $',147;>CFKNSV\adhknquz}
%0:EQZcgjnqvy| T]) " 6 W ` i r { |   Ö ͌!P͖͌!͞ ##̈́ ͡ Ö ̈́ ͞ Ö ̈́  Ö ̈́ Ö ̈́ 0Ö %͌!P͖+Ì͖Ͷ !S~_+~W+~O+~Go_}W}O}G͌Ͷ ͖   x !P~  !P!T͖    ͭܡ  B͌ :P B   1       b͸{w{ÖüH!K]jU2͵^#V#*~#fo^# *~#fo^#V#*n^# *n^#V#	~#fo^#& 	~#fo! +!  #! +!  #! +! +        }|z{|}|z7||7zZZ)|/g}/o#  |͉k|/g}/o#ɯ2hZZk:h|/g}/o#|/g}/o#:h<2hqDM!  xxGyO҃)v|͔`i|)Öx  ڷz/W{/_ѯzW{_=yOxGæ2hZZ͉M|}ȯ|g}o)|/g}/o    !T.x@XͿ,K}2X!P:X=|2Xͭc33͞ Ͷ 7͡ F#N#V#^p#q#r#sxGyOzW{_~w#~w#~w#~w{_zWyOxG###~w+~w+~w+~ww#w#w#wx>~###~pG#~qO#~rW#~s_J 	         1 4 : @ F L O X [ ^ a d g j m p s v y |                   $(+.1:=@FORV`dgnvz: @ F L O X [ ^ a d}O}G͌Ͷ ͖   x !P~  !P!T͖    ͭܡ  B͌ :P B   #z/W{/_! 9~#fo! ! !
 ! ! ! P! 9~#A!  9"w* *w"j!z*"d!"f!Y"H>2^>2a>2`2c>2s2t>2r>2v! "@! "D!@ "B! "F   ! F#x :~#! |2i~# :"	2i
+}|~#:G:ix."2i+w# +6 #!6 #@A2n2?*j**|+`"d!"f!!>ڌo& ͖=}	
w~2ʸͼ 56 !  +W	?_ !~7z?ͧ:> ͞@w#5      * .w w#w#w#w*>?@͌>w#͌5> w#@ͧ͵g  2q& 0OxG͵j/ʆSx\͞.7:77!a{  ʨ	ʨ0:?ŷO	!y$ 7o& ))T])))!y ,  2p_  :p*    ڌo& ͖=}	
w~2ʸͼ 56 !  +W	?_ !~7z?ͧ:> ͞@w#5          /*
	CP.C
	Written by Leor Zolman, 3/18/82
	Modified for v1.50 9/82

	CP either copies a file from any disk and user area to any other
	disk and user area, or copies a list of files from the current
	disk and user area to some other disk and/or user area.

	Usages:

	A>cp [user#/][d:]<filename> [user#/][d:][<filename>] [options] <cr>
	A>cp [user#/][d:]<filename> { user#/ or d: or . } [options] <cr>
    or 	A>cp [user#/][d:]<filename> . [options] <cr> 
    or	A>cp <afn>  { <user#/> or <d:> } [op  ame u/ [-v]\n");
		printf("	cp [u/][d:]filename d: [-v]\n");
		printf("	cp [u/][d:]filename .  [-v]\n");
		printf("	cp <afn>  { <u/> or <d:> or <u/d:> } [-v]\n");
		exit();
	}

	if (verify)
		vbuf =  sbrk(SECSIZ);

	corebuf = sbrk(SECSIZ);
	for (bufsize = SECSIZ; sbrk(SECSIZ) != ERROR; bufsize += SECSIZ)
		;
	bufsects = bufsize / SECSIZ;


   for (loop = 1; loop < argc-1; loop++)
   {
	if ((fd1 = open(argv[loop],0)) == ERROR) {
		printf("\nCan't open %s\n",argv[loop]);
		continue;	/* go   tions] <cr>

	Options:
			-V	Verify by reading after writing
			

	Note that the filename portion of the last argument is optional
	when only one file is being copied, but not permitted at all when
	multiple files are being copied.
	If files are being copied and the destination filename is omitted,
 	CP attempts to copy to the disk and/or user number specified, leaving
	the filename(s) the same. For example, to copy *.com into user area 7:

		cp  *.com  7/ 

	If the entire second argument is   on to next one anyway. */
	}

	strcpy(destname,lastarg);	/* create output filename */

	if ( (c = destname[strlen(destname) - 1])=='/' || c == ':' ||
		  				!strcmp(destname,"."))
	{
		if (!strcmp(destname,"."))
			*destname = '\0';
		for (i = strlen(argv[loop]) - 1; i >= 0; i--)
			if (argv[loop][i] == '/' || argv[loop][i] == ':')
				break;				
		strcat(destname,&argv[loop][i+1]);
	}

	if ((fd2 = creat(destname)) == ERROR) {
	  	printf("\nCan't create %s\n",destname);
		printf("Assuming l a single dot (.), then the destin-
	ation is the CURRENT disk and user area. For example, to copy foo.c
	from user are 4 into the current user area:

		cp 4/foo.c .

	Link with:
		clink cp wildexp -n

	(or) 	l2 cp wildexp
		noboot cp
*/

#include <bdscio.h>

main(argc,argv)
char **argv;
{
	int i,j,k,c,loop;
	int fd1,fd2;
	int bufsects;
	unsigned bufsize;
	unsigned corebuf;
	char cur_disk;			/* currently logged-in disk */
	char destname[30];
	char *lastarg;
	char verify, *vbuf;		/*    out of directory space and aborting.\n");
		exit();	
	}

	if (loop != 1)
		putchar('\n');

	printf("\t copying %s to %s...",argv[loop],destname);

	while (1)
	{
		if (kbhit()) getchar();
		if (!(i = read(fd1,corebuf,bufsects))) break;
		if (i == ERROR)
		{
		    printf("\nRead error: tell(fd1) = %d, \"%s\"\n",
						tell(fd1), errmsg(errno()));
		    break;
		}

		if (kbhit()) getchar();
		if (write(fd2,corebuf,i) != i) {
			printf("\nWrite error: %s\n",errmsg(errno()));
			exit();
  true when verifying writes */

	verify = FALSE;
	wildexp(&argc,&argv);

	cur_disk = 'A' + bdos(25);

	for (i = argc - 1; i > 2; --i)
		if (*argv[i] == '-')
		{
			switch(argv[i][1])
			{
				case 'V':
					verify = TRUE;
					break;
			}
			argc--;
		}
		else
			break;

	lastarg = argv[argc - 1];

	if (argc < 3 || (argc > 3 &&
	    !((c = lastarg[strlen(lastarg)-1]) == '/' || c == ':')))
	{
		printf("Usages: cp [u/][d:]filename [u/][d:]newname [-v]\n");
		printf("	cp [u/][d:]filen  		}
		if (verify)
		{	
			puts("(verifying)");
			seek(fd2, -i, 1);
			for (j = 0, k = corebuf; j < i; j++, k += SECSIZ)
			{
				if (read(fd2, vbuf, 1) != 1)
					printf("\nVerify read error on %s\n",
						destname);
				if (memcmp(vbuf, k, SECSIZ))
					continue;
				else
					printf("\nVerify error on %s\n",
						destname);
			}
		}
	}

	if (close(fd2) == ERROR) {
		printf("\nCan't close the output file.\n");;
		exit();
	}
	fabort(fd1);
   }
}

/*
	Return true if the string  
   /*
 *	The BDS C Standard I/O header file --  v1.50	12/29/82
 *
 *	This file contains global definitions, for use in all C programs
 *	in PLACE of (yechhh) CONSTANTS. Characteristics of your system such
 *	buffered I/O allocations, storage allocator state, etc., should all
 *	be configured just once within this file. Any program which needs
 *	them should contain the preprocessor directive:
 *
 *		#include <bdscio.h>
 *
 *	near the beginning. 
 */


/*
 *	General purpose Symbolic constants:
   f {				/* Or this...	    */
	int _fd;
	int _nleft;
	char *_nextp;
	char _buff[NSECTS * SECSIZ];
	char _flags;
};

#define FILE struct _buf	/* Poor man's "typedef" */

#define _READ 1
#define _WRITE 2


/*
 * Storage allocation data, used by  "alloc" and "free"
 */

struct _header  {
	struct _header *_ptr;
	unsigned _size;
 };

struct _header _base;		/* declare this external data to  */
struct _header *_allocp;	/* be used by alloc() and free()  */
   v  */

#define BASE 0		/* Base of CP/M system RAM (0 or 0x4200)  */
#define NULL 0
#define EOF -1		/* Physical EOF returned by low level I/O functions */
#define ERROR -1	/* General "on error" return value */
#define OK 0		/* General purpose "no error" return value */
#define JBUFSIZE 6	/* Length of setjump/longjump buffer	*/
#define CPMEOF 0x1a	/* CP/M End-of-text-file marker (sometimes!)  */
#define SECSIZ 128	/* Sector size for CP/M read/write calls */
#define MAXLINE 150	/* Longest line of input        expected from the console */
#define TRUE 1		/* logical true constant */
#define FALSE 0		/* logical false constant */

/*
 *	The NSECTS symbol controls the compilation of the buffered
 *	I/O routines within STDLIB2.C, allowing each user to set the
 *	buffer size most convenient for his system, while keeping
 *	the numbers totally invisible to the C source programs using
 *	buffered I/O (via the BUFSIZ defined symbol.) For larger
 *	NSECTS, the disk I/O is faster...but more ram is taken up.
 *	T      ` o change the buffer size allocation, follow these steps:
 *
 *	1) Change NSECTS below
 *	2) Re-compile STDLIB1.C and STDLIB2.C
 *	3) Use CLIB to combine STDLIB1.CRL and STDLIB2.CRL to make
 *	   a new DEFF.CRL. This isn't as touch as it sounds.
 *
 *	Make sure you declare all your I/O buffers with the a
 *	statement such as:
 *
 *		char buf_name[BUFSIZ];
 */

#define NSECTS 8	/* Number of sectors to buffer up in ram */

#define BUFSIZ (NSECTS * SECSIZ + 7)	/* Don't touch this */

struct _bu      arg is a filename prefixed by "nn/",
	where "nn" is a user number:
*/

int hasuno(str)
char *str;
{
	char c;
	int sum;

	sum = 0;

	if (!isdigit(*str)) return FALSE;

	while (isdigit(c = *str++))
		sum = sum * 10 + c - '0';
	return (c == ' ,/') ? (sum >= 0 && sum < 32) : FALSE;
}

* ROR) {
		printf("\nCan't close the output file.\n");;
		exit();
	}
	fabort(fd1);
   }
}

/*
	Return true if the string   /*
	NOBOOT.C	written by Leor Zolman
	v1.50 ONLY!		3/82, 9/82

	Given the name of a C-generated COM file linked with the standard
	distribution version of the v1.50 C.CCC run-time package using
	either the standard CLINK or optional "L2" linker), this program
	changes that COM file so that it does not perform a warm-boot after
	its execution is complete, but instead preserves the CCP (Console
	Command Processor) that is in memory when execution begins and
	returns to the CCP directly following exec     ution.

	The versions of NOBOOT.C distributed with BDS C v1.46 will NOT
	work with files produced by v1.50.

	The CLINK option "-N" may be used instead of this program to the
	same effect. NOBOOT is basically intended for use with COM files
	produced by the L2 linker, as opposed to by CLINK.
*/

#include <bdscio.h>

#define JMP	0xC3	/* 8080 JMP instruction				*/
#define SNOBSP 0x0138	/* Location of Set NoBoot SP routine in C.CCC	*/
#define NOBRET 0x013B	/* Locatio of NoBoot RETurn routine in C    ) .CCC	*/

main(argc,argv)
char **argv;
{
	int fd;
	int i;
	char c;
	char nambuf[30];
	char workbuf[0x500];

	if (argc != 2) {
		puts("Usage: noboot <C-generated COM file name>\n");
		exit();
	}

	for (i=0; (c = argv[1][i]) && c != '.'; i++)
		 nambuf[i] = c;
	nambuf[i] = '\0';
	strcat(nambuf,".COM");

	if ((fd = open(nambuf,2)) == ERROR) {
		puts("Can't open: ");
		puts(nambuf);
		exit();
	}

	i = read(fd,workbuf+0x100,8);
	if (i != 8) puts("Couldn't read in at least 8 sectors...\    F n");

	workbuf[0x100] = JMP;
	workbuf[0x101] = (SNOBSP & 0xFF);	/* Low byte of SNOBSP	*/
	workbuf[0x102] = (SNOBSP >> 8);		/*  Hi byte of SNOBSP	*/

	workbuf[0x109] = JMP;
	workbuf[0x10A] = (NOBRET & 0xFF);	/* Low byte of NOBRET	*/
	workbuf[0x10B]  = (NOBRET >> 8);		/*  Hi byte of NOBRET	*/

	seek(fd,0,0);
	if (write(fd,workbuf+0x100,8) != 8) {
		puts("Write error.\n");
		exit();
	}

	if (close(fd) == ERROR) {
		puts("Close error\n");
	}
}
     /*
 * This header file contains hardware-dependent definitions for C programs.
 * If the symbol "DIRECT_CURSOR" has been defined at the point this file
 * is included into the program, then the "gotoxy" function
 * and other advanced video-terminal functions will be compiled. THIS FILE
 * MUST BE CUSTOMIZED BY EACH INDIVIDUAL USER AT THE TIME BDS C IS BROUGHT UP.
 */

/*
 * Some console (video) terminal characteristics:
 */

#define TWIDTH	80	/* # of columns	*/
#define TLENGTH	24	/* # of lines	  ] , byte))	/* write to control port  */

#define	MOD_TBE		(inp(0x08) & 0x80)	/* Modem */
#define MOD_RDA		(inp(0x08) & 0x40)
#define	MOD_TDATA(byte)	(outp(0x09, byte))
#define	MOD_RDATA	(inp(0x09))
#define MOD_CTRL(byte)	(outp(0x08, byte))

#else				/* this section for memory-mappped I/O only */
#define CON_TBE		(peek(FOO) & BAR)	/* Console */
#define CON_RDA		(peek(FOO) & BAR)
#define CON_TDATA(byte)	(poke(FOO, byte))
#define CON_RDATA	(peek(FOO))
#define CON_CTRL(byte)	(poke(FOO, byte))

#def   */
#define CLEARS	"\033E"	/* String to clear screen on console	*/
#define INTOREV	"\033p"	/* String to switch console into reverse video	*/
#define OUTAREV "\033q"	/* String to switch console OUT of reverse video  */
#define CURSOROFF "\033x5"	/* String to turn cursor off	*/
#define CURSORON "\033y5"	/* String to turn cursor on	*/
#define ESC	'\033'	/* Standard ASCII 'escape' character	*/


#ifdef DIRECT_CURSOR		/* if user has enabled advanced	*/
				/* video-terminal functions: 	*/
gotoxy(x,y)
   ine	MOD_TBE		(peek(FOO) & BAR)	/* Modem */
#define	MOD_RDA		(peek(FOO) & BAR)
#define	MOD_TDATA(byte)	(poke(FOO, byte))
#define	MOD_RDATA	(peek(FOO))
#define MOD_CTRL(byte)	(poke(FOO, byte))
#endif
 /* this section for memory-mappped I/O only */
#define CON_TBE		(peek(FOO) & BAR)	/* Console */
#define CON_RDA		(peek(FOO) & BAR)
#define CON_TDATA(byte)	(poke(FOO, byte))
#define CON_RDATA	(peek(FOO))
#define CON_CTRL(byte)	(poke(FOO, byte))

#de f  5 {
	bios(4,ESC);
	bios(4,'Y');
	bios(4, x + ' ');
	bios(4, y + ' ');
}

clear()
{
	bios(4,ESC);
	bios(4,'E');
}

#endif


/*
	The following definitions provide a portable low-level interface
	for direct I/O to the  console and modem devices. The values
	used here are only for example; be certain to go in and customize
	them for your system! Note that only one of the two sections
	(I/O port vs. memory mapped) will be needed for your system,
	so feel free to edit the unused section out of      l  the file and remove
	the conditional compilation lines around the section you end up
	using.
*/

#define IO_PORTS	1	/* change to 0 if I/O is memory-mapped */

#if IO_PORTS			/* this section for status-driven I/O only */
#define CON_TBE		(inp(0x00) & 0x80)	/* Console: output ready? */
#define CON_RDA		(inp(0x00) & 0x40)	/*	    input ready?  */
#define CON_TDATA(byte)	(outp(0x01, byte))	/* 	    transmit data */
#define CON_RDATA	(inp(0x01))		/*	    read data	  */
#define CON_CTRL(byte)	(outp(0x00     % /*
	DI.C

	Find simple differences between two binary or text files.
	Written by Leor Zolman. This command is useful for quick comparisons,
	as to determine whether two files are identical, or else to find the
	first area of divergence.

	The addresses printed for binary files assumes they are being examined
	using DDT or SID (i.e., offset by 100h from the start of the file.)

	Usage: 
		di <file1> <file2> [-a]
	  or	di <file1> { <user#/> or <d:> or <user#/d:> } [-a]

	The second form allows   count);
				if (ascii) printf(" [line %d]",lineno);
				printf(", but %s goes on...\n",nam2);
				exit();
			}
		} else {			     /* 1st file didn't end  */
			j = getc(buf2);
			if (j == EOF || (ascii && j == CPMEOF)) { /* did 2nd?*/
				printf("%s ends at %04x",nam2,count);
				if (ascii) printf(" [line %d]",lineno);
				printf(", but %s goes on...\n",argv[1]);
				exit();
			} else if (i != j) {
				printf("Mismatch at location %04x",count);
				if (ascii) printf(" [line %d]",lineno);
				p [ for omission of the second filename if is to be
	identical to the first.

	(use -a for ASCII files; else binary assumed)

	Compile by:
		cc di.c -e2000 -o
		clink di -n
*/

#include <bdscio.h>

int i, j;
char ascii;
unsigned count;
unsigned lineno;
char buf1[BUFSIZ], buf2[BUFSIZ];
char nam2[20];
char perfect;

main(argc,argv)
char **argv;
{
	if (argc < 3) {
	   printf("Usage:\tdi file1 file2 [-a]\n");
	   printf("or:\tdi file1 { <user#/> or <d:> or <user#/d:> } [-a]\n");
	   exit()  7utchar('\n');
				perfect = FALSE;
			}
		}
	}
}
$ 	     /* 1st file didn't end  */
			j = getc(buf2);
			if (j == EOF || (ascii && j == CPMEOF)) { /* did 2nd?*/
				printf("%s ends at %04x",nam2,count);
				if (ascii) printf(" [line %d]",lineno);
				printf(", but %s goes on...\n",argv[1]);
				ex it();
			} else if (i != j) {
				printf("Mismatch at location %04x",count);
				if (ascii) printf(" [line %d]",lineno);
				p P ;
	}

	if (fopen(argv[1],buf1) == ERROR) {
		printf("Can't open %s\n",argv[1]);
		exit();
	}

	strcpy(nam2,argv[2]);		/* construct second filename */
	if ((j = nam2[strlen(nam2)-1]) == ':' || j == '/')
	{
		for (i = strlen(argv[1])-1; i >= 0; i--)
			if (argv[i][i] == '/' || argv[1][i] == ':')
				break;
		strcat(nam2, &argv[1][i+1]);
	}


	if (fopen(nam2,buf2) == ERROR) {
		printf("Can't open %s\n",nam2);
		exit();
	}

	printf("Comparing %s to %s:\n",argv[1],nam2);

	lineno = 1;
	    k ascii = 0;
	perfect = TRUE;
	if (argc > 3 && argv[3][1] == 'A') ascii++;

	for (count = 0x100 ; ; count++) {
		if (kbhit())		/* flow control */
			getchar();

		i = getc(buf1);
		if (i == '\n') lineno++;
		if (i == EOF || (ascii && i == CPMEOF)) {
			j = getc(buf2);			 /* first file ended */
			if (j == EOF || (ascii && j == CPMEOF)) { /* did 2nd?*/
				if (perfect)
					printf("Perfect match!\n");   /* yes */
				exit();
			 } else {				       /* no */
				printf("%s ends at %04x",argv[1],       /*
	STDLIB1.C -- for BDS C v1.50 -- 12/29/82
	Copyright (c) 1982 by Leor Zolman

	The files STDLIB1.C and STDLIB2.C contain the source for
	all functions in the DEFF.CRL library file.

	Functions appearing in this source file:

	fopen		getc		ungetc		getw
	fcreat		fappend		putc		putw
	fflush		fclose
	atoi
	strcat		strcmp		strcpy		strlen
	isalpha		isupper		islower		isdigit
	isspace		toupper		tolower
	qsort *
	initw		initb		getval
	alloc		free
	abs		max		min

	* - The symbolic constant "MA    SECSIZ);
	iobuf -> _flags = _WRITE;
	return iobuf -> _fd;
}


/*
	Fappend: Open a text file for buffered output, appending onto the end:
*/

int fappend(name, iobuf)
char *name;
FILE *iobuf;
{
	int i, fd;
	if ((fd = open(name,2)) == ERROR)
		return fcreat(name, iobuf);
	if (!(i = cfsize(fd)))
	{
		close(fd);
		return fcreat(name, iobuf);
	}
	if (seek(fd, -1, 2) == ERROR || read(fd, iobuf->_buff, 1) < 1)
	{
		close(fd);
		return ERROR;
	}
	seek(fd, -1, 2);
	for (i = 0; i < SECSIZ   X_QSORT_WIDTH" must be enlarged when
	    sorting objects of greater width than in the definition below.
*/


#include <bdscio.h>

#define 	MAX_QSORT_WIDTH	513		/* Largest object "qsort"
						   can sort	          */

/*
	Buffered I/O for C:
*/

#define STD_IN	0
#define STD_OUT 1
#define STD_ERR 4

#define DEV_LST 2
#define DEV_RDR 3
#define DEV_PUN 3


int fopen(filename,iobuf)
FILE *iobuf;
char *filename;
{
	if ((iobuf -> _fd = open(filename,0))<0) return ERROR;
	iobuf -> _nle   ; i++)
		if (iobuf->_buff[i] == CPMEOF)
			break;
	iobuf -> _fd = fd;
	iobuf -> _nextp = iobuf -> _buff + i;
	iobuf -> _nleft = (NSECTS * SECSIZ) - i;
	iobuf -> _flags = _WRITE;
	return fd;
}


int putc(c,iobuf)
char c;
FILE *iobuf;
{
	if (iobuf <= 4)			/* handle special device codes: */
	 {
		switch (iobuf)
		 {
			case STD_OUT: return putchar(c);  /* std output */
			case DEV_LST: return (bdos(5,c)); /* list dev.  */
			case DEV_PUN: return (bdos(4,c)); /* to punch   */
			case STD_E  I ft = 0;
	iobuf -> _flags = _READ;
	return iobuf -> _fd;
}


int getc(iobuf)
FILE *iobuf;
{
	int nsecs;
	if (iobuf == STD_IN) return getchar();
	if (iobuf == DEV_RDR) return bdos(3);
	if (!iobuf->_nleft--)		/* if buffer empty, fill it up first */
	 {
		if ((nsecs = read(iobuf -> _fd, iobuf -> _buff, NSECTS)) <= 0)
			return iobuf -> _nleft++;
		iobuf -> _nleft = nsecs * SECSIZ - 1;
		iobuf -> _nextp = iobuf -> _buff;
	 }
	return *iobuf->_nextp++;
}

int ungetc(c, iobuf)
FILE *iobuf;
c  Z RR: if (c == '\n')	  /* to std err */
						bdos(2,'\r');
				      return bdos(2,c);
		 }	
	 }
	if (!iobuf -> _nleft--)		/*   if buffer full, flush it 	*/
	 {
		if ((write(iobuf -> _fd, iobuf -> _buff, NSECTS)) != NSECTS)
			return ERROR;
		iobuf -> _nleft = (NSECTS * SECSIZ - 1);
		iobuf -> _nextp = iobuf -> _buff;
	 }
	return *iobuf -> _nextp++ = c;
}


int putw(w,iobuf)
unsigned w;
FILE *iobuf;
{
	if ((putc(w%256,iobuf) >=0 ) && (putc(w / 256,iobuf) >= 0))
				return w;
	return ERR   har c;
{
	if (iobuf == STD_IN) return ungetch(c);
	if ((iobuf < 7) || iobuf -> _nleft == (NSECTS * SECSIZ)) return ERROR;
	*--iobuf -> _nextp = c;
	iobuf -> _nleft++;
	return OK;
}
	

int getw(iobuf)
FILE *iobuf;
{
	int a,b;	
	if (((a=getc(iobuf)) >= 0) && ((b= getc(iobuf)) >=0))
			return 256*b+a;
	return ERROR;
}


int fcreat(name,iobuf)
char *name;
FILE *iobuf;
{
	if ((iobuf -> _fd = creat(name)) < 0 ) return ERROR;
	iobuf -> _nextp = iobuf -> _buff;
	iobuf -> _nleft = (NSECTS *   OR;
}


int fflush(iobuf)
FILE *iobuf;
{
	int i;
	if (iobuf < 4) return OK;
	if (!(iobuf->_flags & _WRITE))
		return OK;
	if (iobuf -> _nleft == (NSECTS * SECSIZ)) return OK;

	i = NSECTS - iobuf->_nleft / SECSIZ;
	if (write(iobuf -> _fd, iobuf -> _buff, i) != i)
			return ERROR;
	i = (i-1) * SECSIZ;

	if (iobuf -> _nleft) {
		movmem(iobuf->_buff + i, iobuf->_buff, SECSIZ);
		iobuf -> _nleft += i;
		iobuf -> _nextp -= i;
		return seek(iobuf->_fd, -1, 1);
	 }

	iobuf -> _nleft = (NSE V ;
; FP and LONG functions for floating point and long packages
;

	INCLUDE "bds.lib"


	FUNCTION	fp

	CALL	arghak
	PUSH	B		; save BC
 	LXI	H,COMMON$EXIT	 

	PUSH	H		; save the common exit addr in the stack
	LDA	arg1		;Get code ptr
	RAL			;Multiply code by 2
	MOV	E,A
	MVI	D,0		;Move result to DE
	LXI	H,JMPTAB	;Get JMPTAB addr
	DAD	D		;Add offset to it
	XCHG			;Store result in DE
	LDAX	D
	MOV	L,A
	INX	D
	LDAX	D
	MOV	H,A		;Move table addr to HL
	PCHL			;Jump to selected routine
JMPTA  
	LXI	H,FPACC-1
	MVI	C,5
	CALL	NEGATE		;2's complement FPACC
	RET			;Exit FPNORM
FPADD:
	LXI	H,FPACC
	MVI	C,4
	CALL	ZERO$TEST		;if FPACC not = zero
	JNZ	TEST$FPOP		;.. go test FPOP for zero
	LXI	H,FPACC
	LXI	D,FPOP
	MVI	C,5
	CALL	MOVE		;Move FPOP to  FPACC
	RET			;Exit FPADD
TEST$FPOP:
	LXI	H,FPOP
	MVI	C,4
	CALL	ZERO$TEST	;if FPOP = 0
	RZ			;.. exit FPADD
	LDA	FPACCX
	LXI	H,FPOPX
	SUB	M		;if exponents are equal
	JZ	ADD$SETUP	;.. go to add setup
	JP	RANGE$TEST	;if diff of exp >=0,goto  B:
	DW	XNORM
	DW	XADD
	DW	XSUB
	DW	XMULT
	DW	XDIV
	DW	XFTOA

COMMON$EXIT:
	POP	B		; restore BC
	RET			; return to BDS C

XNORM:
	CALL	LD$OP1
	CALL	FPNORM
EXIT0:
	CALL	ST$ACC
	RET

XADD:
	CALL	LD$OP2
	CALL	FPADD
	JMP	EXIT0
XSUB:
	CALL	LD$OP2
	CALL	FPSUB
	JMP	EXIT0
XMULT:
	CALL	LD$OP2
	CALL	FPMULT
	JMP	EXIT0

XDIV:
	CALL	LD$OP2
	CALL	FPDIV
	JMP	EXIT0

XFTOA:
	CALL	LD$OP1
	CALL	FTOA
	RET

LD$OP1:
	LHLD	arg3
	XCHG
	LXI	H,FPACC-1
	MVI	M,0
	INX	H
	MVI	C,5
	CALL	MOV   range test
	CMA
	INR	A		;ABS of difference

RANGE$TEST:
	CPI	32		;if diff < 32
	JM	ALGN$OPRNDS	;.. we can go align the operands
	LXI	H,FPACCX
	LDA	FPOPX
	SUB	M		;if exp of FPACC > exp of FPOP
	RM			;.. exit FPADD
	LXI	D,FPOP
	LXI	H,FPACC
	MVI	C,5
	CALL	MOVE		;move FPOP to FPACC
	RET			;Exit FPADD

ALGN$OPRNDS:
	LDA	FPACCX
	LXI	H,FPOPX
	SUB	M		;subt exponents
	MOV	B,A		;save difference of exponents
	JM	SHFT$FPACC	;if diff neg, go shift FPACC

ALGN$FPOP:
	LXI	H,FPOPX
	CALL	SHFT$LOOP 5 E
	RET

LD$OP2:
	CALL	LD$OP1
	LHLD	arg4
	XCHG
	LXI	H,FPOP-1
	MVI	M,0
	INX	H
	MVI	C,5
	CALL	MOVE
	RET

ST$ACC:
	LHLD	arg2
	LXI	D,FPACC
	MVI	C,5
	CALL	MOVE
	RET

FPNORM:
	LDA	FPACC+3		;Get MS byte of FPACC
	STA	SIGN		;Save SIGN byte of FPACC
	ANA	A		;If number is positive
	JP	NZERO$TEST	;.. go test for zero
	LXI	H,FPACC-1	;Load addr of FPACC (+ xtra byte)
	MVI	C,5		;Load precision register
	CALL	NEGATE		;Negate FPACC

NZERO$TEST:
	LXI	H,FPACC-1
	MVI	C,5
	CALL	ZERO$TEST	;If FPA  	;shift FPOP & increment exponent
	DCR	B		;Decrement diff register
	JNZ	ALGN$FPOP	;loop until exponents are equal
	JMP	ADD$SETUP	;go to add setup

SHFT$FPACC:
	LXI	H,FPACCX
	CALL	SHFT$LOOP	;shift FPACC & increment exponent
	INR	B		;increment difference register
	JNZ	SHFT$FPACC	;loop until exponents are equal

ADD$SETUP:
	XRA	A
	STA	FPACC-1
	STA	FPOP-1
	LXI	H,FPACCX
	CALL	SHFT$LOOP	;shift FPACC right
	LXI	H,FPOPX
	CALL	SHFT$LOOP	;shift FPOP right
	LXI	H,FPACC-1
	LXI	D,FPOP-1
	MVI	C,5
	C  CC not zero
	JNZ	NOTZERO		;.. go normalize
	STA	FPACCX		;make sure exponent is zero
	RET

NOTZERO:
	LXI	H,FPACC-1
	MVI	C,5
	CALL	SHIFTL		;shift FPACC left
	LXI	H,FPACCX
	DCR	M		;subtract 1 from FPACC exponent
	LDA	FPACC+3		;get MS byte of FPACC
	ANA	A		;if high order bit not no
	JP	NOTZERO		;.. go do again

;compensate for last shift

	LXI	H,FPACCX
	INR	M
	DCX	H
	MVI	C,5
	CALL	SHIFTR
	LDA	SIGN		;fetch original sign
	RAL			;shift sign bit into carry
	RNC			;exit if orig # was positive * ALL	ADDER		;add FPOP to FPACC
	CALL	FPNORM		;normalize result
	RET			;exit FPADD

SHFT$LOOP:
	INR	M		;increment exponent
	DCX	H		;decrement ptr
	MVI	C,4
	MOV	A,M		;get MS byte
	ANA	A		;if negative number
	JM	SHFT$MINUS	;.. goto negative shift
	CALL	SHIFTR		;shift mantissa
	RET

SHFT$MINUS:
	STC			;set carry
	CALL	SHFTR		;shift mantissa progatating sign
	RET			;exit

FPSUB:
	LXI	H,FPACC
	MVI	C,4
	CALL	NEGATE
	JMP	FPADD

FPMULT:
	CALL	SIGNJOB		;process the signs
	LXI	H,WORK
	MVI	C,    CTS * SECSIZ);
	iobuf -> _nextp = iobuf -> _buff;
	return OK;
}

int fclose(iobuf)
FILE *iobuf;
{
	if (iobuf < 4) return OK;
	fflush(iobuf);
	return close(iobuf -> _fd);
}


/*
	Some string functions
*/

int atoi(n)
char *n;
{
	int val; 
	char c;
	int sign;
	val=0;
	sign=1;
	while ((c = *n) == '\t' || c== ' ') ++n;
	if (c== '-') {sign = -1; n++;}
	while (  isdigit(c = *n++)) val = val * 10 + c - '0';
	return sign*val;
}


char *strcat(s1,s2)
char *s1, *s2;
{
	char *temp;   ~ 


/*
 	Initialization functions
*/


initw(var,string)
int *var;
char *string;
{
	int n;
	while ((n = getval(&string)) != -32760) *var++ = n;
}

initb(var,string)
char *var, *string;
{
	int n;
	while ((n = getval(&string)) != -32760) *var++ = n;
}

int getval(strptr)
char **strptr;
{
	int n;
	if (!**strptr) return -32760;
	n = atoi(*strptr);
	while (**strptr && *(*strptr)++ != ',');
	return n;
}


/*
	Storage allocation functions:
*/

char *alloc(nbytes)
unsigned nbyte   temp=s1;
	while(*s1) s1++;
	do *s1++ = *s2; while (*s2++);
	return temp;
}


int strcmp(s,t)
char s[], t[];
{
	int i;
	i = 0;
	while (s[i] == t[i])
		if (s[i++] == '\0')
			return 0;
	return s[i] - t[i];
}


char *strcpy(s1,s2)
char *s1, *s2;
{
	char *temp; temp=s1;
	while (*s1++ = *s2++);
	return temp;
}


int strlen(s)
char *s;
{
	int len;
	len=0;
	while (*s++) len++;
	return len;
}


/*
	Some character diddling functions
*/

int isalpha(c)
char c;
{
	return is   s;
{
	struct _header *p, *q, *cp;
	int nunits; 
	nunits = 1 + (nbytes + (sizeof (_base) - 1)) / sizeof (_base);
	if ((q = _allocp) == NULL) {
		_base._ptr = _allocp = q = &_base;
		_base._size = 0;
	 }
	for (p = q -> _ptr; ; q = p, p = p -> _ptr) {
		if (p -> _size >= nunits) {
			_allocp = q;
			if (p -> _size == nunits)
				_allocp->_ptr = p->_ptr;
			else {
				q = _allocp->_ptr = p + nunits;
				q->_ptr = p->_ptr;
				q->_size = p->_size - nunits;
				p -> _size = nunits;
			 }
			re   upper(c) || islower(c);
}


int isupper(c)
char c;
{
	return c>='A' && c<='Z';
}


int islower(c)
char c;
{
	return c>='a' && c<='z';
}


int isdigit(c)
char c;
{
	return c>='0' && c<='9';
}


int isspace(c)
char c;
{
	return c==' ' || c=='\t' || c=='\n';
}


char toupper(c)
char c;
{
	return islower(c) ? c-32 : c;
}


char tolower(c)
char c;
{
	return isupper(c) ? c+32 : c;
}



qsort(base, nel, width, compar)
char *base; int (*compar)();
unsigned width,nel;   turn p + 1;
		 }
		if (p == _allocp) {
			if ((cp = sbrk(nunits *	 sizeof (_base))) == ERROR)
				return NULL;
			cp -> _size = nunits; 
			free(cp+1);	/* remember: pointer arithmetic! */
			p = _allocp;
		}
	 }
}


free(ap)
struct _header *ap;
{
	struct _header *p, *q;

	p = ap - 1;	/* No need for the cast when "ap" is a struct ptr */

	for (q = _allocp; !(p > q && p < q -> _ptr); q = q -> _ptr)
		if (q >= q -> _ptr && (p > q || p < q -> _ptr))
			break;
	if (p + p -> _size == q -> _   
{	int i, j;
	unsigned gap, ngap, t1;
	int jd, t2;

	t1 = nel * width;
	for (ngap = nel / 2; ngap > 0; ngap /= 2) {
	   gap = ngap * width;
	   t2 = gap + width;
	   jd = base + gap;
	   for (i = t2; i <= t1; i += width)
	      for (j =  i - t2; j >= 0; j -= gap) {
		if ((*compar)(base+j, jd+j) <=0) break;
			 _swp(width, base+j, jd+j);
	      }
	}
}

_swp(w,a,b)
char *a,*b;
unsigned w;
{
	char swapbuf[MAX_QSORT_WIDTH];
	movmem(a,swapbuf,w);
	movmem(b,a,w);
	movmem(swapbuf,b,w);
}   ptr) {
		p -> _size += q -> _ptr -> _size;
		p -> _ptr = q -> _ptr -> _ptr;
	 }
	else p -> _ptr = q -> _ptr;

	if (q + q -> _size == p) {
		q -> _size += p -> _size;
		q -> _ptr = p -> _ptr;
	 }
	else q -> _ptr = p;

	_allocp = q;
}


/*
 	Now some really hairy functions to wrap things up:
*/

int abs(n)
{
	return (n<0) ? -n : n;
}

int max(a,b)
{
	return (a > b) ? a : b;
}

int min(a,b)
{
	return (a <= b) ? a : b;
}

x  8
	CALL	ZERO$MEMORY	;WORK := 0 (partial product)
	LXI	H,FPACCX
	LDA	FPOPX
	ADD	M
	INR	A		;compensate for algolrithm
	MOV	M,A		;add FPOP exp to FPACC exponent
	LXI	H,FPACC-4
	MVI	C,4
	CALL	ZERO$MEMORY	;clear multiplicand extra bytes
	LXI	H,BITS
	MVI	M,31

MULT$LOOP:
	LXI	H,FPOP+3
	MVI	C,4
	CALL	SHIFTR		;shift multiplier right
	CC	ADD$MULTIPLICAND ;add multiplicand if carry
	LXI	H,WORK+7
	MVI	C,8
	CALL	SHIFTR		;shift partial product right
	LXI	H,BITS
	DCR	M		;decrement BITS counter
	JNZ G 
	LXI	H,FPACCX
	INR	M
DVEXIT:
	LXI	H,FPACC
	LXI	D,WORK+4
	MVI	C,4
	JMP	EXMLDV

SETSUB:
	LXI	D,FPACC
	LXI	H,WORK2
	MVI	C,4
	CALL	MOVE		;move dividend to work2
	LXI	H,WORK2
	LXI	D,FPOP
	MVI	C,4
	CALL	SUBBER		;subtract divisor from work2
	LDA	WORK2+3
	ANA	A
	RET

FTOA:
	LHLD	arg2
	SHLD	ASCII$PTR
	MVI	M,' '
	LDA	FPACC+3
	ANA	A
	JP	BYSIGN
	MVI	M,'-'
	LXI	H,FPACC
	MVI	C,4
	CALL	NEGATE
BYSIGN:
	LHLD	ASCII$PTR
	INX	H
	MVI	M,'0'
	INX	H
	MVI	M,'.'
	INX	H
	SHLD	ASCII$PTR
	XRA	A / 	MULT$LOOP	;if not zero, do again
	LXI	H,WORK+7
	MVI	C,8
	CALL	SHIFTR		;shift once more for rounding
	LXI	H,WORK+3
	MOV	A,M
	RAL			;fetch 32th bit
	ANA	A		;if it is a 1
	CM	ROUND$IT	;.. round the result
	LXI	D,WORK+3
	LXI	H,FPACC-1
	MVI	C,5
EXMLDV:
	CALL	MOVE
	LDA	SIGN		;fetch SIGN and save it on the stack
	PUSH	PSW
	CALL	FPNORM
	POP	PSW
	ANA	A
	RP
	LXI	H,FPACC
	MVI	C,4
	CALL	NEGATE
	RET

ADD$MULTIPLICAND:
	LXI	H,WORK
	LXI	D,FPACC-4
	MVI	C,8
	CALL	ADDER
	RET
ROUND$IT:
	MVI	A, = 
	STA	EXP
	LXI	H,FPACC
	MVI	C,4
	CALL	ZERO$TEST
	JNZ	SU$FTOA
	MVI	C,7
	LHLD	ASCII$PTR
ZERO$LOOP:
	MVI	M,'0'
	INX	H
	DCR	C
	JNZ	ZERO$LOOP
	SHLD	ASCII$PTR
	JMP	EXPOUT
SU$FTOA:
	LXI	H,FPACCX
	DCR	M
DECEXT:
	JP	DECEXD
	MVI	A,4
	ADD	M
	JP	DECOUT
	CALL	FPX10
DECREP:
	LXI	H,FPACCX
	MOV	A,M
	ANA	A
	JMP	DECEXT

DECEXD:
	CALL	FPD10
	JMP	DECREP	

DECOUT:
	LXI	H,FPACC
	LXI	D,ADJ
	MVI	C,4
	CALL	ADDER
	LXI	H,OUTAREA
	LXI	D,FPACC
	MVI	C,4
	CALL	MOVE
	LXI	H,OUTAREA+4
	MVI	M,0
	L  40H
	ADD	M
	MVI	C,4
RND$LOOP:
	MOV	M,A
	INX	H
	MVI	A,0
	ADC	M
	DCR	C
	JNZ	RND$LOOP
	MOV	M,A
	RET
FPDIV:
	LXI	H,FPOP
	MVI	C,4
	CALL	ZERO$TEST
	JNZ	DIV$SIGN
	LXI	H,FPACC
	MVI	C,5
	CALL	ZERO$MEMORY
	RET

DIV$SIGN:
	CALL	SIGNJOB
	LXI	H,WORK
	MVI	C,12
	CALL	ZERO$MEMORY
	MVI	A,31
	STA	BITS
	LXI	H,FPACCX
	LDA	FPOPX
	MOV	B,A
	MOV	A,M
	SUB	B
	INR	A
	MOV	M,A
DIVIDE:
	CALL	SETSUB		;WORK2 := dividend - divisor
	JM	NOGO		;if minus, go put 0 in quotient
	LXI	H,FPACC
	LXI	D,WORK2
	  XI	H,OUTAREA
	MVI	C,4
	CALL	SHIFTL
	CALL	OUTX10
COMPEN:
	LXI	H,FPACCX
	INR	M
	JZ	OUTDIG
	LXI	H,OUTAREA+4
	MVI	C,5
	CALL	SHIFTR
	JMP	COMPEN
OUTDIG:
	MVI	A,7
	STA	DIGCNT
	LXI	H,OUTAREA+4
	MOV	A,M
	ANA	A
	JZ	ZERODG
OUTDGS:
	LXI	H,OUTAREA+4
	MVI	A,'0'
	ADD	M
	LHLD	ASCII$PTR
	MOV	M,A
	INX	H
	SHLD	ASCII$PTR
DECRDG:
	LXI	H,DIGCNT
	DCR	M
	JZ	EXPOUT
	CALL	OUTX10
	JMP	OUTDGS

ZERODG:
	LXI	H,EXP
	DCR	M
	LXI	H,OUTAREA
	MVI	C,5
	CALL	ZERO$TEST
	JNZ	DECRDG
	XRA	A
	STA	DIGCNT
	JM  MVI	C,4
	CALL	MOVE		;move subt results to dividend
	STC
	JMP	QUOROT

NOGO:
	ANA	A
QUOROT:
	LXI	H,WORK+4
	MVI	C,4
	CALL	SHFTL		;Insert carry flag into quotient
	LXI	H,FPACC
	MVI	C,4
	CALL	SHFTL		;shift dividend left
	LXI	H,BITS
	DCR	M		;decrement BITS counter
	JNZ	DIVIDE		;loop until BITS = zero
	CALL	SETSUB		;1 more time for rounding
	JM	DVEXIT		;if 24th bit = 0, goto exit
	LXI	H,WORK+4
	LXI	D,ONE
	MVI	C,4
	CALL	ADDER
	LXI	H,WORK+7
	MOV	A,M
	ANA	A
	JP	DVEXIT
	MVI	C,4
	CALL	SHIFTR  P	DECRDG

OUTX10:
	XRA	A
	STA	OUTAREA+4
	LXI	H,WORK
	LXI	D,OUTAREA
	MVI	C,5
	CALL	MOVE
	LXI	H,OUTAREA
	MVI	C,5
	CALL	SHIFTL
	LXI	H,OUTAREA
	MVI	C,5
	CALL	SHIFTL
	LXI	D,WORK
	LXI	H,OUTAREA
	MVI	C,5
	CALL	ADDER
	LXI	H,OUTAREA
	MVI	C,5
	CALL	SHIFTL
	RET
EXPOUT:
	LHLD	ASCII$PTR
	MVI	M,'E'
	INX	H
	LDA	EXP
	ANA	A
	JP	EXPOT
	CMA
	INR	A
	STA	EXP
	MVI	M,'-'
	INX	H
	LDA	EXP
EXPOT:
	MVI	C,0
EXPLOOP:
	SUI	10
	JM	TOMUCH
	STA	EXP
	INR	C
	JMP	EXPLOOP

TOMUCH:
	MVI	A,'0'
	ADD	 f   /*
	STDLIB2.C -- for BDS C v1.50 	12/29/82
	Copyright (c) 1982 by Leor Zolman

	This file contains the following library functions sources:

	printf 		lprintf	*	fprintf		sprintf		_spr
	scanf		fscanf		sscanf		_scn
	fgets
	puts		fputs
	swapin

	* --  << Not yet documented in the v1.50 User's Guide. >>

	Note:	The maximum output line length for all formatted output
		functions is now unlimited, due to some new technology,
		although the limit of any one "format conversion" is still
		MAXLINE c    string	*/
	args = fmt;	    /* now fmt points to the first arg value	*/

	while (c = *format++)
	  if (c == '%') {
	    wptr = wbuf;
	    precision = 6;
	    ljflag = pf = zfflag = 0;

	    if (*format == '-') {
		    format++;
		    ljflag++;
	     }


	    if (*format == '0') zfflag++;	/* test for zero-fill */

	    width = (isdigit(*format)) ? _gv2(&format) : 0;

	    if ((c = *format++) == '.') {
		    precision = _gv2(&format);
		    pf++;
		    c = *format++;
	     }

	    swi   haracters.

*/

#include <bdscio.h>

#define DEV_LST 2		/* List device for lprintf */

char toupper(), isdigit();

printf(format)
char *format;
{
	int putchar();
	return _spr(&format, &putchar);	/* use "_spr" to form the output */
}

int lprintf(format)
char *format;
{
	int _fputc();
	return _spr(&format, &_fputc, DEV_LST);
}

sprintf(buffer,format)
char *buffer, *format;
{
	int _sspr();
	_spr(&format, &_sspr, &buffer);	/* call _spr to do all the work */
	*buffer = '\0';
}

_  * tch(toupper(c)) {

		case 'D':  if (*args < 0) {
				*wptr++ = '-';
				*args = -*args;
				width--;
			    }

		case 'U':  base = 10; goto val;

		case 'X':  base = 16; goto val;

		case 'O':  base = 8;  /* note that arbitrary bases can be
				         added easily before this line */

		     val:  width -= _uspr(&wptr,*args++,base);
			   goto pad;

		case 'C':  *wptr++ = *args++;
			   width--;
			   goto pad;

		case 'S':  if (!pf) precision = 200;
			   sptr = *args++;
			   whi   sspr(c,strptr)
char **strptr;
{
	*(*strptr)++ = c;
}

int fprintf(iobuf,format)
char *format;
FILE *iobuf;
{
	int _fputc();
	return _spr(&format, &_fputc, iobuf);
}

int _fputc(c,iobuf)
{
	if (c == '\n')
		if (putc('\r',iobuf) == ERROR)
			return ERROR;
	if (putc(c,iobuf) == ERROR)
		return ERROR;
	return OK;
}	

int scanf(format)
char *format;
{
	char line[MAXLINE];
	gets(line);			/* get a line of input from user */
	return _scn(line,&format);	/* and scan it with "_scn"	 */
}   le (*sptr && precision) {
				*wptr++ = *sptr++;
				precision--;
				width--;
			    }

		     pad:  *wptr = '\0';
		     pad2: wptr = wbuf;
			   if (!ljflag)
				while (width-- > 0)
					if ((*putcf)(zfflag ? '0' : ' ',arg1)
						== ERROR) return ERROR;;

			   while (*wptr)
				if ((*putcf)(*wptr++,arg1) == ERROR) 
					return ERROR;

			   if (ljflag)
				while (width-- > 0)
					if ((*putcf)(' ',arg1) == ERROR)
						return ERROR;
			   break;

		case NULL:
			   return OK;
  P 

int sscanf(line,format)
char *line, *format;
{
	return _scn(line,&format);	/* let _scn do all the work */
}


int fscanf(iobuf,format)
char *format;
FILE *iobuf;
{
	char text[MAXLINE];
	if (!fgets(text,iobuf))
		return ERROR;
	return _scn(text,&format);
}


_spr(fmt,putcf,arg1)
int (*putcf)();
char **fmt;
{
	char _uspr(), c, base, *sptr, *format;
	char wbuf[MAXLINE], *wptr, pf, ljflag, zfflag;
	int width, precision,  *args;

	format = *fmt++;    /* fmt first points to the format   
		default:   if ((*putcf)(c,arg1) == ERROR)
				return ERROR;
	     }
	  }
	  else if ((*putcf)(c,arg1) == ERROR)
			return ERROR;
	return OK;
}

/*
	Internal routine used by "_spr" to perform ascii-
	to-decimal conversion and update an associated pointer:
*/

int _gv2(sptr)
char **sptr;
{
	int n;
	n = 0;
	while (isdigit(**sptr)) n = 10 * n + *(*sptr)++ - '0';
	return n;
}

char _uspr(string, n, base)
char **string;
unsigned n;
{
	char length;
	if (n<base) {
		*(*string)++ = (n < C
	MOV	M,A
	INX	H
	LDA	EXP
	ADI	'0'
	MOV	M,A
	INX	H
	MVI	M,0
	RET
FPX10:
	LXI	H,FPOP
	LXI	D,TEN
	MVI	C,5
	CALL	MOVE
	CALL	FPMULT
	LXI	H,EXP
	DCR	M
	RET

FPD10:
	LXI	H,FPOP
	LXI	D,ONE$TENTH
	MVI	C,5
	CALL	MOVE
	CALL	FPMULT
	LXI	H,EXP
	INR	M
	RET

NEGATE:
	STC			;CARRY forces an add of 1
NEGAT$LOOP:
	MOV	A,M		;fetch byte
	CMA			;complement it
	ACI	0		;make it two's complement
	MOV	M,A		;store the result
	INX	H		;bump ptr
	DCR	C		;decrement precision register
	JNZ	NEGAT$LO E )
uh	equ  u		;high word of u
ul	equ  u+2	;low word of u
mq	equ  u+4	;temporary quad storage used by
			;multiplication and division routines
temp	equ  mq+4	;temporary storage byte used by div'n routine


; long is main routine which dispatches to the various functions
; of the package according to the value of its first argument

long:	push b		;save for benefit of caller
	call ma2toh	;get 1st arg (function code) into HL and A
	mov  d,h
	mov  e,l
	dad  h
	dad  d		;HL now has triple the functi  OP	;if not done, go do it again
	RET			;Return to caller

ZERO$TEST:
	XRA	A		;clear A
	ORA	M		;'OR' A with next byte
	INX	H		;bump ptr
	DCR	C		;decrement precision register
	JNZ	ZERO$TEST+1	;loop until done
	ANA	A		;set flags
	RET

SHIFTL:
	ANA	A		;clear CARRY
SHFTL:
	MOV	A,M		;get next byte
	RAL			;shift it left
	MOV	M,A		;store result
	INX	H		;bump ptr
	DCR	C		;decrement precision register
	JNZ	SHFTL		;loop until done
	RET

SHIFTR:
	ANA	A
SHFTR:
	MOV	A,M
	RAR
	MOV	M,A
	DCX	H
 @ on code
	lxi  d,jtab	;base of jump table
	dad  d
	pchl		;dispatch to appropriate function

jtab:	jmp  lmake	;jump table for quad functions
	jmp  lcomp
	jmp  ladd
	jmp  lsub
	jmp  lmul
	jmp  ldiv
	jmp  lmod


; lmake converts integer (arg3) to a long (arg2)

lmake:	call ma4toh	;get arg3 into HL
	mov  a,h	;look at sign first
	ora  a
	push psw	;save it
	cm   cmh	;take abs value
	xchg		;into (DE)
	lxi  b,0	;zero out high word
	pop  psw
	cm   qneg	;complement if necessary
	jmp  putarg	;c  	DCR	C
	JNZ	SHFTR
	RET

ADDER:
	ANA	A
ADD$LOOP:
	LDAX	D
	ADC	M
	MOV	M,A
	INX	D
	INX	H
	DCR	C
	JNZ	ADD$LOOP
	RET

SUBBER:
	ANA	A
	XCHG
SUB$LOOP:
	LDAX	D
	SBB	M
	STAX	D
	INX	D
	INX	H
	DCR	C
	JNZ	SUB$LOOP
	XCHG
	RET

ZERO$MEMORY:
	MVI	M,0
	INX	H
	DCR	C
	JNZ	ZERO$MEMORY
	RET

MOVE:
	LDAX	D
	MOV	M,A
	INX	D
	INX	H
	DCR	C
	JNZ	MOVE
	RET

SIGNJOB:
	LDA	FPACC+3
	STA	SIGN
	ANA	A
	JP	CKFPOP
	LXI	H,FPACC
	MVI	C,4
	CALL	NEGATE
CKFPOP:
	LXI	H,SIGN
	LDA	FPOP+3
	XRA	 O opy result into arg2 and return

;all other routines copy their arguments into the quad register (BCDE)
;and the temporary quad storage location u  (note that temporary storage
;must be used to keep the routines from clobbering the user's arguments)


;lcomp compares arg2 with arg3, returns -1, 0, 1 for <, =, >, resp

lcomp:  call ma3toh	;get pointer to arg2
	call qld	
	lxi  h,u
	call qst	;arg2 now in u
	call ma4toh	;get pointer to arg3
	call qld	;arg3 now in (BCDE)
	lxi  h,-1	;presume <
	ca  M
	MOV	M,A
	LDA	FPOP+3
	ANA	A
	RP
	LXI	H,FPOP
	MVI	C,4
	CALL	NEGATE
	RET

	DS	4
FPACC:	DS	4
FPACCX:	DS	1
	DS	4
FPOP:	DS	4
FPOPX:	DS	1
SIGN:	DS	1
WORK:	DS	8
WORK2:	DS	4
BITS:	DS	1
ASCII$PTR:	DS	2
EXP:	DS	1
OUTAREA:	DS	5
DIGCNT:	DS	1
ONE$TENTH:	DB	66H,66H,66H,66H,0FDH
TEN:	DB	0,0,0,50H,4
ADJ:	DB	5,0,0,0
ONE:	DB	80H,0,0,0

	ENDFUNC

 	FUNCTION long

; temporary storage is allocated in the
; "args" area of the run-time environment

u	equ  args	;temporary quad storage (4 bytes  ll qsub
	call qtst
	pop  b		;restore bc for caller
	rm
	inx  h
	rz
	inx  h
	ret

; long addition

ladd:	call getargs	;get args into (BCDE) and u
	call qadd	;do the addition
	jmp  putarg	;copy result into arg2 and return

lsub:	call getargs
	call qsub
	jmp  putarg

lmul:	call getargs
	call qmul
	jmp  putarg

ldiv:	call getargs
	call qdiv
	jmp  putarg

lmod:	call getargs
	call qmod
	jmp  putarg

;getargs gets arg3 into u, arg4 into (BCDE)

getargs:
	call ma5toh		;get ptr to a   c  < 10) ? n + '0' : n + 55;
		return 1;
	}
	length = _uspr(string, n/base, base);
	_uspr(string, n%base, base);
	return length + 1;
}


/*
	General formatted input conversion routine:
*/

int _scn(line,fmt)
char *line, **fmt;
{
	char sf, c, base, n, *sptr, *format;
	int sign, val, **args;

	format = *fmt++;	/* fmt first points to the format string */
	args = fmt;		/* now it points to the arg list */

	n = 0;
	while (c = *format++)
	{
	   if (isspace(c)) continue;	/* skip white space    -= 0x30;
	 else return ERROR;
	if (c > b-1) return ERROR;
		else return c;
}

puts(s)
char *s;
{
	while (*s) putchar(*s++);
}


char *fgets(s,iobuf)
char *s;
FILE *iobuf;
{
	int count, c;
	char *cptr;
	count = MAXLINE - 2;
	cptr = s;
	if ( (c = getc(iobuf)) == CPMEOF || c == EOF) return NULL;

	do {
		if ((*cptr++ = c) == '\n') {
		  if (cptr>s+1 && *(cptr-2) == '\r')
			*(--cptr - 1) = '\n';
		  break;
		}
	 } while (count-- && (c=getc(iobuf)) != EOF && c != CPMEOF);

	if (c   O in format string */
	   if (c != '%')		/* if not %, must match text */
	    {
		if (c != _igs(&line)) return n;
		else line++;
	    }
	   else		/* process conversion */
	    {
		sign = 1;
		base = 10;
		sf = 0;
		if ((c = *format++) == '*')
		 {
			sf++;		/* if "*" given, supress assignment */
			c = *format++;
		 }
		switch (toupper(c))
		 {
		   case 'X': base = 16;
			     goto doval;

		   case 'O': base = 8;
			     goto doval;

		   case 'D': if (_igs(&line) == '-') {
				sign   == CPMEOF) ungetc(c,iobuf);	/* push back control-Z */
	*cptr = '\0';
	return s;
}


fputs(s,iobuf)
char *s;
FILE *iobuf;
{
	char c;
	while (c = *s++) {
		if (c == '\n') putc('\r',iobuf);
		if (putc(c,iobuf) == ERROR) return ERROR;
	}
	retur n OK;
}

swapin(name,addr)
char *name;
{
	int fd;
	if (( fd = open(name,0)) == ERROR)
		return ERROR;

	if ((read(fd,addr,512)) < 0) {
		close(fd);
		return ERROR;
	}

	close(fd);
	return OK;
}

   C  = -1;
				line++;
			      }

	   doval:  case 'U': val = 0;
			     if (_bc(_igs(&line),base) == ERROR)
				return n;
			     while ((c = _bc(*line++,base)) != 255)
				val = val * base + c;
			     line--;
			     break;

		   case 'S': _igs(&line);
			     sptr = *args;
			     while (c = *line++)   {
				if (c == *format) {
					format++;
					break;
				 }
				if (!sf) *sptr++ = c;
			      }				
			     if (!sf) {
				n++;
				*sptr = '\0';
				args++;
			      }
			     con      } tinue;

		   case 'C': if (!sf) {
				poke(*args++, *line);
				n++;
			     }
			     line++;
			     continue;

		   default:  return n;
		 }
		if (!sf)
		 {
			**args++ = val * sign;
			n++;
		 }
	    }
	   if (!*line) return n;	/* if end of input string, return */
	}
	return n;
}

char _igs(sptr)
char **sptr;
{
	char c;
	while (isspace(c = **sptr)) ++*sptr;
	return (c);
}

int _bc(c,b)
char c,b;
{
	if (isalpha(c = toupper(c))) c -= 55;
         else  if (isdigit(c))  c     j  rg3 (note use ma5 cause of 
				;return addr on stack)
	call qld		;arg3 now in (BCDE)
	lxi  h,u
	call qst		;now in u
	call ma6toh		;get ptr to arg4
	jmp  qld		;arg4 now in (BCDE)


; putarg copies (BCDE) into result arg (arg2) and cleans up

putarg:	call ma3toh		;get pointer to arg2
	call qst		;copy (BCDE) into it
	pop  b			;restore BC for caller
	ret



; quad subtraction  u - (BCDE) -> (BCDE)

qsub:	call qneg  	;complement (BCDE) and fall thru to add

; quad addition     u + (BCDE) - d r
	cc   qadd			;add u to (BCDE) if lsb=1
	xthl				;get pointer to u
	xra  a				;clear carry
	call qralhl			;double u
	xthl				;get back pointer to mq
	jmp  uqmul1
uqmul2:	pop  h				;restore stack
	ret

; signed division  u / (BCDE) --> (BCDE)

qdiv:	call qtst			;first test for zero divisor
	rz
	call csign			;take care of signs
	push psw			;save quotient sign
	call uqdiv
	call qld			;get quotient in (BCDE)
	jmp  qmul1			;adjust sign of result

;  signed remainder  u mod (BCDE) --> (BCDE)  > (BCDE)

qadd:   push h
	lxi  h,u+3	;tenSHUN
	mov  a,m	;hup
	add  e		;two
	mov  e,a	;three
	dcx  h		;four
	mov  a,m	;hup
	adc  d		;two
	mov  d,a	;three
	dcx  h		;four
	mov  a,m	;hup
	adc  c		;two
	mov  c,a	;three
	dcx  h		;four
	mov  a,m	;hup
	adc  b		;two
	mov  b,a	;three
	pop  h		;four
	ret		;at ease	
	

; two's complement (BCDE)

qneg:	push h
	xra  a
	mov  l,a
	sbb  e
	mov  e,a
	mov  a,l
	sbb  d
	mov  d,a
	mov  a,l
	sbb  c
	mov  c,a
	mov  a,l
	sbb  b
	mov  b,a
	pop  

qmod:	call qtst			;test for zero modulus
	rz
	lda  u				;sign of u is that of result
	ora  a
	push psw			;save flags
	call csign			;get abs val of args
	call uqdiv			;remainder in (BCDE)
	jmp  qmul1


;  unsigned division  u / (BCDE) --> mq, remainder in (BCDE)



uqdiv:	lxi  h,mq			;mq will contain quotient
	call qclrhl			;clear it
	push h				;save it on the stack

	mvi  l,1			;now normalize divisor
uqdiv1:	mov  a,b			;look at most signif non-sign bit
	ani  40h
	jnz   uqdiv2
	call  ,   h
	ret


qneghl: push b
	push d
	call qld
	call qneg
	call qst
	pop  d
	pop  b
	ret

; signed quad multiplication
; u * (BCDE) --> (BCDE)

qmul:	call csign			;take abs values and compute signs
	push psw			;save result sign
	call uqmul			;compute product
qmul1:	pop  psw
	jm   qneg			;complement product if needed
	ret

; csign takes abs vals of u, (BCDE), and computes product of their signs

csign:	mov  a,b			;look at (BCDE) first
	ora  a
	push psw			;save flags
	cm   qneg			;com  qral			;if not 1, shift left
	inr  l
	jmp  uqdiv1
uqdiv2:	mov  a,l
	sta  temp			;save normalization count
	lxi  h,u			
	call qxchg			;want divid in (BCDE), divisor in u
	xthl				;pointer to mq in (HL), u on stack

;main loop

uqdiv3: call trial			;trial subtraction of divisor
	call qralhl			;shift in the carry
	lda  temp			;get the count
	dcr  a
	jz   uqdiv4			;done
	sta  temp			;save count again
	xthl				;divisor in (HL)
	xra  a
	call qrarhl			;shift it right one
	xthl				;quotient in (  plement if needed
	lxi  h,u			;now look at u
	mov  a,m
	ora  a
	jp   csign1
	call qneghl
	pop  psw
	xri  80h			;flip sign
	ret
csign1:	pop psw
	ret

; unsigned quad multiplication 
; u * (BCDE) --> (BCDE)	    (expects ptr. to u in (HL)

uqmul:	lxi  h,u
	push h				;put pointer to u on stack
	lxi  h,mq
	call qst			;(BCDE) -> mq
	lxi  b,0			;init product to 0
	lxi  d,0
uqmul1:	call qtsthl			;test if mq is 0
	jz   uqmul2			;if so, done
	xra  a				;clear carry
	call qrarhl			;shift mq ove  HL)
	jmp  uqdiv3

uqdiv4: inx  sp
	inx  sp				;clean off top of stack
	ret


trial:	call qsub			;subtract divid from divisor
	call qneg			;actually want divisor from divid
	stc				;assume was positive
	rp
	call qadd			;else must restore dividend
	xra  a				;clear carry
	ret


;
; routines to manipulate quads
;
; qld loads the quad pointed to by (HL) into (BCDE)

qld:	push h
	mov  b,m
	inx  h
	mov  c,m
	inx  h
	mov  d,m
	inx  h
	mov  e,m
	pop  h
	ret

; qst is inverse of qld t  ^ 
;
; BDS.LIB		for BDS C v1.50		    September 4,1982
;
; Addresses within C.CCC and the ram area to be used by machine
; language CRL functions. 
;
; If you alter C.CCC by reassembling CCC.ASM, be sure to go through
; this file and make sure all the addresses are equated to the 
; appropriate values resulting from the reassembly. Then the library
; functions will be ready to reassemble.
;

	page 76

CPM:	EQU 1		;true if running under CP/M or MP/M II; else 0
MPM2:	EQU 0		;true only if running    at DE
fgfd:	equ error+12	;set C according to whether file fd is open
fgfcb:	equ error+15	;figure address of internal fcb for file fd
setfcu:	equ error+18	;set up fcb with possible user number prefix
setusr:	equ error+21	;set current user area to high 5 bits of A
rstusr:	equ error+24	;reset user area to value before last setusr call
khack:	equ error+33	;Kirkland interrupt vector initialization
clrex:	equ error+36	;clear external data routine
	endif


eqwel:	equ cccorg+0e5h

smod:	equ cccorg+10fh  % under MP/M II
;
; System addresses:
;

	if not cpm
CCCORG:	EQU WHATEVER	;if not runninng under cp/m, set this to load addr,
RAM:	EQU WHATEVER2	;set this to address of CCC's ram area
BASE:	EQU WHATEVER3	;and this to the base of system memory (`base' is 
			;the re-boot location under cp/m; for non-cp/m oper-
			;ation, it should be set to a safe place to jump to on
			;error or user-abort.
	endif


	if cpm
base:	equ 0000h	;either 0 or 4200h for CP/M systems
fcb:	equ base+5ch	;default file co   
usmod:	equ cccorg+129h
smul:	equ cccorg+13fh
usmul:	equ cccorg+16bh
usdiv:	equ cccorg+189h
sdiv:	equ cccorg+1cbh

cmphd:	equ cccorg+1ddh
cmh:	equ cccorg+1fah
cmd:	equ cccorg+202h

ma1toh:	equ cccorg+20ah	;get 1st stack element into HL and A
ma2toh:	equ cccorg+213h	;    2nd
ma3toh:	equ ma2toh+6	;    3rd
ma4toh:	equ ma2toh+12	;    4th
ma5toh:	equ ma2toh+18	;    5th
ma6toh:	equ ma2toh+24	;    6th
ma7toh:	equ ma2toh+30	;    7th

arghak:	equ ma2toh+36	;copy first 6 or so stack elements to arg  ȭ ntrol block
tbuff:	equ base+80h	;sector buffer
bdos:	equ base+5	;bdos entry point
tpa:	equ base+100h	;transient program area
nfcbs:	equ 9		;max number of open files allowed at one time
errorv:	equ 255		;error value returned by BDOS calls
cccorg:	equ 7 tpa		;where run-time package resides *TESTING*

			;** P
ram:	equ cccorg+52Bh	;THIS WILL PROBABLY CHANGE IF YOU CUSTOMIZE CCC.ASM
			;** 
	endif


cr:	equ    c area

;
; The following addresses will depend on the value of RAM if you
; customize CCC.ASM....be sure they correspond to the assembly
; results of CCC.ASM in such cases. If you remove some of the data
; areas from CCC.ASM (in case they aren't needed), be sure to remove
; from here also.
;

	org ram

	ds 20		;padding bytes...varies with ccc code size

errnum:	ds 1		;error code from file I/O operations

pbase:	ds 2		;DMA video plotting base
ysize:	ds 2		;screen width (# of columns)
xsize  Q 0dh		;ASCII codes:	carriage return
lf:	equ 0ah		;		linefeed
newlin:	equ lf		;		newline
tab:	equ 9		;		tab
bs:	equ 08h		;		backspace
cntrlc:	equ 3		;		control-C

;
; Subroutines in C.CCC (the addresses should be that of the 
; appropriate jump vector entry points):
;

fexitv:	equ cccorg+09h	;where to go to terminate execution
error:	equ cccorg+1dh	;return -1 in HL:
exit:	equ error+3	;close all open files and reboot

	if cpm
close:	equ error+6
setfcb:	equ error+9	;set up fcb at HL from text    :	ds 2		;screen length (# of lines)
psize:	ds 2		;screen size (ysize * xsize)

rseed:	ds 8		;random number seed scratch area

args:	ds 14		;where arghak puts arg values off the stack

iohack:	ds 6		;room for input and output ops for "inp" and "outp"

allocp: ds 2		;storage allocation pointer for sbrk
alocmx:	ds 2		;closest sbrk is allowed to get to the stack (set
			;by rsvstk)

room:	ds 30		;misc. scratch area (for use by BDS...you can have
			;the last ten bytes or so, though, if you really  

qst:	push h
	mov  m,b
	inx  h
	mov  m,c
	inx  h
	mov  m,d
	inx  h
	mov  m,e
	pop  h
	ret



; rotate  (BCDE) right thru carry

qrar:	mov a,b
	rar
	mov b,a
	mov a,c
	rar
	mov c,a
	mov a,d
	rar
	mov d,a
	mov a,e
	rar
	mov e,a
	ret

; same for quad pointed to by (HL)

qrarhl:	push h
	mov  a,m
	rar
	mov  m,a
	inx  h
	mov  a,m
	rar
	mov  m,a
	inx  h
	mov  a,m
	rar
	mov  m,a
	inx  h
	mov  a,m
	rar
	mov  m,a
	pop  h
	ret


; rotate (BCDE) left thru carry

qra     l:	mov a,e
	ral
	mov e,a
	mov a,d
	ral
	mov d,a
	mov a,c
	ral
	mov c,a
	mov a,b
	ral
	mov b,a
	ret

; qralhl does it for quad pointed to by (HL)

qralhl:	inx  h
	inx  h
	inx  h				;get to rightmost byte
	mov  a,m
	ral
	mov  m,a
	dcx  h
	mov  a,m
	ral
	mov  m,a
	dcx  h
	mov  a,m
	ral
	mov  m,a
	dcx  h
	mov  a,m
	ral
	mov  m,a
	ret
	

;qclrhl clears quad pointed to by (HL)

qclrhl:	push h
	xra  a
	mov  m,a
	inx  h
	mov  m,a
	inx  h
	mov  m,a
	inx  h
	mov  m,a
	p     op  h
	ret


; qtst tests sign of (BCDE), setting the usual flags

qtst:	mov  a,b			;look at most signif byte
	ora  a
	rnz
	ora  c				;test for zero
	ora  d
	ora  e
qtst1:	rp
	mvi  a,1
	ora  a  
	ret
	
qtsthl:	mov  a,m
	ora  a
	rnz
	push h
	inx  h
	ora  m
	inx  h
	ora  m
	inx  h
	ora  m
	pop  h
	jmp  qtst1

; swap (BCDE) with thing pointed to by HL

qxchg:	push h
	mov  a,m
	mov  m,b
	mov  b,a
	inx  h
	mov  a,m
	mov  m,c
	mov  c,a
	inx  h
	mov  a,m
	mov  m,d
	mov  d    E O,a
	inx  h
	mov  a,m
	mov  m,e
	mov  e,a
	pop  h
	ret

	ENDFUNCTION

 nz
	ora  c				;test for zero
	ora  d
	ora  e
qtst1:	rp
	mvi  a,1
	ora  a  
	ret
	
qtsthl:	mov  a,m
	ora  a
	rnz
	push h
	inx  h
	ora  m
	inx  h
	ora  m
	inx  h
	ora  m
	pop  h
	jmp  qtst1

; swap (BCDE) with thing pointed to by HL
 
qxchg:	push h
	mov  a,m
	mov  m,b
	mov  b,a
	inx  h
	mov  a,m
	mov  m,c
	mov  c,a
	inx  h
	mov  a,m
	mov  m,d
	mov  d       
			;need them)

uroom:	ds 20		;available for use by user

;
; Nothing beyond this point will ordinarily require any modifications
; by the user.
;

extrns:	equ cccorg+15h	;base of external data area (set by CLINK)
cccsiz:	equ cccorg+17h	;size of C.CCC for use by CLINK only
codend:	equ cccorg+19h	;address of byte following last byte of program code
			; (set by CLINK)
freram:	equ cccorg+1bh	;first free address after external area
			; (set by CLINK)


arg1:	equ args	;these are just convenie  ) ential)
creatc:	equ 22		;make a file
renc:	equ 23		;rename file
sdma:	equ 26		;set dma
gsuser:	equ 32		;get/set user code
readr:	equ 33		;read random sector
writr:	equ 34		;write random sector
cfsizc:	equ 35		;compute file size
srrecc:	equ 36		;se t random record
	endif

3 		;close a file
delc:	equ 19		;delete a file
reads:	equ 20		;read a sector (sequential)
;writs:	equ 21		;write a sector (sequ   nt names for 
arg2:	equ args+2	;the words in the "args" area
arg3:	equ args+4
arg4:	equ args+6
arg5:	equ args+8
arg6:	equ args+10
arg7:	equ args+12

tmp:	equ room	;some scratch data areas used by library
tmp1:	equ room+1	;functions.
tmp2:	equ room+2
tmp2a:	equ room+4
ungetl:	equ room+6
unused:	equ room+7
curusr:	equ room+8
usrnum:	equ room+9

			;Stuff for CIO.CSM package:

mode:	equ room+10	; console I/O mode byte (see bit masks below)
freeze:	equ room+11	; console I/O output frozen
pe       nding: equ room+12	; console I/O input character pending
pendch:	equ room+13	; if pending is true, this holds the character
quitc:	equ room+14	; standard abort character (normally control-C)

echo:	equ 1		;masks for "mode" byte...echo mode
quit:	equ 2		;quit enabled
flow:	equ 4		;X-ON/X-OFF protocol
strip:	equ 8		;strip parity
expand:	equ 16		;expand '\n' into CR-LF on output
swap:	equ 32		;switch CR and LF on input (so CR means newline)

;
; BDOS call codes:
;

	if cpm
conin:	equ 1		;get a        character from console
conout:	equ 2		;write a character to console
lstout:	equ 5		;write a character to list device
dconio:	equ 6		;direct console I/O (only for CP/M 2.0)
pstrng:	equ 9		;print string (terminated by '$')
getlin:	equ 10		;get buffered line from console
cstat:	equ 11		;get console status
select:	equ 14		;select disk
openc:	equ 15		;open a file
closec:	equ 16		;close a file
delc:	equ 19		;delete a file
reads:	equ 20		;read a sector (sequential)
;writs:	equ 21		;write a sector (sequ    \                         B   ;
;	BD Software C Compiler v1.50
;	Standard Library Machine Language Functions (part A)
;	Copyright (c) 1982 by Leor Zolman
;
; This file is in "CSM" format; to convert to CRL format,
; use CASM.SUB in conjunction with CASM.COM, ASM.COM and DDT.COM.
; 
; Functions appearing in this file:
;
; 	getchar	kbhit	ungetch	putchar	putch	gets	rand	srand
;	srand1	nrand	csw	setmem	movmem	call	calla	inp
;	outp	peek	poke	sleep	pause	exit	bdos	bios
;	biosh	codend	externs	endext	topofmem 	exec	execv
;	sbrk	rs   o the screen, alas)
	cpi	cntrlc	;is it control-C?
	jz	exit	;if so, abort and reboot
	pop	b	;else ignore it.
	ret
	ENDFUNC

	FUNCTION	putch
	call	ma1toh
	push	b
	mvi	c,conout
	mov	e,a
	cpi	newlin
	jnz	putch1	;if not newline, just put it out
	mvi	e,cr	;else put out CR-LF
	call	bdos
	mvi	c,conout
	mvi	e,lf
putch1:	call	bdos
	pop	b
	ret
	ENDFUNC

	FUNCTION	gets
	call	ma1toh	;get destination address
	push	b	;save BC
	push	h
	push	h
	lxi	h,-150	;use space below stack for reading line
  E vstk	memcmp
;

	INCLUDE "bds.lib"

	FUNCTION	getchar
	lda	ungetl	;any character pushed back?
	ora	a
	mov	l,a
	jz	gch2
	xra	a	;yes. return it and clear the pushback
	sta	ungetl	;byte in C.CCC.
	mvi	h,0
	ret

gch2:	push	b
	mvi	c,conin
	call	bdos
	pop	b
	cpi	cntrlc	;control-C ?
	jz	exit	;if so, exit the program.
	cpi	1ah	;control-Z ?
	lxi	h,-1	;if so, return -1.
	rz
	mov	l,a
	cpi	cr	;carriage return?
	jnz	gch3
	push	b
	mvi	c,conout	;if so, also echo linefeed
	mvi	e,lf
	call	bdos
  	 	dad	sp
	push	h	;save buffer address
	mvi	m,88h	;Allow a max of about 135 characters
	mvi	c,getlin
	xchg		;put buffer addr in DE
	call	bdos	;get the input line
	mvi	c,conout
	mvi	e,lf	;put out a LF
	call	bdos
	pop	h	;get back buffer address
	inx	h	;point to returned char count
	mov	b,m	;set B equal to char count
	inx	h	;HL points to first char of line
	pop	d	;DE points to start destination area
copyl:	mov	a,b	;copy line to start of buffer
	ora	a
	jz	gets2
	mov	a,m
	stax	d
	inx	h
	inx	d
  p 	pop	b
	mvi	l,newlin	;and return newline (linefeed)..

gch3:	mvi	h,0
	ret
	ENDFUNC

	FUNCTION	kbhit
	lda	ungetl	;any character ungotten?
	mvi	h,0
	mov	l,a
	ora	a
	rnz		;if so, return true

	push	b
	mvi	c,cstat	;else interrogate console status
	call	bdos
	pop	b

	ora	a	;0 returned by BDOS if no character ready
	lxi	h,0
	rz		;return 0 in HL if no character ready
	inr	l	;otherwise return 1 in HL
	ret
	ENDFUNC kbhit

	FUNCTION	ungetch
	lda	ungetl
	mov	l,a
	push	h
	call	ma2toh
	sta   	dcr	b
	jmp	copyl
	
gets2:	xra	a	;store terminating null
	stax	d
	pop	h	;return buffer address in HL
	pop	b
	ret
	ENDFUNC


	FUNCTION	rand
	lhld	rseed
	xchg
	mvi	a,48h
	ana	e
	jz	rand1
	jpe	rand1
	stc
rand1:	lhld	rseed+2
	mov	a,h
	ral
	mov	h,a
	mov	a,l
	ral
	mov	l,a
	shld	rseed+2
	mov	a,d
	ral
	mov	h,a
	mov	a,e
	ral
	mov	l,a
	shld	rseed
	mov	a,h
	ani	7fh
	mov	h,a
	ret
	ENDFUNC

	FUNCTION	srand
	call	ma1toh
	mov	a,h
	ora	l
	jz	srand2
	shld	rseed
	shld	rseed+2
	r   	ungetl
	pop	h
	mvi	h,0
	ret
	ENDFUNC ungetch

	FUNCTION	putchar
	call	ma1toh	;get character in A
	push	b
	mvi	c,conout
	cpi	newlin	;newline?
	jnz	put1	;if not, just go put out the character
	mvi	e,cr	;else...put out CR-LF
	call	bdos
	mvi	c,conout
	mvi	a,lf

put1:	mov	e,a
	call	bdos

put2:	mvi	c,cstat	;now, is input present at the console?
	call	bdos
	ora	a
	jnz	put3
	pop	b	;no...all done.
	ret

put3:	mvi	c,conin	;yes. sample it (this will always echo the
	call	bdos	;	character t  | et

srand2:	lxi	d,stg1
	push	b
	mvi	c,9
	call	bdos
	lxi	h,0bdbdh
srand3:	push	h
	mvi	c,11
	call	bdos
	pop	h
	inx	h
	inx	h
	inx	h
	ani	1
	jz	srand3
	shld	rseed
	shld	rseed+2
	mvi	c,conout
	mvi	e,cr
	call	bdos
	mvi	c,conout
	mvi	e,lf
	call	bdos
	mvi	c,conin	;clear the character
	call	bdos
	pop	b
	ret
stg1:	db 'Wait a few seconds, and type a CR: $'
	ENDFUNC


	FUNCTION	srand1
	EXTERNAL	puts
	call	ma1toh
	push	h
	call	puts	;print prompt string
	pop	h
	push	b
	lxi	h,5678h
                            sr1a:	push	h
	mvi	c,cstat
	call	bdos
	pop	h
	inx	h
	inx	h
	inx	h
	ora	a
	jz	sr1a
	shld	rseed
	shld	rseed+2
	pop	b
	ret
	ENDFUNC

	FUNCTION	nrand
	EXTERNAL	puts
	call	arghak
	lhld	arg1	;get n (1st arg)
	mov	a,h
	ana	l
	cpi	255	;was it -1 (set seed) ?
	jnz	nrand1
	lhld	arg2	;copy seed
	shld	seed
	lhld	arg3
	shld	seed+2
	lhld	arg4
	shld	seed+4	
	ret		;all done

nrand1:	push	b
	mov	a,h	;look at first arg again
	ora	l
	jnz	nrand3	;is it 0 (randomize)?
	lhld	arg2
	push	h	;yes.    inx	d
	dcr	b
	jnz	randm7

	dcx	h	;put the two high order bytes
	mov	a,m	;into HL for return to C, not
	ani	7fh	;neglecting to zero the high
	mov	h,a	;order bit so a positive int
	lda	seed+4	;is returned
	mov	l,a
	pop	b
	ret

plier:	db	0c5h,87 $h,1
	db	0eh,9ah,0e0h	

seed:	db	1,0 

prod:	db	0, 0
	ENDFUNC

	FUNCTION	csw
	in	255
	mov	l,a
	mvi	h,0
	ret
	ENDFUNC

	FUNCTION	setmem
	call	arghak
	push	b
	lhld	arg2
	xchg
	lhld	arg1
	lda	arg3
	mov	c,a
	inx	d
setm2:	dcx  [ print out string
	call	puts	;call	puts
	pop	d
	lxi	h,5a97h	;yes. start w/something odd
nrand2:	push	h
	mvi	c,cstat	;interrogate console status
	call	bdos
	pop	h
	inx	h	;and keep it odd
	inx	h	;and growing
	ora	a
	jz	nrand2	;until user types something.
	shld	seed	;then plaster the value all over the
	shld	seed+2	;seed.
	shld	seed+4
	pop	b
	ret

nrand3:	lda	seed	;now compute next random number. from this
	ori	1	; point on, the code is that of Prof. Paul Gans
	sta	seed	;lsb of SEED must be    	d
	mov	a,d
	ora	e
	jnz	setm3
	pop	b
	ret

setm3:	mov	m,c
	inx	h
	jmp	setm2
	ENDFUNC

	FUNCTION	movmem
	call	arghak
	lhld	arg3	;get block length
	mov	a,h
	ora	l
	rz		;do nothing if zero length
	push	b
	mov	b,h
	mov	c,l	;set BC to length
	lhld	arg2	;get dest addr
	xchg		;put in DE
	lhld	arg1	;get source addr in HL
	call	cmphd	;if source < dest, do tail-first
	jc	tailf	;else do head-first

headf:	mvi	a,2	;test for Z-80
	inr	a
	jpe	m8080h	;Z80?
	db	0edh,0b0h	;yes. do block move.
   1
	
	mvi	b,6	;clear 6 PROD bytes to 0
	lxi	h,prod
randm1:	mvi	m,0
	inx	h
	dcr	b
	jnz	randm1

	lxi	b,6	;set byte counter
randm2:	lxi	h,plier-1
	dad	b	;make addr of lsb of PLIER
	mov	a,m	;PLIER byte
	push	b	;save byte counter
	mvi	b,8	;set bit counter

randm3:	mov	d,a	;save PLIER byte
	lxi	h,prod	;shift whole PROD left one bit
	mvi	c,6
	xra	a
randm4:	mov	a,m	;get byte	
	ral		;shift left
	mov	m,a	;put byte
	inx	h
	dcr	c
	jnz	randm4

	mov	a,d	;recover PLIER byte
	ral		;look at curren   	pop	b
	ret		;and done.

m8080h:	mov	a,m
	stax	d
	inx	h
	inx	d
	dcx	b
	mov	a,b
	ora	c
	jnz	m8080h
	pop	b
	ret

tailf:	dcx	b	;tail first. Compute new source
	dad	b	;and destination addresses
	xchg
	dad	b
	xchg
	inx	b
	mvi	a,2	;test for Z80
	inr	a
	jpe	m8080t	;Z80?
	db	0edh,0b8h	;yes. do block move.
	pop	b
	ret

m8080t:	mov	a,m
	stax	d
	dcx	h
	dcx	d
	dcx	b
	mov	a,b
	ora	c
	jnz	m8080t
	pop	b
	ret

cmphd:	mov	a,h
	cmp	d
	rnz
	mov	a,l
	cmp	e
	ret
	ENDFUNC

	FUNCTION	  v t high bit
	jnc	randm6	;0 means no add cycle

	push	psw	;add SEED to PROD
	xra	a
	mvi	c,6
	lxi	h,prod
	lxi	d,seed
randm5:	ldax	d
	adc	m
	mov	m,a
	inx	h
	inx	d
	dcr	c
	jnz	randm5
	pop	psw

randm6:	dcr	b	;test bit counter
	jnz	randm3	;go cycle more bits
	pop	b	;recover byte counter
	dcr	c	;test it
	jnz	randm2	;go process more bytes

	mvi	b,6	;complement PROD, add 1 to it,
	lxi	h,seed	;and transfer it to SEED.
	lxi	d,prod
	xra	a
	cmc
randm7:	ldax	d
	cma
	aci	0
	mov	m,a
	inx	h
	  S call
	call	arghak
	push	b
	lhld	arg5
	xchg
	lhld	arg4
	mov	b,h
	mov	c,l
	lda	arg2
	lxi	h,call2
	push	h
	lhld	arg1
	push	h
	lhld	arg3
	ret

call2:	pop	b
	ret
	ENDFUNC

	FUNCTION	calla
	call	arghak
	push	b
	lhld	arg5	;get de value
	xchg
	lhld	arg4	;get bc value
	mov	b,h
	mov	c,l
	lda	arg2	;get a value
	lxi	h,calla2  ;get return address
	push	h	;push	it
	lhld	arg1	;get address of routine
	push	h
	lhld	arg3	;get hl value	
	ret		;call	routine
	
calla2:	mov	l,a	;put A value in N                         P   HL
	mvi	h,0	;clear high byte
	pop	b
	ret
	ENDFUNC

	FUNCTION	inp
	call	ma1toh
	sta	iohack+1	;store as arg to ram area input subroutine
	call	iohack		;call the subroutine to get value
	mov	l,a		;and put into HL
	mvi	h,0
	ret
	ENDFUNC

	FUNCTION	outp
	call	ma1toh		;get port number
	sta	iohack+4	;store as arg to ram area output subroutine
	call	ma2toh		;get data byte
	call	iohack+3	;output it
	ret
	ENDFUNC

	FUNCTION	peek
peek:	call	ma1toh
	mov	l,m
	mvi	h,0
	ret
	ENDFUNC peek


	   ly by 3
	add	a
	add	b
	mov	e,a	;put in DE
	mvi	d,0
	dad	d	;add to base of jump table
	push	h	;and save for later

	lhld	arg2	;get value to be put in BC
	mov	b,h	;and put it there
	mov	c,l

	lhld	arg3	;get value to be put in DE
	mov	d,h	;adn put it there
	mov	e,l

	lxi	h,retadd	;where call to bios will return to
	xthl		;get address of vector in HL
	pchl		;and go to it...
retadd:	pop	b	;all done. Leave return value in HL
	ret		;and return to caller
	ENDFUNC

	FUNCTION	codend
	lhld	code   FUNCTION	poke
	call	arghak
	lhld	arg1
	lda	arg2
	mov	m,a
	ret
	ENDFUNC

	FUNCTION	sleep
	call	ma1toh
	push	b
	inx	h
sl1:	dcx	h
	mov	a,h
	ora	l
	jnz	sl1a
	pop	b
	ret

sl1a:	lxi	d,10000
sl2:	dcx	d
	mov	a,d
	ora	e
	jnz	sl2
	push	h
	mvi	c,cstat
	call	bdos
	ora	a
	pop	h
	jz	sl1
	push	h
	mvi	c,conin
	call	bdos
	cpi	cntrlc
	jz	exit
	pop	h
	jmp	sl1
	ENDFUNC

	FUNCTION	pause
	push	b
paus1:	mvi	c,cstat
	call	bdos
	ora	a
	jz	paus1
	pop	b
	ret
	ENDFUNC


	FUNCTION	exit   nd
	ret
	ENDFUNC

	FUNCTION	externs
	lhld	extrns
	ret
	ENDFUNC

	FUNCTION	endext
	lhld	freram
	ret
	ENDFUNC

	FUNCTION	topofmem  
	lhld	base+6
	lda	tpa	;check for "NOBOOT" hackery
	cpi	0c3h	; "jmp" at start of C.CCC (as inserted by "-n")?
	dcx	h	;if CCC doesn't begin with "lxi h," then top of
	rnz		;memory is just below the base of the bdos
	lxi	d,-2100	;else subtract CCP size (plus little more for good
	dad	d	;measure) and return that as top of memory.
	ret
	ENDFUNC

	FUNCTION	exec   
	jmp	exit
	ENDFUNC

	FUNCTION	bdos
	call	arghak	
	push	b
	lda	arg1	;get C value
	mov	c,a
	lhld	arg2	;get DE value
	xchg		;put in DE
	call	bdos	;make the bdos call
	pop	b
	ret		;and return to caller
	ENDFUNC

	FUNCTION	bios
	call	arghak	
	push	b
	lhld	base+1	;get addr of jump table + 3
	dcx	h	;set to addr of first jump
	dcx	h
	dcx	h
	lda	arg1	;get function number (1-85)
	mov	b,a	;multiply by 3
	add	a
	add	b
	mov	e,a	;put in DE
	mvi	d,0
	dad	d	;add to base of jump table
	push	h	;   
	EXTERNAL	execl
	call ma1toh	;get filename
	lxi d,0		;load null parameter in DE
	push d		;push null parameter
	push h		;push filename
	call execl	;do an execl
	pop d		;clean up stack
	pop d
	ret
	ENDFUNC		


	FUNCTION	execv
	EXTERNAL	execl
	call	arghak
	push	b	;save BC
	lhld	arg2	;get -> arg list
	mvi	b,0	;clear arg count
execv1:	inr	b	;bump arg count
	mov	e,m
	inx	h
	mov	d,m
	inx	h
	mov	a,d
	ora	e	;last arg?
	jnz	execv1	;if not, keep looking for last one

	mov	a,b	;save arg cou   and save for later
	lhld	arg2	;get value to be put in BC
	mov	b,h	;and put it there
	mov	c,l
	lxi	h,retadd	;where call to bios will return to
	xthl		;get address of vector in HL
	pchl		;and go to it...
retadd:	mov	l,a	;all done. now put return value in HL
	mvi	h,0
	pop	b
	ret		;and return to caller
	ENDFUNC

	FUNCTION	biosh
	call	arghak	
	push	b
	lhld	base+1	;get addr of jump table + 3
	dcx	h	;set to addr of first jump
	dcx	h
	dcx	h
	lda	arg1	;get function number (1-85)
	mov	b,a	;multip   nt in case of error
	sta	savcnt

	dcx	h	;HL -> next to last arg
execv2:	mov	d,m	;now push args on stack
	dcx	h
	mov	e,m
	dcx	h
	dcr 	b
	push	d
	jnz	execv2

execv3:	lhld	arg1	;get program name
	push	h	;save as first arg to execl
	call	execl	;go do it; shouldn't come back.
	lda	savcnt	;woops, we're back. Must've been an error...
	inr 	a	;bump to take prog name into consideration
	add 	a
	mov	l,a	;put size of passed parameter list
	mvi	h,0	;into HL, and adjust stack
	dad	sp
	sphl
	pop	b	;                          9   v restore BC
	lxi	h,-1	;return error value
	ret

savcnt:	ds 	1	;save arg count here
	ENDFUNC



	FUNCTION	sbrk
	call	ma1toh	;get # of bytes needed in HL
	xchg		;put into DE
	lhld	allocp	;get current allocation pointer
	push	h	;save it
	dad	d	;get tentative last address of new segment
	jc	brkerr	;better not allow it to go over the top!
	dcx	h
	xchg		; now last addr is in DE
	lhld	alocmx	;get safety factor
	mov	a,h	;negate
	cma
	mov	h,a
	mov	a,l
	cma 
	mov	l,a		
	inx	h
	dad	sp	;get HL    E ;
;	BD Software C Compiler v1.50
;	Standard Library Machine Language Functions (part B)
;	Copyright (c) 1982 by Leor Zolman
;
; This file is in "CSM" format; to convert to CRL format,
; use CASM.SUB in conjunction with CASM.COM, ASM.COM and DDT.COM.
; 
; Functions appearing in this file:
;
;	index	getline
;	setjmp	longjmp
;	setplot	clrplot	line	plot	txtplot
;

	INCLUDE "bds.lib"


;
; Index(str,substr)
; char *str, *substr;
;
; Returns index of substr in str, or -1 if not found.
;

    = (SP - alocmx)

	call	cmpdh	;is DE less than HL?
	jnc	brkerr	;if not, can't provide the needed memory.
	xchg		;else OK.
	inx	h
	shld	allocp	;save start of next area to be allocated
	pop	h	;get pointer to this area
	ret		;and return with it.

brkerr:	pop	h	;clean up stack
	jmp	error	;and return with -1 to indicate can't allocate.

cmpdh:	mov	a,d
	cmp	h
	rc
	rnz
	mov	a,e
	cmp	l
	ret
	ENDFUNC

	FUNCTION	rsvstk
	call	ma1toh	;get the value to reserve
	shld	alocmx	;and set new safety fact    	FUNCTION	index
	call	arghak
	lhld	arg1
	xchg		;main str ptr in DE
	lhld	arg2	;substr ptr in HL
	dcx	d
index1:	inx	d
	ldax	d	;end of str?
	ora	a
	jnz	index2
	lxi	h,-1	;yes. not found.
	ret
index2:	cmp	m	;quick check for dissimilarity
	jnz	index1	;loop if not same right here
	push	d	;else do long compare
	push	h
index3:	inx	h
	inx	d
	mov	a,m	;end of substr?
	ora	a
	jnz	index4	;if not, go on testing
	pop	d	;else matches
	pop	d	;get starting address of substr in DE
	lhld	arg1	;subtract b    or
	ret
	ENDFUNC

	FUNCTION	memcmp
	call	ma3toh	;get length in HL
	push	b	;save BC
	mov	b,h
	mov	c,l	;move length to BC
	call	ma3toh	;get block2 address in HL
	xchg		;move to DE
	call	ma2toh	;get block1 address in HL
loop:	mov	a,b	;all done?
	ora	c
	jnz loop1
	lxi	h,1	;if so, return TRUE, for perfect match
	pop	b
	ret

loop1:	dcx	b	;decrement count
	ldax	d	;get block2 byte
	cmp	m	;compare to block1 byte
	inx	d	;bump pointers
	inx	h
	jz	loop	;if so far so good, go on comparing
	lxi	h   y eginning of str
	call	cmh
	dad	d	;and return the result
	ret

index4:	ldax	d	;current char match?
	cmp	m
	jz	index3	;if so, keep testing
	pop	h	;else go on to next char in str
	pop	d
	jmp	index1
	ENDFUNC

;
; Getline(str,lim)
; char *str;
;
; Gets a line of text from the console, up to 'lim' characters.
;

	FUNCTION	getline
	push	b	;save BC
	call	ma3toh	;get max no. of chars
	mov	c,a	;save max length in C
	dcr	c	;allow room for final terminating null
	lxi	d,10	;allow a bit extra sta   ƹ -,0	;else a mismatch
	pop	b
	ret

	ENDFUNC) 
	call	ma3toh	;get block2 address in HL
	xchg		;move to DE
	call	ma2toh	;get block1 address in HL
loop:	mov	a,b	;all done?
	ora	c
	jnz loop1
	lxi	h,1	;if so, return TRUE, for perfect match
	pop	b
	ret

loop1:	dcx	b	;decrement count
	ldax	d	;ge t block2 byte
	cmp	m	;compare to block1 byte
	inx	d	;bump pointers
	inx	h
	jz	loop	;if so far so good, go on comparing
	lxi	h    ck for good measure
	dad	d
	call	cmh	;save amount of space to allocate on stack
	push	h
	call	ma3toh	;get destination address
	xthl		;push dest addr, get back stack offset
	dad	sp	;allocate space on stack
	push	h	;save buffer address
	mov	m,c	;Set max # of characters
	mvi	c,getlin
	xchg		;put buffer addr in DE
	call	bdos	;get the input line
	mvi	c,conout
	mvi	e,lf	;put out a LF
	call	bdos
	pop	h	;get back buffer address
	inx	h	;point to returned char count
	mov	b,m	;set B equal to char coun                                 ! !   t
	inx	h	;HL points to first char of line
	pop	d	;DE points to start destination area
	mov	c,b	;save char count in C
copyl:	mov	a,b	;copy line to start of buffer
	ora	a
	jz	gets2
	mov	a,m
	stax	d
	inx	h
	inx	d
	dcr	b
	jmp	copyl
	
gets2:	xra	a	;store terminating null
	stax	d
	mov	l,c	;return char count in HL
	mvi	h,0
	pop	b
	ret
	ENDFUNC

	FUNCTION	setjmp
	call	ma1toh
	mov	m,c	;save BC
	inx	h
	mov	m,b
	inx	h
	xchg
	lxi	h,0
	dad	sp
	xchg
	mov	m,e	;save SP
	inx	h
	mov	m,d
	in!   
	mov	c,a
	lda	arg5
	mov	b,a
	call	put	;(but first put up the point from BC)
	mov	h,b
	mov	l,c
	call	liner	;now connect them...
	pop	b
	ret		;all done.

liner:	mov	a,d
	sub	h
	call	abs
	cpi	2
	jnc	line2	;are points far enough apart
			;in both dimensions to warrant
	mov	a,e	;drawing a line?
	sub	l
	call	abs
	cpi	2
	jnc	line2
	ret		;if not, return.

line2:	call	midp	;find midpoint
	call	put	;put it up
	push	d	;set up recursive calls
	mov	d,b
	mov	e,c
	call	liner
	xthl
	call	line!  m x	h
	pop	d	;save return address
	push	d
	mov	m,e
	inx	h
	mov	m,d
	lxi	h,0	;and return 0
	ret
	ENDFUNC

	FUNCTION	longjmp
	call	ma1toh	;get buffer address
	mov	c,m	;restore BC
	inx	h
	mov	b,m
	inx	h
	mov	e,m	;restore SP...first put it in DE
	inx	h
	mov	d,m
	inx	h
	shld	temp	;save pointer to return address
	call	ma2toh	;get return value
	xchg		;put return val in DE, old SP in HL
	sphl		;restore SP with old value
	pop	h	;pop retur address off stack
	lhld	temp	;get back ptr to return ad!   r
	xchg
	pop	h
	ret		;and we are done!

midp:	push	h
	push	d

	mov	a,h
	sub	d
	ani	1
	jz	mid3

	mov	a,h
	cmp	d
	jc	mid2a
	inr	d
	jmp	mid3

mid2a:	dcr	h

mid3:	mov	a,l
	sub	e
	ani	1
	jz	mid4

	mov	a,l
	cmp	e
	jc	mid3a
	inr	e
	jmp	mid4

mid3a:	dcr	l

mid4:	mov	a,h
	add	d
	ora	a
	rrc
	mov	b,a
	mov	a,l
	add	e
	ora	a
	rrc
	mov	c,a
	pop	d
	pop	h
	ret

put:	push	h
	push	d
	mov	a,b
	lhld	ysize
	xchg
	lhld	pbase
	inr	a
put1:	dcr	a
	jz	 put2
	dad	d
	jmp	put1
!   dress
	mov	a,m
	inx	h
	mov	h,m
	mov	l,a	;HL holds return address
	xchg		;put ret addr in DE, get return value in HL
	push	d	;push return address on stack
	ret		;and return...
temp:	ds 2
	ENDFUNC


	FUNCTION	setplot
	call	arghak
	push	b
 	lhld	arg1	;get base address
	shld	pbase	;	initialize
	lhld	arg3	;get y size
	shld	ysize	;	initialize
	xchg		;leave it in DE
	lhld	arg2	;get x size
	shld	xsize	;	initialize
	call	usmul	;figure out screen size
	shld	psize	;	initialize
	pop	b
	ret
	EN!  < 
put2:	mov	e,c
	mvi	d,0
	dad	d
	lda	arg1
	mov	m,a
	pop	d
	pop	h
	ret

abs:	ora	a
	rp
	cma
	inr	a
	ret
	ENDFUNC

	FUNCTION	plot
	call	arghak
	lda	arg1
	lhld	ysize
	xchg
	lhld	pbase
	inr	a
plot1:	dcr	a
	jz	plotc
	dad	d
	jmp	plot1

plotc:	lda	arg2
	mov	e,a
	mvi	d,0
	dad	d
	lda	arg3
	mov	m,a
	ret
	ENDFUNC

	FUNCTION	txtplot
	call	arghak
	push	b
	lhld	arg2
	xchg
	lhld	ysize
	call	usmul
	xchg
	lhld	arg3
	dad	d
	xchg
	lhld	pbase
	dad	d
	xchg
	lhld	arg1
	mvi	b,0!  " DFUNC

	FUNCTION	clrplot
	lhld	psize	;put screen size
	xchg		;	in DE
	lhld	pbase	;get screen base in HL
clr2:	mvi	m,' '	;and
	inx	h	;   clear
	dcx	d	; 	each
	mov	a,d	;	  location
	ora	e	;		(all DE of 'em)
	jnz	clr2
	ret
	ENDFUNC

	FUNCTION	line
	call	arghak	;get args
	push	b
	lda	arg2	;put one set of endpoint data in DE in
	mov	c,a	;format:  D = x = arg2, E = y = arg3
	lda	arg3
	mov	b,a
	mov	d,b
	mov	e,c
	call	put	; put up one endpoint at BC
	lda	arg4	;put other endpoint data in HL!  $ 
	lda	arg4
	ora	a
	jz	txt2
	mvi	b,80h
txt2:	mov	a,m
	ora	a
	jnz	txt3
	pop	b
	ret

txt3:	ora	b
	stax	d
	inx	h
	inx	d
	jmp	txt2
	ENDFUNC

3 
plotc:	lda	arg2
	mov	e,a
	mvi	d,0
	dad	d
	lda	arg3
	mov	m,a
	ret
	ENDFUNC

	FUNCTION	txtplot
	call	arghak
	push	b
	lhld	arg2
	xchg
	lhld	ysize
	call	usmul
	xchg
	lhld	arg3
	dad	d
	xchg
	lhld	pbase
	dad	d
	xchg
	lhld	arg1
	mvi	b, 0!'!   !   !   !   !   !   !   !   " +"   ;
;	BD Software C Compiler v1.50
;	Standard Library Machine Language Functions (part C)
;	Copyright (c) 1982 by Leor Zolman
;
; This file is in "CSM" format; to convert to CRL format,
; use CASM.SUB in conjunction with CASM.COM, ASM.COM and DDT.COM.
; 
; Functions appearing in this file:
;
;	setfcb	open	close	creat	unlink	rename	fabort
;	fcbaddr	read	write	seek	tell	cfsize	oflow
;	errno	errmsg	execl
;


	INCLUDE "bds.lib"

;
; Setfcb:
;	setfcb(fcbaddr, filename)
;	char *filename;
;
; "   v	m,a	;and store in fd table
	inx	h	;clear max sector number field of fd entry
	xra	a
	mov	m,a
	inx	h
	mov	m,a
	lda	tmp	;get back fd
	mov	l,a
	mvi	h,0
	call	rstusr	;reset user number
	ret

oerror:	call	rstusr	;reset user number
	sta	errnum	;store error code number
	jmp	error	;and return general error condition
	ENDFUNC


;
; Close:
;	close(fd);
;
; Close a file opened via "open" or "creat":
;

	FUNCTION	close
	jmp	close	;jump to the close routine in C.CCC
	ENDFUNC


;
; Creat:"   Parse a given filename onto a given FCB area. This function does NOT
; recognize user number prefixes on filenames; that is a feature limited
; to internal subroutines within the C low-level-file-I/O library and not
; generally available to users.
;

	FUNCTION	setfcb
	call	arghak
	push	b
	lhld	arg2	;get pointer to name text
igsp:	mov	a,m
	inx	h
	cpi	' '
	jz	igsp
	cpi	tab
	jz	igsp
	dcx	h
	xchg		;set DE pointing to 1st non-space char
	lhld	arg1	;get --> fcb area
	call	setfcb	; do it
	lxi	h"   
;	int creat(filename)
;	    char *filename;
; Creates the named file, first deleting any old versions, and opens it
; for both read and write. Returns a file descriptor.
;

	FUNCTION	creat
	EXTERNAL	unlink,open

	call	arghak
	lhld	arg1
	push	b

	push	h
	call	unlink	;erase any old versions of file
	pop	d

	lda	usrnum	;set to appropriate user area computed by "unlink"
	call	setusr
	mvi	c,creatc	;create the file
	lxi	d,fcb	;assume fcb has been set by "unlink"
	call	bdos
	call	rstusr	;re"  7 ,0	;all OK.
	pop	b
	ret
	ENDFUNC


;
; Open:
;	int open(filename,mode)
;	    char *filename;
;
; Open a file for read (mode == 0), write (mode == 1) or both (mode = 2),
; and detect a user-number prefix. Returns a file descriptor.
;

	FUNCTION	open
	call	arghak
	xra	a
	call	fgfcb	;any fcb's free?
	jnc	open2	;if not, error
	mvi	a,10	;"no more file slots"
	jmp	error

open2:	sta	tmp
	xchg
	lhld	arg1
	xchg
	push	b
	call	setfcu	;parse name and set usenum
	lda	usrnum
	call	setusr	;se"   store previous user number
	cpi	errorv
	pop	b
	jnz	creat0	;if no error, go open
	mvi	a,13	;"can't create file" error code
	sta	errnum
	jmp	error

creat0:	lxi	h,2	;now open for read/write
	push	h
	lhld	arg1
	push	h
	call	open
	pop	d
	pop	d
	ret
	ENDFUNC creat


;
; Unlink:
;	unlink(filename)
;	char *filename;
;
; Deletes the named file. User number prefixes are recognized:
;

	FUNCTION	unlink
	call	ma1toh
	push	b
	xchg	
	lxi	h,fcb
	call	setfcu	;parse for fcb and compute user n"  H t new user number

	mvi	c,openc
	call	bdos
	cpi	errorv	;successful open?
	pop	b

	mvi	a,11	; set error code in case of error
	jz	oerror	;if error, go abort

	lda	tmp
	call	fgfd	;get HL pointing to fd table entry
	lda	arg2
	ora	a	;open for read?
	mvi	d,3
	jz	open4
	dcr	a
	mvi	d,5
	jz	open4	;write?
	dcr	a
	mvi	a,12	;"bad mode" for open operation...
	jnz	oerror	;...if not mode 2
	mvi	d,7	;else must be mode 2.
open4:	lda	usrnum	;get user number for the file
	add	d	;add r/w bit codes
	mo"  < umber
	lda	usrnum
	call	setusr	;set to correct user number
	mvi	c,delc	;delete
	call	bdos
	call	rstusr	;restore original user number
	lxi	h,0
	pop	b	;restore BC
	cpi	errorv	;was BDOS able to find the file?
	rnz		;if so, all done.
	mvi	a,11	;set error code for "file not found"
	sta	errnum
	dcx	h	;return -1
	ret
	ENDFUNC


;
; Rename:
;	int rename(old_name,new_name)
;	    char *old_name, *new_name;
;
; Renames the given file. User number prefixes are allowed, but only
; the one on the f""   "   "   "   "   "   "   "   # #  b irst filename (if specified) effects the operation.
;
 
	FUNCTION	rename
	call	arghak
	push	b
renam:	lhld	arg1	;get old name
	xchg
	lxi	h,wfcb
	call	setfcu	;compute user number and set fcb
	lda	usrnum
	call	setusr	;set to user number of first name
	lhld	arg2
	xchg
	lxi	h,wfcb+16
	call	setfcu	;parse second name, but ignore user number
	lxi	d,wfcb
	mvi	c,renc	;perform rename operation
	call	bdos
	call	rstusr	;reset user number
	lxi	h,0
	pop	b	;restore BC
	cpi	errorv	;was BDOS able to fin#   

	mov	a,d
	ani	2
	mvi	a,8	;prepare for possible "no read permission"
	jz	rerror

	push	b
	mov	a,d	;get fd table entry
	call	setusr	;set user area to that of the file

	lda	arg1	;get fd
	call	fgfcb
	shld	tmp2	;save fcb address
	lxi	h,0	;clear sector count
	shld	tmp2a
r2:	lhld	arg3	;get countdown
	mov	a,h
	ora	l	;done?
r2aa:	lhld	tmp2a
	jnz	r2a
r2done:	call	rstusr	;reset user number
	pop	b	;yes. return with success count in HL
	ret

r2a:	lhld	arg2	;get transfer addr in DE
	xchg
	mvi#  n d the file?
	rnz		;if so, all done
	mvi	a,11	;set error code for "file not found"
	sta	errnum
	dcx	h	;return -1
	ret

wfcb:	ds 53		;space for working fcb's
	ENDFUNC


;
; Fabort:
;	fabort(fd);
; Abort all operations on file fd. Has no effect under MP/M II.
;

	FUNCTION	fabort
	call	ma1toh
	call	fgfd
	jnc	abrt2	;legal fd?
	mvi	a,7
	sta	errnum	;set "bad fd" error code
	jmp	error
	
abrt2:
	IF NOT MPM2
	mvi	m,0	;clear entry in fd table
	ENDIF

	lxi	h,0
	ret
	ENDFUNC


;
; Fcb#  Z 	c,sdma	;set DMA there
	call	bdos

	lhld	tmp2
	xchg
	mvi	c,readr	;code for BDOS random read
	push	d	;save DE so we can fudge nr field if
	call	bdos	;we stop reading on extent boundary...
	pop	d
	ora	a
	jz	r4	;go to r4 if no problem

	sta	errnum	;otherwise save error code

	cpi	1	;ok, we have SOME kind of hangup...
	jz	r2b	;check for EOF condition:
	cpi	4	;  error codes 1 and 4 both indicate reading
	jz	r2b	;  unwritten data..treat as EOF

	lxi	h,-1	;put ERROR value in HL
	jmp	r2done

r#   addr:
;	char *fcbaddr(fd)
; Returns a pointer to the internal file control block associated
; with open file having descriptor fd.
;


	FUNCTION	fcbaddr
	call	ma1toh
	call	fgfd	;is it an open file?
	jnc	fcbad2	;if so, go do it
	mvi	a,7
	sta	errnum	;"bad fd" error code
	jmp	error

fcbad2:	call	ma1toh
	call	fgfcb	;get fcb addr in HL
	ret
	ENDFUNC

;
; Read:
;
;	i = read(fd, buf, n);
;
; Read a number of sectors using random-record I/O.
;
; The return value is either the number of se#   2b:	lhld	tmp2a	;return count
	jmp	r2done

r4:	lhld	arg3	;decrement countdown
	dcx	h
	shld	arg3
	lhld	arg2	;bump DMA address
	lxi	d,128
	dad	d
	shld	arg2
	lhld	tmp2a	;bump success count
	inx	h
	shld	tmp2a
	lhld	tmp2	;get address of fcb
	lxi	b,33	;get addr of random record field
	dad	b
	mov	c,m	;bump
	inx	h	;    value
	mov	b,m	;	  of 
	inx	b	;	    random
	mov	m,b	;		  field
	dcx	h	;			by one
	mov	m,c
	mov	a,b	;overflow past 16-bit record count?
	ora	c
	jnz	r2	; go for next sector if n#  < ctors successfully
; read, 0 for EOF, or -1 on error with errno() returning the error
; code (or errmsg(n) returning a pointer to an error message).
; 
; The Random Record Field is incremented following each successful
; sector is read, just as if the normal (sequential) read function
; were being used. "seek" must be used to go back to a previous 
; sector.
;

	FUNCTION read

	call	arghak
	lda	arg1
	call	fgfd
	mov	d,m	;save fdt entry in D
	mvi	a,7	;prepare for possible "bad fd"
	jc	rerror#   o overflow
	inx	h	;else set 3rd byte of random sector count
	inx	h
	mvi	m,1
	mvi	a,14	;"seek past 65536th record of file"
	sta	errnum
	jmp	r2aa	;and don't read any more.

rerror:	sta	errnum
	jmp	error
	ENDFUNC

;
; Write:
;	i = write(fd, buf, n);
;
; The random sector write function. Returns either the number
; of sectors successfully written, or -1 on hard error. Any return
; value other than n (the third arg) should be considered an error,
; after which errno() can tell you the error co#5#   #   #   #   #   #   #   #   $ $   ndition and errmsg() 
; can return a pointer to an appropriate error message text.
;

	FUNCTION write

	call	arghak
	lda	arg1
	call	fgfd
	shld	arg5	;save pointer to fd table entry
	mov	d,m	;save fd table entry in D
	mvi	a,7	;prepare for possible "bad fd"
	jc	werror

	mov	a,d
	ani	4
	mvi	a,9	;prepare for possible "no write permission"
	jz	werror

	push	b
	mov	a,d	;set user number
	call	setusr
	lda	arg1	;get fd
	call	fgfcb	;compute fcb address
	shld	tmp2	;save it away
	lxi	h,0	;clear $   33	; get address of random field
	dad	b
	mov	c,m	; bump 16-bit value at random
	inx	h	; record
	mov	b,m	;	field
	inx	b	;	     of
	mov	m,b	;	       fcb
	dcx	h	;		  by one
	mov	m,c

	mov	a,b	;overflow past 16-bit record count?
	ora	c
	jnz	writ1	; go for next sector if no overflow
	inx	h	;else set 3rd byte of random sector count
	inx	h
	mvi	m,1
	mvi	a,14	;set "past 65536th sector" error code
	sta	errnum
	jmp	writ1a	;and don't read any more.

werror:	sta	errnum
	jmp	error

	ENDFUNC

;
$   success count
	shld	tmp2a

writ1:	lhld	arg3	;done yet?
	mov	a,h
	ora	l
	jnz	writ2

			;take care of maximum sector count for cfsize:
	lhld	tmp2	;get fcb address
	lxi	d,33	;point to random record field
	dad	d
	mov	e,m
	inx	h
	mov	d,m	;DE now holds random record number for next rec
	push	d	;save it
	lhld	arg5	;get fd table pointer
	inx	h	;point to max value
	mov	e,m	;get in DE
	inx	h
	mov	d,m	;now DE is old max value, HL points to end of entry
	xthl		;DE = old max, HL = current sector, ST$   ; Seek:
;
; seek(fd, offset, origin)
;	   seeks to offset records if origin == 0,
;     to present position + offset if origin == 1,
;	or to end of file + offset if origin == 2.
; (note that in the last case, the offset must be non-positive)
;
; There are no errors returned by this function, aside from a
; possible bad fd, because all the function does is fudge the
; random-record field of an fcb...if the seek is out of bounds,
; a subsequent direct file I/O operation (such as read or write)
; w$   ACK = tab ptr
	xchg		;HL = old max, DE = current sector
	call	cmphd	;is  old max less than current sector?
	pop	h	;get tab ptr in HL
	jnc	writ1a	;if old max not < current sector, don't update max
	mov	m,d	;else update max value with new sector number
	dcx	h
	mov	m,e
	
writ1a:	lhld	tmp2a	;if so, return count
wrdone:	call	rstusr	;reset user number
	pop	b
	ret

writ2:	lhld	arg2	;else get transfer address
	push	h	;save on stack
	xchg		;put in DE
	mvi	c,sdma	;set DMA there
	call	bdos

	pop	h	$   ill draw the error.
;

	FUNCTION seek
	EXTERNAL cfsize

	call	arghak
	push	b	;save BC
	lda	arg1
	call	fgfcb	;figure addr of fcb
	mvi	a,7	;prepare for possible "bad fd" error code
	jnc	seek0
	sta	errnum	;set the error code
	pop	b	;restore BC
	jmp	error

seek0:	push	h	;save addr of fcb
	lxi	d,33	;get current position in DE
	dad	d
	mov	e,m	
	inx	h
	mov	d,m
	lhld	arg2	;get offset in HL
	lda	arg3	;is origin == 0?
	ora	a
	jz	rseek2	;if so, HL holds new position
	dcr	a	;no. is origin == 1$   ;get back transfer address
	lxi	d,128	;bump by 128 bytes for next time
	dad	d
	shld	arg2	;save -> to next 128 bytes

	lhld	tmp2	;get addr of fcb
	xchg
	mvi	c,writr	;write random sector
	call	bdos
	lhld	tmp2a	;get success count in HL
	ora	a	;error?
	jz	writ3	;if not, go do bookkeeping
	
	sta	errnum	;else save error code
	jmp	wrdone
		
writ3:	inx	h	; else bump successful sector count,
	shld	tmp2a

	lhld	arg3	; debump countdown,
	dcx	h
	shld	arg3

	lhld	tmp2	; get address of fcb
	lxi	b,$   ?
	jnz	rseek1
	dad	d	;yes. add offset to current position
	jmp	rseek2	;and result is in HL

rseek1:			;else origin must be 2...
	lhld	arg1	;compute file size
	push	d	;save current position
	push	h
	call	cfsize
	pop	d	;pop argument
	pop	d	;pop useless current position
	xchg		;place file size in DE

;	call	fgfd
;	mov	a,m
;	call	setusr	;set the file's native user number
;
;	pop	d	;get fcb pointer back in DE
;	push	d
;	mvi	c,cfsizc ;compute end of file position
;	call	bdos
;	call	rstusr	;r$$   $   $   $   $   $   $   $   % %   eset user number
;	pop	h	;get fcb addr in HL again
;	push	h
;	call	rseek3	;get DE = position

	lhld	arg2	;add offset
	dad d		;and HL holds new position
rseek2:	xthl		;get fcb, push	new position
	lxi	d,33
	dad	d	;HL points to random field of fcb
	pop	d	;get new position in DE
	mov	m,e	;and put into fcb
	inx	h
	mov	m,d
	xchg		;and return the position value
	pop	b	;pop saved BC off stack
	ret

;rseek3:	lxi	d,33
;	dad	d
;	mov	e,m	
;	inx	h
;	mov	d,m
;	ret

	ENDFUNC

;
; Tell:
;
; i %   old max as current max
	xthl		;get back pointer to old max value
	mov	m,e	;update with new fsize value
	inx	h
	mov	m,d
	xchg		;put end-of-file sector number in HL for return

cfsiz3:	pop	d	;clean up stack
	call	rstusr	;reset user area
	pop	b
	ret
	ENDFUNC

;
; Oflow:
;	i = oflow(fd);
;
; Returns true if the highest-order byte (the third byte) of the
; sector count in the fcb for the given file is non-zero:
;

	FUNCTION	oflow
	call	ma1toh
	call	fgfcb
	jnc	oflow0
	mvi	a,7	;"bad fd" er%  ? = tell(fd);
;
; Return random record position of file:
;

	FUNCTION tell

	call	ma1toh	;get fd in A
	call	fgfcb
	jnc	tell0
	mvi	a,7	; "bad fd" error
	sta	errnum
	jmp	error

tell0:	lxi	d,33	;go to random record field
	dad	d
	mov	a,m	;get position in HL
	inx	h
	mov	h,m
	mov	l,a
	ret

	ENDFUNC

	
;
; cfsize:
; 	cfsize(fd)
;
; Compute size of file, but leave random-record field at original value.
;

	FUNCTION	cfsize
	call	ma1toh
	call	fgfcb
	jnc	cfsiz2
	mvi	a,7	;"bad fd" erro%  	 ror
	sta	errnum
	jmp	error	;abort if file isn't valid

oflow0:	lxi	d,35	;look at high byte of sector position
	dad	d
	mov	a,m
	ora	a	;is it zero?
	lxi	h,0
	rz		;if so, no overflow
	inx	h	;else overflow.
	ret
	ENDFUNC


;
; Errno:
;	int errno()
; Returns last recorded file I/O error condition, set following the
; last error encountered by the "read" and "write" functions.
;

	FUNCTION errno

	lda	errnum
	mov	l,a
	mvi	h,0
	ret

	ENDFUNC

;
; Errmsg:
;	errmsg(n)
; Prints out t%   r
	sta	errnum
	jmp	error

cfsiz2:	push	b	;save BC
	push 	h	;save fcb address
	call	ma3toh	;set user area
	call	fgfd	;get pointer to fd table entry

	mov	a,m
	call	setusr
	inx	h
	shld	tmp2	;save pointer to max sector value

	pop	d	;restore fcb address into DE
	lxi	h,33	;get to random record field
	dad	d
	push	h	;save ptr to random record field for after BDOS call

	mov	a,m
	inx	h
	mov	h,m
	mov	l,a	;HL = current setting
	push	h	;save current value of random record field

	mvi	c,cfsizc%   he BDS C file I/O error message having number n, as returned
; by the "errno()" function.
;

	FUNCTION	errmsg

nerrs:	equ	14	;highest legal error code


	call	ma1toh	;get the number
	cpi	nerrs
	jnc errms2
	mvi	a,nerrs+1 ;get the error error message
errms2:	dad	h	;double to get table offset
	lxi	d,txtab	;get base of text pointer table
	dad	d	;add to get appropriate pointer
	mov	a,m	;return pointer in HL
	inx	h
	mov	h,m
	mov	l,a	
	ret

txtab:	dw	err0
	dw	err1
	dw	err2
	dw	err3
	dw	er%   	;compute file size
	call	bdos
	pop	b	;pop old random record value into BC
	pop	h	;get pointer to random record field

	mov	e,m	;get end-of-file sector number into DE
	inx	h
	mov	d,m

	mov	m,b	;restore original value
	dcx	h
	mov	m,c

	lhld	tmp2	;get pointer to fd table max sector value
	push	h	;save ptr to max value
	mov	a,m	;get max sector value in HL
	inx	h
	mov	h,m
	mov	l,a	;now old max in HL, fsize value in DE
	call	cmphd	;is old max < current fsize?
	jnc	cfsiz3	;if not, just return %  W r4
	dw	err5
	dw	err6
	dw	err7
	dw	err8
	dw	err9
	dw	err10
	dw	err11
	dw	err12
	dw	err13
	dw	err14
	dw	errerr
	

err0:	db	'No errors occurred yet',0
err1:	db	'Reading unwritten data',0
err2:	db	'Disk out of data space',0
err3:	db	'Can''t close current extent',0
err4:	db	'Seek to unwritten extent',0
err5:	db	'Can''t create new extent',0
err6:	db	'Seek past end of disk',0
err7:	db	'Bad file descriptor',0
err8:	db	'File not open for read',0
err9:	db	'File not open for write',0
err10:	db	%%   %   %   %   %   %   %   %   & &   'Too many files open',0
err11:	db	'File not found',0
err12:	db	'Bad mode to "open"',0
err13:	db	'Can''t create the file',0
err14:	db	'Seek past 65535th record',0

errerr:	db 	'Errmsg: error number out of range',0
	ENDFUNC



	FUNCTION	execl

	call	arghak
	push	b
	lhld	arg1
	xchg
	lxi	h,-60	;compute &nfcb for use here
	dad	sp
	push	h	; save for much later (will pop	into BC)
  	push	h	;make a few copies for local use below
	push	h
	call	setfcu	;set up COM file for execl-ing
	lda	usrnum&   ng

excl3:	pop	h	;clean up stack
	mov	a,b	;check for command buffer overflow
	cpi	53h
	jc	excl30	;if no overflow, go load file
	lxi	d,errmsg
	mvi	c,9	;else comlain and abort...
	call	bdos
	jmp	err

errmsg:	db	7,'EXECL: Command line overflow',cr,lf,'$'

excl30:	lxi	h,tbuff	;set length of command line
	mov	m,b	;at location tbuff

excl3a:	lxi	d,code0	;copy loader down to end of tbuff
	lxi	h,tpa-42
	mvi	b,42	;length of loader
excl4:	ldax	d
	mov	m,a
	inx	d
	inx	h
	dcr	b
	jnz	excl4

	pop&   
	call	setusr	;set destination user area
	pop	h	;get new fcb addr
	lxi	b,9	;set extension to COM
	dad	b
	mvi	m,'C'
	inx	h
	mvi	m,'O'
	inx	h
	mvi	m,'M'
	pop	d	;get new fcb addr again
	mvi	c,openc	;open the file for reading
	call	bdos
	call	rstusr	;reset user number to previous
	cpi	errorv
	jnz	noerrr
err:	pop	h
	pop	b
	jmp	error

noerrr:	lhld	arg2	;any first parameter?
	mov	a,h
	ora	l
	jnz	excl0
	lxi	d,arg2	;no...null out first default fcb slot
	push	d
	lxi	h,fcb
	call	setfcb
	pop	&   	b	;get fcb pointer in BC
			;reset the SP:
	lhld	base+6	;get BDOS pointer in HL
	lda	tpa	;look at first op byte of run-time pkg
	cpi	31h	;begin with "lxi sp,"?
	jnz	go0	;if so, use the same value now...
	lhld	tpa+1	;else get special SP value
	jmp	go1

go0:	cpi	21h	;begin with "lxi h" (the NOBOOT sequence?)
	jnz	go1	;if not, just use the BDOS addr as top of memory
	lxi	d,-2050	;for NOBOOT, subtract 2100 from BDOS addr
	dad	d	;and make that the new SP
go1:	sphl

	lxi	h,base
	push	h	;set base &   h
	jmp	excl0a	;and go null out 2nd fcb slot

excl0:	xchg		;yes.. place into first default fcb slot
	lxi	h,fcb
	call	setfcb
	lhld	arg3	;any second parameter given?
	mov	a,h
	ora	l
	jnz	excl0a
	lxi	h,arg3

excl0a:	xchg		;yes: stick it into second default fcb slot
	lxi	h,fcb+16
	call	setfcb	
	lxi	d,tbuff+1   ;now construct command line:
	xra	a	;  zero tbuff+1 just in case there
	stax	d	;  are no arg strings
	lxi	h,8	;get pointer to 1st arg string in HL
	dad	sp	;   by offsetting 4 objects fro&  W of ram as return addr
	jmp	tpa-42	;(go to `code0:')

mpuc:	cpi	61h	;convert character in A to upper case
	rc
	cpi	7bh
	rnc
	sui	32
	ret

;
; This loader code is now: 42 bytes long.
;

code0:	lxi	d,tpa	;destination address of new program
code1:	push	d	;push	dma addr
	push	b	;push	fcb pointer
	mvi	c,sdma	;set DMA address for new sector
	call	bdos
	pop	d	;get pointer to working fcb in DE
	push	d	;and re-push	it
	mvi	c,reads	;read a sector
	call	bdos
	pop	b	;restore fcb pointer into BC
	&   m the current SP
	mvi	b,0	;char count for com. line buf.
excl1:	push	h	;and construct command line
	mov	a,m	;get addr of next arg string pointer
	inx	h
	mov	h,m
	mov	l,a	;0000 indicates end of list.
	ora	h	;end of list?
	jz	excl3

	mvi	a,' '	;no. install next string
	dcx	h
excl2:	call	mpuc	;convert to upper case for command line buffer
	stax	d
	inx	d
	inr	b
	inx	h
	mov	a,m
	ora	a	;end of string?
	jnz	excl2
	pop	h	;yes.
	inx	h	;bump param pointer
	inx	h	
	jmp	excl1	;and go do next stri&   pop	d	;and dma address into DE
	ora	a	;end of file?
	jz	tpa-8	;if not, get next sector (goto `code2:')
	mvi	c,sdma	;reset DMA pointer
	lxi	d,tbuff
	call	bdos
	jmp	tpa	;and go invoke the program

code2:	lxi	h,80h	;bump dma address
	dad d
	xchg
	 ;jmp	tpa-39 	;and go loop (at code1)

	ENDFUNC


	END
# r to working fcb in DE
	push	d	;and re-push	it
	mvi	c,reads	;read a sector
	call	bdos
	pop	b	;restore fcb pointer into BC
	&&   &   &   &   &   &   &   &   ' '   ;
; CCC.ASM:  BDS C Run-Time Package (C.CCC)	    v1.50, 11/9/82
; Copyright (c) 1982 by Leor Zolman
;
; NOTE: If you are running under MP/M II, be sure to set the MPM2
;	equate to 1.
;
; This is the BDS C run-time package. Normally, it resides at
; the start of the TPA (at BASE+100h). The code generated
; by BDS C always sits immediately on top of this run-time
; package code.
;
; Equate statements in CAPITAL letters may be customized by the
; user in order to change a) the origin of the run-ti'  } done executing
	ENDIF

;
; The location of the jump vectors and utility routines must remain
; constant relative to the beginning of this run-time module.
;
; Do NOT change ANYTHING between here and the start of the
; "init" routine!!!!!!!!
;

	org	origin

;
; The "lxi sp,0" instruction at the start of the code is changed by
; CLINK, if the "-t" option is NOT used, into:
;		lhld	base+6
;		sphl
;
; If "-t <addr>" is used, then the sequence becomes:
;		lxi	sp,<addr>
;		nop
;
; If "-n" i'   me package,
; b) the origin of the run-time package's local r/w area, and c) the
; RST vector used to interface with Kirkland's CDB debugger. If
; you will be generating code to run in a non-CP/M environment,
; set the CPM equate to zero and make sure to set the ORIGIN, RAM
; and EXITAD equates to fit your custom run-time configuration.
;

FALSE:	EQU	0
TRUE:	EQU	NOT FALSE

CPM:	EQU	TRUE	;True if to be run under CP/M or MP/M

MPM2:	EQU	FALSE	;True ONLY if running under MP/M II

DMAVIO:	EQU	TRU'   s used, to indicate no-warm-boot, then the the sequence becomes:
;		jmp	snobsp
;		nop
;

	lxi	sp,0	;These two instructions change depending on whether
	nop		;or not the CLINK "-t" or "-n" options are given.

	nop
	nop

	jmp	skpfex	;skip over the following vector (don't ask...)

fexitv:	jmp	exitad	;final exit vector. If "-n" used, this
			;becomes address of the "nobret" routine.

skpfex:	call	init	;do ARGC & ARGV processing, plus misc. initializations
	call	main	;go crunch!!!!
	jmp	vexit	;'   E	;True if using DMA video library routines and
			;need parameters initialized

USERST:	EQU	FALSE	;True to use a restart vector for CDB interfacing
RSTNUM:	EQU	6	;Use "RST n" as default debugger vector. Has no
			;effect if USERST is false.
rstloc:	equ  RSTNUM*8	;Memory address where "RST n" vector falls

	IF CPM
nfcbs:	equ	9	;maximum # of files open at one time
base:	equ	0	;start of ram in system (either 0 or 4200h)
bdos:	equ	base+5	;the rest of these do not vary between CP/M systems.
tpa:	equ'   close open files and reboot

extrns:	ds	2		;set by CLINK to external data base address
cccsiz:	dw	main-origin	;size of this code (for use by CLINK)
codend:	ds	2		;set by CLINK to (last addr of code + 1)
freram:	ds	2		;set by CLINK to (last addr of externals + 1)

;
; Jump vectors to some file i/o utility routines:
;

error:	jmp	verror	;loads -1 into HL and returns
exit:	jmp	vexit	;close all open files and reboot

	IF	CPM
close:	jmp	vclose	;close a file
setfcb:	jmp	vsetfcb	;set up fcb at HL g'   	base+100h
tbuff:	equ	base+80h
origin:	equ	tpa
exitad:	equ	base	;warm boot location

conin:	equ	1	;BDOS call codes...console input
cstat:	equ	11	;interrogate console status
closec:	equ	16	;close file
gsuser:	equ	32	;get/set user code
	ENDIF

	IF NOT CPM		;fill in the appropriate values...
ORIGIN:	EQU	NEWBASE		;Address at which programs are to run
RAM:	EQU	WHATEVER	;R/W memory area for non-CP/M configurations
				;  (default: just after C.CCC under CP/M)
EXITAD:	EQU	WHENDONE	;where to go when '  r iven filename at DE
fgfd:	jmp	vfgfd	;return C set if file fd in A not open
fgfcb:	jmp	vfgfcb	;compute address of internal fcb for fd in A
setfcu:	jmp	vsetfcu	;set up FCB and process user number prefix
setusr:	jmp	vsetusr ;set user area to upper 5 bits of A, save previous
rstusr:	jmp	vrstusr	;restore user area to what it was before setusr call
snobsp: jmp	vsnobsp	;set up SP for non-boot ("-tn") CLINK option
nobret:	jmp	vnobret	;return to CCP when non-boot ("-tn") in effect.
khack:	jmp	vkhack	;Kirklan''   '   '   '   '   '   '   '   ( q$    $    $    $    $    $    $    $    ($   $   $   $   $   $   $   $   ) '    '    '    '    '    '    '    '    )o'   '   '   '   '   '   '   '   * /&    &    & 9  & rz         #& ) 3 c ^&    &    &    *&i@  &o    ty<@ G#y<@// G#y<@ G#y<@ G#9<  G#    !y<@ G+yy yxyy yyyy 2< / @W+&/  ,   &Y  
   
/_  |   $ >  / &3   o 0.    C *