Complete.Org: Mailing Lists: Archives: freeciv-dev: July 2002:
[Freeciv-Dev] client string options: choosing from a list (PR#1856)
Home

[Freeciv-Dev] client string options: choosing from a list (PR#1856)

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: freeciv-dev@xxxxxxxxxxx
Cc: bugs@xxxxxxxxxxxxxxxxxxx
Subject: [Freeciv-Dev] client string options: choosing from a list (PR#1856)
From: jdorje@xxxxxxxxxxxxxxxxxxxxx
Date: Mon, 29 Jul 2002 19:27:30 -0700 (PDT)

The next step in allowing easier selection of tilesets from within the client is to provide the user with a list of tilesets to choose from.

This patch does that, and more. It provides a list of choices for some of the string options; the user selects from these choices in a drop-down list. Only xaw has been implemented so far.

Specifically, a new field is added to the client option list - this field contains a function that can be called to get a list of string options for the list (or NULL). Functions are provided to assemble lists of valid tilesets, soundsets, and sound plugins. For tilesets and soundsets, the function calls another (shared) function to search the data directories (with scandir; is this safe?) to assemble the list. For sound plugins the list is assembled easily using preprocessor macros.

Changes that may affect other code include:

- datafilename() has been changed so that it calls a separate function to get the list of data directories.

- The name of the soundset only should now be specified, without the trailing ".spec". This matches what is done for tilesets.

Changes to the interface include:

- A new function, datafilelist, in shared.[ch] returns a list of files matching a given suffix.

- New functions get_tileset_list, get_soundset_list, and get_soundplugin_list have been introduced. The names of these are consistent with each other rather than with the local code (I'm not sure what is best).

If anyone can provide changes for the other GUI's to support the listings, that would be great.

jason
? foo
? get_data_dirs.diff
? option_list.diff
Index: client/audio.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/audio.c,v
retrieving revision 1.11
diff -u -r1.11 audio.c
--- client/audio.c      2002/07/23 02:48:45     1.11
+++ client/audio.c      2002/07/30 02:20:02
@@ -17,12 +17,15 @@
 
 #include <string.h>
 #include <assert.h>
+#include <stdio.h>
 #include <stdlib.h>
 
+#include "audio.h"
 #include "support.h"
 #include "fcintl.h"
 #include "log.h"
 #include "capability.h"
+#include "mem.h"
 #include "shared.h"
 #include "registry.h"
 #include "audio_none.h"
@@ -54,6 +57,49 @@
 static int num_plugins_used = 0;
 static int selected_plugin = -1;
 
+/**********************************************************************
+  Returns a static, NULL-terminated list of all sound plugins
+  available on the system.
+***********************************************************************/
+char **get_soundplugin_list(void)
+{
+  static char* plugin_list[] = 
+    {"none",
+#ifdef ESD
+     "esd",
+#endif
+#ifdef SDL
+     "sdl",
+#endif
+#ifdef WINMM
+     "winmm",
+#endif
+#ifdef AMIGA
+     "amiga",
+#endif
+     NULL};
+
+  return plugin_list;
+}
+
+/**********************************************************************
+  Returns a static list of soundsets available on the system by
+  searching all data directories for files matching ".spec".  The
+  list is NULL-terminated.
+***********************************************************************/
+char **get_soundset_list(void)
+{
+  static char **audio_list = NULL;
+
+  if (!audio_list) {
+    /* Note: this means you must restart the client after installing a new
+       soundset. */
+    audio_list = datafilelist(".spec");
+  }
+
+  return audio_list;
+}
+
 /**************************************************************************
   Add a plugin.
 **************************************************************************/
@@ -128,6 +174,24 @@
 #endif
 }
 
+static char *soundspec_fullname(const char *soundset_name)
+{
+  char *soundset_default = "stdsounds"; /* Do not i18n! */
+  char *fname, *dname;
+  
+  fname = fc_malloc(strlen(soundset_name) + 16);
+  sprintf(fname, "%s.spec", soundset_name);
+
+  dname = datafilename(fname);
+  if (dname
+      || strcmp(soundset_name, soundset_default) == 0) {
+    free(fname);
+    return NULL;
+  }
+
+  return soundspec_fullname(soundset_default);
+}
+
 /**************************************************************************
   Initialize audio system and autoselect a plugin
 **************************************************************************/
@@ -161,7 +225,7 @@
     exit(EXIT_FAILURE);
   }
   freelog(LOG_VERBOSE, "Initializing sound using %s...", spec_name);
-  filename = datafilename(spec_name);
+  filename = soundspec_fullname(spec_name);
   if (!filename) {
     freelog(LOG_ERROR, _("Cannot find audio spec-file \"%s\"."), spec_name);
     freelog(LOG_ERROR, _("To get sound you need to download a sound set!"));
Index: client/audio.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/audio.h,v
retrieving revision 1.2
diff -u -r1.2 audio.h
--- client/audio.h      2002/04/23 22:51:22     1.2
+++ client/audio.h      2002/07/30 02:20:02
@@ -28,6 +28,9 @@
   bool (*play) (const char *const tag, const char *const path, bool repeat);
 };
 
+char **get_soundplugin_list(void);
+char **get_soundset_list(void);
+
 void audio_init(void);
 void audio_real_init(const char *const spec_name,
                     const char *const prefered_plugin_name);
Index: client/options.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/options.c,v
retrieving revision 1.62
diff -u -r1.62 options.c
--- client/options.c    2002/07/23 02:48:45     1.62
+++ client/options.c    2002/07/30 02:20:05
@@ -20,6 +20,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include "audio.h"
 #include "clinet.h"
 #include "events.h"
 #include "fcintl.h"
@@ -28,6 +29,7 @@
 #include "registry.h"
 #include "shared.h"
 #include "support.h"
+#include "tilespec.h"
 #include "version.h"
 #include "mem.h"
 
@@ -44,7 +46,7 @@
 int  default_server_port = DEFAULT_SOCK_PORT;
 char default_metaserver[512] = METALIST_ADDR;
 char default_tile_set_name[512] = "\0";
-char default_sound_set_name[512] = "stdsounds.spec";
+char default_sound_set_name[512] = "stdsounds";
 char default_sound_plugin_name[512] = "\0";
 
 /** Local Options: **/
@@ -66,22 +68,27 @@
 bool meta_accelerators = TRUE;
 
 #define GEN_INT_OPTION(name, desc) { #name, desc, COT_INT, \
-                                     &name, NULL, NULL, 0, NULL }
+                                     &name, NULL, NULL, 0, NULL, NULL }
 #define GEN_BOOL_OPTION(name, desc) { #name, desc, COT_BOOL, \
