![](/file/12652/www.mactech.com.tar/www.mactech.com/sites/all/themes/custom_front/images/you_are_here_red.gif)
![](/file/12652/www.mactech.com.tar/www.mactech.com/sites/default/files/beta-site.gif)
|
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
![](/file/12652/www.mactech.com.tar/www.mactech.com/sites/all/themes/custom_front/img/search_text.gif)
- SPREAD THE WORD:
- Slashdot
- Digg
- Del.icio.us
- Newsvine