#include "tclInt.h"
#include "tclPort.h"
#include "tclMacInt.h"
#include <Aliases.h>
#include <Errors.h>
#include <Processes.h>
#include <Strings.h>
#include <Types.h>
#include <MoreFiles.h>
#include <MoreFilesExtras.h>
#include <FSpCompat.h>
static int initalized = false;
static long gmt_offset;
static char *currentDir = NULL;
int
TclChdir(
Tcl_Interp *interp,
char *dirName)
{
FSSpec spec;
OSErr err;
Boolean isFolder;
long dirID;
if (currentDir != NULL) {
ckfree(currentDir);
currentDir = NULL;
}
err = FSpLocationFromPath(strlen(dirName), dirName, &spec);
if (err != noErr) {
errno = ENOENT;
goto chdirError;
}
err = FSpGetDirectoryID(&spec, &dirID, &isFolder);
if (err != noErr) {
errno = ENOENT;
goto chdirError;
}
if (isFolder != true) {
errno = ENOTDIR;
goto chdirError;
}
err = FSpSetDefaultDir(&spec);
if (err != noErr) {
switch (err) {
case afpAccessDenied:
errno = EACCES;
break;
default:
errno = ENOENT;
}
goto chdirError;
}
return TCL_OK;
chdirError:
if (interp != NULL) {
Tcl_AppendResult(interp, "couldn't change working directory to \"",
dirName, "\": ", Tcl_PosixError(interp), (char *) NULL);
}
return TCL_ERROR;
}
char *
TclGetCwd(
Tcl_Interp *interp)
{
FSSpec theSpec;
int length;
Handle pathHandle = NULL;
if (currentDir == NULL) {
if (FSpGetDefaultDir(&theSpec) != noErr) {
if (interp != NULL) {
interp->result = "error getting working directory name";
}
return NULL;
}
if (FSpPathFromLocation(&theSpec, &length, &pathHandle) != noErr) {
if (interp != NULL) {
interp->result = "error getting working directory name";
}
return NULL;
}
HLock(pathHandle);
currentDir = (char *) ckalloc((unsigned) (length + 1));
strcpy(currentDir, *pathHandle);
HUnlock(pathHandle);
DisposeHandle(pathHandle);
}
return currentDir;
}
Tcl_Pid
Tcl_WaitPid(
Tcl_Pid pid,
int *statPtr,
int options)
{
return (Tcl_Pid) -1;
}
void
Tcl_FindExecutable(
char *argv0)
{
ProcessSerialNumber psn;
ProcessInfoRec info;
Str63 appName;
FSSpec fileSpec;
int pathLength;
Handle pathName = NULL;
OSErr err;
GetCurrentProcess(&psn);
info.processInfoLength = sizeof(ProcessInfoRec);
info.processName = appName;
info.processAppSpec = &fileSpec;
GetProcessInformation(&psn, &info);
if (tclExecutableName != NULL) {
ckfree(tclExecutableName);
tclExecutableName = NULL;
}
err = FSpPathFromLocation(&fileSpec, &pathLength, &pathName);
tclExecutableName = (char *) ckalloc((unsigned) pathLength + 1);
HLock(pathName);
strcpy(tclExecutableName, *pathName);
HUnlock(pathName);
DisposeHandle(pathName);
}
char *
TclGetUserHome(
char *name,
Tcl_DString *bufferPtr)
{
return NULL;
}
int
TclMatchFiles(
Tcl_Interp *interp,
char *separators,
Tcl_DString *dirPtr,
char *pattern,
char *tail)
{
char *dirName, *patternEnd = tail;
char savedChar;
int result = TCL_OK;
int baseLength = Tcl_DStringLength(dirPtr);
CInfoPBRec pb;
OSErr err;
FSSpec dirSpec;
Boolean isDirectory;
long dirID;
short itemIndex;
Str255 fileName;
dirName = dirPtr->string;
FSpLocationFromPath(strlen(dirName), dirName, &dirSpec);
err = FSpGetDirectoryID(&dirSpec, &dirID, &isDirectory);
if ((err != noErr) || !isDirectory) {
return TCL_OK;
}
pb.hFileInfo.ioVRefNum = dirSpec.vRefNum;
pb.hFileInfo.ioDirID = dirID;
pb.hFileInfo.ioNamePtr = (StringPtr) fileName;
pb.hFileInfo.ioFDirIndex = itemIndex = 1;
if (*tail == '\\') {
tail++;
}
if (*tail == '\0') {
tail = NULL;
} else {
tail++;
}
savedChar = *patternEnd;
*patternEnd = '\0';
while (1) {
pb.hFileInfo.ioFDirIndex = itemIndex;
pb.hFileInfo.ioDirID = dirID;
err = PBGetCatInfoSync(&pb);
if (err != noErr) {
break;
}
p2cstr(fileName);
if (Tcl_StringMatch((char *) fileName, pattern)) {
Tcl_DStringSetLength(dirPtr, baseLength);
Tcl_DStringAppend(dirPtr, (char *) fileName, -1);
if (tail == NULL) {
if ((dirPtr->length > 1) &&
(strchr(dirPtr->string+1, ':') == NULL)) {
Tcl_AppendElement(interp, dirPtr->string+1);
} else {
Tcl_AppendElement(interp, dirPtr->string);
}
} else if ((pb.hFileInfo.ioFlAttrib & ioDirMask) != 0) {
Tcl_DStringAppend(dirPtr, ":", 1);
result = TclDoGlob(interp, separators, dirPtr, tail);
if (result != TCL_OK) {
break;
}
}
}
itemIndex++;
}
*patternEnd = savedChar;
return result;
}
int
TclpStat(
CONST char *path,
struct stat *buf)
{
HFileInfo fpb;
HVolumeParam vpb;
OSErr err;
FSSpec fileSpec;
Boolean isDirectory;
long dirID;
err = FSpLocationFromPath(strlen(path), path, &fileSpec);
if (err != noErr) {
errno = TclMacOSErrorToPosixError(err);
return -1;
}
FSpGetDirectoryID(&fileSpec, &dirID, &isDirectory);
vpb.ioVRefNum = fpb.ioVRefNum = fileSpec.vRefNum;
vpb.ioNamePtr = fpb.ioNamePtr = fileSpec.name;
if (isDirectory) {
fpb.ioDirID = fileSpec.parID;
} else {
fpb.ioDirID = dirID;
}
fpb.ioFDirIndex = 0;
err = PBGetCatInfoSync((CInfoPBPtr)&fpb);
if (err == noErr) {
vpb.ioVolIndex = 0;
err = PBHGetVInfoSync((HParmBlkPtr)&vpb);
if (err == noErr && buf != NULL) {
buf->st_mode = S_IRUSR | S_IRGRP | S_IROTH;
if (fpb.ioFlAttrib & 0x10) {
buf->st_mode |= S_IFDIR;
buf->st_nlink = 2;
} else {
buf->st_nlink = 1;
if (fpb.ioFlFndrInfo.fdFlags & 0x8000) {
buf->st_mode |= S_IFLNK;
} else {
buf->st_mode |= S_IFREG;
}
}
if ((fpb.ioFlAttrib & 0x10) || (fpb.ioFlFndrInfo.fdType == 'APPL')) {
buf->st_mode |= S_IXUSR | S_IXGRP | S_IXOTH;
}
if ((fpb.ioFlAttrib & 0x01) == 0){
buf->st_mode |= S_IWUSR | S_IWGRP | S_IWOTH;
}
buf->st_ino = fpb.ioDirID;
buf->st_dev = fpb.ioVRefNum;
buf->st_uid = -1;
buf->st_gid = -1;
buf->st_rdev = 0;
buf->st_size = fpb.ioFlLgLen;
buf->st_blksize = vpb.ioVAlBlkSiz;
buf->st_blocks = (buf->st_size + buf->st_blksize - 1)
/ buf->st_blksize;
if (initalized == false) {
MachineLocation loc;
ReadLocation(&loc);
gmt_offset = loc.u.gmtDelta & 0x00ffffff;
if (gmt_offset & 0x00800000) {
gmt_offset = gmt_offset | 0xff000000;
}
initalized = true;
}
buf->st_atime = buf->st_mtime = fpb.ioFlMdDat - gmt_offset;
buf->st_ctime = fpb.ioFlCrDat - gmt_offset;
}
}
if (err != noErr) {
errno = TclMacOSErrorToPosixError(err);
}
return (err == noErr ? 0 : -1);
}
int
TclMacReadlink(
char *path,
char *buf,
int size)
{
HFileInfo fpb;
OSErr err;
FSSpec fileSpec;
Boolean isDirectory;
Boolean wasAlias;
long dirID;
char fileName[256];
char *end;
Handle theString = NULL;
int pathSize;
while ((strlen(path) != 0) && (path[strlen(path) - 1] == ':')) {
path[strlen(path) - 1] = NULL;
}
if (strchr(path, ':') == NULL) {
strcpy(fileName, path);
path = NULL;
} else {
end = strrchr(path, ':') + 1;
strcpy(fileName, end);
*end = NULL;
}
c2pstr(fileName);
if (path != NULL) {
err = FSpLocationFromPath(strlen(path), path, &fileSpec);
if (err != noErr) {
errno = EINVAL;
return -1;
}
} else {
FSMakeFSSpecCompat(0, 0, NULL, &fileSpec);
}
FSpGetDirectoryID(&fileSpec, &dirID, &isDirectory);
fpb.ioVRefNum = fileSpec.vRefNum;
fpb.ioDirID = dirID;
fpb.ioNamePtr = (StringPtr) fileName;
fpb.ioFDirIndex = 0;
err = PBGetCatInfoSync((CInfoPBPtr)&fpb);
if (err != noErr) {
errno = TclMacOSErrorToPosixError(err);
return -1;
} else {
if (fpb.ioFlAttrib & 0x10) {
errno = EINVAL;
return -1;
} else {
if (fpb.ioFlFndrInfo.fdFlags & 0x8000) {
} else {
errno = EINVAL;
return -1;
}
}
}
err = FSMakeFSSpecCompat(fileSpec.vRefNum, dirID, (StringPtr) fileName, &fileSpec);
if (err == noErr) {
err = ResolveAliasFile(&fileSpec, true, &isDirectory, &wasAlias);
}
if ((err == fnfErr) || wasAlias) {
err = FSpPathFromLocation(&fileSpec, &pathSize, &theString);
if ((err != noErr) || (pathSize > size)) {
DisposeHandle(theString);
errno = ENAMETOOLONG;
return -1;
}
} else {
errno = EINVAL;
return -1;
}
strncpy(buf, *theString, pathSize);
DisposeHandle(theString);
return pathSize;
}
int
TclpAccess(
const char *path,
int mode)
{
HFileInfo fpb;
HVolumeParam vpb;
OSErr err;
FSSpec fileSpec;
Boolean isDirectory;
long dirID;
int full_mode = 0;
err = FSpLocationFromPath(strlen(path), (char *) path, &fileSpec);
if (err != noErr) {
errno = TclMacOSErrorToPosixError(err);
return -1;
}
FSpGetDirectoryID(&fileSpec, &dirID, &isDirectory);
vpb.ioVRefNum = fpb.ioVRefNum = fileSpec.vRefNum;
vpb.ioNamePtr = fpb.ioNamePtr = fileSpec.name;
if (isDirectory) {
fpb.ioDirID = fileSpec.parID;
} else {
fpb.ioDirID = dirID;
}
fpb.ioFDirIndex = 0;
err = PBGetCatInfoSync((CInfoPBPtr)&fpb);
if (err == noErr) {
vpb.ioVolIndex = 0;
err = PBHGetVInfoSync((HParmBlkPtr)&vpb);
if (err == noErr) {
if (mode & W_OK) {
if ((vpb.ioVAtrb & 0x0080) || (vpb.ioVAtrb & 0x8000)) {
errno = EROFS;
return -1;
}
if (fpb.ioFlAttrib & 0x01) {
errno = EACCES;
return -1;
}
}
if (!(fpb.ioFlAttrib & 0x10) && (mode & X_OK)
&& (fpb.ioFlFndrInfo.fdType != 'APPL')) {
return -1;
}
}
}
if (err != noErr) {
errno = TclMacOSErrorToPosixError(err);
return -1;
}
return 0;
}
#undef fopen
FILE *
TclMacFOpenHack(
const char *path,
const char *mode)
{
OSErr err;
FSSpec fileSpec;
Handle pathString = NULL;
int size;
FILE * f;
err = FSpLocationFromPath(strlen(path), (char *) path, &fileSpec);
if ((err != noErr) && (err != fnfErr)) {
return NULL;
}
err = FSpPathFromLocation(&fileSpec, &size, &pathString);
if ((err != noErr) && (err != fnfErr)) {
return NULL;
}
HLock(pathString);
f = fopen(*pathString, mode);
HUnlock(pathString);
DisposeHandle(pathString);
return f;
}
int
TclMacOSErrorToPosixError(
int error)
{
switch (error) {
case noErr:
return 0;
case bdNamErr:
return ENAMETOOLONG;
case afpObjectTypeErr:
return ENOTDIR;
case fnfErr:
case dirNFErr:
return ENOENT;
case dupFNErr:
return EEXIST;
case dirFulErr:
case dskFulErr:
return ENOSPC;
case fBsyErr:
return EBUSY;
case tmfoErr:
return ENFILE;
case fLckdErr:
case permErr:
case afpAccessDenied:
return EACCES;
case wPrErr:
case vLckdErr:
return EROFS;
case badMovErr:
return EINVAL;
case diffVolErr:
return EXDEV;
default:
return EINVAL;
}
}