;---------------------------------------------;
;                 Recoder		      ;
; Copyright (c) 1991 by Alexander V. Lukyanov ;
;---------------------------------------------;

	MODEL	TINY

INCLUDE		MACRO.ASI

PUTCH	MACRO	CHR
	MOV	DL,CHR
	MOV	AH,2
	INT	21H
ENDM

EOS	EQU	13
BSIZE	EQU	1000H

	.DATA
TABLE_EXT	DB	'.tbl',0
FILE_EXT	DB	'.txt',0

UNTOOP		DB	'open',0
UNTOCL		DB	'close',0
UNTORE		DB	'read',0
UNTOWR		DB	'write',0
NOTFOU		DB	'find',0

UNABLE		DB	' : unable to ',0
FILEMSG		DB	' file',0

FORREAD		DB	' for reading',13,10,0
FORWRITE	DB	' for writing',13,10,0

BAD_TABLE_MSG	DB	' : too short table, length must be 256'
NL		DB	13,10,0

TITLEMSG DB	13
	DB	"Recoder   Version 1.0  Copyright (c) 1991 by Alexander V. Lukyanov",13,10,0
HELPMSG DB	"  Usage: RECODE tablename filename [ filename... ]",13,10
	DB	"  In filename possibly to use '*' and '?'",13,10,0 

	.CODE

	ORG	80H
RESERV	DB	21 DUP (?)
ATTIB	DB	?
TIME	DW	?
DATE	DW	?
FLEN	DD	?
FNAME	DB	13 DUP (?)

ARGC	DW	?
ARGV	DW	?

	ORG	100H
START:	
	CLD
	MOV	BP,SP		; STACK FRAGMENT
	MOV	SI,81H		; PARAMETERS STRING START
	XOR	BX,BX		; ARGUMENT COUNTER
	
DEL_SPACE:
	LODSB			; GET CHARACTER
DEL_SPACE_1:
	CALL	ISSPACE		; IF IT IS SPACE
	JE	DEL_SPACE	; THEN DELETE IT
	CMP	AL,EOS		; IF END OF STRING
	JE	DONE		; THEN DONE

NEXT_CH:
	MOV	AH,AL		; TO SAVE IN STACK
	PUSH	AX		; SAVE
	INC	SP		; ONE BYTE ONLY
	LODSB			; NEXT CHARACTER
	CALL	ISSPACE		; IF IT IS SPACE
	JE	END_OF_PARAMETER; THEN EOP
	CMP	AL,'/'		; IF IT IS '/'
	JE	END_OF_PARAMETER; THEN EOP
	CMP	AL,EOS		; IF NO END OF STRING
	JNE	NEXT_CH		; THEN CONTINUE
END_OF_PARAMETER:
	INC	BX		; INCREMENT THE ARG COUNTER
	MOV	DH,0		; 0 TO INDICATE EOS
	PUSH	DX		; PUSH IT
	INC	SP		; ONE BYTE ONLY
	JMP	DEL_SPACE_1	; SEARCH NEXT ARGUMENT

DONE:
	MOV	CX,BP		; GET LENGTH OF ARG AREA
	SUB	CX,SP
	MOV	DI,SP		; START OF ARG AREA
	PUSH	SS		; STACK SEGMENT
	POP	ES		; TO 'ES'
	PUSH	BP		; SAVE 'BP'
	PUSH	CX		; SAVE 'CX'
	SHR	CX,1		; DIVIDE BY 2
	JCXZ	DONE_CYCLE
XCHG_AREA:
	MOV	AL,SS:[DI]	; CH FROM BEGIN
	XCHG	AL,[BP-1]	; XCHANGE WITH END
	STOSB			; CH TO BEGIN AND INCREMENT BEGIN PTR
	DEC	BP		; DECREMENT END POINTER
	LOOP	XCHG_AREA
DONE_CYCLE:
	POP	CX		; RESTORE 'CX'
	POP	BP		; RESTORE 'BP'
	JCXZ	DONE_ALL	; IF ARG AREA NOT EXISTS
	MOV	DX,SP		; START OF ARG AREA
	SUB	SP,BX		; SPACE FOR ARRAY OF POINTERS
	SUB	SP,BX		; 1 PTR = 2 BYTES
	MOV	DI,SP		; START OF ARRAY
