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