home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / os2sdk / os2sdk10 / apps / cpgrep / cpgrepsb.asm < prev    next >
Encoding:
Assembly Source File  |  1988-08-11  |  14.9 KB  |  678 lines

  1. name cpgrepsub
  2.  
  3. retlen    equ    2            ; Size of return address on stack
  4.  
  5. dgroup    group    _data
  6.  
  7. extrn    _casesen:    word        ; Case-sensitivity flag
  8. extrn    _stringlist:    word        ; Table of string lists
  9. extrn    _target:    byte        ; Target string
  10. extrn    _targetlen:    word        ; Length of target string
  11. extrn    _transtab:    byte        ; Translation table for _findlist
  12.  
  13. ;    This segment is puposely word-aligned.  See note
  14. ;    in _findlist below.
  15.  
  16. _text    segment word public 'code'
  17.     assume    cs:_text, ds:dgroup, es:nothing, ss:dgroup
  18.  
  19. ; char            *findone(buffer,bufend)
  20. ; char            *buffer        /* Buffer in which to search */
  21. ; char            *bufend;    /* End of buffer */
  22. ;
  23. ; NOTE: targetlen MUST BE greater than zero
  24.  
  25. buffer    equ    word ptr [bp+retlen+2]
  26. bufend    equ    word ptr [bp+retlen+4]
  27.  
  28.     EVEN
  29.  
  30.     public    _findone
  31. _findone proc    near
  32.     push    bp
  33.     mov    bp,sp
  34.     push    di
  35.     push    si
  36.     push    es
  37.     push    ds            ; ES = DS
  38.     pop    es
  39.     mov    cx,bufend        ; CX = end of buffer
  40.     mov    di,buffer        ; ES:DI = buffer
  41.     sub    cx,di            ; CX = length of buffer
  42.     jbe    sfnomatch        ;  length less than or equal to zero
  43.     mov    dx,_targetlen        ; DX = length of target
  44.     dec    dx            ; Decrement it
  45.     sub    cx,dx            ; target must fit in buffer
  46.     jbe    sfnomatch        ;  (no match if buffer too short)
  47.  
  48. ;    CX = buffer length
  49. ;    DX = target length (minus first character)
  50. ;    ES:DI = buffer pointer
  51.  
  52. sf0:    jcxz    sfnomatch        ; No match if count zero
  53.     mov    si,offset dgroup:_target ; DS:SI = target
  54.     lodsb                ; AL = first byte of target
  55.     repne scasb            ; Look for first character
  56.     jne    sfnomatch        ;  jump if not found
  57.     mov    bx,cx            ; BX = buffer length
  58.     mov    ax,di            ; AX = buffer pointer
  59.     mov    cx,dx            ; Get count for cmpsb
  60.     or    cx,cx            ; Zero? (JCXZ doesn't set flag)
  61.     je    sf1            ;  yes, skip compare
  62.     repe cmpsb            ; Do string compare
  63. sf1:    mov    di,ax            ; DI = buffer pointer
  64.     mov    cx,bx            ; CX = buffer length
  65.     jne    sf0            ; Loop if no match
  66.     dec    ax            ; AX = offset of start of match
  67.     jmp    short sf4
  68.  
  69. sfnomatch:
  70.     xor    ax,ax            ; No match
  71. sf4:    pop    es
  72.     pop    si
  73.     pop    di
  74.     pop    bp
  75.     ret
  76. _findone endp
  77.  
  78.  
  79. ; int            revfind(s,c,slen)
  80. ; char            *s;        /* String to search */
  81. ; int            c;        /* Char to search for */
  82. ; int            slen;        /* Length of s */
  83.  
  84. s    equ    [bp+retlen+2]
  85. c    equ    [bp+retlen+4]
  86. slen    equ    [bp+retlen+6]
  87.  
  88.     EVEN
  89.  
  90.     public    _revfind
  91. _revfind proc    near
  92.     push    bp
  93.     mov    bp,sp
  94.     push    di
  95.     push    es
  96.     push    ds
  97.     pop    es
  98.     mov    di,s
  99.     mov    ax,c
  100.     mov    cx,slen
  101.     jcxz    rf1
  102.     std
  103.     repne scasb
  104.     cld
  105.     mov    cx,s
  106.     jne    rf0
  107.     inc    di
  108. rf0:    sub    cx,di
  109. rf1:    mov    ax,cx
  110.     pop    es
  111.     pop    di
  112.     pop    bp
  113.     ret
  114. _revfind endp
  115.  
  116.  
  117. ; int            countlines(start,finish)
  118. ; char            *start;
  119. ; char            *finish;
  120.  
  121. start    equ    [bp+retlen+2]
  122. finish    equ    [bp+retlen+4]
  123.  
  124.     EVEN
  125.  
  126.     public    _countlines
  127. _countlines proc near
  128.     push    bp
  129.     mov    bp,sp
  130.     push    di
  131.     push    es
  132.     push    ds
  133.     pop    es
  134.     xor    dx,dx            ; Accumulate count in DX
  135.     mov    di,start        ; ES:DI points to start
  136.     mov    cx,finish        ; Put length in CX
  137.     sub    cx,di
  138.     jbe    cl1            ;  branch if no bytes
  139.     mov    al,0Ah            ; Search for linefeeds
  140. cl0:    jcxz    cl1            ; Exit loop if count zero
  141.     repne scasb            ; Do search
  142.     jne    cl1            ;  branch if none found
  143.     inc    dx            ; Increment count
  144.     jmp    short cl0        ; Loop
  145. cl1:    mov    ax,dx            ; Return line count in AX
  146.     pop    es
  147.     pop    di
  148.     pop    bp
  149.     ret
  150. _countlines endp
  151.  
  152.  
  153. ; char            *findlist(buffer,bufend)
  154. ; char            *buffer;    /* Buffer to search */
  155. ; char            *bufend;    /* End of buffer */
  156.  
  157. savesi    equ    word ptr [bp-2]
  158. endbyte    equ    byte ptr [bp-4]
  159.  
  160. stringnode struc
  161.     s_alt    dw    ?        ; List of alternate portions
  162.     s_suf    dw    ?        ; Pointer to suffix string list
  163.     s_must    dw    ?        ; Length of portion that must match
  164. stringnode ends
  165.  
  166.     EVEN
  167.  
  168. flworker dw    findsubi, findsub    ; Worker dispatch table
  169.  
  170.     public    _findlist
  171. _findlist proc    near
  172.     ASSUME    DS:DGROUP, ES:NOTHING, SS:DGROUP
  173.  
  174.     push    bp
  175.     mov    bp,sp
  176.     sub    sp,4            ; Make room for local vars
  177.     push    di
  178.     push    si
  179.     push    ds
  180.     pop    es
  181.     ASSUME    ES:DGROUP
  182.  
  183. ;    We mark the end of our search buffer with 0FFh so that
  184. ;    any comparisons that might run past the end of the buffer
  185. ;    will fail on the 0FFh.  We choose 0FFh so that if the
  186. ;    comparison fails on it, it will always appear as though
  187. ;    the string in the buffer is greater that the string in
  188. ;    the search list.  This will prevent us from stopping
  189. ;    the search too soon.  Of course, we must restore the byte
  190. ;    when we're done.
  191.  
  192.     mov    bx,bufend        ; BX = end of buffer
  193.     mov    al,0FFh            ; End marker
  194.     xchg    byte ptr [bx],al    ; AL = byte after end of buffer
  195.     mov    endbyte,al        ; Save the byte
  196.  
  197.     mov    cx,bx            ; CX = end of buffer
  198.     mov    si,buffer        ; SI = buffer
  199.     sub    cx,si            ; CX = buffer length
  200.     jbe    fl1            ;  no match if empty buffer
  201.     mov    bx,offset dgroup:_transtab ; BX = translation table address
  202.  
  203.     mov    di,_casesen        ; Get flag
  204.     shl    di,1            ; Scale to word index
  205.     call    cs:flworker[di]        ; Call helper
  206.     jc    fl1            ;  branch if no match
  207.  
  208. ;    We have a match
  209. ;
  210. ;    SI = offset of first character past end of matched string
  211. ;    savesi = offset of first character past start of matched string
  212.  
  213.     mov    ax,savesi        ; AX = 1st char past start
  214.     dec    ax            ; AX = start of matched string
  215.     jmp    short fl2
  216.  
  217. ;    We did not find a match
  218.  
  219. fl1:
  220.     xor    ax,ax            ; Return NULL
  221.  
  222. ;    Restore end byte before leaving
  223.  
  224. fl2:
  225.     mov    bx,bufend        ; BX = end of buffer
  226.     mov    dl,endbyte        ; DL = end byte
  227.     mov    [bx],dl            ; Restore byte
  228.  
  229.     pop    si
  230.     pop    di
  231.     mov    sp,bp
  232.     pop    bp
  233.     ret
  234.  
  235. _findlist endp
  236.  
  237.  
  238. ;***    findsub - case-sensitive worker for _findlist
  239. ;
  240. ;    This function does most of the work for
  241. ;    case-sensitive multi-string searches.
  242. ;
  243. ;    ENTRY    BX = address of translation table
  244. ;        CX = number of bytes left in buffer
  245. ;        DS:SI = buffer pointer
  246. ;        SS:BP = pointer to stack frame for _findlist
  247. ;    EXIT    Carry set
  248. ;            No match
  249. ;        Carry clear
  250. ;            DS:SI = pointer to first character after match
  251. ;    USES    AX, CX, DX, DI, SI, Flags
  252.  
  253.     EVEN
  254.  
  255.     public    findsub, fs0, fs1, fs2, fs3, fs4, fs5, fs6
  256. findsub    proc    near
  257.     ASSUME    DS:DGROUP, ES:DGROUP, SS:DGROUP
  258.  
  259. fs0:
  260.     xor    ax,ax            ; AH = 0
  261.  
  262. ;    AH = 0
  263. ;    BX = address of translation table
  264. ;    CX = number of bytes left in buffer
  265. ;    SI = buffer pointer
  266. ;    DS = ES = SS = DGROUP
  267.  
  268. fs1:
  269.     lodsb                ; Character in AL
  270.     xlat byte ptr [bx]        ; Translate character to index
  271.     or    al,al            ; Zero means invalid 1st byte
  272.     loopz    fs1            ;  if so, try next character
  273.  
  274. ;    Either the zero bit is set, meaning the buffer is empty,
  275. ;    or the zero bit is clear, meaning we have a valid first
  276. ;    character.  Either way, CX has been decremented.
  277.  
  278.     jz    fs6            ;  branch if buffer empty
  279.     mov    savesi,si        ; Save buffer pointer
  280.     shl    ax,1            ; Scale to word index
  281.     mov    di,ax
  282.     mov    di,_stringlist[di]    ; DI points to string record
  283.     or    di,di            ; One byte match? (OR clears carry)
  284.     jz    fs3            ;  yes, skip ahead
  285.  
  286. ;    Loop to search for match.
  287. ;    BX = address of translation table
  288. ;    DI = pointer to string record
  289. ;    SI = pointer into buffer
  290.  
  291. fs2:
  292.     mov    cx,[di].s_must        ; CX = length of string
  293.     sub    di,cx            ; DI = pointer to string
  294.     mov    dx,si            ; Save pointer to start of suffix
  295.     repe cmpsb            ; Strings match?
  296.     ja    fs4            ;  no, try alternate if follows
  297.     jb    fs5            ;  no, cannot be in this list
  298.     add    di,cx            ; DI = pointer to string record
  299.     mov    di,[di].s_suf        ; Get pointer to suffix string list
  300.     or    di,di            ; Is there one? (OR clears carry)
  301.     jnz    fs2            ;  yes, keep looking
  302.  
  303. ;    Match found
  304.  
  305. fs3:
  306.     ret                ;  no, we have a match
  307.  
  308. ;    Try alternate suffix
  309.  
  310. fs4:
  311.     add    di,cx            ; DI = pointer to string record
  312.     mov    di,[di].s_alt        ; Get pointer to alternate
  313.     mov    si,dx            ; Restore SI to start of suffix
  314.     or    di,di            ; Is there one?
  315.     jnz    fs2            ;  yes, loop
  316.  
  317. ;    Try new first character
  318.  
  319. fs5:
  320.     mov    cx,bufend        ; CX = end of buffer
  321.     mov    si,savesi        ; Restore SI to saved value
  322.     sub    cx,si            ; CX = length of buffer
  323.     ja    short fs0        ; Try next character in buffer
  324.  
  325. ;    No match
  326.  
  327. fs6:
  328.     stc                ; No match
  329.     ret
  330.  
  331. findsub    endp
  332.  
  333.  
  334. ;***    findsubi - case-insensitive worker for _findlist
  335. ;
  336. ;    This function does most of the work for
  337. ;    case-insensitive multi-string searches.
  338. ;
  339. ;    ENTRY    BX = address of translation table
  340. ;        CX = number of bytes left in buffer
  341. ;        DS:SI = buffer pointer
  342. ;        SS:BP = pointer to stack frame for _findlist
  343. ;    EXIT    Carry set
  344. ;            No match
  345. ;        Carry clear
  346. ;            DS:SI = pointer to first character after match
  347. ;    USES    AX, CX, DX, DI, SI, Flags
  348.  
  349.     EVEN
  350.  
  351.     public    findsubi
  352. findsubi proc    near
  353.     ASSUME    DS:DGROUP, ES:DGROUP, SS:DGROUP
  354.  
  355. fsi0:
  356.     xor    ax,ax            ; AH = 0
  357.  
  358. ;    AH = 0
  359. ;    BX = address of translation table
  360. ;    CX = number of bytes left in buffer
  361. ;    SI = buffer pointer
  362. ;    DS = ES = SS = DGROUP
  363.  
  364. fsi1:
  365.     lodsb                ; Character in AL
  366.     xlat byte ptr [bx]        ; Translate character to index
  367.     or    al,al            ; Zero means invalid 1st byte
  368.     loopz    fsi1            ;  if so, try next character
  369.  
  370. ;    Either the zero bit is set, meaning the buffer is empty,
  371. ;    or the zero bit is clear, meaning we have a valid first
  372. ;    character.  Either way, CX has been decremented.
  373.  
  374.     jz    fsi7            ;  branch if buffer empty
  375.     mov    savesi,si        ; Save buffer pointer
  376.     shl    ax,1            ; Scale to word index
  377.     mov    di,ax
  378.     mov    di,_stringlist[di]    ; DI points to string record
  379.     or    di,di            ; One byte match? (OR clears carry)
  380.     jz    fsi4            ;  yes, skip ahead
  381.  
  382. ;    Loop to search for match.
  383. ;    BX = address of translation table
  384. ;    DI = pointer to string record
  385. ;    SI = pointer into buffer
  386.  
  387. fsi2:
  388.     mov    cx,[di].s_must        ; CX = length of string
  389.     sub    di,cx            ; DI = pointer to string
  390.     mov    dx,si            ; Save pointer to start of suffix
  391. fsi3:    lodsb                ; Byte in AL, SI = SI + 1
  392.     mov    ah,[di]            ; Byte in AH, DI = DI + 1
  393.     inc    di
  394.     or    ax,2020h        ; Fold bytes onto lower case
  395.     cmp    al,ah            ; Compare bytes
  396.     loope    fsi3            ; Loop while same
  397.     ja    fsi5            ;  no, try alternate if follows
  398.     jb    fsi6            ;  no, cannot be in this list
  399.     add    di,cx            ; DI = pointer to string record
  400.     mov    di,[di].s_suf        ; Get pointer to suffix string list
  401.     or    di,di            ; Is there one? (OR clears carry)
  402.     jnz    fsi2            ;  yes, keep looking
  403.  
  404. ;    Match found
  405.  
  406. fsi4:
  407.     ret                ;  no, we have a match
  408.  
  409. ;    Try alternate suffix
  410.  
  411. fsi5:
  412.     add    di,cx            ; DI = pointer to string record
  413.     mov    di,[di].s_alt        ; Get pointer to alternate
  414.     mov    si,dx            ; Restore SI to start of suffix
  415.     or    di,di            ; Is there one?
  416.     jnz    fsi2            ;  yes, loop
  417.  
  418. ;    Try new first character
  419.  
  420. fsi6:
  421.     mov    cx,bufend        ; CX = end of buffer
  422.     mov    si,savesi        ; Restore SI to saved value
  423.     sub    cx,si            ; CX = length of buffer
  424.     ja    short fsi0        ; Try next character in buffer
  425.  
  426. ;    No match
  427.  
  428. fsi7:
  429.     stc                ; No match
  430.     ret
  431.  
  432. findsubi endp
  433.  
  434.  
  435. ; int            strnspn(s,t,n)
  436. ; char            *s;        /* String to search */
  437. ; char            *t;        /* Target list */
  438. ; int            n;        /* Length of s */
  439.  
  440. s    equ    word ptr [bp+retlen+2]
  441. t    equ    word ptr [bp+retlen+4]
  442. n    equ    word ptr [bp+retlen+6]
  443.  
  444.     EVEN
  445.  
  446.     public    _strnspn
  447. _strnspn proc    near
  448.     push    bp
  449.     mov    bp,sp
  450.     push    di
  451.     push    si
  452.     push    ds
  453.     pop    es
  454.     cld
  455.     mov    bx,t            ; BX = t
  456.     mov    di,bx            ; DI = t
  457.     xor    al,al            ; Search for 0 byte
  458.     mov    cx,0FFFFh
  459.     repne scasb
  460.     dec    di            ; Back up to 0
  461.     sub    di,bx            ; DI = length of t
  462.     jz    spn1            ; Done if length of t is 0
  463.     mov    dx,di            ; DX = length of t
  464.     mov    si,s            ; SI = s
  465.     mov    cx,n            ; CX = length of s
  466.     jcxz    spn1            ; Check for null string
  467.     push    bp
  468. spn0:    lodsb                ; AL = next char in s
  469.     mov    bp,cx            ; BP = length of s
  470.     mov    cx,dx            ; CX = length of t
  471.     mov    di,bx            ; DI = t
  472.     repne scasb            ; Scan until match found
  473.     mov    cx,bp            ; CX = length of s
  474.     loope    spn0            ; Loop if match found
  475.     pop    bp
  476.     je    spn1            ; Skip ahead if end of s reached
  477.     dec    si            ; Back up one char
  478. spn1:    sub    si,s            ; SI = length of prefix
  479.     mov    ax,si            ; AX = length of prefix
  480.     pop    si
  481.     pop    di
  482.     pop    bp
  483.     ret
  484. _strnspn endp
  485.  
  486.  
  487. ; int            strncspn(s,t,n)
  488. ; char            *s;        /* String to search */
  489. ; char            *t;        /* Target list */
  490. ; int            n;        /* Length of s */
  491.  
  492.     EVEN
  493.  
  494.     public    _strncspn
  495. _strncspn proc    near
  496.     push    bp
  497.     mov    bp,sp
  498.     push    di
  499.     push    si
  500.     push    ds
  501.     pop    es
  502.     cld
  503.     mov    bx,t            ; BX = t
  504.     mov    di,bx            ; DI = t
  505.     xor    al,al            ; Search for 0 byte
  506.     mov    cx,0FFFFh
  507.     repne scasb
  508.     dec    di            ; Back up to 0
  509.     sub    di,bx            ; DI = length of t
  510.     mov    ax,n            ; Assume length of t is 0
  511.     jz    cspn2            ; Done if length of t is 0
  512.     mov    dx,di            ; DX = length of t
  513.     mov    si,s            ; SI = s
  514.     mov    cx,ax            ; CX = length of s
  515.     jcxz    cspn1            ; Check for null string
  516.     push    bp
  517. cspn0:    lodsb                ; AL = next char in s
  518.     mov    bp,cx            ; BP = length of s
  519.     mov    cx,dx            ; CX = length of t
  520.     mov    di,bx            ; DI = t
  521.     repne scasb            ; Scan until match found
  522.     mov    cx,bp            ; CX = length of s
  523.     loopne    cspn0            ; Loop if match not found
  524.     pop    bp
  525.     jne    cspn1            ; Skip ahead if end of s reached
  526.     dec    si            ; Back up one char
  527. cspn1:    sub    si,s            ; SI = length of prefix
  528.     mov    ax,si            ; AX = length of prefix
  529. cspn2:    pop    si
  530.     pop    di
  531.     pop    bp
  532.     ret
  533. _strncspn endp
  534.  
  535.  
  536. ;    cmpsen - case-sensitive comparison
  537. ;
  538. ;    ENTRY    DS:SI = buffer
  539. ;        ES:DI = string
  540. ;        CX = length of string
  541. ;    EXIT    CX = length of string unused
  542. ;        DI = unused portion of string
  543. ;        Z set
  544. ;            match found
  545. ;        Z clear
  546. ;            no match
  547. ;    USES    CX, DI, SI, Flags
  548.  
  549.     EVEN
  550.  
  551. cmpsen    proc    near
  552.     repe cmpsb
  553.     ret
  554. cmpsen    endp
  555.  
  556.  
  557. ;    cmpinsen - case-insensitive comparison
  558. ;
  559. ;    ENTRY    DS:SI = buffer
  560. ;        ES:DI = string
  561. ;        CX = length of string
  562. ;    EXIT    CX = length of string unused
  563. ;        DI = unused portion of string
  564. ;        Z set
  565. ;            match found
  566. ;        Z clear
  567. ;            no match
  568. ;    USES    AX, CX, DI, SI, Flags
  569.  
  570.     EVEN
  571.  
  572. cmpinsen proc    near
  573. cmpi0:    lodsb                ; Byte in AL, SI = SI + 1
  574.     mov    ah,[di]            ; Byte in AH, DI = DI + 1
  575.     inc    di
  576.     or    ax,2020h        ; Fold bytes onto lower case
  577.     cmp    al,ah            ; Compare bytes
  578.     loope    cmpi0            ; Loop while same
  579.     ret
  580. cmpinsen endp
  581.  
  582.  
  583. ; void            matchstrings(s1,s2,len,nmatched,leg)
  584. ; char            *s1;        /* First string */
  585. ; char            *s2;        /* Second string */
  586. ; int            len;        /* Length */
  587. ; int            *nmatched;    /* Number of bytes matched */
  588. ; int            *leg;        /* Less than, equal, greater than */
  589.  
  590. cm_s1        equ    word ptr [bp+retlen+2]
  591. cm_s2        equ    word ptr [bp+retlen+4]
  592. cm_len        equ    word ptr [bp+retlen+6]
  593. cm_nmatched    equ    word ptr [bp+retlen+8]
  594. cm_leg        equ    word ptr [bp+retlen+10]
  595.  
  596.     EVEN
  597.  
  598.     public    _matchstrings
  599. _matchstrings proc near
  600.     ASSUME    DS:DGROUP, ES:NOTHING, SS:DGROUP
  601.  
  602.     push    bp
  603.     mov    bp,sp
  604.     push    di
  605.     push    si
  606.     push    ds
  607.     pop    es
  608.     ASSUME    ES:DGROUP
  609.     mov    di,cm_s2
  610.     mov    si,cm_s1
  611.     mov    cx,cm_len
  612.     cmp    _casesen,0
  613.     je    cm0
  614.     call    cmpsen
  615.     jmp    short cm1
  616. cm0:    call    cmpinsen
  617. cm1:    mov    bx,cm_leg
  618.     mov    word ptr [bx],0        ; Assume equal
  619.     jz    cm2            ;  yes, skip ahead
  620.     mov    word ptr [bx],1        ; Assume greater than
  621.     jg    cm1a            ;  yes, skip ahead
  622.     mov    word ptr [bx],-1    ; Less than
  623. cm1a:    dec    si
  624. cm2:    sub    si,cm_s1
  625.     mov    bx,cm_nmatched
  626.     mov    [bx],si
  627.     pop    si
  628.     pop    di
  629.     pop    bp
  630.     ret
  631.  
  632. _matchstrings endp
  633.  
  634.  
  635. ; int            strcmp(s1,s2)
  636. ; char            *s1;        /* First string */
  637. ; char            *s2;        /* Second string */
  638.  
  639.     public    _strcmp
  640. _strcmp    proc    near
  641.     push    bp
  642.     mov    bp,sp
  643.     push    di
  644.     push    si
  645.     push    ds
  646.     pop    es
  647.     mov    si,[bp+4]        ; DS:SI = s1
  648.     mov    di,[bp+6]        ; ES:DI = s2
  649. sc0:    lodsb                ; AL = *s1++
  650.     scasb                ; AL - *s2++
  651.     jne    sc1            ;  branch if no match
  652.     or    al,al            ; End of s1?
  653.     jne    sc0            ;  no, loop
  654.     cbw                ; AX = 0
  655.     jmp    short sc2        ; Exit
  656. sc1:    mov    ax,1            ; Assume s1 > s2
  657.     jg    sc2            ;  yes, branch
  658.     neg    ax            ; s1 < s2
  659. sc2:    pop    si
  660.     pop    di
  661.     pop    bp
  662.     ret
  663. _strcmp    endp
  664.  
  665.  
  666.     public    _bpt
  667. _bpt    proc    near
  668.     int    3
  669.     ret
  670. _bpt    endp
  671.  
  672. _text    ends
  673.  
  674. _data    segment word public 'data'
  675. _data    ends
  676.  
  677. end
  678.