Previous | Table of Contents | Next

LISTING 9.2 L9-2.ASM

    ; Searches a text buffer for a text string. Uses REPNZ SCASB to scan
    ; the buffer for locations that match a specified character of the
    ; searched-for string, then uses REPZ CMPS to check fully only those
    ; locations that REPNZ SCASB has identified as potential matches.
    ;
    ; C small model-callable as:
    ;    unsigned char * FindString(unsigned char * Buffer,
    ;     unsigned int BufferLength, unsigned char * SearchString,
    ;     unsigned int SearchStringLength,
    ;     unsigned int ScanCharOffset);
    ;
    ; Returns a pointer to the first match for SearchString in Buffer,or
    ; a NULL pointer if no match is found. Buffer should not start at
    ; offset 0 in the data segment to avoid confusing a match at 0 with
    ; no match found.
    Parms  struc
                            dw      2 dup(?)      ;pushed BP/return address
    Buffer                  dw      ?             ;pointer to buffer to search
    BufferLength            dw      ?             ;length of buffer to search
    SearchString            dw      ?             ;pointer to string for which to search
    SearchStringLength      dw      ?             ;length of string for which to search
    ScanCharOffset          dw      ?             ;offset in string of character for
                                                  ; which to scan
    Parmsends
          .model      small
          .code
          public _FindString
    _FindStringprocnear
          push     bp      ;preserve caller’s stack frame
          mov      bp,sp   ;point to our stack frame
          push     si      ;preserve caller’s register variables
          push     di
          cld              ;make string instructions increment pointers
          mov      si,[bp+SearchString]       ;pointer to string to search for
          mov      cx,[bp+SearchStringLength] ;length of string
          jcxz     FindStringNotFound         ;no match if string is 0 length
          mov      dx,[bp+BufferLength]       ;length of buffer
          sub      dx,cx                      ;difference between buffer and search
                                              ; lengths
          jc        FindStringNotFound ;no match if search string is
                        ; longer than buffer
          inc       dx  ; difference between buffer and search string
                        ; lengths, plus 1 (# of possible string start
                        ; locations to check in the buffer)
          mov       di,ds
          mov       es,di
          mov       di,[bp+Buffer]         ;point ES:DI to buffer to search thru
          mov       bx,[bp+ScanCharOffset] ;offset in string of character
                                           ; on which to scan
          add       di,bx         ;point ES:DI to first buffer byte to scan
          mov       al,[si+bx]    ;put the scan character in AL
          inc       bx            ;set BX to the offset back to the start of the
                                  ; potential full match after a scan match,
                                  ; accounting for the 1-byte overrun of
                                  ; REPNZ SCASB
    FindStringLoop:
          mov       cx,dx              ;put remaining buffer search length in CX
          repnz     scasb              ;scan for the scan byte
          jnz       FindStringNotFound ;not found, so there’s no match
                                       ;found, so we have a potential match-check the
                                       ; rest of this candidate location
          push       di                ;remember the address of the next byte to scan
          mov        dx,cx             ;set aside the remaining length to search in
                                       ; the buffer
          sub        di,bx             ;point back to the potential start of the
                                       ; match in the buffer
          mov        si,[bp+SearchString]       ;point to the start of the string
          mov        cx,[bp+SearchStringLength] ;string length
          shr        cx,1                       ;convert to word for faster search
          jnc        FindStringWord             ;do word search if no odd byte
          cmpsb                                 ;compare the odd byte
          jnz        FindStringNoMatch          ;odd byte doesn’t match, so we
                                                ; haven’t found the search string here
    FindStringWord:
          jcxz       FindStringFound        ;if the string is only 1 byte long,
                                            ; we’ve found a match
          repz       cmpsw                  ;check the rest of the string a word at a time
          jz         FindStringFound        ;it’s a match
    FindStringNoMatch:
          pop        di                     ;get back pointer to the next byte to scan
          and        dx,dx                  ;is there anything left to check?
          jnz        FindStringLoop         ;yes-check next byte
    FindStringNotFound:
          sub        ax,ax                  ;return a NULL pointer indicating that the
          jmp        FindStringDone         ; string was not found
    FindStringFound:
          pop         ax         ;point to the buffer location at which the
          sub         ax,bx      ; string was found (earlier we pushed the
                                 ; address of the byte after the scan match)
    FindStringDone:
          pop         di         ;restore caller’s register variables
          pop         si
          pop         bp         ;restore caller’s stack frame
          ret
    _FindStringendp
          end

LISTING 9.3 L9-3.C

    /* Program to exercise buffer-search routines in Listings 9.1 & 9.2 */
    #include <stdio.h>
    #include <string.h>

    #define DISPLAY_LENGTH  40
    extern unsigned char * FindString(unsigned char *, unsigned int,
          unsigned char *, unsigned int, unsigned int);
    void main(void);
    static unsigned char TestBuffer[] = “When, in the course of human \
    events, it becomes necessary for one people to dissolve the \
    political bands which have connected them with another, and to \
    assume among the powers of the earth the separate and equal station \
    to which the laws of nature and of nature’s God entitle them...”;
    void main() {
       static unsigned char TestString[] = “equal”;
       unsigned char TempBuffer[DISPLAY_LENGTH+1];
       unsigned char *MatchPtr;
       /* Search for TestString and report the results */
       if ((MatchPtr = FindString(TestBuffer,
             (unsigned int) strlen(TestBuffer), TestString,
             (unsigned int) strlen(TestString), 1)) == NULL) {
          /* TestString wasn’t found */
          printf(“\”%s\“ not found\n”, TestString);
       } else {
          /* TestString was found. Zero-terminate TempBuffer; strncpy
             won’t do it if DISPLAY_LENGTH characters are copied */
          TempBuffer[DISPLAY_LENGTH] = 0;
          printf(“\”%s\“ found. Next %d characters at match:\n\”%s\“\n”,
                TestString, DISPLAY_LENGTH,
                strncpy(TempBuffer, MatchPtr, DISPLAY_LENGTH));
       }
    }

Previous | Table of Contents | Next

Graphics Programming Black Book © 2001 Michael Abrash