/***************************************************************************
*       NAME:  PROFILE.C $Revision: 1.3 $
**      COPYRIGHT:
**      "Copyright (c) 1994,1995 by e-Tek Labs"
**
**       "This software is furnished under a license and may be used,
**       copied, or disclosed only in accordance with the terms of such
**       license and with the inclusion of the above copyright notice.
**       This software or any other copies thereof may not be provided or
**       otherwise made available to any other person. No title to and
**       ownership of the software is hereby transfered."
****************************************************************************
* $Log: profile.c $
* Revision 1.3  1995/05/25 15:14:51  mleibow
* Added far ptrs for list handling.
* Added support for stdio or local file functions.
* Added support for malloc/free or local memory functions.
* Revision 1.2  1995/05/15 22:49:24  sdsmith
* Switched to far versions of list code
* Revision 1.1  1995/02/23 11:07:52  unknown
* Initial revision
***************************************************************************/
/***************************************************************************
OVERVIEW:
profile.c - profile utilities

This file contains utility routines for use by wrappers or applications.
The utilities are for reading data from a .ini file in the standard
Microsoft Windows format:

[section1]
entry1=value1
entry2=value2

[section2]
.
.
.

If this routine is being compiled specifically for Microsoft Windows,
most of the code is preprocessed out since the actual Microsoft 
routines will be used.
*/
#ifdef _WINDOWS
#include <windows.h>
#endif

#include "iw.h"
#include "os.h"
#include "iwllist.h"
#include "profile.h"
#include "config.h"

#ifndef _WINDOWS

struct iwl_list profiles = {0,0};
static char input_line[256];

void skip_whitespace(char RFAR *cp, char RFAR *RFAR*pcp)
{
    while (iwu_isspace(*cp)) cp++;
    *pcp = cp;
}

/***************************************************************************

FUNCTION DEFINITION:
search_disk_profile - search a profile on disk

DESCRIPTION:
This routine opens a profile on disk and searches the contents for the
section, entry, and value specified by the caller.  The profile is
expected to be in the standard Microsoft Windows .ini file format 
described in the OVERVIEW.

The general flow of the routine is:
loop1: get a line from the file
 - if the first char is a '[' then this is a new section
   - compare the section name with the specified name
   - if equal
     - loop2: get the next line
     - if the first character is alphanumeric
        - find the '='
	- compare the string up to the '=' to the specified entry
	- if equal
	  - copy the characters following the '=' to the caller's buffer
          else goto loop2
     else goto loop1

RETURNS: int - number of bytes copied to the ouput buffer

SEE ALSO: 
GetPrivateProfileString in the Microsoft Windows SDK documentation

*/
static int search_disk_profile(
  char RFAR *Section,   /* section to search for */
  char RFAR *Entry,     /* entry to search for */
  char RFAR *Filename,  /* file name of profile to search */
  char RFAR *Buffer,    /* caller's data buffer to copy value into */
  int   BufSize)        /* size of data buffer */
{
  int fp;
  char RFAR *buffer, RFAR *val, RFAR *il;
  int input_lineok, error = 0, found_section=0;
  unsigned int i;
  int filled;
  unsigned int limit;


  filled = 0;
  fp = os_file_open(Filename);
  if (fp >= 0) {
    os_file_seek(fp, 0, DOS_SEEK_START);
    while (!error) {
      if (os_file_gets(fp, (char RFAR *)input_line, 255)) {
	skip_whitespace(input_line, &il);
        if (*il == '[') {
	  if (found_section && Entry == 0) {
	    error = FOUND_ENTRY;
	  } else {
	    for (i=0;i<(UINT)iwu_strlen(il);i++)
	      if (il[i] == ']') il[i]='\0';
	    if (iwu_stricmp(Section, (char RFAR *)&il[1]) == 0) {
	      found_section = 1;
	      buffer = Buffer;
	      limit = BufSize;
	    }
	    else found_section = 0;
	  }
        } else {
          if (found_section) {
            input_lineok = 0;
            if (il[0] != ';') {
              for (i=0;i<(UINT)iwu_strlen(il);i++) {
                if (il[i] == '=') {
                  input_lineok = 1;
                  il[i] = 0;
                  val = (char RFAR *)&il[i+1];
                  for (i=0;i<(UINT)iwu_strlen(val);i++)
                    if (val[i] == '\n') {
                      val[i] = 0;
                      break;
                    }
                  break;
                }
              }
	    }
	    if (input_lineok) {
	      if (Entry) {
		if (iwu_stricmp(Entry,
			       (char RFAR *)il) == 0) {
		  iwu_strncpy(buffer, val, BufSize);
		  buffer[BufSize - 1] = '\0';
		  filled += iwu_strlen(buffer);
		  error = FOUND_ENTRY;
		}
	      } else {
		if ((UINT)iwu_strlen(il) < limit) {
		  iwu_strcpy(buffer, (char RFAR *)il);
		  buffer += iwu_strlen((char RFAR *)il) + 1;
		  limit -= (iwu_strlen((char RFAR *)il) + 1);
		  filled += iwu_strlen((char RFAR *)il) + 1;
		  buffer[0] = '\0';
		  buffer[1] = '\0';
		}
		else {
		  if (limit > 0) iwu_strncpy(buffer, 
					    (char RFAR *)il,
					    limit);
		  filled = BufSize - 1;
		  Buffer[BufSize - 2] = '\0';
		  Buffer[BufSize - 1] = '\0';
		  error = BUFFER_FULL;
		}
	      }
            }
          }
        }
      }
      else error = END_OF_FILE;
    }
    os_file_close(fp);
  }
  else error = NO_SUCH_FILE;

  return(filled);
}

