通常我们在BSP下一般使用RETAILMSG这个函数来实现串口打印,某些驱动也用DEBUGMSG。 在OAL又是另外一些串口打印函数。我们很早就知道这是OAL之下的debug.c的串口函数实现的,但是具体是怎么实现的,我从来没有去看过。今天碰到在串口MDD层无法使用串口打印的情况,搞得我很郁闷。就下决心找出来到底是怎么回事。
C:\WINCE500\PUBLIC\COMMON\SDK\INC中的dbgapi.h实现了RETAILMSG和DEBUGMSG,下面来看看到底是怎么回事。
Module Name: dbgapi.h
Purpose: Debug Message and Zone APIs.
--*/
#ifndef __DBGAPI_H__
#define __DBGAPI_H__
#ifdef __cplusplus
extern "C" {
#endif
void WINAPIV NKDbgPrintfW(LPCWSTR lpszFmt,
);void WINAPI WriteDebugLED(WORD wIndex, DWORD dwPattern);
/*
@doc EXTERNAL KERNEL
@struct DBGPARAM | Debug zone information structure
@comm The name of the module is used to look for zone initialization
information in the host PC registry. Zone names are displayed by
the control app (eg shell) which allows the user to dynamically
set zones.
@xref <f DEBUGREGISTER>
*/
typedef struct _DBGPARAM {
WCHAR lpszName[32]; // @field Name of module
WCHAR rglpszZones[16][32]; // @field names of zones for first 16 bits
ULONG ulZoneMask; // @field Current zone Mask
} DBGPARAM, *LPDBGPARAM;
BOOL RegisterDbgZones(HMODULE hMod, LPDBGPARAM lpdbgparam);
/*
@func BOOL | DEBUGZONE | Associates a mask bit with a zone
@parm int | bitnum | Bitnumber being defined
@rdesc A boolean which is TRUE if bitnum in '1' else is FALSE
@ex Example of use is |
// associate bit 0 with an info zone
#define ZONE_INFO DEBUGZONE(0)
// we can now use ZONE_INFO as a boolean for anything.
// We'd typically use it in a DEBUGMSG

*/
#define DEBUGZONE(n) (dpCurSettings.ulZoneMask&(0x00000001<<(n)))
#ifdef DEBUG
#ifdef SHIP_BUILD
#undef SHIP_BUILD
#pragma message (__FILE__ ":WARNING: SHIP_BUILD turned off since DEBUG defined")
#endif
#endif
#ifdef SHIP_BUILD //如果定义了SHIP_BUILD 那么以下串口打印函数就不会打印了。这个貌似可以使用环境变量设定。
#define ERRORMSG(cond,printf_exp) ((void)0)
#define RETAILMSG(cond,printf_exp) ((void)0)
#define DEBUGMSG(cond,printf_exp) ((void)0)
#define DEBUGLED(cond,parms) ((void)0)
#define DBGCHK(module,exp) ((void)0)
#define DEBUGCHK(exp) ((void)0)
#define DEBUGREGISTER(hMod) ((void)0)
#define RETAILREGISTERZONES(hMod) ((void)0)
#else // SHIP_BUILD
#ifdef DEBUG //debug模式NK
/*
@func BOOL | DEBUGMSG | Output a debug message conditionally
@parm BOOL | cond | The condition under which the message is printed
@parm <null> | (printf_exp) | A printf style expression to be output. Must be enclosed
in parentheses. Gets passed on to the <f NKDbgPrintf> function.
@ex Example of use |
DEBUGMSG(ZONE_INFO, (L"DLLNAME: Entered func1. Param 1 = %d\r\n", par1));
@xref <f RETAILMSG> <tab> <f ERRORMSG> <tab> <f NKDbgPrintf>
*/
#define DEBUGMSG(cond,printf_exp) \
((void)((cond)?(NKDbgPrintfW printf_exp),1:0)) //DEBUGMSG是通过NKDbgPrintfW 来实现的
#define DBGCHK(module,exp) \
((void)((exp)?1:( \
NKDbgPrintfW ( TEXT("%s: DEBUGCHK failed in file %s at line %d \r\n"), \
(LPWSTR)module, TEXT(__FILE__) ,__LINE__ ), \
DebugBreak(), \
0 \
)))
/*
@func BOOL | DEBUGLED | Output a debug LED pattern conditionally
@parm BOOL | cond | The condition under which the message is printed
@parm <null> | (parms) | The parameters to be passed to the WriteDebugLED
function. Must be in parentheses. First parameter is wIndex and second
parameter is dwPattern.
@ex Example of use |
DEBUGLED(ZONE_INFO, (3, 0x2345);
@xref <f RETAILMSG> <tab> <f ERRORMSG> <tab> <f WriteDebugLED>
*/
#define DEBUGLED(cond,parms) \
((void)((cond)?(WriteDebugLED parms),1:0))
/*
@func BOOL | DEBUGCHK | Asserts an expression
@parm BOOL | exp | Expression to be asserted
@comm If the expression is false, this will cause a DebugBreak to be hit which
will cause you to enter the debugger if you are running with one. It will
also give you the line number and file name where the assert failed.
*/
#define DEBUGCHK(exp) DBGCHK(dpCurSettings.lpszName, exp)
extern DBGPARAM dpCurSettings;
/*
@func BOOL | DEBUGREGISTER | Registers debug settings for a process / module
@parm HINSTANCE | hInstance | If target is a module this is it's hInstance. If
target is a process this should be NULL.
@comm This simply calls through to <f RegisterDebugZones>. It assumes that
there is a variable of name <b dpCurSettings> visible in the code.
*/
#define DEBUGREGISTER(hMod) RegisterDbgZones(hMod, &dpCurSettings)
#else // DEBUG 如果没有定义,就不会打印。
#define DEBUGMSG(cond,printf_exp) ((void)0)
#define DEBUGLED(cond,parms) ((void)0)
#define DBGCHK(module,exp) ((void)0)
#define DEBUGCHK(exp) ((void)0)
#define DEBUGREGISTER(hMod) ((void)0)
#endif // DEBUG
/*
@func BOOL | RETAILMSG | Output a message in retail builds
@parm BOOL | cond | The condition under which the message is printed
@parm <null> | (printf_exp) | A printf style expression to be output. Must be enclosed
in parentheses. This is simply passed in to the <f NKDbgPrintf> function.
@comm This should be used in a very limited fashion since it can increase
the size of your retail build.
@ex Example of use |
RETAILMSG(x==y, (L"DLLNAME: Expect. x==y = %d\r\n", x));
@xref <f DEBUGMSG> <tab> <f ERRORMSG> <tab> <f NKDbgPrintf>
*/
#define RETAILMSG(cond,printf_exp)\//从这里可以知道,RETAILMSG、DEBUGMSG一模一样,只是换了名字,通过NKDbgPrintfW来实现的
((cond)?(NKDbgPrintfW printf_exp),1:0)
/*
@func BOOL | ERRORMSG | Output an error msg
@parm BOOL | cond | The condition under which the message is printed
@parm <null> | (printf_exp) | A printf style expression to be output. Must be enclosed
in parentheses. This is passed in to the <f NKDbgPrintf> function.
@comm Very similar to <f RETAILMSG> except that this will prefix the message
with "ERROR" and give the file name & line number of the error.
@ex Example of use |
ERRORMSG(x==y, (L"DLLNAME: x===y = %d\r\n", x));
@xref <f DEBUGMSG> <tab> <f RETAILMSG> <tab> <f NKDbgPrintf>
*/
#define ERRORMSG(cond,printf_exp) \
((cond)?(NKDbgPrintfW(TEXT("ERROR: %s line %d: "),TEXT(__FILE__),__LINE__), NKDbgPrintfW printf_exp),1:0)
/*
@func BOOL | RETAILREGISTERZONES | Registers zone settings for a process / module
(Same as DEBUGREGISTER except available in retail and debug builds)
@parm HINSTANCE | hInstance | If target is a module this is it's hInstance. If
target is a process this should be NULL.
@comm This simply calls through to <f RegisterDebugZones>. It assumes that
there is a variable of name <b dpCurSettings> visible in the code.
*/
#define RETAILREGISTERZONES(hMod) RegisterDbgZones(hMod, &dpCurSettings)
#endif // SHIP_BUILD
/*
@func BOOL | RETAILLED | Output a LED code in retail builds
@parm BOOL | cond | The condition under which the message is printed
@parm <null> | (parms) | The parameters to be passed to the WriteDebugLED
function. Must be in parentheses. First parameter is wIndex and second
parameter is dwPattern.
@comm This should be used in a very limited fashion since it can increase
the size of your retail build.
@ex Example of use |
RETAILLED(ZONE_INFO, (3, 0x2345);
@xref <f DEBUGMSG> <tab> <f ERRORMSG> <tab> <f WriteDebugLED>
*/
#define RETAILLED(cond,parms) \
((void)((cond)?(WriteDebugLED parms),1:0))
// some alternate ways to get to these
#define ASSERTMSG(msg, exp) (DEBUGMSG(!exp,(msg)),DBGCHK(TEXT("Unknown"),exp))
#define ASSERT( exp ) DBGCHK(TEXT("Unknown"), exp)
#define ASSERT_IMPLIES( cond, exp ) ASSERT( !(cond) || (exp) )
#ifdef DEBUG
#define VERIFY(exp) ASSERT(exp)
#else
#define VERIFY(exp) ((void)(exp))
#endif
// Enable providing a hint to prefast via __assume
// e.g.
// PREFAST_ASSUME( pPointer); // we know pPointer can never be NULL
#ifdef _PREFAST_
#define PREFAST_ASSUME(exp) __assume(exp)
#else
#define PREFAST_ASSUME(exp)
#endif
// Simplify the cases where a PREFAST_ASSUME would be followed by an assertion
#define PREFAST_DEBUGCHK(exp) \
{ \
PREFAST_ASSUME(exp); \
DEBUGCHK(exp); \
}
#define PREFAST_ASSERT(exp) \
{ \
PREFAST_ASSUME(exp); \
ASSERT(exp); \
}
// macro to tell Prefast to not issue a specific warning for the following line of code
// use to suppress false positives from Prefast
// e.g.
// if( fPointerNotNull )
// PREFAST_SUPPRESS( 11, "pointer access is guarded by 'fPointerNotNull'" )
// p->Foo();
#ifdef _PREFAST_
#define PREFAST_SUPPRESS( cWarning, comment) __pragma ( prefast(suppress: cWarning, comment) )
#else
#define PREFAST_SUPPRESS( cWarning, comment)
#endif
// Helpful DBG macros that tighten up code.
// They prepend __FUNCTION__ to your debug msg and add a \n to the end.
#define DEB_0(ZONE,STR) DEBUGMSG(ZONE,(L"%S:"STR L"\n",__FUNCTION__))
#define DEB_1(ZONE,STR,ARG1) DEBUGMSG(ZONE,(L"%S:"STR L"\n",__FUNCTION__,ARG1))
#define DEB_2(ZONE,STR,ARG1,ARG2) DEBUGMSG(ZONE,(L"%S:"STR L"\n",__FUNCTION__,ARG1,ARG2))
#define DEB_3(ZONE,STR,ARG1,ARG2,ARG3) DEBUGMSG(ZONE,(L"%S:"STR L"\n",__FUNCTION__,ARG1,ARG2,ARG3))
#define DEB_4(ZONE,STR,ARG1,ARG2,ARG3,ARG4) DEBUGMSG(ZONE,(L"%S:"STR L"\n",__FUNCTION__,ARG1,ARG2,ARG3,ARG4))
#define DEB_5(ZONE,STR,ARG1,ARG2,ARG3,ARG4,ARG5) DEBUGMSG(ZONE,(L"%S:"STR L"\n",__FUNCTION__,ARG1,ARG2,ARG3,ARG4,ARG5))
//
// The _A version of the above are identical, except they call assert after the DEB_*.
// It's highly recommend that you use DEB_*_A with ZONE_ERROR so the user can always see the error.
// printed with the assert.
// NOTE: The assert is not conditioned on the ZONE.
#define DEB_0_A(ZONE,STR) { DEB_0(ZONE,STR);ASSERT(FALSE); }
#define DEB_1_A(ZONE,STR,ARG1) { DEB_1(ZONE,STR,ARG1); ASSERT(FALSE);}
#define DEB_2_A(ZONE,STR,ARG1,ARG2) { DEB_2(ZONE,STR,ARG1,ARG2); ASSERT(FALSE);}
#define DEB_3_A(ZONE,STR,ARG1,ARG2,ARG3) { DEB_3(ZONE,STR,ARG1,ARG2,ARG3); ASSERT(FALSE);}
#define DEB_4_A(ZONE,STR,ARG1,ARG2,ARG3,ARG4) { DEB_4(ZONE,STR,ARG1,ARG2,ARG3,ARG4); ASSERT(FALSE);}
#define DEB_5_A(ZONE,STR,ARG1,ARG2,ARG3,ARG4,ARG5) {DEB_5(ZONE,STR,ARG1,ARG2,ARG3,ARG4,ARG5); ASSERT(FALSE);}
#ifdef __cplusplus
}
#endif
#endif
从上面可以知道,RETAILMSG、DEBUGMSG一模一样,只是换了名字,通过NKDbgPrintfW来实现的,那么这个NKDbgPrintfW又是怎么来的呢?
1
//2
// Copyright (c) Microsoft Corporation. All rights reserved.3
//4
//5
// This source code is licensed under Microsoft Shared Source License6
// Version 1.0 for Windows CE.7
// For a copy of the license visit http://go.microsoft.com/fwlink/?LinkId=3223.8
//9

