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 youve been programming the Mac for a while, you find that youre starting to wear out your copy of Inside Macintosh. Its not that youre looking up the hundreds of calls in order to figure out what they do, its 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 dont 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 Dons 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 wont 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 havent pursued, Word doesnt crash, but ROMRef doesnt affect its clipboard after the first lookup. If you do all your program editing in Word and track this down, please let me know whats 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 youre 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 dont 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; Ive already adapted it for multiple use in an application Ime 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 wasnt 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 Meltons 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. Dont 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=dont 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;
/* cant 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))
/* dont 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;
/* cant 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