EuroAssembler Index Manual Download Source Macros


Sitemap Links Forum Tests Projects

cpuext32.htm
Macros
Align2Dword
Align2Qword
Clear
Compare
CopyTo
LodD
LodH
LodQD
LodQH
StoD
StoH
StoQD
StoQH
StripApostrophes
StripColons
StripQuotes
StripSpaces

This file can be included to 32bit programs written in Euro Assembler.
The library contains OS-independent macroinstructions with calling convention similar to the standard Intel machine instruction set. They mostly pass operands in general-purpose registers and change the register contents on return.

Align* performs alignment at run time,
Clear, Compare, CopyTo provide some string operations,
Lod* converts numbers from human-readable notation to a binary number,
Sto* does the opposite,
Strip* trims the string from garbage characters which may surround it.

Similar macros with identical names for different program width are defined in cpuext16.htm and cpuext64.htm.

See also cpuext.htm for width-indepentent macros.


cpuext32 HEAD
       INCLUDEHEAD1 status32.htm
; Definition of flags used by macros in this library.
%cpuextMinus    %SETA 0x80
%cpuextSigned   %SETA 0x40
%cpuextAlignL   %SETA 0x20
%cpuextLeading0 %SETA 0x10
%cpuextLowCase  %SETA 0x08
; Saved values in standard EBP frame.
%Param4         %SET EBP+48
%Param3         %SET EBP+44
%Param2         %SET EBP+40
%Param1         %SET EBP+36
%ReturnEAX      %SET EBP+28
%ReturnECX      %SET EBP+24
%ReturnEDX      %SET EBP+20
%ReturnEBX      %SET EBP+16
%ReturnEBP      %SET EBP+08
%ReturnESI      %SET EBP+04
%ReturnEDI      %SET EBP+00
↑ Align2Dword
This inline macro will align the 32bit GPR or contents of memory variable to DWORD value upward.
Input
Variable is 32bit register or memory operand.
Output
CF=0, other registers unchanged.
Examples
Align2Dword ECX Align2Dword [DwPointer]
Align2Dword %MACRO Variable
               ADDD %Variable,  3
               ANDD %Variable, ~3
            %ENDMACRO Align2Dword
↑ Align2Qword
This inline macro will align the 32bit GPR or memory variable to QWORD value upward.
Input
Variable is 32bit register or memory operand.
Output
CF=0, registers unchanged.
Example
Align2Qword ECX ; ECX changed from 12 to 16. Align2Qword [mem32]
Align2Qword %MACRO Variable
               ADDD %Variable,  7
               ANDD %Variable, ~7
            %ENDMACRO Align2Qword
↑ Clear Operand, Size=, Filler=0
This macro will fill the string in memory at Operand offset with the character Filler=.
Input
Operand is pointer to a memory variable.
Size= specifies number of bytes to fill. By default it is SIZE# Operand.
Filler=0 is DWORD value whose LSB will be used to fill the Operand.
Output
All registers are preserved.
Examples
Clear Buffer1, Filler=" " ; Fill the whole memory variable Buffer1 with spaces. Clear EDI, Size=80, Filler=EAX ; Fill the memory at EDI with the contents of AL.
Clear %MACRO Operand, Size=, Filler=0
        PUSHD %Operand
        %IF "%Size" !=== ""
          PUSHD %Size
        %ELSE
          PUSHD SIZE# (%Operand)
        %ENDIF
        PUSHD %Filler
        CALL Clear32@RT::
Clear32@RT:: PROC1
    PUSH EAX,ECX,EDX,EDI
      MOV EDX,[ESP+20] ; Filler
      MOV ECX,[ESP+24] ; Size
      MOV EDI,[ESP+28] ; Operand
      SHRD EAX,EDX,8
      SHRD EAX,EDX,8
      SHRD EAX,EDX,8
      SHRD EAX,EDX,8
      SHR ECX,1
      JNC .10
      STOSB
.10:  SHR ECX,1
      JNC .20
      STOSW
.20:  JECXZ .90
      REP:STOSD
.90:POP EDI,EDX,ECX,EAX
    RET 12
   ENDP1 Clear32@RT::
%ENDMACRO Clear
↑ Compare Data1Ptr, Data1Size, Data2Ptr, Data2Size
This macro will compare two data fields (strings) byte per byte.
Input
Data1Ptr and Data1Size specify the first data field,
Data2Ptr andData2Size the second one.
The last parameter (Data2Size) may be omitted and it equals to Data1Size in this case.
Output
ZF=1 if both fields are identical, otherwise ZF=0. All registers are preserved, .
Examples
Compare F1, SIZE# F1, F2, SIZE# F2 Compare EDI,ESI,ECX
Compare  %MACRO Data1Ptr,Data1Size,Data2Ptr,Data2Size
         %IF %# < 3                                                                                ; >
           %ERROR ID=5911, "Macro Compare requires 3 or 4 parameters."
           %EXITMACRO
         %ENDIF
         %IF %# > 3
           PUSHD %Data2Size,%Data2Ptr,%Data1Size,%Data1Ptr
         %ELSE
           PUSHD %Data1Size,%Data2Ptr,%Data1Size,%Data1Ptr
         %ENDIF
         CALL Compare32@RT::
Compare32@RT:: PROC1
       PUSH ECX,ESI,EDI
        MOV ESI,[ESP+16] ; %Data1Ptr
        MOV ECX,[ESP+20] ; %Data1Size
        MOV EDI,[ESP+24] ; %Data2Ptr
        CMP ECX,[ESP+28] ; %Data2Size
        JNE .90:
        REPE:CMPSB
   .90:POP EDI,ESI,ECX
       RET 16
  ENDP1 Compare32@RT::
%ENDMACRO Compare
↑ CopyTo Destination, Source, Size=
This macro will copy the memory content from Source to Destination.
Input
Destination is a pointer to target memory.
Source is a pointer to the source of data.
Size= specifies number of bytes to copy. By default it is the SIZE# Destination attribute, if possible. The size may be alternatively specified with the keyword Size=.
Output
All registers are preserved.
Examples
CopyTo Buffer1, Buffer2 CopyTo EDI,ESI,ECX CopyTo EDI,Line,Size=80
CopyTo  %MACRO Destination, Source, Size=
        %IF "%Size" !=== ""
          PUSHD %Size
        %ELSE
          %IF TYPE# %Destination = 'R'
            %ERROR ID=5912, "CopyTo data size not specified."
            %EXITMACRO CopyTo
          %ELSE
            PUSHD SIZE# (%Destination)
          %ENDIF
         %ENDIF
      PUSHD %Source, %Destination
      CALL CopyTo32@RT::