MAKE:
	MOV	AX,DX		; POINTER
	STOSW			; WRITE IT TO ARRAY
	XCHG	DX,DI		; CURRENT PTR
	MOV	AL,0		; EOS MARKER
	REPNE SCASB		; FIND NEXT STRING START
	XCHG	DX,DI		; RESTORE ARRAY INDEX
	JCXZ	DONE_ALL
	JMP	MAKE

ISSPACE	PROC
	CMP	AL,32
	JE	SPACE
	CMP	AL,9
SPACE:	RET
ISSPACE	ENDP

DONE_ALL:
	PUSH	DS
	POP	ES		; RESTORE 'ES'

	MOV	CX,BX		; int argc;
	MOV	BX,SP		; char **argv;
	
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

	PUSH	BP
	MOV	BP,SP
	SUB	SP,128+256+2+BSIZE+128+4

FILE_NAME	EQU	BYTE PTR [BP-128]
TABLE		EQU	BYTE PTR [BP-128-256]
END_OF_DIR	EQU	WORD PTR [BP-128-256-2]
BUFFER		EQU	BYTE PTR [BP-128-256-2-BSIZE]
CURR_FILE	EQU	BYTE PTR [BP-128-256-2-BSIZE-128]
FLENL		EQU	WORD PTR [BP-128-256-2-BSIZE-128-4]
FLENH		EQU	WORD PTR [BP-128-256-2-BSIZE-128-4]+2

	MOV	ARGC,CX
	MOV	ARGV,BX

	MOV	SI,OFFSET TITLEMSG
	CALL	PRINT

	CMP	CX,2
	NJ B,	HELP

	PUSH	CX

	MOV	SI,[BX]
	LEA	DI,FILE_NAME
	CALL	STRCPY
	MOV	SI,OFFSET TABLE_EXT
	CALL	DEFAULT_EXT
	CALL	READ_TABLE

	POP	CX
	DEC	CX

NEXT_FILE:
	PUSH	CX		; SAVE CX FOR LOOP
	INC	BX		; GET NEXT FILE ** POINTER
	INC	BX
	
	MOV	SI,[BX]		; NEXT FILE
	LEA	DI,CURR_FILE	; COPY ITS NAME
	CALL	STRCPY
	MOV	SI,OFFSET FILE_EXT; MAKE DEFAULT EXT
	CALL	DEFAULT_EXT
	MOV	SI,DI		; COPY NAME WITH THE EXT
	LEA	DI,FILE_NAME	; TO FILE_NAME
	CALL	STRCPY
	CALL	DIRECTORY_END
	MOV	END_OF_DIR,SI	; SAVE FOUND EOD
	
	MOV	DX,DI
	XOR	CX,CX
	MOV	AH,4EH
	INT	21H		; FIND FIRST FILE
	JC	NOT_FOUND_1

REC:	MOV	SI,OFFSET FNAME
	MOV	DI,END_OF_DIR
	CALL	STRCPY		; PUT FILE NAME ON THE END OF DIRECTORY
	
	LEA	SI,FILE_NAME
	CALL	TOLOWERSTR

	CALL	RECODE		; RECODE THE FILE
	MOV	AH,4FH
	INT	21H		; FIND NEXT FILE
	JC	DONESEARCH
	CMP	AX,18
	JNE	REC
DONESEARCH:
	CMP	AX,18
	JE	ENDLOOP
NOT_FOUND_1:
	CALL	NOT_FOUND	; ERROR OF SEARCHING
ENDLOOP:
	POP	CX
	LOOP	NEXT_FILE

NORMAL_EXIT:
	EXIT	0

HELP:
	MOV	SI,OFFSET HELPMSG
	CALL	PRINT
	JMP	SHORT NORMAL_EXIT	; PRINT HELP AND EXIT
	
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;----------------------- MESSAGES ABOUT AN ERRORS -------------------:
UNABLE_TO_OPEN_W:
	CALL	PRUNTOOP
	MOV	SI,OFFSET FORWRITE
	CALL	PRINT
	RETN

UNABLE_TO_OPEN_R:
	CALL	PRUNTOOP
	MOV	SI,OFFSET FORREAD
	CALL	PRINT
	RETN

