#include "cfgopts.h"

void switch_type_and_write (struct Config_Tag ptr[], int count, FILE *outfile);
long fcopy(char *dest, char *source);	// copy one file to another


static unsigned char line[1000], line_bak[1000];
static char *true_false[]={ "ERROR","FALSE","TRUE" };

/*---------------------------------------------------------------------/
/   reads from an input configuration (INI) file.
/---------------------------------------------------------------------*/
/*>>------[   input_config()   ]-------------[ 08-02-95 14:02PM ]------/
/ return value:
/     int                     ; number of records read or -1 on error
/ parameters:
/     char *filename          ; filename of INI style file
/     struct Config_Tag configs[]; Configuration structure
/     char *header            ; INI header name (i.e. "[TEST]")
/-------------------------------------------------------------------<<*/
int input_config(char *filename, struct Config_Tag configs[], char *header)
{
   struct Config_Tag *ptr;
   int count=0,lineno=0,temp;
   FILE *file;
   char *fptr,*tok,*next;

   file=fopen(filename,"r");
   if ( file==NULL ) return ERROR;   // return error designation.
   if ( header!=NULL )
      do
   {
      fptr=fgets(line,sizeof(line)-2,file);  // get input line
   }
   while ( memcasecmp(line,header,strlen(header)) && !feof(file));
   if ( !feof(file) ) do {
      fptr=fgets(line,sizeof(line)-2,file);  // get input line
      if ( fptr==NULL ) continue;
      lineno++;
      if ( line[0]=='#' || line[0]==';' || line[0]=='/') continue;    // skip comments
      if ( line[0]=='[' ) continue;    // skip next header
      tok=strtok(line,"=\n\r");   // get first token
      if ( tok!=NULL )
      {
         next=strtok(NULL,"=\n\r"); // get actual config information
         for ( ptr=configs;ptr->buf;++ptr )   // scan for token
         {
            if ( !strcasecmp( tok , ptr->code ) )  // got a match?
            {
               if(!next) break;
               switch ( ptr->type )     // check type
               {
               case Boolean_Tag:
                  if (!strcasecmp(next,"FALSE"))
                     *((Boolean_T *)(ptr->buf)) = FALSE;
                  else if (!strcasecmp(next,"TRUE"))
                     *((Boolean_T *)(ptr->buf)) = TRUE;
                  ++count;
                  break;

               case Byte_Tag:
                  sscanf(next, "%d", &temp);
                  *((char *)(ptr->buf))=(char)temp;
                  ++count;
                  break;

               case Word_Tag:
                  sscanf(next, "%hd", (short *)(ptr->buf));
                  ++count;
                  break;

               case DWord_Tag:
                  sscanf(next, "%ld", (long *)(ptr->buf));
                  ++count;
                  break;

               case OctWord_Tag:
                  sscanf(next, "%ho", (short *)(ptr->buf));
                  ++count;
                  break;

               case DOctWord_Tag:
                  sscanf(next, "%lo", (long *)(ptr->buf));
                  ++count;
                  break;

               case HexWord_Tag:
                  sscanf(next, "%hx", (short *)(ptr->buf));
                  ++count;
                  break;

               case DHexWord_Tag:
                  sscanf(next, "%lx", (long *)(ptr->buf));
                  ++count;
                  break;

               case Float_Tag:
                  sscanf(next, "%g", (float *)ptr->buf);
                  ++count;
                  break;

               case Double_Tag:
                  sscanf(next, "%lg", (double *)ptr->buf);
                  ++count;
                  break;

               case String_Tag:
                  if(ptr->size_buf <= strlen(next)) strcpy((char *)ptr->buf, "\0\0");
                  else strcpy((char *)ptr->buf, next);
                  ++count;
                  break;

               case Function_Tag:
               case Error_Tag:
               default:
                  printf("Error in Config file %s on line %d\n",filename,lineno);
                  break;
               }
            }

         }
      }
   }
   while ( fptr!=NULL && line[0]!='[');
   fclose(file);
   return count;
}

/*---------------------------------------------------------------------/
/   updates an input configuration (INI) file from a structure.
/---------------------------------------------------------------------*/
/*>>------[   update_config()  ]-------------[ 08-02-95 14:02PM ]------/
/ return value:
/     int                     ; Number of records read & updated
/ parameters:
/     char *filename          ; filename of INI file
/     struct Config_Tag configs[]; Configuration structure
/     char *header            ; INI header name (i.e. "[TEST]")
/-------------------------------------------------------------------<<*/
int update_config(char *filename, struct Config_Tag configs[], char *header)
{
   int count=0,lineno=0, section_not_found;
   FILE *infile,*outfile;
   char *fptr,*tok;

   infile=fopen(filename,"r");
   if ( infile==NULL ) {	// file not found, creating new onw
      outfile=fopen("temp_PHX.$$$","w");
      if ( outfile==NULL )
         return ERROR;       // return error designation.
      if ( header!=NULL ) fprintf(outfile,"%s\n",header);
      switch_type_and_write(configs, count, outfile);

      fclose(outfile);
      fcopy(filename,"temp_PHX.$$$");
      remove("temp_PHX.$$$");
      return count;
   }
   outfile=fopen("temp_PHX.$$$","w");
   if ( outfile==NULL ) {
      fclose(infile);
      return ERROR;          // return error designation.
   }
   if ( header!=NULL )
   {
      do
      {
		 fptr=fgets(line,sizeof(line)-2,infile);    // get input line
         if(fptr) fprintf(outfile,"%s",line);
		 section_not_found=memcasecmp(line,header,strlen(header));
      }
      while ( section_not_found && !feof(infile));
   }
   if ( feof(infile) ) {
      fprintf(outfile,"\n");
      if ( header!=NULL && section_not_found ) fprintf(outfile,"\n%s\n",header);
      switch_type_and_write(configs, count, outfile);
   }
   else {
      do
      {
         fptr=fgets(line,sizeof(line)-2,infile);    // get input line
         if ( fptr==NULL )
		 {	// eof reached, lets write it
			switch_type_and_write(configs, count, outfile);
			break;
		 }
         lineno++;
         if ( line[0]=='#' || line[0]=='\r' || line[0]=='\n' || line[0]==';' || line[0]=='/') {
            fprintf(outfile,"%s",line);
            continue;  // skip comments
         }
         else if ( line[0]=='[' ) {	// new section found, last section was empty
            switch_type_and_write(configs, count, outfile);

			fprintf(outfile,"%s",line);
			do
			{	// write the rest of the file
				fptr=fgets(line,sizeof(line)-2,infile);
				if (fptr) fprintf(outfile,"%s",line);
			}
			while (!feof(infile));
			break;
         }
		 strcpy(line_bak, line);
         tok=strtok(line,"=\n\r");  // get first token
         if ( tok!=NULL )
         {
			if ( !strcasecmp( tok , configs->code ) ) // got a match?
			{
				switch_type_and_write(configs, count, outfile);
				do
				{	// write the rest of the file
					fptr=fgets(line,sizeof(line)-2,infile);
					if (fptr) fprintf(outfile,"%s",line);
				}
				while (!feof(infile));
				break;
			}
			fprintf(outfile,"%s",line_bak);
         }
      }
      while ( fptr!=NULL );
   }
   fclose(infile);
   fclose(outfile);
   fcopy(filename,"temp_PHX.$$$");
   remove("temp_PHX.$$$");
   return count;
}




void GetPrivateProfileString(char *INIsection, char *INIkey, char *INIdefault, char *INIbuffer, int INIbuflen, char *INIpath)
{
	struct Config_Tag cfgStr[] = {
	   { INIkey, String_Tag, INIbuffer, INIbuflen },
	   { NULL, Error_Tag, NULL, 0  }   /* Terminating record   */
	};

	unsigned char INIsect2[250];

	INIbuffer[0]=0;
	INIsect2[0]='[';
	strcpy(INIsect2+1, INIsection);
	strcat(INIsect2, "]");

	input_config(INIpath, cfgStr, INIsect2);

	if(INIbuffer[0]==0) strcpy(INIbuffer, INIdefault);

	if(INIbuffer[0]==0x22 && INIbuffer[strlen(INIbuffer)-1]==0x22)	// kill ""
	{
		INIbuffer[strlen(INIbuffer)-1]=0;
		strcpy(INIbuffer, INIbuffer+1);
	}
}


