home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c082_144 / 2.ddi / CLIBSRC3.ZIP / VPRINTER.CAS < prev    next >
Encoding:
Text File  |  1992-06-10  |  39.7 KB  |  1,115 lines

  1. /*-----------------------------------------------------------------------*
  2.  * filename - vprinter.cas
  3.  *
  4.  * function(s)
  5.  *        Hex4       - converts int to 4 hex digits
  6.  *        __vprinter - sends formatted output
  7.  *-----------------------------------------------------------------------*/
  8.  
  9. /*
  10.  *      C/C++ Run Time Library - Version 5.0
  11.  *
  12.  *      Copyright (c) 1987, 1992 by Borland International
  13.  *      All Rights Reserved.
  14.  *
  15.  */
  16.  
  17.  
  18. #pragma  inline
  19. #include <stdio.h>
  20. #include <asmrules.h>
  21. #include <_printf.h>
  22.  
  23. #define I asm
  24.  
  25. #define BREAKPOINT      asm int 3
  26.  
  27. static  char    NullString[] = "(null)";
  28.  
  29. /*-----------------------------------------------------------------------*
  30.  
  31. Name            Hex4 - converts int to 4 hex digits
  32.  
  33. Usage           static void near pascal Hex4( void )
  34.  
  35. Description     Convert 16 bit parameter (in dx) to 4 hex digits at ES: [di].
  36.  
  37.                 NOTE: TC does not realize that "stosb" implies DI, so DI is
  38.                 not pushed/popped.  That is nice, but one day it may cease
  39.                 to be true...
  40.  
  41.                 The calling code expects di to be incremented by 4 as a
  42.                 side effect of this function.
  43.  
  44. *------------------------------------------------------------------------*/
  45. I _TEXT    segment
  46. I  Hex4    proc near
  47. I          mov     al,dh
  48. I          call    Byte2Ascii
  49. I          mov     al,dl
  50.  
  51. I Byte2Ascii:                         /* convert byte in al to ASCII */
  52. I          db      0d4h,10h           /* AAM trick to separate nibbles in al */
  53. I          xchg    ah,al
  54. I          call    Nibble2Ascii
  55. I          xchg    ah,al
  56.  
  57. I Nibble2Ascii:                       /* convert hex digit in al to ASCII */
  58. I          add     al,90h
  59. I          daa
  60. I          adc     al,40h
  61. I          daa
  62. I          stosb
  63. I          ret
  64. I          endp
  65. I          ends
  66.  
  67. /*-----------------------------------------------------------------------*
  68.  
  69. __vprinter is a table-driven design, for speed and flexibility. There are
  70. two tables.  The first table classifies all 7-bit ASCII chars and then the
  71. second table is the switch table which points to the function blocks which
  72. handle the various classes of characters.
  73.  
  74. All characters with the 8th bit set are currently classed as don't cares,
  75. which is the class of character also used for normal alphabetics.  All
  76. characters less than ' ' (0x20) are also classed as don't cares.
  77.  
  78. *------------------------------------------------------------------------*/
  79.  
  80. typedef
  81.         enum
  82.         {
  83.                 _si,    /* sign fill +/-        */
  84.                 _af,    /* alternate form       */
  85.                 _ar,    /* format (width or precision) by argument */
  86.                 _lj,    /* left justify         */
  87.  
  88.                 _pr,    /* precision            */
  89.                 _nu,    /* numeral              */
  90.                 _lo,    /* long                 */
  91.                 _ld,    /* long double          */
  92.                 _sh,    /* short                */
  93.                 _fz,    /* fill zeros           */
  94.  
  95.                 _de,    /* decimal              */
  96.                 _oc,    /* octal                */
  97.                 _un,    /* unsigned decimal     */
  98.                 _he,    /* hexadecimal          */
  99.  
  100.                 _pt,    /* pointer              */
  101.                 _fl,    /* float                */
  102.                 _ch,    /* char                 */
  103.                 _st,    /* string               */
  104.  
  105.                 _ns,    /* number sent          */
  106.                 _zz,    /* terminator           */
  107.                 _dc,    /* don't care           */
  108.                 _pc,    /* percent              */
  109.  
  110.                 _ne,    /* near pointer         */
  111.                 _fa,    /* far pointer          */
  112.         } characterClass;
  113.  
  114.         /*  Here is the table of classes, indexed by character. */
  115.  
  116. static unsigned char printCtype [96] =
  117. {
  118. /*       SP   !   "   #   $   %   &   '   (   )   *   +   ,   -   .   /  */
  119.         _si,_dc,_dc,_af,_dc,_pc,_dc,_dc,_dc,_dc,_ar,_si,_dc,_lj,_pr,_dc,
  120.  
  121. /*        0   1   2   3   4   5   6   7   8   9   :   ;   <   =   >   ?  */
  122.         _fz,_nu,_nu,_nu,_nu,_nu,_nu,_nu,_nu,_nu,_dc,_dc,_dc,_dc,_dc,_dc,
  123.  
  124. /*        _   A   B   C   D   E   F   G   H   I   J   K   L   M   N   O  */
  125.         _dc,_dc,_dc,_dc,_dc,_fl,_fa,_fl,_sh,_dc,_dc,_dc,_ld,_dc,_ne,_dc,
  126.  
  127. /*        P   Q   R   S   T   U   V   W   X   Y   Z   [   \   ]   ^   _  */
  128.         _dc,_dc,_dc,_dc,_dc,_dc,_dc,_dc,_he,_dc,_dc,_dc,_dc,_dc,_dc,_dc,
  129.  
  130. /*        `   a   b   c   d   e   f   g   h   i   j   k   l   m   n   o  */
  131.         _dc,_dc,_dc,_ch,_de,_fl,_fl,_fl,_sh,_de,_dc,_dc,_lo,_dc,_ns,_oc,
  132.  
  133. /*        p   q   r   s   t   u   v   w   x   y   z   {   |   }   ~ DEL  */
  134.         _pt,_dc,_dc,_st,_dc,_un,_dc,_dc,_he,_dc,_dc,_dc,_dc,_dc,_dc,_dc,
  135. };
  136.  
  137.  
  138. /*---------------------------------------------------------------------*
  139.  
  140. Name            __vprinter - sends formatted output
  141.  
  142. Usage           int   pascal __vprinter (putnF  *putter,
  143.                                          void   *outP,
  144.                                          const char   *formP,
  145.                                          void _ss *argP)
  146.  
  147. Prototype in    _printf.h
  148.  
  149. Description     The list of arguments *argP is combined with literal text in
  150.                 the format string *formP according to format specifications
  151.                 inside the format string.
  152.  
  153.                 The supplied procedure *putter is used to generate the output.
  154.                 It is required to take the string S, which has been
  155.                 constructed by __vprinter, and copy it to the destination
  156.                 outP.  The destination may be a string, a FILE, or whatever
  157.                 other class of construct the caller requires.  It is possible
  158.                 for several calls to be made to *putter since the buffer S
  159.                 is of limited size.
  160.  
  161.                 *putter is required to preserve  SI, DI.
  162.  
  163.                 The only purpose of the outP argument is to be passed through
  164.                 to putter.
  165.  
  166.                 The object at *argP is a record of unknown structure, which
  167.                 structure is interpreted with the aid of the format string.
  168.                 Each field of the structure may be an integer, long, double,
  169.                 or string (char *).  Chars may appear but occupy integer-sized
  170.                 cells.  Floats, character arrays, and structures may not
  171.                 appear.
  172.  
  173. Return value    The result of the function is a count of the characters sent to
  174.                 *outP.
  175.  
  176.                 There is no error indication.  When an incorrect conversion
  177.                 spec is encountered __vprinter copies the format as a literal
  178.                 (since it is assumed that alignment with the argument list has
  179.                 been lost), beginning with the '%' which introduced the bad
  180.                 format.
  181.  
  182.                 If the destination outP is of limited size, for example a
  183.                 string or a full disk, __vprinter does not know.  Overflowing
  184.                 the destination causes undefined results.  In some cases
  185.                 *putter is able to handle overflows safely, but that is not
  186.                 the concern of __vprinter.
  187.  
  188.                 The syntax of the format string is:
  189.  
  190.                 format ::=      ([literal] ['%' conversion ])* ;
  191.  
  192.                 conversion ::=  '%' | [flag]* [width] ['.' precision]
  193.                                       ['l'] type ;
  194.  
  195.                 flag ::=        '-' | '+' | ' ' | '#' | '0' ;
  196.  
  197.                 width ::=       '*' | number ;
  198.                 precision ::=   '.' ('*' | number) ;
  199.  
  200.                 type ::=        'd'|'i'|'o'|'u'|'x'|'n'|'X'|'f'|'e'|'E'|
  201.                                 'g'|'G'|'c'|'s'|'p'|'N'|'F'
  202.  
  203. *---------------------------------------------------------------------*/
  204. int   pascal near __vprinter (putnF near *putter,
  205.                               void       *outP,
  206.                               const char *formP,
  207.                               void _ss   *argP)
  208. {
  209.  
  210. #define Ssize 80
  211.  
  212.         typedef
  213.                 enum
  214.                 {
  215.                 flagStage, fillzStage, wideStage, dotStage, precStage,
  216.                 ellStage, typeStage,
  217.                 } syntaxStages;
  218.  
  219.         typedef
  220.                 enum
  221.                 {
  222.                 altFormatBit = 1,       /* the '#' flag                 */
  223.                 leftJustBit  = 2,       /* the '-' flag                 */
  224.                 notZeroBit   = 4,       /* 0 (octal) or 0x (hex) prefix */
  225.                 fillZerosBit = 8,       /* zero fill width              */
  226.                 isLongBit    = 16,      /* long-type argument           */
  227.                 farPtrBit    = 32,      /* far pointers                 */
  228.                 alt0xBit     = 64,      /* '#' confirmed for %x format  */
  229.                 floatBit     = 128,     /* float arg 4 bytes not 8!     */
  230.                 LongDoubleBit= 256      /* signal a long double argument*/
  231.                 } flagBits;
  232.  
  233.         flagBits flagSet;
  234.  
  235.         unsigned aP;
  236.         char     fc;                    /* format char, from fmt string */
  237.         char     isSigned;              /* chooses signed/unsigned ints */
  238.         int      width;
  239.         int      precision;
  240.         char     plusSign;
  241.         int      leadZ;
  242.         unsigned abandonP;              /* posn of bad syntax in fmt str*/
  243.         char     tempStr [__CVTMAX__];  /* longest _realcvt or longtoa string*/
  244.         unsigned totalSent = 0;         /* characters sent to putter    */
  245.         unsigned Scount = Ssize;        /* free space remaining in S    */
  246.         char     S [Ssize];             /* temp working result buffer   */
  247.         int      eof_error = 0;         /* flag, TRUE is EOF error      */
  248.  
  249. #if 0   /* the remaining variables are held entirely in registers       */
  250.  
  251.         char    hexCase;                /* upper/lower Hex alphabet     */
  252.         long    tempL;
  253.         syntaxStages    stage; -- CH
  254.         char            c;
  255.         char            *cP;
  256.         int             *iP;
  257. #endif
  258.  
  259.         SaveSI
  260.         SaveDI
  261. /*
  262. General outline of the method:
  263.  
  264. First the string is scanned, and conversion specifications detected.
  265.  
  266. The preliminary fields of a conversion (flags, width, precision, long)
  267. are detected and noted.
  268.  
  269. The argument is fetched and converted, under the optional guidance of
  270. the values of the preliminary fields.  With the sole exception of the
  271. 's' conversion, the converted strings are first placed in the tempStr
  272. buffer.
  273.  
  274. The contents of the tempStr (or the argument string for 's') are copied
  275. to the output, following the guidance of the preliminary fields in
  276. matters such as zero fill, field width, and justification.
  277. */
  278.  
  279. I       jmp short func_start    /* Skip over inline nested PROCs        */
  280.  
  281. /***************************************************************************
  282.                 local, nested functions are placed here
  283.                 ES *must* be defined in all models.
  284. ***************************************************************************/
  285.  
  286. #define RETN    db      0xC3    /* "RETN" is used to force a near ret   */
  287.  
  288. /* Get length of string pointed to by ES:DI, return result in CX.       */
  289.  
  290. I vpr_strlen LABEL NEAR         /* scan string ES: [DI] up to \0        */
  291. I       push    di
  292. I       mov     cx, -1          /*   count the string length.           */
  293. I       xor     al, al
  294. I       repne   scasb
  295. I       not     cx              /* (not CX) == (-1 -CX)                 */
  296. I       dec     cx              /* scasb overshoots                     */
  297. I       pop     di
  298. I       RETN
  299.  
  300.  
  301. /* call *putter to flush S */
  302. /* Put character to next position in S, check for S full */
  303.  
  304. I vpr_PutToS LABEL NEAR
  305. I       mov     BY0 (ss:[di]), al
  306. I       inc     di
  307. I       dec     BY0 (Scount)
  308. I       jnz     exit_PutToS
  309.  
  310. I vpr_CallPutter LABEL NEAR
  311. I       push    bx
  312. I       push    cx
  313. I       push    dx
  314. I       push    ES
  315. I       lea     ax, S
  316. I       sub     di, ax          /* count chars in S */
  317.  
  318.         if( !putter (S, _DI, outP) )
  319.           {
  320.           eof_error = 1;
  321.           }
  322.  
  323.         Scount = Ssize;
  324.         totalSent += _DI;
  325.  
  326. I       lea     di, S
  327. I       pop     ES
  328. I       pop     dx
  329. I       pop     cx
  330. I       pop     bx
  331.  
  332. exit_PutToS :
  333. I       RETN                    /* 'shared' RET for both PROCs */
  334.  
  335. /************************ end of embedded functions *******************/
  336.  
  337. func_start:
  338.  
  339. I       push    ES
  340. I       cld
  341.  
  342. I       lea     di, S
  343. I       mov     aP, di
  344.  
  345. /*
  346. This paragraph is arranged to give in-line flow to the most frequent
  347. case, literal transcription from *formP to *outP.
  348. */
  349.  
  350. vpr_NEXTap:
  351. I       mov     di, aP
  352.  
  353. vpr_NEXT:                       /* loop to here when DI still valid */
  354. I       LES_    si, formP
  355.  
  356.         for (;;)                /* resume here from this literal/space */
  357.         {
  358. vpr_nextCh :
  359. I               lods    BY0 (ES_ [si])  /* if (pattern[x] == '\0')      */
  360. I               or      al, al          /*      goto exit               */
  361. I               jz      vpr_respondJmp
  362.  
  363. I               cmp     al, '%'         /* '%' char begins a conversion */
  364. I               je      vpr_CONV
  365.  
  366. vpr_literal:                            /* but "%%" is just a literal '%'. */
  367. I               mov     ss:[di], al
  368. I               inc     di
  369.  
  370. I               dec     BY0 (Scount)    /* if (--Scount)        */
  371. I               jg      vpr_nextCh      /*      continue;       */
  372.  
  373. I               call    vpr_CallPutter  /* Compact way(smaller)         */
  374.         }
  375.  
  376. vpr_respondJmp:
  377. I       jmp     vpr_respond
  378.  
  379. /* If arrived here then a conversion specification has been encountered. */
  380.  
  381. vpr_CONV:
  382. I       mov     W0 (abandonP), si       /* abandon will print from here */
  383.  
  384. I       lods    BY0 (ES_ [si])          /* AL <- char at ES:SI          */
  385. I       cmp     al, '%'                 /* %% really means %            */
  386. I       je      vpr_literal
  387.  
  388. I       mov     W0 (aP), di             /* keep result pointer safe     */
  389.  
  390. I       xor     cx, cx                  /* CH is flagStage              */
  391. I       mov     W0 (leadZ), cx          /* leadZ     <- 0               */
  392. #if LDATA
  393. I       mov     W0 (flagSet), farPtrBit /* flagSet   <- pointers are FAR*/
  394. #else
  395. I       mov     W0 (flagSet), cx        /* flagSet   <- 0               */
  396. #endif
  397. I       mov     BY0 (plusSign), cl      /* plusSign  <- 0               */
  398. I       mov     W0 (width), -1          /* width     <- default         */
  399. I       mov     W0 (precision), -1      /* precision <- default         */
  400. I       jmp     short vpr_doSwitch
  401.  
  402.                 /*==================================*/
  403.                 /* loop to here when scanning flags */
  404.                 /*==================================*/
  405.  
  406. vpr_nextSwitch:
  407. I       lods    BY0 (ES_ [si])          /* AL <- char at ES:SI          */
  408.  
  409. /**************************************************************************
  410.  *                 Main character classification switch                   *
  411.  **************************************************************************/
  412.  
  413. vpr_doSwitch:
  414. I       xor     ah, ah                  /* Remove any high order trash  */
  415. I       mov     dx, ax                  /* Duplicate original char in DL*/
  416. I       mov     bx, ax                  /* Duplicate original char in BL*/
  417. I       sub     bl, ' '                 /* Scale char in BL to 0-95     */
  418. I       cmp     bl, 128 - ' '           /* Weed out don't cares         */
  419. I       jae     vpr_jmpAbandon
  420. I       mov     bl, BY0 (printCtype [bx]) /* BL <- char type of the char*/
  421.  
  422.         switch  (_BX)                   /* =-=>  clobbers AX, BX  <=-=  */
  423.         {
  424.  
  425. vpr_jmpAbandon:                         /* Extend local jump range      */
  426. I       jmp     vpr_abandon
  427.  
  428. case (_af):                             /* when '#' was seen            */
  429. I       cmp     ch, flagStage
  430. I       ja      vpr_jmpAbandon
  431. I       or      W0 (flagSet), altFormatBit
  432. I       jmp     vpr_nextSwitch
  433.  
  434. case (_lj):                             /* when '-' was seen            */
  435. I       cmp     ch, flagStage
  436. I       ja      vpr_jmpAbandon
  437. I       or      W0 (flagSet), leftJustBit
  438. I       jmp     vpr_nextSwitch
  439.  
  440. case (_si):                             /* when ' ' or '+' was seen     */
  441. I       cmp     ch, flagStage
  442. I       ja      vpr_jmpAbandon
  443. I       cmp     BY0 (plusSign), 2Bh     /* '+'                          */
  444. I       je      gtvp_nxt_swit           /* ' ' ignored if '+' already   */
  445. I       mov     plusSign, dl
  446.  
  447. gtvp_nxt_swit:
  448. I       jmp     vpr_nextSwitch
  449.  
  450. case (_ne):                             /* near pointer                 */
  451. I       and     W0 (flagSet), NOT farPtrBit
  452. I       jmp     short ell_stagetail
  453.  
  454. case (_fa):                             /* far pointer                  */
  455. I       or      W0 (flagSet), farPtrBit
  456. ell_stagetail:
  457. I       mov     ch, ellStage
  458. I       jmp     vpr_nextSwitch
  459.  
  460.  
  461. case (_fz):                             /* leading width '0' is a flag  */
  462. I       cmp     ch, flagStage
  463. I       ja      case_nu                 /*   else it is just a digit    */
  464. I       test    W0 (flagSet), leftJustBit
  465. I       jnz     short   vpr_nextSwitchJmp
  466. I       or      W0 (flagSet), fillZerosBit
  467. I       mov     ch, fillzStage          /*   but it must be part of width */
  468. I       jmp     vpr_nextSwitch
  469.  
  470. vpr_abandonJmp:                         /* Extend local jump range      */
  471. I       jmp     vpr_abandon
  472.  
  473. case (_ar):                             /* when '*' was seen it causes  */
  474. I       mov     di, argP
  475. I       mov     ax, ss:[di]             /*    the next argument to be   */
  476. I       add     W0 (argP), 2            /*       taken, depending on    */
  477. I       cmp     ch, wideStage           /*          the stage, as the   */
  478. I       jnb     vpr_argPrec             /*             width, or...     */
  479.  
  480. I       or      ax,ax                   /* is the width negative?       */
  481. I       jns     vpr_pos
  482. I       neg     ax
  483. I       or      W0 (flagSet), leftJustBit
  484.  
  485. vpr_pos:
  486. I       mov     width, ax
  487. I       mov     ch, wideStage + 1
  488. vpr_nextSwitchJmp:
  489. I       jmp     vpr_nextSwitch
  490.  
  491. vpr_argPrec:
  492. I       cmp     ch, precStage
  493. I       jne     vpr_abandonJmp
  494. I       mov     precision, ax           /*             the precision.   */
  495. I       inc     ch
  496. I       jmp     vpr_nextSwitch
  497.  
  498. case (_pr):                             /* when '.' is seen, precision  */
  499. I       cmp     ch, precStage
  500. I       jnb     vpr_abandonJmp
  501. I       mov     ch, precStage           /* should follow                */
  502. I       inc     W0 (precision)          /* if no digits, ANSI says zero */
  503. I       jmp     vpr_nextSwitch
  504.  
  505. /*
  506.         When a numeral is seen, it may be either part of a width, or
  507.         part of the precision, depending on the stage.
  508. */
  509. case (_nu):                             /* when 0..9 seen               */
  510. case_nu:
  511. I       xchg    ax, dx                  /* move char back into AL       */
  512. I       sub     al, '0'                 /* turn '0'-'9' to 0-9          */
  513. I       cbw                             /* make it a word               */
  514. I       cmp     ch, wideStage           /* is it part of a width spec?  */
  515. I       ja      vpr_precNumeral         /* no, see if it's a precision  */
  516.  
  517. I       mov     ch, wideStage
  518. I       xchg    ax, width
  519. I       or      ax, ax                  /* first width digit ?          */
  520. I       jl      vpr_nextSwitchJmp       /*   default width was -1       */
  521. I       shl     ax, 1                   /* *2                           */
  522. I       mov     dx, ax
  523. I       shl     ax, 1                   /* *4                           */
  524. I       shl     ax, 1                   /* *8                           */
  525. I       add     ax, dx                  /* (*2 + *8) = *10              */
  526. I       add     width, ax               /* width = (width * 10 + num)   */
  527. I       jmp     vpr_nextSwitch
  528.  
  529. vpr_precNumeral:
  530. I       cmp     ch, precStage           /* is it part of precision spec */
  531. I       jne     vpr_abandonJmp          /* no, it's just a literal      */
  532.  
  533. //  At this point we know that the precision specifier '.' has been seen,
  534. //  so we know that the precision is zero (set at '.') or greater.
  535.  
  536. I       xchg    ax, precision           /* we only need to scale the    */
  537. I       or      ax, ax                  /* precision if it's non zero   */
  538. I       jz      vpr_nextSwitchJmp
  539. I       shl     ax, 1                   /* *2                           */
  540. I       mov     dx, ax
  541. I       shl     ax, 1                   /* *4                           */
  542. I       shl     ax, 1                   /* *8                           */
  543. I       add     ax, dx                  /* (*2 + *8) = *10              */
  544. I       add     precision, ax           /* prec = (prec * 10 + numeral) */
  545. I       jmp     vpr_nextSwitch
  546.  
  547.  
  548. case (_lo):                             /* 'l' was seen (long)          */
  549. I       or      W0 (flagSet), isLongBit
  550. I       jmp     ell_stagetail
  551.  
  552. case (_ld):                             /* 'L' was seen (long double)   */
  553. I       or      W0 (flagSet), LongDoubleBit
  554.  
  555. case (_sh):                             /* 'h' or 'H' was seen (short)  */
  556. I       and     W0 (flagSet), not isLongBit
  557. I       jmp     ell_stagetail
  558.  
  559. /*--------------------------------------------------------------------------
  560. The previous cases covered all the possible flags.  Now the following
  561. cases deal with the different argument types.
  562.  
  563. Remember DL contains a copy of the original character.
  564. --------------------------------------------------------------------------*/
  565.  
  566.         /*==========================================================*/
  567.         /* The first group of cases is for the integer conversions. */
  568.         /*==========================================================*/
  569.  
  570. case (_oc):                             /* octal                        */
  571. I       mov     bh, 8                   /* BH <- Base 8                 */
  572. I       jmp     short vpr_NoSign
  573.  
  574. case (_un):                             /* unsigned                     */
  575. I       mov     bh, 10                  /* BH <- Base 10                */
  576. I       jmp     short vpr_UINT
  577.  
  578.  
  579. case (_he):                             /* hex                          */
  580. I       mov     bh, 10h                 /* BH <- Base 16                */
  581. I       mov     bl, 'A' - 'X'
  582. I       add     bl, dl                  /* Adjust for aAbBcC etc later  */
  583.  
  584. vpr_NoSign:
  585. I       mov     BY0 (plusSign), 0       /* It's an unsigned operand     */
  586. /*      jmp     short   vpr_UINT */
  587.  
  588.  
  589. vpr_UINT:
  590. I       mov     fc, dl                  /* 'fc' <- orig fmt char        */
  591. I       xor     dx, dx                  /* zero extend by default       */
  592. I       mov     BY0 (isSigned), dl
  593. I       mov     di, argP
  594. I       mov     ax, ss:[di]             /* AX <- word arg at SS:DI      */
  595. I       jmp     short vpr_toAscii
  596.  
  597.  
  598. case (_de):                             /* decimal                      */
  599. I       mov     bh, 10                  /* BH <- Base 10                */
  600. vpr_INT:
  601. I       mov     BY0 (isSigned), 1
  602. I       mov     fc, dl                  /* 'fc' <- orig fmt char        */
  603.  
  604. I       mov     di, argP                /* SS:DI -> argument word[0]    */
  605. I       mov     ax, ss:[di]             /* AX <- word arg at SS:DI      */
  606. I       cwd                             /* sign-extend by default       */
  607.  
  608. vpr_toAscii:
  609. I       inc     di                      /* SS:DI -> next arg word       */
  610. I       inc     di
  611.  
  612. I       mov     formP, si               /* remember progress through format */
  613.  
  614. I       test    W0 (flagSet),isLongBit  /* short or long int ?          */
  615. I       je      vpr_shortInt            /* If the operand is a long     */
  616. I       mov     dx, ss:[di]             /* DX:AX holds long argument    */
  617. I       inc     di                      /* SS:DI -> next arg word       */
  618. I       inc     di
  619.  
  620. vpr_shortInt:
  621. I       mov     argP, di                /* Save arg list pointer        */
  622.  
  623. I       lea     di, tempStr [1]         /* (SS) DI <- &tempStr[1]       */
  624.  
  625. I       or      ax, ax                  /* Is the value zero?           */
  626. I       jnz     vpr_flag_nz             /* No,                          */
  627. I       or      dx, dx                  /* Is the value zero?           */
  628. I       jnz     vpr_flag_nz             /* No,                          */
  629.  
  630. /*-----------------------------------------------------------------------
  631.         Check for the special ANSI case of a zero value with an explicit
  632.         precision of zero.
  633. ------------------------------------------------------------------------*/
  634.  
  635. I       cmp     W0 (precision), 0       /* Is it the special case?      */
  636. I       jne     vpr_flag_zr             /* No, continue                 */
  637. I       mov     byte ptr SS:[di], 0     /* Otherwise, make empty string */
  638. I       mov     ax, di                  /* longtoa returns pointer      */
  639. I       jmp     vpr_converted
  640.  
  641.  
  642. /*-------------------------------------------------------------------------
  643.         "Normal" integer output cases wind up down here somewhere.
  644. -------------------------------------------------------------------------*/
  645.  
  646. vpr_flag_nz:
  647. I       or      W0 (flagSet), notZeroBit /* flag non-zeroness           */
  648. vpr_flag_zr:
  649.  
  650. vpr_doLtoA:
  651. I       push    dx                      /* Push long value (AX:DX)      */
  652. I       push    ax
  653.  
  654. #if LDATA
  655. I       push    SS
  656. #endif
  657. I       push    di                      /*    ie. &tempStr[1]           */
  658.  
  659. I       mov     al, bh                  /* AL <- numeric base/radix     */
  660. I       cbw                             /* Convert it to a word         */
  661. I       push    ax                      /* Push the radix               */
  662.  
  663. I       mov     al, isSigned            /* Push the isSigned flag,      */
  664. I       push    ax                      /* AH should still be 0         */
  665.  
  666. I       push    bx                      /* BL ==        , hexCase)      */
  667.  
  668. /***    __longtoa(number, string, radix, signflag, hexcase)           ***/
  669.  
  670. I       call    __longtoa               /* returns pointer to string    */
  671.  
  672. vpr_converted:
  673. I       push    SS
  674. I       pop     ES                      /* ES_ [di] = cP == 1+tempStr   */
  675.                                         /* ES is needed in all models   */
  676.  
  677. I       mov     dx, precision           /* Has precsion been set?       */
  678. I       or      dx, dx
  679. I       jge     vpr_countActualJmp      /* Yes.                         */
  680. I       jmp     vpr_testFillZeros       /* No.                          */
  681.  
  682. vpr_countActualJmp:
  683. I       jmp     vpr_countActual
  684.  
  685. /*
  686. The 'p' conversion takes either a near or a far pointer and puts
  687. it out in the usual Intel xxxx:xxxx hex style.
  688. */
  689. case (_pt):                             /* pointer      */
  690. I       mov     fc, dl                  /* remember the type character. */
  691. I       mov     formP, si               /* remember progress through format */
  692. I       lea     di, tempStr
  693.  
  694. I       mov     bx, argP
  695. I       push    ss:[bx]                 /* fetch the argument.w0 */
  696. I       inc     bx
  697. I       inc     bx
  698. I       mov     argP, bx
  699.  
  700. I       test    W0 (flagSet), farPtrBit
  701. I       jz      vpr_ptrLSW
  702.  
  703. I       mov     dx, ss:[bx]             /* fetch the argument.w1 */
  704. I       inc     bx
  705. I       inc     bx
  706. I       mov     argP, bx
  707. I       push    SS
  708. I       pop     ES
  709. I       call    Hex4
  710.  
  711. /*      add     di, 4                   Hex4 does this          */
  712.  
  713. I       mov     al, ':'
  714. I       stosb
  715.  
  716. vpr_ptrLSW:
  717. I       push    SS
  718. I       pop     ES
  719. I       pop     dx
  720. I       call    Hex4
  721.  
  722. /*      add     di, 4                   Hex4 does this          */
  723.  
  724. I       mov     BY0 (ss:[di]), 0
  725.  
  726. I       mov     BY0 (isSigned), 0
  727. I       and     W0 (flagSet), NOT notZeroBit
  728.  
  729. I       lea     cx, tempStr
  730. I       sub     di, cx
  731. I       xchg    cx, di          /* CX = len,  DI = tempStr      */
  732.  
  733. I       mov     dx, precision
  734. I       cmp     dx, cx
  735. I       jg      vpr_ptrEnd
  736. I       mov     dx, cx
  737.  
  738. vpr_ptrEnd:
  739. I       jmp     vpr_testFillZeros
  740.  
  741.  
  742. /*
  743. The 'c' conversion takes a character as parameter.  Note, however,
  744. that the character occupies an (int) sized cell in the argument
  745. list.
  746. */
  747.  
  748. case (_ch):                     /* char         */
  749. I       mov     formP, si       /* remember progress through format */
  750. I       mov     fc, dl          /* remember the type character */
  751.  
  752. I       mov     di, argP
  753. I       mov     ax, ss:[di]
  754. I       add     W0 (argP), 2
  755.  
  756. I       push    SS
  757. I       pop     ES
  758. I       lea     di, tempStr [1]
  759. I       xor     ah, ah          /* terminate the temporary string. */
  760. I       mov     ss:[di], ax
  761. I       mov     cx, 1
  762. I       jmp     vpr_CopyLen
  763.  
  764. /*
  765. The 's' conversion takes a string (char *) as argument and copies
  766. the string to the output buffer.
  767. */
  768.  
  769. case (_st):                     /* string       */
  770. I       mov     formP, si       /* remember progress through format */
  771. I       mov     fc, dl          /* remember the type character */
  772.  
  773. I       mov     di, argP
  774. I       test    W0 (flagSet), farPtrBit
  775. I       jnz     vpr_farString
  776. #ifdef __HUGE__
  777. I       jmp     vpr_abandonJmp  /* DS can't be assumed in HUGE model */
  778. #else
  779. I       mov     di, ss:[di]     /* [di] = (DS:char *) *(argP++) */
  780. I       add     W0 (argP), 2
  781. I       push    DS
  782. I       pop     ES
  783. I       or      di, di
  784. I       jmp     short vpr_countString
  785. #endif
  786. vpr_farString:
  787. I       les     di, ss:[di]     /* ES: [di] = (char far *) *(argP++) */
  788. I       add     W0 (argP), 4
  789. I       mov     ax, es
  790. I       or      ax, di
  791.  
  792. vpr_countString:
  793. I       jnz     NotaNullPtr
  794. I       push    DS
  795. I       pop     ES
  796. I       lea     di, NullString
  797.  
  798. NotaNullPtr:
  799. I       call    vpr_strlen              /* CX = strlen (ES: [di]) */
  800. I       cmp     cx, precision
  801. I       jna     vpr_CopyLenJmp
  802. I       mov     cx, precision           /* precision may truncate string. */
  803.  
  804. vpr_CopyLenJmp:
  805. I       jmp     vpr_CopyLen
  806.  
  807.  
  808. /* All real-number conversions are done by __realcvt. */
  809.  
  810. case (_fl):                     /* float        */
  811. I       mov     formP, si       /* remember progress through format */
  812. I       mov     fc, dl          /* remember the type character */
  813.  
  814. I       mov     di, argP
  815.  
  816. I       mov     cx, precision
  817. I       or      cx, cx          /* is precision defaulted ? */
  818. I       jnl     vpr_cvtReal
  819. I       mov     cx, 6
  820.  
  821. vpr_cvtReal:
  822. #if LDATA
  823. I       push    SS
  824. #endif
  825. I       push    di              /* (valueP */
  826. I       push    cx              /*      , ndec */
  827. #if LDATA
  828. I       push    SS
  829. #endif
  830. I       lea     bx, tempStr [1]
  831. I       push    bx                      /*      , cP */
  832. I       push    dx                      /*      , formCh */
  833. I       mov     ax, altFormatBit
  834. I       and     ax, W0 (flagSet)
  835. I       push    ax                      /*      , altFormat) */
  836.  
  837. /*
  838.         Determine the argument type double/long double.
  839.         Save the size of the argument type.
  840. */
  841. I       mov     ax, W0 (flagSet)
  842.  
  843. try_long :
  844. I       test    ax, LongDoubleBit
  845. I       jz      its_plain_double
  846. I       mov     ax, F_10byteFloat
  847. I       add     W0 (argP), 10           /* argP += sizeof(long double) */
  848. I       jmp     short push_argtype
  849.  
  850. its_plain_double :
  851. I       add     W0 (argP), 8            /* argP += sizeof(double) */
  852. I       mov     ax, F_8byteFloat
  853.  
  854. push_argtype :
  855. I       push    ax
  856.  
  857. I       call    __realcvt
  858.  
  859. I       push    SS
  860. I       pop     ES
  861. I       lea     di, tempStr [1]         /* ES_ [di] = cP == 1+tempStr */
  862.  
  863. vpr_testFillZeros:
  864. I       test    W0 (flagSet), fillZerosBit
  865. I       jz      vpr_NUMERIC
  866. I       mov     dx, width
  867. I       or      dx, dx
  868. I       jng     vpr_NUMERIC
  869.  
  870. vpr_countActual:                        /* Get strlen of result string  */
  871. I       call    vpr_strlen              /* CX <- strlen (ES:[DI])       */
  872. I       cmp     BY0 (ES: [di]), '-'
  873. I       jne     vpr_noSignAdjust
  874. I       dec     cx                      /* Length too long because '-'  */
  875. vpr_noSignAdjust:
  876. I       sub     dx, cx                  /* DX <- leading 0 count(if any)*/
  877. I       jng     vpr_NUMERIC             /* leadZ defaulted to 0 before  */
  878. I       mov     leadZ, dx               /* leadZ <- (width or prec-len) */
  879.  
  880. /*
  881. If arrived here, then tempStr contains the result of a numeric
  882. conversion.  It may be necessary the prefix the number with
  883. a mandatory sign or space.
  884. */
  885.  
  886. vpr_NUMERIC:                            /* ES must be well defined !    */
  887. I       cmp     BY0 (ES: [di]), '-'     /* If sign there then adjust    */
  888. I       je      vpr_AdjustLeadZ
  889. I       mov     al, plusSign            /* Do we need a sign?           */
  890. I       or      al, al
  891. I       jz      vpr_COPY                /* No, not required             */
  892. I       dec     di                      /* Back up 1 in the string      */
  893. I       mov     ES: [di], al            /*    and insert the sign       */
  894. vpr_AdjustLeadZ:
  895. I       cmp     W0 (leadZ), 0           /* If leadZ > 0 then leadZ--    */
  896. I       jle     vpr_COPY
  897. I       mov     cx, precision
  898. I       or      cx, cx
  899. I       jge     vpr_COPY                /* Don't adjust if precision set*/
  900. I       dec     W0 (leadZ)
  901.  
  902. /*
  903. If arrived here then ES: [di] = cP points to the converted string,
  904. which must now be padded, aligned, and copied to the output.
  905. */
  906.  
  907. vpr_COPY:
  908. I       call    vpr_strlen              /* CX = strlen (ES: [di])       */
  909.  
  910. vpr_CopyLen:                            /* comes from %c or %s section  */
  911. I       mov     si, di                  /* cP <- ES: [si]               */
  912. I       mov     di, aP
  913.  
  914. I       mov     bx, width               /* BX <- width                  */
  915.  
  916. I       mov     ax, notZeroBit + altFormatBit
  917. I       and     ax, W0 (flagSet)
  918. I       cmp     ax, notZeroBit + altFormatBit
  919. I       jne     goto_doLead
  920. I       mov     ah, fc                  /* AH <- original format char   */
  921.  
  922. I       cmp     ah, 'o'                 /* Is it alternate octal form?  */
  923. I       jne     vpr_maybeAltHex         /* No, try the next one         */
  924. I       cmp     W0 (leadZ), 0           /* Yes, alternate mode w/octal  */
  925. I       jg      goto_doLead             /*   requires at least          */
  926. I       mov     W0 (leadZ), 1           /*     one leading zero.        */
  927.  
  928. goto_doLead:
  929. I       jmp     vpr_doLead;
  930.  
  931. vpr_maybeAltHex:
  932. I       cmp     ah, 'x'                 /* Is it alternate hex form?    */
  933. I       je      vpr_isAltHex            /* Yes, send                    */
  934. I       cmp     ah, 'X'                 /*    "0x" or "0X" prefix.      */
  935. I       jne     vpr_doLead              /* No, insert leading 0's       */
  936.  
  937. vpr_isAltHex:
  938. I       or      W0 (flagSet), alt0xBit  /* flagSet |= alt0xBit;         */
  939. I       dec     bx                      /* width -= 2;                  */
  940. I       dec     bx
  941. I       sub     W0 (leadZ), 2           /* leadZ -= 2;                  */
  942. I       jnl     vpr_doLead              /* Still leading 0's?           */
  943. I       mov     W0 (leadZ), 0           /* No more leading 0's          */
  944.  
  945. vpr_doLead:
  946. I       add     cx, leadZ               /* CX <- len + leadZ            */
  947.  
  948.                 /* Is result to be left justified? */
  949.  
  950. I       test    W0 (flagSet), leftJustBit
  951. I       jnz     vpr_check0x
  952. I       jmp     short vpr_nextJust      /* (! leftJust) == leftFill */
  953.  
  954. vpr_justLoop:
  955. I       mov     al, ' '
  956. I       call    vpr_PutToS
  957. I       dec     bx
  958.  
  959. vpr_nextJust:
  960. I       cmp     bx, cx
  961. I       jg      vpr_justLoop
  962.  
  963. vpr_check0x:
  964. I       test    W0 (flagSet), alt0xBit  /* Need alternate hex form?     */
  965. I       jz     vpr_checkLeadZ           /* No,                          */
  966.  
  967. I       mov     al, '0'                 /* Yes, Send "0x" or "0X"       */
  968. I       call    vpr_PutToS
  969. I       mov     al, fc                  /* original 'fc' is 'x' or 'X'  */
  970. I       call    vpr_PutToS
  971.  
  972. vpr_checkLeadZ:                         /* leading zero fill required ? */
  973. I       mov     dx, leadZ
  974. I       or      dx, dx
  975. I       jng     vpr_actualCopy
  976.  
  977. I       sub     cx, dx                  /* len -= leadZ */
  978. I       sub     bx, dx                  /* width -= leadZ */
  979.  
  980. I       mov     al, ES: [si]            /* any leading sign must be */
  981. I       cmp     al, '-'                 /*   copied before the      */
  982. I       je      vpr_leadSign            /*     leading zeros.       */
  983. I       cmp     al, ' '
  984. I       je      vpr_leadSign
  985. I       cmp     al, '+'
  986. I       jne     vpr_signedLead
  987.  
  988. vpr_leadSign:
  989. I       lods    BY0 (ES: [si])          /* Get the 'sign'               */
  990. I       call    vpr_PutToS              /* Send the 'sign'              */
  991. I       dec     cx
  992. I       dec     bx                      /* anticipates actualCopy     */
  993.  
  994. vpr_signedLead:
  995. I       xchg    cx, dx                  /* leading zeros follow sign */
  996. I       jcxz    vpr_leadDone
  997.  
  998. vpr_leadZero:
  999. I       mov     al, '0'
  1000. I       call    vpr_PutToS
  1001. I       loop    vpr_leadZero
  1002.  
  1003. vpr_leadDone:
  1004. I       xchg    cx, dx
  1005.  
  1006.  
  1007. /* Now we copy the actual converted string from tempStr to output. */
  1008.  
  1009. vpr_actualCopy:
  1010.  
  1011. I       jcxz    vpr_copied      /* Degenerate case?     */
  1012. I       sub     bx, cx          /* No, width -= len;    */
  1013.  
  1014. vpr_copyLoop:                   /* this is the high-point of __vprinter ! */
  1015. I       lods    BY0 (ES: [si])          /* ES:SI -> tempStr     */
  1016. I       mov     BY0 (SS: [di]), al      /* SS:DI -> S[xxx]      */
  1017. I       inc     di
  1018. I       dec     BY0 (Scount)
  1019. I       jg      vpr_loopTest
  1020. I       call    vpr_CallPutter
  1021. vpr_loopTest:
  1022. I       loop    vpr_copyLoop
  1023.  
  1024. vpr_copied:
  1025.  
  1026. /* Is the field to be right-filled ? */
  1027.  
  1028. I       or      bx, bx          /* any remaining width ? */
  1029. I       jng     vpr_done
  1030. I       mov     cx, bx
  1031.  
  1032. vpr_rightLoop:
  1033. I       mov     al, ' '
  1034. I       call    vpr_PutToS
  1035. I       loop    vpr_rightLoop
  1036.  
  1037.  
  1038. /* If arrive here, the conversion has been done and copied to output. */
  1039.  
  1040. vpr_done:
  1041. I       jmp     vpr_NEXT
  1042.  
  1043.  
  1044. case (_ns) :                 /* number sent */
  1045. I       mov     formP, si    /* remember progress through format */
  1046.  
  1047. I       mov     di, argP
  1048. I       test    W0 (flagSet), farPtrBit
  1049. I       jnz     vpr_farCount
  1050. #ifdef __HUGE__
  1051. I       jmp     vpr_abandonJmp  /* DS can't be assumed in HUGE model */
  1052. #else
  1053. I       mov     di, ss:[di]  /* [di]=(DS:char *) *((int _ss *)argP++)*/
  1054. I       add     W0 (argP), 2
  1055. I       push    DS
  1056. I       pop     ES
  1057. I       jmp     short vpr_makeCount
  1058. #endif
  1059. vpr_farCount:
  1060. I       les     di, ss:[di]  /* ES:[di] = (char far *) *((long _ss *)argP++) */
  1061. I       add     W0 (argP), 4
  1062.  
  1063. vpr_makeCount:
  1064. I       mov     ax, Ssize
  1065. I       sub     al, Scount
  1066. I       add     ax, totalSent
  1067. I       mov     ES: [di], ax
  1068. I       test    W0(flagSet),isLongBit
  1069. I       jz      vpr_shortN
  1070. I       inc     di
  1071. I       inc     di
  1072. I       mov     word ptr ES: [di], 0
  1073. vpr_shortN:
  1074. I       jmp     vpr_NEXTap
  1075.  
  1076.  
  1077. case (_zz):     /* \0 characters, unexpected end of format string       */
  1078. case (_dc):     /* ordinary "don't care" chars in the wrong position    */
  1079. case (_pc):     /* '%' percent characters in the wrong position         */
  1080. ;               /* goto vpr_abandon     */
  1081. }               /* end switch */
  1082.  
  1083. /*
  1084. If the format goes badly wrong, then copy it literally to the output
  1085. and abandon the conversion.
  1086. */
  1087.  
  1088. vpr_abandon:
  1089. I       mov     si, abandonP
  1090. #if LDATA
  1091. I       mov     ES, W1 (formP)
  1092. #endif
  1093. I       mov     di, aP
  1094. I       mov     al, '%'
  1095.  
  1096. vpr_abandLoop:
  1097. I       call    vpr_PutToS
  1098. I       lods    BY0 (ES_ [si])
  1099. I       or      al, al
  1100. I       jnz     vpr_abandLoop
  1101.  
  1102.  
  1103. /* If arrived here then the function has finished (either correctly or not). */
  1104.  
  1105. vpr_respond:
  1106. I       cmp     BY0 (Scount), Ssize     /* anything waiting to be written ? */
  1107. I       jnl     vpr_end
  1108. I       call    vpr_CallPutter
  1109. vpr_end:
  1110. I       pop     ES
  1111.  
  1112.     if( eof_error )  return( EOF );
  1113.     else             return( totalSent );
  1114. }
  1115.