The Art of
ASSEMBLY LANGUAGE PROGRAMMING

Chapter Fifteen (Part 6)

Table of Content

Chapter Sixteen

CHAPTER FIFTEEN:
STRINGS AND CHARACTER SETS (Part 7)
15.7 - Sample Programs
15.7.1 - Find.asm
15.7.2 - StrDemo.asm
15.7.3 - Fcmp.asm
15.7 Sample Programs

In this section there are three sample programs. The first searches through a file for a particular string and displays the line numbers of any lines containing that string. This program demonstrates the use of the strstr function (among other things). The second program is a demo program that uses several of the string functions available in the UCR Standard Library's string package. The third program demonstrates how to use the 80x86 cmps instruction to compare the data in two files. These programs (find.asm strdemo.asm and fcmp.asm) are available on the companion CD-ROM.

15.7.1 Find.asm

; Find.asm
;
; This program opens a file specified on the command line and searches for
; a string (also specified on the command line).
;
; Program Usage:
;
;       find "string" filename


.xlist
include         stdlib.a
includelib      stdlib.lib
.list

wp              textequ <word ptr>

dseg            segment para public 'data'

StrPtr          dword   ?
FileName        dword   ?
LineCnt         dword   ?

FVar            filevar {}

InputLine       byte    1024 dup (?)
dseg            ends


cseg            segment para public 'code'
assume  cs:cseg
ds:dseg


; Readln-       This procedure reads a line of text from the input
;               file and buffers it up in the "InputLine" array.

ReadLn          proc
push    es
push    ax
push    di
push    bx

lesi    FVar            ;Read from our file.
mov     bx
0           ;Index into InputLine.
ReadLp:         fgetc                   ;Get next char from file.
jc      EndRead         ;Quit on EOF

cmp     al
cr          ;Ignore carriage returns.
je      ReadLp
cmp     al
lf          ;End of line on line feed.
je      EndRead

mov     InputLine[bx]
al
inc     bx
jmp     ReadLp

; If we hit the end of a line or the end of the file

; zero-terminate the string.

EndRead:        mov     InputLine[bx]
0
pop     bx
pop     di
pop     ax
pop     es
ret
ReadLn          endp


; The following main program extracts the search string and the
; filename from the command line
opens the file
and then searches
; for the string in that file.

Main            proc
mov     ax
dseg
mov     ds
ax
mov     es
ax
meminit

argc
cmp     cx
2
je      GoodArgs
print
byte    "Usage: find 'string' filename"
cr
lf
0
jmp     Quit

GoodArgs:       mov     ax
1           ;Get the string to search for
argv                    ; off the command line.
mov     wp StrPtr
di
mov     wp StrPtr+2
es

mov     ax
2           ;Get the filename from the
argv                    ; command line.
mov     wp Filename
di
mov     wp Filename+2
es

; Open the input file for reading

mov     ax
0           ;Open for read.
mov     si
wp FileName
mov     dx
wp FileName+2
lesi    Fvar
fopen
jc      BadOpen

; Okay
start searching for the string in the file.

mov     wp LineCnt
0
mov     wp LineCnt+2
0
SearchLp:       call    ReadLn
jc      AtEOF


; Bump the line number up by one.  Note that this is 8086 code
; so we have to use extended precision arithmetic to do a 32-bit
; add.  LineCnt is a 32-bit variable because some files have more
; that 65
536 lines.

add     wp LineCnt
1
adc     wp LineCnt+2
0

; Search for the user-specified string on the current line.

lesi    InputLine
mov     dx
wp StrPtr+2
mov     si
wp StrPtr
strstr
jc      SearchLp        ;Jump if not found.

; Print an appropriate message if we found the string.

printf
byte    "Found '%^s' at line %ld\n"
0
dword   StrPtr
LineCnt
jmp     SearchLp

; Close the file when we're done.

AtEOF:          lesi    FVar
fclose
jmp     Quit

BadOpen:        printf
byte    "Error attempting to open %^s\n"
cr
lf
0
dword   FileName


Quit:           ExitPgm                 ;DOS macro to quit program.
Main            endp

cseg            ends

sseg            segment para stack 'stack'
stk             db      1024 dup ("stack   ")
sseg            ends

zzzzzzseg       segment para public 'zzzzzz'
LastBytes       db      16 dup (?)
zzzzzzseg       ends
end     Main

