TweetFollow Us on Twitter

Rom Ref DA
Volume Number:3
Issue Number:10
Column Tag:Advanced Mac'ing

Rom Reference DA for Inside Mac in C

By Frank Alviani, Contributing Editor, Odesta Corp. MPW Guru

Wearing out yer copy of IM?

After you’ve been programming the Mac for a while, you find that you’re starting to wear out your copy of Inside Macintosh. It’s not that you’re looking up the hundreds of calls in order to figure out what they do, it’s just that no human being can remember that many parameter sequences. With the storage capacity available nowadays, this is rather silly - we should be letting the Mac do the lookup for us - and that is exactly the purpose of the ROMRef DA.

This desk acccessory is NOT a help facility (altho one could be built from it rather easily) but only a compilation of the format for every call in volumes 1-3 of IM. The advantage is that looking up a call places a copy of the call, with all parameters, directly on the clipboard, where it can be simply pasted into the program.

I used the Clock DA by Don Melton as a skeleton for ROMRef, and it proved mighty helpful; thanks oodles, Don!! Two versions are included: one operates in ‘C’ format, while the other is in Pascal format. The ‘C’ version is set up to put the calls in the format used by Consulair C (4.53 was used to develop this), while the Pascal version is non-specific (I don’t work in Pascal).

Operation: is quite simple. The data file should be in the “blessed folder” or with the editor. When the DA is invoked, it puts a menu up. Select “Lookup” and a selection box appears listing all of the toolbox managers in alphabetical order:

Fig. 1 Our own RomRef Data Base Manager!

Once you have selected a manager, a second window is displayed with all of the calls for that manager again listed in alphabetical order:

When a call is selected, any of the 1st four buttons on the right will place the call on the clipboard. Either of the accept buttons will cause the call to replace the former contents; either of the append buttons will cause the call to be appended to the previous contents. The “continue” option allows you to return to the manager selection window for another call.

Fig. 2 Getting the rom call on the clipboard

Two entries on the menu affect how the call will be formatted on the clipboard. “Show Memory Mashers” causes a comment to be placed before the call if the call selected can possibly cause memory to be re-arranged. “Disable Typecasting” is available because the default is to have every variable in a call shown with its type; you may not always want this.

Internals: This DA does NOT use the list manager, since I wanted it to work with 64K ROM machines. It turned out to be very illuminating about how to work with (and around) the dialog manager.

One advantage of the approach taken by Don’s DA is in the simplicity of debugging. The locking of the DA when a menu routine is invoked allowed me to debug exactly as if it were a normal application, with the code locked in the heap. Having function names embedded by the compiler allowed TMON (best thing since peanut butter on hot toast!) to work to its fullest and kept me from going absolutely berserk in the early stages. I found that the scrolling selection window was the most complex part of the program to debug. I used the DA Sampler for testing.

Dialog windows within a Desk Accessory: are almost identical to those in a normal application except for one subtlety that drove me crazy for several days...

Macintosh Revealed mentions a bit in the event record that is used to indicate to an application if a DA window has just closed. According to Apple, applications should not depend on this - but MacWrite does! (it crashed with the famed ID=02 bomb every time I closed a ROMRef window..) Therefore, I have to set the windowType field of the dialog box window record to “dialogKind” when starting processing (so the Dialog Manager will recognize it) and reset it to a DA window just before closing the window (so application programs won’t croak in surprize). With the windowType fields properly set, ROMRef now works with all of the editors I have tried it with, including MacWrite and MacAuthor. (For unknown reasons I honestly haven’t pursued, Word doesn’t crash, but ROMRef doesn’t affect its clipboard after the first lookup. If you do all your program editing in Word and track this down, please let me know what’s wrong)

Scrollbars within the Dialog Manger: The scrolling selection window is composed of two user items: the text box and the scrollbar box. The scrollbar is declared to RMaker as a user item and actually created in the application with NewControl. Using a scrollbar within the dialog manager turns out to be a truly awesome pain-in-the-touche, whereas simply using the dialog manager to detect a click in the scrollbar rectangle becomes very easy to deal with.

When a click is detected within the scrollbar box, we simply use GetMouse() to retrieve the current position of the mouse, and use the standard control manager functions. The list being displayed is a text edit record (CRs end lines) and so the amount to scroll is a simple function of number-of-lines-scrolled times the lineheight.

One matter that added a little complexity to scrolling was dealing with trying to scroll beyond the limits of the list. The scrollbar maximum is set so that the bottom line of the list is at the bottom of the window; however, you must be aware of when you’re at the limits and ignore attempts to scroll further.

A filter function is used to deal with keyboard events. The cursor keys on a Mac+ keyboard work as expected, and typing an alphabetic character causes the DA to start searching the list for the first entry starting with that character (or the first entry following if necessary). I don’t have full type-ahead, as in the standard file selection box, but this was easy to implement and still useful. As per the user interface guidelines, the enter and return keys return the “accept” button.

The same lookup routine is used for both dialog windows and can easily be extracted for general use elsewhere; I’ve already adapted it for multiple use in an application I’me working on professionally.

Data Management: Since the actual processing in the DA is rather simple, how to manage the tons of data became the real challenge. After discarding several fairly complex indexing schemes initially, I settled on using the Resource Manager, which worked out nicely. There are 3 basic resource types involved:

(1) Name Lists: The list of manager names, and the lists of routine names in each manager, are stored as ‘ROMN’ resources.

(2) ROM Calls: Each ROM call is stored as a ‘ROMC’ resource. Each variable is prefixed by its type in a simple condensed format.

