OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [tcl/] [mac/] [tclMacResource.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/*
2
 * tclMacResource.c --
3
 *
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.
8
 *
9
 * Copyright (c) 1996-1997 Sun Microsystems, Inc.
10
 *
11
 * See the file "license.terms" for information on usage and redistribution
12
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13
 *
14
 * RCS: @(#) $Id: tclMacResource.c,v 1.1.1.1 2002-01-16 10:25:32 markom Exp $
15
 */
16
 
17
#include <Errors.h>
18
#include <FSpCompat.h>
19
#include <Processes.h>
20
#include <Resources.h>
21
#include <Sound.h>
22
#include <Strings.h>
23
#include <Traps.h>
24
#include <LowMem.h>
25
 
26
#include "FullPath.h"
27
#include "tcl.h"
28
#include "tclInt.h"
29
#include "tclMac.h"
30
#include "tclMacInt.h"
31
#include "tclMacPort.h"
32
 
33
/*
34
 * This flag tells the RegisterResource function to insert the
35
 * resource into the tail of the resource fork list.  Needed only
36
 * Resource_Init.
37
 */
38
 
39
#define TCL_RESOURCE_INSERT_TAIL 1
40
/*
41
 * 2 is taken by TCL_RESOURCE_DONT_CLOSE
42
 * which is the only public flag to TclMacRegisterResourceFork.
43
 */
44
 
45
#define TCL_RESOURCE_CHECK_IF_OPEN 4
46
 
47
/*
48
 * Pass this in the mode parameter of SetSoundVolume to determine
49
 * which volume to set.
50
 */
51
 
52
enum WhichVolume {
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 */
56
};
57
 
58
/*
59
 * Hash table to track open resource files.
60
 */
61
 
62
typedef struct OpenResourceFork {
63
    short fileRef;
64
    int   flags;
65
} OpenResourceFork;
66
 
67
 
68
 
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. */
79
/*
80
 * Prototypes for procedures defined later in this file:
81
 */
82
 
83
static void             DupOSTypeInternalRep _ANSI_ARGS_((Tcl_Obj *srcPtr,
84
                            Tcl_Obj *copyPtr));
85
static void             ResourceInit _ANSI_ARGS_((void));
86
static void             BuildResourceForkList _ANSI_ARGS_((void));
87
static int              SetOSTypeFromAny _ANSI_ARGS_((Tcl_Interp *interp,
88
                            Tcl_Obj *objPtr));
89
static void             UpdateStringOfOSType _ANSI_ARGS_((Tcl_Obj *objPtr));
90
static OpenResourceFork* GetRsrcRefFromObj _ANSI_ARGS_((Tcl_Obj *objPtr,
91
                                int okayOnReadOnly, const char *operation,
92
                                Tcl_Obj *resultPtr));
93
 
94
static void             SetSoundVolume(int volume, enum WhichVolume mode);
95
 
96
/*
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.
99
 */
100
 
101
static Tcl_ObjType osType = {
102
    "ostype",                           /* name */
103
    (Tcl_FreeInternalRepProc *) NULL,   /* freeIntRepProc */
104
    DupOSTypeInternalRep,               /* dupIntRepProc */
105
    UpdateStringOfOSType,               /* updateStringProc */
106
    SetOSTypeFromAny                    /* setFromAnyProc */
107
};
108
 
109
/*
110
 *----------------------------------------------------------------------
111
 *
112
 * Tcl_ResourceObjCmd --
113
 *
114
 *      This procedure is invoked to process the "resource" Tcl command.
115
 *      See the user documentation for details on what it does.
116
 *
117
 * Results:
118
 *      A standard Tcl result.
119
 *
120
 * Side effects:
121
 *      See the user documentation.
122
 *
123
 *----------------------------------------------------------------------
124
 */
125
 
126
int
127
Tcl_ResourceObjCmd(
128
    ClientData clientData,              /* Not used. */
129
    Tcl_Interp *interp,                 /* Current interpreter. */
130
    int objc,                           /* Number of arguments. */
131
    Tcl_Obj *CONST objv[])              /* Argument values. */
132
{
133
    Tcl_Obj *resultPtr, *objPtr;
134
    int index, result;
135
    long fileRef, rsrcId;
136
    FSSpec fileSpec;
137
    Tcl_DString buffer;
138
    char *nativeName;
139
    char *stringPtr;
140
    char errbuf[16];
141
    OpenResourceFork *resourceRef;
142
    Handle resource = NULL;
143
    OSErr err;
144
    int count, i, limitSearch = false, length;
145
    short id, saveRef, resInfo;
146
    Str255 theName;
147
    OSType rezType;
148
    int gotInt, releaseIt = 0, force;
149
    char *resourceId = NULL;
150
    long size;
151
    char macPermision;
152
    int mode;
153
 
154
    static char *switches[] = {"close", "delete" ,"files", "list",
155
            "open", "read", "types", "write", (char *) NULL
156
    };
157
 
158
    enum {
159
            RESOURCE_CLOSE, RESOURCE_DELETE, RESOURCE_FILES, RESOURCE_LIST,
160
            RESOURCE_OPEN, RESOURCE_READ, RESOURCE_TYPES, RESOURCE_WRITE
161
    };
162
 
163
    static char *writeSwitches[] = {
164
            "-id", "-name", "-file", "-force", (char *) NULL
165
    };
166
 
167
    enum {
168
            RESOURCE_WRITE_ID, RESOURCE_WRITE_NAME,
169
            RESOURCE_WRITE_FILE, RESOURCE_FORCE
170
    };
171
 
172
    static char *deleteSwitches[] = {"-id", "-name", "-file", (char *) NULL};
173
 
174
    enum {RESOURCE_DELETE_ID, RESOURCE_DELETE_NAME, RESOURCE_DELETE_FILE};
175
 
176
    resultPtr = Tcl_GetObjResult(interp);
177
 
178
    if (objc < 2) {
179
        Tcl_WrongNumArgs(interp, 1, objv, "option ?arg ...?");
180
        return TCL_ERROR;
181
    }
182
 
183
    if (Tcl_GetIndexFromObj(interp, objv[1], switches, "option", 0, &index)
184
            != TCL_OK) {
185
        return TCL_ERROR;
186
    }
187
    if (!initialized) {
188
        ResourceInit();
189
    }
190
    result = TCL_OK;
191
 
192
    switch (index) {
193
        case RESOURCE_CLOSE:
194
            if (objc != 3) {
195
                Tcl_WrongNumArgs(interp, 2, objv, "resourceRef");
196
                return TCL_ERROR;
197
            }
198
            stringPtr = Tcl_GetStringFromObj(objv[2], &length);
199
            fileRef = TclMacUnRegisterResourceFork(stringPtr, resultPtr);
200
 
201
            if (fileRef >= 0) {
202
                CloseResFile((short) fileRef);
203
                return TCL_OK;
204
            } else {
205
                return TCL_ERROR;
206
            }
207
        case RESOURCE_DELETE:
208
            if (!((objc >= 3) && (objc <= 9) && ((objc % 2) == 1))) {
209
                Tcl_WrongNumArgs(interp, 2, objv,
210
                    "?-id resourceId? ?-name resourceName? ?-file \
211
resourceRef? resourceType");
212
                return TCL_ERROR;
213
            }
214
 
215
            i = 2;
216
            fileRef = -1;
217
            gotInt = false;
218
            resourceId = NULL;
219
            limitSearch = false;
220
 
221
            while (i < (objc - 2)) {
222
                if (Tcl_GetIndexFromObj(interp, objv[i], deleteSwitches,
223
                        "option", 0, &index) != TCL_OK) {
224
                    return TCL_ERROR;
225
                }
226
 
227
                switch (index) {
228
                    case RESOURCE_DELETE_ID:
229
                        if (Tcl_GetLongFromObj(interp, objv[i+1], &rsrcId)
230
                                != TCL_OK) {
231
                            return TCL_ERROR;
232
                        }
233
                        gotInt = true;
234
                        break;
235
                    case RESOURCE_DELETE_NAME:
236
                        resourceId = Tcl_GetStringFromObj(objv[i+1], &length);
237
                        if (length > 255) {
238
                            Tcl_AppendStringsToObj(resultPtr,"-name argument ",
239
                                    "too long, must be < 255 characters",
240
                                    (char *) NULL);
241
                            return TCL_ERROR;
242
                        }
243
                        strcpy((char *) theName, resourceId);
244
                        resourceId = (char *) theName;
245
                        c2pstr(resourceId);
246
                        break;
247
                    case RESOURCE_DELETE_FILE:
248
                        resourceRef = GetRsrcRefFromObj(objv[i+1], 0,
249
                                "delete from", resultPtr);
250
                        if (resourceRef == NULL) {
251
                            return TCL_ERROR;
252
                        }
253
                        limitSearch = true;
254
                        break;
255
                }
256
                i += 2;
257
            }
258
 
259
            if ((resourceId == NULL) && !gotInt) {
260
                Tcl_AppendStringsToObj(resultPtr,"you must specify either ",
261
                        "\"-id\" or \"-name\" or both ",
262
                        "to \"resource delete\"",
263
                        (char *) NULL);
264
                return TCL_ERROR;
265
            }
266
 
267
            if (Tcl_GetOSTypeFromObj(interp, objv[i], &rezType) != TCL_OK) {
268
                return TCL_ERROR;
269
            }
270
 
271
            if (limitSearch) {
272
                saveRef = CurResFile();
273
                UseResFile((short) resourceRef->fileRef);
274
            }
275
 
276
            SetResLoad(false);
277
 
278
            if (gotInt == true) {
279
                if (limitSearch) {
280
                    resource = Get1Resource(rezType, rsrcId);
281
                } else {
282
                    resource = GetResource(rezType, rsrcId);
283
                }
284
                err = ResError();
285
 
286
                if (err == resNotFound || resource == NULL) {
287
                    Tcl_AppendStringsToObj(resultPtr, "resource not found",
288
                        (char *) NULL);
289
                    result = TCL_ERROR;
290
                    goto deleteDone;
291
                } else if (err != noErr) {
292
                    char buffer[16];
293
 
294
                    sprintf(buffer, "%12d", err);
295
                    Tcl_AppendStringsToObj(resultPtr, "resource error #",
296
                            buffer, "occured while trying to find resource",
297
                            (char *) NULL);
298
                    result = TCL_ERROR;
299
                    goto deleteDone;
300
                }
301
            }
302
 
303
            if (resourceId != NULL) {
304
                Handle tmpResource;
305
                if (limitSearch) {
306
                    tmpResource = Get1NamedResource(rezType,
307
                            (StringPtr) resourceId);
308
                } else {
309
                    tmpResource = GetNamedResource(rezType,
310
                            (StringPtr) resourceId);
311
                }
312
                err = ResError();
313
 
314
                if (err == resNotFound || tmpResource == NULL) {
315
                    Tcl_AppendStringsToObj(resultPtr, "resource not found",
316
                        (char *) NULL);
317
                    result = TCL_ERROR;
318
                    goto deleteDone;
319
                } else if (err != noErr) {
320
                    char buffer[16];
321
 
322
                    sprintf(buffer, "%12d", err);
323
                    Tcl_AppendStringsToObj(resultPtr, "resource error #",
324
                            buffer, "occured while trying to find resource",
325
                            (char *) NULL);
326
                    result = TCL_ERROR;
327
                    goto deleteDone;
328
                }
329
 
330
                if (gotInt) {
331
                    if (resource != tmpResource) {
332
                        Tcl_AppendStringsToObj(resultPtr,
333
                                "\"-id\" and \"-name\" ",
334
                                "values do not point to the same resource",
335
                                (char *) NULL);
336
                        result = TCL_ERROR;
337
                        goto deleteDone;
338
                    }
339
                } else {
340
                    resource = tmpResource;
341
                }
342
            }
343
 
344
            resInfo = GetResAttrs(resource);
345
 
346
            if ((resInfo & resProtected) == resProtected) {
347
                Tcl_AppendStringsToObj(resultPtr, "resource ",
348
                        "cannot be deleted: it is protected.",
349
                        (char *) NULL);
350
                result = TCL_ERROR;
351
                goto deleteDone;
352
            } else if ((resInfo & resSysHeap) == resSysHeap) {
353
                Tcl_AppendStringsToObj(resultPtr, "resource",
354
                        "cannot be deleted: it is in the system heap.",
355
                        (char *) NULL);
356
                result = TCL_ERROR;
357
                goto deleteDone;
358
            }
359
 
360
            /*
361
             * Find the resource file, if it was not specified,
362
             * so we can flush the changes now.  Perhaps this is
363
             * a little paranoid, but better safe than sorry.
364
             */
365
 
366
            RemoveResource(resource);
367
 
368
            if (!limitSearch) {
369
                UpdateResFile(HomeResFile(resource));
370
            } else {
371
                UpdateResFile(resourceRef->fileRef);
372
            }
373
 
374
 
375
            deleteDone:
376
 
377
            SetResLoad(true);
378
            if (limitSearch) {
379
                 UseResFile(saveRef);
380
            }
381
            return result;
382
 
383
        case RESOURCE_FILES:
384
            if ((objc < 2) || (objc > 3)) {
385
                Tcl_SetStringObj(resultPtr,
386
                        "wrong # args: should be \"resource files \
387
?resourceId?\"", -1);
388
                return TCL_ERROR;
389
            }
390
 
391
            if (objc == 2) {
392
                stringPtr = Tcl_GetStringFromObj(resourceForkList, &length);
393
                Tcl_SetStringObj(resultPtr, stringPtr, length);
394
            } else {
395
                FCBPBRec fileRec;
396
                Handle pathHandle;
397
                short pathLength;
398
                Str255 fileName;
399
 
400
                if (strcmp(Tcl_GetStringFromObj(objv[2], NULL), "ROM Map")
401
                            == 0) {
402
                    Tcl_SetStringObj(resultPtr,"no file path for ROM Map", -1);
403
                    return TCL_ERROR;
404
                }
405
 
406
                resourceRef = GetRsrcRefFromObj(objv[2], 1, "files", resultPtr);
407
                if (resourceRef == NULL) {
408
                    return TCL_ERROR;
409
                }
410
 
411
                fileRec.ioCompletion = NULL;
412
                fileRec.ioFCBIndx = 0;
413
                fileRec.ioNamePtr = fileName;
414
                fileRec.ioVRefNum = 0;
415
                fileRec.ioRefNum = resourceRef->fileRef;
416
                err = PBGetFCBInfo(&fileRec, false);
417
                if (err != noErr) {
418
                    Tcl_SetStringObj(resultPtr,
419
                            "could not get FCB for resource file", -1);
420
                    return TCL_ERROR;
421
                }
422
 
423
                err = GetFullPath(fileRec.ioFCBVRefNum, fileRec.ioFCBParID,
424
                        fileRec.ioNamePtr, &pathLength, &pathHandle);
425
                if ( err != noErr) {
426
                    Tcl_SetStringObj(resultPtr,
427
                            "could not get file path from token", -1);
428
                    return TCL_ERROR;
429
                }
430
 
431
                HLock(pathHandle);
432
                Tcl_SetStringObj(resultPtr,*pathHandle,pathLength);
433
                HUnlock(pathHandle);
434
                DisposeHandle(pathHandle);
435
            }
436
            return TCL_OK;
437
        case RESOURCE_LIST:
438
            if (!((objc == 3) || (objc == 4))) {
439
                Tcl_WrongNumArgs(interp, 2, objv, "resourceType ?resourceRef?");
440
                return TCL_ERROR;
441
            }
442
            if (Tcl_GetOSTypeFromObj(interp, objv[2], &rezType) != TCL_OK) {
443
                return TCL_ERROR;
444
            }
445
 
446
            if (objc == 4) {
447
                resourceRef = GetRsrcRefFromObj(objv[3], 1,
448
                                "list", resultPtr);
449
                if (resourceRef == NULL) {
450
                    return TCL_ERROR;
451
                }
452
 
453
                saveRef = CurResFile();
454
                UseResFile((short) resourceRef->fileRef);
455
                limitSearch = true;
456
            }
457
 
458
            Tcl_ResetResult(interp);
459
            if (limitSearch) {
460
                count = Count1Resources(rezType);
461
            } else {
462
                count = CountResources(rezType);
463
            }
464
            SetResLoad(false);
465
            for (i = 1; i <= count; i++) {
466
                if (limitSearch) {
467
                    resource = Get1IndResource(rezType, i);
468
                } else {
469
                    resource = GetIndResource(rezType, i);
470
                }
471
                if (resource != NULL) {
472
                    GetResInfo(resource, &id, (ResType *) &rezType, theName);
473
                    if (theName[0] != 0) {
474
                        objPtr = Tcl_NewStringObj((char *) theName + 1,
475
                                theName[0]);
476
                    } else {
477
                        objPtr = Tcl_NewIntObj(id);
478
                    }
479
                    ReleaseResource(resource);
480
                    result = Tcl_ListObjAppendElement(interp, resultPtr,
481
                            objPtr);
482
                    if (result != TCL_OK) {
483
                        Tcl_DecrRefCount(objPtr);
484
                        break;
485
                    }
486
                }
487
            }
488
            SetResLoad(true);
489
 
490
            if (limitSearch) {
491
                UseResFile(saveRef);
492
            }
493
 
494
            return TCL_OK;
495
        case RESOURCE_OPEN:
496
            if (!((objc == 3) || (objc == 4))) {
497
                Tcl_WrongNumArgs(interp, 2, objv, "fileName ?permissions?");
498
                return TCL_ERROR;
499
            }
500
            stringPtr = Tcl_GetStringFromObj(objv[2], &length);
501
            nativeName = Tcl_TranslateFileName(interp, stringPtr, &buffer);
502
            if (nativeName == NULL) {
503
                return TCL_ERROR;
504
            }
505
            err = FSpLocationFromPath(strlen(nativeName), nativeName,
506
                    &fileSpec) ;
507
            Tcl_DStringFree(&buffer);
508
            if (!((err == noErr) || (err == fnfErr))) {
509
                Tcl_AppendStringsToObj(resultPtr,
510
                        "invalid path", (char *) NULL);
511
                return TCL_ERROR;
512
            }
513
 
514
            /*
515
             * Get permissions for the file.  We really only understand
516
             * read-only and shared-read-write.  If no permissions are
517
             * given we default to read only.
518
             */
519
 
520
            if (objc == 4) {
521
                stringPtr = Tcl_GetStringFromObj(objv[3], &length);
522
                mode = TclGetOpenMode(interp, stringPtr, &index);
523
                if (mode == -1) {
524
                    /* TODO: TclGetOpenMode doesn't work with Obj commands. */
525
                    return TCL_ERROR;
526
                }
527
                switch (mode & (O_RDONLY | O_WRONLY | O_RDWR)) {
528
                    case O_RDONLY:
529
                        macPermision = fsRdPerm;
530
                    break;
531
                    case O_WRONLY:
532
                    case O_RDWR:
533
                        macPermision = fsRdWrShPerm;
534
                        break;
535
                    default:
536
                        panic("Tcl_ResourceObjCmd: invalid mode value");
537
                    break;
538
                }
539
            } else {
540
                macPermision = fsRdPerm;
541
            }
542
 
543
            /*
544
             * Don't load in any of the resources in the file, this could
545
             * cause problems if you open a file that has CODE resources...
546
             */
547
 
548
            SetResLoad(false);
549
            fileRef = (long) FSpOpenResFileCompat(&fileSpec, macPermision);
550
            SetResLoad(true);
551
 
552
            if (fileRef == -1) {
553
                err = ResError();
554
                if (((err == fnfErr) || (err == eofErr)) &&
555
                        (macPermision == fsRdWrShPerm)) {
556
                    /*
557
                     * No resource fork existed for this file.  Since we are
558
                     * opening it for writing we will create the resource fork
559
                     * now.
560
                     */
561
 
562
                    HCreateResFile(fileSpec.vRefNum, fileSpec.parID,
563
                            fileSpec.name);
564
                    fileRef = (long) FSpOpenResFileCompat(&fileSpec,
565
                            macPermision);
566
                    if (fileRef == -1) {
567
                        goto openError;
568
                    }
569
                } else if (err == fnfErr) {
570
                    Tcl_AppendStringsToObj(resultPtr,
571
                        "file does not exist", (char *) NULL);
572
                    return TCL_ERROR;
573
                } else if (err == eofErr) {
574
                    Tcl_AppendStringsToObj(resultPtr,
575
                        "file does not contain resource fork", (char *) NULL);
576
                    return TCL_ERROR;
577
                } else {
578
                    openError:
579
                    Tcl_AppendStringsToObj(resultPtr,
580
                        "error opening resource file", (char *) NULL);
581
                    return TCL_ERROR;
582
                }
583
            }
584
 
585
            /*
586
             * The FspOpenResFile function does not set the ResFileAttrs.
587
             * Even if you open the file read only, the mapReadOnly
588
             * attribute is not set.  This means we can't detect writes to a
589
             * read only resource fork until the write fails, which is bogus.
590
             * So set it here...
591
             */
592
 
593
            if (macPermision == fsRdPerm) {
594
                SetResFileAttrs(fileRef, mapReadOnly);
595
            }
596
 
597
            Tcl_SetStringObj(resultPtr, "", 0);
598
            if (TclMacRegisterResourceFork(fileRef, resultPtr,
599
                    TCL_RESOURCE_CHECK_IF_OPEN) != TCL_OK) {
600
                CloseResFile(fileRef);
601
                return TCL_ERROR;
602
            }
603
 
604
            return TCL_OK;
605
        case RESOURCE_READ:
606
            if (!((objc == 4) || (objc == 5))) {
607
                Tcl_WrongNumArgs(interp, 2, objv,
608
                        "resourceType resourceId ?resourceRef?");
609
                return TCL_ERROR;
610
            }
611
 
612
            if (Tcl_GetOSTypeFromObj(interp, objv[2], &rezType) != TCL_OK) {
613
                return TCL_ERROR;
614
            }
615
 
616
            if (Tcl_GetLongFromObj((Tcl_Interp *) NULL, objv[3], &rsrcId)
617
                    != TCL_OK) {
618
                resourceId = Tcl_GetStringFromObj(objv[3], &length);
619
            }
620
 
621
            if (objc == 5) {
622
                stringPtr = Tcl_GetStringFromObj(objv[4], &length);
623
            } else {
624
                stringPtr = NULL;
625
            }
626
 
627
            resource = Tcl_MacFindResource(interp, rezType, resourceId,
628
                rsrcId, stringPtr, &releaseIt);
629
 
630
            if (resource != NULL) {
631
                size = GetResourceSizeOnDisk(resource);
632
                Tcl_SetStringObj(resultPtr, *resource, size);
633
 
634
                /*
635
                 * Don't release the resource unless WE loaded it...
636
                 */
637
 
638
                if (releaseIt) {
639
                    ReleaseResource(resource);
640
                }
641
                return TCL_OK;
642
            } else {
643
                Tcl_AppendStringsToObj(resultPtr, "could not load resource",
644
                    (char *) NULL);
645
                return TCL_ERROR;
646
            }
647
        case RESOURCE_TYPES:
648
            if (!((objc == 2) || (objc == 3))) {
649
                Tcl_WrongNumArgs(interp, 2, objv, "?resourceRef?");
650
                return TCL_ERROR;
651
            }
652
 
653
            if (objc == 3) {
654
                resourceRef = GetRsrcRefFromObj(objv[2], 1,
655
                                "get types of", resultPtr);
656
                if (resourceRef == NULL) {
657
                    return TCL_ERROR;
658
                }
659
 
660
                saveRef = CurResFile();
661
                UseResFile((short) resourceRef->fileRef);
662
                limitSearch = true;
663
            }
664
 
665
            if (limitSearch) {
666
                count = Count1Types();
667
            } else {
668
                count = CountTypes();
669
            }
670
            for (i = 1; i <= count; i++) {
671
                if (limitSearch) {
672
                    Get1IndType((ResType *) &rezType, i);
673
                } else {
674
                    GetIndType((ResType *) &rezType, i);
675
                }
676
                objPtr = Tcl_NewOSTypeObj(rezType);
677
                result = Tcl_ListObjAppendElement(interp, resultPtr, objPtr);
678
                if (result != TCL_OK) {
679
                    Tcl_DecrRefCount(objPtr);
680
                    break;
681
                }
682
            }
683
 
684
            if (limitSearch) {
685
                UseResFile(saveRef);
686
            }
687
 
688
            return result;
689
        case RESOURCE_WRITE:
690
            if ((objc < 4) || (objc > 11)) {
691
                Tcl_WrongNumArgs(interp, 2, objv,
692
                "?-id resourceId? ?-name resourceName? ?-file resourceRef?\
693
 ?-force? resourceType data");
694
                return TCL_ERROR;
695
            }
696
 
697
            i = 2;
698
            gotInt = false;
699
            resourceId = NULL;
700
            limitSearch = false;
701
            force = 0;
702
 
703
            while (i < (objc - 2)) {
704
                if (Tcl_GetIndexFromObj(interp, objv[i], writeSwitches,
705
                        "switch", 0, &index) != TCL_OK) {
706
                    return TCL_ERROR;
707
                }
708
 
709
                switch (index) {
710
                    case RESOURCE_WRITE_ID:
711
                        if (Tcl_GetLongFromObj(interp, objv[i+1], &rsrcId)
712
                                != TCL_OK) {
713
                            return TCL_ERROR;
714
                        }
715
                        gotInt = true;
716
                        i += 2;
717
                        break;
718
                    case RESOURCE_WRITE_NAME:
719
                        resourceId = Tcl_GetStringFromObj(objv[i+1], &length);
720
                        strcpy((char *) theName, resourceId);
721
                        resourceId = (char *) theName;
722
                        c2pstr(resourceId);
723
                        i += 2;
724
                        break;
725
                    case RESOURCE_WRITE_FILE:
726
                        resourceRef = GetRsrcRefFromObj(objv[i+1], 0,
727
                                        "write to", resultPtr);
728
                        if (resourceRef == NULL) {
729
                            return TCL_ERROR;
730
                        }
731
                        limitSearch = true;
732
                        i += 2;
733
                        break;
734
                    case RESOURCE_FORCE:
735
                        force = 1;
736
                        i += 1;
737
                        break;
738
                }
739
            }
740
            if (Tcl_GetOSTypeFromObj(interp, objv[i], &rezType) != TCL_OK) {
741
                return TCL_ERROR;
742
            }
743
            stringPtr = Tcl_GetStringFromObj(objv[i+1], &length);
744
 
745
            if (gotInt == false) {
746
                rsrcId = UniqueID(rezType);
747
            }
748
            if (resourceId == NULL) {
749
                resourceId = (char *) "\p";
750
            }
751
            if (limitSearch) {
752
                saveRef = CurResFile();
753
                UseResFile((short) resourceRef->fileRef);
754
            }
755
 
756
            /*
757
             * If we are adding the resource by number, then we must make sure
758
             * there is not already a resource of that number.  We are not going
759
             * load it here, since we want to detect whether we loaded it or
760
             * not.  Remember that releasing some resources in particular menu
761
             * related ones, can be fatal.
762
             */
763
 
764
            if (gotInt == true) {
765
                SetResLoad(false);
766
                resource = Get1Resource(rezType,rsrcId);
767
                SetResLoad(true);
768
            }
769
 
770
            if (resource == NULL) {
771
                /*
772
                 * We get into this branch either if there was not already a
773
                 * resource of this type & id, or the id was not specified.
774
                 */
775
 
776
                resource = NewHandle(length);
777
                if (resource == NULL) {
778
                    resource = NewHandleSys(length);
779
                    if (resource == NULL) {
780
                        panic("could not allocate memory to write resource");
781
                    }
782
                }
783
                HLock(resource);
784
                memcpy(*resource, stringPtr, length);
785
                HUnlock(resource);
786
                AddResource(resource, rezType, (short) rsrcId,
787
                    (StringPtr) resourceId);
788
                releaseIt = 1;
789
            } else {
790
                /*
791
                 * We got here because there was a resource of this type
792
                 * & ID in the file.
793
                 */
794
 
795
                if (*resource == NULL) {
796
                    releaseIt = 1;
797
                } else {
798
                    releaseIt = 0;
799
                }
800
 
801
                if (!force) {
802
                    /*
803
                     *We only overwrite extant resources
804
                     * when the -force flag has been set.
805
                     */
806
 
807
                    sprintf(errbuf,"%d", rsrcId);
808
 
809
                    Tcl_AppendStringsToObj(resultPtr, "the resource ",
810
                          errbuf, " already exists, use \"-force\"",
811
                          " to overwrite it.", (char *) NULL);
812
 
813
                    result = TCL_ERROR;
814
                    goto writeDone;
815
                } else if (GetResAttrs(resource) & resProtected) {
816
                    /*
817
                     *
818
                     * Next, check to see if it is protected...
819
                     */
820
 
821
                    sprintf(errbuf,"%d", rsrcId);
822
                    Tcl_AppendStringsToObj(resultPtr,
823
                            "could not write resource id ",
824
                            errbuf, " of type ",
825
                            Tcl_GetStringFromObj(objv[i],&length),
826
                            ", it was protected.",(char *) NULL);
827
                    result = TCL_ERROR;
828
                    goto writeDone;
829
                } else {
830
                    /*
831
                     * Be careful, the resource might already be in memory
832
                     * if something else loaded it.
833
                     */
834
 
835
                    if (*resource == 0) {
836
                        LoadResource(resource);
837
                        err = ResError();
838
                        if (err != noErr) {
839
                            sprintf(errbuf,"%d", rsrcId);
840
                            Tcl_AppendStringsToObj(resultPtr,
841
                                    "error loading resource ",
842
                                    errbuf, " of type ",
843
                                    Tcl_GetStringFromObj(objv[i],&length),
844
                                    " to overwrite it", (char *) NULL);
845
                            goto writeDone;
846
                        }
847
                    }
848
 
849
                    SetHandleSize(resource, length);
850
                    if ( MemError() != noErr ) {
851
                        panic("could not allocate memory to write resource");
852
                    }
853
 
854
                    HLock(resource);
855
                    memcpy(*resource, stringPtr, length);
856
                    HUnlock(resource);
857
 
858
                    ChangedResource(resource);
859
 
860
                    /*
861
                     * We also may have changed the name...
862
                     */
863
 
864
                    SetResInfo(resource, rsrcId, (StringPtr) resourceId);
865
                }
866
            }
867
 
868
            err = ResError();
869
            if (err != noErr) {
870
                Tcl_AppendStringsToObj(resultPtr,
871
                        "error adding resource to resource map",
872
                        (char *) NULL);
873
                result = TCL_ERROR;
874
                goto writeDone;
875
            }
876
 
877
            WriteResource(resource);
878
            err = ResError();
879
            if (err != noErr) {
880
                Tcl_AppendStringsToObj(resultPtr,
881
                        "error writing resource to disk",
882
                        (char *) NULL);
883
                result = TCL_ERROR;
884
            }
885
 
886
            writeDone:
887
 
888
            if (releaseIt) {
889
                ReleaseResource(resource);
890
                err = ResError();
891
                if (err != noErr) {
892
                    Tcl_AppendStringsToObj(resultPtr,
893
                            "error releasing resource",
894
                            (char *) NULL);
895
                    result = TCL_ERROR;
896
                }
897
            }
898
 
899
            if (limitSearch) {
900
                UseResFile(saveRef);
901
            }
902
 
903
            return result;
904
        default:
905
            panic("Tcl_GetIndexFromObject returned unrecognized option");
906
            return TCL_ERROR;   /* Should never be reached. */
907
    }
908
}
909
 
910
/*
911
 *----------------------------------------------------------------------
912
 *
913
 * Tcl_MacSourceObjCmd --
914
 *
915
 *      This procedure is invoked to process the "source" Tcl command.
916
 *      See the user documentation for details on what it does.  In
917
 *      addition, it supports sourceing from the resource fork of
918
 *      type 'TEXT'.
919
 *
920
 * Results:
921
 *      A standard Tcl result.
922
 *
923
 * Side effects:
924
 *      See the user documentation.
925
 *
926
 *----------------------------------------------------------------------
927
 */
928
 
929
int
930
Tcl_MacSourceObjCmd(
931
    ClientData dummy,                   /* Not used. */
932
    Tcl_Interp *interp,                 /* Current interpreter. */
933
    int objc,                           /* Number of arguments. */
934
    Tcl_Obj *CONST objv[])              /* Argument objects. */
935
{
936
    char *errNum = "wrong # args: ";
937
    char *errBad = "bad argument: ";
938
    char *errStr;
939
    char *fileName = NULL, *rsrcName = NULL;
940
    long rsrcID = -1;
941
    char *string;
942
    int length;
943
 
944
    if (objc < 2 || objc > 4)  {
945
        errStr = errNum;
946
        goto sourceFmtErr;
947
    }
948
 
949
    if (objc == 2)  {
950
        string = TclGetStringFromObj(objv[1], &length);
951
        return Tcl_EvalFile(interp, string);
952
    }
953
 
954
    /*
955
     * The following code supports a few older forms of this command
956
     * for backward compatability.
957
     */
958
    string = TclGetStringFromObj(objv[1], &length);
959
    if (!strcmp(string, "-rsrc") || !strcmp(string, "-rsrcname")) {
960
        rsrcName = TclGetStringFromObj(objv[2], &length);
961
    } else if (!strcmp(string, "-rsrcid")) {
962
        if (Tcl_GetLongFromObj(interp, objv[2], &rsrcID) != TCL_OK) {
963
            return TCL_ERROR;
964
        }
965
    } else {
966
        errStr = errBad;
967
        goto sourceFmtErr;
968
    }
969
 
970
    if (objc == 4) {
971
        fileName = TclGetStringFromObj(objv[3], &length);
972
    }
973
    return Tcl_MacEvalResource(interp, rsrcName, rsrcID, fileName);
974
 
975
    sourceFmtErr:
976
    Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), errStr, "should be \"",
977
                Tcl_GetStringFromObj(objv[0], (int *) NULL),
978
                " fileName\" or \"",
979
                Tcl_GetStringFromObj(objv[0], (int *) NULL),
980
                " -rsrc name ?fileName?\" or \"",
981
                Tcl_GetStringFromObj(objv[0], (int *) NULL),
982
                " -rsrcid id ?fileName?\"", (char *) NULL);
983
    return TCL_ERROR;
984
}
985
 
986
/*
987
 *----------------------------------------------------------------------
988
 *
989
 * Tcl_BeepObjCmd --
990
 *
991
 *      This procedure makes the beep sound.
992
 *
993
 * Results:
994
 *      A standard Tcl result.
995
 *
996
 * Side effects:
997
 *      Makes a beep.
998
 *
999
 *----------------------------------------------------------------------
1000
 */
1001
 
1002
int
1003
Tcl_BeepObjCmd(
1004
    ClientData dummy,                   /* Not used. */
1005
    Tcl_Interp *interp,                 /* Current interpreter. */
1006
    int objc,                           /* Number of arguments. */
1007
    Tcl_Obj *CONST objv[])              /* Argument values. */
1008
{
1009
    Tcl_Obj *resultPtr, *objPtr;
1010
    Handle sound;
1011
    Str255 sndName;
1012
    int volume = -1, length;
1013
    char * sndArg = NULL;
1014
 
1015
    resultPtr = Tcl_GetObjResult(interp);
1016
    if (objc == 1) {
1017
        SysBeep(1);
1018
        return TCL_OK;
1019
    } else if (objc == 2) {
1020
        if (!strcmp(Tcl_GetStringFromObj(objv[1], &length), "-list")) {
1021
            int count, i;
1022
            short id;
1023
            Str255 theName;
1024
            ResType rezType;
1025
 
1026
            count = CountResources('snd ');
1027
            for (i = 1; i <= count; i++) {
1028
                sound = GetIndResource('snd ', i);
1029
                if (sound != NULL) {
1030
                    GetResInfo(sound, &id, &rezType, theName);
1031
                    if (theName[0] == 0) {
1032
                        continue;
1033
                    }
1034
                    objPtr = Tcl_NewStringObj((char *) theName + 1,
1035
                            theName[0]);
1036
                    Tcl_ListObjAppendElement(interp, resultPtr, objPtr);
1037
                }
1038
            }
1039
            return TCL_OK;
1040
        } else {
1041
            sndArg = Tcl_GetStringFromObj(objv[1], &length);
1042
        }
1043
    } else if (objc == 3) {
1044
        if (!strcmp(Tcl_GetStringFromObj(objv[1], &length), "-volume")) {
1045
            Tcl_GetIntFromObj(interp, objv[2], &volume);
1046
        } else {
1047
            goto beepUsage;
1048
        }
1049
    } else if (objc == 4) {
1050
        if (!strcmp(Tcl_GetStringFromObj(objv[1], &length), "-volume")) {
1051
            Tcl_GetIntFromObj(interp, objv[2], &volume);
1052
            sndArg = Tcl_GetStringFromObj(objv[3], &length);
1053
        } else {
1054
            goto beepUsage;
1055
        }
1056
    } else {
1057
        goto beepUsage;
1058
    }
1059
 
1060
    /*
1061
     * Play the sound
1062
     */
1063
    if (sndArg == NULL) {
1064
        /*
1065
         * Set Volume for SysBeep
1066
         */
1067
 
1068
        if (volume >= 0) {
1069
            SetSoundVolume(volume, SYS_BEEP_VOLUME);
1070
        }
1071
        SysBeep(1);
1072
 
1073
        /*
1074
         * Reset Volume
1075
         */
1076
 
1077
        if (volume >= 0) {
1078
            SetSoundVolume(0, RESET_VOLUME);
1079
        }
1080
    } else {
1081
        strcpy((char *) sndName + 1, sndArg);
1082
        sndName[0] = length;
1083
        sound = GetNamedResource('snd ', sndName);
1084
        if (sound != NULL) {
1085
            /*
1086
             * Set Volume for Default Output device
1087
             */
1088
 
1089
            if (volume >= 0) {
1090
                SetSoundVolume(volume, DEFAULT_SND_VOLUME);
1091
            }
1092
 
1093
            SndPlay(NULL, (SndListHandle) sound, false);
1094
 
1095
            /*
1096
             * Reset Volume
1097
             */
1098
 
1099
            if (volume >= 0) {
1100
                SetSoundVolume(0, RESET_VOLUME);
1101
            }
1102
        } else {
1103
            Tcl_AppendStringsToObj(resultPtr, " \"", sndArg,
1104
                    "\" is not a valid sound.  (Try ",
1105
                    Tcl_GetStringFromObj(objv[0], (int *) NULL),
1106
                    " -list)", NULL);
1107
            return TCL_ERROR;
1108
        }
1109
    }
1110
 
1111
    return TCL_OK;
1112
 
1113
    beepUsage:
1114
    Tcl_WrongNumArgs(interp, 1, objv, "[-volume num] [-list | sndName]?");
1115
    return TCL_ERROR;
1116
}
1117
 
1118
/*
1119
 *-----------------------------------------------------------------------------
1120
 *
1121
 * SetSoundVolume --
1122
 *
1123
 *      Set the volume for either the SysBeep or the SndPlay call depending
1124
 *      on the value of mode (SYS_BEEP_VOLUME or DEFAULT_SND_VOLUME
1125
 *      respectively.
1126
 *
1127
 *      It also stores the last channel set, and the old value of its
1128
 *      VOLUME.  If you call SetSoundVolume with a mode of RESET_VOLUME,
1129
 *      it will undo the last setting.  The volume parameter is
1130
 *      ignored in this case.
1131
 *
1132
 * Side Effects:
1133
 *      Sets the System Volume
1134
 *
1135
 * Results:
1136
 *      None
1137
 *
1138
 *-----------------------------------------------------------------------------
1139
 */
1140
 
1141
void
1142
SetSoundVolume(
1143
    int volume,              /* This is the new volume */
1144
    enum WhichVolume mode)   /* This flag says which volume to
1145
                              * set: SysBeep, SndPlay, or instructs us
1146
                              * to reset the volume */
1147
{
1148
    static int hasSM3 = -1;
1149
    static enum WhichVolume oldMode;
1150
    static long oldVolume = -1;
1151
 
1152
    /*
1153
     * The volume setting calls only work if we have SoundManager
1154
     * 3.0 or higher.  So we check that here.
1155
     */
1156
 
1157
    if (hasSM3 == -1) {
1158
        if (GetToolboxTrapAddress(_SoundDispatch)
1159
                != GetToolboxTrapAddress(_Unimplemented)) {
1160
            NumVersion SMVers = SndSoundManagerVersion();
1161
            if (SMVers.majorRev > 2) {
1162
                hasSM3 = 1;
1163
            } else {
1164
                hasSM3 = 0;
1165
            }
1166
        } else {
1167
            /*
1168
             * If the SoundDispatch trap is not present, then
1169
             * we don't have the SoundManager at all.
1170
             */
1171
 
1172
            hasSM3 = 0;
1173
        }
1174
    }
1175
 
1176
    /*
1177
     * If we don't have Sound Manager 3.0, we can't set the sound volume.
1178
     * We will just ignore the request rather than raising an error.
1179
     */
1180
 
1181
    if (!hasSM3) {
1182
        return;
1183
    }
1184
 
1185
    switch (mode) {
1186
        case SYS_BEEP_VOLUME:
1187
            GetSysBeepVolume(&oldVolume);
1188
            SetSysBeepVolume(volume);
1189
            oldMode = SYS_BEEP_VOLUME;
1190
            break;
1191
        case DEFAULT_SND_VOLUME:
1192
            GetDefaultOutputVolume(&oldVolume);
1193
            SetDefaultOutputVolume(volume);
1194
            oldMode = DEFAULT_SND_VOLUME;
1195
            break;
1196
        case RESET_VOLUME:
1197
            /*
1198
             * If oldVolume is -1 someone has made a programming error
1199
             * and called reset before setting the volume.  This is benign
1200
             * however, so we will just exit.
1201
             */
1202
 
1203
            if (oldVolume != -1) {
1204
                if (oldMode == SYS_BEEP_VOLUME) {
1205
                    SetSysBeepVolume(oldVolume);
1206
                } else if (oldMode == DEFAULT_SND_VOLUME) {
1207
                    SetDefaultOutputVolume(oldVolume);
1208
                }
1209
            }
1210
            oldVolume = -1;
1211
    }
1212
}
1213
 
1214
/*
1215
 *-----------------------------------------------------------------------------
1216
 *
1217
 * Tcl_MacEvalResource --
1218
 *
1219
 *      Used to extend the source command.  Sources Tcl code from a Text
1220
 *      resource.  Currently only sources the resouce by name file ID may be
1221
 *      supported at a later date.
1222
 *
1223
 * Side Effects:
1224
 *      Depends on the Tcl code in the resource.
1225
 *
1226
 * Results:
1227
 *      Returns a Tcl result.
1228
 *
1229
 *-----------------------------------------------------------------------------
1230
 */
1231
 
1232
int
1233
Tcl_MacEvalResource(
1234
    Tcl_Interp *interp,         /* Interpreter in which to process file. */
1235
    char *resourceName,         /* Name of TEXT resource to source,
1236
                                   NULL if number should be used. */
1237
    int resourceNumber,         /* Resource id of source. */
1238
    char *fileName)             /* Name of file to process.
1239
                                   NULL if application resource. */
1240
{
1241
    Handle sourceText;
1242
    Str255 rezName;
1243
    char msg[200];
1244
    int result, iOpenedResFile = false;
1245
    short saveRef, fileRef = -1;
1246
    char idStr[64];
1247
    FSSpec fileSpec;
1248
    Tcl_DString buffer;
1249
    char *nativeName;
1250
 
1251
    saveRef = CurResFile();
1252
 
1253
    if (fileName != NULL) {
1254
        OSErr err;
1255
 
1256
        nativeName = Tcl_TranslateFileName(interp, fileName, &buffer);
1257
        if (nativeName == NULL) {
1258
            return TCL_ERROR;
1259
        }
1260
        err = FSpLocationFromPath(strlen(nativeName), nativeName,
1261
                &fileSpec);
1262
        Tcl_DStringFree(&buffer);
1263
        if (err != noErr) {
1264
            Tcl_AppendResult(interp, "Error finding the file: \"",
1265
                fileName, "\".", NULL);
1266
            return TCL_ERROR;
1267
        }
1268
 
1269
        fileRef = FSpOpenResFileCompat(&fileSpec, fsRdPerm);
1270
        if (fileRef == -1) {
1271
            Tcl_AppendResult(interp, "Error reading the file: \"",
1272
                fileName, "\".", NULL);
1273
            return TCL_ERROR;
1274
        }
1275
 
1276
        UseResFile(fileRef);
1277
        iOpenedResFile = true;
1278
    } else {
1279
        /*
1280
         * The default behavior will search through all open resource files.
1281
         * This may not be the behavior you desire.  If you want the behavior
1282
         * of this call to *only* search the application resource fork, you
1283
         * must call UseResFile at this point to set it to the application
1284
         * file.  This means you must have already obtained the application's
1285
         * fileRef when the application started up.
1286
         */
1287
    }
1288
 
1289
    /*
1290
     * Load the resource by name or ID
1291
     */
1292
    if (resourceName != NULL) {
1293
        strcpy((char *) rezName + 1, resourceName);
1294
        rezName[0] = strlen(resourceName);
1295
        sourceText = GetNamedResource('TEXT', rezName);
1296
    } else {
1297
        sourceText = GetResource('TEXT', (short) resourceNumber);
1298
    }
1299
 
1300
    if (sourceText == NULL) {
1301
        result = TCL_ERROR;
1302
    } else {
1303
        char *sourceStr = NULL;
1304
 
1305
        HLock(sourceText);
1306
        sourceStr = Tcl_MacConvertTextResource(sourceText);
1307
        HUnlock(sourceText);
1308
        ReleaseResource(sourceText);
1309
 
1310
        /*
1311
         * We now evaluate the Tcl source
1312
         */
1313
        result = Tcl_Eval(interp, sourceStr);
1314
        ckfree(sourceStr);
1315
        if (result == TCL_RETURN) {
1316
            result = TCL_OK;
1317
        } else if (result == TCL_ERROR) {
1318
            sprintf(msg, "\n    (rsrc \"%.150s\" line %d)",
1319
                    resourceName,
1320
                    interp->errorLine);
1321
            Tcl_AddErrorInfo(interp, msg);
1322
        }
1323
 
1324
        goto rezEvalCleanUp;
1325
    }
1326
 
1327
    rezEvalError:
1328
    sprintf(idStr, "ID=%d", resourceNumber);
1329
    Tcl_AppendResult(interp, "The resource \"",
1330
            (resourceName != NULL ? resourceName : idStr),
1331
            "\" could not be loaded from ",
1332
            (fileName != NULL ? fileName : "application"),
1333
            ".", NULL);
1334
 
1335
    rezEvalCleanUp:
1336
 
1337
    /*
1338
     * TRICKY POINT: The code that you are sourcing here could load a
1339
     * shared library.  This will go AHEAD of the resource we stored away
1340
     * in saveRef on the resource path.
1341
     * If you restore the saveRef in this case, you will never be able
1342
     * to get to the resources in the shared library, since you are now
1343
     * pointing too far down on the resource list.
1344
     * So, we only reset the current resource file if WE opened a resource
1345
     * explicitly, and then only if the CurResFile is still the
1346
     * one we opened...
1347
     */
1348
 
1349
    if (iOpenedResFile && (CurResFile() == fileRef)) {
1350
        UseResFile(saveRef);
1351
    }
1352
 
1353
    if (fileRef != -1) {
1354
        CloseResFile(fileRef);
1355
    }
1356
 
1357
    return result;
1358
}
1359
 
1360
/*
1361
 *-----------------------------------------------------------------------------
1362
 *
1363
 * Tcl_MacConvertTextResource --
1364
 *
1365
 *      Converts a TEXT resource into a Tcl suitable string.
1366
 *
1367
 * Side Effects:
1368
 *      Mallocs the returned memory, converts '\r' to '\n', and appends a NULL.
1369
 *
1370
 * Results:
1371
 *      A new malloced string.
1372
 *
1373
 *-----------------------------------------------------------------------------
1374
 */
1375
 
1376
char *
1377
Tcl_MacConvertTextResource(
1378
    Handle resource)            /* Handle to TEXT resource. */
1379
{
1380
    int i, size;
1381
    char *resultStr;
1382
 
1383
    size = GetResourceSizeOnDisk(resource);
1384
 
1385
    resultStr = ckalloc(size + 1);
1386
 
1387
    for (i=0; i<size; i++) {
1388
        if ((*resource)[i] == '\r') {
1389
            resultStr[i] = '\n';
1390
        } else {
1391
            resultStr[i] = (*resource)[i];
1392
        }
1393
    }
1394
 
1395
    resultStr[size] = '\0';
1396
 
1397
    return resultStr;
1398
}
1399
 
1400
/*
1401
 *-----------------------------------------------------------------------------
1402
 *
1403
 * Tcl_MacFindResource --
1404
 *
1405
 *      Higher level interface for loading resources.
1406
 *
1407
 * Side Effects:
1408
 *      Attempts to load a resource.
1409
 *
1410
 * Results:
1411
 *      A handle on success.
1412
 *
1413
 *-----------------------------------------------------------------------------
1414
 */
1415
 
1416
Handle
1417
Tcl_MacFindResource(
1418
    Tcl_Interp *interp,         /* Interpreter in which to process file. */
1419
    long resourceType,          /* Type of resource to load. */
1420
    char *resourceName,         /* Name of resource to find,
1421
                                 * NULL if number should be used. */
1422
    int resourceNumber,         /* Resource id of source. */
1423
    char *resFileRef,           /* Registered resource file reference,
1424
                                 * NULL if searching all open resource files. */
1425
    int *releaseIt)             /* Should we release this resource when done. */
1426
{
1427
    Tcl_HashEntry *nameHashPtr;
1428
    OpenResourceFork *resourceRef;
1429
    int limitSearch = false;
1430
    short saveRef;
1431
    Handle resource;
1432
 
1433
    if (resFileRef != NULL) {
1434
        nameHashPtr = Tcl_FindHashEntry(&nameTable, resFileRef);
1435
        if (nameHashPtr == NULL) {
1436
            Tcl_AppendResult(interp, "invalid resource file reference \"",
1437
                             resFileRef, "\"", (char *) NULL);
1438
            return NULL;
1439
        }
1440
        resourceRef = (OpenResourceFork *) Tcl_GetHashValue(nameHashPtr);
1441
        saveRef = CurResFile();
1442
        UseResFile((short) resourceRef->fileRef);
1443
        limitSearch = true;
1444
    }
1445
 
1446
    /*
1447
     * Some system resources (for example system resources) should not
1448
     * be released.  So we set autoload to false, and try to get the resource.
1449
     * If the Master Pointer of the returned handle is null, then resource was
1450
     * not in memory, and it is safe to release it.  Otherwise, it is not.
1451
     */
1452
 
1453
    SetResLoad(false);
1454
 
1455
    if (resourceName == NULL) {
1456
        if (limitSearch) {
1457
            resource = Get1Resource(resourceType, resourceNumber);
1458
        } else {
1459
            resource = GetResource(resourceType, resourceNumber);
1460
        }
1461
    } else {
1462
        c2pstr(resourceName);
1463
        if (limitSearch) {
1464
            resource = Get1NamedResource(resourceType,
1465
                    (StringPtr) resourceName);
1466
        } else {
1467
            resource = GetNamedResource(resourceType,
1468
                    (StringPtr) resourceName);
1469
        }
1470
        p2cstr((StringPtr) resourceName);
1471
    }
1472
 
1473
    if (*resource == NULL) {
1474
        *releaseIt = 1;
1475
        LoadResource(resource);
1476
    } else {
1477
        *releaseIt = 0;
1478
    }
1479
 
1480
    SetResLoad(true);
1481
 
1482
 
1483
    if (limitSearch) {
1484
        UseResFile(saveRef);
1485
    }
1486
 
1487
    return resource;
1488
}
1489
 
1490
/*
1491
 *----------------------------------------------------------------------
1492
 *
1493
 * ResourceInit --
1494
 *
1495
 *      Initialize the structures used for resource management.
1496
 *
1497
 * Results:
1498
 *      None.
1499
 *
1500
 * Side effects:
1501
 *      Read the code.
1502
 *
1503
 *----------------------------------------------------------------------
1504
 */
1505
 
1506
static void
1507
ResourceInit()
1508
{
1509
 
1510
    initialized = 1;
1511
    Tcl_InitHashTable(&nameTable, TCL_STRING_KEYS);
1512
    Tcl_InitHashTable(&resourceTable, TCL_ONE_WORD_KEYS);
1513
    resourceForkList = Tcl_NewObj();
1514
    Tcl_IncrRefCount(resourceForkList);
1515
 
1516
    BuildResourceForkList();
1517
 
1518
}
1519
/***/
1520
 
1521
/*Tcl_RegisterObjType(typePtr) */
1522
 
1523
/*
1524
 *----------------------------------------------------------------------
1525
 *
1526
 * Tcl_NewOSTypeObj --
1527
 *
1528
 *      This procedure is used to create a new resource name type object.
1529
 *
1530
 * Results:
1531
 *      The newly created object is returned. This object will have a NULL
1532
 *      string representation. The returned object has ref count 0.
1533
 *
1534
 * Side effects:
1535
 *      None.
1536
 *
1537
 *----------------------------------------------------------------------
1538
 */
1539
 
1540
Tcl_Obj *
1541
Tcl_NewOSTypeObj(
1542
    OSType newOSType)           /* Int used to initialize the new object. */
1543
{
1544
    register Tcl_Obj *objPtr;
1545
 
1546
    if (!osTypeInit) {
1547
        osTypeInit = 1;
1548
        Tcl_RegisterObjType(&osType);
1549
    }
1550
 
1551
    objPtr = Tcl_NewObj();
1552
    objPtr->bytes = NULL;
1553
    objPtr->internalRep.longValue = newOSType;
1554
    objPtr->typePtr = &osType;
1555
    return objPtr;
1556
}
1557
 
1558
/*
1559
 *----------------------------------------------------------------------
1560
 *
1561
 * Tcl_SetOSTypeObj --
1562
 *
1563
 *      Modify an object to be a resource type and to have the
1564
 *      specified long value.
1565
 *
1566
 * Results:
1567
 *      None.
1568
 *
1569
 * Side effects:
1570
 *      The object's old string rep, if any, is freed. Also, any old
1571
 *      internal rep is freed.
1572
 *
1573
 *----------------------------------------------------------------------
1574
 */
1575
 
1576
void
1577
Tcl_SetOSTypeObj(
1578
    Tcl_Obj *objPtr,            /* Object whose internal rep to init. */
1579
    OSType newOSType)           /* Integer used to set object's value. */
1580
{
1581
    register Tcl_ObjType *oldTypePtr = objPtr->typePtr;
1582
 
1583
    if (!osTypeInit) {
1584
        osTypeInit = 1;
1585
        Tcl_RegisterObjType(&osType);
1586
    }
1587
 
1588
    Tcl_InvalidateStringRep(objPtr);
1589
    if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) {
1590
        oldTypePtr->freeIntRepProc(objPtr);
1591
    }
1592
 
1593
    objPtr->internalRep.longValue = newOSType;
1594
    objPtr->typePtr = &osType;
1595
}
1596
 
