gwenhywfar  5.4.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 <ctype.h>
36 
37 
38 
39 /* ------------------------------------------------------------------------------------------------
40  * forward declarations
41  * ------------------------------------------------------------------------------------------------
42  */
43 
44 
45 static void *GWEN_Path_AppendPathElement(const char *entry, void *data, unsigned int flags);
46 
47 
48 /* ------------------------------------------------------------------------------------------------
49  * implementations
50  * ------------------------------------------------------------------------------------------------
51  */
52 
53 
54 
55 
56 void *GWEN_Path_Handle(const char *path,
57  void *data,
58  uint32_t flags,
59  GWEN_PATHHANDLERPTR elementFunction)
60 {
61  GWEN_BUFFER *buf1;
62  unsigned int origflags;
63  int startAtRoot;
64 
65  origflags=flags;
66 
67  buf1=GWEN_Buffer_new(0, 128, 0, 1);
68 
69  /* skip leading blanks */
70  while (*path && isspace((int)*path))
71  path++;
72 
73  /* skip leading slashes */
74  startAtRoot=0;
75  while (*path && (*path=='/' || *path=='\\')) {
76  if (origflags & GWEN_PATH_FLAGS_CHECKROOT)
77  startAtRoot=1;
78  path++;
79  } /* while */
80 
81  while (*path) {
82  GWEN_Buffer_Reset(buf1);
83 
84  flags=origflags &
87 
88  /* copy element into buffer */
89  if (startAtRoot) {
90  GWEN_Buffer_AppendByte(buf1, '/');
91  flags|=GWEN_PATH_FLAGS_ROOT;
92  }
93  while (*path && !(*path=='/' || *path=='\\'))
94  GWEN_Buffer_AppendByte(buf1, *(path++));
95 
96  /* check for group or entry */
97  if (*path) {
98  /* skip slashes */
99  path++;
100  while (*path && (*path=='/' || *path=='\\'))
101  path++;
102 
103  /* check if delimiter is followed by #0 */
104  if (!*path) {
105  /* it is so do some more tests */
106  if (origflags & GWEN_PATH_FLAGS_VARIABLE) {
107  /* a trailing slash indicates that the current entry is
108  * supposed to be a group. If the flags indicate that an entry
109  * is to be found then this would be an error, because the path
110  * ends in a group instead of an entry */
111  DBG_DEBUG(GWEN_LOGDOMAIN, "Path ends with a group while an entry is wanted");
112  return 0;
113  }
114  /* other wise simply mark this element as the last one */
115  flags|=GWEN_PATH_FLAGS_LAST;
116  }
117  } /* if *path */
118  else {
119  /* path ends here with #0 */
120  flags|=GWEN_PATH_FLAGS_LAST;
121  if (origflags & GWEN_PATH_FLAGS_VARIABLE) {
122  /* path ends with #0, caller wants a variable so this
123  * last element is one */
125  }
126  }
127 
128  /* escape or unescape if wanted */
129  if (!(flags & GWEN_PATH_FLAGS_LAST) ||
130  ((flags & GWEN_PATH_FLAGS_LAST) &&
131  (flags & GWEN_PATH_FLAGS_CONVERT_LAST))) {
132  if (flags & GWEN_PATH_FLAGS_ESCAPE) {
133  GWEN_BUFFER *buf2;
134  const char *p;
135  int rv;
136 
137  buf2=GWEN_Buffer_new(0, 64, 0, 1);
138  GWEN_Buffer_SetStep(buf2, 128);
139  p=GWEN_Buffer_GetStart(buf1);
140  if (startAtRoot) {
141  p++;
142  GWEN_Buffer_AppendByte(buf2, '/');
143  }
146  else
147  rv=GWEN_Text_EscapeToBuffer(p, buf2);
148  if (rv) {
149  DBG_ERROR(GWEN_LOGDOMAIN, "Could not escape path element");
150  GWEN_Buffer_free(buf2);
151  GWEN_Buffer_free(buf1);
152  return 0;
153  }
154  GWEN_Buffer_free(buf1);
155  buf1=buf2;
156  }
157  else if (flags & GWEN_PATH_FLAGS_UNESCAPE) {
158  GWEN_BUFFER *buf2;
159  const char *p;
160  int rv;
161 
162  buf2=GWEN_Buffer_new(0, 64, 0, 1);
163  GWEN_Buffer_SetStep(buf2, 128);
164  p=GWEN_Buffer_GetStart(buf1);
165  if (startAtRoot) {
166  p++;
167  GWEN_Buffer_AppendByte(buf2, '/');
168  }
171  else
172  rv=GWEN_Text_UnescapeToBuffer(p, buf2);
173  if (rv) {
174  DBG_ERROR(GWEN_LOGDOMAIN, "Could not unescape path element");
175  GWEN_Buffer_free(buf2);
176  GWEN_Buffer_free(buf1);
177  return 0;
178  }
179  GWEN_Buffer_free(buf1);
180  buf1=buf2;
181  }
182  }
183 
184  /* call function */
185  if (elementFunction) {
186  data=(elementFunction)(GWEN_Buffer_GetStart(buf1), data, flags);
187  if (!data) {
188  DBG_DEBUG(GWEN_LOGDOMAIN, "Error on path element \"%s\"",
189  GWEN_Buffer_GetStart(buf1));
190  GWEN_Buffer_free(buf1);
191  return 0;
192  }
193  }
194  DBG_DEBUG(GWEN_LOGDOMAIN, "Successfully handled element \"%s\"",
195  GWEN_Buffer_GetStart(buf1));
196  if (startAtRoot)
197  startAtRoot=0;
198  } /* while (*path) */
199 
200  GWEN_Buffer_free(buf1);
201  return data;
202 }
203 
204 
205 
206 void *GWEN_Path_HandleWithIdx(const char *path,
207  void *data,
208  uint32_t flags,
209  GWEN_PATHIDXHANDLERPTR elementFunction)
210 {
211  GWEN_BUFFER *buf1;
212  unsigned int origflags;
213  int startAtRoot;
214 
215  origflags=flags;
216 
217  buf1=GWEN_Buffer_new(0, 128, 0, 1);
218 
219  /* skip leading blanks */
220  while (*path && isspace((int)*path))
221  path++;
222 
223  /* skip leading slashes */
224  startAtRoot=0;
225  while (*path && (*path=='/' || *path=='\\')) {
226  if (origflags & GWEN_PATH_FLAGS_CHECKROOT)
227  startAtRoot=1;
228  path++;
229  } /* while */
230 
231  while (*path) {
232  int idx;
233 
234  idx=0;
235  GWEN_Buffer_Reset(buf1);
236 
237  flags=origflags &
240 
241  /* copy element into buffer */
242  if (startAtRoot) {
243  GWEN_Buffer_AppendByte(buf1, '/');
244  flags|=GWEN_PATH_FLAGS_ROOT;
245  }
246  while (*path && !(*path=='/' || *path=='\\'))
247  GWEN_Buffer_AppendByte(buf1, *(path++));
248 
249  /* now buffer contains the element, check for index */
250  if (!(flags & GWEN_PATH_FLAGS_NO_IDX)) {
251  char *p;
252 
253  p=strchr(GWEN_Buffer_GetStart(buf1), '[');
254  if (p) {
255  char *p2;
256  int x;
257 
258  *p=0;
259  p++;
260  p2=strchr(p, ']');
261  if (!p2) {
262  DBG_ERROR(GWEN_LOGDOMAIN, "Closing bracket missing");
263  GWEN_Buffer_free(buf1);
264  return 0;
265  }
266  *p2=0;
267  if (sscanf(p, "%d", &x)!=1) {
268  DBG_ERROR(GWEN_LOGDOMAIN, "Bad or missing index in element (%s)",
269  p);
270  GWEN_Buffer_free(buf1);
271  return 0;
272  }
273  idx=x;
274  }
275  }
276 
277  /* check for group or entry */
278  if (*path) {
279  /* skip slashes */
280  path++;
281  while (*path && (*path=='/' || *path=='\\'))
282  path++;
283 
284  /* check if delimiter is followed by #0 */
285  if (!*path) {
286  /* it is so do some more tests */
287  if (origflags & GWEN_PATH_FLAGS_VARIABLE) {
288  /* a trailing slash indicates that the current entry is
289  * supposed to be a group. If the flags indicate that an entry
290  * is to be found then this would be an error, because the path
291  * ends in a group instead of an entry */
292  DBG_DEBUG(GWEN_LOGDOMAIN, "Path ends with a group while an entry is wanted");
293  return 0;
294  }
295  /* other wise simply mark this element as the last one */
296  flags|=GWEN_PATH_FLAGS_LAST;
297  }
298  } /* if *path */
299  else {
300  /* path ends here with #0 */
301  flags|=GWEN_PATH_FLAGS_LAST;
302  if (origflags & GWEN_PATH_FLAGS_VARIABLE) {
303  /* path ends with #0, caller wants a variable so this
304  * last element is one */
306  }
307  }
308 
309  /* escape or unescape if wanted */
310  if (!(flags & GWEN_PATH_FLAGS_LAST) ||
311  ((flags & GWEN_PATH_FLAGS_LAST) &&
312  (flags & GWEN_PATH_FLAGS_CONVERT_LAST))) {
313  if (flags & GWEN_PATH_FLAGS_ESCAPE) {
314  GWEN_BUFFER *buf2;
315  const char *p;
316  int rv;
317 
318  buf2=GWEN_Buffer_new(0, 64, 0, 1);
319  GWEN_Buffer_SetStep(buf2, 128);
320  p=GWEN_Buffer_GetStart(buf1);
321  if (startAtRoot) {
322  p++;
323  GWEN_Buffer_AppendByte(buf2, '/');
324  }
327  else
328  rv=GWEN_Text_EscapeToBuffer(p, buf2);
329  if (rv) {
330  DBG_ERROR(GWEN_LOGDOMAIN, "Could not escape path element");
331  GWEN_Buffer_free(buf2);
332  GWEN_Buffer_free(buf1);
333  return 0;
334  }
335  GWEN_Buffer_free(buf1);
336  buf1=buf2;
337  }
338  else if (flags & GWEN_PATH_FLAGS_UNESCAPE) {
339  GWEN_BUFFER *buf2;
340  const char *p;
341  int rv;
342 
343  buf2=GWEN_Buffer_new(0, 64, 0, 1);
344  GWEN_Buffer_SetStep(buf2, 128);
345  p=GWEN_Buffer_GetStart(buf1);
346  if (startAtRoot) {
347  p++;
348  GWEN_Buffer_AppendByte(buf2, '/');
349  }
352  else
353  rv=GWEN_Text_UnescapeToBuffer(p, buf2);
354  if (rv) {
355  DBG_ERROR(GWEN_LOGDOMAIN, "Could not unescape path element");
356  GWEN_Buffer_free(buf2);
357  GWEN_Buffer_free(buf1);
358  return 0;
359  }
360  GWEN_Buffer_free(buf1);
361  buf1=buf2;
362  }
363  }
364 
365  /* call function */
366  if (elementFunction) {
367  data=(elementFunction)(GWEN_Buffer_GetStart(buf1), data, idx, flags);
368  if (!data) {
369  DBG_DEBUG(GWEN_LOGDOMAIN, "Error on path element \"%s\"",
370  GWEN_Buffer_GetStart(buf1));
371  GWEN_Buffer_free(buf1);
372  return 0;
373  }
374  }
375  DBG_DEBUG(GWEN_LOGDOMAIN, "Successfully handled element \"%s\"",
376  GWEN_Buffer_GetStart(buf1));
377  if (startAtRoot)
378  startAtRoot=0;
379  } /* while (*path) */
380 
381  GWEN_Buffer_free(buf1);
382  return data;
383 }
384 
385 
386 
387 
388 void *GWEN_Path_AppendPathElement(const char *entry, void *data, unsigned int flags)
389 {
390  GWEN_BUFFER *ebuf;
391 
392  ebuf=(GWEN_BUFFER *)data;
393 
394  GWEN_Buffer_AppendString(ebuf, entry);
395  if (!(flags & GWEN_PATH_FLAGS_LAST) ||
396  !(flags & GWEN_PATH_FLAGS_VARIABLE))
397  GWEN_Buffer_AppendByte(ebuf, '/');
398  GWEN_Buffer_AllocRoom(ebuf, 1);
399  GWEN_Buffer_GetPosPointer(ebuf)[0]=0;
400  return data;
401 }
402 
403 
404 
405 int GWEN_Path_Convert(const char *path,
406  GWEN_BUFFER *buffer,
407  uint32_t flags)
408 {
409  void *p;
410 
411  p=GWEN_Path_Handle(path,
412  buffer,
413  flags,
415  if (!p) {
416  return -1;
417  }
418  return 0;
419 }
420 
421 
422 
423 
424 
425 
426 
void * GWEN_Path_Handle(const char *path, void *data, uint32_t flags, GWEN_PATHHANDLERPTR elementFunction)
Definition: path.c:56
#define GWEN_PATH_FLAGS_ESCAPE
Definition: path.h:121
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
#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:405
#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
void GWEN_Buffer_Reset(GWEN_BUFFER *bf)
Definition: buffer.c:650
#define GWEN_PATH_FLAGS_LAST
Definition: path.h:166
#define GWEN_PATH_FLAGS_ROOT
Definition: path.h:174
#define DBG_DEBUG(dbg_logger, format, args...)
Definition: debug.h:209
#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
void *(* GWEN_PATHHANDLERPTR)(const char *entry, void *data, uint32_t flags)
Definition: path.h:180
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
#define DBG_ERROR(dbg_logger, format, args...)
Definition: debug.h:97
static void * GWEN_Path_AppendPathElement(const char *entry, void *data, unsigned int flags)
Definition: path.c:388
#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:206
int GWEN_Buffer_AppendString(GWEN_BUFFER *bf, const char *buffer)
Definition: buffer.c:989