home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
pcmagazi
/
1986
/
19
/
change.asm
next >
Wrap
Assembly Source File
|
1987-12-13
|
13KB
|
251 lines
; Change.asm
; A find and replace utility for text files.
; Format: CHANGE filespec findstring replacestring
; The strings have to be in quotes or decimal ASCII
; Multiple codes in a string are separated by commas
; e.g. CHANGE MYFILE 27,"-1" "*"
CODE SEGMENT ;*************************
ASSUME CS:CODE,DS:CODE ;* *
ORG 100H ;* REMEMBER TO EXE2BIN *
;* *
START: JMP BEGINNING ;*************************
; DATA AREA
; ---------
FILE_START DW ?
FIND_CNT DW 0
REPLACE_CNT DW 0
CHANGE_FLAG DB 0
SYNTAX_MSG DB 'Syntax error$'
NOT_FOUND$ DB 'File not found$'
TOO_BIG$ DB 'File too big$'
CHANGE$ DB 'Not Changed$'
DB "Copyright 1986 Ziff-Davis Publishing Co.",1Ah
DB "Programmed by Michael J. Mefford",1Ah
; CODE AREA
; ---------
;-------------------------------------------------------;
; First we will parse the filename and the two strings. ;
;-------------------------------------------------------;
BEGINNING: MOV SI,80H ;Point to parameters.
MOV DX,OFFSET SYNTAX_MSG ;Point to syntax message.
CLD ;Move in forward direction.
CALL SPACE ;Parse leading spaces.
MOV FILE_START,SI ;We now point to filename.
FILE_BYTE: CMP BYTE PTR [SI],13 ;Is it a carriage return?
JZ EXIT ;If yes, exit with syntax error.
CMP BYTE PTR [SI],32 ;Is it a space?
JZ ASCIIZ ;If yes, end of filename
INC SI ; else, point to next byte
JMP SHORT FILE_BYTE ; and check it.
ASCIIZ: MOV BYTE PTR [SI],0 ;Make filename into ASCIIZ.
CALL SPACE ;Parse the spaces.
XOR CX,CX ;Set string counter to zero.
MOV DI,OFFSET FIND$ ;Point to find string storage.
FIND_BYTE: CALL STRING ;Get string.
CMP BYTE PTR [SI],32 ;Are we now pointing to space?
JZ REPLACE ;If yes, done here.
CMP BYTE PTR [SI],13 ;Is it a carriage return?
JZ EXIT ;If yes, it's a syntax error
INC SI ; else point to next byte
JMP SHORT FIND_BYTE ; and get rest of string.
REPLACE: CALL SPACE ;Parse spaces.
MOV FIND_CNT,CX ;Save count of find string bytes.
XOR CX,CX ;Reset counter to zero.
MOV DI,OFFSET REPLACE$ ;Point to replace string storage.
REPLACE_BYTE: CALL STRING ;Get string.
CMP BYTE PTR [SI],32 ;Are we now pointing to space?
JZ OPEN_FILE ;If yes, we are done here.
CMP BYTE PTR [SI],13 ;Are we now pointing to CR?
JZ OPEN_FILE ;If yes, we are done here
INC SI ; else, point to next byte
JMP SHORT REPLACE_BYTE ; and get rest of string.
;------------------------------------------;
; The exit is placed in the middle of code ;
; so it can be reached by short jumps. ;
;------------------------------------------;
EXIT: MOV AH,9 ;Display message
INT 21H
INT 20H ; and terminate.
;-----------------------------------------------------------;
; We are ready to open the file and read it into the buffer ;
; offset 20,000 bytes from the start. We will then move the ;
; bytes to the start of buffer, trading any match of find ;
; string with replacement string. ;
;-----------------------------------------------------------;
OPEN_FILE: MOV REPLACE_CNT,CX ;Save count of replace bytes.
MOV DX,FILE_START ;Point to ASCIIZ filename
MOV AX,3D00H ; and open file for reading.
INT 21H
MOV DX,OFFSET NOT_FOUND$ ;If not found
JC EXIT ; display message and exit.
READ_FILE: MOV BX,AX ;File handle into BX
MOV DX,OFFSET BUFFER+20000 ;Point buffer
MOV CX,40000 ;Attempt to read 40,000 bytes.
MOV AH,3FH
INT 21H
MOV DX,OFFSET TOO_BIG$ ;Point to error message.
CMP AX,40000 ;Did we read 40,000 bytes?
JZ EXIT ;If yes, file too big; exit
PUSH AX ; else, save count of bytes
MOV AH,3EH ; and close the file.
INT 21H
COMPARE: POP DX ;Retrieve byte count.
MOV AX,FIND_CNT ;Retrieve find string length.
CMP DX,AX ;Is find string bigger than file?
JGE OK ;If no, it's OK
MOV DX,OFFSET CHANGE$ ; else exit with no change.
JMP SHORT EXIT
OK: MOV BX,OFFSET BUFFER+20000 ;Point to start of file
MOV AX,OFFSET BUFFER ; and start of storage.
NEXT_COMP: MOV SI,OFFSET FIND$ ; point to find string
MOV DI,BX ; point to match attempt
MOV CX,FIND_CNT ; get find string length
REP CMPSB ; and compare.
MOV DI,AX ;Point storage area.
JZ MATCH ;If match, store replace string
MOV SI,BX ; else store
MOVSB ; old byte
INC AX ; point to next storage spot
INC BX ; start of next byte to compare
DEC DX ; decrement file byte count
JMP SHORT LOOP ; and check if end of file.
MATCH: OR CHANGE_FLAG,1 ;Indicate that we found a match.
MOV SI,OFFSET REPLACE$ ;Point to replacement string.
MOV CX,REPLACE_CNT ;Get length.
ADD AX,CX ; point to next storage spot
ADD BX,FIND_CNT ; start of next byte to compare
SUB DX,FIND_CNT ; subtract from file byte count
REP MOVSB ; and store the string.
LOOP: CMP DX,FIND_CNT ;Is find string bigger than
JGE NEXT_COMP ; balance of file? If no, next
MOV CX,DX ; compare else, transfer the
ADD AX,CX ; balance of file to write
MOV SI,BX ; storage area.
REP MOVSB
;-----------------------------------------;
; We are ready to write the file to disk. ;
;-----------------------------------------;
WRITE: PUSH AX ;Save length of new file.
MOV DX,FILE_START ; point to ASCIIZ filename.
XOR CX,CX ; normal attribute
MOV AH,3CH ; and create new file.
INT 21H
POP CX ;Retrieve file length
SUB CX,OFFSET BUFFER ;It's in offset form; correct it.
MOV BX,AX ;File handle into BX
MOV DX,OFFSET BUFFER ; point to storage buffer
MOV AH,40H ; and write the file.
INT 21H
MOV AH,3EH ;Close file.
INT 21H
MOV DX,OFFSET CHANGE$ ;Point to "Not Changed"
CMP CHANGE_FLAG,0 ;Did we find a match?
JZ NOT_CHANGED ;If no, display as is
ADD DX,4 ; else bump pointer to "Changed"
NOT_CHANGED: JMP EXIT ; and we are done.
;---------------------------------------------;
; This subroutine will get the quoted string ;
; or convert the decimal ASCII to hexadecimal ;
; and store in the appropriate storage area. ;
;---------------------------------------------;
STRING: CMP BYTE PTR [SI],'"' ;Is it quotes?
JNZ NUMBER ;If no, must be number
INC SI ; else, point to first string
NEXT_STRING: LODSB ; byte and retrieve.
CMP AL,13 ;Is it carriage return?
JZ ERROR ;If yes, syntax error; exit.
CMP AL,'"' ;Is it quotes?
JNZ STORE ;If no, store the byte
CALL DELIMITER ; else, see if delimiter
JNC STORE ; and store the quote if part
RET ; of string else, we are done.
STORE: STOSB ;Store the byte
INC CX ; increment byte count
JMP SHORT NEXT_STRING ; and get next string byte
NUMBER: XOR BL,BL ;Zero into hex counter.
GET_NUMBER: CALL DELIMITER ;Is it a delimiter?
JNC LOAD_NUMBER ;If no, get next decimal number
MOV AL,BL ; get hex byte
STOSB ; and store
INC CX ; increment byte count
RET ; and we are done
LOAD_NUMBER: LODSB ;Get the decimal number
CMP AL,'0' ;Is it between 0 and 9?
JB ERROR ;If no, syntax error
CMP AL,'9'
JA ERROR
SUB AL,30H ; else, convert to hex
MOV BH,AL ; and save
MOV AL,10 ; multiply by ten
MUL BL ; to shift place left
MOV BL,AL
ADD BL,BH ; add new number
JMP SHORT GET_NUMBER ; and get next decimal number.
ERROR: JMP EXIT ;In lieu of range of short jump.
;--------------------------------;
; This subroutine will parse ;
; leading and delimiting spaces. ;
;--------------------------------;
SPACE: INC SI ;Point to next byte
CMP BYTE PTR [SI],32 ;Is it space?
JZ SPACE ;If no, get next byte
RET ; else, return.
;----------------------------;
; This subroutine will check ;
; for delimiter characters. ;
;----------------------------;
DELIMITER: CLC ;Assume not delimiter.
CMP BYTE PTR [SI],32 ;Is it space
JZ SET_CARRY
CMP BYTE PTR [SI],13 ; or carriage return
JZ SET_CARRY
CMP BYTE PTR [SI],',' ; or comma?
JNZ RETURN ;If no, return else, indicate
SET_CARRY: STC ; by setting carry flag
RETURN: RET ; and return.
;-------------------------------------------------------------;
; Storage buffers for findstring, replacestring and file at ;
; end of code to make basic data listing appreciably shorter. ;
;-------------------------------------------------------------;
FIND$:
ORG OFFSET FIND$+128
REPLACE$:
ORG OFFSET REPLACE$+128
BUFFER:
CODE ENDS
END START