CopyTo32@RT:: PROC1
       PUSH ECX,ESI,EDI
        MOV ECX,[ESP+24] ; %Size
        MOV ESI,[ESP+20] ; %Source
        MOV EDI,[ESP+16] ; %Destination
        SHR ECX,1
        JNC .10:
        MOVSB
   .10: SHR ECX,1
        JNC .20:
        MOVSW
   .20: JECXZ .90
        REP:MOVSD
   .90:POP EDI,ESI,ECX
       RET 12
  ENDPROC1 CopyTo32@RT::
%ENDMACRO CopyTo
↑ LodD Source, Size=
Load signed or unsigned integer number in decimal notation and return its binary value in EAX.
LodD tolerates leading white spaces before the number and underscores _ inside the notation. The number may begin with + or -, at least one digit must immediately follow the sign.
Parsing stops when non-digit character is encountered or when the number of characters specified with Size= has been examinated.
Input
Source is a pointer to ANSI-encoded decimal number.
When the Source operand is not specified explicitly, ESI is assumed.
Size= specifies length of the source field in characters (=bytes). By default it is unlimited.
Output
CF=0, EAX=loaded number in range -2_147_483_648 .. 4_294_967_295.
ESI points behind the last parsed digit.
Error
CF=1, EAX,ESI unchanged
when the source number has wrong format:
1. After skipping the leading white spaces Source does not start with a digit or sign.
2. No digit immediately follows the sign.
3. Loaded number does not fit into 32 bits.
Example
InputField DB " -123.45" LodD InputField ; Loads EAX with -123d=0xFFFFFF85
Tested by
tmac32.htm
LodD  %MACRO  Source, Size=
    %IF "%Size" === ""
      %IF "%Source" === "" || "%Source" == "ESI"
        PUSHD -1
      %ELSE
        PUSHD SIZE# (%Source)
      %ENDIF
    %ELSE               ; Explicit Size was specified.
       PUSHD %Size
    %ENDIF
    %IF "%Source" === ""
       PUSH ESI         ; Implicit source.
    %ELSE
       PUSHD %Source
    %ENDIF
    CALL LodD32@RT::
LodD32@RT:: PROC1
     PUSHAD
       MOV EBP,ESP
       MOV EDX,[EBP+40] ; Size.
       MOV ESI,[EBP+36] ; Source.
       MOV ECX,EDX
       ADD EDX,ESI      ; Parse end limit.
       INC ECX
       JNZ .00:
       MOV EDX,-1
 .00:  SUB EAX,EAX
       SUB ECX,ECX      ; Signum.
       SUB EBX,EBX      ; Output value accumulator.
       MOV EDI,10
 .10:  CMP ESI,EDX
       JNB .Error:
       LODSB
       CMP AL,' '
       JBE .10:         ; Skip leading white spaces.
       ; Sign or digit expected.
       CMP AL,'+'
       JE .20:
       CMP AL,'-'
       JNE .30:
       DEC ECX
 .20: ; At least one digit expected behind the signum, otherwise error.
       CMP ESI,EDX
       JNB .Error:
       LODSB
 .30:  SUB AL,'0'
       JB .Error:
       CMP AL,9
       JA .Error:
       MOV EBX,EAX      ; Most significant digit loaded.
 .40: ; Other digits or underscores expexted, otherwise the parsing stops.
       CMP ESI,EDX
       JNB .EndOfNumber:
       LODSB
       CMP AL,'_'
       JE .40:
       SUB AL,'0'
       JB .EndOfNumber1:
       CMP AL,9
       JA .EndOfNumber1:
       XCHG EAX,EBX
       PUSH EDX
        MUL EDI
       POP EDX
       JC .Error:
       ADD EBX,EAX
       JC .Error:
       SUB EAX,EAX
       JMP .40:
 .Error:DEC ESI
       STC
       JMP .95:
 .EndOfNumber1:DEC ESI
 .EndOfNumber:
       TEST ECX         ; Minus?
       JZ .90:
       NEG EBX
  .90: CLC
       MOV [%ReturnEAX],EBX
  .95: MOV [%ReturnESI],ESI
     POPAD
     RET 8
  ENDPROC1 LodD32@RT::
%ENDMACRO LodD
↑ LodQD Source, Size=, Align=Left
Load 64bit number in decimal notation and return its binary value in register pair EDX:EAX.
LodQD tolerates underscores _ inside the notation. The number may begin with + or -, at least one digit must immediately follow the sign.
Parsing stops when non-digit character is encountered or when the number of characters specified with Size= has been examinated.
Input
Source is a pointer to ANSI-encoded decimal number.
When the Source operand is not specified explicitly, ESI is assumed.
Size= specifies number of characters (=bytes) in the source field. When the Size is not explicitly specified, it assumes SIZE# %Source. Size is not limited if it cannot be determined from %Source.
Align=Left. By default the source must start with sign or digit. LodQD will tolerate leading spaces or control characters only when Align=right.
Output
CF=0, EDX:EAX=loaded number in range -9_223_372_036_854_775_808 .. 18_446_744_073_709_551_615.
ESI points behind the last parsed digit.
Error
CF=1, EDX,EAX undefined
ESI unchanged
when the source number has wrong format:
1. source does not start with a digit or sign
2. no digit immediately follows the sign
3. loaded number does not fit into 64 bits
Example
InputField DB " +123.45" LodQD InputField, Align=right ; loads EDX=0, EAX=123d=0x0000007B MOV EBX,EAX ; save the integer part LODSB ; skips the decimal point LodQD ; loads EDX=0, EAX=45d=0x0000002D
LodQD  %MACRO  Source, Size=, Align=Left
    %LodQDflags %SETA %cpuextAlignL & "%Align[1]" == "L"
    PUSHD %LodQDflags
    %IF "%Size" === ""
      %IF "%Source" === "" || "%Source" == "ESI"
        PUSHD -1
      %ELSE
        PUSHD SIZE# (%Source)
      %ENDIF
    %ELSE
      PUSHD %Size
    %ENDIF
    %IF "%Source" === ""
       PUSH ESI
    %ELSE
      PUSHD %Source
    %ENDIF
    CALL LodQD32@RT::
