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 %MACRO Variable
ADDD %Variable, 3
ANDD %Variable, ~3
%ENDMACRO Align2Dword
Align2Qword %MACRO Variable
ADDD %Variable, 7
ANDD %Variable, ~7
%ENDMACRO Align2Qword
Align2Oword %MACRO Variable
ADDD %Variable, 15
ANDD %Variable, ~15
%ENDMACRO Align2Oword
SIZE# Operand.
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 %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 %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 %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
ESI is assumed.
SIZE# %Source. Size is not limited if it cannot be determined from %Source.
Align=right.
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
0x is not supported (LodH would return EAX=0 and ESI behind the 0x.
SIZE# %Source is assumed.
Size is not limited if it cannot be determined from %Source.
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
0x is not supported (LodQH would return EDX:EAX=0 and ESI behind the
0x.SIZE# %Source is assumed.
Size is not limited if it cannot be determined from %Source.
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
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).
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
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).
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
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).
ABCDEF and abcdef digits.
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
SIZE# %Destination.
ABCDEF and abcdef.
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
PUSHD %StoQHflags
%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 %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 %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 %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 %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