home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
drdobbs
/
1990
/
11
/
cramer.asc
< prev
next >
Wrap
Text File
|
1990-10-12
|
22KB
|
698 lines
_CTRACE: A MESSAGE LOGGING CLASS_
by William D. Cramer
[LISTING ONE]
/** CTrace.h -- Definitions for using the Trace class **/
#define _H_CTrace
/* System/library header files */
#include <Commands.h> /* standard menu command definition */
#include <oops.h> /* standard OOP definitions */
#include <stdarg.h> /* varg macro definitions */
#include <CDesktop.h> /* definitions for desktop class */
#include <CBartender.h> /* definitions for menu bar manager */
#include <CDataFile.h> /* definitions for data file class */
#include <CApplication.h> /* definitions for the application class */
#include <CDocument.h> /* definitions for parent class */
#include <Constants.h> /* miscellaneous environment constants */
/* Local header files */
#include "CLogPanorama.h" /* definitions for logging panorama class */
/* Resource numbers */
#define TRACE_MENU_ID (2000) /* menu resource ID */
#define TRACE_MENU_SHOW (2000L) /* menu command for show/hide log */
#define TRACE_MENU_MASK (2001L) /* menu command for log masking */
#define TRACE_WINDOW_ID (2000) /* main window resource ID */
#define TRACE_MASK_DIALOG (2000) /* resource ID for dialog box */
#define FIRST_MASK (3) /* item # of first checkbox in dialog */
#define LAST_MASK (34) /* item # of last checkbox in dialog */
#define UNHILITE_CONTROL (255) /* magic part # for disabling control */
#define OKAY_BUTTON_ITEM (1) /* item # for the 'okay' button */
#define CANCEL_BUTTON_ITEM (2) /* item # for the 'cancel' button */
/* Standard trace categories */
#define T_ERROR (0x00000001) /* serious error */
#define T_WARNING (0x00000002) /* mildly serious problem */
#define T_INFO (0x00000004) /* news you can use */
#define T_FUNC_IN (0x00000008) /* function entry */
#define T_FUNC_OUT (0x00000010) /* function exit */
/* Other constants */
#define MAX_USER_BUFF (MAX_LOGREC_CHAR-19+1) /* max length of user message */
#define TRACE_DEFAULT_MASK (0L) /* initial trace mask */
/* External references */
extern CDesktop *gDesktop; /* the whole desktop view */
extern CApplication *gApplication; /* the application object */
extern CBartender *gBartender; /* the menu bar object */
extern OSType gSignature; /* application signature */
struct CTrace : CDocument
{
/* local instance variables */
CLogPanorama *itsLogPanorama; /* panorama for trace messages */
unsigned long currMask; /* currently enabled trace categories */
/* local class methods */
void ITrace(short records);
void ToggleTraceWindow(void);
void SetTraceMask (void);
void Trace (unsigned long mask, char *format, ...);
Boolean IsItVisible(void);
/* inherited methods overriden */
void UpdateMenus (void);
Boolean DoSaveAs (SFReply *macSFReply);
Boolean Close (Boolean quitting);
};
[LISTING TWO]
/** CTrace.c -- Methods for the trace document class. **/
#include "CTrace.h" /* trace class parameters */
/** Global declaration **/
CTrace
*gTrace; /* the one instance of this class */
/** ITrace() -- Initializes trace document object. **/
void CTrace::ITrace
(
short records /* number of records before wrap */
)
{
Rect
frameRect; /* window frame */
CDocument::IDocument (gApplication, TRUE);
itsWindow = new (CWindow);
itsWindow->IWindow (TRACE_WINDOW_ID, FALSE, gDesktop, this);
itsWindow->GetFrame (&frameRect);
itsWindow->Move (gDesktop->bounds.right - frameRect.right - RIGHT_SMARGIN,gDesktop->bounds.top + TOP_SMARGIN);
itsLogPanorama = new (CLogPanorama);
itsLogPanorama->ILogPane (records, this, itsWindow);
itsMainPane = itsLogPanorama;
currMask = TRACE_DEFAULT_MASK;
gTrace = this;
}
/** ToggleTraceWindow() -- Toggles visibility of trace window. **/
void CTrace::ToggleTraceWindow(void)
{
if (itsWindow->visible)
itsWindow->Hide ();
else
{
itsWindow->Show ();
itsWindow->Select ();
}
}
/** Close() -- Overrides normal document method by closing trace window. **/
Boolean CTrace::Close
(
Boolean quitting /* ignored */
)
{
itsWindow->Hide ();
return (TRUE);
}
/** SetTraceMask -- Allows user to set/clear defined trace masks.**/
void CTrace::SetTraceMask (void)
{
int
bitNum, /* bit number within the trace mask */
checkBoxState, /* state of a checkbox (0=unset,1=set) */
item, /* loop counter */
itemType, /* item type (4=button, 5=checkbox) */
whichItem; /* item number selected by user */
Handle
itemStuff; /* handle to dialog item parameters */
Boolean
done; /* loop-termination flag */
Str255
title; /* text associated with a dialog item */
Rect
itemRect; /* rectangle surrounding a control */
DialogPtr
maskDialog; /* structure for dialog box */
/* Pull up the mask dialog box out of the resource fork */
maskDialog = GetNewDialog (TRACE_MASK_DIALOG, NULL, (Ptr)(-1));
/* Run through checkboxes */
for (item=FIRST_MASK, bitNum=0;
item<=LAST_MASK; item++,
bitNum++)
{
GetDItem (maskDialog, item, &itemType, &itemStuff, &itemRect);
GetCTitle ( (ControlHandle)itemStuff, title);
PtoCstr ((char*)title);
if (strcmp((char*)title, "Undefined") != 0)
{
checkBoxState = ((currMask&(1L<<bitNum)) == 0L) ? 0 : 1;
SetCtlValue ( (ControlHandle) itemStuff, checkBoxState);
}
else
HiliteControl (itemStuff, UNHILITE_CONTROL);
}
/* The default button (#1) is the okay button, draw outline around it. */
GetDItem (maskDialog, OKAY_BUTTON_ITEM, &itemType, &itemStuff, &itemRect);
SetPort (maskDialog);
PenSize (3, 3);
InsetRect (&itemRect, -4, -4);
FrameRoundRect (&itemRect, 16, 16);
/* Get events from dialog manager and process accordingly */
done = FALSE;
while (!done)
{
ModalDialog (NULL, &whichItem);
GetDItem (maskDialog, whichItem, &itemType, &itemStuff, &itemRect);
switch (itemType)
{
case ctrlItem + btnCtrl : /* CANCEL or OKAY */
if (whichItem == OKAY_BUTTON_ITEM)
{
currMask = 0L;
for (item=FIRST_MASK, bitNum=0; item<=LAST_MASK; item++, bitNum++)
{
GetDItem (maskDialog, item, &itemType, &itemStuff, &itemRect);
checkBoxState = GetCtlValue ( (ControlHandle) itemStuff);
currMask |= (checkBoxState==0) ? 0L : (1L<<bitNum);
}
done = TRUE;
}
else if (whichItem == CANCEL_BUTTON_ITEM)
done = TRUE;
break;
case ctrlItem + chkCtrl : /* a category checkbox */
checkBoxState = GetCtlValue ( (ControlHandle) itemStuff);
if (checkBoxState == 0)
SetCtlValue ( (ControlHandle) itemStuff, 1);
else
SetCtlValue ( (ControlHandle) itemStuff, 0);
break;
default:
break;
}
}
/* On exit, trash dialog record and controls */
DisposDialog (maskDialog);
}
/** Trace() -- Checks current mask **/
void CTrace::Trace
(
unsigned long mask, /* severity of message */
char *format, /* format for user's arguments */
... /* arguments to format (varg) */
)
{
static char
traceBuff[MAX_LOGREC_CHAR], /* string that will be added to log */
userBuff[MAX_LOGREC_CHAR*2], /* user's contribution to log record */
prefix[40]; /* date+time string */
int
maxUserBuff; /* maximum length of formatted user string */
long
timeSecs; /* current time/date */
DateTimeRec
dateRec; /* time/date in MM/DD/YY HH:MM:SS components */
/* Should the message get added to the trace log? */
if ( (currMask & mask) != 0)
{
/* format the user's portion of the message */
vsprintf (userBuff, format, __va(format));
/* make sure the entire record will fit into traceBuff */
if (strlen (userBuff) > MAX_USER_BUFF)
userBuff[MAX_USER_BUFF] = NULL;
/* build log message and add it to the log */
GetDateTime (&timeSecs);
Secs2Date (timeSecs, &dateRec);
sprintf (traceBuff, "%02d/%02d/%02d--%02d:%02d:%02d %s",
dateRec.month, dateRec.day, dateRec.year-1900,
dateRec.hour, dateRec.minute, dateRec.second,
userBuff);
itsLogPanorama->AddString (traceBuff);
}
}
/** IsItVisible() -- Returns 'visible' flag to update menu bar entries. **/
Boolean CTrace::IsItVisible(void)
{
return (itsWindow->visible);
}
/** UpdateMenus() -- Disables Save and Revert entries **/
void CTrace::UpdateMenus(void)
{
inherited::UpdateMenus ();;
gBartender->DisableCmd (cmdSave);
gBartender->DisableCmd (cmdRevert);
}
/** DoSaveAs() -- Writes out contents of itsLogList to indicated file. **/
Boolean CTrace::DoSaveAs
(
SFReply *macSFReply /* the user's choice of file */
)
{
char
logRecBuff[MAX_LOGREC_CHAR]; /* buffer for log entry */
short
maxRec, /* number of records in LogList */
offsetToNull, /* byte offset to end of log entry */
rec; /* loop counter */
/* Dispose of the data used for the old file record */
if (itsFile != NULL)
itsFile->Dispose ();
/* Set up the new data file (no error checking!) */
itsFile = new (CDataFile);
((CDataFile *)itsFile)->IDataFile ();
itsFile->SFSpecify (macSFReply);
itsFile->CreateNew (gSignature, 'TEXT');
itsFile->Open (fsRdWrPerm);
/* Write out all records in list (add carriage return to end of each line).*/
maxRec = (short)(itsLogPanorama->itsLogList)->GetNumItems();
for (rec=1; rec<=maxRec; rec++)
{
(itsLogPanorama->itsLogList)->GetString (rec, logRecBuff);
offsetToNull = strlen (logRecBuff);
logRecBuff[offsetToNull] = '\r';
((CDataFile*)itsFile)->WriteSome (logRecBuff, offsetToNull+1);
}
return (TRUE);
}
[LISTING THREE]
/** CLogPanarama.h -- Definitions for using the LogPanorama class **/
#define _H_CLogPanorama
/* System/library headers */
#include <CPanorama.h> /* definitions for superclass Panorama */
#include <CScrollPane.h> /* definitions for ScrollPane class */
#include <CWindow.h> /* definitions for Window class */
#include <oops.h> /* standard OOP definitions */
#include <Constants.h> /* miscellaneous look-n-feel paramaters */
#include <Limits.h> /* numeric extrema */
/* Local headers */
#include "CLogList.h" /* definitions for LogList class */
#define LOGPANE_FONT (monaco) /* font family of text in the log window */
#define LOGPANE_FONT_SIZE (9) /* size of text in the log window */
#define LOGPANE_HORZ_SCROLL (5) /* units per horizontal scroll */
#define LOGPANE_VERT_SCROLL (1) /* units per vertical scroll */
#define LOGPANE_INSET (4) /* left margin for start of text */
/* Externals referenced */
extern RgnHandle
gUtilRgn; /* drawing region */
struct CLogPanorama : CPanorama
{
/* local class instance data */
CLogList *itsLogList; /* the buffer for logged data */
/* local class methods */
void ILogPane (short records, CBureaucrat *aSupervisor, CWindow *anEnclosure);
void AddString (char *theString);
/* inherited methods overriden */
void Draw (Rect *theRect);
};
[LISTING FOUR]
/** CLogPanorama.c -- Methods for a CLogPanorama class object. **/
#include "CLogPanorama.h" /* defines log class */
/** ILogPanorama -- Initializes an instance of the log panorama class. **/
void CLogPanorama::ILogPane
(
short records, /* number of records in LogList */
CBureaucrat *aSupervisor, /* in-charge for this panorama */
CWindow *aWindow /* window object to place pane into */
)
{
FontInfo
fontParms; /* paramaters of selected font */
short
lineSpace, /* pixels per line */
charSpace; /* pixels per widest character */
Rect
maxWindowRect, /* maximum growth of log window */
marginRect; /* inside margins of viewable area */
CScrollPane
*theScrollPane; /* pane associated with panorama */
/* Set drawing parameters and adjust record size, if necessary. **/
aWindow->Prepare ();
TextFont (LOGPANE_FONT);
TextSize (LOGPANE_FONT_SIZE);
GetFontInfo (&fontParms);
lineSpace = fontParms.ascent+fontParms.descent+fontParms.leading;
charSpace = fontParms.widMax;
if ( ((long)records*(long)lineSpace) > (long)INT_MAX)
records = INT_MAX / lineSpace;
SetRect (&maxWindowRect, MIN_WSIZE, MIN_WSIZE,
(MAX_LOGREC_CHAR * charSpace) + SBARSIZE,
(records * lineSpace) + SBARSIZE);
aWindow->SetSizeRect (&maxWindowRect);
/* Initialize Panorama's ScrollPane, set scroll units to the defaulted
** values, and attach the Panorama to the ScrollPane. */
theScrollPane = new (CScrollPane);
theScrollPane->IScrollPane(aWindow, this, 0, 0, 0, 0,sizELASTIC, sizELASTIC,TRUE, TRUE, TRUE);
theScrollPane->FitToEnclFrame (TRUE, TRUE);
theScrollPane->SetSteps (LOGPANE_HORZ_SCROLL, LOGPANE_VERT_SCROLL);
/* Initialize Panarama to include maximum chars wide and maximum records tall,
** set the Panarama units to one char wide and one char tall. */
CPanorama::IPanorama(theScrollPane, aSupervisor, MAX_LOGREC_CHAR,
records, 0, 0, sizELASTIC, sizELASTIC);
SetScales (charSpace, lineSpace);
FitToEnclosure (TRUE, TRUE);
theScrollPane->InstallPanorama (this);
/* Create the LogList and initialize. */
itsLogList = new (CLogList);
itsLogList->ILogList (records);
}
/** Draw() -- Refreshes the visible portion of the window. **/
void CLogPanorama::Draw
(
Rect *drawRect /* portion of window to refresh */
)
{
short
firstRec, /* record number of first visible line */
hScale, /* how many pixels wide is a character? */
lastRec, /* record number of last line */
totalRec, /* total number of records in LogList */
vScale; /* how many pixels tall is a line? */
register short
currRow, /* window coordinates of current row */
rec; /* loop counter */
char
buff[MAX_LOGREC_CHAR]; /* buffer for fetching log records */
/* First, translate draw rectangle to records. **/
GetScales (&hScale, &vScale);
totalRec = (short)itsLogList->GetNumItems ();
firstRec = (drawRect->top / vScale);
if (firstRec == 0)
firstRec = 1;
lastRec = (drawRect->bottom / vScale) + 1;
if (lastRec > totalRec)
lastRec = totalRec;
/* Refresh all of visible lines. **/
Prepare ();
for (rec=firstRec, currRow=firstRec*vScale;
rec<=lastRec;
rec++, currRow+=vScale)
{
itsLogList->GetString (rec, buff);
MoveTo (LOGPANE_INSET, currRow);
DrawString (CtoPstr(buff));
}
}
/** AddString() -- Adds a new string to panorama. **/
void CLogPanorama::AddString
(
char *theString /* null-terminated string to add */
)
{
Rect
frameRect; /* interior of current frame */
short
listLimits, /* maximum the LogList will hold */
hSpan, /* the horizontal span of frame */
vSpan, /* the vertical span of frame */
hScale, /* horizontal pixels in panarama unit */
vScale; /* vertical pixels in panarama unit */
Point
topRecord, /* LogList record number of top row */
bottomRecord, /* LogList record number of bottom row */
newRecord, /* LogList record number of new row */
currPosition, /* panorama coordinates of top/left frame */
recPosition; /* panorama coordinates of new string */
/* Add the record to the LogList. */
itsLogList->AddString (theString);
/* Get coordinates of current frame and calculate tentative coordinates for
newly added record. */
GetPosition (&currPosition);
GetFrameSpan (&hSpan, &vSpan);
GetScales (&hScale, &vScale);
topRecord.v = currPosition.v + 1;
bottomRecord.v = topRecord.v + vSpan - 1;
newRecord.v = (short)itsLogList->GetNumItems ();
newRecord.h = currPosition.h;
/* Determine where we are in reference to bottom of screen and of list. **/
if (newRecord.v > (bottomRecord.v+1) )
{
/* bottom record isn't visible */
currPosition.v = newRecord.v - vSpan;
ScrollTo (currPosition, FALSE);
GetInterior (&frameRect);
Prepare ();
EraseRect (&frameRect);
}
else
{
/* bottom record is visible */
listLimits = itsLogList->GetMaxRecordCount ();
if (bottomRecord.v < listLimits)
{
/* room in list--create blank line if necessary */
if (newRecord.v == (bottomRecord.v + 1) )
{
Scroll (0, 1, TRUE);
SetRect (&frameRect, newRecord.h*hScale, (newRecord.v-1)*vScale,(newRecord.h+hSpan)*hScale, (newRecord.v)*vScale);
}
else
SetRect (&frameRect, newRecord.h*hScale, (newRecord.v-1)*vScale,
(newRecord.h+hSpan-1)*hScale, (newRecord.v)*vScale);
}
else if (bottomRecord.v > listLimits)
{
currPosition.v = newRecord.v - vSpan;
ScrollTo (currPosition, FALSE);
GetInterior (&frameRect);
Prepare ();
EraseRect (&frameRect);
}
else
{
/* bottom of pane=limit of list, so do our own scrolling */
Prepare ();
GetInterior (&frameRect);
ScrollRect (&frameRect, 0, -vScale, gUtilRgn);
SetRect (&frameRect, bottomRecord.h*hScale, (bottomRecord.v-1)*vScale,(bottomRecord.h+hSpan-1)*hScale, (bottomRecord.v)*vScale);
EraseRect (&frameRect);
}
}
Draw (&frameRect);
itsScrollPane->Calibrate();
}
[LISTING FIVE]
/** CLogList.h -- Definitions for a LogList object. **/
#define _H_CLogList
#include <CList.h> /* definitions for superclass */
#include <oops.h> /* standard OOP definitions */
#include <string.h> /* miscellaneous string definitions */
#define MAX_LOGREC_CHAR (200L) /* size of longest entry (inc NULL) */
struct CLogList : CList
{
/* internal instance data */
short maxRec; /* maximum number of records */
/* local class methods */
void ILogList (short records);
void AddString (char *theString);
void GetString (short which, char *theString);
short GetMaxRecordCount (void);
/* inherited methods overriden */
void Dispose (void);
};
[LISTING SIX]
/** CLogList.c -- Methods for a LogList object. **/
#include "CLogList.h" /* definitions for LogList class */
/** ILogList -- Initializes a LogList for the indicated number of entries. **/
void CLogList::ILogList
(
short records /* maximum number of entries */
)
{
CList::IList ();
maxRec = records;
}
/** Dispose -- Frees all records (and their handles) in the list **/
void CLogList::Dispose (void)
{
short
i; /* loop counter */
Handle
record; /* handle to list record */
while (GetNumItems() > 0)
{
record = (Handle)FirstItem();
Remove ((CObject*)record);
DisposHandle (record);
}
}
/** AddString -- Adds a string to LogList. **/
void CLogList::AddString
(
char *theString /* pointer to null-terminated string */
)
{
Handle
record; /* handle for a list entry */
if (strlen(theString)+1 < MAX_LOGREC_CHAR)
{
record = NewHandle (strlen(theString)+1);
strcpy (*record, theString);
}
else
{
record = NewHandle (MAX_LOGREC_CHAR);
strncpy (*record, theString, MAX_LOGREC_CHAR);
*record[MAX_LOGREC_CHAR-1] = NULL;
}
Append ((CObject*)record);
if (GetNumItems () > maxRec)
{
record = (Handle)FirstItem ();
Remove ((CObject*)record);
DisposHandle (record);
}
}
/** GetString -- Grabs requested entry and copies it to user's buffer. **/
void CLogList::GetString
(
short which, /* record number to return */
char *theString /* point to destination buffer */
)
{
Handle
record; /* handle for a list entry */
if ( (record=(Handle)NthItem(which)) != NULL)
strcpy (theString, *record);
else
theString[0] = 0;
}
/** GetMaxRecordCount -- Returns max.number of records available in LogList **/
short CLogList::GetMaxRecordCount (void)
{
return (maxRec);
}
[LISTING SEVEN]
/** CMyApp.c -- Demonstrates how to include the CTrace utility as part of your
** application. Functions it performs are showing/hiding the trace log window
** and setting the trace mask. To demonstrate the calls to Trace(),
** it uses the New and Open menu commands. **/
#include <CApplication.h> /* Application class definitions */
#include <CBartender.h> /* Bartender class definitions */
#include <Commands.h> /* standard command definitions */
#include "CTrace.h" /* Trace log class definitions */
/* external references */
extern CBartender *gBartender;
extern CTrace *gTrace;
/* Declare the application class */
struct CMyApp : CApplication
{
CTrace *itsTraceLog;
void IMyApp (void);
void DoCommand(long c);
void UpdateMenus(void);
};
/** ITestApp -- Initializes the application and the CTrace object. **/
void CTestApp::ITestApp(void)
{
CApplication::IApplication (4, 20480L, 2048L);
itsTraceLog = new (CTrace);
itsTraceLog->ITrace (100);
}
/** ITestApp -- Updates the Trace portion of the menus. **/
void CTestApp::UpdateMenus (void)
{
inherited::UpdateMenus ();
gBartender->EnableMenu (TRACE_MENU_ID);
gBartender->EnableCmd (TRACE_MENU_SHOW);
gBartender->EnableCmd (TRACE_MENU_MASK);
if (itsTraceLog->IsItVisible ())
gBartender->CheckMarkCmd (TRACE_MENU_SHOW, TRUE);
else
gBartender->CheckMarkCmd (TRACE_MENU_SHOW, FALSE);
}
/** ITestApp -- Processes application commands. **/
void CTestApp::DoCommand (long command)
{
int
i; /* a loop counter */
static
int addno=1; /* a counter for the demo adds */
switch (command)
{
case cmdNew : /* trace one value at mask TRACE_INFO */
gTrace->Trace (T_INFO, "one'sies add, data=%d", addno++);
break;
case cmdOpen : /* trace 32 messages, one at each mask value */
for (i=0; i<32; i++)
gTrace->Trace ((1L<<i), "Entry #%d, trace mask #%d (mask=0x%08lX)",addno++, i+1, (long)(1L<<i));
break;
case TRACE_MENU_SHOW :
itsTraceLog->ToggleTraceWindow ();
break;
case TRACE_MENU_MASK :
itsTraceLog->SetTraceMask ();
break;
default :
inherited::DoCommand (command);
}
}
/** main() -- Main routine of the demo program. **/
void main ()
{
gApplication = new (CTestApp);
((CTestApp*)gApplication)->ITestApp ();
gApplication->Run ();
gApplication->Exit ();
}