/** * 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; }
std::string make_utf8_seq(int codepoint) { int num_bytes = ucwidth(codepoint); char byte_sequence[num_bytes + 1]; // +1 for terminating 0 usetc(byte_sequence, codepoint); byte_sequence[num_bytes] = 0; return std::string(byte_sequence); }
/* 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; } }
/* be_sys_find_resource: * This is the same of the unix resource finder; it looks into the * home directory and in /etc. */ int be_sys_find_resource(char *dest, AL_CONST char *resource, int size) { char buf[256], tmp[256], *last; char *home = getenv("HOME"); if (home) { /* look for ~/file */ append_filename(buf, uconvert_ascii(home, tmp), resource, sizeof(buf)); if (exists(buf)) { ustrzcpy(dest, size, buf); return 0; } /* if it is a .cfg, look for ~/.filerc */ if (ustricmp(get_extension(resource), uconvert_ascii("cfg", tmp)) == 0) { ustrzcpy(buf, sizeof(buf) - ucwidth(OTHER_PATH_SEPARATOR), uconvert_ascii(home, tmp)); put_backslash(buf); ustrzcat(buf, sizeof(buf), uconvert_ascii(".", tmp)); ustrzcpy(tmp, sizeof(tmp), resource); ustrzcat(buf, sizeof(buf), ustrtok_r(tmp, ".", &last)); ustrzcat(buf, sizeof(buf), uconvert_ascii("rc", tmp)); if (file_exists(buf, FA_ARCH | FA_RDONLY | FA_HIDDEN, NULL)) { ustrzcpy(dest, size, buf); return 0; } } } /* look for /etc/file */ append_filename(buf, uconvert_ascii("/etc/", tmp), resource, sizeof(buf)); if (exists(buf)) { ustrzcpy(dest, size, buf); return 0; } /* if it is a .cfg, look for /etc/filerc */ if (ustricmp(get_extension(resource), uconvert_ascii("cfg", tmp)) == 0) { ustrzcpy(buf, sizeof(buf), uconvert_ascii("/etc/", tmp)); ustrzcpy(tmp, sizeof(tmp), resource); ustrzcat(buf, sizeof(buf), ustrtok_r(tmp, ".", &last)); ustrzcat(buf, sizeof(buf), uconvert_ascii("rc", tmp)); if (exists(buf)) { ustrzcpy(dest, size, buf); return 0; } } return -1; }
int d_agtk_list_proc(int msg, DIALOG *d, int c) { if (msg == MSG_DRAW) { BITMAP *bmp = gui_get_screen(); int height, listsize, i, len, bar, x, y, w; int fg_color, fg, bg; char *sel = (char *)d->dp2; char s[1024]; (*(getfuncptr)d->dp)(-1, &listsize); height = (d->h-4) / text_height(font); bar = (listsize > height); w = (bar ? d->w-14 : d->w-3); fg_color = (d->flags & D_DISABLED) ? agtk_mg_color : d->fg; /* draw box contents */ for (i=0; i<height; i++) { if (d->d2+i < listsize) { if (d->d2+i == d->d1) { fg = white; bg = blue; } else if ((sel) && (sel[d->d2+i])) { fg = white; bg = blue; } else { fg = black; bg = white; } usetc(s, 0); ustrncat(s, (*(getfuncptr)d->dp)(i+d->d2, NULL), sizeof(s)-ucwidth(0)); x = d->x + 2; y = d->y + 2 + i*text_height(font); rectfill(bmp, x, y, x+7, y+text_height(font)-1, bg); x += 8; len = ustrlen(s); while (text_length(font, s) >= MAX(d->w - 1 - (bar ? 22 : 10), 1)) { len--; usetat(s, len, 0); } textout_ex(bmp, font, s, x, y, fg, bg); x += text_length(font, s); if (x <= d->x+w) rectfill(bmp, x, y, d->x+w, y+text_height(font)-1, bg); #if 0 /* GTK puts a yellow box around the currently selected * item, but it's quite ugly when we emulate it, so * I'm disabling it. --pw */ if (d->d2+i == d->d1) rect(bmp, x-text_length(font, s)-8, y, d->x+w, y+text_height(font)-1, yellow); #endif } else { rectfill(bmp, d->x+2, d->y+2+i*text_height(font), d->x+w, d->y+1+(i+1)*text_height(font), white); } } if (d->y+2+i*text_height(font) <= d->y+d->h-3) rectfill(bmp, d->x+2, d->y+2+i*text_height(font), d->x+w, d->y+d->h-3, white); /* draw frame, maybe with scrollbar */ gtk_draw_scrollable_frame(d, listsize, d->d2, height); return D_O_K; } return d_list_proc(msg, d, c); }
/* jwin_file_select_ex: * Displays the JWin file selector, with the message as caption. * Allows the user to select a file, and stores the selection in the * path buffer, whose length in bytes is given by size and should have * room for at least 80 characters. The files are filtered according to * the file extensions in ext. Passing NULL includes all files, "PCX;BMP" * includes only files with .PCX or .BMP extensions. Returns zero if it * was closed with the Cancel button or non-zero if it was OK'd. */ int jwin_file_select_ex(AL_CONST char *message, char *path, AL_CONST char *ext, int size, int width, int height, FONT *title_font) { static attrb_state_t default_attrb_state[ATTRB_MAX] = DEFAULT_ATTRB_STATE; int ret; char *p; char tmp[32]; ASSERT(message); ASSERT(path); if(title_font) { file_selector[0].dp2=title_font; } if(width == OLD_FILESEL_WIDTH) width = 304; #ifdef HAVE_DIR_LIST if(height == OLD_FILESEL_HEIGHT) height = 160; #else if(height == OLD_FILESEL_HEIGHT) height = 188; #endif /* for fs_dlist_proc() */ ASSERT(size >= 4 * uwidth_max(U_CURRENT)); usetc(updir, 0); file_selector[FS_WIN].dp = (char *)message; file_selector[FS_EDIT].d1 = size/uwidth_max(U_CURRENT) - 1; file_selector[FS_EDIT].dp = path; file_selector[FS_OK].dp = (void*)get_config_text("OK"); file_selector[FS_CANCEL].dp = (void*)get_config_text("Cancel"); /* Set default attributes. */ memcpy(attrb_state, default_attrb_state, sizeof(default_attrb_state)); /* Parse extension string. */ // if (ext)// && ugetc(ext)) { parse_extension_string(ext); } if(!ugetc(path)) { #ifdef HAVE_DIR_LIST int drive = _al_getdrive(); #else int drive = 0; #endif _al_getdcwd(drive, path, size - ucwidth(OTHER_PATH_SEPARATOR)); fix_filename_case(path); fix_filename_slashes(path); put_backslash(path); } clear_keybuf(); do { } while(gui_mouse_b()); file_selector[FS_TYPES].proc = fs_dummy_proc; enlarge_file_selector(width, height); ret = popup_zqdialog(file_selector, FS_EDIT); if(fext) { zc_free(fext); fext = NULL; } if(fext_p) { _al_free(fext_p); fext_p = NULL; } if((ret == FS_CANCEL) || (ret == FS_WIN) || (!ugetc(get_filename(path)))) return FALSE; p = get_extension(path); if((!ugetc(p)) && (ext) && (!ustrpbrk(ext, uconvert_ascii(" ,;", tmp)))) { size -= ((long)(size_t)p - (long)(size_t)path + ucwidth('.')); if(size >= uwidth_max(U_CURRENT) + ucwidth(0)) /* do not end with '.' */ { p += usetc(p, '.'); ustrzcpy(p, size, ext); } } return TRUE; }
/* 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 int fs_flist_putter(AL_CONST char *str, int attrib, void *check_attrib) { char *s, *ext, *name; int c, c2; s = get_filename(str); fix_filename_case(s); if(!(attrib & FA_DIREC)) { /* Check if file extension matches. */ if(fext_p) { ext = get_extension(s); for(c=0; c<fext_size; c++) { if(ustricmp(ext, fext_p[c]) == 0) goto Next; } return 0; } Next: /* Check if file attributes match. */ if(check_attrib) { for(c=0; c<ATTRB_MAX; c++) { if((attrb_state[c] == ATTRB_SET) && (!(attrib & attrb_flag[c]))) return 0; if((attrb_state[c] == ATTRB_UNSET) && (attrib & attrb_flag[c])) return 0; } } } if((flist->size < FLIST_SIZE) && ((ugetc(s) != '.') || (ugetat(s, 1)))) { int size = ustrsizez(s) + ((attrib & FA_DIREC) ? ucwidth(OTHER_PATH_SEPARATOR) : 0); name = (char *) zc_malloc(size); if(!name) return -1; ustrzcpy(name, size, s); if(attrib & FA_DIREC) put_backslash(name); /* Sort alphabetically with directories first. */ for(c=0; c<flist->size; c++) { if(ugetat(flist->name[c], -1) == OTHER_PATH_SEPARATOR) { if(attrib & FA_DIREC) if(ustrfilecmp(name, flist->name[c]) < 0) break; } else { if(attrib & FA_DIREC) break; if(ustrfilecmp(name, flist->name[c]) < 0) break; } } /* Shift in preparation for inserting the new entry. */ for(c2=flist->size; c2>c; c2--) flist->name[c2] = flist->name[c2-1]; /* Insert the new entry. */ flist->name[c] = name; flist->size++; } return 0; }
/* fs_edit_proc: * Dialog procedure for the file selector editable string. */ static int fs_edit_proc(int msg, DIALOG *d, int c) { char *s = (char *) d->dp; int size = (d->d1 + 1) * uwidth_max(U_CURRENT); /* of s (in bytes) */ int list_size; int found = 0; char b[1024], tmp[16]; int ch, attr; int i; if(msg == MSG_START) { canonicalize_filename(b, s, sizeof(b)); ustrzcpy(s, size, b); } if(msg == MSG_KEY) { if((!ugetc(s)) || (ugetat(s, -1) == DEVICE_SEPARATOR)) ustrzcat(s, size, uconvert_ascii("./", tmp)); canonicalize_filename(b, s, sizeof(b)); ustrzcpy(s, size - ucwidth(OTHER_PATH_SEPARATOR), b); ch = ugetat(s, -1); if((ch != '/') && (ch != OTHER_PATH_SEPARATOR)) { if(file_exists(s, FA_RDONLY | FA_HIDDEN | FA_DIREC, &attr)) { if(attr & FA_DIREC) put_backslash(s); else return D_CLOSE; } else return D_CLOSE; } object_message(file_selector+FS_FILES, MSG_START, 0); /* did we `cd ..' ? */ if(ustrlen(updir)) { /* now we have to find a directory name equal to updir */ for(i = 0; i<flist->size; i++) { if(!ustrcmp(updir, flist->name[i])) /* we got it ! */ { file_selector[FS_FILES].d1 = i; /* we have to know the number of visible lines in the filelist */ /* -1 to avoid an off-by-one problem */ list_size = (file_selector[FS_FILES].h-4) / text_height(font) - 1; if(i>list_size) file_selector[FS_FILES].d2 = i-list_size; else file_selector[FS_FILES].d2 = 0; found = 1; break; /* ok, our work is done... */ } } /* by some strange reason, we didn't find the old directory... */ if(!found) { file_selector[FS_FILES].d1 = 0; file_selector[FS_FILES].d2 = 0; } } /* and continue... */ object_message(file_selector+FS_FILES, MSG_DRAW, 0); object_message(d, MSG_START, 0); object_message(d, MSG_DRAW, 0); return D_O_K; } int allegro_lfn = ALLEGRO_LFN; //removes compiler warning if(msg == MSG_UCHAR) { if((c >= 'a') && (c <= 'z')) { if(!allegro_lfn) c = utoupper(c); } else if(c == '/') { c = OTHER_PATH_SEPARATOR; } else if(allegro_lfn) { if((c > 127) || (c < 32)) return D_O_K; } else { if((c != OTHER_PATH_SEPARATOR) && (c != '_') && (c != DEVICE_SEPARATOR) && (c != '.') && ((c < 'A') || (c > 'Z')) && ((c < '0') || (c > '9'))) return D_O_K; } } // return _gui_edit_proc(msg, d, c); return jwin_edit_proc(msg, d, c); }
/* 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++; } }