1597
/*
1598
 *----------------------------------------------------------------------
1599
 *
1600
 * Tcl_GetOSTypeFromObj --
1601
 *
1602
 *      Attempt to return an int from the Tcl object "objPtr". If the object
1603
 *      is not already an int, an attempt will be made to convert it to one.
1604
 *
1605
 * Results:
1606
 *      The return value is a standard Tcl object result. If an error occurs
1607
 *      during conversion, an error message is left in interp->objResult
1608
 *      unless "interp" is NULL.
1609
 *
1610
 * Side effects:
1611
 *      If the object is not already an int, the conversion will free
1612
 *      any old internal representation.
1613
 *
1614
 *----------------------------------------------------------------------
1615
 */
1616
 
1617
int
1618
Tcl_GetOSTypeFromObj(
1619
    Tcl_Interp *interp,         /* Used for error reporting if not NULL. */
1620
    Tcl_Obj *objPtr,            /* The object from which to get a int. */
1621
    OSType *osTypePtr)          /* Place to store resulting int. */
1622
{
1623
    register int result;
1624
 
1625
    if (!osTypeInit) {
1626
        osTypeInit = 1;
1627
        Tcl_RegisterObjType(&osType);
1628
    }
1629
 
1630
    if (objPtr->typePtr == &osType) {
1631
        *osTypePtr = objPtr->internalRep.longValue;
1632
        return TCL_OK;
1633
    }
1634
 
1635
    result = SetOSTypeFromAny(interp, objPtr);
1636
    if (result == TCL_OK) {
1637
        *osTypePtr = objPtr->internalRep.longValue;
1638
    }
1639
    return result;
1640
}
1641
 