PRUNTOOP	PROC
	LEA	SI,FILE_NAME
	CALL	TOLOWERSTR
	CALL	PRINT
	MOV	SI,OFFSET UNABLE
	CALL	PRINT
	MOV	SI,OFFSET UNTOOP
	CALL	PRINT
	MOV	SI,OFFSET FILEMSG
	CALL	PRINT
	RET
PRUNTOOP	ENDP

UNABLE_TO_READ:
	MOV	DI,OFFSET UNTORE
	JMP	SHORT PRE

UNABLE_TO_WRITE:
	MOV	DI,OFFSET UNTOWR
	JMP	SHORT PRE

UNABLE_TO_CLOSE:
	MOV	DI,OFFSET UNTOCL
	JMP	SHORT PRE

NOT_FOUND:
	LEA	SI,CURR_FILE
	MOV	DI,OFFSET NOTFOU
	JMP	SHORT PRE1

PRE:	LEA	SI,FILE_NAME
PRE1:	CALL	TOLOWERSTR
	CALL	PRINT
	MOV	SI,OFFSET UNABLE
	CALL	PRINT
	MOV	SI,DI
	CALL	PRINT
	MOV	SI,OFFSET FILEMSG
	CALL	PRINT
	MOV	SI,OFFSET NL
	CALL	PRINT
	RETN

ERROR_EXIT:
	EXIT	1		; TERMINATE WITH ERROR CODE

;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;----------------------- READ TABLE FOR RECODING ---------------------:
READ_TABLE	PROC
	PUSH	BX
	MOV	AX,OFFSET ERROR_EXIT
	PUSH	AX

	LEA	DX,FILE_NAME
	MOV	AX,3D00H
	INT	21H
	JNC	CONT_READ
int 3
	MOV	DI,DX
	CMP	BYTE PTR [DI+1],':'
	JE	UNABLE_TO_OPEN_R
	CALL	STRLEN
	MOV	AL,'\'
	CLD
	REPNE SCASB
	NJ E,	UNABLE_TO_OPEN_R

	MOV	ES,WORD PTR [DS:002CH]	; ENVP
	XOR	DI,DI
	XOR	AX,AX
	MOV	CX,-1
	REPNE SCASW
	NJN E,	UNABLE_TO_OPEN_R
	SCASW
	PUSH	ES
	PUSH	DS
	POP	ES
	POP	DS
	MOV	SI,DI
	LEA	DI,CURR_FILE
	CALL	STRCPY
	PUSH	CS
	POP	DS
	MOV	SI,DI
	CALL	DIRECTORY_END
	MOV	DI,SI
	LEA	SI,FILE_NAME
	CALL	STRCPY
	MOV	DI,SI
	LEA	SI,CURR_FILE
	CALL	STRCPY
	MOV	DX,DI
	MOV	AX,3D00H
	INT	21H
	NJ C,	UNABLE_TO_OPEN_R
	
CONT_READ:
	MOV	BX,AX

	LEA	DX,TABLE
	MOV	CX,256
	MOV	AH,3FH
	INT	21H
	NJ C,	UNABLE_TO_READ

	CMP	AX,256
	JB	BAD_TABLE
	
	MOV	AH,3EH
	INT	21H
	NJ C,	UNABLE_TO_CLOSE

	POP	BX
	POP	BX
	RET

BAD_TABLE:
	LEA	SI,FILE_NAME
	CALL	TOLOWERSTR
	CALL	PRINT
	MOV	SI,OFFSET BAD_TABLE_MSG
	CALL	PRINT
	RET
READ_TABLE	ENDP

;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;----------------- RECODE FILE (FILE_NAME CONTENTS ITS NAME)------;
RECODE	PROC
	PUSH	BX
	MOV	AX,OFFSET DONERECODE_1
	PUSH	AX

	LEA	DX,FILE_NAME
	MOV	AX,3D00H
	INT	21H
	NJ C,	UNABLE_TO_OPEN_R
	MOV	BX,AX
	MOV	AX,3D01H
	INT	21H
	NJ C,	UNABLE_TO_OPEN_W
	MOV	SI,AX
	CALL	FILELENGTH
	MOV	FLENH,DX
	MOV	FLENL,AX
