gimme-alpha 0.1

read_nextnano_inputfile.c

Go to the documentation of this file.
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 }
 All Classes Files Functions Variables Enumerations Enumerator Defines