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
#include
#include
#include
#include
#include
#include
#include
#include
#include
/* 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