// GetPrivateProfileString() -- approximate implementation of
// Windows NT System Services version of GetPrivateProfileString()
// probably doesn't handle the NULL key for section name or value key
// correctly also, doesn't provide Microsoft backwards compatability
// wrt TAB characters in the value string -- Microsoft terminates value
// at the first TAB, but I couldn't discover what the behavior should
// be regarding TABS in quoted strings so, I treat tabs like any other
// characters -- NO comments following value string separated by a TAB
// are allowed (that is an anachronism anyway)
// Added code to search for ODBC_INI file in users home directory on
// Unix

#ifndef WIN32

#if HAVE_CONFIG_H
#include "config.h"	// produced by configure
#endif

#include <stdio.h>
#include <unistd.h>
#include <ctype.h>

#if HAVE_PWD_H
#include <pwd.h>
#endif

#include <sys/types.h>
#include <string.h>
#include "gpps.h"
#include "misc.h"

#ifndef TRUE
#define TRUE	((BOOL)1)
#endif
#ifndef FALSE
#define FALSE	((BOOL)0)
#endif

#if HAVE_SYS_PARAM_H
#include <sys/param.h>
#else
#define MAXPATHLEN	255
#endif

DWORD
GetPrivateProfileString(char *theSection,	// section name
	char *theKey,		// search key name
	char *theDefault,	// default value if not found
	char *theReturnBuffer,	// return value stored here
	size_t theReturnBufferLength,	// byte length of return buffer
	char *theIniFileName)		// pathname of ini file to search
{
	char buf[MAXPATHLEN+1];
	char* ptr = 0;
	FILE* aFile = 0;
	size_t aLength;
	char aLine[2048];
	char *aValue;
	char *aStart;
	char *aString;
	size_t aLineLength;
	size_t aReturnLength = 0;

	BOOL aSectionFound = FALSE;
	BOOL aKeyFound = FALSE;
	int j = 0;
	
	j = strlen(theIniFileName) + 1;
	ptr = (char*)getpwuid(getuid());	// get user info

	if( ptr == NULL)
	{
		if( MAXPATHLEN < j )
			theIniFileName[MAXPATHLEN] = '\0';

		sprintf(buf,"%s",theIniFileName);
	}
	ptr = ((struct passwd*)ptr)->pw_dir;	// get user home dir
	if( ptr == NULL || *ptr == '\0' )
		ptr = "/home";

	/* This doesn't make it so we find an ini file but allows normal
	 * processing to continue further on down. The likelihood is that
	 * the file won't be found and thus the default value will be
	 * returned.
	*/
	if( MAXPATHLEN < strlen(ptr) + j )
	{
		if( MAXPATHLEN < strlen(ptr) )
			ptr[MAXPATHLEN] = '\0';
		else
			theIniFileName[MAXPATHLEN-strlen(ptr)] = '\0';
	}

	sprintf( buf, "%s/%s",ptr,theIniFileName );

	  /* This code makes it so that a file in the users home dir
	   * overrides a the "default" file as passed in
	  */
#ifndef __CYGWIN32__
	aFile = (FILE*)(buf ? fopen(buf, "r") : NULL);
#else
	aFile = (FILE*)(buf ? fopen(buf, "rb") : NULL);
#endif
	if(!aFile) {
		sprintf(buf,"%s",theIniFileName);
#ifndef __CYGWIN32__
		aFile = (FILE*)(buf ? fopen(buf, "r") : NULL);
#else
		aFile = (FILE*)(buf ? fopen(buf, "rb") : NULL);
#endif
	}

		
	aLength = (theDefault == NULL) ? 0 : strlen(theDefault);

	if(theReturnBufferLength == 0 || theReturnBuffer == NULL)
	{
		if(aFile)
		{
			fclose(aFile);
		}
		return 0;
	}

	if(aFile == NULL)
	{
		// no ini file specified, return the default

		++aLength;	// room for NULL char
		aLength = theReturnBufferLength < aLength ?
			theReturnBufferLength : aLength;
		strncpy(theReturnBuffer, theDefault, aLength);
		theReturnBuffer[aLength - 1] = '\0';
		return aLength - 1;
	}


	while(fgets(aLine, sizeof(aLine), aFile) != NULL)
	{
		aLineLength = strlen(aLine);
		// strip final '\n'
		if(aLineLength > 0 && aLine[aLineLength - 1] == '\n')
		{
			aLine[aLineLength - 1] = '\0';
		}
		switch(*aLine)
		{
			case ' ': // blank line
			case ';': // comment line
				continue;
			break;
			
			case '[':	// section marker

				if( (aString = strchr(aLine, ']')) )
				{
					aStart = aLine + 1;
					aString--;
					while (isspace(*aStart)) aStart++;
					while (isspace(*aString)) aString--;
					*(aString+1) = '\0';

					// accept as matched if NULL key or exact match

					if(!theSection || !strcmp(aStart, theSection))
					{
						aSectionFound = TRUE;
					}
				}

			break;

			default:

				// try to match value keys if in proper section

				if(aSectionFound)
				{
					// try to match requested key
	
					if( (aString = aValue = strchr(aLine, '=')) )
					{
						*aValue = '\0';
						++aValue;

						// strip leading blanks in value field

						while(*aValue == ' ' && aValue < aLine + sizeof(aLine))
						{
							*aValue++ = '\0';
						}
						if(aValue >= aLine + sizeof(aLine))
						{
							aValue = "";
						}
					}
					else
					{
						aValue = "";
					}

					aStart = aLine;
					while(isspace(*aStart)) aStart++;

					// strip trailing blanks from key

					if(aString)
					{
						while(--aString >= aStart && *aString == ' ')
						{
							*aString = '\0';
						}
					}

					// see if key is matched

					if(theKey == NULL || !strcmp(theKey, aStart))
					{
						// matched -- first, terminate value part

						aKeyFound = TRUE;
						aLength = strlen(aValue);

						// remove trailing blanks from aValue if any

						aString = aValue + aLength - 1;
						
						while(--aString > aValue && *aString == ' ')
						{
							*aString = '\0';
							--aLength;
						}

						// unquote value if quoted

						if(aLength >= 2 && aValue[0] == '"' &&
							aValue[aLength - 1] == '"')
						{
							// string quoted with double quotes

							aValue[aLength - 1] = '\0';
							++aValue;
							aLength -= 2;
						}
						else
						{
							// single quotes allowed also...

							if(aLength >= 2 && aValue[0] == '\'' &&
								aValue[aLength - 1] == '\'')
							{
								aValue[aLength - 1] = '\0';
								++aValue;
								aLength -= 2;
							}
						}

						// compute maximum length copyable

						aLineLength = (aLength <
							theReturnBufferLength - aReturnLength) ? aLength :
							theReturnBufferLength - aReturnLength;

						// do the copy to return buffer

						if(aLineLength)
						{
							strncpy(&theReturnBuffer[aReturnLength],
								aValue, aLineLength);
							aReturnLength += aLineLength;
							if(aReturnLength < theReturnBufferLength)
							{
								theReturnBuffer[aReturnLength] = '\0';
								++aReturnLength;
							}
						}
						if(aFile)
						{
							fclose(aFile);
							aFile = NULL;
						}

						return aReturnLength > 0 ? aReturnLength - 1 : 0;
					}
				}

			break;
		}
	}

	if(aFile)
	{
		fclose(aFile);
	}

	if(!aKeyFound) {	// key wasn't found return default
		++aLength;	// room for NULL char
		aLength = theReturnBufferLength < aLength ?
			theReturnBufferLength : aLength;
		strncpy(theReturnBuffer, theDefault, aLength);
		theReturnBuffer[aLength - 1] = '\0';
		aReturnLength = aLength - 1;
	}
	return aReturnLength > 0 ? aReturnLength - 1 : 0;
}

