/*\ |*| Parity Archive - A way to restore missing files in a set. |*| |*| Copyright (C) 2001 Willem Monsuwe (willem@stack.nl) |*| |*| File format by Stefan Wehlus - |*| initial idea by Tobias Rieper, further suggestions by Kilroy Balore |*| |*| Text User Interface \*/ #include #include #include #include #include "interface.h" #include "fileops.h" static u16 **parlist = 0; static u16 **filelist = 0; static u16 **dirlist = 0; enum { CMD_FLAGS, CMD_SETFLAGS, CMD_UNSETFLAGS, CMD_LOAD, CMD_SEARCH, CMD_UNLOAD, CMD_PARLIST, CMD_FILELIST, CMD_DIRLIST, CMD_CHECK, CMD_FIND, CMD_FIXNAME, CMD_GETSTATUS, CMD_SETSTATUS, CMD_RECOVER, CMD_ADDFILE, CMD_REMOVEFILE, CMD_ADDPARS, CMD_CREATE, CMD_SETSMART, CMD_HELP, CMD_QUIT, CMD_UNKNOWN, CMD_AMBIGUOUS }; static struct cmds { char *str; int cmd; } cmds[] = { { "FLAGS", CMD_FLAGS }, { "SETFLAGS", CMD_SETFLAGS }, { "UNSETFLAGS", CMD_UNSETFLAGS }, { "LOAD", CMD_LOAD }, { "SEARCH", CMD_SEARCH }, { "UNLOAD", CMD_UNLOAD }, { "PARLIST", CMD_PARLIST }, { "FILELIST", CMD_FILELIST }, { "DIRLIST", CMD_DIRLIST }, { "CHECK", CMD_CHECK }, { "FIND", CMD_FIND }, { "FIXNAME", CMD_FIXNAME }, { "GETSTATUS", CMD_GETSTATUS }, { "SETSTATUS", CMD_SETSTATUS }, { "RECOVER", CMD_RECOVER }, { "ADDFILE", CMD_ADDFILE }, { "REMOVEFILE", CMD_REMOVEFILE }, { "ADDPARS", CMD_ADDPARS }, { "CREATE", CMD_CREATE }, { "SETSMART", CMD_SETSMART }, { "HELP", CMD_HELP }, { "QUIT", CMD_QUIT } }; #define NO_CMDS (sizeof(cmds) / sizeof(*cmds)) static void print_help(void) { printf( "FLAGS : Show the current flags (with numbers).\n" "SETFLAGS : Set flag number .\n" "UNSETFLAGS : Unset flag number .\n" "SETSMART [ ] : Setup handling of consistently misnamed files.\n" "LOAD : Add a (new) PAR file to the current list.\n" "SEARCH : Search for PAR files matching the current filelist.\n" "UNLOAD : Remove a PAR file from the list.\n" "PARLIST : Show the current list of PAR files.\n" "FILELIST : Show the current list of data files.\n" "DIRLIST : Show the currently cached directory entries.\n" "CHECK : Check the MD5sum of a file.\n" "FIND : Find a file by its filename.\n" "FIXNAME [] : Fix faulty filenames [of ].\n" "GETSTATUS : Get the status bits of an entry.\n" "SETSTATUS : Set the status bits of an entry.\n" "RECOVER [] : Recover missing files [only ]\n" "ADDFILE : Add a data file to the current filelist.\n" "REMOVEFILE : Remove a data file from the current filelist.\n" "ADDPARS : Add new PAR files until there are .\n" "CREATE [] : Create PAR files [only ].\n" "HELP : Show this help.\n" "QUIT : Quit.\n" ); } static int cc = '\n'; #define EOL(x) (((x) == '\n') || ((x) == EOF)) static void sort_cmds(void) { int i, j, k; k = NO_CMDS - 1; do { for (i = j = 0; i < k; i++) { if (strcmp(cmds[i].str, cmds[i + 1].str) > 0) { struct cmds tmp; tmp = cmds[i + 1]; cmds[i + 1] = cmds[i]; cmds[i] = tmp; j = i; } } k = j; } while (k > 0); } static int get_cmd(void) { struct cmds *l, *r; int c; int idx; do { while (!EOL(cc)) cc = getchar(); if (cc == EOF) return CMD_QUIT; putchar('>'); fflush(stdout); l = cmds; r = cmds + NO_CMDS - 1; for (idx = 0;; idx++) { cc = getchar(); if (!isalnum(cc)) break; c = toupper(cc); while (c > l->str[idx]) if (++l > r) return CMD_UNKNOWN; while (c < r->str[idx]) if (--r < l) return CMD_UNKNOWN; } } while (idx == 0); if (r > l) return CMD_AMBIGUOUS; return l->cmd; } static int bufidx = 0; static u16 * buf_add(u16 c) { static u16 *buf = 0; static int bufsz = 0; if (bufidx >= bufsz) { bufsz += 256; buf = realloc(buf, bufsz * sizeof(*buf)); } buf[bufidx++] = c; return buf; } static u16 * get_str(void) { bufidx = 0; while (isspace(cc)) { if (EOL(cc)) return buf_add(0); cc = getchar(); } do { buf_add(cc); cc = getchar(); } while (!EOL(cc)); return buf_add(0); } static i64 get_number(void) { i64 ret; int base = 10; while (isspace(cc)) { if (EOL(cc)) return 0; cc = getchar(); } ret = 0; if (cc == '0') { base = 8; cc = getchar(); } if ((cc == 'x') || (cc == 'X') || (cc == '$')) { base = 16; cc = getchar(); } for (;;) { int c; c = toupper(cc); if (c >= 'a') c -= 'a'; else c -= '0'; if ((c < 0) || (c >= base)) return ret; ret = ret * base + c; cc = getchar(); } } static u16 * get_entry(u16 **list) { i64 num, i; i = get_number(); if (!list) return 0; for (num = 0; list[num]; num++) ; if ((i < 0) || (i > num)) i = 0; if (i == 0) return 0; return list[i - 1]; } static void print_errcode(int code) { static char *err_list[] = { "OK", "ERROR: File error", "ERROR: Does not exist", "ERROR: Not found", "ERROR: Corrupt", "ERROR: Failed", "ERROR: Already loaded", "ERROR: Not Implemented", "ERROR: Name Clash", "ERROR: Invalid Argument" }; printf("%s\n", err_list[code]); } static void print_flags(int flags) { static char *flag_list[] = { "MOVE", "CASE", "CTRL", "KEEP", }; unsigned int i; for (i = 0; i < (sizeof(flag_list) / sizeof(*flag_list)); i++) { if (i > 0) printf(", "); if (!(flags & (1 << i))) printf("NO"); printf("%s(%d)", flag_list[i], 1 << i); } printf("\n"); } static void print_string(u16 *str) { while (*str) putchar(*str++); putchar('\n'); } static void print_number(i64 num) { printf("0x%llx\n", num); } static void print_list(u16 **list) { int i; for (i = 1; *list; list++, i++) { printf("%3d: ", i); print_string(*list); } } /*\ Parse commands until QUIT is read \*/ void ui_text(void) { u16 *e; sort_cmds(); cc = '\n'; for (;;) switch (get_cmd()) { case CMD_FLAGS: print_flags(par_flags()); break; case CMD_SETFLAGS: print_flags(par_setflags(get_number())); break; case CMD_UNSETFLAGS: print_flags(par_unsetflags(get_number())); break; case CMD_LOAD: print_errcode(par_load(get_str())); break; case CMD_SEARCH: print_errcode(par_search(get_number())); break; case CMD_UNLOAD: print_errcode(par_unload(get_entry(parlist))); break; case CMD_PARLIST: if (parlist) free(parlist); parlist = par_parlist(); print_list(parlist); break; case CMD_FILELIST: if (filelist) free(filelist); filelist = par_filelist(); print_list(filelist); break; case CMD_DIRLIST: if (dirlist) free(dirlist); dirlist = par_dirlist(); print_list(dirlist); break; case CMD_CHECK: e = get_entry(filelist); if (e) { print_errcode(par_check(e)); } else if (filelist) { int i; for (i = 0; filelist[i]; i++) { printf("CHECK "); print_string(filelist[i]); print_errcode(par_check(filelist[i])); } } else { printf("ERROR: No filelist.\n"); } break; case CMD_FIND: e = get_entry(filelist); if (e) { print_string(par_find(e)); } else if (filelist) { int i; for (i = 0; filelist[i]; i++) { printf("FIND "); print_string(filelist[i]); print_string(par_find(filelist[i])); } } else { printf("ERROR: No filelist.\n"); } break; case CMD_FIXNAME: print_errcode(par_fixname(get_entry(filelist))); break; case CMD_GETSTATUS: print_number(par_getstatus(get_entry(filelist))); break; case CMD_SETSTATUS: e = get_entry(filelist); print_errcode(par_setstatus(e, get_number())); break; case CMD_RECOVER: print_errcode(par_recover(get_entry(filelist))); break; case CMD_ADDFILE: print_errcode(par_addfile(get_str())); break; case CMD_REMOVEFILE: print_errcode(par_removefile(get_entry(filelist))); break; case CMD_ADDPARS: e = get_entry(parlist); print_errcode(par_addpars(e, get_number())); break; case CMD_CREATE: print_errcode(par_create(get_entry(parlist))); break; case CMD_SETSMART: e = get_entry(filelist); print_errcode(par_setsmart(e, e ? get_str() : 0)); break; case CMD_QUIT: return; case CMD_HELP: print_help(); break; case CMD_AMBIGUOUS: printf("Ambiguous command.\n"); break; default: printf("Unknown command.\n"); break; } }