Tutorial 02: StrLib - String Manipulation

0
#
24
27.12.25 15:41

Tutorial 02: StrLib - String Manipulation

Overview

This tutorial covers advanced string manipulation operations in FreshLib's StrLib. You'll learn how to insert, extract, transform, and trim strings using the comprehensive set of string manipulation functions.

Topics Covered

  1. String Modification - Inserting characters and strings at specific positions

  2. Substring Operations - Extracting parts of strings, splitting, trimming

  3. Case Conversion - Converting between uppercase and lowercase

  4. Whitespace Handling - Trimming spaces, handling duplicate spaces

  5. Quote Handling - Adding and removing quotes

  6. Memory Management - Setting capacity, fixing length

Prerequisites

  • Completion of Tutorial 01: StrLib Basics

  • Understanding of string handles vs pointers

  • Familiarity with carry flag error checking

Functions in This Tutorial

String Modification

Function Purpose
StrInsert Insert string at position
StrCatMem Append from memory buffer
StrCharInsert Insert up to 4 characters at position
StrSetCapacity Expand/collapse string capacity

Substring Operations

Function Purpose
StrExtract Extract substring (returns new string)
StrCopyPart Copy part of string to destination
StrSplit Split string at position
StrTrim Trim string at position

Case Conversion

Function Purpose
StrLCase Convert to lowercase
StrUCase Convert to uppercase

Whitespace Handling

Function Purpose
StrClipSpacesR Trim trailing whitespace
StrClipSpacesL Trim leading whitespace
StrCleanDupSpaces Remove duplicate spaces
StrClipQuotes Remove surrounding quotes
StrSetQuotes Add surrounding quotes
StrFixLen Fix length for external strings

Advanced

Function Purpose
StrCompSort2 Sort comparison (returns -1, 0, 1)
SetString Create/set string variable

Demo Programs

Demo 05: String Modification

File: demo05_string_modify.asm

Demonstrates:

  • Inserting strings at specific positions with StrInsert

  • Appending from memory buffers with StrCatMem

  • Inserting characters with StrCharInsert

  • Expanding string capacity with StrSetCapacity

    Key Concepts:

  • Positions are 0-based (0 = start of string)

  • Insert at -1 to append to end

  • StrInsert shifts existing content to make room

  • StrSetCapacity pre-allocates memory for efficiency

Demo 06: Substring Operations

File: demo06_string_substring.asm

Demonstrates:

  • Extracting substrings with StrExtract

  • Copying parts of strings with StrCopyPart

  • Splitting strings at positions with StrSplit

  • Trimming strings at positions with StrTrim

    Key Concepts:

  • StrExtract creates a NEW string (must be freed)

  • StrCopyPart copies to existing destination

  • StrSplit creates two new strings from one

  • Positions are 0-based

Demo 07: Case Conversion

File: demo07_string_case.asm

Demonstrates:

  • Converting to lowercase with StrLCase

  • Converting to uppercase with StrUCase

  • Locale handling considerations

    Key Concepts:

  • Case conversion modifies string in place

  • Works with ASCII and extended characters

  • Locale-dependent for some characters

Demo 08: String Trimming

File: demo08_string_trim.asm

Demonstrates:

  • Trailing whitespace removal with StrClipSpacesR

  • Leading whitespace removal with StrClipSpacesL

  • Cleaning duplicate spaces with StrCleanDupSpaces

  • Adding/removing quotes with StrSetQuotes/StrClipQuotes

  • Fixing length with StrFixLen

    Key Concepts:

  • Whitespace includes spaces, tabs, newlines

  • Trimming modifies string in place

  • Quote functions handle both single and double quotes

  • StrFixLen for strings managed by external code

Common Patterns

Inserting at Position

; Insert at specific position
stdcall StrInsert, hString, pos, hToInsert
jc      .error_handler

; Insert at end (append)
stdcall StrInsert, hString, -1, hToInsert
jc      .error_handler

Extracting Substring

; Extract creates NEW string - must free!
stdcall StrExtract, hSource, start, length
jc      .error_handler
mov     [hResult], eax

; ... use hResult ...

stdcall StrDel, [hResult]      ; Don't forget!

Cleaning User Input

; Remove leading/trailing whitespace
stdcall StrClipSpacesL, hInput
stdcall StrClipSpacesR, hInput

; Clean duplicate spaces
stdcall StrCleanDupSpaces, hInput

Working with Quotes