-                                      NULL, &name, NULL, 0, NULL }
-#define GEN_STR_OPTION(name, desc) { #name, desc, COT_STR, \
-                                     NULL, NULL, name, sizeof(name), NULL }
+                                      NULL, &name, NULL, 0, NULL, NULL }
+#define GEN_STR_OPTION(name, desc, dflt) { #name, desc, COT_STR, \
+                                     NULL, NULL, name, sizeof(name), \
+                                     dflt, NULL }
 #define GEN_OPTION_TERMINATOR { NULL, NULL, COT_BOOL, \
                                 NULL, NULL, NULL, 0, NULL }
 
 client_option options[] = {
-  GEN_STR_OPTION(default_player_name,       N_("Default player's username")), 
-  GEN_STR_OPTION(default_server_host,       N_("Default server")),
+  GEN_STR_OPTION(default_player_name,       N_("Default player's username"),
+                NULL), 
+  GEN_STR_OPTION(default_server_host,       N_("Default server"), NULL),
   GEN_INT_OPTION(default_server_port,       N_("Default server's port")),
-  GEN_STR_OPTION(default_metaserver,        N_("Default metaserver")),
-  GEN_STR_OPTION(default_tile_set_name,     N_("Default tileset")),
-  GEN_STR_OPTION(default_sound_set_name,    N_("Default name of sound set")),
-  GEN_STR_OPTION(default_sound_plugin_name, N_("Default sound plugin")),
+  GEN_STR_OPTION(default_metaserver,        N_("Default metaserver"), NULL),
+  GEN_STR_OPTION(default_tile_set_name,     N_("Default tileset"),
+                get_tileset_list),
+  GEN_STR_OPTION(default_sound_set_name,    N_("Default name of sound set"),
+                get_soundset_list),
+  GEN_STR_OPTION(default_sound_plugin_name, N_("Default sound plugin"),
+                get_soundplugin_list),
 
   GEN_BOOL_OPTION(solid_color_behind_units, N_("Solid unit background color")),
   GEN_BOOL_OPTION(sound_bell_at_new_turn,   N_("Sound bell at new turn")),
Index: client/options.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/options.h,v
retrieving revision 1.18
diff -u -r1.18 options.h
--- client/options.h    2002/07/23 02:48:45     1.18
+++ client/options.h    2002/07/30 02:20:06
@@ -59,6 +59,10 @@
   char *p_string_value;
   size_t string_length;
 
+  /* A function to return a static NULL-terminated list of possible
+     string values, or NULL for none. */
+  char **(*p_string_vals)(void);
+
   /* volatile */
   void *p_gui_data;
 } client_option;
