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
23
fp_compare_fun(const void * p1,const void * p2)24 static inline int fp_compare_fun (const void *p1, const void *p2) {
25 return strcasecmp(*(const char**) p1, *(const char**) p2);
26 }
27
fp_compare_hidden_dirs_fun(const void * p1,const void * p2)28 static inline int fp_compare_hidden_dirs_fun (const void *p1, const void *p2) {
29 if(strstr(*(const char**)p1, PATH_SEPARATOR".") && strstr(*(const char**)p2, PATH_SEPARATOR".")) return 0;
30 if(strstr(*(const char**)p1, PATH_SEPARATOR".")) return 1;
31 if(strstr(*(const char**)p2, PATH_SEPARATOR".")) return -1;
32 return strcasecmp(*(const char**) p1, *(const char**) p2);
33 }
34
fp_compare_hidden_files_fun(const void * p1,const void * p2)35 static inline int fp_compare_hidden_files_fun (const void *p1, const void *p2) {
36 if(strncmp(*(const char**)p1, ".",1)==0 && strncmp(*(const char**)p2, ".",1)==0) return 0;
37 if(strncmp(*(const char**)p1, ".",1)==0 ) return 1;
38 if(strncmp(*(const char**)p2, ".",1)==0 ) return -1;
39 return strcasecmp(*(const char**) p1, *(const char**) p2);
40 }
41
fp_show_hidden_files(FilePicker * filepicker,char * file)42 static inline bool fp_show_hidden_files(FilePicker *filepicker, char* file) {
43 return (filepicker->show_hidden) ? strcmp(file,".")!=0 : (file[0] != '.');
44 }
45
fp_show_filter_files(FilePicker * filepicker,char * file)46 static inline bool fp_show_filter_files(FilePicker *filepicker, char* file) {
47 if (!filepicker->use_filter) {
48 return true;
49 } else {
50 if(strstr(filepicker->filter,"."))
51 return strstr(file, filepicker->filter);
52 #ifdef __XDG_MIME_H__
53 return strstr(xdg_mime_get_mime_type_from_file_name(file), filepicker->filter);
54 #else
55 return true;
56 #endif
57 }
58 }
59
fp_sort_buffers(FilePicker * filepicker,int get_dirs)60 static void fp_sort_buffers(FilePicker *filepicker, int get_dirs) {
61 if (filepicker->dir_counter>1 && get_dirs) {
62 qsort (filepicker->dir_names, filepicker->dir_counter,
63 sizeof filepicker->dir_names[0], (filepicker->show_hidden) ?
64 fp_compare_hidden_dirs_fun : fp_compare_fun);
65 }
66 if (filepicker->file_counter>1) {
67 qsort (filepicker->file_names, filepicker->file_counter,
68 sizeof filepicker->file_names[0], (filepicker->show_hidden) ?
69 fp_compare_hidden_files_fun : fp_compare_fun);
70 }
71 }
72
fp_clear_filebuffer(FilePicker * filepicker)73 static void fp_clear_filebuffer(FilePicker *filepicker) {
74 unsigned int j = 0;
75 for(; j<filepicker->file_counter;j++) {
76 free(filepicker->file_names[j]);
77 filepicker->file_names[j] = NULL;
78 }
79 if(filepicker->file_counter) {
80 free(filepicker->file_names);
81 filepicker->file_names = NULL;
82 filepicker->file_counter=0;
83 }
84 }
85
fp_clear_dirbuffer(FilePicker * filepicker)86 static void fp_clear_dirbuffer(FilePicker *filepicker) {
87 unsigned int j = 0;
88 for(; j<filepicker->dir_counter;j++) {
89 free(filepicker->dir_names[j]);
90 filepicker->dir_names[j] = NULL;
91 }
92 if(filepicker->dir_counter) {
93 free(filepicker->dir_names);
94 filepicker->dir_names = NULL;
95 filepicker->dir_counter=0;
96 }
97 }
98
fp_prefill_dirbuffer(FilePicker * filepicker,char * path)99 static inline int fp_prefill_dirbuffer(FilePicker *filepicker, char *path) {
100 int ret = 0;
101 if (strcmp (path, PATH_SEPARATOR) == 0) {
102 filepicker->dir_names = (char **)realloc(filepicker->dir_names,
103 (filepicker->dir_counter + 1) * sizeof(char *));
104 assert(filepicker->dir_names != NULL);
105 asprintf(&filepicker->dir_names[filepicker->dir_counter++], "%s",path);
106 assert(&filepicker->dir_names[filepicker->dir_counter] != NULL);
107 } else {
108 char *ho;
109 asprintf(&ho, "%s",path);
110 assert(ho != NULL);
111 while (strcmp (ho, PATH_SEPARATOR) != 0) {
112 filepicker->dir_names = (char **)realloc(filepicker->dir_names,
113 (filepicker->dir_counter + 1) * sizeof(char *));
114 assert(filepicker->dir_names != NULL);
115 asprintf(&filepicker->dir_names[filepicker->dir_counter++], "%s",dirname(ho));
116 assert(&filepicker->dir_names[filepicker->dir_counter] != NULL);
117 ret++;
118 }
119 if (strcmp (path, PATH_SEPARATOR) != 0) {
120 filepicker->dir_names = (char **)realloc(filepicker->dir_names,
121 (filepicker->dir_counter + 1) * sizeof(char *));
122 assert(filepicker->dir_names != NULL);
123 asprintf(&filepicker->dir_names[filepicker->dir_counter++], "%s",path);
124 assert(&filepicker->dir_names[filepicker->dir_counter] != NULL);
125 }
126 free(ho);
127 }
128 return ret;
129 }
130
fp_get_files(FilePicker * filepicker,char * path,int get_dirs)131 int fp_get_files(FilePicker *filepicker, char *path, int get_dirs) {
132 int ret = 0;
133 fp_clear_filebuffer(filepicker);
134
135 DIR *dirp;
136 struct dirent *dp;
137 if((dirp = opendir(path)) == NULL) {
138 path =(char*)PATH_SEPARATOR;
139 dirp = opendir(PATH_SEPARATOR);
140 assert(dirp);
141 }
142
143 if(get_dirs) {
144 fp_clear_dirbuffer(filepicker);
145 ret = fp_prefill_dirbuffer(filepicker, path);
146 }
147
148 while ((dp = readdir(dirp)) != NULL) {
149
150 if(dp-> d_type != DT_DIR && strlen(dp->d_name)!=0 && dp->d_type != DT_UNKNOWN
151 && strcmp(dp->d_name,"..")!=0 && fp_show_hidden_files(filepicker, dp->d_name) &&
152 fp_show_filter_files(filepicker, dp->d_name)) {
153
154 filepicker->file_names = (char **)realloc(filepicker->file_names,
155 (filepicker->file_counter + 1) * sizeof(char *));
156 assert(filepicker->file_names != NULL);
157 asprintf(&filepicker->file_names[filepicker->file_counter++],"%s",dp->d_name);
158 assert(&filepicker->file_names[filepicker->file_counter] != NULL);
159
160 } else if(get_dirs && dp -> d_type == DT_DIR && strlen(dp->d_name)!=0
161 && strcmp(dp->d_name,"..")!=0 && fp_show_hidden_files(filepicker, dp->d_name)) {
162
163 filepicker->dir_names = (char **)realloc(filepicker->dir_names,
164 (filepicker->dir_counter + 1) * sizeof(char *));
165 assert(filepicker->dir_names != NULL);
166 asprintf(&filepicker->dir_names[filepicker->dir_counter++], (strcmp(path, PATH_SEPARATOR) != 0) ?
167 "%s" PATH_SEPARATOR "%s" : "%s%s" , path,dp->d_name);
168 assert(&filepicker->dir_names[filepicker->dir_counter] != NULL);
169 }
170 }
171 closedir(dirp);
172 fp_sort_buffers(filepicker, get_dirs);
173 return ret;
174 }
175
fp_free(FilePicker * filepicker)176 void fp_free(FilePicker *filepicker) {
177 fp_clear_filebuffer(filepicker);
178 fp_clear_dirbuffer(filepicker);
179 free(filepicker->selected_file);
180 free(filepicker->path);
181 free(filepicker->filter);
182 }
183
fp_init(FilePicker * filepicker,const char * path)184 void fp_init(FilePicker *filepicker, const char *path) {
185 filepicker->file_counter=0;
186 filepicker->dir_counter=0;
187 filepicker->use_filter = 0;
188 filepicker->show_hidden = false;
189 filepicker->file_names = NULL;
190 filepicker->dir_names = NULL;
191 filepicker->selected_file = NULL;
192 filepicker->path = NULL;
193 filepicker->filter = NULL;
194 asprintf(&filepicker->path, path);
195 assert(filepicker->path != NULL);
196 }
197