funkalicious 0.1

matdb-dotcode.c

Go to the documentation of this file.
00001 /*
00002  * matdb-dotcode: reads in Craig's Dotcode materials database.
00003  
00004  Copyright (C) 2009 Joseph Pingenot
00005 
00006  This program is free software: you can redistribute it and/or modify
00007  it under the terms of the GNU Affero General Public License as published by
00008  the Free Software Foundation, either version 3 of the License, or
00009  (at your option) any later version.
00010 
00011  This program is distributed in the hope that it will be useful,
00012  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  GNU Affero General Public License for more details.
00015 
00016  You should have received a copy of the GNU Affero General Public License
00017  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00018 */
00019 
00020 #include <stdio.h>
00021 #include <math.h>
00022 #include <strings.h>
00023 #include <stdlib.h>
00024 #include <glib-2.0/glib.h>
00025 #include "config.h"
00026 #include <libdotcode/matdb.h>
00027 #include <libdotcode/matdb-dotcode.h>
00028 
00029 #define GERROR_DOMAIN_MATDB_DOTCODE 4096
00030 
00031 /*If we don't have getline, we need to kludge around it*/
00032 #ifndef HAVE_GETLINE
00033 ssize_t getline(char **lineptr, size_t *n, FILE *stream) {
00034   GString *s = g_string_new_len("", 4096);
00035   int c;
00036   long int i=0;
00037   while(((c=fgetc(stream)) != '\n') && (c!=EOF) && ((n != NULL) || (i<*n))) {
00038     if((*lineptr) == NULL) {
00039       (*lineptr)[i] = c;
00040     }else{
00041       s = g_string_append_c(s, c);
00042     }
00043     i++;
00044   }
00045   if((*lineptr) == NULL) {
00046     *lineptr = s->str;
00047     g_string_free(s, FALSE);
00048   }else{
00049     g_string_free(s, TRUE);
00050   }
00051   return i;
00052 }
00053 #endif
00054 
00055 
00056 /*Functions to be used by the hash.*/
00057 static void destroy_string(gpointer data) {
00058   free((char*)data);
00059 }
00060 static void destroy_double(gpointer data){
00061   free((double*)data);
00062 }
00063 static void destroy_inner_bowhash(gpointer data) {
00064   g_hash_table_unref((GHashTable*)data);
00065 }
00066 
00067 int insert_into_matdb(struct matdb *mdb, struct matdb_material **mat, struct matdb_bowing **bow) {
00068   if((*mat) != NULL) {
00069 #ifdef DEBUG_2
00070     fprintf(stderr, "inserting material %s\n", (*mat)->name->str);
00071 #endif
00072     g_hash_table_insert(mdb->materials, (gpointer)g_strdup((*mat)->name->str), (gpointer)(*mat));
00073     (*mat) = NULL;
00074   }
00075   if((*bow) != NULL) {
00076 #ifdef DEBUG_2
00077     fprintf(stderr, "inserting bowing %s:%s\n", (*bow)->from->str, (*bow)->to->str);
00078 #endif
00079     /*Inner table*/
00080     GHashTable *it;
00081     if((it=(GHashTable*)g_hash_table_lookup(mdb->bowings, (*bow)->from->str)) == NULL) {
00082       if((it = g_hash_table_new_full(&g_str_hash, &g_str_equal, &destroy_string, &destroy_inner_bowhash)) == NULL) {
00083   (*bow) = NULL;
00084   return 1;
00085       }
00086       g_hash_table_insert(mdb->bowings, (*bow)->from->str, it);
00087 #ifdef DEBUG_2
00088       fprintf(stderr, "Got new hash table (from=%s)\n", (*bow)->from->str);
00089 #endif
00090     }
00091     g_hash_table_insert(it, (gpointer)g_strdup((*bow)->to->str), (gpointer)(*bow));
00092     (*bow) = NULL;
00093   }
00094   return 0;
00095 }
00096 
00097 /*Removes leading and trailing whitespace, comments, and reduces
00098   redundant whitespace down to one tab, makes an empty line an empty string.*/
00099 static void prettify_line(char *line) {
00100   register char *look;
00101   register char *write;
00102   register int in_whitespace;
00103   register int leading_whitespace;
00104   for(look=write=line, in_whitespace=0, leading_whitespace=1; *look != '\0'; look++) {
00105 #ifdef DEBUG_2
00106     fprintf(stderr, " look=%d(%c) write=%d(%c) in_whitespace=%d leading_whitespace=%d: ", (look-line), *look, (write-line), *write, in_whitespace, leading_whitespace);
00107 #endif
00108     if(*look == '#') {
00109 #ifdef DEBUG_2
00110       fprintf(stderr, "comment\n");
00111 #endif
00112       *write = '\0';
00113       break;
00114     }
00115     switch(*look) {
00116     case ' ':
00117     case '\n':
00118     case '\t':
00119 #ifdef DEBUG_2
00120       fprintf(stderr, "whitespace\n");
00121 #endif
00122     if((!leading_whitespace) && (!in_whitespace)) *write++ = '\t';
00123     in_whitespace=1;
00124     break;
00125     default:
00126 #ifdef DEBUG_2
00127       fprintf(stderr, "default\n");
00128 #endif
00129       *write++ = *look;
00130       in_whitespace=leading_whitespace=0;
00131     }
00132   }
00133   *write='\0';
00134   for(look=write=line; *look != '\0'; look++) {
00135     switch(*look) {
00136     case ' ':
00137     case '\n':
00138     case '\t':
00139       if(*(look+1) == '\0') {
00140   *look = '\0';
00141       }
00142     }
00143   }
00144 }
00145 
00146 /*Error values:
00147  *   0: success
00148  *   1: failure malloc'ing / initializing mdb struct
00149  *   2: failure opening file.
00150  *   4: failure reading line.
00151  *   8: warning reading line: no tab separator (line parsing error)
00152  *  16: warning reading line: bad section declaration
00153  *  32: warning reading line: unable to allocate material struct.
00154  *  64: warning reading line: ignored line (unallocated material struct)
00155  * 128: warning reading line: unable to allocate bowing struct
00156  * 256: warning reading line: ignored line (unallocated bowing struct)
00157  * 512: warning reading file: improper section detected (programming
00158  *   error)
00159  *1024: warning reading file: no : separator in bowing materials
00160  *   description.
00161  *2048: warning reading file: unable to read numeric value for property.
00162  */
00163 struct matdb* read_matdb_dotcode(const GString *name, int* err) {
00164 #ifdef DEBUG_2
00165   fprintf(stderr, "in read_matdb_dotcode(%s, %d)\n", name->str, *err);
00166 #endif
00167   *err=0;
00168   struct matdb *mdb = (struct matdb*)malloc(sizeof(struct matdb));
00169   if(mdb == NULL) {*err = 1; return NULL;}
00170 
00171   double *value;
00172   if((mdb->materials = g_hash_table_new_full(&g_str_hash, &g_str_equal, &destroy_string, &destroy_material_gpointer)) == NULL) {
00173     *err = 1;
00174     free(mdb);
00175     return NULL;
00176   }
00177   if((mdb->bowings = g_hash_table_new_full(&g_str_hash, &g_str_equal, &destroy_string, &destroy_bowing_gpointer)) == NULL) {
00178     *err = 1;
00179     g_hash_table_unref(mdb->materials);
00180     free(mdb);
00181     return NULL;
00182   }
00183   struct matdb_material *mat = NULL;
00184   struct matdb_bowing *bow = NULL;
00185   /*Valid sections:
00186    * 0 (no/global section)
00187    * 1 (material)
00188    * 2 (bow)
00189    */
00190   int section=0;
00191   size_t n;
00192   char *line;
00193   FILE *infile = fopen(name->str, "r");
00194   if(infile == NULL) {
00195     g_hash_table_unref(mdb->materials);
00196     g_hash_table_unref(mdb->bowings);
00197     free(mdb);
00198     *err=2;
00199     return NULL;
00200 #ifdef DEBUG_2
00201   }else{
00202     fprintf(stderr, "infile=%x\n", (unsigned int)infile);
00203 #endif
00204   }
00205   int val;
00206   while(!feof(infile)) {
00207 #ifdef DEBUG_2
00208     fprintf(stderr, "mat=%p(%s), bow=%p(%s:%s)\n", (void*)mat, mat?mat->name->str:"", (void*)bow, bow?bow->from->str:"", bow?bow->to->str:"");
00209 #endif
00210     line=NULL;
00211     if((val = getline(&line, &n, infile)) == -1) {
00212 #ifdef DEBUG_2
00213       fprintf(stderr, "getline returned %d\n", val);
00214 #endif
00215       if(!feof(infile)) *err = 4;
00216       //fclose(infile);
00217       break;
00218     }
00219 #ifdef DEBUG_2
00220     fprintf(stderr, "line=(%s)\n", line);
00221 #endif
00222     prettify_line(line);
00223 #ifdef DEBUG_2
00224     fprintf(stderr, "%d: prettified line=(%s)\n", section, line);
00225 #endif
00226     if(*line == '\0') {
00227       free(line);
00228       continue;
00229     }
00230     char *i = index(line, '\t');
00231     if(i == NULL) {
00232       *err &= 8;
00233     }
00234     *i++ = '\0';
00235     /*At this point, we have line which stores the first word on the
00236       line, and i which stores the second word on the line.
00237     */
00238     char *to;
00239     GHashTable *ht;
00240 #ifdef DEBUG_2
00241     fprintf(stderr, "part_a=(%s) part_b=(%s)\n", line, i);
00242 #endif
00243     /*If we have a material or bowing underway, save it off*/
00244     if(strcasecmp(line, "material") == 0) {
00245       insert_into_matdb(mdb, &mat, &bow);
00246       if((mat = (struct matdb_material*)malloc(sizeof(struct matdb_material))) == NULL) {
00247   *err &= 32;
00248       }
00249       if((mat->name = g_string_new(i)) == NULL) {
00250   *err &= 32;
00251   free(mat);
00252   section=0;
00253   continue;
00254       }
00255       if((mat->properties = g_hash_table_new_full(&g_str_hash, &g_str_equal, &destroy_string, &destroy_double)) == NULL) {
00256   *err &= 32;
00257   g_string_free(mat->name, TRUE);
00258   free(bow);
00259   section=0;
00260   continue;
00261       }
00262 #ifdef DEBUG_2
00263       fprintf(stderr, "new material (%s):\n", i);
00264 #endif
00265       section=1;
00266     }else if(strcasecmp(line, "bow") == 0) {
00267       insert_into_matdb(mdb, &mat, &bow);
00268       if((bow = (struct matdb_bowing*)malloc(sizeof(struct matdb_bowing))) == NULL) {
00269   *err &= 128;
00270       }
00271       if((to = index(i, ':')) == NULL) {
00272   *err &= 1024;
00273   free(bow);
00274   section=0;
00275   continue;
00276       }
00277       *to++ = '\0';
00278       /*Same trick as before, but i now stores the from material,
00279   and to the to material
00280       */
00281       if((bow->from = g_string_new(i)) == NULL) {
00282   *err &= 128;
00283   free(bow);
00284   section=0;
00285   continue;
00286       }
00287       if((bow->to = g_string_new(to)) == NULL) {
00288   *err &= 128;
00289   g_string_free(bow->from, TRUE);
00290   free(bow);
00291   section=0;
00292   continue;
00293       }
00294       if((bow->properties = g_hash_table_new_full(&g_str_hash, &g_str_equal, &destroy_string, &destroy_double)) == NULL) {
00295   *err &= 128;
00296   g_string_free(bow->to, TRUE);
00297   g_string_free(bow->from, TRUE);
00298   free(bow);
00299   section=0;
00300   continue;
00301       }
00302 #ifdef DEBUG_2
00303       fprintf(stderr, "new bowing (%s:%s):\n", i, to);
00304 #endif
00305       section=2;
00306     }else{
00307 #ifdef DEBUG_2
00308       fprintf(stderr, "\t%d/%s\t", section, line);
00309 #endif
00310       /*Process a property.*/
00311       switch(section) {
00312       case 1:
00313 #ifdef DEBUG_2
00314   fprintf(stderr, "(1)\t");
00315 #endif
00316   ht = mat->properties;
00317   break;
00318       case 2:
00319 #ifdef DEBUG_2
00320   fprintf(stderr, "(2)\t");
00321 #endif
00322   ht = bow->properties;
00323   break;
00324       default:
00325 #ifdef DEBUG
00326   fprintf(stderr, "(default)\t");
00327 #endif
00328   *err &= 16;
00329   section = 0;
00330       }
00331       if(section == 0) {
00332 #ifdef DEBUG
00333   fprintf(stderr, "section was 0\n");
00334 #endif
00335   continue;
00336       }
00337       if((value = (double*)malloc(sizeof(double))) == NULL) {
00338   *err &= 2048;
00339 #ifdef DEBUG
00340   fprintf(stderr, "malloc of value failed\n");
00341 #endif
00342   continue;
00343       }
00344       int num;
00345       if((num=sscanf(i, " %lg", value)) != 1) {
00346   *err &= 2048;
00347   free(value);
00348 #ifdef DEBUG
00349   fprintf(stderr, "bad sscanf to get value (scanned \"%s\", returned %d)\n", i, num);
00350 #endif
00351   continue;
00352       }
00353       g_hash_table_insert(ht, g_strdup(line), value);
00354 #ifdef DEBUG_2
00355       fprintf(stderr, "%g(%s)\n", *value, line);
00356 #endif
00357     }
00358     free(line);
00359     line=i=to=NULL;
00360     value=NULL;
00361   }
00362   fclose(infile);
00363   insert_into_matdb(mdb, &mat, &bow);
00364   return mdb;
00365 }
00366 
00367 struct matdb* read_matdb_dotcode_gio(GFile *f, GError **error) {
00368   char* str;
00369 #ifdef DEBUG_2
00370   fprintf(stderr, "in read_matdb_dotcode_gio(%s, %p)\n", str=g_file_get_uri(f), (void*)error);
00371   g_free(str);
00372 #endif
00373   GError *e = NULL;
00374   struct matdb *mdb = (struct matdb*)malloc(sizeof(struct matdb));
00375   if(mdb == NULL) {
00376     *error = g_error_new(GERROR_DOMAIN_MATDB_DOTCODE, 1, "ERROR: failed to allocate memory for matdb structure.");
00377     return NULL;
00378   }
00379 
00380   double *value;
00381   if((mdb->materials = g_hash_table_new_full(&g_str_hash, &g_str_equal, &destroy_string, &destroy_material_gpointer)) == NULL) {
00382     *error = g_error_new(GERROR_DOMAIN_MATDB_DOTCODE, 1, "ERROR: failed to allocate memory for matdb->materials hash table.");
00383     free(mdb);
00384     return NULL;
00385   }
00386   if((mdb->bowings = g_hash_table_new_full(&g_str_hash, &g_str_equal, &destroy_string, &destroy_bowing_gpointer)) == NULL) {
00387     *error = g_error_new(GERROR_DOMAIN_MATDB_DOTCODE, 1, "ERROR: failed to allocate memory for matdb->bowings hash table.");
00388     g_hash_table_unref(mdb->materials);
00389     free(mdb);
00390     return NULL;
00391   }
00392   struct matdb_material *mat = NULL;
00393   struct matdb_bowing *bow = NULL;
00394   /*Valid sections:
00395    * 0 (no/global section)
00396    * 1 (material)
00397    * 2 (bow)
00398    */
00399   int section=0;
00400   char *line;
00401   GFileInputStream *fis = g_file_read(f, NULL, &e);
00402   if((fis == NULL) || (e != NULL)) {
00403     g_propagate_prefixed_error(error, e, "Failed to open file (%s) for reading.", str=g_file_get_uri(f));
00404     g_free(str);
00405     g_hash_table_unref(mdb->bowings);
00406     g_hash_table_unref(mdb->materials);
00407     free(mdb);
00408     return NULL;
00409   }
00410   GDataInputStream *dis = g_data_input_stream_new((GInputStream*)fis);
00411   gsize amt_read = 1;
00412   /*Exit condition is line is NULL*/
00413   while(1) {
00414 #ifdef DEBUG_2
00415     fprintf(stderr, "mat=%p(%s), bow=%p(%s:%s)\n", (void*)mat, mat?mat->name->str:"", (void*)bow, bow?bow->from->str:"", bow?bow->to->str:"");
00416 #endif
00417     e=NULL;
00418     line = g_data_input_stream_read_line(dis, &amt_read, NULL, &e);
00419     if(e != NULL){
00420 #ifdef DEBUG_2
00421       fprintf(stderr, "Error: getline returned %d chars\n", amt_read);
00422 #endif
00423       g_propagate_prefixed_error(error, e, "Failed to read a line from file (%s)", str=g_file_get_uri(f));
00424       g_free(str);
00425       g_hash_table_unref(mdb->bowings);
00426       g_hash_table_unref(mdb->materials);
00427       free(mdb);
00428       return NULL;
00429     }
00430     if(line == NULL) break;
00431     if(amt_read == 0) {
00432 #ifdef DEBUG
00433       fprintf(stderr, "read zero chars in that call; line=%s", line);
00434 #endif
00435       continue;
00436     }
00437 #ifdef DEBUG_2
00438     fprintf(stderr, "line=(%s)\n", line);
00439 #endif
00440     prettify_line(line);
00441 #ifdef DEBUG_2
00442     fprintf(stderr, "%d: prettified line=(%s)\n", section, line);
00443 #endif
00444     if(*line == '\0') {
00445       free(line);
00446       continue;
00447     }
00448     char *i = index(line, '\t');
00449     if(i == NULL) {
00450       *error = g_error_new(GERROR_DOMAIN_MATDB_DOTCODE, 8, "There was no tab on the line (line was \"%s\")", line);
00451       g_hash_table_unref(mdb->bowings);
00452       g_hash_table_unref(mdb->materials);
00453       free(mdb);
00454       return NULL;
00455     }
00456     *i++ = '\0';
00457     /*At this point, we have line which stores the first word on the
00458       line, and i which stores the second word on the line.
00459     */
00460     char *to;
00461     GHashTable *ht;
00462 #ifdef DEBUG_2
00463     fprintf(stderr, "part_a=(%s) part_b=(%s)\n", line, i);
00464 #endif
00465     /*If we have a material or bowing underway, save it off*/
00466     if(strcasecmp(line, "material") == 0) {
00467       insert_into_matdb(mdb, &mat, &bow);
00468       if((mat = (struct matdb_material*)malloc(sizeof(struct matdb_material))) == NULL) {
00469   *error = g_error_new(GERROR_DOMAIN_MATDB_DOTCODE, 32, "Failed to allocate memory for a new matdb material");
00470   g_hash_table_unref(mdb->bowings);
00471   g_hash_table_unref(mdb->materials);
00472   free(mdb);
00473   return NULL;
00474       }
00475       if((mat->name = g_string_new(i)) == NULL) {
00476   *error = g_error_new(GERROR_DOMAIN_MATDB_DOTCODE, 32, "Failed to allocate string for material name");
00477   g_hash_table_unref(mdb->bowings);
00478   g_hash_table_unref(mdb->materials);
00479   free(mdb);
00480   return NULL;
00481       }
00482       if((mat->properties = g_hash_table_new_full(&g_str_hash, &g_str_equal, &destroy_string, &destroy_double)) == NULL) {
00483   *error = g_error_new(GERROR_DOMAIN_MATDB_DOTCODE, 32, "Failed to allocate new properties hash for material %s", i);
00484   g_hash_table_unref(mdb->bowings);
00485   g_hash_table_unref(mdb->materials);
00486   free(mdb);
00487   return NULL;
00488       }
00489 #ifdef DEBUG_2
00490       fprintf(stderr, "new material (%s):\n", i);
00491 #endif
00492       section=1;
00493     }else if(strcasecmp(line, "bow") == 0) {
00494       insert_into_matdb(mdb, &mat, &bow);
00495       if((bow = (struct matdb_bowing*)malloc(sizeof(struct matdb_bowing))) == NULL) {
00496   *error = g_error_new(GERROR_DOMAIN_MATDB_DOTCODE, 32, "Failed to allocate new bowing");
00497   g_hash_table_unref(mdb->bowings);
00498   g_hash_table_unref(mdb->materials);
00499   free(mdb);
00500   return NULL;
00501       }
00502       if((to = index(i, ':')) == NULL) {
00503   *error = g_error_new(GERROR_DOMAIN_MATDB_DOTCODE, 1024, "Failed to allocate new bowing");
00504   g_hash_table_unref(mdb->bowings);
00505   g_hash_table_unref(mdb->materials);
00506   free(mdb);
00507   return NULL;
00508       }
00509       *to++ = '\0';
00510       /*Same trick as before, but i now stores the from material,
00511   and to the to material
00512       */
00513       if((bow->from = g_string_new(i)) == NULL) {
00514   *error = g_error_new(GERROR_DOMAIN_MATDB_DOTCODE, 128, "Failed to allocate new string (for \"%s\")", i);
00515   g_hash_table_unref(mdb->bowings);
00516   g_hash_table_unref(mdb->materials);
00517   free(mdb);
00518   return NULL;
00519       }
00520       if((bow->to = g_string_new(to)) == NULL) {
00521   *error = g_error_new(GERROR_DOMAIN_MATDB_DOTCODE, 128, "Failed to allocate new string (for \"%s\")", to);
00522   g_hash_table_unref(mdb->bowings);
00523   g_hash_table_unref(mdb->materials);
00524   free(mdb);
00525   return NULL;
00526       }
00527       if((bow->properties = g_hash_table_new_full(&g_str_hash, &g_str_equal, &destroy_string, &destroy_double)) == NULL) {
00528   *error = g_error_new(GERROR_DOMAIN_MATDB_DOTCODE, 128, "Failed to allocate new bowing hash table for properties for material %s,%s", bow->from->str, bow->to->str);
00529   g_hash_table_unref(mdb->bowings);
00530   g_hash_table_unref(mdb->materials);
00531   free(mdb);
00532   return NULL;
00533       }
00534 #ifdef DEBUG_2
00535       fprintf(stderr, "new bowing (%s:%s):\n", i, to);
00536 #endif
00537       section=2;
00538     }else{
00539 #ifdef DEBUG_2
00540       fprintf(stderr, "\t%d/%s\t", section, line);
00541 #endif
00542       /*Process a property.*/
00543       switch(section) {
00544       case 1:
00545 #ifdef DEBUG_2
00546   fprintf(stderr, "(1)\t");
00547 #endif
00548   ht = mat->properties;
00549   break;
00550       case 2:
00551 #ifdef DEBUG_2
00552   fprintf(stderr, "(2)\t");
00553 #endif
00554   ht = bow->properties;
00555   break;
00556       default:
00557 #ifdef DEBUG
00558   fprintf(stderr, "(default)\t");
00559 #endif
00560   *error = g_error_new(GERROR_DOMAIN_MATDB_DOTCODE, 16, "Invalid section index (%d)\n", section);
00561   g_hash_table_unref(mdb->bowings);
00562   g_hash_table_unref(mdb->materials);
00563   free(mdb);
00564   return NULL;
00565       }
00566       if(section == 0) {
00567 #ifdef DEBUG_2
00568   fprintf(stderr, "section was 0\n");
00569 #endif
00570   continue;
00571       }
00572       if((value = (double*)malloc(sizeof(double))) == NULL) {
00573   *error = g_error_new(GERROR_DOMAIN_MATDB_DOTCODE, 2048, "Malloc of value failed");
00574   g_hash_table_unref(mdb->bowings);
00575   g_hash_table_unref(mdb->materials);
00576   free(mdb);
00577   return NULL;
00578 #ifdef DEBUG
00579   fprintf(stderr, "malloc of value failed\n");
00580 #endif
00581   continue;
00582       }
00583       int num;
00584       if((num=sscanf(i, " %lg", value)) != 1) {
00585   /*Invalid values are used to insert NaNs*/
00586   num=nan("NaN");
00587 #ifdef DEBUG
00588   fprintf(stderr, "bad sscanf to get value (scanned \"%s\", returned %d; using NaN)\n", i, num);
00589 #endif
00590       }
00591       g_hash_table_insert(ht, g_strdup(line), value);
00592 #ifdef DEBUG_2
00593       fprintf(stderr, "%g(%s)\n", *value, line);
00594 #endif
00595     }
00596     free(line);
00597     line=i=to=NULL;
00598     value=NULL;
00599   }
00600 #ifdef DEBUG_2
00601   fprintf(stderr, "amt_read=%lu", (long unsigned int)amt_read);
00602 #endif
00603   g_input_stream_close((GInputStream*)fis, NULL, &e);
00604   if(e != NULL) {
00605     g_propagate_prefixed_error(error, e, "Error closing file (%s):", str=g_file_get_uri(f));
00606     g_free(str);
00607   }
00608   insert_into_matdb(mdb, &mat, &bow);
00609   return mdb;
00610 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Defines