Index: client/tilespec.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/tilespec.c,v
retrieving revision 1.81
diff -u -r1.81 tilespec.c
--- client/tilespec.c   2002/07/27 14:14:23     1.81
+++ client/tilespec.c   2002/07/30 02:20:09
@@ -115,6 +115,24 @@
 static bool no_backdrop = FALSE;
 
 /**********************************************************************
+  Returns a static list of tilesets available on the system by
+  searching all data directories for files matching ".tilespec".  The
+  list is NULL-terminated.
+***********************************************************************/
+char **get_tileset_list(void)
+{
+  static char **tileset_list = NULL;
+
+  if (!tileset_list) {
+    /* Note: this means you must restart the client after installing a new
+       tileset. */
+    tileset_list = datafilelist(".tilespec");
+  }
+
+  return tileset_list;
+}
+
+/**********************************************************************
   Gets full filename for tilespec file, based on input name.
   Returned data is allocated, and freed by user as required.
   Input name may be null, in which case uses default.
Index: client/tilespec.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/tilespec.h,v
retrieving revision 1.28
diff -u -r1.28 tilespec.h
--- client/tilespec.h   2002/04/06 11:42:57     1.28
+++ client/tilespec.h   2002/07/30 02:20:10
@@ -26,6 +26,8 @@
 struct unit;
 struct player;
 
+char **get_tileset_list(void);
+
 void tilespec_read_toplevel(const char *tileset_name);
 void tilespec_load_tiles(void);
 
Index: client/gui-xaw/optiondlg.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-xaw/optiondlg.c,v
retrieving revision 1.19
diff -u -r1.19 optiondlg.c
--- client/gui-xaw/optiondlg.c  2002/07/23 02:47:38     1.19
+++ client/gui-xaw/optiondlg.c  2002/07/30 02:20:12
@@ -22,9 +22,12 @@
 #include <X11/StringDefs.h>
 #include <X11/Xaw/Form.h>
 #include <X11/Xaw/Label.h>
+#include <X11/Xaw/List.h>
 #include <X11/Xaw/Command.h>
+#include <X11/Xaw/MenuButton.h>
 #include <X11/Xaw/SimpleMenu.h>
 #include <X11/Xaw/Scrollbar.h>
+#include <X11/Xaw/SmeBSB.h>
 #include <X11/Xaw/AsciiText.h>  
 #include <X11/Xaw/Toggle.h>     
 
@@ -77,7 +80,8 @@
       XtVaSetValues((Widget) o->p_gui_data, XtNstring, valstr, NULL);
       break;
     case COT_STR:
-      XtVaSetValues((Widget) o->p_gui_data, XtNstring,
+      XtVaSetValues((Widget) o->p_gui_data,
+                   o->p_string_vals ? "label" : XtNstring,
                    o->p_string_value, NULL);
       break;
     }
@@ -90,7 +94,19 @@
 
 
 
+/****************************************************************
+  Callback to change the entry for a string option that has
+  a fixed list of possible entries.
+*****************************************************************/
+static void stropt_change_callback(Widget w,
+                                  XtPointer client_data,
+                                  XtPointer call_data)
+{
+  char* val = (char*)client_data;
 
+  XtVaSetValues(XtParent(XtParent(w)), "label", val, NULL);
+}
+
 /****************************************************************
 ...
 *****************************************************************/
@@ -151,8 +167,51 @@
                                NULL);
       XtAddCallback(prev_widget, XtNcallback, toggle_callback, NULL);
       break;
-    case COT_INT:
     case COT_STR:
