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: dk4path8.ctr
12 */
13
14 /** @file dk4path8.c The dk4path8 module.
15 */
16
17
18
19 #include "dk4conf.h"
20 #include <libdk4c/dk4path8.h>
21 #include <libdk4base/dk4mem.h>
22 #include <libdk4base/dk4str8.h>
23 #include <libdk4ma/dk4maasz.h>
24
25 #if DK4_HAVE_STRING_H
26 #ifndef STRING_H_INCLUDED
27 #include <string.h>
28 #define STRING_H_INCLUDED 1
29 #endif
30 #endif
31
32 #if DK4_HAVE_ASSERT_H
33 #ifndef ASSERT_H_INCLUDED
34 #include <assert.h>
35 #define ASSERT_H_INCLUDED 1
36 #endif
37 #endif
38
39 #include <libdk4base/dk4unused.h>
40
41
42
43
44
45
46
47 /** Constant keywords used by the dk4path8 module.
48 */
49 static const char * const dk4path8_kw[] = {
50 #if DK4_HAVE_BACKSLASH_AS_SEP
51 /* 0 */ "\\",
52 /* 1 */ "/",
53 #else
54 /* 0 */ "/",
55 /* 1 */ "\\",
56 #endif
57 /* 2 */ ".",
58 /* 3 */ "..",
59 /* 4 */ ":"
60 };
61
62
63
64 /** Get last character from a string.
65
66 CRT on Windows: Not used.
67 @param str String to test.
68 @return Last character from string.
69 */
70 static
71 char
dk4path8_lastchar(const char * str)72 dk4path8_lastchar(const char *str)
73 {
74 char back = '\0';
75 #if DK4_USE_ASSERT
76 assert(NULL != str);
77 #endif
78 if (str) { while ('\0' != *str) { back = *(str++); } }
79 return back;
80 }
81
82
83
84 int
dk4path8_is_absolute(const char * path)85 dk4path8_is_absolute(const char *path)
86 {
87 int back = 0;
88 #if DK4_ON_WINDOWS
89 char c;
90 #endif
91 #if DK4_USE_ASSERT
92 assert(NULL != path);
93 #endif
94 if (NULL != path) {
95 #if DK4_ON_WINDOWS
96 c = *path;
97 if ( *(dk4path8_kw[0]) == c ) {
98 back = 1;
99 } else {
100 if ((('a' <= c) && ('z' >= c)) || (('A' <= c) && ('Z' >= c))) {
101 if ( *(dk4path8_kw[4]) == path[1] ) {
102 c = path[2];
103 if ( ( *(dk4path8_kw[0]) == c ) || ( '\0' == c ) ) {
104 back = 1;
105 }
106 }
107 }
108 }
109 #else
110 if ( *(dk4path8_kw[0]) == *path ) {
111 back = 1;
112 }
113 #endif
114 }
115 return back;
116 }
117
118
119
120 int
dk4path8_is_relative(const char * path)121 dk4path8_is_relative(const char *path)
122 {
123 int back = 0;
124 #if DK4_USE_ASSERT
125 assert(NULL != path);
126 #endif
127 if (NULL != path) {
128 if (NULL != dk4str8_chr(path, *(dk4path8_kw[0]))) {
129 if (0 == dk4path8_is_absolute(path)) {
130 back = 1;
131 }
132 }
133 }
134 return back;
135 }
136
137
138
139 int
dk4path8_append(char * buffer,size_t sz,const char * filename,dk4_er_t * erp)140 dk4path8_append(char *buffer, size_t sz, const char *filename, dk4_er_t *erp)
141 {
142 char *pc; /* Current path part to append */
143 char *pn; /* Next part to append */
144 char *pd; /* Part to delete */
145 char *mycp = NULL; /* Private copy */
146 #if DK4_ON_WINDOWS
147 int ischr;
148 #endif
149 int back = 0; /* Function result */
150 int failed = 0; /* Definitely failed */
151 char lch; /* Last character from string */
152
153 #if DK4_USE_ASSERT
154 assert(NULL != buffer);
155 assert(0 < sz);
156 assert(NULL != filename);
157 #endif
158 if ((NULL != buffer) && (NULL != filename) && (0 < sz)) {
159 mycp = dk4str8_dup(filename, erp);
160 if (NULL != mycp) {
161 pc = mycp;
162 while ((NULL != pc) && (0 == failed)) {
163 pn = dk4str8_chr(pc, *(dk4path8_kw[0]));
164 if (NULL != pn) { *(pn++) = '\0'; }
165 if (0 != dk4str8_cmp(pc, dk4path8_kw[2])) {
166 if (0 == dk4str8_cmp(pc, dk4path8_kw[3])) { /* Remove from buffer */
167 pd = dk4str8_rchr(buffer, *(dk4path8_kw[0]));
168 if (NULL != pd) {
169 *pd = '\0';
170 if (0 < dk4str8_len(&(pd[1]))) {
171 #if DK4_ON_WINDOWS
172 if (2 == dk4str8_len(buffer)) {
173 ischr = 0;
174 if (('A' <= buffer[0]) && ('Z' >= buffer[0])) {
175 ischr = 1;
176 }
177 if (('a' <= buffer[0]) && ('z' >= buffer[0])) {
178 ischr = 1;
179 }
180 if (1 == ischr) {
181 if (':' == buffer[1]) {
182 buffer[2] = *(dk4path8_kw[0]);
183 buffer[3] = '\0';
184 }
185 }
186 }
187 #else
188 if (0 == dk4str8_len(buffer)) {
189 *pd = *(dk4path8_kw[0]);
190 pd++;
191 *pd = '\0';
192 }
193 #endif
194 } else {
195 failed = 1;
196 dk4error_set_simple_error_code(erp, DK4_E_SYNTAX);
197 }
198 } else {
199 failed = 1;
200 dk4error_set_simple_error_code(erp, DK4_E_SYNTAX);
201 }
202 } else { /* Add to buffer */
203 lch = dk4path8_lastchar(buffer);
204 if (lch != *(dk4path8_kw[0])) {
205 if (0 != dk4str8_cat_s(buffer, sz, dk4path8_kw[0], erp)) {
206 if (0 == dk4str8_cat_s(buffer, sz, pc, erp)) {
207 failed = 1;
208 }
209 } else {
210 failed = 1;
211 }
212 } else {
213 if (0 == dk4str8_cat_s(buffer, sz, pc, erp)) {
214 failed = 1;
215 }
216 }
217 }
218 }
219 pc = pn;
220 }
221 if (0 == failed) {
222 back = 1;
223 }
224 dk4mem_release(mycp);
225 }
226 } else {
227 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
228 }
229 return back;
230 }
231
232
233
234 char *
dk4path8_get_suffix(const char * filename,dk4_er_t * erp)235 dk4path8_get_suffix(const char *filename, dk4_er_t *erp)
236 {
237 const char *back = NULL;
238 #if DK4_USE_ASSERT
239 assert(NULL != filename);
240 #endif
241 if (NULL != filename) {
242 while ('\0' != *filename) {
243 if (('\\' == *filename) || ('/' == *filename)) {
244 back = NULL;
245 } else {
246 if ('.' == *filename) {
247 back = filename;
248 }
249 }
250 filename++;
251 }
252 if (NULL == back) {
253 dk4error_set_simple_error_code(erp, DK4_E_NOT_FOUND);
254 }
255 } else {
256 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
257 }
258 return ((char *)back);
259 }
260
261
262
263 void
dk4path8_correct_sep(char * filename)264 dk4path8_correct_sep(char *filename)
265 {
266 #if DK4_USE_ASSERT
267 assert(NULL != filename);
268 #endif
269 if (NULL != filename) {
270 while ('\0' != *filename) {
271 #if DK4_HAVE_BACKSLASH_AS_SEP
272 if ('/' == *filename) { *filename = '\\'; }
273 #else
274 if ('\\' == *filename) { *filename = '/'; }
275 #endif
276 filename++;
277 }
278 }
279 }
280
281
282
283 int
dk4path8_must_expand(const char * filename)284 dk4path8_must_expand(
285 #if DK4_ON_WINDOWS
286 const char *filename
287 #else
288 const char * DK4_ARG_UNUSED(filename)
289 #endif
290 )
291 {
292 #if DK4_ON_WINDOWS
293 int back = 0;
294 #if DK4_USE_ASSERT
295 assert(NULL != filename);
296 #endif
297 if (NULL != filename) {
298 while(('\0' != *filename) && (0 == back)) {
299 switch (*filename) {
300 case '*': case '?': {
301 back = 1;
302 } break;
303 default: {
304 filename++;
305 } break;
306 }
307 }
308 }
309 return back;
310 #else
311 DK4_UNUSED_ARG(filename)
312 return 0;
313 #endif
314 }
315
316
317
318 int
dk4path8_set_suffix(char * pdst,size_t szdst,char const * srcname,char const * newsu,dk4_er_t * erp)319 dk4path8_set_suffix(
320 char *pdst,
321 size_t szdst,
322 char const *srcname,
323 char const *newsu,
324 dk4_er_t *erp
325 )
326 {
327 char *sp = NULL;
328 int back = 0;
329 #if DK4_USE_ASSERT
330 assert(NULL != pdst);
331 assert(0 < szdst);
332 assert(NULL != srcname);
333 assert(NULL != newsu);
334 #endif
335 if ((NULL == pdst) || (NULL == srcname) || (NULL == newsu) || (0 == szdst)) {
336 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
337 goto finished;
338 }
339 if (0 == dk4str8_cpy_s(pdst, szdst, srcname, erp)) {
340 goto finished;
341 }
342 sp = dk4path8_get_suffix(pdst, NULL);
343 if (NULL != sp) {
344 *sp = '\0';
345 }
346 back = dk4str8_cat_s(pdst, szdst, newsu, erp);
347
348 finished:
349 return back;
350 }
351
352
353
354 char *
dk4path8_dup_change_suffix(char const * srcname,char const * newsu,dk4_er_t * erp)355 dk4path8_dup_change_suffix(
356 char const *srcname,
357 char const *newsu,
358 dk4_er_t *erp
359 )
360 {
361 dk4_er_t er;
362 char *sp;
363 char *back = NULL;
364 size_t lold;
365 size_t lsuff;
366 size_t lnew;
367
368 #if DK4_USE_ASSERT
369 assert(NULL != srcname);
370 assert(NULL != newsu);
371 #endif
372 if ((NULL == srcname) || (NULL == newsu)) {
373 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
374 goto finished;
375 }
376 sp = dk4path8_get_suffix(srcname, NULL);
377 lold = strlen(srcname);
378 lsuff = 0;
379 if (NULL != sp) {
380 lsuff = strlen(sp);
381 }
382 if (lsuff > lold) {
383 /* BUG */
384 dk4error_set_simple_error_code(erp, DK4_E_BUG);
385 goto finished;
386 }
387 lold -= lsuff;
388 lsuff = strlen(newsu);
389 dk4error_init(&er);
390 lnew = dk4ma_size_t_add(lold, lsuff, &er);
391 lnew = dk4ma_size_t_add(lnew, 1, &er);
392 if (DK4_E_NONE != er.ec) {
393 dk4error_copy(erp, &er);
394 goto finished;
395 }
396 back = dk4mem_new(char,lnew,erp);
397 if (NULL == back) {
398 goto finished;
399 }
400 /* 2018-04-04 Bugfix
401 The new file name may be shorter than the original
402 file name, so we must not copy the original name
403 into the new buffer!
404 */
405 #if 0
406 /* 2018-04-04 Performance
407 Performance should be better using strncpy.
408 */
409 for (i = 0; i < lold; i++) { back[i] = srcname[i]; }
410 #endif
411 #if 0
412 strncpy(back, srcname, lold);
413 #endif
414 DK4_MEMCPY(back,srcname,lold);
415 back[lold] = '\0';
416 strcat(back, newsu);
417 finished:
418 return back;
419 }
420
421
422
423 size_t
dk4path8_concatenate_size(char const * dirname,char const * filename,dk4_er_t * erp)424 dk4path8_concatenate_size(
425 char const *dirname,
426 char const *filename,
427 dk4_er_t *erp
428 )
429 {
430 dk4_er_t er; /* Test for math overflow */
431 size_t back = 0; /* Function result */
432 size_t sldir = 0; /* Length of dirname */
433 size_t slfil = 0; /* Length of filename */
434 size_t toadd = 2; /* Path separator and finalizer byte */
435
436 #if DK4_USE_ASSERT
437 assert(NULL != dirname);
438 assert(NULL != filename);
439 #endif
440 if ((NULL != dirname) && (NULL != filename)) {
441 sldir = dk4str8_len(dirname);
442 slfil = dk4str8_len(filename);
443 if (0 < sldir) {
444 if (*(dk4path8_kw[0]) == dirname[sldir - 1]) { toadd = 1; }
445 }
446 dk4error_init(&er);
447 back = dk4ma_size_t_add( dk4ma_size_t_add(sldir, slfil, &er), toadd, &er );
448 if (DK4_E_NONE != er.ec) {
449 dk4error_copy(erp, &er);
450 back = 0;
451 }
452 }
453 else {
454 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
455 }
456
457 return back;
458 }
459
460
461
462 int
dk4path8_concatenate_buffer(char * buffer,size_t szbuf,char const * dirn,char const * filen,dk4_er_t * erp)463 dk4path8_concatenate_buffer(
464 char *buffer,
465 size_t szbuf,
466 char const *dirn,
467 char const *filen,
468 dk4_er_t *erp
469 )
470 {
471 size_t sld;
472 int back = 0;
473 int sep = 1;
474
475 #if DK4_USE_ASSERT
476 assert(NULL != buffer);
477 assert(0 < szbuf);
478 assert(NULL != dirn);
479 assert(NULL != filen);
480 #endif
481 if ((NULL != buffer) && (NULL != dirn) && (NULL != filen) && (0 != szbuf)) {
482 sld = dk4str8_len(dirn);
483 if (0 < sld) { if (dirn[sld - 1] == *(dk4path8_kw[0])) { sep = 0; } }
484 back = dk4str8_cpy_s(buffer, szbuf, dirn, erp);
485 if (0 != back) {
486 if (0 != sep) {
487 back = dk4str8_cat_s(buffer, szbuf, dk4path8_kw[0], erp);
488 }
489 }
490 if (0 != back) {
491 back = dk4str8_cat_s(buffer, szbuf, filen, erp);
492 }
493 }
494 else {
495 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
496 }
497 if ((0 == back) && (NULL != buffer) && (0 < szbuf)) { buffer[0] = '\0'; }
498
499 return back;
500 }
501
502
503
504 char *
dk4path8_concatenate_new(char const * dirn,char const * filen,dk4_er_t * erp)505 dk4path8_concatenate_new(
506 char const *dirn,
507 char const *filen,
508 dk4_er_t *erp
509 )
510 {
511 char *back = NULL;
512 size_t bl = 0;
513
514 #if DK4_USE_ASSERT
515 assert(NULL != dirn);
516 assert(NULL != filen);
517 #endif
518 if ((NULL != dirn) && (NULL != filen)) {
519 bl = dk4path8_concatenate_size(dirn, filen, erp);
520 if (0 != bl) {
521 back = dk4mem_new(char,bl,erp);
522 if (NULL != back) {
523 if (0 == dk4path8_concatenate_buffer(back, bl, dirn, filen, erp)) {
524 dk4mem_free(back);
525 back = NULL;
526 }
527 #if TRACE_DEBUG
528 if (NULL != back) {
529
530 }
531 #endif
532 }
533 }
534 }
535 else {
536 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
537 }
538
539 return back;
540 }
541
542