mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-31 10:56:12 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			1405 lines
		
	
	
	
		
			40 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1405 lines
		
	
	
	
		
			40 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  * 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 02110-1335 USA
 | |
|  */
 | |
| #include "my_global.h"
 | |
| 
 | |
| #include <ctype.h>
 | |
| //#include <errno.h>
 | |
| #include <fcntl.h>
 | |
| //#include <io.h>  commented this line out to compile for solaris
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| #include <stdio.h>
 | |
| #include <sys/stat.h>
 | |
| //#include <sys/types.h>
 | |
| //#include <memory.h>
 | |
| #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 : "<null>")
 | |
| #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 <stdarg.h>
 | |
|         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");
 | |
| 
 | |
| 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[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(2))
 | |
|           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(2))
 | |
|         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(2))
 | |
|     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(2))
 | |
|     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(2))
 | |
|     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(2))
 | |
|       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(2))
 | |
|           htrc("(%s): already opened (mru=%d)\n", filename, i);
 | |
|           
 | |
|       } else {
 | |
|         if (trace(2))
 | |
|           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(2))
 | |
|     htrc("Opening %s\n", filename);
 | |
|     
 | |
|   if ((file = fopen(filename, "r"))) {
 | |
|     if (trace(2))
 | |
|       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(2))
 | |
|     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(2))
 | |
|       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(2)) {
 | |
|         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(3))
 | |
|     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(3))
 | |
|       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(2))
 | |
|     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(2))
 | |
|     htrc("GetSectionNames: section=%p\n", section);
 | |
| 
 | |
|   while (section != NULL) {
 | |
|     if (trace(2))
 | |
|       htrc("section=%s\n", section->name);
 | |
| 
 | |
|     if (section->name[0]) {
 | |
|       l = strlen(section->name) + 1;
 | |
| 
 | |
|       if (trace(2))
 | |
|         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(2))
 | |
|       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(2))
 | |
|       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(2))
 | |
|       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(2))
 | |
|       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(2))
 | |
|           htrc("  no change needed\n" );
 | |
| 
 | |
|         return TRUE;     /* No change needed */
 | |
|         }  // endif value
 | |
| 
 | |
|       if (trace(2))
 | |
|         htrc("  replacing '%s'\n", key->value);
 | |
| 
 | |
|       free(key->value);
 | |
|     }  else if (trace(2))
 | |
|       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 small 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.
 | |
|  */
 | |
| #ifdef TEST_MODULE
 | |
| static DWORD
 | |
| GetPrivateProfileSectionNames(LPSTR buffer, DWORD size,  LPCSTR filename)
 | |
| {
 | |
|   DWORD ret = 0;
 | |
|   
 | |
|   if (trace(2))
 | |
|     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
 | |
|  ************************************************************************/
 | |
| 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
 | 
