• Keine Ergebnisse gefunden

Chapter II/Refining the Application (Tic-Tac-Toe)

Im Dokument PenPomt GO (Seite 168-172)

Tic-Tac.,. T oe has many of the niceties expected of a real application. Many of these enhancements are independent of the program, and could be added to Empty Application as easily as to Tic-T ac-Toe.

". Debugging

You can use DB, the PenPoint Source-level debugger, to step through code. In an object-oriented system, your objects receive many messages from outside sources, many of which you may not expect. It's useful to be able to easily track the flow of messages through your routines, and to turn this on and off while your program is running. As you've noticed if you've looked at the code, Tic-Tac-Toe has

extensive support for debugging. The facilities it uses are:

• Tracing messages using msg Trace

• Printing debug messages using Debugf

• Dumping objects' state using msgDump

• Giving the Class Manager symbolic names for its objects, messages, and status values using ClsSymbolslnit.

The complexity in Tic-Tac-Toe arises because it lets you turn features on and off while the program is running.

",. Tracing

It's very useful to have a log of what messages are coming in. You can get a

message log by turning on message tracing; you can either turn it on for a class or for a single instance of that class.

In DEBUG mode, TTTMBAR.C defines a debug menu which can turn tracing on or off for the various classes. All the menu items send msgTttAppChangeTracing to the application. The message argument encodes the target object to trace and whether to trace it or not:

static TK_TABLE_ENTRY traceMenu[] = {

("Trace App On", msgTttAppChangeTracing, MakeU32 (0,1) } , {"Trace App Off", msgTttAppChangeTracing, MakeU32 (0, 0) } , {"Trace View On", msgTttAppChangeTracing, MakeU32 (1, 1) }, ("Trace View Off", msgTttAppChangeTracing, .MakeU32(1,O)}, {"Trace Data On", msgTttAppChangeTracing, MakeU32 (2, 1) } , ("Trace Data Off", msgTttAppChangeTracing, MakeU32(2,O)}, {pNull}

} ;

11.1

11.1.1

The TttDbgChangeTracing routine is implemented in TTTDBG.C. It simply sends msgTrace to the target objec~t with an argument of true or false.

".. Debugf Statements and Debug Flags

Going beyond message tracing, it's useful to print out what your application is doing at various stages. One approach is to add simple Debugf statements as you debug various sections. However, in a large program you quickly get overwhelmed by debugging statements you're not interested in. Tic-Tac-Toe leaves all the Debugf statements in the code, and controls which statements show up by examining a debugging flag set. It uses DbgFlagGet to check whether a flag is set, the same as Empty App and the other simpler applications. What Tic-T ac-T oe prQvides is an easy way to print out a string identifying the routine, followed by whatever printf-style parameters you want to use. Thus this code:

if (s == stsFSNodeNotFound) {

DbgTttAppCheckStationery (("file not found; s=Ox%lx", s)) goto NormalExiti

will print out

TttAppCheckStationery: file not found; s=Oxnum but only if the appropriate debugging flag is set.

So, how is it implemented? A definition of its debug routine precedes each function for which you want to print debugging information, for example, Dbg TttAppCheckStationery.

#define DbgTttAppCheckStationery(x) \

TttDbgHelper("TttAppCheckStationery",tttAppDbgSet,Oxl,x)

Call this macro anywhere that you might want to display a debugging string. The parameter to the macro (x) is the printf-style format string and any arguments

«"file not found; s=Ox%lx",s)). In order to treat multiple parameters as one, they must be enclosed in a second set of parentheses.

The TttDbgHelper routine checks if the specified flag (Ox0001) is set in the specified debugging flag set (tttAppDbgSet), and if so prints the identifying string ("TttAppCheckStationery") together with any printf-style format string passed in (x).

There are 256 debugging flag sets, each of which has a 32-bit value. GO uses some of them for its applications-see \PENPOINT\SDK\INC\DEBUG.H for a full list. TTTPRIV.H defines the debugging flag sets used in Tic-Tac-Toe, such as tttAppDbgSet:

11.1.2

CHAPTER 11 I REFINING THE APPLICATION (TIC-TAC-TOE) '161

II

II Debug flag sets II

idefine tttAppDbgSet OxCO idefine tttDataDbgSet OxCl idefine tttUtilDbgSet OxC2 idefine tttViewDbgSet OxC3 idefine tttViewOptsDbgSet OxC4 idefine tttViewXferDbgSet Oxcs Other routines use other flags.

