From 341a36021dfee36541ab75334b086cddded20a20 Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Fri, 3 Nov 2017 15:24:48 +0100 Subject: - Fix MDEV-13925: Actually this fixes SELECT queries when the WHERE clause have single quote. modified: storage/connect/ha_connect.cc - Use Windows VirtualAlloc and VirtualFree for the Sarea workspace modified: storage/connect/global.h modified: storage/connect/ha_connect.cc modified: storage/connect/jsonudf.cpp modified: storage/connect/plgdbutl.cpp modified: storage/connect/plugutil.cpp modified: storage/connect/user_connect.cc - Change inihandl from c to c++. Because it now includes global.h that contains a bool function definition that make compile to fail on Linux. modified: storage/connect/CMakeLists.txt removed: storage/connect/inihandl.c added: storage/connect/inihandl.cpp - Fix MDEV-13860 CONNECT engine does not build with JDBC without ODBC. By including Sergei's patch in connect_assisted_discovery. modified: storage/connect/ha_connect.cc --- storage/connect/CMakeLists.txt | 2 +- storage/connect/global.h | 3 +- storage/connect/ha_connect.cc | 42 +- storage/connect/inihandl.c | 1406 -------------------------------------- storage/connect/inihandl.cpp | 1407 +++++++++++++++++++++++++++++++++++++++ storage/connect/jsonudf.cpp | 13 +- storage/connect/plgdbutl.cpp | 2 +- storage/connect/plugutil.cpp | 73 +- storage/connect/user_connect.cc | 23 +- 9 files changed, 1503 insertions(+), 1468 deletions(-) delete mode 100644 storage/connect/inihandl.c create mode 100644 storage/connect/inihandl.cpp (limited to 'storage/connect') diff --git a/storage/connect/CMakeLists.txt b/storage/connect/CMakeLists.txt index ca01c903ae7..e6b90aced1b 100644 --- a/storage/connect/CMakeLists.txt +++ b/storage/connect/CMakeLists.txt @@ -78,7 +78,7 @@ IF(UNIX) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive -fexceptions -fPIC ") get_property(inc_dirs DIRECTORY PROPERTY INCLUDE_DIRECTORIES) - SET(CONNECT_SOURCES ${CONNECT_SOURCES} inihandl.c) + SET(CONNECT_SOURCES ${CONNECT_SOURCES} inihandl.cpp) SET(IPHLPAPI_LIBRARY "") ELSE(NOT UNIX) SET(CONNECT_SOURCES ${CONNECT_SOURCES} diff --git a/storage/connect/global.h b/storage/connect/global.h index de7a9fb3c03..e4b00786efa 100644 --- a/storage/connect/global.h +++ b/storage/connect/global.h @@ -217,7 +217,8 @@ DllExport int PlugExit(PGLOBAL); // Plug global termination DllExport LPSTR PlugRemoveType(LPSTR, LPCSTR); DllExport LPCSTR PlugSetPath(LPSTR to, LPCSTR prefix, LPCSTR name, LPCSTR dir); DllExport BOOL PlugIsAbsolutePath(LPCSTR path); -DllExport void *PlugAllocMem(PGLOBAL, uint); +DllExport bool AllocSarea(PGLOBAL, uint); +DllExport void FreeSarea(PGLOBAL); DllExport BOOL PlugSubSet(PGLOBAL, void *, uint); DllExport void *PlugSubAlloc(PGLOBAL, void *, size_t); DllExport char *PlugDup(PGLOBAL g, const char *str); diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc index c6b9c2450be..25957909856 100644 --- a/storage/connect/ha_connect.cc +++ b/storage/connect/ha_connect.cc @@ -3009,7 +3009,9 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, const Item *cond) return NULL; if (!x) { + const char *p; char *s = (ishav) ? havg : body; + uint j, k, n; // Append the value to the filter switch (args[i]->field_type()) { @@ -3065,16 +3067,38 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, const Item *cond) strcat(s, "'}"); break; default: - strcat(s, "'"); - strncat(s, res->ptr(), res->length()); - strcat(s, "'"); - } // endswitch field type + j = strlen(s); + s[j++] = '\''; + p = res->ptr(); + n = res->length(); + + for (k = 0; k < n; k++) { + if (p[k] == '\'') + s[j++] = '\''; + + s[j++] = p[k]; + } // endfor k + + s[j++] = '\''; + s[j] = 0; + } // endswitch field type } else { - strcat(s, "'"); - strncat(s, res->ptr(), res->length()); - strcat(s, "'"); - } // endif tty + j = strlen(s); + s[j++] = '\''; + p = res->ptr(); + n = res->length(); + + for (k = 0; k < n; k++) { + if (p[k] == '\'') + s[j++] = '\''; + + s[j++] = p[k]; + } // endfor k + + s[j++] = '\''; + s[j] = 0; + } // endif tty break; default: @@ -5386,10 +5410,10 @@ static int connect_assisted_discovery(handlerton *, THD* thd, #endif // __WIN__ //int hdr, mxe; int port = 0, mxr = 0, rc = 0, mul = 0, lrecl = 0; + PCSZ tabtyp = NULL; #if defined(ODBC_SUPPORT) POPARM sop= NULL; PCSZ ucnc= NULL; - PCSZ tabtyp = NULL; bool cnc= false; int cto= -1, qto= -1; #endif // ODBC_SUPPORT diff --git a/storage/connect/inihandl.c b/storage/connect/inihandl.c deleted file mode 100644 index 0ce0eb9fa0d..00000000000 --- a/storage/connect/inihandl.c +++ /dev/null @@ -1,1406 +0,0 @@ -/* - * Profile functions - * - * Copyright 1993 Miguel de Icaza - * Copyright 1996 Alexandre Julliard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ -#include "my_global.h" - -#include -//#include -#include -//#include commented this line out to compile for solaris -#include -#include -#include -#include -//#include -//#include -#include "osutil.h" -#include "global.h" -#include "inihandl.h" - -// The types and variables used locally -//typedef int bool; -typedef unsigned int uint; -#define SVP(S) ((S) ? S : "") -#define _strlwr(P) strlwr(P) //OB: changed this line -#define MAX_PATHNAME_LEN 256 -#define N_CACHED_PROFILES 10 -#ifndef WIN32 -#define stricmp strcasecmp -#define _strnicmp strncasecmp -#endif // !WIN32 -#define EnterCriticalSection(x) -#define LeaveCriticalSection(x) - -#if defined(TEST_MODULE) -// Stand alone test program -#include - int trace = 0; -void htrc(char const *fmt, ...) -{ - va_list ap; - va_start (ap, fmt); - vfprintf(stderr, fmt, ap); - va_end (ap); -} /* end of htrc */ -#else // !TEST_MODULE -// Normal included functions -extern int trace; -void htrc(char const *fmt, ...); -#endif // !TEST MODULE - - -typedef struct tagPROFILEKEY { - char *value; - struct tagPROFILEKEY *next; - char name[1]; - } PROFILEKEY; - -typedef struct tagPROFILESECTION { - struct tagPROFILEKEY *key; - struct tagPROFILESECTION *next; - char name[1]; - } PROFILESECTION; - -typedef struct { - BOOL changed; - PROFILESECTION *section; -//char *dos_name; -//char *unix_name; - char *filename; - time_t mtime; - } PROFILE; - -#define memfree(P) if (P) free(P) - -/* Cached profile files */ -static PROFILE *MRUProfile[N_CACHED_PROFILES] = {NULL}; - -#define CurProfile (MRUProfile[0]) - -/* wine.ini config file registry root */ -//static HKEY wine_profile_key; - -#define PROFILE_MAX_LINE_LEN 1024 - -/* Wine profile name in $HOME directory; must begin with slash */ -//static const char PROFILE_WineIniName[] = "/.winerc"; - -/* Wine profile: the profile file being used */ -//static char PROFILE_WineIniUsed[MAX_PATHNAME_LEN] = ""; - -/* Check for comments in profile */ -#define IS_ENTRY_COMMENT(str) ((str)[0] == ';') - -//static const WCHAR wininiW[] = { 'w','i','n','.','i','n','i',0 }; - -//static CRITICAL_SECTION PROFILE_CritSect = CRITICAL_SECTION_INIT("PROFILE_CritSect"); - -static const char hex[16] = "0123456789ABCDEF"; - -BOOL WritePrivateProfileString(LPCSTR section, LPCSTR entry, - LPCSTR string, LPCSTR filename ); -/*********************************************************************** - * PROFILE_CopyEntry - * - * Copy the content of an entry into a buffer, removing quotes, - * and possibly translating environment variables. - ***********************************************************************/ -static void PROFILE_CopyEntry( char *buffer, const char *value, uint len, - int handle_env ) -{ - const char *p; - char quote = '\0'; - - if (!buffer) - return; - - if ((*value == '\'') || (*value == '\"')) - if (value[1] && (value[strlen(value)-1] == *value)) - quote = *value++; - - if (!handle_env) { - strncpy(buffer, value, len); - - if (quote && (len >= strlen(value))) - buffer[strlen(buffer)-1] = '\0'; - - return; - } // endif handle - - for (p = value; (*p && (len > 1)); *buffer++ = *p++, len--) { - if ((*p == '$') && (p[1] == '{')) { - char env_val[1024]; - const char *env_p; - const char *p2 = strchr(p, '}'); - - if (!p2) - continue; /* ignore it */ - - strncpy(env_val, p + 2, MY_MIN((int) sizeof(env_val), (int)(p2-p)-1)); - - if ((env_p = getenv(env_val)) != NULL) { - int buffer_len; - - strncpy( buffer, env_p, len ); - buffer_len = strlen( buffer ); - buffer += buffer_len; - len -= buffer_len; - } // endif env_p - - p = p2 + 1; - } // endif p - - } // endfor p - - if (quote && (len > 1)) - buffer--; - - *buffer = '\0'; -} // end of PROFILE_CopyEntry - - -/*********************************************************************** - * PROFILE_Save - * - * Save a profile tree to a file. - ***********************************************************************/ -static void PROFILE_Save( FILE *file, PROFILESECTION *section ) -{ - PROFILEKEY *key; - int secno; - - for (secno= 0; section; section= section->next) { - if (section->name[0]) { - fprintf(file, "%s[%s]\n", secno ? "\n" : "", SVP(section->name)); - secno++; - } - - for (key = section->key; key; key = key->next) - if (key->name && key->name[0]) { - fprintf(file, "%s", SVP(key->name)); - - if (key->value) - fprintf(file, "=%s", SVP(key->value)); - - fprintf(file, "\n"); - } // endif key->name - - } // endfor section - -} // end of PROFILE_Save - - -/*********************************************************************** - * PROFILE_Free - * - * Free a profile tree. - ***********************************************************************/ -static void PROFILE_Free( PROFILESECTION *section ) -{ - PROFILESECTION *next_section; - PROFILEKEY *key, *next_key; - - for (; section; section = next_section) { - for (key = section->key; key; key = next_key) { - next_key = key->next; - memfree(key->value); - free(key); - } // endfor key - - next_section = section->next; - free(section); - } // endfor section - -} // end of PROFILE_Free - -static int PROFILE_isspace(char c) -{ - /* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */ - if (isspace(c) || c=='\r' || c==0x1a) - return 1; - - return 0; -} // end of PROFILE_isspace - - -/*********************************************************************** - * PROFILE_Load - * - * Load a profile tree from a file. - ***********************************************************************/ -static PROFILESECTION *PROFILE_Load( FILE *file ) -{ - char buffer[PROFILE_MAX_LINE_LEN]; - char *p, *p2; - int line = 0; - PROFILESECTION *section, *first_section; - PROFILESECTION* *next_section; - PROFILEKEY *key, *prev_key, **next_key; - - first_section = malloc(sizeof(*section)); - - if (first_section == NULL) - return NULL; - - first_section->name[0] = 0; - first_section->key = NULL; - first_section->next = NULL; - next_section = &first_section->next; - next_key = &first_section->key; - prev_key = NULL; - - while (fgets(buffer, PROFILE_MAX_LINE_LEN, file)) { - line++; - p = buffer; - - while (*p && PROFILE_isspace(*p)) - p++; - - if (*p == '[') { /* section start */ - if (!(p2 = strrchr( p, ']'))) { - fprintf(stderr, "Invalid section header at line %d: '%s'\n", - line, p); - } else { - *p2 = '\0'; - p++; - - if (!(section = malloc(sizeof(*section) + strlen(p)))) - break; - - strcpy(section->name, p); - section->key = NULL; - section->next = NULL; - *next_section = section; - next_section = §ion->next; - next_key = §ion->key; - prev_key = NULL; - - if (trace > 1) - htrc("New section: '%s'\n",section->name); - - continue; - } // endif p2 - - } // endif p - - p2 = p + strlen(p) - 1; - - while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) - *p2-- = '\0'; - - if ((p2 = strchr(p, '=')) != NULL) { - char *p3 = p2 - 1; - - while ((p3 > p) && PROFILE_isspace(*p3)) - *p3-- = '\0'; - - *p2++ = '\0'; - - while (*p2 && PROFILE_isspace(*p2)) - p2++; - - } // endif p2 - - if (*p || !prev_key || *prev_key->name) { - if (!(key = malloc(sizeof(*key) + strlen(p)))) - break; - - strcpy(key->name, p); - - if (p2) { - key->value = malloc(strlen(p2)+1); - strcpy(key->value, p2); - } else - key->value = NULL; - - key->next = NULL; - *next_key = key; - next_key = &key->next; - prev_key = key; - - if (trace > 1) - htrc("New key: name='%s', value='%s'\n", - key->name,key->value?key->value:"(none)"); - - } // endif p || prev_key - - } // endif *p - - return first_section; -} // end of PROFILE_Load - -/*********************************************************************** - * PROFILE_FlushFile - * - * Flush the current profile to disk if changed. - ***********************************************************************/ -static BOOL PROFILE_FlushFile(void) -{ -//char *p, buffer[MAX_PATHNAME_LEN]; -//const char *unix_name; - FILE *file = NULL; - struct stat buf; - - if (trace > 1) - htrc("PROFILE_FlushFile: CurProfile=%p\n", CurProfile); - - if (!CurProfile) { - fprintf(stderr, "No current profile!\n"); - return FALSE; - } // endif !CurProfile - - if (!CurProfile->changed || !CurProfile->filename) - return TRUE; - -#if 0 - if (!(file = fopen(unix_name, "w"))) { - /* Try to create it in $HOME/.wine */ - /* FIXME: this will need a more general solution */ - //strcpy( buffer, get_config_dir() ); - //p = buffer + strlen(buffer); - //*p++ = '/'; - char *p1 = strrchr(CurProfile->filename, '\\'); - - p = buffer; // OB: To be elaborate - - if (p1) - p1++; - else - p1 = CurProfile->dos_name; - - strcpy(p, p1); - _strlwr(p); - file = fopen(buffer, "w"); - unix_name = buffer; - } // endif !unix_name -#endif // 0 - - if (!(file = fopen(CurProfile->filename, "w"))) { - fprintf(stderr, "could not save profile file %s\n", CurProfile->filename); - return FALSE; - } // endif !file - - if (trace > 1) - htrc("Saving '%s'\n", CurProfile->filename); - - PROFILE_Save(file, CurProfile->section); - fclose(file); - CurProfile->changed = FALSE; - - if (!stat(CurProfile->filename, &buf)) - CurProfile->mtime = buf.st_mtime; - - return TRUE; -} // end of PROFILE_FlushFile - - -/*********************************************************************** - * PROFILE_ReleaseFile - * - * Flush the current profile to disk and remove it from the cache. - ***********************************************************************/ -static void PROFILE_ReleaseFile(void) -{ - PROFILE_FlushFile(); - PROFILE_Free(CurProfile->section); -//memfree(CurProfile->dos_name); -//memfree(CurProfile->unix_name); - memfree(CurProfile->filename); - CurProfile->changed = FALSE; - CurProfile->section = NULL; -//CurProfile->dos_name = NULL; -//CurProfile->unix_name = NULL; - CurProfile->filename = NULL; - CurProfile->mtime = 0; -} // end of PROFILE_ReleaseFile - - -/*********************************************************************** - * PROFILE_Open - * - * Open a profile file, checking the cached file first. - ***********************************************************************/ -static BOOL PROFILE_Open(LPCSTR filename) -{ -//char buffer[MAX_PATHNAME_LEN]; -//char *p; - FILE *file = NULL; - int i, j; - struct stat buf; - PROFILE *tempProfile; - - if (trace > 1) - htrc("PROFILE_Open: CurProfile=%p N=%d\n", CurProfile, N_CACHED_PROFILES); - - /* First time around */ - if (!CurProfile) - for (i = 0; i < N_CACHED_PROFILES; i++) { - MRUProfile[i] = malloc(sizeof(PROFILE)); - - if (MRUProfile[i] == NULL) - break; - - MRUProfile[i]->changed=FALSE; - MRUProfile[i]->section=NULL; -// MRUProfile[i]->dos_name=NULL; -// MRUProfile[i]->unix_name=NULL; - MRUProfile[i]->filename=NULL; - MRUProfile[i]->mtime=0; - } // endfor i - - /* Check for a match */ - for (i = 0; i < N_CACHED_PROFILES; i++) { - if (trace > 1) - htrc("MRU=%s i=%d\n", SVP(MRUProfile[i]->filename), i); - - if (MRUProfile[i]->filename && !strcmp(filename, MRUProfile[i]->filename)) { - if (i) { - PROFILE_FlushFile(); - tempProfile = MRUProfile[i]; - - for (j = i; j > 0; j--) - MRUProfile[j] = MRUProfile[j-1]; - - CurProfile=tempProfile; - } // endif i - - if (!stat(CurProfile->filename, &buf) && CurProfile->mtime == buf.st_mtime) { - if (trace > 1) - htrc("(%s): already opened (mru=%d)\n", filename, i); - - } else { - if (trace > 1) - htrc("(%s): already opened, needs refreshing (mru=%d)\n", filename, i); - - } // endif stat - - return TRUE; - } // endif filename - - } // endfor i - - /* Flush the old current profile */ - PROFILE_FlushFile(); - - /* Make the oldest profile the current one only in order to get rid of it */ - if (i == N_CACHED_PROFILES) { - tempProfile = MRUProfile[N_CACHED_PROFILES-1]; - - for(i = N_CACHED_PROFILES-1; i > 0; i--) - MRUProfile[i] = MRUProfile[i-1]; - - CurProfile = tempProfile; - } // endif i - - if (CurProfile->filename) - PROFILE_ReleaseFile(); - - /* OK, now that CurProfile is definitely free we assign it our new file */ -// newdos_name = HeapAlloc( GetProcessHeap(), 0, strlen(full_name.short_name)+1 ); -// strcpy( newdos_name, full_name.short_name ); - -// newdos_name = malloc(strlen(filename)+1); -// strcpy(newdos_name, filename); - -// CurProfile->dos_name = newdos_name; - CurProfile->filename = malloc(strlen(filename) + 1); - strcpy(CurProfile->filename, filename); - - /* Try to open the profile file, first in $HOME/.wine */ - - /* FIXME: this will need a more general solution */ -// strcpy( buffer, get_config_dir() ); -// p = buffer + strlen(buffer); -// *p++ = '/'; -// strcpy( p, strrchr( newdos_name, '\\' ) + 1 ); -// p = buffer; -// strcpy(p, filename); -// _strlwr(p); - - if (trace > 1) - htrc("Opening %s\n", filename); - - if ((file = fopen(filename, "r"))) { - if (trace > 1) - htrc("(%s): found it\n", filename); - -// CurProfile->unix_name = malloc(strlen(buffer)+1); -// strcpy(CurProfile->unix_name, buffer); - } /* endif file */ - - if (file) { - CurProfile->section = PROFILE_Load(file); - fclose(file); - - if (!stat(CurProfile->filename, &buf)) - CurProfile->mtime = buf.st_mtime; - - } else { - /* Does not exist yet, we will create it in PROFILE_FlushFile */ - fprintf(stderr, "profile file %s not found\n", filename); - } /* endif file */ - - return TRUE; -} - - -/*********************************************************************** - * PROFILE_Close - * - * Flush the named profile to disk and remove it from the cache. - ***********************************************************************/ -void PROFILE_Close(LPCSTR filename) -{ - int i; - BOOL close = FALSE; - struct stat buf; - PROFILE *tempProfile; - - if (trace > 1) - htrc("PROFILE_Close: CurProfile=%p N=%d\n", CurProfile, N_CACHED_PROFILES); - - /* Check for a match */ - for (i = 0; i < N_CACHED_PROFILES; i++) { - if (trace > 1) - htrc("MRU=%s i=%d\n", SVP(MRUProfile[i]->filename), i); - - if (MRUProfile[i]->filename && !strcmp(filename, MRUProfile[i]->filename)) { - if (i) { - /* Make the profile to close current */ - tempProfile = MRUProfile[i]; - MRUProfile[i] = MRUProfile[0]; - MRUProfile[0] = tempProfile; - CurProfile=tempProfile; - } // endif i - - if (trace > 1) { - if (!stat(CurProfile->filename, &buf) && CurProfile->mtime == buf.st_mtime) - htrc("(%s): already opened (mru=%d)\n", filename, i); - else - htrc("(%s): already opened, needs refreshing (mru=%d)\n", filename, i); - - } // endif trace - - close = TRUE; - break; - } // endif filename - - } // endfor i - - if (close) - PROFILE_ReleaseFile(); - -} // end of PROFILE_Close - - -/*********************************************************************** - * PROFILE_End - * - * Terminate and release the cache. - ***********************************************************************/ -void PROFILE_End(void) -{ - int i; - - if (trace) - htrc("PROFILE_End: CurProfile=%p N=%d\n", CurProfile, N_CACHED_PROFILES); - - if (!CurProfile) // Sergey Vojtovich - return; - - /* Close all opened files and free the cache structure */ - for (i = 0; i < N_CACHED_PROFILES; i++) { - if (trace) - htrc("MRU=%s i=%d\n", SVP(MRUProfile[i]->filename), i); - -// CurProfile = MRUProfile[i]; Sergey Vojtovich -// PROFILE_ReleaseFile(); see MDEV-9997 - free(MRUProfile[i]); - } // endfor i - -} // end of PROFILE_End - - -/*********************************************************************** - * PROFILE_DeleteSection - * - * Delete a section from a profile tree. - ***********************************************************************/ -static BOOL PROFILE_DeleteSection(PROFILESECTION* *section, LPCSTR name) -{ - while (*section) { - if ((*section)->name[0] && !stricmp((*section)->name, name)) { - PROFILESECTION *to_del = *section; - - *section = to_del->next; - to_del->next = NULL; - PROFILE_Free(to_del); - return TRUE; - } // endif section - - section = &(*section)->next; - } // endwhile section - - return FALSE; -} // end of PROFILE_DeleteSection - - -/*********************************************************************** - * PROFILE_DeleteKey - * - * Delete a key from a profile tree. - ***********************************************************************/ -static BOOL PROFILE_DeleteKey(PROFILESECTION* *section, - LPCSTR section_name, LPCSTR key_name) -{ - while (*section) { - if ((*section)->name[0] && !stricmp((*section)->name, section_name)) { - PROFILEKEY* *key = &(*section)->key; - - while (*key) { - if (!stricmp((*key)->name, key_name)) { - PROFILEKEY *to_del = *key; - - *key = to_del->next; - memfree(to_del->value); - free(to_del); - return TRUE; - } // endif name - - key = &(*key)->next; - } // endwhile *key - - } // endif section->name - - section = &(*section)->next; - } // endwhile *section - - return FALSE; -} // end of PROFILE_DeleteKey - - -/*********************************************************************** - * PROFILE_DeleteAllKeys - * - * Delete all keys from a profile tree. - ***********************************************************************/ -static void PROFILE_DeleteAllKeys(LPCSTR section_name) -{ - PROFILESECTION* *section= &CurProfile->section; - - while (*section) { - if ((*section)->name[0] && !stricmp((*section)->name, section_name)) { - PROFILEKEY* *key = &(*section)->key; - - while (*key) { - PROFILEKEY *to_del = *key; - - *key = to_del->next; - memfree(to_del->value); - free(to_del); - CurProfile->changed = TRUE; - } // endwhile *key - - } // endif section->name - - section = &(*section)->next; - } // endwhile *section - -} // end of PROFILE_DeleteAllKeys - - -/*********************************************************************** - * PROFILE_Find - * - * Find a key in a profile tree, optionally creating it. - ***********************************************************************/ -static PROFILEKEY *PROFILE_Find(PROFILESECTION* *section, - const char *section_name, - const char *key_name, - BOOL create, BOOL create_always) -{ - const char *p; - int seclen, keylen; - - while (PROFILE_isspace(*section_name)) - section_name++; - - p = section_name + strlen(section_name) - 1; - - while ((p > section_name) && PROFILE_isspace(*p)) - p--; - - seclen = p - section_name + 1; - - while (PROFILE_isspace(*key_name)) - key_name++; - - p = key_name + strlen(key_name) - 1; - - while ((p > key_name) && PROFILE_isspace(*p)) - p--; - - keylen = p - key_name + 1; - - while (*section) { - if (((*section)->name[0]) - && (!(_strnicmp((*section)->name, section_name, seclen ))) - && (((*section)->name)[seclen] == '\0')) { - PROFILEKEY* *key = &(*section)->key; - - while (*key) { - /* If create_always is FALSE then we check if the keyname already exists. - * Otherwise we add it regardless of its existence, to allow - * keys to be added more then once in some cases. - */ - if (!create_always) { - if ((!(_strnicmp( (*key)->name, key_name, keylen ))) - && (((*key)->name)[keylen] == '\0')) - return *key; - - } // endif !create_always - - key = &(*key)->next; - } // endwhile *key - - if (!create) - return NULL; - - if (!(*key = malloc(sizeof(PROFILEKEY) + strlen(key_name)))) - return NULL; - - strcpy((*key)->name, key_name); - (*key)->value = NULL; - (*key)->next = NULL; - return *key; - } // endifsection->name - - section = &(*section)->next; - } // endwhile *section - - if (!create) - return NULL; - - *section = malloc(sizeof(PROFILESECTION) + strlen(section_name)); - - if (*section == NULL) - return NULL; - - strcpy((*section)->name, section_name); - (*section)->next = NULL; - - if (!((*section)->key = malloc(sizeof(PROFILEKEY) + strlen(key_name)))) { - free(*section); - return NULL; - } // endif malloc - - strcpy((*section)->key->name, key_name); - (*section)->key->value = NULL; - (*section)->key->next = NULL; - return (*section)->key; -} // end of PROFILE_Find - - -/*********************************************************************** - * PROFILE_GetSection - * - * Returns all keys of a section. - * If return_values is TRUE, also include the corresponding values. - ***********************************************************************/ -static int PROFILE_GetSection(PROFILESECTION *section, LPCSTR section_name, - LPSTR buffer, uint len, - BOOL handle_env, BOOL return_values) -{ - PROFILEKEY *key; - - if(!buffer) - return 0; - - while (section) { - if (section->name[0] && !stricmp(section->name, section_name)) { - uint oldlen = len; - - for (key = section->key; key; key = key->next) { - if (len <= 2) - break; - - if (!*key->name) - continue; /* Skip empty lines */ - - if (IS_ENTRY_COMMENT(key->name)) - continue; /* Skip comments */ - - PROFILE_CopyEntry(buffer, key->name, len - 1, handle_env); - len -= strlen(buffer) + 1; - buffer += strlen(buffer) + 1; - - if (len < 2) - break; - - if (return_values && key->value) { - buffer[-1] = '='; - PROFILE_CopyEntry(buffer, key->value, len - 1, handle_env); - len -= strlen(buffer) + 1; - buffer += strlen(buffer) + 1; - } // endif return_values - - } // endfor key - - *buffer = '\0'; - - if (len <= 1) { - /*If either lpszSection or lpszKey is NULL and the supplied - destination buffer is too small to hold all the strings, - the last string is truncated and followed by two null characters. - In this case, the return value is equal to cchReturnBuffer - minus two. */ - buffer[-1] = '\0'; - return oldlen - 2; - } // endif len - - return oldlen - len; - } // endif section->name - - section = section->next; - } // endwhile section - - buffer[0] = buffer[1] = '\0'; - return 0; -} // end of PROFILE_GetSection - - -/* See GetPrivateProfileSectionNamesA for documentation */ -static int PROFILE_GetSectionNames(LPSTR buffer, uint len) -{ - LPSTR buf; - uint f,l; - PROFILESECTION *section; - - if (trace > 1) - htrc("GetSectionNames: buffer=%p len=%u\n", buffer, len); - - if (!buffer || !len) - return 0; - - if (len == 1) { - *buffer='\0'; - return 0; - } // endif len - - f = len - 1; - buf = buffer; - section = CurProfile->section; - - if (trace > 1) - htrc("GetSectionNames: section=%p\n", section); - - while (section != NULL) { - if (trace > 1) - htrc("section=%s\n", section->name); - - if (section->name[0]) { - l = strlen(section->name) + 1; - - if (trace > 1) - htrc("l=%u f=%u\n", l, f); - - if (l > f) { - if (f > 0) { - strncpy(buf, section->name, f-1); - buf += f-1; - *buf++='\0'; - } // endif f - - *buf = '\0'; - return len - 2; - } // endif l - - strcpy(buf, section->name); - buf += l; - f -= l; - } // endif section->name - - section = section->next; - } // endwhile section - - *buf='\0'; - return buf-buffer; -} // end of PROFILE_GetSectionNames - - -/*********************************************************************** - * PROFILE_GetString - * - * Get a profile string. - * - * Tests with GetPrivateProfileString16, W95a, - * with filled buffer ("****...") and section "set1" and key_name "1" valid: - * section key_name def_val res buffer - * "set1" "1" "x" 43 [data] - * "set1" "1 " "x" 43 [data] (!) - * "set1" " 1 "' "x" 43 [data] (!) - * "set1" "" "x" 1 "x" - * "set1" "" "x " 1 "x" (!) - * "set1" "" " x " 3 " x" (!) - * "set1" NULL "x" 6 "1\02\03\0\0" - * "set1" "" "x" 1 "x" - * NULL "1" "x" 0 "" (!) - * "" "1" "x" 1 "x" - * NULL NULL "" 0 "" - * - *************************************************************************/ -static int PROFILE_GetString(LPCSTR section, LPCSTR key_name, - LPCSTR def_val, LPSTR buffer, uint len) -{ - PROFILEKEY *key = NULL; - - if(!buffer) - return 0; - - if (!def_val) - def_val = ""; - - if (key_name && key_name[0]) { - key = PROFILE_Find(&CurProfile->section, section, key_name, FALSE, FALSE); - PROFILE_CopyEntry(buffer, (key && key->value) ? key->value : def_val, len, FALSE); - - if (trace > 1) - htrc("('%s','%s','%s'): returning '%s'\n", - section, key_name, def_val, buffer ); - - return strlen(buffer); - } // endif key_name - - if (key_name && !(key_name[0])) - /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227 */ - return 0; - - if (section && section[0]) - return PROFILE_GetSection(CurProfile->section, section, buffer, len, - FALSE, FALSE); - buffer[0] = '\0'; - return 0; -} // end of PROFILE_GetString - - -/*********************************************************************** - * PROFILE_SetString - * - * Set a profile string. - ***********************************************************************/ -static BOOL PROFILE_SetString(LPCSTR section_name, LPCSTR key_name, - LPCSTR value, BOOL create_always) -{ - if (!key_name) { /* Delete a whole section */ - if (trace > 1) - htrc("Deleting('%s')\n", section_name); - - CurProfile->changed |= PROFILE_DeleteSection(&CurProfile->section, - section_name); - return TRUE; /* Even if PROFILE_DeleteSection() has failed, - this is not an error on application's level.*/ - } else if (!value) { /* Delete a key */ - if (trace > 1) - htrc("Deleting('%s','%s')\n", section_name, key_name); - - CurProfile->changed |= PROFILE_DeleteKey(&CurProfile->section, - section_name, key_name); - return TRUE; /* same error handling as above */ - } else { /* Set the key value */ - PROFILEKEY *key = PROFILE_Find(&CurProfile->section, section_name, - key_name, TRUE, create_always); - if (trace > 1) - htrc("Setting('%s','%s','%s')\n", section_name, key_name, value); - - if (!key) - return FALSE; - - if (key->value) { - /* strip the leading spaces. We can safely strip \n\r and - * friends too, they should not happen here anyway. */ - while (PROFILE_isspace(*value)) - value++; - - if (!strcmp(key->value, value)) { - if (trace > 1) - htrc(" no change needed\n" ); - - return TRUE; /* No change needed */ - } // endif value - - if (trace > 1) - htrc(" replacing '%s'\n", key->value); - - free(key->value); - } else if (trace > 1) - htrc(" creating key\n" ); - - key->value = malloc(strlen(value) + 1); - strcpy(key->value, value); - CurProfile->changed = TRUE; - } // endelse - - return TRUE; -} // end of PROFILE_SetString - - -/*********************************************************************** - * PROFILE_GetStringItem - * - * Convenience function that turns a string 'xxx, yyy, zzz' into - * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'. - ***********************************************************************/ -#if 0 -char *PROFILE_GetStringItem(char* start) -{ - char *lpchX, *lpch; - - for (lpchX = start, lpch = NULL; *lpchX != '\0'; lpchX++) { - if (*lpchX == ',') { - if (lpch) - *lpch = '\0'; - else - *lpchX = '\0'; - - while(*(++lpchX)) - if (!PROFILE_isspace(*lpchX)) - return lpchX; - - } else if (PROFILE_isspace(*lpchX) && !lpch) { - lpch = lpchX; - } else - lpch = NULL; - - } // endfor lpchX - - if (lpch) - *lpch = '\0'; - - return NULL; -} // end of PROFILE_GetStringItem -#endif - -/********************************************************************** - * if allow_section_name_copy is TRUE, allow the copying : - * - of Section names if 'section' is NULL - * - of Keys in a Section if 'entry' is NULL - * (see MSDN doc for GetPrivateProfileString) - **********************************************************************/ -static int PROFILE_GetPrivateProfileString(LPCSTR section, LPCSTR entry, - LPCSTR def_val, LPSTR buffer, - uint len, LPCSTR filename, - BOOL allow_section_name_copy) -{ - int ret; - LPSTR pDefVal = NULL; - - if (!filename) - filename = "win.ini"; - - /* strip any trailing ' ' of def_val. */ - if (def_val) { - LPSTR p = (LPSTR)&def_val[strlen(def_val)]; // even "" works ! - - while (p > def_val) - if ((*(--p)) != ' ') - break; - - if (*p == ' ') { /* ouch, contained trailing ' ' */ - int len = p - (LPSTR)def_val; - - pDefVal = malloc(len + 1); - strncpy(pDefVal, def_val, len); - pDefVal[len] = '\0'; - } // endif *p - - } // endif def_val - - if (!pDefVal) - pDefVal = (LPSTR)def_val; - - EnterCriticalSection(&PROFILE_CritSect); - - if (PROFILE_Open(filename)) { - if ((allow_section_name_copy) && (section == NULL)) - ret = PROFILE_GetSectionNames(buffer, len); - else - /* PROFILE_GetString already handles the 'entry == NULL' case */ - ret = PROFILE_GetString(section, entry, pDefVal, buffer, len); - - } else { - strncpy(buffer, pDefVal, len); - ret = strlen(buffer); - } // endif Open - - LeaveCriticalSection(&PROFILE_CritSect); - - if (pDefVal != def_val) /* allocated */ - memfree(pDefVal); - - return ret; -} // end of PROFILE_GetPrivateProfileString - -/********************** API functions **********************************/ - -/*********************************************************************** - * GetPrivateProfileStringA (KERNEL32.@) - ***********************************************************************/ -int GetPrivateProfileString(LPCSTR section, LPCSTR entry, LPCSTR def_val, - LPSTR buffer, DWORD len, LPCSTR filename) -{ - return PROFILE_GetPrivateProfileString(section, entry, def_val, - buffer, len, filename, TRUE); -} // end of GetPrivateProfileString - - -/*********************************************************************** - * GetPrivateProfileIntA (KERNEL32.@) - ***********************************************************************/ -uint GetPrivateProfileInt(LPCSTR section, LPCSTR entry, - int def_val, LPCSTR filename) -{ - char buffer[20]; - int result; - - if (!PROFILE_GetPrivateProfileString(section, entry, "", buffer, - sizeof(buffer), filename, FALSE)) - return def_val; - - /* FIXME: if entry can be found but it's empty, then Win16 is - * supposed to return 0 instead of def_val ! Difficult/problematic - * to implement (every other failure also returns zero buffer), - * thus wait until testing framework avail for making sure nothing - * else gets broken that way. */ - if (!buffer[0]) - return (uint)def_val; - - /* Don't use strtol() here ! - * (returns LONG_MAX/MIN on overflow instead of "proper" overflow) - YES, scan for unsigned format ! (otherwise compatibility error) */ - if (!sscanf(buffer, "%u", &result)) - return 0; - - return (uint)result; -} // end of GetPrivateProfileInt - - -/*********************************************************************** - * GetPrivateProfileSectionA (KERNEL32.@) - ***********************************************************************/ -int GetPrivateProfileSection(LPCSTR section, LPSTR buffer, - DWORD len, LPCSTR filename) -{ - int ret = 0; - - EnterCriticalSection( &PROFILE_CritSect ); - - if (PROFILE_Open(filename)) - ret = PROFILE_GetSection(CurProfile->section, section, buffer, len, - FALSE, TRUE); - - LeaveCriticalSection( &PROFILE_CritSect ); - return ret; -} // end of GetPrivateProfileSection - - -/*********************************************************************** - * WritePrivateProfileStringA (KERNEL32.@) - ***********************************************************************/ -BOOL WritePrivateProfileString(LPCSTR section, LPCSTR entry, - LPCSTR string, LPCSTR filename) -{ - BOOL ret = FALSE; - - EnterCriticalSection( &PROFILE_CritSect ); - - if (PROFILE_Open(filename)) { - if (!section && !entry && !string) /* documented "file flush" case */ - PROFILE_ReleaseFile(); /* always return FALSE in this case */ - else { - if (!section) { - //FIXME("(NULL?,%s,%s,%s)? \n",entry,string,filename); - } else { - ret = PROFILE_SetString(section, entry, string, FALSE); - - if (ret) - ret = PROFILE_FlushFile(); - - } // endif section - - } // endif section || entry|| string - - } // endif Open - - LeaveCriticalSection( &PROFILE_CritSect ); - return ret; -} // end of WritePrivateProfileString - - -/*********************************************************************** - * WritePrivateProfileSectionA (KERNEL32.@) - ***********************************************************************/ -BOOL WritePrivateProfileSection(LPCSTR section, - LPCSTR string, LPCSTR filename ) -{ - BOOL ret = FALSE; - LPSTR p ; - - EnterCriticalSection(&PROFILE_CritSect); - - if (PROFILE_Open(filename)) { - if (!section && !string) - PROFILE_ReleaseFile(); /* always return FALSE in this case */ - else if (!string) { /* delete the named section*/ - ret = PROFILE_SetString(section, NULL, NULL, FALSE); - - if (ret) - ret = PROFILE_FlushFile(); - } else { - PROFILE_DeleteAllKeys(section); - ret = TRUE; - - while (*string) { - LPSTR buf = malloc(strlen(string) + 1); - strcpy(buf, string); - - if ((p = strchr(buf, '='))) { - *p='\0'; - ret = PROFILE_SetString(section, buf, p+1, TRUE); - } // endif p - - free(buf); - string += strlen(string) + 1; - - if (ret) - ret = PROFILE_FlushFile(); - - } // endwhile *string - - } // endelse - - } // endif Open - - LeaveCriticalSection(&PROFILE_CritSect); - return ret; -} // end of WritePrivateProfileSection - - -/*********************************************************************** - * GetPrivateProfileSectionNamesA (KERNEL32.@) - * - * Returns the section names contained in the specified file. - * FIXME: Where do we find this file when the path is relative? - * The section names are returned as a list of strings with an extra - * '\0' to mark the end of the list. Except for that the behavior - * depends on the Windows version. - * - * Win95: - * - if the buffer is 0 or 1 character long then it is as if it was of - * infinite length. - * - otherwise, if the buffer is to small only the section names that fit - * are returned. - * - note that this means if the buffer was to small to return even just - * the first section name then a single '\0' will be returned. - * - the return value is the number of characters written in the buffer, - * except if the buffer was too smal in which case len-2 is returned - * - * Win2000: - * - if the buffer is 0, 1 or 2 characters long then it is filled with - * '\0' and the return value is 0 - * - otherwise if the buffer is too small then the first section name that - * does not fit is truncated so that the string list can be terminated - * correctly (double '\0') - * - the return value is the number of characters written in the buffer - * except for the trailing '\0'. If the buffer is too small, then the - * return value is len-2 - * - Win2000 has a bug that triggers when the section names and the - * trailing '\0' fit exactly in the buffer. In that case the trailing - * '\0' is missing. - * - * Wine implements the observed Win2000 behavior (except for the bug). - * - * Note that when the buffer is big enough then the return value may be any - * value between 1 and len-1 (or len in Win95), including len-2. - */ -static DWORD -GetPrivateProfileSectionNames(LPSTR buffer, DWORD size, LPCSTR filename) -{ - DWORD ret = 0; - - if (trace > 1) - htrc("GPPSN: filename=%s\n", filename); - - EnterCriticalSection(&PROFILE_CritSect); - - if (PROFILE_Open(filename)) - ret = PROFILE_GetSectionNames(buffer, size); - - LeaveCriticalSection(&PROFILE_CritSect); - return ret; -} // end of GetPrivateProfileSectionNames - - -/************************************************************************ - * Program to test the above - ************************************************************************/ -#ifdef TEST_MODULE -int main(int argc, char**argv) { - char buff[128]; - char *p, *inifile = "D:\\Plug\\Data\\contact.ini"; - DWORD n; - - n = GetPrivateProfileSectionNames(buff, 128, inifile); - printf("Sections: n=%d\n", n); - - for (p = buff; *p; p += (strlen(p) + 1)) - printf("section=[%s]\n", p); - - GetPrivateProfileString("BER", "name", "?", buff, 128, inifile); - printf("[BER](name) = %s\n", buff); - - WritePrivateProfileString("FOO", "city", NULL, inifile); - GetPrivateProfileString("FOO", "city", "?", buff, 128, inifile); - printf("[FOO](city) = %s\n", buff); - - printf("FOO city: "); - fgets(buff, sizeof(buff), stdin); - if (buff[strlen(buff) - 1] == '\n') - buff[strlen(buff) - 1] = '\0'; - WritePrivateProfileString("FOO", "city", buff, inifile); - GetPrivateProfileString("FOO", "city", "???", buff, 128, inifile); - printf("After write, [FOO](City) = %s\n", buff); - - printf("New city: "); - fgets(buff, sizeof(buff), stdin); - if (buff[strlen(buff) - 1] == '\n') - buff[strlen(buff) - 1] = '\0'; - WritePrivateProfileString("FOO", "city", buff, inifile); - GetPrivateProfileString("FOO", "city", "???", buff, 128, inifile); - printf("After update, [FOO](City) = %s\n", buff); - - printf("FOO name: "); - fgets(buff, sizeof(buff), stdin); - if (buff[strlen(buff) - 1] == '\n') - buff[strlen(buff) - 1] = '\0'; - WritePrivateProfileString("FOO", "name", buff, inifile); - GetPrivateProfileString("FOO", "name", "X", buff, 128, inifile); - printf("[FOO](name) = %s\n", buff); -} // end of main -#endif // TEST_MODULE diff --git a/storage/connect/inihandl.cpp b/storage/connect/inihandl.cpp new file mode 100644 index 00000000000..96ae0a67a6b --- /dev/null +++ b/storage/connect/inihandl.cpp @@ -0,0 +1,1407 @@ +/* + * Profile functions + * + * Copyright 1993 Miguel de Icaza + * Copyright 1996 Alexandre Julliard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ +#include "my_global.h" + +#include +//#include +#include +//#include commented this line out to compile for solaris +#include +#include +#include +#include +//#include +//#include +#include "osutil.h" +#include "global.h" +#include "inihandl.h" + +// The types and variables used locally +//typedef int bool; +typedef unsigned int uint; +//#define SVP(S) ((S) ? S : "") +#define _strlwr(P) strlwr(P) //OB: changed this line +#define MAX_PATHNAME_LEN 256 +#define N_CACHED_PROFILES 10 +#ifndef WIN32 +#define stricmp strcasecmp +#define _strnicmp strncasecmp +#endif // !WIN32 +#define EnterCriticalSection(x) +#define LeaveCriticalSection(x) + +#if defined(TEST_MODULE) +// Stand alone test program +#include + int trace = 0; +void htrc(char const *fmt, ...) +{ + va_list ap; + va_start (ap, fmt); + vfprintf(stderr, fmt, ap); + va_end (ap); +} /* end of htrc */ +#else // !TEST_MODULE +// Normal included functions +//extern int trace; +//void htrc(char const *fmt, ...); +#endif // !TEST MODULE + + +typedef struct tagPROFILEKEY { + char *value; + struct tagPROFILEKEY *next; + char name[1]; + } PROFILEKEY; + +typedef struct tagPROFILESECTION { + struct tagPROFILEKEY *key; + struct tagPROFILESECTION *next; + char name[1]; + } PROFILESECTION; + +typedef struct { + BOOL changed; + PROFILESECTION *section; +//char *dos_name; +//char *unix_name; + char *filename; + time_t mtime; + } PROFILE; + +#define memfree(P) if (P) free(P) + +/* Cached profile files */ +static PROFILE *MRUProfile[N_CACHED_PROFILES] = {NULL}; + +#define CurProfile (MRUProfile[0]) + +/* wine.ini config file registry root */ +//static HKEY wine_profile_key; + +#define PROFILE_MAX_LINE_LEN 1024 + +/* Wine profile name in $HOME directory; must begin with slash */ +//static const char PROFILE_WineIniName[] = "/.winerc"; + +/* Wine profile: the profile file being used */ +//static char PROFILE_WineIniUsed[MAX_PATHNAME_LEN] = ""; + +/* Check for comments in profile */ +#define IS_ENTRY_COMMENT(str) ((str)[0] == ';') + +//static const WCHAR wininiW[] = { 'w','i','n','.','i','n','i',0 }; + +//static CRITICAL_SECTION PROFILE_CritSect = CRITICAL_SECTION_INIT("PROFILE_CritSect"); + +static const char hex[17] = "0123456789ABCDEF"; + +BOOL WritePrivateProfileString(LPCSTR section, LPCSTR entry, + LPCSTR string, LPCSTR filename); + +/*********************************************************************** + * PROFILE_CopyEntry + * + * Copy the content of an entry into a buffer, removing quotes, + * and possibly translating environment variables. + ***********************************************************************/ +static void PROFILE_CopyEntry( char *buffer, const char *value, uint len, + int handle_env ) +{ + const char *p; + char quote = '\0'; + + if (!buffer) + return; + + if ((*value == '\'') || (*value == '\"')) + if (value[1] && (value[strlen(value)-1] == *value)) + quote = *value++; + + if (!handle_env) { + strncpy(buffer, value, len); + + if (quote && (len >= strlen(value))) + buffer[strlen(buffer)-1] = '\0'; + + return; + } // endif handle + + for (p = value; (*p && (len > 1)); *buffer++ = *p++, len--) { + if ((*p == '$') && (p[1] == '{')) { + char env_val[1024]; + const char *env_p; + const char *p2 = strchr(p, '}'); + + if (!p2) + continue; /* ignore it */ + + strncpy(env_val, p + 2, MY_MIN((int) sizeof(env_val), (int)(p2-p)-1)); + + if ((env_p = getenv(env_val)) != NULL) { + int buffer_len; + + strncpy( buffer, env_p, len ); + buffer_len = strlen( buffer ); + buffer += buffer_len; + len -= buffer_len; + } // endif env_p + + p = p2 + 1; + } // endif p + + } // endfor p + + if (quote && (len > 1)) + buffer--; + + *buffer = '\0'; +} // end of PROFILE_CopyEntry + + +/*********************************************************************** + * PROFILE_Save + * + * Save a profile tree to a file. + ***********************************************************************/ +static void PROFILE_Save( FILE *file, PROFILESECTION *section ) +{ + PROFILEKEY *key; + int secno; + + for (secno= 0; section; section= section->next) { + if (section->name[0]) { + fprintf(file, "%s[%s]\n", secno ? "\n" : "", SVP(section->name)); + secno++; + } + + for (key = section->key; key; key = key->next) + if (key->name && key->name[0]) { + fprintf(file, "%s", SVP(key->name)); + + if (key->value) + fprintf(file, "=%s", SVP(key->value)); + + fprintf(file, "\n"); + } // endif key->name + + } // endfor section + +} // end of PROFILE_Save + + +/*********************************************************************** + * PROFILE_Free + * + * Free a profile tree. + ***********************************************************************/ +static void PROFILE_Free( PROFILESECTION *section ) +{ + PROFILESECTION *next_section; + PROFILEKEY *key, *next_key; + + for (; section; section = next_section) { + for (key = section->key; key; key = next_key) { + next_key = key->next; + memfree(key->value); + free(key); + } // endfor key + + next_section = section->next; + free(section); + } // endfor section + +} // end of PROFILE_Free + +static int PROFILE_isspace(char c) +{ + /* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */ + if (isspace(c) || c=='\r' || c==0x1a) + return 1; + + return 0; +} // end of PROFILE_isspace + + +/*********************************************************************** + * PROFILE_Load + * + * Load a profile tree from a file. + ***********************************************************************/ +static PROFILESECTION *PROFILE_Load( FILE *file ) +{ + char buffer[PROFILE_MAX_LINE_LEN]; + char *p, *p2; + int line = 0; + PROFILESECTION *section, *first_section; + PROFILESECTION* *next_section; + PROFILEKEY *key, *prev_key, **next_key; + + first_section = (PROFILESECTION*)malloc(sizeof(*section)); + + if (first_section == NULL) + return NULL; + + first_section->name[0] = 0; + first_section->key = NULL; + first_section->next = NULL; + next_section = &first_section->next; + next_key = &first_section->key; + prev_key = NULL; + + while (fgets(buffer, PROFILE_MAX_LINE_LEN, file)) { + line++; + p = buffer; + + while (*p && PROFILE_isspace(*p)) + p++; + + if (*p == '[') { /* section start */ + if (!(p2 = strrchr( p, ']'))) { + fprintf(stderr, "Invalid section header at line %d: '%s'\n", + line, p); + } else { + *p2 = '\0'; + p++; + + if (!(section = (PROFILESECTION*)malloc(sizeof(*section) + strlen(p)))) + break; + + strcpy(section->name, p); + section->key = NULL; + section->next = NULL; + *next_section = section; + next_section = §ion->next; + next_key = §ion->key; + prev_key = NULL; + + if (trace > 1) + htrc("New section: '%s'\n",section->name); + + continue; + } // endif p2 + + } // endif p + + p2 = p + strlen(p) - 1; + + while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) + *p2-- = '\0'; + + if ((p2 = strchr(p, '=')) != NULL) { + char *p3 = p2 - 1; + + while ((p3 > p) && PROFILE_isspace(*p3)) + *p3-- = '\0'; + + *p2++ = '\0'; + + while (*p2 && PROFILE_isspace(*p2)) + p2++; + + } // endif p2 + + if (*p || !prev_key || *prev_key->name) { + if (!(key = (PROFILEKEY*)malloc(sizeof(*key) + strlen(p)))) + break; + + strcpy(key->name, p); + + if (p2) { + key->value = (char*)malloc(strlen(p2)+1); + strcpy(key->value, p2); + } else + key->value = NULL; + + key->next = NULL; + *next_key = key; + next_key = &key->next; + prev_key = key; + + if (trace > 1) + htrc("New key: name='%s', value='%s'\n", + key->name,key->value?key->value:"(none)"); + + } // endif p || prev_key + + } // endif *p + + return first_section; +} // end of PROFILE_Load + +/*********************************************************************** + * PROFILE_FlushFile + * + * Flush the current profile to disk if changed. + ***********************************************************************/ +static BOOL PROFILE_FlushFile(void) +{ +//char *p, buffer[MAX_PATHNAME_LEN]; +//const char *unix_name; + FILE *file = NULL; + struct stat buf; + + if (trace > 1) + htrc("PROFILE_FlushFile: CurProfile=%p\n", CurProfile); + + if (!CurProfile) { + fprintf(stderr, "No current profile!\n"); + return FALSE; + } // endif !CurProfile + + if (!CurProfile->changed || !CurProfile->filename) + return TRUE; + +#if 0 + if (!(file = fopen(unix_name, "w"))) { + /* Try to create it in $HOME/.wine */ + /* FIXME: this will need a more general solution */ + //strcpy( buffer, get_config_dir() ); + //p = buffer + strlen(buffer); + //*p++ = '/'; + char *p1 = strrchr(CurProfile->filename, '\\'); + + p = buffer; // OB: To be elaborate + + if (p1) + p1++; + else + p1 = CurProfile->dos_name; + + strcpy(p, p1); + _strlwr(p); + file = fopen(buffer, "w"); + unix_name = buffer; + } // endif !unix_name +#endif // 0 + + if (!(file = fopen(CurProfile->filename, "w"))) { + fprintf(stderr, "could not save profile file %s\n", CurProfile->filename); + return FALSE; + } // endif !file + + if (trace > 1) + htrc("Saving '%s'\n", CurProfile->filename); + + PROFILE_Save(file, CurProfile->section); + fclose(file); + CurProfile->changed = FALSE; + + if (!stat(CurProfile->filename, &buf)) + CurProfile->mtime = buf.st_mtime; + + return TRUE; +} // end of PROFILE_FlushFile + + +/*********************************************************************** + * PROFILE_ReleaseFile + * + * Flush the current profile to disk and remove it from the cache. + ***********************************************************************/ +static void PROFILE_ReleaseFile(void) +{ + PROFILE_FlushFile(); + PROFILE_Free(CurProfile->section); +//memfree(CurProfile->dos_name); +//memfree(CurProfile->unix_name); + memfree(CurProfile->filename); + CurProfile->changed = FALSE; + CurProfile->section = NULL; +//CurProfile->dos_name = NULL; +//CurProfile->unix_name = NULL; + CurProfile->filename = NULL; + CurProfile->mtime = 0; +} // end of PROFILE_ReleaseFile + + +/*********************************************************************** + * PROFILE_Open + * + * Open a profile file, checking the cached file first. + ***********************************************************************/ +static BOOL PROFILE_Open(LPCSTR filename) +{ +//char buffer[MAX_PATHNAME_LEN]; +//char *p; + FILE *file = NULL; + int i, j; + struct stat buf; + PROFILE *tempProfile; + + if (trace > 1) + htrc("PROFILE_Open: CurProfile=%p N=%d\n", CurProfile, N_CACHED_PROFILES); + + /* First time around */ + if (!CurProfile) + for (i = 0; i < N_CACHED_PROFILES; i++) { + MRUProfile[i] = (PROFILE*)malloc(sizeof(PROFILE)); + + if (MRUProfile[i] == NULL) + break; + + MRUProfile[i]->changed=FALSE; + MRUProfile[i]->section=NULL; +// MRUProfile[i]->dos_name=NULL; +// MRUProfile[i]->unix_name=NULL; + MRUProfile[i]->filename=NULL; + MRUProfile[i]->mtime=0; + } // endfor i + + /* Check for a match */ + for (i = 0; i < N_CACHED_PROFILES; i++) { + if (trace > 1) + htrc("MRU=%s i=%d\n", SVP(MRUProfile[i]->filename), i); + + if (MRUProfile[i]->filename && !strcmp(filename, MRUProfile[i]->filename)) { + if (i) { + PROFILE_FlushFile(); + tempProfile = MRUProfile[i]; + + for (j = i; j > 0; j--) + MRUProfile[j] = MRUProfile[j-1]; + + CurProfile=tempProfile; + } // endif i + + if (!stat(CurProfile->filename, &buf) && CurProfile->mtime == buf.st_mtime) { + if (trace > 1) + htrc("(%s): already opened (mru=%d)\n", filename, i); + + } else { + if (trace > 1) + htrc("(%s): already opened, needs refreshing (mru=%d)\n", filename, i); + + } // endif stat + + return TRUE; + } // endif filename + + } // endfor i + + /* Flush the old current profile */ + PROFILE_FlushFile(); + + /* Make the oldest profile the current one only in order to get rid of it */ + if (i == N_CACHED_PROFILES) { + tempProfile = MRUProfile[N_CACHED_PROFILES-1]; + + for(i = N_CACHED_PROFILES-1; i > 0; i--) + MRUProfile[i] = MRUProfile[i-1]; + + CurProfile = tempProfile; + } // endif i + + if (CurProfile->filename) + PROFILE_ReleaseFile(); + + /* OK, now that CurProfile is definitely free we assign it our new file */ +// newdos_name = HeapAlloc( GetProcessHeap(), 0, strlen(full_name.short_name)+1 ); +// strcpy( newdos_name, full_name.short_name ); + +// newdos_name = malloc(strlen(filename)+1); +// strcpy(newdos_name, filename); + +// CurProfile->dos_name = newdos_name; + CurProfile->filename = (char*)malloc(strlen(filename) + 1); + strcpy(CurProfile->filename, filename); + + /* Try to open the profile file, first in $HOME/.wine */ + + /* FIXME: this will need a more general solution */ +// strcpy( buffer, get_config_dir() ); +// p = buffer + strlen(buffer); +// *p++ = '/'; +// strcpy( p, strrchr( newdos_name, '\\' ) + 1 ); +// p = buffer; +// strcpy(p, filename); +// _strlwr(p); + + if (trace > 1) + htrc("Opening %s\n", filename); + + if ((file = fopen(filename, "r"))) { + if (trace > 1) + htrc("(%s): found it\n", filename); + +// CurProfile->unix_name = malloc(strlen(buffer)+1); +// strcpy(CurProfile->unix_name, buffer); + } /* endif file */ + + if (file) { + CurProfile->section = PROFILE_Load(file); + fclose(file); + + if (!stat(CurProfile->filename, &buf)) + CurProfile->mtime = buf.st_mtime; + + } else { + /* Does not exist yet, we will create it in PROFILE_FlushFile */ + fprintf(stderr, "profile file %s not found\n", filename); + } /* endif file */ + + return TRUE; +} + + +/*********************************************************************** + * PROFILE_Close + * + * Flush the named profile to disk and remove it from the cache. + ***********************************************************************/ +void PROFILE_Close(LPCSTR filename) +{ + int i; + BOOL close = FALSE; + struct stat buf; + PROFILE *tempProfile; + + if (trace > 1) + htrc("PROFILE_Close: CurProfile=%p N=%d\n", CurProfile, N_CACHED_PROFILES); + + /* Check for a match */ + for (i = 0; i < N_CACHED_PROFILES; i++) { + if (trace > 1) + htrc("MRU=%s i=%d\n", SVP(MRUProfile[i]->filename), i); + + if (MRUProfile[i]->filename && !strcmp(filename, MRUProfile[i]->filename)) { + if (i) { + /* Make the profile to close current */ + tempProfile = MRUProfile[i]; + MRUProfile[i] = MRUProfile[0]; + MRUProfile[0] = tempProfile; + CurProfile=tempProfile; + } // endif i + + if (trace > 1) { + if (!stat(CurProfile->filename, &buf) && CurProfile->mtime == buf.st_mtime) + htrc("(%s): already opened (mru=%d)\n", filename, i); + else + htrc("(%s): already opened, needs refreshing (mru=%d)\n", filename, i); + + } // endif trace + + close = TRUE; + break; + } // endif filename + + } // endfor i + + if (close) + PROFILE_ReleaseFile(); + +} // end of PROFILE_Close + + +/*********************************************************************** + * PROFILE_End + * + * Terminate and release the cache. + ***********************************************************************/ +void PROFILE_End(void) +{ + int i; + + if (trace) + htrc("PROFILE_End: CurProfile=%p N=%d\n", CurProfile, N_CACHED_PROFILES); + + if (!CurProfile) // Sergey Vojtovich + return; + + /* Close all opened files and free the cache structure */ + for (i = 0; i < N_CACHED_PROFILES; i++) { + if (trace) + htrc("MRU=%s i=%d\n", SVP(MRUProfile[i]->filename), i); + +// CurProfile = MRUProfile[i]; Sergey Vojtovich +// PROFILE_ReleaseFile(); see MDEV-9997 + free(MRUProfile[i]); + } // endfor i + +} // end of PROFILE_End + + +/*********************************************************************** + * PROFILE_DeleteSection + * + * Delete a section from a profile tree. + ***********************************************************************/ +static BOOL PROFILE_DeleteSection(PROFILESECTION* *section, LPCSTR name) +{ + while (*section) { + if ((*section)->name[0] && !stricmp((*section)->name, name)) { + PROFILESECTION *to_del = *section; + + *section = to_del->next; + to_del->next = NULL; + PROFILE_Free(to_del); + return TRUE; + } // endif section + + section = &(*section)->next; + } // endwhile section + + return FALSE; +} // end of PROFILE_DeleteSection + + +/*********************************************************************** + * PROFILE_DeleteKey + * + * Delete a key from a profile tree. + ***********************************************************************/ +static BOOL PROFILE_DeleteKey(PROFILESECTION* *section, + LPCSTR section_name, LPCSTR key_name) +{ + while (*section) { + if ((*section)->name[0] && !stricmp((*section)->name, section_name)) { + PROFILEKEY* *key = &(*section)->key; + + while (*key) { + if (!stricmp((*key)->name, key_name)) { + PROFILEKEY *to_del = *key; + + *key = to_del->next; + memfree(to_del->value); + free(to_del); + return TRUE; + } // endif name + + key = &(*key)->next; + } // endwhile *key + + } // endif section->name + + section = &(*section)->next; + } // endwhile *section + + return FALSE; +} // end of PROFILE_DeleteKey + + +/*********************************************************************** + * PROFILE_DeleteAllKeys + * + * Delete all keys from a profile tree. + ***********************************************************************/ +static void PROFILE_DeleteAllKeys(LPCSTR section_name) +{ + PROFILESECTION* *section= &CurProfile->section; + + while (*section) { + if ((*section)->name[0] && !stricmp((*section)->name, section_name)) { + PROFILEKEY* *key = &(*section)->key; + + while (*key) { + PROFILEKEY *to_del = *key; + + *key = to_del->next; + memfree(to_del->value); + free(to_del); + CurProfile->changed = TRUE; + } // endwhile *key + + } // endif section->name + + section = &(*section)->next; + } // endwhile *section + +} // end of PROFILE_DeleteAllKeys + + +/*********************************************************************** + * PROFILE_Find + * + * Find a key in a profile tree, optionally creating it. + ***********************************************************************/ +static PROFILEKEY *PROFILE_Find(PROFILESECTION* *section, + const char *section_name, + const char *key_name, + BOOL create, BOOL create_always) +{ + const char *p; + int seclen, keylen; + + while (PROFILE_isspace(*section_name)) + section_name++; + + p = section_name + strlen(section_name) - 1; + + while ((p > section_name) && PROFILE_isspace(*p)) + p--; + + seclen = p - section_name + 1; + + while (PROFILE_isspace(*key_name)) + key_name++; + + p = key_name + strlen(key_name) - 1; + + while ((p > key_name) && PROFILE_isspace(*p)) + p--; + + keylen = p - key_name + 1; + + while (*section) { + if (((*section)->name[0]) + && (!(_strnicmp((*section)->name, section_name, seclen ))) + && (((*section)->name)[seclen] == '\0')) { + PROFILEKEY* *key = &(*section)->key; + + while (*key) { + /* If create_always is FALSE then we check if the keyname already exists. + * Otherwise we add it regardless of its existence, to allow + * keys to be added more then once in some cases. + */ + if (!create_always) { + if ((!(_strnicmp( (*key)->name, key_name, keylen ))) + && (((*key)->name)[keylen] == '\0')) + return *key; + + } // endif !create_always + + key = &(*key)->next; + } // endwhile *key + + if (!create) + return NULL; + + if (!(*key = (PROFILEKEY*)malloc(sizeof(PROFILEKEY) + strlen(key_name)))) + return NULL; + + strcpy((*key)->name, key_name); + (*key)->value = NULL; + (*key)->next = NULL; + return *key; + } // endifsection->name + + section = &(*section)->next; + } // endwhile *section + + if (!create) + return NULL; + + *section = (PROFILESECTION*)malloc(sizeof(PROFILESECTION) + strlen(section_name)); + + if (*section == NULL) + return NULL; + + strcpy((*section)->name, section_name); + (*section)->next = NULL; + + if (!((*section)->key = (tagPROFILEKEY*)malloc(sizeof(PROFILEKEY) + strlen(key_name)))) { + free(*section); + return NULL; + } // endif malloc + + strcpy((*section)->key->name, key_name); + (*section)->key->value = NULL; + (*section)->key->next = NULL; + return (*section)->key; +} // end of PROFILE_Find + + +/*********************************************************************** + * PROFILE_GetSection + * + * Returns all keys of a section. + * If return_values is TRUE, also include the corresponding values. + ***********************************************************************/ +static int PROFILE_GetSection(PROFILESECTION *section, LPCSTR section_name, + LPSTR buffer, uint len, + BOOL handle_env, BOOL return_values) +{ + PROFILEKEY *key; + + if(!buffer) + return 0; + + while (section) { + if (section->name[0] && !stricmp(section->name, section_name)) { + uint oldlen = len; + + for (key = section->key; key; key = key->next) { + if (len <= 2) + break; + + if (!*key->name) + continue; /* Skip empty lines */ + + if (IS_ENTRY_COMMENT(key->name)) + continue; /* Skip comments */ + + PROFILE_CopyEntry(buffer, key->name, len - 1, handle_env); + len -= strlen(buffer) + 1; + buffer += strlen(buffer) + 1; + + if (len < 2) + break; + + if (return_values && key->value) { + buffer[-1] = '='; + PROFILE_CopyEntry(buffer, key->value, len - 1, handle_env); + len -= strlen(buffer) + 1; + buffer += strlen(buffer) + 1; + } // endif return_values + + } // endfor key + + *buffer = '\0'; + + if (len <= 1) { + /*If either lpszSection or lpszKey is NULL and the supplied + destination buffer is too small to hold all the strings, + the last string is truncated and followed by two null characters. + In this case, the return value is equal to cchReturnBuffer + minus two. */ + buffer[-1] = '\0'; + return oldlen - 2; + } // endif len + + return oldlen - len; + } // endif section->name + + section = section->next; + } // endwhile section + + buffer[0] = buffer[1] = '\0'; + return 0; +} // end of PROFILE_GetSection + + +/* See GetPrivateProfileSectionNamesA for documentation */ +static int PROFILE_GetSectionNames(LPSTR buffer, uint len) +{ + LPSTR buf; + uint f,l; + PROFILESECTION *section; + + if (trace > 1) + htrc("GetSectionNames: buffer=%p len=%u\n", buffer, len); + + if (!buffer || !len) + return 0; + + if (len == 1) { + *buffer='\0'; + return 0; + } // endif len + + f = len - 1; + buf = buffer; + section = CurProfile->section; + + if (trace > 1) + htrc("GetSectionNames: section=%p\n", section); + + while (section != NULL) { + if (trace > 1) + htrc("section=%s\n", section->name); + + if (section->name[0]) { + l = strlen(section->name) + 1; + + if (trace > 1) + htrc("l=%u f=%u\n", l, f); + + if (l > f) { + if (f > 0) { + strncpy(buf, section->name, f-1); + buf += f-1; + *buf++='\0'; + } // endif f + + *buf = '\0'; + return len - 2; + } // endif l + + strcpy(buf, section->name); + buf += l; + f -= l; + } // endif section->name + + section = section->next; + } // endwhile section + + *buf='\0'; + return buf-buffer; +} // end of PROFILE_GetSectionNames + + +/*********************************************************************** + * PROFILE_GetString + * + * Get a profile string. + * + * Tests with GetPrivateProfileString16, W95a, + * with filled buffer ("****...") and section "set1" and key_name "1" valid: + * section key_name def_val res buffer + * "set1" "1" "x" 43 [data] + * "set1" "1 " "x" 43 [data] (!) + * "set1" " 1 "' "x" 43 [data] (!) + * "set1" "" "x" 1 "x" + * "set1" "" "x " 1 "x" (!) + * "set1" "" " x " 3 " x" (!) + * "set1" NULL "x" 6 "1\02\03\0\0" + * "set1" "" "x" 1 "x" + * NULL "1" "x" 0 "" (!) + * "" "1" "x" 1 "x" + * NULL NULL "" 0 "" + * + *************************************************************************/ +static int PROFILE_GetString(LPCSTR section, LPCSTR key_name, + LPCSTR def_val, LPSTR buffer, uint len) +{ + PROFILEKEY *key = NULL; + + if(!buffer) + return 0; + + if (!def_val) + def_val = ""; + + if (key_name && key_name[0]) { + key = PROFILE_Find(&CurProfile->section, section, key_name, FALSE, FALSE); + PROFILE_CopyEntry(buffer, (key && key->value) ? key->value : def_val, len, FALSE); + + if (trace > 1) + htrc("('%s','%s','%s'): returning '%s'\n", + section, key_name, def_val, buffer ); + + return strlen(buffer); + } // endif key_name + + if (key_name && !(key_name[0])) + /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227 */ + return 0; + + if (section && section[0]) + return PROFILE_GetSection(CurProfile->section, section, buffer, len, + FALSE, FALSE); + buffer[0] = '\0'; + return 0; +} // end of PROFILE_GetString + + +/*********************************************************************** + * PROFILE_SetString + * + * Set a profile string. + ***********************************************************************/ +static BOOL PROFILE_SetString(LPCSTR section_name, LPCSTR key_name, + LPCSTR value, BOOL create_always) +{ + if (!key_name) { /* Delete a whole section */ + if (trace > 1) + htrc("Deleting('%s')\n", section_name); + + CurProfile->changed |= PROFILE_DeleteSection(&CurProfile->section, + section_name); + return TRUE; /* Even if PROFILE_DeleteSection() has failed, + this is not an error on application's level.*/ + } else if (!value) { /* Delete a key */ + if (trace > 1) + htrc("Deleting('%s','%s')\n", section_name, key_name); + + CurProfile->changed |= PROFILE_DeleteKey(&CurProfile->section, + section_name, key_name); + return TRUE; /* same error handling as above */ + } else { /* Set the key value */ + PROFILEKEY *key = PROFILE_Find(&CurProfile->section, section_name, + key_name, TRUE, create_always); + if (trace > 1) + htrc("Setting('%s','%s','%s')\n", section_name, key_name, value); + + if (!key) + return FALSE; + + if (key->value) { + /* strip the leading spaces. We can safely strip \n\r and + * friends too, they should not happen here anyway. */ + while (PROFILE_isspace(*value)) + value++; + + if (!strcmp(key->value, value)) { + if (trace > 1) + htrc(" no change needed\n" ); + + return TRUE; /* No change needed */ + } // endif value + + if (trace > 1) + htrc(" replacing '%s'\n", key->value); + + free(key->value); + } else if (trace > 1) + htrc(" creating key\n" ); + + key->value = (char*)malloc(strlen(value) + 1); + strcpy(key->value, value); + CurProfile->changed = TRUE; + } // endelse + + return TRUE; +} // end of PROFILE_SetString + + +/*********************************************************************** + * PROFILE_GetStringItem + * + * Convenience function that turns a string 'xxx, yyy, zzz' into + * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'. + ***********************************************************************/ +#if 0 +char *PROFILE_GetStringItem(char* start) +{ + char *lpchX, *lpch; + + for (lpchX = start, lpch = NULL; *lpchX != '\0'; lpchX++) { + if (*lpchX == ',') { + if (lpch) + *lpch = '\0'; + else + *lpchX = '\0'; + + while(*(++lpchX)) + if (!PROFILE_isspace(*lpchX)) + return lpchX; + + } else if (PROFILE_isspace(*lpchX) && !lpch) { + lpch = lpchX; + } else + lpch = NULL; + + } // endfor lpchX + + if (lpch) + *lpch = '\0'; + + return NULL; +} // end of PROFILE_GetStringItem +#endif + +/********************************************************************** + * if allow_section_name_copy is TRUE, allow the copying : + * - of Section names if 'section' is NULL + * - of Keys in a Section if 'entry' is NULL + * (see MSDN doc for GetPrivateProfileString) + **********************************************************************/ +static int PROFILE_GetPrivateProfileString(LPCSTR section, LPCSTR entry, + LPCSTR def_val, LPSTR buffer, + uint len, LPCSTR filename, + BOOL allow_section_name_copy) +{ + int ret; + LPSTR pDefVal = NULL; + + if (!filename) + filename = "win.ini"; + + /* strip any trailing ' ' of def_val. */ + if (def_val) { + LPSTR p = (LPSTR)&def_val[strlen(def_val)]; // even "" works ! + + while (p > def_val) + if ((*(--p)) != ' ') + break; + + if (*p == ' ') { /* ouch, contained trailing ' ' */ + int len = p - (LPSTR)def_val; + + pDefVal = (LPSTR)malloc(len + 1); + strncpy(pDefVal, def_val, len); + pDefVal[len] = '\0'; + } // endif *p + + } // endif def_val + + if (!pDefVal) + pDefVal = (LPSTR)def_val; + + EnterCriticalSection(&PROFILE_CritSect); + + if (PROFILE_Open(filename)) { + if ((allow_section_name_copy) && (section == NULL)) + ret = PROFILE_GetSectionNames(buffer, len); + else + /* PROFILE_GetString already handles the 'entry == NULL' case */ + ret = PROFILE_GetString(section, entry, pDefVal, buffer, len); + + } else { + strncpy(buffer, pDefVal, len); + ret = strlen(buffer); + } // endif Open + + LeaveCriticalSection(&PROFILE_CritSect); + + if (pDefVal != def_val) /* allocated */ + memfree(pDefVal); + + return ret; +} // end of PROFILE_GetPrivateProfileString + +/********************** API functions **********************************/ + +/*********************************************************************** + * GetPrivateProfileStringA (KERNEL32.@) + ***********************************************************************/ +int GetPrivateProfileString(LPCSTR section, LPCSTR entry, LPCSTR def_val, + LPSTR buffer, DWORD len, LPCSTR filename) +{ + return PROFILE_GetPrivateProfileString(section, entry, def_val, + buffer, len, filename, TRUE); +} // end of GetPrivateProfileString + + +/*********************************************************************** + * GetPrivateProfileIntA (KERNEL32.@) + ***********************************************************************/ +uint GetPrivateProfileInt(LPCSTR section, LPCSTR entry, + int def_val, LPCSTR filename) +{ + char buffer[20]; + int result; + + if (!PROFILE_GetPrivateProfileString(section, entry, "", buffer, + sizeof(buffer), filename, FALSE)) + return def_val; + + /* FIXME: if entry can be found but it's empty, then Win16 is + * supposed to return 0 instead of def_val ! Difficult/problematic + * to implement (every other failure also returns zero buffer), + * thus wait until testing framework avail for making sure nothing + * else gets broken that way. */ + if (!buffer[0]) + return (uint)def_val; + + /* Don't use strtol() here ! + * (returns LONG_MAX/MIN on overflow instead of "proper" overflow) + YES, scan for unsigned format ! (otherwise compatibility error) */ + if (!sscanf(buffer, "%u", &result)) + return 0; + + return (uint)result; +} // end of GetPrivateProfileInt + + +/*********************************************************************** + * GetPrivateProfileSectionA (KERNEL32.@) + ***********************************************************************/ +int GetPrivateProfileSection(LPCSTR section, LPSTR buffer, + DWORD len, LPCSTR filename) +{ + int ret = 0; + + EnterCriticalSection( &PROFILE_CritSect ); + + if (PROFILE_Open(filename)) + ret = PROFILE_GetSection(CurProfile->section, section, buffer, len, + FALSE, TRUE); + + LeaveCriticalSection( &PROFILE_CritSect ); + return ret; +} // end of GetPrivateProfileSection + + +/*********************************************************************** + * WritePrivateProfileStringA (KERNEL32.@) + ***********************************************************************/ +BOOL WritePrivateProfileString(LPCSTR section, LPCSTR entry, + LPCSTR string, LPCSTR filename) +{ + BOOL ret = FALSE; + + EnterCriticalSection( &PROFILE_CritSect ); + + if (PROFILE_Open(filename)) { + if (!section && !entry && !string) /* documented "file flush" case */ + PROFILE_ReleaseFile(); /* always return FALSE in this case */ + else { + if (!section) { + //FIXME("(NULL?,%s,%s,%s)? \n",entry,string,filename); + } else { + ret = PROFILE_SetString(section, entry, string, FALSE); + + if (ret) + ret = PROFILE_FlushFile(); + + } // endif section + + } // endif section || entry|| string + + } // endif Open + + LeaveCriticalSection( &PROFILE_CritSect ); + return ret; +} // end of WritePrivateProfileString + + +/*********************************************************************** + * WritePrivateProfileSectionA (KERNEL32.@) + ***********************************************************************/ +BOOL WritePrivateProfileSection(LPCSTR section, + LPCSTR string, LPCSTR filename ) +{ + BOOL ret = FALSE; + LPSTR p ; + + EnterCriticalSection(&PROFILE_CritSect); + + if (PROFILE_Open(filename)) { + if (!section && !string) + PROFILE_ReleaseFile(); /* always return FALSE in this case */ + else if (!string) { /* delete the named section*/ + ret = PROFILE_SetString(section, NULL, NULL, FALSE); + + if (ret) + ret = PROFILE_FlushFile(); + } else { + PROFILE_DeleteAllKeys(section); + ret = TRUE; + + while (*string) { + LPSTR buf = (LPSTR)malloc(strlen(string) + 1); + strcpy(buf, string); + + if ((p = strchr(buf, '='))) { + *p='\0'; + ret = PROFILE_SetString(section, buf, p+1, TRUE); + } // endif p + + free(buf); + string += strlen(string) + 1; + + if (ret) + ret = PROFILE_FlushFile(); + + } // endwhile *string + + } // endelse + + } // endif Open + + LeaveCriticalSection(&PROFILE_CritSect); + return ret; +} // end of WritePrivateProfileSection + + +/*********************************************************************** + * GetPrivateProfileSectionNamesA (KERNEL32.@) + * + * Returns the section names contained in the specified file. + * FIXME: Where do we find this file when the path is relative? + * The section names are returned as a list of strings with an extra + * '\0' to mark the end of the list. Except for that the behavior + * depends on the Windows version. + * + * Win95: + * - if the buffer is 0 or 1 character long then it is as if it was of + * infinite length. + * - otherwise, if the buffer is to small only the section names that fit + * are returned. + * - note that this means if the buffer was to small to return even just + * the first section name then a single '\0' will be returned. + * - the return value is the number of characters written in the buffer, + * except if the buffer was too smal in which case len-2 is returned + * + * Win2000: + * - if the buffer is 0, 1 or 2 characters long then it is filled with + * '\0' and the return value is 0 + * - otherwise if the buffer is too small then the first section name that + * does not fit is truncated so that the string list can be terminated + * correctly (double '\0') + * - the return value is the number of characters written in the buffer + * except for the trailing '\0'. If the buffer is too small, then the + * return value is len-2 + * - Win2000 has a bug that triggers when the section names and the + * trailing '\0' fit exactly in the buffer. In that case the trailing + * '\0' is missing. + * + * Wine implements the observed Win2000 behavior (except for the bug). + * + * Note that when the buffer is big enough then the return value may be any + * value between 1 and len-1 (or len in Win95), including len-2. + */ +static DWORD +GetPrivateProfileSectionNames(LPSTR buffer, DWORD size, LPCSTR filename) +{ + DWORD ret = 0; + + if (trace > 1) + htrc("GPPSN: filename=%s\n", filename); + + EnterCriticalSection(&PROFILE_CritSect); + + if (PROFILE_Open(filename)) + ret = PROFILE_GetSectionNames(buffer, size); + + LeaveCriticalSection(&PROFILE_CritSect); + return ret; +} // end of GetPrivateProfileSectionNames + + +/************************************************************************ + * Program to test the above + ************************************************************************/ +#ifdef TEST_MODULE +int main(int argc, char**argv) { + char buff[128]; + char *p, *inifile = "D:\\Plug\\Data\\contact.ini"; + DWORD n; + + n = GetPrivateProfileSectionNames(buff, 128, inifile); + printf("Sections: n=%d\n", n); + + for (p = buff; *p; p += (strlen(p) + 1)) + printf("section=[%s]\n", p); + + GetPrivateProfileString("BER", "name", "?", buff, 128, inifile); + printf("[BER](name) = %s\n", buff); + + WritePrivateProfileString("FOO", "city", NULL, inifile); + GetPrivateProfileString("FOO", "city", "?", buff, 128, inifile); + printf("[FOO](city) = %s\n", buff); + + printf("FOO city: "); + fgets(buff, sizeof(buff), stdin); + if (buff[strlen(buff) - 1] == '\n') + buff[strlen(buff) - 1] = '\0'; + WritePrivateProfileString("FOO", "city", buff, inifile); + GetPrivateProfileString("FOO", "city", "???", buff, 128, inifile); + printf("After write, [FOO](City) = %s\n", buff); + + printf("New city: "); + fgets(buff, sizeof(buff), stdin); + if (buff[strlen(buff) - 1] == '\n') + buff[strlen(buff) - 1] = '\0'; + WritePrivateProfileString("FOO", "city", buff, inifile); + GetPrivateProfileString("FOO", "city", "???", buff, 128, inifile); + printf("After update, [FOO](City) = %s\n", buff); + + printf("FOO name: "); + fgets(buff, sizeof(buff), stdin); + if (buff[strlen(buff) - 1] == '\n') + buff[strlen(buff) - 1] = '\0'; + WritePrivateProfileString("FOO", "name", buff, inifile); + GetPrivateProfileString("FOO", "name", "X", buff, 128, inifile); + printf("[FOO](name) = %s\n", buff); +} // end of main +#endif // TEST_MODULE diff --git a/storage/connect/jsonudf.cpp b/storage/connect/jsonudf.cpp index afb5ae811c7..550b442dd40 100644 --- a/storage/connect/jsonudf.cpp +++ b/storage/connect/jsonudf.cpp @@ -1505,23 +1505,16 @@ static my_bool CheckMemory(PGLOBAL g, UDF_INIT *initid, UDF_ARGS *args, uint n, ml += g->More; if (ml > g->Sarea_Size) { -#if !defined(DEVELOPMENT) - if (trace) -#endif - htrc("Freeing Sarea at %p size=%d\n", g->Sarea, g->Sarea_Size); - - free(g->Sarea); + FreeSarea(g); - if (!(g->Sarea = PlugAllocMem(g, ml))) { + if (AllocSarea(g, ml)) { char errmsg[MAX_STR]; sprintf(errmsg, MSG(WORK_AREA), g->Message); strcpy(g->Message, errmsg); - g->Sarea_Size = 0; return true; - } // endif Alloc + } // endif SareaAlloc - g->Sarea_Size = ml; g->Createas = 0; g->Xchk = NULL; initid->max_length = rl; diff --git a/storage/connect/plgdbutl.cpp b/storage/connect/plgdbutl.cpp index 0a6507315db..f669d644637 100644 --- a/storage/connect/plgdbutl.cpp +++ b/storage/connect/plgdbutl.cpp @@ -334,7 +334,7 @@ PDBUSER PlgMakeUser(PGLOBAL g) { PDBUSER dbuserp; - if (!(dbuserp = (PDBUSER)PlugAllocMem(g, (uint)sizeof(DBUSERBLK)))) { + if (!(dbuserp = (PDBUSER)malloc(sizeof(DBUSERBLK)))) { sprintf(g->Message, MSG(MALLOC_ERROR), "PlgMakeUser"); return NULL; } // endif dbuserp diff --git a/storage/connect/plugutil.cpp b/storage/connect/plugutil.cpp index d63674e2e36..e9ba1682e69 100644 --- a/storage/connect/plugutil.cpp +++ b/storage/connect/plugutil.cpp @@ -138,7 +138,7 @@ PGLOBAL PlugInit(LPCSTR Language, uint worksize) if (trace > 1) htrc("PlugInit: Language='%s'\n", - ((!Language) ? "Null" : (char*)Language)); + ((!Language) ? "Null" : (char*)Language)); try { g = new GLOBAL; @@ -160,13 +160,11 @@ PGLOBAL PlugInit(LPCSTR Language, uint worksize) /*******************************************************************/ /* Allocate the main work segment. */ /*******************************************************************/ - if (worksize && !(g->Sarea = PlugAllocMem(g, worksize))) { + if (worksize && AllocSarea(g, worksize)) { char errmsg[MAX_STR]; sprintf(errmsg, MSG(WORK_AREA), g->Message); strcpy(g->Message, errmsg); - g->Sarea_Size = 0; - } else - g->Sarea_Size = worksize; + } // endif Sarea g->jump_level = -1; /* New setting to allow recursive call of Plug */ return(g); @@ -183,15 +181,7 @@ int PlugExit(PGLOBAL g) if (dup) free(dup); - if (g->Sarea) { -#if !defined(DEVELOPMENT) - if (trace) -#endif - htrc("Freeing Sarea at %p size=%d\n", g->Sarea, g->Sarea_Size); - - free(g->Sarea); - } // endif Sarea - + FreeSarea(g); delete g; } // endif g @@ -459,30 +449,65 @@ short GetLineLength(PGLOBAL g) /***********************************************************************/ /* Program for memory allocation of work and language areas. */ /***********************************************************************/ -void *PlugAllocMem(PGLOBAL g, uint size) +bool AllocSarea(PGLOBAL g, uint size) { - void *areap; /* Pointer to allocated area */ - /*********************************************************************/ /* This is the allocation routine for the WIN32/UNIX/AIX version. */ /*********************************************************************/ - if (!(areap = malloc(size))) - sprintf(g->Message, MSG(MALLOC_ERROR), "malloc"); +#if defined(__WIN__) + if (size >= 1048576) // 1M + g->Sarea = VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + else +#endif + g->Sarea = malloc(size); + + if (!g->Sarea) { + sprintf(g->Message, MSG(MALLOC_ERROR), "malloc"); + g->Sarea_Size = 0; + } else + g->Sarea_Size = size; #if defined(DEVELOPMENT) if (true) { #else if (trace) { #endif - if (areap) - htrc("Memory of %u allocated at %p\n", size, areap); + if (g->Sarea) + htrc("Work area of %u allocated at %p\n", size, g->Sarea); else - htrc("PlugAllocMem: %s\n", g->Message); + htrc("SareaAlloc: %s\n", g->Message); } // endif trace - return (areap); -} // end of PlugAllocMem + return (!g->Sarea); +} // end of AllocSarea + +/***********************************************************************/ +/* Program for memory freeing the work area. */ +/***********************************************************************/ +void FreeSarea(PGLOBAL g) +{ + if (g->Sarea) { +#if defined(__WIN__) + if (g->Sarea_Size >= 1048576) // 1M + VirtualFree(g->Sarea, 0, MEM_RELEASE); + else +#endif + free(g->Sarea); + +#if defined(DEVELOPMENT) + if (true) +#else + if (trace) +#endif + htrc("Freeing Sarea at %p size = %d\n", g->Sarea, g->Sarea_Size); + + g->Sarea = NULL; + g->Sarea_Size = 0; + } // endif Sarea + + return; +} // end of FreeSarea /***********************************************************************/ /* Program for SubSet initialization of memory pools. */ diff --git a/storage/connect/user_connect.cc b/storage/connect/user_connect.cc index 94d2c8ad5fd..cb62667c0fe 100644 --- a/storage/connect/user_connect.cc +++ b/storage/connect/user_connect.cc @@ -156,29 +156,20 @@ void user_connect::SetHandler(ha_connect *hc) bool user_connect::CheckCleanup(bool force) { if (thdp->query_id > last_query_id || force) { - uint worksize= GetWorkSize(); + uint worksize= GetWorkSize(), size = g->Sarea_Size; PlugCleanup(g, true); - if (g->Sarea_Size != worksize) { - if (g->Sarea) { -#if !defined(DEVELOPMENT) - if (trace) -#endif - htrc("CheckCleanup: Free Sarea at %p size=%d\n", - g->Sarea, g->Sarea_Size); - - free(g->Sarea); - } // endif Size + if (size != worksize) { + FreeSarea(g); // Check whether the work area could be allocated - if (!(g->Sarea = PlugAllocMem(g, worksize))) { - g->Sarea = PlugAllocMem(g, g->Sarea_Size); + if (AllocSarea(g, worksize)) { + AllocSarea(g, size); SetWorkSize(g->Sarea_Size); // Was too big - } else - g->Sarea_Size = worksize; // Ok + } // endif sarea - } // endif worksize + } // endif worksize PlugSubSet(g, g->Sarea, g->Sarea_Size); g->Xchk = NULL; -- cgit v1.2.1