gwenhywfar 5.12.0
path.c
Go to the documentation of this file.
1/***************************************************************************
2 begin : Tue Sep 09 2003
3 copyright : (C) 2019 by Martin Preuss
4 email : martin@libchipcard.de
5
6 ***************************************************************************
7 * *
8 * This library is free software; you can redistribute it and/or *
9 * modify it under the terms of the GNU Lesser General Public *
10 * License as published by the Free Software Foundation; either *
11 * version 2.1 of the License, or (at your option) any later version. *
12 * *
13 * This library is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
16 * Lesser General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU Lesser General Public *
19 * License along with this library; if not, write to the Free Software *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
21 * MA 02111-1307 USA *
22 * *
23 ***************************************************************************/
24
25#ifdef HAVE_CONFIG_H
26# include <config.h>
27#endif
28
29#define DISABLE_DEBUGLOG
30
31#include "path.h"
32#include "gwenhywfar/debug.h"
33#include "gwenhywfar/misc.h"
34#include "gwenhywfar/text.h"
35#include "gwenhywfar/stringlist.h"
36
37#include <ctype.h>
38
39
40
41/* ------------------------------------------------------------------------------------------------
42 * forward declarations
43 * ------------------------------------------------------------------------------------------------
44 */
45
46
47static void *GWEN_Path_AppendPathElement(const char *entry, void *data, unsigned int flags);
48static void _getPathBetween(const char *path1, const char *path2, GWEN_BUFFER *diffBuf);
49
50
51
52/* ------------------------------------------------------------------------------------------------
53 * implementations
54 * ------------------------------------------------------------------------------------------------
55 */
56
57
58
59
60void *GWEN_Path_Handle(const char *path,
61 void *data,
62 uint32_t flags,
63 GWEN_PATHHANDLERPTR elementFunction)
64{
65 GWEN_BUFFER *buf1;
66 unsigned int origflags;
67 int startAtRoot;
68
69 origflags=flags;
70
71 buf1=GWEN_Buffer_new(0, 128, 0, 1);
72
73 /* skip leading blanks */
74 while (*path && isspace((int)*path))
75 path++;
76
77 /* skip leading slashes */
78 startAtRoot=0;
79 while (*path && (*path=='/' || *path=='\\')) {
80 if (origflags & GWEN_PATH_FLAGS_CHECKROOT)
81 startAtRoot=1;
82 path++;
83 } /* while */
84
85 while (*path) {
87
88 flags=origflags &
91
92 /* copy element into buffer */
93 if (startAtRoot) {
94 GWEN_Buffer_AppendByte(buf1, '/');
96 }
97 while (*path && !(*path=='/' || *path=='\\'))
98 GWEN_Buffer_AppendByte(buf1, *(path++));
99
100 /* check for group or entry */
101 if (*path) {
102 /* skip slashes */
103 path++;
104 while (*path && (*path=='/' || *path=='\\'))
105 path++;
106
107 /* check if delimiter is followed by #0 */
108 if (!*path) {
109 /* it is so do some more tests */
110 if (origflags & GWEN_PATH_FLAGS_VARIABLE) {
111 /* a trailing slash indicates that the current entry is
112 * supposed to be a group. If the flags indicate that an entry
113 * is to be found then this would be an error, because the path
114 * ends in a group instead of an entry */
115 DBG_DEBUG(GWEN_LOGDOMAIN, "Path ends with a group while an entry is wanted");
116 return 0;
117 }
118 /* other wise simply mark this element as the last one */
120 }
121 } /* if *path */
122 else {
123 /* path ends here with #0 */
125 if (origflags & GWEN_PATH_FLAGS_VARIABLE) {
126 /* path ends with #0, caller wants a variable so this
127 * last element is one */
129 }
130 }
131
132 /* escape or unescape if wanted */
133 if (!(flags & GWEN_PATH_FLAGS_LAST) ||
134 ((flags & GWEN_PATH_FLAGS_LAST) &&
135 (flags & GWEN_PATH_FLAGS_CONVERT_LAST))) {
136 if (flags & GWEN_PATH_FLAGS_ESCAPE) {
137 GWEN_BUFFER *buf2;
138 const char *p;
139 int rv;
140
141 buf2=GWEN_Buffer_new(0, 64, 0, 1);
142 GWEN_Buffer_SetStep(buf2, 128);
143 p=GWEN_Buffer_GetStart(buf1);
144 if (startAtRoot) {
145 p++;
146 GWEN_Buffer_AppendByte(buf2, '/');
147 }
150 else
151 rv=GWEN_Text_EscapeToBuffer(p, buf2);
152 if (rv) {
153 DBG_ERROR(GWEN_LOGDOMAIN, "Could not escape path element");
154 GWEN_Buffer_free(buf2);
155 GWEN_Buffer_free(buf1);
156 return 0;
157 }
158 GWEN_Buffer_free(buf1);
159 buf1=buf2;
160 }
161 else if (flags & GWEN_PATH_FLAGS_UNESCAPE) {
162 GWEN_BUFFER *buf2;
163 const char *p;
164 int rv;
165
166 buf2=GWEN_Buffer_new(0, 64, 0, 1);
167 GWEN_Buffer_SetStep(buf2, 128);
168 p=GWEN_Buffer_GetStart(buf1);
169 if (startAtRoot) {
170 p++;
171 GWEN_Buffer_AppendByte(buf2, '/');
172 }
175 else
176 rv=GWEN_Text_UnescapeToBuffer(p, buf2);
177 if (rv) {
178 DBG_ERROR(GWEN_LOGDOMAIN, "Could not unescape path element");
179 GWEN_Buffer_free(buf2);
180 GWEN_Buffer_free(buf1);
181 return 0;
182 }
183 GWEN_Buffer_free(buf1);
184 buf1=buf2;
185 }
186 }
187
188 /* call function */
189 if (elementFunction) {
190 data=(elementFunction)(GWEN_Buffer_GetStart(buf1), data, flags);
191 if (!data) {
192 DBG_DEBUG(GWEN_LOGDOMAIN, "Error on path element \"%s\"",
194 GWEN_Buffer_free(buf1);
195 return 0;
196 }
197 }
198 DBG_DEBUG(GWEN_LOGDOMAIN, "Successfully handled element \"%s\"",
200 if (startAtRoot)
201 startAtRoot=0;
202 } /* while (*path) */
203
204 GWEN_Buffer_free(buf1);
205 return data;
206}
207
208
209
210void *GWEN_Path_HandleWithIdx(const char *path,
211 void *data,
212 uint32_t flags,
213 GWEN_PATHIDXHANDLERPTR elementFunction)
214{
215 GWEN_BUFFER *buf1;
216 unsigned int origflags;
217 int startAtRoot;
218
219 origflags=flags;
220
221 buf1=GWEN_Buffer_new(0, 128, 0, 1);
222
223 /* skip leading blanks */
224 while (*path && isspace((int)*path))
225 path++;
226
227 /* skip leading slashes */
228 startAtRoot=0;
229 while (*path && (*path=='/' || *path=='\\')) {
230 if (origflags & GWEN_PATH_FLAGS_CHECKROOT)
231 startAtRoot=1;
232 path++;
233 } /* while */
234
235 while (*path) {
236 int idx;
237
238 idx=0;
239 GWEN_Buffer_Reset(buf1);
240
241 flags=origflags &
244
245 /* copy element into buffer */
246 if (startAtRoot) {
247 GWEN_Buffer_AppendByte(buf1, '/');
249 }
250 while (*path && !(*path=='/' || *path=='\\'))
251 GWEN_Buffer_AppendByte(buf1, *(path++));
252
253 /* now buffer contains the element, check for index */
254 if (!(flags & GWEN_PATH_FLAGS_NO_IDX)) {
255 char *p;
256
257 p=strchr(GWEN_Buffer_GetStart(buf1), '[');
258 if (p) {
259 char *p2;
260 int x;
261
262 *p=0;
263 p++;
264 p2=strchr(p, ']');
265 if (!p2) {
266 DBG_ERROR(GWEN_LOGDOMAIN, "Closing bracket missing");
267 GWEN_Buffer_free(buf1);
268 return 0;
269 }
270 *p2=0;
271 if (sscanf(p, "%d", &x)!=1) {
272 DBG_ERROR(GWEN_LOGDOMAIN, "Bad or missing index in element (%s)",
273 p);
274 GWEN_Buffer_free(buf1);
275 return 0;
276 }
277 idx=x;
278 }
279 }
280
281 /* check for group or entry */
282 if (*path) {
283 /* skip slashes */
284 path++;
285 while (*path && (*path=='/' || *path=='\\'))
286 path++;
287
288 /* check if delimiter is followed by #0 */
289 if (!*path) {
290 /* it is so do some more tests */
291 if (origflags & GWEN_PATH_FLAGS_VARIABLE) {
292 /* a trailing slash indicates that the current entry is
293 * supposed to be a group. If the flags indicate that an entry
294 * is to be found then this would be an error, because the path
295 * ends in a group instead of an entry */
296 DBG_DEBUG(GWEN_LOGDOMAIN, "Path ends with a group while an entry is wanted");
297 return 0;
298 }
299 /* other wise simply mark this element as the last one */
301 }
302 } /* if *path */
303 else {
304 /* path ends here with #0 */
306 if (origflags & GWEN_PATH_FLAGS_VARIABLE) {
307 /* path ends with #0, caller wants a variable so this
308 * last element is one */
310 }
311 }
312
313 /* escape or unescape if wanted */
314 if (!(flags & GWEN_PATH_FLAGS_LAST) ||
315 ((flags & GWEN_PATH_FLAGS_LAST) &&
316 (flags & GWEN_PATH_FLAGS_CONVERT_LAST))) {
317 if (flags & GWEN_PATH_FLAGS_ESCAPE) {
318 GWEN_BUFFER *buf2;
319 const char *p;
320 int rv;
321
322 buf2=GWEN_Buffer_new(0, 64, 0, 1);
323 GWEN_Buffer_SetStep(buf2, 128);
324 p=GWEN_Buffer_GetStart(buf1);
325 if (startAtRoot) {
326 p++;
327 GWEN_Buffer_AppendByte(buf2, '/');
328 }
331 else
332 rv=GWEN_Text_EscapeToBuffer(p, buf2);
333 if (rv) {
334 DBG_ERROR(GWEN_LOGDOMAIN, "Could not escape path element");
335 GWEN_Buffer_free(buf2);
336 GWEN_Buffer_free(buf1);
337 return 0;
338 }
339 GWEN_Buffer_free(buf1);
340 buf1=buf2;
341 }
342 else if (flags & GWEN_PATH_FLAGS_UNESCAPE) {
343 GWEN_BUFFER *buf2;
344 const char *p;
345 int rv;
346
347 buf2=GWEN_Buffer_new(0, 64, 0, 1);
348 GWEN_Buffer_SetStep(buf2, 128);
349 p=GWEN_Buffer_GetStart(buf1);
350 if (startAtRoot) {
351 p++;
352 GWEN_Buffer_AppendByte(buf2, '/');
353 }
356 else
357 rv=GWEN_Text_UnescapeToBuffer(p, buf2);
358 if (rv) {
359 DBG_ERROR(GWEN_LOGDOMAIN, "Could not unescape path element");
360 GWEN_Buffer_free(buf2);
361 GWEN_Buffer_free(buf1);
362 return 0;
363 }
364 GWEN_Buffer_free(buf1);
365 buf1=buf2;
366 }
367 }
368
369 /* call function */
370 if (elementFunction) {
371 data=(elementFunction)(GWEN_Buffer_GetStart(buf1), data, idx, flags);
372 if (!data) {
373 DBG_DEBUG(GWEN_LOGDOMAIN, "Error on path element \"%s\"",
375 GWEN_Buffer_free(buf1);
376 return 0;
377 }
378 }
379 DBG_DEBUG(GWEN_LOGDOMAIN, "Successfully handled element \"%s\"",
381 if (startAtRoot)
382 startAtRoot=0;
383 } /* while (*path) */
384
385 GWEN_Buffer_free(buf1);
386 return data;
387}
388
389
390
391
392void *GWEN_Path_AppendPathElement(const char *entry, void *data, unsigned int flags)
393{
394 GWEN_BUFFER *ebuf;
395
396 ebuf=(GWEN_BUFFER *)data;
397
398 GWEN_Buffer_AppendString(ebuf, entry);
399 if (!(flags & GWEN_PATH_FLAGS_LAST) ||
400 !(flags & GWEN_PATH_FLAGS_VARIABLE))
401 GWEN_Buffer_AppendByte(ebuf, '/');
402 GWEN_Buffer_AllocRoom(ebuf, 1);
403 GWEN_Buffer_GetPosPointer(ebuf)[0]=0;
404 return data;
405}
406
407
408
409int GWEN_Path_Convert(const char *path,
410 GWEN_BUFFER *buffer,
411 uint32_t flags)
412{
413 void *p;
414
415 p=GWEN_Path_Handle(path,
416 buffer,
417 flags,
419 if (!p) {
420 return -1;
421 }
422 return 0;
423}
424
425
426
427int GWEN_Path_GetPathBetween(const char *path1, const char *path2, GWEN_BUFFER *diffBuf)
428{
429 if (!(path1 && *path1)) {
430 if (path2 && *path2) {
431 GWEN_Buffer_AppendString(diffBuf, path2);
432 return 0;
433 }
434 else {
435 DBG_INFO(GWEN_LOGDOMAIN, "Both paths are NULL.");
436 return 0;
437 }
438 }
439
440 if (!(path2 && *path2)) {
441 GWEN_STRINGLIST *sl1;
442
444 if (sl1) {
445 int cnt;
446 int i;
447
448 cnt=GWEN_StringList_Count(sl1);
449 for (i=0; i<cnt; i++) {
450 if (i>0)
451 GWEN_Buffer_AppendString(diffBuf, "/");
452 GWEN_Buffer_AppendString(diffBuf, "..");
453 }
455 return 0;
456 }
457 }
458
459 _getPathBetween(path1, path2, diffBuf);
460 return 0;
461}
462
463
464
465void _getPathBetween(const char *path1, const char *path2, GWEN_BUFFER *diffBuf)
466{
467 GWEN_STRINGLIST *sl1;
468 GWEN_STRINGLIST *sl2;
470 int count;
471 int i;
472
475
477
478 count=GWEN_StringList_Count(sl1);
479 for (i=0; i<count; i++) {
480 if (GWEN_Buffer_GetUsedBytes(diffBuf))
481 GWEN_Buffer_AppendString(diffBuf, "/");
482 GWEN_Buffer_AppendString(diffBuf, "..");
483 }
485
487 while(se) {
488 const char *s;
489
491 if (s && *s) {
492 if (GWEN_Buffer_GetUsedBytes(diffBuf))
493 GWEN_Buffer_AppendString(diffBuf, "/");
494 GWEN_Buffer_AppendString(diffBuf, s);
495 }
496
498 }
500}
501
502
503
504
GWEN_BUFFER * GWEN_Buffer_new(char *buffer, uint32_t size, uint32_t used, int take)
Definition buffer.c:42
void GWEN_Buffer_SetStep(GWEN_BUFFER *bf, uint32_t step)
Definition buffer.c:716
void GWEN_Buffer_Reset(GWEN_BUFFER *bf)
Definition buffer.c:653
char * GWEN_Buffer_GetPosPointer(const GWEN_BUFFER *bf)
Definition buffer.c:548
void GWEN_Buffer_free(GWEN_BUFFER *bf)
Definition buffer.c:89
int GWEN_Buffer_AppendString(GWEN_BUFFER *bf, const char *buffer)
Definition buffer.c:992
uint32_t GWEN_Buffer_GetUsedBytes(const GWEN_BUFFER *bf)
Definition buffer.c:277
char * GWEN_Buffer_GetStart(const GWEN_BUFFER *bf)
Definition buffer.c:235
int GWEN_Buffer_AllocRoom(GWEN_BUFFER *bf, uint32_t size)
Definition buffer.c:285
int GWEN_Buffer_AppendByte(GWEN_BUFFER *bf, char c)
Definition buffer.c:393
#define DBG_INFO(dbg_logger, format,...)
Definition debug.h:181
#define DBG_ERROR(dbg_logger, format,...)
Definition debug.h:97
#define DBG_DEBUG(dbg_logger, format,...)
Definition debug.h:214
struct GWEN_BUFFER GWEN_BUFFER
A dynamically resizeable text buffer.
Definition buffer.h:38
#define GWEN_LOGDOMAIN
Definition logger.h:35
static void _getPathBetween(const char *path1, const char *path2, GWEN_BUFFER *diffBuf)
Definition path.c:465
void * GWEN_Path_HandleWithIdx(const char *path, void *data, uint32_t flags, GWEN_PATHIDXHANDLERPTR elementFunction)
Definition path.c:210
static void * GWEN_Path_AppendPathElement(const char *entry, void *data, unsigned int flags)
Definition path.c:392
int GWEN_Path_GetPathBetween(const char *path1, const char *path2, GWEN_BUFFER *diffBuf)
Definition path.c:427
void * GWEN_Path_Handle(const char *path, void *data, uint32_t flags, GWEN_PATHHANDLERPTR elementFunction)
Definition path.c:60
int GWEN_Path_Convert(const char *path, GWEN_BUFFER *buffer, uint32_t flags)
Definition path.c:409
#define GWEN_PATH_FLAGS_UNESCAPE
Definition path.h:124
#define GWEN_PATH_FLAGS_CHECKROOT
Definition path.h:142
void *(* GWEN_PATHHANDLERPTR)(const char *entry, void *data, uint32_t flags)
Definition path.h:180
#define GWEN_PATH_FLAGS_INTERNAL
Definition path.h:159
#define GWEN_PATH_FLAGS_NO_IDX
Definition path.h:148
#define GWEN_PATH_FLAGS_CONVERT_LAST
Definition path.h:133
#define GWEN_PATH_FLAGS_LAST
Definition path.h:166
#define GWEN_PATH_FLAGS_TOLERANT_ESCAPE
Definition path.h:127
#define GWEN_PATH_FLAGS_VARIABLE
Definition path.h:111
#define GWEN_PATH_FLAGS_ROOT
Definition path.h:174
#define GWEN_PATH_FLAGS_ESCAPE
Definition path.h:121
void *(* GWEN_PATHIDXHANDLERPTR)(const char *entry, void *data, int idx, uint32_t flags)
Definition path.h:184
void GWEN_StringList_free(GWEN_STRINGLIST *sl)
Definition stringlist.c:62
GWEN_STRINGLIST * GWEN_StringList_fromString2(const char *str, const char *delimiters, int checkDouble, uint32_t flags)
Definition stringlist.c:818
const char * GWEN_StringListEntry_Data(const GWEN_STRINGLISTENTRY *se)
Definition stringlist.c:406
GWEN_STRINGLISTENTRY * GWEN_StringListEntry_Next(const GWEN_STRINGLISTENTRY *se)
Definition stringlist.c:398
unsigned int GWEN_StringList_Count(const GWEN_STRINGLIST *sl)
Definition stringlist.c:427
void GWEN_StringList_RemoveCommonFirstEntries(GWEN_STRINGLIST *sl1, GWEN_STRINGLIST *sl2)
Definition stringlist.c:884
GWEN_STRINGLISTENTRY * GWEN_StringList_FirstEntry(const GWEN_STRINGLIST *sl)
Definition stringlist.c:390
struct GWEN_STRINGLISTENTRYSTRUCT GWEN_STRINGLISTENTRY
Definition stringlist.h:53
struct GWEN_STRINGLISTSTRUCT GWEN_STRINGLIST
Definition stringlist.h:56
int GWEN_Text_EscapeToBuffer(const char *src, GWEN_BUFFER *buf)
Definition text.c:1376
int GWEN_Text_EscapeToBufferTolerant(const char *src, GWEN_BUFFER *buf)
Definition text.c:1471
int GWEN_Text_UnescapeToBuffer(const char *src, GWEN_BUFFER *buf)
Definition text.c:1411
int GWEN_Text_UnescapeToBufferTolerant(const char *src, GWEN_BUFFER *buf)
Definition text.c:1515
#define GWEN_TEXT_FLAGS_DEL_QUOTES
Definition text.h:49
#define GWEN_TEXT_FLAGS_CHECK_BACKSLASH
Definition text.h:50