(3) Abbreviations: This is the list of expansions for each of the data type abbreviations used in the ROM calls.

Since we are dealing with a large number of resources (there are 640 calls in the data file, plus the name lists) and the data had to be as compact as possible if it was going to be useful, I used several tricks to save space.

At the start of a ROMN (name list) resource, before the text data, there are 2 16-bit integers. The first gives the number of lines in the data; this is convenient for setting the scrollbar maximum. The second field gives the starting resource number for the calls listed. The calls for a manager are numbered sequentially from the number listed in the ROMN resource, so the resource ID for a call is simply its relative position in the list plus the “base” resource number. This avoided having to store the resource ID with each individual name (and saved about 1.5K). It also means that additional calls and managers can be added at any time; simply choose an “unused” range for the new manager.

ROM Call Formatting: As mentioned above, the ROM call prototypes are stored in a simple compressed format. Each call is preceeded by a 1-byte flags field; currently, all it indicates is whether or not the call is a “memory masher”.

Abbreviations in a call are indicated by bytes with a value of $80 or more. These abbreviations fall into 2 classes: $80 - $BF are non-VAR datatypes, while the range of $C0 - $FF is identical to the lower range, but are considered VAR types. An abbrev- iation is shifted to the range $0-$3F and used to index into a table; this table is simply a “rom abbreviation” (ROMA) resource that was loaded during initialization and detached.

The expansion of an abbreviation is the only difference between the ‘C’ and Pascal versions (other than the names of the datafiles opened). Being initially written for ‘C’, the processing is simpler for that: simply look up the abbreviation and substitute, formatting it as (type *) if it is a ‘var’ variable. The expansion for Pascal is more complex, since the VAR and datatype are on opposite ‘ends’ of the variable name.

Clipboard manipulation: this is pretty conventional, except for the appendScrap function. This assumes there is only 1 data type on the clipboard. Following the data type (a 4 byte field) is the length; I copy the existing text to a working buffer, append the new text, and copy the new text back to the scrap, updating the length. Simply doing 2 PutScraps will append the text, but not update the length, making the new text unaccesable. It would not be much more complicated to deal with multiple data types on the clipboard.

Data File Construction: This was, not surprisingly, the most laborious part of the project, and changed several times while under construction.

Heavy use is made of macros and assembler variables. Macros are created for each datatype, and generate the abbrev- iation byte preceeding each formal parameter. Changing the text in the ROMA resource corresponding to a given macro will change the expansion. I wasn’t entirely consistant with some of the subtly different (but functionally identical) datatypes, since the typecasting is generally only a reminder and not left in the working program.

Assembler variables are used to automatically generate the resource IDs in ascending sequence; the variable at the beginning of a sequence is set to allow for “pre-incrementing”.

The sources for the data file are for the ‘C’ format calls. The only real difference between the ‘C’ and Pascal forms is that Consulair ‘C’ requires all structures to be referenced by pointers, even those that are not VAR variables in the Pascal sense. Thus, converting the data file to Pascal conventions will simply involve removing the VAR status of most structures and rebuilding.

Construction: is fairly conventional. The DA is built exactly as in Don Melton’s article, using his files (with 1 header file renamed to reflect a change between Consulair versions). See MacTutor Vol. 2 No. 4 (April, 1986).

The data files are in assembler; they are assembled and then linked to form the final data file. Assembling the data files is quick, but linking seems to take forever. On a Mac+ with no RAM disk, linking the data file takes 8 minutes, although the assembly only takes about 1. Don’t worry...

Miscellaneous: I want to thank Don Melton again for his DA article; I had been having no luck with DAs until then. I also want to highly recommend MEdit, by Mathias Aebi; it allows you to build editing macros to automate repetitive tasks. When I decided to change approaches to the data file, it allowed me to reformat about 80K of source in less than 1 hour!

It should not be difficult to adapt ROMRef into an online help facility for the toolbox. After the routine had been selected, the routine that currently expands the rom call would bring up a small dialog box and display the help text instead. I think the text would be rather terse, since the amount involved would be even larger than the current file; most likely, a hard disk would be required to work with adequate information. A different set of abbreviations could be built to compress the most common words in the database, and the ‘VAR’ mechanism would be un-needed. If anyone does use ROMRef to build such a DA, please put it out for the public to use!!

/*  A ROM Reference Desk Accessory  */
/*          Frank Alviani           */
/*           Version 1.1            */
/*       8:36:39 PM  8/5/86         */
/*                                  */
/*  Thanks to Don Melton for making */
/*  this a whole bunch easier!      */

#Options R=4 Z K
#include <MacDefs.h>
#include <QuickDraw.h>
#include <Control.h>
#include <TextEdit.h>
#include <Dialog.h>
#include <Menu.h>
#include <Events.h>
#include <Desk.h>
#include <DeskAccessory.c>
#include <Resource.h>

/* MODIFIED DEFINITIONS

*** IMPORTANT *** Other alternate elements of the OpParamType union structure 
are not defined here!!!

The CntrlParam structure also must be defined because OSIO.h is not included. 
However, it remains unaltered. */

#define OsType long
union __OP
    { 
    struct
        {
        short menuID;
        short menuItem;
        } menuData;
    Ptr event;
    };

#define OpParamType union __OP

struct __CP
    {
    struct __CP *ioLink;
    short ioType;
    short ioTrap;
    Ptr ioCmdAddr;
    ProcPtr ioCompletion;
    short ioResult;
    char *ioNamePtr;
    short ioVRefNum;
    short ioRefNum;
    short CSCode;
    OpParamType csp;
    };

