home *** CD-ROM | disk | FTP | other *** search
- Page 58,132
- Title PRINTF.ASM Generic Printf Routine
- ;******************************************************************************
- ;
- ; Name: PRINTF.ASM Generic Printf Routine
- ;
- ; Group: Emulator
- ;
- ; Revision: 1.00
- ;
- ; Date: January 30, 1988
- ;
- ; Author: Randy W. Spurlock
- ;
- ;******************************************************************************
- ;
- ; Module Functional Description:
- ;
- ; Printf - Prints a formatted string of arguments to
- ; the requested handle.
- ;
- ; Calling Sequence:
- ;
- ; lea bx,ds:[args] ; Get a pointer to the arguments
- ; lea si,ds:[format] ; Get a pointer to the format string
- ; call printf ; Call the printf routine
- ;
- ; The conversion characters are as follows:
- ;
- ; %% - Print percent sign to handle
- ; %c - Output the next argument as a character
- ; %s - Output the next argument as a string
- ; %x - Output the next argument as a hex number using abcdef
- ; %X - Output the next argument as a hex number using ABCDEF
- ; %h - Output the next argument as a hex number using abcdef
- ; %H - Output the next argument as a hex number using ABCDEF
- ; %d - Output the next argument as a decimal number (Signed)
- ; %u - Output the next argument as a decimal number (Unsigned)
- ; %o - Output the next argument as a octal number
- ; %b - Output the next argument as a binary number
- ; %f - Output the next argument as a fractional number (Signed)
- ;
- ; Other format specifiers may precede the conversion character:
- ;
- ; - - Left justify the field
- ; + - Set signed field
- ; n - Specify the field width/precision
- ; t - Specify short value
- ; l - Specify long value
- ; # - Specify far argument pointer
- ; * - Variable precision/width value (From argument list)
- ;
- ; All arguments must be pointers to the actual values.
- ;
- ; The following escape sequences are also handled:
- ;
- ; \\ - Backslash
- ; \n - Newline
- ; \t - Horizontal Tab
- ; \v - Vertical Tab
- ; \b - Backspace
- ; \r - Carriage Return
- ; \f - Form Feed
- ; \ddd - ASCII Character (Octal Notation)
- ; \xdd - ASCII Character (Hexadecimal Notation)
- ;
- ;******************************************************************************
- ;
- ; Changes:
- ;
- ; DATE REVISION DESCRIPTION
- ; -------- -------- -------------------------------------------------------
- ; 1/30/88 1.00 Original
- ;
- ;******************************************************************************
- Page
- ;
- ; Public Declarations
- ;
- Public Printf ; Generic Printf routine
- ;
- ; External Declarations
- ;
- Extrn Write_TTY:Near ; Write TTY routine (TTY)
- ;
- ; Define the Local Equates
- ;
- FORMAT_CHAR Equ "%" ; Format specification character
- ESCAPE_CHAR Equ "\" ; Escape sequence character
- HEX Equ 16 ; Base 16 - Hexadecimal
- DECIMAL Equ 10 ; Base 10 - Decimal
- OCTAL Equ 8 ; Base 8 - Octal
- BINARY Equ 2 ; Base 2 - Binary
- FORMAT_LENGTH Equ 5 ; Maximum format number width
- ESCAPE_LENGTH Equ 3 ; Escape sequence number width (Decimal)
- HEX_LENGTH Equ 2 ; Escape sequence number width (Hex)
- MAX_WORD Equ 0FFFFh ; Maximum 16-bit count value
- MAX_BYTE Equ 0FFh ; Maximum 8-bit count value
- SPACE_PAD Equ " " ; Space pad character
- ZERO_PAD Equ "0" ; Zero pad character
- LEFT_JUST Equ 8000h ; Left justification flag
- SHORT_SPEC Equ 4000h ; Short specification flag
- LONG_SPEC Equ 2000h ; Long specification flag
- UPPER_CASE Equ 1000h ; Upper case hexadecimal flag
- SIGNED_CONV Equ 0800h ; Signed conversion flag
- SIGNED_TYPE Equ 0400h ; Signed type flag
- SIGNED_VAL Equ 0200h ; Signed value flag
- PRE_PAD Equ 0100h ; Pre-pad sign character flag
- FAR_SPEC Equ 0080h ; Far argument specification flag
- OVER_FLOW Equ 0040h ; Field overflow flag
- FRACTIONAL Equ 0020h ; Fractional integer flag
- VAR_WIDTH Equ 0010h ; Variable width flag
- VAR_PRE Equ 0008h ; Variable precision flag
- PAD_CHAR Equ 0004h ; Pad character flag (0=Space, 1=Zero)
- SIGNED Equ 8000h ; Sign flag test mask
- WRITE_HANDLE Equ 40h ; MS-DOS write handle function code
- DECIMAL_ADJUST Equ 30h ; ASCII decimal to binary adjust value
- HEX_ADJUST Equ 07h ; ASCII hex to binary adjust value
- UPPER_MASK Equ 0DFh ; Lower to upper case mask value
- DOS Equ 21h ; MS-DOS interrupt call number
- FAR_SIZE Equ 4h ; Far argument pointer size (4 bytes)
- NEAR_SIZE Equ 2h ; Near argument pointer size (2 bytes)
- LONG_SIZE Equ 4h ; Long numeric argument size (4 bytes)
- SHORT_SIZE Equ 2h ; Short numeric argument size (2 bytes)
- BUFF_SIZE Equ 64 ; Numeric build buffer size
- DIGIT_MAX Equ 39h ; Maximum ASCII digit value
- ;
- ; Define any include files needed
- ;
- Include Macros.inc ; Include the macro definitions
- Include Equates.inc ; Include the equate definitions
- .286c ; Include 80286 instructions
- ;
- ; Define the emulator code segment
- ;
- Emulate Segment Word Public 'EMULATE' ; Emulator code segment
- Assume cs:Emulate, ds:Nothing, es:Nothing
- Subttl Printf Generic Printf Routine
- Page +
- ;******************************************************************************
- ;
- ; Routine Functional Description
- ;
- ; Printf(Format_String, Arguments, Handle)
- ;
- ; Save the required registers
- ; While next character from Format_String <> 0
- ; If next character is a format character (percent sign)
- ; Get the next character from Format_String
- ; If a format specifier (+,-,n,l,#,*)
- ; Set the appropriate specifier flag
- ; Else not a format specifier
- ; If a conversion character (c,s,x,d,o,b)
- ; Print argument using conversion
- ; Increment argument pointer
- ; Else not a conversion character
- ; Ignore this format
- ; Endif
- ; Endif
- ; Else the character is not a format character
- ; If character is a escape character (backslash)
- ; Get next character from Format_String
- ; If a valid escape sequence
- ; Handle the escape sequence
- ; Else an invalid escape sequence
- ; Print the character to Handle
- ; Endif
- ; Else the character is not an escape character
- ; Print the character to Handle
- ; Endif
- ; Endif
- ; Endwhile
- ; Restore the required registers
- ; Return to the caller
- ;
- ; Registers on Entry:
- ;
- ; DS:BX = Pointer to Argument List
- ; DS:SI = Pointer to Format String
- ;
- ; Registers on Exit:
- ;
- ; Direction flag is cleared (Move forward)
- ;
- ;******************************************************************************
- Printf Proc Near ; Generic printf procedure
- Save ax,bx,cx,dx,si,di,bp,ds,es
- mov ah,al ; Save print handle in AH
- cld ; Clear the direction flag (Forward)
- Get_Char:
- call Clear_Flags ; Clear all of the specifier flags
- lodsb ; Get a character from format string
- cmp al,FORMAT_CHAR ; Check for a format character (%)
- je Do_Format ; Jump if a format character
- cmp al,ESCAPE_CHAR ; Check for an escape character (\)
- je Do_Escape ; Jump if a escape character
- or al,al ; Check for end of the format string
- jnz Normal_Output ; Jump if a normal character to output
- jmp Printf_Exit ; Jump if end of the format string
- Do_Escape:
- lodsb ; Get next character from format string
- push cs ; Put copy of CS onto the stack
- pop es ; Put copy of current CS into ES
- lea di,cs:[Escape_Table] ; Setup the escape character table
- mov cx,ESCAPE_SIZE ; Get the escape character table size
- repne scasb ; Scan the escape table for a match
- je Go_Escape ; Jump if an there was a table match
- mov ch,OCTAL ; Set the current base value to OCTAL
- mov cl,ESCAPE_LENGTH ; Set the escape maximum number count
- call Check_Digit ; Check for numeric digit (Character)
- jnc Get_Code ; Jump if an octal number sequence
- jmp Normal_Output ; Jump if an unknown escape character
- Get_Code:
- dec si ; Backup to the start of the number
- push dx ; Save the field width/precision
- call Get_Number ; Call routine to get the number
- mov al,dl ; Put the character number into AL
- pop dx ; Restore the field width/precision
- jmp Normal_Output ; Go get next format string character
- Go_Escape:
- mov di,ESCAPE_SIZE ; Get the escape table size
- sub di,cx ; Compute the matching entry number
- dec di ; Convert number to zero based
- shl di,1 ; Make number into jump table index
- call cs:[di+Escape_Jump] ; Call the correct routine
- jmp Get_Char ; Go get the next character
- Normal_Output:
- call Write_TTY ; Not a special character, output it
- jmp Get_Char ; Go get next format string character
- Do_Convert:
- lea di,cs:[Convert_Table] ; Setup the convert character table
- mov cx,CONVERT_SIZE ; Get the convert character table size
- repne scasb ; Scan the convert table for a match
- jne Get_Char ; Jump if an unknown convert character
- mov di,CONVERT_SIZE ; Get the convert table size
- sub di,cx ; Compute the matching entry number
- dec di ; Convert number to zero based
- shl di,1 ; Make number into jump table index
- call cs:[di+Convert_Jump] ; Call the correct routine
- jmp Get_Char ; Go get the next character
- Do_Format:
- lodsb ; Get next character from format string
- push cs ; Put copy of CS onto the stack
- pop es ; Put copy of current CS into ES
- lea di,cs:[Format_Table] ; Setup the format character table
- mov cx,FORMAT_SIZE ; Get the format character table size
- repne scasb ; Scan the format table for a match
- je Go_Format ; Jump if an there was a table match
- mov ch,DECIMAL ; Set the current base value to DECIMAL
- mov cl,FORMAT_LENGTH ; Set the format maximum number count
- cmp al,POINT ; Check for a decimal point
- jne Chk_Var ; Jump if no decimal point found
- dec si ; Correct pointer for no width value
- xor dh,dh ; Setup a width value of zero
- jmp Chk_Pre ; Go check for a precision value
- Chk_Var:
- cmp al,ASTERISK ; Check for variable width field
- jne Do_Width ; Jump if not a variable width field
- or bp,VAR_WIDTH ; Set variable width flag bit
- mov dh,MAX_BYTE ; Set width value as already set
- jmp Chk_Pre ; Go check for a precision value
- Do_Width:
- call Check_Digit ; Check for numeric digit (Field width)
- jc Do_Convert ; Jump if an unknown format character
- dec si ; Backup to the start of the number
- or al,al ; Check for a leading zero
- jnz Get_Width ; Jump if first digit not a zero
- or bp,PAD_CHAR ; First digit zero, use zero pad
- or bp,PRE_PAD ; Set pre-pad sign character flag
- Get_Width:
- call Get_Number ; Call routine to get the field width
- mov dh,dl ; Save the field width in DH
- cmp Byte Ptr ds:[si],ASTERISK
- jne Chk_Pre ; Jump if not a variable width field
- inc si ; Increment past variable character
- or bp,VAR_WIDTH ; Set variable width flag bit
- mov dh,MAX_BYTE ; Set width value as already set
- Chk_Pre:
- xor dl,dl ; Setup a precision of zero
- cmp Byte Ptr ds:[si],POINT ; Check for a decimal point
- jne Do_Format ; Jump if no precision given
- or bp,FRACTIONAL ; Set the fractional conversion flag
- dec dl ; Set precision as already set
- inc si ; Increment past the decimal point
- cmp Byte Ptr ds:[si],ASTERISK
- jne Get_Pre ; Jump if not a variable precision
- inc si ; Increment past variable character
- or bp,VAR_PRE ; Set variable precision flag bit
- jmp Do_Format ; Go check for more format characters
- Get_Pre:
- call Get_Number ; Call routine to get the precision
- jmp Do_Format ; Go check for more format characters
- Go_Format:
- mov di,FORMAT_SIZE ; Get the format table size
- sub di,cx ; Compute the matching entry number
- dec di ; Convert number to zero based
- shl di,1 ; Make number into jump table index
- call cs:[di+Format_Jump] ; Call the correct routine
- jmp Do_Format ; Go check for more format characters
- Printf_Exit:
- Restore ax,bx,cx,dx,si,di,bp,ds,es
- ret ; Return to the caller
- Printf Endp ; End of the Printf procedure
- Subttl Format Specifier Routines
- Page +
- ;******************************************************************************
- ;
- ; Format Specifier Routines
- ;
- ;
- ; These routines handle the following format specifiers:
- ;
- ;
- ; Specifier Action Taken
- ; --------- ------------
- ;
- ; - The following field will be left justified.
- ;
- ; + The following field will be have a sign (+/-)
- ; if it is a signed type field (d).
- ;
- ; t The following field is a short value.
- ;
- ; T The following field is a short value.
- ;
- ; l The following field is a long value.
- ;
- ; L The following field is a long value.
- ;
- ; # The following argument has a far address.
- ;
- ;
- ; These routines simply set or reset flags which are
- ; used later during actual conversion to perform the special
- ; formatting options.
- ;
- ;******************************************************************************
- Subttl Left_Justify Left Justify Specifier Routine
- Page +
- ;******************************************************************************
- ;
- ; Routine Functional Description
- ;
- ; Left_Justify()
- ;
- ; Set the left justification flag
- ; Return to the caller
- ;
- ; Registers on Entry:
- ;
- ; None
- ;
- ; Registers on Exit:
- ;
- ; BP - Left justification flag set
- ;
- ;******************************************************************************
- Left_Justify Proc Near ; Left justify procedure
- or bp,LEFT_JUST ; Set the left justification flag
- ret ; Return to the caller
- Left_Justify Endp ; End of the Left_Justify procedure
- Subttl Set_Signed Set Signed Conversion Specifier Routine
- Page +
- ;******************************************************************************
- ;
- ; Routine Functional Description
- ;
- ; Set_Signed()
- ;
- ; Set the signed flag
- ; If the field width is non-zero
- ; Set the pre-pad sign flag
- ; Endif
- ; Return to the caller
- ;
- ; Registers on Entry:
- ;
- ; DH - Field width (Not given if zero)
- ;
- ; Registers on Exit:
- ;
- ; BP - Signed flag set
- ;
- ;******************************************************************************
- Set_Signed Proc Near ; Set signed procedure
- or bp,SIGNED_CONV ; Set the signed conversion flag
- or dh,dh ; Check the field width
- jz Sign_Ret ; Jump if field width not set
- or bp,PRE_PAD ; Set the pre-pad sign flag
- Sign_Ret:
- ret ; Return to the caller
- Set_Signed Endp ; End of the Set_Signed procedure
- Subttl Short_Specify Set Short Value Specifier Routine
- Page +
- ;******************************************************************************
- ;
- ; Routine Functional Description
- ;
- ; Short_Specify()
- ;
- ; Set the short specification flag
- ; Return to the caller
- ;
- ; Registers on Entry:
- ;
- ; None
- ;
- ; Registers on Exit:
- ;
- ; BP - Short specification flag set
- ;
- ;******************************************************************************
- Short_Specify Proc Near ; Short specify procedure
- or bp,SHORT_SPEC ; Set the short specification flag
- ret ; Return to the caller
- Short_Specify Endp ; End of the Short_Specify procedure
- Subttl Long_Specify Set Long Value Specifier Routine
- Page +
- ;******************************************************************************
- ;
- ; Routine Functional Description
- ;
- ; Long_Specify()
- ;
- ; Set the long specification flag
- ; Return to the caller
- ;
- ; Registers on Entry:
- ;
- ; None
- ;
- ; Registers on Exit:
- ;
- ; BP - Long specification flag set
- ;
- ;******************************************************************************
- Long_Specify Proc Near ; Long specify procedure
- or bp,LONG_SPEC ; Set the long specification flag
- ret ; Return to the caller
- Long_Specify Endp ; End of the Long_Specify procedure
- Subttl Far_Specify Set Far Address Specifier Routine
- Page +
- ;******************************************************************************
- ;
- ; Routine Functional Description
- ;
- ; Far_Specify()
- ;
- ; Set the far specification flag
- ; Return to the caller
- ;
- ; Registers on Entry:
- ;
- ; None
- ;
- ; Registers on Exit:
- ;
- ; BP - Far specification flag set
- ;
- ;******************************************************************************
- Far_Specify Proc Near ; Far specify procedure
- or bp,FAR_SPEC ; Set the far specification flag
- ret ; Return to the caller
- Far_Specify Endp ; End of the Far_Specify procedure
- Subttl Escape Sequence Routines
- Page +
- ;******************************************************************************
- ;
- ; Escape Sequence Routines
- ;
- ;
- ; These routines handle the following escape sequences:
- ;
- ;
- ; Character Escape Sequence
- ; --------- ---------------
- ;
- ; n Newline is output to requested handle
- ;
- ; t Horizontal tab is output to requested handle
- ;
- ; v Vertical tab is output to requested handle
- ;
- ; b Backspace is output to requested handle
- ;
- ; r Carriage return is output to requested handle
- ;
- ; f Form feed is output to requested handle
- ;
- ; x Character is output to requested handle (Hex code)
- ;
- ;
- ; All of these routines except for the "x" escape
- ; sequence simply send the desired character(s) out to the
- ; requested handle. The "x" routine get the hexadecimal
- ; number given and outputs the corresponding character to
- ; the requested handle.
- ;
- ;******************************************************************************
- Subttl New_Line New Line Escape Sequence Routine
- Page +
- ;******************************************************************************
- ;
- ; Routine Functional Description
- ;
- ; New_Line(Handle)
- ;
- ; Output carriage return to handle
- ; Output line feed to handle
- ; Return to the caller
- ;
- ; Registers on Entry:
- ;
- ; AH - Handle
- ;
- ; Registers on Exit:
- ;
- ; AL - Destroyed
- ;
- ;******************************************************************************
- New_Line Proc Near ; Output new line procedure
- mov al,CR ; Get carriage return ASCII character
- call Write_TTY ; Output the carriage return to handle
- mov al,LF ; Get a line feed ASCII character
- call Write_TTY ; Output the line feed to handle
- ret ; Return to the caller
- New_Line Endp ; End of the New_Line procedure
- Subttl Horz_Tab Horizontal Tab Escape Sequence Routine
- Page +
- ;******************************************************************************
- ;
- ; Routine Functional Description
- ;
- ; Horz_Tab(Handle)
- ;
- ; Output horizontal tab to handle
- ; Return to the caller
- ;
- ; Registers on Entry:
- ;
- ; AH - Handle
- ;
- ; Registers on Exit:
- ;
- ; AL - Destroyed
- ;
- ;******************************************************************************
- Horz_Tab Proc Near ; Output horizontal tab procedure
- mov al,HT ; Get horizontal tab ASCII character
- call Write_TTY ; Output the horizontal tab to handle
- ret ; Return to the caller
- Horz_Tab Endp ; End of the Horz_Tab procedure
- Subttl Vert_Tab Vertical Tab Escape Sequence Routine
- Page +
- ;******************************************************************************
- ;
- ; Routine Functional Description
- ;
- ; Vert_Tab(Handle)
- ;
- ; Output vertical tab to handle
- ; Return to the caller
- ;
- ; Registers on Entry:
- ;
- ; AH - Handle
- ;
- ; Registers on Exit:
- ;
- ; AL - Destroyed
- ;
- ;******************************************************************************
- Vert_Tab Proc Near ; Output vertical tab procedure
- mov al,VT ; Get vertical tab ASCII character
- call Write_TTY ; Output the vertical tab to handle
- ret ; Return to the caller
- Vert_Tab Endp ; End of the Vert_Tab procedure
- Subttl Back_Space Back Space Escape Sequence Routine
- Page +
- ;******************************************************************************
- ;
- ; Routine Functional Description
- ;
- ; Back_Space(Handle)
- ;
- ; Output backspace to handle
- ; Return to the caller
- ;
- ; Registers on Entry:
- ;
- ; AH - Handle
- ;
- ; Registers on Exit:
- ;
- ; AL - Destroyed
- ;
- ;******************************************************************************
- Back_Space Proc Near ; Output backspace procedure
- mov al,BS ; Get backspace ASCII character
- call Write_TTY ; Output the backspace to handle
- ret ; Return to the caller
- Back_Space Endp ; End of the Back_Space procedure
- Subttl Carr_Ret Carriage Return Escape Sequence Routine
- Page +
- ;******************************************************************************
- ;
- ; Routine Functional Description
- ;
- ; Carr_Ret(Handle)
- ;
- ; Output carriage return to handle
- ; Return to the caller
- ;
- ; Registers on Entry:
- ;
- ; AH - Handle
- ;
- ; Registers on Exit:
- ;
- ; AL - Destroyed
- ;
- ;******************************************************************************
- Carr_Ret Proc Near ; Output carriage return procedure
- mov al,CR ; Get carriage return ASCII character
- call Write_TTY ; Output the carriage return to handle
- ret ; Return to the caller
- Carr_Ret Endp ; End of the Carr_Ret procedure
- Subttl Form_Feed Form Feed Escape Sequence Routine
- Page +
- ;******************************************************************************
- ;
- ; Routine Functional Description
- ;
- ; Form_Feed(Handle)
- ;
- ; Output form feed to handle
- ; Return to the caller
- ;
- ; Registers on Entry:
- ;
- ; AH - Handle
- ;
- ; Registers on Exit:
- ;
- ; AL - Destroyed
- ;
- ;******************************************************************************
- Form_Feed Proc Near ; Output form feed procedure
- mov al,FF ; Get form feed ASCII character
- call Write_TTY ; Output the form feed to handle
- ret ; Return to the caller
- Form_Feed Endp ; End of the Form_Feed procedure
- Subttl Out_Hex Output Hex Escape Sequence Routine
- Page +
- ;******************************************************************************
- ;
- ; Routine Functional Description
- ;
- ; Out_Hex(String, Handle)
- ;
- ; Set number base to hexadecimal
- ; Set maximum number length
- ; Call routine to get the number
- ; Output the number (Character) to handle
- ; Return to the caller
- ;
- ; Registers on Entry:
- ;
- ; AH - Handle
- ; DS:SI - Pointer to number
- ;
- ; Registers on Exit:
- ;
- ; AL - Destroyed
- ; CX - Destroyed
- ; DL - Destroyed
- ; DS:SI - Pointer set to first character past number
- ;
- ;******************************************************************************
- Out_Hex Proc Near ; Output hex character procedure
- mov ch,HEX ; Set number base to hexadecimal
- mov cl,HEX_LENGTH ; Set maximum hex digit length
- call Get_Number ; Call routine to get the number
- jc Out_Exit ; Jump if no number present
- mov al,dl ; Move the number value into AL
- call Write_TTY ; Output the corresponding character
- Out_Exit:
- ret ; Return to the caller
- Out_Hex Endp ; End of the Out_Hex procedure
- Subttl Conversion Formatting Routines
- Page +
- ;******************************************************************************
- ;
- ; Conversion Formatting Routines
- ;
- ;
- ; These routines handle the following conversion types:
- ;
- ;
- ; Character Conversion Done
- ; --------- ---------------
- ;
- ; c Convert next argument as a character
- ;
- ; s Convert next argument as a string
- ;
- ; x Convert next argument as a hex number using abcdef
- ;
- ; X Convert next argument as a hex number using ABCDEF
- ;
- ; d Convert next argument as a decimal number (Signed)
- ;
- ; u Convert next argument as a decimal number (Unsigned)
- ;
- ; o Convert next argument as a octal number
- ;
- ; b Convert next argument as a binary number
- ;
- ;
- ; These routines format the arguments passed to them.
- ; Numeric arguments can be either word or double word (long)
- ; values and for the decimal option it can be formatted as
- ; signed or unsigned. All arguments are passed as pointers,
- ; either near or far, to the actual argument value.
- ;
- ;******************************************************************************
- Subttl Do_Char Character Formatting Routine
- Page +
- ;******************************************************************************
- ;
- ; Routine Functional Description
- ;
- ; Do_Char(Argument, Handle, Flags)
- ;
- ; Save the required registers
- ; Call routine to get the character address
- ; If field width is not set (Zero)
- ; Set field width to character value (1)
- ; Endif
- ; If character length (1) > field width
- ; Set the field overflow flag
- ; Set character length to field width
- ; Endif
- ; Set pad character to a space
- ; Call routine to calculate pad counts
- ; Call routine to output pre-string pad characters
- ; Get character to output
- ; Call routine to output character to handle
- ; Call routine to output post-string pad characters
- ; Restore the required registers
- ; Return to the caller
- ;
- ; Registers on Entry:
- ;
- ; AH - Handle
- ; DS:BX - Pointer to argument
- ; DH - Current field width
- ; BP - Formatting flags
- ;
- ; Registers on Exit:
- ;
- ; AL - Destroyed
- ; BX - Points to next argument
- ; CX - Destroyed
- ; DL - Destroyed
- ; DI - Destroyed
- ; ES - Destroyed
- ;
- ;******************************************************************************
- Do_Char Proc Near ; Character formatting procedure
- Save si,ds ; Save the required registers
- call Variable ; Call routine to check width/precision
- call Get_Address ; Call routine to get argument address
- mov cl,1 ; Set actual width to character value
- or dh,dh ; Check the current field width
- jnz Width_Chk ; Jump if field width specified
- mov dh,1 ; Set field width to character length
- Width_Chk:
- cmp cl,dh ; Compare actual width to given width
- jbe Send_Pre ; Jump if string fits in field width
- or bp,OVER_FLOW ; Set the field overflow flag
- mov cl,dh ; Clip string to the field width
- Send_Pre:
- mov al,cl ; Save the actual string length
- and bp,Not PAD_CHAR ; Set current pad character to a space
- call Calculate ; Call routine to calculate pad values
- call Pad ; Call routine to send pad characters
- Send_Char:
- lodsb ; Get the character to output
- call Write_TTY ; Call routine to output the character
- Send_Post:
- mov cl,ch ; Get the calculated pad counts
- call Pad ; Call routine to send pad characters
- Restore si,ds ; Restore the required registers
- ret ; Return to the caller
- Do_Char Endp ; End of the Do_Char procedure
- Subttl Do_String String Formatting Routine
- Page +
- ;******************************************************************************
- ;
- ; Routine Functional Description
- ;
- ; Do_String(Argument, Handle, Width, Flags)
- ;
- ; Save the required registers
- ; Call routine to get the string address
- ; Call routine to compute string length
- ; If field width is not set (Zero)
- ; Set field width to string length
- ; Endif
- ; If string length > field width
- ; Set the field overflow flag
- ; Set string length to field width
- ; Endif
- ; Set pad character to a space
- ; Call routine to calculate pad counts
- ; Call routine to output pre-string pad characters
- ; While length > 0
- ; Get next character of string
- ; Call routine to output character to handle
- ; Decrement the length
- ; Endwhile
- ; Call routine to output post-string pad characters
- ; Restore the required registers
- ; Return to the caller
- ;
- ; Registers on Entry:
- ;
- ; AH - Handle
- ; DS:BX - Pointer to argument
- ; DH - Current field width
- ; BP - Formatting flags
- ;
- ; Registers on Exit:
- ;
- ; AL - Destroyed
- ; BX - Points to next argument
- ; CX - Destroyed
- ; DL - Destroyed
- ; DI - Destroyed
- ; ES - Destroyed
- ;
- ;******************************************************************************
- Do_String Proc Near ; String formatting procedure
- Save si,ds ; Save the required registers
- call Variable ; Call routine to check width/precision
- call Get_Address ; Call routine to get argument address
- call Get_Length ; Call routine to get string length
- jz String_Exit ; Jump if nothing to output
- or dh,dh ; Check the current field width
- jnz Chk_Width ; Jump if field width specified
- mov dh,cl ; Set field width to string length
- Chk_Width:
- cmp cl,dh ; Compare actual width to given width
- jbe Do_Pre ; Jump if string fits in field width
- or bp,OVER_FLOW ; Set the field overflow flag
- mov cl,dh ; Clip string to the field width
- Do_Pre:
- mov al,cl ; Save the actual string length
- and bp,Not PAD_CHAR ; Set current pad character to a space
- call Calculate ; Call routine to calculate pad values
- mov dl,al ; Setup the string output length
- call Pad ; Call routine to send pad characters
- Send_String:
- lodsb ; Get the next string character
- call Write_TTY ; Call routine to output the character
- dec dl ; Decrement the output length
- jnz Send_String ; Go get next character if more left
- Do_Post:
- mov cl,ch ; Get the calculated pad counts
- call Pad ; Call routine to send pad characters
- String_Exit:
- Restore si,ds ; Restore the required registers
- ret ; Return to the caller
- Do_String Endp ; End of the Do_String procedure
- Subttl Do_Hex Hexadecimal Formatting Routine
- Page +
- ;******************************************************************************
- ;
- ; Routine Functional Description
- ;
- ; Do_Hex(Argument, Handle, Width, Precision, Flags, Type)
- ;
- ; Save the required registers
- ; If type is uppercase
- ; Set the uppercase format flag
- ; Endif
- ; Set current number base to hexadecimal
- ; Call routine to get the argument address
- ; Call routine to output the numeric string
- ; Restore the required registers
- ; Return to the caller
- ;
- ; Registers on Entry:
- ;
- ; AH - Handle
- ; DS:BX - Pointer to argument
- ; DH - Current field width
- ; DL - Current field precision
- ; BP - Formatting flags
- ;
- ; Registers on Exit:
- ;
- ; BX - Points to next argument
- ;
- ;******************************************************************************
- Do_Hex Proc Near ; Hexadecimal formatting procedure
- Do_Hex_Upper Label Near ; Do_Hex_Upper entry point (ABCDEF)
- or bp,UPPER_CASE ; Set uppercase formatting flag
- Do_Hex_Lower Label Near ; Do_Hex_Lower entry point (abcdef)
- Save si,ds ; Save the required registers
- call Variable ; Call routine to check width/precision
- mov ch,HEX ; Set the current number base to hex
- call Get_Address ; Call routine to get argument address
- call Compute ; Call routine to output number
- Restore si,ds ; Restore the required registers
- ret ; Return to the caller
- Do_Hex Endp ; End of the Do_Hex procedure
- Subttl Do_Decimal Decimal Formatting Routine
- Page +
- ;******************************************************************************
- ;
- ; Routine Functional Description
- ;
- ; Do_Decimal(Argument, Handle, Width, Precision, Flags)
- ;
- ; Save the required registers
- ; Set the signed type formatting flag
- ; Set current number base to decimal
- ; Call routine to get the argument address
- ; Call routine to output the numeric string
- ; Restore the required registers
- ; Return to the caller
- ;
- ; Registers on Entry:
- ;
- ; AH - Handle
- ; DS:BX - Pointer to argument
- ; DH - Current field width
- ; DL - Current field precision
- ; BP - Formatting flags
- ;
- ; Registers on Exit:
- ;
- ; BX - Points to next argument
- ;
- ;******************************************************************************
- Do_Decimal Proc Near ; Decimal formatting procedure
- Save si,ds ; Save the required registers
- call Variable ; Call routine to check width/precision
- or bp,SIGNED_TYPE ; Set signed type formatting flag
- mov ch,DECIMAL ; Set current number base to decimal
- call Get_Address ; Call routine to get argument address
- call Compute ; Call routine to output number
- Restore si,ds ; Restore the required registers
- ret ; Return to the caller
- Do_Decimal Endp ; End of the Do_Decimal procedure
- Subttl Do_Unsigned Unsigned Decimal Formatting Routine
- Page +
- ;******************************************************************************
- ;
- ; Routine Functional Description
- ;
- ; Do_Unsigned(Argument, Handle, Width, Precision, Flags)
- ;
- ; Save the required registers
- ; Set current number base to decimal
- ; Call routine to get the argument address
- ; Call routine to output the numeric string
- ; Restore the required registers
- ; Return to the caller
- ;
- ; Registers on Entry:
- ;
- ; AH - Handle
- ; DS:BX - Pointer to argument
- ; DH - Current field width
- ; DL - Current field precision
- ; BP - Formatting flags
- ;
- ; Registers on Exit:
- ;
- ; BX - Points to next argument
- ;
- ;******************************************************************************
- Do_Unsigned Proc Near ; Unsigned decimal formatting procedure
- Save si,ds ; Save the required registers
- call Variable ; Call routine to check width/precision
- mov ch,DECIMAL ; Set current number base to decimal
- call Get_Address ; Call routine to get argument address
- call Compute ; Call routine to output number
- Restore si,ds ; Restore the required registers
- ret ; Return to the caller
- Do_Unsigned Endp ; End of the Do_Unsigned procedure
- Subttl Do_Octal Octal Formatting Routine
- Page +
- ;******************************************************************************
- ;
- ; Routine Functional Description
- ;
- ; Do_Octal(Argument, Handle, Width, Precision, Flags)
- ;
- ; Save the required registers
- ; Set current number base to octal
- ; Call routine to get the argument address
- ; Call routine to output the numeric string
- ; Restore the required registers
- ; Return to the caller
- ;
- ; Registers on Entry:
- ;
- ; AH - Handle
- ; DS:BX - Pointer to argument
- ; DH - Current field width
- ; DL - Current field precision
- ; BP - Formatting flags
- ;
- ; Registers on Exit:
- ;
- ; BX - Points to next argument
- ;
- ;******************************************************************************
- Do_Octal Proc Near ; Octal formatting procedure
- Save si,ds ; Save the required registers
- call Variable ; Call routine to check width/precision
- mov ch,OCTAL ; Set current number base to octal
- call Get_Address ; Call routine to get argument address
- call Compute ; Call routine to output number
- Restore si,ds ; Restore the required registers
- ret ; Return to the caller
- Do_Octal Endp ; End of the Do_Octal procedure
- Subttl Do_Binary Binary Formatting Routine
- Page +
- ;******************************************************************************
- ;
- ; Routine Functional Description
- ;
- ; Do_Binary(Argument, Handle, Width, Precision, Flags)
- ;
- ; Save the required registers
- ; Set current number base to binary
- ; Call routine to get the argument address
- ; Call routine to output the numeric string
- ; Retore the required registers
- ; Return to the caller
- ;
- ; Registers on Entry:
- ;
- ; AH - Handle
- ; DS:BX - Pointer to argument
- ; DH - Current field width
- ; DL - Current field precision
- ; BP - Formatting flags
- ;
- ; Registers on Exit:
- ;
- ; BX - Points to next argument
- ;
- ;******************************************************************************
- Do_Binary Proc Near ; Binary formatting procedure
- Save si,ds ; Save the required registers
- call Variable ; Call routine to check width/precision
- mov ch,BINARY ; Set current number base to binary
- call Get_Address ; Call routine to get argument address
- call Compute ; Call routine to output number
- Restore si,ds ; Restore the required registers
- ret ; Return to the caller
- Do_Binary Endp ; End of the Do_Binary procedure
- Subttl Do_Fractional Fractional Formatting Routine
- Page +
- ;******************************************************************************
- ;
- ; Routine Functional Description
- ;
- ; Do_Fractional(Argument, Handle, Width, Precision, Flags)
- ;
- ; Save the required registers
- ; Set the signed type formatting flag
- ; Set current number base to decimal
- ; Call routine to get the argument address
- ; Call routine to output the numeric string
- ; Restore the required registers
- ; Return to the caller
- ;
- ; Registers on Entry:
- ;
- ; AH - Handle
- ; DS:BX - Pointer to argument
- ; DH - Current field width
- ; DL - Current field precision
- ; BP - Formatting flags
- ;
- ; Registers on Exit:
- ;
- ; BX - Points to next argument
- ;
- ;******************************************************************************
- Do_Fractional Proc Near ; Fractional formatting procedure
- Save si,ds ; Save the required registers
- call Variable ; Call routine to check width/precision
- or bp,SIGNED_TYPE ; Set signed type formatting flag
- or bp,FRACTIONAL ; Set the fractional formatting flag
- mov ch,DECIMAL ; Set current number base to decimal
- call Get_Address ; Call routine to get argument address
- call Compute ; Call routine to output number
- Restore si,ds ; Restore the required registers
- ret ; Return to the caller
- Do_Fractional Endp ; End of the Do_Fractional procedure
- Subttl Get_Address Get Argument Address Routine
- Page +
- ;******************************************************************************
- ;
- ; Routine Functional Description
- ;
- ; Get_Address(Argument, Flags)
- ;
- ; If far format specifier has been set
- ; Set DS:SI to far pointer at DS:BX
- ; Increment BX to next argument (4)
- ; Else no far specifier
- ; Set SI to near pointer at DS:BX
- ; Increment BX to next argument (2)
- ; Endif
- ; Return to the caller
- ;
- ; Registers on Entry:
- ;
- ; DS:BX - Pointer to argument list
- ; BP - Formatting flags
- ;
- ; Registers on Exit:
- ;
- ; DS:SI - New address pointer (Character or string)
- ; BX - Points to the next argument
- ;
- ;******************************************************************************
- Get_Address Proc Near ; Get address procedure
- test bp,FAR_SPEC ; Check for far specifier set
- jz Near_Addr ; Jump if a normal near address
- Far_Addr:
- lds si,Dword Ptr ds:[bx] ; Load the far address into DS:SI
- add bx,FAR_SIZE ; Update the argument pointer value
- jmp Get_Exit ; Go return to the caller
- Near_Addr:
- mov si,Word Ptr ds:[bx] ; Load the near address into SI
- add bx,NEAR_SIZE ; Update the argument pointer value
- Get_Exit:
- ret ; Return to the caller
- Get_Address Endp ; End of the Get_Address procedure
- Subttl Variable Get Variable Value Routine
- Page +
- ;******************************************************************************
- ;
- ; Routine Functional Description
- ;
- ; Variable(Width, Precision, Flags)
- ;
- ; Save the required registers
- ; If variable width specified
- ; Get the actual width value (Byte)
- ; Endif
- ; If variable precision specified
- ; Get the actual precision value (Byte)
- ; Endif
- ; Restore the required registers
- ; Return to the caller
- ;
- ; Registers on Entry:
- ;
- ; DS:BX - Pointer to argument list
- ; BP - Formatting flags
- ;
- ; Registers on Exit:
- ;
- ; DH - Actual width value
- ; DL - Actual precision value
- ; BX - Points to the next argument
- ;
- ;******************************************************************************
- Variable Proc Near ; Get variable width/precision procedure
- Save si ; Save the required registers
- test bp,VAR_WIDTH ; Check for a variable width value
- jz Pre_Chk ; Jump if no variable width
- mov si,Word Ptr ds:[bx] ; Load the near address into SI
- add bx,NEAR_SIZE ; Update the argument pointer value
- mov dh,Byte Ptr ds:[si] ; Get the actual field width value
- Pre_Chk:
- test bp,VAR_PRE ; Check for a variable precision value
- jz Var_Exit ; Jump if no variable precision
- mov si,Word Ptr ds:[bx] ; Load the near address into SI
- add bx,NEAR_SIZE ; Update the argument pointer value
- mov dl,Byte Ptr ds:[si] ; Get the actual precision value
- Var_Exit:
- Restore si ; Restore the required registers
- ret ; Return to the caller
- Variable Endp ; End of the Variable procedure
- Subttl Get_Length Get String Length Routine
- Page +
- ;******************************************************************************
- ;
- ; Routine Functional Description
- ;
- ; Get_Length(String)
- ;
- ; Calculate the length of the string (Null terminator)
- ; Return to the caller
- ;
- ; Registers on Entry:
- ;
- ; DS:SI - Pointer to string
- ;
- ; Registers on Exit:
- ;
- ; AL - Destroyed
- ; CX - String length
- ; DI - Destroyed
- ; ES - Destroyed
- ; ZR - Zero set if zero length
- ;
- ;******************************************************************************
- Get_Length Proc Near ; Get string length procedure
- push ds ; Put a copy of DS onto the stack
- pop es ; Set ES to the current DS value
- mov di,si ; Set DI to the current SI value
- mov al,NULL ; Setup to scan for null terminator
- mov cx,MAX_WORD ; Setup to scan for maximum length
- repne scasb ; Scan for the string terminator
- not cx ; Correct the count value
- dec cx ; Adjust to get actual string length
- ret ; Return to the caller
- Get_Length Endp ; End of the Get_Length procedure
- Subttl Calculate Calculate Pad Lengths Routine
- Page +
- ;******************************************************************************
- ;
- ; Routine Functional Description
- ;
- ; Calculate(Width, Length)
- ;
- ; Save the required registers
- ; Calculate total pad length
- ; If total pad length > 0
- ; If left justification is not requested
- ; Set pre pad count to total
- ; Zero post pad count
- ; Else left justification requested
- ; Set post pad count to total
- ; Zero pre pad count
- ; Endif
- ; Else total pad length < 0
- ; Set pre pad count to zero
- ; Set post pad count to zero
- ; Endif
- ; Restore the required registers
- ; Return to the caller
- ;
- ; Registers on Entry:
- ;
- ; CL - Length of the string
- ; DH - Field width
- ; BP - Formatting flags
- ;
- ; Registers on Exit:
- ;
- ; CH - Post string pad count
- ; CL - Pre string pad count
- ;
- ;******************************************************************************
- Calculate Proc Near ; Calculate pad length procedure
- Save ax ; Save the required registers
- mov al,dh ; Get the current field width
- mov ah,cl ; Get the length of the output string
- xor cx,cx ; Default pre/post pad counts to zero
- sub al,ah ; Compute the total pad count
- jbe Calc_Exit ; Jump if no pad necessary
- mov cl,al ; Default to right justification
- test bp,LEFT_JUST ; Check if left justify was specified
- jz Calc_Exit ; Jump if no left justification
- mov ch,cl ; Make post pad count the total count
- xor cl,cl ; Zero the pre pad count value
- Calc_Exit:
- Restore ax ; Restore the required registers
- ret ; Return to the caller
- Calculate Endp ; End of the Calculate procedure
- Subttl Pad Output Pad Characters Routine
- Page +
- ;******************************************************************************
- ;
- ; Routine Functional Description
- ;
- ; Pad(Handle, Pad, Count)
- ;
- ; Save the required registers
- ; While count > 0
- ; Output the current pad character
- ; Decrement the count
- ; Endwhile
- ; Restore the required registers
- ; Return to the caller
- ;
- ; Registers on Entry:
- ;
- ; AH - Handle
- ; CL - Pad count
- ;
- ; Registers on Exit:
- ;
- ; CL - Destroyed
- ;
- ;******************************************************************************
- Pad Proc Near ; Pad character procedure
- Save ax ; Save the required registers
- or cl,cl ; Check for no padding required
- jz Pad_Exit ; Jump if no padding is required
- mov al,SPACE_PAD ; Default to a space pad character
- test bp,PAD_CHAR ; Check for a zero pad character
- jz Pad_Loop ; Jump if using a space pad character
- mov al,ZERO_PAD ; Setup to use a zero pad character
- Pad_Loop:
- call Write_TTY ; Call routine to output pad character
- dec cl ; Decrement the pad count
- jnz Pad_Loop ; Jump if more pad characters to send
- Pad_Exit:
- Restore ax ; Restore the required registers
- ret ; Return to the caller
- Pad Endp ; End of the Pad procedure
- Subttl Clear_Flags Clear All Flags Routine
- Page +
- ;******************************************************************************
- ;
- ; Routine Functional Description
- ;
- ; Clear_Flags(Flags)
- ;
- ; Clear the formatting flags
- ; Default to space padding
- ; Zero the current field width
- ; Clear direction flag (All string operations forward)
- ; Return to the caller
- ;
- ; Registers on Entry:
- ;
- ; None
- ;
- ; Registers on Exit:
- ;
- ; BP - Destroyed (BP contains the flags and is zeroed)
- ; DH - Set to zero (Current field width)
- ; DL - Set to zero (Current field precision)
- ;
- ;******************************************************************************
- Clear_Flags Proc Near ; Clear formatting flags procedure
- xor bp,bp ; Clear all of the formatting flags
- xor dh,dh ; Zero the current field width
- xor dl,dl ; Zero the current field precision
- cld ; Clear the direction flag
- ret ; Return to the caller
- Clear_Flags Endp ; End of the Clear_Flags procedure
- Subttl Print_Format Print Format Character Routine
- Page +
- ;******************************************************************************
- ;
- ; Routine Functional Description
- ;
- ; Print_Format(Handle)
- ;
- ; Save the required registers
- ; Output format specification character to handle
- ; Restore the required registers
- ; Return to the caller
- ;
- ; Registers on Entry:
- ;
- ; AH - Handle
- ;
- ; Registers on Exit:
- ;
- ; AL - Destroyed
- ; None
- ;
- ;******************************************************************************
- Print_Format Proc Near ; Output format specifier procedure
- mov al,FORMAT_CHAR ; Get format specifier character
- call Write_TTY ; Output the format specifier to handle
- ret ; Return to the caller
- Print_Format Endp ; End of the Print_Format procedure
- Subttl Check_Digit Check Digit Routine
- Page +
- ;******************************************************************************
- ;
- ; Routine Functional Description
- ;
- ; Check_Digit(Base, Character)
- ;
- ; Save the required registers
- ; Call routine to convert character to binary
- ; If the character can be converted
- ; If value is greater than base
- ; Set carry flag (Character not a digit)
- ; Endif
- ; Else character cannot be converted
- ; Set carry flag (Character not a digit)
- ; Endif
- ; Restore the required registers
- ; Return to the caller
- ;
- ; Registers on Entry:
- ;
- ; AL - Digit to check (ASCII)
- ; CH - Number system base
- ;
- ; Registers on Exit:
- ;
- ; AL - Binary value of digit (If it is a digit)
- ; CY - Set if character is not a digit in current base
- ;
- ;******************************************************************************
- Check_Digit Proc Near ; Check digit procedure
- Save bx ; Save the required registers
- Save ax ; Save the original digit value
- call Convert_Char ; Call routine to convert character
- mov bl,al ; Save converted value in BL
- Restore ax ; Restore the original digit value
- jc Check_Exit ; Jump if could not be converted
- cmp bl,ch ; Check against current number base
- cmc ; Set correct carry flag state
- jc Check_Exit ; Jump if not valid for this base
- mov al,bl ; Digit is valid, save binary value
- Check_Exit:
- Restore bx ; Restore the required registers
- ret ; Return to the caller
- Check_Digit Endp ; End of the Check_Digit procedure
- Subttl Convert_Char Convert to Binary Conversion Routine
- Page +
- ;******************************************************************************
- ;
- ; Routine Functional Description
- ;
- ; Convert_Char(Character)
- ;
- ; If character is a decimal digit (0 to 9)
- ; Convert ASCII digit to binary (Subtract 30h)
- ; Clear the carry flag (Character could be converted)
- ; Else character is not a decimal digit
- ; Convert character to uppercase
- ; If character is a hex digit (A to F)
- ; Convert ASCII digit to binary (Subtract 37h)
- ; Clear carry flag (Character could be converted)
- ; Else character is not a hex digit
- ; Set carry flag (Could not be converted)
- ; Endif
- ; Endif
- ; Return to the caller
- ;
- ; Registers on Entry:
- ;
- ; AL - Digit to check (ASCII)
- ; CH - Number system base
- ;
- ; Registers on Exit:
- ;
- ; AL - Binary value of digit (If it is a digit)
- ; CY - Set if character is not a digit in current base
- ;
- ;******************************************************************************
- Convert_Char Proc Near ; Convert character procedure
- sub al,DECIMAL_ADJUST ; Adjust character for ASCII decimal
- jc Convert_Exit ; Jump if below decimal limit
- cmp al,DECIMAL ; Check for a valid decimal character
- cmc ; Set carry flag to correct state
- jnc Convert_Exit ; Jump if there is a valid digit
- and al,UPPER_MASK ; Convert anything else to uppercase
- sub al,HEX_ADJUST ; Adjust character for ASCII hexadecimal
- cmp al,DECIMAL ; Check for a valid hex character
- jc Convert_Exit ; Jump if below hexadecimal limit
- cmp al,HEX ; Check against upper hex limit
- cmc ; Set carry flag to correct state
- Convert_Exit:
- ret ; Return to caller with value and flag
- Convert_Char Endp ; End of the Convert_Char procedure
- Subttl Get_Number ASCII to Binary Conversion Routine
- Page +
- ;******************************************************************************
- ;
- ; Routine Functional Description
- ;
- ; Get_Number(String, Base, Length)
- ;
- ; Save the required registers
- ; While length > 0
- ; Decrement the length
- ; Get the next character from string
- ; Call routine to check for a valid digit
- ; If character is a valid digit
- ; Add new value into total
- ; Endif
- ; Endwhile
- ; Decrement pointer back to last character
- ; Restore the required registers
- ; Return to the caller
- ;
- ; Registers on Entry:
- ;
- ; CH - Number Base
- ; CL - Maximum number length
- ; DS:SI - Current string pointer
- ;
- ; Registers on Exit:
- ;
- ; CL - Destroyed
- ; DL - Number retrieved (Zero if none)
- ; DS:SI - Pointer to character following number
- ; CY - Carry set if no number was found
- ; ZR - Zero set if zero number found
- ;
- ;******************************************************************************
- Get_Number Proc Near ; Get number procedure
- Save ax,bx ; Save the required registers
- mov dl,MAX_BYTE ; Get maximum value for a byte
- xor al,al ; Initialize the current total
- Get_Loop:
- mov bx,ax ; Save current total in BX register
- lodsb ; Get the next string character
- call Check_Digit ; Call routine to check for digit
- jc Number_Exit ; Jump if this is not a valid digit
- inc dl ; Increment no number present flag
- cbw ; Convert binary value into full word
- xchg ax,bx ; Move total to AX, digit value in BX
- mul ch ; Multiply current total by number base
- add ax,bx ; Add in the new digit to current total
- dec cl ; Decrement the number length count
- jnz Get_Loop ; Jump if more digits are allowed
- mov bx,ax ; Move the current total into BX
- inc si ; Increment to next character
- Number_Exit:
- dec si ; Decrement back to non-digit character
- add dl,0 ; Set carry to indicate presence
- mov dl,bl ; Save the computed number in DL
- or dl,dl ; Set zero flag for zero result
- Restore ax,bx ; Restore the required registers
- ret ; Return to the caller
- Get_Number Endp ; End of the Get_Number procedure
- Subttl Compute Convert Argument Routine
- Page +
- ;******************************************************************************
- ;
- ; Routine Functional Description
- ;
- ; Compute(Argument, Handle, Width, Precision, Base, Flags)
- ;
- ; Save the required registers
- ; Allocate buffer space on the stack
- ; If argument value is long
- ; Get the long numeric value (4 bytes)
- ; Else if argument value is short
- ; Get the short numeric value (1 byte)
- ; Convert short to long value
- ; Else argument value is normal
- ; Get the normal numeric value (2 bytes)
- ; Convert normal to long value
- ; Endif
- ; If signed type is specified
- ; If the value is signed
- ; Set the signed value flag
- ; Take the twos complement of the value
- ; Endif
- ; Endif
- ; Zero the fraction value (Integer default)
- ; If fractional type conversion
- ; Separate number into integer and fraction
- ; Endif
- ; Convert integer to ASCII string in buffer
- ; If fractional type conversion
- ; Convert fraction to ASCII string in buffer
- ; Endif
- ; Calculate the numeric string length
- ; Default to no sign character
- ; If signed type conversion
- ; If numeric value was signed (Negative)
- ; Setup minus sign as sign character
- ; Increment the string length (For sign character)
- ; Else numeric value was not signed
- ; If signed conversion was specified
- ; Setup plus sign as sign character
- ; Increment the string length
- ; Endif
- ; Endif
- ; Endif
- ; If field width is not set (Zero)
- ; Set field width to string length
- ; Endif
- ; If string length > field width
- ; Set the field overflow flag
- ; Set string length to field width - 1
- ; Endif
- ; Call routine to calculate pad counts
- ; If sign character is present
- ; If pre-pad sign character
- ; Output sign character to handle
- ; Call routine to output pre-string pad characters
- ; Else post-pad sign character
- ; Call routine to output pre-string pad characters
- ; Output sign character to handle
- ; Endif
- ; Else sign character is not present
- ; Call routine to output pre-string pad characters
- ; Endif
- ; While length > 0
- ; Get next character of string
- ; Call routine to output character to handle
- ; Decrement the length
- ; Endwhile
- ; Set current pad character to a space
- ; Call routine to output post-string pad characters
- ; If the field overflow flag is set
- ; Output the overflow character
- ; Endif
- ; Restore the required registers
- ; Return to the caller
- ;
- ; Registers on Entry:
- ;
- ; AH - Handle
- ; DS:SI - Pointer to argument
- ; CH - Current number base
- ; DH - Current field width
- ; DL - Current field precision
- ; BP - Formatting flags
- ;
- ; Registers on Exit:
- ;
- ; Direction flag is cleared (Move Forward)
- ;
- ;******************************************************************************
- Compute Proc Near ; Output numeric string procedure
- Save bx,si,ds ; Save the required registers
- sub sp,BUFF_SIZE ; Allocate buffer space on the stack
- mov di,sp ; Setup the buffer pointer
- add di,BUFF_SIZE/2 ; Set the starting buffer position
- push ax ; Save the output handle value
- push dx ; Save the field width/precision
- xor dh,dh ; Convert precision to a full word
- push dx ; Save the field precision
- mov cl,ch ; Move current base value into CL
- xor ch,ch ; Make current base value into a word
- xor ax,ax ; Default to an unsigned
- xor dx,dx ; non-long value
- test bp,SHORT_SPEC ; Check for short value specified
- jnz Get_Short ; Jump if short value specified
- test bp,LONG_SPEC ; Check for long value specified
- jnz Get_Long ; Jump if long value specified
- mov ax,ds:[si] ; Get the normal value (2 Bytes)
- test bp,SIGNED_TYPE ; Check for a signed conversion
- jz Chk_Frac ; Jump if not a signed conversion
- cwd ; Signed conversion, do sign extension
- jmp Chk_Sign ; Go check for signed argument
- Get_Short:
- mov al,ds:[si] ; Get the short value (1 Byte)
- test bp,SIGNED_TYPE ; Check for a signed conversion
- jz Chk_Frac ; Jump if not a signed conversion
- cbw ; Signed conversion,
- cwd ; do sign extension
- jmp Chk_Sign ; Go check for signed argument
- Get_Long:
- mov ax,ds:[si] ; Get the
- mov dx,ds:[si + 2] ; long value (4 Bytes)
- Chk_Sign:
- test bp,SIGNED_TYPE ; Check for a signed type
- jz Chk_Frac ; Jump if not signed
- test dx,SIGNED ; Check the number for signed
- jz Chk_Frac ; Jump if number is not signed
- or bp,SIGNED_VAL ; Set the signed value flag
- not ax ; Ones complement of the LSW
- not dx ; Ones complement of the MSW
- add ax,1 ; Twos complement of the LSW
- adc dx,0 ; Twos complement of the MSW
- Chk_Frac:
- mov si,ss ; Get the current stack segment
- mov ds,si ; Setup DS to current stack segment
- mov es,si ; Setup ES to current stack segment
- xor bx,bx ; Zero fraction value (Integer default)
- test bp,FRACTIONAL ; Check for fractional conversion
- jz Do_Integer ; Jump if standard integer conversion
- test bp,SHORT_SPEC ; Check for short value specified
- jnz Do_Short ; Jump if a short fractional value
- test bp,LONG_SPEC ; Check for long value specified
- jnz Do_Long ; Jump if a long fractional value
- mov bh,al ; Move fraction value to MSB (BH)
- xor bl,bl ; Zero the lower LSB of fraction (BL)
- mov al,ah ; Move integer value to LSB (AL)
- xor ah,ah ; Zero the upper MSB of integer (AH)
- xor dx,dx ; Zero the upper MSW of integer (DX)
- jmp Do_Integer ; Go convert the integer portion
- Do_Long:
- mov bx,ax ; Move fraction value to BX
- mov ax,dx ; Move integer value to LSW (AX)
- xor dx,dx ; Zero the upper MSW of integer (DX)
- jmp Do_Integer ; Go convert the integer portion
- Do_Short:
- mov bh,al ; Move fraction value to MSB (BH)
- xor bl,bl ; Zero the lower LSB of fraction (BL)
- xor ax,ax ; Zero the lower LSW of integer (AX)
- xor dx,dx ; Zero the upper MSW of integer (DX)
- Do_Integer:
- push di ; Save the starting position
- cld ; Clear direction flag (Move forward)
- Integer_Loop:
- mov si,ax ; Save LSW of value in SI register
- mov ax,dx ; Move MSW of value into AX
- xor dx,dx ; Setup to do the first divide
- div cx ; Divide the MSW by the current base
- xchg ax,si ; Setup for the second division
- div cx ; Divide the result by the current base
- xchg ax,dx ; Put the remainder into AX
- call Digit ; Call routine to convert it to a digit
- stosb ; Store the ASCII digit into buffer
- xchg ax,dx ; Restore quotient of second division
- mov dx,si ; Restore quotient of first division
- or si,ax ; Check for a zero result
- jnz Integer_Loop ; Jump if more digits to get
- Do_Fraction:
- pop dx ; Restore the starting position
- pop si ; Restore the field precision
- mov ax,bx ; Get the fraction value into AX
- mov bx,di ; Save the final position in BX
- mov di,dx ; Get the starting position
- test bp,FRACTIONAL ; Check for fractional conversion
- jz Calc_Length ; Jump if standard integer conversion
- dec di ; Decrement to get new start position
- std ; Set direction flag (Move Backward)
- mov Byte Ptr es:[di],POINT ; Put a decimal point into buffer
- or si,si ; Check for zero precision
- jz Calc_Length ; Jump if no digits to compute
- dec di ; Update pointer for decimal point
- Fraction_Loop:
- mul cx ; Multiply by the current base
- xchg ax,dx ; Put the MSW of result into AX
- call Digit ; Call routine to convert it to a digit
- stosb ; Store the ASCII digit into buffer
- xchg ax,dx ; Restore fraction from multiply
- dec si ; Decrement the precision count
- jnz Fraction_Loop ; Jump if more digits left to do
- inc di ; Correct for length calculation
- Do_Round:
- mul cx ; Compute the next actual digit
- shl dx,1 ; Multiply digit value by two
- cmp dx,cx ; Compare value to current base
- jb Calc_Length ; Jump if below current base value
- push di ; Save the current position
- mov ch,cl ; Move current base to CH
- Round_Loop:
- mov al,es:[di] ; Get the digit to round
- call Convert_Char ; Convert the ASCII to binary
- inc al ; Round the digit up
- mov ah,al ; Save the rounded value in AH
- call Digit ; Convert the binary digit to ASCII
- cmp ah,ch ; Check the value against current base
- jb Round_Done ; Jump if rounding is complete
- xor al,al ; Zero the AL register value
- call Digit ; Convert to an ASCII zero value
- mov es:[di],al ; Zero the current digit value
- inc di ; Increment to the next digit position
- cmp di,bx ; Check against final position
- jbe Round_Loop ; Jump if more digits to round with
- mov bx,di ; Update the new final position
- xor al,al ; Zero the AL register value
- inc al ; Increment AL to a one value
- call Digit ; Convert the one value to ASCII
- Round_Done:
- mov es:[di],al ; Save the last rounded digit
- pop di ; Restore the current position
- Calc_Length:
- pop dx ; Restore field width/precision
- pop ax ; Restore the file handle
- mov cx,bx ; Get the final buffer pointer
- sub cx,di ; Compute the numeric string length
- xor al,al ; Default to no sign character
- test bp,SIGNED_TYPE ; Check for signed type
- jz Do_Check ; Jump if not a signed type
- test bp,SIGNED_VAL ; Check for a signed value
- jz Chk_Conv ; Jump if not a signed value
- mov al,MINUS ; Setup minus as sign character
- inc cx ; Increment the string length
- jmp Do_Check ; Go check the field width
- Chk_Conv:
- test bp,SIGNED_CONV ; Check for a signed conversion
- jz Do_Check ; Jump if not a signed type
- mov al,PLUS ; Setup plus as sign character
- inc cx ; Increment the string length
- Do_Check:
- or dh,dh ; Check the current field width
- jnz Width_Check ; Jump if field width specified
- mov dh,cl ; Set field width to string length
- Width_Check:
- cmp cl,dh ; Check actual width to field width
- jbe Do_Calc ; Jump if string fits in the field
- or bp,OVER_FLOW ; Set the field overflow flag
- mov cl,dh ; Set string width to field width
- dec cl ; Adjust for the overflow character
- jz Compute_Exit ; Jump if no more room in the field
- Do_Calc:
- push ax ; Save the sign character (If any)
- mov al,cl ; Save the actual string length
- call Calculate ; Call routine to calculate pad values
- mov dl,al ; Setup the string output length
- pop ax ; Restore the sign character (If any)
- test bp,PRE_PAD ; Check for pre pad sign character
- jz Do_Pad ; Jump if not pre pad sign character
- or al,al ; Check for a sign needed
- jz Do_Pad ; Jump if no sign is needed
- call Write_TTY ; Call routine to output sign character
- dec dl ; Decrement the output count
- jz Compute_Exit ; Jump if no more room in field
- Do_Pad:
- call Pad ; Call routine to output pad characters
- test bp,PRE_PAD ; Check for post pad sign character
- jnz Do_Setup ; Jump if not post pad sign character
- or al,al ; Check for a sign needed
- jz Do_Setup ; Jump if no sign character needed
- call Write_TTY ; Call routine to output the sign
- dec dl ; Decrement the output count
- jz Compute_Exit ; Jump if no more room in field
- Do_Setup:
- mov si,bx ; Setup the source pointer to buffer
- dec si ; Point back to first character
- std ; Set direction flag (Reverse order)
- Send_Loop:
- lodsb ; Get the next character to output
- call Write_TTY ; Call routine to output character
- dec dl ; Decrement the output count
- jnz Send_Loop ; Jump if more characters to output
- mov cl,ch ; Get the calculated pad counts
- and bp,Not PAD_CHAR ; Set pad character to a space
- call Pad ; Call routine to send pad characters
- Compute_Exit:
- test bp,OVER_FLOW ; Check for field overflow
- jz Compute_Done ; Jump if no field overflow
- mov al,ASTERISK ; Get the field overflow character (*)
- call Write_TTY ; Output the field overflow character
- Compute_Done:
- add sp,BUFF_SIZE ; Deallocate the buffer area
- Restore bx,si,ds ; Restore the required registers
- cld ; Clear the direction flag
- ret ; Return to the caller
- Compute Endp ; End of the Compute procedure
- Subttl Digit Binary to Character Conversion Routine
- Page +
- ;******************************************************************************
- ;
- ; Routine Functional Description
- ;
- ; Digit(Value, Flags)
- ;
- ; Save the required registers
- ; Translate character to ASCII value
- ; If uppercase flag is set
- ; If ASCII value is not a digit (abcdef)
- ; Convert to uppercase (ABCDEF)
- ; Endif
- ; Endif
- ; Restore the required registers
- ; Return to the caller
- ;
- ; Registers on Entry:
- ;
- ; AL - Binary value (0 - 15)
- ;
- ; Registers on Exit:
- ;
- ; AL - ASCII character
- ;
- ;******************************************************************************
- Digit Proc Near ; Convert to ASCII digit procedure
- Save bx ; Save the required registers
- lea bx,cs:[Digit_Table] ; Get pointer to digit translate table
- xlat byte ptr cs:[bx] ; Translate to ASCII digit
- test bp,UPPER_CASE ; Check for uppercase flag
- jz Digit_Exit ; Jump if no uppercase flag set
- cmp al,DIGIT_MAX ; Check for uppercase adjust needed
- jbe Digit_Exit ; Jump if adjustment not needed
- and al,UPPER_MASK ; Convert character to uppercase
- Digit_Exit:
- Restore bx ; Restore the required registers
- ret ; Return to the caller
- Digit Endp ; End of the Digit procedure
- Subttl Define the Printf Data Areas
- Page +
- ;******************************************************************************
- ;
- ; Define any data tables needed by the Printf routine
- ;
- ;******************************************************************************
- Format_Table Label Byte
- Db '-' ; Left justify format specifier
- Db '+' ; Set signed specifier
- Db 't' ; Short format specifier
- Db 'T' ; Short format specifier
- Db 'l' ; Long format specifier
- Db 'L' ; Long format specifier
- Db '#' ; Far format specifier
- FORMAT_SIZE Equ This Byte - Format_Table
- Format_Jump Label Word
- Dw Left_Justify ; Left justify format specifier
- Dw Set_Signed ; Set signed specifier
- Dw Short_Specify ; Short format specifier
- Dw Short_Specify ; Short format specifier
- Dw Long_Specify ; Long format specifier
- Dw Long_Specify ; Long format specifier
- Dw Far_Specify ; Far format specifier
- Escape_Table Label Byte
- Db 'n' ; Newline escape character
- Db 't' ; Horizontal tab escape character
- Db 'v' ; Vertical tab escape character
- Db 'b' ; Backspace escape character
- Db 'r' ; Carriage return escape character
- Db 'f' ; Form feed escape character
- Db 'x' ; Output character (Hex representation)
- ESCAPE_SIZE Equ This Byte - Escape_Table
- Escape_Jump Label Word
- Dw New_Line ; Newline escape character
- Dw Horz_Tab ; Horizontal tab escape character
- Dw Vert_Tab ; Vertical tab escape character
- Dw Back_Space ; Backspace escape character
- Dw Carr_Ret ; Carriage return escape character
- Dw Form_Feed ; Form feed escape character
- Dw Out_Hex ; Output character (Hex representation)
- Convert_Table Label Byte
- Db '%' ; Print the percent sign
- Db 'c' ; Print next argument as a character
- Db 'C' ; Print next argument as a character
- Db 's' ; Print next argument as a string
- Db 'S' ; Print next argument as a string
- Db 'x' ; Print next argument as HEX (abcdef)
- Db 'X' ; Print next argument as HEX (ABCDEF)
- Db 'h' ; Print next argument as HEX (abcdef)
- Db 'H' ; Print next argument as HEX (ABCDEF)
- Db 'd' ; Print next argument as DECIMAL (+/-)
- Db 'D' ; Print next argument as DECIMAL (+/-)
- Db 'u' ; Print next argument as UNSIGNED
- Db 'U' ; Print next argument as UNSIGNED
- Db 'o' ; Print next argument as OCTAL
- Db 'O' ; Print next argument as OCTAL
- Db 'b' ; Print next argument as BINARY
- Db 'B' ; Print next argument as BINARY
- Db 'f' ; Print next argument as FRACTIONAL
- Db 'F' ; Print next argument as FRACTIONAL
- CONVERT_SIZE Equ This Byte - Convert_Table
- Convert_Jump Label Word
- Dw Print_Format ; Print format routine
- Dw Do_Char ; Print character routine
- Dw Do_Char ; Print character routine
- Dw Do_String ; Print string routine
- Dw Do_String ; Print string routine
- Dw Do_Hex_Lower ; Print lowercase hexadecimal routine
- Dw Do_Hex_Upper ; Print uppercase hexadecimal routine
- Dw Do_Hex_Lower ; Print lowercase hexadecimal routine
- Dw Do_Hex_Upper ; Print uppercase hexadecimal routine
- Dw Do_Decimal ; Print signed decimal routine
- Dw Do_Decimal ; Print signed decimal routine
- Dw Do_Unsigned ; Print unsigned decimal routine
- Dw Do_Unsigned ; Print unsigned decimal routine
- Dw Do_Octal ; Print octal routine
- Dw Do_Octal ; Print octal routine
- Dw Do_Binary ; Print binary routine
- Dw Do_Binary ; Print binary routine
- Dw Do_Fractional ; Print decimal fractional routine
- Dw Do_Fractional ; Print decimal fractional routine
- Digit_Table Label Byte ; Digit translation table
- Db "0123456789abcdef"
- ;******************************************************************************
- ;
- ; Define the end of the Emulator Code Segment
- ;
- ;******************************************************************************
- Emulate Ends
- End ; End of the Printf module