[comp.sys.atari.8bit] Yet Another Uudecoder!

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!