nftw.c (4095B)
1 #define _GNU_SOURCE 2 #define _FILE_OFFSET_BITS 64 3 4 #include <errno.h> 5 #include <fcntl.h> 6 #include <ftw.h> 7 #include <janet.h> 8 #include <stdbool.h> 9 #include <unistd.h> 10 11 #include "os.h" 12 13 static JanetFunction *janet_callback = NULL; 14 15 static const char *FTW_(int flag) { 16 switch (flag) { 17 case FTW_F: 18 return "f"; 19 case FTW_D: 20 return "d"; 21 case FTW_DNR: 22 return "dnr"; 23 case FTW_DP: 24 return "dp"; 25 case FTW_NS: 26 return "ns"; 27 case FTW_SL: 28 return "sl"; 29 case FTW_SLN: 30 return "sln"; 31 default: 32 return "err"; 33 } 34 } 35 36 int callback(const char *path, const struct stat *st, int flag, 37 struct FTW *info) { 38 39 JanetTable *ftwtab = janet_table(0); 40 janet_table_put(ftwtab, janet_ckeywordv("base"), 41 janet_wrap_integer(info->base)); 42 janet_table_put(ftwtab, janet_ckeywordv("level"), 43 janet_wrap_integer(info->level)); 44 45 return janet_unwrap_integer(janet_call( 46 janet_callback, 4, 47 (const Janet[]){janet_cstringv(path), stat2table(st, NULL), 48 janet_ckeywordv(FTW_(flag)), janet_wrap_table(ftwtab)})); 49 } 50 51 struct { 52 const char *name; 53 int value; 54 } flagnames[] = { 55 {"chdir", FTW_CHDIR}, 56 {"depth", FTW_DEPTH}, 57 {"mount", FTW_MOUNT}, 58 {"phys", FTW_PHYS}, 59 }; 60 61 static Janet c_nftw(int32_t argc, Janet *argv) { 62 janet_arity(argc, 3, 7); 63 64 int flags = 0; 65 66 for (int i = 3; i < argc; i++) { 67 for (int j = 0; j < sizeof(flagnames) / sizeof(flagnames[0]); j++) { 68 if (strcmp((const char *)janet_unwrap_keyword(argv[i]), 69 flagnames[j].name) == 0) { 70 flags |= flagnames[j].value; 71 break; 72 } 73 } 74 } 75 76 janet_callback = janet_unwrap_function(argv[1]); 77 78 return janet_wrap_integer(nftw((const char *)janet_unwrap_string(argv[0]), 79 callback, janet_unwrap_integer(argv[2]), 80 flags)); 81 } 82 83 static Janet c_fileno(int32_t argc, Janet *argv) { 84 janet_fixarity(argc, 1); 85 return janet_wrap_integer( 86 fileno(((JanetFile *)janet_unwrap_abstract(argv[0]))->file)); 87 } 88 89 static Janet c_fstat(int32_t argc, Janet *argv) { 90 janet_arity(argc, 1, 2); 91 92 struct stat st; 93 if (fstat(janet_unwrap_integer(argv[0]), &st) == -1) 94 return janet_wrap_nil(); 95 96 const uint8_t *key = 97 argc == 2 ? (const uint8_t *)janet_unwrap_string(argv[1]) : NULL; 98 99 return stat2table(&st, key); 100 } 101 102 static int O_(char name) { 103 switch (name) { 104 case '+': 105 return O_APPEND; 106 case 'c': 107 return O_CREAT; 108 case 'x': 109 return O_EXCL; 110 case '-': 111 return O_TRUNC; 112 default: 113 return 0; 114 } 115 } 116 117 static int parseO(const unsigned char *opts) { 118 int flags = 0; 119 bool read = false; 120 bool write = false; 121 for (int i = 0; opts[i]; i++) { 122 if (opts[i] == 'w') 123 write = true; 124 else if (opts[i] == 'r') 125 read = true; 126 else 127 flags |= O_(opts[i]); 128 } 129 130 if (read && write) 131 flags |= O_RDWR; 132 else if (write) 133 flags |= O_WRONLY; 134 else if (read) 135 flags |= O_RDONLY; 136 137 return flags; 138 } 139 140 static Janet c_open(int argc, Janet *argv) { 141 janet_arity(argc, 1, 3); 142 143 int flags = argc > 1 ? parseO(janet_unwrap_string(argv[1])) : 0; 144 jmode_t mode = argc > 2 ? os_getmode(argv, 2) : 644; 145 146 return janet_wrap_integer( 147 open((const char *)janet_unwrap_string(argv[0]), flags, mode)); 148 } 149 150 static Janet c_close(int argc, Janet *argv) { 151 janet_fixarity(argc, 1); 152 153 return janet_wrap_integer(close(janet_unwrap_integer(argv[0]))); 154 } 155 156 static Janet c_strerror(int argc, Janet *argv) { 157 janet_fixarity(argc, 0); 158 159 return janet_cstringv(strerror(errno)); 160 } 161 162 static JanetReg cfuns[] = { 163 {"nftw", c_nftw, "(nftw path callback fd_limit & flags)\n\nruns nftw"}, 164 {"fileno", c_fileno, "(fileno file)\n\nreturns fd"}, 165 {"fstat", c_fstat, "(fstat fd &opt key)\n\nreturns stats from fd"}, 166 {"open", c_open, "(open path &opt flags mode)\n\nreturns fd"}, 167 {"close", c_close, "(close fd)\n\ncloses fd"}, 168 {"strerror", c_strerror, "(strerror)\n\nprint errno error string"}, 169 {NULL, NULL, NULL}}; 170 171 JANET_MODULE_ENTRY(JanetTable *env) { janet_cfuns(env, "nftw", cfuns); }