1 /*\
2 |*| Parity Archive - A way to restore missing files in a set.
3 |*|
4 |*| Copyright (C) 2001 Willem Monsuwe (willem@stack.nl)
5 |*|
6 |*| File format by Stefan Wehlus -
7 |*| initial idea by Tobias Rieper, further suggestions by Kilroy Balore
8 |*|
9 |*| Text User Interface
10 \*/
11
12 #include <stdio.h>
13 #include <ctype.h>
14 #include <string.h>
15 #include <stdlib.h>
16
17 #include "interface.h"
18 #include "fileops.h"
19
20 static u16 **parlist = 0;
21 static u16 **filelist = 0;
22 static u16 **dirlist = 0;
23
24 enum {
25 CMD_FLAGS,
26 CMD_SETFLAGS,
27 CMD_UNSETFLAGS,
28 CMD_LOAD,
29 CMD_SEARCH,
30 CMD_UNLOAD,
31 CMD_PARLIST,
32 CMD_FILELIST,
33 CMD_DIRLIST,
34 CMD_CHECK,
35 CMD_FIND,
36 CMD_FIXNAME,
37 CMD_GETSTATUS,
38 CMD_SETSTATUS,
39 CMD_RECOVER,
40 CMD_ADDFILE,
41 CMD_REMOVEFILE,
42 CMD_ADDPARS,
43 CMD_CREATE,
44 CMD_SETSMART,
45 CMD_HELP,
46 CMD_QUIT,
47 CMD_UNKNOWN,
48 CMD_AMBIGUOUS
49 };
50
51 static struct cmds {
52 char *str;
53 int cmd;
54 } cmds[] = {
55 { "FLAGS", CMD_FLAGS },
56 { "SETFLAGS", CMD_SETFLAGS },
57 { "UNSETFLAGS", CMD_UNSETFLAGS },
58 { "LOAD", CMD_LOAD },
59 { "SEARCH", CMD_SEARCH },
60 { "UNLOAD", CMD_UNLOAD },
61 { "PARLIST", CMD_PARLIST },
62 { "FILELIST", CMD_FILELIST },
63 { "DIRLIST", CMD_DIRLIST },
64 { "CHECK", CMD_CHECK },
65 { "FIND", CMD_FIND },
66 { "FIXNAME", CMD_FIXNAME },
67 { "GETSTATUS", CMD_GETSTATUS },
68 { "SETSTATUS", CMD_SETSTATUS },
69 { "RECOVER", CMD_RECOVER },
70 { "ADDFILE", CMD_ADDFILE },
71 { "REMOVEFILE", CMD_REMOVEFILE },
72 { "ADDPARS", CMD_ADDPARS },
73 { "CREATE", CMD_CREATE },
74 { "SETSMART", CMD_SETSMART },
75 { "HELP", CMD_HELP },
76 { "QUIT", CMD_QUIT }
77 };
78
79 #define NO_CMDS (sizeof(cmds) / sizeof(*cmds))
80
81 static void
print_help(void)82 print_help(void)
83 {
84 printf(
85 "FLAGS : Show the current flags (with numbers).\n"
86 "SETFLAGS <n> : Set flag number <n>.\n"
87 "UNSETFLAGS <n> : Unset flag number <n>.\n"
88 "SETSMART [<entry> <name>] : Setup handling of consistently misnamed files.\n"
89 "LOAD <filename> : Add a (new) PAR file to the current list.\n"
90 "SEARCH : Search for PAR files matching the current filelist.\n"
91 "UNLOAD <entry> : Remove a PAR file from the list.\n"
92 "PARLIST : Show the current list of PAR files.\n"
93 "FILELIST : Show the current list of data files.\n"
94 "DIRLIST : Show the currently cached directory entries.\n"
95 "CHECK <entry> : Check the MD5sum of a file.\n"
96 "FIND <entry> : Find a file by its filename.\n"
97 "FIXNAME [<entry>] : Fix faulty filenames [of <entry>].\n"
98 "GETSTATUS <entry> : Get the status bits of an entry.\n"
99 "SETSTATUS <entry> <status> : Set the status bits of an entry.\n"
100 "RECOVER [<entry>] : Recover missing files [only <entry>]\n"
101 "ADDFILE <filename> : Add a data file to the current filelist.\n"
102 "REMOVEFILE <entry> : Remove a data file from the current filelist.\n"
103 "ADDPARS <number> : Add new PAR files until there are <number>.\n"
104 "CREATE [<entry>] : Create PAR files [only <entry>].\n"
105 "HELP : Show this help.\n"
106 "QUIT : Quit.\n"
107 );
108 }
109
110 static int cc = '\n';
111
112 #define EOL(x) (((x) == '\n') || ((x) == EOF))
113
114 static void
sort_cmds(void)115 sort_cmds(void)
116 {
117 int i, j, k;
118
119 k = NO_CMDS - 1;
120 do {
121 for (i = j = 0; i < k; i++) {
122 if (strcmp(cmds[i].str, cmds[i + 1].str) > 0) {
123 struct cmds tmp;
124 tmp = cmds[i + 1];
125 cmds[i + 1] = cmds[i];
126 cmds[i] = tmp;
127 j = i;
128 }
129 }
130 k = j;
131 } while (k > 0);
132 }
133
134 static int
get_cmd(void)135 get_cmd(void)
136 {
137 struct cmds *l, *r;
138 int c;
139 int idx;
140
141 do {
142 while (!EOL(cc))
143 cc = getchar();
144
145 if (cc == EOF)
146 return CMD_QUIT;
147
148 putchar('>'); fflush(stdout);
149
150 l = cmds;
151 r = cmds + NO_CMDS - 1;
152 for (idx = 0;; idx++) {
153 cc = getchar();
154 if (!isalnum(cc))
155 break;
156 c = toupper(cc);
157 while (c > l->str[idx])
158 if (++l > r)
159 return CMD_UNKNOWN;
160 while (c < r->str[idx])
161 if (--r < l)
162 return CMD_UNKNOWN;
163 }
164 } while (idx == 0);
165 if (r > l)
166 return CMD_AMBIGUOUS;
167 return l->cmd;
168 }
169
170 static int bufidx = 0;
171
172 static u16 *
buf_add(u16 c)173 buf_add(u16 c)
174 {
175 static u16 *buf = 0;
176 static int bufsz = 0;
177
178 if (bufidx >= bufsz) {
179 bufsz += 256;
180 buf = realloc(buf, bufsz * sizeof(*buf));
181 }
182 buf[bufidx++] = c;
183 return buf;
184 }
185
186 static u16 *
get_str(void)187 get_str(void)
188 {
189 bufidx = 0;
190 while (isspace(cc)) {
191 if (EOL(cc))
192 return buf_add(0);
193 cc = getchar();
194 }
195 do {
196 buf_add(cc);
197 cc = getchar();
198 } while (!EOL(cc));
199 return buf_add(0);
200 }
201
202 static i64
get_number(void)203 get_number(void)
204 {
205 i64 ret;
206 int base = 10;
207
208 while (isspace(cc)) {
209 if (EOL(cc))
210 return 0;
211 cc = getchar();
212 }
213 ret = 0;
214 if (cc == '0') {
215 base = 8;
216 cc = getchar();
217 }
218 if ((cc == 'x') || (cc == 'X') || (cc == '$')) {
219 base = 16;
220 cc = getchar();
221 }
222 for (;;) {
223 int c;
224
225 c = toupper(cc);
226 if (c >= 'a') c -= 'a';
227 else c -= '0';
228 if ((c < 0) || (c >= base)) return ret;
229 ret = ret * base + c;
230 cc = getchar();
231 }
232 }
233
234 static u16 *
get_entry(u16 ** list)235 get_entry(u16 **list)
236 {
237 i64 num, i;
238
239 i = get_number();
240 if (!list) return 0;
241 for (num = 0; list[num]; num++)
242 ;
243 if ((i < 0) || (i > num))
244 i = 0;
245 if (i == 0) return 0;
246 return list[i - 1];
247 }
248
249 static void
print_errcode(int code)250 print_errcode(int code)
251 {
252 static char *err_list[] = {
253 "OK",
254 "ERROR: File error",
255 "ERROR: Does not exist",
256 "ERROR: Not found",
257 "ERROR: Corrupt",
258 "ERROR: Failed",
259 "ERROR: Already loaded",
260 "ERROR: Not Implemented",
261 "ERROR: Name Clash",
262 "ERROR: Invalid Argument"
263 };
264 printf("%s\n", err_list[code]);
265 }
266
267 static void
print_flags(int flags)268 print_flags(int flags)
269 {
270 static char *flag_list[] = {
271 "MOVE",
272 "CASE",
273 "CTRL",
274 "KEEP",
275 };
276 unsigned int i;
277
278 for (i = 0; i < (sizeof(flag_list) / sizeof(*flag_list)); i++)
279 {
280 if (i > 0) printf(", ");
281 if (!(flags & (1 << i))) printf("NO");
282 printf("%s(%d)", flag_list[i], 1 << i);
283 }
284 printf("\n");
285 }
286
287 static void
print_string(u16 * str)288 print_string(u16 *str)
289 {
290 while (*str)
291 putchar(*str++);
292 putchar('\n');
293 }
294
295 static void
print_number(i64 num)296 print_number(i64 num)
297 {
298 printf("0x%llx\n", num);
299 }
300
301 static void
print_list(u16 ** list)302 print_list(u16 **list)
303 {
304 int i;
305
306 for (i = 1; *list; list++, i++) {
307 printf("%3d: ", i);
308 print_string(*list);
309 }
310 }
311
312 /*\ Parse commands until QUIT is read \*/
313 void
ui_text(void)314 ui_text(void)
315 {
316 u16 *e;
317
318 sort_cmds();
319 cc = '\n';
320
321 for (;;) switch (get_cmd()) {
322 case CMD_FLAGS:
323 print_flags(par_flags());
324 break;
325 case CMD_SETFLAGS:
326 print_flags(par_setflags(get_number()));
327 break;
328 case CMD_UNSETFLAGS:
329 print_flags(par_unsetflags(get_number()));
330 break;
331 case CMD_LOAD:
332 print_errcode(par_load(get_str()));
333 break;
334 case CMD_SEARCH:
335 print_errcode(par_search(get_number()));
336 break;
337 case CMD_UNLOAD:
338 print_errcode(par_unload(get_entry(parlist)));
339 break;
340 case CMD_PARLIST:
341 if (parlist) free(parlist);
342 parlist = par_parlist();
343 print_list(parlist);
344 break;
345 case CMD_FILELIST:
346 if (filelist) free(filelist);
347 filelist = par_filelist();
348 print_list(filelist);
349 break;
350 case CMD_DIRLIST:
351 if (dirlist) free(dirlist);
352 dirlist = par_dirlist();
353 print_list(dirlist);
354 break;
355 case CMD_CHECK:
356 e = get_entry(filelist);
357 if (e) {
358 print_errcode(par_check(e));
359 } else if (filelist) {
360 int i;
361 for (i = 0; filelist[i]; i++) {
362 printf("CHECK ");
363 print_string(filelist[i]);
364 print_errcode(par_check(filelist[i]));
365 }
366 } else {
367 printf("ERROR: No filelist.\n");
368 }
369 break;
370 case CMD_FIND:
371 e = get_entry(filelist);
372 if (e) {
373 print_string(par_find(e));
374 } else if (filelist) {
375 int i;
376 for (i = 0; filelist[i]; i++) {
377 printf("FIND ");
378 print_string(filelist[i]);
379 print_string(par_find(filelist[i]));
380 }
381 } else {
382 printf("ERROR: No filelist.\n");
383 }
384 break;
385 case CMD_FIXNAME:
386 print_errcode(par_fixname(get_entry(filelist)));
387 break;
388 case CMD_GETSTATUS:
389 print_number(par_getstatus(get_entry(filelist)));
390 break;
391 case CMD_SETSTATUS:
392 e = get_entry(filelist);
393 print_errcode(par_setstatus(e, get_number()));
394 break;
395 case CMD_RECOVER:
396 print_errcode(par_recover(get_entry(filelist)));
397 break;
398 case CMD_ADDFILE:
399 print_errcode(par_addfile(get_str()));
400 break;
401 case CMD_REMOVEFILE:
402 print_errcode(par_removefile(get_entry(filelist)));
403 break;
404 case CMD_ADDPARS:
405 e = get_entry(parlist);
406 print_errcode(par_addpars(e, get_number()));
407 break;
408 case CMD_CREATE:
409 print_errcode(par_create(get_entry(parlist)));
410 break;
411 case CMD_SETSMART:
412 e = get_entry(filelist);
413 print_errcode(par_setsmart(e, e ? get_str() : 0));
414 break;
415 case CMD_QUIT:
416 return;
417 case CMD_HELP:
418 print_help();
419 break;
420 case CMD_AMBIGUOUS:
421 printf("Ambiguous command.\n");
422 break;
423 default:
424 printf("Unknown command.\n");
425 break;
426 }
427 }
428