home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast2.iso / asmutil / stdlib.zip / PRINTF.ASM < prev    next >
Assembly Source File  |  1990-06-23  |  15KB  |  707 lines

  1. stdlib        segment    para public 'slcode'
  2.         assume    cs:stdlib
  3.         extrn    sl_Putc:far, sl_Puti:far, sl_ISize:far
  4.         extrn    sl_Putw:far, sl_Puth:far
  5.         extrn    sl_Putu:far, sl_PutUL:far, sl_ULSize:far
  6.         extrn    sl_LSize:far, sl_USize:far, sl_PutL:far
  7. ;
  8. putc        equ    sl_putc
  9. puti        equ    sl_puti
  10. ISize        equ    sl_ISize
  11. putw        equ    sl_putw
  12. puth        equ    sl_puth
  13. putu        equ    sl_putu
  14. putul        equ    sl_putul
  15. ulsize        equ    sl_ulsize
  16. lsize        equ    sl_lsize
  17. usize        equ    sl_usize
  18. putl        equ    sl_putl
  19. ;
  20. ;
  21. ; Printf- Like the "C" routine by the same name.  Calling sequence:
  22. ;
  23. ;               call    printf
  24. ;               db      "format string",0
  25. ;               dd      item1, item2, ..., itemn
  26. ;
  27. ; The format string is identical to "C".  Item1..Itemn are pointers to
  28. ; values to print for this string.  Each item must be matched by the
  29. ; corresponding "%xxx" item in the format string.
  30. ;
  31. ; Format string format:
  32. ;
  33. ; 1)    All characters, except the following, are printed to the standard
  34. ;       output as-is.
  35. ;
  36. ; 2)    "\" is the escape character.  Anything following it is printed
  37. ;       as-is except standard "C" values like \r, \n, \b, \t, etc.  If
  38. ;       a decimal digit follows the back-slash, printf assumes that this
  39. ;       is a hexadecimal number and converts following three digits to
  40. ;       an ASCII character and prints it.  Other back-slash operators are
  41. ;       just like those for "C".
  42. ;
  43. ; 3)    Format Control Strings:
  44. ;
  45. ;    General format:  "%s\cn^f" where:
  46. ;                s = -
  47. ;                n = a decimal integer
  48. ;                c = a fill character
  49. ;                ^ = ^
  50. ;                f = a format character
  51. ;
  52. ;            All fields except "%" and "f" are optional.
  53. ;
  54. ;    s = -       Left justify value and use fill character.
  55. ;    \c present    Use "c" as fill character.
  56. ;    n present    Use "n" as the minimum field width.
  57. ;    ^ present    The address associated with f is the address of a
  58. ;                pointer to the object, not the address of
  59. ;                the object itself.  The pointer is a far ptr.
  60. ;
  61. ;    f is one of the following
  62. ;
  63. ;        d -    Print signed integer in decimal notation.
  64. ;        i -    Print signed integer in decimal notation.
  65. ;        x -    Print word value in hexadecimal notation.
  66. ;        h -    Print byte value in hexadecimal notation.
  67. ;        u -    Print unsigned integer in decimal notation.
  68. ;        c -    Print character.
  69. ;        s -    Print string.
  70. ;
  71. ;        ld-    Print long signed integer.
  72. ;        li-    Print long unsigned integer.
  73. ;        lx-    Print long hexadecimal number.
  74. ;        lu-    Print long unsigned number.
  75. ;
  76. ;
  77. ;    Calling Sequence:
  78. ;
  79. ;        call    Printf
  80. ;        db    "Format String",0
  81. ;        dd    adrs1, adrs2, ..., adrsn
  82. ;
  83. ;    Where the format string is ala "C" (and the descriptions above)
  84. ;    and adrs1..adrsn are addresses (far ptr) to the items to print.
  85. ;    Unless the "^" modifier is present, these addresses are the actual
  86. ;    addresses of the objects to print.
  87. ;
  88. ;
  89. ;
  90. cr        equ    0dh
  91. ff        equ    0ch
  92. lf        equ    0ah
  93. tab        equ    09h
  94. bs        equ    08h
  95. ;
  96. RtnAdrs        equ    2[bp]
  97. ;
  98.         public  sl_printf
  99. sl_printf    proc    far
  100.         push    bp
  101.         mov    bp, sp
  102.         pushf
  103.         push    ax
  104.         push    bx
  105.         push    cx
  106.         push    dx
  107.         push    di
  108.         push    si
  109.         push    es
  110.         push    ds
  111. ;
  112. ; Get pointers to the return address (format string).
  113.         cld
  114.         les    di, RtnAdrs
  115.         lds    si, RtnAdrs
  116. ;
  117. ; Okay, search for the end of the format string.  After these instructions,
  118. ; di points just beyond the zero byte at the end of the format string.  This,
  119. ; of course, points at the first address beyond the format string.
  120. ;
  121.         mov    al, 0
  122.         mov    cx, 65535
  123.     repne    scasb
  124. ;
  125. PrintItems:    lodsb            ;Get char si points at.
  126.         cmp    al, 0        ;EOS?
  127.         jz    PrintfDone
  128.         cmp    al, "%"        ;Start of a format string?
  129.         jz    FmtItem
  130.         cmp    al, "\"        ;Escape character?
  131.         jnz    PrintIt
  132.         call    GetEscChar
  133. PrintIt:    call    Putc
  134.         jmp    PrintItems
  135. ;
  136. FmtItem:    call    GetFmtItem    ;Process the format item here.
  137.         jmp    PrintItems
  138. ;
  139. PrintfDone:    mov    RtnAdrs, di    ;Put out new return address.
  140.         pop    ds
  141.         pop    es
  142.         pop    si
  143.         pop    di
  144.         pop    dx
  145.         pop    cx
  146.         pop    bx
  147.         pop    ax
  148.         pop    bp
  149.         popf
  150.         ret
  151. sl_printf       endp
  152. ;
  153. ; GetEscChar- Handles items immediately following the escape character "\".
  154. ;
  155. ;    Special escape characters (upper/lower case is acceptable):
  156. ;
  157. ;        n    Newline (cr/lf)
  158. ;        t    tab
  159. ;        b    backspace
  160. ;        r    return
  161. ;        l    line feed
  162. ;        f    formfeed
  163. ;        \    \
  164. ;        %    &
  165. ;        0xhh    Char with hex character code hh.  Must have exactly
  166. ;            two hexadecimal digits.
  167. ;
  168. GetEscChar    proc    near
  169.         lodsb            ;Get next character
  170.         cmp    al, 'n'
  171.         je    RtnNL
  172.         cmp    al, 'N'
  173.         je    RtnNL
  174.         cmp    al, 't'
  175.         je    RtnTab
  176.         cmp    al, 'T'
  177.         je    RtnTab
  178.         cmp    al, 'b'
  179.         je    RtnBS
  180.         cmp    al, 'B'
  181.         je    RtnBS
  182.         cmp    al, 'r'
  183.         je    RtnRtn
  184.         cmp    al, 'R'
  185.         je    RtnRtn
  186.         cmp    al, 'l'
  187.         je    RtnLF
  188.         cmp    al, 'L'
  189.         je    RtnLF
  190.         cmp    al, 'f'
  191.         je    RtnFF
  192.         cmp    al, 'F'
  193.         je    RtnFF
  194. ;
  195. ; Check for the presence of a 0xhh value here:
  196. ;
  197.         cmp    al, '0'
  198.         jne    RtnChar
  199.         cmp    byte ptr [si], 'x'
  200.         je    GetHex
  201.         cmp    byte ptr [si], 'X'
  202.         jne    RtnChar
  203. ;
  204. ; Okay, process the hex value here.  Note that exactly two hex digits must
  205. ; follow the 0x.
  206. ;
  207. GetHex:        inc    si        ;Point at first hex digit.
  208.         lodsb            ;Get first hex digit.
  209.         and    al, 05fh    ;l.c. -> u.c.
  210.         cmp    al, 'A'
  211.         jb    GotIt
  212.         sub    al, '7'
  213. GotIt:        shl    al, 1        ;Put into H.O. nibble.
  214.         shl    al, 1
  215.         shl    al, 1
  216.         shl    al, 1
  217.         mov    ah, al        ;Save for later
  218.         lodsb            ;Get next char.
  219.         and    al, 05fh
  220.         cmp    al, 'A'
  221.         jb    GotIt2
  222.         sub    al, '7'
  223. GotIt2:        and    al, 0fh
  224.         or    al, ah
  225.         ret            ;Return hex constant.
  226. ;
  227. ; RtnNL (return Newline) cheats.  It needs to return two characters.
  228. ; Since GetEscChar only returns a single character, this code goes ahead
  229. ; and calls putc to output the CR and the returns the LF.
  230. ;
  231. RtnNL:        mov    al, cr
  232.         call    Putc
  233.         mov    al, lf
  234.         ret
  235. ;
  236. RtnTab:        mov    al, tab
  237.         ret
  238. ;
  239. RtnBS:        mov    al, bs
  240.         ret
  241. ;
  242. RtnRtn:        mov    al, cr
  243.         ret
  244. ;
  245. RtnLF:        mov    al, lf
  246.         ret
  247. ;
  248. RtnFF:        mov    al, ff
  249. RtnChar:    ret
  250. ;
  251. GetEscChar    endp
  252. ;
  253. ;
  254. ;
  255. GetFmtItem    proc    near
  256.         lodsb                ;Get char beyond "%"
  257. ;
  258.         mov    cx, 1            ;Default field width is 1.
  259.         mov    dl, 0            ;Default is right justified
  260.         mov    dh, ' '            ;Default fill char is space.
  261.         mov    ah, ' '            ;Assume straight ptr, not handle.
  262. ;
  263. ; See if the user wants the value left justified:
  264. ;
  265.         cmp    al, '-'
  266.         jne    NotLeftJust
  267.         inc    dl            ;Set to right justified
  268.         lodsb                ;Get next character.
  269. ;
  270. ; See if the user wants to change the padding character.
  271. ;
  272. NotLeftJust:    cmp    al, '\'
  273.         jne    NoPadChange
  274.         lodsb                ;Get Padding Character.
  275.         mov    dh, al            ;Save padding character.
  276.         lodsb                ;Get next character
  277. ;
  278. ; See if the user wants a different field width:
  279. ;
  280. NoPadChange:    cmp    al, '0'
  281.         jb    NoFldWidth
  282.         cmp    al, '9'
  283.         ja    NoFldWidth
  284.         call    GetDecVal
  285. ;
  286. ; See if the user wants to specify a handle rather than a straight pointer
  287. ;
  288. NoFldWidth:    cmp    al, '^'
  289.         jne     ChkFmtChars
  290.         mov    ah, al
  291.         lodsb                ;Skip "^" character
  292. ;
  293. ; Okay, process the format characters down here.
  294. ;
  295. ChkFmtChars:    and    al, 05fh        ;l.c. -> U.C.
  296.         cmp    al, 'D'
  297.         je    PrintDec
  298.         cmp    al, 'I'
  299.         je    PrintDec
  300.         cmp    al, 'C'
  301.         je    PrintChar
  302. ;
  303.         cmp    al, 'X'
  304.         jne    TryH
  305.         jmp    PrintHexWord
  306. ;
  307. TryH:        cmp    al, 'H'
  308.         jne    TryU
  309.         jmp    PrintHexByte
  310. ;
  311. TryU:        cmp    al, 'U'
  312.         jne    TryString
  313.         jmp    PrintUDec
  314. ;
  315. TryString:    cmp    al, 'S'
  316.         jne    TryLong
  317.         jmp    PrintString
  318. ;
  319. TryLong:        cmp    al, 'L'
  320.         jne    Default
  321. ;
  322. ; If we've got the "L" modifier, this is a long value to print, get the
  323. ; data type character as the next value:
  324. ;
  325.         lodsb
  326.         and    al, 05fh        ;l.c. -> U.C.
  327.         cmp    al, 'D'
  328.         je    JmpDec
  329.         cmp    al, 'I'
  330.         jne    TryLU
  331. JmpDec:        jmp    LongDec
  332. ;
  333. TryLU:        cmp    al, 'U'
  334.         jne    TryX
  335.         jmp    LongU
  336. ;
  337. TryX:        cmp    al, 'X'
  338.         jne    Default
  339.         jmp    LongX
  340. ;
  341. ;
  342. ;
  343. ; If none of the above, simply return without printing anything.
  344. ;
  345. Default:        ret
  346. ;
  347. ;
  348. ;
  349. ;
  350. ;
  351. ; Print a signed decimal value here.
  352. ;
  353. PrintDec:    call    GetPtr            ;Get next pointer into ES:BX
  354.         mov    ax, es:[bx]        ;Get value to print.
  355.         call    ISize            ;Get the size of this guy.
  356.         sub    cx, ax                 ;Compute padding
  357.         mov    ax, es:[bx]        ;Retrieve value to print.
  358.         js    NoPadDec        ;Is CX negative?
  359.         cmp    dl, 0            ;Right justified?
  360.         jne    LeftJustDec
  361.         call    PrintPad        ;Print padding characters
  362.         call    Puti            ;Print the integer
  363.         ret                ;We're done!
  364. ;
  365. ; Print left justified value here.
  366. ;
  367. LeftJustDec:    call    Puti
  368.         call    PrintPad
  369.         ret
  370. ;
  371. ; Print non-justified value here:
  372. ;
  373. NoPadDec:    call    Puti
  374.         ret
  375. ;
  376. ;
  377. ;
  378. ; Print a character variable here.
  379. ;
  380. PrintChar:    call    GetPtr            ;Get next pointer into ES:BX
  381.         mov    al, es:[bx]        ;Retrieve value to print.
  382.                 dec    cx
  383.         js    NoPadChar        ;Is CX negative?
  384.         cmp    dl, 0            ;Right justified?
  385.         jne    LeftJustChar
  386.         call    PrintPad        ;Print padding characters
  387.         call    Putc            ;Print the character
  388.         ret                ;We're done!
  389. ;
  390. ; Print left justified value here.
  391. ;
  392. LeftJustChar:    call    Putc
  393.         call    PrintPad
  394.         ret
  395. ;
  396. ; Print non-justified character here:
  397. ;
  398. NoPadChar:    call    Putc
  399.         ret
  400. ;
  401. ;
  402. ;
  403. ;
  404. ; Print a hexadecimal word value here.
  405. ;
  406. PrintHexWord:    call    GetPtr            ;Get next pointer into ES:BX
  407.         mov    ax, es:[bx]        ;Get value to print.
  408.         sub    cx, 4            ;Compute padding
  409.         js    NoPadHexW        ;Is CX negative?
  410.         cmp    dl, 0            ;Right justified?
  411.         jne    LeftJustHexW
  412.         call    PrintPad        ;Print padding characters
  413.         call    Putw            ;Print the hex value
  414.         ret                ;We're done!
  415. ;
  416. ; Print left justified value here.
  417. ;
  418. LeftJustHexW:    call    Putw
  419.         call    PrintPad
  420.         ret
  421. ;
  422. ; Print non-justified value here:
  423. ;
  424. NoPadHexW:    call    Putw
  425.         ret
  426. ;
  427. ;
  428. ;
  429. ;
  430. ; Print hex bytes here.
  431. ;
  432. ;
  433. PrintHexByte:    call    GetPtr            ;Get next pointer into ES:BX
  434.         mov    ax, es:[bx]        ;Get value to print.
  435.         sub    cx, 2            ;Compute padding
  436.         js    NoPadHexB        ;Is CX negative?
  437.         cmp    dl, 0            ;Right justified?
  438.         jne    LeftJustHexB
  439.         call    PrintPad        ;Print padding characters
  440.         call    Puth            ;Print the hex value
  441.         ret                ;We're done!
  442. ;
  443. ; Print left justified value here.
  444. ;
  445. LeftJustHexB:    call    Puth
  446.         call    PrintPad
  447.         ret
  448. ;
  449. ; Print non-justified value here:
  450. ;
  451. NoPadHexB:    call    Puth
  452.         ret
  453. ;
  454. ;
  455. ;
  456. ; Output unsigned decimal numbers here:
  457. ;
  458. PrintUDec:    call    GetPtr            ;Get next pointer into ES:BX
  459.         mov    ax, es:[bx]        ;Get value to print.
  460.         call    USize            ;Get the size of this guy.
  461.         sub    cx, ax                 ;Compute padding
  462.         mov    ax, es:[bx]        ;Retrieve value to print.
  463.         js    NoPadUDec        ;Is CX negative?
  464.         cmp    dl, 0            ;Right justified?
  465.         jne    LeftJustUDec
  466.         call    PrintPad        ;Print padding characters
  467.         call    Putu            ;Print the integer
  468.         ret                ;We're done!
  469. ;
  470. ; Print left justified value here.
  471. ;
  472. LeftJustUDec:    call    Putu
  473.         call    PrintPad
  474.         ret
  475. ;
  476. ; Print non-justified value here:
  477. ;
  478. NoPadUDec:    call    Putu
  479.         ret
  480. ;
  481. ;
  482. ;
  483. ;
  484. ; Output a string here:
  485. ;
  486. PrintString:    call    GetPtr            ;Get next pointer into ES:BX
  487. ;
  488. ; Compute the length of the string:
  489. ;
  490.         push    di
  491.         push    cx
  492.         mov    cx, -1
  493.         mov    di, bx
  494.         mov    al, 0
  495.     repne    scasb
  496.         mov    ax, cx
  497.         neg    ax
  498.         dec    ax
  499.         dec    ax
  500.         pop    cx
  501.         pop    di
  502.         sub    cx, ax            ;Field width - String Length.
  503. ;
  504.         js    NoPadStr        ;Is CX negative?
  505.         cmp    dl, 0            ;Right justified?
  506.         jne    LeftJustStr
  507.         call    PrintPad        ;Print padding characters
  508.         call    Puts            ;Print the string
  509.         ret                ;We're done!
  510. ;
  511. ; Print left justified value here.
  512. ;
  513. LeftJustStr:    call    Puts
  514.         call    PrintPad
  515.         ret
  516. ;
  517. ; Print non-justified value here:
  518. ;
  519. NoPadStr:    call    Puts
  520.         ret
  521. GetFmtItem    endp
  522. ;
  523. ;
  524. ;
  525. ; Print a signed long decimal value here.
  526. ;
  527. LongDec:    call    GetPtr            ;Get next pointer into ES:BX
  528.         mov    ax, es:[bx]        ;Get value to print.
  529.         push    dx
  530.         mov    dx, es:2[bx]
  531.         call    LSize            ;Get the size of this guy.
  532.         pop    dx
  533.         sub    cx, ax                 ;Compute padding
  534.         mov    ax, es:[bx]        ;Retrieve value to print.
  535.         js    NoPadLong        ;Is CX negative?
  536.         cmp    dl, 0            ;Right justified?
  537.         jne    LeftJustLong
  538.         call    PrintPad        ;Print padding characters
  539.         mov    dx, es:2[bx]        ;Get H.O. word
  540.         call    PutL            ;Print the integer
  541.         ret                ;We're done!
  542. ;
  543. ; Print left justified value here.
  544. ;
  545. LeftJustLong:    push    dx
  546.         mov    dx, es:2[bx]        ;Get H.O. word
  547.         call    PutL
  548.         pop    dx
  549.         call    PrintPad
  550.         ret
  551. ;
  552. ; Print non-justified value here:
  553. ;
  554. NoPadLong:    mov    dx, es:2[bx]        ;Get H.O. word
  555.         call    Putl
  556.         ret
  557. ;
  558. ;
  559. ; Print an unsigned long decimal value here.
  560. ;
  561. LongU:        call    GetPtr            ;Get next pointer into ES:BX
  562.         mov    ax, es:[bx]        ;Get value to print.
  563.         push    dx
  564.         mov    dx, es:[bx]
  565.         call    ULSize            ;Get the size of this guy.
  566.         pop    dx
  567.         sub    cx, ax                 ;Compute padding
  568.         mov    ax, es:[bx]        ;Retrieve value to print.
  569.         js    NoPadULong        ;Is CX negative?
  570.         cmp    dl, 0            ;Right justified?
  571.         jne    LeftJustULong
  572.         call    PrintPad        ;Print padding characters
  573.         mov    dx, es:2[bx]        ;Get H.O. word
  574.         call    PutUL            ;Print the integer
  575.         ret                ;We're done!
  576. ;
  577. ; Print left justified value here.
  578. ;
  579. LeftJustULong:    push    dx
  580.         mov    dx, es:2[bx]        ;Get H.O. word
  581.         call    PutUL
  582.         pop    dx
  583.         call    PrintPad
  584.         ret
  585. ;
  586. ; Print non-justified value here:
  587. ;
  588. NoPadULong:    mov    dx, es:2[bx]        ;Get H.O. word
  589.         call    Putul
  590.         ret
  591. ;
  592. ;
  593. ; Print a long hexadecimal value here.
  594. ;
  595. LongX:        call    GetPtr            ;Get next pointer into ES:BX
  596.         sub    cx, 8            ;Compute padding
  597.         js    NoPadXLong        ;Is CX negative?
  598.         cmp    dl, 0            ;Right justified?
  599.         jne    LeftJustXLong
  600.         call    PrintPad        ;Print padding characters
  601.         mov    ax, es:2[bx]        ;Get H.O. word
  602.         call    Putw
  603.         mov    ax, es:[bx]
  604.         call    Putw
  605.         ret                ;We're done!
  606. ;
  607. ; Print left justified value here.
  608. ;
  609. LeftJustxLong:    mov    ax, es:2[bx]        ;Get H.O. word
  610.         call    Putw
  611.         mov    ax, es:[bx]        ;Get L.O. word
  612.         call    Putw
  613.         call    PrintPad
  614.         ret
  615. ;
  616. ; Print non-justified value here:
  617. ;
  618. NoPadxLong:    mov    ax, es:2[bx]        ;Get H.O. word
  619.         call    Putw
  620.         mov    ax, es:[bx]
  621.         call    Putw
  622.         ret
  623. ;
  624. ;
  625. ;
  626. ;
  627. ; Puts- Outputs the zero terminated string pointed at by ES:BX.
  628. ;
  629. Puts        proc    near
  630. PutsLp:        mov    al, es:[bx]
  631.         cmp    al, 0
  632.         je    PutsDone
  633.         call    putc
  634.         inc    bx
  635.         jmp    PutsLp
  636. ;
  637. PutsDone:    ret
  638. Puts        endp
  639. ;
  640. ;
  641. ;
  642. ;
  643. ;
  644. ; PrintPad-    Prints padding characters.  Character to print is in DH.
  645. ;        We must print it CX times.  CX must be greater than zero.
  646. ;
  647. PrintPad    proc    near
  648.         push    ax
  649.         mov    al, dh
  650.         jcxz    NoPadding
  651. PPLoop:        call    Putc
  652.         loop    PPLoop
  653. NoPadding:    pop    ax
  654.         ret
  655. PrintPad    endp
  656. ;
  657. ;
  658. ;
  659. ;
  660. ;
  661. ; GetPtr- Grabs the next pointer which DS:DI points at and returns this
  662. ;      far pointer in ES:BX.
  663. ;
  664. GetPtr        proc    near
  665.         les    bx, [di]
  666.         add    di, 4
  667. ;
  668. ; See if this is a handle rather than a pointer.
  669. ;
  670.         cmp    ah, '^'
  671.         jne    NotHandle
  672.         les    bx, es:[bx]
  673. NotHandle:    ret
  674. GetPtr        endp
  675. ;
  676. ;
  677. ;
  678. ;
  679. ;
  680. ; GetDecVal-    Converts the string of decimal digits in AL and [SI] into
  681. ;        an integer and returns this integer in CX.
  682. ;
  683. GetDecVal    proc    near
  684.         push    dx
  685.         dec    si
  686.         xor    cx, cx
  687. DecLoop:    lodsb
  688.         cmp    al, '0'
  689.         jb    NoMore
  690.         cmp    al, '9'
  691.         ja    NoMore
  692.         and    al, 0fh
  693.         shl    cx, 1            ;Compute CX := CX*10 + al
  694.         mov    dx, cx
  695.         shl    cx, 1
  696.         shl    cx, 1
  697.         add    cx, dx
  698.         add    cl, al
  699.         adc    ch, 0
  700.         jmp    DecLoop
  701. NoMore:        pop    dx
  702.         ret
  703. GetDecVal    endp
  704. ;
  705. stdlib        ends
  706.         end
  707.