/* 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 "misc.h"
#include "gpps.h"

#ifndef TRUE
#define TRUE	((BOOL)1)
#endif
#ifndef FALSE
#define FALSE	((BOOL)0)
#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[MAXPGPATH];
	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( MAXPGPATH-1 < j )
			theIniFileName[MAXPGPATH-1] = '\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( MAXPGPATH-1 < strlen(ptr) + j )
	{
		if( MAXPGPATH-1 < strlen(ptr) )
			ptr[MAXPGPATH-1] = '\0';
		else
			theIniFileName[MAXPGPATH-1-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, PG_BINARY_R) : NULL);
	if(!aFile) {
		sprintf(buf,"%s",theIniFileName);
		aFile = (FILE*)(buf ? fopen(buf, PG_BINARY_R) : NULL);
	}


	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((unsigned char) *aStart)) aStart++;
					while (isspace((unsigned char) *aString)) aString--;
					*(aString+1) = '\0';

					/* accept as matched if NULL key or exact match */

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

			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((unsigned char) *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;
}

#if 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[MAXPGPATH];
	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( MAXPGPATH-1 < j )
			theIniFileName[MAXPGPATH-1] = '\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( MAXPGPATH-1 < strlen(ptr) + j )
	{
		if( MAXPGPATH-1 < strlen(ptr) )
			ptr[MAXPGPATH-1] = '\0';
		else
			theIniFileName[MAXPGPATH-1-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


#endif
