[net.micro.atari16] UUDECODE program enclosed; ignores absent trailing blanks

MOEWS@UCONNVM.BITNET (09/09/86)

    There's been a lot of UUENCODEd stuff on INFO-ATARI16 recently.  If you're
on an IBM system running VM/CMS, you will have two problems with raw UUENCODEd
files:

      (1) Trailing blanks will be removed when the files are shipped over
          BITNET.

      (2) Trailing blanks will be removed if you use VM/CMS Kermit to
          transmit the files from VM/CMS to your Atari ST.  (Try it and see!)

I have written a version of UUDECODE that ignores the absence of trailing
blanks in a file to be UUDECODEd; using it, I have been able to decode most
of the UUENCODEd stuff that has been posted this summer.

     The program is written in assembly language and as a result is much
faster than, for example, the UUENCODE distributed in Franco's starter kit.
It can be assembled with the public domain assembler, AS68, which can be found
in Franco's starter kit or on the Atari BBS.  This assembler does not assemble
register shifts, so all the register shifts in the code have been commented
out and hand-assembled to dc.w's.

             David Moews               MOEWS@UCONNVM.BITNET
---------------cut here----------------
* UUDECODE a file.  Copyright (C) 1986 by David Moews.
* Permission to use and redistribute for non-commercial purposes granted.
*  ... print an explanatory message ...
pfile   pea     openm
        move.w  #pline, -(a7)
        trap    #1
        addq.l  #6, a7
* ... get the line ...
        lea     buffer, a1
        move.l  #blen, d2
        bsr     getln
* Open file!
        clr.w   -(a7)           Open for reading
        pea     buffer
        move.w  #fopen, -(a7)
        trap    #1
        addq.l  #8, a7
* Check for error...
        tst.w   d0
        bmi     error
        move.w  d0, d1          Save handle number
* Skip over first 10 characters ('begin xxx ')
        clr.w   -(a7)
        move.w  d1, -(a7)
        move.l  #10, -(a7)
        move.w  #lseek, -(a7)
        trap    #1
        add.l   #10, a7
        tst.l   d0
        bmi     erroro
* Initialize I/O pointers
        bsr     init
* Get filename (terminated with CR/LF)
        lea     buf2, a1
gfloop  bsr     getch
        cmp.b   #$0d, d7
        beq     gfdone
        move.b  d7, (a1)+
        bra     gfloop
gfdone  clr.b   (a1)
        bsr     getch           Discard $0a
*
* Open file!
*
        clr.w   -(a7)           R/W file will be created
        pea     buf2
        move.w  #fcreat, -(a7)
        trap    #1
        addq.l  #8, a7
* Check for error...
        tst.w   d0
        bmi     erroro
        move.w  d0, d2          Save handle number
* ... now the fun begins ...
* GEM uses a0; input buffer pointers a2-a3; output ptrs a4-a5; stack ptr a7
* GEM uses d0; d3=byte count in this line; d4=byte count in this 4-character
* group -or- char count while reading;
*  d5=group of 4 characters -or- 3 bytes.
* Scratch in d7.
*
* LINE LOOP
*
* Get count.  If 0, we are done.
loop    bsr     getnn
        sub.b   #$20, d7        Subtract space
        beq     done
* Otherwise, get that many characters.
        clr.w   d3              High byte 0 for "dbf"
        move.b  d7, d3
        subq.w  #1, d3          Correct for "dbf"
        bsr     init3           Reset counters
loop3   bsr     getch3
        bsr     prtch
        dbf     d3, loop3
        bsr     skipnl          Skip over junk + $0d/$0a
        bra     loop
*
*  Initialize state of 3-characters.
*
init3   clr.w   d4
        rts
*
*  Get another character from a group of 3.
*
getch3  tst.w   d4
        bne     get32
* Read in another group of 4 into d3; reset count to 3.
        move.w  #3, d4
        clr.l   d5
*et3l   lsl.l   #6, d5
get3l   dc.w    $ed8d
        bsr     getnn
        sub.b   #$20, d7
        or.b    d7, d5
        dbf     d4, get3l
        move.w  #3, d4          Set byte count
        swap    d5              Pattern from [0123] to [2301]
* Get a character out of d3, decrement count in d2, & return!
get32   move.b  d5, d7
*       rol.l   #8, d5
        dc.w    $e19d
        subq.w  #1, d4
        rts
* Read until we come to a newline; then skip over $0d/$0a.
skipnl  bsr     getch
        cmp.b   #$0d, d7
        bne     skipnl
        bra     getch
*
*  Buffered I/O subroutines.  Input buffer pointer a2, end ptr in a3;
*                             output buffer pointer a4, end prt a5.
*
*  Sets up.
init    lea     inpend, a2
        lea     inpend, a3
        lea     outbuf, a4
        lea     outend, a5
        rts