/**//*10
* NK Kernel printf code11
*12
*13
* Module Name:14
*15
* printf.c16
*17
* Abstract:18
*19
* This file implements debug and string routines20
*21
*/22
23

/**//*24
@doc EXTERNAL KERNEL25
@topic Debug Support for Applications | 26
The kernel provides several kinds of supports for debugging27
applications. These are:28
29
<b Debug Messages>: The kernel provides API's for printing out30
of debug messages which can be turned on and off dynamically 31
using zones. Any module (DLL/Process) can register itself32
with the debug subsystem using <f DEBUGREGISTER>. This API33
registers the address of a Zonemask (which is a DWORD) with the34
kernel. Using the debug shell, a user can now dynamically turn35
bits of this zonemask on and off from the shell window. 36
The most typical way to use this is to filter debug messages37
based on these bits. A structured way to do this is to use38
the <f DEBUGZONE> macro to associate zones with bits, and then39
use the <f DEBUGMSG> function to associate each debug message40
with a zone. Type ? in the shell to see how to change zones 41
dynamically from the shell which uses the <f SetDbgZone> function42
to implement the change. See the example below for general zone43
usage.44
45
<b Asserts>: The kernel also provides for simple asserts. See46
<f DEBUGCHK> for details.47
48
@ex An example of using debug zones |49
// Declare a DBGPARAM structure & give names to all used zones50
DBGPARAM dpCurSettings = { L"foodll", {51
L"Info", L"Validate", L"bar", L"random",52
L"Undefined", L"Undefined", L"Undefined", L"Undefined",53
L"Undefined", L"Undefined", L"Undefined", L"Undefined",54
L"Undefined", L"Undefined", L"Undefined", L"Undefined" },55
0x00000000 };56
57
// Associate bits with a zone 58
// these should match up with the text strings above!59
#define ZONE_INFO DEBUGZONE(0)60
#define ZONE_VALIDATE DEBUGZONE(1)61

62
// Register : Assume this is a DLL 63
// A Process would do the same in their libmain64
BOOL DllEntry (HANDLE hinstDLL, DWORD fdwReason, LPVOID lpv) {65
if ( fdwReason == DLL_PROCESS_ATTACH ) {66
DEBUGREGISTER(hinstDLL);67
}68

69
}70

71
// Use the defined zone in debug messages72
DEBUGMSG (ZONE_INFO, (L"This is an illustrative messages only!"));73

74
// Or use a zone to turn execution of some code on & off75
if (ZONE_VALIDATE) {76
// validate some stuff 
77
} 78
79
@xref 80
<f DEBUGMSG> <tab> <f RETAILMSG> <tab> <f ERRORMSG> <tab> <f DEBUGCHK> <tab>81
<f DEBUGREGISTER> <tab> <f DEBUGZONE> <tab> <t DBGPARAM> <tab>82
<f RegisterDebugZones> <tab> <f SetDbgZone>83
*/ 84

