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!