Moved SystemHeap allocations to the process heap.
[wine.git] / files / profile.c
blob5575b91097f8cddcc20a25963cc70f2d4b379031
1 /*
2 * Profile functions
4 * Copyright 1993 Miguel de Icaza
5 * Copyright 1996 Alexandre Julliard
6 */
8 #include <ctype.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <stdio.h>
12 #include <sys/stat.h>
13 #include <sys/types.h>
14 #include <pwd.h>
15 #include <unistd.h>
17 #include "winbase.h"
18 #include "winerror.h"
19 #include "wine/winbase16.h"
20 #include "windef.h"
21 #include "wingdi.h"
22 #include "winuser.h"
23 #include "winnls.h"
24 #include "file.h"
25 #include "heap.h"
26 #include "debugtools.h"
27 #include "xmalloc.h"
28 #include "options.h"
30 DEFAULT_DEBUG_CHANNEL(profile);
32 typedef struct tagPROFILEKEY
34 char *name;
35 char *value;
36 struct tagPROFILEKEY *next;
37 } PROFILEKEY;
39 typedef struct tagPROFILESECTION
41 char *name;
42 struct tagPROFILEKEY *key;
43 struct tagPROFILESECTION *next;
44 } PROFILESECTION;
47 typedef struct
49 BOOL changed;
50 PROFILESECTION *section;
51 char *dos_name;
52 char *unix_name;
53 char *filename;
54 time_t mtime;
55 } PROFILE;
58 #define N_CACHED_PROFILES 10
60 /* Cached profile files */
61 static PROFILE *MRUProfile[N_CACHED_PROFILES]={NULL};
63 #define CurProfile (MRUProfile[0])
65 /* wine.ini profile content */
66 static PROFILESECTION *PROFILE_WineProfile;
68 #define PROFILE_MAX_LINE_LEN 1024
70 /* Wine profile name in $HOME directory; must begin with slash */
71 static const char PROFILE_WineIniName[] = "/.winerc";
73 /* Wine profile: the profile file being used */
74 static char PROFILE_WineIniUsed[MAX_PATHNAME_LEN] = "";
76 /* Check for comments in profile */
77 #define IS_ENTRY_COMMENT(str) ((str)[0] == ';')
79 #define WINE_INI_GLOBAL ETCDIR "/wine.conf"
80 #define WINE_CONFIG_DIR "/.wine" /* config dir inside $HOME */
82 static LPCWSTR wininiW = NULL;
84 static CRITICAL_SECTION PROFILE_CritSect;
86 static const char hex[16] = "0123456789ABCDEF";
88 /***********************************************************************
89 * PROFILE_GetConfigDir
91 * Return the name of the configuration directory ($HOME/.wine)
93 const char *PROFILE_GetConfigDir(void)
95 static char *confdir;
96 if (!confdir)
98 const char *home = getenv( "HOME" );
99 if (!home)
101 struct passwd *pwd = getpwuid( getuid() );
102 if (!pwd)
104 fprintf( stderr, "wine: could not find your home directory\n" );
105 exit(1);
107 home = pwd->pw_dir;
109 confdir = xmalloc( strlen(home) + strlen(WINE_CONFIG_DIR) + 1 );
110 strcpy( confdir, home );
111 strcat( confdir, WINE_CONFIG_DIR );
112 mkdir( confdir, 0755 ); /* create it just in case */
114 return confdir;
118 /***********************************************************************
119 * PROFILE_CopyEntry
121 * Copy the content of an entry into a buffer, removing quotes, and possibly
122 * translating environment variables.
124 static void PROFILE_CopyEntry( char *buffer, const char *value, int len,
125 int handle_env )
127 char quote = '\0';
128 const char *p;
130 if ((*value == '\'') || (*value == '\"'))
132 if (value[1] && (value[strlen(value)-1] == *value)) quote = *value++;
135 if (!handle_env)
137 lstrcpynA( buffer, value, len );
138 if (quote && (len >= strlen(value))) buffer[strlen(buffer)-1] = '\0';
139 return;
142 for (p = value; (*p && (len > 1)); *buffer++ = *p++, len-- )
144 if ((*p == '$') && (p[1] == '{'))
146 char env_val[1024];
147 const char *env_p;
148 const char *p2 = strchr( p, '}' );
149 if (!p2) continue; /* ignore it */
150 lstrcpynA(env_val, p + 2, MIN( sizeof(env_val), (int)(p2-p)-1 ));
151 if ((env_p = getenv( env_val )) != NULL)
153 lstrcpynA( buffer, env_p, len );
154 buffer += strlen( buffer );
155 len -= strlen( buffer );
157 p = p2 + 1;
160 if (quote && (len > 1)) buffer--;
161 *buffer = '\0';
165 /***********************************************************************
166 * PROFILE_Save
168 * Save a profile tree to a file.
170 static void PROFILE_Save( FILE *file, PROFILESECTION *section )
172 PROFILEKEY *key;
174 for ( ; section; section = section->next)
176 if (section->name) fprintf( file, "\r\n[%s]\r\n", section->name );
177 for (key = section->key; key; key = key->next)
179 fprintf( file, "%s", key->name );
180 if (key->value) fprintf( file, "=%s", key->value );
181 fprintf( file, "\r\n" );
187 /***********************************************************************
188 * PROFILE_Free
190 * Free a profile tree.
192 static void PROFILE_Free( PROFILESECTION *section )
194 PROFILESECTION *next_section;
195 PROFILEKEY *key, *next_key;
197 for ( ; section; section = next_section)
199 if (section->name) HeapFree( GetProcessHeap(), 0, section->name );
200 for (key = section->key; key; key = next_key)
202 next_key = key->next;
203 if (key->name) HeapFree( GetProcessHeap(), 0, key->name );
204 if (key->value) HeapFree( GetProcessHeap(), 0, key->value );
205 HeapFree( GetProcessHeap(), 0, key );
207 next_section = section->next;
208 HeapFree( GetProcessHeap(), 0, section );
212 static inline int PROFILE_isspace(char c)
214 if (isspace(c)) return 1;
215 if (c=='\r' || c==0x1a) return 1;
216 /* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */
217 return 0;
221 /***********************************************************************
222 * PROFILE_Load
224 * Load a profile tree from a file.
226 static PROFILESECTION *PROFILE_Load( FILE *file )
228 char buffer[PROFILE_MAX_LINE_LEN];
229 char *p, *p2;
230 int line = 0;
231 PROFILESECTION *section, *first_section;
232 PROFILESECTION **next_section;
233 PROFILEKEY *key, *prev_key, **next_key;
235 first_section = HEAP_xalloc( GetProcessHeap(), 0, sizeof(*section) );
236 first_section->name = NULL;
237 first_section->key = NULL;
238 first_section->next = NULL;
239 next_section = &first_section->next;
240 next_key = &first_section->key;
241 prev_key = NULL;
243 while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
245 line++;
246 p = buffer;
247 while (*p && PROFILE_isspace(*p)) p++;
248 if (*p == '[') /* section start */
250 if (!(p2 = strrchr( p, ']' )))
252 WARN("Invalid section header at line %d: '%s'\n",
253 line, p );
255 else
257 *p2 = '\0';
258 p++;
259 section = HEAP_xalloc( GetProcessHeap(), 0, sizeof(*section) );
260 section->name = HEAP_strdupA( GetProcessHeap(), 0, p );
261 section->key = NULL;
262 section->next = NULL;
263 *next_section = section;
264 next_section = &section->next;
265 next_key = &section->key;
266 prev_key = NULL;
268 TRACE("New section: '%s'\n",section->name);
270 continue;
274 p2=p+strlen(p) - 1;
275 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
277 if ((p2 = strchr( p, '=' )) != NULL)
279 char *p3 = p2 - 1;
280 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
281 *p2++ = '\0';
282 while (*p2 && PROFILE_isspace(*p2)) p2++;
285 if(*p || !prev_key || *prev_key->name)
287 key = HEAP_xalloc( GetProcessHeap(), 0, sizeof(*key) );
288 key->name = HEAP_strdupA( GetProcessHeap(), 0, p );
289 key->value = p2 ? HEAP_strdupA( GetProcessHeap(), 0, p2 ) : NULL;
290 key->next = NULL;
291 *next_key = key;
292 next_key = &key->next;
293 prev_key = key;
295 TRACE("New key: name='%s', value='%s'\n",key->name,key->value?key->value:"(none)");
298 return first_section;
302 /***********************************************************************
303 * PROFILE_DeleteSection
305 * Delete a section from a profile tree.
307 static BOOL PROFILE_DeleteSection( PROFILESECTION **section, LPCSTR name )
309 while (*section)
311 if ((*section)->name && !strcasecmp( (*section)->name, name ))
313 PROFILESECTION *to_del = *section;
314 *section = to_del->next;
315 to_del->next = NULL;
316 PROFILE_Free( to_del );
317 return TRUE;
319 section = &(*section)->next;
321 return FALSE;
325 /***********************************************************************
326 * PROFILE_DeleteKey
328 * Delete a key from a profile tree.
330 static BOOL PROFILE_DeleteKey( PROFILESECTION **section,
331 LPCSTR section_name, LPCSTR key_name )
333 while (*section)
335 if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
337 PROFILEKEY **key = &(*section)->key;
338 while (*key)
340 if (!strcasecmp( (*key)->name, key_name ))
342 PROFILEKEY *to_del = *key;
343 *key = to_del->next;
344 if (to_del->name) HeapFree( GetProcessHeap(), 0, to_del->name );
345 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
346 HeapFree( GetProcessHeap(), 0, to_del );
347 return TRUE;
349 key = &(*key)->next;
352 section = &(*section)->next;
354 return FALSE;
358 /***********************************************************************
359 * PROFILE_Find
361 * Find a key in a profile tree, optionally creating it.
363 static PROFILEKEY *PROFILE_Find( PROFILESECTION **section,
364 const char *section_name,
365 const char *key_name, int create )
367 const char *p;
368 int seclen, keylen;
370 while (PROFILE_isspace(*section_name)) section_name++;
371 p = section_name + strlen(section_name) - 1;
372 while ((p > section_name) && PROFILE_isspace(*p)) p--;
373 seclen = p - section_name + 1;
375 while (PROFILE_isspace(*key_name)) key_name++;
376 p = key_name + strlen(key_name) - 1;
377 while ((p > key_name) && PROFILE_isspace(*p)) p--;
378 keylen = p - key_name + 1;
380 while (*section)
382 if ( ((*section)->name)
383 && (!(strncasecmp( (*section)->name, section_name, seclen )))
384 && (((*section)->name)[seclen] == '\0') )
386 PROFILEKEY **key = &(*section)->key;
387 while (*key)
389 if ( (!(strncasecmp( (*key)->name, key_name, keylen )))
390 && (((*key)->name)[keylen] == '\0') )
391 return *key;
392 key = &(*key)->next;
394 if (!create) return NULL;
395 *key = HEAP_xalloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) );
396 (*key)->name = HEAP_strdupA( GetProcessHeap(), 0, key_name );
397 (*key)->value = NULL;
398 (*key)->next = NULL;
399 return *key;
401 section = &(*section)->next;
403 if (!create) return NULL;
404 *section = HEAP_xalloc( GetProcessHeap(), 0, sizeof(PROFILESECTION) );
405 (*section)->name = HEAP_strdupA( GetProcessHeap(), 0, section_name );
406 (*section)->next = NULL;
407 (*section)->key = HEAP_xalloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) );
408 (*section)->key->name = HEAP_strdupA( GetProcessHeap(), 0, key_name );
409 (*section)->key->value = NULL;
410 (*section)->key->next = NULL;
411 return (*section)->key;
415 /***********************************************************************
416 * PROFILE_FlushFile
418 * Flush the current profile to disk if changed.
420 static BOOL PROFILE_FlushFile(void)
422 char *p, buffer[MAX_PATHNAME_LEN];
423 const char *unix_name;
424 FILE *file = NULL;
425 struct stat buf;
427 if(!CurProfile)
429 WARN("No current profile!\n");
430 return FALSE;
433 if (!CurProfile->changed || !CurProfile->dos_name) return TRUE;
434 if (!(unix_name = CurProfile->unix_name) || !(file = fopen(unix_name, "w")))
436 /* Try to create it in $HOME/.wine */
437 /* FIXME: this will need a more general solution */
438 strcpy( buffer, PROFILE_GetConfigDir() );
439 p = buffer + strlen(buffer);
440 *p++ = '/';
441 strcpy( p, strrchr( CurProfile->dos_name, '\\' ) + 1 );
442 CharLowerA( p );
443 file = fopen( buffer, "w" );
444 unix_name = buffer;
447 if (!file)
449 WARN("could not save profile file %s\n", CurProfile->dos_name);
450 return FALSE;
453 TRACE("Saving '%s' into '%s'\n", CurProfile->dos_name, unix_name );
454 PROFILE_Save( file, CurProfile->section );
455 fclose( file );
456 CurProfile->changed = FALSE;
457 if(!stat(unix_name,&buf))
458 CurProfile->mtime=buf.st_mtime;
459 return TRUE;
463 /***********************************************************************
464 * PROFILE_ReleaseFile
466 * Flush the current profile to disk and remove it from the cache.
468 static void PROFILE_ReleaseFile(void)
470 PROFILE_FlushFile();
471 PROFILE_Free( CurProfile->section );
472 if (CurProfile->dos_name) HeapFree( GetProcessHeap(), 0, CurProfile->dos_name );
473 if (CurProfile->unix_name) HeapFree( GetProcessHeap(), 0, CurProfile->unix_name );
474 if (CurProfile->filename) HeapFree( GetProcessHeap(), 0, CurProfile->filename );
475 CurProfile->changed = FALSE;
476 CurProfile->section = NULL;
477 CurProfile->dos_name = NULL;
478 CurProfile->unix_name = NULL;
479 CurProfile->filename = NULL;
480 CurProfile->mtime = 0;
484 /***********************************************************************
485 * PROFILE_Open
487 * Open a profile file, checking the cached file first.
489 static BOOL PROFILE_Open( LPCSTR filename )
491 DOS_FULL_NAME full_name;
492 char buffer[MAX_PATHNAME_LEN];
493 char *newdos_name, *p;
494 FILE *file = NULL;
495 int i,j;
496 struct stat buf;
497 PROFILE *tempProfile;
499 /* First time around */
501 if(!CurProfile)
502 for(i=0;i<N_CACHED_PROFILES;i++)
504 MRUProfile[i]=HEAP_xalloc( GetProcessHeap(), 0, sizeof(PROFILE) );
505 MRUProfile[i]->changed=FALSE;
506 MRUProfile[i]->section=NULL;
507 MRUProfile[i]->dos_name=NULL;
508 MRUProfile[i]->unix_name=NULL;
509 MRUProfile[i]->filename=NULL;
510 MRUProfile[i]->mtime=0;
513 /* Check for a match */
515 if (strchr( filename, '/' ) || strchr( filename, '\\' ) ||
516 strchr( filename, ':' ))
518 if (!DOSFS_GetFullName( filename, FALSE, &full_name )) return FALSE;
520 else
522 GetWindowsDirectoryA( buffer, sizeof(buffer) );
523 strcat( buffer, "\\" );
524 strcat( buffer, filename );
525 if (!DOSFS_GetFullName( buffer, FALSE, &full_name )) return FALSE;
528 for(i=0;i<N_CACHED_PROFILES;i++)
530 if ((MRUProfile[i]->filename && !strcmp( filename, MRUProfile[i]->filename )) ||
531 (MRUProfile[i]->dos_name && !strcmp( full_name.short_name, MRUProfile[i]->dos_name )))
533 if(i)
535 PROFILE_FlushFile();
536 tempProfile=MRUProfile[i];
537 for(j=i;j>0;j--)
538 MRUProfile[j]=MRUProfile[j-1];
539 CurProfile=tempProfile;
541 if(!stat(CurProfile->unix_name,&buf) && CurProfile->mtime==buf.st_mtime)
542 TRACE("(%s): already opened (mru=%d)\n",
543 filename, i );
544 else
545 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
546 filename, i );
547 return TRUE;
551 /* Flush the old current profile */
552 PROFILE_FlushFile();
554 /* Make the oldest profile the current one only in order to get rid of it */
555 if(i==N_CACHED_PROFILES)
557 tempProfile=MRUProfile[N_CACHED_PROFILES-1];
558 for(i=N_CACHED_PROFILES-1;i>0;i--)
559 MRUProfile[i]=MRUProfile[i-1];
560 CurProfile=tempProfile;
562 if(CurProfile->filename) PROFILE_ReleaseFile();
564 /* OK, now that CurProfile is definitely free we assign it our new file */
565 newdos_name = HEAP_strdupA( GetProcessHeap(), 0, full_name.short_name );
566 CurProfile->dos_name = newdos_name;
567 CurProfile->filename = HEAP_strdupA( GetProcessHeap(), 0, filename );
569 /* Try to open the profile file, first in $HOME/.wine */
571 /* FIXME: this will need a more general solution */
572 strcpy( buffer, PROFILE_GetConfigDir() );
573 p = buffer + strlen(buffer);
574 *p++ = '/';
575 strcpy( p, strrchr( newdos_name, '\\' ) + 1 );
576 CharLowerA( p );
577 if ((file = fopen( buffer, "r" )))
579 TRACE("(%s): found it in %s\n",
580 filename, buffer );
581 CurProfile->unix_name = HEAP_strdupA( GetProcessHeap(), 0, buffer );
584 if (!file)
586 CurProfile->unix_name = HEAP_strdupA( GetProcessHeap(), 0,
587 full_name.long_name );
588 if ((file = fopen( full_name.long_name, "r" )))
589 TRACE("(%s): found it in %s\n",
590 filename, full_name.long_name );
593 if (file)
595 CurProfile->section = PROFILE_Load( file );
596 fclose( file );
597 if(!stat(CurProfile->unix_name,&buf))
598 CurProfile->mtime=buf.st_mtime;
600 else
602 /* Does not exist yet, we will create it in PROFILE_FlushFile */
603 WARN("profile file %s not found\n", newdos_name );
605 return TRUE;
609 /***********************************************************************
610 * PROFILE_GetSection
612 * Returns all keys of a section.
613 * If return_values is TRUE, also include the corresponding values.
615 static INT PROFILE_GetSection( PROFILESECTION *section, LPCSTR section_name,
616 LPSTR buffer, UINT len, BOOL handle_env,
617 BOOL return_values )
619 PROFILEKEY *key;
620 while (section)
622 if (section->name && !strcasecmp( section->name, section_name ))
624 UINT oldlen = len;
625 for (key = section->key; key; key = key->next)
627 if (len <= 2) break;
628 if (!*key->name) continue; /* Skip empty lines */
629 if (IS_ENTRY_COMMENT(key->name)) continue; /* Skip comments */
630 PROFILE_CopyEntry( buffer, key->name, len - 1, handle_env );
631 len -= strlen(buffer) + 1;
632 buffer += strlen(buffer) + 1;
633 if (return_values && key->value) {
634 buffer[-1] = '=';
635 PROFILE_CopyEntry ( buffer,
636 key->value, len - 1, handle_env );
637 len -= strlen(buffer) + 1;
638 buffer += strlen(buffer) + 1;
641 *buffer = '\0';
642 if (len <= 1)
643 /*If either lpszSection or lpszKey is NULL and the supplied
644 destination buffer is too small to hold all the strings,
645 the last string is truncated and followed by two null characters.
646 In this case, the return value is equal to cchReturnBuffer
647 minus two. */
649 buffer[-1] = '\0';
650 return oldlen - 2;
652 return oldlen - len;
654 section = section->next;
656 buffer[0] = buffer[1] = '\0';
657 return 0;
661 static INT PROFILE_GetSectionNames( LPSTR buffer, UINT len )
663 LPSTR buf = buffer;
664 WORD l, cursize = 0;
665 PROFILESECTION *section;
667 for (section = CurProfile->section; section; section = section->next)
668 if (section->name) {
669 l = strlen(section->name);
670 cursize += l+1;
671 if (cursize > len+1)
672 return len-2;
674 strcpy(buf, section->name);
675 buf += l+1;
678 *buf=0;
679 buf++;
680 return buf-buffer;
684 /***********************************************************************
685 * PROFILE_GetString
687 * Get a profile string.
689 static INT PROFILE_GetString( LPCSTR section, LPCSTR key_name,
690 LPCSTR def_val, LPSTR buffer, UINT len )
692 PROFILEKEY *key = NULL;
694 if (!def_val) def_val = "";
695 if (key_name && key_name[0])
697 key = PROFILE_Find( &CurProfile->section, section, key_name, FALSE );
698 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def_val,
699 len, FALSE );
700 TRACE("('%s','%s','%s'): returning '%s'\n",
701 section, key_name, def_val, buffer );
702 return strlen( buffer );
704 if (section && section[0])
705 return PROFILE_GetSection(CurProfile->section, section, buffer, len,
706 FALSE, FALSE);
707 /* undocumented; both section and key_name are NULL */
708 return PROFILE_GetSectionNames(buffer, len);
712 /***********************************************************************
713 * PROFILE_SetString
715 * Set a profile string.
717 static BOOL PROFILE_SetString( LPCSTR section_name, LPCSTR key_name,
718 LPCSTR value )
720 if (!key_name) /* Delete a whole section */
722 TRACE("('%s')\n", section_name);
723 CurProfile->changed |= PROFILE_DeleteSection( &CurProfile->section,
724 section_name );
725 return TRUE; /* Even if PROFILE_DeleteSection() has failed,
726 this is not an error on application's level.*/
728 else if (!value) /* Delete a key */
730 TRACE("('%s','%s')\n",
731 section_name, key_name );
732 CurProfile->changed |= PROFILE_DeleteKey( &CurProfile->section,
733 section_name, key_name );
734 return TRUE; /* same error handling as above */
736 else /* Set the key value */
738 PROFILEKEY *key = PROFILE_Find( &CurProfile->section, section_name,
739 key_name, TRUE );
740 TRACE("('%s','%s','%s'): \n",
741 section_name, key_name, value );
742 if (!key) return FALSE;
743 if (key->value)
745 if (!strcmp( key->value, value ))
747 TRACE(" no change needed\n" );
748 return TRUE; /* No change needed */
750 TRACE(" replacing '%s'\n", key->value );
751 HeapFree( GetProcessHeap(), 0, key->value );
753 else TRACE(" creating key\n" );
754 key->value = HEAP_strdupA( GetProcessHeap(), 0, value );
755 CurProfile->changed = TRUE;
757 return TRUE;
761 /***********************************************************************
762 * PROFILE_GetWineIniString
764 * Get a config string from the wine.ini file.
766 int PROFILE_GetWineIniString( const char *section, const char *key_name,
767 const char *def, char *buffer, int len )
769 int ret;
771 EnterCriticalSection( &PROFILE_CritSect );
773 if (key_name)
775 PROFILEKEY *key = PROFILE_Find(&PROFILE_WineProfile, section, key_name, FALSE);
776 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def,
777 len, TRUE );
778 TRACE("('%s','%s','%s'): returning '%s'\n",
779 section, key_name, def, buffer );
780 ret = strlen( buffer );
782 else
784 ret = PROFILE_GetSection( PROFILE_WineProfile, section, buffer, len, TRUE, FALSE );
786 LeaveCriticalSection( &PROFILE_CritSect );
788 return ret;
792 /***********************************************************************
793 * PROFILE_GetWineIniInt
795 * Get a config integer from the wine.ini file.
797 int PROFILE_GetWineIniInt( const char *section, const char *key_name, int def )
799 char buffer[20];
800 char *p;
801 long result;
802 PROFILEKEY *key;
803 int ret;
805 EnterCriticalSection( &PROFILE_CritSect );
807 key = PROFILE_Find( &PROFILE_WineProfile, section, key_name, FALSE );
808 if (!key || !key->value) {
809 ret = def;
810 } else {
811 PROFILE_CopyEntry( buffer, key->value, sizeof(buffer), TRUE );
812 result = strtol( buffer, &p, 0 );
813 ret = (p == buffer) ? 0 /* No digits at all */ : (int)result;
816 LeaveCriticalSection( &PROFILE_CritSect );
818 return ret;
822 /******************************************************************************
824 * int PROFILE_EnumerateWineIniSection(
825 * char const *section, #Name of the section to enumerate
826 * void (*cbfn)(char const *key, char const *value, void *user),
827 * # Address of the callback function
828 * void *user ) # User-specified pointer.
830 * For each entry in a section in the wine.conf file, this function will
831 * call the specified callback function, informing it of each key and
832 * value. An optional user pointer may be passed to it (if this is not
833 * needed, pass NULL through it and ignore the value in the callback
834 * function).
836 * The callback function must accept three parameters:
837 * The name of the key (char const *)
838 * The value of the key (char const *)
839 * A user-specified parameter (void *)
840 * Note that the first two are char CONST *'s, not char *'s! The callback
841 * MUST not modify these strings!
843 * The return value indicates the number of times the callback function
844 * was called.
846 int PROFILE_EnumerateWineIniSection(
847 char const *section,
848 void (*cbfn)(char const *, char const *, void *),
849 void *userptr )
851 PROFILESECTION *scansect;
852 PROFILEKEY *scankey;
853 int calls = 0;
855 EnterCriticalSection( &PROFILE_CritSect );
857 /* Search for the correct section */
858 for(scansect = PROFILE_WineProfile; scansect; scansect = scansect->next) {
859 if(scansect->name && !strcasecmp(scansect->name, section)) {
861 /* Enumerate each key with the callback */
862 for(scankey = scansect->key; scankey; scankey = scankey->next) {
864 /* Ignore blank entries -- these shouldn't exist, but let's
865 be extra careful */
866 if (!scankey->name[0]) continue;
867 if (!scankey->value) cbfn(scankey->name, NULL, userptr);
868 else
870 char value[1024];
871 PROFILE_CopyEntry(value, scankey->value, sizeof(value), TRUE);
872 cbfn(scankey->name, value, userptr);
874 ++calls;
877 break;
880 LeaveCriticalSection( &PROFILE_CritSect );
882 return calls;
886 /******************************************************************************
888 * int PROFILE_GetWineIniBool(
889 * char const *section,
890 * char const *key_name,
891 * int def )
893 * Reads a boolean value from the wine.ini file. This function attempts to
894 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
895 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
896 * true. Anything else results in the return of the default value.
898 * This function uses 1 to indicate true, and 0 for false. You can check
899 * for existence by setting def to something other than 0 or 1 and
900 * examining the return value.
902 int PROFILE_GetWineIniBool(
903 char const *section,
904 char const *key_name,
905 int def )
907 char key_value[2];
908 int retval;
910 PROFILE_GetWineIniString(section, key_name, "~", key_value, 2);
912 switch(key_value[0]) {
913 case 'n':
914 case 'N':
915 case 'f':
916 case 'F':
917 case '0':
918 retval = 0;
919 break;
921 case 'y':
922 case 'Y':
923 case 't':
924 case 'T':
925 case '1':
926 retval = 1;
927 break;
929 default:
930 retval = def;
933 TRACE("(\"%s\", \"%s\", %s), "
934 "[%c], ret %s.\n", section, key_name,
935 def ? "TRUE" : "FALSE", key_value[0],
936 retval ? "TRUE" : "FALSE");
938 return retval;
942 /***********************************************************************
943 * PROFILE_LoadWineIni
945 * Load the wine.ini file.
947 int PROFILE_LoadWineIni(void)
949 char buffer[MAX_PATHNAME_LEN];
950 const char *p;
951 FILE *f;
953 InitializeCriticalSection( &PROFILE_CritSect );
954 MakeCriticalSectionGlobal( &PROFILE_CritSect );
956 if ( (Options.configFileName!=NULL) && (f = fopen(Options.configFileName, "r")) )
958 /* Open -config specified file */
959 PROFILE_WineProfile = PROFILE_Load ( f);
960 fclose ( f );
961 lstrcpynA(PROFILE_WineIniUsed,Options.configFileName,MAX_PATHNAME_LEN);
962 return 1;
965 if ( (p = getenv( "WINE_INI" )) && (f = fopen( p, "r" )) )
967 PROFILE_WineProfile = PROFILE_Load( f );
968 fclose( f );
969 lstrcpynA(PROFILE_WineIniUsed,p,MAX_PATHNAME_LEN);
970 return 1;
972 if ((p = getenv( "HOME" )) != NULL)
974 lstrcpynA(buffer, p, MAX_PATHNAME_LEN - sizeof(PROFILE_WineIniName));
975 strcat( buffer, PROFILE_WineIniName );
976 if ((f = fopen( buffer, "r" )) != NULL)
978 PROFILE_WineProfile = PROFILE_Load( f );
979 fclose( f );
980 lstrcpynA(PROFILE_WineIniUsed,buffer,MAX_PATHNAME_LEN);
981 return 1;
984 else WARN("could not get $HOME value for config file.\n" );
986 /* Try global file */
988 if ((f = fopen( WINE_INI_GLOBAL, "r" )) != NULL)
990 PROFILE_WineProfile = PROFILE_Load( f );
991 fclose( f );
992 lstrcpynA(PROFILE_WineIniUsed,WINE_INI_GLOBAL,MAX_PATHNAME_LEN);
993 return 1;
995 MESSAGE( "Can't open configuration file %s or $HOME%s\n",
996 WINE_INI_GLOBAL, PROFILE_WineIniName );
997 return 0;
1001 /***********************************************************************
1002 * PROFILE_UsageWineIni
1004 * Explain the wine.ini file to those who don't read documentation.
1005 * Keep below one screenful in length so that error messages above are
1006 * noticed.
1008 void PROFILE_UsageWineIni(void)
1010 MESSAGE("Perhaps you have not properly edited or created "
1011 "your Wine configuration file.\n");
1012 MESSAGE("This is either %s or $HOME%s\n",WINE_INI_GLOBAL,PROFILE_WineIniName);
1013 MESSAGE(" or it is determined by the -config option or from\n"
1014 " the WINE_INI environment variable.\n");
1015 if (*PROFILE_WineIniUsed)
1016 MESSAGE("Wine has used %s as configuration file.\n", PROFILE_WineIniUsed);
1017 /* RTFM, so to say */
1020 /***********************************************************************
1021 * PROFILE_GetStringItem
1023 * Convenience function that turns a string 'xxx, yyy, zzz' into
1024 * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
1026 char* PROFILE_GetStringItem( char* start )
1028 char* lpchX, *lpch;
1030 for (lpchX = start, lpch = NULL; *lpchX != '\0'; lpchX++ )
1032 if( *lpchX == ',' )
1034 if( lpch ) *lpch = '\0'; else *lpchX = '\0';
1035 while( *(++lpchX) )
1036 if( !PROFILE_isspace(*lpchX) ) return lpchX;
1038 else if( PROFILE_isspace( *lpchX ) && !lpch ) lpch = lpchX;
1039 else lpch = NULL;
1041 if( lpch ) *lpch = '\0';
1042 return NULL;
1045 /********************* API functions **********************************/
1047 /***********************************************************************
1048 * GetProfileInt16 (KERNEL.57)
1050 UINT16 WINAPI GetProfileInt16( LPCSTR section, LPCSTR entry, INT16 def_val )
1052 return GetPrivateProfileInt16( section, entry, def_val, "win.ini" );
1056 /***********************************************************************
1057 * GetProfileInt32A (KERNEL32.264)
1059 UINT WINAPI GetProfileIntA( LPCSTR section, LPCSTR entry, INT def_val )
1061 return GetPrivateProfileIntA( section, entry, def_val, "win.ini" );
1064 /***********************************************************************
1065 * GetProfileInt32W (KERNEL32.264)
1067 UINT WINAPI GetProfileIntW( LPCWSTR section, LPCWSTR entry, INT def_val )
1069 if (!wininiW) wininiW = HEAP_strdupAtoW( GetProcessHeap(), 0, "win.ini" );
1070 return GetPrivateProfileIntW( section, entry, def_val, wininiW );
1073 /***********************************************************************
1074 * GetProfileString16 (KERNEL.58)
1076 INT16 WINAPI GetProfileString16( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1077 LPSTR buffer, UINT16 len )
1079 return GetPrivateProfileString16( section, entry, def_val,
1080 buffer, len, "win.ini" );
1083 /***********************************************************************
1084 * GetProfileString32A (KERNEL32.268)
1086 INT WINAPI GetProfileStringA( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1087 LPSTR buffer, UINT len )
1089 return GetPrivateProfileStringA( section, entry, def_val,
1090 buffer, len, "win.ini" );
1093 /***********************************************************************
1094 * GetProfileString32W (KERNEL32.269)
1096 INT WINAPI GetProfileStringW( LPCWSTR section, LPCWSTR entry,
1097 LPCWSTR def_val, LPWSTR buffer, UINT len )
1099 if (!wininiW) wininiW = HEAP_strdupAtoW( GetProcessHeap(), 0, "win.ini" );
1100 return GetPrivateProfileStringW( section, entry, def_val,
1101 buffer, len, wininiW );
1104 /***********************************************************************
1105 * WriteProfileString16 (KERNEL.59)
1107 BOOL16 WINAPI WriteProfileString16( LPCSTR section, LPCSTR entry,
1108 LPCSTR string )
1110 return WritePrivateProfileString16( section, entry, string, "win.ini" );
1113 /***********************************************************************
1114 * WriteProfileString32A (KERNEL32.587)
1116 BOOL WINAPI WriteProfileStringA( LPCSTR section, LPCSTR entry,
1117 LPCSTR string )
1119 return WritePrivateProfileStringA( section, entry, string, "win.ini" );
1122 /***********************************************************************
1123 * WriteProfileString32W (KERNEL32.588)
1125 BOOL WINAPI WriteProfileStringW( LPCWSTR section, LPCWSTR entry,
1126 LPCWSTR string )
1128 if (!wininiW) wininiW = HEAP_strdupAtoW( GetProcessHeap(), 0, "win.ini" );
1129 return WritePrivateProfileStringW( section, entry, string, wininiW );
1133 /***********************************************************************
1134 * GetPrivateProfileInt16 (KERNEL.127)
1136 UINT16 WINAPI GetPrivateProfileInt16( LPCSTR section, LPCSTR entry,
1137 INT16 def_val, LPCSTR filename )
1139 long result=(long)GetPrivateProfileIntA(section,entry,def_val,filename);
1141 if (result > 65535) return 65535;
1142 if (result >= 0) return (UINT16)result;
1143 if (result < -32768) return -32768;
1144 return (UINT16)(INT16)result;
1147 /***********************************************************************
1148 * GetPrivateProfileInt32A (KERNEL32.251)
1150 UINT WINAPI GetPrivateProfileIntA( LPCSTR section, LPCSTR entry,
1151 INT def_val, LPCSTR filename )
1153 char buffer[20];
1154 char *p;
1155 long result;
1157 GetPrivateProfileStringA( section, entry, "",
1158 buffer, sizeof(buffer), filename );
1159 if (!buffer[0]) return (UINT)def_val;
1160 result = strtol( buffer, &p, 0 );
1161 if (p == buffer) return 0; /* No digits at all */
1162 return (UINT)result;
1165 /***********************************************************************
1166 * GetPrivateProfileInt32W (KERNEL32.252)
1168 UINT WINAPI GetPrivateProfileIntW( LPCWSTR section, LPCWSTR entry,
1169 INT def_val, LPCWSTR filename )
1171 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1172 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1173 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1174 UINT res = GetPrivateProfileIntA(sectionA, entryA, def_val, filenameA);
1175 HeapFree( GetProcessHeap(), 0, sectionA );
1176 HeapFree( GetProcessHeap(), 0, filenameA );
1177 HeapFree( GetProcessHeap(), 0, entryA );
1178 return res;
1181 /***********************************************************************
1182 * GetPrivateProfileString16 (KERNEL.128)
1184 INT16 WINAPI GetPrivateProfileString16( LPCSTR section, LPCSTR entry,
1185 LPCSTR def_val, LPSTR buffer,
1186 UINT16 len, LPCSTR filename )
1188 return GetPrivateProfileStringA(section,entry,def_val,buffer,len,filename);
1191 /***********************************************************************
1192 * GetPrivateProfileString32A (KERNEL32.255)
1194 INT WINAPI GetPrivateProfileStringA( LPCSTR section, LPCSTR entry,
1195 LPCSTR def_val, LPSTR buffer,
1196 UINT len, LPCSTR filename )
1198 int ret;
1200 if (!filename)
1201 filename = "win.ini";
1203 EnterCriticalSection( &PROFILE_CritSect );
1205 if (PROFILE_Open( filename )) {
1206 ret = PROFILE_GetString( section, entry, def_val, buffer, len );
1207 } else {
1208 lstrcpynA( buffer, def_val, len );
1209 ret = strlen( buffer );
1212 LeaveCriticalSection( &PROFILE_CritSect );
1214 return ret;
1217 /***********************************************************************
1218 * GetPrivateProfileString32W (KERNEL32.256)
1220 INT WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1221 LPCWSTR def_val, LPWSTR buffer,
1222 UINT len, LPCWSTR filename )
1224 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1225 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1226 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1227 LPSTR def_valA = HEAP_strdupWtoA( GetProcessHeap(), 0, def_val );
1228 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1229 INT ret = GetPrivateProfileStringA( sectionA, entryA, def_valA,
1230 bufferA, len, filenameA );
1231 lstrcpynAtoW( buffer, bufferA, len );
1232 HeapFree( GetProcessHeap(), 0, sectionA );
1233 HeapFree( GetProcessHeap(), 0, entryA );
1234 HeapFree( GetProcessHeap(), 0, filenameA );
1235 HeapFree( GetProcessHeap(), 0, def_valA );
1236 HeapFree( GetProcessHeap(), 0, bufferA);
1237 return ret;
1240 /***********************************************************************
1241 * GetPrivateProfileSection16 (KERNEL.418)
1243 INT16 WINAPI GetPrivateProfileSection16( LPCSTR section, LPSTR buffer,
1244 UINT16 len, LPCSTR filename )
1246 return GetPrivateProfileSectionA( section, buffer, len, filename );
1249 /***********************************************************************
1250 * GetPrivateProfileSection32A (KERNEL32.255)
1252 INT WINAPI GetPrivateProfileSectionA( LPCSTR section, LPSTR buffer,
1253 DWORD len, LPCSTR filename )
1255 int ret = 0;
1257 EnterCriticalSection( &PROFILE_CritSect );
1259 if (PROFILE_Open( filename ))
1260 ret = PROFILE_GetSection(CurProfile->section, section, buffer, len,
1261 FALSE, TRUE);
1263 LeaveCriticalSection( &PROFILE_CritSect );
1265 return ret;
1268 /***********************************************************************
1269 * GetPrivateProfileSection32W (KERNEL32.256)
1272 INT WINAPI GetPrivateProfileSectionW (LPCWSTR section, LPWSTR buffer,
1273 DWORD len, LPCWSTR filename )
1276 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1277 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1278 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1279 INT ret = GetPrivateProfileSectionA( sectionA, bufferA, len,
1280 filenameA );
1281 MultiByteToWideChar(CP_ACP,0,bufferA,ret,buffer,len);
1282 HeapFree( GetProcessHeap(), 0, sectionA );
1283 HeapFree( GetProcessHeap(), 0, filenameA );
1284 HeapFree( GetProcessHeap(), 0, bufferA);
1285 return ret;
1288 /***********************************************************************
1289 * GetProfileSection16 (KERNEL.419)
1291 INT16 WINAPI GetProfileSection16( LPCSTR section, LPSTR buffer, UINT16 len )
1293 return GetPrivateProfileSection16( section, buffer, len, "win.ini" );
1296 /***********************************************************************
1297 * GetProfileSection32A (KERNEL32.268)
1299 INT WINAPI GetProfileSectionA( LPCSTR section, LPSTR buffer, DWORD len )
1301 return GetPrivateProfileSectionA( section, buffer, len, "win.ini" );
1304 /***********************************************************************
1305 * GetProfileSection32W (KERNEL32)
1307 INT WINAPI GetProfileSectionW( LPCWSTR section, LPWSTR buffer, DWORD len )
1309 if (!wininiW) wininiW = HEAP_strdupAtoW( GetProcessHeap(), 0, "win.ini" );
1310 return GetPrivateProfileSectionW( section, buffer, len, wininiW );
1314 /***********************************************************************
1315 * WritePrivateProfileString16 (KERNEL.129)
1317 BOOL16 WINAPI WritePrivateProfileString16( LPCSTR section, LPCSTR entry,
1318 LPCSTR string, LPCSTR filename )
1320 return WritePrivateProfileStringA(section,entry,string,filename);
1323 /***********************************************************************
1324 * WritePrivateProfileString32A (KERNEL32.582)
1326 BOOL WINAPI WritePrivateProfileStringA( LPCSTR section, LPCSTR entry,
1327 LPCSTR string, LPCSTR filename )
1329 BOOL ret = FALSE;
1331 EnterCriticalSection( &PROFILE_CritSect );
1333 if (PROFILE_Open( filename ))
1335 if (!section && !entry && !string)
1336 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1337 else
1338 ret = PROFILE_SetString( section, entry, string );
1341 LeaveCriticalSection( &PROFILE_CritSect );
1342 return ret;
1345 /***********************************************************************
1346 * WritePrivateProfileString32W (KERNEL32.583)
1348 BOOL WINAPI WritePrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1349 LPCWSTR string, LPCWSTR filename )
1351 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1352 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1353 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1354 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1355 BOOL res = WritePrivateProfileStringA( sectionA, entryA,
1356 stringA, filenameA );
1357 HeapFree( GetProcessHeap(), 0, sectionA );
1358 HeapFree( GetProcessHeap(), 0, entryA );
1359 HeapFree( GetProcessHeap(), 0, stringA );
1360 HeapFree( GetProcessHeap(), 0, filenameA );
1361 return res;
1364 /***********************************************************************
1365 * WritePrivateProfileSection16 (KERNEL.416)
1367 BOOL16 WINAPI WritePrivateProfileSection16( LPCSTR section,
1368 LPCSTR string, LPCSTR filename )
1370 return WritePrivateProfileSectionA( section, string, filename );
1373 /***********************************************************************
1374 * WritePrivateProfileSectionA (KERNEL32)
1376 BOOL WINAPI WritePrivateProfileSectionA( LPCSTR section,
1377 LPCSTR string, LPCSTR filename )
1379 BOOL ret = FALSE;
1380 LPSTR p ;
1382 EnterCriticalSection( &PROFILE_CritSect );
1384 if (PROFILE_Open( filename )) {
1385 if (!section && !string && !filename)
1386 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1387 else {
1388 while(*string){
1389 LPSTR buf=HEAP_strdupA( GetProcessHeap(), 0, string );
1390 if((p=strchr( buf, '='))){
1391 *p='\0';
1392 ret = PROFILE_SetString( section, buf, p+1 );
1395 HeapFree( GetProcessHeap(), 0, buf );
1396 string += strlen(string)+1;
1402 LeaveCriticalSection( &PROFILE_CritSect );
1403 return ret;
1406 /***********************************************************************
1407 * WritePrivateProfileSection32W (KERNEL32)
1409 BOOL WINAPI WritePrivateProfileSectionW( LPCWSTR section,
1410 LPCWSTR string, LPCWSTR filename)
1413 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1414 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1415 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1416 BOOL res = WritePrivateProfileSectionA( sectionA, stringA, filenameA );
1417 HeapFree( GetProcessHeap(), 0, sectionA );
1418 HeapFree( GetProcessHeap(), 0, stringA );
1419 HeapFree( GetProcessHeap(), 0, filenameA );
1420 return res;
1423 /***********************************************************************
1424 * WriteProfileSection16 (KERNEL.417)
1426 BOOL16 WINAPI WriteProfileSection16( LPCSTR section, LPCSTR keys_n_values)
1428 return WritePrivateProfileSection16( section, keys_n_values, "win.ini");
1431 /***********************************************************************
1432 * WriteProfileSection32A (KERNEL32.747)
1434 BOOL WINAPI WriteProfileSectionA( LPCSTR section, LPCSTR keys_n_values)
1437 return WritePrivateProfileSectionA( section, keys_n_values, "win.ini");
1440 /***********************************************************************
1441 * WriteProfileSection32W (KERNEL32.748)
1443 BOOL WINAPI WriteProfileSectionW( LPCWSTR section, LPCWSTR keys_n_values)
1445 if (!wininiW) wininiW = HEAP_strdupAtoW( GetProcessHeap(), 0, "win.ini");
1447 return (WritePrivateProfileSectionW (section,keys_n_values, wininiW));
1450 /***********************************************************************
1451 * GetPrivateProfileSectionNames16 (KERNEL.143)
1453 WORD WINAPI GetPrivateProfileSectionNames16( LPSTR buffer, WORD size,
1454 LPCSTR filename )
1456 WORD ret = 0;
1458 EnterCriticalSection( &PROFILE_CritSect );
1460 if (PROFILE_Open( filename ))
1461 ret = PROFILE_GetSectionNames(buffer, size);
1463 LeaveCriticalSection( &PROFILE_CritSect );
1465 return ret;
1469 /***********************************************************************
1470 * GetProfileSectionNames16 (KERNEL.142)
1472 WORD WINAPI GetProfileSectionNames16( LPSTR buffer, WORD size)
1475 return (GetPrivateProfileSectionNames16 (buffer,size,"win.ini"));
1479 /***********************************************************************
1480 * GetPrivateProfileSectionNames32A (KERNEL32.365)
1482 DWORD WINAPI GetPrivateProfileSectionNamesA( LPSTR buffer, DWORD size,
1483 LPCSTR filename)
1486 return (GetPrivateProfileSectionNames16 (buffer,size,filename));
1490 /***********************************************************************
1491 * GetPrivateProfileSectionNames32W (KERNEL32.366)
1493 DWORD WINAPI GetPrivateProfileSectionNamesW( LPWSTR buffer, DWORD size,
1494 LPCWSTR filename)
1497 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1498 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, size);
1500 INT ret = GetPrivateProfileSectionNames16 (bufferA, size, filenameA);
1501 lstrcpynAtoW( buffer, bufferA, size);
1502 HeapFree( GetProcessHeap(), 0, bufferA);
1503 HeapFree( GetProcessHeap(), 0, filenameA );
1505 return ret;
1508 /***********************************************************************
1509 * GetPrivateProfileStruct16 (KERNEL.407)
1511 BOOL16 WINAPI GetPrivateProfileStruct16(LPCSTR section, LPCSTR key,
1512 LPVOID buf, UINT16 len, LPCSTR filename)
1514 return GetPrivateProfileStructA( section, key, buf, len, filename );
1517 /***********************************************************************
1518 * GetPrivateProfileStruct32A (KERNEL32.370)
1520 * Should match Win95's behaviour pretty much
1522 BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key,
1523 LPVOID buf, UINT len, LPCSTR filename)
1525 BOOL ret = FALSE;
1527 EnterCriticalSection( &PROFILE_CritSect );
1529 if (PROFILE_Open( filename )) {
1530 PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE);
1531 if (k) {
1532 TRACE("value (at %p): '%s'\n", k->value, k->value);
1533 if (((strlen(k->value) - 2) / 2) == len)
1535 LPSTR end, p;
1536 BOOL valid = TRUE;
1537 CHAR c;
1538 DWORD chksum = 0;
1540 end = k->value + strlen(k->value); /* -> '\0' */
1541 /* check for invalid chars in ASCII coded hex string */
1542 for (p=k->value; p < end; p++)
1544 if (!isxdigit(*p))
1546 WARN("invalid char '%c' in file '%s'->'[%s]'->'%s' !\n",
1547 *p, filename, section, key);
1548 valid = FALSE;
1549 break;
1552 if (valid)
1554 BOOL highnibble = TRUE;
1555 BYTE b = 0, val;
1556 LPBYTE binbuf = (LPBYTE)buf;
1558 end -= 2; /* don't include checksum in output data */
1559 /* translate ASCII hex format into binary data */
1560 for (p=k->value; p < end; p++)
1562 c = toupper(*p);
1563 val = (c > '9') ?
1564 (c - 'A' + 10) : (c - '0');
1566 if (highnibble)
1567 b = val << 4;
1568 else
1570 b += val;
1571 *binbuf++ = b; /* feed binary data into output */
1572 chksum += b; /* calculate checksum */
1574 highnibble ^= 1; /* toggle */
1576 /* retrieve stored checksum value */
1577 c = toupper(*p++);
1578 b = ( (c > '9') ? (c - 'A' + 10) : (c - '0') ) << 4;
1579 c = toupper(*p);
1580 b += (c > '9') ? (c - 'A' + 10) : (c - '0');
1581 if (b == (chksum & 0xff)) /* checksums match ? */
1582 ret = TRUE;
1587 LeaveCriticalSection( &PROFILE_CritSect );
1589 return ret;
1592 /***********************************************************************
1593 * GetPrivateProfileStruct32W (KERNEL32.543)
1595 BOOL WINAPI GetPrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1596 LPVOID buffer, UINT len, LPCWSTR filename)
1598 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1599 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1600 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1601 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1603 INT ret = GetPrivateProfileStructA( sectionA, keyA, bufferA,
1604 len, filenameA );
1605 lstrcpynAtoW( buffer, bufferA, len );
1606 HeapFree( GetProcessHeap(), 0, bufferA);
1607 HeapFree( GetProcessHeap(), 0, sectionA );
1608 HeapFree( GetProcessHeap(), 0, keyA );
1609 HeapFree( GetProcessHeap(), 0, filenameA );
1611 return ret;
1616 /***********************************************************************
1617 * WritePrivateProfileStruct16 (KERNEL.406)
1619 BOOL16 WINAPI WritePrivateProfileStruct16 (LPCSTR section, LPCSTR key,
1620 LPVOID buf, UINT16 bufsize, LPCSTR filename)
1622 return WritePrivateProfileStructA( section, key, buf, bufsize, filename );
1625 /***********************************************************************
1626 * WritePrivateProfileStruct32A (KERNEL32.744)
1628 BOOL WINAPI WritePrivateProfileStructA (LPCSTR section, LPCSTR key,
1629 LPVOID buf, UINT bufsize, LPCSTR filename)
1631 BOOL ret = FALSE;
1632 LPBYTE binbuf;
1633 LPSTR outstring, p;
1634 DWORD sum = 0;
1636 if (!section && !key && !buf) /* flush the cache */
1637 return WritePrivateProfileStringA( NULL, NULL, NULL, filename );
1639 /* allocate string buffer for hex chars + checksum hex char + '\0' */
1640 outstring = HeapAlloc( GetProcessHeap(), 0, bufsize*2 + 2 + 1);
1641 p = outstring;
1642 for (binbuf = (LPBYTE)buf; binbuf < (LPBYTE)buf+bufsize; binbuf++) {
1643 *p++ = hex[*binbuf >> 4];
1644 *p++ = hex[*binbuf & 0xf];
1645 sum += *binbuf;
1647 /* checksum is sum & 0xff */
1648 *p++ = hex[(sum & 0xf0) >> 4];
1649 *p++ = hex[sum & 0xf];
1650 *p++ = '\0';
1652 EnterCriticalSection( &PROFILE_CritSect );
1654 if (PROFILE_Open( filename ))
1655 ret = PROFILE_SetString( section, key, outstring );
1657 LeaveCriticalSection( &PROFILE_CritSect );
1659 HeapFree( GetProcessHeap(), 0, outstring );
1661 return ret;
1664 /***********************************************************************
1665 * WritePrivateProfileStruct32W (KERNEL32.544)
1667 BOOL WINAPI WritePrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1668 LPVOID buf, UINT bufsize, LPCWSTR filename)
1670 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1671 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1672 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1673 INT ret = WritePrivateProfileStructA( sectionA, keyA, buf, bufsize,
1674 filenameA );
1675 HeapFree( GetProcessHeap(), 0, sectionA );
1676 HeapFree( GetProcessHeap(), 0, keyA );
1677 HeapFree( GetProcessHeap(), 0, filenameA );
1679 return ret;
1683 /***********************************************************************
1684 * WriteOutProfiles (KERNEL.315)
1686 void WINAPI WriteOutProfiles16(void)
1688 EnterCriticalSection( &PROFILE_CritSect );
1689 PROFILE_FlushFile();
1690 LeaveCriticalSection( &PROFILE_CritSect );
1693 /***********************************************************************
1694 * CloseProfileUserMapping (KERNEL.138)
1696 BOOL WINAPI CloseProfileUserMapping(void) {
1697 FIXME("(), stub!\n");
1698 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1699 return FALSE;