- All audio device handles are initialized to -1 and set to -1 when closed.
[wine/dcerpc.git] / files / profile.c
blobf7d320bc56b2a642d146646511e1e809739f1cf4
1 /*
2 * Profile functions
4 * Copyright 1993 Miguel de Icaza
5 * Copyright 1996 Alexandre Julliard
6 */
8 #include <ctype.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <stdio.h>
12 #include <sys/stat.h>
13 #include <sys/types.h>
14 #include <pwd.h>
15 #include <unistd.h>
17 #include "winbase.h"
18 #include "winerror.h"
19 #include "wine/winbase16.h"
20 #include "wine/winestring.h"
21 #include "windef.h"
22 #include "winnls.h"
23 #include "winreg.h"
24 #include "file.h"
25 #include "heap.h"
26 #include "debugtools.h"
27 #include "options.h"
28 #include "server.h"
30 DEFAULT_DEBUG_CHANNEL(profile);
32 typedef struct tagPROFILEKEY
34 char *name;
35 char *value;
36 struct tagPROFILEKEY *next;
37 } PROFILEKEY;
39 typedef struct tagPROFILESECTION
41 char *name;
42 struct tagPROFILEKEY *key;
43 struct tagPROFILESECTION *next;
44 } PROFILESECTION;
47 typedef struct
49 BOOL changed;
50 PROFILESECTION *section;
51 char *dos_name;
52 char *unix_name;
53 char *filename;
54 time_t mtime;
55 } PROFILE;
58 #define N_CACHED_PROFILES 10
60 /* Cached profile files */
61 static PROFILE *MRUProfile[N_CACHED_PROFILES]={NULL};
63 #define CurProfile (MRUProfile[0])
65 /* wine.ini config file registry root */
66 static HKEY wine_profile_key;
68 #define PROFILE_MAX_LINE_LEN 1024
70 /* Wine profile name in $HOME directory; must begin with slash */
71 static const char PROFILE_WineIniName[] = "/.winerc";
73 /* Wine profile: the profile file being used */
74 static char PROFILE_WineIniUsed[MAX_PATHNAME_LEN] = "";
76 /* Check for comments in profile */
77 #define IS_ENTRY_COMMENT(str) ((str)[0] == ';')
79 #define WINE_INI_GLOBAL ETCDIR "/wine.conf"
81 static const WCHAR wininiW[] = { 'w','i','n','.','i','n','i',0 };
83 static CRITICAL_SECTION PROFILE_CritSect = CRITICAL_SECTION_INIT;
85 static const char hex[16] = "0123456789ABCDEF";
87 /***********************************************************************
88 * PROFILE_CopyEntry
90 * Copy the content of an entry into a buffer, removing quotes, and possibly
91 * translating environment variables.
93 static void PROFILE_CopyEntry( char *buffer, const char *value, int len,
94 int handle_env )
96 char quote = '\0';
97 const char *p;
99 if ((*value == '\'') || (*value == '\"'))
101 if (value[1] && (value[strlen(value)-1] == *value)) quote = *value++;
104 if (!handle_env)
106 lstrcpynA( buffer, value, len );
107 if (quote && (len >= strlen(value))) buffer[strlen(buffer)-1] = '\0';
108 return;
111 for (p = value; (*p && (len > 1)); *buffer++ = *p++, len-- )
113 if ((*p == '$') && (p[1] == '{'))
115 char env_val[1024];
116 const char *env_p;
117 const char *p2 = strchr( p, '}' );
118 if (!p2) continue; /* ignore it */
119 lstrcpynA(env_val, p + 2, min( sizeof(env_val), (int)(p2-p)-1 ));
120 if ((env_p = getenv( env_val )) != NULL)
122 lstrcpynA( buffer, env_p, len );
123 buffer += strlen( buffer );
124 len -= strlen( buffer );
126 p = p2 + 1;
129 if (quote && (len > 1)) buffer--;
130 *buffer = '\0';
134 /***********************************************************************
135 * PROFILE_Save
137 * Save a profile tree to a file.
139 static void PROFILE_Save( FILE *file, PROFILESECTION *section )
141 PROFILEKEY *key;
143 for ( ; section; section = section->next)
145 if (section->name) fprintf( file, "\r\n[%s]\r\n", section->name );
146 for (key = section->key; key; key = key->next)
148 fprintf( file, "%s", key->name );
149 if (key->value) fprintf( file, "=%s", key->value );
150 fprintf( file, "\r\n" );
156 /***********************************************************************
157 * PROFILE_Free
159 * Free a profile tree.
161 static void PROFILE_Free( PROFILESECTION *section )
163 PROFILESECTION *next_section;
164 PROFILEKEY *key, *next_key;
166 for ( ; section; section = next_section)
168 if (section->name) HeapFree( GetProcessHeap(), 0, section->name );
169 for (key = section->key; key; key = next_key)
171 next_key = key->next;
172 if (key->name) HeapFree( GetProcessHeap(), 0, key->name );
173 if (key->value) HeapFree( GetProcessHeap(), 0, key->value );
174 HeapFree( GetProcessHeap(), 0, key );
176 next_section = section->next;
177 HeapFree( GetProcessHeap(), 0, section );
181 static inline int PROFILE_isspace(char c)
183 if (isspace(c)) return 1;
184 if (c=='\r' || c==0x1a) return 1;
185 /* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */
186 return 0;
190 /***********************************************************************
191 * PROFILE_Load
193 * Load a profile tree from a file.
195 static PROFILESECTION *PROFILE_Load( FILE *file )
197 char buffer[PROFILE_MAX_LINE_LEN];
198 char *p, *p2;
199 int line = 0;
200 PROFILESECTION *section, *first_section;
201 PROFILESECTION **next_section;
202 PROFILEKEY *key, *prev_key, **next_key;
204 first_section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) );
205 if(first_section == NULL) return NULL;
206 first_section->name = NULL;
207 first_section->key = NULL;
208 first_section->next = NULL;
209 next_section = &first_section->next;
210 next_key = &first_section->key;
211 prev_key = NULL;
213 while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
215 line++;
216 p = buffer;
217 while (*p && PROFILE_isspace(*p)) p++;
218 if (*p == '[') /* section start */
220 if (!(p2 = strrchr( p, ']' )))
222 WARN("Invalid section header at line %d: '%s'\n",
223 line, p );
225 else
227 *p2 = '\0';
228 p++;
229 section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) );
230 if(section == NULL) break;
231 section->name = HEAP_strdupA( GetProcessHeap(), 0, p );
232 section->key = NULL;
233 section->next = NULL;
234 *next_section = section;
235 next_section = &section->next;
236 next_key = &section->key;
237 prev_key = NULL;
239 TRACE("New section: '%s'\n",section->name);
241 continue;
245 p2=p+strlen(p) - 1;
246 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
248 if ((p2 = strchr( p, '=' )) != NULL)
250 char *p3 = p2 - 1;
251 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
252 *p2++ = '\0';
253 while (*p2 && PROFILE_isspace(*p2)) p2++;
256 if(*p || !prev_key || *prev_key->name)
258 key = HeapAlloc( GetProcessHeap(), 0, sizeof(*key) );
259 if(key == NULL) break;
260 key->name = HEAP_strdupA( GetProcessHeap(), 0, p );
261 key->value = p2 ? HEAP_strdupA( GetProcessHeap(), 0, p2 ) : NULL;
262 key->next = NULL;
263 *next_key = key;
264 next_key = &key->next;
265 prev_key = key;
267 TRACE("New key: name='%s', value='%s'\n",key->name,key->value?key->value:"(none)");
270 return first_section;
274 /***********************************************************************
275 * PROFILE_RegistryLoad
277 * Load a profile tree from a file into a registry key.
279 static DWORD PROFILE_RegistryLoad( HKEY root, FILE *file )
281 HKEY hkey = 0;
282 DWORD err = 0;
283 char buffer[PROFILE_MAX_LINE_LEN];
284 char *p, *p2;
285 int line = 0;
287 while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
289 line++;
290 p = buffer;
291 while (*p && PROFILE_isspace(*p)) p++;
292 if (*p == '[') /* section start */
294 if (!(p2 = strrchr( p, ']' )))
296 WARN("Invalid section header at line %d: '%s'\n",
297 line, p );
299 else
301 *p2 = '\0';
302 p++;
303 if (hkey) RegCloseKey( hkey );
304 if ((err = RegCreateKeyExA( root, p, 0, NULL, REG_OPTION_VOLATILE,
305 KEY_ALL_ACCESS, NULL, &hkey, NULL ))) return err;
306 TRACE("New section: '%s'\n",p);
307 continue;
311 p2=p+strlen(p) - 1;
312 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
314 if ((p2 = strchr( p, '=' )) != NULL)
316 char *p3 = p2 - 1;
317 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
318 *p2++ = '\0';
319 while (*p2 && PROFILE_isspace(*p2)) p2++;
322 if (*p && hkey && !IS_ENTRY_COMMENT(p))
324 if (!p2) p2 = "";
325 if ((err = RegSetValueExA( hkey, p, 0, REG_SZ, p2, strlen(p2)+1 )))
327 RegCloseKey( hkey );
328 return err;
330 TRACE("New key: name='%s', value='%s'\n",p,p2);
333 if (hkey) RegCloseKey( hkey );
334 return 0;
338 /***********************************************************************
339 * PROFILE_DeleteSection
341 * Delete a section from a profile tree.
343 static BOOL PROFILE_DeleteSection( PROFILESECTION **section, LPCSTR name )
345 while (*section)
347 if ((*section)->name && !strcasecmp( (*section)->name, name ))
349 PROFILESECTION *to_del = *section;
350 *section = to_del->next;
351 to_del->next = NULL;
352 PROFILE_Free( to_del );
353 return TRUE;
355 section = &(*section)->next;
357 return FALSE;
361 /***********************************************************************
362 * PROFILE_DeleteKey
364 * Delete a key from a profile tree.
366 static BOOL PROFILE_DeleteKey( PROFILESECTION **section,
367 LPCSTR section_name, LPCSTR key_name )
369 while (*section)
371 if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
373 PROFILEKEY **key = &(*section)->key;
374 while (*key)
376 if (!strcasecmp( (*key)->name, key_name ))
378 PROFILEKEY *to_del = *key;
379 *key = to_del->next;
380 if (to_del->name) HeapFree( GetProcessHeap(), 0, to_del->name );
381 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
382 HeapFree( GetProcessHeap(), 0, to_del );
383 return TRUE;
385 key = &(*key)->next;
388 section = &(*section)->next;
390 return FALSE;
394 /***********************************************************************
395 * PROFILE_DeleteAllKeys
397 * Delete all keys from a profile tree.
399 void PROFILE_DeleteAllKeys( LPCSTR section_name)
401 PROFILESECTION **section= &CurProfile->section;
402 while (*section)
404 if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
406 PROFILEKEY **key = &(*section)->key;
407 while (*key)
409 PROFILEKEY *to_del = *key;
410 *key = to_del->next;
411 if (to_del->name) HeapFree( GetProcessHeap(), 0, to_del->name );
412 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
413 HeapFree( GetProcessHeap(), 0, to_del );
414 CurProfile->changed =TRUE;
417 section = &(*section)->next;
422 /***********************************************************************
423 * PROFILE_Find
425 * Find a key in a profile tree, optionally creating it.
427 static PROFILEKEY *PROFILE_Find( PROFILESECTION **section,
428 const char *section_name,
429 const char *key_name, int create )
431 const char *p;
432 int seclen, keylen;
434 while (PROFILE_isspace(*section_name)) section_name++;
435 p = section_name + strlen(section_name) - 1;
436 while ((p > section_name) && PROFILE_isspace(*p)) p--;
437 seclen = p - section_name + 1;
439 while (PROFILE_isspace(*key_name)) key_name++;
440 p = key_name + strlen(key_name) - 1;
441 while ((p > key_name) && PROFILE_isspace(*p)) p--;
442 keylen = p - key_name + 1;
444 while (*section)
446 if ( ((*section)->name)
447 && (!(strncasecmp( (*section)->name, section_name, seclen )))
448 && (((*section)->name)[seclen] == '\0') )
450 PROFILEKEY **key = &(*section)->key;
451 while (*key)
453 if ( (!(strncasecmp( (*key)->name, key_name, keylen )))
454 && (((*key)->name)[keylen] == '\0') )
455 return *key;
456 key = &(*key)->next;
458 if (!create) return NULL;
459 *key = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) );
460 if(*key == NULL) return NULL;
461 (*key)->name = HEAP_strdupA( GetProcessHeap(), 0, key_name );
462 (*key)->value = NULL;
463 (*key)->next = NULL;
464 return *key;
466 section = &(*section)->next;
468 if (!create) return NULL;
469 *section = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILESECTION) );
470 if(*section == NULL) return NULL;
471 (*section)->name = HEAP_strdupA( GetProcessHeap(), 0, section_name );
472 (*section)->next = NULL;
473 (*section)->key = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) );
474 if((*section)->key == NULL)
476 HeapFree(GetProcessHeap(), 0, *section);
477 return NULL;
479 (*section)->key->name = HEAP_strdupA( GetProcessHeap(), 0, key_name );
480 (*section)->key->value = NULL;
481 (*section)->key->next = NULL;
482 return (*section)->key;
486 /***********************************************************************
487 * PROFILE_FlushFile
489 * Flush the current profile to disk if changed.
491 static BOOL PROFILE_FlushFile(void)
493 char *p, buffer[MAX_PATHNAME_LEN];
494 const char *unix_name;
495 FILE *file = NULL;
496 struct stat buf;
498 if(!CurProfile)
500 WARN("No current profile!\n");
501 return FALSE;
504 if (!CurProfile->changed || !CurProfile->dos_name) return TRUE;
505 if (!(unix_name = CurProfile->unix_name) || !(file = fopen(unix_name, "w")))
507 /* Try to create it in $HOME/.wine */
508 /* FIXME: this will need a more general solution */
509 strcpy( buffer, get_config_dir() );
510 p = buffer + strlen(buffer);
511 *p++ = '/';
512 strcpy( p, strrchr( CurProfile->dos_name, '\\' ) + 1 );
513 _strlwr( p );
514 file = fopen( buffer, "w" );
515 unix_name = buffer;
518 if (!file)
520 WARN("could not save profile file %s\n", CurProfile->dos_name);
521 return FALSE;
524 TRACE("Saving '%s' into '%s'\n", CurProfile->dos_name, unix_name );
525 PROFILE_Save( file, CurProfile->section );
526 fclose( file );
527 CurProfile->changed = FALSE;
528 if(!stat(unix_name,&buf))
529 CurProfile->mtime=buf.st_mtime;
530 return TRUE;
534 /***********************************************************************
535 * PROFILE_ReleaseFile
537 * Flush the current profile to disk and remove it from the cache.
539 static void PROFILE_ReleaseFile(void)
541 PROFILE_FlushFile();
542 PROFILE_Free( CurProfile->section );
543 if (CurProfile->dos_name) HeapFree( GetProcessHeap(), 0, CurProfile->dos_name );
544 if (CurProfile->unix_name) HeapFree( GetProcessHeap(), 0, CurProfile->unix_name );
545 if (CurProfile->filename) HeapFree( GetProcessHeap(), 0, CurProfile->filename );
546 CurProfile->changed = FALSE;
547 CurProfile->section = NULL;
548 CurProfile->dos_name = NULL;
549 CurProfile->unix_name = NULL;
550 CurProfile->filename = NULL;
551 CurProfile->mtime = 0;
555 /***********************************************************************
556 * PROFILE_Open
558 * Open a profile file, checking the cached file first.
560 static BOOL PROFILE_Open( LPCSTR filename )
562 DOS_FULL_NAME full_name;
563 char buffer[MAX_PATHNAME_LEN];
564 char *newdos_name, *p;
565 FILE *file = NULL;
566 int i,j;
567 struct stat buf;
568 PROFILE *tempProfile;
570 /* First time around */
572 if(!CurProfile)
573 for(i=0;i<N_CACHED_PROFILES;i++)
575 MRUProfile[i]=HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILE) );
576 if(MRUProfile[i] == NULL) break;
577 MRUProfile[i]->changed=FALSE;
578 MRUProfile[i]->section=NULL;
579 MRUProfile[i]->dos_name=NULL;
580 MRUProfile[i]->unix_name=NULL;
581 MRUProfile[i]->filename=NULL;
582 MRUProfile[i]->mtime=0;
585 /* Check for a match */
587 if (strchr( filename, '/' ) || strchr( filename, '\\' ) ||
588 strchr( filename, ':' ))
590 if (!DOSFS_GetFullName( filename, FALSE, &full_name )) return FALSE;
592 else
594 GetWindowsDirectoryA( buffer, sizeof(buffer) );
595 strcat( buffer, "\\" );
596 strcat( buffer, filename );
597 if (!DOSFS_GetFullName( buffer, FALSE, &full_name )) return FALSE;
600 for(i=0;i<N_CACHED_PROFILES;i++)
602 if ((MRUProfile[i]->filename && !strcmp( filename, MRUProfile[i]->filename )) ||
603 (MRUProfile[i]->dos_name && !strcmp( full_name.short_name, MRUProfile[i]->dos_name )))
605 if(i)
607 PROFILE_FlushFile();
608 tempProfile=MRUProfile[i];
609 for(j=i;j>0;j--)
610 MRUProfile[j]=MRUProfile[j-1];
611 CurProfile=tempProfile;
613 if(!stat(CurProfile->unix_name,&buf) && CurProfile->mtime==buf.st_mtime)
614 TRACE("(%s): already opened (mru=%d)\n",
615 filename, i );
616 else
617 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
618 filename, i );
619 return TRUE;
623 /* Flush the old current profile */
624 PROFILE_FlushFile();
626 /* Make the oldest profile the current one only in order to get rid of it */
627 if(i==N_CACHED_PROFILES)
629 tempProfile=MRUProfile[N_CACHED_PROFILES-1];
630 for(i=N_CACHED_PROFILES-1;i>0;i--)
631 MRUProfile[i]=MRUProfile[i-1];
632 CurProfile=tempProfile;
634 if(CurProfile->filename) PROFILE_ReleaseFile();
636 /* OK, now that CurProfile is definitely free we assign it our new file */
637 newdos_name = HEAP_strdupA( GetProcessHeap(), 0, full_name.short_name );
638 CurProfile->dos_name = newdos_name;
639 CurProfile->filename = HEAP_strdupA( GetProcessHeap(), 0, filename );
641 /* Try to open the profile file, first in $HOME/.wine */
643 /* FIXME: this will need a more general solution */
644 strcpy( buffer, get_config_dir() );
645 p = buffer + strlen(buffer);
646 *p++ = '/';
647 strcpy( p, strrchr( newdos_name, '\\' ) + 1 );
648 _strlwr( p );
649 if ((file = fopen( buffer, "r" )))
651 TRACE("(%s): found it in %s\n",
652 filename, buffer );
653 CurProfile->unix_name = HEAP_strdupA( GetProcessHeap(), 0, buffer );
656 if (!file)
658 CurProfile->unix_name = HEAP_strdupA( GetProcessHeap(), 0,
659 full_name.long_name );
660 if ((file = fopen( full_name.long_name, "r" )))
661 TRACE("(%s): found it in %s\n",
662 filename, full_name.long_name );
665 if (file)
667 CurProfile->section = PROFILE_Load( file );
668 fclose( file );
669 if(!stat(CurProfile->unix_name,&buf))
670 CurProfile->mtime=buf.st_mtime;
672 else
674 /* Does not exist yet, we will create it in PROFILE_FlushFile */
675 WARN("profile file %s not found\n", newdos_name );
677 return TRUE;
681 /***********************************************************************
682 * PROFILE_GetSection
684 * Returns all keys of a section.
685 * If return_values is TRUE, also include the corresponding values.
687 static INT PROFILE_GetSection( PROFILESECTION *section, LPCSTR section_name,
688 LPSTR buffer, UINT len, BOOL handle_env,
689 BOOL return_values )
691 PROFILEKEY *key;
692 while (section)
694 if (section->name && !strcasecmp( section->name, section_name ))
696 UINT oldlen = len;
697 for (key = section->key; key; key = key->next)
699 if (len <= 2) break;
700 if (!*key->name) continue; /* Skip empty lines */
701 if (IS_ENTRY_COMMENT(key->name)) continue; /* Skip comments */
702 PROFILE_CopyEntry( buffer, key->name, len - 1, handle_env );
703 len -= strlen(buffer) + 1;
704 buffer += strlen(buffer) + 1;
705 if (return_values && key->value) {
706 buffer[-1] = '=';
707 PROFILE_CopyEntry ( buffer,
708 key->value, len - 1, handle_env );
709 len -= strlen(buffer) + 1;
710 buffer += strlen(buffer) + 1;
713 *buffer = '\0';
714 if (len <= 1)
715 /*If either lpszSection or lpszKey is NULL and the supplied
716 destination buffer is too small to hold all the strings,
717 the last string is truncated and followed by two null characters.
718 In this case, the return value is equal to cchReturnBuffer
719 minus two. */
721 buffer[-1] = '\0';
722 return oldlen - 2;
724 return oldlen - len;
726 section = section->next;
728 buffer[0] = buffer[1] = '\0';
729 return 0;
733 static INT PROFILE_GetSectionNames( LPSTR buffer, UINT len )
735 LPSTR buf = buffer;
736 WORD l, cursize = 0;
737 PROFILESECTION *section;
739 for (section = CurProfile->section; section; section = section->next)
740 if (section->name) {
741 l = strlen(section->name);
742 cursize += l+1;
743 if (cursize > len+1)
744 return len-2;
746 strcpy(buf, section->name);
747 buf += l+1;
750 *buf=0;
751 buf++;
752 return buf-buffer;
756 /***********************************************************************
757 * PROFILE_GetString
759 * Get a profile string.
761 * Tests with GetPrivateProfileString16, W95a,
762 * with filled buffer ("****...") and section "set1" and key_name "1" valid:
763 * section key_name def_val res buffer
764 * "set1" "1" "x" 43 [data]
765 * "set1" "1 " "x" 43 [data] (!)
766 * "set1" " 1 "' "x" 43 [data] (!)
767 * "set1" "" "x" 1 "x"
768 * "set1" "" "x " 1 "x" (!)
769 * "set1" "" " x " 3 " x" (!)
770 * "set1" NULL "x" 6 "1\02\03\0\0"
771 * "set1" "" "x" 1 "x"
772 * NULL "1" "x" 0 "" (!)
773 * "" "1" "x" 1 "x"
774 * NULL NULL "" 0 ""
778 static INT PROFILE_GetString( LPCSTR section, LPCSTR key_name,
779 LPCSTR def_val, LPSTR buffer, UINT len )
781 PROFILEKEY *key = NULL;
783 if (!def_val) def_val = "";
784 if (key_name && key_name[0])
786 key = PROFILE_Find( &CurProfile->section, section, key_name, FALSE );
787 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def_val,
788 len, FALSE );
789 TRACE("('%s','%s','%s'): returning '%s'\n",
790 section, key_name, def_val, buffer );
791 return strlen( buffer );
793 if (key_name && !(key_name[0]))
794 /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227 */
795 return 0;
796 if (section && section[0])
797 return PROFILE_GetSection(CurProfile->section, section, buffer, len,
798 FALSE, FALSE);
799 buffer[0] = '\0';
800 return 0;
804 /***********************************************************************
805 * PROFILE_SetString
807 * Set a profile string.
809 static BOOL PROFILE_SetString( LPCSTR section_name, LPCSTR key_name,
810 LPCSTR value )
812 if (!key_name) /* Delete a whole section */
814 TRACE("('%s')\n", section_name);
815 CurProfile->changed |= PROFILE_DeleteSection( &CurProfile->section,
816 section_name );
817 return TRUE; /* Even if PROFILE_DeleteSection() has failed,
818 this is not an error on application's level.*/
820 else if (!value) /* Delete a key */
822 TRACE("('%s','%s')\n",
823 section_name, key_name );
824 CurProfile->changed |= PROFILE_DeleteKey( &CurProfile->section,
825 section_name, key_name );
826 return TRUE; /* same error handling as above */
828 else /* Set the key value */
830 PROFILEKEY *key = PROFILE_Find( &CurProfile->section, section_name,
831 key_name, TRUE );
832 TRACE("('%s','%s','%s'): \n",
833 section_name, key_name, value );
834 if (!key) return FALSE;
835 if (key->value)
837 /* strip the leading spaces. We can safely strip \n\r and
838 * friends too, they should not happen here anyway. */
839 while (PROFILE_isspace(*value)) value++;
841 if (!strcmp( key->value, value ))
843 TRACE(" no change needed\n" );
844 return TRUE; /* No change needed */
846 TRACE(" replacing '%s'\n", key->value );
847 HeapFree( GetProcessHeap(), 0, key->value );
849 else TRACE(" creating key\n" );
850 key->value = HEAP_strdupA( GetProcessHeap(), 0, value );
851 CurProfile->changed = TRUE;
853 return TRUE;
857 /***********************************************************************
858 * PROFILE_GetWineIniString
860 * Get a config string from the wine.ini file.
862 int PROFILE_GetWineIniString( const char *section, const char *key_name,
863 const char *def, char *buffer, int len )
865 char tmp[PROFILE_MAX_LINE_LEN];
866 HKEY hkey;
867 DWORD err;
869 if (!(err = RegOpenKeyA( wine_profile_key, section, &hkey )))
871 DWORD type;
872 DWORD count = sizeof(tmp);
873 err = RegQueryValueExA( hkey, key_name, 0, &type, tmp, &count );
874 RegCloseKey( hkey );
876 PROFILE_CopyEntry( buffer, err ? def : tmp, len, TRUE );
877 TRACE( "('%s','%s','%s'): returning '%s'\n", section, key_name, def, buffer );
878 return strlen(buffer);
882 /***********************************************************************
883 * PROFILE_EnumWineIniString
885 * Get a config string from the wine.ini file.
887 BOOL PROFILE_EnumWineIniString( const char *section, int index,
888 char *name, int name_len, char *buffer, int len )
890 char tmp[PROFILE_MAX_LINE_LEN];
891 HKEY hkey;
892 DWORD err, type;
893 DWORD count = sizeof(tmp);
895 if (RegOpenKeyA( wine_profile_key, section, &hkey )) return FALSE;
896 err = RegEnumValueA( hkey, index, name, (DWORD*)&name_len, NULL, &type, tmp, &count );
897 RegCloseKey( hkey );
898 if (!err)
900 PROFILE_CopyEntry( buffer, tmp, len, TRUE );
901 TRACE( "('%s',%d): returning '%s'='%s'\n", section, index, name, buffer );
903 return !err;
907 /***********************************************************************
908 * PROFILE_GetWineIniInt
910 * Get a config integer from the wine.ini file.
912 int PROFILE_GetWineIniInt( const char *section, const char *key_name, int def )
914 char buffer[20];
915 char *p;
916 long result;
918 PROFILE_GetWineIniString( section, key_name, "", buffer, sizeof(buffer) );
919 if (!buffer[0]) return def;
920 result = strtol( buffer, &p, 0 );
921 return (p == buffer) ? 0 /* No digits at all */ : (int)result;
925 /******************************************************************************
927 * int PROFILE_GetWineIniBool(
928 * char const *section,
929 * char const *key_name,
930 * int def )
932 * Reads a boolean value from the wine.ini file. This function attempts to
933 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
934 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
935 * true. Anything else results in the return of the default value.
937 * This function uses 1 to indicate true, and 0 for false. You can check
938 * for existence by setting def to something other than 0 or 1 and
939 * examining the return value.
941 int PROFILE_GetWineIniBool(
942 char const *section,
943 char const *key_name,
944 int def )
946 char key_value[2];
947 int retval;
949 PROFILE_GetWineIniString(section, key_name, "~", key_value, 2);
951 switch(key_value[0]) {
952 case 'n':
953 case 'N':
954 case 'f':
955 case 'F':
956 case '0':
957 retval = 0;
958 break;
960 case 'y':
961 case 'Y':
962 case 't':
963 case 'T':
964 case '1':
965 retval = 1;
966 break;
968 default:
969 retval = def;
972 TRACE("(\"%s\", \"%s\", %s), "
973 "[%c], ret %s.\n", section, key_name,
974 def ? "TRUE" : "FALSE", key_value[0],
975 retval ? "TRUE" : "FALSE");
977 return retval;
981 /***********************************************************************
982 * PROFILE_LoadWineIni
984 * Load the wine.ini file.
986 int PROFILE_LoadWineIni(void)
988 char buffer[MAX_PATHNAME_LEN];
989 const char *p;
990 FILE *f;
991 HKEY hKeySW;
992 DWORD disp;
994 /* make sure HKLM\\Software\\Wine\\Wine exists as non-volatile key */
995 if (RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine", &hKeySW ))
997 ERR("Cannot create config registry key\n" );
998 return 0;
1000 RegCloseKey( hKeySW );
1001 if (RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config", 0, NULL,
1002 REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &wine_profile_key, &disp ))
1004 ERR("Cannot create config registry key\n" );
1005 return 0;
1008 if (!CLIENT_IsBootThread()) return 1; /* already loaded */
1010 if ( (Options.configFileName!=NULL) && (f = fopen(Options.configFileName, "r")) )
1012 /* Open -config specified file */
1013 lstrcpynA(PROFILE_WineIniUsed,Options.configFileName,MAX_PATHNAME_LEN);
1014 goto found;
1017 if ( (p = getenv( "WINE_INI" )) && (f = fopen( p, "r" )) )
1019 lstrcpynA(PROFILE_WineIniUsed,p,MAX_PATHNAME_LEN);
1020 goto found;
1022 if ((p = getenv( "HOME" )) != NULL)
1024 lstrcpynA(buffer, p, MAX_PATHNAME_LEN - sizeof(PROFILE_WineIniName));
1025 strcat( buffer, PROFILE_WineIniName );
1026 if ((f = fopen( buffer, "r" )) != NULL)
1028 lstrcpynA(PROFILE_WineIniUsed,buffer,MAX_PATHNAME_LEN);
1029 goto found;
1032 else WARN("could not get $HOME value for config file.\n" );
1034 /* Try global file */
1036 if ((f = fopen( WINE_INI_GLOBAL, "r" )) != NULL)
1038 lstrcpynA(PROFILE_WineIniUsed,WINE_INI_GLOBAL,MAX_PATHNAME_LEN);
1039 goto found;
1042 if (disp == REG_OPENED_EXISTING_KEY) return 1; /* loaded by the server */
1044 MESSAGE( "Can't open configuration file %s or $HOME%s\n",
1045 WINE_INI_GLOBAL, PROFILE_WineIniName );
1046 return 0;
1048 found:
1050 if (disp == REG_OPENED_EXISTING_KEY)
1052 MESSAGE( "Warning: configuration loaded by the server from %s/config,\n"
1053 " file %s was ignored.\n", get_config_dir(), PROFILE_WineIniUsed );
1054 fclose( f );
1055 return 1;
1058 PROFILE_RegistryLoad( wine_profile_key, f );
1059 fclose( f );
1060 return 1;
1064 /***********************************************************************
1065 * PROFILE_UsageWineIni
1067 * Explain the wine.ini file to those who don't read documentation.
1068 * Keep below one screenful in length so that error messages above are
1069 * noticed.
1071 void PROFILE_UsageWineIni(void)
1073 MESSAGE("Perhaps you have not properly edited or created "
1074 "your Wine configuration file.\n");
1075 MESSAGE("This is either %s or $HOME%s\n",WINE_INI_GLOBAL,PROFILE_WineIniName);
1076 MESSAGE(" or it is determined by the -config option or from\n"
1077 " the WINE_INI environment variable.\n");
1078 if (*PROFILE_WineIniUsed)
1079 MESSAGE("Wine has used %s as configuration file.\n", PROFILE_WineIniUsed);
1080 /* RTFM, so to say */
1083 /***********************************************************************
1084 * PROFILE_GetStringItem
1086 * Convenience function that turns a string 'xxx, yyy, zzz' into
1087 * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
1089 char* PROFILE_GetStringItem( char* start )
1091 char* lpchX, *lpch;
1093 for (lpchX = start, lpch = NULL; *lpchX != '\0'; lpchX++ )
1095 if( *lpchX == ',' )
1097 if( lpch ) *lpch = '\0'; else *lpchX = '\0';
1098 while( *(++lpchX) )
1099 if( !PROFILE_isspace(*lpchX) ) return lpchX;
1101 else if( PROFILE_isspace( *lpchX ) && !lpch ) lpch = lpchX;
1102 else lpch = NULL;
1104 if( lpch ) *lpch = '\0';
1105 return NULL;
1108 /********************* API functions **********************************/
1110 /***********************************************************************
1111 * GetProfileInt16 (KERNEL.57)
1113 UINT16 WINAPI GetProfileInt16( LPCSTR section, LPCSTR entry, INT16 def_val )
1115 return GetPrivateProfileInt16( section, entry, def_val, "win.ini" );
1119 /***********************************************************************
1120 * GetProfileIntA (KERNEL32.264)
1122 UINT WINAPI GetProfileIntA( LPCSTR section, LPCSTR entry, INT def_val )
1124 return GetPrivateProfileIntA( section, entry, def_val, "win.ini" );
1127 /***********************************************************************
1128 * GetProfileIntW (KERNEL32.264)
1130 UINT WINAPI GetProfileIntW( LPCWSTR section, LPCWSTR entry, INT def_val )
1132 return GetPrivateProfileIntW( section, entry, def_val, wininiW );
1136 * undoc_feature means:
1137 * return section names string list if both section and entry are NULL.
1139 static int PROFILE_GetPrivateProfileString( LPCSTR section, LPCSTR entry,
1140 LPCSTR def_val, LPSTR buffer,
1141 UINT16 len, LPCSTR filename,
1142 BOOL undoc_feature )
1144 int ret;
1145 LPSTR pDefVal = NULL;
1147 if (!filename)
1148 filename = "win.ini";
1150 /* strip any trailing ' ' of def_val. */
1151 if (def_val)
1153 LPSTR p = (LPSTR)&def_val[strlen(def_val)]; /* even "" works ! */
1155 while (p > def_val)
1157 p--;
1158 if ((*p) != ' ')
1159 break;
1161 if (*p == ' ') /* ouch, contained trailing ' ' */
1163 int len = (int)p - (int)def_val;
1164 pDefVal = HeapAlloc(GetProcessHeap(), 0, len + 1);
1165 strncpy(pDefVal, def_val, len);
1166 pDefVal[len] = '\0';
1169 if (!pDefVal)
1170 pDefVal = (LPSTR)def_val;
1172 EnterCriticalSection( &PROFILE_CritSect );
1174 if (PROFILE_Open( filename )) {
1175 if ((undoc_feature) && (section == NULL) && (entry == NULL))
1176 /* undocumented; both section and entry are NULL */
1177 ret = PROFILE_GetSectionNames(buffer, len);
1178 else
1179 ret = PROFILE_GetString( section, entry, pDefVal, buffer, len );
1180 } else {
1181 lstrcpynA( buffer, pDefVal, len );
1182 ret = strlen( buffer );
1185 LeaveCriticalSection( &PROFILE_CritSect );
1187 if (pDefVal != def_val) /* allocated */
1188 HeapFree(GetProcessHeap(), 0, pDefVal);
1190 return ret;
1193 /***********************************************************************
1194 * GetPrivateProfileString16 (KERNEL.128)
1196 INT16 WINAPI GetPrivateProfileString16( LPCSTR section, LPCSTR entry,
1197 LPCSTR def_val, LPSTR buffer,
1198 UINT16 len, LPCSTR filename )
1200 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1201 buffer, len, filename, FALSE );
1204 /***********************************************************************
1205 * GetPrivateProfileStringA (KERNEL32.255)
1207 INT WINAPI GetPrivateProfileStringA( LPCSTR section, LPCSTR entry,
1208 LPCSTR def_val, LPSTR buffer,
1209 UINT len, LPCSTR filename )
1211 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1212 buffer, len, filename, TRUE );
1215 /***********************************************************************
1216 * GetPrivateProfileStringW (KERNEL32.256)
1218 INT WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1219 LPCWSTR def_val, LPWSTR buffer,
1220 UINT len, LPCWSTR filename )
1222 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1223 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1224 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1225 LPSTR def_valA = HEAP_strdupWtoA( GetProcessHeap(), 0, def_val );
1226 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1227 INT ret = GetPrivateProfileStringA( sectionA, entryA, def_valA,
1228 bufferA, len, filenameA );
1229 lstrcpynAtoW( buffer, bufferA, len );
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 && !filename)
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 lstrcpynAtoW( buffer, bufferA, size);
1607 HeapFree( GetProcessHeap(), 0, bufferA);
1608 HeapFree( GetProcessHeap(), 0, filenameA );
1610 return ret;
1613 /***********************************************************************
1614 * GetPrivateProfileStruct16 (KERNEL.407)
1616 BOOL16 WINAPI GetPrivateProfileStruct16(LPCSTR section, LPCSTR key,
1617 LPVOID buf, UINT16 len, LPCSTR filename)
1619 return GetPrivateProfileStructA( section, key, buf, len, filename );
1622 /***********************************************************************
1623 * GetPrivateProfileStructA (KERNEL32.370)
1625 * Should match Win95's behaviour pretty much
1627 BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key,
1628 LPVOID buf, UINT len, LPCSTR filename)
1630 BOOL ret = FALSE;
1632 EnterCriticalSection( &PROFILE_CritSect );
1634 if (PROFILE_Open( filename )) {
1635 PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE);
1636 if (k) {
1637 TRACE("value (at %p): '%s'\n", k->value, k->value);
1638 if (((strlen(k->value) - 2) / 2) == len)
1640 LPSTR end, p;
1641 BOOL valid = TRUE;
1642 CHAR c;
1643 DWORD chksum = 0;
1645 end = k->value + strlen(k->value); /* -> '\0' */
1646 /* check for invalid chars in ASCII coded hex string */
1647 for (p=k->value; p < end; p++)
1649 if (!isxdigit(*p))
1651 WARN("invalid char '%c' in file '%s'->'[%s]'->'%s' !\n",
1652 *p, filename, section, key);
1653 valid = FALSE;
1654 break;
1657 if (valid)
1659 BOOL highnibble = TRUE;
1660 BYTE b = 0, val;
1661 LPBYTE binbuf = (LPBYTE)buf;
1663 end -= 2; /* don't include checksum in output data */
1664 /* translate ASCII hex format into binary data */
1665 for (p=k->value; p < end; p++)
1667 c = toupper(*p);
1668 val = (c > '9') ?
1669 (c - 'A' + 10) : (c - '0');
1671 if (highnibble)
1672 b = val << 4;
1673 else
1675 b += val;
1676 *binbuf++ = b; /* feed binary data into output */
1677 chksum += b; /* calculate checksum */
1679 highnibble ^= 1; /* toggle */
1681 /* retrieve stored checksum value */
1682 c = toupper(*p++);
1683 b = ( (c > '9') ? (c - 'A' + 10) : (c - '0') ) << 4;
1684 c = toupper(*p);
1685 b += (c > '9') ? (c - 'A' + 10) : (c - '0');
1686 if (b == (chksum & 0xff)) /* checksums match ? */
1687 ret = TRUE;
1692 LeaveCriticalSection( &PROFILE_CritSect );
1694 return ret;
1697 /***********************************************************************
1698 * GetPrivateProfileStructW (KERNEL32.543)
1700 BOOL WINAPI GetPrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1701 LPVOID buffer, UINT len, LPCWSTR filename)
1703 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1704 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1705 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1706 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1708 INT ret = GetPrivateProfileStructA( sectionA, keyA, bufferA,
1709 len, filenameA );
1710 lstrcpynAtoW( buffer, bufferA, len );
1711 HeapFree( GetProcessHeap(), 0, bufferA);
1712 HeapFree( GetProcessHeap(), 0, sectionA );
1713 HeapFree( GetProcessHeap(), 0, keyA );
1714 HeapFree( GetProcessHeap(), 0, filenameA );
1716 return ret;
1721 /***********************************************************************
1722 * WritePrivateProfileStruct16 (KERNEL.406)
1724 BOOL16 WINAPI WritePrivateProfileStruct16 (LPCSTR section, LPCSTR key,
1725 LPVOID buf, UINT16 bufsize, LPCSTR filename)
1727 return WritePrivateProfileStructA( section, key, buf, bufsize, filename );
1730 /***********************************************************************
1731 * WritePrivateProfileStructA (KERNEL32.744)
1733 BOOL WINAPI WritePrivateProfileStructA (LPCSTR section, LPCSTR key,
1734 LPVOID buf, UINT bufsize, LPCSTR filename)
1736 BOOL ret = FALSE;
1737 LPBYTE binbuf;
1738 LPSTR outstring, p;
1739 DWORD sum = 0;
1741 if (!section && !key && !buf) /* flush the cache */
1742 return WritePrivateProfileStringA( NULL, NULL, NULL, filename );
1744 /* allocate string buffer for hex chars + checksum hex char + '\0' */
1745 outstring = HeapAlloc( GetProcessHeap(), 0, bufsize*2 + 2 + 1);
1746 p = outstring;
1747 for (binbuf = (LPBYTE)buf; binbuf < (LPBYTE)buf+bufsize; binbuf++) {
1748 *p++ = hex[*binbuf >> 4];
1749 *p++ = hex[*binbuf & 0xf];
1750 sum += *binbuf;
1752 /* checksum is sum & 0xff */
1753 *p++ = hex[(sum & 0xf0) >> 4];
1754 *p++ = hex[sum & 0xf];
1755 *p++ = '\0';
1757 EnterCriticalSection( &PROFILE_CritSect );
1759 if (PROFILE_Open( filename ))
1760 ret = PROFILE_SetString( section, key, outstring );
1762 LeaveCriticalSection( &PROFILE_CritSect );
1764 HeapFree( GetProcessHeap(), 0, outstring );
1766 return ret;
1769 /***********************************************************************
1770 * WritePrivateProfileStructW (KERNEL32.544)
1772 BOOL WINAPI WritePrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1773 LPVOID buf, UINT bufsize, LPCWSTR filename)
1775 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1776 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1777 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1778 INT ret = WritePrivateProfileStructA( sectionA, keyA, buf, bufsize,
1779 filenameA );
1780 HeapFree( GetProcessHeap(), 0, sectionA );
1781 HeapFree( GetProcessHeap(), 0, keyA );
1782 HeapFree( GetProcessHeap(), 0, filenameA );
1784 return ret;
1788 /***********************************************************************
1789 * WriteOutProfiles (KERNEL.315)
1791 void WINAPI WriteOutProfiles16(void)
1793 EnterCriticalSection( &PROFILE_CritSect );
1794 PROFILE_FlushFile();
1795 LeaveCriticalSection( &PROFILE_CritSect );
1798 /***********************************************************************
1799 * CloseProfileUserMapping (KERNEL.138)
1801 BOOL WINAPI CloseProfileUserMapping(void) {
1802 FIXME("(), stub!\n");
1803 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1804 return FALSE;