void WritePrivateProfileString(char *INIsection, char *INIkey, char *INIvalue, char *INIpath)
{
	unsigned char INIsect2[250];

	struct Config_Tag cfgStr[] = {
	   { INIkey, String_Tag, INIvalue  }
	};

	INIsect2[0]='[';
	strcpy(INIsect2+1, INIsection);
	strcat(INIsect2, "]");

	update_config(INIpath, cfgStr, INIsect2);
}




/*
 * copy one file to another.  Returns the (positive)
 * number of bytes copied, or -1 if an error occurred.
 */

#define BUFFER_SIZE 1024

/*---------------------------------------------------------------------/
/   copy one file to another.
/---------------------------------------------------------------------*/
/*>>------[       fcopy()      ]-------------[ 08-02-95 14:02PM ]------/
/ return value:
/     long                    ; Number of bytes copied or -1 on error
/ parameters:
/     char *dest              ; Destination file name
/     char *source            ; Source file name
/-------------------------------------------------------------------<<*/
long fcopy(char *dest, char *source)
{
   FILE *d, *s;
   char *buffer;
   size_t incount;
   long totcount = 0L;

   s = fopen(source, "rb");
   if(s == NULL)
      return -1L;

   d = fopen(dest, "wb");
   if(d == NULL)
   {
      fclose(s);
      return -1L;
   }

   buffer = (char *)malloc(BUFFER_SIZE);
   if(buffer == NULL)
   {
      fclose(s);
      fclose(d);
      return -1L;
   }

   incount = fread(buffer, sizeof(char), BUFFER_SIZE, s);

   while(!feof(s))
   {
      totcount += (long)incount;
      fwrite(buffer, sizeof(char), incount, d);
      incount = fread(buffer, sizeof(char), BUFFER_SIZE, s);
   }

   totcount += (long)incount;
   fwrite(buffer, sizeof(char), incount, d);

   free(buffer);
   fclose(s);
   fclose(d);

   return totcount;
}



int memcasecmp (const void *vs1, const void *vs2, size_t n)
{
  unsigned int i;
  unsigned char const *s1 = (unsigned char const *) vs1;
  unsigned char const *s2 = (unsigned char const *) vs2;
  for (i = 0; i < n; i++)
    {
      unsigned char u1 = *s1++;
      unsigned char u2 = *s2++;
      if (TOUPPER (u1) != TOUPPER (u2))
        return TOUPPER (u1) - TOUPPER (u2);
    }
  return 0;
}



void switch_type_and_write (struct Config_Tag ptr[], int count, FILE *outfile)
{
  int temp;

  fprintf(outfile,"%s=",ptr->code);
  switch ( ptr->type )    // check type
  {
  case Boolean_Tag:
     fprintf(outfile,"%s\n",
       true_false[*((Boolean_T *)(ptr->buf))+1]);
     ++count;
     return;

  case Byte_Tag:
     temp=(int)*((char *)(ptr->buf));
     fprintf(outfile, "%hd\n", temp);
     ++count;
     return;

  case Word_Tag:
     fprintf(outfile, "%hd\n", *((short *)(ptr->buf)));
     ++count;
     return;

  case DWord_Tag:
     fprintf(outfile, "%ld\n", *((long *)(ptr->buf)));
     ++count;
     return;

  case OctWord_Tag:
     fprintf(outfile, "%ho\n", *((short *)(ptr->buf)));
     ++count;
     return;

  case DOctWord_Tag:
     fprintf(outfile, "%lo\n", *((long *)(ptr->buf)));
     ++count;
     return;

  case HexWord_Tag:
     fprintf(outfile, "%hx\n", *((short *)(ptr->buf)));
     ++count;
     return;

  case DHexWord_Tag:
     fprintf(outfile, "%lx\n", *((long *)(ptr->buf)));
     ++count;
     return;

  case Float_Tag:
     fprintf(outfile, "%hg\n", *((float *)ptr->buf));
     ++count;
     return;

  case Double_Tag:
     fprintf(outfile, "%lg\n", *((double *)ptr->buf));
     ++count;
     return;

  case String_Tag:
     fprintf(outfile, "%s\n",(char *)ptr->buf);
     ++count;
     return;
  }
}


syntax highlighted by Code2HTML, v. 0.9.1