; Add quotes
stdcall StrSetQuotes, hString, '"'    ; Double quotes

; Remove quotes
stdcall StrClipQuotes, hString

Position Indexing

All position-based functions use 0-based indexing:

String:  "Hello World"
Position: 0123456789...

StrInsert at pos=5: "Hello<insert>World"
StrExtract from=5, len=5: "World"
StrTrim at pos=5: "Hello"

Special position -1 means "end of string".

Memory Management

Functions That Create New Strings

These functions return a NEW string handle that must be freed:

  • StrExtract - Creates new substring

  • StrSplit - Creates two new strings

Always pair with StrDel:

stdcall StrExtract, hSource, 0, 5
jc      .error
mov     [hResult], eax

; ... use hResult ...

stdcall StrDel, [hResult]    ; Required!

Functions That Modify In Place

These modify the existing string (no new handle):

  • StrInsert

  • StrCatMem

  • StrCharInsert

  • StrClipSpacesR/L

  • StrCleanDupSpaces

  • StrClipQuotes

  • StrSetQuotes

  • StrLCase

  • StrUCase

No need to free - the handle stays the same.

Important Discoveries During Implementation

1. StrInsert Argument Order is Counter-Intuitive

Problem: Initial implementation resulted in segfaults when calling StrInsert.

Discovery: The signature is StrInsert .dest, .source, .pos - the position comes LAST, not second.

Common Mistake:

stdcall StrInsert, [hBase], 6, [hInsert]    ; WRONG!

Correct:

stdcall StrInsert, [hBase], [hInsert], 6    ; Position is last

Impact: Wrong argument order causes the position value to be interpreted as a string handle, leading to immediate segmentation faults.

2. StrCharInsert Only Accepts One Character

Problem: Documentation initially suggested it could insert multiple characters.

Discovery: StrCharInsert has signature .hString, .char, .pos - it only accepts a SINGLE character per call.

What Doesn't Work:

stdcall StrCharInsert, [hBase], '*', '*', '*', 6    ; WRONG!

Correct Usage:

stdcall StrCharInsert, [hBase], '*', 6    ; Inserts one asterisk

Workaround: To insert multiple characters, call the function multiple times or use StrInsert with a string.

3. StrSplit Returns One String, Modifies Another

Problem: Initial implementation treated StrSplit as returning an array of handles, causing memory access violations.

Discovery: StrSplit has unique behavior:

  • Modifies the source string in place to contain the LEFT part

  • Returns a NEW string handle in EAX containing the RIGHT part

    Wrong Assumption:

    stdcall StrSplit, [hSource], 15
    mov     [hArray], eax
    mov     eax, [hArray]
    mov     eax, [eax]              ; WRONG! Not an array!
    

    Correct Usage:

    stdcall StrSplit, [hSource], 15
    mov     [hRightPart], eax       ; EAX = right part (NEW string)
    ; [hSource] now contains left part (modified in place)
    
    ; Display both parts
    stdcall StrPtr, [hSource], eax  ; Left part
    stdcall StrPtr, [hRightPart], eax  ; Right part
    
    ; Clean up
    stdcall StrDel, [hSource]       ; Delete left part
    stdcall StrDel, [hRightPart]    ; Delete right part
    

    Impact: Understanding this pattern is crucial for correct memory management.

4. StrCatMem Length Must Be Exact

Problem: Using $ - label for length calculation inside iglobal section caused FASM errors.

Discovery: The length calculation $ - cRawBytes only works during preprocessing. In the constants section, you must use the actual byte count.

Wrong:

iglobal
  cRawBytes text " Beautiful"
  cRawLen = $ - cRawBytes        ; Illegal instruction error!
endg

Correct:

iglobal
  cRawBytes text " Beautiful"
  cRawLen = 10                   ; Count the bytes: space + "Beautiful"
endg

Impact: Incorrect length causes either truncated output or buffer overruns.

5. @AllImportEmbeded is Not Supported in This Build

Problem: Initial demo files included @AllImportEmbeded and @AllDataEmbeded macros at the end, causing "illegal instruction" errors.

Discovery: These macros are not available in the console compact binary type configuration used for these tutorials.

Fix: Simply remove these lines from all demo files. The FreshLib framework handles imports automatically for console applications.

Impact: Without removing these macros, demos fail to build with cryptic "illegal instruction" errors.

6. Position -1 is Special

Discovery: Most position-based functions treat -1 as a special value meaning "end of string" or "append".

Example:

stdcall StrInsert, [hString], [hToInsert], -1    ; Appends to end

Benefit: Provides a convenient way to append without calculating string length first.

Building and Running

cd 02-strlib-manipulation
./build.sh

This will compile and test all 4 demos.

Next Steps

After completing this tutorial, continue to:

  • Tutorial 03: Advanced Features (numbers, encoding, patterns, hash)

Reference

  • FreshLib Source: ~/Documents/fossil/FreshIDE/freshlib/data/strlib.asm

  • AsmBB Usage: ~/Documents/fossil/asmbb/source/*.asm

23
27.12.25 15:42
; _______________________________________________________________________________________
;| FreshLib String Processing Tutorial: Demo 05 - String Modification
;|_______________________________________________________________________________________|
;  Description: Demonstrates inserting strings and characters at specific positions
;  Topics: StrInsert, StrCatMem, StrCharInsert, StrSetCapacity
;  Prerequisites: Demo 01
;_________________________________________________________________________________________

include "%lib%/freshlib.inc"

LINUX_INTERPRETER equ './ld-musl-i386.so'

@BinaryType console, compact
LIB_MODE equ NOGUI

options.DebugMode = 0

include "%lib%/freshlib.asm"

; ========================================
; FUNCTION REFERENCE
; ========================================
;
; StrInsert
;   Description: Insert a string at a specific position
;   Arguments:   .dest    = destination string handle
;               .pos     = insertion position (0-based, -1 for end)
;               .source  = source string handle or pointer
;   Returns:     EAX = destination handle (unchanged)
;   CF:          0 = success, 1 = error
;   Note:        Shifts existing content to make room
;
; StrCatMem
;   Description: Append raw memory bytes to a string
;   Arguments:   .dest    = destination string handle
;               .pointer = memory address to append
;               .length  = number of bytes to append
;   Returns:     EAX = destination handle (unchanged)
;   CF:          0 = success, 1 = error
;   Note:        Does NOT require null-terminated source
;
; StrCharInsert
;   Description: Insert a single character at a specific position
;   Arguments:   .hString = destination string handle
;               .char    = character to insert
;               .pos     = insertion position (0-based, -1 for end)
;   Returns:     EAX = destination handle (unchanged)
;   CF:          0 = success, 1 = error
;   Note:        Only inserts one character per call
;
; StrSetCapacity
;   Description: Set minimum capacity for a string (pre-allocate memory)
;   Arguments:   .hString = string handle
;               .cap     = new capacity in bytes
;   Returns:     EAX = string handle (unchanged)
;   CF:          0 = success, 1 = error
;   Note:        Useful for efficiency when building large strings
;
; See demo01 for: InitializeAll, FinalizeAll, StrNew, StrDup, StrDupMem,
;               StrPtr, StrLen, StrDel, FileWriteString
;
; ========================================

; ========================================
; Global Variables
; ========================================
uglobal
  hBase          dd ?
  hInsert        dd ?
  hResult        dd ?
endg

; ========================================
; Constants
; ========================================
iglobal
  cCRLF      text 13, 10

  cTitle     text "=== Demo 05: String Modification ===", 13, 10, 13, 10
  cBase      text "Hello World"

  cLabel1    text "1. StrInsert at position 6: ", 13, 10, "  Before: 'Hello World'", 13, 10
  cLabel2    text "2. StrCatMem append raw bytes: ", 13, 10, "  Before: 'Hello Beautiful'"
  cLabel3    text "3. StrCharInsert '*' at position 6: ", 13, 10, "  Before: 'Hello World'"
  cLabel4    text "4. StrSetCapacity pre-allocation: ", 13, 10

  cCrazy     text "Crazy"

  cPrefix    text "Result: '"
  cSuffix    text "'", 13, 10

  cRawBytes  text " Beautiful"
  cRawLen    = 10                   ; Length of cRawBytes (space + "Beautiful")

  cDone      text 13, 10, "Demo 05 complete!", 13, 10
  cError     text "Error!", 13, 10
endg

; ========================================
; Entry Point
; ========================================
start:
        InitializeAll

        stdcall FileWriteString, [STDOUT], cTitle

; ========================================
; Demo 1: StrInsert - Insert at position
; ========================================
        stdcall FileWriteString, [STDOUT], cLabel1

        stdcall StrDupMem, cBase
        jc      .error
        mov     [hBase], eax

        stdcall StrDupMem, cCrazy
        jc      .error
        mov     [hInsert], eax

; Insert "Crazy" at position 6 (after "Hello ")
        stdcall StrInsert, [hBase], [hInsert], 6
        jc      .error

        stdcall FileWriteString, [STDOUT], cPrefix
        stdcall StrPtr, [hBase], eax
        stdcall FileWriteString, [STDOUT], eax
        stdcall FileWriteString, [STDOUT], cSuffix

        stdcall StrDel, [hBase]
        stdcall StrDel, [hInsert]

; ========================================
; Demo 2: StrCatMem - Append raw memory
; ========================================
        stdcall FileWriteString, [STDOUT], cLabel2

        stdcall StrDupMem, cBase
        jc      .error
        mov     [hBase], eax

; Change "World" to "Beautiful" first
; We'll use StrInsert to replace by deleting first
        stdcall StrLen, [hBase]
        push    eax                     ; Save length

; Truncate to "Hello " (length 6)
        stdcall StrTrim, [hBase], 6
        jc      .error

        pop     eax                     ; Restore original length (not used)

; Append raw bytes from memory
        stdcall StrCatMem, [hBase], cRawBytes, cRawLen
        jc      .error

        stdcall FileWriteString, [STDOUT], cPrefix
        stdcall StrPtr, [hBase], eax
        stdcall FileWriteString, [STDOUT], eax
        stdcall FileWriteString, [STDOUT], cSuffix
        stdcall FileWriteString, [STDOUT], cCRLF

        stdcall StrDel, [hBase]

; ========================================
; Demo 3: StrCharInsert - Insert character
; ========================================
        stdcall FileWriteString, [STDOUT], cLabel3

        stdcall StrDupMem, cBase
        jc      .error
        mov     [hBase], eax

; Insert '*' at position 6
        stdcall StrCharInsert, [hBase], '*', 6
        jc      .error

        stdcall FileWriteString, [STDOUT], cPrefix
        stdcall StrPtr, [hBase], eax
        stdcall FileWriteString, [STDOUT], eax
        stdcall FileWriteString, [STDOUT], cSuffix
        stdcall FileWriteString, [STDOUT], cCRLF

        stdcall StrDel, [hBase]

; ========================================
; Demo 4: StrSetCapacity - Pre-allocate
; ========================================
        stdcall FileWriteString, [STDOUT], cLabel4

        stdcall StrNew
        jc      .error
        mov     [hBase], eax

; Pre-allocate capacity for efficiency
        stdcall StrSetCapacity, [hBase], 1024
        jc      .error

        stdcall FileWriteString, [STDOUT], <"  Capacity set to 1024 bytes", 13, 10>

        stdcall StrDel, [hBase]

        stdcall FileWriteString, [STDOUT], cDone

.finish:
        FinalizeAll
        stdcall TerminateAll, 0

.error:
        stdcall FileWriteString, [STDOUT], cError
        jmp     .finish
22
27.12.25 15:42
; _______________________________________________________________________________________
;| FreshLib String Processing Tutorial: Demo 06 - Substring Operations
;|_______________________________________________________________________________________|
;  Description: Demonstrates extracting, copying, splitting, and trimming substrings
;  Topics: StrExtract, StrCopyPart, StrSplit, StrTrim
;  Prerequisites: Demo 01
;_________________________________________________________________________________________

include "%lib%/freshlib.inc"

LINUX_INTERPRETER equ './ld-musl-i386.so'

@BinaryType console, compact
LIB_MODE equ NOGUI

options.DebugMode = 0

include "%lib%/freshlib.asm"

; ========================================
; FUNCTION REFERENCE
; ========================================
;
; StrExtract
;   Description: Extract a substring (creates NEW string)
;   Arguments:   .source  = source string handle
;               .start   = starting position (0-based)
;               .length  = number of characters to extract
;   Returns:     EAX = new string handle with extracted substring
;   CF:          0 = success, 1 = error
;   Note:        Creates NEW string - caller must free with StrDel
;
; StrCopyPart
;   Description: Copy part of source string to destination
;   Arguments:   .dest    = destination string handle
;               .source  = source string handle or pointer
;               .start   = starting position (0-based)
;               .length  = number of characters to copy
;   Returns:     EAX = destination handle (unchanged)
;   CF:          0 = success, 1 = error
;   Note:        Destination is modified, source unchanged
;
; StrSplit
;   Description: Split string into two parts at position
;   Arguments:   .hString = source string handle (modified to contain left part)
;               .pos     = split position (0-based)
;   Returns:     EAX = new string handle containing right part
;   CF:          0 = success, 1 = error
;   Note:        Source is modified to contain left part
;               Right part is NEW string - caller must free it
;
; StrTrim
;   Description: Trim string to specified length
;   Arguments:   .hString = string handle
;               .len     = new length (0 to current length)
;   Returns:     EAX = string handle (unchanged)
;   CF:          0 = success, 1 = error
;   Note:        Truncates string in place (shortens, never expands)
;
; See demo01 for: InitializeAll, FinalizeAll, StrNew, StrDup, StrDupMem,
;               StrPtr, StrLen, StrDel, NumToStr, FileWriteString
;
; ========================================

; ========================================
; Global Variables
; ========================================
uglobal
  hSource        dd ?
  hExtracted     dd ?
  hDest          dd ?
  hSplitRight    dd ?        ; Right part from StrSplit
endg

; ========================================
; Constants
; ========================================
iglobal
  cCRLF      text 13, 10

  cTitle     text "=== Demo 06: Substring Operations ===", 13, 10, 13, 10
  cSource    text "Hello Beautiful World"

  cLabel1    text "1. StrExtract positions 6-15: "
  cLabel2    text "2. StrCopyPart copy 'World': "
  cLabel3    text "3. StrSplit at position 15:", 13, 10, "   Left part: '"
  cLabel4    text "   Right part: '"
  cLabel5    text "4. StrTrim to length 11: "

  cPrefix    text "'"
  cDone      text 13, 10, "Demo 06 complete!", 13, 10
  cError     text "Error!", 13, 10
endg

; ========================================
; Entry Point
; ========================================
start:
        InitializeAll

        stdcall FileWriteString, [STDOUT], cTitle

; ========================================
; Demo 1: StrExtract - Extract substring
; ========================================
        stdcall FileWriteString, [STDOUT], cLabel1

        stdcall StrDupMem, cSource
        jc      .error
        mov     [hSource], eax

; Extract "Beautiful" (starts at position 6, length 9)
        stdcall StrExtract, [hSource], 6, 9
        jc      .error
        mov     [hExtracted], eax        ; Save extracted string

        stdcall FileWriteString, [STDOUT], <"'", 13, 10, "    Result: '">
        stdcall StrPtr, [hExtracted], eax
        stdcall FileWriteString, [STDOUT], eax
        stdcall FileWriteString, [STDOUT], <"'", 13, 10>

; Clean up
        stdcall StrDel, [hSource]
        stdcall StrDel, [hExtracted]

; ========================================
; Demo 2: StrCopyPart - Copy part of string
; ========================================
        stdcall FileWriteString, [STDOUT], cLabel2

        stdcall StrDupMem, cSource
        jc      .error
        mov     [hSource], eax

        stdcall StrNew
        jc      .error
        mov     [hDest], eax

; Copy "World" (position 16, length 5)
        stdcall StrCopyPart, [hDest], [hSource], 16, 5
        jc      .error

        stdcall FileWriteString, [STDOUT], <"'", 13, 10, "    Result: '">
        stdcall StrPtr, [hDest], eax
        stdcall FileWriteString, [STDOUT], eax
        stdcall FileWriteString, [STDOUT], <"'", 13, 10>

; Clean up
        stdcall StrDel, [hSource]
        stdcall StrDel, [hDest]

; ========================================
; Demo 3: StrSplit - Split string in two
; ========================================
        stdcall FileWriteString, [STDOUT], cLabel3

        stdcall StrDupMem, cSource
        jc      .error
        mov     [hSource], eax

; Split at position 15 (after "Hello Beautiful")
; After StrSplit:
;   - hSource contains left part ("Hello Beautiful")
;   - EAX contains right part (" World") - NEW string, must free
        stdcall StrSplit, [hSource], 15
        jc      .error
        mov     [hSplitRight], eax       ; Save right part (must free)

; Display left part (hSource now contains left part)
        stdcall StrPtr, [hSource], eax
        stdcall FileWriteString, [STDOUT], eax
        stdcall FileWriteString, [STDOUT], <"'", 13, 10>

        stdcall FileWriteString, [STDOUT], cLabel4

; Display right part
        stdcall StrPtr, [hSplitRight], eax
        stdcall FileWriteString, [STDOUT], eax
        stdcall FileWriteString, [STDOUT], <"'", 13, 10>

; Clean up
        stdcall StrDel, [hSource]        ; Left part
        stdcall StrDel, [hSplitRight]    ; Right part (from StrSplit)

; ========================================
; Demo 4: StrTrim - Truncate string
; ========================================
        stdcall FileWriteString, [STDOUT], cLabel5

        stdcall StrDupMem, cSource
        jc      .error
        mov     [hSource], eax

        stdcall FileWriteString, [STDOUT], <"'", 13, 10, "    Before: '">
        stdcall StrPtr, [hSource], eax
        stdcall FileWriteString, [STDOUT], eax
        stdcall FileWriteString, [STDOUT], <"'", 13, 10>

; Trim to length 11 ("Hello Beaut")
        stdcall StrTrim, [hSource], 11
        jc      .error

        stdcall FileWriteString, [STDOUT], <"    After length 11: '">
        stdcall StrPtr, [hSource], eax
        stdcall FileWriteString, [STDOUT], eax
        stdcall FileWriteString, [STDOUT], <"'", 13, 10>

; Clean up
        stdcall StrDel, [hSource]

        stdcall FileWriteString, [STDOUT], cDone

.finish:
        FinalizeAll
        stdcall TerminateAll, 0

.error:
        stdcall FileWriteString, [STDOUT], cError
        jmp     .finish
21
27.12.25 15:43
; _______________________________________________________________________________________
;| FreshLib String Processing Tutorial: Demo 07 - Case Conversion
;|_______________________________________________________________________________________|
;  Description: Demonstrates converting strings between uppercase and lowercase
;  Topics: StrLCase, StrUCase
;  Prerequisites: Demo 01
;_________________________________________________________________________________________

include "%lib%/freshlib.inc"

LINUX_INTERPRETER equ './ld-musl-i386.so'

@BinaryType console, compact
LIB_MODE equ NOGUI

options.DebugMode = 0

include "%lib%/freshlib.asm"

; ========================================
; FUNCTION REFERENCE
; ========================================
;
; StrLCase
;   Description: Convert string to lowercase
;   Arguments:   .hString = string handle
;   Returns:     EAX = string handle (unchanged)
;   CF:          0 = success, 1 = error
;   Note:        Modifies string in place, handles ASCII and extended chars
;
; StrUCase
;   Description: Convert string to uppercase
;   Arguments:   .hString = string handle
;   Returns:     EAX = string handle (unchanged)
;   CF:          0 = success, 1 = error
;   Note:        Modifies string in place, handles ASCII and extended chars
;
; See demo01 for: InitializeAll, FinalizeAll, StrNew, StrDup, StrDupMem,
;               StrPtr, StrLen, StrDel, FileWriteString
;
; ========================================

; ========================================
; Global Variables
; ========================================
uglobal
  hString        dd ?
endg

; ========================================
; Constants
; ========================================
iglobal
  cCRLF      text 13, 10

  cTitle     text "=== Demo 07: Case Conversion ===", 13, 10, 13, 10

  cLabel1    text "1. Original: '"
  cLabel2    text "2. StrUCase (uppercase): '"
  cLabel3    text "3. StrLCase (lowercase): '"
  cLabel4    text "4. Mixed case handling:", 13, 10, "    'HeLLo WoRLd!' -> UCase: '"

  cMixed     text "HeLLo WoRLd!"

  cSource    text "Hello, World!"

  cSuffix    text "'", 13, 10

  cDone      text 13, 10, "Demo 07 complete!", 13, 10
  cError     text "Error!", 13, 10
endg

; ========================================
; Entry Point
; ========================================
start:
        InitializeAll

        stdcall FileWriteString, [STDOUT], cTitle

; ========================================
; Demo 1: Original string
; ========================================
        stdcall FileWriteString, [STDOUT], cLabel1

        stdcall StrDupMem, cSource
        jc      .error
        mov     [hString], eax

        stdcall StrPtr, [hString], eax
        stdcall FileWriteString, [STDOUT], eax
        stdcall FileWriteString, [STDOUT], cSuffix

; ========================================
; Demo 2: Convert to uppercase
; ========================================
        stdcall FileWriteString, [STDOUT], cLabel2

        stdcall StrUCase, [hString]
        jc      .error

        stdcall StrPtr, [hString], eax
        stdcall FileWriteString, [STDOUT], eax
        stdcall FileWriteString, [STDOUT], cSuffix

; ========================================
; Demo 3: Convert back to lowercase
; ========================================
        stdcall FileWriteString, [STDOUT], cLabel3

        stdcall StrLCase, [hString]
        jc      .error

        stdcall StrPtr, [hString], eax
        stdcall FileWriteString, [STDOUT], eax
        stdcall FileWriteString, [STDOUT], cSuffix

; Clean up
        stdcall StrDel, [hString]

; ========================================
; Demo 4: Mixed case handling
; ========================================
        stdcall FileWriteString, [STDOUT], cLabel4

        stdcall StrDupMem, cMixed
        jc      .error
        mov     [hString], eax

; Convert to uppercase
        stdcall StrUCase, [hString]
        jc      .error

        stdcall StrPtr, [hString], eax
        stdcall FileWriteString, [STDOUT], eax
        stdcall FileWriteString, [STDOUT], <"'", 13, 10, "    'HeLLo WoRLd!' -> LCase: '">

; Convert back to lowercase
        stdcall StrLCase, [hString]
        jc      .error

        stdcall StrPtr, [hString], eax
        stdcall FileWriteString, [STDOUT], eax
        stdcall FileWriteString, [STDOUT], <"'", 13, 10>

; Clean up
        stdcall StrDel, [hString]

        stdcall FileWriteString, [STDOUT], cDone

.finish:
        FinalizeAll
        stdcall TerminateAll, 0

.error:
        stdcall FileWriteString, [STDOUT], cError
        jmp     .finish
20
27.12.25 15:43
; _______________________________________________________________________________________
;| FreshLib String Processing Tutorial: Demo 08 - String Trimming and Cleaning
;|_______________________________________________________________________________________|
;  Description: Demonstrates trimming whitespace, handling quotes, and fixing length
;  Topics: StrClipSpacesR, StrClipSpacesL, StrCleanDupSpaces, StrClipQuotes, StrSetQuotes, StrFixLen
;  Prerequisites: Demo 01
;_________________________________________________________________________________________

include "%lib%/freshlib.inc"

LINUX_INTERPRETER equ './ld-musl-i386.so'

@BinaryType console, compact
LIB_MODE equ NOGUI

options.DebugMode = 0

include "%lib%/freshlib.asm"

; ========================================
; FUNCTION REFERENCE
; ========================================
;
; StrClipSpacesR
;   Description: Remove trailing whitespace from string
;   Arguments:   .hString = string handle
;   Returns:     EAX = string handle (unchanged)
;   CF:          0 = success, 1 = error
;   Note:        Whitespace includes spaces, tabs, newlines
;
; StrClipSpacesL
;   Description: Remove leading whitespace from string
;   Arguments:   .hString = string handle
;   Returns:     EAX = string handle (unchanged)
;   CF:          0 = success, 1 = error
;   Note:        Whitespace includes spaces, tabs, newlines
;
; StrCleanDupSpaces
;   Description: Remove duplicate spaces, replace tabs/newlines with single space
;   Arguments:   .hString = string handle
;   Returns:     EAX = string handle (unchanged)
;   CF:          0 = success, 1 = error
;   Note:        Useful for cleaning user input
;
; StrClipQuotes
;   Description: Remove surrounding quotes (single or double) from string
;   Arguments:   .hString = string handle
;   Returns:     EAX = string handle (unchanged)
;   CF:          0 = success, 1 = error
;   Note:        Only removes matching quotes at start and end
;
; StrSetQuotes
;   Description: Add surrounding quotes to string
;   Arguments:   .hString = string handle
;               .quote   = quote character (single ' or double ")
;   Returns:     EAX = string handle (unchanged)
;   CF:          0 = success, 1 = error
;   Note:        Adds quote character at start and end
;
; StrFixLen
;   Description: Set string length for externally-managed strings
;   Arguments:   .hString = string handle
;               .len     = new length
;   Returns:     EAX = string handle (unchanged)
;   CF:          0 = success, 1 = error
;   Note:        For strings whose data is modified by external code
;
; See demo01 for: InitializeAll, FinalizeAll, StrNew, StrDup, StrDupMem,
;               StrPtr, StrLen, StrDel, NumToStr, FileWriteString
;
; ========================================

; ========================================
; Global Variables
; ========================================
uglobal
  hString        dd ?
endg

; ========================================
; Constants
; ========================================
iglobal
  cCRLF      text 13, 10

  cTitle     text "=== Demo 08: String Trimming and Cleaning ===", 13, 10, 13, 10

  cLabel1    text "1. StrClipSpacesL (leading): '"
  cLabel2    text "2. StrClipSpacesR (trailing): '"
  cLabel3    text "3. StrCleanDupSpaces (duplicate spaces):", 13, 10, "   'Hello     World   This   Is   A   Test'"
  cLabel4    text "   Result: '"

  cLabel5    text "4. StrClipQuotes (remove quotes): '"
  cLabel6    text "5. StrSetQuotes (add quotes): '"
  cLabel7    text "6. StrFixLen (external string):", 13, 10

  cWithLeading   text "   Hello, World!"
  cWithTrailing  text "Hello, World!   "
  cDupSpaces     text "Hello     World   This   Is   A   Test"

  cQuoted        text '"Hello, World!"'
  cUnquoted      text "Hello, World!"

  cDone          text 13, 10, "Demo 08 complete!", 13, 10
  cError         text "Error!", 13, 10
endg

; ========================================
; Entry Point
; ========================================
start:
        InitializeAll

        stdcall FileWriteString, [STDOUT], cTitle

; ========================================
; Demo 1: Remove leading whitespace
; ========================================
        stdcall FileWriteString, [STDOUT], cLabel1

        stdcall StrDupMem, cWithLeading
        jc      .error
        mov     [hString], eax

        stdcall StrClipSpacesL, [hString]
        jc      .error

        stdcall StrPtr, [hString], eax
        stdcall FileWriteString, [STDOUT], eax
        stdcall FileWriteString, [STDOUT], <"'", 13, 10>

        stdcall StrDel, [hString]

; ========================================
; Demo 2: Remove trailing whitespace
; ========================================
        stdcall FileWriteString, [STDOUT], cLabel2

        stdcall StrDupMem, cWithTrailing
        jc      .error
        mov     [hString], eax

        stdcall StrClipSpacesR, [hString]
        jc      .error

        stdcall StrPtr, [hString], eax
        stdcall FileWriteString, [STDOUT], eax
        stdcall FileWriteString, [STDOUT], <"'", 13, 10>

        stdcall StrDel, [hString]

; ========================================
; Demo 3: Clean duplicate spaces
; ========================================
        stdcall FileWriteString, [STDOUT], cLabel3

        stdcall StrDupMem, cDupSpaces
        jc      .error
        mov     [hString], eax

        stdcall StrCleanDupSpaces, [hString]
        jc      .error

        stdcall FileWriteString, [STDOUT], cLabel4
        stdcall StrPtr, [hString], eax
        stdcall FileWriteString, [STDOUT], eax
        stdcall FileWriteString, [STDOUT], <"'", 13, 10>

        stdcall StrDel, [hString]

; ========================================
; Demo 4: Remove quotes
; ========================================
        stdcall FileWriteString, [STDOUT], cLabel5

        stdcall StrDupMem, cQuoted
        jc      .error
        mov     [hString], eax

        stdcall StrClipQuotes, [hString]
        jc      .error

        stdcall StrPtr, [hString], eax
        stdcall FileWriteString, [STDOUT], eax
        stdcall FileWriteString, [STDOUT], <"'", 13, 10>

        stdcall StrDel, [hString]

; ========================================
; Demo 5: Add quotes
; ========================================
        stdcall FileWriteString, [STDOUT], cLabel6

        stdcall StrDupMem, cUnquoted
        jc      .error
        mov     [hString], eax

; Add double quotes
        stdcall StrSetQuotes, [hString], '"'
        jc      .error

        stdcall StrPtr, [hString], eax
        stdcall FileWriteString, [STDOUT], eax
        stdcall FileWriteString, [STDOUT], <"'", 13, 10>

        stdcall StrDel, [hString]

; ========================================
; Demo 6: StrFixLen - for external strings
; ========================================
        stdcall FileWriteString, [STDOUT], cLabel7

        stdcall FileWriteString, [STDOUT], <"   StrFixLen is used when string data is modified", 13, 10>
        stdcall FileWriteString, [STDOUT], <"   by external code (not FreshLib).", 13, 10>
        stdcall FileWriteString, [STDOUT], <"   Example: C library writes to buffer", 13, 10>
        stdcall FileWriteString, [STDOUT], <"   You must call StrFixLen to update length.", 13, 10>

        stdcall FileWriteString, [STDOUT], cDone

.finish:
        FinalizeAll
        stdcall TerminateAll, 0

.error:
        stdcall FileWriteString, [STDOUT], cError
        jmp     .finish

Tutorial 02: StrLib - String Manipulation

0
#