85
#include "kernel.h"86

87
#define out(c) if (--cchLimit) *lpOut++=(c); else goto errorout88

89
//-------------------------- Prototype declarations ---------------------------90

91
int NKwvsprintfW(LPWSTR lpOut, LPCWSTR lpFmt, CONST VOID * lpParms, int maxchars);92
LPCWSTR SP_GetFmtValue(LPCWSTR lpch, int *lpw, va_list *plpParms);93
int SP_PutNumber(LPWSTR, ULONG, int, int, int);94
int SP_PutNumber64(LPWSTR lpb, __int64 i64, int limit, int radix, int mycase);95
void SP_Reverse(LPWSTR lp1, LPWSTR lp2);96

97
extern CRITICAL_SECTION ODScs, DbgApiCS, VAcs, PhysCS;98

99
extern BOOL fSysStarted;100
extern BOOL g_cInterruptsOff; // this indicates KD had turned interrupts off101

102

103
//------------------------------------------------------------------------------104
//------------------------------------------------------------------------------105
VOID WINAPI 106
OutputDebugStringW(107
LPCWSTR str108
) 109


{110
BOOL fGetODScs = FALSE, fLockPages = FALSE;111
int len;112

113
// if we ever call OutputDebugString with interrupts off, send it to serial114
// port and return right away115

if (g_cInterruptsOff)
{116
OEMWriteDebugString((unsigned short *)str);117
return;118
}119

120
// increase debug count to indicate we're in ODS121
if (!str)122
str = __TEXT("(NULL)");123

124

if (pCurThread)
{125

126
pCurThread->bDbgCnt ++;127

128
// do not notify debugger while in power handler because we cannot block129

if (!InSysCall () && !IsInPwrHdlr ())
{130
131
if (pCurThread->pThrdDbg && (DbgApiCS.OwnerThread != hCurThread) 132

&& ProcStarted(pCurProc) && pCurThread->pThrdDbg->hEvent)
{133
pCurThread->pThrdDbg->dbginfo.dwDebugEventCode = OUTPUT_DEBUG_STRING_EVENT;134
pCurThread->pThrdDbg->dbginfo.dwProcessId = (DWORD)hCurProc;135
pCurThread->pThrdDbg->dbginfo.dwThreadId = (DWORD)hCurThread;136
pCurThread->pThrdDbg->dbginfo.u.DebugString.lpDebugStringData = (LPBYTE)str;137
pCurThread->pThrdDbg->dbginfo.u.DebugString.fUnicode = TRUE;138
pCurThread->pThrdDbg->dbginfo.u.DebugString.nDebugStringLength = (strlenW(str)+1)*2;139
SetEvent(pCurThread->pThrdDbg->hEvent);140
SC_WaitForMultiple(1,&pCurThread->pThrdDbg->hBlockEvent,FALSE,INFINITE);141
}142
143
fGetODScs = !ReadyForStrings && (hCurThread != ODScs.OwnerThread);144
fLockPages = (1 == pCurThread->bDbgCnt);145

146
}147
}148
149
// forces the string to be paged in if not already150
len = (strlenW(str)+1)*sizeof(WCHAR);151

152
// Lock page if we need to153
if (fLockPages)154
LockPages((LPVOID)str,len,0,0);155

156
if (fGetODScs)157
EnterCriticalSection(&ODScs);158

159
lpWriteDebugStringFunc((unsigned short *)str);160

161
if (fGetODScs)162
LeaveCriticalSection(&ODScs);163

164
if (fLockPages)165
UnlockPages((LPVOID)str,len);166

167
// decrement debug count to indicate we're out of ODS168

if (pCurThread)
{169
pCurThread->bDbgCnt --;170
}171
}172