+      if (o->p_string_vals) {
+       int i;
+       char **vals = (*o->p_string_vals)();
+       Widget popupmenu;
+       char *current_value = o->p_string_value;
+       
+       if (current_value[0] == '\0') {
+         current_value = _("(none)");
+       }
+
+       prev_widget = XtVaCreateManagedWidget(o->name,
+                                             menuButtonWidgetClass,
+                                             option_form,
+                                             XtNfromHoriz, longest_label,
+                                             XtNfromVert, o->p_gui_data,
+                                             NULL);
+
+       popupmenu = XtVaCreatePopupShell("menu",
+                                        simpleMenuWidgetClass,
+                                        prev_widget,
+                                        NULL);
+
+       for (i = 0; vals[i]; i++) {
+         Widget entry = XtVaCreateManagedWidget(vals[i], smeBSBObjectClass,
+                                                popupmenu, NULL);
+         XtAddCallback(entry, XtNcallback, stropt_change_callback,
+                       (XtPointer)(vals[i]));
+       }
+
+#if 0
+       /* We don't do this, since an option that has only one possible
+          value may still be left uninitialized (empty), and that would
+          be really confusing. */
+       if (i <= 1) {
+         XtSetSensitive(prev_widget, FALSE);
+       }
+#endif
+       
+       XtVaSetValues(prev_widget, "label", current_value, NULL);
+
+       break;
+      }
+      /* else fall through */
+    case COT_INT:
       prev_widget =
        XtVaCreateManagedWidget("input", asciiTextWidgetClass, option_form,
                                XtNfromHoriz, longest_label,
@@ -219,7 +278,9 @@
       sscanf(dp, "%d", o->p_int_value);
       break;
     case COT_STR:
-      XtVaGetValues(o->p_gui_data, XtNstring, &dp, NULL);
+      XtVaGetValues(o->p_gui_data,
+                   o->p_string_vals ? "label" : XtNstring,
+                   &dp, NULL);
       mystrlcpy(o->p_string_value,dp,o->string_length);
       break;
     }
Index: common/shared.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/shared.c,v
retrieving revision 1.86
diff -u -r1.86 shared.c
--- common/shared.c     2002/06/12 07:24:47     1.86
+++ common/shared.c     2002/07/30 02:20:14
@@ -15,6 +15,7 @@
 #endif
 
 #include <assert.h>
+#include <dirent.h>
 #include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -711,97 +712,214 @@
 }
 
 /***************************************************************************
-  Returns a filename to access the specified file from a data directory;
-  The file may be in any of the directories in the data path, which is
-  specified internally or may be set as the environment variable
-  $FREECIV_PATH.  (A separated list of directories, where the separator
-  itself can specified internally.)
-  '~' at the start of a component (provided followed by '/' or '\0')
-  is expanded as $HOME.
+  Returns a list of data directory paths, in the order in which they should
+  be searched.  These paths are specified internally or may be set as the
+  environment variable $FREECIV_PATH (a separated list of directories,
+  where the separator itself is specified internally, platform-dependent).
+  '~' at the start of a component (provided followed by '/' or '\0') is
+  expanded as $HOME.
 
-  If the specified 'filename' is NULL, the returned string contains
-  the effective data path.  (But this should probably only be used
-  for debug output.)
-  
-  Returns NULL if the specified filename cannot be found in any of the
-  data directories.  (A file is considered "found" if it can be read-opened.)
-  The returned pointer points to static memory, so this function can
-  only supply one filename at a time.
+  The returned value is a static NULL-terminated list of strings.
+
+  num_dirs, if not NULL, will be set to the number of entries in the list.
 ***************************************************************************/
