1 /* libSoX minimal glob for MS-Windows: (c) 2009 SoX contributors
2 *
3 * This library is free software; you can redistribute it and/or modify it
4 * under the terms of the GNU Lesser General Public License as published by
5 * the Free Software Foundation; either version 2.1 of the License, or (at
6 * your option) any later version.
7 *
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
11 * General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this library; if not, write to the Free Software Foundation,
15 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17
18 #include "glob.h"
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <errno.h>
22 #define WIN32_LEAN_AND_MEAN 1
23 #include <windows.h>
24
25 typedef struct file_entry
26 {
27 char name[MAX_PATH];
28 struct file_entry *next;
29 } file_entry;
30
31 static int
insert(const char * path,const char * name,file_entry ** phead)32 insert(
33 const char* path,
34 const char* name,
35 file_entry** phead)
36 {
37 int len;
38 file_entry* cur = malloc(sizeof(file_entry));
39 if (!cur)
40 {
41 return ENOMEM;
42 }
43
44 len = _snprintf(cur->name, MAX_PATH, "%s%s", path, name);
45 cur->name[MAX_PATH - 1] = 0;
46 cur->next = *phead;
47 *phead = cur;
48
49 return len < 0 || len >= MAX_PATH ? ENAMETOOLONG : 0;
50 }
51
52 static int
entry_comparer(const void * pv1,const void * pv2)53 entry_comparer(
54 const void* pv1,
55 const void* pv2)
56 {
57 const file_entry* const * pe1 = pv1;
58 const file_entry* const * pe2 = pv2;
59 return _stricmp((*pe1)->name, (*pe2)->name);
60 }
61
62 int
glob(const char * pattern,int flags,void * unused,glob_t * pglob)63 glob(
64 const char *pattern,
65 int flags,
66 void *unused,
67 glob_t *pglob)
68 {
69 char path[MAX_PATH];
70 file_entry *head = NULL;
71 int err = 0;
72 size_t len;
73 unsigned entries = 0;
74 WIN32_FIND_DATAA finddata;
75 HANDLE hfindfile;
76
77 if (!pattern || flags != (flags & GLOB_FLAGS) || unused || !pglob)
78 {
79 errno = EINVAL;
80 return EINVAL;
81 }
82
83 path[MAX_PATH - 1] = 0;
84 strncpy(path, pattern, MAX_PATH);
85 if (path[MAX_PATH - 1] != 0)
86 {
87 errno = ENAMETOOLONG;
88 return ENAMETOOLONG;
89 }
90
91 len = strlen(path);
92 while (len > 0 && path[len - 1] != '/' && path[len - 1] != '\\')
93 len--;
94 path[len] = 0;
95
96 hfindfile = FindFirstFileA(pattern, &finddata);
97 if (hfindfile == INVALID_HANDLE_VALUE)
98 {
99 if (flags & GLOB_NOCHECK)
100 {
101 err = insert("", pattern, &head);
102 entries++;
103 }
104 }
105 else
106 {
107 do
108 {
109 err = insert(path, finddata.cFileName, &head);
110 entries++;
111 } while (!err && FindNextFileA(hfindfile, &finddata));
112
113 FindClose(hfindfile);
114 }
115
116 if (err == 0)
117 {
118 pglob->gl_pathv = malloc((entries + 1) * sizeof(char*));
119 if (pglob->gl_pathv)
120 {
121 pglob->gl_pathc = entries;
122 pglob->gl_pathv[entries] = NULL;
123 for (; head; head = head->next, entries--)
124 pglob->gl_pathv[entries - 1] = (char*)head;
125 qsort(pglob->gl_pathv, pglob->gl_pathc, sizeof(char*), entry_comparer);
126 }
127 else
128 {
129 pglob->gl_pathc = 0;
130 err = ENOMEM;
131 }
132 }
133 else if (pglob)
134 {
135 pglob->gl_pathc = 0;
136 pglob->gl_pathv = NULL;
137 }
138
139 if (err)
140 {
141 file_entry *cur;
142 while (head)
143 {
144 cur = head;
145 head = head->next;
146 free(cur);
147 }
148
149 errno = err;
150 }
151
152 return err;
153 }
154
155 void
globfree(glob_t * pglob)156 globfree(
157 glob_t* pglob)
158 {
159 if (pglob)
160 {
161 char** cur;
162 for (cur = pglob->gl_pathv; *cur; cur++)
163 {
164 free(*cur);
165 }
166
167 pglob->gl_pathc = 0;
168 pglob->gl_pathv = NULL;
169 }
170 }
171