;.TITLE "YAU: Yet Another Uudecoder"
;.TAB 8,14,20
	*=	$3000
;
; .INCLUDE D2:SYSEQU.ASM
;-----------------------------------------------------------
; .PAGE "OSS SYSTEM EQUATES FOR ATARI"
;
;  FILE = #DN:SYSEQU.ASM
;
;
; I/O CONTROL BLOCK EQUATES
;
SAVEPC	=	*	; SAVE CURRENT ORG
;
	*=	$0340	; START OF SYSTEM IOCBS
IOCB
;
ICHID
	*=	*+1	; DEVICE HANDLER IS (SET BY OS)
ICDNO
	*=	*+1	; DEVICE NUMBER (SET BY OS)
ICCOM
	*=	*+1	; I/O COMMAND
ICSTA
	*=	*+1	; I/O STATUS
ICBADR
	*=	*+2	; BUFFER ADDRESS
ICPUT
	*=	*+2	; DH PUT ROUTINE (ADR-1)
ICBLEN
	*=	*+2	; BUFFER LENGTH
ICAUX1
	*=	*+1	; AUX 1
ICAUX2
	*=	*+1	; AUX 2
ICAUX3
	*=	*+1	; AUX 3
ICAUX4
	*=	*+1	; AUX 4
ICAUX5
	*=	*+1	; AUX 5
ICAUX6
	*=	*+1	; AUX 6
;
IOCBLEN	=	*-IOCB	; LENGTH OF ONE IOCB
;
; IOCB COMMAND VALUE EQUATES
;
COPN	=	3	; OPEN
CGBINR	=	7	; GET BINARY RECORD
CGTXTR	=	5	; GET TEXT RECORD
CPBINR	=	11	; PUT BINARY RECORD
CPTXTR	=	9	; PUT TEXT RECORD
CCLOSE	=	12	; CLOSE 
CSTAT	=	13	; GET STATUS
;
; DEVICE DEPENDENT COMMAND EQUATES FOR FILE MANAGER
;
CREN	=	32	; RENAME
CERA	=	33	; ERASE
CPRO	=	35	; PROTECT
CUNP	=	36	; UNPROTECT
CPOINT	=	37	; POINT
CNOTE	=	38	; NOTE
;
; AUX1 VALUES REQD FOR OPEN
;
OPIN	=	4	; OPEN INPUT
OPOUT	=	8	; OPEN OUTPUT
OPUPD	=	12	; OPEN UPDATE
OPAPND	=	9	; OPEN APPEND
OPDIR	=	6	; OPEN DIRECTORY
;
; .PAGE
;
;    EXECUTE FLAG DEFINES
;
EXCYES	=	$80	; EXECUTE IN PROGRESS
EXCSCR	=	$40	; ECHO EXCUTE INPUT TO SCREEN
EXCNEW	=	$10	; EXECUTE START UP MODE
EXCSUP	=	$20	; COLD START EXEC FLAG
;
; MISC ADDRESS EQUATES
;
CPALOC	=	$0A	; POINTER TO CP/A
WARMST	=	$08	; WARM START (0=COLD)
MEMLO	=	$2E7	; AVAIL MEM (LOW) PTR
MEMTOP	=	$2E5	; AVAIL MEM (HIGH) PTR
APPMHI	=	$0E	; UPPER LIMIT OF APPLICATION MEMORY
INITADR	=	$2E2	; ATARI LOAD/INIT ADR
GOADR	=	$2E0	; ATARI LOAD/GO ADR
CARTLOC	=	$BFFA	; CARTRIDGE RUN LOCATION
CIO	=	$E456	; CIO ENTRY ADR
EOL	=	$9B	; END OF LINE CHAR
;
; Character defs from sysmac.sml
;
ATCLR	=	$7D	;CLEAR SCREEN CHARACTER
ATRUB	=	$7E	;BACK SPACE (RUBOUT)
ATTAB	=	$7F	;TAB
ATEOL	=	$9B	;END-OF-LINE
ATBEL	=	$FD	;CONSOLE BELL
ATURW	=	$1C	;UP-ARROW
ATDRW	=	$1D	;DOWN-ARROW
ATLRW	=	$1E	;LEFT-ARROW
ATRRW	=	$1F	;RIGHT-ARROW
space	=	$20
;
;  CP/A FUNCTION AND VALUE DISPLACEMSNT
;     (INDIRECT THROUGH CPALOC)
;           IE. (CPALOC),Y
;
CPGNFN	=	3	; GET NEXT FILE NAME
CPDFDV	=	$07	; DEFAULT DRIVE (3 BYTES)
CPBUFP	=	$0A	; CMD BUFF NEXT CHAR POINTR (1 BYTE)
CPEXFL	=	$0B	; EXECUTE FLAG
CPEXFN	=	$0C	; EXECUTE FILE NAME (16 BYTES)
CPEXNP	=	$1C	; EXECUTE NOTE/POINT VALUES
CPFNAM	=	$21	; FILENAME BUFFER
RUNLOC	=	$3D	; CP/A LOAD/RUN ADR
CPCMDB	=	$3F	; COMMAND BUFFER (60 BYTES)
;CPCMDGO	=	-6	;  CP SUBROUTINE VECTOR
;
	*=	SAVEPC	; RESTORE PC
;
;-----------------------------------------------------------
;
; .page	"Page zero"
zpc	=	$80	; page zero pc
spc1	=	*
	*=	zpc

