; File: pastring.text
; Date: 24-Sep-82

        IDENT   PASTRING
        
        GLOBAL  %_CAT,%_POS,%_COPY,%_DEL,%_INS
        
;
; %_CAT - Concatenate strings
;
; Parameters: ST.L - Address of 1st string
;             ST.L - Address of 2nd string
;             ...
;             ST.L - Address of Nth string
;             ST.L - Address to put result
;             ST.W - N
;
; Returns: ST.L - Address of result
;
; This routine preserves all registers
;

%_CAT
        MOVEM.L D0-D2/A0-A2,-(SP)
        MOVE.W  28(SP),D0       ; N
        MOVE.L  30(SP),A0       ; Address of result
        LEA     34(SP),A1       ; Addr of Addr of Nth parameter
        MOVE.W  D0,D2           ; Incr A1 to point to ...
        LSL.W   #2,D2           ; ... the address of ...
        ADDA.W  D2,A1           ; ... the first parameter
        CLR.W   D1              ; Length of result
        ADDQ.L  #1,A0
        BRA.S   C_TEST
C_LOOP  MOVE.L  -(A1),A2        ; Address of Kth string
        CLR.W   D2
        MOVE.B  (A2)+,D2        ; Length of Kth string
        ADD.W   D2,D1           ; Update total length
        BRA.S   C_TEST2
C_LOOP2 MOVE.B  (A2)+,(A0)+
C_TEST2 SUBQ.W  #1,D2
        BPL.S   C_LOOP2
C_TEST  SUBQ.W  #1,D0           ; See if any more strings
        BPL.S   C_LOOP
        MOVE.L  30(SP),A0       ; Address of result
        MOVE.B  D1,(A0)         ; Store length of result
        LEA     34(SP),A1       ; Addr of Addr of Nth parameter
        MOVE.W  28(SP),D0       ; N
        LSL.W   #2,D0           ; Set A1 to the address of ...
        ADDA.W  D0,A1           ; ... the first parameter
        MOVE.L  A0,-(A1)        ; Set up function result
        MOVE.L  24(SP),-(A1)    ; Set up return address
        MOVE.L  A1,24(SP)       ; Set up final SP
        MOVEM.L (SP)+,D0-D2/A0-A2
        MOVE.L  (SP)+,SP
        RTS

;
; %_POS - Position of one string in another
;
; Parameters: ST.L - Address of SubString
;             ST.L - Address of Main String
;
; Returns:    ST.W - Position
;
; This procedure preserves all registers.
;

%_POS
        MOVEM.L D0-D2/A0-A2,-(SP)
        MOVE.L  28(SP),A0       ; Address of Main String
        CLR.W   D0
        MOVE.B  (A0)+,D0        ; Length of Main String
        CLR.W   D1              ; Result
POS_TOP MOVE.L  32(SP),A1       ; Address of SubString
        CLR.W   D2
        MOVE.B  (A1)+,D2        ; Length of Substring
        CMP.W   D2,D0           ; Compare lengths
        BGE.S   POS_TRY
        CLR.W   D1              ; No match if substring shorter
        BRA.S   POSDONE
POS_TRY MOVE.L  A0,A2           ; Get fresh copy of main pointer
        ADDQ.L  #1,D1           ; Update result counter
        BRA.S   POSTEST
POSLOOP CMPM.B  (A2)+,(A1)+
        BNE.S   TRYNEXT         ; No Match if not equal
POSTEST SUBQ.W  #1,D2
        BPL.S   POSLOOP
        BRA.S   POSDONE         ; Fall through means found it
TRYNEXT ADDQ.L  #1,A0           ; Update main pointer for next try
        SUBQ.W  #1,D0           ; Decrement remaining length of main string
        BRA.S   POS_TOP
POSDONE MOVE.W  D1,34(SP)       ; Store the result
        MOVE.L  24(SP),30(SP)   ; Set up the return address
        MOVEM.L (SP)+,D0-D2/A0-A2
        ADDQ.L  #6,SP
        RTS

;
; %_COPY - Copy a substring
;
; Parameters: ST.L - Source string address
;             ST.W - Starting index
;             ST.W - Size to copy
;             ST.L - Address of result
;
; Returns: ST.L - Address of result
;
; This routine saves all registers
;

