Patrick Georgi ([email protected]) just uploaded a new patch set to 
gerrit, which you can find at http://review.coreboot.org/119

-gerrit

commit 7f65f079c80bf52ff9e2f12b3c118ad3dcb5647b
Author: Patrick Georgi <[email protected]>
Date:   Tue Jul 19 16:38:23 2011 +0200

    Add POSIXy readdir/scandir support
    
    This abuses the print_a_completion mechanism to build the right data
    structures to support opendir/readdir/closedir and scandir on top of
    them.
    
    It's BSD-licensed so it can eventually be moved over to libpayload.
    
    Change-Id: Iadc1daed3cab4cf2ead778c23ad756d36cbbb99a
    Signed-off-by: Patrick Georgi <[email protected]>
---
 fs/vfs.c                |  118 ++++++++++++++++++++++++++++++++++++++++++++++-
 include/dirent.h        |   28 +++++++++++
 include/grub/shared.h   |    2 +-
 main/grub/completions.c |   27 -----------
 4 files changed, 146 insertions(+), 29 deletions(-)

diff --git a/fs/vfs.c b/fs/vfs.c
index 49b38d8..18dbcbc 100644
--- a/fs/vfs.c
+++ b/fs/vfs.c
@@ -24,6 +24,7 @@
 #include <config.h>
 #include <fs.h>
 #include "filesys.h"
+#include <dirent.h>
 
 #define DEBUG_THIS CONFIG_DEBUG_VFS
 #include <debug.h>
@@ -241,7 +242,7 @@ void file_close(void)
        devclose();
 }
 
-int dir(char *dirname)
+int dir(const char *dirname)
 {
        char *dev = 0;
        const char *path;
@@ -300,6 +301,8 @@ int dir(char *dirname)
 
        retval = fsys->dir_func((char *) path);
 
+       print_possibilities = 0;
+
 out:
        if (dev)
                free(dev);
@@ -307,4 +310,117 @@ out:
        return retval;
 }
 
+/* The following functions are BSD-L, Copyright 2011 secunet AG
+ * licensing is chosen to simplify migration to libpayload at some point */
+
+struct dirent **opendir_s;
+int opendir_ssize, opendir_selem;
+
+void print_a_completion(char *name)
+{
+       opendir_s[opendir_selem] = malloc(sizeof(struct dirent));
+       opendir_s[opendir_selem]->d_name = strdup(name);
+       opendir_selem++;
+       if (opendir_selem == opendir_ssize) {
+               opendir_ssize *= 2;
+               opendir_s = realloc(opendir_s, sizeof(struct 
dirent*)*opendir_ssize);
+       }
+       opendir_s[opendir_selem] = 0;
+}
+
+DIR *opendir(const char *path)
+{
+       DIR *p = malloc(sizeof(DIR));
+
+       if (opendir_s) free(opendir_s);
+       opendir_ssize = 32;
+       opendir_selem = 0;
+       opendir_s = malloc(sizeof(struct dirent*)*opendir_ssize);
+       dir(path);
+       p->items = opendir_s;
+       p->cur = opendir_s;
+       return p;
+}
+
+struct dirent *readdir(DIR *dirp)
+{
+       if (NULL == *dirp->cur) return NULL;
+
+       return *(dirp->cur++);
+}
+
+int closedir(DIR *dirp)
+{
+       if (!dirp) return -1;
+
+       struct dirent **cur = dirp->items;
+       while (*cur) {
+               free(*cur);
+               cur++;
+       }
+       free(dirp->items);
+       free(dirp);
+
+       return 0;
+}
+
+static int (*metafilter_flt)(const struct dirent *);
+static int (*metafilter_cmp)(const struct dirent **, const struct dirent **);
+
+static int metafilter(const struct dirent **a, const struct dirent **b)
+{
+       /* make sure that filtered out entries end up at the end, for simple 
elimination */
+       if ((metafilter_flt(*a) == 0) && (metafilter_flt(*b) == 0))
+               return 0;
+       if (metafilter_flt(*a) == 0)
+               return 1;
+       if (metafilter_flt(*b) == 0)
+               return -1;
+       return metafilter_cmp(a, b);
+}
+
+int scandir(const char *path, struct dirent ***namelist,
+       int (*filter)(const struct dirent *),
+       int (*compar)(const struct dirent **, const struct dirent **))
+{
+       DIR *dirp = opendir(path);
+
+       struct dirent **e = dirp->items;
+       int nelem = 0;
+       while (*e) {
+               nelem++;
+               e++;
+       }
+
+       if (filter) {
+               metafilter_flt = filter;
+               metafilter_cmp = compar;
+               compar = metafilter;
+       }
+
+       *namelist = malloc(sizeof(struct dirent*)*nelem);
+       memcpy(*namelist, dirp->items, sizeof(struct dirent*)*nelem);
+       qsort(*namelist, nelem, sizeof(struct dirent*), (int(*)(const void*, 
const void*))compar);
+
+       // if things were filtered, truncate them away
+       if (filter) {
+               int nelem2;
+               e = *namelist;
+               nelem2 = 0;
+               while ((nelem > nelem2) && filter(*e)) {
+                       nelem2++;
+                       e++;
+               }
+               realloc(namelist, sizeof(struct dirent**)*nelem2);
+       }
+
+       return nelem;
+}
+
+int alphasort(const struct dirent **a, const struct dirent **b)
+{
+       const struct dirent *a1 = *(const struct dirent **)(a);
+       const struct dirent *b1 = *(const struct dirent **)(b);
+       return strcmp(a1->d_name, b1->d_name);
+}
 
