//	ScriptMenu.c////	This file defines a "Script" menu//	UPDATED 06/12/97 to use the new PB trap names//	(can somebody tell me why Apple saw fit to change half the trap names,//	only a year before they all go out the window for Rhapsody anyway?)//	NOTE: if you're using an older compiler that doesn't like these//	"PBxxxSync" names, take off the "Sync", and add "FALSE" as an extra//	parameter to the function!//	UPDATED 8/15/97 to use an icon for the menu title instead of the//	word "Scripts", if an 'ics#' whose name matches kScriptMenuIconName//	(defined below) is available.#include "ScriptMenu.h"#include <Icons.h>// script icon suite resource ID#define kScriptMenuIconName "\pScript Menu Icon"// global variablesMenuHandle smMenuHdl = 0;ComponentInstance smComponent = nil;Handle smIconSuite = nil;OSErr DoScriptScpt( Handle scpt );// Execute the script from its raw resource data handle.OSErr DoScriptScpt( Handle scpt ){	OSErr err;	OSAID scriptID;	OSAID resultID;	// load the script into the scripting component, and get its "ID"	AEDesc 	scriptDesc;		// (need a descriptor to talk to OSA)	scriptDesc.descriptorType = typeOSAGenericStorage;	scriptDesc.dataHandle = scpt;	err = OSALoad(smComponent,&scriptDesc,kOSAModeNull,&scriptID);	if (err) return err;		// execute the script, dispose of the results	err = OSAExecute(smComponent,scriptID,kOSANullScript,kOSAModeNull,&resultID);	if (err) return err;	else OSADispose(smComponent,resultID);	// dispose of the script	return OSADispose(smComponent,scriptID);}OSErr DoScriptFSSpec( FSSpec *filespec );// Execute a script from its FSSpec.OSErr DoScriptFSSpec( FSSpec *filespec ){	short 	fRefNum;	OSErr	err;	Handle	scpt;//	Handle	desc = 0;					// open resource fork	fRefNum = FSpOpenResFile( filespec, fsRdPerm );	if (fRefNum == -1) return ResError();		// get the first script resource in the file	scpt = Get1IndResource('scpt',1); 	if (!scpt) return ResError();	// the first text resource has the description of the script (if any)	// we fail quietly if there's no text, since it's optional/*	desc = Get1IndResource('TEXT',1);	if (desc) DetachResource(desc);*/	// execute the scpt	err = DoScriptScpt( scpt );	// note that the script might have changed property values	ChangedResource( scpt );	err = ResError();	if (!err) WriteResource( scpt );		// close the resource file -- it's no longer needed	if (fRefNum != -1) CloseResFile(fRefNum);	// (the data should be freed automatically by CloseResFile)//	if (scpt) DisposeHandle( scpt );//	if (desc) DisposeHandle( desc );		return err;}OSErr ScanScriptFolder();// scan the "Scripts" folder, and add the scripts found to the menuOSErr ScanScriptFolder(){	CInfoPBRec	cipbr;						// local parameter block	HFileInfo	*fpb = (HFileInfo *)&cipbr;	// two pointers	DirInfo	*dpb = (DirInfo *) &cipbr;	OSErr	err;	short	idx, volID;	long	dirID;	Str255	pathname = "\pScripts";	Str255	temp = "\pScripts";	// first, get volume reference number via PBHGetVInfo...	HVolumeParam	hpb;	hpb.ioNamePtr = temp;		// (use temp, since it will be overwritten)	hpb.ioVRefNum = 0;			// use pathname, not ref num	hpb.ioVolIndex = -1;		// don't use volume index either	err = PBHGetVInfoSync( (HParmBlkPtr)&hpb );	if (err) return err;		// bail out if can't get volume info	volID = hpb.ioVRefNum;	// next, get directory ID via PBGetCatInfo...	fpb->ioVRefNum = 0;			fpb->ioNamePtr = pathname;	// partial pathname, and buffer to receive name	fpb->ioDirID = 0;			// search from working directory	fpb->ioFDirIndex = 0;		// gimme info about the named directory	err = PBGetCatInfoSync( &cipbr );	// *** get the catalog info ***	if (err) return err;			// if error getting directory info, then bail out	dirID = dpb->ioDrDirID;	// get directory ID for subsequent searching		// now loop through files using PBGetCatInfo...	fpb->ioVRefNum = volID;	for( idx=1; TRUE; idx++) {		fpb->ioDirID = dirID;		// set ioDirID on each loop		fpb->ioFDirIndex = idx;		// index of entry to return		err = PBGetCatInfoSync( &cipbr );		if (err) break;				// exit when no more entries		// now pathname contains the full name of a file within this directory		if (fpb->ioFlAttrib & 16) {			// we have a subdirectory			// LATER: implement sub-menus here		}		else {			// we have a file			if (fpb->ioFlFndrInfo.fdType == kOSAFileType) {				// add it to the script menu				AppendMenu( smMenuHdl, pathname );				// attach balloon help for it				// (LATER!!!)			}		}	}	return noErr;}// build a menu from the Scripts folder,// and initialize the OSA component needed to execute scriptsOSErr BuildScriptMenu( const short menuID ){	OSErr err;	Handle tempRsrc;	Str255 tempStr;	short iconID;	ResType tempResType;		// delete previous menu and icon suite, if any	if (smMenuHdl) {		DisposeMenu(smMenuHdl);		smMenuHdl = nil;	}	if (smIconSuite) {		DisposeIconSuite(smIconSuite, TRUE);		smIconSuite = nil;	}		// see if we can find the script icon	tempRsrc = GetNamedResource('ics#', kScriptMenuIconName );	err = ResError();	if (tempRsrc) {		GetResInfo(tempRsrc,&iconID,&tempResType,tempStr);		ReleaseResource(tempRsrc);		GetIconSuite( &smIconSuite, iconID, kSelectorAllSmallData );		if (smIconSuite) {			// build menu with icon for title			// c.f. Apple Technical Q&A Tidbit 06			//		http://devworld.apple.com/dev/qa/tb/tb06.html			smMenuHdl = NewMenu( menuID, "\p12345" );			(**smMenuHdl).menuData[1] = 0x01;			*((long *)&((**smMenuHdl).menuData[2])) = (long)smIconSuite;		}	}	if (!smMenuHdl) {		// build menu with ordinary text title		smMenuHdl = NewMenu( menuID, "\pScripts" );	}		// build the list of scripts	err = ScanScriptFolder();	if (err) return err;		// insert into the menu bar	InsertMenu( smMenuHdl, 0 );	// create the OSA scripting component	if (!smComponent) 		smComponent = OpenDefaultComponent(kOSAComponentType,'scpt');	return noErr;}// enable the Scripts menuvoid EnableScriptMenu(){	// we'd like to just say this:	//		EnableItem( smMenuHdl, 0 );	// ...but some apps (like MacZoop) muck with the enable flags,	// and then this doesn't work.  So we'll do it the hard way:	short i;	short cnt = CountMItems( smMenuHdl );	for (i=0; i<=cnt; i++) {		EnableItem( smMenuHdl, i );	}}// disable the Scripts menuvoid DisableScriptMenu(){	DisableItem( smMenuHdl, 0 );}// handle a menu selectionOSErr HandleScriptMenuSelection( const short num ){	OSErr err;	FSSpec filespec;	Str255	scriptname, pathname = "\p:Scripts:";	short i;		// build a pathname for the chosen script	GetMenuItemText( smMenuHdl, num, scriptname);	for (i=1; i<=scriptname[0]; i++)		pathname[pathname[0]+i] = scriptname[i];	pathname[0] += i-1;		// make an FSSpec out of the given script name	err = FSMakeFSSpec(0, 0, pathname, &filespec);	// execute the script by its FSSpec	if (!err) err = DoScriptFSSpec( &filespec );	}