// 
// Two C functions to read from and write to ini-files.
//
// All code was written by Roman Hoegg, 2006 (romanh_at_gmx_dot_ch )
// You may use this code for whatever you like
//
// Of course, it would be cool if you would send me an email if the
// code was helpful to you. (but you don't _have_ to do that.)
//
// (the code works in windows. Don't know about other OS'...)
//
// Places where I found "inspiration" and help:
// http://www.cl.uni-heidelberg.de/kurs/ws02/prog2/html/page029.html
// http://www.thescripts.com/forum/threadnav214876-1-10.html
// and of course the gamedev.net forums!!!
// thanks!!!
//
// The test.ini file could look something like this:
// 
// [Section1]
// ;lines that start with ";" are considered comments and are skipped
// [Section2]
// ;a blank space (" ") is expected before and after "="
// Entry1 = some value
// Entry2 = some other value
// Entry3 = yet another value
// [Section3]
// [Section4]
// [Section5]
// [Section6]
// 

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#define INI_FILENAME "test.ini" // name of the ini file
#define MAX_LENGTH_OF_LINE 100  // maximum length of a line

char *readFromINI(char *iniFile, char *section, char *entry)
{
  char buffer[MAX_LENGTH_OF_LINE];  // = holds the content of current line
  char *foundSection;  // = picking out the section name
  char *foundEntry;  // = picking out the entry name
  int sectionLength = 0;
  int entryLength = 0;
  bool sectionFound = false;

  FILE *cfgFile=fopen(iniFile, "r"); //open the file

  if (!cfgFile) { // if file doesn't exist do something...
    // insert error routine here...
    return 0;
  } 

  //go through the lines of the ini
  while (fgets(buffer, MAX_LENGTH_OF_LINE, cfgFile))
  {
    if (buffer[0]==';') {continue;} // skip comments

    if(sectionFound == false)
    {
      foundSection = buffer;
      while (*foundSection && *foundSection!='[') {foundSection++;}
      if (*foundSection!='[') {continue;}
      *foundSection++ = 0; // delete "["
      
      while (*foundSection && *foundSection!=']') {foundSection++; sectionLength++;}
      if (*foundSection!=']') {continue;}
      *foundSection++ = 0; // delete "]"
      
      while (*foundSection) {foundSection++;}  *--foundSection = 0;
      
      for(int i = sectionLength+1; i > 0; i--){foundSection--;}
      sectionLength = 0;
      
      if (strcmp(foundSection, section) == 0) // compare the char arrays
       {
         sectionFound = true; // found the section we were looking for
         continue;
       }
    } // = end if sectionFound == false

    if(sectionFound == true)
    {
      if (buffer[0]=='[') {sectionFound = false; continue;}
      foundEntry = buffer;
      while (*foundEntry && *foundEntry!='=') {foundEntry++;}
      if (*foundEntry!='=') {continue;}

      *foundEntry-- = 0; // delete " " before the "="
      *foundEntry++ = 0; // delete " " before the "="
      *foundEntry++ = 0; // delete "="
      *foundEntry++ = 0; // delete " " after the "="

      // Skip to end of string and delete lf (=line feed char)
      while (*foundEntry) {foundEntry++; entryLength++;} *--foundEntry = 0;

      // move back to the beginning of the value of the entry
      for(int i = entryLength-1; i > 0; i--){foundEntry--;}
      entryLength = 0;

      if(strcmp(buffer, entry) == 0) // found the entry we were looking for
      {
        char *returnValue = new char[MAX_LENGTH_OF_LINE];
        strcpy( returnValue, foundEntry );
        fclose (cfgFile);
        return returnValue;
      }
    } // = end if sectionFound == true
  } // = end of skipping through the lines
}