173

174

175
//------------------------------------------------------------------------------176
//------------------------------------------------------------------------------177
int 178
InputDebugCharW(void) 179


{180
int retvalue;181
if (!InSysCall())182
EnterCriticalSection(&ODScs);183
retvalue = OEMReadDebugByte();184
if (!InSysCall())185
LeaveCriticalSection(&ODScs);186
return retvalue;187
}188

189
//------------------------------------------------------------------------------190
// special version if we're on KStack191
//------------------------------------------------------------------------------192

static VOID _NKvDbgPrintfW(LPCWSTR lpszFmt, va_list lpParms)
{193
static WCHAR rgchBuf[384];194
NKwvsprintfW(rgchBuf, lpszFmt, lpParms, sizeof(rgchBuf)/sizeof(WCHAR));195
OutputDebugStringW(rgchBuf);196
}197

198
//------------------------------------------------------------------------------199
//------------------------------------------------------------------------------200
#if (_MSC_VER >= 1300)201
__declspec(noinline) // Too much KStack is used if this is inlined202
#endif203
static VOID NKvDbgPrintfWOnStack(LPCWSTR lpszFmt, va_list lpParms) 204


{205
WCHAR rgchBuf[384];206
WORD wLen = 0;207
// Get it into a string208
#ifdef DEBUG209

if (ZONE_DEBUG)
{210
rgchBuf[0] = '0';211
rgchBuf[1] = 'x';212
wLen += 2;213
wLen += SP_PutNumber(rgchBuf+2,(ULONG)pCurThread,8,16,0);214
SP_Reverse(rgchBuf+2,rgchBuf+wLen-1);215
rgchBuf[wLen++] = ':';216
rgchBuf[wLen++] = ' ';217
}218
#endif219
wLen += NKwvsprintfW(rgchBuf + wLen, lpszFmt, lpParms, sizeof(rgchBuf)/sizeof(WCHAR) - wLen);220

221
// don't need to call LockPages since it's on stack.222

if (pCurThread)
{223
pCurThread->bDbgCnt ++;224
}225
OutputDebugStringW(rgchBuf);226

if (pCurThread)
{227
pCurThread->bDbgCnt --;228
}229
}230

