Got rid of PROFILE_ functions, now accessing Wine config options
[wine.git] / files / profile.c
blob9448832a0909ac8b8c6ce07cc469a07af5b6594c
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 "winreg.h"
25 #include "file.h"
26 #include "heap.h"
27 #include "debugtools.h"
28 #include "xmalloc.h"
29 #include "options.h"
30 #include "server.h"
32 DEFAULT_DEBUG_CHANNEL(profile);
34 typedef struct tagPROFILEKEY
36 char *name;
37 char *value;
38 struct tagPROFILEKEY *next;
39 } PROFILEKEY;
41 typedef struct tagPROFILESECTION
43 char *name;
44 struct tagPROFILEKEY *key;
45 struct tagPROFILESECTION *next;
46 } PROFILESECTION;
49 typedef struct
51 BOOL changed;
52 PROFILESECTION *section;
53 char *dos_name;
54 char *unix_name;
55 char *filename;
56 time_t mtime;
57 } PROFILE;
60 #define N_CACHED_PROFILES 10
62 /* Cached profile files */
63 static PROFILE *MRUProfile[N_CACHED_PROFILES]={NULL};
65 #define CurProfile (MRUProfile[0])
67 /* wine.ini config file registry root */
68 static HKEY wine_profile_key;
70 #define PROFILE_MAX_LINE_LEN 1024
72 /* Wine profile name in $HOME directory; must begin with slash */
73 static const char PROFILE_WineIniName[] = "/.winerc";
75 /* Wine profile: the profile file being used */
76 static char PROFILE_WineIniUsed[MAX_PATHNAME_LEN] = "";
78 /* Check for comments in profile */
79 #define IS_ENTRY_COMMENT(str) ((str)[0] == ';')
81 #define WINE_INI_GLOBAL ETCDIR "/wine.conf"
82 #define WINE_CONFIG_DIR "/.wine" /* config dir inside $HOME */
84 static const WCHAR wininiW[] = { 'w','i','n','.','i','n','i',0 };
86 static CRITICAL_SECTION PROFILE_CritSect;
88 static const char hex[16] = "0123456789ABCDEF";
90 /***********************************************************************
91 * PROFILE_GetConfigDir
93 * Return the name of the configuration directory ($HOME/.wine)
95 const char *PROFILE_GetConfigDir(void)
97 static char *confdir;
98 if (!confdir)
100 const char *home = getenv( "HOME" );
101 if (!home)
103 struct passwd *pwd = getpwuid( getuid() );
104 if (!pwd)
106 fprintf( stderr, "wine: could not find your home directory\n" );
107 exit(1);
109 home = pwd->pw_dir;
111 confdir = xmalloc( strlen(home) + strlen(WINE_CONFIG_DIR) + 1 );
112 strcpy( confdir, home );
113 strcat( confdir, WINE_CONFIG_DIR );
114 mkdir( confdir, 0755 ); /* create it just in case */
116 return confdir;
120 /***********************************************************************
121 * PROFILE_CopyEntry
123 * Copy the content of an entry into a buffer, removing quotes, and possibly
124 * translating environment variables.
126 static void PROFILE_CopyEntry( char *buffer, const char *value, int len,
127 int handle_env )
129 char quote = '\0';
130 const char *p;
132 if ((*value == '\'') || (*value == '\"'))
134 if (value[1] && (value[strlen(value)-1] == *value)) quote = *value++;
137 if (!handle_env)
139 lstrcpynA( buffer, value, len );
140 if (quote && (len >= strlen(value))) buffer[strlen(buffer)-1] = '\0';
141 return;
144 for (p = value; (*p && (len > 1)); *buffer++ = *p++, len-- )
146 if ((*p == '$') && (p[1] == '{'))
148 char env_val[1024];
149 const char *env_p;
150 const char *p2 = strchr( p, '}' );
151 if (!p2) continue; /* ignore it */
152 lstrcpynA(env_val, p + 2, MIN( sizeof(env_val), (int)(p2-p)-1 ));
153 if ((env_p = getenv( env_val )) != NULL)
155 lstrcpynA( buffer, env_p, len );
156 buffer += strlen( buffer );
157 len -= strlen( buffer );
159 p = p2 + 1;
162 if (quote && (len > 1)) buffer--;
163 *buffer = '\0';
167 /***********************************************************************
168 * PROFILE_Save
170 * Save a profile tree to a file.
172 static void PROFILE_Save( FILE *file, PROFILESECTION *section )
174 PROFILEKEY *key;
176 for ( ; section; section = section->next)
178 if (section->name) fprintf( file, "\r\n[%s]\r\n", section->name );
179 for (key = section->key; key; key = key->next)
181 fprintf( file, "%s", key->name );
182 if (key->value) fprintf( file, "=%s", key->value );
183 fprintf( file, "\r\n" );
189 /***********************************************************************
190 * PROFILE_Free
192 * Free a profile tree.
194 static void PROFILE_Free( PROFILESECTION *section )
196 PROFILESECTION *next_section;
197 PROFILEKEY *key, *next_key;
199 for ( ; section; section = next_section)
201 if (section->name) HeapFree( GetProcessHeap(), 0, section->name );
202 for (key = section->key; key; key = next_key)
204 next_key = key->next;
205 if (key->name) HeapFree( GetProcessHeap(), 0, key->name );
206 if (key->value) HeapFree( GetProcessHeap(), 0, key->value );
207 HeapFree( GetProcessHeap(), 0, key );
209 next_section = section->next;
210 HeapFree( GetProcessHeap(), 0, section );
214 static inline int PROFILE_isspace(char c)
216 if (isspace(c)) return 1;
217 if (c=='\r' || c==0x1a) return 1;
218 /* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */
219 return 0;
223 /***********************************************************************
224 * PROFILE_Load
226 * Load a profile tree from a file.
228 static PROFILESECTION *PROFILE_Load( FILE *file )
230 char buffer[PROFILE_MAX_LINE_LEN];
231 char *p, *p2;
232 int line = 0;
233 PROFILESECTION *section, *first_section;
234 PROFILESECTION **next_section;
235 PROFILEKEY *key, *prev_key, **next_key;
237 first_section = HEAP_xalloc( GetProcessHeap(), 0, sizeof(*section) );
238 first_section->name = NULL;
239 first_section->key = NULL;
240 first_section->next = NULL;
241 next_section = &first_section->next;
242 next_key = &first_section->key;
243 prev_key = NULL;
245 while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
247 line++;
248 p = buffer;
249 while (*p && PROFILE_isspace(*p)) p++;
250 if (*p == '[') /* section start */
252 if (!(p2 = strrchr( p, ']' )))
254 WARN("Invalid section header at line %d: '%s'\n",
255 line, p );
257 else
259 *p2 = '\0';
260 p++;
261 section = HEAP_xalloc( GetProcessHeap(), 0, sizeof(*section) );
262 section->name = HEAP_strdupA( GetProcessHeap(), 0, p );
263 section->key = NULL;
264 section->next = NULL;
265 *next_section = section;
266 next_section = &section->next;
267 next_key = &section->key;
268 prev_key = NULL;
270 TRACE("New section: '%s'\n",section->name);
272 continue;
276 p2=p+strlen(p) - 1;
277 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
279 if ((p2 = strchr( p, '=' )) != NULL)
281 char *p3 = p2 - 1;
282 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
283 *p2++ = '\0';
284 while (*p2 && PROFILE_isspace(*p2)) p2++;
287 if(*p || !prev_key || *prev_key->name)
289 key = HEAP_xalloc( GetProcessHeap(), 0, sizeof(*key) );
290 key->name = HEAP_strdupA( GetProcessHeap(), 0, p );
291 key->value = p2 ? HEAP_strdupA( GetProcessHeap(), 0, p2 ) : NULL;
292 key->next = NULL;
293 *next_key = key;
294 next_key = &key->next;
295 prev_key = key;
297 TRACE("New key: name='%s', value='%s'\n",key->name,key->value?key->value:"(none)");
300 return first_section;
304 /***********************************************************************
305 * PROFILE_RegistryLoad
307 * Load a profile tree from a file into a registry key.
309 static DWORD PROFILE_RegistryLoad( HKEY root, FILE *file )
311 HKEY hkey = 0;
312 DWORD err = 0;
313 char buffer[PROFILE_MAX_LINE_LEN];
314 char *p, *p2;
315 int line = 0;
317 while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
319 line++;
320 p = buffer;
321 while (*p && PROFILE_isspace(*p)) p++;
322 if (*p == '[') /* section start */
324 if (!(p2 = strrchr( p, ']' )))
326 WARN("Invalid section header at line %d: '%s'\n",
327 line, p );
329 else
331 *p2 = '\0';
332 p++;
333 if (hkey) RegCloseKey( hkey );
334 if ((err = RegCreateKeyExA( root, p, 0, NULL, REG_OPTION_VOLATILE,
335 KEY_ALL_ACCESS, NULL, &hkey, NULL ))) return err;
336 TRACE("New section: '%s'\n",p);
337 continue;
341 p2=p+strlen(p) - 1;
342 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
344 if ((p2 = strchr( p, '=' )) != NULL)
346 char *p3 = p2 - 1;
347 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
348 *p2++ = '\0';
349 while (*p2 && PROFILE_isspace(*p2)) p2++;
352 if (*p && hkey && !IS_ENTRY_COMMENT(p))
354 if (!p2) p2 = "";
355 if ((err = RegSetValueExA( hkey, p, 0, REG_SZ, p2, strlen(p2)+1 )))
357 RegCloseKey( hkey );
358 return err;
360 TRACE("New key: name='%s', value='%s'\n",p,p2);
363 if (hkey) RegCloseKey( hkey );
364 return 0;
368 /***********************************************************************
369 * PROFILE_DeleteSection
371 * Delete a section from a profile tree.
373 static BOOL PROFILE_DeleteSection( PROFILESECTION **section, LPCSTR name )
375 while (*section)
377 if ((*section)->name && !strcasecmp( (*section)->name, name ))
379 PROFILESECTION *to_del = *section;
380 *section = to_del->next;
381 to_del->next = NULL;
382 PROFILE_Free( to_del );
383 return TRUE;
385 section = &(*section)->next;
387 return FALSE;
391 /***********************************************************************
392 * PROFILE_DeleteKey
394 * Delete a key from a profile tree.
396 static BOOL PROFILE_DeleteKey( PROFILESECTION **section,
397 LPCSTR section_name, LPCSTR key_name )
399 while (*section)
401 if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
403 PROFILEKEY **key = &(*section)->key;
404 while (*key)
406 if (!strcasecmp( (*key)->name, key_name ))
408 PROFILEKEY *to_del = *key;
409 *key = to_del->next;
410 if (to_del->name) HeapFree( GetProcessHeap(), 0, to_del->name );
411 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
412 HeapFree( GetProcessHeap(), 0, to_del );
413 return TRUE;
415 key = &(*key)->next;
418 section = &(*section)->next;
420 return FALSE;
424 /***********************************************************************
425 * PROFILE_Find
427 * Find a key in a profile tree, optionally creating it.
429 static PROFILEKEY *PROFILE_Find( PROFILESECTION **section,
430 const char *section_name,
431 const char *key_name, int create )
433 const char *p;
434 int seclen, keylen;
436 while (PROFILE_isspace(*section_name)) section_name++;
437 p = section_name + strlen(section_name) - 1;
438 while ((p > section_name) && PROFILE_isspace(*p)) p--;
439 seclen = p - section_name + 1;
441 while (PROFILE_isspace(*key_name)) key_name++;
442 p = key_name + strlen(key_name) - 1;
443 while ((p > key_name) && PROFILE_isspace(*p)) p--;
444 keylen = p - key_name + 1;
446 while (*section)
448 if ( ((*section)->name)
449 && (!(strncasecmp( (*section)->name, section_name, seclen )))
450 && (((*section)->name)[seclen] == '\0') )
452 PROFILEKEY **key = &(*section)->key;
453 while (*key)
455 if ( (!(strncasecmp( (*key)->name, key_name, keylen )))
456 && (((*key)->name)[keylen] == '\0') )
457 return *key;
458 key = &(*key)->next;
460 if (!create) return NULL;
461 *key = HEAP_xalloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) );
462 (*key)->name = HEAP_strdupA( GetProcessHeap(), 0, key_name );
463 (*key)->value = NULL;
464 (*key)->next = NULL;
465 return *key;
467 section = &(*section)->next;
469 if (!create) return NULL;
470 *section = HEAP_xalloc( GetProcessHeap(), 0, sizeof(PROFILESECTION) );
471 (*section)->name = HEAP_strdupA( GetProcessHeap(), 0, section_name );
472 (*section)->next = NULL;
473 (*section)->key = HEAP_xalloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) );
474 (*section)->key->name = HEAP_strdupA( GetProcessHeap(), 0, key_name );
475 (*section)->key->value = NULL;
476 (*section)->key->next = NULL;
477 return (*section)->key;
481 /***********************************************************************
482 * PROFILE_FlushFile
484 * Flush the current profile to disk if changed.
486 static BOOL PROFILE_FlushFile(void)
488 char *p, buffer[MAX_PATHNAME_LEN];
489 const char *unix_name;
490 FILE *file = NULL;
491 struct stat buf;
493 if(!CurProfile)
495 WARN("No current profile!\n");
496 return FALSE;
499 if (!CurProfile->changed || !CurProfile->dos_name) return TRUE;
500 if (!(unix_name = CurProfile->unix_name) || !(file = fopen(unix_name, "w")))
502 /* Try to create it in $HOME/.wine */
503 /* FIXME: this will need a more general solution */
504 strcpy( buffer, PROFILE_GetConfigDir() );
505 p = buffer + strlen(buffer);
506 *p++ = '/';
507 strcpy( p, strrchr( CurProfile->dos_name, '\\' ) + 1 );
508 CharLowerA( p );
509 file = fopen( buffer, "w" );
510 unix_name = buffer;
513 if (!file)
515 WARN("could not save profile file %s\n", CurProfile->dos_name);
516 return FALSE;
519 TRACE("Saving '%s' into '%s'\n", CurProfile->dos_name, unix_name );
520 PROFILE_Save( file, CurProfile->section );
521 fclose( file );
522 CurProfile->changed = FALSE;
523 if(!stat(unix_name,&buf))
524 CurProfile->mtime=buf.st_mtime;
525 return TRUE;
529 /***********************************************************************
530 * PROFILE_ReleaseFile
532 * Flush the current profile to disk and remove it from the cache.
534 static void PROFILE_ReleaseFile(void)
536 PROFILE_FlushFile();
537 PROFILE_Free( CurProfile->section );
538 if (CurProfile->dos_name) HeapFree( GetProcessHeap(), 0, CurProfile->dos_name );
539 if (CurProfile->unix_name) HeapFree( GetProcessHeap(), 0, CurProfile->unix_name );
540 if (CurProfile->filename) HeapFree( GetProcessHeap(), 0, CurProfile->filename );
541 CurProfile->changed = FALSE;
542 CurProfile->section = NULL;
543 CurProfile->dos_name = NULL;
544 CurProfile->unix_name = NULL;
545 CurProfile->filename = NULL;
546 CurProfile->mtime = 0;
550 /***********************************************************************
551 * PROFILE_Open
553 * Open a profile file, checking the cached file first.
555 static BOOL PROFILE_Open( LPCSTR filename )
557 DOS_FULL_NAME full_name;
558 char buffer[MAX_PATHNAME_LEN];
559 char *newdos_name, *p;
560 FILE *file = NULL;
561 int i,j;
562 struct stat buf;
563 PROFILE *tempProfile;
565 /* First time around */
567 if(!CurProfile)
568 for(i=0;i<N_CACHED_PROFILES;i++)
570 MRUProfile[i]=HEAP_xalloc( GetProcessHeap(), 0, sizeof(PROFILE) );
571 MRUProfile[i]->changed=FALSE;
572 MRUProfile[i]->section=NULL;
573 MRUProfile[i]->dos_name=NULL;
574 MRUProfile[i]->unix_name=NULL;
575 MRUProfile[i]->filename=NULL;
576 MRUProfile[i]->mtime=0;
579 /* Check for a match */
581 if (strchr( filename, '/' ) || strchr( filename, '\\' ) ||
582 strchr( filename, ':' ))
584 if (!DOSFS_GetFullName( filename, FALSE, &full_name )) return FALSE;
586 else
588 GetWindowsDirectoryA( buffer, sizeof(buffer) );
589 strcat( buffer, "\\" );
590 strcat( buffer, filename );
591 if (!DOSFS_GetFullName( buffer, FALSE, &full_name )) return FALSE;
594 for(i=0;i<N_CACHED_PROFILES;i++)
596 if ((MRUProfile[i]->filename && !strcmp( filename, MRUProfile[i]->filename )) ||
597 (MRUProfile[i]->dos_name && !strcmp( full_name.short_name, MRUProfile[i]->dos_name )))
599 if(i)
601 PROFILE_FlushFile();
602 tempProfile=MRUProfile[i];
603 for(j=i;j>0;j--)
604 MRUProfile[j]=MRUProfile[j-1];
605 CurProfile=tempProfile;
607 if(!stat(CurProfile->unix_name,&buf) && CurProfile->mtime==buf.st_mtime)
608 TRACE("(%s): already opened (mru=%d)\n",
609 filename, i );
610 else
611 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
612 filename, i );
613 return TRUE;
617 /* Flush the old current profile */
618 PROFILE_FlushFile();
620 /* Make the oldest profile the current one only in order to get rid of it */
621 if(i==N_CACHED_PROFILES)
623 tempProfile=MRUProfile[N_CACHED_PROFILES-1];
624 for(i=N_CACHED_PROFILES-1;i>0;i--)
625 MRUProfile[i]=MRUProfile[i-1];
626 CurProfile=tempProfile;
628 if(CurProfile->filename) PROFILE_ReleaseFile();
630 /* OK, now that CurProfile is definitely free we assign it our new file */
631 newdos_name = HEAP_strdupA( GetProcessHeap(), 0, full_name.short_name );
632 CurProfile->dos_name = newdos_name;
633 CurProfile->filename = HEAP_strdupA( GetProcessHeap(), 0, filename );
635 /* Try to open the profile file, first in $HOME/.wine */
637 /* FIXME: this will need a more general solution */
638 strcpy( buffer, PROFILE_GetConfigDir() );
639 p = buffer + strlen(buffer);
640 *p++ = '/';
641 strcpy( p, strrchr( newdos_name, '\\' ) + 1 );
642 CharLowerA( p );
643 if ((file = fopen( buffer, "r" )))
645 TRACE("(%s): found it in %s\n",
646 filename, buffer );
647 CurProfile->unix_name = HEAP_strdupA( GetProcessHeap(), 0, buffer );
650 if (!file)
652 CurProfile->unix_name = HEAP_strdupA( GetProcessHeap(), 0,
653 full_name.long_name );
654 if ((file = fopen( full_name.long_name, "r" )))
655 TRACE("(%s): found it in %s\n",
656 filename, full_name.long_name );
659 if (file)
661 CurProfile->section = PROFILE_Load( file );
662 fclose( file );
663 if(!stat(CurProfile->unix_name,&buf))
664 CurProfile->mtime=buf.st_mtime;
666 else
668 /* Does not exist yet, we will create it in PROFILE_FlushFile */
669 WARN("profile file %s not found\n", newdos_name );
671 return TRUE;
675 /***********************************************************************
676 * PROFILE_GetSection
678 * Returns all keys of a section.
679 * If return_values is TRUE, also include the corresponding values.
681 static INT PROFILE_GetSection( PROFILESECTION *section, LPCSTR section_name,
682 LPSTR buffer, UINT len, BOOL handle_env,
683 BOOL return_values )
685 PROFILEKEY *key;
686 while (section)
688 if (section->name && !strcasecmp( section->name, section_name ))
690 UINT oldlen = len;
691 for (key = section->key; key; key = key->next)
693 if (len <= 2) break;
694 if (!*key->name) continue; /* Skip empty lines */
695 if (IS_ENTRY_COMMENT(key->name)) continue; /* Skip comments */
696 PROFILE_CopyEntry( buffer, key->name, len - 1, handle_env );
697 len -= strlen(buffer) + 1;
698 buffer += strlen(buffer) + 1;
699 if (return_values && key->value) {
700 buffer[-1] = '=';
701 PROFILE_CopyEntry ( buffer,
702 key->value, len - 1, handle_env );
703 len -= strlen(buffer) + 1;
704 buffer += strlen(buffer) + 1;
707 *buffer = '\0';
708 if (len <= 1)
709 /*If either lpszSection or lpszKey is NULL and the supplied
710 destination buffer is too small to hold all the strings,
711 the last string is truncated and followed by two null characters.
712 In this case, the return value is equal to cchReturnBuffer
713 minus two. */
715 buffer[-1] = '\0';
716 return oldlen - 2;
718 return oldlen - len;
720 section = section->next;
722 buffer[0] = buffer[1] = '\0';
723 return 0;
727 static INT PROFILE_GetSectionNames( LPSTR buffer, UINT len )
729 LPSTR buf = buffer;
730 WORD l, cursize = 0;
731 PROFILESECTION *section;
733 for (section = CurProfile->section; section; section = section->next)
734 if (section->name) {
735 l = strlen(section->name);
736 cursize += l+1;
737 if (cursize > len+1)
738 return len-2;
740 strcpy(buf, section->name);
741 buf += l+1;
744 *buf=0;
745 buf++;
746 return buf-buffer;
750 /***********************************************************************
751 * PROFILE_GetString
753 * Get a profile string.
755 static INT PROFILE_GetString( LPCSTR section, LPCSTR key_name,
756 LPCSTR def_val, LPSTR buffer, UINT len )
758 PROFILEKEY *key = NULL;
760 if (!def_val) def_val = "";
761 if (key_name && key_name[0])
763 key = PROFILE_Find( &CurProfile->section, section, key_name, FALSE );
764 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def_val,
765 len, FALSE );
766 TRACE("('%s','%s','%s'): returning '%s'\n",
767 section, key_name, def_val, buffer );
768 return strlen( buffer );
770 if (section && section[0])
771 return PROFILE_GetSection(CurProfile->section, section, buffer, len,
772 FALSE, FALSE);
773 /* undocumented; both section and key_name are NULL */
774 return PROFILE_GetSectionNames(buffer, len);
778 /***********************************************************************
779 * PROFILE_SetString
781 * Set a profile string.
783 static BOOL PROFILE_SetString( LPCSTR section_name, LPCSTR key_name,
784 LPCSTR value )
786 if (!key_name) /* Delete a whole section */
788 TRACE("('%s')\n", section_name);
789 CurProfile->changed |= PROFILE_DeleteSection( &CurProfile->section,
790 section_name );
791 return TRUE; /* Even if PROFILE_DeleteSection() has failed,
792 this is not an error on application's level.*/
794 else if (!value) /* Delete a key */
796 TRACE("('%s','%s')\n",
797 section_name, key_name );
798 CurProfile->changed |= PROFILE_DeleteKey( &CurProfile->section,
799 section_name, key_name );
800 return TRUE; /* same error handling as above */
802 else /* Set the key value */
804 PROFILEKEY *key = PROFILE_Find( &CurProfile->section, section_name,
805 key_name, TRUE );
806 TRACE("('%s','%s','%s'): \n",
807 section_name, key_name, value );
808 if (!key) return FALSE;
809 if (key->value)
811 if (!strcmp( key->value, value ))
813 TRACE(" no change needed\n" );
814 return TRUE; /* No change needed */
816 TRACE(" replacing '%s'\n", key->value );
817 HeapFree( GetProcessHeap(), 0, key->value );
819 else TRACE(" creating key\n" );
820 key->value = HEAP_strdupA( GetProcessHeap(), 0, value );
821 CurProfile->changed = TRUE;
823 return TRUE;
827 /***********************************************************************
828 * PROFILE_GetWineIniString
830 * Get a config string from the wine.ini file.
832 int PROFILE_GetWineIniString( const char *section, const char *key_name,
833 const char *def, char *buffer, int len )
835 char tmp[PROFILE_MAX_LINE_LEN];
836 HKEY hkey;
837 DWORD err;
839 if (!(err = RegOpenKeyA( wine_profile_key, section, &hkey )))
841 DWORD type;
842 DWORD count = sizeof(tmp);
843 err = RegQueryValueExA( hkey, key_name, 0, &type, tmp, &count );
844 RegCloseKey( hkey );
846 PROFILE_CopyEntry( buffer, err ? def : tmp, len, TRUE );
847 TRACE( "('%s','%s','%s'): returning '%s'\n", section, key_name, def, buffer );
848 return strlen(buffer);
852 /***********************************************************************
853 * PROFILE_EnumWineIniString
855 * Get a config string from the wine.ini file.
857 BOOL PROFILE_EnumWineIniString( const char *section, int index,
858 char *name, int name_len, char *buffer, int len )
860 char tmp[PROFILE_MAX_LINE_LEN];
861 HKEY hkey;
862 DWORD err, type;
863 DWORD count = sizeof(tmp);
865 if (RegOpenKeyA( wine_profile_key, section, &hkey )) return FALSE;
866 err = RegEnumValueA( hkey, index, name, (DWORD*)&name_len, NULL, &type, tmp, &count );
867 RegCloseKey( hkey );
868 if (!err)
870 PROFILE_CopyEntry( buffer, tmp, len, TRUE );
871 TRACE( "('%s',%d): returning '%s'='%s'\n", section, index, name, buffer );
873 return !err;
877 /***********************************************************************
878 * PROFILE_GetWineIniInt
880 * Get a config integer from the wine.ini file.
882 int PROFILE_GetWineIniInt( const char *section, const char *key_name, int def )
884 char buffer[20];
885 char *p;
886 long result;
888 PROFILE_GetWineIniString( section, key_name, "", buffer, sizeof(buffer) );
889 if (!buffer[0]) return def;
890 result = strtol( buffer, &p, 0 );
891 return (p == buffer) ? 0 /* No digits at all */ : (int)result;
895 /******************************************************************************
897 * int PROFILE_GetWineIniBool(
898 * char const *section,
899 * char const *key_name,
900 * int def )
902 * Reads a boolean value from the wine.ini file. This function attempts to
903 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
904 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
905 * true. Anything else results in the return of the default value.
907 * This function uses 1 to indicate true, and 0 for false. You can check
908 * for existence by setting def to something other than 0 or 1 and
909 * examining the return value.
911 int PROFILE_GetWineIniBool(
912 char const *section,
913 char const *key_name,
914 int def )
916 char key_value[2];
917 int retval;
919 PROFILE_GetWineIniString(section, key_name, "~", key_value, 2);
921 switch(key_value[0]) {
922 case 'n':
923 case 'N':
924 case 'f':
925 case 'F':
926 case '0':
927 retval = 0;
928 break;
930 case 'y':
931 case 'Y':
932 case 't':
933 case 'T':
934 case '1':
935 retval = 1;
936 break;
938 default:
939 retval = def;
942 TRACE("(\"%s\", \"%s\", %s), "
943 "[%c], ret %s.\n", section, key_name,
944 def ? "TRUE" : "FALSE", key_value[0],
945 retval ? "TRUE" : "FALSE");
947 return retval;
951 /***********************************************************************
952 * PROFILE_LoadWineIni
954 * Load the wine.ini file.
956 int PROFILE_LoadWineIni(void)
958 char buffer[MAX_PATHNAME_LEN];
959 const char *p;
960 FILE *f;
961 HKEY hKeySW;
963 /* make sure HKLM\\Software exists as non-volatile key */
964 if (RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software", &hKeySW ))
966 ERR("Cannot create config registry key\n" );
967 return 0;
969 RegCloseKey( hKeySW );
970 if (RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config", 0, NULL,
971 REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &wine_profile_key, NULL ))
973 ERR("Cannot create config registry key\n" );
974 return 0;
977 InitializeCriticalSection( &PROFILE_CritSect );
978 MakeCriticalSectionGlobal( &PROFILE_CritSect );
980 if (!CLIENT_IsBootThread()) return 1; /* already loaded */
982 if ( (Options.configFileName!=NULL) && (f = fopen(Options.configFileName, "r")) )
984 /* Open -config specified file */
985 lstrcpynA(PROFILE_WineIniUsed,Options.configFileName,MAX_PATHNAME_LEN);
986 goto found;
989 if ( (p = getenv( "WINE_INI" )) && (f = fopen( p, "r" )) )
991 lstrcpynA(PROFILE_WineIniUsed,p,MAX_PATHNAME_LEN);
992 goto found;
994 if ((p = getenv( "HOME" )) != NULL)
996 lstrcpynA(buffer, p, MAX_PATHNAME_LEN - sizeof(PROFILE_WineIniName));
997 strcat( buffer, PROFILE_WineIniName );
998 if ((f = fopen( buffer, "r" )) != NULL)
1000 lstrcpynA(PROFILE_WineIniUsed,buffer,MAX_PATHNAME_LEN);
1001 goto found;
1004 else WARN("could not get $HOME value for config file.\n" );
1006 /* Try global file */
1008 if ((f = fopen( WINE_INI_GLOBAL, "r" )) != NULL)
1010 lstrcpynA(PROFILE_WineIniUsed,WINE_INI_GLOBAL,MAX_PATHNAME_LEN);
1011 goto found;
1013 MESSAGE( "Can't open configuration file %s or $HOME%s\n",
1014 WINE_INI_GLOBAL, PROFILE_WineIniName );
1015 return 0;
1017 found:
1018 PROFILE_RegistryLoad( wine_profile_key, f );
1019 fclose( f );
1020 return 1;
1024 /***********************************************************************
1025 * PROFILE_UsageWineIni
1027 * Explain the wine.ini file to those who don't read documentation.
1028 * Keep below one screenful in length so that error messages above are
1029 * noticed.
1031 void PROFILE_UsageWineIni(void)
1033 MESSAGE("Perhaps you have not properly edited or created "
1034 "your Wine configuration file.\n");
1035 MESSAGE("This is either %s or $HOME%s\n",WINE_INI_GLOBAL,PROFILE_WineIniName);
1036 MESSAGE(" or it is determined by the -config option or from\n"
1037 " the WINE_INI environment variable.\n");
1038 if (*PROFILE_WineIniUsed)
1039 MESSAGE("Wine has used %s as configuration file.\n", PROFILE_WineIniUsed);
1040 /* RTFM, so to say */
1043 /***********************************************************************
1044 * PROFILE_GetStringItem
1046 * Convenience function that turns a string 'xxx, yyy, zzz' into
1047 * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
1049 char* PROFILE_GetStringItem( char* start )
1051 char* lpchX, *lpch;
1053 for (lpchX = start, lpch = NULL; *lpchX != '\0'; lpchX++ )
1055 if( *lpchX == ',' )
1057 if( lpch ) *lpch = '\0'; else *lpchX = '\0';
1058 while( *(++lpchX) )
1059 if( !PROFILE_isspace(*lpchX) ) return lpchX;
1061 else if( PROFILE_isspace( *lpchX ) && !lpch ) lpch = lpchX;
1062 else lpch = NULL;
1064 if( lpch ) *lpch = '\0';
1065 return NULL;
1068 /********************* API functions **********************************/
1070 /***********************************************************************
1071 * GetProfileInt16 (KERNEL.57)
1073 UINT16 WINAPI GetProfileInt16( LPCSTR section, LPCSTR entry, INT16 def_val )
1075 return GetPrivateProfileInt16( section, entry, def_val, "win.ini" );
1079 /***********************************************************************
1080 * GetProfileInt32A (KERNEL32.264)
1082 UINT WINAPI GetProfileIntA( LPCSTR section, LPCSTR entry, INT def_val )
1084 return GetPrivateProfileIntA( section, entry, def_val, "win.ini" );
1087 /***********************************************************************
1088 * GetProfileInt32W (KERNEL32.264)
1090 UINT WINAPI GetProfileIntW( LPCWSTR section, LPCWSTR entry, INT def_val )
1092 return GetPrivateProfileIntW( section, entry, def_val, wininiW );
1095 /***********************************************************************
1096 * GetProfileString16 (KERNEL.58)
1098 INT16 WINAPI GetProfileString16( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1099 LPSTR buffer, UINT16 len )
1101 return GetPrivateProfileString16( section, entry, def_val,
1102 buffer, len, "win.ini" );
1105 /***********************************************************************
1106 * GetProfileString32A (KERNEL32.268)
1108 INT WINAPI GetProfileStringA( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1109 LPSTR buffer, UINT len )
1111 return GetPrivateProfileStringA( section, entry, def_val,
1112 buffer, len, "win.ini" );
1115 /***********************************************************************
1116 * GetProfileString32W (KERNEL32.269)
1118 INT WINAPI GetProfileStringW( LPCWSTR section, LPCWSTR entry,
1119 LPCWSTR def_val, LPWSTR buffer, UINT len )
1121 return GetPrivateProfileStringW( section, entry, def_val,
1122 buffer, len, wininiW );
1125 /***********************************************************************
1126 * WriteProfileString16 (KERNEL.59)
1128 BOOL16 WINAPI WriteProfileString16( LPCSTR section, LPCSTR entry,
1129 LPCSTR string )
1131 return WritePrivateProfileString16( section, entry, string, "win.ini" );
1134 /***********************************************************************
1135 * WriteProfileString32A (KERNEL32.587)
1137 BOOL WINAPI WriteProfileStringA( LPCSTR section, LPCSTR entry,
1138 LPCSTR string )
1140 return WritePrivateProfileStringA( section, entry, string, "win.ini" );
1143 /***********************************************************************
1144 * WriteProfileString32W (KERNEL32.588)
1146 BOOL WINAPI WriteProfileStringW( LPCWSTR section, LPCWSTR entry,
1147 LPCWSTR string )
1149 return WritePrivateProfileStringW( section, entry, string, wininiW );
1153 /***********************************************************************
1154 * GetPrivateProfileInt16 (KERNEL.127)
1156 UINT16 WINAPI GetPrivateProfileInt16( LPCSTR section, LPCSTR entry,
1157 INT16 def_val, LPCSTR filename )
1159 long result=(long)GetPrivateProfileIntA(section,entry,def_val,filename);
1161 if (result > 65535) return 65535;
1162 if (result >= 0) return (UINT16)result;
1163 if (result < -32768) return -32768;
1164 return (UINT16)(INT16)result;
1167 /***********************************************************************
1168 * GetPrivateProfileInt32A (KERNEL32.251)
1170 UINT WINAPI GetPrivateProfileIntA( LPCSTR section, LPCSTR entry,
1171 INT def_val, LPCSTR filename )
1173 char buffer[20];
1174 char *p;
1175 long result;
1177 GetPrivateProfileStringA( section, entry, "",
1178 buffer, sizeof(buffer), filename );
1179 if (!buffer[0]) return (UINT)def_val;
1180 result = strtol( buffer, &p, 0 );
1181 if (p == buffer) return 0; /* No digits at all */
1182 return (UINT)result;
1185 /***********************************************************************
1186 * GetPrivateProfileInt32W (KERNEL32.252)
1188 UINT WINAPI GetPrivateProfileIntW( LPCWSTR section, LPCWSTR entry,
1189 INT def_val, LPCWSTR filename )
1191 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1192 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1193 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1194 UINT res = GetPrivateProfileIntA(sectionA, entryA, def_val, filenameA);
1195 HeapFree( GetProcessHeap(), 0, sectionA );
1196 HeapFree( GetProcessHeap(), 0, filenameA );
1197 HeapFree( GetProcessHeap(), 0, entryA );
1198 return res;
1201 /***********************************************************************
1202 * GetPrivateProfileString16 (KERNEL.128)
1204 INT16 WINAPI GetPrivateProfileString16( LPCSTR section, LPCSTR entry,
1205 LPCSTR def_val, LPSTR buffer,
1206 UINT16 len, LPCSTR filename )
1208 return GetPrivateProfileStringA(section,entry,def_val,buffer,len,filename);
1211 /***********************************************************************
1212 * GetPrivateProfileString32A (KERNEL32.255)
1214 INT WINAPI GetPrivateProfileStringA( LPCSTR section, LPCSTR entry,
1215 LPCSTR def_val, LPSTR buffer,
1216 UINT len, LPCSTR filename )
1218 int ret;
1220 if (!filename)
1221 filename = "win.ini";
1223 EnterCriticalSection( &PROFILE_CritSect );
1225 if (PROFILE_Open( filename )) {
1226 ret = PROFILE_GetString( section, entry, def_val, buffer, len );
1227 } else {
1228 lstrcpynA( buffer, def_val, len );
1229 ret = strlen( buffer );
1232 LeaveCriticalSection( &PROFILE_CritSect );
1234 return ret;
1237 /***********************************************************************
1238 * GetPrivateProfileString32W (KERNEL32.256)
1240 INT WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1241 LPCWSTR def_val, LPWSTR buffer,
1242 UINT len, LPCWSTR filename )
1244 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1245 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1246 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1247 LPSTR def_valA = HEAP_strdupWtoA( GetProcessHeap(), 0, def_val );
1248 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1249 INT ret = GetPrivateProfileStringA( sectionA, entryA, def_valA,
1250 bufferA, len, filenameA );
1251 lstrcpynAtoW( buffer, bufferA, len );
1252 HeapFree( GetProcessHeap(), 0, sectionA );
1253 HeapFree( GetProcessHeap(), 0, entryA );
1254 HeapFree( GetProcessHeap(), 0, filenameA );
1255 HeapFree( GetProcessHeap(), 0, def_valA );
1256 HeapFree( GetProcessHeap(), 0, bufferA);
1257 return ret;
1260 /***********************************************************************
1261 * GetPrivateProfileSection16 (KERNEL.418)
1263 INT16 WINAPI GetPrivateProfileSection16( LPCSTR section, LPSTR buffer,
1264 UINT16 len, LPCSTR filename )
1266 return GetPrivateProfileSectionA( section, buffer, len, filename );
1269 /***********************************************************************
1270 * GetPrivateProfileSection32A (KERNEL32.255)
1272 INT WINAPI GetPrivateProfileSectionA( LPCSTR section, LPSTR buffer,
1273 DWORD len, LPCSTR filename )
1275 int ret = 0;
1277 EnterCriticalSection( &PROFILE_CritSect );
1279 if (PROFILE_Open( filename ))
1280 ret = PROFILE_GetSection(CurProfile->section, section, buffer, len,
1281 FALSE, TRUE);
1283 LeaveCriticalSection( &PROFILE_CritSect );
1285 return ret;
1288 /***********************************************************************
1289 * GetPrivateProfileSection32W (KERNEL32.256)
1292 INT WINAPI GetPrivateProfileSectionW (LPCWSTR section, LPWSTR buffer,
1293 DWORD len, LPCWSTR filename )
1296 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1297 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1298 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1299 INT ret = GetPrivateProfileSectionA( sectionA, bufferA, len,
1300 filenameA );
1301 MultiByteToWideChar(CP_ACP,0,bufferA,ret,buffer,len);
1302 HeapFree( GetProcessHeap(), 0, sectionA );
1303 HeapFree( GetProcessHeap(), 0, filenameA );
1304 HeapFree( GetProcessHeap(), 0, bufferA);
1305 return ret;
1308 /***********************************************************************
1309 * GetProfileSection16 (KERNEL.419)
1311 INT16 WINAPI GetProfileSection16( LPCSTR section, LPSTR buffer, UINT16 len )
1313 return GetPrivateProfileSection16( section, buffer, len, "win.ini" );
1316 /***********************************************************************
1317 * GetProfileSection32A (KERNEL32.268)
1319 INT WINAPI GetProfileSectionA( LPCSTR section, LPSTR buffer, DWORD len )
1321 return GetPrivateProfileSectionA( section, buffer, len, "win.ini" );
1324 /***********************************************************************
1325 * GetProfileSection32W (KERNEL32)
1327 INT WINAPI GetProfileSectionW( LPCWSTR section, LPWSTR buffer, DWORD len )
1329 return GetPrivateProfileSectionW( section, buffer, len, wininiW );
1333 /***********************************************************************
1334 * WritePrivateProfileString16 (KERNEL.129)
1336 BOOL16 WINAPI WritePrivateProfileString16( LPCSTR section, LPCSTR entry,
1337 LPCSTR string, LPCSTR filename )
1339 return WritePrivateProfileStringA(section,entry,string,filename);
1342 /***********************************************************************
1343 * WritePrivateProfileString32A (KERNEL32.582)
1345 BOOL WINAPI WritePrivateProfileStringA( LPCSTR section, LPCSTR entry,
1346 LPCSTR string, LPCSTR filename )
1348 BOOL ret = FALSE;
1350 EnterCriticalSection( &PROFILE_CritSect );
1352 if (PROFILE_Open( filename ))
1354 if (!section && !entry && !string)
1355 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1356 else
1357 ret = PROFILE_SetString( section, entry, string );
1360 LeaveCriticalSection( &PROFILE_CritSect );
1361 return ret;
1364 /***********************************************************************
1365 * WritePrivateProfileString32W (KERNEL32.583)
1367 BOOL WINAPI WritePrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1368 LPCWSTR string, LPCWSTR filename )
1370 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1371 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1372 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1373 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1374 BOOL res = WritePrivateProfileStringA( sectionA, entryA,
1375 stringA, filenameA );
1376 HeapFree( GetProcessHeap(), 0, sectionA );
1377 HeapFree( GetProcessHeap(), 0, entryA );
1378 HeapFree( GetProcessHeap(), 0, stringA );
1379 HeapFree( GetProcessHeap(), 0, filenameA );
1380 return res;
1383 /***********************************************************************
1384 * WritePrivateProfileSection16 (KERNEL.416)
1386 BOOL16 WINAPI WritePrivateProfileSection16( LPCSTR section,
1387 LPCSTR string, LPCSTR filename )
1389 return WritePrivateProfileSectionA( section, string, filename );
1392 /***********************************************************************
1393 * WritePrivateProfileSectionA (KERNEL32)
1395 BOOL WINAPI WritePrivateProfileSectionA( LPCSTR section,
1396 LPCSTR string, LPCSTR filename )
1398 BOOL ret = FALSE;
1399 LPSTR p ;
1401 EnterCriticalSection( &PROFILE_CritSect );
1403 if (PROFILE_Open( filename )) {
1404 if (!section && !string && !filename)
1405 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1406 else {
1407 while(*string){
1408 LPSTR buf=HEAP_strdupA( GetProcessHeap(), 0, string );
1409 if((p=strchr( buf, '='))){
1410 *p='\0';
1411 ret = PROFILE_SetString( section, buf, p+1 );
1414 HeapFree( GetProcessHeap(), 0, buf );
1415 string += strlen(string)+1;
1421 LeaveCriticalSection( &PROFILE_CritSect );
1422 return ret;
1425 /***********************************************************************
1426 * WritePrivateProfileSection32W (KERNEL32)
1428 BOOL WINAPI WritePrivateProfileSectionW( LPCWSTR section,
1429 LPCWSTR string, LPCWSTR filename)
1432 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1433 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1434 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1435 BOOL res = WritePrivateProfileSectionA( sectionA, stringA, filenameA );
1436 HeapFree( GetProcessHeap(), 0, sectionA );
1437 HeapFree( GetProcessHeap(), 0, stringA );
1438 HeapFree( GetProcessHeap(), 0, filenameA );
1439 return res;
1442 /***********************************************************************
1443 * WriteProfileSection16 (KERNEL.417)
1445 BOOL16 WINAPI WriteProfileSection16( LPCSTR section, LPCSTR keys_n_values)
1447 return WritePrivateProfileSection16( section, keys_n_values, "win.ini");
1450 /***********************************************************************
1451 * WriteProfileSection32A (KERNEL32.747)
1453 BOOL WINAPI WriteProfileSectionA( LPCSTR section, LPCSTR keys_n_values)
1456 return WritePrivateProfileSectionA( section, keys_n_values, "win.ini");
1459 /***********************************************************************
1460 * WriteProfileSection32W (KERNEL32.748)
1462 BOOL WINAPI WriteProfileSectionW( LPCWSTR section, LPCWSTR keys_n_values)
1464 return (WritePrivateProfileSectionW (section,keys_n_values, wininiW));
1467 /***********************************************************************
1468 * GetPrivateProfileSectionNames16 (KERNEL.143)
1470 WORD WINAPI GetPrivateProfileSectionNames16( LPSTR buffer, WORD size,
1471 LPCSTR filename )
1473 WORD ret = 0;
1475 EnterCriticalSection( &PROFILE_CritSect );
1477 if (PROFILE_Open( filename ))
1478 ret = PROFILE_GetSectionNames(buffer, size);
1480 LeaveCriticalSection( &PROFILE_CritSect );
1482 return ret;
1486 /***********************************************************************
1487 * GetProfileSectionNames16 (KERNEL.142)
1489 WORD WINAPI GetProfileSectionNames16( LPSTR buffer, WORD size)
1492 return (GetPrivateProfileSectionNames16 (buffer,size,"win.ini"));
1496 /***********************************************************************
1497 * GetPrivateProfileSectionNames32A (KERNEL32.365)
1499 DWORD WINAPI GetPrivateProfileSectionNamesA( LPSTR buffer, DWORD size,
1500 LPCSTR filename)
1503 return (GetPrivateProfileSectionNames16 (buffer,size,filename));
1507 /***********************************************************************
1508 * GetPrivateProfileSectionNames32W (KERNEL32.366)
1510 DWORD WINAPI GetPrivateProfileSectionNamesW( LPWSTR buffer, DWORD size,
1511 LPCWSTR filename)
1514 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1515 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, size);
1517 INT ret = GetPrivateProfileSectionNames16 (bufferA, size, filenameA);
1518 lstrcpynAtoW( buffer, bufferA, size);
1519 HeapFree( GetProcessHeap(), 0, bufferA);
1520 HeapFree( GetProcessHeap(), 0, filenameA );
1522 return ret;
1525 /***********************************************************************
1526 * GetPrivateProfileStruct16 (KERNEL.407)
1528 BOOL16 WINAPI GetPrivateProfileStruct16(LPCSTR section, LPCSTR key,
1529 LPVOID buf, UINT16 len, LPCSTR filename)
1531 return GetPrivateProfileStructA( section, key, buf, len, filename );
1534 /***********************************************************************
1535 * GetPrivateProfileStruct32A (KERNEL32.370)
1537 * Should match Win95's behaviour pretty much
1539 BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key,
1540 LPVOID buf, UINT len, LPCSTR filename)
1542 BOOL ret = FALSE;
1544 EnterCriticalSection( &PROFILE_CritSect );
1546 if (PROFILE_Open( filename )) {
1547 PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE);
1548 if (k) {
1549 TRACE("value (at %p): '%s'\n", k->value, k->value);
1550 if (((strlen(k->value) - 2) / 2) == len)
1552 LPSTR end, p;
1553 BOOL valid = TRUE;
1554 CHAR c;
1555 DWORD chksum = 0;
1557 end = k->value + strlen(k->value); /* -> '\0' */
1558 /* check for invalid chars in ASCII coded hex string */
1559 for (p=k->value; p < end; p++)
1561 if (!isxdigit(*p))
1563 WARN("invalid char '%c' in file '%s'->'[%s]'->'%s' !\n",
1564 *p, filename, section, key);
1565 valid = FALSE;
1566 break;
1569 if (valid)
1571 BOOL highnibble = TRUE;
1572 BYTE b = 0, val;
1573 LPBYTE binbuf = (LPBYTE)buf;
1575 end -= 2; /* don't include checksum in output data */
1576 /* translate ASCII hex format into binary data */
1577 for (p=k->value; p < end; p++)
1579 c = toupper(*p);
1580 val = (c > '9') ?
1581 (c - 'A' + 10) : (c - '0');
1583 if (highnibble)
1584 b = val << 4;
1585 else
1587 b += val;
1588 *binbuf++ = b; /* feed binary data into output */
1589 chksum += b; /* calculate checksum */
1591 highnibble ^= 1; /* toggle */
1593 /* retrieve stored checksum value */
1594 c = toupper(*p++);
1595 b = ( (c > '9') ? (c - 'A' + 10) : (c - '0') ) << 4;
1596 c = toupper(*p);
1597 b += (c > '9') ? (c - 'A' + 10) : (c - '0');
1598 if (b == (chksum & 0xff)) /* checksums match ? */
1599 ret = TRUE;
1604 LeaveCriticalSection( &PROFILE_CritSect );
1606 return ret;
1609 /***********************************************************************
1610 * GetPrivateProfileStruct32W (KERNEL32.543)
1612 BOOL WINAPI GetPrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1613 LPVOID buffer, UINT len, LPCWSTR filename)
1615 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1616 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1617 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1618 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1620 INT ret = GetPrivateProfileStructA( sectionA, keyA, bufferA,
1621 len, filenameA );
1622 lstrcpynAtoW( buffer, bufferA, len );
1623 HeapFree( GetProcessHeap(), 0, bufferA);
1624 HeapFree( GetProcessHeap(), 0, sectionA );
1625 HeapFree( GetProcessHeap(), 0, keyA );
1626 HeapFree( GetProcessHeap(), 0, filenameA );
1628 return ret;
1633 /***********************************************************************
1634 * WritePrivateProfileStruct16 (KERNEL.406)
1636 BOOL16 WINAPI WritePrivateProfileStruct16 (LPCSTR section, LPCSTR key,
1637 LPVOID buf, UINT16 bufsize, LPCSTR filename)
1639 return WritePrivateProfileStructA( section, key, buf, bufsize, filename );
1642 /***********************************************************************
1643 * WritePrivateProfileStruct32A (KERNEL32.744)
1645 BOOL WINAPI WritePrivateProfileStructA (LPCSTR section, LPCSTR key,
1646 LPVOID buf, UINT bufsize, LPCSTR filename)
1648 BOOL ret = FALSE;
1649 LPBYTE binbuf;
1650 LPSTR outstring, p;
1651 DWORD sum = 0;
1653 if (!section && !key && !buf) /* flush the cache */
1654 return WritePrivateProfileStringA( NULL, NULL, NULL, filename );
1656 /* allocate string buffer for hex chars + checksum hex char + '\0' */
1657 outstring = HeapAlloc( GetProcessHeap(), 0, bufsize*2 + 2 + 1);
1658 p = outstring;
1659 for (binbuf = (LPBYTE)buf; binbuf < (LPBYTE)buf+bufsize; binbuf++) {
1660 *p++ = hex[*binbuf >> 4];
1661 *p++ = hex[*binbuf & 0xf];
1662 sum += *binbuf;
1664 /* checksum is sum & 0xff */
1665 *p++ = hex[(sum & 0xf0) >> 4];
1666 *p++ = hex[sum & 0xf];
1667 *p++ = '\0';
1669 EnterCriticalSection( &PROFILE_CritSect );
1671 if (PROFILE_Open( filename ))
1672 ret = PROFILE_SetString( section, key, outstring );
1674 LeaveCriticalSection( &PROFILE_CritSect );
1676 HeapFree( GetProcessHeap(), 0, outstring );
1678 return ret;
1681 /***********************************************************************
1682 * WritePrivateProfileStruct32W (KERNEL32.544)
1684 BOOL WINAPI WritePrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1685 LPVOID buf, UINT bufsize, LPCWSTR filename)
1687 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1688 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1689 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1690 INT ret = WritePrivateProfileStructA( sectionA, keyA, buf, bufsize,
1691 filenameA );
1692 HeapFree( GetProcessHeap(), 0, sectionA );
1693 HeapFree( GetProcessHeap(), 0, keyA );
1694 HeapFree( GetProcessHeap(), 0, filenameA );
1696 return ret;
1700 /***********************************************************************
1701 * WriteOutProfiles (KERNEL.315)
1703 void WINAPI WriteOutProfiles16(void)
1705 EnterCriticalSection( &PROFILE_CritSect );
1706 PROFILE_FlushFile();
1707 LeaveCriticalSection( &PROFILE_CritSect );
1710 /***********************************************************************
1711 * CloseProfileUserMapping (KERNEL.138)
1713 BOOL WINAPI CloseProfileUserMapping(void) {
1714 FIXME("(), stub!\n");
1715 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1716 return FALSE;