1642
/*
1643
 *----------------------------------------------------------------------
1644
 *
1645
 * DupOSTypeInternalRep --
1646
 *
1647
 *      Initialize the internal representation of an int Tcl_Obj to a
1648
 *      copy of the internal representation of an existing int object.
1649
 *
1650
 * Results:
1651
 *      None.
1652
 *
1653
 * Side effects:
1654
 *      "copyPtr"s internal rep is set to the integer corresponding to
1655
 *      "srcPtr"s internal rep.
1656
 *
1657
 *----------------------------------------------------------------------
1658
 */
1659
 
1660
static void
1661
DupOSTypeInternalRep(
1662
    Tcl_Obj *srcPtr,    /* Object with internal rep to copy. */
1663
    Tcl_Obj *copyPtr)   /* Object with internal rep to set. */
1664
{
1665
    copyPtr->internalRep.longValue = srcPtr->internalRep.longValue;
1666
    copyPtr->typePtr = &osType;
1667
}
1668
 
1669
/*
1670
 *----------------------------------------------------------------------
1671
 *
1672
 * SetOSTypeFromAny --
1673
 *
1674
 *      Attempt to generate an integer internal form for the Tcl object
1675
 *      "objPtr".
1676
 *
1677
 * Results:
1678
 *      The return value is a standard object Tcl result. If an error occurs
1679
 *      during conversion, an error message is left in interp->objResult
1680
 *      unless "interp" is NULL.
1681
 *
1682
 * Side effects:
1683
 *      If no error occurs, an int is stored as "objPtr"s internal
1684
 *      representation.
1685
 *
1686
 *----------------------------------------------------------------------
1687
 */
