home *** CD-ROM | disk | FTP | other *** search
/ The Unsorted BBS Collection / thegreatunsorted.tar / thegreatunsorted / misc / printf.asm < prev    next >
Assembly Source File  |  1990-03-30  |  69KB  |  1,977 lines

  1.     Page    58,132
  2.     Title    PRINTF.ASM    Generic Printf Routine
  3. ;******************************************************************************
  4. ;
  5. ;   Name:    PRINTF.ASM    Generic Printf Routine
  6. ;
  7. ;   Group:    Emulator
  8. ;
  9. ;   Revision:    1.00
  10. ;
  11. ;   Date:    January 30, 1988
  12. ;
  13. ;   Author:    Randy W. Spurlock
  14. ;
  15. ;******************************************************************************
  16. ;
  17. ;  Module Functional Description:
  18. ;
  19. ;    Printf - Prints a formatted string of arguments to
  20. ;         the requested handle.
  21. ;
  22. ;    Calling Sequence:
  23. ;
  24. ;        lea    bx,ds:[args]    ; Get a pointer to the arguments
  25. ;        lea    si,ds:[format]    ; Get a pointer to the format string
  26. ;        call    printf        ; Call the printf routine
  27. ;
  28. ;    The conversion characters are as follows:
  29. ;
  30. ;        %% - Print percent sign to handle
  31. ;        %c - Output the next argument as a character
  32. ;        %s - Output the next argument as a string
  33. ;        %x - Output the next argument as a hex number using abcdef
  34. ;        %X - Output the next argument as a hex number using ABCDEF
  35. ;        %h - Output the next argument as a hex number using abcdef
  36. ;        %H - Output the next argument as a hex number using ABCDEF
  37. ;        %d - Output the next argument as a decimal number (Signed)
  38. ;        %u - Output the next argument as a decimal number (Unsigned)
  39. ;        %o - Output the next argument as a octal number
  40. ;        %b - Output the next argument as a binary number
  41. ;        %f - Output the next argument as a fractional number (Signed)
  42. ;
  43. ;    Other format specifiers may precede the conversion character:
  44. ;
  45. ;        -  - Left justify the field
  46. ;        +  - Set signed field
  47. ;        n  - Specify the field width/precision
  48. ;        t  - Specify short value
  49. ;        l  - Specify long value
  50. ;        #  - Specify far argument pointer
  51. ;        *  - Variable precision/width value (From argument list)
  52. ;
  53. ;    All arguments must be pointers to the actual values.
  54. ;
  55. ;    The following escape sequences are also handled:
  56. ;
  57. ;        \\   -    Backslash
  58. ;        \n   -    Newline
  59. ;        \t   -    Horizontal Tab
  60. ;        \v   -    Vertical Tab
  61. ;        \b   -    Backspace
  62. ;        \r   -    Carriage Return
  63. ;        \f   -    Form Feed
  64. ;        \ddd -    ASCII Character (Octal Notation)
  65. ;        \xdd -    ASCII Character (Hexadecimal Notation)
  66. ;
  67. ;******************************************************************************
  68. ;
  69. ;  Changes:
  70. ;
  71. ;    DATE     REVISION                DESCRIPTION
  72. ;  --------   --------    -------------------------------------------------------
  73. ;   1/30/88    1.00    Original
  74. ;
  75. ;******************************************************************************
  76.     Page
  77. ;
  78. ;    Public Declarations
  79. ;
  80.     Public    Printf            ; Generic Printf routine
  81. ;
  82. ;  External Declarations
  83. ;
  84.     Extrn    Write_TTY:Near        ; Write TTY routine          (TTY)
  85. ;
  86. ;    Define the Local Equates
  87. ;
  88. FORMAT_CHAR    Equ    "%"             ; Format specification character
  89. ESCAPE_CHAR    Equ    "\"             ; Escape sequence character
  90. HEX        Equ    16        ; Base 16 - Hexadecimal
  91. DECIMAL     Equ    10        ; Base 10 - Decimal
  92. OCTAL        Equ    8        ; Base 8  - Octal
  93. BINARY        Equ    2        ; Base 2  - Binary
  94. FORMAT_LENGTH    Equ    5        ; Maximum format number width
  95. ESCAPE_LENGTH    Equ    3        ; Escape sequence number width (Decimal)
  96. HEX_LENGTH    Equ    2        ; Escape sequence number width (Hex)
  97. MAX_WORD    Equ    0FFFFh        ; Maximum 16-bit count value
  98. MAX_BYTE    Equ    0FFh        ; Maximum 8-bit count value
  99. SPACE_PAD    Equ    " "             ; Space pad character
  100. ZERO_PAD    Equ    "0"             ; Zero pad character
  101. LEFT_JUST    Equ    8000h        ; Left justification flag
  102. SHORT_SPEC    Equ    4000h        ; Short specification flag
  103. LONG_SPEC    Equ    2000h        ; Long specification flag
  104. UPPER_CASE    Equ    1000h        ; Upper case hexadecimal flag
  105. SIGNED_CONV    Equ    0800h        ; Signed conversion flag
  106. SIGNED_TYPE    Equ    0400h        ; Signed type flag
  107. SIGNED_VAL    Equ    0200h        ; Signed value flag
  108. PRE_PAD     Equ    0100h        ; Pre-pad sign character flag
  109. FAR_SPEC    Equ    0080h        ; Far argument specification flag
  110. OVER_FLOW    Equ    0040h        ; Field overflow flag
  111. FRACTIONAL    Equ    0020h        ; Fractional integer flag
  112. VAR_WIDTH    Equ    0010h        ; Variable width flag
  113. VAR_PRE     Equ    0008h        ; Variable precision flag
  114. PAD_CHAR    Equ    0004h        ; Pad character flag (0=Space, 1=Zero)
  115. SIGNED        Equ    8000h        ; Sign flag test mask
  116. WRITE_HANDLE    Equ    40h        ; MS-DOS write handle function code
  117. DECIMAL_ADJUST    Equ    30h        ; ASCII decimal to binary adjust value
  118. HEX_ADJUST    Equ    07h        ; ASCII hex to binary adjust value
  119. UPPER_MASK    Equ    0DFh        ; Lower to upper case mask value
  120. DOS        Equ    21h        ; MS-DOS interrupt call number
  121. FAR_SIZE    Equ    4h        ; Far argument pointer size   (4 bytes)
  122. NEAR_SIZE    Equ    2h        ; Near argument pointer size  (2 bytes)
  123. LONG_SIZE    Equ    4h        ; Long numeric argument size  (4 bytes)
  124. SHORT_SIZE    Equ    2h        ; Short numeric argument size (2 bytes)
  125. BUFF_SIZE    Equ    64        ; Numeric build buffer size
  126. DIGIT_MAX    Equ    39h        ; Maximum ASCII digit value
  127. ;
  128. ;  Define any include files needed
  129. ;
  130.     Include     Macros.inc    ; Include the macro definitions
  131.     Include     Equates.inc    ; Include the equate definitions
  132.     .286c                ; Include 80286 instructions
  133. ;
  134. ;  Define the emulator code segment
  135. ;
  136. Emulate Segment Word Public 'EMULATE'   ; Emulator code segment
  137.     Assume    cs:Emulate, ds:Nothing, es:Nothing
  138.     Subttl    Printf        Generic Printf Routine
  139.     Page    +
  140. ;******************************************************************************
  141. ;
  142. ;  Routine Functional Description
  143. ;
  144. ;    Printf(Format_String, Arguments, Handle)
  145. ;
  146. ;        Save the required registers
  147. ;        While next character from Format_String <> 0
  148. ;            If next character is a format character (percent sign)
  149. ;                Get the next character from Format_String
  150. ;                If a format specifier (+,-,n,l,#,*)
  151. ;                    Set the appropriate specifier flag
  152. ;                Else not a format specifier
  153. ;                    If a conversion character (c,s,x,d,o,b)
  154. ;                        Print argument using conversion
  155. ;                        Increment argument pointer
  156. ;                    Else not a conversion character
  157. ;                        Ignore this format
  158. ;                    Endif
  159. ;                Endif
  160. ;            Else the character is not a format character
  161. ;                If character is a escape character (backslash)
  162. ;                    Get next character from Format_String
  163. ;                    If a valid escape sequence
  164. ;                        Handle the escape sequence
  165. ;                    Else an invalid escape sequence
  166. ;                        Print the character to Handle
  167. ;                    Endif
  168. ;                Else the character is not an escape character
  169. ;                    Print the character to Handle
  170. ;                Endif
  171. ;            Endif
  172. ;        Endwhile
  173. ;        Restore the required registers
  174. ;        Return to the caller
  175. ;
  176. ;    Registers on Entry:
  177. ;
  178. ;        DS:BX = Pointer to Argument List
  179. ;        DS:SI = Pointer to Format String
  180. ;
  181. ;    Registers on Exit:
  182. ;
  183. ;        Direction flag is cleared (Move forward)
  184. ;
  185. ;******************************************************************************
  186. Printf        Proc    Near        ; Generic printf procedure
  187.     Save    ax,bx,cx,dx,si,di,bp,ds,es
  188.     mov    ah,al            ; Save print handle in AH
  189.     cld                ; Clear the direction flag (Forward)
  190. Get_Char:
  191.     call    Clear_Flags        ; Clear all of the specifier flags
  192.     lodsb                ; Get a character from format string
  193.     cmp    al,FORMAT_CHAR        ; Check for a format character (%)
  194.     je    Do_Format        ; Jump if a format character
  195.     cmp    al,ESCAPE_CHAR        ; Check for an escape character (\)
  196.     je    Do_Escape        ; Jump if a escape character
  197.     or    al,al            ; Check for end of the format string
  198.     jnz    Normal_Output        ; Jump if a normal character to output
  199.     jmp    Printf_Exit        ; Jump if end of the format string
  200. Do_Escape:
  201.     lodsb                ; Get next character from format string
  202.     push    cs            ; Put copy of CS onto the stack
  203.     pop    es            ; Put copy of current CS into ES
  204.     lea    di,cs:[Escape_Table]    ; Setup the escape character table
  205.     mov    cx,ESCAPE_SIZE        ; Get the escape character table size
  206.     repne    scasb            ; Scan the escape table for a match
  207.     je    Go_Escape        ; Jump if an there was a table match
  208.     mov    ch,OCTAL        ; Set the current base value to OCTAL
  209.     mov    cl,ESCAPE_LENGTH    ; Set the escape maximum number count
  210.     call    Check_Digit        ; Check for numeric digit (Character)
  211.     jnc    Get_Code        ; Jump if an octal number sequence
  212.     jmp    Normal_Output        ; Jump if an unknown escape character
  213. Get_Code:
  214.     dec    si            ; Backup to the start of the number
  215.     push    dx            ; Save the field width/precision
  216.     call    Get_Number        ; Call routine to get the number
  217.     mov    al,dl            ; Put the character number into AL
  218.     pop    dx            ; Restore the field width/precision
  219.     jmp    Normal_Output        ; Go get next format string character
  220. Go_Escape:
  221.     mov    di,ESCAPE_SIZE        ; Get the escape table size
  222.     sub    di,cx            ; Compute the matching entry number
  223.     dec    di            ; Convert number to zero based
  224.     shl    di,1            ; Make number into jump table index
  225.     call    cs:[di+Escape_Jump]    ; Call the correct routine
  226.     jmp    Get_Char        ; Go get the next character
  227. Normal_Output:
  228.     call    Write_TTY        ; Not a special character, output it
  229.     jmp    Get_Char        ; Go get next format string character
  230. Do_Convert:
  231.     lea    di,cs:[Convert_Table]    ; Setup the convert character table
  232.     mov    cx,CONVERT_SIZE     ; Get the convert character table size
  233.     repne    scasb            ; Scan the convert table for a match
  234.     jne    Get_Char        ; Jump if an unknown convert character
  235.     mov    di,CONVERT_SIZE     ; Get the convert table size
  236.     sub    di,cx            ; Compute the matching entry number
  237.     dec    di            ; Convert number to zero based
  238.     shl    di,1            ; Make number into jump table index
  239.     call    cs:[di+Convert_Jump]    ; Call the correct routine
  240.     jmp    Get_Char        ; Go get the next character
  241. Do_Format:
  242.     lodsb                ; Get next character from format string
  243.     push    cs            ; Put copy of CS onto the stack
  244.     pop    es            ; Put copy of current CS into ES
  245.     lea    di,cs:[Format_Table]    ; Setup the format character table
  246.     mov    cx,FORMAT_SIZE        ; Get the format character table size
  247.     repne    scasb            ; Scan the format table for a match
  248.     je    Go_Format        ; Jump if an there was a table match
  249.     mov    ch,DECIMAL        ; Set the current base value to DECIMAL
  250.     mov    cl,FORMAT_LENGTH    ; Set the format maximum number count
  251.     cmp    al,POINT        ; Check for a decimal point
  252.     jne    Chk_Var         ; Jump if no decimal point found
  253.     dec    si            ; Correct pointer for no width value
  254.     xor    dh,dh            ; Setup a width value of zero
  255.     jmp    Chk_Pre         ; Go check for a precision value
  256. Chk_Var:
  257.     cmp    al,ASTERISK        ; Check for variable width field
  258.     jne    Do_Width        ; Jump if not a variable width field
  259.     or    bp,VAR_WIDTH        ; Set variable width flag bit
  260.     mov    dh,MAX_BYTE        ; Set width value as already set
  261.     jmp    Chk_Pre         ; Go check for a precision value
  262. Do_Width:
  263.     call    Check_Digit        ; Check for numeric digit (Field width)
  264.     jc    Do_Convert        ; Jump if an unknown format character
  265.     dec    si            ; Backup to the start of the number
  266.     or    al,al            ; Check for a leading zero
  267.     jnz    Get_Width        ; Jump if first digit not a zero
  268.     or    bp,PAD_CHAR        ; First digit zero, use zero pad
  269.     or    bp,PRE_PAD        ; Set pre-pad sign character flag
  270. Get_Width:
  271.     call    Get_Number        ; Call routine to get the field width
  272.     mov    dh,dl            ; Save the field width in DH
  273.     cmp    Byte Ptr ds:[si],ASTERISK
  274.     jne    Chk_Pre         ; Jump if not a variable width field
  275.     inc    si            ; Increment past variable character
  276.     or    bp,VAR_WIDTH        ; Set variable width flag bit
  277.     mov    dh,MAX_BYTE        ; Set width value as already set
  278. Chk_Pre:
  279.     xor    dl,dl            ; Setup a precision of zero
  280.     cmp    Byte Ptr ds:[si],POINT    ; Check for a decimal point
  281.     jne    Do_Format        ; Jump if no precision given
  282.     or    bp,FRACTIONAL        ; Set the fractional conversion flag
  283.     dec    dl            ; Set precision as already set
  284.     inc    si            ; Increment past the decimal point
  285.     cmp    Byte Ptr ds:[si],ASTERISK
  286.     jne    Get_Pre         ; Jump if not a variable precision
  287.     inc    si            ; Increment past variable character
  288.     or    bp,VAR_PRE        ; Set variable precision flag bit
  289.     jmp    Do_Format        ; Go check for more format characters
  290. Get_Pre:
  291.     call    Get_Number        ; Call routine to get the precision
  292.     jmp    Do_Format        ; Go check for more format characters
  293. Go_Format:
  294.     mov    di,FORMAT_SIZE        ; Get the format table size
  295.     sub    di,cx            ; Compute the matching entry number
  296.     dec    di            ; Convert number to zero based
  297.     shl    di,1            ; Make number into jump table index
  298.     call    cs:[di+Format_Jump]    ; Call the correct routine
  299.     jmp    Do_Format        ; Go check for more format characters
  300. Printf_Exit:
  301.     Restore ax,bx,cx,dx,si,di,bp,ds,es
  302.     ret                ; Return to the caller
  303. Printf        Endp            ; End of the Printf procedure
  304.     Subttl            Format Specifier Routines
  305.     Page    +
  306. ;******************************************************************************
  307. ;
  308. ;    Format Specifier Routines
  309. ;
  310. ;
  311. ;        These routines handle the following format specifiers:
  312. ;
  313. ;
  314. ;    Specifier        Action Taken
  315. ;    ---------        ------------
  316. ;
  317. ;        -        The following field will be left justified.
  318. ;
  319. ;        +        The following field will be have a sign (+/-)
  320. ;            if it is a signed type field (d).
  321. ;
  322. ;        t        The following field is a short value.
  323. ;
  324. ;        T        The following field is a short value.
  325. ;
  326. ;        l        The following field is a long value.
  327. ;
  328. ;        L        The following field is a long value.
  329. ;
  330. ;        #        The following argument has a far address.
  331. ;
  332. ;
  333. ;        These routines simply set or reset flags which are
  334. ;    used later during actual conversion to perform the special
  335. ;    formatting options.
  336. ;
  337. ;******************************************************************************
  338.     Subttl    Left_Justify    Left Justify Specifier Routine
  339.     Page    +
  340. ;******************************************************************************
  341. ;
  342. ;  Routine Functional Description
  343. ;
  344. ;    Left_Justify()
  345. ;
  346. ;        Set the left justification flag
  347. ;        Return to the caller
  348. ;
  349. ;    Registers on Entry:
  350. ;
  351. ;        None
  352. ;
  353. ;    Registers on Exit:
  354. ;
  355. ;        BP    - Left justification flag set
  356. ;
  357. ;******************************************************************************
  358. Left_Justify    Proc    Near        ; Left justify procedure
  359.     or    bp,LEFT_JUST        ; Set the left justification flag
  360.     ret                ; Return to the caller
  361. Left_Justify    Endp            ; End of the Left_Justify procedure
  362.     Subttl    Set_Signed    Set Signed Conversion Specifier Routine
  363.     Page    +
  364. ;******************************************************************************
  365. ;
  366. ;  Routine Functional Description
  367. ;
  368. ;    Set_Signed()
  369. ;
  370. ;        Set the signed flag
  371. ;        If the field width is non-zero
  372. ;            Set the pre-pad sign flag
  373. ;        Endif
  374. ;        Return to the caller
  375. ;
  376. ;    Registers on Entry:
  377. ;
  378. ;        DH    - Field width (Not given if zero)
  379. ;
  380. ;    Registers on Exit:
  381. ;
  382. ;        BP    - Signed flag set
  383. ;
  384. ;******************************************************************************
  385. Set_Signed    Proc    Near        ; Set signed procedure
  386.     or    bp,SIGNED_CONV        ; Set the signed conversion flag
  387.     or    dh,dh            ; Check the field width
  388.     jz    Sign_Ret        ; Jump if field width not set
  389.     or    bp,PRE_PAD        ; Set the pre-pad sign flag
  390. Sign_Ret:
  391.     ret                ; Return to the caller
  392. Set_Signed    Endp            ; End of the Set_Signed procedure
  393.     Subttl    Short_Specify    Set Short Value Specifier Routine
  394.     Page    +
  395. ;******************************************************************************
  396. ;
  397. ;  Routine Functional Description
  398. ;
  399. ;    Short_Specify()
  400. ;
  401. ;        Set the short specification flag
  402. ;        Return to the caller
  403. ;
  404. ;    Registers on Entry:
  405. ;
  406. ;        None
  407. ;
  408. ;    Registers on Exit:
  409. ;
  410. ;        BP    - Short specification flag set
  411. ;
  412. ;******************************************************************************
  413. Short_Specify    Proc    Near        ; Short specify procedure
  414.     or    bp,SHORT_SPEC        ; Set the short specification flag
  415.     ret                ; Return to the caller
  416. Short_Specify    Endp            ; End of the Short_Specify procedure
  417.     Subttl    Long_Specify    Set Long Value Specifier Routine
  418.     Page    +
  419. ;******************************************************************************
  420. ;
  421. ;  Routine Functional Description
  422. ;
  423. ;    Long_Specify()
  424. ;
  425. ;        Set the long specification flag
  426. ;        Return to the caller
  427. ;
  428. ;    Registers on Entry:
  429. ;
  430. ;        None
  431. ;
  432. ;    Registers on Exit:
  433. ;
  434. ;        BP    - Long specification flag set
  435. ;
  436. ;******************************************************************************
  437. Long_Specify    Proc    Near        ; Long specify procedure
  438.     or    bp,LONG_SPEC        ; Set the long specification flag
  439.     ret                ; Return to the caller
  440. Long_Specify    Endp            ; End of the Long_Specify procedure
  441.     Subttl    Far_Specify    Set Far Address Specifier Routine
  442.     Page    +
  443. ;******************************************************************************
  444. ;
  445. ;  Routine Functional Description
  446. ;
  447. ;    Far_Specify()
  448. ;
  449. ;        Set the far specification flag
  450. ;        Return to the caller
  451. ;
  452. ;    Registers on Entry:
  453. ;
  454. ;        None
  455. ;
  456. ;    Registers on Exit:
  457. ;
  458. ;        BP    - Far specification flag set
  459. ;
  460. ;******************************************************************************
  461. Far_Specify    Proc    Near        ; Far specify procedure
  462.     or    bp,FAR_SPEC        ; Set the far specification flag
  463.     ret                ; Return to the caller
  464. Far_Specify    Endp            ; End of the Far_Specify procedure
  465.     Subttl            Escape Sequence Routines
  466.     Page    +
  467. ;******************************************************************************
  468. ;
  469. ;    Escape Sequence Routines
  470. ;
  471. ;
  472. ;        These routines handle the following escape sequences:
  473. ;
  474. ;
  475. ;    Character        Escape Sequence
  476. ;    ---------        ---------------
  477. ;
  478. ;        n        Newline is output to requested handle
  479. ;
  480. ;        t        Horizontal tab is output to requested handle
  481. ;
  482. ;        v        Vertical tab is output to requested handle
  483. ;
  484. ;        b        Backspace is output to requested handle
  485. ;
  486. ;        r        Carriage return is output to requested handle
  487. ;
  488. ;        f        Form feed is output to requested handle
  489. ;
  490. ;        x        Character is output to requested handle (Hex code)
  491. ;
  492. ;
  493. ;        All of these routines except for the "x" escape
  494. ;    sequence simply send the desired character(s) out to the
  495. ;    requested handle. The "x" routine get the hexadecimal
  496. ;    number given and outputs the corresponding character to
  497. ;    the requested handle.
  498. ;
  499. ;******************************************************************************
  500.     Subttl    New_Line    New Line Escape Sequence Routine
  501.     Page    +
  502. ;******************************************************************************
  503. ;
  504. ;  Routine Functional Description
  505. ;
  506. ;    New_Line(Handle)
  507. ;
  508. ;        Output carriage return to handle
  509. ;        Output line feed to handle
  510. ;        Return to the caller
  511. ;
  512. ;    Registers on Entry:
  513. ;
  514. ;        AH    - Handle
  515. ;
  516. ;    Registers on Exit:
  517. ;
  518. ;        AL    - Destroyed
  519. ;
  520. ;******************************************************************************
  521. New_Line    Proc    Near        ; Output new line procedure
  522.     mov    al,CR            ; Get carriage return ASCII character
  523.     call    Write_TTY        ; Output the carriage return to handle
  524.     mov    al,LF            ; Get a line feed ASCII character
  525.     call    Write_TTY        ; Output the line feed to handle
  526.     ret                ; Return to the caller
  527. New_Line    Endp            ; End of the New_Line procedure
  528.     Subttl    Horz_Tab    Horizontal Tab Escape Sequence Routine
  529.     Page    +
  530. ;******************************************************************************
  531. ;
  532. ;  Routine Functional Description
  533. ;
  534. ;    Horz_Tab(Handle)
  535. ;
  536. ;        Output horizontal tab to handle
  537. ;        Return to the caller
  538. ;
  539. ;    Registers on Entry:
  540. ;
  541. ;        AH    - Handle
  542. ;
  543. ;    Registers on Exit:
  544. ;
  545. ;        AL    - Destroyed
  546. ;
  547. ;******************************************************************************
  548. Horz_Tab    Proc    Near        ; Output horizontal tab procedure
  549.     mov    al,HT            ; Get horizontal tab ASCII character
  550.     call    Write_TTY        ; Output the horizontal tab to handle
  551.     ret                ; Return to the caller
  552. Horz_Tab    Endp            ; End of the Horz_Tab procedure
  553.     Subttl    Vert_Tab    Vertical Tab Escape Sequence Routine
  554.     Page    +
  555. ;******************************************************************************
  556. ;
  557. ;  Routine Functional Description
  558. ;
  559. ;    Vert_Tab(Handle)
  560. ;
  561. ;        Output vertical tab to handle
  562. ;        Return to the caller
  563. ;
  564. ;    Registers on Entry:
  565. ;
  566. ;        AH    - Handle
  567. ;
  568. ;    Registers on Exit:
  569. ;
  570. ;        AL    - Destroyed
  571. ;
  572. ;******************************************************************************
  573. Vert_Tab    Proc    Near        ; Output vertical tab procedure
  574.     mov    al,VT            ; Get vertical tab ASCII character
  575.     call    Write_TTY        ; Output the vertical tab to handle
  576.     ret                ; Return to the caller
  577. Vert_Tab    Endp            ; End of the Vert_Tab procedure
  578.     Subttl    Back_Space    Back Space Escape Sequence Routine
  579.     Page    +
  580. ;******************************************************************************
  581. ;
  582. ;  Routine Functional Description
  583. ;
  584. ;    Back_Space(Handle)
  585. ;
  586. ;        Output backspace to handle
  587. ;        Return to the caller
  588. ;
  589. ;    Registers on Entry:
  590. ;
  591. ;        AH    - Handle
  592. ;
  593. ;    Registers on Exit:
  594. ;
  595. ;        AL    - Destroyed
  596. ;
  597. ;******************************************************************************
  598. Back_Space    Proc    Near        ; Output backspace procedure
  599.     mov    al,BS            ; Get backspace ASCII character
  600.     call    Write_TTY        ; Output the backspace to handle
  601.     ret                ; Return to the caller
  602. Back_Space    Endp            ; End of the Back_Space procedure
  603.     Subttl    Carr_Ret    Carriage Return Escape Sequence Routine
  604.     Page    +
  605. ;******************************************************************************
  606. ;
  607. ;  Routine Functional Description
  608. ;
  609. ;    Carr_Ret(Handle)
  610. ;
  611. ;        Output carriage return to handle
  612. ;        Return to the caller
  613. ;
  614. ;    Registers on Entry:
  615. ;
  616. ;        AH    - Handle
  617. ;
  618. ;    Registers on Exit:
  619. ;
  620. ;        AL    - Destroyed
  621. ;
  622. ;******************************************************************************
  623. Carr_Ret    Proc    Near        ; Output carriage return procedure
  624.     mov    al,CR            ; Get carriage return ASCII character
  625.     call    Write_TTY        ; Output the carriage return to handle
  626.     ret                ; Return to the caller
  627. Carr_Ret    Endp            ; End of the Carr_Ret procedure
  628.     Subttl    Form_Feed    Form Feed Escape Sequence Routine
  629.     Page    +
  630. ;******************************************************************************
  631. ;
  632. ;  Routine Functional Description
  633. ;
  634. ;    Form_Feed(Handle)
  635. ;
  636. ;        Output form feed to handle
  637. ;        Return to the caller
  638. ;
  639. ;    Registers on Entry:
  640. ;
  641. ;        AH    - Handle
  642. ;
  643. ;    Registers on Exit:
  644. ;
  645. ;        AL    - Destroyed
  646. ;
  647. ;******************************************************************************
  648. Form_Feed    Proc    Near        ; Output form feed procedure
  649.     mov    al,FF            ; Get form feed ASCII character
  650.     call    Write_TTY        ; Output the form feed to handle
  651.     ret                ; Return to the caller
  652. Form_Feed    Endp            ; End of the Form_Feed procedure
  653.     Subttl    Out_Hex     Output Hex Escape Sequence Routine
  654.     Page    +
  655. ;******************************************************************************
  656. ;
  657. ;  Routine Functional Description
  658. ;
  659. ;    Out_Hex(String, Handle)
  660. ;
  661. ;        Set number base to hexadecimal
  662. ;        Set maximum number length
  663. ;        Call routine to get the number
  664. ;        Output the number (Character) to handle
  665. ;        Return to the caller
  666. ;
  667. ;    Registers on Entry:
  668. ;
  669. ;        AH    - Handle
  670. ;        DS:SI - Pointer to number
  671. ;
  672. ;    Registers on Exit:
  673. ;
  674. ;        AL    - Destroyed
  675. ;        CX    - Destroyed
  676. ;        DL    - Destroyed
  677. ;        DS:SI - Pointer set to first character past number
  678. ;
  679. ;******************************************************************************
  680. Out_Hex     Proc    Near        ; Output hex character procedure
  681.     mov    ch,HEX            ; Set number base to hexadecimal
  682.     mov    cl,HEX_LENGTH        ; Set maximum hex digit length
  683.     call    Get_Number        ; Call routine to get the number
  684.     jc    Out_Exit        ; Jump if no number present
  685.     mov    al,dl            ; Move the number value into AL
  686.     call    Write_TTY        ; Output the corresponding character
  687. Out_Exit:
  688.     ret                ; Return to the caller
  689. Out_Hex     Endp            ; End of the Out_Hex procedure
  690.     Subttl            Conversion Formatting Routines
  691.     Page    +
  692. ;******************************************************************************
  693. ;
  694. ;    Conversion Formatting Routines
  695. ;
  696. ;
  697. ;        These routines handle the following conversion types:
  698. ;
  699. ;
  700. ;    Character        Conversion Done
  701. ;    ---------        ---------------
  702. ;
  703. ;        c        Convert next argument as a character
  704. ;
  705. ;        s        Convert next argument as a string
  706. ;
  707. ;        x        Convert next argument as a hex number using abcdef
  708. ;
  709. ;        X        Convert next argument as a hex number using ABCDEF
  710. ;
  711. ;        d        Convert next argument as a decimal number (Signed)
  712. ;
  713. ;        u        Convert next argument as a decimal number (Unsigned)
  714. ;
  715. ;        o        Convert next argument as a octal number
  716. ;
  717. ;        b        Convert next argument as a binary number
  718. ;
  719. ;
  720. ;        These routines format the arguments passed to them.
  721. ;    Numeric arguments can be either word or double word (long)
  722. ;    values and for the decimal option it can be formatted as
  723. ;    signed or unsigned. All arguments are passed as pointers,
  724. ;    either near or far, to the actual argument value.
  725. ;
  726. ;******************************************************************************
  727.     Subttl    Do_Char     Character Formatting Routine
  728.     Page    +
  729. ;******************************************************************************
  730. ;
  731. ;  Routine Functional Description
  732. ;
  733. ;    Do_Char(Argument, Handle, Flags)
  734. ;
  735. ;        Save the required registers
  736. ;        Call routine to get the character address
  737. ;        If field width is not set (Zero)
  738. ;            Set field width to character value (1)
  739. ;        Endif
  740. ;        If character length (1) > field width
  741. ;            Set the field overflow flag
  742. ;            Set character length to field width
  743. ;        Endif
  744. ;        Set pad character to a space
  745. ;        Call routine to calculate pad counts
  746. ;        Call routine to output pre-string pad characters
  747. ;        Get character to output
  748. ;        Call routine to output character to handle
  749. ;        Call routine to output post-string pad characters
  750. ;        Restore the required registers
  751. ;        Return to the caller
  752. ;
  753. ;    Registers on Entry:
  754. ;
  755. ;        AH    - Handle
  756. ;        DS:BX - Pointer to argument
  757. ;        DH    - Current field width
  758. ;        BP    - Formatting flags
  759. ;
  760. ;    Registers on Exit:
  761. ;
  762. ;        AL    - Destroyed
  763. ;        BX    - Points to next argument
  764. ;        CX    - Destroyed
  765. ;        DL    - Destroyed
  766. ;        DI    - Destroyed
  767. ;        ES    - Destroyed
  768. ;
  769. ;******************************************************************************
  770. Do_Char     Proc    Near        ; Character formatting procedure
  771.     Save    si,ds            ; Save the required registers
  772.     call    Variable        ; Call routine to check width/precision
  773.     call    Get_Address        ; Call routine to get argument address
  774.     mov    cl,1            ; Set actual width to character value
  775.     or    dh,dh            ; Check the current field width
  776.     jnz    Width_Chk        ; Jump if field width specified
  777.     mov    dh,1            ; Set field width to character length
  778. Width_Chk:
  779.     cmp    cl,dh            ; Compare actual width to given width
  780.     jbe    Send_Pre        ; Jump if string fits in field width
  781.     or    bp,OVER_FLOW        ; Set the field overflow flag
  782.     mov    cl,dh            ; Clip string to the field width
  783. Send_Pre:
  784.     mov    al,cl            ; Save the actual string length
  785.     and    bp,Not PAD_CHAR     ; Set current pad character to a space
  786.     call    Calculate        ; Call routine to calculate pad values
  787.     call    Pad            ; Call routine to send pad characters
  788. Send_Char:
  789.     lodsb                ; Get the character to output
  790.     call    Write_TTY        ; Call routine to output the character
  791. Send_Post:
  792.     mov    cl,ch            ; Get the calculated pad counts
  793.     call    Pad            ; Call routine to send pad characters
  794.     Restore si,ds            ; Restore the required registers
  795.     ret                ; Return to the caller
  796. Do_Char     Endp            ; End of the Do_Char procedure
  797.     Subttl    Do_String    String Formatting Routine
  798.     Page    +
  799. ;******************************************************************************
  800. ;
  801. ;  Routine Functional Description
  802. ;
  803. ;    Do_String(Argument, Handle, Width, Flags)
  804. ;
  805. ;        Save the required registers
  806. ;        Call routine to get the string address
  807. ;        Call routine to compute string length
  808. ;        If field width is not set (Zero)
  809. ;            Set field width to string length
  810. ;        Endif
  811. ;        If string length > field width
  812. ;            Set the field overflow flag
  813. ;            Set string length to field width
  814. ;        Endif
  815. ;        Set pad character to a space
  816. ;        Call routine to calculate pad counts
  817. ;        Call routine to output pre-string pad characters
  818. ;        While length > 0
  819. ;            Get next character of string
  820. ;            Call routine to output character to handle
  821. ;            Decrement the length
  822. ;        Endwhile
  823. ;        Call routine to output post-string pad characters
  824. ;        Restore the required registers
  825. ;        Return to the caller
  826. ;
  827. ;    Registers on Entry:
  828. ;
  829. ;        AH    - Handle
  830. ;        DS:BX - Pointer to argument
  831. ;        DH    - Current field width
  832. ;        BP    - Formatting flags
  833. ;
  834. ;    Registers on Exit:
  835. ;
  836. ;        AL    - Destroyed
  837. ;        BX    - Points to next argument
  838. ;        CX    - Destroyed
  839. ;        DL    - Destroyed
  840. ;        DI    - Destroyed
  841. ;        ES    - Destroyed
  842. ;
  843. ;******************************************************************************
  844. Do_String    Proc    Near        ; String formatting procedure
  845.     Save    si,ds            ; Save the required registers
  846.     call    Variable        ; Call routine to check width/precision
  847.     call    Get_Address        ; Call routine to get argument address
  848.     call    Get_Length        ; Call routine to get string length
  849.     jz    String_Exit        ; Jump if nothing to output
  850.     or    dh,dh            ; Check the current field width
  851.     jnz    Chk_Width        ; Jump if field width specified
  852.     mov    dh,cl            ; Set field width to string length
  853. Chk_Width:
  854.     cmp    cl,dh            ; Compare actual width to given width
  855.     jbe    Do_Pre            ; Jump if string fits in field width
  856.     or    bp,OVER_FLOW        ; Set the field overflow flag
  857.     mov    cl,dh            ; Clip string to the field width
  858. Do_Pre:
  859.     mov    al,cl            ; Save the actual string length
  860.     and    bp,Not PAD_CHAR     ; Set current pad character to a space
  861.     call    Calculate        ; Call routine to calculate pad values
  862.     mov    dl,al            ; Setup the string output length
  863.     call    Pad            ; Call routine to send pad characters
  864. Send_String:
  865.     lodsb                ; Get the next string character
  866.     call    Write_TTY        ; Call routine to output the character
  867.     dec    dl            ; Decrement the output length
  868.     jnz    Send_String        ; Go get next character if more left
  869. Do_Post:
  870.     mov    cl,ch            ; Get the calculated pad counts
  871.     call    Pad            ; Call routine to send pad characters
  872. String_Exit:
  873.     Restore si,ds            ; Restore the required registers
  874.     ret                ; Return to the caller
  875. Do_String    Endp            ; End of the Do_String procedure
  876.     Subttl    Do_Hex        Hexadecimal Formatting Routine
  877.     Page    +
  878. ;******************************************************************************
  879. ;
  880. ;  Routine Functional Description
  881. ;
  882. ;    Do_Hex(Argument, Handle, Width, Precision, Flags, Type)
  883. ;
  884. ;        Save the required registers
  885. ;        If type is uppercase
  886. ;            Set the uppercase format flag
  887. ;        Endif
  888. ;        Set current number base to hexadecimal
  889. ;        Call routine to get the argument address
  890. ;        Call routine to output the numeric string
  891. ;        Restore the required registers
  892. ;        Return to the caller
  893. ;
  894. ;    Registers on Entry:
  895. ;
  896. ;        AH    - Handle
  897. ;        DS:BX - Pointer to argument
  898. ;        DH    - Current field width
  899. ;        DL    - Current field precision
  900. ;        BP    - Formatting flags
  901. ;
  902. ;    Registers on Exit:
  903. ;
  904. ;        BX    - Points to next argument
  905. ;
  906. ;******************************************************************************
  907. Do_Hex        Proc    Near        ; Hexadecimal formatting procedure
  908. Do_Hex_Upper    Label    Near        ; Do_Hex_Upper entry point (ABCDEF)
  909.     or    bp,UPPER_CASE        ; Set uppercase formatting flag
  910. Do_Hex_Lower    Label    Near        ; Do_Hex_Lower entry point (abcdef)
  911.     Save    si,ds            ; Save the required registers
  912.     call    Variable        ; Call routine to check width/precision
  913.     mov    ch,HEX            ; Set the current number base to hex
  914.     call    Get_Address        ; Call routine to get argument address
  915.     call    Compute         ; Call routine to output number
  916.     Restore si,ds            ; Restore the required registers
  917.     ret                ; Return to the caller
  918. Do_Hex        Endp            ; End of the Do_Hex procedure
  919.     Subttl    Do_Decimal    Decimal Formatting Routine
  920.     Page    +
  921. ;******************************************************************************
  922. ;
  923. ;  Routine Functional Description
  924. ;
  925. ;    Do_Decimal(Argument, Handle, Width, Precision, Flags)
  926. ;
  927. ;        Save the required registers
  928. ;        Set the signed type formatting flag
  929. ;        Set current number base to decimal
  930. ;        Call routine to get the argument address
  931. ;        Call routine to output the numeric string
  932. ;        Restore the required registers
  933. ;        Return to the caller
  934. ;
  935. ;    Registers on Entry:
  936. ;
  937. ;        AH    - Handle
  938. ;        DS:BX - Pointer to argument
  939. ;        DH    - Current field width
  940. ;        DL    - Current field precision
  941. ;        BP    - Formatting flags
  942. ;
  943. ;    Registers on Exit:
  944. ;
  945. ;        BX    - Points to next argument
  946. ;
  947. ;******************************************************************************
  948. Do_Decimal    Proc    Near        ; Decimal formatting procedure
  949.     Save    si,ds            ; Save the required registers
  950.     call    Variable        ; Call routine to check width/precision
  951.     or    bp,SIGNED_TYPE        ; Set signed type formatting flag
  952.     mov    ch,DECIMAL        ; Set current number base to decimal
  953.     call    Get_Address        ; Call routine to get argument address
  954.     call    Compute         ; Call routine to output number
  955.     Restore si,ds            ; Restore the required registers
  956.     ret                ; Return to the caller
  957. Do_Decimal    Endp            ; End of the Do_Decimal procedure
  958.     Subttl    Do_Unsigned    Unsigned Decimal Formatting Routine
  959.     Page    +
  960. ;******************************************************************************
  961. ;
  962. ;  Routine Functional Description
  963. ;
  964. ;    Do_Unsigned(Argument, Handle, Width, Precision, Flags)
  965. ;
  966. ;        Save the required registers
  967. ;        Set current number base to decimal
  968. ;        Call routine to get the argument address
  969. ;        Call routine to output the numeric string
  970. ;        Restore the required registers
  971. ;        Return to the caller
  972. ;
  973. ;    Registers on Entry:
  974. ;
  975. ;        AH    - Handle
  976. ;        DS:BX - Pointer to argument
  977. ;        DH    - Current field width
  978. ;        DL    - Current field precision
  979. ;        BP    - Formatting flags
  980. ;
  981. ;    Registers on Exit:
  982. ;
  983. ;        BX    - Points to next argument
  984. ;
  985. ;******************************************************************************
  986. Do_Unsigned    Proc    Near        ; Unsigned decimal formatting procedure
  987.     Save    si,ds            ; Save the required registers
  988.     call    Variable        ; Call routine to check width/precision
  989.     mov    ch,DECIMAL        ; Set current number base to decimal
  990.     call    Get_Address        ; Call routine to get argument address
  991.     call    Compute         ; Call routine to output number
  992.     Restore si,ds            ; Restore the required registers
  993.     ret                ; Return to the caller
  994. Do_Unsigned    Endp            ; End of the Do_Unsigned procedure
  995.     Subttl    Do_Octal    Octal Formatting Routine
  996.     Page    +
  997. ;******************************************************************************
  998. ;
  999. ;  Routine Functional Description
  1000. ;
  1001. ;    Do_Octal(Argument, Handle, Width, Precision, Flags)
  1002. ;
  1003. ;        Save the required registers
  1004. ;        Set current number base to octal
  1005. ;        Call routine to get the argument address
  1006. ;        Call routine to output the numeric string
  1007. ;        Restore the required registers
  1008. ;        Return to the caller
  1009. ;
  1010. ;    Registers on Entry:
  1011. ;
  1012. ;        AH    - Handle
  1013. ;        DS:BX - Pointer to argument
  1014. ;        DH    - Current field width
  1015. ;        DL    - Current field precision
  1016. ;        BP    - Formatting flags
  1017. ;
  1018. ;    Registers on Exit:
  1019. ;
  1020. ;        BX    - Points to next argument
  1021. ;
  1022. ;******************************************************************************
  1023. Do_Octal    Proc    Near        ; Octal formatting procedure
  1024.     Save    si,ds            ; Save the required registers
  1025.     call    Variable        ; Call routine to check width/precision
  1026.     mov    ch,OCTAL        ; Set current number base to octal
  1027.     call    Get_Address        ; Call routine to get argument address
  1028.     call    Compute         ; Call routine to output number
  1029.     Restore si,ds            ; Restore the required registers
  1030.     ret                ; Return to the caller
  1031. Do_Octal    Endp            ; End of the Do_Octal procedure
  1032.     Subttl    Do_Binary    Binary Formatting Routine
  1033.     Page    +
  1034. ;******************************************************************************
  1035. ;
  1036. ;  Routine Functional Description
  1037. ;
  1038. ;    Do_Binary(Argument, Handle, Width, Precision, Flags)
  1039. ;
  1040. ;        Save the required registers
  1041. ;        Set current number base to binary
  1042. ;        Call routine to get the argument address
  1043. ;        Call routine to output the numeric string
  1044. ;        Retore the required registers
  1045. ;        Return to the caller
  1046. ;
  1047. ;    Registers on Entry:
  1048. ;
  1049. ;        AH    - Handle
  1050. ;        DS:BX - Pointer to argument
  1051. ;        DH    - Current field width
  1052. ;        DL    - Current field precision
  1053. ;        BP    - Formatting flags
  1054. ;
  1055. ;    Registers on Exit:
  1056. ;
  1057. ;        BX    - Points to next argument
  1058. ;
  1059. ;******************************************************************************
  1060. Do_Binary    Proc    Near        ; Binary formatting procedure
  1061.     Save    si,ds            ; Save the required registers
  1062.     call    Variable        ; Call routine to check width/precision
  1063.     mov    ch,BINARY        ; Set current number base to binary
  1064.     call    Get_Address        ; Call routine to get argument address
  1065.     call    Compute         ; Call routine to output number
  1066.     Restore si,ds            ; Restore the required registers
  1067.     ret                ; Return to the caller
  1068. Do_Binary    Endp            ; End of the Do_Binary procedure
  1069.     Subttl    Do_Fractional    Fractional Formatting Routine
  1070.     Page    +
  1071. ;******************************************************************************
  1072. ;
  1073. ;  Routine Functional Description
  1074. ;
  1075. ;    Do_Fractional(Argument, Handle, Width, Precision, Flags)
  1076. ;
  1077. ;        Save the required registers
  1078. ;        Set the signed type formatting flag
  1079. ;        Set current number base to decimal
  1080. ;        Call routine to get the argument address
  1081. ;        Call routine to output the numeric string
  1082. ;        Restore the required registers
  1083. ;        Return to the caller
  1084. ;
  1085. ;    Registers on Entry:
  1086. ;
  1087. ;        AH    - Handle
  1088. ;        DS:BX - Pointer to argument
  1089. ;        DH    - Current field width
  1090. ;        DL    - Current field precision
  1091. ;        BP    - Formatting flags
  1092. ;
  1093. ;    Registers on Exit:
  1094. ;
  1095. ;        BX    - Points to next argument
  1096. ;
  1097. ;******************************************************************************
  1098. Do_Fractional    Proc    Near        ; Fractional formatting procedure
  1099.     Save    si,ds            ; Save the required registers
  1100.     call    Variable        ; Call routine to check width/precision
  1101.     or    bp,SIGNED_TYPE        ; Set signed type formatting flag
  1102.     or    bp,FRACTIONAL        ; Set the fractional formatting flag
  1103.     mov    ch,DECIMAL        ; Set current number base to decimal
  1104.     call    Get_Address        ; Call routine to get argument address
  1105.     call    Compute         ; Call routine to output number
  1106.     Restore si,ds            ; Restore the required registers
  1107.     ret                ; Return to the caller
  1108. Do_Fractional    Endp            ; End of the Do_Fractional procedure
  1109.     Subttl    Get_Address    Get Argument Address Routine
  1110.     Page    +
  1111. ;******************************************************************************
  1112. ;
  1113. ;  Routine Functional Description
  1114. ;
  1115. ;    Get_Address(Argument, Flags)
  1116. ;
  1117. ;        If far format specifier has been set
  1118. ;            Set DS:SI to far pointer at DS:BX
  1119. ;            Increment BX to next argument (4)
  1120. ;        Else no far specifier
  1121. ;            Set SI to near pointer at DS:BX
  1122. ;            Increment BX to next argument (2)
  1123. ;        Endif
  1124. ;        Return to the caller
  1125. ;
  1126. ;    Registers on Entry:
  1127. ;
  1128. ;        DS:BX - Pointer to argument list
  1129. ;        BP    - Formatting flags
  1130. ;
  1131. ;    Registers on Exit:
  1132. ;
  1133. ;        DS:SI - New address pointer (Character or string)
  1134. ;        BX    - Points to the next argument
  1135. ;
  1136. ;******************************************************************************
  1137. Get_Address    Proc    Near        ; Get address procedure
  1138.     test    bp,FAR_SPEC        ; Check for far specifier set
  1139.     jz    Near_Addr        ; Jump if a normal near address
  1140. Far_Addr:
  1141.     lds    si,Dword Ptr ds:[bx]    ; Load the far address into DS:SI
  1142.     add    bx,FAR_SIZE        ; Update the argument pointer value
  1143.     jmp    Get_Exit        ; Go return to the caller
  1144. Near_Addr:
  1145.     mov    si,Word Ptr ds:[bx]    ; Load the near address into SI
  1146.     add    bx,NEAR_SIZE        ; Update the argument pointer value
  1147. Get_Exit:
  1148.     ret                ; Return to the caller
  1149. Get_Address    Endp            ; End of the Get_Address procedure
  1150.     Subttl    Variable    Get Variable Value Routine
  1151.     Page    +
  1152. ;******************************************************************************
  1153. ;
  1154. ;  Routine Functional Description
  1155. ;
  1156. ;    Variable(Width, Precision, Flags)
  1157. ;
  1158. ;        Save the required registers
  1159. ;        If variable width specified
  1160. ;            Get the actual width value (Byte)
  1161. ;        Endif
  1162. ;        If variable precision specified
  1163. ;            Get the actual precision value (Byte)
  1164. ;        Endif
  1165. ;        Restore the required registers
  1166. ;        Return to the caller
  1167. ;
  1168. ;    Registers on Entry:
  1169. ;
  1170. ;        DS:BX - Pointer to argument list
  1171. ;        BP    - Formatting flags
  1172. ;
  1173. ;    Registers on Exit:
  1174. ;
  1175. ;        DH    - Actual width value
  1176. ;        DL    - Actual precision value
  1177. ;        BX    - Points to the next argument
  1178. ;
  1179. ;******************************************************************************
  1180. Variable    Proc    Near        ; Get variable width/precision procedure
  1181.     Save    si            ; Save the required registers
  1182.     test    bp,VAR_WIDTH        ; Check for a variable width value
  1183.     jz    Pre_Chk         ; Jump if no variable width
  1184.     mov    si,Word Ptr ds:[bx]    ; Load the near address into SI
  1185.     add    bx,NEAR_SIZE        ; Update the argument pointer value
  1186.     mov    dh,Byte Ptr ds:[si]    ; Get the actual field width value
  1187. Pre_Chk:
  1188.     test    bp,VAR_PRE        ; Check for a variable precision value
  1189.     jz    Var_Exit        ; Jump if no variable precision
  1190.     mov    si,Word Ptr ds:[bx]    ; Load the near address into SI
  1191.     add    bx,NEAR_SIZE        ; Update the argument pointer value
  1192.     mov    dl,Byte Ptr ds:[si]    ; Get the actual precision value
  1193. Var_Exit:
  1194.     Restore si            ; Restore the required registers
  1195.     ret                ; Return to the caller
  1196. Variable    Endp            ; End of the Variable procedure
  1197.     Subttl    Get_Length    Get String Length Routine
  1198.     Page    +
  1199. ;******************************************************************************
  1200. ;
  1201. ;  Routine Functional Description
  1202. ;
  1203. ;    Get_Length(String)
  1204. ;
  1205. ;        Calculate the length of the string (Null terminator)
  1206. ;        Return to the caller
  1207. ;
  1208. ;    Registers on Entry:
  1209. ;
  1210. ;        DS:SI - Pointer to string
  1211. ;
  1212. ;    Registers on Exit:
  1213. ;
  1214. ;        AL    - Destroyed
  1215. ;        CX    - String length
  1216. ;        DI    - Destroyed
  1217. ;        ES    - Destroyed
  1218. ;        ZR    - Zero set if zero length
  1219. ;
  1220. ;******************************************************************************
  1221. Get_Length    Proc    Near        ; Get string length procedure
  1222.     push    ds            ; Put a copy of DS onto the stack
  1223.     pop    es            ; Set ES to the current DS value
  1224.     mov    di,si            ; Set DI to the current SI value
  1225.     mov    al,NULL         ; Setup to scan for null terminator
  1226.     mov    cx,MAX_WORD        ; Setup to scan for maximum length
  1227.     repne    scasb            ; Scan for the string terminator
  1228.     not    cx            ; Correct the count value
  1229.     dec    cx            ; Adjust to get actual string length
  1230.     ret                ; Return to the caller
  1231. Get_Length    Endp            ; End of the Get_Length procedure
  1232.     Subttl    Calculate    Calculate Pad Lengths Routine
  1233.     Page    +
  1234. ;******************************************************************************
  1235. ;
  1236. ;  Routine Functional Description
  1237. ;
  1238. ;    Calculate(Width, Length)
  1239. ;
  1240. ;        Save the required registers
  1241. ;        Calculate total pad length
  1242. ;        If total pad length > 0
  1243. ;            If left justification is not requested
  1244. ;                Set pre pad count to total
  1245. ;                Zero post pad count
  1246. ;            Else left justification requested
  1247. ;                Set post pad count to total
  1248. ;                Zero pre pad count
  1249. ;            Endif
  1250. ;        Else total pad length < 0
  1251. ;            Set pre pad count to zero
  1252. ;            Set post pad count to zero
  1253. ;        Endif
  1254. ;        Restore the required registers
  1255. ;        Return to the caller
  1256. ;
  1257. ;    Registers on Entry:
  1258. ;
  1259. ;        CL    - Length of the string
  1260. ;        DH    - Field width
  1261. ;        BP    - Formatting flags
  1262. ;
  1263. ;    Registers on Exit:
  1264. ;
  1265. ;        CH    - Post string pad count
  1266. ;        CL    - Pre string pad count
  1267. ;
  1268. ;******************************************************************************
  1269. Calculate    Proc    Near        ; Calculate pad length procedure
  1270.     Save    ax            ; Save the required registers
  1271.     mov    al,dh            ; Get the current field width
  1272.     mov    ah,cl            ; Get the length of the output string
  1273.     xor    cx,cx            ; Default pre/post pad counts to zero
  1274.     sub    al,ah            ; Compute the total pad count
  1275.     jbe    Calc_Exit        ; Jump if no pad necessary
  1276.     mov    cl,al            ; Default to right justification
  1277.     test    bp,LEFT_JUST        ; Check if left justify was specified
  1278.     jz    Calc_Exit        ; Jump if no left justification
  1279.     mov    ch,cl            ; Make post pad count the total count
  1280.     xor    cl,cl            ; Zero the pre pad count value
  1281. Calc_Exit:
  1282.     Restore ax            ; Restore the required registers
  1283.     ret                ; Return to the caller
  1284. Calculate    Endp            ; End of the Calculate procedure
  1285.     Subttl    Pad        Output Pad Characters Routine
  1286.     Page    +
  1287. ;******************************************************************************
  1288. ;
  1289. ;  Routine Functional Description
  1290. ;
  1291. ;    Pad(Handle, Pad, Count)
  1292. ;
  1293. ;        Save the required registers
  1294. ;        While count > 0
  1295. ;            Output the current pad character
  1296. ;            Decrement the count
  1297. ;        Endwhile
  1298. ;        Restore the required registers
  1299. ;        Return to the caller
  1300. ;
  1301. ;    Registers on Entry:
  1302. ;
  1303. ;        AH    - Handle
  1304. ;        CL    - Pad count
  1305. ;
  1306. ;    Registers on Exit:
  1307. ;
  1308. ;        CL    - Destroyed
  1309. ;
  1310. ;******************************************************************************
  1311. Pad        Proc    Near        ; Pad character procedure
  1312.     Save    ax            ; Save the required registers
  1313.     or    cl,cl            ; Check for no padding required
  1314.     jz    Pad_Exit        ; Jump if no padding is required
  1315.     mov    al,SPACE_PAD        ; Default to a space pad character
  1316.     test    bp,PAD_CHAR        ; Check for a zero pad character
  1317.     jz    Pad_Loop        ; Jump if using a space pad character
  1318.     mov    al,ZERO_PAD        ; Setup to use a zero pad character
  1319. Pad_Loop:
  1320.     call    Write_TTY        ; Call routine to output pad character
  1321.     dec    cl            ; Decrement the pad count
  1322.     jnz    Pad_Loop        ; Jump if more pad characters to send
  1323. Pad_Exit:
  1324.     Restore ax            ; Restore the required registers
  1325.     ret                ; Return to the caller
  1326. Pad        Endp            ; End of the Pad procedure
  1327.     Subttl    Clear_Flags    Clear All Flags Routine
  1328.     Page    +
  1329. ;******************************************************************************
  1330. ;
  1331. ;  Routine Functional Description
  1332. ;
  1333. ;    Clear_Flags(Flags)
  1334. ;
  1335. ;        Clear the formatting flags
  1336. ;        Default to space padding
  1337. ;        Zero the current field width
  1338. ;        Clear direction flag (All string operations forward)
  1339. ;        Return to the caller
  1340. ;
  1341. ;    Registers on Entry:
  1342. ;
  1343. ;        None
  1344. ;
  1345. ;    Registers on Exit:
  1346. ;
  1347. ;        BP    - Destroyed (BP contains the flags and is zeroed)
  1348. ;        DH    - Set to zero (Current field width)
  1349. ;        DL    - Set to zero (Current field precision)
  1350. ;
  1351. ;******************************************************************************
  1352. Clear_Flags    Proc    Near        ; Clear formatting flags procedure
  1353.     xor    bp,bp            ; Clear all of the formatting flags
  1354.     xor    dh,dh            ; Zero the current field width
  1355.     xor    dl,dl            ; Zero the current field precision
  1356.     cld                ; Clear the direction flag
  1357.     ret                ; Return to the caller
  1358. Clear_Flags    Endp            ; End of the Clear_Flags procedure
  1359.     Subttl    Print_Format    Print Format Character Routine
  1360.     Page    +
  1361. ;******************************************************************************
  1362. ;
  1363. ;  Routine Functional Description
  1364. ;
  1365. ;    Print_Format(Handle)
  1366. ;
  1367. ;        Save the required registers
  1368. ;        Output format specification character to handle
  1369. ;        Restore the required registers
  1370. ;        Return to the caller
  1371. ;
  1372. ;    Registers on Entry:
  1373. ;
  1374. ;        AH    - Handle
  1375. ;
  1376. ;    Registers on Exit:
  1377. ;
  1378. ;        AL    - Destroyed
  1379. ;        None
  1380. ;
  1381. ;******************************************************************************
  1382. Print_Format    Proc    Near        ; Output format specifier procedure
  1383.     mov    al,FORMAT_CHAR        ; Get format specifier character
  1384.     call    Write_TTY        ; Output the format specifier to handle
  1385.     ret                ; Return to the caller
  1386. Print_Format    Endp            ; End of the Print_Format procedure
  1387.     Subttl    Check_Digit    Check Digit Routine
  1388.     Page    +
  1389. ;******************************************************************************
  1390. ;
  1391. ;  Routine Functional Description
  1392. ;
  1393. ;    Check_Digit(Base, Character)
  1394. ;
  1395. ;        Save the required registers
  1396. ;        Call routine to convert character to binary
  1397. ;        If the character can be converted
  1398. ;            If value is greater than base
  1399. ;                Set carry flag (Character not a digit)
  1400. ;            Endif
  1401. ;        Else character cannot be converted
  1402. ;            Set carry flag (Character not a digit)
  1403. ;        Endif
  1404. ;        Restore the required registers
  1405. ;        Return to the caller
  1406. ;
  1407. ;    Registers on Entry:
  1408. ;
  1409. ;        AL    - Digit to check (ASCII)
  1410. ;        CH    - Number system base
  1411. ;
  1412. ;    Registers on Exit:
  1413. ;
  1414. ;        AL    - Binary value of digit (If it is a digit)
  1415. ;        CY    - Set if character is not a digit in current base
  1416. ;
  1417. ;******************************************************************************
  1418. Check_Digit    Proc    Near        ; Check digit procedure
  1419.     Save    bx            ; Save the required registers
  1420.     Save    ax            ; Save the original digit value
  1421.     call    Convert_Char        ; Call routine to convert character
  1422.     mov    bl,al            ; Save converted value in BL
  1423.     Restore ax            ; Restore the original digit value
  1424.     jc    Check_Exit        ; Jump if could not be converted
  1425.     cmp    bl,ch            ; Check against current number base
  1426.     cmc                ; Set correct carry flag state
  1427.     jc    Check_Exit        ; Jump if not valid for this base
  1428.     mov    al,bl            ; Digit is valid, save binary value
  1429. Check_Exit:
  1430.     Restore bx            ; Restore the required registers
  1431.     ret                ; Return to the caller
  1432. Check_Digit    Endp            ; End of the Check_Digit procedure
  1433.     Subttl    Convert_Char    Convert to Binary Conversion Routine
  1434.     Page    +
  1435. ;******************************************************************************
  1436. ;
  1437. ;  Routine Functional Description
  1438. ;
  1439. ;    Convert_Char(Character)
  1440. ;
  1441. ;        If character is a decimal digit (0 to 9)
  1442. ;            Convert ASCII digit to binary (Subtract 30h)
  1443. ;            Clear the carry flag (Character could be converted)
  1444. ;        Else character is not a decimal digit
  1445. ;            Convert character to uppercase
  1446. ;            If character is a hex digit (A to F)
  1447. ;                Convert ASCII digit to binary (Subtract 37h)
  1448. ;                Clear carry flag (Character could be converted)
  1449. ;            Else character is not a hex digit
  1450. ;                Set carry flag (Could not be converted)
  1451. ;            Endif
  1452. ;        Endif
  1453. ;        Return to the caller
  1454. ;
  1455. ;    Registers on Entry:
  1456. ;
  1457. ;        AL    - Digit to check (ASCII)
  1458. ;        CH    - Number system base
  1459. ;
  1460. ;    Registers on Exit:
  1461. ;
  1462. ;        AL    - Binary value of digit (If it is a digit)
  1463. ;        CY    - Set if character is not a digit in current base
  1464. ;
  1465. ;******************************************************************************
  1466. Convert_Char    Proc    Near        ; Convert character procedure
  1467.     sub    al,DECIMAL_ADJUST    ; Adjust character for ASCII decimal
  1468.     jc    Convert_Exit        ; Jump if below decimal limit
  1469.     cmp    al,DECIMAL        ; Check for a valid decimal character
  1470.     cmc                ; Set carry flag to correct state
  1471.     jnc    Convert_Exit        ; Jump if there is a valid digit
  1472.     and    al,UPPER_MASK        ; Convert anything else to uppercase
  1473.     sub    al,HEX_ADJUST        ; Adjust character for ASCII hexadecimal
  1474.     cmp    al,DECIMAL        ; Check for a valid hex character
  1475.     jc    Convert_Exit        ; Jump if below hexadecimal limit
  1476.     cmp    al,HEX            ; Check against upper hex limit
  1477.     cmc                ; Set carry flag to correct state
  1478. Convert_Exit:
  1479.     ret                ; Return to caller with value and flag
  1480. Convert_Char    Endp            ; End of the Convert_Char procedure
  1481.     Subttl    Get_Number    ASCII to Binary Conversion Routine
  1482.     Page    +
  1483. ;******************************************************************************
  1484. ;
  1485. ;  Routine Functional Description
  1486. ;
  1487. ;    Get_Number(String, Base, Length)
  1488. ;
  1489. ;        Save the required registers
  1490. ;        While length > 0
  1491. ;            Decrement the length
  1492. ;            Get the next character from string
  1493. ;            Call routine to check for a valid digit
  1494. ;            If character is a valid digit
  1495. ;                Add new value into total
  1496. ;            Endif
  1497. ;        Endwhile
  1498. ;        Decrement pointer back to last character
  1499. ;        Restore the required registers
  1500. ;        Return to the caller
  1501. ;
  1502. ;    Registers on Entry:
  1503. ;
  1504. ;        CH    - Number Base
  1505. ;        CL    - Maximum number length
  1506. ;        DS:SI - Current string pointer
  1507. ;
  1508. ;    Registers on Exit:
  1509. ;
  1510. ;        CL    - Destroyed
  1511. ;        DL    - Number retrieved (Zero if none)
  1512. ;        DS:SI - Pointer to character following number
  1513. ;        CY    - Carry set if no number was found
  1514. ;        ZR    - Zero set if zero number found
  1515. ;
  1516. ;******************************************************************************
  1517. Get_Number    Proc    Near        ; Get number procedure
  1518.     Save    ax,bx            ; Save the required registers
  1519.     mov    dl,MAX_BYTE        ; Get maximum value for a byte
  1520.     xor    al,al            ; Initialize the current total
  1521. Get_Loop:
  1522.     mov    bx,ax            ; Save current total in BX register
  1523.     lodsb                ; Get the next string character
  1524.     call    Check_Digit        ; Call routine to check for digit
  1525.     jc    Number_Exit        ; Jump if this is not a valid digit
  1526.     inc    dl            ; Increment no number present flag
  1527.     cbw                ; Convert binary value into full word
  1528.     xchg    ax,bx            ; Move total to AX, digit value in BX
  1529.     mul    ch            ; Multiply current total by number base
  1530.     add    ax,bx            ; Add in the new digit to current total
  1531.     dec    cl            ; Decrement the number length count
  1532.     jnz    Get_Loop        ; Jump if more digits are allowed
  1533.     mov    bx,ax            ; Move the current total into BX
  1534.     inc    si            ; Increment to next character
  1535. Number_Exit:
  1536.     dec    si            ; Decrement back to non-digit character
  1537.     add    dl,0            ; Set carry to indicate presence
  1538.     mov    dl,bl            ; Save the computed number in DL
  1539.     or    dl,dl            ; Set zero flag for zero result
  1540.     Restore ax,bx            ; Restore the required registers
  1541.     ret                ; Return to the caller
  1542. Get_Number    Endp            ; End of the Get_Number procedure
  1543.     Subttl    Compute     Convert Argument Routine
  1544.     Page    +
  1545. ;******************************************************************************
  1546. ;
  1547. ;  Routine Functional Description
  1548. ;
  1549. ;    Compute(Argument, Handle, Width, Precision, Base, Flags)
  1550. ;
  1551. ;        Save the required registers
  1552. ;        Allocate buffer space on the stack
  1553. ;        If argument value is long
  1554. ;            Get the long numeric value (4 bytes)
  1555. ;        Else if argument value is short
  1556. ;            Get the short numeric value (1 byte)
  1557. ;            Convert short to long value
  1558. ;        Else argument value is normal
  1559. ;            Get the normal numeric value (2 bytes)
  1560. ;            Convert normal to long value
  1561. ;        Endif
  1562. ;        If signed type is specified
  1563. ;            If the value is signed
  1564. ;                Set the signed value flag
  1565. ;                Take the twos complement of the value
  1566. ;            Endif
  1567. ;        Endif
  1568. ;        Zero the fraction value (Integer default)
  1569. ;        If fractional type conversion
  1570. ;            Separate number into integer and fraction
  1571. ;        Endif
  1572. ;        Convert integer to ASCII string in buffer
  1573. ;        If fractional type conversion
  1574. ;            Convert fraction to ASCII string in buffer
  1575. ;        Endif
  1576. ;        Calculate the numeric string length
  1577. ;        Default to no sign character
  1578. ;        If signed type conversion
  1579. ;            If numeric value was signed (Negative)
  1580. ;                Setup minus sign as sign character
  1581. ;                Increment the string length (For sign character)
  1582. ;            Else numeric value was not signed
  1583. ;                If signed conversion was specified
  1584. ;                    Setup plus sign as sign character
  1585. ;                    Increment the string length
  1586. ;                Endif
  1587. ;            Endif
  1588. ;        Endif
  1589. ;        If field width is not set (Zero)
  1590. ;            Set field width to string length
  1591. ;        Endif
  1592. ;        If string length > field width
  1593. ;            Set the field overflow flag
  1594. ;            Set string length to field width - 1
  1595. ;        Endif
  1596. ;        Call routine to calculate pad counts
  1597. ;        If sign character is present
  1598. ;            If pre-pad sign character
  1599. ;                Output sign character to handle
  1600. ;                Call routine to output pre-string pad characters
  1601. ;            Else post-pad sign character
  1602. ;                Call routine to output pre-string pad characters
  1603. ;                Output sign character to handle
  1604. ;            Endif
  1605. ;        Else sign character is not present
  1606. ;            Call routine to output pre-string pad characters
  1607. ;        Endif
  1608. ;        While length > 0
  1609. ;            Get next character of string
  1610. ;            Call routine to output character to handle
  1611. ;            Decrement the length
  1612. ;        Endwhile
  1613. ;        Set current pad character to a space
  1614. ;        Call routine to output post-string pad characters
  1615. ;        If the field overflow flag is set
  1616. ;            Output the overflow character
  1617. ;        Endif
  1618. ;        Restore the required registers
  1619. ;        Return to the caller
  1620. ;
  1621. ;    Registers on Entry:
  1622. ;
  1623. ;        AH    - Handle
  1624. ;        DS:SI - Pointer to argument
  1625. ;        CH    - Current number base
  1626. ;        DH    - Current field width
  1627. ;        DL    - Current field precision
  1628. ;        BP    - Formatting flags
  1629. ;
  1630. ;    Registers on Exit:
  1631. ;
  1632. ;        Direction flag is cleared (Move Forward)
  1633. ;
  1634. ;******************************************************************************
  1635. Compute     Proc    Near        ; Output numeric string procedure
  1636.     Save    bx,si,ds        ; Save the required registers
  1637.     sub    sp,BUFF_SIZE        ; Allocate buffer space on the stack
  1638.     mov    di,sp            ; Setup the buffer pointer
  1639.     add    di,BUFF_SIZE/2        ; Set the starting buffer position
  1640.     push    ax            ; Save the output handle value
  1641.     push    dx            ; Save the field width/precision
  1642.     xor    dh,dh            ; Convert precision to a full word
  1643.     push    dx            ; Save the field precision
  1644.     mov    cl,ch            ; Move current base value into CL
  1645.     xor    ch,ch            ; Make current base value into a word
  1646.     xor    ax,ax            ; Default to an unsigned
  1647.     xor    dx,dx            ;             non-long value
  1648.     test    bp,SHORT_SPEC        ; Check for short value specified
  1649.     jnz    Get_Short        ; Jump if short value specified
  1650.     test    bp,LONG_SPEC        ; Check for long value specified
  1651.     jnz    Get_Long        ; Jump if long value specified
  1652.     mov    ax,ds:[si]        ; Get the normal value (2 Bytes)
  1653.     test    bp,SIGNED_TYPE        ; Check for a signed conversion
  1654.     jz    Chk_Frac        ; Jump if not a signed conversion
  1655.     cwd                ; Signed conversion, do sign extension
  1656.     jmp    Chk_Sign        ; Go check for signed argument
  1657. Get_Short:
  1658.     mov    al,ds:[si]        ; Get the short value (1 Byte)
  1659.     test    bp,SIGNED_TYPE        ; Check for a signed conversion
  1660.     jz    Chk_Frac        ; Jump if not a signed conversion
  1661.     cbw                ; Signed conversion,
  1662.     cwd                ;             do sign extension
  1663.     jmp    Chk_Sign        ; Go check for signed argument
  1664. Get_Long:
  1665.     mov    ax,ds:[si]        ; Get the
  1666.     mov    dx,ds:[si + 2]        ;      long value (4 Bytes)
  1667. Chk_Sign:
  1668.     test    bp,SIGNED_TYPE        ; Check for a signed type
  1669.     jz    Chk_Frac        ; Jump if not signed
  1670.     test    dx,SIGNED        ; Check the number for signed
  1671.     jz    Chk_Frac        ; Jump if number is not signed
  1672.     or    bp,SIGNED_VAL        ; Set the signed value flag
  1673.     not    ax            ; Ones complement of the LSW
  1674.     not    dx            ; Ones complement of the MSW
  1675.     add    ax,1            ; Twos complement of the LSW
  1676.     adc    dx,0            ; Twos complement of the MSW
  1677. Chk_Frac:
  1678.     mov    si,ss            ; Get the current stack segment
  1679.     mov    ds,si            ; Setup DS to current stack segment
  1680.     mov    es,si            ; Setup ES to current stack segment
  1681.     xor    bx,bx            ; Zero fraction value (Integer default)
  1682.     test    bp,FRACTIONAL        ; Check for fractional conversion
  1683.     jz    Do_Integer        ; Jump if standard integer conversion
  1684.     test    bp,SHORT_SPEC        ; Check for short value specified
  1685.     jnz    Do_Short        ; Jump if a short fractional value
  1686.     test    bp,LONG_SPEC        ; Check for long value specified
  1687.     jnz    Do_Long         ; Jump if a long fractional value
  1688.     mov    bh,al            ; Move fraction value to MSB (BH)
  1689.     xor    bl,bl            ; Zero the lower LSB of fraction (BL)
  1690.     mov    al,ah            ; Move integer value to LSB (AL)
  1691.     xor    ah,ah            ; Zero the upper MSB of integer (AH)
  1692.     xor    dx,dx            ; Zero the upper MSW of integer (DX)
  1693.     jmp    Do_Integer        ; Go convert the integer portion
  1694. Do_Long:
  1695.     mov    bx,ax            ; Move fraction value to BX
  1696.     mov    ax,dx            ; Move integer value to LSW (AX)
  1697.     xor    dx,dx            ; Zero the upper MSW of integer (DX)
  1698.     jmp    Do_Integer        ; Go convert the integer portion
  1699. Do_Short:
  1700.     mov    bh,al            ; Move fraction value to MSB (BH)
  1701.     xor    bl,bl            ; Zero the lower LSB of fraction (BL)
  1702.     xor    ax,ax            ; Zero the lower LSW of integer (AX)
  1703.     xor    dx,dx            ; Zero the upper MSW of integer (DX)
  1704. Do_Integer:
  1705.     push    di            ; Save the starting position
  1706.     cld                ; Clear direction flag (Move forward)
  1707. Integer_Loop:
  1708.     mov    si,ax            ; Save LSW of value in SI register
  1709.     mov    ax,dx            ; Move MSW of value into AX
  1710.     xor    dx,dx            ; Setup to do the first divide
  1711.     div    cx            ; Divide the MSW by the current base
  1712.     xchg    ax,si            ; Setup for the second division
  1713.     div    cx            ; Divide the result by the current base
  1714.     xchg    ax,dx            ; Put the remainder into AX
  1715.     call    Digit            ; Call routine to convert it to a digit
  1716.     stosb                ; Store the ASCII digit into buffer
  1717.     xchg    ax,dx            ; Restore quotient of second division
  1718.     mov    dx,si            ; Restore quotient of first division
  1719.     or    si,ax            ; Check for a zero result
  1720.     jnz    Integer_Loop        ; Jump if more digits to get
  1721. Do_Fraction:
  1722.     pop    dx            ; Restore the starting position
  1723.     pop    si            ; Restore the field precision
  1724.     mov    ax,bx            ; Get the fraction value into AX
  1725.     mov    bx,di            ; Save the final position in BX
  1726.     mov    di,dx            ; Get the starting position
  1727.     test    bp,FRACTIONAL        ; Check for fractional conversion
  1728.     jz    Calc_Length        ; Jump if standard integer conversion
  1729.     dec    di            ; Decrement to get new start position
  1730.     std                ; Set direction flag (Move Backward)
  1731.     mov    Byte Ptr es:[di],POINT    ; Put a decimal point into buffer
  1732.     or    si,si            ; Check for zero precision
  1733.     jz    Calc_Length        ; Jump if no digits to compute
  1734.     dec    di            ; Update pointer for decimal point
  1735. Fraction_Loop:
  1736.     mul    cx            ; Multiply by the current base
  1737.     xchg    ax,dx            ; Put the MSW of result into AX
  1738.     call    Digit            ; Call routine to convert it to a digit
  1739.     stosb                ; Store the ASCII digit into buffer
  1740.     xchg    ax,dx            ; Restore fraction from multiply
  1741.     dec    si            ; Decrement the precision count
  1742.     jnz    Fraction_Loop        ; Jump if more digits left to do
  1743.     inc    di            ; Correct for length calculation
  1744. Do_Round:
  1745.     mul    cx            ; Compute the next actual digit
  1746.     shl    dx,1            ; Multiply digit value by two
  1747.     cmp    dx,cx            ; Compare value to current base
  1748.     jb    Calc_Length        ; Jump if below current base value
  1749.     push    di            ; Save the current position
  1750.     mov    ch,cl            ; Move current base to CH
  1751. Round_Loop:
  1752.     mov    al,es:[di]        ; Get the digit to round
  1753.     call    Convert_Char        ; Convert the ASCII to binary
  1754.     inc    al            ; Round the digit up
  1755.     mov    ah,al            ; Save the rounded value in AH
  1756.     call    Digit            ; Convert the binary digit to ASCII
  1757.     cmp    ah,ch            ; Check the value against current base
  1758.     jb    Round_Done        ; Jump if rounding is complete
  1759.     xor    al,al            ; Zero the AL register value
  1760.     call    Digit            ; Convert to an ASCII zero value
  1761.     mov    es:[di],al        ; Zero the current digit value
  1762.     inc    di            ; Increment to the next digit position
  1763.     cmp    di,bx            ; Check against final position
  1764.     jbe    Round_Loop        ; Jump if more digits to round with
  1765.     mov    bx,di            ; Update the new final position
  1766.     xor    al,al            ; Zero the AL register value
  1767.     inc    al            ; Increment AL to a one value
  1768.     call    Digit            ; Convert the one value to ASCII
  1769. Round_Done:
  1770.     mov    es:[di],al        ; Save the last rounded digit
  1771.     pop    di            ; Restore the current position
  1772. Calc_Length:
  1773.     pop    dx            ; Restore field width/precision
  1774.     pop    ax            ; Restore the file handle
  1775.     mov    cx,bx            ; Get the final buffer pointer
  1776.     sub    cx,di            ; Compute the numeric string length
  1777.     xor    al,al            ; Default to no sign character
  1778.     test    bp,SIGNED_TYPE        ; Check for signed type
  1779.     jz    Do_Check        ; Jump if not a signed type
  1780.     test    bp,SIGNED_VAL        ; Check for a signed value
  1781.     jz    Chk_Conv        ; Jump if not a signed value
  1782.     mov    al,MINUS        ; Setup minus as sign character
  1783.     inc    cx            ; Increment the string length
  1784.     jmp    Do_Check        ; Go check the field width
  1785. Chk_Conv:
  1786.     test    bp,SIGNED_CONV        ; Check for a signed conversion
  1787.     jz    Do_Check        ; Jump if not a signed type
  1788.     mov    al,PLUS         ; Setup plus as sign character
  1789.     inc    cx            ; Increment the string length
  1790. Do_Check:
  1791.     or    dh,dh            ; Check the current field width
  1792.     jnz    Width_Check        ; Jump if field width specified
  1793.     mov    dh,cl            ; Set field width to string length
  1794. Width_Check:
  1795.     cmp    cl,dh            ; Check actual width to field width
  1796.     jbe    Do_Calc         ; Jump if string fits in the field
  1797.     or    bp,OVER_FLOW        ; Set the field overflow flag
  1798.     mov    cl,dh            ; Set string width to field width
  1799.     dec    cl            ; Adjust for the overflow character
  1800.     jz    Compute_Exit        ; Jump if no more room in the field
  1801. Do_Calc:
  1802.     push    ax            ; Save the sign character (If any)
  1803.     mov    al,cl            ; Save the actual string length
  1804.     call    Calculate        ; Call routine to calculate pad values
  1805.     mov    dl,al            ; Setup the string output length
  1806.     pop    ax            ; Restore the sign character (If any)
  1807.     test    bp,PRE_PAD        ; Check for pre pad sign character
  1808.     jz    Do_Pad            ; Jump if not pre pad sign character
  1809.     or    al,al            ; Check for a sign needed
  1810.     jz    Do_Pad            ; Jump if no sign is needed
  1811.     call    Write_TTY        ; Call routine to output sign character
  1812.     dec    dl            ; Decrement the output count
  1813.     jz    Compute_Exit        ; Jump if no more room in field
  1814. Do_Pad:
  1815.     call    Pad            ; Call routine to output pad characters
  1816.     test    bp,PRE_PAD        ; Check for post pad sign character
  1817.     jnz    Do_Setup        ; Jump if not post pad sign character
  1818.     or    al,al            ; Check for a sign needed
  1819.     jz    Do_Setup        ; Jump if no sign character needed
  1820.     call    Write_TTY        ; Call routine to output the sign
  1821.     dec    dl            ; Decrement the output count
  1822.     jz    Compute_Exit        ; Jump if no more room in field
  1823. Do_Setup:
  1824.     mov    si,bx            ; Setup the source pointer to buffer
  1825.     dec    si            ; Point back to first character
  1826.     std                ; Set direction flag (Reverse order)
  1827. Send_Loop:
  1828.     lodsb                ; Get the next character to output
  1829.     call    Write_TTY        ; Call routine to output character
  1830.     dec    dl            ; Decrement the output count
  1831.     jnz    Send_Loop        ; Jump if more characters to output
  1832.     mov    cl,ch            ; Get the calculated pad counts
  1833.     and    bp,Not PAD_CHAR     ; Set pad character to a space
  1834.     call    Pad            ; Call routine to send pad characters
  1835. Compute_Exit:
  1836.     test    bp,OVER_FLOW        ; Check for field overflow
  1837.     jz    Compute_Done        ; Jump if no field overflow
  1838.     mov    al,ASTERISK        ; Get the field overflow character (*)
  1839.     call    Write_TTY        ; Output the field overflow character
  1840. Compute_Done:
  1841.     add    sp,BUFF_SIZE        ; Deallocate the buffer area
  1842.     Restore bx,si,ds        ; Restore the required registers
  1843.     cld                ; Clear the direction flag
  1844.     ret                ; Return to the caller
  1845. Compute     Endp            ; End of the Compute procedure
  1846.     Subttl    Digit        Binary to Character Conversion Routine
  1847.     Page    +
  1848. ;******************************************************************************
  1849. ;
  1850. ;  Routine Functional Description
  1851. ;
  1852. ;    Digit(Value, Flags)
  1853. ;
  1854. ;        Save the required registers
  1855. ;        Translate character to ASCII value
  1856. ;        If uppercase flag is set
  1857. ;            If ASCII value is not a digit (abcdef)
  1858. ;                Convert to uppercase  (ABCDEF)
  1859. ;            Endif
  1860. ;        Endif
  1861. ;        Restore the required registers
  1862. ;        Return to the caller
  1863. ;
  1864. ;    Registers on Entry:
  1865. ;
  1866. ;        AL    - Binary value (0 - 15)
  1867. ;
  1868. ;    Registers on Exit:
  1869. ;
  1870. ;        AL    - ASCII character
  1871. ;
  1872. ;******************************************************************************
  1873. Digit        Proc    Near        ; Convert to ASCII digit procedure
  1874.     Save    bx            ; Save the required registers
  1875.     lea    bx,cs:[Digit_Table]    ; Get pointer to digit translate table
  1876.     xlat    byte ptr cs:[bx]    ; Translate to ASCII digit
  1877.     test    bp,UPPER_CASE        ; Check for uppercase flag
  1878.     jz    Digit_Exit        ; Jump if no uppercase flag set
  1879.     cmp    al,DIGIT_MAX        ; Check for uppercase adjust needed
  1880.     jbe    Digit_Exit        ; Jump if adjustment not needed
  1881.     and    al,UPPER_MASK        ; Convert character to uppercase
  1882. Digit_Exit:
  1883.     Restore bx            ; Restore the required registers
  1884.     ret                ; Return to the caller
  1885. Digit        Endp            ; End of the Digit procedure
  1886.     Subttl            Define the Printf Data Areas
  1887.     Page    +
  1888. ;******************************************************************************
  1889. ;
  1890. ;    Define any data tables needed by the Printf routine
  1891. ;
  1892. ;******************************************************************************
  1893. Format_Table    Label    Byte
  1894.     Db    '-'                     ; Left justify format specifier
  1895.     Db    '+'                     ; Set signed specifier
  1896.     Db    't'                     ; Short format specifier
  1897.     Db    'T'                     ; Short format specifier
  1898.     Db    'l'                     ; Long format specifier
  1899.     Db    'L'                     ; Long format specifier
  1900.     Db    '#'                     ; Far format specifier
  1901. FORMAT_SIZE    Equ    This Byte - Format_Table
  1902. Format_Jump    Label    Word
  1903.     Dw    Left_Justify        ; Left justify format specifier
  1904.     Dw    Set_Signed        ; Set signed specifier
  1905.     Dw    Short_Specify        ; Short format specifier
  1906.     Dw    Short_Specify        ; Short format specifier
  1907.     Dw    Long_Specify        ; Long format specifier
  1908.     Dw    Long_Specify        ; Long format specifier
  1909.     Dw    Far_Specify        ; Far format specifier
  1910. Escape_Table    Label    Byte
  1911.     Db    'n'                     ; Newline escape character
  1912.     Db    't'                     ; Horizontal tab escape character
  1913.     Db    'v'                     ; Vertical tab escape character
  1914.     Db    'b'                     ; Backspace escape character
  1915.     Db    'r'                     ; Carriage return escape character
  1916.     Db    'f'                     ; Form feed escape character
  1917.     Db    'x'                     ; Output character (Hex representation)
  1918. ESCAPE_SIZE    Equ    This Byte - Escape_Table
  1919. Escape_Jump    Label    Word
  1920.     Dw    New_Line        ; Newline escape character
  1921.     Dw    Horz_Tab        ; Horizontal tab escape character
  1922.     Dw    Vert_Tab        ; Vertical tab escape character
  1923.     Dw    Back_Space        ; Backspace escape character
  1924.     Dw    Carr_Ret        ; Carriage return escape character
  1925.     Dw    Form_Feed        ; Form feed escape character
  1926.     Dw    Out_Hex         ; Output character (Hex representation)
  1927. Convert_Table    Label    Byte
  1928.     Db    '%'                     ; Print the percent sign
  1929.     Db    'c'                     ; Print next argument as a character
  1930.     Db    'C'                     ; Print next argument as a character
  1931.     Db    's'                     ; Print next argument as a string
  1932.     Db    'S'                     ; Print next argument as a string
  1933.     Db    'x'                     ; Print next argument as HEX (abcdef)
  1934.     Db    'X'                     ; Print next argument as HEX (ABCDEF)
  1935.     Db    'h'                     ; Print next argument as HEX (abcdef)
  1936.     Db    'H'                     ; Print next argument as HEX (ABCDEF)
  1937.     Db    'd'                     ; Print next argument as DECIMAL (+/-)
  1938.     Db    'D'                     ; Print next argument as DECIMAL (+/-)
  1939.     Db    'u'                     ; Print next argument as UNSIGNED
  1940.     Db    'U'                     ; Print next argument as UNSIGNED
  1941.     Db    'o'                     ; Print next argument as OCTAL
  1942.     Db    'O'                     ; Print next argument as OCTAL
  1943.     Db    'b'                     ; Print next argument as BINARY
  1944.     Db    'B'                     ; Print next argument as BINARY
  1945.     Db    'f'                     ; Print next argument as FRACTIONAL
  1946.     Db    'F'                     ; Print next argument as FRACTIONAL
  1947. CONVERT_SIZE    Equ    This Byte - Convert_Table
  1948. Convert_Jump    Label    Word
  1949.     Dw    Print_Format        ; Print format routine
  1950.     Dw    Do_Char         ; Print character routine
  1951.     Dw    Do_Char         ; Print character routine
  1952.     Dw    Do_String        ; Print string routine
  1953.     Dw    Do_String        ; Print string routine
  1954.     Dw    Do_Hex_Lower        ; Print lowercase hexadecimal routine
  1955.     Dw    Do_Hex_Upper        ; Print uppercase hexadecimal routine
  1956.     Dw    Do_Hex_Lower        ; Print lowercase hexadecimal routine
  1957.     Dw    Do_Hex_Upper        ; Print uppercase hexadecimal routine
  1958.     Dw    Do_Decimal        ; Print signed decimal routine
  1959.     Dw    Do_Decimal        ; Print signed decimal routine
  1960.     Dw    Do_Unsigned        ; Print unsigned decimal routine
  1961.     Dw    Do_Unsigned        ; Print unsigned decimal routine
  1962.     Dw    Do_Octal        ; Print octal routine
  1963.     Dw    Do_Octal        ; Print octal routine
  1964.     Dw    Do_Binary        ; Print binary routine
  1965.     Dw    Do_Binary        ; Print binary routine
  1966.     Dw    Do_Fractional        ; Print decimal fractional routine
  1967.     Dw    Do_Fractional        ; Print decimal fractional routine
  1968. Digit_Table    Label    Byte        ; Digit translation table
  1969.     Db    "0123456789abcdef"
  1970. ;******************************************************************************
  1971. ;
  1972. ;    Define the end of the Emulator Code Segment
  1973. ;
  1974. ;******************************************************************************
  1975. Emulate Ends
  1976.     End                ; End of the Printf module
  1977.