231

232
//------------------------------------------------------------------------------233
//234
// @doc EXTERNAL KERNEL235
// @func VOID | NKDbgPrintf | Prints debug messages236
// @parm LPWSTR | lpszFmt | Printf style formatting string237
// @parmvar Variable argument list238
// @comm Should not be used directly - macros like <f DEBUGMSG> should239
// be used to print messages. This function will format the240
// debug string into a buffer and then log it according to the241
// current logging paramters. If terminal logging is on it242
// outputs this to the debug terminal, and if file logging243
// is on it stores it to the file peg.log on the host PC.244
// 245
// <b WARNING>: The message being output must be smaller than246
// 256 bytes - ie 128 unicode characters.247
// @xref <f DEBUGMSG>248
//249
//------------------------------------------------------------------------------250
void WINAPIV 251
NKDbgPrintfW(252
LPCWSTR lpszFmt,253

254
) 255


{256
va_list arglist;257
va_start(arglist, lpszFmt);258
NKvDbgPrintfW(lpszFmt, arglist);259
va_end(arglist);260
}261

262
VOID NKvDbgPrintfW (LPCWSTR lpszFmt, va_list lpParms) 263


{264
if (fSysStarted && !InSysCall ()) 265
NKvDbgPrintfWOnStack (lpszFmt, lpParms);266
else267
_NKvDbgPrintfW(lpszFmt, lpParms);268
}269