%_COPY
        MOVEM.L D0-D2/A0-A1,-(SP)
        MOVE.L  24(SP),A0       ; Address for result
        MOVE.W  28(SP),D0       ; Size to copy
        BLE.S   Y_ZERO          ; '' if size <= 0
        MOVE.W  30(SP),D1       ; Index
        BLE.S   Y_ZERO          ; '' if index <= 0
        SUBQ.W  #1,D1
        MOVE.L  32(SP),A1       ; Address of source string
        CLR.W   D2              ; to get length of source
        MOVE.B  (A1)+,D2        ;
        SUB.W   D1,D2
        BLE.S   Y_ZERO          ; '' if index > length(string)
        SUB.W   D0,D2
        BGE.S   Y_OK            ; See if too little source
        ADD.W   D2,D0           ; Copy only what exists
Y_OK    ADDA.W  D1,A1           ; Point to first byte to copy
        MOVE.B  D0,(A0)+        ; Store result length
        BRA.S   Y_TEST
Y_LOOP  MOVE.B  (A1)+,(A0)+
Y_TEST  SUBQ.W  #1,D0
        BPL.S   Y_LOOP
Y_LEAVE MOVE.L  24(SP),32(SP)   ; Set up function result
        MOVE.L  20(SP),28(SP)   ; Set up return address
        MOVEM.L (SP)+,D0-D2/A0-A1
        ADDQ.W  #8,SP           ; Pop parameters
        RTS
Y_ZERO  CLR.B   (A0)            ; Return null string
        BRA.S   Y_LEAVE

;
; %_DEL - Delete a substring form a string
;
; Parameters: ST.L - Address of string
;             ST.W - Position to start deleting
;             ST.W - Number bytes to delete
;

%_DEL
        MOVE.L  (SP)+,A2        ; Pop return address
        MOVE.W  (SP)+,D0        ; Pop Number bytes
        MOVE.W  (SP)+,D1        ; Pop position
        MOVE.L  (SP)+,A0        ; Pop string address
        CMPI.W  #0,D0           ; Exit if bytes to delete
        BLE.S   D_DONE          ; is <= 0
        CMPI.W  #0,D1           ; or if starting position
        BLE.S   D_DONE          ; is <= 0
        CLR.W   D2              ; Fetch ...
        MOVE.B  (A0),D2         ; ... string size
        CMP.W   D1,D2           ; Exit if starting position
        BLT.S   D_DONE          ; is > string size
        MOVE.W  D1,D3           ; Compare position
        ADD.W   D0,D3           ; plus number bytes
        SUBQ.W  #1,D3           ; minus 1
        SUB.W   D2,D3           ; to string size
        BLE.S   D_SETUP
        SUBQ.W  #1,D1           ; Compute result size
        MOVE.B  D1,(A0)         ; and store it
        BRA.S   D_DONE
D_SETUP SUB.W   D0,D2           ; Compute result size
        MOVE.B  D2,(A0)         ; and store it
        ADDA.W  D1,A0           ; Point to first char to delete
        MOVE.L  A0,A1
        ADDA.W  D0,A1           ; Point to first char to move
        BRA.S   D_TEST
D_LOOP  MOVE.B  (A1)+,(A0)+
D_TEST  ADDQ.W  #1,D3
        BLE.S   D_LOOP
D_DONE  JMP     (A2)

;
; %_INS - Insert a string in another
;
; Parameters: ST.L - Address of string to insert
;             ST.L - Address of main string
;             ST.W - Position in main string to insert
;

%_INS
        MOVE.L  (SP)+,A2        ; Pop return address
        MOVE.W  (SP)+,D0        ; Pop index
        MOVE.L  (SP)+,A1        ; Pop address of main string
        MOVE.L  (SP)+,A0        ; Pop address of string to insert
        MOVE.L  A2,-(SP)
        SUBQ.W  #1,D0
        BLT.S   I_DONE          ; Exit if index < 0
        CLR.W   D1
        MOVE.B  (A0)+,D1        ; Length of substring
        CLR.W   D2
        MOVE.B  (A1),D2         ; Length of Main String
        CMP.W   D0,D2           ; Exit if index
        BLT.S   I_DONE          ; not in main string
        MOVE.W  D1,D3
        ADD.W   D2,D3           ; Final string size
        MOVE.B  D3,(A1)+
        MOVE.L  A1,A2
        ADDA.W  D3,A2           ; points to last byte in result string +1
        MOVE.L  A1,A3
        ADDA.W  D2,A3           ; points to last byte of main string +1
        SUB.W   D0,D2           ; How many bytes to move
        BRA.S   I_TEST
I_LOOP  MOVE.B  -(A3),-(A2)
I_TEST  SUBQ.W  #1,D2
        BPL.S   I_LOOP
        ADDA.W  D0,A1           ; Address of hole
        BRA.S   I_TEST2
I_LOOP2 MOVE.B  (A0)+,(A1)+
I_TEST2 SUBQ.W  #1,D1
        BPL.S   I_LOOP2
I_DONE  RTS

        END

