/////////////////////////////////////////////////////////////////////////////
// INI.C
//
// Copyright (C) 1997,1998 Progressive Networks.
// All rights reserved.
//
// $Log: ppvini.cpp,v $
// Revision 1.4  1999/04/08 17:01:28  smpatel
// Stop messing with errno without declaring, fixes BB
//
// Revision 1.3  1999/04/06 19:45:41  paulm
// Actually, I think this is what they meant to do..
//
// Revision 1.2  1999/04/06 19:40:12  paulm
// um,  errno is already there, don't use it as a var name PLEASE!
//
// Revision 1.1.1.1  1998/11/09 23:23:04  lesterj
// G2 Commerce RealServer Demo Application
//
// Revision 1.6  1997/06/06 22:18:21  darrens
// Fixed a bunch of warnings and errors for C++ compiler.
//
// Revision 1.5  1997/06/06 20:48:58  peterh
// - .c -> .cpp
//
// Revision 1.4  1997/05/28 15:55:30  darrens
// Changed AudioConnections parameter to ClientConnections and fixed file descriptor leaks.
//
// Revision 1.3  1997/05/22 18:33:00  darrens
// Added intro panel to allow user to choose between multiple UNIX installations.
//
//

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include "ppvini.h"

/*
 Returns a pointer to the line that contains the desired string
 open for write opens a file from the beginning
 Basic finding function for reads.
 See ScanForCopy() for use with writes
*/

int ScanFor
(
	LPCSTR	lpAppName,
	LPCSTR	lpKeyName,
	LPSTR	lpReturnedString,
	int		nSize,
	FILE	*pIniFile
)
{
	int nAppLen = strlen (lpAppName);
	int nKeyLen = strlen (lpKeyName);
	char *rc;  

	/* find application name, if present */
	
	do
	{
		rc = fgets (lpReturnedString, nSize, pIniFile);
		
		/* check for error, possibly EOF. */
		if (rc != lpReturnedString)
		{
			
			/* didn't find the application.  Return not found */
			return 0;
		}
	} while (lpReturnedString[0] != '['
		|| strncmp (lpAppName, &lpReturnedString[1], nAppLen)
		|| lpReturnedString[1+nAppLen] != ']');

	/* Found the application section and now look for the keyword */
	do
	{
		rc = fgets (lpReturnedString, nSize, pIniFile);

		/* check for error, possibly EOF */
		if (rc != lpReturnedString)
		{
		
			/* didn't find the application so Return not found */
			return 0;
		}

		/* Reached the end of an application so obviously the keyword wasn't found */
		if (lpReturnedString[0] == '[')
		{
			/* didn't find the keyword.  Return not found */
			return 0;
		}
	} while (strncmp (lpKeyName, lpReturnedString, nKeyLen)
			|| lpReturnedString[nKeyLen] != '=');

	/*
	 It was found and it's in the current buffer.  Return success.
	 Success is the nonzero index into the return string of where
	 the result (after the equal sign) is located
	 */

	return nKeyLen+1;
}

/*
 Basic finding function for writes
 See ScanFor() for use with reads
*/

int InsertSection
(
	LPCSTR	lpAppName,
	LPCSTR	lpKeyName,
	LPCSTR	lpValue,
	FILE	*pFile
)
{
	return fprintf (pFile, "[%s]\n%s=%s\n", lpAppName, lpKeyName, lpValue);
}

int InsertKey
(
	LPCSTR	lpKeyName,
	LPCSTR	lpValue,
	FILE	*pFile
)
{
	return fprintf (pFile, "%s=%s\n", lpKeyName, lpValue);
}

/* Return of zero means no more copy to do */

