os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/mac/tclMacResource.c
Update contrib.
4 * This file contains several commands that manipulate or use
5 * Macintosh resources. Included are extensions to the "source"
6 * command, the mac specific "beep" and "resource" commands, and
7 * administration for open resource file references.
9 * Copyright (c) 1996-1997 Sun Microsystems, Inc.
11 * See the file "license.terms" for information on usage and redistribution
12 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
14 * RCS: @(#) $Id: tclMacResource.c,v 1.14.2.1 2003/10/01 14:34:16 das Exp $
18 #include <FSpCompat.h>
19 #include <Processes.h>
20 #include <Resources.h>
30 #include "tclMacInt.h"
31 #include "tclMacPort.h"
34 * This flag tells the RegisterResource function to insert the
35 * resource into the tail of the resource fork list. Needed only
39 #define TCL_RESOURCE_INSERT_TAIL 1
41 * 2 is taken by TCL_RESOURCE_DONT_CLOSE
42 * which is the only public flag to TclMacRegisterResourceFork.
45 #define TCL_RESOURCE_CHECK_IF_OPEN 4
48 * Pass this in the mode parameter of SetSoundVolume to determine
49 * which volume to set.
53 SYS_BEEP_VOLUME, /* This sets the volume for SysBeep calls */
54 DEFAULT_SND_VOLUME, /* This one for SndPlay calls */
55 RESET_VOLUME /* And this undoes the last call to SetSoundVolume */
59 * Hash table to track open resource files.
62 typedef struct OpenResourceFork {
69 static Tcl_HashTable nameTable; /* Id to process number mapping. */
70 static Tcl_HashTable resourceTable; /* Process number to id mapping. */
71 static Tcl_Obj *resourceForkList; /* Ordered list of resource forks */
72 static int appResourceIndex; /* This is the index of the application*
73 * in the list of resource forks */
74 static int newId = 0; /* Id source. */
75 static int initialized = 0; /* 0 means static structures haven't
76 * been initialized yet. */
77 static int osTypeInit = 0; /* 0 means Tcl object of osType hasn't
78 * been initialized yet. */
80 * Prototypes for procedures defined later in this file:
83 static void DupOSTypeInternalRep _ANSI_ARGS_((Tcl_Obj *srcPtr,
85 static void ResourceInit _ANSI_ARGS_((void));
86 static void BuildResourceForkList _ANSI_ARGS_((void));
87 static int SetOSTypeFromAny _ANSI_ARGS_((Tcl_Interp *interp,
89 static void UpdateStringOfOSType _ANSI_ARGS_((Tcl_Obj *objPtr));
90 static OpenResourceFork* GetRsrcRefFromObj _ANSI_ARGS_((Tcl_Obj *objPtr,
91 int okayOnReadOnly, const char *operation,
94 static void SetSoundVolume(int volume, enum WhichVolume mode);
97 * The structures below defines the Tcl object type defined in this file by
98 * means of procedures that can be invoked by generic object code.
101 static Tcl_ObjType osType = {
103 (Tcl_FreeInternalRepProc *) NULL, /* freeIntRepProc */
104 DupOSTypeInternalRep, /* dupIntRepProc */
105 UpdateStringOfOSType, /* updateStringProc */
106 SetOSTypeFromAny /* setFromAnyProc */
110 *----------------------------------------------------------------------
112 * Tcl_ResourceObjCmd --
114 * This procedure is invoked to process the "resource" Tcl command.
115 * See the user documentation for details on what it does.
118 * A standard Tcl result.
121 * See the user documentation.
123 *----------------------------------------------------------------------
128 ClientData clientData, /* Not used. */
129 Tcl_Interp *interp, /* Current interpreter. */
130 int objc, /* Number of arguments. */
131 Tcl_Obj *CONST objv[]) /* Argument values. */
133 Tcl_Obj *resultPtr, *objPtr;
135 long fileRef, rsrcId;
139 OpenResourceFork *resourceRef;
140 Handle resource = NULL;
142 int count, i, limitSearch = false, length;
143 short id, saveRef, resInfo;
146 int gotInt, releaseIt = 0, force;
147 char *resourceId = NULL;
152 static CONST char *switches[] = {"close", "delete" ,"files", "list",
153 "open", "read", "types", "write", (char *) NULL
157 RESOURCE_CLOSE, RESOURCE_DELETE, RESOURCE_FILES, RESOURCE_LIST,
158 RESOURCE_OPEN, RESOURCE_READ, RESOURCE_TYPES, RESOURCE_WRITE
161 static CONST char *writeSwitches[] = {
162 "-id", "-name", "-file", "-force", (char *) NULL
166 RESOURCE_WRITE_ID, RESOURCE_WRITE_NAME,
167 RESOURCE_WRITE_FILE, RESOURCE_FORCE
170 static CONST char *deleteSwitches[] = {"-id", "-name", "-file", (char *) NULL};
172 enum {RESOURCE_DELETE_ID, RESOURCE_DELETE_NAME, RESOURCE_DELETE_FILE};
174 resultPtr = Tcl_GetObjResult(interp);
177 Tcl_WrongNumArgs(interp, 1, objv, "option ?arg ...?");
181 if (Tcl_GetIndexFromObj(interp, objv[1], switches, "option", 0, &index)
193 Tcl_WrongNumArgs(interp, 2, objv, "resourceRef");
196 stringPtr = Tcl_GetStringFromObj(objv[2], &length);
197 fileRef = TclMacUnRegisterResourceFork(stringPtr, resultPtr);
200 CloseResFile((short) fileRef);
205 case RESOURCE_DELETE:
206 if (!((objc >= 3) && (objc <= 9) && ((objc % 2) == 1))) {
207 Tcl_WrongNumArgs(interp, 2, objv,
208 "?-id resourceId? ?-name resourceName? ?-file \
209 resourceRef? resourceType");
219 while (i < (objc - 2)) {
220 if (Tcl_GetIndexFromObj(interp, objv[i], deleteSwitches,
221 "option", 0, &index) != TCL_OK) {
226 case RESOURCE_DELETE_ID:
227 if (Tcl_GetLongFromObj(interp, objv[i+1], &rsrcId)
233 case RESOURCE_DELETE_NAME:
234 resourceId = Tcl_GetStringFromObj(objv[i+1], &length);
236 Tcl_AppendStringsToObj(resultPtr,"-name argument ",
237 "too long, must be < 255 characters",
241 strcpy((char *) theName, resourceId);
242 resourceId = (char *) theName;
245 case RESOURCE_DELETE_FILE:
246 resourceRef = GetRsrcRefFromObj(objv[i+1], 0,
247 "delete from", resultPtr);
248 if (resourceRef == NULL) {
257 if ((resourceId == NULL) && !gotInt) {
258 Tcl_AppendStringsToObj(resultPtr,"you must specify either ",
259 "\"-id\" or \"-name\" or both ",
260 "to \"resource delete\"",
265 if (Tcl_GetOSTypeFromObj(interp, objv[i], &rezType) != TCL_OK) {
270 saveRef = CurResFile();
271 UseResFile((short) resourceRef->fileRef);
276 if (gotInt == true) {
278 resource = Get1Resource(rezType, rsrcId);
280 resource = GetResource(rezType, rsrcId);
284 if (err == resNotFound || resource == NULL) {
285 Tcl_AppendStringsToObj(resultPtr, "resource not found",
289 } else if (err != noErr) {
292 sprintf(buffer, "%12d", err);
293 Tcl_AppendStringsToObj(resultPtr, "resource error #",
294 buffer, "occured while trying to find resource",
301 if (resourceId != NULL) {
304 tmpResource = Get1NamedResource(rezType,
305 (StringPtr) resourceId);
307 tmpResource = GetNamedResource(rezType,
308 (StringPtr) resourceId);
312 if (err == resNotFound || tmpResource == NULL) {
313 Tcl_AppendStringsToObj(resultPtr, "resource not found",
317 } else if (err != noErr) {
320 sprintf(buffer, "%12d", err);
321 Tcl_AppendStringsToObj(resultPtr, "resource error #",
322 buffer, "occured while trying to find resource",
329 if (resource != tmpResource) {
330 Tcl_AppendStringsToObj(resultPtr,
331 "\"-id\" and \"-name\" ",
332 "values do not point to the same resource",
338 resource = tmpResource;
342 resInfo = GetResAttrs(resource);
344 if ((resInfo & resProtected) == resProtected) {
345 Tcl_AppendStringsToObj(resultPtr, "resource ",
346 "cannot be deleted: it is protected.",
350 } else if ((resInfo & resSysHeap) == resSysHeap) {
351 Tcl_AppendStringsToObj(resultPtr, "resource",
352 "cannot be deleted: it is in the system heap.",
359 * Find the resource file, if it was not specified,
360 * so we can flush the changes now. Perhaps this is
361 * a little paranoid, but better safe than sorry.
364 RemoveResource(resource);
367 UpdateResFile(HomeResFile(resource));
369 UpdateResFile(resourceRef->fileRef);
382 if ((objc < 2) || (objc > 3)) {
383 Tcl_SetStringObj(resultPtr,
384 "wrong # args: should be \"resource files \
385 ?resourceId?\"", -1);
390 stringPtr = Tcl_GetStringFromObj(resourceForkList, &length);
391 Tcl_SetStringObj(resultPtr, stringPtr, length);
399 if (strcmp(Tcl_GetString(objv[2]), "ROM Map") == 0) {
400 Tcl_SetStringObj(resultPtr,"no file path for ROM Map", -1);
404 resourceRef = GetRsrcRefFromObj(objv[2], 1, "files", resultPtr);
405 if (resourceRef == NULL) {
409 fileRec.ioCompletion = NULL;
410 fileRec.ioFCBIndx = 0;
411 fileRec.ioNamePtr = fileName;
412 fileRec.ioVRefNum = 0;
413 fileRec.ioRefNum = resourceRef->fileRef;
414 err = PBGetFCBInfo(&fileRec, false);
416 Tcl_SetStringObj(resultPtr,
417 "could not get FCB for resource file", -1);
421 err = GetFullPath(fileRec.ioFCBVRefNum, fileRec.ioFCBParID,
422 fileRec.ioNamePtr, &pathLength, &pathHandle);
424 Tcl_SetStringObj(resultPtr,
425 "could not get file path from token", -1);
430 Tcl_ExternalToUtfDString(NULL, *pathHandle, pathLength, &dstr);
432 Tcl_SetStringObj(resultPtr, Tcl_DStringValue(&dstr), Tcl_DStringLength(&dstr));
434 DisposeHandle(pathHandle);
435 Tcl_DStringFree(&dstr);
439 if (!((objc == 3) || (objc == 4))) {
440 Tcl_WrongNumArgs(interp, 2, objv, "resourceType ?resourceRef?");
443 if (Tcl_GetOSTypeFromObj(interp, objv[2], &rezType) != TCL_OK) {
448 resourceRef = GetRsrcRefFromObj(objv[3], 1,
450 if (resourceRef == NULL) {
454 saveRef = CurResFile();
455 UseResFile((short) resourceRef->fileRef);
459 Tcl_ResetResult(interp);
461 count = Count1Resources(rezType);
463 count = CountResources(rezType);
466 for (i = 1; i <= count; i++) {
468 resource = Get1IndResource(rezType, i);
470 resource = GetIndResource(rezType, i);
472 if (resource != NULL) {
473 GetResInfo(resource, &id, (ResType *) &rezType, theName);
474 if (theName[0] != 0) {
476 objPtr = Tcl_NewStringObj((char *) theName + 1,
479 objPtr = Tcl_NewIntObj(id);
481 ReleaseResource(resource);
482 result = Tcl_ListObjAppendElement(interp, resultPtr,
484 if (result != TCL_OK) {
485 Tcl_DecrRefCount(objPtr);
497 case RESOURCE_OPEN: {
498 Tcl_DString ds, buffer;
499 CONST char *str, *native;
502 if (!((objc == 3) || (objc == 4))) {
503 Tcl_WrongNumArgs(interp, 2, objv, "fileName ?permissions?");
506 str = Tcl_GetStringFromObj(objv[2], &length);
507 if (Tcl_TranslateFileName(interp, str, &buffer) == NULL) {
510 native = Tcl_UtfToExternalDString(NULL, Tcl_DStringValue(&buffer),
511 Tcl_DStringLength(&buffer), &ds);
512 err = FSpLocationFromPath(Tcl_DStringLength(&ds), native, &fileSpec);
513 Tcl_DStringFree(&ds);
514 Tcl_DStringFree(&buffer);
516 if (!((err == noErr) || (err == fnfErr))) {
517 Tcl_AppendStringsToObj(resultPtr, "invalid path", (char *) NULL);
522 * Get permissions for the file. We really only understand
523 * read-only and shared-read-write. If no permissions are
524 * given we default to read only.
528 stringPtr = Tcl_GetStringFromObj(objv[3], &length);
529 mode = TclGetOpenMode(interp, stringPtr, &index);
531 /* TODO: TclGetOpenMode doesn't work with Obj commands. */
534 switch (mode & (O_RDONLY | O_WRONLY | O_RDWR)) {
536 macPermision = fsRdPerm;
540 macPermision = fsRdWrShPerm;
543 panic("Tcl_ResourceObjCmd: invalid mode value");
547 macPermision = fsRdPerm;
551 * Don't load in any of the resources in the file, this could
552 * cause problems if you open a file that has CODE resources...
556 fileRef = (long) FSpOpenResFileCompat(&fileSpec, macPermision);
561 if (((err == fnfErr) || (err == eofErr)) &&
562 (macPermision == fsRdWrShPerm)) {
564 * No resource fork existed for this file. Since we are
565 * opening it for writing we will create the resource fork
569 HCreateResFile(fileSpec.vRefNum, fileSpec.parID,
571 fileRef = (long) FSpOpenResFileCompat(&fileSpec,
576 } else if (err == fnfErr) {
577 Tcl_AppendStringsToObj(resultPtr,
578 "file does not exist", (char *) NULL);
580 } else if (err == eofErr) {
581 Tcl_AppendStringsToObj(resultPtr,
582 "file does not contain resource fork", (char *) NULL);
586 Tcl_AppendStringsToObj(resultPtr,
587 "error opening resource file", (char *) NULL);
593 * The FspOpenResFile function does not set the ResFileAttrs.
594 * Even if you open the file read only, the mapReadOnly
595 * attribute is not set. This means we can't detect writes to a
596 * read only resource fork until the write fails, which is bogus.
600 if (macPermision == fsRdPerm) {
601 SetResFileAttrs(fileRef, mapReadOnly);
604 Tcl_SetStringObj(resultPtr, "", 0);
605 if (TclMacRegisterResourceFork(fileRef, resultPtr,
606 TCL_RESOURCE_CHECK_IF_OPEN) != TCL_OK) {
607 CloseResFile(fileRef);
613 if (!((objc == 4) || (objc == 5))) {
614 Tcl_WrongNumArgs(interp, 2, objv,
615 "resourceType resourceId ?resourceRef?");
619 if (Tcl_GetOSTypeFromObj(interp, objv[2], &rezType) != TCL_OK) {
623 if (Tcl_GetLongFromObj((Tcl_Interp *) NULL, objv[3], &rsrcId)
625 resourceId = Tcl_GetStringFromObj(objv[3], &length);
629 stringPtr = Tcl_GetStringFromObj(objv[4], &length);
634 resource = Tcl_MacFindResource(interp, rezType, resourceId,
635 rsrcId, stringPtr, &releaseIt);
637 if (resource != NULL) {
638 size = GetResourceSizeOnDisk(resource);
639 Tcl_SetByteArrayObj(resultPtr, (unsigned char *) *resource, size);
642 * Don't release the resource unless WE loaded it...
646 ReleaseResource(resource);
650 Tcl_AppendStringsToObj(resultPtr, "could not load resource",
655 if (!((objc == 2) || (objc == 3))) {
656 Tcl_WrongNumArgs(interp, 2, objv, "?resourceRef?");
661 resourceRef = GetRsrcRefFromObj(objv[2], 1,
662 "get types of", resultPtr);
663 if (resourceRef == NULL) {
667 saveRef = CurResFile();
668 UseResFile((short) resourceRef->fileRef);
673 count = Count1Types();
675 count = CountTypes();
677 for (i = 1; i <= count; i++) {
679 Get1IndType((ResType *) &rezType, i);
681 GetIndType((ResType *) &rezType, i);
683 objPtr = Tcl_NewOSTypeObj(rezType);
684 result = Tcl_ListObjAppendElement(interp, resultPtr, objPtr);
685 if (result != TCL_OK) {
686 Tcl_DecrRefCount(objPtr);
697 if ((objc < 4) || (objc > 11)) {
698 Tcl_WrongNumArgs(interp, 2, objv,
699 "?-id resourceId? ?-name resourceName? ?-file resourceRef?\
700 ?-force? resourceType data");
710 while (i < (objc - 2)) {
711 if (Tcl_GetIndexFromObj(interp, objv[i], writeSwitches,
712 "switch", 0, &index) != TCL_OK) {
717 case RESOURCE_WRITE_ID:
718 if (Tcl_GetLongFromObj(interp, objv[i+1], &rsrcId)
725 case RESOURCE_WRITE_NAME:
726 resourceId = Tcl_GetStringFromObj(objv[i+1], &length);
727 strcpy((char *) theName, resourceId);
728 resourceId = (char *) theName;
732 case RESOURCE_WRITE_FILE:
733 resourceRef = GetRsrcRefFromObj(objv[i+1], 0,
734 "write to", resultPtr);
735 if (resourceRef == NULL) {
747 if (Tcl_GetOSTypeFromObj(interp, objv[i], &rezType) != TCL_OK) {
750 stringPtr = (char *) Tcl_GetByteArrayFromObj(objv[i+1], &length);
752 if (gotInt == false) {
753 rsrcId = UniqueID(rezType);
755 if (resourceId == NULL) {
756 resourceId = (char *) "\p";
759 saveRef = CurResFile();
760 UseResFile((short) resourceRef->fileRef);
764 * If we are adding the resource by number, then we must make sure
765 * there is not already a resource of that number. We are not going
766 * load it here, since we want to detect whether we loaded it or
767 * not. Remember that releasing some resources in particular menu
768 * related ones, can be fatal.
771 if (gotInt == true) {
773 resource = Get1Resource(rezType,rsrcId);
777 if (resource == NULL) {
779 * We get into this branch either if there was not already a
780 * resource of this type & id, or the id was not specified.
783 resource = NewHandle(length);
784 if (resource == NULL) {
785 resource = NewHandleSys(length);
786 if (resource == NULL) {
787 panic("could not allocate memory to write resource");
791 memcpy(*resource, stringPtr, length);
793 AddResource(resource, rezType, (short) rsrcId,
794 (StringPtr) resourceId);
798 * We got here because there was a resource of this type
802 if (*resource == NULL) {
810 *We only overwrite extant resources
811 * when the -force flag has been set.
814 sprintf(errbuf,"%d", rsrcId);
816 Tcl_AppendStringsToObj(resultPtr, "the resource ",
817 errbuf, " already exists, use \"-force\"",
818 " to overwrite it.", (char *) NULL);
822 } else if (GetResAttrs(resource) & resProtected) {
825 * Next, check to see if it is protected...
828 sprintf(errbuf,"%d", rsrcId);
829 Tcl_AppendStringsToObj(resultPtr,
830 "could not write resource id ",
832 Tcl_GetStringFromObj(objv[i],&length),
833 ", it was protected.",(char *) NULL);
838 * Be careful, the resource might already be in memory
839 * if something else loaded it.
842 if (*resource == 0) {
843 LoadResource(resource);
846 sprintf(errbuf,"%d", rsrcId);
847 Tcl_AppendStringsToObj(resultPtr,
848 "error loading resource ",
850 Tcl_GetStringFromObj(objv[i],&length),
851 " to overwrite it", (char *) NULL);
856 SetHandleSize(resource, length);
857 if ( MemError() != noErr ) {
858 panic("could not allocate memory to write resource");
862 memcpy(*resource, stringPtr, length);
865 ChangedResource(resource);
868 * We also may have changed the name...
871 SetResInfo(resource, rsrcId, (StringPtr) resourceId);
877 Tcl_AppendStringsToObj(resultPtr,
878 "error adding resource to resource map",
884 WriteResource(resource);
887 Tcl_AppendStringsToObj(resultPtr,
888 "error writing resource to disk",
896 ReleaseResource(resource);
899 Tcl_AppendStringsToObj(resultPtr,
900 "error releasing resource",
912 panic("Tcl_GetIndexFromObj returned unrecognized option");
913 return TCL_ERROR; /* Should never be reached. */
918 *----------------------------------------------------------------------
920 * Tcl_MacSourceObjCmd --
922 * This procedure is invoked to process the "source" Tcl command.
923 * See the user documentation for details on what it does. In
924 * addition, it supports sourceing from the resource fork of
928 * A standard Tcl result.
931 * See the user documentation.
933 *----------------------------------------------------------------------
938 ClientData dummy, /* Not used. */
939 Tcl_Interp *interp, /* Current interpreter. */
940 int objc, /* Number of arguments. */
941 Tcl_Obj *CONST objv[]) /* Argument objects. */
943 char *errNum = "wrong # args: ";
944 char *errBad = "bad argument: ";
946 char *fileName = NULL, *rsrcName = NULL;
951 if (objc < 2 || objc > 4) {
957 return Tcl_FSEvalFile(interp, objv[1]);
961 * The following code supports a few older forms of this command
962 * for backward compatability.
964 string = Tcl_GetStringFromObj(objv[1], &length);
965 if (!strcmp(string, "-rsrc") || !strcmp(string, "-rsrcname")) {
966 rsrcName = Tcl_GetStringFromObj(objv[2], &length);
967 } else if (!strcmp(string, "-rsrcid")) {
968 if (Tcl_GetLongFromObj(interp, objv[2], &rsrcID) != TCL_OK) {
977 fileName = Tcl_GetStringFromObj(objv[3], &length);
979 return Tcl_MacEvalResource(interp, rsrcName, rsrcID, fileName);
982 Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), errStr, "should be \"",
983 Tcl_GetString(objv[0]), " fileName\" or \"",
984 Tcl_GetString(objv[0]), " -rsrc name ?fileName?\" or \"",
985 Tcl_GetString(objv[0]), " -rsrcid id ?fileName?\"",
991 *----------------------------------------------------------------------
995 * This procedure makes the beep sound.
998 * A standard Tcl result.
1003 *----------------------------------------------------------------------
1008 ClientData dummy, /* Not used. */
1009 Tcl_Interp *interp, /* Current interpreter. */
1010 int objc, /* Number of arguments. */
1011 Tcl_Obj *CONST objv[]) /* Argument values. */
1013 Tcl_Obj *resultPtr, *objPtr;
1016 int volume = -1, length;
1017 char * sndArg = NULL;
1019 resultPtr = Tcl_GetObjResult(interp);
1023 } else if (objc == 2) {
1024 if (!strcmp(Tcl_GetStringFromObj(objv[1], &length), "-list")) {
1030 count = CountResources('snd ');
1031 for (i = 1; i <= count; i++) {
1032 sound = GetIndResource('snd ', i);
1033 if (sound != NULL) {
1034 GetResInfo(sound, &id, &rezType, theName);
1035 if (theName[0] == 0) {
1038 objPtr = Tcl_NewStringObj((char *) theName + 1,
1040 Tcl_ListObjAppendElement(interp, resultPtr, objPtr);
1045 sndArg = Tcl_GetStringFromObj(objv[1], &length);
1047 } else if (objc == 3) {
1048 if (!strcmp(Tcl_GetStringFromObj(objv[1], &length), "-volume")) {
1049 Tcl_GetIntFromObj(interp, objv[2], &volume);
1053 } else if (objc == 4) {
1054 if (!strcmp(Tcl_GetStringFromObj(objv[1], &length), "-volume")) {
1055 Tcl_GetIntFromObj(interp, objv[2], &volume);
1056 sndArg = Tcl_GetStringFromObj(objv[3], &length);
1067 if (sndArg == NULL) {
1069 * Set Volume for SysBeep
1073 SetSoundVolume(volume, SYS_BEEP_VOLUME);
1082 SetSoundVolume(0, RESET_VOLUME);
1085 strcpy((char *) sndName + 1, sndArg);
1086 sndName[0] = length;
1087 sound = GetNamedResource('snd ', sndName);
1088 if (sound != NULL) {
1090 * Set Volume for Default Output device
1094 SetSoundVolume(volume, DEFAULT_SND_VOLUME);
1097 SndPlay(NULL, (SndListHandle) sound, false);
1104 SetSoundVolume(0, RESET_VOLUME);
1107 Tcl_AppendStringsToObj(resultPtr, " \"", sndArg,
1108 "\" is not a valid sound. (Try ",
1109 Tcl_GetString(objv[0]), " -list)", NULL);
1117 Tcl_WrongNumArgs(interp, 1, objv, "[-volume num] [-list | sndName]?");
1122 *-----------------------------------------------------------------------------
1126 * Set the volume for either the SysBeep or the SndPlay call depending
1127 * on the value of mode (SYS_BEEP_VOLUME or DEFAULT_SND_VOLUME
1130 * It also stores the last channel set, and the old value of its
1131 * VOLUME. If you call SetSoundVolume with a mode of RESET_VOLUME,
1132 * it will undo the last setting. The volume parameter is
1133 * ignored in this case.
1136 * Sets the System Volume
1141 *-----------------------------------------------------------------------------
1146 int volume, /* This is the new volume */
1147 enum WhichVolume mode) /* This flag says which volume to
1148 * set: SysBeep, SndPlay, or instructs us
1149 * to reset the volume */
1151 static int hasSM3 = -1;
1152 static enum WhichVolume oldMode;
1153 static long oldVolume = -1;
1156 * The volume setting calls only work if we have SoundManager
1157 * 3.0 or higher. So we check that here.
1161 if (GetToolboxTrapAddress(_SoundDispatch)
1162 != GetToolboxTrapAddress(_Unimplemented)) {
1163 NumVersion SMVers = SndSoundManagerVersion();
1164 if (SMVers.majorRev > 2) {
1171 * If the SoundDispatch trap is not present, then
1172 * we don't have the SoundManager at all.
1180 * If we don't have Sound Manager 3.0, we can't set the sound volume.
1181 * We will just ignore the request rather than raising an error.
1189 case SYS_BEEP_VOLUME:
1190 GetSysBeepVolume(&oldVolume);
1191 SetSysBeepVolume(volume);
1192 oldMode = SYS_BEEP_VOLUME;
1194 case DEFAULT_SND_VOLUME:
1195 GetDefaultOutputVolume(&oldVolume);
1196 SetDefaultOutputVolume(volume);
1197 oldMode = DEFAULT_SND_VOLUME;
1201 * If oldVolume is -1 someone has made a programming error
1202 * and called reset before setting the volume. This is benign
1203 * however, so we will just exit.
1206 if (oldVolume != -1) {
1207 if (oldMode == SYS_BEEP_VOLUME) {
1208 SetSysBeepVolume(oldVolume);
1209 } else if (oldMode == DEFAULT_SND_VOLUME) {
1210 SetDefaultOutputVolume(oldVolume);
1218 *-----------------------------------------------------------------------------
1220 * Tcl_MacEvalResource --
1222 * Used to extend the source command. Sources Tcl code from a Text
1223 * resource. Currently only sources the resouce by name file ID may be
1224 * supported at a later date.
1227 * Depends on the Tcl code in the resource.
1230 * Returns a Tcl result.
1232 *-----------------------------------------------------------------------------
1236 Tcl_MacEvalResource(
1237 Tcl_Interp *interp, /* Interpreter in which to process file. */
1238 CONST char *resourceName, /* Name of TEXT resource to source,
1239 NULL if number should be used. */
1240 int resourceNumber, /* Resource id of source. */
1241 CONST char *fileName) /* Name of file to process.
1242 NULL if application resource. */
1247 int result, iOpenedResFile = false;
1248 short saveRef, fileRef = -1;
1251 Tcl_DString ds, buffer;
1252 CONST char *nativeName;
1254 saveRef = CurResFile();
1256 if (fileName != NULL) {
1259 if (Tcl_TranslateFileName(interp, fileName, &buffer) == NULL) {
1262 nativeName = Tcl_UtfToExternalDString(NULL, Tcl_DStringValue(&buffer),
1263 Tcl_DStringLength(&buffer), &ds);
1264 err = FSpLocationFromPath(strlen(nativeName), nativeName,
1266 Tcl_DStringFree(&ds);
1267 Tcl_DStringFree(&buffer);
1269 Tcl_AppendResult(interp, "Error finding the file: \"",
1270 fileName, "\".", NULL);
1274 fileRef = FSpOpenResFileCompat(&fileSpec, fsRdPerm);
1275 if (fileRef == -1) {
1276 Tcl_AppendResult(interp, "Error reading the file: \"",
1277 fileName, "\".", NULL);
1281 UseResFile(fileRef);
1282 iOpenedResFile = true;
1285 * The default behavior will search through all open resource files.
1286 * This may not be the behavior you desire. If you want the behavior
1287 * of this call to *only* search the application resource fork, you
1288 * must call UseResFile at this point to set it to the application
1289 * file. This means you must have already obtained the application's
1290 * fileRef when the application started up.
1295 * Load the resource by name or ID
1297 if (resourceName != NULL) {
1299 Tcl_UtfToExternalDString(NULL, resourceName, -1, &ds);
1300 strcpy((char *) rezName + 1, Tcl_DStringValue(&ds));
1301 rezName[0] = (unsigned) Tcl_DStringLength(&ds);
1302 sourceText = GetNamedResource('TEXT', rezName);
1303 Tcl_DStringFree(&ds);
1305 sourceText = GetResource('TEXT', (short) resourceNumber);
1308 if (sourceText == NULL) {
1311 char *sourceStr = NULL;
1314 sourceStr = Tcl_MacConvertTextResource(sourceText);
1315 HUnlock(sourceText);
1316 ReleaseResource(sourceText);
1319 * We now evaluate the Tcl source
1321 result = Tcl_Eval(interp, sourceStr);
1323 if (result == TCL_RETURN) {
1325 } else if (result == TCL_ERROR) {
1326 sprintf(msg, "\n (rsrc \"%.150s\" line %d)",
1329 Tcl_AddErrorInfo(interp, msg);
1332 goto rezEvalCleanUp;
1336 sprintf(idStr, "ID=%d", resourceNumber);
1337 Tcl_AppendResult(interp, "The resource \"",
1338 (resourceName != NULL ? resourceName : idStr),
1339 "\" could not be loaded from ",
1340 (fileName != NULL ? fileName : "application"),
1346 * TRICKY POINT: The code that you are sourcing here could load a
1347 * shared library. This will go AHEAD of the resource we stored away
1348 * in saveRef on the resource path.
1349 * If you restore the saveRef in this case, you will never be able
1350 * to get to the resources in the shared library, since you are now
1351 * pointing too far down on the resource list.
1352 * So, we only reset the current resource file if WE opened a resource
1353 * explicitly, and then only if the CurResFile is still the
1357 if (iOpenedResFile && (CurResFile() == fileRef)) {
1358 UseResFile(saveRef);
1361 if (fileRef != -1) {
1362 CloseResFile(fileRef);
1369 *-----------------------------------------------------------------------------
1371 * Tcl_MacConvertTextResource --
1373 * Converts a TEXT resource into a Tcl suitable string.
1376 * Mallocs the returned memory, converts '\r' to '\n', and appends a NULL.
1379 * A new malloced string.
1381 *-----------------------------------------------------------------------------
1385 Tcl_MacConvertTextResource(
1386 Handle resource) /* Handle to TEXT resource. */
1392 size = GetResourceSizeOnDisk(resource);
1394 Tcl_ExternalToUtfDString(NULL, *resource, size, &dstr);
1396 size = Tcl_DStringLength(&dstr) + 1;
1397 resultStr = (char *) ckalloc((unsigned) size);
1399 memcpy((VOID *) resultStr, (VOID *) Tcl_DStringValue(&dstr), (size_t) size);
1401 Tcl_DStringFree(&dstr);
1403 for (i=0; i<size; i++) {
1404 if (resultStr[i] == '\r') {
1405 resultStr[i] = '\n';
1413 *-----------------------------------------------------------------------------
1415 * Tcl_MacFindResource --
1417 * Higher level interface for loading resources.
1420 * Attempts to load a resource.
1423 * A handle on success.
1425 *-----------------------------------------------------------------------------
1429 Tcl_MacFindResource(
1430 Tcl_Interp *interp, /* Interpreter in which to process file. */
1431 long resourceType, /* Type of resource to load. */
1432 CONST char *resourceName, /* Name of resource to find,
1433 * NULL if number should be used. */
1434 int resourceNumber, /* Resource id of source. */
1435 CONST char *resFileRef, /* Registered resource file reference,
1436 * NULL if searching all open resource files. */
1437 int *releaseIt) /* Should we release this resource when done. */
1439 Tcl_HashEntry *nameHashPtr;
1440 OpenResourceFork *resourceRef;
1441 int limitSearch = false;
1445 if (resFileRef != NULL) {
1446 nameHashPtr = Tcl_FindHashEntry(&nameTable, resFileRef);
1447 if (nameHashPtr == NULL) {
1448 Tcl_AppendResult(interp, "invalid resource file reference \"",
1449 resFileRef, "\"", (char *) NULL);
1452 resourceRef = (OpenResourceFork *) Tcl_GetHashValue(nameHashPtr);
1453 saveRef = CurResFile();
1454 UseResFile((short) resourceRef->fileRef);
1459 * Some system resources (for example system resources) should not
1460 * be released. So we set autoload to false, and try to get the resource.
1461 * If the Master Pointer of the returned handle is null, then resource was
1462 * not in memory, and it is safe to release it. Otherwise, it is not.
1467 if (resourceName == NULL) {
1469 resource = Get1Resource(resourceType, resourceNumber);
1471 resource = GetResource(resourceType, resourceNumber);
1476 Tcl_UtfToExternalDString(NULL, resourceName, -1, &ds);
1477 strcpy((char *) rezName + 1, Tcl_DStringValue(&ds));
1478 rezName[0] = (unsigned) Tcl_DStringLength(&ds);
1480 resource = Get1NamedResource(resourceType,
1483 resource = GetNamedResource(resourceType,
1486 Tcl_DStringFree(&ds);
1489 if (resource != NULL && *resource == NULL) {
1491 LoadResource(resource);
1500 UseResFile(saveRef);
1507 *----------------------------------------------------------------------
1511 * Initialize the structures used for resource management.
1519 *----------------------------------------------------------------------
1527 Tcl_InitHashTable(&nameTable, TCL_STRING_KEYS);
1528 Tcl_InitHashTable(&resourceTable, TCL_ONE_WORD_KEYS);
1529 resourceForkList = Tcl_NewObj();
1530 Tcl_IncrRefCount(resourceForkList);
1532 BuildResourceForkList();
1537 /*Tcl_RegisterObjType(typePtr) */
1540 *----------------------------------------------------------------------
1542 * Tcl_NewOSTypeObj --
1544 * This procedure is used to create a new resource name type object.
1547 * The newly created object is returned. This object will have a NULL
1548 * string representation. The returned object has ref count 0.
1553 *----------------------------------------------------------------------
1558 OSType newOSType) /* Int used to initialize the new object. */
1560 register Tcl_Obj *objPtr;
1564 Tcl_RegisterObjType(&osType);
1567 objPtr = Tcl_NewObj();
1568 objPtr->bytes = NULL;
1569 objPtr->internalRep.longValue = newOSType;
1570 objPtr->typePtr = &osType;
1575 *----------------------------------------------------------------------
1577 * Tcl_SetOSTypeObj --
1579 * Modify an object to be a resource type and to have the
1580 * specified long value.
1586 * The object's old string rep, if any, is freed. Also, any old
1587 * internal rep is freed.
1589 *----------------------------------------------------------------------
1594 Tcl_Obj *objPtr, /* Object whose internal rep to init. */
1595 OSType newOSType) /* Integer used to set object's value. */
1597 register Tcl_ObjType *oldTypePtr = objPtr->typePtr;
1601 Tcl_RegisterObjType(&osType);
1604 if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) {
1605 oldTypePtr->freeIntRepProc(objPtr);
1608 objPtr->internalRep.longValue = newOSType;
1609 objPtr->typePtr = &osType;
1611 Tcl_InvalidateStringRep(objPtr);
1615 *----------------------------------------------------------------------
1617 * Tcl_GetOSTypeFromObj --
1619 * Attempt to return an int from the Tcl object "objPtr". If the object
1620 * is not already an int, an attempt will be made to convert it to one.
1623 * The return value is a standard Tcl object result. If an error occurs
1624 * during conversion, an error message is left in interp->objResult
1625 * unless "interp" is NULL.
1628 * If the object is not already an int, the conversion will free
1629 * any old internal representation.
1631 *----------------------------------------------------------------------
1635 Tcl_GetOSTypeFromObj(
1636 Tcl_Interp *interp, /* Used for error reporting if not NULL. */
1637 Tcl_Obj *objPtr, /* The object from which to get a int. */
1638 OSType *osTypePtr) /* Place to store resulting int. */
1640 register int result;
1644 Tcl_RegisterObjType(&osType);
1647 if (objPtr->typePtr == &osType) {
1648 *osTypePtr = objPtr->internalRep.longValue;
1652 result = SetOSTypeFromAny(interp, objPtr);
1653 if (result == TCL_OK) {
1654 *osTypePtr = objPtr->internalRep.longValue;
1660 *----------------------------------------------------------------------
1662 * DupOSTypeInternalRep --
1664 * Initialize the internal representation of an int Tcl_Obj to a
1665 * copy of the internal representation of an existing int object.
1671 * "copyPtr"s internal rep is set to the integer corresponding to
1672 * "srcPtr"s internal rep.
1674 *----------------------------------------------------------------------
1678 DupOSTypeInternalRep(
1679 Tcl_Obj *srcPtr, /* Object with internal rep to copy. */
1680 Tcl_Obj *copyPtr) /* Object with internal rep to set. */
1682 copyPtr->internalRep.longValue = srcPtr->internalRep.longValue;
1683 copyPtr->typePtr = &osType;
1687 *----------------------------------------------------------------------
1689 * SetOSTypeFromAny --
1691 * Attempt to generate an integer internal form for the Tcl object
1695 * The return value is a standard object Tcl result. If an error occurs
1696 * during conversion, an error message is left in interp->objResult
1697 * unless "interp" is NULL.
1700 * If no error occurs, an int is stored as "objPtr"s internal
1703 *----------------------------------------------------------------------
1708 Tcl_Interp *interp, /* Used for error reporting if not NULL. */
1709 Tcl_Obj *objPtr) /* The object to convert. */
1711 Tcl_ObjType *oldTypePtr = objPtr->typePtr;
1717 * Get the string representation. Make it up-to-date if necessary.
1720 string = Tcl_GetStringFromObj(objPtr, &length);
1723 if (interp != NULL) {
1724 Tcl_ResetResult(interp);
1725 Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1726 "expected Macintosh OS type but got \"", string, "\"",
1731 newOSType = *((long *) string);
1734 * The conversion to resource type succeeded. Free the old internalRep
1735 * before setting the new one.
1738 if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) {
1739 oldTypePtr->freeIntRepProc(objPtr);
1742 objPtr->internalRep.longValue = newOSType;
1743 objPtr->typePtr = &osType;
1748 *----------------------------------------------------------------------
1750 * UpdateStringOfOSType --
1752 * Update the string representation for an resource type object.
1753 * Note: This procedure does not free an existing old string rep
1754 * so storage will be lost if this has not already been done.
1760 * The object's string is set to a valid string that results from
1761 * the int-to-string conversion.
1763 *----------------------------------------------------------------------
1767 UpdateStringOfOSType(
1768 register Tcl_Obj *objPtr) /* Int object whose string rep to update. */
1770 objPtr->bytes = ckalloc(5);
1771 sprintf(objPtr->bytes, "%-4.4s", &(objPtr->internalRep.longValue));
1776 *----------------------------------------------------------------------
1778 * GetRsrcRefFromObj --
1780 * Given a String object containing a resource file token, return
1781 * the OpenResourceFork structure that it represents, or NULL if
1782 * the token cannot be found. If okayOnReadOnly is false, it will
1783 * also check whether the token corresponds to a read-only file,
1784 * and return NULL if it is.
1787 * A pointer to an OpenResourceFork structure, or NULL.
1790 * An error message may be left in resultPtr.
1792 *----------------------------------------------------------------------
1795 static OpenResourceFork *
1797 register Tcl_Obj *objPtr, /* String obj containing file token */
1798 int okayOnReadOnly, /* Whether this operation is okay for a *
1799 * read only file. */
1800 const char *operation, /* String containing the operation we *
1801 * were trying to perform, used for errors */
1802 Tcl_Obj *resultPtr) /* Tcl_Obj to contain error message */
1805 Tcl_HashEntry *nameHashPtr;
1806 OpenResourceFork *resourceRef;
1810 stringPtr = Tcl_GetStringFromObj(objPtr, &length);
1811 nameHashPtr = Tcl_FindHashEntry(&nameTable, stringPtr);
1812 if (nameHashPtr == NULL) {
1813 Tcl_AppendStringsToObj(resultPtr,
1814 "invalid resource file reference \"",
1815 stringPtr, "\"", (char *) NULL);
1819 resourceRef = (OpenResourceFork *) Tcl_GetHashValue(nameHashPtr);
1821 if (!okayOnReadOnly) {
1822 err = GetResFileAttrs((short) resourceRef->fileRef);
1823 if (err & mapReadOnly) {
1824 Tcl_AppendStringsToObj(resultPtr, "cannot ", operation,
1825 " resource file \"",
1826 stringPtr, "\", it was opened read only",
1835 *----------------------------------------------------------------------
1837 * TclMacRegisterResourceFork --
1839 * Register an open resource fork in the table of open resources
1840 * managed by the procedures in this file. If the resource file
1841 * is already registered with the table, then no new token is made.
1843 * The behavior is controlled by the value of tokenPtr, and of the
1844 * flags variable. For tokenPtr, the possibilities are:
1845 * - NULL: The new token is auto-generated, but not returned.
1846 * - The string value of tokenPtr is the empty string: Then
1847 * the new token is auto-generated, and returned in tokenPtr
1848 * - tokenPtr has a value: The string value will be used for the token,
1849 * unless it is already in use, in which case a new token will
1850 * be generated, and returned in tokenPtr.
1852 * For the flags variable: it can be one of:
1853 * - TCL_RESOURCE__INSERT_TAIL: The element is inserted at the
1854 * end of the list of open resources. Used only in Resource_Init.
1855 * - TCL_RESOURCE_DONT_CLOSE: The resource close command will not close
1857 * - TCL_RESOURCE_CHECK_IF_OPEN: This will check to see if this file's
1858 * resource fork is already opened by this Tcl shell, and return
1859 * an error without registering the resource fork.
1862 * Standard Tcl Result
1865 * An entry may be added to the resource name table.
1867 *----------------------------------------------------------------------
1871 TclMacRegisterResourceFork(
1872 short fileRef, /* File ref for an open resource fork. */
1873 Tcl_Obj *tokenPtr, /* A Tcl Object to which to write the *
1875 int flags) /* 1 means insert at the head of the resource
1876 * fork list, 0 means at the tail */
1879 Tcl_HashEntry *resourceHashPtr;
1880 Tcl_HashEntry *nameHashPtr;
1881 OpenResourceFork *resourceRef;
1883 char *resourceId = NULL;
1890 * If we were asked to, check that this file has not been opened
1891 * already with a different permission. It it has, then return an error.
1896 if (flags & TCL_RESOURCE_CHECK_IF_OPEN) {
1897 Tcl_HashSearch search;
1898 short oldFileRef, filePermissionFlag;
1899 FCBPBRec newFileRec, oldFileRec;
1902 oldFileRec.ioCompletion = NULL;
1903 oldFileRec.ioFCBIndx = 0;
1904 oldFileRec.ioNamePtr = NULL;
1906 newFileRec.ioCompletion = NULL;
1907 newFileRec.ioFCBIndx = 0;
1908 newFileRec.ioNamePtr = NULL;
1909 newFileRec.ioVRefNum = 0;
1910 newFileRec.ioRefNum = fileRef;
1911 err = PBGetFCBInfo(&newFileRec, false);
1912 filePermissionFlag = ( newFileRec.ioFCBFlags >> 12 ) & 0x1;
1915 resourceHashPtr = Tcl_FirstHashEntry(&resourceTable, &search);
1916 while (resourceHashPtr != NULL) {
1917 oldFileRef = (short) Tcl_GetHashKey(&resourceTable,
1919 if (oldFileRef == fileRef) {
1923 oldFileRec.ioVRefNum = 0;
1924 oldFileRec.ioRefNum = oldFileRef;
1925 err = PBGetFCBInfo(&oldFileRec, false);
1928 * err might not be noErr either because the file has closed
1929 * out from under us somehow, which is bad but we're not going
1930 * to fix it here, OR because it is the ROM MAP, which has a
1931 * fileRef, but can't be gotten to by PBGetFCBInfo.
1934 && (newFileRec.ioFCBVRefNum == oldFileRec.ioFCBVRefNum)
1935 && (newFileRec.ioFCBFlNm == oldFileRec.ioFCBFlNm)) {
1937 * In MacOS 8.1 it seems like we get different file refs even
1938 * though we pass the same file & permissions. This is not
1939 * what Inside Mac says should happen, but it does, so if it
1940 * does, then close the new res file and return the original
1944 if (filePermissionFlag == ((oldFileRec.ioFCBFlags >> 12) & 0x1)) {
1945 CloseResFile(fileRef);
1949 if (tokenPtr != NULL) {
1950 Tcl_SetStringObj(tokenPtr, "Resource already open with different permissions.", -1);
1955 resourceHashPtr = Tcl_NextHashEntry(&search);
1961 * If the file has already been opened with these same permissions, then it
1962 * will be in our list and we will have set new to 0 above.
1963 * So we will just return the token (if tokenPtr is non-null)
1967 resourceHashPtr = Tcl_CreateHashEntry(&resourceTable,
1968 (char *) fileRef, &new);
1972 if (tokenPtr != NULL) {
1973 resourceId = (char *) Tcl_GetHashValue(resourceHashPtr);
1974 Tcl_SetStringObj(tokenPtr, resourceId, -1);
1980 * If we were passed in a result pointer which is not an empty
1981 * string, attempt to use that as the key. If the key already
1982 * exists, silently fall back on resource%d...
1985 if (tokenPtr != NULL) {
1988 tokenVal = Tcl_GetStringFromObj(tokenPtr, &length);
1990 nameHashPtr = Tcl_FindHashEntry(&nameTable, tokenVal);
1991 if (nameHashPtr == NULL) {
1992 resourceId = ckalloc(length + 1);
1993 memcpy(resourceId, tokenVal, length);
1994 resourceId[length] = '\0';
1999 if (resourceId == NULL) {
2000 resourceId = (char *) ckalloc(15);
2001 sprintf(resourceId, "resource%d", newId);
2004 Tcl_SetHashValue(resourceHashPtr, resourceId);
2007 nameHashPtr = Tcl_CreateHashEntry(&nameTable, resourceId, &new);
2009 panic("resource id has repeated itself");
2012 resourceRef = (OpenResourceFork *) ckalloc(sizeof(OpenResourceFork));
2013 resourceRef->fileRef = fileRef;
2014 resourceRef->flags = flags;
2016 Tcl_SetHashValue(nameHashPtr, (ClientData) resourceRef);
2017 if (tokenPtr != NULL) {
2018 Tcl_SetStringObj(tokenPtr, resourceId, -1);
2021 if (flags & TCL_RESOURCE_INSERT_TAIL) {
2022 Tcl_ListObjAppendElement(NULL, resourceForkList, tokenPtr);
2024 Tcl_ListObjReplace(NULL, resourceForkList, 0, 0, 1, &tokenPtr);
2030 *----------------------------------------------------------------------
2032 * TclMacUnRegisterResourceFork --
2034 * Removes the entry for an open resource fork from the table of
2035 * open resources managed by the procedures in this file.
2036 * If resultPtr is not NULL, it will be used for error reporting.
2039 * The fileRef for this token, or -1 if an error occured.
2042 * An entry is removed from the resource name table.
2044 *----------------------------------------------------------------------
2048 TclMacUnRegisterResourceFork(
2053 Tcl_HashEntry *resourceHashPtr;
2054 Tcl_HashEntry *nameHashPtr;
2055 OpenResourceFork *resourceRef;
2056 char *resourceId = NULL;
2059 int i, match, index, listLen, length, elemLen;
2063 nameHashPtr = Tcl_FindHashEntry(&nameTable, tokenPtr);
2064 if (nameHashPtr == NULL) {
2065 if (resultPtr != NULL) {
2066 Tcl_AppendStringsToObj(resultPtr,
2067 "invalid resource file reference \"",
2068 tokenPtr, "\"", (char *) NULL);
2073 resourceRef = (OpenResourceFork *) Tcl_GetHashValue(nameHashPtr);
2074 fileRef = resourceRef->fileRef;
2076 if ( resourceRef->flags & TCL_RESOURCE_DONT_CLOSE ) {
2077 if (resultPtr != NULL) {
2078 Tcl_AppendStringsToObj(resultPtr,
2079 "can't close \"", tokenPtr, "\" resource file",
2085 Tcl_DeleteHashEntry(nameHashPtr);
2086 ckfree((char *) resourceRef);
2090 * Now remove the resource from the resourceForkList object
2093 Tcl_ListObjGetElements(NULL, resourceForkList, &listLen, &elemPtrs);
2097 length = strlen(tokenPtr);
2099 for (i = 0; i < listLen; i++) {
2101 bytes = Tcl_GetStringFromObj(elemPtrs[i], &elemLen);
2102 if (length == elemLen) {
2103 match = (memcmp(bytes, tokenPtr,
2104 (size_t) length) == 0);
2112 panic("the resource Fork List is out of synch!");
2115 Tcl_ListObjReplace(NULL, resourceForkList, index, 1, 0, NULL);
2117 resourceHashPtr = Tcl_FindHashEntry(&resourceTable, (char *) fileRef);
2119 if (resourceHashPtr == NULL) {
2120 panic("Resource & Name tables are out of synch in resource command.");
2122 ckfree(Tcl_GetHashValue(resourceHashPtr));
2123 Tcl_DeleteHashEntry(resourceHashPtr);
2131 *----------------------------------------------------------------------
2133 * BuildResourceForkList --
2135 * Traverses the list of open resource forks, and builds the
2136 * list of resources forks. Also creates a resource token for any that
2137 * are opened but not registered with our resource system.
2138 * This is based on code from Apple DTS.
2144 * The list of resource forks is updated.
2145 * The resource name table may be augmented.
2147 *----------------------------------------------------------------------
2151 BuildResourceForkList()
2153 Handle currentMapHandle, mSysMapHandle;
2160 ProcessSerialNumber psn;
2161 ProcessInfoRec info;
2165 * Get the application name, so we can substitute
2166 * the token "application" for the application's resource.
2169 GetCurrentProcess(&psn);
2170 info.processInfoLength = sizeof(ProcessInfoRec);
2171 info.processName = (StringPtr) &appName;
2172 info.processAppSpec = &fileSpec;
2173 GetProcessInformation(&psn, &info);
2174 p2cstr((StringPtr) appName);
2177 fileRec.ioCompletion = NULL;
2178 fileRec.ioVRefNum = 0;
2179 fileRec.ioFCBIndx = 0;
2180 fileRec.ioNamePtr = (StringPtr) &fileName;
2183 currentMapHandle = LMGetTopMapHndl();
2184 mSysMapHandle = LMGetSysMapHndl();
2188 * Now do the ones opened after the application.
2191 nameObj = Tcl_NewObj();
2193 tempPtr = *currentMapHandle;
2195 fileRec.ioRefNum = *((short *) (tempPtr + 20));
2196 err = PBGetFCBInfo(&fileRec, false);
2200 * The ROM resource map does not correspond to an opened file...
2202 Tcl_SetStringObj(nameObj, "ROM Map", -1);
2204 p2cstr((StringPtr) fileName);
2205 if (strcmp(fileName,appName) == 0) {
2206 Tcl_SetStringObj(nameObj, "application", -1);
2208 Tcl_SetStringObj(nameObj, fileName, -1);
2213 TclMacRegisterResourceFork(fileRec.ioRefNum, nameObj,
2214 TCL_RESOURCE_DONT_CLOSE | TCL_RESOURCE_INSERT_TAIL);
2216 if (currentMapHandle == mSysMapHandle) {
2220 currentMapHandle = *((Handle *) (tempPtr + 16));