mirror of
https://github.com/postgres/postgres.git
synced 2025-07-20 05:03:10 +03:00
455 lines
11 KiB
C
455 lines
11 KiB
C
/*-------
|
|
* 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
|
|
*-------
|
|
*/
|
|
|
|
#if !defined(WIN32) && !defined(WITH_UNIXODBC) && !defined(WITH_IODBC)
|
|
|
|
#include "gpps.h"
|
|
|
|
#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 "dlg_specific.h"
|
|
|
|
#ifndef TRUE
|
|
#define TRUE ((BOOL)1)
|
|
#endif
|
|
#ifndef FALSE
|
|
#define FALSE ((BOOL)0)
|
|
#endif
|
|
|
|
#ifndef ODBCINSTDIR
|
|
#error "ODBCINSTDIR must be defined to compile this file"
|
|
#endif
|
|
|
|
|
|
/*
|
|
* theIniFileName is searched for in:
|
|
* $HOME/theIniFileName
|
|
* theIniFileName
|
|
* ODBCINSTDIR/ODBCINST_INI
|
|
*/
|
|
DWORD
|
|
GetPrivateProfileString(const char *theSection, /* section name */
|
|
const char *theKey, /* search key name */
|
|
const char *theDefault, /* default value if not
|
|
* found */
|
|
char *theReturnBuffer, /* return value stored
|
|
* here */
|
|
size_t theReturnBufferLength, /* byte length of return
|
|
* buffer */
|
|
const 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;
|
|
|
|
ptr = (char *) getpwuid(getuid()); /* get user info */
|
|
|
|
if (ptr == NULL || (((struct passwd *) ptr)->pw_dir) == NULL || *(((struct passwd *) ptr)->pw_dir) == '\0')
|
|
ptr = "/home";
|
|
else
|
|
ptr = ((struct passwd *) ptr)->pw_dir; /* get user home dir */
|
|
|
|
/*
|
|
* If it can't be opened because the paths are too long, then skip it,
|
|
* don't just truncate the path string... The truncated path might
|
|
* accidently be an existing file. The default value will be returned
|
|
* instead.
|
|
*/
|
|
if (MAXPGPATH - 1 >= strlen(ptr) + 1 + strlen(theIniFileName))
|
|
{
|
|
sprintf(buf, "%s/%s", ptr, theIniFileName);
|
|
aFile = (FILE *) fopen(buf, PG_BINARY_R);
|
|
}
|
|
|
|
/*
|
|
* This code makes it so that a file in the users home dir overrides a
|
|
* the "default" file as passed in
|
|
*/
|
|
if (!aFile)
|
|
{
|
|
aFile = (FILE *) fopen(theIniFileName, PG_BINARY_R);
|
|
if (!aFile)
|
|
aFile = (FILE *) fopen(ODBCINSTDIR "/" ODBCINST_INI, PG_BINARY_R);
|
|
}
|
|
|
|
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(const char *theSection, /* section name */
|
|
const char *theKey, /* write key name */
|
|
const char *theBuffer, /* input buffer */
|
|
const char *theIniFileName) /* pathname of ini file
|
|
* to write */
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
#if NOT_USED
|
|
/*
|
|
* 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 /* NOT_USED */
|
|
|
|
#endif /* not WIN32 */
|