# Disk 5: Strings and Substrings



- [Part I: The Strings Collection](#part-i-the-strings-collection)

  - [Strings Components](#string-components)

  - [Strings Header File](#header-file)

- [Strings Macros and Subroutines](#macros-and-subroutines)
- [Whole Strings](#whole-string-macros)
    - [The SCMP Macro](#the-scmp-macro)
    - [The STRCOMP Subroutine](#the-strcomp-subroutine)
      - [The SCAT Macro](#the-scat-macro)
        - [The STRCAT Subroutine](#the-strcat-subroutine)
      - [The STRIM Macro](#the-strim-macro)
        - [The STRTRIM Subroutine](#the-strtrim-subroutine)
      - [The STRUP Macro](#the-strup-macro)
        - [The STRUPPER Subroutine](#the-strupper-subroutine)
      
    - [The SLO Macro](#the-slo-macro)
    - [The STRLOWER Subroutine](#the-strlower-subroutine)
      - [The SREV Macro](#the-srev-macro)
        - [The STRREV Subroutine](#the-strrev-subroutine)
      - [The SCAP Macro](#the-scap-macro)
        - [The STRCAP Subroutine](#the-strcap-subroutine)
      
    - [Substrings](#substring-macros)
- [The SPOS Macro](#the-spos-macro)
        - [The SUBPOS Subroutine](#the-subpos-subroutine)
  - [The SCPY Macro](#the-scpy-macro)
        - [The SUBCOPY Subroutine](#the-subcopy-subroutine)
      - [The SDEL Macro](#the-sdel-macro)
        - [The SUBDEL Subroutine](#the-subdel-subroutine)
      - [The SINS Macro](#the-sins-macro)
        - [The SUBINS Subroutine](#the-subins-subroutine)
      - [The STOK Macro](#the-stok-macro)
        - [The SUBTOK Subroutine](#the-subtok-subroutine)
      - [The SCNT Macro](#the-scnt-macro)
        - [The SUBCHARCNT Subroutine](#the-subcharcnt-subroutine)
  
- [Part II: String Collection Demos](#part-ii-string-and-substring-demonstrations)
- Whole Strings Demo
  - Substrings Demo









---





## Part I: The Strings Collection



The fifth disk of the AppleIIAsm library is dedicated to manipulating strings, with a substantial portion of the macros and subroutines dealing with substring functions. Since roughly half of these deal with whole strings and half deal with substrings, the strings collection is further divided as such in terms of both macros and demos: whole string functions and substring functions. This collection includes macros and substrings for the following:

- Finding a substring position
- Copying a substring
- Deleting a substring
- Inserting a substring
- Finding a tokenized substring
- Counting the number of tokens in a string
- Comparing strings
- Concatenating strings
- Trimming strings
- String conversion to uppercase
- String conversion to lowercase
- String reversal
- Sentence-based capitalization





---



## Strings Components



The Strings collection contains the following components:

- A header file that includes a number of hooks and vectors to be used by the macros and subroutines in the collection.
- Macros and subroutines used to manipulate strings and substrings in  variety of ways. These can be further paired for greater functionality, for instance by using `SDEL` and `SINS` to write a substring replacing routine. Currently, the macros are divided into two files: MAC.STRINGS.ASM for whole string operations and MAC.SUBSTRINGS.ASM for substring operations.
- Demonstrations of all of the macros in the strings collection.  This is divided into two files, the DEMO.STRINGS.ASM file and the DEMO.SUBSTRINGS.ASM file.





---



## Header File



| Condition     | Value                                                        |
| ------------- | ------------------------------------------------------------ |
| Name          | File: HEAD.STRINGS.ASM                                       |
| Type          | Header File                                                  |
| Author        | Nathan Riggs                                                 |
| Last Revision | 03-APR-2021                                                  |
| Assembler     | Merlin 8 Pro                                                 |
| OS            | Apple DOS 3.3                                                |
| Purpose       | Provide appropriate hooks and routines for the Strings collection |
| Dependencies  | none                                                         |
| Bytes         | 0                                                            |
| Notes         | Repeatedly used subroutines by the library may be placed here in the future |
| See Also      | none                                                         |

---

*DETAILS*

Currently, the Strings Collection header file only includes a single vector, which serves as an alternative entry point to `COUT`.



`LISTING 5.00: HEAD.STRINGS.ASM Source`

```assembly
*
*``````````````````````````````*
* HOOKS.STRINGS                *
*                              *
* THIS FILE CONTAINS ALL OF    *
* THE HOOKS REQUIRED BY THE    *
* STRING LIBRARY.              *
*                              *
* AUTHOR:    NATHAN RIGGS      *
* CONTACT:   NATHAN.RIGGS@     *
*            OUTLOOK.COM       *
*                              *
* DATE:      19-SEP-2019       *
* ASSEMBLER: MERLIN 8 PRO      *
* OS:        DOS 3.3           *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
SCOUT1   EQU   $FDF0
*

```



---



### Macros and Subroutines

The Strings Collection is further divided into two basic sections: functions for manipulating whole strings and those used for manipulating substrings. By combining the various macros provided, more complex (and more contemporary) routines may be created, such as a substring replace function, a substring search function, and so on.



---



### Whole String Macros

The macros contained here are dedicated to operations on whole strings. Technically, of course, all strings are whole strings; what is meant by "whole string operation" here is that the entire string being operated on is passed back after the macro is called, albeit transformed in some way. 

`LISTING 5.10: MAC.STRINGS.ASM Header Source`

```assembly
*
*``````````````````````````````*
* MAC.STRINGS                  *
*                              *
* THIS FILE CONTAINS ALL OF    *
* THE MACROS RELATED TO STRING *
* MANIPULATION.                *
*                              *
* AUTHOR:    NATHAN RIGGS      *
* CONTACT:   NATHAN.RIGGS@     *
*            OUTLOOK.COM       *
*                              *
* DATE:      11-APR-2021       *
* ASSEMBLER: MERLIN 8 PRO      *
* OS:        DOS 3.3           *
*                              *
* SUBROUTINE FILES USED        *
*                              *
* SUB.STRCAT.ASM               *
* SUB.STRCOMP.ASM              *
* SUB.STRTRIM.ASM              *
* SUB.STRUPPER.ASM             *
* SUB.STRLOWER.ASM             *
* SUB.STRREV.ASM               *
* SUB.STRCAP.ASM               *
*                              *
* LIST OF MACROS               *
*                              *
* SCMP : STRING COMPARE        *
* SCAT : STRING CONCATENATE    *
* STRIM: STRING TRIM           *
* SUP  : STRING UPPERCASE      *
* SLO  : STRING LOWERCASE      *
* SREV :  STRING REVERSE       *
* SCAP : STRING CAPITALIZATION *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*

```



---



### THE SCMP MACRO

_SUMMARY_

| Condition       | Value                                                        |
| --------------- | ------------------------------------------------------------ |
| Name            | `SCMP`                                                       |
| Type            | Macro                                                        |
| File            | `MAC.STRINGS.ASM`                                            |
| Author          | Nathan Riggs                                                 |
| Last Revision   | 12-APR-2021                                                  |
| Assembler       | Merlin Pro 8                                                 |
| OS              | Apple DOS 3.3                                                |
| Purpose         | Compare two strings                                          |
| Input           | ]1 = First string to compare<br />]2 = Second string to compare |
| Output          | none                                                         |
| Dependencies    | `SUB.STRCOMP.ASM`                                            |
| Flags Destroyed | NZCV                                                         |
| Cycles          | 110+                                                         |
| Bytes           | 67 bytes                                                     |
| Notes           | None                                                         |
| See Also        | none                                                         |

---

*DETAILS*

The `SCMP` macro accepts two strings as input and compares them, returning the results via the status register as a regular `CMP` instruction would do. In particular, the zero flag and the carry flag are set or unset based on the comparison of the strings as follows:

- If the strings match, then the zero flag is set to one
- If the strings do not match, then the zero flag is set to zero
- If the strings do match up to the length of the shortest string, then a further comparison is done to test the lengths. Then:
  - The carry flag is set to zero if the first string length is less than the second string length
  - The carry flag is set to one if the first string length is greater than or equal to the length of the second string

`LISTING 5.11: The SCMP Macro Source`

```assembly
*
*``````````````````````````````*
* SCMP          (NATHAN RIGGS) *
*                              *
* COMPARES TWO STRINGS AND     *
* CHANGES THE ZERO FLAG TO 1   *
* IF THE STRINGS ARE EQUAL. IF *
* UNEQUAL, THE MACRO THEN      *
* COMPARES THE LENGTHS; IF THE *
* FIRST IS LESS THAN SECOND,   *
* THE CARRY FLAG IS SET TO 0.  *
* OTHERWISE, IT IS SET TO 1.   *
*                              *
* PARAMETERS                   *
*                              *
*  ]1 = 1ST STRING TO COMPARE  *
*  ]2 = 2ND STRING TO COMPARE  *
*                              *
* CYCLES: 110+                 *
* SIZE: 67 BYTES               *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
SCMP     MAC
         STY   SCRATCH    ; {3C2B} BACKUP .Y REGISTER
         _MSTR ]1;WPAR1   ; {15C14B}
         _MSTR ]2;WPAR2   ; {15C14B}
         JSR   STRCMP     ; {74C26B}
         LDY   SCRATCH    ; {3C2B} RELOAD .Y
         <<<
*

```



---



### THE STRCOMP SUBROUTINE

_SUMMARY_

| Condition       | Value                                            |
| --------------- | ------------------------------------------------ |
| Name            | `STRCOMP`                                        |
| Type            | Subroutine                                       |
| File            | `SUB.STRCOMP.ASM`                                |
| Author          | Nathan Riggs                                     |
| Last Revision   | 12-APR-2021                                      |
| Assembler       | Merlin Pro 8                                     |
| OS              | Apple DOS 3.3                                    |
| Purpose         | Compare two strings                              |
| Input           | WPAR1 = First string<br />WPAR2 = Second strings |
| Output          | none                                             |
| Dependencies    | none                                             |
| Flags Destroyed | NZCV                                             |
| Cycles          | 68+                                              |
| Bytes           | 32                                               |
| Notes           | none                                             |
| See Also        | `SCMP`                                           |

---

*DETAILS*

The `STRCOMP` subroutine is provided the addresses of two strings with a preceding length-byte, then runs a comparison on them. The results are passed back via the Carry and Zero flags of the status register, as such:

- If the strings match, then the zero flag is set to one

- If the strings do not match, then the zero flag is set to zero

- If the strings do match up to the length of the shortest string, then a further comparison is done to test the lengths. Then:

  - The carry flag is set to zero if the first string length is less than the second string length
  - The carry flag is set to one if the first string length is greater than or equal to the length of the second string

  

`LISTING 5.12: The STRCOMP Subroutine Source`

```assembly
*``````````````````````````````*
* STRCMP        (NATHAN RIGGS) *
*                              *
* COMPARES A STRING TO ANOTHER *
* STRING AND SETS THE FLAGS    *
* ACCORDINGLY:                 *
*                              *
* Z = 1 IF STRINGS MATCH       *
* Z = 0 IF STRINGS DON'T MATCH *
*                              *
* IF THE STRINGS MATCH UP TO   *
* THE LENGTH OF THE SHORTEST   *
* STRING, THE STRING LENGTHS   *
* ARE THEN COMPARED AND THE    *
* CARRY FLAG IS SET AS SUCH:   *
*                              *
* C = 0 IF 1ST STRING < 2ND    *
* C = 1 IF 1ST STRING >= 2ND   *
*                              *
* INPUT:                       *
*                              *
*  WPAR1 = 1ST STRING ADDRESS  *
*  WPAR2 = 2ND STRING ADDRESS  *
*                              *
* DESTROY: NZCIDV              *
*          ^^^  ^              *
*                              *
* CYCLES: 68+                  *
* SIZE: 32 BYTES               *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
]STR1    EQU   WPAR1      ; ZP POINTER TO 1ST STRING
]STR2    EQU   WPAR2      ; ZP POINTER TO 2ND STRING
*
STRCMP
*
         LDY   #0         ; {3C2B} RESET .Y COUNTER
         LDA   (]STR1),Y  ; {5C2B} GET LENGTH OF 1ST STRING
         CMP   (]STR2),Y  ; {5C2B} IF STR1 LENGTH < STR2 LENGTH
         BCC   :BEGCMP    ; {3C2B} THEN BEGIN COMPARISON; ELSE
         LDA   (]STR2),Y  ; {5C2B} USE STR2 LENGTH INSTEAD
:BEGCMP
         TAX              ; {2C1B} X IS LENGTH OF SHORTER STRING
         BEQ   :TSTLEN    ; {3C2B} IF LENGTH IS 0, TEST LENGTH
         LDY   #1         ; {3C2B} ELSE SET .Y TO 1ST CHAR
:CMPLP
         LDA   (]STR1),Y  ; {5C2B} GET INDEXED CHAR OF 1ST STRING
         CMP   (]STR2),Y  ; {5C2B} COMPARE TO INDEXED CHAR OF 2ND
         BNE   :EXIT      ; {3C2B} EXIT IF THE CHARS ARE NOT EQUAL
                          ; Z,C WILL BE PROPERLY SET
         INY              ; {2C1B} INCREASE CHARACTER INDEX
         DEX              ; {2C1B} DECREMENT COUNTER
         BNE   :CMPLP     ; {3C2B} CONT UNTIL ALL CHARS CHECKED
:TSTLEN
         LDY   #0         ; {3C2B} NOW COMPARE LENGTHS
         LDA   (]STR1),Y  ; {5C2B} GET LENGTH OF 1ST STRING
         CMP   (]STR2),Y  ; {5C2B} SET OR CLEAR THE FLAGS
:EXIT
         RTS              ; {6C1B}

```



---



### THE SCAT MACRO

_SUMMARY_

| Condition       | Value                                      |
| --------------- | ------------------------------------------ |
| Name            | `SCAT`                                     |
| Type            | Macro                                      |
| File            | `MAC.STRINGS.ASM`                          |
| Author          | Nathan Riggs                               |
| Last Revision   | 12-APR-2021                                |
| Assembler       | Merlin Pro 8                               |
| OS              | Apple DOS 3.3                              |
| Purpose         | Concatenate one string to another          |
| Input           | ]1 = First string <br />]2 = Second string |
| Output          | none                                       |
| Dependencies    | `SUB.STRCAT.ASM`                           |
| Flags Destroyed | NZCV                                       |
| Cycles          | 170+                                       |
| Bytes           | 113 bytes                                  |
| Notes           | None                                       |
| See Also        | `STRCAT`                                   |

---

*DETAILS*

The `STRCAT` macro concatenates two strings, with the string at the second given address attached to the end of the string at the first given address. Like with all of the whole string macros, a new copy of the concatenated strings is passed back via **RETURN**, with its length in **RETLEN**. The length is also available in the **.A ** register.



`LISTING 5.13: The STRCAT Macro Source`

```assembly
*
*``````````````````````````````*
* SCAT          (NATHAN RIGGS) *
*                              *
* CONCATENATE TWO STRINGS      *
*                              *
* PARAMETERS                   *
*                              *
*  ]1 = FIRST STRING           *
*  ]2 = SECOND STRING          *
*                              *
* CYCLES: 170+                 *
* SIZE: 113 BYTES              *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
SCAT     MAC
         STY   SCRATCH    ; {3C2B} BACKUP .Y
         _MSTR ]1;WPAR1   ; {15C14B}
         _MSTR ]2;WPAR2   ; {15C14B}
         JSR   STRCAT     ; {134C81B}
         LDY   SCRATCH    ; {3C2B} RESTORE .Y
         <<<
*

```



---



### THE STRCAT SUBROUTINE

_SUMMARY_

| Condition       | Value                                           |
| --------------- | ----------------------------------------------- |
| Name            | `STRCAT`                                        |
| Type            | Subroutine                                      |
| File            | `SUB.STRCAT.ASM`                                |
| Author          | Nathan Riggs                                    |
| Last Revision   | 12-APR-2021                                     |
| Assembler       | Merlin Pro 8                                    |
| OS              | Apple DOS 3.3                                   |
| Purpose         | Compare two strings                             |
| Input           | WPAR1 = First string<br />WPAR2 = Second string |
| Output          | none                                            |
| Dependencies    | none                                            |
| Flags Destroyed | NZCV                                            |
| Cycles          | 128+                                            |
| Bytes           | 78                                              |
| Notes           | none                                            |
| See Also        | `SCAT`                                          |

---

*DETAILS*

The `STRCAT` subroutine appends (or concatenates) a given second string to a first string. The resulting new string is stored in **RETURN**, with the length stored in **RETLEN.**



`LISTING 5.14: The STRCAT Subroutine Source`

```assembly
*``````````````````````````````*
* STRCAT        (NATHAN RIGGS) *
*                              *
* CONCATENATE TWO STRINGS AND  *
* STORE THE NEW STRING IN      *
* RETURN, WITH THE LENGTH BYTE *
* AT RETLEN.                   *
*                              *
* NOTE THAT THE WHOLE STRING   *
* IS ACTUALLY PLACED IN RETLEN *
* TO ACCOUNT FOR THE LENGTH    *
* BYTE THAT PRECEDES IT.       *
*                              *
* INPUT:                       *
*                              *
*  WPAR1 = 1ST STRING ADDRESS  *
*  WPAR2 = 2ND STRING ADDRESS  *
*                              *
* DESTROY: NZCIDV              *
*          ^^^  ^              *
*                              *
* CYCLES: 128+                 *
* SIZE: 78 BYTES               *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
]S1LEN   EQU   VARTAB+1   ; FIRST STRING LENGTH
]S2LEN   EQU   VARTAB+3   ; SECOND STRING LENGTH
]INDEX   EQU   WPAR3      ; ADDRESS TO PLACE 2ND STRING
]STR2    EQU   WPAR2      ; POINTER TO 2ND STRING
]STR1    EQU   WPAR1      ; POINTER TO 1ST STRING
*
STRCAT
*
         LDY   #0         ; {3C2B} CLEAR INDEX POINTER
         LDA   (]STR1),Y  ; {5C2B} GET LENGTH OF 1ST STRING
         STA   ]S1LEN     ; {4C3B} STORE IN 1ST STRING LENGTH
         LDA   (]STR2),Y  ; {5C2B} GET LENGTH OF 2ND STRING
         STA   ]S2LEN     ; {4C3B} STORE 2ND STRING LENGTH
*
** DETERMINE NUMBER OF CHAR
*
         LDA   ]S2LEN     ; {4C3B} GET 2ND STRING LENGTH
         CLC              ; {2C1B} CLEAR CARRY
         ADC   ]S1LEN     ; {4C3B} ADD TO LENGTH OF 1ST STRING
         STA   RETLEN     ; {4C3B} SAVE SUM OF TWO LENGTHS
         BCC   :DOCAT     ; {3C2B} NO OVERFLOW, JUST CONCATENATE
         LDA   #255       ; {3C2B} OTHERWISE, 255 IS MAX
         STA   RETLEN     ; {4C3B}
*
:DOCAT
*
         LDY   #0         ; {4C3B} OFFSET INDEX BY 1
:CAT1
         INY              ; {2C1B}
         LDA   (]STR1),Y  ; {5C2B} LOAD 1ST STRING INDEXED CHAR
         STA   RETLEN,Y   ; {5C2B} STORE IN RETURN AT SAME INDEX
         CPY   ]S1LEN     ; {4C3B} IF .Y < 1ST STRING LENGTH
         BNE   :CAT1      ; {3C2B} THEN LOOP UNTIL FALSE
*
         TYA              ; {2C1B} TRANSFER COUNTER TO .A
         CLC              ; {2C1B} CLEAR CARRY
         ADC   #<RETLEN   ; {4C3B} ADD LOW BYTE OF RETLEN ADDRESS
         STA   ]INDEX     ; {4C3B} STORE AS NEW ADDRESS LOW BYTE
         LDA   #0         ; {3C2B} NOW ADJUST HIGH BYTE
         ADC   #>RETLEN+1 ; {4C3B} OF NEW ADDRESS
         STA   ]INDEX+1   ; {4C3B} AND STORE HIGH BYTE
         CLC              ; {2C1B} RESET CARRY
         LDY   #0         ; {3C2B}
*
:CAT2
         INY              ; {2C1B}
         LDA   (]STR2),Y  ; {5C2B} LOAD 2ND STRING INDEXED CHAR
         STA   (]INDEX),Y ; {5C2B} STORE AT NEW ADDRESS
         CPY   RETLEN     ; {4C3B} IF .Y < 2ND STRING LENGTH
         BEQ   :EXIT      ; {3C2B}
         BNE   :CAT2      ; {3C2B} LOOP UNTIL FALSE
:EXIT
         LDA   RETLEN     ; {4C3B} RETURN NEW LENGTH IN .A
         RTS              ; {6C2B}

```



---



### THE STRIM MACRO

_SUMMARY_

| Condition       | Value                                                    |
| --------------- | -------------------------------------------------------- |
| Name            | `STRIM`                                                  |
| Type            | Macro                                                    |
| File            | `MAC.STRINGS.ASM`                                        |
| Author          | Nathan Riggs                                             |
| Last Revision   | 12-APR-2021                                              |
| Assembler       | Merlin Pro 8                                             |
| OS              | Apple DOS 3.3                                            |
| Purpose         | Trim a token from the beginning and<br />end of a string |
| Input           | ]1 = String <br />]2 = Token                             |
| Output          | none                                                     |
| Dependencies    | `SUB.STRTRIM.ASM`                                        |
| Flags Destroyed | NZCV                                                     |
| Cycles          | 123+                                                     |
| Bytes           | 80                                                       |
| Notes           | None                                                     |
| See Also        | `STRTRIM`                                                |

---

*DETAILS*

The `STRIM` macro trims a single character (like a space) from the beginning and end of a string, if said character is present on either end. The new string is stored in **RETURN** with its length in **RETLEN**, which is also passed back via the **.A** register.



`LISTING 5.15: The STRIM Macro Source`

```assembly
*
*``````````````````````````````*
* STRIM         (NATHAN RIGGS) *
*                              *
* CONCATENATE TWO STRINGS      *
*                              *
* PARAMETERS                   *
*                              *
*  ]1 = STRING ADDRESS         *
*  ]2 = DELIMITER              *
*                              *
* CYCLES: 123+                 *
* SIZE: 80 BYTES               *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
STRIM    MAC
         _MSTR ]1;WPAR1   ; {15C14B}
         LDA   ]2         ; {4C3B}
         STA   WPAR2      ; {3C2B}
         JSR   STRTRIM    ; {101C61B}
         <<<
*

```



---



### THE STRTRIM SUBROUTINE

_SUMMARY_

| Condition       | Value                             |
| --------------- | --------------------------------- |
| Name            | `STRTRIM`                         |
| Type            | Subroutine                        |
| File            | `SUB.STRTRIM.ASM`                 |
| Author          | Nathan Riggs                      |
| Last Revision   | 12-APR-2021                       |
| Assembler       | Merlin Pro 8                      |
| OS              | Apple DOS 3.3                     |
| Purpose         | Compare two strings               |
| Input           | WPAR1 = String<br />WPAR2 = Token |
| Output          | none                              |
| Dependencies    | none                              |
| Flags Destroyed | NZCV                              |
| Cycles          | 95+                               |
| Bytes           | 58                                |
| Notes           | none                              |
| See Also        | `STRIM`                           |

---

*DETAILS*

The `STRTRIM` subroutine trims a specified token from the beginning and end of a string at a given address. Once executed, the new string is held in **RETURN**, with its length held in **RETLEN**. This length is also passed back via the **.A** register.



`LISTING 5.16: The STRTRIM Subroutine Source`

```assembly
*``````````````````````````````*
* STRTRIM       (NATHAN RIGGS) *
*                              *
* STRTRIM CUTS THE SPECIFIED   *
* CHARACTER FROM THE FRONT AND *
* END OF THE GIVEN STRING, IF  *
* IT EXISTS.                   *
*                              *
* INPUT:                       *
*                              *
*  WPAR1 = STRING ADDRESS      *
*  WPAR2 = DELIMITER           *
*                              *
* DESTROY: NZCIDV              *
*          ^^^  ^              *
*                              *
* CYCLES: 95+                  *
* SIZE: 58 BYTES               *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
]STR     EQU   WPAR1      ; STRING ADDRESS
]DELIM   EQU   WPAR2      ; DELIMITER
]RET     EQU   WPAR3      ; RETURN AREA
]LEN     EQU   BPAR1      ; STRING LENGTH
*
STRTRIM
         LDY   #0         ; {3C2B} RESET .Y COUNTER
         LDA   (]STR),Y   ; {5C3B} GET STRING LENGTH
         STA   ]LEN       ; {3C2B} STORE IN TEMP VARIABLE
         TYA              ; {2C1B} RESET .A
         TAX              ; {2C1B} RESET .X
:FIRST
         LDY   #1         ; {3C2B} LOAD FIRST CHAR OF STRING
         LDA   (]STR),Y   ; {5C3B}
         CMP   ]DELIM     ; {3C2B} COMPARE TO THE DELIMITER
         BNE   :NOFIRST   ; {3C2B} IF NO MATCH, SKIP TO :NOFIRST
         LDX   #255       ; {3C2B} IF MATCHED, SET X TO -1
         LDY   #1         ; {3C2B} AND SET Y TO 1
         JMP   :COPY      ; {3C3B} JUMP OVER TO COPYING
:NOFIRST
         LDX   #255       ; {3C2B} SET .X TO -1
         LDY   #0         ; {3C2B} SET .Y TO 0
:COPY
         INY              ; {2C1B} INCREASE .Y
         INX              ; {2C1B} INCREASAE .X
         LDA   (]STR),Y   ; {5C3B} LOAD CHAR FROM STRING AT .Y
         STA   RETURN,X   ; {5C3B} STORE IN RETURN AT .X
         CPY   ]LEN       ; {3C2B} IF .Y != STRING LENGTH
         BNE   :COPY      ; {3C2B} THEN RELOOP COPYING
:LAST
         LDY   ]LEN       ; {3C2B} LOAD LENGTH INTO .Y
         LDA   (]STR),Y   ; {5C3B} LOAD LAST CHAR OF STRING
         CMP   ]DELIM     ; {3C2B} IF NOT EQUAL TO DELIMITER
         BNE   :EXIT      ; {3C2B} THEN GOTO EXIT
         DEC   ]LEN       ; {2C1B} OTHERWISE, DECREASE LENGTH
:EXIT
         LDY   ]LEN       ; {3C2B} LOAD (POSSIBLY) ALTERED LENGTH
         STY   RETLEN     ; {4C3B} STORE IN RETLEN
         TYA              ; {2C1B} PASS LENGTH IN .A REGISTER
         RTS              ; {6C1B}

```



---



### THE STRUP MACRO

_SUMMARY_

| Condition       | Value                                             |
| --------------- | ------------------------------------------------- |
| Name            | `STRUP`                                           |
| Type            | Macro                                             |
| File            | `MAC.STRINGS.ASM`                                 |
| Author          | Nathan Riggs                                      |
| Last Revision   | 12-APR-2021                                       |
| Assembler       | Merlin Pro 8                                      |
| OS              | Apple DOS 3.3                                     |
| Purpose         | Turn a string into its<br />uppercase equivalent. |
| Input           | ]1 = String                                       |
| Output          | none                                              |
| Dependencies    | `SUB.STRUPPER.ASM`                                |
| Flags Destroyed | NZCV                                              |
| Cycles          | 114+                                              |
| Bytes           | 64                                                |
| Notes           | None                                              |
| See Also        | `SUB.STRUPPER.ASM`                                |

---

*DETAILS*

The `STRUP` macro accepts a string or address to a string and transforms it into a string that represents its uppercase equivalent. This new string is passed back in **RETURN**, with the length held in **RETLEN**. The length is also available in the **.A** register.



`LISTING 5.17: The STRUP Macro Source`

```assembly
*
*``````````````````````````````*
* STRUP         (NATHAN RIGGS) *
*                              *
* CONVERTS A STRING TO ITS     *
* UPPERCASE EQUIVALENT.        *
*                              *
* PARAMETERS                   *
*                              *
*  ]1 = STRING ADDRESS         *
*                              *
* CYCLES: 114+                 *
* SIZE: 64 BYTES               *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
STRUP    MAC
         _MSTR ]1;WPAR1   ; {15C14B}
         JSR   STRUPPER   ; {99C50B}
         <<<
*

```



---



### THE STRUPPER SUBROUTINE

_SUMMARY_

| Condition       | Value                         |
| --------------- | ----------------------------- |
| Name            | `STRUPPER`                    |
| Type            | Subroutine                    |
| File            | `SUB.STRUPPER.ASM`            |
| Author          | Nathan Riggs                  |
| Last Revision   | 12-APR-2021                   |
| Assembler       | Merlin Pro 8                  |
| OS              | Apple DOS 3.3                 |
| Purpose         | Convert a string to uppercase |
| Input           | WPAR1 = String address        |
| Output          | none                          |
| Dependencies    | none                          |
| Flags Destroyed | NZCV                          |
| Cycles          | 93+                           |
| Bytes           | 47                            |
| Notes           | none                          |
| See Also        | `STRUP`                       |

---

*DETAILS*

The `STRUPPER` subroutine accepts a string address and passes back a string via **RETURN** that is an all-uppercase equivalent of the string, with its length stored in both **RETLEN** and in the **.A** register.



`LISTING 5.18: The STRUPPER Subroutine Source`

```assembly
*``````````````````````````````*
* STRUPPER      (NATHAN RIGGS) *
*                              *
* THIS SUBROUTINE ACCEPTS A    *
* STRING AND PASSES BACK A NEW *
* STRING THAT IS ITS UPPERCASE *
* EQUIVALENT.                  *
*                              *
* INPUT:                       *
*                              *
*  WPAR1 = STRING ADDRESS      *
*                              *
* DESTROY: NZCIDV              *
*          ^^^  ^              *
*                              *
* CYCLES: 93+                  *
* SIZE: 47 BYTES               *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
]STR     EQU   WPAR1      ; STRING ADDRESS
]LEN     EQU   BPAR1      ; STRING LENGTH
]RET     EQU   WPAR2      ; REUTURN ADDRESS
*
STRUPPER
*
         LDA   #0         ; {3C2B} RESET .A REGISTER
         TAX              ; {2C1B} RESET .X
         TAY              ; {2C1B} RESET .Y
         LDA   (]STR),Y   ; {5C2B} GET THE STRING LENGTH
         STA   ]LEN       ; {3C2B} AND STORE IN ]LEN
         INC   ]LEN       ; {5C2B} TEMPORARILY INCREASE LENGTH
         LDY   #255       ; {3C2B} COUNTER = -1
:COPYLP
         INY              ; {2C1B} INCREASE INDEX COUNTER
         LDA   (]STR),Y   ; {5C2B} LOAD CHARACTER FROM STRING
         STA   RETLEN,Y   ; {5C2B} STORE IN RETURN AREA AT INDEX
         CPY   ]LEN       ; {3C2B} IF .Y != STRING LENGTH
         BNE   :COPYLP    ; {3C2B} KEEP LOOPING UNTIL ALL COPIED
*
         LDY   #0         ; {3C2B} RESET INDEX COUNTER
         DEC   ]LEN       ; {5C2B} LENGTH BACK TO NORMAL
:MAINLP
         INY              ; {2C1B} INCREASE INDEX COUNTER
         LDA   RETLEN,Y   ; {5C2B} LOAD CHARACTER FROM RETURN
         CMP   #225       ; {3C2B} IS IT < LOWERCASE A?
         BCC   :RELOOP    ; {3C2B} IF SO, LOOP TO NEXT CHAR
         CMP   #251       ; {3C2B} IS IT >= LOWERCASE Z?
         BCS   :RELOOP    ; {3C2B} IF SO, LOOP TO NEXT CHAR
         SEC              ; {2C1B} ELSE, WE FOUND A LOWERCASE LETTER
         SBC   #32        ; {3C2B} SO SUBTRACT 32 TO GET UPPERCASE
         STA   RETLEN,Y   ; {5C2B} AND REPLACE THE LETTER IN RETURN
:RELOOP  CPY   ]LEN       ; {3C2B} NOW CHECK IF Y = LENGTH
         BNE   :MAINLP    ; {3C2B} AND IF NOT, CONTINUE LOOP
:EXIT
         TYA              ; {2C1B} SEND BACK LENGTH IN .A
         RTS              ; {6C1B}

```



---



### THE SLO MACRO

_SUMMARY_

| Condition       | Value                                             |
| --------------- | ------------------------------------------------- |
| Name            | `SLO`                                             |
| Type            | Macro                                             |
| File            | `MAC.STRINGS.ASM`                                 |
| Author          | Nathan Riggs                                      |
| Last Revision   | 12-APR-2021                                       |
| Assembler       | Merlin Pro 8                                      |
| OS              | Apple DOS 3.3                                     |
| Purpose         | Turn a string into its<br />lowercase equivalent. |
| Input           | ]1 = String                                       |
| Output          | none                                              |
| Dependencies    | `SUB.STRLOWER.ASM`                                |
| Flags Destroyed | NZCV                                              |
| Cycles          | 113+                                              |
| Bytes           | 64                                                |
| Notes           | None                                              |
| See Also        | `SUB.STRLOWER.ASM`                                |

---

*DETAILS*

The `STRLO` macro accepts a string or a string address and returns the lowercase equivalent of the string in **RETURN**, with its length passed back in both **RETLEN** and the **.A** register.



`LISTING 5.19: The SLO Macro Source`

```assembly
*
*``````````````````````````````*
* STRLO         (NATHAN RIGGS) *
*                              *
* CONVERTS A STRING TO ITS     *
* LOWERCASE EQUIVALENT.        *
*                              *
* PARAMETERS                   *
*                              *
*  ]1 = STRING ADDRESS         *
*                              *
* CYCLES: 113+                 *
* SIZE: 64 BYTES               *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
STRLO    MAC
         _MSTR ]1;WPAR1   ; {15C14B}
         JSR   STRLOWER   ; {98C50B}
         <<<
*
```



---



### THE STRLOWER SUBROUTINE

_SUMMARY_

| Condition       | Value                         |
| --------------- | ----------------------------- |
| Name            | `STRLOWER`                    |
| Type            | Subroutine                    |
| File            | `SUB.STRLOWER.ASM`            |
| Author          | Nathan Riggs                  |
| Last Revision   | 12-APR-2021                   |
| Assembler       | Merlin Pro 8                  |
| OS              | Apple DOS 3.3                 |
| Purpose         | Convert a string to lowercase |
| Input           | WPAR1 = String address        |
| Output          | none                          |
| Dependencies    | none                          |
| Flags Destroyed | NZCV                          |
| Cycles          | 92+                           |
| Bytes           | 47                            |
| Notes           | none                          |
| See Also        | `SLO`                         |

---

*DETAILS*

The `STRLOWER` subroutine accepts an address that holds a string and converts the string to its lowercase equivalent, storing the new string in **RETURN** with its preceding length-byte in **RETLEN**. The length is also passed back via the **.A** register.



`LISTING 5.20: The STRLOWER Subroutine Source`

```assembly
*``````````````````````````````*
* STRLOWER      (NATHAN RIGGS) *
*                              *
* THIS SUBROUTINE ACCEPTS A    *
* STRING AND PASSES BACK A NEW *
* STRING THAT IS ITS LOWERCASE *
* EQUIVALENT.                  *
*                              *
* INPUT:                       *
*                              *
*  WPAR1 = STRING ADDRESS      *
*                              *
* DESTROY: NZCIDV              *
*          ^^^  ^              *
*                              *
* CYCLES: 92+                  *
* SIZE: 47 BYTES               *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
]STR     EQU   WPAR1      ; STRING ADDRESS
]LEN     EQU   BPAR1      ; STRING LENGTH
]RET     EQU   WPAR2      ; REUTURN ADDRESS
*
STRLOWER
*
         LDA   #0         ; {3C2B} RESET .A REGISTER
         TAX              ; {2C1B} RESET .X
         TAY              ; {2C1B} RESET .Y
         LDA   (]STR),Y   ; {5C2B} GET THE STRING LENGTH
         STA   ]LEN       ; {3C2B} AND STORE IN ]LEN
         INC   ]LEN       ; {5C2B} TEMPORARILY INCREASE LENGTH
         LDY   #255       ; {3C2B} COUNTER = -1
:COPYLP
         INY              ; {2C1B} INCREASE INDEX COUNTER
         LDA   (]STR),Y   ; {5C2B} LOAD CHARACTER FROM STRING
         STA   RETLEN,Y   ; {5C2B} STORE IN RETURN AREA AT INDEX
         CPY   ]LEN       ; {3C2B} IF .Y != STRING LENGTH
         BNE   :COPYLP    ; {3C2B} KEEP LOOPING UNTIL ALL COPIED
*
         LDY   #0         ; {3C2B} RESET INDEX COUNTER
         DEC   ]LEN       ; {5C2B} LENGTH BACK TO NORMAL
:MAINLP
         INY              ; {2C1B} INCREASE INDEX COUNTER
         LDA   RETLEN,Y   ; {5C2B} LOAD CHARACTER FROM RETURN
         CMP   #193       ; {3C2B} IS IT < UPPERCASE A?
         BCC   :RELOOP    ; {3C2B} IF SO, LOOP TO NEXT CHAR
         CMP   #219       ; {3C2B} IS IT >= UPPERCASE Z?
         BCS   :RELOOP    ; {3C2B} IF SO, LOOP TO NEXT CHAR
         CLC              ; {2C1B} ELSE, FOUND AN UPPERCASE LETTER
         ADC   #32        ; {3C2B} SO ADD 32 TO GET LOWERCASE
         STA   RETLEN,Y   ; {5C2B} AND REPLACE THE LETTER IN RETURN
:RELOOP  CPY   ]LEN       ; {3C2B} NOW CHECK IF Y = LENGTH
         BNE   :MAINLP    ; {3C2B} AND IF NOT, CONTINUE LOOP
:EXIT
         TYA              ; {2C1B} SEND BACK LENGTH IN .A
         RTS              ; {6C1B}

```



---



### THE SREV MACRO

_SUMMARY_

| Condition       | Value             |
| --------------- | ----------------- |
| Name            | `SREV`            |
| Type            | Macro             |
| File            | `MAC.STRINGS.ASM` |
| Author          | Nathan Riggs      |
| Last Revision   | 12-APR-2021       |
| Assembler       | Merlin Pro 8      |
| OS              | Apple DOS 3.3     |
| Purpose         | Reverse a string. |
| Input           | ]1 = String       |
| Output          | none              |
| Dependencies    | `SUB.STRREV.ASM`  |
| Flags Destroyed | NZCV              |
| Cycles          | 70+               |
| Bytes           | 41                |
| Notes           | None              |
| See Also        | `SUB.STRREV.ASM`  |

---

*DETAILS*

The `SREV` macro accepts a string or a string's address and passes back a copy of that string in reverse. This new string is passed back via **RETURN**, with the length-byte held in **RETLEN**. The length can also be retrieved in the **.A** register.



`LISTING 5.21: The SREV Macro Source`

```assembly
*
*``````````````````````````````*
* SREV          (NATHAN RIGGS) *
*                              *
*                              *
* PARAMETERS                   *
*                              *
*  ]1 = STRING ADDRESS         *
*                              *
* CYCLES: 70+                  *
* SIZE: 41 BYTES               *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
SREV     MAC
         _MSTR ]1;WPAR1   ; {14C13B}
         JSR   STRREV     ; {56C28B}
         <<<

```



---



### THE STRREV SUBROUTINE

_SUMMARY_

| Condition       | Value                  |
| --------------- | ---------------------- |
| Name            | `STRREV`               |
| Type            | Subroutine             |
| File            | `SUB.STRREV.ASM`       |
| Author          | Nathan Riggs           |
| Last Revision   | 12-APR-2021            |
| Assembler       | Merlin Pro 8           |
| OS              | Apple DOS 3.3          |
| Purpose         | reverse a string       |
| Input           | WPAR1 = String address |
| Output          | none                   |
| Dependencies    | none                   |
| Flags Destroyed | NZCV                   |
| Cycles          | 50+                    |
| Bytes           | 25                     |
| Notes           | none                   |
| See Also        | `SREV`                 |

---

*DETAILS*

The `STRREV` subroutine accepts a string address and then passes back a copy of the string reversed in **RETURN.** The length is held in both **RETLEN** and in the **.A** register.



`LISTING 5.22: The STRREV Subroutine Source`

```assembly
*``````````````````````````````*
* STRREV        (NATHAN RIGGS) *
*                              *
* REVERSE A STRING.            *
*                              *
* INPUT:                       *
*                              *
*  WPAR1 = STRING ADDRESS      *
*                              *
* DESTROY: NZCIDV              *
*          ^^^  ^              *
*                              *
* CYCLES: 50+                  *
* SIZE: 25 BYTES               *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
]STR     EQU   WPAR1      ; STRING ADDRESS
]REV     EQU   RETLEN     ; REVERSE STRING ADDRESS
]LEN     EQU   BPAR1      ; STRING LENGTH
*
STRREV
         LDY   #0         ; {3C2B} CLEAR .Y REGISTER
         LDX   #0         ; {3C2B} CLEAR .X REGISTER
         LDA   (]STR),Y   ; {5C2B} LOAD STRING LENGTH
         STA   ]LEN       ; {3C2B} AND STORE IN ]LEN
         TAY              ; {2C1B} TRANSFER LENGTH TO .Y INDEX
         INY              ; {2C1B} INCREASE BY ONE
*
:LP1
         INX              ; {2C1B} INCREASE .X COUNTER
         DEY              ; {2C1B} DECREASE .Y COUNTER
         LDA   (]STR),Y   ; {5C2B} LOAD CHAR FROM BACK OF STRING
         STA   ]REV,X     ; {5C2B} STORE IN REVERSE ADDRESS
         CPX   ]LEN       ; {3C2B} COMPARE .X COUNTER TO LENGTH
         BNE   :LP1       ; {3C2B} IF !=, THEN RELOOP
:EXIT
         TXA              ; {2C1B} MOVE LENGTH TO .A REGISTER
         STX   RETLEN     ; {4C3B} ALSO STORE IN RETLEN
         RTS              ; {6C1B}

```



---



### THE SCAP MACRO

_SUMMARY_

| Condition       | Value                                                        |
| --------------- | ------------------------------------------------------------ |
| Name            | `SCAP`                                                       |
| Type            | Macro                                                        |
| File            | `MAC.STRINGS.ASM`                                            |
| Author          | Nathan Riggs                                                 |
| Last Revision   | 12-APR-2021                                                  |
| Assembler       | Merlin Pro 8                                                 |
| OS              | Apple DOS 3.3                                                |
| Purpose         | Capitalize characters in a string<br />based on punctuation. |
| Input           | ]1 = String                                                  |
| Output          | none                                                         |
| Dependencies    | `SUB.STRCAP.ASM`                                             |
| Flags Destroyed | NZCV                                                         |
| Cycles          | 192+                                                         |
| Bytes           | 117                                                          |
| Notes           | None                                                         |
| See Also        | `SUB.STRCAP.ASM`                                             |

---

*DETAILS*

The `SCAP` macro accepts a string or string address and returns a copy of the string with the appropriate letters capitalized, including the first letter of the string. This can be used in conjunction with the `SLO` macro to get a properly formatted copy of a string that was previously in all uppercase.

The new string is passed back via **RETURN** with its length in **RETLEN.**



`LISTING 5.23: The SCAP Macro Source`

```assembly
*
*``````````````````````````````*
* SCAP          (NATHAN RIGGS) *
*                              *
* CAPITALIZES THE APPROPRIATE  *
* CHARACTERS IN A LOWERCASE    *
* STRING.                      *
*                              *
* PARAMETERS                   *
*                              *
*  ]1 = STRING ADDRESS         *
*                              *
* CYCLES: 192+                 *
* SIZE: 117 BYTES              *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
SCAP     MAC
         _MSTR ]1;WPAR1   ; {15C14B}
         JSR   STRCAP     ; {177C103B}
         <<<
*

```



---



### THE STRCAP SUBROUTINE

_SUMMARY_

| Condition       | Value                                                  |
| --------------- | ------------------------------------------------------ |
| Name            | `STRCAP`                                               |
| Type            | Subroutine                                             |
| File            | `SUB.STRCAP.ASM`                                       |
| Author          | Nathan Riggs                                           |
| Last Revision   | 12-APR-2021                                            |
| Assembler       | Merlin Pro 8                                           |
| OS              | Apple DOS 3.3                                          |
| Purpose         | capitalize the beginning of<br />sentences in a string |
| Input           | WPAR1 = String                                         |
| Output          | none                                                   |
| Dependencies    | none                                                   |
| Flags Destroyed | NZCV                                                   |
| Cycles          | 171+                                                   |
| Bytes           | 100                                                    |
| Notes           | none                                                   |
| See Also        | `SCAP`                                                 |

---

*DETAILS*

The `STRCAP` subroutine accepts an address that points to a string, then creates a copy of that string in **RETURN** with the first letter of every sentence capitalized, including the first letter of the string. The length is passed back via **RETLEN** as well as in the **.A ** register.



`LISTING 5.24: The STRCAP Subroutine Source`

```assembly
*``````````````````````````````*
* STRCAP        (NATHAN RIGGS) *
*                              *
* THIS SUBROUTINE TAKES A      *
* STRING OF LOWERCASE LETTERS  *
* AND CAPITALIZES LETTERS WHEN *
* IT IS APPROPRIATE--AFTER A   *
* PERIOD, ETC.                 *
*                              *
* INPUT:                       *
*                              *
*  WPAR1 = STRING ADDRESS      *
*                              *
* DESTROY: NZCIDV              *
*          ^^^  ^              *
*                              *
* CYCLES: 171+                 *
* SIZE: 100 BYTES              *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
]STR     EQU   WPAR1      ; STRING ADDRESS
]LEN     EQU   BPAR1      ; STRING LENGTH
]FLAG    EQU   WPAR2      ; CAPITALIZATION FLAG
*
STRCAP
*
         LDA   #0         ; {3C2B} RESET .A REGISTER
         TAX              ; {2C1B} RESET .X
         TAY              ; {2C1B} RESET .Y
         STA   ]FLAG      ; {3C2B}
         LDA   (]STR),Y   ; {5C2B} GET THE STRING LENGTH
         STA   ]LEN       ; {3C2B} AND STORE IN ]LEN
         INC   ]LEN       ; {5C2B} TEMPORARILY INCREASE LENGTH
         LDY   #255       ; {3C2B} COUNTER = -1
:COPYLP
         INY              ; {2C1B} INCREASE INDEX COUNTER
         LDA   (]STR),Y   ; {5C2B} LOAD CHARACTER FROM STRING
         STA   RETLEN,Y   ; {5C2B} STORE IN RETURN AREA AT INDEX
         CPY   ]LEN       ; {3C2B} IF .Y != STRING LENGTH
         BNE   :COPYLP    ; {3C2B} KEEP LOOPING UNTIL ALL COPIED
*
         LDY   #0         ; {3C2B} RESET INDEX COUNTER
         DEC   ]LEN       ; {5C2B} LENGTH BACK TO NORMAL
:MAINLP
         INY              ; {2C1B} INCREASE INDEX COUNTER
         LDA   RETLEN,Y   ; {5C2B} GET CHARACTER FROM STRING
         CMP   #"."       ; {3C2B} IS IT A PERIOD?
         BEQ   :SETFLAG   ; {3C2B} IF SO, SET CAPITAL FLAG
         CMP   #"?"       ; {3C2B} IS IT A QUESTION MARK?
         BEQ   :SETFLAG   ; {3C2B} IF SO, SET CAPITAL FLAG
         CMP   #"!"       ; {3C2B} IS IT AN EXCLAMATION MARK?
         BEQ   :SETFLAG   ; {3C2B} IF SO, SET CAPITAL FLAG
*
         CMP   #225       ; {3C2B} COMPARE TO LOWERCASE A
         BCC   :RELOOP    ; {3C2B} IF ASCII < THAT, DO NOT REPLACE
         CMP   #251       ; {3C2B} COMPARE TO LOWERCASE Z
         BCS   :RELOOP    ; {3C2B} IF ASCII >= THAT, DON'T REPLACE
*
         LDX   ]FLAG      ; {3C2B} LOAD CAPITALIZATION FLAG
         CPX   #1         ; {3C2B} COMPARE TO #1 (SET)
         BNE   :RELOOP    ; {3C2B} IF NOT SET, LOOP TO NEXT CHAR
         SEC              ; {2C1B} IF SET, THEN SET CARRY
         SBC   #32        ; {3C2B} SUBTRACT #32 ASCII
         STA   RETLEN,Y   ; {5C2B} STORE OVER TOP LOWERCASE
         LDX   #0         ; {3C2B} CLEAR .X REGISTER
         STX   ]FLAG      ; {3C2B} AND CLEAR CAPITALIZATION FLAG
:RELOOP  CPY   ]LEN       ; {3C2B} NOW CHECK IF Y = LENGTH
         BNE   :MAINLP    ; {3C2B} AND IF NOT, CONTINUE LOOP
         JMP   :EXIT      ; {3C3B} IF SO, JUMP TO EXIT
:SETFLAG
         LDX   #1         ; {3C2B} LOAD #1 IN .X REGISTER
         STX   ]FLAG      ; {3C2B} STORE IN FLAG (MEANING IT IS SET)
         JMP   :RELOOP    ; {3C3B} LOOP TO NEXT CHARACTER
:EXIT
         LDY   #1         ; {3C2B} LOAD FIRST LETTER OF STRING
         LDA   RETLEN,Y   ; {5C2B}
         CMP   #225       ; {3C2B} COMPARE TO LOWERCASE A
         BCC   :EXIT2     ; {3C2B} IF < LC A, EXIT FOR REAL
         CMP   #251       ; {3C2B} COMPARE TO LOWERCASE Z
         BCS   :EXIT2     ; {3C2B} IF >= LC Z, EXIT FOR REAL
         SEC              ; {2C1B} OTHERWISE, SET THE CARRY
         SBC   #32        ; {3C2B} AND SUBTRACT 32 FROM ASCII
         STA   RETLEN,Y   ; {5C2B} AND STORE OVER TOP FIRST CHAR
:EXIT2
         LDA   ]LEN       ; {3C2B} SEND BACK LENGTH IN .A
         RTS              ; {6C1B}

```



---



### Substring Macros

The macros contained here are dedicated to operations on substrings, which we define as strings pulled from parts of another string. Put together, the macros and subroutines available here should be enough to create more complicated routines for substring manipulation, such as searching and replacing, counting substring repetitions, and so on.

 

`LISTING 5.30: MAC.SUBSTRINGS.ASM Header Source`

```assembly
*``````````````````````````````*
* MAC.SUBSTRINGS.ASM           *
*                              *
* THIS FILE CONTAINS ALL OF    *
* THE MACROS RELATED TO        *
* SUBSTRING MANIPULATION.      *
*                              *
* AUTHOR:    NATHAN RIGGS      *
* CONTACT:   NATHAN.RIGGS@     *
*            OUTLOOK.COM       *
*                              *
* DATE:      12-APR-2021       *
* ASSEMBLER: MERLIN 8 PRO      *
* OS:        DOS 3.3           *
*                              *
* SUBROUTINE FILES USED        *
*                              *
* SUB.SUBCOPY.ASM              *
* SUB.SUBDEL.ASM               *
* SUB.SUBINS.ASM               *
* SUB.SUBPOS.ASM               *
* SUB.SUBCHARCNT.ASM           *
* SUB.SUBTOK.ASM               *
*                              *
* LIST OF MACROS               *
*                              *
* SPOS : FIND SUBSTRING POS    *
* SCOP : SUBSTRING COPY        *
* SDEL : SUBSTRING DELETE      *
* SINS : SUBSTRING INSERT      *
* STOK : TOKENIZED SUBSTRING   *
* SCNT : CHARACTER COUNT       *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*

```



---



### THE SPOS MACRO

_SUMMARY_

| Condition       | Value                                                    |
| --------------- | -------------------------------------------------------- |
| Name            | `SPOS`                                                   |
| Type            | Macro                                                    |
| File            | `MAC.SUBSTRINGS.ASM`                                     |
| Author          | Nathan Riggs                                             |
| Last Revision   | 12-APR-2021                                              |
| Assembler       | Merlin Pro 8                                             |
| OS              | Apple DOS 3.3                                            |
| Purpose         | Find the position of a substring<br />in another string. |
| Input           | ]1 = Source string<br />]2 = Substring                   |
| Output          | none                                                     |
| Dependencies    | `SUB.SUBPOS.ASM`                                         |
| Flags Destroyed | NZCV                                                     |
| Cycles          | 205+                                                     |
| Bytes           | 136                                                      |
| Notes           | None                                                     |
| See Also        | `SUB.SUBPOS.ASM`                                         |

---

*DETAILS*

The `SPOS`macro finds the position of a given substring within a larger string. The one byte index is stored in **RETURN** as well as in the **.A** register.



`LISTING 5.31: The SCPOS Macro Source`

```assembly
*
*``````````````````````````````*
* SPOS          (NATHAN RIGGS) *
*                              *
* FIND THE POSITION OF A SUB-  *
* STRING IN A GIVEN STRING.    *
*                              *
* PARAMETERS                   *
*                              *
*  ]1 = SOURCE STRING          *
*  ]2 = SUBSTRING              *
*                              *
* CYCLES: 205+                 *
* SIZE: 136 BYTES              *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
SPOS     MAC
         _MSTR ]1;WPAR2   ; {14C13B}
         _MSTR ]2;WPAR1   ; {14C13B}
         JSR   SUBPOS     ; {177C110B}
         <<<
*

```



---



### THE SUBPOS SUBROUTINE

_SUMMARY_

| Condition       | Value                                                 |
| --------------- | ----------------------------------------------------- |
| Name            | `SUBPOS`                                              |
| Type            | Subroutine                                            |
| File            | `SUB.SUBPOS.ASM`                                      |
| Author          | Nathan Riggs                                          |
| Last Revision   | 12-APR-2021                                           |
| Assembler       | Merlin Pro 8                                          |
| OS              | Apple DOS 3.3                                         |
| Purpose         | find index of substring                               |
| Input           | WPAR1 = Substring address<br />WPAR2 = String address |
| Output          | none                                                  |
| Dependencies    | none                                                  |
| Flags Destroyed | NZCV                                                  |
| Cycles          | 171+                                                  |
| Bytes           | 107                                                   |
| Notes           | none                                                  |
| See Also        | `SPOS`                                                |

---

*DETAILS*

The `SUBPOS` macro finds the index position of a substring within a string, both of which are pointed to by the subroutine's arguments. The position is a single byte length, and is held in **RETURN** and in the **.A** register. If no substring is found, then a value of #255 ($FF) is returned.



`LISTING 5.32: The SUBPOS Subroutine Source`

```assembly
*``````````````````````````````*
* SUBPOS        (NATHAN RIGGS) *
*                              *
* RETURNS THE POSITION OF A    *
* SUBSTRING IN A GIVEN STRING. *
* IF NO SUBSTRING IS FOUND,    *
* THEN #255 IS PASSED BACK     *
* INSTEAD.                     *
*                              *
* INPUT:                       *
*                              *
*  WPAR1 = SUBSTRING (ADDRESS) *
*  WPAR2 = STRING ADDRESS      *
*                              *
* DESTROYS: NZCIDV             *
*           ^^^  ^             *
*                              *
* CYCLES: 171+                 *
* SIZE: 107 BYTES              *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
]STRIND  EQU   VARTAB     ; STRING INDEX
]SUBIND  EQU   VARTAB+1   ; SUBSTRING INDEX
]CNT     EQU   VARTAB+2   ; COUNTER
]STRLEN  EQU   VARTAB+3   ; STRING LENGTH
]SUBLEN  EQU   VARTAB+4   ; SUBSTRING LENGTH
]SIDX    EQU   VARTAB+6   ; STRING INDEX
]SUB     EQU   WPAR1      ; ZP SUBSTRING ADDR PTR
]STR     EQU   WPAR2      ; ZP STRING ADDR POINTER
*
SUBPOS
         LDY   #0         ; {3C2B} RESET INDEX COUNTER
         LDA   (]STR),Y   ; {5C2B} GET LENGTH OF STRING
         BEQ   :NOTFND    ; {3C2B} EXIT IF LENGTH = 0
         STA   ]STRLEN    ; {4C3B} STORE STRING LENGTH
         LDA   (]SUB),Y   ; {5C2B} GET SUBSTR LENGTH
         BEQ   :NOTFND    ; {3C2B} EXIT IF SUB LENGTH = 0
         STA   ]SUBLEN    ; {4C3B} STORE SUBSTRING LENGTH
         LDA   ]SUBLEN    ; {4C3B} IF SUBSTRING LENGTH IS
         CMP   ]STRLEN    ; {4C3B} > STRING LENGTH, DECLARE
         BEQ   :LENOK     ; {3C2B} THE STRING NOT FOUND
         BCS   :NOTFND    ; {3C2B} OTHERWISE, CONTINUE
:LENOK
         LDA   #1         ; {3C2B} SET STRING INDEX TO
         STA   ]STRIND    ; {4C3B} THE FIRST CHARACTER
         LDA   ]STRLEN    ; {4C3B} GET STRING LENGTH
         SEC              ; {2C1B} SET CARRY
         SBC   ]SUBLEN    ; {4C3B} SUBTRACT SUBSTRING LENGTH
         STA   ]CNT       ; {4C3B} STORE AS COUNTER
         INC   ]CNT       ; {5C2B} INCREASE BY 1
:SLP1
         LDA   ]STRIND    ; {4C3B}
         STA   ]SIDX      ; {4C3B}
         LDA   #1         ; {3C2B} START SUBSTRING INDEX
         STA   ]SUBIND    ; {4C3B} AT 1
:CMPLP
         LDY   ]SIDX      ; {4C3B} LOAD STRING INDEX TO .7
         LDA   (]STR),Y   ; {5C2B} GET NEXT CHAR FROM STR
         LDY   ]SUBIND    ; {4C3B} LOAD SUBSTRING INDEX TO .Y
         CMP   (]SUB),Y   ; {5C2B} COMPARE TO NEXT SUB CHAR
         BNE   :SLP2      ; {3C2B} NOT A MATCH; BRANCH
         CPY   ]SUBLEN    ; {4C3B} TEST IF SUB INDEX = SUB LENGTH
         BEQ   :FOUND     ; {3C2B} IF SO, FOUND THE SUBSTRING
         INY              ; {2C1B} ELSE INC TO NEXT CHAR
         STY   ]SUBIND    ; {4C3B} STORE NEW SUBSTRING INDEX
         INC   ]SIDX      ; {5C2B} INCREASE STRING INDEX
         JMP   :CMPLP     ; {3C3B} LOOP UNTIL DONE
:SLP2
         INC   ]STRIND    ; {5C2B} INCREMENT INDEX
         DEC   ]CNT       ; {5C2B} DEC COUNT
         BNE   :SLP1      ; {3C2B} LOOP BACK IF UNFINISHED
         BEQ   :NOTFND    ; {3C2B} ELSE EXIT TO NOT FOUND
:FOUND
         LDA   ]STRIND    ; {4C3B} FOUND, STORE INDEX IN .A
         JMP   :EXIT      ; {3C3B}
:NOTFND
         LDA   #255       ; {3C2B} SUB NOT FOUND, .A = 255
:EXIT
         STA   RETURN     ; {4C3B} STORE INDEX OR 255 IN RETURN
         LDY   #1         ; {3C2B} STORE BYTE LENGTH OF 1
         STY   RETLEN     ; {4C3B} INTO RETLEN
         LDY   ]SUBLEN    ; {4C3B}
         RTS              ; {6C1B}

```



---



### THE SCPY MACRO

_SUMMARY_

| Condition       | Value                                                        |
| --------------- | ------------------------------------------------------------ |
| Name            | `SCPY`                                                       |
| Type            | Macro                                                        |
| File            | `MAC.SUBSTRINGS.ASM`                                         |
| Author          | Nathan Riggs                                                 |
| Last Revision   | 12-APR-2021                                                  |
| Assembler       | Merlin Pro 8                                                 |
| OS              | Apple DOS 3.3                                                |
| Purpose         | Copy a substring from another string                         |
| Input           | ]1 = Source string<br />]2 = Substring index<br />]3 = Substring length |
| Output          | none                                                         |
| Dependencies    | `SUB.SUBCOPY.ASM`                                            |
| Flags Destroyed | NZCV                                                         |
| Cycles          | 91+                                                          |
| Bytes           | 71                                                           |
| Notes           | None                                                         |
| See Also        | `SUB.SUBCOPY.ASM`                                            |

---

*DETAILS*

The `SCPY` macro copies a substring from a larger string starting at the given index and continuing until the given length. The substring is passed back in **RETURN** with its length in **RETLEN**. Additionally, the length is passed back via the **.A** register.



`LISTING 5.33: The SCPY Macro Source`

```assembly
*
*``````````````````````````````*
* SCPY          (NATHAN RIGGS) *
*                              *
* COPY SUBSTRING FROM STRING   *
*                              *
* PARAMETERS                   *
*                              *
*  ]1 = SOURCE STRING          *
*  ]2 = SUBSTRING INDEX        *
*  ]3 = SUBSTRING LENGTH       *
*                              *
* CYCLES: 91+                  *
* SIZE: 71 BYTES               *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
SCPY     MAC
         _MSTR ]1;WPAR1   ; {14C13B}
         LDA   ]2         ; {4C3B}
         STA   BPAR2      ; {3C2B}
         LDA   ]3         ; {4C3B}
         STA   BPAR1      ; {3C2B}
         JSR   SUBCOPY    ; {63C48B}
         <<<
*

```



---



### THE SUBCOPY SUBROUTINE

_SUMMARY_

| Condition       | Value                                                        |
| --------------- | ------------------------------------------------------------ |
| Name            | `SUBCOPY`                                                    |
| Type            | Subroutine                                                   |
| File            | `SUB.SUBCOPY.ASM`                                            |
| Author          | Nathan Riggs                                                 |
| Last Revision   | 12-APR-2021                                                  |
| Assembler       | Merlin Pro 8                                                 |
| OS              | Apple DOS 3.3                                                |
| Purpose         | copy a substring                                             |
| Input           | WPAR1 = Source string address<br />BPAR1 = Substring length<br />BPAR2 = Substring index |
| Output          | none                                                         |
| Dependencies    | none                                                         |
| Flags Destroyed | NZCV                                                         |
| Cycles          | 47+                                                          |
| Bytes           | 25                                                           |
| Notes           | none                                                         |
| See Also        | `SCPY`                                                       |

---

*DETAILS*

The `SUBCOPY` subroutine accepts a string address, and index and a length and then copies the part of the string that starts at the index through the length provided. The string itself is then stored in **RETURN** with its length in both **RETLEN** and the **.A** register.



`LISTING 5.34: The SUBCOPY Subroutine Source`

```assembly
*``````````````````````````````*
* SUBCOPY       (NATHAN RIGGS) *
*                              *
* INPUT:                       *
*                              *
*  BPAR1 = SUBSTRING LENGTH    *
*  BPAR2 = SUBSTRING INDEX     *
*  WPAR1 = SOURCE STRING ADDR  *
*                              *
* DESTROY: NZCIDV              *
*          ^^^  ^              *
*                              *
* CYCLES: 47+                  *
* SIZE: 25 BYTES               *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
]SUBLEN  EQU   BPAR1      ; SUBSTRING LENGTH
]SUBIND  EQU   BPAR2      ; SUBSTRING INDEX
]STR     EQU   WPAR1      ; SOURCE STRING
*
SUBCOPY
         LDY   ]SUBIND    ; {3C2B} STARTING COPY INDEX
         LDA   ]SUBLEN    ; {3C2B} SUBSTRING LENGTH
         STA   RETLEN     ; {4C3B} STORE SUB LENGTH IN RETLEN
         LDX   #0         ; {3C2B}
:COPY
         LDA   (]STR),Y   ; {5C2B} GET SUBSTRING CHARACTER
         STA   RETURN,X   ; {5C2B} STORE CHAR IN RETURN
         CPX   ]SUBLEN    ; {3C2B} IF .X COUNTER = SUBSTRING LENGTH
         BEQ   :EXIT      ; {3C2B} THEN FINISHED WITH LOOP
         INY              ; {2C1B} OTHERWISE, INCREMENT .Y
         INX              ; {2C1B} AND INCREMENT .X
         CLC              ; {2C1B} CLEAR CARRY FOR FORCED BRANCH
         BCC   :COPY      ; {3C2B} LOOP
:EXIT
         LDA   ]SUBLEN    ; {3C2B} RETURN SUBSTRING LENGTH IN .A
         RTS              ; {6C1B}

```



---



### THE SDEL MACRO

_SUMMARY_

| Condition       | Value                                                        |
| --------------- | ------------------------------------------------------------ |
| Name            | `SDEL`                                                       |
| Type            | Macro                                                        |
| File            | `MAC.SUBSTRINGS.ASM`                                         |
| Author          | Nathan Riggs                                                 |
| Last Revision   | 12-APR-2021                                                  |
| Assembler       | Merlin Pro 8                                                 |
| OS              | Apple DOS 3.3                                                |
| Purpose         | Delete a substring from a string                             |
| Input           | ]1 = Source string<br />]2 = Substring index<br />]3 = Substring length |
| Output          | none                                                         |
| Dependencies    | `SUB.SUBDEL.ASM`                                             |
| Flags Destroyed | NZCV                                                         |
| Cycles          | 135+                                                         |
| Bytes           | 79                                                           |
| Notes           | None                                                         |
| See Also        | `SUB.SUBDEL.ASM`                                             |

---

*DETAILS*

The `SUBDEL` macro deletes a substring from a larger string that starts at the given index and continues until the given length has been met. The new string (with no substring) is held in **RETURN**, with its length in both **RETLEN** and the **.A** register.



`LISTING 5.35: The SUBDEL Macro Source`

```assembly
*
*``````````````````````````````*
* SDEL          (NATHAN RIGGS) *
*                              *
* DELETE SUBSTRING FROM STRING *
*                              *
* PARAMETERS                   *
*                              *
*  ]1 = SOURCE STRING          *
*  ]2 = SUBSTRING INDEX        *
*  ]3 = SUBSTRING LENGTH       *
*                              *
* CYCLES: 135+                 *
* SIZE: 79 BYTES               *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
SDEL     MAC
         _MSTR ]1;WPAR1   ; {14C13B}
         LDA   ]2         ; {4C3B}
         STA   BPAR2      ; {3C2B}
         LDA   ]3         ; {4C3B}
         STA   BPAR1      ; {3C2B}
         JSR   SUBDEL     ; {107C56B}
         <<<
*

```



---



### THE SUBDEL SUBROUTINE

_SUMMARY_

| Condition       | Value                                                        |
| --------------- | ------------------------------------------------------------ |
| Name            | `SUBDEL`                                                     |
| Type            | Subroutine                                                   |
| File            | `SUB.SUBDEL.ASM`                                             |
| Author          | Nathan Riggs                                                 |
| Last Revision   | 12-APR-2021                                                  |
| Assembler       | Merlin Pro 8                                                 |
| OS              | Apple DOS 3.3                                                |
| Purpose         | delete a substring                                           |
| Input           | WPAR1 = Source string address<br />BPAR1 = Substring length<br />BPAR2 = Substring index |
| Output          | none                                                         |
| Dependencies    | none                                                         |
| Flags Destroyed | NZCV                                                         |
| Cycles          | 101+                                                         |
| Bytes           | 53                                                           |
| Notes           | none                                                         |
| See Also        | `SDEL`                                                       |

---

*DETAILS*

The `SUBDEL` subroutine accepts a string address, an index and a length, then deletes a substring from the source string at the given index through to the given length. The string with the deleted substring is then held in **RETURN** with its length in **RETLEN** and the **.A** register.



`LISTING 5.36: The SDEL Macro Source`

```assembly
*``````````````````````````````*
* SUBDEL        (NATHAN RIGGS) *
*                              *
* DELETE A SUBSTRING FROM A    *
* LARGER STRING.               *
*                              *
* INPUT:                       *
*                              *
*  WPAR1 = STRING ADDRESS      *
*  BPAR2 = SUBSTRING INDEX     *
*  BPAR1 = SUBSTRING LENGTH    *
*                              *
* DESTROY: NZCIDV              *
*          ^^^  ^              *
*                              *
* CYCLES: 101+                 *
* SIZE: 53 BYTES               *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
]SUBLEN  EQU   BPAR1
]SUBIND  EQU   BPAR2
]STR     EQU   WPAR1
*
SUBDEL
         DEC   ]SUBIND    ; {5C2B}
         INC   ]SUBLEN    ; {5C2B}
         LDY   #0         ; {3C2B} RESET .Y INDEX
         LDA   (]STR),Y   ; {5C2B} GET STRING LENGTH
         SEC              ; {2C1B} SET CARRY
         SBC   ]SUBLEN    ; {4C3B} SUBTRACT SUBSTRING LENGTH
         STA   RETLEN     ; {4C3B} STORE NEW LENGTH IN RETLEN
         INC   RETLEN     ; {5C2B}
:LP1
         INY              ; {2C1B} INCREASE .Y INDEX
         LDA   (]STR),Y   ; {5C2B} LOAD CHARACTER FROM STRING
         STA   RETLEN,Y   ; {5C2B} STORE IN RETURN
         CPY   ]SUBIND    ; {4C3B} IF .Y != SUBSTRING INDEX
         BNE   :LP1       ; {3C2B} THEN CONTINUE LOOPING
         LDX   ]SUBIND    ; {4C3B} OTHERWISE, .X = SUB INDEX
         TYA              ; {2C1B} TRANSFER .Y INDEX TO .A
         CLC              ; {2C1B} CLEAR CARRY
         ADC   ]SUBLEN    ; {4C3B} ADD .Y TO SUBSTRING LENGTH
         TAY              ; {2C1B} FOR NEW POS, THEN BACK TO .Y
         DEX              ; {2C1B}
         DEY              ; {2C1B}
:LP2
         INY              ; {2C1B} INCREMENT .Y INDEX
         INX              ; {2C1B} INCREMEMNT .X INDEX
         LDA   (]STR),Y   ; {5C2B} GET CHAR AFTER SUBSTRING
         STA   RETURN,X   ; {5C2B} STORE IN RETURN AT .X
         CPX   RETLEN     ; {4C3B} IF .X != NEW STRING LENGTH,
         BNE   :LP2       ; {3C2B} CONTINUE LOOPING
:EXIT
         LDA   RETLEN     ; {4C3B} LOAD NEW STRING LENGTH IN .A
         RTS              ; {6C1B}
*CPY #255 ; IF AT LENGTH MAX
*BEQ :EXIT ; THEN QUIT COPYING

```



---



### THE SINS MACRO

_SUMMARY_

| Condition       | Value                                                        |
| --------------- | ------------------------------------------------------------ |
| Name            | `SINS`                                                       |
| Type            | Macro                                                        |
| File            | `MAC.SUBSTRINGS.ASM`                                         |
| Author          | Nathan Riggs                                                 |
| Last Revision   | 12-APR-2021                                                  |
| Assembler       | Merlin Pro 8                                                 |
| OS              | Apple DOS 3.3                                                |
| Purpose         | Insert a substring into another string                       |
| Input           | ]1 = Source string<br />]2 = Substring<br />]3 = Substring index |
| Output          | none                                                         |
| Dependencies    | `SUB.SUBINS.ASM`                                             |
| Flags Destroyed | NZCV                                                         |
| Cycles          | 177+                                                         |
| Bytes           | 111                                                          |
| Notes           | None                                                         |
| See Also        | `SUB.SUBINS.ASM`                                             |

---

*DETAILS*

The `SUBINS` macro inserts a given substring at a specific index in another string. This new string is then held in **RETURN** with the length-byte stored in **RETLEN**.



`LISTING 5.37: The SUBINS Macro Source`

```assembly
*
*``````````````````````````````*
* SINS          (NATHAN RIGGS) *
*                              *
* INSERT SUBSTRING INTO STRING *
*                              *
* PARAMETERS                   *
*                              *
*  ]1 = STRING ADDRESS         *
*  ]2 = SUBSTRING ADDRESS      *
*  ]3 = SUBSTRING INDEX        *
*                              *
* CYCLES: 177+                 *
* SIZE: 111 BYTES              *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
SINS     MAC
         _MSTR ]1;WPAR2   ; {14C13B}
         _MSTR ]2;WPAR1   ; {14C13B}
         LDA   ]3         ; {4C3B}
         STA   BPAR1      ; {3C2B}
         JSR   SUBINS     ; {142C82B}
         <<<
*

```



---



### THE SUBINS SUBROUTINE

_SUMMARY_

| Condition       | Value                                                        |
| --------------- | ------------------------------------------------------------ |
| Name            | `SUBINS`                                                     |
| Type            | Subroutine                                                   |
| File            | `SUB.SUBINS.ASM`                                             |
| Author          | Nathan Riggs                                                 |
| Last Revision   | 12-APR-2021                                                  |
| Assembler       | Merlin Pro 8                                                 |
| OS              | Apple DOS 3.3                                                |
| Purpose         | insert a substring                                           |
| Input           | WPAR1 = Substring address<br />BPAR1 = String length<br />BPAR2 = Insertion index |
| Output          | none                                                         |
| Dependencies    | none                                                         |
| Flags Destroyed | NZCV                                                         |
| Cycles          | 136+                                                         |
| Bytes           | 79                                                           |
| Notes           | none                                                         |
| See Also        | `SINS`                                                       |

---

*DETAILS*

The `SUBINS` subroutine accepts a substring address, a source string address and an index, then inserts the substring into a copy of the source string at the specified index. This new string copy is then stored in **RETURN**, with the length stored in the **.A** register and **RETLEN**.



`LISTING 5.38: The SUBINS Subroutine Source`

```assembly
*``````````````````````````````*
* SUBINS        (NATHAN RIGGS) *
*                              *
* INSERT A SUBSTRING INTO A    *
* STRING AT A GIVEN POSITION.  *
*                              *
* INPUT:                       *
*                              *
*  WPAR1 = SUBSTRING ADDRESS   *
*  WPAR2 = STRING ADDRESS      *
*  BPAR1 = INSERTION INDEX     *
*                              *
* DESTROY: NZCIDV              *
*          ^^^  ^              *
*                              *
* CYCLES: 136+                 *
* SIZE: 79 BYTES               *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
]SUB     EQU   WPAR1      ; SUBSTRING ADDRESS
]STR     EQU   WPAR2      ; STRING ADDRESS
]INDEX   EQU   BPAR1      ; STRING INDEX
]OLDIND  EQU   VARTAB     ; OLD INDEX
]TMP     EQU   VARTAB+2   ; TEMPORARY VARIABLE
]SUBLEN  EQU   VARTAB+4   ; SUBSTRING LENGTH
*
SUBINS
         DEC   ]INDEX     ; {5C2B}
         LDY   #0         ; {3C2B} SET .Y INDEX TO 0
         LDA   (]STR),Y   ; {5C2B} GET STRING LENGTH
         STA   ]TMP       ; {4C3B} TEMPORARILY STORE
         LDA   (]SUB),Y   ; {5C2B} GET SUBSTRING LENGTH
         STA   ]SUBLEN    ; {4C3B}
         CLC              ; {2C1B} CLEAR CARRY
         ADC   ]TMP       ; {4C3B} ADD SOURCE STRING LENGTH
         STA   RETLEN     ; {4C3B} STORE NEW STRING LENGTH
         BCC   :CONT      ; {3C2B} IF NO OVERFLOW, CONTINUE
         LDA   #255       ; {3C2B} ELSE, NEW STRING LENGTH IS 255
         STA   RETLEN     ; {4C3B} STORE IN RETLEN
:CONT
         LDA   ]INDEX     ; {4C3B} IF INDEX IS 0, GO STRAIGHT
         BEQ   :SUBCOPY   ; {3C2B} TO COPYING SUBSTRING FIRST
:LP1
         INY              ; {2C1B} INCREASE INDEX
         LDA   (]STR),Y   ; {5C2B} GET SOURCE STRING CHARACTER
         STA   RETLEN,Y   ; {4C3B} STORE IN RETURN
         CPY   ]INDEX     ; {3C2B} IF WE DON'T HIT SUBSTRING INDEX
         BNE   :LP1       ; {3C2B} KEEP ON COPYING
:SUBCOPY
         STY   ]OLDIND    ; {4C3B} STORE CURRENT STRING INDEX
         TYA              ; {2C1B} TRANSFER .Y COUNTER TO
         TAX              ; {2C1B} .X COUNTER TEMPORARILY
         LDY   #0         ; {3C2B} RESET .Y COUNTER
:SUBLP
         INY              ; {2C1B} INCREASE .Y SUBSTRING INDEX
         INX              ; {2C1B} CONTINUE INCREASING .X INDEX
         LDA   (]SUB),Y   ; {5C2B} LOAD INDEXED CHAR FROM SUBSTRING
         STA   RETLEN,X   ; {5C2B} STORE INTO RETURN AT INDEX
         CPY   ]SUBLEN    ; {4C3B} IF .Y != SUBSTRING LENGTH
         BNE   :SUBLP     ; {3C2B} THEN CONTINUE COPYING
         LDY   ]OLDIND    ; {4C3B} RESTORE OLD INDEX
:FINLP
         INY              ; {2C1B} INCREASE ORIGINAL INDEX
         INX              ; {2C1B} INCREASE NEW INDEX
         LDA   (]STR),Y   ; {5C2B} LOAD NEXT CHAR FROM STRING
         STA   RETLEN,X   ; {5C2B} AND STORE AFTER SUBSTRING
         CPY   ]TMP       ; {4C3B} IF ORIGINAL STRING LENGTH
         BNE   :FINLP     ; {3C2B} IS NOT YET HIT, KEEP LOOPING
:EXIT
         LDA   RETLEN     ; {4C3B} RETURN NEW LENGTH IN .A
         RTS              ; {6C1B}

```



---



### THE STOK MACRO

_SUMMARY_

| Condition       | Value                                               |
| --------------- | --------------------------------------------------- |
| Name            | `STOK`                                              |
| Type            | Macro                                               |
| File            | `MAC.SUBSTRINGS.ASM`                                |
| Author          | Nathan Riggs                                        |
| Last Revision   | 12-APR-2021                                         |
| Assembler       | Merlin Pro 8                                        |
| OS              | Apple DOS 3.3                                       |
| Purpose         | Find a substring by token                           |
| Input           | ]1 = String <br />]2 = Token<br />]3 = Token Number |
| Output          | none                                                |
| Dependencies    | `SUB.SUBTOK.ASM`                                    |
| Flags Destroyed | NZCV                                                |
| Cycles          | 182+                                                |
| Bytes           | 118                                                 |
| Notes           | None                                                |
| See Also        | `SUB.SUBTOK.ASM`                                    |

---

*DETAILS*

The `STOK` macro searches a string for a given token and passes through the specified number of tokens before copying a substring from that token to the next token. If the token number is #0, then the substring pulled will be whatever text comes become the first token. The substring is held in **RETURN**, with its length in **RETLEN**.

Note that this macro has no protection against overflow, and thus extra care should be taken not to request a token number that extends beyond the number of tokens+1 (the extra token is due to having an implied token at the beginning of the string). The number of tokens available can be found by using the `SCNT` macro, which counts the number of occurrences of a character in a string.



`LISTING 5.39: The STOK Macro Source`

```assembly
*
*``````````````````````````````*
* STOK          (NATHAN RIGGS) *
*                              *
* THIS MACRO FINDS AN ARGUMENT *
* WITHIN A STRING THAT IS      *
* SEPARATED BY TOKENS AT A     *
* GIVEN INDEX.                 *
*                              *
* PARAMETERS                   *
*                              *
*  ]1 = STRING ADDRESS         *
*  ]2 = DELIMITER / TOKEN      *
*  ]3 = ARGUMENT NUMBER        *
*                              *
* CYCLES: 182+                 *
* SIZE: 118 BYTES              *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
STOK     MAC
         _MLIT ]1;WPAR1   ; {14C13B}
         LDA   ]2         ; {4C3B}
         STA   WPAR2      ; {3C2B}
         LDA   ]3         ; {4C3B}
         STA   BPAR2      ; {3C2B}
         JSR   SUBTOK     ; {154C95B}
         <<<
*

```



---



### THE SUBTOK SUBROUTINE

_SUMMARY_

| Condition       | Value                                                        |
| --------------- | ------------------------------------------------------------ |
| Name            | `SUBTOK`                                                     |
| Type            | Subroutine                                                   |
| File            | `SUB.SUBTOK.ASM`                                             |
| Author          | Nathan Riggs                                                 |
| Last Revision   | 12-APR-2021                                                  |
| Assembler       | Merlin Pro 8                                                 |
| OS              | Apple DOS 3.3                                                |
| Purpose         | retrieve substring by token                                  |
| Input           | WPAR1 = String address<br />WPAR2 = Token<br />BPAR2 = Token number |
| Output          | none                                                         |
| Dependencies    | none                                                         |
| Flags Destroyed | NZCV                                                         |
| Cycles          | 148+                                                         |
| Bytes           | 92                                                           |
| Notes           | none                                                         |
| See Also        | `STOK`                                                       |

---

*DETAILS*

The `SUBTOK` subroutine accepts a string address, a token character and a token number as parameters, then steps through the string as it counts the number of tokens. When the specified token number is found, the substring following it is copied to **RETURN** up until either another token is encountered or the end of the string is reached. The length of this substring is held in both **RETLEN** and the **.A** register.

Importantly, this subroutine does not protect against overflow. As such, the `SCNT` macro should be used to determine the number of tokens in a string if that number is not known beforehand.



`LISTING 5.40: The SUBTOK Subroutine Source`

```assembly
*``````````````````````````````*
* SUBTOK        (NATHAN RIGGS) *
*                              *
* THIS SUBROUTINE PULLS FROM A *
* STRING OF ARGUMENTS THAT ARE *
* SEPARATED BY A DELIMITER AND *
* RETURNS THE ARGUMENT NUMBER  *
* THAT IS REQUESTED.           *
*                              *
* INPUT:                       *
*                              *
*  WPAR1 = STRING ADDRESS      *
*  WPAR2 = DELIMITER           *
*  BPAR2 = ARGUMENT INDEX      *
*                              *
* DESTROY: NZCIDV              *
*          ^^^  ^              *
*                              *
* CYCLES: 148+                 *
* SIZE: 92 BYTES               *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
]STR     EQU   WPAR1      ; STRING ADDRESS
]DELIM   EQU   WPAR2      ; DELIMITER
]LEN     EQU   BPAR1      ; STRING LENGTH
]ARG     EQU   BPAR2      ; ARGUMENT NUMBER
]START   EQU   VARTAB     ; START POS OF ARGUMENT
]END     EQU   VARTAB+2   ; END POS OF ARGUMENT
]COUNT   EQU   VARTAB+4   ; ARGUMENT COUNTER
]XFLAG   EQU   VARTAB+6   ; LOOP EXIT FLAG
]FOUND   EQU   VARTAB+8   ; ARGUMENT FOUND FLAG
*
SUBTOK
         LDY   #0         ; {3C2B} CLEAR .Y REGISTER
         STY   ]COUNT     ; {4C3B} CLEAR COUNTER
         STY   ]XFLAG     ; {4C3B} CLEAR LOOP FLAG
         LDA   (]STR),Y   ; {5C2B} LOAD STRING LENGTH
         STA   ]LEN       ; {3C2B} AND STORE IN LENGTH VARIABLE
         STY   ]START     ; {4C3B} CLEAR START POS
         STY   ]END       ; {4C3B} CLEAR ENDING POS
         STY   ]FOUND     ; {4C3B} CLEAR FOUND FLAG
         TAX              ; {2C1B} CLEAR .X REGISTER
:_LP2
         INY              ; {2C1B} INCREASE INDEX
         LDA   (]STR),Y   ; {5C2B} LOAD CHARACTER FROM STRING
         CMP   ]DELIM     ; {3C2B} COMPARE TO DELIMITER
         BEQ   :CHECK     ; {3C2B} IF EQUAL, GOTO :CHECK
:RELOOP  CPY   ]LEN       ; {3C2B} ELSE, COMPARE .Y TO LENGTH
         BNE   :_LP2      ; {3C2B} IF NOT EQUAL, LOOP AGAIN
         LDX   #1         ; {3C2B} LOAD #1 IN .X
         STX   ]XFLAG     ; {4C3B} SET LOOP EXIT FLAG
:CHECK
         STY   ]END       ; {4C3B} STORE CUR INDEX TO END POS
         LDX   ]ARG       ; {3C2B} LOAD ARGUMENT NUMBER
         CPX   ]COUNT     ; {4C3B} COMPARE TO CURRENT COUNT
         BEQ   :COPY      ; {3C2B} IF EQUAL, PROCEED TO :COPY
         INC   ]COUNT     ; {5C2B} OTHERWISE, INCREASE COUNT
         STY   ]START     ; {4C3B} STORE CURRENT INDEX AS START
         JMP   :RELOOP    ; {3C3B} GOTO BEGINNING LOOP
:COPY
         LDY   ]START     ; {4C3B} LOAD STARTING POSITION IN .Y
         LDX   #255       ; {3C2B} LOAD -1 IN .X REGISTER
         LDA   ]XFLAG     ; {4C3B} LOAD LOOP EXIT FLAG
         CMP   #1         ; {3C2B} AND COMPARE TO #1
         BEQ   :CPLP      ; {3C2B} IF SET, GOTO COPY LOOP
         DEC   ]END       ; {5C2B} OTHERWISE, DECREASE END POS
:CPLP
         INY              ; {2C1B} INCREASE .Y INDEX
         INX              ; {2C1B} INCREASE .X INDEX
         LDA   (]STR),Y   ; {5C2B} LOAD CHARACTER FROM STRING
         STA   RETURN,X   ; {5C2B} STORE IN RETURN
         CPY   ]END       ; {4C3B} IF .Y INDEX != END POS
         BNE   :CPLP      ; {3C2B} THEN CONTINUE COPY LOOP
:SETLEN
         LDA   ]END       ; {4C3B} LOAD ENDING POS
         SEC              ; {2C1B} SET CARRY
         SBC   ]START     ; {4C3B} SUBTRACT STARTING POS
         STA   RETLEN     ; {4C3B} AND STORE IN RETLEN
:EXIT
         RTS              ; {6C1B}

```



---



### THE SCNT MACRO

_SUMMARY_

| Condition       | Value                                      |
| --------------- | ------------------------------------------ |
| Name            | `SCNT`                                     |
| Type            | Macro                                      |
| File            | `MAC.SUBSTRINGS.ASM`                       |
| Author          | Nathan Riggs                               |
| Last Revision   | 12-APR-2021                                |
| Assembler       | Merlin Pro 8                               |
| OS              | Apple DOS 3.3                              |
| Purpose         | Count occurrence of characters in a string |
| Input           | ]1 = String <br />]2 = Character           |
| Output          | none                                       |
| Dependencies    | `SUB.SUBCHARCNT.ASM`                       |
| Flags Destroyed | NZCV                                       |
| Cycles          | 88+                                        |
| Bytes           | 57                                         |
| Notes           | None                                       |
| See Also        | `SUB.SUBCHARCNT.ASM`                       |

---

*DETAILS*

The `SCNT` macro counts the number of times a character appears in a string. This is especially useful for tokenized strings that need to be parsed into other variables, such as the classic comma-delimited string used prevalently for arrays and spreadsheets. This macro is doubly important due to the fact that the `STOK` macro and the `SUBTOK` subroutine do not check for value overflows, meaning that the `SCNT` macro must be relied on for strings with an unknown number of tokens.



`LISTING 5.41: The SCNT Macro Source`

```
*
*``````````````````````````````*
* SCNT          (NATHAN RIGGS) *
*                              *
*                              *
* PARAMETERS                   *
*                              *
*  ]1 = STRING ADDRESS         *
*  ]2 = DELIMITER / TOKEN      *
*                              *
* CYCLES: 88+                  *
* SIZE: 57 BYTES               *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
SCNT     MAC
         _MSTR ]1;WPAR1   ; {14C13B}
         LDA   ]2         ; {4C3B}
         STA   WPAR2      ; {3C2B}
         JSR   SUBCHARCNT ; {67C39B}
         <<<

```



---



### THE SUBCHARCNT SUBROUTINE

_SUMMARY_

| Condition       | Value                                                 |
| --------------- | ----------------------------------------------------- |
| Name            | `SUBCHARCNT`                                          |
| Type            | Subroutine                                            |
| File            | `SUB.SUBCHARCNT.ASM`                                  |
| Author          | Nathan Riggs                                          |
| Last Revision   | 12-APR-2021                                           |
| Assembler       | Merlin Pro 8                                          |
| OS              | Apple DOS 3.3                                         |
| Purpose         | count character occurrences in string                 |
| Input           | WPAR1 = String address<br />WPAR2 = Character to find |
| Output          | none                                                  |
| Dependencies    | none                                                  |
| Flags Destroyed | NZCV                                                  |
| Cycles          | 61+                                                   |
| Bytes           | 36                                                    |
| Notes           | none                                                  |
| See Also        | `SCNT`                                                |

---

*DETAILS*

The `SUBCHARCNT` subroutine counts the number of occurrences of a character within a string, storing that number (byte) in both **RETLEN** and the **.A** register. While potentially useful on its own, this subroutine is immediately available to work in tandem with the `STOK` macro (or the `SUBTOK` subroutine), since it does not protect against overflow. `SUBCHARCNT` can be used to count the number of tokens in a string before `STOK` is used to retrieve a substring by token number.



`LISTING 5.41: The SUBCHARCNT Subroutine Source`

```assembly
*``````````````````````````````*
* SUBCHARCNT    (NATHAN RIGGS) *
*                              *
* COUNT THE NUMBER OF TOKENS,  *
* OR OCCURRENCES OF A GIVEN    *
* CHARACTER, IN A STRING.      *
*                              *
* INPUT:                       *
*                              *
*  WPAR1 = STRING ADDRESS      *
*  WPAR2 = CHARACTER TO FIND   *
*                              *
* DESTROYS: NZCIDV             *
*           ^^^  ^             *
*                              *
* CYCLES: 61+                  *
* SIZE: 36 BYTES               *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
]STR     EQU   WPAR1      ; STRING ADDRESS
]CHAR    EQU   WPAR2      ; TOKEN TO FIND
]LEN     EQU   BPAR2      ; LENGTH OF STRING
*
SUBCHARCNT
         LDA   #0         ; {3C2B} CLEAR OUT .A REGISTER
         TAY              ; {2C1B} CLEAR OUT .Y
         TAX              ; {2C1B} CLEAR OUT .X
         LDA   (]STR),Y   ; {5C2B} GET LENGTH FROM STRING
         STA   ]LEN       ; {3C2B} AND HOLD TEMPORARILY
:LP1
         INY              ; {2C1B} INCREASE .Y INDEX
         LDA   (]STR),Y   ; {5C2B} LOAD CHAR AT INDEX
         CMP   ]CHAR      ; {3C2B} COMPARE TO TOKEN
         BEQ   :FOUND     ; {3C2B} IF EQUAL, THEN GOTO :FOUND
:RELOOP  CPY   ]LEN       ; {3C2B} COMPARE .Y TO STRING LENGTH
         BNE   :LP1       ; {3C2B} RELOOP UNTIL EQUAL
         JMP   :EXIT      ; {3C3B} JUMP OVER REST
:FOUND
         INX              ; {2C1B} INCREASE .X COUNTER
         JMP   :RELOOP    ; {3C3B} JUMP BACK TO LOOP
:EXIT
         STX   RETURN     ; {4C3B} STORE .X COUNT IN RETURN
         LDA   #1         ; {3C2B} LOAD #1 AND
         STA   RETLEN     ; {4C3B} STORE IN RETLEN
         TXA              ; {2C1B} ALSO RETURN NUMBER IN .A
         RTS              ; {6C1B}

```



---



# PART II: STRING AND SUBSTRING DEMONSTRATIONS

The following demo files illustrate how each macro in the collection is used. This includes two demos, one for whole strings and one for substrings.



`LISTING 5.50: Whole Strings Demonstration Source`

```assembly
*
*``````````````````````````````*
* DEMO.STRINGS.ASM             *
*                              *
* A DEMO OF THE VARIOUS MACROS *
* FOR STRING HANDLING.         *
*                              *
* AUTHOR:    NATHAN RIGGS      *
* CONTACT:   NATHAN.RIGGS@     *
*            OUTLOOK.COM       *
*                              *
* DATE:      12-APR-2021       *
* ASSEMBLER: MERLIN 8 PRO      *
* OS:        DOS 3.3           *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
** ASSEMBLER DIRECTIVES
*
         CYC   AVE
         EXP   OFF
         TR    ON
         DSK   DEMO.STRINGS
         OBJ   $BFE0
         ORG   $6000
*
*``````````````````````````````*
*  TOP INCLUDES (PUTS, MACROS) *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
         PUT   MIN.HEAD.REQUIRED.ASM
         USE   MIN.MAC.REQUIRED.ASM
         USE   MIN.MAC.STRINGS.ASM
         PUT   MIN.HEAD.STRINGS.ASM
]HOME    EQU   $FC58
*
*``````````````````````````````*
*      PROGRAM MAIN BODY       *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
*``````````````````````````````*
* STRING MACROS                *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
** THIS FILE CONTAINS MACRO DEMONSTRATIONS FOR THE
** STRING COLLECTION OF THE APPLEIIASM LIBRARY. NOTE
** THAT ANOTHER DEMO FILE EXISTS THAT IS DEDICATED TO
** MACROS THAT SPECIFICALLY DEAL WITH SUBSTRINGS,
** WHERAS THIS FILE DEMONSTRATES MACROS THAT WORK ON
** THE WHOLE STRING.
*
*``````````````````````````````*
* STRING REVERSE               *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
** THE SREV MACRO SIMPLY ACCEPTS A STRING
** OR ITS ADDRESS AND REVERSES IT, HANDING
** BACK THE REVERSED STRING IN RETURN WITH
** ITS LENGTH IN RETLEN.
*
         JSR   ]HOME
         _PRN  "STRING REVERSAL",8D
         _PRN  "===============",8D8D
         LDA   #"-"
         JSR   $FDF0
         SREV  #S2
         _AXLIT #RETLEN
         JSR   _PS
         LDA   #"-"
         JSR   $FDF0
         _WAIT
*
*``````````````````````````````*
* STRING TRIMMING              *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
** THE STRIM MACRO ACCEPTS A GIVEN TOKEN OR
** DELIMITER TO CHECK FOR AT THE BEGINNING OR
** END OF A STRING, THEN DELETES THEM FROM THE
** STRING IF THEY EXIST AT EITHER END.
*
         JSR   ]HOME
         _PRN  "STRING TRIMMING",8D
         _PRN  "===============",8D8D
         STRIM #S2;#" "
         _AXLIT #RETLEN
         JSR   _PS
         _WAIT
*
*``````````````````````````````*
* STRING UPPERCASE             *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
** THE STRUP MACRO ACCEPTS A STRING AND
** RETURNS ITS UPPERCASE EQUIVALENT.
*
         JSR   ]HOME
         _PRN  "STRING UPPERCASING",8D
         _PRN  "==================",8D8D
         STRUP #S6
         _AXLIT #RETLEN
         JSR   _PS
         _WAIT
*
*``````````````````````````````*
* STRING LOWERCASE             *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
** THE SLO MACRO TAKES A STRING AND MAKES
** EVERY CHARACTER LOWERCASE, PASSING THE NEW
** STRING BACK IN RETURN WITH ITS LENGTH IN
** RETLEN. NOTE THAT *ALL* CHARACTERS ARE TURNED
** TO LOWERCASE THAT ARE ALREADY UPPERCASE, SO EVEN
** WORDS THAT SHOULD BE CAPITALIZED WILL BE
** IN LOWERCASE. YOU CAN REMEDY THIS, IF NEEDED, WITH
** THE SCAP MACRO.
*
         JSR   ]HOME
         _PRN  "STRING LOWERCASING",8D
         _PRN  "==================",8D8D
         STRLO #S1
         _AXLIT #RETLEN
         JSR   _PS
         _WAIT
*
*``````````````````````````````*
* STRING CAPITALIZATION        *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
** THE SCAP MACRO ACCEPTS A STRING AND SCANS
** IT FOR WORDS THAT SHOULD BE CAPITALIZED,
** INCLUDING THE FIRST LETTER OF THE STRING.
** WHILE NOT ALL NEEDS ARE MET WITH THIS, AS
** IT ONLY CAPITALIZES BASED ON WHETHER A NEW
** SENTENCE IS STARTED, IT SHOULD SERVE MOST
** PURPOSES.
*
         JSR   ]HOME
         _PRN  "STRING CAPITALIZATION",8D
         _PRN  "=====================",8D8D
         SCAP  #S5
         _AXLIT #RETLEN
         JSR   _PS
         _WAIT
*
*``````````````````````````````*
* STRING CONCATENATION         *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
** THE SCAT MACRO CONCATENATES (OR JOINS)
** ONE STRING TO ANOTHER AND PASSES THE NEW
** STRING BACK IN RETURN, WITH THE NEW LENGTH
** HELD IN RETLEN.
*
         JSR   ]HOME
         _PRN  "STRING CONCATENATION",8D
         _PRN  "====================",8D8D
         SCAT #S3;#S4
         _AXLIT #RETLEN
         JSR   _PS
         _WAIT
*
*``````````````````````````````*
* STRING COMPARISON            *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
** THE SCMP MACRO COMPARES ONE STRING TO ANOTHER,
** RETURNING THE COMPARISON RESULTS VIA THE STATUS
** REGISTER AS FOLLOWS:
*
** Z = 1 IF STRINGS MATCH
** Z = 0 IF STRINGS DON'T MATCH
** C = 0 IF 1ST STRING < 2ND STRING LENGTH
** C = 1 IF IST STRING >= 2ND STRING LENGTH
*
** NOTE THAT THIS MIRRORS, IN WAYS, HOW THE CMP
** INSTRUCTION WORKS.
*
         JSR   ]HOME
         _PRN  "STRING COMPARISON",8D
         _PRN  "=================",8D8D
         SCMP  #S1;#S2
         BCC   :ALTB
         BCS   :AGTEB
:ALTB
         _PRN  "STRING 1 IS LESS THAN STRING 2.",8D8D
         JMP   :_END
:AGTEB
         _PRN  "STRING 1 IS GREATER THAN OR EQUAL TO",8D
         _PRN  "STRING 2.",8D8D
:_END
         _WAIT
*
         JSR   ]HOME
         _PRN  "FIN!",8D8D
*
*
*
         JMP   $3D0
*
** THE FOLLOWING SUBROUTINE IS A COPY OF THE STDIO
** LIBRARY'S PRNSTR SUBROUTINE, WHICH IS USED TO
** PRINT STRINGS WITH A PRECEDING LENGTH-BYTE. THIS
** IS USED FOR SHOWING THE OUTPUT OF THE VARIOUS
** STRING MACROS.
*
]STRLEN  HEX   0000
]COUT1   EQU   $FDF0
_PS
         STA   ADDR1
         STX   ADDR1+1
         LDY   #0
         LDA   (ADDR1),Y
         STA   ]STRLEN
:_LP
         INY
         LDA   (ADDR1),Y
         JSR   ]COUT1
         CPY   ]STRLEN
         BNE   :_LP
         LDA   ]STRLEN
         RTS
*
S1       STR   "ONE RING TO RULE THEM ALL"
S2       STR   " ONE RING TO FIND THEM "
S3       STR   " ONE RING TO BRING THEM ALL"
S4       STR   "AND IN THE DARKNESS BIND THEM "
S5       STR   "this is a test? a test. a test! a test."
S6       STR   "this is a test."
S7       STR   "ZERO ONE TWO THREE FOUR FIVE SIX"
*
*``````````````````````````````*
*        BOTTOM INCLUDES       *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
** BOTTOM INCLUDES
*
         PUT   MIN.LIB.REQUIRED.ASM
*
** INDIVIDUAL SUBROUTINE INCLUDES
*
** STRING SUBROUTINES
*
         PUT   MIN.SUB.STRCAT.ASM
         PUT   MIN.SUB.STRCOMP.ASM
         PUT   MIN.SUB.STRTRIM.ASM
         PUT   MIN.SUB.STRUPPER.ASM
         PUT   MIN.SUB.STRCAP.ASM
         PUT   MIN.SUB.STRLOWER.ASM
         PUT   MIN.SUB.STRREV.ASM

```



`LISTING 5.51: Substrings Demonstration Source`

```assembly
*
*``````````````````````````````*
* DEMO.SUBSTRINGS.ASM          *
*                              *
* A DEMO OF THE VARIOUS MACROS *
* FOR HANDLING SUBSTRINGS.     *
*                              *
* AUTHOR:    NATHAN RIGGS      *
* CONTACT:   NATHAN.RIGGS@     *
*            OUTLOOK.COM       *
*                              *
* DATE:      11-APR-2021       *
* ASSEMBLER: MERLIN 8 PRO      *
* OS:        DOS 3.3           *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
** ASSEMBLER DIRECTIVES
*
         CYC   AVE
         EXP   OFF
         TR    ON
         DSK   DEMO.SUBSTRINGS
         OBJ   $BFE0
         ORG   $6000
*
*``````````````````````````````*
*  TOP INCLUDES (PUTS, MACROS) *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
         PUT   MIN.HEAD.REQUIRED.ASM
         USE   MIN.MAC.REQUIRED.ASM
         USE   MAC.SUBSTRINGS.ASM
         PUT   MIN.HEAD.STRINGS.ASM
]HOME    EQU   $FC58
*
*``````````````````````````````*
*      PROGRAM MAIN BODY       *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
** THIS FILE CONTAINS DEMONSTRATIONS OF THE MACROS
** DEDICATED TO SUBSTRINGS IN THE STRINGS COLLECTION
** OF THE APPLEIIASM LIBRARY. NOTE THAT ANOTHER
** DEMO FILE EXISTS FOR OPERATIONS ON FULL STRINGS.
*
*``````````````````````````````*
* TOKENIZED SUBSTRING RETRIEVE *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
** THE STOK MACRO RETRIEVES A SUBSTRING FROM A
** LARGER STRING THAT IS FOUND BY A PRECEDING
** TOKEN. THE ENTIRE STRING CONSISTS OF SUBSTRINGS
** SEPARATED BY TOKENS (A SPACE, A COMMA, ETC.), AND
** THE SUBSTRING IS RETRIEVED BY SPECIFYING THE TOKEN
** NUMBER PRECEDING IT.
*
** NOTE THAT THERE IS CURRENTLY NO SAFETY MEASURE TO
** PREVENT OVERFLOW HERE. TO BE SPECIFIC, IT IS
** POSSIBLE TO ATTEMPT TO RETRIEVE A TOKEN SUBSTRING
** THAT DOES NOT EXIST, SUCH AS A SEVENTH SUBSTRING
** WHERE ONLY SIX EXIST. TO GUARD AGAINST THIS, THE
** SCNT MACRO SHOULD BE USED TO ASCERTAIN THE NUMBER OF
** TOKENS IN THE STRING (SEE BELOW).
*
** ADDITIONALLY, IT IS IMPORTANT TO KNOW THAT TOKEN
** NUMBER ZERO IS COUNTED, MEANING THE TEXT BEFORE
** THE FIRST OCCURENCE OF A TOKEN. IF A STRING HAS
** SIX TOKENS IN IT, THEN, IT WILL TECHNICALLY HAVE
** SEVEN SUBSTRINGS.
*
         JSR   ]HOME
         _PRN  "TOKENIZED SUBSTRINGS",8D
         _PRN  "====================",8D8D
         STOK  #S7;#" ";#6
         _AXLIT #RETLEN
         JSR   _PS
         _WAIT
*
*``````````````````````````````*
* STRING TOKEN COUNTING        *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
** THE SCNT MACRO COUNTS THE NUMBER OF TOKENS,
** OR THE NUMBER OF TIMES A GIVEN CHARACTER IS
** PRESENTED IN A STRING. THIS IS MOSTLY USEFUL
** IN CONJUNCTION WITH THE STOK MACRO, AS IT
** PROVIDES THE NUMBER OF SUBSTRINGS AVAILABLE
** TO BE RETRIEVED.
*
** NOTE THAT WHEN USED WITH THE STOK MACRO,
** ONE SHOULD BE ADDED TO THE RESULT OF SCNT
** TO FIND THE TOTAL NUMBER OF SUBSTRINGS THAT
** ARE AVAILABLE. THIS IS DUE TO THE FACT THAT
** THE STOK MACRO STARTS WITH A ZERO INDEX,
** COUNTING THE TEXT BEFORE THE FIRST TOKEN AS
** A TOKENIZED SUBSTRING AS WELL.
*
         JSR   ]HOME
         _PRN  "STRING TOKEN COUNTING",8D
         _PRN  "=====================",8D8D
         SCNT  #S7;#" "
         DUMP  #RETURN;#1
         _WAIT
*
*``````````````````````````````*
* SUBSTRING POSITION           *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
** THE SPOS MACRO FINDS THE POSITION OF A SUBSTRING
** IN A GIVEN STRING AND RETURNS IT. NOTE THAT THIS
** MACRO ONLY RETURNS THE POSITION OF THE FIRST
** INSTANCE OF THE SUBSTRING, AND DOES NOT ACCOUNT
** FOR REPETITIONS.
*
** NOTE THAT THIS MACRO USES A STARTING INDEX OF ONE
** FOR A MORE INTUITIVE FEEL. WHEN USED IN CONJUNCTION
** WITH ZERO-INDEXED MACROS, CARE SHOULD BE TAKEN TO
** ADD OR SUBTRACT TO THIS VALUE ACCORDINGLY.
*
         JSR   ]HOME
         _PRN  "SUBSTRING POSITION",8D
         _PRN  "==================",8D8D
         SPOS  #S1;"RING"
         DUMP  #RETURN;#1
         _WAIT
*
*``````````````````````````````*
* SUBSTRING INSERTION          *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
** THE SINS MACRO INSERTS A GIVEN SUBSTRING INTO
** ANOTHER GIVEN STRING AT THE PROVIDED INDEX. THE
** NEW STRING IS PASSED BACK VIA RETURN, WITH ITS
** LENGTH BYTE IN RETLEN.
*
         JSR   ]HOME
         _PRN  "SUBSTRING INSERTION",8D
         _PRN  "===================",8D8D
         SINS  #S1;#S7;#10
         _AXLIT #RETLEN
         JSR   _PS
         _WAIT
*
*``````````````````````````````*
* SUBSTRING COPY               *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
** THE SCPY MACRO COPIES A SUBSTRING FROM A GIVEN
** STRING AT AN INDEX AND LENGTH. THE RESULTING
** SUBSTRING IS STORED IN RETURN, WITH ITS LENGTH
** HELD IN RETLEN.
*
         JSR   ]HOME
         _PRN  "SUBSTRING COPY",8D
         _PRN  "==============",8D8D
         SCPY  #S1;#5;#10
         _AXLIT #RETLEN
         JSR   _PS
         _WAIT
*
*``````````````````````````````*
* SUBSTRING DELETION           *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
** THE SDEL MACRO TAKES A STRING, AN INDEX AND A
** SUBSTRING LENGTH AND DELETES THAT SUBSTRING
** FROM THE LARGER STRING, PASSING BACK THE RESULTING
** STRING IN RETURN WITH ITS LENGTH IN RETLEN.
*
         JSR   ]HOME
         _PRN  "SUBSTRING DELETION",8D
         _PRN  "==================",8D8D
         SDEL  #S1;#5;#10
         _AXLIT #RETLEN
         JSR   _PS
         _WAIT
*
         JSR   ]HOME
         _PRN  " ",8D8D
         _PRN  "FIN!",8D8D
*
         JMP   $3D0
*
** THE FOLLOWING SUBROUTINE IS A COPY OF THE STDIO
** LIBRARY'S PRNSTR SUBROUTINE, WHICH IS USED TO
** PRINT STRINGS WITH A PRECEDING LENGTH-BYTE. THIS
** IS USED FOR SHOWING THE OUTPUT OF THE VARIOUS
** STRING MACROS.
*
]STRLEN  HEX   0000
]COUT1   EQU   $FDF0
_PS
         STA   ADDR1
         STX   ADDR1+1
         LDY   #0
         LDA   (ADDR1),Y
         STA   ]STRLEN
:_LP
         INY
         LDA   (ADDR1),Y
         JSR   ]COUT1
         CPY   ]STRLEN
         BNE   :_LP
         LDA   ]STRLEN
         RTS
*
S1       STR   "ONE RING TO RULE THEM ALL"
S2       STR   " ONE RING TO FIND THEM "
S3       STR   " ONE RING TO BRING THEM ALL"
S4       STR   "AND IN THE DARKNESS BIND THEM "
S5       STR   "this is a test? a test. a test! a test."
S6       STR   "this is a test."
S7       STR   "ZERO ONE TWO THREE FOUR FIVE SIX"
*
*``````````````````````````````*
*        BOTTOM INCLUDES       *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
** BOTTOM INCLUDES
*
         PUT   MIN.LIB.REQUIRED.ASM
*
** INDIVIDUAL SUBROUTINE INCLUDES
*
** STRING SUBROUTINES
*
         PUT   SUB.SUBTOK.ASM
         PUT   SUB.SUBCOPY.ASM
         PUT   SUB.SUBDEL.ASM
         PUT   SUB.SUBINS.ASM
         PUT   SUB.SUBPOS.ASM
         PUT   SUB.SUBCHARCNT.ASM

```

























