Use libwine and libwine_unicode directly from their build directory
[wine/multimedia.git] / files / profile.c
blobc93833277b2a970630a26359d915a9f118f06b3d
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 "windef.h"
18 #include "winbase.h"
19 #include "winnls.h"
20 #include "winerror.h"
21 #include "wine/winbase16.h"
22 #include "winreg.h"
23 #include "file.h"
24 #include "heap.h"
25 #include "debugtools.h"
26 #include "options.h"
27 #include "server.h"
29 DEFAULT_DEBUG_CHANNEL(profile);
31 typedef struct tagPROFILEKEY
33 char *name;
34 char *value;
35 struct tagPROFILEKEY *next;
36 } PROFILEKEY;
38 typedef struct tagPROFILESECTION
40 char *name;
41 struct tagPROFILEKEY *key;
42 struct tagPROFILESECTION *next;
43 } PROFILESECTION;
46 typedef struct
48 BOOL changed;
49 PROFILESECTION *section;
50 char *dos_name;
51 char *unix_name;
52 char *filename;
53 time_t mtime;
54 } PROFILE;
57 #define N_CACHED_PROFILES 10
59 /* Cached profile files */
60 static PROFILE *MRUProfile[N_CACHED_PROFILES]={NULL};
62 #define CurProfile (MRUProfile[0])
64 /* wine.ini config file registry root */
65 static HKEY wine_profile_key;
67 #define PROFILE_MAX_LINE_LEN 1024
69 /* Wine profile name in $HOME directory; must begin with slash */
70 static const char PROFILE_WineIniName[] = "/.winerc";
72 /* Wine profile: the profile file being used */
73 static char PROFILE_WineIniUsed[MAX_PATHNAME_LEN] = "";
75 /* Check for comments in profile */
76 #define IS_ENTRY_COMMENT(str) ((str)[0] == ';')
78 #define WINE_INI_GLOBAL ETCDIR "/wine.conf"
80 static const WCHAR wininiW[] = { 'w','i','n','.','i','n','i',0 };
82 static CRITICAL_SECTION PROFILE_CritSect = CRITICAL_SECTION_INIT;
84 static const char hex[16] = "0123456789ABCDEF";
86 /***********************************************************************
87 * PROFILE_CopyEntry
89 * Copy the content of an entry into a buffer, removing quotes, and possibly
90 * translating environment variables.
92 static void PROFILE_CopyEntry( char *buffer, const char *value, int len,
93 int handle_env )
95 char quote = '\0';
96 const char *p;
98 if ((*value == '\'') || (*value == '\"'))
100 if (value[1] && (value[strlen(value)-1] == *value)) quote = *value++;
103 if (!handle_env)
105 lstrcpynA( buffer, value, len );
106 if (quote && (len >= strlen(value))) buffer[strlen(buffer)-1] = '\0';
107 return;
110 for (p = value; (*p && (len > 1)); *buffer++ = *p++, len-- )
112 if ((*p == '$') && (p[1] == '{'))
114 char env_val[1024];
115 const char *env_p;
116 const char *p2 = strchr( p, '}' );
117 if (!p2) continue; /* ignore it */
118 lstrcpynA(env_val, p + 2, min( sizeof(env_val), (int)(p2-p)-1 ));
119 if ((env_p = getenv( env_val )) != NULL)
121 lstrcpynA( buffer, env_p, len );
122 buffer += strlen( buffer );
123 len -= strlen( buffer );
125 p = p2 + 1;
128 if (quote && (len > 1)) buffer--;
129 *buffer = '\0';
133 /***********************************************************************
134 * PROFILE_Save
136 * Save a profile tree to a file.
138 static void PROFILE_Save( FILE *file, PROFILESECTION *section )
140 PROFILEKEY *key;
142 for ( ; section; section = section->next)
144 if (section->name) fprintf( file, "\r\n[%s]\r\n", section->name );
145 for (key = section->key; key; key = key->next)
147 fprintf( file, "%s", key->name );
148 if (key->value) fprintf( file, "=%s", key->value );
149 fprintf( file, "\r\n" );
155 /***********************************************************************
156 * PROFILE_Free
158 * Free a profile tree.
160 static void PROFILE_Free( PROFILESECTION *section )
162 PROFILESECTION *next_section;
163 PROFILEKEY *key, *next_key;
165 for ( ; section; section = next_section)
167 if (section->name) HeapFree( GetProcessHeap(), 0, section->name );
168 for (key = section->key; key; key = next_key)
170 next_key = key->next;
171 if (key->name) HeapFree( GetProcessHeap(), 0, key->name );
172 if (key->value) HeapFree( GetProcessHeap(), 0, key->value );
173 HeapFree( GetProcessHeap(), 0, key );
175 next_section = section->next;
176 HeapFree( GetProcessHeap(), 0, section );
180 static inline int PROFILE_isspace(char c)
182 if (isspace(c)) return 1;
183 if (c=='\r' || c==0x1a) return 1;
184 /* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */
185 return 0;
189 /***********************************************************************
190 * PROFILE_Load
192 * Load a profile tree from a file.
194 static PROFILESECTION *PROFILE_Load( FILE *file )
196 char buffer[PROFILE_MAX_LINE_LEN];
197 char *p, *p2;
198 int line = 0;
199 PROFILESECTION *section, *first_section;
200 PROFILESECTION **next_section;
201 PROFILEKEY *key, *prev_key, **next_key;
203 first_section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) );
204 if(first_section == NULL) return NULL;
205 first_section->name = NULL;
206 first_section->key = NULL;
207 first_section->next = NULL;
208 next_section = &first_section->next;
209 next_key = &first_section->key;
210 prev_key = NULL;
212 while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
214 line++;
215 p = buffer;
216 while (*p && PROFILE_isspace(*p)) p++;
217 if (*p == '[') /* section start */
219 if (!(p2 = strrchr( p, ']' )))
221 WARN("Invalid section header at line %d: '%s'\n",
222 line, p );
224 else
226 *p2 = '\0';
227 p++;
228 section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) );
229 if(section == NULL) break;
230 section->name = HEAP_strdupA( GetProcessHeap(), 0, p );
231 section->key = NULL;
232 section->next = NULL;
233 *next_section = section;
234 next_section = &section->next;
235 next_key = &section->key;
236 prev_key = NULL;
238 TRACE("New section: '%s'\n",section->name);
240 continue;
244 p2=p+strlen(p) - 1;
245 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
247 if ((p2 = strchr( p, '=' )) != NULL)
249 char *p3 = p2 - 1;
250 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
251 *p2++ = '\0';
252 while (*p2 && PROFILE_isspace(*p2)) p2++;
255 if(*p || !prev_key || *prev_key->name)
257 key = HeapAlloc( GetProcessHeap(), 0, sizeof(*key) );
258 if(key == NULL) break;
259 key->name = HEAP_strdupA( GetProcessHeap(), 0, p );
260 key->value = p2 ? HEAP_strdupA( GetProcessHeap(), 0, p2 ) : NULL;
261 key->next = NULL;
262 *next_key = key;
263 next_key = &key->next;
264 prev_key = key;
266 TRACE("New key: name='%s', value='%s'\n",key->name,key->value?key->value:"(none)");
269 return first_section;
273 /***********************************************************************
274 * PROFILE_RegistryLoad
276 * Load a profile tree from a file into a registry key.
278 static DWORD PROFILE_RegistryLoad( HKEY root, FILE *file )
280 HKEY hkey = 0;
281 DWORD err = 0;
282 char buffer[PROFILE_MAX_LINE_LEN];
283 char *p, *p2;
284 int line = 0;
286 while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
288 line++;
289 p = buffer;
290 while (*p && PROFILE_isspace(*p)) p++;
291 if (*p == '[') /* section start */
293 if (!(p2 = strrchr( p, ']' )))
295 WARN("Invalid section header at line %d: '%s'\n",
296 line, p );
298 else
300 *p2 = '\0';
301 p++;
302 if (hkey) RegCloseKey( hkey );
303 if ((err = RegCreateKeyExA( root, p, 0, NULL, REG_OPTION_VOLATILE,
304 KEY_ALL_ACCESS, NULL, &hkey, NULL ))) return err;
305 TRACE("New section: '%s'\n",p);
306 continue;
310 p2=p+strlen(p) - 1;
311 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
313 if ((p2 = strchr( p, '=' )) != NULL)
315 char *p3 = p2 - 1;
316 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
317 *p2++ = '\0';
318 while (*p2 && PROFILE_isspace(*p2)) p2++;
321 if (*p && hkey && !IS_ENTRY_COMMENT(p))
323 if (!p2) p2 = "";
324 if ((err = RegSetValueExA( hkey, p, 0, REG_SZ, p2, strlen(p2)+1 )))
326 RegCloseKey( hkey );
327 return err;
329 TRACE("New key: name='%s', value='%s'\n",p,p2);
332 if (hkey) RegCloseKey( hkey );
333 return 0;
337 /***********************************************************************
338 * PROFILE_DeleteSection
340 * Delete a section from a profile tree.
342 static BOOL PROFILE_DeleteSection( PROFILESECTION **section, LPCSTR name )
344 while (*section)
346 if ((*section)->name && !strcasecmp( (*section)->name, name ))
348 PROFILESECTION *to_del = *section;
349 *section = to_del->next;
350 to_del->next = NULL;
351 PROFILE_Free( to_del );
352 return TRUE;
354 section = &(*section)->next;
356 return FALSE;
360 /***********************************************************************
361 * PROFILE_DeleteKey
363 * Delete a key from a profile tree.
365 static BOOL PROFILE_DeleteKey( PROFILESECTION **section,
366 LPCSTR section_name, LPCSTR key_name )
368 while (*section)
370 if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
372 PROFILEKEY **key = &(*section)->key;
373 while (*key)
375 if (!strcasecmp( (*key)->name, key_name ))
377 PROFILEKEY *to_del = *key;
378 *key = to_del->next;
379 if (to_del->name) HeapFree( GetProcessHeap(), 0, to_del->name );
380 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
381 HeapFree( GetProcessHeap(), 0, to_del );
382 return TRUE;
384 key = &(*key)->next;
387 section = &(*section)->next;
389 return FALSE;
393 /***********************************************************************
394 * PROFILE_DeleteAllKeys
396 * Delete all keys from a profile tree.
398 void PROFILE_DeleteAllKeys( LPCSTR section_name)
400 PROFILESECTION **section= &CurProfile->section;
401 while (*section)
403 if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
405 PROFILEKEY **key = &(*section)->key;
406 while (*key)
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 CurProfile->changed =TRUE;
416 section = &(*section)->next;
421 /***********************************************************************
422 * PROFILE_Find
424 * Find a key in a profile tree, optionally creating it.
426 static PROFILEKEY *PROFILE_Find( PROFILESECTION **section,
427 const char *section_name,
428 const char *key_name, int create )
430 const char *p;
431 int seclen, keylen;
433 while (PROFILE_isspace(*section_name)) section_name++;
434 p = section_name + strlen(section_name) - 1;
435 while ((p > section_name) && PROFILE_isspace(*p)) p--;
436 seclen = p - section_name + 1;
438 while (PROFILE_isspace(*key_name)) key_name++;
439 p = key_name + strlen(key_name) - 1;
440 while ((p > key_name) && PROFILE_isspace(*p)) p--;
441 keylen = p - key_name + 1;
443 while (*section)
445 if ( ((*section)->name)
446 && (!(strncasecmp( (*section)->name, section_name, seclen )))
447 && (((*section)->name)[seclen] == '\0') )
449 PROFILEKEY **key = &(*section)->key;
450 while (*key)
452 if ( (!(strncasecmp( (*key)->name, key_name, keylen )))
453 && (((*key)->name)[keylen] == '\0') )
454 return *key;
455 key = &(*key)->next;
457 if (!create) return NULL;
458 *key = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) );
459 if(*key == NULL) return NULL;
460 (*key)->name = HEAP_strdupA( GetProcessHeap(), 0, key_name );
461 (*key)->value = NULL;
462 (*key)->next = NULL;
463 return *key;
465 section = &(*section)->next;
467 if (!create) return NULL;
468 *section = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILESECTION) );
469 if(*section == NULL) return NULL;
470 (*section)->name = HEAP_strdupA( GetProcessHeap(), 0, section_name );
471 (*section)->next = NULL;
472 (*section)->key = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) );
473 if((*section)->key == NULL)
475 HeapFree(GetProcessHeap(), 0, *section);
476 return NULL;
478 (*section)->key->name = HEAP_strdupA( GetProcessHeap(), 0, key_name );
479 (*section)->key->value = NULL;
480 (*section)->key->next = NULL;
481 return (*section)->key;
485 /***********************************************************************
486 * PROFILE_FlushFile
488 * Flush the current profile to disk if changed.
490 static BOOL PROFILE_FlushFile(void)
492 char *p, buffer[MAX_PATHNAME_LEN];
493 const char *unix_name;
494 FILE *file = NULL;
495 struct stat buf;
497 if(!CurProfile)
499 WARN("No current profile!\n");
500 return FALSE;
503 if (!CurProfile->changed || !CurProfile->dos_name) return TRUE;
504 if (!(unix_name = CurProfile->unix_name) || !(file = fopen(unix_name, "w")))
506 /* Try to create it in $HOME/.wine */
507 /* FIXME: this will need a more general solution */
508 strcpy( buffer, get_config_dir() );
509 p = buffer + strlen(buffer);
510 *p++ = '/';
511 strcpy( p, strrchr( CurProfile->dos_name, '\\' ) + 1 );
512 _strlwr( p );
513 file = fopen( buffer, "w" );
514 unix_name = buffer;
517 if (!file)
519 WARN("could not save profile file %s\n", CurProfile->dos_name);
520 return FALSE;
523 TRACE("Saving '%s' into '%s'\n", CurProfile->dos_name, unix_name );
524 PROFILE_Save( file, CurProfile->section );
525 fclose( file );
526 CurProfile->changed = FALSE;
527 if(!stat(unix_name,&buf))
528 CurProfile->mtime=buf.st_mtime;
529 return TRUE;
533 /***********************************************************************
534 * PROFILE_ReleaseFile
536 * Flush the current profile to disk and remove it from the cache.
538 static void PROFILE_ReleaseFile(void)
540 PROFILE_FlushFile();
541 PROFILE_Free( CurProfile->section );
542 if (CurProfile->dos_name) HeapFree( GetProcessHeap(), 0, CurProfile->dos_name );
543 if (CurProfile->unix_name) HeapFree( GetProcessHeap(), 0, CurProfile->unix_name );
544 if (CurProfile->filename) HeapFree( GetProcessHeap(), 0, CurProfile->filename );
545 CurProfile->changed = FALSE;
546 CurProfile->section = NULL;
547 CurProfile->dos_name = NULL;
548 CurProfile->unix_name = NULL;
549 CurProfile->filename = NULL;
550 CurProfile->mtime = 0;
554 /***********************************************************************
555 * PROFILE_Open
557 * Open a profile file, checking the cached file first.
559 static BOOL PROFILE_Open( LPCSTR filename )
561 DOS_FULL_NAME full_name;
562 char buffer[MAX_PATHNAME_LEN];
563 char *newdos_name, *p;
564 FILE *file = NULL;
565 int i,j;
566 struct stat buf;
567 PROFILE *tempProfile;
569 /* First time around */
571 if(!CurProfile)
572 for(i=0;i<N_CACHED_PROFILES;i++)
574 MRUProfile[i]=HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILE) );
575 if(MRUProfile[i] == NULL) break;
576 MRUProfile[i]->changed=FALSE;
577 MRUProfile[i]->section=NULL;
578 MRUProfile[i]->dos_name=NULL;
579 MRUProfile[i]->unix_name=NULL;
580 MRUProfile[i]->filename=NULL;
581 MRUProfile[i]->mtime=0;
584 /* Check for a match */
586 if (strchr( filename, '/' ) || strchr( filename, '\\' ) ||
587 strchr( filename, ':' ))
589 if (!DOSFS_GetFullName( filename, FALSE, &full_name )) return FALSE;
591 else
593 GetWindowsDirectoryA( buffer, sizeof(buffer) );
594 strcat( buffer, "\\" );
595 strcat( buffer, filename );
596 if (!DOSFS_GetFullName( buffer, FALSE, &full_name )) return FALSE;
599 for(i=0;i<N_CACHED_PROFILES;i++)
601 if ((MRUProfile[i]->filename && !strcmp( filename, MRUProfile[i]->filename )) ||
602 (MRUProfile[i]->dos_name && !strcmp( full_name.short_name, MRUProfile[i]->dos_name )))
604 if(i)
606 PROFILE_FlushFile();
607 tempProfile=MRUProfile[i];
608 for(j=i;j>0;j--)
609 MRUProfile[j]=MRUProfile[j-1];
610 CurProfile=tempProfile;
612 if(!stat(CurProfile->unix_name,&buf) && CurProfile->mtime==buf.st_mtime)
613 TRACE("(%s): already opened (mru=%d)\n",
614 filename, i );
615 else
616 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
617 filename, i );
618 return TRUE;
622 /* Flush the old current profile */
623 PROFILE_FlushFile();
625 /* Make the oldest profile the current one only in order to get rid of it */
626 if(i==N_CACHED_PROFILES)
628 tempProfile=MRUProfile[N_CACHED_PROFILES-1];
629 for(i=N_CACHED_PROFILES-1;i>0;i--)
630 MRUProfile[i]=MRUProfile[i-1];
631 CurProfile=tempProfile;
633 if(CurProfile->filename) PROFILE_ReleaseFile();
635 /* OK, now that CurProfile is definitely free we assign it our new file */
636 newdos_name = HEAP_strdupA( GetProcessHeap(), 0, full_name.short_name );
637 CurProfile->dos_name = newdos_name;
638 CurProfile->filename = HEAP_strdupA( GetProcessHeap(), 0, filename );
640 /* Try to open the profile file, first in $HOME/.wine */
642 /* FIXME: this will need a more general solution */
643 strcpy( buffer, get_config_dir() );
644 p = buffer + strlen(buffer);
645 *p++ = '/';
646 strcpy( p, strrchr( newdos_name, '\\' ) + 1 );
647 _strlwr( p );
648 if ((file = fopen( buffer, "r" )))
650 TRACE("(%s): found it in %s\n",
651 filename, buffer );
652 CurProfile->unix_name = HEAP_strdupA( GetProcessHeap(), 0, buffer );
655 if (!file)
657 CurProfile->unix_name = HEAP_strdupA( GetProcessHeap(), 0,
658 full_name.long_name );
659 if ((file = fopen( full_name.long_name, "r" )))
660 TRACE("(%s): found it in %s\n",
661 filename, full_name.long_name );
664 if (file)
666 CurProfile->section = PROFILE_Load( file );
667 fclose( file );
668 if(!stat(CurProfile->unix_name,&buf))
669 CurProfile->mtime=buf.st_mtime;
671 else
673 /* Does not exist yet, we will create it in PROFILE_FlushFile */
674 WARN("profile file %s not found\n", newdos_name );
676 return TRUE;
680 /***********************************************************************
681 * PROFILE_GetSection
683 * Returns all keys of a section.
684 * If return_values is TRUE, also include the corresponding values.
686 static INT PROFILE_GetSection( PROFILESECTION *section, LPCSTR section_name,
687 LPSTR buffer, UINT len, BOOL handle_env,
688 BOOL return_values )
690 PROFILEKEY *key;
691 while (section)
693 if (section->name && !strcasecmp( section->name, section_name ))
695 UINT oldlen = len;
696 for (key = section->key; key; key = key->next)
698 if (len <= 2) break;
699 if (!*key->name) continue; /* Skip empty lines */
700 if (IS_ENTRY_COMMENT(key->name)) continue; /* Skip comments */
701 PROFILE_CopyEntry( buffer, key->name, len - 1, handle_env );
702 len -= strlen(buffer) + 1;
703 buffer += strlen(buffer) + 1;
704 if (return_values && key->value) {
705 buffer[-1] = '=';
706 PROFILE_CopyEntry ( buffer,
707 key->value, len - 1, handle_env );
708 len -= strlen(buffer) + 1;
709 buffer += strlen(buffer) + 1;
712 *buffer = '\0';
713 if (len <= 1)
714 /*If either lpszSection or lpszKey is NULL and the supplied
715 destination buffer is too small to hold all the strings,
716 the last string is truncated and followed by two null characters.
717 In this case, the return value is equal to cchReturnBuffer
718 minus two. */
720 buffer[-1] = '\0';
721 return oldlen - 2;
723 return oldlen - len;
725 section = section->next;
727 buffer[0] = buffer[1] = '\0';
728 return 0;
732 static INT PROFILE_GetSectionNames( LPSTR buffer, UINT len )
734 LPSTR buf = buffer;
735 WORD l, cursize = 0;
736 PROFILESECTION *section;
738 for (section = CurProfile->section; section; section = section->next)
739 if (section->name) {
740 l = strlen(section->name);
741 cursize += l+1;
742 if (cursize > len+1)
743 return len-2;
745 strcpy(buf, section->name);
746 buf += l+1;
749 *buf=0;
750 buf++;
751 return buf-buffer;
755 /***********************************************************************
756 * PROFILE_GetString
758 * Get a profile string.
760 * Tests with GetPrivateProfileString16, W95a,
761 * with filled buffer ("****...") and section "set1" and key_name "1" valid:
762 * section key_name def_val res buffer
763 * "set1" "1" "x" 43 [data]
764 * "set1" "1 " "x" 43 [data] (!)
765 * "set1" " 1 "' "x" 43 [data] (!)
766 * "set1" "" "x" 1 "x"
767 * "set1" "" "x " 1 "x" (!)
768 * "set1" "" " x " 3 " x" (!)
769 * "set1" NULL "x" 6 "1\02\03\0\0"
770 * "set1" "" "x" 1 "x"
771 * NULL "1" "x" 0 "" (!)
772 * "" "1" "x" 1 "x"
773 * NULL NULL "" 0 ""
777 static INT PROFILE_GetString( LPCSTR section, LPCSTR key_name,
778 LPCSTR def_val, LPSTR buffer, UINT len )
780 PROFILEKEY *key = NULL;
782 if (!def_val) def_val = "";
783 if (key_name && key_name[0])
785 key = PROFILE_Find( &CurProfile->section, section, key_name, FALSE );
786 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def_val,
787 len, FALSE );
788 TRACE("('%s','%s','%s'): returning '%s'\n",
789 section, key_name, def_val, buffer );
790 return strlen( buffer );
792 if (key_name && !(key_name[0]))
793 /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227 */
794 return 0;
795 if (section && section[0])
796 return PROFILE_GetSection(CurProfile->section, section, buffer, len,
797 FALSE, FALSE);
798 buffer[0] = '\0';
799 return 0;
803 /***********************************************************************
804 * PROFILE_SetString
806 * Set a profile string.
808 static BOOL PROFILE_SetString( LPCSTR section_name, LPCSTR key_name,
809 LPCSTR value )
811 if (!key_name) /* Delete a whole section */
813 TRACE("('%s')\n", section_name);
814 CurProfile->changed |= PROFILE_DeleteSection( &CurProfile->section,
815 section_name );
816 return TRUE; /* Even if PROFILE_DeleteSection() has failed,
817 this is not an error on application's level.*/
819 else if (!value) /* Delete a key */
821 TRACE("('%s','%s')\n",
822 section_name, key_name );
823 CurProfile->changed |= PROFILE_DeleteKey( &CurProfile->section,
824 section_name, key_name );
825 return TRUE; /* same error handling as above */
827 else /* Set the key value */
829 PROFILEKEY *key = PROFILE_Find( &CurProfile->section, section_name,
830 key_name, TRUE );
831 TRACE("('%s','%s','%s'): \n",
832 section_name, key_name, value );
833 if (!key) return FALSE;
834 if (key->value)
836 /* strip the leading spaces. We can safely strip \n\r and
837 * friends too, they should not happen here anyway. */
838 while (PROFILE_isspace(*value)) value++;
840 if (!strcmp( key->value, value ))
842 TRACE(" no change needed\n" );
843 return TRUE; /* No change needed */
845 TRACE(" replacing '%s'\n", key->value );
846 HeapFree( GetProcessHeap(), 0, key->value );
848 else TRACE(" creating key\n" );
849 key->value = HEAP_strdupA( GetProcessHeap(), 0, value );
850 CurProfile->changed = TRUE;
852 return TRUE;
856 /***********************************************************************
857 * PROFILE_GetWineIniString
859 * Get a config string from the wine.ini file.
861 int PROFILE_GetWineIniString( const char *section, const char *key_name,
862 const char *def, char *buffer, int len )
864 char tmp[PROFILE_MAX_LINE_LEN];
865 HKEY hkey;
866 DWORD err;
868 if (!(err = RegOpenKeyA( wine_profile_key, section, &hkey )))
870 DWORD type;
871 DWORD count = sizeof(tmp);
872 err = RegQueryValueExA( hkey, key_name, 0, &type, tmp, &count );
873 RegCloseKey( hkey );
875 PROFILE_CopyEntry( buffer, err ? def : tmp, len, TRUE );
876 TRACE( "('%s','%s','%s'): returning '%s'\n", section, key_name, def, buffer );
877 return strlen(buffer);
881 /***********************************************************************
882 * PROFILE_EnumWineIniString
884 * Get a config string from the wine.ini file.
886 BOOL PROFILE_EnumWineIniString( const char *section, int index,
887 char *name, int name_len, char *buffer, int len )
889 char tmp[PROFILE_MAX_LINE_LEN];
890 HKEY hkey;
891 DWORD err, type;
892 DWORD count = sizeof(tmp);
894 if (RegOpenKeyA( wine_profile_key, section, &hkey )) return FALSE;
895 err = RegEnumValueA( hkey, index, name, (DWORD*)&name_len, NULL, &type, tmp, &count );
896 RegCloseKey( hkey );
897 if (!err)
899 PROFILE_CopyEntry( buffer, tmp, len, TRUE );
900 TRACE( "('%s',%d): returning '%s'='%s'\n", section, index, name, buffer );
902 return !err;
906 /***********************************************************************
907 * PROFILE_GetWineIniInt
909 * Get a config integer from the wine.ini file.
911 int PROFILE_GetWineIniInt( const char *section, const char *key_name, int def )
913 char buffer[20];
914 char *p;
915 long result;
917 PROFILE_GetWineIniString( section, key_name, "", buffer, sizeof(buffer) );
918 if (!buffer[0]) return def;
919 result = strtol( buffer, &p, 0 );
920 return (p == buffer) ? 0 /* No digits at all */ : (int)result;
924 /******************************************************************************
926 * int PROFILE_GetWineIniBool(
927 * char const *section,
928 * char const *key_name,
929 * int def )
931 * Reads a boolean value from the wine.ini file. This function attempts to
932 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
933 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
934 * true. Anything else results in the return of the default value.
936 * This function uses 1 to indicate true, and 0 for false. You can check
937 * for existence by setting def to something other than 0 or 1 and
938 * examining the return value.
940 int PROFILE_GetWineIniBool(
941 char const *section,
942 char const *key_name,
943 int def )
945 char key_value[2];
946 int retval;
948 PROFILE_GetWineIniString(section, key_name, "~", key_value, 2);
950 switch(key_value[0]) {
951 case 'n':
952 case 'N':
953 case 'f':
954 case 'F':
955 case '0':
956 retval = 0;
957 break;
959 case 'y':
960 case 'Y':
961 case 't':
962 case 'T':
963 case '1':
964 retval = 1;
965 break;
967 default:
968 retval = def;
971 TRACE("(\"%s\", \"%s\", %s), "
972 "[%c], ret %s.\n", section, key_name,
973 def ? "TRUE" : "FALSE", key_value[0],
974 retval ? "TRUE" : "FALSE");
976 return retval;
980 /***********************************************************************
981 * PROFILE_LoadWineIni
983 * Load the wine.ini file.
985 int PROFILE_LoadWineIni(void)
987 char buffer[MAX_PATHNAME_LEN];
988 const char *p;
989 FILE *f;
990 HKEY hKeySW;
991 DWORD disp;
993 /* make sure HKLM\\Software\\Wine\\Wine exists as non-volatile key */
994 if (RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine", &hKeySW ))
996 ERR("Cannot create config registry key\n" );
997 return 0;
999 RegCloseKey( hKeySW );
1000 if (RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config", 0, NULL,
1001 REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &wine_profile_key, &disp ))
1003 ERR("Cannot create config registry key\n" );
1004 return 0;
1007 if (!CLIENT_IsBootThread()) return 1; /* already loaded */
1009 if ( (Options.configFileName!=NULL) && (f = fopen(Options.configFileName, "r")) )
1011 /* Open -config specified file */
1012 lstrcpynA(PROFILE_WineIniUsed,Options.configFileName,MAX_PATHNAME_LEN);
1013 goto found;
1016 if ( (p = getenv( "WINE_INI" )) && (f = fopen( p, "r" )) )
1018 lstrcpynA(PROFILE_WineIniUsed,p,MAX_PATHNAME_LEN);
1019 goto found;
1021 if ((p = getenv( "HOME" )) != NULL)
1023 lstrcpynA(buffer, p, MAX_PATHNAME_LEN - sizeof(PROFILE_WineIniName));
1024 strcat( buffer, PROFILE_WineIniName );
1025 if ((f = fopen( buffer, "r" )) != NULL)
1027 lstrcpynA(PROFILE_WineIniUsed,buffer,MAX_PATHNAME_LEN);
1028 goto found;
1031 else WARN("could not get $HOME value for config file.\n" );
1033 /* Try global file */
1035 if ((f = fopen( WINE_INI_GLOBAL, "r" )) != NULL)
1037 lstrcpynA(PROFILE_WineIniUsed,WINE_INI_GLOBAL,MAX_PATHNAME_LEN);
1038 goto found;
1041 if (disp == REG_OPENED_EXISTING_KEY) return 1; /* loaded by the server */
1043 MESSAGE( "Can't open configuration file %s or $HOME%s\n",
1044 WINE_INI_GLOBAL, PROFILE_WineIniName );
1045 return 0;
1047 found:
1049 if (disp == REG_OPENED_EXISTING_KEY)
1051 MESSAGE( "Warning: configuration loaded by the server from %s/config,\n"
1052 " file %s was ignored.\n", get_config_dir(), PROFILE_WineIniUsed );
1053 fclose( f );
1054 return 1;
1057 PROFILE_RegistryLoad( wine_profile_key, f );
1058 fclose( f );
1059 return 1;
1063 /***********************************************************************
1064 * PROFILE_UsageWineIni
1066 * Explain the wine.ini file to those who don't read documentation.
1067 * Keep below one screenful in length so that error messages above are
1068 * noticed.
1070 void PROFILE_UsageWineIni(void)
1072 MESSAGE("Perhaps you have not properly edited or created "
1073 "your Wine configuration file.\n");
1074 MESSAGE("This is either %s or $HOME%s\n",WINE_INI_GLOBAL,PROFILE_WineIniName);
1075 MESSAGE(" or it is determined by the -config option or from\n"
1076 " the WINE_INI environment variable.\n");
1077 if (*PROFILE_WineIniUsed)
1078 MESSAGE("Wine has used %s as configuration file.\n", PROFILE_WineIniUsed);
1079 /* RTFM, so to say */
1082 /***********************************************************************
1083 * PROFILE_GetStringItem
1085 * Convenience function that turns a string 'xxx, yyy, zzz' into
1086 * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
1088 char* PROFILE_GetStringItem( char* start )
1090 char* lpchX, *lpch;
1092 for (lpchX = start, lpch = NULL; *lpchX != '\0'; lpchX++ )
1094 if( *lpchX == ',' )
1096 if( lpch ) *lpch = '\0'; else *lpchX = '\0';
1097 while( *(++lpchX) )
1098 if( !PROFILE_isspace(*lpchX) ) return lpchX;
1100 else if( PROFILE_isspace( *lpchX ) && !lpch ) lpch = lpchX;
1101 else lpch = NULL;
1103 if( lpch ) *lpch = '\0';
1104 return NULL;
1107 /********************* API functions **********************************/
1109 /***********************************************************************
1110 * GetProfileInt16 (KERNEL.57)
1112 UINT16 WINAPI GetProfileInt16( LPCSTR section, LPCSTR entry, INT16 def_val )
1114 return GetPrivateProfileInt16( section, entry, def_val, "win.ini" );
1118 /***********************************************************************
1119 * GetProfileIntA (KERNEL32.264)
1121 UINT WINAPI GetProfileIntA( LPCSTR section, LPCSTR entry, INT def_val )
1123 return GetPrivateProfileIntA( section, entry, def_val, "win.ini" );
1126 /***********************************************************************
1127 * GetProfileIntW (KERNEL32.264)
1129 UINT WINAPI GetProfileIntW( LPCWSTR section, LPCWSTR entry, INT def_val )
1131 return GetPrivateProfileIntW( section, entry, def_val, wininiW );
1135 * undoc_feature means:
1136 * return section names string list if both section and entry are NULL.
1138 static int PROFILE_GetPrivateProfileString( LPCSTR section, LPCSTR entry,
1139 LPCSTR def_val, LPSTR buffer,
1140 UINT16 len, LPCSTR filename,
1141 BOOL undoc_feature )
1143 int ret;
1144 LPSTR pDefVal = NULL;
1146 if (!filename)
1147 filename = "win.ini";
1149 /* strip any trailing ' ' of def_val. */
1150 if (def_val)
1152 LPSTR p = (LPSTR)&def_val[strlen(def_val)]; /* even "" works ! */
1154 while (p > def_val)
1156 p--;
1157 if ((*p) != ' ')
1158 break;
1160 if (*p == ' ') /* ouch, contained trailing ' ' */
1162 int len = (int)p - (int)def_val;
1163 pDefVal = HeapAlloc(GetProcessHeap(), 0, len + 1);
1164 strncpy(pDefVal, def_val, len);
1165 pDefVal[len] = '\0';
1168 if (!pDefVal)
1169 pDefVal = (LPSTR)def_val;
1171 EnterCriticalSection( &PROFILE_CritSect );
1173 if (PROFILE_Open( filename )) {
1174 if ((undoc_feature) && (section == NULL) && (entry == NULL))
1175 /* undocumented; both section and entry are NULL */
1176 ret = PROFILE_GetSectionNames(buffer, len);
1177 else
1178 ret = PROFILE_GetString( section, entry, pDefVal, buffer, len );
1179 } else {
1180 lstrcpynA( buffer, pDefVal, len );
1181 ret = strlen( buffer );
1184 LeaveCriticalSection( &PROFILE_CritSect );
1186 if (pDefVal != def_val) /* allocated */
1187 HeapFree(GetProcessHeap(), 0, pDefVal);
1189 return ret;
1192 /***********************************************************************
1193 * GetPrivateProfileString16 (KERNEL.128)
1195 INT16 WINAPI GetPrivateProfileString16( LPCSTR section, LPCSTR entry,
1196 LPCSTR def_val, LPSTR buffer,
1197 UINT16 len, LPCSTR filename )
1199 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1200 buffer, len, filename, FALSE );
1203 /***********************************************************************
1204 * GetPrivateProfileStringA (KERNEL32.255)
1206 INT WINAPI GetPrivateProfileStringA( LPCSTR section, LPCSTR entry,
1207 LPCSTR def_val, LPSTR buffer,
1208 UINT len, LPCSTR filename )
1210 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1211 buffer, len, filename, TRUE );
1214 /***********************************************************************
1215 * GetPrivateProfileStringW (KERNEL32.256)
1217 INT WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1218 LPCWSTR def_val, LPWSTR buffer,
1219 UINT len, LPCWSTR filename )
1221 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1222 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1223 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1224 LPSTR def_valA = HEAP_strdupWtoA( GetProcessHeap(), 0, def_val );
1225 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1226 INT ret = GetPrivateProfileStringA( sectionA, entryA, def_valA,
1227 bufferA, len, filenameA );
1228 if (len > 0 && !MultiByteToWideChar( CP_ACP, 0, bufferA, -1, buffer, len ))
1229 buffer[len-1] = 0;
1230 HeapFree( GetProcessHeap(), 0, sectionA );
1231 HeapFree( GetProcessHeap(), 0, entryA );
1232 HeapFree( GetProcessHeap(), 0, filenameA );
1233 HeapFree( GetProcessHeap(), 0, def_valA );
1234 HeapFree( GetProcessHeap(), 0, bufferA);
1235 return ret;
1238 /***********************************************************************
1239 * GetProfileString16 (KERNEL.58)
1241 INT16 WINAPI GetProfileString16( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1242 LPSTR buffer, UINT16 len )
1244 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1245 buffer, len, "win.ini", FALSE );
1248 /***********************************************************************
1249 * GetProfileStringA (KERNEL32.268)
1251 INT WINAPI GetProfileStringA( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1252 LPSTR buffer, UINT len )
1254 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1255 buffer, len, "win.ini", TRUE );
1258 /***********************************************************************
1259 * GetProfileStringW (KERNEL32.269)
1261 INT WINAPI GetProfileStringW( LPCWSTR section, LPCWSTR entry,
1262 LPCWSTR def_val, LPWSTR buffer, UINT len )
1264 return GetPrivateProfileStringW( section, entry, def_val,
1265 buffer, len, wininiW );
1268 /***********************************************************************
1269 * WriteProfileString16 (KERNEL.59)
1271 BOOL16 WINAPI WriteProfileString16( LPCSTR section, LPCSTR entry,
1272 LPCSTR string )
1274 return WritePrivateProfileString16( section, entry, string, "win.ini" );
1277 /***********************************************************************
1278 * WriteProfileStringA (KERNEL32.587)
1280 BOOL WINAPI WriteProfileStringA( LPCSTR section, LPCSTR entry,
1281 LPCSTR string )
1283 return WritePrivateProfileStringA( section, entry, string, "win.ini" );
1286 /***********************************************************************
1287 * WriteProfileStringW (KERNEL32.588)
1289 BOOL WINAPI WriteProfileStringW( LPCWSTR section, LPCWSTR entry,
1290 LPCWSTR string )
1292 return WritePrivateProfileStringW( section, entry, string, wininiW );
1296 /***********************************************************************
1297 * GetPrivateProfileInt16 (KERNEL.127)
1299 UINT16 WINAPI GetPrivateProfileInt16( LPCSTR section, LPCSTR entry,
1300 INT16 def_val, LPCSTR filename )
1302 long result=(long)GetPrivateProfileIntA(section,entry,def_val,filename);
1304 if (result > 65535) return 65535;
1305 if (result >= 0) return (UINT16)result;
1306 if (result < -32768) return -32768;
1307 return (UINT16)(INT16)result;
1310 /***********************************************************************
1311 * GetPrivateProfileIntA (KERNEL32.251)
1313 UINT WINAPI GetPrivateProfileIntA( LPCSTR section, LPCSTR entry,
1314 INT def_val, LPCSTR filename )
1316 char buffer[20];
1317 char *p;
1318 long result;
1320 PROFILE_GetPrivateProfileString( section, entry, "",
1321 buffer, sizeof(buffer), filename, FALSE );
1322 if (!buffer[0]) return (UINT)def_val;
1323 result = strtol( buffer, &p, 0 );
1324 if (p == buffer) return 0; /* No digits at all */
1325 return (UINT)result;
1328 /***********************************************************************
1329 * GetPrivateProfileIntW (KERNEL32.252)
1331 UINT WINAPI GetPrivateProfileIntW( LPCWSTR section, LPCWSTR entry,
1332 INT def_val, LPCWSTR filename )
1334 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1335 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1336 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1337 UINT res = GetPrivateProfileIntA(sectionA, entryA, def_val, filenameA);
1338 HeapFree( GetProcessHeap(), 0, sectionA );
1339 HeapFree( GetProcessHeap(), 0, filenameA );
1340 HeapFree( GetProcessHeap(), 0, entryA );
1341 return res;
1344 /***********************************************************************
1345 * GetPrivateProfileSection16 (KERNEL.418)
1347 INT16 WINAPI GetPrivateProfileSection16( LPCSTR section, LPSTR buffer,
1348 UINT16 len, LPCSTR filename )
1350 return GetPrivateProfileSectionA( section, buffer, len, filename );
1353 /***********************************************************************
1354 * GetPrivateProfileSectionA (KERNEL32.255)
1356 INT WINAPI GetPrivateProfileSectionA( LPCSTR section, LPSTR buffer,
1357 DWORD len, LPCSTR filename )
1359 int ret = 0;
1361 EnterCriticalSection( &PROFILE_CritSect );
1363 if (PROFILE_Open( filename ))
1364 ret = PROFILE_GetSection(CurProfile->section, section, buffer, len,
1365 FALSE, TRUE);
1367 LeaveCriticalSection( &PROFILE_CritSect );
1369 return ret;
1372 /***********************************************************************
1373 * GetPrivateProfileSectionW (KERNEL32.256)
1376 INT WINAPI GetPrivateProfileSectionW (LPCWSTR section, LPWSTR buffer,
1377 DWORD len, LPCWSTR filename )
1380 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1381 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1382 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1383 INT ret = GetPrivateProfileSectionA( sectionA, bufferA, len,
1384 filenameA );
1385 MultiByteToWideChar(CP_ACP,0,bufferA,ret,buffer,len);
1386 HeapFree( GetProcessHeap(), 0, sectionA );
1387 HeapFree( GetProcessHeap(), 0, filenameA );
1388 HeapFree( GetProcessHeap(), 0, bufferA);
1389 return ret;
1392 /***********************************************************************
1393 * GetProfileSection16 (KERNEL.419)
1395 INT16 WINAPI GetProfileSection16( LPCSTR section, LPSTR buffer, UINT16 len )
1397 return GetPrivateProfileSection16( section, buffer, len, "win.ini" );
1400 /***********************************************************************
1401 * GetProfileSectionA (KERNEL32.268)
1403 INT WINAPI GetProfileSectionA( LPCSTR section, LPSTR buffer, DWORD len )
1405 return GetPrivateProfileSectionA( section, buffer, len, "win.ini" );
1408 /***********************************************************************
1409 * GetProfileSectionW (KERNEL32)
1411 INT WINAPI GetProfileSectionW( LPCWSTR section, LPWSTR buffer, DWORD len )
1413 return GetPrivateProfileSectionW( section, buffer, len, wininiW );
1417 /***********************************************************************
1418 * WritePrivateProfileString16 (KERNEL.129)
1420 BOOL16 WINAPI WritePrivateProfileString16( LPCSTR section, LPCSTR entry,
1421 LPCSTR string, LPCSTR filename )
1423 return WritePrivateProfileStringA(section,entry,string,filename);
1426 /***********************************************************************
1427 * WritePrivateProfileStringA (KERNEL32.582)
1429 BOOL WINAPI WritePrivateProfileStringA( LPCSTR section, LPCSTR entry,
1430 LPCSTR string, LPCSTR filename )
1432 BOOL ret = FALSE;
1434 EnterCriticalSection( &PROFILE_CritSect );
1436 if (PROFILE_Open( filename ))
1438 if (!section && !entry && !string)
1439 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1440 else
1441 ret = PROFILE_SetString( section, entry, string );
1444 LeaveCriticalSection( &PROFILE_CritSect );
1445 return ret;
1448 /***********************************************************************
1449 * WritePrivateProfileStringW (KERNEL32.583)
1451 BOOL WINAPI WritePrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1452 LPCWSTR string, LPCWSTR filename )
1454 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1455 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1456 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1457 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1458 BOOL res = WritePrivateProfileStringA( sectionA, entryA,
1459 stringA, filenameA );
1460 HeapFree( GetProcessHeap(), 0, sectionA );
1461 HeapFree( GetProcessHeap(), 0, entryA );
1462 HeapFree( GetProcessHeap(), 0, stringA );
1463 HeapFree( GetProcessHeap(), 0, filenameA );
1464 return res;
1467 /***********************************************************************
1468 * WritePrivateProfileSection16 (KERNEL.416)
1470 BOOL16 WINAPI WritePrivateProfileSection16( LPCSTR section,
1471 LPCSTR string, LPCSTR filename )
1473 return WritePrivateProfileSectionA( section, string, filename );
1476 /***********************************************************************
1477 * WritePrivateProfileSectionA (KERNEL32)
1479 BOOL WINAPI WritePrivateProfileSectionA( LPCSTR section,
1480 LPCSTR string, LPCSTR filename )
1482 BOOL ret = FALSE;
1483 LPSTR p ;
1485 EnterCriticalSection( &PROFILE_CritSect );
1487 if (PROFILE_Open( filename )) {
1488 if (!section && !string)
1489 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1490 else if (!string) /* delete the named section*/
1491 ret = PROFILE_SetString(section,NULL,NULL);
1492 else {
1493 PROFILE_DeleteAllKeys(section);
1494 ret = TRUE;
1495 while(*string) {
1496 LPSTR buf=HEAP_strdupA( GetProcessHeap(), 0, string );
1497 if((p=strchr( buf, '='))){
1498 *p='\0';
1499 ret = PROFILE_SetString( section, buf, p+1 );
1502 HeapFree( GetProcessHeap(), 0, buf );
1503 string += strlen(string)+1;
1509 LeaveCriticalSection( &PROFILE_CritSect );
1510 return ret;
1513 /***********************************************************************
1514 * WritePrivateProfileSectionW (KERNEL32)
1516 BOOL WINAPI WritePrivateProfileSectionW( LPCWSTR section,
1517 LPCWSTR string, LPCWSTR filename)
1520 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1521 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1522 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1523 BOOL res = WritePrivateProfileSectionA( sectionA, stringA, filenameA );
1524 HeapFree( GetProcessHeap(), 0, sectionA );
1525 HeapFree( GetProcessHeap(), 0, stringA );
1526 HeapFree( GetProcessHeap(), 0, filenameA );
1527 return res;
1530 /***********************************************************************
1531 * WriteProfileSection16 (KERNEL.417)
1533 BOOL16 WINAPI WriteProfileSection16( LPCSTR section, LPCSTR keys_n_values)
1535 return WritePrivateProfileSection16( section, keys_n_values, "win.ini");
1538 /***********************************************************************
1539 * WriteProfileSectionA (KERNEL32.747)
1541 BOOL WINAPI WriteProfileSectionA( LPCSTR section, LPCSTR keys_n_values)
1544 return WritePrivateProfileSectionA( section, keys_n_values, "win.ini");
1547 /***********************************************************************
1548 * WriteProfileSectionW (KERNEL32.748)
1550 BOOL WINAPI WriteProfileSectionW( LPCWSTR section, LPCWSTR keys_n_values)
1552 return (WritePrivateProfileSectionW (section,keys_n_values, wininiW));
1555 /***********************************************************************
1556 * GetPrivateProfileSectionNames16 (KERNEL.143)
1558 WORD WINAPI GetPrivateProfileSectionNames16( LPSTR buffer, WORD size,
1559 LPCSTR filename )
1561 WORD ret = 0;
1563 EnterCriticalSection( &PROFILE_CritSect );
1565 if (PROFILE_Open( filename ))
1566 ret = PROFILE_GetSectionNames(buffer, size);
1568 LeaveCriticalSection( &PROFILE_CritSect );
1570 return ret;
1574 /***********************************************************************
1575 * GetProfileSectionNames16 (KERNEL.142)
1577 WORD WINAPI GetProfileSectionNames16( LPSTR buffer, WORD size)
1580 return (GetPrivateProfileSectionNames16 (buffer,size,"win.ini"));
1584 /***********************************************************************
1585 * GetPrivateProfileSectionNamesA (KERNEL32.365)
1587 DWORD WINAPI GetPrivateProfileSectionNamesA( LPSTR buffer, DWORD size,
1588 LPCSTR filename)
1591 return (GetPrivateProfileSectionNames16 (buffer,size,filename));
1595 /***********************************************************************
1596 * GetPrivateProfileSectionNamesW (KERNEL32.366)
1598 DWORD WINAPI GetPrivateProfileSectionNamesW( LPWSTR buffer, DWORD size,
1599 LPCWSTR filename)
1602 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1603 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, size);
1605 INT ret = GetPrivateProfileSectionNames16 (bufferA, size, filenameA);
1606 if (size > 0 && !MultiByteToWideChar( CP_ACP, 0, bufferA, -1, buffer, size ))
1607 buffer[size-1] = 0;
1608 HeapFree( GetProcessHeap(), 0, bufferA);
1609 HeapFree( GetProcessHeap(), 0, filenameA );
1611 return ret;
1614 /***********************************************************************
1615 * GetPrivateProfileStruct16 (KERNEL.407)
1617 BOOL16 WINAPI GetPrivateProfileStruct16(LPCSTR section, LPCSTR key,
1618 LPVOID buf, UINT16 len, LPCSTR filename)
1620 return GetPrivateProfileStructA( section, key, buf, len, filename );
1623 /***********************************************************************
1624 * GetPrivateProfileStructA (KERNEL32.370)
1626 * Should match Win95's behaviour pretty much
1628 BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key,
1629 LPVOID buf, UINT len, LPCSTR filename)
1631 BOOL ret = FALSE;
1633 EnterCriticalSection( &PROFILE_CritSect );
1635 if (PROFILE_Open( filename )) {
1636 PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE);
1637 if (k) {
1638 TRACE("value (at %p): '%s'\n", k->value, k->value);
1639 if (((strlen(k->value) - 2) / 2) == len)
1641 LPSTR end, p;
1642 BOOL valid = TRUE;
1643 CHAR c;
1644 DWORD chksum = 0;
1646 end = k->value + strlen(k->value); /* -> '\0' */
1647 /* check for invalid chars in ASCII coded hex string */
1648 for (p=k->value; p < end; p++)
1650 if (!isxdigit(*p))
1652 WARN("invalid char '%c' in file '%s'->'[%s]'->'%s' !\n",
1653 *p, filename, section, key);
1654 valid = FALSE;
1655 break;
1658 if (valid)
1660 BOOL highnibble = TRUE;
1661 BYTE b = 0, val;
1662 LPBYTE binbuf = (LPBYTE)buf;
1664 end -= 2; /* don't include checksum in output data */
1665 /* translate ASCII hex format into binary data */
1666 for (p=k->value; p < end; p++)
1668 c = toupper(*p);
1669 val = (c > '9') ?
1670 (c - 'A' + 10) : (c - '0');
1672 if (highnibble)
1673 b = val << 4;
1674 else
1676 b += val;
1677 *binbuf++ = b; /* feed binary data into output */
1678 chksum += b; /* calculate checksum */
1680 highnibble ^= 1; /* toggle */
1682 /* retrieve stored checksum value */
1683 c = toupper(*p++);
1684 b = ( (c > '9') ? (c - 'A' + 10) : (c - '0') ) << 4;
1685 c = toupper(*p);
1686 b += (c > '9') ? (c - 'A' + 10) : (c - '0');
1687 if (b == (chksum & 0xff)) /* checksums match ? */
1688 ret = TRUE;
1693 LeaveCriticalSection( &PROFILE_CritSect );
1695 return ret;
1698 /***********************************************************************
1699 * GetPrivateProfileStructW (KERNEL32.543)
1701 BOOL WINAPI GetPrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1702 LPVOID buffer, UINT len, LPCWSTR filename)
1704 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1705 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1706 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1707 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1709 INT ret = GetPrivateProfileStructA( sectionA, keyA, bufferA,
1710 len, filenameA );
1711 if (len > 0 && !MultiByteToWideChar( CP_ACP, 0, bufferA, -1, buffer, len ))
1712 ((LPWSTR)buffer)[len-1] = 0;
1713 HeapFree( GetProcessHeap(), 0, bufferA);
1714 HeapFree( GetProcessHeap(), 0, sectionA );
1715 HeapFree( GetProcessHeap(), 0, keyA );
1716 HeapFree( GetProcessHeap(), 0, filenameA );
1718 return ret;
1723 /***********************************************************************
1724 * WritePrivateProfileStruct16 (KERNEL.406)
1726 BOOL16 WINAPI WritePrivateProfileStruct16 (LPCSTR section, LPCSTR key,
1727 LPVOID buf, UINT16 bufsize, LPCSTR filename)
1729 return WritePrivateProfileStructA( section, key, buf, bufsize, filename );
1732 /***********************************************************************
1733 * WritePrivateProfileStructA (KERNEL32.744)
1735 BOOL WINAPI WritePrivateProfileStructA (LPCSTR section, LPCSTR key,
1736 LPVOID buf, UINT bufsize, LPCSTR filename)
1738 BOOL ret = FALSE;
1739 LPBYTE binbuf;
1740 LPSTR outstring, p;
1741 DWORD sum = 0;
1743 if (!section && !key && !buf) /* flush the cache */
1744 return WritePrivateProfileStringA( NULL, NULL, NULL, filename );
1746 /* allocate string buffer for hex chars + checksum hex char + '\0' */
1747 outstring = HeapAlloc( GetProcessHeap(), 0, bufsize*2 + 2 + 1);
1748 p = outstring;
1749 for (binbuf = (LPBYTE)buf; binbuf < (LPBYTE)buf+bufsize; binbuf++) {
1750 *p++ = hex[*binbuf >> 4];
1751 *p++ = hex[*binbuf & 0xf];
1752 sum += *binbuf;
1754 /* checksum is sum & 0xff */
1755 *p++ = hex[(sum & 0xf0) >> 4];
1756 *p++ = hex[sum & 0xf];
1757 *p++ = '\0';
1759 EnterCriticalSection( &PROFILE_CritSect );
1761 if (PROFILE_Open( filename ))
1762 ret = PROFILE_SetString( section, key, outstring );
1764 LeaveCriticalSection( &PROFILE_CritSect );
1766 HeapFree( GetProcessHeap(), 0, outstring );
1768 return ret;
1771 /***********************************************************************
1772 * WritePrivateProfileStructW (KERNEL32.544)
1774 BOOL WINAPI WritePrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1775 LPVOID buf, UINT bufsize, LPCWSTR filename)
1777 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1778 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1779 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1780 INT ret = WritePrivateProfileStructA( sectionA, keyA, buf, bufsize,
1781 filenameA );
1782 HeapFree( GetProcessHeap(), 0, sectionA );
1783 HeapFree( GetProcessHeap(), 0, keyA );
1784 HeapFree( GetProcessHeap(), 0, filenameA );
1786 return ret;
1790 /***********************************************************************
1791 * WriteOutProfiles (KERNEL.315)
1793 void WINAPI WriteOutProfiles16(void)
1795 EnterCriticalSection( &PROFILE_CritSect );
1796 PROFILE_FlushFile();
1797 LeaveCriticalSection( &PROFILE_CritSect );
1800 /***********************************************************************
1801 * CloseProfileUserMapping (KERNEL.138)
1803 BOOL WINAPI CloseProfileUserMapping(void) {
1804 FIXME("(), stub!\n");
1805 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1806 return FALSE;