I49printer.c
上传用户:super_houu
上传日期:2008-09-21
资源大小:4099k
文件大小:41k
源码类别:

DVD

开发平台:

Others

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