/***************************************************************************

FUNCTION DEFINITION:
search_loaded_profile - search a cached profile

DESCRIPTION:

This routine searches the in memory list of profiles that may be cached
with a call to iwu_load_profile.

RETURNS: int - number of bytes copied to the ouput buffer

SEE ALSO: 
search_disk_profile
iwu_load_profile
GetPrivateProfileString in the Microsoft Windows SDK documentation

*/
static int search_loaded_profile(
  profile_header RFAR *profile, /* cached profile structure to search */
  char RFAR *Section,           /* section to search for */
  char RFAR *Entry,             /* entry to search for */
  char RFAR *Buffer,            /* caller's data buffer to hold value */
  int   BufSize)                /* size of data buffer */
{
  profile_section RFAR *section;
  profile_entry RFAR *entry;
  char RFAR *input_line, RFAR *val, RFAR *buffer;
  int error = 0;
  int filled = 0;
  unsigned int limit;

  section = (profile_section RFAR *)profile->sections.head;
  while (section && !error) {
    if (section->valid) {
      if (iwu_stricmp(Section,section->name) == 0) {
	entry = (profile_entry RFAR *)section->entries.head;
	limit = BufSize;
	buffer = Buffer;
	while (entry && !error) {
	  if (entry->valid) {
	    input_line = entry->name;
	    val = entry->value;
	    if (Entry) {
	      if (iwu_stricmp(Entry, input_line) == 0) {
		iwu_strncpy(buffer, val, BufSize);
		buffer[BufSize - 1] = '\0';
		filled += iwu_strlen(buffer);
		error = FOUND_ENTRY;
	      }
	    } else {
	      if ((UINT)iwu_strlen(input_line) < limit) {
		iwu_strcpy(buffer, input_line);
		buffer += iwu_strlen(input_line) + 1;
		limit -= (iwu_strlen(input_line) + 1);
		filled += iwu_strlen(input_line) + 1;
		buffer[0] = '\0';
		buffer[1] = '\0';
	      } else {
		if (limit > 0) iwu_strncpy(buffer, input_line, limit);
		filled = BufSize - 1;
		Buffer[BufSize - 2] = '\0';
		Buffer[BufSize - 1] = '\0';
		error = BUFFER_FULL;
	      }
	    }
	  }
	  entry = (profile_entry RFAR *)entry->node.next;
	}
      }
    }
    section = (profile_section RFAR *)section->node.next;
  }
  return(filled);
}
#endif /* if _WINDOWS is not defined */

/***************************************************************************

FUNCTION DEFINITION:
iwu_get_profile_string - get profile string

DESCRIPTION:
iwu_get_profile_string performs the same function as the Microsoft
Windows function GetPrivateProfileString.

This routine searches the in memory list of profiles that may be cached
with a call to iwu_load_profile.  If there are no cached profiles in
memory, the profile is searched on disk.

If this routine is being compiled specifically for use with Microsoft
Windows, the actual Microsoft GetPrivateProfileString is called.

RETURNS: int - number of bytes copied to the ouput buffer

SEE ALSO: 
iwu_load_profile
GetPrivateProfileString in the Microsoft Windows SDK documentation

*/
int iwu_get_profile_string(
  char RFAR *section,     /* section to search for */
  char RFAR *entry,       /* entry to search for */
  char RFAR *default_str, /* default value if entry does not exist */
  char RFAR *buffer,      /* caller's data buffer to copy value into */
  int   buf_size,         /* size of data buffer */
  char RFAR *file)        /* file name of profile to search */
{
#ifdef _WINDOWS
  return(GetPrivateProfileString(section, entry, default_str,
                                 buffer, buf_size, file));
#else
  int profile_searched = 0;
  profile_header RFAR *profile;
  int rc;

    /* Check loaded profiles */
  profile = (profile_header RFAR *)profiles.head;
  while (profile) {
    if (iwu_stricmp(profile->filename, file) == 0) {
      rc = search_loaded_profile(profile, section, entry, buffer, buf_size);
      profile_searched = 1;
    }
    profile = (profile_header RFAR *)profile->node.next;
  }

    /* Go to disk */
  if (!profile_searched) {
    rc = search_disk_profile(section, entry, file, buffer, buf_size);
  }
  if (!rc) {
    if (default_str == 0) default_str = "";
    iwu_strncpy(buffer, default_str, buf_size);
    rc = iwu_strlen(buffer);
  }
  return(rc);
#endif
}
