📄 tclmacresource.c
字号:
/* * tclMacResource.c -- * * This file contains several commands that manipulate or use * Macintosh resources. Included are extensions to the "source" * command, the mac specific "beep" and "resource" commands, and * administration for open resource file references. * * Copyright (c) 1996-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * SCCS: @(#) tclMacResource.c 1.35 97/11/24 15:03:58 */#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"/* * This flag tells the RegisterResource function to insert the * resource into the tail of the resource fork list. Needed only * Resource_Init. */ #define TCL_RESOURCE_INSERT_TAIL 1/* * 2 is taken by TCL_RESOURCE_DONT_CLOSE * which is the only public flag to TclMacRegisterResourceFork. */ #define TCL_RESOURCE_CHECK_IF_OPEN 4/* * Pass this in the mode parameter of SetSoundVolume to determine * which volume to set. */enum WhichVolume { SYS_BEEP_VOLUME, /* This sets the volume for SysBeep calls */ DEFAULT_SND_VOLUME, /* This one for SndPlay calls */ RESET_VOLUME /* And this undoes the last call to SetSoundVolume */}; /* * Hash table to track open resource files. */typedef struct OpenResourceFork { short fileRef; int flags;} OpenResourceFork;static Tcl_HashTable nameTable; /* Id to process number mapping. */static Tcl_HashTable resourceTable; /* Process number to id mapping. */static Tcl_Obj *resourceForkList; /* Ordered list of resource forks */static int appResourceIndex; /* This is the index of the application* * in the list of resource forks */static int newId = 0; /* Id source. */static int initialized = 0; /* 0 means static structures haven't * been initialized yet. */static int osTypeInit = 0; /* 0 means Tcl object of osType hasn't * been initialized yet. *//* * Prototypes for procedures defined later in this file: */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);/* * The structures below defines the Tcl object type defined in this file by * means of procedures that can be invoked by generic object code. */static Tcl_ObjType osType = { "ostype", /* name */ (Tcl_FreeInternalRepProc *) NULL, /* freeIntRepProc */ DupOSTypeInternalRep, /* dupIntRepProc */ UpdateStringOfOSType, /* updateStringProc */ SetOSTypeFromAny /* setFromAnyProc */};/* *---------------------------------------------------------------------- * * Tcl_ResourceObjCmd -- * * This procedure is invoked to process the "resource" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */intTcl_ResourceObjCmd( ClientData clientData, /* Not used. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[]) /* Argument values. */{ 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; } /* * Find the resource file, if it was not specified, * so we can flush the changes now. Perhaps this is * a little paranoid, but better safe than sorry. */ 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; } /* * Get permissions for the file. We really only understand * read-only and shared-read-write. If no permissions are * given we default to read only. */ if (objc == 4) { stringPtr = Tcl_GetStringFromObj(objv[3], &length); mode = TclGetOpenMode(interp, stringPtr, &index); if (mode == -1) { /* TODO: TclGetOpenMode doesn't work with Obj commands. */ 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; } /* * Don't load in any of the resources in the file, this could * cause problems if you open a file that has CODE resources... */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -