/*
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Library General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include "config_option.h"

unsigned int parse_config_file(const char *filename) {
/* -----------------------------------------------------------------------------
 * Parse a config file and create all option
 * 
 * @param  const char *, the filename
 * @param  int
 * -------------------------------------------------------------------------- */
  FILE * stream;
  char *buffer = NULL;
  struct chain_string *strings = NULL, *strings_value = NULL, *strings_tmp = NULL;
  char *parameter_name = NULL, *parameter_value = NULL, *one_value = NULL;
  char *old_parameter_name = NULL;
  int nb_chain_string = 0, int_val = 0;
  
  stream = fopen(filename, "r");
  if (stream == NULL) {
    return 0;
  }
  
  safefgets(&buffer, FGETS_BUF_SIZE, stream);
  while(!feof(stream)) {
  /* On a lu une ligne dans le fichier */
    if ((*buffer != '#')
    && (*buffer != '\r')
    && (*buffer != '\n')) {
    /* On skippe les lignes vides et les lignes commentées */     
      stripcrlf(buffer);
      strings = explode_to_chain_string(buffer, "=");
      nb_chain_string = get_nb_chain_string(strings);
      /* Format type :
        name = string value
        name = int value
        name = string value1, string value2, string value3
        name = string value1
               string value2
               string value3
      */
      if (nb_chain_string >= 2) {
      /* On est sur un paramètre */        
        parameter_name = trim(get_chain_string(strings, 0)->value);
        parameter_value = trim(get_chain_string(strings, 1)->value);
        
        strings_value = explode_to_chain_string(parameter_value, ",");
        nb_chain_string = get_nb_chain_string(strings_value);
        if (nb_chain_string >= 2) {
        /* On est sur un paramètre multi valeurs */
          for (strings_tmp = strings_value; strings_tmp != NULL; strings_tmp = strings_tmp->next) {
            one_value = trim(strings_tmp->value);
            if ((int_val = str2int(one_value)) == -1)
              add_option(parameter_name, OPTION_STRING, one_value);
            else
              add_option(parameter_name, OPTION_INT, &int_val);
            free(one_value);
          }
        }
        else {
        /* On est sur un paramètre à une seule valeur */
          if (*parameter_value) {
            if ((int_val = str2int(parameter_value)) == -1)
              set_option(parameter_name, OPTION_STRING, parameter_value);
            else
              set_option(parameter_name, OPTION_INT, &int_val);
          }
        }
        
        free(old_parameter_name);
        old_parameter_name = strdup(parameter_name);
        if (old_parameter_name == NULL)
          return 0;
        
        free(parameter_name);
        free(parameter_value);
        
        drop_all_chain_string(strings_value);
        strings_value = NULL;
      }
      else if (((*buffer == ' ') || (*buffer == '\t'))
      && (old_parameter_name != NULL)) {
      /* On est sur un paramètre multi valeurs, sur plusieurs lignes */
        parameter_value = trim(get_chain_string(strings, 0)->value);
        if (*parameter_value) {
          if ((int_val = str2int(parameter_value)) == -1)
            add_option(old_parameter_name, OPTION_STRING, parameter_value);
          else
            add_option(old_parameter_name, OPTION_INT, &int_val);
        }
        free(parameter_value);
      }
      
      drop_all_chain_string(strings);
      strings = NULL;
    }
    free(buffer);
    buffer = NULL;
    safefgets(&buffer, FGETS_BUF_SIZE, stream);
  }
  free(old_parameter_name);
  free(buffer);
  fclose(stream);
  return 1;
  
}

size_t safefgets(char **buffer, int size, FILE * stream) {
/* -----------------------------------------------------------------------------
 * Safe implementation of fgets()
 * 
 * @param  char **, address to the buffer to fill and dynamically allocated
 * @param  int, block size for fread()
 * @param  FILE *, the file stream
 * @param  size_t, number of character read
 * -------------------------------------------------------------------------- */	
  
  char *tmp_buffer = NULL;
  char *buffer2 = NULL;
  int i = 0;
  size_t size_read = 0;
  size_t total_size_read = 0;
 
  tmp_buffer = (char *)malloc((size + 1) * sizeof(char));
  if (tmp_buffer == NULL)
    return -1;
  
  for (;;) {
    size_read = fread(tmp_buffer, sizeof(char), size, stream);
    if ((size_read <= 0) || (ferror(stream)))
      return -1;
    total_size_read += size_read;
    
    buffer2 = (char *)realloc(*buffer, (total_size_read + 1) * sizeof(char));
    if (buffer2 == NULL)
      return -1;
    *buffer = buffer2;
    memcpy(*buffer + total_size_read - size_read, tmp_buffer, size_read * sizeof(char));
    for(i = 0; i < size_read; i++) {
      if (tmp_buffer[i] == '\n') {
        break;
      }
    }
    if (i < size_read) {
    /* On a récupéré une ligne */
      *(*buffer + total_size_read - size_read + i + 1) = '\0';
      fseek(stream, i - size_read + 1, SEEK_CUR);
      free(tmp_buffer);
      return total_size_read - size_read + i + 1;
    }
    if (feof(stream)) {
      free(tmp_buffer);
      return total_size_read;
    }
  }
}


syntax highlighted by Code2HTML, v. 0.9.1