home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-06-07 | 30.2 KB | 1,143 lines |
- /*-----------------------------------------------------------------------*
- * filename - vprinter.cas
- *
- * function(s)
- * Hex4 - converts int to 4 hex digits
- * __vprinter - sends formatted output
- *-----------------------------------------------------------------------*/
-
- /*[]------------------------------------------------------------[]*/
- /*| |*/
- /*| Turbo C Run Time Library - Version 3.0 |*/
- /*| |*/
- /*| |*/
- /*| Copyright (c) 1987,1988,1990 by Borland International |*/
- /*| All Rights Reserved. |*/
- /*| |*/
- /*[]------------------------------------------------------------[]*/
-
- #pragma inline
- #include <stdio.h>
- #include <asmrules.h>
- #include <_printf.h>
-
- #define I asm
-
- #define BREAKPOINT asm int 3
-
- static char NullString[] = "(null)";
-
- /*-----------------------------------------------------------------------*
-
- 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. */
-
- static unsigned char printCtype [96] =
- {
- /* 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'
-
- *---------------------------------------------------------------------*/
- int pascal near __vprinter (putnF near *putter,
- void *outP,
- const char *formP,
- void _ss *argP)
- {
-
- #define Ssize 80
-
- 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;
-
- unsigned aP;
- 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 */
- unsigned Scount = Ssize; /* free space remaining in S */
- char S [Ssize]; /* temp working result buffer */
- 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 \0 */
- 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
- I mov BY0 (ss:[di]), al
- I inc di
- I dec BY0 (Scount)
- I jle 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 */
-
- /************************ end of embedded functions *******************/
-
- func_start:
-
- I push ES
- I cld
-
- I lea di, S
- I mov aP, di
-
- /*
- This paragraph is arranged to give in-line flow to the most frequent
- case, literal transcription from *formP to *outP.
- */
-
- vpr_NEXTap:
- I mov di, aP
-
- 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] == '\0') */
- 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 '%'. */
- 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) */
- }
-
- 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
-
- I mov W0 (aP), di /* keep result pointer safe */
-
- 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 mov bl, BY0 (printCtype [bx]) /* BL <- char type of the char*/
-
- 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 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 */
-
- I xchg ax, precision
- I or ax, ax /* first precision digit ? */
- I jl vpr_nextSwitchJmp /* default precision 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 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_UINT
-
-
- 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 */
-
-
- vpr_UINT:
- 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 */
- vpr_INT:
- 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_doLtoA /* No, continue */
-
- /*
- Yes...this is the ANSI special case where precision is zero and the value
- is zero. This will result in NO conversion characters being produced.
- The way we do this is:
- 1. Deal with degenerate case of 0 field width. ex. "%00.0x"
- 2. Determine if leading zeros are to be forced anyway. For example
- this could occur with printf("%04.0x", 0); In this case we have
- a zero result with zero precision but the '0' flag char will
- cause us to fill the field with 0s anyway.
- 3. Fill for 'width' characters with either '0' or ' ' depending on
- if leading zeros were specified.
- 4. Terminate this conversion field.
- */
- I mov di, aP /* SS:DI -> somewhere in 'S' */
- I mov cx, width /* If he asked for nothing, */
- I jcxz ANSI_special_end /* then give him nothing. */
- I cmp cx, -1 /* Was width defaulted? */
- I je ANSI_special_end /* Assume width = 0 */
-
- I mov ax, W0 (flagSet) /* fillChar = */
- I and ax, fillZerosBit /* (flagSet & fillZerosBit) ? */
- I jz blankfill /* */
- I mov dl, '0' /* fillChar = '0'; */
- I jmp short fillAnother
-
- blankfill:
- I mov dl, ' ' /* fillChar = ' '; */
-
- /* for (i=0; i<width; i++) PutToS( fillChar ); */
-
- fillAnother:
- I mov al, dl /* AL <- fillChar */
- I call vpr_PutToS /* This clobbers AX */
- I loop fillAnother /* CX is safe though */
-
- ANSI_special_end:
- I jmp vpr_NEXT /* That's the end of this field */
-
- /*-------------------------------------------------------------------------
- "Normal" integer output cases wind up down here somewhere.
- -------------------------------------------------------------------------*/
-
- vpr_flag_nz:
- I or W0 (flagSet), notZeroBit /* flag non-zeroness */
-
- vpr_doLtoA:
- 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 */
-
- I push SS
- I pop ES /* ES_ [di] = cP == 1+tempStr */
- /* ES is needed in all models */
-
- I mov dx, precision /* Is precision > 0 ? */
- I or dx, dx
- I jg 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 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
- I push DS
- I pop ES
- I mov di,offset 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)
-
- try_long :
- 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]), '-' /* Is the number negative? */
- I jne calc
- I dec cx /* decrement the string length */
- calc:
- 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 mov al, plusSign /* Do we need a sign? */
- I or al, al
- I jz vpr_COPY /* No, not required */
- I cmp BY0 (ES: [di]), '-'
- I je vpr_COPY /* No, its there already */
-
- I sub W0 (leadZ), 1 /* Yes, leading 0's are 1 less */
- I adc W0 (leadZ), 0 /* don't allow negative leadZ */
-
- I dec di /* Back up 1 in the string */
- I mov ES: [di], al /* and insert the sign */
-
- /*
- 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] */
- I mov di, aP
-
- 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 */
- 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:
- 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:
- I mov ax, Ssize
- I sub al, Scount
- I add ax, totalSent
- 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): /* \0 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
- I mov di, aP
- 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:
- I cmp BY0 (Scount), Ssize /* anything waiting to be written ? */
- I jnl vpr_end
- I call vpr_CallPutter
- vpr_end:
- I pop ES
-
- if( eof_error ) return( EOF );
- else return( totalSent );
- }
-