#define CntrlParam struct __CP

typedef struct
    {
    char typeName[4];
    } ResType;

typedef struct {
long        scrapSize;
Handle      scrapHandle;
short       scrapCount;
short       scrapState;
char        *scrapName;
} ScrapStuff, *ScrapStuffPtr;

#define NULL 0
#define FALSE 0
#define TRUE 1
#define geneva      3
#define NAMES_IN_BOX 7
#define TIX ((long *) 0x16A)

#define ACCEPT 1
#define ACCEPT_CONT 2
#define APPEND 3
#define APPEND_CONT 4
#define CANCEL 5
#define NBOX 7
#define SBAR 8

#define FRONT_WINDOW -1

/* SETUP DA HEADER AND GLUE ROUTINES
*** IMPORTANT *** Invoke this macro BEFORE declaring any global variables 
or defining any Mac C functions!!!

Macro parameters:
    1       Name of desk accessory (enclose text in single quotes)
    2       Resource ID of desk accessory (12-31 inclusive)
    3       Flags
    4       Delay
    5       Event Mask
    6       Request for global variable allocation: NeedGlobals or NoGlobals
*/

#asm

 DeskAccessory ‘ROM Ref’,12,$0400,0,$0142,NeedGlobals

#endasm

/* GLOBAL VARIABLES */
short     ownedID;
short     no_casting; /* 0=typecast 1=don’t typecast */
short     mem_mash;   /* 1=include comment */
short      selection;
MenuHandle hRRMenu;
DialogPtr  abtDlgPtr, mgrDlgPtr, rtnDlgPtr;
long       lastClick;
short      lastPick;     /* double-click test */
short      data_refNum;  /* vol ref num data file */
short      old_v;        /* for arrow-scrolling */
ControlHandle   rtnScrlH, namScrlH; 
 /* scroll bar in routine window */
ControlHandle   vScrlH;   
 /* “generic” for ModalDialog filterProc */
Handle   abTblH;   /* handle to abbreviation table */
TEHandle hTE;      /* for names selection routine */
Rect     textR, TERect;
char     call[256];    /* sample here */
ScrapStuffPtr   sInfo;

/*~Open/Close/Control~ -- Open Routine -- */
short open(pb, dce)
CntrlParam      *pb;
DeviceControl   *dce;
{
GrafPtr         oldPort;
short           item, type, err, def_vol;
ControlHandle   ctlH;
Ptr             tPtr;
short           pbCall();

 ownedID = 0xC000 - (32 * (1 + dce->dCtlRefNum));
 dce->dCtlMenu = ownedID;

  if (!dce->dCtlWindow)
   { hRRMenu = GetMenu(ownedID);
     HNoPurge(hRRMenu);

     if (!(mgrDlgPtr = (DialogPtr) NewPtr(sizeof(DialogRecord))))
          return -1;
     mgrDlgPtr = GetNewDialog(ownedID, mgrDlgPtr, FRONT_WINDOW);
     GetDItem(mgrDlgPtr, SBAR, &type, &namScrlH, &textR);  /* scrollbar 
*/
     namScrlH = NewControl(mgrDlgPtr, &textR, “\px”, FALSE, 0, 0, 0, 
scrollBarProc, 0); 
     if (!(rtnDlgPtr = (DialogPtr) NewPtr(sizeof(DialogRecord))))
          return -1;
     rtnDlgPtr = GetNewDialog(ownedID+1, rtnDlgPtr, FRONT_WINDOW);   
 
     GetDItem(rtnDlgPtr, SBAR, &type, &rtnScrlH, &textR);  /* scrollbar 
*/
     rtnScrlH = NewControl(rtnDlgPtr, &textR, “\px”, FALSE, 0, 0, 0, 
scrollBarProc, 0);  
     GetDItem(rtnDlgPtr, NBOX, &type, &ctlH, &textR);  /* get scrollBOX 
rect */
     TERect = textR;
     InsetRect(&TERect, 2, 2);
     if (!(abtDlgPtr = (DialogPtr) NewPtr(sizeof(DialogRecord))))
          return -1;
     abtDlgPtr = GetNewDialog(ownedID+2, abtDlgPtr, FRONT_WINDOW);
        /* open data file */ 
     if ((data_refNum = OpenResFile(“\pRom Reference Data”)) == -1)
          return -1;
     if ((abTblH = GetResource(‘ROMA’, 1)) == NULL)   /* get abb. table 
*/
          return -1;
     no_casting = 0; mem_mash = 0;
     activate();
  }
  return 0;
}

/* -- Close -- */
short close(pb, dce)
CntrlParam      *pb;
DeviceControl   *dce;
{
    deActivate();
    ReleaseResource(hRRMenu);
    ReleaseResource(abTblH);
    DisposeDialog(mgrDlgPtr);
    DisposeDialog(rtnDlgPtr);
    DisposeDialog(abtDlgPtr);
    dce->dCtlWindow = (WindowPtr) NULL;
    CloseResFile(data_refNum);  /* close data file */
    return 0;
}

/* -- Control -- */
short control(pb, dce)
CntrlParam      *pb;
DeviceControl   *dce;
{
EventRecord     *theEvent;

    switch (pb->CSCode)
      { case accEvent:
          theEvent = (EventRecord *) pb->csp.event;
          if (theEvent->what ==activateEvt)
              if (theEvent->modifiers & activeFlag)
                activate();
          break;
        case accMenu:
          doMenu(pb, pb->csp.menuData.menuItem, dce);
          break;
    }
  return 0;
}

