libxputty 0.1
Loading...
Searching...
No Matches
xfilepicker.c
Go to the documentation of this file.
1/*
2 * 0BSD
3 *
4 * BSD Zero Clause License
5 *
6 * Copyright (c) 2019 Hermann Meyer
7 *
8 * Permission to use, copy, modify, and/or distribute this software for any
9 * purpose with or without fee is hereby granted.
10
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
16 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 *
19 */
20
21#include "xfilepicker.h"
22#ifdef _WIN32 //Includes
23#include <windows.h>
24#endif
25
26
27static inline int fp_compare_fun (const void *p1, const void *p2) {
28 return strcasecmp(*(const char**) p1, *(const char**) p2);
29}
30
31static inline int fp_compare_hidden_dirs_fun (const void *p1, const void *p2) {
32 if(strstr(*(const char**)p1, PATH_SEPARATOR".") && strstr(*(const char**)p2, PATH_SEPARATOR".")) return 0;
33 if(strstr(*(const char**)p1, PATH_SEPARATOR".")) return 1;
34 if(strstr(*(const char**)p2, PATH_SEPARATOR".")) return -1;
35 return strcasecmp(*(const char**) p1, *(const char**) p2);
36}
37
38static inline int fp_compare_hidden_files_fun (const void *p1, const void *p2) {
39 if(strncmp(*(const char**)p1, ".",1)==0 && strncmp(*(const char**)p2, ".",1)==0) return 0;
40 if(strncmp(*(const char**)p1, ".",1)==0 ) return 1;
41 if(strncmp(*(const char**)p2, ".",1)==0 ) return -1;
42 return strcasecmp(*(const char**) p1, *(const char**) p2);
43}
44
45static inline bool fp_show_hidden_files(FilePicker *filepicker, char* file) {
46 return (filepicker->show_hidden) ? strcmp(file,".")!=0 : (file[0] != '.');
47}
48
49static inline bool fp_show_filter_files(FilePicker *filepicker, char* file) {
50 if (!filepicker->use_filter) {
51 return true;
52 } else {
53 if(strstr(filepicker->filter,"."))
54 return strstr(file, filepicker->filter);
55#ifdef __XDG_MIME_H__
56 return strstr(xdg_mime_get_mime_type_from_file_name(file), filepicker->filter);
57#else
58 return true;
59#endif
60 }
61}
62
63static void fp_sort_buffers(FilePicker *filepicker, int get_dirs) {
64 if (filepicker->dir_counter>1 && get_dirs) {
65 qsort (filepicker->dir_names, filepicker->dir_counter,
66 sizeof filepicker->dir_names[0], (filepicker->show_hidden) ?
67 fp_compare_hidden_dirs_fun : fp_compare_fun);
68 }
69 if (filepicker->file_counter>1) {
70 qsort (filepicker->file_names, filepicker->file_counter,
71 sizeof filepicker->file_names[0], (filepicker->show_hidden) ?
72 fp_compare_hidden_files_fun : fp_compare_fun);
73 }
74}
75
76static void fp_clear_filebuffer(FilePicker *filepicker) {
77 unsigned int j = 0;
78 for(; j<filepicker->file_counter;j++) {
79 free(filepicker->file_names[j]);
80 filepicker->file_names[j] = NULL;
81 }
82 if(filepicker->file_counter) {
83 free(filepicker->file_names);
84 filepicker->file_names = NULL;
85 filepicker->file_counter=0;
86 }
87}
88
89static void fp_clear_dirbuffer(FilePicker *filepicker) {
90 unsigned int j = 0;
91 for(; j<filepicker->dir_counter;j++) {
92 free(filepicker->dir_names[j]);
93 filepicker->dir_names[j] = NULL;
94 }
95 if(filepicker->dir_counter) {
96 free(filepicker->dir_names);
97 filepicker->dir_names = NULL;
98 filepicker->dir_counter=0;
99 }
100}
101
102#ifdef _WIN32 //file/drive functions
103bool is_root_directory(char *path) {
104 return (((strlen(path)==3) && path[1] == ':' && path[2] == '\\')
105 ||((strlen(path)==1) && path[0] == '\\'));
106}
107
108void add_root_directory(FilePicker *filepicker, char *path) {
109 DWORD drives = GetLogicalDrives();
110 int i;
111 for (i=0; i<='Z'-'A'; i++) {
112 if ((drives & (1 << i)) != 0) {
113 filepicker->dir_counter += 1;
114 filepicker->dir_names = (char **)realloc(filepicker->dir_names,
115 (filepicker->dir_counter) * sizeof(char *));
116 asprintf(&filepicker->dir_names[filepicker->dir_counter-1], "%c:\\", 'A'+i);
117 }
118 }
119 /* filepicker->dir_names = (char **)realloc(filepicker->dir_names,
120 (filepicker->dir_counter + 1) * sizeof(char *));
121 assert(filepicker->dir_names != NULL);
122 asprintf(&filepicker->dir_names[filepicker->dir_counter++], "c:%s", PATH_SEPARATOR);
123 assert(&filepicker->dir_names[filepicker->dir_counter] != NULL);*/
124
125}
126
127bool is_file(DIR *dirp, struct dirent *dp) {
128 return ((dirp->dd_dta.attrib & _A_SUBDIR)==0);
129}
130
131bool is_directory(DIR *dirp, struct dirent *dp) {
132 return ((dirp->dd_dta.attrib & _A_SUBDIR) != 0);
133}
134
135#else // __linux__
136bool is_root_directory(char *path) {
137 return (strcmp (path, PATH_SEPARATOR) == 0);
138}
139
140void add_root_directory(FilePicker *filepicker, char *path) {
141 filepicker->dir_names = (char **)realloc(filepicker->dir_names,
142 (filepicker->dir_counter + 1) * sizeof(char *));
143 assert(filepicker->dir_names != NULL);
144 asprintf(&filepicker->dir_names[filepicker->dir_counter++], "%s",path);
145 assert(&filepicker->dir_names[filepicker->dir_counter] != NULL);
146}
147
148bool is_file(DIR *dirp, struct dirent *dp) {
149 return (dp-> d_type != DT_DIR && dp->d_type != DT_UNKNOWN);
150}
151
152bool is_directory(DIR *dirp, struct dirent *dp) {
153 return (dp -> d_type == DT_DIR);
154}
155
156#endif
157
158static inline int fp_prefill_dirbuffer(FilePicker *filepicker, char *path) {
159 int ret = 0;
160 if (is_root_directory(path)) {
161 add_root_directory(filepicker, path);
162 } else {
163 char *ho;
164 asprintf(&ho, "%s",path);
165 assert(ho != NULL);
166 while (strcmp (ho, PATH_SEPARATOR) != 0) {
167 filepicker->dir_names = (char **)realloc(filepicker->dir_names,
168 (filepicker->dir_counter + 1) * sizeof(char *));
169 assert(filepicker->dir_names != NULL);
170 asprintf(&filepicker->dir_names[filepicker->dir_counter++], "%s",dirname(ho));
171 assert(&filepicker->dir_names[filepicker->dir_counter-1] != NULL);
172 ret++;
173 }
174 if (strcmp (path, PATH_SEPARATOR) != 0) {
175 filepicker->dir_names = (char **)realloc(filepicker->dir_names,
176 (filepicker->dir_counter + 1) * sizeof(char *));
177 assert(filepicker->dir_names != NULL);
178 asprintf(&filepicker->dir_names[filepicker->dir_counter++], "%s",path);
179 assert(&filepicker->dir_names[filepicker->dir_counter-1] != NULL);
180 }
181 free(ho);
182 }
183 return ret;
184}
185
186int fp_check_link(char *path, struct dirent *dp) {
187#ifdef __linux__ //not supported on win32
188 if(dp -> d_type == DT_LNK) {
189 char s[256];
190 snprintf(s, 256, (strcmp(path, PATH_SEPARATOR) != 0) ?
191 "%s" PATH_SEPARATOR "%s" : "%s%s" , path,dp->d_name);
192 struct stat sb;
193 if (stat(s, &sb) == 0 && S_ISDIR(sb.st_mode)) {
194 return 1;
195 }
196 }
197#endif
198 return 0;
199}
200
201int fp_check_dir(char *path, struct dirent *dp) {
202#ifdef __linux__ //not supported on win32
203 if (dp->d_type == DT_UNKNOWN) {
204 char s[256];
205 snprintf(s, 256, (strcmp(path, PATH_SEPARATOR) != 0) ?
206 "%s" PATH_SEPARATOR "%s" : "%s%s" , path,dp->d_name);
207 struct stat sb;
208 if (stat(s, &sb) == 0 && S_ISDIR(sb.st_mode)) {
209 return 1;
210 } else {
211 return 2;
212 }
213 }
214#endif
215 return 0;
216}
217
218int fp_is_link(struct dirent *dp) {
219#ifdef _WIN32 //not supported on win32
220 return 0;
221#else
222 return dp -> d_type == DT_LNK;
223#endif
224}
225
226int fp_get_files(FilePicker *filepicker, char *path, int get_dirs, int get_files) {
227 int ret = 0;
228 fp_clear_filebuffer(filepicker);
229
230 DIR *dirp;
231 struct dirent *dp;
232 if((dirp = opendir(path)) == NULL) {
233 path =(char*)PATH_SEPARATOR;
234 dirp = opendir(PATH_SEPARATOR);
235 assert(dirp);
236 }
237
238 if(get_dirs) {
239 fp_clear_dirbuffer(filepicker);
240 ret = fp_prefill_dirbuffer(filepicker, path);
241 }
242
243 while ((dp = readdir(dirp)) != NULL) {
244
245 if((get_files && (is_file(dirp, dp) || (fp_check_dir(path, dp) == 2)) && strlen(dp->d_name)!=0
246 && strcmp(dp->d_name,"..")!=0 && fp_show_hidden_files(filepicker, dp->d_name)
247 && fp_show_filter_files(filepicker, dp->d_name) && !fp_check_link(path, dp)) ) {
248
249 filepicker->file_names = (char **)realloc(filepicker->file_names,
250 (filepicker->file_counter + 1) * sizeof(char *));
251 assert(filepicker->file_names != NULL);
252 asprintf(&filepicker->file_names[filepicker->file_counter++],"%s",dp->d_name);
253 assert(&filepicker->file_names[filepicker->file_counter-1] != NULL);
254
255 } else if(get_dirs && (is_directory(dirp, dp) || fp_is_link(dp) || (fp_check_dir(path, dp) == 1))
256 && strlen(dp->d_name)!=0 && strcmp(dp->d_name,"..")!=0 && fp_show_hidden_files(filepicker, dp->d_name)) {
257
258 if (fp_is_link(dp)) {
259 if (!fp_check_link(path, dp)) continue;
260 }
261 filepicker->file_names = (char **)realloc(filepicker->file_names,
262 (filepicker->file_counter + 1) * sizeof(char *));
263 assert(filepicker->file_names != NULL);
264 asprintf(&filepicker->file_names[filepicker->file_counter++], (strcmp(path, PATH_SEPARATOR) != 0) ?
265 "%s" PATH_SEPARATOR "%s" : "%s%s" , path,dp->d_name);
266 //asprintf(&filepicker->file_names[filepicker->file_counter++],"%s%s" , path,dp->d_name);
267 assert(&filepicker->dir_names[filepicker->file_counter-1] != NULL);
268 }
269 }
270 closedir(dirp);
271 fp_sort_buffers(filepicker, get_dirs);
272 return ret;
273}
274
275void fp_free(FilePicker *filepicker) {
276 fp_clear_filebuffer(filepicker);
277 fp_clear_dirbuffer(filepicker);
278 free(filepicker->selected_file);
279 free(filepicker->path);
280 free(filepicker->filter);
281}
282
283void fp_init(FilePicker *filepicker, const char *path) {
284 filepicker->file_counter=0;
285 filepicker->dir_counter=0;
286 filepicker->use_filter = 0;
287 filepicker->show_hidden = false;
288 filepicker->file_names = NULL;
289 filepicker->dir_names = NULL;
290 filepicker->selected_file = NULL;
291 filepicker->path = NULL;
292 filepicker->filter = NULL;
293#ifdef _WIN32 //file/drive functions
294 asprintf(&filepicker->path, "%s", "C:\\");
295#else
296 asprintf(&filepicker->path, "%s", path);
297#endif
298 assert(filepicker->path != NULL);
299}
unsigned int file_counter
Definition xfilepicker.h:69
char * filter
Definition xfilepicker.h:64
bool show_hidden
Definition xfilepicker.h:72
char * selected_file
Definition xfilepicker.h:66
char * path
Definition xfilepicker.h:65
unsigned int dir_counter
Definition xfilepicker.h:70
char ** dir_names
Definition xfilepicker.h:68
char ** file_names
Definition xfilepicker.h:67
int asprintf(char *strp[], const char *fmt,...)
Definition xasprintf.c:36
const char * xdg_mime_get_mime_type_from_file_name(const char *file_name)
Definition xdgmime.c:572
int fp_check_link(char *path, struct dirent *dp)
void fp_init(FilePicker *filepicker, const char *path)
fp_init - set default values used by the filepicker
bool is_file(DIR *dirp, struct dirent *dp)
int fp_check_dir(char *path, struct dirent *dp)
int fp_is_link(struct dirent *dp)
void add_root_directory(FilePicker *filepicker, char *path)
bool is_root_directory(char *path)
int fp_get_files(FilePicker *filepicker, char *path, int get_dirs, int get_files)
fp_get_files - fill file_names and dir_names with the results from readdir path
bool is_directory(DIR *dirp, struct dirent *dp)
void fp_free(FilePicker *filepicker)
fp_free - release all memory used by the filepicker