cmdptr:	.blkb	2	; pointer to cmd line
binp:	.blkb	2	; pointer into binary buf
strptr:	.blkb	2
dbgptr:	.blkb	2
; end of page zero defs
zpc1	=	*
	*=	spc1
;
; fp defs
;
fr0	=	$D4
fr1	=	$E0
flptr	=	$FC
inbuff	=	$F3
cix	=	$F2
;
fasc	=	$D8E6	; fp -> ascii
ifp	=	$D9AA	; int -> fp
fadd	=	$DA66	; fr0 + fr1 -> fr0
fmul	=	$DADB	; fr0 * fr1 -> fr0
fmove	=	$DDB6	; fr0 -> fr1
;
; .PAGE "Data defs"
;
inf	=	$10	; input file
outf	=	$20	; output file
;
	*=	$3000
	JMP	START	; in case goadr ignored
;
; binary buffering stuff
; binary buf size must be a 
; multiple of 256
;
BINMAX	=	8192	; how much binary to buffer up
BINBUF:	.blkb	BINMAX
BINSIZE: .word	0
BINEMPTY: .byte	1
;
nbytes:	.byte	0,0,0	; 3 ought to be big enough
chksum:	.byte	0,0	; ones comp checksum
;
; debug flag
;
debug:	.byte	0
;
; Debug code
;

; char in A out to tty
;
;
; debug code
;
	.byte	0
dbgchr:
	sta	dbgchr-1
	tya
	pha
	txa
	pha
	ldx	#0
	txa
	tay
	jsr	SETLEN
	lda	#CPBINR
	STA	ICCOM,X
	lda	dbgchr-1
	JSR	CIO
	pla
	tax
	pla
	tay
	rts
;
; dump a str, ptr in x,y, terminated by 0.
; preserves A
;
dbgstr:
	pha
	stx	dbgptr
	sty	dbgptr+1
	ldy	#0
dbgs1:
	lda	(dbgptr),y
	beq	dbgs2
	jsr	dbgchr
	iny
	bne	dbgs1
	inc	dbgptr
	bne	dbgs1
	inc	dbgptr+1
	bne	dbgs1
dbgs2:
	pla
	rts
;
dbgstre:
	pha
	stx	dbgptr
	sty	dbgptr+1
	ldy	#0
dbge1:
	lda	(dbgptr),y
	cmp	#ateol
	beq	dbge2
	jsr	dbgchr
	iny
	bne	dbge1
	inc	dbgptr
	bne	dbge1
	inc	dbgptr+1
	bne	dbge1
dbge2:
	pla
	rts

;
; print a string, textc form
;
	.byte	0
dbgstrc:
	pha
	stx	dbgptr
	sty	dbgptr+1
	ldy	#0
	lda	(dbgptr),y
	beq	dbgsc9
	sta	dbgstrc-1
dbgsc1:
	iny
	lda	(dbgptr),y
	jsr	dbgchr
	dec	dbgstrc-1
	bne	dbgsc1
dbgsc9:
	pla
	rts
;
dbgeol:
	lda	#ATEOL
	jmp	dbgchr
;
; print a byte (in A) in hex
;
	.byte	0
dbghex:
	pha
	lsr	a
	lsr	a
	lsr	a
	lsr	a
	jsr	dbghd
	pla
dbghd:
	and	#$0F
	stx	dbghex-1
	tax
	lda	hex,x
	jsr	dbgchr
	ldx	dbghex-1
	rts

dbghxy:
	tya
	jsr	dbghex
	txa
	jsr	dbghex
	rts
HEX:	.BYTE	"0123456789ABCDEF"
;
;
;----------------------------------------------------------------
;
; pathname parsing stuff.
;
; a pathname consists of optional device, name, and optional
; extension.
;
; a pathname descriptor is a structure containing three fields,
; each of which is a byte of max, a byte of length, and a (max) bytes
; of data. they are:
;	dev	device spec 	(2 bytes)
;	name	file name	(8 bytes)
;	ext	file type	(3 bytes)
;
; equates for pathname descriptor block
;
pnd.fl  =	0		; flags byte
pnd.dm	=	1		; dev max, 1 byte
pnd.ds	=	2		; dev size, one byte
pnd.dt	=	3		; dev text, two bytes
pnd.nm	=	5		; name max, 1 byte
pnd.ns	=	6		; name size, 1 byte
pnd.nt	=	7		; name text, 8 bytes
pnd.em	=	15		; ext max
pnd.es	=	16
pnd.et	=	17
pndsiz	=	20		; total size
;
; generic component equates
;
pnc.m	=	0		; max this component
pnc.s	=	1		; size this component
pnc.t	=	2		; text this component
;
; bits in flag byte
;
pnf.dp	=	$01		; dev spec present
pnf.np	=	$02		; name present
pnf.ep	=	$04		; type present
pnf.wl	=	$08		; wild card somewhere
;
; if we had macros, the macro for building one of these would
; look like this:
;
;	.byte	0		; flags
;	.byte	2		; dev max
;	.byte	0
;	.blkb	2
;	.byte	8		; name max
;	.byte	0
;	.blkb	8
;	.byte	3
;	.byte	0
;	.blkb	3
;
; pointers
;
spc2	=	*
	*=	zpc1

pnptr	.blkb	2	; string ptr
pndptr	.blkb	2	; pathname struct
pnddef	.blkb	2	; default
pncptr	.blkb	2	; pathname component

zpc2	=	*
	*=	spc2
