;.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 ;