|
funkalicious 0.1
|
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 }