;
ppnt0:	.byte	0		; temp for parse-pathname and friends
ppnt1:	.byte	0
ppnt2:	.byte	0
;
;	pncupc:		char-upcase char in A
;
pncupc:
	cmp	#'a		; >= 'a ?
	bcc	pncupc9		; nope, leave
	cmp	#'z+1		; < 'z?
	bcs	pncupc9		; nope, leave
	sec
	sbc	#$20		; shift to up case.  (carry's set)
pncupc9:
	rts
;
;	pnclgl:		char in a legal pathname char?
;			returns carry set if not legal
;
pnclgl:
	cmp	#':		; colon's ok
	beq	pnclgl9
	cmp	#'.		; dot's ok too
	beq	pnclgl9
	cmp	#'*		; star is ok
	beq	pnclgl9
	cmp	#'?		; q-mark is ok
	beq	pnclgl9
	cmp	#'0		; 0..9 is ok
	bcc	pnclgl8		;  less, no good
	cmp	#'9+1
	bcc	pnclgl9		; less, ok
	cmp	#'A		; alpha?
	bcc	pnclgl8		; less is no good
	cmp	#'Z+1
	bcc	pnclgl9		; A..Z's ok
pnclgl8:
	sec			; error return
	rts
pnclgl9:
	clc			; ok return
	rts
;
;	pnfindc:	find a character, in x, in (pnptr), starting
;			at y.  returns idx or -1 in y, EQ if found, NEQ
;			if not found.  Trashes A
;
pnfindc:
	stx	ppnt1		; save char
pnfindc1:
	lda	(pnptr),y	; get a char
	beq	pnfindc8	; 0? ok, stop here
	jsr	pncupc		; upcase it
	jsr	pnclgl		; legal pathname char?
	bcs	pnfindc8	; nope, go error
	cmp	ppnt1		; compare it
	beq	pnfindc9	; got it, return
	iny			; next!
	bne	pnfindc1
pnfindc8:
	ldy	#-1		; return 'not found'
pnfindc9:
	rts
;
;	parsepn::
;	grok a pathname string into a pathname descriptor.
;	expects pathname string pointed to by x,y, desc in (pndptr).
;	pathname string terminated by any non-pathname char.
;
; this routine copies in one component.  Initial idx in Y, terminating
; character in X, component offset in desc in A
;
;ppndbg1: .byte	"Enter parsepn",ATEOL,0
;ppndbg2: .byte	"Leave parsepn",ATEOL,0
ppnct:	.byte	0		; terminator char
ppncf:	.byte	0		; flags for pathname we're parsing
ppncpf:	.byte	0		; flag to set in component we're on
ppncomp:
	stx	ppnct		; save terminator
	clc			; first calculate 
	adc	pndptr		;  pointer to pathname
	sta	pncptr		;  component
	lda	pndptr+1
	adc	#0
	sta	pncptr+1
ppncp1:
	lda	(pnptr),y	; get a char
; below?	iny			; and bump the string idx
	beq	ppncp9		; always terminate on nuls
	cmp	ppnct		; hit terminator?
	beq	ppncp8		; yes, stop this component
	cmp	#ATEOL		; eol?
	beq	ppncp9		; yes, always terminate on eols, too
	cmp	#space		; space?
	beq	ppncp9		; yes, always terminate on spaces, too
	iny			; and bump the string idx
	jsr	pncupc		; upcase it
	jsr	pnclgl		; legal char?
	bcs	ppncp9		; nope, stop here
	cmp	#'*		; is it one of the wild chars?
	beq	ppncp2		; yes, flag it as such
	cmp	#'?
	bne	ppncp3
ppncp2:
	pha			; save char
	lda	#pnf.wl		; or in the 'wild' flag
	ora	ppncf
	sta	ppncf
	pla			; get char back
ppncp3:
	sty	ppnt0		; save y for a bit
	pha			; save char
	ldy	#pnc.s		; component size offset
	lda	(pncptr),y	; get component size
; check size
	ldy	#pnc.m		; component max
	cmp	(pncptr),y	; compare size to max
	bcs	ppncp6		; too big! ignore this byte
	ldy	#pnc.s		; idx for size again
;
	pha			; save size for later indexing
	clc			; add one to it for
	adc	#1		;  next time
	sta	(pncptr),y	; put it back
	pla			; get the old size (index) back
	clc			; zap carry again, and
	adc	#pnc.t		;  add dev text offset
	tay			; into y
	pla			; get char back
	sta	(pncptr),y	; stuff into dev text
	lda	ppncpf		; or in the flag corresponding to 
	ora	ppncf		;  this component
	sta	ppncf
	jmp	ppncp7		; and go back for more
ppncp6:
	pla			; throw char away
ppncp7:
	ldy	ppnt0		; get string idx back
	jmp	ppncp1
ppncp8:
;
; found terminator.  Skip it.
	iny
	clc			; tell caller we saw it
	rts
;
ppncp9:
	sec			; tell caller we didn't see it
	rts
;
;	The main routine of the pathname parser.
;
parsepn:
	stx	pnptr		; set string pointer lo
	sty	pnptr+1		;  and hi
;zzz debug
;	ldx	#ppndbg1\
;	ldy	#ppndbg1^
;	jsr	pstrnul
;zzz
	lda	#0		; first zap len flds in desc
	sta	ppncf		; and flags in progress
	ldy	#pnd.ds		; dev size
	sta	(pndptr),y	; zap
	ldy	#pnd.ns
	sta	(pndptr),y
	ldy	#pnd.es
	sta	(pndptr),y
	ldy	#0		; idx into name string
