home *** CD-ROM | disk | FTP | other *** search
/ C!T ROM 5 / ctrom5b.zip / ctrom5b / PROGRAM / ASM / ALIB30B / SCAN05.ASM < prev    next >
Assembly Source File  |  1994-10-31  |  12KB  |  430 lines

  1.     page    66,132
  2. ;******************************* SCAN05.ASM *********************************
  3.  
  4. LIBSEG           segment byte public "LIB"
  5.         assume cs:LIBSEG , ds:nothing
  6.  
  7. ;----------------------------------------------------------------------------
  8. .xlist
  9.     include  mac.inc
  10.     include  common.inc
  11.  
  12.     extrn    strlen1:far
  13.     extrn    dos_mem_allocate:far
  14.     extrn    dos_mem_release:far
  15. .list
  16. ;----------------------------------------------------------------------------
  17. ; data needed by SCAN_BLOCK routines
  18. ;
  19. LARGENUM    = 255
  20. MAXPATLEN    = 254
  21.  
  22. data_area    struc
  23. iPatLen        dw ?
  24. aiPatStart    db MAXPATLEN dup (?)
  25. piPatCurr    dw ?
  26. aiDelta1    db 256 dup (?)
  27. ;
  28. ; variables used by Check_tail
  29. ;
  30. pchSaveTrgCurr    dw    ?
  31. iSaveTrgLen    dw    ?
  32. ;
  33. ; variables used by search
  34. ;
  35. pchTrgSave    dw    ?
  36. pchTrgStart    dw    ?
  37. data_area    ends
  38.  
  39. our_data_seg    dw    0
  40.  
  41. comment 
  42. ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -( SEARCH  )
  43. ;SCAN_BLOCK_FOPEN - initialize fast scan of sequential buffers
  44. ;  input:  ds:si = points at string to search for (max length 254)
  45. ;             dl = 0 for match case, 20h for match either case
  46. ;
  47. ;  output:    ax = 0 if sucessful,  1 if error
  48. ;             possible errors are: - string length too long or zero bytes.
  49. ;                                  - insufficient memory
  50. ;
  51. ;  Note:  The fast block scan functions need to be called as follows:
  52. ;            SCAN_BLOCK_FOPEN  - allocate memory, initialize tables for scan
  53. ;            SCAN_BLOCK_FAST   - actual scan operation, call repeatedly
  54. ;            SCAN_BLOCK_FCLOSE - release memory allocated by SCAN_BLOCK_FOPEN
  55. ;
  56. ;         See SCAN_BLOCK_FAST and SCAN_BLOCK_FCLOSE
  57. ;* * * * * * * * * * * * * *
  58. 
  59.  
  60.     PUBLIC    SCAN_BLOCK_FOPEN
  61. SCAN_BLOCK_FOPEN    PROC    FAR
  62.     apush    bx,cx,dx,si,di,es
  63.     cld
  64.     push    dx
  65.     mov    dx,0
  66.     mov    ax,size data_area
  67.     call    dos_mem_allocate
  68.     pop    dx
  69.     jc    md1_abort    ;jmp if insufficient memory
  70.     mov    cs:our_data_seg,es
  71. ;
  72. ; determine compare string length
  73. ;
  74.     call    strlen1
  75.     jcxz    md1_abort    ;jmp if zero length compare string
  76.     cmp    cx,MAXPATLEN
  77.     ja    md1_abort    ;jmp if string too long
  78.     mov    es:iPatLen,cx
  79. ;
  80. ; fill aiDelta1 table with length of compare string
  81. ;
  82.     mov    ah, cl
  83.     mov    al, cl
  84.     mov    cx, 256 / 2
  85.     mov    di, offset aiDelta1
  86.     rep    stosw
  87.  
  88. ;For each character 'x' in the pattern string, set aiDelta1['x']
  89. ;with the distance that 'x' is away from the end of the pattern string.
  90. ;If 'x' occurs more than once, use the smallest distance (which
  91. ;  is already built in to the algorithm).
  92. ;If 'x' is the last character in the pattern string, use
  93. ;  LARGENUM instead of 0.
  94. ;For case insensitivity, aiDelta1['x'] = aiDelta1['X'].
  95. ;Example: if the pattern string is 'Kitty' and DL = 20h, then
  96. ;  aiDelta1['k'] = aiDelta1['K'] = 4
  97. ;  aiDelta1['i'] = aiDelta1['I'] = 3
  98. ;  aiDelta1['t'] = aiDelta1['T'] = 1 (the 2nd 't' overwrites 2)
  99. ;  aiDelta1['y'] = aiDelta1['Y'] = LARGENUM
  100. ;  all other entries (i.e. those entries of aiDelta1['x'] where
  101. ;  'x' in not in the pattern string) have a distance of 5
  102.  
  103.         mov    cl, al
  104.         sub    bh, bh
  105. md1_loop2:    dec    al
  106.         jnz    md1_skip1
  107.         mov    al, LARGENUM
  108. md1_skip1:    mov    bl, [ds:si]
  109.         inc    si
  110.         mov    [es:aiDelta1 + bx], al
  111.         mov    ah, bl
  112.         or    ah, dl
  113.         sub    ah, 'a'
  114.         cmp    ah, 'z' - 'a' + 1
  115.         jnc    md1_skip2
  116.         xor    bl, dl
  117.         mov    [es:aiDelta1 + bx], al
  118. md1_skip2:    loop    md1_loop2
  119.  
  120. ;Convert the pattern string into distances, using the aiDelta1
  121. ;  table (aiPatStart[i] = aiDelta1[pchPatStart[i]]).  This
  122. ;  speeds up the search routine later.
  123.  
  124.         mov    cx, [es:iPatLen]
  125.         sub    si,cx
  126.         mov    di, offset aiPatStart
  127. md1_loop3:    mov    bl, [ds:si]
  128.         mov    bl, [es:aiDelta1 + bx]
  129.         mov    [es:di], bl
  130.         inc    di
  131.         inc    si
  132.         loop    md1_loop3
  133.         mov    byte ptr [es:si], 00h
  134.  
  135. ;Start at the beginning of the pattern string.
  136.  
  137.         mov    [es:piPatCurr], offset aiPatStart
  138.  
  139.         sub    ax, ax        ; return okay
  140. md1_exit:    apop    es,di,si,dx,cx,bx
  141.         retf
  142.  
  143. md1_abort:    mov    ax, 0001h    ; return error
  144.         jmp    md1_exit
  145. SCAN_BLOCK_FOPEN    ENDP
  146.  
  147. comment 
  148. ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -( SEARCH  )
  149. ;SCAN_BLOCK_FCLOSE - terminate fast scan sequential buffers
  150. ;  inputs:  none
  151. ;  outputs: none
  152. ;  See SCAN_BLOCK_FOPEN and SCAN_BLOCK_FAST
  153. ;* * * * * * * * * * * * * *
  154. 
  155.  
  156.     PUBLIC    SCAN_BLOCK_FCLOSE
  157. SCAN_BLOCK_FCLOSE    PROC    FAR
  158.     push    es
  159.     mov    es,cs:our_data_seg
  160.     call    dos_mem_release
  161.     pop    es
  162.     retf
  163. SCAN_BLOCK_FCLOSE    ENDP
  164.  
  165. comment 
  166. ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -( SEARCH  )
  167. ;SCAN_BLOCK_FAST - fast scan of sequential buffers for string
  168. ;  inputs:  ds:si = points at block of data to be scanned
  169. ;              cx = block length (byte count)
  170. ;
  171. ;  output:  ds:si = points at remaining data to be scanned
  172. ;              cx = number of bytes remaining to be scanned
  173. ;              ax = 0 for match found (may be match split between two blocks)
  174. ;                   1 for end of block, no match.
  175. ;
  176. ;  note:  SCAN_BLOCK_FAST can find multiple matches in a buffer, and
  177. ;         automatically sets up inputs to be re-entered.  Matches split
  178. ;         across two buffers (blocks) are also handled.
  179. ;
  180. ;         SCAN_BLOCK_FAST can be called repeatedly as long as the compare
  181. ;         string is not changed.  If the compare string changes, then
  182. ;         SCAN_BLOCK_FCLOSE must be called, followed by SCAN_BLOCK_FOPEN.
  183. ;
  184. ;                            code size   speed
  185. ;         SCAN_BLOCK_TINY1    46 bytes    2.36 (small is faster)
  186. ;         SCAN_BLOCK_TINY2    69 bytes   13.35 (matches ether case)
  187. ;         SCAN_BLOCK1         43 bytes    2.36
  188. ;         SCAN_BLOCK2        152 bytes    6.37 (matches either case)
  189. ;         SCAN_BLOCK_FAST    466 bytes    1.42 
  190. ;
  191. ;         See also SCAN_BLOCK_FOPEN and SCAN_BLOCK_FCLOSE
  192. ;
  193. ;  Example:      mov   ds, seg pattern
  194. ;                mov   si, offset pattern
  195. ;                mov   dl, 20h
  196. ;                call  SCAN_BLOCK_FOPEN
  197. ;                test  ax, ax
  198. ;                jnz   error
  199. ;
  200. ;                 mov   ds, seg target
  201. ;        read_loop:
  202. ;                 mov   si, offset target
  203. ;                 (setup ds,si,cx here for SCAN_BLOCK_FAST call)
  204. ;                 (if last buffer then goto to done)
  205. ;        search_loop:
  206. ;                 call  SCAN_BLOCK_FAST
  207. ;                 test  ax, ax
  208. ;                 jz    read_loop
  209. ;                 (process match found here, ds:si point at end of match)
  210. ;                 jcxz  read_loop
  211. ;                 jmp   search_loop
  212. ;
  213. ;          done:  call   SCAN_BLOCK_FCLOSE
  214. ;
  215. ; Credits:  This code origionally provided by Mike Levis and modified
  216. ;           by Jeff Owens
  217. ;* * * * * * * * * * * * * *
  218. 
  219.  
  220. cx_iTrgLen    equ cx
  221. dx_iPatLen1    equ dx
  222. dx_piSavePatCurr equ dx
  223. si_pchTrgCurr    equ si
  224. di_piPatCurr    equ di
  225. bp_pchTrgEnd    equ bp
  226.  
  227.  
  228.     PUBLIC    SCAN_BLOCK_FAST
  229. SCAN_BLOCK_FAST    PROC    FAR
  230.         apush    bx,dx,di,bp,es
  231.         mov    es,cs:our_data_seg
  232.  
  233.         sub    bh, bh
  234.         mov    di_piPatCurr, [es:piPatCurr]
  235.  
  236. ;get length of pattern string (may be partial match)
  237.  
  238.         mov    dx_iPatLen1, [es:iPatLen]
  239.         add    dx_iPatLen1, offset aiPatStart
  240.         sub    dx_iPatLen1, di_piPatCurr
  241.  
  242. ;get address of target string end
  243.  
  244.         mov    bp_pchTrgEnd, si_pchTrgCurr
  245.         add    bp_pchTrgEnd, cx_iTrgLen
  246.  
  247. ; if (iPatLen1 > iTrgLen) then no possible match
  248.  
  249.         cmp    dx_iPatLen1, cx_iTrgLen
  250.         ja    s_no_match
  251.  
  252.         mov    [es:pchTrgStart], si_pchTrgCurr
  253.  
  254. ;use brute force if partial match is in progress
  255.  
  256.         cmp    dx_iPatLen1, [es:iPatLen]
  257.         jne    s_slow
  258.  
  259. ;Jump over characters in target string that are not in the
  260. ;  pattern string, and/or jump to the character in the target
  261. ;  string that is the same as the last chacter of the pattern
  262. ;  string.
  263.  
  264. s_fast:        mov    bl, [si_pchTrgCurr]
  265.         mov    bl, [es:aiDelta1 + bx]
  266.                 cmp    bl, LARGENUM          
  267.                 je    s_fast_end            
  268.                 add    si_pchTrgCurr, bx     
  269.                 jc    s_no_match            
  270.                 cmp    si_pchTrgCurr, bp_pchTrgEnd
  271.                 jb    s_fast                     
  272.                 jmp    s_no_match                
  273. s_fast_end:
  274.         inc    si_pchTrgCurr             
  275.         mov    [es:pchTrgSave], si_pchTrgCurr
  276.         sub    si_pchTrgCurr, dx_iPatLen1
  277.  
  278. ; if (pchTrgCurr < pchTrgStart) {pchTrgCurr += iPatLen1;   goto fast;}
  279.  
  280.         cmp    si_pchTrgCurr, [es:pchTrgStart]
  281.         jnb    s_slow
  282.         add    si_pchTrgCurr, dx_iPatLen1
  283.         jmp    s_fast
  284.  
  285. ;Do a char-by-char comparison of the target string with the pattern string.
  286.  
  287. s_slow:        mov    bl, [si_pchTrgCurr]
  288.         mov    al, [es:aiDelta1 + bx]
  289.         mov    bl, [es:di_piPatCurr]
  290.         cmp    al, bl
  291.         jne    s_skip1
  292.         inc    si_pchTrgCurr
  293.         inc    di_piPatCurr
  294.         dec    dx_iPatLen1
  295.         jnz    s_slow
  296.         jmp    s_match
  297. s_skip1:
  298.  
  299. ;Since the pattern has not been found in the target string yet,
  300. ;  adjust target string index to look for the next match
  301. ;  ("pchTrgSave + 2" is needed to avoid backsliding)
  302.  
  303.         add    si_pchTrgCurr, dx_iPatLen1
  304.         cmp    al, LARGENUM
  305.         je    s_skip2a
  306.         cmp    si_pchTrgCurr, [es:pchTrgSave]
  307.         jnb    s_skip2b
  308. s_skip2a:    mov    si_pchTrgCurr, [es:pchTrgSave]
  309.         add    si_pchTrgCurr, 0002h
  310. s_skip2b:
  311.  
  312. ;Check to see if there are more characters in the target string
  313.  
  314.         cmp    si_pchTrgCurr, bp_pchTrgend
  315.         jnbe    s_skip3
  316.         mov    dx_iPatLen1, [es:iPatLen]
  317.         mov    di_piPatCurr, offset aiPatStart
  318.         jmp    s_fast
  319. s_skip3:
  320.  
  321. s_no_match:    mov    ax, 0001h
  322.         jcxz    s_null_string
  323.         call    CheckTail
  324.         sub    cx_iTrgLen, cx_iTrgLen
  325.         jmp    short s_exit
  326.  
  327. s_null_string:  mov    [es:piPatCurr], di_piPatCurr
  328.         jmp    short s_exit
  329.  
  330. s_match:    sub    cx_iTrgLen, si_pchTrgCurr
  331.         add    cx_iTrgLen, [es:pchTrgStart]
  332.         mov    [es:piPatCurr], offset aiPatStart
  333.         sub    ax, ax
  334.  
  335. s_exit:        apop    es,bp,di,dx,bx
  336.         retf
  337. SCAN_BLOCK_FAST    ENDP
  338. ;====================================================================
  339. ;  CheckTail
  340. ;    Called only by Search to look for partial matches at the tail end
  341. ;    of the target string, using a brute force variation.
  342. ;    Essential, this routine scans the target string tail to get
  343. ;    characters that are in the pattern string, and then uses the brute
  344. ;    force method on them.
  345.  
  346. CheckTail    proc    near
  347.  
  348.         mov    ax, dx_iPatLen1
  349.         mov    dx_piSavePatCurr, di_piPatCurr
  350.         dec    ax
  351.  
  352. ; if (iTrgLen > iPatLen1 - 1)
  353. ;    iTrgLen = iPatLen1 - 1;
  354. ; iSaveTrgLen = iTrgLen;
  355.  
  356.         cmp    cx_iTrgLen, ax
  357.         jbe    ct_skip1
  358.         mov    cx_iTrgLen, ax
  359. ct_skip1:    mov    ax, [es:iPatLen]
  360.         mov    ah, cl
  361.  
  362.         lea    si_pchTrgCurr, [bp_pchTrgEnd - 1]
  363.  
  364. ; while (iPatLen != aiDelta1[*pchTrgCurr] && iTrgLen --)  pchTrgCurr ++;
  365.  
  366. ct_loop1:    mov    bl, [si_pchTrgCurr]
  367.         mov    bl, [es:aiDelta1 + bx]
  368.         cmp    al, bl
  369.         je    ct_skip2
  370.         dec    si_pchTrgCurr
  371.         loop    ct_loop1
  372.  
  373. ; pchTrgCurr ++; if (pchTrgCurr == pchTrgEnd)
  374. ;    goto no_match;
  375.  
  376. ct_skip2:    inc    si_pchTrgCurr
  377.         cmp    si_pchTrgCurr, bp_pchTrgEnd
  378.         je    ct_no_match
  379.  
  380. ; iTrgLen = iSaveTmpLen - iTrgLen;
  381.  
  382.         mov    al, ah
  383.         neg    cx_iTrgLen
  384.         sub    ah, ah
  385.         add    cx_iTrgLen, ax
  386.  
  387. ct_loop2:    mov    [es:iSaveTrgLen], cx_iTrgLen
  388.         mov    [es:pchSaveTrgCurr], si_pchTrgCurr
  389.  
  390. ;    while (aiDelta1[*pchTrgCurr++] == *piPatCurr++ && iTrgLen--)
  391. ;    if (aiDelta1[*(pchTrgCurr - 1)] == *(piPatCurr - 1))
  392. ;       goto match
  393.  
  394. ct_loop3:    mov    bl, [si_pchTrgCurr]
  395.         mov    al, [es:aiDelta1 + bx]
  396.         mov    bl, [es:di_piPatCurr]
  397.         inc    si_pchTrgCurr
  398.         inc    di_piPatCurr
  399.         cmp    al, bl
  400.         loope    ct_loop3
  401.         je    ct_match
  402.  
  403. ;    piPatCurr = piSavePatCurr
  404. ;    pchTrgCurr = pchSaveTrgCurr + 1
  405. ;    iTrgLen = iSaveTrgLen
  406. ; } while (iTrgLen --);
  407.  
  408.         mov    di_piPatCurr, dx_piSavePatCurr
  409.         mov    si_pchTrgCurr, [es:pchSaveTrgCurr]
  410.         mov    cx_iTrgLen, [es:iSaveTrgLen]
  411.         inc    si_pchTrgCurr
  412.         loop    ct_loop2
  413.  
  414. ct_no_match:    mov    ax, 0001h
  415.         mov    [es:piPatCurr], offset aiPatStart
  416.         jmp    ct_exit
  417.  
  418. ct_match:    mov    [es:piPatCurr], di_piPatCurr
  419.         cmp    si_pchTrgCurr, bp_pchTrgEnd
  420.         sbb    ax, ax
  421.         inc    ax
  422.  
  423. ct_exit:    mov    si_pchTrgCurr, bp_pchTrgEnd
  424.         ret
  425. CheckTail    endp
  426.  
  427. LIBSEG    ENDS
  428. ;;    end
  429.