*  Get a character in d7.b, EXCEPT that if we are at a newline, get a blank
*  instead.
getnn   cmp.l   a3, a2
        bcc     getrn
        cmp.b   #$0d, (a2)
        beq     getsn
        move.b  (a2)+, d7
        rts
getsn   move.b  #$20, d7
        rts
getrn   bsr     getrec
        bra     getnn
*  Gets a character in d7.b.
getch   cmp.l   a3, a2
        bcc     getr
        move.b  (a2)+, d7
        rts
getr    bsr     getrec
        bra     getch
*
* Get a new record into the buffer.
getrec  pea     inpbuf
        move.l  #inplen, -(a7)
        move.w  d1, -(a7)
        move.w  #fread, -(a7)
        trap    #1
        add.l   #12, a7
        tst.l   d0
        bmi     error2
        beq     done            No bytes read, file over, done.
* Actual number of bytes read in d0!
        lea     inpbuf, a2
        lea     0(a2, d0.l), a3
        rts
*
*  Prints byte in d7.b.
prtch   cmp.l   a5, a4
        bcc     putr
        move.b  d7, (a4)+
        rts
putr    bsr     putrec
        bra     prtch
*
* Dump buffer out.
* Compute number of bytes to put out.
putrec  lea     outbuf, a5
        move.l  a5, -(a7)
        sub.l   a5, a4
        move.l  a4, -(a7)
        move.w  d2, -(a7)
        move.w  #fwrite, -(a7)
        trap    #1
        add.l   #12, a7
        tst.l   d0
        bmi     error2
        lea     outbuf, a4
        lea     outend, a5
        rts
*
*
*   We come here in case of error.
error   bsr     pmsg
        bra     xit
* Here for error after opening 1 file.
erroro  bsr     pmsg
        bsr     close1
        bra     xit
* Here for error after opening  2 files.
error2  bsr     pmsg
        bsr     close1
        bsr     close2
        bra     xit
* Here for normal end.  Notice that we flush output buffer.
done    bsr     putrec
        bsr     close1
        bsr     close2
xit     clr.w   -(a7)
        trap    #1
*
pmsg    pea     msg
        move.w  #pline,-(a7)
        trap    #1
        addq.l  #6,a7
        rts
*
close1  move.w  d1, -(a7)
        move.w  #fclose, -(a7)
        trap    #1
        addq.l  #4, a7
        rts
*
close2  move.w  d2, -(a7)
        move.w  #fclose, -(a7)
        trap    #1
        addq.l  #4, a7
        rts
*
*
*
*   This subroutine reads a line of input into the buffer at a1.
*   Maximum buffer length should be passed in d2.  Actual count is
*   returned in d1.  The buffer should have one more byte than d2
*   (to allow for a zero at the end.)
getln   movem.l d0/a0, -(a7)
* Clear char count
        clr.l   d1
glloop  move.w  #conine,-(a7)
        trap    #1
        addq.l  #2, a7
* A BS?
        cmp.b   #$08, d0
        beq     bs
* A CR?
        cmp.b   #$0d, d0
        beq     crret
* Just a plain character ... are we at EOL?
        cmp.l   d1, d2
* Yes, ignore it.
        beq     glloop
*  Otherwise, store it...
        move.b  d0, 0(a1, d1.l)
        addq.l  #1, d1
* ... and echo.
        bsr     echo
        bra     glloop
* A BS --- are we at start of line?
bs      tst.l   d1
*  If so, ignore keystroke.
        beq     glloop
* Otherwise, decrement counter...
        subq.l  #1, d1
* ... print BS, space, BS to wipe out char
        move.b  #$08, d0
        bsr     echo
        move.b  #$20, d0
        bsr     echo
        move.b  #$08, d0
        bsr     echo
        bra     glloop
* A CR --- echo & return.
crret   bsr     echo
        move.b  #$0a, d0
        bsr     echo
        clr.b   0(a1, d1.l)
        movem.l (a7)+, d0/a0
        rts
*
*
*   Echo --- echoes a character in d0 to the screen.  Destroys d0 & a0.
echo    move.w  d0, -(a7)
        move.w  #conout, -(a7)
        trap    #1
        addq.l  #4, a7
        rts
*
*
*
openm   dc.b    'Enter filename to read: '
        dc.b    0
msg     dc.b    'TOS error occurred!', 13, 10
        dc.b    0
buffer  ds.b    51
buf2    ds.b    51
blen    equ     50
* Buffer for reading from file
inpbuf  ds.b    $400
inpend  ds.b    0
inplen  equ     $400
* ... and for writing ...
outbuf  ds.b    $400
outend  ds.b    0
outlen  equ     $400
* Codes for GEMDOS
conout  equ     $02
rawcon  equ     $06
conine  equ     $07
pline   equ     $09
fcreat  equ     $3c
fopen   equ     $3d
fclose  equ     $3e
fread   equ     $3f
fwrite  equ     $40
lseek   equ     $42
        end