ppndev:
	ldx	#':		; do we have a colon?
	jsr	pnfindc
	bmi	ppndev9		; nope, skip this part
	lda	#pnf.dp		; flag to set if we do it
	sta	ppncpf
	ldy	#0		; start at zero please
	lda	#pnd.dm		; do device component
	jsr	ppncomp
	jmp	ppnnam		; go do the name
ppndev9:
	ldy	#0		; reset string ptr
ppnnam:
	lda	#pnf.np		; flag to set if we do it
	sta	ppncpf
	lda	#pnd.nm		; do name component
	ldx	#'.		; stop at dot
				; y's already set
	jsr	ppncomp
;
; rather a kludge.  If see a dot, always say
; ext present, even if no ext text
;
	bcs	ppnext
	lda	#pnf.ep
	ora	ppncf
	sta	ppncf
ppnext:
	lda	#pnf.ep		; flag to set if we do it
	sta	ppncpf
	lda	#pnd.em		; extension, please
	ldx	#ATEOL		; sort of irrelevant, as we'll stop
				;  on any illegal char.
	jsr	ppncomp		; y's already set.
	lda	ppncf		; now put in accumulated flags
	ldy	#pnd.fl
	sta	(pndptr),y
;zzz debug
;	ldx	#ppndbg2\
;	ldy	#ppndbg2^
;	jsr	pstrnul
;zzz
	rts			; done!
;
;	pn2str:		(parsed) pathname to string.
;			expects a pathname descriptor in (pndptr)
;			and a string in X,Y.  Generates a namestring
;			terminated by ATEOL, suitable for passing to
;			CIO.  Note that it wants a fully qualified
;			parsed pathname.
;ppndbg3: .byte	"Enter pn2str",ATEOL,0
;ppndbg4: .byte	"Leave pn2str",ATEOL,0
;
; this pushes one byte into output string
;
pn2sp:
	sty	ppnt2		; save y value for a bit
	ldy	ppnt0		; get string idx
	sta	(pnptr),y	; shove the char
;zzz debug
;	pha			; save a
;	txa			; save x
;	pha
;	lda	(pnptr),y	; get char back
;	pha
;	lda	#'|
;	jsr	prchr
;	pla
;	jsr	prchr
;	pla
;	tax
;	pla
;zzz
	inc	ppnt0		; bump the str idx
	ldy	ppnt2		; get y back
	rts
;
; copy one component into outgoing string.
; y contains offset into desc for component text, x contains size
;
pn2scs:
	lda	(pndptr),y	; get a char
	jsr	pn2sp		; stuff it
	iny			; bump dev text idx
	dex			; dec size
	bne	pn2scs		; back for more
	rts
;
; this inits regs, given an initial offset into the descriptor.
; returns Z if length 0.
;
pn2sin:
	lda	(pndptr),y	; get the component size
;zzz debug
;	pha
;	tya
;	pha
;	lda	#'#
;	jsr	prchr
;	pla			; y val
;	pha
;	jsr	prbyte
;	pla
;	pha
;	tay
;	lda	(pndptr),y
;	jsr	prbyte
;	pla
;	tay
;	pla
;zzz	
	iny			; point y at text
	tax			; save it as a counter, set Z for return
	rts
;
;	the main routine
;
pn2str:
	stx	pnptr		; set pathname string lo
	sty	pnptr+1		;  and hi
;zzz debug
;	ldx	#ppndbg3\
;	ldy	#ppndbg3^
;	jsr	pstrnul
;	lda	pnptr+1
;	jsr	prbyte
;	lda	pnptr
;	jsr	prbyte
;zzz
	ldy	#0		; string idx
	sty	ppnt0
	ldy	#pnd.ds		; dev component size
	jsr	pn2sin		; set up regs
	beq	pn2str1		; No dev???  ok, skip it
	jsr	pn2scs		; copy a string
	lda	#':		; get a colon
	jsr	pn2sp		; push it in
;
pn2str1:
	ldy	#pnd.ns		; name component size
	jsr	pn2sin		; set up
	beq	pn2str2		; zero length name?? this should error ...
	jsr	pn2scs		; copy it in
;
pn2str2:
	lda	#'.		; get a dot
	jsr	pn2sp		; push it in
;
	ldy	#pnd.es		; name component size
	jsr	pn2sin
	beq	pn2str3		; zero length ext?
	jsr	pn2scs		; copy it in
pn2str3:
	lda	#ATEOL		; get an eol
	jsr	pn2sp		; push it in
;zzz debug
;	ldx	#ppndbg4\
;	ldy	#ppndbg4^
;	jsr	pstrnul
;zzz
	rts			; done!!!
;
;	pnmerge::	Merge two pathnames.  Move components from the
;			first into missing components of the second, ie
;		merge "D1:FOO.BAR","CRUD.BAZ" -> "D1:CRUD.BAZ"
;
;	wants pnddef pointing at pn1, pndptr at pn2
;
pnmflg:	.byte	0		; flag byte for which comp we're doing
pnmc:
	sta	pnmflg		; store component mask
	ldx	#0		; idx for flags byte
	lda	(pndptr,x)	; get flags
	and	pnmflg		; target path have this component?
	bne	pnmc9		; if there, skip
	lda	(pndptr),y	; get component size in target pathname
	bne	pnmc9		; nonzero, try next
	lda	(pnddef,x)	; get flags for default pn
	and	pnmflg		; and with mask
	beq	pnmc9		; if not there, skip component
	lda	(pnddef),y	; ok, get the one we're merging from
	beq	pnmc9		; this one zero too?? ok, skip it
	tax			; get size in x
	inx			; inc to include size byte
