blob: 7005076c1a03ee843e8b5fe0690749bcbebcea33 [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
Alexandre Julliard0799c1a2002-03-09 23:29:33 +00006 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Alexandre Julliard7e56f681996-01-31 19:02:28 +000020 */
21
Patrik Stridvall43255542002-08-09 01:07:29 +000022#include "config.h"
Patrik Stridvall51e6c0c2002-08-31 19:04:14 +000023#include "wine/port.h"
Patrik Stridvall43255542002-08-09 01:07:29 +000024
Alexandre Julliard7e56f681996-01-31 19:02:28 +000025#include <ctype.h>
Alexandre Julliard73be8d12000-12-06 20:25:11 +000026#include <fcntl.h>
Alexandre Julliard02ed4c21996-03-02 19:34:10 +000027#include <stdlib.h>
Alexandre Julliard7e56f681996-01-31 19:02:28 +000028#include <string.h>
Jeremy Whited3e22d92000-02-10 19:03:02 +000029#include <stdio.h>
Alexandre Julliard829fe321998-07-26 14:27:39 +000030#include <sys/stat.h>
Alexandre Julliard647876e2000-01-25 01:35:01 +000031#include <sys/types.h>
Patrik Stridvalld016f812002-08-17 00:43:16 +000032#ifdef HAVE_UNISTD_H
33# include <unistd.h>
34#endif
Alexandre Julliard829fe321998-07-26 14:27:39 +000035
Alexandre Julliard24a62ab2000-11-28 22:40:56 +000036#include "windef.h"
Marcus Meissner317af321999-02-17 13:51:06 +000037#include "winbase.h"
Alexandre Julliard24a62ab2000-11-28 22:40:56 +000038#include "winnls.h"
Marcus Meissner9b4fcf71999-12-04 04:19:55 +000039#include "winerror.h"
Patrik Stridvall9c1de6d2002-09-12 22:07:02 +000040#include "winternl.h"
Marcus Meissner317af321999-02-17 13:51:06 +000041#include "wine/winbase16.h"
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +000042#include "drive.h"
Alexandre Julliardc6c09441997-01-12 18:32:19 +000043#include "file.h"
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +000044#include "heap.h"
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +000045#include "wine/unicode.h"
Alexandre Julliard37e95032001-07-19 00:39:09 +000046#include "wine/server.h"
Alexandre Julliard4144b5b2002-06-20 23:21:27 +000047#include "wine/library.h"
48#include "wine/debug.h"
Alexandre Julliard7e56f681996-01-31 19:02:28 +000049
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000050WINE_DEFAULT_DEBUG_CHANNEL(profile);
Patrik Stridvallb4b9fae1999-04-19 14:56:29 +000051
Alexandre Julliard7e56f681996-01-31 19:02:28 +000052typedef struct tagPROFILEKEY
53{
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +000054 WCHAR *value;
Alexandre Julliard7e56f681996-01-31 19:02:28 +000055 struct tagPROFILEKEY *next;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +000056 WCHAR name[1];
Alexandre Julliard7e56f681996-01-31 19:02:28 +000057} PROFILEKEY;
58
59typedef struct tagPROFILESECTION
60{
Alexandre Julliard7e56f681996-01-31 19:02:28 +000061 struct tagPROFILEKEY *key;
62 struct tagPROFILESECTION *next;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +000063 WCHAR name[1];
Alexandre Julliard5f728ca2001-07-24 21:45:22 +000064} PROFILESECTION;
Alexandre Julliard7e56f681996-01-31 19:02:28 +000065
66
67typedef struct
68{
Eric Poueched155751999-03-25 13:24:08 +000069 BOOL changed;
Alexandre Julliard7e56f681996-01-31 19:02:28 +000070 PROFILESECTION *section;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +000071 WCHAR *dos_name;
Alexandre Julliardc6c09441997-01-12 18:32:19 +000072 char *unix_name;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +000073 WCHAR *filename;
Alexandre Julliard829fe321998-07-26 14:27:39 +000074 time_t mtime;
Alexandre Julliard7e56f681996-01-31 19:02:28 +000075} PROFILE;
76
77
Alexandre Julliard829fe321998-07-26 14:27:39 +000078#define N_CACHED_PROFILES 10
79
80/* Cached profile files */
81static PROFILE *MRUProfile[N_CACHED_PROFILES]={NULL};
82
83#define CurProfile (MRUProfile[0])
Alexandre Julliard7e56f681996-01-31 19:02:28 +000084
Alexandre Julliard7e56f681996-01-31 19:02:28 +000085#define PROFILE_MAX_LINE_LEN 1024
86
Alexandre Julliard7e56f681996-01-31 19:02:28 +000087/* Check for comments in profile */
88#define IS_ENTRY_COMMENT(str) ((str)[0] == ';')
89
Stefan Leichterb5695082003-03-23 20:03:13 +000090static const WCHAR emptystringW[] = {0};
Alexandre Julliard00377a72000-02-19 20:50:00 +000091static const WCHAR wininiW[] = { 'w','i','n','.','i','n','i',0 };
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000092
Alexandre Julliard301df6b2001-08-16 18:12:56 +000093static CRITICAL_SECTION PROFILE_CritSect = CRITICAL_SECTION_INIT("PROFILE_CritSect");
Eric Poueched155751999-03-25 13:24:08 +000094
Andreas Mohr17b1f462000-01-30 21:15:14 +000095static const char hex[16] = "0123456789ABCDEF";
Alexandre Julliard647876e2000-01-25 01:35:01 +000096
97/***********************************************************************
Alexandre Julliard7e56f681996-01-31 19:02:28 +000098 * PROFILE_CopyEntry
99 *
100 * Copy the content of an entry into a buffer, removing quotes, and possibly
101 * translating environment variables.
102 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000103static void PROFILE_CopyEntry( LPWSTR buffer, LPCWSTR value, int len,
104 int handle_env, BOOL strip_quote )
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000105{
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000106 WCHAR quote = '\0';
107 LPCWSTR p;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000108
Dmitry Timoshkovfdc78a32000-12-19 19:37:03 +0000109 if(!buffer) return;
110
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000111 if (strip_quote && ((*value == '\'') || (*value == '\"')))
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000112 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000113 if (value[1] && (value[strlenW(value)-1] == *value)) quote = *value++;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000114 }
115
116 if (!handle_env)
117 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000118 lstrcpynW( buffer, value, len );
119 if (quote && (len >= strlenW(value))) buffer[strlenW(buffer)-1] = '\0';
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000120 return;
121 }
122
123 for (p = value; (*p && (len > 1)); *buffer++ = *p++, len-- )
124 {
125 if ((*p == '$') && (p[1] == '{'))
126 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000127 WCHAR env_val[1024];
128 LPCWSTR p2 = strchrW( p, '}' );
129 int copy_len;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000130 if (!p2) continue; /* ignore it */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000131 copy_len = min( 1024, (int)(p2-p)-1 );
132 strncpyW(env_val, p + 2, copy_len );
133 env_val[copy_len - 1] = 0; /* ensure 0 termination */
134 *buffer = 0;
135 if (GetEnvironmentVariableW( env_val, buffer, len))
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000136 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000137 copy_len = strlenW( buffer );
138 buffer += copy_len;
139 len -= copy_len;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000140 }
141 p = p2 + 1;
142 }
143 }
Eric Pouechf54c95f1999-10-31 17:32:57 +0000144 if (quote && (len > 1)) buffer--;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000145 *buffer = '\0';
146}
147
148
149/***********************************************************************
150 * PROFILE_Save
151 *
152 * Save a profile tree to a file.
153 */
154static void PROFILE_Save( FILE *file, PROFILESECTION *section )
155{
156 PROFILEKEY *key;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000157 char buffer[PROFILE_MAX_LINE_LEN];
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000158
159 for ( ; section; section = section->next)
160 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000161 if (section->name[0])
162 {
163 WideCharToMultiByte(CP_ACP, 0, section->name, -1, buffer, sizeof(buffer), NULL, NULL);
164 fprintf( file, "\r\n[%s]\r\n", buffer );
165 }
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000166 for (key = section->key; key; key = key->next)
167 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000168 WideCharToMultiByte(CP_ACP, 0, key->name, -1, buffer, sizeof(buffer), NULL, NULL);
169 fprintf( file, "%s", buffer );
170 if (key->value)
171 {
172 WideCharToMultiByte(CP_ACP, 0, key->value, -1, buffer, sizeof(buffer), NULL, NULL);
173 fprintf( file, "=%s", buffer );
174 }
Alexandre Julliard7d654eb1996-02-25 11:36:22 +0000175 fprintf( file, "\r\n" );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000176 }
177 }
178}
179
180
181/***********************************************************************
182 * PROFILE_Free
183 *
184 * Free a profile tree.
185 */
186static void PROFILE_Free( PROFILESECTION *section )
187{
188 PROFILESECTION *next_section;
189 PROFILEKEY *key, *next_key;
190
191 for ( ; section; section = next_section)
192 {
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000193 for (key = section->key; key; key = next_key)
194 {
195 next_key = key->next;
Alexandre Julliard90476d62000-02-16 22:47:24 +0000196 if (key->value) HeapFree( GetProcessHeap(), 0, key->value );
197 HeapFree( GetProcessHeap(), 0, key );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000198 }
199 next_section = section->next;
Alexandre Julliard90476d62000-02-16 22:47:24 +0000200 HeapFree( GetProcessHeap(), 0, section );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000201 }
202}
203
Andreas Mohr17b1f462000-01-30 21:15:14 +0000204static inline int PROFILE_isspace(char c)
205{
Alexandre Julliardf90efa91998-06-14 15:24:15 +0000206 if (isspace(c)) return 1;
207 if (c=='\r' || c==0x1a) return 1;
208 /* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */
209 return 0;
210}
211
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000212
213/***********************************************************************
214 * PROFILE_Load
215 *
216 * Load a profile tree from a file.
217 */
218static PROFILESECTION *PROFILE_Load( FILE *file )
219{
220 char buffer[PROFILE_MAX_LINE_LEN];
221 char *p, *p2;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000222 int line = 0, len;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000223 PROFILESECTION *section, *first_section;
Alexandre Julliard642d3131998-07-12 19:29:36 +0000224 PROFILESECTION **next_section;
225 PROFILEKEY *key, *prev_key, **next_key;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000226
Dimitrie O. Paunabdbced2000-04-29 14:20:28 +0000227 first_section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) );
Alexandre Julliard5f728ca2001-07-24 21:45:22 +0000228 if(first_section == NULL) return NULL;
229 first_section->name[0] = 0;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000230 first_section->key = NULL;
231 first_section->next = NULL;
Alexandre Julliard642d3131998-07-12 19:29:36 +0000232 next_section = &first_section->next;
233 next_key = &first_section->key;
234 prev_key = NULL;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000235
236 while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
237 {
238 line++;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000239 p = buffer;
Alexandre Julliardf90efa91998-06-14 15:24:15 +0000240 while (*p && PROFILE_isspace(*p)) p++;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000241 if (*p == '[') /* section start */
242 {
243 if (!(p2 = strrchr( p, ']' )))
244 {
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000245 WARN("Invalid section header at line %d: '%s'\n",
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000246 line, p );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000247 }
248 else
249 {
250 *p2 = '\0';
251 p++;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000252 len = strlen(p);
253 if (!(section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) + len * sizeof(WCHAR) )))
Alexandre Julliard5f728ca2001-07-24 21:45:22 +0000254 break;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000255 MultiByteToWideChar(CP_ACP, 0, p, -1, section->name, len + 1);
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000256 section->key = NULL;
257 section->next = NULL;
Alexandre Julliard642d3131998-07-12 19:29:36 +0000258 *next_section = section;
259 next_section = &section->next;
260 next_key = &section->key;
261 prev_key = NULL;
Alexandre Julliard829fe321998-07-26 14:27:39 +0000262
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000263 TRACE("New section: %s\n", debugstr_w(section->name));
Alexandre Julliard829fe321998-07-26 14:27:39 +0000264
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000265 continue;
266 }
267 }
Alexandre Julliard829fe321998-07-26 14:27:39 +0000268
269 p2=p+strlen(p) - 1;
270 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
271
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000272 if ((p2 = strchr( p, '=' )) != NULL)
273 {
274 char *p3 = p2 - 1;
Alexandre Julliardf90efa91998-06-14 15:24:15 +0000275 while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000276 *p2++ = '\0';
Alexandre Julliardf90efa91998-06-14 15:24:15 +0000277 while (*p2 && PROFILE_isspace(*p2)) p2++;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000278 }
Alexandre Julliard642d3131998-07-12 19:29:36 +0000279
280 if(*p || !prev_key || *prev_key->name)
Dimitrie O. Paunabdbced2000-04-29 14:20:28 +0000281 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000282 len = strlen(p);
283 if (!(key = HeapAlloc( GetProcessHeap(), 0, sizeof(*key) + len * sizeof(WCHAR) ))) break;
284 MultiByteToWideChar(CP_ACP, 0, p, -1, key->name, len + 1);
Alexandre Julliard5f728ca2001-07-24 21:45:22 +0000285 if (p2)
286 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000287 len = strlen(p2) + 1;
288 key->value = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
289 MultiByteToWideChar(CP_ACP, 0, p2, -1, key->value, len);
Alexandre Julliard5f728ca2001-07-24 21:45:22 +0000290 }
291 else key->value = NULL;
292
Alexandre Julliard642d3131998-07-12 19:29:36 +0000293 key->next = NULL;
294 *next_key = key;
295 next_key = &key->next;
296 prev_key = key;
297
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000298 TRACE("New key: name=%s, value=%s\n",
299 debugstr_w(key->name), key->value ? debugstr_w(key->value) : "(none)");
Dimitrie O. Paunabdbced2000-04-29 14:20:28 +0000300 }
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000301 }
302 return first_section;
303}
304
Alexandre Julliard00377a72000-02-19 20:50:00 +0000305
306/***********************************************************************
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000307 * PROFILE_DeleteSection
308 *
309 * Delete a section from a profile tree.
310 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000311static BOOL PROFILE_DeleteSection( PROFILESECTION **section, LPCWSTR name )
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000312{
313 while (*section)
314 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000315 if ((*section)->name[0] && !strcmpiW( (*section)->name, name ))
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000316 {
317 PROFILESECTION *to_del = *section;
318 *section = to_del->next;
319 to_del->next = NULL;
320 PROFILE_Free( to_del );
321 return TRUE;
322 }
323 section = &(*section)->next;
324 }
325 return FALSE;
326}
327
328
329/***********************************************************************
330 * PROFILE_DeleteKey
331 *
332 * Delete a key from a profile tree.
333 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000334static BOOL PROFILE_DeleteKey( PROFILESECTION **section,
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000335 LPCWSTR section_name, LPCWSTR key_name )
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000336{
337 while (*section)
338 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000339 if ((*section)->name[0] && !strcmpiW( (*section)->name, section_name ))
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000340 {
341 PROFILEKEY **key = &(*section)->key;
342 while (*key)
343 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000344 if (!strcmpiW( (*key)->name, key_name ))
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000345 {
346 PROFILEKEY *to_del = *key;
347 *key = to_del->next;
Alexandre Julliard90476d62000-02-16 22:47:24 +0000348 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
349 HeapFree( GetProcessHeap(), 0, to_del );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000350 return TRUE;
351 }
352 key = &(*key)->next;
353 }
354 }
355 section = &(*section)->next;
356 }
357 return FALSE;
358}
359
360
361/***********************************************************************
Uwe Bonnesd88fbb72000-06-20 20:48:46 +0000362 * PROFILE_DeleteAllKeys
363 *
364 * Delete all keys from a profile tree.
365 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000366void PROFILE_DeleteAllKeys( LPCWSTR section_name)
Uwe Bonnesd88fbb72000-06-20 20:48:46 +0000367{
368 PROFILESECTION **section= &CurProfile->section;
369 while (*section)
370 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000371 if ((*section)->name[0] && !strcmpiW( (*section)->name, section_name ))
Uwe Bonnesd88fbb72000-06-20 20:48:46 +0000372 {
373 PROFILEKEY **key = &(*section)->key;
374 while (*key)
375 {
376 PROFILEKEY *to_del = *key;
377 *key = to_del->next;
Uwe Bonnesd88fbb72000-06-20 20:48:46 +0000378 if (to_del->value) HeapFree( GetProcessHeap(), 0, to_del->value);
379 HeapFree( GetProcessHeap(), 0, to_del );
380 CurProfile->changed =TRUE;
381 }
382 }
383 section = &(*section)->next;
384 }
385}
386
387
388/***********************************************************************
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000389 * PROFILE_Find
390 *
391 * Find a key in a profile tree, optionally creating it.
392 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000393static PROFILEKEY *PROFILE_Find( PROFILESECTION **section, LPCWSTR section_name,
394 LPCWSTR key_name, BOOL create, BOOL create_always )
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000395{
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000396 LPCWSTR p;
Andreas Mohr17b1f462000-01-30 21:15:14 +0000397 int seclen, keylen;
398
399 while (PROFILE_isspace(*section_name)) section_name++;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000400 p = section_name + strlenW(section_name) - 1;
Andreas Mohr17b1f462000-01-30 21:15:14 +0000401 while ((p > section_name) && PROFILE_isspace(*p)) p--;
402 seclen = p - section_name + 1;
Vincent Béron9a624912002-05-31 23:06:46 +0000403
Andreas Mohr17b1f462000-01-30 21:15:14 +0000404 while (PROFILE_isspace(*key_name)) key_name++;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000405 p = key_name + strlenW(key_name) - 1;
Andreas Mohr17b1f462000-01-30 21:15:14 +0000406 while ((p > key_name) && PROFILE_isspace(*p)) p--;
407 keylen = p - key_name + 1;
408
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000409 while (*section)
410 {
Alexandre Julliard5f728ca2001-07-24 21:45:22 +0000411 if ( ((*section)->name[0])
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000412 && (!(strncmpiW( (*section)->name, section_name, seclen )))
Gerhard Gruber024a0ac2002-02-05 19:44:54 +0000413 && (((*section)->name)[seclen] == '\0') )
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000414 {
415 PROFILEKEY **key = &(*section)->key;
Gerhard Gruber024a0ac2002-02-05 19:44:54 +0000416
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000417 while (*key)
418 {
Gerhard Gruber024a0ac2002-02-05 19:44:54 +0000419 /* If create_always is FALSE then we check if the keyname already exists.
420 * Otherwise we add it regardless of its existence, to allow
421 * keys to be added more then once in some cases.
422 */
423 if(!create_always)
424 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000425 if ( (!(strncmpiW( (*key)->name, key_name, keylen )))
Gerhard Gruber024a0ac2002-02-05 19:44:54 +0000426 && (((*key)->name)[keylen] == '\0') )
427 return *key;
428 }
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000429 key = &(*key)->next;
430 }
431 if (!create) return NULL;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000432 if (!(*key = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) + strlenW(key_name) * sizeof(WCHAR) )))
Alexandre Julliard5f728ca2001-07-24 21:45:22 +0000433 return NULL;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000434 strcpyW( (*key)->name, key_name );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000435 (*key)->value = NULL;
436 (*key)->next = NULL;
437 return *key;
438 }
439 section = &(*section)->next;
440 }
441 if (!create) return NULL;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000442 *section = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILESECTION) + strlenW(section_name) * sizeof(WCHAR) );
Dimitrie O. Paunabdbced2000-04-29 14:20:28 +0000443 if(*section == NULL) return NULL;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000444 strcpyW( (*section)->name, section_name );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000445 (*section)->next = NULL;
Alexandre Julliard5f728ca2001-07-24 21:45:22 +0000446 if (!((*section)->key = HeapAlloc( GetProcessHeap(), 0,
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000447 sizeof(PROFILEKEY) + strlenW(key_name) * sizeof(WCHAR) )))
Dimitrie O. Paunabdbced2000-04-29 14:20:28 +0000448 {
Alexandre Julliard5f728ca2001-07-24 21:45:22 +0000449 HeapFree(GetProcessHeap(), 0, *section);
450 return NULL;
Dimitrie O. Paunabdbced2000-04-29 14:20:28 +0000451 }
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000452 strcpyW( (*section)->key->name, key_name );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000453 (*section)->key->value = NULL;
454 (*section)->key->next = NULL;
455 return (*section)->key;
456}
457
458
459/***********************************************************************
460 * PROFILE_FlushFile
461 *
462 * Flush the current profile to disk if changed.
463 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000464static BOOL PROFILE_FlushFile(void)
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000465{
466 char *p, buffer[MAX_PATHNAME_LEN];
467 const char *unix_name;
468 FILE *file = NULL;
Alexandre Julliard829fe321998-07-26 14:27:39 +0000469 struct stat buf;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000470
Alexandre Julliard829fe321998-07-26 14:27:39 +0000471 if(!CurProfile)
472 {
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000473 WARN("No current profile!\n");
Alexandre Julliard829fe321998-07-26 14:27:39 +0000474 return FALSE;
475 }
476
477 if (!CurProfile->changed || !CurProfile->dos_name) return TRUE;
478 if (!(unix_name = CurProfile->unix_name) || !(file = fopen(unix_name, "w")))
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000479 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000480 int drive = toupperW(CurProfile->dos_name[0]) - 'A';
Dmitry Timoshkovdb45e1e2002-11-13 19:47:22 +0000481 WCHAR *name, *name_lwr;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000482 /* Try to create it in $HOME/.wine */
483 /* FIXME: this will need a more general solution */
Alexandre Julliard4144b5b2002-06-20 23:21:27 +0000484 strcpy( buffer, wine_get_config_dir() );
Alexandre Julliard647876e2000-01-25 01:35:01 +0000485 p = buffer + strlen(buffer);
486 *p++ = '/';
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000487 *p = 0; /* make strlen() below happy */
488 name = strrchrW( CurProfile->dos_name, '\\' ) + 1;
Dmitry Timoshkovdb45e1e2002-11-13 19:47:22 +0000489
490 /* create a lower cased version of the name */
491 name_lwr = HeapAlloc(GetProcessHeap(), 0, (strlenW(name) + 1) * sizeof(WCHAR));
492 strcpyW(name_lwr, name);
493 strlwrW(name_lwr);
494 WideCharToMultiByte(DRIVE_GetCodepage(drive), 0, name_lwr, -1,
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000495 p, sizeof(buffer) - strlen(buffer), NULL, NULL);
Dmitry Timoshkovdb45e1e2002-11-13 19:47:22 +0000496 HeapFree(GetProcessHeap(), 0, name_lwr);
497
Alexandre Julliard647876e2000-01-25 01:35:01 +0000498 file = fopen( buffer, "w" );
499 unix_name = buffer;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000500 }
Vincent Béron9a624912002-05-31 23:06:46 +0000501
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000502 if (!file)
503 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000504 WARN("could not save profile file %s\n", debugstr_w(CurProfile->dos_name));
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000505 return FALSE;
506 }
507
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000508 TRACE("Saving %s into '%s'\n", debugstr_w(CurProfile->dos_name), unix_name );
Alexandre Julliard829fe321998-07-26 14:27:39 +0000509 PROFILE_Save( file, CurProfile->section );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000510 fclose( file );
Alexandre Julliard829fe321998-07-26 14:27:39 +0000511 CurProfile->changed = FALSE;
512 if(!stat(unix_name,&buf))
513 CurProfile->mtime=buf.st_mtime;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000514 return TRUE;
515}
516
517
518/***********************************************************************
Alexandre Julliarde61b7921999-07-31 19:24:11 +0000519 * PROFILE_ReleaseFile
520 *
521 * Flush the current profile to disk and remove it from the cache.
522 */
523static void PROFILE_ReleaseFile(void)
524{
525 PROFILE_FlushFile();
526 PROFILE_Free( CurProfile->section );
Alexandre Julliard90476d62000-02-16 22:47:24 +0000527 if (CurProfile->dos_name) HeapFree( GetProcessHeap(), 0, CurProfile->dos_name );
528 if (CurProfile->unix_name) HeapFree( GetProcessHeap(), 0, CurProfile->unix_name );
529 if (CurProfile->filename) HeapFree( GetProcessHeap(), 0, CurProfile->filename );
Alexandre Julliarde61b7921999-07-31 19:24:11 +0000530 CurProfile->changed = FALSE;
531 CurProfile->section = NULL;
532 CurProfile->dos_name = NULL;
533 CurProfile->unix_name = NULL;
534 CurProfile->filename = NULL;
535 CurProfile->mtime = 0;
536}
537
538
539/***********************************************************************
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000540 * PROFILE_Open
541 *
542 * Open a profile file, checking the cached file first.
543 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000544static BOOL PROFILE_Open( LPCWSTR filename )
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000545{
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000546 DOS_FULL_NAME full_name;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000547 char buffer[MAX_PATHNAME_LEN];
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000548 WCHAR *newdos_name;
Dmitry Timoshkovdb45e1e2002-11-13 19:47:22 +0000549 WCHAR *name, *name_lwr;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000550 char *p;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000551 FILE *file = NULL;
Alexandre Julliard829fe321998-07-26 14:27:39 +0000552 int i,j;
553 struct stat buf;
554 PROFILE *tempProfile;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000555
Alexandre Julliard829fe321998-07-26 14:27:39 +0000556 /* First time around */
557
558 if(!CurProfile)
559 for(i=0;i<N_CACHED_PROFILES;i++)
560 {
Dimitrie O. Paunabdbced2000-04-29 14:20:28 +0000561 MRUProfile[i]=HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILE) );
562 if(MRUProfile[i] == NULL) break;
Alexandre Julliard829fe321998-07-26 14:27:39 +0000563 MRUProfile[i]->changed=FALSE;
564 MRUProfile[i]->section=NULL;
565 MRUProfile[i]->dos_name=NULL;
566 MRUProfile[i]->unix_name=NULL;
567 MRUProfile[i]->filename=NULL;
568 MRUProfile[i]->mtime=0;
569 }
570
571 /* Check for a match */
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000572
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000573 if (strchrW( filename, '/' ) || strchrW( filename, '\\' ) ||
574 strchrW( filename, ':' ))
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000575 {
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000576 if (!DOSFS_GetFullName( filename, FALSE, &full_name )) return FALSE;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000577 }
578 else
579 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000580 static const WCHAR bkslashW[] = {'\\',0};
581 WCHAR windirW[MAX_PATH];
582
583 GetWindowsDirectoryW( windirW, MAX_PATH );
584 strcatW( windirW, bkslashW );
585 strcatW( windirW, filename );
586 if (!DOSFS_GetFullName( windirW, FALSE, &full_name )) return FALSE;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000587 }
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000588
Alexandre Julliard829fe321998-07-26 14:27:39 +0000589 for(i=0;i<N_CACHED_PROFILES;i++)
590 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000591 if ((MRUProfile[i]->filename && !strcmpW( filename, MRUProfile[i]->filename )) ||
592 (MRUProfile[i]->dos_name && !strcmpW( full_name.short_name, MRUProfile[i]->dos_name )))
Alexandre Julliard829fe321998-07-26 14:27:39 +0000593 {
594 if(i)
595 {
596 PROFILE_FlushFile();
597 tempProfile=MRUProfile[i];
598 for(j=i;j>0;j--)
599 MRUProfile[j]=MRUProfile[j-1];
600 CurProfile=tempProfile;
601 }
602 if(!stat(CurProfile->unix_name,&buf) && CurProfile->mtime==buf.st_mtime)
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000603 TRACE("(%s): already opened (mru=%d)\n",
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000604 debugstr_w(filename), i );
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000605 else
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000606 TRACE("(%s): already opened, needs refreshing (mru=%d)\n",
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000607 debugstr_w(filename), i );
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000608 return TRUE;
Alexandre Julliard829fe321998-07-26 14:27:39 +0000609 }
610 }
611
Andreas Mohr87bff281999-11-21 02:03:03 +0000612 /* Flush the old current profile */
613 PROFILE_FlushFile();
Alexandre Julliard829fe321998-07-26 14:27:39 +0000614
Andreas Mohr87bff281999-11-21 02:03:03 +0000615 /* Make the oldest profile the current one only in order to get rid of it */
Alexandre Julliard829fe321998-07-26 14:27:39 +0000616 if(i==N_CACHED_PROFILES)
617 {
618 tempProfile=MRUProfile[N_CACHED_PROFILES-1];
619 for(i=N_CACHED_PROFILES-1;i>0;i--)
620 MRUProfile[i]=MRUProfile[i-1];
621 CurProfile=tempProfile;
622 }
Alexandre Julliarde61b7921999-07-31 19:24:11 +0000623 if(CurProfile->filename) PROFILE_ReleaseFile();
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000624
Andreas Mohr87bff281999-11-21 02:03:03 +0000625 /* OK, now that CurProfile is definitely free we assign it our new file */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000626 newdos_name = HeapAlloc( GetProcessHeap(), 0, (strlenW(full_name.short_name)+1) * sizeof(WCHAR) );
627 strcpyW( newdos_name, full_name.short_name );
Alexandre Julliard829fe321998-07-26 14:27:39 +0000628 CurProfile->dos_name = newdos_name;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000629 CurProfile->filename = HeapAlloc( GetProcessHeap(), 0, (strlenW(filename)+1) * sizeof(WCHAR) );
630 strcpyW( CurProfile->filename, filename );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000631
632 /* Try to open the profile file, first in $HOME/.wine */
633
634 /* FIXME: this will need a more general solution */
Alexandre Julliard4144b5b2002-06-20 23:21:27 +0000635 strcpy( buffer, wine_get_config_dir() );
Alexandre Julliard647876e2000-01-25 01:35:01 +0000636 p = buffer + strlen(buffer);
637 *p++ = '/';
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000638 *p = 0; /* make strlen() below happy */
639 name = strrchrW( newdos_name, '\\' ) + 1;
Dmitry Timoshkovdb45e1e2002-11-13 19:47:22 +0000640
641 /* create a lower cased version of the name */
642 name_lwr = HeapAlloc(GetProcessHeap(), 0, (strlenW(name) + 1) * sizeof(WCHAR));
643 strcpyW(name_lwr, name);
644 strlwrW(name_lwr);
645 WideCharToMultiByte(DRIVE_GetCodepage(full_name.drive), 0, name_lwr, -1,
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000646 p, sizeof(buffer) - strlen(buffer), NULL, NULL);
Dmitry Timoshkovdb45e1e2002-11-13 19:47:22 +0000647 HeapFree(GetProcessHeap(), 0, name_lwr);
648
Alexandre Julliard647876e2000-01-25 01:35:01 +0000649 if ((file = fopen( buffer, "r" )))
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000650 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000651 TRACE("(%s): found it in %s\n", debugstr_w(filename), buffer );
Alexandre Julliard5f728ca2001-07-24 21:45:22 +0000652 CurProfile->unix_name = HeapAlloc( GetProcessHeap(), 0, strlen(buffer)+1 );
653 strcpy( CurProfile->unix_name, buffer );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000654 }
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000655 else
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000656 {
Alexandre Julliard5f728ca2001-07-24 21:45:22 +0000657 CurProfile->unix_name = HeapAlloc( GetProcessHeap(), 0, strlen(full_name.long_name)+1 );
658 strcpy( CurProfile->unix_name, full_name.long_name );
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000659 if ((file = fopen( full_name.long_name, "r" )))
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000660 TRACE("(%s): found it in %s\n",
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000661 debugstr_w(filename), full_name.long_name );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000662 }
663
664 if (file)
665 {
Alexandre Julliard829fe321998-07-26 14:27:39 +0000666 CurProfile->section = PROFILE_Load( file );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000667 fclose( file );
Alexandre Julliard829fe321998-07-26 14:27:39 +0000668 if(!stat(CurProfile->unix_name,&buf))
669 CurProfile->mtime=buf.st_mtime;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000670 }
671 else
Alexandre Julliardd1ce8b21996-09-02 16:46:30 +0000672 {
673 /* Does not exist yet, we will create it in PROFILE_FlushFile */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000674 WARN("profile file %s not found\n", debugstr_w(newdos_name) );
Alexandre Julliardd1ce8b21996-09-02 16:46:30 +0000675 }
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000676 return TRUE;
677}
678
679
680/***********************************************************************
681 * PROFILE_GetSection
682 *
Alexandre Julliarda845b881998-06-01 10:44:35 +0000683 * Returns all keys of a section.
Alexandre Julliard642d3131998-07-12 19:29:36 +0000684 * If return_values is TRUE, also include the corresponding values.
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000685 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000686static INT PROFILE_GetSection( PROFILESECTION *section, LPCWSTR section_name,
687 LPWSTR buffer, UINT len, BOOL handle_env,
Eric Poueched155751999-03-25 13:24:08 +0000688 BOOL return_values )
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000689{
690 PROFILEKEY *key;
Dmitry Timoshkovfdc78a32000-12-19 19:37:03 +0000691
692 if(!buffer) return 0;
693
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000694 TRACE("%s,%p,%u\n", debugstr_w(section_name), buffer, len);
695
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000696 while (section)
697 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000698 if (section->name[0] && !strcmpiW( section->name, section_name ))
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000699 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000700 UINT oldlen = len;
Alexandre Julliard9416aba1999-01-26 17:29:49 +0000701 for (key = section->key; key; key = key->next)
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000702 {
703 if (len <= 2) break;
Alexandre Julliard9416aba1999-01-26 17:29:49 +0000704 if (!*key->name) continue; /* Skip empty lines */
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000705 if (IS_ENTRY_COMMENT(key->name)) continue; /* Skip comments */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000706 PROFILE_CopyEntry( buffer, key->name, len - 1, handle_env, 0 );
707 len -= strlenW(buffer) + 1;
708 buffer += strlenW(buffer) + 1;
Marcus Meissneree6ea512001-06-06 21:03:40 +0000709 if (len < 2)
710 break;
Alexandre Julliarda845b881998-06-01 10:44:35 +0000711 if (return_values && key->value) {
712 buffer[-1] = '=';
713 PROFILE_CopyEntry ( buffer,
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000714 key->value, len - 1, handle_env, 0 );
715 len -= strlenW(buffer) + 1;
716 buffer += strlenW(buffer) + 1;
Alexandre Julliarda845b881998-06-01 10:44:35 +0000717 }
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000718 }
719 *buffer = '\0';
Marcus Meissneracfae0c1999-05-08 18:29:10 +0000720 if (len <= 1)
Alexandre Julliard46ea8b31998-05-03 19:01:20 +0000721 /*If either lpszSection or lpszKey is NULL and the supplied
Vincent Béron9a624912002-05-31 23:06:46 +0000722 destination buffer is too small to hold all the strings,
Alexandre Julliard46ea8b31998-05-03 19:01:20 +0000723 the last string is truncated and followed by two null characters.
724 In this case, the return value is equal to cchReturnBuffer
725 minus two. */
726 {
727 buffer[-1] = '\0';
728 return oldlen - 2;
729 }
Alexandre Julliard829fe321998-07-26 14:27:39 +0000730 return oldlen - len;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000731 }
732 section = section->next;
733 }
734 buffer[0] = buffer[1] = '\0';
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000735 return 0;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000736}
737
Francois Gouget19b05e52001-08-28 18:39:26 +0000738/* See GetPrivateProfileSectionNamesA for documentation */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000739static INT PROFILE_GetSectionNames( LPWSTR buffer, UINT len )
Andreas Mohradfeec91999-05-22 16:04:57 +0000740{
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000741 LPWSTR buf;
Francois Gouget19b05e52001-08-28 18:39:26 +0000742 UINT f,l;
Andreas Mohradfeec91999-05-22 16:04:57 +0000743 PROFILESECTION *section;
744
Francois Gouget19b05e52001-08-28 18:39:26 +0000745 if (!buffer || !len)
746 return 0;
747 if (len==1) {
748 *buffer='\0';
749 return 0;
750 }
Dmitry Timoshkovfdc78a32000-12-19 19:37:03 +0000751
Francois Gouget19b05e52001-08-28 18:39:26 +0000752 f=len-1;
753 buf=buffer;
754 section = CurProfile->section;
755 while ((section!=NULL)) {
756 if (section->name[0]) {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000757 l = strlenW(section->name)+1;
Francois Gouget19b05e52001-08-28 18:39:26 +0000758 if (l > f) {
759 if (f>0) {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000760 strncpyW(buf, section->name, f-1);
Francois Gouget19b05e52001-08-28 18:39:26 +0000761 buf += f-1;
762 *buf++='\0';
763 }
764 *buf='\0';
765 return len-2;
766 }
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000767 strcpyW(buf, section->name);
Francois Gouget19b05e52001-08-28 18:39:26 +0000768 buf += l;
769 f -= l;
770 }
771 section = section->next;
772 }
773 *buf='\0';
Andreas Mohradfeec91999-05-22 16:04:57 +0000774 return buf-buffer;
775}
776
777
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000778/***********************************************************************
779 * PROFILE_GetString
780 *
781 * Get a profile string.
Andreas Mohr3ac104f2000-09-29 21:04:44 +0000782 *
783 * Tests with GetPrivateProfileString16, W95a,
784 * with filled buffer ("****...") and section "set1" and key_name "1" valid:
785 * section key_name def_val res buffer
786 * "set1" "1" "x" 43 [data]
787 * "set1" "1 " "x" 43 [data] (!)
788 * "set1" " 1 "' "x" 43 [data] (!)
789 * "set1" "" "x" 1 "x"
790 * "set1" "" "x " 1 "x" (!)
791 * "set1" "" " x " 3 " x" (!)
792 * "set1" NULL "x" 6 "1\02\03\0\0"
793 * "set1" "" "x" 1 "x"
794 * NULL "1" "x" 0 "" (!)
795 * "" "1" "x" 1 "x"
796 * NULL NULL "" 0 ""
Vincent Béron9a624912002-05-31 23:06:46 +0000797 *
798 *
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000799 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000800static INT PROFILE_GetString( LPCWSTR section, LPCWSTR key_name,
801 LPCWSTR def_val, LPWSTR buffer, UINT len )
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000802{
803 PROFILEKEY *key = NULL;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000804 static const WCHAR empty_strW[] = { 0 };
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000805
Dmitry Timoshkovfdc78a32000-12-19 19:37:03 +0000806 if(!buffer) return 0;
807
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000808 if (!def_val) def_val = empty_strW;
Andreas Mohr470a3f92002-05-11 22:59:41 +0000809 if (key_name)
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000810 {
Andreas Mohr470a3f92002-05-11 22:59:41 +0000811 if (!key_name[0])
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000812 {
Andreas Mohr470a3f92002-05-11 22:59:41 +0000813 /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227 */
814 return 0;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000815 }
Gerhard Gruber024a0ac2002-02-05 19:44:54 +0000816 key = PROFILE_Find( &CurProfile->section, section, key_name, FALSE, FALSE);
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000817 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def_val,
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000818 len, FALSE, TRUE );
819 TRACE("(%s,%s,%s): returning %s\n",
820 debugstr_w(section), debugstr_w(key_name),
821 debugstr_w(def_val), debugstr_w(buffer) );
822 return strlenW( buffer );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000823 }
Andreas Mohr470a3f92002-05-11 22:59:41 +0000824 /* no "else" here ! */
Andreas Mohradfeec91999-05-22 16:04:57 +0000825 if (section && section[0])
Andreas Mohr470a3f92002-05-11 22:59:41 +0000826 {
Mike McCormacke921e462002-07-01 18:12:47 +0000827 INT ret = PROFILE_GetSection(CurProfile->section, section, buffer, len, FALSE, FALSE);
828 if (!buffer[0]) /* no luck -> def_val */
829 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000830 PROFILE_CopyEntry(buffer, def_val, len, FALSE, TRUE);
831 ret = strlenW(buffer);
Mike McCormacke921e462002-07-01 18:12:47 +0000832 }
833 return ret;
Andreas Mohr470a3f92002-05-11 22:59:41 +0000834 }
Andreas Mohr3ac104f2000-09-29 21:04:44 +0000835 buffer[0] = '\0';
836 return 0;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000837}
838
839
840/***********************************************************************
841 * PROFILE_SetString
842 *
843 * Set a profile string.
844 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000845static BOOL PROFILE_SetString( LPCWSTR section_name, LPCWSTR key_name,
846 LPCWSTR value, BOOL create_always )
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000847{
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000848 if (!key_name) /* Delete a whole section */
849 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000850 TRACE("(%s)\n", debugstr_w(section_name));
Alexandre Julliard829fe321998-07-26 14:27:39 +0000851 CurProfile->changed |= PROFILE_DeleteSection( &CurProfile->section,
852 section_name );
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +0000853 return TRUE; /* Even if PROFILE_DeleteSection() has failed,
854 this is not an error on application's level.*/
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000855 }
856 else if (!value) /* Delete a key */
857 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000858 TRACE("(%s,%s)\n", debugstr_w(section_name), debugstr_w(key_name) );
Alexandre Julliard829fe321998-07-26 14:27:39 +0000859 CurProfile->changed |= PROFILE_DeleteKey( &CurProfile->section,
860 section_name, key_name );
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +0000861 return TRUE; /* same error handling as above */
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000862 }
863 else /* Set the key value */
864 {
Gerhard Gruber024a0ac2002-02-05 19:44:54 +0000865 PROFILEKEY *key = PROFILE_Find(&CurProfile->section, section_name,
866 key_name, TRUE, create_always );
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000867 TRACE("(%s,%s,%s):\n",
868 debugstr_w(section_name), debugstr_w(key_name), debugstr_w(value) );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000869 if (!key) return FALSE;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000870 if (key->value)
871 {
Vincent Béron9a624912002-05-31 23:06:46 +0000872 /* strip the leading spaces. We can safely strip \n\r and
Marcus Meissnera6ae5552000-06-13 01:06:22 +0000873 * friends too, they should not happen here anyway. */
874 while (PROFILE_isspace(*value)) value++;
875
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000876 if (!strcmpW( key->value, value ))
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000877 {
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000878 TRACE(" no change needed\n" );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000879 return TRUE; /* No change needed */
880 }
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000881 TRACE(" replacing %s\n", debugstr_w(key->value) );
Alexandre Julliard90476d62000-02-16 22:47:24 +0000882 HeapFree( GetProcessHeap(), 0, key->value );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000883 }
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000884 else TRACE(" creating key\n" );
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000885 key->value = HeapAlloc( GetProcessHeap(), 0, (strlenW(value)+1) * sizeof(WCHAR) );
886 strcpyW( key->value, value );
Alexandre Julliard829fe321998-07-26 14:27:39 +0000887 CurProfile->changed = TRUE;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000888 }
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +0000889 return TRUE;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000890}
891
892
893/***********************************************************************
Alexandre Julliard11f361a2002-11-23 02:24:53 +0000894 * get_profile_key
895 */
896static HKEY get_profile_key(void)
897{
898 static HKEY profile_key;
899
900 if (!profile_key)
901 {
902 OBJECT_ATTRIBUTES attr;
903 UNICODE_STRING nameW;
904 HKEY hkey;
905
906 attr.Length = sizeof(attr);
907 attr.RootDirectory = 0;
908 attr.ObjectName = &nameW;
909 attr.Attributes = 0;
910 attr.SecurityDescriptor = NULL;
911 attr.SecurityQualityOfService = NULL;
912
913 if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Machine\\Software\\Wine\\Wine\\Config" ) ||
914 NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, REG_OPTION_VOLATILE, NULL ))
915 {
916 ERR("Cannot create config registry key\n" );
917 ExitProcess( 1 );
918 }
919 RtlFreeUnicodeString( &nameW );
920
921 if (InterlockedCompareExchangePointer( (void **)&profile_key, hkey, 0 ))
922 NtClose( hkey ); /* somebody beat us to it */
923 }
924 return profile_key;
925}
926
927
928/***********************************************************************
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000929 * PROFILE_GetWineIniString
930 *
931 * Get a config string from the wine.ini file.
932 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000933int PROFILE_GetWineIniString( LPCWSTR section, LPCWSTR key_name,
934 LPCWSTR def, LPWSTR buffer, int len )
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000935{
Alexandre Julliard00377a72000-02-19 20:50:00 +0000936 HKEY hkey;
Alexandre Julliard81bdcf12002-09-13 17:47:44 +0000937 NTSTATUS err;
938 OBJECT_ATTRIBUTES attr;
939 UNICODE_STRING nameW;
Eric Poueched155751999-03-25 13:24:08 +0000940
Alexandre Julliard81bdcf12002-09-13 17:47:44 +0000941 attr.Length = sizeof(attr);
Alexandre Julliard11f361a2002-11-23 02:24:53 +0000942 attr.RootDirectory = get_profile_key();
Alexandre Julliard81bdcf12002-09-13 17:47:44 +0000943 attr.ObjectName = &nameW;
944 attr.Attributes = 0;
945 attr.SecurityDescriptor = NULL;
946 attr.SecurityQualityOfService = NULL;
947 RtlInitUnicodeString( &nameW, section );
948 if (!(err = NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr )))
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000949 {
Alexandre Julliard81bdcf12002-09-13 17:47:44 +0000950 char tmp[PROFILE_MAX_LINE_LEN*sizeof(WCHAR) + sizeof(KEY_VALUE_PARTIAL_INFORMATION)];
951 DWORD count;
952
953 RtlInitUnicodeString( &nameW, key_name );
954 if (!(err = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
955 tmp, sizeof(tmp), &count )))
956 {
957 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
958 PROFILE_CopyEntry( buffer, str, len, TRUE, TRUE );
959 }
960 NtClose( hkey );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000961 }
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000962
Alexandre Julliard81bdcf12002-09-13 17:47:44 +0000963 if (err) PROFILE_CopyEntry( buffer, def, len, TRUE, TRUE );
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000964 TRACE( "(%s,%s,%s): returning %s\n", debugstr_w(section),
965 debugstr_w(key_name), debugstr_w(def), debugstr_w(buffer) );
966 return strlenW(buffer);
Alexandre Julliard00377a72000-02-19 20:50:00 +0000967}
Eric Poueched155751999-03-25 13:24:08 +0000968
Alexandre Julliard00377a72000-02-19 20:50:00 +0000969
Alexandre Julliardd37eb361997-07-20 16:23:21 +0000970/******************************************************************************
971 *
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000972 * PROFILE_GetWineIniBool
Alexandre Julliardd37eb361997-07-20 16:23:21 +0000973 *
974 * Reads a boolean value from the wine.ini file. This function attempts to
975 * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
976 * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
977 * true. Anything else results in the return of the default value.
978 *
979 * This function uses 1 to indicate true, and 0 for false. You can check
980 * for existence by setting def to something other than 0 or 1 and
981 * examining the return value.
982 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000983int PROFILE_GetWineIniBool( LPCWSTR section, LPCWSTR key_name, int def )
Alexandre Julliardd37eb361997-07-20 16:23:21 +0000984{
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000985 static const WCHAR def_valueW[] = {'~',0};
986 WCHAR key_value[2];
Alexandre Julliardd37eb361997-07-20 16:23:21 +0000987 int retval;
988
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +0000989 PROFILE_GetWineIniString(section, key_name, def_valueW, key_value, 2);
Alexandre Julliardd37eb361997-07-20 16:23:21 +0000990
991 switch(key_value[0]) {
992 case 'n':
993 case 'N':
994 case 'f':
995 case 'F':
996 case '0':
997 retval = 0;
998 break;
999
1000 case 'y':
1001 case 'Y':
1002 case 't':
1003 case 'T':
1004 case '1':
1005 retval = 1;
1006 break;
1007
1008 default:
1009 retval = def;
1010 }
1011
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001012 TRACE("(%s, %s, %s), [%c], ret %s\n", debugstr_w(section), debugstr_w(key_name),
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001013 def ? "TRUE" : "FALSE", key_value[0],
1014 retval ? "TRUE" : "FALSE");
1015
1016 return retval;
1017}
1018
1019
Alexandre Julliard18f92e71996-07-17 20:02:21 +00001020/***********************************************************************
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001021 * PROFILE_UsageWineIni
1022 *
1023 * Explain the wine.ini file to those who don't read documentation.
1024 * Keep below one screenful in length so that error messages above are
1025 * noticed.
1026 */
1027void PROFILE_UsageWineIni(void)
1028{
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001029 MESSAGE("Perhaps you have not properly edited or created "
Gerald Pfeifer181dfdd2003-03-20 19:22:24 +00001030 "your Wine configuration file,\n");
1031 MESSAGE("which is (supposed to be) '%s/config'.\n", wine_get_config_dir());
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001032}
1033
Alexandre Julliard23946ad1997-06-16 17:43:53 +00001034
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001035/********************* API functions **********************************/
1036
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001037/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001038 * GetProfileInt (KERNEL.57)
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001039 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001040UINT16 WINAPI GetProfileInt16( LPCSTR section, LPCSTR entry, INT16 def_val )
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001041{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001042 return GetPrivateProfileInt16( section, entry, def_val, "win.ini" );
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001043}
1044
1045
1046/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001047 * GetProfileIntA (KERNEL32.@)
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001048 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001049UINT WINAPI GetProfileIntA( LPCSTR section, LPCSTR entry, INT def_val )
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001050{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001051 return GetPrivateProfileIntA( section, entry, def_val, "win.ini" );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001052}
1053
1054/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001055 * GetProfileIntW (KERNEL32.@)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001056 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001057UINT WINAPI GetProfileIntW( LPCWSTR section, LPCWSTR entry, INT def_val )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001058{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001059 return GetPrivateProfileIntW( section, entry, def_val, wininiW );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001060}
1061
Andreas Mohr3ac104f2000-09-29 21:04:44 +00001062/*
Lionel Ulmerf89722d2001-07-20 17:55:39 +00001063 * if allow_section_name_copy is TRUE, allow the copying :
1064 * - of Section names if 'section' is NULL
1065 * - of Keys in a Section if 'entry' is NULL
1066 * (see MSDN doc for GetPrivateProfileString)
Andreas Mohr3ac104f2000-09-29 21:04:44 +00001067 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001068static int PROFILE_GetPrivateProfileString( LPCWSTR section, LPCWSTR entry,
1069 LPCWSTR def_val, LPWSTR buffer,
1070 UINT len, LPCWSTR filename,
Lionel Ulmerf89722d2001-07-20 17:55:39 +00001071 BOOL allow_section_name_copy )
Andreas Mohr3ac104f2000-09-29 21:04:44 +00001072{
1073 int ret;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001074 LPWSTR pDefVal = NULL;
Andreas Mohr3ac104f2000-09-29 21:04:44 +00001075
Vincent Béron9a624912002-05-31 23:06:46 +00001076 if (!filename)
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001077 filename = wininiW;
1078
1079 TRACE("%s,%s,%s,%p,%u,%s\n", debugstr_w(section), debugstr_w(entry),
1080 debugstr_w(def_val), buffer, len, debugstr_w(filename));
Andreas Mohr3ac104f2000-09-29 21:04:44 +00001081
1082 /* strip any trailing ' ' of def_val. */
1083 if (def_val)
1084 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001085 LPCWSTR p = &def_val[strlenW(def_val)]; /* even "" works ! */
Andreas Mohr3ac104f2000-09-29 21:04:44 +00001086
1087 while (p > def_val)
1088 {
1089 p--;
1090 if ((*p) != ' ')
1091 break;
1092 }
1093 if (*p == ' ') /* ouch, contained trailing ' ' */
1094 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001095 int len = (int)(p - def_val);
1096 pDefVal = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
1097 strncpyW(pDefVal, def_val, len);
Andreas Mohr3ac104f2000-09-29 21:04:44 +00001098 pDefVal[len] = '\0';
1099 }
1100 }
1101 if (!pDefVal)
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001102 pDefVal = (LPWSTR)def_val;
Andreas Mohr3ac104f2000-09-29 21:04:44 +00001103
1104 EnterCriticalSection( &PROFILE_CritSect );
1105
1106 if (PROFILE_Open( filename )) {
Lionel Ulmerf89722d2001-07-20 17:55:39 +00001107 if ((allow_section_name_copy) && (section == NULL))
Andreas Mohr3ac104f2000-09-29 21:04:44 +00001108 ret = PROFILE_GetSectionNames(buffer, len);
1109 else
Lionel Ulmerf89722d2001-07-20 17:55:39 +00001110 /* PROFILE_GetString already handles the 'entry == NULL' case */
Andreas Mohr3ac104f2000-09-29 21:04:44 +00001111 ret = PROFILE_GetString( section, entry, pDefVal, buffer, len );
1112 } else {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001113 lstrcpynW( buffer, pDefVal, len );
1114 ret = strlenW( buffer );
Andreas Mohr3ac104f2000-09-29 21:04:44 +00001115 }
1116
1117 LeaveCriticalSection( &PROFILE_CritSect );
1118
1119 if (pDefVal != def_val) /* allocated */
1120 HeapFree(GetProcessHeap(), 0, pDefVal);
Vincent Béron9a624912002-05-31 23:06:46 +00001121
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001122 TRACE("returning %s, %d\n", debugstr_w(buffer), ret);
1123
Andreas Mohr3ac104f2000-09-29 21:04:44 +00001124 return ret;
1125}
1126
1127/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001128 * GetPrivateProfileString (KERNEL.128)
Andreas Mohr3ac104f2000-09-29 21:04:44 +00001129 */
1130INT16 WINAPI GetPrivateProfileString16( LPCSTR section, LPCSTR entry,
1131 LPCSTR def_val, LPSTR buffer,
1132 UINT16 len, LPCSTR filename )
1133{
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001134 UNICODE_STRING sectionW, entryW, def_valW, filenameW;
1135 LPWSTR bufferW;
1136 INT16 retW, ret = 0;
1137
1138 bufferW = buffer ? HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)) : NULL;
1139 if (section) RtlCreateUnicodeStringFromAsciiz(&sectionW, section);
1140 else sectionW.Buffer = NULL;
1141 if (entry) RtlCreateUnicodeStringFromAsciiz(&entryW, entry);
1142 else entryW.Buffer = NULL;
1143 if (def_val) RtlCreateUnicodeStringFromAsciiz(&def_valW, def_val);
1144 else def_valW.Buffer = NULL;
1145 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
1146 else filenameW.Buffer = NULL;
1147
1148 retW = PROFILE_GetPrivateProfileString( sectionW.Buffer, entryW.Buffer,
1149 def_valW.Buffer, bufferW, len,
1150 filenameW.Buffer, FALSE );
1151 if (len)
1152 {
1153 ret = WideCharToMultiByte(CP_ACP, 0, bufferW, retW + 1, buffer, len, NULL, NULL);
1154 if (!ret)
1155 {
1156 ret = len - 1;
1157 buffer[ret] = 0;
1158 }
1159 else
1160 ret--; /* strip terminating 0 */
1161 }
1162
1163 RtlFreeUnicodeString(&sectionW);
1164 RtlFreeUnicodeString(&entryW);
1165 RtlFreeUnicodeString(&def_valW);
1166 RtlFreeUnicodeString(&filenameW);
1167 if (bufferW) HeapFree(GetProcessHeap(), 0, bufferW);
1168 return ret;
Andreas Mohr3ac104f2000-09-29 21:04:44 +00001169}
1170
1171/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001172 * GetPrivateProfileStringA (KERNEL32.@)
Andreas Mohr3ac104f2000-09-29 21:04:44 +00001173 */
1174INT WINAPI GetPrivateProfileStringA( LPCSTR section, LPCSTR entry,
1175 LPCSTR def_val, LPSTR buffer,
1176 UINT len, LPCSTR filename )
1177{
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001178 UNICODE_STRING sectionW, entryW, def_valW, filenameW;
1179 LPWSTR bufferW;
1180 INT retW, ret = 0;
1181
1182 bufferW = buffer ? HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)) : NULL;
1183 if (section) RtlCreateUnicodeStringFromAsciiz(&sectionW, section);
1184 else sectionW.Buffer = NULL;
1185 if (entry) RtlCreateUnicodeStringFromAsciiz(&entryW, entry);
1186 else entryW.Buffer = NULL;
1187 if (def_val) RtlCreateUnicodeStringFromAsciiz(&def_valW, def_val);
1188 else def_valW.Buffer = NULL;
1189 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
1190 else filenameW.Buffer = NULL;
1191
1192 retW = GetPrivateProfileStringW( sectionW.Buffer, entryW.Buffer,
1193 def_valW.Buffer, bufferW, len,
1194 filenameW.Buffer);
1195 if (len)
1196 {
1197 ret = WideCharToMultiByte(CP_ACP, 0, bufferW, retW + 1, buffer, len, NULL, NULL);
1198 if (!ret)
1199 {
1200 ret = len - 1;
1201 buffer[ret] = 0;
1202 }
1203 else
1204 ret--; /* strip terminating 0 */
1205 }
1206
1207 RtlFreeUnicodeString(&sectionW);
1208 RtlFreeUnicodeString(&entryW);
1209 RtlFreeUnicodeString(&def_valW);
1210 RtlFreeUnicodeString(&filenameW);
1211 if (bufferW) HeapFree(GetProcessHeap(), 0, bufferW);
1212 return ret;
Andreas Mohr3ac104f2000-09-29 21:04:44 +00001213}
1214
1215/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001216 * GetPrivateProfileStringW (KERNEL32.@)
Andreas Mohr3ac104f2000-09-29 21:04:44 +00001217 */
1218INT WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1219 LPCWSTR def_val, LPWSTR buffer,
1220 UINT len, LPCWSTR filename )
1221{
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001222 return PROFILE_GetPrivateProfileString( section, entry, def_val,
1223 buffer, len, filename, TRUE );
Andreas Mohr3ac104f2000-09-29 21:04:44 +00001224}
1225
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001226/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001227 * GetProfileString (KERNEL.58)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001228 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001229INT16 WINAPI GetProfileString16( LPCSTR section, LPCSTR entry, LPCSTR def_val,
Alexandre Julliard642d3131998-07-12 19:29:36 +00001230 LPSTR buffer, UINT16 len )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001231{
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001232 return GetPrivateProfileString16( section, entry, def_val,
1233 buffer, len, "win.ini" );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001234}
1235
1236/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001237 * GetProfileStringA (KERNEL32.@)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001238 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001239INT WINAPI GetProfileStringA( LPCSTR section, LPCSTR entry, LPCSTR def_val,
Eric Poueched155751999-03-25 13:24:08 +00001240 LPSTR buffer, UINT len )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001241{
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001242 return GetPrivateProfileStringA( section, entry, def_val,
1243 buffer, len, "win.ini" );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001244}
1245
1246/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001247 * GetProfileStringW (KERNEL32.@)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001248 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001249INT WINAPI GetProfileStringW( LPCWSTR section, LPCWSTR entry,
Eric Poueched155751999-03-25 13:24:08 +00001250 LPCWSTR def_val, LPWSTR buffer, UINT len )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001251{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001252 return GetPrivateProfileStringW( section, entry, def_val,
Eric Poueched155751999-03-25 13:24:08 +00001253 buffer, len, wininiW );
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001254}
1255
Alexandre Julliard77b99181997-09-14 17:17:23 +00001256/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001257 * WriteProfileString (KERNEL.59)
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001258 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001259BOOL16 WINAPI WriteProfileString16( LPCSTR section, LPCSTR entry,
1260 LPCSTR string )
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001261{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001262 return WritePrivateProfileString16( section, entry, string, "win.ini" );
1263}
1264
1265/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001266 * WriteProfileStringA (KERNEL32.@)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001267 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001268BOOL WINAPI WriteProfileStringA( LPCSTR section, LPCSTR entry,
Eric Poueched155751999-03-25 13:24:08 +00001269 LPCSTR string )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001270{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001271 return WritePrivateProfileStringA( section, entry, string, "win.ini" );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001272}
1273
1274/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001275 * WriteProfileStringW (KERNEL32.@)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001276 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001277BOOL WINAPI WriteProfileStringW( LPCWSTR section, LPCWSTR entry,
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001278 LPCWSTR string )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001279{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001280 return WritePrivateProfileStringW( section, entry, string, wininiW );
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001281}
1282
1283
1284/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001285 * GetPrivateProfileInt (KERNEL.127)
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001286 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001287UINT16 WINAPI GetPrivateProfileInt16( LPCSTR section, LPCSTR entry,
1288 INT16 def_val, LPCSTR filename )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001289{
Andreas Mohrc8dcafc2002-02-27 18:49:06 +00001290 /* we used to have some elaborate return value limitation (<= -32768 etc.)
1291 * here, but Win98SE doesn't care about this at all, so I deleted it.
1292 * AFAIR versions prior to Win9x had these limits, though. */
1293 return (INT16)GetPrivateProfileIntA(section,entry,def_val,filename);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001294}
1295
1296/***********************************************************************
Stefan Leichterb5695082003-03-23 20:03:13 +00001297 * GetPrivateProfileIntW (KERNEL32.@)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001298 */
Stefan Leichterb5695082003-03-23 20:03:13 +00001299UINT WINAPI GetPrivateProfileIntW( LPCWSTR section, LPCWSTR entry,
1300 INT def_val, LPCWSTR filename )
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001301{
Stefan Leichterb5695082003-03-23 20:03:13 +00001302 WCHAR buffer[30];
1303 UNICODE_STRING bufferW;
1304 INT len;
1305 ULONG result;
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001306
Stefan Leichterb5695082003-03-23 20:03:13 +00001307 if (!(len = GetPrivateProfileStringW( section, entry, emptystringW,
1308 buffer, sizeof(buffer)/sizeof(WCHAR),
1309 filename )))
Andreas Mohrc8dcafc2002-02-27 18:49:06 +00001310 return def_val;
Stefan Leichterb5695082003-03-23 20:03:13 +00001311
1312 if (len+1 == sizeof(buffer)/sizeof(WCHAR)) FIXME("result may be wrong!");
1313
Andreas Mohrc8dcafc2002-02-27 18:49:06 +00001314 /* FIXME: if entry can be found but it's empty, then Win16 is
1315 * supposed to return 0 instead of def_val ! Difficult/problematic
1316 * to implement (every other failure also returns zero buffer),
1317 * thus wait until testing framework avail for making sure nothing
1318 * else gets broken that way. */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001319 if (!buffer[0]) return (UINT)def_val;
Andreas Mohrc8dcafc2002-02-27 18:49:06 +00001320
Stefan Leichterb5695082003-03-23 20:03:13 +00001321 RtlInitUnicodeString( &bufferW, buffer );
1322 RtlUnicodeStringToInteger( &bufferW, 10, &result);
1323 return result;
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001324}
1325
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001326/***********************************************************************
Stefan Leichterb5695082003-03-23 20:03:13 +00001327 * GetPrivateProfileIntA (KERNEL32.@)
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001328 *
1329 * FIXME: rewrite using unicode
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001330 */
Stefan Leichterb5695082003-03-23 20:03:13 +00001331UINT WINAPI GetPrivateProfileIntA( LPCSTR section, LPCSTR entry,
1332 INT def_val, LPCSTR filename )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001333{
Stefan Leichterb5695082003-03-23 20:03:13 +00001334 UNICODE_STRING entryW, filenameW, sectionW;
1335 UINT res;
1336 if(entry) RtlCreateUnicodeStringFromAsciiz(&entryW, entry);
1337 else entryW.Buffer = NULL;
1338 if(filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
1339 else filenameW.Buffer = NULL;
1340 if(section) RtlCreateUnicodeStringFromAsciiz(&sectionW, section);
1341 else sectionW.Buffer = NULL;
1342 res = GetPrivateProfileIntW(sectionW.Buffer, entryW.Buffer, def_val,
1343 filenameW.Buffer);
1344 RtlFreeUnicodeString(&sectionW);
1345 RtlFreeUnicodeString(&filenameW);
1346 RtlFreeUnicodeString(&entryW);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001347 return res;
1348}
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001349
1350/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001351 * GetPrivateProfileSection (KERNEL.418)
Ulrich Weigand8228bd61999-04-22 09:56:09 +00001352 */
1353INT16 WINAPI GetPrivateProfileSection16( LPCSTR section, LPSTR buffer,
1354 UINT16 len, LPCSTR filename )
1355{
1356 return GetPrivateProfileSectionA( section, buffer, len, filename );
1357}
1358
1359/***********************************************************************
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001360 * GetPrivateProfileSectionW (KERNEL32.@)
Alexandre Julliard77b99181997-09-14 17:17:23 +00001361 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001362INT WINAPI GetPrivateProfileSectionW( LPCWSTR section, LPWSTR buffer,
1363 DWORD len, LPCWSTR filename )
Alexandre Julliard77b99181997-09-14 17:17:23 +00001364{
Eric Poueched155751999-03-25 13:24:08 +00001365 int ret = 0;
1366
1367 EnterCriticalSection( &PROFILE_CritSect );
1368
Alexandre Julliard77b99181997-09-14 17:17:23 +00001369 if (PROFILE_Open( filename ))
Eric Poueched155751999-03-25 13:24:08 +00001370 ret = PROFILE_GetSection(CurProfile->section, section, buffer, len,
1371 FALSE, TRUE);
Vincent Béron9a624912002-05-31 23:06:46 +00001372
Eric Poueched155751999-03-25 13:24:08 +00001373 LeaveCriticalSection( &PROFILE_CritSect );
Alexandre Julliarda845b881998-06-01 10:44:35 +00001374
Marcus Meissner264360f1999-05-08 10:02:05 +00001375 return ret;
Alexandre Julliard77b99181997-09-14 17:17:23 +00001376}
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001377
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001378/***********************************************************************
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001379 * GetPrivateProfileSectionA (KERNEL32.@)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001380 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001381INT WINAPI GetPrivateProfileSectionA( LPCSTR section, LPSTR buffer,
1382 DWORD len, LPCSTR filename )
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001383{
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001384 UNICODE_STRING sectionW, filenameW;
1385 LPWSTR bufferW;
1386 INT retW, ret = 0;
1387
1388 bufferW = buffer ? HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)) : NULL;
1389 if (section) RtlCreateUnicodeStringFromAsciiz(&sectionW, section);
1390 else sectionW.Buffer = NULL;
1391 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
1392 else filenameW.Buffer = NULL;
1393
1394 retW = GetPrivateProfileSectionW(sectionW.Buffer, bufferW, len, filenameW.Buffer);
1395 if (len > 2)
1396 {
1397 ret = WideCharToMultiByte(CP_ACP, 0, bufferW, retW + 2, buffer, len, NULL, NULL);
1398 if (ret > 2)
1399 ret -= 2;
1400 else
1401 {
1402 ret = 0;
1403 buffer[len-2] = 0;
1404 buffer[len-1] = 0;
1405 }
1406 }
1407 else
1408 {
1409 buffer[0] = 0;
1410 buffer[1] = 0;
1411 }
1412
1413 RtlFreeUnicodeString(&sectionW);
1414 RtlFreeUnicodeString(&filenameW);
1415 if (bufferW) HeapFree(GetProcessHeap(), 0, bufferW);
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001416 return ret;
1417}
1418
1419/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001420 * GetProfileSection (KERNEL.419)
Ulrich Weigand8228bd61999-04-22 09:56:09 +00001421 */
1422INT16 WINAPI GetProfileSection16( LPCSTR section, LPSTR buffer, UINT16 len )
1423{
1424 return GetPrivateProfileSection16( section, buffer, len, "win.ini" );
1425}
1426
1427/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001428 * GetProfileSectionA (KERNEL32.@)
Ulrich Weigand8228bd61999-04-22 09:56:09 +00001429 */
1430INT WINAPI GetProfileSectionA( LPCSTR section, LPSTR buffer, DWORD len )
1431{
1432 return GetPrivateProfileSectionA( section, buffer, len, "win.ini" );
1433}
1434
1435/***********************************************************************
Patrik Stridvall3ca98232001-06-20 23:03:14 +00001436 * GetProfileSectionW (KERNEL32.@)
Ulrich Weigand8228bd61999-04-22 09:56:09 +00001437 */
1438INT WINAPI GetProfileSectionW( LPCWSTR section, LPWSTR buffer, DWORD len )
1439{
Ulrich Weigand8228bd61999-04-22 09:56:09 +00001440 return GetPrivateProfileSectionW( section, buffer, len, wininiW );
1441}
1442
1443
1444/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001445 * WritePrivateProfileString (KERNEL.129)
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001446 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001447BOOL16 WINAPI WritePrivateProfileString16( LPCSTR section, LPCSTR entry,
1448 LPCSTR string, LPCSTR filename )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001449{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001450 return WritePrivateProfileStringA(section,entry,string,filename);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001451}
1452
1453/***********************************************************************
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001454 * WritePrivateProfileStringW (KERNEL32.@)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001455 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001456BOOL WINAPI WritePrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
1457 LPCWSTR string, LPCWSTR filename )
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001458{
Alexandre Julliarde61b7921999-07-31 19:24:11 +00001459 BOOL ret = FALSE;
Eric Poueched155751999-03-25 13:24:08 +00001460
1461 EnterCriticalSection( &PROFILE_CritSect );
1462
Alexandre Julliarde61b7921999-07-31 19:24:11 +00001463 if (PROFILE_Open( filename ))
1464 {
Andreas Mohrf3598952001-10-02 17:49:20 +00001465 if (!section && !entry && !string) /* documented "file flush" case */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001466 {
1467 PROFILE_FlushFile();
Alexandre Julliarde61b7921999-07-31 19:24:11 +00001468 PROFILE_ReleaseFile(); /* always return FALSE in this case */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001469 }
Marcus Meissner4589a072002-01-21 23:36:53 +00001470 else {
1471 if (!section) {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001472 FIXME("(NULL?,%s,%s,%s)?\n",
1473 debugstr_w(entry), debugstr_w(string), debugstr_w(filename));
Marcus Meissner4589a072002-01-21 23:36:53 +00001474 } else {
Gerhard Gruber024a0ac2002-02-05 19:44:54 +00001475 ret = PROFILE_SetString( section, entry, string, FALSE);
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001476 PROFILE_FlushFile();
Marcus Meissner4589a072002-01-21 23:36:53 +00001477 }
1478 }
Eric Poueched155751999-03-25 13:24:08 +00001479 }
1480
1481 LeaveCriticalSection( &PROFILE_CritSect );
Eric Poueched155751999-03-25 13:24:08 +00001482 return ret;
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001483}
1484
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001485/***********************************************************************
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001486 * WritePrivateProfileStringA (KERNEL32.@)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001487 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001488BOOL WINAPI WritePrivateProfileStringA( LPCSTR section, LPCSTR entry,
1489 LPCSTR string, LPCSTR filename )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001490{
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001491 UNICODE_STRING sectionW, entryW, stringW, filenameW;
1492 BOOL ret;
1493
1494 if (section) RtlCreateUnicodeStringFromAsciiz(&sectionW, section);
1495 else sectionW.Buffer = NULL;
1496 if (entry) RtlCreateUnicodeStringFromAsciiz(&entryW, entry);
1497 else entryW.Buffer = NULL;
1498 if (string) RtlCreateUnicodeStringFromAsciiz(&stringW, string);
1499 else stringW.Buffer = NULL;
1500 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
1501 else filenameW.Buffer = NULL;
1502
1503 ret = WritePrivateProfileStringW(sectionW.Buffer, entryW.Buffer,
1504 stringW.Buffer, filenameW.Buffer);
1505 RtlFreeUnicodeString(&sectionW);
1506 RtlFreeUnicodeString(&entryW);
1507 RtlFreeUnicodeString(&stringW);
1508 RtlFreeUnicodeString(&filenameW);
1509 return ret;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001510}
1511
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00001512/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001513 * WritePrivateProfileSection (KERNEL.416)
Ulrich Weigand8228bd61999-04-22 09:56:09 +00001514 */
Vincent Béron9a624912002-05-31 23:06:46 +00001515BOOL16 WINAPI WritePrivateProfileSection16( LPCSTR section,
Ulrich Weigand8228bd61999-04-22 09:56:09 +00001516 LPCSTR string, LPCSTR filename )
1517{
1518 return WritePrivateProfileSectionA( section, string, filename );
1519}
1520
1521/***********************************************************************
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001522 * WritePrivateProfileSectionW (KERNEL32.@)
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00001523 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001524BOOL WINAPI WritePrivateProfileSectionW( LPCWSTR section,
1525 LPCWSTR string, LPCWSTR filename )
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00001526{
Rein Klazes7458be02000-01-05 01:42:51 +00001527 BOOL ret = FALSE;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001528 LPWSTR p;
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00001529
Rein Klazes7458be02000-01-05 01:42:51 +00001530 EnterCriticalSection( &PROFILE_CritSect );
1531
1532 if (PROFILE_Open( filename )) {
Marcus Meissner25e74032000-11-26 22:36:19 +00001533 if (!section && !string)
Rein Klazes7458be02000-01-05 01:42:51 +00001534 PROFILE_ReleaseFile(); /* always return FALSE in this case */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001535 else if (!string) {/* delete the named section*/
Gerhard Gruber024a0ac2002-02-05 19:44:54 +00001536 ret = PROFILE_SetString(section,NULL,NULL, FALSE);
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001537 PROFILE_FlushFile();
1538 } else {
Uwe Bonnesd88fbb72000-06-20 20:48:46 +00001539 PROFILE_DeleteAllKeys(section);
1540 ret = TRUE;
1541 while(*string) {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001542 LPWSTR buf = HeapAlloc( GetProcessHeap(), 0, (strlenW(string)+1) * sizeof(WCHAR) );
1543 strcpyW( buf, string );
1544 if((p = strchrW( buf, '='))) {
Rein Klazes7458be02000-01-05 01:42:51 +00001545 *p='\0';
Gerhard Gruber024a0ac2002-02-05 19:44:54 +00001546 ret = PROFILE_SetString( section, buf, p+1, TRUE);
Rein Klazes7458be02000-01-05 01:42:51 +00001547 }
1548 HeapFree( GetProcessHeap(), 0, buf );
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001549 string += strlenW(string)+1;
Rein Klazes7458be02000-01-05 01:42:51 +00001550 }
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001551 PROFILE_FlushFile();
Rein Klazes7458be02000-01-05 01:42:51 +00001552 }
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00001553 }
Rein Klazes7458be02000-01-05 01:42:51 +00001554
1555 LeaveCriticalSection( &PROFILE_CritSect );
1556 return ret;
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00001557}
1558
Alexandre Julliarda845b881998-06-01 10:44:35 +00001559/***********************************************************************
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001560 * WritePrivateProfileSectionA (KERNEL32.@)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001561 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001562BOOL WINAPI WritePrivateProfileSectionA( LPCSTR section,
1563 LPCSTR string, LPCSTR filename)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001564
1565{
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001566 UNICODE_STRING sectionW, filenameW;
1567 LPWSTR stringW;
1568 BOOL ret;
1569
1570 if (string)
1571 {
1572 INT lenA, lenW;
1573 LPCSTR p = string;
1574
1575 while(*p) p += strlen(p) + 1;
1576 lenA = p - string + 1;
1577 lenW = MultiByteToWideChar(CP_ACP, 0, string, lenA, NULL, 0);
1578 if ((stringW = HeapAlloc(GetProcessHeap(), 0, lenW * sizeof(WCHAR))))
1579 MultiByteToWideChar(CP_ACP, 0, string, lenA, stringW, lenW);
1580 }
1581 else stringW = NULL;
1582 if (section) RtlCreateUnicodeStringFromAsciiz(&sectionW, section);
1583 else sectionW.Buffer = NULL;
1584 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
1585 else filenameW.Buffer = NULL;
1586
1587 ret = WritePrivateProfileSectionW(sectionW.Buffer, stringW, filenameW.Buffer);
1588
1589 HeapFree(GetProcessHeap(), 0, stringW);
1590 RtlFreeUnicodeString(&sectionW);
1591 RtlFreeUnicodeString(&filenameW);
1592 return ret;
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001593}
1594
Ulrich Weigand8228bd61999-04-22 09:56:09 +00001595/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001596 * WriteProfileSection (KERNEL.417)
Ulrich Weigand8228bd61999-04-22 09:56:09 +00001597 */
1598BOOL16 WINAPI WriteProfileSection16( LPCSTR section, LPCSTR keys_n_values)
1599{
1600 return WritePrivateProfileSection16( section, keys_n_values, "win.ini");
1601}
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001602
1603/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001604 * WriteProfileSectionA (KERNEL32.@)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001605 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001606BOOL WINAPI WriteProfileSectionA( LPCSTR section, LPCSTR keys_n_values)
Vincent Béron9a624912002-05-31 23:06:46 +00001607
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001608{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001609 return WritePrivateProfileSectionA( section, keys_n_values, "win.ini");
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001610}
1611
1612/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001613 * WriteProfileSectionW (KERNEL32.@)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001614 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001615BOOL WINAPI WriteProfileSectionW( LPCWSTR section, LPCWSTR keys_n_values)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001616{
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001617 return WritePrivateProfileSectionW(section, keys_n_values, wininiW);
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001618}
1619
1620/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001621 * GetPrivateProfileSectionNames (KERNEL.143)
Alexandre Julliarda845b881998-06-01 10:44:35 +00001622 */
1623WORD WINAPI GetPrivateProfileSectionNames16( LPSTR buffer, WORD size,
1624 LPCSTR filename )
1625{
Francois Gouget19b05e52001-08-28 18:39:26 +00001626 return GetPrivateProfileSectionNamesA(buffer,size,filename);
Alexandre Julliarda845b881998-06-01 10:44:35 +00001627}
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001628
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001629
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001630/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001631 * GetProfileSectionNames (KERNEL.142)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001632 */
Francois Gouget19b05e52001-08-28 18:39:26 +00001633WORD WINAPI GetProfileSectionNames16(LPSTR buffer, WORD size)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001634
1635{
Francois Gouget19b05e52001-08-28 18:39:26 +00001636 return GetPrivateProfileSectionNamesA(buffer,size,"win.ini");
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001637}
1638
1639
1640/***********************************************************************
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001641 * GetPrivateProfileSectionNamesW (KERNEL32.@)
Francois Gouget19b05e52001-08-28 18:39:26 +00001642 *
1643 * Returns the section names contained in the specified file.
1644 * FIXME: Where do we find this file when the path is relative?
Vincent Béron9a624912002-05-31 23:06:46 +00001645 * The section names are returned as a list of strings with an extra
1646 * '\0' to mark the end of the list. Except for that the behavior
Francois Gouget19b05e52001-08-28 18:39:26 +00001647 * depends on the Windows version.
1648 *
1649 * Win95:
Vincent Béron9a624912002-05-31 23:06:46 +00001650 * - if the buffer is 0 or 1 character long then it is as if it was of
Francois Gouget19b05e52001-08-28 18:39:26 +00001651 * infinite length.
Vincent Béron9a624912002-05-31 23:06:46 +00001652 * - otherwise, if the buffer is to small only the section names that fit
Francois Gouget19b05e52001-08-28 18:39:26 +00001653 * are returned.
Vincent Béron9a624912002-05-31 23:06:46 +00001654 * - note that this means if the buffer was to small to return even just
Francois Gouget19b05e52001-08-28 18:39:26 +00001655 * the first section name then a single '\0' will be returned.
Vincent Béron9a624912002-05-31 23:06:46 +00001656 * - the return value is the number of characters written in the buffer,
Francois Gouget19b05e52001-08-28 18:39:26 +00001657 * except if the buffer was too smal in which case len-2 is returned
1658 *
1659 * Win2000:
Vincent Béron9a624912002-05-31 23:06:46 +00001660 * - if the buffer is 0, 1 or 2 characters long then it is filled with
Francois Gouget19b05e52001-08-28 18:39:26 +00001661 * '\0' and the return value is 0
Vincent Béron9a624912002-05-31 23:06:46 +00001662 * - otherwise if the buffer is too small then the first section name that
1663 * does not fit is truncated so that the string list can be terminated
Francois Gouget19b05e52001-08-28 18:39:26 +00001664 * correctly (double '\0')
Vincent Béron9a624912002-05-31 23:06:46 +00001665 * - the return value is the number of characters written in the buffer
1666 * except for the trailing '\0'. If the buffer is too small, then the
Francois Gouget19b05e52001-08-28 18:39:26 +00001667 * return value is len-2
Vincent Béron9a624912002-05-31 23:06:46 +00001668 * - Win2000 has a bug that triggers when the section names and the
1669 * trailing '\0' fit exactly in the buffer. In that case the trailing
Francois Gouget19b05e52001-08-28 18:39:26 +00001670 * '\0' is missing.
1671 *
1672 * Wine implements the observed Win2000 behavior (except for the bug).
1673 *
Vincent Béron9a624912002-05-31 23:06:46 +00001674 * Note that when the buffer is big enough then the return value may be any
Francois Gouget19b05e52001-08-28 18:39:26 +00001675 * value between 1 and len-1 (or len in Win95), including len-2.
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001676 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001677DWORD WINAPI GetPrivateProfileSectionNamesW( LPWSTR buffer, DWORD size,
1678 LPCWSTR filename)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001679{
Francois Gouget19b05e52001-08-28 18:39:26 +00001680 DWORD ret = 0;
1681
1682 EnterCriticalSection( &PROFILE_CritSect );
1683
1684 if (PROFILE_Open( filename ))
1685 ret = PROFILE_GetSectionNames(buffer, size);
1686
1687 LeaveCriticalSection( &PROFILE_CritSect );
1688
1689 return ret;
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001690}
1691
1692
1693/***********************************************************************
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001694 * GetPrivateProfileSectionNamesA (KERNEL32.@)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001695 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001696DWORD WINAPI GetPrivateProfileSectionNamesA( LPSTR buffer, DWORD size,
1697 LPCSTR filename)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001698{
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001699 UNICODE_STRING filenameW;
1700 LPWSTR bufferW;
1701 INT retW, ret = 0;
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001702
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001703 bufferW = buffer ? HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR)) : NULL;
1704 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
1705 else filenameW.Buffer = NULL;
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001706
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001707 retW = GetPrivateProfileSectionNamesW(bufferW, size, filenameW.Buffer);
1708 if (retW && size)
1709 {
1710 ret = WideCharToMultiByte(CP_ACP, 0, bufferW, retW, buffer, size, NULL, NULL);
1711 if (!ret)
1712 {
1713 ret = size;
1714 buffer[size-1] = 0;
1715 }
1716 }
1717
1718 RtlFreeUnicodeString(&filenameW);
1719 if (bufferW) HeapFree(GetProcessHeap(), 0, bufferW);
Francois Gouget19b05e52001-08-28 18:39:26 +00001720 return ret;
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001721}
1722
Ulrich Weigand8228bd61999-04-22 09:56:09 +00001723/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001724 * GetPrivateProfileStruct (KERNEL.407)
Ulrich Weigand8228bd61999-04-22 09:56:09 +00001725 */
Vincent Béron9a624912002-05-31 23:06:46 +00001726BOOL16 WINAPI GetPrivateProfileStruct16(LPCSTR section, LPCSTR key,
Ulrich Weigand8228bd61999-04-22 09:56:09 +00001727 LPVOID buf, UINT16 len, LPCSTR filename)
1728{
1729 return GetPrivateProfileStructA( section, key, buf, len, filename );
1730}
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001731
1732/***********************************************************************
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001733 * GetPrivateProfileStructW (KERNEL32.@)
Andreas Mohr17b1f462000-01-30 21:15:14 +00001734 *
1735 * Should match Win95's behaviour pretty much
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001736 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001737BOOL WINAPI GetPrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1738 LPVOID buf, UINT len, LPCWSTR filename)
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001739{
Eric Poueched155751999-03-25 13:24:08 +00001740 BOOL ret = FALSE;
1741
1742 EnterCriticalSection( &PROFILE_CritSect );
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001743
1744 if (PROFILE_Open( filename )) {
Gerhard Gruber024a0ac2002-02-05 19:44:54 +00001745 PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE, FALSE);
Eric Poueched155751999-03-25 13:24:08 +00001746 if (k) {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001747 TRACE("value (at %p): %s\n", k->value, debugstr_w(k->value));
1748 if (((strlenW(k->value) - 2) / 2) == len)
Andreas Mohr17b1f462000-01-30 21:15:14 +00001749 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001750 LPWSTR end, p;
Andreas Mohr17b1f462000-01-30 21:15:14 +00001751 BOOL valid = TRUE;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001752 WCHAR c;
Andreas Mohr17b1f462000-01-30 21:15:14 +00001753 DWORD chksum = 0;
1754
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001755 end = k->value + strlenW(k->value); /* -> '\0' */
Andreas Mohr17b1f462000-01-30 21:15:14 +00001756 /* check for invalid chars in ASCII coded hex string */
1757 for (p=k->value; p < end; p++)
1758 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001759 if (!isxdigitW(*p))
Andreas Mohr17b1f462000-01-30 21:15:14 +00001760 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001761 WARN("invalid char '%x' in file %s->[%s]->%s !\n",
1762 *p, debugstr_w(filename), debugstr_w(section), debugstr_w(key));
Andreas Mohr17b1f462000-01-30 21:15:14 +00001763 valid = FALSE;
1764 break;
1765 }
1766 }
1767 if (valid)
1768 {
1769 BOOL highnibble = TRUE;
1770 BYTE b = 0, val;
1771 LPBYTE binbuf = (LPBYTE)buf;
Vincent Béron9a624912002-05-31 23:06:46 +00001772
Andreas Mohr17b1f462000-01-30 21:15:14 +00001773 end -= 2; /* don't include checksum in output data */
1774 /* translate ASCII hex format into binary data */
1775 for (p=k->value; p < end; p++)
1776 {
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001777 c = toupperW(*p);
Andreas Mohr17b1f462000-01-30 21:15:14 +00001778 val = (c > '9') ?
1779 (c - 'A' + 10) : (c - '0');
1780
1781 if (highnibble)
1782 b = val << 4;
1783 else
1784 {
1785 b += val;
1786 *binbuf++ = b; /* feed binary data into output */
1787 chksum += b; /* calculate checksum */
1788 }
1789 highnibble ^= 1; /* toggle */
1790 }
1791 /* retrieve stored checksum value */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001792 c = toupperW(*p++);
Andreas Mohr17b1f462000-01-30 21:15:14 +00001793 b = ( (c > '9') ? (c - 'A' + 10) : (c - '0') ) << 4;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001794 c = toupperW(*p);
Andreas Mohr17b1f462000-01-30 21:15:14 +00001795 b += (c > '9') ? (c - 'A' + 10) : (c - '0');
1796 if (b == (chksum & 0xff)) /* checksums match ? */
1797 ret = TRUE;
1798 }
1799 }
Eric Poueched155751999-03-25 13:24:08 +00001800 }
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001801 }
Eric Poueched155751999-03-25 13:24:08 +00001802 LeaveCriticalSection( &PROFILE_CritSect );
1803
Andreas Mohr17b1f462000-01-30 21:15:14 +00001804 return ret;
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001805}
1806
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001807/***********************************************************************
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001808 * GetPrivateProfileStructA (KERNEL32.@)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001809 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001810BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key,
1811 LPVOID buffer, UINT len, LPCSTR filename)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001812{
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001813 UNICODE_STRING sectionW, keyW, filenameW;
1814 INT ret;
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001815
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001816 if (section) RtlCreateUnicodeStringFromAsciiz(&sectionW, section);
1817 else sectionW.Buffer = NULL;
1818 if (key) RtlCreateUnicodeStringFromAsciiz(&keyW, key);
1819 else keyW.Buffer = NULL;
1820 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
1821 else filenameW.Buffer = NULL;
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001822
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001823 ret = GetPrivateProfileStructW(sectionW.Buffer, keyW.Buffer, buffer, len,
1824 filenameW.Buffer);
1825 /* Do not translate binary data. */
1826
1827 RtlFreeUnicodeString(&sectionW);
1828 RtlFreeUnicodeString(&keyW);
1829 RtlFreeUnicodeString(&filenameW);
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001830 return ret;
1831}
1832
1833
1834
Ulrich Weigand8228bd61999-04-22 09:56:09 +00001835/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001836 * WritePrivateProfileStruct (KERNEL.406)
Ulrich Weigand8228bd61999-04-22 09:56:09 +00001837 */
Vincent Béron9a624912002-05-31 23:06:46 +00001838BOOL16 WINAPI WritePrivateProfileStruct16 (LPCSTR section, LPCSTR key,
Ulrich Weigand8228bd61999-04-22 09:56:09 +00001839 LPVOID buf, UINT16 bufsize, LPCSTR filename)
1840{
1841 return WritePrivateProfileStructA( section, key, buf, bufsize, filename );
1842}
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001843
1844/***********************************************************************
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001845 * WritePrivateProfileStructW (KERNEL32.@)
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001846 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001847BOOL WINAPI WritePrivateProfileStructW (LPCWSTR section, LPCWSTR key,
1848 LPVOID buf, UINT bufsize, LPCWSTR filename)
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001849{
Alexandre Julliarde61b7921999-07-31 19:24:11 +00001850 BOOL ret = FALSE;
Andreas Mohr17b1f462000-01-30 21:15:14 +00001851 LPBYTE binbuf;
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001852 LPWSTR outstring, p;
Andreas Mohr17b1f462000-01-30 21:15:14 +00001853 DWORD sum = 0;
Alexandre Julliarde61b7921999-07-31 19:24:11 +00001854
1855 if (!section && !key && !buf) /* flush the cache */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001856 return WritePrivateProfileStringW( NULL, NULL, NULL, filename );
Eric Poueched155751999-03-25 13:24:08 +00001857
Andreas Mohr17b1f462000-01-30 21:15:14 +00001858 /* allocate string buffer for hex chars + checksum hex char + '\0' */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001859 outstring = HeapAlloc( GetProcessHeap(), 0, (bufsize*2 + 2 + 1) * sizeof(WCHAR) );
Andreas Mohr17b1f462000-01-30 21:15:14 +00001860 p = outstring;
1861 for (binbuf = (LPBYTE)buf; binbuf < (LPBYTE)buf+bufsize; binbuf++) {
1862 *p++ = hex[*binbuf >> 4];
1863 *p++ = hex[*binbuf & 0xf];
1864 sum += *binbuf;
1865 }
1866 /* checksum is sum & 0xff */
1867 *p++ = hex[(sum & 0xf0) >> 4];
1868 *p++ = hex[sum & 0xf];
1869 *p++ = '\0';
1870
Eric Poueched155751999-03-25 13:24:08 +00001871 EnterCriticalSection( &PROFILE_CritSect );
1872
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001873 if (PROFILE_Open( filename )) {
Gerhard Gruber024a0ac2002-02-05 19:44:54 +00001874 ret = PROFILE_SetString( section, key, outstring, FALSE);
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001875 PROFILE_FlushFile();
1876 }
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001877
Eric Poueched155751999-03-25 13:24:08 +00001878 LeaveCriticalSection( &PROFILE_CritSect );
1879
Alexandre Julliard90476d62000-02-16 22:47:24 +00001880 HeapFree( GetProcessHeap(), 0, outstring );
Andreas Mohr17b1f462000-01-30 21:15:14 +00001881
Eric Poueched155751999-03-25 13:24:08 +00001882 return ret;
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001883}
1884
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001885/***********************************************************************
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001886 * WritePrivateProfileStructA (KERNEL32.@)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001887 */
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001888BOOL WINAPI WritePrivateProfileStructA (LPCSTR section, LPCSTR key,
1889 LPVOID buf, UINT bufsize, LPCSTR filename)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001890{
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001891 UNICODE_STRING sectionW, keyW, filenameW;
1892 INT ret;
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001893
Dmitry Timoshkovd75aed22002-08-27 01:13:58 +00001894 if (section) RtlCreateUnicodeStringFromAsciiz(&sectionW, section);
1895 else sectionW.Buffer = NULL;
1896 if (key) RtlCreateUnicodeStringFromAsciiz(&keyW, key);
1897 else keyW.Buffer = NULL;
1898 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename);
1899 else filenameW.Buffer = NULL;
1900
1901 /* Do not translate binary data. */
1902 ret = WritePrivateProfileStructW(sectionW.Buffer, keyW.Buffer, buf, bufsize,
1903 filenameW.Buffer);
1904
1905 RtlFreeUnicodeString(&sectionW);
1906 RtlFreeUnicodeString(&keyW);
1907 RtlFreeUnicodeString(&filenameW);
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001908 return ret;
1909}
1910
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001911
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001912/***********************************************************************
1913 * WriteOutProfiles (KERNEL.315)
1914 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001915void WINAPI WriteOutProfiles16(void)
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001916{
Eric Poueched155751999-03-25 13:24:08 +00001917 EnterCriticalSection( &PROFILE_CritSect );
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001918 PROFILE_FlushFile();
Eric Poueched155751999-03-25 13:24:08 +00001919 LeaveCriticalSection( &PROFILE_CritSect );
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001920}
Marcus Meissner9b4fcf71999-12-04 04:19:55 +00001921
1922/***********************************************************************
Patrik Stridvall044855c2001-07-11 18:56:41 +00001923 * CloseProfileUserMapping (KERNEL32.@)
Marcus Meissner9b4fcf71999-12-04 04:19:55 +00001924 */
1925BOOL WINAPI CloseProfileUserMapping(void) {
1926 FIXME("(), stub!\n");
1927 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1928 return FALSE;
1929}