270

271
//------------------------------------------------------------------------------272
//------------------------------------------------------------------------------273
int 274
NKwvsprintfW(275
LPWSTR lpOut,276
LPCWSTR lpFmt,277
va_list lpParms,278
int maxchars279
) 280


{281
int left, width, prec, size, sign, radix, upper, cch, cchLimit;282
WCHAR prefix, fillch;283
LPWSTR lpT;284
LPCHAR lpC;285

union
{286
long l;287
unsigned long ul;288
__int64 i64;289
WCHAR sz[sizeof(long)];290
} val;291

292
cchLimit = maxchars;293

while (*lpFmt)
{294

if (*lpFmt==(WCHAR)'%')
{295

/**//* read the flags. These can be in any order */296
left=0;297
prefix=0;298

while (*++lpFmt)
{299
if (*lpFmt==(WCHAR)'-')300
left++;301
else if (*lpFmt==(WCHAR)'#')302
prefix++;303
else304
break;305
}306

/**//* find fill character */307

if (*lpFmt==(WCHAR)'0')
{308
fillch=(WCHAR)'0';309
lpFmt++;310
} else311
fillch=(WCHAR)' ';312

/**//* read the width specification */313
lpFmt=SP_GetFmtValue(lpFmt,&cch, &lpParms);314
width=cch;315

/**//* read the precision */316

if (*lpFmt==(WCHAR)'.')
{317
lpFmt=SP_GetFmtValue(++lpFmt,&cch, &lpParms);318
prec=cch;319
} else320
prec=-1;321

/**//* get the operand size */322
size=1;323

if (*lpFmt=='l')
{324
lpFmt++;325

} else if (*lpFmt=='h')
{326
size=0;327
lpFmt++;328

} else if ((*lpFmt == 'I') && (*(lpFmt+1) == '6') && (*(lpFmt+2) == '4'))
{329
lpFmt+=3;330
size = 2;331
}332
upper=0;333
sign=0;334
radix=10;335

switch (*lpFmt)
{336
case 0:337
goto errorout;338
case (WCHAR)'i':339
case (WCHAR)'d':340
sign++;341
case (WCHAR)'u':342

/**//* turn off prefix if decimal */343
prefix=0;344
donumeric:345

/**//* special cases to act like MSC v5.10 */346
if (left || prec>=0)347
fillch=(WCHAR)' ';348
if (size == 1)349
val.l=va_arg(lpParms, long);350
else if (size == 2)351
val.i64 = va_arg(lpParms, __int64);352
else if (sign)353
val.l=va_arg(lpParms, short);354
else355
val.ul=va_arg(lpParms, unsigned);356
if (sign && val.l<0L)357
val.l=-val.l;358
else359
sign=0;360
lpT=lpOut;361

/**//* blast the number backwards into the user buffer */362
if (size == 2)363
cch=SP_PutNumber64(lpOut,val.i64,cchLimit,radix,upper);364
else365
cch=SP_PutNumber(lpOut,val.l,cchLimit,radix,upper);366
if (!(cchLimit-=cch))367
goto errorout;368
lpOut+=cch;369
width-=cch;370
prec-=cch;371
if (prec>0)372
width-=prec;373

/**//* fill to the field precision */374
while (prec-->0)375
out((WCHAR)'0');376

if (width>0 && !left)
{377

/**//* if we're filling with spaces, put sign first */378

if (fillch!=(WCHAR)'0')
{379

if (sign)
{380
sign=0;381
out((WCHAR)'-');382
width--;383
}384

if (prefix)
{385
out(prefix);386
out((WCHAR)'0');387
prefix=0;388
}389
}390
if (sign)391
width--;392

/**//* fill to the field width */393
while (width-->0)394
out(fillch);395

/**//* still have a sign? */396
if (sign)397
out((WCHAR)'-');398

if (prefix)
{399
out(prefix);400
out((WCHAR)'0');401
}402

/**//* now reverse the string in place */403
SP_Reverse(lpT,lpOut-1);404

} else
{405

/**//* add the sign character */406

if (sign)
{407
out((WCHAR)'-');408
width--;409
}410

if (prefix)
{411
out(prefix);412
out((WCHAR)'0');413
}414

/**//* reverse the string in place */415
SP_Reverse(lpT,lpOut-1);416

/**//* pad to the right of the string in case left aligned */417
while (width-->0)418
out(fillch);419
}420
break;421
case (WCHAR) 'p' :422
// Fall into case below, since NT is going to 64 bit423
// they are starting to use p to indicate a pointer424
// value. They only seem to support lower case 'p'425
case (WCHAR)'X':426
upper++;427
case (WCHAR)'x':428
radix=16;429
if (prefix)430
if (upper)431
prefix=(WCHAR)'X';432
else433
prefix=(WCHAR)'x';434
goto donumeric;435
case (WCHAR)'c':436
val.sz[0] = va_arg(lpParms, WCHAR);437
val.sz[1]=0;438
lpT=val.sz;439
cch = 1; // Length is one character. 440

/**//* stack aligned to larger size */441
goto putstring;442
case 'a': // ascii string!443
case 'S':444
PrtAscii:445
if (!(lpC=va_arg(lpParms, LPCHAR)))446
lpC = "(NULL)";447
cch=strlen(lpC);448
if (prec>=0 && cch>prec)449
cch=prec;450
width -= cch;451

if (left)
{452
while (cch--)453
out((WCHAR)*lpC++);454
while (width-->0)455
out(fillch);456

} else
{457
while (width-->0)458
out(fillch);459
while (cch--)460
out((WCHAR)*lpC++);461
}462
break;463
case 's':464
if (!size)465
goto PrtAscii;466
if (!(lpT=va_arg(lpParms,LPWSTR)))467
lpT = L"(NULL)";468
cch=strlenW(lpT);469
putstring:470
if (prec>=0 && cch>prec)471
cch=prec;472
width -= cch;473

if (left)
{474
while (cch--)475
out(*lpT++);476
while (width-->0)477
out(fillch);478

} else
{479
while (width-->0)480
out(fillch);481
while (cch--)482
out(*lpT++);483
}484
break;485
default:486

out(*lpFmt); /**//* Output the invalid char and continue */487
break;488
}489

} else /**//* character not a '%', just do it */490
out(*lpFmt);491

/**//* advance to next format string character */492
lpFmt++;493
}494
errorout:495
*lpOut=0;496
return maxchars-cchLimit;497
}498

