Re: [AD] File selector improvement |
[ Thread Index |
Date Index
| More lists.liballeg.org/allegro-developers Archives
]
> The patch also fixes the library build with GCC 3.1 or later because it
> replaces the only occurence of deprecated API functions in the library, a
> call to for_each_file(), by its newer equivalent, for_each_file_ex() here.
Here's the patch.
--
Eric Botcazou
Index: src/fsel.c
===================================================================
RCS file: /cvsroot/alleg/allegro/src/fsel.c,v
retrieving revision 1.32
diff -u -r1.32 fsel.c
--- src/fsel.c 8 Feb 2003 21:31:38 -0000 1.32
+++ src/fsel.c 14 May 2003 18:11:00 -0000
@@ -26,10 +26,14 @@
* Annie Testes modified it so that buffer overflows cannot occur
* anymore.
*
+ * Eric Botcazou optimized the handling of the extension string.
+ *
* See readme.txt for copyright information.
*/
+#include <string.h>
+
#include "allegro.h"
#include "allegro/internal/aintern.h"
@@ -63,7 +67,24 @@
static FLIST *flist = NULL;
-static AL_CONST char *fext = NULL;
+
+/* file extensions */
+static char *fext = NULL; /* tokenized extension string (dynamically allocated) */
+static char **fext_p = NULL; /* list of pointers to the tokens (dynamically allocated) */
+static int fext_size = 0; /* size of the list */
+
+
+/* file attributes (rhsda order) */
+#define ATTRB_MAX 5 /* number of attributes */
+#define ATTRB_DIREC 3 /* index of FA_DIREC */
+
+typedef enum { ATTRB_ABSENT, ATTRB_UNSET, ATTRB_SET } attrb_state_t;
+
+#define DEFAULT_ATTRB_STATE { ATTRB_ABSENT, ATTRB_UNSET, ATTRB_UNSET, ATTRB_ABSENT, ATTRB_ABSENT }
+
+static int attrb_flag[ATTRB_MAX] = { FA_RDONLY, FA_HIDDEN, FA_SYSTEM, FA_DIREC, FA_ARCH };
+static attrb_state_t attrb_state[ATTRB_MAX] = DEFAULT_ATTRB_STATE;
+
static char updir[1024];
@@ -375,119 +396,44 @@
/* 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)
+static int fs_flist_putter(AL_CONST char *str, int attrib, void *check_attrib)
{
- char ext_tokens[32];
- char *s, *ext, *tok, *name, *last;
- 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);
+ char *s, *ext, *name;
+ int c, c2;
s = get_filename(str);
fix_filename_case(s);
- if (fext) {
- ustrzcpy(tmp, sizeof(tmp), fext);
- ustrtok_r(tmp, ext_tokens, &last);
- c = (ustrtok_r(NULL, ext_tokens, &last) ? 1 : 0);
- if (!c) {
- if (!ustrchr(fext, '/'))
- c = 1;
- }
-
- if (c && (!(attrib & FA_DIREC))) {
- ustrzcpy(tmp, sizeof(tmp), fext);
+ if (!(attrib & FA_DIREC)) {
+ /* Check if file extension matches. */
+ if (fext_p) {
ext = get_extension(s);
- tok = ustrtok_r(tmp, ext_tokens, &last);
-
- while (tok) {
- if (ustricmp(ext, tok) == 0)
- break;
-
- tok = ustrtok_r(NULL, ext_tokens, &last);
+ for (c=0; c<fext_size; c++) {
+ if (ustricmp(ext, fext_p[c]) == 0)
+ goto Next;
}
-
- if (!tok)
- return;
+ return 0;
}
- c = usetc(ext_tokens, ' ');
- c += usetc(ext_tokens+c, ',');
- c += usetc(ext_tokens+c, ';');
- c += usetc(ext_tokens+c, '/');
- usetc(ext_tokens+c, 0);
-
- ustrzcpy(tmp, sizeof(tmp), fext);
- tok = ustrchr(tmp, '/');
-
- if (tok)
- tok = ustrtok_r(tok, ext_tokens, &last);
-
- 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++;
- }
+ Next:
+ /* Check if file attributes match. */
+ if (check_attrib) {
+ for (c=0; c<ATTRB_MAX; c++) {
+ /* ???? We check all attributes except FA_DIREC. */
+ if (c == ATTRB_DIREC)
+ continue;
+ if ((attrb_state[c] == ATTRB_SET) && (!(attrib & attrb_flag[c])))
+ return 0;
+ if ((attrb_state[c] == ATTRB_UNSET) && (attrib & attrb_flag[c]))
+ return 0;
+ }
}
}
- /* 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;
+ return -1;
for (c=0; c<flist->size; c++) {
if (ugetat(flist->name[c], -1) == OTHER_PATH_SEPARATOR) {
@@ -514,6 +460,8 @@
flist->size++;
}
+
+ return 0;
}
@@ -534,6 +482,23 @@
+/* build_attrb_flag:
+ * Returns the cumulative flag for all attributes in state STATE.
+ */
+static int build_attrb_flag(attrb_state_t state)
+{
+ int i, flag = 0;
+
+ for (i = 0; i < ATTRB_MAX; i++) {
+ if (attrb_state[i] == state)
+ flag |= attrb_flag[i];
+ }
+
+ return flag;
+}
+
+
+
/* fs_flist_proc:
* Dialog procedure for the file selector list.
*/
@@ -566,12 +531,16 @@
replace_filename(flist->dir, s, uconvert_ascii("*.*", tmp), sizeof(flist->dir));
- *allegro_errno = 0;
-
- for_each_file(flist->dir, FA_RDONLY | FA_DIREC | FA_ARCH | FA_HIDDEN | FA_SYSTEM, fs_flist_putter, 0);
-
- if (*allegro_errno)
- alert(NULL, get_config_text("Disk error"), NULL, get_config_text("OK"), NULL, 13, 0);
+ /* The semantics of the attributes passed to file_select_ex() is
+ * different from that of for_each_file_ex() because directories
+ * are always all included regardless of the other specified
+ * attributes, unless they are all excluded. So we can't filter
+ * with for_each_file_ex() unless we are in the latter case.
+ */
+ if (attrb_state[ATTRB_DIREC] == ATTRB_UNSET)
+ for_each_file_ex(flist->dir, build_attrb_flag(ATTRB_SET), build_attrb_flag(ATTRB_UNSET) | FA_LABEL, fs_flist_putter, (void *)FALSE /* don't check */);
+ else
+ for_each_file_ex(flist->dir, 0 /* accept all dirs */, FA_LABEL, fs_flist_putter, (void *)TRUE /* check */);
usetc(get_filename(flist->dir), 0);
d->d1 = d->d2 = 0;
@@ -626,6 +595,89 @@
+/* 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 *tok, *last, *p, *attrb_p;
+ int c, c2, i;
+
+ fext = ustrdup(ext);
+ if (!fext)
+ return;
+
+ /* 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 (!ugetc(p))
+ return;
+
+ i = 0;
+ fext_size = 0;
+ fext_p = NULL;
+ attrb_p = NULL;
+
+ 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)));
+
+ /* 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)))) {
+ p = attrb_char;
+ for (i = 0; (c2 = ugetx(&p)); i++) {
+ if (c == c2) {
+ if (i < ATTRB_MAX)
+ attrb_state[i] = state;
+ else
+ state = (i == ATTRB_MAX) ? ATTRB_SET : ATTRB_UNSET;
+ break;
+ }
+ }
+ }
+ }
+}
+
+
+
/* stretch_dialog:
* Stretch the dialog horizontally and vertically to the specified
* size and the font in use.
@@ -748,6 +800,7 @@
*/
int file_select_ex(AL_CONST char *message, char *path, AL_CONST char *ext, int size, int width, int height)
{
+ static attrb_state_t default_attrb_state[ATTRB_MAX] = DEFAULT_ATTRB_STATE;
int ret;
char *p;
char tmp[32];
@@ -778,7 +831,13 @@
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");
- fext = ext;
+
+ /* 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)) {
@@ -808,6 +867,16 @@
set_dialog_color(file_selector, gui_fg_color, gui_bg_color);
ret = popup_dialog(file_selector, FS_EDIT);
+ if (fext) {
+ free(fext);
+ fext = NULL;
+ }
+
+ if (fext_p) {
+ free(fext_p);
+ fext_p = NULL;
+ }
+
if ((ret == FS_CANCEL) || (!ugetc(get_filename(path))))
return FALSE;
@@ -820,6 +889,6 @@
}
}
- return TRUE;
+ return TRUE;
}