activate()
{
  (*hRRMenu)->menuID = ownedID;
  InsertMenu(hRRMenu, 0);
  DrawMenuBar();
}

deActivate()
{
    DeleteMenu(ownedID);
    DrawMenuBar();
}

/*~Menu Stuff~ -- Handle Menu Invocations -- */
doMenu(pb, menuItem, dce)
CntrlParam      *pb;
short           menuItem;
DeviceControl   *dce;
{
short       theItem;
GrafPtr     tGPtr;

    switch (menuItem)
      { case 1:     /* ABOUT */
       dce->dCtlFlags &= 0xFBFF; /* clear dCtlEnable */
       dce->dCtlFlags ^= 0x4000; /* set dNeedLock */

       ((WindowPeek) abtDlgPtr)->windowKind = 2;  /* dialogkind */
       ShowWindow(abtDlgPtr);
       BringToFront(abtDlgPtr);
       SetPort(abtDlgPtr);
       ModalDialog(NULL, &theItem);
       ((WindowPeek) abtDlgPtr)->windowKind = dce->dCtlRefNum;
       HideWindow(abtDlgPtr);

       dce->dCtlFlags ^= 0x0400; /* set dCtlEnable */
       dce->dCtlFlags &= 0xBFFF; /* clear dNeedLock */
          break;
      case 2:     /* LOOKUP CALLS */
       dce->dCtlFlags &= 0xFBFF; /* clear dCtlEnable */
       dce->dCtlFlags ^= 0x4000; /* set dNeedLock */

       findRtn(dce);

       dce->dCtlFlags ^= 0x0400; /* set dCtlEnable */
       dce->dCtlFlags &= 0xBFFF; /* clear dNeedLock */
          break;
      case 3:     /* DISABLE TYPECASTING */
       if (no_casting)       /* was NO, now YES */
          { no_casting = 0;
            CheckItem(hRRMenu, 3, FALSE);
          }
        else
          { no_casting = 1;
            CheckItem(hRRMenu, 3, TRUE);
          }
         break;
      case 4:     /* INCLUDE ‘MASHES MEMORY’ COMMENT */
          if (mem_mash)
            { mem_mash = 0;
              CheckItem(hRRMenu, 4, FALSE);
            }
          else
            { mem_mash = 1;
              CheckItem(hRRMenu, 4, TRUE);
            }
          break;
        case 5:     /* CLOSE */
          close(pb, dce);
          break;
      }
    HiliteMenu(0);
}

/*~Lookup Code~ -- Heart of the DA -- */
findRtn(dce)
DeviceControl   *dce;
{
short       the_manager, item, base_res_no, pick;
long        scrap_err, call_len;
short       BoxPick();

  get_mgr:
    /* use “select manager” dialog */
    dce->dCtlWindow = 0;
    /* get titles for selected manager */
    SetPort(mgrDlgPtr);
    item =  BoxPick(mgrDlgPtr, namScrlH, 99, &the_manager, &base_res_no);
    HideWindow(mgrDlgPtr);
    if (item == CANCEL) return;
      
    /* get titles for selected manager */
    SetPort(rtnDlgPtr);
    item =  BoxPick(rtnDlgPtr, rtnScrlH, the_manager+1, &pick, &base_res_no);
    if (item < CANCEL )
      { expandCall(base_res_no+pick, &call_len);
        if (call_len)
          { if (item < APPEND )
              { ZeroScrap();
                scrap_err = PutScrap((long) call_len, ‘TEXT’, call);
              }
            else
              AppendScrap((long) call_len, ‘TEXT’, call);
          }
      }

    ((WindowPeek) rtnDlgPtr)->windowKind = dce->dCtlRefNum;
    HideWindow(rtnDlgPtr);

    if (item == ACCEPT_CONT || item == APPEND_CONT)     
 /* keep it up! */
      goto get_mgr;
}

/* -- assumes port is properly set before entry -- */
   /* -- returns item_no from modal dialog box -- */
