|
k-dot-p 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 <strings.h> 00022 #include <stdlib.h> 00023 #include "config.h" 00024 #include <libmodelxx/matdb.h++> 00025 #include <libmodelxx/matdb-dotcode.h++> 00026 00027 namespace kdotp { 00028 namespace libmodelxx { 00029 namespace structure { 00030 00031 #ifdef DEBUG 00032 #undef DEBUG 00033 #endif 00034 #ifdef DEBUG_2 00035 #undef DEBUG_2 00036 #endif 00037 00038 /*Functions to be used by the hash.*/ 00039 static void destroy_string(gpointer data) { 00040 free((char*)data); 00041 } 00042 static void destroy_double(gpointer data){ 00043 free((double*)data); 00044 } 00045 static void destroy_inner_bowhash(gpointer data) { 00046 g_hash_table_unref((GHashTable*)data); 00047 } 00048 00049 int insert_into_matdb(struct matdb *mdb, struct matdb_material **mat, struct matdb_bowing **bow) { 00050 if((*mat) != NULL) { 00051 #ifdef DEBUG 00052 fprintf(stderr, "inserting material %s\n", (*mat)->name->str); 00053 #endif 00054 g_hash_table_insert(mdb->materials, (gpointer)g_strdup((*mat)->name->str), (gpointer)(*mat)); 00055 (*mat) = NULL; 00056 } 00057 if((*bow) != NULL) { 00058 #ifdef DEBUG 00059 fprintf(stderr, "inserting bowing %s:%s\n", (*bow)->from->str, (*bow)->to->str); 00060 #endif 00061 /*Inner table*/ 00062 GHashTable *it; 00063 if((it=(GHashTable*)g_hash_table_lookup(mdb->bowings, (*bow)->from->str)) == NULL) { 00064 if((it = g_hash_table_new_full(&g_str_hash, &g_str_equal, &destroy_string, &destroy_inner_bowhash)) == NULL) { 00065 (*bow) = NULL; 00066 return 1; 00067 } 00068 g_hash_table_insert(mdb->bowings, (*bow)->from->str, it); 00069 #ifdef DEBUG 00070 fprintf(stderr, "Got new hash table (from=%s)\n", (*bow)->from->str); 00071 #endif 00072 } 00073 g_hash_table_insert(it, (gpointer)g_strdup((*bow)->to->str), (gpointer)(*bow)); 00074 (*bow) = NULL; 00075 } 00076 return 0; 00077 } 00078 00079 /*Removes leading and trailing whitespace, comments, and reduces 00080 redundant whitespace down to one tab, makes an empty line an empty string.*/ 00081 static void prettify_line(char *line) { 00082 register char *look; 00083 register char *write; 00084 register int in_whitespace; 00085 register int leading_whitespace; 00086 for(look=write=line, in_whitespace=0, leading_whitespace=1; *look != '\0'; look++) { 00087 #ifdef DEBUG_2 00088 fprintf(stderr, " look=%d(%c) write=%d(%c) in_whitespace=%d leading_whitespace=%d: ", (look-line), *look, (write-line), *write, in_whitespace, leading_whitespace); 00089 #endif 00090 if(*look == '#') { 00091 #ifdef DEBUG_2 00092 fprintf(stderr, "comment\n"); 00093 #endif 00094 *write = '\0'; 00095 break; 00096 } 00097 switch(*look) { 00098 case ' ': 00099 case '\n': 00100 case '\t': 00101 #ifdef DEBUG_2 00102 fprintf(stderr, "whitespace\n"); 00103 #endif 00104 if((!leading_whitespace) && (!in_whitespace)) *write++ = '\t'; 00105 in_whitespace=1; 00106 break; 00107 default: 00108 #ifdef DEBUG_2 00109 fprintf(stderr, "default\n"); 00110 #endif 00111 *write++ = *look; 00112 in_whitespace=leading_whitespace=0; 00113 } 00114 } 00115 *write='\0'; 00116 for(look=write=line; *look != '\0'; look++) { 00117 switch(*look) { 00118 case ' ': 00119 case '\n': 00120 case '\t': 00121 if(*(look+1) == '\0') { 00122 *look = '\0'; 00123 } 00124 } 00125 } 00126 } 00127 00128 /*Error values: 00129 * 0: success 00130 * 1: failure malloc'ing / initializing mdb struct 00131 * 2: failure opening file. 00132 * 4: failure reading line. 00133 * 8: warning reading line: no tab separator (line parsing error) 00134 * 16: warning reading line: bad section declaration 00135 * 32: warning reading line: unable to allocate material struct. 00136 * 64: warning reading line: ignored line (unallocated material struct) 00137 * 128: warning reading line: unable to allocate bowing struct 00138 * 256: warning reading line: ignored line (unallocated bowing struct) 00139 * 512: warning reading file: improper section detected (programming 00140 * error) 00141 *1024: warning reading file: no : separator in bowing materials 00142 * description. 00143 *2048: warning reading file: unable to read numeric value for property. 00144 */ 00145 struct matdb* read_matdb_dotcode(const GString *name, int* err) { 00146 #ifdef DEBUG_2 00147 fprintf(stderr, "in read_matdb_dotcode(%s, %d)\n", name->str, *err); 00148 #endif 00149 *err=0; 00150 struct matdb *mdb = (struct matdb*)malloc(sizeof(struct matdb)); 00151 if(mdb == NULL) {*err = 1; return NULL;} 00152 00153 double *value; 00154 if((mdb->materials = g_hash_table_new_full(&g_str_hash, &g_str_equal, &destroy_string, &destroy_material_gpointer)) == NULL) { 00155 *err = 1; 00156 free(mdb); 00157 return NULL; 00158 } 00159 if((mdb->bowings = g_hash_table_new_full(&g_str_hash, &g_str_equal, &destroy_string, &destroy_bowing_gpointer)) == NULL) { 00160 *err = 1; 00161 g_hash_table_unref(mdb->materials); 00162 free(mdb); 00163 return NULL; 00164 } 00165 struct matdb_material *mat = NULL; 00166 struct matdb_bowing *bow = NULL; 00167 /*Valid sections: 00168 * 0 (no/global section) 00169 * 1 (material) 00170 * 2 (bow) 00171 */ 00172 int section=0; 00173 size_t n; 00174 char *line; 00175 FILE *infile = fopen(name->str, "r"); 00176 if(infile == NULL) { 00177 g_hash_table_unref(mdb->materials); 00178 g_hash_table_unref(mdb->bowings); 00179 free(mdb); 00180 *err=2; 00181 return NULL; 00182 #ifdef DEBUG_2 00183 }else{ 00184 fprintf(stderr, "infile=%x\n", (unsigned int)infile); 00185 #endif 00186 } 00187 int val; 00188 while(!feof(infile)) { 00189 #ifdef DEBUG 00190 fprintf(stderr, "mat=%x(%s), bow=%x(%s:%s)\n", (unsigned int)mat, mat?mat->name->str:"", (unsigned int)bow, bow?bow->from->str:"", bow?bow->to->str:""); 00191 #endif 00192 line=NULL; 00193 if((val = getline(&line, &n, infile)) == -1) { 00194 #ifdef DEBUG_2 00195 fprintf(stderr, "getline returned %d\n", val); 00196 #endif 00197 if(!feof(infile)) *err = 4; 00198 //fclose(infile); 00199 break; 00200 } 00201 #ifdef DEBUG_2 00202 fprintf(stderr, "line=(%s)\n", line); 00203 #endif 00204 prettify_line(line); 00205 #ifdef DEBUG 00206 fprintf(stderr, "%d: prettified line=(%s)\n", section, line); 00207 #endif 00208 if(*line == '\0') { 00209 free(line); 00210 continue; 00211 } 00212 char *i = index(line, '\t'); 00213 if(i == NULL) { 00214 *err &= 8; 00215 } 00216 *i++ = '\0'; 00217 /*At this point, we have line which stores the first word on the 00218 line, and i which stores the second word on the line. 00219 */ 00220 char *to; 00221 GHashTable *ht; 00222 #ifdef DEBUG_2 00223 fprintf(stderr, "part_a=(%s) part_b=(%s)\n", line, i); 00224 #endif 00225 /*If we have a material or bowing underway, save it off*/ 00226 if(strcasecmp(line, "material") == 0) { 00227 insert_into_matdb(mdb, &mat, &bow); 00228 if((mat = (struct matdb_material*)malloc(sizeof(struct matdb_material))) == NULL) { 00229 *err &= 32; 00230 } 00231 if((mat->name = g_string_new(i)) == NULL) { 00232 *err &= 32; 00233 free(mat); 00234 section=0; 00235 continue; 00236 } 00237 if((mat->properties = g_hash_table_new_full(&g_str_hash, &g_str_equal, &destroy_string, &destroy_double)) == NULL) { 00238 *err &= 32; 00239 g_string_free(mat->name, TRUE); 00240 free(bow); 00241 section=0; 00242 continue; 00243 } 00244 #ifdef DEBUG_2 00245 fprintf(stderr, "new material (%s):\n", i); 00246 #endif 00247 section=1; 00248 }else if(strcasecmp(line, "bow") == 0) { 00249 insert_into_matdb(mdb, &mat, &bow); 00250 if((bow = (struct matdb_bowing*)malloc(sizeof(struct matdb_bowing))) == NULL) { 00251 *err &= 128; 00252 } 00253 if((to = index(i, ':')) == NULL) { 00254 *err &= 1024; 00255 free(bow); 00256 section=0; 00257 continue; 00258 } 00259 *to++ = '\0'; 00260 /*Same trick as before, but i now stores the from material, 00261 and to the to material 00262 */ 00263 if((bow->from = g_string_new(i)) == NULL) { 00264 *err &= 128; 00265 free(bow); 00266 section=0; 00267 continue; 00268 } 00269 if((bow->to = g_string_new(to)) == NULL) { 00270 *err &= 128; 00271 g_string_free(bow->from, TRUE); 00272 free(bow); 00273 section=0; 00274 continue; 00275 } 00276 if((bow->properties = g_hash_table_new_full(&g_str_hash, &g_str_equal, &destroy_string, &destroy_double)) == NULL) { 00277 *err &= 128; 00278 g_string_free(bow->to, TRUE); 00279 g_string_free(bow->from, TRUE); 00280 free(bow); 00281 section=0; 00282 continue; 00283 } 00284 #ifdef DEBUG_2 00285 fprintf(stderr, "new bowing (%s:%s):\n", i, to); 00286 #endif 00287 section=2; 00288 }else{ 00289 #ifdef DEBUG 00290 fprintf(stderr, "\t%d/%s\t", section, line); 00291 #endif 00292 /*Process a property.*/ 00293 switch(section) { 00294 case 1: 00295 #ifdef DEBUG 00296 fprintf(stderr, "(1)\t"); 00297 #endif 00298 ht = mat->properties; 00299 break; 00300 case 2: 00301 #ifdef DEBUG 00302 fprintf(stderr, "(2)\t"); 00303 #endif 00304 ht = bow->properties; 00305 break; 00306 default: 00307 #ifdef DEBUG 00308 fprintf(stderr, "(default)\t"); 00309 #endif 00310 *err &= 16; 00311 section = 0; 00312 } 00313 if(section == 0) { 00314 #ifdef DEBUG 00315 fprintf(stderr, "section was 0\n"); 00316 #endif 00317 continue; 00318 } 00319 if((value = (double*)malloc(sizeof(double))) == NULL) { 00320 *err &= 2048; 00321 #ifdef DEBUG 00322 fprintf(stderr, "malloc of value failed\n"); 00323 #endif 00324 continue; 00325 } 00326 int num; 00327 if((num=sscanf(i, " %lg", value)) != 1) { 00328 *err &= 2048; 00329 free(value); 00330 #ifdef DEBUG 00331 fprintf(stderr, "bad sscanf to get value (scanned \"%s\", returned %d)\n", i, num); 00332 #endif 00333 continue; 00334 } 00335 g_hash_table_insert(ht, g_strdup(line), value); 00336 #ifdef DEBUG 00337 fprintf(stderr, "%g(%s)\n", *value, line); 00338 #endif 00339 } 00340 free(line); 00341 line=i=to=NULL; 00342 value=NULL; 00343 } 00344 fclose(infile); 00345 insert_into_matdb(mdb, &mat, &bow); 00346 return mdb; 00347 } 00348 00349 00350 } 00351 } 00352 }