/** * Compares two FileItems. * * Based on 'ustricmp' of Allegro. It makes sure that eg "foo.bar" * comes before "foo-1.bar", and also that "foo9.bar" comes before * "foo10.bar". */ int FileItem::compare(const FileItem& that) const { if (IS_FOLDER(this)) { if (!IS_FOLDER(&that)) return -1; } else if (IS_FOLDER(&that)) return 1; { int c1, c2; int x1, x2; char *t1, *t2; const char* s1 = this->displayname.c_str(); const char* s2 = that.displayname.c_str(); for (;;) { c1 = utolower(ugetxc(&s1)); c2 = utolower(ugetxc(&s2)); if ((c1 >= '0') && (c1 <= '9') && (c2 >= '0') && (c2 <= '9')) { x1 = ustrtol(s1 - ucwidth(c1), &t1, 10); x2 = ustrtol(s2 - ucwidth(c2), &t2, 10); if (x1 != x2) return x1 - x2; else if (t1 - s1 != t2 - s2) return (t2 - s2) - (t1 - s1); s1 = t1; s2 = t2; } else if (c1 != c2) { if (!c1) return -1; else if (!c2) return 1; else if (c1 == '.') return -1; else if (c2 == '.') return 1; return c1 - c2; } if (!c1) return 0; } } return -1; }
/* ustrfilecmp: * ustricmp for filenames: makes sure that eg "foo.bar" comes before * "foo-1.bar", and also that "foo9.bar" comes before "foo10.bar". */ static int ustrfilecmp(AL_CONST char *s1, AL_CONST char *s2) { int c1, c2; int x1, x2; char *t1, *t2; for(;;) { c1 = utolower(ugetxc(&s1)); c2 = utolower(ugetxc(&s2)); if((c1 >= '0') && (c1 <= '9') && (c2 >= '0') && (c2 <= '9')) { x1 = ustrtol(s1 - ucwidth(c1), &t1, 10); x2 = ustrtol(s2 - ucwidth(c2), &t2, 10); if(x1 != x2) return x1 - x2; else if(t1 - s1 != t2 - s2) return (t2 - s2) - (t1 - s1); s1 = t1; s2 = t2; } else if(c1 != c2) { if(!c1) return -1; else if(!c2) return 1; else if(c1 == '.') return -1; else if(c2 == '.') return 1; return c1 - c2; } if(!c1) return 0; } }
/* parse_extension_string: * Parses the extension string, possibly containing attribute characters. */ static void parse_extension_string(AL_CONST char *ext) { attrb_state_t state; char ext_tokens[32], attrb_char[32]; char *last, *p, *attrb_p; int c, c2, i; i = 0; fext_size = 0; fext_p = NULL; attrb_p = NULL; if(!ext) return; fext = ustrdup(ext); /* Tokenize the extension string and record the pointers to the * beginning of each token in a dynamically growing array. * ???? We rely on the implementation of ustrtok_r() which writes * null characters in the string to delimit the tokens. Yuck. */ c = usetc(ext_tokens, ' '); c += usetc(ext_tokens+c, ','); c += usetc(ext_tokens+c, ';'); usetc(ext_tokens+c, 0); p = ustrtok_r(fext, ext_tokens, &last); if(p == NULL || !ugetc(p)) return; do { /* Set of attribute characters. */ if(ugetc(p) == '/') { attrb_p = p + ucwidth('/'); continue; } /* Dynamically grow the array if needed. */ if(i >= fext_size) { fext_size = (fext_size ? fext_size*2 : 2); fext_p = (char **)_al_sane_realloc(fext_p, fext_size * sizeof(char *)); } /* Record a pointer to the beginning of the token. */ fext_p[i++] = p; } while((p = ustrtok_r(NULL, ext_tokens, &last))!=NULL); /* This is the meaningful size now. */ fext_size = i; if(attrb_p) { state = ATTRB_SET; c = usetc(attrb_char, 'r'); c += usetc(attrb_char+c, 'h'); c += usetc(attrb_char+c, 's'); c += usetc(attrb_char+c, 'd'); c += usetc(attrb_char+c, 'a'); c += usetc(attrb_char+c, '+'); c += usetc(attrb_char+c, '-'); usetc(attrb_char+c, 0); /* Scan the string. */ while((c = utolower(ugetx(&attrb_p)))!=0) { p = attrb_char; for(i = 0; (c2 = ugetx(&p))!=0; i++) { if(c == c2) { if(i < ATTRB_MAX) attrb_state[i] = state; else state = (i == ATTRB_MAX) ? ATTRB_SET : ATTRB_UNSET; break; } } } } }
/* fs_flist_putter: * Callback routine for for_each_file() to fill the file selector listbox. */ static void fs_flist_putter(AL_CONST char *str, int attrib, int param) { char ext_tokens[32]; char *s, *ext, *tok, *name; char tmp[512], tmp2[32]; int c, c2, i, k, sign; /* attribute flags (rhsda order) * 0 = not required, 1 = must be set, -1 = must be unset */ int attr_flag[5+5] = { 0, -1, -1, 0, 0, FA_RDONLY, FA_HIDDEN, FA_SYSTEM, FA_DIREC, FA_ARCH }; c = usetc(ext_tokens, ' '); c += usetc(ext_tokens+c, ','); c += usetc(ext_tokens+c, ';'); usetc(ext_tokens+c, 0); s = get_filename(str); fix_filename_case(s); if (fext) { ustrcpy(tmp, fext); ustrtok(tmp, ext_tokens); c = (ustrtok(NULL, ext_tokens) ? 1 : 0); if (!c) { if (!ustrchr(fext, '/')) c = 1; } if (c && (!(attrib & FA_DIREC))) { ustrcpy(tmp, fext); ext = get_extension(s); tok = ustrtok(tmp, ext_tokens); while (tok) { if (ustricmp(ext, tok) == 0) break; tok = ustrtok(NULL, ext_tokens); } if (!tok) return; } c = usetc(ext_tokens, ' '); c += usetc(ext_tokens+c, ','); c += usetc(ext_tokens+c, ';'); c += usetc(ext_tokens+c, '/'); usetc(ext_tokens+c, 0); ustrcpy(tmp, fext); tok = ustrchr(tmp, '/'); if (tok) tok = ustrtok(tok, ext_tokens); if (tok) { sign = 1; c = usetc(tmp2, 'r'); c += usetc(tmp2+c, 'h'); c += usetc(tmp2+c, 's'); c += usetc(tmp2+c, 'd'); c += usetc(tmp2+c, 'a'); c += usetc(tmp2+c, '+'); c += usetc(tmp2+c, '-'); usetc(tmp2+c, 0); /* scan the string */ i = 0; while ((c = utolower(ugetat(tok, i)))) { k = 0; while ((c2 = ugetat(tmp2, k))!=0) { if (c == c2) { if (k<5) { attr_flag[k] = sign; break; } else sign = (k==5) ? 1 : -1; } k++; } i++; } } } /* check if file attributes match */ if (!(attr_flag[3+5] & attrib)) { /* if not a directory, we check all attributes except FA_DIREC */ for (c=0; c<5; c++) { if (c == 3) continue; if ((attr_flag[c] == 1) && (!(attrib & attr_flag[c+5]))) return; if ((attr_flag[c] == -1) && (attrib & attr_flag[c+5])) return; } } else { /* if a directory, we check only FA_DIREC */ if (attr_flag[3] == -1) return; } if ((flist->size < FLIST_SIZE) && ((ugetc(s) != '.') || (ugetat(s, 1)))) { name = malloc(ustrsizez(s) + ((attrib & FA_DIREC) ? ucwidth(OTHER_PATH_SEPARATOR) : 0)); if (!name) return; for (c=0; c<flist->size; c++) { if (ugetat(flist->name[c], -1) == OTHER_PATH_SEPARATOR) { if (attrib & FA_DIREC) if (ustrfilecmp(s, flist->name[c]) < 0) break; } else { if (attrib & FA_DIREC) break; if (ustrfilecmp(s, flist->name[c]) < 0) break; } } for (c2=flist->size; c2>c; c2--) flist->name[c2] = flist->name[c2-1]; flist->name[c] = name; ustrcpy(flist->name[c], s); if (attrib & FA_DIREC) put_backslash(flist->name[c]); flist->size++; } }
int main(int argc, char *argv[]) { int c; if (install_allegro(SYSTEM_NONE, &errno, atexit) != 0) return 1; for (c=1; c<argc; c++) { if (argv[c][0] == '-') { switch (utolower(argv[c][1])) { case 'a': opt_allegro = TRUE; break; case 'b': opt_binary = TRUE; break; case 'c': opt_compress = TRUE; break; case 'd': opt_delete = TRUE; break; case 'x': opt_extract = TRUE; break; case '0': if ((opt_password) || (c >= argc-1)) { usage(); return 1; } opt_password = argv[++c]; break; default: printf("Unknown option '%s'\n", argv[c]); return 1; } } else { if (!opt_filename) opt_filename = argv[c]; else if (!opt_dataname) opt_dataname = argv[c]; else { usage(); return 1; } } } if ((!opt_filename) || ((opt_allegro) && (opt_binary)) || ((opt_delete) && (opt_extract))) { usage(); return 1; } if (opt_password) packfile_password(opt_password); if (opt_delete) { if (opt_dataname) { usage(); return 1; } update_file(opt_filename, NULL); } else if (opt_extract) { if (!opt_dataname) { usage(); return 1; } if ((!opt_allegro) && (!opt_binary)) { printf("The -x option must be used together with -a or -b\n"); return 1; } extract_data(); } else { if (opt_dataname) update_file(opt_filename, opt_dataname); else show_stats(); } return err; }