#include <Errors.h>
#include <FSpCompat.h>
#include <Processes.h>
#include <Resources.h>
#include <Sound.h>
#include <Strings.h>
#include <Traps.h>
#include <LowMem.h>
#include "FullPath.h"
#include "tcl.h"
#include "tclInt.h"
#include "tclMac.h"
#include "tclMacInt.h"
#include "tclMacPort.h"
#define TCL_RESOURCE_INSERT_TAIL 1
#define TCL_RESOURCE_CHECK_IF_OPEN 4
enum WhichVolume {
SYS_BEEP_VOLUME,
DEFAULT_SND_VOLUME,
RESET_VOLUME
};
typedef struct OpenResourceFork {
short fileRef;
int flags;
} OpenResourceFork;
static Tcl_HashTable nameTable;
static Tcl_HashTable resourceTable;
static Tcl_Obj *resourceForkList;
static int appResourceIndex;
static int newId = 0;
static int initialized = 0;
static int osTypeInit = 0;
static void DupOSTypeInternalRep _ANSI_ARGS_((Tcl_Obj *srcPtr,
Tcl_Obj *copyPtr));
static void ResourceInit _ANSI_ARGS_((void));
static void BuildResourceForkList _ANSI_ARGS_((void));
static int SetOSTypeFromAny _ANSI_ARGS_((Tcl_Interp *interp,
Tcl_Obj *objPtr));
static void UpdateStringOfOSType _ANSI_ARGS_((Tcl_Obj *objPtr));
static OpenResourceFork* GetRsrcRefFromObj _ANSI_ARGS_((Tcl_Obj *objPtr,
int okayOnReadOnly, const char *operation,
Tcl_Obj *resultPtr));
static void SetSoundVolume(int volume, enum WhichVolume mode);
static Tcl_ObjType osType = {
"ostype",
(Tcl_FreeInternalRepProc *) NULL,
DupOSTypeInternalRep,
UpdateStringOfOSType,
SetOSTypeFromAny
};
int
Tcl_ResourceObjCmd(
ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[])
{
Tcl_Obj *resultPtr, *objPtr;
int index, result;
long fileRef, rsrcId;
FSSpec fileSpec;
Tcl_DString buffer;
char *nativeName;
char *stringPtr;
char errbuf[16];
OpenResourceFork *resourceRef;
Handle resource = NULL;
OSErr err;
int count, i, limitSearch = false, length;
short id, saveRef, resInfo;
Str255 theName;
OSType rezType;
int gotInt, releaseIt = 0, force;
char *resourceId = NULL;
long size;
char macPermision;
int mode;
static char *switches[] = {"close", "delete" ,"files", "list",
"open", "read", "types", "write", (char *) NULL
};
enum {
RESOURCE_CLOSE, RESOURCE_DELETE, RESOURCE_FILES, RESOURCE_LIST,
RESOURCE_OPEN, RESOURCE_READ, RESOURCE_TYPES, RESOURCE_WRITE
};
static char *writeSwitches[] = {
"-id", "-name", "-file", "-force", (char *) NULL
};
enum {
RESOURCE_WRITE_ID, RESOURCE_WRITE_NAME,
RESOURCE_WRITE_FILE, RESOURCE_FORCE
};
static char *deleteSwitches[] = {"-id", "-name", "-file", (char *) NULL};
enum {RESOURCE_DELETE_ID, RESOURCE_DELETE_NAME, RESOURCE_DELETE_FILE};
resultPtr = Tcl_GetObjResult(interp);
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "option ?arg ...?");
return TCL_ERROR;
}
if (Tcl_GetIndexFromObj(interp, objv[1], switches, "option", 0, &index)
!= TCL_OK) {
return TCL_ERROR;
}
if (!initialized) {
ResourceInit();
}
result = TCL_OK;
switch (index) {
case RESOURCE_CLOSE:
if (objc != 3) {
Tcl_WrongNumArgs(interp, 2, objv, "resourceRef");
return TCL_ERROR;
}
stringPtr = Tcl_GetStringFromObj(objv[2], &length);
fileRef = TclMacUnRegisterResourceFork(stringPtr, resultPtr);
if (fileRef >= 0) {
CloseResFile((short) fileRef);
return TCL_OK;
} else {
return TCL_ERROR;
}
case RESOURCE_DELETE:
if (!((objc >= 3) && (objc <= 9) && ((objc % 2) == 1))) {
Tcl_WrongNumArgs(interp, 2, objv,
"?-id resourceId? ?-name resourceName? ?-file \
resourceRef? resourceType");
return TCL_ERROR;
}
i = 2;
fileRef = -1;
gotInt = false;
resourceId = NULL;
limitSearch = false;
while (i < (objc - 2)) {
if (Tcl_GetIndexFromObj(interp, objv[i], deleteSwitches,
"option", 0, &index) != TCL_OK) {
return TCL_ERROR;
}
switch (index) {
case RESOURCE_DELETE_ID:
if (Tcl_GetLongFromObj(interp, objv[i+1], &rsrcId)
!= TCL_OK) {
return TCL_ERROR;
}
gotInt = true;
break;
case RESOURCE_DELETE_NAME:
resourceId = Tcl_GetStringFromObj(objv[i+1], &length);
if (length > 255) {
Tcl_AppendStringsToObj(resultPtr,"-name argument ",
"too long, must be < 255 characters",
(char *) NULL);
return TCL_ERROR;
}
strcpy((char *) theName, resourceId);
resourceId = (char *) theName;
c2pstr(resourceId);
break;
case RESOURCE_DELETE_FILE:
resourceRef = GetRsrcRefFromObj(objv[i+1], 0,
"delete from", resultPtr);
if (resourceRef == NULL) {
return TCL_ERROR;
}
limitSearch = true;
break;
}
i += 2;
}
if ((resourceId == NULL) && !gotInt) {
Tcl_AppendStringsToObj(resultPtr,"you must specify either ",
"\"-id\" or \"-name\" or both ",
"to \"resource delete\"",
(char *) NULL);
return TCL_ERROR;
}
if (Tcl_GetOSTypeFromObj(interp, objv[i], &rezType) != TCL_OK) {
return TCL_ERROR;
}
if (limitSearch) {
saveRef = CurResFile();
UseResFile((short) resourceRef->fileRef);
}
SetResLoad(false);
if (gotInt == true) {
if (limitSearch) {
resource = Get1Resource(rezType, rsrcId);
} else {
resource = GetResource(rezType, rsrcId);
}
err = ResError();
if (err == resNotFound || resource == NULL) {
Tcl_AppendStringsToObj(resultPtr, "resource not found",
(char *) NULL);
result = TCL_ERROR;
goto deleteDone;
} else if (err != noErr) {
char buffer[16];
sprintf(buffer, "%12d", err);
Tcl_AppendStringsToObj(resultPtr, "resource error #",
buffer, "occured while trying to find resource",
(char *) NULL);
result = TCL_ERROR;
goto deleteDone;
}
}
if (resourceId != NULL) {
Handle tmpResource;
if (limitSearch) {
tmpResource = Get1NamedResource(rezType,
(StringPtr) resourceId);
} else {
tmpResource = GetNamedResource(rezType,
(StringPtr) resourceId);
}
err = ResError();
if (err == resNotFound || tmpResource == NULL) {
Tcl_AppendStringsToObj(resultPtr, "resource not found",
(char *) NULL);
result = TCL_ERROR;
goto deleteDone;
} else if (err != noErr) {
char buffer[16];
sprintf(buffer, "%12d", err);
Tcl_AppendStringsToObj(resultPtr, "resource error #",
buffer, "occured while trying to find resource",
(char *) NULL);
result = TCL_ERROR;
goto deleteDone;
}
if (gotInt) {
if (resource != tmpResource) {
Tcl_AppendStringsToObj(resultPtr,
"\"-id\" and \"-name\" ",
"values do not point to the same resource",
(char *) NULL);
result = TCL_ERROR;
goto deleteDone;
}
} else {
resource = tmpResource;
}
}
resInfo = GetResAttrs(resource);
if ((resInfo & resProtected) == resProtected) {
Tcl_AppendStringsToObj(resultPtr, "resource ",
"cannot be deleted: it is protected.",
(char *) NULL);
result = TCL_ERROR;
goto deleteDone;
} else if ((resInfo & resSysHeap) == resSysHeap) {
Tcl_AppendStringsToObj(resultPtr, "resource",
"cannot be deleted: it is in the system heap.",
(char *) NULL);
result = TCL_ERROR;
goto deleteDone;
}
RemoveResource(resource);
if (!limitSearch) {
UpdateResFile(HomeResFile(resource));
} else {
UpdateResFile(resourceRef->fileRef);
}
deleteDone:
SetResLoad(true);
if (limitSearch) {
UseResFile(saveRef);
}
return result;
case RESOURCE_FILES:
if ((objc < 2) || (objc > 3)) {
Tcl_SetStringObj(resultPtr,
"wrong # args: should be \"resource files \
?resourceId?\"", -1);
return TCL_ERROR;
}
if (objc == 2) {
stringPtr = Tcl_GetStringFromObj(resourceForkList, &length);
Tcl_SetStringObj(resultPtr, stringPtr, length);
} else {
FCBPBRec fileRec;
Handle pathHandle;
short pathLength;
Str255 fileName;
if (strcmp(Tcl_GetStringFromObj(objv[2], NULL), "ROM Map")
== 0) {
Tcl_SetStringObj(resultPtr,"no file path for ROM Map", -1);
return TCL_ERROR;
}
resourceRef = GetRsrcRefFromObj(objv[2], 1, "files", resultPtr);
if (resourceRef == NULL) {
return TCL_ERROR;
}
fileRec.ioCompletion = NULL;
fileRec.ioFCBIndx = 0;
fileRec.ioNamePtr = fileName;
fileRec.ioVRefNum = 0;
fileRec.ioRefNum = resourceRef->fileRef;
err = PBGetFCBInfo(&fileRec, false);
if (err != noErr) {
Tcl_SetStringObj(resultPtr,
"could not get FCB for resource file", -1);
return TCL_ERROR;
}
err = GetFullPath(fileRec.ioFCBVRefNum, fileRec.ioFCBParID,
fileRec.ioNamePtr, &pathLength, &pathHandle);
if ( err != noErr) {
Tcl_SetStringObj(resultPtr,
"could not get file path from token", -1);
return TCL_ERROR;
}
HLock(pathHandle);
Tcl_SetStringObj(resultPtr,*pathHandle,pathLength);
HUnlock(pathHandle);
DisposeHandle(pathHandle);
}
return TCL_OK;
case RESOURCE_LIST:
if (!((objc == 3) || (objc == 4))) {
Tcl_WrongNumArgs(interp, 2, objv, "resourceType ?resourceRef?");
return TCL_ERROR;
}
if (Tcl_GetOSTypeFromObj(interp, objv[2], &rezType) != TCL_OK) {
return TCL_ERROR;
}
if (objc == 4) {
resourceRef = GetRsrcRefFromObj(objv[3], 1,
"list", resultPtr);
if (resourceRef == NULL) {
return TCL_ERROR;
}
saveRef = CurResFile();
UseResFile((short) resourceRef->fileRef);
limitSearch = true;
}
Tcl_ResetResult(interp);
if (limitSearch) {
count = Count1Resources(rezType);
} else {
count = CountResources(rezType);
}
SetResLoad(false);
for (i = 1; i <= count; i++) {
if (limitSearch) {
resource = Get1IndResource(rezType, i);
} else {
resource = GetIndResource(rezType, i);
}
if (resource != NULL) {
GetResInfo(resource, &id, (ResType *) &rezType, theName);
if (theName[0] != 0) {
objPtr = Tcl_NewStringObj((char *) theName + 1,
theName[0]);
} else {
objPtr = Tcl_NewIntObj(id);
}
ReleaseResource(resource);
result = Tcl_ListObjAppendElement(interp, resultPtr,
objPtr);
if (result != TCL_OK) {
Tcl_DecrRefCount(objPtr);
break;
}
}
}
SetResLoad(true);
if (limitSearch) {
UseResFile(saveRef);
}
return TCL_OK;
case RESOURCE_OPEN:
if (!((objc == 3) || (objc == 4))) {
Tcl_WrongNumArgs(interp, 2, objv, "fileName ?permissions?");
return TCL_ERROR;
}
stringPtr = Tcl_GetStringFromObj(objv[2], &length);
nativeName = Tcl_TranslateFileName(interp, stringPtr, &buffer);
if (nativeName == NULL) {
return TCL_ERROR;
}
err = FSpLocationFromPath(strlen(nativeName), nativeName,
&fileSpec) ;
Tcl_DStringFree(&buffer);
if (!((err == noErr) || (err == fnfErr))) {
Tcl_AppendStringsToObj(resultPtr,
"invalid path", (char *) NULL);
return TCL_ERROR;
}
if (objc == 4) {
stringPtr = Tcl_GetStringFromObj(objv[3], &length);
mode = TclGetOpenMode(interp, stringPtr, &index);
if (mode == -1) {
return TCL_ERROR;
}
switch (mode & (O_RDONLY | O_WRONLY | O_RDWR)) {
case O_RDONLY:
macPermision = fsRdPerm;
break;
case O_WRONLY:
case O_RDWR:
macPermision = fsRdWrShPerm;
break;
default:
panic("Tcl_ResourceObjCmd: invalid mode value");
break;
}
} else {
macPermision = fsRdPerm;
}
SetResLoad(false);
fileRef = (long) FSpOpenResFileCompat(&fileSpec, macPermision);
SetResLoad(true);
if (fileRef == -1) {
err = ResError();
if (((err == fnfErr) || (err == eofErr)) &&
(macPermision == fsRdWrShPerm)) {
HCreateResFile(fileSpec.vRefNum, fileSpec.parID,
fileSpec.name);
fileRef = (long) FSpOpenResFileCompat(&fileSpec,
macPermision);
if (fileRef == -1) {
goto openError;
}
} else if (err == fnfErr) {
Tcl_AppendStringsToObj(resultPtr,
"file does not exist", (char *) NULL);
return TCL_ERROR;
} else if (err == eofErr) {
Tcl_AppendStringsToObj(resultPtr,
"file does not contain resource fork", (char *) NULL);
return TCL_ERROR;
} else {
openError:
Tcl_AppendStringsToObj(resultPtr,
"error opening resource file", (char *) NULL);
return TCL_ERROR;
}
}
if (macPermision == fsRdPerm) {
SetResFileAttrs(fileRef, mapReadOnly);
}
Tcl_SetStringObj(resultPtr, "", 0);
if (TclMacRegisterResourceFork(fileRef, resultPtr,
TCL_RESOURCE_CHECK_IF_OPEN) != TCL_OK) {
CloseResFile(fileRef);
return TCL_ERROR;
}
return TCL_OK;
case RESOURCE_READ:
if (!((objc == 4) || (objc == 5))) {
Tcl_WrongNumArgs(interp, 2, objv,
"resourceType resourceId ?resourceRef?");
return TCL_ERROR;
}
if (Tcl_GetOSTypeFromObj(interp, objv[2], &rezType) != TCL_OK) {
return TCL_ERROR;
}
if (Tcl_GetLongFromObj((Tcl_Interp *) NULL, objv[3], &rsrcId)
!= TCL_OK) {
resourceId = Tcl_GetStringFromObj(objv[3], &length);
}
if (objc == 5) {
stringPtr = Tcl_GetStringFromObj(objv[4], &length);
} else {
stringPtr = NULL;
}
resource = Tcl_MacFindResource(interp, rezType, resourceId,
rsrcId, stringPtr, &releaseIt);
if (resource != NULL) {
size = GetResourceSizeOnDisk(resource);
Tcl_SetStringObj(resultPtr, *resource, size);
if (releaseIt) {
ReleaseResource(resource);
}
return TCL_OK;
} else {
Tcl_AppendStringsToObj(resultPtr, "could not load resource",
(char *) NULL);
return TCL_ERROR;
}
case RESOURCE_TYPES:
if (!((objc == 2) || (objc == 3))) {
Tcl_WrongNumArgs(interp, 2, objv, "?resourceRef?");
return TCL_ERROR;
}
if (objc == 3) {
resourceRef = GetRsrcRefFromObj(objv[2], 1,
"get types of", resultPtr);
if (resourceRef == NULL) {
return TCL_ERROR;
}
saveRef = CurResFile();
UseResFile((short) resourceRef->fileRef);
limitSearch = true;
}
if (limitSearch) {
count = Count1Types();
} else {
count = CountTypes();
}
for (i = 1; i <= count; i++) {
if (limitSearch) {
Get1IndType((ResType *) &rezType, i);
} else {
GetIndType((ResType *) &rezType, i);
}
objPtr = Tcl_NewOSTypeObj(rezType);
result = Tcl_ListObjAppendElement(interp, resultPtr, objPtr);
if (result != TCL_OK) {
Tcl_DecrRefCount(objPtr);
break;
}
}
if (limitSearch) {
UseResFile(saveRef);
}
return result;
case RESOURCE_WRITE:
if ((objc < 4) || (objc > 11)) {
Tcl_WrongNumArgs(interp, 2, objv,
"?-id resourceId? ?-name resourceName? ?-file resourceRef?\
?-force? resourceType data");
return TCL_ERROR;
}
i = 2;
gotInt = false;
resourceId = NULL;
limitSearch = false;
force = 0;
while (i < (objc - 2)) {
if (Tcl_GetIndexFromObj(interp, objv[i], writeSwitches,
"switch", 0, &index) != TCL_OK) {
return TCL_ERROR;
}
switch (index) {
case RESOURCE_WRITE_ID:
if (Tcl_GetLongFromObj(interp, objv[i+1], &rsrcId)
!= TCL_OK) {
return TCL_ERROR;
}
gotInt = true;
i += 2;
break;
case RESOURCE_WRITE_NAME:
resourceId = Tcl_GetStringFromObj(objv[i+1], &length);
strcpy((char *) theName, resourceId);
resourceId = (char *) theName;
c2pstr(resourceId);
i += 2;
break;
case RESOURCE_WRITE_FILE:
resourceRef = GetRsrcRefFromObj(objv[i+1], 0,
"write to", resultPtr);
if (resourceRef == NULL) {
return TCL_ERROR;
}
limitSearch = true;
i += 2;
break;
case RESOURCE_FORCE:
force = 1;
i += 1;
break;
}
}
if (Tcl_GetOSTypeFromObj(interp, objv[i], &rezType) != TCL_OK) {
return TCL_ERROR;
}
stringPtr = Tcl_GetStringFromObj(objv[i+1], &length);
if (gotInt == false) {
rsrcId = UniqueID(rezType);
}
if (resourceId == NULL) {
resourceId = (char *) "\p";
}
if (limitSearch) {
saveRef = CurResFile();
UseResFile((short) resourceRef->fileRef);
}
if (gotInt == true) {
SetResLoad(false);
resource = Get1Resource(rezType,rsrcId);
SetResLoad(true);
}
if (resource == NULL) {
resource = NewHandle(length);
if (resource == NULL) {
resource = NewHandleSys(length);
if (resource == NULL) {
panic("could not allocate memory to write resource");
}
}
HLock(resource);
memcpy(*resource, stringPtr, length);
HUnlock(resource);
AddResource(resource, rezType, (short) rsrcId,
(StringPtr) resourceId);
releaseIt = 1;
} else {
if (*resource == NULL) {
releaseIt = 1;
} else {
releaseIt = 0;
}
if (!force) {
sprintf(errbuf,"%d", rsrcId);
Tcl_AppendStringsToObj(resultPtr, "the resource ",
errbuf, " already exists, use \"-force\"",
" to overwrite it.", (char *) NULL);
result = TCL_ERROR;
goto writeDone;
} else if (GetResAttrs(resource) & resProtected) {
sprintf(errbuf,"%d", rsrcId);
Tcl_AppendStringsToObj(resultPtr,
"could not write resource id ",
errbuf, " of type ",
Tcl_GetStringFromObj(objv[i],&length),
", it was protected.",(char *) NULL);
result = TCL_ERROR;
goto writeDone;
} else {
if (*resource == 0) {
LoadResource(resource);
err = ResError();
if (err != noErr) {
sprintf(errbuf,"%d", rsrcId);
Tcl_AppendStringsToObj(resultPtr,
"error loading resource ",
errbuf, " of type ",
Tcl_GetStringFromObj(objv[i],&length),
" to overwrite it", (char *) NULL);
goto writeDone;
}
}
SetHandleSize(resource, length);
if ( MemError() != noErr ) {
panic("could not allocate memory to write resource");
}
HLock(resource);
memcpy(*resource, stringPtr, length);
HUnlock(resource);
ChangedResource(resource);
SetResInfo(resource, rsrcId, (StringPtr) resourceId);
}
}
err = ResError();
if (err != noErr) {
Tcl_AppendStringsToObj(resultPtr,
"error adding resource to resource map",
(char *) NULL);
result = TCL_ERROR;
goto writeDone;
}
WriteResource(resource);
err = ResError();
if (err != noErr) {
Tcl_AppendStringsToObj(resultPtr,
"error writing resource to disk",
(char *) NULL);
result = TCL_ERROR;
}
writeDone:
if (releaseIt) {
ReleaseResource(resource);
err = ResError();
if (err != noErr) {
Tcl_AppendStringsToObj(resultPtr,
"error releasing resource",
(char *) NULL);
result = TCL_ERROR;
}
}
if (limitSearch) {
UseResFile(saveRef);
}
return result;
default:
panic("Tcl_GetIndexFromObject returned unrecognized option");
return TCL_ERROR;
}
}
int
Tcl_MacSourceObjCmd(
ClientData dummy,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[])
{
char *errNum = "wrong # args: ";
char *errBad = "bad argument: ";
char *errStr;
char *fileName = NULL, *rsrcName = NULL;
long rsrcID = -1;
char *string;
int length;
if (objc < 2 || objc > 4) {
errStr = errNum;
goto sourceFmtErr;
}
if (objc == 2) {
string = TclGetStringFromObj(objv[1], &length);
return Tcl_EvalFile(interp, string);
}
string = TclGetStringFromObj(objv[1], &length);
if (!strcmp(string, "-rsrc") || !strcmp(string, "-rsrcname")) {
rsrcName = TclGetStringFromObj(objv[2], &length);
} else if (!strcmp(string, "-rsrcid")) {
if (Tcl_GetLongFromObj(interp, objv[2], &rsrcID) != TCL_OK) {
return TCL_ERROR;
}
} else {
errStr = errBad;
goto sourceFmtErr;
}
if (objc == 4) {
fileName = TclGetStringFromObj(objv[3], &length);
}
return Tcl_MacEvalResource(interp, rsrcName, rsrcID, fileName);
sourceFmtErr:
Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), errStr, "should be \"",
Tcl_GetStringFromObj(objv[0], (int *) NULL),
" fileName\" or \"",
Tcl_GetStringFromObj(objv[0], (int *) NULL),
" -rsrc name ?fileName?\" or \"",
Tcl_GetStringFromObj(objv[0], (int *) NULL),
" -rsrcid id ?fileName?\"", (char *) NULL);
return TCL_ERROR;
}
int
Tcl_BeepObjCmd(
ClientData dummy,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[])
{
Tcl_Obj *resultPtr, *objPtr;
Handle sound;
Str255 sndName;
int volume = -1, length;
char * sndArg = NULL;
resultPtr = Tcl_GetObjResult(interp);
if (objc == 1) {
SysBeep(1);
return TCL_OK;
} else if (objc == 2) {
if (!strcmp(Tcl_GetStringFromObj(objv[1], &length), "-list")) {
int count, i;
short id;
Str255 theName;
ResType rezType;
count = CountResources('snd ');
for (i = 1; i <= count; i++) {
sound = GetIndResource('snd ', i);
if (sound != NULL) {
GetResInfo(sound, &id, &rezType, theName);
if (theName[0] == 0) {
continue;
}
objPtr = Tcl_NewStringObj((char *) theName + 1,
theName[0]);
Tcl_ListObjAppendElement(interp, resultPtr, objPtr);
}
}
return TCL_OK;
} else {
sndArg = Tcl_GetStringFromObj(objv[1], &length);
}
} else if (objc == 3) {
if (!strcmp(Tcl_GetStringFromObj(objv[1], &length), "-volume")) {
Tcl_GetIntFromObj(interp, objv[2], &volume);
} else {
goto beepUsage;
}
} else if (objc == 4) {
if (!strcmp(Tcl_GetStringFromObj(objv[1], &length), "-volume")) {
Tcl_GetIntFromObj(interp, objv[2], &volume);
sndArg = Tcl_GetStringFromObj(objv[3], &length);
} else {
goto beepUsage;
}
} else {
goto beepUsage;
}
if (sndArg == NULL) {
if (volume >= 0) {
SetSoundVolume(volume, SYS_BEEP_VOLUME);
}
SysBeep(1);
if (volume >= 0) {
SetSoundVolume(0, RESET_VOLUME);
}
} else {
strcpy((char *) sndName + 1, sndArg);
sndName[0] = length;
sound = GetNamedResource('snd ', sndName);
if (sound != NULL) {
if (volume >= 0) {
SetSoundVolume(volume, DEFAULT_SND_VOLUME);
}
SndPlay(NULL, (SndListHandle) sound, false);
if (volume >= 0) {
SetSoundVolume(0, RESET_VOLUME);
}
} else {
Tcl_AppendStringsToObj(resultPtr, " \"", sndArg,
"\" is not a valid sound. (Try ",
Tcl_GetStringFromObj(objv[0], (int *) NULL),
" -list)", NULL);
return TCL_ERROR;
}
}
return TCL_OK;
beepUsage:
Tcl_WrongNumArgs(interp, 1, objv, "[-volume num] [-list | sndName]?");
return TCL_ERROR;
}
void
SetSoundVolume(
int volume,
enum WhichVolume mode)
{
static int hasSM3 = -1;
static enum WhichVolume oldMode;
static long oldVolume = -1;
if (hasSM3 == -1) {
if (GetToolboxTrapAddress(_SoundDispatch)
!= GetToolboxTrapAddress(_Unimplemented)) {
NumVersion SMVers = SndSoundManagerVersion();
if (SMVers.majorRev > 2) {
hasSM3 = 1;
} else {
hasSM3 = 0;
}
} else {
hasSM3 = 0;
}
}
if (!hasSM3) {
return;
}
switch (mode) {
case SYS_BEEP_VOLUME:
GetSysBeepVolume(&oldVolume);
SetSysBeepVolume(volume);
oldMode = SYS_BEEP_VOLUME;
break;
case DEFAULT_SND_VOLUME:
GetDefaultOutputVolume(&oldVolume);
SetDefaultOutputVolume(volume);
oldMode = DEFAULT_SND_VOLUME;
break;
case RESET_VOLUME:
if (oldVolume != -1) {
if (oldMode == SYS_BEEP_VOLUME) {
SetSysBeepVolume(oldVolume);
} else if (oldMode == DEFAULT_SND_VOLUME) {
SetDefaultOutputVolume(oldVolume);
}
}
oldVolume = -1;
}
}
int
Tcl_MacEvalResource(
Tcl_Interp *interp,
char *resourceName,
int resourceNumber,
char *fileName)
{
Handle sourceText;
Str255 rezName;
char msg[200];
int result, iOpenedResFile = false;
short saveRef, fileRef = -1;
char idStr[64];
FSSpec fileSpec;
Tcl_DString buffer;
char *nativeName;
saveRef = CurResFile();
if (fileName != NULL) {
OSErr err;
nativeName = Tcl_TranslateFileName(interp, fileName, &buffer);
if (nativeName == NULL) {
return TCL_ERROR;
}
err = FSpLocationFromPath(strlen(nativeName), nativeName,
&fileSpec);
Tcl_DStringFree(&buffer);
if (err != noErr) {
Tcl_AppendResult(interp, "Error finding the file: \"",
fileName, "\".", NULL);
return TCL_ERROR;
}
fileRef = FSpOpenResFileCompat(&fileSpec, fsRdPerm);
if (fileRef == -1) {
Tcl_AppendResult(interp, "Error reading the file: \"",
fileName, "\".", NULL);
return TCL_ERROR;
}
UseResFile(fileRef);
iOpenedResFile = true;
} else {
}
if (resourceName != NULL) {
strcpy((char *) rezName + 1, resourceName);
rezName[0] = strlen(resourceName);
sourceText = GetNamedResource('TEXT', rezName);
} else {
sourceText = GetResource('TEXT', (short) resourceNumber);
}
if (sourceText == NULL) {
result = TCL_ERROR;
} else {
char *sourceStr = NULL;
HLock(sourceText);
sourceStr = Tcl_MacConvertTextResource(sourceText);
HUnlock(sourceText);
ReleaseResource(sourceText);
result = Tcl_Eval(interp, sourceStr);
ckfree(sourceStr);
if (result == TCL_RETURN) {
result = TCL_OK;
} else if (result == TCL_ERROR) {
sprintf(msg, "\n (rsrc \"%.150s\" line %d)",
resourceName,
interp->errorLine);
Tcl_AddErrorInfo(interp, msg);
}
goto rezEvalCleanUp;
}
rezEvalError:
sprintf(idStr, "ID=%d", resourceNumber);
Tcl_AppendResult(interp, "The resource \"",
(resourceName != NULL ? resourceName : idStr),
"\" could not be loaded from ",
(fileName != NULL ? fileName : "application"),
".", NULL);
rezEvalCleanUp:
if (iOpenedResFile && (CurResFile() == fileRef)) {
UseResFile(saveRef);
}
if (fileRef != -1) {
CloseResFile(fileRef);
}
return result;
}
char *
Tcl_MacConvertTextResource(
Handle resource)
{
int i, size;
char *resultStr;
size = GetResourceSizeOnDisk(resource);
resultStr = ckalloc(size + 1);
for (i=0; i<size; i++) {
if ((*resource)[i] == '\r') {
resultStr[i] = '\n';
} else {
resultStr[i] = (*resource)[i];
}
}
resultStr[size] = '\0';
return resultStr;
}
Handle
Tcl_MacFindResource(
Tcl_Interp *interp,
long resourceType,
char *resourceName,
int resourceNumber,
char *resFileRef,
int *releaseIt)
{
Tcl_HashEntry *nameHashPtr;
OpenResourceFork *resourceRef;
int limitSearch = false;
short saveRef;
Handle resource;
if (resFileRef != NULL) {
nameHashPtr = Tcl_FindHashEntry(&nameTable, resFileRef);
if (nameHashPtr == NULL) {
Tcl_AppendResult(interp, "invalid resource file reference \"",
resFileRef, "\"", (char *) NULL);
return NULL;
}
resourceRef = (OpenResourceFork *) Tcl_GetHashValue(nameHashPtr);
saveRef = CurResFile();
UseResFile((short) resourceRef->fileRef);
limitSearch = true;
}
SetResLoad(false);
if (resourceName == NULL) {
if (limitSearch) {
resource = Get1Resource(resourceType, resourceNumber);
} else {
resource = GetResource(resourceType, resourceNumber);
}
} else {
c2pstr(resourceName);
if (limitSearch) {
resource = Get1NamedResource(resourceType,
(StringPtr) resourceName);
} else {
resource = GetNamedResource(resourceType,
(StringPtr) resourceName);
}
p2cstr((StringPtr) resourceName);
}
if (*resource == NULL) {
*releaseIt = 1;
LoadResource(resource);
} else {
*releaseIt = 0;
}
SetResLoad(true);
if (limitSearch) {
UseResFile(saveRef);
}
return resource;
}
static void
ResourceInit()
{
initialized = 1;
Tcl_InitHashTable(&nameTable, TCL_STRING_KEYS);
Tcl_InitHashTable(&resourceTable, TCL_ONE_WORD_KEYS);
resourceForkList = Tcl_NewObj();
Tcl_IncrRefCount(resourceForkList);
BuildResourceForkList();
}
Tcl_Obj *
Tcl_NewOSTypeObj(
OSType newOSType)
{
register Tcl_Obj *objPtr;
if (!osTypeInit) {
osTypeInit = 1;
Tcl_RegisterObjType(&osType);
}
objPtr = Tcl_NewObj();
objPtr->bytes = NULL;
objPtr->internalRep.longValue = newOSType;
objPtr->typePtr = &osType;
return objPtr;
}
void
Tcl_SetOSTypeObj(
Tcl_Obj *objPtr,
OSType newOSType)
{
register Tcl_ObjType *oldTypePtr = objPtr->typePtr;
if (!osTypeInit) {
osTypeInit = 1;
Tcl_RegisterObjType(&osType);
}
Tcl_InvalidateStringRep(objPtr);
if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) {
oldTypePtr->freeIntRepProc(objPtr);
}
objPtr->internalRep.longValue = newOSType;
objPtr->typePtr = &osType;
}
int
Tcl_GetOSTypeFromObj(
Tcl_Interp *interp,
Tcl_Obj *objPtr,
OSType *osTypePtr)
{
register int result;
if (!osTypeInit) {
osTypeInit = 1;
Tcl_RegisterObjType(&osType);
}
if (objPtr->typePtr == &osType) {
*osTypePtr = objPtr->internalRep.longValue;
return TCL_OK;
}
result = SetOSTypeFromAny(interp, objPtr);
if (result == TCL_OK) {
*osTypePtr = objPtr->internalRep.longValue;
}
return result;
}
static void
DupOSTypeInternalRep(
Tcl_Obj *srcPtr,
Tcl_Obj *copyPtr)
{
copyPtr->internalRep.longValue = srcPtr->internalRep.longValue;
copyPtr->typePtr = &osType;
}
static int
SetOSTypeFromAny(
Tcl_Interp *interp,
Tcl_Obj *objPtr)
{
Tcl_ObjType *oldTypePtr = objPtr->typePtr;
char *string;
int length;
long newOSType;
string = TclGetStringFromObj(objPtr, &length);
if (length != 4) {
if (interp != NULL) {
Tcl_ResetResult(interp);
Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
"expected Macintosh OS type but got \"", string, "\"",
(char *) NULL);
}
return TCL_ERROR;
}
newOSType = *((long *) string);
if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) {
oldTypePtr->freeIntRepProc(objPtr);
}
objPtr->internalRep.longValue = newOSType;
objPtr->typePtr = &osType;
return TCL_OK;
}
static void
UpdateStringOfOSType(
register Tcl_Obj *objPtr)
{
objPtr->bytes = ckalloc(5);
sprintf(objPtr->bytes, "%-4.4s", &(objPtr->internalRep.longValue));
objPtr->length = 4;
}
static OpenResourceFork *
GetRsrcRefFromObj(
register Tcl_Obj *objPtr,
int okayOnReadOnly,
const char *operation,
Tcl_Obj *resultPtr)
{
char *stringPtr;
Tcl_HashEntry *nameHashPtr;
OpenResourceFork *resourceRef;
int length;
OSErr err;
stringPtr = Tcl_GetStringFromObj(objPtr, &length);
nameHashPtr = Tcl_FindHashEntry(&nameTable, stringPtr);
if (nameHashPtr == NULL) {
Tcl_AppendStringsToObj(resultPtr,
"invalid resource file reference \"",
stringPtr, "\"", (char *) NULL);
return NULL;
}
resourceRef = (OpenResourceFork *) Tcl_GetHashValue(nameHashPtr);
if (!okayOnReadOnly) {
err = GetResFileAttrs((short) resourceRef->fileRef);
if (err & mapReadOnly) {
Tcl_AppendStringsToObj(resultPtr, "cannot ", operation,
" resource file \"",
stringPtr, "\", it was opened read only",
(char *) NULL);
return NULL;
}
}
return resourceRef;
}
int
TclMacRegisterResourceFork(
short fileRef,
Tcl_Obj *tokenPtr,
int flags)
{
Tcl_HashEntry *resourceHashPtr;
Tcl_HashEntry *nameHashPtr;
OpenResourceFork *resourceRef;
int new;
char *resourceId = NULL;
if (!initialized) {
ResourceInit();
}
new = 1;
if (flags & TCL_RESOURCE_CHECK_IF_OPEN) {
Tcl_HashSearch search;
short oldFileRef, filePermissionFlag;
FCBPBRec newFileRec, oldFileRec;
OSErr err;
oldFileRec.ioCompletion = NULL;
oldFileRec.ioFCBIndx = 0;
oldFileRec.ioNamePtr = NULL;
newFileRec.ioCompletion = NULL;
newFileRec.ioFCBIndx = 0;
newFileRec.ioNamePtr = NULL;
newFileRec.ioVRefNum = 0;
newFileRec.ioRefNum = fileRef;
err = PBGetFCBInfo(&newFileRec, false);
filePermissionFlag = ( newFileRec.ioFCBFlags >> 12 ) & 0x1;
resourceHashPtr = Tcl_FirstHashEntry(&resourceTable, &search);
while (resourceHashPtr != NULL) {
oldFileRef = (short) Tcl_GetHashKey(&resourceTable,
resourceHashPtr);
if (oldFileRef == fileRef) {
new = 0;
break;
}
oldFileRec.ioVRefNum = 0;
oldFileRec.ioRefNum = oldFileRef;
err = PBGetFCBInfo(&oldFileRec, false);
if ((err == noErr)
&& (newFileRec.ioFCBVRefNum == oldFileRec.ioFCBVRefNum)
&& (newFileRec.ioFCBFlNm == oldFileRec.ioFCBFlNm)) {
if (filePermissionFlag == ((oldFileRec.ioFCBFlags >> 12) & 0x1)) {
CloseResFile(fileRef);
new = 0;
break;
} else {
if (tokenPtr != NULL) {
Tcl_SetStringObj(tokenPtr,
"Resource already open with different permissions.", -1);
}
return TCL_ERROR;
}
}
resourceHashPtr = Tcl_NextHashEntry(&search);
}
}
if (new) {
resourceHashPtr = Tcl_CreateHashEntry(&resourceTable,
(char *) fileRef, &new);
}
if (!new) {
if (tokenPtr != NULL) {
resourceId = (char *) Tcl_GetHashValue(resourceHashPtr);
Tcl_SetStringObj(tokenPtr, resourceId, -1);
}
return TCL_OK;
}
if (tokenPtr != NULL) {
char *tokenVal;
int length;
tokenVal = (char *) Tcl_GetStringFromObj(tokenPtr, &length);
if (length > 0) {
nameHashPtr = Tcl_FindHashEntry(&nameTable, tokenVal);
if (nameHashPtr == NULL) {
resourceId = ckalloc(length + 1);
memcpy(resourceId, tokenVal, length);
resourceId[length] = '\0';
}
}
}
if (resourceId == NULL) {
resourceId = (char *) ckalloc(15);
sprintf(resourceId, "resource%d", newId);
}
Tcl_SetHashValue(resourceHashPtr, resourceId);
newId++;
nameHashPtr = Tcl_CreateHashEntry(&nameTable, resourceId, &new);
if (!new) {
panic("resource id has repeated itself");
}
resourceRef = (OpenResourceFork *) ckalloc(sizeof(OpenResourceFork));
resourceRef->fileRef = fileRef;
resourceRef->flags = flags;
Tcl_SetHashValue(nameHashPtr, (ClientData) resourceRef);
if (tokenPtr != NULL) {
Tcl_SetStringObj(tokenPtr, resourceId, -1);
}
if (flags & TCL_RESOURCE_INSERT_TAIL) {
Tcl_ListObjAppendElement(NULL, resourceForkList, tokenPtr);
} else {
Tcl_ListObjReplace(NULL, resourceForkList, 0, 0, 1, &tokenPtr);
}
return TCL_OK;
}
short
TclMacUnRegisterResourceFork(
char *tokenPtr,
Tcl_Obj *resultPtr)
{
Tcl_HashEntry *resourceHashPtr;
Tcl_HashEntry *nameHashPtr;
OpenResourceFork *resourceRef;
char *resourceId = NULL;
short fileRef;
char *bytes;
int i, match, index, listLen, length, elemLen;
Tcl_Obj **elemPtrs;
nameHashPtr = Tcl_FindHashEntry(&nameTable, tokenPtr);
if (nameHashPtr == NULL) {
if (resultPtr != NULL) {
Tcl_AppendStringsToObj(resultPtr,
"invalid resource file reference \"",
tokenPtr, "\"", (char *) NULL);
}
return -1;
}
resourceRef = (OpenResourceFork *) Tcl_GetHashValue(nameHashPtr);
fileRef = resourceRef->fileRef;
if ( resourceRef->flags & TCL_RESOURCE_DONT_CLOSE ) {
if (resultPtr != NULL) {
Tcl_AppendStringsToObj(resultPtr,
"can't close \"", tokenPtr, "\" resource file",
(char *) NULL);
}
return -1;
}
Tcl_DeleteHashEntry(nameHashPtr);
ckfree((char *) resourceRef);
Tcl_ListObjGetElements(NULL, resourceForkList, &listLen, &elemPtrs);
index = -1;
length = strlen(tokenPtr);
for (i = 0; i < listLen; i++) {
match = 0;
bytes = Tcl_GetStringFromObj(elemPtrs[i], &elemLen);
if (length == elemLen) {
match = (memcmp(bytes, tokenPtr,
(size_t) length) == 0);
}
if (match) {
index = i;
break;
}
}
if (!match) {
panic("the resource Fork List is out of synch!");
}
Tcl_ListObjReplace(NULL, resourceForkList, index, 1, 0, NULL);
resourceHashPtr = Tcl_FindHashEntry(&resourceTable, (char *) fileRef);
if (resourceHashPtr == NULL) {
panic("Resource & Name tables are out of synch in resource command.");
}
ckfree(Tcl_GetHashValue(resourceHashPtr));
Tcl_DeleteHashEntry(resourceHashPtr);
return fileRef;
}
void
BuildResourceForkList()
{
Handle currentMapHandle, mSysMapHandle;
Ptr tempPtr;
FCBPBRec fileRec;
char fileName[256];
char appName[62];
Tcl_Obj *nameObj;
OSErr err;
ProcessSerialNumber psn;
ProcessInfoRec info;
FSSpec fileSpec;
GetCurrentProcess(&psn);
info.processInfoLength = sizeof(ProcessInfoRec);
info.processName = (StringPtr) &appName;
info.processAppSpec = &fileSpec;
GetProcessInformation(&psn, &info);
p2cstr((StringPtr) appName);
fileRec.ioCompletion = NULL;
fileRec.ioVRefNum = 0;
fileRec.ioFCBIndx = 0;
fileRec.ioNamePtr = (StringPtr) &fileName;
currentMapHandle = LMGetTopMapHndl();
mSysMapHandle = LMGetSysMapHndl();
while (1) {
nameObj = Tcl_NewObj();
tempPtr = *currentMapHandle;
fileRec.ioRefNum = *((short *) (tempPtr + 20));
err = PBGetFCBInfo(&fileRec, false);
if (err != noErr) {
Tcl_SetStringObj(nameObj, "ROM Map", -1);
} else {
p2cstr((StringPtr) fileName);
if (strcmp(fileName,(char *) appName) == 0) {
Tcl_SetStringObj(nameObj, "application", -1);
} else {
Tcl_SetStringObj(nameObj, fileName, -1);
}
c2pstr(fileName);
}
TclMacRegisterResourceFork(fileRec.ioRefNum, nameObj,
TCL_RESOURCE_DONT_CLOSE | TCL_RESOURCE_INSERT_TAIL);
if (currentMapHandle == mSysMapHandle) {
break;
}
currentMapHandle = *((Handle *) (tempPtr + 16));
}
}