TweetFollow Us on Twitter

Debug DA Window
Volume Number:6
Issue Number:9
Column Tag:C Workshop

Code Debugging Window

By Alexander S. Colwell, Redondo Beach, CA

Note: Source code files accompanying article are located on MacTech CD-ROM or source code disks.

Introduction

A friend of mine called me the other day about developing several 4th Dimension externals and ask for suggestions to make his life easier developing software on the Macintosh. As usual, I recommended buying Inside Macintosh Volumes 1, 2, 4, and 5, several other how-to-do programming books, get all of the Macintosh Technical Notes, and buy THINK C compiler or MPW with Pascal + MacApp and/or C depending on the programming project involved. In this case, my favorite is the THINK C compiler.

However, the major problem I encountered from programmers who have worked on VAXes and IBM main-framers is the ability to perform simple debugging techniques using a print statement such as “C” printf function. Most of these programmers usually do not want to deal with the 680XX assembly code using TMON or MacBugs as a debugging tool. The THINK C or MPW SADE symbolic debugger will help alleviate debugging their applications, but will not be much help on resource code debugging. So, in response to this problem, I thought this would be a good DA for resource code debugging and an article in MacTutor magazine.

So, “What good would the “Debugger Window” DA be?”. The THINK C symbolic debugger is an excellent tool at finding tough logic problems in your code. But programming on the Macintosh is much like real-time programming. Problems don’t show up very easily while using the symbolic debugger. Most bugs occur the nth execution time, but you would not know when that may occur. For example, tough bugs usually occur only in certain combinations of procedure/function calls. Hence, simple print statements showing the flow of the module calls can be used to determine when the problem occurs or when the program crashes the Mac. Then the symbolic debugger would be used to finish the debugging process. On the other hand, a symbolic debugger does not work on resource codes such as MDEF, WDEF, XCMD, 4DEX, and device drivers to name a few.

The ideal debugging print statement should look like the printf function statement found in the “C” language. Hence, a DbgPrint procedure would be used to perform in a similar manner as fprintf function. For example,

/* 1 */

 DbgPrint(dbgHdl, “WDEF: message - %d\n”, message);

would be used to output the WDEF’s message codes in the “Round Window” DA demo as shown in Figure 1. The dbgHdl is the debugger resource handle used to communicate between the two DA’s. The remainder arguments are the format string and its arguments to generate text stream output to the “Debugger Window” DA’s display.

Figure 1. Sample “Debugger Window” with another DA

Debugger Interface

The trick in getting debugging outputs delivered to the “Debugger Window” DA is the use of the Resource Manager. By using a resource data block, it can be used as a clearing house between DA and other resource codes. The DA will fill in the necessary information into the resource data for the other resource codes to determine if it can send the debugging outputs and to which DA. (I tend to think this resource data block is like a VAX/VMS shareable image for you VAX hackers).

The other trick is really quite simple. It requires defining a new DA control message (ie. accDbgPrint = 128 control message). Here is an interesting point: there is really no reason that desk accessory control messages cannot handle other messages defined by Inside Macintosh Volume I in Desk Manager Chapter such as accEvent, accRun, accCursor, accMenu, accUndo, accCut, etc. This brings up several interesting possiblities for a DA and other applications, resource codes, and/or DAs communications.

Let’s talk about the resource data block structure and its communication between DA and others.

/* 2 */

/* Debugger error types              */
typedef enum {
 dbgNoOvrFlw,   /* No, overflow      */
 dbgTableOvrFlw,/* Table overflow    */
 dbgDataOvrFlw, /* Data buf overflow */
 dbgBufOvrFlw   /* Buf size overflow */
 } DBGERROR;
 
/* Debugger interface data structure */
typedef struct {
 short daRefNbr;
 DBGERROR bufError;
 long bufTableIdx;
 long bufNextIdx;
 long bufDataIdx;
 long bufTableSize;
 long bufDataSize;
 long **bufTable;
 char **bufData;
 } DBGINTERFACE;

The daRefNbr variable is used to point to the “Debugger Window” DA. For every opened desk accessory, it has an associated reference number that identifies it from other DA or device drivers. If the variable is ZERO then the DA is not open and cannot accept any debugging outputs.

The remaining variables are primarily used for asynchronous debugging output operation. These variables are used in a ring-buffer fashion, where the bufTable variable is table of index offsets into the bufData holding the debugging output data streams. The bufTableIdx and bufNextIdx variables are indexes into the bufTable. The bufTableIdx is used by the “Debugger Window” DA to catch-up to the bufNextIdx incremented by the other resource codes. Finally, the bufTableSize and bufDataSize are handle sizes of the bufTable and bufData handles respectively. Please refer to DebuggerDA.c and Debugger.c source code on these variables implementation.

Now, why would anybody want to do synchronous or asynchronous debugging outputs? Suppose, you are trying to debug VBL or asynchronous I/O completion in your PBCall? They require no Memory Manager ROM call operations during its interrupt level processing. Therefore, it would require buffering for the DA’s communication.

The DBGERROR enum type is used to inform the DA that there has been a buffer overflow and there will be some data loss for asynchronous debugging processing. For example, the VBL could generate so much debugging outputs and overflow the buffer before the DA has a chance to display the text data streams. If this happens alot, then one could increase the table and data buffer sizes. But, you are always constrained by the size of available memory. Nothing is perfect.

Module Descriptions

The “Debugger Window” DA debugging outputs are broken-up into two parts: synchronous or asynchronous. The DbgPrint procedure is used for synchronous operations, while the DbgBufPrint is used for asynchronous operations. The DbgPrint and DbgBufPrint arguments are similar to the “C” language fprintf function. The first argument is the debugger resource handle which is used to communicate between the DA and other resource codes. The second argument is the format string, and the third and henceforth arguments are the parameters for the format string that is used to output debugging data stream to the DA. The primary responsibility of these procedures is to check if the DA is available to accept debugging outputs, and then make the necessary operations to send the debugging outputs to the DA for display.

The DbgGetRefHdl function will retrieve the debugger resource data to be used to communicate with the “Debugger Window” DA. If it returns a non-NIL resource handle then the DA is opened. This routine must not be called at non-interrupt level. For example, it cannot be called during a VBL. So, you must pass the debugger resource handle at the end of the VBLTask data structure. Refer to Round Window.c source code.

The DbgPrint procedure calls the DA directly via the Control toolbox function. This is where the resource code makes a direct call to the DA and passing the necessary information to be displayed in the DA’s window.

The DbgBufPrint procedure moves its arguments into a data buffer and schedule a DA’s accRun action (ie. schedule DA wake-up). Normally, a DA will be invoked for periodic actions specified by its delay timer defined in the Device Control Entry data block. During the DA’s idle processing loop it will check if there is debugging outputs to be displayed.

The DbgBufPrint must know how many bytes are on the stack (ie. the arguments) to be copied into the data buffer for later processing by the DA. This problem reminds me of my college professor famous saying : “Know thy Compiler”. This commandment is critical in making the DbgBufPrint procedure to work with THINK C compiler. Upon careful examination of THINK C code generation, it always has an ADD instruction after the DbgBufPrint’s JSR instruction. Note: MPW C does not always have an ADD instruction after the DbgBufPrint’s JSR instruction. Sometime, MPW C has ADD instruction or LEA instruction but it depends on the previous procedure/function calls’ arguments. Hence, you cannot use this function with MPW C compiler.

The DbgBufPrint procedure will analyze the return address of its caller that points to the ADD instruction and decodes the number of bytes it must pop-off the stack when the DbgBufPrint returns control back to the caller. This way it knows how many bytes to copy from the stack to the data buffer for later processing by the DA. This is really a weird code. One must understand how the compiler works in order to supply the module interface equivalent to the fprintf function. Anyway, this stuff works!

Debugger Window DA Files

The DA requires the standard ANSI-A4 and MacTraps libraries as shown in Figure 2. Note: the PE/DA.p project file is not part of the standard THINK C software package purchased by your friendly software dealer. Hence, you may obtain the PE/DA.p project file from the LightSpeed CAPPS’ software package.

The PE/DA.p project file is a general purpose RAM-base text editor. I use this to perform simple text output that is not limited to 32K of memory as the TextEdit ROM routines.

Round Window DA Demo

Figure 1 shows an example how the “Debugger Window” DA is used to debug several things concurrently with the “Round Window” DA demo. The “Round Window” DA sends its debugging output statements from its event message handlers, its WDEF window message handlers, and VBL messages to the “Debugger Window” DA.

This demonstrates how to use the “Debugger Window” DA via the DbgPrint and DbgBufPrint procedures. The DA demo will start-up a VBL using a resource code containing the VBL code and use its own WDEF window definition. The VBL will call DbgBufPrint procedure to display its every module invocation during the VBL processing. (Again, VBL resource code must use asynchronous debugging outputs since it is at interrupt level.) And, the WDEF window definition will call DbgPrint procedure to display every window message code. Finally the DA demo will call DbgPrint procedure to display every event it receives.

Figure 2. “Debugger Window” DA files

Wrapping It Up

The use of the resource data as a common data block between DA’s, resource codes, and applications would have interesting possibilities other than this DA demonstration. However the future System 7.0 version would eliminate this technique using InterApplication Communications Architecture (IAC). I would be able to send the equivalent printf debugging commands via the extended Event Manager’s Program-to-Program Communication (PPC) protocol. This would greatly reduce the code overhead in the Debugger.c source file communications between the DA and the resource code. But I had written this DA since late 1988 and had been using it ever since.

/*
 *  Source   - Debugger.h
 *  Author   - Alexander S. Colwell,
 *             Copyright (C) 1988, 1989
 *  Purpose  - This is the “Debugger Window” DA
 *             include file definition.
 */

#ifndef _Debugger_
#define _Debugger_

/* Debugger resource info                             */
#define debuggerType ‘Dbgr’  /* Debugger resource type*/
#define debuggerName “\pDebugger Reference”/* Res name*/

typedef enum {               /* Debugger error types  */
    dbgNoOvrFlw,             /* No, overflow          */
    dbgTableOvrFlw,          /* Table overflow        */
    dbgDataOvrFlw,           /* Data buffer overflow  */
    dbgBufOvrFlw             /* Buffer size overflow  */
    } DBGERROR;
    
typedef enum {               /* Debugger types        */
    accDbgPrint = 128,       /* Perform “print” action*/
    accDbgDump               /* Perform “dump” action */
    } DBGTYPE;

typedef struct {             /* Debugger Interface def*/
    short   daRefNbr;        /* DA’s reference number */
    DBGERROR bufError;       /* Buffer error indicator*/
    long    bufTableIdx;     /* Buffer index          */
    long    bufNextIdx;      /* Next buffer index     */
    long    bufDataIdx;      /* Buffer data index     */
    long    bufTableSize;    /* Buffer idx table size */
    long    bufDataSize;     /* Buffer data hdl size  */
    long    **bufTable;      /* Buffer index table    */
    char    **bufData;       /* Buffer data handle    */
    } DBGINTERFACE;
typedef DBGINTERFACE    *DBGPTR;
typedef DBGPTR          *DBGHDL;
                                    
DBGHDL  DbgGetRefHdl();      /* Debugging proto-types */
void DbgPrint(/* DBGHDL dbgRefHdl, char *fmt, var-args... */);
void DbgBufPrint(/* DBGHDL dbgRefHdl, char *fmt, var-args... */);
void DbgDump(DBGHDL dbgRefHdl, char *buffer, long size);
void DbgBufDump(DBGHDL dbgRefHdl, char *buffer, long size);
long DbgStrLen(char *str);

#endif

/*
 *  Source  - DebuggerDA.c
 *  Author  - Alexander S. Colwell,
 *            Copyright (C) 1988, 1989
 *  Purpose - This is the “Debugger Window” desk
 *            accessory to simplify debugging resource
 *            codes, DA’s or applications that does not
 *            have a debugging output window. This
 *            requires System 4.1 or greater version.
 */

#include “Debugger.h”        /* DA Debugger defs      */
#include <Color.h>           /* Color Manager defs    */
#include <CType.h>           /* C Type defs           */
#include <StdArg.h>          /* Standard Argument defs*/
#include <SetUpA4.h>         /* Desk Accessory defs   */
#include <PE.h>              /* Program Edit defs     */

                             /* Misc definitions      */
#define NIL     (0L)         /* NIL pointer           */
#define abs(a)  (a<0?-a:a)   /* Absolute macro func   */
#define min(a,b) (a<b?a:b)   /* Minumim macro function*/
#define max(a,b) (a<b?b:a)   /* Maximum macro function*/

                             /* Trap definitions      */
#define SysEnvironsTrap 0xa090/* System Enviorment    */
#define UnknownTrap     0xa89f/* Unknown trap instr   */

                             /* Limit definitions     */
#define maxColumns      132  /* Maximum # of columns  */

                             /* Resource ID #’s       */
#define windID          0    /* Window ID #           */
#define infoID          0    /* Info dialog ID #      */
#define errorID         1    /* Error dialog ID #     */
#define strID           0    /* String STR ID #       */
#define errID           1    /* Error STR ID #        */
#define optionsID       0    /* Options ID #          */
#define debuggerID      0    /* Debugger ID #         */

typedef enum {               /* Menu commands         */
    Info = 1,                /* On-line information   */
    NullItem2,
    StartOutput,             /* Start/Stop output     */
    Quit                     /* Quit from DA          */
    } MENU;
    
