1 /*
2 Copyright (C) 2015-2021, Dirk Krause
3 SPDX-License-Identifier: BSD-3-Clause
4 */
5
6 /*
7 WARNING: This file was generated by the dkct program (see
8 http://dktools.sourceforge.net/ for details).
9 Changes you make here will be lost if dkct is run again!
10 You should modify the original source and run dkct on it.
11 Original source: dk4dirwc.ctr
12 */
13
14 /** @file dk4dirwc.c The dk4dirwc module.
15 */
16
17
18 #include "dk4conf.h"
19
20 #if DK4_ON_WINDOWS
21 #ifndef WINDOWS_H_INCLUDED
22 #include <windows.h>
23 #define WINDOWS_H_INCLUDED 1
24 #endif
25 #endif
26
27 #include <libdk4c/dk4dirwc.h>
28
29 #ifndef DK4DIR_H_INCLUDED
30 #include <libdk4c/dk4dir.h>
31 #endif
32
33 #ifndef DK4PATHW_H_INCLUDED
34 #include <libdk4c/dk4pathw.h>
35 #endif
36
37 #ifndef DK4STR8_H_INCLUDED
38 #include <libdk4base/dk4strw.h>
39 #endif
40
41 #ifndef DK4STAT_H_INCLUDED
42 #include <libdk4c/dk4stat.h>
43 #endif
44
45 #ifndef DK4STAT8_H_INCLUDED
46 #include <libdk4c/dk4statw.h>
47 #endif
48
49 #ifndef DK4MEM_H_INCLUDED
50 #include <libdk4base/dk4mem.h>
51 #endif
52
53 #ifndef DK4MPL_H_INCLUDED
54 #include <libdk4base/dk4mpl.h>
55 #endif
56
57 #ifndef DK4MAASZ_H_INCLUDED
58 #include <libdk4ma/dk4maasz.h>
59 #endif
60
61 #if DK4_HAVE_SYS_TYPES_H
62 #ifndef SYS_TYPES_H_INCLUDED
63 #include <sys/types.h>
64 #define SYS_TYPES_H_INCLUDED 1
65 #endif
66 #endif
67
68 #if DK4_HAVE_WCHAR_H
69 #ifndef WCHAR_H_INCLUDED
70 #include <wchar.h>
71 #define WCHAR_H_INCLUDED 1
72 #endif
73 #endif
74
75 #if DK4_HAVE_DIRENT_H
76 #ifndef DIRENT_H_INCLUDED
77 #include <dirent.h>
78 #define DIRENT_H_INCLUDED 1
79 #endif
80 #endif
81
82 #if DK4_HAVE_ERRNO_H
83 #ifndef ERRNO_H_INCLUDED
84 #include <errno.h>
85 #define ERRNO_H_INCLUDED 1
86 #endif
87 #endif
88
89 #if DK4_HAVE_ASSERT_H
90 #ifndef ASSERT_H_INCLUDED
91 #include <assert.h>
92 #define ASSERT_H_INCLUDED 1
93 #endif
94 #endif
95
96 #include <libdk4base/dk4unused.h>
97
98
99
100
101
102
103
104
105 #if DK4_ON_WINDOWS
106
107 int
dk4dir_wc_compare(const void * l,const void * r,int DK4_ARG_UNUSED (cr))108 dk4dir_wc_compare(const void *l, const void *r, int DK4_ARG_UNUSED(cr))
109 {
110 int back = 0;
111 DK4_UNUSED_ARG(cr)
112 if (NULL != l) {
113 if (NULL != r) {
114 back = dk4strw_pathcmp((const wchar_t *)l, (const wchar_t *)r);
115 } else {
116 back = 1;
117 }
118 } else {
119 if (NULL != r) { back = -1; }
120 }
121 return back;
122 }
123
124 #endif
125
126
127
128 static
129 void
dk4dir_wc_clean_storage(dk4_sto_t * s,dk4_sto_it_t * i)130 dk4dir_wc_clean_storage(dk4_sto_t *s, dk4_sto_it_t *i)
131 {
132 wchar_t *n;
133 if (NULL != s) {
134 if (NULL != i) {
135 dk4sto_it_reset(i);
136 while (NULL != (n = (wchar_t *)dk4sto_it_next(i))) {
137 dk4mem_free(n);
138 }
139 dk4sto_it_close(i);
140 }
141 dk4sto_close(s);
142 }
143 }
144
145
146
147 void
dk4dir_wc_close(dk4_dir_wc_t * dptr)148 dk4dir_wc_close(dk4_dir_wc_t *dptr)
149 {
150 #if DK4_USE_ASSERT
151 assert(NULL != dptr);
152 #endif
153 if (NULL != dptr) {
154 dk4mem_release(dptr->path);
155 dk4dir_wc_clean_storage(dptr->s_dir, dptr->i_dir);
156 dptr->s_dir = NULL; dptr->i_dir = NULL;
157 dk4dir_wc_clean_storage(dptr->s_file, dptr->i_file);
158 dptr->s_file = NULL; dptr->i_file = NULL;
159 dk4mem_free(dptr);
160 }
161 }
162
163
164
165 #if DK4_ON_WINDOWS
166 /** Fixed texts used by the module.
167 */
168 static const wchar_t * const dk4dir_wc_kw[] = {
169 /* 0 */
170 L".",
171
172 /* 1 */
173 L"..",
174
175 /* 2 */
176 L"/",
177
178 /* 3 */
179 L"\\",
180
181 /* 4 */
182 L"*",
183
184 NULL
185
186 };
187
188
189
190 static
191 int
dk4dir_wc_fill_with_pab(dk4_dir_wc_t * dptr,int om,wchar_t * pab,size_t szpab,dk4_er_t * erp)192 dk4dir_wc_fill_with_pab(
193 dk4_dir_wc_t *dptr,
194 int om,
195 wchar_t *pab,
196 size_t szpab,
197 dk4_er_t *erp
198 )
199 {
200 WIN32_FIND_DATAW ffdata; /* Find result */
201 HANDLE ffres; /* Result from findfirst */
202 dkChar *nn; /* Copy of name, dyn */
203 DWORD attr; /* File attributes */
204 size_t slen; /* Entry name length. */
205 int isdir; /* Flag: Entry is directory */
206 int back = 0;
207
208 #if DK4_USE_ASSERT
209 assert(NULL != dptr);
210 assert(NULL != pab);
211 assert(0 < szpab);
212 #endif
213 if (dk4strw_cpy_s(pab, szpab, dptr->path, erp)) {
214 if (dk4strw_cat_s(pab, szpab, dk4dir_wc_kw[3], erp)) {
215 if (dk4strw_cat_s(pab, szpab, dk4dir_wc_kw[4], erp)) {
216 ffres = FindFirstFileW(pab, &ffdata);
217 if (INVALID_HANDLE_VALUE != ffres) {
218 back = 1;
219 do {
220 if (0 != dk4strw_cmp(dk4dir_wc_kw[0], ffdata.cFileName)) {
221 if (0 != dk4strw_cmp(dk4dir_wc_kw[1], ffdata.cFileName)) {
222 slen = dk4strw_len(ffdata.cFileName);
223 if (slen > dptr->maxlen) { dptr->maxlen = slen; }
224 nn = dk4strw_dup(ffdata.cFileName, erp);
225 if (NULL != nn) {
226 isdir = 0;
227 attr = ffdata.dwFileAttributes;
228 if (0 != (FILE_ATTRIBUTE_DIRECTORY & attr)) {
229 isdir = 1;
230 if (0 != (FILE_ATTRIBUTE_REPARSE_POINT & attr)) {
231 if (0 != (DK4_DIR_SYMLINK_DIR_AS_FILE & om)) {
232 isdir = 0;
233 }
234 }
235 }
236 if (0 != isdir) {
237 if (0 == dk4sto_add(dptr->s_dir, (void *)nn, erp)) {
238 back = 0;
239 dk4mem_free(nn);
240 }
241 } else {
242 if (0 == dk4sto_add(dptr->s_file, (void *)nn, erp)) {
243 back = 0;
244 dk4mem_free(nn);
245 }
246 }
247 } else {
248 back = 0;
249 }
250 }
251 }
252 } while(FindNextFileW(ffres, &ffdata));
253 FindClose(ffres);
254 } else {
255 /* ERROR: FindFirstFile failed */
256 dk4error_set_ldetails(
257 erp, DK4_E_FINDFIRSTFILE_FAILED,
258 (long)((unsigned long)GetLastError())
259 );
260 }
261 }
262 }
263 }
264
265 return back;
266 }
267
268
269
270 static
271 int
dk4dir_wc_fill_with_local(dk4_dir_wc_t * dptr,int om,dk4_er_t * erp)272 dk4dir_wc_fill_with_local(dk4_dir_wc_t *dptr, int om, dk4_er_t *erp)
273 {
274 wchar_t pab[DK4_MAX_PATH];
275 #if DK4_USE_ASSERT
276 assert(NULL != dptr);
277 #endif
278 return (dk4dir_wc_fill_with_pab(dptr, om, pab, DK4_SIZEOF(pab,wchar_t), erp));
279 }
280
281
282
283 /** Fill directory structure with data about subdirectories and files.
284 @param dptr Directory structure to fill.
285 @param om Opening mode.
286 @param erp Error report, may be NULL.
287 @return 1 on success, 0 on errors.
288 */
289 static
290 int
dk4dir_wc_fill_directory(dk4_dir_wc_t * dptr,int om,dk4_er_t * erp)291 dk4dir_wc_fill_directory(dk4_dir_wc_t *dptr, int om, dk4_er_t *erp)
292 {
293 dk4_er_t er;
294 wchar_t *pab;
295 size_t dptrlgt;
296 int back = 0;
297
298 #if DK4_USE_ASSERT
299 assert(NULL != dptr);
300 #endif
301 dptrlgt = dk4strw_len(dptr->path);
302 if ((DK4_MAX_PATH - 2) > dptrlgt) {
303 back = dk4dir_wc_fill_with_local(dptr, om, erp);
304 } else {
305 dk4error_init(&er);
306 dptrlgt = dk4ma_size_t_add(dptrlgt, 3, &er);
307 if (DK4_E_NONE == er.ec) {
308 pab = dk4mem_new(wchar_t, dptrlgt, erp);
309 if (NULL != pab) {
310 back = dk4dir_wc_fill_with_pab(dptr, om, pab, dptrlgt, erp);
311 dk4mem_free(pab);
312 }
313 } else {
314 dk4error_copy(erp, &er);
315 }
316 }
317 return back;
318 }
319
320 #endif
321
322
323
324 dk4_dir_wc_t *
dk4dir_wc_open(const wchar_t * path,int om,dk4_er_t * erp)325 dk4dir_wc_open(
326 const wchar_t *path,
327 #if DK4_ON_WINDOWS
328 int om,
329 #else
330 int DK4_ARG_UNUSED(om),
331 #endif
332 dk4_er_t *erp
333 )
334 {
335 dk4_dir_wc_t *back = NULL;
336 #if DK4_ON_WINDOWS
337 int ok = 0;
338 #endif
339 #if DK4_USE_ASSERT
340 assert(NULL != path);
341 #endif
342 if (NULL != path) {
343 #if DK4_ON_WINDOWS
344 back = dk4mem_new(dk4_dir_wc_t, 1, erp);
345 if (NULL != back) {
346 back->path = NULL;
347 back->s_dir = NULL;
348 back->i_dir = NULL;
349 back->s_file = NULL;
350 back->i_file = NULL;
351 back->path = dk4strw_dup(path, erp);
352 back->maxlen = 0;
353 if (NULL != back->path) {
354 back->s_dir = dk4sto_open(erp);
355 if (NULL != back->s_dir) {
356 if (0 != (DK4_DIR_OPEN_SORTED & om)) {
357 dk4sto_set_comp(back->s_dir, dk4dir_wc_compare, 0);
358 }
359 back->i_dir = dk4sto_it_open(back->s_dir, erp);
360 if (NULL != back->i_dir) {
361 back->s_file = dk4sto_open(erp);
362 if (NULL != back->s_file) {
363 if (0 != (DK4_DIR_OPEN_SORTED & om)) {
364 dk4sto_set_comp(back->s_file, dk4dir_wc_compare, 0);
365 }
366 back->i_file = dk4sto_it_open(back->s_file, erp);
367 if (NULL != back->i_file) {
368 ok = dk4dir_wc_fill_directory(back, om, erp);
369 }
370 }
371 }
372 }
373 }
374 if (0 == ok) {
375 dk4dir_wc_close(back);
376 back = NULL;
377 }
378 }
379 #else
380 DK4_UNUSED_ARG(om)
381 dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED);
382 #endif
383 } else {
384 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
385 }
386 return back;
387 }
388
389
390
391 void
dk4dir_wc_reset(dk4_dir_wc_t * dptr)392 dk4dir_wc_reset(dk4_dir_wc_t *dptr)
393 {
394 #if DK4_USE_ASSERT
395 assert(NULL != dptr);
396 #endif
397 if (NULL != dptr) {
398 if ((NULL != dptr->s_dir) && (NULL != dptr->i_dir)) {
399 dk4sto_it_reset(dptr->i_dir);
400 }
401 if ((NULL != dptr->s_file) && (NULL != dptr->i_file)) {
402 dk4sto_it_reset(dptr->i_file);
403 }
404 }
405 }
406
407
408
409 const wchar_t *
dk4dir_wc_get_path(dk4_dir_wc_t const * dptr)410 dk4dir_wc_get_path(dk4_dir_wc_t const *dptr)
411 {
412 const wchar_t *back = NULL;
413 #if DK4_USE_ASSERT
414 assert(NULL != dptr);
415 #endif
416 if (NULL != dptr) {
417 back = (const wchar_t *)(dptr->path);
418 }
419 return back;
420 }
421
422
423
424 const wchar_t *
dk4dir_wc_next_dir(dk4_dir_wc_t * dptr)425 dk4dir_wc_next_dir(dk4_dir_wc_t *dptr)
426 {
427 const wchar_t *back = NULL;
428 #if DK4_USE_ASSERT
429 assert(NULL != dptr);
430 #endif
431 if (NULL != dptr) {
432 if ((NULL != dptr->s_dir) && (NULL != dptr->i_dir)) {
433 back = (const wchar_t *)dk4sto_it_next(dptr->i_dir);
434 }
435 }
436 return back;
437 }
438
439
440
441 const wchar_t *
dk4dir_wc_next_file(dk4_dir_wc_t * dptr)442 dk4dir_wc_next_file(dk4_dir_wc_t *dptr)
443 {
444 const wchar_t *back = NULL;
445 #if DK4_USE_ASSERT
446 assert(NULL != dptr);
447 #endif
448 if (NULL != dptr) {
449 if ((NULL != dptr->s_file) && (NULL != dptr->i_file)) {
450 back = (const wchar_t *)dk4sto_it_next(dptr->i_file);
451 }
452 }
453 return back;
454 }
455
456
457
458 void
dk4dir_wc_skip_files(dk4_dir_wc_t * dptr)459 dk4dir_wc_skip_files(dk4_dir_wc_t *dptr)
460 {
461 #if DK4_USE_ASSERT
462 assert(NULL != dptr);
463 #endif
464 if (NULL != dptr) {
465 dk4dir_wc_clean_storage(dptr->s_file, dptr->i_file);
466 dptr->s_file = NULL; dptr->i_file = NULL;
467 }
468 }
469
470
471
472 size_t
dk4dir_wc_get_max_entry_length(dk4_dir_wc_t const * dptr)473 dk4dir_wc_get_max_entry_length(dk4_dir_wc_t const *dptr)
474 {
475 size_t back = 0;
476 #if DK4_USE_ASSERT
477 assert(NULL != dptr);
478 #endif
479 if (NULL != dptr) {
480 back = dptr->maxlen;
481 }
482 return back;
483 }
484
485
486
487 int
dk4dir_wc_full_name_buffer(wchar_t * buffer,size_t szbuf,dk4_dir_wc_t const * pdir,wchar_t const * fn,dk4_er_t * erp)488 dk4dir_wc_full_name_buffer(
489 wchar_t *buffer,
490 size_t szbuf,
491 dk4_dir_wc_t const *pdir,
492 wchar_t const *fn,
493 dk4_er_t *erp
494 )
495 {
496 int back = 0;
497 #if DK4_USE_ASSERT
498 assert(NULL != pdir);
499 assert(NULL != fn);
500 assert(NULL != buffer);
501 assert(0 < szbuf);
502 #endif
503 if ((NULL != buffer) && (NULL != pdir) && (NULL != fn) && (0 < szbuf)) {
504 back = dk4pathw_concatenate_buffer(buffer, szbuf, pdir->path, fn, erp);
505 }
506 else {
507 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
508 }
509 return back;
510 }
511
512
513
514 wchar_t *
dk4dir_wc_full_name_new(dk4_dir_wc_t const * pdir,wchar_t const * fn,dk4_er_t * erp)515 dk4dir_wc_full_name_new(
516 dk4_dir_wc_t const *pdir,
517 wchar_t const *fn,
518 dk4_er_t * erp
519 )
520 {
521 wchar_t *back = NULL;
522 #if DK4_USE_ASSERT
523 assert(NULL != pdir);
524 assert(NULL != fn);
525 #endif
526 if ((NULL != pdir) && (NULL != fn)) {
527 back = dk4pathw_concatenate_new(pdir->path, fn, erp);
528 }
529 else {
530 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
531 }
532 return back;
533 }
534
535