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

Tokkun Studio unveils alpha trailer for...
We are back on the MMORPG news train, and this time it comes from the sort of international developers Tokkun Studio. They are based in France and Japan, so it counts. Anyway, semantics aside, they have released an alpha trailer for the upcoming... | Read more »
Win a host of exclusive in-game Honor of...
To celebrate its latest Jujutsu Kaisen crossover event, Honor of Kings is offering a bounty of login and achievement rewards kicking off the holiday season early. [Read more] | Read more »
Miraibo GO comes out swinging hard as it...
Having just launched what feels like yesterday, Dreamcube Studio is wasting no time adding events to their open-world survival Miraibo GO. Abyssal Souls arrives relatively in time for the spooky season and brings with it horrifying new partners to... | Read more »
Ditch the heavy binders and high price t...
As fun as the real-world equivalent and the very old Game Boy version are, the Pokemon Trading Card games have historically been received poorly on mobile. It is a very strange and confusing trend, but one that The Pokemon Company is determined to... | Read more »
Peace amongst mobile gamers is now shatt...
Some of the crazy folk tales from gaming have undoubtedly come from the EVE universe. Stories of spying, betrayal, and epic battles have entered history, and now the franchise expands as CCP Games launches EVE Galaxy Conquest, a free-to-play 4x... | Read more »
Lord of Nazarick, the turn-based RPG bas...
Crunchyroll and A PLUS JAPAN have just confirmed that Lord of Nazarick, their turn-based RPG based on the popular OVERLORD anime, is now available for iOS and Android. Starting today at 2PM CET, fans can download the game from Google Play and the... | Read more »
Digital Extremes' recent Devstream...
If you are anything like me you are impatiently waiting for Warframe: 1999 whilst simultaneously cursing the fact Excalibur Prime is permanently Vault locked. To keep us fed during our wait, Digital Extremes hosted a Double Devstream to dish out a... | Read more »
The Frozen Canvas adds a splash of colou...
It is time to grab your gloves and layer up, as Torchlight: Infinite is diving into the frozen tundra in its sixth season. The Frozen Canvas is a colourful new update that brings a stylish flair to the Netherrealm and puts creativity in the... | Read more »
Back When AOL WAS the Internet – The Tou...
In Episode 606 of The TouchArcade Show we kick things off talking about my plans for this weekend, which has resulted in this week’s show being a bit shorter than normal. We also go over some more updates on our Patreon situation, which has been... | Read more »
Creative Assembly's latest mobile p...
The Total War series has been slowly trickling onto mobile, which is a fantastic thing because most, if not all, of them are incredibly great fun. Creative Assembly's latest to get the Feral Interactive treatment into portable form is Total War:... | Read more »

Price Scanner via MacPrices.net

Early Black Friday Deal: Apple’s newly upgrad...
Amazon has Apple 13″ MacBook Airs with M2 CPUs and 16GB of RAM on early Black Friday sale for $200 off MSRP, only $799. Their prices are the lowest currently available for these newly upgraded 13″ M2... Read more
13-inch 8GB M2 MacBook Airs for $749, $250 of...
Best Buy has Apple 13″ MacBook Airs with M2 CPUs and 8GB of RAM in stock and on sale on their online store for $250 off MSRP. Prices start at $749. Their prices are the lowest currently available for... Read more
Amazon is offering an early Black Friday $100...
Amazon is offering early Black Friday discounts on Apple’s new 2024 WiFi iPad minis ranging up to $100 off MSRP, each with free shipping. These are the lowest prices available for new minis anywhere... Read more
Price Drop! Clearance 14-inch M3 MacBook Pros...
Best Buy is offering a $500 discount on clearance 14″ M3 MacBook Pros on their online store this week with prices available starting at only $1099. Prices valid for online orders only, in-store... Read more
Apple AirPods Pro with USB-C on early Black F...
A couple of Apple retailers are offering $70 (28%) discounts on Apple’s AirPods Pro with USB-C (and hearing aid capabilities) this weekend. These are early AirPods Black Friday discounts if you’re... Read more
Price drop! 13-inch M3 MacBook Airs now avail...
With yesterday’s across-the-board MacBook Air upgrade to 16GB of RAM standard, Apple has dropped prices on clearance 13″ 8GB M3 MacBook Airs, Certified Refurbished, to a new low starting at only $829... Read more
Price drop! Apple 15-inch M3 MacBook Airs now...
With yesterday’s release of 15-inch M3 MacBook Airs with 16GB of RAM standard, Apple has dropped prices on clearance Certified Refurbished 15″ 8GB M3 MacBook Airs to a new low starting at only $999.... Read more
Apple has clearance 15-inch M2 MacBook Airs a...
Apple has clearance, Certified Refurbished, 15″ M2 MacBook Airs now available starting at $929 and ranging up to $410 off original MSRP. These are the cheapest 15″ MacBook Airs for sale today at... Read more
Apple drops prices on 13-inch M2 MacBook Airs...
Apple has dropped prices on 13″ M2 MacBook Airs to a new low of only $749 in their Certified Refurbished store. These are the cheapest M2-powered MacBooks for sale at Apple. Apple’s one-year warranty... Read more
Clearance 13-inch M1 MacBook Airs available a...
Apple has clearance 13″ M1 MacBook Airs, Certified Refurbished, now available for $679 for 8-Core CPU/7-Core GPU/256GB models. Apple’s one-year warranty is included, shipping is free, and each... Read more

Jobs Board

Seasonal Cashier - *Apple* Blossom Mall - J...
Seasonal Cashier - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Seasonal Fine Jewelry Commission Associate -...
…Fine Jewelry Commission Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) Read more
Seasonal Operations Associate - *Apple* Blo...
Seasonal Operations Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Read more
Hair Stylist - *Apple* Blossom Mall - JCPen...
Hair Stylist - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Blossom 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
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.