short BoxPick(dPtr, scrlH, resNo, sel, base)
DialogPtr       dPtr;
ControlHandle   scrlH;
short           resNo;
short           *sel;   /* zero-based! */
short           *base;
{
short       filter();
Handle      nameListH;  /* handle to names-list res */
long        call_len, nameList_len, ticks;
short       res_ct, done, item, l_no, sel_st, sel_en;
Point       pt;

  if ((nameListH = GetResource(‘ROMN’, resNo)) == NULL)
      { SysBeep(60);
        return CANCEL;
      }
    nameList_len = SizeResource(nameListH);
    HLock(nameListH);
    res_ct = *((short *) *nameListH);   
 /* ct of call resources */
    *base = *((short *) *nameListH+1);  
 /* starting call res # is 2nd short! */

    hTE = TENew(&TERect, &TERect);
    (*hTE)->txFont = geneva;
    (*hTE)->crOnly = -1;        /* CR breaks only */
    (*hTE)->txSize = 12;
    TESetText(*nameListH+4, nameList_len-4, hTE);
    TECalText(hTE);
    TESetSelect((*hTE)->lineStarts[0], (*hTE)->lineStarts[1], hTE);

    ((WindowPeek) dPtr)->windowKind = 2;
    ShowWindow(dPtr);
    BringToFront(dPtr);
    FrameRect(&textR.top);
    TEUpdate(&TERect.top, hTE);
    TEActivate(hTE);
    ShowControl(scrlH);
    SetCtlMin(scrlH, 0);
    if ((*hTE)->nLines > NAMES_IN_BOX)   
 /* set up scrollbar */
      SetCtlMax(scrlH, (*hTE)->nLines-NAMES_IN_BOX);
    else
      SetCtlMax(scrlH, 0);
    SetCtlValue(scrlH, 0);

    done = FALSE; selection=0;
    old_v = 0;
    vScrlH = scrlH;
    while (!done)
      { ModalDialog(filter, &item);   
 /* filter for keystrokes only */
        switch (item)
          { case ACCEPT:
            case ACCEPT_CONT:
            case APPEND:
            case APPEND_CONT:
            case CANCEL:
              done = TRUE;
              break;
            case NBOX:
              GetMouse(&pt);
              ticks = *TIX;
              l_no = (pt.v - textR.top) / (*hTE)-> lineHeight; /* relative 
line# */
              selection = GetCtlValue(scrlH) + l_no;
              if ((lastClick + 30) > ticks)
                { item = ACCEPT;  
 /* double click in same item */
                  done = TRUE;
                  break;
                }
              sel_st = (*hTE)->lineStarts[selection];
              if (selection >= res_ct)
                sel_en = 32767;
              else
                sel_en=(*hTE)->lineStarts[selection+1];
              TESetSelect(sel_st, sel_en, hTE);
              TEActivate(hTE);
              lastPick = selection;
              lastClick = ticks;
              break;
            case SBAR:
              nameScroll(dPtr);
              break;
          }
      }
    TEDispose(hTE);
    HUnlock(nameListH);
    ReleaseResource(nameListH);
    *sel = selection;
    return item;
}

/* -- Append to scrap,updating scrapCount-Memory Only -- */
/* assumes only 1 data type in desk scrap */
AppendScrap(len, type, str)
long        len;
long        type;   /* 4-char string */
char        *str;
{
long        sSize, dSize;

        sInfo = (ScrapStuffPtr)0x960;
        if (sInfo->scrapState <= 0) return;     
 /* can’t do anything */
        sSize = GetHandleSize(sInfo->scrapHandle);
        dSize = *((long *)(*sInfo->scrapHandle) + 1);   
 /* get existing len */
        SetHandleSize(sInfo->scrapHandle, sSize + len); 
 /* make room */
       *((long *)(*sInfo->scrapHandle) + 1) = dSize + len;
   BlockMove(str, (*sInfo->scrapHandle + 8 + dSize), len);
}

/*~Scrolling~ -- Filter Events, Handle Scrolling, etc. -- */
short filter(dPtr, ePtr, item)
DialogPtr       dPtr;
EventRecord     *ePtr;
short           *item;
{
#asm
    link        A6,#0           ;no locals
    movem.l     D1-D2,-(sp)     ;save
    move.l      16(A6),D0
    move.l      12(A6),D1
    move.l      8(A6),D2
    jsr         md_filter       ;call C routine
    movem.l     (SP)+,D1-D2
    unlk        A6
    move.l      (SP)+,A0        ;return addr
    add.l       #12,sp
    move.b      D0,(SP)         ;return condition
    jmp         (A0)
#endasm
}

/* uses global “vScrlH” to access vertical scrollbar in MD window */
short md_filter(dPtr, ePtr, item)
DialogPtr       dPtr;
EventRecord     *ePtr;
short           *item;
{
short           part, new_v, i, j, k, dV;
short           sel_st, sel_en, delta;
char            ch, ch2, key;
Ptr             tPtr, base;
short           nameScroll();

    switch(ePtr->what)
      { case mouseDown:
          return FALSE; /* handle normally */
          break;
        case autoKey:
        case keyDown:   /* select by 1st letter, cursor keys, etc. */
          ch = ePtr->message & 0xFF;
          if (ch==0x03 || ch==0x0D)   /* ent or ret */
            { *item = 1;    /* accept */
              return TRUE;
            }
          /* check for up/down arrow keys */
          if (old_v <= GetCtlMax(vScrlH))   
 /* don’t update if in last paneful */
            old_v = GetCtlValue(vScrlH);
          j = GetCtlMax(vScrlH);
          TEDeactivate(hTE);
          TESetSelect(0, 0, hTE);
          key = (ePtr->message & 0xFF00) >> 8;
          if (key == 0x4D) /* up arrow on Mac+ */
            { i = old_v-1;
              if (i < 0) i = 0;
              goto qa1;
            }
          if (key == 0x48) /* down arrow on Mac+ */
            { i = old_v + 1;
              goto qa1;
            }
/* look up 1st entry starting with given key or higher */
          ch &= (~0x20);   /* force uppercase */
          HLock((*hTE)->hText);     
 /* lock text for examination */
          base = *(*hTE)->hText;
          for (i=0;i<j;i++)
            { tPtr = base + (*hTE)->lineStarts[i];
              ch2 = *tPtr & (~0x20);    
 /* 1st char of line, upper-cased */
              if (ch2 >= ch)            
 /* found desired line */
                break;
            }
          HUnlock((*hTE)->hText);
        qa1:
          if (i <= j)   /* in normal range, scroll */
            { dV = (old_v - i) * (*hTE)->lineHeight;
              SetCtlValue(vScrlH, i);
              TEScroll(0, dV, hTE);
            }
          
          if (i >= GetCtlMax(vScrlH)+NAMES_IN_BOX)
            { i = GetCtlMax(vScrlH)+NAMES_IN_BOX-1;   
 /* can’t go too far */
              sel_en = 32767;
              k = (*hTE)->nLines-1;
              sel_st = (*hTE)->lineStarts[k];
            }
          else
            { sel_en = (*hTE)->lineStarts[i+1];
              sel_st = (*hTE)->lineStarts[i];
            }
          TESetSelect(sel_st, sel_en, hTE);
          old_v = i;
          selection = i;    
 /* in global so ACCEPT works */
          TEActivate(hTE);
          return TRUE;
          break;
        default:
          return FALSE;
          break;
      }
}