1688
 
1689
static int
1690
SetOSTypeFromAny(
1691
    Tcl_Interp *interp,         /* Used for error reporting if not NULL. */
1692
    Tcl_Obj *objPtr)            /* The object to convert. */
1693
{
1694
    Tcl_ObjType *oldTypePtr = objPtr->typePtr;
1695
    char *string;
1696
    int length;
1697
    long newOSType;
1698
 
1699
    /*
1700
     * Get the string representation. Make it up-to-date if necessary.
1701
     */
1702
 
1703
    string = TclGetStringFromObj(objPtr, &length);
1704
 
1705
    if (length != 4) {
1706
        if (interp != NULL) {
1707
            Tcl_ResetResult(interp);
1708
            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1709
                    "expected Macintosh OS type but got \"", string, "\"",
1710
                    (char *) NULL);
1711
        }
1712
        return TCL_ERROR;
1713
    }
1714
    newOSType =  *((long *) string);
1715
 
1716
    /*
1717
     * The conversion to resource type succeeded. Free the old internalRep
1718
     * before setting the new one.
1719
     */
1720
 
1721
    if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) {
1722
        oldTypePtr->freeIntRepProc(objPtr);
1723
    }
1724
 
1725
    objPtr->internalRep.longValue = newOSType;
1726
    objPtr->typePtr = &osType;
