diff options
Diffstat (limited to 'unix/tclUnixFile.c')
-rw-r--r-- | unix/tclUnixFile.c | 136 |
1 files changed, 117 insertions, 19 deletions
diff --git a/unix/tclUnixFile.c b/unix/tclUnixFile.c index 248079d..8feb007 100644 --- a/unix/tclUnixFile.c +++ b/unix/tclUnixFile.c @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclUnixFile.c,v 1.6 1999/04/16 00:48:05 stanton Exp $ + * RCS: @(#) $Id: tclUnixFile.c,v 1.7 1999/12/12 22:46:50 hobbs Exp $ */ #include "tclInt.h" @@ -176,7 +176,7 @@ TclpFindExecutable(argv0) /* *---------------------------------------------------------------------- * - * TclpMatchFiles -- + * TclpMatchFilesTypes -- * * This routine is used by the globbing code to search a * directory for all files which match a given pattern. @@ -195,15 +195,18 @@ TclpFindExecutable(argv0) */ int -TclpMatchFiles(interp, separators, dirPtr, pattern, tail) - Tcl_Interp *interp; /* Interpreter to receive results. */ - char *separators; /* Path separators to pass to TclDoGlob. */ - Tcl_DString *dirPtr; /* Contains path to directory to search. */ - char *pattern; /* Pattern to match against. */ - char *tail; /* Pointer to end of pattern. Must not - * refer to a static string. */ +TclpMatchFilesTypes( + Tcl_Interp *interp, /* Interpreter to receive results. */ + char *separators, /* Directory separators to pass to TclDoGlob. */ + Tcl_DString *dirPtr, /* Contains path to directory to search. */ + char *pattern, /* Pattern to match against. */ + char *tail, /* Pointer to end of pattern. Tail must + * point to a location in pattern and must + * not be static.*/ + GlobTypeData *types) /* Object containing list of acceptable types. + * May be NULL. */ { - char *native, *dirName, *patternEnd = tail; + char *native, *fname, *dirName, *patternEnd = tail; char savedChar = 0; /* lint. */ DIR *d; Tcl_DString ds; @@ -211,6 +214,7 @@ TclpMatchFiles(interp, separators, dirPtr, pattern, tail) int matchHidden; int result = TCL_OK; int baseLength = Tcl_DStringLength(dirPtr); + Tcl_Obj *resultPtr; /* * Make sure that the directory part of the name really is a @@ -289,6 +293,7 @@ TclpMatchFiles(interp, separators, dirPtr, pattern, tail) savedChar = *patternEnd; *patternEnd = '\0'; + resultPtr = Tcl_GetObjResult(interp); while (1) { char *utf; struct dirent *entryPtr; @@ -298,12 +303,19 @@ TclpMatchFiles(interp, separators, dirPtr, pattern, tail) break; } - /* - * Don't match names starting with "." unless the "." is - * present in the pattern. - */ - - if (!matchHidden && (*entryPtr->d_name == '.')) { + if (types != NULL && (types->perm & TCL_GLOB_PERM_HIDDEN)) { + /* + * We explicitly asked for hidden files, so turn around + * and ignore any file which isn't hidden. + */ + if (*entryPtr->d_name != '.') { + continue; + } + } else if (!matchHidden && (*entryPtr->d_name == '.')) { + /* + * Don't match names starting with "." unless the "." is + * present in the pattern. + */ continue; } @@ -318,12 +330,79 @@ TclpMatchFiles(interp, separators, dirPtr, pattern, tail) if (Tcl_StringMatch(utf, pattern) != 0) { Tcl_DStringSetLength(dirPtr, baseLength); Tcl_DStringAppend(dirPtr, utf, -1); + fname = Tcl_DStringValue(dirPtr); if (tail == NULL) { - Tcl_AppendElement(interp, Tcl_DStringValue(dirPtr)); - } else if ((TclpStat(Tcl_DStringValue(dirPtr), &statBuf) == 0) + int typeOk = 1; + if (types != NULL) { + if (types->perm != 0) { + struct stat buf; + + if (TclpStat(fname, &buf) != 0) { + panic("stat failed on known file\n"); + } + /* + * readonly means that there are NO write permissions + * (even for user), but execute is OK for anybody + */ + if ( + ((types->perm & TCL_GLOB_PERM_RONLY) && + (buf.st_mode & (S_IWOTH|S_IWGRP|S_IWUSR))) || + ((types->perm & TCL_GLOB_PERM_R) && + (TclpAccess(fname, R_OK) != 0)) || + ((types->perm & TCL_GLOB_PERM_W) && + (TclpAccess(fname, W_OK) != 0)) || + ((types->perm & TCL_GLOB_PERM_X) && + (TclpAccess(fname, X_OK) != 0)) + ) { + typeOk = 0; + } + } + if (typeOk && (types->type != 0)) { + struct stat buf; + /* + * We must match at least one flag to be listed + */ + typeOk = 0; + if (TclpLstat(fname, &buf) >= 0) { + /* + * In order bcdpfls as in 'find -t' + */ + 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_ISLNK + || ((types->type & TCL_GLOB_TYPE_LINK) && + S_ISLNK(buf.st_mode)) +#endif +#ifdef S_ISSOCK + || ((types->type & TCL_GLOB_TYPE_SOCK) && + S_ISSOCK(buf.st_mode)) +#endif + ) { + typeOk = 1; + } + } else { + /* Posix error occurred */ + } + } + } + if (typeOk) { + Tcl_ListObjAppendElement(interp, resultPtr, + Tcl_NewStringObj(fname, + Tcl_DStringLength(dirPtr))); + } + } else if ((TclpStat(fname, &statBuf) == 0) && S_ISDIR(statBuf.st_mode)) { Tcl_DStringAppend(dirPtr, "/", 1); - result = TclDoGlob(interp, separators, dirPtr, tail); + result = TclDoGlob(interp, separators, dirPtr, tail, types); if (result != TCL_OK) { Tcl_DStringFree(&ds); break; @@ -338,6 +417,25 @@ TclpMatchFiles(interp, separators, dirPtr, pattern, tail) return result; } +/* + * TclpMatchFiles -- + * + * This function is now obsolete. Call the above function + * 'TclpMatchFilesTypes' instead. + */ +int +TclpMatchFiles( + Tcl_Interp *interp, /* Interpreter to receive results. */ + char *separators, /* Directory separators to pass to TclDoGlob. */ + Tcl_DString *dirPtr, /* Contains path to directory to search. */ + char *pattern, /* Pattern to match against. */ + char *tail) /* Pointer to end of pattern. Tail must + * point to a location in pattern and must + * not be static.*/ +{ + return TclpMatchFilesTypes(interp,separators,dirPtr,pattern,tail,NULL); +} + /* *--------------------------------------------------------------------------- * |