499

500

501
//------------------------------------------------------------------------------502
// GetFmtValue503
// reads a width or precision value from the format string504
//------------------------------------------------------------------------------505
LPCWSTR 506
SP_GetFmtValue(507
LPCWSTR lpch,508
int *lpw,509
va_list *plpParms510
) 511


{512
int i=0;513

if (*lpch == TEXT('*'))
{514
*lpw = va_arg(*plpParms, int);515
lpch++;516

} else
{517

while (*lpch>=(WCHAR)'0' && *lpch<=(WCHAR)'9')
{518
i = i*10 + (*lpch-(WCHAR)'0');519
lpch++;520
}521
*lpw=i;522
}523

/**//* return the address of the first non-digit character */524
return lpch;525
}526

527

528

529
//------------------------------------------------------------------------------530
//------------------------------------------------------------------------------531
void 532
SP_Reverse(533
LPWSTR lpFirst,534
LPWSTR lpLast535
) 536


{537
int swaps;538
WCHAR tmp;539
swaps = ((((DWORD)lpLast - (DWORD)lpFirst)/sizeof(WCHAR)) + 1)/2;540

while (swaps--)
{541
tmp = *lpFirst;542
*lpFirst++ = *lpLast;543
*lpLast-- = tmp;544
}545
}546

