|
gimme-alpha 0.1
|
00001 /* 00002 ** read_nextnano_inputfile.c 00003 ** 00004 ** Made by (Johnny Q. Hacker) 00005 ** Login <solarion@borkborkbork> 00006 ** 00007 00008 00009 Copyright (C) 2008 Joseph Pingenot 00010 00011 This program is free software: you can redistribute it and/or modify 00012 it under the terms of the GNU Affero General Public License as published by 00013 the Free Software Foundation, either version 3 of the License, or 00014 (at your option) any later version. 00015 00016 This program is distributed in the hope that it will be useful, 00017 but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 GNU Affero General Public License for more details. 00020 00021 You should have received a copy of the GNU Affero General Public License 00022 along with this program. If not, see <http://www.gnu.org/licenses/>. 00023 ** Started on Mon Sep 29 16:18:29 2008 Johnny Q. Hacker 00024 */ 00025 00026 #include <stdlib.h> 00027 #include <stdio.h> 00028 #include <string.h> 00029 00030 #include <libcommon/gcc_hints.h> 00031 #include <libnextnano/read_nextnano_inputfile.h> 00032 #include <libcommon/textfile_common.h> 00033 00034 #define DEFAULT_SECTION "default" 00035 static void destroy_chunklist(gpointer data, gpointer user_data) { 00036 //fprintf(stderr, "destroying chunklist\n"); 00037 g_hash_table_destroy(data); 00038 } 00039 static void destroy_section(gpointer data) { 00040 //fprintf(stderr, "destroying section (%p)\n", data); 00041 g_list_foreach(data, destroy_chunklist, NULL); 00042 } 00043 static void destroy_secname(gpointer data) { 00044 //fprintf(stderr, "destroying section name (%p)(%s0\n", data, (char*)data); 00045 /*Free the *line*, not just the string*/ 00046 /*Casting to char* so that we make sure the right size is counted! 00047 *Thanks, little gcc pedant!*/ 00048 free(((char*)data)-1); 00049 } 00050 static void free_nothing(gpointer data) { 00051 //fprintf(stderr, "freeing nothing\n"); 00052 } 00053 static void free_esec(char* esec) { 00054 /*free the *line*, not just the string.*/ 00055 //fprintf(stderr, "free_esec: Freeing line, not just char.\n"); 00056 free(esec-5); 00057 } 00058 static void destroy_value(gpointer data, gpointer user_data) { 00059 //fprintf(stderr, "destroying value\n"); 00060 //free(data); 00061 } 00062 static void destroy_values(gpointer data) { 00063 //fprintf(stderr, "destroying values\n"); 00064 g_list_foreach(data, destroy_value, NULL); 00065 } 00066 static void destroy_keyword_section(gpointer data) { 00067 g_hash_table_destroy(((struct nextnano_keyword_section*)data)->keywords); 00068 free((struct nextnano_keyword_section*)data); 00069 } 00070 static void destroy_keyword(gpointer data) { 00071 free((struct nextnano_keyword*)data); 00072 } 00073 static void destroy_c_string(gpointer data) { 00074 free((char*)data); 00075 } 00076 00077 00078 /*If this is a section command, returns the section name. Otherwise, NULL. 00079 *NOTE: this may be end_section. 00080 */ 00081 ___always_inline char* is_section(char* str) { 00082 if (str[0] == '$') { 00083 return &(str[1]); 00084 }else{ 00085 return NULL; 00086 } 00087 } 00088 00089 __always_inline char* get_section_end(char* str) { 00090 if(strncmp(str, "$end_", 5) == 0) 00091 return &(str[5]); 00092 else 00093 return NULL; 00094 } 00095 00096 /*Determines whether or not the key listed will start a new chunk. 00097 *ARGS: 00098 * secname: the name of the section (not currently used, but probably 00099 * important in the future when per-section customization is needed. 00100 * chunk: the current chunk being worked on 00101 * key: the key in question 00102 *RETURNS: 00103 * 0 if not a new chunk; 1 if a new chunk. 00104 **/ 00105 static int starts_new_chunk(const char* secname, GHashTable* chunk, const char* key) { 00106 if(chunk == NULL) return 1; 00107 if(g_hash_table_lookup(chunk, key) != NULL) return 1; 00108 return 0; 00109 } 00110 00111 /*! 00112 *\deprecated 00113 */ 00114 GHashTable *read_nextnano_inputfile(GInputStream *istream, GError **err) { 00115 GHashTable *h = read_nextnano_inputfile_stringy(istream, err); 00116 if((h == NULL) || (*err != NULL)) return NULL; 00117 fprintf(stderr, "WARNING: read_nextnano_inputfile: datatype conversion not yet implemented. Returning stringy data.\n"); 00118 return h; 00119 } 00120 00121 static void print_key_value_item(gpointer data, gpointer userdata) { 00122 fprintf(stderr, "\t%s", (char*)data); 00123 } 00124 00125 static void print_key_value_lists(gpointer data, gpointer userdata) { 00126 g_list_foreach(data, print_key_value_item, userdata); 00127 fprintf(stderr, "\n"); 00128 } 00129 00130 00131 /*! 00132 *\brief this is the core function which processes a nextnano input file. 00133 *\param istream pointer to a GInputStream to read from 00134 *\param GError pointer to a GError to store the last error 00135 *\return GHashTable containing the (stringy) processed input file. 00136 */ 00137 GHashTable *read_nextnano_inputfile_stringy_core(GInputStream *istream, GError **err) { 00138 GDataInputStream *in = g_data_input_stream_new(istream); 00139 GHashTable *sections = g_hash_table_new_full(g_str_hash, g_str_equal, destroy_secname, destroy_section); 00140 if(unlikely(sections == NULL)) return NULL; 00141 char *str; 00142 char *sname = NULL; 00143 gsize len; 00144 char *sec; 00145 char *esec; 00146 char *key; 00147 char *value; 00148 GList *def = NULL; 00149 int n; 00150 int goodclose; 00151 /*Current section*/ 00152 GList *s = NULL; 00153 /*Current chunk*/ 00154 GHashTable *chunk = NULL; 00155 char *saveptr; 00156 /*Current value list.*/ 00157 GList *val = NULL; 00158 GList *tmp = NULL; 00159 00160 while((str = g_data_input_stream_read_line(in, &len, NULL, err)) != NULL) { 00161 prettify_line(str, '!'); 00162 if((strlen(str)) == 0) continue; 00163 //fprintf(stderr, "read_nextnano_inputfile: got line (%s)\n", str); 00164 if((sec = is_section(str)) == NULL) { 00165 //fprintf(stderr, "*is not a section(%s)\n", str); 00166 /*Not the beginning or end of a new section.*/ 00167 GList *v = get_key_value_pairs(str, "="); 00168 /* 00169 fprintf(stderr, "key/value list for %s:\n", str); 00170 g_list_foreach(v, print_key_value_lists, NULL); 00171 printf("\n"); 00172 */ 00173 if(v == NULL) continue; 00174 GList *c; 00175 if((g_list_first(v)->data != NULL)) { 00176 //fprintf(stderr, "APPENDING APPENDED DATA\n"); 00177 /*This ought to preserve the head of val.*/ 00178 val = g_list_concat(val, g_list_first(v)->data); 00179 } 00180 /*Go through the list of key/value sets and add them to the list.*/ 00181 for(c = g_list_next(v); c != NULL; c = g_list_next(c)) { 00182 GList *sl = c->data; 00183 GList *kl = g_list_first(sl); 00184 /* 00185 fprintf(stderr, "\tsl(%p)=%s\n", sl, (char*)((sl == NULL)?NULL:sl->data)); 00186 fprintf(stderr, "*is a new value/key pair: "); 00187 */ 00188 key = kl->data; 00189 //fprintf(stderr, "\tsl=%p\n", sl); 00190 sl = g_list_remove_link(g_list_first(sl), kl); 00191 //fprintf(stderr, "\tAfter remove_link, sl=%p\n", sl); 00192 //fprintf(stderr, "key=%s", key); 00193 if(sname == NULL) { 00194 fprintf(stderr, "WARNING in read_nextnano_inputfile: have data but does not belong to a section! Assuming section \"%s\".\n", DEFAULT_SECTION); 00195 /*If there's no "default" section, create it, add it, then add 00196 the data.*/ 00197 sname = DEFAULT_SECTION; 00198 } 00199 //fprintf(stderr, "*section is: %s\n", sname); 00200 /*Create a new chunk if we need one; save off the current 00201 chunk if we're starting a new one.*/ 00202 if((chunk == NULL) || starts_new_chunk(sname, chunk, key)) { 00203 //fprintf(stderr, "*is a new chunk\n"); 00204 /*We've not yet started a chunk.*/ 00205 chunk = g_hash_table_new_full(g_str_hash, g_str_equal, free, destroy_values); 00206 /*Go ahead and add the chunk to the section now; 00207 * we'll still have the pointer around later to add to the 00208 * chunk. 00209 */ 00210 s = g_list_append(s, chunk); 00211 } 00212 val = sl; 00213 g_hash_table_replace(chunk, key, val); 00214 } 00215 //fprintf(stderr, "\n*done with key/value pair line.\n"); 00216 }else{ 00217 esec=get_section_end(str); 00218 if((esec != NULL) || ((sec != NULL) && (sname != NULL))) { 00219 if(esec != NULL){ 00220 if(sname == NULL) { 00221 fprintf(stderr, "WARNING: got a request to end section (%s) but there was no section currently open!\n", esec); 00222 continue; 00223 }else if(strcmp(esec, sname) != 0) { 00224 fprintf(stderr, "WARNING: got a request to end section (%s) but a different section is currently open (%s)!\n", esec, sname); 00225 } 00226 }else{ 00227 fprintf(stderr, "WARNING: got a request to start a new section (%s) but a section is still open (%s)!\n", sec, sname); 00228 } 00229 /*Now close the section*/ 00230 //fprintf(stderr, "\tinserting %s(%p) into hash table %p\n", sname, (void*)s, (void*)sections); 00231 if((tmp = g_hash_table_lookup(sections, sname)) == NULL) { 00232 g_hash_table_replace(sections, sname, g_list_append(NULL, s)); 00233 }else{ 00234 tmp = g_list_append(tmp, s); 00235 } 00236 s = NULL; 00237 sname = NULL; 00238 }else{ 00239 sname=sec; 00240 } 00241 if(esec != NULL) free_esec(esec); 00242 esec = NULL; 00243 sec=NULL; 00244 s = NULL; 00245 val = NULL; 00246 chunk = NULL; 00247 } 00248 } 00249 00250 if(sname != NULL) { 00251 fprintf(stderr, "WARNING: section (%s) wasn't ended before the end of the file.\n", sname); 00252 if((tmp = g_hash_table_lookup(sections, sname)) == NULL) { 00253 g_hash_table_replace(sections, sname, g_list_append(NULL, s)); 00254 }else{ 00255 tmp = g_list_append(tmp, s); 00256 } 00257 s = NULL; 00258 sname = NULL; 00259 } 00260 g_object_unref(in); 00261 return sections; 00262 } 00263 00264 void static print_valueitem(gpointer data, gpointer userdata) { 00265 printf("print_valueitem: data=%p userdata=%p\n", data, userdata); 00266 if(*((int*)userdata)) { 00267 printf("\t\t%s\n", (char*)data); 00268 }else{ 00269 char *format; 00270 switch(((struct nextnano_value*)data)->t) { 00271 INT: format="\t\t%d\n"; break; 00272 DOUBLE: format="\t\t%g\n"; break; 00273 STRING: format="\t\t%s\n"; break; 00274 default: 00275 fprintf(stderr, "PROGRMMING ERROR: unable to recognize value type (%d). Skipping.\n", ((struct nextnano_value*)data)->t); 00276 return; 00277 }; 00278 printf(format, ((struct nextnano_value*)data)->store); 00279 } 00280 } 00281 00282 void static print_value(gpointer key, gpointer data, gpointer userdata) { 00283 printf("print_value: key=%p data=%p userdata=%p\n", key, data, userdata); 00284 printf("\t(%s)\n", (char*)key); 00285 g_list_foreach(data, print_valueitem, userdata); 00286 } 00287 00288 void static print_chunk(gpointer data, gpointer userdata){ 00289 printf("print_chunk: data=%p userdata=%p\n", data, userdata); 00290 g_hash_table_foreach(data, print_value, userdata); 00291 printf("\n"); 00292 } 00293 00294 void static print_section(gpointer key, gpointer value, gpointer userdata){ 00295 fprintf(stderr, "print_section: key=%p value=%p userdata=%p\n", key, value, userdata); 00296 printf("[%s]\n", (char*)key); 00297 g_list_foreach(value, print_chunk, userdata); 00298 } 00299 00300 void print_stringy_inputfile(GHashTable *h) { 00301 int stringy = 1; 00302 g_hash_table_foreach(h, print_section, &stringy); 00303 } 00304 00305 void print_finalized_inputfile(GHashTable *h) { 00306 int stringy = 0; 00307 g_hash_table_foreach(h, print_section, &stringy); 00308 } 00309 00310 GHashTable *read_nextnano_dbfile(GInputStream *istream, GError **err) { 00311 GHashTable *ht = read_nextnano_inputfile_stringy_core(istream, err); 00312 if(ht == NULL) return ht; 00313 /*Convert the strings to numbers here.*/ 00314 return ht; 00315 } 00316 00317 00318 static void stick_this_in_the_hash(gpointer key, gpointer data, gpointer hash) { 00319 g_hash_table_insert(hash, key, data); 00320 } 00321 00322 /*! 00323 *\deprecated 00324 */ 00325 GHashTable *read_nextnano_inputfile_stringy(GInputStream *istream, GError **err) { 00326 GHashTable *ht = read_nextnano_inputfile_stringy_core(istream, err); 00327 GHashTableIter hit; 00328 g_hash_table_iter_init(&hit, ht); 00329 gpointer key, value; 00330 GHashTable *tempt = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL); 00331 while(g_hash_table_iter_next(&hit, &key, &value)) { 00332 if(unlikely(g_list_length(((GList*) value)) != 1)) { 00333 if(unlikely(g_list_length(((GList*) value)) < 1)) { 00334 fprintf(stderr, "WARNING: PROGRAMMING ERROR: the list for section %s was empty! This should never happen!\n", (char*)key); 00335 continue; 00336 } 00337 fprintf(stderr, "WARNING: there are duplicate definitions of section %s. Will be assuming the last definition of the section.\n", (char*)key); 00338 } 00339 g_hash_table_iter_steal(&hit); 00340 g_hash_table_replace(tempt, key, (g_list_last((GList*)value))->data); 00341 /*Free the list structures for the top-level list. They're no 00342 longer needed.*/ 00343 g_list_free((GList*)value); 00344 //fprintf(stderr, "Raised chunklist to top-level for %s\n", (char*)key); 00345 } 00346 g_hash_table_foreach(tempt, stick_this_in_the_hash, ht); 00347 g_hash_table_steal_all(tempt); 00348 return ht; 00349 } 00350 00351 /*! 00352 *\brief Returns the list for a specific part of the input file. 00353 *\param section name of the section you want 00354 *\param secnum There may be multiple sections that match the name. 00355 * This specifies which one you want (in order of 00356 * occurrance) 00357 *\param chunknum There may be multiple chunks of key/value lists within 00358 * each section. This specifies which which one you 00359 * want (in order of occurrance) (NOTE: first chunk is 00360 * chunk 0) 00361 *\param key Specifies the key within the section. 00362 *\return 00363 * The list associated with the requested key. 00364 * NULL if the key wasn't found. 00365 */ 00366 GList* read_nextnano_extract_list_db(GHashTable *input, char* section, int secnum, int chunknum, char* key) { 00367 return NULL; 00368 } 00369 00370 /*Same as read_nextnano_extract_list_db, but does not allow for 00371 multiple sections with the same name (for input puts, not db puts) 00372 * ERROR CODES: 00373 * 0: if returned non-NULL, success 00374 * 0: if returned NULL, there was no such key. 00375 * 1: section doesn't exist. 00376 * 2: there was no such chunknum (key/value set) 00377 */ 00378 00379 GList* read_nextnano_extract_list(GHashTable *input, char* section, int chunknum, char* key, int *err) { 00380 GList *chunk = g_hash_table_lookup(input, section); 00381 if(chunk == NULL) { 00382 //fprintf(stderr, "chunk was NULL\n"); 00383 *err = 1; 00384 return NULL; 00385 } 00386 GHashTable *kv_set = g_list_nth_data(g_list_first(chunk), chunknum); 00387 if(kv_set == NULL) { 00388 //fprintf(stderr, "kv_set was NULL\n"); 00389 *err = 2; 00390 return NULL; 00391 } 00392 //if(g_hash_table_lookup(kv_set, key) == NULL) {fprintf(stderr, "Unable to find key %s in chunk.\n", key);} 00393 /*g_hash_table_lookup returns NULL if not found, which is a valid 00394 * 0-length list. */ 00395 *err = 0; 00396 return g_list_first(g_hash_table_lookup(kv_set, key)); 00397 } 00398 00399 /*Same as read_nextnano_extract_list, but converts to type. 00400 *Same error codes, but 00401 * 10: couldn't convert to type. 00402 */ 00403 GList* read_nextnano_extract_list_typed(GHashTable *input, char* section, int chunknum, char* key, int *err, enum data_types type) { 00404 GList *c; 00405 GList *l = NULL; 00406 if(unlikely((c=read_nextnano_extract_list(input, section, chunknum, key, err)) == NULL)) { 00407 return NULL; 00408 } 00409 void *v; 00410 for(l = c; l != NULL; l = g_list_next(l)) { 00411 v = string_to_data(c->data, type); 00412 if(unlikely(v == NULL)) { 00413 *err = 10; 00414 } 00415 l->data = v; 00416 } 00417 return c; 00418 } 00419 00420 /*Returns the first value in the key/value list. If there are 00421 * multiple key/value lists, err is set to 1. 00422 *ARGS: 00423 * same as read_nextnano_extract_list 00424 * err pointer to an int to store the error. 00425 *RETURNS: 00426 * the item, or NULL if it wasn't found. 00427 *ERR VALUES: 00428 * Same as read_nextnano_extract_list, except 00429 * 20: List had incorrect (likely more than 1; could be 0?) number of items. 00430 */ 00431 char* read_nextnano_extract_item(GHashTable *input, char* section, int chunknum, char* key, int* err) { 00432 GList *values = read_nextnano_extract_list(input, section, chunknum, key, err); 00433 if(values == NULL) { 00434 return NULL; 00435 } 00436 if(g_list_length(g_list_first(values)) != 1) { 00437 *err = 20; 00438 return NULL; 00439 } 00440 *err = 0; 00441 return g_list_first(values)->data; 00442 } 00443 00444 /*Same as above, but now converts types, as requested. 00445 *ERROR CODES: 00446 * Same as above, but with: 00447 * 10: Failed to convert data type from string 00448 */ 00449 void* read_nextnano_extract_item_typed(GHashTable *input, char* section, int chunknum, char* key, int* err, enum data_types type) { 00450 char *c; 00451 if(unlikely((c=read_nextnano_extract_item(input, section, chunknum, key, err)) == NULL)) { 00452 return NULL; 00453 } 00454 void *v = string_to_data(c, type); 00455 if(unlikely(v == NULL)) { 00456 *err = 10; 00457 } 00458 return v; 00459 } 00460 00461 00462 /*! 00463 *\brief gets the type from a string specifying the type. 00464 *\param s string to convert to a type 00465 *\returns enum data_types representing the type.(see gimme_alpha_types.h) 00466 *\warning assumes s to be null-terminated. 00467 *\note grep -v '^ *\!' keywords.in | grep -v '^ *\$' | sed 's/ *!.*$//g' | sed 's/ +/ /g' | grep -v '^$' | sed 's/_array//g' | awk '{print $2;}' | sort | uniq -c | less 00468 * 13 00469 * 232 character 00470 * 654 double 00471 * 195 integer 00472 * 1 logical 00473 *\attetion default is to be a string type, i.e. unconverted. 00474 */ 00475 enum data_types get_type_from_string(const char* s) { 00476 if(!(strcasecmp(s, "double"))) { 00477 return DOUBLE_TYPE; 00478 }else if(!(strcasecmp(s, "double_array"))) { 00479 return DOUBLE_TYPE; 00480 }else if(!(strcasecmp(s, "character"))) { 00481 return STRING_TYPE; 00482 }else if(!(strcasecmp(s, "integer"))) { 00483 return INT_TYPE; 00484 }else if(!(strcasecmp(s, "integer_array"))) { 00485 return INT_TYPE; 00486 }else if(!(strcasecmp(s, "logical"))) { 00487 return BOOLEAN_TYPE; 00488 }else if(!(strcasecmp(s, "logical_array"))) { 00489 return BOOLEAN_TYPE; 00490 }else{ 00491 g_warning("didn't recognize type %s; assuming string to preserve the information", s); 00492 return STRING_TYPE; 00493 } 00494 } 00495 00496 /*! 00497 *\brief determines if a keyword or section is required or optional. 00498 *\param s string containing either "optional" or "required" 00499 *\return 0 if optional, 1 if required, 2 if uncertain what was meant. 00500 *\note 00501 * 13 00502 * 955 optional 00503 * 127 required 00504 */ 00505 short int is_required(const char* s) { 00506 if(!(strcasecmp(s, "optional"))) { 00507 return 0; 00508 }else if(!(strcasecmp(s, "required"))) { 00509 return 1; 00510 } 00511 g_warning("read_nextnano_inputfile.c::is_required: got unknown requirement string (%s)", s); 00512 return 2; 00513 } 00514 00515 /*! 00516 *\brief processes a line which contains a keyword, and outputs a keyword structure and key name. 00517 *\param line line of input 00518 *\param key pointer to a pointer to a string to hold the key name 00519 *\return pointer to struct nextnano_keyword which has the keyword information. 00520 */ 00521 struct nextnano_keyword* get_keyword_from_line(const char* line, char** key, int seqnum) { 00522 struct nextnano_keyword* keyword = malloc(sizeof(struct nextnano_keyword)); 00523 *key = NULL; 00524 if(unlikely(keyword == NULL)) return NULL; 00525 gchar **set = g_strsplit_set(line, " \t", 4); 00526 if(unlikely(set[0] == NULL)) {free(keyword); return NULL;} 00527 if(unlikely(set[1] == NULL)) {free(keyword); free(set[0]); return NULL;} 00528 if(unlikely(set[2] == NULL)) {free(keyword); free(set[0]); free(set[1]); return NULL;} 00529 /*if we have 4 sections, we have too many!*/ 00530 if(unlikely(set[3] != NULL)) {free(keyword); free(set[0]); free(set[1]); free(set[2]); free(set[3]); return NULL;} 00531 keyword->t = get_type_from_string(set[1]); 00532 if(unlikely((keyword->required = is_required(set[2])) == 2)) { 00533 free(keyword); 00534 free(set[0]); 00535 free(set[1]); 00536 free(set[2]); 00537 free(set[3]); 00538 return NULL; 00539 } 00540 *key = set[0]; 00541 keyword->seqnum = seqnum; 00542 return keyword; 00543 } 00544 00545 /*! 00546 *\brief processes a line which contains the start of a keyword section, and outputs a keyword structure and key name. 00547 *\param line line of input 00548 *\param secname pointer to a pointer to a string to hold the key name 00549 *\return pointer to struct nextnano_keyword_section which has the keyword information. 00550 */ 00551 struct nextnano_keyword_section* get_keyword_section_from_line(const char* line, char** secname) { 00552 struct nextnano_keyword_section* keyword_section = malloc(sizeof(struct nextnano_keyword_section)); 00553 *secname = NULL; 00554 if(unlikely(keyword_section == NULL)) return NULL; 00555 gchar **set = g_strsplit_set(line, " \t", 3); 00556 //fprintf(stderr, "set[0]=%s set[1]=%s set[2]=%s\n", (set[0]==NULL)?"(null)":set[0], (set[1]==NULL)?"(null)":set[1], (set[2]==NULL)?"(null)":set[2]); 00557 if(unlikely(set[0] == NULL)) {free(keyword_section); return NULL;} 00558 if(unlikely(set[1] == NULL)) {free(keyword_section); free(set[0]); return NULL;} 00559 /*if we have 3 sections, we have too many!*/ 00560 if(unlikely(set[2] != NULL)) {free(keyword_section); free(set[0]); free(set[1]); free(set[2]); return NULL;} 00561 if(unlikely((keyword_section->required = is_required(set[1])) == 2)) { 00562 free(keyword_section); 00563 free(set[0]); 00564 free(set[1]); 00565 return NULL; 00566 } 00567 /*We're done with the optional/required keyword*/ 00568 free(set[1]); 00569 keyword_section->keywords = g_hash_table_new_full(g_str_hash, g_str_equal, destroy_c_string, destroy_keyword); 00570 *secname = set[0]; 00571 return keyword_section; 00572 } 00573 00574 /*!\brief struct for the keyword_sequence_search_foreach_callback 00575 */ 00576 struct keyword_sequence_search_foreach_info { 00577 int sought; 00578 char* found; 00579 }; 00580 /*!\brief Static helper function for 00581 */ 00582 void keyword_sequence_search_foreach_callback(gpointer key, gpointer value, gpointer data) { 00583 /*wordy, but straightforward; if seqnum = sought, found = key)*/ 00584 if((((struct nextnano_keyword*)value)->seqnum) == (((struct keyword_sequence_search_foreach_info*)data)->sought)) { 00585 (((struct keyword_sequence_search_foreach_info*)data)->found) = key; 00586 fprintf(stderr, "Y: key=%s seqnum=%d sought=%d\n", (char*)key, ((struct nextnano_keyword*)value)->seqnum, (((struct keyword_sequence_search_foreach_info*)data)->sought)); 00587 }else{ 00588 fprintf(stderr, "N: key=%s seqnum=%d sought=%d\n", (char*)key, ((struct nextnano_keyword*)value)->seqnum, (((struct keyword_sequence_search_foreach_info*)data)->sought)); 00589 } 00590 } 00591 00592 /*! 00593 *\brief reads in a nextnano inputfile, as it should be. 00594 *\param basedir pointer to GFile with the project base directory 00595 *\param keys ptr to GHashTable containing the processed keywords file 00596 *\param inputfile integer, "sequence number" of the input file to postprocess 00597 *\param err ptr to ptr to GError for file read errors 00598 *\return GHashTable containing the fully postprocessed input file 00599 *\attention use this version; the original (GInputStream) version is deprecated. 00600 */ 00601 GHashTable *read_nextnano_inputfile2(GFile *basedir, GHashTable *keys, int inputfile, GError **err, char** filename) { 00602 *filename = NULL; 00603 if(unlikely((keys == NULL) || (basedir == NULL) || (err == NULL))) return NULL; 00604 struct keyword_sequence_search_foreach_info kssfi = {.sought = inputfile, .found = NULL}; 00605 g_hash_table_foreach(g_hash_table_lookup(keys, "input_filename"), keyword_sequence_search_foreach_callback, &kssfi); 00606 if(kssfi.found == NULL) return NULL; 00607 GFile* infile = g_file_get_child(basedir, kssfi.found); 00608 GFileInputStream *istream = g_file_read(infile, NULL, err); 00609 if(*err != NULL) return NULL; 00610 GHashTable *ht = read_nextnano_inputfile(G_INPUT_STREAM(istream), err); 00611 GError *e = NULL; 00612 g_input_stream_close(G_INPUT_STREAM(istream), NULL, &e); 00613 /*If we fail to close the stream, we almost certainly have bigger 00614 *issues to worry about! Let the user know of *those* errors, not 00615 *the close failure*/ 00616 if(e != NULL) g_error_free(e); 00617 g_object_unref(infile); 00618 *filename = kssfi.found; 00619 return ht; 00620 } 00621 /*! 00622 *\attention Use this variant; the normal version is DEPRECATED*/ 00623 GHashTable *read_nextnano_inputfile_stringy2(GFile* basedir, GHashTable *keys, int inputfile, GError **err) { 00624 if(unlikely((keys == NULL) || (basedir == NULL) || (err == NULL))) return NULL; 00625 struct keyword_sequence_search_foreach_info kssfi = {.sought = inputfile, .found = NULL}; 00626 g_hash_table_foreach(keys, keyword_sequence_search_foreach_callback, &kssfi); 00627 if(kssfi.found == NULL) return NULL; 00628 GFile* infile = g_file_get_child(basedir, kssfi.found); 00629 GFileInputStream *istream = g_file_read(infile, NULL, err); 00630 if(*err != NULL) return NULL; 00631 GHashTable *ht = read_nextnano_inputfile_stringy(G_INPUT_STREAM(istream), err); 00632 GError *e = NULL; 00633 g_input_stream_close(G_INPUT_STREAM(istream), NULL, &e); 00634 /*If we fail to close the stream, we almost certainly have bigger 00635 *issues to worry about! Let the user know of *those* errors, not 00636 *the close failure*/ 00637 if(e != NULL) g_error_free(e); 00638 g_object_unref(infile); 00639 return ht; 00640 } 00641 GHashTable *read_nextnano_dbfile2(GFile* basedir, GError **err) { 00642 GFile* dbfile = g_file_get_child(basedir, "database.in"); 00643 GFileInputStream *dbstream = g_file_read(dbfile, NULL, err); 00644 if(*err != NULL) return NULL; 00645 GHashTable *ht = read_nextnano_dbfile(G_INPUT_STREAM(dbstream), err); 00646 GError *e = NULL; 00647 g_input_stream_close(G_INPUT_STREAM(dbstream), NULL, &e); 00648 /*If we fail to close the stream, we almost certainly have bigger 00649 *issues to worry about! Let the user know of *those* errors, not 00650 *the close failure*/ 00651 if(e != NULL) g_error_free(e); 00652 g_object_unref(dbfile); 00653 return ht; 00654 } 00655 /*! 00656 *\brief reads in a keywords.in file from an istream 00657 *\param basedir directory in which the project is based 00658 *\param GError pointer to a pointer to use to store the last i/o error. 00659 *\return a GHashTable containing the sections of the inputfile. 00660 */ 00661 GHashTable *read_nextnano_keyfile2(GFile* basedir, GError **err) { 00662 GFile* keyfile = g_file_get_child(basedir, "keywords.in"); 00663 GFileInputStream *keystream = g_file_read(keyfile, NULL, err); 00664 if(*err != NULL) return NULL; 00665 GDataInputStream *in = g_data_input_stream_new((GInputStream*)keystream); 00666 GHashTable *sections = g_hash_table_new_full(g_str_hash, g_str_equal, destroy_c_string, destroy_keyword_section); 00667 if(unlikely(sections == NULL)) return NULL; 00668 char *str; 00669 char *sname = NULL; 00670 gsize len; 00671 char *sec; 00672 char *esec; 00673 char *key; 00674 GList *def = NULL; 00675 int n; 00676 int goodclose; 00677 /*Current chunk*/ 00678 char *saveptr; 00679 /*Current value list.*/ 00680 GList *val = NULL; 00681 GList *tmp = NULL; 00682 int seqnum = 1; 00683 struct nextnano_keyword_section *section = NULL; 00684 struct nextnano_keyword *keyword; 00685 while((str = g_data_input_stream_read_line(in, &len, NULL, err)) != NULL) { 00686 prettify_line(str, '!'); 00687 if((strlen(str)) == 0) continue; 00688 //fprintf(stderr, "read_nextnano_inputfile: got line (%s)\n", str); 00689 if((sec = is_section(str)) == NULL) { 00690 if(section == NULL) { 00691 *err = g_error_new_literal(DOMAIN_READ_NEXTNANO_INPUTFILE, ERR_NO_START_SECTION, "read_nextnano_inputfile.c::read_nextnano_keyfile2: Error reading keywords.in: there was no section given for these keywords!"); 00692 g_hash_table_destroy(sections); 00693 return NULL; 00694 } 00695 keyword = get_keyword_from_line(str, &key, seqnum++); 00696 if(keyword == NULL) { 00697 /*Note that the seqnum won't get decrement if we fail to parse 00698 *the line; it's still a line, valid or not*/ 00699 *err = g_error_new(DOMAIN_READ_NEXTNANO_INPUTFILE, ERR_BAD_KEYWORD_LINE, "read_nextnano_inputfile.c::read_nextnano_keyfile2: Error reading keywords.in: failed to parse malformed keyword line (%s)", str); 00700 g_hash_table_destroy(sections); 00701 return NULL; 00702 } 00703 g_hash_table_replace(section->keywords, key, keyword); 00704 }else{ 00705 esec=get_section_end(str); 00706 if((esec != NULL) || ((sec != NULL) && (sname != NULL))) { 00707 if(esec != NULL){ 00708 char *tesec; 00709 struct nextnano_keyword_section *tmps = get_keyword_section_from_line(esec, &tesec); 00710 g_hash_table_destroy(tmps->keywords); 00711 free(tmps); 00712 if(sname == NULL) { 00713 g_warning("read_nextnano_inputfile.c::read_nextnano_keyfile2: got a request to end section (%s) but there was no section currently open!\n", esec); 00714 free(tesec); 00715 continue; 00716 }else if(strcmp(tesec, sname) != 0) { 00717 g_warning("read_nextnano_inputfile.c::read_nextnano_keyfile2: got a request to end section (%s) but a different section is currently open (%s)!\n", esec, sname); 00718 } 00719 free(tesec); 00720 }else{ 00721 g_warning("read_nextnano_inputfile.c::read_nextnano_keyfile2: got a request to start a new section (%s) but a section is still open (%s)!\n", sec, sname); 00722 } 00723 /*Now close the section*/ 00724 //fprintf(stderr, "\tinserting %s(%p) into hash table %p\n", sname, (void*)s, (void*)sections); 00725 g_hash_table_replace(sections, sname, section); 00726 sname = NULL; 00727 }else{ 00728 /*New section*/ 00729 if(unlikely((section = get_keyword_section_from_line(sec, &sname)) == NULL)) { 00730 g_warning("read_nextnano_inputfile.c::read_nextnano_keyfile2: failed to parse section name (%s)!", sec); 00731 /*Sequence numbers start at 1.*/ 00732 } 00733 seqnum=1; 00734 } 00735 if(esec != NULL) free_esec(esec); 00736 esec = NULL; 00737 sec=NULL; 00738 seqnum=1; 00739 } 00740 } 00741 00742 if(sname != NULL) { 00743 g_warning("read_nextnano_inputfile.c::read_nextnano_keyfile2: section (%s) wasn't ended before the end of the file.\n", sname); 00744 g_hash_table_replace(sections, sname, section); 00745 sname = NULL; 00746 } 00747 GError *e = NULL; 00748 g_input_stream_close(G_INPUT_STREAM(keystream), NULL, &e); 00749 /*If we fail to close the stream, we almost certainly have bigger 00750 *issues to worry about! Let the user know of *those* errors, not 00751 *the close failure*/ 00752 if(e != NULL) 00753 g_error_free(e); 00754 g_object_unref(in); 00755 return sections; 00756 }