LodQD32@RT:: PROC1
     SUB EAX,EAX          ; Initialize the result.
     SUB EDX,EDX
     PUSHAD
       MOV EBP,ESP
 %LodQD@RTflags  %SET EBP+44
 %LodQD@RTSize   %SET EBP+40
 %LodQD@RTSource %SET EBP+36
       MOV ESI,[%LodQD@RTSource]
       MOV ECX,[%LodQD@RTSize]
       SUB EAX,EAX
       SUB EBX,EBX
       MOV EDI,10
       JECXZ .Error:
       JSt [%LodQD@RTflags],%cpuextAlignL,.30
  .10: LODSB               ; White spaces are tolerated.
       CMP AL,' '
       JA .40:
       LOOP .10:
 .Error:STC ; Error
       JMP .99:
  .30: LODSB               ; Signum or digit expected.
  .40: CMP AL,'+'
       JE .70:
       CMP AL,'-'
       JNE .60:
       SetSt [%LodQD@RTflags],%cpuextMinus
       JMP .70:
  .50: SUB EAX,EAX         ; Decimal digit expected.
       LODSB
  .60: SUB AL,'0'
       JB .EON:
       CMP AL,9
       JA .EON:
       MOV EBX,EAX         ; Temporary save number 0..9
       ; Multiply partial result in %ReturnEDX:%ReturnEAX by EDI=10
       MOV EAX,[%ReturnEDX]
       MUL EDI
       JC .Error:
       MOV [%ReturnEDX],EAX
       MOV EAX,[%ReturnEAX]
       MUL EDI
       MOV [%ReturnEAX],EAX
       ADD [%ReturnEDX],EDX
       JC .Error:
       ADD [%ReturnEAX],EBX
       ADCD [%ReturnEDX],0
       JC .Error:
       SetSt [%LodQD@RTflags],%cpuextLeading0 ; At least one digit was found.
  .70: LOOP .50:
       INC ESI
  .EON:DEC ESI ; End of numer
       JNSt [%LodQD@RTflags],%cpuextLeading0,.Error:
       JNSt [%LodQD@RTflags],%cpuextMinus,.90:
       NOTD [%ReturnEAX]
       NOTD [%ReturnEDX]
       ADDD [%ReturnEAX],1
       ADCD [%ReturnEDX],0
  .90: CLC
       MOV [%ReturnESI],ESI
 .99: POPAD
     RET 12
  ENDP1 LodQD32@RT::
