Implement EnumPrinterDataEx{A|W}.
[wine.git] / files / profile.c
blobaec6153eac9462cf1e42b52fb3c3152790ecd0fd
1 /*
2 * Profile functions
4 * Copyright 1993 Miguel de Icaza
5 * Copyright 1996 Alexandre Julliard
6 */
8 #include <ctype.h>
9 #include <fcntl.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <stdio.h>
13 #include <sys/stat.h>
14 #include <sys/types.h>
15 #include <pwd.h>
16 #include <unistd.h>
18 #include "windef.h"
19 #include "winbase.h"
20 #include "winnls.h"
21 #include "winerror.h"
22 #include "wine/winbase16.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 static const WCHAR wininiW[] = { 'w','i','n','.','i','n','i',0 };
81 static CRITICAL_SECTION PROFILE_CritSect = CRITICAL_SECTION_INIT;
83 static const char hex[16] = "0123456789ABCDEF";
85 /***********************************************************************
86 * PROFILE_CopyEntry
88 * Copy the content of an entry into a buffer, removing quotes, and possibly
89 * translating environment variables.
91 static void PROFILE_CopyEntry( char *buffer, const char *value, int len,
92 int handle_env )
94 char quote = '\0';
95 const char *p;
97 if(!buffer) return;
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;
273 /* convert the .winerc file to the new format */
274 static int convert_config( FILE *in, const char *output_name )
276 char buffer[PROFILE_MAX_LINE_LEN];
277 char *p, *p2;
278 FILE *out;
280 /* create the output file, only if it doesn't exist already */
281 int fd = open( output_name, O_WRONLY|O_CREAT|O_EXCL, 0666 );
282 if (fd == -1) return 0;
284 out = fdopen( fd, "w" );
285 fprintf( out, "WINE REGISTRY Version 2\n" );
286 fprintf( out, ";; All keys relative to \\\\Machine\\\\Software\\\\Wine\\\\Wine\\\\Config\n\n" );
287 while (fgets( buffer, PROFILE_MAX_LINE_LEN, in ))
289 if (buffer[strlen(buffer)-1] == '\n') buffer[strlen(buffer)-1] = 0;
290 p = buffer;
291 while (*p && PROFILE_isspace(*p)) p++;
292 if (*p == '[') /* section start */
294 if ((p2 = strrchr( p, ']' )))
296 *p2 = '\0';
297 p++;
298 fprintf( out, "[%s]\n", p );
300 continue;
303 if (*p == ';' || *p == '#')
305 fprintf( out, "%s\n", p );
306 continue;
309 p2=p+strlen(p) - 1;
310 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
312 if ((p2 = strchr( p, '=' )) != NULL)
314 char *p3 = p2 - 1;
315 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
316 *p2++ = '\0';
317 while (*p2 && PROFILE_isspace(*p2)) p2++;
320 if (!*p)
322 fprintf( out, "\n" );
323 continue;
325 fputc( '"', out );
326 while (*p)
328 if (*p == '\\') fputc( '\\', out );
329 fputc( *p, out );
330 p++;
332 fprintf( out, "\" = \"" );
333 if (p2)
335 while (*p2)
337 if (*p2 == '\\') fputc( '\\', out );
338 fputc( *p2, out );
339 p2++;
342 fprintf( out, "\"\n" );
344 fclose( out );
345 return 1;
349 /***********************************************************************
350 * PROFILE_RegistryLoad
352 * Load a profile tree from a file into a registry key.
354 static DWORD PROFILE_RegistryLoad( HKEY root, FILE *file )
356 HKEY hkey = 0;
357 DWORD err = 0;
358 char buffer[PROFILE_MAX_LINE_LEN];
359 char *p, *p2;
360 int line = 0;
362 while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
364 line++;
365 p = buffer;
366 while (*p && PROFILE_isspace(*p)) p++;
367 if (*p == '[') /* section start */
369 if (!(p2 = strrchr( p, ']' )))
371 WARN("Invalid section header at line %d: '%s'\n",
372 line, p );
374 else
376 *p2 = '\0';
377 p++;
378 if (hkey) RegCloseKey( hkey );
379 if ((err = RegCreateKeyExA( root, p, 0, NULL, REG_OPTION_VOLATILE,
380 KEY_ALL_ACCESS, NULL, &hkey, NULL ))) return err;
381 TRACE("New section: '%s'\n",p);
382 continue;
386 p2=p+strlen(p) - 1;
387 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
389 if ((p2 = strchr( p, '=' )) != NULL)
391 char *p3 = p2 - 1;
392 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
393 *p2++ = '\0';
394 while (*p2 && PROFILE_isspace(*p2)) p2++;
397 if (*p && hkey && !IS_ENTRY_COMMENT(p))
399 if (!p2) p2 = "";
400 if ((err = RegSetValueExA( hkey, p, 0, REG_SZ, p2, strlen(p2)+1 )))
402 RegCloseKey( hkey );
403 return err;
405 TRACE("New key: name='%s', value='%s'\n",p,p2);
408 if (hkey) RegCloseKey( hkey );
409 return 0;
413 /***********************************************************************
414 * PROFILE_DeleteSection
416 * Delete a section from a profile tree.
418 static BOOL PROFILE_DeleteSection( PROFILESECTION **section, LPCSTR name )
420 while (*section)
422 if ((*section)->name && !strcasecmp( (*section)->name, name ))
424 PROFILESECTION *to_del = *section;
425 *section = to_del->next;
426 to_del->next = NULL;
427 PROFILE_Free( to_del );
428 return TRUE;
430 section = &(*section)->next;
432 return FALSE;
436 /***********************************************************************
437 * PROFILE_DeleteKey
439 * Delete a key from a profile tree.
441 static BOOL PROFILE_DeleteKey( PROFILESECTION **section,
442 LPCSTR section_name, LPCSTR key_name )
444 while (*section)
446 if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
448 PROFILEKEY **key = &(*section)->key;
449 while (*key)
451 if (!strcasecmp( (*key)->name, key_name ))
453 PROFILEKEY *to_del = *key;
454 *key = to_del->next;
455 if (to_del->name) HeapFree( GetProcessHeap(), 0, to_del->name );
456 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
457 HeapFree( GetProcessHeap(), 0, to_del );
458 return TRUE;
460 key = &(*key)->next;
463 section = &(*section)->next;
465 return FALSE;
469 /***********************************************************************
470 * PROFILE_DeleteAllKeys
472 * Delete all keys from a profile tree.
474 void PROFILE_DeleteAllKeys( LPCSTR section_name)
476 PROFILESECTION **section= &CurProfile->section;
477 while (*section)
479 if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
481 PROFILEKEY **key = &(*section)->key;
482 while (*key)
484 PROFILEKEY *to_del = *key;
485 *key = to_del->next;
486 if (to_del->name) HeapFree( GetProcessHeap(), 0, to_del->name );
487 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
488 HeapFree( GetProcessHeap(), 0, to_del );
489 CurProfile->changed =TRUE;
492 section = &(*section)->next;
497 /***********************************************************************
498 * PROFILE_Find
500 * Find a key in a profile tree, optionally creating it.
502 static PROFILEKEY *PROFILE_Find( PROFILESECTION **section,
503 const char *section_name,
504 const char *key_name, int create )
506 const char *p;
507 int seclen, keylen;
509 while (PROFILE_isspace(*section_name)) section_name++;
510 p = section_name + strlen(section_name) - 1;
511 while ((p > section_name) && PROFILE_isspace(*p)) p--;
512 seclen = p - section_name + 1;
514 while (PROFILE_isspace(*key_name)) key_name++;
515 p = key_name + strlen(key_name) - 1;
516 while ((p > key_name) && PROFILE_isspace(*p)) p--;
517 keylen = p - key_name + 1;
519 while (*section)
521 if ( ((*section)->name)
522 && (!(strncasecmp( (*section)->name, section_name, seclen )))
523 && (((*section)->name)[seclen] == '\0') )
525 PROFILEKEY **key = &(*section)->key;
526 while (*key)
528 if ( (!(strncasecmp( (*key)->name, key_name, keylen )))
529 && (((*key)->name)[keylen] == '\0') )
530 return *key;
531 key = &(*key)->next;
533 if (!create) return NULL;
534 *key = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) );
535 if(*key == NULL) return NULL;
536 (*key)->name = HEAP_strdupA( GetProcessHeap(), 0, key_name );
537 (*key)->value = NULL;
538 (*key)->next = NULL;
539 return *key;
541 section = &(*section)->next;
543 if (!create) return NULL;
544 *section = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILESECTION) );
545 if(*section == NULL) return NULL;
546 (*section)->name = HEAP_strdupA( GetProcessHeap(), 0, section_name );
547 (*section)->next = NULL;
548 (*section)->key = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) );
549 if((*section)->key == NULL)
551 HeapFree(GetProcessHeap(), 0, *section);
552 return NULL;
554 (*section)->key->name = HEAP_strdupA( GetProcessHeap(), 0, key_name );
555 (*section)->key->value = NULL;
556 (*section)->key->next = NULL;
557 return (*section)->key;
561 /***********************************************************************
562 * PROFILE_FlushFile
564 * Flush the current profile to disk if changed.
566 static BOOL PROFILE_FlushFile(void)
568 char *p, buffer[MAX_PATHNAME_LEN];
569 const char *unix_name;
570 FILE *file = NULL;
571 struct stat buf;
573 if(!CurProfile)
575 WARN("No current profile!\n");
576 return FALSE;
579 if (!CurProfile->changed || !CurProfile->dos_name) return TRUE;
580 if (!(unix_name = CurProfile->unix_name) || !(file = fopen(unix_name, "w")))
582 /* Try to create it in $HOME/.wine */
583 /* FIXME: this will need a more general solution */
584 strcpy( buffer, get_config_dir() );
585 p = buffer + strlen(buffer);
586 *p++ = '/';
587 strcpy( p, strrchr( CurProfile->dos_name, '\\' ) + 1 );
588 _strlwr( p );
589 file = fopen( buffer, "w" );
590 unix_name = buffer;
593 if (!file)
595 WARN("could not save profile file %s\n", CurProfile->dos_name);
596 return FALSE;
599 TRACE("Saving '%s' into '%s'\n", CurProfile->dos_name, unix_name );
600 PROFILE_Save( file, CurProfile->section );
601 fclose( file );
602 CurProfile->changed = FALSE;
603 if(!stat(unix_name,&buf))
604 CurProfile->mtime=buf.st_mtime;
605 return TRUE;
609 /***********************************************************************
610 * PROFILE_ReleaseFile
612 * Flush the current profile to disk and remove it from the cache.
614 static void PROFILE_ReleaseFile(void)
616 PROFILE_FlushFile();
617 PROFILE_Free( CurProfile->section );
618 if (CurProfile->dos_name) HeapFree( GetProcessHeap(), 0, CurProfile->dos_name );
619 if (CurProfile->unix_name) HeapFree( GetProcessHeap(), 0, CurProfile->unix_name );
620 if (CurProfile->filename) HeapFree( GetProcessHeap(), 0, CurProfile->filename );
621 CurProfile->changed = FALSE;
622 CurProfile->section = NULL;
623 CurProfile->dos_name = NULL;
624 CurProfile->unix_name = NULL;
625 CurProfile->filename = NULL;
626 CurProfile->mtime = 0;
630 /***********************************************************************
631 * PROFILE_Open
633 * Open a profile file, checking the cached file first.
635 static BOOL PROFILE_Open( LPCSTR filename )
637 DOS_FULL_NAME full_name;
638 char buffer[MAX_PATHNAME_LEN];
639 char *newdos_name, *p;
640 FILE *file = NULL;
641 int i,j;
642 struct stat buf;
643 PROFILE *tempProfile;
645 /* First time around */
647 if(!CurProfile)
648 for(i=0;i<N_CACHED_PROFILES;i++)
650 MRUProfile[i]=HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILE) );
651 if(MRUProfile[i] == NULL) break;
652 MRUProfile[i]->changed=FALSE;
653 MRUProfile[i]->section=NULL;
654 MRUProfile[i]->dos_name=NULL;
655 MRUProfile[i]->unix_name=NULL;
656 MRUProfile[i]->filename=NULL;
657 MRUProfile[i]->mtime=0;
660 /* Check for a match */
662 if (strchr( filename, '/' ) || strchr( filename, '\\' ) ||
663 strchr( filename, ':' ))
665 if (!DOSFS_GetFullName( filename, FALSE, &full_name )) return FALSE;
667 else
669 GetWindowsDirectoryA( buffer, sizeof(buffer) );
670 strcat( buffer, "\\" );
671 strcat( buffer, filename );
672 if (!DOSFS_GetFullName( buffer, FALSE, &full_name )) return FALSE;
675 for(i=0;i<N_CACHED_PROFILES;i++)
677 if ((MRUProfile[i]->filename && !strcmp( filename, MRUProfile[i]->filename )) ||
678 (MRUProfile[i]->dos_name && !strcmp( full_name.short_name, MRUProfile[i]->dos_name )))
680 if(i)
682 PROFILE_FlushFile();
683 tempProfile=MRUProfile[i];
684 for(j=i;j>0;j--)
685 MRUProfile[j]=MRUProfile[j-1];
686 CurProfile=tempProfile;
688 if(!stat(CurProfile->unix_name,&buf) && CurProfile->mtime==buf.st_mtime)
689 TRACE("(%s): already opened (mru=%d)\n",
690 filename, i );
691 else
692 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
693 filename, i );
694 return TRUE;
698 /* Flush the old current profile */
699 PROFILE_FlushFile();
701 /* Make the oldest profile the current one only in order to get rid of it */
702 if(i==N_CACHED_PROFILES)
704 tempProfile=MRUProfile[N_CACHED_PROFILES-1];
705 for(i=N_CACHED_PROFILES-1;i>0;i--)
706 MRUProfile[i]=MRUProfile[i-1];
707 CurProfile=tempProfile;
709 if(CurProfile->filename) PROFILE_ReleaseFile();
711 /* OK, now that CurProfile is definitely free we assign it our new file */
712 newdos_name = HEAP_strdupA( GetProcessHeap(), 0, full_name.short_name );
713 CurProfile->dos_name = newdos_name;
714 CurProfile->filename = HEAP_strdupA( GetProcessHeap(), 0, filename );
716 /* Try to open the profile file, first in $HOME/.wine */
718 /* FIXME: this will need a more general solution */
719 strcpy( buffer, get_config_dir() );
720 p = buffer + strlen(buffer);
721 *p++ = '/';
722 strcpy( p, strrchr( newdos_name, '\\' ) + 1 );
723 _strlwr( p );
724 if ((file = fopen( buffer, "r" )))
726 TRACE("(%s): found it in %s\n",
727 filename, buffer );
728 CurProfile->unix_name = HEAP_strdupA( GetProcessHeap(), 0, buffer );
731 if (!file)
733 CurProfile->unix_name = HEAP_strdupA( GetProcessHeap(), 0,
734 full_name.long_name );
735 if ((file = fopen( full_name.long_name, "r" )))
736 TRACE("(%s): found it in %s\n",
737 filename, full_name.long_name );
740 if (file)
742 CurProfile->section = PROFILE_Load( file );
743 fclose( file );
744 if(!stat(CurProfile->unix_name,&buf))
745 CurProfile->mtime=buf.st_mtime;
747 else
749 /* Does not exist yet, we will create it in PROFILE_FlushFile */
750 WARN("profile file %s not found\n", newdos_name );
752 return TRUE;
756 /***********************************************************************
757 * PROFILE_GetSection
759 * Returns all keys of a section.
760 * If return_values is TRUE, also include the corresponding values.
762 static INT PROFILE_GetSection( PROFILESECTION *section, LPCSTR section_name,
763 LPSTR buffer, UINT len, BOOL handle_env,
764 BOOL return_values )
766 PROFILEKEY *key;
768 if(!buffer) return 0;
770 while (section)
772 if (section->name && !strcasecmp( section->name, section_name ))
774 UINT oldlen = len;
775 for (key = section->key; key; key = key->next)
777 if (len <= 2) break;
778 if (!*key->name) continue; /* Skip empty lines */
779 if (IS_ENTRY_COMMENT(key->name)) continue; /* Skip comments */
780 PROFILE_CopyEntry( buffer, key->name, len - 1, handle_env );
781 len -= strlen(buffer) + 1;
782 buffer += strlen(buffer) + 1;
783 if (return_values && key->value) {
784 buffer[-1] = '=';
785 PROFILE_CopyEntry ( buffer,
786 key->value, len - 1, handle_env );
787 len -= strlen(buffer) + 1;
788 buffer += strlen(buffer) + 1;
791 *buffer = '\0';
792 if (len <= 1)
793 /*If either lpszSection or lpszKey is NULL and the supplied
794 destination buffer is too small to hold all the strings,
795 the last string is truncated and followed by two null characters.
796 In this case, the return value is equal to cchReturnBuffer
797 minus two. */
799 buffer[-1] = '\0';
800 return oldlen - 2;
802 return oldlen - len;
804 section = section->next;
806 buffer[0] = buffer[1] = '\0';
807 return 0;
811 static INT PROFILE_GetSectionNames( LPSTR buffer, UINT len )
813 LPSTR buf = buffer;
814 WORD l, cursize = 0;
815 PROFILESECTION *section;
817 if(!buffer) return 0;
819 for (section = CurProfile->section; section; section = section->next)
820 if (section->name) {
821 l = strlen(section->name);
822 cursize += l+1;
823 if (cursize > len+1)
824 return len-2;
826 strcpy(buf, section->name);
827 buf += l+1;
830 *buf=0;
831 buf++;
832 return buf-buffer;
836 /***********************************************************************
837 * PROFILE_GetString
839 * Get a profile string.
841 * Tests with GetPrivateProfileString16, W95a,
842 * with filled buffer ("****...") and section "set1" and key_name "1" valid:
843 * section key_name def_val res buffer
844 * "set1" "1" "x" 43 [data]
845 * "set1" "1 " "x" 43 [data] (!)
846 * "set1" " 1 "' "x" 43 [data] (!)
847 * "set1" "" "x" 1 "x"
848 * "set1" "" "x " 1 "x" (!)
849 * "set1" "" " x " 3 " x" (!)
850 * "set1" NULL "x" 6 "1\02\03\0\0"
851 * "set1" "" "x" 1 "x"
852 * NULL "1" "x" 0 "" (!)
853 * "" "1" "x" 1 "x"
854 * NULL NULL "" 0 ""
858 static INT PROFILE_GetString( LPCSTR section, LPCSTR key_name,
859 LPCSTR def_val, LPSTR buffer, UINT len )
861 PROFILEKEY *key = NULL;
863 if(!buffer) return 0;
865 if (!def_val) def_val = "";
866 if (key_name && key_name[0])
868 key = PROFILE_Find( &CurProfile->section, section, key_name, FALSE );
869 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def_val,
870 len, FALSE );
871 TRACE("('%s','%s','%s'): returning '%s'\n",
872 section, key_name, def_val, buffer );
873 return strlen( buffer );
875 if (key_name && !(key_name[0]))
876 /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227 */
877 return 0;
878 if (section && section[0])
879 return PROFILE_GetSection(CurProfile->section, section, buffer, len,
880 FALSE, FALSE);
881 buffer[0] = '\0';
882 return 0;
886 /***********************************************************************
887 * PROFILE_SetString
889 * Set a profile string.
891 static BOOL PROFILE_SetString( LPCSTR section_name, LPCSTR key_name,
892 LPCSTR value )
894 if (!key_name) /* Delete a whole section */
896 TRACE("('%s')\n", section_name);
897 CurProfile->changed |= PROFILE_DeleteSection( &CurProfile->section,
898 section_name );
899 return TRUE; /* Even if PROFILE_DeleteSection() has failed,
900 this is not an error on application's level.*/
902 else if (!value) /* Delete a key */
904 TRACE("('%s','%s')\n",
905 section_name, key_name );
906 CurProfile->changed |= PROFILE_DeleteKey( &CurProfile->section,
907 section_name, key_name );
908 return TRUE; /* same error handling as above */
910 else /* Set the key value */
912 PROFILEKEY *key = PROFILE_Find( &CurProfile->section, section_name,
913 key_name, TRUE );
914 TRACE("('%s','%s','%s'): \n",
915 section_name, key_name, value );
916 if (!key) return FALSE;
917 if (key->value)
919 /* strip the leading spaces. We can safely strip \n\r and
920 * friends too, they should not happen here anyway. */
921 while (PROFILE_isspace(*value)) value++;
923 if (!strcmp( key->value, value ))
925 TRACE(" no change needed\n" );
926 return TRUE; /* No change needed */
928 TRACE(" replacing '%s'\n", key->value );
929 HeapFree( GetProcessHeap(), 0, key->value );
931 else TRACE(" creating key\n" );
932 key->value = HEAP_strdupA( GetProcessHeap(), 0, value );
933 CurProfile->changed = TRUE;
935 return TRUE;
939 /***********************************************************************
940 * PROFILE_GetWineIniString
942 * Get a config string from the wine.ini file.
944 int PROFILE_GetWineIniString( const char *section, const char *key_name,
945 const char *def, char *buffer, int len )
947 char tmp[PROFILE_MAX_LINE_LEN];
948 HKEY hkey;
949 DWORD err;
951 if (!(err = RegOpenKeyA( wine_profile_key, section, &hkey )))
953 DWORD type;
954 DWORD count = sizeof(tmp);
955 err = RegQueryValueExA( hkey, key_name, 0, &type, tmp, &count );
956 RegCloseKey( hkey );
958 PROFILE_CopyEntry( buffer, err ? def : tmp, len, TRUE );
959 TRACE( "('%s','%s','%s'): returning '%s'\n", section, key_name, def, buffer );
960 return strlen(buffer);
964 /***********************************************************************
965 * PROFILE_EnumWineIniString
967 * Get a config string from the wine.ini file.
969 BOOL PROFILE_EnumWineIniString( const char *section, int index,
970 char *name, int name_len, char *buffer, int len )
972 char tmp[PROFILE_MAX_LINE_LEN];
973 HKEY hkey;
974 DWORD err, type;
975 DWORD count = sizeof(tmp);
977 if (RegOpenKeyA( wine_profile_key, section, &hkey )) return FALSE;
978 err = RegEnumValueA( hkey, index, name, (DWORD*)&name_len, NULL, &type, tmp, &count );
979 RegCloseKey( hkey );
980 if (!err)
982 PROFILE_CopyEntry( buffer, tmp, len, TRUE );
983 TRACE( "('%s',%d): returning '%s'='%s'\n", section, index, name, buffer );
985 return !err;
989 /***********************************************************************
990 * PROFILE_GetWineIniInt
992 * Get a config integer from the wine.ini file.
994 int PROFILE_GetWineIniInt( const char *section, const char *key_name, int def )
996 char buffer[20];
997 char *p;
998 long result;
1000 PROFILE_GetWineIniString( section, key_name, "", buffer, sizeof(buffer) );
1001 if (!buffer[0]) return def;
1002 result = strtol( buffer, &p, 0 );
1003 return (p == buffer) ? 0 /* No digits at all */ : (int)result;
1007 /******************************************************************************
1009 * int PROFILE_GetWineIniBool(
1010 * char const *section,
1011 * char const *key_name,
1012 * int def )
1014 * Reads a boolean value from the wine.ini file. This function attempts to
1015 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
1016 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
1017 * true. Anything else results in the return of the default value.
1019 * This function uses 1 to indicate true, and 0 for false. You can check
1020 * for existence by setting def to something other than 0 or 1 and
1021 * examining the return value.
1023 int PROFILE_GetWineIniBool(
1024 char const *section,
1025 char const *key_name,
1026 int def )
1028 char key_value[2];
1029 int retval;
1031 PROFILE_GetWineIniString(section, key_name, "~", key_value, 2);
1033 switch(key_value[0]) {
1034 case 'n':
1035 case 'N':
1036 case 'f':
1037 case 'F':
1038 case '0':
1039 retval = 0;
1040 break;
1042 case 'y':
1043 case 'Y':
1044 case 't':
1045 case 'T':
1046 case '1':
1047 retval = 1;
1048 break;
1050 default:
1051 retval = def;
1054 TRACE("(\"%s\", \"%s\", %s), "
1055 "[%c], ret %s.\n", section, key_name,
1056 def ? "TRUE" : "FALSE", key_value[0],
1057 retval ? "TRUE" : "FALSE");
1059 return retval;
1063 /***********************************************************************
1064 * PROFILE_LoadWineIni
1066 * Load the old .winerc file.
1068 int PROFILE_LoadWineIni(void)
1070 char buffer[MAX_PATHNAME_LEN];
1071 const char *p;
1072 FILE *f;
1073 HKEY hKeySW;
1074 DWORD disp;
1076 /* make sure HKLM\\Software\\Wine\\Wine exists as non-volatile key */
1077 if (RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine", &hKeySW ))
1079 ERR("Cannot create config registry key\n" );
1080 return 0;
1082 RegCloseKey( hKeySW );
1083 if (RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config", 0, NULL,
1084 REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &wine_profile_key, &disp ))
1086 ERR("Cannot create config registry key\n" );
1087 return 0;
1090 if (!CLIENT_IsBootThread()) return 1; /* already loaded */
1092 if ((p = getenv( "HOME" )) != NULL)
1094 lstrcpynA(buffer, p, MAX_PATHNAME_LEN - sizeof(PROFILE_WineIniName));
1095 strcat( buffer, PROFILE_WineIniName );
1096 if ((f = fopen( buffer, "r" )) != NULL)
1098 lstrcpynA(PROFILE_WineIniUsed,buffer,MAX_PATHNAME_LEN);
1099 goto found;
1102 else WARN("could not get $HOME value for config file.\n" );
1104 if (disp == REG_OPENED_EXISTING_KEY) return 1; /* loaded by the server */
1106 MESSAGE( "Can't open configuration file %s/config\n",get_config_dir() );
1107 return 0;
1109 found:
1111 if (disp == REG_OPENED_EXISTING_KEY)
1113 MESSAGE( "Warning: configuration loaded by the server from '%s/config',\n"
1114 " file '%s' was ignored.\n", get_config_dir(), PROFILE_WineIniUsed );
1115 fclose( f );
1116 return 1;
1119 /* convert to the new format */
1120 sprintf( buffer, "%s/config", get_config_dir() );
1121 if (convert_config( f, buffer ))
1123 MESSAGE( "The '%s' configuration file has been converted\n"
1124 "to the new format and saved as '%s'.\n", PROFILE_WineIniUsed, buffer );
1125 MESSAGE( "You should verify that the contents of the new file are correct,\n"
1126 "and then remove the old one and restart Wine.\n" );
1127 ExitProcess(0);
1130 PROFILE_RegistryLoad( wine_profile_key, f );
1131 fclose( f );
1132 return 1;
1136 /***********************************************************************
1137 * PROFILE_UsageWineIni
1139 * Explain the wine.ini file to those who don't read documentation.
1140 * Keep below one screenful in length so that error messages above are
1141 * noticed.
1143 void PROFILE_UsageWineIni(void)
1145 MESSAGE("Perhaps you have not properly edited or created "
1146 "your Wine configuration file.\n");
1147 MESSAGE("This is '%s/config'\n", get_config_dir());
1148 /* RTFM, so to say */
1151 /***********************************************************************
1152 * PROFILE_GetStringItem
1154 * Convenience function that turns a string 'xxx, yyy, zzz' into
1155 * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
1157 char* PROFILE_GetStringItem( char* start )
1159 char* lpchX, *lpch;
1161 for (lpchX = start, lpch = NULL; *lpchX != '\0'; lpchX++ )
1163 if( *lpchX == ',' )
1165 if( lpch ) *lpch = '\0'; else *lpchX = '\0';
1166 while( *(++lpchX) )
1167 if( !PROFILE_isspace(*lpchX) ) return lpchX;
1169 else if( PROFILE_isspace( *lpchX ) && !lpch ) lpch = lpchX;
1170 else lpch = NULL;
1172 if( lpch ) *lpch = '\0';
1173 return NULL;
1176 /********************* API functions **********************************/
1178 /***********************************************************************
1179 * GetProfileInt16 (KERNEL.57)
1181 UINT16 WINAPI GetProfileInt16( LPCSTR section, LPCSTR entry, INT16 def_val )
1183 return GetPrivateProfileInt16( section, entry, def_val, "win.ini" );
1187 /***********************************************************************
1188 * GetProfileIntA (KERNEL32.264)
1190 UINT WINAPI GetProfileIntA( LPCSTR section, LPCSTR entry, INT def_val )
1192 return GetPrivateProfileIntA( section, entry, def_val, "win.ini" );
1195 /***********************************************************************
1196 * GetProfileIntW (KERNEL32.264)
1198 UINT WINAPI GetProfileIntW( LPCWSTR section, LPCWSTR entry, INT def_val )
1200 return GetPrivateProfileIntW( section, entry, def_val, wininiW );
1204 * undoc_feature means:
1205 * return section names string list if both section and entry are NULL.
1207 static int PROFILE_GetPrivateProfileString( LPCSTR section, LPCSTR entry,
1208 LPCSTR def_val, LPSTR buffer,
1209 UINT16 len, LPCSTR filename,
1210 BOOL undoc_feature )
1212 int ret;
1213 LPSTR pDefVal = NULL;
1215 if (!filename)
1216 filename = "win.ini";
1218 /* strip any trailing ' ' of def_val. */
1219 if (def_val)
1221 LPSTR p = (LPSTR)&def_val[strlen(def_val)]; /* even "" works ! */
1223 while (p > def_val)
1225 p--;
1226 if ((*p) != ' ')
1227 break;
1229 if (*p == ' ') /* ouch, contained trailing ' ' */
1231 int len = (int)p - (int)def_val;
1232 pDefVal = HeapAlloc(GetProcessHeap(), 0, len + 1);
1233 strncpy(pDefVal, def_val, len);
1234 pDefVal[len] = '\0';
1237 if (!pDefVal)
1238 pDefVal = (LPSTR)def_val;
1240 EnterCriticalSection( &PROFILE_CritSect );
1242 if (PROFILE_Open( filename )) {
1243 if ((undoc_feature) && (section == NULL) && (entry == NULL))
1244 /* undocumented; both section and entry are NULL */
1245 ret = PROFILE_GetSectionNames(buffer, len);
1246 else
1247 ret = PROFILE_GetString( section, entry, pDefVal, buffer, len );
1248 } else {
1249 lstrcpynA( buffer, pDefVal, len );
1250 ret = strlen( buffer );
1253 LeaveCriticalSection( &PROFILE_CritSect );
1255 if (pDefVal != def_val) /* allocated */
1256 HeapFree(GetProcessHeap(), 0, pDefVal);
1258 return ret;
1261 /***********************************************************************
1262 * GetPrivateProfileString16 (KERNEL.128)
1264 INT16 WINAPI GetPrivateProfileString16( LPCSTR section, LPCSTR entry,
1265 LPCSTR def_val, LPSTR buffer,
1266 UINT16 len, LPCSTR filename )
1268 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1269 buffer, len, filename, FALSE );
1272 /***********************************************************************
1273 * GetPrivateProfileStringA (KERNEL32.255)
1275 INT WINAPI GetPrivateProfileStringA( LPCSTR section, LPCSTR entry,
1276 LPCSTR def_val, LPSTR buffer,
1277 UINT len, LPCSTR filename )
1279 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1280 buffer, len, filename, TRUE );
1283 /***********************************************************************
1284 * GetPrivateProfileStringW (KERNEL32.256)
1286 INT WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1287 LPCWSTR def_val, LPWSTR buffer,
1288 UINT len, LPCWSTR filename )
1290 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1291 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1292 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1293 LPSTR def_valA = HEAP_strdupWtoA( GetProcessHeap(), 0, def_val );
1294 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1295 INT ret = GetPrivateProfileStringA( sectionA, entryA, def_valA,
1296 bufferA, len, filenameA );
1297 if (len > 0 && !MultiByteToWideChar( CP_ACP, 0, bufferA, -1, buffer, len ))
1298 buffer[len-1] = 0;
1299 HeapFree( GetProcessHeap(), 0, sectionA );
1300 HeapFree( GetProcessHeap(), 0, entryA );
1301 HeapFree( GetProcessHeap(), 0, filenameA );
1302 HeapFree( GetProcessHeap(), 0, def_valA );
1303 HeapFree( GetProcessHeap(), 0, bufferA);
1304 return ret;
1307 /***********************************************************************
1308 * GetProfileString16 (KERNEL.58)
1310 INT16 WINAPI GetProfileString16( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1311 LPSTR buffer, UINT16 len )
1313 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1314 buffer, len, "win.ini", FALSE );
1317 /***********************************************************************
1318 * GetProfileStringA (KERNEL32.268)
1320 INT WINAPI GetProfileStringA( LPCSTR section, LPCSTR entry, LPCSTR def_val,
1321 LPSTR buffer, UINT len )
1323 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1324 buffer, len, "win.ini", TRUE );
1327 /***********************************************************************
1328 * GetProfileStringW (KERNEL32.269)
1330 INT WINAPI GetProfileStringW( LPCWSTR section, LPCWSTR entry,
1331 LPCWSTR def_val, LPWSTR buffer, UINT len )
1333 return GetPrivateProfileStringW( section, entry, def_val,
1334 buffer, len, wininiW );
1337 /***********************************************************************
1338 * WriteProfileString16 (KERNEL.59)
1340 BOOL16 WINAPI WriteProfileString16( LPCSTR section, LPCSTR entry,
1341 LPCSTR string )
1343 return WritePrivateProfileString16( section, entry, string, "win.ini" );
1346 /***********************************************************************
1347 * WriteProfileStringA (KERNEL32.587)
1349 BOOL WINAPI WriteProfileStringA( LPCSTR section, LPCSTR entry,
1350 LPCSTR string )
1352 return WritePrivateProfileStringA( section, entry, string, "win.ini" );
1355 /***********************************************************************
1356 * WriteProfileStringW (KERNEL32.588)
1358 BOOL WINAPI WriteProfileStringW( LPCWSTR section, LPCWSTR entry,
1359 LPCWSTR string )
1361 return WritePrivateProfileStringW( section, entry, string, wininiW );
1365 /***********************************************************************
1366 * GetPrivateProfileInt16 (KERNEL.127)
1368 UINT16 WINAPI GetPrivateProfileInt16( LPCSTR section, LPCSTR entry,
1369 INT16 def_val, LPCSTR filename )
1371 long result=(long)GetPrivateProfileIntA(section,entry,def_val,filename);
1373 if (result > 65535) return 65535;
1374 if (result >= 0) return (UINT16)result;
1375 if (result < -32768) return -32768;
1376 return (UINT16)(INT16)result;
1379 /***********************************************************************
1380 * GetPrivateProfileIntA (KERNEL32.251)
1382 UINT WINAPI GetPrivateProfileIntA( LPCSTR section, LPCSTR entry,
1383 INT def_val, LPCSTR filename )
1385 char buffer[20];
1386 char *p;
1387 long result;
1389 PROFILE_GetPrivateProfileString( section, entry, "",
1390 buffer, sizeof(buffer), filename, FALSE );
1391 if (!buffer[0]) return (UINT)def_val;
1392 result = strtol( buffer, &p, 0 );
1393 if (p == buffer) return 0; /* No digits at all */
1394 return (UINT)result;
1397 /***********************************************************************
1398 * GetPrivateProfileIntW (KERNEL32.252)
1400 UINT WINAPI GetPrivateProfileIntW( LPCWSTR section, LPCWSTR entry,
1401 INT def_val, LPCWSTR filename )
1403 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1404 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1405 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1406 UINT res = GetPrivateProfileIntA(sectionA, entryA, def_val, filenameA);
1407 HeapFree( GetProcessHeap(), 0, sectionA );
1408 HeapFree( GetProcessHeap(), 0, filenameA );
1409 HeapFree( GetProcessHeap(), 0, entryA );
1410 return res;
1413 /***********************************************************************
1414 * GetPrivateProfileSection16 (KERNEL.418)
1416 INT16 WINAPI GetPrivateProfileSection16( LPCSTR section, LPSTR buffer,
1417 UINT16 len, LPCSTR filename )
1419 return GetPrivateProfileSectionA( section, buffer, len, filename );
1422 /***********************************************************************
1423 * GetPrivateProfileSectionA (KERNEL32.255)
1425 INT WINAPI GetPrivateProfileSectionA( LPCSTR section, LPSTR buffer,
1426 DWORD len, LPCSTR filename )
1428 int ret = 0;
1430 EnterCriticalSection( &PROFILE_CritSect );
1432 if (PROFILE_Open( filename ))
1433 ret = PROFILE_GetSection(CurProfile->section, section, buffer, len,
1434 FALSE, TRUE);
1436 LeaveCriticalSection( &PROFILE_CritSect );
1438 return ret;
1441 /***********************************************************************
1442 * GetPrivateProfileSectionW (KERNEL32.256)
1445 INT WINAPI GetPrivateProfileSectionW (LPCWSTR section, LPWSTR buffer,
1446 DWORD len, LPCWSTR filename )
1449 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1450 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1451 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1452 INT ret = GetPrivateProfileSectionA( sectionA, bufferA, len,
1453 filenameA );
1454 MultiByteToWideChar(CP_ACP,0,bufferA,ret,buffer,len);
1455 HeapFree( GetProcessHeap(), 0, sectionA );
1456 HeapFree( GetProcessHeap(), 0, filenameA );
1457 HeapFree( GetProcessHeap(), 0, bufferA);
1458 return ret;
1461 /***********************************************************************
1462 * GetProfileSection16 (KERNEL.419)
1464 INT16 WINAPI GetProfileSection16( LPCSTR section, LPSTR buffer, UINT16 len )
1466 return GetPrivateProfileSection16( section, buffer, len, "win.ini" );
1469 /***********************************************************************
1470 * GetProfileSectionA (KERNEL32.268)
1472 INT WINAPI GetProfileSectionA( LPCSTR section, LPSTR buffer, DWORD len )
1474 return GetPrivateProfileSectionA( section, buffer, len, "win.ini" );
1477 /***********************************************************************
1478 * GetProfileSectionW (KERNEL32)
1480 INT WINAPI GetProfileSectionW( LPCWSTR section, LPWSTR buffer, DWORD len )
1482 return GetPrivateProfileSectionW( section, buffer, len, wininiW );
1486 /***********************************************************************
1487 * WritePrivateProfileString16 (KERNEL.129)
1489 BOOL16 WINAPI WritePrivateProfileString16( LPCSTR section, LPCSTR entry,
1490 LPCSTR string, LPCSTR filename )
1492 return WritePrivateProfileStringA(section,entry,string,filename);
1495 /***********************************************************************
1496 * WritePrivateProfileStringA (KERNEL32.582)
1498 BOOL WINAPI WritePrivateProfileStringA( LPCSTR section, LPCSTR entry,
1499 LPCSTR string, LPCSTR filename )
1501 BOOL ret = FALSE;
1503 EnterCriticalSection( &PROFILE_CritSect );
1505 if (PROFILE_Open( filename ))
1507 if (!section && !entry && !string)
1508 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1509 else
1510 ret = PROFILE_SetString( section, entry, string );
1513 LeaveCriticalSection( &PROFILE_CritSect );
1514 return ret;
1517 /***********************************************************************
1518 * WritePrivateProfileStringW (KERNEL32.583)
1520 BOOL WINAPI WritePrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1521 LPCWSTR string, LPCWSTR filename )
1523 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1524 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1525 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1526 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1527 BOOL res = WritePrivateProfileStringA( sectionA, entryA,
1528 stringA, filenameA );
1529 HeapFree( GetProcessHeap(), 0, sectionA );
1530 HeapFree( GetProcessHeap(), 0, entryA );
1531 HeapFree( GetProcessHeap(), 0, stringA );
1532 HeapFree( GetProcessHeap(), 0, filenameA );
1533 return res;
1536 /***********************************************************************
1537 * WritePrivateProfileSection16 (KERNEL.416)
1539 BOOL16 WINAPI WritePrivateProfileSection16( LPCSTR section,
1540 LPCSTR string, LPCSTR filename )
1542 return WritePrivateProfileSectionA( section, string, filename );
1545 /***********************************************************************
1546 * WritePrivateProfileSectionA (KERNEL32)
1548 BOOL WINAPI WritePrivateProfileSectionA( LPCSTR section,
1549 LPCSTR string, LPCSTR filename )
1551 BOOL ret = FALSE;
1552 LPSTR p ;
1554 EnterCriticalSection( &PROFILE_CritSect );
1556 if (PROFILE_Open( filename )) {
1557 if (!section && !string)
1558 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1559 else if (!string) /* delete the named section*/
1560 ret = PROFILE_SetString(section,NULL,NULL);
1561 else {
1562 PROFILE_DeleteAllKeys(section);
1563 ret = TRUE;
1564 while(*string) {
1565 LPSTR buf=HEAP_strdupA( GetProcessHeap(), 0, string );
1566 if((p=strchr( buf, '='))){
1567 *p='\0';
1568 ret = PROFILE_SetString( section, buf, p+1 );
1571 HeapFree( GetProcessHeap(), 0, buf );
1572 string += strlen(string)+1;
1578 LeaveCriticalSection( &PROFILE_CritSect );
1579 return ret;
1582 /***********************************************************************
1583 * WritePrivateProfileSectionW (KERNEL32)
1585 BOOL WINAPI WritePrivateProfileSectionW( LPCWSTR section,
1586 LPCWSTR string, LPCWSTR filename)
1589 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1590 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1591 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1592 BOOL res = WritePrivateProfileSectionA( sectionA, stringA, filenameA );
1593 HeapFree( GetProcessHeap(), 0, sectionA );
1594 HeapFree( GetProcessHeap(), 0, stringA );
1595 HeapFree( GetProcessHeap(), 0, filenameA );
1596 return res;
1599 /***********************************************************************
1600 * WriteProfileSection16 (KERNEL.417)
1602 BOOL16 WINAPI WriteProfileSection16( LPCSTR section, LPCSTR keys_n_values)
1604 return WritePrivateProfileSection16( section, keys_n_values, "win.ini");
1607 /***********************************************************************
1608 * WriteProfileSectionA (KERNEL32.747)
1610 BOOL WINAPI WriteProfileSectionA( LPCSTR section, LPCSTR keys_n_values)
1613 return WritePrivateProfileSectionA( section, keys_n_values, "win.ini");
1616 /***********************************************************************
1617 * WriteProfileSectionW (KERNEL32.748)
1619 BOOL WINAPI WriteProfileSectionW( LPCWSTR section, LPCWSTR keys_n_values)
1621 return (WritePrivateProfileSectionW (section,keys_n_values, wininiW));
1624 /***********************************************************************
1625 * GetPrivateProfileSectionNames16 (KERNEL.143)
1627 WORD WINAPI GetPrivateProfileSectionNames16( LPSTR buffer, WORD size,
1628 LPCSTR filename )
1630 WORD ret = 0;
1632 EnterCriticalSection( &PROFILE_CritSect );
1634 if (PROFILE_Open( filename ))
1635 ret = PROFILE_GetSectionNames(buffer, size);
1637 LeaveCriticalSection( &PROFILE_CritSect );
1639 return ret;
1643 /***********************************************************************
1644 * GetProfileSectionNames16 (KERNEL.142)
1646 WORD WINAPI GetProfileSectionNames16( LPSTR buffer, WORD size)
1649 return (GetPrivateProfileSectionNames16 (buffer,size,"win.ini"));
1653 /***********************************************************************
1654 * GetPrivateProfileSectionNamesA (KERNEL32.365)
1656 DWORD WINAPI GetPrivateProfileSectionNamesA( LPSTR buffer, DWORD size,
1657 LPCSTR filename)
1660 return (GetPrivateProfileSectionNames16 (buffer,size,filename));
1664 /***********************************************************************
1665 * GetPrivateProfileSectionNamesW (KERNEL32.366)
1667 DWORD WINAPI GetPrivateProfileSectionNamesW( LPWSTR buffer, DWORD size,
1668 LPCWSTR filename)
1671 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1672 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, size);
1674 INT ret = GetPrivateProfileSectionNames16 (bufferA, size, filenameA);
1675 if (size > 0 && !MultiByteToWideChar( CP_ACP, 0, bufferA, -1, buffer, size ))
1676 buffer[size-1] = 0;
1677 HeapFree( GetProcessHeap(), 0, bufferA);
1678 HeapFree( GetProcessHeap(), 0, filenameA );
1680 return ret;
1683 /***********************************************************************
1684 * GetPrivateProfileStruct16 (KERNEL.407)
1686 BOOL16 WINAPI GetPrivateProfileStruct16(LPCSTR section, LPCSTR key,
1687 LPVOID buf, UINT16 len, LPCSTR filename)
1689 return GetPrivateProfileStructA( section, key, buf, len, filename );
1692 /***********************************************************************
1693 * GetPrivateProfileStructA (KERNEL32.370)
1695 * Should match Win95's behaviour pretty much
1697 BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key,
1698 LPVOID buf, UINT len, LPCSTR filename)
1700 BOOL ret = FALSE;
1702 EnterCriticalSection( &PROFILE_CritSect );
1704 if (PROFILE_Open( filename )) {
1705 PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE);
1706 if (k) {
1707 TRACE("value (at %p): '%s'\n", k->value, k->value);
1708 if (((strlen(k->value) - 2) / 2) == len)
1710 LPSTR end, p;
1711 BOOL valid = TRUE;
1712 CHAR c;
1713 DWORD chksum = 0;
1715 end = k->value + strlen(k->value); /* -> '\0' */
1716 /* check for invalid chars in ASCII coded hex string */
1717 for (p=k->value; p < end; p++)
1719 if (!isxdigit(*p))
1721 WARN("invalid char '%c' in file '%s'->'[%s]'->'%s' !\n",
1722 *p, filename, section, key);
1723 valid = FALSE;
1724 break;
1727 if (valid)
1729 BOOL highnibble = TRUE;
1730 BYTE b = 0, val;
1731 LPBYTE binbuf = (LPBYTE)buf;
1733 end -= 2; /* don't include checksum in output data */
1734 /* translate ASCII hex format into binary data */
1735 for (p=k->value; p < end; p++)
1737 c = toupper(*p);
1738 val = (c > '9') ?
1739 (c - 'A' + 10) : (c - '0');
1741 if (highnibble)
1742 b = val << 4;
1743 else
1745 b += val;
1746 *binbuf++ = b; /* feed binary data into output */
1747 chksum += b; /* calculate checksum */
1749 highnibble ^= 1; /* toggle */
1751 /* retrieve stored checksum value */
1752 c = toupper(*p++);
1753 b = ( (c > '9') ? (c - 'A' + 10) : (c - '0') ) << 4;
1754 c = toupper(*p);
1755 b += (c > '9') ? (c - 'A' + 10) : (c - '0');
1756 if (b == (chksum & 0xff)) /* checksums match ? */
1757 ret = TRUE;
1762 LeaveCriticalSection( &PROFILE_CritSect );
1764 return ret;
1767 /***********************************************************************
1768 * GetPrivateProfileStructW (KERNEL32.543)
1770 BOOL WINAPI GetPrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1771 LPVOID buffer, UINT len, LPCWSTR filename)
1773 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1774 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1775 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1776 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1778 INT ret = GetPrivateProfileStructA( sectionA, keyA, bufferA,
1779 len, filenameA );
1780 if (len > 0 && !MultiByteToWideChar( CP_ACP, 0, bufferA, -1, buffer, len ))
1781 ((LPWSTR)buffer)[len-1] = 0;
1782 HeapFree( GetProcessHeap(), 0, bufferA);
1783 HeapFree( GetProcessHeap(), 0, sectionA );
1784 HeapFree( GetProcessHeap(), 0, keyA );
1785 HeapFree( GetProcessHeap(), 0, filenameA );
1787 return ret;
1792 /***********************************************************************
1793 * WritePrivateProfileStruct16 (KERNEL.406)
1795 BOOL16 WINAPI WritePrivateProfileStruct16 (LPCSTR section, LPCSTR key,
1796 LPVOID buf, UINT16 bufsize, LPCSTR filename)
1798 return WritePrivateProfileStructA( section, key, buf, bufsize, filename );
1801 /***********************************************************************
1802 * WritePrivateProfileStructA (KERNEL32.744)
1804 BOOL WINAPI WritePrivateProfileStructA (LPCSTR section, LPCSTR key,
1805 LPVOID buf, UINT bufsize, LPCSTR filename)
1807 BOOL ret = FALSE;
1808 LPBYTE binbuf;
1809 LPSTR outstring, p;
1810 DWORD sum = 0;
1812 if (!section && !key && !buf) /* flush the cache */
1813 return WritePrivateProfileStringA( NULL, NULL, NULL, filename );
1815 /* allocate string buffer for hex chars + checksum hex char + '\0' */
1816 outstring = HeapAlloc( GetProcessHeap(), 0, bufsize*2 + 2 + 1);
1817 p = outstring;
1818 for (binbuf = (LPBYTE)buf; binbuf < (LPBYTE)buf+bufsize; binbuf++) {
1819 *p++ = hex[*binbuf >> 4];
1820 *p++ = hex[*binbuf & 0xf];
1821 sum += *binbuf;
1823 /* checksum is sum & 0xff */
1824 *p++ = hex[(sum & 0xf0) >> 4];
1825 *p++ = hex[sum & 0xf];
1826 *p++ = '\0';
1828 EnterCriticalSection( &PROFILE_CritSect );
1830 if (PROFILE_Open( filename ))
1831 ret = PROFILE_SetString( section, key, outstring );
1833 LeaveCriticalSection( &PROFILE_CritSect );
1835 HeapFree( GetProcessHeap(), 0, outstring );
1837 return ret;
1840 /***********************************************************************
1841 * WritePrivateProfileStructW (KERNEL32.544)
1843 BOOL WINAPI WritePrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1844 LPVOID buf, UINT bufsize, LPCWSTR filename)
1846 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1847 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1848 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1849 INT ret = WritePrivateProfileStructA( sectionA, keyA, buf, bufsize,
1850 filenameA );
1851 HeapFree( GetProcessHeap(), 0, sectionA );
1852 HeapFree( GetProcessHeap(), 0, keyA );
1853 HeapFree( GetProcessHeap(), 0, filenameA );
1855 return ret;
1859 /***********************************************************************
1860 * WriteOutProfiles (KERNEL.315)
1862 void WINAPI WriteOutProfiles16(void)
1864 EnterCriticalSection( &PROFILE_CritSect );
1865 PROFILE_FlushFile();
1866 LeaveCriticalSection( &PROFILE_CritSect );
1869 /***********************************************************************
1870 * CloseProfileUserMapping (KERNEL.138)
1872 BOOL WINAPI CloseProfileUserMapping(void) {
1873 FIXME("(), stub!\n");
1874 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1875 return FALSE;