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