ks_bparse.c

Go to the documentation of this file.
00001 /*
00002  * libkarmaclient - A C Library to the Karmasphere Reputation Server
00003  * Copyright (C) 2006 Karmasphere <http://www.karmasphere.com/>
00004  *  - Shevek <shevek@karmasphere.com>
00005  *  - Dave Stewart <dave.stewart@karmasphere.com>
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this library; if not, write to the Free Software
00019  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
00020  */
00021 
00022 #include "ks_config.h"
00023 #include "ks_bparse.h"
00024 #include "ks_assoc.h"
00025 #include "ks_array.h"
00026 #include "ks_string.h"
00027 #include "ks_number.h"
00028 
00029 #ifdef HAVE_STDLIB_H
00030 #include <stdlib.h>
00031 #endif
00032 
00033 #ifdef HAVE_CTYPE_H
00034 #include <ctype.h>
00035 #endif
00036 
00037 #ifdef HAVE_STDIO_H
00038 #include <stdio.h>
00039 #endif
00040 
00060 static long
00061 ks_strtol(const char **datap, const char *endp, char stop)
00062 {
00063         const char      *cp = *datap;
00064         long             value = 0;
00065         char             invert = 0;
00066 
00067         if (cp < endp && *cp == '-') {
00068                 cp++;
00069                 invert = 1;
00070         }
00071 
00072         while (cp < endp) {
00073                 char    c = *cp++;
00074                 if (c == stop)
00075                         break;
00076                 if (!isdigit(c)) {
00077                         /* XXX Report error. */
00078                         ks_error("Invalid character %c in number %8.8s",
00079                                                         c, *datap);
00080                         break;
00081                 }
00082                 /* XXX Can this be done in a portable way? */
00083                 value = (value * 10) + (c - '0');
00084         }
00085         *datap = cp;
00086 
00087         if (invert)
00088                 value = 0 - value;
00089 
00090         return value;
00091 }
00092 
00093 /* XXX This is a slightly generous parser.
00094  *
00095  * The following invalid cases are accepted:
00096  * "ie" is an integer value 0.
00097  *
00098  * The following cases will cause a crash:
00099  * "dieiee" is a dictionary with a nonstring key
00100  */
00101 static ks_base_t *
00102 ks_bparse_recursive(const char **datap, const char *endp)
00103 {
00104         ks_array_t      *a;
00105         ks_assoc_t      *s;
00106         ks_string_t     *r;
00107         ks_base_t       *b;
00108         const char      *k;
00109         const char      *cp = *datap;
00110         long             l;
00111 
00112         if (cp == endp)
00113                 return NULL;
00114         switch (*cp++) {
00115                 case '0': case '1': case '2': case '3': case '4':
00116                 case '5': case '6': case '7': case '8': case '9':
00117                         cp--;   /* Digit not consumed. */
00118                         l = ks_strtol(&cp, endp, ':');
00119                         if (cp + l > endp) {
00120                                 ks_error("String length %ld longer than "
00121                                                 "data length %d", l, endp - cp);
00122                                 return NULL;
00123                         }
00124                         r = ks_string_new(cp, l);
00125                         *datap = cp + l;
00126                         return (ks_base_t *)r;
00127                 case 'i':
00128                         l = ks_strtol(&cp, endp, 'e');
00129                         *datap = cp;
00130                         return (ks_base_t *)ks_number_new(l);
00131                 case 'l':
00132                         a = ks_array_new();
00133                         *datap = cp;
00134                         while (**datap != 'e') {
00135                                 b = ks_bparse_recursive(datap, endp);
00136                                 if (b == NULL) {
00137                                         ks_array_free(a);
00138                                         return NULL;
00139                                 }
00140                                 ks_array_add(a, b);
00141                         }
00142                         (*datap)++;
00143                         return (ks_base_t *)a;
00144                 case 'd':
00145                         s = ks_assoc_new();
00146                         *datap = cp;
00147                         while (**datap != 'e') {
00148                                 if (!isdigit(**datap)) {
00149                                         /* XXX Not a string. Report error. */
00150                                         ks_error("Key %8.8s not a string", *datap);
00151                                         ks_assoc_free(s);
00152                                         return NULL;
00153                                 }
00154                                 /* Get the key and length. */
00155                                 l = ks_strtol(datap, endp, ':');
00156                                 k = *datap;
00157                                 *datap += l;
00158 
00159                                 b = ks_bparse_recursive(datap, endp);
00160                                 if (b == NULL) {
00161                                         ks_assoc_free(s);
00162                                         return NULL;
00163                                 }
00164 
00165                                 ks_assoc_put(s, k, l, b);
00166                         }
00167                         (*datap)++;
00168                         return (ks_base_t *)s;
00169                 case 'e':
00170                         /* This can only be an error.
00171                          * Note that this differs structurally from the Java
00172                          * version. In this version, ANY NULL return is an
00173                          * error, and means clean up and return NULL. */
00174                         /*
00175                         *datap = cp;
00176                         return NULL;
00177                         */
00178                 default:
00179                         /* XXX Report error. */
00180                         ks_error("Value %8.8s not valid", *datap);
00181                         break;
00182         }
00183 
00184         return NULL;
00185 }
00186 
00200 ks_base_t *
00201 ks_bparse(const char *data, int len)
00202 {
00203         const char      *endp = data + len;
00204         return ks_bparse_recursive(&data, endp);
00205 }

Generated on Wed May 9 01:01:56 2007 for libkarmaclient by  doxygen 1.5.1