typedef enum {               /* String ID #’s         */
    itmStartOutput = 1,      /* “Start Output” item   */
    itmStopOutput,           /* “Stop Output” item    */
    bufTableOvrFlw,          /* Table overflow        */
    bufDataOvrFlw,           /* Data buffer overflow  */
    bufBufOvrFlw             /* Buffer size overflow  */
    } STRID;
                             /* Resource types        */
#define optionType ‘Opts’    /* Option definition type*/

typedef enum {               /* Error messages        */
    errFailOpenDA = 1,       /* Fail to open DA       */
    errNoGlobals,            /* Fail to alloc globals */
    errLowMemory,            /* Low memory error      */
    errOldSystem,            /* Old System file       */
    errLisaClone,            /* Lisa clone Macintosh  */
    errOriginalMac           /* Original 128/512 Mac! */
    } ERROR;
    
typedef struct {             /* Options definitions   */
    short   maxTextSize;     /* Maximum text size     */
    short   fontFamily;      /* Font ID family        */
    short   fontSize;        /* Font size             */
    short   spacesPerTab;    /* # of spaces per tab   */
    long    bufTableSize;    /* Buffer table size     */
    long    bufDataSize;     /* Buffer data size      */
    } OPT;
typedef OPT     *OPTPTR;
typedef OPTPTR  *OPTHDL;

                             /* Global variables      */
short           alreadyOpen = FALSE;/* DA open flag   */
SysEnvRec       sysEnv;      /* System enviroment     */
DCtlPtr         dce;         /* Device control entry  */
WindowPtr       wp = NIL;    /* My window pointer     */
Rect            originalRect;/* Original rect area    */
PEHandle        peHdl = NIL; /* PE handle             */
short           active = FALSE;/* Active flag         */
ControlHandle   hScrollBar = NIL;/* Horz scroll bar   */
ControlHandle   vScrollBar = NIL;/* Vert scroll bar   */
DBGHDL          dbgHdl = NIL;/* Debugger handle       */
OPTHDL          optHdl = NIL;/* Options handle        */
short           cursorMode = FALSE;/* Cursor mode     */
MenuHandle      menu = NIL;  /* Menu handle           */
short           menuID = 0;  /* Menu ID #             */
long            **bufTable = NIL;/* Buffer idx tbl hdl*/
char            **bufData = NIL;/* Buffer data handle */
short           outputEnable = TRUE;/* Output flag    */
char            PrintOutputBuf[1024];/* Print buffer  */

pascal void DoTextScroll();  /* Define forwared refa  */
pascal void DoClickScroll();
pascal void DoHighLite();
void        DoPrintChar();
DialogTHndl DoDlgCenter();

main(p,d,n)
 cntrlParam  *p;             /* Parameter block       */
 DCtlPtr     d;              /* Device control entry  */
 short       n;              /* Entry point selector  */
 {
  WindowPtr   savePort;      /* Save cur window port  */
  short       saveResFile;   /* Save cur resource file*/

  if (d->dCtlStorage == 0) { /* Check if got globals! */
   if (n == 0) {             /* Check if “Open”ing    */
    DoError(errNoGlobals);   /* Opps, fail get globals*/
    CloseDriver(d->dCtlRefNum);/* Close the DA        */
   }
  }

  else {                     /* Got globals then cont */
   RememberA4();             /* Remember A4 register  */
   GetPort(&savePort);       /* Get cur window port   */

   if (wp)                   /* Check if ptr valid    */
    SetPort(wp);             /* Set port to my window */
    dce = d;                 /* Save DCE ptr          */
    dce->dCtlFlags &= ~dCtlEnable;/*Set not re-entrant*/

    switch(n) {              /* Handle request:       */
     case 0:                 /*      “Open”           */
      DoOpen(); break;    
     case 2:                 /*      “Control”        */
      DoControl(p->csCode,p->csParam); break; 
     case 4:                 /*      “Close”          */
      DoClose(); break;
    }

    dce->dCtlFlags |= dCtlEnable;/* Enable it again   */
    SetPort(savePort);       /* OK, let’s restore it  */
   }
  return(0);                 /* Return default success*/
 }

DoOpen()
 {
  short           rom;       /* Working ROM id        */
  short           machine;   /* Working Mac id        */
  Rect            wRect;     /* Working wind rect area*/
  Point           pt;        /* Working point         */
  register PEPtr  pePtr;     /* Working edit pointer  */
  DBGPTR          dbgPtr;    /* Working debugger ptr  */
  register short  canDoIt;   /* Working can do it flag*/
  register short  errCode = errFailOpenDA;/*Error code*/
        
  dce->dCtlFlags |= dNeedLock|dNeedGoodBye;/*Set flags*/
  if (wp)                    /* Check if there window */
   if (wp != FrontWindow())  /* Check if not in front */
    SelectWindow(wp);        /* Bring our window front*/
            
  if (!alreadyOpen) {        /* Check if require inits*/
   Environs(&rom,&machine);  /* Get Mac’s evniroment  */
   if (machine == macXLMachine) {/* Check if “Lisa”   */
    canDoIt = FALSE;         /* It’s a “Lisa” computer*/
    errCode = errLisaClone;  /* Set error message     */
   }
   else if (rom >= 0x0078)   /* It’s Mac II           */
    canDoIt = TRUE;          /* It’s Mac II computer  */
   else if (rom >= 0x0076)   /* It’s Mac SE           */
    canDoIt = TRUE;          /* It’s Mac SE computer  */
   else if (rom >= 0x0075) { /* it’s 128K rom         */
    if (MemTop > (char *)(1024L * 512L))/* Mac 512KE? */
     canDoIt = TRUE;         /* It’s Mac 512K Enhanced*/
    else                     /* Must be Mac Plus      */
     canDoIt = TRUE;         /* Its Mac Plus computer */
   }
   else  if (rom >= 0x0069){ /* It’s 64K rom, it’s old*/
    canDoIt = FALSE;         /* It’s original Mac!    */
    errCode = errOriginalMac;/* Set error message     */
   }
            
   if (canDoIt) {            /* OK, we can do it!     */
                             /* Check if it’s valid   */
    if ((long)NGetTrapAddress(SysEnvironsTrap,OSTrap) != 
        (long)NGetTrapAddress(UnknownTrap,ToolTrap)) {
     SysEnvirons(1,&sysEnv); /* Get system enviroment */
     if (sysEnv.systemVersion >= 0x0410) {/* Latest?  */
      wp = GetNewWindow(GetResourceID(windID),NIL,-1L);
      if (wp) {              /* Check if got window   */
       ShowWindow(wp);       /* OK, let’s show it     */
       SetPort(wp);          /* Set port to our window*/
       alreadyOpen = TRUE;   /* Set open DA indicator */
                            
                             /*Save window association*/
       ((WindowPeek)wp)->windowKind = dce->dCtlRefNum;
       dce->dCtlWindow = wp;/* Tell device where I am */

       originalRect = wp->portRect;/* Save orig area  */
       LocalToGlobal(&originalRect.top);
       LocalToGlobal(&originalRect.bottom);

                             /* Check if create scroll*/
       wRect.left = wp->portRect.left - 1;
       wRect.top = wp->portRect.bottom - 15;
       wRect.right = wp->portRect.right - 14;
       wRect.bottom = wp->portRect.bottom + 1;
       hScrollBar = NewControl(wp,&wRect,””,FALSE,
                               0,0,0,scrollBarProc,0L);
                                
                             /* Check if create scroll*/
       wRect.left = wp->portRect.right - 15;
       wRect.top = wp->portRect.top - 1;
       wRect.right = wp->portRect.right + 1;
       wRect.bottom = wp->portRect.bottom - 14;
       vScrollBar = NewControl(wp,&wRect,””,FALSE,
                               0,0,0,scrollBarProc,0L);
                                
                             /* Get options defs      */
       optHdl = (OPTHDL)(GetResource(optionType,
                             GetResourceID(optionsID)));
                                                     
                             /* Get debugger defs     */
       dbgHdl = (DBGHDL)(GetResource(debuggerType,
                            GetResourceID(debuggerID)));
                                                 
       TextFace(0);          /* Set “Plain” style font*/
       if (optHdl) {         /*Check if got option hdl*/
        TextSize((*optHdl)->fontSize);
        TextFont((*optHdl)->fontFamily);
       }
       else {                /* Nope, set to default  */
        TextSize(9);
         TextFont(monaco);
       }

       wRect.left = wp->portRect.left;/* Set edit view*/
       wRect.top = wp->portRect.top + 5;
       wRect.right = wp->portRect.right - 15;
       wRect.bottom = wp->portRect.bottom - 15;

       if (peHdl = PENew(&wRect)) {/* Check if got it */
        pePtr = *peHdl;      /* Set edit pointer      */
                             /* Set auto scroll hook  */
        pePtr->clikLoop = (ProcPtr)DoClickScroll;
        if (sysEnv.hasColorQD)/* Check if has color   */
         pePtr->highHook = (ProcPtr)DoHighLite;
        pePtr->viewOrgH = -5;/* Set horizontal offset */
        pePtr->viewOrgV = 0; /* Set vertical offset   */
                             /*Set # of spaces per tab*/
        (*peHdl)->tabWidth = CharWidth(‘ ‘) * 
                                (*optHdl)->spacesPerTab;
        DoRestoreClippings();/* Restore text clipping */
       }

       menuID = GetResourceID(menuID);/* Get menu ID  */
       if (menu = GetMenu(menuID)) {/* Check if got it*/
        (**menu).menuID = menuID;/* Reset default ID  */
        dce->dCtlMenu = menuID;/* Set device menu ID  */
        if (!dbgHdl)         /*Check if fail to get it*/
         DisableItem(menu,StartOutput);/* Disable it  */
       }
       else                  /* Fail to get menu hdl  */
        menuID = 0;          /* Reset menu ID #       */
                                
       if (optHdl) {         /*Check if got option hdl*/
                             /* Allocate buffer table */
        bufTable = (long **)(NewHandle(
                       (long)((*optHdl)->bufTableSize) *
                       (long)(sizeof(long))));
                
        bufData = NewHandle(/* Allocate buffer data   */
                        (long)((*optHdl)->bufDataSize) *
                        (long)(sizeof(char)));
       }
                            /* Check if memory low    */
       if (!hScrollBar || !vScrollBar || !peHdl || 
           ! menu || !optHdl || !dbgHdl || 
           !bufTable || !bufData)
           DoError(errLowMemory);
                                
       if (dbgHdl) {         /* Check if got resource */
        SetHandleSize(dbgHdl,/* Make sure right size  */
 (long)(sizeof(DBGINTERFACE)));
        dbgPtr = *dbgHdl;    /* Set debugger pointer  */
        dbgPtr->bufError = dbgNoOvrFlw;/* Init buffer */
        dbgPtr->bufTableIdx = 0;
        dbgPtr->bufNextIdx = 0;
        dbgPtr->bufDataIdx = 0;
        dbgPtr->bufTableSize = 0L;
        dbgPtr->bufTable = NIL;
        dbgPtr->bufData = NIL;
        dbgPtr->bufDataSize = 0L;
        dbgPtr->daRefNbr = 0;
                             /* Check if tables valid */
        if (optHdl && bufTable && bufData) {
         dbgPtr->bufTableSize = (*optHdl)->bufTableSize;
         dbgPtr->bufTable = bufTable;
         dbgPtr->bufData = bufData;
         dbgPtr->bufDataSize = (*optHdl)->bufDataSize;
         dbgPtr->daRefNbr = dce->dCtlRefNum;
        }
        ChangedResource(dbgHdl);/* Update it          */
        WriteResource(dbgHdl);
       }
      }
     }
     else                    /* Require newer system  */
      errCode = errOldSystem;
    }
    else                     /* Require newer system  */
     errCode = errOldSystem;
   }
   if (!wp) {                /* Check if fail to open */
    DoError(errCode);        /* Fail to open DA       */
    DoQuit();                /* Let’s get out now!    */
   }
  }
 }