pnmc1:
	lda	(pnddef),y	; get a byte
	sta	(pndptr),y	; put it in target
	iny			; bump component ptr
	dex			; dec count
	bne	pnmc1		; round again
pnmc9:
	rts			; done with this component

;ppndbg5: .byte	"Enter pnmerge",ATEOL,0
;ppndbg6: .byte	"Leave pnmerge",ATEOL,0

pnmerge:
;zzz debug
;	ldx	#ppndbg5\
;	ldy	#ppndbg5^
;	jsr	pstrnul
;zzz
	lda	#pnf.dp		; device flag
	ldy	#pnd.ds		; look at dev component size
	jsr	pnmc		; merge this component
	lda	#pnf.np		; device flag
	ldy	#pnd.ns		; do name
	jsr	pnmc		;  ...
	lda	#pnf.ep		; device flag
	ldy	#pnd.es		; and extension
	jsr	pnmc
pnmzzz:
	ldy	#pnd.fl		; merge flags flds
	lda	(pnddef),y
	ora	(pndptr),y
	sta	(pndptr),y
;zzz debug
;	ldx	#ppndbg6\
;	ldy	#ppndbg6^
;	jsr	pstrnul
;zzz
	rts			; done!	
;
;
;-----------------------------------------------------------------
;
cmdidx:	.byte	0	; idx into cmd line
LINELEN: .byte	0
LINEIDX: .byte	0
LINE:	.blkb	256
;
cmdmax	=	60	; command line max
cmdbuf	.blkb	cmdmax
cmddone: .byte	0	; if command line already processed
;
done:	.byte	0	; time to exit flag
;
iname:	.blkb	32	; input file name
oname:	.blkb	32	; output file name
idname:	.byte	"D1:FOO.UUE",ateol	; input default
defdrv	=	idname+1
odname:	.byte	"FOO.COM",ateol	; output default
fpn:	.byte	0,2,0,"  ",8,0,"        ",3,0,"   " ; pathname from file
ipn:	.byte	0,2,0,"  ",8,0,"        ",3,0,"   " ; input pathame
opn:	.byte	0,2,0,"  ",8,0,"        ",3,0,"   " ; output pathname
dpn:	.byte	0,2,0,"  ",8,0,"        ",3,0,"   " ; default pathname
;
;
; .PAGE "Utils"
;
FLUSHBIN
	PHA
	LDA	BINEMPTY
	BNE	FLUSHB99
	LDX	#outf
	LDA	#binbuf&$FF
	LDY	#binbuf/256
	JSR	SETBUF
	LDY	BINSIZE+1
	LDA	BINSIZE
	JSR	SETLEN
	LDA	#CPBINR
	JSR	IOCMD
FLUSHB99
	LDA	#1		; say we're empty
	STA	BINEMPTY	
	LDA	#0		; say current size 
	STA	BINSIZE		; is zero
	STA	BINSIZE+1
;
	lda	#BINBUF\	; set ptr to beginning
	sta	binp		; of buf
	lda	#BINBUF^
	sta	binp+1
;
	PLA			; get A back
	RTS
;
GENBYTE
;
; Stuff it in out buf
;
	PHA
	LDA	BINSIZE+1
	CMP	#BINMAX/256	; buffer full?
;	BCC	GENB1A
	bne	GENB1A
GENBF
	JSR	FLUSHBIN
GENB1A
	PLA
	LDY	#0
	sta	(binp),y
;
; count and sum it
;
	clc
	adc	chksum
	sta	chksum
	lda	chksum+1
	adc	#0
	sta	chksum+1
	inc	nbytes
	bne	genb1b
	inc	nbytes+1
	bne	genb1b
	inc	nbytes+2
genb1b:	
	LDA	#0
	STA	BINEMPTY
	INC	BINSIZE
	BNE	GENB1C
	INC	BINSIZE+1
GENB1C:
	INC	binp
	bne	GENB1D
	inc	binp+1
GENB1D:
	RTS
;
; x,Y points to pathname
;
GETFNAME
	stx	pndptr
	sty	pndptr+1
;
; zap the pathname
;
	lda	#0
	ldy	#pnd.fl
	sta	(pndptr),y
	ldy	#pnd.ds
	sta	(pndptr),y
	ldy	#pnd.ns
	sta	(pndptr),y
	ldy	#pnd.es
	sta	(pndptr),y
;
	ldy	cmdidx		; get cmd line idx
;
; y points to pathname
;
	lda	(cmdptr),y
	cmp	#ateol		; eol?
	beq	getf9		; yup, stop
	sty	cmdidx		; for next time
	tya
	clc
	adc	cmdptr
	tax			; lo byte
	lda	cmdptr+1
	adc	#0		; get carry
	tay			; points to namestring now
	jsr	parsepn		; parse it
	jsr	pnmerge
;
; now skip this one.  This is sort of gross...
;
	ldy	cmdidx
getf1:
	lda	(cmdptr),y	; find a space
	cmp	#ateol
	beq	getf3
	cmp	#space
	beq	getf2
	iny
	jmp	getf1
getf2:
	iny			; skip it
	lda	(cmdptr),y
	cmp	#ateol
	beq	getf3
	cmp	#space
	beq	getf2
;
getf3:
	sty	cmdidx
	clc			; say we win
	rts
getf9:
	sty	cmdidx
	jsr	pnmerge		; merge defaults anyway
	sec			; say we lose
	rts