1727
    return TCL_OK;
1728
}
1729
 
1730
/*
1731
 *----------------------------------------------------------------------
1732
 *
1733
 * UpdateStringOfOSType --
1734
 *
1735
 *      Update the string representation for an resource type object.
1736
 *      Note: This procedure does not free an existing old string rep
1737
 *      so storage will be lost if this has not already been done.
1738
 *
1739
 * Results:
1740
 *      None.
1741
 *
1742
 * Side effects:
1743
 *      The object's string is set to a valid string that results from
1744
 *      the int-to-string conversion.
1745
 *
1746
 *----------------------------------------------------------------------
1747
 */
1748
 
1749
static void
1750
UpdateStringOfOSType(
1751
    register Tcl_Obj *objPtr)   /* Int object whose string rep to update. */
1752
{
1753
    objPtr->bytes = ckalloc(5);
1754
    sprintf(objPtr->bytes, "%-4.4s", &(objPtr->internalRep.longValue));
1755
    objPtr->length = 4;
1756
}
1757
 
1758
/*
1759
 *----------------------------------------------------------------------
1760
 *
1761
 * GetRsrcRefFromObj --
1762
 *
1763
 *      Given a String object containing a resource file token, return
1764
 *      the OpenResourceFork structure that it represents, or NULL if
1765
 *      the token cannot be found.  If okayOnReadOnly is false, it will
1766
 *      also check whether the token corresponds to a read-only file,
1767
 *      and return NULL if it is.
1768
 *
1769
 * Results:
1770
 *      A pointer to an OpenResourceFork structure, or NULL.
1771
 *
1772
 * Side effects:
1773
 *      An error message may be left in resultPtr.
1774
 *
1775
 *----------------------------------------------------------------------
1776
 */
