source: trunk/src/kernel32/profile.cpp@ 516

Last change on this file since 516 was 436, checked in by phaller, 26 years ago

Fix: Heap changes

File size: 41.9 KB
Line 
1/* $Id: profile.cpp,v 1.8 1999-08-06 12:14:12 phaller Exp $ */
2
3/*
4 * Project Odin Software License can be found in LICENSE.TXT
5 *
6 * Win32 profile API functions
7 *
8 * Copyright 1993 Miguel de Icaza
9 * Copyright 1996 Alexandre Julliard
10 * Copyright 1998 Sander van Leeuwen (sandervl@xs4all.nl)
11 * Copyright 1998 Patrick Haller
12 */
13
14#include <os2win.h>
15#include <ctype.h>
16#include <stdlib.h>
17#include <string.h>
18#include <stdio.h>
19#include <unicode.h>
20#include "heap.h"
21#include "heapstring.h"
22
23#include <sys/stat.h>
24
25#include "winbase.h"
26//#include "wine/winbase16.h"
27#include "winuser.h"
28#include "winnls.h"
29
30
31// -------------------------
32// WINE compatibility macros
33// -------------------------
34
35#ifndef MAX_PATHNAME_LEN
36#define MAX_PATHNAME_LEN 260
37#endif
38
39#define SystemHeap GetProcessHeap()
40#define strcasecmp strcmp
41#define DOSFS_GetFullName(a,b,c) strcpy(c,a)
42//#define lstrcpynA(a,b,c) strncpy((char*)a,(char*)b,(int)c)
43#define CharLowerA(a) (a)
44
45
46typedef struct tagPROFILEKEY
47{
48 char *name;
49 char *value;
50 struct tagPROFILEKEY *next;
51} PROFILEKEY;
52
53typedef struct tagPROFILESECTION
54{
55 char *name;
56 struct tagPROFILEKEY *key;
57 struct tagPROFILESECTION *next;
58} PROFILESECTION;
59
60
61typedef struct
62{
63 BOOL changed;
64 PROFILESECTION *section;
65 char *filename;
66 time_t mtime;
67} PROFILE;
68
69
70#define N_CACHED_PROFILES 10
71
72/* Cached profile files */
73static PROFILE *MRUProfile[N_CACHED_PROFILES]={NULL};
74
75#define CurProfile (MRUProfile[0])
76
77/* wine.ini profile content */
78static PROFILESECTION *PROFILE_WineProfile;
79
80#define PROFILE_MAX_LINE_LEN 1024
81
82/* Wine profile name in $HOME directory; must begin with slash */
83static const char PROFILE_WineIniName[] = "/.winerc";
84
85/* Wine profile: the profile file being used */
86static char PROFILE_WineIniUsed[MAX_PATHNAME_LEN] = "";
87
88/* Check for comments in profile */
89#define IS_ENTRY_COMMENT(str) ((str)[0] == ';')
90
91#define WINE_INI_GLOBAL ETCDIR "/wine.conf"
92
93static LPCWSTR wininiW = NULL;
94
95static CRITICAL_SECTION PROFILE_CritSect;
96
97
98/***********************************************************************
99 * PROFILE_CopyEntry
100 *
101 * Copy the content of an entry into a buffer, removing quotes, and possibly
102 * translating environment variables.
103 */
104static void PROFILE_CopyEntry( char *buffer,
105 const char *value,
106 int len,
107 int handle_env )
108{
109 char quote = '\0';
110 const char *p;
111
112 if ((*value == '\'') || (*value == '\"'))
113 {
114 if (value[1] && (value[strlen(value)-1] == *value)) quote = *value++;
115 }
116
117 if (!handle_env)
118 {
119 lstrcpynA( buffer, value, len );
120 if (quote && (len >= strlen(value))) buffer[strlen(buffer)-1] = '\0';
121 return;
122 }
123
124 for (p = value; (*p && (len > 1)); *buffer++ = *p++, len-- )
125 {
126 if ((*p == '$') && (p[1] == '{'))
127 {
128 char env_val[1024];
129 const char *env_p;
130 const char *p2 = strchr( p, '}' );
131 if (!p2) continue; /* ignore it */
132 lstrcpynA(env_val, p + 2, MIN( sizeof(env_val), (int)(p2-p)-1 ));
133 if ((env_p = getenv( env_val )) != NULL)
134 {
135 lstrcpynA( buffer, env_p, len );
136 buffer += strlen( buffer );
137 len -= strlen( buffer );
138 }
139 p = p2 + 1;
140 }
141 }
142 *buffer = '\0';
143}
144
145
146/***********************************************************************
147 * PROFILE_Save
148 *
149 * Save a profile tree to a file.
150 */
151static void PROFILE_Save( FILE *file, PROFILESECTION *section )
152{
153 PROFILEKEY *key;
154
155 for ( ; section; section = section->next)
156 {
157 if (section->name) fprintf( file, "\r\n[%s]\r\n", section->name );
158 for (key = section->key; key; key = key->next)
159 {
160 fprintf( file, "%s", key->name );
161 if (key->value) fprintf( file, "=%s", key->value );
162 fprintf( file, "\r\n" );
163 }
164 }
165}
166
167
168/***********************************************************************
169 * PROFILE_Free
170 *
171 * Free a profile tree.
172 */
173static void PROFILE_Free( PROFILESECTION *section )
174{
175 PROFILESECTION *next_section;
176 PROFILEKEY *key, *next_key;
177
178 for ( ; section; section = next_section)
179 {
180 if (section->name) HeapFree( SystemHeap, 0, section->name );
181 for (key = section->key; key; key = next_key)
182 {
183 next_key = key->next;
184 if (key->name) HeapFree( SystemHeap, 0, key->name );
185 if (key->value) HeapFree( SystemHeap, 0, key->value );
186 HeapFree( SystemHeap, 0, key );
187 }
188 next_section = section->next;
189 HeapFree( SystemHeap, 0, section );
190 }
191}
192
193static int
194PROFILE_isspace(char c) {
195 if (isspace(c)) return 1;
196 if (c=='\r' || c==0x1a) return 1;
197 /* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */
198 return 0;
199}
200
201
202/***********************************************************************
203 * PROFILE_Load
204 *
205 * Load a profile tree from a file.
206 */
207static PROFILESECTION *PROFILE_Load( FILE *file )
208{
209 char buffer[PROFILE_MAX_LINE_LEN];
210 char *p, *p2;
211 int line = 0;
212 PROFILESECTION *section, *first_section;
213 PROFILESECTION **next_section;
214 PROFILEKEY *key, *prev_key, **next_key;
215
216 first_section = (PROFILESECTION *)HEAP_xalloc( SystemHeap, 0, sizeof(*section) );
217 first_section->name = NULL;
218 first_section->key = NULL;
219 first_section->next = NULL;
220 next_section = &first_section->next;
221 next_key = &first_section->key;
222 prev_key = NULL;
223
224 while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
225 {
226 line++;
227 p = buffer;
228 while (*p && PROFILE_isspace(*p)) p++;
229 if (*p == '[') /* section start */
230 {
231 if (!(p2 = strrchr( p, ']' )))
232 {
233 dprintf(("Kernel32:Profile:Invalid section header at line %d: '%s'\n",
234 line, p ));
235 }
236 else
237 {
238 *p2 = '\0';
239 p++;
240 section = (PROFILESECTION*)HEAP_xalloc( SystemHeap, 0, sizeof(*section) );
241 section->name = HEAP_strdupA( SystemHeap, 0, p );
242 section->key = NULL;
243 section->next = NULL;
244 *next_section = section;
245 next_section = &section->next;
246 next_key = &section->key;
247 prev_key = NULL;
248
249 dprintf(("Kernel32:Profile:New section: '%s'\n",section->name));
250
251 continue;
252 }
253 }
254
255 p2=p+strlen(p) - 1;
256 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
257
258 if ((p2 = strchr( p, '=' )) != NULL)
259 {
260 char *p3 = p2 - 1;
261 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
262 *p2++ = '\0';
263 while (*p2 && PROFILE_isspace(*p2)) p2++;
264 }
265
266 if(*p || !prev_key || *prev_key->name)
267 {
268 key = (PROFILEKEY*)HEAP_xalloc( SystemHeap, 0, sizeof(*key) );
269 key->name = HEAP_strdupA( SystemHeap, 0, p );
270 key->value = p2 ? HEAP_strdupA( SystemHeap, 0, p2 ) : NULL;
271 key->next = NULL;
272 *next_key = key;
273 next_key = &key->next;
274 prev_key = key;
275
276 dprintf(("Kernel32:Profile:New key: name='%s', value='%s'\n",key->name,key->value?key->value:"(none)"));
277 }
278 }
279 return first_section;
280}
281
282
283/***********************************************************************
284 * PROFILE_DeleteSection
285 *
286 * Delete a section from a profile tree.
287 */
288static BOOL PROFILE_DeleteSection( PROFILESECTION **section, LPCSTR name )
289{
290 while (*section)
291 {
292 if ((*section)->name && !strcasecmp( (*section)->name, name ))
293 {
294 PROFILESECTION *to_del = *section;
295 *section = to_del->next;
296 to_del->next = NULL;
297 PROFILE_Free( to_del );
298 return TRUE;
299 }
300 section = &(*section)->next;
301 }
302 return FALSE;
303}
304
305
306/***********************************************************************
307 * PROFILE_DeleteKey
308 *
309 * Delete a key from a profile tree.
310 */
311static BOOL PROFILE_DeleteKey( PROFILESECTION **section,
312 LPCSTR section_name, LPCSTR key_name )
313{
314 while (*section)
315 {
316 if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
317 {
318 PROFILEKEY **key = &(*section)->key;
319 while (*key)
320 {
321 if (!strcasecmp( (*key)->name, key_name ))
322 {
323 PROFILEKEY *to_del = *key;
324 *key = to_del->next;
325 if (to_del->name) HeapFree( SystemHeap, 0, to_del->name );
326 if (to_del->value) HeapFree( SystemHeap, 0, to_del->value);
327 HeapFree( SystemHeap, 0, to_del );
328 return TRUE;
329 }
330 key = &(*key)->next;
331 }
332 }
333 section = &(*section)->next;
334 }
335 return FALSE;
336}
337
338
339/***********************************************************************
340 * PROFILE_Find
341 *
342 * Find a key in a profile tree, optionally creating it.
343 */
344static PROFILEKEY *PROFILE_Find( PROFILESECTION **section,
345 const char *section_name,
346 const char *key_name, int create )
347{
348 while (*section)
349 {
350 if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
351 {
352 PROFILEKEY **key = &(*section)->key;
353 while (*key)
354 {
355 if (!strcasecmp( (*key)->name, key_name )) return *key;
356 key = &(*key)->next;
357 }
358 if (!create) return NULL;
359 *key = (PROFILEKEY*)HEAP_xalloc( SystemHeap, 0, sizeof(PROFILEKEY) );
360 (*key)->name = HEAP_strdupA( SystemHeap, 0, key_name );
361 (*key)->value = NULL;
362 (*key)->next = NULL;
363 return *key;
364 }
365 section = &(*section)->next;
366 }
367 if (!create) return NULL;
368 *section = (PROFILESECTION*)HEAP_xalloc( SystemHeap, 0, sizeof(PROFILESECTION) );
369 (*section)->name = HEAP_strdupA( SystemHeap, 0, section_name );
370 (*section)->next = NULL;
371 (*section)->key = (tagPROFILEKEY*)HEAP_xalloc( SystemHeap, 0, sizeof(PROFILEKEY) );
372 (*section)->key->name = HEAP_strdupA( SystemHeap, 0, key_name );
373 (*section)->key->value = NULL;
374 (*section)->key->next = NULL;
375 return (*section)->key;
376}
377
378
379/***********************************************************************
380 * PROFILE_FlushFile
381 *
382 * Flush the current profile to disk if changed.
383 */
384static BOOL PROFILE_FlushFile(void)
385{
386 FILE *file = NULL;
387 struct stat buf;
388
389 if(!CurProfile)
390 {
391 dprintf(("Kernel32:Profile:No current profile!\n"));
392 return FALSE;
393 }
394
395 // not changed, return immediately
396 if (!CurProfile->changed)
397 return TRUE;
398
399 // try to open file
400 file = fopen(CurProfile->filename, "w");
401 if (!file)
402 {
403 dprintf(("Kernel32:Profile:could not save profile file %s\n", CurProfile->filename));
404 return FALSE;
405 }
406
407 dprintf(("Kernel32:Profile:Saving %s\n", CurProfile->filename ));
408 PROFILE_Save( file, CurProfile->section );
409 fclose( file );
410 CurProfile->changed = FALSE;
411 if(!stat(CurProfile->filename,&buf))
412 CurProfile->mtime=buf.st_mtime;
413 return TRUE;
414}
415
416
417/***********************************************************************
418 * PROFILE_ReleaseFile
419 *
420 * Flush the current profile to disk and remove it from the cache.
421 */
422static void PROFILE_ReleaseFile(void)
423{
424 PROFILE_FlushFile();
425 PROFILE_Free( CurProfile->section );
426 if (CurProfile->filename) HeapFree( SystemHeap, 0, CurProfile->filename );
427 CurProfile->changed = FALSE;
428 CurProfile->section = NULL;
429 CurProfile->filename = NULL;
430 CurProfile->mtime = 0;
431}
432
433
434/***********************************************************************
435 * PROFILE_Open
436 *
437 * Open a profile file, checking the cached file first.
438 */
439static BOOL PROFILE_Open( LPCSTR filename )
440{
441 char buffer[MAX_PATHNAME_LEN];
442 FILE *file = NULL;
443 int i,j;
444 struct stat buf;
445 PROFILE *tempProfile;
446
447 /* First time around */
448
449 if(!CurProfile)
450 for(i=0;i<N_CACHED_PROFILES;i++)
451 {
452 MRUProfile[i]= (PROFILE*)HEAP_xalloc( SystemHeap, 0, sizeof(PROFILE) );
453 MRUProfile[i]->changed=FALSE;
454 MRUProfile[i]->section=NULL;
455 MRUProfile[i]->filename=NULL;
456 MRUProfile[i]->mtime=0;
457 }
458
459 /* Check for a match */
460
461 if (!strchr( filename, '/' ) &&
462 !strchr( filename, '\\' ) &&
463 !strchr( filename, ':' ))
464 {
465 GetWindowsDirectoryA( buffer, sizeof(buffer) );
466 strcat( buffer, "\\" );
467 strcat( buffer, filename );
468 }
469
470 for(i=0;i<N_CACHED_PROFILES;i++)
471 {
472 if ((MRUProfile[i]->filename && !strcmp( filename, MRUProfile[i]->filename )))
473 {
474 if(i)
475 {
476 PROFILE_FlushFile();
477 tempProfile=MRUProfile[i];
478 for(j=i;j>0;j--)
479 MRUProfile[j]=MRUProfile[j-1];
480 CurProfile=tempProfile;
481 }
482 if(!stat(CurProfile->filename,&buf) && CurProfile->mtime==buf.st_mtime)
483 dprintf(("Kernel32:Profile:(%s): already opened (mru=%d)\n",
484 filename, i ));
485 else
486 dprintf(("Kernel32:Profile:(%s): already opened, needs refreshing (mru=%d)\n",
487 filename, i ));
488 return TRUE;
489 }
490 }
491
492 /* Rotate the oldest to the top to be replaced */
493
494 if(i==N_CACHED_PROFILES)
495 {
496 tempProfile=MRUProfile[N_CACHED_PROFILES-1];
497 for(i=N_CACHED_PROFILES-1;i>0;i--)
498 MRUProfile[i]=MRUProfile[i-1];
499 CurProfile=tempProfile;
500 }
501
502 /* Flush the profile */
503
504 if(CurProfile->filename) PROFILE_ReleaseFile();
505
506 CurProfile->filename = HEAP_strdupA( SystemHeap, 0, filename );
507
508 file = fopen( filename, "r" );
509 if (file)
510 {
511 dprintf(("Kernel32:Profile:(%s): found it in %s\n",
512 filename, filename ));
513
514 CurProfile->section = PROFILE_Load( file );
515 fclose( file );
516 if(!stat(CurProfile->filename,&buf))
517 CurProfile->mtime=buf.st_mtime;
518 }
519 else
520 {
521 /* Does not exist yet, we will create it in PROFILE_FlushFile */
522 dprintf(("Kernel32:Profile:profile file %s not found\n", filename ));
523 }
524 return TRUE;
525}
526
527
528/***********************************************************************
529 * PROFILE_GetSection
530 *
531 * Returns all keys of a section.
532 * If return_values is TRUE, also include the corresponding values.
533 */
534static INT PROFILE_GetSection( PROFILESECTION *section, LPCSTR section_name,
535 LPSTR buffer, UINT len, BOOL handle_env,
536 BOOL return_values )
537{
538 PROFILEKEY *key;
539 while (section)
540 {
541 if (section->name && !strcasecmp( section->name, section_name ))
542 {
543 UINT oldlen = len;
544 for (key = section->key; key; key = key->next)
545 {
546 if (len <= 2) break;
547 if (!*key->name) continue; /* Skip empty lines */
548 if (IS_ENTRY_COMMENT(key->name)) continue; /* Skip comments */
549 PROFILE_CopyEntry( buffer, key->name, len - 1, handle_env );
550 len -= strlen(buffer) + 1;
551 buffer += strlen(buffer) + 1;
552 if (return_values && key->value) {
553 buffer[-1] = '=';
554 PROFILE_CopyEntry ( buffer,
555 key->value, len - 1, handle_env );
556 len -= strlen(buffer) + 1;
557 buffer += strlen(buffer) + 1;
558 }
559 }
560 *buffer = '\0';
561 if (len <= 1)
562 /*If either lpszSection or lpszKey is NULL and the supplied
563 destination buffer is too small to hold all the strings,
564 the last string is truncated and followed by two null characters.
565 In this case, the return value is equal to cchReturnBuffer
566 minus two. */
567 {
568 buffer[-1] = '\0';
569 return oldlen - 2;
570 }
571 return oldlen - len;
572 }
573 section = section->next;
574 }
575 buffer[0] = buffer[1] = '\0';
576 return 0;
577}
578
579
580static INT PROFILE_GetSectionNames( LPSTR buffer, UINT len )
581{
582 LPSTR buf = buffer;
583 WORD l, cursize = 0;
584 PROFILESECTION *section;
585
586 for (section = CurProfile->section; section; section = section->next)
587 if (section->name) {
588 l = strlen(section->name);
589 cursize += l+1;
590 if (cursize > len+1)
591 return len-2;
592
593 strcpy(buf, section->name);
594 buf += l+1;
595 }
596
597 *buf=0;
598 buf++;
599 return buf-buffer;
600}
601
602
603/***********************************************************************
604 * PROFILE_GetString
605 *
606 * Get a profile string.
607 */
608static INT PROFILE_GetString( LPCSTR section, LPCSTR key_name,
609 LPCSTR def_val, LPSTR buffer, UINT len )
610{
611 PROFILEKEY *key = NULL;
612
613 if (!def_val) def_val = "";
614 if (key_name && key_name[0])
615 {
616 key = PROFILE_Find( &CurProfile->section, section, key_name, FALSE );
617 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def_val,
618 len, FALSE );
619 dprintf(("Kernel32:Profile:('%s','%s','%s'): returning '%s'\n",
620 section, key_name, def_val, buffer ));
621 return strlen( buffer );
622 }
623 if (section && section[0])
624 return PROFILE_GetSection(CurProfile->section, section, buffer, len,
625 FALSE, FALSE);
626 /* undocumented; both section and key_name are NULL */
627 return PROFILE_GetSectionNames(buffer, len);
628}
629
630
631/***********************************************************************
632 * PROFILE_SetString
633 *
634 * Set a profile string.
635 */
636static BOOL PROFILE_SetString( LPCSTR section_name, LPCSTR key_name,
637 LPCSTR value )
638{
639 if (!key_name) /* Delete a whole section */
640 {
641 dprintf(("Kernel32:Profile:('%s')\n", section_name));
642 CurProfile->changed |= PROFILE_DeleteSection( &CurProfile->section,
643 section_name );
644 return TRUE; /* Even if PROFILE_DeleteSection() has failed,
645 this is not an error on application's level.*/
646 }
647 else if (!value) /* Delete a key */
648 {
649 dprintf(("Kernel32:Profile:('%s','%s')\n",
650 section_name, key_name ));
651 CurProfile->changed |= PROFILE_DeleteKey( &CurProfile->section,
652 section_name, key_name );
653 return TRUE; /* same error handling as above */
654 }
655 else /* Set the key value */
656 {
657 PROFILEKEY *key = PROFILE_Find( &CurProfile->section, section_name,
658 key_name, TRUE );
659 dprintf(("Kernel32:Profile:('%s','%s','%s'): \n",
660 section_name, key_name, value ));
661 if (!key) return FALSE;
662 if (key->value)
663 {
664 if (!strcmp( key->value, value ))
665 {
666 dprintf(("Kernel32:Profile: no change needed\n" ));
667 return TRUE; /* No change needed */
668 }
669 dprintf(("Kernel32:Profile: replacing '%s'\n", key->value ));
670 HeapFree( SystemHeap, 0, key->value );
671 }
672 else dprintf(("Kernel32:Profile: creating key\n" ));
673 key->value = HEAP_strdupA( SystemHeap, 0, value );
674 CurProfile->changed = TRUE;
675 }
676 return TRUE;
677}
678
679
680/***********************************************************************
681 * PROFILE_GetWineIniString
682 *
683 * Get a config string from the wine.ini file.
684 */
685int PROFILE_GetWineIniString( const char *section, const char *key_name,
686 const char *def, char *buffer, int len )
687{
688 int ret;
689
690 EnterCriticalSection( &PROFILE_CritSect );
691
692 if (key_name)
693 {
694 PROFILEKEY *key = PROFILE_Find(&PROFILE_WineProfile, section, key_name, FALSE);
695 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def,
696 len, TRUE );
697 dprintf(("Kernel32:Profile:('%s','%s','%s'): returning '%s'\n",
698 section, key_name, def, buffer ));
699 ret = strlen( buffer );
700 }
701 else
702 {
703 ret = PROFILE_GetSection( PROFILE_WineProfile, section, buffer, len, TRUE, FALSE );
704 }
705 LeaveCriticalSection( &PROFILE_CritSect );
706
707 return ret;
708}
709
710
711/***********************************************************************
712 * PROFILE_GetWineIniInt
713 *
714 * Get a config integer from the wine.ini file.
715 */
716int PROFILE_GetWineIniInt( const char *section, const char *key_name, int def )
717{
718 char buffer[20];
719 char *p;
720 long result;
721 PROFILEKEY *key;
722 int ret;
723
724 EnterCriticalSection( &PROFILE_CritSect );
725
726 key = PROFILE_Find( &PROFILE_WineProfile, section, key_name, FALSE );
727 if (!key || !key->value) {
728 ret = def;
729 } else {
730 PROFILE_CopyEntry( buffer, key->value, sizeof(buffer), TRUE );
731 result = strtol( buffer, &p, 0 );
732 ret = (p == buffer) ? 0 /* No digits at all */ : (int)result;
733 }
734
735 LeaveCriticalSection( &PROFILE_CritSect );
736
737 return ret;
738}
739
740
741/******************************************************************************
742 *
743 * int PROFILE_EnumerateWineIniSection(
744 * char const *section, #Name of the section to enumerate
745 * void (*cbfn)(char const *key, char const *value, void *user),
746 * # Address of the callback function
747 * void *user ) # User-specified pointer.
748 *
749 * For each entry in a section in the wine.conf file, this function will
750 * call the specified callback function, informing it of each key and
751 * value. An optional user pointer may be passed to it (if this is not
752 * needed, pass NULL through it and ignore the value in the callback
753 * function).
754 *
755 * The callback function must accept three parameters:
756 * The name of the key (char const *)
757 * The value of the key (char const *)
758 * A user-specified parameter (void *)
759 * Note that the first two are char CONST *'s, not char *'s! The callback
760 * MUST not modify these strings!
761 *
762 * The return value indicates the number of times the callback function
763 * was called.
764 */
765int PROFILE_EnumerateWineIniSection(
766 char const *section,
767 void (*cbfn)(char const *, char const *, void *),
768 void *userptr )
769{
770 PROFILESECTION *scansect;
771 PROFILEKEY *scankey;
772 int calls = 0;
773
774 EnterCriticalSection( &PROFILE_CritSect );
775
776 /* Search for the correct section */
777 for(scansect = PROFILE_WineProfile; scansect; scansect = scansect->next) {
778 if(scansect->name && !strcasecmp(scansect->name, section)) {
779
780 /* Enumerate each key with the callback */
781 for(scankey = scansect->key; scankey; scankey = scankey->next) {
782
783 /* Ignore blank entries -- these shouldn't exist, but let's
784 be extra careful */
785 if(scankey->name[0]) {
786 cbfn(scankey->name, scankey->value, userptr);
787 ++calls;
788 }
789 }
790
791 break;
792 }
793 }
794 LeaveCriticalSection( &PROFILE_CritSect );
795
796 return calls;
797}
798
799
800/******************************************************************************
801 *
802 * int PROFILE_GetWineIniBool(
803 * char const *section,
804 * char const *key_name,
805 * int def )
806 *
807 * Reads a boolean value from the wine.ini file. This function attempts to
808 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
809 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
810 * true. Anything else results in the return of the default value.
811 *
812 * This function uses 1 to indicate true, and 0 for false. You can check
813 * for existence by setting def to something other than 0 or 1 and
814 * examining the return value.
815 */
816int PROFILE_GetWineIniBool(
817 char const *section,
818 char const *key_name,
819 int def )
820{
821 char key_value[2];
822 int retval;
823
824 PROFILE_GetWineIniString(section, key_name, "~", key_value, 2);
825
826 switch(key_value[0]) {
827 case 'n':
828 case 'N':
829 case 'f':
830 case 'F':
831 case '0':
832 retval = 0;
833 break;
834
835 case 'y':
836 case 'Y':
837 case 't':
838 case 'T':
839 case '1':
840 retval = 1;
841 break;
842
843 default:
844 retval = def;
845 }
846
847 dprintf(("Kernel32:Profile:(\"%s\", \"%s\", %s), "
848 "[%c], ret %s.\n", section, key_name,
849 def ? "TRUE" : "FALSE", key_value[0],
850 retval ? "TRUE" : "FALSE"));
851
852 return retval;
853}
854
855
856#if 0
857/***********************************************************************
858 * PROFILE_LoadWineIni
859 *
860 * Load the wine.ini file.
861 */
862int PROFILE_LoadWineIni(void)
863{
864 char buffer[MAX_PATHNAME_LEN];
865 const char *p;
866 FILE *f;
867
868 InitializeCriticalSection( &PROFILE_CritSect );
869 MakeCriticalSectionGlobal( &PROFILE_CritSect );
870
871 if ( (Options.configFileName!=NULL) && (f = fopen(Options.configFileName, "r")) )
872 {
873 /* Open -config specified file */
874 PROFILE_WineProfile = PROFILE_Load ( f);
875 fclose ( f );
876 strncpy(PROFILE_WineIniUsed,Options.configFileName,MAX_PATHNAME_LEN-1);
877 return 1;
878 }
879
880 if ( (p = getenv( "WINE_INI" )) && (f = fopen( p, "r" )) )
881 {
882 PROFILE_WineProfile = PROFILE_Load( f );
883 fclose( f );
884 strncpy(PROFILE_WineIniUsed,p,MAX_PATHNAME_LEN-1);
885 return 1;
886 }
887 if ((p = getenv( "HOME" )) != NULL)
888 {
889 lstrcpynA(buffer, p, MAX_PATHNAME_LEN - sizeof(PROFILE_WineIniName));
890 strcat( buffer, PROFILE_WineIniName );
891 if ((f = fopen( buffer, "r" )) != NULL)
892 {
893 PROFILE_WineProfile = PROFILE_Load( f );
894 fclose( f );
895 strncpy(PROFILE_WineIniUsed,buffer,MAX_PATHNAME_LEN-1);
896 return 1;
897 }
898 }
899 else dprintf(("Kernel32:Profile:could not get $HOME value for config file.\n" ));
900
901 /* Try global file */
902
903 if ((f = fopen( WINE_INI_GLOBAL, "r" )) != NULL)
904 {
905 PROFILE_WineProfile = PROFILE_Load( f );
906 fclose( f );
907 strncpy(PROFILE_WineIniUsed,WINE_INI_GLOBAL,MAX_PATHNAME_LEN-1);
908 return 1;
909 }
910 MESSAGE( "Can't open configuration file %s or $HOME%s\n",
911 WINE_INI_GLOBAL, PROFILE_WineIniName );
912 return 0;
913}
914
915
916/***********************************************************************
917 * PROFILE_UsageWineIni
918 *
919 * Explain the wine.ini file to those who don't read documentation.
920 * Keep below one screenful in length so that error messages above are
921 * noticed.
922 */
923void PROFILE_UsageWineIni(void)
924{
925 MESSAGE("Perhaps you have not properly edited or created "
926 "your Wine configuration file.\n");
927 MESSAGE("This is either %s or $HOME%s\n",WINE_INI_GLOBAL,PROFILE_WineIniName);
928 MESSAGE(" or it is determined by the -config option or from\n"
929 " the WINE_INI environment variable.\n");
930 if (*PROFILE_WineIniUsed)
931 MESSAGE("Wine has used %s as configuration file.\n", PROFILE_WineIniUsed);
932 /* RTFM, so to say */
933}
934#endif
935
936/***********************************************************************
937 * PROFILE_GetStringItem
938 *
939 * Convenience function that turns a string 'xxx, yyy, zzz' into
940 * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
941 */
942char* PROFILE_GetStringItem( char* start )
943{
944 char* lpchX, *lpch;
945
946 for (lpchX = start, lpch = NULL; *lpchX != '\0'; lpchX++ )
947 {
948 if( *lpchX == ',' )
949 {
950 if( lpch ) *lpch = '\0'; else *lpchX = '\0';
951 while( *(++lpchX) )
952 if( !PROFILE_isspace(*lpchX) ) return lpchX;
953 }
954 else if( PROFILE_isspace( *lpchX ) && !lpch ) lpch = lpchX;
955 else lpch = NULL;
956 }
957 if( lpch ) *lpch = '\0';
958 return NULL;
959}
960
961/********************* API functions **********************************/
962
963/***********************************************************************
964 * GetProfileInt32A (KERNEL32.264)
965 */
966UINT WINAPI GetProfileIntA( LPCSTR section, LPCSTR entry, INT def_val )
967{
968 return GetPrivateProfileIntA( section, entry, def_val, "win.ini" );
969}
970
971/***********************************************************************
972 * GetProfileInt32W (KERNEL32.264)
973 */
974UINT WINAPI GetProfileIntW( LPCWSTR section, LPCWSTR entry, INT def_val )
975{
976 if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, "win.ini" );
977 return GetPrivateProfileIntW( section, entry, def_val, wininiW );
978}
979
980/***********************************************************************
981 * GetProfileString32A (KERNEL32.268)
982 */
983INT WINAPI GetProfileStringA( LPCSTR section, LPCSTR entry, LPCSTR def_val,
984 LPSTR buffer, UINT len )
985{
986 return GetPrivateProfileStringA( section, entry, def_val,
987 buffer, len, "win.ini" );
988}
989
990/***********************************************************************
991 * GetProfileString32W (KERNEL32.269)
992 */
993INT WINAPI GetProfileStringW( LPCWSTR section, LPCWSTR entry,
994 LPCWSTR def_val, LPWSTR buffer, UINT len )
995{
996 if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, "win.ini" );
997 return GetPrivateProfileStringW( section, entry, def_val,
998 buffer, len, wininiW );
999}
1000
1001/***********************************************************************
1002 * WriteProfileString32A (KERNEL32.587)
1003 */
1004BOOL WINAPI WriteProfileStringA( LPCSTR section, LPCSTR entry,
1005 LPCSTR string )
1006{
1007 return WritePrivateProfileStringA( section, entry, string, "win.ini" );
1008}
1009
1010/***********************************************************************
1011 * WriteProfileString32W (KERNEL32.588)
1012 */
1013BOOL WINAPI WriteProfileStringW( LPCWSTR section, LPCWSTR entry,
1014 LPCWSTR string )
1015{
1016 if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, "win.ini" );
1017 return WritePrivateProfileStringW( section, entry, string, wininiW );
1018}
1019
1020/***********************************************************************
1021 * GetPrivateProfileInt32A (KERNEL32.251)
1022 */
1023UINT WINAPI GetPrivateProfileIntA( LPCSTR section, LPCSTR entry,
1024 INT def_val, LPCSTR filename )
1025{
1026 char buffer[20];
1027 char *p;
1028 long result;
1029
1030 GetPrivateProfileStringA( section, entry, "",
1031 buffer, sizeof(buffer), filename );
1032 if (!buffer[0]) return (UINT)def_val;
1033 result = strtol( buffer, &p, 0 );
1034 if (p == buffer) return 0; /* No digits at all */
1035 return (UINT)result;
1036}
1037
1038/***********************************************************************
1039 * GetPrivateProfileInt32W (KERNEL32.252)
1040 */
1041UINT WINAPI GetPrivateProfileIntW( LPCWSTR section, LPCWSTR entry,
1042 INT def_val, LPCWSTR filename )
1043{
1044 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1045 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1046 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1047 UINT res = GetPrivateProfileIntA(sectionA, entryA, def_val, filenameA);
1048 HeapFree( GetProcessHeap(), 0, sectionA );
1049 HeapFree( GetProcessHeap(), 0, filenameA );
1050 HeapFree( GetProcessHeap(), 0, entryA );
1051 return res;
1052}
1053
1054/***********************************************************************
1055 * GetPrivateProfileString32A (KERNEL32.255)
1056 */
1057INT WINAPI GetPrivateProfileStringA( LPCSTR section, LPCSTR entry,
1058 LPCSTR def_val, LPSTR buffer,
1059 UINT len, LPCSTR filename )
1060{
1061 int ret;
1062
1063 if (!filename)
1064 filename = "win.ini";
1065
1066 EnterCriticalSection( &PROFILE_CritSect );
1067
1068 if (PROFILE_Open( filename )) {
1069 ret = PROFILE_GetString( section, entry, def_val, buffer, len );
1070 } else {
1071 lstrcpynA( buffer, def_val, len );
1072 ret = strlen( buffer );
1073 }
1074
1075 LeaveCriticalSection( &PROFILE_CritSect );
1076
1077 return ret;
1078}
1079
1080/***********************************************************************
1081 * GetPrivateProfileString32W (KERNEL32.256)
1082 */
1083INT WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1084 LPCWSTR def_val, LPWSTR buffer,
1085 UINT len, LPCWSTR filename )
1086{
1087 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1088 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1089 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1090 LPSTR def_valA = HEAP_strdupWtoA( GetProcessHeap(), 0, def_val );
1091 LPSTR bufferA = (LPSTR)HeapAlloc( GetProcessHeap(), 0, len );
1092 INT ret = GetPrivateProfileStringA( sectionA, entryA, def_valA,
1093 bufferA, len, filenameA );
1094 lstrcpynAtoW( buffer, bufferA, len );
1095 HeapFree( GetProcessHeap(), 0, sectionA );
1096 HeapFree( GetProcessHeap(), 0, entryA );
1097 HeapFree( GetProcessHeap(), 0, filenameA );
1098 HeapFree( GetProcessHeap(), 0, def_valA );
1099 HeapFree( GetProcessHeap(), 0, bufferA);
1100 return ret;
1101}
1102
1103/***********************************************************************
1104 * GetPrivateProfileSection32A (KERNEL32.255)
1105 */
1106INT WINAPI GetPrivateProfileSectionA( LPCSTR section, LPSTR buffer,
1107 DWORD len, LPCSTR filename )
1108{
1109 int ret = 0;
1110
1111 EnterCriticalSection( &PROFILE_CritSect );
1112
1113 if (PROFILE_Open( filename ))
1114 ret = PROFILE_GetSection(CurProfile->section, section, buffer, len,
1115 FALSE, TRUE);
1116
1117 LeaveCriticalSection( &PROFILE_CritSect );
1118
1119 return ret;
1120}
1121
1122/***********************************************************************
1123 * GetPrivateProfileSection32W (KERNEL32.256)
1124 */
1125
1126INT WINAPI GetPrivateProfileSectionW (LPCWSTR section, LPWSTR buffer,
1127 DWORD len, LPCWSTR filename )
1128
1129{
1130 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1131 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1132 LPSTR bufferA = (LPSTR)HeapAlloc( GetProcessHeap(), 0, len );
1133 INT ret = GetPrivateProfileSectionA( sectionA, bufferA, len,
1134 filenameA );
1135 MultiByteToWideChar(CP_ACP,0,bufferA,ret,buffer,len);
1136 HeapFree( GetProcessHeap(), 0, sectionA );
1137 HeapFree( GetProcessHeap(), 0, filenameA );
1138 HeapFree( GetProcessHeap(), 0, bufferA);
1139 return ret;
1140}
1141
1142/***********************************************************************
1143 * GetProfileSection32A (KERNEL32.268)
1144 */
1145INT WINAPI GetProfileSectionA( LPCSTR section, LPSTR buffer, DWORD len )
1146{
1147 return GetPrivateProfileSectionA( section, buffer, len, "win.ini" );
1148}
1149
1150/***********************************************************************
1151 * GetProfileSection32W (KERNEL32)
1152 */
1153INT WINAPI GetProfileSectionW( LPCWSTR section, LPWSTR buffer, DWORD len )
1154{
1155 if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, "win.ini" );
1156 return GetPrivateProfileSectionW( section, buffer, len, wininiW );
1157}
1158
1159/***********************************************************************
1160 * WritePrivateProfileString32A (KERNEL32.582)
1161 */
1162BOOL WINAPI WritePrivateProfileStringA( LPCSTR section, LPCSTR entry,
1163 LPCSTR string, LPCSTR filename )
1164{
1165 BOOL ret = FALSE;
1166
1167 EnterCriticalSection( &PROFILE_CritSect );
1168
1169 if (PROFILE_Open( filename ))
1170 {
1171 if (!section && !entry && !string)
1172 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1173 else
1174 ret = PROFILE_SetString( section, entry, string );
1175 }
1176
1177 LeaveCriticalSection( &PROFILE_CritSect );
1178 return ret;
1179}
1180
1181/***********************************************************************
1182 * WritePrivateProfileString32W (KERNEL32.583)
1183 */
1184BOOL WINAPI WritePrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1185 LPCWSTR string, LPCWSTR filename )
1186{
1187 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1188 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1189 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1190 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1191 BOOL res = WritePrivateProfileStringA( sectionA, entryA,
1192 stringA, filenameA );
1193 HeapFree( GetProcessHeap(), 0, sectionA );
1194 HeapFree( GetProcessHeap(), 0, entryA );
1195 HeapFree( GetProcessHeap(), 0, stringA );
1196 HeapFree( GetProcessHeap(), 0, filenameA );
1197 return res;
1198}
1199
1200/***********************************************************************
1201 * WritePrivateProfileSection32A (KERNEL32)
1202 */
1203BOOL WINAPI WritePrivateProfileSectionA( LPCSTR section,
1204 LPCSTR string, LPCSTR filename )
1205{
1206 char *p =(char*)string;
1207
1208 dprintf(("Kernel32:Profile:fixme WritePrivateProfileSection32A empty stub\n"));
1209 return FALSE;
1210}
1211
1212/***********************************************************************
1213 * WritePrivateProfileSection32W (KERNEL32)
1214 */
1215BOOL WINAPI WritePrivateProfileSectionW( LPCWSTR section,
1216 LPCWSTR string, LPCWSTR filename)
1217
1218{
1219 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1220 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1221 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1222 BOOL res = WritePrivateProfileSectionA( sectionA, stringA, filenameA );
1223 HeapFree( GetProcessHeap(), 0, sectionA );
1224 HeapFree( GetProcessHeap(), 0, stringA );
1225 HeapFree( GetProcessHeap(), 0, filenameA );
1226 return res;
1227}
1228
1229/***********************************************************************
1230 * WriteProfileSection32A (KERNEL32.747)
1231 */
1232BOOL WINAPI WriteProfileSectionA( LPCSTR section, LPCSTR keys_n_values)
1233
1234{
1235 return WritePrivateProfileSectionA( section, keys_n_values, "win.ini");
1236}
1237
1238/***********************************************************************
1239 * WriteProfileSection32W (KERNEL32.748)
1240 */
1241BOOL WINAPI WriteProfileSectionW( LPCWSTR section, LPCWSTR keys_n_values)
1242{
1243 if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, "win.ini");
1244
1245 return (WritePrivateProfileSectionW (section,keys_n_values, wininiW));
1246}
1247
1248/***********************************************************************
1249 * GetPrivateProfileSectionNames16 (KERNEL.143)
1250 */
1251WORD WINAPI GetPrivateProfileSectionNames16( LPSTR buffer, WORD size,
1252 LPCSTR filename )
1253{
1254 WORD ret = 0;
1255
1256 EnterCriticalSection( &PROFILE_CritSect );
1257
1258 if (PROFILE_Open( filename ))
1259 ret = PROFILE_GetSectionNames(buffer, size);
1260
1261 LeaveCriticalSection( &PROFILE_CritSect );
1262
1263 return ret;
1264}
1265
1266/***********************************************************************
1267 * GetPrivateProfileSectionNames32A (KERNEL32.365)
1268 */
1269DWORD WINAPI GetPrivateProfileSectionNamesA( LPSTR buffer, DWORD size,
1270 LPCSTR filename)
1271
1272{
1273 return (GetPrivateProfileSectionNames16 (buffer,size,filename));
1274}
1275
1276/***********************************************************************
1277 * GetPrivateProfileSectionNames32W (KERNEL32.366)
1278 */
1279DWORD WINAPI GetPrivateProfileSectionNamesW( LPWSTR buffer, DWORD size,
1280 LPCWSTR filename)
1281
1282{
1283 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1284 LPSTR bufferA = (LPSTR)HeapAlloc( GetProcessHeap(), 0, size);
1285
1286 INT ret = GetPrivateProfileSectionNames16 (bufferA, size, filenameA);
1287 lstrcpynAtoW( buffer, bufferA, size);
1288 HeapFree( GetProcessHeap(), 0, bufferA);
1289 HeapFree( GetProcessHeap(), 0, filenameA );
1290
1291 return ret;
1292}
1293
1294/***********************************************************************
1295 * GetPrivateProfileStruct32A (KERNEL32.370)
1296 */
1297BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key,
1298 LPVOID buf, UINT len, LPCSTR filename)
1299{
1300 BOOL ret = FALSE;
1301
1302 EnterCriticalSection( &PROFILE_CritSect );
1303
1304 if (PROFILE_Open( filename )) {
1305 PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE);
1306 if (k) {
1307 lstrcpynA( (LPSTR)buf, k->value, strlen(k->value));
1308 ret = TRUE;
1309 }
1310 }
1311 LeaveCriticalSection( &PROFILE_CritSect );
1312
1313 return FALSE;
1314}
1315
1316/***********************************************************************
1317 * GetPrivateProfileStruct32W (KERNEL32.543)
1318 */
1319BOOL WINAPI GetPrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1320 LPVOID buffer, UINT len, LPCWSTR filename)
1321{
1322 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1323 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1324 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1325 LPSTR bufferA = (LPSTR)HeapAlloc( GetProcessHeap(), 0, len );
1326
1327 INT ret = GetPrivateProfileStructA( sectionA, keyA, bufferA,
1328 len, filenameA );
1329 lstrcpynAtoW( (LPWSTR)buffer, bufferA, len );
1330 HeapFree( GetProcessHeap(), 0, bufferA);
1331 HeapFree( GetProcessHeap(), 0, sectionA );
1332 HeapFree( GetProcessHeap(), 0, keyA );
1333 HeapFree( GetProcessHeap(), 0, filenameA );
1334
1335 return ret;
1336}
1337
1338
1339/***********************************************************************
1340 * WritePrivateProfileStruct32A (KERNEL32.744)
1341 */
1342BOOL WINAPI WritePrivateProfileStructA (LPCSTR section, LPCSTR key,
1343 LPVOID buf, UINT bufsize, LPCSTR filename)
1344{
1345 BOOL ret = FALSE;
1346
1347 if (!section && !key && !buf) /* flush the cache */
1348 return WritePrivateProfileStringA( NULL, NULL, NULL, filename );
1349
1350 EnterCriticalSection( &PROFILE_CritSect );
1351
1352 if (PROFILE_Open( filename ))
1353 ret = PROFILE_SetString( section, key, (LPCSTR)buf );
1354
1355 LeaveCriticalSection( &PROFILE_CritSect );
1356
1357 return ret;
1358}
1359
1360/***********************************************************************
1361 * WritePrivateProfileStruct32W (KERNEL32.544)
1362 */
1363BOOL WINAPI WritePrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1364 LPVOID buf, UINT bufsize, LPCWSTR filename)
1365{
1366 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1367 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1368 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1369 INT ret = WritePrivateProfileStructA( sectionA, keyA, buf, bufsize,
1370 filenameA );
1371 HeapFree( GetProcessHeap(), 0, sectionA );
1372 HeapFree( GetProcessHeap(), 0, keyA );
1373 HeapFree( GetProcessHeap(), 0, filenameA );
1374
1375 return ret;
1376}
Note: See TracBrowser for help on using the repository browser.