;
; IOCB in X, addr hi in Y, lo in A
;
SETBUF
	STA	ICBADR,X
	TYA
	STA	ICBADR+1,X
	RTS
SETLEN
	STA	ICBLEN,X
	TYA
	STA	ICBLEN+1,X
	RTS
SETAUX
	STA	ICAUX1,X
	TYA
	STA	ICAUX2,X
	RTS
;
; IO command in A
;
IOCMD
	STA	ICCOM,X
	JSR	CIO
	LDA	ICSTA,X
	RTS
;
; A,Y point to name
;
OPENF
	JSR	SETBUF
	LDA	#COPN
	JMP	IOCMD
OPENIN
	PHA
	TYA
	PHA
	LDA	#OPIN
	LDY	#0
	JSR	SETAUX
	PLA
	TAY
	PLA
	JMP	OPENF
OPENOUT
	PHA
	TYA
	PHA
	LDA	#OPOUT
	LDY	#0
	JSR	SETAUX
	PLA
	TAY
	PLA
	JMP	OPENF
;
;
READLINE
	LDX	#INF
	LDY	#LINE/256
	LDA	#LINE&$FF
	JSR	SETBUF
	LDA	#255
	LDY	#0
	JSR	SETLEN
	LDA	#CGTXTR
	JSR	IOCMD
	cpy	#0		; status?
	bmi	readerr		; lose, die
	PHA
;
; debug
;
;	ldx	#line\
;	ldy	#line^
;	jsr	dbgstre
;;
RDL2
	PLA
	clc
	RTS
readerr:
	tya
	pha
	ldx	#rdemsg\
	ldy	#rdemsg^
	jsr	dbgstr
	pla
	jsr	dbghex
	jsr	dbgeol
	sec
	rts
rdemsg:	.byte	ATEOL,"Read error ",0
;
; getcmd: get a pointer to command line.  
; Leave cmdidx pointing at
; first non-blank in the command line.
;
getcmd:
;
; first try to guess what OS we're running under.
; Use the algorithm suggested by Dick Curzon.
; Look thru $0A.  Should see a jmp, another jmp,
; and something that's not a jump.
;
	ldy	#0
	lda	($0A),y
	cmp	#$4C		; a jmp?
	bne	getnxl		; nope
	ldy	#3
	lda	($0A),y
	cmp	#$4C		; a jmp?
	bne	getnxl		; nope
	ldy	#6
	lda	($0A),y
	cmp	#$4C		; a jmp?
	bne	getcxl		; nope, that means xl
;
; note that the above test will be passed by
; Spartados too, which means we'll die horribly.
; Someone should come up with a better test...
;
getnxl:
;
; not xl; just prompt for it
;
	jmp	ncmd	
getcxl:
	lda	cmddone		; we already do this one?
	bne	ncmd		; yup, don't do it again
;
; get default drive from dos xl, and stuff into our default drive
;
	ldy	#cpdfdv+1	; idx for drive num
	lda	(cpaloc),y	; get the digit
	sta	defdrv		; stuff it in ours	
;
; get command line from DOS XL
;
	lda	cpaloc
	sta	cmdptr
	lda	cpaloc+1
	sta	cmdptr+1
	LDY	#CPBUFP
	LDA	(CPALOC),Y
	CLC
	ADC	#CPCMDB
	sta	cmdidx
;
; say we've processed this command line.
;
	lda	#1
	sta	cmddone
;
; we got one from cmd line; set done 
; flag so we'll exit after we're done
;
;	lda	#1
	sta	done
	jsr	cmdsk		; skip spaces
	bcs	ncmd		; none? ok, prompt
	rts			; return his codes
;
; no command line, prompt for one
;
prompt:	.byte	"YAU>",0
ncmd:
	ldx	#prompt\
	ldy	#prompt^
	jsr	dbgstr
	ldx	#0		; e: iocb
	lda	#cmdbuf\
	ldy	#cmdbuf^
	jsr	setbuf
	lda	#cmdmax\
	ldy	#cmdmax^
	jsr	setlen
	lda	#CGTXTR		; get rec
	jsr	iocmd
	cpy	#0		; win?
	bpl	ncmd1		; yes, go do it
	jmp	cmderr
ncmd1:
	lda	#cmdbuf\
	sta	cmdptr
	lda	#cmdbuf^
	sta	cmdptr+1
	ldy	#0
	sty	cmdidx
	lda	icblen,x	; get low order len
	beq	cmderr		; if zero len cmd, exit
	lda	#0		; if get here, not done
	sta	done
	jsr	cmdsk		; skip spaces
	bcs	cmderr		; if none, say error
	rts			; return his flags
;
cmderr:
	inc	done
	sec
	rts
;
cmdsk:
;
; skip spaces
;
	ldy	cmdidx
cmds1:
	lda	(cmdptr),y	; get one
	cmp	#ateol		; none??
	beq	cmds3		; ok, prompt
	cmp	#space		; sp?
	bne	cmds2		; nope, stop
	iny
	jmp	cmds1
cmds2:
	sty	cmdidx
	clc
	rts
cmds3:	sty	cmdidx
	sec
	rts
;
;
; match: see if string in (x,y) matches stuff in LINE
;
match:
	stx	strptr
	sty	strptr+1
	ldy	#0
m1:
	lda	(strptr),y	; get a byte
	beq	m2		; end of string?
	cmp	line,y		; look like what's in line?
	bne	m9		; no match
	iny
	jmp	m1
m2:
	clc			; say we won
	rts
m9:
	sec			; say we lost
	rts
