ccn_extend_dict.c

Go to the documentation of this file.
00001 /**
00002  * @file ccn_extend_dict.c
00003  * @brief Routines for extending a dictionary such as that which represents default DTAG table.
00004  * 
00005  * Part of the CCNx C Library.
00006  *
00007  * Copyright (C) 2010 Palo Alto Research Center, Inc.
00008  *
00009  * This library is free software; you can redistribute it and/or modify it
00010  * under the terms of the GNU Lesser General Public License version 2.1
00011  * as published by the Free Software Foundation.
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. You should have received
00016  * a copy of the GNU Lesser General Public License along with this library;
00017  * if not, write to the Free Software Foundation, Inc., 51 Franklin Street,
00018  * Fifth Floor, Boston, MA 02110-1301 USA.
00019  */
00020 
00021 #include <stdio.h>
00022 #include <stdlib.h>
00023 #include <string.h>
00024 #include <ctype.h>
00025 
00026 #include <ccn/charbuf.h>
00027 #include <ccn/extend_dict.h>
00028 
00029 static int
00030 qsort_compare_dict_names(const void *x, const void *y)
00031 {
00032     const struct ccn_dict_entry *ex = x;
00033     const struct ccn_dict_entry *ey = y;
00034     return (strcmp(ex->name, ey->name));
00035 }
00036 
00037 /* compare entries based on index, except that an entry with a NULL name
00038  * field is always greater than a non-NULL name field, which allows us
00039  * to bubble exact duplicates eliminated after the name sort to the end
00040  */
00041 static int
00042 qsort_compare_dict_indices(const void *x, const void *y)
00043 {
00044     const struct ccn_dict_entry *ex = x;
00045     const struct ccn_dict_entry *ey = y;
00046     if (ex->name == NULL)
00047         return ((ey->name == NULL) ? 0 : 1);
00048     if (ey->name == NULL) return (-1);
00049     if (ex->index == ey->index) return (0);
00050     return ((ex->index < ey->index) ? -1 : 1);
00051 }
00052 
00053 /**
00054  * Destroy a dictionary dynamically allocated by ccn_extend_dict
00055  * @param dp    Pointer to a pointer to a ccn_dict which will be freed
00056  *              and set to NULL
00057  */
00058 void
00059 ccn_destroy_dict(struct ccn_dict **dp)
00060 {
00061     struct ccn_dict *d = *dp;
00062     int i;
00063     if (d != NULL) {
00064         for (i = 0; i < d->count; i++) {
00065             if (d->dict[i].name != NULL)
00066                 free((void *)d->dict[i].name);
00067         }
00068         free(d);
00069     }
00070     *dp = NULL;
00071 }
00072 
00073 /**
00074  * Create a dictionary by combining a file of key/value pairs with an existing
00075  * dictionary.
00076  * 
00077  * @param dict_file     the name of a file containing integer,name pairs one per line
00078  * @param d             a pre-existing dictionary that will be copied in the result
00079  * @param rdp           a pointer to storage into which a pointer to the result
00080  *                      dictionary will be stored
00081  * @result 0 if the new dictionary was created successfully, otherwise -1.
00082  */
00083 int
00084 ccn_extend_dict(const char *dict_file, struct ccn_dict *d, struct ccn_dict **rdp)
00085 {
00086     FILE *df = NULL;
00087     int i, c;
00088     struct ccn_dict_entry *ndd = NULL;
00089     int ndc = 0;
00090     struct ccn_charbuf *enamebuf = NULL;
00091     unsigned int eindex = 0;;
00092     struct ccn_dict *nd = NULL;
00093     enum scanner_state {
00094         S_OVERFLOW = -2,
00095         S_ERROR = -1,
00096         S_INITIAL = 0,
00097         S_INDEX = 1,
00098         S_NAME = 2,
00099         S_FLUSH = 3
00100     } s = S_INITIAL;
00101     
00102     if (rdp == NULL)
00103         return (-1);
00104 
00105     enamebuf = ccn_charbuf_create();
00106     if (enamebuf == NULL)
00107         return (-1);
00108     
00109     df = fopen(dict_file, "r");
00110     if (df == NULL)
00111         goto err;
00112     
00113     
00114     /* preload result with copy of supplied dictionary */
00115     if (d) {
00116         ndd = calloc(d->count, sizeof(*(d->dict)));
00117         for (ndc = 0; ndc < d->count; ndc++) {
00118             ndd[ndc].index = d->dict[ndc].index;
00119             ndd[ndc].name = strdup(d->dict[ndc].name);
00120         }
00121     }
00122     
00123     /* parse csv format file */
00124     while ((c = fgetc(df)) != EOF && s >= S_INITIAL) {
00125         switch (s) {
00126             case S_INITIAL:
00127                 if (isdigit(c)) {
00128                     s = S_INDEX;
00129                     eindex = c - '0';
00130                 } else
00131                     s = S_ERROR;
00132                 break;
00133             case S_INDEX:
00134                 if (isdigit(c)) {
00135                     unsigned int teindex = eindex;
00136                     eindex = 10 * eindex + (c - '0');
00137                     if (eindex < teindex)
00138                         s = S_OVERFLOW;
00139                 } else if (c == ',')
00140                     s = S_NAME;
00141                 else
00142                     s = S_ERROR;
00143                 break;
00144             case S_NAME:
00145                 if (isalnum(c)) {
00146                     ccn_charbuf_append_value(enamebuf, c, 1);
00147                 } else if (c == ',' || c == '\n') {
00148                     /* construct entry */
00149                     ndd = realloc(ndd, sizeof(*ndd) * (ndc + 1));
00150                     ndd[ndc].index = eindex;
00151                     ndd[ndc].name = strdup(ccn_charbuf_as_string(enamebuf));
00152                     ndc++;
00153                     ccn_charbuf_reset(enamebuf);
00154                     s = (c == ',') ? S_FLUSH : S_INITIAL;
00155                 } else
00156                     s = S_ERROR;
00157                 break;
00158             case S_FLUSH:
00159                 if (c == '\n')
00160                     s = S_INITIAL;
00161                 break;
00162             default:
00163                 break;
00164         }
00165     }
00166     fclose(df);
00167     df = NULL;
00168     
00169     /* handle error exit from parsing and pick up trailing entry without newline */
00170     if (s < 0 || s == S_INDEX)
00171         goto err;
00172     else if (s == S_NAME) {
00173         ndd = realloc(ndd, sizeof(*ndd) * (ndc + 1));
00174         ndd[ndc].index = eindex;
00175         ndd[ndc].name = strdup(ccn_charbuf_as_string(enamebuf));
00176         ndc++;
00177     }
00178     ccn_charbuf_destroy(&enamebuf);
00179     
00180     /* check for inconsistent duplicate names, mark exact duplicates for removal */
00181     qsort(ndd, ndc, sizeof(*ndd), qsort_compare_dict_names);
00182     for (i = 1; i < ndc; i++) {
00183         if (strcmp(ndd[i-1].name, ndd[i].name) == 0) {
00184             if (ndd[i-1].index == ndd[i].index) {
00185                 free((void *)ndd[i-1].name);
00186                 ndd[i-1].name = NULL;
00187             } else
00188                 goto err;
00189         }
00190     }
00191     /* check for inconsistent duplicate index values,
00192      * trim the array when we reach the duplicates, marked above,
00193      * which sorted to the end.
00194      */
00195     qsort(ndd, ndc, sizeof(*ndd), qsort_compare_dict_indices);
00196     for (i = 1; i < ndc; i++) {
00197         if (ndd[i].name == NULL) {
00198             ndc = i;
00199             ndd = realloc(ndd, sizeof(*ndd) * ndc);
00200             break;
00201         }
00202         if (ndd[i-1].index == ndd[i].index)
00203             goto err;
00204     }
00205     
00206     /* construct the final dictionary object */
00207     nd = calloc(1, sizeof(*nd));
00208     if (nd == NULL)
00209         goto err;
00210     nd->dict = ndd;
00211     nd->count = ndc;
00212     *rdp = nd;
00213     return (0);
00214     
00215 err:
00216     ccn_charbuf_destroy(&enamebuf);
00217     if (df != NULL)
00218         fclose(df);
00219     if (ndd != NULL) {
00220         for (ndc--; ndc >= 0; ndc--) {
00221             free((void *)ndd[ndc].name);
00222         }
00223     }
00224     return (-1);
00225     
00226 }

Generated on Thu Feb 16 00:44:00 2012 for Content-Centric Networking in C by  doxygen 1.5.6