Fix yaz_use_attribute_create (uninit memory)
[yaz-moved-to-github.git] / src / file_glob.c
index 8b10664..a2e9031 100644 (file)
@@ -1,9 +1,9 @@
 /* This file is part of the YAZ toolkit.
- * Copyright (C) 1995-2010 Index Data
+ * Copyright (C) Index Data
  * See the file LICENSE for details.
  */
 
-/** \file 
+/** \file
     \brief File globbing (ala POSIX glob, but simpler)
 */
 #if HAVE_CONFIG_H
 #include <sys/stat.h>
 #include <stdio.h>
 #include <string.h>
+#include <stdlib.h>
 #include <assert.h>
 #include <yaz/wrbuf.h>
 #include <yaz/tpath.h>
 #include <yaz/log.h>
-#include <dirent.h>
+#include <yaz/dirent.h>
 #include <yaz/nmem.h>
 #include <yaz/file_glob.h>
 #include <yaz/match_glob.h>
@@ -30,11 +31,23 @@ struct res_entry {
 
 struct glob_res {
     NMEM nmem;
+    unsigned flags;
     size_t number_of_entries;
     struct res_entry **last_entry;
     struct res_entry *entries;
 };
 
+static void add_entry(yaz_glob_res_t res, const char *str)
+{
+    struct res_entry *ent =
+        nmem_malloc(res->nmem, sizeof(*ent));
+    ent->file = nmem_strdup(res->nmem, str);
+    ent->next = 0;
+    *res->last_entry = ent;
+    res->last_entry = &ent->next;
+    res->number_of_entries++;
+}
+
 static void glob_r(yaz_glob_res_t res, const char *pattern, size_t off,
                    char *prefix)
 {
@@ -47,7 +60,7 @@ static void glob_r(yaz_glob_res_t res, const char *pattern, size_t off,
             is_pattern = 1;
         i++;
     }
-    
+
     if (!is_pattern && pattern[i]) /* no pattern and directory part */
     {
         i++; /* skip dir sep */
@@ -56,6 +69,12 @@ static void glob_r(yaz_glob_res_t res, const char *pattern, size_t off,
         glob_r(res, pattern, i, prefix);
         prefix[prefix_len] = '\0';
     }
+    else if ((res->flags & YAZ_FILE_GLOB_FAIL_NOTEXIST) &&
+             !is_pattern && !pattern[i])
+    {
+        strcpy(prefix + prefix_len, pattern + off);
+        add_entry(res, prefix);
+    }
     else
     {
         DIR * dir = opendir(*prefix ? prefix : "." );
@@ -81,13 +100,7 @@ static void glob_r(yaz_glob_res_t res, const char *pattern, size_t off,
                     }
                     else
                     {
-                        struct res_entry *ent =
-                            nmem_malloc(res->nmem, sizeof(*ent));
-                        ent->file = nmem_strdup(res->nmem, prefix);
-                        ent->next = 0;
-                        *res->last_entry = ent;
-                        res->last_entry = &ent->next;
-                        res->number_of_entries++;
+                        add_entry(res, prefix);
                     }
                     prefix[prefix_len] = '\0';
                 }
@@ -97,18 +110,53 @@ static void glob_r(yaz_glob_res_t res, const char *pattern, size_t off,
     }
 }
 
+static int cmp_entry(const void *a, const void *b)
+{
+    struct res_entry *ent_a = *(struct res_entry **) a;
+    struct res_entry *ent_b = *(struct res_entry **) b;
+    return strcmp(ent_a->file, ent_b->file);
+}
+
+static void sort_them(yaz_glob_res_t res)
+{
+    size_t i;
+    struct res_entry **ent_p;
+    struct res_entry **ent = nmem_malloc(res->nmem, sizeof(*ent) * res->number_of_entries);
+    struct res_entry *ent_i = res->entries;
+    for (i = 0; i < res->number_of_entries; i++)
+    {
+        ent[i] = ent_i;
+        ent_i = ent_i->next;
+    }
+    qsort(ent, res->number_of_entries, sizeof(*ent), cmp_entry);
+    ent_p = &res->entries;
+    for (i = 0; i < res->number_of_entries; i++)
+    {
+        *ent_p = ent[i];
+        ent_p = &ent[i]->next;
+    }
+    *ent_p = 0;
+}
+
 int yaz_file_glob(const char *pattern, yaz_glob_res_t *res)
 {
+    return yaz_file_glob2(pattern, res, 0);
+}
+
+int yaz_file_glob2(const char *pattern, yaz_glob_res_t *res, unsigned flags)
+{
     char prefix[FILENAME_MAX+1];
     NMEM nmem = nmem_create();
 
     *prefix = '\0';
     *res = nmem_malloc(nmem, sizeof(**res));
+    (*res)->flags = flags;
     (*res)->number_of_entries = 0;
     (*res)->nmem = nmem;
     (*res)->entries = 0;
     (*res)->last_entry = &(*res)->entries;
     glob_r(*res, pattern, 0, prefix);
+    sort_them(*res);
     return 0;
 }