path.c

Go to the documentation of this file.
00001 /***************************************************************************
00002  begin       : Tue Sep 09 2003
00003  copyright   : (C) 2003 by Martin Preuss
00004  email       : martin@libchipcard.de
00005 
00006  ***************************************************************************
00007  *                                                                         *
00008  *   This library is free software; you can redistribute it and/or         *
00009  *   modify it under the terms of the GNU Lesser General Public            *
00010  *   License as published by the Free Software Foundation; either          *
00011  *   version 2.1 of the License, or (at your option) any later version.    *
00012  *                                                                         *
00013  *   This library is distributed in the hope that it will be useful,       *
00014  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00015  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00016  *   Lesser General Public License for more details.                       *
00017  *                                                                         *
00018  *   You should have received a copy of the GNU Lesser General Public      *
00019  *   License along with this library; if not, write to the Free Software   *
00020  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston,                 *
00021  *   MA  02111-1307  USA                                                   *
00022  *                                                                         *
00023  ***************************************************************************/
00024 
00025 #ifdef HAVE_CONFIG_H
00026 # include <config.h>
00027 #endif
00028 
00029 #define DISABLE_DEBUGLOG
00030 
00031 #include "path.h"
00032 #include "gwenhywfar/debug.h"
00033 #include "gwenhywfar/misc.h"
00034 #include "gwenhywfar/text.h"
00035 #include <ctype.h>
00036 
00037 
00038 
00039 void *GWEN_Path_Handle(const char *path,
00040                        void *data,
00041                        uint32_t flags,
00042                        GWEN_PATHHANDLERPTR elementFunction) {
00043   GWEN_BUFFER *buf1;
00044   int i;
00045   unsigned int origflags;
00046   int startAtRoot;
00047 
00048   origflags=flags;
00049 
00050   buf1=GWEN_Buffer_new(0, 128, 0, 1);
00051 
00052   /* skip leading blanks */
00053   while (*path && isspace((int)*path))
00054     path++;
00055 
00056   /* skip leading slashes */
00057   startAtRoot=0;
00058   while (*path && (*path=='/' || *path=='\\')) {
00059     if (origflags & GWEN_PATH_FLAGS_CHECKROOT)
00060       startAtRoot=1;
00061     path++;
00062   } /* while */
00063 
00064   while (*path) {
00065     GWEN_Buffer_Reset(buf1);
00066 
00067     flags=origflags &
00068       ~GWEN_PATH_FLAGS_INTERNAL &
00069       ~GWEN_PATH_FLAGS_VARIABLE;
00070 
00071     /* copy element into buffer */
00072     i=0;
00073     if (startAtRoot) {
00074       GWEN_Buffer_AppendByte(buf1, '/');
00075       flags|=GWEN_PATH_FLAGS_ROOT;
00076     }
00077     while (*path && !(*path=='/' || *path=='\\'))
00078       GWEN_Buffer_AppendByte(buf1, *(path++));
00079 
00080     /* check for group or entry */
00081     if (*path) {
00082       /* skip slashes */
00083       path++;
00084       while (*path && (*path=='/' || *path=='\\'))
00085         path++;
00086 
00087       /* check if delimiter is followed by #0 */
00088       if (!*path) {
00089         /* it is so do some more tests */
00090         if (origflags & GWEN_PATH_FLAGS_VARIABLE) {
00091           /* a trailing slash indicates that the current entry is
00092            * supposed to be a group. If the flags indicate that an entry
00093            * is to be found then this would be an error, because the path
00094            * ends in a group instead of an entry */
00095           DBG_DEBUG(GWEN_LOGDOMAIN, "Path ends with a group while an entry is wanted");
00096           return 0;
00097         }
00098         /* other wise simply mark this element as the last one */
00099         flags|=GWEN_PATH_FLAGS_LAST;
00100       }
00101     } /* if *path */
00102     else {
00103       /* path ends here with #0 */
00104       flags|=GWEN_PATH_FLAGS_LAST;
00105       if (origflags & GWEN_PATH_FLAGS_VARIABLE) {
00106         /* path ends with #0, caller wants a variable so this
00107          * last element is one */
00108         flags|=GWEN_PATH_FLAGS_VARIABLE;
00109       }
00110     }
00111 
00112     /* escape or unescape if wanted */
00113     if (!(flags & GWEN_PATH_FLAGS_LAST) ||
00114         ((flags & GWEN_PATH_FLAGS_LAST) &&
00115          (flags & GWEN_PATH_FLAGS_CONVERT_LAST))) {
00116       if (flags & GWEN_PATH_FLAGS_ESCAPE) {
00117         GWEN_BUFFER *buf2;
00118         const char *p;
00119         int rv;
00120 
00121         buf2=GWEN_Buffer_new(0, 64, 0, 1);
00122         GWEN_Buffer_SetStep(buf2, 128);
00123         p=GWEN_Buffer_GetStart(buf1);
00124         if (startAtRoot) {
00125           p++;
00126           GWEN_Buffer_AppendByte(buf2, '/');
00127         }
00128         if (flags & GWEN_PATH_FLAGS_TOLERANT_ESCAPE)
00129           rv=GWEN_Text_EscapeToBufferTolerant(p, buf2);
00130         else
00131           rv=GWEN_Text_EscapeToBuffer(p, buf2);
00132         if (rv) {
00133           DBG_ERROR(GWEN_LOGDOMAIN, "Could not escape path element");
00134           GWEN_Buffer_free(buf2);
00135           GWEN_Buffer_free(buf1);
00136           return 0;
00137         }
00138         GWEN_Buffer_free(buf1);
00139         buf1=buf2;
00140       }
00141       else if (flags & GWEN_PATH_FLAGS_UNESCAPE) {
00142         GWEN_BUFFER *buf2;
00143         const char *p;
00144         int rv;
00145 
00146         buf2=GWEN_Buffer_new(0, 64, 0, 1);
00147         GWEN_Buffer_SetStep(buf2, 128);
00148         p=GWEN_Buffer_GetStart(buf1);
00149         if (startAtRoot) {
00150           p++;
00151           GWEN_Buffer_AppendByte(buf2, '/');
00152         }
00153         if (flags & GWEN_PATH_FLAGS_TOLERANT_ESCAPE)
00154           rv=GWEN_Text_UnescapeToBufferTolerant(p, buf2);
00155         else
00156           rv=GWEN_Text_UnescapeToBuffer(p, buf2);
00157         if (rv) {
00158           DBG_ERROR(GWEN_LOGDOMAIN, "Could not unescape path element");
00159           GWEN_Buffer_free(buf2);
00160           GWEN_Buffer_free(buf1);
00161           return 0;
00162         }
00163         GWEN_Buffer_free(buf1);
00164         buf1=buf2;
00165       }
00166     }
00167 
00168     /* call function */
00169     if (elementFunction) {
00170       data=(elementFunction)(GWEN_Buffer_GetStart(buf1), data, flags);
00171       if (!data) {
00172         DBG_DEBUG(GWEN_LOGDOMAIN, "Error on path element \"%s\"",
00173                   GWEN_Buffer_GetStart(buf1));
00174         GWEN_Buffer_free(buf1);
00175         return 0;
00176       }
00177     }
00178     DBG_DEBUG(GWEN_LOGDOMAIN, "Successfully handled element \"%s\"",
00179               GWEN_Buffer_GetStart(buf1));
00180     if (startAtRoot)
00181       startAtRoot=0;
00182   } /* while (*path) */
00183 
00184   GWEN_Buffer_free(buf1);
00185   return data;
00186 }
00187 
00188 
00189 
00190 void *GWEN_Path_HandleWithIdx(const char *path,
00191                               void *data,
00192                               uint32_t flags,
00193                               GWEN_PATHIDXHANDLERPTR elementFunction) {
00194   GWEN_BUFFER *buf1;
00195   int i;
00196   unsigned int origflags;
00197   int startAtRoot;
00198 
00199   origflags=flags;
00200 
00201   buf1=GWEN_Buffer_new(0, 128, 0, 1);
00202 
00203   /* skip leading blanks */
00204   while (*path && isspace((int)*path))
00205     path++;
00206 
00207   /* skip leading slashes */
00208   startAtRoot=0;
00209   while (*path && (*path=='/' || *path=='\\')) {
00210     if (origflags & GWEN_PATH_FLAGS_CHECKROOT)
00211       startAtRoot=1;
00212     path++;
00213   } /* while */
00214 
00215   while (*path) {
00216     char *p;
00217     int idx;
00218 
00219     idx=0;
00220     GWEN_Buffer_Reset(buf1);
00221 
00222     flags=origflags &
00223       ~GWEN_PATH_FLAGS_INTERNAL &
00224       ~GWEN_PATH_FLAGS_VARIABLE;
00225 
00226     /* copy element into buffer */
00227     i=0;
00228     if (startAtRoot) {
00229       GWEN_Buffer_AppendByte(buf1, '/');
00230       flags|=GWEN_PATH_FLAGS_ROOT;
00231     }
00232     while (*path && !(*path=='/' || *path=='\\'))
00233       GWEN_Buffer_AppendByte(buf1, *(path++));
00234 
00235     /* now buffer contains the element, check for index */
00236     if (!(flags & GWEN_PATH_FLAGS_NO_IDX)) {
00237       p=strchr(GWEN_Buffer_GetStart(buf1), '[');
00238       if (p) {
00239         char *p2;
00240         int x;
00241 
00242         *p=0;
00243         p++;
00244         p2=strchr(p, ']');
00245         if (!p2) {
00246           DBG_ERROR(GWEN_LOGDOMAIN, "Closing bracket missing");
00247           GWEN_Buffer_free(buf1);
00248           return 0;
00249         }
00250         *p2=0;
00251         if (sscanf(p, "%d", &x)!=1) {
00252           DBG_ERROR(GWEN_LOGDOMAIN, "Bad or missing index in element (%s)",
00253                     p);
00254           GWEN_Buffer_free(buf1);
00255           return 0;
00256         }
00257         idx=x;
00258       }
00259     }
00260 
00261     /* check for group or entry */
00262     if (*path) {
00263       /* skip slashes */
00264       path++;
00265       while (*path && (*path=='/' || *path=='\\'))
00266         path++;
00267 
00268       /* check if delimiter is followed by #0 */
00269       if (!*path) {
00270         /* it is so do some more tests */
00271         if (origflags & GWEN_PATH_FLAGS_VARIABLE) {
00272           /* a trailing slash indicates that the current entry is
00273            * supposed to be a group. If the flags indicate that an entry
00274            * is to be found then this would be an error, because the path
00275            * ends in a group instead of an entry */
00276           DBG_DEBUG(GWEN_LOGDOMAIN, "Path ends with a group while an entry is wanted");
00277           return 0;
00278         }
00279         /* other wise simply mark this element as the last one */
00280         flags|=GWEN_PATH_FLAGS_LAST;
00281       }
00282     } /* if *path */
00283     else {
00284       /* path ends here with #0 */
00285       flags|=GWEN_PATH_FLAGS_LAST;
00286       if (origflags & GWEN_PATH_FLAGS_VARIABLE) {
00287         /* path ends with #0, caller wants a variable so this
00288          * last element is one */
00289         flags|=GWEN_PATH_FLAGS_VARIABLE;
00290       }
00291     }
00292 
00293     /* escape or unescape if wanted */
00294     if (!(flags & GWEN_PATH_FLAGS_LAST) ||
00295         ((flags & GWEN_PATH_FLAGS_LAST) &&
00296          (flags & GWEN_PATH_FLAGS_CONVERT_LAST))) {
00297       if (flags & GWEN_PATH_FLAGS_ESCAPE) {
00298         GWEN_BUFFER *buf2;
00299         const char *p;
00300         int rv;
00301 
00302         buf2=GWEN_Buffer_new(0, 64, 0, 1);
00303         GWEN_Buffer_SetStep(buf2, 128);
00304         p=GWEN_Buffer_GetStart(buf1);
00305         if (startAtRoot) {
00306           p++;
00307           GWEN_Buffer_AppendByte(buf2, '/');
00308         }
00309         if (flags & GWEN_PATH_FLAGS_TOLERANT_ESCAPE)
00310           rv=GWEN_Text_EscapeToBufferTolerant(p, buf2);
00311         else
00312           rv=GWEN_Text_EscapeToBuffer(p, buf2);
00313         if (rv) {
00314           DBG_ERROR(GWEN_LOGDOMAIN, "Could not escape path element");
00315           GWEN_Buffer_free(buf2);
00316           GWEN_Buffer_free(buf1);
00317           return 0;
00318         }
00319         GWEN_Buffer_free(buf1);
00320         buf1=buf2;
00321       }
00322       else if (flags & GWEN_PATH_FLAGS_UNESCAPE) {
00323         GWEN_BUFFER *buf2;
00324         const char *p;
00325         int rv;
00326 
00327         buf2=GWEN_Buffer_new(0, 64, 0, 1);
00328         GWEN_Buffer_SetStep(buf2, 128);
00329         p=GWEN_Buffer_GetStart(buf1);
00330         if (startAtRoot) {
00331           p++;
00332           GWEN_Buffer_AppendByte(buf2, '/');
00333         }
00334         if (flags & GWEN_PATH_FLAGS_TOLERANT_ESCAPE)
00335           rv=GWEN_Text_UnescapeToBufferTolerant(p, buf2);
00336         else
00337           rv=GWEN_Text_UnescapeToBuffer(p, buf2);
00338         if (rv) {
00339           DBG_ERROR(GWEN_LOGDOMAIN, "Could not unescape path element");
00340           GWEN_Buffer_free(buf2);
00341           GWEN_Buffer_free(buf1);
00342           return 0;
00343         }
00344         GWEN_Buffer_free(buf1);
00345         buf1=buf2;
00346       }
00347     }
00348 
00349     /* call function */
00350     if (elementFunction) {
00351       data=(elementFunction)(GWEN_Buffer_GetStart(buf1), data, idx, flags);
00352       if (!data) {
00353         DBG_DEBUG(GWEN_LOGDOMAIN, "Error on path element \"%s\"",
00354                   GWEN_Buffer_GetStart(buf1));
00355         GWEN_Buffer_free(buf1);
00356         return 0;
00357       }
00358     }
00359     DBG_DEBUG(GWEN_LOGDOMAIN, "Successfully handled element \"%s\"",
00360               GWEN_Buffer_GetStart(buf1));
00361     if (startAtRoot)
00362       startAtRoot=0;
00363   } /* while (*path) */
00364 
00365   GWEN_Buffer_free(buf1);
00366   return data;
00367 }
00368 
00369 
00370 
00371 
00372 void *GWEN_Path_AppendPathElement(const char *entry,
00373                                   void *data,
00374                                   unsigned int flags){
00375   GWEN_BUFFER *ebuf;
00376 
00377   ebuf=(GWEN_BUFFER*)data;
00378 
00379   GWEN_Buffer_AppendString(ebuf, entry);
00380   if (!(flags & GWEN_PATH_FLAGS_LAST) ||
00381       !(flags & GWEN_PATH_FLAGS_VARIABLE))
00382     GWEN_Buffer_AppendByte(ebuf, '/');
00383   GWEN_Buffer_AllocRoom(ebuf, 1);
00384   GWEN_Buffer_GetPosPointer(ebuf)[0]=0;
00385   return data;
00386 }
00387 
00388 
00389 
00390 int GWEN_Path_Convert(const char *path,
00391                       GWEN_BUFFER *buffer,
00392                       uint32_t flags) {
00393   void *p;
00394 
00395   p=GWEN_Path_Handle(path,
00396                      buffer,
00397                      flags,
00398                      GWEN_Path_AppendPathElement);
00399   if (!p) {
00400     return -1;
00401   }
00402   return 0;
00403 }
00404 
00405 
00406 
00407 
00408 
00409 
00410