DO NOT REPLY TO THIS MESSAGE.  INSTEAD, POST ANY RESPONSES TO THE LINK BELOW.

[STR New]

Link: http://www.fltk.org/str.php?L2931
Version: 1.3-current


Added a patch file to replace the full source files in the uploaded tar
file. The patch is against current svn (r 9827). Although bigger than the
compressed tar file, I prefer the patch format.

The patch contains a few small changes WRT the tar file:

 - copyright year adjusted (e.g. "1998-2010, 2013" -> "1998-2013"
 - fixed one typo

Still testing, but patch looks good AFAICT. I'll post my test results with
Cygwin and other available systems later, but this can take some days due
to restricted test time. :-(


Link: http://www.fltk.org/str.php?L2931
Version: 1.3-current
Index: FL/filename.H
===================================================================
--- FL/filename.H       (revision 9827)
+++ FL/filename.H       (working copy)
@@ -3,7 +3,7 @@
  *
  * Filename header file for the Fast Light Tool Kit (FLTK).
  *
- * Copyright 1998-2010 by Bill Spitzak and others.
+ * Copyright 1998-2013 by Bill Spitzak and others.
  *
  * This library is free software. Distribution and use rights are outlined in
  * the file "COPYING" which should have been included with this file.  If this
@@ -107,13 +107,15 @@
 #  endif /* __cplusplus */
 
 #  if !defined(FL_DOXYGEN)
-FL_EXPORT int fl_alphasort(struct dirent **, struct dirent **);
-FL_EXPORT int fl_casealphasort(struct dirent **, struct dirent **);
-FL_EXPORT int fl_casenumericsort(struct dirent **, struct dirent **);
-FL_EXPORT int fl_numericsort(struct dirent **, struct dirent **);
+/* Parameters changed to 'const struct dirent**' */
+FL_EXPORT int fl_alphasort(const struct dirent **, const struct dirent **);
+FL_EXPORT int fl_casealphasort(const struct dirent **, const struct dirent **);
+FL_EXPORT int fl_casenumericsort(const struct dirent **, const struct dirent 
**);
+FL_EXPORT int fl_numericsort(const struct dirent **, const struct dirent **);
 #  endif
 
-  typedef int (Fl_File_Sort_F)(struct dirent **, struct dirent **); /**< File 
sorting function. \see fl_filename_list() */
+  /* Changed to match POSIX.1-2008 compliant sort function like 'alphasort()' 
*/
+  typedef int (Fl_File_Sort_F)(const struct dirent **, const struct dirent 
**); /**< File sorting function. \see fl_filename_list() */
 
 #  if defined(__cplusplus)
 }
Index: src/filename_list.cxx
===================================================================
--- src/filename_list.cxx       (revision 9827)
+++ src/filename_list.cxx       (working copy)
@@ -3,7 +3,7 @@
 //
 // Filename list routines for the Fast Light Tool Kit (FLTK).
 //
-// Copyright 1998-2010 by Bill Spitzak and others.
+// Copyright 1998-2013 by Bill Spitzak and others.
 //
 // This library is free software. Distribution and use rights are outlined in
 // the file "COPYING" which should have been included with this file.  If this
@@ -28,17 +28,18 @@
 
 extern "C" {
 #ifndef HAVE_SCANDIR
-  int fl_scandir (const char *dir, dirent ***namelist,
-                 int (*select)(dirent *),
-                 int (*compar)(dirent **, dirent **));
+  /* POSIX.1-2008 compliant prototype for own implementation of 'scandir()' */
+  int fl_scandir(const char *dir, struct dirent ***namelist,
+                 int (*select)(const struct dirent *),
+                 int (*compar)(const struct dirent **, const struct dirent 
**));
 #endif
 }
 
-int fl_alphasort(struct dirent **a, struct dirent **b) {
+int fl_alphasort(const struct dirent **a, const struct dirent **b) {
   return strcmp((*a)->d_name, (*b)->d_name);
 }
 
-int fl_casealphasort(struct dirent **a, struct dirent **b) {
+int fl_casealphasort(const struct dirent **a, const struct dirent **b) {
   return strcasecmp((*a)->d_name, (*b)->d_name);
 }
 
@@ -72,8 +73,7 @@
         according to their ASCII ordering - uppercase before lowercase. 
    \return the number of entries if no error, a negative value otherwise.
 */
-int fl_filename_list(const char *d, dirent ***list,
-                     Fl_File_Sort_F *sort) {
+int fl_filename_list(const char *d, dirent ***list, Fl_File_Sort_F *sort) {
 #if defined(WIN32) && !defined(__CYGWIN__) && !defined(HAVE_SCANDIR)
   // For Windows we have a special scandir implementation that uses
   // the Win32 "wide" functions for lookup, avoiding the code page mess
@@ -94,32 +94,29 @@
   fl_utf8to_mb(d, dirlen, dirloc, dirlen + 1);
 #endif
 
+  // We should not write 'dirent' here if we mean 'struct dirent' because the
+  // implicit 'struct' is only allowed with C++ and 'scandir()' is a C function
 #ifndef HAVE_SCANDIR
-  // This version is when we define our own scandir
+  // The system don't provide a usable implementation
+  // This is e.g. the case on SunOS 5.9 and older versions
   int n = fl_scandir(dirloc, list, 0, sort);
-#elif defined(HAVE_SCANDIR_POSIX) && !defined(__APPLE__)
-  // POSIX (2008) defines the comparison function like this:
-  int n = scandir(dirloc, list, 0, (int(*)(const dirent **, const dirent 
**))sort);
-#elif defined(__osf__)
-  // OSF, DU 4.0x
-  int n = scandir(dirloc, list, 0, (int(*)(dirent **, dirent **))sort);
+#elif defined(HAVE_SCANDIR_POSIX) || \
+      defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 
MAC_OS_X_VERSION_10_8
+  // POSIX.1-2008
+  // http://pubs.opengroup.org/onlinepubs/9699919799/functions/scandir.html
+  int n = scandir(dirloc, list, 0, sort);
+#elif defined(__osf__) || defined(__sgi)
+  // OSF, DU 4.0x, Tru64, IRIX
+  int n = scandir(dirloc, list, 0, (int(*)(struct dirent **, struct dirent 
**)) sort);
 #elif defined(_AIX)
-  // AIX is almost standard...
-  int n = scandir(dirloc, list, 0, (int(*)(void*, void*))sort);
-#elif defined(__sgi)
-  int n = scandir(dirloc, list, 0, sort);
-#elif defined(__APPLE__)
-# if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
-  int n = scandir(dirloc, list, 0, (int(*)(const struct dirent**,const struct 
dirent**))sort);
-# else
-  int n = scandir(dirloc, list, 0, (int(*)(const void*,const void*))sort);
-# endif
+  // AIX
+  int n = scandir(dirloc, list, 0, (int(*)(void *, void *)) sort);
 #else
   // The vast majority of UNIX systems want the sort function to have this
   // prototype, most likely so that it can be passed to qsort without any
-  // changes:
-  int n = scandir(dirloc, list, 0, (int(*)(const void*,const void*))sort);
-#endif
+  // changes
+  int n = scandir(dirloc, list, 0, (int(*)(const void *, const void *)) sort);
+#endif  /* HAVE_SCANDIR */
 
 #ifndef __APPLE__
   free(dirloc);
Index: src/numericsort.c
===================================================================
--- src/numericsort.c   (revision 9827)
+++ src/numericsort.c   (working copy)
@@ -3,7 +3,7 @@
  *
  * Numeric sorting routine for the Fast Light Tool Kit (FLTK).
  *
- * Copyright 1998-2010 by Bill Spitzak and others.
+ * Copyright 1998-2013 by Bill Spitzak and others.
  *
  * This library is free software. Distribution and use rights are outlined in
  * the file "COPYING" which should have been included with this file.  If this
@@ -48,7 +48,7 @@
  *                   a case-insensitive comparison...
  */
 
-static int numericsort(struct dirent **A, struct dirent **B, int cs) {
+static int numericsort(const struct dirent **A, const struct dirent **B, int 
cs) {
   const char* a = (*A)->d_name;
   const char* b = (*B)->d_name;
   int ret = 0;
@@ -63,14 +63,14 @@
       while (isdigit(*a & 255)) {magdiff++; a++;}
       while (isdigit(*b & 255)) {magdiff--; b++;}
       if (magdiff) {ret = magdiff; break;} /* compare # of significant digits*/
-      if (diff) {ret = diff; break;}   /* compare first non-zero digit */
+      if (diff) {ret = diff; break;}       /* compare first non-zero digit */
     } else {
       if (cs) {
-       /* compare case-sensitive */
-       if ((ret = *a-*b)) break;
+        /* compare case-sensitive */
+        if ((ret = *a-*b)) break;
       } else {
-       /* compare case-insensitve */
-       if ((ret = tolower(*a & 255)-tolower(*b & 255))) break;
+        /* compare case-insensitve */
+        if ((ret = tolower(*a & 255)-tolower(*b & 255))) break;
       }
 
       if (!*a) break;
@@ -85,7 +85,7 @@
  * 'fl_casenumericsort()' - Compare directory entries with case-sensitivity.
  */
 
-int fl_casenumericsort(struct dirent **A, struct dirent **B) {
+int fl_casenumericsort(const struct dirent **A, const struct dirent **B) {
   return numericsort(A, B, 0);
 }
 
@@ -93,7 +93,7 @@
  * 'fl_numericsort()' - Compare directory entries with case-sensitivity.
  */
 
-int fl_numericsort(struct dirent **A, struct dirent **B) {
+int fl_numericsort(const struct dirent **A, const struct dirent **B) {
   return numericsort(A, B, 1);
 }
 
Index: src/scandir.c
===================================================================
--- src/scandir.c       (revision 9827)
+++ src/scandir.c       (working copy)
@@ -1,10 +1,10 @@
 /*
  * "$Id$"
  *
- * This is a placekeeper stub that puuls in scandir implementations for host
+ * This is a placekeeper stub that pulls in scandir implementations for host
  * systems that do not provide a compatible one natively
  *
- * Copyright 1998-2010 by Bill Spitzak and others.
+ * Copyright 1998-2013 by Bill Spitzak and others.
  *
  * This library is free software. Distribution and use rights are outlined in
  * the file "COPYING" which should have been included with this file.  If this
@@ -17,44 +17,13 @@
  *     http://www.fltk.org/str.php
  */
 
+#include "../config.h"
 
-#if defined(WIN32) && !defined(__CYGWIN__)
+/* Added '!defined(HAVE_SCANDIR)' to be in sync with 'filename_list.cxx' */
+#if defined(WIN32) && !defined(__CYGWIN__) && !defined(HAVE_SCANDIR)
 #  include "scandir_win32.c"
-#else
-
-#  include "flstring.h"
-
-/* NOTE: Most (all?) modern non-WIN32 hosts DO have a usable scandir */
-#  if !HAVE_SCANDIR 
-#    include <stdlib.h>
-#    include <sys/types.h>
-#    include <errno.h>
-
-#    if HAVE_DIRENT_H
-#      include <dirent.h>
-#      define NAMLEN(dirent) strlen((dirent)->d_name)
-#    else /* HAVE_DIRENT_H */
-#      define dirent direct
-#      define NAMLEN(dirent) (dirent)->d_namlen
-#      if HAVE_SYS_NDIR_H
-#        include <sys/ndir.h>
-#      endif /* HAVE_SYS_NDIR_H */
-#      if HAVE_SYS_DIR_H
-#        include <sys/dir.h>
-#      endif /* HAVE_SYS_DIR_H */
-#      if HAVE_NDIR_H
-#        include <ndir.h>
-#      endif /* HAVE_NDIR_H */
-#    endif
-
-/* This warning added to help identify any non-WIN32 hosts that actually try 
to use 
- * our "private" implementation of the scandir function, which was suspect... 
*/
-#    if defined(__GNUC__)
-#      warning Attempting to use the deprecated scandir() replacement function
-#    endif /*__GNUC__*/
-#    error No compatible scandir implementation found (STR 2687 applies!)
-
-#  endif /* !HAVE_SCANDIR */
+#elif !defined(HAVE_SCANDIR)
+#  include "scandir_posix.c"
 #endif
 
 /*
Index: src/scandir_posix.c
===================================================================
--- src/scandir_posix.c (revision 0)
+++ src/scandir_posix.c (working copy)
@@ -0,0 +1,197 @@
+/*
+ * This implementation of 'scandir()' is intended to be POSIX.1-2008 compliant.
+ * A POSIX.1-1990 compliant system is required as minimum base.
+ *
+ * Copyright (c) 2013 by Michael Baeuerle
+ *
+ * This library is free software. Distribution and use rights are outlined in
+ * the file "COPYING" which should have been included with this file. If this
+ * file is missing or damaged, see the license at:
+ *
+ *     http://www.fltk.org/COPYING.php
+ *
+ * Please report all bugs and problems on the following page:
+ *
+ *     http://www.fltk.org/str.php
+ *
+ * It is required that 'SIZE_MAX' is at least 'INT_MAX'.
+ * Don't use a C++ compiler to build this module.
+ *
+ * The build system must define 'HAVE_PTHREAD' and link against a potentially
+ * required library to switch this implementation into thread-safe mode.
+ * The POSIX.1c-1995 extension is required if 'HAVE_PTHREAD' is defined.
+ *
+ * Note:
+ * In theory, a system that provide threads should also provide 'readdir_r()',
+ * a thread-safe version of 'readdir()'. In reality this is not always the 
case.
+ * In addition there may be a race condition that can lead to a buffer 
overflow:
+ * http://womble.decadent.org.uk/readdir_r-advisory.html
+ */
+
+#ifndef HAVE_PTHREAD
+   /* Switch system headers into POSIX.1-1990 mode */
+#  define _POSIX_SOURCE
+#else  /* HAVE_PTHREAD */
+   /* Switch system headers into POSIX.1c-1995 mode */
+#  define _POSIX_C_SOURCE  199506L
+#endif  /* HAVE_PTHREAD */
+
+#include <sys/types.h>        /* XPG2 require this for '*dir()' functions */
+#include <dirent.h>
+#include <errno.h>
+#include <stdlib.h>           /* For 'malloc()', 'realloc()' and 'qsort()' */
+#include <stddef.h>           /* For 'offsetof()', 'NULL' and 'size_t' */
+#include <limits.h>           /* For 'INT_MAX' */
+#include <string.h>           /* For 'memcpy()' */
+#if defined(HAVE_PTHREAD) && defined(HAVE_PTHREAD_H)
+#  include <pthread.h>
+#endif  /* HAVE_PTHREAD */
+
+
+/* ========================================================================== 
*/
+/* At startup allocate memory for this number of result array elements */
+#define ENTRIES_MIN  (size_t) 32
+
+
+/* ========================================================================== 
*/
+#ifdef HAVE_PTHREAD
+static pthread_mutex_t scandir_mutex = PTHREAD_MUTEX_INITIALIZER;
+#endif  /* HAVE_PTHREAD */
+
+
+/* ========================================================================== 
*/
+/*
+ * This function reads the next entry from the directory referenced by 'dirp',
+ * allocate a buffer for the entry and copy it into this buffer.
+ * A pointer to this buffer is written to 'entryp' and the size of the buffer 
is
+ * written to 'len'.
+ * Success and a NULL pointer is returned for 'entryp' if there are no more
+ * entries in the directory.
+ * On sucess zero is returned and the caller is responsible for 'free()'ing the
+ * buffer after use.
+ * On error the return value is nonzero, 'entryp' and 'len' are invalid.
+ *
+ * Should be declared as 'static inline' if the compiler support that.
+ */
+static int
+readentry(DIR *dirp, struct dirent **entryp, size_t *len)
+{
+  int result = -1;
+  struct dirent *e;
+
+#ifdef HAVE_PTHREAD
+  if (!pthread_mutex_lock(&scandir_mutex))
+  {
+    /* Ensure that there is no code path that bypass the '_unlock()' call! */
+#endif  /* HAVE_PTHREAD */
+    errno = 0;
+    e = readdir(dirp);
+    if (NULL == e)
+    {
+      if (!errno)
+      {
+        /* No more entries in directory */
+        *entryp = NULL;
+        *len = 0;
+        result = 0;
+      }
+    }
+    else
+    {
+      /* Entry found, allocate local buffer */
+      *len = offsetof(struct dirent, d_name) + strlen(e->d_name) + (size_t) 1;
+      *entryp = (struct dirent *) malloc(*len);
+      if (NULL != *entryp)
+      {
+        memcpy((void *) *entryp, (void *) e, *len);
+        /* Force NUL termination at end of buffer */
+        ((char *) *entryp)[*len - (size_t) 1] = 0;
+        result = 0;
+      }
+    }
+#ifdef HAVE_PTHREAD
+    /*
+     * In a multithreading environment the systems dirent buffer may be shared
+     * between all threads. Therefore the mutex must stay locked until we have
+     * copied the data to our thread local buffer.
+     */
+    pthread_mutex_unlock(&scandir_mutex);
+  }
+#endif  /* HAVE_PTHREAD */
+
+  return result;
+}
+
+
+/* ========================================================================== 
*/
+int
+fl_scandir(const char *dir, struct dirent ***namelist,
+           int (*sel)(const struct dirent *),
+           int (*compar)(const struct dirent **, const struct dirent **))
+{
+  int result = -1;
+  DIR *dirp;
+  size_t len, num = 0, max = ENTRIES_MIN;
+  struct dirent *entryp, **entries, **p;
+
+  entries = (struct dirent **) malloc(sizeof(*entries) * max);
+  if (NULL != entries)
+  {
+    /* Open directory 'dir' (and verify that it really is a directory) */
+    dirp = opendir(dir);
+    if (NULL != dirp)
+    {
+      /* Read next directory entry */
+      while (!readentry(dirp, &entryp, &len))
+      {
+        if (NULL == entryp)
+        {
+          /* EOD => Return number of directory entries */
+          result = (int) num;
+          break;
+        }
+        /* Apply select function if there is one provided */
+        if (NULL != sel)  { if (!sel(entryp))  continue; }
+        entries[num++] = entryp;
+        if (num >= max)
+        {
+          /* Allocate exponentially increasing sized memory chunks */
+          if (INT_MAX / 2 >= (int) max)  { max *= (size_t) 2; }
+          else
+          {
+            errno = ENOMEM;
+            break;
+          }
+          p = (struct dirent **) realloc((void *) entries,
+                                         sizeof(*entries) * max);
+          if (NULL != p)  { entries = p; }
+          else  break;
+        }
+      }
+      closedir(dirp);
+      /*
+       * A standard compliant 'closedir()' is allowed to fail with 'EINTR', but
+       * the state of the directory structure is undefined in this case.
+       * Therefore we ignore the return value because we can't call 
'closedir()'
+       * again and must hope that the system has released all ressources.
+       */
+    }
+    /* Sort entries in array if there is a compare function provided */
+    if (NULL != compar)
+    {
+      qsort((void *) entries, num, sizeof(*entries),
+            (int (*)(const void *, const void *)) compar);
+    }
+    *namelist = entries;
+  }
+
+  /* Check for error */
+  if (-1 == result)
+  {
+    /* Free all memory we have allocated */
+    while (num--)  { free(entries[num]); }
+    free(entries);
+  }
+
+  return result;
+}
Index: src/scandir_win32.c
===================================================================
--- src/scandir_win32.c (revision 9827)
+++ src/scandir_win32.c (working copy)
@@ -3,7 +3,7 @@
  *
  * WIN32 scandir function for the Fast Light Tool Kit (FLTK).
  *
- * Copyright 1998-2010 by Bill Spitzak and others.
+ * Copyright 1998-2013 by Bill Spitzak and others.
  *
  * This library is free software. Distribution and use rights are outlined in
  * the file "COPYING" which should have been included with this file.  If this
@@ -24,9 +24,10 @@
 #include <windows.h>
 #include <stdlib.h>
 
-int fl_scandir(const char *dirname, struct dirent ***namelist,
-              int (*select)(struct dirent *),
-              int (*compar)(struct dirent **, struct dirent **)) {
+int
+fl_scandir(const char *dirname, struct dirent ***namelist,
+           int (*select)(const struct dirent *),
+           int (*compar)(const struct dirent **, const struct dirent **)) {
   int len;
   char *findIn, *d, is_dir = 0;
   WIN32_FIND_DATAW findw;
_______________________________________________
fltk-bugs mailing list
fltk-bugs@easysw.com
http://lists.easysw.com/mailman/listinfo/fltk-bugs

Reply via email to