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

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... | Read more »
Price of Glory unleashes its 1.4 Alpha u...
As much as we all probably dislike Maths as a subject, we do have to hand it to geometry for giving us the good old Hexgrid, home of some of the best strategy games. One such example, Price of Glory, has dropped its 1.4 Alpha update, stocked full... | Read more »
The SLC 2025 kicks off this month to cro...
Ever since the Solo Leveling: Arise Championship 2025 was announced, I have been looking forward to it. The promotional clip they released a month or two back showed crowds going absolutely nuts for the previous competitions, so imagine the... | Read more »
Dive into some early Magicpunk fun as Cr...
Excellent news for fans of steampunk and magic; the Precursor Test for Magicpunk MMORPG Crystal of Atlan opens today. This rather fancy way of saying beta test will remain open until March 5th and is available for PC - boo - and Android devices -... | Read more »
Prepare to get your mind melted as Evang...
If you are a fan of sci-fi shooters and incredibly weird, mind-bending anime series, then you are in for a treat, as Goddess of Victory: Nikke is gearing up for its second collaboration with Evangelion. We were also treated to an upcoming... | Read more »
Square Enix gives with one hand and slap...
We have something of a mixed bag coming over from Square Enix HQ today. Two of their mobile games are revelling in life with new events keeping them alive, whilst another has been thrown onto the ever-growing discard pile Square is building. I... | Read more »
Let the world burn as you have some fest...
It is time to leave the world burning once again as you take a much-needed break from that whole “hero” lark and enjoy some celebrations in Genshin Impact. Version 5.4, Moonlight Amidst Dreams, will see you in Inazuma to attend the Mikawa Flower... | Read more »
Full Moon Over the Abyssal Sea lands on...
Aether Gazer has announced its latest major update, and it is one of the loveliest event names I have ever heard. Full Moon Over the Abyssal Sea is an amazing name, and it comes loaded with two side stories, a new S-grade Modifier, and some fancy... | Read more »
Open your own eatery for all the forest...
Very important question; when you read the title Zoo Restaurant, do you also immediately think of running a restaurant in which you cook Zoo animals as the course? I will just assume yes. Anyway, come June 23rd we will all be able to start up our... | Read more »
Crystal of Atlan opens registration for...
Nuverse was prominently featured in the last month for all the wrong reasons with the USA TikTok debacle, but now it is putting all that behind it and preparing for the Crystal of Atlan beta test. Taking place between February 18th and March 5th,... | Read more »

Price Scanner via MacPrices.net

AT&T is offering a 65% discount on the ne...
AT&T is offering the new iPhone 16e for up to 65% off their monthly finance fee with 36-months of service. No trade-in is required. Discount is applied via monthly bill credits over the 36 month... Read more
Use this code to get a free iPhone 13 at Visi...
For a limited time, use code SWEETDEAL to get a free 128GB iPhone 13 Visible, Verizon’s low-cost wireless cell service, Visible. Deal is valid when you purchase the Visible+ annual plan. Free... Read more
M4 Mac minis on sale for $50-$80 off MSRP at...
B&H Photo has M4 Mac minis in stock and on sale right now for $50 to $80 off Apple’s MSRP, each including free 1-2 day shipping to most US addresses: – M4 Mac mini (16GB/256GB): $549, $50 off... Read more
Buy an iPhone 16 at Boost Mobile and get one...
Boost Mobile, an MVNO using AT&T and T-Mobile’s networks, is offering one year of free Unlimited service with the purchase of any iPhone 16. Purchase the iPhone at standard MSRP, and then choose... Read more
Get an iPhone 15 for only $299 at Boost Mobil...
Boost Mobile, an MVNO using AT&T and T-Mobile’s networks, is offering the 128GB iPhone 15 for $299.99 including service with their Unlimited Premium plan (50GB of premium data, $60/month), or $20... Read more
Unreal Mobile is offering $100 off any new iP...
Unreal Mobile, an MVNO using AT&T and T-Mobile’s networks, is offering a $100 discount on any new iPhone with service. This includes new iPhone 16 models as well as iPhone 15, 14, 13, and SE... Read more
Apple drops prices on clearance iPhone 14 mod...
With today’s introduction of the new iPhone 16e, Apple has discontinued the iPhone 14, 14 Pro, and SE. In response, Apple has dropped prices on unlocked, Certified Refurbished, iPhone 14 models to a... Read more
B&H has 16-inch M4 Max MacBook Pros on sa...
B&H Photo is offering a $360-$410 discount on new 16-inch MacBook Pros with M4 Max CPUs right now. B&H offers free 1-2 day shipping to most US addresses: – 16″ M4 Max MacBook Pro (36GB/1TB/... Read more
Amazon is offering a $100 discount on the M4...
Amazon has the M4 Pro Mac mini discounted $100 off MSRP right now. Shipping is free. Their price is the lowest currently available for this popular mini: – Mac mini M4 Pro (24GB/512GB): $1299, $100... Read more
B&H continues to offer $150-$220 discount...
B&H Photo has 14-inch M4 MacBook Pros on sale for $150-$220 off MSRP. B&H offers free 1-2 day shipping to most US addresses: – 14″ M4 MacBook Pro (16GB/512GB): $1449, $150 off MSRP – 14″ M4... Read more

Jobs Board

All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.