By default, most of the routines in this package send their output to the stdlib "standard output device"; This is a pseudo-device with an output hook that lets the system redirect output to some other procedure. By changing a far pointer (using some access methods), you can capture all output sent to the standard output device.
Normally, the stdlib standard output device is the DOS standard output device. Therefore, programs you write that send data to the stdlib standard output device can have their output redirected to a file or other device via DOS I/O redirection.
include stdout.a or include ucrlib.aThe stdout.a include file exports several symbols. The UCR Standard Library prefaces all "private" names with a dollar sign ("$"). You should not call any routine in this package that begins with this symbol. To avoid name conflicts, you should not define any symbols in your programs that begin with a dollar sign ("$"). Note that future versions of the stdlib (that remain compatible with this release) may change "private" names. To remain compatible with future releases, you must not refer to these "private" names within your programs.
Source code appearing in this chapter is current as of Version Two, Release 40. There may be minor changes between this source code and the current release.
IsAlNum ;Passed in AL register. IsAlNumCS dword chrPtr ;Passed by reference in code stream. push 'a' ;Passed by value on the stack. IsAlNumTOS push seg chrVar ;Passed by reference on the stack. push offset chrVar IsAlNumStkIn addition to the above forms there are two other suffixes generally applied to stdlib routine names: "m" and "x". The "m" suffix stands for "malloc". Routines with the "m" suffix typically generate a string result and malloc storage for the string on the heap, returning a pointer to this string in the ES:DI register pair. The routines with an "x" suffix also process strings. Most stdlib routines preserve the value of the ES:DI registers when processing strings; typically, they leave the ES:DI register pair pointing at the start of the string. The routines with an "x" suffix do not preserve ES:DI, they generally leave ES:DI pointing at the zero byte of the string they processed or generated.
To make it easier to use all these different variants, the standard library typically defines a macro for each routine that lets you specify various operands using stdlib "addressing modes." The allowable addressing modes vary by routines, but they typically take one of the following forms:
name ;If operand field is blank, use "plain" version. name var ;Generally passes address of var in code stream (CS). name const ;Pushes const onto TOS and uses nameTOS routine. name [wvar] ;Pushes DS followed by value of wVar variable ; (assumed to be a word) and calls nameSTK name [dVar] ;Pushes dword value of dVar onto stk, calls nameStk.Since not all of these "addressing modes" are applicable to all instructions, and some instructions allow different sets of operands (including multiple operands), there are lots of special cases. Such cases are noted after the explaination for each particular routine.
| Name | Plain | CS | TOS | Stk | X | CSi |
|---|---|---|---|---|---|---|
| Putc | X | X | X | X | - | - |
The putc macro allows the following operands:
| Name | byteVar | Num const | [word Var] | [dword Var] | Character Const | 8-bit Register | |
|---|---|---|---|---|---|---|---|
| Putc | X | X | - | X | X | X | X |
mov al, 'A'
putc
push word ptr CharVar
PutcTOS
PutcCS
dword CharVar
pshadrs CharVar
PutcStk
putc 'A'
putc CharVar
putc BH
putc CL
putc [wvar]
putc [dvar]
; putc 'A'
push 'A'
putcTOS
; putc charvar
putcCS
dword charvar
; putc BH
xchg bl, bh
push bx
xchg bl, bh
putcTOS
; putc CL
push cx
putcTOS
; putc [wvar]
push wvar
putcStk
; putc [dvar]
push [dvar]
putcStk
| Name | Plain | CS | TOS | Stk | X | CSi |
|---|---|---|---|---|---|---|
| Putc | X | - | - | - | - | - |
The putcr macro allows the following operands:
| Name | byteVar | Num const | [word Var] | [dword Var] | String Const | 8-bit Register | |
|---|---|---|---|---|---|---|---|
| Putcr | X | X | - | - | - | - | - |
putcr ;Print a newline to the standard output device.
The DOS Standard Output Device, on the other hand, is not so easily redirected under program control. It is easy, however, to redirect DOS' standard output via command line parameters, e.g., ">filename>.
If you directly call PutcStdOut, you can bypass the stdlib redirection process. For example, if you've currently redirected the stdlib Standard Output Device and you want to send a character to the DOS standard output without resetting the Putc pointer, you can call the PutcStdOut routine to accomplish this.
PutcStdOut uses the DOS call INT 21h, AH=02 to send its character to the standard output.
| Name | Plain | CS | TOS | Stk | X | CSi |
|---|---|---|---|---|---|---|
| PutcStdOut | X | X | X | X | - | - |
The PutcStdOut macro allows the following operands:
| Name | byteVar | Num const | [word Var] | [dword Var] | String Const | 8-bit Register | |
|---|---|---|---|---|---|---|---|
| PutcStdOut | X | - | - | - | - | - | - |
mov al, 'A' putcStdOut ;Print 'A' to the DOS standard output device.
PutcBIOS prints its character using the INT 10h, AH=0Eh call. DOS usually makes this same call when printing data to the standard output (assuming no redirection), however, DOS calls the BIOS routine directly, it does not go through the PutcBIOS routine. PutcBIOS just happens to make the same call that DOS does in order to print a character to the video display.
| Name | Plain | CS | TOS | Stk | X | CSi |
|---|---|---|---|---|---|---|
| PutcStdOut | X | X | X | X | - | - |
The PutcBIOS macro allows the following operands:
| Name | byteVar | Num const | [word Var] | [dword Var] | String Const | 8-bit Register | |
|---|---|---|---|---|---|---|---|
| PutcBIOS | X | - | - | - | - | - | - |
mov al, 'A' putcBIOS ;Print 'A' to the Video Display using BIOS.
| Name | Plain | CS | TOS | Stk | X | CSi |
|---|---|---|---|---|---|---|
| Puts | X | X | - | X | - | - |
| - | - | - | - | - | X |
The Puts macro allows the following operands:
| Name | byteVar | Num const | [word Var] | [dword Var] | String Const | 8-bit Register | |
|---|---|---|---|---|---|---|---|
| Puts | X | X | - | X | X | X | - |
StringToPrint byte "Print this string",nl,0
StrPointer dword StringToPrint
.
.
.
; Directly print "StringToPrint" by loading the address of this
; zero terminated string into ES:DI
lesi StringToPrint
puts
.
.
.
; Print the string that "StrPointer" points at ("StringtoPrint" in
; this case).
les di, StrPointer
puts
.
.
.
; PutsStk expects the far address of a zero-terminated string
; on the stack. The following code pushes the address of
; StringToPrint onto the stack and calls PutsStk:
push StrPointer
PutsStk
.
.
.
push seg StringToPrint
push offset StringToPrint
PutsStk
.
.
.
; PutsCS expects the far address of a zero-terminated string
; immediately following the call:
PutsStk
dword StringToPrint
.
.
.
; The Print routine lets you print string literals (constants) rather than
; a string variable.
print
byte "String to print",nl,0
The Puts and Print macros support an alternate syntax that allows operands on the same line with the Puts and Print macros. If you include an operand for the Print statement, the Print macro assumes you're supplying a sequence of bytes and emits a "byte" directive with the operand you specify. Print automatically supplies a zero terminating byte when you use Print in this manner. Do not include a zero terminating byte as part of the operand; furthermore, you cannot follow this particular call to Print with additional string data using byte directives.
Examples:
print "String to print"
.
.
.
print "This string takes two lines",nl,"to print",nl
The Puts macro lets you specify several different types of arguments. If you supply a string literal or a constant, Puts emits a call to the Print routine. If you do this, Puts behaves exactly like the call to Print above. Like Print, you can supply multiple parameters. Puts automatically supplies the zero-terminating byte, you must not explicitly supply this yourself.
Examples:
puts "String to print"
.
.
.
puts "This string takes two lines",nl,"to print",nl
If you supply the name of a byte variable as the Puts operand, the Puts macro will assume that this is the name of a string variable you wish to print. Puts will push the address of this string literal onto the stack and emit a call to the PutsStk routine.
Example:
MyString byte "String to print",nl,0
.
.
.
puts MyString
; Note: the above is equivalent to the following sequence.
PutsCS
dword MyString
If you supply the name of a word variable as the Puts operand, the Puts macro will assume that this variable contains a near address of a zero terminated string to print. Puts will assume that the string is in the data segment at the specified offset. Puts will push the current DS value following by the word variable's value onto the stack and then call the PutsStk routine.
Example:
; Note: this code assumes that the following two statements are in the
; current data segment.
MyString byte "String to print",nl,0
NearPtr word MyString
.
.
.
puts [NearPtr]
; Note: the above is equivalent to the following sequence.
push DS
push NearPtr
PutsStk
If you supply the name of a double word variable as the Puts operand, Puts will assume this is a far pointer to a zero terminated string. Puts will push that pointer onto the stack and call the PutsStk code.
Example:
MyString byte "String to print",nl,0
FarPtr dword MyString
.
.
.
puts [FarPtr]
; Note: the above is equivalent to the following sequence.
pushd FarPtr
PutsStk
printf
byte "format string",0
dword operand1, operand2, ..., operandn
The format string is comparable to the one provided in the "C" programming language. For most characters, Printf simply prints the characters in the format string up to the terminating zero byte. The two exceptions are characters prefixed by a backslash ("\") and characters prefixed by a percent sign ("%"). Like C's printf, stdlib's printf uses the backslash as an escape character and the percent sign as a lead-in to a format string.
Printf uses the escape character ("\") to print special characters in a fashion similar to, but not identical to C's printf. Stdlib's Printf routine supports the following special characters:
* r Print a carriage return (but no line feed)
* n Print a new line character (carriage return/line feed).
* b Print a backspace character.
* t Print a tab character.
* l Print a line feed character (but no carriage return).
* f Print a form feed character.
* \ Print the backslash character.
* % Print the percent sign character.
* 0xhh Print ASCII code hh, represented by two hex digits.
C users should note a couple of differences between stdlib's escape sequences and C's. First, use "\%" to print a percent sign within a format string, not "%%". C doesn't allow the use of "\%" because the C compiler processes "\%" at compile time (leaving a single "%" in the object code) whereas printf processes the format string at run-time. It would see a single "%" and treat it as a format lead-in character. Stdlib's Printf, on the other hand, processes both the "\" and "%" at run-time, therefore it can distinguish "\%".
Strings of the form "\0xhh" must contain exactly two hex digits. The current Printf routine isn't robust enough to handle sequences of the form "\0xh" which contain only a single hex digit. Keep this in mind if you find Printf chopping off characters after you print a value.
There is absolutely no reason to use any escape character sequences except "\0x00". Printf grabs all characters following the call to Printf up to the terminating zero byte (which is why you'd need to use "\0x00" if you want to print the null character, Printf will not print such values). Stdlib's Printf routine doesn't care how those characters got there. In particular, you are not limited to using a single string after the printf call. The following is perfectly legal:
printf
byte "This is a string",13,10
byte "This is on a new line",13,10
byte "Print a backspace at the end of this line:"
byte 8,13,10,0
Your code will run a tiny amount faster if you avoid the use of the escape character sequences. More importantly, the escape character sequences take at least two bytes. You can encode most of them as a single byte by simply embedding the ASCII code for that byte directly into the code stream. Don't forget, you cannot embed a zero byte into the code stream. A zero byte terminates the format string. Instead, use the "\0x00" escape sequence.
Format sequences always between with "%". For each format sequence you must provide a far pointer to the associated data immediately following the format string, e.g.,
printf
byte "%i %i",0
dword i,j
Format sequences take the general form "%s\cn^f" where:
The "s", "\c", "n", and "^" items are optional, the "%" and "f" items must be present. Furthermore, the order of these items in the format item is very important. The "\c" entry, for example, cannot precede the "s" entry. Likewise, the "^" character, if present, must follow everything except the "f" character(s).
The characters i, d, x, h, u, c, s, ld, li, lx, and lu control the conversion from a binary format to ASCII text. These format characters specify the type and size of the corresponding memory variable.
The i and d format characters are synonyms; they tell Printf to print the corresponding value as a 16-bit signed decimal integer. If the corresponding value is negative, Printf will print apreceding minus sign. Printf will not print any leading zeros for these values:
IntVal sword -12345
IntVal2 sword 54321
.
.
.
printf
byte "IntVal = %d, IntVal2 = %i",nl,0
dword IntVal, IntVal2
If you specify u, Printf prints the value as a 16-bit unsigned decimal integer. Printf will not print any leading zeros for the number (although see the description of the pad character below).
UnsVal word 12345
UnsVal2 word 54321
.
.
.
printf
byte "UnsVal = %u, UnsVal2 = %u",nl,0
dword UnsVal, UnsVal2
The x and h format characters instruct Printf to print the specified value as a 16-bit or 8-bit hexadecimal value (respectively). Printf always prints 16-bit values using exactly four hexadecimal digits with leading zeros, if necessary. Likewise, Printf always prints eight-bit hexadecimal value using exactly two characters. Printf does not print a leading minus sign if the H.O. bit of the corresponding value is set.
HexVal word 0ABCDh
HexVal2 byte 0FFh
.
.
.
printf
byte "HexVal = %x, UnsVal2 = %h",nl,0
dword HexVal, HexVal2
Using the "c" format character tells Printf to print the value as a single character. Printf prints the character corresponding to the ASCII code of the corresponding parameter value.
CharVal byte 'A'
.
.
.
printf
byte "ASCII code of '%c' is 0x%h",nl,0
dword CharVal, CharVal
The "s" format option tells printf that you're supplying the address of a zero-terminated character string. Printf prints that string up to the zero terminating byte.
String byte "Hello World",0
.
.
.
printf
byte "String = '%s'",nl,0
dword String
The ld, li, lx, and lu entries are long (32-bit) versions of d/i, x, and u. The corresponding address points at a 32-bit value that Printf will format and print to the standard output. Note that the lx option (hexadecimal) always prints eight hex characters including any leading zeros.
L sdword -123456789
UL dword 123456789
HL dword 0ABCDEFh
.
.
.
printf
byte "L=%ld, L=%li, UL=%lu, HL=%lx",nl,0
dword L, L, UL, HL
The following code sequence provides one more example of these format items:
i sword -25
u word 20
HexC byte 2ah
C byte 'A'
S byte "Hello World", nl, 0
l dword 123456789
.
.
.
printf
byte "I= %i, U= %u, HexC= %h, HexI= %x, C= %c, "
byte "S= %s",nl
byte "L= %ld",nl,0
dword i,u,c,i,c,s,l
The number of far addresses (specified by operands to the "dword" pseudo-opcode) must match the number of "%" format items in the format string. For each "%" format specifier appearing in the format string, Printf fetches a single far address immediately after the format string. When Printf encounters the zero terminating byte in the format string, it uses the address after the last dword address it has fetched as the return address. If the number of items do not match, the return address for Printf will be incorrect and the program will probably hang or otherwise malfunction. Likewise (as for the print routine), the format string must end with a zero byte.
When used in the format above, printf always prints the values using the minimum number of print positions for each operand. If you want to specify a minimum field width, you can do so using the "n" format option. A format item of the format "%10d" prints a decimal integer using at least ten print positions. Likewise, "%16s" prints a string using at least 16 print positions. If the value to print requires more than the specified number of print positions, Printf will use however many are necessary. If the value to print requires fewer, Printf will always print the specified number, padding the value with blanks.
printf
byte "I= %i, U= %u, HexC= %h, HexI= %x, C= %c, "
byte "S= %s",nl
byte "L= %ld",nl,0
dword i,u,c,i,c,s,l
Printf will print the value right justified in the print field (regardless of the data's type). Note that this is the "intuitive" operation for numeric values, but it is counter-intuitive for strings and characters. If you want to print the value left justified in its field, use the "-" format character as a prefix to the field width, e.g.,
string byte "0123456789",0
.
.
.
printf
byte "%17s",nl
byte "%-17s",0
dword string, string
This displays:
_ _ _ _ _ _ _ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 _ _ _ _ _ _ _In this example, printf prints the string using a 17 character long field with the string left and right justified in the output field. By default, Printf pads the output field with spaces if the value requires fewer print positions than specified by the format item. The "\c" format item allows you to change the padding character. For example, to print a value, right justified, using "*" as the padding character you would use the format item "%\*10d". To print it left justified you would use the format item "%-\*10d". Note that the "-" must precede the "\*"; the operands must appear in this order.
string byte "0123456789",0
.
.
.
printf
byte "%\#17s",nl
byte "%-\@17s",0
dword string, string
This displays:
# # # # # # # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 @ @ @ @ @ @ @
Normally, the address(es) following the Printf format string must be far pointers to the actual data to print. On occasion, especially when allocating storage on the heap (using malloc), you may not know (at assembly time) the address of the object you want to print. You may have only a pointer to the data you want to print. The "^" format option tells Printf that the far pointer following the format string is the address of a pointer to the data rather than the address of the data itself. This option lets you access the data indirectly. Consider the following example:
StrPtr dword ?
.
.
.
getsm ;Read a string from the user
mov wp StrPtr, di ;Save pointer to string malloc'd
mov wp Strptr+2, es ; on the heap in the StrPtr var.
.
.
.
printf
byte "The string you entered was %^s\n",0
dword StrPtr
Printf's parameters must all be variables whose address is known at assembly time. In addition to excluding direct access to values allocated on the heap, Printf cannot access a procedure's local variables that you allocate on the stack and access via the BP register. Likewise, Printf cannot directly access values in one of the 80x86's registers. These limitations may be removed in a future version of Printf.
Unlike C, stdlib's printf routine does not support floating point output. Putting floating point into printf would increase the size of this routine a tremendous amount. Since most people don't need the floating point output facilities, it doesn't appear here. Check out PRINTFF.
The PrintfR routine is similar to Printf except you pass the pointers to the format string and parameter list in the FS:SI and ES:DI register pairs, respectively. This provides you with the ability to construct the format string (and, possibly, the parameter list) at run-time.
The PrintfStk routine also lets you pass the addresses of the format string and dword parameter list to it; however, you pass the pointers to the format string and parameter list on the stack (push the address of the parameter list first, the format string second).
printf
byte "format string",0
dword operand1, operand2, ..., operandn
The primary point to keep in mind when using Printf is that the number of (dword) parameters following the format string must exactly match the number of "%" format items appearing in the format string. Failure to do so will produce undefined results, often resulting in a crashed program.
Examples of various Printf features:
IntVar sword -1234
UnsignedVar word 556
CharVar byte 'A'
StrVar byte "String",0
LongUnsigned dword 1234567
LongSigned sdword -123456
StrPtr dword StrVar
IntPtr dword IntVar
.
.
.
; Simple examples of Printf
printf
byte "IntVar = %d\n"
byte "UnsignedVar = %u\n"
byte "CharVar = '%c'\n"
byte "StrVar = '%s'\n"
byte "LongUnsigned = %lu\n"
byte "LongSigned = %ld\n"
byte "Hex(IntVar) = %x\n"
byte "ASCII code of '%c' is %h\n"
byte nl, 0
dword IntVar, UnsignedVar, CharVar, StrVar
dword LongUnsigned, LongSigned, IntVar
dword CharVar, CharVar
.
.
.
; Examples involving field widths:
printf
byte "IntVar = %8d\n"
byte "UnsignedVar = %8u\n"
byte "CharVar = %8c\n"
byte "LongUnsigned = %8lu\n"
byte "LongSigned = %8ld\n"
byte "Hex(IntVar) = %8x\n"
byte "ASCII ('%c') = %8h\n"
byte nl, 0
dword IntVar, UnsignedVar, CharVar
dword LongUnsigned, LongSigned, IntVar
dword CharVar, CharVar
.
.
.
; The following example shows how to use the pad character to
; force leading zeros on decimal integers. In this example,
; Printf prints the integer value in a field width of eight positions,
; right justified, with leading zeros between the "$" symbol and the
; actual start of the number.
printf
byte "Pay exactly $%\08d Dollars and no cents",nl,0
dword IntVar
.
.
.
; Numeric values typically look best when right justified in a print
; field. String and character values, however, generally look best when
; left justified in a print field. The following example uses left
; justification to print character and string fields:
printf
byte "The string is %-10s, the character is %-4c.",nl,0
dword StrVar, CharVar
.
.
.
; Sometimes you may only know the address of a pointer variable that
; contains the address of an object, you might not know the actual
; address of the object until run-time. The following example demonstrates
; how to use the indirection operator, "^", to print the value referenced
; by a pointer variable.
printf
byte "String = '%-8^s'",nl
byte "Integer= %8^s",nl,0
dword StrPtr, IntPtr
Examples:
printf "I=%5d, J=%5d,%s", I, J, String
printf "Array[%d] = %d\n"
dword Index, ArrayValue
Since PRINTFF supports everything PRINTF does, you should not use both routines in the same program (just use PRINTF). Using both will not cause your program to fail, but it will make your program unnecessarily larger. You should not use PRINTFF unless you really need to print floating point values. When you use PRINTFF, it forces the linker to load in the entire floating point package, making your program considerably larger.
fpVar real4 1.23456
dpVar real8 1.234567890e4
epVar real10 -123.456e-789
.
.
.
printff
byte "Single Precision FP Value = %8.3f",nl
byte "Scientific Notation Valut = %10e",nl
byte "Double Precision FP Value = $%\015.2gf",nl
byte "Double Precision Scientific = %20ge",nl
byte "Extended Precision Value = %15.8lf",nl
byte "Also Extended Precision = %20le",nl,0
dword fpVar, fpVar
dword dpVar, dpVar
dword epVar, epVar
printff "Alternate Syntax: %8.3f", fpVar
Note that Puth, PuthCS, PuthTOS, and PuthStk, by default, use uppercase characters to display values in the range A..F. You can change this by calling the HexOutLC and HexOutUC routines. These routines do not print any prefix or suffix characters (e.g., "h" or "0x") to denote the hexadecimal radix. You must print these yourself if you need them.
| Name | Plain | CS | TOS | Stk | X | CSi |
|---|---|---|---|---|---|---|
| Puth | X | X | X | X | - | - |
The PutcBIOS macro allows the following operands:
| Name | byteVar | Num const | [word Var] | [dword Var] | String Const | 8-bit Register | |
|---|---|---|---|---|---|---|---|
| Puth | X | X | X | X | X | - | X |
HexValue byte 0ABh
wHex word HexValue
dHex dword HexValue
.
.
.
mov al, HexValue
Puth
push word ptr HexValue
PuthTOS
pshadrs HexValue
PuthStk
PuthCS
dword HexValue
puth ;Prints value in AL
;-------------------------------------------
; An eight-bit register is a legal operand:
puth bl
; Equivalent to:
push bx
PuthTOS
puth bh
; Equivalent to:
xchg bl, bh
push bx
xchg bl, bh
PuthTOS
;------------------------------------------
; An eight-bit constant is a legal operand:
Puth 123
; Equivalent to:
push 123
PuthTOS
;-------------------------------------------
; An eight-bit variable is a legal operand:
Puth HexValue
;Equivalent to:
PuthCS
dword HexValue
;-----------------------------------------------
; An 16-bit pointer variable is a legal operand:
Puth [wHex]
; Equivalent to:
push ds
push wHex
puthStk
;-----------------------------------------------
; A 32-bit pointer variable is a legal operand:
Puth [dHex]
; Equivalent to:
pushd dHex
puthStk
Note that Putw, PutwCS, PutwTOS, and PutwStk, by default, use uppercase characters to display values in the range A..F. You can change this by calling the HexOutLC and HexOutUC routines. They do not print any prefix or suffix characters (e.g., "h" or "0x") to denote the hexadecimal radix. You must print these yourself if you need them.
| Name | Plain | CS | TOS | Stk | X | CSi |
|---|---|---|---|---|---|---|
| Putw | X | X | X | X | - | - |
The PutcBIOS macro allows the following operands:
| Name | word Var | Num const | [word Var] | [dword Var] | String Const | 16-bit Register | |
|---|---|---|---|---|---|---|---|
| Putw | X | X | X | X | X | - | X |
HexValue word 0ABCDh
wHex word HexValue
dHex dword HexValue
.
.
.
mov ax, HexValue
Putw
push HexValue
PutwTOS
pshadrs HexValue
PutwStk
PutwCS
dword HexValue
putw ;Prints value in AX
;-------------------------------------------
; A 16-bit register is a legal operand:
putw bx
; Equivalent to:
push bx
PutwTOS
;------------------------------------------
; A 16-bit constant is a legal operand:
Putw 1234
; Equivalent to:
push 1234
PutwTOS
;-------------------------------------------
; A 16-bit variable is a legal operand:
Putw HexValue
;Equivalent to:
PutwCS
dword HexValue
;-----------------------------------------------
; A 16-bit pointer variable is a legal operand:
Puth [wHex]
; Equivalent to:
push ds
push wHex
putwStk
;-----------------------------------------------
; A 32-bit pointer variable is a legal operand:
Putw [dHex]
; Equivalent to:
pushd dHex
putwStk
The minimum field width value specifies the number of print positions to use when outputting a value. If the number to print requires fewer than this specified number of print positions to display, the PutiSizexxxx routines will pad the number with spaces; these two routines will print the number right justified in the specified field width (by adding an appropriate number of spaces before the number). If the number requires more print positions than specified, PutiSizexxxx will ignore the minimum field width specification and print the number using however many positions are necessary. Don't forget than negative numbers use one print position for the leading minus sign.
| Name | Plain | CS | TOS | Stk | X | CSi |
|---|---|---|---|---|---|---|
| Puti | X | X | X | X | - | - |
| PutiSize | X | X | X | X | - | - |
The Puti and PutiSize macros allow the following operands:
| Name | word Var | Num const | [word Var] | [dword Var] | String Const | 16-bit Register | |
|---|---|---|---|---|---|---|---|
| Puti | X | X | X | X | X | - | X |
| PutiSize | X | X | X | X | X | - | - |
DecValue word 0ABCDh
wDec word DecValue
dDec dword DecValue
.
.
.
mov ax, DecValue
Puti
push DecValue
PutiTOS
pshadrs DecValue
PutiStk
PutiCS
dword DecValue
puti ;Prints value in AX
;-------------------------------------------
; A 16-bit register is a legal operand:
puti bx
; Equivalent to:
push bx
PutiTOS
;------------------------------------------
; A 16-bit constant is a legal operand:
Puti 1234
; Equivalent to:
push 1234
PutiTOS
;-------------------------------------------
; A 16-bit variable is a legal operand:
Puti HexValue
;Equivalent to:
PutiCS
dword HexValue
;-----------------------------------------------
; A 16-bit pointer variable is a legal operand:
Puti [wHex]
; Equivalent to:
push ds
push wHex
putiStk
;-----------------------------------------------
; A 32-bit pointer variable is a legal operand:
Puti [dHex]
; Equivalent to:
pushd dHex
putiStk
;-----------------------------------------------
;-----------------------------------------------
The minimum field width value specifies the number of print positions to use when outputting a value. If the number to print requires fewer than this specified number of print positions to display, the PutuSize and PutuSizeStk routines will pad the number with spaces; these two routines will print the number right justified in the specified field width (by adding an appropriate number of spaces before the number). If the number requires more print positions than specified, PutuSize and PutuSizeStk will ignore the minimum field width specification and print the number using however many positions are necessary.
UnsValue sword 12345
.
.
.
mov ax, UnsValue
Putu
push UnsValue
PutuStk
mov ax, UnsValue
mov cx, 10 ;Minimum print field width = 10.
PutuSize
push UnsValue
push 10 ;Field width is ten print positions
PutuSizeStk
putu ax
putu bx
putu cx
putu dx
putu si
putu di
putu bp
putu Mem16
If you supply two operands to Putu, the macro will push these two operands onto the stack and call PutuSizeStk (the first operand is the value to print, the second operand is the minimum field width value):
putu ax, cx
putu mem16, 10
putu bp, ax
putu mem16, mem16
putu mem16, cx
The minimum field width value specifies the number of print positions to use when outputting a value. If the number to print requires fewer than this specified number of print positions to display, the PutlSize and PutlSizeStk routines will pad the number with spaces; these two routines will print the number right justified in the specified field width (by adding an appropriate number of spaces before the number). If the number requires more print positions than specified, PutlSize and PutlSizeStk will ignore the minimum field width specification and print the number using however many positions are necessary. Don't forget than negative numbers use one print position for the leading minus sign.
LongValue sdword -12345
.
.
.
mov eax, LongIntValue
Putl
push LongValue
PutlStk
mov ex, LongValue
mov cx, 10 ;Minimum print field width = 10.
PutlSize
push LongValue
push 10 ;Field width is ten print positions
PutlSizeStk
putl eax
putl ebx
putl ecx
putl edx
putl esi
putl edi
putl ebp
putl Mem32
If you supply two operands to Putl, the macro will push these two operands onto the stack and call PutlSizeStk (the first operand is the value to print and must be a 32-bit value, the second operand is the minimum field width value which must be 16-bits):
putl eax, cx
putl mem32, 10
putl ebp, ax
putl mem32, mem16
putl mem32, cx
The minimum field width value specifies the number of print positions to use when outputting a value. If the number to print requires fewer than this specified number of print positions to display, the PutulSize and PutulSizeStk routines will pad the number with spaces; these two routines will print the number right justified in the specified field width (by adding an appropriate number of spaces before the number). If the number requires more print positions than specified, PutulSize and PutulSizeStk will ignore the minimum field width specification and print the number using however many positions are necessary.
UnsValue32 dword 123456789
.
.
.
mov ax, UnsValue32
Putul
push UnsValue32
PutulStk
mov eax, UnsValue32
mov cx, 10 ;Minimum print field width = 10.
PutulSize
push UnsValue32
push 10 ;Field width is ten print positions
PutulSizeStk
putul eax
putul ebx
putul ecx
putul edx
putul esi
putul edi
putul ebp
putul Mem32
If you supply two operands to Putu, the macro will push these two operands onto the stack and call PutuSizeStk (the first operand is the value to print, the second operand is the minimum field width value):
putul eax, cx
putul mem32, 10
putul ebp, ax
putul mem32, mem16
putul mem32, cx
The Putf routine expects two additional parameters: the minimum field width in the AL register and the number of positions to print after the decimal point in AH:
AL (Field Width) = 17
vvvvvvvvvvvvvvvvv
-1234.567
^^^
AH (Fractional Width) = 3
Unlike the integer output routines, Putf will not attempt to print the number if it cannot display the number using the specified field width. Instead, Putf will fill the specified field width with "#" characters.
Pute requires a single field width parameter in the AL register. This field width must account for a leading sign, a decimal pointer, the "E" symbol, an exponent sign, and a two, three, or four character exponent (depending on the dynamic range of the floating point value):
-1.234567e+1000 ^^^^^^^^^^^^^^^ AL (Field width) = 15Putf and Pute print the 80-bit (real10) value on TOS. The FPU will automatically convert 32-bit (real4) and 64-bit (real8) floating point numbers to 80 bits when loading these values into the FPU. Note that with 32-bit floating point values there are only 6-1/2 digits of precision available. If you specify a field width that would cause Putf or Pute to print more than 6-1/2 digits, the extra digits are noise. Likewise, 64-bit floating point values support only 14-1/2 digits of precision and 80-bit floating point values support only 18 digits of precision. Note that converting a 32-bit or 64-bit value to 80-bits (by loading it into the FPU) does not give you additional digits of precision. If you attempt to print more than 18 digits, the Putf and Pute functions will print zeros for the additional digit positions. This does not imply that there would actually be zeros in those positions in a correct computation.
The current versions of Putf and Pute limit the field width to 30 characters. If you specify a field width larger than this, these routines will clip the value to 30 positions.
FPValue real10 9.87654e+3
.
.
.
fld FPValue
mov al, 12
mov ah, 2
Putf
fld FPValue
mov al, 12
pute
Typically, you would use the GetOutAdrs function to obtain and save the current output function, then you would change this pointer using the SetOutAdrs call. Later, you would restore the original value using a second call to SetOutAdrs.
Note: to redirect the output pointer to the DOS standard output device, load the address of the "$PutcStdOut" routine into ES:DI. To redirect the output to the standard error device (the BIOS output routines), load ES:DI with the address of the "PutcBIOS" subroutine.
The character handler routine should expect an ASCII character code in the AL register. It most output this character to the appropriate device. On return, it must preserve all registers.
wp textequ <word ptr>
AdrsSave dword ?
.
.
.
; Preserve the address of the current output routine.
GetOutAdrs
mov wp AdrsSave, di
mov wp AdrsSave+2, es
; Load the address of "MyCharHandler" into the Putc pointer.
lesi MyCharHandler
SetOutAdrs
; Print a string through "MyCharHandler".
print
byte "DOUBLE",cr,lf,0
; Restore the Putc address to its original value.
les di, AdrsSave
SetOutAdrs
.
.
.
; Redirect the output to the standard error output device (BIOS):
lesi $PutcBIOS
SetOutAdrs
print
byte "This text goes to the video display"
byte nl, 0
.
.
.
; Redirect the output back to the DOS standard output device.
lesi $PutcStdOut
SetOutAdrs
.
.
.
; MyCharHandler- Prints every character sent to it twice through
; the DOS standard output device.
MyCharHandler proc far
putcStdout
putcStdOut
ret
MyCharHandler endp
These two routines provide a convenient way to temporarily switch the Putc pointer to some special handler (e.g., file output) and then restore the original output vector without manually saving the original pointer (vector) first.
The stdlib's internal address stack is large enough to hold 16 pointers. It would be hard to imagine any (error-free) program needing to stack up this many Putc pointers, so there should never be a problem with stack overflow under normal circumstances.
wp textequ <word ptr>
.
.
.
; Redirect the standard output to a routine that will send each
; character to a file rather than to the display.
lesi MyFileOut
PushOutAdrs
.
.
.
printf
byte "This data goes to a file",nl
byte "I = %4d, J = %4d",nl
byte 0
dword I,J
.
.
.
; Stop redirecting output to a file and resume sending it to the
; DOS standard output device:
PopOutAdrs
.
.
.
MyFileOut proc far
<Code that sends the ASCII character in >
<AL to a file. >
MyFileOut endp
ResetStdOut