15.7.2 StrDemo.asm

This short demo program just shows off how to use several of the string routines found in the UCR Standard Library strings package.

; StrDemo.asm-  Demonstration of some of the various UCR Standard Library
;               string routines.

include         stdlib.a
includelib      stdlib.lib

dseg            segment para public 'data'

MemAvail        dw      ?
String          byte    256 dup (0)

dseg            ends



cseg            segment para public 'code'
assume  cs:cseg
ds:dseg


Main            proc
mov     ax
seg dseg            ;Set up the segment registers
mov     ds
ax
mov     es
ax

MemInit
mov     MemAvail
cx
printf
db      "There are %x paragraphs of memory available."
db      cr
lf
lf
0
dd      MemAvail

; Demonstration of StrTrim:

print
db      "Testing strtrim on 'Hello there   '"
cr
lf
0
strdupl
HelloThere1     db      "Hello there   "
0
strtrim
mov     al
"'"
putc
puts
putc
putcr
free

;Demonstration of StrTrimm:

print
db      "Testing strtrimm on 'Hello there   '"
cr
lf
0
lesi    HelloThere1
strtrimm
mov     al
"'"
putc
puts
putc
putcr
free

; Demonstration of StrBdel

print
db      "Testing strbdel on '  Hello there   '"
cr
lf
0
strdupl
HelloThere3     db      "  Hello there   "
0
strbdel
mov     al
"'"
putc
puts
putc
putcr
free

; Demonstration of StrBdelm

print
db      "Testing strbdelm on '  Hello there   '"
cr
lf
0
lesi    HelloThere3
strbdelm
mov     al
"'"
putc
puts
putc
putcr
free


; Demonstrate StrCpyl:

ldxi    string
strcpyl
byte    "Copy this string to the 'String' variable"
0

printf
byte    "STRING = '%s'"
cr
lf
0
dword   String

; Demonstrate StrCatl:

lesi    String
strcatl
byte    ". Put at end of 'String'"
0

printf
byte    "STRING = "
'"%s"'
cr
lf
0
dword   String

; Demonstrate StrChr:

lesi    String
mov     al
"'"
strchr

print
byte    "StrChr: First occurrence of "
'"'
"'"
byte    '" found at position '
0
mov     ax
cx
puti
putcr

; Demonstrate StrStrl:

lesi    String
strstrl
byte    "String"
0

print
byte    'StrStr: First occurrence of "String" found at position '
0

mov     ax
cx
puti
putcr

; Demo of StrSet

lesi    String
mov     al
'*'
strset

printf
byte    "Strset:  '%s'"
cr
lf
0
dword   String

; Demo of strlen

lesi    String
strlen

print
byte    "String length = "
0
puti
putcr




Quit:           mov     ah
4ch
int     21h
Main            endp

cseg            ends

; Allocate a reasonable amount of space for the stack (2k).

sseg            segment para stack 'stack'
stk             db      256 dup ("stack   ")
sseg            ends



; zzzzzzseg must be the last segment that gets loaded into memory!

zzzzzzseg       segment para public 'zzzzzz'
LastBytes       db      16 dup (?)
heap            db      1024 dup (?)
zzzzzzseg       ends
end     Main

15.7.3 Fcmp.asm

This is a file comparison program. It demonstrates the use of the 80x86 cmps instruction (as well as blocked I/O under DOS).

; FCMP.ASM-     A file comparison program that demonstrates the use
;               of the 80x86 string instructions.

.xlist
include         stdlib.a
includelib      stdlib.lib
.list

dseg            segment para public 'data'

Name1           dword   ?               ;Ptr to filename #1
Name2           dword   ?               ;Ptr to filename #2
Handle1         word    ?               ;File handle for file #1
Handle2         word    ?               ;File handle for file #2
LineCnt         word    0               ;# of lines in the file.

Buffer1         db      256 dup (0)     ;Block of data from file 1
Buffer2         db      256 dup (0)     ;Block of data from file 2

dseg            ends

wp              equ     <word ptr>


cseg            segment para public 'code'
assume  cs:cseg
ds:dseg


; Error- Prints a DOS error message depending upon the error type.

Error           proc    near
cmp     ax
2
jne     NotFNF
print
db      "File not found"
0
jmp     ErrorDone

NotFNF:         cmp     ax
4
jne     NotTMF
print
db      "Too many open files"
0
jmp     ErrorDone

NotTMF:         cmp     ax
5
jne     NotAD
print
db      "Access denied"
0
jmp     ErrorDone

NotAD:          cmp     ax
12
jne     NotIA
print
db      "Invalid access"
0
jmp     ErrorDone

NotIA:
ErrorDone:      putcr
ret
Error           endp




; Okay
here's the main program.  It opens two files
compares them
and
; complains if they're different.

Main            proc
mov     ax
seg dseg            ;Set up the segment registers
mov     ds
ax
mov     es
ax

meminit

; File comparison routine.  First
open the two source files.

argc
cmp     cx
2           ;Do we have two filenames?
je      GotTwoNames
print
db      "Usage: fcmp file1 file2"
cr
lf
0
jmp     Quit

GotTwoNames:    mov     ax
1           ;Get first file name
argv
mov     wp Name1
di
mov     wp Name1+2
es

; Open the files by calling DOS.

mov     ax
3d00h       ;Open for reading
lds     dx
Name1
int     21h
jnc     GoodOpen1
printf
db      "Error opening %^s:"
0
dd      Name1
call    Error
jmp     Quit

GoodOpen1:      mov     dx
dseg
mov     ds
dx
mov     Handle1
ax

mov     ax
2           ;Get second file name
argv
mov     wp Name2
di
mov     wp Name2+2
es

mov     ax
3d00h       ;Open for reading
lds     dx
Name2
int     21h
jnc     GoodOpen2
printf
db      "Error opening %^s:"
0
dd      Name2
call    Error
jmp     Quit

GoodOpen2:      mov     dx
dseg
mov     ds
dx
mov     Handle2
ax

; Read the data from the files using blocked I/O
; and compare it.

mov     LineCnt
1
CmpLoop:        mov     bx
Handle1     ;Read 256 bytes from
mov     cx
256         ; the first file into
lea     dx
Buffer1     ; Buffer1.
mov     ah
3fh
int     21h
jc      FileError
cmp     ax
256         ;Leave if at EOF.
jne     EndOfFile

mov     bx
Handle2     ;Read 256 bytes from
mov     cx
256         ; the second file into
lea     dx
Buffer2     ; Buffer2
mov     ah
3fh
int     21h
jc      FileError
cmp     ax
256         ;If we didn't read 256 bytes

jne     BadLen          ; the files are different.

; Okay
we've just read 256 bytes from each file
compare the buffers
; to see if the data is the same in both files.

mov     ax
dseg
mov     ds
ax
mov     es
ax
mov     cx
256
lea     di
Buffer1
lea     si
Buffer2
cld
repe    cmpsb
jne     BadCmp
jmp     CmpLoop


FileError:      print
db      "Error reading files: "
0
call    Error
jmp     Quit


BadLen:         print
db      "File lengths were different"
cr
lf
0

BadCmp:         print
db      7
"Files were not equal"
cr
lf
0

mov     ax
4c01h               ;Exit with error.
int     21h


; If we reach the end of the first file
compare any remaining bytes
; in that first file against the remaining bytes in the second file.

EndOfFile:      push    ax                      ;Save final length.
mov     bx
Handle2
mov     cx
256
lea     dx
Buffer2
mov     ah
3fh
int     21h
jc      BadCmp

pop     bx                      ;Retrieve file1's length.
cmp     ax
bx                  ;See if file2 matches it.
jne     BadLen

mov     cx
ax                  ;Compare the remaining
mov     ax
dseg                ; bytes down here.
mov     ds
ax
mov     es
ax
lea     di
Buffer2
lea     si
Buffer1
repe    cmpsb
jne     BadCmp

Quit:           mov     ax
4c00h               ;Set Exit code to okay.
int     21h
Main            endp

cseg            ends



; Allocate a reasonable amount of space for the stack (2k).

sseg            segment para stack 'stack'
stk             db      256 dup ("stack   ")
sseg            ends


; zzzzzzseg must be the last segment that gets loaded into memory!

zzzzzzseg       segment para public 'zzzzzz'
LastBytes       db      16 dup (?)
zzzzzzseg       ends
end     Main

Chapter Fifteen (Part 6)

Table of Content

Chapter Sixteen

Chapter Fifteen: Strings And Character Sets (Part 7)
28 SEP 1996