-char *datafilename(const char *filename)
+static char **get_data_dirs(int *num_dirs)
 {
-  static char *path = NULL;
-  static int num_dirs = 0;
+  char *path, *path2, *tok;
+  static int num = 0;
   static char **dirs = NULL;
-  static struct astring realfile = ASTRING_INIT;
-  int i;
-
-  if (!path) {
-    char *tok;
-    char *path2;
 
-    path = getenv("FREECIV_PATH");
-    if (!path) {
-      path = DEFAULT_DATA_PATH;
-    } else if (*path == '\0') {
-      freelog(LOG_ERROR, _("FREECIV_PATH is set but empty; "
-                          "using default path instead."));
-      path = DEFAULT_DATA_PATH;
+  /* The first time this function is called it will search and allocate
+   * the directory listing.  Subsequently we will already know the list
+   * and can just return it. */
+  if (dirs) {
+    if (num_dirs) {
+      *num_dirs = num;
     }
-    assert(path != NULL);
+    return dirs;
+  }
 
-    path2 = mystrdup(path);    /* something we can strtok */
+  path = getenv("FREECIV_PATH");
+  if (!path) {
+    path = DEFAULT_DATA_PATH;
+  } else if (*path == '\0') {
+    freelog(LOG_ERROR, _("FREECIV_PATH is set but empty; "
+                        "using default path instead."));
+    path = DEFAULT_DATA_PATH;
+  }
+  assert(path != NULL);
+  
+  path2 = mystrdup(path);      /* something we can strtok */
     
-    tok = strtok(path2, PATH_SEPARATOR);
-    do {
-      int i;                   /* strlen(tok), or -1 as flag */
-      
-      tok = skip_leading_spaces(tok);
-      remove_trailing_spaces(tok);
-      if (strcmp(tok, "/")!=0) {
-       remove_trailing_char(tok, '/');
-      }
+  tok = strtok(path2, PATH_SEPARATOR);
+  do {
+    int i;                     /* strlen(tok), or -1 as flag */
+
+    tok = skip_leading_spaces(tok);
+    remove_trailing_spaces(tok);
+    if (strcmp(tok, "/")!=0) {
+      remove_trailing_char(tok, '/');
+    }
       
-      i = strlen(tok);
-      if (tok[0] == '~') {
-       if (i>1 && tok[1] != '/') {
-         freelog(LOG_ERROR, "For \"%s\" in data path cannot expand '~'"
-                             " except as '~/'; ignoring", tok);
-         i = 0;   /* skip this one */
+    i = strlen(tok);
+    if (tok[0] == '~') {
+      if (i>1 && tok[1] != '/') {
+       freelog(LOG_ERROR, "For \"%s\" in data path cannot expand '~'"
+               " except as '~/'; ignoring", tok);
+       i = 0;   /* skip this one */
+      } else {
+       char *home = user_home_dir();
+       if (!home) {
+         freelog(LOG_VERBOSE,
+                 "No HOME, skipping data path component %s", tok);
+         i = 0;
        } else {
-         char *home = user_home_dir();
-         if (!home) {
-           freelog(LOG_VERBOSE,
-                   "No HOME, skipping data path component %s", tok);
-           i = 0;
-         } else {
-           int len = strlen(home) + i;    /* +1 -1 */
-           char *tmp = fc_malloc(len);
-           my_snprintf(tmp, len, "%s%s", home, tok+1);
-           tok = tmp;
-           i = -1;             /* flag to free tok below */
-         }
+         int len = strlen(home) + i;      /* +1 -1 */
+         char *tmp = fc_malloc(len);
+         my_snprintf(tmp, len, "%s%s", home, tok + 1);
+         tok = tmp;
+         i = -1;               /* flag to free tok below */
        }
       }
-      if (i != 0) {
-       /* We could check whether the directory exists and
-        * is readable etc?  Don't currently. */
-       num_dirs++;
-       dirs = fc_realloc(dirs, num_dirs*sizeof(char*));
-       dirs[num_dirs-1] = mystrdup(tok);
-       freelog(LOG_VERBOSE, "Data path component (%d): %s", num_dirs-1, tok);
-       if (i == -1) {
-         free(tok);
-         tok = NULL;
-       }
+    }
+    if (i != 0) {
+      /* We could check whether the directory exists and
+       * is readable etc?  Don't currently. */
+      num++;
+      dirs = fc_realloc(dirs, num * sizeof(char*));
+      dirs[num - 1] = mystrdup(tok);
+      freelog(LOG_VERBOSE, "Data path component (%d): %s", num - 1, tok);
+      if (i == -1) {
+       free(tok);
+       tok = NULL;
       }
+    }
+
+    tok = strtok(NULL, PATH_SEPARATOR);
+  } while(tok);
+
+  /* NULL-terminate the list. */
+  dirs = fc_realloc(dirs, (num + 1) * sizeof(char*));
+  dirs[num] = NULL;
+
+  free(path2);
+  
+  if (num_dirs) {
+    *num_dirs = num;
+  }
+  return dirs;
+}
+
+/* The use of this variable is a hack, unfortunately necessary in C.  See
+   parse_datafile_direntry() and datafilelist(). */
+static const char *datafile_suffix = NULL;
+
+/***************************************************************************
+  A function passed to scandir() to check for file names matching a given
+  suffix.  The suffix is stored in the datafile_suffix variable, since C
+  doesn't support anything more elegant.
+***************************************************************************/
+static int parse_datafile_direntry(const struct dirent *dent)
+{
+  int dent_len = strlen(dent->d_name);
+  int pattern_len = strlen(datafile_suffix);
+  return dent_len > pattern_len
+         && !strcmp(datafile_suffix,
+                   dent->d_name + dent_len - pattern_len);
+}
+
+/***************************************************************************
+  Returns a NULL-terminated list of filenames in the data directories
+  matching the given suffix.
 
-      tok = strtok(NULL, PATH_SEPARATOR);
-    } while(tok);
+  The list is allocated when the function is called; it should either be
+  stored permanently or de-allocated (by free'ing each element and the
+  whole list).
+
+  The list is unsorted and may include duplicates (for now).  The suffixes
+  are removed from the filenames before the list is returned.
+***************************************************************************/
+char **datafilelist(const char* suffix)
+{
+  char **dirs = get_data_dirs(NULL);
+  char **file_list = NULL;
+  int num_matches = 0, i, j;
+  int dir_num;
+  struct dirent **dirent_list;
+
+  /* First assemble a full list of names. */
+  for (dir_num = 0; dirs[dir_num]; dir_num++) {
+    /* Scan the data directory for files ending in the suffix. */
+    int num_entries, entry_num;
+
+    datafile_suffix = suffix;
+    num_entries = scandir(dirs[dir_num], &dirent_list,
+                         parse_datafile_direntry, NULL);
+    datafile_suffix = NULL;
+
+    if (num_entries <= 0) {
+      continue;
+    }
 
-    free(path2);
+    /* Add the entries found to the list.  Note that we don't check
+       for duplicates. */
+    file_list = fc_realloc(file_list, (num_matches + num_entries) * 
+                          sizeof(*file_list));
+    for (entry_num = 0; entry_num < num_entries; entry_num++) {
+      char *name = mystrdup(dirent_list[entry_num]->d_name);
+      name[strlen(name) - strlen(suffix)] = '\0';
+      file_list[num_matches++] = name;
+    }
   }
 
+  /* Sort the list. */
+  qsort(file_list, num_matches, sizeof(*file_list), compare_strings_ptrs);
+
+  /* Remove duplicates (easy since it's sorted). */
+  i = j = 0;
+  do {
+    char *this = file_list[j];
+
+    for (j++; j < num_matches && !strcmp(this, file_list[j]); j++) {
+      free(file_list[j]);
+    }
+
+    file_list[i] = this;
+
+    i++;
+  } while (j < num_matches);
+  num_matches = i;
+
+  /* NULL-terminate the whole thing. */
+  file_list = fc_realloc(file_list,
+                        (num_matches + 1) * sizeof(*file_list));
+  file_list[num_matches] = NULL;
+
+  return file_list;
+}
+
+/***************************************************************************
+  Returns a filename to access the specified file from a data directory by
+  searching all data directories (as specified by get_data_dirs) for the
+  file.
+
+  If the specified 'filename' is NULL, the returned string contains
+  the effective data path.  (But this should probably only be used
+  for debug output.)
+  
+  Returns NULL if the specified filename cannot be found in any of the
+  data directories.  (A file is considered "found" if it can be read-opened.)
+  The returned pointer points to static memory, so this function can
+  only supply one filename at a time.
+***************************************************************************/
+char *datafilename(const char *filename)
+{
+  char **dirs;
+  int num_dirs, i;
+  static struct astring realfile = ASTRING_INIT;
+
+  dirs = get_data_dirs(&num_dirs);
+
   if (!filename) {
     int len = 1;               /* in case num_dirs==0 */
     int seplen = strlen(PATH_SEPARATOR);
@@ -812,7 +930,7 @@
     realfile.str[0] = '\0';
     for(i=0; i<num_dirs; i++) {
       (void) mystrlcat(realfile.str, dirs[i], len);
-      if(i != num_dirs-1) {
+      if (i<num_dirs) {
        (void) mystrlcat(realfile.str, PATH_SEPARATOR, len);
       }
     }
Index: common/shared.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/shared.h,v
retrieving revision 1.95
diff -u -r1.95 shared.h
--- common/shared.h     2002/05/25 17:44:08     1.95
+++ common/shared.h     2002/07/30 02:20:14
@@ -109,6 +109,7 @@
 
 char *user_home_dir(void);
 char *user_username(void);
+char **datafilelist(const char *suffix);
 char *datafilename(const char *filename);
 char *datafilename_required(const char *filename);
 

[Prev in Thread] Current Thread [Next in Thread]