1777
 
1778
static OpenResourceFork *
1779
GetRsrcRefFromObj(
1780
    register Tcl_Obj *objPtr,   /* String obj containing file token     */
1781
    int okayOnReadOnly,         /* Whether this operation is okay for a *
1782
                                 * read only file.                      */
1783
    const char *operation,      /* String containing the operation we   *
1784
                                 * were trying to perform, used for errors */
1785
    Tcl_Obj *resultPtr)         /* Tcl_Obj to contain error message     */
1786
{
1787
    char *stringPtr;
1788
    Tcl_HashEntry *nameHashPtr;
1789
    OpenResourceFork *resourceRef;
1790
    int length;
1791
    OSErr err;
1792
 
1793
    stringPtr = Tcl_GetStringFromObj(objPtr, &length);
1794
    nameHashPtr = Tcl_FindHashEntry(&nameTable, stringPtr);
1795
    if (nameHashPtr == NULL) {
1796
        Tcl_AppendStringsToObj(resultPtr,
1797
                "invalid resource file reference \"",
1798
                stringPtr, "\"", (char *) NULL);
1799
        return NULL;
1800
    }
1801
 
1802
    resourceRef = (OpenResourceFork *) Tcl_GetHashValue(nameHashPtr);
1803
 
1804
    if (!okayOnReadOnly) {
1805
        err = GetResFileAttrs((short) resourceRef->fileRef);
1806
        if (err & mapReadOnly) {
1807
            Tcl_AppendStringsToObj(resultPtr, "cannot ", operation,
1808
                    " resource file \"",
1809
                    stringPtr, "\", it was opened read only",
1810
                    (char *) NULL);
1811
            return NULL;
1812
        }
1813
    }
1814
    return resourceRef;
1815
}
1816
 