int writeToINI(char *filename, char *section, char *entry, char *value)
{
  char buffer[MAX_LENGTH_OF_LINE];  // = holds the content of current line
  char *foundSection;  // = picking out the section name
  char *foundEntry;  // = picking out the entry name
  int sectionLength = 0;
  int entryLength = 0;
  bool sectionFound = false;
  int sectionline = 0;
  int entryline = 0;
  int lastline = 0;
  bool entryfound = false;
  int linecounter=0;

  FILE *cfgFile=fopen(filename, "r"); //open the file

  if (!cfgFile) { // if file doesn't exist do something...
    // insert error routine here...
    return 0;
  } 

  //go through the lines one by one
  while (fgets(buffer, MAX_LENGTH_OF_LINE, cfgFile))
  {
    linecounter++;
    if (buffer[0]==';') {continue;} // skip comments

    if(sectionFound == false)
    {
      foundSection = buffer;

      while (*foundSection && *foundSection!='[') {foundSection++;}
      if (*foundSection!='[') {continue;}
      *foundSection++ = 0; // delete "["

      while (*foundSection && *foundSection!=']') {foundSection++; sectionLength++;}
      if (*foundSection!=']') {continue;}
      *foundSection++ = 0; // delete "]"

      while (*foundSection) {foundSection++;}  *--foundSection = 0;
      for(int i = sectionLength+1; i > 0; i--){foundSection--;}
      sectionLength = 0;

      if (strcmp(foundSection, section) == 0) // compare the char arrays
       {
        sectionFound = true; // found the section we were looking for
        sectionline = linecounter; // store the location of the section
        continue;
       }
    } // = end if sectionFound == false


    if(sectionFound == true)
    {
    if (buffer[0]=='[') {sectionFound = false; continue;}
      foundEntry = buffer;

      while (*foundEntry && *foundEntry!='=') {foundEntry++;}

      if (*foundEntry!='=') {continue;}

      *foundEntry-- = 0; // delete " " before the "="
      *foundEntry++ = 0; // delete " " before the "="
      *foundEntry++ = 0; // delete "="
      *foundEntry++ = 0; // delete " " after the "="

      // Skip to end of string and delete lf (=line feed char)
      while (*foundEntry) {foundEntry++; entryLength++;} *--foundEntry = 0;

      // move back to the beginning of the value of the entry
      for(int i = entryLength-1; i > 0; i--){foundEntry--;}
      entryLength = 0;
      if(strcmp(buffer, entry) == 0)
      {
        entryfound = true; // found the entry we were looking for
        entryline = linecounter; // store the location of the entry
      }
    } // = end if sectionFound == true
  } // = end of skipping through the lines
  fclose (cfgFile);
  lastline = linecounter; //store the total number of lines

// ok, now we know where the line is we want to replace
// so let's replace it!
  linecounter = 0;
  FILE* in_file = NULL;
  FILE* out_file = NULL;
  char* temporary_file_name = NULL;
  char line[128];
  in_file = fopen(filename, "r"); // open the file

  if(in_file == NULL){ // if the file doesn't exist, do something...
  //insert error routine here...
  return 1;
  }

  temporary_file_name = tmpnam(NULL);
  out_file = fopen(temporary_file_name, "w");

  while(fgets(line, sizeof(line), in_file)) // go through the lines
  {
    linecounter++;

    if(sectionline > 0 && entryline > 0) //section and entry already exist
    {
      if(linecounter == entryline)
      {
        strcpy(line, entry);
        strcat(line, " = ");
        strcat(line, value);
        strcat(line, "\n");
      }
    }

    if(sectionline > 0 && entryline == 0) //section exists but entry doesn't
    {
      if(linecounter == sectionline)
      {
      strcat(line, "\n"); //needed just in cast there is no line break
      strcat(line, entry);
      strcat(line, " = ");
      strcat(line, value);
      strcat(line, "\n");
      }
    }
  
    if(sectionline == 0) //section does not yet exist
    {
      if(linecounter == lastline) // add the new section to the end of the file
      {
        strcat(line, "\n[");   //needed just in cast there is no line break
        strcat(line, section);
        strcat(line, "]\n");
        strcat(line, entry);
        strcat(line, " = ");
        strcat(line, value);
        strcat(line, "\n");
      }  
    }

    fputs(line, out_file);
  } // end of going through the lines

  fclose(in_file);
  fflush(out_file);
  fclose(out_file);

  remove(INI_FILENAME);
  rename(temporary_file_name, INI_FILENAME);
  return 0;  
}

int main(void)
{
  // an example of how to call the functions...
  char *value = readFromINI(INI_FILENAME, "Section2", "Entry2");
  printf("returned value from readFromINI: %s\n", value);
  free(value);

  writeToINI(INI_FILENAME, "Section2", "Entry2", "I've changed this value! Weehee!!!");
  getchar ();
  return 0;
}
