brian@ut-sally.UUCP (Brian H. Powell) (12/25/85)
# This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # # Wrapped by sally!brian on Wed Dec 25 01:22:08 CST 1985 # Contents: Changes Bugs data.c rmaker.h crtdrvr.s crtproc.s rmaker.1 # rmaker.doc samp.rc test.rc echo x - Changes sed 's/^@//' > "Changes" <<'@//E*O*F Changes//' General improvements: Resources are now sorted by type & id. Previously, if you didn't group all of your resources together, some of them would silently disappear. Tabs are now considered whitespace. Whitespace is now allowed between the resource ID and the attributes, eg: Type FOO ,1 (20) \ escapes are recognized in all strings and titles. \HH is replaced by ascii code HH (where HH are 2 hex digits) \ followed by "anything else" is replace by "anything else". Thus, \\ is a backslash \' and \" permit quotes to be put in quoted string in type GNRL \<space> can be used to introduce a leading space in a title \<newline> turns into a blank line in STR# and POST string lists The syntax for including resources from other files has been modified to be compatible with IM. e.g.: Type FOO filename!resource name,1 (32) Portability: Htons and htonl are now machine independent. Fixed up many complaints from lint. Unfortunately, I got bored and didn't finish the job, so there are still lots of places where type 'int' is assumed to be 32 bits. Type DITL: ResCItem keyword now recognized. Used to require 2 blank lines after a UserItem. Now only 1. Case is no longer significant in recognizing keywords. BtnItem, btnitem, etc are all acceptable. At least 1 item type keyword must now be present for each item. \ escape sequences are now interpreted within item titles. Type WIND, DLOG, CNTL: There used to be no checking for the validity of keywords GoAway, NoGoAway, Visible, and Invisible. Previously, "goaway" was interpreted the same as "NoGoAway". Now the keywords are checked, and case is no longer significant. Type DLOG ignores leading whitespace in the dialog title. Type MENU: Now allows an optional menu definition id before the title. Type PICT added. Type PICT picture-file,1 Type FILE added. Reads a file into a resource. Replacement for Type ANYB, which is inconvenient to use in the normal case when you want to read the entire file. Type FILE file-name,1 Type GNRL added. Input is free format, with one or more tokens per line, except for strings following .S or .P. Input is terminated by the first blank line. .I succeeding number tokens are to be interpreted as decimal 16 bit integers .L following numbers are decimal, 32 bit .C following numbers are decimal, 8 bit .H following numbers are hexadecimal 'string' output the contained ascii characters "string" output the string in Pascal format, with a length byte .F filename interpolate the contents of the named file .S following lines contain strings without length bytes, up to a blank line or a line whose first non-blank character is '.' .P following lines contain pascal strings (with length byte) Notes: This implementation of GNRL is upward compatible with the Apple syntax, except that .B is unsupported (replaced by .F). To put a ' or " into a quoted string, use \' or \". To put an empty string into .S or .P, use a line containing only "\" If the first non-blank character of a string after .S or .P is ".", then you need to write "\." There is an implicit .I at the beginning of the input. If all of your numbers are 16 bit decimal format, you don't need to use .I anywhere. For example, Type BNDL = GNRL ,128 'SAMP' 0 1 'ICN#' 0 1 128 'FREF' 0 1 128 or if you restrict yourself to Apple syntax, Type BNDL = GNRL ,128 .S SAMP .I 0 1 .S ICN# .I 0 1 128 .S FREF .I 0 1 128 Type FREF added. Type BNDL added. @//E*O*F Changes// chmod u=rw,g=rw,o=r Changes echo x - Bugs sed 's/^@//' > "Bugs" <<'@//E*O*F Bugs//' A blank line is not tolerated after the item count in type DITL. In general, the Lisa Workshop rmaker is much more tolerant about blank lines, which are ignored everywhere except where they are specifically required. The usage: Type FOO ,1 ...whatever... ,2 ...whatever... is not recognized. Type GNRL does not support .B format. Then again, with .F, who cares. If a trailing blank is present on a type line, eg Type STR <- trailing blank then Sumacc will abort. This is because of a bug in scanf(). Perhaps it would be appropriate to strip trailing whitespace off each input line in getline(). Unimplemented types: PAT# FONT ANYB (Type FILE has been provided to perform the function of ANYB) Type ICN# is implemented the same as HEXA. I.M. says it is supposed to start with a field giving the number of icons. Types PAT, ICON and CURS do not check to see that their data contains the correct number of bytes. @//E*O*F Bugs// chmod u=rw,g=rw,o=r Bugs echo x - data.c sed 's/^@//' > "data.c" <<'@//E*O*F data.c//' /* * data.c * * Routines for preparing binary data for the output file. */ #include "rmaker.h" /* * "Host" to "Mac" byte order swappers. * (on the Mac, the high order byte of a word is stored first in memory, * the low order byte is stored last.) */ unsigned short htons(a) short a; { unsigned short result; register char *dp = (char *)&result; dp[0] = a >> 8; dp[1] = a; return result; } unsigned long htonl(a) long a; { unsigned long result; register char *dp = (char *)&result; dp[0] = a >> 24; dp[1] = a >> 16; dp[2] = a >> 8; dp[3] = a; return result; } /* * "Mac" to "host" byte order swapper */ unsigned short mtohs(a) unsigned short a; { unsigned char *sp = (unsigned char *)&a; unsigned short result = (sp[0] << 8) + sp[1]; return result; } reserve(bytesneeded) int bytesneeded; { int bytesleft = sizeof data - (datap - data); if (bytesleft < bytesneeded) abort("Out of space in 'data' array. Make it bigger."); } /* * Store a byte into the data area. */ databyte(n) int n; { reserve(sizeof (char)); *datap++ = n; } /* * Store a short into the data area. */ datashort(i) short i; { reserve(sizeof (short)); *(unsigned short *)datap = htons(i); datap += sizeof (short); } /* * Store a long into the data area. */ datalong(i) long i; { reserve(sizeof (long)); *(unsigned long *)datap = htonl(i); datap += sizeof (long); } /* * Store string into data area, expanding escape sequences. * The PASCAL flag means store an initial length byte. * The ROUND flag means pad the string to an even number of bytes. */ datastring(sp, flags) char *sp; int flags; { char *lenp; int len; if (flags & PASCAL) lenp = datap++; for (len = 0 ; *sp ; len++) { /* * \HH where HH are two hex digits emits ASCII code HH; * \anything-else emits anything-else. */ if (*sp == '\\') { if (ishex(sp[1]) && ishex(sp[2])) { *datap++ = tohex(sp[1])*16 + tohex(sp[2]); sp += 3; } else ++sp; } else *datap++ = *sp++; } if (flags & ROUND && len & 1) { *datap++ = 0; ++len; } if (flags & PASCAL) *lenp = len; return len; } ishex(c) char c; { return c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f'; } tohex(c) char c; { if (c >= 'a') return c - 'a' + 10; if (c >= 'A') return c - 'A' + 10; return c - '0'; } /* * Read a file and add it to the data area. */ datafile(f) FILE *f; { struct stat statBuf; if (fstat(fileno(f), &statBuf) < 0) abort("fstat failed"); /* can't happen */ reserve(statBuf.st_size); if (fread(datap, sizeof (char), statBuf.st_size, f) != statBuf.st_size) abort("can't read file"); /* can't happen */ datap += statBuf.st_size; } @//E*O*F data.c// chmod u=rw,g=rw,o=r data.c echo x - rmaker.h sed 's/^@//' > "rmaker.h" <<'@//E*O*F rmaker.h//' #include <stdio.h> #include <ctype.h> #include <sys/types.h> #include <sys/stat.h> #include <mac/res.h> #include <mac/quickdraw.h> #include <mac/toolintf.h> struct rescomp { /* resource being compiled */ char rc_type[8]; /* resource type (e.g. "CODE") */ char *rc_name; /* resource name */ int rc_id; /* resource id number */ int rc_att; /* attributes */ long rc_length; /* length in resource file */ char *rc_data; /* pointer to data */ int rc_datalen; /* length of data */ FILE *rc_file; /* file to read data from */ int rc_filelen; /* length of data in file */ int rc_bss; /* number of zero pad bytes */ char *rc_rel; /* relocation info */ int rc_rellen; /* length of relocation info */ } *rcp; char fineof; /* true after all commands read */ char line[256]; /* line buffer */ char *lp; /* current position in line */ int linenum; /* line number in command file */ char token[128]; /* current token being scanned */ char data[8*1024]; /* area to build simple resource data */ char *datap; /* pointer to data area */ FILE *fin; /* file for compiler commands */ /* Keyword/value pair for scankeys() */ struct keylist { char *keyname; int keyvalue; }; /* Flags for datastring() */ #define PASCAL 01 #define ROUND 02 char *malloc(); char *index(); unsigned short htons(); /* host to "net" byte order, short. */ unsigned long htonl(); @//E*O*F rmaker.h// chmod u=rw,g=rw,o=r rmaker.h echo x - crtdrvr.s sed 's/^@//' > "crtdrvr.s" <<'@//E*O*F crtdrvr.s//' | | crtdrvr.s - dynamically relocating C runtime startoff for Mac desk accessory | | Copyright (C) 1984, Stanford Univ. SUMEX project | May be used but not sold without permission. | | history | 07/20/84 Croft Created. | 10/24/84 Smith Customize for test | 01/10/85 Moy Add dynamic rellocation | Open = 0 Prime = 4 Ctl = 8 Status = 12 Close = 16 .data .text .globl _savea5 .globl drvr .globl drvrOpen,drvrPrime,drvrCtl,drvrStatus,drvrClose | driver header drvr: .word 0x2400 | enable control, need time .word 2 | 30 times a second .word 0x0142 | mouseDown, update, activate events .word 0 | no menu doffset: .word dopen-drvr .word dprime-drvr .word dctl-drvr .word dstatus-drvr .word dclose-drvr .byte 6 | .ascii "\0Sleep" .byte 0 .ascii "Sleep" .blkb 25 | 32 bytes total for name jra dopen | magic number reloff: .long 0 .long 0,0,0,0,0,0,0,0,0,0 | longruns from rmaker reladdr:.long 0 _savea5:.long 0 | | driver entry points | dopen: moveq #Open,d0 bras .L21 dprime: moveq #Prime,d0 bras .L21 dctl: moveq #Ctl,d0 bras .L21 dstatus: moveq #Status,d0 bras .L21 dclose: moveq #Close,d0 @.L21: moveml #0x3ffc,sp@- lea pc@([reladdr-.-2]),a2 | reloc addr lea pc@([drvr-.-2]),a3 | reloc factor movl a3,d1 andl #0xffffff,d1 | clear out trash in high byte subl a2@,d1 | have we moved? beqs call addl d1,a2@ | adjust reladdr lea pc@([reloff-.-2]),a3 addl d1,a3@ | adjust addr of reloc table movl a3@+,a4 | get addr of reloc table addl d1,a3@ | adjust 1st relocation movl a3@+,a2 | pickup 1st relocation | | a2 = current reloc address | a3 = next longrun address | a4 = next reloc table address | d1 = relocation factor | | for(;;) { | *(u_long *)a2 += (u_long)d1; | if ((i = (*a4++ & 0377)) == 0) { | *a3 += d1; | a2 = *a3++; | continue; | } | if (i == 0377) | goto start; | a2 += (i << 1); | } @.L16: addl d1,a2@ movb a4@+,d7 andl #255,d7 bnes .L19 addl d1,a3@ movl a3@+,a2 bras .L16 @.L19: cmpl #255,d7 beqs .L18 roll #1,d7 addl d7,a2 bras .L16 | | if shift button is pressed on entry, beep and hang around for an NMI. | @.L18: btst #0,0x17b beqs .L31 | if not pressed movw #1,sp@- | sysbeep, duration 1 .word /A9C8 moveq #1,d2 @.L22: tstl d2 bnes .L22 | hang, waiting for NMI @.L31: movl a5,_savea5 call: movl a1,sp@- movl a0,sp@- movl #jmptab,a0 addl d0,a0 movl a0@,a0 jsr a0@ addql #8,sp moveml sp@+,#0x3ffc cmpl #0x40000000,d0 bnes done clrl d0 rts jiodone = 0x8fc done: movl jiodone,sp@- rts jmptab: .long drvrOpen .long drvrPrime .long drvrCtl .long drvrStatus .long drvrClose @//E*O*F crtdrvr.s// chmod u=rw,g=rw,o=r crtdrvr.s echo x - crtproc.s sed 's/^@//' > "crtproc.s" <<'@//E*O*F crtproc.s//' | | crtproc.s - dynamically relocating C runtime startoff for PROCs. | This is a sample window definition procedure. | | Copyright (C) 1984, Stanford Univ. SUMEX project | May be used but not sold without permission. | | history | 01/10/85 Moy Created | 07/01/85 Powell renamed from crtwdef.s to crtproc.s | .data .text .globl _savea5 .globl wdef .globl MyWindow wdef: jra .L21 | magic number reloff: .long 0 .long 0,0,0,0,0,0,0,0,0,0 | longruns from rmaker reladdr:.long 0 _savea5:.long 0 @.L21: moveml #0x3ffc,sp@- lea pc@([reladdr-.-2]),a2 | reloc addr lea pc@([wdef-.-2]),a3 | reloc factor movl a3,d1 andl #0xffffff,d1 | clear out trash in high byte subl a2@,d1 | have we moved? beqs call addl d1,a2@ | adjust reladdr lea pc@([reloff-.-2]),a3 addl d1,a3@ | adjust addr of reloc table movl a3@+,a4 | get addr of reloc table addl d1,a3@ | adjust 1st relocation movl a3@+,a2 | pickup 1st relocation | | a2 = current reloc address | a3 = next longrun address | a4 = next reloc table address | d1 = relocation factor | | for(;;) { | *(u_long *)a2 += (u_long)d1; | if ((i = (*a4++ & 0377)) == 0) { | *a3 += d1; | a2 = *a3++; | continue; | } | if (i == 0377) | goto start; | a2 += (i << 1); | } @.L16: addl d1,a2@ movb a4@+,d7 andl #255,d7 bnes .L19 addl d1,a3@ movl a3@+,a2 bras .L16 @.L19: cmpl #255,d7 beqs .L20 roll #1,d7 addl d7,a2 bras .L16 @.L20: movl a5,_savea5 call: moveml sp@+,#0x3ffc jmp MyWindow @//E*O*F crtproc.s// chmod u=rw,g=rw,o=r crtproc.s echo x - rmaker.1 sed 's/^@//' > "rmaker.1" <<'@//E*O*F rmaker.1//' @.TH RMAKER local "10/20/84" @.UC 4 @.SH NAME rmaker \- resource maker (compiler) for Macintosh @.SH SYNOPSIS @.B rmaker file.rc @.br @.B rmaker [ @.B \-d type ] file.rc @.SH DESCRIPTION @.I Rmaker reads an ascii resource compiler input file "file.rc" and produces a Macintosh executable binary "file.rsrc". See the Inside Mac manual "Putting Together a Macintosh Application" for a description of this format and process. It is also helpful to look at one of the example '.rc' files in the SUMacC 'mac/' source directory. @.PP Most of the commonly used resource types are implemented: STR, STR#, HEXA, CODE, DRVR, ALRT, DITL, DLOG, WIND, MENU, CNTL, ICON, ICN#, CURS, PAT, PICT, FILE, BNDL, GNRL, FREF, INIT, PACK, CDEF, MDEF, WDEF, POST, FKEY, and PROC. See the BUGS section below for exceptions. @.PP The optional \-d (debug) switch will list out in hex the contents of all resources matching that four letter type. @.PP Backslash escape sequences are allowed in strings in the form \\hh where "hh" are two hexadecimal digits. @.SH SEE ALSO "Putting Together a Macintosh Application" (note: this manual is no longer part of Inside Macintosh) @.PP "Format of the SUMacC Resource Compiler Input File" (basically the same as IM, but specific details of the SUMacC rmaker are covered.) This document is included in this release. @.SH BUGS Types NOT implemented: PAT#, FONT, ANYB. You can always use an "inherited type" of HEXA (e.g. Type PAT# = HEXA) to simulate unimplemented types. (Type FILE has been provided to perform the function of ANYB) @.PP A blank line is not tolerated after the item count in type DITL. In general, the Lisa Workshop rmaker is much more tolerant about blank lines, which are ignored everywhere except where they are specifically required. @.PP The usage: @.TP Type FOO @.br ,1 @.br <data> @.br ,2 @.br <data> @.PP is not recognized. (i.e., you must specify Type FOO for each.) @.PP Type GNRL does not support .B format. Then again, with .F, who cares. @.PP If a trailing blank is present on a type line, e.g. @.TP Type STR <- trailing blank @.PP then Sumacc will abort. This is because of a bug in scanf(). Perhaps it would be appropriate to strip trailing whitespace off each input line in getline(). @.PP Type ICN# is implemented the same as HEXA. I.M. says it is supposed to start with a field giving the number of icons. @.PP Types PAT, ICON and CURS do not check to see that their data contains the correct number of bytes. @.PP Rmaker input has no "standard" format. Where possible, the format of the Lisa Rmaker has been used. In the case of STR#, the format is different than that of the Mac Rmaker. See "Format of the SUMacC Resource Compiler Input File." @.PP If you get the message "impossible relocation", it usually means your b.out had some undefined external references; check the error output from 'ld', you probably misspelled some global or routine name. @.PP If you get a message similar to "no crtxxx.s prefix", you have probably linked with the wrong type of crt*.s file for your DRVR or PROC (WDEF, INIT, etc.). The proper files are included in this release. @//E*O*F rmaker.1// chmod u=rw,g=rw,o=r rmaker.1 echo x - rmaker.doc sed 's/^@//' > "rmaker.doc" <<'@//E*O*F rmaker.doc//' _______________________________________________________________________________ FORMAT OF THE SUMACC RESOURCE COMPILER INPUT FILE Modified 07/01/85 by Brian Powell Adapt for SUMacC 07/11/85 Brian Powell mention backslash escapes 12/23/85 Brian Powell Show input format changes implemented by Doug Moen _______________________________________________________________________________ You'll need to create a resource file for your application. This is done with the Resource Compiler, and you'll have among your working files an input file to the Resource Compiler. *** In the future, you'll be able to use the Resource Editor. *** One convention for naming this input file is to give it the name of your application followed by ".rc" (Such as samp.rc) One of the entries in the input file specifies the name to be given to the output resource file; you'll enter the application name and ."rsrc". Another entry tells which file the application code segments are to be read from. (As discussed in the Resource Manager manual, the code segments are actually resources of the application.) You'll enter the name of the Linker output file specified in the Exec file for building your application, as described in the next section. If you don't want to include any resources other than the code segments, you can have a simple input file like this: * samp.rc -- Resource input for sample application * Written by Macintosh User Education 1/13/84 samp.rsrc Type SAMP = STR ,0 Samp Version 1.0 -- January 13, 1984 Type CODE samp.o,0 This tells the Resource Compiler to write the resulting resource file to samp.rsrc and to read the application code segments from samp.o in the working directory. It also specifies the file's signature and version data, which the Finder needs. *** (Documentation on the signature and version data is forthcoming.) *** It's a good idea to begin the input file with a comment that describes its contents and shows its author, creation date, and other such information. Any line beginning with an asterisk (*) is ignored *** (except within a menu, for now) ***. The Resource Compiler also ignores the following: - leading spaces (except before the text of a string resource) - embedded spaces (except in file names, titles, or other text strings) - blank lines (except for those indicated as required) The first line that isn't ignored specifies the name to be given to the resulting resource file. Then, for each type of resource to be defined, there are one or more "Type statements". A Type statement consists of the word "Type" followed by the resource type (without quotes) and, below that, an entry of following format for each resource: file name!resource name, resource ID (resource attributes) type-specific data The punctuation shown here is typed as part of the format. You must always provide a resource ID. Specifications other than the resource ID may or may not be required, depending on the resource type: - Either there will be some type-specific data defining the resource or you'll give a file name indicating where the resources will be read from. You can specify a directory; if not, the working directory is assumed. Even in the absence of a file name, you must include the comma before the resource ID. *** For now, the filename is ignored, and you must completely specify the data. *** - You specify a resource name along with the file name for fonts and drivers. The Menu Manager procedures AddResMenu and InsertResMenu will put these resource names in menus. Enter the names in the combination of uppercase and lowercase that you want to appear in the menus. - Resource attributes in parentheses are optional for all types. They're given as a number equal to the value of the resource attributes byte, and 0 is assumed if none is specified. (See the Resource Manager manual for details.) For example, for a resource that's purgeable but has no other attributes set, the input will be "(32)"; for one that's purgeable and in the system heap, it will be "(96)". The formats for the different types of resources are best explained by example. Some examples are given below along with comments that provide further explanation. Here are some points to remember: - In every case, resource attributes in parentheses may be specified after the resource ID. - All numbers are base 10 except where hexadecimal is indicated. - In general, all strings may include backslash escape characters. (\XX where X is a hexadecimal digit.) \ followed by "anything else" is replaced by "anything else". For example, \\ is a backslash. \' and \" permit quotes to be put in quoted strings in type GNRL. \<space> can be used to introduce a leading space in a title. \<newline> turns into a blank line in STR# and POST string lists. Type WIND Window template ,1 Resource ID Status Report Window title 40 80 120 300 BoundsRect (top left bottom right) Visible GoAway For FALSE, use Invisible or NoGoAway 0 ProcID (window definition ID) 0 RefCon (reference value) Type MENU Menu (standard, enabled) ,2 Resource ID (menu ID) Edit Menu title Cut/X Menu items, one per line, with meta- Paste/Z characters, ! alone for check mark (- You cannot specify a blank item; use (- Word Wrap! for a disabled continuous line. Blank line required at end of menu Type CNTL Control template ,1 Resource ID Help Control title 55 20 75 90 BoundsRect Visible For FALSE, use Invisible 0 ProcID (control definition ID) 1 refCon (reference value) 0 0 0 Value minimum maximum Type DLOG Dialog template ,1 Resource ID 100 100 190 250 BoundsRect Visible 1 GoAway 0 1 is procID, 0 is refCon 3 Resource ID of item list Title (none in this case) Type ALRT Alert template ,1 Resource ID 120 100 190 250 BoundsRect 5 Resource ID of item list F721 Stages word in hexadecimal Type DITL Item list in dialog or alert ,3 Resource ID 5 Number of items BtnItem Enabled Also: ChkItem, RadioItem 60 10 80 70 Display rectangle Start Title Blank line required between items CtrlItem Enabled Control defined in control template 60 10 80 100 Display rectangle 1 Resource ID of control template StatText Disabled Also: EditText 10 93 26 130 Display Rectangle Seed The text (may be blank if EditText) IconItem Disabled Also: PicItem 10 24 42 56 Display rectangle 1 Resource ID of icon ResCItem Enabled Control defined in control template 60 30 80 100 Display rectangle 128 Resource ID of control template UserItem Disabled Application-defined item 20 50 60 85 Display rectangle Type ICON An Icon ,1 Resource ID 0380 0000 0380 0000 0380 0000 0380 0000 The icon in hexadecimal 0380 0000 0380 0000 0380 0000 0380 0000 0380 0000 0380 0000 0380 0000 0380 0000 0380 0000 0380 0000 0380 0000 0380 0000 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 Type ICN# Icon list ,128 Resource ID 0380 0000 0380 0000 0380 0000 0380 0000 The icons in hexadecimal 0380 0000 0380 0000 0380 0000 0380 0000 (specify an id and 128 bytes 0380 0000 0380 0000 0380 0000 0380 0000 for each.) 0380 0000 0380 0000 0380 0000 0380 0000 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 Blank line required after last icon Type CURS Cursor ,300 Resource ID 7FFC . . . 287F The data: 64 hex dgits on one line 0FC0 . . . 1FF8 The mask: 64 hex digits on one line 0008 0008 The hotSpot in hexadecimal (v h) Type PAT Pattern ,200 Resource ID AADDAA66AADDAA66 The pattern in hexadecimal Type STR String (use "STR" instead of "STR ". (BUG)) ,36 Resource ID This is your string The string on one line (leading spaces not ignored) Type STR# String list ,1 Resource ID This is string one the strings... This is string two This is string three Blank line required following STR# Type DRVR Desk accessory or other I/O driver Monkey/Monkey,17 (32) File name/resource name, resource ID [ SEE NOTE 1 BELOW ] Type FREF File reference ,128 Resource ID APPL 0 TgFile File type, local ID of icon, filename (the filename is optional) Type HEXA Any bytes specified here ,9 Resource ID 526FEEC942E78EA4 The bytes in hexadecimal (any number 0F4C total, any nuber per line) Blank line required at end Type POST Postscript resource ,1 Resource ID This is string one The strings... This is string two Third string Bench warmer Apple's joke, not mine. Type PICT A Picture (see the quickdraw documentation) picture-file,1 File resource ID Type FILE Reads a file into a resource. Replaces type file-name,1 ANYB, but reads entire file. * 3 different ways to do a bundle, * illustrating types BNDL and GNRL Type BNDL Bundle ,128 Resource ID SAMP 0 Bundle owner SAMP 0 2 Two types in bundle (ICN# and FREF) ICN# 1 ICN# number of resources 0 128 local ID 0 maps to resource ID 128 FREF 1 FREF number of resources 0 128 local ID 0 maps to resource ID 128 Type BNDL = GNRL Type General (more on GNRL below) ,129 'SAMP' 0 store data string 1 number of resources minus 1 'ICN#' 0 number of ICN#'s minus 1 0 128 'FREF' 0 0 128 Type BNDL = GNRL ,130 .S store data string SAMP .I store decimal integer 0 1 .S ICN# .I 0 0 128 .S FREF .I 0 0 128 Type CODE Application code segments samp.o,0 Linker output file name, resource ID [ SEE NOTE 3 BELOW ] Notes: 1. The Resource Compiler adds a NUL character (ASCII code 0) at the beginning of the name you specify for a 'DRVR' type of resource if it doesn't begin with a period ('.'). Therefore, device drivers should start with a '.', and desk accessories with any other character. This inclusion of a nonprinting character avoids confilict with file names that are the same as the names of desk accessories. 3. For a 'CODE' type of resource, the resource ID you specify is ignored. The Resource Compiler always creates two resources of this type, with ID numbers 0 and 1, and will create additional ones numbered sequentially from 2 if your program is divided into segments. The Type statement for a resource of type 'WDEF', 'MDEF', 'CDEF', 'FKEY' *** function key code ***, 'PACK', 'PROC', or 'INIT' has the same format as for 'CODE': only a file name and a resource ID are specified. The file contains the compiled code of the resource. You can also define a new resource type that inherits the properties of a standard type. For example, Type XDEF = WDEF defines the new type 'XDEF', which the Resource Compiler treats exactly like 'WDEF'. The next line would contain a file name and resource ID just as for a 'WDEF' resource. As another example, suppose you want to define a resource type 'MINE' that consists of any bytes specified in hexadecimal in the Resource Compiler input file; you can use Type MINE = HEXA followed by the resource ID and bytes on the subsequent lines. More on Type GNRL: Input is free format, with one or more tokens per line, except for strings following .S or .P. Input is terminated by the first blank line. .I succeeding number tokens are to be interpreted as decimal 16 bit integers .L following numbers are decimal, 32 bit .C following numbers are decimal, 8 bit .H following numbers are hexadecimal 'string' output the contained ascii characters "string" output the string in Pascal format, with a length byte .F filename interpolate the contents of the named file .S following lines contain strings without length bytes, up to a blank line or a line whose first non-blank character is '.' .P following lines contain pascal strings (with length byte) Notes: This implementation of GNRL is upward compatible with the Apple syntax, except that .B is unsupported (replaced by .F). To put a ' or " into a quoted string, use \' or \". To put an empty string into .S or .P, use a line containing only "\" If the first non-blank character of a string after .S or .P is ".", then you need to write "\." There is an implicit .I at the beginning of the input. If all of your numbers are 16 bit decimal format, you don't need to use .I anywhere. For example, Type BNDL = GNRL ,128 'SAMP' 0 1 'ICN#' 0 1 128 'FREF' 0 1 128 @//E*O*F rmaker.doc// chmod u=rw,g=rw,o=r rmaker.doc echo x - samp.rc sed 's/^@//' > "samp.rc" <<'@//E*O*F samp.rc//' * samp.rc -- Resource input for sample application * samp.rsrc Type SAMP = STR ,0 Samp Version 1.0 -- January 13, 1984 * Type CODE * samp.o,0 Type WIND ,1 Status Report 40 80 120 300 Visible GoAway 0 0 Type MENU ,2 Edit Cut/X Paste/Z (- Word Wrap! Type CNTL ,1 Help 55 20 75 90 Visible 0 1 0 0 0 Type DLOG ,1 100 100 190 250 Visible 1 GoAway 0 3 Type ALRT ,1 120 100 190 250 5 F721 Type DITL ,3 5 BtnItem Enabled 60 10 80 70 Start ResCItem Enabled 60 30 80 100 128 StatText Disabled 10 93 26 130 Seed IconItem Disabled 10 24 42 56 128 UserItem Disabled 20 50 60 85 Type ICON ,1 0380 0000 0380 0000 0380 0000 0380 0000 0380 0000 0380 0000 0380 0000 0380 0000 0380 0000 0380 0000 0380 0000 0380 0000 0380 0000 0380 0000 0380 0000 0380 0000 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 Type ICN# ,128 0380 0000 0380 0000 0380 0000 0380 0000 0380 0000 0380 0000 0380 0000 0380 0000 0380 0000 0380 0000 0380 0000 0380 0000 0380 0000 0380 0000 0380 0000 0380 0000 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 1EC0 3180 Type CURS ,300 7FFC 287F 7FFC 287F 7FFC 287F 7FFC 287F 7FFC 287F 7FFC 287F 7FFC 287F 7FFC 287F 0FC0 1FF8 0FC0 1FF8 0FC0 1FF8 0FC0 1FF8 0FC0 1FF8 0FC0 1FF8 0FC0 1FF8 0FC0 1FF8 0008 0008 Type PAT ,200 AADDAA66AADDAA66 Type STR ,36 This is your string Type STR# ,1 This is string one This is string two This is string three * Type DRVR * Monkey/Monkey,17 (32) Type FREF ,128 APPL 0 TgFile Type HEXA ,9 526FEEC942E78EA4 0F4C Type POST ,1 4 This is string one This is string two Third string Bench warmer * 3 different ways to do a bundle, * illustrating types BNDL and GNRL Type BNDL ,128 SAMP 0 2 ICN# 1 0 128 FREF 1 0 128 Type BNDL = GNRL ,129 'SAMP' 0 1 'ICN#' 0 0 128 'FREF' 0 0 128 Type BNDL = GNRL ,130 .S SAMP .I 0 1 .S ICN# .I 0 0 128 .S FREF .I 0 0 128 @//E*O*F samp.rc// chmod u=rw,g=rw,o=r samp.rc echo x - test.rc sed 's/^@//' > "test.rc" <<'@//E*O*F test.rc//' test.rsrc Type GNRL |foobar,42 .C 100 .I 100 .L 100 .H afafaf 'foo' "foo" .F foo @//E*O*F test.rc// chmod u=rw,g=rw,o=r test.rc exit 0
brian@ut-sally.UUCP (Brian H. Powell) (12/25/85)
# This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # # Wrapped by sally!brian on Wed Dec 25 01:21:22 CST 1985 # Contents: code.c hand.c rmaker.c scan.c echo x - code.c sed 's/^@//' > "code.c" <<'@//E*O*F code.c//' #include "rmaker.h" #include <mac/b.out.h> #define bh filhdr struct bhdr bh; /* b.out header */ char seg0[sizeof(struct jumphead) + sizeof(struct jumptab)] = { 0,0,0,0x28, 0,0,2,0, 0,0,0,8, 0,0,0,0x20, 0,0, 0x3F,0x3C, 0,1, 0xA9,0xF0 }; /* "standard" segment 0 jump header/table */ char seg1[sizeof(struct codehead)] = { 0,0, 0,1 }; #ifndef CRTLEN #define CRTLEN 10 /* length of relocation table in crtmac.s */ #endif CRTLEN #define CRTMAGIC (0x6004+4*CRTLEN) /* jump at beginning of crtmac.s */ #ifndef RELLEN #define RELLEN 12 /* length of relocation table in crt*.s */ #endif #define RELMAGIC (0x6004+4*RELLEN) /* jump at beginning of crt*.s */ char *relpnt; /* current position in longrun area */ char *relrel; /* current position in reloc area */ int rellen; /* length of longrun area */ int reloff; /* current relocation offset */ /* * Handle program (code) data. */ handcode() { struct reloc rl; /* * setup CODE, id=0 (jumptable) */ if (rcp->rc_id == 0) { rcp[1] = rcp[0]; /* duplicate rescomp entry */ rcp->rc_att = ATT_PURGEABLE; rcp->rc_datalen = rcp->rc_length = sizeof seg0; rcp->rc_data = seg0; rcp->rc_file = (FILE *)0; rcp->rc_bss = 0; rcp++; } /* * setup CODE, id=1 (text/data) */ if (fread((char *)&bh, sizeof bh, 1, rcp->rc_file) != 1 || bh.fmagic != FMAGIC) abort("bad b.out header"); if ((rcp->rc_data = malloc(rcp->rc_datalen = bh.tsize + bh.dsize + sizeof seg1)) == 0) abort("code malloc"); rcp->rc_id++; /* normally id is now 1 */ seg1[3] = rcp->rc_id; /* put id in jump table */ bcopy(seg1, rcp->rc_data, sizeof seg1); rcp->rc_data += sizeof seg1; if (fread((char *)rcp->rc_data, rcp->rc_datalen - sizeof seg1, 1, rcp->rc_file) != 1) abort("code readerror"); rcp->rc_bss = bh.bsize; rcp->rc_length = rcp->rc_datalen + rcp->rc_bss; if (!rcp->rc_att) /* set default attributes if none supplied */ rcp->rc_att = ATT_PURGEABLE | ATT_LOCKED | ATT_PRELOAD; if ((bh.rtsize + bh.rdsize) <= 0) abort("b.out must have reloc info"); fseek(rcp->rc_file, RTEXTPOS, 0); if (*(short *)rcp->rc_data != htons(CRTMAGIC)) abort("no crtmac.s prefix"); relpnt = rcp->rc_data + 2; /* start of longrun table */ rellen = CRTLEN; /* length of longrun table */ reloff = 0; readrel(0L, bh.rtsize/sizeof rl); /* reloc text */ readrel(bh.tsize, bh.rdsize/sizeof rl); /* reloc data */ *(rcp->rc_data+reloff) = 0377; /* signals end of reloc data */ rcp->rc_data -= sizeof seg1; fclose(rcp->rc_file); rcp->rc_file = 0; fprintf(stderr, " text %d, data %d, bss %d, longruns %d\n", bh.tsize, bh.dsize, bh.bsize, CRTLEN - rellen); } /* * Read relocation data and run length encode it. */ readrel(off, nrel) long off, nrel; { struct reloc rl; long run, newoff; for ( ; nrel > 0 ; nrel--) { if (fread((char *)&rl, sizeof rl, 1, rcp->rc_file) != 1) abort("error reading reloc"); if (rl.rsize != RLONG || (rl.rpos & 1) || rl.rsymbol || rl.rsegment == REXT) abort("impossible relocation"); newoff = (rl.rpos + off); run = (newoff - reloff) >> 1; if (reloff == 0 || run >= 0377) { *(long *)relpnt = htonl(newoff); relpnt += sizeof (long); if (--rellen <= 0) abort("too many longruns"); } else { *(rcp->rc_data+reloff) = run; } reloff = newoff; } } /* * DRVR, INIT, PACK, CDEF, MDEF, and WDEF all have essentially * the same format. The only difference is that DRVR's require * a different offset to the entry point. */ #define DRVROFF 50 /* offset of longruns in DRVR resource */ /* Interpretation of that last comment for the rest of us: The entry point in crtdrvr.s is the 50th byte. */ #define DRVRMAGIC #define PROCOFF 0 /* zero offset for crtwdef.s entry point */ handdrvr() { relocate(DRVROFF); } handproc() { relocate(PROCOFF); } /* * Relocate a resource. */ relocate(off) { struct reloc rl; if (fread((char *)&bh, sizeof bh, 1, rcp->rc_file) != 1 || bh.fmagic != FMAGIC) abort("bad b.out header"); if((rcp->rc_rellen = (bh.rtsize + bh.rdsize) / sizeof(rl)) & 1) rcp->rc_rellen++; if ((rcp->rc_data = malloc((rcp->rc_datalen = bh.tsize + bh.dsize) + rcp->rc_rellen)) == 0) abort("text malloc"); rcp->rc_rel = rcp->rc_data + rcp->rc_datalen; if (fread((char *)rcp->rc_data, rcp->rc_datalen, 1, rcp->rc_file) != 1) abort("text readerror"); rcp->rc_bss = bh.bsize; rcp->rc_length = rcp->rc_datalen + rcp->rc_bss + rcp->rc_rellen; if ((bh.rtsize + bh.rdsize) <= 0) abort("b.out must have reloc info"); fseek(rcp->rc_file, RTEXTPOS, 0); if (*(short *)(rcp->rc_data+off) != htons(RELMAGIC)) abort("no crtxxx.s prefix"); relpnt = rcp->rc_data + off + 2; /* start of longrun table */ rellen = RELLEN; /* length of longrun table */ *(long *)relpnt = htonl(rcp->rc_length - rcp->rc_rellen); /* offset to reloc table */ relpnt += sizeof(long); relrel = rcp->rc_rel; /* start of reloc table */ reloff = 0; rdreloc(0L, bh.rtsize/sizeof rl); /* reloc text */ rdreloc(bh.tsize, bh.rdsize/sizeof rl); /* reloc data */ *relrel = 0377; /* signals end of reloc data */ fclose(rcp->rc_file); rcp->rc_file = 0; fprintf(stderr, " %s text %d, data %d, bss %d, reloc %d, longruns %d\n", rcp->rc_type, bh.tsize, bh.dsize, bh.bsize, rcp->rc_rellen, RELLEN - rellen); } /* * Read relocation data and run length encode it in a dynamically relocatable * form. */ rdreloc(off, nrel) long off, nrel; { struct reloc rl; long run, newoff; for ( ; nrel > 0 ; nrel--) { if (fread((char *)&rl, sizeof rl, 1, rcp->rc_file) != 1) abort("error reading reloc"); if (rl.rsize != RLONG || (rl.rpos & 1) || rl.rsymbol || rl.rsegment == REXT) abort("impossible relocation"); newoff = (rl.rpos + off); run = (newoff - reloff) >> 1; if (reloff == 0 || run >= 0377) { *(long *)relpnt = htonl(newoff); relpnt += sizeof (long); if (--rellen <= 0) abort("too many longruns"); if(reloff) *relrel++ = 0; } else { *relrel++ = run; } reloff = newoff; } } @//E*O*F code.c// chmod u=rw,g=rw,o=r code.c echo x - hand.c sed 's/^@//' > "hand.c" <<'@//E*O*F hand.c//' /* * hand.c * Rmaker type handlers. */ #include "rmaker.h" struct keylist visible[] = { "visible", 1, "invisible", 0, 0, 0 }; struct keylist goaway[] = { "goaway", 1, "nogoaway", 0, 0, 0 }; /* * Handle string format data. */ handstr() { if (getline() == 0) abort("missing string"); datastring(lp, PASCAL); } /* * Handle string list format data. */ handstrl() { int count; char *backp = datap; /* Pad for count */ *datap++ = 0; *datap++ = 0; /* Process lines */ for (count = 0; ; ++count) { if (getline() == 0) break; datastring(lp, PASCAL); } if (count == 0) abort("empty STR# string list"); /* Stuff count where it belongs */ *backp++ = count >> 8; *backp++ = count & 0xFF; } /* * Handle hexadecimal format data. */ handhexa() { while (getline() != 0) while (skipsp() != 0) databyte(scanhex(2)); } /* * Handle dialog template (DLOG). * * This structure is defined in toolintf.h, but to avoid byte swap * and alignment problems, we fill it "by hand". * * typedef struct { * Rect boundsRect; * short procID; * char visible; * char filler1; * char goAwayFlag; * char filler2; * long refCon; * short itemsID; * Str255 title; * } DialogTemplate; */ handdlog() { int vis,go,pid; long ref; register i; if (getline() == 0) abort("no dlog rectangle"); for (i=0 ; i<4 ; i++) /* parse 4 ints - rectangle */ datashort(scanshort()); if (getline() == 0) abort("no dlog vis/proc"); vis = scankeys(visible); pid = scanshort(); go = scankeys(goaway); ref = scanlong(); datashort(pid); *datap++ = vis; *datap++ = 0; *datap++ = go; *datap++ = 0; datalong(ref); if (getline() == 0) abort("missing Item list ID"); datashort(scanshort()); if (getline() != 0) { skipsp(); datastring(lp, PASCAL); } else datashort(0); } /* * Handle alert template. * * This structure is defined in toolintf.h, but to avoid byte swap * and alignment problems, we fill it "by hand". * * typedef struct { * Rect boundsRect; * short itemsID; * short stages; * } AlertTemplate; */ handalrt() { int i; getline(); for (i=0 ; i<4 ; i++) /* parse 4 ints - rectangle */ datashort(scanshort()); getline(); datashort(scanshort()); getline(); datashort(scanhex(4)); } /* * Handle Dialog and Alert Item Lists (Type DITL) * * Structure of an item list. * * struct { * long zero; placeholder for handle * Rect itemrect; * char itemtype; * char itemlength; * ... followed by variable length data * } */ struct keylist ditlkeys[] = { /* Standard item types */ "btnitem", ctrlItem + btnCtrl, "chkitem", ctrlItem + chkCtrl, "radioitem", ctrlItem + radCtrl, "rescitem", ctrlItem + resCtrl, "stattext", statText, "edittext", editText, "iconitem", iconItem, "picitem", picItem, "useritem", userItem, /* * For backward compatibility with older versions of sumacc rmaker: * eg, "BtnItem" can be specified as "CtrlItem BtnCtrl" */ "ctrlitem", ctrlItem, /* used in conjunction with: */ "btnctrl", btnCtrl, /* a button control */ "chkctrl", chkCtrl, /* checkbox */ "radctrl", radCtrl, /* etc... */ "resctrl", resCtrl, "enabled", 0, "disabled", itemDisable, /* Synonyms for "Disabled", for backward compatibility */ "itemdisable", itemDisable, "disable", itemDisable, "itemdisabled", itemDisable, 0,0 }; handditl() { char *lenp; int i, val, types; /* first line is item count, drop in count-1 */ if (getline() == 0 || (val = scanshort()) < 1) abort("bad DITL item count"); datashort(val-1); /* for each item */ for ( ; val > 0 ; val--) { datalong(0); if (getline() == 0) /* line with item types */ abort("Missing DITL item type"); types = 0; do { types += scankeys(ditlkeys); } while (skipsp() != 0); if (getline() == 0) abort("Missing DITL rectangle"); for ( i=0 ; i < 4 ; i++) datashort(scanshort()); *datap++ = types; types &= ~itemDisable; /* don't care about this bit */ /* * data line is missing for userItem and optional for editText */ if (types != userItem && getline() == 0 && types != editText) abort("Missing DITL data"); skipsp(); lenp = datap++; /* remember spot for length */ switch (types) { case iconItem: /* 2 byte resource ID */ case picItem: case ctrlItem+resCtrl: datashort(scanshort()); *lenp = sizeof (short); break; case userItem: *lenp = 0; /* is nothing */ break; case ctrlItem+btnCtrl: case ctrlItem+chkCtrl: case ctrlItem+radCtrl: case statText: case editText: *lenp = datastring(lp, ROUND); break; } if (getline() != 0) abort("Expected blank line in DITL"); } } /* * Handle window template (WIND). * * typedef struct { * Rect boundsRect; * short procID; * char visible; * char filler1; * char goAwayFlag; * char filler2; * long refCon; * Str255 title; * } WindowTemplate; */ handwind() { int vis,go,pid; long ref; char title[128]; register i; getline(); skipsp(); strcpy(title,lp); getline(); for (i=0 ; i<4 ; i++) /* parse 4 ints - rectangle */ datashort(scanshort()); getline(); vis = scankeys(visible); go = scankeys(goaway); getline(); pid = scanshort(); getline(); ref = scanlong(); datashort(pid); *datap++ = vis; *datap++ = 0; *datap++ = go; *datap++ = 0; datalong(ref); datastring(title, PASCAL); } /* * Handle control template (CNTL). * * typedef struct { * Rect boundsRect; * short value; * char visible; * char filler1; * short max; * short min; * short procID; * long refCon; * Str255 title; * } ControlTemplate; */ handcntl() { int vis,min,max,pid; long ref; char title[128]; register i; getline(); skipsp(); strcpy(title,lp); getline(); for (i=0 ; i<4 ; i++) /* parse 4 ints - rectangle */ datashort(scanshort()); getline(); vis = scankeys(visible); getline(); pid = scanshort(); getline(); ref = scanlong(); getline(); datashort(scanshort()); *datap++ = vis; *datap++ = 0; min = scanshort(); max = scanshort(); datashort(max); datashort(min); datashort(pid); datalong(ref); datastring(title, PASCAL); } /* * Handle menu template (MENU). * * typedef struct { * short menuID; * long fill1; * short menuProc; menu definition procedure (normally 0) * short fill2; placeholder * long enableFlags; * Str255 title; * for each menu item: * Str255 text; * char icon#; * char keyboardequiv; * char mark; * char textstyle; * finally: * char zero; end of items. * } */ handmenu() { int iconid, styleid, cmdid, markid, item; long *flagsp, flags; register char *cp,*dp,*sp; char itext[128]; static char styles[] = "BIUOS"; datashort(rcp->rc_id); /* menu resource id */ datalong(0); /* * Read an optional line containing the resource id of * the menu definition procedure, */ getline(); skipsp(); if (isdigit(*lp)) { datashort(scanshort()); getline(); skipsp(); } else datashort(textMenuProc); datashort(0); flagsp = (long *)datap; /* remember where the flags were */ flags = -1; /* enable all items */ datalong(-1); /* placeholder for flags */ datastring(lp, PASCAL); /* The menu title */ for (item = 1 ; getline() && item < 32 ; item++) { skipsp(); iconid = styleid = cmdid = markid = 0; for (cp = lp, dp = itext ; *cp ; cp++) { switch (*cp) { default: *dp++ = *cp; break; case '(': flags &= ~(1<<item); break; case '^': cp++; iconid = *cp; break; case '/': cp++; cmdid = *cp; break; case '!': cp++; markid = *cp; break; case '<': cp++; sp = index(styles, *cp); if (sp == 0) abort("BIUOS expected after <"); styleid |= (1 << (sp-styles)); break; } } *dp++ = 0; datastring(itext, PASCAL); *datap++ = iconid; *datap++ = cmdid; *datap++ = markid; *datap++ = styleid; } /* end of items */ *datap++ = 0; *flagsp = htonl(flags); } handpict() { unsigned short pictSize; if (fread((char *)&pictSize, sizeof pictSize, 1, rcp->rc_file) != 1) abort("can't read picture file"); pictSize = mtohs(pictSize); if (pictSize > sizeof data) abort("picture too large. Increase size of 'data' variable"); rewind(rcp->rc_file); if (fread(data, sizeof (char), pictSize, rcp->rc_file) != pictSize) abort("can't read picture file"); datap += pictSize; fprintf(stderr, "picture %d: %d bytes\n", rcp->rc_id, pictSize); } handfile() { datafile(rcp->rc_file); } handgnrl() { FILE *f; int mode; if (getline() == 0) abort("GNRL: missing data"); mode = 'I'; for (;;) { if (skip() == 0) break; switch (*lp) { case '.': ++lp; if (islower(*lp)) *lp = toupper(*lp); switch (*lp) { default: abort("unknown format code .%c", *lp); break; case 'C': case 'I': case 'L': case 'H': mode = *lp++; break; case 'F': ++lp; if (skip() == 0) abort(".F: missing filename"); gettoken(); f = fopen(token, "r"); if (f == NULL) abort(".F: can't open %s", token); datafile(f); fclose(f); break; case 'S': for (;;) { if (getline() == 0) return; if (skipsp() == '.') break; datastring(line, 0); } break; case 'P': for (;;) { if (getline() == 0) return; if (skipsp() == '.') break; datastring(line, PASCAL); } break; } break; case '"': getstring(); datastring(token, PASCAL); break; case '\'': getstring(); datastring(token, 0); break; default: switch (mode) { case 'C': databyte(scanshort()); break; case 'I': datashort(scanshort()); break; case 'L': datalong(scanlong()); break; case 'H': databyte(scanhex(2)); break; } } } } /* * Handle FREF * * Input: * one line containing * file-type local-id optional-file-name * eg: * APPL 0 FileName * * Output: * 4 bytes - file type * 2 bytes - local resource id for icon list * n bytes - file name as pascal string (0 if filename missing) */ handfref() { if (getline() == 0) abort("FREF: missing data line"); gettoken(); checktype(token); strcpy(datap, token); datap += 4; datashort(scanshort()); skipsp(); datastring(lp, PASCAL); } /* * Handle BNDL * * Input: * signature-type signature-resource-id * number-of-types-in-bundle * For each resource type: * resource-type number-of-resources * For each resource: * local-id global-id * * Output: * 4 bytes - signature type * 2 bytes - signature resource id * 2 bytes - number of types - 1 * For each type: * 4 bytes - resource type * 2 bytes - number of resources - 1 * For each resource: * 2 bytes - local id * 2 bytes - actual id */ handbndl() { short ntypes, nresources; if (getline() == 0) abort("BNDL: missing signature data"); gettoken(); checktype(token); strcpy(datap, token); datap += 4; datashort(scanshort()); if (getline() == 0) abort("BNDL: missing number of types"); ntypes = scanshort(); datashort(ntypes - 1); while (ntypes-- > 0) { if (getline() == 0) abort("BNDL: missing resource type line"); gettoken(); checktype(token); strcpy(datap, token); datap += 4; nresources = scanshort(); datashort(nresources - 1); while (nresources-- > 0) { if (getline() == 0) abort("BNDL: missing resource id line"); datashort(scanshort()); datashort(scanshort()); } } } @//E*O*F hand.c// chmod u=rw,g=rw,o=r hand.c echo x - rmaker.c sed 's/^@//' > "rmaker.c" <<'@//E*O*F rmaker.c//' /* rmaker.c 1.0 04/11/84 */ /* * Resource compiler. */ /* * Copyright (C) 1984, Stanford Univ. SUMEX project. * May be used but not sold without permission. */ /* * history * 04/11/84 Croft Created. * 04/16/84 Croft Reloc info now imbedded in long addresses. * 06/18/84 Schilit Added DITL and ALRT. * 07/06/84 Croft Added DLOG WIND MENU CNTL ICON ICN# CURS PAT. * 07/21/84 Croft Added DRVR; multiple code segs (jks). * 07/26/84 Schuster Added resource names. *** Branch 1 * 01/10/85 Moy Implement [CMW]DEF. These and DRVR use dynamic * relocation scheme. *** Branch 2 * 09/18/84 Croft Fixed fwrite bug for resource names. * 11/06/84 Croft Added INIT and PACK. * 11/11/84 Maio/Schilit no NULL in DRVR name if device driver. *** Branch 3 * 06/25/85 GvR Added STR#. * 06/26/85 Crosswell Added POST (PostScript resource in * Laser Prep file) * 07/06/85 Horvath Add Backslash escapes in strings. *** Reunion * 06/27/85 Powell Combined branches 1, 2 and 3. * 06/27/85 Powell Modify INIT and PACK to use dynamic relocation. * 06/27/85 Powell Added FKEY. * 06/29/85 Powell Added PROC. * 07/06/85 Powell Fix tolower bug in backslash code. Limit \ooo to three digits, \xhh to two. * 07/09/85 GvR Allow CRTLEN and RELLEN to be overridden * on compilation with -D; made CRTMAGIC and * RELMAGIC self-adjusting; changed \ escapes * to hex (as in Inside Mac). * 11/09/85 GvR Changed POST to be identical to STR#. * 07/11/85 Doug Moen Added PICT and FILE. Fixed: Resources are now sorted by type & id. Fixed: tabs are now considered whitespace Fixed: htons, htonl are now machine independent removed lint. * 12/23/85 Powell Changed filename/resource name separator from '|' to '!'. (as in Inside Mac) */ #include "rmaker.h" #define NRESCOMP 50 /* max number of resources per compile */ struct rescomp rescomp[NRESCOMP]; struct resfile rf; /* compiled resource file header */ struct resmap rm; /* compiled resource map header */ struct restype rt[NRESCOMP]; /* compiled resource type list */ struct resid ri[NRESCOMP]; /* compiled resource id list */ #define NAMELEN 1024 char rn[NAMELEN]; /* compiled resource name list */ char debugtype[8]; /* debug type switch */ FILE *fout; /* file for compiler output */ /* type format handlers */ extern handstr(), handstrl(), handhexa(); extern handcode(), handdrvr(), handproc(); extern handdlog(), handalrt(), handditl(); extern handwind(), handmenu(), handcntl(); extern handpict(), handfile(), handgnrl(); extern handfref(), handbndl(); struct typehand { /* type string to handler table */ char th_type[8]; /* e.g. "CODE" */ int (*th_handler)(); /* format handler function */ } typehand[] = { "STR ", handstr, "STR#", handstrl, "HEXA", handhexa, "CODE", handcode, "DRVR", handdrvr, "INIT", handproc, "PACK", handproc, "ALRT", handalrt, "DITL", handditl, "DLOG", handdlog, "WIND", handwind, "MENU", handmenu, "CNTL", handcntl, "ICON", handhexa, "ICN#", handhexa, "CURS", handhexa, "PAT ", handhexa, "CDEF", handproc, "MDEF", handproc, "WDEF", handproc, "POST", handstrl, "FKEY", handproc, "PROC", handproc, "PICT", handpict, "FILE", handfile, "GNRL", handgnrl, "FREF", handfref, "BNDL", handbndl, 0, 0 }; main(argc, argv) char **argv; { for (argc--,argv++ ; argc > 0 ; argc--,argv++) { if (argv[0][0] != '-') break; switch (argv[0][1]) { case 'd': argc--,argv++; if (argc < 1) abort("syntax: -d TYPE"); strcpy(debugtype,argv[0]); break; } } if (argc != 1) abort("usage: rmaker commandfilename"); if ((fin = fopen(argv[0], "r")) == NULL) abort("can't open commandfile"); rmaker(); buildrf(); /* build resource file from rescomp */ exit(0); } rmaker() { register i; char infile[32], *ip; struct typehand *thp; int haveoutfile = 0; int items, id, att; char littype[32], type[32], format[32]; rcp = &rescomp[0]; while (fineof == 0) { if (getline() == 0) continue; /* skip blank lines */ if (haveoutfile == 0) { /* if output file not yet open */ if ((fout = fopen(lp, "w")) == NULL) abort("can't open output file %s", lp); haveoutfile++; continue; } littype[0] = type[0] = 0; items = sscanf(lp, "%s %s = %s", littype, type, format); if (items < 2 || strcmp(littype, "Type") != 0) { printf("items %d littype %s lp %s\n", items, littype, lp); abort("bad Type line"); /*DEBUG*/ } checktype(type); strcpy(rcp->rc_type, type); if (items == 3) { checktype(format); strcpy(type, format); } if (getline() == 0) abort("bad id"); if (skipsp() == 0) abort("bad id"); for (i=0 ; *lp != ',' && *lp != 0 ; lp++,i++) infile[i] = *lp; infile[i] = 0; if (*lp != ',') abort("bad id"); lp++; id = att = 0; items = sscanf(lp, " %d (%d) ", &id, &att); ip = index(infile, '!'); if (ip) { *ip++ = 0; if ((rcp->rc_name = malloc(strlen(ip) + 1)) == 0) abort("name malloc"); strcpy(rcp->rc_name, ip); } else rcp->rc_name = 0; if (items < 1) abort("bad id"); if (strlen(infile)) { if ((rcp->rc_file = fopen(infile, "r")) == NULL) abort("can't open input file %s", infile); } else { rcp->rc_file = 0; } rcp->rc_id = id; rcp->rc_att = att; /* search for type handler */ for (thp = &typehand[0] ; ; thp++) { if (thp->th_handler == 0) abort("type %s not implemented", type); if (strcmp(thp->th_type, type) == 0) break; } datap = data; (*thp->th_handler)(); if (datap != data) { int len = datap - data; if (len & 1) { len++; *datap++ = 0; } if ((rcp->rc_data = malloc(len)) == 0) abort("data malloc"); bcopy(data, rcp->rc_data, len); rcp->rc_datalen = rcp->rc_length = len; } if (strcmp(type, debugtype) == 0) printrcp(); rcp++; if ((rcp - &rescomp[0]) > NRESCOMP - 3) abort("too many resources"); } if (rcp == &rescomp[0] || fout == 0) abort("nothing to do"); } /* * Used by qsort to sort resources by type, then id. */ compareRescomp(r1, r2) struct rescomp *r1, *r2; { int cmp = strncmp(r1->rc_type, r2->rc_type, 4); if (cmp != 0) return cmp; return r1->rc_id - r2->rc_id; } /* * Build resource file output from incore rescomp structure. */ buildrf() { register struct rescomp *rcpp; register struct resid *rip; register struct restype *rtp; register char *rnp; struct restype *rtpp; int offdata, roundtomap, sizetypes; long sizemap; register i; register char *cp; numtypes_t numtypes; lendata_t lendata; /* Before scanning, sort rescomp by type/id */ qsort((char *)rescomp, rcp - rescomp, sizeof rescomp[0], compareRescomp); rtp = &rt[0]; rip = &ri[0]; rnp = rn; rcpp = &rescomp[0]; offdata = 0; /* * Scan through the resources making type and id lists. In this * 1st pass, the rt_offids field is set to the offset from the * start of the id's list. Below, the 2nd pass adds the size * of the type list to this field. */ bcopy(rcpp->rc_type, rtp->rt_type, 4); /* preset 1st type */ for ( ; rcpp < rcp ; rcpp++) { if (strncmp(rcpp->rc_type, rtp->rt_type, 4) != 0) { rtp++; /* we've found a new type */ bcopy(rcpp->rc_type, rtp->rt_type, 4); rtp->rt_offids = (rip - &ri[0]) * sizeof *rip; } rtp->rt_numids++; rip->ri_id = htons(rcpp->rc_id); /* ensure final byte order */ if (rcpp->rc_name) { rip->ri_offname = htons(rnp - rn); i = strlen(rcpp->rc_name); if (((rnp - rn) + i + 2) > NAMELEN) abort("namemap exhausted"); /* * desk accessories start with null, device * drivers start with '.'. */ if (strncmp(rcpp->rc_type, "DRVR", 4) == 0 && rcpp->rc_name[0] != '.') { *rnp++ = (char)(i + 1); *rnp++ = 0; } else { *rnp++ = (char) i; } bcopy(rcpp->rc_name, rnp, i); rnp += i; } else rip->ri_offname = htons(-1); rip->ri_att = rcpp->rc_att; rip->ri_offdata = htons(offdata & 0xFFFF); rip->ri_offdatahi = ((offdata >> 16) & 0xFF); rip++; offdata += (rcpp->rc_length + sizeof lendata); } rtp++; /* * Write the file header and pad it out. */ rf.rf_offdata = htonl((long)OFFDATA); offdata += OFFDATA; roundtomap = (offdata & (ROUNDMAP-1)); if (roundtomap) roundtomap = ROUNDMAP - roundtomap; /* # of pad bytes */ rf.rf_offmap = offdata + roundtomap; rf.rf_lendata = htonl(rf.rf_offmap - OFFDATA); rf.rf_offmap = htonl(rf.rf_offmap); sizetypes = ((numtypes = rtp - &rt[0]) * sizeof *rtp); if ((rnp - rn) & 1) /* to be conservative */ *rnp++ = 0; sizemap = sizeof rm + sizetypes + sizeof numtypes + ((rip - &ri[0]) * sizeof *rip) + (rnp - rn); rf.rf_lenmap = htonl(sizemap); fwrite((char *)&rf, sizeof rf, 1, fout); i = OFFDATA - sizeof rf; do { putc(0, fout); } while (--i); /* * correct type list. */ for (rtpp = &rt[0] ; rtpp < rtp ; rtpp++) { rtpp->rt_offids = htons(rtpp->rt_offids + sizetypes + sizeof numtypes); rtpp->rt_numids = htons(rtpp->rt_numids - 1); } /* * For each resource, write data, file, and bss. */ for (rcpp = &rescomp[0] ; rcpp < rcp ; rcpp++) { lendata = htonl(rcpp->rc_length); fwrite((char *)&lendata, sizeof lendata, 1, fout); if ((cp = rcpp->rc_data)) for (i = rcpp->rc_datalen ; i > 0 ; i--) putc(*cp++, fout); if (rcpp->rc_file) for (i = rcpp->rc_filelen ; i > 0 ; i--) putc(getc(rcpp->rc_file), fout); for (i = rcpp->rc_bss ; i > 0 ; i--) putc(0, fout); if ((cp = rcpp->rc_rel)) for (i = rcpp->rc_rellen ; i > 0 ; i--) putc(*cp++, fout); } for (i = roundtomap ; i > 0 ; i--) putc(0, fout); /* * Write the resource map. */ rm.rm_offtype = htons(sizeof rm); rm.rm_offname = htons(sizemap - (rnp - rn)); fwrite((char *)&rm, sizeof rm, 1, fout); numtypes--; numtypes = htons(numtypes); fwrite((char *)&numtypes,sizeof numtypes, 1, fout); fwrite((char *)&rt[0], sizeof *rtp, rtp - &rt[0], fout); fwrite((char *)&ri[0], sizeof *rip, rip - &ri[0], fout); if (rnp - rn) fwrite((char *)rn, rnp - rn, 1, fout); } /* * Abort with message. */ /* VARARGS1 */ abort(s,a,b) char *s; { fprintf(stderr, "rmaker: "); fprintf(stderr, s, a, b); if (linenum) fprintf(stderr, "; line number %d", linenum); fprintf(stderr, "\n"); exit(1); } /* * Check for legal length type. Fix "STR ". */ checktype(s) char *s; { register len; len = strlen(s); if (len < 3 || len > 4) abort("bad type"); if (len == 3) { s[3] = ' '; s[4] = 0; } } /* * Copy bytes. */ bcopy(a, b, n) register n; register char *a, *b; { if (n <= 0) return; do { *b++ = *a++; } while (--n); } /* * Print the data portion of the current rcp record. */ printrcp() { char *cp; int i; unsigned int j; printf("Type %s, ID %d, length %d, datalen %d\n", rcp->rc_type, rcp->rc_id, rcp->rc_length, rcp->rc_datalen); cp = rcp->rc_data; /* pick up the data pointer */ for (i=0 ; i < rcp->rc_datalen ; i++) { j = *cp++ & 0xFF; if ((i % 16) == 15) printf("%02X\n",j); else printf("%02X ",j); } printf("\n"); } @//E*O*F rmaker.c// chmod u=rw,g=rw,o=r rmaker.c echo x - scan.c sed 's/^@//' > "scan.c" <<'@//E*O*F scan.c//' /* * scan.c * * Routines for scanning and lexical analysis of the rmaker input file. */ #include "rmaker.h" /* * Get next line of input, skipping comments. * Returns 0 if blank line, otherwise 1. */ getline() { register n; do { if ((fgets(line, sizeof line, fin)) == NULL) { fineof++; return (0); } linenum++; } while (line[0] == '*'); /* remove newline at end */ n = strlen(line); if (n == 0) return 0; if (line[n-1] == '\n') line[n-1] = 0; /* determine if it's a blank line */ lp = line; n = skipsp(); lp = line; if (n == 0) return 0; return 1; } /* * Skip spaces. Return 0 if end of line. */ skipsp() { while (*lp == ' ' || *lp == '\t') lp++; return(*lp); } /* * Skip to the next non-blank character, * reading in another line if necessary. * Return 0 if new line is blank. */ skip() { if (skipsp()) return 1; if (getline()) return skipsp(); return 0; } /* * Scan the next token from "line" into "token". * Return 0 if none left. */ gettoken() { char *tp; if (skipsp() == 0) return 0; tp = token; while (*lp != ' ' && *lp != '\t' && *lp != 0) *tp++ = *lp++; *tp = 0; return 1; } /* * Scan quoted string into "token". */ getstring() { char quote = *lp++; char *tp = token; while (*lp != quote && *lp != 0) { *tp++ = *lp++; if (lp[-1] == '\\' && *lp != 0) *tp++ = *lp++; } if (*lp == quote) ++lp; *tp = 0; } /* * Scan for one of the keywords in 'keys'. * Abort if none found, otherwise return associated value. */ int scankeys(keys) struct keylist *keys; { char *tp; struct keylist *k; if (gettoken() == 0) abort("missing keyword"); /* convert token to lower case */ for (tp = token; *tp != 0; ++tp) if (isupper(*tp)) *tp = tolower(*tp); /* determine which keyword it is */ for (k = keys; k->keyname; ++k) if (strcmp(k->keyname, token) == 0) return k->keyvalue; abort("invalid keyword %s", token); /* NOTREACHED */ } /* * Scan a short integer from the line and return it. */ scanshort() { int val; if (gettoken() == 0 || sscanf(token, "%d", &val) != 1) abort("bad or missing number"); return val; } /* * Scan a long integer from the line and return it. */ long scanlong() { long val; if (gettoken() == 0 || sscanf(token, "%ld", &val) != 1) abort("bad or missing number"); return val; } /* * Scan an n digit hex constant from the line and return it. */ scanhex(ndigits) int ndigits; { char *tp = token; int val; if (skipsp() == 0) abort("missing hex constant"); while (ndigits-- > 0) { if (!isxdigit(*lp)) abort("bad hex constant"); *tp++ = *lp++; } *tp = 0; sscanf(token, "%x", &val); return val; } @//E*O*F scan.c// chmod u=rw,g=rw,o=r scan.c exit 0