Leaked source code of windows server 2003
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

/*++
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