;
; find the 'begin ' line
;
begtxt:	.byte	"begin ",0
endtxt: .byte	"end",0
beginp:
	lda	#fpn\		; set path ptr
	sta	pndptr		;  in case we
	lda	#fpn^		;  find one
	sta	pndptr+1
;
	ldx	#begtxt\
	ldy	#begtxt^
	jsr	match
	bcc	beg1		; match? ok, go do pathname stuff
	rts			; say we lost
beg1:
;
; Y points at first char after 'begin '
;
	lda	line,y		; find non-blank
	cmp	#ATEOL		; eol???
	beq	beg9		; yup, quit
	cmp	#space		; sp?
	bne	beg2
	iny
	jmp	beg1
beg2:
;
; find a blank
;
	iny
	lda	line,y
	cmp	#ateol
	beq	beg9
	cmp	#space
	bne	beg2
beg3:
;
; find a non-blank
;
	iny
	lda	line,y
	cmp	#ateol
	beq	beg9
	cmp	#space
	beq	beg3
;
; ok, pointing at pathname
;
	clc
	tya
	adc	#line\
	tax
	lda	#line^
	adc	#0
	tay
	jsr	parsepn
;
; look at the pathname we got back.  if it's got
; anything in it, set name and type field bits,
; to keep from having things spuriously merged in later.
;
	lda	fpn+pnd.fl	; get flags byte
	and	#pnf.np|pnf.ep	; either name or ext?
	beq	beg9
	lda	#pnf.np|pnf.ep	; ok, set both
	sta	fpn+pnd.fl
beg9:
 	clc
	rts
;
; return next byte from line; barf if eol.
; starting idx in y
;
nextb:
	lda	line,y
	beq	nextbn	; nul?
	cmp	#ATEOL	; end of line???
	beq	nextbe	; that's an error
	iny		; bump idx
	rts		; and return the char
nextbe:
	tya
	pha
	ldx	#shlerr\
	ldy	#shlerr^
	jsr	dbgstr	; bitch
	pla
	tay
	lda	#0
	sta	line,y	; so we only bitch once
nextbn:	lda	#$20	; return a space
	rts
shlerr:	.byte	"Bogus line!  UUE file is bad.",ATEOL,0
;
; process a line
;
ltxt:	.byte	0,0,0,0	; text bytes this line
lbin:	.byte	0,0,0	; binary bytes this line
lbc:	.byte	0	; bin count this 
bytec:	.byte	0	; temp
eatline:
	lda	line	; get size byte
	sec
	sbc	#$20	; uncharacterify
	sta	lbc	; save it
	lda	#1	; start line data
	sta	lineidx	;  at 1
uud1:
	lda	lbc	; any remaining here?
	bne	uud2
	jmp	uud9
uud2:
	ldy	lineidx	; get line idx into y
	ldx	#4	; get next 4
	stx	bytec
	ldx	#0
uud3:
;	lda	line,y	; get a uu char
	jsr	nextb
	sec
	sbc	#$20	; unchar it
	and	#$3F	; mask, for sanity check
	sta	ltxt,x	; shove it in hold area
;	iny
	inx
	dec	bytec
	bne	uud3
	sty	lineidx	; save idx for next time
;
; guts of uudecode
;
	lda	ltxt	; get byte 0
	asl	a
	asl	a	; shift left 2
	sta	lbin	; store top 6 bits
	lda	ltxt+1	; get byte 1
	lsr	a	; shift right 
	lsr	a	;  by 4,
	lsr	a	;  leaving 
	lsr	a	;  two bits
	ora	lbin	; OR with 6 from before
	sta	lbin	; making the first whole byte!
;
	lda	ltxt+1	; get byte 1 again
	asl	a	; shift left
	asl	a	;  by 4, 
	asl	a	;  leaving
	asl	a	;  top 4
	sta	lbin+1	; save temporarily
	lda	ltxt+2	; get byte 2
	lsr	a	; shift right 2,
	lsr	a	;  leaving bottom 4
	ora	lbin+1	; OR em in
	sta	lbin+1	; and save em
;
	lda	ltxt+2	; get byte 2
	asl	a	; shift left 6,
	asl	a	;  leaving top 2
	asl	a
	asl	a
	asl	a
	asl	a
	ora	ltxt+3	; or with last byte
	sta	lbin+2	; done!
;
; now, that wasn't so hard, was it?
;
	lda	lbin	; get a byte
	jsr	genbyte	; shove it out
	dec	lbc	; dec line byte count
	beq	uud9	; done with line?
	lda	lbin+1	; get a byte
	jsr	genbyte	; shove it out
	dec	lbc	; dec line byte count
	beq	uud9	; done with line?
	lda	lbin+2	; get a byte
	jsr	genbyte	; shove it out
	dec	lbc	; dec line byte count
	beq	uud9	; done with line?
	jmp	uud1	; around again
uud9:
	rts
;
closef:
	LDX	#INF
	LDA	#CCLOSE
	JSR	IOCMD
	LDx	#outf
	LDA	#CCLOSE
	JSR	IOCMD
	rts
;
; commentary
;
amuse1: .byte	"Yow! ",0
amuse2: .byte	" -> ",0
START:
;
	lda	#0	; zap counts etc
	sta	chksum
	sta	chksum+1
	sta	nbytes
	sta	nbytes+1
	sta	nbytes+2
;
	lda	#1
	sta	done	; getcmd will clr it if cmd
	jsr	getcmd
	bcc	start1
	jmp	exit