DoClose()
 {
  register Handle hdl;       /* Working handle        */
  Rect            curRect;   /* Working cur rect area */
  register Rect   **wRect;   /* Working window rect   */
        
  if (dbgHdl) {              /* Check if have handle  */
   (*dbgHdl)->daRefNbr = 0;  /* OK, let’s clear these */
   (*dbgHdl)->bufTable = NIL;
   (*dbgHdl)->bufData = NIL;
   ChangedResource(dbgHdl);  /* Update resource, too  */
   WriteResource(dbgHdl);
   dbgHdl = NIL;             /* Clear handle, but dont*/
                             /* release it since other*/
                             /* DA’s and etc will be  */
                             /* using it, too.        */
  }

  if (bufTable)              /* Check if it’s valid   */
   DisposHandle(bufTable);   /* Release it to mem mgr */
  bufTable = NIL;            /* Invalidate it         */
        
  if (bufData)               /* Check if it’s valid   */
   DisposHandle(bufData);    /* Release it to mem mgr */
  bufData = NIL;             /* Invalidate it         */
        
  if (optHdl)                /* Check if have option  */
   ReleaseResource(optHdl);  /* Release it            */
  optHdl = NIL;              /* Invalidate it too     */
        
  if (menu) {                /* Check if have menu hdl*/
   DeleteMenu(menuID);       /* Delete from menu bar  */
   DrawMenuBar();
   DisposeMenu(menu);        /* Release menu handle   */
   menu = NIL;               /* Invalidate menu handle*/
   dce->dCtlMenu = 0;        /* Clear-out menu ID #   */
  }
  
  if (peHdl) {                /* Check if it’s valid  */
   PEDispose(peHdl);          /* Release it now       */
   peHdl = NIL;               /* Invalidate edit hdl  */
  }
        
  if (wp) {                   /* Check if window valid*/
   curRect = wp->portRect;    /* Translate to global  */
   LocalToGlobal(&curRect.top);
   LocalToGlobal(&curRect.bottom);
            
   DisposeWindow(wp);         /* Delete the window now*/
   wp = NIL;                  /* Reset it now         */
   if (!EqualRect(&curRect,&originalRect)) {/*Changed?*/
        
                              /* Check if got wnd hdl */
    if (wRect = ((Rect **)GetResource(‘WIND’,
                             GetResourceID(windID)))) {
     **wRect = curRect;       /* Save new  location   */
     ChangedResource(wRect);  /* Mark it changed      */
     WriteResource(wRect);    /* Write resource now   */
    }
   }
  }
        
                             /* Get ‘STR#’ resource   */
  if (hdl = GetResource(‘STR#’,GetResourceID(strID)))
   ReleaseResource(hdl);     /* OK, release it now    */
  if (hdl = GetResource(‘STR#’,GetResourceID(errID)))
   ReleaseResource(hdl);     /* OK, release it now    */
            
  InitCursor();              /* Restore arrow cursor  */
  alreadyOpen = FALSE;       /* Reset it              */
 }

DoControl(code,parm)
 short code;                 /* Control command code  */
 short *parm;                /* “csParam” list pointer*/
 {
  switch(code) {             /* Handle request:       */
   case accEvent:            /*      “Event”          */
    DoEvent(*((EventRecord **)parm)); break;
   case accMenu:             /*      “Menu”           */
    DoMenu(*(parm + 1)); break;
   case accRun:              /*      “Run”            */
    DoIdle(); break;
   case accCopy:             /*      “Copy”           */
    DoCopy(); break;
   case accClear:            /*      “Clear”          */
    DoClear(); break;
   case goodBye:             /*      “GoodBye”        */
    DoClose(); break;
   case accDbgPrint:         /*      “DbgPrint”       */
    DoDbgPrint(((long *)(parm))); break;
   case accDbgDump:          /*      “DbgDump”        */
    DoPrintDump(*((long *)(parm)),
                *(((long *)(parm))+1)); break;
  }
 }

DoEvent(e)
 register EventRecord *e;    /* Event Record pointer  */
 {
  switch(e->what) {          /* Handle request:       */
   case updateEvt:           /*      “Update”         */
    DoUpdate(); break;
   case mouseDown:           /*      “Mouse Down”     */
    DoMouse(e->where,e->modifiers); break;
   case activateEvt:         /*      “Activate”       */
    DoActivate((Boolean)(e->modifiers & activeFlag));
    break;
   case keyDown:             /*      “Key Down”       */
   case autoKey:             /*      “Auto-Key Down”  */
                             /* Handle the input key  */
    DoKey((char)(e->message & charCodeMask),
          (char)((e->message & keyCodeMask) >> 8L),
          e->modifiers);
  }
 }

DoUpdate()
 {
  BeginUpdate(wp);           /* Start update processng*/
  ClipRect(&wp->portRect);   /* Reset clipping        */
  EraseRect(&wp->portRect);  /* Erase part of screen  */
  DrawGrowIcon(wp);          /* Draw the grow icon    */
  DrawControls(wp);          /* Draw the controls     */
  if (peHdl) {               /* Check if has edit hdl */
   DoRestoreClippings();     /* Restore clippgings    */
   PEUpdate(peHdl);          /* OK, let’s update it   */
  }
  EndUpdate(wp);             /* Wrapup update         */
}
    
DoMouse(p,modifiers)
 Point   p;                  /* Mouse point position  */
 short   modifiers;          /* Mouse’s modifiers     */
 {
  register long   i;         /* Working index         */
  Rect            wRect;     /* Working window rect   */
  register long   wGrow;     /* Working grow size     */
  ProcPtr         wDef;      /* Working window proc   */
    
                             /* Get window proc def   */
  wDef = (ProcPtr)*((WindowPeek)wp)->windowDefProc;

                             /* Check if in “Content” */
  if (CallPascalL(8,wp,(int)wHit,p,wDef) == wInContent)
   DoContent(p,modifiers);
        
                             /* Check if in “Grow”    */
  else if (CallPascalL(8,wp,(int)wHit,p,wDef) ==
           wInGrow) {
   SetRect(&wRect,100,100,32767,32767);/*Define limits*/
   wGrow = GrowWindow(wp,p,&wRect);/* OK, grow it now */
   if (wGrow) {              /* Check if got new size */
                             /* Reset new size        */
    SizeWindow(wp,LoWord(wGrow),HiWord(wGrow),TRUE);
    DoResizeScrollBar();     /* Resize the scroll bar */
    InvalRect(&wp->portRect);/* Invalidate everything */
    DoAdjustScrollBar();     /* Adjust scroll bar     */
   }   
  }
            
                             /* Check if in “Zoom In” */
  else if (CallPascalL(8,wp,(int)wHit,p,wDef) == 
           wInZoomIn) {
   ZoomWindow(wp,inZoomIn,TRUE);/* Zoom it in         */
   DoResizeScrollBar();      /* Resize the scroll bar */
   DoAdjustScrollBar();      /* Adjust scroll bar     */
  }
                             /* Check if in “Zoom Out”*/
  else if (CallPascalL(8,wp,(int)wHit,p,wDef) ==
           wInZoomOut) {
   ZoomWindow(wp,inZoomOut,TRUE);/* Zoom it out       */
   DoResizeScrollBar();      /* Resize the scroll bar */
   DoAdjustScrollBar();      /* Adjust scroll bar     */
  }
 }
    
DoActivate(activate)
 short   activate;           /* Activate flag         */
 {
  Rect    wRect;             /* Working window rect   */
        
                             /* Set vertical ctrl area*/
  wRect.left = wp->portRect.right - 14;
  wRect.top = wp->portRect.top - 1;
  wRect.right = wp->portRect.right + 1;
  wRect.bottom = wp->portRect.bottom - 16;
        
  ClipRect(&wRect);          /* Reset clippings       */
  if (activate) {            /* Check if activating   */
   dce->dCtlFlags |= dNeedTime;/* Allow periodic runs */
   dce->dCtlDelay = 15;      /* Reset delay timer     */
   if (peHdl) {              /* Check if got the text */
    active = TRUE;           /* Activate text editing */
    PEActivate(peHdl);       /* Activate the text     */
   }
   DoActivateScrollBars();   /* Activate scroll bars  */
   if (menu) {               /* Check if menu is valid*/
    InsertMenu(menu,0);      /* Insert into menu bar  */
    DrawMenuBar();
    dce->dCtlMenu = menuID;  /* Reset menu ID #       */
   }
  }
  
  else {                     /* Nope, deactivating    */
   if (dbgHdl) {             /* Check if it’s valid   */
                             /* Check if there outputs*/ 
    if ((*dbgHdl)->bufTableIdx !=
     (*dbgHdl)->bufNextIdx) {
     dce->dCtlFlags |= dNeedTime;/* Allow periodic run*/
     dce->dCtlDelay = 15;    /* Reset delay timer     */
    }
    else                     /* No, buffer outputs    */
     dce->dCtlFlags &= ~dNeedTime;/* Turn off runs    */
   }
   else                      /* Nope, use defaults    */
    dce->dCtlFlags &= ~dNeedTime;/* Turn off runs     */
   active = FALSE;           /* Deactivate text edit  */
   if (peHdl)                /* Check if got the text */
    PEDeactivate(peHdl);     /* Deactivate the text   */
   DoDeActivateScrollBars(); /* Deactivate scroll bars*/
   InitCursor();             /* Restore arrow cursor  */
   cursorMode = FALSE;       /* Reset cursor mode     */
   if (menu) {               /* Check if menu is valid*/
    DeleteMenu(menuID);      /* Delete from menu bar  */
    DrawMenuBar();
    dce->dCtlMenu = 0;       /* Clear-out menu ID #   */
   }
  }
 }
    
DoActivateScrollBars()
 {
  Rect    wRect;             /* Working rect area     */
        
  ClipRect(&wp->portRect);   /* Set clippings         */
  if (hScrollBar)            /* Check if have horz bar*/
   ShowControl(hScrollBar);  /* Show the scroll bar   */
  if (vScrollBar)            /* Check if have vert bar*/
   ShowControl(vScrollBar);  /* Show the scroll bar   */
                             /* Invalidate drag icon  */
  wRect.top = wp->portRect.bottom - 14;
  wRect.bottom = wp->portRect.bottom;
  wRect.left = wp->portRect.right - 14;
  wRect.right = wp->portRect.right;
  InvalRect(&wRect);
  DoRestoreClippings();      /* Restore clippings     */
}
    
DoDeActivateScrollBars()
 {
  Rect    wRect;             /* Working rect area     */
  ClipRect(&wp->portRect);   /* Set clippings         */
  if (hScrollBar)            /* Check if have horz bar*/
   HideControl(hScrollBar);  /* Hide the scroll bar   */
  if (vScrollBar)            /* Check if have vert bar*/
   HideControl(vScrollBar);  /* Hide the scroll bar   */
                             /* Clear drag icon       */
  wRect.top = wp->portRect.bottom - 14;
  wRect.bottom = wp->portRect.bottom;
  wRect.left = wp->portRect.right - 14;
  wRect.right = wp->portRect.right;
  EraseRect(&wRect);
  DoUpdate();                /* Update the DA window  */
  DoRestoreClippings();      /* Restore clippings     */
 }   

DoIdle()
 {
  register short  id;        /* Working string ID #   */
  register DBGPTR dbgPtr;    /* Working debugger ptr  */
  register char   *s,*f;     /* Working string ptrs   */
  Str255          wStr;      /* Working string        */
  Point           p;         /* Working mouse location*/
    
  if (active) {              /* Check if it activated */
   GetMouse(&p);             /* Get mouse location    */
   if (peHdl)  {             /* Check if got the text */
    PEIdle(peHdl);           /* Do cursor blinking    */
    if (PtInRect(p,&(*peHdl)->viewRect)){/*Within view*/
     if (!cursorMode) {      /* Check if not I-Beam   */
      SetCursor(*GetCursor(iBeamCursor));/* Reset curs*/
      cursorMode = TRUE;     /* Reset cursor mode     */
     }
    }
    else {                   /* Reset to arrow cursor */
     if (cursorMode) {       /* Check if using I-Beam */
      InitCursor();          /* Restore arrow cursor  */
      cursorMode = FALSE;    /* Reset cursor mode     */
     }
    }
   }
  }
  if (dbgHdl) {              /* Check if handle valid */
   if ((*dbgHdl)->bufError) {/* Check for buf overflow*/
    switch((*dbgHdl)->bufError) {/* Get buf err ID #  */
     case bufTableOvrFlw:
      id = dbgTableOvrFlw; break;
     case bufDataOvrFlw:
      id = dbgDataOvrFlw; break;
     case bufBufOvrFlw:
      id = dbgBufOvrFlw;
    }
                             /* Let user know about it*/
    GetIndString(wStr,GetResourceID(strID),id);
    DoPrintLine(“%p\n”,wStr);
    (*dbgHdl)->bufError = dbgNoOvrFlw;/* Reset flag   */
   }
   dbgPtr = *dbgHdl;         /* Set debugger pointer  */
                             /* Check if has changed  */
   if (dbgPtr->bufTableIdx != dbgPtr->bufNextIdx) {
                             /* Bump to next index    */
    dbgPtr->bufTableIdx = (dbgPtr->bufTableIdx + 1L) %
                          dbgPtr->bufTableSize;
    HLock(dbgPtr->bufData);  /*Lock it down for output*/
                             /* Set switch code ptr   */
    s = &(*dbgPtr->bufData)[(*dbgPtr->bufTable)
           [dbgPtr->bufTableIdx]];
    f = s + 2L;              /*Set format string addr */
    switch((unsigned char)(*s)){/* Process input cmd  */
     case accDbgPrint:       /* Do LSC debugging line */
      DoDbgPrintSetUp(f); break;
     case accDbgDump:        /* Do debugging dump     */
      DoPrintDump(((long *)(f + sizeof(long))),
                  *((long *)(f)));
    }
    dbgPtr = *dbgHdl;        /* Reset debugger pointer*/
                             /* Check if it’s finished*/
    if (dbgPtr->bufTableIdx == dbgPtr->bufNextIdx) {
     if (!active)            /* Check if not active   */
      dce->dCtlFlags &= ~dNeedTime;/* Turn it off     */
     else                    /* Restore delay timer   */
      dce->dCtlDelay = 15;
    }
    HUnlock(dbgPtr->bufData);/* OK, let’s unlock it   */
   }
  }
 }
    
DoKey(c,code,modifiers)
 char    c;                  /* Input character       */
 char    code;               /* Input code            */
 short   modifiers;          /* Input modifiers       */
 {
  register short  i,j;       /* Working indexes       */
  register short  adjustIt = TRUE;/* adjust view      */
  register short  item = 0;  /* Working item #        */
  char            cmdChar[2];/* Working command char  */
  register ControlHandle ctrlHdl;/* Working ctrl hdl  */
  static short cnt = 0;       /* Debugging counter    */
        
  if (active) {               /* Check if activated   */
   if (modifiers & cmdKey) {  /* Check if key command */
    switch(c) {               /* Process key command  */
     case ‘c’:                /* “Copy” command       */
     case ‘C’:
      DoCopy(); c = 0; break;
     case ‘k’:                /* “Clear” command      */
     case ‘K’:
      DoClear(); c = 0;
    }
    if (c) {                  /* Check if should cont */
     if (menu) {              /* Check if got menu hdl*/
                              /* Search for item cmd  */
      for(i = 1, j = CountMItems(menu); i <= j; i++) {
       GetItemCmd(menu,i,cmdChar);/* Get item’s cmd   */
       if (cmdChar[1] == ‘?’) /* Check if ‘?’ char    */
        cmdChar[1] = ‘/’;     /* Translate lower case */
                              /* Check if this is it  */
       if (!IUMagIDString(&c,&cmdChar[1],1,1)) {
        item = i;             /* Yup, save item #     */
        i += j;               /* Break-out of loop    */
       }
      }
      if (item) {             /* Check if got our guy */
       HiliteMenu(menuID);    /* OK, let’s highlite it*/
       DoMenu(item);          /* Let’s do it          */
       HiliteMenu(0);         /* Unhighlite the menu  */
      }
      else                    /* Opps, wrong menu     */
       SysBeep(1);            /* Let um know about it */
     }
     else                     /* Opps, no menu handle */
      SysBeep(1);             /* Let um know about it */
    }
   }
   else if (peHdl) {          /* Check if got the text*/
                              /* Check if has ext key */
    if (sysEnv.keyBoardType == envAExtendKbd || 
        sysEnv.keyBoardType == envStandADBKbd) {
     if (modifiers & optionKey)/* Check if want horz  */
      ctrlHdl = hScrollBar;   /* Set horz scroll bar  */
     else                     /* Nope, use vert bar   */
      ctrlHdl = vScrollBar;
     switch(code) {           /* Check if F1-F4 keys  */
      case 0x63:              /* F3 “Copy” key        */
       DoCopy(); break;
      case 0x73:              /* Home key             */
       if (ctrlHdl) {         /* Check if has ctrl hdl*/
        if (i = GetCtlValue(ctrlHdl)) {/* Can scroll ?*/
         ClipRect(&wp->portRect);/* Reset clippings   */
         SetCtlValue(ctrlHdl,0);/* Set new value      */
         DoRestoreClippings();/* Restore clippings    */
         if (ctrlHdl == vScrollBar)/* Check if vert   */
          PEScroll(0,(long)(i),peHdl);/* Scroll vert  */
         else                 /* Nope, horz scroll    */
          PEScroll(i,0L,peHdl);/* Scroll horz dir.    */
        }
       }
       adjustIt = FALSE;      /* Don’t adjust view    */
       break;
      case 0x77:              /* End key              */
       if (ctrlHdl) {         /* Check if has ctrl hdl*/
                              /* Check if can scroll  */
        if ((i = GetCtlValue(ctrlHdl)) !=
            (j = GetCtlMax(ctrlHdl))) {
         ClipRect(&wp->portRect);/* Reset clippings   */
         SetCtlValue(ctrlHdl,j);/* Reset new value    */
         DoRestoreClippings();/* Restore clippings    */
         if (ctrlHdl == vScrollBar)/* Check if vert   */
          PEScroll(0,(long)(i - j),peHdl);
         else                 /* Scroll horz dir.     */
          PEScroll(i - j,0L,peHdl);
        }
       }
       adjustIt = FALSE;      /* Don’t adjust view    */
       break;
      case 0x74:              /* Page up key          */
       if (ctrlHdl) {         /* Check if has ctrl hdl*/
        DoTextScroll(ctrlHdl,inPageUp);/* Scroll up   */
       }
       adjustIt = FALSE;      /* Don’t adjust view    */
       break;
      case 0x79:              /* Page down key        */
       if (ctrlHdl) {         /* Check if has ctrl hdl*/
        DoTextScroll(ctrlHdl,inPageDown);/*Scroll down*/
       }
       adjustIt = FALSE;      /* Don’t adjust view    */
       break;
     }
    }
    if (adjustIt)             /* Should adjust it ?   */
     DoAdjustScrollBar();     /* Adjust the scroll bar*/
   }
  }
 }

DoMenu(item)
 short   item;               /* Item code             */
 {
  switch(item) {             /* Process menu command  */
   case Info:                /* On-line information   */
    DoInfo(); break;
   case StartOutput:         /* Start/Stop output     */
    DoStartStopOutput(); break;
   case Quit:                /* Quit from the DA      */
    DoQuit(); break;
  }
 }
    
DoContent(p,modifiers)
 Point    p;                 /* Mouse down point      */
 short   modifiers;          /* Mouse’s modifiers     */
 {
  long            i;         /* Working index         */
  register short  selectIt = FALSE;/* Selection flag  */
  Point           pt;        /* Working point         */
        
  pt = p;                    /* Convert to local coord*/
  GlobalToLocal(&pt);
        
  if (!DoScrollBar(pt))      /* Check if in scroll bar*/
   DoTextClick(pt,modifiers);/* Do text clicking      */
}
    
DoQuit()
 {
  SysBeep(1);                /* Beep the user now!    */
  CloseDriver(dce->dCtlRefNum);/* OK, let’s close DA  */
 }
    
DoCopy()
 {
  register long   len;       /* Working text length   */
  
  if (active) {              /* Check if it activated */
   if (peHdl) {              /* Check if have edit hdl*/
                             /* Check if any selection*/
    if (len = (*peHdl)->selEnd - (*peHdl)->selStart) {
     ZeroScrap();            /* Reset the scrap file  */
     HLock((*peHdl)->hText); /* Lock the text down    */
                             /* Transfer to clipboard */
     PutScrap(len,’TEXT’,*(*peHdl)->hText + 
                         (*peHdl)->selStart);
     HUnlock((*peHdl)->hText);/* OK, safe to unlock it*/
    }
   }
  }
 }

DoClear()
 {
  register Handle txtHdl;    /* Working text handle   */
  Rect            wRect;     /* Working rect area     */
        
  if (peHdl) {               /* Check if have edit hdl*/
   if (txtHdl = NewHandle(0L)) {/* Check if got hdl   */
    ClipRect(&wp->portRect); /* Reset clipping        */
    if (hScrollBar) {        /* Check if have scroll  */
     (*hScrollBar)->contrlMax = 0;/* Reset values     */
     SetCtlValue(hScrollBar,0);
    }
    if (vScrollBar) {        /* Check if have scroll  */
     (*vScrollBar)->contrlMax = 0;/* Reset values     */
     SetCtlValue(vScrollBar,0);
    }
    DoRestoreClippings();    /* Restore clippings     */
    DisposHandle((*peHdl)->hText);/* Release old text */
    (*peHdl)->hText = NIL;   /* Reset it to zip!      */
    PESetHText(txtHdl,peHdl);/* Set new text handle   */
    wRect = wp->portRect;    /* Clear the display     */
    wRect.right -= 15; wRect.bottom -= 15;
    InvalRect(&wp->portRect);
   }
  }
 }

DoInfo()
 {
  register DialogPtr  dPtr;  /* Working dialog pointer*/
  short               dItem; /* Working dialogue item */
  register short      next = TRUE;/* Working next flag*/
        
  if (dbgHdl) {              /* Check if got ref hdl  */
   (*dbgHdl)->daRefNbr = 0;  /* Clear debugger ref hdl*/
   ChangedResource(dbgHdl);
   WriteResource(dbgHdl);
  }
  DoDeActivateScrollBars();  /* Deactivate scroll bars*/
  DoDlgCenter(‘DLOG’,infoID);/* Center the dialog now */
                             /* Open dialog           */
  dPtr = GetNewDialog(GetResourceID(infoID),NIL,-1L);
  if (dPtr) {                /* Check if open dialog  */
   InitCursor();             /* Restore arrow cursor  */
   cursorMode = FALSE;       /* Reset cursor mode     */
   SetPort(dPtr);            /* Set to my window port */
   while(next) {             /* Process next event    */
    ModalDialog(NIL,&dItem); /* Get modal event       */
    if (dItem == OK)         /* Check if time to quit */
     next = FALSE;           /* Let’s break-out !     */
   }
   SetPort(wp);              /* Restore DA window port*/
   DisposDialog(dPtr);       /* Kill dialogue window  */
  }
  DoActivateScrollBars();    /* Activate scroll bars  */
  if (dbgHdl) {              /* Check if got ref hdl  */
   if (outputEnable) {       /* Check if enabled      */
                             /* Restore ref handle    */
    (*dbgHdl)->daRefNbr = dce->dCtlRefNum;
    ChangedResource(dbgHdl);
    WriteResource(dbgHdl);
   }
  }
 }

DoStartStopOutput()
 {
  Str255      wStr;          /* Working item string   */
        
  if (dbgHdl) {              /* Check if has ref hdl  */
   if (outputEnable) {       /* Check if to turn off  */
    outputEnable = FALSE;    /* Disable output display*/
    (*dbgHdl)->daRefNbr = 0;
    GetIndString(wStr,GetResourceID(strID),
                 itmStartOutput);
   }
   else {                    /* Nope, start-up output */
    outputEnable = TRUE;     /* Enable output display */
    (*dbgHdl)->daRefNbr = dce->dCtlRefNum;
    GetIndString(wStr,GetResourceID(strID),itmStopOutput);
   }
   SetItem(menu,StartOutput,wStr);/* Reset item string*/
  }
 }

DoError(errMsg)
 ERROR   errMsg;             /* Error message         */
 {
  Str255  wStr;              /* Working string        */
        
  if (dbgHdl) {              /* Check if got ref hdl  */
   (*dbgHdl)->daRefNbr = 0;  /* Clear debugger ref hdl*/
   ChangedResource(dbgHdl);
   WriteResource(dbgHdl);
  }
                             /* Get error message     */
  GetIndString(wStr,GetResourceID(errID),errMsg);
  ParamText(wStr,””,””,””);  /* Setup text messages   */
  DoDlgCenter(‘ALRT’,errorID);/* Center alert dialog  */
  DoDeActivateScrollBars();  /* Deactivate scroll bars*/
  CautionAlert(GetResourceID(errorID),NIL);/* Show it */
  DoActivateScrollBars();    /* Activate scroll bars  */
  if (dbgHdl) {              /* Check if got ref hdl  */
   if (outputEnable) {       /* Check if enabled      */
                             /* Restore ref handle    */
    (*dbgHdl)->daRefNbr = dce->dCtlRefNum;
    ChangedResource(dbgHdl);
    WriteResource(dbgHdl);
   }
  }
 }

DoTextClick(pt,modifiers)
 Point   pt;                 /* Mouse down point      */
 short   modifiers;          /* Modifiers selection   */
 {
  register short  extendIt = FALSE;/* Extend selection*/

  if (peHdl) {               /* Check if got the text */
   if ((*peHdl)->peLength > 0) {/* Check if any text  */
    if (modifiers & shiftKey)/*Check if want extend it*/
     extendIt = TRUE;        /* Extend selection then */
    PEClick(pt,extendIt,peHdl);/* Do clicking stuff   */
   }
  }
 }

DoScrollBar(pt)
 Point   pt;                 /* Mouse down point      */
 {
  register short  partCtrl;  /* Working control part  */
  ControlHandle   ctrlHdl;   /* Working control handle*/

                             /* Check if got ctrl part*/
  if (partCtrl = FindControl(pt,wp,&ctrlHdl)) {
   ClipRect(&wp->portRect);  /* Setup clippings       */
   if (partCtrl == inThumb) {/* Check if using thumb  */
                             /* Save cur ctrl’s value */
    SetCRefCon(ctrlHdl,GetCtlValue(ctrlHdl));
    ClipRect(&wp->portRect); /* Reset for a moment    */
    TrackControl(ctrlHdl,pt,NIL);/* Let track by thumb*/
    DoTextScroll(ctrlHdl,inThumb);/* OK, let’s scroll */
    DoRestoreClippings();    /* Restore view clippings*/
   }
   else {                    /* Nope, other types     */
    ClipRect(&wp->portRect); /* Reset for a moment    */
    TrackControl(ctrlHdl,pt,DoTextScroll);/* Scroll it*/
    DoRestoreClippings();    /* Restore text clippings*/
   }
  }
  return(partCtrl);          /* Return part control   */
 }

pascal void DoTextScroll(ctrlHdl,partCtrl)
 ControlHandle   ctrlHdl;    /* Control scroll handle */
 short           partCtrl;   /* Control’s part        */
 {
  register short  delta;     /* Working delta scroll  */
  register short  value;     /* Working current value */
  register short  maxValue;  /* Working maximum value */
  register short  viewLines; /* Working view lines    */
  short           dh = 0;    /* Working delta horz    */
  long            dv = 0;    /* Working delta vertical*/
  PEPtr           pePtr;     /* Working edit pointer  */
        
  SetUpA4();                 /* Setup register A4     */
  delta = GetCtlValue(ctrlHdl);/* Get current value   */
  maxValue = GetCtlMax(ctrlHdl);/* Get maximum value  */
  switch(partCtrl) {         /* Handle request:       */
   case 0:                   /*      “Nothing”        */
    return;
   case inUpButton:
    value = max(0,delta - 1);/* Set new value position*/
    break;
   case inDownButton:
    value = min(maxValue,delta + 1);/* Set new value  */
    break;
   case inPageUp:            /*      “Page Up”        */
   case inPageDown:          /*      “Page Down”      */
    if (ctrlHdl == vScrollBar) {/* Check if vertical  */
     pePtr = *peHdl;         /* Set edit text pointer */
                             /* Set vis lines by half */
     viewLines = (pePtr->viewRect.bottom - 
               pePtr->viewRect.top) / pePtr->lineHeight;
     if (partCtrl == inPageUp)/* Check if page up reg */
      value = max(0,delta - viewLines);
     else                    /* Nope, page down region*/
      value = min(maxValue,delta + viewLines);
    }
    else {                   /* Check if horizontal   */
     if (partCtrl == inPageUp)/* Check if page up reg */
      value = max(0,delta - 10);/* Set new position   */
     else                    /* Nope, page down region*/
      value = min(maxValue,delta + 10);
    }
    break;
   case inThumb:             /*      “Thumb”          */
    delta = GetCRefCon(ctrlHdl);/* Get starting value */
    value = GetCtlValue(ctrlHdl);/* Get new value     */
  }
  SetCtlValue(ctrlHdl,value);/* Reset the value       */
  if (hScrollBar == ctrlHdl) /* Check if horzontal    */
   dh = delta - value;       /* Set horizontal offset */
  else
   dv = delta - value;       /* Set vertical offset   */
  DoRestoreClippings();      /* Restore view clippings*/
  if (dh || dv)              /* Check if should scroll*/
   PEScroll(dh * CharWidth(‘ ‘),dv,peHdl);/* Scroll it*/
  ClipRect(&wp->portRect);   /* Reset clippings       */
  RestoreA4();               /* Restore register A4   */
 }

pascal void DoClickScroll(peHdl)
 register PEHandle    peHdl; /* Edit data handle      */
 {
  register Rect     viewRect;/* Working view rect area*/
  Point             pt;      /* Working mouse point   */
    
  viewRect = (*peHdl)->viewRect;/* Set view rect area */
  GetMouse(&pt);             /* Get current mouse     */
  if (pt.v < viewRect.top)   /* Check if going upward */
   DoTextScroll(vScrollBar,inUpButton);
  else if (pt.v > viewRect.bottom)/* Check if downward*/
   DoTextScroll(vScrollBar,inDownButton);
  else if (pt.h < viewRect.left)/* Check if leftward  */
   DoTextScroll(hScrollBar,inUpButton);
  else if (pt.h > viewRect.right)/* Check if rightward*/
   DoTextScroll(hScrollBar,inDownButton);
 }
   
pascal  void    DoHighLite(hilite,pePtr)
 Rect      *hilite;          /* Highlite rect area    */
 register PEPtr pePtr;       /* Edit text pointer     */
 {
  HiliteMode &= 0x7f;        /* Set highliting bit    */
  InvertRect(hilite);        /* Invert rect area      */
 }

DoNewLineToReturn(s)
 char    *s;                 /* Input string pointer  */
 {
  while(*s) {                /* Cvt NEW-LINE to RETURN*/
   if (*s == ‘\n’)           /* Check if NEW-LINE char*/
    *s = ‘\r’;               /* Convert to RETURN char*/
   s += 1;                   /* Bump to next character*/
  }
 }
    
DoPrintLine(format,args)
 char    *format;            /* Format string pointer */
 va_list args;               /* Argument’s list       */
 {
  vsprintf(PrintOutputBuf,format,&args);/* Format buf */
  DoNewLineToReturn(PrintOutputBuf);/*Convert NEW-LINE*/
                             /* Output string         */
  PEInsert(PrintOutputBuf,DbgStrLen(PrintOutputBuf), peHdl);
  DoAdjustScrollBar();       /* Adjust the scroll bar */
 }
    
DoDbgPrintSetUp(fmt)
 char        *fmt;           /* Input format pointer  */
 {
  register short  fLen;      /* Working format str len*/
  register char   *stack;    /* Working fake stack ptr*/
        
  fLen = DbgStrLen(fmt) + 1; /* Set string length     */
  if (fLen & 0x1)            /* Check if even # chars */
   fLen += 1;                /* Align it to even addr */
  stack = fmt + fLen;        /* Set format string addr*/
  *((long *)(stack)) = ((long)(fmt));
  DoDbgPrint(stack);         /* OK, let’s really do it*/
 }

DoDbgPrint(args)
 long    *args;              /* Input argument’s list */
 {
  DoSetupView();             /* Setup the view display*/
  DoAdjustView();            /* Adjust the view       */
  vsprintf(PrintOutputBuf,*args,args + 1L);/*Format it*/
  DoNewLineToReturn(PrintOutputBuf);/*Convert NEW-LINE*/
                             /* Output string         */
  PEInsert(PrintOutputBuf,DbgStrLen(PrintOutputBuf), peHdl);
  DoAdjustScrollBar();       /* Adjust the scroll bar */
 }
    
DoPrintDump(ptr,size)
 char    *ptr;               /* Print buffer pointer  */
 long    size;               /* Print buffer length   */
 {
  register  long    i,j,k,m,n;/* Working indexes      */
  register  char    *tptr;   /* Working temporary ptr */
  Str255            buffer;  /* Working string buffer */
  Str255            tbuffer; /* Working temp buffer   */
      
  DoSetupView();             /* Setup the view display*/
  DoAdjustView();            /* Adjust the view       */
                             /* Output # of bytes     */
  DoPrintLine(“\nNumber of bytes - %ld\n”,size);
  DoPrintLine(“Cnt  Address  %s %s\n”,
              “Hex Values--------------------------------------------------”,
              “ASCII Values--------”);
  for(i = 0L; i < size; i += 16L) {/*Transfer all data*/
   n = 14L;                  /* Set init buffer index */
   for(j = 0L; j < sizeof(buffer); j++)/* Clr buf str */
    buffer[j] = ‘ ‘;         /* Pad it with spaces    */
   sprintf(buffer,”%04ld %08lx “,i,tptr = ptr);
   j = i; k = m = 0L;        /* Init indexes          */
   while(j < size && m < 16L) {/* Output hex parts    */
    m += 1L;                 /* Bump # of characters  */
    if (k++ == 3L) {         /* Check if time to pad  */
     sprintf(tbuffer,”%04x “,*tptr++);/* Get char hex */
                             /* Add it to output buf  */
     BlockMove(&tbuffer[2],&buffer[n],
               DbgStrLen((char *)(&tbuffer[2])) + 1);
     k = 0L;                 /* Reset index           */
     n += 1L;                /* Bump one extra        */
    }
    else {
     sprintf(tbuffer,”%04x”,*tptr++);/* Get char hex  */
                             /* Add it to output buf  */
     BlockMove(&tbuffer[2],&buffer[n],
               DbgStrLen((char *)(&tbuffer[2])) + 1);
    }
    j += 1L;                 /* Bump to next character*/
    n += 2L;                 /* Bump for two hex chars*/
   }
   buffer[n] = ‘ ‘;          /* Remove end-of-string  */
   n = 50L;                  /* Reset character index */
   j = i; m = 0L;            /* Init indexes          */
   while(j < size && m < 16L) {/* Output hex parts    */
    j += 1L;                 /* Bump to next character*/
    m += 1L;                 /* Bump # of characters  */
    if (isprint(*ptr))       /* Check if printable    */
     sprintf(&buffer[n],”%c”,*ptr++);/* Output char   */
    else {                   /* It’s not printable    */
     BlockMove(“.”,&buffer[n],2L);/* Show period only */
      ptr += 1L;             /* Bump to next character*/
    }
    n += 1L;                 /* Bump for one character*/
   }
                             /* Add RETURN character  */
   BlockMove(“\r”,&buffer[DbgStrLen((char *)(buffer))], 2L);
   DoPrintLine(“%s”,buffer); /* Output the string     */
  }
 }
    
DoRestoreClippings()
 {
  Rect    wRect;             /* Working rect area     */
        
  if (peHdl) {               /* Check if it’s valid   */
   wRect = (*peHdl)->viewRect;/* Restore clipping     */
   ClipRect(&wRect);
  }
 }
    
DoAdjustScrollBar()
 {
  register short  viewHeight;/* Working view height   */
  register short  hiddenLines;/* Working # hidden line*/
  register PEPtr  pePtr;     /* Working edit pointer  */
        
  if (peHdl) {               /* Check if have edit hdl*/
   pePtr = *peHdl;           /* Set edit pointer      */
   if (pePtr->peLength) {    /*Check if there any text*/
    ClipRect(&wp->portRect); /* Reset clippings       */
    if (hScrollBar) {        /* Check if there a horz */
     if (!GetCtlMax(hScrollBar))/* Check if not init  */
      SetCtlMax(hScrollBar,maxColumns);/* Reset to max*/
    }
    if (vScrollBar) {        /* Check if there a vert */
                             /* Set view height       */
     viewHeight = abs(pePtr->viewRect.bottom - 
                      pePtr->viewRect.top);
                             /*Check if need to enable*/
     if (pePtr->nLines*pePtr->lineHeight > viewHeight) {
                             /* Set # of hidden lines */
      hiddenLines = max(0,pePtr->nLines - viewHeight / 
                          pePtr->lineHeight);
                             /*Check if hidden changed*/
      if (GetCtlMax(vScrollBar) != hiddenLines) {
                             /* Update maximum # lines*/
       (*vScrollBar)->contrlMax = hiddenLines - 1;
                             /* Adjust thumb position */
       SetCtlValue(vScrollBar,
                   min((short)pePtr->viewOrgV, hiddenLines - 1));
       DoAdjustView();       /* Adjust the view       */
      }
     }
     else {                  /* Nope, disable scroll  */
                             /* Check if it’s enabled */
      if (GetCtlMax(vScrollBar)) {
       (*vScrollBar)->contrlMax = 0;/* Reset it       */
       SetCtlValue(vScrollBar,0);
      }
     }
    }
   }
   else {                   /* Reset the scroll bars  */
    if (hScrollBar) {       /* Check if there a horz  */
     if (GetCtlMax(hScrollBar)) {/* Check if enabled  */
      (*hScrollBar)->contrlMax = 0;/* Reset it        */
      SetCtlValue(hScrollBar,0);
     }
    }
    if (vScrollBar) {       /* Check if there a vert  */
     if (GetCtlMax(vScrollBar)) {/* Check if enabled  */
      (*vScrollBar)->contrlMax = 0;/* Reset it        */
      SetCtlValue(vScrollBar,0);
     }
    }
   }
   DoRestoreClippings();   /* Restore view clippings  */
  }
 }
    
DoSetupView()
 {
  register PEPtr  pePtr;     /* Working edit data ptr */
    
  if (peHdl) {               /* Check if have edit hdl*/
   pePtr = *peHdl;           /* Set edit pointer      */
                             /* Check if selected text*/
   if (pePtr->selStart != pePtr->selEnd)
    PESetSelect(pePtr->peLength,pePtr->peLength,peHdl);
                             /* Check not end-of-text */
   else if (pePtr->selStart != pePtr->peLength)
    PESetSelect(pePtr->peLength,pePtr->peLength,peHdl);
  }
 }
    

DoAdjustView()
 {
  register PEPtr     pePtr;  /* Working edit data ptr */
  long               delta;  /* Working delta offset  */
  long               currentLine;/* Cur line selection*/
  register long      selectLine;/* Working line sel   */
  register long      viewLines;/* Working view lines  */
  long               hViewLines;/* Half view lines    */
  register long      viewOrgV;/* Origin view offset   */
  long               saveSelStr;/* Save selStart value*/
  long               saveSelEnd;/* Save selEnd value  */
  register long      status = TRUE;/* Adjust view flag*/
  short              adjust = FALSE;/* Vert adjustment*/
    
  if (peHdl) {               /* Check if have edit hdl*/
   DoRestoreClippings();     /* Restore view clippings*/
   pePtr = *peHdl;           /* Set edit text pointer */
   if (optHdl) {             /* Check if hdl valid    */
    if ((*optHdl)->maxTextSize) {/* Check if maxing   */
                             /* Set cur line to chop  */
     currentLine = pePtr->peLength - (*optHdl)->maxTextSize;
     if (currentLine > 0) {  /* Check if time to chop */
      PECloseGap(peHdl);     /* Close the gap first   */
      saveSelStr = pePtr->selStart;/* Save start sel  */
      saveSelEnd = pePtr->selEnd;/* Save end selection*/
                             /* Reset selection       */
      PESetSelect(0L,currentLine = PEEol(currentLine,
                               peHdl) + 1L,peHdl);
      PEDelete(peHdl);       /* OK, let’s delete it   */
                             /* Restore it            */
      PESetSelect(saveSelStr - currentLine,
                  saveSelEnd - currentLine,peHdl);
     }
    }
   }
   pePtr = *peHdl;           /* Set edit text pointer */
   viewOrgV = pePtr->viewOrgV;/*Set view origin offset*/
                             /* Set # of visible lines*/
   viewLines = abs(pePtr->viewRect.bottom -
                   pePtr->viewRect.top) /
               pePtr->lineHeight;
   hViewLines = viewLines / 2;/*Half of the view lines*/
                             /* Set selected line #   */
   selectLine=currentLine=PELineNum(pePtr->selEnd,peHdl);
   pePtr = *peHdl;           /* Reset edit text ptr   */
                             /* Check if within view  */
   if (selectLine >= viewOrgV &&
       selectLine < viewOrgV + viewLines)
    status = FALSE;
   if (status) {             /* Check if should adjust*/
    adjust = TRUE;           /* Set adjust vert offset*/
    selectLine -= viewOrgV;  /* Adjust select line #  */
    if (selectLine == viewLines)/* Check if just off  */
     selectLine -= viewLines - 1;/* Adjust by one line*/
                             /* Check if close bottom */
    else if (delta = (pePtr->nLines - currentLine - 
                              1 - hViewLines) < 0)
     selectLine += delta - viewLines;/*Adjust to bottom*/
    else if (selectLine != -1)/*Check if completely off*/
     selectLine -= hViewLines;/* Center the page      */
    selectLine += viewOrgV;  /*Adjust physical offset */
                             /* Scroll to cursor      */
    PEScrollTo(pePtr->viewOrgH,selectLine,peHdl);
   }
  }
 }

DoResizeScrollBar()
 {
  Rect    wRect;             /* Window rect area     */
        
  if (peHdl) {               /*Check if have edit hdl*/
   wRect.left = wp->portRect.left;
   wRect.top = wp->portRect.top + 5;
   wRect.right = wp->portRect.right - 15;
   wRect.bottom = wp->portRect.bottom - 15;
   (*peHdl)->viewRect = wRect;
  }
  if (hScrollBar) {          /* Check if have scroll  */
                             /* Compute rect area     */
   wRect.left = wp->portRect.left - 1;
   wRect.top = wp->portRect.bottom - 15;
   wRect.right = wp->portRect.right - 14;
   wRect.bottom = wp->portRect.bottom + 1;
   (*hScrollBar)->contrlRect = wRect;/* Set new rect  */
  }
  if (vScrollBar) {          /* Check if have scroll  */
                             /* Compute rect area     */
   wRect.left = wp->portRect.right - 15;
   wRect.top = wp->portRect.top - 1;
   wRect.right = wp->portRect.right + 1;
   wRect.bottom = wp->portRect.bottom - 14;
   (*vScrollBar)->contrlRect = wRect;/* Set new ret   */
  }
 }
    
DialogTHndl DoDlgCenter(type,id)
 long  type;                 /* Resource type id      */
 short id;                   /* Id #                  */
 {
  register DialogTHndl dhdl; /* Working dialog handle */
  register DialogTPtr  dptr; /* Working dialog ptr    */
  WindowPtr            wPtr; /* Working window ptr    */
  register short       swidth;/*Working 1/2 horz width*/
  register short       width;/*Working 1/2 horz width */
      
                             /* Check if got dlg hdl  */
  if (dhdl = ((DialogTHndl)GetResource(type,
                                  GetResourceID(id)))) {  
   GetWMgrPort(&wPtr);       /* Get window mgr ptr    */
   dptr = *dhdl;             /* Set dialog ptr        */
                             /* Set 1/2 screen width  */
   swidth = abs(wPtr->portRect.right -
                wPtr->portRect.left) / 2;
                             /* Set 1/2 dialog width  */
   width = abs(dptr->boundsRect.right -
               dptr->boundsRect.left) / 2;
                             /* Center the dialog     */
   dptr->boundsRect.left = swidth - width;
   dptr->boundsRect.right = swidth + width;
  }
  return(dhdl);              /* Return dialog handle  */
 }

DoItemIdx(item,menu)
 register unsigned char  *item;/* Item string look up */
 register MenuHandle     menu;/* Menu handle          */
 {
  register short  i,j;       /* Working index         */
  register unsigned short len = *item++;/* Item length*/
  Str255          wStr;      /* Working string        */
        
                             /* Look for matching item*/
  for(i = 1, j = CountMItems(menu); i <= j; i++) {
   GetItem(menu,i,&wStr);    /* Working string        */
   if (!IUMagString(item,&wStr[1],len,len))/* Matches?*/
    return(i);               /* Found matching string */
  }
  return(1);                 /* Opps, didn’t find it  */
 }

GetResourceID(n)
 { return(0xC000 + ((~(dce->dCtlRefNum))<<5) + n); }

/*
 *  Source    - Debugger.c
 *  Author    - Alexander S. Colwell,
 *              Copyright (C) 1988, 1989
 *  Purpose   - This is the “Debugger Window” DA
 *              interface routines.
 */

#include “Debugger.h”        /* Debugger defs         */

                             /* Device ctrl entry func*/
#define DbgDCtlEntry(refNbr) (UTableBase[-1*(refNbr+1)])
short   DbgArgCnt();         /* Define forward refs   */

DBGHDL  DbgGetRefHdl()
 {
  register DBGHDL dbgHdl;    /* DA’s reference # hdl  */

  asm {                      /* Debugger’s res name   */
   CLR.L   -(sp)             ;Allocate return handle
   PEA     debuggerType      ;Load resource type
   PEA     @dbgRef           ;Load resource name 
   _GetNamedResource         ;Get resource handle
   MOVE.L  (sp)+,dbgHdl      ;Save resource handle
   BRA.S   @dbgExit          ;Skip around resource name
dbgRef: DC.B 18,’D’,’e’,’b’,’u’,’g’,’g’,’e’,’r’,’ ‘,’R’,’e’,’f’,’e’,’r’,’e’,’n’,’c’,’e’
dbgExit:
  }
  return(dbgHdl);            /* Return resource handle*/
}
    
void    DbgPrint(dbgHdl,args)
 register DBGHDL dbgHdl;     /* Working DA’s ref # hdl*/
 char    *args;              /* Input arguments       */
 {
  register short  refNbr;    /* Working DA’s ref #    */
  register short  daEnable;  /* Working save DA state */
  register DCtlHandle dceHdl;/* Device control entry  */
        
  if (dbgHdl) {              /* Check if got handle   */
   if (refNbr = (*dbgHdl)->daRefNbr) {/*Check if valid*/
                             /* Check if got dev hdl  */
    if (dceHdl = GetDCtlEntry(refNbr)) {
                             /* Save enabled stated   */
     daEnable = (*dceHdl)->dCtlFlags & dCtlEnable;
                             /* Enable DA’s entry     */
     (*dceHdl)->dCtlFlags |= dCtlEnable;
     Control(refNbr,accDbgPrint,&args);/* Write it    */
     if (!daEnable)          /* Check if not enabled  */
      (*dceHdl)->dCtlFlags &= ~dCtlEnable;
    }
   }
  }
 }

void    DbgBufPrint(args)
 long    *args;              /* Input arguments       */
 {
  register DBGHDL dbgHdl;    /* Working DA’s ref # hdl*/
  register DBGPTR dbgPtr;    /* Working DA’s ref hdl  */
  DCtlHandle      dceHdl;    /* Working device ctrl   */
  register char   *fmt;      /* Working format string */
  register char   *buf;      /* Working buffer address*/
  long            *addr;     /* Working stack address */
  register long   fLen;      /* Working format str len*/
  register long   dLen;      /* Working data buf len  */
  register long   argc;      /* Working # of arg bytes*/
  register long   nextIdx;   /* Working next table idx*/
  register long   dataIdx;   /* Working data index    */
        
  dbgHdl = (DBGHDL)(&args[0]);/* Set debugger handle  */
  if (dbgHdl) {              /* Check if got handle   */
   dbgPtr = *dbgHdl;         /* Setup debugger pointer*/
   if (dbgPtr->daRefNbr) {   /* Check if it’s valid   */
                             /* Check if got device   */
    if (dceHdl = DbgDCtlEntry(dbgPtr->daRefNbr)) {
                             /* Check if have buffers */
     if (dbgPtr->bufTable && dbgPtr->bufData) {
                             /* Set next tbl idx entry*/
      nextIdx = (dbgPtr->bufNextIdx + 1L) %
                dbgPtr->bufTableSize;
      if (nextIdx == dbgPtr->bufTableIdx)/* Overflow? */
       dbgPtr->bufError = dbgTableOvrFlw;
      else {                 /* Nope, continue        */
       argc = DbgArgCnt(&args) - 4L;/* Get # of args  */
       if (argc >= 4L) {     /* Check if has fmt str  */
        addr = (long *)(&args);/* Set stack address   */
        fmt = (char *)(addr[1]);/* Get variable arg   */
        fLen = DbgStrLen(fmt) + 1L;/* Get fmt str len */
        if (fLen & 0x1L)     /* Check if even align   */
         fLen += 1L;         /* Align it              */
        dLen = argc + fLen + 2L;/* Total buf length   */
                             /* Check if time buf wrap*/
         if ((dataIdx = dbgPtr->bufDataIdx) + dLen >= 
             dbgPtr->bufDataSize)
          dataIdx = 0L;      /* Reset begin-of-buffer */
         if (dLen > dbgPtr->bufDataSize)/* Buf to big?*/
          dbgPtr->bufError = dbgBufOvrFlw;
                             /* Check if any in buffer*/
         else if (dbgPtr->bufTableIdx != dbgPtr->bufNextIdx) {
                             /* Check if buf overflow */
          if (dataIdx < (*dbgPtr->bufTable)[dbgPtr->bufTableIdx+1L])
           if (dLen + dataIdx >           (*dbgPtr->bufTable)[dbgPtr->bufTableIdx+1L])
            dbgPtr->bufError = dbgDataOvrFlw;
         }
         if (!dbgPtr->bufError) {/* Check no overflow */
          dbgPtr->bufNextIdx = nextIdx;/* Set next lin*/
                             /* Save data buffer index*/
          (*dbgPtr->bufTable)[nextIdx] = dataIdx;
                             /* Set buffer address    */
          buf = &(*dbgPtr->bufData)[dataIdx];
          *buf = accDbgPrint;/* Set code              */
          BlockMove(fmt,buf + 2L,fLen);/* Copy fmt str*/
                             /* Copy the stack        */    
          BlockMove(&addr[1],buf + fLen + 2L,argc);
                             /* Bump to next position */
          dbgPtr->bufDataIdx = dataIdx + dLen;
          (*dceHdl)->dCtlFlags |= dNeedTime;/* Enable */
          (*dceHdl)->dCtlDelay = 1;/* Reset delay time*/
         }
        }
       }
      }
     }
    }
   }
 }
    
void    DbgDump(dbgHdl,buffer,size)
 register DBGHDL dbgHdl;     /* Working DA’s ref # hdl*/
 char    *buffer;            /* Input buffer          */
 long    size;               /* Input buffer size     */
 {
  register short  refNbr;    /* Working DA’s ref #    */
  register short  daEnable;  /* Working save DA state */
  register DCtlHandle dceHdl;/* Working dev ctrl entry*/
  long            csParam[2];/* Working ctrl parm list*/
        
  if (dbgHdl) {              /* Check if got handle   */
   if (refNbr = (*dbgHdl)->daRefNbr) {/*Check if valid*/
                             /*Check if got device hdl*/
    if (dceHdl = GetDCtlEntry(refNbr)) {
                             /* Save enabled stated   */
     daEnable = (*dceHdl)->dCtlFlags & dCtlEnable;
                             /* Enable DA’s entry     */
     (*dceHdl)->dCtlFlags |= dCtlEnable;
     csParam[0] = (long)(buffer);/* Init param list   */
     csParam[1] = size;
                             /* OK, let’s dump it now */
     Control(refNbr,accDbgDump,csParam);
     if (!daEnable)          /* Check if not enabled  */
      (*dceHdl)->dCtlFlags &= ~dCtlEnable;
    }
   }
  }
 }

void    DbgBufDump(dbgHdl,buffer,size)
 register DBGHDL dbgHdl;     /* Working DA’s ref # hdl*/
 char    *buffer;            /* Input buffer          */
 long    size;               /* Input buffer size     */
 {
  register DBGPTR dbgPtr;    /* Working DA’s ref hdl  */
  DCtlHandle      dceHdl;    /* Working dev ctrl entry*/
  register char   *buf;      /* Working buffer address*/
  register long   dLen;      /* Working data buf len  */
  register long   argc;      /* Working # of arg bytes*/
  register long   nextIdx;   /* Working next table idx*/
  register long   dataIdx;   /* Working data index    */
        
  if (dbgHdl) {              /* Check if got handle   */
   dbgPtr = *dbgHdl;         /* Setup debugger pointer*/
   if (dbgPtr->daRefNbr) {   /* Check if it’s valid   */
                             /* Check if got dev hdl  */
    if (dceHdl = DbgDCtlEntry(dbgPtr->daRefNbr)) {
                             /* Check if have buffers */
     if (dbgPtr->bufTable && dbgPtr->bufData) {
                             /* Set next tbl idx entry*/
      nextIdx = (dbgPtr->bufNextIdx + 1L) %
                dbgPtr->bufTableSize;
      if (nextIdx == dbgPtr->bufTableIdx)/* Overflow? */
       dbgPtr->bufError = dbgTableOvrFlw;
      else {                 /* Nope, continue        */
       dLen = size + sizeof(size) + 2L;/*Total buf len*/
       if (dLen & 0x1L)      /* Check if odd size     */
        dLen += 1L;          /* Let’s make it even    */
                             /* Check if time buf wrap*/
       if ((dataIdx = dbgPtr->bufDataIdx) + dLen >= 
           dbgPtr->bufDataSize)
         dataIdx = 0L;       /* Reset begin-of-buffer */
       if (dLen > dbgPtr->bufDataSize)/*Buffer to big?*/
        dbgPtr->bufError = dbgBufOvrFlw;
                             /* Check if any in buffer*/
       else if (dbgPtr->bufTableIdx != dbgPtr->bufNextIdx) {
                             /* Check if buf overflow */
        if (dataIdx <
            (*dbgPtr->bufTable)[dbgPtr->bufTableIdx+1L])
         if (dLen + dataIdx >
             (*dbgPtr->bufTable)[dbgPtr->bufTableIdx+1L])
          dbgPtr->bufError = dbgDataOvrFlw;
       }
       if (!dbgPtr->bufError) {/* Check if no overflow*/
        dbgPtr->bufNextIdx = nextIdx;/* Set next line */
                             /* Save data buffer index*/
        (*dbgPtr->bufTable)[nextIdx] = dataIdx;
                             /* Set buffer address    */
        buf = &(*dbgPtr->bufData)[dataIdx];
        *buf = accDbgDump;   /* Set code              */
                             /* Copy size of buffer   */
        BlockMove(&size,buf + 2L,(long)(sizeof(size)));
                             /* Copy the buffer       */    
        BlockMove(buffer,buf + sizeof(size) + 2L,size);
                             /* Bump to next position */
        dbgPtr->bufDataIdx = dataIdx + dLen;
        (*dceHdl)->dCtlFlags |= dNeedTime;/* Enable it*/
        (*dceHdl)->dCtlDelay = 1;/* Reset delay timer */
       }
      }
     }
    }
   }
  }
 }

short   DbgArgCnt(vararg)
 long vararg;                /* Variable argument list */
 {
  register union {           /* Union of 3 var types   */
   long            addr;     /* Address of the types   */
   long            **args;
  }               varg;      /* Working var arg list   */
  register unsigned long instr;/* Working instruction  */
  register long     arg;     /* Working argument       */
  register long     count = 0L;/* # of arguments       */

  varg.addr = vararg;        /* Init variable arg list */
  varg.addr -= 4;            /* Position to instruction*/
  instr = **varg.args & 0xffff0000;/* Set instr word   */
  if (instr == 0x4fef0000)   /* Check if ADD instr     */
  count = (**varg.args & 0x0000ffff );/* Set # of bytes*/
                             /* Check if ADDI instr    */
  else if ((instr & 0xf1ff0000) == 0x508f0000) {
                             /* Check if 0, then 8 byte*/
   if (!(count = ((instr & 0x0e000000) >> 25)))
   count = 8;                /* Reset 8 bytes on stack */
  }
  return(count);             /* Return count           */
 }
 
long    DbgStrLen(s)
 register char   *s;         /* String pointer        */
 {
  register long   sLen = 0;  /* String length         */
        
  while(*s++)                /* Continue to end-of-str*/
   sLen++;                   /* Bump string length    */
  return(sLen);              /* Return string length  */
 }
    
*
*   Resource - DebuggerDA.R
*   Author   - Alexander S. Colwell,
*              Copyright (C) 1988, 1989
*   Purpose -  This is the resource file for the 
*              “Debugger Window” DA.
*
DebuggerDA.Π.rsrc
rsrcRSED

Type MENU
Debugger Menu,-16000
Debugger
About This Debugger Window.../?
(-
Stop Output/S
Quit/Q

Type STR#
Debugger Misc,-16000 (32)
5
Start Output
Stop Output
ERROR: Table index overflow
ERROR: Data buffer overflow
ERROR: Buffer size overflow

Debugger Errors,-15999 (32)
6
Sorry, fail to open DA. Perhaps running low on memory.
DA’s global memory allocation fail. Running low on memory.
Warning, running low on memory!
Sorry, require 4.1 or higher “System” file version.
Sorry, cannot run under “Lisa” clone Macintosh.
Sorry, cannot run on Mac 128K or 512K computer.

Type WIND
Debugger,-16000 (32)
Debugger Window
227 10 337 502
NoVisible GoAway
8
0

Type DLOG
Debugger Info,-16000 (32)
Info
64 92 105 323 
Visible NoGoAway
1
0
-16000

Type ALRT
Debugger Alert,-15999 (32)
100 100 199 401
-15999
4444

Type DITL
Debugger Info,-16000 (32)
1
StatText Enabled 
5 5 110 278 
  Debugger Window, Version 1.0    Written  by  Alexander S. Colwell

Debugger Alert,-15999 (32)
2
BtnItem Enabled
71 215 91 294 
OK

StatText Enabled
8 60 63 297 
^0

Type Opts = GNRL
Debugger Options,-16000
.I
0
4
9
4
.L
100
2048

Type Dbgr = GNRL
Debugger Reference,-16000 (32)
.I
0
0
.L
0
0
0
0
0
0
0

/*
 *  Source  - Round Window.c
 *  Author  - Alexander S. Colwell,
 *            Copyright (C) 1988, 1989
 *  Purpose - This will display a round window using
 *            “Debugger Window” DA demostration.
 */

#include <Color.h>           /* Color Manager defs    */
#include <math.h>            /* Math defs             */
#include <SetUpA4.h>         /* Desk Accessory defs   */
#include <VRetraceMgr.h>     /* Vertical Retrace defs */
#include “Debugger.h”        /* Debugger defs         */

                             /* Misc definitions      */
#define NIL     (0L)         /* NIL pointer           */
#define abs(a)  (a<0?-a:a)   /* Absolute macro func   */
#define min(a,b) (a<b?a:b)   /* Minumim macro function*/
#define max(a,b) (a<b?b:a)   /* Maximum macro function*/

                             /* Resource ID #’s       */
#define windID          0    /* Window ID #           */

#define helloWorld “\pHello, World”/* String message  */

typedef struct {             /* VBL data structure    */
    VBLTask vblTask;         /* VBL                   */
    DBGHDL  dbgHdl;          /* Debugger handler      */
    short   counter;         /* Tick counter          */
    } VBL;
typedef VBL *VBLPTR;

DCtlPtr         dce;         /* Device control entry  */
WindowPtr       wp = NIL;    /* My window pointer     */
short           alreadyOpen = FALSE;/* DA is opened   */
VBLPTR          vblPtr = NIL;/* VBL data block        */
Handle          vblHdl = NIL;/* VBL code handle       */
DBGHDL          dbgHdl = NIL;/* Debugger reference hdl*/ 

main(p,d,n)
 cntrlParam  *p;             /* Parameter block       */
 DCtlPtr     d;              /* Device control entry  */
 short       n;              /* Entry point selector  */
 {
  WindowPtr   savePort;      /* Save cur window port  */

  if (d->dCtlStorage == 0) { /* Check if got globals  */
   if (n == 0) {             /*Check if request “Open”*/
    SysBeep(1);              /* Beep da user!         */
    CloseDriver(d->dCtlRefNum);/* Close the DA        */
   }
  }
  else {                     /* Got globals then cont */
   GetPort(&savePort);       /* Get cur window port   */
   if (wp)                   /* Check if win ptr valid*/
    SetPort(wp);             /* Set port to my window */
   dce = d;                  /* Save DCE in our global*/
   dce->dCtlFlags &= ~dCtlEnable;/* Set not re-entrant*/
   switch(n) {               /* Handle request:       */
    case 0:                  /*      “Open”           */
     DoOpen(); break;    
    case 2:                  /*      “Control”        */
     DoControl(p->csCode,p->csParam); break; 
    case 4:                  /*      “Close”          */
     DoClose(); break;
   }
   dce->dCtlFlags |= dCtlEnable;/* Enable calls again */
   SetPort(savePort);        /* OK, let’s restore it  */
  }
  return(0);                 /* Return default success*/
 }

DoOpen()
 {
  Handle  wDEFHdl;           /* Working window def hdl*/
        
                             /* Add driver flags      */
  dce->dCtlFlags |= dNeedLock|dNeedGoodBye;
  if (wp)                    /* Check if there a wind */
   SelectWindow(wp);         /* Bring our window front*/
  if (!alreadyOpen) {        /* Check if require inits*/
   wp = GetNewWindow(GetResourceID(windID),NIL,-1L);
   if (wp) {                 /* Check if got window   */
                             /* Check if got our WDEF */
    if (wDEFHdl = GetResource(‘WDEF’,GetResourceID(0)))
     ((WindowPeek)(wp))->windowDefProc = wDEFHdl;
    ShowWindow(wp);          /* Show the window now   */
    SetPort(wp);             /* Set port to our window*/
    alreadyOpen = TRUE;      /* Set open DA indicator */
                             /*Save window association*/
    ((WindowPeek)wp)->windowKind = dce->dCtlRefNum;
    dce->dCtlWindow = wp;    /* Tell device where I am*/
    dbgHdl = DbgGetRefHdl(); /* Get reference handle  */
                             /* Check if got VBL ptr  */
    if (vblPtr = (VBLPTR)(NewPtr((long)sizeof(VBL)))) {
                             /* Check if got VBL code */
     if (vblHdl = GetResource(‘VBLC’,GetResourceID(0))){
      HLock(vblHdl);         /* Lock it for VBL task  */
                             /* Init VBL task         */
      vblPtr->vblTask.vblAddr = (ProcPtr)(*vblHdl);
      vblPtr->vblTask.vblCount = 120;
      vblPtr->vblTask.vblPhase = 0;
      vblPtr->vblTask.qType = vType;
      vblPtr->dbgHdl = dbgHdl;
      vblPtr->counter = 120;
      VInstall(vblPtr);      /* Install the VBL task  */
     }
    }
   }
   else {                   /* Fail to open           */
    SysBeep(1);             /* Beep da user!          */
    CloseDriver(dce->dCtlRefNum);/* OK, let’s close DA*/
   }
  }
 }

DoClose()
 {
  if (wp)                    /* Check if win ptr valid*/
   DisposeWindow(wp);        /* Delete the window now */
  wp = NIL;                  /* Invalidate it now     */
  if (vblPtr && vblHdl)      /* Check if VBL installed*/
   VRemove(vblPtr);
  if (vblPtr)                /* Check if has VBL ptr  */
   DisposPtr(vblPtr);        /* Release it now        */
  vblPtr = NIL;              /* Invalidate it now     */
  if (vblHdl) {              /* Check if has VBL hdl  */
   HUnlock(vblHdl);          /* OK, it safe unlock it */
   ReleaseResource(vblHdl);  /* Release it now        */
  }
  vblHdl = NIL;              /* Invalidate it now     */
  alreadyOpen = FALSE;       /* Reset it              */
 }

DoControl(code,parm)
 short code;                 /* Control command code  */
 short *parm;                /* “csParam” list pointer*/
 {
  switch(code) {             /* Handle request:       */
   case accEvent:            /*      “Event”          */
    DoEvent(*((EventRecord **)parm)); break;
   case goodBye:             /*      “GoodBye”        */
    DoClose(); break;
  }
 }

DoEvent(e)
 register EventRecord *e;    /* Event Record pointer  */
 {
                             /* Output DA’s event type*/
  DbgPrint(dbgHdl,”DA Event: what - %d\n”,e->what);
  switch(e->what) {          /* Handle request:       */
   case updateEvt:           /*      “Update”         */
    DoUpdate(); break;
   case mouseDown:           /*      “Mouse Down”     */
    DoMouse(e->where,e->modifiers); break;
   case keyDown:             /*      “Key Down”       */
   case autoKey:             /*      “Auto-Key Down”  */
                             /* Handle the input key  */
    DoKey((char)(e->message & charCodeMask),
          (char)((e->message & keyCodeMask) >> 8L),
          e->modifiers);
  }
 }

DoUpdate()
 {
  BeginUpdate(wp);           /* Start update process  */
  EraseRect(&wp->portRect);  /* Clear the window      */
  MoveTo(abs(wp->portRect.right - wp->portRect.left)/2 -
         StringWidth(helloWorld) / 2,
         abs(wp->portRect.bottom - wp->portRect.top)/2);
  DrawString(helloWorld);    /* Draw string message   */
  EndUpdate(wp);             /* Wrapup update process */
 }
    
DoMouse(p,modifiers)
 Point   p;                  /* Mouse point position  */
 short   modifiers;          /* Mouse’s modifiers     */
 {
  register long   i;         /* Working index         */
  Rect            wRect;     /* Working window rect   */
  register long   wGrow;     /* Working grow size     */
  ProcPtr         wDef;      /* Working wind proc hdl */
    
                             /* Load it into memory   */
  LoadResource(((WindowPeek)wp)->windowDefProc);
  HLock(((WindowPeek)wp)->windowDefProc);/* Lock it   */
                             /* Get window proc def   */
  wDef = (ProcPtr)*((WindowPeek)wp)->windowDefProc;
                             /* Check if in “Content” */
  if (CallPascalL(8,wp,(int)wHit,p,wDef) == wInContent)
   DoContent(p,modifiers);
  HUnlock(((WindowPeek)wp)->windowDefProc);
 }
    
DoKey(c,code,modifiers)
 char    c;                  /* Input character       */
 char    code;               /* Input code            */
 short   modifiers;          /* Input modifiers       */
 {
  if (modifiers & cmdKey) {  /* Check if key command  */
   if (c == ‘q’)             /* Check if time to quit */
    CloseDriver(dce->dCtlRefNum);/* OK, let’s close DA*/
   else                      /* Opps, invalid command */
    SysBeep(1);              /* Let the user know it  */
  }
 }

DoContent(p,modifiers)
 Point    p;                 /* Mouse down point      */
 short   modifiers;          /* Mouse’s modifiers     */
 {
  Rect            wRect;     /* Working window rect   */
  register long   wGrow;     /* Working grow point    */
  WindowPtr       wPtr;      /* Working window pointer*/
        
                             /* Check if want to resiz*/
  if (modifiers & (shiftKey | optionKey | cmdKey)) {
   SetRect(&wRect,50,50,32767,32767);/* Define limits */
   wGrow = GrowWindow(wp,p,&wRect);/* OK, let grow it */
   if (wGrow) {              /* Check if got new size */
                             /* Reset new size        */
    SizeWindow(wp,LoWord(wGrow),HiWord(wGrow),TRUE);
    InvalRect(&wp->portRect);/* Invalidate everything */
   }
  }
  else {                     /* Nope, just move it    */
   GetWMgrPort(&wPtr);       /* Get window manager ptr*/
   DragWindow(wp,p,&wPtr->portRect);/* Drag the window*/
  }
 }
    
GetResourceID(n)
 { return(0xC000 + ((~(dce->dCtlRefNum))<<5) + n); }

*
*   Resource - Round Window.R
*   Author   - Alexander S. Colwell,
*              Copyright (C) 1988
*   Purpose -  This is resource file for Round Window.
*
Round Window.Π.rsrc
rsrcRSED

Type WIND
Clock,-16000 (32)
Clock
64 64 187 187
NoVisible GoAway
2
0

include RoundWDEF.Π.rsrc
include RoundVBL.Π.rsrc

/*
 *  Source  - RoundVBL.c
 *  Author  - Alexander S. Colwell,
 *            Copyright (C) 1988
 *  Purpose - This is VBL def for “Debugger” DA’s demo.
 */

#include <VRetraceMgr.h>     /* Vertical Retrace defs */
#include <SetupA4.h>         /* Setup Register A4 defs*/
#include “Debugger.h”        /* Debugger defs         */

typedef struct {             /* VBL data structure    */
    VBLTask vblTask;         /* VBL                   */
    DBGHDL  dbgHdl;          /* Debugger handler      */
    short   counter;         /* Tick counter          */
    } VBL;
typedef VBL *VBLPTR;

main()
 {
  register VBLPTR vblPtr;    /* Working VBL data block*/
        
  asm { MOVE.L d0,vblPtr };  /* Move to vblPtr        */
  RememberA0();              /* Remember global ptr   */
  SetUpA4();                 /* Setup register A4     */
                             /* Output entry message  */
  DbgBufPrint(vblPtr->dbgHdl,”VBL: entry\n”);
                             /* Reset timer           */
  vblPtr->vblTask.vblCount = vblPtr->counter; 
  RestoreA4();               /* Restore register A4   */
 }
 /*
 *  Source  - RoundWDEF.c
 *  Author  - Alexander S. Colwell,
 *            Copyright (C) 1988
 *  Purpose - This is WDEF def for “Debugger” DA’s demo.
 */

#include <WindowMgr.h>       /* Window Manager defs   */
#include <SetUpA4.h>         /* Setup Register A4     */
#include “Debugger.h”        /* Debugger defs         */

                             /* Compilation directives*/
#define DEBUG                /* Enable debugging stuff*/

                             /* ‘WDEF’ entry point    */
pascal long main(varCode,theWindow,message,param)
 short       varCode;        /* Variation code        */
 WindowPtr   theWindow;      /* Window pointer        */
 short       message;        /* Message command       */
 long        param;          /* Parameter control     */
 {
  long    status = 0L;       /* Working status flag   */
        
  RememberA0();              /* Remember A0 global ptr*/
  SetUpA4();                 /* Setup register A4     */
        
  #ifdef DEBUG               /* Check if want debug   */
                             /* Output debugging info */
  DbgPrint(DbgGetRefHdl(),”WDEF: message - %d\n”,message);
  #endif
        
  switch(message) {          /* Process message       */
   case wNew:                /* Opening window        */
    break;
   case wDispose:            /* Closing window        */
    break;
   case wDraw:               /* Draw window frame     */
    DoDrawMsg(theWindow,param); break;
   case wHit:                /* Check mouse down hits */
    status = DoHitMsg(theWindow,param); break;
   case wCalcRgns:           /* Calc window regions   */
    DoCalcMsg(theWindow); break;
   case wGrow:               /* Grow window           */
    DoGrowMsg(theWindow,param); break;
   case wDrawGIcon:          /* Draw window Grow Icon */
    break;
  }
  RestoreA4();                /* Restore register A4  */
  return(status);             /* Return status flag   */
 }

DoDrawMsg(theWindow,param)
 WindowPtr   theWindow;      /* Window pointer        */
 long        param;          /* Message parameter     */
 {
  Rect        wRect;         /* Working window rect   */
  long        wPat[2];       /* Working white pattern */
  long        bPat[2];       /* Working black pattern */
        
  if (!param) {              /* Check if want to frame*/
   wPat[0] = wPat[1] = 0L;   /* Init patterns         */
   bPat[0] = bPat[1] = 0xFFFFFFFFL;
                             /* Set window rect area  */
   wRect=(*((WindowPeek)(theWindow))->strucRgn)->rgnBBox;
   PenNormal();              /* Reset pen states      */
   FrameOval(&wRect);        /* Frame outer-most part */
            
   InsetRect(&wRect,1,1);    /* Frame between part    */
   PenPat(wPat);
   FrameOval(&wRect);
            
   InsetRect(&wRect,1,1);    /* Frame middle part     */
   PenSize(3,3);
   PenPat(bPat);
   FrameOval(&wRect);
            
   InsetRect(&wRect,3,3);    /* Frame between part    */
   PenSize(1,1);
   PenPat(wPat);
   FrameOval(&wRect);

   InsetRect(&wRect,1,1);    /* Frame inter-most part */
   PenSize(1,1);
   PenPat(bPat);
   FrameOval(&wRect);
        
   InsetRect(&wRect,1,1);    /* Frame between parts   */
   PenPat(wPat);
   FrameOval(&wRect);
   PenPat(bPat);
  }
 }
    
DoHitMsg(theWindow,pt)
 WindowPtr   theWindow;      /* Window pointer        */
 Point       pt;             /* Mouse-down point      */
 {
  register short  status;    /* Working status flag   */
        
                             /* Check if point inside */
  if (PtInRgn(pt,((WindowPeek)(theWindow))->contRgn))
   status = wInContent;      /* Yup, inside contents  */
  else                       /* Nope, outside contents*/
   status = wNoHit;          /* Set no hit indicator  */
  return(status);            /* Return hit status flag*/
 }
    
DoCalcMsg(theWindow)
 WindowPtr   theWindow;      /* Window pointer        */
 {
  Rect    wRect;             /* Working window rect   */
        
  wRect = theWindow->portRect;/* Set window rect area */

                             /* Normalize window rect */
  OffsetRect(&wRect,-theWindow->portBits.bounds.left,
                    -theWindow->portBits.bounds.top);
                          
                             /* Setup content’s region*/
  SetEmptyRgn(((WindowPeek)(theWindow))->contRgn);
  OpenRgn();
  FrameOval(&wRect);
  CloseRgn(((WindowPeek)(theWindow))->contRgn);
                          
                             /* Setup content’s region*/
  SetEmptyRgn(((WindowPeek)(theWindow))->strucRgn);
  OpenRgn();
  InsetRect(&wRect,-8,-8);
  FrameOval(&wRect);
  CloseRgn(((WindowPeek)(theWindow))->strucRgn);
 }
    
DoGrowMsg(theWindow,theRect)
 WindowPtr   theWindow;      /* Window pointer        */
 Rect        *theRect;       /* Rect area to grow     */
 {
  FrameOval(theRect);        /* Draw the frame area   */
 }
    

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Latest Forum Discussions

See All

Challenge those pesky wyverns to a dance...
After recently having you do battle against your foes by wildly flailing Hello Kitty and friends at them, GungHo Online has whipped out another surprising collaboration for Puzzle & Dragons. It is now time to beat your opponents by cha-cha... | Read more »
Pack a magnifying glass and practice you...
Somehow it has already been a year since Torchlight: Infinite launched, and XD Games is celebrating by blending in what sounds like a truly fantastic new update. Fans of Cthulhu rejoice, as Whispering Mist brings some horror elements, and tests... | Read more »
Summon your guild and prepare for war in...
Netmarble is making some pretty big moves with their latest update for Seven Knights Idle Adventure, with a bunch of interesting additions. Two new heroes enter the battle, there are events and bosses abound, and perhaps most interesting, a huge... | Read more »
Make the passage of time your plaything...
While some of us are still waiting for a chance to get our hands on Ash Prime - yes, don’t remind me I could currently buy him this month I’m barely hanging on - Digital Extremes has announced its next anticipated Prime Form for Warframe. Starting... | Read more »
If you can find it and fit through the d...
The holy trinity of amazing company names have come together, to release their equally amazing and adorable mobile game, Hamster Inn. Published by HyperBeard Games, and co-developed by Mum Not Proud and Little Sasquatch Studios, it's time to... | Read more »
Amikin Survival opens for pre-orders on...
Join me on the wonderful trip down the inspiration rabbit hole; much as Palworld seemingly “borrowed” many aspects from the hit Pokemon franchise, it is time for the heavily armed animal survival to also spawn some illegitimate children as Helio... | Read more »
PUBG Mobile teams up with global phenome...
Since launching in 2019, SpyxFamily has exploded to damn near catastrophic popularity, so it was only a matter of time before a mobile game snapped up a collaboration. Enter PUBG Mobile. Until May 12th, players will be able to collect a host of... | Read more »
Embark into the frozen tundra of certain...
Chucklefish, developers of hit action-adventure sandbox game Starbound and owner of one of the cutest logos in gaming, has released their roguelike deck-builder Wildfrost. Created alongside developers Gaziter and Deadpan Games, Wildfrost will... | Read more »
MoreFun Studios has announced Season 4,...
Tension has escalated in the ever-volatile world of Arena Breakout, as your old pal Randall Fisher and bosses Fred and Perrero continue to lob insults and explosives at each other, bringing us to a new phase of warfare. Season 4, Into The Fog of... | Read more »
Top Mobile Game Discounts
Every day, we pick out a curated list of the best mobile discounts on the App Store and post them here. This list won't be comprehensive, but it every game on it is recommended. Feel free to check out the coverage we did on them in the links below... | Read more »

Price Scanner via MacPrices.net

Free iPhone 15 plus Unlimited service for $60...
Boost Infinite, part of MVNO Boost Mobile using AT&T and T-Mobile’s networks, is offering a free 128GB iPhone 15 for $60 per month including their Unlimited service plan (30GB of premium data).... Read more
$300 off any new iPhone with service at Red P...
Red Pocket Mobile has new Apple iPhones on sale for $300 off MSRP when you switch and open up a new line of service. Red Pocket Mobile is a nationwide MVNO using all the major wireless carrier... Read more
Clearance 13-inch M1 MacBook Airs available a...
Apple has clearance 13″ M1 MacBook Airs, Certified Refurbished, available for $759 for 8-Core CPU/7-Core GPU/256GB models and $929 for 8-Core CPU/8-Core GPU/512GB models. Apple’s one-year warranty is... Read more
Updated Apple MacBook Price Trackers
Our Apple award-winning MacBook Price Trackers are continually updated with the latest information on prices, bundles, and availability for 16″ and 14″ MacBook Pros along with 13″ and 15″ MacBook... Read more
Every model of Apple’s 13-inch M3 MacBook Air...
Best Buy has Apple 13″ MacBook Airs with M3 CPUs in stock and on sale today for $100 off MSRP. Prices start at $999. Their prices are the lowest currently available for new 13″ M3 MacBook Airs among... Read more
Sunday Sale: Apple iPad Magic Keyboards for 1...
Walmart has Apple Magic Keyboards for 12.9″ iPad Pros, in Black, on sale for $150 off MSRP on their online store. Sale price for online orders only, in-store price may vary. Order online and choose... Read more
Apple Watch Ultra 2 now available at Apple fo...
Apple has, for the first time, begun offering Certified Refurbished Apple Watch Ultra 2 models in their online store for $679, or $120 off MSRP. Each Watch includes Apple’s standard one-year warranty... Read more
AT&T has the iPhone 14 on sale for only $...
AT&T has the 128GB Apple iPhone 14 available for only $5.99 per month for new and existing customers when you activate unlimited service and use AT&T’s 36 month installment plan. The fine... Read more
Amazon is offering a $100 discount on every M...
Amazon is offering a $100 instant discount on each configuration of Apple’s new 13″ M3 MacBook Air, in Midnight, this weekend. These are the lowest prices currently available for new 13″ M3 MacBook... Read more
You can save $300-$480 on a 14-inch M3 Pro/Ma...
Apple has 14″ M3 Pro and M3 Max MacBook Pros in stock today and available, Certified Refurbished, starting at $1699 and ranging up to $480 off MSRP. Each model features a new outer case, shipping is... Read more

Jobs Board

Omnichannel Associate - *Apple* Blossom Mal...
Omnichannel Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Operations Associate - *Apple* Blossom Mall...
Operations Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Cashier - *Apple* Blossom Mall - JCPenney (...
Cashier - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Blossom Mall Read more
IT Systems Engineer ( *Apple* Platforms) - S...
IT Systems Engineer ( Apple Platforms) at SpaceX Hawthorne, CA SpaceX was founded under the belief that a future where humanity is out exploring the stars is Read more
*Apple* Systems Administrator - JAMF - Activ...
…**Public Trust/Other Required:** None **Job Family:** Systems Administration **Skills:** Apple Platforms,Computer Servers,Jamf Pro **Experience:** 3 + years of Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.