📄 tclmacresource.c
字号:
* the OpenResourceFork structure that it represents, or NULL if * the token cannot be found. If okayOnReadOnly is false, it will * also check whether the token corresponds to a read-only file, * and return NULL if it is. * * Results: * A pointer to an OpenResourceFork structure, or NULL. * * Side effects: * An error message may be left in resultPtr. * *---------------------------------------------------------------------- */static OpenResourceFork *GetRsrcRefFromObj( register Tcl_Obj *objPtr, /* String obj containing file token */ int okayOnReadOnly, /* Whether this operation is okay for a * * read only file. */ const char *operation, /* String containing the operation we * * were trying to perform, used for errors */ Tcl_Obj *resultPtr) /* Tcl_Obj to contain error message */{ 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;}/* *---------------------------------------------------------------------- * * TclMacRegisterResourceFork -- * * Register an open resource fork in the table of open resources * managed by the procedures in this file. If the resource file * is already registered with the table, then no new token is made. * * The behavior is controlled by the value of tokenPtr, and of the * flags variable. For tokenPtr, the possibilities are: * - NULL: The new token is auto-generated, but not returned. * - The string value of tokenPtr is the empty string: Then * the new token is auto-generated, and returned in tokenPtr * - tokenPtr has a value: The string value will be used for the token, * unless it is already in use, in which case a new token will * be generated, and returned in tokenPtr. * * For the flags variable: it can be one of: * - TCL_RESOURCE__INSERT_TAIL: The element is inserted at the * end of the list of open resources. Used only in Resource_Init. * - TCL_RESOURCE_DONT_CLOSE: The resource close command will not close * this resource. * - TCL_RESOURCE_CHECK_IF_OPEN: This will check to see if this file's * resource fork is already opened by this Tcl shell, and return * an error without registering the resource fork. * * Results: * Standard Tcl Result * * Side effects: * An entry may be added to the resource name table. * *---------------------------------------------------------------------- */intTclMacRegisterResourceFork( short fileRef, /* File ref for an open resource fork. */ Tcl_Obj *tokenPtr, /* A Tcl Object to which to write the * * new token */ int flags) /* 1 means insert at the head of the resource * fork list, 0 means at the tail */{ Tcl_HashEntry *resourceHashPtr; Tcl_HashEntry *nameHashPtr; OpenResourceFork *resourceRef; int new; char *resourceId = NULL; if (!initialized) { ResourceInit(); } /* * If we were asked to, check that this file has not been opened * already with a different permission. It it has, then return an error. */ 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); /* * err might not be noErr either because the file has closed * out from under us somehow, which is bad but we're not going * to fix it here, OR because it is the ROM MAP, which has a * fileRef, but can't be gotten to by PBGetFCBInfo. */ if ((err == noErr) && (newFileRec.ioFCBVRefNum == oldFileRec.ioFCBVRefNum) && (newFileRec.ioFCBFlNm == oldFileRec.ioFCBFlNm)) { /* * In MacOS 8.1 it seems like we get different file refs even * though we pass the same file & permissions. This is not * what Inside Mac says should happen, but it does, so if it * does, then close the new res file and return the original * one... */ 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 the file has already been opened with these same permissions, then it * will be in our list and we will have set new to 0 above. * So we will just return the token (if tokenPtr is non-null) */ 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 we were passed in a result pointer which is not an empty * string, attempt to use that as the key. If the key already * exists, silently fall back on resource%d... */ if (tokenPtr != NULL) { char *tokenVal; int length; tokenVal = 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;}/* *---------------------------------------------------------------------- * * TclMacUnRegisterResourceFork -- * * Removes the entry for an open resource fork from the table of * open resources managed by the procedures in this file. * If resultPtr is not NULL, it will be used for error reporting. * * Results: * The fileRef for this token, or -1 if an error occured. * * Side effects: * An entry is removed from the resource name table. * *---------------------------------------------------------------------- */shortTclMacUnRegisterResourceFork( 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); /* * Now remove the resource from the resourceForkList object */ 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;}/* *---------------------------------------------------------------------- * * BuildResourceForkList -- * * Traverses the list of open resource forks, and builds the * list of resources forks. Also creates a resource token for any that * are opened but not registered with our resource system. * This is based on code from Apple DTS. * * Results: * None. * * Side effects: * The list of resource forks is updated. * The resource name table may be augmented. * *---------------------------------------------------------------------- */voidBuildResourceForkList(){ Handle currentMapHandle, mSysMapHandle; Ptr tempPtr; FCBPBRec fileRec; char fileName[256]; char appName[62]; Tcl_Obj *nameObj; OSErr err; ProcessSerialNumber psn; ProcessInfoRec info; FSSpec fileSpec; /* * Get the application name, so we can substitute * the token "application" for the application's resource. */ 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) { /* * Now do the ones opened after the application. */ nameObj = Tcl_NewObj(); tempPtr = *currentMapHandle; fileRec.ioRefNum = *((short *) (tempPtr + 20)); err = PBGetFCBInfo(&fileRec, false); if (err != noErr) { /* * The ROM resource map does not correspond to an opened file... */ Tcl_SetStringObj(nameObj, "ROM Map", -1); } else { p2cstr((StringPtr) fileName); if (strcmp(fileName,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)); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -