You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
453 lines
8.5 KiB
453 lines
8.5 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
sprintf.c
|
|
|
|
Abstract:
|
|
|
|
Implements Windows friendly versions of sprintf and vsprintf
|
|
|
|
Author:
|
|
|
|
|
|
|
|
Revision History:
|
|
|
|
2/15/89 craigc Initial
|
|
4/6/93 ROBWI For VxD
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#pragma code_seg("PAGE")
|
|
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
|
|
#ifndef CSC_RECORDMANAGER_WINNT
|
|
#include "basedef.h"
|
|
#include "vmm.h"
|
|
#pragma VxD_LOCKED_CODE_SEG
|
|
#endif //ifndef CSC_RECORDMANAGER_WINNT
|
|
|
|
#include "vxdwraps.h"
|
|
|
|
#define WSPRINTF_LIMIT 1024
|
|
#define DEBUG_BUFFER_SIZE 16376
|
|
|
|
extern int SP_PutNumber(char *, long, int, int, int);
|
|
extern void SP_Reverse(char * lp1, char * lp2);
|
|
|
|
DWORD DebugBufferLength = 0;
|
|
char * DebugBuffer;
|
|
|
|
|
|
#define out(c) if (--cchLimit) *lpOut++=(c); else goto errorout
|
|
#pragma intrinsic (memcmp, memcpy, memset, strcat, strcmp, strcpy, strlen)
|
|
|
|
/*
|
|
* GetFmtValue
|
|
*
|
|
* reads a width or precision value from the format string
|
|
*/
|
|
|
|
char * SP_GetFmtValue(char * lpch, int * lpw)
|
|
{
|
|
register int i=0;
|
|
|
|
while (*lpch>='0' && *lpch<='9')
|
|
{
|
|
i *= 10;
|
|
i += (int)(*lpch-'0');
|
|
lpch++;
|
|
}
|
|
|
|
*lpw=i;
|
|
|
|
/* return the address of the first non-digit character */
|
|
return lpch;
|
|
}
|
|
|
|
/*
|
|
* vsprintf()
|
|
*
|
|
* VxD version of vsprintf(). Does not support floating point or
|
|
* pointer types, and all strings are assumed to be NEAR. 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.
|
|
*
|
|
*/
|
|
|
|
int vxd_vsprintf(char * lpOut, char * lpFmt, CONST VOID * 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;
|
|
char * lpT;
|
|
union {
|
|
long l;
|
|
ULONG ul;
|
|
char sz[sizeof(long)];
|
|
} val;
|
|
int fWideChar;
|
|
|
|
while (*lpFmt)
|
|
{
|
|
if (*lpFmt=='%')
|
|
{
|
|
|
|
/* read the flags. These can be in any order */
|
|
left=0;
|
|
prefix=0;
|
|
fWideChar = 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 *)lpParms)++;
|
|
else
|
|
if (sign)
|
|
val.l=*((long *)lpParms)++;
|
|
else
|
|
val.ul=(ULONG)*((ULONG *)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] = *((char *)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 */
|
|
(BYTE *)lpParms += sizeof(DWORD);
|
|
|
|
goto putstring;
|
|
case 'w':
|
|
fWideChar = 1;
|
|
case 's':
|
|
lpT=*((char **)lpParms)++;
|
|
cch=((!fWideChar)?strlen(lpT):wstrlen((USHORT *)lpT));
|
|
putstring:
|
|
if (prec>=0 && cch>prec)
|
|
cch=prec;
|
|
width -= cch;
|
|
if (left)
|
|
{
|
|
while (cch--) {
|
|
if (*lpT == 0x0A || *lpT == 0x0D) {
|
|
out(0x0D);
|
|
out(0x0A);
|
|
}
|
|
else
|
|
out(*lpT++);
|
|
if (fWideChar)
|
|
{
|
|
++lpT;
|
|
}
|
|
}
|
|
while (width-->0)
|
|
out(fillch);
|
|
}
|
|
else
|
|
{
|
|
while (width-->0)
|
|
out(fillch);
|
|
while (cch--) {
|
|
if (*lpT == 0x0A || *lpT == 0x0D) {
|
|
out(0x0D);
|
|
out(0x0A);
|
|
}
|
|
else
|
|
out(*lpT++);
|
|
if (fWideChar)
|
|
{
|
|
++lpT;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
/* This is an unsupported character that followed %; So,
|
|
* we must output that character as it is; This is the
|
|
* Documented behaviour; This is the Fix for Bug #15410.
|
|
* Please note that this could be due to a typo in the app as in the
|
|
* case of the sample app for Bug #13946 and in such cases,
|
|
* we might mis-interpret the parameters that follow and that
|
|
* could result in a GP Fault. But, this is clearly a bug in the app
|
|
* and we can't do anything about it. We will just RIP and let
|
|
* them know in such cases.
|
|
*/
|
|
if (*lpFmt == 0x0A || *lpFmt == 0x0D) {
|
|
out(0x0D);
|
|
out(0x0A);
|
|
}
|
|
else
|
|
out(*lpFmt); /* Output the invalid char and continue */
|
|
break;
|
|
|
|
} /* END OF SWITCH(*lpFmt) */
|
|
} /* END OF IF(%) */
|
|
else
|
|
{
|
|
/* character not a '%', just do it */
|
|
if (*lpFmt == 0x0A || *lpFmt == 0x0D) {
|
|
out(0x0D);
|
|
out(0x0A);
|
|
}
|
|
else
|
|
out(*lpFmt);
|
|
}
|
|
|
|
/* advance to next format string character */
|
|
lpFmt++;
|
|
} /* END OF OUTER WHILE LOOP */
|
|
|
|
errorout:
|
|
*lpOut=0;
|
|
|
|
return WSPRINTF_LIMIT-cchLimit;
|
|
}
|
|
|
|
|
|
int vxd_vprintf(char * Format, CONST VOID * lpParms)
|
|
{
|
|
int length;
|
|
|
|
if (DebugBufferLength+WSPRINTF_LIMIT < DEBUG_BUFFER_SIZE) {
|
|
length = vxd_vsprintf(DebugBuffer+DebugBufferLength, Format, lpParms);
|
|
DebugBufferLength += length;
|
|
}
|
|
else
|
|
length = 0;
|
|
|
|
return length;
|
|
|
|
}
|
|
|
|
#ifdef CSC_RECORDMANAGER_WINNT
|
|
int
|
|
SP_PutNumber(
|
|
LPSTR lpb,
|
|
long n,
|
|
int limit,
|
|
int radix,
|
|
int strCase
|
|
)
|
|
{
|
|
unsigned long nT = (unsigned long)n, nRem=0;
|
|
int i;
|
|
|
|
for (i=0; i < limit; ++i)
|
|
{
|
|
|
|
nRem = nT%radix;
|
|
|
|
nT = nT/radix;
|
|
|
|
lpb[i] = (char)((nRem > 9)?((nRem-10) + ((strCase)?'A':'a')):(nRem+'0'));
|
|
|
|
if (!nT)
|
|
{
|
|
++i; // bump up the count appropriately
|
|
break;
|
|
}
|
|
}
|
|
|
|
return (i);
|
|
}
|
|
|
|
void
|
|
SP_Reverse(
|
|
LPSTR lpFirst,
|
|
LPSTR lpLast
|
|
)
|
|
{
|
|
LPSTR lpT = lpFirst;
|
|
char ch;
|
|
|
|
while (lpFirst < lpLast)
|
|
{
|
|
ch = *lpFirst;
|
|
*lpFirst = *lpLast;
|
|
*lpLast = ch;
|
|
++lpFirst; --lpLast;
|
|
}
|
|
}
|
|
#endif //ifdef CSC_RECORDMANAGER_WINNT
|
|
|
|
|