Small typo fix.
[wine.git] / files / profile.c
blobb198dca43da10dc26751da1f2dc978e27474043e
1 /*
2 * Profile functions
4 * Copyright 1993 Miguel de Icaza
5 * Copyright 1996 Alexandre Julliard
6 */
8 #include <ctype.h>
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <stdio.h>
14 #include <sys/stat.h>
15 #include <sys/types.h>
16 #include <pwd.h>
17 #include <unistd.h>
19 #include "windef.h"
20 #include "winbase.h"
21 #include "winnls.h"
22 #include "winerror.h"
23 #include "wine/winbase16.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 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(!buffer) return;
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;
274 /* convert the .winerc file to the new format */
275 static void convert_config( FILE *in, const char *output_name )
277 char buffer[PROFILE_MAX_LINE_LEN];
278 char *p, *p2;
279 FILE *out;
281 /* create the output file, only if it doesn't exist already */
282 int fd = open( output_name, O_WRONLY|O_CREAT|O_EXCL, 0666 );
283 if (fd == -1)
285 MESSAGE( "Could not create new config file '%s': %s\n", output_name, strerror(errno) );
286 ExitProcess(1);
289 out = fdopen( fd, "w" );
290 fprintf( out, "WINE REGISTRY Version 2\n" );
291 fprintf( out, ";; All keys relative to \\\\Machine\\\\Software\\\\Wine\\\\Wine\\\\Config\n\n" );
292 while (fgets( buffer, PROFILE_MAX_LINE_LEN, in ))
294 if (buffer[strlen(buffer)-1] == '\n') buffer[strlen(buffer)-1] = 0;
295 p = buffer;
296 while (*p && PROFILE_isspace(*p)) p++;
297 if (*p == '[') /* section start */
299 if ((p2 = strrchr( p, ']' )))
301 *p2 = '\0';
302 p++;
303 fprintf( out, "[%s]\n", p );
305 continue;
308 if (*p == ';' || *p == '#')
310 fprintf( out, "%s\n", p );
311 continue;
314 p2=p+strlen(p) - 1;
315 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
317 if ((p2 = strchr( p, '=' )) != NULL)
319 char *p3 = p2 - 1;
320 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
321 *p2++ = '\0';
322 while (*p2 && PROFILE_isspace(*p2)) p2++;
325 if (!*p)
327 fprintf( out, "\n" );
328 continue;
330 fputc( '"', out );
331 while (*p)
333 if (*p == '\\') fputc( '\\', out );
334 fputc( *p, out );
335 p++;
337 fprintf( out, "\" = \"" );
338 if (p2)
340 while (*p2)
342 if (*p2 == '\\') fputc( '\\', out );
343 fputc( *p2, out );
344 p2++;
347 fprintf( out, "\"\n" );
349 fclose( out );
353 /***********************************************************************
354 * PROFILE_DeleteSection
356 * Delete a section from a profile tree.
358 static BOOL PROFILE_DeleteSection( PROFILESECTION **section, LPCSTR name )
360 while (*section)
362 if ((*section)->name && !strcasecmp( (*section)->name, name ))
364 PROFILESECTION *to_del = *section;
365 *section = to_del->next;
366 to_del->next = NULL;
367 PROFILE_Free( to_del );
368 return TRUE;
370 section = &(*section)->next;
372 return FALSE;
376 /***********************************************************************
377 * PROFILE_DeleteKey
379 * Delete a key from a profile tree.
381 static BOOL PROFILE_DeleteKey( PROFILESECTION **section,
382 LPCSTR section_name, LPCSTR key_name )
384 while (*section)
386 if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
388 PROFILEKEY **key = &(*section)->key;
389 while (*key)
391 if (!strcasecmp( (*key)->name, key_name ))
393 PROFILEKEY *to_del = *key;
394 *key = to_del->next;
395 if (to_del->name) HeapFree( GetProcessHeap(), 0, to_del->name );
396 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
397 HeapFree( GetProcessHeap(), 0, to_del );
398 return TRUE;
400 key = &(*key)->next;
403 section = &(*section)->next;
405 return FALSE;
409 /***********************************************************************
410 * PROFILE_DeleteAllKeys
412 * Delete all keys from a profile tree.
414 void PROFILE_DeleteAllKeys( LPCSTR section_name)
416 PROFILESECTION **section= &CurProfile->section;
417 while (*section)
419 if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
421 PROFILEKEY **key = &(*section)->key;
422 while (*key)
424 PROFILEKEY *to_del = *key;
425 *key = to_del->next;
426 if (to_del->name) HeapFree( GetProcessHeap(), 0, to_del->name );
427 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
428 HeapFree( GetProcessHeap(), 0, to_del );
429 CurProfile->changed =TRUE;
432 section = &(*section)->next;
437 /***********************************************************************
438 * PROFILE_Find
440 * Find a key in a profile tree, optionally creating it.
442 static PROFILEKEY *PROFILE_Find( PROFILESECTION **section,
443 const char *section_name,
444 const char *key_name, int create )
446 const char *p;
447 int seclen, keylen;
449 while (PROFILE_isspace(*section_name)) section_name++;
450 p = section_name + strlen(section_name) - 1;
451 while ((p > section_name) && PROFILE_isspace(*p)) p--;
452 seclen = p - section_name + 1;
454 while (PROFILE_isspace(*key_name)) key_name++;
455 p = key_name + strlen(key_name) - 1;
456 while ((p > key_name) && PROFILE_isspace(*p)) p--;
457 keylen = p - key_name + 1;
459 while (*section)
461 if ( ((*section)->name)
462 && (!(strncasecmp( (*section)->name, section_name, seclen )))
463 && (((*section)->name)[seclen] == '\0') )
465 PROFILEKEY **key = &(*section)->key;
466 while (*key)
468 if ( (!(strncasecmp( (*key)->name, key_name, keylen )))
469 && (((*key)->name)[keylen] == '\0') )
470 return *key;
471 key = &(*key)->next;
473 if (!create) return NULL;
474 *key = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) );
475 if(*key == NULL) return NULL;
476 (*key)->name = HEAP_strdupA( GetProcessHeap(), 0, key_name );
477 (*key)->value = NULL;
478 (*key)->next = NULL;
479 return *key;
481 section = &(*section)->next;
483 if (!create) return NULL;
484 *section = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILESECTION) );
485 if(*section == NULL) return NULL;
486 (*section)->name = HEAP_strdupA( GetProcessHeap(), 0, section_name );
487 (*section)->next = NULL;
488 (*section)->key = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) );
489 if((*section)->key == NULL)
491 HeapFree(GetProcessHeap(), 0, *section);
492 return NULL;
494 (*section)->key->name = HEAP_strdupA( GetProcessHeap(), 0, key_name );
495 (*section)->key->value = NULL;
496 (*section)->key->next = NULL;
497 return (*section)->key;
501 /***********************************************************************
502 * PROFILE_FlushFile
504 * Flush the current profile to disk if changed.
506 static BOOL PROFILE_FlushFile(void)
508 char *p, buffer[MAX_PATHNAME_LEN];
509 const char *unix_name;
510 FILE *file = NULL;
511 struct stat buf;
513 if(!CurProfile)
515 WARN("No current profile!\n");
516 return FALSE;
519 if (!CurProfile->changed || !CurProfile->dos_name) return TRUE;
520 if (!(unix_name = CurProfile->unix_name) || !(file = fopen(unix_name, "w")))
522 /* Try to create it in $HOME/.wine */
523 /* FIXME: this will need a more general solution */
524 strcpy( buffer, get_config_dir() );
525 p = buffer + strlen(buffer);
526 *p++ = '/';
527 strcpy( p, strrchr( CurProfile->dos_name, '\\' ) + 1 );
528 _strlwr( p );
529 file = fopen( buffer, "w" );
530 unix_name = buffer;
533 if (!file)
535 WARN("could not save profile file %s\n", CurProfile->dos_name);
536 return FALSE;
539 TRACE("Saving '%s' into '%s'\n", CurProfile->dos_name, unix_name );
540 PROFILE_Save( file, CurProfile->section );
541 fclose( file );
542 CurProfile->changed = FALSE;
543 if(!stat(unix_name,&buf))
544 CurProfile->mtime=buf.st_mtime;
545 return TRUE;
549 /***********************************************************************
550 * PROFILE_ReleaseFile
552 * Flush the current profile to disk and remove it from the cache.
554 static void PROFILE_ReleaseFile(void)
556 PROFILE_FlushFile();
557 PROFILE_Free( CurProfile->section );
558 if (CurProfile->dos_name) HeapFree( GetProcessHeap(), 0, CurProfile->dos_name );
559 if (CurProfile->unix_name) HeapFree( GetProcessHeap(), 0, CurProfile->unix_name );
560 if (CurProfile->filename) HeapFree( GetProcessHeap(), 0, CurProfile->filename );
561 CurProfile->changed = FALSE;
562 CurProfile->section = NULL;
563 CurProfile->dos_name = NULL;
564 CurProfile->unix_name = NULL;
565 CurProfile->filename = NULL;
566 CurProfile->mtime = 0;
570 /***********************************************************************
571 * PROFILE_Open
573 * Open a profile file, checking the cached file first.
575 static BOOL PROFILE_Open( LPCSTR filename )
577 DOS_FULL_NAME full_name;
578 char buffer[MAX_PATHNAME_LEN];
579 char *newdos_name, *p;
580 FILE *file = NULL;
581 int i,j;
582 struct stat buf;
583 PROFILE *tempProfile;
585 /* First time around */
587 if(!CurProfile)
588 for(i=0;i<N_CACHED_PROFILES;i++)
590 MRUProfile[i]=HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILE) );
591 if(MRUProfile[i] == NULL) break;
592 MRUProfile[i]->changed=FALSE;
593 MRUProfile[i]->section=NULL;
594 MRUProfile[i]->dos_name=NULL;
595 MRUProfile[i]->unix_name=NULL;
596 MRUProfile[i]->filename=NULL;
597 MRUProfile[i]->mtime=0;
600 /* Check for a match */
602 if (strchr( filename, '/' ) || strchr( filename, '\\' ) ||
603 strchr( filename, ':' ))
605 if (!DOSFS_GetFullName( filename, FALSE, &full_name )) return FALSE;
607 else
609 GetWindowsDirectoryA( buffer, sizeof(buffer) );
610 strcat( buffer, "\\" );
611 strcat( buffer, filename );
612 if (!DOSFS_GetFullName( buffer, FALSE, &full_name )) return FALSE;
615 for(i=0;i<N_CACHED_PROFILES;i++)
617 if ((MRUProfile[i]->filename && !strcmp( filename, MRUProfile[i]->filename )) ||
618 (MRUProfile[i]->dos_name && !strcmp( full_name.short_name, MRUProfile[i]->dos_name )))
620 if(i)
622 PROFILE_FlushFile();
623 tempProfile=MRUProfile[i];
624 for(j=i;j>0;j--)
625 MRUProfile[j]=MRUProfile[j-1];
626 CurProfile=tempProfile;
628 if(!stat(CurProfile->unix_name,&buf) && CurProfile->mtime==buf.st_mtime)
629 TRACE("(%s): already opened (mru=%d)\n",
630 filename, i );
631 else
632 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
633 filename, i );
634 return TRUE;
638 /* Flush the old current profile */
639 PROFILE_FlushFile();
641 /* Make the oldest profile the current one only in order to get rid of it */
642 if(i==N_CACHED_PROFILES)
644 tempProfile=MRUProfile[N_CACHED_PROFILES-1];
645 for(i=N_CACHED_PROFILES-1;i>0;i--)
646 MRUProfile[i]=MRUProfile[i-1];
647 CurProfile=tempProfile;
649 if(CurProfile->filename) PROFILE_ReleaseFile();
651 /* OK, now that CurProfile is definitely free we assign it our new file */
652 newdos_name = HEAP_strdupA( GetProcessHeap(), 0, full_name.short_name );
653 CurProfile->dos_name = newdos_name;
654 CurProfile->filename = HEAP_strdupA( GetProcessHeap(), 0, filename );
656 /* Try to open the profile file, first in $HOME/.wine */
658 /* FIXME: this will need a more general solution */
659 strcpy( buffer, get_config_dir() );
660 p = buffer + strlen(buffer);
661 *p++ = '/';
662 strcpy( p, strrchr( newdos_name, '\\' ) + 1 );
663 _strlwr( p );
664 if ((file = fopen( buffer, "r" )))
666 TRACE("(%s): found it in %s\n",
667 filename, buffer );
668 CurProfile->unix_name = HEAP_strdupA( GetProcessHeap(), 0, buffer );
671 if (!file)
673 CurProfile->unix_name = HEAP_strdupA( GetProcessHeap(), 0,
674 full_name.long_name );
675 if ((file = fopen( full_name.long_name, "r" )))
676 TRACE("(%s): found it in %s\n",
677 filename, full_name.long_name );
680 if (file)
682 CurProfile->section = PROFILE_Load( file );
683 fclose( file );
684 if(!stat(CurProfile->unix_name,&buf))
685 CurProfile->mtime=buf.st_mtime;
687 else
689 /* Does not exist yet, we will create it in PROFILE_FlushFile */
690 WARN("profile file %s not found\n", newdos_name );
692 return TRUE;
696 /***********************************************************************
697 * PROFILE_GetSection
699 * Returns all keys of a section.
700 * If return_values is TRUE, also include the corresponding values.
702 static INT PROFILE_GetSection( PROFILESECTION *section, LPCSTR section_name,
703 LPSTR buffer, UINT len, BOOL handle_env,
704 BOOL return_values )
706 PROFILEKEY *key;
708 if(!buffer) return 0;
710 while (section)
712 if (section->name && !strcasecmp( section->name, section_name ))
714 UINT oldlen = len;
715 for (key = section->key; key; key = key->next)
717 if (len <= 2) break;
718 if (!*key->name) continue; /* Skip empty lines */
719 if (IS_ENTRY_COMMENT(key->name)) continue; /* Skip comments */
720 PROFILE_CopyEntry( buffer, key->name, len - 1, handle_env );
721 len -= strlen(buffer) + 1;
722 buffer += strlen(buffer) + 1;
723 if (return_values && key->value) {
724 buffer[-1] = '=';
725 PROFILE_CopyEntry ( buffer,
726 key->value, len - 1, handle_env );
727 len -= strlen(buffer) + 1;
728 buffer += strlen(buffer) + 1;
731 *buffer = '\0';
732 if (len <= 1)
733 /*If either lpszSection or lpszKey is NULL and the supplied
734 destination buffer is too small to hold all the strings,
735 the last string is truncated and followed by two null characters.
736 In this case, the return value is equal to cchReturnBuffer
737 minus two. */
739 buffer[-1] = '\0';
740 return oldlen - 2;
742 return oldlen - len;
744 section = section->next;
746 buffer[0] = buffer[1] = '\0';
747 return 0;
751 static INT PROFILE_GetSectionNames( LPSTR buffer, UINT len )
753 LPSTR buf = buffer;
754 WORD l, cursize = 0;
755 PROFILESECTION *section;
757 if(!buffer) return 0;
759 for (section = CurProfile->section; section; section = section->next)
760 if (section->name) {
761 l = strlen(section->name);
762 cursize += l+1;
763 if (cursize > len+1)
764 return len-2;
766 strcpy(buf, section->name);
767 buf += l+1;
770 *buf=0;
771 buf++;
772 return buf-buffer;
776 /***********************************************************************
777 * PROFILE_GetString
779 * Get a profile string.
781 * Tests with GetPrivateProfileString16, W95a,
782 * with filled buffer ("****...") and section "set1" and key_name "1" valid:
783 * section key_name def_val res buffer
784 * "set1" "1" "x" 43 [data]
785 * "set1" "1 " "x" 43 [data] (!)
786 * "set1" " 1 "' "x" 43 [data] (!)
787 * "set1" "" "x" 1 "x"
788 * "set1" "" "x " 1 "x" (!)
789 * "set1" "" " x " 3 " x" (!)
790 * "set1" NULL "x" 6 "1\02\03\0\0"
791 * "set1" "" "x" 1 "x"
792 * NULL "1" "x" 0 "" (!)
793 * "" "1" "x" 1 "x"
794 * NULL NULL "" 0 ""
798 static INT PROFILE_GetString( LPCSTR section, LPCSTR key_name,
799 LPCSTR def_val, LPSTR buffer, UINT len )
801 PROFILEKEY *key = NULL;
803 if(!buffer) return 0;
805 if (!def_val) def_val = "";
806 if (key_name && key_name[0])
808 key = PROFILE_Find( &CurProfile->section, section, key_name, FALSE );
809 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def_val,
810 len, FALSE );
811 TRACE("('%s','%s','%s'): returning '%s'\n",
812 section, key_name, def_val, buffer );
813 return strlen( buffer );
815 if (key_name && !(key_name[0]))
816 /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227 */
817 return 0;
818 if (section && section[0])
819 return PROFILE_GetSection(CurProfile->section, section, buffer, len,
820 FALSE, FALSE);
821 buffer[0] = '\0';
822 return 0;
826 /***********************************************************************
827 * PROFILE_SetString
829 * Set a profile string.
831 static BOOL PROFILE_SetString( LPCSTR section_name, LPCSTR key_name,
832 LPCSTR value )
834 if (!key_name) /* Delete a whole section */
836 TRACE("('%s')\n", section_name);
837 CurProfile->changed |= PROFILE_DeleteSection( &CurProfile->section,
838 section_name );
839 return TRUE; /* Even if PROFILE_DeleteSection() has failed,
840 this is not an error on application's level.*/
842 else if (!value) /* Delete a key */
844 TRACE("('%s','%s')\n",
845 section_name, key_name );
846 CurProfile->changed |= PROFILE_DeleteKey( &CurProfile->section,
847 section_name, key_name );
848 return TRUE; /* same error handling as above */
850 else /* Set the key value */
852 PROFILEKEY *key = PROFILE_Find( &CurProfile->section, section_name,
853 key_name, TRUE );
854 TRACE("('%s','%s','%s'): \n",
855 section_name, key_name, value );
856 if (!key) return FALSE;
857 if (key->value)
859 /* strip the leading spaces. We can safely strip \n\r and
860 * friends too, they should not happen here anyway. */
861 while (PROFILE_isspace(*value)) value++;
863 if (!strcmp( key->value, value ))
865 TRACE(" no change needed\n" );
866 return TRUE; /* No change needed */
868 TRACE(" replacing '%s'\n", key->value );
869 HeapFree( GetProcessHeap(), 0, key->value );
871 else TRACE(" creating key\n" );
872 key->value = HEAP_strdupA( GetProcessHeap(), 0, value );
873 CurProfile->changed = TRUE;
875 return TRUE;
879 /***********************************************************************
880 * PROFILE_GetWineIniString
882 * Get a config string from the wine.ini file.
884 int PROFILE_GetWineIniString( const char *section, const char *key_name,
885 const char *def, char *buffer, int len )
887 char tmp[PROFILE_MAX_LINE_LEN];
888 HKEY hkey;
889 DWORD err;
891 if (!(err = RegOpenKeyA( wine_profile_key, section, &hkey )))
893 DWORD type;
894 DWORD count = sizeof(tmp);
895 err = RegQueryValueExA( hkey, key_name, 0, &type, tmp, &count );
896 RegCloseKey( hkey );
898 PROFILE_CopyEntry( buffer, err ? def : tmp, len, TRUE );
899 TRACE( "('%s','%s','%s'): returning '%s'\n", section, key_name, def, buffer );
900 return strlen(buffer);
904 /***********************************************************************
905 * PROFILE_EnumWineIniString
907 * Get a config string from the wine.ini file.
909 BOOL PROFILE_EnumWineIniString( const char *section, int index,
910 char *name, int name_len, char *buffer, int len )
912 char tmp[PROFILE_MAX_LINE_LEN];
913 HKEY hkey;
914 DWORD err, type;
915 DWORD count = sizeof(tmp);
917 if (RegOpenKeyA( wine_profile_key, section, &hkey )) return FALSE;
918 err = RegEnumValueA( hkey, index, name, (DWORD*)&name_len, NULL, &type, tmp, &count );
919 RegCloseKey( hkey );
920 if (!err)
922 PROFILE_CopyEntry( buffer, tmp, len, TRUE );
923 TRACE( "('%s',%d): returning '%s'='%s'\n", section, index, name, buffer );
925 return !err;
929 /***********************************************************************
930 * PROFILE_GetWineIniInt
932 * Get a config integer from the wine.ini file.
934 int PROFILE_GetWineIniInt( const char *section, const char *key_name, int def )
936 char buffer[20];
937 char *p;
938 long result;
940 PROFILE_GetWineIniString( section, key_name, "", buffer, sizeof(buffer) );
941 if (!buffer[0]) return def;
942 result = strtol( buffer, &p, 0 );
943 return (p == buffer) ? 0 /* No digits at all */ : (int)result;
947 /******************************************************************************
949 * int PROFILE_GetWineIniBool(
950 * char const *section,
951 * char const *key_name,
952 * int def )
954 * Reads a boolean value from the wine.ini file. This function attempts to
955 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
956 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
957 * true. Anything else results in the return of the default value.
959 * This function uses 1 to indicate true, and 0 for false. You can check
960 * for existence by setting def to something other than 0 or 1 and
961 * examining the return value.
963 int PROFILE_GetWineIniBool(
964 char const *section,
965 char const *key_name,
966 int def )
968 char key_value[2];
969 int retval;
971 PROFILE_GetWineIniString(section, key_name, "~", key_value, 2);
973 switch(key_value[0]) {
974 case 'n':
975 case 'N':
976 case 'f':
977 case 'F':
978 case '0':
979 retval = 0;
980 break;
982 case 'y':
983 case 'Y':
984 case 't':
985 case 'T':
986 case '1':
987 retval = 1;
988 break;
990 default:
991 retval = def;
994 TRACE("(\"%s\", \"%s\", %s), "
995 "[%c], ret %s.\n", section, key_name,
996 def ? "TRUE" : "FALSE", key_value[0],
997 retval ? "TRUE" : "FALSE");
999 return retval;
1003 /***********************************************************************
1004 * PROFILE_LoadWineIni
1006 * Load the old .winerc file.
1008 int PROFILE_LoadWineIni(void)
1010 OBJECT_ATTRIBUTES attr;
1011 UNICODE_STRING nameW;
1012 char buffer[MAX_PATHNAME_LEN];
1013 const char *p;
1014 FILE *f;
1015 HKEY hKeySW;
1016 DWORD disp;
1018 attr.Length = sizeof(attr);
1019 attr.RootDirectory = 0;
1020 attr.ObjectName = &nameW;
1021 attr.Attributes = 0;
1022 attr.SecurityDescriptor = NULL;
1023 attr.SecurityQualityOfService = NULL;
1025 /* make sure HKLM\\Software\\Wine\\Wine exists as non-volatile key */
1026 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Machine\\Software\\Wine\\Wine" ) ||
1027 NtCreateKey( &hKeySW, KEY_ALL_ACCESS, &attr, 0, NULL, 0, &disp ))
1029 ERR("Cannot create config registry key\n" );
1030 ExitProcess( 1 );
1032 RtlFreeUnicodeString( &nameW );
1033 NtClose( hKeySW );
1035 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Machine\\Software\\Wine\\Wine\\Config" ) ||
1036 NtCreateKey( &wine_profile_key, KEY_ALL_ACCESS, &attr, 0,
1037 NULL, REG_OPTION_VOLATILE, &disp ))
1039 ERR("Cannot create config registry key\n" );
1040 ExitProcess( 1 );
1042 RtlFreeUnicodeString( &nameW );
1044 if (!CLIENT_IsBootThread()) return 1; /* already loaded */
1046 if ((p = getenv( "HOME" )) != NULL)
1048 lstrcpynA(buffer, p, MAX_PATHNAME_LEN - sizeof(PROFILE_WineIniName));
1049 strcat( buffer, PROFILE_WineIniName );
1050 if ((f = fopen( buffer, "r" )) != NULL)
1052 lstrcpynA(PROFILE_WineIniUsed,buffer,MAX_PATHNAME_LEN);
1053 goto found;
1056 else WARN("could not get $HOME value for config file.\n" );
1058 if (disp == REG_OPENED_EXISTING_KEY) return 1; /* loaded by the server */
1060 MESSAGE( "Can't open configuration file %s/config\n",get_config_dir() );
1061 return 0;
1063 found:
1065 if (disp == REG_OPENED_EXISTING_KEY)
1067 MESSAGE( "Warning: configuration loaded by the server from '%s/config',\n"
1068 " file '%s' was ignored.\n", get_config_dir(), PROFILE_WineIniUsed );
1069 fclose( f );
1070 return 1;
1073 /* convert to the new format */
1074 sprintf( buffer, "%s/config", get_config_dir() );
1075 convert_config( f, buffer );
1076 fclose( f );
1078 MESSAGE( "The '%s' configuration file has been converted\n"
1079 "to the new format and saved as '%s'.\n", PROFILE_WineIniUsed, buffer );
1080 MESSAGE( "You should verify that the contents of the new file are correct,\n"
1081 "and then remove the old one and restart Wine.\n" );
1082 ExitProcess(0);
1086 /***********************************************************************
1087 * PROFILE_UsageWineIni
1089 * Explain the wine.ini file to those who don't read documentation.
1090 * Keep below one screenful in length so that error messages above are
1091 * noticed.
1093 void PROFILE_UsageWineIni(void)
1095 MESSAGE("Perhaps you have not properly edited or created "
1096 "your Wine configuration file.\n");
1097 MESSAGE("This is '%s/config'\n", get_config_dir());
1098 /* RTFM, so to say */
1101 /***********************************************************************
1102 * PROFILE_GetStringItem
1104 * Convenience function that turns a string 'xxx, yyy, zzz' into
1105 * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
1107 char* PROFILE_GetStringItem( char* start )
1109 char* lpchX, *lpch;
1111 for (lpchX = start, lpch = NULL; *lpchX != '\0'; lpchX++ )
1113 if( *lpchX == ',' )
1115 if( lpch ) *lpch = '\0'; else *lpchX = '\0';
1116 while( *(++lpchX) )
1117 if( !PROFILE_isspace(*lpchX) ) return lpchX;
1119 else if( PROFILE_isspace( *lpchX ) && !lpch ) lpch = lpchX;
1120 else lpch = NULL;
1122 if( lpch ) *lpch = '\0';
1123 return NULL;
1126 /********************* API functions **********************************/
1128 /***********************************************************************
1129 * GetProfileInt16 (KERNEL.57)
1131 UINT16 WINAPI GetProfileInt16( LPCSTR section, LPCSTR entry, INT16 def_val )
1133 return GetPrivateProfileInt16( section, entry, def_val, "win.ini" );
1137 /***********************************************************************
1138 * GetProfileIntA (KERNEL32.264)
1140 UINT WINAPI GetProfileIntA( LPCSTR section, LPCSTR entry, INT def_val )
1142 return GetPrivateProfileIntA( section, entry, def_val, "win.ini" );
1145 /***********************************************************************
1146 * GetProfileIntW (KERNEL32.264)
1148 UINT WINAPI GetProfileIntW( LPCWSTR section, LPCWSTR entry, INT def_val )
1150 return GetPrivateProfileIntW( section, entry, def_val, wininiW );
1154 * undoc_feature means:
1155 * return section names string list if both section and entry are NULL.
1157 static int PROFILE_GetPrivateProfileString( LPCSTR section, LPCSTR entry,
1158 LPCSTR def_val, LPSTR buffer,
1159 UINT16 len, LPCSTR filename,
1160 BOOL undoc_feature )
1162 int ret;
1163 LPSTR pDefVal = NULL;
1165 if (!filename)
1166 filename = "win.ini";
1168 /* strip any trailing ' ' of def_val. */
1169 if (def_val)
1171 LPSTR p = (LPSTR)&def_val[strlen(def_val)]; /* even "" works ! */
1173 while (p > def_val)
1175 p--;
1176 if ((*p) != ' ')
1177 break;
1179 if (*p == ' ') /* ouch, contained trailing ' ' */
1181 int len = (int)p - (int)def_val;
1182 pDefVal = HeapAlloc(GetProcessHeap(), 0, len + 1);
1183 strncpy(pDefVal, def_val, len);
1184 pDefVal[len] = '\0';
1187 if (!pDefVal)
1188 pDefVal = (LPSTR)def_val;
1190 EnterCriticalSection( &PROFILE_CritSect );
1192 if (PROFILE_Open( filename )) {
1193 if ((undoc_feature) && (section == NULL) && (entry == NULL))
1194 /* undocumented; both section and entry are NULL */
1195 ret = PROFILE_GetSectionNames(buffer, len);
1196 else
1197 ret = PROFILE_GetString( section, entry, pDefVal, buffer, len );
1198 } else {
1199 lstrcpynA( buffer, pDefVal, len );
1200 ret = strlen( buffer );
1203 LeaveCriticalSection( &PROFILE_CritSect );
1205 if (pDefVal != def_val) /* allocated */
1206 HeapFree(GetProcessHeap(), 0, pDefVal);
1208 return ret;
1211 /***********************************************************************
1212 * GetPrivateProfileString16 (KERNEL.128)
1214 INT16 WINAPI GetPrivateProfileString16( LPCSTR section, LPCSTR entry,
1215 LPCSTR def_val, LPSTR buffer,
1216 UINT16 len, LPCSTR filename )
1218 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1219 buffer, len, filename, FALSE );
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 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1230 buffer, len, filename, TRUE );
1233 /***********************************************************************
1234 * GetPrivateProfileStringW (KERNEL32.256)
1236 INT WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1237 LPCWSTR def_val, LPWSTR buffer,
1238 UINT len, LPCWSTR filename )
1240 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1241 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1242 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1243 LPSTR def_valA = HEAP_strdupWtoA( GetProcessHeap(), 0, def_val );
1244 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1245 INT ret = GetPrivateProfileStringA( sectionA, entryA, def_valA,
1246 bufferA, len, filenameA );
1247 if (len > 0 && !MultiByteToWideChar( CP_ACP, 0, bufferA, -1, buffer, len ))
1248 buffer[len-1] = 0;
1249 HeapFree( GetProcessHeap(), 0, sectionA );
1250 HeapFree( GetProcessHeap(), 0, entryA );
1251 HeapFree( GetProcessHeap(), 0, filenameA );
1252 HeapFree( GetProcessHeap(), 0, def_valA );
1253 HeapFree( GetProcessHeap(), 0, bufferA);
1254 return ret;
1257 /***********************************************************************
1258 * GetProfileString16 (KERNEL.58)
1260 INT16 WINAPI GetProfileString16( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1261 LPSTR buffer, UINT16 len )
1263 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1264 buffer, len, "win.ini", FALSE );
1267 /***********************************************************************
1268 * GetProfileStringA (KERNEL32.268)
1270 INT WINAPI GetProfileStringA( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1271 LPSTR buffer, UINT len )
1273 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1274 buffer, len, "win.ini", TRUE );
1277 /***********************************************************************
1278 * GetProfileStringW (KERNEL32.269)
1280 INT WINAPI GetProfileStringW( LPCWSTR section, LPCWSTR entry,
1281 LPCWSTR def_val, LPWSTR buffer, UINT len )
1283 return GetPrivateProfileStringW( section, entry, def_val,
1284 buffer, len, wininiW );
1287 /***********************************************************************
1288 * WriteProfileString16 (KERNEL.59)
1290 BOOL16 WINAPI WriteProfileString16( LPCSTR section, LPCSTR entry,
1291 LPCSTR string )
1293 return WritePrivateProfileString16( section, entry, string, "win.ini" );
1296 /***********************************************************************
1297 * WriteProfileStringA (KERNEL32.587)
1299 BOOL WINAPI WriteProfileStringA( LPCSTR section, LPCSTR entry,
1300 LPCSTR string )
1302 return WritePrivateProfileStringA( section, entry, string, "win.ini" );
1305 /***********************************************************************
1306 * WriteProfileStringW (KERNEL32.588)
1308 BOOL WINAPI WriteProfileStringW( LPCWSTR section, LPCWSTR entry,
1309 LPCWSTR string )
1311 return WritePrivateProfileStringW( section, entry, string, wininiW );
1315 /***********************************************************************
1316 * GetPrivateProfileInt16 (KERNEL.127)
1318 UINT16 WINAPI GetPrivateProfileInt16( LPCSTR section, LPCSTR entry,
1319 INT16 def_val, LPCSTR filename )
1321 long result=(long)GetPrivateProfileIntA(section,entry,def_val,filename);
1323 if (result > 65535) return 65535;
1324 if (result >= 0) return (UINT16)result;
1325 if (result < -32768) return -32768;
1326 return (UINT16)(INT16)result;
1329 /***********************************************************************
1330 * GetPrivateProfileIntA (KERNEL32.251)
1332 UINT WINAPI GetPrivateProfileIntA( LPCSTR section, LPCSTR entry,
1333 INT def_val, LPCSTR filename )
1335 char buffer[20];
1336 char *p;
1337 long result;
1339 PROFILE_GetPrivateProfileString( section, entry, "",
1340 buffer, sizeof(buffer), filename, FALSE );
1341 if (!buffer[0]) return (UINT)def_val;
1342 result = strtol( buffer, &p, 0 );
1343 if (p == buffer) return 0; /* No digits at all */
1344 return (UINT)result;
1347 /***********************************************************************
1348 * GetPrivateProfileIntW (KERNEL32.252)
1350 UINT WINAPI GetPrivateProfileIntW( LPCWSTR section, LPCWSTR entry,
1351 INT def_val, LPCWSTR filename )
1353 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1354 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1355 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1356 UINT res = GetPrivateProfileIntA(sectionA, entryA, def_val, filenameA);
1357 HeapFree( GetProcessHeap(), 0, sectionA );
1358 HeapFree( GetProcessHeap(), 0, filenameA );
1359 HeapFree( GetProcessHeap(), 0, entryA );
1360 return res;
1363 /***********************************************************************
1364 * GetPrivateProfileSection16 (KERNEL.418)
1366 INT16 WINAPI GetPrivateProfileSection16( LPCSTR section, LPSTR buffer,
1367 UINT16 len, LPCSTR filename )
1369 return GetPrivateProfileSectionA( section, buffer, len, filename );
1372 /***********************************************************************
1373 * GetPrivateProfileSectionA (KERNEL32.255)
1375 INT WINAPI GetPrivateProfileSectionA( LPCSTR section, LPSTR buffer,
1376 DWORD len, LPCSTR filename )
1378 int ret = 0;
1380 EnterCriticalSection( &PROFILE_CritSect );
1382 if (PROFILE_Open( filename ))
1383 ret = PROFILE_GetSection(CurProfile->section, section, buffer, len,
1384 FALSE, TRUE);
1386 LeaveCriticalSection( &PROFILE_CritSect );
1388 return ret;
1391 /***********************************************************************
1392 * GetPrivateProfileSectionW (KERNEL32.256)
1395 INT WINAPI GetPrivateProfileSectionW (LPCWSTR section, LPWSTR buffer,
1396 DWORD len, LPCWSTR filename )
1399 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1400 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1401 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1402 INT ret = GetPrivateProfileSectionA( sectionA, bufferA, len,
1403 filenameA );
1404 MultiByteToWideChar(CP_ACP,0,bufferA,ret,buffer,len);
1405 HeapFree( GetProcessHeap(), 0, sectionA );
1406 HeapFree( GetProcessHeap(), 0, filenameA );
1407 HeapFree( GetProcessHeap(), 0, bufferA);
1408 return ret;
1411 /***********************************************************************
1412 * GetProfileSection16 (KERNEL.419)
1414 INT16 WINAPI GetProfileSection16( LPCSTR section, LPSTR buffer, UINT16 len )
1416 return GetPrivateProfileSection16( section, buffer, len, "win.ini" );
1419 /***********************************************************************
1420 * GetProfileSectionA (KERNEL32.268)
1422 INT WINAPI GetProfileSectionA( LPCSTR section, LPSTR buffer, DWORD len )
1424 return GetPrivateProfileSectionA( section, buffer, len, "win.ini" );
1427 /***********************************************************************
1428 * GetProfileSectionW (KERNEL32)
1430 INT WINAPI GetProfileSectionW( LPCWSTR section, LPWSTR buffer, DWORD len )
1432 return GetPrivateProfileSectionW( section, buffer, len, wininiW );
1436 /***********************************************************************
1437 * WritePrivateProfileString16 (KERNEL.129)
1439 BOOL16 WINAPI WritePrivateProfileString16( LPCSTR section, LPCSTR entry,
1440 LPCSTR string, LPCSTR filename )
1442 return WritePrivateProfileStringA(section,entry,string,filename);
1445 /***********************************************************************
1446 * WritePrivateProfileStringA (KERNEL32.582)
1448 BOOL WINAPI WritePrivateProfileStringA( LPCSTR section, LPCSTR entry,
1449 LPCSTR string, LPCSTR filename )
1451 BOOL ret = FALSE;
1453 EnterCriticalSection( &PROFILE_CritSect );
1455 if (PROFILE_Open( filename ))
1457 if (!section && !entry && !string)
1458 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1459 else
1460 ret = PROFILE_SetString( section, entry, string );
1463 LeaveCriticalSection( &PROFILE_CritSect );
1464 return ret;
1467 /***********************************************************************
1468 * WritePrivateProfileStringW (KERNEL32.583)
1470 BOOL WINAPI WritePrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1471 LPCWSTR string, LPCWSTR filename )
1473 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1474 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1475 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1476 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1477 BOOL res = WritePrivateProfileStringA( sectionA, entryA,
1478 stringA, filenameA );
1479 HeapFree( GetProcessHeap(), 0, sectionA );
1480 HeapFree( GetProcessHeap(), 0, entryA );
1481 HeapFree( GetProcessHeap(), 0, stringA );
1482 HeapFree( GetProcessHeap(), 0, filenameA );
1483 return res;
1486 /***********************************************************************
1487 * WritePrivateProfileSection16 (KERNEL.416)
1489 BOOL16 WINAPI WritePrivateProfileSection16( LPCSTR section,
1490 LPCSTR string, LPCSTR filename )
1492 return WritePrivateProfileSectionA( section, string, filename );
1495 /***********************************************************************
1496 * WritePrivateProfileSectionA (KERNEL32)
1498 BOOL WINAPI WritePrivateProfileSectionA( LPCSTR section,
1499 LPCSTR string, LPCSTR filename )
1501 BOOL ret = FALSE;
1502 LPSTR p ;
1504 EnterCriticalSection( &PROFILE_CritSect );
1506 if (PROFILE_Open( filename )) {
1507 if (!section && !string)
1508 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1509 else if (!string) /* delete the named section*/
1510 ret = PROFILE_SetString(section,NULL,NULL);
1511 else {
1512 PROFILE_DeleteAllKeys(section);
1513 ret = TRUE;
1514 while(*string) {
1515 LPSTR buf=HEAP_strdupA( GetProcessHeap(), 0, string );
1516 if((p=strchr( buf, '='))){
1517 *p='\0';
1518 ret = PROFILE_SetString( section, buf, p+1 );
1521 HeapFree( GetProcessHeap(), 0, buf );
1522 string += strlen(string)+1;
1528 LeaveCriticalSection( &PROFILE_CritSect );
1529 return ret;
1532 /***********************************************************************
1533 * WritePrivateProfileSectionW (KERNEL32)
1535 BOOL WINAPI WritePrivateProfileSectionW( LPCWSTR section,
1536 LPCWSTR string, LPCWSTR filename)
1539 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1540 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1541 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1542 BOOL res = WritePrivateProfileSectionA( sectionA, stringA, filenameA );
1543 HeapFree( GetProcessHeap(), 0, sectionA );
1544 HeapFree( GetProcessHeap(), 0, stringA );
1545 HeapFree( GetProcessHeap(), 0, filenameA );
1546 return res;
1549 /***********************************************************************
1550 * WriteProfileSection16 (KERNEL.417)
1552 BOOL16 WINAPI WriteProfileSection16( LPCSTR section, LPCSTR keys_n_values)
1554 return WritePrivateProfileSection16( section, keys_n_values, "win.ini");
1557 /***********************************************************************
1558 * WriteProfileSectionA (KERNEL32.747)
1560 BOOL WINAPI WriteProfileSectionA( LPCSTR section, LPCSTR keys_n_values)
1563 return WritePrivateProfileSectionA( section, keys_n_values, "win.ini");
1566 /***********************************************************************
1567 * WriteProfileSectionW (KERNEL32.748)
1569 BOOL WINAPI WriteProfileSectionW( LPCWSTR section, LPCWSTR keys_n_values)
1571 return (WritePrivateProfileSectionW (section,keys_n_values, wininiW));
1574 /***********************************************************************
1575 * GetPrivateProfileSectionNames16 (KERNEL.143)
1577 WORD WINAPI GetPrivateProfileSectionNames16( LPSTR buffer, WORD size,
1578 LPCSTR filename )
1580 WORD ret = 0;
1582 EnterCriticalSection( &PROFILE_CritSect );
1584 if (PROFILE_Open( filename ))
1585 ret = PROFILE_GetSectionNames(buffer, size);
1587 LeaveCriticalSection( &PROFILE_CritSect );
1589 return ret;
1593 /***********************************************************************
1594 * GetProfileSectionNames16 (KERNEL.142)
1596 WORD WINAPI GetProfileSectionNames16( LPSTR buffer, WORD size)
1599 return (GetPrivateProfileSectionNames16 (buffer,size,"win.ini"));
1603 /***********************************************************************
1604 * GetPrivateProfileSectionNamesA (KERNEL32.365)
1606 DWORD WINAPI GetPrivateProfileSectionNamesA( LPSTR buffer, DWORD size,
1607 LPCSTR filename)
1610 return (GetPrivateProfileSectionNames16 (buffer,size,filename));
1614 /***********************************************************************
1615 * GetPrivateProfileSectionNamesW (KERNEL32.366)
1617 DWORD WINAPI GetPrivateProfileSectionNamesW( LPWSTR buffer, DWORD size,
1618 LPCWSTR filename)
1621 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1622 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, size);
1624 INT ret = GetPrivateProfileSectionNames16 (bufferA, size, filenameA);
1625 if (size > 0 && !MultiByteToWideChar( CP_ACP, 0, bufferA, -1, buffer, size ))
1626 buffer[size-1] = 0;
1627 HeapFree( GetProcessHeap(), 0, bufferA);
1628 HeapFree( GetProcessHeap(), 0, filenameA );
1630 return ret;
1633 /***********************************************************************
1634 * GetPrivateProfileStruct16 (KERNEL.407)
1636 BOOL16 WINAPI GetPrivateProfileStruct16(LPCSTR section, LPCSTR key,
1637 LPVOID buf, UINT16 len, LPCSTR filename)
1639 return GetPrivateProfileStructA( section, key, buf, len, filename );
1642 /***********************************************************************
1643 * GetPrivateProfileStructA (KERNEL32.370)
1645 * Should match Win95's behaviour pretty much
1647 BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key,
1648 LPVOID buf, UINT len, LPCSTR filename)
1650 BOOL ret = FALSE;
1652 EnterCriticalSection( &PROFILE_CritSect );
1654 if (PROFILE_Open( filename )) {
1655 PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE);
1656 if (k) {
1657 TRACE("value (at %p): '%s'\n", k->value, k->value);
1658 if (((strlen(k->value) - 2) / 2) == len)
1660 LPSTR end, p;
1661 BOOL valid = TRUE;
1662 CHAR c;
1663 DWORD chksum = 0;
1665 end = k->value + strlen(k->value); /* -> '\0' */
1666 /* check for invalid chars in ASCII coded hex string */
1667 for (p=k->value; p < end; p++)
1669 if (!isxdigit(*p))
1671 WARN("invalid char '%c' in file '%s'->'[%s]'->'%s' !\n",
1672 *p, filename, section, key);
1673 valid = FALSE;
1674 break;
1677 if (valid)
1679 BOOL highnibble = TRUE;
1680 BYTE b = 0, val;
1681 LPBYTE binbuf = (LPBYTE)buf;
1683 end -= 2; /* don't include checksum in output data */
1684 /* translate ASCII hex format into binary data */
1685 for (p=k->value; p < end; p++)
1687 c = toupper(*p);
1688 val = (c > '9') ?
1689 (c - 'A' + 10) : (c - '0');
1691 if (highnibble)
1692 b = val << 4;
1693 else
1695 b += val;
1696 *binbuf++ = b; /* feed binary data into output */
1697 chksum += b; /* calculate checksum */
1699 highnibble ^= 1; /* toggle */
1701 /* retrieve stored checksum value */
1702 c = toupper(*p++);
1703 b = ( (c > '9') ? (c - 'A' + 10) : (c - '0') ) << 4;
1704 c = toupper(*p);
1705 b += (c > '9') ? (c - 'A' + 10) : (c - '0');
1706 if (b == (chksum & 0xff)) /* checksums match ? */
1707 ret = TRUE;
1712 LeaveCriticalSection( &PROFILE_CritSect );
1714 return ret;
1717 /***********************************************************************
1718 * GetPrivateProfileStructW (KERNEL32.543)
1720 BOOL WINAPI GetPrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1721 LPVOID buffer, UINT len, LPCWSTR filename)
1723 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1724 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1725 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1726 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1728 INT ret = GetPrivateProfileStructA( sectionA, keyA, bufferA,
1729 len, filenameA );
1730 if (len > 0 && !MultiByteToWideChar( CP_ACP, 0, bufferA, -1, buffer, len ))
1731 ((LPWSTR)buffer)[len-1] = 0;
1732 HeapFree( GetProcessHeap(), 0, bufferA);
1733 HeapFree( GetProcessHeap(), 0, sectionA );
1734 HeapFree( GetProcessHeap(), 0, keyA );
1735 HeapFree( GetProcessHeap(), 0, filenameA );
1737 return ret;
1742 /***********************************************************************
1743 * WritePrivateProfileStruct16 (KERNEL.406)
1745 BOOL16 WINAPI WritePrivateProfileStruct16 (LPCSTR section, LPCSTR key,
1746 LPVOID buf, UINT16 bufsize, LPCSTR filename)
1748 return WritePrivateProfileStructA( section, key, buf, bufsize, filename );
1751 /***********************************************************************
1752 * WritePrivateProfileStructA (KERNEL32.744)
1754 BOOL WINAPI WritePrivateProfileStructA (LPCSTR section, LPCSTR key,
1755 LPVOID buf, UINT bufsize, LPCSTR filename)
1757 BOOL ret = FALSE;
1758 LPBYTE binbuf;
1759 LPSTR outstring, p;
1760 DWORD sum = 0;
1762 if (!section && !key && !buf) /* flush the cache */
1763 return WritePrivateProfileStringA( NULL, NULL, NULL, filename );
1765 /* allocate string buffer for hex chars + checksum hex char + '\0' */
1766 outstring = HeapAlloc( GetProcessHeap(), 0, bufsize*2 + 2 + 1);
1767 p = outstring;
1768 for (binbuf = (LPBYTE)buf; binbuf < (LPBYTE)buf+bufsize; binbuf++) {
1769 *p++ = hex[*binbuf >> 4];
1770 *p++ = hex[*binbuf & 0xf];
1771 sum += *binbuf;
1773 /* checksum is sum & 0xff */
1774 *p++ = hex[(sum & 0xf0) >> 4];
1775 *p++ = hex[sum & 0xf];
1776 *p++ = '\0';
1778 EnterCriticalSection( &PROFILE_CritSect );
1780 if (PROFILE_Open( filename ))
1781 ret = PROFILE_SetString( section, key, outstring );
1783 LeaveCriticalSection( &PROFILE_CritSect );
1785 HeapFree( GetProcessHeap(), 0, outstring );
1787 return ret;
1790 /***********************************************************************
1791 * WritePrivateProfileStructW (KERNEL32.544)
1793 BOOL WINAPI WritePrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1794 LPVOID buf, UINT bufsize, LPCWSTR filename)
1796 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1797 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1798 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1799 INT ret = WritePrivateProfileStructA( sectionA, keyA, buf, bufsize,
1800 filenameA );
1801 HeapFree( GetProcessHeap(), 0, sectionA );
1802 HeapFree( GetProcessHeap(), 0, keyA );
1803 HeapFree( GetProcessHeap(), 0, filenameA );
1805 return ret;
1809 /***********************************************************************
1810 * WriteOutProfiles (KERNEL.315)
1812 void WINAPI WriteOutProfiles16(void)
1814 EnterCriticalSection( &PROFILE_CritSect );
1815 PROFILE_FlushFile();
1816 LeaveCriticalSection( &PROFILE_CritSect );
1819 /***********************************************************************
1820 * CloseProfileUserMapping (KERNEL.138)
1822 BOOL WINAPI CloseProfileUserMapping(void) {
1823 FIXME("(), stub!\n");
1824 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1825 return FALSE;