summaryrefslogtreecommitdiffstats
path: root/unix/tclUnixFile.c
diff options
context:
space:
mode:
Diffstat (limited to 'unix/tclUnixFile.c')
-rw-r--r--unix/tclUnixFile.c136
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);
+}
+
/*
*---------------------------------------------------------------------------
*