Update copyright headers
[neverball] / share / dir.c
1 /*
2  * Copyright (C) 2003-2010 Neverball authors
3  *
4  * NEVERBALL is  free software; you can redistribute  it and/or modify
5  * it under the  terms of the GNU General  Public License as published
6  * by the Free  Software Foundation; either version 2  of the License,
7  * or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT  ANY  WARRANTY;  without   even  the  implied  warranty  of
11  * MERCHANTABILITY or  FITNESS FOR A PARTICULAR PURPOSE.   See the GNU
12  * General Public License for more details.
13  */
14
15 #include <dirent.h>
16
17 #include <string.h>
18 #include <stdlib.h>
19 #include <assert.h>
20
21 #include "dir.h"
22 #include "common.h"
23
24 static char **get_dir_list(const char *path)
25 {
26     DIR *dir;
27     char **files = NULL;
28     int count = 0;
29
30     /*
31      * HACK: MinGW provides numerous POSIX extensions to MSVCRT,
32      * including dirent.h, so parasti ever so lazily has not bothered
33      * to port the code below to FindFirstFile et al.
34      */
35
36     if ((dir = opendir(path)))
37     {
38         struct dirent *ent;
39
40         files = malloc(sizeof (char *));
41
42         while ((ent = readdir(dir)))
43         {
44             if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
45                 continue;
46
47             files[count++] = strdup(ent->d_name);
48             files = realloc(files, (count + 1) * sizeof (char *));
49         }
50
51         files[count] = NULL;
52
53         closedir(dir);
54     }
55
56     return files;
57 }
58
59 static void free_dir_list(void *files)
60 {
61     if (files)
62     {
63         char **file;
64
65         /* Free file names. */
66         for (file = files; *file; free(*file++));
67
68         /* Free trailing NULL. */
69         free(*file);
70
71         /* Free pointer list. */
72         free(files);
73     }
74 }
75
76 static struct dir_item *add_item(Array items, const char *dir, const char *name)
77 {
78     struct dir_item *item = array_add(items);
79
80     item->path = *dir ? concat_string(dir, "/", name, NULL) : strdup(name);
81     item->data = NULL;
82
83     return item;
84 }
85
86 static void del_item(Array items)
87 {
88     struct dir_item *item = array_get(items, array_len(items) - 1);
89
90     free((void *) item->path);
91     assert(!item->data);
92
93     array_del(items);
94 }
95
96 Array dir_scan(const char *path,
97                int    (*filter)   (struct dir_item *),
98                char **(*get_list) (const char *),
99                void   (*free_list)(void *))
100 {
101     char **list;
102     Array items = NULL;
103
104     assert((get_list && free_list) || (!get_list && !free_list));
105
106     if (!get_list)
107         get_list = get_dir_list;
108
109     if (!free_list)
110         free_list = free_dir_list;
111
112     if ((list = get_list(path)))
113     {
114         char **file = list;
115
116         items = array_new(sizeof (struct dir_item));
117
118         while (*file)
119         {
120             struct dir_item *item;
121
122             item = add_item(items, path, *file);
123
124             if (filter && !filter(item))
125                 del_item(items);
126
127             file++;
128         }
129
130         free_list(list);
131     }
132
133     return items;
134 }
135
136 void dir_free(Array items)
137 {
138     while (array_len(items))
139         del_item(items);
140
141     array_free(items);
142 }