1817
/*
1818
 *----------------------------------------------------------------------
1819
 *
1820
 * TclMacRegisterResourceFork --
1821
 *
1822
 *      Register an open resource fork in the table of open resources
1823
 *      managed by the procedures in this file.  If the resource file
1824
 *      is already registered with the table, then no new token is made.
1825
 *
1826
 *      The behavior is controlled by the value of tokenPtr, and of the
1827
 *      flags variable.  For tokenPtr, the possibilities are:
1828
 *        - NULL: The new token is auto-generated, but not returned.
1829
 *        - The string value of tokenPtr is the empty string: Then
1830
 *              the new token is auto-generated, and returned in tokenPtr
1831
 *        - tokenPtr has a value: The string value will be used for the token,
1832
 *              unless it is already in use, in which case a new token will
1833
 *              be generated, and returned in tokenPtr.
1834
 *
1835
 *      For the flags variable:  it can be one of:
1836
 *        - TCL_RESOURCE__INSERT_TAIL: The element is inserted at the
1837
 *              end of the list of open resources.  Used only in Resource_Init.
1838
 *        - TCL_RESOURCE_DONT_CLOSE: The resource close command will not close
1839
 *              this resource.
1840
 *        - TCL_RESOURCE_CHECK_IF_OPEN: This will check to see if this file's
1841
 *              resource fork is already opened by this Tcl shell, and return
1842
 *              an error without registering the resource fork.
1843
 *
1844
 * Results:
1845
 *      Standard Tcl Result
1846
 *
1847
 * Side effects:
1848
 *      An entry may be added to the resource name table.
1849
 *
1850
 *----------------------------------------------------------------------
1851
 */
1852
 
1853
int
1854
TclMacRegisterResourceFork(
1855
    short fileRef,              /* File ref for an open resource fork. */
1856
    Tcl_Obj *tokenPtr,          /* A Tcl Object to which to write the  *
1857
                                 * new token */
1858
    int flags)                  /* 1 means insert at the head of the resource
1859
                                 * fork list, 0 means at the tail */
1860
 
1861
{
1862
    Tcl_HashEntry *resourceHashPtr;
1863
    Tcl_HashEntry *nameHashPtr;
1864
    OpenResourceFork *resourceRef;
1865
    int new;
1866
    char *resourceId = NULL;
1867
 
1868
    if (!initialized) {
1869
        ResourceInit();
1870
    }
1871
 
1872
    /*
1873
     * If we were asked to, check that this file has not been opened
1874
     * already with a different permission.  It it has, then return an error.
1875
     */
1876
 
1877
    new = 1;
1878
 
1879
    if (flags & TCL_RESOURCE_CHECK_IF_OPEN) {
1880
        Tcl_HashSearch search;
1881
        short oldFileRef, filePermissionFlag;
1882
        FCBPBRec newFileRec, oldFileRec;
1883
        OSErr err;
1884
 
1885
        oldFileRec.ioCompletion = NULL;
1886
        oldFileRec.ioFCBIndx = 0;
1887
        oldFileRec.ioNamePtr = NULL;
1888
 
1889
        newFileRec.ioCompletion = NULL;
1890
        newFileRec.ioFCBIndx = 0;
1891
        newFileRec.ioNamePtr = NULL;
1892
        newFileRec.ioVRefNum = 0;
1893
        newFileRec.ioRefNum = fileRef;
1894
        err = PBGetFCBInfo(&newFileRec, false);
1895
        filePermissionFlag = ( newFileRec.ioFCBFlags >> 12 ) & 0x1;
1896
 
1897
 
1898
        resourceHashPtr = Tcl_FirstHashEntry(&resourceTable, &search);
1899
        while (resourceHashPtr != NULL) {
1900
            oldFileRef = (short) Tcl_GetHashKey(&resourceTable,
1901
                    resourceHashPtr);
1902
            if (oldFileRef == fileRef) {
1903
                new = 0;
1904
                break;
1905
            }
1906
            oldFileRec.ioVRefNum = 0;
1907
            oldFileRec.ioRefNum = oldFileRef;
1908
            err = PBGetFCBInfo(&oldFileRec, false);
1909
 
1910
            /*
1911
             * err might not be noErr either because the file has closed
1912
             * out from under us somehow, which is bad but we're not going
1913
             * to fix it here, OR because it is the ROM MAP, which has a
1914
             * fileRef, but can't be gotten to by PBGetFCBInfo.
1915
             */
1916
 
1917
            if ((err == noErr)
1918
                    && (newFileRec.ioFCBVRefNum == oldFileRec.ioFCBVRefNum)
1919
                    && (newFileRec.ioFCBFlNm == oldFileRec.ioFCBFlNm)) {
1920
                /* In MacOS 8.1 it seems like we get different file refs even though
1921
                 * we pass the same file & permissions.  This is not what Inside Mac
1922
                 * says should happen, but it does, so if it does, then close the new res
1923
                 * file and return the original one...
1924
                 */
1925
 
1926
                if (filePermissionFlag == ((oldFileRec.ioFCBFlags >> 12) & 0x1)) {
1927
                    CloseResFile(fileRef);
1928
                    new = 0;
1929
                    break;
1930
                } else {
1931
                    if (tokenPtr != NULL) {
1932
                        Tcl_SetStringObj(tokenPtr,
1933
                                 "Resource already open with different permissions.", -1);
1934
                    }
1935
                    return TCL_ERROR;
1936
                }
1937
            }
1938
            resourceHashPtr = Tcl_NextHashEntry(&search);
1939
        }
1940
    }
1941
 
1942
 
1943
    /*
1944
     * If the file has already been opened with these same permissions, then it
1945
     * will be in our list and we will have set new to 0 above.
1946
     * So we will just return the token (if tokenPtr is non-null)
1947
     */
1948
 
1949
    if (new) {
1950
        resourceHashPtr = Tcl_CreateHashEntry(&resourceTable,
1951
                (char *) fileRef, &new);
1952
    }
1953
 
1954
    if (!new) {
1955
        if (tokenPtr != NULL) {
1956
            resourceId = (char *) Tcl_GetHashValue(resourceHashPtr);
1957
            Tcl_SetStringObj(tokenPtr, resourceId, -1);
1958
        }
1959
        return TCL_OK;
1960
    }
1961
 
1962
    /*
1963
     * If we were passed in a result pointer which is not an empty
1964
     * string, attempt to use that as the key.  If the key already
1965
     * exists, silently fall back on resource%d...
1966
     */
1967
 
1968
    if (tokenPtr != NULL) {
1969
        char *tokenVal;
1970
        int length;
1971
        tokenVal = (char *) Tcl_GetStringFromObj(tokenPtr, &length);
1972
        if (length > 0) {
1973
            nameHashPtr = Tcl_FindHashEntry(&nameTable, tokenVal);
1974
            if (nameHashPtr == NULL) {
1975
                resourceId = ckalloc(length + 1);
1976
                memcpy(resourceId, tokenVal, length);
1977
                resourceId[length] = '\0';
1978
            }
1979
        }
1980
    }
1981
 
1982
    if (resourceId == NULL) {
1983
        resourceId = (char *) ckalloc(15);
1984
        sprintf(resourceId, "resource%d", newId);
1985
    }
1986
 
1987
    Tcl_SetHashValue(resourceHashPtr, resourceId);
1988
    newId++;
1989
 
1990
    nameHashPtr = Tcl_CreateHashEntry(&nameTable, resourceId, &new);
1991
    if (!new) {
1992
        panic("resource id has repeated itself");
1993
    }
1994
 
1995
    resourceRef = (OpenResourceFork *) ckalloc(sizeof(OpenResourceFork));
1996
    resourceRef->fileRef = fileRef;
1997
    resourceRef->flags = flags;
1998
 
1999
    Tcl_SetHashValue(nameHashPtr, (ClientData) resourceRef);
2000
    if (tokenPtr != NULL) {
2001
        Tcl_SetStringObj(tokenPtr, resourceId, -1);
2002
    }
2003
 
2004
    if (flags & TCL_RESOURCE_INSERT_TAIL) {
2005
        Tcl_ListObjAppendElement(NULL, resourceForkList, tokenPtr);
2006
    } else {
2007
        Tcl_ListObjReplace(NULL, resourceForkList, 0, 0, 1, &tokenPtr);
2008
    }
2009
    return TCL_OK;
2010
}
2011
 
