Convert WND.text field to Unicode.
[wine.git] / files / profile.c
blobafbf8b0b18fa1f2c6827b3ab8bd0a24716d65863
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 "options.h"
29 #include "server.h"
31 DEFAULT_DEBUG_CHANNEL(profile);
33 typedef struct tagPROFILEKEY
35 char *name;
36 char *value;
37 struct tagPROFILEKEY *next;
38 } PROFILEKEY;
40 typedef struct tagPROFILESECTION
42 char *name;
43 struct tagPROFILEKEY *key;
44 struct tagPROFILESECTION *next;
45 } PROFILESECTION;
48 typedef struct
50 BOOL changed;
51 PROFILESECTION *section;
52 char *dos_name;
53 char *unix_name;
54 char *filename;
55 time_t mtime;
56 } PROFILE;
59 #define N_CACHED_PROFILES 10
61 /* Cached profile files */
62 static PROFILE *MRUProfile[N_CACHED_PROFILES]={NULL};
64 #define CurProfile (MRUProfile[0])
66 /* wine.ini config file registry root */
67 static HKEY wine_profile_key;
69 #define PROFILE_MAX_LINE_LEN 1024
71 /* Wine profile name in $HOME directory; must begin with slash */
72 static const char PROFILE_WineIniName[] = "/.winerc";
74 /* Wine profile: the profile file being used */
75 static char PROFILE_WineIniUsed[MAX_PATHNAME_LEN] = "";
77 /* Check for comments in profile */
78 #define IS_ENTRY_COMMENT(str) ((str)[0] == ';')
80 #define WINE_INI_GLOBAL ETCDIR "/wine.conf"
82 static const WCHAR wininiW[] = { 'w','i','n','.','i','n','i',0 };
84 static CRITICAL_SECTION PROFILE_CritSect = CRITICAL_SECTION_INIT;
86 static const char hex[16] = "0123456789ABCDEF";
88 /***********************************************************************
89 * PROFILE_CopyEntry
91 * Copy the content of an entry into a buffer, removing quotes, and possibly
92 * translating environment variables.
94 static void PROFILE_CopyEntry( char *buffer, const char *value, int len,
95 int handle_env )
97 char quote = '\0';
98 const char *p;
100 if ((*value == '\'') || (*value == '\"'))
102 if (value[1] && (value[strlen(value)-1] == *value)) quote = *value++;
105 if (!handle_env)
107 lstrcpynA( buffer, value, len );
108 if (quote && (len >= strlen(value))) buffer[strlen(buffer)-1] = '\0';
109 return;
112 for (p = value; (*p && (len > 1)); *buffer++ = *p++, len-- )
114 if ((*p == '$') && (p[1] == '{'))
116 char env_val[1024];
117 const char *env_p;
118 const char *p2 = strchr( p, '}' );
119 if (!p2) continue; /* ignore it */
120 lstrcpynA(env_val, p + 2, min( sizeof(env_val), (int)(p2-p)-1 ));
121 if ((env_p = getenv( env_val )) != NULL)
123 lstrcpynA( buffer, env_p, len );
124 buffer += strlen( buffer );
125 len -= strlen( buffer );
127 p = p2 + 1;
130 if (quote && (len > 1)) buffer--;
131 *buffer = '\0';
135 /***********************************************************************
136 * PROFILE_Save
138 * Save a profile tree to a file.
140 static void PROFILE_Save( FILE *file, PROFILESECTION *section )
142 PROFILEKEY *key;
144 for ( ; section; section = section->next)
146 if (section->name) fprintf( file, "\r\n[%s]\r\n", section->name );
147 for (key = section->key; key; key = key->next)
149 fprintf( file, "%s", key->name );
150 if (key->value) fprintf( file, "=%s", key->value );
151 fprintf( file, "\r\n" );
157 /***********************************************************************
158 * PROFILE_Free
160 * Free a profile tree.
162 static void PROFILE_Free( PROFILESECTION *section )
164 PROFILESECTION *next_section;
165 PROFILEKEY *key, *next_key;
167 for ( ; section; section = next_section)
169 if (section->name) HeapFree( GetProcessHeap(), 0, section->name );
170 for (key = section->key; key; key = next_key)
172 next_key = key->next;
173 if (key->name) HeapFree( GetProcessHeap(), 0, key->name );
174 if (key->value) HeapFree( GetProcessHeap(), 0, key->value );
175 HeapFree( GetProcessHeap(), 0, key );
177 next_section = section->next;
178 HeapFree( GetProcessHeap(), 0, section );
182 static inline int PROFILE_isspace(char c)
184 if (isspace(c)) return 1;
185 if (c=='\r' || c==0x1a) return 1;
186 /* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */
187 return 0;
191 /***********************************************************************
192 * PROFILE_Load
194 * Load a profile tree from a file.
196 static PROFILESECTION *PROFILE_Load( FILE *file )
198 char buffer[PROFILE_MAX_LINE_LEN];
199 char *p, *p2;
200 int line = 0;
201 PROFILESECTION *section, *first_section;
202 PROFILESECTION **next_section;
203 PROFILEKEY *key, *prev_key, **next_key;
205 first_section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) );
206 if(first_section == NULL) return NULL;
207 first_section->name = NULL;
208 first_section->key = NULL;
209 first_section->next = NULL;
210 next_section = &first_section->next;
211 next_key = &first_section->key;
212 prev_key = NULL;
214 while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
216 line++;
217 p = buffer;
218 while (*p && PROFILE_isspace(*p)) p++;
219 if (*p == '[') /* section start */
221 if (!(p2 = strrchr( p, ']' )))
223 WARN("Invalid section header at line %d: '%s'\n",
224 line, p );
226 else
228 *p2 = '\0';
229 p++;
230 section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) );
231 if(section == NULL) break;
232 section->name = HEAP_strdupA( GetProcessHeap(), 0, p );
233 section->key = NULL;
234 section->next = NULL;
235 *next_section = section;
236 next_section = &section->next;
237 next_key = &section->key;
238 prev_key = NULL;
240 TRACE("New section: '%s'\n",section->name);
242 continue;
246 p2=p+strlen(p) - 1;
247 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
249 if ((p2 = strchr( p, '=' )) != NULL)
251 char *p3 = p2 - 1;
252 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
253 *p2++ = '\0';
254 while (*p2 && PROFILE_isspace(*p2)) p2++;
257 if(*p || !prev_key || *prev_key->name)
259 key = HeapAlloc( GetProcessHeap(), 0, sizeof(*key) );
260 if(key == NULL) break;
261 key->name = HEAP_strdupA( GetProcessHeap(), 0, p );
262 key->value = p2 ? HEAP_strdupA( GetProcessHeap(), 0, p2 ) : NULL;
263 key->next = NULL;
264 *next_key = key;
265 next_key = &key->next;
266 prev_key = key;
268 TRACE("New key: name='%s', value='%s'\n",key->name,key->value?key->value:"(none)");
271 return first_section;
275 /***********************************************************************
276 * PROFILE_RegistryLoad
278 * Load a profile tree from a file into a registry key.
280 static DWORD PROFILE_RegistryLoad( HKEY root, FILE *file )
282 HKEY hkey = 0;
283 DWORD err = 0;
284 char buffer[PROFILE_MAX_LINE_LEN];
285 char *p, *p2;
286 int line = 0;
288 while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
290 line++;
291 p = buffer;
292 while (*p && PROFILE_isspace(*p)) p++;
293 if (*p == '[') /* section start */
295 if (!(p2 = strrchr( p, ']' )))
297 WARN("Invalid section header at line %d: '%s'\n",
298 line, p );
300 else
302 *p2 = '\0';
303 p++;
304 if (hkey) RegCloseKey( hkey );
305 if ((err = RegCreateKeyExA( root, p, 0, NULL, REG_OPTION_VOLATILE,
306 KEY_ALL_ACCESS, NULL, &hkey, NULL ))) return err;
307 TRACE("New section: '%s'\n",p);
308 continue;
312 p2=p+strlen(p) - 1;
313 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
315 if ((p2 = strchr( p, '=' )) != NULL)
317 char *p3 = p2 - 1;
318 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
319 *p2++ = '\0';
320 while (*p2 && PROFILE_isspace(*p2)) p2++;
323 if (*p && hkey && !IS_ENTRY_COMMENT(p))
325 if (!p2) p2 = "";
326 if ((err = RegSetValueExA( hkey, p, 0, REG_SZ, p2, strlen(p2)+1 )))
328 RegCloseKey( hkey );
329 return err;
331 TRACE("New key: name='%s', value='%s'\n",p,p2);
334 if (hkey) RegCloseKey( hkey );
335 return 0;
339 /***********************************************************************
340 * PROFILE_DeleteSection
342 * Delete a section from a profile tree.
344 static BOOL PROFILE_DeleteSection( PROFILESECTION **section, LPCSTR name )
346 while (*section)
348 if ((*section)->name && !strcasecmp( (*section)->name, name ))
350 PROFILESECTION *to_del = *section;
351 *section = to_del->next;
352 to_del->next = NULL;
353 PROFILE_Free( to_del );
354 return TRUE;
356 section = &(*section)->next;
358 return FALSE;
362 /***********************************************************************
363 * PROFILE_DeleteKey
365 * Delete a key from a profile tree.
367 static BOOL PROFILE_DeleteKey( PROFILESECTION **section,
368 LPCSTR section_name, LPCSTR key_name )
370 while (*section)
372 if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
374 PROFILEKEY **key = &(*section)->key;
375 while (*key)
377 if (!strcasecmp( (*key)->name, key_name ))
379 PROFILEKEY *to_del = *key;
380 *key = to_del->next;
381 if (to_del->name) HeapFree( GetProcessHeap(), 0, to_del->name );
382 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
383 HeapFree( GetProcessHeap(), 0, to_del );
384 return TRUE;
386 key = &(*key)->next;
389 section = &(*section)->next;
391 return FALSE;
395 /***********************************************************************
396 * PROFILE_DeleteAllKeys
398 * Delete all keys from a profile tree.
400 void PROFILE_DeleteAllKeys( LPCSTR section_name)
402 PROFILESECTION **section= &CurProfile->section;
403 while (*section)
405 if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
407 PROFILEKEY **key = &(*section)->key;
408 while (*key)
410 PROFILEKEY *to_del = *key;
411 *key = to_del->next;
412 if (to_del->name) HeapFree( GetProcessHeap(), 0, to_del->name );
413 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
414 HeapFree( GetProcessHeap(), 0, to_del );
415 CurProfile->changed =TRUE;
418 section = &(*section)->next;
423 /***********************************************************************
424 * PROFILE_Find
426 * Find a key in a profile tree, optionally creating it.
428 static PROFILEKEY *PROFILE_Find( PROFILESECTION **section,
429 const char *section_name,
430 const char *key_name, int create )
432 const char *p;
433 int seclen, keylen;
435 while (PROFILE_isspace(*section_name)) section_name++;
436 p = section_name + strlen(section_name) - 1;
437 while ((p > section_name) && PROFILE_isspace(*p)) p--;
438 seclen = p - section_name + 1;
440 while (PROFILE_isspace(*key_name)) key_name++;
441 p = key_name + strlen(key_name) - 1;
442 while ((p > key_name) && PROFILE_isspace(*p)) p--;
443 keylen = p - key_name + 1;
445 while (*section)
447 if ( ((*section)->name)
448 && (!(strncasecmp( (*section)->name, section_name, seclen )))
449 && (((*section)->name)[seclen] == '\0') )
451 PROFILEKEY **key = &(*section)->key;
452 while (*key)
454 if ( (!(strncasecmp( (*key)->name, key_name, keylen )))
455 && (((*key)->name)[keylen] == '\0') )
456 return *key;
457 key = &(*key)->next;
459 if (!create) return NULL;
460 *key = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) );
461 if(*key == NULL) return NULL;
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 = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILESECTION) );
471 if(*section == NULL) return NULL;
472 (*section)->name = HEAP_strdupA( GetProcessHeap(), 0, section_name );
473 (*section)->next = NULL;
474 (*section)->key = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) );
475 if((*section)->key == NULL)
477 HeapFree(GetProcessHeap(), 0, *section);
478 return NULL;
480 (*section)->key->name = HEAP_strdupA( GetProcessHeap(), 0, key_name );
481 (*section)->key->value = NULL;
482 (*section)->key->next = NULL;
483 return (*section)->key;
487 /***********************************************************************
488 * PROFILE_FlushFile
490 * Flush the current profile to disk if changed.
492 static BOOL PROFILE_FlushFile(void)
494 char *p, buffer[MAX_PATHNAME_LEN];
495 const char *unix_name;
496 FILE *file = NULL;
497 struct stat buf;
499 if(!CurProfile)
501 WARN("No current profile!\n");
502 return FALSE;
505 if (!CurProfile->changed || !CurProfile->dos_name) return TRUE;
506 if (!(unix_name = CurProfile->unix_name) || !(file = fopen(unix_name, "w")))
508 /* Try to create it in $HOME/.wine */
509 /* FIXME: this will need a more general solution */
510 strcpy( buffer, get_config_dir() );
511 p = buffer + strlen(buffer);
512 *p++ = '/';
513 strcpy( p, strrchr( CurProfile->dos_name, '\\' ) + 1 );
514 CharLowerA( p );
515 file = fopen( buffer, "w" );
516 unix_name = buffer;
519 if (!file)
521 WARN("could not save profile file %s\n", CurProfile->dos_name);
522 return FALSE;
525 TRACE("Saving '%s' into '%s'\n", CurProfile->dos_name, unix_name );
526 PROFILE_Save( file, CurProfile->section );
527 fclose( file );
528 CurProfile->changed = FALSE;
529 if(!stat(unix_name,&buf))
530 CurProfile->mtime=buf.st_mtime;
531 return TRUE;
535 /***********************************************************************
536 * PROFILE_ReleaseFile
538 * Flush the current profile to disk and remove it from the cache.
540 static void PROFILE_ReleaseFile(void)
542 PROFILE_FlushFile();
543 PROFILE_Free( CurProfile->section );
544 if (CurProfile->dos_name) HeapFree( GetProcessHeap(), 0, CurProfile->dos_name );
545 if (CurProfile->unix_name) HeapFree( GetProcessHeap(), 0, CurProfile->unix_name );
546 if (CurProfile->filename) HeapFree( GetProcessHeap(), 0, CurProfile->filename );
547 CurProfile->changed = FALSE;
548 CurProfile->section = NULL;
549 CurProfile->dos_name = NULL;
550 CurProfile->unix_name = NULL;
551 CurProfile->filename = NULL;
552 CurProfile->mtime = 0;
556 /***********************************************************************
557 * PROFILE_Open
559 * Open a profile file, checking the cached file first.
561 static BOOL PROFILE_Open( LPCSTR filename )
563 DOS_FULL_NAME full_name;
564 char buffer[MAX_PATHNAME_LEN];
565 char *newdos_name, *p;
566 FILE *file = NULL;
567 int i,j;
568 struct stat buf;
569 PROFILE *tempProfile;
571 /* First time around */
573 if(!CurProfile)
574 for(i=0;i<N_CACHED_PROFILES;i++)
576 MRUProfile[i]=HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILE) );
577 if(MRUProfile[i] == NULL) break;
578 MRUProfile[i]->changed=FALSE;
579 MRUProfile[i]->section=NULL;
580 MRUProfile[i]->dos_name=NULL;
581 MRUProfile[i]->unix_name=NULL;
582 MRUProfile[i]->filename=NULL;
583 MRUProfile[i]->mtime=0;
586 /* Check for a match */
588 if (strchr( filename, '/' ) || strchr( filename, '\\' ) ||
589 strchr( filename, ':' ))
591 if (!DOSFS_GetFullName( filename, FALSE, &full_name )) return FALSE;
593 else
595 GetWindowsDirectoryA( buffer, sizeof(buffer) );
596 strcat( buffer, "\\" );
597 strcat( buffer, filename );
598 if (!DOSFS_GetFullName( buffer, FALSE, &full_name )) return FALSE;
601 for(i=0;i<N_CACHED_PROFILES;i++)
603 if ((MRUProfile[i]->filename && !strcmp( filename, MRUProfile[i]->filename )) ||
604 (MRUProfile[i]->dos_name && !strcmp( full_name.short_name, MRUProfile[i]->dos_name )))
606 if(i)
608 PROFILE_FlushFile();
609 tempProfile=MRUProfile[i];
610 for(j=i;j>0;j--)
611 MRUProfile[j]=MRUProfile[j-1];
612 CurProfile=tempProfile;
614 if(!stat(CurProfile->unix_name,&buf) && CurProfile->mtime==buf.st_mtime)
615 TRACE("(%s): already opened (mru=%d)\n",
616 filename, i );
617 else
618 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
619 filename, i );
620 return TRUE;
624 /* Flush the old current profile */
625 PROFILE_FlushFile();
627 /* Make the oldest profile the current one only in order to get rid of it */
628 if(i==N_CACHED_PROFILES)
630 tempProfile=MRUProfile[N_CACHED_PROFILES-1];
631 for(i=N_CACHED_PROFILES-1;i>0;i--)
632 MRUProfile[i]=MRUProfile[i-1];
633 CurProfile=tempProfile;
635 if(CurProfile->filename) PROFILE_ReleaseFile();
637 /* OK, now that CurProfile is definitely free we assign it our new file */
638 newdos_name = HEAP_strdupA( GetProcessHeap(), 0, full_name.short_name );
639 CurProfile->dos_name = newdos_name;
640 CurProfile->filename = HEAP_strdupA( GetProcessHeap(), 0, filename );
642 /* Try to open the profile file, first in $HOME/.wine */
644 /* FIXME: this will need a more general solution */
645 strcpy( buffer, get_config_dir() );
646 p = buffer + strlen(buffer);
647 *p++ = '/';
648 strcpy( p, strrchr( newdos_name, '\\' ) + 1 );
649 CharLowerA( p );
650 if ((file = fopen( buffer, "r" )))
652 TRACE("(%s): found it in %s\n",
653 filename, buffer );
654 CurProfile->unix_name = HEAP_strdupA( GetProcessHeap(), 0, buffer );
657 if (!file)
659 CurProfile->unix_name = HEAP_strdupA( GetProcessHeap(), 0,
660 full_name.long_name );
661 if ((file = fopen( full_name.long_name, "r" )))
662 TRACE("(%s): found it in %s\n",
663 filename, full_name.long_name );
666 if (file)
668 CurProfile->section = PROFILE_Load( file );
669 fclose( file );
670 if(!stat(CurProfile->unix_name,&buf))
671 CurProfile->mtime=buf.st_mtime;
673 else
675 /* Does not exist yet, we will create it in PROFILE_FlushFile */
676 WARN("profile file %s not found\n", newdos_name );
678 return TRUE;
682 /***********************************************************************
683 * PROFILE_GetSection
685 * Returns all keys of a section.
686 * If return_values is TRUE, also include the corresponding values.
688 static INT PROFILE_GetSection( PROFILESECTION *section, LPCSTR section_name,
689 LPSTR buffer, UINT len, BOOL handle_env,
690 BOOL return_values )
692 PROFILEKEY *key;
693 while (section)
695 if (section->name && !strcasecmp( section->name, section_name ))
697 UINT oldlen = len;
698 for (key = section->key; key; key = key->next)
700 if (len <= 2) break;
701 if (!*key->name) continue; /* Skip empty lines */
702 if (IS_ENTRY_COMMENT(key->name)) continue; /* Skip comments */
703 PROFILE_CopyEntry( buffer, key->name, len - 1, handle_env );
704 len -= strlen(buffer) + 1;
705 buffer += strlen(buffer) + 1;
706 if (return_values && key->value) {
707 buffer[-1] = '=';
708 PROFILE_CopyEntry ( buffer,
709 key->value, len - 1, handle_env );
710 len -= strlen(buffer) + 1;
711 buffer += strlen(buffer) + 1;
714 *buffer = '\0';
715 if (len <= 1)
716 /*If either lpszSection or lpszKey is NULL and the supplied
717 destination buffer is too small to hold all the strings,
718 the last string is truncated and followed by two null characters.
719 In this case, the return value is equal to cchReturnBuffer
720 minus two. */
722 buffer[-1] = '\0';
723 return oldlen - 2;
725 return oldlen - len;
727 section = section->next;
729 buffer[0] = buffer[1] = '\0';
730 return 0;
734 static INT PROFILE_GetSectionNames( LPSTR buffer, UINT len )
736 LPSTR buf = buffer;
737 WORD l, cursize = 0;
738 PROFILESECTION *section;
740 for (section = CurProfile->section; section; section = section->next)
741 if (section->name) {
742 l = strlen(section->name);
743 cursize += l+1;
744 if (cursize > len+1)
745 return len-2;
747 strcpy(buf, section->name);
748 buf += l+1;
751 *buf=0;
752 buf++;
753 return buf-buffer;
757 /***********************************************************************
758 * PROFILE_GetString
760 * Get a profile string.
762 static INT PROFILE_GetString( LPCSTR section, LPCSTR key_name,
763 LPCSTR def_val, LPSTR buffer, UINT len )
765 PROFILEKEY *key = NULL;
767 if (!def_val) def_val = "";
768 if (key_name && key_name[0])
770 key = PROFILE_Find( &CurProfile->section, section, key_name, FALSE );
771 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def_val,
772 len, FALSE );
773 TRACE("('%s','%s','%s'): returning '%s'\n",
774 section, key_name, def_val, buffer );
775 return strlen( buffer );
777 if (key_name && !(key_name[0]))
778 /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227*/
779 return 0;
780 if (section && section[0])
781 return PROFILE_GetSection(CurProfile->section, section, buffer, len,
782 FALSE, FALSE);
783 /* undocumented; both section and key_name are NULL */
784 return PROFILE_GetSectionNames(buffer, len);
788 /***********************************************************************
789 * PROFILE_SetString
791 * Set a profile string.
793 static BOOL PROFILE_SetString( LPCSTR section_name, LPCSTR key_name,
794 LPCSTR value )
796 if (!key_name) /* Delete a whole section */
798 TRACE("('%s')\n", section_name);
799 CurProfile->changed |= PROFILE_DeleteSection( &CurProfile->section,
800 section_name );
801 return TRUE; /* Even if PROFILE_DeleteSection() has failed,
802 this is not an error on application's level.*/
804 else if (!value) /* Delete a key */
806 TRACE("('%s','%s')\n",
807 section_name, key_name );
808 CurProfile->changed |= PROFILE_DeleteKey( &CurProfile->section,
809 section_name, key_name );
810 return TRUE; /* same error handling as above */
812 else /* Set the key value */
814 PROFILEKEY *key = PROFILE_Find( &CurProfile->section, section_name,
815 key_name, TRUE );
816 TRACE("('%s','%s','%s'): \n",
817 section_name, key_name, value );
818 if (!key) return FALSE;
819 if (key->value)
821 /* strip the leading spaces. We can safely strip \n\r and
822 * friends too, they should not happen here anyway. */
823 while (PROFILE_isspace(*value)) value++;
825 if (!strcmp( key->value, value ))
827 TRACE(" no change needed\n" );
828 return TRUE; /* No change needed */
830 TRACE(" replacing '%s'\n", key->value );
831 HeapFree( GetProcessHeap(), 0, key->value );
833 else TRACE(" creating key\n" );
834 key->value = HEAP_strdupA( GetProcessHeap(), 0, value );
835 CurProfile->changed = TRUE;
837 return TRUE;
841 /***********************************************************************
842 * PROFILE_GetWineIniString
844 * Get a config string from the wine.ini file.
846 int PROFILE_GetWineIniString( const char *section, const char *key_name,
847 const char *def, char *buffer, int len )
849 char tmp[PROFILE_MAX_LINE_LEN];
850 HKEY hkey;
851 DWORD err;
853 if (!(err = RegOpenKeyA( wine_profile_key, section, &hkey )))
855 DWORD type;
856 DWORD count = sizeof(tmp);
857 err = RegQueryValueExA( hkey, key_name, 0, &type, tmp, &count );
858 RegCloseKey( hkey );
860 PROFILE_CopyEntry( buffer, err ? def : tmp, len, TRUE );
861 TRACE( "('%s','%s','%s'): returning '%s'\n", section, key_name, def, buffer );
862 return strlen(buffer);
866 /***********************************************************************
867 * PROFILE_EnumWineIniString
869 * Get a config string from the wine.ini file.
871 BOOL PROFILE_EnumWineIniString( const char *section, int index,
872 char *name, int name_len, char *buffer, int len )
874 char tmp[PROFILE_MAX_LINE_LEN];
875 HKEY hkey;
876 DWORD err, type;
877 DWORD count = sizeof(tmp);
879 if (RegOpenKeyA( wine_profile_key, section, &hkey )) return FALSE;
880 err = RegEnumValueA( hkey, index, name, (DWORD*)&name_len, NULL, &type, tmp, &count );
881 RegCloseKey( hkey );
882 if (!err)
884 PROFILE_CopyEntry( buffer, tmp, len, TRUE );
885 TRACE( "('%s',%d): returning '%s'='%s'\n", section, index, name, buffer );
887 return !err;
891 /***********************************************************************
892 * PROFILE_GetWineIniInt
894 * Get a config integer from the wine.ini file.
896 int PROFILE_GetWineIniInt( const char *section, const char *key_name, int def )
898 char buffer[20];
899 char *p;
900 long result;
902 PROFILE_GetWineIniString( section, key_name, "", buffer, sizeof(buffer) );
903 if (!buffer[0]) return def;
904 result = strtol( buffer, &p, 0 );
905 return (p == buffer) ? 0 /* No digits at all */ : (int)result;
909 /******************************************************************************
911 * int PROFILE_GetWineIniBool(
912 * char const *section,
913 * char const *key_name,
914 * int def )
916 * Reads a boolean value from the wine.ini file. This function attempts to
917 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
918 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
919 * true. Anything else results in the return of the default value.
921 * This function uses 1 to indicate true, and 0 for false. You can check
922 * for existence by setting def to something other than 0 or 1 and
923 * examining the return value.
925 int PROFILE_GetWineIniBool(
926 char const *section,
927 char const *key_name,
928 int def )
930 char key_value[2];
931 int retval;
933 PROFILE_GetWineIniString(section, key_name, "~", key_value, 2);
935 switch(key_value[0]) {
936 case 'n':
937 case 'N':
938 case 'f':
939 case 'F':
940 case '0':
941 retval = 0;
942 break;
944 case 'y':
945 case 'Y':
946 case 't':
947 case 'T':
948 case '1':
949 retval = 1;
950 break;
952 default:
953 retval = def;
956 TRACE("(\"%s\", \"%s\", %s), "
957 "[%c], ret %s.\n", section, key_name,
958 def ? "TRUE" : "FALSE", key_value[0],
959 retval ? "TRUE" : "FALSE");
961 return retval;
965 /***********************************************************************
966 * PROFILE_LoadWineIni
968 * Load the wine.ini file.
970 int PROFILE_LoadWineIni(void)
972 char buffer[MAX_PATHNAME_LEN];
973 const char *p;
974 FILE *f;
975 HKEY hKeySW;
977 /* make sure HKLM\\Software\\Wine\\Wine exists as non-volatile key */
978 if (RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine", &hKeySW ))
980 ERR("Cannot create config registry key\n" );
981 return 0;
983 RegCloseKey( hKeySW );
984 if (RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config", 0, NULL,
985 REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &wine_profile_key, NULL ))
987 ERR("Cannot create config registry key\n" );
988 return 0;
991 if (!CLIENT_IsBootThread()) return 1; /* already loaded */
993 if ( (Options.configFileName!=NULL) && (f = fopen(Options.configFileName, "r")) )
995 /* Open -config specified file */
996 lstrcpynA(PROFILE_WineIniUsed,Options.configFileName,MAX_PATHNAME_LEN);
997 goto found;
1000 if ( (p = getenv( "WINE_INI" )) && (f = fopen( p, "r" )) )
1002 lstrcpynA(PROFILE_WineIniUsed,p,MAX_PATHNAME_LEN);
1003 goto found;
1005 if ((p = getenv( "HOME" )) != NULL)
1007 lstrcpynA(buffer, p, MAX_PATHNAME_LEN - sizeof(PROFILE_WineIniName));
1008 strcat( buffer, PROFILE_WineIniName );
1009 if ((f = fopen( buffer, "r" )) != NULL)
1011 lstrcpynA(PROFILE_WineIniUsed,buffer,MAX_PATHNAME_LEN);
1012 goto found;
1015 else WARN("could not get $HOME value for config file.\n" );
1017 /* Try global file */
1019 if ((f = fopen( WINE_INI_GLOBAL, "r" )) != NULL)
1021 lstrcpynA(PROFILE_WineIniUsed,WINE_INI_GLOBAL,MAX_PATHNAME_LEN);
1022 goto found;
1024 MESSAGE( "Can't open configuration file %s or $HOME%s\n",
1025 WINE_INI_GLOBAL, PROFILE_WineIniName );
1026 return 0;
1028 found:
1029 PROFILE_RegistryLoad( wine_profile_key, f );
1030 fclose( f );
1031 return 1;
1035 /***********************************************************************
1036 * PROFILE_UsageWineIni
1038 * Explain the wine.ini file to those who don't read documentation.
1039 * Keep below one screenful in length so that error messages above are
1040 * noticed.
1042 void PROFILE_UsageWineIni(void)
1044 MESSAGE("Perhaps you have not properly edited or created "
1045 "your Wine configuration file.\n");
1046 MESSAGE("This is either %s or $HOME%s\n",WINE_INI_GLOBAL,PROFILE_WineIniName);
1047 MESSAGE(" or it is determined by the -config option or from\n"
1048 " the WINE_INI environment variable.\n");
1049 if (*PROFILE_WineIniUsed)
1050 MESSAGE("Wine has used %s as configuration file.\n", PROFILE_WineIniUsed);
1051 /* RTFM, so to say */
1054 /***********************************************************************
1055 * PROFILE_GetStringItem
1057 * Convenience function that turns a string 'xxx, yyy, zzz' into
1058 * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
1060 char* PROFILE_GetStringItem( char* start )
1062 char* lpchX, *lpch;
1064 for (lpchX = start, lpch = NULL; *lpchX != '\0'; lpchX++ )
1066 if( *lpchX == ',' )
1068 if( lpch ) *lpch = '\0'; else *lpchX = '\0';
1069 while( *(++lpchX) )
1070 if( !PROFILE_isspace(*lpchX) ) return lpchX;
1072 else if( PROFILE_isspace( *lpchX ) && !lpch ) lpch = lpchX;
1073 else lpch = NULL;
1075 if( lpch ) *lpch = '\0';
1076 return NULL;
1079 /********************* API functions **********************************/
1081 /***********************************************************************
1082 * GetProfileInt16 (KERNEL.57)
1084 UINT16 WINAPI GetProfileInt16( LPCSTR section, LPCSTR entry, INT16 def_val )
1086 return GetPrivateProfileInt16( section, entry, def_val, "win.ini" );
1090 /***********************************************************************
1091 * GetProfileIntA (KERNEL32.264)
1093 UINT WINAPI GetProfileIntA( LPCSTR section, LPCSTR entry, INT def_val )
1095 return GetPrivateProfileIntA( section, entry, def_val, "win.ini" );
1098 /***********************************************************************
1099 * GetProfileIntW (KERNEL32.264)
1101 UINT WINAPI GetProfileIntW( LPCWSTR section, LPCWSTR entry, INT def_val )
1103 return GetPrivateProfileIntW( section, entry, def_val, wininiW );
1106 /***********************************************************************
1107 * GetProfileString16 (KERNEL.58)
1109 INT16 WINAPI GetProfileString16( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1110 LPSTR buffer, UINT16 len )
1112 return GetPrivateProfileString16( section, entry, def_val,
1113 buffer, len, "win.ini" );
1116 /***********************************************************************
1117 * GetProfileStringA (KERNEL32.268)
1119 INT WINAPI GetProfileStringA( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1120 LPSTR buffer, UINT len )
1122 return GetPrivateProfileStringA( section, entry, def_val,
1123 buffer, len, "win.ini" );
1126 /***********************************************************************
1127 * GetProfileStringW (KERNEL32.269)
1129 INT WINAPI GetProfileStringW( LPCWSTR section, LPCWSTR entry,
1130 LPCWSTR def_val, LPWSTR buffer, UINT len )
1132 return GetPrivateProfileStringW( section, entry, def_val,
1133 buffer, len, wininiW );
1136 /***********************************************************************
1137 * WriteProfileString16 (KERNEL.59)
1139 BOOL16 WINAPI WriteProfileString16( LPCSTR section, LPCSTR entry,
1140 LPCSTR string )
1142 return WritePrivateProfileString16( section, entry, string, "win.ini" );
1145 /***********************************************************************
1146 * WriteProfileStringA (KERNEL32.587)
1148 BOOL WINAPI WriteProfileStringA( LPCSTR section, LPCSTR entry,
1149 LPCSTR string )
1151 return WritePrivateProfileStringA( section, entry, string, "win.ini" );
1154 /***********************************************************************
1155 * WriteProfileStringW (KERNEL32.588)
1157 BOOL WINAPI WriteProfileStringW( LPCWSTR section, LPCWSTR entry,
1158 LPCWSTR string )
1160 return WritePrivateProfileStringW( section, entry, string, wininiW );
1164 /***********************************************************************
1165 * GetPrivateProfileInt16 (KERNEL.127)
1167 UINT16 WINAPI GetPrivateProfileInt16( LPCSTR section, LPCSTR entry,
1168 INT16 def_val, LPCSTR filename )
1170 long result=(long)GetPrivateProfileIntA(section,entry,def_val,filename);
1172 if (result > 65535) return 65535;
1173 if (result >= 0) return (UINT16)result;
1174 if (result < -32768) return -32768;
1175 return (UINT16)(INT16)result;
1178 /***********************************************************************
1179 * GetPrivateProfileIntA (KERNEL32.251)
1181 UINT WINAPI GetPrivateProfileIntA( LPCSTR section, LPCSTR entry,
1182 INT def_val, LPCSTR filename )
1184 char buffer[20];
1185 char *p;
1186 long result;
1188 GetPrivateProfileStringA( section, entry, "",
1189 buffer, sizeof(buffer), filename );
1190 if (!buffer[0]) return (UINT)def_val;
1191 result = strtol( buffer, &p, 0 );
1192 if (p == buffer) return 0; /* No digits at all */
1193 return (UINT)result;
1196 /***********************************************************************
1197 * GetPrivateProfileIntW (KERNEL32.252)
1199 UINT WINAPI GetPrivateProfileIntW( LPCWSTR section, LPCWSTR entry,
1200 INT def_val, LPCWSTR filename )
1202 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1203 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1204 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1205 UINT res = GetPrivateProfileIntA(sectionA, entryA, def_val, filenameA);
1206 HeapFree( GetProcessHeap(), 0, sectionA );
1207 HeapFree( GetProcessHeap(), 0, filenameA );
1208 HeapFree( GetProcessHeap(), 0, entryA );
1209 return res;
1212 /***********************************************************************
1213 * GetPrivateProfileString16 (KERNEL.128)
1215 INT16 WINAPI GetPrivateProfileString16( LPCSTR section, LPCSTR entry,
1216 LPCSTR def_val, LPSTR buffer,
1217 UINT16 len, LPCSTR filename )
1219 return GetPrivateProfileStringA(section,entry,def_val,buffer,len,filename);
1222 /***********************************************************************
1223 * GetPrivateProfileStringA (KERNEL32.255)
1225 INT WINAPI GetPrivateProfileStringA( LPCSTR section, LPCSTR entry,
1226 LPCSTR def_val, LPSTR buffer,
1227 UINT len, LPCSTR filename )
1229 int ret;
1231 if (!filename)
1232 filename = "win.ini";
1234 EnterCriticalSection( &PROFILE_CritSect );
1236 if (PROFILE_Open( filename )) {
1237 ret = PROFILE_GetString( section, entry, def_val, buffer, len );
1238 } else {
1239 lstrcpynA( buffer, def_val, len );
1240 ret = strlen( buffer );
1243 LeaveCriticalSection( &PROFILE_CritSect );
1245 return ret;
1248 /***********************************************************************
1249 * GetPrivateProfileStringW (KERNEL32.256)
1251 INT WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1252 LPCWSTR def_val, LPWSTR buffer,
1253 UINT len, LPCWSTR filename )
1255 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1256 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1257 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1258 LPSTR def_valA = HEAP_strdupWtoA( GetProcessHeap(), 0, def_val );
1259 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1260 INT ret = GetPrivateProfileStringA( sectionA, entryA, def_valA,
1261 bufferA, len, filenameA );
1262 lstrcpynAtoW( buffer, bufferA, len );
1263 HeapFree( GetProcessHeap(), 0, sectionA );
1264 HeapFree( GetProcessHeap(), 0, entryA );
1265 HeapFree( GetProcessHeap(), 0, filenameA );
1266 HeapFree( GetProcessHeap(), 0, def_valA );
1267 HeapFree( GetProcessHeap(), 0, bufferA);
1268 return ret;
1271 /***********************************************************************
1272 * GetPrivateProfileSection16 (KERNEL.418)
1274 INT16 WINAPI GetPrivateProfileSection16( LPCSTR section, LPSTR buffer,
1275 UINT16 len, LPCSTR filename )
1277 return GetPrivateProfileSectionA( section, buffer, len, filename );
1280 /***********************************************************************
1281 * GetPrivateProfileSectionA (KERNEL32.255)
1283 INT WINAPI GetPrivateProfileSectionA( LPCSTR section, LPSTR buffer,
1284 DWORD len, LPCSTR filename )
1286 int ret = 0;
1288 EnterCriticalSection( &PROFILE_CritSect );
1290 if (PROFILE_Open( filename ))
1291 ret = PROFILE_GetSection(CurProfile->section, section, buffer, len,
1292 FALSE, TRUE);
1294 LeaveCriticalSection( &PROFILE_CritSect );
1296 return ret;
1299 /***********************************************************************
1300 * GetPrivateProfileSectionW (KERNEL32.256)
1303 INT WINAPI GetPrivateProfileSectionW (LPCWSTR section, LPWSTR buffer,
1304 DWORD len, LPCWSTR filename )
1307 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1308 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1309 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1310 INT ret = GetPrivateProfileSectionA( sectionA, bufferA, len,
1311 filenameA );
1312 MultiByteToWideChar(CP_ACP,0,bufferA,ret,buffer,len);
1313 HeapFree( GetProcessHeap(), 0, sectionA );
1314 HeapFree( GetProcessHeap(), 0, filenameA );
1315 HeapFree( GetProcessHeap(), 0, bufferA);
1316 return ret;
1319 /***********************************************************************
1320 * GetProfileSection16 (KERNEL.419)
1322 INT16 WINAPI GetProfileSection16( LPCSTR section, LPSTR buffer, UINT16 len )
1324 return GetPrivateProfileSection16( section, buffer, len, "win.ini" );
1327 /***********************************************************************
1328 * GetProfileSectionA (KERNEL32.268)
1330 INT WINAPI GetProfileSectionA( LPCSTR section, LPSTR buffer, DWORD len )
1332 return GetPrivateProfileSectionA( section, buffer, len, "win.ini" );
1335 /***********************************************************************
1336 * GetProfileSectionW (KERNEL32)
1338 INT WINAPI GetProfileSectionW( LPCWSTR section, LPWSTR buffer, DWORD len )
1340 return GetPrivateProfileSectionW( section, buffer, len, wininiW );
1344 /***********************************************************************
1345 * WritePrivateProfileString16 (KERNEL.129)
1347 BOOL16 WINAPI WritePrivateProfileString16( LPCSTR section, LPCSTR entry,
1348 LPCSTR string, LPCSTR filename )
1350 return WritePrivateProfileStringA(section,entry,string,filename);
1353 /***********************************************************************
1354 * WritePrivateProfileStringA (KERNEL32.582)
1356 BOOL WINAPI WritePrivateProfileStringA( LPCSTR section, LPCSTR entry,
1357 LPCSTR string, LPCSTR filename )
1359 BOOL ret = FALSE;
1361 EnterCriticalSection( &PROFILE_CritSect );
1363 if (PROFILE_Open( filename ))
1365 if (!section && !entry && !string)
1366 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1367 else
1368 ret = PROFILE_SetString( section, entry, string );
1371 LeaveCriticalSection( &PROFILE_CritSect );
1372 return ret;
1375 /***********************************************************************
1376 * WritePrivateProfileStringW (KERNEL32.583)
1378 BOOL WINAPI WritePrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1379 LPCWSTR string, LPCWSTR filename )
1381 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1382 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1383 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1384 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1385 BOOL res = WritePrivateProfileStringA( sectionA, entryA,
1386 stringA, filenameA );
1387 HeapFree( GetProcessHeap(), 0, sectionA );
1388 HeapFree( GetProcessHeap(), 0, entryA );
1389 HeapFree( GetProcessHeap(), 0, stringA );
1390 HeapFree( GetProcessHeap(), 0, filenameA );
1391 return res;
1394 /***********************************************************************
1395 * WritePrivateProfileSection16 (KERNEL.416)
1397 BOOL16 WINAPI WritePrivateProfileSection16( LPCSTR section,
1398 LPCSTR string, LPCSTR filename )
1400 return WritePrivateProfileSectionA( section, string, filename );
1403 /***********************************************************************
1404 * WritePrivateProfileSectionA (KERNEL32)
1406 BOOL WINAPI WritePrivateProfileSectionA( LPCSTR section,
1407 LPCSTR string, LPCSTR filename )
1409 BOOL ret = FALSE;
1410 LPSTR p ;
1412 EnterCriticalSection( &PROFILE_CritSect );
1414 if (PROFILE_Open( filename )) {
1415 if (!section && !string && !filename)
1416 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1417 else if (!string) /* delete the named section*/
1418 ret = PROFILE_SetString(section,NULL,NULL);
1419 else {
1420 PROFILE_DeleteAllKeys(section);
1421 ret = TRUE;
1422 while(*string) {
1423 LPSTR buf=HEAP_strdupA( GetProcessHeap(), 0, string );
1424 if((p=strchr( buf, '='))){
1425 *p='\0';
1426 ret = PROFILE_SetString( section, buf, p+1 );
1429 HeapFree( GetProcessHeap(), 0, buf );
1430 string += strlen(string)+1;
1436 LeaveCriticalSection( &PROFILE_CritSect );
1437 return ret;
1440 /***********************************************************************
1441 * WritePrivateProfileSectionW (KERNEL32)
1443 BOOL WINAPI WritePrivateProfileSectionW( LPCWSTR section,
1444 LPCWSTR string, LPCWSTR filename)
1447 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1448 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1449 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1450 BOOL res = WritePrivateProfileSectionA( sectionA, stringA, filenameA );
1451 HeapFree( GetProcessHeap(), 0, sectionA );
1452 HeapFree( GetProcessHeap(), 0, stringA );
1453 HeapFree( GetProcessHeap(), 0, filenameA );
1454 return res;
1457 /***********************************************************************
1458 * WriteProfileSection16 (KERNEL.417)
1460 BOOL16 WINAPI WriteProfileSection16( LPCSTR section, LPCSTR keys_n_values)
1462 return WritePrivateProfileSection16( section, keys_n_values, "win.ini");
1465 /***********************************************************************
1466 * WriteProfileSectionA (KERNEL32.747)
1468 BOOL WINAPI WriteProfileSectionA( LPCSTR section, LPCSTR keys_n_values)
1471 return WritePrivateProfileSectionA( section, keys_n_values, "win.ini");
1474 /***********************************************************************
1475 * WriteProfileSectionW (KERNEL32.748)
1477 BOOL WINAPI WriteProfileSectionW( LPCWSTR section, LPCWSTR keys_n_values)
1479 return (WritePrivateProfileSectionW (section,keys_n_values, wininiW));
1482 /***********************************************************************
1483 * GetPrivateProfileSectionNames16 (KERNEL.143)
1485 WORD WINAPI GetPrivateProfileSectionNames16( LPSTR buffer, WORD size,
1486 LPCSTR filename )
1488 WORD ret = 0;
1490 EnterCriticalSection( &PROFILE_CritSect );
1492 if (PROFILE_Open( filename ))
1493 ret = PROFILE_GetSectionNames(buffer, size);
1495 LeaveCriticalSection( &PROFILE_CritSect );
1497 return ret;
1501 /***********************************************************************
1502 * GetProfileSectionNames16 (KERNEL.142)
1504 WORD WINAPI GetProfileSectionNames16( LPSTR buffer, WORD size)
1507 return (GetPrivateProfileSectionNames16 (buffer,size,"win.ini"));
1511 /***********************************************************************
1512 * GetPrivateProfileSectionNamesA (KERNEL32.365)
1514 DWORD WINAPI GetPrivateProfileSectionNamesA( LPSTR buffer, DWORD size,
1515 LPCSTR filename)
1518 return (GetPrivateProfileSectionNames16 (buffer,size,filename));
1522 /***********************************************************************
1523 * GetPrivateProfileSectionNamesW (KERNEL32.366)
1525 DWORD WINAPI GetPrivateProfileSectionNamesW( LPWSTR buffer, DWORD size,
1526 LPCWSTR filename)
1529 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1530 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, size);
1532 INT ret = GetPrivateProfileSectionNames16 (bufferA, size, filenameA);
1533 lstrcpynAtoW( buffer, bufferA, size);
1534 HeapFree( GetProcessHeap(), 0, bufferA);
1535 HeapFree( GetProcessHeap(), 0, filenameA );
1537 return ret;
1540 /***********************************************************************
1541 * GetPrivateProfileStruct16 (KERNEL.407)
1543 BOOL16 WINAPI GetPrivateProfileStruct16(LPCSTR section, LPCSTR key,
1544 LPVOID buf, UINT16 len, LPCSTR filename)
1546 return GetPrivateProfileStructA( section, key, buf, len, filename );
1549 /***********************************************************************
1550 * GetPrivateProfileStructA (KERNEL32.370)
1552 * Should match Win95's behaviour pretty much
1554 BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key,
1555 LPVOID buf, UINT len, LPCSTR filename)
1557 BOOL ret = FALSE;
1559 EnterCriticalSection( &PROFILE_CritSect );
1561 if (PROFILE_Open( filename )) {
1562 PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE);
1563 if (k) {
1564 TRACE("value (at %p): '%s'\n", k->value, k->value);
1565 if (((strlen(k->value) - 2) / 2) == len)
1567 LPSTR end, p;
1568 BOOL valid = TRUE;
1569 CHAR c;
1570 DWORD chksum = 0;
1572 end = k->value + strlen(k->value); /* -> '\0' */
1573 /* check for invalid chars in ASCII coded hex string */
1574 for (p=k->value; p < end; p++)
1576 if (!isxdigit(*p))
1578 WARN("invalid char '%c' in file '%s'->'[%s]'->'%s' !\n",
1579 *p, filename, section, key);
1580 valid = FALSE;
1581 break;
1584 if (valid)
1586 BOOL highnibble = TRUE;
1587 BYTE b = 0, val;
1588 LPBYTE binbuf = (LPBYTE)buf;
1590 end -= 2; /* don't include checksum in output data */
1591 /* translate ASCII hex format into binary data */
1592 for (p=k->value; p < end; p++)
1594 c = toupper(*p);
1595 val = (c > '9') ?
1596 (c - 'A' + 10) : (c - '0');
1598 if (highnibble)
1599 b = val << 4;
1600 else
1602 b += val;
1603 *binbuf++ = b; /* feed binary data into output */
1604 chksum += b; /* calculate checksum */
1606 highnibble ^= 1; /* toggle */
1608 /* retrieve stored checksum value */
1609 c = toupper(*p++);
1610 b = ( (c > '9') ? (c - 'A' + 10) : (c - '0') ) << 4;
1611 c = toupper(*p);
1612 b += (c > '9') ? (c - 'A' + 10) : (c - '0');
1613 if (b == (chksum & 0xff)) /* checksums match ? */
1614 ret = TRUE;
1619 LeaveCriticalSection( &PROFILE_CritSect );
1621 return ret;
1624 /***********************************************************************
1625 * GetPrivateProfileStructW (KERNEL32.543)
1627 BOOL WINAPI GetPrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1628 LPVOID buffer, UINT len, LPCWSTR filename)
1630 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1631 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1632 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1633 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1635 INT ret = GetPrivateProfileStructA( sectionA, keyA, bufferA,
1636 len, filenameA );
1637 lstrcpynAtoW( buffer, bufferA, len );
1638 HeapFree( GetProcessHeap(), 0, bufferA);
1639 HeapFree( GetProcessHeap(), 0, sectionA );
1640 HeapFree( GetProcessHeap(), 0, keyA );
1641 HeapFree( GetProcessHeap(), 0, filenameA );
1643 return ret;
1648 /***********************************************************************
1649 * WritePrivateProfileStruct16 (KERNEL.406)
1651 BOOL16 WINAPI WritePrivateProfileStruct16 (LPCSTR section, LPCSTR key,
1652 LPVOID buf, UINT16 bufsize, LPCSTR filename)
1654 return WritePrivateProfileStructA( section, key, buf, bufsize, filename );
1657 /***********************************************************************
1658 * WritePrivateProfileStructA (KERNEL32.744)
1660 BOOL WINAPI WritePrivateProfileStructA (LPCSTR section, LPCSTR key,
1661 LPVOID buf, UINT bufsize, LPCSTR filename)
1663 BOOL ret = FALSE;
1664 LPBYTE binbuf;
1665 LPSTR outstring, p;
1666 DWORD sum = 0;
1668 if (!section && !key && !buf) /* flush the cache */
1669 return WritePrivateProfileStringA( NULL, NULL, NULL, filename );
1671 /* allocate string buffer for hex chars + checksum hex char + '\0' */
1672 outstring = HeapAlloc( GetProcessHeap(), 0, bufsize*2 + 2 + 1);
1673 p = outstring;
1674 for (binbuf = (LPBYTE)buf; binbuf < (LPBYTE)buf+bufsize; binbuf++) {
1675 *p++ = hex[*binbuf >> 4];
1676 *p++ = hex[*binbuf & 0xf];
1677 sum += *binbuf;
1679 /* checksum is sum & 0xff */
1680 *p++ = hex[(sum & 0xf0) >> 4];
1681 *p++ = hex[sum & 0xf];
1682 *p++ = '\0';
1684 EnterCriticalSection( &PROFILE_CritSect );
1686 if (PROFILE_Open( filename ))
1687 ret = PROFILE_SetString( section, key, outstring );
1689 LeaveCriticalSection( &PROFILE_CritSect );
1691 HeapFree( GetProcessHeap(), 0, outstring );
1693 return ret;
1696 /***********************************************************************
1697 * WritePrivateProfileStructW (KERNEL32.544)
1699 BOOL WINAPI WritePrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1700 LPVOID buf, UINT bufsize, LPCWSTR filename)
1702 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1703 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1704 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1705 INT ret = WritePrivateProfileStructA( sectionA, keyA, buf, bufsize,
1706 filenameA );
1707 HeapFree( GetProcessHeap(), 0, sectionA );
1708 HeapFree( GetProcessHeap(), 0, keyA );
1709 HeapFree( GetProcessHeap(), 0, filenameA );
1711 return ret;
1715 /***********************************************************************
1716 * WriteOutProfiles (KERNEL.315)
1718 void WINAPI WriteOutProfiles16(void)
1720 EnterCriticalSection( &PROFILE_CritSect );
1721 PROFILE_FlushFile();
1722 LeaveCriticalSection( &PROFILE_CritSect );
1725 /***********************************************************************
1726 * CloseProfileUserMapping (KERNEL.138)
1728 BOOL WINAPI CloseProfileUserMapping(void) {
1729 FIXME("(), stub!\n");
1730 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1731 return FALSE;