void nameScroll(dPtr)
DialogPtr   dPtr;
{
short           part, new_part, old_v, new_v, dV;
ControlHandle   ctlH;
Point           pt;
void            scroll_up(), scroll_dn();

    GetMouse(&pt);
    if (part = FindControl(&pt, dPtr, &ctlH))
      { old_v = GetCtlValue(ctlH);
        switch (part)
          { case inThumb:
              new_part = TrackControl(ctlH, &pt, NULL);
              if (new_part == part)   /* redraw box */
                { TEDeactivate(hTE);
                  new_v = GetCtlValue(ctlH);
                dV = (old_v - new_v) * (*hTE)->lineHeight;
                  TEScroll(0, dV, hTE);
                }
              break;
            case inUpButton:
              TrackControl(ctlH, &pt, scroll_up);
              break;
            case inDownButton:
              TrackControl(ctlH, &pt, scroll_dn);
              break;
            case inPageUp:
              new_v = old_v - (NAMES_IN_BOX-1);
              if (old_v-new_v < 0)
                { dV = old_v * (*hTE)->lineHeight;    
 /* stop at beginning */
                  SetCtlValue(ctlH, 0);
                }
              else
                { dV = (NAMES_IN_BOX-1) * (*hTE)->lineHeight;
                  SetCtlValue(ctlH, new_v);
                }
              TEScroll(0, dV, hTE);
              break;
            case inPageDown:
              new_v = old_v + (NAMES_IN_BOX-1);
              if (new_v > GetCtlMax(ctlH))
                { dV = -(GetCtlMax(ctlH) - old_v) * (*hTE)->lineHeight;
                  SetCtlValue(ctlH, GetCtlMax(ctlH));
                }
              else
                { dV = -(NAMES_IN_BOX-1) * (*hTE)->lineHeight;
                  SetCtlValue(ctlH, new_v);
                }
              TEScroll(0, dV, hTE);
              break;
          }
        selection = new_v = GetCtlValue(ctlH);
        TESetSelect((*hTE)->lineStarts[new_v], (*hTE)->lineStarts[new_v+1], 
hTE);
        TEActivate(hTE);
      }
}

void my_scroll_up(theControl, part)
ControlHandle   theControl;
short           part;
{
short   v;

    if (part == inUpButton)   /* */
      { v = GetCtlValue(theControl);
        if (v == 0) return;
        SetCtlValue(theControl, v-1);
        TEScroll(0, (*hTE)->lineHeight, hTE);
      }
    return;
#asm
scroll_up:
    MOVE.L  (SP)+,A0        ;RETURN
    MOVE.W  (SP)+,D1        ;PART
    MOVE.L  (SP)+,D0        ;CTL HANDLE
    MOVE.L  A0,-(SP)
    MOVEM.L A3-A4/D3-D7,-(SP)
    JSR     my_scroll_up
    MOVEM.L (SP)+,A3-A4/D3-D7
    RTS
#endasm
}

void my_scroll_dn(theControl, part)
ControlHandle   theControl;
short           part;
{
short   v;

    if (part == inDownButton)
      { v = GetCtlValue(theControl);
        if (v == GetCtlMax(theControl)) return;
        SetCtlValue(theControl, v+1);
        TEScroll(0, -(*hTE)->lineHeight, hTE);
      }
    return;
#asm
scroll_dn:
    MOVE.L  (SP)+,A0        ;RETURN
    MOVE.W  (SP)+,D1        ;PART
    MOVE.L  (SP)+,D0        ;CTL HANDLE
    MOVE.L  A0,-(SP)
    MOVEM.L A3-A4/D3-D7,-(SP)
    JSR     my_scroll_dn
    MOVEM.L (SP)+,A3-A4/D3-D7
    RTS
#endasm
}

/*~Prototype Expansion~ -- Resource -> usable call -- */
void expandCall(res_no, len)
short       res_no;
long        *len;
{
Handle      rHndl;
short       i, j, isVar;
long        rSize;
unsigned char   *rPtr, ch, abb[32];

    if ((rHndl = GetResource(‘ROMC’, res_no)) == NULL)
      { SysBeep(30);
         *len = 0; *call = NULL;
         return;
      }
    rSize = SizeResource(rHndl);
    HLock(rHndl);
    rPtr = (unsigned char *) *rHndl;
    HLock(abTblH);      /* lock abb. table */

    /* deal with “memory mashing” */
    j=0;
    if (mem_mash) 
      { if (*(rPtr++))   /* this one moves memory */
          appStr(“/* mashes memory */ “, call, &j)
      }
    else
      rPtr += 1;    /* just skip flag */

    for (i=1;i<rSize;i++)    
 /* copy into output, expanding abbreviations */
      { if (*rPtr < 0x80)   /* normal char */
          { call[j++] = *(rPtr++);
            continue;
          }
        if (no_casting == NULL)
          { if (*rPtr >= 0xC0)   /* “var” */
              { isVar = 1; ch = *rPtr - 0x40;
              }
            else
              { isVar = 0; ch = *rPtr;
              }
            call[j++] = ‘(‘;
            findabb(ch, abb);     /* lookup typecast */
            appStr(abb, &(call[j]), &j);
            if (isVar)
              { call[j++] = ‘ ‘; call[j++] = ‘*’;
              }
            call[j++] = ‘)’;
          }
        rPtr += 1;
      }

    appStr(“;\n”, &(call[j]), &j);
    *len = j;
    HUnlock(rHndl);
    HUnlock(abTblH);
    ReleaseResource(rHndl);
}

