Release 960114
[wine/gsoc-2012-control.git] / misc / profile.c
blob4790c0155486a211aff5630de10d5cbfaf697b90
1 /*
2 * Initialization-File Functions.
4 * Copyright (c) 1993 Miguel de Icaza
6 * 1/Dec o Corrected return values for Get*ProfileString
8 * o Now, if AppName == NULL in Get*ProfileString it returns a list
9 * of the KeyNames (as documented in the MS-SDK).
11 * o if KeyValue == NULL now clears the value in Get*ProfileString
13 * 20/Apr SL - I'm not sure where these definitions came from, but my SDK
14 * has a NULL KeyValue returning a list of KeyNames, and a NULL
15 * AppName undefined. I changed GetSetProfile to match. This makes
16 * PROGMAN.EXE do the right thing.
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <ctype.h>
23 #include "wine.h"
24 #include "windows.h"
25 #include "dos_fs.h"
26 #include "toolhelp.h"
27 #include "stddebug.h"
28 #include "debug.h"
29 #include "xmalloc.h"
31 #define STRSIZE 255
33 typedef struct TKeys {
34 char *KeyName;
35 char *Value;
36 struct TKeys *link;
37 } TKeys;
39 typedef struct TSecHeader {
40 char *AppName;
41 TKeys *Keys;
42 struct TSecHeader *link;
43 } TSecHeader;
45 typedef struct TProfile {
46 char *FileName;
47 char *FullName;
48 TSecHeader *Section;
49 struct TProfile *link;
50 int changed;
51 } TProfile;
53 TProfile *Current = 0;
54 TProfile *Base = 0;
56 static TSecHeader *is_loaded (char *FileName)
58 TProfile *p = Base;
60 while (p){
61 if (!lstrcmpi( FileName, p->FileName)){
62 Current = p;
63 return p->Section;
65 p = p->link;
67 return 0;
70 #define WIN_INI WinIniFileName()
72 static char *WinIniFileName(void)
74 static char *name = NULL;
75 int len;
76 const char *unixName;
78 if (name) return name;
80 len = GetWindowsDirectory( NULL, 0 ) + 9;
81 name = xmalloc( len );
82 GetWindowsDirectory( name, len );
83 strcat( name, "/win.ini" );
84 if (!(unixName = DOSFS_GetUnixFileName( name, TRUE ))) return NULL;
85 free( name );
86 name = strdup( unixName );
87 return name;
90 static char *GetIniFileName(char *name, char *dir)
92 char temp[256];
94 if (strchr(name, '/'))
95 return name;
97 if (strlen(dir)) {
98 strcpy(temp, dir);
99 strcat(temp, "\\");
100 strcat(temp, name);
102 else
103 strcpy(temp, name);
104 return DOSFS_GetUnixFileName(temp,TRUE);
107 static TSecHeader *load (char *filename, char **pfullname)
109 FILE *f;
110 TSecHeader *SecHeader = 0;
111 char CharBuffer [STRSIZE];
112 char *bufptr;
113 char *lastnonspc;
114 int bufsize;
115 char *file, *purefilename;
116 int c;
117 char path[MAX_PATH+1];
118 BOOL firstbrace;
120 *pfullname = NULL;
122 dprintf_profile(stddeb,"Trying to load file %s \n", filename);
124 /* First try it as is */
125 file = GetIniFileName(filename, "");
126 if (!file || !(f = fopen(file, "r")))
128 if ((purefilename = strrchr( filename, '\\' )))
129 purefilename++;
130 else if ((purefilename = strrchr( filename, '/' )))
131 purefilename++;
132 else
133 purefilename = filename;
135 /* Now try the Windows directory */
136 GetWindowsDirectory(path, sizeof(path));
137 if ((file = GetIniFileName(purefilename, path)))
139 dprintf_profile(stddeb,"Trying to load in windows directory file %s\n",
140 file);
141 f = fopen(file, "r");
143 else f = NULL;
145 if (f == NULL)
146 { /* Try the path of the current executable */
148 if (GetCurrentTask())
150 char *p;
151 GetModuleFileName( GetCurrentTask(), path, MAX_PATH );
152 if ((p = strrchr( path, '\\' )))
154 p[0] = '\0'; /* Remove trailing slash */
155 if ((file = GetIniFileName(purefilename, path)))
157 dprintf_profile(stddeb,
158 "Trying to load in current directory%s\n",
159 file);
160 f = fopen(file, "r");
165 if (f == NULL) { /* And now in $HOME/.wine */
167 strcpy(path,getenv("HOME"));
168 strcat(path, "/.wine/");
169 strcat(path, purefilename);
170 dprintf_profile(stddeb,"Trying to load in user-directory %s\n", path);
171 file = path;
172 f = fopen(file, "r");
175 if (f == NULL) {
176 /* FIXED: we ought to create it now (in which directory?) */
177 /* lets do it in ~/.wine */
178 strcpy(path,getenv("HOME"));
179 strcat(path, "/.wine/");
180 strcat(path, purefilename);
181 dprintf_profile(stddeb,"Creating %s\n", path);
182 file = path;
183 f = fopen(file, "w+");
184 if (f == NULL) {
185 fprintf(stderr, "profile.c: load() can't find file %s\n", filename);
186 return NULL;
191 *pfullname = xstrdup(file);
192 dprintf_profile(stddeb,"Loading %s\n", file);
194 firstbrace = TRUE;
195 for(;;) {
196 c = fgetc(f);
197 if (c == EOF) goto finished;
199 if (isspace(c))
200 continue;
201 if (c == ';') {
202 do {
203 c = fgetc(f);
204 } while (!(c == EOF || c == '\n'));
205 if (c == EOF) goto finished;
207 if (c == '[') {
208 TSecHeader *temp = SecHeader;
210 SecHeader = (TSecHeader *) xmalloc (sizeof (TSecHeader));
211 SecHeader->link = temp;
212 SecHeader->Keys = NULL;
213 do {
214 c = fgetc(f);
215 if (c == EOF) goto bad_file;
216 } while (isspace(c));
217 bufptr = lastnonspc = CharBuffer;
218 bufsize = 0;
219 do {
220 if (c != ']') {
221 bufsize++;
222 *bufptr++ = c;
223 if (!isspace(c))
224 lastnonspc = bufptr;
225 } else
226 break;
227 c = fgetc(f);
228 if (c == EOF) goto bad_file;
229 } while(bufsize < STRSIZE-1);
230 *lastnonspc = 0;
231 if (!strlen(CharBuffer))
232 fprintf(stderr, "warning: empty section name in ini file\n");
233 SecHeader->AppName = xstrdup (CharBuffer);
234 dprintf_profile(stddeb,"%s: section %s\n", file, CharBuffer);
235 firstbrace = FALSE;
236 } else if (SecHeader) {
237 TKeys *temp = SecHeader->Keys;
238 BOOL skipspc;
240 if (firstbrace)
241 goto bad_file;
242 bufptr = lastnonspc = CharBuffer;
243 bufsize = 0;
244 do {
245 if (c != '=') {
246 bufsize++;
247 *bufptr++ = c;
248 if (!isspace(c))
249 lastnonspc = bufptr;
250 } else
251 break;
252 c = fgetc(f);
253 if (c == EOF) goto bad_file;
254 } while(bufsize < STRSIZE-1);
255 *lastnonspc = 0;
256 if (!strlen(CharBuffer))
257 fprintf(stderr, "warning: empty key name in ini file\n");
258 SecHeader->Keys = (TKeys *) xmalloc (sizeof (TKeys));
259 SecHeader->Keys->link = temp;
260 SecHeader->Keys->KeyName = xstrdup (CharBuffer);
262 dprintf_profile(stddeb,"%s: key %s\n", file, CharBuffer);
264 bufptr = lastnonspc = CharBuffer;
265 bufsize = 0;
266 skipspc = TRUE;
267 do {
268 c = fgetc(f);
269 if (c == EOF || c == '\n') break;
270 if (!isspace(c) || !skipspc) {
271 skipspc = FALSE;
272 bufsize++;
273 *bufptr++ = c;
274 if (!isspace(c))
275 lastnonspc = bufptr;
277 } while(bufsize < STRSIZE-1);
278 *lastnonspc = 0;
279 SecHeader->Keys->Value = xstrdup (CharBuffer);
280 dprintf_profile (stddeb, "[%s] (%s)=%s\n", SecHeader->AppName,
281 SecHeader->Keys->KeyName, SecHeader->Keys->Value);
282 if (c == ';') {
283 do {
284 c = fgetc(f);
285 } while (!(c == EOF || c == '\n'));
286 if (c == EOF)
287 goto finished;
292 bad_file:
293 fprintf(stderr, "warning: bad ini file\n");
294 finished:
295 return SecHeader;
298 static void new_key (TSecHeader *section, char *KeyName, char *Value)
300 TKeys *key;
302 key = (TKeys *) xmalloc (sizeof (TKeys));
303 key->KeyName = xstrdup (KeyName);
304 key->Value = xstrdup (Value);
305 key->link = section->Keys;
306 section->Keys = key;
309 static short GetSetProfile (int set, LPSTR AppName, LPSTR KeyName,
310 LPSTR Default, LPSTR ReturnedString, short Size,
311 LPSTR FileName)
314 TProfile *New;
315 TSecHeader *section;
316 TKeys *key;
318 /* Supposedly Default should NEVER be NULL. But sometimes it is. */
319 if (Default == NULL)
320 Default = "";
322 if (!(section = is_loaded (FileName))){
323 New = (TProfile *) xmalloc (sizeof (TProfile));
324 New->link = Base;
325 New->FileName = xstrdup (FileName);
326 New->Section = load (FileName, &New->FullName);
327 New->changed = FALSE;
328 Base = New;
329 section = New->Section;
330 Current = New;
333 /* Start search */
334 for (; section; section = section->link){
335 if (lstrcmpi(section->AppName, AppName))
336 continue;
338 /* If no key value given, then list all the keys */
339 if ((!KeyName) && (!set)){
340 char *p = ReturnedString;
341 int left = Size - 2;
342 int slen;
344 dprintf_profile(stddeb,"GetSetProfile // KeyName == NULL, Enumeration !\n");
345 for (key = section->Keys; key; key = key->link){
346 if (left < 1) {
347 dprintf_profile(stddeb,"GetSetProfile // No more storage for enum !\n");
348 return Size - 2;
350 slen = MIN(strlen(key->KeyName) + 1, left);
351 lstrcpyn(p, key->KeyName, slen);
352 dprintf_profile(stddeb,"GetSetProfile // enum '%s' !\n", p);
353 left -= slen;
354 p += slen;
356 *p = '\0';
357 return Size - 2 - left;
359 for (key = section->Keys; key; key = key->link){
360 int slen;
361 if (lstrcmpi(key->KeyName, KeyName))
362 continue;
363 if (set){
364 free (key->Value);
365 key->Value = xstrdup (Default ? Default : "");
366 Current->changed=TRUE;
367 return 1;
369 slen = MIN(strlen(key->Value)+1, Size);
370 lstrcpyn(ReturnedString, key->Value, slen);
371 dprintf_profile(stddeb,"GetSetProfile // Return ``%s''\n", ReturnedString);
372 return 1;
374 /* If Getting the information, then don't write the information
375 to the INI file, need to run a couple of tests with windog */
376 /* No key found */
377 if (set) {
378 new_key (section, KeyName, Default);
379 } else {
380 int slen = MIN(strlen(Default)+1, Size);
381 lstrcpyn(ReturnedString, Default, slen);
382 dprintf_profile(stddeb,"GetSetProfile // Key not found\n");
384 return 1;
387 /* Non existent section */
388 if (set){
389 section = (TSecHeader *) xmalloc (sizeof (TSecHeader));
390 section->AppName = xstrdup (AppName);
391 section->Keys = 0;
392 new_key (section, KeyName, Default);
393 section->link = Current->Section;
394 Current->Section = section;
395 Current->changed = TRUE;
396 } else {
397 int slen = MIN(strlen(Default)+1, Size);
398 lstrcpyn(ReturnedString, Default, slen);
399 dprintf_profile(stddeb,"GetSetProfile // Section not found\n");
401 return 1;
404 short GetPrivateProfileString (LPCSTR AppName, LPCSTR KeyName,
405 LPCSTR Default, LPSTR ReturnedString,
406 short Size, LPCSTR FileName)
408 int v;
410 dprintf_profile(stddeb,"GetPrivateProfileString ('%s', '%s', '%s', %p, %d, %s\n",
411 AppName, KeyName, Default, ReturnedString, Size, FileName);
412 v = GetSetProfile (0,AppName,KeyName,Default,ReturnedString,Size,FileName);
413 if (AppName)
414 return strlen (ReturnedString);
415 else
416 return Size - v;
419 int GetProfileString (LPCSTR AppName, LPCSTR KeyName, LPCSTR Default,
420 LPSTR ReturnedString, int Size)
422 return GetPrivateProfileString (AppName, KeyName, Default,
423 ReturnedString, Size, WIN_INI );
426 WORD GetPrivateProfileInt (LPCSTR AppName, LPCSTR KeyName, short Default,
427 LPCSTR File)
429 static char IntBuf[10];
430 static char buf[10];
432 sprintf (buf, "%d", Default);
434 /* Check the exact semantic with the SDK */
435 GetPrivateProfileString (AppName, KeyName, buf, IntBuf, 10, File);
436 if (!lstrcmpi(IntBuf, "true"))
437 return 1;
438 if (!lstrcmpi(IntBuf, "yes"))
439 return 1;
440 return strtoul( IntBuf, NULL, 0 );
443 WORD GetProfileInt (LPCSTR AppName, LPCSTR KeyName, int Default)
445 return GetPrivateProfileInt (AppName, KeyName, Default, WIN_INI);
448 BOOL WritePrivateProfileString (LPSTR AppName, LPSTR KeyName, LPSTR String,
449 LPSTR FileName)
451 if (!AppName || !KeyName || !String) /* Flush file to disk */
452 return TRUE;
453 return GetSetProfile (1, AppName, KeyName, String, "", 0, FileName);
456 BOOL WriteProfileString (LPSTR AppName, LPSTR KeyName, LPSTR String)
458 return (WritePrivateProfileString (AppName, KeyName, String, WIN_INI));
461 static void dump_keys (FILE *profile, TKeys *p)
463 if (!p)
464 return;
465 dump_keys (profile, p->link);
466 fprintf (profile, "%s=%s\r\n", p->KeyName, p->Value);
469 static void dump_sections (FILE *profile, TSecHeader *p)
471 if (!p)
472 return;
473 dump_sections (profile, p->link);
474 fprintf (profile, "\r\n[%s]\r\n", p->AppName);
475 dump_keys (profile, p->Keys);
478 static void dump_profile (TProfile *p)
480 FILE *profile;
482 if (!p)
483 return;
484 dump_profile (p->link);
485 if(!p->changed)
486 return;
487 if (p->FullName && (profile = fopen (p->FullName, "w")) != NULL){
488 dump_sections (profile, p->Section);
489 fclose (profile);
493 void sync_profiles (void)
495 dump_profile (Base);