The Standard Error Module (stderr.hhf)
This unit contains routines that write data to the standard error device. This is usually the console device, although the user may redirect the standard error to a file from the command line.
Note: be sure to read the chapter on “Passing Parameters to
Standard Library Routines” (parmpassing.rtf) before reading this chapter.
Note about stack diagrams:
this documentation includes stack diagrams for those functions that pass
parameters on the stack. To conserve space, this documentation does not include
a stack diagram for any function that does not pass data on the stack (that is,
only a return address appears on the stack).
A Note About Thread Safety:
Because the standard error device is a single resource, you will get
inconsistent results if multiple threads attempt to write to the standard error
device simultaneously. The HLA standard library stderr module does not attempt
to synchronize thread access to the standard error device. If you are going to
be writing to the standard error from multiple threads, it is your
responsibility to ensure that the threads use properly synchronized access to
this resource.
A Note About the FPU:
The Standard Library code makes occasional use of the FPU, particularly when
converting between real and string formats and when computung certain
mathematical functions. You should exercise caution when using MMX instructions
in a program that makes use of the Standard Library. In particular, you should
ensure that you are always in FPU mode (by executing an EMMS instruction) after
you are finished using MMX instructions. Better yet, you should avoid the MMX
instruction set altogether and use the improved SSE instruction set that
accomplishes the same tasks (and doesn’t disturb the FPU).
The standard error functions that convert numeric values to
hexadecimal, unsigned decimal, and signed decimal output provide the ability to
inject underscores between groups
of three (decimal) or four (hexadecimal) digits to make it easier to read large
numbers. You enable and disable underscore output using the conv.setUnderscores
and conv.getUnderscores functions. Please refer to their documentation in the
conv.rtf file for more details.
When converting numeric values to string form for output, the standard
error routines call the conversion functions found in the conv (conversions)
module. For detailed information on the actual conversions, please consult the
conv.rtf document.
The standard error routines are basically a thin layer over the
top of the fileio routines (see the fileio documention for a complete
description of those routines). Indeed, if you obtain the standard error
handle, you can write data to the standard error device by passing this handle
to a fileio function. Because the fileio module provides a slightly richer set
of routines, there are a few instances where you might want to do this. You
might also want to write a generic output function that expects a file handle
and then pass it the standard error device file handle so that the function
writes its output to the console (or other standard error device) rather than
to some file. In any case, just be aware that it is perfectly reasonable to
call fileio functions to write data to the standard error device.
stderr.handle; @returns( "eax" );
This routine returns the Linux/Windows handle for the Standard Error Device in the EAX register. You may use this handle with the file I/O routines to write data to the standard error device.
The output routines in the stderr module are very similar to the file output routines in the stderr module. In general, these routines require (at least) one parameter: the value to write to the standard error device. Some functions contain additional parameters that provide formatting information.
stderr.write( var buffer:var; count:uns32 );
This procedure writes the number of bytes specified by the count
variable to the standard error device.
The bytes starting at the address of the buffer variable are
written to standard err. No range
checking is done on the buffer, it is your responsibility to ensure that the
buffer contains at least count valid data bytes. Because the buffer
parameter is passed by untyped reference, a high-level style call to this
function will take the address of whatever object you supply as the buffer
parameter. This includes pointer variables (which
is probably not what you want to do). Use the VAL keyword in a high-level style
call if you want to use the value of a pointer variable rather than the address
of that pointer variable (see the examples that follow).
HLA high-level calling sequence examples:
stderr.write( buffer, count );
// If “bufPtr” is dword containing the address of the buffer, then
// use the following code:
stderr.write( val bufPtr, bufferSize );
// If you actually want to write out the four bytes held by
// bufPtr (an unusual thing to do), you would use the
// following code:
stderr.write( bufPtr, 4 );
HLA low-level calling sequence examples:
// Assumes buffer is a static object at a fixed
// address in memory:
pushd( &buffer );
push( count );
call stderr.write;
//
If a 32-bit register is available and buffer
//
isn’t at a fixed, static, address:
lea( eax, buffer );
push( eax );
push( count );
call stderr.write;
//
If a 32-bit register is not available and buffer
//
isn’t at a fixed, static, address:
sub( 4, esp );
push( eax );
lea( eax, buffer );
mov( eax, [esp+4] );
pop( eax );
push( count );
call stderr.write;
stderr.newln()
This function writes a newline sequence (e.g., carriage return/line feed under Windows or line feed under Linux) to the standard error output.
HLA high-level calling sequence examples:
stderr.newln();
HLA low-level calling sequence examples:
call stderr.newln;
stderr.putbool( b:boolean );
This procedure writes the string "true" or "false" to the standard error depending on the value of the b parameter.
HLA high-level calling sequence examples:
stderr.putbool( boolVar );
// If the boolean is in a register (AL):
stderr.putbool( al );
HLA low-level calling sequence examples:
//
If “boolVar” is not one of the last three
//
bytes on a page of memory, you can do this:
push( (type dword boolVar ) );
call stderr.putbool;
// If you can’t guarantee that the previous code
// won’t generate an illegal memory access, and a
// 32-bit register is available, use code like
// the following:
movzx( boolVar , eax ); // Assume EAX is available
push( eax );
call stderr.putbool;
// If no register is available, do something
// like the following code:
sub( 4, esp );
push( eax );
movzx( boolVar , eax );
mov( eax, [esp+4] );
pop( eax );
call stderr.putbool;
// If the boolean value is in al, bl, cl, or dl
// then you can use code like the following:
push( eax ); //
Assume boolVar is in AL
call stderr.putbool;
// If the Boolean value is in ah, bh, ch, or dh
// you’ll have to use code like the following:
xchg( al, ah ); // Assume boolVar is in AH
push( eax );
// It’s now in AL
xchg( al, ah ); // Restore al/ah
call stderr.putbool;
stderr.putc( c:char );
Writes the character specified by the c parameter to the standard error device.
HLA high-level calling sequence examples:
stderr.putc( charVar );
// If the character is in a register (AL):
stderr.putc( al );
HLA low-level calling sequence examples:
//
If “charVar” is not one of the last three
//
bytes on a page of memory, you can do this:
push( (type dword charVar) );
call stderr.putc;
// If you can’t guarantee that the previous code
// won’t generate an illegal memory access, and a
// 32-bit register is available, use code like
// the following:
movzx( charVar, eax ); // Assume EAX is available
push( eax );
call stderr.putc;
// If no register is available, do something
// like the following code:
sub( 4, esp );
push( eax );
movzx( charVar, eax );
mov( eax, [esp+4] );
pop( eax );
call stderr.putc;
// If the character value is in al, bl, cl, or dl
// then you can use code like the following:
push( eax ); //
Assume charVar is in AL
call stderr.putc;
// If the character value is in ah, bh, ch, or dh
// you’ll have to use code like the following:
xchg( al, ah ); // Assume charVar is in AH
push( eax );
// It’s now in AL
xchg( al, ah ); // Restore al/ah
call stderr.putc;
stderr.putcSize( c:char; width:int32; fill:char )
Outputs the character c to the standard error using at least width output positions. If the absolute value of width is greater than one, then this function writes fill characters as padding characters during the output. If width is a positive value greater than one, then stderr.putcSize writes c left justfied in a field of width characters; if width is a negative value less than one, then stderr.putcSize writes c right justified in a field of width characters.
HLA high-level calling sequence examples:
stderr.putcSize( charVar, width, padChar );
HLA low-level calling sequence examples:
//
If “charVar” and “padChar” are not one of the last three
//
bytes on a page of memory, you can do this:
push( (type dword charVar) );
push( width );
push( (type dword padChar) );
call stderr.putcSize;
// If you can’t guarantee that the previous code
// won’t generate an illegal memory access, and a
// 32-bit register is available, use code like
// the following:
movzx( charVar, eax ); // Assume EAX is available
push( eax );
push( width );
movzx( padChar, ebx ); // Assume EBX is available
push( ebx );
call stderr.putcSize;
// If no registers are available, do something
// like the following code:
push( eax );
movzx( charVar, eax );
push( eax );
push( width );
movzx( padChar, eax );
push( eax );
call stderr.putcSize;
pop( eax );
// If “charVar” or “padChar” are in an
// 8-bit register, then you can push
// the corresponding 32-bit register if
// the register is AL, BL, CL, or DL:
push( eax );
// Assume charVar is in AL
push( width );
push( ebx );
// Assume padChar is in BL
call stderr.putcSize;
// Do the following if the characters are
// in AH, BH, CH, or DH:
xchg( al, ah );
// Assume charVar is in AH
xchg( bl, bh );
// Assume padChar is in BH
push( eax );
push( width );
push( ebx );
xchg( al, ah );
xchg( bl, bh );
call stderr.putcSize;
stderr.putcset( cst:cset );
This function writes all the members of the cst character set parameter to the standard error device.
HLA high-level calling sequence examples:
stderr.putcset( csVar );
stderr.putcset( [ebx] ); // EBX points at the cset.
HLA low-level calling sequence examples:
push( (type dword csVar[12]) ); // Push H.O. dword first
push( (type dword csVar[8]) );
push( (type dword csVar[4]) );
push( (type dword csVar) ); // Push L.O. dword last
call stderr.putcset;
push( (type dword [ebx+12]) ); // Push H.O. dword first
push( (type dword [ebx+8]) );
push( (type dword [ebx+4]) );
push( (type dword [ebx]) ); // Push L.O. dword last
call stderr.putcset;
stderr.puts( s:string );
This procedure writes the value of the string parameter to the standard error. Remember, string values are actually 4-byte pointers to the string’s character data.
HLA high-level calling sequence examples:
stderr.puts( strVar );
stderr.puts( ebx ); // EBX holds a string value.
stderr.puts( “Hello World” );
HLA low-level calling sequence examples:
// For string variables:
push( strVar );
call stderr.puts;
// For string values held in registers:
push( ebx ); //
Assume EBX holds the string value
call stderr.puts;
// For string literals, assuming a 32-bit register
// is available:
lea( eax, “Hello World” ); // Assume EAX is available.
push( eax );
call stderr.puts;
// If a 32-bit register is not available:
readonly
literalString
:string := “Hello World”;
.
.
.
push( literalString );
call stderr.puts;
stderr.putsSize( s:string; width:int32; fill:char );
This function writes the s string to the standard error using at least width character positions. If the absolute value of width is less than or equal to the length of s, then this function behaves exactly like stderr.puts. On the other hand, if the absolute value of width is greater than the length of s, then stderr.putsSize writes width characters to the standard error. This procedure emits the fill character in the extra print positions. If width is positive, then stderr.putsSize right justifies the string in the print field. If width is negative, then stderr.putsSize left justifies the string in the print field. Generally, people expect the string to be left justified, so you should ensure that this value is negative to achieve this.
HLA high-level calling sequence examples:
stderr.putsSize( strVar, width, ‘ ‘ );
// For the following, EBX holds the string value,
// ECX contains the width, and AL holds the pad
// character:
stderr.putsSize( ebx, ecx, al );
stderr.putsSize( “Hello World”, 25, padChar );
HLA low-level calling sequence examples:
// For string variables:
push( strVar );
push( width );
pushd( ‘ ‘ );
call stderr.putsSize;
// For string values held in registers:
push( ebx ); //
Assume EBX holds the string value
push( ecx ); //
Assume ECX holds the width
push( eax ); //
Assume AL holds the fill character
call stderr.putsSize;
// For string literals, assuming a 32-bit register
// is available:
lea( eax, “Hello World” ); // Assume EAX is available.
push( eax );
pushd( 25 );
movzx( padChar, eax );
push( eax );
call stderr.putsSize;
// If a 32-bit register is not available:
readonly
literalString
:string := “Hello World”;
// Note:
element zero is the actual pad character.
// The other
elements are just padding.
padChar
:char[4] := [ ‘.’, #0, #0, #0 ];
.
.
.
push( literalString );
pushd( 25 );
push( (type dword padChar) );
call stderr.putsSize;
These routines convert numeric data to hexadecimal string form
(using the hexadecimal conversion routines found in the conv module) and write
the resulting string to the standard error device.
stderr.putb( b:byte )
This procedure writes the value of b to the standard error using exactly two hexadecimal digits (including a leading zero if necessary).
HLA high-level calling sequence examples:
stderr.putb( byteVar );
// If the character is in a register (AL):
stderr.putb( al );
HLA low-level calling sequence examples:
//
If “byteVar ” is not one of the last three
//
bytes on a page of memory, you can do this:
push( (type dword byteVar ) );
call stderr.putb;
// If you can’t guarantee that the previous code
// won’t generate an illegal memory access, and a
// 32-bit register is available, use code like
// the following:
movzx( byteVar , eax ); // Assume EAX is available
push( eax );
call stderr.putb;
// If no register is available, do something
// like the following code:
sub( 4, esp );
push( eax );
movzx( byteVar , eax );
mov( eax, [esp+4] );
pop( eax );
call stderr.putb;
// If the character value is in al, bl, cl, or dl
// then you can use code like the following:
push( eax ); //
Assume byteVar is in AL
call stderr.putb;
// If the byte value is in ah, bh, ch, or dh
// you’ll have to use code like the following:
xchg( al, ah ); // Assume byteVar is in AH
push( eax ); // It’s now in AL
xchg( al, ah ); // Restore al/ah
call stderr.putb;
stderr.puth8( b:byte );
This procedure writes the value of b to the standard error using the minimum necessary number of hexadecimal digits.
HLA high-level calling sequence examples:
stderr.puth8( byteVar );
// If the character is in a register (AL):
stderr.puth8( al );
HLA low-level calling sequence examples:
//
If “byteVar ” is not one of the last three
//
bytes on a page of memory, you can do this:
push( (type dword byteVar ) );
call stderr.puth8;
// If you can’t guarantee that the previous code
// won’t generate an illegal memory access, and a
// 32-bit register is available, use code like
// the following:
movzx( byteVar , eax ); // Assume EAX is available
push( eax );
call stderr.puth8;
// If no register is available, do something
// like the following code:
sub( 4, esp );
push( eax );
movzx( byteVar , eax );
mov( eax, [esp+4] );
pop( eax );
call stderr.puth8;
// If the character value is in al, bl, cl, or dl
// then you can use code like the following:
push( eax ); // Assume byteVar
is in AL
call stderr.puth8;
// If the byte value is in ah, bh, ch, or dh
// you’ll have to use code like the following:
xchg( al, ah ); // Assume byteVar is in AH
push( eax );
// It’s now in AL
xchg( al, ah ); // Restore al/ah
call stderr.puth8;
stderr.puth8Size(
b:byte; size:dword; fill:char )
The stderr.puth8Size function writes an 8-bit hexadecimal value to the standard error allowing you specify a minimum field width and a fill character.
HLA high-level calling sequence examples:
stderr.puth8Size( byteVar, width, padChar );
HLA low-level calling sequence examples:
//
If “byteVar” and “padChar” are not one of the last three
//
bytes on a page of memory, you can do this:
push( (type dword byteVar) );
push( width );
push( (type dword padChar) );
call stderr.puth8Size;
// If you can’t guarantee that the previous code
// won’t generate an illegal memory access, and a
// 32-bit register is available, use code like
// the following:
movzx( byteVar, eax ); // Assume EAX is available
push( eax );
push( width );
movzx( padChar, ebx ); // Assume EBX is available
push( ebx );
call stderr.puth8Size;
// If no registers are available, do something
// like the following code:
push( eax );
movzx( byteVar, eax );
push( eax );
push( width );
movzx( padChar, eax );
push( eax );
call stderr.puth8Size;
pop( eax );
// If “byteVar” or “padChar” are in an
// 8-bit register, then you can push
// the corresponding 32-bit register if
// the register is AL, BL, CL, or DL:
push( eax ); //
Assume byteVar is in AL
push( width );
push( ebx ); //
Assume padChar is in BL
call stderr.puth8Size;
// Do the following if the characters are
// in AH, BH, CH, or DH:
xchg( al, ah );
// Assume byteVar is in AH
xchg( bl, bh );
// Assume padChar is in BH
push( eax );
push( width );
push( ebx );
xchg( al, ah );
xchg( bl, bh );
call stderr.puth8Size;
stderr.putw( w:word )
This procedure writes the value of w to the standard error device using exactly four hexadecimal digits (including leading zeros if necessary).
HLA high-level calling sequence examples:
stderr.putw( wordVar );
// If the word is in a register (AX):
stderr.putw( ax );
HLA low-level calling sequence examples:
//
If “wordVar ” is not one of the last three
//
bytes on a page of memory, you can do this:
push( (type dword wordVar) );
call stderr.putw;
// If you can’t guarantee that the previous code
// won’t generate an illegal memory access, and a
// 32-bit register is available, use code like
// the following:
movzx( wordVar, eax ); // Assume EAX is available
push( eax );
call stderr.putw;
// If no register is available, do something
// like the following code:
push( eax ):
movzx( wordVar, eax );
push( eax );
call stderr.putw;
pop( eax );
// If the word value is in a 16-bit register
// then you can use code like the following:
push( eax ); //
Assume wordVar is in AX
call stderr.putw;
stderr.puth16( w:word )
This procedure writes the value of w to the standard err using the minimum necessary number of hexadecimal digits.
HLA high-level calling sequence examples:
stderr.puth16( wordVar );
// If the word is in a register (AX):
stderr.puth16( ax );
HLA low-level calling sequence examples:
//
If “wordVar ” is not one of the last three
//
bytes on a page of memory, you can do this:
push( (type dword wordVar) );
call stderr.puth16;
// If you can’t guarantee that the previous code
// won’t generate an illegal memory access, and a
// 32-bit register is available, use code like
// the following:
movzx( wordVar, eax ); // Assume EAX is available
push( eax );
call stderr.puth16;
// If no register is available, do something
// like the following code:
push( eax );
movzx( wordVar, eax );
push( eax );
call stderr.puth16;
pop( eax );
// If the word value is in a 16-bit register
// then you can use code like the following:
push( eax ); //
Assume wordVar is in AX
call stderr.puth16;
stderr.puth16Size(
w:word; size:dword; fill:char )
The stderr.puth16Size function writes a 16-bit hexadecimal value to the standard error allowing you specify a minimum field width and a fill character.
HLA high-level calling sequence examples:
stderr.puth16Size( wordVar, width, padChar );
HLA low-level calling sequence examples:
//
If “wordVar” and “padChar” are not one of the last three
//
bytes on a page of memory, you can do this:
push( (type dword wordVar) );
push( width );
push( (type dword padChar) );
call stderr.puth16Size;
// If you can’t guarantee that the previous code
// won’t generate an illegal memory access, and a
// 32-bit register is available, use code like
// the following:
movzx( wordVar, eax ); // Assume EAX is available
push( eax );
push( width );
movzx( padChar, ebx ); // Assume EBX is available
push( ebx );
call stderr.puth16Size;
// If no registers are available, do something
// like the following code:
push( eax );
movzx( wordVar, eax );
push( eax );
push( width );
movzx( padChar, eax );
push( eax );
call stderr.puth16Size;
pop( eax );
// If “wordVar” is in a 16-bit register
// and “padChar” is in an
// 8-bit register, then you can push
// the corresponding 32-bit register if
// the register is AL, BL, CL, or DL:
push( eax );
// Assume wordVar is in AX
push( width );
push( ebx );
// Assume padChar is in BL
call stderr.puth16Size;
stderr.putd( d:dword )
This procedure writes the value of d to the standard err using exactly eight hexadecimal digits (including leading zeros if necessary), if underscore output is not enabled. This routine will emit nine characters (eight digits plus an underscore) if underscore output is enabled.
HLA high-level calling sequence examples:
stderr.putd( dwordVar );
// If the dword value is in a register (EAX):
stderr.putd( eax );
HLA low-level calling sequence examples:
push( dwordVar );
call stderr.putd;
push( eax );
call stderr.putd;
stderr.puth32( d:dword );
This procedure writes the value of d to the standard error using the minimum number of hexadecimal digits necessary. If underscore output is enabled (see conv.setUnderscores and conv.getUnderscores) then this function will emit an underscore between groups of four hexadecimal digits, starting from the least signficant digit.
HLA high-level calling sequence examples:
stderr.puth32( dwordVar );
// If the dword is in a register (EAX):
stderr.puth32( eax );
HLA low-level calling sequence examples:
push( dwordVar );
call stderr.puth32;
push( eax );
call stderr.puth32;
stderr.puth32Size(
d:dword; size:dword; fill:char )
The stderr.puth32Size function outputs d as a hexadecimal string (including underscores, if enabled) and it allows you specify a minimum field width and a fill character.
HLA high-level calling sequence examples:
stderr.puth32Size( dwordVar, width, ‘ ‘ );
// If the dword is in a register (EAX):
stderr.puth32Size( eax, width, cl );
HLA low-level calling sequence examples:
push( dwordVar );
push( width );
pushd( ‘ ‘ );
call stderr.puth32Size;
push( eax );
push( width );
push( ecx ); // fill char is in CL
call stderr.puth32Size;
// Assume fill char is in CH
push( eax );
push( width );
xchg( cl, ch ); // fill char is in CH
push( ecx );
xchg( cl, ch );
call stderr.puth32Size;
// Alternate method of the above
push( eax );
push( width );
sub( 4, esp );
mov( ch, [esp] );
call stderr.puth32Size;
// If the fill char is a variable and
// a register is available, try this code:
push( eax );
push( width );
movzx( fillChar, ebx ); // Assume EBX is available
push( ebx );
call stderr.puth32Size;
// If the fill char is a variable and
// no register is available, here’s one
// possibility:
push( eax );
push( width );
push( (type dword fillChar) ); // Chance of page crossing!
call stderr.puth32Size;
// In the very rare case that the above would
// cause an illegal memory access, use this:
push( eax );
push( width );
sub( 4, esp );
push( eax );
movzx( fillChar, eax );
mov( eax, [esp+4] );
pop( eax );
call stderr.puth32Size;
stderr.putq( q:qword );
This procedure writes the value of q to the standard error device using exactly sixteen hexadecimal digits (including leading zeros if necessary and an intervening underscores if underscore output is enabled).
HLA high-level calling sequence examples:
stderr.putq( qwordVar );
HLA low-level calling sequence examples:
push( (type dword qwordVar[4]) ); // H.O. dword first
push( (type dword qwordVar)); // L.O. dword last
call stderr.putq;
stderr.puth64( q:qword );
This procedure writes the value of q to the standard error using the minimum necessary number of hexadecimal digits (including intervening underscores if underscore output is enabled).
HLA high-level calling sequence examples:
stderr.puth64( qwordVar );
HLA low-level calling sequence examples:
push( (type dword qwordVar[4]) ); // H.O. dword first
push( (type dword qwordVar)); // L.O. dword last
call stderr.puth64;
stderr.puth64Size(
q:qword; size:dword; fill:char );
The stderr.putqSize function lets you specify a minimum field width and a fill character. The stderr.putq routine uses a minimum size of two and a fill character of ’0’. Note that if underscore output is enabled, this routine will emit 19 characters (16 digits plus three underscores).
HLA high-level calling sequence examples:
stderr.puth64Size( qwordVar, width, ‘ ‘ );
HLA low-level calling sequence examples:
push( (type dword qwordVar[4]) ); // H.O. dword first
push( (type dword qwordVar)); // L.O. dword last
push( width );
pushd( ‘ ‘ );
call stderr.puth64Size;
push( edx ); // Assume 64-bit value in edx:eax
push( eax );
push( width );
push( ecx ); // fill char is in CL
call stderr.puth64Size;
// Assume fill char is in CH
push( (type dword qwordVar[4]) ); // H.O. dword first
push( (type dword qwordVar)); // L.O. dword last
push( width );
xchg( cl, ch ); // fill char is in CH
push( ecx );
xchg( cl, ch );
call stderr.puth64Size;
// Alternate method of the above
push( (type dword qwordVar[4]) ); // H.O. dword first
push( (type dword qwordVar)); // L.O. dword last
push( width );
sub( 4, esp );
mov( ch, [esp] );
call stderr.puth64Size;
// If the fill char is a variable and
// a register is available, try this code:
push( (type dword qwordVar[4]) ); // H.O. dword first
push( (type dword qwordVar)); // L.O. dword last
push( width );
movzx( fillChar, ebx ); // Assume EBX is available
push( ebx );
call stderr.puth64Size;
// If the fill char is a variable and
// no register is available, here’s one
// possibility:
push( (type dword qwordVar[4]) ); // H.O. dword first
push( (type dword qwordVar)); // L.O. dword last
push( width );
push( (type dword fillChar) ); // Chance of page crossing!
call stderr.puth64Size;
// In the very rare case that the above would
// cause an illegal memory access, use this:
push( (type dword qwordVar[4]) ); // H.O. dword first
push( (type dword qwordVar)); // L.O. dword last
push( width );
sub( 4, esp );
push( eax );
movzx( fillChar, eax );
mov( eax, [esp+4] );
pop( eax );
call stderr.puth64Size;
stderr.puttb( tb:tbyte );
This procedure writes the value of tb to the standard err using exactly 20 hexadecimal digits (including leading zeros if necessary and an intervening underscores if underscore output is enabled).
HLA high-level calling sequence examples:
stderr.puttb( tbyteVar );
HLA low-level calling sequence examples:
pushw( 0 );
// Push push a 0 pad word
push( (type word tbyteVar[8])); // Push H.O. word first
push( (type dword tbyteVar[4]) ); // M.O. dword second
push( (type dword tbyteVar)); // L.O. dword last
call stderr.puttb;
stderr.puth80( tb:tbyte );
This procedure writes the value of tb to the standard error using the minimum necessary number of hexadecimal digits (including intervening underscores if underscore output is enabled).
HLA high-level calling sequence examples:
stderr.puth80( tbyteVar );
HLA low-level calling sequence examples:
pushw( 0 );
// Push push a 0 pad word
push( (type word tbyteVar[8])); // Push H.O. word first
push( (type dword tbyteVar[4]) ); // M.O. dword second
push( (type dword tbyteVar)); // L.O. dword last
call stderr.puth80;
stderr.puth80Size( tb:tbyte; size:dword; fill:char );
The stderr.puth80Size function lets you specify a minimum field width and a fill character. It writes the tbyte value tb as a hexadecimal string to the standard error device using the provided minimum size and fill character.
HLA high-level calling sequence examples:
stderr.puth80Size( tbyteVar, width, ‘ ‘ );
HLA low-level calling sequence examples:
pushw( 0 );
// Push push a 0 pad word
push( (type word tbyteVar[8])); // Push H.O. word first
push( (type dword tbyteVar[4]) ); // M.O. dword second
push( (type dword tbyteVar)); // L.O. dword last
push( width );
pushd( ‘ ‘ );
call stderr.puth80Size;
// Assume fill char is in CH
pushw( 0 );
// Push push a 0 pad word
push( (type word tbyteVar[8])); // Push H.O. word first
push( (type dword tbyteVar[4]) ); // M.O. dword second
push( (type dword tbyteVar)); // L.O. dword last
push( width );
xchg( cl, ch ); // fill char is in CH
push( ecx );
xchg( cl, ch );
call stderr.puth80Size;
// Alternate method of the above
pushw( 0 );
// Push push a 0 pad word
push( (type word tbyteVar[8])); // Push H.O. word first
push( (type dword tbyteVar[4]) ); // M.O. dword second
push( (type dword tbyteVar)); // L.O. dword last
push( width );
sub( 4, esp );
mov( ch, [esp] );
call stderr.puth80Size;
// If the fill char is a variable and
// a register is available, try this code:
pushw( 0 );
// Push push a 0 pad word
push( (type word tbyteVar[8])); // Push H.O. word first
push( (type dword tbyteVar[4]) ); // M.O. dword second
push( (type dword tbyteVar)); // L.O. dword last
push( width );
movzx( fillChar, ebx ); // Assume EBX is available
push( ebx );
call stderr.puth80Size;
// If the fill char is a variable and
// no register is available, here’s one
// possibility:
pushw( 0 );
// Push push a 0 pad word
push( (type word tbyteVar[8])); // Push H.O. word first
push( (type dword tbyteVar[4]) ); // M.O. dword second
push( (type dword tbyteVar)); // L.O. dword last
push( width );
push( (type dword fillChar) ); // Chance of page crossing!
call stderr.puth80Size;
// In the very rare case that the above would
// cause an illegal memory access, use this:
pushw( 0 );
// Push push a 0 pad word
push( (type word tbyteVar[8])); // Push H.O. word first
push( (type dword tbyteVar[4]) ); // M.O. dword second
push( (type dword tbyteVar)); // L.O. dword last
push( width );
sub( 4, esp );
push( eax );
movzx( fillChar, eax );
mov( eax, [esp+4] );
pop( eax );
call stderr.puth80Size;
stderr.putl( l:lword );
This procedure writes the value of l to the standard error using exactly 32 hexadecimal digits (including leading zeros if necessary and an intervening underscores if underscore output is enabled).
HLA high-level calling sequence examples:
stderr.putl( lwordVar );
HLA low-level calling sequence examples:
push( (type dword lwordVar[12]) ); // H.O. dword first
push( (type dword lwordVar[8]) );
push( (type dword lwordVar[4]) );
push( (type dword lwordVar)); // L.O. dword last
call stderr.putl;
stderr.puth128( l:lword );
This procedure writes the value of l to the standard error using the minimum necessary number of hexadecimal digits (including intervening underscores if underscore output is enabled).
HLA high-level calling sequence examples:
stderr.puth128( lwordVar );
HLA low-level calling sequence examples:
push( (type dword lwordVar[12]) ); // H.O. dword first
push( (type dword lwordVar[8]) );
push( (type dword lwordVar[4]) );
push( (type dword lwordVar)); // L.O. dword last
call stderr.puth128;
stderr.puth128Size(
l:lword; size:dword; fill:char );
The stderr.puth128Size function writes an lword value to the standard error and it lets you specify a minimum field width and a fill character.
HLA high-level calling sequence examples:
stderr.puth128Size( tbyteVar, width, ‘ ‘ );
HLA low-level calling sequence examples:
push( (type dword lwordVar[12])); // Push H.O. word first
push( (type dword lwordVar[8]) );
push( (type dword lwordVar[4]) );
push( (type dword lwordVar)); // L.O. dword last
push( width );
pushd( ‘ ‘ );
call stderr.puth128Size;
// Assume fill char is in CH
push( (type dword lwordVar[12])); // Push H.O. word first
push( (type dword lwordVar[8]) );
push( (type dword lwordVar[4]) );
push( (type dword lwordVar)); // L.O. dword last
push( width );
xchg( cl, ch ); // fill char is in CH
push( ecx );
xchg( cl, ch );
call stderr.puth128Size;
// Alternate method of the above
push( (type dword lwordVar[12])); // Push H.O. word first
push( (type dword lwordVar[8]) );
push( (type dword lwordVar[4]) );
push( (type dword lwordVar)); // L.O. dword last
push( width );
sub( 4, esp );
mov( ch, [esp] );
call stderr.puth128Size;
// If the fill char is a variable and
// a register is available, try this code:
push( (type dword lwordVar[12])); // Push H.O. word first
push( (type dword lwordVar[8]) );
push( (type dword lwordVar[4]) );
push( (type dword lwordVar)); // L.O. dword last
push( width );
movzx( fillChar, ebx ); // Assume EBX is available
push( ebx );
call stderr.puth128Size;
// If the fill char is a variable and
// no register is available, here’s one
// possibility:
push( (type dword lwordVar[12])); // Push H.O. word first
push( (type dword lwordVar[8]) );
push( (type dword lwordVar[4]) );
push( (type dword lwordVar)); // L.O. dword last
push( width );
push( (type dword fillChar) ); // Chance of page crossing!
call stderr.puth128Size;
// In the very rare case that the above would
// cause an illegal memory access, use this:
push( (type dword lwordVar[12])); // Push H.O. word first
push( (type dword lwordVar[8]) );
push( (type dword lwordVar[4]) );
push( (type dword lwordVar)); // L.O. dword last
push( width );
sub( 4, esp );
push( eax );
movzx( fillChar, eax );
mov( eax, [esp+4] );
pop( eax );
call stderr.puth128Size;
These routines convert signed integer values to string format and write that string to the standard error device. The stderr.putxxxSize functions contain width and fill parameters that let you specify the minimum field width when outputting a value.
If the absolute value of width is greater than the number of print positions the value requires, then these functions output width characters to the standard error device. If width is non-negative, then these functions right-justify the value in the output field; if value is negative, then these functions left-justify the value in the output field.
These functions print the fill character as the padding value for the extra print positions.
Note that unlike floating point values, these functions do not print a space in front of the value if it is non-negative.
stderr.puti8 ( b:byte );
This function converts the eight-bit signed integer you pass as a parameter to a string and writes this string to the standard error using the minimum number of print positions the number requires.
HLA high-level calling sequence examples:
stderr.puti8( byteVar );
// If the character is in a register (AL):
stderr.puti8( al );
HLA low-level calling sequence examples:
//
If “byteVar ” is not one of the last three
//
bytes on a page of memory, you can do this:
push( (type dword byteVar ) );
call stderr.puti8;
// If you can’t guarantee that the previous code
// won’t generate an illegal memory access, and a
// 32-bit register is available, use code like
// the following:
movzx( byteVar , eax ); // Assume EAX is available
push( eax );
call stderr.puti8;
// If no register is available, do something
// like the following code:
push( eax );
movzx( byteVar , eax );
push( eax );
call stderr.puti8;
pop( eax );
// If the character value is in al, bl, cl, or dl
// then you can use code like the following:
push( eax ); //
Assume byteVar is in AL
call stderr.puti8;
// If the byte value is in ah, bh, ch, or dh
// you’ll have to use code like the following:
xchg( al, ah ); // Assume byteVar is in AH
push( eax );
// It’s now in AL
xchg( al, ah ); // Restore al/ah
call stderr.puti8;
stderr.puti8Size ( b:byte; width:int32; fill:char )
This function writes the eight-bit signed integer value you pass to the standard error using the width and fill values as specified above.
HLA high-level calling sequence examples:
stderr.puti8Size( byteVar, width, padChar );
HLA low-level calling sequence examples:
//
If “byteVar” and “padChar” are not one of the last three
//
bytes on a page of memory, you can do this:
push( (type dword byteVar) );
push( width );
push( (type dword padChar) );
call stderr.puti8Size;
// If you can’t guarantee that the previous code
// won’t generate an illegal memory access, and a
// 32-bit register is available, use code like
// the following:
movzx( byteVar, eax ); // Assume EAX is available
push( eax );
push( width );
movzx( padChar, ebx ); // Assume EBX is available
push( ebx );
call stderr.puti8Size;
// If no registers are available, do something
// like the following code:
push( eax );
movzx( byteVar, eax );
push( eax );
push( width );
movzx( padChar, eax );
push( eax );
call stderr.puti8Size;
pop( eax );
// If “byteVar” or “padChar” are in an
// 8-bit register, then you can push
// the corresponding 32-bit register if
// the register is AL, BL, CL, or DL:
push( eax );
// Assume byteVar is in AL
push( width );
push( ebx );
// Assume padChar is in BL
call stderr.puti8Size;
// Do the following if the characters are
// in AH, BH, CH, or DH:
xchg( al, ah );
// Assume byteVar is in AH
xchg( bl, bh );
// Assume padChar is in BH
push( eax );
push( width );
push( ebx );
xchg( al, ah );
xchg( bl, bh );
call stderr.puti8Size;
stderr.puti16( w:word );
This function converts the 16-bit signed integer you pass as a parameter to a string and writes this string to the standard error device using the minimum number of print positions the number requires.
HLA high-level calling sequence examples:
stderr.puti16( wordVar );
// If the word is in a register (AX):
stderr.puti16( ax );
HLA low-level calling sequence examples:
//
If “wordVar ” is not one of the last three
//
bytes on a page of memory, you can do this:
push( (type dword wordVar) );
call stderr.puti16;
// If you can’t guarantee that the previous code
// won’t generate an illegal memory access, and a
// 32-bit register is available, use code like
// the following:
movzx( wordVar, eax ); // Assume EAX is available
push( eax );
call stderr.puti16;
// If no register is available, do something
// like the following code:
push( eax );
movzx( wordVar, eax );
push( eax );
call stderr.puti16;
pop( eax );
// If the word value is in a 16-bit register
// then you can use code like the following:
push( eax ); //
Assume wordVar is in AX
call stderr.puti16;
stderr.puti16Size( w:word; width:int32; fill:char );
This function writes the 16-bit signed integer value you pass to the standard error using the width and fill values as specified above.
HLA high-level calling sequence examples:
stderr.puti16Size( wordVar, width, padChar );
HLA low-level calling sequence examples:
//
If “wordVar” and “padChar” are not one of the last three
//
bytes on a page of memory, you can do this:
push( (type dword wordVar) );
push( width );
push( (type dword padChar) );
call stderr.puti16Size;
// If you can’t guarantee that the previous code
// won’t generate an illegal memory access, and a
// 32-bit register is available, use code like
// the following:
movzx( wordVar, eax ); // Assume EAX is available
push( eax );
push( width );
movzx( padChar, ebx ); // Assume EBX is available
push( ebx );
call stderr.puti16Size;
// If no registers are available, do something
// like the following code:
push( eax );
movzx( wordVar, eax );
push( eax );
push( width );
movzx( padChar, eax );
push( eax );
call stderr.puti16Size;
pop( eax );
// If “wordVar” is in a 16-bit register
// and “padChar” is in an
// 8-bit register, then you can push
// the corresponding 32-bit register if
// the register is AL, BL, CL, or DL:
push( eax );
// Assume wordVar is in AX
push( width );
push( ebx );
// Assume padChar is in BL
call stderr.puti16Size;
stderr.puti32( d:dword );
This function converts the 32-bit signed integer you pass as a parameter to a string and writes this string to the standard err using the minimum number of print positions the number requires.
HLA high-level calling sequence examples:
stderr.puti32( dwordVar );
// If the dword is in a register (EAX):
stderr.puti32( eax );
HLA low-level calling sequence examples:
push( dwordVar );
call stderr.puti32;
push( eax );
call stderr.puti32;
stderr.puti32Size( d:dword; width:int32; fill:char );
This function writes the 32-bit value you pass as a signed integer to the standard error device using the width and fill values as specified above.
HLA high-level calling sequence examples:
stderr.putu32Size( dwordVar, width, ‘ ‘ );
// If the dword is in a register (EAX):
stderr.putu32Size( eax, width, cl );
HLA low-level calling sequence examples:
push( dwordVar );
push( width );
pushd( ‘ ‘ );
call stderr.putu32Size;
push( eax );
push( width );
push( ecx ); // fill char is in CL
call stderr.putu32Size;
// Assume fill char is in CH
push( eax );
push( width );
xchg( cl, ch ); // fill char is in CH
push( ecx );
xchg( cl, ch );
call stderr.putu32Size;
// Alternate method of the above
push( eax );
push( width );
sub( 4, esp );
mov( ch, [esp] );
call stderr.putu32Size;
// If the fill char is a variable and
// a register is available, try this code:
push( eax );
push( width );
movzx( fillChar, ebx ); // Assume EBX is available
push( ebx );
call stderr.putu32Size;
// If the fill char is a variable and
// no register is available, here’s one
// possibility:
push( eax );
push( width );
push( (type dword fillChar) ); // Chance of page crossing!
call stderr.putu32Size;
// In the very rare case that the above would
// cause an illegal memory access, use this:
push( eax );
push( width );
sub( 4, esp );
push( eax );
movzx( fillChar, eax );
mov( eax, [esp+4] );
pop( eax );
call stderr.puti32Size;
stderr.puti64( q:qword );
This function converts the 64-bit signed integer you pass as a parameter to a string and writes this string to the standard error using the minimum number of print positions the number requires.
HLA high-level calling sequence examples:
stderr.puti64( qwordVar );
HLA low-level calling sequence examples:
push( (type dword qwordVar[4]) ); // H.O. dword first
push( (type dword qwordVar)); // L.O. dword last
call stderr.puti64;
stderr.puti64Size( q:qword; width:int32; fill:char );
This function writes the 64-bit value you pass as a signed integer to the standard error file using the width and fill values as specified above.
HLA high-level calling sequence examples:
stderr.puti64Size( qwordVar, width, ‘ ‘ );
HLA low-level calling sequence examples:
push( (type dword qwordVar[4]) ); // H.O. dword first
push( (type dword qwordVar)); // L.O. dword last
push( width );
pushd( ‘ ‘ );
call stderr.puti64Size;
push( edx ); // Assume 64-bit value in edx:eax
push( eax );
push( width );
push( ecx ); // fill char is in CL
call stderr.puti64Size;
// Assume fill char is in CH
push( (type dword qwordVar[4]) ); // H.O. dword first
push( (type dword qwordVar)); // L.O. dword last
push( width );
xchg( cl, ch ); // fill char is in CH
push( ecx );
xchg( cl, ch );
call stderr.puti64Size;
// Alternate method of the above
push( (type dword qwordVar[4]) ); // H.O. dword first
push( (type dword qwordVar)); // L.O. dword last
push( width );
sub( 4, esp );
mov( ch, [esp] );
call stderr.puti64Size;
// If the fill char is a variable and
// a register is available, try this code:
push( (type dword qwordVar[4]) ); // H.O. dword first
push( (type dword qwordVar)); // L.O. dword last
push( width );
movzx( fillChar, ebx ); // Assume EBX is available
push( ebx );
call stderr.puti64Size;
// If the fill char is a variable and
// no register is available, here’s one
// possibility:
push( (type dword qwordVar[4]) ); // H.O. dword first
push( (type dword qwordVar)); // L.O. dword last
push( width );
push( (type dword fillChar) ); // Chance of page crossing!
call stderr.puti64Size;
// In the very rare case that the above would
// cause an illegal memory access, use this:
push( (type dword qwordVar[4]) ); // H.O. dword first
push( (type dword qwordVar)); // L.O. dword last
push( width );
sub( 4, esp );
push( eax );
movzx( fillChar, eax );
mov( eax, [esp+4] );
pop( eax );
call stderr.puti64Size;
stderr.puti128( l:lword );
This function converts the 128-bit signed integer you pass as a parameter to a string and writes this string to the standard err using the minimum number of print positions the number requires.
HLA high-level calling sequence examples:
stderr.puti128( lwordVar );
HLA low-level calling sequence examples:
push( (type dword lwordVar[12]) ); // H.O. dword first
push( (type dword lwordVar[8]) );
push( (type dword lwordVar[4]) );
push( (type dword lwordVar)); // L.O. dword last
call stderr.puti128;
stderr.puti128Size( l:lword; width:int32; fill:char );
This function writes the 128-bit value you pass as a signed integer to the standard error device using the width and fill values as specified above.
HLA high-level calling sequence examples:
stderr.puti128Size( lwordVar, width, ‘ ‘ );
HLA low-level calling sequence examples:
push( (type dword lwordVar[12])); // Push H.O. word first
push( (type dword lwordVar[8]) );
push( (type dword lwordVar[4]) );
push( (type dword lwordVar)); // L.O. dword last
push( width );
pushd( ‘ ‘ );
call stderr.puti128Size;
// Assume fill char is in CH
push( (type dword lwordVar[12])); // Push H.O. word first
push( (type dword lwordVar[8]) );
push( (type dword lwordVar[4]) );
push( (type dword lwordVar)); // L.O. dword last
push( width );
xchg( cl, ch ); // fill char is in CH
push( ecx );
xchg( cl, ch );
call stderr.puti128Size;
// Alternate method of the above
push( (type dword lwordVar[12])); // Push H.O. word first
push( (type dword lwordVar[8]) );
push( (type dword lwordVar[4]) );
push( (type dword lwordVar)); // L.O. dword last
push( width );
sub( 4, esp );
mov( ch, [esp] );
call stderr.puti128Size;
// If the fill char is a variable and
// a register is available, try this code:
push( (type dword lwordVar[12])); // Push H.O. word first
push( (type dword lwordVar[8]) );
push( (type dword lwordVar[4]) );
push( (type dword lwordVar)); // L.O. dword last
push( width );
movzx( fillChar, ebx ); // Assume EBX is available
push( ebx );
call stderr.puti128Size;
// If the fill char is a variable and
// no register is available, here’s one
// possibility:
push( (type dword lwordVar[12])); // Push H.O. word first
push( (type dword lwordVar[8]) );
push( (type dword lwordVar[4]) );
push( (type dword lwordVar)); // L.O. dword last
push( width );
push( (type dword fillChar) ); // Chance of page crossing!
call stderr.puti128Size;
// In the very rare case that the above would
// cause an illegal memory access, use this:
push( (type dword lwordVar[12])); // Push H.O. word first
push( (type dword lwordVar[8]) );
push( (type dword lwordVar[4]) );
push( (type dword lwordVar)); // L.O. dword last
push( width );
sub( 4, esp );
push( eax );
movzx( fillChar, eax );
mov( eax, [esp+4] );
pop( eax );
call stderr.puti128Size;
These routines convert unsigned integer values to string format and write that string to the standard error device. The stderr.putxxxSize functions contain width and fill parameters that let you specify the minimum field width when outputting a value.
If the absolute value of width is greater than the number of print positions the value requires, then these functions output width characters to the standard err. If width is non-negative, then these functions right-justify the value in the output field; if value is negative, then these functions left-justify the value in the output field.
These functions print the fill character as the padding value for the extra print positions.
stderr.putu8 ( b:byte );
This function converts the eight-bit unsigned integer you pass as a parameter to a string and writes this string to the standard error device using the minimum number of print positions the number requires.
HLA high-level calling sequence examples:
stderr.putu8( byteVar );
// If the character is in a register (AL):
stderr.putu8( al );
HLA low-level calling sequence examples:
//
If “byteVar ” is not one of the last three
//
bytes on a page of memory, you can do this:
push( (type dword byteVar ) );
call stderr.putu8;
// If you can’t guarantee that the previous code
// won’t generate an illegal memory access, and a
// 32-bit register is available, use code like
// the following:
movzx( byteVar , eax ); // Assume EAX is available
push( eax );
call stderr.putu8;
// If no register is available, do something
// like the following code:
push( eax );
movzx( byteVar , eax );
push( eax );
call stderr.putu8;
pop( eax );
// If the character value is in al, bl, cl, or dl
// then you can use code like the following:
push( eax ); //
Assume byteVar is in AL
call stderr.putu8;
// If the byte value is in ah, bh, ch, or dh
// you’ll have to use code like the following:
xchg( al, ah ); // Assume byteVar is in AH
push( eax );
// It’s now in AL
xchg( al, ah ); // Restore al/ah
call stderr.putu8;
stderr.putu8Size( b:byte; width:int32; fill:char );
This function writes the unsigned eight-bit value you pass to the standard error using the width and fill values as specified above.
HLA high-level calling sequence examples:
stderr.putu8Size( byteVar, width, padChar );
HLA low-level calling sequence examples:
//
If “byteVar” and “padChar” are not one of the last three
//
bytes on a page of memory, you can do this:
push( (type dword byteVar) );
push( width );
push( (type dword padChar) );
call stderr.putu8Size;
// If you can’t guarantee that the previous code
// won’t generate an illegal memory access, and a
// 32-bit register is available, use code like
// the following:
movzx( byteVar, eax ); // Assume EAX is available
push( eax );
push( width );
movzx( padChar, ebx ); // Assume EBX is available
push( ebx );
call stderr.putu8Size;
// If no registers are available, do something
// like the following code:
push( eax );
movzx( byteVar, eax );
push( eax );
push( width );
movzx( padChar, eax );
push( eax );
call stderr.putu8Size;
pop( eax );
// If “byteVar” or “padChar” are in an
// 8-bit register, then you can push
// the corresponding 32-bit register if
// the register is AL, BL, CL, or DL:
push( eax );
// Assume byteVar is in AL
push( width );
push( ebx );
// Assume padChar is in BL
call stderr.putu8Size;
// Do the following if the characters are
// in AH, BH, CH, or DH:
xchg( al, ah );
// Assume byteVar is in AH
xchg( bl, bh );
// Assume padChar is in BH
push( eax );
push( width );
push( ebx );
xchg( al, ah );
xchg( bl, bh );
call stderr.putu8Size;
stderr.putu16( w:word );
This function converts the 16-bit unsigned integer you pass as a parameter to a string and writes this string to the standard error device using the minimum number of print positions the number requires.
HLA high-level calling sequence examples:
stderr.putu16( wordVar );
// If the word is in a register (AX):
stderr.putu16( ax );
HLA low-level calling sequence examples:
//
If “wordVar ” is not one of the last three
//
bytes on a page of memory, you can do this:
push( (type dword wordVar) );
call stderr.putu16;
// If you can’t guarantee that the previous code
// won’t generate an illegal memory access, and a
// 32-bit register is available, use code like
// the following:
movzx( wordVar, eax ); // Assume EAX is available
push( eax );
call stderr.putu16;
// If no register is available, do something
// like the following code:
push( eax );
movzx( wordVar, eax );
push( eax );
call stderr.putu16;
pop( eax );
// If the word value is in a 16-bit register
// then you can use code like the following:
push( eax ); //
Assume wordVar is in AX
call stderr.putu16;
stderr.putu16Size( w:word; width:int32; fill:char );
This function writes the unsigned 16-bit value you pass to the standard err using the width and fill values as specified above.
HLA high-level calling sequence examples:
stderr.putu16Size( wordVar, width, padChar );
HLA low-level calling sequence examples:
//
If “wordVar” and “padChar” are not one of the last three
//
bytes on a page of memory, you can do this:
push( (type dword wordVar) );
push( width );
push( (type dword padChar) );
call stderr.putu16Size;
// If you can’t guarantee that the previous code
// won’t generate an illegal memory access, and a
// 32-bit register is available, use code like
// the following:
movzx( wordVar, eax ); // Assume EAX is available
push( eax );
push( width );
movzx( padChar, ebx ); // Assume EBX is available
push( ebx );
call stderr.putu16Size;
// If no registers are available, do something
// like the following code:
push( eax );
movzx( wordVar, eax );
push( eax );
push( width );
movzx( padChar, eax );
push( eax );
call stderr.putu16Size;
pop( eax );
// If “wordVar” is in a 16-bit register
// and “padChar” is in an
// 8-bit register, then you can push
// the corresponding 32-bit register if
// the register is AL, BL, CL, or DL:
push( eax );
// Assume wordVar is in AX
push( width );
push( ebx );
// Assume padChar is in BL
call stderr.putu16Size;
stderr.putu32( d:dword );
This function converts the 32-bit unsigned integer you pass as a parameter to a string and writes this string to the standard error device using the minimum number of print positions the number requires.
HLA high-level calling sequence examples:
stderr.putu32( dwordVar );
// If the dword is in a register (EAX):
stderr.putu32( eax );
HLA low-level calling sequence examples:
push( dwordVar );
call stderr.putu32;
push( eax );
call stderr.putu32;
stderr.putu32Size( d:dword; width:int32; fill:char );
This function writes the unsigned 32-bit value you pass to the standard err using the width and fill values as specified above.
HLA high-level calling sequence examples:
stderr.putu32Size( dwordVar, width, ‘ ‘ );
// If the dword is in a register (EAX):
stderr.putu32Size( eax, width, cl );
HLA low-level calling sequence examples:
push( dwordVar );
push( width );
pushd( ‘ ‘ );
call stderr.putu32Size;
push( eax );
push( width );
push( ecx ); // fill char is in CL
call stderr.putu32Size;
// Assume fill char is in CH
push( eax );
push( width );
xchg( cl, ch ); // fill char is in CH
push( ecx );
xchg( cl, ch );
call stderr.putu32Size;
// Alternate method of the above
push( eax );
push( width );
sub( 4, esp );
mov( ch, [esp] );
call stderr.putu32Size;
// If the fill char is a variable and
// a register is available, try this code:
push( eax );
push( width );
movzx( fillChar, ebx ); // Assume EBX is available
push( ebx );
call stderr.putu32Size;
// If the fill char is a variable and
// no register is available, here’s one
// possibility:
push( eax );
push( width );
push( (type dword fillChar) ); // Chance of page crossing!
call stderr.putu32Size;
// In the very rare case that the above would
// cause an illegal memory access, use this:
push( eax );
push( width );
sub( 4, esp );
push( eax );
movzx( fillChar, eax );
mov( eax, [esp+4] );
pop( eax );
call stderr.putu32Size;
stderr.putu64( q:qword );
This function converts the 64-bit unsigned integer you pass as a parameter to a string and writes this string to the standard error device using the minimum number of print positions the number requires.
HLA high-level calling sequence examples:
stderr.putu64( qwordVar );
HLA low-level calling sequence examples:
push( (type dword qwordVar[4]) ); // H.O. dword first
push( (type dword qwordVar)); // L.O. dword last
call stderr.putu64;
stderr.putu64Size( q:qword; width:int32; fill:char );
This function writes the unsigned 64-bit value you pass to the error output using the width and fill values as specified above.
HLA high-level calling sequence examples:
stderr.putu64Size( qwordVar, width, ‘ ‘ );
HLA low-level calling sequence examples:
push( (type dword qwordVar[4]) ); // H.O. dword first
push( (type dword qwordVar)); // L.O. dword last
push( width );
pushd( ‘ ‘ );
call stderr.putu64Size;
push( edx ); // Assume 64-bit value in edx:eax
push( eax );
push( width );
push( ecx ); // fill char is in CL
call stderr.putu64Size;
// Assume fill char is in CH
push( (type dword qwordVar[4]) ); // H.O. dword first
push( (type dword qwordVar)); // L.O. dword last
push( width );
xchg( cl, ch ); // fill char is in CH
push( ecx );
xchg( cl, ch );
call stderr.putu64Size;
// Alternate method of the above
push( (type dword qwordVar[4]) ); // H.O. dword first
push( (type dword qwordVar)); // L.O. dword last
push( width );
sub( 4, esp );
mov( ch, [esp] );
call stderr.putu64Size;
// If the fill char is a variable and
// a register is available, try this code:
push( (type dword qwordVar[4]) ); // H.O. dword first
push( (type dword qwordVar)); // L.O. dword last
push( width );
movzx( fillChar, ebx ); // Assume EBX is available
push( ebx );
call stderr.putu64Size;
// If the fill char is a variable and
// no register is available, here’s one
// possibility:
push( (type dword qwordVar[4]) ); // H.O. dword first
push( (type dword qwordVar)); // L.O. dword last
push( width );
push( (type dword fillChar) ); // Chance of page crossing!
call stderr.putu64Size;
// In the very rare case that the above would
// cause an illegal memory access, use this:
push( (type dword qwordVar[4]) ); // H.O. dword first
push( (type dword qwordVar)); // L.O. dword last
push( width );
sub( 4, esp );
push( eax );
movzx( fillChar, eax );
mov( eax, [esp+4] );
pop( eax );
call stderr.putu64Size;
stderr.putu128( l:lword );
This function converts the 128-bit unsigned integer you pass as a parameter to a string and writes this string to the standard err using the minimum number of print positions the number requires.
HLA high-level calling sequence examples:
stderr.putu128( lwordVar );
HLA low-level calling sequence examples:
push( (type dword lwordVar[12]) ); // H.O. dword first
push( (type dword lwordVar[8]) );
push( (type dword lwordVar[4]) );
push( (type dword lwordVar)); // L.O. dword last
call stderr.putu128;
stderr.putu128Size( l:lword; width:int32; fill:char )
This function writes the unsigned 128-bit value you pass to the standard err using the width and fill values as specified above.
HLA high-level calling sequence examples:
stderr.putu128Size( lwordVar, width, ‘ ‘ );
HLA low-level calling sequence examples:
push( (type dword lwordVar[12])); // Push H.O. word first
push( (type dword lwordVar[8]) );
push( (type dword lwordVar[4]) );
push( (type dword lwordVar)); // L.O. dword last
push( width );
pushd( ‘ ‘ );
call stderr.putu128Size;
// Assume fill char is in CH
push( (type dword lwordVar[12])); // Push H.O. word first
push( (type dword lwordVar[8]) );
push( (type dword lwordVar[4]) );
push( (type dword lwordVar)); // L.O. dword last
push( width );
xchg( cl, ch ); // fill char is in CH
push( ecx );
xchg( cl, ch );
call stderr.putu128Size;
// Alternate method of the above
push( (type dword lwordVar[12])); // Push H.O. word first
push( (type dword lwordVar[8]) );
push( (type dword lwordVar[4]) );
push( (type dword lwordVar)); // L.O. dword last
push( width );
sub( 4, esp );
mov( ch, [esp] );
call stderr.putu128Size;
// If the fill char is a variable and
// a register is available, try this code:
push( (type dword lwordVar[12])); // Push H.O. word first
push( (type dword lwordVar[8]) );
push( (type dword lwordVar[4]) );
push( (type dword lwordVar)); // L.O. dword last
push( width );
movzx( fillChar, ebx ); // Assume EBX is available
push( ebx );
call stderr.putu128Size;
// If the fill char is a variable and
// no register is available, here’s one
// possibility:
push( (type dword lwordVar[12])); // Push H.O. word first
push( (type dword lwordVar[8]) );
push( (type dword lwordVar[4]) );
push( (type dword lwordVar)); // L.O. dword last
push( width );
push( (type dword fillChar) ); // Chance of page crossing!
call stderr.putu128Size;
// In the very rare case that the above would
// cause an illegal memory access, use this:
push( (type dword lwordVar[12])); // Push H.O. word first
push( (type dword lwordVar[8]) );
push( (type dword lwordVar[4]) );
push( (type dword lwordVar)); // L.O. dword last
push( width );
sub( 4, esp );
push( eax );
movzx( fillChar, eax );
mov( eax, [esp+4] );
pop( eax );
call stderr.putu128Size;
The HLA standard error module provides several procedures you can use to write floating point values to the standard error device. The following subsections describe these routines.
The floating point numeric output routines translate the three different binary floating point formats to their string representation and then write this string to the standard error. There are two generic classes of these routines: those that convert their values to exponential/scientific notation and those that convert their string to a decimal form.
The stderr.pute80, stderr.pute64, and stderr.pute32 routines convert their values to a string using scientific notation. These three routines each have two parameters: the value to output and the field width of the result. These routines produce a string with the following format:
stderr.pute32( r:real32; width:uns32 );
This function writes the 32-bit single precision floating point value passed in r to the standard err using scientific/exponential notation. This procedure prints the value using width print positions in the output. width should have a minimum value of five for real numbers in the range 1e-9..1e+9 and a minimum value of six for all other values. Note that 32-bit extended precision floating point values support about 6-7 significant digits. So a width value that yeilds more than seven mantissa digits will produce garbage output in the low order digits of the number.
HLA high-level calling sequence examples:
stderr.pute32( r32Var, width );
// If the real32 value is in an FPU register (ST0):
var
r32Temp :real32;
.
.
.
fstp( r32Temp );
stderr.pute32( r32Temp, 12 );
HLA low-level calling sequence examples:
push( (type dword r32Var) );
push( width );
call stderr.pute32;
sub( 4, esp );
fstp( (type real32 [esp]) );
pushd( 12 );
call stderr.pute32;
stderr.pute64( r:real64; width:uns32 );
This function writes the 64-bit double precision floating point value passed in r to the standard error using scientific/exponential notation. This procedure prints the value using width print positions in the output. width should have a minimum value of five for real numbers in the range 1e-9..1e+9 and a minimum value of six for all other values. Note that 64-bit double precision floating point values support about 15 significant digits. So a width value that yeilds more than 15 mantissa digits will produce garbage output in the low order digits of the number.
HLA high-level calling sequence examples:
stderr.pute64( r64Var, width );
// If the real64 value is in an FPU register (ST0):
var
r64Temp :real64;
.
.
.
fstp( r64Temp );
stderr.pute64( r64Temp, 12 );
HLA low-level calling sequence examples:
push( (type dword r64Var[4]));
push( (type dword r64Var[0]));
push( width );
call stderr.pute64;
sub( 8, esp );
fstp( (type real64 [esp]) );
pushd( 12 );
call stderr.pute64;
stderr.pute80( r:real80; width:uns32 );
This function writes the 80-bit extended precision floating point value passed in r to the standard error device using scientific/exponential notation. This procedure prints the value using width print positions in the standard err. width should have a minimum value of five for real numbers in the range 1e-9..1e+9 and a minimum value of six for all other values. Note that 80-bit extended precision floating point values support about 18 significant digits. So a width value that yeilds more than 18 mantissa digits will produce garbage output in the low order digits of the number.
HLA high-level calling sequence examples:
stderr.pute80( r80Var, width );
// If the real80 value is in an FPU register (ST0):
var
r80Temp :real80;
.
.
.
fstp( r80Temp );
stderr.pute80( r80Temp, 12 );
HLA low-level calling sequence examples:
pushw( 0 ); // A word of padding.
push( (type word r80Var[8]));
push( (type dword r80Var[4]));
push( (type dword r80Var[0]));
push( width );
call stderr.pute80;
sub( 12, esp );
fstp( (type real80 [esp]) );
pushd( 12 );
call stderr.pute80;
Although scientific (exponential) notation is the most general display format for real numbers, real numbers you display in this format are very difficult to read. Therefore, the HLA stderr module also provides a set of functions that output real values using the decimal representation. Although you cannot (practically) use these decimal output routines for all real values, they are applicable to a wide variety of common numbers you will use in your programs.
These functions require four parameters: the real value to convert, the width of the converted value, the number of digit positions to the right of the decimal point, and a padding character. These functions write their values using the following string format:
stderr.putr32( r:real32; width:uns32; decpts:uns32; pad:char );
This procedure writes a 32-bit single precision floating point value to the standard error as a string. The string consumes exactly width characters in the output. If the numeric output, using the specified number of positions to the right of the decimal point, is sufficiently small that the string representation would be less than width characters, then this procedure uses the value of pad as the padding character to fill the output with width characters. The number is right-justified within the output field (that is, this function prints the padding characters before the string representation of the number).
HLA high-level calling sequence examples:
stderr.putr32( r32Var, width, decpts, fill );
stderr.putr32( r32Var, 10, 2, ‘*’ );
// If the real32 value is in an FPU register (ST0):
var
r32Temp :real32;
.
.
.
fstp( r32Temp );
stderr.putr32( r32Temp, 12, 2, al );
HLA low-level calling sequence examples:
push( (type dword r32Var) );
push( width );
push( decpts );
movzx( fill, eax );
push( eax );
call stderr.putr32;
push( (type dword r32Var) );
push( width );
push( decpts );
pushd( (type dword fill) ); // If no memory fault possible
call stderr.putr32;
sub( 4, esp );
fstp( (type real32 [esp]) );
pushd( 12 );
sub( 4, esp );
push( eax );
movzx( fill, eax ): //
If memory fault were possible
mov( eax, [esp+4] ); // in above code.
pop( eax );
call stderr.putr32;
stderr.putr64( r:real64; width:uns32; decpts:uns32; pad:char);
This procedure writes a 64-bit double precision floating point value to the standard error device as a string. The string consumes exactly width characters in the output. If the numeric output, using the specified number of positions to the right of the decimal point, is sufficiently small that the string representation would be less than width characters, then this procedure uses the value of pad as the padding character to fill the output with width characters.
HLA high-level calling sequence examples:
stderr.putr64( r64Var, width, decpts, fill );
stderr.putr64( r64Var, 10, 2, ‘*’ );
// If the real64 value is in an FPU register (ST0):
var
r64Temp :real64;
.
.
.
fstp( r64Temp );
stderr.putr64( r64Temp, 12, 2, al );
HLA low-level calling sequence examples:
push( (type dword r64Var[4]) );
push( (type dword r64Var) );
push( width );
push( decpts );
movzx( fill, eax );
push( eax );
call stderr.putr64;
push( (type dword r64Var[4]) );
push( (type dword r64Var) );
push( width );
push( decpts );
pushd( (type dword fill) ); // If no memory fault possible
call stderr.putr64;
sub( 8, esp );
fstp( (type real64 [esp]) );
pushd( 12 );
sub( 4, esp );
push( eax );
movzx( fill, eax ): //
If memory fault were possible
mov( eax, [esp+4] ); // in above code.
pop( eax );
call stderr.putr64;
stderr.putr80( r:real80; width:uns32; decpts:uns32; pad:char);
This procedure writes an 80-bit extended precision floating point value to the output as a string. The string consumes exactly width characters in the output. If the numeric output, using the specified number of positions to the right of the decimal point, is sufficiently small that the string representation would be less than width characters, then this procedure uses the value of pad as the padding character to fill the output with width characters.
HLA high-level calling sequence examples:
stderr.putr80( r80Var, width, decpts, fill );
stderr.putr80( r80Var, 10, 2, ‘*’ );
// If the real80 value is in an FPU register (ST0):
var
r80Temp :real80;
.
.
.
fstp( r80Temp );
stderr.putr80( r80Temp, 12, 2, al );
HLA low-level calling sequence examples:
pushw( 0 );
push( (type word r80Var[8]) );
push( (type dword r80Var[4]) );
push( (type dword r80Var) );
push( width );
push( decpts );
movzx( fill, eax );
push( eax );
call stderr.putr80;
pushw( 0 );
push( (type word r80Var[8]) );
push( (type dword r80Var[4]) );
push( (type dword r80Var) );
push( width );
push( decpts );
pushd( (type dword fill) ); // If no memory fault possible
call stderr.putr80;
sub( 12, esp );
fstp( (type real80 [esp]) );
pushd( 12 );
sub( 4, esp );
push( eax );
movzx( fill, eax ): //
If memory fault were possible
mov( eax, [esp+4] ); // in above code.
pop( eax );
call stderr.putr80;
stderr.put( list_of_items );
stderr.put is a macro that automatically invokes an appropriate stderr output routine based on the type of the parameter(s) you pass it. This is a very convenient output routine and is probably the stderr output call you will use most often in your programs. Keep in mind that this macro is not a single function call; instead, HLA translates this macro into a sequence of calls to procedures like stderr.putu32, stderr.puts, etc.
stderr.put is a macro that provides a flexible syntax for outputting data to the standard error device. This macro allows a variable number of parameters. For each parameter present in the list, stderr.put will call the appropriate routine to emit that data, according to the type of the parameter. Parameters may be constants, registers, or memory locations. You must separate each macro parameter with a comma.
Here is an example of a typical invocation of stderr.put:
stderr.put( "I=", i,
" j=", j, nl );
The above is roughly equivalent to
stderr.puts( "I=" );
stderr.putu32( i );
stderr.puts( " j=" );
stderr.putu32( j );
stderr.newln();
This assumes, of course, that i and j are int32 variables.
The stderr.put macro also lets you specify the minimum field width for each parameter you specify. To print a value using a minimum field width, follow the object you wish to print with a colon and the value of the minimum field width. The previous example, using field widths, could look like the following:
stderr.put( "I=",
i:2, " j=", j:5, nl );
Although this example used the
literal decimal constants two and five for the field widths, keep in mind that
register values and memory value (integers, anyway) are prefectly legal here.
For floating point numbers you wish to display in decimal form, you can specify both the minimum field width and the number of digits to print to the right of the decimal point by using the following syntax:
stderr.put( "Real value is
", f:10:3, nl );
The stderr.put macro can handle all the basic primitive types, including boolean, unsigned (8, 16, 32, 64, 128), signed (8, 16, 32, 64, 128), character, character set, real (32, 64, 80), string, and hexadecimal (byte, word, dword, qword, lword).
There is a known "design flaw" in the stderr.put macro. You cannot use it to print HLA intermediate variables (i.e., non-local VAR objects). The problem is that HLA’s syntax for non-local accesses takes the form "reg32:varname" and stderr.put cannot determine if you want to print reg32 using varname print positions versus simply printing the non-local varname object. If you want to display non-local variables you must copy the non-local object into a register, a static variable, or a local variable prior to using stderr.put to print it. Of course, there is no problem using the other stderr.putXXXX functions to display non-local VAR objects, so you can use those as well.