In case you care, here's the definition ofTttDbgHelper:

idefine TttDbgHelper(str,set,flag,x) \

Debugging

Dbg (if (DbgFlagGet ( (set) , (U32) (flag) » {DPrintf ("%s: ", str) i Debugf Xi})

Dprintf is the same as Debugf, except that Dprintf doesn't insert an automatic new-line at the end of the function.

".. Dumping Obiects

One of the messages defined by the Class Manager is msgDump. A class should respond to it by calling its ancestor, then printing out information about seWs state. Most classes only implement msgDump in the DEBUG version of their code.

Tic-Tac-Toe lets you dump its various objects from its Debug menu. In TITMBAR.C, it defines the menu:

static TK_TABLE_ENTRY debugMenu[] = {

{"Dump View", msgTttAppDumpView, {"Dump Data", msgTttAppDumpDataObject, {"Dump App", msgDump,

O} ,

OJ,

O} ,

11.1.3

{"Dump Window Tree", (U32) dumpTreeMenu, 0, 0, tkMenuPullRight}, {"Trace", (U32)traceMenu,

{"Force Repaint", msgTttAppForceRepaint,

0, 0, tkMenuPullRight I tkBorderEdgeTop}, 0, 0, tkBorderEdgeTop},

{pNull}

} ;

The client of the menu is the application, so to dump the application all the menu item needs to do is send msgDump. For the view and data object, you would either have to change the -clients of the menu items, or have the application class respond to special msgTttAppDumpView or insgTttAppDumpData messages by sending msgDump to the appropriate target. Tic-T ac-T oe does the latter; the handlers for these messages are in TTTDBG.C.

".,. Dumping Any Obiect

Another approach is to have a generic dump-object function in the DEBUG version of your code which sends msgDump to its argument. When running DB, you can call this routine directly, passing it the UID of the object you want dumped.

". Symbol Names

All the Class Manager's macros (ObjCallRet, ObjCallWarn,

ObjCallAncestorChk, and so on) print a string giving the message, object, and status value if they fail (in DEBUG mode). You can also ask DB to print out messages, objects, and status values. Ordinarily the most the Class Manager and DB can do is print the various fields in the UID, such as the administrated field and message number. However, if you supply the Class Manager a mapping from symbol names to English names, it and DB will use the English names in their debugging output.

The Class Manager routine you use is ClsSymbolsInit. The routine takes three arrays, one for objects, one for messages, and one for status values. Each array is composed of symbol-string pairs. Tic-Tac-Toe sets up these arrays in the file S_TTT.C:

const CLS_SYM_STS tttStsSymbols[]

0, O};

const CLS_SYM_MSG tttMsgSymbols[]

msgTttAppChangeDebugFlag, "msgTttAppChangeDebugFlag", msgTttAppChangeDebugSet, "msgTttAppChangeDebugSet",

msgTttViewTakeSel, "msgTttViewTakeSel",

0, O};

const CLS_SYM_OBJ tttObjSymbols[] = {

cl·sTttApp, "clsTttApp", clsTttData, "clsTttData", clsTttView, "clsTttView",

0, O};

(Tic-Tac-Toe doesn't define any STATUS values.) ClsSymbolsInit also takes a fourth parameter, a unique string identifYing this group of symbolic names.

Here's the routine in S_TTT.C that calls ClsSymbolsInit:

return ClsSymbolslnit(

"ttt",

tttObjSymbols, t ttMsgSymbols, tttStsSymbols) ;

At installation (from process instance 0), TTT.EXE calls TttSymbolsInit to load these arrays. To save space, all of this code is excluded with an hfdef if DEBUG is not set.

""'" Generating Symbols Automatica~ly

It's cumbersome to type in and update the arrays of UID-string pairs. At GO we have developed scripts that automatically generate files like S_TTT.C. These scripts require the MKS toolkit and other third-party utilities, so they are not part of the SDK release and are not supported. If you're interested in these scripts, contact GO Developer Support.

11.1.4

11.1.4.1

CHAPTER 11 I REFINING THE APPLICATION (TlC-TAC-TOE) 163

~V' C'i"iii~iiig §ymb@~ Names YClUJll'se!f

Tic-Tac-Toe just prints UIDs as long integers when it needs to print them out.

You can also print them in hexadecimal format using the %p format code. If you want to print out the long names within your own code, the Class Manager defines several functions to convert objects, messages, and status values to strings, such as ClsObjectToString.

Im Dokument PenPomt GO (Seite 168-172)