DWORD
WritePrivateProfileString(char *theSection,	// section name
	char *theKey,		// write key name
	char *theBuffer,	// input buffer
	char *theIniFileName)	// pathname of ini file to write
{
	return 0;
}

/* Ok. What the hell's the default behaviour for a null input buffer, and null
 * section name. For now if either are null I ignore the request, until
 * I find out different.
DWORD
WritePrivateProfileString(char *theSection,	// section name
	char *theKey,		// write key name
	char *theBuffer,	// input buffer
	char *theIniFileName)	// pathname of ini file to write
{
	char buf[MAXPATHLEN+1];
	char* ptr = 0;
	FILE* aFile = 0;
	size_t aLength;
	char aLine[2048];
	char *aValue;
	char *aString;
	size_t aLineLength;
	size_t aReturnLength = 0;

	BOOL aSectionFound = FALSE;
	BOOL keyFound = FALSE;
	int j = 0;
	
		// If this isn't correct processing we'll change it later 
	if(theSection == NULL || theKey == NULL || theBuffer == NULL || 
		theIniFileName == NULL) return 0;

	aLength = strlen(theBuffer);
	if(aLength == 0) return 0;

	j = strlen(theIniFileName) + 1;
	ptr = (char*)getpwuid(getuid());	// get user info

	if( ptr == NULL)
	{
		if( MAXPATHLEN < j )
			theIniFileName[MAXPATHLEN] = '\0';

		sprintf(buf,"%s",theIniFileName);
	}
	ptr = ((struct passwd*)ptr)->pw_dir;	// get user home dir
	if( ptr == NULL || *ptr == '\0' )
		ptr = "/home";

	// This doesn't make it so we find an ini file but allows normal
	//  processing to continue further on down. The likelihood is that
	// the file won't be found and thus the default value will be
	// returned.
	//
	if( MAXPATHLEN < strlen(ptr) + j )
	{
		if( MAXPATHLEN < strlen(ptr) )
			ptr[MAXPATHLEN] = '\0';
		else
			theIniFileName[MAXPATHLEN-strlen(ptr)] = '\0';
	}

	sprintf( buf, "%s/%s",ptr,theIniFileName );

	  // This code makes it so that a file in the users home dir
	  //  overrides a the "default" file as passed in
	  //
	aFile = (FILE*)(buf ? fopen(buf, "r+") : NULL);
	if(!aFile) {
		sprintf(buf,"%s",theIniFileName);
		aFile = (FILE*)(buf ? fopen(buf, "r+") : NULL);
		if(!aFile) return 0;
	}

		
	aLength = strlen(theBuffer);

		// We have to search for theKey, because if it already
		// exists we have to overwrite it. If it doesn't exist
		// we just write a new line to the file.
		//
	while(fgets(aLine, sizeof(aLine), aFile) != NULL)
	{
		aLineLength = strlen(aLine);
		// strip final '\n'
		if(aLineLength > 0 && aLine[aLineLength - 1] == '\n')
		{
			aLine[aLineLength - 1] = '\0';
		}
		switch(*aLine)
		{
			case ' ': // blank line
			case ';': // comment line
				continue;
			break;
			
			case '[':	// section marker

				if( (aString = strchr(aLine, ']')) )
				{
					*aString = '\0';

					// accept as matched if key exact match

					if(!strcmp(aLine + 1, theSection))
					{
						aSectionFound = TRUE;
					}
				}

			break;

			default:

				// try to match value keys if in proper section

				if(aSectionFound)
				{
					// try to match requested key
	
					if( (aString = aValue = strchr(aLine, '=')) )
					{
						*aValue = '\0';
						++aValue;

						// strip leading blanks in value field

						while(*aValue == ' ' && aValue < aLine + sizeof(aLine))
						{
							*aValue++ = '\0';
						}
						if(aValue >= aLine + sizeof(aLine))
						{
							aValue = "";
						}
					}
					else
					{
						aValue = "";
					}

					// strip trailing blanks from key

					if(aString)
					{
						while(--aString >= aLine && *aString == ' ')
						{
							*aString = '\0';
						}
					}

					// see if key is matched

					if(!strcmp(theKey, aLine))
					{
						keyFound = TRUE;
						// matched -- first, terminate value part

						// overwrite current value
						fseek(aFile,-aLineLength,SEEK_CUR);
						// overwrite key and value
						sprintf(aLine,"%s = %s\n",theKey,theBuffer);
						fputs(aLine,aFile);
						}
					}
				}

			break;
		}
	}

	if(!keyFound) {		// theKey wasn't in file so 
	if(aFile)
	{
		fclose(aFile);
	}

	return aReturnLength > 0 ? aReturnLength - 1 : 0;
}
*/

#endif
