; --------------------------------------- ;
; LCASE.ASM                               ;
;                                         ;
; Version 1.0                             ;
;                                         ;
; IC v2.0+ Installable Command            ;
;                                         ;
; Convert STDIN to lowercase and send the ;
; results to STDOUT.                      ;
;                                         ;
; Copyright (C) 1992, Geoff Friesen B.Sc. ;
; All rights reserved.                    ;
;                                         ;
; Developed with: Borland TASM 2.5        ;
; --------------------------------------- ;

_TEXT           SEGMENT BYTE PUBLIC 'CODE'
		ASSUME  cs:_TEXT, ds:_TEXT, es:_TEXT, ss:_TEXT
		ORG     100h

CR              EQU     13
LF              EQU     10

CLINE		EQU	10ah
HEXW		EQU	10ch
STDINIT		EQU	10eh

_lcase:
		lea     dx, msg
		mov     ah, 9
		int     21h
		int     20h

msg             DB      "NONCOM$"

code_entry      DW      _code
help_entry      DW      _help
byline_entry    DW      _byline
setup_entry     DW      _setup
cleanup_entry   DW      _cleanup

BUFSIZE		EQU	4000

_okmsg		DB	CR, LF
		DB	"lcase: standard input successfully converted"
		DB	CR, LF
		DB	'$'

_errmsg		DB	CR, LF
		DB	"lcase: I/O error"
		DB	CR, LF
		DB	'$'

_code           PROC    NEAR
		call	cs:[STDINIT]	; Standard initialization.
_code1:
		lea	dx, buffer	; Read standard input.
		mov	cx, BUFSIZE
		mov	bx, 0
		mov	ah, 3fh
		int	21h
		jc	_code4		; Branch on error.

		mov	cx, ax		; Get bytes read count.
		jcxz	_code5		; Branch if finished.

		push	cx
		lea	si, buffer
_code2:
		lodsb			; Scan each byte read.

		cmp	al, 'A'
		jb	_code3

		cmp	al, 'Z'
		ja	_code3

		add	al, 32		; Convert to lowercase.
_code3:
		mov	[si-1], al
		loop	_code2

		pop	cx

		mov	bx, 1		; Write to standard output.
		mov	ah, 40h
		int	21h
		jnc	_code1
_code4:
		lea	dx, _errmsg	; Get error message.
		jmp	SHORT _code6
_code5:
		lea	dx, _okmsg	; Get ok message.
_code6:
		jmp	SHORT stderr	; Display message and exit.
_code           ENDP

; ---------------------------------------------- ;
; STDERR :- Send output string to STDERR device. ;
;           The string is delimited by a '$'.    ;
;                                                ;
; Entry: DX - address of string                  ;
;                                                ;
; All registers preserved.                       ;
; ---------------------------------------------- ;

stderr		PROC	NEAR
		push	ax
		push	bx
		push	cx
		push	si

		xor	cx, cx		; Initialize counter.
		mov	si, dx		; Point to string start.
stderr1:
		lodsb			; Get string character.

		cmp	al, '$'		; Delimiter reached?
		jz	stderr2		; Yes, branch.

		inc	cx		; Advance counter.
		jmp	SHORT stderr1
stderr2:
		mov	bx, 2		; STDERR device handle.
		mov	ah, 40h		; Send string to STDERR device.
		int	21h

		pop	si
		pop	cx
		pop	bx
		pop	ax

		ret
stderr		ENDP

_help           DB      CR, LF
		DB      "LCASE: Convert standard input to lowercase"
		DB      CR, LF
		DB	CR, LF
		DB	"Syntax: LCASE [<infile] [>outfile]"
		DB	CR, LF
		DB	CR, LF
		DB	"The LCASE command reads standard input and"
		DB	CR, LF
		DB	"changes uppercase alphabetic characters to"
		DB	CR, LF
		DB	"lowercase before sending them to standard"
		DB	CR, LF
		DB	"output.  For example, LCASE <C:\CONFIG.SYS"
		DB	CR, LF
		DB	">PRN"
		DB	CR, LF
		DB	'$'

_byline         DB      "LCASE    - convert standard input to lowercase"
		DB      CR, LF
		DB      '$'

smsg		DB	CR, LF
		DB	"lcase: setting up"
		DB	CR, LF
		DB	'$'

_setup          PROC    NEAR
		lea	dx, smsg
		mov	ah, 9
		int	21h

		ret
_setup          ENDP

cmsg		DB	CR, LF
		DB	"lcase: cleaning up"
		DB	CR, LF
		DB	'$'

_cleanup        PROC    NEAR
		lea	dx, cmsg
		mov	ah, 9
		int	21h

		ret
_cleanup        ENDP

buffer		LABEL	BYTE

_TEXT           ENDS
		END     _lcase