summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bftw.c56
-rw-r--r--bftw.h29
-rw-r--r--eval.c30
-rw-r--r--parse.c93
-rw-r--r--printf.c80
-rwxr-xr-xtests.sh12
-rw-r--r--tests/test_0142.out6
-rw-r--r--tests/test_0143.out9
8 files changed, 146 insertions, 169 deletions
diff --git a/bftw.c b/bftw.c
index d62a71f..d239d40 100644
--- a/bftw.c
+++ b/bftw.c
@@ -523,67 +523,63 @@ static void ftwbuf_use_dirent(struct BFTW *ftwbuf, const struct dirent *de) {
#endif
}
-/** Call stat() and use the results. */
-static int ftwbuf_stat(struct BFTW *ftwbuf, struct stat *sb) {
- int ret = fstatat(ftwbuf->at_fd, ftwbuf->at_path, sb, ftwbuf->at_flags);
- if (ret != 0) {
- return ret;
- }
-
- ftwbuf->statbuf = sb;
-
- switch (sb->st_mode & S_IFMT) {
+enum bftw_typeflag bftw_mode_to_typeflag(mode_t mode) {
+ switch (mode & S_IFMT) {
#ifdef S_IFBLK
case S_IFBLK:
- ftwbuf->typeflag = BFTW_BLK;
- break;
+ return BFTW_BLK;
#endif
#ifdef S_IFCHR
case S_IFCHR:
- ftwbuf->typeflag = BFTW_CHR;
- break;
+ return BFTW_CHR;
#endif
#ifdef S_IFDIR
case S_IFDIR:
- ftwbuf->typeflag = BFTW_DIR;
- break;
+ return BFTW_DIR;
#endif
#ifdef S_IFDOOR
case S_IFDOOR:
- ftwbuf->typeflag = BFTW_DOOR;
- break;
+ return BFTW_DOOR;
#endif
#ifdef S_IFIFO
case S_IFIFO:
- ftwbuf->typeflag = BFTW_FIFO;
- break;
+ return BFTW_FIFO;
#endif
#ifdef S_IFLNK
case S_IFLNK:
- ftwbuf->typeflag = BFTW_LNK;
- break;
+ return BFTW_LNK;
#endif
#ifdef S_IFPORT
case S_IFPORT:
- ftwbuf->typeflag = BFTW_PORT;
- break;
+ return BFTW_PORT;
#endif
#ifdef S_IFREG
case S_IFREG:
- ftwbuf->typeflag = BFTW_REG;
- break;
+ return BFTW_REG;
#endif
#ifdef S_IFSOCK
case S_IFSOCK:
- ftwbuf->typeflag = BFTW_SOCK;
- break;
+ return BFTW_SOCK;
#endif
#ifdef S_IFWHT
case S_IFWHT:
- ftwbuf->typeflag = BFTW_WHT;
- break;
+ return BFTW_WHT;
#endif
+
+ default:
+ return BFTW_UNKNOWN;
}
+}
+
+/** Call stat() and use the results. */
+static int ftwbuf_stat(struct BFTW *ftwbuf, struct stat *sb) {
+ int ret = fstatat(ftwbuf->at_fd, ftwbuf->at_path, sb, ftwbuf->at_flags);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ftwbuf->statbuf = sb;
+ ftwbuf->typeflag = bftw_mode_to_typeflag(sb->st_mode);
return 0;
}
diff --git a/bftw.h b/bftw.h
index 2fb1ef0..3bfe2a2 100644
--- a/bftw.h
+++ b/bftw.h
@@ -20,32 +20,37 @@
*/
enum bftw_typeflag {
/** Unknown type. */
- BFTW_UNKNOWN,
+ BFTW_UNKNOWN = 0,
/** Block device. */
- BFTW_BLK,
+ BFTW_BLK = 1 << 0,
/** Character device. */
- BFTW_CHR,
+ BFTW_CHR = 1 << 1,
/** Directory. */
- BFTW_DIR,
+ BFTW_DIR = 1 << 2,
/** Solaris door. */
- BFTW_DOOR,
+ BFTW_DOOR = 1 << 3,
/** Pipe. */
- BFTW_FIFO,
+ BFTW_FIFO = 1 << 4,
/** Symbolic link. */
- BFTW_LNK,
+ BFTW_LNK = 1 << 5,
/** Solaris event port. */
- BFTW_PORT,
+ BFTW_PORT = 1 << 6,
/** Regular file. */
- BFTW_REG,
+ BFTW_REG = 1 << 7,
/** Socket. */
- BFTW_SOCK,
+ BFTW_SOCK = 1 << 8,
/** BSD whiteout. */
- BFTW_WHT,
+ BFTW_WHT = 1 << 9,
/** An error occurred for this file. */
- BFTW_ERROR,
+ BFTW_ERROR = 1 << 10,
};
/**
+ * Convert a stat() st_mode to a bftw() typeflag.
+ */
+enum bftw_typeflag bftw_mode_to_typeflag(mode_t mode);
+
+/**
* Possible visit occurrences.
*/
enum bftw_visit {
diff --git a/eval.c b/eval.c
index 6109d44..37bea60 100644
--- a/eval.c
+++ b/eval.c
@@ -866,7 +866,7 @@ bool eval_sparse(const struct expr *expr, struct eval_state *state) {
* -type test.
*/
bool eval_type(const struct expr *expr, struct eval_state *state) {
- return state->ftwbuf->typeflag == expr->idata;
+ return state->ftwbuf->typeflag & expr->idata;
}
/**
@@ -900,33 +900,7 @@ bool eval_xtype(const struct expr *expr, struct eval_state *state) {
}
}
- switch ((enum bftw_typeflag)expr->idata) {
- case BFTW_UNKNOWN:
- case BFTW_ERROR:
- break;
- case BFTW_BLK:
- return S_ISBLK(sb.st_mode);
- case BFTW_CHR:
- return S_ISCHR(sb.st_mode);
- case BFTW_DIR:
- return S_ISDIR(sb.st_mode);
- case BFTW_DOOR:
- return S_ISDOOR(sb.st_mode);
- case BFTW_FIFO:
- return S_ISFIFO(sb.st_mode);
- case BFTW_LNK:
- return S_ISLNK(sb.st_mode);
- case BFTW_PORT:
- return S_ISPORT(sb.st_mode);
- case BFTW_REG:
- return S_ISREG(sb.st_mode);
- case BFTW_SOCK:
- return S_ISSOCK(sb.st_mode);
- case BFTW_WHT:
- return S_ISWHT(sb.st_mode);
- }
-
- return false;
+ return bftw_mode_to_typeflag(sb.st_mode) & expr->idata;
}
#if _POSIX_MONOTONIC_CLOCK > 0
diff --git a/parse.c b/parse.c
index eb431aa..2d24dda 100644
--- a/parse.c
+++ b/parse.c
@@ -1754,7 +1754,7 @@ static struct expr *parse_sparse(struct parser_state *state, int arg1, int arg2)
}
/**
- * Parse -x?type [bcdpfls].
+ * Parse -x?type [bcdpflsD].
*/
static struct expr *parse_type(struct parser_state *state, int x, int arg2) {
eval_fn *eval = x ? eval_xtype : eval_type;
@@ -1763,44 +1763,69 @@ static struct expr *parse_type(struct parser_state *state, int x, int arg2) {
return NULL;
}
- int typeflag = BFTW_UNKNOWN;
+ enum bftw_typeflag types = 0;
- switch (expr->sdata[0]) {
- case 'b':
- typeflag = BFTW_BLK;
- break;
- case 'c':
- typeflag = BFTW_CHR;
- break;
- case 'd':
- typeflag = BFTW_DIR;
- break;
- case 'D':
- typeflag = BFTW_DOOR;
- break;
- case 'p':
- typeflag = BFTW_FIFO;
- break;
- case 'f':
- typeflag = BFTW_REG;
- break;
- case 'l':
- typeflag = BFTW_LNK;
- break;
- case 's':
- typeflag = BFTW_SOCK;
- break;
- }
+ const char *c = expr->sdata;
+ while (true) {
+ switch (*c) {
+ case 'b':
+ types |= BFTW_BLK;
+ break;
+ case 'c':
+ types |= BFTW_CHR;
+ break;
+ case 'd':
+ types |= BFTW_DIR;
+ break;
+ case 'D':
+ types |= BFTW_DOOR;
+ break;
+ case 'p':
+ types |= BFTW_FIFO;
+ break;
+ case 'f':
+ types |= BFTW_REG;
+ break;
+ case 'l':
+ types |= BFTW_LNK;
+ break;
+ case 's':
+ types |= BFTW_SOCK;
+ break;
- if (typeflag == BFTW_UNKNOWN || expr->sdata[1] != '\0') {
- pretty_error(state->cmdline->stderr_colors,
- "error: Unknown type flag '%s'.\n", expr->sdata);
- free_expr(expr);
- return NULL;
+ case '\0':
+ pretty_error(state->cmdline->stderr_colors,
+ "error: %s %s: Expected a type flag.\n",
+ expr->argv[0], expr->argv[1]);
+ goto fail;
+
+ default:
+ pretty_error(state->cmdline->stderr_colors,
+ "error: %s %s: Unknown type flag '%c' (expected one of [bcdpflsD]).\n",
+ expr->argv[0], expr->argv[1], *c);
+ goto fail;
+ }
+
+ ++c;
+ if (*c == '\0') {
+ break;
+ } else if (*c == ',') {
+ ++c;
+ continue;
+ } else {
+ pretty_error(state->cmdline->stderr_colors,
+ "error: %s %s: Types must be comma-separated.\n",
+ expr->argv[0], expr->argv[1]);
+ goto fail;
+ }
}
- expr->idata = typeflag;
+ expr->idata = types;
return expr;
+
+fail:
+ free_expr(expr);
+ return NULL;
}
/**
diff --git a/printf.c b/printf.c
index 0977d5e..cad4dc0 100644
--- a/printf.c
+++ b/printf.c
@@ -318,39 +318,32 @@ static int bfs_printf_u(FILE *file, const struct bfs_printf_directive *directive
return fprintf(file, directive->str, pwd->pw_name);
}
-/** %y: type */
-static int bfs_printf_y(FILE *file, const struct bfs_printf_directive *directive, const struct BFTW *ftwbuf) {
- const char *type;
- switch (ftwbuf->typeflag) {
+static const char *bfs_printf_type(enum bftw_typeflag typeflag) {
+ switch (typeflag) {
case BFTW_BLK:
- type = "b";
- break;
+ return "b";
case BFTW_CHR:
- type = "c";
- break;
+ return "c";
case BFTW_DIR:
- type = "d";
- break;
+ return "d";
case BFTW_DOOR:
- type = "D";
- break;
+ return "D";
case BFTW_FIFO:
- type = "p";
- break;
+ return "p";
case BFTW_LNK:
- type = "l";
- break;
+ return "l";
case BFTW_REG:
- type = "f";
- break;
+ return "f";
case BFTW_SOCK:
- type = "s";
- break;
+ return "s";
default:
- type = "U";
- break;
+ return "U";
}
+}
+/** %y: type */
+static int bfs_printf_y(FILE *file, const struct bfs_printf_directive *directive, const struct BFTW *ftwbuf) {
+ const char *type = bfs_printf_type(ftwbuf->typeflag);
return fprintf(file, directive->str, type);
}
@@ -364,48 +357,7 @@ static int bfs_printf_Y(FILE *file, const struct bfs_printf_directive *directive
struct stat sb;
if (fstatat(ftwbuf->at_fd, ftwbuf->at_path, &sb, 0) == 0) {
- switch (sb.st_mode & S_IFMT) {
-#ifdef S_IFBLK
- case S_IFBLK:
- type = "b";
- break;
-#endif
-#ifdef S_IFCHR
- case S_IFCHR:
- type = "c";
- break;
-#endif
-#ifdef S_IFDIR
- case S_IFDIR:
- type = "d";
- break;
-#endif
-#ifdef S_IFDOOR
- case S_IFDOOR:
- type = "D";
- break;
-#endif
-#ifdef S_IFIFO
- case S_IFIFO:
- type = "p";
- break;
-#endif
-#ifdef S_IFLNK
- case S_IFLNK:
- type = "l";
- break;
-#endif
-#ifdef S_IFREG
- case S_IFREG:
- type = "f";
- break;
-#endif
-#ifdef S_IFSOCK
- case S_IFSOCK:
- type = "s";
- break;
-#endif
- }
+ type = bfs_printf_type(bftw_mode_to_typeflag(sb.st_mode));
} else {
switch (errno) {
case ELOOP:
diff --git a/tests.sh b/tests.sh
index a6d9784..ecaf837 100755
--- a/tests.sh
+++ b/tests.sh
@@ -858,9 +858,19 @@ function test_0141() {
bfs_diff basic -maxdepth 0 -printf '%p'
}
+function test_0142() {
+ [ "$ALL" ] || return 0
+ bfs_diff links -type f,d,c
+}
+
+function test_0143() {
+ [ "$ALL" ] || return 0
+ bfs_diff links -xtype f,d,c
+}
+
result=0
-for i in {1..141}; do
+for i in {1..143}; do
test="test_$(printf '%04d' $i)"
if [ -t 1 ]; then
diff --git a/tests/test_0142.out b/tests/test_0142.out
new file mode 100644
index 0000000..1f94970
--- /dev/null
+++ b/tests/test_0142.out
@@ -0,0 +1,6 @@
+links
+links/a
+links/c
+links/d
+links/d/e
+links/d/e/f
diff --git a/tests/test_0143.out b/tests/test_0143.out
new file mode 100644
index 0000000..8849bb9
--- /dev/null
+++ b/tests/test_0143.out
@@ -0,0 +1,9 @@
+links
+links/a
+links/b
+links/c
+links/d
+links/h
+links/d/e
+links/d/e/f
+links/d/e/g