gwenhywfar  5.10.1
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 
47 static void *GWEN_Path_AppendPathElement(const char *entry, void *data, unsigned int flags);
48 static void _getPathBetween(const char *path1, const char *path2, GWEN_BUFFER *diffBuf);
49 
50 
51 
52 /* ------------------------------------------------------------------------------------------------
53  * implementations
54  * ------------------------------------------------------------------------------------------------
55  */
56 
57 
58 
59 
60 void *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) {
86  GWEN_Buffer_Reset(buf1);
87 
88  flags=origflags &
91 
92  /* copy element into buffer */
93  if (startAtRoot) {
94  GWEN_Buffer_AppendByte(buf1, '/');
95  flags|=GWEN_PATH_FLAGS_ROOT;
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 */
119  flags|=GWEN_PATH_FLAGS_LAST;
120  }
121  } /* if *path */
122  else {
123  /* path ends here with #0 */
124  flags|=GWEN_PATH_FLAGS_LAST;
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\"",
193  GWEN_Buffer_GetStart(buf1));
194  GWEN_Buffer_free(buf1);
195  return 0;
196  }
197  }
198  DBG_DEBUG(GWEN_LOGDOMAIN, "Successfully handled element \"%s\"",
199  GWEN_Buffer_GetStart(buf1));
200  if (startAtRoot)
201  startAtRoot=0;
202  } /* while (*path) */
203 
204  GWEN_Buffer_free(buf1);
205  return data;
206 }
207 
208 
209 
210 void *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, '/');
248  flags|=GWEN_PATH_FLAGS_ROOT;
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 */
300  flags|=GWEN_PATH_FLAGS_LAST;
301  }
302  } /* if *path */
303  else {
304  /* path ends here with #0 */
305  flags|=GWEN_PATH_FLAGS_LAST;
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\"",
374  GWEN_Buffer_GetStart(buf1));
375  GWEN_Buffer_free(buf1);
376  return 0;
377  }
378  }
379  DBG_DEBUG(GWEN_LOGDOMAIN, "Successfully handled element \"%s\"",
380  GWEN_Buffer_GetStart(buf1));
381  if (startAtRoot)
382  startAtRoot=0;
383  } /* while (*path) */
384 
385  GWEN_Buffer_free(buf1);
386  return data;
387 }
388 
389 
390 
391 
392 void *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 
409 int 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 
427 int 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 
465 void _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_STRINGLIST * GWEN_StringList_fromString2(const char *str, const char *delimiters, int checkDouble, uint32_t flags)
Definition: stringlist.c:801
void * GWEN_Path_Handle(const char *path, void *data, uint32_t flags, GWEN_PATHHANDLERPTR elementFunction)
Definition: path.c:60
#define GWEN_PATH_FLAGS_ESCAPE
Definition: path.h:121
char * GWEN_Buffer_GetStart(const GWEN_BUFFER *bf)
Definition: buffer.c:235
struct GWEN_STRINGLISTENTRYSTRUCT GWEN_STRINGLISTENTRY
Definition: stringlist.h:53
int GWEN_Buffer_AllocRoom(GWEN_BUFFER *bf, uint32_t size)
Definition: buffer.c:285
uint32_t GWEN_Buffer_GetUsedBytes(const GWEN_BUFFER *bf)
Definition: buffer.c:277
#define GWEN_PATH_FLAGS_CONVERT_LAST
Definition: path.h:133
void GWEN_Buffer_SetStep(GWEN_BUFFER *bf, uint32_t step)
Definition: buffer.c:713
#define GWEN_PATH_FLAGS_TOLERANT_ESCAPE
Definition: path.h:127
int GWEN_Text_EscapeToBufferTolerant(const char *src, GWEN_BUFFER *buf)
Definition: text.c:1471
#define GWEN_PATH_FLAGS_INTERNAL
Definition: path.h:159
void *(* GWEN_PATHIDXHANDLERPTR)(const char *entry, void *data, int idx, uint32_t flags)
Definition: path.h:184
int GWEN_Path_Convert(const char *path, GWEN_BUFFER *buffer, uint32_t flags)
Definition: path.c:409
#define GWEN_LOGDOMAIN
Definition: logger.h:35
GWEN_BUFFER * GWEN_Buffer_new(char *buffer, uint32_t size, uint32_t used, int take)
Definition: buffer.c:42
int GWEN_Text_UnescapeToBufferTolerant(const char *src, GWEN_BUFFER *buf)
Definition: text.c:1515
char * GWEN_Buffer_GetPosPointer(const GWEN_BUFFER *bf)
Definition: buffer.c:549
GWEN_STRINGLISTENTRY * GWEN_StringList_FirstEntry(const GWEN_STRINGLIST *sl)
Definition: stringlist.c:390
void GWEN_Buffer_Reset(GWEN_BUFFER *bf)
Definition: buffer.c:650
const char * GWEN_StringListEntry_Data(const GWEN_STRINGLISTENTRY *se)
Definition: stringlist.c:406
#define GWEN_PATH_FLAGS_LAST
Definition: path.h:166
void GWEN_StringList_free(GWEN_STRINGLIST *sl)
Definition: stringlist.c:62
#define GWEN_PATH_FLAGS_ROOT
Definition: path.h:174
#define DBG_DEBUG(dbg_logger, format, args...)
Definition: debug.h:214
#define GWEN_PATH_FLAGS_UNESCAPE
Definition: path.h:124
#define GWEN_PATH_FLAGS_VARIABLE
Definition: path.h:111
int GWEN_Text_EscapeToBuffer(const char *src, GWEN_BUFFER *buf)
Definition: text.c:1376
static void _getPathBetween(const char *path1, const char *path2, GWEN_BUFFER *diffBuf)
Definition: path.c:465
void *(* GWEN_PATHHANDLERPTR)(const char *entry, void *data, uint32_t flags)
Definition: path.h:180
struct GWEN_STRINGLISTSTRUCT GWEN_STRINGLIST
Definition: stringlist.h:56
int GWEN_Buffer_AppendByte(GWEN_BUFFER *bf, char c)
Definition: buffer.c:394
void GWEN_Buffer_free(GWEN_BUFFER *bf)
Definition: buffer.c:89
struct GWEN_BUFFER GWEN_BUFFER
A dynamically resizeable text buffer.
Definition: buffer.h:38
int GWEN_Text_UnescapeToBuffer(const char *src, GWEN_BUFFER *buf)
Definition: text.c:1411
#define GWEN_PATH_FLAGS_CHECKROOT
Definition: path.h:142
unsigned int GWEN_StringList_Count(const GWEN_STRINGLIST *sl)
Definition: stringlist.c:427
#define DBG_ERROR(dbg_logger, format, args...)
Definition: debug.h:97
GWEN_STRINGLISTENTRY * GWEN_StringListEntry_Next(const GWEN_STRINGLISTENTRY *se)
Definition: stringlist.c:398
int GWEN_Path_GetPathBetween(const char *path1, const char *path2, GWEN_BUFFER *diffBuf)
Definition: path.c:427
static void * GWEN_Path_AppendPathElement(const char *entry, void *data, unsigned int flags)
Definition: path.c:392
#define DBG_INFO(dbg_logger, format, args...)
Definition: debug.h:181
#define GWEN_TEXT_FLAGS_DEL_QUOTES
Definition: text.h:49
#define GWEN_PATH_FLAGS_NO_IDX
Definition: path.h:148
void * GWEN_Path_HandleWithIdx(const char *path, void *data, uint32_t flags, GWEN_PATHIDXHANDLERPTR elementFunction)
Definition: path.c:210
#define GWEN_TEXT_FLAGS_CHECK_BACKSLASH
Definition: text.h:50
int GWEN_Buffer_AppendString(GWEN_BUFFER *bf, const char *buffer)
Definition: buffer.c:989
void GWEN_StringList_RemoveCommonFirstEntries(GWEN_STRINGLIST *sl1, GWEN_STRINGLIST *sl2)
Definition: stringlist.c:867