os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/mac/tclMacUtil.c
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 /* 
     2  * tclMacUtil.c --
     3  *
     4  *  This contains utility functions used to help with
     5  *  implementing Macintosh specific portions of the Tcl port.
     6  *
     7  * Copyright (c) 1993-1994 Lockheed Missle & Space Company, AI Center
     8  * Copyright (c) 1995-1997 Sun Microsystems, Inc.
     9  *
    10  * See the file "license.terms" for information on usage and redistribution
    11  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
    12  *
    13  * RCS: @(#) $Id: tclMacUtil.c,v 1.7 2003/03/03 20:22:44 das Exp $
    14  */
    15 
    16 #include "tcl.h"
    17 #include "tclInt.h"
    18 #include "tclMacInt.h"
    19 #include "tclMath.h"
    20 #include "tclMacPort.h"
    21 
    22 #include <Aliases.h>
    23 #include <Errors.h>
    24 #include <Files.h>
    25 #include <Folders.h>
    26 #include <FSpCompat.h>
    27 #include <Strings.h>
    28 #include <TextUtils.h>
    29 #include <MoreFilesExtras.h>
    30 
    31 /* 
    32  * The following two Includes are from the More Files package.
    33  */
    34 #include <FileCopy.h>
    35 #include <MoreFiles.h>
    36 
    37 /*
    38  *----------------------------------------------------------------------
    39  *
    40  * hypotd --
    41  *
    42  *	The standard math function hypot is not supported by Think C.
    43  *	It is included here so everything works. It is supported by
    44  *	CodeWarrior Pro 1, but the 68K version does not support doubles.
    45  *	So we hack it in.
    46  *
    47  * Results:
    48  *	Result of computation.
    49  *
    50  * Side effects:
    51  *	None.
    52  *
    53  *----------------------------------------------------------------------
    54  */
    55  
    56 #if defined(THINK_C)
    57 double hypotd(double x, double y);
    58 
    59 double
    60 hypotd(
    61     double x,		/* X value */
    62     double y)		/* Y value */
    63 {
    64     double sum;
    65 
    66     sum = x*x + y*y;
    67     return sqrt(sum);
    68 }
    69 #endif
    70 
    71 /*
    72  *----------------------------------------------------------------------
    73  *
    74  * FSpGetDefaultDir --
    75  *
    76  *	This function gets the current default directory.
    77  *
    78  * Results:
    79  *	The provided FSSpec is changed to point to the "default"
    80  *	directory.  The function returns what ever errors
    81  *	FSMakeFSSpecCompat may encounter.
    82  *
    83  * Side effects:
    84  *	None.
    85  *
    86  *----------------------------------------------------------------------
    87  */
    88 
    89 int
    90 FSpGetDefaultDir(
    91 	FSSpecPtr dirSpec)	/* On return the default directory. */
    92 {
    93     OSErr err;
    94     short vRefNum = 0;
    95     long int dirID = 0;
    96 
    97     err = HGetVol(NULL, &vRefNum, &dirID);
    98 	
    99     if (err == noErr) {
   100 	err = FSMakeFSSpecCompat(vRefNum, dirID, (ConstStr255Param) NULL,
   101 		dirSpec);
   102     }
   103 	
   104     return err;
   105 }
   106 
   107 /*
   108  *----------------------------------------------------------------------
   109  *
   110  * FSpSetDefaultDir --
   111  *
   112  *	This function sets the default directory to the directory
   113  *	pointed to by the provided FSSpec.
   114  *
   115  * Results:
   116  *	The function returns what ever errors HSetVol may encounter.
   117  *
   118  * Side effects:
   119  *	None.
   120  *
   121  *----------------------------------------------------------------------
   122  */
   123 
   124 int
   125 FSpSetDefaultDir(
   126 	FSSpecPtr dirSpec)	/* The new default directory. */
   127 {
   128     OSErr err;
   129 
   130     /*
   131      * The following special case is needed to work around a bug
   132      * in the Macintosh OS.  (Acutally PC Exchange.)
   133      */
   134     
   135     if (dirSpec->parID == fsRtParID) {
   136 	err = HSetVol(NULL, dirSpec->vRefNum, fsRtDirID);
   137     } else {
   138 	err = HSetVol(dirSpec->name, dirSpec->vRefNum, dirSpec->parID);
   139     }
   140     
   141     return err;
   142 }
   143 
   144 /*
   145  *----------------------------------------------------------------------
   146  *
   147  * FSpFindFolder --
   148  *
   149  *	This function is a version of the FindFolder function that 
   150  *	returns the result as a FSSpec rather than a vRefNum and dirID.
   151  *
   152  * Results:
   153  *	Results will be simaler to that of the FindFolder function.
   154  *
   155  * Side effects:
   156  *	None.
   157  *
   158  *----------------------------------------------------------------------
   159  */
   160 
   161 OSErr
   162 FSpFindFolder(
   163     short vRefNum,		/* Volume reference number. */
   164     OSType folderType,		/* Folder type taken by FindFolder. */
   165     Boolean createFolder,	/* Should we create it if non-existant. */
   166     FSSpec *spec)		/* Pointer to resulting directory. */
   167 {
   168     short foundVRefNum;
   169     long foundDirID;
   170     OSErr err;
   171 
   172     err = FindFolder(vRefNum, folderType, createFolder,
   173 	    &foundVRefNum, &foundDirID);
   174     if (err != noErr) {
   175 	return err;
   176     }
   177 		
   178     err = FSMakeFSSpecCompat(foundVRefNum, foundDirID, "\p", spec);
   179     return err;
   180 }
   181 
   182 static int
   183 FSpLocationFromPathAlias _ANSI_ARGS_((int length, CONST char *path,
   184 	FSSpecPtr fileSpecPtr, Boolean resolveLink));
   185 
   186 /*
   187  *----------------------------------------------------------------------
   188  *
   189  * FSpLocationFromPath --
   190  *
   191  *	This function obtains an FSSpec for a given macintosh path.
   192  *	Unlike the More Files function FSpLocationFromFullPath, this
   193  *	function will also accept partial paths and resolve any aliases
   194  *	along the path.  
   195  *
   196  * Results:
   197  *	OSErr code.
   198  *
   199  * Side effects:
   200  *	None.
   201  *
   202  *----------------------------------------------------------------------
   203  */
   204 
   205 int
   206 FSpLocationFromPath(
   207     int length,			/* Length of path. */
   208     CONST char *path,		/* The path to convert. */
   209     FSSpecPtr fileSpecPtr)	/* On return the spec for the path. */
   210 {
   211 	return FSpLocationFromPathAlias(length, path, fileSpecPtr, TRUE);
   212 }
   213 
   214 /*
   215  *----------------------------------------------------------------------
   216  *
   217  * FSpLLocationFromPath --
   218  *
   219  *	This function obtains an FSSpec for a given macintosh path.
   220  *	Unlike the More Files function FSpLocationFromFullPath, this
   221  *	function will also accept partial paths and resolve any aliases
   222  *	along the path expect for the last path component.
   223  *
   224  * Results:
   225  *	OSErr code.
   226  *
   227  * Side effects:
   228  *	None.
   229  *
   230  *----------------------------------------------------------------------
   231  */
   232 
   233 int
   234 FSpLLocationFromPath(
   235     int length,			/* Length of path. */
   236     CONST char *path,		/* The path to convert. */
   237     FSSpecPtr fileSpecPtr)	/* On return the spec for the path. */
   238 {
   239 	return FSpLocationFromPathAlias(length, path, fileSpecPtr, FALSE);
   240 }
   241 
   242 static int
   243 FSpLocationFromPathAlias(
   244     int length,			/* Length of path. */
   245     CONST char *path,		/* The path to convert. */
   246     FSSpecPtr fileSpecPtr,	/* On return the spec for the path. */
   247     Boolean resolveLink)	/* Resolve the last path component? */
   248 {
   249     Str255 fileName;
   250     OSErr err;
   251     short vRefNum;
   252     long dirID;
   253     int pos, cur;
   254     Boolean isDirectory;
   255     Boolean wasAlias=FALSE;
   256     FSSpec lastFileSpec;
   257 
   258     /*
   259      * Check to see if this is a full path.  If partial
   260      * we assume that path starts with the current working
   261      * directory.  (Ie. volume & dir = 0)
   262      */
   263     vRefNum = 0;
   264     dirID = 0;
   265     cur = 0;
   266     if (length == 0) {
   267         return fnfErr;
   268     }
   269     if (path[cur] == ':') {
   270 	cur++;
   271 	if (cur >= length) {
   272 	    /*
   273 	     * If path = ":", just return current directory.
   274 	     */
   275 	    FSMakeFSSpecCompat(0, 0, NULL, fileSpecPtr);
   276 	    return noErr;
   277 	}
   278     } else {
   279 	while (path[cur] != ':' && cur < length) {
   280 	    cur++;
   281 	}
   282 	if (cur > 255) {
   283 	    return bdNamErr;
   284 	}
   285 	if (cur < length) {
   286 	    /*
   287 	     * This is a full path
   288 	     */
   289 	    cur++;
   290 	    strncpy((char *) fileName + 1, path, cur);
   291 	    fileName[0] = cur;
   292 	    err = FSMakeFSSpecCompat(0, 0, fileName, fileSpecPtr);
   293 	    if (err != noErr) return err;
   294 	    FSpGetDirectoryID(fileSpecPtr, &dirID, &isDirectory);
   295 	    vRefNum = fileSpecPtr->vRefNum;
   296 	} else {
   297 	    cur = 0;
   298 	}
   299     }
   300     
   301     isDirectory = 1;
   302     while (cur < length) {
   303 	if (!isDirectory) {
   304 	    return dirNFErr;
   305 	}
   306 	pos = cur;
   307 	while (path[pos] != ':' && pos < length) {
   308 	    pos++;
   309 	}
   310 	if (pos == cur) {
   311 	    /* Move up one dir */
   312 	    /* cur++; */
   313 	    strcpy((char *) fileName + 1, "::");
   314 	    fileName[0] = 2;
   315 	} else if (pos - cur > 255) {
   316 	    return bdNamErr;
   317 	} else {
   318 	    strncpy((char *) fileName + 1, &path[cur], pos - cur);
   319 	    fileName[0] = pos - cur;
   320 	}
   321 	err = FSMakeFSSpecCompat(vRefNum, dirID, fileName, fileSpecPtr);
   322 	if (err != noErr) return err;
   323 	lastFileSpec=*fileSpecPtr;
   324 	err = ResolveAliasFile(fileSpecPtr, true, &isDirectory, &wasAlias);
   325 	if (err != noErr) {
   326 	    /* ignore alias resolve errors on last path component */
   327 	    if (pos < length) return err;
   328 	    else *fileSpecPtr=lastFileSpec;
   329 	}
   330 	FSpGetDirectoryID(fileSpecPtr, &dirID, &isDirectory);
   331 	vRefNum = fileSpecPtr->vRefNum;
   332 	cur = pos;
   333 	if (path[cur] == ':') {
   334 	    cur++;
   335 	}
   336     }
   337     
   338     if(!resolveLink && wasAlias)
   339     	*fileSpecPtr=lastFileSpec;
   340     
   341     return noErr;
   342 }
   343 
   344 /*
   345  *----------------------------------------------------------------------
   346  *
   347  * FSpPathFromLocation --
   348  *
   349  *	This function obtains a full path name for a given macintosh
   350  *	FSSpec.  Unlike the More Files function FSpGetFullPath, this
   351  *	function will return a C string in the Handle.  It also will
   352  *	create paths for FSSpec that do not yet exist.
   353  *
   354  * Results:
   355  *	OSErr code.
   356  *
   357  * Side effects:
   358  *	None.
   359  *
   360  *----------------------------------------------------------------------
   361  */
   362 
   363 OSErr
   364 FSpPathFromLocation(
   365     FSSpec *spec,		/* The location we want a path for. */
   366     int *length,		/* Length of the resulting path. */
   367     Handle *fullPath)		/* Handle to path. */
   368 {
   369     OSErr err;
   370     FSSpec tempSpec;
   371     CInfoPBRec pb;
   372 	
   373     *fullPath = NULL;
   374 	
   375     /* 
   376      * Make a copy of the input FSSpec that can be modified.
   377      */
   378     BlockMoveData(spec, &tempSpec, sizeof(FSSpec));
   379 	
   380     if (tempSpec.parID == fsRtParID) {
   381 	/* 
   382 	 * The object is a volume.  Add a colon to make it a full 
   383 	 * pathname.  Allocate a handle for it and we are done.
   384 	 */
   385 	tempSpec.name[0] += 2;
   386 	tempSpec.name[tempSpec.name[0] - 1] = ':';
   387 	tempSpec.name[tempSpec.name[0]] = '\0';
   388 		
   389 	err = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]);
   390     } else {
   391 	/* 
   392 	 * The object isn't a volume.  Is the object a file or a directory? 
   393 	 */
   394 	pb.dirInfo.ioNamePtr = tempSpec.name;
   395 	pb.dirInfo.ioVRefNum = tempSpec.vRefNum;
   396 	pb.dirInfo.ioDrDirID = tempSpec.parID;
   397 	pb.dirInfo.ioFDirIndex = 0;
   398 	err = PBGetCatInfoSync(&pb);
   399 
   400 	if ((err == noErr) || (err == fnfErr)) {
   401 	    /* 
   402 	     * If the file doesn't currently exist we start over.  If the
   403 	     * directory exists everything will work just fine.  Otherwise we
   404 	     * will just fail later.  If the object is a directory, append a
   405 	     * colon so full pathname ends with colon, but only if the name is
   406 	     * not empty.  NavServices returns FSSpec's with the parent ID set,
   407 	     * but the name empty...
   408 	     */
   409 	    if (err == fnfErr) {
   410 		BlockMoveData(spec, &tempSpec, sizeof(FSSpec));
   411 	    } else if ( (pb.hFileInfo.ioFlAttrib & ioDirMask) != 0 ) {
   412 	        if (tempSpec.name[0] > 0) {
   413 		    tempSpec.name[0] += 1;
   414 		    tempSpec.name[tempSpec.name[0]] = ':';
   415 		}
   416 	    }
   417 			
   418 	    /* 
   419 	     * Create a new Handle for the object - make it a C string.
   420 	     */
   421 	    tempSpec.name[0] += 1;
   422 	    tempSpec.name[tempSpec.name[0]] = '\0';
   423 	    err = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]);
   424 	    if (err == noErr) {
   425 		/* 
   426 		 * Get the ancestor directory names - loop until we have an 
   427 		 * error or find the root directory.
   428 		 */
   429 		pb.dirInfo.ioNamePtr = tempSpec.name;
   430 		pb.dirInfo.ioVRefNum = tempSpec.vRefNum;
   431 		pb.dirInfo.ioDrParID = tempSpec.parID;
   432 		do {
   433 		    pb.dirInfo.ioFDirIndex = -1;
   434 		    pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID;
   435 		    err = PBGetCatInfoSync(&pb);
   436 		    if (err == noErr) {
   437 			/* 
   438 			 * Append colon to directory name and add 
   439 			 * directory name to beginning of fullPath.
   440 			 */
   441 			++tempSpec.name[0];
   442 			tempSpec.name[tempSpec.name[0]] = ':';
   443 						
   444 			(void) Munger(*fullPath, 0, NULL, 0, &tempSpec.name[1],
   445 				tempSpec.name[0]);
   446 			err = MemError();
   447 		    }
   448 		} while ( (err == noErr) &&
   449 			(pb.dirInfo.ioDrDirID != fsRtDirID) );
   450 	    }
   451 	}
   452     }
   453     
   454     /*
   455      * On error Dispose the handle, set it to NULL & return the err.
   456      * Otherwise, set the length & return.
   457      */
   458     if (err == noErr) {
   459 	*length = GetHandleSize(*fullPath) - 1;
   460     } else {
   461 	if ( *fullPath != NULL ) {
   462 	    DisposeHandle(*fullPath);
   463 	}
   464 	*fullPath = NULL;
   465 	*length = 0;
   466     }
   467 
   468     return err;
   469 }
   470 
   471 /*
   472  *----------------------------------------------------------------------
   473  *
   474  * GetGlobalMouseTcl --
   475  *
   476  *	This procedure obtains the current mouse position in global
   477  *	coordinates.
   478  *
   479  * Results:
   480  *	None.
   481  *
   482  * Side effects:
   483  *	None.
   484  *
   485  *----------------------------------------------------------------------
   486  */
   487 
   488 void
   489 GetGlobalMouseTcl(
   490     Point *mouse)		/* Mouse position. */
   491 {
   492     EventRecord event;
   493     
   494     OSEventAvail(0, &event);
   495     *mouse = event.where;
   496 }
   497 
   498 pascal OSErr	FSpGetDirectoryIDTcl (CONST FSSpec * spec, 
   499 				long * theDirID, Boolean * isDirectory)
   500 {
   501 	return(FSpGetDirectoryID(spec, theDirID, isDirectory));
   502 }
   503 
   504 pascal short	FSpOpenResFileCompatTcl (CONST FSSpec * spec, SignedByte permission)
   505 {
   506 	return(FSpOpenResFileCompat(spec,permission));
   507 }
   508 
   509 pascal void	FSpCreateResFileCompatTcl (
   510 				CONST FSSpec * spec, OSType creator, 
   511 				OSType fileType, ScriptCode scriptTag)
   512 {
   513 	FSpCreateResFileCompat (spec,creator,fileType,scriptTag);
   514 }