start1:
	lda	#dpn\
	sta	pndptr
	lda	#dpn^
	sta	pndptr+1
	ldx	#idname\
	ldy	#idname^
	jsr	parsepn		; parse the default pathname
	lda	#dpn\
	sta	pnddef
	lda	#dpn^
	sta	pnddef+1
;
	LDY	#ipn/256
	LDx	#ipn&$FF
	JSR	GETFNAME
	ldx	#iname\
	ldy	#iname^
	jsr	pn2str
;
; Open the source file
;
	LDX	#inf
	LDY	#iname/256
	LDA	#iname&$FF
	JSR	OPENin
	cpy	#1		; win?
	beq	main1
	tya
	pha
	ldx	#err1\
	ldy	#err1^
	jsr	dbgstr
	pla
	jsr	dbghex
	jsr	dbgeol
	jmp	finish
err1:	.byte	"Open error on infile: ",0
main1:
;
; find the begin
;
findb:
	jsr	readline
	bcc	findb1		; got one
	ldx	#nobtxt\
	ldy	#nobtxt^
	jsr	dbgstr
	jmp	finish
nobtxt:	.byte	"No 'begin ' found",ATEOL,0
findb1:
	jsr	beginp		; try to parse 'begin ...'
	bcs	findb		; nope, try again
;
; now do target path.  beginp parsed fpn for us.
;
	lda	#dpn\
	sta	pndptr
	lda	#dpn^
	sta	pndptr+1
	ldx	#odname\
	ldy	#odname^
	jsr	parsepn		; parse the default pathname
;
	lda	#fpn\		; use fpn for defaults
	sta	pnddef
	lda	#fpn^
	sta	pnddef+1
;
	LDY	#opn/256
	LDx	#opn&$FF
	JSR	GETFNAME
;
	lda	#dpn\		; use dpn for defaults
	sta	pnddef
	lda	#dpn^
	sta	pnddef+1
	jsr	pnmerge
;
	lda	#ipn\		; and merge in ipn
	sta	pnddef		; in case no device
	lda	#ipn^		; specified
	sta	pnddef+1
	jsr	pnmerge
;
	ldx	#oname\
	ldy	#oname^
	jsr	pn2str
;
; say what we're doing
;
	ldx	#amuse1\
	ldy	#amuse1^
	jsr	dbgstr
	ldx	#iname\
	ldy	#iname^
	jsr	dbgstre
	ldx	#amuse2\
	ldy	#amuse2^
	jsr	dbgstr
	ldx	#oname\
	ldy	#oname^
	jsr	dbgstre
	jsr	dbgeol
;
; Open the bin file
;
	LDX	#outf
	LDY	#oname/256
	LDA	#oname&$FF
	JSR	OPENOUT
	cpy	#1		; win?
	beq	main2
	tya
	pha
	ldx	#err2\
	ldy	#err2^
	jsr	dbgstr
	pla
	jsr	dbghex
	jsr	dbgeol
	jmp	finish
err2:	.byte	"Open error on outfile: ",0
;
main2:
	LDA	#1
	STA	BINEMPTY	; nothing in bin buf
	jsr	FLUSHBIN	; init ptrs etc
;
; Read til eof.
;
MAINLOOP
	JSR	READLINE
	bcs	badeof		; couldn't get line?
	ldx	#endtxt\	; see end?
	ldy	#endtxt^
	jsr	match
	bcc	cleanup
	JSR	EATLINE
	jmp	mainloop
bctxt:	.byte	"Byte count = ",0
cktxt:	.byte	"Checksum = #x",0
eoftxt:	.byte	"Unexpected EOF!",ATEOL,0
badeof:
	ldx	#eoftxt\
	ldy	#eoftxt^
	jsr	dbgstr	
cleanup:
	jsr	flushbin
	jsr	closef	; close em
;
; display byte count etc
;
	ldx	#bctxt\
	ldy	#bctxt^
	jsr	dbgstr
;	lda	nbytes+2
;	jsr	dbghex
;	lda	nbytes+1
;	jsr	dbghex
;	lda	nbytes
;	jsr	dbghex
;
; do it in decimal.  what a pain
;
;
; rather a kludge here.  We need to make an fp
; 256, then use it to get top byte in.
;
	lda	#1		; 256^
	sta	fr0+1
	lda	#0
	sta	fr0
	jsr	ifp
	jsr	fmove		; move fr0 -> fr1
	lda	nbytes+2	; top byte
	sta	fr0+1
	lda	#0
	sta	fr0
	jsr	ifp		; make that a float
	jsr	fmul		; mult em together
	jsr	fmove		; move result back to fr1
;
	lda	nbytes		; lo order
	sta	fr0
	lda	nbytes+1	; mid order
	sta	fr0+1
	jsr	ifp		; make a float
	jsr	fadd		; add top byte
	jsr	fasc
	ldy	#0
dec1:
	lda	(inbuff),y
	pha
	and	#$7F
	jsr	dbgchr
	iny
	pla
	cmp	#0
	bpl	dec1
;
	jsr	dbgeol
	ldx	#cktxt\
	ldy	#cktxt^
	jsr	dbgstr
	lda	chksum+1
	jsr	dbghex
	lda	chksum
	jsr	dbghex
	jsr	dbgeol
finish:
	jsr	closef	; close em
;
; unless done flag, go back for more commands
;
	lda	done
	bne	exit
	jmp	start
exit:
;
; make dead sure they're closed
;
	jsr	closef
;
; All done!
;
	RTS
 *=GOADR
	.word	START
; .END
; 
