[net.sources.mac] New SUMacC RMaker

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