547
const WCHAR lowerval[] = TEXT("0123456789abcdef");548
const WCHAR upperval[] = TEXT("0123456789ABCDEF");549

550

551

552
//------------------------------------------------------------------------------553
//------------------------------------------------------------------------------554
int 555
SP_PutNumber(556
LPWSTR lpb,557
ULONG n,558
int limit,559
int radix,560
int mycase561
) 562


{563
int used = 0;564

while (limit--)
{565
*lpb++ = (mycase ? upperval[(n % radix)] : lowerval[(n % radix)]);566
used++;567
if (!(n /= radix))568
break;569
}570
return used;571
}572

573

574

575
//------------------------------------------------------------------------------576
//------------------------------------------------------------------------------577
int 578
SP_PutNumber64(579
LPWSTR lpb,580
__int64 i64,581
int limit,582
int radix,583
int mycase584
) 585


{586
int used = 0;587

while (limit--)
{588
*lpb++ = (mycase ? upperval[(i64 % radix)] : lowerval[(i64 % radix)]);589
used++;590
if (!(i64 /= radix))591
break;592
}593
return used;594
}595

596

关于OAL下的debug.c的
注意事项:
一、如果文章标题标有【原创】字眼的,gooogleman有原创著作权,请转载的时候不要删除文章的任何部分,并且商业网站转载必须经过gooogleman同意。
二、文章标题标有【转载】也请转载的时候标明原创作者的名字和原文地址,尊重原创作者。
三、本博客为gooogleman的官方博客,并且会和gooogleman官方网站http://www.gooogleman.com/以及gooogleman CSDN 博客同步更新。
四、本博客原创文章所有权属于gooogleman嵌入式开发板联盟。
五、gooogleman嵌入式开发板联盟盟主旗舰店为http://gooogleman.taobao.com/ 旺旺ID 为:gooogleman2009 目前发现网上有类似的ID,请各位网友不要认错, gooogleman和gooogleman2009 是唯一的!


浙公网安备 33010602011771号