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-2012 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     struct ccn_dict_entry *ndd_tmp = NULL;
00090     int ndc = 0;
00091     struct ccn_charbuf *enamebuf = NULL;
00092     unsigned int eindex = 0;;
00093     struct ccn_dict *nd = NULL;
00094     enum scanner_state {
00095         S_OVERFLOW = -2,
00096         S_ERROR = -1,
00097         S_INITIAL = 0,
00098         S_INDEX = 1,
00099         S_NAME = 2,
00100         S_FLUSH = 3
00101     } s = S_INITIAL;
00102     
00103     if (rdp == NULL)
00104         return (-1);
00105 
00106     enamebuf = ccn_charbuf_create();
00107     if (enamebuf == NULL)
00108         return (-1);
00109     
00110     df = fopen(dict_file, "r");
00111     if (df == NULL)
00112         goto err;
00113     
00114     
00115     /* preload result with copy of supplied dictionary */
00116     if (d) {
00117         ndd = calloc(d->count, sizeof(*(d->dict)));
00118         for (ndc = 0; ndc < d->count; ndc++) {
00119             ndd[ndc].index = d->dict[ndc].index;
00120             ndd[ndc].name = strdup(d->dict[ndc].name);
00121         }
00122     }
00123     
00124     /* parse csv format file */
00125     while ((c = fgetc(df)) != EOF && s >= S_INITIAL) {
00126         switch (s) {
00127             case S_INITIAL:
00128                 if (isdigit(c)) {
00129                     s = S_INDEX;
00130                     eindex = c - '0';
00131                 } else
00132                     s = S_ERROR;
00133                 break;
00134             case S_INDEX:
00135                 if (isdigit(c)) {
00136                     unsigned int teindex = eindex;
00137                     eindex = 10 * eindex + (c - '0');
00138                     if (eindex < teindex)
00139                         s = S_OVERFLOW;
00140                 } else if (c == ',')
00141                     s = S_NAME;
00142                 else
00143                     s = S_ERROR;
00144                 break;
00145             case S_NAME:
00146                 if (isalnum(c)) {
00147                     ccn_charbuf_append_value(enamebuf, c, 1);
00148                 } else if (c == ',' || c == '\n') {
00149                     /* construct entry */
00150                     ndd_tmp = realloc(ndd, sizeof(*ndd) * (ndc + 1));
00151                     if (ndd_tmp == NULL)
00152                         goto err;
00153                     ndd = ndd_tmp;
00154                     ndd[ndc].index = eindex;
00155                     ndd[ndc].name = strdup(ccn_charbuf_as_string(enamebuf));
00156                     ndc++;
00157                     ccn_charbuf_reset(enamebuf);
00158                     s = (c == ',') ? S_FLUSH : S_INITIAL;
00159                 } else
00160                     s = S_ERROR;
00161                 break;
00162             case S_FLUSH:
00163                 if (c == '\n')
00164                     s = S_INITIAL;
00165                 break;
00166             default:
00167                 break;
00168         }
00169     }
00170     fclose(df);
00171     df = NULL;
00172     
00173     /* handle error exit from parsing and pick up trailing entry without newline */
00174     if (s < 0 || s == S_INDEX)
00175         goto err;
00176     else if (s == S_NAME) {
00177         ndd_tmp = realloc(ndd, sizeof(*ndd) * (ndc + 1));
00178         if (ndd_tmp == NULL)
00179             goto err;
00180         ndd = ndd_tmp;
00181         ndd[ndc].index = eindex;
00182         ndd[ndc].name = strdup(ccn_charbuf_as_string(enamebuf));
00183         ndc++;
00184     }
00185     ccn_charbuf_destroy(&enamebuf);
00186     
00187     /* check for inconsistent duplicate names, mark exact duplicates for removal */
00188     qsort(ndd, ndc, sizeof(*ndd), qsort_compare_dict_names);
00189     for (i = 1; i < ndc; i++) {
00190         if (strcmp(ndd[i-1].name, ndd[i].name) == 0) {
00191             if (ndd[i-1].index == ndd[i].index) {
00192                 free((void *)ndd[i-1].name);
00193                 ndd[i-1].name = NULL;
00194             } else
00195                 goto err;
00196         }
00197     }
00198     /* check for inconsistent duplicate index values,
00199      * trim the array when we reach the duplicates, marked above,
00200      * which sorted to the end.
00201      */
00202     qsort(ndd, ndc, sizeof(*ndd), qsort_compare_dict_indices);
00203     for (i = 1; i < ndc; i++) {
00204         if (ndd[i].name == NULL) {
00205             ndc = i;
00206             ndd_tmp = realloc(ndd, sizeof(*ndd) * ndc);
00207             if (ndd_tmp == NULL)
00208                 goto err;
00209             ndd = ndd_tmp;
00210             break;
00211         }
00212         if (ndd[i-1].index == ndd[i].index)
00213             goto err;
00214     }
00215     
00216     /* construct the final dictionary object */
00217     nd = calloc(1, sizeof(*nd));
00218     if (nd == NULL)
00219         goto err;
00220     nd->dict = ndd;
00221     nd->count = ndc;
00222     *rdp = nd;
00223     return (0);
00224     
00225 err:
00226     ccn_charbuf_destroy(&enamebuf);
00227     if (df != NULL)
00228         fclose(df);
00229     if (ndd != NULL) {
00230         for (ndc--; ndc >= 0; ndc--) {
00231             free((void *)ndd[ndc].name);
00232         }
00233         free(ndd);
00234     }
00235     return (-1);
00236     
00237 }
Generated on Tue Aug 21 14:54:18 2012 for Content-Centric Networking in C by  doxygen 1.6.3