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