_XCMD and XFCN_
by
Stan Krute


Listing One


*--------------------------------------- file information 
*	XCMDandXFCN.a									
*	MPW record definitions useful in XCMD and XFCN work				
*	Edited with MPW 2.02								
*	Compiled under MPW 2.02								
*	Written and (C)1988 by Stan Krute. All rights reserved. 				
*-----------------------------------------------------------------------

; general array structures

Array4L		RECORD	0	; an array of 4 longs
zero		DS.L	1
one		DS.L	1
two		DS.L	1
three		DS.L	1
		ENDR
			
Array8L		RECORD	0	; an array of 8 longs
zero		DS.L	1
one		DS.L	1
two		DS.L	1
three		DS.L	1
four		DS.L	1
five		DS.L	1
six		DS.L	1
seven		DS.L	1
		ENDR
				
Array16L	RECORD	0	; an array of 16 longs
zero		DS.L	1
one		DS.L	1
two		DS.L	1
three		DS.L	1
four		DS.L	1
five		DS.L	1
six		DS.L	1
seven		DS.L	1
eight		DS.L	1
nine		DS.L	1
ten		DS.L	1
eleven		DS.L	1
twelve		DS.L	1
thirteen	DS.L	1
fourteen	DS.L	1
fifteen		DS.L	1
		ENDR

; an XCmdBlock record

XCmdBlock	RECORD 0
paramCount	DS.W	1		; # of entry parameters 
params		DS	Array16L	; array of handles to entry parameters
returnValue	DS.L	1		; handle to a return value
passFlag	DS.W	2		; boolean: if true, HC passes message on

entryPoint	DS.L	1		; pointer to HyperCard callback function (cbf)	
request		DS.W	1		; a cbf command code               	
result		DS.W  	1		; HC's answer to a cbf command     	
inArgs		DS	Array8L   	; array of arguments in to a cbf command    
outArgs   	DS	Array4L		; array of arguments out from a cbf command 
		ENDR



Listing Two


# make instructions for the isAlpha XFCN

# the object file depends on the assembly language source code file 
isAlpha.a.o	f	isAlpha.a 
# to create the object file, assemble the assembly language source code file
	# the source code file is isAlpha.a
	# we'll send a listing to the file isAlpha.a.lst
	Asm isAlpha.a -l

# the resource file depends on the object file
isAlpha		f	isAlpha.a.o
# to create the resource file, link the object file
	# the output file is isAlpha
	# the output file's type is RSRC
	# the output file's creator is RSED
	# the code will be an XFCN resource with ID #990
	# the segment name will be isAlpha, same as the new HyperCard command name
	# the input file is the object file isAlpha.a.o 
	Link -o isAlpha -t RSRC -c RSED -rt XFCN=990 -sn Main=isAlpha isAlpha.a.o  


Listing Three

*--------------------------------------- file information 
*	isAlpha.a									
*	Assembly language source code for the HyperCard XFCN isAlpha				
*	Given a character, isAlpha returns the string 'true' 
*       if the character is an uppercase or lowercase letter, the
*       string 'false' if it is not.		
*       A c function prototype might look like this:
*		BOOLEAN_STRING isAlpha(CHAR chSomeChar) ;
*	Edited with MPW 2.02
*	Compiled under MPW 2.02
*	Written and )1988 by Stan Krute. All rights reserved. 
*       No part of this file other files in the project it belongs to, 
*       or the object code the file(s) lead(s) to, may be reproduced, 
*       in any form or by any means, without the express written 
*       permission of the author and copyright holder.		
*-------------------------------------------------------------------	


*-------------------------------------- include files 	

; standard Mac definitions
	INCLUDE 	'QuickEqu.a'		; quickdraw
	INCLUDE 	'ToolEqu.a'		; toolbox
	INCLUDE 	'SysEqu.a'		; system
	INCLUDE 	'Traps.a'		; traps

; our stuff
	INCLUDE 	'XCMDandXFCN.a'		; XCMD and XFCN definitions		


*------------------------------------------ isAlpha -----------------	

; set local constants
smallBlockSize		SET	6	; size of a small result block we'll allocate
XCmdPtr			SET	8	; where we'll find the XCmdPtr after register saving
bytesOfEntryParams	SET	4	; bytes of entry parameters

isAlpha	MAIN	
	; save a register
	MOVE.L		A2,-(SP)

	; get a small result block, filled with zeroes for cheap 0-terminated strings
	MOVE.L		#smallBlockSize,D0
	_NewHandle 	,CLEAR

	; store the result block's handle as a return value
	MOVE.L		XCmdPtr(SP),A2       		; A2 gets pointer to XCmdBlock
	MOVE.L		A0,XCmdBlock.returnValue(A2)    ; handle to result block
	
	; point to the result block
	MOVE.L		(A0),A0	
	
	; get the single entry parameter
	MOVE.L		XCmdBlock.params.zero(A2),A1   	; handle to first entry parameter
	MOVE.L    	(A1),A1				; pointer to first entry parameter
	
	; clear a data register, and move entry parameter, a character, into it
	CLR.L	D0
	MOVE.B	(A1),D0	
	
	; now run a series of boundary tests
	; check against the low bound of upper-casedness
	CMP.B	#'A',D0
	BLT.S	notAlpha	; less than this, and we're not alphabetical
	
	; check against the high bound of upper-casedness
	CMP.B	#'Z',D0
	BLE.S	yesAlpha	; less than or equal to this, and we're upper-case,
				; thus alphabetical
	
	; check against the low bound of lower-casedness
	CMP.B	#'a',D0
	BLT.S	notAlpha	; less than this, and we're not alphabetical
	
	; check against the high bound of lower-casedness
	CMP.B	#'z',D0
	BGT.S	notAlpha	; greater than this, and we're not alphabetical
	
yesAlpha	
	; we have an upper- or lower-case letter
	; set result into result block
	MOVE.L	#'true',(A0)
	BRA.S	bye
	
notAlpha	
	; we have neither an upper- nor a lower-case letter
	; set result into result block
	MOVE.L	#'fals',(A0)+
	MOVE.B	#'e',(A0)
	
bye	; tell HyperCard we've handled things
	CLR.W	XCmdBlock.passFlag(A2)
	
	; restore a register
	MOVE.L	(SP)+,A2
	
	; move the return address into A0
	MOVE.L 	(A7)+,A0
	
	; jump over entry parameters
	ADD.W	#bytesOfEntryParams,A7
	
	; puffasmoke and we be gone
	JMP 	(A0)
	
	; end of the procedure
	ENDPROC
	
	; end of the assembly language source file



Example 1: C rendition of an XCmdBlock data structure

#include "Types.r"
resource 'SIZE' (-1, purgeable) {
    dontSaveScreen,
    ignoreSuspendResumeEvents,
    disableOptionSwitch,
    cannotBackground,
    notMultiFinderAware,
    150*1024, /* maximum size 150K */
    150*1024  /* minimum size 150K */
    };


