diff options
-rw-r--r-- | Makefile | 6 | ||||
-rw-r--r-- | arg.h | 63 | ||||
-rw-r--r-- | stest.c | 125 |
3 files changed, 141 insertions, 53 deletions
@@ -22,7 +22,7 @@ config.h: | |||
22 | @echo creating $@ from config.def.h | 22 | @echo creating $@ from config.def.h |
23 | @cp config.def.h $@ | 23 | @cp config.def.h $@ |
24 | 24 | ||
25 | ${OBJ}: config.h config.mk drw.h | 25 | ${OBJ}: arg.h config.h config.mk drw.h |
26 | 26 | ||
27 | dmenu: dmenu.o drw.o util.o | 27 | dmenu: dmenu.o drw.o util.o |
28 | @echo CC -o $@ | 28 | @echo CC -o $@ |
@@ -39,8 +39,8 @@ clean: | |||
39 | dist: clean | 39 | dist: clean |
40 | @echo creating dist tarball | 40 | @echo creating dist tarball |
41 | @mkdir -p dmenu-${VERSION} | 41 | @mkdir -p dmenu-${VERSION} |
42 | @cp LICENSE Makefile README config.mk dmenu.1 drw.h util.h dmenu_path \ | 42 | @cp LICENSE Makefile README arg.h config.mk dmenu.1 drw.h util.h \ |
43 | dmenu_run stest.1 ${SRC} dmenu-${VERSION} | 43 | dmenu_path dmenu_run stest.1 ${SRC} dmenu-${VERSION} |
44 | @tar -cf dmenu-${VERSION}.tar dmenu-${VERSION} | 44 | @tar -cf dmenu-${VERSION}.tar dmenu-${VERSION} |
45 | @gzip dmenu-${VERSION}.tar | 45 | @gzip dmenu-${VERSION}.tar |
46 | @rm -rf dmenu-${VERSION} | 46 | @rm -rf dmenu-${VERSION} |
@@ -0,0 +1,63 @@ | |||
1 | /* | ||
2 | * Copy me if you can. | ||
3 | * by 20h | ||
4 | */ | ||
5 | |||
6 | #ifndef ARG_H__ | ||
7 | #define ARG_H__ | ||
8 | |||
9 | extern char *argv0; | ||
10 | |||
11 | /* use main(int argc, char *argv[]) */ | ||
12 | #define ARGBEGIN for (argv0 = *argv, argv++, argc--;\ | ||
13 | argv[0] && argv[0][1]\ | ||
14 | && argv[0][0] == '-';\ | ||
15 | argc--, argv++) {\ | ||
16 | char argc_;\ | ||
17 | char **argv_;\ | ||
18 | int brk_;\ | ||
19 | if (argv[0][1] == '-' && argv[0][2] == '\0') {\ | ||
20 | argv++;\ | ||
21 | argc--;\ | ||
22 | break;\ | ||
23 | }\ | ||
24 | for (brk_ = 0, argv[0]++, argv_ = argv;\ | ||
25 | argv[0][0] && !brk_;\ | ||
26 | argv[0]++) {\ | ||
27 | if (argv_ != argv)\ | ||
28 | break;\ | ||
29 | argc_ = argv[0][0];\ | ||
30 | switch (argc_) | ||
31 | |||
32 | /* Handles obsolete -NUM syntax */ | ||
33 | #define ARGNUM case '0':\ | ||
34 | case '1':\ | ||
35 | case '2':\ | ||
36 | case '3':\ | ||
37 | case '4':\ | ||
38 | case '5':\ | ||
39 | case '6':\ | ||
40 | case '7':\ | ||
41 | case '8':\ | ||
42 | case '9' | ||
43 | |||
44 | #define ARGEND }\ | ||
45 | } | ||
46 | |||
47 | #define ARGC() argc_ | ||
48 | |||
49 | #define ARGNUMF(base) (brk_ = 1, estrtol(argv[0], (base))) | ||
50 | |||
51 | #define EARGF(x) ((argv[0][1] == '\0' && argv[1] == NULL)?\ | ||
52 | ((x), abort(), (char *)0) :\ | ||
53 | (brk_ = 1, (argv[0][1] != '\0')?\ | ||
54 | (&argv[0][1]) :\ | ||
55 | (argc--, argv++, argv[0]))) | ||
56 | |||
57 | #define ARGF() ((argv[0][1] == '\0' && argv[1] == NULL)?\ | ||
58 | (char *)0 :\ | ||
59 | (brk_ = 1, (argv[0][1] != '\0')?\ | ||
60 | (&argv[0][1]) :\ | ||
61 | (argc--, argv++, argv[0]))) | ||
62 | |||
63 | #endif | ||
@@ -1,66 +1,31 @@ | |||
1 | /* See LICENSE file for copyright and license details. */ | 1 | /* See LICENSE file for copyright and license details. */ |
2 | #include <sys/stat.h> | ||
3 | |||
2 | #include <dirent.h> | 4 | #include <dirent.h> |
3 | #include <stdbool.h> | 5 | #include <limits.h> |
4 | #include <stdio.h> | 6 | #include <stdio.h> |
5 | #include <stdlib.h> | 7 | #include <stdlib.h> |
6 | #include <string.h> | 8 | #include <string.h> |
7 | #include <unistd.h> | 9 | #include <unistd.h> |
8 | #include <sys/stat.h> | 10 | |
11 | #include "arg.h" | ||
12 | char *argv0; | ||
9 | 13 | ||
10 | #define FLAG(x) (flag[(x)-'a']) | 14 | #define FLAG(x) (flag[(x)-'a']) |
11 | 15 | ||
12 | static void test(const char *, const char *); | 16 | static void test(const char *, const char *); |
17 | static void usage(void); | ||
13 | 18 | ||
14 | static bool match = false; | 19 | static int match = 0; |
15 | static bool flag[26]; | 20 | static int flag[26]; |
16 | static struct stat old, new; | 21 | static struct stat old, new; |
17 | 22 | ||
18 | int | 23 | static void |
19 | main(int argc, char *argv[]) { | 24 | test(const char *path, const char *name) |
20 | struct dirent *d; | 25 | { |
21 | char buf[BUFSIZ], *p; | ||
22 | DIR *dir; | ||
23 | int opt; | ||
24 | |||
25 | while((opt = getopt(argc, argv, "abcdefghln:o:pqrsuvwx")) != -1) | ||
26 | switch(opt) { | ||
27 | case 'n': /* newer than file */ | ||
28 | case 'o': /* older than file */ | ||
29 | if(!(FLAG(opt) = !stat(optarg, (opt == 'n' ? &new : &old)))) | ||
30 | perror(optarg); | ||
31 | break; | ||
32 | default: /* miscellaneous operators */ | ||
33 | FLAG(opt) = true; | ||
34 | break; | ||
35 | case '?': /* error: unknown flag */ | ||
36 | fprintf(stderr, "usage: %s [-abcdefghlpqrsuvwx] [-n file] [-o file] [file...]\n", argv[0]); | ||
37 | exit(2); | ||
38 | } | ||
39 | if(optind == argc) | ||
40 | while(fgets(buf, sizeof buf, stdin)) { | ||
41 | if((p = strchr(buf, '\n'))) | ||
42 | *p = '\0'; | ||
43 | test(buf, buf); | ||
44 | } | ||
45 | for(; optind < argc; optind++) | ||
46 | if(FLAG('l') && (dir = opendir(argv[optind]))) { | ||
47 | /* test directory contents */ | ||
48 | while((d = readdir(dir))) | ||
49 | if(snprintf(buf, sizeof buf, "%s/%s", argv[optind], d->d_name) < sizeof buf) | ||
50 | test(buf, d->d_name); | ||
51 | closedir(dir); | ||
52 | } | ||
53 | else | ||
54 | test(argv[optind], argv[optind]); | ||
55 | |||
56 | return match ? 0 : 1; | ||
57 | } | ||
58 | |||
59 | void | ||
60 | test(const char *path, const char *name) { | ||
61 | struct stat st, ln; | 26 | struct stat st, ln; |
62 | 27 | ||
63 | if((!stat(path, &st) && (FLAG('a') || name[0] != '.') /* hidden files */ | 28 | if ((!stat(path, &st) && (FLAG('a') || name[0] != '.') /* hidden files */ |
64 | && (!FLAG('b') || S_ISBLK(st.st_mode)) /* block special */ | 29 | && (!FLAG('b') || S_ISBLK(st.st_mode)) /* block special */ |
65 | && (!FLAG('c') || S_ISCHR(st.st_mode)) /* character special */ | 30 | && (!FLAG('c') || S_ISCHR(st.st_mode)) /* character special */ |
66 | && (!FLAG('d') || S_ISDIR(st.st_mode)) /* directory */ | 31 | && (!FLAG('d') || S_ISDIR(st.st_mode)) /* directory */ |
@@ -76,9 +41,69 @@ test(const char *path, const char *name) { | |||
76 | && (!FLAG('u') || st.st_mode & S_ISUID) /* set-user-id flag */ | 41 | && (!FLAG('u') || st.st_mode & S_ISUID) /* set-user-id flag */ |
77 | && (!FLAG('w') || access(path, W_OK) == 0) /* writable */ | 42 | && (!FLAG('w') || access(path, W_OK) == 0) /* writable */ |
78 | && (!FLAG('x') || access(path, X_OK) == 0)) != FLAG('v')) { /* executable */ | 43 | && (!FLAG('x') || access(path, X_OK) == 0)) != FLAG('v')) { /* executable */ |
79 | if(FLAG('q')) | 44 | if (FLAG('q')) |
80 | exit(0); | 45 | exit(0); |
81 | match = true; | 46 | match = 1; |
82 | puts(name); | 47 | puts(name); |
83 | } | 48 | } |
84 | } | 49 | } |
50 | |||
51 | static void | ||
52 | usage(void) | ||
53 | { | ||
54 | fprintf(stderr, "usage: %s [-abcdefghlpqrsuvwx] " | ||
55 | "[-n file] [-o file] [file...]\n", argv0); | ||
56 | exit(2); /* like test(1) return > 1 on error */ | ||
57 | } | ||
58 | |||
59 | int | ||
60 | main(int argc, char *argv[]) | ||
61 | { | ||
62 | struct dirent *d; | ||
63 | char path[PATH_MAX], *line = NULL, *file; | ||
64 | size_t linesiz = 0; | ||
65 | ssize_t n; | ||
66 | DIR *dir; | ||
67 | int r; | ||
68 | |||
69 | ARGBEGIN { | ||
70 | case 'n': /* newer than file */ | ||
71 | case 'o': /* older than file */ | ||
72 | file = EARGF(usage()); | ||
73 | if (!(FLAG(ARGC()) = !stat(file, (ARGC() == 'n' ? &new : &old)))) | ||
74 | perror(file); | ||
75 | break; | ||
76 | default: | ||
77 | /* miscellaneous operators */ | ||
78 | if (strchr("abcdefghlpqrsuvwx", ARGC())) | ||
79 | FLAG(ARGC()) = 1; | ||
80 | else | ||
81 | usage(); /* unknown flag */ | ||
82 | } ARGEND; | ||
83 | |||
84 | if (!argc) { | ||
85 | /* read list from stdin */ | ||
86 | while ((n = getline(&line, &linesiz, stdin)) > 0) { | ||
87 | if (n && line[n - 1] == '\n') | ||
88 | line[n - 1] = '\0'; | ||
89 | test(line, line); | ||
90 | } | ||
91 | free(line); | ||
92 | } else { | ||
93 | for (; argc; argc--, argv++) { | ||
94 | if (FLAG('l') && (dir = opendir(*argv))) { | ||
95 | /* test directory contents */ | ||
96 | while ((d = readdir(dir))) { | ||
97 | r = snprintf(path, sizeof path, "%s/%s", | ||
98 | *argv, d->d_name); | ||
99 | if (r >= 0 && (size_t)r < sizeof path) | ||
100 | test(path, d->d_name); | ||
101 | } | ||
102 | closedir(dir); | ||
103 | } else { | ||
104 | test(*argv, *argv); | ||
105 | } | ||
106 | } | ||
107 | } | ||
108 | return match ? 0 : 1; | ||
109 | } | ||