jrd@STONY-BROOK.SCRC.SYMBOLICS.COM (John R. Dunning) (10/20/87)
Are you tired of waiting for those old slow C UU en/de coders? Sick of having to reboot your machine to run the BASIC version? Well, your troubles are over. It's a floor wax! It's a desert topping! It's... Hype aside, it's another UUdecoder, with a companion encoder for 8-bitters. They're written in assembler language, so they're pretty fast, and quite small (around 2K bytes per). They know how to run in either command-line mode, ie just like other commands, or in prompting mode, for doing several files at a time, or under things like DOS, that don't do command lines. That's about it. This posting is consists of 5 sections (all in this one message) containing: yau.doc the doc file for both yau and yaue yau.uue uuencoded binary for yau.com yaue.uue " " " yaue.com yau.m65 source for yau.com yaue.m65 " " yaue.com To get them going, use jhs's BASIC uudecoder to decode yau, then use yau to decode itself and yaue, in order to make sure the checksum and byte count values (in the doc) came out right. One request; if anyone comes up with significant enhancements, could you repost them, of at least send them to me? Thanks. Here goes. --------------------------------yau.doc-------------------------------- Yau and Yaue Manual Page 1 Yau and YauE: The last word in Uu en/decoders for Ataris? Introduction: Yau and Yaue were written because I got sick of waiting around for the outrageously slow C versions, and didn't want to constantly be rebooting the machine to get the Basic cart in and out. The re- sult was a hack attack in which I whomped up what's probably about the fastest, and easiest to use (in my opinion) of the UU coders available for Atari 8-bitters. This is NOT a discussion of the UU format; see various cryptic Un*x manuals, or apocryphal stories bandied about the network for more edification. Or, read the code. YAU: Yet Another Uudecoder. Yau is the uudecoder. It takes a UUencoded file and decodes it, yielding the original data. It also dumps the byte count and checksum of the resultant file, as an extra sanity check, for cases where that data about the original file is available. Yau can be run two ways: either from the command line, if you're using DOS XL, or by prompting for its own commands. In either case, the form of the command line to Yau is 'source-file [target-file]' where target file is optional. Examples: If you ARE running DOS XL, you could type: YAU D1:FOO.UUE D1:FOO.COM If you aren't running DOS XL, or you are but didn't give Yau any args when you started it up, it will prompt, as: YAU> ...to which you could answer D1:FOO.UUE D1:FOO.COM If Yau is took its args from a DOS XL command line, it will exit immediately after it runs. If it prompted for its args (regard- less of whether or not you're running DOS XL) it will keep prompt- ing until you feed it an empty line. Yau and Yaue Manual Page 2 Now, all that command stuff may look like a lot of typing, (yes, I know it's what the others make you do, but I thought it was a lot of typing when they did it, too) but it's not as bad as all that. Both source and target file specs are merged against various de- faults, so you need not type them out explicitly. The default source pathname is 'D1:FOO.UUE'; the default target pathname is 'FOO.COM'. The default target pathname is overridden by the name in the 'begin' line of the uue file, so typically you wouldn't type that at all; ie the command line to YAU would just look like: YAU FOO where the 'D1:' and the '.UUE' in the source pathname were de- faulted. (In this, and the examples following, I'll be discussing the commands as you'd type them on the command line of DOS XL; they're exactly the same for other cases, except that you type line when Yau prompts for it, and you just type the args, not the word 'YAU'; it knows what it is) In that case, the target file spec gets read out of the 'begin' line, so if the uue file was originally created from something called 'FOO.COM', it'll use that name. Yau will also merge the target pathname against the source pathname, in order to default the device of the target to the same one as the source. The net result of all this merging is that the above example will do exactly the same thing as 'YAU D1:FOO.UUE D1:FOO.COM', above. It's also easier to deal with the more com- plicated cases; ie you could say YAU FOO D2: to decode a file on D1: to a the resultant file on D2:. You could say YAU FOO BAR to override whatever's in the 'begin' line, and put the result into BAR.COM. Finally, if YAU senses that it's running under DOS XL, it'll inherit the default device spec, so you're not stuck do- ing everything on D1:. (No prizes for guessing what OS I use on my 800). Lastly, in case you're old-fashioned, and don't want your computer outsmarting you behind your back, after all the dust has settled, Yau will tell you what it's doing, as: Yow! D1:SQUZ.UUE -> D1:SQUZ.BIN If you're REALLY old fashioned, and don't think you computer has any business trying to do smart things, don't use YAU and YAUE. Yau and Yaue Manual Page 3 Other tidbits: Yau keeps a byte count and simple 16 bit checksum while it's decoding; when it's done with a file, it will display them, as: Byte count = 2099 Checksum = #x1FC0 The byte count is in decimal, the checksum is in hex; the #x is to remind you that it's hex, in case it's not obvious from the va- lue. The checksum is the running unsigned sum of all the bytes in the resultant file, truncated to 16 bits. Yau tries to minimize disk overhead by buffering up data destined for the target file. The buffer size is 8k, so most files will only require one or two writes, ie you're not constantly seeking the disk head back and forth. If you're using ramdisks, you won't care, but if you've got a real mechanical disk, it'll make a big difference. Yau is pretty good about error checking; it tries to make sure the advertised byte count makes sense for what it finds in each line, tries to make sure there's a legit looking 'end' line etc. It's a bit more lenient about trailing spaces that some other implementations; it never requires them. It will gripe about er- rors as it finds them, and, of course, about IO errors. Yau and Yaue Manual Page 4 YAUE: Yet Another UU Encoder. Yaue is a companion program to Yau. It takes binary files (pro- grams, archives, etc) and encodes them into text suitable for sending through predatory mail systems, etc. Needless to say, things encoded with Yaue can be decoded with Yau. Yaue is run in exactly the same way as Yau; ei you can run it di- rectly from the command line if you're using DOS XL, or just start it up and type things at it when it prompts. (yes, its prompt is 'YAUE>'). Pathname defaulting works in exactly the same way as with Yau; the default pathames are 'D1:FOO.COM' for input and '.UUE' for output. If you're using DOS XL, Yaue will inherit the current default device. One slightly wierd thing about Yaue; there's currently no way to specify a name to go in the 'begin' line other than the name of the file you're starting with, ie if you encode D1:FOO.COM, the begin line will look like begin 666 FOO.COM I thought about making the command line parser smarter, to allow for something like that, and decided it wasn't worth the effort. If you really care what the file claims to be called, edit the UUE or rename the file before you encode it. Other bits: Yaue will dump byte count and checksum values for encoded files, in exactly the same form as Yau does. (Shouldn't come as a com- plete surprise) That way, when you send around uuencoded binaries, you can send the expected byte count and checksum with them. Yaue doesn't go to as great lengths as Yau to avoid disk overhead. I figured that in general the decoder gets run a lot more fre- quently than the encoder, so it was the more important one to op- timize. I may have another hack attack at some point, and put in the buffering stuff. A word of warning for Spartados users: The algorithm used to guess which OS I'm running under is the one suggested by Dick Cur- zon some months ago. Unfortunately, it has the characteristic that it can't distinguish Spartados from DOS XL. What that means is that these things will almost certainly crash horribly when run under Spartados. If someone can tell me how to tell the differ- ence when booting, please do; but until this gets fixed, Sparta- dos users probably can't use these things. Yau and Yaue Manual Page 5 One last word about these guys, If you don't like the names 'YAU' and 'YAUE', you're completely free to rename them, they don't care what their names are. The byte count and checksums for this release are: Yau: 2134. bytes, #x39F2 checksum. Yaue: 1988. bytes, #xE74D checksum. I guess that's about it. Happy coding! --------------------------------yau.uue-------------------------------- begin 666 YAU.COM M__\ , (P3+=7__\#4&Q2 ! (T,4)A(BDBB (JH("55J0N=0@.My M#% @5N1HJFBH8$B&AH2'H "QAO .( U0R-#VYH;0\N:'T.YH8$B&AH2'H "Qy MALF;\ X@#5#(T/3FAM#PYH?0[&A@ $B&AH2'H "QAO .C6-0R+&&( U0SF-0y MT/5H8*F;3 U0 $A*2DI*((Y0:"D/CH10JKVG4" -4*Z$4&"8((50BB"%4& Py M,3(S-#4V-S@Y04)#1$5& R6&0!\E[L ,XZ2!@R3KP'LDN\!K)*O 6R3_Py M$LDPD S).I *R4&0!,E;D (X8!A@CKA0L8CP$""Z4"#&4+ (S;A0\ 7(T.R@y M_V ".!%$898J%CJ6+:0"%C[&(\%S-!%'P5,F;\%/)(/!/R""Z4"#&4+!&y MR2KP!,D_T I(J0@-!5&-!5%HC+=02* !L8Z@ -&.L!R@ 4@8:0&1CF@8:0*Hy M:)&.K091#051C0513&Q1:*RW4$P54<@88#A@AHB$B:D C051H *1BJ &D8J@y M$)&*H "B.B#J4# /J0&-!E&@ *D!( =13*91H "I HT&4:D%HBX@!U&P"*D$y M#051C051J02-!E&I#Z*;( =1K051H "1BF",N5"LMU"1B.ZW4*RY4&"QBB#0y M4<C*T/=@L8K(JF"&B(2)H ",MU"@ B#I4? ((-]1J3H@T%&@!B#I4? #(-]1y MJ2X@T%&@$"#I4? #(-]1J9L@T%%@ (TE4J( H8HM)5+0&;&*T!6AC"TE4O .y ML8SP"JKHL8R1BLC*T/A@J0&@ B F4JD"H 8@)E*I!* 0("92H "QC!&*D8I@y M __^I4ZI3 #__^M3L5E$,3I&3T\N555%FT9/3RY#3TV; ( (" ( " @y M(" @(" @ P @(" @ @( @ (" @(" @(" # " @( " " @" @(" @(" @y M( , (" @ ( (" ( " @(" @(" @ P @("!(K050T!>B(*D#H# @'56L!%"My M U @)56I"R U5:D!C050J0"- U"-!%"I X6"J3"%@VA@2*T$4,D@T ,@3E1Hy MH "1@AAM"5"-"5"M"E!I (T*4.X&4- ([@=0T /N"%"I (T%4.X#4- #[@10y MYH+0 N:#8(:*A(NI * D8J@ I&*H :1BJ 0D8JL:E*Q@,F;\#2,:E*8&&6 y MJJ6!:0"H('=1($Q2K&I2L8#)F_ 3R2#P!,A,]U3(L8#)F_ $R2#P]8QJ4AA@y MC&I2($Q2.&"=1 .8G44#8)U( YB=20-@G4H#F)U+ V"=0@,@5N2]0P-@(!U5y MJ0-,-55(F$BI!* ("U5:*AH3#]52)A(J0B@ " M56BH:$P_5:(0H%*I;2 =y M5:G_H @)56I!2 U5< , 1(:!A@F$BBEJ!5("M0:""%4"!_4#A@FU)E860@y M97)R;W(@ * L0K)3- 0H .Q"LE,T B@!K$*R4S0 TSO5:VI4] LH BQ"HWLy M4Z4*A8"E"X6!H JQ"AAI/XUJ4JD!C:E3C:I3(#16L 9@64%5/@"BZJ!5("M0y MH@"I;:!3(!U5J3R@ " E5:D%(#55P 0 TPO5JEMA8"I4X6!H ",:E*]2 /Py M"ZD C:I3(#16L %@[JI3.&"L:E*Q@,F;\ W)(- $R$PW5HQJ4AA@C&I2.&"&y MA(2%H "QA/ )V6U2T ;(3%56&& X8&)E9VEN( !E;F0 J?Z%BJE3A8NB9J!6y M($]6D %@N6U2R9OP.<D@T 3(3(-6R+EM4LF;\"G)(-#TR+EM4LF;\!W)(/#Ty M&)AI;:JI4FD J"!W4:W^4RD&\ 6I!HW^4QA@N6U2\!;)F_ "R&"82*+CH%8@y M*U!HJ*D F6U2J2!@0F]G=7,@;&EN92$@(%5512!F:6QE(&ES(&)A9"Z; y M *UM4CCI((T)5ZD!C6Q2K0E7T -,G%>L;%*B!(X*5Z( (,56..D@y M*3^= E?HS@I7T.^,;%*M E<*"HT&5ZT#5TI*2DH-!E>-!E>M U<*"@H*C0=7y MK0172DH-!U>-!U>M!%<*"@H*"@H-!5>-"%>M!E<@@E3."5?P&:T'5R""5,X)y M5_ .K0A7(()4S@E7\ -,&5=@HA"I#" U5:(@J0P@-55@66]W(2 ("T^( "Iy M (T)4(T*4(T&4(T'4(T(4*D!C:I3(*-5D -,KEFI.H6*J52%BZ+KH%,@=U&Iy M.H6,J52%C:!4HA(@PE2BJZ!3(.Y1HA"@4ZFK($=5P 'P*IA(HAJ@6" K4&@@y MA5 @?U!,HUE/<&5N(&5R<F]R(&]N(&EN9FEL93H@ "!G59 =HD"@6" K4$RCy M64YO("="14=)3B G(&9O=6YDFP @<5:PV:DZA8JI5(6+HO:@4R!W4:G^A8RIy M4X6-H%2B)B#"5*DZA8RI5(6-($Q2J1*%C*E4A8T@3%*BRZ!3(.Y1HJR@5R Ky M4**KH%,@1E"BLJ!7("M0HLN@4R!&4"!_4*(@H%.IRR!75< !\"N82*+2H%@@y M*U!H((50(']03*-93W!E;B!E<G)O<B!O;B!O=71F:6QE.B J0&-!5 @3E0@y M9U6P/*)MH%8@3U:0.B +5TSR6$)Y=&4@8V]U;G0@/2 0VAE8VMS=6T@/2 Cy M> !5;F5X<&5C=&5D($5/1B&; *(BH%D@*U @3E0@G5>B!J!9("M0J0&%U:D y MA=0@JMD@MMVM"%"%U:D A=0@JMD@V]H@MMVM!E"%U*T'4(75(*K9(&;:(.;8y MH "Q\T@I?R -4,AHR0 0\B!_4*(4H%D@*U"M"E @A5"M"5 @A5 @?U @G5>My 3JE/0 TRW5R"=5V#__^ "X0*W5P y end --------------------------------yaue.uue-------------------------------- begin 666 YAUE.COM M__\ ,'$R3%LW (T),)A(BDBB (JH(.,TJ0N=0@.M"3 @5N1HJFBHy M8$B&AH2'H "QAO .( HPR-#VYH;0\N:'T.YH8$B&AH2'H "QALF;\ X@"C#(y MT/3FAM#PYH?0[&A@ $B&AH2'H "QAO .C6 PR+&&( HPSF PT/5H8*F;3 HPy M $A*2DI*((LP:"D/CH$PJKVD," *,*Z!,&"8(((PBB"",& P,3(S-#4V-S@Yy M04)#1$5& R6&0!\E[L ,XZ2!@R3KP'LDN\!K)*O 6R3_P$LDPD S).I *y MR4&0!,E;D (X8!A@CK4PL8CP$""W,"##,+ (S;4P\ 7(T.R@_V ". 3$8y M98J%CJ6+:0"%C[&(\%S- 3'P5,F;\%/)(/!/R""W,"##,+!&R2KP!,D_T I(y MJ0@- C&- C%HC+0P2* !L8Z@ -&.L!R@ 4@8:0&1CF@8:0*H:)&.K0,Q#0(Qy MC0(Q3&DQ:*RT,$P2,<@88#A@AHB$B:D C0(QH *1BJ &D8J@$)&*H "B.B#Gy M,# /J0&- S&@ *D!( 0Q3*,QH "I HT#,:D%HBX@!#&P"*D$#0(QC0(QJ02-y M S&I#Z*;( 0QK0(QH "1BF",MC"LM#"1B.ZT,*RV,&"QBB#-,<C*T/=@L8K(y MJF"&B(2)H ",M#"@ +&**0'P#Z "(.8Q\ @@W#&I.B#-,: &(.8Q\ ,@W#&Iy M+B#-,: 0(.8Q\ ,@W#&IFR#-,6 C2HRH@"ABBTJ,M 9L8K0%:&,+2HR\ ZQy MC/ *JNBQC)&*R,K0^&"I : "("LRJ0*@!B K,JD$H! @*S*@ +&,$8J1BF y M #__ZXSKS, /__\#,E.40Q.D9/3RY#3TV;+E5519L @ @( @ (" @(" @y M(" # " @( " " @" @(" @(" @( , (" @ ( (" ( " @(" @(" @ P @y M(" K3PTT"JB$*D J"#;-"#C-*D'G4(#(%;D,!#N S#0$NX$,- -[@4P3&XTy MJ0&-/#2I $@8;08PC08PK0<P:0"-!S!H8(:*A(NI * D8J@ I&*H :1BJ 0y MD8JL;S*Q@,F;\#2,;S*8&&6 JJ6!:0"H('0Q(%$RK&\RL8#)F_ 3R2#P!,A,y MM33(L8#)F_ $R2#P]8QO,AA@C&\R(%$R.&"=1 .8G44#8)U( YB=20-@G4H#y MF)U+ V"=0@,@5N2]0P-@(-LTJ0-,\S1(F$BI!* (.LT:*AH3/TT2)A(J0B@y M "#K-&BH:$S]-(JB("#;-*G_H @XS2I"2#S-, , 1(:!A@F$BB4: U("@Py M:""","!\,#A@FU=R:71E(&5R<F]R( "@ +$*R4S0$* #L0K)3- (H :Q"LE,y MT -,K#6MKC/0+: (L0J-\3.E"H6 I0N%@: *L0H8:3^-;S*I 8VN,XVO,R#Qy M-; '8%E!544^ **FH#4@*#"B *ERH#,@VS2I/* (.,TJ04@\S3 ! #3.PUy MJ7*%@*DSA8&@ (QO,KU( _ +J0"-KS,@\36P 6#NKS,X8*QO,K& R9OP#<D@y MT 3(3/0UC&\R&&",;S(X8&)E9VEN(#8V-B @(" @(" @(" @(" @(" @(" @y M()L@FV5N9)NI (6*J32%BZT -"G^C0 THA:@-B#K,: VH@P@)35@ y M J0"-5S:I 8UQ,JD C50VC54VC58V(#TTC50VK3PTT!_N5S8@/32-53:My M/#30$>Y7-B ]-(U6-JT\-- #[E<VK50V2DJ-4#:M539*2DI*C5$VK50V"@H*y M"BDP#5$VC5$VK54V"@HI/(U2-JU6-DI*2DI*2@U2-HU2-JU6-BD_C5,VK'$Ry MK5 V*3\8:2"9<C+(K5$V*3\8:2"9<C+(K5(V*3\8:2"9<C+(K5,V*3\8:2"9y M<C+(C'$RK5<VR2VP"*T\-- #3&,VK5<V&&D@C7(RK'$RJ7F9<C+(J9N9<C*By M<J R("4U&&"B$*D,(/,THB"I#"#S-&!9;W=E92$@ " M/B J0"-!C"-!S"-y M S"-!#"-!3"-/#2I 8VO,R!?-9 #3"(YJ2B%BJDTA8NB\* S('0QJ2B%C*DTy MA8V@-*( (( THK"@,R#K,:(0H#.IL" %-< !\"J82*+!H#<@*#!H(((P('PPy M3!<Y3W!E;B!E<G)O<B!O;B!I;F9I;&4Z( "I*(6*J32%BZ+[H#,@=#&I*(6,y MJ32%C2!1,J THA0@@#2I (6,J32%C2!1,J+0H#,@ZS&B3J W("@PHK"@,R!#y M,*)6H#<@*#"BT* S($,P('PPHB"@,ZG0(!4UP 'P*YA(HDJ@." H,&@@@C @y M?#!,%SE/<&5N(&5R<F]R(&]N(&]U=&9I;&4Z( @,38@63:P0ZT\-/#VHBN@y M-B E-:(MH#8@)35,M#A">71E(&-O=6YT(#T@ $-H96-K<W5M(#T@(W@ 56YEy M>'!E8W1E9"!%3T8AFP"BG* X("@P(#\WHH"@." H,*D!A=6I (74(*K9(+;=y MK04PA=6I (74(*K9(-O:(+;=K0,PA=2M!#"%U2"JV2#FV* L?-(*7\@"C#(y M:,D $/(@?#"BCJ X("@PK0<P(((PK08P(((P('PP(#\WK:\ST -,6S<@/S=@y (___@ N$"6S< y end --------------------------------yau.m65-------------------------------- ;.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 ; --------------------------------yaue.m65-------------------------------- ;.TITLE "YAUE: Yet Another Uu Encoder" ;.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 ; fp + fp 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 ; ; put it back if we decide to do buffering ; ;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.fl ; get flags lda (pndptr),y and #pnf.dp ; device present? beq pn2str1 ; nope, skip it 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.COM",ateol ; input default defdrv = idname+1 odname: .byte ".UUE",ateol ; output default 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 ineof: .byte 0 ; eof on inf ; ; ; .PAGE "Utils" ; getbyte: lda ineof bne getb8 ldx #inf lda #0 tay jsr setbuf jsr setlen lda #CGBINR ; get binary sta iccom,x jsr cio bmi getb7 inc nbytes bne getb9 inc nbytes+1 bne getb9 inc nbytes+2 jmp getb9 getb7: lda #1 sta ineof getb8: lda #0 getb9: pha clc adc chksum sta chksum lda chksum+1 adc #0 sta chksum+1 pla 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 ; ; write the line pointed to by x,y ; wrline: txa LDX #outF JSR SETBUF LDA #255 LDY #0 JSR SETLEN LDA #CPTXTR JSR IOCMD cpy #0 ; status? bmi wrerr ; lose, die PHA ; ; debug ; ; ldx #line\ ; ldy #line^ ; jsr dbgstre ;; wrl2 PLA clc RTS wrerr: tya pha ldx #wremsg\ ldy #wremsg^ jsr dbgstr pla jsr dbghex jsr dbgeol sec rts wremsg: .byte ATEOL,"Write 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 dos xl's default dev ; ldy #cpdfdv+1 lda (cpaloc),y sta defdrv ; ; 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 "YAUE>",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 ; ; write the 'begin ' line ; begtxt: .byte "begin 666 " begfn: .byte " ",ateol endt1: .byte " ",ateol endt2: .byte "end",ateol wrbegin: lda #ipn\ ; set path ptr sta pndptr ; in case we lda #ipn^ ; find one sta pndptr+1 ; ; zap dev flg in ipn, so it won't show up in name ; lda ipn+pnd.fl and #$FF-pnf.dp sta ipn+pnd.fl ldx #begfn\ ldy #begfn^ jsr pn2str ; ; now write it ; LDY #begtxt/256 LDx #begtxt&$FF JSR wrline rts ; ; 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 spitline: lda #0 ; bin count this line sta lbc ; save it lda #1 ; start line data sta lineidx ; at 1 uue1: ; ; get 3 bytes ; lda #0 sta lbin sta lbin+1 sta lbin+2 jsr getbyte sta lbin lda ineof ; out of data? bne uue2 ; yup, don't inc count inc lbc jsr getbyte sta lbin+1 lda ineof ; out of data? bne uue2 ; yup, don't inc count inc lbc jsr getbyte sta lbin+2 lda ineof ; out of data? bne uue2 ; yup, don't inc count inc lbc uue2: ; ; guts of uuencode ; lda lbin ; get first byte lsr a ; shift right lsr a ; by 2 sta ltxt ; for the first byte ; lda lbin+1 ; get the second byte lsr a ; shift right lsr a ; 4 lsr a ; . lsr a ; . sta ltxt+1 ; save here for a sec lda lbin ; get the first one again asl a ; shift left asl a ; 4 asl a ; . asl a ; . and #$30 ; mask the bits we want ora ltxt+1 ; or with top 4 of second byte sta ltxt+1 ; yielding second encoded byte ; lda lbin+1 ; get second bin byte asl a ; shift left 2 asl a and #$3C ; mask 4 bits we're keeping sta ltxt+2 ; save for a sec lda lbin+2 ; get last bin byte lsr a ; shift right 6 lsr a lsr a lsr a lsr a lsr a ora ltxt+2 ; or in last 4 bits sta ltxt+2 ; yielding 3rd encoded ; lda lbin+2 ; get last byte and #$3f ; mask for bottom 6 sta ltxt+3 ; yielding last encoded! ; ; now, that wasn't so hard, was it? ; ldy lineidx ; get line idx lda ltxt and #$3F ; sanity check clc adc #$20 ; make it a char sta line,y ; and store it iny ; lda ltxt+1 and #$3F ; sanity check clc adc #$20 ; make it a char sta line,y ; and store it iny ; lda ltxt+2 and #$3F ; sanity check clc adc #$20 ; make it a char sta line,y ; and store it iny ; lda ltxt+3 and #$3F ; sanity check clc adc #$20 ; make it a char sta line,y ; and store it iny ; sty lineidx ; ; see if time to flush ; lda lbc ; how many in this line? cmp #45 bcs uue8 ; time to flush lda ineof ; eof on inf? bne uue8 ; yup, flush jmp uue1 ; go back for more uue8: lda lbc ; get byte count clc adc #$20 ; make it a char sta line ; save as first byte ldy lineidx ; get line idx lda #'y ; our trademark sta line,y iny lda #ATEOL sta line,y ldx #line\ ldy #line^ jsr wrline ; write it for real clc rts ; closef: LDX #INF LDA #CCLOSE JSR IOCMD LDx #outf LDA #CCLOSE JSR IOCMD rts ; ; commentary ; amuse1: .byte "Yowee! ",0 amuse2: .byte " -> ",0 START: ; lda #0 ; zap counts etc sta chksum sta chksum+1 sta nbytes sta nbytes+1 sta nbytes+2 sta ineof ; 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: ; ; now do target path. ; lda #dpn\ sta pndptr lda #dpn^ sta pndptr+1 ldx #odname\ ldy #odname^ jsr parsepn ; parse the default pathname ; lda #dpn\ ; use dpn for defaults sta pnddef lda #dpn^ sta pnddef+1 jsr pnmerge ; LDY #opn/256 LDx #opn&$FF JSR GETFNAME ; 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 uue 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 ; ; write the begin line ; jsr wrbegin ; ; Read til eof. ; MAINLOOP JSR spitLINE bcs badeof ; couldn't write line? lda ineof ; eof? beq mainloop ; nope, keep going ldx #endt1\ ; write blank line ldy #endt1^ jsr wrline ldx #endt2\ ; write end ldy #endt2^ jsr wrline jmp cleanup ; 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 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 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 ; ---------------------------------------------------------------- That's all!