void appStr(src, target, tLen)
char    *src;    /* string copied FROM, null-terminated */
char    *target; /* string appended TO */
short   *tLen;   /* initial length of target; updated */
{
long    ct=0;
Ptr     tp;

    tp = src;
    while (*(tp++))
      ct++;
    BlockMove(src, target, ct);
    *tLen = *tLen + ct;
}

void findabb(c, dest)
unsigned char   c;
unsigned char   *dest;
{
short   i,j;
Ptr     tPtr;

    tPtr = *abTblH;
    j = c - 0x80;
    for (i=0;i<j;i++)
      while (*(tPtr++));
    while (*tPtr)
      *(dest++) = *(tPtr++);
    *dest = NULL;
}



*   Resource file for the ROM Ref DA
*   Frank Alviani
*   3:50:20 PM  6/6/86

RomRef_DA:Rels:RomRef.rsrc


* Menus
Type MENU
  ,-16000
ToolBox
About Myself..
Lookup Calls
Disable Typecasting
Show Memory Mashers
Close

*
*   Manager Selector box    (#1)
*
TYPE DLOG
  ,-16000
x
77 62 239 451 
InVisible NoGoAway
1 
0
-16000

TYPE DITL
  ,-16000
8
BtnItem Enabled
68 265 94 383 
Accept

BtnItem Enabled
*38 264 64 383
1000 1000 1001 1001
Accept/Continue

BtnItem Enabled
*68 265 94 383 
1000 1000 1001 1001
Append

BtnItem Enabled
*98 265 124 383 
1000 1000 1001 1001
Append/Continue

BtnItem Enabled
98 265 124 383 
Cancel

StatText Disabled
6 8 22 251 
Select a ROM Manager

* TextBox
UserItem Enabled
34 10 151 223 

* ScrollBox
UserItem Enabled
34 222 151 238 

*
*  Routine Selector box  (#2)
*
TYPE DLOG
  ,-15999
x
77 62 239 451 
InVisible NoGoAway
1 
0
-15999

TYPE DITL
  ,-15999
8
BtnItem Enabled
8 264 34 383 
Accept

BtnItem Enabled
38 264 64 383 
Accept/Continue

BtnItem Enabled
68 265 94 383 
Append

BtnItem Enabled
98 265 124 383 
Append/Continue

BtnItem Enabled
128 265 154 383 
Cancel

StatText Disabled
6 8 22 251 
Copy a sample call to the clipboard

* TextBox
UserItem Enabled
34 10 151 223 

* ScrollBox
UserItem Enabled
34 222 151 238 

*
*   About box   (#3)
*
type DLOG
,-15998
x
48 62 314 451 
InVisible NoGoAway
1
0
-15998

type DITL
,-15998
15
BtnItem Enabled
238 301 264 380 
OK!

StatText Disabled
10 69 26 319 
ROM Ref: Online Toolbox Call Samples

StatText Disabled
36 10 52 384 
ROM Ref allows you to put 1 or more sample ROM calls

StatText Disabled
52 10 68 384 
on the clipboard to be pasted directly into the program.

StatText Disabled
68 10 84 384 
When you select ‘lookup’, you are presented with a list

StatText Disabled
85 10 101 384 
of ROM managers.  When you pick one, a list of all the

StatText Disabled
101 10 117 384 
calls is presented. ‘Accept’ puts the selected call on the

StatText Disabled
118 10 134 384 
clipboard and quits;  ‘accept/continue’ then returns to 

StatText Disabled
135 10 151 384 
the manager list. ‘Append’ adds the selected call to the

StatText Disabled
152 10 168 384 
clipboard so several can be copied at once.  Typecasting

StatText Disabled
169 10 185 384 
can be disabled. A comment can be added for every call

StatText Disabled
186 10 202 384 
that can scramble memory.

StatText Disabled
215 10 231 106 
Frank Alviani

StatText Disabled
231 10 247 114 
425 McAlister

StatText Disabled
248 10 264 159 
Waukegan, Ill  60085
 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Latest Forum Discussions

See All

Summon your guild and prepare for war in...
Netmarble is making some pretty big moves with their latest update for Seven Knights Idle Adventure, with a bunch of interesting additions. Two new heroes enter the battle, there are events and bosses abound, and perhaps most interesting, a huge... | Read more »
Make the passage of time your plaything...
While some of us are still waiting for a chance to get our hands on Ash Prime - yes, don’t remind me I could currently buy him this month I’m barely hanging on - Digital Extremes has announced its next anticipated Prime Form for Warframe. Starting... | Read more »
If you can find it and fit through the d...
The holy trinity of amazing company names have come together, to release their equally amazing and adorable mobile game, Hamster Inn. Published by HyperBeard Games, and co-developed by Mum Not Proud and Little Sasquatch Studios, it's time to... | Read more »
Amikin Survival opens for pre-orders on...
Join me on the wonderful trip down the inspiration rabbit hole; much as Palworld seemingly “borrowed” many aspects from the hit Pokemon franchise, it is time for the heavily armed animal survival to also spawn some illegitimate children as Helio... | Read more »
PUBG Mobile teams up with global phenome...
Since launching in 2019, SpyxFamily has exploded to damn near catastrophic popularity, so it was only a matter of time before a mobile game snapped up a collaboration. Enter PUBG Mobile. Until May 12th, players will be able to collect a host of... | Read more »
Embark into the frozen tundra of certain...
Chucklefish, developers of hit action-adventure sandbox game Starbound and owner of one of the cutest logos in gaming, has released their roguelike deck-builder Wildfrost. Created alongside developers Gaziter and Deadpan Games, Wildfrost will... | Read more »
MoreFun Studios has announced Season 4,...
Tension has escalated in the ever-volatile world of Arena Breakout, as your old pal Randall Fisher and bosses Fred and Perrero continue to lob insults and explosives at each other, bringing us to a new phase of warfare. Season 4, Into The Fog of... | Read more »
Top Mobile Game Discounts
Every day, we pick out a curated list of the best mobile discounts on the App Store and post them here. This list won't be comprehensive, but it every game on it is recommended. Feel free to check out the coverage we did on them in the links below... | Read more »
Marvel Future Fight celebrates nine year...
Announced alongside an advertising image I can only assume was aimed squarely at myself with the prominent Deadpool and Odin featured on it, Netmarble has revealed their celebrations for the 9th anniversary of Marvel Future Fight. The Countdown... | Read more »
HoYoFair 2024 prepares to showcase over...
To say Genshin Impact took the world by storm when it was released would be an understatement. However, I think the most surprising part of the launch was just how much further it went than gaming. There have been concerts, art shows, massive... | Read more »

Price Scanner via MacPrices.net

Apple Watch Ultra 2 now available at Apple fo...
Apple has, for the first time, begun offering Certified Refurbished Apple Watch Ultra 2 models in their online store for $679, or $120 off MSRP. Each Watch includes Apple’s standard one-year warranty... Read more
AT&T has the iPhone 14 on sale for only $...
AT&T has the 128GB Apple iPhone 14 available for only $5.99 per month for new and existing customers when you activate unlimited service and use AT&T’s 36 month installment plan. The fine... Read more
Amazon is offering a $100 discount on every M...
Amazon is offering a $100 instant discount on each configuration of Apple’s new 13″ M3 MacBook Air, in Midnight, this weekend. These are the lowest prices currently available for new 13″ M3 MacBook... Read more
You can save $300-$480 on a 14-inch M3 Pro/Ma...
Apple has 14″ M3 Pro and M3 Max MacBook Pros in stock today and available, Certified Refurbished, starting at $1699 and ranging up to $480 off MSRP. Each model features a new outer case, shipping is... Read more
24-inch M1 iMacs available at Apple starting...
Apple has clearance M1 iMacs available in their Certified Refurbished store starting at $1049 and ranging up to $300 off original MSRP. Each iMac is in like-new condition and comes with Apple’s... Read more
Walmart continues to offer $699 13-inch M1 Ma...
Walmart continues to offer new Apple 13″ M1 MacBook Airs (8GB RAM, 256GB SSD) online for $699, $300 off original MSRP, in Space Gray, Silver, and Gold colors. These are new MacBook for sale by... Read more
B&H has 13-inch M2 MacBook Airs with 16GB...
B&H Photo has 13″ MacBook Airs with M2 CPUs, 16GB of memory, and 256GB of storage in stock and on sale for $1099, $100 off Apple’s MSRP for this configuration. Free 1-2 day delivery is available... Read more
14-inch M3 MacBook Pro with 16GB of RAM avail...
Apple has the 14″ M3 MacBook Pro with 16GB of RAM and 1TB of storage, Certified Refurbished, available for $300 off MSRP. Each MacBook Pro features a new outer case, shipping is free, and an Apple 1-... Read more
Apple M2 Mac minis on sale for up to $150 off...
Amazon has Apple’s M2-powered Mac minis in stock and on sale for $100-$150 off MSRP, each including free delivery: – Mac mini M2/256GB SSD: $499, save $100 – Mac mini M2/512GB SSD: $699, save $100 –... Read more
Amazon is offering a $200 discount on 14-inch...
Amazon has 14-inch M3 MacBook Pros in stock and on sale for $200 off MSRP. Shipping is free. Note that Amazon’s stock tends to come and go: – 14″ M3 MacBook Pro (8GB RAM/512GB SSD): $1399.99, $200... Read more

Jobs Board

Sublease Associate Optometrist- *Apple* Val...
Sublease Associate Optometrist- Apple Valley, CA- Target Optical Date: Apr 20, 2024 Brand: Target Optical Location: Apple Valley, CA, US, 92307 **Requisition Read more
*Apple* Systems Administrator - JAMF - Syste...
Title: Apple Systems Administrator - JAMF ALTA is supporting a direct hire opportunity. This position is 100% Onsite for initial 3-6 months and then remote 1-2 Read more
Relationship Banker - *Apple* Valley Financ...
Relationship Banker - Apple Valley Financial Center APPLE VALLEY, Minnesota **Job Description:** At Bank of America, we are guided by a common purpose to help Read more
IN6728 Optometrist- *Apple* Valley, CA- Tar...
Date: Apr 9, 2024 Brand: Target Optical Location: Apple Valley, CA, US, 92308 **Requisition ID:** 824398 At Target Optical, we help people see and look great - and Read more
Medical Assistant - Orthopedics *Apple* Hil...
Medical Assistant - Orthopedics Apple Hill York Location: WellSpan Medical Group, York, PA Schedule: Full Time Sign-On Bonus Eligible Remote/Hybrid Regular Apply Now Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.