1 /**
2 * \file os_match.c
3 * \brief Match files and directories.
4 * \author Copyright (c) 2002-2014 Jason Perkins and the Premake project
5 */
6
7 #include <stdlib.h>
8 #include <string.h>
9 #include "premake.h"
10
11
12 #if PLATFORM_WINDOWS
13
14 typedef struct struct_MatchInfo
15 {
16 HANDLE handle;
17 int is_first;
18 WIN32_FIND_DATAW entry;
19 } MatchInfo;
20
os_matchstart(lua_State * L)21 int os_matchstart(lua_State* L)
22 {
23 const char* mask = luaL_checkstring(L, 1);
24 MatchInfo* m;
25
26 wchar_t wide_mask[PATH_MAX];
27 if (MultiByteToWideChar(CP_UTF8, 0, mask, -1, wide_mask, PATH_MAX) == 0)
28 {
29 lua_pushstring(L, "unable to encode mask");
30 return lua_error(L);
31 }
32
33 m = (MatchInfo*)malloc(sizeof(MatchInfo));
34
35 m->handle = FindFirstFileW(wide_mask, &m->entry);
36 m->is_first = 1;
37 lua_pushlightuserdata(L, m);
38 return 1;
39 }
40
os_matchdone(lua_State * L)41 int os_matchdone(lua_State* L)
42 {
43 MatchInfo* m = (MatchInfo*)lua_touserdata(L, 1);
44 if (m->handle != INVALID_HANDLE_VALUE)
45 FindClose(m->handle);
46 free(m);
47 return 0;
48 }
49
os_matchname(lua_State * L)50 int os_matchname(lua_State* L)
51 {
52 MatchInfo* m = (MatchInfo*)lua_touserdata(L, 1);
53
54 char filename[PATH_MAX];
55 if (WideCharToMultiByte(CP_UTF8, 0, m->entry.cFileName, -1, filename, PATH_MAX, NULL, NULL) == 0)
56 {
57 lua_pushstring(L, "unable to decode filename");
58 return lua_error(L);
59 }
60
61 lua_pushstring(L, filename);
62 return 1;
63 }
64
os_matchisfile(lua_State * L)65 int os_matchisfile(lua_State* L)
66 {
67 MatchInfo* m = (MatchInfo*)lua_touserdata(L, 1);
68 lua_pushboolean(L, (m->entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0);
69 return 1;
70 }
71
os_matchnext(lua_State * L)72 int os_matchnext(lua_State* L)
73 {
74 MatchInfo* m = (MatchInfo*)lua_touserdata(L, 1);
75 if (m->handle == INVALID_HANDLE_VALUE) {
76 return 0;
77 }
78
79 while (m) /* loop forever */
80 {
81 if (m->is_first)
82 m->is_first = 0;
83 else
84 {
85 if (!FindNextFileW(m->handle, &m->entry))
86 return 0;
87 }
88
89 if (wcscmp(m->entry.cFileName, L".") != 0 && wcscmp(m->entry.cFileName, L"..") != 0)
90 {
91 lua_pushboolean(L, 1);
92 return 1;
93 }
94 }
95
96 return 0;
97 }
98
99 #else
100
101 #include <dirent.h>
102 #include <fnmatch.h>
103 #include <sys/stat.h>
104
105 typedef struct struct_MatchInfo
106 {
107 DIR* handle;
108 struct dirent* entry;
109 char* path;
110 char* mask;
111 } MatchInfo;
112
os_matchstart(lua_State * L)113 int os_matchstart(lua_State* L)
114 {
115 const char* split;
116 const char* mask = luaL_checkstring(L, 1);
117 MatchInfo* m = (MatchInfo*)malloc(sizeof(MatchInfo));
118
119 /* split the mask into path and filename components */
120 split = strrchr(mask, '/');
121 if (split)
122 {
123 m->path = (char*)malloc(split - mask + 1);
124 strncpy(m->path, mask, split - mask);
125 m->path[split - mask] = '\0';
126 m->mask = (char*)malloc(mask + strlen(mask) - split);
127 strcpy(m->mask, split + 1);
128 }
129 else
130 {
131 m->path = (char*)malloc(2);
132 strcpy(m->path, ".");
133 m->mask = (char*)malloc(strlen(mask)+1);
134 strcpy(m->mask, mask);
135 }
136
137 m->handle = opendir(m->path);
138 lua_pushlightuserdata(L, m);
139 return 1;
140 }
141
os_matchdone(lua_State * L)142 int os_matchdone(lua_State* L)
143 {
144 MatchInfo* m = (MatchInfo*)lua_touserdata(L, 1);
145 if (m->handle != NULL)
146 closedir(m->handle);
147 free(m->path);
148 free(m->mask);
149 free(m);
150 return 0;
151 }
152
os_matchname(lua_State * L)153 int os_matchname(lua_State* L)
154 {
155 MatchInfo* m = (MatchInfo*)lua_touserdata(L, 1);
156 lua_pushstring(L, m->entry->d_name);
157 return 1;
158 }
159
os_matchisfile(lua_State * L)160 int os_matchisfile(lua_State* L)
161 {
162 MatchInfo* m = (MatchInfo*)lua_touserdata(L, 1);
163 #if defined(_DIRENT_HAVE_D_TYPE)
164 // Dirent marks symlinks as DT_LNK, not (DT_LNK|DT_DIR). The fallback handles symlinks using stat.
165 if (m->entry->d_type == DT_DIR)
166 {
167 lua_pushboolean(L, 0);
168 }
169 else
170 #endif
171 {
172 const char* fname;
173 lua_pushfstring(L, "%s/%s", m->path, m->entry->d_name);
174 fname = lua_tostring(L, -1);
175 lua_pop(L, 1);
176
177 lua_pushboolean(L, do_isfile(L, fname));
178 }
179 return 1;
180 }
181
os_matchnext(lua_State * L)182 int os_matchnext(lua_State* L)
183 {
184 MatchInfo* m = (MatchInfo*)lua_touserdata(L, 1);
185 if (m->handle == NULL) {
186 return 0;
187 }
188
189 m->entry = readdir(m->handle);
190 while (m->entry != NULL)
191 {
192 const char* name = m->entry->d_name;
193 if (strcmp(name, ".") != 0 && strcmp(name, "..") != 0)
194 {
195 if (fnmatch(m->mask, name, 0) == 0)
196 {
197 lua_pushboolean(L, 1);
198 return 1;
199 }
200 }
201 m->entry = readdir(m->handle);
202 }
203
204 return 0;
205 }
206
207 #endif
208