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