DO_RECODE:
	CALL	PRINT_INFO
	LEA	DX,BUFFER
	MOV	CX,BSIZE
	MOV	AH,3FH
	INT	21H
	NJ C,	UNABLE_TO_READ
	MOV	CX,AX
	JCXZ	DONERECODE
	LEA	DI,BUFFER
	PUSH	BX
	LEA	BX,TABLE
	CLD
	PUSH	CX
RECODE_BUFFER:
	MOV	AL,[DI]
	XLAT
	STOSB
	LOOP	RECODE_BUFFER
	POP	CX
	MOV	BX,SI
	LEA	DX,BUFFER
	MOV	AH,40H
	INT	21H
	POP	BX
	JNC	DO_RECODE
	JMP	UNABLE_TO_WRITE

DONERECODE:
	POP	AX
	MOV	AH,3EH
	INT	21H
	MOV	BX,SI
	MOV	AH,3EH
	INT	21H
	MOV	SI,OFFSET NL
	CALL	PRINT
DONERECODE_1:
	POP	BX
	RET

PRINT_INFO	PROC
	MPUSH	<AX,CX,DX,SI>
	LEA	SI,FILE_NAME
	CALL	PRINT
	PUTCH	9
	
	PUSH	FLENH
	PUSH	FLENL
	OR	AX,DX
	JZ	NULL
	XOR	CX,CX
	XOR	DX,DX
	MOV	AX,4201H
	INT	21H
	
	XOR	CX,CX
	PUSH	CX
	MOV	CX,100
	PUSH	CX
	CALL	LMUL
		
	CALL	LDIV
PRINT_PR:
	CALL	PRINT_NUM
	PUTCH	'%'
	PUTCH	13
	MPOP	<SI,DX,CX,AX>
	RET
NULL:
	ADD	SP,4
	MOV	AX,100
	JMP	PRINT_PR
PRINT_INFO	ENDP
RECODE	ENDP

PRINT_NUM	PROC
	PUSH	BX
	MOV	BX,10
	XOR	CX,CX
PR_NUM:
	XOR	DX,DX
	DIV	BX
	ADD	DX,'0'
	PUSH	DX
	INC	CX
	CMP	AX,0
	JNE	PR_NUM
PR_NUM_1:
	POP	DX
	MOV	AH,2
	INT	21H
	LOOP	PR_NUM_1
	POP	BX
	RET
PRINT_NUM	ENDP

;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;------------- IF EXT MISSING MAKE DEFAULT EXT -----------------:
DEFAULT_EXT	PROC
	CALL	STRLEN
	PUSH	SI
	MOV	SI,DI
	ADD	SI,CX
	DEC	SI
	STD
SH:
	LODSB
	CMP	AL,'.'
	JE	EXT
	CMP	AL,':'
	JE	ELOOP
	CMP	AL,'\'
	LOOPNE	SH
ELOOP:
	POP	SI
	CALL	STRCAT
	PUSH	SI
EXT:
	POP	SI
	RET
DEFAULT_EXT	ENDP

DIRECTORY_END	PROC	; SI -> FILE NAME
	MOV	SI,DI		;
	CALL	STRLEN		; FILE NAME LENGTH
	ADD	SI,CX
	DEC	SI
	STD
SCAN:				; FIND END OF DIRECTORY
	LODSB
	CMP	AL,'\'
	JE	FOUND_DIR
	CMP	AL,':'
	LOOPNE	SCAN
FOUND_DIR:
	JNZ	ADD1
	INC	SI
ADD1:	INC	SI	; SI -> END OF DIRECTORY
	RET
DIRECTORY_END	ENDP

;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

	.DATA
OLDPOSL	DW	?
OLDPOSH	DW	?

	.CODE
FILELENGTH	PROC
	PUSH	CX
	XOR	CX,CX
	XOR	DX,DX
	MOV	AX,4201H
	INT	21H
	MOV	OLDPOSL,AX
	MOV	OLDPOSH,DX
	XOR	CX,CX
	XOR	DX,DX
	MOV	AX,4202H
	INT	21H
	PUSH	AX
	PUSH	DX
	MOV	DX,OLDPOSL
	MOV	CX,OLDPOSH
	MOV	AX,4200H
	INT	21H
	POP	DX
	POP	AX
	POP	CX
	RET
