command.c (6090B)
1 /* Copyright 2021 Jacob R. Edwards 2 * 3 * This file is part of gawk. 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 3 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <https://www.gnu.org/licenses/>. 17 */ 18 19 #include <errno.h> 20 #include <libgen.h> 21 #include <limits.h> 22 #include <string.h> 23 #include <unistd.h> 24 25 #include "gawk.h" 26 #include "net.h" 27 #include "util.h" 28 29 /* 30 * NOTE: The second and last parameters of the commands should at 31 * every level (of pointers) be treated as immutable. 32 * 33 * TODO: Figure out why `char **` -> `char const **` and the like 34 * causes warnings and, if possible, make the second and last 35 * parameters of commands truely immutable. 36 */ 37 38 #define LOCAL /* functions local to this file */ 39 40 char ** 41 itemtoaddr(char **request) 42 { 43 return request + 1; 44 } 45 46 LOCAL int 47 type(int c, char const *types, int want) 48 { 49 if (strchr(types, c) != NULL) 50 return !want; 51 else return want; 52 } 53 54 LOCAL int 55 wtype(char const *argv0, int c, char const *types, int want) 56 { 57 if (type(c, types, want) == 1) { 58 warn(0, "%s: '%c': Invalid type", argv0, c); 59 return 1; 60 } 61 return 0; 62 } 63 64 LOCAL int 65 warg(int min, int max, int argc, char **ap) 66 { 67 if (max > 0 && argc > max) 68 warn(0, "%s: '%s'... unused", *ap, ap[max]); 69 else if (min > 0 && argc < min) 70 warn(0, "%s: Not enough arguments", *ap); 71 else 72 return 0; 73 return 1; 74 } 75 76 int 77 cextern(int argc, char **argv, int ino, char **item) 78 { 79 char url[MY_URL_MAX]; 80 int i; 81 82 if (warg(2, -1, argc, argv)) 83 return FAIL; 84 85 snprintf(url, sizeof(url), "%s%s", item[GI_HOST], item[GI_PATH]); 86 for (i = 1; i < argc; ++i) 87 if (strcmp(argv[i], "%") == 0) 88 argv[i] = url; 89 90 switch (fork()) { 91 case -1: 92 warn(errno, "unable to fork"); 93 return FAIL; 94 case 0: 95 ++argv; 96 execvp(*argv, argv); 97 warn(errno, "execvp '%s'", *argv); 98 _exit(1); 99 } 100 101 return PASS; 102 } 103 104 LOCAL int 105 timid_gopher(char **addr, char *path, int bin, int timeout) 106 { 107 if (!exists(path)) 108 return gopher(addr, path, bin, timeout); 109 warn(EEXIST, "not writing to '%s'", path); 110 return 1; 111 } 112 113 int 114 cfetch(int argc, char **argv, int ino, char **item) 115 { 116 char *path; 117 int bin; 118 119 if (warg(1, 2, argc, argv) || wtype(*argv, **item, "i3", 0)) 120 return FAIL; 121 122 if (argv[1]) 123 path = argv[1]; 124 else { 125 path = basename(item[GI_PATH]); 126 if (path == NULL) { 127 warn(errno, "unable to get basename '%s'", item[GI_PATH]); 128 return NEXT; 129 } 130 } 131 132 bin = **item == '0' ? 0 : 1; 133 if (timid_gopher(itemtoaddr(item), path, bin, timeout)) 134 return NEXT; 135 warn(0, "%s: '%s%s' > '%s'", *argv, item[GI_HOST], item[GI_PATH], path); 136 return PASS; 137 } 138 139 LOCAL int 140 cgoto7(int argc, char **argv, int ino, char **item) 141 { 142 char tmp[MY_PATH_MAX]; 143 144 if (wtype(*argv, **item, "7", 1) || warg(2, 2, argc, argv)) 145 return FAIL; 146 147 /* NOTE: the user inserts `?` for a space */ 148 snprintf(tmp, sizeof(tmp), "%s?%s", item[GI_PATH], argv[1]); 149 item[GI_PATH] = tmp; 150 return gawk(itemtoaddr(item)); 151 } 152 153 int 154 cgoto(int argc, char **argv, int ino, char **item) 155 { 156 if (**item == '1') { 157 if (warg(1, 1, argc, argv)) 158 return FAIL; 159 return gawk(itemtoaddr(item)); 160 } 161 return cgoto7(argc, argv, ino, item); 162 } 163 164 int 165 cprint(int argc, char **argv, int ino, char **item) 166 { 167 if (warg(1, 1, argc, argv)) 168 return FAIL; 169 170 if (**item == 'i') 171 printf(" %s\n", item[GI_INFO] + 1); 172 else if (**item == '3') 173 fprintf(stderr, "%s: %s\n", item[GI_HOST], item[GI_INFO] + 1); 174 else 175 printf("%4d [%c] %s\n", ino, item[GI_INFO][0], 176 item[GI_INFO] + 1); 177 return PASS; 178 } 179 180 int 181 cprintv(int argc, char **argv, int ino, char **item) 182 { 183 if (**item != 'i' && **item != '3') 184 printf("\n %s%s\n", item[GI_HOST], item[GI_PATH]); 185 return cprint(argc, argv, ino, item); 186 } 187 188 int 189 findex(int argc, char **argv, int ino, char **item) 190 { 191 char const *err; 192 int i; 193 int n; 194 195 if (warg(2, -1, argc, argv)) 196 return FAIL; 197 198 for (i = 1; i < argc; ++i) { 199 n = wstrtonum(argv[i], 0, INT_MAX, &err); 200 if (err != NULL) 201 return FAIL; 202 if (ino == n) 203 return PASS; 204 } 205 return NEXT; 206 } 207 208 int 209 frange(int argc, char **argv, int ino, char **item) 210 { 211 char const *err; 212 int i, j; 213 int range[2]; 214 215 if (warg(3, -1, argc, argv)) 216 return FAIL; 217 if (argc % 2 != 1) { 218 warn(0, "%s: Unbalenced range", *argv); 219 return FAIL; 220 } 221 222 for (i = 1; i < argc; i += 2) { 223 for (j = 0; j < 2; ++j) { 224 range[j] = wstrtonum(argv[i + j], 0, INT_MAX, &err); 225 if (err != NULL) 226 return FAIL; 227 } 228 if (range[0] > range[1]) { 229 if (ino < range[1] || ino > range[0]) 230 return NEXT; 231 } else if (ino < range[0] || ino > range[1]) 232 return NEXT; 233 } 234 235 return PASS; 236 } 237 238 int 239 fstring(int argc, char **argv, int ino, char **item) 240 { 241 int i; 242 243 if (warg(2, -1, argc, argv)) 244 return FAIL; 245 for (i = 1; i < argc; ++i) 246 if (strcasestr(item[GI_INFO], argv[1]) == NULL) 247 return NEXT; 248 return PASS; 249 } 250 251 int 252 ftype(int argc, char **argv, int ino, char **item) 253 { 254 if (warg(2, 2, argc, argv)) 255 return FAIL; 256 if (type(**item, argv[1], 0)) 257 return PASS; 258 return NEXT; 259 } 260 261 int 262 sexit(int argc, char **argv, int depth, char **addr) 263 { 264 if (warg(1, 1, argc, argv)) 265 return FAIL; 266 return depth; 267 } 268 269 int 270 sgoto(int argc, char **argv, int depth, char **addr) 271 { 272 char *newaddr[AR_NULL]; 273 int i; 274 275 if (warg(1, 4, argc, argv)) 276 return FAIL; 277 278 newaddr[AR_HOST] = addr[AR_HOST]; 279 newaddr[AR_PATH] = "/"; 280 newaddr[AR_PORT] = addr[AR_PORT]; 281 282 for (i = 1; i < argc; ++i) 283 newaddr[i - 1] = argv[i]; 284 return gawk(newaddr); 285 } 286 287 int 288 sunwind(int argc, char **argv, int depth, char **addr) 289 { 290 char const *err; 291 int n; 292 293 if (warg(1, 2, argc, argv)) 294 return FAIL; 295 296 if (argc == 1) 297 n = 1; 298 else { 299 n = wstrtonum(argv[1], 0, INT_MAX, &err); 300 if (err != NULL) 301 return FAIL; 302 } 303 return n; 304 }