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

Whitethorn Games combines two completely...
If you have ever gone fishing then you know that it is a lesson in patience, sitting around waiting for a bite that may never come. Well, that's because you have been doing it wrong, since as Whitehorn Games now demonstrates in new release Skate... | Read more »
Call of Duty Warzone is a Waiting Simula...
It's always fun when a splashy multiplayer game comes to mobile because they are few and far between, so I was excited to see the notification about Call of Duty: Warzone Mobile (finally) launching last week and wanted to try it out. As someone who... | Read more »
Albion Online introduces some massive ne...
Sandbox Interactive has announced an upcoming update to its flagship MMORPG Albion Online, containing massive updates to its existing guild Vs guild systems. Someone clearly rewatched the Helms Deep battle in Lord of the Rings and spent the next... | Read more »
Chucklefish announces launch date of the...
Chucklefish, the indie London-based team we probably all know from developing Terraria or their stint publishing Stardew Valley, has revealed the mobile release date for roguelike deck-builder Wildfrost. Developed by Gaziter and Deadpan Games, the... | Read more »
Netmarble opens pre-registration for act...
It has been close to three years since Netmarble announced they would be adapting the smash series Solo Leveling into a video game, and at last, they have announced the opening of pre-orders for Solo Leveling: Arise. [Read more] | Read more »
PUBG Mobile celebrates sixth anniversary...
For the past six years, PUBG Mobile has been one of the most popular shooters you can play in the palm of your hand, and Krafton is celebrating this milestone and many years of ups by teaming up with hit music man JVKE to create a special song for... | Read more »
ASTRA: Knights of Veda refuse to pump th...
In perhaps the most recent example of being incredibly eager, ASTRA: Knights of Veda has dropped its second collaboration with South Korean boyband Seventeen, named so as it consists of exactly thirteen members and a video collaboration with Lee... | Read more »
Collect all your cats and caterpillars a...
If you are growing tired of trying to build a town with your phone by using it as a tiny, ineffectual shover then fear no longer, as Independent Arts Software has announced the upcoming release of Construction Simulator 4, from the critically... | Read more »
Backbone complete its lineup of 2nd Gene...
With all the ports of big AAA games that have been coming to mobile, it is becoming more convenient than ever to own a good controller, and to help with this Backbone has announced the completion of their 2nd generation product lineup with their... | Read more »
Zenless Zone Zero opens entries for its...
miHoYo, aka HoYoverse, has become such a big name in mobile gaming that it's hard to believe that arguably their flagship title, Genshin Impact, is only three and a half years old. Now, they continue the road to the next title in their world, with... | Read more »

Price Scanner via MacPrices.net

B&H has Apple’s 13-inch M2 MacBook Airs o...
B&H Photo has 13″ MacBook Airs with M2 CPUs and 256GB of storage in stock and on sale for up to $150 off Apple’s new MSRP, starting at only $849. Free 1-2 day delivery is available to most US... Read more
M2 Mac minis on sale for $100-$200 off MSRP,...
B&H Photo has Apple’s M2-powered Mac minis back in stock and on sale today for $100-$200 off MSRP. Free 1-2 day shipping is available for most US addresses: – Mac mini M2/256GB SSD: $499, save $... Read more
Mac Studios with M2 Max and M2 Ultra CPUs on...
B&H Photo has standard-configuration Mac Studios with Apple’s M2 Max & Ultra CPUs in stock today and on Easter sale for $200 off MSRP. Their prices are the lowest available for these models... Read more
Deal Alert! B&H Photo has Apple’s 14-inch...
B&H Photo has new Gray and Black 14″ M3, M3 Pro, and M3 Max MacBook Pros on sale for $200-$300 off MSRP, starting at only $1399. B&H offers free 1-2 day delivery to most US addresses: – 14″ 8... Read more
Department Of Justice Sets Sights On Apple In...
NEWS – The ball has finally dropped on the big Apple. The ball (metaphorically speaking) — an antitrust lawsuit filed in the U.S. on March 21 by the Department of Justice (DOJ) — came down following... Read more
New 13-inch M3 MacBook Air on sale for $999,...
Amazon has Apple’s new 13″ M3 MacBook Air on sale for $100 off MSRP for the first time, now just $999 shipped. Shipping is free: – 13″ MacBook Air (8GB RAM/256GB SSD/Space Gray): $999 $100 off MSRP... Read more
Amazon has Apple’s 9th-generation WiFi iPads...
Amazon has Apple’s 9th generation 10.2″ WiFi iPads on sale for $80-$100 off MSRP, starting only $249. Their prices are the lowest available for new iPads anywhere: – 10″ 64GB WiFi iPad (Space Gray or... Read more
Discounted 14-inch M3 MacBook Pros with 16GB...
Apple retailer Expercom has 14″ MacBook Pros with M3 CPUs and 16GB of standard memory discounted by up to $120 off Apple’s MSRP: – 14″ M3 MacBook Pro (16GB RAM/256GB SSD): $1691.06 $108 off MSRP – 14... Read more
Clearance 15-inch M2 MacBook Airs on sale for...
B&H Photo has Apple’s 15″ MacBook Airs with M2 CPUs (8GB RAM/256GB SSD) in stock today and on clearance sale for $999 in all four colors. Free 1-2 delivery is available to most US addresses.... Read more
Clearance 13-inch M1 MacBook Airs drop to onl...
B&H has Apple’s base 13″ M1 MacBook Air (Space Gray, Silver, & Gold) in stock and on clearance sale today for $300 off MSRP, only $699. Free 1-2 day shipping is available to most addresses in... Read more

Jobs Board

Senior Product Associate - *Apple* Pay (AME...
…is seeking a Senior Associate of Digital Product Management to support our Apple Pay product team. Labs drives innovation at American Express by originating, Read more
Medical Assistant - Surgical Oncology- *Apple...
Medical Assistant - Surgical Oncology- Apple Hill Location: WellSpan Medical Group, York, PA Schedule: Full Time Sign-On Bonus Eligible Remote/Hybrid Regular Apply Read more
Omnichannel Associate - *Apple* Blossom Mal...
Omnichannel Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
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
Operations Associate - *Apple* Blossom Mall...
Operations Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.