sl@0: /* sl@0: * tclMacUtil.c -- sl@0: * sl@0: * This contains utility functions used to help with sl@0: * implementing Macintosh specific portions of the Tcl port. sl@0: * sl@0: * Copyright (c) 1993-1994 Lockheed Missle & Space Company, AI Center sl@0: * Copyright (c) 1995-1997 Sun Microsystems, Inc. sl@0: * sl@0: * See the file "license.terms" for information on usage and redistribution sl@0: * of this file, and for a DISCLAIMER OF ALL WARRANTIES. sl@0: * sl@0: * RCS: @(#) $Id: tclMacUtil.c,v 1.7 2003/03/03 20:22:44 das Exp $ sl@0: */ sl@0: sl@0: #include "tcl.h" sl@0: #include "tclInt.h" sl@0: #include "tclMacInt.h" sl@0: #include "tclMath.h" sl@0: #include "tclMacPort.h" sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: /* sl@0: * The following two Includes are from the More Files package. sl@0: */ sl@0: #include sl@0: #include sl@0: sl@0: /* sl@0: *---------------------------------------------------------------------- sl@0: * sl@0: * hypotd -- sl@0: * sl@0: * The standard math function hypot is not supported by Think C. sl@0: * It is included here so everything works. It is supported by sl@0: * CodeWarrior Pro 1, but the 68K version does not support doubles. sl@0: * So we hack it in. sl@0: * sl@0: * Results: sl@0: * Result of computation. sl@0: * sl@0: * Side effects: sl@0: * None. sl@0: * sl@0: *---------------------------------------------------------------------- sl@0: */ sl@0: sl@0: #if defined(THINK_C) sl@0: double hypotd(double x, double y); sl@0: sl@0: double sl@0: hypotd( sl@0: double x, /* X value */ sl@0: double y) /* Y value */ sl@0: { sl@0: double sum; sl@0: sl@0: sum = x*x + y*y; sl@0: return sqrt(sum); sl@0: } sl@0: #endif sl@0: sl@0: /* sl@0: *---------------------------------------------------------------------- sl@0: * sl@0: * FSpGetDefaultDir -- sl@0: * sl@0: * This function gets the current default directory. sl@0: * sl@0: * Results: sl@0: * The provided FSSpec is changed to point to the "default" sl@0: * directory. The function returns what ever errors sl@0: * FSMakeFSSpecCompat may encounter. sl@0: * sl@0: * Side effects: sl@0: * None. sl@0: * sl@0: *---------------------------------------------------------------------- sl@0: */ sl@0: sl@0: int sl@0: FSpGetDefaultDir( sl@0: FSSpecPtr dirSpec) /* On return the default directory. */ sl@0: { sl@0: OSErr err; sl@0: short vRefNum = 0; sl@0: long int dirID = 0; sl@0: sl@0: err = HGetVol(NULL, &vRefNum, &dirID); sl@0: sl@0: if (err == noErr) { sl@0: err = FSMakeFSSpecCompat(vRefNum, dirID, (ConstStr255Param) NULL, sl@0: dirSpec); sl@0: } sl@0: sl@0: return err; sl@0: } sl@0: sl@0: /* sl@0: *---------------------------------------------------------------------- sl@0: * sl@0: * FSpSetDefaultDir -- sl@0: * sl@0: * This function sets the default directory to the directory sl@0: * pointed to by the provided FSSpec. sl@0: * sl@0: * Results: sl@0: * The function returns what ever errors HSetVol may encounter. sl@0: * sl@0: * Side effects: sl@0: * None. sl@0: * sl@0: *---------------------------------------------------------------------- sl@0: */ sl@0: sl@0: int sl@0: FSpSetDefaultDir( sl@0: FSSpecPtr dirSpec) /* The new default directory. */ sl@0: { sl@0: OSErr err; sl@0: sl@0: /* sl@0: * The following special case is needed to work around a bug sl@0: * in the Macintosh OS. (Acutally PC Exchange.) sl@0: */ sl@0: sl@0: if (dirSpec->parID == fsRtParID) { sl@0: err = HSetVol(NULL, dirSpec->vRefNum, fsRtDirID); sl@0: } else { sl@0: err = HSetVol(dirSpec->name, dirSpec->vRefNum, dirSpec->parID); sl@0: } sl@0: sl@0: return err; sl@0: } sl@0: sl@0: /* sl@0: *---------------------------------------------------------------------- sl@0: * sl@0: * FSpFindFolder -- sl@0: * sl@0: * This function is a version of the FindFolder function that sl@0: * returns the result as a FSSpec rather than a vRefNum and dirID. sl@0: * sl@0: * Results: sl@0: * Results will be simaler to that of the FindFolder function. sl@0: * sl@0: * Side effects: sl@0: * None. sl@0: * sl@0: *---------------------------------------------------------------------- sl@0: */ sl@0: sl@0: OSErr sl@0: FSpFindFolder( sl@0: short vRefNum, /* Volume reference number. */ sl@0: OSType folderType, /* Folder type taken by FindFolder. */ sl@0: Boolean createFolder, /* Should we create it if non-existant. */ sl@0: FSSpec *spec) /* Pointer to resulting directory. */ sl@0: { sl@0: short foundVRefNum; sl@0: long foundDirID; sl@0: OSErr err; sl@0: sl@0: err = FindFolder(vRefNum, folderType, createFolder, sl@0: &foundVRefNum, &foundDirID); sl@0: if (err != noErr) { sl@0: return err; sl@0: } sl@0: sl@0: err = FSMakeFSSpecCompat(foundVRefNum, foundDirID, "\p", spec); sl@0: return err; sl@0: } sl@0: sl@0: static int sl@0: FSpLocationFromPathAlias _ANSI_ARGS_((int length, CONST char *path, sl@0: FSSpecPtr fileSpecPtr, Boolean resolveLink)); sl@0: sl@0: /* sl@0: *---------------------------------------------------------------------- sl@0: * sl@0: * FSpLocationFromPath -- sl@0: * sl@0: * This function obtains an FSSpec for a given macintosh path. sl@0: * Unlike the More Files function FSpLocationFromFullPath, this sl@0: * function will also accept partial paths and resolve any aliases sl@0: * along the path. sl@0: * sl@0: * Results: sl@0: * OSErr code. sl@0: * sl@0: * Side effects: sl@0: * None. sl@0: * sl@0: *---------------------------------------------------------------------- sl@0: */ sl@0: sl@0: int sl@0: FSpLocationFromPath( sl@0: int length, /* Length of path. */ sl@0: CONST char *path, /* The path to convert. */ sl@0: FSSpecPtr fileSpecPtr) /* On return the spec for the path. */ sl@0: { sl@0: return FSpLocationFromPathAlias(length, path, fileSpecPtr, TRUE); sl@0: } sl@0: sl@0: /* sl@0: *---------------------------------------------------------------------- sl@0: * sl@0: * FSpLLocationFromPath -- sl@0: * sl@0: * This function obtains an FSSpec for a given macintosh path. sl@0: * Unlike the More Files function FSpLocationFromFullPath, this sl@0: * function will also accept partial paths and resolve any aliases sl@0: * along the path expect for the last path component. sl@0: * sl@0: * Results: sl@0: * OSErr code. sl@0: * sl@0: * Side effects: sl@0: * None. sl@0: * sl@0: *---------------------------------------------------------------------- sl@0: */ sl@0: sl@0: int sl@0: FSpLLocationFromPath( sl@0: int length, /* Length of path. */ sl@0: CONST char *path, /* The path to convert. */ sl@0: FSSpecPtr fileSpecPtr) /* On return the spec for the path. */ sl@0: { sl@0: return FSpLocationFromPathAlias(length, path, fileSpecPtr, FALSE); sl@0: } sl@0: sl@0: static int sl@0: FSpLocationFromPathAlias( sl@0: int length, /* Length of path. */ sl@0: CONST char *path, /* The path to convert. */ sl@0: FSSpecPtr fileSpecPtr, /* On return the spec for the path. */ sl@0: Boolean resolveLink) /* Resolve the last path component? */ sl@0: { sl@0: Str255 fileName; sl@0: OSErr err; sl@0: short vRefNum; sl@0: long dirID; sl@0: int pos, cur; sl@0: Boolean isDirectory; sl@0: Boolean wasAlias=FALSE; sl@0: FSSpec lastFileSpec; sl@0: sl@0: /* sl@0: * Check to see if this is a full path. If partial sl@0: * we assume that path starts with the current working sl@0: * directory. (Ie. volume & dir = 0) sl@0: */ sl@0: vRefNum = 0; sl@0: dirID = 0; sl@0: cur = 0; sl@0: if (length == 0) { sl@0: return fnfErr; sl@0: } sl@0: if (path[cur] == ':') { sl@0: cur++; sl@0: if (cur >= length) { sl@0: /* sl@0: * If path = ":", just return current directory. sl@0: */ sl@0: FSMakeFSSpecCompat(0, 0, NULL, fileSpecPtr); sl@0: return noErr; sl@0: } sl@0: } else { sl@0: while (path[cur] != ':' && cur < length) { sl@0: cur++; sl@0: } sl@0: if (cur > 255) { sl@0: return bdNamErr; sl@0: } sl@0: if (cur < length) { sl@0: /* sl@0: * This is a full path sl@0: */ sl@0: cur++; sl@0: strncpy((char *) fileName + 1, path, cur); sl@0: fileName[0] = cur; sl@0: err = FSMakeFSSpecCompat(0, 0, fileName, fileSpecPtr); sl@0: if (err != noErr) return err; sl@0: FSpGetDirectoryID(fileSpecPtr, &dirID, &isDirectory); sl@0: vRefNum = fileSpecPtr->vRefNum; sl@0: } else { sl@0: cur = 0; sl@0: } sl@0: } sl@0: sl@0: isDirectory = 1; sl@0: while (cur < length) { sl@0: if (!isDirectory) { sl@0: return dirNFErr; sl@0: } sl@0: pos = cur; sl@0: while (path[pos] != ':' && pos < length) { sl@0: pos++; sl@0: } sl@0: if (pos == cur) { sl@0: /* Move up one dir */ sl@0: /* cur++; */ sl@0: strcpy((char *) fileName + 1, "::"); sl@0: fileName[0] = 2; sl@0: } else if (pos - cur > 255) { sl@0: return bdNamErr; sl@0: } else { sl@0: strncpy((char *) fileName + 1, &path[cur], pos - cur); sl@0: fileName[0] = pos - cur; sl@0: } sl@0: err = FSMakeFSSpecCompat(vRefNum, dirID, fileName, fileSpecPtr); sl@0: if (err != noErr) return err; sl@0: lastFileSpec=*fileSpecPtr; sl@0: err = ResolveAliasFile(fileSpecPtr, true, &isDirectory, &wasAlias); sl@0: if (err != noErr) { sl@0: /* ignore alias resolve errors on last path component */ sl@0: if (pos < length) return err; sl@0: else *fileSpecPtr=lastFileSpec; sl@0: } sl@0: FSpGetDirectoryID(fileSpecPtr, &dirID, &isDirectory); sl@0: vRefNum = fileSpecPtr->vRefNum; sl@0: cur = pos; sl@0: if (path[cur] == ':') { sl@0: cur++; sl@0: } sl@0: } sl@0: sl@0: if(!resolveLink && wasAlias) sl@0: *fileSpecPtr=lastFileSpec; sl@0: sl@0: return noErr; sl@0: } sl@0: sl@0: /* sl@0: *---------------------------------------------------------------------- sl@0: * sl@0: * FSpPathFromLocation -- sl@0: * sl@0: * This function obtains a full path name for a given macintosh sl@0: * FSSpec. Unlike the More Files function FSpGetFullPath, this sl@0: * function will return a C string in the Handle. It also will sl@0: * create paths for FSSpec that do not yet exist. sl@0: * sl@0: * Results: sl@0: * OSErr code. sl@0: * sl@0: * Side effects: sl@0: * None. sl@0: * sl@0: *---------------------------------------------------------------------- sl@0: */ sl@0: sl@0: OSErr sl@0: FSpPathFromLocation( sl@0: FSSpec *spec, /* The location we want a path for. */ sl@0: int *length, /* Length of the resulting path. */ sl@0: Handle *fullPath) /* Handle to path. */ sl@0: { sl@0: OSErr err; sl@0: FSSpec tempSpec; sl@0: CInfoPBRec pb; sl@0: sl@0: *fullPath = NULL; sl@0: sl@0: /* sl@0: * Make a copy of the input FSSpec that can be modified. sl@0: */ sl@0: BlockMoveData(spec, &tempSpec, sizeof(FSSpec)); sl@0: sl@0: if (tempSpec.parID == fsRtParID) { sl@0: /* sl@0: * The object is a volume. Add a colon to make it a full sl@0: * pathname. Allocate a handle for it and we are done. sl@0: */ sl@0: tempSpec.name[0] += 2; sl@0: tempSpec.name[tempSpec.name[0] - 1] = ':'; sl@0: tempSpec.name[tempSpec.name[0]] = '\0'; sl@0: sl@0: err = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]); sl@0: } else { sl@0: /* sl@0: * The object isn't a volume. Is the object a file or a directory? sl@0: */ sl@0: pb.dirInfo.ioNamePtr = tempSpec.name; sl@0: pb.dirInfo.ioVRefNum = tempSpec.vRefNum; sl@0: pb.dirInfo.ioDrDirID = tempSpec.parID; sl@0: pb.dirInfo.ioFDirIndex = 0; sl@0: err = PBGetCatInfoSync(&pb); sl@0: sl@0: if ((err == noErr) || (err == fnfErr)) { sl@0: /* sl@0: * If the file doesn't currently exist we start over. If the sl@0: * directory exists everything will work just fine. Otherwise we sl@0: * will just fail later. If the object is a directory, append a sl@0: * colon so full pathname ends with colon, but only if the name is sl@0: * not empty. NavServices returns FSSpec's with the parent ID set, sl@0: * but the name empty... sl@0: */ sl@0: if (err == fnfErr) { sl@0: BlockMoveData(spec, &tempSpec, sizeof(FSSpec)); sl@0: } else if ( (pb.hFileInfo.ioFlAttrib & ioDirMask) != 0 ) { sl@0: if (tempSpec.name[0] > 0) { sl@0: tempSpec.name[0] += 1; sl@0: tempSpec.name[tempSpec.name[0]] = ':'; sl@0: } sl@0: } sl@0: sl@0: /* sl@0: * Create a new Handle for the object - make it a C string. sl@0: */ sl@0: tempSpec.name[0] += 1; sl@0: tempSpec.name[tempSpec.name[0]] = '\0'; sl@0: err = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]); sl@0: if (err == noErr) { sl@0: /* sl@0: * Get the ancestor directory names - loop until we have an sl@0: * error or find the root directory. sl@0: */ sl@0: pb.dirInfo.ioNamePtr = tempSpec.name; sl@0: pb.dirInfo.ioVRefNum = tempSpec.vRefNum; sl@0: pb.dirInfo.ioDrParID = tempSpec.parID; sl@0: do { sl@0: pb.dirInfo.ioFDirIndex = -1; sl@0: pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID; sl@0: err = PBGetCatInfoSync(&pb); sl@0: if (err == noErr) { sl@0: /* sl@0: * Append colon to directory name and add sl@0: * directory name to beginning of fullPath. sl@0: */ sl@0: ++tempSpec.name[0]; sl@0: tempSpec.name[tempSpec.name[0]] = ':'; sl@0: sl@0: (void) Munger(*fullPath, 0, NULL, 0, &tempSpec.name[1], sl@0: tempSpec.name[0]); sl@0: err = MemError(); sl@0: } sl@0: } while ( (err == noErr) && sl@0: (pb.dirInfo.ioDrDirID != fsRtDirID) ); sl@0: } sl@0: } sl@0: } sl@0: sl@0: /* sl@0: * On error Dispose the handle, set it to NULL & return the err. sl@0: * Otherwise, set the length & return. sl@0: */ sl@0: if (err == noErr) { sl@0: *length = GetHandleSize(*fullPath) - 1; sl@0: } else { sl@0: if ( *fullPath != NULL ) { sl@0: DisposeHandle(*fullPath); sl@0: } sl@0: *fullPath = NULL; sl@0: *length = 0; sl@0: } sl@0: sl@0: return err; sl@0: } sl@0: sl@0: /* sl@0: *---------------------------------------------------------------------- sl@0: * sl@0: * GetGlobalMouseTcl -- sl@0: * sl@0: * This procedure obtains the current mouse position in global sl@0: * coordinates. sl@0: * sl@0: * Results: sl@0: * None. sl@0: * sl@0: * Side effects: sl@0: * None. sl@0: * sl@0: *---------------------------------------------------------------------- sl@0: */ sl@0: sl@0: void sl@0: GetGlobalMouseTcl( sl@0: Point *mouse) /* Mouse position. */ sl@0: { sl@0: EventRecord event; sl@0: sl@0: OSEventAvail(0, &event); sl@0: *mouse = event.where; sl@0: } sl@0: sl@0: pascal OSErr FSpGetDirectoryIDTcl (CONST FSSpec * spec, sl@0: long * theDirID, Boolean * isDirectory) sl@0: { sl@0: return(FSpGetDirectoryID(spec, theDirID, isDirectory)); sl@0: } sl@0: sl@0: pascal short FSpOpenResFileCompatTcl (CONST FSSpec * spec, SignedByte permission) sl@0: { sl@0: return(FSpOpenResFileCompat(spec,permission)); sl@0: } sl@0: sl@0: pascal void FSpCreateResFileCompatTcl ( sl@0: CONST FSSpec * spec, OSType creator, sl@0: OSType fileType, ScriptCode scriptTag) sl@0: { sl@0: FSpCreateResFileCompat (spec,creator,fileType,scriptTag); sl@0: }