FILELENGTH	ENDP

LDIV	PROC
	PUSH	BP
	MOV	BP,SP
DIVH	EQU	WORD PTR [BP+6]
DIVL	EQU	WORD PTR [BP+4]
	PUSH	BX
	CMP	DIVH,0
	JE	SMALL_DIV

	PUSH	CX
	PUSH	SI
	PUSH	DI
	MOV	CX,DIVH
	MOV	BX,DIVL
	XOR	DI,DI		; RESULT
	MOV	SI,1
SHIFT_1:
	CMP	DX,CX
	JNE	M1
	CMP	AX,BX
M1:	JB	SHIFT_2
	SHL	SI,1
	SHL	BX,1
	RCL	CX,1
	JNC	SHIFT_1
	STC
	JMP	SHORT SHIFT_3

SHIFT_2:
	CLC
SHIFT_3:
	RCR	CX,1
	RCR	BX,1
	SHR	SI,1
	JC	DONE_2
	CMP	DX,CX
	JNE	M2
	CMP	AX,BX
M2:	JB	SHIFT_2
	ADD	DI,SI
	SUB	AX,BX
	SBB	DX,CX
	JMP	SHIFT_2
DONE_2:
	MOV	AX,DI
	XOR	DX,DX
	POP	DI
	POP	SI
	POP	CX
	JMP	SHORT DONE_LDIV

SMALL_DIV:
	PUSH	AX
	MOV	AX,DX
	XOR	DX,DX
	DIV	DIVL
	MOV	BX,AX
	POP	AX
	DIV	DIVL
	MOV	DX,BX
DONE_LDIV:
	POP	BX
	POP	BP
	RET	4
LDIV	ENDP

LMUL	PROC
	PUSH	BP
	MOV	BP,SP
MULH	EQU	WORD PTR [BP+6]
MULL	EQU	WORD PTR [BP+4]
	PUSH	BX
	PUSH	CX

	PUSH	AX
	PUSH	DX
	MUL	MULL
	POP	BX
	PUSH	AX
	PUSH	DX
	MOV	AX,BX
	MUL	MULL
	POP	CX
	ADD	CX,AX
	POP	BX
	POP	AX
	MUL	MULH
	MOV	DX,AX
	ADD	DX,CX
	MOV	AX,BX

	POP	CX
	POP	BX
	POP	BP
	RET	4
LMUL	ENDP
	
PRINT	PROC
	PUSH	SI
	CLD
PRINT_1:
	LODSB
	CMP	AL,0
	JE	DONE_PRINT
	MOV	DL,AL
	MOV	AH,2
	INT	21H
	JMP	PRINT_1
DONE_PRINT:
	POP	SI
	RET
PRINT	ENDP

STRCPY	PROC
	PUSH	SI
	PUSH	DI
	CLD
COPY_1:
	CMP	BYTE PTR [SI],0
	MOVSB
	JNE	COPY_1
	POP	DI
	POP	SI
	RET
STRCPY	ENDP

STRCAT	PROC
	PUSH	SI
	PUSH	DI
	CLD
SEARCH_1:
	CMP	BYTE PTR [ES:DI],0
	JE	COPY_2
	INC	DI
	JMP	SEARCH_1
COPY_2:
	CMP	BYTE PTR [SI],0
	MOVSB
	JNE	COPY_2
	POP	DI
	POP	SI
	RET
STRCAT	ENDP

STRLEN	PROC
	PUSH	DI
	CLD
	MOV	CX,-1
	MOV	AL,0
	REPNE SCASB
	NOT	CX
	DEC	CX
	POP	DI
	RET
STRLEN	ENDP	

TOLOWER	PROC
	CMP	AL,'A'
	JB	DONE_TOLOWER
	CMP	AL,'Z'
	JA	DONE_TOLOWER
	ADD	AL,'a'-'A'
DONE_TOLOWER:
	RET
TOLOWER	ENDP

TOLOWERSTR	PROC
	PUSH	SI
	CLD
DO_TOL:
	LODSB
	CALL	TOLOWER
	MOV	[SI-1],AL
	CMP	AL,0
	JNE	DO_TOL
	POP	SI
	RET
TOLOWERSTR	ENDP
	
	END	START

