| test.c - sbase - suckless unix tools | |
| git clone git://git.suckless.org/sbase | |
| Log | |
| Files | |
| Refs | |
| README | |
| LICENSE | |
| --- | |
| test.c (6472B) | |
| --- | |
| 1 /* See LICENSE file for copyright and license details. */ | |
| 2 #include <sys/stat.h> | |
| 3 | |
| 4 #include <ctype.h> | |
| 5 #include <fcntl.h> | |
| 6 #include <string.h> | |
| 7 #include <unistd.h> | |
| 8 | |
| 9 #include "util.h" | |
| 10 | |
| 11 static int | |
| 12 intcmp(char *a, char *b) | |
| 13 { | |
| 14 char *s; | |
| 15 int asign = *a == '-' ? -1 : 1; | |
| 16 int bsign = *b == '-' ? -1 : 1; | |
| 17 | |
| 18 if (*a == '-' || *a == '+') a += 1; | |
| 19 if (*b == '-' || *b == '+') b += 1; | |
| 20 | |
| 21 if (!*a || !*b) | |
| 22 goto noint; | |
| 23 for (s = a; *s; s++) | |
| 24 if (!isdigit(*s)) | |
| 25 goto noint; | |
| 26 for (s = b; *s; s++) | |
| 27 if (!isdigit(*s)) | |
| 28 goto noint; | |
| 29 | |
| 30 while (*a == '0') a++; | |
| 31 while (*b == '0') b++; | |
| 32 asign *= !!*a; | |
| 33 bsign *= !!*b; | |
| 34 | |
| 35 if (asign != bsign) | |
| 36 return asign < bsign ? -1 : 1; | |
| 37 else if (strlen(a) != strlen(b)) | |
| 38 return asign * (strlen(a) < strlen(b) ? -1 : 1); | |
| 39 else | |
| 40 return asign * strcmp(a, b); | |
| 41 | |
| 42 noint: | |
| 43 enprintf(2, "expected integer operands\n"); | |
| 44 | |
| 45 return 0; /* not reached */ | |
| 46 } | |
| 47 | |
| 48 static int | |
| 49 mtimecmp(struct stat *buf1, struct stat *buf2) | |
| 50 { | |
| 51 if (buf1->st_mtime < buf2->st_mtime) return -1; | |
| 52 if (buf1->st_mtime > buf2->st_mtime) return +1; | |
| 53 #ifdef st_mtime | |
| 54 if (buf1->st_mtim.tv_nsec < buf2->st_mtim.tv_nsec) return -1; | |
| 55 if (buf1->st_mtim.tv_nsec > buf2->st_mtim.tv_nsec) return +1; | |
| 56 #endif | |
| 57 return 0; | |
| 58 } | |
| 59 | |
| 60 static int unary_b(char *s) { struct stat buf; if ( stat(s, &buf)) retur… | |
| 61 static int unary_c(char *s) { struct stat buf; if ( stat(s, &buf)) retur… | |
| 62 static int unary_d(char *s) { struct stat buf; if ( stat(s, &buf)) retur… | |
| 63 static int unary_f(char *s) { struct stat buf; if ( stat(s, &buf)) retur… | |
| 64 static int unary_g(char *s) { struct stat buf; if ( stat(s, &buf)) retur… | |
| 65 static int unary_h(char *s) { struct stat buf; if (lstat(s, &buf)) retur… | |
| 66 static int unary_k(char *s) { struct stat buf; if ( stat(s, &buf)) retur… | |
| 67 static int unary_p(char *s) { struct stat buf; if ( stat(s, &buf)) retur… | |
| 68 static int unary_S(char *s) { struct stat buf; if ( stat(s, &buf)) retur… | |
| 69 static int unary_s(char *s) { struct stat buf; if ( stat(s, &buf)) retur… | |
| 70 static int unary_u(char *s) { struct stat buf; if ( stat(s, &buf)) retur… | |
| 71 | |
| 72 static int unary_n(char *s) { return *s; } | |
| 73 static int unary_z(char *s) { return !*s; } | |
| 74 | |
| 75 static int unary_e(char *s) { return !faccessat(AT_FDCWD, s, F_OK, AT_EA… | |
| 76 static int unary_r(char *s) { return !faccessat(AT_FDCWD, s, R_OK, AT_EA… | |
| 77 static int unary_w(char *s) { return !faccessat(AT_FDCWD, s, W_OK, AT_EA… | |
| 78 static int unary_x(char *s) { return !faccessat(AT_FDCWD, s, X_OK, AT_EA… | |
| 79 | |
| 80 static int unary_t(char *s) { int fd = enstrtonum(2, s, 0, INT_MAX); ret… | |
| 81 | |
| 82 static int binary_se(char *s1, char *s2) { return !strcmp(s1, s2); } | |
| 83 static int binary_sn(char *s1, char *s2) { return strcmp(s1, s2); } | |
| 84 | |
| 85 static int binary_eq(char *s1, char *s2) { return intcmp(s1, s2) == 0; } | |
| 86 static int binary_ne(char *s1, char *s2) { return intcmp(s1, s2) != 0; } | |
| 87 static int binary_gt(char *s1, char *s2) { return intcmp(s1, s2) > 0; } | |
| 88 static int binary_ge(char *s1, char *s2) { return intcmp(s1, s2) >= 0; } | |
| 89 static int binary_lt(char *s1, char *s2) { return intcmp(s1, s2) < 0; } | |
| 90 static int binary_le(char *s1, char *s2) { return intcmp(s1, s2) <= 0; } | |
| 91 | |
| 92 static int | |
| 93 binary_ef(char *s1, char *s2) | |
| 94 { | |
| 95 struct stat buf1, buf2; | |
| 96 if (stat(s1, &buf1) || stat(s2, &buf2)) return 0; | |
| 97 return buf1.st_dev == buf2.st_dev && buf1.st_ino == buf2.st_ino; | |
| 98 } | |
| 99 | |
| 100 static int | |
| 101 binary_ot(char *s1, char *s2) | |
| 102 { | |
| 103 struct stat buf1, buf2; | |
| 104 if (stat(s1, &buf1) || stat(s2, &buf2)) return 0; | |
| 105 return mtimecmp(&buf1, &buf2) < 0; | |
| 106 } | |
| 107 | |
| 108 static int | |
| 109 binary_nt(char *s1, char *s2) | |
| 110 { | |
| 111 struct stat buf1, buf2; | |
| 112 if (stat(s1, &buf1) || stat(s2, &buf2)) return 0; | |
| 113 return mtimecmp(&buf1, &buf2) > 0; | |
| 114 } | |
| 115 | |
| 116 struct test { | |
| 117 char *name; | |
| 118 union { | |
| 119 int (*u)(char *); | |
| 120 int (*b)(char *, char *); | |
| 121 } func; | |
| 122 }; | |
| 123 | |
| 124 static struct test unary[] = { | |
| 125 { "-b", { .u = unary_b } }, | |
| 126 { "-c", { .u = unary_c } }, | |
| 127 { "-d", { .u = unary_d } }, | |
| 128 { "-e", { .u = unary_e } }, | |
| 129 { "-f", { .u = unary_f } }, | |
| 130 { "-g", { .u = unary_g } }, | |
| 131 { "-h", { .u = unary_h } }, | |
| 132 { "-k", { .u = unary_k } }, | |
| 133 { "-L", { .u = unary_h } }, | |
| 134 { "-n", { .u = unary_n } }, | |
| 135 { "-p", { .u = unary_p } }, | |
| 136 { "-r", { .u = unary_r } }, | |
| 137 { "-S", { .u = unary_S } }, | |
| 138 { "-s", { .u = unary_s } }, | |
| 139 { "-t", { .u = unary_t } }, | |
| 140 { "-u", { .u = unary_u } }, | |
| 141 { "-w", { .u = unary_w } }, | |
| 142 { "-x", { .u = unary_x } }, | |
| 143 { "-z", { .u = unary_z } }, | |
| 144 | |
| 145 { NULL }, | |
| 146 }; | |
| 147 | |
| 148 static struct test binary[] = { | |
| 149 { "=" , { .b = binary_se } }, | |
| 150 { "!=" , { .b = binary_sn } }, | |
| 151 { "-eq", { .b = binary_eq } }, | |
| 152 { "-ne", { .b = binary_ne } }, | |
| 153 { "-gt", { .b = binary_gt } }, | |
| 154 { "-ge", { .b = binary_ge } }, | |
| 155 { "-lt", { .b = binary_lt } }, | |
| 156 { "-le", { .b = binary_le } }, | |
| 157 { "-ef", { .b = binary_ef } }, | |
| 158 { "-ot", { .b = binary_ot } }, | |
| 159 { "-nt", { .b = binary_nt } }, | |
| 160 | |
| 161 { NULL }, | |
| 162 }; | |
| 163 | |
| 164 static struct test * | |
| 165 find_test(struct test *tests, char *name) | |
| 166 { | |
| 167 struct test *t; | |
| 168 | |
| 169 for (t = tests; t->name; t++) | |
| 170 if (!strcmp(t->name, name)) | |
| 171 return t; | |
| 172 | |
| 173 return NULL; | |
| 174 } | |
| 175 | |
| 176 static int | |
| 177 noarg(char *argv[]) | |
| 178 { | |
| 179 return 0; | |
| 180 } | |
| 181 | |
| 182 static int | |
| 183 onearg(char *argv[]) | |
| 184 { | |
| 185 return unary_n(argv[0]); | |
| 186 } | |
| 187 | |
| 188 static int | |
| 189 twoarg(char *argv[]) | |
| 190 { | |
| 191 struct test *t; | |
| 192 | |
| 193 if (!strcmp(argv[0], "!")) | |
| 194 return !onearg(argv + 1); | |
| 195 | |
| 196 if ((t = find_test(unary, *argv))) | |
| 197 return t->func.u(argv[1]); | |
| 198 | |
| 199 enprintf(2, "bad unary test %s\n", argv[0]); | |
| 200 | |
| 201 return 0; /* not reached */ | |
| 202 } | |
| 203 | |
| 204 static int | |
| 205 threearg(char *argv[]) | |
| 206 { | |
| 207 struct test *t = find_test(binary, argv[1]); | |
| 208 | |
| 209 if (t) | |
| 210 return t->func.b(argv[0], argv[2]); | |
| 211 | |
| 212 if (!strcmp(argv[0], "!")) | |
| 213 return !twoarg(argv + 1); | |
| 214 | |
| 215 enprintf(2, "bad binary test %s\n", argv[1]); | |
| 216 | |
| 217 return 0; /* not reached */ | |
| 218 } | |
| 219 | |
| 220 static int | |
| 221 fourarg(char *argv[]) | |
| 222 { | |
| 223 if (!strcmp(argv[0], "!")) | |
| 224 return !threearg(argv + 1); | |
| 225 | |
| 226 enprintf(2, "too many arguments\n"); | |
| 227 | |
| 228 return 0; /* not reached */ | |
| 229 } | |
| 230 | |
| 231 int | |
| 232 main(int argc, char *argv[]) | |
| 233 { | |
| 234 int (*narg[])(char *[]) = { noarg, onearg, twoarg, threearg, fou… | |
| 235 size_t len; | |
| 236 | |
| 237 argv0 = *argv, argv0 ? (argc--, argv++) : (void *)0; | |
| 238 | |
| 239 len = argv0 ? strlen(argv0) : 0; | |
| 240 if (len && argv0[--len] == '[' && (!len || argv0[--len] == '/') … | |
| 241 enprintf(2, "no matching ]\n"); | |
| 242 | |
| 243 if (argc > 4) | |
| 244 enprintf(2, "too many arguments\n"); | |
| 245 | |
| 246 return !narg[argc](argv); | |
| 247 } |