\*
 *   ZEN 1.10  String operators
 *     C 1990  by Martin Tracy
 *             Last modified  1.1.90
 *\

\ Transform counted string into text string
CODE COUNT ( a - a2 u) \ CORE
        mov   ax,bx
        inc   ax
        mov   bl,[bx]
        sub   bh,bh
        push  ax
        NEXT
END-CODE

\ Store packed string at address a2.
: PLACE ( a n a2)
   2DUP C!  1+ SWAP MOVE ;


\ Truncate leftmost n chars of string.
\ n may be negative
CODE /STRING ( a u n - a2 u2) \ STRING
        pop   cx
        pop   ax
        add   ax,bx
        sub   cx,bx
        mov   bx,cx
        push  ax
        NEXT
END-CODE

\ Return shorter string from first position unequal to byte
CODE SKIP ( a u b - a2 u2) \ STRING
        mov   ax,bx
        pop   cx
        pop   di
        jcxz  Ski1
        mov   bx,ds
        mov   es,bx
        repe scasb
        jz    Ski1
        inc   cx
        dec   di
Ski1:   push  di
        mov   bx,cx
        NEXT
END-CODE

\ Return shorter string from first position equal to byte
CODE SCAN ( a u b - a2 u2) \ STRING
        mov   ax,bx
        pop   cx
        pop   di
        jcxz  Sca1
        mov   bx,ds
        mov   es,bx
        repne scasb
        jnz   Sca1
        inc   cx
        dec   di
Sca1:   push  di
        mov   bx,cx
        NEXT
END-CODE

\ Return string from first trailing position unequal to byte
\ Used by -TRAILING
| CODE SKIP> ( a u b - a2 u2) \ STRING
        pop   cx
        pop   di
        push  di
        jcxz  Skb2
        mov   ax,ds
        mov   es,ax
        add   di,cx
        dec   di
Skb1:   mov   al,[di]
        cmp   al,bl
        jnz   Skb2
        dec   di
        loop  Skb1
Skb2:   mov   bx,cx
        NEXT
END-CODE


\ Move u bytes from a to a2, leftmost byte first
CODE CMOVE ( a a2 u) \ EXT CORE
        mov   cx,bx
        mov   bx,si
        pop   di
        pop   si
        jcxz  Cmo1
        mov   ax,ds
        mov   es,ax
        rep movsb
Cmo1:   mov   si,bx
        pop   bx
        NEXT
END-CODE

\ Move u bytes from a to a2, rightmost byte first
CODE CMOVE> ( a a2 u) \ EXT CORE
        mov   cx,bx
        mov   bx,si
        pop   di
        pop   si
        mov   ax,cx
        dec   ax
        add   di,ax
        add   si,ax
        jcxz  Cmu1
        mov   ax,ds
        mov   es,ax
        std
        rep movsb
        cld
Cmu1:   mov   si,bx
        pop   bx
        NEXT
END-CODE

\ Move u bytes from a to a2 without overlap
: MOVE ( a a2 u) \ CORE
   >R  2DUP U< IF  R> CMOVE>  ELSE  R> CMOVE  THEN ;


\ Store u bytes, starting at address a
CODE FILL ( a u b) \ CORE
        mov   ax,bx
        pop   cx
        pop   di
        jcxz  Fil1
        mov   dx,ds
        mov   es,dx
        rep stosb
Fil1:   pop   bx
        NEXT
END-CODE

\ Store u zeroes, starting at address a.
: ERASE ( a u) \ EXT CORE
   0 FILL ;

\ Store u blanks, starting at address a.
: BLANK ( a u) \ EXT CORE
   BL FILL ;

\*
\ Transform counted string into text string.
: COUNT ( a - a2 u) \ CORE
   DUP C@ SWAP 1+ ;

\ Truncate leftmost n chars of string.
\ n may be negative
: /STRING ( a u n - a2 u2) \ STRING
   ROT OVER + ROT ROT - ;

\ Return shorter string from first position unequal to byte
: SKIP ( a u b - a2 u2) \ STRING
   >R  BEGIN  DUP
       WHILE  OVER C@ R@ - IF  R> DROP  EXIT  THEN  1 /STRING
       REPEAT   R> DROP ;

\ Return shorter string from first position equal to byte
: SCAN ( a u b - a2 u2) \ STRING
   >R  BEGIN  DUP
       WHILE  OVER C@ R@ =  IF  R> DROP  EXIT  THEN  1 /STRING
       REPEAT   R> DROP ;

\ Return string from first trailing position unequal to byte
: SKIP> ( a u b - a2 u2) \ STRING
   >R  BEGIN  DUP
       WHILE  1-  2DUP + C@ R@ - IF  R> DROP  1+ EXIT THEN
       REPEAT  R> DROP ;

\ Move u bytes from a to a2, leftmost byte first.
: CMOVE ( a a2 u) \ EXT CORE
   ?DO  OVER C@ OVER C!  1+ SWAP 1+ SWAP  LOOP  2DROP ;

\ Move u bytes from a to a2, rightmost byte first.
: CMOVE> ( a a2 u) \ EXT CORE
   >R  SWAP R@ + SWAP R@ +  R> 0
   ?DO  1- SWAP 1- SWAP  OVER C@ OVER C!  LOOP  2DROP ;

\ Store u bytes, starting at address a.
: FILL ( a u b) \ CORE
   SWAP ?DUP 0= IF  2DROP EXIT  THEN
   >R OVER C!  DUP 1+ R> 1- CMOVE ;
*\