2012
/*
2013
 *----------------------------------------------------------------------
2014
 *
2015
 * TclMacUnRegisterResourceFork --
2016
 *
2017
 *      Removes the entry for an open resource fork from the table of
2018
 *      open resources managed by the procedures in this file.
2019
 *      If resultPtr is not NULL, it will be used for error reporting.
2020
 *
2021
 * Results:
2022
 *      The fileRef for this token, or -1 if an error occured.
2023
 *
2024
 * Side effects:
2025
 *      An entry is removed from the resource name table.
2026
 *
2027
 *----------------------------------------------------------------------
2028
 */
2029
 
2030
short
2031
TclMacUnRegisterResourceFork(
2032
    char *tokenPtr,
2033
    Tcl_Obj *resultPtr)
2034
 
2035
{
2036
    Tcl_HashEntry *resourceHashPtr;
2037
    Tcl_HashEntry *nameHashPtr;
2038
    OpenResourceFork *resourceRef;
2039
    char *resourceId = NULL;
2040
    short fileRef;
2041
    char *bytes;
2042
    int i, match, index, listLen, length, elemLen;
2043
    Tcl_Obj **elemPtrs;
2044
 
2045
 
2046
    nameHashPtr = Tcl_FindHashEntry(&nameTable, tokenPtr);
2047
    if (nameHashPtr == NULL) {
2048
        if (resultPtr != NULL) {
2049
            Tcl_AppendStringsToObj(resultPtr,
2050
                    "invalid resource file reference \"",
2051
                    tokenPtr, "\"", (char *) NULL);
2052
        }
2053
        return -1;
2054
    }
2055
 
2056
    resourceRef = (OpenResourceFork *) Tcl_GetHashValue(nameHashPtr);
2057
    fileRef = resourceRef->fileRef;
2058
 
2059
    if ( resourceRef->flags & TCL_RESOURCE_DONT_CLOSE ) {
2060
        if (resultPtr != NULL) {
2061
            Tcl_AppendStringsToObj(resultPtr,
2062
                    "can't close \"", tokenPtr, "\" resource file",
2063
                    (char *) NULL);
2064
        }
2065
        return -1;
2066
    }
2067
 
2068
    Tcl_DeleteHashEntry(nameHashPtr);
2069
    ckfree((char *) resourceRef);
2070
 
2071
 
2072
    /*
2073
     * Now remove the resource from the resourceForkList object
2074
     */
2075
 
2076
    Tcl_ListObjGetElements(NULL, resourceForkList, &listLen, &elemPtrs);
2077
 
2078
 
2079
    index = -1;
2080
    length = strlen(tokenPtr);
2081
 
2082
    for (i = 0; i < listLen; i++) {
2083
        match = 0;
2084
        bytes = Tcl_GetStringFromObj(elemPtrs[i], &elemLen);
2085
        if (length == elemLen) {
2086
                match = (memcmp(bytes, tokenPtr,
2087
                        (size_t) length) == 0);
2088
        }
2089
        if (match) {
2090
            index = i;
2091
            break;
2092
        }
2093
    }
2094
    if (!match) {
2095
        panic("the resource Fork List is out of synch!");
2096
    }
2097
 
2098
    Tcl_ListObjReplace(NULL, resourceForkList, index, 1, 0, NULL);
2099
 
2100
    resourceHashPtr = Tcl_FindHashEntry(&resourceTable, (char *) fileRef);
2101
 
2102
    if (resourceHashPtr == NULL) {
2103
        panic("Resource & Name tables are out of synch in resource command.");
2104
    }
2105
    ckfree(Tcl_GetHashValue(resourceHashPtr));
2106
    Tcl_DeleteHashEntry(resourceHashPtr);
2107
 
2108
    return fileRef;
2109
 
2110
}
2111
 
2112
 
2113
/*
2114
 *----------------------------------------------------------------------
2115
 *
2116
 * BuildResourceForkList --
2117
 *
2118
 *      Traverses the list of open resource forks, and builds the
2119
 *      list of resources forks.  Also creates a resource token for any that
2120
 *      are opened but not registered with our resource system.
2121
 *      This is based on code from Apple DTS.
2122
 *
2123
 * Results:
2124
 *      None.
2125
 *
2126
 * Side effects:
2127
 *      The list of resource forks is updated.
2128
 *      The resource name table may be augmented.
2129
 *
2130
 *----------------------------------------------------------------------
2131
 */
2132
 
2133
void
2134
BuildResourceForkList()
2135
{
2136
    Handle currentMapHandle, mSysMapHandle;
2137
    Ptr tempPtr;
2138
    FCBPBRec fileRec;
2139
    char fileName[256];
2140
    char appName[62];
2141
    Tcl_Obj *nameObj;
2142
    OSErr err;
2143
    ProcessSerialNumber psn;
2144
    ProcessInfoRec info;
2145
    FSSpec fileSpec;
2146
 
2147
    /*
2148
     * Get the application name, so we can substitute
2149
     * the token "application" for the application's resource.
2150
     */
2151
 
2152
    GetCurrentProcess(&psn);
2153
    info.processInfoLength = sizeof(ProcessInfoRec);
2154
    info.processName = (StringPtr) &appName;
2155
    info.processAppSpec = &fileSpec;
2156
    GetProcessInformation(&psn, &info);
2157
    p2cstr((StringPtr) appName);
2158
 
2159
 
2160
    fileRec.ioCompletion = NULL;
2161
    fileRec.ioVRefNum = 0;
2162
    fileRec.ioFCBIndx = 0;
2163
    fileRec.ioNamePtr = (StringPtr) &fileName;
2164
 
2165
 
2166
    currentMapHandle = LMGetTopMapHndl();
2167
    mSysMapHandle = LMGetSysMapHndl();
2168
 
2169
    while (1) {
2170
        /*
2171
         * Now do the ones opened after the application.
2172
         */
2173
 
2174
        nameObj = Tcl_NewObj();
2175
 
2176
        tempPtr = *currentMapHandle;
2177
 
2178
        fileRec.ioRefNum = *((short *) (tempPtr + 20));
2179
        err = PBGetFCBInfo(&fileRec, false);
2180
 
2181
        if (err != noErr) {
2182
            /*
2183
             * The ROM resource map does not correspond to an opened file...
2184
             */
2185
             Tcl_SetStringObj(nameObj, "ROM Map", -1);
2186
        } else {
2187
            p2cstr((StringPtr) fileName);
2188
            if (strcmp(fileName,(char *) appName) == 0) {
2189
                Tcl_SetStringObj(nameObj, "application", -1);
2190
            } else {
2191
                Tcl_SetStringObj(nameObj, fileName, -1);
2192
            }
2193
            c2pstr(fileName);
2194
        }
2195
 
2196
        TclMacRegisterResourceFork(fileRec.ioRefNum, nameObj,
2197
            TCL_RESOURCE_DONT_CLOSE | TCL_RESOURCE_INSERT_TAIL);
2198
 
2199
        if (currentMapHandle == mSysMapHandle) {
2200
            break;
2201
        }
2202
 
2203
        currentMapHandle = *((Handle *) (tempPtr + 16));
2204
    }
2205
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.