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