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