[comp.sources.mac] debugger FKEY installer/creator using LightspeedC

macintosh@felix.UUCP (09/06/87)

---
/*
 * LightspeedC source for a program to create and install a debugger
 * FKEY, number 8, in the current system file.  
 * Earle R. Horton, August 30, 1987.
 * (Inspired by Apple Technical Note # 145.)  
 * The above-mentioned technical note requires the MPW assembler, the
 * MPW linker, RMaker, and a resource editor in order to create it.  It
 * also requires MacWrite in order to decode the technical note.
 * This example requires only LightspeedC, version 2.01 or greater, and
 * requires no special program to decode it, other than a text editor.
 *
 * This example is superior to the example provided in Technical Note 145 
 * for the following reasons.
 *
 * 	a)	A data structure is used to insure our FKEY has the correct
 * 		format.
 * 	b)	The program creates the FKEY, installs it in the current
 * 		system file, and then tests it, all without leaving
 *		LightspeedC.
 *	c)	This example is more elaborate than the example in the
 *		technical note, but yet is more simple in execution.
 *			i)   It uses the C preprocessor.
 *			ii)  It uses structure assignment.
 *			iii) It uses the "application" mode of 
 *			     LightspeedC to produce stand-alone code.
 *			iv)  It uses Inline assembly.
 *
 * I know I will get bad karma for ridiculing Apple and their writers like
 * this, but I just couldn't stop myself.  I have just spent three days
 * trying to decipher the specifications for a Printing Manager, and I am
 * on the verge of "losing it".  To the moderator of comp.sources.mac:
 * Please, oh, please post this.  Make my day.
 *
 * Tabstops are 8.
 * Instructions:
 *	Make a new LightspeedC application project.  Add this source 
 *	file to it and select Run from the Project menu.  For a really
 *	bloated project file, set the macro USING_MACTRAPS equal to 1
 *	and link the project with MacTraps.
 */

#define FBRANCH(a)	(0x6000 | a)	/* Assemble a short branch. */
#define	Version		0x0000		/* Version number of zero. */
#define	IDnum		0x0008		/* Use cmd-shift-8. */
#define	Flags		0x0000		/* No flags. */
#define	Type		'FKEY'		/* It's an FKEY. */
#define	INSTRUCTIONS	2	/* How many instructions will you need? */

#define	nil	0L

/* Set the following to 1 if loading MacTraps into the project, 0 if not. */

#define USING_MACTRAPS	0

typedef struct{
	short	thebranch;		/* Standard header, branch to start. */
	short	flags;			/* You know, flags! */
	long	thename;		/* Resource type. */
	short	theid;			/* Number of resource. */
	short	theversion;		/* Two byte version for your FKEY. */
	short	instructions[INSTRUCTIONS];
					/* As many instructions as you need. */
}FKEY,*PFKEY,**HFKEY;

typedef	void (*TESTFKEY)();		/* ProcPtr for testing FKEYs. */
short	*makefkeycode();		/* Function to produce code.  */

static FKEY myfkey = {
	FBRANCH(10),			/* Branch to +10, start of our code. */
	Flags,				/* Whatever you want. */
	Type,				/* Define the type. */
	IDnum,				/* Define the ID. */
	Version,			/* Version number of this resource. */
	{0,0},				/* The actual code, to be filled in */
					/* later. */
};

main(){
HFKEY		newfkey,oldfkey;	/* Handle to FKEY resource. */
int		resultcode;		/* Abort on error. */
TESTFKEY	testing;		/* ProcPtr to test it. */
short		*stream;		/* Array to hold machine code. */
int		i;			/* Loop counter. */

	UseResFile(0);			/* Use system file. */
	oldfkey = (HFKEY)GetResource('FKEY',8);
					/* Get the old FKEY. */
	RmveResource(oldfkey);		/* Pluck it out, discard. */

	/* (Ignore errors, might not have been an old one present.) */
/* 
 * Get a handle to a block of memory big enough to hold our new FKEY.
 * Check for memory error.
 */
#if USING_MACTRAPS
	newfkey = (HFKEY)NewHandle((long)sizeof(FKEY));
	resultcode = MemError();
#else
/*
 * LightspeedC doesn't do inline register-based calls, so if you don't
 * use MacTraps, you have to do this.
 */
	asm{
		move.l	#((long)sizeof(FKEY)),d0	;; Same thing as
		NewHandle				;; above.
		move.l	a0,newfkey
		move.w	d0,resultcode
	}
#endif
	if((resultcode == 0) && (newfkey != nil)){
	/* If new handle is assumed valid. */
	
		stream = makefkeycode();		/* Get actual code. */
		for(i= 0;INSTRUCTIONS - i;i++){
			myfkey.instructions[i] = stream[i];	/* Copy it. */
		}
		**newfkey = myfkey;
		/* Do the structure assignment, Ooh, Ahh! */
		
		AddResource(newfkey,'FKEY',8,"\pDebugger FKEY");
		/* Make it an FKEY resource. */
	
		WriteResource(newfkey);
		/* Save it. */
	
		/* Let's try it out, right now! */
		testing = (TESTFKEY)(*newfkey);
		(*testing)();
	}
}
/* This function is in two parts.  The first part returns a pointer to 
 * the second part, then returns.  The second part contains the actual
 * FKEY code.
 */
short	*makefkeycode()
{
	asm{
		dc.l	0x41FA0006		;; lea 8(pc),a0
		move.l	a0,d0			;; d0 = return value
		rts
		Debugger			;; FKEY code here
		rts				;; don't forget to return
	}
}
---