#include "tclInt.h"
#include "tclPort.h"
#include "tclRegexp.h"
#define MAC_UNDERSTANDS_UNIX_PATHS
#ifdef MAC_UNDERSTANDS_UNIX_PATHS
#define MAC_ROOT_PATTERN "^((/+([.][.]?/+)*([.][.]?)?)|(~[^:/]*)(/[^:]*)?|(~[^:]*)(:.*)?|/+([.][.]?/+)*([^:/]+)(/[^:]*)?|([^:]+):.*)$"
typedef struct ThreadSpecificData {
int initialized;
Tcl_Obj *macRootPatternPtr;
} ThreadSpecificData;
static Tcl_ThreadDataKey dataKey;
static void FileNameCleanup _ANSI_ARGS_((ClientData clientData));
static void FileNameInit _ANSI_ARGS_((void));
#endif
TclPlatformType tclPlatform = TCL_PLATFORM_UNIX;
static CONST char * DoTildeSubst _ANSI_ARGS_((Tcl_Interp *interp,
CONST char *user, Tcl_DString *resultPtr));
static CONST char * ExtractWinRoot _ANSI_ARGS_((CONST char *path,
Tcl_DString *resultPtr, int offset,
Tcl_PathType *typePtr));
static int SkipToChar _ANSI_ARGS_((char **stringPtr,
char *match));
static Tcl_Obj* SplitMacPath _ANSI_ARGS_((CONST char *path));
static Tcl_Obj* SplitWinPath _ANSI_ARGS_((CONST char *path));
static Tcl_Obj* SplitUnixPath _ANSI_ARGS_((CONST char *path));
#ifdef MAC_UNDERSTANDS_UNIX_PATHS
static void
FileNameInit()
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
if (!tsdPtr->initialized) {
tsdPtr->initialized = 1;
tsdPtr->macRootPatternPtr = Tcl_NewStringObj(MAC_ROOT_PATTERN, -1);
Tcl_CreateThreadExitHandler(FileNameCleanup, NULL);
}
}
static void
FileNameCleanup(clientData)
ClientData clientData;
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
Tcl_DecrRefCount(tsdPtr->macRootPatternPtr);
tsdPtr->initialized = 0;
}
#endif
static CONST char *
ExtractWinRoot(path, resultPtr, offset, typePtr)
CONST char *path;
Tcl_DString *resultPtr;
int offset;
Tcl_PathType *typePtr;
{
if (path[0] == '/' || path[0] == '\\') {
CONST char *host, *share, *tail;
int hlen, slen;
if (path[1] != '/' && path[1] != '\\') {
Tcl_DStringSetLength(resultPtr, offset);
*typePtr = TCL_PATH_VOLUME_RELATIVE;
Tcl_DStringAppend(resultPtr, "/", 1);
return &path[1];
}
host = &path[2];
while (host[0] == '/' || host[0] == '\\') host++;
for (hlen = 0; host[hlen];hlen++) {
if (host[hlen] == '/' || host[hlen] == '\\')
break;
}
if (host[hlen] == 0 || host[hlen+1] == 0) {
*typePtr = TCL_PATH_VOLUME_RELATIVE;
Tcl_DStringAppend(resultPtr, "/", 1);
return &path[2];
}
Tcl_DStringSetLength(resultPtr, offset);
share = &host[hlen];
while (share[0] == '/' || share[0] == '\\') share++;
for (slen = 0; share[slen];slen++) {
if (share[slen] == '/' || share[slen] == '\\')
break;
}
Tcl_DStringAppend(resultPtr, "//", 2);
Tcl_DStringAppend(resultPtr, host, hlen);
Tcl_DStringAppend(resultPtr, "/", 1);
Tcl_DStringAppend(resultPtr, share, slen);
tail = &share[slen];
while (tail[0] == '/' || tail[0] == '\\') tail++;
*typePtr = TCL_PATH_ABSOLUTE;
return tail;
} else if (*path && path[1] == ':') {
Tcl_DStringSetLength(resultPtr, offset);
if (path[2] != '/' && path[2] != '\\') {
*typePtr = TCL_PATH_VOLUME_RELATIVE;
Tcl_DStringAppend(resultPtr, path, 2);
return &path[2];
} else {
char *tail = (char*)&path[3];
while (*tail && (tail[0] == '/' || tail[0] == '\\')) tail++;
*typePtr = TCL_PATH_ABSOLUTE;
Tcl_DStringAppend(resultPtr, path, 2);
Tcl_DStringAppend(resultPtr, "/", 1);
return tail;
}
} else {
*typePtr = TCL_PATH_RELATIVE;
return path;
}
}
Tcl_PathType
Tcl_GetPathType(path)
CONST char *path;
{
Tcl_PathType type;
Tcl_Obj *tempObj = Tcl_NewStringObj(path,-1);
Tcl_IncrRefCount(tempObj);
type = Tcl_FSGetPathType(tempObj);
Tcl_DecrRefCount(tempObj);
return type;
}
Tcl_PathType
TclpGetNativePathType(pathObjPtr, driveNameLengthPtr, driveNameRef)
Tcl_Obj *pathObjPtr;
int *driveNameLengthPtr;
Tcl_Obj **driveNameRef;
{
Tcl_PathType type = TCL_PATH_ABSOLUTE;
int pathLen;
char *path = Tcl_GetStringFromObj(pathObjPtr, &pathLen);
if (path[0] == '~') {
if (driveNameLengthPtr != NULL) {
char *end = path + 1;
while ((*end != '\0') && (*end != '/')) {
end++;
}
*driveNameLengthPtr = end - path;
}
} else {
switch (tclPlatform) {
case TCL_PLATFORM_UNIX: {
char *origPath = path;
#ifdef __QNX__
if (*path && (pathLen > 3) && (path[0] == '/')
&& (path[1] == '/') && isdigit(UCHAR(path[2]))) {
path += 3;
while (isdigit(UCHAR(*path))) {
++path;
}
}
#endif
if (path[0] == '/') {
if (driveNameLengthPtr != NULL) {
*driveNameLengthPtr = (1 + path - origPath);
}
} else {
type = TCL_PATH_RELATIVE;
}
break;
}
case TCL_PLATFORM_MAC:
if (path[0] == ':') {
type = TCL_PATH_RELATIVE;
} else {
#ifdef MAC_UNDERSTANDS_UNIX_PATHS
ThreadSpecificData *tsdPtr;
Tcl_RegExp re;
tsdPtr = TCL_TSD_INIT(&dataKey);
FileNameInit();
re = Tcl_GetRegExpFromObj(NULL, tsdPtr->macRootPatternPtr,
REG_ADVANCED);
if (!Tcl_RegExpExec(NULL, re, path, path)) {
type = TCL_PATH_RELATIVE;
} else {
CONST char *root, *end;
Tcl_RegExpRange(re, 2, &root, &end);
if (root != NULL) {
type = TCL_PATH_RELATIVE;
} else {
if (driveNameLengthPtr != NULL) {
Tcl_RegExpRange(re, 0, &root, &end);
*driveNameLengthPtr = end - root;
}
if (driveNameRef != NULL) {
if (*root == '/') {
char *c;
int gotColon = 0;
*driveNameRef = Tcl_NewStringObj(root + 1,
end - root -1);
c = Tcl_GetString(*driveNameRef);
while (*c != '\0') {
if (*c == '/') {
gotColon++;
*c = ':';
}
c++;
}
if (gotColon == 0) {
Tcl_AppendToObj(*driveNameRef, ":", 1);
} else if ((gotColon > 1) &&
(*(c-1) == ':')) {
Tcl_SetObjLength(*driveNameRef,
c - Tcl_GetString(*driveNameRef) - 1);
}
}
}
}
}
#else
if (path[0] == '~') {
} else if (path[0] == ':') {
type = TCL_PATH_RELATIVE;
} else {
char *colonPos = strchr(path,':');
if (colonPos == NULL) {
type = TCL_PATH_RELATIVE;
} else {
}
}
if (type == TCL_PATH_ABSOLUTE) {
if (driveNameLengthPtr != NULL) {
*driveNameLengthPtr = strlen(path);
}
}
#endif
}
break;
case TCL_PLATFORM_WINDOWS: {
Tcl_DString ds;
CONST char *rootEnd;
Tcl_DStringInit(&ds);
rootEnd = ExtractWinRoot(path, &ds, 0, &type);
if ((rootEnd != path) && (driveNameLengthPtr != NULL)) {
*driveNameLengthPtr = rootEnd - path;
if (driveNameRef != NULL) {
*driveNameRef = Tcl_NewStringObj(Tcl_DStringValue(&ds),
Tcl_DStringLength(&ds));
Tcl_IncrRefCount(*driveNameRef);
}
}
Tcl_DStringFree(&ds);
break;
}
}
}
return type;
}
Tcl_Obj*
TclpNativeSplitPath(pathPtr, lenPtr)
Tcl_Obj *pathPtr;
int *lenPtr;
{
Tcl_Obj *resultPtr = NULL;
switch (tclPlatform) {
case TCL_PLATFORM_UNIX:
resultPtr = SplitUnixPath(Tcl_GetString(pathPtr));
break;
case TCL_PLATFORM_WINDOWS:
resultPtr = SplitWinPath(Tcl_GetString(pathPtr));
break;
case TCL_PLATFORM_MAC:
resultPtr = SplitMacPath(Tcl_GetString(pathPtr));
break;
}
if (lenPtr != NULL) {
Tcl_ListObjLength(NULL, resultPtr, lenPtr);
}
return resultPtr;
}
void
Tcl_SplitPath(path, argcPtr, argvPtr)
CONST char *path;
int *argcPtr;
CONST char ***argvPtr;
{
Tcl_Obj *resultPtr = NULL;
Tcl_Obj *tmpPtr, *eltPtr;
int i, size, len;
char *p, *str;
tmpPtr = Tcl_NewStringObj(path, -1);
Tcl_IncrRefCount(tmpPtr);
resultPtr = Tcl_FSSplitPath(tmpPtr, argcPtr);
Tcl_DecrRefCount(tmpPtr);
size = 1;
for (i = 0; i < *argcPtr; i++) {
Tcl_ListObjIndex(NULL, resultPtr, i, &eltPtr);
Tcl_GetStringFromObj(eltPtr, &len);
size += len + 1;
}
*argvPtr = (CONST char **) ckalloc((unsigned)
((((*argcPtr) + 1) * sizeof(char *)) + size));
p = (char *) &(*argvPtr)[(*argcPtr) + 1];
for (i = 0; i < *argcPtr; i++) {
Tcl_ListObjIndex(NULL, resultPtr, i, &eltPtr);
str = Tcl_GetStringFromObj(eltPtr, &len);
memcpy((VOID *) p, (VOID *) str, (size_t) len+1);
p += len+1;
}
p = (char *) &(*argvPtr)[(*argcPtr) + 1];
for (i = 0; i < *argcPtr; i++) {
(*argvPtr)[i] = p;
while ((*p++) != '\0') {}
}
(*argvPtr)[i] = NULL;
Tcl_DecrRefCount(resultPtr);
}
static Tcl_Obj*
SplitUnixPath(path)
CONST char *path;
{
int length;
CONST char *p, *elementStart;
Tcl_Obj *result = Tcl_NewObj();
#ifdef __QNX__
if ((path[0] == '/') && (path[1] == '/')
&& isdigit(UCHAR(path[2]))) {
path += 3;
while (isdigit(UCHAR(*path))) {
++path;
}
}
#endif
if (path[0] == '/') {
Tcl_ListObjAppendElement(NULL, result, Tcl_NewStringObj("/",1));
p = path+1;
} else {
p = path;
}
for (;;) {
elementStart = p;
while ((*p != '\0') && (*p != '/')) {
p++;
}
length = p - elementStart;
if (length > 0) {
Tcl_Obj *nextElt;
if ((elementStart[0] == '~') && (elementStart != path)) {
nextElt = Tcl_NewStringObj("./",2);
Tcl_AppendToObj(nextElt, elementStart, length);
} else {
nextElt = Tcl_NewStringObj(elementStart, length);
}
Tcl_ListObjAppendElement(NULL, result, nextElt);
}
if (*p++ == '\0') {
break;
}
}
return result;
}
static Tcl_Obj*
SplitWinPath(path)
CONST char *path;
{
int length;
CONST char *p, *elementStart;
Tcl_PathType type = TCL_PATH_ABSOLUTE;
Tcl_DString buf;
Tcl_Obj *result = Tcl_NewObj();
Tcl_DStringInit(&buf);
p = ExtractWinRoot(path, &buf, 0, &type);
if (p != path) {
Tcl_ListObjAppendElement(NULL, result,
Tcl_NewStringObj(Tcl_DStringValue(&buf),
Tcl_DStringLength(&buf)));
}
Tcl_DStringFree(&buf);
do {
elementStart = p;
while ((*p != '\0') && (*p != '/') && (*p != '\\')) {
p++;
}
length = p - elementStart;
if (length > 0) {
Tcl_Obj *nextElt;
if ((elementStart[0] == '~') && (elementStart != path)) {
nextElt = Tcl_NewStringObj("./",2);
Tcl_AppendToObj(nextElt, elementStart, length);
} else {
nextElt = Tcl_NewStringObj(elementStart, length);
}
Tcl_ListObjAppendElement(NULL, result, nextElt);
}
} while (*p++ != '\0');
return result;
}
static Tcl_Obj*
SplitMacPath(path)
CONST char *path;
{
int isMac = 0;
int length;
CONST char *p, *elementStart;
Tcl_Obj *result;
#ifdef MAC_UNDERSTANDS_UNIX_PATHS
Tcl_RegExp re;
int i;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
#endif
result = Tcl_NewObj();
#ifdef MAC_UNDERSTANDS_UNIX_PATHS
FileNameInit();
i = 0;
re = Tcl_GetRegExpFromObj(NULL, tsdPtr->macRootPatternPtr, REG_ADVANCED);
if (Tcl_RegExpExec(NULL, re, path, path) == 1) {
CONST char *start, *end;
Tcl_Obj *nextElt;
Tcl_RegExpRange(re, 2, &start, &end);
if (start) {
Tcl_Obj *elt = Tcl_NewStringObj(":", 1);
Tcl_RegExpRange(re, 0, &start, &end);
Tcl_AppendToObj(elt, path, end - start);
Tcl_ListObjAppendElement(NULL, result, elt);
return result;
}
Tcl_RegExpRange(re, 5, &start, &end);
if (start) {
isMac = 0;
i = 5;
} else {
Tcl_RegExpRange(re, 7, &start, &end);
if (start) {
isMac = 1;
i = 7;
} else {
Tcl_RegExpRange(re, 10, &start, &end);
if (start) {
isMac = 0;
i = 10;
} else {
Tcl_RegExpRange(re, 12, &start, &end);
if (start) {
isMac = 1;
i = 12;
}
}
}
}
Tcl_RegExpRange(re, i, &start, &end);
length = end - start;
nextElt = Tcl_NewStringObj(start, length);
Tcl_AppendToObj(nextElt, ":", 1);
Tcl_ListObjAppendElement(NULL, result, nextElt);
p = end;
} else {
isMac = (strchr(path, ':') != NULL);
p = path;
}
#else
if ((path[0] != ':') && (path[0] == '~' || (strchr(path,':') != NULL))) {
CONST char *end;
Tcl_Obj *nextElt;
isMac = 1;
end = strchr(path,':');
if (end == NULL) {
length = strlen(path);
} else {
length = end - path;
}
nextElt = Tcl_NewStringObj(path, length);
Tcl_AppendToObj(nextElt, ":", 1);
Tcl_ListObjAppendElement(NULL, result, nextElt);
p = path + length;
} else {
isMac = (strchr(path, ':') != NULL);
isMac = 1;
p = path;
}
#endif
if (isMac) {
elementStart = p;
if (*p == ':') {
p++;
}
while ((p = strchr(p, ':')) != NULL) {
length = p - elementStart;
if (length == 1) {
while (*p == ':') {
Tcl_ListObjAppendElement(NULL, result,
Tcl_NewStringObj("::", 2));
elementStart = p++;
}
} else {
if ((elementStart[1] != '~')
&& (strchr(elementStart+1, '/') == NULL)) {
elementStart++;
length--;
}
Tcl_ListObjAppendElement(NULL, result,
Tcl_NewStringObj(elementStart, length));
elementStart = p++;
}
}
if (elementStart[0] != ':') {
if (elementStart[0] != '\0') {
Tcl_ListObjAppendElement(NULL, result,
Tcl_NewStringObj(elementStart, -1));
}
} else {
if (elementStart[1] != '\0' || elementStart == path) {
if ((elementStart[1] != '~') && (elementStart[1] != '\0')
&& (strchr(elementStart+1, '/') == NULL)) {
elementStart++;
}
Tcl_ListObjAppendElement(NULL, result,
Tcl_NewStringObj(elementStart, -1));
}
}
} else {
for (;;) {
elementStart = p;
while ((*p != '\0') && (*p != '/')) {
p++;
}
length = p - elementStart;
if (length > 0) {
if ((length == 1) && (elementStart[0] == '.')) {
Tcl_ListObjAppendElement(NULL, result,
Tcl_NewStringObj(":", 1));
} else if ((length == 2) && (elementStart[0] == '.')
&& (elementStart[1] == '.')) {
Tcl_ListObjAppendElement(NULL, result,
Tcl_NewStringObj("::", 2));
} else {
Tcl_Obj *nextElt;
if (*elementStart == '~') {
nextElt = Tcl_NewStringObj(":",1);
Tcl_AppendToObj(nextElt, elementStart, length);
} else {
nextElt = Tcl_NewStringObj(elementStart, length);
}
Tcl_ListObjAppendElement(NULL, result, nextElt);
}
}
if (*p++ == '\0') {
break;
}
}
}
return result;
}
Tcl_Obj*
Tcl_FSJoinToPath(basePtr, objc, objv)
Tcl_Obj *basePtr;
int objc;
Tcl_Obj *CONST objv[];
{
int i;
Tcl_Obj *lobj, *ret;
if (basePtr == NULL) {
lobj = Tcl_NewListObj(0, NULL);
} else {
lobj = Tcl_NewListObj(1, &basePtr);
}
for (i = 0; i<objc;i++) {
Tcl_ListObjAppendElement(NULL, lobj, objv[i]);
}
ret = Tcl_FSJoinPath(lobj, -1);
Tcl_DecrRefCount(lobj);
return ret;
}
void
TclpNativeJoinPath(prefix, joining)
Tcl_Obj *prefix;
char* joining;
{
int length, needsSep;
char *dest, *p, *start;
start = Tcl_GetStringFromObj(prefix, &length);
p = joining;
if (length != 0) {
if ((p[0] == '.') && (p[1] == '/') && (p[2] == '~')) {
p += 2;
}
}
if (*p == '\0') {
return;
}
switch (tclPlatform) {
case TCL_PLATFORM_UNIX:
if (length > 0 && (start[length-1] != '/')) {
Tcl_AppendToObj(prefix, "/", 1);
length++;
}
needsSep = 0;
Tcl_SetObjLength(prefix, length + (int) strlen(p));
dest = Tcl_GetString(prefix) + length;
for (; *p != '\0'; p++) {
if (*p == '/') {
while (p[1] == '/') {
p++;
}
if (p[1] != '\0') {
if (needsSep) {
*dest++ = '/';
}
}
} else {
*dest++ = *p;
needsSep = 1;
}
}
length = dest - Tcl_GetString(prefix);
Tcl_SetObjLength(prefix, length);
break;
case TCL_PLATFORM_WINDOWS:
if ((length > 0) &&
(start[length-1] != '/') && (start[length-1] != ':')) {
Tcl_AppendToObj(prefix, "/", 1);
length++;
}
needsSep = 0;
Tcl_SetObjLength(prefix, length + (int) strlen(p));
dest = Tcl_GetString(prefix) + length;
for (; *p != '\0'; p++) {
if ((*p == '/') || (*p == '\\')) {
while ((p[1] == '/') || (p[1] == '\\')) {
p++;
}
if ((p[1] != '\0') && needsSep) {
*dest++ = '/';
}
} else {
*dest++ = *p;
needsSep = 1;
}
}
length = dest - Tcl_GetString(prefix);
Tcl_SetObjLength(prefix, length);
break;
case TCL_PLATFORM_MAC: {
int newLength;
#ifdef MAC_UNDERSTANDS_UNIX_PATHS
int adjustedPath = 0;
if ((strchr(p, ':') == NULL) && (strchr(p, '/') != NULL)) {
char *start = p;
adjustedPath = 1;
while (*start != '\0') {
if (*start == '/') {
*start = ':';
}
start++;
}
}
#endif
if (length > 0) {
if ((p[0] == ':') && (p[1] == '\0')) {
return;
}
if (start[length-1] != ':') {
if (*p != '\0' && *p != ':') {
Tcl_AppendToObj(prefix, ":", 1);
length++;
}
} else if (*p == ':') {
p++;
}
} else {
if (*p != '\0' && *p != ':') {
Tcl_AppendToObj(prefix, ":", 1);
length++;
}
}
newLength = strlen(p);
Tcl_AppendToObj(prefix, p, newLength);
dest = Tcl_GetString(prefix) + length + newLength;
if (*(dest-1) == ':') {
if (dest-1 > Tcl_GetString(prefix)) {
if (*(dest-2) != ':') {
Tcl_SetObjLength(prefix, length + newLength -1);
}
}
}
#ifdef MAC_UNDERSTANDS_UNIX_PATHS
if (adjustedPath) {
char *start = joining;
while (*start != '\0') {
if (*start == ':') {
*start = '/';
}
start++;
}
}
#endif
break;
}
}
return;
}
char *
Tcl_JoinPath(argc, argv, resultPtr)
int argc;
CONST char * CONST *argv;
Tcl_DString *resultPtr;
{
int i, len;
Tcl_Obj *listObj = Tcl_NewObj();
Tcl_Obj *resultObj;
char *resultStr;
for (i = 0; i < argc; i++) {
Tcl_ListObjAppendElement(NULL, listObj,
Tcl_NewStringObj(argv[i], -1));
}
Tcl_IncrRefCount(listObj);
resultObj = Tcl_FSJoinPath(listObj, argc);
Tcl_IncrRefCount(resultObj);
Tcl_DecrRefCount(listObj);
resultStr = Tcl_GetStringFromObj(resultObj, &len);
Tcl_DStringAppend(resultPtr, resultStr, len);
Tcl_DecrRefCount(resultObj);
return Tcl_DStringValue(resultPtr);
}
char *
Tcl_TranslateFileName(interp, name, bufferPtr)
Tcl_Interp *interp;
CONST char *name;
Tcl_DString *bufferPtr;
{
Tcl_Obj *path = Tcl_NewStringObj(name, -1);
CONST char *result;
Tcl_IncrRefCount(path);
result = Tcl_FSGetTranslatedStringPath(interp, path);
if (result == NULL) {
Tcl_DecrRefCount(path);
return NULL;
}
Tcl_DStringInit(bufferPtr);
Tcl_DStringAppend(bufferPtr, result, -1);
Tcl_DecrRefCount(path);
if (tclPlatform == TCL_PLATFORM_WINDOWS) {
#if defined(__CYGWIN__) && defined(__WIN32__)
extern int cygwin_conv_to_win32_path
_ANSI_ARGS_((CONST char *, char *));
char winbuf[MAX_PATH];
if (Tcl_DStringLength(bufferPtr)) {
cygwin_conv_to_win32_path(Tcl_DStringValue(bufferPtr), winbuf);
Tcl_DStringFree(bufferPtr);
Tcl_DStringAppend(bufferPtr, winbuf, -1);
}
#else
register char *p;
for (p = Tcl_DStringValue(bufferPtr); *p != '\0'; p++) {
if (*p == '/') {
*p = '\\';
}
}
#endif
}
return Tcl_DStringValue(bufferPtr);
}
char *
TclGetExtension(name)
char *name;
{
char *p, *lastSep;
lastSep = NULL;
switch (tclPlatform) {
case TCL_PLATFORM_UNIX:
lastSep = strrchr(name, '/');
break;
case TCL_PLATFORM_MAC:
#ifdef MAC_UNDERSTANDS_UNIX_PATHS
if (strchr(name, ':') == NULL) {
lastSep = strrchr(name, '/');
} else {
lastSep = strrchr(name, ':');
}
#else
lastSep = strrchr(name, ':');
#endif
break;
case TCL_PLATFORM_WINDOWS:
lastSep = NULL;
for (p = name; *p != '\0'; p++) {
if (strchr("/\\:", *p) != NULL) {
lastSep = p;
}
}
break;
}
p = strrchr(name, '.');
if ((p != NULL) && (lastSep != NULL) && (lastSep > p)) {
p = NULL;
}
return p;
}
static CONST char *
DoTildeSubst(interp, user, resultPtr)
Tcl_Interp *interp;
CONST char *user;
Tcl_DString *resultPtr;
{
CONST char *dir;
if (*user == '\0') {
Tcl_DString dirString;
dir = TclGetEnv("HOME", &dirString);
if (dir == NULL) {
if (interp) {
Tcl_ResetResult(interp);
Tcl_AppendResult(interp, "couldn't find HOME environment ",
"variable to expand path", (char *) NULL);
}
return NULL;
}
Tcl_JoinPath(1, &dir, resultPtr);
Tcl_DStringFree(&dirString);
} else {
if (TclpGetUserHome(user, resultPtr) == NULL) {
if (interp) {
Tcl_ResetResult(interp);
Tcl_AppendResult(interp, "user \"", user, "\" doesn't exist",
(char *) NULL);
}
return NULL;
}
}
return Tcl_DStringValue(resultPtr);
}
int
Tcl_GlobObjCmd(dummy, interp, objc, objv)
ClientData dummy;
Tcl_Interp *interp;
int objc;
Tcl_Obj *CONST objv[];
{
int index, i, globFlags, length, join, dir, result;
char *string, *separators;
Tcl_Obj *typePtr, *resultPtr, *look;
Tcl_Obj *pathOrDir = NULL;
Tcl_DString prefix;
static CONST char *options[] = {
"-directory", "-join", "-nocomplain", "-path", "-tails",
"-types", "--", NULL
};
enum options {
GLOB_DIR, GLOB_JOIN, GLOB_NOCOMPLAIN, GLOB_PATH, GLOB_TAILS,
GLOB_TYPE, GLOB_LAST
};
enum pathDirOptions {PATH_NONE = -1 , PATH_GENERAL = 0, PATH_DIR = 1};
Tcl_GlobTypeData *globTypes = NULL;
globFlags = 0;
join = 0;
dir = PATH_NONE;
typePtr = NULL;
resultPtr = Tcl_GetObjResult(interp);
for (i = 1; i < objc; i++) {
if (Tcl_GetIndexFromObj(interp, objv[i], options, "option", 0, &index)
!= TCL_OK) {
string = Tcl_GetStringFromObj(objv[i], &length);
if (string[0] == '-') {
return TCL_ERROR;
} else {
Tcl_ResetResult(interp);
break;
}
}
switch (index) {
case GLOB_NOCOMPLAIN:
globFlags |= TCL_GLOBMODE_NO_COMPLAIN;
break;
case GLOB_DIR:
if (i == (objc-1)) {
Tcl_AppendToObj(resultPtr,
"missing argument to \"-directory\"", -1);
return TCL_ERROR;
}
if (dir != PATH_NONE) {
Tcl_AppendToObj(resultPtr,
"\"-directory\" cannot be used with \"-path\"",
-1);
return TCL_ERROR;
}
dir = PATH_DIR;
globFlags |= TCL_GLOBMODE_DIR;
pathOrDir = objv[i+1];
i++;
break;
case GLOB_JOIN:
join = 1;
break;
case GLOB_TAILS:
globFlags |= TCL_GLOBMODE_TAILS;
break;
case GLOB_PATH:
if (i == (objc-1)) {
Tcl_AppendToObj(resultPtr,
"missing argument to \"-path\"", -1);
return TCL_ERROR;
}
if (dir != PATH_NONE) {
Tcl_AppendToObj(resultPtr,
"\"-path\" cannot be used with \"-directory\"",
-1);
return TCL_ERROR;
}
dir = PATH_GENERAL;
pathOrDir = objv[i+1];
i++;
break;
case GLOB_TYPE:
if (i == (objc-1)) {
Tcl_AppendToObj(resultPtr,
"missing argument to \"-types\"", -1);
return TCL_ERROR;
}
typePtr = objv[i+1];
if (Tcl_ListObjLength(interp, typePtr, &length) != TCL_OK) {
return TCL_ERROR;
}
i++;
break;
case GLOB_LAST:
i++;
goto endOfForLoop;
break;
}
}
endOfForLoop:
if (objc - i < 1) {
Tcl_WrongNumArgs(interp, 1, objv, "?switches? name ?name ...?");
return TCL_ERROR;
}
if ((globFlags & TCL_GLOBMODE_TAILS) && (pathOrDir == NULL)) {
Tcl_AppendToObj(resultPtr,
"\"-tails\" must be used with either \"-directory\" or \"-path\"",
-1);
return TCL_ERROR;
}
separators = NULL;
switch (tclPlatform) {
case TCL_PLATFORM_UNIX:
separators = "/";
break;
case TCL_PLATFORM_WINDOWS:
separators = "/\\:";
break;
case TCL_PLATFORM_MAC:
separators = ":";
break;
}
if (dir == PATH_GENERAL) {
int pathlength;
char *last;
char *first = Tcl_GetStringFromObj(pathOrDir,&pathlength);
last = first + pathlength;
for (; last != first; last--) {
if (strchr(separators, *(last-1)) != NULL) {
break;
}
}
if (last == first + pathlength) {
dir = PATH_DIR;
} else {
Tcl_DString pref;
char *search, *find;
Tcl_DStringInit(&pref);
if (last == first) {
Tcl_DStringAppend(&pref, first, -1);
pathOrDir = NULL;
} else {
Tcl_DStringAppend(&pref, last, first+pathlength-last);
pathOrDir = Tcl_NewStringObj(first, last-first-1);
}
Tcl_DStringInit(&prefix);
search = Tcl_DStringValue(&pref);
while ((find = (strpbrk(search, "\\[]*?{}"))) != NULL) {
Tcl_DStringAppend(&prefix, search, find-search);
Tcl_DStringAppend(&prefix, "\\", 1);
Tcl_DStringAppend(&prefix, find, 1);
search = find+1;
if (*search == '\0') {
break;
}
}
if (*search != '\0') {
Tcl_DStringAppend(&prefix, search, -1);
}
Tcl_DStringFree(&pref);
}
}
if (pathOrDir != NULL) {
Tcl_IncrRefCount(pathOrDir);
}
if (typePtr != NULL) {
Tcl_ListObjLength(interp, typePtr, &length);
globTypes = (Tcl_GlobTypeData*) ckalloc(sizeof(Tcl_GlobTypeData));
globTypes->type = 0;
globTypes->perm = 0;
globTypes->macType = NULL;
globTypes->macCreator = NULL;
while(--length >= 0) {
int len;
char *str;
Tcl_ListObjIndex(interp, typePtr, length, &look);
str = Tcl_GetStringFromObj(look, &len);
if (strcmp("readonly", str) == 0) {
globTypes->perm |= TCL_GLOB_PERM_RONLY;
} else if (strcmp("hidden", str) == 0) {
globTypes->perm |= TCL_GLOB_PERM_HIDDEN;
} else if (len == 1) {
switch (str[0]) {
case 'r':
globTypes->perm |= TCL_GLOB_PERM_R;
break;
case 'w':
globTypes->perm |= TCL_GLOB_PERM_W;
break;
case 'x':
globTypes->perm |= TCL_GLOB_PERM_X;
break;
case 'b':
globTypes->type |= TCL_GLOB_TYPE_BLOCK;
break;
case 'c':
globTypes->type |= TCL_GLOB_TYPE_CHAR;
break;
case 'd':
globTypes->type |= TCL_GLOB_TYPE_DIR;
break;
case 'p':
globTypes->type |= TCL_GLOB_TYPE_PIPE;
break;
case 'f':
globTypes->type |= TCL_GLOB_TYPE_FILE;
break;
case 'l':
globTypes->type |= TCL_GLOB_TYPE_LINK;
break;
case 's':
globTypes->type |= TCL_GLOB_TYPE_SOCK;
break;
default:
goto badTypesArg;
}
} else if (len == 4) {
if (globTypes->macType != NULL) {
goto badMacTypesArg;
}
globTypes->macType = look;
Tcl_IncrRefCount(look);
} else {
Tcl_Obj* item;
if ((Tcl_ListObjLength(NULL, look, &len) == TCL_OK) &&
(len == 3)) {
Tcl_ListObjIndex(interp, look, 0, &item);
if (!strcmp("macintosh", Tcl_GetString(item))) {
Tcl_ListObjIndex(interp, look, 1, &item);
if (!strcmp("type", Tcl_GetString(item))) {
Tcl_ListObjIndex(interp, look, 2, &item);
if (globTypes->macType != NULL) {
goto badMacTypesArg;
}
globTypes->macType = item;
Tcl_IncrRefCount(item);
continue;
} else if (!strcmp("creator", Tcl_GetString(item))) {
Tcl_ListObjIndex(interp, look, 2, &item);
if (globTypes->macCreator != NULL) {
goto badMacTypesArg;
}
globTypes->macCreator = item;
Tcl_IncrRefCount(item);
continue;
}
}
}
badTypesArg:
resultPtr = Tcl_GetObjResult(interp);
Tcl_AppendToObj(resultPtr, "bad argument to \"-types\": ", -1);
Tcl_AppendObjToObj(resultPtr, look);
result = TCL_ERROR;
join = 0;
goto endOfGlob;
badMacTypesArg:
resultPtr = Tcl_GetObjResult(interp);
Tcl_AppendToObj(resultPtr,
"only one MacOS type or creator argument"
" to \"-types\" allowed", -1);
result = TCL_ERROR;
join = 0;
goto endOfGlob;
}
}
}
objc -= i;
objv += i;
resultPtr = Tcl_GetObjResult(interp);
result = TCL_OK;
if (join) {
if (dir != PATH_GENERAL) {
Tcl_DStringInit(&prefix);
}
for (i = 0; i < objc; i++) {
string = Tcl_GetStringFromObj(objv[i], &length);
Tcl_DStringAppend(&prefix, string, length);
if (i != objc -1) {
Tcl_DStringAppend(&prefix, separators, 1);
}
}
if (TclGlob(interp, Tcl_DStringValue(&prefix), pathOrDir,
globFlags, globTypes) != TCL_OK) {
result = TCL_ERROR;
goto endOfGlob;
}
} else {
if (dir == PATH_GENERAL) {
Tcl_DString str;
for (i = 0; i < objc; i++) {
Tcl_DStringInit(&str);
if (dir == PATH_GENERAL) {
Tcl_DStringAppend(&str, Tcl_DStringValue(&prefix),
Tcl_DStringLength(&prefix));
}
string = Tcl_GetStringFromObj(objv[i], &length);
Tcl_DStringAppend(&str, string, length);
if (TclGlob(interp, Tcl_DStringValue(&str), pathOrDir,
globFlags, globTypes) != TCL_OK) {
result = TCL_ERROR;
Tcl_DStringFree(&str);
goto endOfGlob;
}
}
Tcl_DStringFree(&str);
} else {
for (i = 0; i < objc; i++) {
string = Tcl_GetString(objv[i]);
if (TclGlob(interp, string, pathOrDir,
globFlags, globTypes) != TCL_OK) {
result = TCL_ERROR;
goto endOfGlob;
}
}
}
}
if ((globFlags & TCL_GLOBMODE_NO_COMPLAIN) == 0) {
if (Tcl_ListObjLength(interp, Tcl_GetObjResult(interp),
&length) != TCL_OK) {
result = TCL_ERROR;
goto endOfGlob;
}
if (length == 0) {
Tcl_AppendResult(interp, "no files matched glob pattern",
(join || (objc == 1)) ? " \"" : "s \"", (char *) NULL);
if (join) {
Tcl_AppendResult(interp, Tcl_DStringValue(&prefix),
(char *) NULL);
} else {
char *sep = "";
for (i = 0; i < objc; i++) {
string = Tcl_GetString(objv[i]);
Tcl_AppendResult(interp, sep, string, (char *) NULL);
sep = " ";
}
}
Tcl_AppendResult(interp, "\"", (char *) NULL);
result = TCL_ERROR;
}
}
endOfGlob:
if (join || (dir == PATH_GENERAL)) {
Tcl_DStringFree(&prefix);
}
if (pathOrDir != NULL) {
Tcl_DecrRefCount(pathOrDir);
}
if (globTypes != NULL) {
if (globTypes->macType != NULL) {
Tcl_DecrRefCount(globTypes->macType);
}
if (globTypes->macCreator != NULL) {
Tcl_DecrRefCount(globTypes->macCreator);
}
ckfree((char *) globTypes);
}
return result;
}
int
TclGlob(interp, pattern, unquotedPrefix, globFlags, types)
Tcl_Interp *interp;
char *pattern;
Tcl_Obj *unquotedPrefix;
int globFlags;
Tcl_GlobTypeData *types;
{
char *separators;
CONST char *head;
char *tail, *start;
char c;
int result, prefixLen;
Tcl_DString buffer;
Tcl_Obj *oldResult;
separators = NULL;
switch (tclPlatform) {
case TCL_PLATFORM_UNIX:
separators = "/";
break;
case TCL_PLATFORM_WINDOWS:
separators = "/\\:";
break;
case TCL_PLATFORM_MAC:
#ifdef MAC_UNDERSTANDS_UNIX_PATHS
if (unquotedPrefix == NULL) {
separators = (strchr(pattern, ':') == NULL) ? "/" : ":";
} else {
separators = ":";
}
#else
separators = ":";
#endif
break;
}
Tcl_DStringInit(&buffer);
if (unquotedPrefix != NULL) {
start = Tcl_GetString(unquotedPrefix);
} else {
start = pattern;
}
if (start[0] == '~') {
for (tail = start; *tail != '\0'; tail++) {
if (*tail == '\\') {
if (strchr(separators, tail[1]) != NULL) {
break;
}
} else if (strchr(separators, *tail) != NULL) {
break;
}
}
c = *tail;
*tail = '\0';
if (globFlags & TCL_GLOBMODE_NO_COMPLAIN) {
head = DoTildeSubst(NULL, start+1, &buffer);
} else {
head = DoTildeSubst(interp, start+1, &buffer);
}
*tail = c;
if (head == NULL) {
if (globFlags & TCL_GLOBMODE_NO_COMPLAIN) {
return TCL_OK;
} else {
return TCL_ERROR;
}
}
if (head != Tcl_DStringValue(&buffer)) {
Tcl_DStringAppend(&buffer, head, -1);
}
if (unquotedPrefix != NULL) {
Tcl_DStringAppend(&buffer, tail, -1);
tail = pattern;
}
} else {
tail = pattern;
if (unquotedPrefix != NULL) {
Tcl_DStringAppend(&buffer,Tcl_GetString(unquotedPrefix),-1);
}
}
prefixLen = Tcl_DStringLength(&buffer);
if (prefixLen > 0) {
c = Tcl_DStringValue(&buffer)[prefixLen-1];
if (strchr(separators, c) == NULL) {
if (globFlags & TCL_GLOBMODE_DIR) {
Tcl_DStringAppend(&buffer,separators,1);
}
prefixLen++;
}
}
oldResult = Tcl_GetObjResult(interp);
Tcl_IncrRefCount(oldResult);
Tcl_ResetResult(interp);
result = TclDoGlob(interp, separators, &buffer, tail, types);
if (result != TCL_OK) {
if (globFlags & TCL_GLOBMODE_NO_COMPLAIN) {
Tcl_SetObjResult(interp, oldResult);
result = TCL_OK;
}
} else {
int objc, i;
Tcl_Obj **objv;
if (Tcl_IsShared(oldResult)) {
Tcl_DecrRefCount(oldResult);
oldResult = Tcl_DuplicateObj(oldResult);
Tcl_IncrRefCount(oldResult);
}
Tcl_ListObjGetElements(NULL, Tcl_GetObjResult(interp),
&objc, &objv);
#ifdef MAC_TCL
if ((prefixLen > 0) && (objc > 0)
&& (Tcl_DStringValue(&buffer)[0] != ':')) {
char *str = Tcl_GetStringFromObj(objv[0],NULL);
if (str[0] == ':') {
prefixLen++;
}
}
#endif
for (i = 0; i< objc; i++) {
Tcl_Obj* elt;
if (globFlags & TCL_GLOBMODE_TAILS) {
int len;
char *oldStr = Tcl_GetStringFromObj(objv[i],&len);
if (len == prefixLen) {
if ((pattern[0] == '\0')
|| (strchr(separators, pattern[0]) == NULL)) {
elt = Tcl_NewStringObj(".",1);
} else {
elt = Tcl_NewStringObj("/",1);
}
} else {
elt = Tcl_NewStringObj(oldStr + prefixLen,
len - prefixLen);
}
} else {
elt = objv[i];
}
Tcl_ListObjAppendElement(interp, oldResult, elt);
}
Tcl_SetObjResult(interp, oldResult);
}
Tcl_DecrRefCount(oldResult);
Tcl_DStringFree(&buffer);
return result;
}
static int
SkipToChar(stringPtr, match)
char **stringPtr;
char *match;
{
int quoted, level;
register char *p;
quoted = 0;
level = 0;
for (p = *stringPtr; *p != '\0'; p++) {
if (quoted) {
quoted = 0;
continue;
}
if ((level == 0) && (*p == *match)) {
*stringPtr = p;
return 1;
}
if (*p == '{') {
level++;
} else if (*p == '}') {
level--;
} else if (*p == '\\') {
quoted = 1;
}
}
*stringPtr = p;
return 0;
}
int
TclDoGlob(interp, separators, headPtr, tail, types)
Tcl_Interp *interp;
char *separators;
Tcl_DString *headPtr;
char *tail;
Tcl_GlobTypeData *types;
{
int baseLength, quoted, count;
int result = TCL_OK;
char *name, *p, *openBrace, *closeBrace, *firstSpecialChar, savedChar;
char lastChar = 0;
int length = Tcl_DStringLength(headPtr);
if (length > 0) {
lastChar = Tcl_DStringValue(headPtr)[length-1];
}
count = 0;
name = tail;
for (; *tail != '\0'; tail++) {
if ((*tail == '\\') && (strchr(separators, tail[1]) != NULL)) {
tail++;
} else if (strchr(separators, *tail) == NULL) {
break;
}
count++;
}
switch (tclPlatform) {
case TCL_PLATFORM_MAC:
#ifdef MAC_UNDERSTANDS_UNIX_PATHS
if (*separators == '/') {
if (((length == 0) && (count == 0))
|| ((length > 0) && (lastChar != ':'))) {
Tcl_DStringAppend(headPtr, ":", 1);
}
} else {
#endif
if (count == 0) {
if ((length > 0) && (lastChar != ':')) {
Tcl_DStringAppend(headPtr, ":", 1);
}
} else {
if (lastChar == ':') {
count--;
}
while (count-- > 0) {
Tcl_DStringAppend(headPtr, ":", 1);
}
}
#ifdef MAC_UNDERSTANDS_UNIX_PATHS
}
#endif
break;
case TCL_PLATFORM_WINDOWS:
#if defined(__CYGWIN__) && defined(__WIN32__)
{
extern int cygwin_conv_to_win32_path
_ANSI_ARGS_((CONST char *, char *));
char winbuf[MAX_PATH];
cygwin_conv_to_win32_path(Tcl_DStringValue(headPtr), winbuf);
Tcl_DStringFree(headPtr);
Tcl_DStringAppend(headPtr, winbuf, -1);
}
#endif
if (*name == ':') {
Tcl_DStringAppend(headPtr, ":", 1);
if (count > 1) {
Tcl_DStringAppend(headPtr, "/", 1);
}
} else if ((*tail != '\0')
&& (((length > 0)
&& (strchr(separators, lastChar) == NULL))
|| ((length == 0) && (count > 0)))) {
Tcl_DStringAppend(headPtr, "/", 1);
if ((length == 0) && (count > 1)) {
Tcl_DStringAppend(headPtr, "/", 1);
}
}
break;
case TCL_PLATFORM_UNIX:
if ((*tail != '\0')
&& (((length > 0)
&& (strchr(separators, lastChar) == NULL))
|| ((length == 0) && (count > 0)))) {
Tcl_DStringAppend(headPtr, "/", 1);
}
break;
}
openBrace = closeBrace = NULL;
quoted = 0;
for (p = tail; *p != '\0'; p++) {
if (quoted) {
quoted = 0;
} else if (*p == '\\') {
quoted = 1;
if (strchr(separators, p[1]) != NULL) {
break;
}
} else if (strchr(separators, *p) != NULL) {
break;
} else if (*p == '{') {
openBrace = p;
p++;
if (SkipToChar(&p, "}")) {
closeBrace = p;
break;
}
Tcl_SetResult(interp, "unmatched open-brace in file name",
TCL_STATIC);
return TCL_ERROR;
} else if (*p == '}') {
Tcl_SetResult(interp, "unmatched close-brace in file name",
TCL_STATIC);
return TCL_ERROR;
}
}
if (openBrace != NULL) {
char *element;
Tcl_DString newName;
Tcl_DStringInit(&newName);
Tcl_DStringAppend(&newName, tail, openBrace-tail);
baseLength = Tcl_DStringLength(&newName);
length = Tcl_DStringLength(headPtr);
*closeBrace = '\0';
for (p = openBrace; p != closeBrace; ) {
p++;
element = p;
SkipToChar(&p, ",");
Tcl_DStringSetLength(headPtr, length);
Tcl_DStringSetLength(&newName, baseLength);
Tcl_DStringAppend(&newName, element, p-element);
Tcl_DStringAppend(&newName, closeBrace+1, -1);
result = TclDoGlob(interp, separators, headPtr,
Tcl_DStringValue(&newName), types);
if (result != TCL_OK) {
break;
}
}
*closeBrace = '}';
Tcl_DStringFree(&newName);
return result;
}
if (*p != '\0') {
savedChar = *p;
*p = '\0';
firstSpecialChar = strpbrk(tail, "*[]?\\");
*p = savedChar;
} else {
firstSpecialChar = strpbrk(tail, "*[]?\\");
}
if (firstSpecialChar != NULL) {
int ret;
Tcl_Obj *head = Tcl_NewStringObj(Tcl_DStringValue(headPtr),-1);
Tcl_IncrRefCount(head);
if (*p == '\0') {
ret = Tcl_FSMatchInDirectory(interp, Tcl_GetObjResult(interp),
head, tail, types);
} else {
Tcl_Obj* resultPtr;
Tcl_GlobTypeData dirOnly = { TCL_GLOB_TYPE_DIR, 0, NULL, NULL };
char save = *p;
*p = '\0';
resultPtr = Tcl_NewListObj(0, NULL);
ret = Tcl_FSMatchInDirectory(interp, resultPtr,
head, tail, &dirOnly);
*p = save;
if (ret == TCL_OK) {
int resLength;
ret = Tcl_ListObjLength(interp, resultPtr, &resLength);
if (ret == TCL_OK) {
int i;
for (i =0; i< resLength; i++) {
Tcl_Obj *elt;
Tcl_DString ds;
Tcl_ListObjIndex(interp, resultPtr, i, &elt);
Tcl_DStringInit(&ds);
Tcl_DStringAppend(&ds, Tcl_GetString(elt), -1);
if(tclPlatform == TCL_PLATFORM_MAC) {
Tcl_DStringAppend(&ds, ":",1);
} else {
Tcl_DStringAppend(&ds, "/",1);
}
ret = TclDoGlob(interp, separators, &ds, p+1, types);
Tcl_DStringFree(&ds);
if (ret != TCL_OK) {
break;
}
}
}
}
Tcl_DecrRefCount(resultPtr);
}
Tcl_DecrRefCount(head);
return ret;
}
Tcl_DStringAppend(headPtr, tail, p-tail);
if (*p != '\0') {
return TclDoGlob(interp, separators, headPtr, p, types);
} else {
Tcl_Obj *nameObj;
int macSpecialCase = 0;
switch (tclPlatform) {
case TCL_PLATFORM_MAC: {
if (strchr(Tcl_DStringValue(headPtr), ':') == NULL) {
Tcl_DStringAppend(headPtr, ":", 1);
}
macSpecialCase = 1;
break;
}
case TCL_PLATFORM_WINDOWS: {
if (Tcl_DStringLength(headPtr) == 0) {
if (((*name == '\\') && (name[1] == '/' || name[1] == '\\'))
|| (*name == '/')) {
Tcl_DStringAppend(headPtr, "\\", 1);
} else {
Tcl_DStringAppend(headPtr, ".", 1);
}
}
for (p = Tcl_DStringValue(headPtr); *p != '\0'; p++) {
if (*p == '\\') {
*p = '/';
}
}
break;
}
case TCL_PLATFORM_UNIX: {
if (Tcl_DStringLength(headPtr) == 0) {
if ((*name == '\\' && name[1] == '/') || (*name == '/')) {
Tcl_DStringAppend(headPtr, "/", 1);
} else {
Tcl_DStringAppend(headPtr, ".", 1);
}
}
break;
}
}
name = Tcl_DStringValue(headPtr);
nameObj = Tcl_NewStringObj(name, Tcl_DStringLength(headPtr));
Tcl_IncrRefCount(nameObj);
Tcl_FSMatchInDirectory(interp, Tcl_GetObjResult(interp), nameObj,
NULL, types);
Tcl_DecrRefCount(nameObj);
return TCL_OK;
}
}
Tcl_Obj*
TclFileDirname(interp, pathPtr)
Tcl_Interp *interp;
Tcl_Obj *pathPtr;
{
int splitElements;
Tcl_Obj *splitPtr;
Tcl_Obj *splitResultPtr = NULL;
splitPtr = Tcl_FSSplitPath(pathPtr, &splitElements);
if ((splitElements == 1) && (Tcl_GetString(pathPtr)[0] == '~')) {
Tcl_DecrRefCount(splitPtr);
splitPtr = Tcl_FSGetNormalizedPath(interp, pathPtr);
if (splitPtr == NULL) {
return NULL;
}
splitPtr = Tcl_FSSplitPath(splitPtr, &splitElements);
}
if (splitElements > 1) {
splitResultPtr = Tcl_FSJoinPath(splitPtr, splitElements - 1);
} else if (splitElements == 0 ||
(Tcl_FSGetPathType(pathPtr) == TCL_PATH_RELATIVE)) {
splitResultPtr = Tcl_NewStringObj(
((tclPlatform == TCL_PLATFORM_MAC) ? ":" : "."), 1);
} else {
Tcl_ListObjIndex(NULL, splitPtr, 0, &splitResultPtr);
}
Tcl_IncrRefCount(splitResultPtr);
Tcl_DecrRefCount(splitPtr);
return splitResultPtr;
}
Tcl_StatBuf *
Tcl_AllocStatBuf() {
return (Tcl_StatBuf *) ckalloc(sizeof(Tcl_StatBuf));
}