I49printer.c
上传用户:super_houu
上传日期:2008-09-21
资源大小:4099k
文件大小:41k
- /*
- * Paradigm C/C++ Run-Time Library - Version 5.0
- *
- * Copyright (c) 1998 Paradigm Systems. All rights reserved.
- * Portions Copyright (c) 1996 Borland International.
- *
- * $Revision: 5 $
- * $Workfile: I49printer.c $
- *
- * function(s)
- * Hex4 - converts int to 4 hex digits
- * __vprinter - sends formatted output
- */
- #include "Config.h" // Global Configuration - do not remove!
- #pragma inline
- #include <stdio.h>
- #include "ServicesIncludeasmrules.h"
- #include "ServicesInclude_printf.h"
- #define I49_PRINTF 1
- #ifdef I49_PRINTF
- #pragma codeseg _TEXT "CODE"
- #include "cpuv186tv186t.h"
- #endif
- #define I asm
- #define BREAKPOINT asm int 3
- #ifdef I49_PRINTF
- static const far char NullString[] = "(null)";
- #else
- static char NullString[] = "(null)";
- #endif
- /*-----------------------------------------------------------------------*
- Name Hex4 - converts int to 4 hex digits
- Usage static void near pascal Hex4( void )
- Description Convert 16 bit parameter (in dx) to 4 hex digits at ES: [di].
- NOTE: TC does not realize that "stosb" implies DI, so DI is
- not pushed/popped. That is nice, but one day it may cease
- to be true...
- The calling code expects di to be incremented by 4 as a
- side effect of this function.
- *------------------------------------------------------------------------*/
- I _TEXT segment
- I Hex4 proc near
- I mov al,dh
- I call Byte2Ascii
- I mov al,dl
- I Byte2Ascii: /* convert byte in al to ASCII */
- I db 0d4h,10h /* AAM trick to separate nibbles in al */
- I xchg ah,al
- I call Nibble2Ascii
- I xchg ah,al
- I Nibble2Ascii: /* convert hex digit in al to ASCII */
- I add al,90h
- I daa
- I adc al,40h
- I daa
- I stosb
- I ret
- I endp
- I ends
- /*-----------------------------------------------------------------------*
- __vprinter is a table-driven design, for speed and flexibility. There are
- two tables. The first table classifies all 7-bit ASCII chars and then the
- second table is the switch table which points to the function blocks which
- handle the various classes of characters.
- All characters with the 8th bit set are currently classed as don't cares,
- which is the class of character also used for normal alphabetics. All
- characters less than ' ' (0x20) are also classed as don't cares.
- *------------------------------------------------------------------------*/
- typedef
- enum
- {
- _si, /* sign fill +/- */
- _af, /* alternate form */
- _ar, /* format (width or precision) by argument */
- _lj, /* left justify */
- _pr, /* precision */
- _nu, /* numeral */
- _lo, /* long */
- _ld, /* long double */
- _sh, /* short */
- _fz, /* fill zeros */
- _de, /* decimal */
- _oc, /* octal */
- _un, /* unsigned decimal */
- _he, /* hexadecimal */
- _pt, /* pointer */
- _fl, /* float */
- _ch, /* char */
- _st, /* string */
- _ns, /* number sent */
- _zz, /* terminator */
- _dc, /* don't care */
- _pc, /* percent */
- _ne, /* near pointer */
- _fa, /* far pointer */
- } characterClass;
- /* Here is the table of classes, indexed by character. */
- #ifdef I49_PRINTF
- static const far unsigned char printCtype [96] =
- #else
- static unsigned char printCtype [96] =
- #endif
- {
- /* SP ! " # $ % & ' ( ) * + , - . / */
- _si,_dc,_dc,_af,_dc,_pc,_dc,_dc,_dc,_dc,_ar,_si,_dc,_lj,_pr,_dc,
- /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
- _fz,_nu,_nu,_nu,_nu,_nu,_nu,_nu,_nu,_nu,_dc,_dc,_dc,_dc,_dc,_dc,
- /* _ A B C D E F G H I J K L M N O */
- _dc,_dc,_dc,_dc,_dc,_fl,_fa,_fl,_sh,_dc,_dc,_dc,_ld,_dc,_ne,_dc,
- /* P Q R S T U V W X Y Z [ ] ^ _ */
- _dc,_dc,_dc,_dc,_dc,_dc,_dc,_dc,_he,_dc,_dc,_dc,_dc,_dc,_dc,_dc,
- /* ` a b c d e f g h i j k l m n o */
- _dc,_dc,_dc,_ch,_de,_fl,_fl,_fl,_sh,_de,_dc,_dc,_lo,_dc,_ns,_oc,
- /* p q r s t u v w x y z { | } ~ DEL */
- _pt,_dc,_dc,_st,_dc,_un,_dc,_dc,_he,_dc,_dc,_dc,_dc,_dc,_dc,_dc,
- };
- /*---------------------------------------------------------------------*
- Name __vprinter - sends formatted output
- Usage int pascal __vprinter (putnF *putter,
- void *outP,
- const char *formP,
- void _ss *argP)
- Prototype in _printf.h
- Description The list of arguments *argP is combined with literal text in
- the format string *formP according to format specifications
- inside the format string.
- The supplied procedure *putter is used to generate the output.
- It is required to take the string S, which has been
- constructed by __vprinter, and copy it to the destination
- outP. The destination may be a string, a FILE, or whatever
- other class of construct the caller requires. It is possible
- for several calls to be made to *putter since the buffer S
- is of limited size.
- *putter is required to preserve SI, DI.
- The only purpose of the outP argument is to be passed through
- to putter.
- The object at *argP is a record of unknown structure, which
- structure is interpreted with the aid of the format string.
- Each field of the structure may be an integer, long, double,
- or string (char *). Chars may appear but occupy integer-sized
- cells. Floats, character arrays, and structures may not
- appear.
- Return value The result of the function is a count of the characters sent to
- *outP.
- There is no error indication. When an incorrect conversion
- spec is encountered __vprinter copies the format as a literal
- (since it is assumed that alignment with the argument list has
- been lost), beginning with the '%' which introduced the bad
- format.
- If the destination outP is of limited size, for example a
- string or a full disk, __vprinter does not know. Overflowing
- the destination causes undefined results. In some cases
- *putter is able to handle overflows safely, but that is not
- the concern of __vprinter.
- The syntax of the format string is:
- format ::= ([literal] ['%' conversion ])* ;
- conversion ::= '%' | [flag]* [width] ['.' precision]
- ['l'] type ;
- flag ::= '-' | '+' | ' ' | '#' | '0' ;
- width ::= '*' | number ;
- precision ::= '.' ('*' | number) ;
- type ::= 'd'|'i'|'o'|'u'|'x'|'n'|'X'|'f'|'e'|'E'|
- 'g'|'G'|'c'|'s'|'p'|'N'|'F'
- *---------------------------------------------------------------------*/
- #ifdef I49_PRINTF
- int pascal near __I49vprinter (const char *formP, void _ss *argP)
- #else
- int pascal near __vprinter (putnF near *putter,
- void *outP,
- const char *formP,
- void _ss *argP)
- #endif
- {
- #define Ssize 40
- typedef
- enum
- {
- flagStage, fillzStage, wideStage, dotStage, precStage,
- ellStage, typeStage,
- } syntaxStages;
- typedef
- enum
- {
- altFormatBit = 1, /* the '#' flag */
- leftJustBit = 2, /* the '-' flag */
- notZeroBit = 4, /* 0 (octal) or 0x (hex) prefix */
- fillZerosBit = 8, /* zero fill width */
- isLongBit = 16, /* long-type argument */
- farPtrBit = 32, /* far pointers */
- alt0xBit = 64, /* '#' confirmed for %x format */
- floatBit = 128, /* float arg 4 bytes not 8! */
- LongDoubleBit= 256 /* signal a long double argument*/
- } flagBits;
- flagBits flagSet;
- #ifndef I49_PRINTF
- /* do not buffer any data */
- unsigned aP;
- #endif
- char fc; /* format char, from fmt string */
- char isSigned; /* chooses signed/unsigned ints */
- int width;
- int precision;
- char plusSign;
- int leadZ;
- unsigned abandonP; /* posn of bad syntax in fmt str*/
- char tempStr [__CVTMAX__]; /* longest _realcvt or longtoa string*/
- unsigned totalSent = 0; /* characters sent to putter */
- #ifndef I49_PRINTF
- /* do not buffer any data */
- unsigned Scount = Ssize; /* free space remaining in S */
- char S [Ssize]; /* temp working result buffer */
- #endif
- int eof_error = 0; /* flag, TRUE is EOF error */
- #if 0 /* the remaining variables are held entirely in registers */
- char hexCase; /* upper/lower Hex alphabet */
- long tempL;
- syntaxStages stage; -- CH
- char c;
- char *cP;
- int *iP;
- #endif
- SaveSI
- SaveDI
- /*
- General outline of the method:
- First the string is scanned, and conversion specifications detected.
- The preliminary fields of a conversion (flags, width, precision, long)
- are detected and noted.
- The argument is fetched and converted, under the optional guidance of
- the values of the preliminary fields. With the sole exception of the
- 's' conversion, the converted strings are first placed in the tempStr
- buffer.
- The contents of the tempStr (or the argument string for 's') are copied
- to the output, following the guidance of the preliminary fields in
- matters such as zero fill, field width, and justification.
- */
- I jmp short func_start /* Skip over inline nested PROCs */
- /***************************************************************************
- local, nested functions are placed here
- ES *must* be defined in all models.
- ***************************************************************************/
- #define RETN db 0xC3 /* "RETN" is used to force a near ret */
- /* Get length of string pointed to by ES:DI, return result in CX. */
- I vpr_strlen LABEL NEAR /* scan string ES: [DI] up to */
- I push di
- I mov cx, -1 /* count the string length. */
- I xor al, al
- I repne scasb
- I not cx /* (not CX) == (-1 -CX) */
- I dec cx /* scasb overshoots */
- I pop di
- I RETN
- /* call *putter to flush S */
- /* Put character to next position in S, check for S full */
- I vpr_PutToS LABEL NEAR
- #ifdef I49_PRINTF
- I push dx
- I push ax
- vpr_cput:
- I mov dx,SxSTS
- vpr_wait_empty:
- I in ax,dx /* wait for empty transmit buffer */
- I and ax,SER_THRE
- I je vpr_wait_empty
- I mov dx,SxTBUF
- I pop ax
- I out dx,ax
- I cmp al,0x0A /* if /n add /r */
- I je vpr_carrige_return
- I pop dx
- totalSent++;
- I RETN
- vpr_carrige_return:
- I push 0x0D
- I jmp vpr_cput
- #else
- I mov BY0 (ss:[di]), al
- I inc di
- I dec BY0 (Scount)
- I jnz exit_PutToS
- I vpr_CallPutter LABEL NEAR
- I push bx
- I push cx
- I push dx
- I push ES
- I lea ax, S
- I sub di, ax /* count chars in S */
- if( !putter (S, _DI, outP) )
- {
- eof_error = 1;
- }
- Scount = Ssize;
- totalSent += _DI;
- I lea di, S
- I pop ES
- I pop dx
- I pop cx
- I pop bx
- exit_PutToS :
- I RETN /* 'shared' RET for both PROCs */
- #endif
- /************************ end of embedded functions *******************/
- func_start:
- I push ES
- I cld
- #ifndef I49_PRINTF
- I lea di, S
- I mov aP, di
- #endif
- /*
- This paragraph is arranged to give in-line flow to the most frequent
- case, literal transcription from *formP to *outP.
- */
- vpr_NEXTap:
- #ifndef I49_PRINTF
- I mov di, aP
- #endif
- vpr_NEXT: /* loop to here when DI still valid */
- I LES_ si, formP
- for (;;) /* resume here from this literal/space */
- {
- vpr_nextCh:
- I lods BY0 (ES_ [si]) /* if (pattern[x] == '') */
- I or al, al /* goto exit */
- I jz vpr_respondJmp
- I cmp al, '%' /* '%' char begins a conversion */
- I je vpr_CONV
- vpr_literal: /* but "%%" is just a literal '%'. */
- #ifdef I49_PRINTF
- I call vpr_PutToS
- I jmp vpr_nextCh /* continue; */
- #else
- I mov ss:[di], al
- I inc di
- I dec BY0 (Scount) /* if (--Scount) */
- I jg vpr_nextCh /* continue; */
- I call vpr_CallPutter /* Compact way(smaller) */
- #endif
- }
- vpr_respondJmp:
- I jmp vpr_respond
- /* If arrived here then a conversion specification has been encountered. */
- vpr_CONV:
- I mov W0 (abandonP), si /* abandon will print from here */
- I lods BY0 (ES_ [si]) /* AL <- char at ES:SI */
- I cmp al, '%' /* %% really means % */
- I je vpr_literal
- #ifndef I49_PRINTF
- I mov W0 (aP), di /* keep result pointer safe */
- #endif
- I xor cx, cx /* CH is flagStage */
- I mov W0 (leadZ), cx /* leadZ <- 0 */
- #if LDATA
- I mov W0 (flagSet), farPtrBit /* flagSet <- pointers are FAR*/
- #else
- I mov W0 (flagSet), cx /* flagSet <- 0 */
- #endif
- I mov BY0 (plusSign), cl /* plusSign <- 0 */
- I mov W0 (width), -1 /* width <- default */
- I mov W0 (precision), -1 /* precision <- default */
- I jmp short vpr_doSwitch
- /*==================================*/
- /* loop to here when scanning flags */
- /*==================================*/
- vpr_nextSwitch:
- I lods BY0 (ES_ [si]) /* AL <- char at ES:SI */
- /**************************************************************************
- * Main character classification switch *
- **************************************************************************/
- vpr_doSwitch:
- I xor ah, ah /* Remove any high order trash */
- I mov dx, ax /* Duplicate original char in DL*/
- I mov bx, ax /* Duplicate original char in BL*/
- I sub bl, ' ' /* Scale char in BL to 0-95 */
- I cmp bl, 128 - ' ' /* Weed out don't cares */
- I jae vpr_jmpAbandon
- I push ES /* preserve ES */
- I push seg printCtype
- I pop ES
- I mov bl, BY0 (ES_ printCtype [bx]) /* BL <- char type of the char*/
- I pop ES
- switch (_BX) /* =-=> clobbers AX, BX <=-= */
- {
- vpr_jmpAbandon: /* Extend local jump range */
- I jmp vpr_abandon
- case (_af): /* when '#' was seen */
- I cmp ch, flagStage
- I ja vpr_jmpAbandon
- I or W0 (flagSet), altFormatBit
- I jmp vpr_nextSwitch
- case (_lj): /* when '-' was seen */
- I cmp ch, flagStage
- I ja vpr_jmpAbandon
- I or W0 (flagSet), leftJustBit
- I jmp vpr_nextSwitch
- case (_si): /* when ' ' or '+' was seen */
- I cmp ch, flagStage
- I ja vpr_jmpAbandon
- I cmp BY0 (plusSign), 2Bh /* '+' */
- I je gtvp_nxt_swit /* ' ' ignored if '+' already */
- I mov plusSign, dl
- gtvp_nxt_swit:
- I jmp vpr_nextSwitch
- case (_ne): /* near pointer */
- I and W0 (flagSet), NOT farPtrBit
- I jmp short ell_stagetail
- case (_fa): /* far pointer */
- I or W0 (flagSet), farPtrBit
- ell_stagetail:
- I mov ch, ellStage
- I jmp vpr_nextSwitch
- case (_fz): /* leading width '0' is a flag */
- I cmp ch, flagStage
- I ja case_nu /* else it is just a digit */
- I test W0 (flagSet), leftJustBit
- I jnz short vpr_nextSwitchJmp
- I or W0 (flagSet), fillZerosBit
- I mov ch, fillzStage /* but it must be part of width */
- I jmp vpr_nextSwitch
- vpr_abandonJmp: /* Extend local jump range */
- I jmp vpr_abandon
- case (_ar): /* when '*' was seen it causes */
- I mov di, argP
- I mov ax, ss:[di] /* the next argument to be */
- I add W0 (argP), 2 /* taken, depending on */
- I cmp ch, wideStage /* the stage, as the */
- I jnb vpr_argPrec /* width, or... */
- I or ax,ax /* is the width negative? */
- I jns vpr_pos
- I neg ax
- I or W0 (flagSet), leftJustBit
- vpr_pos:
- I mov width, ax
- I mov ch, wideStage + 1
- vpr_nextSwitchJmp:
- I jmp vpr_nextSwitch
- vpr_argPrec:
- I cmp ch, precStage
- I jne vpr_abandonJmp
- I mov precision, ax /* the precision. */
- I inc ch
- I jmp vpr_nextSwitch
- case (_pr): /* when '.' is seen, precision */
- I cmp ch, precStage
- I jnb vpr_abandonJmp
- I mov ch, precStage /* should follow */
- I inc W0 (precision) /* if no digits, ANSI says zero */
- I jmp vpr_nextSwitch
- /*
- When a numeral is seen, it may be either part of a width, or
- part of the precision, depending on the stage.
- */
- case (_nu): /* when 0..9 seen */
- case_nu:
- I xchg ax, dx /* move char back into AL */
- I sub al, '0' /* turn '0'-'9' to 0-9 */
- I cbw /* make it a word */
- I cmp ch, wideStage /* is it part of a width spec? */
- I ja vpr_precNumeral /* no, see if it's a precision */
- I mov ch, wideStage
- I xchg ax, width
- I or ax, ax /* first width digit ? */
- I jl vpr_nextSwitchJmp /* default width was -1 */
- I shl ax, 1 /* *2 */
- I mov dx, ax
- I shl ax, 1 /* *4 */
- I shl ax, 1 /* *8 */
- I add ax, dx /* (*2 + *8) = *10 */
- I add width, ax /* width = (width * 10 + num) */
- I jmp vpr_nextSwitch
- vpr_precNumeral:
- I cmp ch, precStage /* is it part of precision spec */
- I jne vpr_abandonJmp /* no, it's just a literal */
- // At this point we know that the precision specifier '.' has been seen,
- // so we know that the precision is zero (set at '.') or greater.
- I xchg ax, precision /* we only need to scale the */
- I or ax, ax /* precision if it's non zero */
- I jz vpr_nextSwitchJmp
- I shl ax, 1 /* *2 */
- I mov dx, ax
- I shl ax, 1 /* *4 */
- I shl ax, 1 /* *8 */
- I add ax, dx /* (*2 + *8) = *10 */
- I add precision, ax /* prec = (prec * 10 + numeral) */
- I jmp vpr_nextSwitch
- case (_lo): /* 'l' was seen (long) */
- I or W0 (flagSet), isLongBit
- I jmp ell_stagetail
- case (_ld): /* 'L' was seen (long double) */
- I or W0 (flagSet), LongDoubleBit
- case (_sh): /* 'h' or 'H' was seen (short) */
- I and W0 (flagSet), not isLongBit
- I jmp ell_stagetail
- /*--------------------------------------------------------------------------
- The previous cases covered all the possible flags. Now the following
- cases deal with the different argument types.
- Remember DL contains a copy of the original character.
- --------------------------------------------------------------------------*/
- /*==========================================================*/
- /* The first group of cases is for the integer conversions. */
- /*==========================================================*/
- case (_oc): /* octal */
- I mov bh, 8 /* BH <- Base 8 */
- I jmp short vpr_NoSign
- case (_un): /* unsigned */
- I mov bh, 10 /* BH <- Base 10 */
- I jmp short vpr_NoSign
- case (_he): /* hex */
- I mov bh, 10h /* BH <- Base 16 */
- I mov bl, 'A' - 'X'
- I add bl, dl /* Adjust for aAbBcC etc later */
- vpr_NoSign:
- I mov BY0 (plusSign), 0 /* It's an unsigned operand */
- /* jmp short vpr_UINT */
- #ifndef I49_PRINTF
- vpr_UINT:
- #endif
- I mov fc, dl /* 'fc' <- orig fmt char */
- I xor dx, dx /* zero extend by default */
- I mov BY0 (isSigned), dl
- I mov di, argP
- I mov ax, ss:[di] /* AX <- word arg at SS:DI */
- I jmp short vpr_toAscii
- case (_de): /* decimal */
- I mov bh, 10 /* BH <- Base 10 */
- #ifndef I49_PRINTF
- vpr_INT:
- #endif
- I mov BY0 (isSigned), 1
- I mov fc, dl /* 'fc' <- orig fmt char */
- I mov di, argP /* SS:DI -> argument word[0] */
- I mov ax, ss:[di] /* AX <- word arg at SS:DI */
- I cwd /* sign-extend by default */
- vpr_toAscii:
- I inc di /* SS:DI -> next arg word */
- I inc di
- I mov formP, si /* remember progress through format */
- I test W0 (flagSet),isLongBit /* short or long int ? */
- I je vpr_shortInt /* If the operand is a long */
- I mov dx, ss:[di] /* DX:AX holds long argument */
- I inc di /* SS:DI -> next arg word */
- I inc di
- vpr_shortInt:
- I mov argP, di /* Save arg list pointer */
- I lea di, tempStr [1] /* (SS) DI <- &tempStr[1] */
- I or ax, ax /* Is the value zero? */
- I jnz vpr_flag_nz /* No, */
- I or dx, dx /* Is the value zero? */
- I jnz vpr_flag_nz /* No, */
- /*-----------------------------------------------------------------------
- Check for the special ANSI case of a zero value with an explicit
- precision of zero.
- ------------------------------------------------------------------------*/
- I cmp W0 (precision), 0 /* Is it the special case? */
- I jne vpr_flag_zr /* No, continue */
- I mov byte ptr SS:[di], 0 /* Otherwise, make empty string */
- I mov ax, di /* longtoa returns pointer */
- I jmp vpr_converted
- /*-------------------------------------------------------------------------
- "Normal" integer output cases wind up down here somewhere.
- -------------------------------------------------------------------------*/
- vpr_flag_nz:
- I or W0 (flagSet), notZeroBit /* flag non-zeroness */
- vpr_flag_zr:
- #ifndef I49_PRINTF
- vpr_doLtoA:
- #endif
- I push dx /* Push long value (AX:DX) */
- I push ax
- #if LDATA
- I push SS
- #endif
- I push di /* ie. &tempStr[1] */
- I mov al, bh /* AL <- numeric base/radix */
- I cbw /* Convert it to a word */
- I push ax /* Push the radix */
- I mov al, isSigned /* Push the isSigned flag, */
- I push ax /* AH should still be 0 */
- I push bx /* BL == , hexCase) */
- /*** __longtoa(number, string, radix, signflag, hexcase) ***/
- I call __longtoa /* returns pointer to string */
- vpr_converted:
- I push SS
- I pop ES /* ES_ [di] = cP == 1+tempStr */
- /* ES is needed in all models */
- I mov dx, precision /* Has precsion been set? */
- I or dx, dx
- I jge vpr_countActualJmp /* Yes. */
- I jmp vpr_testFillZeros /* No. */
- vpr_countActualJmp:
- I jmp vpr_countActual
- /*
- The 'p' conversion takes either a near or a far pointer and puts
- it out in the usual Intel xxxx:xxxx hex style.
- */
- case (_pt): /* pointer */
- I mov fc, dl /* remember the type character. */
- I mov formP, si /* remember progress through format */
- I lea di, tempStr
- I mov bx, argP
- I push word ptr ss:[bx] /* fetch the argument.w0 */
- I inc bx
- I inc bx
- I mov argP, bx
- I test W0 (flagSet), farPtrBit
- I jz vpr_ptrLSW
- I mov dx, ss:[bx] /* fetch the argument.w1 */
- I inc bx
- I inc bx
- I mov argP, bx
- I push SS
- I pop ES
- I call Hex4
- /* add di, 4 Hex4 does this */
- I mov al, ':'
- I stosb
- vpr_ptrLSW:
- I push SS
- I pop ES
- I pop dx
- I call Hex4
- /* add di, 4 Hex4 does this */
- I mov BY0 (ss:[di]), 0
- I mov BY0 (isSigned), 0
- I and W0 (flagSet), NOT notZeroBit
- I lea cx, tempStr
- I sub di, cx
- I xchg cx, di /* CX = len, DI = tempStr */
- I mov dx, precision
- I cmp dx, cx
- I jg vpr_ptrEnd
- I mov dx, cx
- vpr_ptrEnd:
- I jmp vpr_testFillZeros
- /*
- The 'c' conversion takes a character as parameter. Note, however,
- that the character occupies an (int) sized cell in the argument
- list.
- */
- case (_ch): /* char */
- I mov formP, si /* remember progress through format */
- I mov fc, dl /* remember the type character */
- I mov di, argP
- I mov ax, ss:[di]
- I add W0 (argP), 2
- I push SS
- I pop ES
- I lea di, tempStr [1]
- I xor ah, ah /* terminate the temporary string. */
- I mov ss:[di], ax
- I mov cx, 1
- I jmp vpr_CopyLen
- /*
- The 's' conversion takes a string (char *) as argument and copies
- the string to the output buffer.
- */
- case (_st): /* string */
- I mov formP, si /* remember progress through format */
- I mov fc, dl /* remember the type character */
- I mov di, argP
- I test W0 (flagSet), farPtrBit
- I jnz vpr_farString
- #ifdef __HUGE__
- I jmp vpr_abandonJmp /* DS can't be assumed in HUGE model */
- #else
- I mov di, ss:[di] /* [di] = (DS:char *) *(argP++) */
- I add W0 (argP), 2
- I push DS
- I pop ES
- I or di, di
- I jmp short vpr_countString
- #endif
- vpr_farString:
- I les di, ss:[di] /* ES: [di] = (char far *) *(argP++) */
- I add W0 (argP), 4
- I mov ax, es
- I or ax, di
- vpr_countString:
- I jnz NotaNullPtr
- #ifdef I49_PRINTF
- I push seg printCtype
- #else
- I push DS
- #endif
- I pop ES
- I lea di, NullString
- NotaNullPtr:
- I call vpr_strlen /* CX = strlen (ES: [di]) */
- I cmp cx, precision
- I jna vpr_CopyLenJmp
- I mov cx, precision /* precision may truncate string. */
- vpr_CopyLenJmp:
- I jmp vpr_CopyLen
- /* All real-number conversions are done by __realcvt. */
- case (_fl): /* float */
- I mov formP, si /* remember progress through format */
- I mov fc, dl /* remember the type character */
- I mov di, argP
- I mov cx, precision
- I or cx, cx /* is precision defaulted ? */
- I jnl vpr_cvtReal
- I mov cx, 6
- vpr_cvtReal:
- #if LDATA
- I push SS
- #endif
- I push di /* (valueP */
- I push cx /* , ndec */
- #if LDATA
- I push SS
- #endif
- I lea bx, tempStr [1]
- I push bx /* , cP */
- I push dx /* , formCh */
- I mov ax, altFormatBit
- I and ax, W0 (flagSet)
- I push ax /* , altFormat) */
- /*
- Determine the argument type double/long double.
- Save the size of the argument type.
- */
- I mov ax, W0 (flagSet)
- #ifndef I49_PRINTF
- try_long :
- #endif
- I test ax, LongDoubleBit
- I jz its_plain_double
- I mov ax, F_10byteFloat
- I add W0 (argP), 10 /* argP += sizeof(long double) */
- I jmp short push_argtype
- its_plain_double :
- I add W0 (argP), 8 /* argP += sizeof(double) */
- I mov ax, F_8byteFloat
- push_argtype :
- I push ax
- I call __realcvt
- I push SS
- I pop ES
- I lea di, tempStr [1] /* ES_ [di] = cP == 1+tempStr */
- vpr_testFillZeros:
- I test W0 (flagSet), fillZerosBit
- I jz vpr_NUMERIC
- I mov dx, width
- I or dx, dx
- I jng vpr_NUMERIC
- vpr_countActual: /* Get strlen of result string */
- I call vpr_strlen /* CX <- strlen (ES:[DI]) */
- I cmp BY0 (ES: [di]), '-'
- I jne vpr_noSignAdjust
- I dec cx /* Length too long because '-' */
- vpr_noSignAdjust:
- I sub dx, cx /* DX <- leading 0 count(if any)*/
- I jng vpr_NUMERIC /* leadZ defaulted to 0 before */
- I mov leadZ, dx /* leadZ <- (width or prec-len) */
- /*
- If arrived here, then tempStr contains the result of a numeric
- conversion. It may be necessary the prefix the number with
- a mandatory sign or space.
- */
- vpr_NUMERIC: /* ES must be well defined ! */
- I cmp BY0 (ES: [di]), '-' /* If sign there then adjust */
- I je vpr_AdjustLeadZ
- I mov al, plusSign /* Do we need a sign? */
- I or al, al
- I jz vpr_COPY /* No, not required */
- I dec di /* Back up 1 in the string */
- I mov ES: [di], al /* and insert the sign */
- vpr_AdjustLeadZ:
- I cmp W0 (leadZ), 0 /* If leadZ > 0 then leadZ-- */
- I jle vpr_COPY
- I mov cx, precision
- I or cx, cx
- I jge vpr_COPY /* Don't adjust if precision set*/
- I dec W0 (leadZ)
- /*
- If arrived here then ES: [di] = cP points to the converted string,
- which must now be padded, aligned, and copied to the output.
- */
- vpr_COPY:
- I call vpr_strlen /* CX = strlen (ES: [di]) */
- vpr_CopyLen: /* comes from %c or %s section */
- I mov si, di /* cP <- ES: [si] */
- #ifndef I49_PRINTF
- I mov di, aP
- #endif
- I mov bx, width /* BX <- width */
- I mov ax, notZeroBit + altFormatBit
- I and ax, W0 (flagSet)
- I cmp ax, notZeroBit + altFormatBit
- I jne goto_doLead
- I mov ah, fc /* AH <- original format char */
- I cmp ah, 'o' /* Is it alternate octal form? */
- I jne vpr_maybeAltHex /* No, try the next one */
- I cmp W0 (leadZ), 0 /* Yes, alternate mode w/octal */
- I jg goto_doLead /* requires at least */
- I mov W0 (leadZ), 1 /* one leading zero. */
- goto_doLead:
- I jmp vpr_doLead;
- vpr_maybeAltHex:
- I cmp ah, 'x' /* Is it alternate hex form? */
- I je vpr_isAltHex /* Yes, send */
- I cmp ah, 'X' /* "0x" or "0X" prefix. */
- I jne vpr_doLead /* No, insert leading 0's */
- vpr_isAltHex:
- I or W0 (flagSet), alt0xBit /* flagSet |= alt0xBit; */
- I dec bx /* width -= 2; */
- I dec bx
- I sub W0 (leadZ), 2 /* leadZ -= 2; */
- I jnl vpr_doLead /* Still leading 0's? */
- I mov W0 (leadZ), 0 /* No more leading 0's */
- vpr_doLead:
- I add cx, leadZ /* CX <- len + leadZ */
- /* Is result to be left justified? */
- I test W0 (flagSet), leftJustBit
- I jnz vpr_check0x
- I jmp short vpr_nextJust /* (! leftJust) == leftFill */
- vpr_justLoop:
- I mov al, ' '
- I call vpr_PutToS
- I dec bx
- vpr_nextJust:
- I cmp bx, cx
- I jg vpr_justLoop
- vpr_check0x:
- I test W0 (flagSet), alt0xBit /* Need alternate hex form? */
- I jz vpr_checkLeadZ /* No, */
- I mov al, '0' /* Yes, Send "0x" or "0X" */
- I call vpr_PutToS
- I mov al, fc /* original 'fc' is 'x' or 'X' */
- I call vpr_PutToS
- vpr_checkLeadZ: /* leading zero fill required ? */
- I mov dx, leadZ
- I or dx, dx
- I jng vpr_actualCopy
- I sub cx, dx /* len -= leadZ */
- I sub bx, dx /* width -= leadZ */
- I mov al, ES: [si] /* any leading sign must be */
- I cmp al, '-' /* copied before the */
- I je vpr_leadSign /* leading zeros. */
- I cmp al, ' '
- I je vpr_leadSign
- I cmp al, '+'
- I jne vpr_signedLead
- vpr_leadSign:
- I lods BY0 (ES: [si]) /* Get the 'sign' */
- I call vpr_PutToS /* Send the 'sign' */
- I dec cx
- I dec bx /* anticipates actualCopy */
- vpr_signedLead:
- I xchg cx, dx /* leading zeros follow sign */
- I jcxz vpr_leadDone
- vpr_leadZero:
- I mov al, '0'
- I call vpr_PutToS
- I loop vpr_leadZero
- vpr_leadDone:
- I xchg cx, dx
- /* Now we copy the actual converted string from tempStr to output. */
- vpr_actualCopy:
- I jcxz vpr_copied /* Degenerate case? */
- I sub bx, cx /* No, width -= len; */
- vpr_copyLoop: /* this is the high-point of __vprinter ! */
- I lods BY0 (ES: [si]) /* ES:SI -> tempStr */
- #ifdef I49_PRINTF
- I call vpr_PutToS
- #else
- I mov BY0 (SS: [di]), al /* SS:DI -> S[xxx] */
- I inc di
- I dec BY0 (Scount)
- I jg vpr_loopTest
- I call vpr_CallPutter
- vpr_loopTest:
- #endif
- I loop vpr_copyLoop
- vpr_copied:
- /* Is the field to be right-filled ? */
- I or bx, bx /* any remaining width ? */
- I jng vpr_done
- I mov cx, bx
- vpr_rightLoop:
- I mov al, ' '
- I call vpr_PutToS
- I loop vpr_rightLoop
- /* If arrive here, the conversion has been done and copied to output. */
- vpr_done:
- I jmp vpr_NEXT
- case (_ns) : /* number sent */
- I mov formP, si /* remember progress through format */
- I mov di, argP
- I test W0 (flagSet), farPtrBit
- I jnz vpr_farCount
- #ifdef __HUGE__
- I jmp vpr_abandonJmp /* DS can't be assumed in HUGE model */
- #else
- I mov di, ss:[di] /* [di]=(DS:char *) *((int _ss *)argP++)*/
- I add W0 (argP), 2
- I push DS
- I pop ES
- I jmp short vpr_makeCount
- #endif
- vpr_farCount:
- I les di, ss:[di] /* ES:[di] = (char far *) *((long _ss *)argP++) */
- I add W0 (argP), 4
- vpr_makeCount:
- #ifdef I49_PRINTF
- I mov ax, totalSent
- #else
- I mov ax, Ssize
- I sub al, Scount
- I add ax, totalSent
- #endif
- I mov ES: [di], ax
- I test W0(flagSet),isLongBit
- I jz vpr_shortN
- I inc di
- I inc di
- I mov word ptr ES: [di], 0
- vpr_shortN:
- I jmp vpr_NEXTap
- case (_zz): /* characters, unexpected end of format string */
- case (_dc): /* ordinary "don't care" chars in the wrong position */
- case (_pc): /* '%' percent characters in the wrong position */
- ; /* goto vpr_abandon */
- } /* end switch */
- /*
- If the format goes badly wrong, then copy it literally to the output
- and abandon the conversion.
- */
- vpr_abandon:
- I mov si, abandonP
- #if LDATA
- I mov ES, W1 (formP)
- #endif
- #ifndef I49_PRINTF
- I mov di, aP
- #endif
- I mov al, '%'
- vpr_abandLoop:
- I call vpr_PutToS
- I lods BY0 (ES_ [si])
- I or al, al
- I jnz vpr_abandLoop
- /* If arrived here then the function has finished (either correctly or not). */
- vpr_respond:
- #ifndef I49_PRINTF
- I cmp BY0 (Scount), Ssize /* anything waiting to be written ? */
- I jnl vpr_end
- I call vpr_CallPutter
- vpr_end:
- #endif
- I pop ES
- if( eof_error ) return( EOF );
- else return( totalSent );
- }