%ENDMACRO LodQD
↑ LodH Source, Size=, Align=Left
Load 32bit number in hexadecimal notation to register EAX. Number may contain hexadecimal digits '0'..'9', 'a'..'f', 'A'..'F' optionally prefixed with '+' or '-' sign. At least one hexadecimal digit should immediately follow the sign. Parsing stops when non-hexadigit character is encountered or when Size= is exhausted.
Prefix 0x is not supported (LodH would return EAX=0 and ESI behind the 0x.
Input
Source is a pointer to the ANSI-encoded hexadecimal number.
ESI is assumed when the Source operand is not specified explicitly.
Size= is number of characters in the source field. When the size is not explicitly specified, SIZE# %Source is assumed. Size is not limited if it cannot be determined from %Source.
Align=Left. By default the source must start with sign or hexadecimal digit. LodH will tolerate leading spaces or control characters only when Align=right.
Output
CF=0, EAX=loaded number
ESI=behind the last parsed source digit.
Error
CF=1, EAX,ESI unchanged
when the source number has wrong format:
1. source does not start with a hexadecimal digit or sign,
2. no hexadecimal digit immediately follows the sign,
3. loaded number does not fit into 32 bits.
Example
InputField DB "3FCh" LodH InputField ; loads EAX with 0x3FC=1020, ESI points to 'h'
LodH  %MACRO  Source, Size=, Align=Left
    %LodHflags %SETA  %cpuextAlignL & "%Align[1]" == "L"
    PUSHD %LodHflags
    %IF "%Size" === ""
      %IF "%Source" === "" || "%Source" == "ESI"
        PUSHD -1
      %ELSE
        PUSHD SIZE# (%Source)
      %ENDIF
    %ELSE
      PUSHD %Size
    %ENDIF
    %IF "%Source" === ""
      PUSH ESI
    %ELSE
      PUSHD %Source
    %ENDIF
    CALL LodH32@RT::
LodH32@RT:: PROC1
     PUSHAD
       MOV EBP,ESP
 %LodH@RTflags  %SET EBP+44
 %LodH@RTSize   %SET EBP+40
 %LodH@RTSource %SET EBP+36
       MOV ESI,[%LodH@RTSource]
       MOV ECX,[%LodH@RTSize]
       SUB EAX,EAX
       SUB EBX,EBX
       JECXZ .20:
       JSt [%LodH@RTflags],%cpuextAlignL,.30
  .10: LODSB             ; White spaces are tolerated.
       CMP AL,' '
       JA .40:
       LOOP .10:
  .20: STC ; Error.
       JMP .95:
  .30: LODSB             ; Signum or digit expected.
  .40: CMP AL,'+'
       JE .70:
       CMP AL,'-'
       JNE .60:
       SetSt [%LodH@RTflags],%cpuextMinus
       JMP .70:
  .50: ; Digit expected.
       LODSB
  .60: SUB AL,'0'
       JB .80:
       CMP AL,9
       JNA .65:
       SUB AL,'A'-'0'
       JB .80:
       CMP AL,5
       JNA .64:
       SUB AL,'a'-'A'
       JB .80:
       CMP AL,5
       JA .80:
  .64: ADD AL,10
  .65: ; EAX is now a valid nibble 0x00000000..0x0000000F.
       TEST EBX,0xF000_0000
       JNZ .20: ; Overflow.
       SAL EBX,4
       ADD EBX,EAX
       SetSt [%LodH@RTflags],%cpuextLeading0 ; At least one digit was found.
  .70: LOOP .50:
       JMP .85:
  .80: DEC ESI
  .85: JNSt [%LodH@RTflags],%cpuextLeading0,.20:
       JNSt [%LodH@RTflags],%cpuextMinus,.90:
       NEG EBX
  .90: CLC
       MOV [%ReturnEAX],EBX
       MOV [%ReturnESI],ESI
 .95:POPAD
     RET 12
  ENDP1 LodH32@RT::
%ENDMACRO LodH
↑ LodQH Source, Size=, Align=Left
Load 64bit number in hexadecimal notation to register pair EDX:EAX.
Number may contain hexadecimal digits '0'..'9', 'a'..'f', 'A'..'F' optionally prefixed with '+' or '-' sign. At least one hexadecimal digit should immediately follow the sign. Parsing stops when non-hexadigit character is encountered or when Size= is exhausted. Prefix 0x is not supported (LodQH would return EDX:EAX=0 and ESI behind the 0x.
Input
Source is a pointer to the ANSI-encoded hexadecimal number.
ESI is assumed when the Source operand is not specified explicitly.
Size= specifies the length of the source field. When the size is not explicitly specified, SIZE# %Source is assumed. Size is not limited if it cannot be determined from %Source.
Align=Left. By default the source must start with sign or hexadecimal digit. LodH will tolerate leading spaces or control characters only when Align=right.
Output
CF=0, EDX:EAX=loaded number
ESI=behind the last accepted source digit
Error
CF=1, EAX,ESI unchanged
when the source number has wrong format:
1. source does not start with a hexadecimal digit or sign
2. no hexadecimal digit immediately follows the sign
3. loaded number does not fit into 64 bits
Example
InputField DB "3FCh" LodQH InputField ; loads EDX=0, EAX=0x3FC=1020, ESI points to 'h'
LodQH  %MACRO  Source, Size=, Align=Left
    %LodQHflags %SETA  %cpuextAlignL & "%Align[1]" == "L"
    PUSHD %LodQHflags
    %IF "%Size" === ""
      %IF "%Source" === "" || "%Source" == "ESI"
        PUSHD -1
      %ELSE
        PUSHD SIZE# (%Source)
      %ENDIF
    %ELSE
      PUSHD %Size
    %ENDIF
    %IF "%Source" === ""
      PUSH ESI
    %ELSE
      PUSHD %Source
    %ENDIF
    CALL LodQH32@RT::
LodQH32@RT:: PROC1
     PUSHAD
       MOV EBP,ESP
 %LodQH@RTflags  %SET EBP+44
 %LodQH@RTSize   %SET EBP+40
 %LodQH@RTSource %SET EBP+36
       MOV ESI,[%LodQH@RTSource]
       MOV ECX,[%LodQH@RTSize]
       SUB EAX,EAX
       SUB EBX,EBX
       SUB EDX,EDX ; Result is calculated in EDX:EBX.
       JECXZ .20:
       JSt [%LodQH@RTflags],%cpuextAlignL,.30
  .10: LODSB            ; White spaces are tolerated.
       CMP AL,' '
       JA .40:
       LOOP .10:
  .20: STC ; Error
       JMP .95:
  .30: LODSB            ; Signum or digit expected.
  .40: CMP AL,'+'
       JE .70:
       CMP AL,'-'
       JNE .60:
       SetSt [%LodQH@RTflags],%cpuextMinus
       JMP .70:
  .50: ; Digit expected.
       LODSB
  .60: SUB AL,'0'
       JB .80:
       CMP AL,9
       JNA .65:
       SUB AL,'A'-'0'-10
       JB .80:
       CMP AL,15
       JNA .65
       SUB AL,'a'-'A'
       JB .80:
       CMP AL,15
       JA .80:
  .65: SAL EBX,1
       RCL EDX,1
       JC .20:
       SAL EBX,1
       RCL EDX,1
       JC .20:
       SAL EBX,1
       RCL EDX,1
       JC .20:
       SAL EBX,1
       RCL EDX,1
       JC .20:
       ADD EBX,EAX
       SetSt [%LodQH@RTflags],%cpuextLeading0 ; At least one digit was found.
  .70: LOOP .50:
  .80: JNSt [%LodQH@RTflags],%cpuextLeading0,.20:
       JNSt [%LodQH@RTflags],%cpuextMinus,.90:
       NOT EBX
       NOT EDX
       ADD EBX,1
       ADC EDX,0
  .90: CLC
       MOV [%ReturnEAX],EBX
       MOV [%ReturnEDX],EDX
       MOV [%ReturnESI],ESI
  .95:POPAD
     RET 12
  ENDP1 LodQH32@RT::
%ENDMACRO LodQH
↑ StoD Destination, Size=, Signed=Yes, Align=Left, LeadingZeroes=No
Store 32bit integer from EAX in decimal notation.
Input
EAX contains the input number.
Destination is a pointer to memory where the decimal number will be stored. EDI is assumed when Destination is omitted.
Size= specifies length of the Destination field. When the size is not explicitly specified, it is taken from SIZE# %Destination . Size is not limited if it cannot be determined from %Destination. Size will never exceed 11 characters. The output string is ANSI (1byte per digit).
Signed=Yes specifies whether the input number is treated as signed. Negative numbers will be prefixed with minus sign -, positive sign is not used.
Align=Left specifies alignment of the number in Destination field. If Size= cannot be determined, this parameter is ignored. When Align=right and Size= is specified, the vacant characters on the left side will be filled with spaces or unsignificant leading zeroes.
LeadingZeroes=No specifies if the whole field should be filled with unsignificant 0 from the left side. When Align=Left or when the Size= is not determined, leading zeroes are not used.
Output
CF=0, Destination filled, EDI points behind the last stored destination digit.
Error
CF=1 on overflow (destination field was not long enough), EDI is unchanged.
Example
OutputField DB 12*B'?' MOV EAX,123 StoD OutputField MOV AL,'.' STOSB MOV EAX,45 StoD ; OutputField is now "123.45??????", ; EDI points to the 1st question mark
Tested by
tmac32.htm
StoD  %MACRO  Destination, Size=, Signed=Yes, Align=Left, LeadingZeroes=No
    %StoDflags %SETA              %cpuextSigned   & "%Signed[1]" !== "N"
    %StoDflags %SETA %StoDflags | %cpuextAlignL   & "%Align[1]" == "L"
    %StoDflags %SETA %StoDflags | %cpuextLeading0 & "%LeadingZeroes[1]" !== "N"
    %IF "%Align[1]" !== "L" && "%Size" === "" && ("%Destination" === "" || "%Destination" == "EDI")
      %ERROR ID=5913, "StoD cannot Align=right when Size is not specified."
      %StoDflags %SETA %StoDflags | %cpuextAlignL
    %ENDIF
    PUSHD %StoDflags
    %IF "%Size" === ""
      %IF "%Destination" === "" || "%Destination" == "EDI"
        PUSHD -1
      %ELSE
        PUSHD SIZE# (%Destination)
      %ENDIF
    %ELSE
      PUSHD %Size
    %ENDIF
    %IF "%Destination" === ""
      PUSH EDI
    %ELSE
      PUSHD %Destination
    %ENDIF
    CALL StoD32@RT::
StoD32@RT:: PROC1
     PUSHAD
       MOV EBP,ESP
 %StoD@RTflags       %SET EBP+44
 %StoD@RTSize        %SET EBP+40
 %StoD@RTDestination %SET EBP+36
 %StoD@RTlength      %SET EBP-4
       SUB ESP,12+4
       MOV EDX,EAX ; input value
       MOV EDI,ESP ; temporary destination field
       PUSHD 10,100,1000,10000,100000,1000000, 10000000,100000000,1000000000
       MOV ESI,ESP
       MOV ECX,9
       JNSt [%StoD@RTflags],%cpuextSigned,.10:
       TEST EDX
       JNS .10:
       MOV AL,'-'
       NEG EDX
       SetSt [%StoD@RTflags],%cpuextMinus
       STOSB
  .10: LODSD ; 10^9, 10^8, 10^7 ...
       CMP EDX,EAX
       JNB .20
       LOOP .10:
       JMP .40:
  .20: MOV EBX,EAX
       SUB EAX,EAX
       XCHG EAX,EDX
       DIV EBX
       ADD AL,'0'
       STOSB
       LODSD
       LOOP .20:
       LEA ESI,[ESI-4]
  .40: MOV EAX,EDX
       ADD AL,'0'
       STOSB ; the last digit
       SUB EDI,ESI
       MOV [%StoD@RTlength],EDI
       MOV ECX,[%StoD@RTSize]
       SUB ECX,EDI ; padding characters if Align=right
       MOV EDI,[%StoD@RTDestination]
       JB .95: ; overflow
       JSt [%StoD@RTflags],%cpuextAlignL,.80:
       CMPD [%StoD@RTSize],-1
       JE .80: ; unspecified Size=
       JECXZ .80
       MOV AL,' '
       JNSt [%StoD@RTflags],%cpuextLeading0,.70:
       JNSt [%StoD@RTflags],%cpuextMinus,.60:
       DECD [%StoD@RTlength]
       MOVSB ; copy Minus sign
 .60:  MOV AL,'0'
 .70:  REP STOSB ; leading spaces or zeroes
 .80:  MOV ECX,[%StoD@RTlength]
       REP MOVSB ; significant digits
       CLC
       MOV [%ReturnEDI],EDI
 .95:  MOV ESP,EBP
     POPAD
     RET 12
  ENDP1 StoD32@RT::
%ENDMACRO StoD
↑ StoQD Destination, Size=, Signed=Yes, Align=Left, LeadingZeroes=No
Store 64bit integer number from register pair EDX:EAX in decimal notation do Destination.
Input
EDX:EAX contains the input number.
Destination is a pointer to memory where the decimal number will be stored. EDI is assumed when this operand is omitted.
Size= specifies length of the Destination field. When the size is not explicitly specified, it is assumed SIZE# %Destination. Size is not limited if it cannot be determined from %Destination. Size will never exceed 20 characters. The output string is ANSI (1byte per digit).
Signed=Yes specifies whether the input number is treated as signed. Negative numbers will be prefixed with - sign, positive sign is not used.
Align=Left specifies alignment of the number in Destination field. If Size= cannot be determined, this parameter is ignored.
When Align=Right and Size= is specified, the vacant characters on the left side will be filled with spaces or unsignificant leading zeroes.
LeadingZeroes=No specifies if the whole field should be filled with unsignificant 0 from the left side. When Align=Left or when the Size= is not determined, leading zeroes are not used.
Output
CF=0, Destination is filled,
EDI points behind the last stored destination digit.
Error
CF=1 on overflow (destination field was not long enough),
EDI is unchanged.
Example
OutputField DB 12*B'?' MOV EAX,123 CDQ StoQD OutputField MOV AL,'.' STOSB MOV EAX,45 StoQD ; OutputField is now "123.45??????", ; EDI points to the 1st question mark
StoQD  %MACRO  Destination, Size=, Signed=Yes, Align=Left, LeadingZeroes=No
    %StoQDflags %SETA               %cpuextSigned   & "%Signed[1]" !== "N"
    %StoQDflags %SETA %StoQDflags | %cpuextAlignL   & "%Align[1]" == "L"
    %StoQDflags %SETA %StoQDflags | %cpuextLeading0 & "%LeadingZeroes[1]" !== "N"
    %IF "%Align[1]" !== "L" && "%Size" === "" && ("%Destination" === "" || "%Destination" == "EDI")
      %ERROR ID=5914, "StoQD cannot Align=right when Size= is not specified."
      %StoQDflags %SETA %StoQDflags | %cpuextAlignL
    %ENDIF
    PUSHD %StoQDflags
    %IF "%Size" === ""
      %IF "%Destination" === "" || "%Destination" == "EDI"
        PUSHD -1
      %ELSE
        PUSHD SIZE# (%Destination)
      %ENDIF
    %ELSE
      PUSHD %Size
    %ENDIF
    %IF "%Destination" === ""
      PUSH EDI
    %ELSE
      PUSH %Destination
    %ENDIF
    CALL StoQD32@RT::
StoQD32@RT:: PROC1
    PUSHAD
      MOV EBP,ESP
%StoQD@RTflags       %SET EBP+44
%StoQD@RTSize        %SET EBP+40
%StoQD@RTDestination %SET EBP+36
      SUB ESP,20
%Result %SET EBP-20 ; Room for 20 digits.
       PUSHD 0x00000000,0x0000000A ; 10^1
       PUSHD 0x00000000,0x00000064 ; 10^2
       PUSHD 0x00000000,0x000003E8 ; 10^3
       PUSHD 0x00000000,0x00002710 ; 10^4
       PUSHD 0x00000000,0x000186A0 ; 10^5
       PUSHD 0x00000000,0x000F4240 ; 10^6
       PUSHD 0x00000000,0x00989680 ; 10^7
       PUSHD 0x00000000,0x05F5E100 ; 10^8
       PUSHD 0x00000000,0x3B9ACA00 ; 10^9
       PUSHD 0x00000002,0x540BE400 ; 10^10
       PUSHD 0x00000017,0x4876E800 ; 10^11
       PUSHD 0x000000E8,0xD4A51000 ; 10^12
       PUSHD 0x00000918,0x4E72A000 ; 10^13
       PUSHD 0x00005AF3,0x107A4000 ; 10^14
       PUSHD 0x00038D7E,0xA4C68000 ; 10^15
       PUSHD 0x002386F2,0x6FC10000 ; 10^16
       PUSHD 0x01634578,0x5D8A0000 ; 10^17
       PUSHD 0x0DE0B6B3,0xA7640000 ; 10^18
       PUSHD 0x8AC72304,0x89E80000 ; 10^19
       JNSt [%StoQD@RTflags],%cpuextSigned, .10:
       ; If the input is signed and negative, negate it first.
       TEST EDX
       JNS .10:
       SetSt [%StoQD@RTflags],%cpuextMinus ; Minus sign will be prefixed to result.
       NOT EAX
       NOT EDX
       ADD EAX,1
       ADC EDX,0
 .10:  MOV EBX,EAX
       ; EDX:EBX is unsigned 64bit integer.
       LEA EDI,[%Result]
       MOV AH,20            ; Number of digits in result.
 .20:  DEC AH
       JZ .40:
       MOV AL,'0'-1
       POP ECX,ESI          ; ESI:ECX is constant divisor 10^19, 10^18,,,
 .30:  INC AL
       SUB EBX,ECX
       SBB EDX,ESI
       JNB .30:
       ADD EBX,ECX
       ADC EDX,ESI
       STOSB
       JMP .20:
 .40:  MOV EAX,EBX
       ADD AL,'0'
       STOSB                ; The last digit of the result.
       LEA EDI,[%Result]
       MOV ECX,20
       MOV AL,'0'
       REPE SCASB
       LEA ESI,[EDI-1]      ; 1st significatnt digit.
       MOV EBX,[%StoQD@RTSize]
       MOV EDI,[%StoQD@RTDestination]
       MOV ECX,EBX
       MOV [%ReturnEDI],EDI ; For the case of overflow.
       LEA EAX,[%Result+20]
       JNSt [%StoQD@RTflags],%cpuextMinus,.45:
       DEC ECX ; %StoQD@RTSize-1
  .45: SUB EAX,ESI
       MOV EDX,EAX          ; Number of significant digits.
       SUB ECX,EAX          ; Stuff size.
       JC .99:              ; Size too small.
       JZ .80:              ; No stuff, ignore Alignment and Leading0.
       INC EBX
       JZ .80:              ; Undefined size - force align left.
       JSt [%StoQD@RTflags],%cpuextAlignL,.80:
       JSt [%StoQD@RTflags],%cpuextLeading0,.70:
       MOV AL,' '
       REP STOSB
       JMP .80:
  .70: JNSt [%StoQD@RTflags],%cpuextMinus,.75:
       MOV AL,'-'
       STOSB
  .75: MOV AL,'0'
       REP STOSB
       JMP .85:
  .80: JNSt [%StoQD@RTflags],%cpuextMinus,.85:
       MOV AL,'-'
       STOSB
  .85: MOV ECX,EDX
       REP MOVSB
       MOV [%ReturnEDI],EDI
 .99:  MOV ESP,EBP
     POPAD
     RET 12
  ENDP1 StoQD32@RT::
%ENDMACRO StoQD
↑ StoH Destination, Size=, Case=Upper, Align=Right, LeadingZeroes=Yes
Store 32bit signed integer number from EAX in hexadecimal notation.
Input
EAX contains the input number.
Destination is a pointer to memory where the hexadecimal number will be stored. EDI is assumed when Destination is omitted.
Size= specifies the length of the Destination field. When the size is not explicitly specified, it is taken from SIZE# %Destination. Size is not limited if it cannot be determined from %Destination but it will never exceed 8 characters. The output string is ANSI (1byte per digit).
Case=upper (or lower). This parameter will select between ABCDEF and abcdef digits.
Align=right (or left) specifies alignment of the number in Destination field. If Size= cannot be determined, this parameter is ignored. When Align=right and Size= is specified, the vacant characters on the left side will be filled with spaces or unsignificant leading characters.
LeadingZeroes=yes (or no) specifies if the whole field should be filled from the left side with unsignificant 0 or F. When Align=Left or when the Size= is not determined, leading characters are not used.
Output
CF=0,
EDI points behind the last stored destination digit.
Error
CF=1,
EDI is unchanged on overflow (destination field was not long enough).
Example
OutputField DB 12*B'?' MOV EAX,123 StoH OutputField, Size=3, Align=Right ; OutputField is now '07B?????????', EDI points to the 1st '?' MOV EAX,-4567 StoH OutputField, Align=Left ; OutputField is now 'EE29????????' StoH OutputField ; OutputField is now 'FFFFFFFFEE29'
Tested by
tmac32.htm
StoH  %MACRO  Destination, Size=, Case=Upper, Align=Right, LeadingZeroes=Yes
    %StoHflags %SETA              %cpuextLowCase  & "%Case[1]" !== "U"
    %StoHflags %SETA %StoHflags | %cpuextAlignL   & "%Align[1]" !== "R"
    %StoHflags %SETA %StoHflags | %cpuextLeading0 & "%LeadingZeroes[1]" !== "N"
    %IF "%Align[1]" == "R" && "%Size" === "" && ("%Destination" === "" || "%Destination" == "EDI")
      %ERROR ID=5915, StoH cannot Align=right when Size= is not specified.
      %StoHflags %SETA %StoHflags | %cpuextAlignL
    %ENDIF
    PUSHD %StoHflags
    %IF "%Size" === ""
      %IF "%Destination" === "" || "%Destination" == "EDI"
        PUSHD -1
      %ELSE
        PUSHD SIZE# (%Destination)
      %ENDIF
    %ELSE
      PUSHD %Size
    %ENDIF
    %IF "%Destination" === ""
      PUSHD EDI
    %ELSE
      PUSHD %Destination
    %ENDIF
    CALL StoH32@RT::
StoH32@RT:: PROC1
     PUSHAD
       MOV EBP,ESP
 %StoH@RTflags       %SET EBP+44
 %StoH@RTSize        %SET EBP+40
 %StoH@RTDestination %SET EBP+36
       SUB ESP,8
       MOV EDX,EAX
       MOV EDI,ESP
       MOV ESI,ESP
       SUB EBX,EBX
       JNSt [%StoH@RTflags],%cpuextLowCase,.10:
       OR BL,'x'^'X'
  .10: TEST EDX
       MOV ECX,7
       JNS .20:
       MOV BH,0x0F           ; Unsignificant nibble is 0 of F.
  .20: SHLD EAX,EDX,4
       ROL EDX,4
       AND EAX,0x0000000F
       CMP AL,BH
       LOOPE .20:
       INC ECX
  .30: ADD AL,0x90
       DAA
       ADC AL,0x40
       DAA
       OR EAX,EBX ; LowCase
       STOSB
       SHLD EAX,EDX,4
       ROL EDX,4
       AND EAX,0x0000000F
       LOOP .30:
       ADD AL,0x90
       DAA
       ADC AL,0x40
       DAA
       OR EAX,EBX            ; LowCase.
       STOSB
       SUB EDI,ESI
       MOV EDX,EDI           ; Length of significant string.
       MOV ECX,[%StoH@RTSize]
       SUB ECX,EDI           ; Padding characters if Align=right.
       MOV EDI,[%StoH@RTDestination]
       JB .90: ; overflow
       JSt [%StoH@RTflags],%cpuextAlignL,.80:
       CMPD [%StoH@RTSize],-1
       JE .80:               ; Size= is not specified.
       JECXZ .80
       ; Leading character is 'F' or 'f' or '0' or ' '
       TEST BH
       MOV AL,'F'
       JZ .50:
       OR AL,BL
       JMP .70:
 .50:  MOV AL,'0'
       JSt [%StoH@RTflags],%cpuextLeading0,.70:
       MOV AL,' '
 .70:  REP STOSB             ; Leading spaces or zeroes or 'F's
 .80:  MOV ECX,EDX
       REP MOVSB             ; Significant digits.
       CLC
       MOV [%ReturnEDI],EDI
  .90: MOV ESP,EBP
     POPAD
     RET 12
  ENDP1 StoH32@RT::
 %ENDMACRO StoH
↑ StoQH Destination, Size=, Case=Upper, Align=Right, LeadingZeroes=Yes
Store 64bit signed integer number from EDX:EAX in hexadecimal notation.
Input
EDX:EAX contains the input number.
Destination is a pointer to memory where the hexadecimal number will be stored. EDI is assumed when Destination is omitted.
Size= specifies the length of the Destination field. When the size is not explicitly specified, it is assumed SIZE# %Destination.
Size is not limited if it cannot be determined from %Destination but it will never exceed 16 characters. The output string is ANSI (1byte per digit).
Case=upper (or lower). This parameter will select between ABCDEF and abcdef.
Align=right (or left) specifies alignment of the number in Destination field. If Size= cannot be determined, this parameter is ignored.
When Align=right and Size= is specified, the vacant characters on the left side will be filled with spaces or with unsignificant leading characters (0 or F).
LeadingZeroes=yes (or no) specifies if the whole field should be filled from the left side with unsignificant 0 or F. When Align=Left or when the Size= is not determined, leading characters are not used.
Output
CF=0,
EDI points behind the last stored destination digit.
Error
CF=1,
EDI is unchanged on overflow (destination field was not long enough).
Example
OutputField DB 12*B'?' MOV EAX,123 CDQ StoQH OutputField, Size=3, Align=right ; OutputField is now '07B?????????', EDI points to the 1st '?' MOV EAX,-4567 CDQ StoQH OutputField, Align=Left ; OutputField is now 'EE29????????' StoQH OutputField ; OutputField is now 'FFFFFFFFEE29'
 StoQH  %MACRO  Destination, Size=, Case=Upper, Align=Right, LeadingZeroes=Yes
    %StoQHflags %SETA               %cpuextLowCase  & "%Case[1]"!=="U"
    %StoQHflags %SETA %StoQHflags | %cpuextAlignL   & "%Align[1]"!=="R"
    %StoQHflags %SETA %StoQHflags | %cpuextLeading0 & "%LeadingZeroes[1]"!=="N"
    %IF "%Align[1]" == "R" && "%Size" === "" && ("%Destination" === "" || "%Destination" == "EDI")
      %ERROR ID=5916, StoQH cannot Align=right when Size= is not specified.
      %StoQHflags %SETA %StoQHflags | %cpuextAlignL
    %ENDIF
    %IF "%Size" === ""
      %IF "%Destination" === "" || "%Destination" == "EDI"
        PUSHD -1
      %ELSE
        PUSHD SIZE# {%Destination)
      %ENDIF
    %ELSE
      PUSHD %Size
    %ENDIF
    %IF "%Destination" === ""
      PUSH EDI
    %ELSE
      PUSHD %Destination
    %ENDIF
    CALL StoQH32@RT::
 StoQH32@RT:: PROC1
     PUSHAD
       MOV EBP,ESP
 %StoQH@RTflags       %SET EBP+44
 %StoQH@RTSize        %SET EBP+40
 %StoQH@RTDestination %SET EBP+36
       CMPD [%StoQH@RTSize],-1
       JNE .05:
       SetSt [%StoQH@RTflags],%cpuextAlignL
  .05: PUSHD 'CDEF'
       PUSHD '89AB'
       PUSHD '4567'
       PUSHD '0123'
       LEA EBX,[EBP-16]              ; Table '0'..'F'
       JNSt [%StoQH@RTflags],%cpuextLowCase,.10:
       MOVW [EBX+10],'ab'
       MOVD [EBX+12],'cdef'
  .10: SUB ESP,16 ; Room for output digits.
       MOV EDI,ESP
       MOV ECX,8
  .20: MOV EAX,EDX
       ROL EDX,4
       SHR EAX,28
       MOV AL,[EAX+EBX]
       STOSB
       LOOP .20:
       MOV CL,8
       MOV EDX,[%ReturnEAX]
  .30: MOV EAX,EDX
       ROL EDX,4
       SHR EAX,28
       MOV AL,[EAX+EBX]
       STOSB
       LOOP .30:
       MOV EDX,[%ReturnEDX]
       MOV EAX,[%ReturnEAX]         ; Find the number of significant hexadigits to ECX.
       TEST EDX
       JNS .40:
       SetSt [%StoQH@RTflags],%cpuextMinus
       NOT EAX ; EDX:EAX is negative.
       NOT EDX
       ADD EAX,1
       ADC EDX,0
  .40: ; Number is positive.
       BSR ECX,EDX
       JZ .50:
       ADD CL,36 ; ECX is now 36..67
       SAR ECX,2
       JMP .60:
  .50: BSR ECX,EAX
       JNZ .55:
       MOV ECX,EAX
  .55: ADD CL,4
       SAR ECX,2
  .60: ; ECX=number of significant digits (1..16)
       LEA ESI,[ESP+16]
       SUB ESI,ECX
       MOV EDI,[%StoQH@RTDestination]
       MOV EDX,[%StoQH@RTSize]
       MOV AL,'0'
       JNSt [%StoQH@RTflags],%cpuextMinus, .70:
       MOV AL,[EBX+15]                         ; 'F' or 'f'
  .70: JSt [%StoQH@RTflags],%cpuextLeading0,.75:
       MOV AL,' '
       CMPB [ESI],'8'
       JB .72:
       JSt [%StoQH@RTflags],%cpuextMinus,.75:
       InvSt [%StoQH@RTflags],%cpuextMinus
  .72: JNSt [%StoQH@RTflags],%cpuextMinus,.75:
       CMP CL,16
       JNB .75:
       INC ECX
       DEC ESI
  .75: SUB EDX,ECX                             ; Number of unsignificant digits
       JC .90:                                 ; Output %Size too small.
       JZ .80:
       JSt [%StoQH@RTflags],%cpuextAlignL,.80: ; No leading characters
       XCHG ECX,EDX
       REP STOSB                               ; Leading characters '0','F' or ' '
       XCHG EDX,ECX
 .80:  REP MOVSB ; significant digits
       CLC
 .90:  MOV [%ReturnEDI],EDI
       MOV ESP,EBP
     POPAD
     RET 12
  ENDP1 StoQH32@RT::
 %ENDMACRO StoQH
↑ StripColons PtrReg, SizeReg, Unicode=%^UNICODE
Remove leading and trailing colon(s) : from input field.
Input
PtrReg is a register which points to the input field.
SizeReg is a register with size of the input field in bytes. Both arguments must be specified as general purpose 32bit registers.
Unicode= is a logical parameter which tells whether the strings is ANSI or WIDE.
Output
Both input registers are changed if the field begins and|or ends with colons. If the input field only contains one or more colons, the 2nd register will return 0.
StripColons %MACRO PtrReg, SizeReg, Unicode=%^UNICODE
      %IF TYPE#%PtrReg <> 'R' || TYPE#%SizeReg <> 'R'
        %ERROR ID=5918, "Both arguments of StripColons must be GPR."
        %EXITMACRO StripColons
      %ENDIF
      %IF %Unicode ; WIDE variant.
 StripColons1%.:
        CMP %SizeReg,2
        JL StripColons9%.:
        CMPW [%PtrReg+%SizeReg-2],":"
        JNE StripColons2%.:
        DEC %SizeReg,%SizeReg
        JMP StripColons1%.:
 StripColons2%.:
        CMPW [%PtrReg],":"
        JNE StripColons9%.:
        INC %PtrReg,%PtrReg
        CMP %SizeReg,2
        JL StripColons9%.:
        DEC %SizeReg,%SizeReg
        JMP StripColons2%.:
 StripColons9%.:
      %ELSE ; ANSI variant.
        TEST %SizeReg
        JZ StripColons9%.:
 StripColons1%.:
        CMPB [%PtrReg+%SizeReg-1],':'
        JNE StripColons2%.:
        DEC %SizeReg
        JNG StripColons9%.:
        JMP StripColons1%.:
 StripColons2%.:
        CMPB [%PtrReg],':'
        JNE StripColons9%.:
        INC %PtrReg
        DEC %SizeReg
        JMP StripColons2%.:
      %ENDIF
 StripColons9%.:
 %ENDMACRO StripColons
↑ StripQuotes PtrReg, SizeReg, Unicode=%^UNICODE
Remove leading and trailing double quote " from input field.
Input
PtrReg is a register which points to the input field.
SizeReg is the register with size of the input field in bytes. Both arguments must be specified as general purpose 32bit registers.
Unicode= is a logical parameter which tells whether the strings is ANSI or WIDE.
Output
Both input registers are changed if the field begins and/or ends with double quote. If the input field only contains one or two quotes, the 2nd register will return 0.
StripQuotes %MACRO PtrReg, SizeReg, Unicode=%^UNICODE
      %IF TYPE#%PtrReg <> 'R' || TYPE#%SizeReg <> 'R'
        %ERROR ID=5919, "Both arguments of StripQuotes must be GPR."
        %EXITMACRO StripQuotes
      %ENDIF
      %IF %Unicode  ; WIDE variant.
        CMP %SizeReg,2*2
        JB StripQuotes9%.:
        CMPW [%PtrReg+%SizeReg-2],'"'
        JNE StripQuotes1%.:
        DEC %SizeReg,%SizeReg
 StripQuotes1%.:
        CMPW [%PtrReg],'"'
        JNE StripQuotes9%.:
        INC %PtrReg,%PtrReg
        DEC %SizeReg,%SizeReg
 StripQuotes9%.:
      %ELSE  ; ANSI variant.
        CMP %SizeReg,2
        JB StripQuotes9%.:
        CMPB [%PtrReg+%SizeReg-1],'"'
        JNE StripQuotes1%.:
        DEC %SizeReg
 StripQuotes1%.:
        CMPB [%PtrReg],'"'
        JNE StripQuotes9%.:
        INC %PtrReg
        DEC %SizeReg
StripQuotes9%.:
     %ENDIF
 %ENDMACRO StripQuotes
↑ StripApostrophes PtrReg, SizeReg, Unicode=%^UNICODE
Remove leading and trailing single quote ' from input field.
Input
PtrReg is a register which points to the input field.
SizeReg is register with size of the input field in bytes. Both arguments must be specified as general purpose 32bit registers.
Unicode= is a logical parameter which tells whether the strings is ANSI or WIDE.
Output
Both input registers are changed if the field begins and/or ends with apostrophe. If the input field only contains one or two apostrophes, the 2nd register will return 0.
StripApostrophes %MACRO PtrReg, SizeReg, Unicode=%^UNICODE
      %IF TYPE#%PtrReg <> 'R' || TYPE#%SizeReg <> 'R'
        %ERROR ID=5917, "Both arguments of StripApostrophes must be GPR."
        %EXITMACRO StripApostrophes
      %ENDIF
      %IF %Unicode  ; WIDE variant.
        CMP %SizeReg,2*2
        JB StripApostrophes9%.:
        CMPW [%PtrReg+%SizeReg-2],"'"
        JNE StripApostrophes1%.:
        DEC %SizeReg,%SizeReg
 StripApostrophes1%.:
        CMPW [%PtrReg],"'"
        JNE StripApostrophes9%.:
        INC %PtrReg,%PtrReg
        DEC %SizeReg,%SizeReg
 StripApostrophes9%.:
      %ELSE  ; ANSI variant.
        CMP %SizeReg,2
        JC StripApostrophes9%.:
        CMPB [%PtrReg+%SizeReg-1],"'"
        JNE StripApostrophes1%.:
        DEC %SizeReg
 StripApostrophes1%.:
        CMPB [%PtrReg],"'"
        JNE StripApostrophes9%.:
        INC %PtrReg
        DEC %SizeReg
 StripApostrophes9%.:
      %ENDIF
 %ENDMACRO StripApostrophes
↑ StripSpaces PtrReg, SizeReg, Unicode=%^UNICODE
Remove white spaces (characters equal or below ASCII 32) which surround the input field.
Input
PtrReg is a register which points to the input field.
SizeReg is a register with size of the input field in bytes. Both arguments must be specified as general purpose 32bit registers.
Unicode= is a logical parameter which tells whether the strings is ANSI or WIDE.
Output
Both input registers are changed if the field begins or ends with white spaces. If the input field contains nothing but spaces, the 2nd register will return 0.
Example
Field: DB " some text ",13,10,0 MOV ESI,Field MOV ECX,SIZE#Field ; 14 StripSpaces ESI,ECX ; ESI=Field+1 ECX=9
Tested by
tmac32.htm
StripSpaces %MACRO PtrReg, SizeReg, Unicode=%^UNICODE
      %IF TYPE#%PtrReg <> 'R' || TYPE#%SizeReg <> 'R'
        %ERROR ID=5920, "Both arguments of StripSpaces must be GPR."
        %EXITMACRO StripSpaces
      %ENDIF
      %IF %Unicode ; WIDE variant.
 StripSpaces1%.:
        CMP %SizeReg,2
        JL StripSpaces9%.:
        CMPW [%PtrReg+%SizeReg-2]," "
        JA StripSpaces2%.:
        DEC %SizeReg,%SizeReg
        JMP StripSpaces1%.:
 StripSpaces2%.:
        CMPW [%PtrReg]," "
        JA StripSpaces9%.:
        INC %PtrReg,%PtrReg
        CMP %SizeReg,2
        JL StripSpaces9%.:
        DEC %SizeReg,%SizeReg
        JMP StripSpaces2%.:
 StripSpaces9%.:
      %ELSE  ; ANSI variant.
        TEST %SizeReg
        JZ StripSpaces9%.:
 StripSpaces1%.:
        CMPB [%PtrReg+%SizeReg-1]," "
        JA StripSpaces2%.:
        DEC %SizeReg
        JNG StripSpaces9%.:
        JMP StripSpaces1%.:
 StripSpaces2%.:
        CMPB [%PtrReg]," "
        JA StripSpaces9%.:
        INC %PtrReg
        DEC %SizeReg
        JMP StripSpaces2%.:
 StripSpaces9%.:
      %ENDIF
 %ENDMACRO StripSpaces
 ENDHEAD cpuext32

▲Back to the top▲