	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
