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).

Conversion Format Control

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.

 

File I/O Routines and the Standard Error Handle

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.

 

Standard Error Routines

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. 

Miscellaneous Output Routines

 

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;

 

 

 

 

Boolean Output

 

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;

 

 

 

 

 

Character, String, and Character Set Output Routines

 

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;

 

 

 

 

 

Hexadecimal Output Routines

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;

 

 

 

 

 

Signed Integer Output Routines

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;

 

 

 

 

 

Unsigned Integer Output Routines

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;

 

 

 

 

 

Floating Point Output Routines

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.

Real Output Using Scientific Notation

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;

 

 

 

 

Real Output Using Decimal Notation

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;

 

 

 

 

Generic Error Output Routine

 

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.