blob: 7761acf0113bee76a9e807a8067aa2b97ac643fe [file] [log] [blame]
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001/*
2 * Profile functions
3 *
4 * Copyright 1993 Miguel de Icaza
5 * Copyright 1996 Alexandre Julliard
6 */
7
8#include <ctype.h>
Alexandre Julliard95153362001-03-23 19:13:23 +00009#include <errno.h>
Alexandre Julliard73be8d12000-12-06 20:25:11 +000010#include <fcntl.h>
Alexandre Julliard02ed4c21996-03-02 19:34:10 +000011#include <stdlib.h>
Alexandre Julliard7e56f681996-01-31 19:02:28 +000012#include <string.h>
Jeremy Whited3e22d92000-02-10 19:03:02 +000013#include <stdio.h>
Alexandre Julliard829fe321998-07-26 14:27:39 +000014#include <sys/stat.h>
Alexandre Julliard647876e2000-01-25 01:35:01 +000015#include <sys/types.h>
16#include <pwd.h>
17#include <unistd.h>
Alexandre Julliard829fe321998-07-26 14:27:39 +000018
Alexandre Julliard24a62ab2000-11-28 22:40:56 +000019#include "windef.h"
Marcus Meissner317af321999-02-17 13:51:06 +000020#include "winbase.h"
Alexandre Julliard24a62ab2000-11-28 22:40:56 +000021#include "winnls.h"
Marcus Meissner9b4fcf71999-12-04 04:19:55 +000022#include "winerror.h"
Marcus Meissner317af321999-02-17 13:51:06 +000023#include "wine/winbase16.h"
Alexandre Julliard00377a72000-02-19 20:50:00 +000024#include "winreg.h"
Alexandre Julliardc6c09441997-01-12 18:32:19 +000025#include "file.h"
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +000026#include "heap.h"
Alexandre Julliard359f497e1999-07-04 16:02:24 +000027#include "debugtools.h"
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000028#include "options.h"
Alexandre Julliard37e95032001-07-19 00:39:09 +000029#include "wine/server.h"
Alexandre Julliard7e56f681996-01-31 19:02:28 +000030
Jeremy Whited3e22d92000-02-10 19:03:02 +000031DEFAULT_DEBUG_CHANNEL(profile);
Patrik Stridvallb4b9fae1999-04-19 14:56:29 +000032
Alexandre Julliard7e56f681996-01-31 19:02:28 +000033typedef struct tagPROFILEKEY
34{
Alexandre Julliard7e56f681996-01-31 19:02:28 +000035 char *value;
36 struct tagPROFILEKEY *next;
Alexandre Julliard5f728ca2001-07-24 21:45:22 +000037 char name[1];
Alexandre Julliard7e56f681996-01-31 19:02:28 +000038} PROFILEKEY;
39
40typedef struct tagPROFILESECTION
41{
Alexandre Julliard7e56f681996-01-31 19:02:28 +000042 struct tagPROFILEKEY *key;
43 struct tagPROFILESECTION *next;
Alexandre Julliard5f728ca2001-07-24 21:45:22 +000044 char name[1];
45} PROFILESECTION;
Alexandre Julliard7e56f681996-01-31 19:02:28 +000046
47
48typedef struct
49{
Eric Poueched155751999-03-25 13:24:08 +000050 BOOL changed;
Alexandre Julliard7e56f681996-01-31 19:02:28 +000051 PROFILESECTION *section;
52 char *dos_name;
Alexandre Julliardc6c09441997-01-12 18:32:19 +000053 char *unix_name;
54 char *filename;
Alexandre Julliard829fe321998-07-26 14:27:39 +000055 time_t mtime;
Alexandre Julliard7e56f681996-01-31 19:02:28 +000056} PROFILE;
57
58
Alexandre Julliard829fe321998-07-26 14:27:39 +000059#define N_CACHED_PROFILES 10
60
61/* Cached profile files */
62static PROFILE *MRUProfile[N_CACHED_PROFILES]={NULL};
63
64#define CurProfile (MRUProfile[0])
Alexandre Julliard7e56f681996-01-31 19:02:28 +000065
Alexandre Julliard00377a72000-02-19 20:50:00 +000066/* wine.ini config file registry root */
67static HKEY wine_profile_key;
Alexandre Julliard7e56f681996-01-31 19:02:28 +000068
69#define PROFILE_MAX_LINE_LEN 1024
70
71/* Wine profile name in $HOME directory; must begin with slash */
72static const char PROFILE_WineIniName[] = "/.winerc";
73
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000074/* Wine profile: the profile file being used */
75static char PROFILE_WineIniUsed[MAX_PATHNAME_LEN] = "";
76
Alexandre Julliard7e56f681996-01-31 19:02:28 +000077/* Check for comments in profile */
78#define IS_ENTRY_COMMENT(str) ((str)[0] == ';')
79
Alexandre Julliard00377a72000-02-19 20:50:00 +000080static const WCHAR wininiW[] = { 'w','i','n','.','i','n','i',0 };
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000081
Alexandre Julliard301df6b2001-08-16 18:12:56 +000082static CRITICAL_SECTION PROFILE_CritSect = CRITICAL_SECTION_INIT("PROFILE_CritSect");
Eric Poueched155751999-03-25 13:24:08 +000083
Andreas Mohr17b1f462000-01-30 21:15:14 +000084static const char hex[16] = "0123456789ABCDEF";
Alexandre Julliard647876e2000-01-25 01:35:01 +000085
86/***********************************************************************
Alexandre Julliard7e56f681996-01-31 19:02:28 +000087 * PROFILE_CopyEntry
88 *
89 * Copy the content of an entry into a buffer, removing quotes, and possibly
90 * translating environment variables.
91 */
92static void PROFILE_CopyEntry( char *buffer, const char *value, int len,
93 int handle_env )
94{
95 char quote = '\0';
96 const char *p;
97
Dmitry Timoshkovfdc78a32000-12-19 19:37:03 +000098 if(!buffer) return;
99
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000100 if ((*value == '\'') || (*value == '\"'))
101 {
102 if (value[1] && (value[strlen(value)-1] == *value)) quote = *value++;
103 }
104
105 if (!handle_env)
106 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000107 lstrcpynA( buffer, value, len );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000108 if (quote && (len >= strlen(value))) buffer[strlen(buffer)-1] = '\0';
109 return;
110 }
111
112 for (p = value; (*p && (len > 1)); *buffer++ = *p++, len-- )
113 {
114 if ((*p == '$') && (p[1] == '{'))
115 {
116 char env_val[1024];
117 const char *env_p;
118 const char *p2 = strchr( p, '}' );
119 if (!p2) continue; /* ignore it */
Francois Gouget6d77d3a2000-03-25 21:44:35 +0000120 lstrcpynA(env_val, p + 2, min( sizeof(env_val), (int)(p2-p)-1 ));
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000121 if ((env_p = getenv( env_val )) != NULL)
122 {
Francois Gouget09a17832001-05-07 18:11:57 +0000123 int buffer_len;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000124 lstrcpynA( buffer, env_p, len );
Francois Gouget09a17832001-05-07 18:11:57 +0000125 buffer_len = strlen( buffer );
126 buffer += buffer_len;
127 len -= buffer_len;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000128 }
129 p = p2 + 1;
130 }
131 }
Eric Pouechf54c95f1999-10-31 17:32:57 +0000132 if (quote && (len > 1)) buffer--;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000133 *buffer = '\0';
134}
135
136
137/***********************************************************************
138 * PROFILE_Save
139 *
140 * Save a profile tree to a file.
141 */
142static void PROFILE_Save( FILE *file, PROFILESECTION *section )
143{
144 PROFILEKEY *key;
145
146 for ( ; section; section = section->next)
147 {
Alexandre Julliard23946ad1997-06-16 17:43:53 +0000148 if (section->name) fprintf( file, "\r\n[%s]\r\n", section->name );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000149 for (key = section->key; key; key = key->next)
150 {
151 fprintf( file, "%s", key->name );
152 if (key->value) fprintf( file, "=%s", key->value );
Alexandre Julliard7d654eb1996-02-25 11:36:22 +0000153 fprintf( file, "\r\n" );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000154 }
155 }
156}
157
158
159/***********************************************************************
160 * PROFILE_Free
161 *
162 * Free a profile tree.
163 */
164static void PROFILE_Free( PROFILESECTION *section )
165{
166 PROFILESECTION *next_section;
167 PROFILEKEY *key, *next_key;
168
169 for ( ; section; section = next_section)
170 {
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000171 for (key = section->key; key; key = next_key)
172 {
173 next_key = key->next;
Alexandre Julliard90476d62000-02-16 22:47:24 +0000174 if (key->value) HeapFree( GetProcessHeap(), 0, key->value );
175 HeapFree( GetProcessHeap(), 0, key );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000176 }
177 next_section = section->next;
Alexandre Julliard90476d62000-02-16 22:47:24 +0000178 HeapFree( GetProcessHeap(), 0, section );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000179 }
180}
181
Andreas Mohr17b1f462000-01-30 21:15:14 +0000182static inline int PROFILE_isspace(char c)
183{
Alexandre Julliardf90efa91998-06-14 15:24:15 +0000184 if (isspace(c)) return 1;
185 if (c=='\r' || c==0x1a) return 1;
186 /* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */
187 return 0;
188}
189
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000190
191/***********************************************************************
192 * PROFILE_Load
193 *
194 * Load a profile tree from a file.
195 */
196static PROFILESECTION *PROFILE_Load( FILE *file )
197{
198 char buffer[PROFILE_MAX_LINE_LEN];
199 char *p, *p2;
200 int line = 0;
201 PROFILESECTION *section, *first_section;
Alexandre Julliard642d3131998-07-12 19:29:36 +0000202 PROFILESECTION **next_section;
203 PROFILEKEY *key, *prev_key, **next_key;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000204
Dimitrie O. Paunabdbced2000-04-29 14:20:28 +0000205 first_section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) );
Alexandre Julliard5f728ca2001-07-24 21:45:22 +0000206 if(first_section == NULL) return NULL;
207 first_section->name[0] = 0;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000208 first_section->key = NULL;
209 first_section->next = NULL;
Alexandre Julliard642d3131998-07-12 19:29:36 +0000210 next_section = &first_section->next;
211 next_key = &first_section->key;
212 prev_key = NULL;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000213
214 while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
215 {
216 line++;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000217 p = buffer;
Alexandre Julliardf90efa91998-06-14 15:24:15 +0000218 while (*p && PROFILE_isspace(*p)) p++;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000219 if (*p == '[') /* section start */
220 {
221 if (!(p2 = strrchr( p, ']' )))
222 {
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000223 WARN("Invalid section header at line %d: '%s'\n",
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000224 line, p );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000225 }
226 else
227 {
228 *p2 = '\0';
229 p++;
Alexandre Julliard5f728ca2001-07-24 21:45:22 +0000230 if (!(section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) + strlen(p) )))
231 break;
232 strcpy( section->name, p );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000233 section->key = NULL;
234 section->next = NULL;
Alexandre Julliard642d3131998-07-12 19:29:36 +0000235 *next_section = section;
236 next_section = &section->next;
237 next_key = &section->key;
238 prev_key = NULL;
Alexandre Julliard829fe321998-07-26 14:27:39 +0000239
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000240 TRACE("New section: '%s'\n",section->name);
Alexandre Julliard829fe321998-07-26 14:27:39 +0000241
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000242 continue;
243 }
244 }
Alexandre Julliard829fe321998-07-26 14:27:39 +0000245
246 p2=p+strlen(p) - 1;
247 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
248
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000249 if ((p2 = strchr( p, '=' )) != NULL)
250 {
251 char *p3 = p2 - 1;
Alexandre Julliardf90efa91998-06-14 15:24:15 +0000252 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000253 *p2++ = '\0';
Alexandre Julliardf90efa91998-06-14 15:24:15 +0000254 while (*p2 && PROFILE_isspace(*p2)) p2++;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000255 }
Alexandre Julliard642d3131998-07-12 19:29:36 +0000256
257 if(*p || !prev_key || *prev_key->name)
Dimitrie O. Paunabdbced2000-04-29 14:20:28 +0000258 {
Alexandre Julliard5f728ca2001-07-24 21:45:22 +0000259 if (!(key = HeapAlloc( GetProcessHeap(), 0, sizeof(*key) + strlen(p) ))) break;
260 strcpy( key->name, p );
261 if (p2)
262 {
263 key->value = HeapAlloc( GetProcessHeap(), 0, strlen(p2)+1 );
264 strcpy( key->value, p2 );
265 }
266 else key->value = NULL;
267
Alexandre Julliard642d3131998-07-12 19:29:36 +0000268 key->next = NULL;
269 *next_key = key;
270 next_key = &key->next;
271 prev_key = key;
272
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000273 TRACE("New key: name='%s', value='%s'\n",key->name,key->value?key->value:"(none)");
Dimitrie O. Paunabdbced2000-04-29 14:20:28 +0000274 }
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000275 }
276 return first_section;
277}
278
Alexandre Julliard73be8d12000-12-06 20:25:11 +0000279/* convert the .winerc file to the new format */
Alexandre Julliard95153362001-03-23 19:13:23 +0000280static void convert_config( FILE *in, const char *output_name )
Alexandre Julliard73be8d12000-12-06 20:25:11 +0000281{
282 char buffer[PROFILE_MAX_LINE_LEN];
283 char *p, *p2;
284 FILE *out;
285
286 /* create the output file, only if it doesn't exist already */
287 int fd = open( output_name, O_WRONLY|O_CREAT|O_EXCL, 0666 );
Alexandre Julliard95153362001-03-23 19:13:23 +0000288 if (fd == -1)
289 {
290 MESSAGE( "Could not create new config file '%s': %s\n", output_name, strerror(errno) );
291 ExitProcess(1);
292 }
Alexandre Julliard73be8d12000-12-06 20:25:11 +0000293
294 out = fdopen( fd, "w" );
295 fprintf( out, "WINE REGISTRY Version 2\n" );
296 fprintf( out, ";; All keys relative to \\\\Machine\\\\Software\\\\Wine\\\\Wine\\\\Config\n\n" );
297 while (fgets( buffer, PROFILE_MAX_LINE_LEN, in ))
298 {
299 if (buffer[strlen(buffer)-1] == '\n') buffer[strlen(buffer)-1] = 0;
300 p = buffer;
301 while (*p && PROFILE_isspace(*p)) p++;
302 if (*p == '[') /* section start */
303 {
304 if ((p2 = strrchr( p, ']' )))
305 {
306 *p2 = '\0';
307 p++;
308 fprintf( out, "[%s]\n", p );
309 }
310 continue;
311 }
312
313 if (*p == ';' || *p == '#')
314 {
315 fprintf( out, "%s\n", p );
316 continue;
317 }
318
319 p2=p+strlen(p) - 1;
320 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
321
322 if ((p2 = strchr( p, '=' )) != NULL)
323 {
324 char *p3 = p2 - 1;
325 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
326 *p2++ = '\0';
327 while (*p2 && PROFILE_isspace(*p2)) p2++;
328 }
329
330 if (!*p)
331 {
332 fprintf( out, "\n" );
333 continue;
334 }
335 fputc( '"', out );
336 while (*p)
337 {
338 if (*p == '\\') fputc( '\\', out );
339 fputc( *p, out );
340 p++;
341 }
342 fprintf( out, "\" = \"" );
Alexandre Julliard550ba5b2001-01-05 22:23:37 +0000343 if (p2)
Alexandre Julliard73be8d12000-12-06 20:25:11 +0000344 {
Alexandre Julliard550ba5b2001-01-05 22:23:37 +0000345 while (*p2)
346 {
347 if (*p2 == '\\') fputc( '\\', out );
348 fputc( *p2, out );
349 p2++;
350 }
Alexandre Julliard73be8d12000-12-06 20:25:11 +0000351 }
352 fprintf( out, "\"\n" );
353 }
354 fclose( out );
Alexandre Julliard00377a72000-02-19 20:50:00 +0000355}
356
357
358/***********************************************************************
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000359 * PROFILE_DeleteSection
360 *
361 * Delete a section from a profile tree.
362 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000363static BOOL PROFILE_DeleteSection( PROFILESECTION **section, LPCSTR name )
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000364{
365 while (*section)
366 {
Alexandre Julliard5f728ca2001-07-24 21:45:22 +0000367 if ((*section)->name[0] && !strcasecmp( (*section)->name, name ))
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000368 {
369 PROFILESECTION *to_del = *section;
370 *section = to_del->next;
371 to_del->next = NULL;
372 PROFILE_Free( to_del );
373 return TRUE;
374 }
375 section = &(*section)->next;
376 }
377 return FALSE;
378}
379
380
381/***********************************************************************
382 * PROFILE_DeleteKey
383 *
384 * Delete a key from a profile tree.
385 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000386static BOOL PROFILE_DeleteKey( PROFILESECTION **section,
Eric Poueched155751999-03-25 13:24:08 +0000387 LPCSTR section_name, LPCSTR key_name )
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000388{
389 while (*section)
390 {
Alexandre Julliard5f728ca2001-07-24 21:45:22 +0000391 if ((*section)->name[0] && !strcasecmp( (*section)->name, section_name ))
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000392 {
393 PROFILEKEY **key = &(*section)->key;
394 while (*key)
395 {
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +0000396 if (!strcasecmp( (*key)->name, key_name ))
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000397 {
398 PROFILEKEY *to_del = *key;
399 *key = to_del->next;
Alexandre Julliard90476d62000-02-16 22:47:24 +0000400 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
401 HeapFree( GetProcessHeap(), 0, to_del );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000402 return TRUE;
403 }
404 key = &(*key)->next;
405 }
406 }
407 section = &(*section)->next;
408 }
409 return FALSE;
410}
411
412
413/***********************************************************************
Uwe Bonnesd88fbb72000-06-20 20:48:46 +0000414 * PROFILE_DeleteAllKeys
415 *
416 * Delete all keys from a profile tree.
417 */
418void PROFILE_DeleteAllKeys( LPCSTR section_name)
419{
420 PROFILESECTION **section= &CurProfile->section;
421 while (*section)
422 {
Alexandre Julliard5f728ca2001-07-24 21:45:22 +0000423 if ((*section)->name[0] && !strcasecmp( (*section)->name, section_name ))
Uwe Bonnesd88fbb72000-06-20 20:48:46 +0000424 {
425 PROFILEKEY **key = &(*section)->key;
426 while (*key)
427 {
428 PROFILEKEY *to_del = *key;
429 *key = to_del->next;
Uwe Bonnesd88fbb72000-06-20 20:48:46 +0000430 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
431 HeapFree( GetProcessHeap(), 0, to_del );
432 CurProfile->changed =TRUE;
433 }
434 }
435 section = &(*section)->next;
436 }
437}
438
439
440/***********************************************************************
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000441 * PROFILE_Find
442 *
443 * Find a key in a profile tree, optionally creating it.
444 */
445static PROFILEKEY *PROFILE_Find( PROFILESECTION **section,
446 const char *section_name,
447 const char *key_name, int create )
448{
Andreas Mohr17b1f462000-01-30 21:15:14 +0000449 const char *p;
450 int seclen, keylen;
451
452 while (PROFILE_isspace(*section_name)) section_name++;
453 p = section_name + strlen(section_name) - 1;
454 while ((p > section_name) && PROFILE_isspace(*p)) p--;
455 seclen = p - section_name + 1;
456
457 while (PROFILE_isspace(*key_name)) key_name++;
458 p = key_name + strlen(key_name) - 1;
459 while ((p > key_name) && PROFILE_isspace(*p)) p--;
460 keylen = p - key_name + 1;
461
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000462 while (*section)
463 {
Alexandre Julliard5f728ca2001-07-24 21:45:22 +0000464 if ( ((*section)->name[0])
Andreas Mohr17b1f462000-01-30 21:15:14 +0000465 && (!(strncasecmp( (*section)->name, section_name, seclen )))
466 && (((*section)->name)[seclen] == '\0') )
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000467 {
468 PROFILEKEY **key = &(*section)->key;
469 while (*key)
470 {
Andreas Mohr17b1f462000-01-30 21:15:14 +0000471 if ( (!(strncasecmp( (*key)->name, key_name, keylen )))
472 && (((*key)->name)[keylen] == '\0') )
473 return *key;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000474 key = &(*key)->next;
475 }
476 if (!create) return NULL;
Alexandre Julliard5f728ca2001-07-24 21:45:22 +0000477 if (!(*key = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) + strlen(key_name) )))
478 return NULL;
479 strcpy( (*key)->name, key_name );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000480 (*key)->value = NULL;
481 (*key)->next = NULL;
482 return *key;
483 }
484 section = &(*section)->next;
485 }
486 if (!create) return NULL;
Alexandre Julliard5f728ca2001-07-24 21:45:22 +0000487 *section = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILESECTION) + strlen(section_name) );
Dimitrie O. Paunabdbced2000-04-29 14:20:28 +0000488 if(*section == NULL) return NULL;
Alexandre Julliard5f728ca2001-07-24 21:45:22 +0000489 strcpy( (*section)->name, section_name );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000490 (*section)->next = NULL;
Alexandre Julliard5f728ca2001-07-24 21:45:22 +0000491 if (!((*section)->key = HeapAlloc( GetProcessHeap(), 0,
492 sizeof(PROFILEKEY) + strlen(key_name) )))
Dimitrie O. Paunabdbced2000-04-29 14:20:28 +0000493 {
Alexandre Julliard5f728ca2001-07-24 21:45:22 +0000494 HeapFree(GetProcessHeap(), 0, *section);
495 return NULL;
Dimitrie O. Paunabdbced2000-04-29 14:20:28 +0000496 }
Alexandre Julliard5f728ca2001-07-24 21:45:22 +0000497 strcpy( (*section)->key->name, key_name );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000498 (*section)->key->value = NULL;
499 (*section)->key->next = NULL;
500 return (*section)->key;
501}
502
503
504/***********************************************************************
505 * PROFILE_FlushFile
506 *
507 * Flush the current profile to disk if changed.
508 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000509static BOOL PROFILE_FlushFile(void)
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000510{
511 char *p, buffer[MAX_PATHNAME_LEN];
512 const char *unix_name;
513 FILE *file = NULL;
Alexandre Julliard829fe321998-07-26 14:27:39 +0000514 struct stat buf;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000515
Alexandre Julliard829fe321998-07-26 14:27:39 +0000516 if(!CurProfile)
517 {
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000518 WARN("No current profile!\n");
Alexandre Julliard829fe321998-07-26 14:27:39 +0000519 return FALSE;
520 }
521
522 if (!CurProfile->changed || !CurProfile->dos_name) return TRUE;
523 if (!(unix_name = CurProfile->unix_name) || !(file = fopen(unix_name, "w")))
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000524 {
525 /* Try to create it in $HOME/.wine */
526 /* FIXME: this will need a more general solution */
Alexandre Julliardde1d5ad2000-04-06 20:36:17 +0000527 strcpy( buffer, get_config_dir() );
Alexandre Julliard647876e2000-01-25 01:35:01 +0000528 p = buffer + strlen(buffer);
529 *p++ = '/';
530 strcpy( p, strrchr( CurProfile->dos_name, '\\' ) + 1 );
Alexandre Julliarddcd247e2000-08-14 17:39:15 +0000531 _strlwr( p );
Alexandre Julliard647876e2000-01-25 01:35:01 +0000532 file = fopen( buffer, "w" );
533 unix_name = buffer;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000534 }
535
536 if (!file)
537 {
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000538 WARN("could not save profile file %s\n", CurProfile->dos_name);
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000539 return FALSE;
540 }
541
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000542 TRACE("Saving '%s' into '%s'\n", CurProfile->dos_name, unix_name );
Alexandre Julliard829fe321998-07-26 14:27:39 +0000543 PROFILE_Save( file, CurProfile->section );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000544 fclose( file );
Alexandre Julliard829fe321998-07-26 14:27:39 +0000545 CurProfile->changed = FALSE;
546 if(!stat(unix_name,&buf))
547 CurProfile->mtime=buf.st_mtime;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000548 return TRUE;
549}
550
551
552/***********************************************************************
Alexandre Julliarde61b7921999-07-31 19:24:11 +0000553 * PROFILE_ReleaseFile
554 *
555 * Flush the current profile to disk and remove it from the cache.
556 */
557static void PROFILE_ReleaseFile(void)
558{
559 PROFILE_FlushFile();
560 PROFILE_Free( CurProfile->section );
Alexandre Julliard90476d62000-02-16 22:47:24 +0000561 if (CurProfile->dos_name) HeapFree( GetProcessHeap(), 0, CurProfile->dos_name );
562 if (CurProfile->unix_name) HeapFree( GetProcessHeap(), 0, CurProfile->unix_name );
563 if (CurProfile->filename) HeapFree( GetProcessHeap(), 0, CurProfile->filename );
Alexandre Julliarde61b7921999-07-31 19:24:11 +0000564 CurProfile->changed = FALSE;
565 CurProfile->section = NULL;
566 CurProfile->dos_name = NULL;
567 CurProfile->unix_name = NULL;
568 CurProfile->filename = NULL;
569 CurProfile->mtime = 0;
570}
571
572
573/***********************************************************************
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000574 * PROFILE_Open
575 *
576 * Open a profile file, checking the cached file first.
577 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000578static BOOL PROFILE_Open( LPCSTR filename )
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000579{
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000580 DOS_FULL_NAME full_name;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000581 char buffer[MAX_PATHNAME_LEN];
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000582 char *newdos_name, *p;
583 FILE *file = NULL;
Alexandre Julliard829fe321998-07-26 14:27:39 +0000584 int i,j;
585 struct stat buf;
586 PROFILE *tempProfile;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000587
Alexandre Julliard829fe321998-07-26 14:27:39 +0000588 /* First time around */
589
590 if(!CurProfile)
591 for(i=0;i<N_CACHED_PROFILES;i++)
592 {
Dimitrie O. Paunabdbced2000-04-29 14:20:28 +0000593 MRUProfile[i]=HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILE) );
594 if(MRUProfile[i] == NULL) break;
Alexandre Julliard829fe321998-07-26 14:27:39 +0000595 MRUProfile[i]->changed=FALSE;
596 MRUProfile[i]->section=NULL;
597 MRUProfile[i]->dos_name=NULL;
598 MRUProfile[i]->unix_name=NULL;
599 MRUProfile[i]->filename=NULL;
600 MRUProfile[i]->mtime=0;
601 }
602
603 /* Check for a match */
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000604
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000605 if (strchr( filename, '/' ) || strchr( filename, '\\' ) ||
606 strchr( filename, ':' ))
607 {
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000608 if (!DOSFS_GetFullName( filename, FALSE, &full_name )) return FALSE;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000609 }
610 else
611 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000612 GetWindowsDirectoryA( buffer, sizeof(buffer) );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000613 strcat( buffer, "\\" );
614 strcat( buffer, filename );
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000615 if (!DOSFS_GetFullName( buffer, FALSE, &full_name )) return FALSE;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000616 }
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000617
Alexandre Julliard829fe321998-07-26 14:27:39 +0000618 for(i=0;i<N_CACHED_PROFILES;i++)
619 {
620 if ((MRUProfile[i]->filename && !strcmp( filename, MRUProfile[i]->filename )) ||
621 (MRUProfile[i]->dos_name && !strcmp( full_name.short_name, MRUProfile[i]->dos_name )))
622 {
623 if(i)
624 {
625 PROFILE_FlushFile();
626 tempProfile=MRUProfile[i];
627 for(j=i;j>0;j--)
628 MRUProfile[j]=MRUProfile[j-1];
629 CurProfile=tempProfile;
630 }
631 if(!stat(CurProfile->unix_name,&buf) && CurProfile->mtime==buf.st_mtime)
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000632 TRACE("(%s): already opened (mru=%d)\n",
Alexandre Julliard829fe321998-07-26 14:27:39 +0000633 filename, i );
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000634 else
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000635 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000636 filename, i );
637 return TRUE;
Alexandre Julliard829fe321998-07-26 14:27:39 +0000638 }
639 }
640
Andreas Mohr87bff281999-11-21 02:03:03 +0000641 /* Flush the old current profile */
642 PROFILE_FlushFile();
Alexandre Julliard829fe321998-07-26 14:27:39 +0000643
Andreas Mohr87bff281999-11-21 02:03:03 +0000644 /* Make the oldest profile the current one only in order to get rid of it */
Alexandre Julliard829fe321998-07-26 14:27:39 +0000645 if(i==N_CACHED_PROFILES)
646 {
647 tempProfile=MRUProfile[N_CACHED_PROFILES-1];
648 for(i=N_CACHED_PROFILES-1;i>0;i--)
649 MRUProfile[i]=MRUProfile[i-1];
650 CurProfile=tempProfile;
651 }
Alexandre Julliarde61b7921999-07-31 19:24:11 +0000652 if(CurProfile->filename) PROFILE_ReleaseFile();
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000653
Andreas Mohr87bff281999-11-21 02:03:03 +0000654 /* OK, now that CurProfile is definitely free we assign it our new file */
Alexandre Julliard5f728ca2001-07-24 21:45:22 +0000655 newdos_name = HeapAlloc( GetProcessHeap(), 0, strlen(full_name.short_name)+1 );
656 strcpy( newdos_name, full_name.short_name );
Alexandre Julliard829fe321998-07-26 14:27:39 +0000657 CurProfile->dos_name = newdos_name;
Alexandre Julliard5f728ca2001-07-24 21:45:22 +0000658 CurProfile->filename = HeapAlloc( GetProcessHeap(), 0, strlen(filename)+1 );
659 strcpy( CurProfile->filename, filename );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000660
661 /* Try to open the profile file, first in $HOME/.wine */
662
663 /* FIXME: this will need a more general solution */
Alexandre Julliardde1d5ad2000-04-06 20:36:17 +0000664 strcpy( buffer, get_config_dir() );
Alexandre Julliard647876e2000-01-25 01:35:01 +0000665 p = buffer + strlen(buffer);
666 *p++ = '/';
667 strcpy( p, strrchr( newdos_name, '\\' ) + 1 );
Alexandre Julliarddcd247e2000-08-14 17:39:15 +0000668 _strlwr( p );
Alexandre Julliard647876e2000-01-25 01:35:01 +0000669 if ((file = fopen( buffer, "r" )))
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000670 {
Alexandre Julliard647876e2000-01-25 01:35:01 +0000671 TRACE("(%s): found it in %s\n",
672 filename, buffer );
Alexandre Julliard5f728ca2001-07-24 21:45:22 +0000673 CurProfile->unix_name = HeapAlloc( GetProcessHeap(), 0, strlen(buffer)+1 );
674 strcpy( CurProfile->unix_name, buffer );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000675 }
676
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000677 if (!file)
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000678 {
Alexandre Julliard5f728ca2001-07-24 21:45:22 +0000679 CurProfile->unix_name = HeapAlloc( GetProcessHeap(), 0, strlen(full_name.long_name)+1 );
680 strcpy( CurProfile->unix_name, full_name.long_name );
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000681 if ((file = fopen( full_name.long_name, "r" )))
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000682 TRACE("(%s): found it in %s\n",
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000683 filename, full_name.long_name );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000684 }
685
686 if (file)
687 {
Alexandre Julliard829fe321998-07-26 14:27:39 +0000688 CurProfile->section = PROFILE_Load( file );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000689 fclose( file );
Alexandre Julliard829fe321998-07-26 14:27:39 +0000690 if(!stat(CurProfile->unix_name,&buf))
691 CurProfile->mtime=buf.st_mtime;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000692 }
693 else
Alexandre Julliardd1ce8b21996-09-02 16:46:30 +0000694 {
695 /* Does not exist yet, we will create it in PROFILE_FlushFile */
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000696 WARN("profile file %s not found\n", newdos_name );
Alexandre Julliardd1ce8b21996-09-02 16:46:30 +0000697 }
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000698 return TRUE;
699}
700
701
702/***********************************************************************
703 * PROFILE_GetSection
704 *
Alexandre Julliarda845b881998-06-01 10:44:35 +0000705 * Returns all keys of a section.
Alexandre Julliard642d3131998-07-12 19:29:36 +0000706 * If return_values is TRUE, also include the corresponding values.
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000707 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000708static INT PROFILE_GetSection( PROFILESECTION *section, LPCSTR section_name,
Eric Poueched155751999-03-25 13:24:08 +0000709 LPSTR buffer, UINT len, BOOL handle_env,
710 BOOL return_values )
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000711{
712 PROFILEKEY *key;
Dmitry Timoshkovfdc78a32000-12-19 19:37:03 +0000713
714 if(!buffer) return 0;
715
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000716 while (section)
717 {
Alexandre Julliard5f728ca2001-07-24 21:45:22 +0000718 if (section->name[0] && !strcasecmp( section->name, section_name ))
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000719 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000720 UINT oldlen = len;
Alexandre Julliard9416aba1999-01-26 17:29:49 +0000721 for (key = section->key; key; key = key->next)
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000722 {
723 if (len <= 2) break;
Alexandre Julliard9416aba1999-01-26 17:29:49 +0000724 if (!*key->name) continue; /* Skip empty lines */
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000725 if (IS_ENTRY_COMMENT(key->name)) continue; /* Skip comments */
726 PROFILE_CopyEntry( buffer, key->name, len - 1, handle_env );
Alexandre Julliard0c126c71996-02-18 18:44:41 +0000727 len -= strlen(buffer) + 1;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000728 buffer += strlen(buffer) + 1;
Marcus Meissneree6ea512001-06-06 21:03:40 +0000729 if (len < 2)
730 break;
Alexandre Julliarda845b881998-06-01 10:44:35 +0000731 if (return_values && key->value) {
732 buffer[-1] = '=';
733 PROFILE_CopyEntry ( buffer,
734 key->value, len - 1, handle_env );
735 len -= strlen(buffer) + 1;
736 buffer += strlen(buffer) + 1;
737 }
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000738 }
739 *buffer = '\0';
Marcus Meissneracfae0c1999-05-08 18:29:10 +0000740 if (len <= 1)
Alexandre Julliard46ea8b31998-05-03 19:01:20 +0000741 /*If either lpszSection or lpszKey is NULL and the supplied
742 destination buffer is too small to hold all the strings,
743 the last string is truncated and followed by two null characters.
744 In this case, the return value is equal to cchReturnBuffer
745 minus two. */
746 {
747 buffer[-1] = '\0';
748 return oldlen - 2;
749 }
Alexandre Julliard829fe321998-07-26 14:27:39 +0000750 return oldlen - len;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000751 }
752 section = section->next;
753 }
754 buffer[0] = buffer[1] = '\0';
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000755 return 0;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000756}
757
Francois Gouget19b05e52001-08-28 18:39:26 +0000758/* See GetPrivateProfileSectionNamesA for documentation */
Andreas Mohradfeec91999-05-22 16:04:57 +0000759static INT PROFILE_GetSectionNames( LPSTR buffer, UINT len )
760{
Francois Gouget19b05e52001-08-28 18:39:26 +0000761 LPSTR buf;
762 UINT f,l;
Andreas Mohradfeec91999-05-22 16:04:57 +0000763 PROFILESECTION *section;
764
Francois Gouget19b05e52001-08-28 18:39:26 +0000765 if (!buffer || !len)
766 return 0;
767 if (len==1) {
768 *buffer='\0';
769 return 0;
770 }
Dmitry Timoshkovfdc78a32000-12-19 19:37:03 +0000771
Francois Gouget19b05e52001-08-28 18:39:26 +0000772 f=len-1;
773 buf=buffer;
774 section = CurProfile->section;
775 while ((section!=NULL)) {
776 if (section->name[0]) {
777 l = strlen(section->name)+1;
778 if (l > f) {
779 if (f>0) {
780 strncpy(buf, section->name, f-1);
781 buf += f-1;
782 *buf++='\0';
783 }
784 *buf='\0';
785 return len-2;
786 }
787 strcpy(buf, section->name);
788 buf += l;
789 f -= l;
790 }
791 section = section->next;
792 }
793 *buf='\0';
Andreas Mohradfeec91999-05-22 16:04:57 +0000794 return buf-buffer;
795}
796
797
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000798/***********************************************************************
799 * PROFILE_GetString
800 *
801 * Get a profile string.
Andreas Mohr3ac104f2000-09-29 21:04:44 +0000802 *
803 * Tests with GetPrivateProfileString16, W95a,
804 * with filled buffer ("****...") and section "set1" and key_name "1" valid:
805 * section key_name def_val res buffer
806 * "set1" "1" "x" 43 [data]
807 * "set1" "1 " "x" 43 [data] (!)
808 * "set1" " 1 "' "x" 43 [data] (!)
809 * "set1" "" "x" 1 "x"
810 * "set1" "" "x " 1 "x" (!)
811 * "set1" "" " x " 3 " x" (!)
812 * "set1" NULL "x" 6 "1\02\03\0\0"
813 * "set1" "" "x" 1 "x"
814 * NULL "1" "x" 0 "" (!)
815 * "" "1" "x" 1 "x"
816 * NULL NULL "" 0 ""
817 *
818 *
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000819 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000820static INT PROFILE_GetString( LPCSTR section, LPCSTR key_name,
Eric Poueched155751999-03-25 13:24:08 +0000821 LPCSTR def_val, LPSTR buffer, UINT len )
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000822{
823 PROFILEKEY *key = NULL;
824
Dmitry Timoshkovfdc78a32000-12-19 19:37:03 +0000825 if(!buffer) return 0;
826
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000827 if (!def_val) def_val = "";
Alexandre Julliard77b99181997-09-14 17:17:23 +0000828 if (key_name && key_name[0])
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000829 {
Alexandre Julliard829fe321998-07-26 14:27:39 +0000830 key = PROFILE_Find( &CurProfile->section, section, key_name, FALSE );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000831 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def_val,
832 len, FALSE );
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000833 TRACE("('%s','%s','%s'): returning '%s'\n",
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000834 section, key_name, def_val, buffer );
835 return strlen( buffer );
836 }
Uwe Bonnesb2ccbb22000-03-04 19:03:15 +0000837 if (key_name && !(key_name[0]))
Andreas Mohr3ac104f2000-09-29 21:04:44 +0000838 /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227 */
Uwe Bonnesb2ccbb22000-03-04 19:03:15 +0000839 return 0;
Andreas Mohradfeec91999-05-22 16:04:57 +0000840 if (section && section[0])
841 return PROFILE_GetSection(CurProfile->section, section, buffer, len,
Alexandre Julliarda845b881998-06-01 10:44:35 +0000842 FALSE, FALSE);
Andreas Mohr3ac104f2000-09-29 21:04:44 +0000843 buffer[0] = '\0';
844 return 0;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000845}
846
847
848/***********************************************************************
849 * PROFILE_SetString
850 *
851 * Set a profile string.
852 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000853static BOOL PROFILE_SetString( LPCSTR section_name, LPCSTR key_name,
Eric Poueched155751999-03-25 13:24:08 +0000854 LPCSTR value )
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000855{
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000856 if (!key_name) /* Delete a whole section */
857 {
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000858 TRACE("('%s')\n", section_name);
Alexandre Julliard829fe321998-07-26 14:27:39 +0000859 CurProfile->changed |= PROFILE_DeleteSection( &CurProfile->section,
860 section_name );
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +0000861 return TRUE; /* Even if PROFILE_DeleteSection() has failed,
862 this is not an error on application's level.*/
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000863 }
864 else if (!value) /* Delete a key */
865 {
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000866 TRACE("('%s','%s')\n",
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000867 section_name, key_name );
Alexandre Julliard829fe321998-07-26 14:27:39 +0000868 CurProfile->changed |= PROFILE_DeleteKey( &CurProfile->section,
869 section_name, key_name );
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +0000870 return TRUE; /* same error handling as above */
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000871 }
872 else /* Set the key value */
873 {
Alexandre Julliard829fe321998-07-26 14:27:39 +0000874 PROFILEKEY *key = PROFILE_Find( &CurProfile->section, section_name,
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000875 key_name, TRUE );
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000876 TRACE("('%s','%s','%s'): \n",
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000877 section_name, key_name, value );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000878 if (!key) return FALSE;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000879 if (key->value)
880 {
Marcus Meissnera6ae5552000-06-13 01:06:22 +0000881 /* strip the leading spaces. We can safely strip \n\r and
882 * friends too, they should not happen here anyway. */
883 while (PROFILE_isspace(*value)) value++;
884
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000885 if (!strcmp( key->value, value ))
886 {
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000887 TRACE(" no change needed\n" );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000888 return TRUE; /* No change needed */
889 }
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000890 TRACE(" replacing '%s'\n", key->value );
Alexandre Julliard90476d62000-02-16 22:47:24 +0000891 HeapFree( GetProcessHeap(), 0, key->value );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000892 }
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000893 else TRACE(" creating key\n" );
Alexandre Julliard5f728ca2001-07-24 21:45:22 +0000894 key->value = HeapAlloc( GetProcessHeap(), 0, strlen(value)+1 );
895 strcpy( key->value, value );
Alexandre Julliard829fe321998-07-26 14:27:39 +0000896 CurProfile->changed = TRUE;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000897 }
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +0000898 return TRUE;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000899}
900
901
902/***********************************************************************
903 * PROFILE_GetWineIniString
904 *
905 * Get a config string from the wine.ini file.
906 */
907int PROFILE_GetWineIniString( const char *section, const char *key_name,
908 const char *def, char *buffer, int len )
909{
Alexandre Julliard00377a72000-02-19 20:50:00 +0000910 char tmp[PROFILE_MAX_LINE_LEN];
911 HKEY hkey;
912 DWORD err;
Eric Poueched155751999-03-25 13:24:08 +0000913
Alexandre Julliard00377a72000-02-19 20:50:00 +0000914 if (!(err = RegOpenKeyA( wine_profile_key, section, &hkey )))
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000915 {
Alexandre Julliard00377a72000-02-19 20:50:00 +0000916 DWORD type;
917 DWORD count = sizeof(tmp);
918 err = RegQueryValueExA( hkey, key_name, 0, &type, tmp, &count );
919 RegCloseKey( hkey );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000920 }
Alexandre Julliard00377a72000-02-19 20:50:00 +0000921 PROFILE_CopyEntry( buffer, err ? def : tmp, len, TRUE );
922 TRACE( "('%s','%s','%s'): returning '%s'\n", section, key_name, def, buffer );
923 return strlen(buffer);
924}
Eric Poueched155751999-03-25 13:24:08 +0000925
Alexandre Julliard00377a72000-02-19 20:50:00 +0000926
927/***********************************************************************
928 * PROFILE_EnumWineIniString
929 *
930 * Get a config string from the wine.ini file.
931 */
932BOOL PROFILE_EnumWineIniString( const char *section, int index,
933 char *name, int name_len, char *buffer, int len )
934{
935 char tmp[PROFILE_MAX_LINE_LEN];
936 HKEY hkey;
937 DWORD err, type;
938 DWORD count = sizeof(tmp);
939
940 if (RegOpenKeyA( wine_profile_key, section, &hkey )) return FALSE;
941 err = RegEnumValueA( hkey, index, name, (DWORD*)&name_len, NULL, &type, tmp, &count );
942 RegCloseKey( hkey );
943 if (!err)
944 {
945 PROFILE_CopyEntry( buffer, tmp, len, TRUE );
946 TRACE( "('%s',%d): returning '%s'='%s'\n", section, index, name, buffer );
947 }
948 return !err;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000949}
950
951
952/***********************************************************************
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000953 * PROFILE_GetWineIniInt
954 *
955 * Get a config integer from the wine.ini file.
956 */
957int PROFILE_GetWineIniInt( const char *section, const char *key_name, int def )
958{
959 char buffer[20];
960 char *p;
961 long result;
962
Alexandre Julliard00377a72000-02-19 20:50:00 +0000963 PROFILE_GetWineIniString( section, key_name, "", buffer, sizeof(buffer) );
964 if (!buffer[0]) return def;
965 result = strtol( buffer, &p, 0 );
966 return (p == buffer) ? 0 /* No digits at all */ : (int)result;
Alexandre Julliardd37eb361997-07-20 16:23:21 +0000967}
968
969
970/******************************************************************************
971 *
972 * int PROFILE_GetWineIniBool(
973 * char const *section,
974 * char const *key_name,
975 * int def )
976 *
977 * Reads a boolean value from the wine.ini file. This function attempts to
978 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
979 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
980 * true. Anything else results in the return of the default value.
981 *
982 * This function uses 1 to indicate true, and 0 for false. You can check
983 * for existence by setting def to something other than 0 or 1 and
984 * examining the return value.
985 */
986int PROFILE_GetWineIniBool(
987 char const *section,
988 char const *key_name,
989 int def )
990{
991 char key_value[2];
992 int retval;
993
994 PROFILE_GetWineIniString(section, key_name, "~", key_value, 2);
995
996 switch(key_value[0]) {
997 case 'n':
998 case 'N':
999 case 'f':
1000 case 'F':
1001 case '0':
1002 retval = 0;
1003 break;
1004
1005 case 'y':
1006 case 'Y':
1007 case 't':
1008 case 'T':
1009 case '1':
1010 retval = 1;
1011 break;
1012
1013 default:
1014 retval = def;
1015 }
1016
Francois Gougete76218d2001-05-09 17:31:31 +00001017 TRACE("(\"%s\", \"%s\", %s), [%c], ret %s.\n", section, key_name,
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001018 def ? "TRUE" : "FALSE", key_value[0],
1019 retval ? "TRUE" : "FALSE");
1020
1021 return retval;
1022}
1023
1024
Alexandre Julliard18f92e71996-07-17 20:02:21 +00001025/***********************************************************************
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001026 * PROFILE_LoadWineIni
1027 *
Chris Morgan4a3d5082001-01-10 22:57:34 +00001028 * Load the old .winerc file.
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001029 */
1030int PROFILE_LoadWineIni(void)
1031{
Alexandre Julliard95153362001-03-23 19:13:23 +00001032 OBJECT_ATTRIBUTES attr;
1033 UNICODE_STRING nameW;
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001034 char buffer[MAX_PATHNAME_LEN];
1035 const char *p;
1036 FILE *f;
Eric Pouech0521a542000-02-20 13:39:42 +00001037 HKEY hKeySW;
Alexandre Julliard6c8d9172000-08-26 04:40:07 +00001038 DWORD disp;
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001039
Alexandre Julliard95153362001-03-23 19:13:23 +00001040 attr.Length = sizeof(attr);
1041 attr.RootDirectory = 0;
1042 attr.ObjectName = &nameW;
1043 attr.Attributes = 0;
1044 attr.SecurityDescriptor = NULL;
1045 attr.SecurityQualityOfService = NULL;
1046
Alexandre Julliard86ff8c02000-04-13 16:10:20 +00001047 /* make sure HKLM\\Software\\Wine\\Wine exists as non-volatile key */
Alexandre Julliard95153362001-03-23 19:13:23 +00001048 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Machine\\Software\\Wine\\Wine" ) ||
1049 NtCreateKey( &hKeySW, KEY_ALL_ACCESS, &attr, 0, NULL, 0, &disp ))
Eric Pouech0521a542000-02-20 13:39:42 +00001050 {
1051 ERR("Cannot create config registry key\n" );
Alexandre Julliard95153362001-03-23 19:13:23 +00001052 ExitProcess( 1 );
Eric Pouech0521a542000-02-20 13:39:42 +00001053 }
Alexandre Julliard95153362001-03-23 19:13:23 +00001054 RtlFreeUnicodeString( &nameW );
1055 NtClose( hKeySW );
1056
1057 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Machine\\Software\\Wine\\Wine\\Config" ) ||
1058 NtCreateKey( &wine_profile_key, KEY_ALL_ACCESS, &attr, 0,
1059 NULL, REG_OPTION_VOLATILE, &disp ))
Alexandre Julliard00377a72000-02-19 20:50:00 +00001060 {
1061 ERR("Cannot create config registry key\n" );
Alexandre Julliard95153362001-03-23 19:13:23 +00001062 ExitProcess( 1 );
Alexandre Julliard00377a72000-02-19 20:50:00 +00001063 }
Alexandre Julliard95153362001-03-23 19:13:23 +00001064 RtlFreeUnicodeString( &nameW );
Eric Poueched155751999-03-25 13:24:08 +00001065
Alexandre Julliard00377a72000-02-19 20:50:00 +00001066 if (!CLIENT_IsBootThread()) return 1; /* already loaded */
1067
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001068 if ((p = getenv( "HOME" )) != NULL)
1069 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001070 lstrcpynA(buffer, p, MAX_PATHNAME_LEN - sizeof(PROFILE_WineIniName));
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001071 strcat( buffer, PROFILE_WineIniName );
1072 if ((f = fopen( buffer, "r" )) != NULL)
1073 {
Francois Gougetbaa9bf91999-12-27 05:24:06 +00001074 lstrcpynA(PROFILE_WineIniUsed,buffer,MAX_PATHNAME_LEN);
Alexandre Julliard00377a72000-02-19 20:50:00 +00001075 goto found;
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001076 }
1077 }
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001078 else WARN("could not get $HOME value for config file.\n" );
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001079
Alexandre Julliard6c8d9172000-08-26 04:40:07 +00001080 if (disp == REG_OPENED_EXISTING_KEY) return 1; /* loaded by the server */
1081
Chris Morgan4a3d5082001-01-10 22:57:34 +00001082 MESSAGE( "Can't open configuration file %s/config\n",get_config_dir() );
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001083 return 0;
Alexandre Julliard00377a72000-02-19 20:50:00 +00001084
1085 found:
Alexandre Julliard6c8d9172000-08-26 04:40:07 +00001086
1087 if (disp == REG_OPENED_EXISTING_KEY)
1088 {
Chris Morgan4a3d5082001-01-10 22:57:34 +00001089 MESSAGE( "Warning: configuration loaded by the server from '%s/config',\n"
1090 " file '%s' was ignored.\n", get_config_dir(), PROFILE_WineIniUsed );
Alexandre Julliard6c8d9172000-08-26 04:40:07 +00001091 fclose( f );
1092 return 1;
1093 }
1094
Alexandre Julliard73be8d12000-12-06 20:25:11 +00001095 /* convert to the new format */
1096 sprintf( buffer, "%s/config", get_config_dir() );
Alexandre Julliard95153362001-03-23 19:13:23 +00001097 convert_config( f, buffer );
Alexandre Julliard00377a72000-02-19 20:50:00 +00001098 fclose( f );
Alexandre Julliard95153362001-03-23 19:13:23 +00001099
1100 MESSAGE( "The '%s' configuration file has been converted\n"
1101 "to the new format and saved as '%s'.\n", PROFILE_WineIniUsed, buffer );
1102 MESSAGE( "You should verify that the contents of the new file are correct,\n"
1103 "and then remove the old one and restart Wine.\n" );
1104 ExitProcess(0);
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001105}
1106
1107
Alexandre Julliard23946ad1997-06-16 17:43:53 +00001108/***********************************************************************
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001109 * PROFILE_UsageWineIni
1110 *
1111 * Explain the wine.ini file to those who don't read documentation.
1112 * Keep below one screenful in length so that error messages above are
1113 * noticed.
1114 */
1115void PROFILE_UsageWineIni(void)
1116{
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001117 MESSAGE("Perhaps you have not properly edited or created "
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001118 "your Wine configuration file.\n");
Gerard Patel151023d2001-01-22 19:27:06 +00001119 MESSAGE("This is '%s/config'\n", get_config_dir());
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001120 /* RTFM, so to say */
1121}
1122
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001123/***********************************************************************
Alexandre Julliard23946ad1997-06-16 17:43:53 +00001124 * PROFILE_GetStringItem
1125 *
1126 * Convenience function that turns a string 'xxx, yyy, zzz' into
1127 * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
1128 */
1129char* PROFILE_GetStringItem( char* start )
1130{
1131 char* lpchX, *lpch;
1132
1133 for (lpchX = start, lpch = NULL; *lpchX != '\0'; lpchX++ )
1134 {
Alexandre Julliard23946ad1997-06-16 17:43:53 +00001135 if( *lpchX == ',' )
1136 {
1137 if( lpch ) *lpch = '\0'; else *lpchX = '\0';
1138 while( *(++lpchX) )
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001139 if( !PROFILE_isspace(*lpchX) ) return lpchX;
Alexandre Julliard23946ad1997-06-16 17:43:53 +00001140 }
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001141 else if( PROFILE_isspace( *lpchX ) && !lpch ) lpch = lpchX;
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001142 else lpch = NULL;
Alexandre Julliard23946ad1997-06-16 17:43:53 +00001143 }
1144 if( lpch ) *lpch = '\0';
1145 return NULL;
1146}
1147
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001148/********************* API functions **********************************/
1149
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001150/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001151 * GetProfileInt (KERNEL.57)
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001152 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001153UINT16 WINAPI GetProfileInt16( LPCSTR section, LPCSTR entry, INT16 def_val )
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001154{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001155 return GetPrivateProfileInt16( section, entry, def_val, "win.ini" );
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001156}
1157
1158
1159/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001160 * GetProfileIntA (KERNEL32.@)
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001161 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001162UINT WINAPI GetProfileIntA( LPCSTR section, LPCSTR entry, INT def_val )
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001163{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001164 return GetPrivateProfileIntA( section, entry, def_val, "win.ini" );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001165}
1166
1167/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001168 * GetProfileIntW (KERNEL32.@)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001169 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001170UINT WINAPI GetProfileIntW( LPCWSTR section, LPCWSTR entry, INT def_val )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001171{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001172 return GetPrivateProfileIntW( section, entry, def_val, wininiW );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001173}
1174
Andreas Mohr3ac104f2000-09-29 21:04:44 +00001175/*
Lionel Ulmerf89722d2001-07-20 17:55:39 +00001176 * if allow_section_name_copy is TRUE, allow the copying :
1177 * - of Section names if 'section' is NULL
1178 * - of Keys in a Section if 'entry' is NULL
1179 * (see MSDN doc for GetPrivateProfileString)
Andreas Mohr3ac104f2000-09-29 21:04:44 +00001180 */
1181static int PROFILE_GetPrivateProfileString( LPCSTR section, LPCSTR entry,
1182 LPCSTR def_val, LPSTR buffer,
1183 UINT16 len, LPCSTR filename,
Lionel Ulmerf89722d2001-07-20 17:55:39 +00001184 BOOL allow_section_name_copy )
Andreas Mohr3ac104f2000-09-29 21:04:44 +00001185{
1186 int ret;
1187 LPSTR pDefVal = NULL;
1188
1189 if (!filename)
1190 filename = "win.ini";
1191
1192 /* strip any trailing ' ' of def_val. */
1193 if (def_val)
1194 {
1195 LPSTR p = (LPSTR)&def_val[strlen(def_val)]; /* even "" works ! */
1196
1197 while (p > def_val)
1198 {
1199 p--;
1200 if ((*p) != ' ')
1201 break;
1202 }
1203 if (*p == ' ') /* ouch, contained trailing ' ' */
1204 {
1205 int len = (int)p - (int)def_val;
1206 pDefVal = HeapAlloc(GetProcessHeap(), 0, len + 1);
1207 strncpy(pDefVal, def_val, len);
1208 pDefVal[len] = '\0';
1209 }
1210 }
1211 if (!pDefVal)
1212 pDefVal = (LPSTR)def_val;
1213
1214 EnterCriticalSection( &PROFILE_CritSect );
1215
1216 if (PROFILE_Open( filename )) {
Lionel Ulmerf89722d2001-07-20 17:55:39 +00001217 if ((allow_section_name_copy) && (section == NULL))
Andreas Mohr3ac104f2000-09-29 21:04:44 +00001218 ret = PROFILE_GetSectionNames(buffer, len);
1219 else
Lionel Ulmerf89722d2001-07-20 17:55:39 +00001220 /* PROFILE_GetString already handles the 'entry == NULL' case */
Andreas Mohr3ac104f2000-09-29 21:04:44 +00001221 ret = PROFILE_GetString( section, entry, pDefVal, buffer, len );
1222 } else {
1223 lstrcpynA( buffer, pDefVal, len );
1224 ret = strlen( buffer );
1225 }
1226
1227 LeaveCriticalSection( &PROFILE_CritSect );
1228
1229 if (pDefVal != def_val) /* allocated */
1230 HeapFree(GetProcessHeap(), 0, pDefVal);
1231
1232 return ret;
1233}
1234
1235/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001236 * GetPrivateProfileString (KERNEL.128)
Andreas Mohr3ac104f2000-09-29 21:04:44 +00001237 */
1238INT16 WINAPI GetPrivateProfileString16( LPCSTR section, LPCSTR entry,
1239 LPCSTR def_val, LPSTR buffer,
1240 UINT16 len, LPCSTR filename )
1241{
1242 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1243 buffer, len, filename, FALSE );
1244}
1245
1246/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001247 * GetPrivateProfileStringA (KERNEL32.@)
Andreas Mohr3ac104f2000-09-29 21:04:44 +00001248 */
1249INT WINAPI GetPrivateProfileStringA( LPCSTR section, LPCSTR entry,
1250 LPCSTR def_val, LPSTR buffer,
1251 UINT len, LPCSTR filename )
1252{
1253 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1254 buffer, len, filename, TRUE );
1255}
1256
1257/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001258 * GetPrivateProfileStringW (KERNEL32.@)
Andreas Mohr3ac104f2000-09-29 21:04:44 +00001259 */
1260INT WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1261 LPCWSTR def_val, LPWSTR buffer,
1262 UINT len, LPCWSTR filename )
1263{
1264 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1265 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1266 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1267 LPSTR def_valA = HEAP_strdupWtoA( GetProcessHeap(), 0, def_val );
1268 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1269 INT ret = GetPrivateProfileStringA( sectionA, entryA, def_valA,
1270 bufferA, len, filenameA );
Alexandre Julliard24a62ab2000-11-28 22:40:56 +00001271 if (len > 0 && !MultiByteToWideChar( CP_ACP, 0, bufferA, -1, buffer, len ))
1272 buffer[len-1] = 0;
Andreas Mohr3ac104f2000-09-29 21:04:44 +00001273 HeapFree( GetProcessHeap(), 0, sectionA );
1274 HeapFree( GetProcessHeap(), 0, entryA );
1275 HeapFree( GetProcessHeap(), 0, filenameA );
1276 HeapFree( GetProcessHeap(), 0, def_valA );
1277 HeapFree( GetProcessHeap(), 0, bufferA);
1278 return ret;
1279}
1280
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001281/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001282 * GetProfileString (KERNEL.58)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001283 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001284INT16 WINAPI GetProfileString16( LPCSTR section, LPCSTR entry, LPCSTR def_val,
Alexandre Julliard642d3131998-07-12 19:29:36 +00001285 LPSTR buffer, UINT16 len )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001286{
Andreas Mohr3ac104f2000-09-29 21:04:44 +00001287 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1288 buffer, len, "win.ini", FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001289}
1290
1291/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001292 * GetProfileStringA (KERNEL32.@)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001293 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001294INT WINAPI GetProfileStringA( LPCSTR section, LPCSTR entry, LPCSTR def_val,
Eric Poueched155751999-03-25 13:24:08 +00001295 LPSTR buffer, UINT len )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001296{
Andreas Mohr3ac104f2000-09-29 21:04:44 +00001297 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1298 buffer, len, "win.ini", TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001299}
1300
1301/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001302 * GetProfileStringW (KERNEL32.@)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001303 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001304INT WINAPI GetProfileStringW( LPCWSTR section, LPCWSTR entry,
Eric Poueched155751999-03-25 13:24:08 +00001305 LPCWSTR def_val, LPWSTR buffer, UINT len )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001306{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001307 return GetPrivateProfileStringW( section, entry, def_val,
Eric Poueched155751999-03-25 13:24:08 +00001308 buffer, len, wininiW );
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001309}
1310
Alexandre Julliard77b99181997-09-14 17:17:23 +00001311/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001312 * WriteProfileString (KERNEL.59)
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001313 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001314BOOL16 WINAPI WriteProfileString16( LPCSTR section, LPCSTR entry,
1315 LPCSTR string )
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001316{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001317 return WritePrivateProfileString16( section, entry, string, "win.ini" );
1318}
1319
1320/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001321 * WriteProfileStringA (KERNEL32.@)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001322 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001323BOOL WINAPI WriteProfileStringA( LPCSTR section, LPCSTR entry,
Eric Poueched155751999-03-25 13:24:08 +00001324 LPCSTR string )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001325{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001326 return WritePrivateProfileStringA( section, entry, string, "win.ini" );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001327}
1328
1329/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001330 * WriteProfileStringW (KERNEL32.@)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001331 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001332BOOL WINAPI WriteProfileStringW( LPCWSTR section, LPCWSTR entry,
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001333 LPCWSTR string )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001334{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001335 return WritePrivateProfileStringW( section, entry, string, wininiW );
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001336}
1337
1338
1339/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001340 * GetPrivateProfileInt (KERNEL.127)
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001341 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001342UINT16 WINAPI GetPrivateProfileInt16( LPCSTR section, LPCSTR entry,
1343 INT16 def_val, LPCSTR filename )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001344{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001345 long result=(long)GetPrivateProfileIntA(section,entry,def_val,filename);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001346
1347 if (result > 65535) return 65535;
1348 if (result >= 0) return (UINT16)result;
1349 if (result < -32768) return -32768;
1350 return (UINT16)(INT16)result;
1351}
1352
1353/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001354 * GetPrivateProfileIntA (KERNEL32.@)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001355 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001356UINT WINAPI GetPrivateProfileIntA( LPCSTR section, LPCSTR entry,
Eric Poueched155751999-03-25 13:24:08 +00001357 INT def_val, LPCSTR filename )
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001358{
1359 char buffer[20];
1360 char *p;
1361 long result;
1362
Andreas Mohr3ac104f2000-09-29 21:04:44 +00001363 PROFILE_GetPrivateProfileString( section, entry, "",
1364 buffer, sizeof(buffer), filename, FALSE );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001365 if (!buffer[0]) return (UINT)def_val;
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001366 result = strtol( buffer, &p, 0 );
1367 if (p == buffer) return 0; /* No digits at all */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001368 return (UINT)result;
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001369}
1370
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001371/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001372 * GetPrivateProfileIntW (KERNEL32.@)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001373 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001374UINT WINAPI GetPrivateProfileIntW( LPCWSTR section, LPCWSTR entry,
Eric Poueched155751999-03-25 13:24:08 +00001375 INT def_val, LPCWSTR filename )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001376{
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +00001377 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1378 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1379 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001380 UINT res = GetPrivateProfileIntA(sectionA, entryA, def_val, filenameA);
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +00001381 HeapFree( GetProcessHeap(), 0, sectionA );
1382 HeapFree( GetProcessHeap(), 0, filenameA );
1383 HeapFree( GetProcessHeap(), 0, entryA );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001384 return res;
1385}
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001386
1387/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001388 * GetPrivateProfileSection (KERNEL.418)
Ulrich Weigand8228bd61999-04-22 09:56:09 +00001389 */
1390INT16 WINAPI GetPrivateProfileSection16( LPCSTR section, LPSTR buffer,
1391 UINT16 len, LPCSTR filename )
1392{
1393 return GetPrivateProfileSectionA( section, buffer, len, filename );
1394}
1395
1396/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001397 * GetPrivateProfileSectionA (KERNEL32.@)
Alexandre Julliard77b99181997-09-14 17:17:23 +00001398 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001399INT WINAPI GetPrivateProfileSectionA( LPCSTR section, LPSTR buffer,
Eric Poueched155751999-03-25 13:24:08 +00001400 DWORD len, LPCSTR filename )
Alexandre Julliard77b99181997-09-14 17:17:23 +00001401{
Eric Poueched155751999-03-25 13:24:08 +00001402 int ret = 0;
1403
1404 EnterCriticalSection( &PROFILE_CritSect );
1405
Alexandre Julliard77b99181997-09-14 17:17:23 +00001406 if (PROFILE_Open( filename ))
Eric Poueched155751999-03-25 13:24:08 +00001407 ret = PROFILE_GetSection(CurProfile->section, section, buffer, len,
1408 FALSE, TRUE);
1409
1410 LeaveCriticalSection( &PROFILE_CritSect );
Alexandre Julliarda845b881998-06-01 10:44:35 +00001411
Marcus Meissner264360f1999-05-08 10:02:05 +00001412 return ret;
Alexandre Julliard77b99181997-09-14 17:17:23 +00001413}
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001414
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001415/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001416 * GetPrivateProfileSectionW (KERNEL32.@)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001417 */
1418
Alexandre Julliarda3960291999-02-26 11:11:13 +00001419INT WINAPI GetPrivateProfileSectionW (LPCWSTR section, LPWSTR buffer,
Eric Poueched155751999-03-25 13:24:08 +00001420 DWORD len, LPCWSTR filename )
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001421
1422{
1423 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1424 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1425 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001426 INT ret = GetPrivateProfileSectionA( sectionA, bufferA, len,
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001427 filenameA );
Marcus Meissner264360f1999-05-08 10:02:05 +00001428 MultiByteToWideChar(CP_ACP,0,bufferA,ret,buffer,len);
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001429 HeapFree( GetProcessHeap(), 0, sectionA );
1430 HeapFree( GetProcessHeap(), 0, filenameA );
1431 HeapFree( GetProcessHeap(), 0, bufferA);
1432 return ret;
1433}
1434
1435/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001436 * GetProfileSection (KERNEL.419)
Ulrich Weigand8228bd61999-04-22 09:56:09 +00001437 */
1438INT16 WINAPI GetProfileSection16( LPCSTR section, LPSTR buffer, UINT16 len )
1439{
1440 return GetPrivateProfileSection16( section, buffer, len, "win.ini" );
1441}
1442
1443/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001444 * GetProfileSectionA (KERNEL32.@)
Ulrich Weigand8228bd61999-04-22 09:56:09 +00001445 */
1446INT WINAPI GetProfileSectionA( LPCSTR section, LPSTR buffer, DWORD len )
1447{
1448 return GetPrivateProfileSectionA( section, buffer, len, "win.ini" );
1449}
1450
1451/***********************************************************************
Patrik Stridvall3ca98232001-06-20 23:03:14 +00001452 * GetProfileSectionW (KERNEL32.@)
Ulrich Weigand8228bd61999-04-22 09:56:09 +00001453 */
1454INT WINAPI GetProfileSectionW( LPCWSTR section, LPWSTR buffer, DWORD len )
1455{
Ulrich Weigand8228bd61999-04-22 09:56:09 +00001456 return GetPrivateProfileSectionW( section, buffer, len, wininiW );
1457}
1458
1459
1460/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001461 * WritePrivateProfileString (KERNEL.129)
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001462 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001463BOOL16 WINAPI WritePrivateProfileString16( LPCSTR section, LPCSTR entry,
1464 LPCSTR string, LPCSTR filename )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001465{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001466 return WritePrivateProfileStringA(section,entry,string,filename);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001467}
1468
1469/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001470 * WritePrivateProfileStringA (KERNEL32.@)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001471 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001472BOOL WINAPI WritePrivateProfileStringA( LPCSTR section, LPCSTR entry,
Eric Poueched155751999-03-25 13:24:08 +00001473 LPCSTR string, LPCSTR filename )
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001474{
Alexandre Julliarde61b7921999-07-31 19:24:11 +00001475 BOOL ret = FALSE;
Eric Poueched155751999-03-25 13:24:08 +00001476
1477 EnterCriticalSection( &PROFILE_CritSect );
1478
Alexandre Julliarde61b7921999-07-31 19:24:11 +00001479 if (PROFILE_Open( filename ))
1480 {
1481 if (!section && !entry && !string)
1482 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1483 else
1484 ret = PROFILE_SetString( section, entry, string );
Eric Poueched155751999-03-25 13:24:08 +00001485 }
1486
1487 LeaveCriticalSection( &PROFILE_CritSect );
Eric Poueched155751999-03-25 13:24:08 +00001488 return ret;
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001489}
1490
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001491/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001492 * WritePrivateProfileStringW (KERNEL32.@)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001493 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001494BOOL WINAPI WritePrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
Eric Poueched155751999-03-25 13:24:08 +00001495 LPCWSTR string, LPCWSTR filename )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001496{
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +00001497 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1498 LPSTR entryA = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
1499 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1500 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001501 BOOL res = WritePrivateProfileStringA( sectionA, entryA,
Eric Poueched155751999-03-25 13:24:08 +00001502 stringA, filenameA );
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +00001503 HeapFree( GetProcessHeap(), 0, sectionA );
1504 HeapFree( GetProcessHeap(), 0, entryA );
1505 HeapFree( GetProcessHeap(), 0, stringA );
1506 HeapFree( GetProcessHeap(), 0, filenameA );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001507 return res;
1508}
1509
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00001510/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001511 * WritePrivateProfileSection (KERNEL.416)
Ulrich Weigand8228bd61999-04-22 09:56:09 +00001512 */
1513BOOL16 WINAPI WritePrivateProfileSection16( LPCSTR section,
1514 LPCSTR string, LPCSTR filename )
1515{
1516 return WritePrivateProfileSectionA( section, string, filename );
1517}
1518
1519/***********************************************************************
Patrik Stridvall3ca98232001-06-20 23:03:14 +00001520 * WritePrivateProfileSectionA (KERNEL32.@)
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00001521 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001522BOOL WINAPI WritePrivateProfileSectionA( LPCSTR section,
Eric Poueched155751999-03-25 13:24:08 +00001523 LPCSTR string, LPCSTR filename )
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00001524{
Rein Klazes7458be02000-01-05 01:42:51 +00001525 BOOL ret = FALSE;
1526 LPSTR p ;
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00001527
Rein Klazes7458be02000-01-05 01:42:51 +00001528 EnterCriticalSection( &PROFILE_CritSect );
1529
1530 if (PROFILE_Open( filename )) {
Marcus Meissner25e74032000-11-26 22:36:19 +00001531 if (!section && !string)
Rein Klazes7458be02000-01-05 01:42:51 +00001532 PROFILE_ReleaseFile(); /* always return FALSE in this case */
Uwe Bonnesd88fbb72000-06-20 20:48:46 +00001533 else if (!string) /* delete the named section*/
1534 ret = PROFILE_SetString(section,NULL,NULL);
Rein Klazes7458be02000-01-05 01:42:51 +00001535 else {
Uwe Bonnesd88fbb72000-06-20 20:48:46 +00001536 PROFILE_DeleteAllKeys(section);
1537 ret = TRUE;
1538 while(*string) {
Alexandre Julliard5f728ca2001-07-24 21:45:22 +00001539 LPSTR buf = HeapAlloc( GetProcessHeap(), 0, strlen(string)+1 );
1540 strcpy( buf, string );
Rein Klazes7458be02000-01-05 01:42:51 +00001541 if((p=strchr( buf, '='))){
1542 *p='\0';
1543 ret = PROFILE_SetString( section, buf, p+1 );
1544
1545 }
1546 HeapFree( GetProcessHeap(), 0, buf );
1547 string += strlen(string)+1;
1548 }
1549
1550 }
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00001551 }
Rein Klazes7458be02000-01-05 01:42:51 +00001552
1553 LeaveCriticalSection( &PROFILE_CritSect );
1554 return ret;
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00001555}
1556
Alexandre Julliarda845b881998-06-01 10:44:35 +00001557/***********************************************************************
Patrik Stridvall3ca98232001-06-20 23:03:14 +00001558 * WritePrivateProfileSectionW (KERNEL32.@)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001559 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001560BOOL WINAPI WritePrivateProfileSectionW( LPCWSTR section,
Eric Poueched155751999-03-25 13:24:08 +00001561 LPCWSTR string, LPCWSTR filename)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001562
1563{
1564 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1565 LPSTR stringA = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
1566 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001567 BOOL res = WritePrivateProfileSectionA( sectionA, stringA, filenameA );
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001568 HeapFree( GetProcessHeap(), 0, sectionA );
1569 HeapFree( GetProcessHeap(), 0, stringA );
1570 HeapFree( GetProcessHeap(), 0, filenameA );
1571 return res;
1572}
1573
Ulrich Weigand8228bd61999-04-22 09:56:09 +00001574/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001575 * WriteProfileSection (KERNEL.417)
Ulrich Weigand8228bd61999-04-22 09:56:09 +00001576 */
1577BOOL16 WINAPI WriteProfileSection16( LPCSTR section, LPCSTR keys_n_values)
1578{
1579 return WritePrivateProfileSection16( section, keys_n_values, "win.ini");
1580}
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001581
1582/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001583 * WriteProfileSectionA (KERNEL32.@)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001584 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001585BOOL WINAPI WriteProfileSectionA( LPCSTR section, LPCSTR keys_n_values)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001586
1587{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001588 return WritePrivateProfileSectionA( section, keys_n_values, "win.ini");
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001589}
1590
1591/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001592 * WriteProfileSectionW (KERNEL32.@)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001593 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001594BOOL WINAPI WriteProfileSectionW( LPCWSTR section, LPCWSTR keys_n_values)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001595{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001596 return (WritePrivateProfileSectionW (section,keys_n_values, wininiW));
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001597}
1598
1599/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001600 * GetPrivateProfileSectionNames (KERNEL.143)
Alexandre Julliarda845b881998-06-01 10:44:35 +00001601 */
1602WORD WINAPI GetPrivateProfileSectionNames16( LPSTR buffer, WORD size,
1603 LPCSTR filename )
1604{
Francois Gouget19b05e52001-08-28 18:39:26 +00001605 return GetPrivateProfileSectionNamesA(buffer,size,filename);
Alexandre Julliarda845b881998-06-01 10:44:35 +00001606}
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001607
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001608
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001609/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001610 * GetProfileSectionNames (KERNEL.142)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001611 */
Francois Gouget19b05e52001-08-28 18:39:26 +00001612WORD WINAPI GetProfileSectionNames16(LPSTR buffer, WORD size)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001613
1614{
Francois Gouget19b05e52001-08-28 18:39:26 +00001615 return GetPrivateProfileSectionNamesA(buffer,size,"win.ini");
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001616}
1617
1618
1619/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001620 * GetPrivateProfileSectionNamesA (KERNEL32.@)
Francois Gouget19b05e52001-08-28 18:39:26 +00001621 *
1622 * Returns the section names contained in the specified file.
1623 * FIXME: Where do we find this file when the path is relative?
1624 * The section names are returned as a list of strings with an extra
1625 * '\0' to mark the end of the list. Except for that the behavior
1626 * depends on the Windows version.
1627 *
1628 * Win95:
1629 * - if the buffer is 0 or 1 character long then it is as if it was of
1630 * infinite length.
1631 * - otherwise, if the buffer is to small only the section names that fit
1632 * are returned.
1633 * - note that this means if the buffer was to small to return even just
1634 * the first section name then a single '\0' will be returned.
1635 * - the return value is the number of characters written in the buffer,
1636 * except if the buffer was too smal in which case len-2 is returned
1637 *
1638 * Win2000:
1639 * - if the buffer is 0, 1 or 2 characters long then it is filled with
1640 * '\0' and the return value is 0
1641 * - otherwise if the buffer is too small then the first section name that
1642 * does not fit is truncated so that the string list can be terminated
1643 * correctly (double '\0')
1644 * - the return value is the number of characters written in the buffer
1645 * except for the trailing '\0'. If the buffer is too small, then the
1646 * return value is len-2
1647 * - Win2000 has a bug that triggers when the section names and the
1648 * trailing '\0' fit exactly in the buffer. In that case the trailing
1649 * '\0' is missing.
1650 *
1651 * Wine implements the observed Win2000 behavior (except for the bug).
1652 *
1653 * Note that when the buffer is big enough then the return value may be any
1654 * value between 1 and len-1 (or len in Win95), including len-2.
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001655 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001656DWORD WINAPI GetPrivateProfileSectionNamesA( LPSTR buffer, DWORD size,
Eric Poueched155751999-03-25 13:24:08 +00001657 LPCSTR filename)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001658
1659{
Francois Gouget19b05e52001-08-28 18:39:26 +00001660 DWORD ret = 0;
1661
1662 EnterCriticalSection( &PROFILE_CritSect );
1663
1664 if (PROFILE_Open( filename ))
1665 ret = PROFILE_GetSectionNames(buffer, size);
1666
1667 LeaveCriticalSection( &PROFILE_CritSect );
1668
1669 return ret;
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001670}
1671
1672
1673/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001674 * GetPrivateProfileSectionNamesW (KERNEL32.@)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001675 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001676DWORD WINAPI GetPrivateProfileSectionNamesW( LPWSTR buffer, DWORD size,
Eric Poueched155751999-03-25 13:24:08 +00001677 LPCWSTR filename)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001678
1679{
Francois Gouget19b05e52001-08-28 18:39:26 +00001680 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1681 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, size);
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001682
Francois Gouget19b05e52001-08-28 18:39:26 +00001683 INT ret = GetPrivateProfileSectionNamesA(bufferA, size, filenameA);
1684 if (size > 0 && !MultiByteToWideChar( CP_ACP, 0, bufferA, -1, buffer, size ))
Alexandre Julliard24a62ab2000-11-28 22:40:56 +00001685 buffer[size-1] = 0;
Francois Gouget19b05e52001-08-28 18:39:26 +00001686 HeapFree( GetProcessHeap(), 0, bufferA);
1687 HeapFree( GetProcessHeap(), 0, filenameA );
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001688
Francois Gouget19b05e52001-08-28 18:39:26 +00001689 return ret;
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001690}
1691
Ulrich Weigand8228bd61999-04-22 09:56:09 +00001692/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001693 * GetPrivateProfileStruct (KERNEL.407)
Ulrich Weigand8228bd61999-04-22 09:56:09 +00001694 */
1695BOOL16 WINAPI GetPrivateProfileStruct16(LPCSTR section, LPCSTR key,
1696 LPVOID buf, UINT16 len, LPCSTR filename)
1697{
1698 return GetPrivateProfileStructA( section, key, buf, len, filename );
1699}
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001700
1701/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001702 * GetPrivateProfileStructA (KERNEL32.@)
Andreas Mohr17b1f462000-01-30 21:15:14 +00001703 *
1704 * Should match Win95's behaviour pretty much
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001705 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001706BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key,
Eric Poueched155751999-03-25 13:24:08 +00001707 LPVOID buf, UINT len, LPCSTR filename)
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001708{
Eric Poueched155751999-03-25 13:24:08 +00001709 BOOL ret = FALSE;
1710
1711 EnterCriticalSection( &PROFILE_CritSect );
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001712
1713 if (PROFILE_Open( filename )) {
Eric Poueched155751999-03-25 13:24:08 +00001714 PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE);
1715 if (k) {
Andreas Mohr17b1f462000-01-30 21:15:14 +00001716 TRACE("value (at %p): '%s'\n", k->value, k->value);
1717 if (((strlen(k->value) - 2) / 2) == len)
1718 {
1719 LPSTR end, p;
1720 BOOL valid = TRUE;
1721 CHAR c;
1722 DWORD chksum = 0;
1723
1724 end = k->value + strlen(k->value); /* -> '\0' */
1725 /* check for invalid chars in ASCII coded hex string */
1726 for (p=k->value; p < end; p++)
1727 {
1728 if (!isxdigit(*p))
1729 {
1730 WARN("invalid char '%c' in file '%s'->'[%s]'->'%s' !\n",
1731 *p, filename, section, key);
1732 valid = FALSE;
1733 break;
1734 }
1735 }
1736 if (valid)
1737 {
1738 BOOL highnibble = TRUE;
1739 BYTE b = 0, val;
1740 LPBYTE binbuf = (LPBYTE)buf;
1741
1742 end -= 2; /* don't include checksum in output data */
1743 /* translate ASCII hex format into binary data */
1744 for (p=k->value; p < end; p++)
1745 {
1746 c = toupper(*p);
1747 val = (c > '9') ?
1748 (c - 'A' + 10) : (c - '0');
1749
1750 if (highnibble)
1751 b = val << 4;
1752 else
1753 {
1754 b += val;
1755 *binbuf++ = b; /* feed binary data into output */
1756 chksum += b; /* calculate checksum */
1757 }
1758 highnibble ^= 1; /* toggle */
1759 }
1760 /* retrieve stored checksum value */
1761 c = toupper(*p++);
1762 b = ( (c > '9') ? (c - 'A' + 10) : (c - '0') ) << 4;
1763 c = toupper(*p);
1764 b += (c > '9') ? (c - 'A' + 10) : (c - '0');
1765 if (b == (chksum & 0xff)) /* checksums match ? */
1766 ret = TRUE;
1767 }
1768 }
Eric Poueched155751999-03-25 13:24:08 +00001769 }
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001770 }
Eric Poueched155751999-03-25 13:24:08 +00001771 LeaveCriticalSection( &PROFILE_CritSect );
1772
Andreas Mohr17b1f462000-01-30 21:15:14 +00001773 return ret;
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001774}
1775
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001776/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001777 * GetPrivateProfileStructW (KERNEL32.@)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001778 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001779BOOL WINAPI GetPrivateProfileStructW (LPCWSTR section, LPCWSTR key,
Eric Poueched155751999-03-25 13:24:08 +00001780 LPVOID buffer, UINT len, LPCWSTR filename)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001781{
1782 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1783 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1784 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
1785 LPSTR bufferA = HeapAlloc( GetProcessHeap(), 0, len );
1786
Alexandre Julliarda3960291999-02-26 11:11:13 +00001787 INT ret = GetPrivateProfileStructA( sectionA, keyA, bufferA,
Eric Poueched155751999-03-25 13:24:08 +00001788 len, filenameA );
Alexandre Julliard24a62ab2000-11-28 22:40:56 +00001789 if (len > 0 && !MultiByteToWideChar( CP_ACP, 0, bufferA, -1, buffer, len ))
1790 ((LPWSTR)buffer)[len-1] = 0;
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001791 HeapFree( GetProcessHeap(), 0, bufferA);
1792 HeapFree( GetProcessHeap(), 0, sectionA );
1793 HeapFree( GetProcessHeap(), 0, keyA );
1794 HeapFree( GetProcessHeap(), 0, filenameA );
1795
1796 return ret;
1797}
1798
1799
1800
Ulrich Weigand8228bd61999-04-22 09:56:09 +00001801/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001802 * WritePrivateProfileStruct (KERNEL.406)
Ulrich Weigand8228bd61999-04-22 09:56:09 +00001803 */
1804BOOL16 WINAPI WritePrivateProfileStruct16 (LPCSTR section, LPCSTR key,
1805 LPVOID buf, UINT16 bufsize, LPCSTR filename)
1806{
1807 return WritePrivateProfileStructA( section, key, buf, bufsize, filename );
1808}
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001809
1810/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001811 * WritePrivateProfileStructA (KERNEL32.@)
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001812 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001813BOOL WINAPI WritePrivateProfileStructA (LPCSTR section, LPCSTR key,
Alexandre Julliarde61b7921999-07-31 19:24:11 +00001814 LPVOID buf, UINT bufsize, LPCSTR filename)
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001815{
Alexandre Julliarde61b7921999-07-31 19:24:11 +00001816 BOOL ret = FALSE;
Andreas Mohr17b1f462000-01-30 21:15:14 +00001817 LPBYTE binbuf;
1818 LPSTR outstring, p;
1819 DWORD sum = 0;
Alexandre Julliarde61b7921999-07-31 19:24:11 +00001820
1821 if (!section && !key && !buf) /* flush the cache */
1822 return WritePrivateProfileStringA( NULL, NULL, NULL, filename );
Eric Poueched155751999-03-25 13:24:08 +00001823
Andreas Mohr17b1f462000-01-30 21:15:14 +00001824 /* allocate string buffer for hex chars + checksum hex char + '\0' */
Alexandre Julliard90476d62000-02-16 22:47:24 +00001825 outstring = HeapAlloc( GetProcessHeap(), 0, bufsize*2 + 2 + 1);
Andreas Mohr17b1f462000-01-30 21:15:14 +00001826 p = outstring;
1827 for (binbuf = (LPBYTE)buf; binbuf < (LPBYTE)buf+bufsize; binbuf++) {
1828 *p++ = hex[*binbuf >> 4];
1829 *p++ = hex[*binbuf & 0xf];
1830 sum += *binbuf;
1831 }
1832 /* checksum is sum & 0xff */
1833 *p++ = hex[(sum & 0xf0) >> 4];
1834 *p++ = hex[sum & 0xf];
1835 *p++ = '\0';
1836
Eric Poueched155751999-03-25 13:24:08 +00001837 EnterCriticalSection( &PROFILE_CritSect );
1838
Alexandre Julliarde61b7921999-07-31 19:24:11 +00001839 if (PROFILE_Open( filename ))
Andreas Mohr17b1f462000-01-30 21:15:14 +00001840 ret = PROFILE_SetString( section, key, outstring );
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001841
Eric Poueched155751999-03-25 13:24:08 +00001842 LeaveCriticalSection( &PROFILE_CritSect );
1843
Alexandre Julliard90476d62000-02-16 22:47:24 +00001844 HeapFree( GetProcessHeap(), 0, outstring );
Andreas Mohr17b1f462000-01-30 21:15:14 +00001845
Eric Poueched155751999-03-25 13:24:08 +00001846 return ret;
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001847}
1848
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001849/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001850 * WritePrivateProfileStructW (KERNEL32.@)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001851 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001852BOOL WINAPI WritePrivateProfileStructW (LPCWSTR section, LPCWSTR key,
Eric Poueched155751999-03-25 13:24:08 +00001853 LPVOID buf, UINT bufsize, LPCWSTR filename)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001854{
1855 LPSTR sectionA = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
1856 LPSTR keyA = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
1857 LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001858 INT ret = WritePrivateProfileStructA( sectionA, keyA, buf, bufsize,
Eric Poueched155751999-03-25 13:24:08 +00001859 filenameA );
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001860 HeapFree( GetProcessHeap(), 0, sectionA );
1861 HeapFree( GetProcessHeap(), 0, keyA );
1862 HeapFree( GetProcessHeap(), 0, filenameA );
1863
1864 return ret;
1865}
1866
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001867
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001868/***********************************************************************
1869 * WriteOutProfiles (KERNEL.315)
1870 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001871void WINAPI WriteOutProfiles16(void)
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001872{
Eric Poueched155751999-03-25 13:24:08 +00001873 EnterCriticalSection( &PROFILE_CritSect );
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001874 PROFILE_FlushFile();
Eric Poueched155751999-03-25 13:24:08 +00001875 LeaveCriticalSection( &PROFILE_CritSect );
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001876}
Marcus Meissner9b4fcf71999-12-04 04:19:55 +00001877
1878/***********************************************************************
Patrik Stridvall044855c2001-07-11 18:56:41 +00001879 * CloseProfileUserMapping (KERNEL32.@)
Marcus Meissner9b4fcf71999-12-04 04:19:55 +00001880 */
1881BOOL WINAPI CloseProfileUserMapping(void) {
1882 FIXME("(), stub!\n");
1883 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1884 return FALSE;
1885}