Fixed debug formatting.
[wine/multimedia.git] / files / profile.c
blobbcac7883b83791e6cc4da713f09a3da8d4a19bbf
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 (key_name && !(key_name[0]))
771 /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227*/
772 return 0;
773 if (section && section[0])
774 return PROFILE_GetSection(CurProfile->section, section, buffer, len,
775 FALSE, FALSE);
776 /* undocumented; both section and key_name are NULL */
777 return PROFILE_GetSectionNames(buffer, len);
781 /***********************************************************************
782 * PROFILE_SetString
784 * Set a profile string.
786 static BOOL PROFILE_SetString( LPCSTR section_name, LPCSTR key_name,
787 LPCSTR value )
789 if (!key_name) /* Delete a whole section */
791 TRACE("('%s')\n", section_name);
792 CurProfile->changed |= PROFILE_DeleteSection( &CurProfile->section,
793 section_name );
794 return TRUE; /* Even if PROFILE_DeleteSection() has failed,
795 this is not an error on application's level.*/
797 else if (!value) /* Delete a key */
799 TRACE("('%s','%s')\n",
800 section_name, key_name );
801 CurProfile->changed |= PROFILE_DeleteKey( &CurProfile->section,
802 section_name, key_name );
803 return TRUE; /* same error handling as above */
805 else /* Set the key value */
807 PROFILEKEY *key = PROFILE_Find( &CurProfile->section, section_name,
808 key_name, TRUE );
809 TRACE("('%s','%s','%s'): \n",
810 section_name, key_name, value );
811 if (!key) return FALSE;
812 if (key->value)
814 if (!strcmp( key->value, value ))
816 TRACE(" no change needed\n" );
817 return TRUE; /* No change needed */
819 TRACE(" replacing '%s'\n", key->value );
820 HeapFree( GetProcessHeap(), 0, key->value );
822 else TRACE(" creating key\n" );
823 key->value = HEAP_strdupA( GetProcessHeap(), 0, value );
824 CurProfile->changed = TRUE;
826 return TRUE;
830 /***********************************************************************
831 * PROFILE_GetWineIniString
833 * Get a config string from the wine.ini file.
835 int PROFILE_GetWineIniString( const char *section, const char *key_name,
836 const char *def, char *buffer, int len )
838 char tmp[PROFILE_MAX_LINE_LEN];
839 HKEY hkey;
840 DWORD err;
842 if (!(err = RegOpenKeyA( wine_profile_key, section, &hkey )))
844 DWORD type;
845 DWORD count = sizeof(tmp);
846 err = RegQueryValueExA( hkey, key_name, 0, &type, tmp, &count );
847 RegCloseKey( hkey );
849 PROFILE_CopyEntry( buffer, err ? def : tmp, len, TRUE );
850 TRACE( "('%s','%s','%s'): returning '%s'\n", section, key_name, def, buffer );
851 return strlen(buffer);
855 /***********************************************************************
856 * PROFILE_EnumWineIniString
858 * Get a config string from the wine.ini file.
860 BOOL PROFILE_EnumWineIniString( const char *section, int index,
861 char *name, int name_len, char *buffer, int len )
863 char tmp[PROFILE_MAX_LINE_LEN];
864 HKEY hkey;
865 DWORD err, type;
866 DWORD count = sizeof(tmp);
868 if (RegOpenKeyA( wine_profile_key, section, &hkey )) return FALSE;
869 err = RegEnumValueA( hkey, index, name, (DWORD*)&name_len, NULL, &type, tmp, &count );
870 RegCloseKey( hkey );
871 if (!err)
873 PROFILE_CopyEntry( buffer, tmp, len, TRUE );
874 TRACE( "('%s',%d): returning '%s'='%s'\n", section, index, name, buffer );
876 return !err;
880 /***********************************************************************
881 * PROFILE_GetWineIniInt
883 * Get a config integer from the wine.ini file.
885 int PROFILE_GetWineIniInt( const char *section, const char *key_name, int def )
887 char buffer[20];
888 char *p;
889 long result;
891 PROFILE_GetWineIniString( section, key_name, "", buffer, sizeof(buffer) );
892 if (!buffer[0]) return def;
893 result = strtol( buffer, &p, 0 );
894 return (p == buffer) ? 0 /* No digits at all */ : (int)result;
898 /******************************************************************************
900 * int PROFILE_GetWineIniBool(
901 * char const *section,
902 * char const *key_name,
903 * int def )
905 * Reads a boolean value from the wine.ini file. This function attempts to
906 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
907 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
908 * true. Anything else results in the return of the default value.
910 * This function uses 1 to indicate true, and 0 for false. You can check
911 * for existence by setting def to something other than 0 or 1 and
912 * examining the return value.
914 int PROFILE_GetWineIniBool(
915 char const *section,
916 char const *key_name,
917 int def )
919 char key_value[2];
920 int retval;
922 PROFILE_GetWineIniString(section, key_name, "~", key_value, 2);
924 switch(key_value[0]) {
925 case 'n':
926 case 'N':
927 case 'f':
928 case 'F':
929 case '0':
930 retval = 0;
931 break;
933 case 'y':
934 case 'Y':
935 case 't':
936 case 'T':
937 case '1':
938 retval = 1;
939 break;
941 default:
942 retval = def;
945 TRACE("(\"%s\", \"%s\", %s), "
946 "[%c], ret %s.\n", section, key_name,
947 def ? "TRUE" : "FALSE", key_value[0],
948 retval ? "TRUE" : "FALSE");
950 return retval;
954 /***********************************************************************
955 * PROFILE_LoadWineIni
957 * Load the wine.ini file.
959 int PROFILE_LoadWineIni(void)
961 char buffer[MAX_PATHNAME_LEN];
962 const char *p;
963 FILE *f;
964 HKEY hKeySW;
966 /* make sure HKLM\\Software exists as non-volatile key */
967 if (RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software", &hKeySW ))
969 ERR("Cannot create config registry key\n" );
970 return 0;
972 RegCloseKey( hKeySW );
973 if (RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config", 0, NULL,
974 REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &wine_profile_key, NULL ))
976 ERR("Cannot create config registry key\n" );
977 return 0;
979 wine_profile_key = ConvertToGlobalHandle( wine_profile_key );
981 InitializeCriticalSection( &PROFILE_CritSect );
982 MakeCriticalSectionGlobal( &PROFILE_CritSect );
984 if (!CLIENT_IsBootThread()) return 1; /* already loaded */
986 if ( (Options.configFileName!=NULL) && (f = fopen(Options.configFileName, "r")) )
988 /* Open -config specified file */
989 lstrcpynA(PROFILE_WineIniUsed,Options.configFileName,MAX_PATHNAME_LEN);
990 goto found;
993 if ( (p = getenv( "WINE_INI" )) && (f = fopen( p, "r" )) )
995 lstrcpynA(PROFILE_WineIniUsed,p,MAX_PATHNAME_LEN);
996 goto found;
998 if ((p = getenv( "HOME" )) != NULL)
1000 lstrcpynA(buffer, p, MAX_PATHNAME_LEN - sizeof(PROFILE_WineIniName));
1001 strcat( buffer, PROFILE_WineIniName );
1002 if ((f = fopen( buffer, "r" )) != NULL)
1004 lstrcpynA(PROFILE_WineIniUsed,buffer,MAX_PATHNAME_LEN);
1005 goto found;
1008 else WARN("could not get $HOME value for config file.\n" );
1010 /* Try global file */
1012 if ((f = fopen( WINE_INI_GLOBAL, "r" )) != NULL)
1014 lstrcpynA(PROFILE_WineIniUsed,WINE_INI_GLOBAL,MAX_PATHNAME_LEN);
1015 goto found;
1017 MESSAGE( "Can't open configuration file %s or $HOME%s\n",
1018 WINE_INI_GLOBAL, PROFILE_WineIniName );
1019 return 0;
1021 found:
1022 PROFILE_RegistryLoad( wine_profile_key, f );
1023 fclose( f );
1024 return 1;
1028 /***********************************************************************
1029 * PROFILE_UsageWineIni
1031 * Explain the wine.ini file to those who don't read documentation.
1032 * Keep below one screenful in length so that error messages above are
1033 * noticed.
1035 void PROFILE_UsageWineIni(void)
1037 MESSAGE("Perhaps you have not properly edited or created "
1038 "your Wine configuration file.\n");
1039 MESSAGE("This is either %s or $HOME%s\n",WINE_INI_GLOBAL,PROFILE_WineIniName);
1040 MESSAGE(" or it is determined by the -config option or from\n"
1041 " the WINE_INI environment variable.\n");
1042 if (*PROFILE_WineIniUsed)
1043 MESSAGE("Wine has used %s as configuration file.\n", PROFILE_WineIniUsed);
1044 /* RTFM, so to say */
1047 /***********************************************************************
1048 * PROFILE_GetStringItem
1050 * Convenience function that turns a string 'xxx, yyy, zzz' into
1051 * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
1053 char* PROFILE_GetStringItem( char* start )
1055 char* lpchX, *lpch;
1057 for (lpchX = start, lpch = NULL; *lpchX != '\0'; lpchX++ )
1059 if( *lpchX == ',' )
1061 if( lpch ) *lpch = '\0'; else *lpchX = '\0';
1062 while( *(++lpchX) )
1063 if( !PROFILE_isspace(*lpchX) ) return lpchX;
1065 else if( PROFILE_isspace( *lpchX ) && !lpch ) lpch = lpchX;
1066 else lpch = NULL;
1068 if( lpch ) *lpch = '\0';
1069 return NULL;
1072 /********************* API functions **********************************/
1074 /***********************************************************************
1075 * GetProfileInt16 (KERNEL.57)
1077 UINT16 WINAPI GetProfileInt16( LPCSTR section, LPCSTR entry, INT16 def_val )
1079 return GetPrivateProfileInt16( section, entry, def_val, "win.ini" );
1083 /***********************************************************************
1084 * GetProfileInt32A (KERNEL32.264)
1086 UINT WINAPI GetProfileIntA( LPCSTR section, LPCSTR entry, INT def_val )
1088 return GetPrivateProfileIntA( section, entry, def_val, "win.ini" );
1091 /***********************************************************************
1092 * GetProfileInt32W (KERNEL32.264)
1094 UINT WINAPI GetProfileIntW( LPCWSTR section, LPCWSTR entry, INT def_val )
1096 return GetPrivateProfileIntW( section, entry, def_val, wininiW );
1099 /***********************************************************************
1100 * GetProfileString16 (KERNEL.58)
1102 INT16 WINAPI GetProfileString16( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1103 LPSTR buffer, UINT16 len )
1105 return GetPrivateProfileString16( section, entry, def_val,
1106 buffer, len, "win.ini" );
1109 /***********************************************************************
1110 * GetProfileString32A (KERNEL32.268)
1112 INT WINAPI GetProfileStringA( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1113 LPSTR buffer, UINT len )
1115 return GetPrivateProfileStringA( section, entry, def_val,
1116 buffer, len, "win.ini" );
1119 /***********************************************************************
1120 * GetProfileString32W (KERNEL32.269)
1122 INT WINAPI GetProfileStringW( LPCWSTR section, LPCWSTR entry,
1123 LPCWSTR def_val, LPWSTR buffer, UINT len )
1125 return GetPrivateProfileStringW( section, entry, def_val,
1126 buffer, len, wininiW );
1129 /***********************************************************************
1130 * WriteProfileString16 (KERNEL.59)
1132 BOOL16 WINAPI WriteProfileString16( LPCSTR section, LPCSTR entry,
1133 LPCSTR string )
1135 return WritePrivateProfileString16( section, entry, string, "win.ini" );
1138 /***********************************************************************
1139 * WriteProfileString32A (KERNEL32.587)
1141 BOOL WINAPI WriteProfileStringA( LPCSTR section, LPCSTR entry,
1142 LPCSTR string )
1144 return WritePrivateProfileStringA( section, entry, string, "win.ini" );
1147 /***********************************************************************
1148 * WriteProfileString32W (KERNEL32.588)
1150 BOOL WINAPI WriteProfileStringW( LPCWSTR section, LPCWSTR entry,
1151 LPCWSTR string )
1153 return WritePrivateProfileStringW( section, entry, string, wininiW );
1157 /***********************************************************************
1158 * GetPrivateProfileInt16 (KERNEL.127)
1160 UINT16 WINAPI GetPrivateProfileInt16( LPCSTR section, LPCSTR entry,
1161 INT16 def_val, LPCSTR filename )
1163 long result=(long)GetPrivateProfileIntA(section,entry,def_val,filename);
1165 if (result > 65535) return 65535;
1166 if (result >= 0) return (UINT16)result;
1167 if (result < -32768) return -32768;
1168 return (UINT16)(INT16)result;
1171 /***********************************************************************
1172 * GetPrivateProfileInt32A (KERNEL32.251)
1174 UINT WINAPI GetPrivateProfileIntA( LPCSTR section, LPCSTR entry,
1175 INT def_val, LPCSTR filename )
1177 char buffer[20];
1178 char *p;
1179 long result;
1181 GetPrivateProfileStringA( section, entry, "",
1182 buffer, sizeof(buffer), filename );
1183 if (!buffer[0]) return (UINT)def_val;
1184 result = strtol( buffer, &p, 0 );
1185 if (p == buffer) return 0; /* No digits at all */
1186 return (UINT)result;
1189 /***********************************************************************
1190 * GetPrivateProfileInt32W (KERNEL32.252)
1192 UINT WINAPI GetPrivateProfileIntW( LPCWSTR section, LPCWSTR entry,
1193 INT def_val, LPCWSTR filename )
1195 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1196 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1197 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1198 UINT res = GetPrivateProfileIntA(sectionA, entryA, def_val, filenameA);
1199 HeapFree( GetProcessHeap(), 0, sectionA );
1200 HeapFree( GetProcessHeap(), 0, filenameA );
1201 HeapFree( GetProcessHeap(), 0, entryA );
1202 return res;
1205 /***********************************************************************
1206 * GetPrivateProfileString16 (KERNEL.128)
1208 INT16 WINAPI GetPrivateProfileString16( LPCSTR section, LPCSTR entry,
1209 LPCSTR def_val, LPSTR buffer,
1210 UINT16 len, LPCSTR filename )
1212 return GetPrivateProfileStringA(section,entry,def_val,buffer,len,filename);
1215 /***********************************************************************
1216 * GetPrivateProfileString32A (KERNEL32.255)
1218 INT WINAPI GetPrivateProfileStringA( LPCSTR section, LPCSTR entry,
1219 LPCSTR def_val, LPSTR buffer,
1220 UINT len, LPCSTR filename )
1222 int ret;
1224 if (!filename)
1225 filename = "win.ini";
1227 EnterCriticalSection( &PROFILE_CritSect );
1229 if (PROFILE_Open( filename )) {
1230 ret = PROFILE_GetString( section, entry, def_val, buffer, len );
1231 } else {
1232 lstrcpynA( buffer, def_val, len );
1233 ret = strlen( buffer );
1236 LeaveCriticalSection( &PROFILE_CritSect );
1238 return ret;
1241 /***********************************************************************
1242 * GetPrivateProfileString32W (KERNEL32.256)
1244 INT WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1245 LPCWSTR def_val, LPWSTR buffer,
1246 UINT len, LPCWSTR filename )
1248 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1249 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1250 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1251 LPSTR def_valA = HEAP_strdupWtoA( GetProcessHeap(), 0, def_val );
1252 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1253 INT ret = GetPrivateProfileStringA( sectionA, entryA, def_valA,
1254 bufferA, len, filenameA );
1255 lstrcpynAtoW( buffer, bufferA, len );
1256 HeapFree( GetProcessHeap(), 0, sectionA );
1257 HeapFree( GetProcessHeap(), 0, entryA );
1258 HeapFree( GetProcessHeap(), 0, filenameA );
1259 HeapFree( GetProcessHeap(), 0, def_valA );
1260 HeapFree( GetProcessHeap(), 0, bufferA);
1261 return ret;
1264 /***********************************************************************
1265 * GetPrivateProfileSection16 (KERNEL.418)
1267 INT16 WINAPI GetPrivateProfileSection16( LPCSTR section, LPSTR buffer,
1268 UINT16 len, LPCSTR filename )
1270 return GetPrivateProfileSectionA( section, buffer, len, filename );
1273 /***********************************************************************
1274 * GetPrivateProfileSection32A (KERNEL32.255)
1276 INT WINAPI GetPrivateProfileSectionA( LPCSTR section, LPSTR buffer,
1277 DWORD len, LPCSTR filename )
1279 int ret = 0;
1281 EnterCriticalSection( &PROFILE_CritSect );
1283 if (PROFILE_Open( filename ))
1284 ret = PROFILE_GetSection(CurProfile->section, section, buffer, len,
1285 FALSE, TRUE);
1287 LeaveCriticalSection( &PROFILE_CritSect );
1289 return ret;
1292 /***********************************************************************
1293 * GetPrivateProfileSection32W (KERNEL32.256)
1296 INT WINAPI GetPrivateProfileSectionW (LPCWSTR section, LPWSTR buffer,
1297 DWORD len, LPCWSTR filename )
1300 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1301 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1302 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1303 INT ret = GetPrivateProfileSectionA( sectionA, bufferA, len,
1304 filenameA );
1305 MultiByteToWideChar(CP_ACP,0,bufferA,ret,buffer,len);
1306 HeapFree( GetProcessHeap(), 0, sectionA );
1307 HeapFree( GetProcessHeap(), 0, filenameA );
1308 HeapFree( GetProcessHeap(), 0, bufferA);
1309 return ret;
1312 /***********************************************************************
1313 * GetProfileSection16 (KERNEL.419)
1315 INT16 WINAPI GetProfileSection16( LPCSTR section, LPSTR buffer, UINT16 len )
1317 return GetPrivateProfileSection16( section, buffer, len, "win.ini" );
1320 /***********************************************************************
1321 * GetProfileSection32A (KERNEL32.268)
1323 INT WINAPI GetProfileSectionA( LPCSTR section, LPSTR buffer, DWORD len )
1325 return GetPrivateProfileSectionA( section, buffer, len, "win.ini" );
1328 /***********************************************************************
1329 * GetProfileSection32W (KERNEL32)
1331 INT WINAPI GetProfileSectionW( LPCWSTR section, LPWSTR buffer, DWORD len )
1333 return GetPrivateProfileSectionW( section, buffer, len, wininiW );
1337 /***********************************************************************
1338 * WritePrivateProfileString16 (KERNEL.129)
1340 BOOL16 WINAPI WritePrivateProfileString16( LPCSTR section, LPCSTR entry,
1341 LPCSTR string, LPCSTR filename )
1343 return WritePrivateProfileStringA(section,entry,string,filename);
1346 /***********************************************************************
1347 * WritePrivateProfileString32A (KERNEL32.582)
1349 BOOL WINAPI WritePrivateProfileStringA( LPCSTR section, LPCSTR entry,
1350 LPCSTR string, LPCSTR filename )
1352 BOOL ret = FALSE;
1354 EnterCriticalSection( &PROFILE_CritSect );
1356 if (PROFILE_Open( filename ))
1358 if (!section && !entry && !string)
1359 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1360 else
1361 ret = PROFILE_SetString( section, entry, string );
1364 LeaveCriticalSection( &PROFILE_CritSect );
1365 return ret;
1368 /***********************************************************************
1369 * WritePrivateProfileString32W (KERNEL32.583)
1371 BOOL WINAPI WritePrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1372 LPCWSTR string, LPCWSTR filename )
1374 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1375 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1376 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1377 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1378 BOOL res = WritePrivateProfileStringA( sectionA, entryA,
1379 stringA, filenameA );
1380 HeapFree( GetProcessHeap(), 0, sectionA );
1381 HeapFree( GetProcessHeap(), 0, entryA );
1382 HeapFree( GetProcessHeap(), 0, stringA );
1383 HeapFree( GetProcessHeap(), 0, filenameA );
1384 return res;
1387 /***********************************************************************
1388 * WritePrivateProfileSection16 (KERNEL.416)
1390 BOOL16 WINAPI WritePrivateProfileSection16( LPCSTR section,
1391 LPCSTR string, LPCSTR filename )
1393 return WritePrivateProfileSectionA( section, string, filename );
1396 /***********************************************************************
1397 * WritePrivateProfileSectionA (KERNEL32)
1399 BOOL WINAPI WritePrivateProfileSectionA( LPCSTR section,
1400 LPCSTR string, LPCSTR filename )
1402 BOOL ret = FALSE;
1403 LPSTR p ;
1405 EnterCriticalSection( &PROFILE_CritSect );
1407 if (PROFILE_Open( filename )) {
1408 if (!section && !string && !filename)
1409 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1410 else {
1411 while(*string){
1412 LPSTR buf=HEAP_strdupA( GetProcessHeap(), 0, string );
1413 if((p=strchr( buf, '='))){
1414 *p='\0';
1415 ret = PROFILE_SetString( section, buf, p+1 );
1418 HeapFree( GetProcessHeap(), 0, buf );
1419 string += strlen(string)+1;
1425 LeaveCriticalSection( &PROFILE_CritSect );
1426 return ret;
1429 /***********************************************************************
1430 * WritePrivateProfileSection32W (KERNEL32)
1432 BOOL WINAPI WritePrivateProfileSectionW( LPCWSTR section,
1433 LPCWSTR string, LPCWSTR filename)
1436 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1437 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1438 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1439 BOOL res = WritePrivateProfileSectionA( sectionA, stringA, filenameA );
1440 HeapFree( GetProcessHeap(), 0, sectionA );
1441 HeapFree( GetProcessHeap(), 0, stringA );
1442 HeapFree( GetProcessHeap(), 0, filenameA );
1443 return res;
1446 /***********************************************************************
1447 * WriteProfileSection16 (KERNEL.417)
1449 BOOL16 WINAPI WriteProfileSection16( LPCSTR section, LPCSTR keys_n_values)
1451 return WritePrivateProfileSection16( section, keys_n_values, "win.ini");
1454 /***********************************************************************
1455 * WriteProfileSection32A (KERNEL32.747)
1457 BOOL WINAPI WriteProfileSectionA( LPCSTR section, LPCSTR keys_n_values)
1460 return WritePrivateProfileSectionA( section, keys_n_values, "win.ini");
1463 /***********************************************************************
1464 * WriteProfileSection32W (KERNEL32.748)
1466 BOOL WINAPI WriteProfileSectionW( LPCWSTR section, LPCWSTR keys_n_values)
1468 return (WritePrivateProfileSectionW (section,keys_n_values, wininiW));
1471 /***********************************************************************
1472 * GetPrivateProfileSectionNames16 (KERNEL.143)
1474 WORD WINAPI GetPrivateProfileSectionNames16( LPSTR buffer, WORD size,
1475 LPCSTR filename )
1477 WORD ret = 0;
1479 EnterCriticalSection( &PROFILE_CritSect );
1481 if (PROFILE_Open( filename ))
1482 ret = PROFILE_GetSectionNames(buffer, size);
1484 LeaveCriticalSection( &PROFILE_CritSect );
1486 return ret;
1490 /***********************************************************************
1491 * GetProfileSectionNames16 (KERNEL.142)
1493 WORD WINAPI GetProfileSectionNames16( LPSTR buffer, WORD size)
1496 return (GetPrivateProfileSectionNames16 (buffer,size,"win.ini"));
1500 /***********************************************************************
1501 * GetPrivateProfileSectionNames32A (KERNEL32.365)
1503 DWORD WINAPI GetPrivateProfileSectionNamesA( LPSTR buffer, DWORD size,
1504 LPCSTR filename)
1507 return (GetPrivateProfileSectionNames16 (buffer,size,filename));
1511 /***********************************************************************
1512 * GetPrivateProfileSectionNames32W (KERNEL32.366)
1514 DWORD WINAPI GetPrivateProfileSectionNamesW( LPWSTR buffer, DWORD size,
1515 LPCWSTR filename)
1518 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1519 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, size);
1521 INT ret = GetPrivateProfileSectionNames16 (bufferA, size, filenameA);
1522 lstrcpynAtoW( buffer, bufferA, size);
1523 HeapFree( GetProcessHeap(), 0, bufferA);
1524 HeapFree( GetProcessHeap(), 0, filenameA );
1526 return ret;
1529 /***********************************************************************
1530 * GetPrivateProfileStruct16 (KERNEL.407)
1532 BOOL16 WINAPI GetPrivateProfileStruct16(LPCSTR section, LPCSTR key,
1533 LPVOID buf, UINT16 len, LPCSTR filename)
1535 return GetPrivateProfileStructA( section, key, buf, len, filename );
1538 /***********************************************************************
1539 * GetPrivateProfileStruct32A (KERNEL32.370)
1541 * Should match Win95's behaviour pretty much
1543 BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key,
1544 LPVOID buf, UINT len, LPCSTR filename)
1546 BOOL ret = FALSE;
1548 EnterCriticalSection( &PROFILE_CritSect );
1550 if (PROFILE_Open( filename )) {
1551 PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE);
1552 if (k) {
1553 TRACE("value (at %p): '%s'\n", k->value, k->value);
1554 if (((strlen(k->value) - 2) / 2) == len)
1556 LPSTR end, p;
1557 BOOL valid = TRUE;
1558 CHAR c;
1559 DWORD chksum = 0;
1561 end = k->value + strlen(k->value); /* -> '\0' */
1562 /* check for invalid chars in ASCII coded hex string */
1563 for (p=k->value; p < end; p++)
1565 if (!isxdigit(*p))
1567 WARN("invalid char '%c' in file '%s'->'[%s]'->'%s' !\n",
1568 *p, filename, section, key);
1569 valid = FALSE;
1570 break;
1573 if (valid)
1575 BOOL highnibble = TRUE;
1576 BYTE b = 0, val;
1577 LPBYTE binbuf = (LPBYTE)buf;
1579 end -= 2; /* don't include checksum in output data */
1580 /* translate ASCII hex format into binary data */
1581 for (p=k->value; p < end; p++)
1583 c = toupper(*p);
1584 val = (c > '9') ?
1585 (c - 'A' + 10) : (c - '0');
1587 if (highnibble)
1588 b = val << 4;
1589 else
1591 b += val;
1592 *binbuf++ = b; /* feed binary data into output */
1593 chksum += b; /* calculate checksum */
1595 highnibble ^= 1; /* toggle */
1597 /* retrieve stored checksum value */
1598 c = toupper(*p++);
1599 b = ( (c > '9') ? (c - 'A' + 10) : (c - '0') ) << 4;
1600 c = toupper(*p);
1601 b += (c > '9') ? (c - 'A' + 10) : (c - '0');
1602 if (b == (chksum & 0xff)) /* checksums match ? */
1603 ret = TRUE;
1608 LeaveCriticalSection( &PROFILE_CritSect );
1610 return ret;
1613 /***********************************************************************
1614 * GetPrivateProfileStruct32W (KERNEL32.543)
1616 BOOL WINAPI GetPrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1617 LPVOID buffer, UINT len, LPCWSTR filename)
1619 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1620 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1621 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1622 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1624 INT ret = GetPrivateProfileStructA( sectionA, keyA, bufferA,
1625 len, filenameA );
1626 lstrcpynAtoW( buffer, bufferA, len );
1627 HeapFree( GetProcessHeap(), 0, bufferA);
1628 HeapFree( GetProcessHeap(), 0, sectionA );
1629 HeapFree( GetProcessHeap(), 0, keyA );
1630 HeapFree( GetProcessHeap(), 0, filenameA );
1632 return ret;
1637 /***********************************************************************
1638 * WritePrivateProfileStruct16 (KERNEL.406)
1640 BOOL16 WINAPI WritePrivateProfileStruct16 (LPCSTR section, LPCSTR key,
1641 LPVOID buf, UINT16 bufsize, LPCSTR filename)
1643 return WritePrivateProfileStructA( section, key, buf, bufsize, filename );
1646 /***********************************************************************
1647 * WritePrivateProfileStruct32A (KERNEL32.744)
1649 BOOL WINAPI WritePrivateProfileStructA (LPCSTR section, LPCSTR key,
1650 LPVOID buf, UINT bufsize, LPCSTR filename)
1652 BOOL ret = FALSE;
1653 LPBYTE binbuf;
1654 LPSTR outstring, p;
1655 DWORD sum = 0;
1657 if (!section && !key && !buf) /* flush the cache */
1658 return WritePrivateProfileStringA( NULL, NULL, NULL, filename );
1660 /* allocate string buffer for hex chars + checksum hex char + '\0' */
1661 outstring = HeapAlloc( GetProcessHeap(), 0, bufsize*2 + 2 + 1);
1662 p = outstring;
1663 for (binbuf = (LPBYTE)buf; binbuf < (LPBYTE)buf+bufsize; binbuf++) {
1664 *p++ = hex[*binbuf >> 4];
1665 *p++ = hex[*binbuf & 0xf];
1666 sum += *binbuf;
1668 /* checksum is sum & 0xff */
1669 *p++ = hex[(sum & 0xf0) >> 4];
1670 *p++ = hex[sum & 0xf];
1671 *p++ = '\0';
1673 EnterCriticalSection( &PROFILE_CritSect );
1675 if (PROFILE_Open( filename ))
1676 ret = PROFILE_SetString( section, key, outstring );
1678 LeaveCriticalSection( &PROFILE_CritSect );
1680 HeapFree( GetProcessHeap(), 0, outstring );
1682 return ret;
1685 /***********************************************************************
1686 * WritePrivateProfileStruct32W (KERNEL32.544)
1688 BOOL WINAPI WritePrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1689 LPVOID buf, UINT bufsize, LPCWSTR filename)
1691 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1692 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1693 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1694 INT ret = WritePrivateProfileStructA( sectionA, keyA, buf, bufsize,
1695 filenameA );
1696 HeapFree( GetProcessHeap(), 0, sectionA );
1697 HeapFree( GetProcessHeap(), 0, keyA );
1698 HeapFree( GetProcessHeap(), 0, filenameA );
1700 return ret;
1704 /***********************************************************************
1705 * WriteOutProfiles (KERNEL.315)
1707 void WINAPI WriteOutProfiles16(void)
1709 EnterCriticalSection( &PROFILE_CritSect );
1710 PROFILE_FlushFile();
1711 LeaveCriticalSection( &PROFILE_CritSect );
1714 /***********************************************************************
1715 * CloseProfileUserMapping (KERNEL.138)
1717 BOOL WINAPI CloseProfileUserMapping(void) {
1718 FIXME("(), stub!\n");
1719 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1720 return FALSE;