#include "tclInt.h"
#include "tclPort.h"
static int NativeMatchType(CONST char* nativeName, Tcl_GlobTypeData *types);
char *
TclpFindExecutable(argv0)
CONST char *argv0;
{
CONST char *name, *p;
Tcl_StatBuf statBuf;
int length;
Tcl_DString buffer, nameString;
if (argv0 == NULL) {
return NULL;
}
if (tclNativeExecutableName != NULL) {
return tclNativeExecutableName;
}
Tcl_DStringInit(&buffer);
name = argv0;
for (p = name; *p != '\0'; p++) {
if (*p == '/') {
goto gotName;
}
}
p = getenv("PATH");
if (p == NULL) {
p = ":/bin:/usr/bin";
} else if (*p == '\0') {
p = "./";
}
while (1) {
while (isspace(UCHAR(*p))) {
p++;
}
name = p;
while ((*p != ':') && (*p != 0)) {
p++;
}
Tcl_DStringSetLength(&buffer, 0);
if (p != name) {
Tcl_DStringAppend(&buffer, name, p - name);
if (p[-1] != '/') {
Tcl_DStringAppend(&buffer, "/", 1);
}
}
name = Tcl_DStringAppend(&buffer, argv0, -1);
if ((access(name, X_OK) == 0)
&& (TclOSstat(name, &statBuf) == 0)
&& S_ISREG(statBuf.st_mode)) {
goto gotName;
}
if (*p == '\0') {
break;
} else if (*(p+1) == 0) {
p = "./";
} else {
p++;
}
}
goto done;
gotName:
#ifdef DJGPP
if (name[1] == ':') {
#else
if (name[0] == '/') {
#endif
Tcl_ExternalToUtfDString(NULL, name, -1, &nameString);
tclNativeExecutableName = (char *)
ckalloc((unsigned) (Tcl_DStringLength(&nameString) + 1));
strcpy(tclNativeExecutableName, Tcl_DStringValue(&nameString));
Tcl_DStringFree(&nameString);
goto done;
}
if ((name[0] == '.') && (name[1] == '/')) {
name += 2;
}
Tcl_ExternalToUtfDString(NULL, name, -1, &nameString);
Tcl_DStringFree(&buffer);
TclpGetCwd(NULL, &buffer);
length = Tcl_DStringLength(&buffer) + Tcl_DStringLength(&nameString) + 2;
tclNativeExecutableName = (char *) ckalloc((unsigned) length);
strcpy(tclNativeExecutableName, Tcl_DStringValue(&buffer));
tclNativeExecutableName[Tcl_DStringLength(&buffer)] = '/';
strcpy(tclNativeExecutableName + Tcl_DStringLength(&buffer) + 1,
Tcl_DStringValue(&nameString));
Tcl_DStringFree(&nameString);
done:
Tcl_DStringFree(&buffer);
return tclNativeExecutableName;
}
int
TclpMatchInDirectory(interp, resultPtr, pathPtr, pattern, types)
Tcl_Interp *interp;
Tcl_Obj *resultPtr;
Tcl_Obj *pathPtr;
CONST char *pattern;
Tcl_GlobTypeData *types;
{
CONST char *native;
Tcl_Obj *fileNamePtr;
fileNamePtr = Tcl_FSGetTranslatedPath(interp, pathPtr);
if (fileNamePtr == NULL) {
return TCL_ERROR;
}
if (pattern == NULL || (*pattern == '\0')) {
CONST char *native = (CONST char*) Tcl_FSGetNativePath(pathPtr);
if (NativeMatchType(native, types)) {
Tcl_ListObjAppendElement(interp, resultPtr, pathPtr);
}
return TCL_OK;
} else {
CONST char *fname, *dirName;
DIR *d;
Tcl_DString ds;
Tcl_StatBuf statBuf;
int matchHidden;
int nativeDirLen;
int result = TCL_OK;
Tcl_DString dsOrig;
int baseLength;
Tcl_DStringInit(&dsOrig);
Tcl_DStringAppend(&dsOrig, Tcl_GetString(fileNamePtr), -1);
baseLength = Tcl_DStringLength(&dsOrig);
if (baseLength == 0) {
dirName = ".";
} else {
dirName = Tcl_DStringValue(&dsOrig);
if (dirName[baseLength-1] != '/') {
dirName = Tcl_DStringAppend(&dsOrig, "/", 1);
baseLength++;
}
}
if ((pattern[0] == '.')
|| ((pattern[0] == '\\') && (pattern[1] == '.'))) {
matchHidden = 1;
} else {
matchHidden = 0;
}
native = Tcl_UtfToExternalDString(NULL, dirName, -1, &ds);
if ((TclOSstat(native, &statBuf) != 0)
|| !S_ISDIR(statBuf.st_mode)) {
Tcl_DStringFree(&dsOrig);
Tcl_DStringFree(&ds);
return TCL_OK;
}
d = opendir(native);
if (d == NULL) {
char savedChar = '\0';
Tcl_ResetResult(interp);
Tcl_DStringFree(&ds);
if (baseLength > 0) {
savedChar = (Tcl_DStringValue(&dsOrig))[baseLength-1];
if (savedChar == '/') {
(Tcl_DStringValue(&dsOrig))[baseLength-1] = '\0';
}
}
Tcl_AppendResult(interp, "couldn't read directory \"",
Tcl_DStringValue(&dsOrig), "\": ",
Tcl_PosixError(interp), (char *) NULL);
if (baseLength > 0) {
(Tcl_DStringValue(&dsOrig))[baseLength-1] = savedChar;
}
Tcl_DStringFree(&dsOrig);
return TCL_ERROR;
}
nativeDirLen = Tcl_DStringLength(&ds);
while (1) {
Tcl_DString utfDs;
CONST char *utf;
Tcl_DirEntry *entryPtr;
entryPtr = TclOSreaddir(d);
if (entryPtr == NULL) {
break;
}
if (types != NULL && (types->perm & TCL_GLOB_PERM_HIDDEN)) {
if (*entryPtr->d_name != '.') {
continue;
}
} else if (!matchHidden && (*entryPtr->d_name == '.')) {
continue;
}
utf = Tcl_ExternalToUtfDString(NULL, entryPtr->d_name, -1, &utfDs);
if (Tcl_StringMatch(utf, pattern) != 0) {
int typeOk = 1;
Tcl_DStringSetLength(&dsOrig, baseLength);
Tcl_DStringAppend(&dsOrig, utf, -1);
fname = Tcl_DStringValue(&dsOrig);
if (types != NULL) {
char *nativeEntry;
Tcl_DStringSetLength(&ds, nativeDirLen);
nativeEntry = Tcl_DStringAppend(&ds, entryPtr->d_name, -1);
typeOk = NativeMatchType(nativeEntry, types);
}
if (typeOk) {
Tcl_ListObjAppendElement(interp, resultPtr,
Tcl_NewStringObj(fname, Tcl_DStringLength(&dsOrig)));
}
}
Tcl_DStringFree(&utfDs);
}
closedir(d);
Tcl_DStringFree(&ds);
Tcl_DStringFree(&dsOrig);
return result;
}
}
static int
NativeMatchType(
CONST char* nativeEntry,
Tcl_GlobTypeData *types)
{
Tcl_StatBuf buf;
if (types == NULL) {
if (TclOSlstat(nativeEntry, &buf) != 0) {
return 0;
}
} else {
if (types->perm != 0) {
if (TclOSstat(nativeEntry, &buf) != 0) {
return 0;
}
if (((types->perm & TCL_GLOB_PERM_RONLY) &&
(buf.st_mode & (S_IWOTH|S_IWGRP|S_IWUSR))) ||
((types->perm & TCL_GLOB_PERM_R) &&
(access(nativeEntry, R_OK) != 0)) ||
((types->perm & TCL_GLOB_PERM_W) &&
(access(nativeEntry, W_OK) != 0)) ||
((types->perm & TCL_GLOB_PERM_X) &&
(access(nativeEntry, X_OK) != 0))
) {
return 0;
}
}
if (types->type != 0) {
if (types->perm == 0) {
if (TclOSstat(nativeEntry, &buf) != 0) {
return 0;
}
}
if (
((types->type & TCL_GLOB_TYPE_BLOCK) &&
S_ISBLK(buf.st_mode)) ||
((types->type & TCL_GLOB_TYPE_CHAR) &&
S_ISCHR(buf.st_mode)) ||
((types->type & TCL_GLOB_TYPE_DIR) &&
S_ISDIR(buf.st_mode)) ||
((types->type & TCL_GLOB_TYPE_PIPE) &&
S_ISFIFO(buf.st_mode)) ||
((types->type & TCL_GLOB_TYPE_FILE) &&
S_ISREG(buf.st_mode))
#ifdef S_ISSOCK
|| ((types->type & TCL_GLOB_TYPE_SOCK) &&
S_ISSOCK(buf.st_mode))
#endif
) {
} else {
#ifdef S_ISLNK
if (types->type & TCL_GLOB_TYPE_LINK) {
if (TclOSlstat(nativeEntry, &buf) == 0) {
if (S_ISLNK(buf.st_mode)) {
return 1;
}
}
}
#endif
return 0;
}
}
}
return 1;
}
char *
TclpGetUserHome(name, bufferPtr)
CONST char *name;
Tcl_DString *bufferPtr;
{
struct passwd *pwPtr;
Tcl_DString ds;
CONST char *native;
native = Tcl_UtfToExternalDString(NULL, name, -1, &ds);
pwPtr = getpwnam(native);
Tcl_DStringFree(&ds);
if (pwPtr == NULL) {
endpwent();
return NULL;
}
Tcl_ExternalToUtfDString(NULL, pwPtr->pw_dir, -1, bufferPtr);
endpwent();
return Tcl_DStringValue(bufferPtr);
}
int
TclpObjAccess(pathPtr, mode)
Tcl_Obj *pathPtr;
int mode;
{
CONST char *path = Tcl_FSGetNativePath(pathPtr);
if (path == NULL) {
return -1;
} else {
return access(path, mode);
}
}
int
TclpObjChdir(pathPtr)
Tcl_Obj *pathPtr;
{
CONST char *path = Tcl_FSGetNativePath(pathPtr);
if (path == NULL) {
return -1;
} else {
return chdir(path);
}
}
int
TclpObjLstat(pathPtr, bufPtr)
Tcl_Obj *pathPtr;
Tcl_StatBuf *bufPtr;
{
return TclOSlstat(Tcl_FSGetNativePath(pathPtr), bufPtr);
}
Tcl_Obj*
TclpObjGetCwd(interp)
Tcl_Interp *interp;
{
Tcl_DString ds;
if (TclpGetCwd(interp, &ds) != NULL) {
Tcl_Obj *cwdPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds), -1);
Tcl_IncrRefCount(cwdPtr);
Tcl_DStringFree(&ds);
return cwdPtr;
} else {
return NULL;
}
}
CONST char *
TclpGetCwd(interp, bufferPtr)
Tcl_Interp *interp;
Tcl_DString *bufferPtr;
{
char buffer[MAXPATHLEN+1];
#ifdef USEGETWD
if (getwd(buffer) == NULL) {
#else
if (getcwd(buffer, MAXPATHLEN + 1) == NULL) {
#endif
if (interp != NULL) {
Tcl_AppendResult(interp,
"error getting working directory name: ",
Tcl_PosixError(interp), (char *) NULL);
}
return NULL;
}
return Tcl_ExternalToUtfDString(NULL, buffer, -1, bufferPtr);
}
char *
TclpReadlink(path, linkPtr)
CONST char *path;
Tcl_DString *linkPtr;
{
#ifndef DJGPP
char link[MAXPATHLEN];
int length;
CONST char *native;
Tcl_DString ds;
native = Tcl_UtfToExternalDString(NULL, path, -1, &ds);
length = readlink(native, link, sizeof(link));
Tcl_DStringFree(&ds);
if (length < 0) {
return NULL;
}
Tcl_ExternalToUtfDString(NULL, link, length, linkPtr);
return Tcl_DStringValue(linkPtr);
#else
return NULL;
#endif
}
int
TclpObjStat(pathPtr, bufPtr)
Tcl_Obj *pathPtr;
Tcl_StatBuf *bufPtr;
{
CONST char *path = Tcl_FSGetNativePath(pathPtr);
if (path == NULL) {
return -1;
} else {
return TclOSstat(path, bufPtr);
}
}
#ifdef S_IFLNK
Tcl_Obj*
TclpObjLink(pathPtr, toPtr, linkAction)
Tcl_Obj *pathPtr;
Tcl_Obj *toPtr;
int linkAction;
{
if (toPtr != NULL) {
CONST char *src = Tcl_FSGetNativePath(pathPtr);
CONST char *target = Tcl_FSGetNativePath(toPtr);
if (src == NULL || target == NULL) {
return NULL;
}
if (access(src, F_OK) != -1) {
errno = EEXIST;
return NULL;
}
if (access(target, F_OK) == -1) {
errno = ENOENT;
return NULL;
}
if (linkAction & TCL_CREATE_SYMBOLIC_LINK) {
if (symlink(target, src) != 0) return NULL;
} else if (linkAction & TCL_CREATE_HARD_LINK) {
if (link(target, src) != 0) return NULL;
} else {
errno = ENODEV;
return NULL;
}
return toPtr;
} else {
Tcl_Obj* linkPtr = NULL;
char link[MAXPATHLEN];
int length;
Tcl_DString ds;
if (Tcl_FSGetTranslatedPath(NULL, pathPtr) == NULL) {
return NULL;
}
length = readlink(Tcl_FSGetNativePath(pathPtr), link, sizeof(link));
if (length < 0) {
return NULL;
}
Tcl_ExternalToUtfDString(NULL, link, length, &ds);
linkPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds),
Tcl_DStringLength(&ds));
Tcl_DStringFree(&ds);
if (linkPtr != NULL) {
Tcl_IncrRefCount(linkPtr);
}
return linkPtr;
}
}
#endif
Tcl_Obj*
TclpFilesystemPathType(pathObjPtr)
Tcl_Obj* pathObjPtr;
{
return NULL;
}