355 lines
7.2 KiB
C
355 lines
7.2 KiB
C
/*++
|
|
*
|
|
* WOW v1.0
|
|
*
|
|
* Copyright (c) 1991, Microsoft Corporation
|
|
*
|
|
* WSPRINTF.C
|
|
* Win16 wsprintf/wvsprintf code
|
|
*
|
|
* History:
|
|
*
|
|
* Created 28-May-1991 by Jeff Parsons (jeffpar)
|
|
* Copied from WIN31 and edited (as little as possible) for WOW16.
|
|
--*/
|
|
|
|
/*
|
|
*
|
|
* sprintf.c
|
|
*
|
|
* Implements Windows friendly versions of sprintf and vsprintf
|
|
*
|
|
* History:
|
|
* 2/15/89 craigc Initial
|
|
*/
|
|
|
|
#include "windows.h"
|
|
#include "winexp.h"
|
|
|
|
#define WSPRINTF_LIMIT 1024
|
|
|
|
extern int near pascal SP_PutNumber(LPSTR, long, int, int, int);
|
|
extern void near pascal SP_Reverse(LPSTR lp1, LPSTR lp2);
|
|
|
|
#define out(c) if (--cchLimit) *lpOut++=(c); else goto errorout
|
|
|
|
/*
|
|
* GetFmtValue
|
|
*
|
|
* reads a width or precision value from the format string
|
|
*/
|
|
|
|
LPCSTR near pascal SP_GetFmtValue(LPCSTR lpch,int FAR *lpw)
|
|
{
|
|
register int i=0;
|
|
|
|
while (*lpch>='0' && *lpch<='9')
|
|
{
|
|
i *= 10;
|
|
i += (WORD)(*lpch-'0');
|
|
lpch++;
|
|
}
|
|
|
|
*lpw=i;
|
|
|
|
/* return the address of the first non-digit character */
|
|
return lpch;
|
|
}
|
|
|
|
/*
|
|
* wvsprintf()
|
|
*
|
|
* Windows version of vsprintf(). Does not support floating point or
|
|
* pointer types, and all strings are assumed to be FAR. Supports only
|
|
* the left alignment flag.
|
|
*
|
|
* Takes pointers to an output buffer, where the string is built, a
|
|
* pointer to an input buffer, and a pointer to a list of parameters.
|
|
*
|
|
* The cdecl function wsprintf() calls this function.
|
|
*/
|
|
|
|
int API Iwvsprintf(LPSTR lpOut, LPCSTR lpFmt, LPSTR lpParms)
|
|
{
|
|
int left;
|
|
char prefix;
|
|
register int width;
|
|
register int prec;
|
|
char fillch;
|
|
int size;
|
|
int sign;
|
|
int radix;
|
|
int upper;
|
|
int cchLimit=WSPRINTF_LIMIT;
|
|
int cch;
|
|
LPSTR lpT;
|
|
union {
|
|
long l;
|
|
unsigned long ul;
|
|
char sz[sizeof(long)];
|
|
} val;
|
|
|
|
while (*lpFmt)
|
|
{
|
|
if (*lpFmt=='%')
|
|
{
|
|
|
|
/* read the flags. These can be in any order */
|
|
left=0;
|
|
prefix=0;
|
|
while (*++lpFmt)
|
|
{
|
|
if (*lpFmt=='-')
|
|
left++;
|
|
else if (*lpFmt=='#')
|
|
prefix++;
|
|
else
|
|
break;
|
|
}
|
|
|
|
/* find fill character */
|
|
if (*lpFmt=='0')
|
|
{
|
|
fillch='0';
|
|
lpFmt++;
|
|
}
|
|
else
|
|
fillch=' ';
|
|
|
|
/* read the width specification */
|
|
lpFmt=SP_GetFmtValue(lpFmt,&cch);
|
|
width=cch;
|
|
|
|
/* read the precision */
|
|
if (*lpFmt=='.')
|
|
{
|
|
lpFmt=SP_GetFmtValue(++lpFmt,&cch);
|
|
prec=cch;
|
|
}
|
|
else
|
|
prec=-1;
|
|
|
|
/* get the operand size */
|
|
if (*lpFmt=='l')
|
|
{
|
|
size=1;
|
|
lpFmt++;
|
|
}
|
|
else
|
|
{
|
|
size=0;
|
|
if (*lpFmt=='h')
|
|
lpFmt++;
|
|
}
|
|
|
|
upper=0;
|
|
sign=0;
|
|
radix=10;
|
|
switch (*lpFmt)
|
|
{
|
|
case 0:
|
|
goto errorout;
|
|
|
|
case 'i':
|
|
case 'd':
|
|
sign++;
|
|
|
|
case 'u':
|
|
/* turn off prefix if decimal */
|
|
prefix=0;
|
|
donumeric:
|
|
/* special cases to act like MSC v5.10 */
|
|
if (left || prec>=0)
|
|
fillch=' ';
|
|
|
|
if (size)
|
|
val.l=*((long far *)lpParms)++;
|
|
else
|
|
if (sign)
|
|
val.l=(long)*((short far *)lpParms)++;
|
|
else
|
|
val.ul=(unsigned long)*((unsigned far *)lpParms)++;
|
|
|
|
if (sign && val.l<0L)
|
|
val.l=-val.l;
|
|
else
|
|
sign=0;
|
|
|
|
lpT=lpOut;
|
|
|
|
/* blast the number backwards into the user buffer */
|
|
cch=SP_PutNumber(lpOut,val.l,cchLimit,radix,upper);
|
|
if (!(cchLimit-=cch))
|
|
goto errorout;
|
|
|
|
lpOut+=cch;
|
|
width-=cch;
|
|
prec-=cch;
|
|
if (prec>0)
|
|
width-=prec;
|
|
|
|
/* fill to the field precision */
|
|
while (prec-->0)
|
|
out('0');
|
|
|
|
if (width>0 && !left)
|
|
{
|
|
/* if we're filling with spaces, put sign first */
|
|
if (fillch!='0')
|
|
{
|
|
if (sign)
|
|
{
|
|
sign=0;
|
|
out('-');
|
|
width--;
|
|
}
|
|
|
|
if (prefix)
|
|
{
|
|
out(prefix);
|
|
out('0');
|
|
prefix=0;
|
|
}
|
|
}
|
|
|
|
if (sign)
|
|
width--;
|
|
|
|
/* fill to the field width */
|
|
while (width-->0)
|
|
out(fillch);
|
|
|
|
/* still have a sign? */
|
|
if (sign)
|
|
out('-');
|
|
|
|
if (prefix)
|
|
{
|
|
out(prefix);
|
|
out('0');
|
|
}
|
|
|
|
/* now reverse the string in place */
|
|
SP_Reverse(lpT,lpOut-1);
|
|
}
|
|
else
|
|
{
|
|
/* add the sign character */
|
|
if (sign)
|
|
{
|
|
out('-');
|
|
width--;
|
|
}
|
|
|
|
if (prefix)
|
|
{
|
|
out(prefix);
|
|
out('0');
|
|
}
|
|
|
|
/* reverse the string in place */
|
|
SP_Reverse(lpT,lpOut-1);
|
|
|
|
/* pad to the right of the string in case left aligned */
|
|
while (width-->0)
|
|
out(fillch);
|
|
}
|
|
break;
|
|
|
|
case 'X':
|
|
upper++;
|
|
case 'x':
|
|
radix=16;
|
|
if (prefix)
|
|
if (upper)
|
|
prefix='X';
|
|
else
|
|
prefix='x';
|
|
goto donumeric;
|
|
|
|
case 'c':
|
|
val.sz[0]=*lpParms;
|
|
val.sz[1]=0;
|
|
lpT=val.sz;
|
|
cch = 1; // Length is one character.
|
|
// Fix for Bug #1862 --01/10/91-- SANKAR --
|
|
/* stack aligned to larger size */
|
|
lpParms+=sizeof(int);
|
|
|
|
goto putstring;
|
|
|
|
case 's':
|
|
lpT=*((LPSTR FAR *)lpParms)++;
|
|
cch=lstrlen(lpT);
|
|
putstring:
|
|
if (prec>=0 && cch>prec)
|
|
cch=prec;
|
|
width -= cch;
|
|
if (left)
|
|
{
|
|
while (cch--)
|
|
out(*lpT++);
|
|
while (width-->0)
|
|
out(fillch);
|
|
}
|
|
else
|
|
{
|
|
while (width-->0)
|
|
out(fillch);
|
|
while (cch--)
|
|
out(*lpT++);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
normalch:
|
|
#ifdef FE_SB /* masas : 90-4-26 */
|
|
// If last char is a high ansi char, that may cause infinite loop
|
|
// In case of Taiwan version(PRC and Korea), this char is treated
|
|
// as DBCS lead byte. So we expect trail byte by default. But this
|
|
// is not correct.
|
|
|
|
// if( IsDBCSLeadByte(*lpFmt) ) This is original code
|
|
// out(*lpFmt++);
|
|
|
|
if( IsDBCSLeadByte(*lpFmt) ) {
|
|
if( *(lpFmt+1) == '\0' ) {
|
|
out('?');
|
|
lpFmt++;
|
|
continue;
|
|
}
|
|
else
|
|
out(*lpFmt++);
|
|
}
|
|
#endif
|
|
out(*lpFmt);
|
|
break;
|
|
|
|
} /* END OF SWITCH(*lpFmt) */
|
|
} /* END OF IF(%) */
|
|
else
|
|
goto normalch; /* character not a '%', just do it */
|
|
|
|
/* advance to next format string character */
|
|
lpFmt++;
|
|
} /* END OF OUTER WHILE LOOP */
|
|
|
|
errorout:
|
|
*lpOut=0;
|
|
|
|
return WSPRINTF_LIMIT-cchLimit;
|
|
}
|
|
|
|
|
|
/*
|
|
* wsprintf
|
|
*
|
|
* Windows version of sprintf
|
|
*
|
|
*/
|
|
|
|
int FAR cdecl wsprintf(LPSTR lpOut, LPCSTR lpFmt, LPSTR lpParms, ...)
|
|
{
|
|
return wvsprintf(lpOut,lpFmt,(LPSTR)&lpParms);
|
|
}
|