diff --git a/include/dirent.h b/include/dirent.h
new file mode 100644
index 0000000..19b3696
--- /dev/null
+++ b/include/dirent.h
@@ -0,0 +1,28 @@
+/* Copyright 2011 secunet AG
+ * written by Patrick Georgi <[email protected]>
+ *
+ * Licensed as BSD-L to ease migration to libpayload */
+
+#ifndef __DIRENT_H
+#define __DIRENT_H
+struct dirent {
+       char *d_name;
+};
+
+typedef struct {
+       struct dirent **items;
+       struct dirent **cur;
+} DIR;
+
+DIR *opendir(const char *path);
+struct dirent *readdir(DIR *dirp);
+int closedir(DIR *dirp); // 0 on success, -1 on error, with errno set
+
+int scandir(const char *path, struct dirent ***namelist,
+               int (*filter)(const struct dirent *),
+               int (*compar)(const struct dirent **, const struct dirent **));
+
+int alphasort(const struct dirent **a, const struct dirent **b);
+
+#endif
+
diff --git a/include/grub/shared.h b/include/grub/shared.h
index 8d876de..127b74f 100644
--- a/include/grub/shared.h
+++ b/include/grub/shared.h
@@ -295,7 +295,7 @@ void grub_putstr (const char *str);
 
 /* List the contents of the directory that was opened with GRUB_OPEN,
    printing all completions. */
-int dir (char *dirname);
+int dir (const char *dirname);
 
 /* Display device and filename completions. */
 void print_a_completion (char *filename);
diff --git a/main/grub/completions.c b/main/grub/completions.c
index 6588301..161026b 100644
--- a/main/grub/completions.c
+++ b/main/grub/completions.c
@@ -64,33 +64,6 @@ set_device (char *device)
        return 0;
 }
 
-/* If DO_COMPLETION is true, just print NAME. Otherwise save the unique
-   part into UNIQUE_STRING.  */
-void print_a_completion(char *name)
-{
-       /* If NAME is "." or "..", do not count it.  */
-       if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
-               return;
-
-       if (do_completion) {
-               char *buf = unique_string;
-
-               if (!unique)
-                       while ((*buf++ = *name++));
-               else {
-                       while (*buf && (*buf == *name)) {
-                               buf++;
-                               name++;
-                       }
-                       /* mismatch, strip it.  */
-                       *buf = '\0';
-               }
-       } else
-               grub_printf(" %s", name);
-
-       unique++;
-}
-
 /*
  *  This lists the possible completions of a device string, filename, or
  *  any sane combination of the two.

-- 
coreboot mailing list: [email protected]
http://www.coreboot.org/mailman/listinfo/coreboot

Reply via email to