int ScanForCopyInsert
(
	LPCSTR	lpAppName,
	LPCSTR	lpKeyName,
	LPCSTR	lpValue,
	FILE	*pIniFile,
	FILE	*pIniFileCopy
)
{
	int nAppLen = strlen (lpAppName);
	int nKeyLen = strlen (lpKeyName);
	char  lpReturnedString [256];
	char *rc;

	/* find application name, if present */
	do
	{
		rc = fgets (lpReturnedString, 256, pIniFile);
   
		/* check for error, possibly EOF. */
		if (rc != lpReturnedString)
		{
			/* didn't find the application.  Return not found */
			InsertSection (lpAppName, lpKeyName, lpValue, pIniFileCopy);
			return 0;
		}
   
	/* copy to output */
	fputs (lpReturnedString, pIniFileCopy);
	} while (lpReturnedString[0] != '[' 
        || strncmp (lpAppName, &lpReturnedString[1], nAppLen)
        || lpReturnedString[1+nAppLen] != ']');

	/* Found the application section.  Now look for the keyword */
	do 
	{
		rc = fgets (lpReturnedString, 256, pIniFile);
		/* check for error, possibly EOF. */
		if (rc != lpReturnedString)
		{
			/* didn't find the application.  Return not found */
			InsertKey (lpKeyName, lpValue, pIniFileCopy);
			return 1;
		}
	
		/* at the end of an application.  Obviously we didn't find the keyword */
		if (lpReturnedString[0] == '[')
		{
			InsertKey (lpKeyName, lpValue, pIniFileCopy);
			
			/* copy the line in the buffer, that we just read, that starts a new section */
			fputs (lpReturnedString, pIniFileCopy);
			
			/* didn't find the keyword.  Return not found */
			return 1;
		}
		
		if (!strncmp (lpKeyName, lpReturnedString, nKeyLen)
			&& lpReturnedString[nKeyLen] == '=')
		{
			/* this is the place */
			break;
		}
	} while (fputs (lpReturnedString, pIniFileCopy) != EOF);


	/*
	 OK, we found it, and it's in the current buffer.  Replace what's after
	 the equal sign and up to any comment, with what's in the string we got
	 here to write in
	*/
	
	rc = strchr (&lpReturnedString[nKeyLen+1], ';');
	
	/* we got a trailing comment.  Now back up over whitespace */
	if (rc)
	{
		while (isspace(*(rc-1)))
		{
			rc--; /* back up */
	    } 
		
		
		/* note that rc usually includes a newline character */
		if (!strchr (rc, '\n'))
		{
	   
			/* must provide a newline char, one wasn't there */
			fprintf (pIniFileCopy, "%s=%s%s\n", lpKeyName, lpValue, rc);
		}
		else
		{
			fprintf (pIniFileCopy, "%s=%s%s", lpKeyName, lpValue, rc);
		}
    }
	else
	{
		fprintf (pIniFileCopy, "%s=%s\n", lpKeyName, lpValue);
	}

	/* indicate probably more to copy */
	return 1;
}


UINT GetPrivateProfileInt
(
	LPCSTR		lpAppName,
	LPCSTR		lpKeyName,
	int			nDefault,
	LPCSTR		lpFileName
)
{
	char	szReturnedString[256];
	UINT	rc;

	FILE	*pIniFile = fopen (lpFileName, "rt");
	if (!pIniFile)
	{
		return nDefault;
	}

	rc = ScanFor (lpAppName, lpKeyName, szReturnedString, 256, pIniFile);

	if (!rc)
	{
		fclose( pIniFile );
		return nDefault;
	}

	// Close the file
	fclose( pIniFile );

	/* get integer value */
	return (UINT) atol (&szReturnedString[ rc ]);
}

int GetPrivateProfileString
(
	LPCSTR		lpAppName,
	LPCSTR		lpKeyName,
	LPCSTR		lpDefault,
	LPSTR		lpReturnedString,
	int			nSize,
	LPCSTR		lpFileName
)
{
	char		szReturnedString[256];
	int			rc;
	int			i;
	int			len;
	char		*p;

	FILE		*pIniFile = fopen (lpFileName, "rt");
	if (!pIniFile)
	{
		strcpy (lpReturnedString, lpDefault);
		
		return strlen (lpDefault);
	}

	rc = ScanFor (lpAppName, lpKeyName, szReturnedString, 256, pIniFile);
	if (!rc)
	{
		strcpy (lpReturnedString, lpDefault);

		fclose ( pIniFile );
		return strlen (lpDefault);
	}

	/* get string.  Copy out and back, to get rid of leading line info */
	strcpy (szReturnedString, &szReturnedString[ rc ]);

	/* look for a double quote */
	if (szReturnedString[0] == '\"')
	{
		/* find terminating quote */
		p = strchr (&szReturnedString[1], '\"');
		p++;
		*p = '\0';  /* string is terminated after end quote */
	} 
	else if (NULL != (p = strchr (szReturnedString, ';')))
	{
		 /*
		 found a comment char
		 terminate string there.  Trailing whitespace trim will still work.
		 */
		*p = '\0';
	}

	/* trim off trailing whitespace */
	len = strlen (szReturnedString);
	for (i = len-1; i > 0; i--)
	{
		if (isspace(szReturnedString[i]))
		{
			szReturnedString[i] = '\0';  /* trim it */
		}
		else
		{
			break;
		}
	}
	
	strncpy (lpReturnedString, szReturnedString, nSize - 1);
	lpReturnedString[nSize] = '\0';  /* force null termination */

	// Close the file
	fclose( pIniFile );

	return strlen (lpReturnedString);
}

BOOL WritePrivateProfileString
(
	LPCSTR	lpAppName,
	LPCSTR	lpKeyName,
	LPCSTR	lpValue,
	LPCSTR	lpFileName
)
{
	char	szTempFileName[256];
	char	szTempFileName2[256];
	char	buffer[256];
	int		rc;

	FILE	*pIniFileCopy;
	FILE	*pIniFile = fopen (lpFileName, "rt");

	/* if it doesn't exist, create it and insert this section */
	if (!pIniFile)
	{
		pIniFile = fopen (lpFileName, "wt");
		if (!pIniFile)
		{
			return 0;   /* failure */
		}
		
		InsertSection (lpAppName, lpKeyName, lpValue, pIniFile);
		fclose (pIniFile);
		return 0;
   }

	/* get a temporary file name that is unique */
	strcpy (szTempFileName, lpFileName);
	szTempFileName[strlen (szTempFileName)-1] = '$';   /* turn last char into $ */

	pIniFileCopy = fopen (szTempFileName, "wt");
	/* if can't open a temporary file, fail */
	if (!pIniFileCopy)
	{
		fclose (pIniFile);
		return 0;
	}

	rc = ScanForCopyInsert (lpAppName, lpKeyName, lpValue, pIniFile, pIniFileCopy);

	if (rc)
	{
		while (!feof (pIniFile))
		{
			if (buffer != fgets (buffer, sizeof (buffer) -1, pIniFile))
			{
				if (!feof (pIniFile))
				{
					fclose (pIniFile);
					fclose (pIniFileCopy);
					remove (szTempFileName);
					return 0;
				}
				else
				{
					/* it is end of file.  All is copied.  Swap files */
					break;
				}
			}
         
			/* while writing to the copy file, if an error is encountered */
			if (fputs (buffer, pIniFileCopy) == EOF)
			{
				/* error while writing */
				fclose (pIniFile);
				fclose (pIniFileCopy);
				remove (szTempFileName);
				return 0;
			}
		} /* end while not eof */
	}

	/* close the files */
	fclose (pIniFile);
	fclose (pIniFileCopy);

	/* form the name of what to rename the current file to.*/
	strcpy (szTempFileName2, lpFileName);
	szTempFileName2[strlen (szTempFileName)-1] = '$';  /* turn last char into $ */
	szTempFileName2[strlen (szTempFileName)-2] = '$';  /* also nextlast char into $ */
	rc = rename (lpFileName, szTempFileName2);
	if (rc)
	{
		/* error on rename. can't perform operation. return. */
		remove (szTempFileName);
		return 0;
	}

	rc = rename (szTempFileName, lpFileName);
	if (rc)
	{
		/* error on rename. Bail out */
		/* rename back original file.  Pray for no error! */
		rename (szTempFileName2, lpFileName);
		remove (szTempFileName);   /* delete temp file */
		return 0;
	}

	/* all went OK.  Now just delete the temp file that is the original file */
	remove (szTempFileName2);

	return 1;
}
