Re: adding directory contents to ogg123 playing in sorted order?

Ray Kohler <[email protected]>
Newsgroups gmane.comp.multimedia.ogg.vorbis.devel
Message-ID <[email protected]>
On Sun, Feb 28, 2010 at 11:11 PM, Ray Kohler <[email protected]> wrote:
> On Sun, Feb 28, 2010 at 11:01 PM,  <[email protected]> wrote:
>>>> Yes, we'd take such a patch.  _Especially_ if you do the extra build
>>>> system legwork to establish portability. :-)  Now is good timing too,
>>>> I intend to release a new ogg123 this month.
>>>
>>> Ok, I will work on this soon, hopefully tomorrow. I have to learn
>>> autotools practically from scratch, so this could give me a little
>>> trouble.
>>
>> Then don't worry about that part.  If you could look to see where
>> support does and doesn't exist, that still helps.
>
> The new functions I'd be using are scandir(3) and alphasort(3). Both
> are BSD-derived. I know they are also present on Solaris 8+ and HP-UX
> 11i v2, as well as any modern glibc, as that's what I have direct
> access to. It's likely that they're available on any SysV-based system
> that ships a BSD-compatibility layer as well. That's quite possibly
> everything.
>
> I'll make a first pass that basically replaces
> playlist_append_directory() entirely, as I'm guessing that's probably
> the easiest way to handle two different cases at compile-time.

This turned out to be very easy - I can't remember the last time I
wrote some code and had it work the first time. Since the relevant
functions are in libc, the autoconf changes were very easy as well, so
I did those too. Given that this is a short function, and changes are
throughout, I judged it more readable to have two complete copies of
the function, rather than one function with lots of #if defined blocks
- the preprocessor directives would practically outnumber the code if
I had done it that way. Patch follows, and is against current SVN
trunk. (I'm also adding it as an attachment, as I don't trust mail not
to mangle it.)

Index: configure.ac
===================================================================
--- configure.ac	(revision 16870)
+++ configure.ac	(working copy)
@@ -317,7 +317,7 @@

 AC_FUNC_ALLOCA
 AM_ICONV
-AC_CHECK_FUNCS(atexit on_exit fcntl select stat chmod)
+AC_CHECK_FUNCS(atexit on_exit fcntl select stat chmod alphasort scandir)
 AM_LANGINFO_CODESET

 dnl --------------------------------------------------
Index: ogg123/playlist.c
===================================================================
--- ogg123/playlist.c	(revision 16870)
+++ ogg123/playlist.c	(working copy)
@@ -120,8 +120,63 @@
 }

 /* Recursively adds files from the directory and subdirectories */
+#if defined(HAVE_ALPHASORT) && defined(HAVE_SCANDIR)
 int playlist_append_directory(playlist_t *list, char *dirname)
 {
+  int dir_len = strlen(dirname);
+  int num_entries = 0, i = 0;
+  struct dirent **entries;
+  struct stat stat_buf;
+  char nextfile[NAME_MAX + 1];
+
+  num_entries = scandir(dirname, &entries, 0, alphasort);
+
+  if (num_entries < 0) {
+    return 0;
+  }
+
+  for (i=0; i<num_entries; i++) {
+    int sub_len = strlen(entries[i]->d_name);
+
+    /* Make sure full pathname is within limits and we don't parse the
+       relative directory entries. */
+    if (dir_len + sub_len + 1 < NAME_MAX
+        && strcmp(entries[i]->d_name, ".") != 0
+        && strcmp(entries[i]->d_name, "..") != 0  ) {
+
+      /* Build the new full pathname */
+      strcpy(nextfile, dirname);
+      strcat(nextfile, "/");
+      strcat(nextfile, entries[i]->d_name);
+
+      if (stat(nextfile, &stat_buf) == 0) {
+
+        /* Decide what type of entry this is */
+        if (S_ISDIR(stat_buf.st_mode)) {
+
+        /* Recursively follow directories */
+          if ( playlist_append_directory(list, nextfile) == 0 ) {
+            fprintf(stderr,
+                  _("Warning: Could not read directory %s.\n"),
+                    nextfile);
+          }
+        } else {
+        /* Assume everything else is a file of some sort */
+          playlist_append_file(list, nextfile);
+        }
+      }
+    }
+
+    free(entries[i]);
+  }
+
+  free(entries);
+
+  return 1;
+}
+#else
+int playlist_append_directory(playlist_t *list, char *dirname)
+{
   DIR *dir;
   int dir_len = strlen(dirname);
   struct dirent *entry;
@@ -174,6 +229,7 @@

   return 1;
 }
+#endif


 /* Opens a file containing filenames, one per line, and adds them to the

_______________________________________________
Vorbis-dev mailing list
[email protected]
http://lists.xiph.org/mailman/listinfo/vorbis-dev
scandir.patch (application/octet-stream, 2.4 KB)
Index: configure.ac
===================================================================
--- configure.ac	(revision 16870)
+++ configure.ac	(working copy)
@@ -317,7 +317,7 @@
 
 AC_FUNC_ALLOCA
 AM_ICONV
-AC_CHECK_FUNCS(atexit on_exit fcntl select stat chmod)
+AC_CHECK_FUNCS(atexit on_exit fcntl select stat chmod alphasort scandir)
 AM_LANGINFO_CODESET
 
 dnl --------------------------------------------------
Index: ogg123/playlist.c
===================================================================
--- ogg123/playlist.c	(revision 16870)
+++ ogg123/playlist.c	(working copy)
@@ -120,8 +120,63 @@
 }
 
 /* Recursively adds files from the directory and subdirectories */
+#if defined(HAVE_ALPHASORT) && defined(HAVE_SCANDIR)
 int playlist_append_directory(playlist_t *list, char *dirname)
 {
+  int dir_len = strlen(dirname);
+  int num_entries = 0, i = 0;
+  struct dirent **entries;
+  struct stat stat_buf;
+  char nextfile[NAME_MAX + 1];
+
+  num_entries = scandir(dirname, &entries, 0, alphasort);
+
+  if (num_entries < 0) {
+    return 0;
+  }
+
+  for (i=0; i<num_entries; i++) {
+    int sub_len = strlen(entries[i]->d_name);
+
+    /* Make sure full pathname is within limits and we don't parse the
+       relative directory entries. */
+    if (dir_len + sub_len + 1 < NAME_MAX 
+        && strcmp(entries[i]->d_name, ".") != 0  
+        && strcmp(entries[i]->d_name, "..") != 0  ) {
+
+      /* Build the new full pathname */
+      strcpy(nextfile, dirname);
+      strcat(nextfile, "/");
+      strcat(nextfile, entries[i]->d_name);
+
+      if (stat(nextfile, &stat_buf) == 0) {
+        
+        /* Decide what type of entry this is */
+        if (S_ISDIR(stat_buf.st_mode)) {
+          
+        /* Recursively follow directories */
+          if ( playlist_append_directory(list, nextfile) == 0 ) {
+            fprintf(stderr,
+                  _("Warning: Could not read directory %s.\n"), 
+                    nextfile);
+          }
+        } else {
+        /* Assume everything else is a file of some sort */
+          playlist_append_file(list, nextfile);
+        }
+      }
+    }
+
+    free(entries[i]);
+  }
+
+  free(entries);
+
+  return 1;
+}
+#else
+int playlist_append_directory(playlist_t *list, char *dirname)
+{
   DIR *dir;
   int dir_len = strlen(dirname);
   struct dirent *entry;
@@ -174,6 +229,7 @@
 
   return 1;
 }
+#endif
 
 
 /* Opens a file containing filenames, one per line, and adds them to the
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.