        name    UUENCODE
        page    55,132
        title   'UUENCODE.ASM'
;
; UUENCODE.ASM -- UUEncodes a Binary File
;
; Cmd line processing, general layout from UU.ASM by Theodore A. Kaldis
;
;Author:  David Kirschbaum
;         Toad Hall
;         kirschd@sesi.com
;Released to Public Domain
;
; To assemble and link this program into the executable UUENCODE.COM:
; (It will NOT run compiled as an .EXE program!)

;               MASM UUE;
;               LINK UUE;
;               (If you just have EXE2BIN:
;                 EXE2BIN UUE
;                 REN UUE.BIN UUENCODE.COM (or whatever)
;               (If you have Public Domain EXE2COM or equivalent:
;                 EXE2COM UUE
;                 REN UUE.COM UUENCODE.COM (or whatever)
;               (Delete the bogus .OBJ file.)

Comment ~

v2.1, 13 Jan 93
- In a 140,848 byte file, uuencoding adds two zero's to the end.
  That's bad.
  Got a little more clever about detecting when and when not to
  add zeroes.

v2.0, 10 Mar 91

- Keith Petersen says we have to make other "weird" modes work
  in the "begin" line (like "begin 0600 foobar.arc").
  Seems to be working in the uudecode.  No changes required here
  in the uuencode side.
- He also asked for the "no overwrite" protection.  Installed from
  the xxencode code (but only if NOT STDOUT).

- Never did incorporate some tweaks from Germany because they were
  too confused with table-related additions (which was broken in
  the uudecode side of the house).  Incorporating them now with the
  v1.9b comments.

- Keith also found we were doing our "no cmdline entry" handling
  backwards: prompting for a filename, and then showing usage only
  if no filename entry. Reversing that so we show usage, and THEN
  prompt for the filename.  All error msgs are going to STDERR
  (unless it's a "-?" switch, where I'm sending it out via Svc 9,
  to permit redirection).

- Tightened up error messages a bit (to include Svc 9 Int 21H display
  for <DOS 2.2 error msg!), common routines, etc.

- Added "-?" for just help, moved usage and <DOS 2.x msgs to buffer space
  at program end.

v1.9b, 01 Nov 1989 (TapirSoft Gisbert W.Selke)
 - tweaked for speed, or rather, style. No noticeable increase in
   overall speed...
 - fixed a bug with file names starting with a slash (and no other slashes
   in the name) or consisting of one character only (without extension).

v1.9, 29 Jul 89
- Had a strange bug in UUD19.
  In the process of fixing that, took a relook at this code
  and did a little tweaking.
  Toad Hall

v1.8, 5 Jul 89

- Version number bumped to v1.8 (skipping v1.4 thru v1.7)
  just to get in synch with the companion uudecode program.

- Thanks to Karl-L. Noell <NOELL%DWIFH1.BITNET@CUNYVM.CUNY.EDU>
  for two bug reports:
    1 - Target filename prompt bug:

|  When I call up UUE12 or UUD17 without filename, a prompt appears:
|  Input path/file:
|  but answering to that prompt always yields the message
|  "Input file error."

  Dumb error, fixed.

    2 - Excessive uuencoded line length at the 45000-byte input point:

|  There is one effect, but it doesn't cause any harm:
|  when I uuencode large binary files, the resulting *.UUE always has
|  line 1001 3 bytes longer as you'll see from the following cut:

|  Line
|   1000:  M!)(0A")3S,<EVET'2%/THAT7@AOB$0AIY[+*1@)6S(I<)",-ZPD(\J`JAWPH
|   1001:  P1SJAV\VFJ+/YP6:,0$$!-Q]T0J?D3%2F<XHO2V>&.=RN#%OYP!:<(H8\P$9*F"E#
|   1002:  M%UA5L3N,TR%C\*86_8E$%!#4(E(JYY.BA$XSJ-.2`72G;K82@GDBQ9YEP"=S

|  Obviously it has to do with your "READSIZE 45000" which is reached in
|  that line (1000 lines * 45 bytes).  Anyway the UUDECODE works fine, I've
|  tried it with your UUD12 and with UUDECODE 2.14 .  The byte count 'P'
|  (instead of 'M') tells us, that there are 3 bytes more in this line.

  Karl-L was right .. I should've checked to see if we had a full line
  (60 chars) of uuencoded bytes BEFORE we check if our binary buffer's
  been used up.  That'll insure the full line gets written out as soon
  as it becomes full.

  The fix seems to be working fine, testing with various odd sized files
  (to include monster ones that insure that 45000-byte refill).

  Added a little logo at the end (overrun by buffers) just to identify
  the program.

~

;v1.3, 9 Nov 88
; - Tightening again.
;   BP holds binary character count throughout each line uuencoding.
;   Tightened uuencoding algorithm itself (fewer shifts & register shuffling).
; - Bumping prompted input filename input to 80 chars.
; - Different (faster) way of testing:
;     (1) if we've hit end of the binary read buffer.
;     (2) if we've completed 60 uuencoded output characters.
; - Changing READSIZE to a MOD 3 so we lessen problems from reading
;   non-MOD 3 numbers of binary characters (until the LAST read).
;   This (and other fixes) finally fixed the problem with 'non-MOD 3'
;   sized binary files adding bogus uuencoded bytes to the end.
; - Found (and fixed) new bug: one junk byte sneaking in after a binary
;   buffer refill from file read.  (Problem was uuencoded buffer overlying
;   binary buffer.)
;
;v1.1, 7 Sep 88
; - Provisional compilation .. Set STDOUT to 1 to enable redirection.
;   Else it'll use the default "filename.uue" format.
; - Fixed bug in filename parsing (need to find the SECOND '\' when
;   stripping paths!

;v1.0, 6 Sep 88
;Hacked together from Kaldis' UU.ASM, the public domain UUENCODE.C,
; UUENCODE.PAS, etc.
;Uses same algorithm (kinda) as the Turbo Pascal UUENCODE.PAS (not the
;C version which does too much bit fiddling).
;
; - The last few uuencoded characters are coming out different from the
;   products of UUENCODE.PAS and my Unix mainframe's uuencode.  (Actually,
;   they're ALL different!)  Doesn't seem to matter:  .ARC files, when
;   uuencoded and then uudecoded again, still check out.  Might bite us
;   somewhere, but haven't had any problems in lots of tests.
;
; David Kirschbaum
; Toad Hall
; kirsch@braggvax.ARPA

;-------------------------------------------
LF              EQU     10
CR              EQU     13
FALSE           equ     0
TRUE            equ     NOT FALSE

READSIZE        EQU     45000           ;max bytes for a binary file read.
                                        ;Small enough to fit within our
                                        ; 64Kb code/data space.
                                        ;Size must be an even divisor of 3.

LINELEN         EQU     60              ;nr chars in a uuencoded line

STDOUT          EQU     0               ;change to non-0 to enable redirection

Cseg    SEGMENT PARA PUBLIC 'CODE'
        ASSUME  CS:Cseg,DS:Cseg, ES:Cseg

        org     80H                     ;PSP cmdline start              v1.8
cmd_tail        label   byte            ;v1.8

        org     100H

UuEncode        PROC    near
        jmp     Start                   ;jump over data

pr_inp          DB      CR,LF,'Input path/file:  '
PR_INP_LEN      EQU     $-pr_inp

err_inp         DB      'Input file error.'
ERR_INP_LEN     EQU     $-err_inp

err_out         DB      'Output file error.'
ERR_OUT_LEN     EQU     $-err_out

end_msg         DB      '`',CR,LF,'end',CR,LF
END_MSG_LEN     EQU     $-end_msg

no_action       db      'No action'                                     ;v2.0
NO_ACTION_LEN   EQU     $-no_action                                     ;v2.0

exist$          db      ' exists!  Aborting!'                           ;v2.0
EXIST$_LEN      equ     $-exist$                                        ;v2.0

inp_handle      DW      0               ;input file handle
out_handle      DW      1               ;output file handle (default StdOut)
read_count      DW      data_buf        ;nr binary bytes read
last_flag       db      FALSE           ;set true when partial read
overwrite       db      FALSE           ;set true if "-o" cmdline switch v2.0

;-------------------------------------------

Start:
; Insure we're DOS 2.0 or above (or handles won't work!)
        mov     ah,30h                  ;get DOS version
        int     21h
        cmp     al,2                    ;2.0 or above?
        jae     Chk_Cmd                 ;yep, ok

         mov    dx,OFFSET msg_v1        ;'DOS 2.0 or above'
         jmp    Msg9_Term               ;display, terminate (AL=1)      v2.0

Msg_Die:
        call    Say_Error               ;write to StdErr, AH unchanged  v2.0
        jmp     Terminate               ;terminate                      v2.0

;-------------------------------------------
;Check our PSP command line for a target filename.
Chk_Cmd:

;v1.8   Moved command line parsing to a separate subroutine
;       (since we may have to do it twice)

        call    Parse_CmdLine           ;parse PSP cmdline              v1.8
        jnc     Open_Inp_Fil            ;we have input                  v1.8
                                        ;(already AsciiZed)             v1.8
                                        ;DI -> AsciiZ 0                 v1.8

;v1.8   No PSP cmdline input.
;       Let's prompt our user:
;v2.0   But first show usage.

        mov     dx,offset usage$        ;'Usage..'                      v2.0
        mov     cx,USAGE_LEN            ;msg length                     v2.0
        call    Say_Error               ;display to STDERR              v2.0

        mov     dx,OFFSET pr_inp        ;'Input/file name:' prompt
        mov     cx,PR_INP_LEN           ;nr chars to display
        mov     bx,2                    ;STDERR
        mov     ah,40H                  ;write to file/device           v2.0
        int     21H

;Get user's kbd input
;v1.8   via regular DOS buffered keyboard input call

        mov     di,offset cmd_tail-1    ;1 byte before PSP cmdline      v1.8
        mov     byte ptr [di],80        ;tell DOS max of 80 chars       v1.8
        mov     dx,di                   ;DX -> buffer                   v1.8
        mov     ah,0AH                  ;buffered kbd input svc         v1.8
        int     21H
        call    Parse_CmdLine           ;parse the input
        jnc     Open_Inp_Fil            ;got input (already AsciiZed)
                                        ;try to open
                                        ;DI -> AsciiZ 0

;v2.0   No user entry at all.  Error msg, die.

        mov     ah,1                    ;ERRORLEVEL 1                   v2.0
        mov     dx,offset no_action     ;'No action'                    v2.0
        mov     cx,NO_ACTION_LEN        ;msg length                     v2.0
        jmp     Msg_Die                 ;display, terminate             v2.0

;We have an input filename.  Open it.

Open_Inp_Fil:
        mov     dx,offset inp_fil       ;input filename buffer
        mov     si,dx                   ;remember input filename
                                        ;buff start
        mov     ax,3D00h                ;open file
        int     21h
        jnb     Inp_Open                ;went ok
         jmp    Inp_Err                 ;input file open error, die

;-------------------------------------------
Inp_Open:
        mov     inp_handle,ax           ;save input file handle

;Take input file name (up to file separator) (no paths)
;move "filename.typ" into our uuencoded buffer and write to file.
;First scan for any paths, drives, etc.
;SI -> input filename buffer start
;DI -> the last filename char+1, so we can compute length.

        mov     cx,di                   ;last char+1
        sub     cx,si                   ;-start = nr chars+1            v2.0
        dec     di                      ;adjust to end of string

;We'll start at the end and scan back toward the front.
;Remember, scasb decrements DI even if it finds the scan char,
;so we'll have to adjust after the find.

        mov     al,'\'                  ;first scan for paths
        std                             ;going backwards
        repne   scasb
        cld                             ;set back forward again
        jz      Found_Path              ;DI points to char before '\'
        mov     di,si                   ;back to start
        cmp     byte ptr [di+1],':'     ;how about a drive?
        jne     Name_Start              ;nope, use buffer start
                                        ;else fall thru and bump di past 'd:'

;DI's now pointing at the REAL target file name starting char
;(past the drive, paths, etc.)
;We first move the original target file name into our uue buffer
;(which is initialized with the "start 644 " characters).
;This uue buffer will be written as the first line of our uuencoded file.

Found_Path:
        inc     di                      ;adjust for scasb or 'd:'
        inc     di
Name_Start:
        mov     si,di                   ;move from input name start
        mov     dx,si                   ;save starting point a sec
        mov     di,offset uue_filename  ;move to within uue buffer
OutName_Loop:
        lodsb                           ;snarf each char
        or      al,al                   ;0 means filename end
        jz      OutName_Done            ;done
        stosb                           ;stuff filename char
        jmp     OutName_Loop            ;keep going

OutName_Done:
        mov     ax,0A0DH                ;get CR/LF
        stosw                           ;stuff it in uuencode buffer

;target file name has now been moved into a starting uuencoded file
;text line (to include CR/LF).

        IF      STDOUT                  ;use StdOut redirection
        mov     cx,di                   ;ptr to last filename char +1
        ELSE                            ;create 'filename.uue'

        push    di                      ;remember that ending psn

;Now to create our output file name: filename.uue

        mov     si,dx                   ;SI is PSP target filename start
        mov     di,offset out_fil       ;move to output file name buffer
        mov     dx,di                   ;we'll need it here also
Uue_Name_Loop:
        lodsb                           ;snarf each char
        or      al,al                   ;0 means filename end
        jne     Check_Dot               ;nope
         mov    al,'.'                  ;no file type, so fake it
Check_Dot:
        stosb                           ;stuff name char into output name
        cmp     al,'.'                  ;go up to separator
        jne     Uue_Name_Loop           ;not yet
;We've now moved the file name (plus the '.') into our output buffer.
;Time for the type
        mov     ax,'uu'                 ;'uue'
        stosw                           ;stuff
        mov     ax,'e'                  ;'e', DOS AsciiZ terminator
        mov     [di],ax                 ;stuff

;DX has output filename starting ofs.
;ptr to last byte in uue buffer is on the stack.
        xor     cx,cx                   ;normal file attrib (R/W)

;v2.0   User asked for output file overwrite protection.
;       Ok .. let's check for output filename existence
;       before we create it.
;       DX -> AsciiZ filename

        cmp     overwrite,TRUE          ;'-o' cmdline switch?
        jz      Out_Create              ;that's right, overwrite if exists

        mov     ah,4EH                  ;find first
        int     21H
        cmp     al,2                    ;file not found?
        jz      Out_Create              ;fine, create it
        cmp     al,18                   ;no more files to be found?
        jz      Out_Create              ;fine, create it

;File exists, so we'll message and abort.

        pop     cx                      ;clear stack
        mov     cx,di                   ;last char in output name
        sub     cx,dx                   ;last -first = length
        mov     bx,2                    ;STDERR
        add     cx,bx                   ;adjust count
        mov     ah,40H                  ;write to file/device
        int     21H
        mov     dx,offset exist$        ;' exists!  Aborting!'
        mov     cx,EXIST$_LEN           ;msg length
        mov     al,5                    ;fake "Access denied" errorlevel
        jmp     Msg_Die                 ;display, terminate

Out_Create:
        mov     ah,3CH                  ;create file
        int     21H
        pop     cx                      ;restore uue ptr into CX
        jnb     Create_Ok               ;ok
         jmp    Out_Err                 ;'Output file error', die

Create_Ok:
        mov     out_handle,ax           ;save output handle

ENDIF                                   ;StdOut or filename.uue

        mov     dx,offset uue_out       ;'start 644 filename.typ', CR/LF
        sub     cx,dx                   ;last char-buff start = bytes to write
        call    Write_File              ;write that record

;Write_File set DI to offset uue_out+1,BP=0

;v1.9b New Code
Read_Loop:
        CALL    Read_File               ;do the initial binary read
        jz      Write_Uue_End           ;nothing read, done with input

        mov     cl,6                    ;handy constant                 v1.9b

;Read_File set SI to offset data_buf, didn't touch DI output buffer ptr,
;or BP binary byte counter.

Uue_Loop:
;SI and BP are incrementing as we uuencode 45 bytes of binary data
;into 60 bytes of 'ready to Asciify' data.

        lodsb                           ;hunk[1]
        mov     ah,al                   ;AH, AL=hunk[1]
        shr     al,1                    ;quad[1] = hunk[1] SHR 2
        shr     al,1                    ;(faster this way)
        stosb                           ;= quad[1], stuff

        lodsb                           ;AL=hunk[2]
        mov     dl,al                   ;save hunk[2] a sec
        shr     ax,1                    ;combine low 2 bits of hunk[1]  v1.9b
        shr     ax,1                    ;and high 4 bits of hunk[2]     v1.9b
        shr     ax,1                    ;(4 single shifts are still     v1.9b
        shr     ax,1                    ;faster than one shift by CL)   v1.9b
        stosb                           ;= quad[2], stuff

        mov     ah,dl                   ;AH=orig hunk[2]
        lodsb                           ;AL=hunk[3]
        mov     dl,al                   ;save hunk[3] in DL a sec
        shr     ax,cl                   ;hunk[2] SHL 2 OR hunk[3] SHR 6 v1.9b
        stosb                           ;= quad[3], stuff

        mov     al,dl                   ;AL=orig hunk[3]
        stosb                           ;= quad[4], stuff

;That 3-byte hunk is done.  See if our binary buffer's empty.
;Notice we ALWAYS assume we did all 3 binary bytes.
;If we didn't (e.g., had a non-MOD 3 nr of binary bytes in our file),
;we'll correct that later with an adjustment to the binary counter
;character in the uuencoded line.

        add     bp,3                    ;+3

;v1.8   Trying to work around that "extra 4 chars"
;       written to output at the 45000-byte buffer end.
;       To do this, we first check to see if our uuencoded output line
;       is full yet (e.g., 45 binary bytes read, 64 uuencoded chars
;       ready to be output):

;v2.1 Bug!  If we've actually lodsb'ed more binary characters
; than there were in the file, BP would still be incorrect (reading
; too large!).  We dare not do that file write until we've checked for
; file end, last read, etc.
IFDEF OLD_CODE  ;v2.1
        cmp     bp,45                   ;done a line of binary data yet? v1.8
        jnz     Chk_BuffEnd             ;nope                           v1.8
         call   Write_Uue               ;stuff binary count in record,  v1.8
                                        ;Asciify entire record,
                                        ;append CR/LF, write to file
                                        ;Reset BP binary counter=0,
                                        ;DI back to output buffer start +1
        mov     cl, 6                   ;restore handy constant         v1.9b

Chk_BuffEnd:                            ;                               v1.8
        cmp     si,read_count           ;hit data end yet?
        jb      Uue_Loop                ;nope,not yet                   v1.8
                                        ;keep uuencoding input buffer   v1.8

        cmp     last_flag,1             ;Was last read the binary file EOF?
        jne     Read_Loop               ;nope, do another read, maybe end.

ELSE    ;v2.1
        cmp     si,read_count           ;hit data end yet?
        jb      Not_Buff_End            ;nope, not yet
         cmp    last_flag,0             ;Was last read the binary file EOF?
         jnz    Write_Uue_End           ;yep, uuencoding is done

Not_Buff_End:                           ;v2.1

;v2.1 We're not at the end of the last binary buffer read,
;so it's safe to write out a uuencoded line.
;BP in fact reflects the number of binary bytes encoded.

        cmp     bp,45                   ;done a line of binary data yet?
        jnz     Chk_BuffEnd             ;nope
         call   Write_Uue               ;stuff binary count in record,
                                        ;Asciify entire record,
                                        ;append CR/LF, write to file
                                        ;Reset BP binary counter=0,
                                        ;DI back to output buffer start +1
        mov     cl, 6                   ;restore handy constant         v1.9b

Chk_BuffEnd:
        cmp     si,read_count           ;hit data end yet?
        jb      Uue_Loop                ;nope,not yet                   v1.8
                                        ;keep uuencoding input buffer   v1.8
        cmp     last_flag,0             ;Was last read the binary file EOF?
        jz      Read_Loop               ;nope, do another read, maybe end.
ENDIF

;-------------------------------------------
Write_Uue_End:
        or      bp,bp                   ;any bytes uuencoded?
        jz      No_Partial_Write        ;none, so no trailing to write

;In converting 3 binary bytes to 4 quad chars, we may have bumped SI
;beyond the actual number of binary bytes read.
;By subtracting the original count of bytes read from SI,
;we'll get the number of 'bogus' binary bytes in that last quad.
;Subtract that from the BP binary counter, and we'll get the TRUE
;number of binary bytes in that uuencoded line.
;It's up to the uudecoding program to catch that difference
;and ignore the extra quads.  (The ones I've tested seem to.)

         sub    si,read_count           ;check for overrun
         sub    bp,si                   ;subtract any bogus bytes
         call   Write_Uue               ;write partial line

No_Partial_Write:
        mov     dx,offset end_msg       ;'end',CR/LF
        mov     cx,END_MSG_LEN          ;nr bytes to move
        call    Write_File              ;do the last write

;DOS closes open files at termination.
;However, just to be neat:

IF      NOT STDOUT                      ;no StdOut
        mov     bx,out_handle           ;output file handle
        mov     ah,3EH                  ;close the file
        int     21H
ENDIF

Terminate:
        mov     ah,4Ch                  ;terminate, ERRORLEVEL ?
        int     21h

;v2.0   Enter here for a msg display via svc 9, Int 21H
;       (msg address in DX)
Msg9_Term:
        push    ax                      ;save errorlevel
        mov     ah,9
        int     21H
        pop     ax                      ;restore
        jmp     Terminate

UuEncode        endp

;-------------------------------------------

Write_Uue       PROC    NEAR
;Enter with DI pointing to char beyond last uuencoded char.
;Stuff CR/LF, compute line length, write to file.

;v1.9   push    si                      ;save input ptr a sec
        MOV     DX,offset uue_out       ;output line start (length byte)
        mov     cx,di                   ;current output pointer
        sub     cx,dx                   ;- buffer start = nr bytes in line
                                        ;+1, but that's ok since we're adding
                                        ;the line_len byte
        push    cx                      ;save full line length for later
;Do the last masking of the line of quads
;v1.9   mov     si,dx                   ;point to line start for 'from'
        mov     di,dx                   ;moving to same place
        mov     ax,bp                   ;binary bytes in this line
;v1.9   mov     [si],al                 ;stuff binary length byte
        mov     [di],al                 ;stuff binary length byte       v1.9
                                        ; (uuencode later)
        mov     ah,20H                  ;get a handy constant

;Gotta process every byte, masking, checking for spaces, etc.
;This includes that length byte.
        mov     bx,(3FH SHL 8) + 96     ;get another handy constant
                                        ;BH=3FH, BL=96
Mask_Loop:
;       lodsb                           ;get output line char
        mov     al,[di]                 ;get output line char           v1.9
        and     al,bh   ;3FH            ;six-bit mask
        add     al,ah                   ;plus asciifying offset
        cmp     al,ah                   ;end up with a space
        jne     Not_Space               ;nope
         mov    al,bl   ;96             ;use space substitute "`"
Not_Space:
        stosb                           ;stuff it back in line buffer
        loop    Mask_Loop               ;do them all

        pop     cx                      ;restore char count for bytes to write
;DI now points at char just beyond uuencoded char line
        mov     ax,0A0DH                ;Get CR/LF
        mov     [di],ax                 ;stuff them in buffer
        inc     cx                      ;add in CR/LF to length
        inc     cx
;v1.9   pop     si                      ;restore SI

Write_File:
        MOV     BX,out_handle           ;output file handle
        MOV     AH,40h                  ;write to file/device
        INT     21h
        jb      Out_Err                 ;write error
         mov    di,dx                   ;point DI back to uue_out start
         inc    di                      ;bump past length byte
         xor    bp,bp                   ;reset byte ctr
         RET                            ;write done

;Output file write error
Out_Err:
        MOV     DX,OFFSET err_out       ;'Output file error'
        MOV     CX,ERR_OUT_LEN          ;msg length
        jmp     short Fatal_Error       ;common code

Write_Uue       ENDP

;-------------------------------------------
;Read a chunk of raw binary data
Read_File       PROC    NEAR
        MOV     DX,offset data_buf      ;into binary input buffer
        mov     cx,READSIZE             ;nr bytes to read
        MOV     BX,inp_handle           ;input file handle
        MOV     AH,3Fh                  ;read from file/device
        INT     21h
        jb      Inp_Err                 ;failed

;AX has nr of bytes read
        mov     si,dx                   ;SI needs offset data_buf
        mov     bx,dx                   ;buffer start
        add     bx,ax                   ;+bytes read = data end

;BX points to the next 'empty' byte (data_buf start + bytes read)

        cmp     ax,cx                   ;read a full buffer?
        je      Read_Full               ;yep, no fiddling required

;We've read less than a buffer full.  Let's make sure the last bytes
;are nulls if bytes read are not MOD 3.
        mov     word ptr [bx],0         ;stuff 2 nulls there
        mov     last_flag,1             ;turn EOF flag on

Read_Full:
        mov     read_count,bx           ;point to data end
        or      ax,ax                   ;set flags for return
        RET                             ;read done

;-------------------------------------------
;Input file read error.  Error value in AL
Inp_Err:
        MOV     DX,OFFSET err_inp       ;'Input file error'
        MOV     CX,ERR_INP_LEN          ;msg length
;Common code added here
Fatal_Error:
        call    Say_Error               ;display error msg, AL unchanged v2.0
        jmp     Terminate               ;terminate                      v2.0

Read_File       ENDP

;-------------------------------------------
Say_Error       proc    near
;DX -> error msg
;CX = msg len

        push    ax                      ;save AX                        v2.0

        push    dx                      ;msg address                    v2.0
        push    cx                      ;msg length
        mov     dx,offset crlf          ;precede msgs w/CRLF
        mov     cx,CRLF_LEN             ;length
        call    ErrOut                  ;display it

        pop     cx                      ;restore
        pop     dx                      ; original error msg
        call    ErrOut                  ;display it

        mov     dx,offset crlf          ;precede msgs w/CRLF
        mov     cx,CRLF_LEN             ;length
        call    ErrOut                  ;display it

        pop     ax                      ;restore AX (error level maybe)
        ret

ErrOut: mov     bx,2                    ;Std ErrOut handle
        mov     ah,40h                  ;write to file/device
        int     21h
        ret

Say_Error       ENDP

;v1.8 Command line processing subroutine

Parse_CmdLine   proc    near

        MOV     SI,offset cmd_tail      ;move cmd line parm             v1.8
        MOV     DI,offset inp_fil       ;to our filename buffer
        CLD                             ;insure fwd
        LODSB                           ;cmd line length byte
        or      al,al                   ;nothing there?
        jz      PC_NoInput              ;yep, nothing there

        mov     ah,20H                  ;get a handy space
Strip_Ct:
        lodsb                           ;next cmd line char
        cmp     al,ah                   ;gobble leading spaces,tabs, etc.
        jbe     Strip_Ct

;v2.0   Check for a "-o" switch on command line

        cmp     al,'/'                  ;this kind of switch?
        jz      GotSwitch               ;yep
         cmp    al,'-'                  ;switch?
         jnz    NotSwitch               ;nope, must be name char
GotSwitch:
        mov     dx,ax                   ;save this char a second
        mov     ax,[si]                 ;snarf next 2 chars
        cmp     al,'?'                  ;Wants help?                    v2.0
        jz      JustHelp                ;yep, help, die                 v2.0

        and     al,5FH                  ;mask 1st char to uppercase
        cmp     ax,' O'                 ;O and space means switch
        mov     ax,dx                   ;restore in case not
        jnz     NotSwitch               ;nope, must be name

;We have the overwrite switch

        not     overwrite               ;toggle flag to TRUE
        inc     si                      ;bump past 'o'
        inc     si                      ;and past space
        lodsb                           ;next char should be name

Ct_Char:
        cmp     al,ah                   ;ctrl char? (e.g., CR)
        jbe     PC_Input                ;yep, done
NotSwitch:
        stosb                           ;stuff filename byte
        lodsb                           ;snarf next cmdline char
        jmp     Ct_Char                 ;and loop


PC_NoInput:
        stc                             ;no input, return CF set
        ret

PC_Input:
        mov     byte ptr [di],0         ;Asciize filename input
        clc                             ;got input, return CF clear
        ret

;v2.0   New code
JustHelp:
        pop     ax                      ;clear original call to be neat
        mov     dx,offset usage$        ;'Usage:'
        mov     al,1                    ;ERRORLEVEL 1
IF      STDOUT
;With output going to STDOUT, we'd better send usage to STDERR
        mov     cx,USAGE_LEN            ;msg length
        jmp     Fatal_Error             ;display STDERR, terminate
ELSE
        jmp     Msg9_Term               ;display via Svc 9, terminate
ENDIF

Parse_CmdLine   endp


;using pointers here at code end for various buffers.
;the uue_out buffer is normally 60 uuencoded chars, plus CR/LF
;It's initialized with the default uuencode file header.
;No, I don't know the magic in '644'.

                EVEN                    ;v1.2

uue_out         db      'begin 644 '    ;first write contains this + name

;The rest of these buffers don't take any code space.

uue_filename    equ     $               ;where we move filename.uue

;Leave room for LINELEN+2 chars for uue_out buffer.

inp_fil         equ     uue_out  + LINELEN +2   ;80 chars long

;Leave room for 80 chars for inp_fil filename buffer.

out_fil         equ     inp_fil + 80    ;15 bytes long

data_buf        equ     out_fil         ;leave room for uue_out

logo    db      'UUENCODE v2.1',0               ;v2.1
        db      'David P Kirschbaum, Toad Hall, '
        db      'Given to the public domain',0

IF      STDOUT
usage$          db      'UUENCODE [d:][\path\]binary.fil [>output] <RETURN>'
                db      CR,LF,'(Uses redirection)'
ELSE
usage$  db      'UUENCODE [-o] [d:][\path\]binary.fil <RETURN>',CR,LF
        db      'produces binary.UUE on current drive\path',CR,LF
        db      '(providing binary.UUE doesn''t already exist).',CR,LF  ;v2.0
        db      '-o switch forces overwrite of existing binary.UUE'     ;v2.0

ENDIF
USAGE_LEN       equ     $-usage$                                ;v2.0
                db      CR,LF,'$'       ;for Svc 9 display      v2.0

msg_v1          DB      'This program requires DOS V2.0 or higher.'
crlf            db      CR,LF                                   ;v2.0
CRLF_LEN        EQU     $-crlf                                  ;v2.0
                db      '$'             ;Svc 9 display only     v2.0

Cseg    ENDS
        END     UuEncode
