- Fix KiDispatchException to unmask KI_EXCEPTION_INTERNAL when setting the exception...
[reactos.git] / rosapps / mc / src / profile.c
1 /*
2 * Initialization-File Functions.
3 *
4 * From the Wine project
5
6 Copyright (C) 1993, 1994 Miguel de Icaza.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 /* "$Id$" */
24
25 #include <config.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <stdlib.h> /* For free() and atoi() */
29 #include <sys/types.h>
30 #include "mad.h"
31 #include "util.h"
32 #include "global.h"
33 #include "profile.h"
34
35 #define INIFILE "xxx.ini"
36 #define STRSIZE 4096
37 #define overflow (next == &CharBuffer [STRSIZE-1])
38
39 enum { FirstBrace, OnSecHeader, IgnoreToEOL, KeyDef, KeyDefOnKey, KeyValue };
40
41 typedef struct TKeys {
42 char *KeyName;
43 char *Value;
44 struct TKeys *link;
45 } TKeys;
46
47 typedef struct TSecHeader {
48 char *AppName;
49 TKeys *Keys;
50 struct TSecHeader *link;
51 } TSecHeader;
52
53 typedef struct TProfile {
54 char *FileName;
55 TSecHeader *Section;
56 struct TProfile *link;
57 } TProfile;
58
59 TProfile *Current = 0;
60 TProfile *Base = 0;
61
62 static int is_loaded (char *FileName, TSecHeader **section)
63 {
64 TProfile *p = Base;
65
66 while (p){
67 if (!strcasecmp (FileName, p->FileName)){
68 Current = p;
69 *section = p->Section;
70 return 1;
71 }
72 p = p->link;
73 }
74 return 0;
75 }
76
77 #define TRANSLATION_CHAR '\200'
78
79 char *str_untranslate_newline_dup (char *s)
80 {
81 int l = 0;
82 char *p = s, *q;
83 while (*p) {
84 l++;
85 l += (*p == '\n' || *p == TRANSLATION_CHAR);
86 p++;
87 }
88 q = p = malloc (l + 1);
89 if (!q)
90 return 0;
91 for (;;) {
92 switch (*s) {
93 case '\n':
94 *p++ = TRANSLATION_CHAR;
95 *p++ = 'n';
96 break;
97 case TRANSLATION_CHAR:
98 if (s[1] == 'n' || s[1] == TRANSLATION_CHAR)
99 *p++ = TRANSLATION_CHAR;
100 *p++ = TRANSLATION_CHAR;
101 break;
102 case '\0':
103 *p = '\0';
104 return q;
105 break;
106 default:
107 *p++ = *s;
108 }
109 s++;
110 }
111 return 0; /* not reached */
112 }
113
114 char *str_translate_newline_dup (char *s)
115 {
116 char *p, *q;
117 q = p = malloc (strlen (s) + 1);
118 if (!q)
119 return 0;
120 while (*s) {
121 if (*s == TRANSLATION_CHAR) {
122 switch (*(++s)) {
123 case 'n':
124 *p++ = '\n';
125 break;
126 case TRANSLATION_CHAR:
127 *p++ = TRANSLATION_CHAR;
128 break;
129 case '\0':
130 *p++ = TRANSLATION_CHAR;
131 *p++ = '\0';
132 return q;
133 default:
134 *p++ = TRANSLATION_CHAR;
135 *p++ = *s;
136 }
137 } else {
138 *p++ = *s;
139 }
140 s++;
141 }
142 *p = '\0';
143 return q; /* not reached */
144 }
145
146 static TSecHeader *load (char *file)
147 {
148 FILE *f;
149 int state;
150 TSecHeader *SecHeader = 0;
151 char CharBuffer [STRSIZE];
152 char *next = ""; /* Not needed */
153 int c;
154
155 if ((f = fopen (file, "r"))==NULL)
156 return NULL;
157
158 state = FirstBrace;
159 while ((c = getc (f)) != EOF){
160 if (c == '\r') /* Ignore Carriage Return */
161 continue;
162
163 switch (state){
164
165 case OnSecHeader:
166 if (c == ']' || overflow){
167 *next = '\0';
168 next = CharBuffer;
169 SecHeader->AppName = strdup (CharBuffer);
170 state = IgnoreToEOL;
171 } else
172 *next++ = c;
173 break;
174
175 case IgnoreToEOL:
176 if (c == '\n'){
177 state = KeyDef;
178 next = CharBuffer;
179 }
180 break;
181
182 case FirstBrace:
183 case KeyDef:
184 case KeyDefOnKey:
185 if (c == '['){
186 TSecHeader *temp;
187
188 temp = SecHeader;
189 SecHeader = (TSecHeader *) xmalloc (sizeof (TSecHeader),
190 "KeyDef");
191 SecHeader->link = temp;
192 SecHeader->Keys = 0;
193 state = OnSecHeader;
194 next = CharBuffer;
195 break;
196 }
197 if (state == FirstBrace) /* On first pass, don't allow dangling keys */
198 break;
199
200 if ((c == ' ' && state != KeyDefOnKey) || c == '\t')
201 break;
202
203 if (c == '\n' || overflow) /* Abort Definition */
204 next = CharBuffer;
205
206 if (c == '=' || overflow){
207 TKeys *temp;
208
209 temp = SecHeader->Keys;
210 *next = '\0';
211 SecHeader->Keys = (TKeys *) xmalloc (sizeof (TKeys), "KD2");
212 SecHeader->Keys->link = temp;
213 SecHeader->Keys->KeyName = strdup (CharBuffer);
214 state = KeyValue;
215 next = CharBuffer;
216 } else {
217 *next++ = c;
218 state = KeyDefOnKey;
219 }
220 break;
221
222 case KeyValue:
223 if (overflow || c == '\n'){
224 *next = '\0';
225 SecHeader->Keys->Value = str_translate_newline_dup (CharBuffer);
226 state = c == '\n' ? KeyDef : IgnoreToEOL;
227 next = CharBuffer;
228 #ifdef DEBUG
229 printf ("[%s] (%s)=%s\n", SecHeader->AppName,
230 SecHeader->Keys->KeyName, SecHeader->Keys->Value);
231 #endif
232 } else
233 *next++ = c;
234 break;
235
236 } /* switch */
237
238 } /* while ((c = getc (f)) != EOF) */
239 if (c == EOF && state == KeyValue){
240 *next = '\0';
241 SecHeader->Keys->Value = str_translate_newline_dup (CharBuffer);
242 }
243 fclose (f);
244 return SecHeader;
245 }
246
247 static void new_key (TSecHeader *section, char *KeyName, char *Value)
248 {
249 TKeys *key;
250
251 key = (TKeys *) xmalloc (sizeof (TKeys), "new_key");
252 key->KeyName = strdup (KeyName);
253 key->Value = strdup (Value);
254 key->link = section->Keys;
255 section->Keys = key;
256 }
257
258 char *GetSetProfileChar (int set, char *AppName, char *KeyName,
259 char *Default, char *FileName)
260 {
261
262 TProfile *New;
263 TSecHeader *section;
264 TKeys *key;
265
266 if (!is_loaded (FileName, &section)){
267 New = (TProfile *) xmalloc (sizeof (TProfile), "GetSetProfile");
268 New->link = Base;
269 New->FileName = strdup (FileName);
270 New->Section = load (FileName);
271 Base = New;
272 section = New->Section;
273 Current = New;
274 }
275
276 /* Start search */
277 for (; section; section = section->link){
278 if (section->AppName == 0 || strcasecmp (section->AppName, AppName))
279 continue;
280 for (key = section->Keys; key; key = key->link){
281 if (strcasecmp (key->KeyName, KeyName))
282 continue;
283 if (set){
284 free (key->Value);
285 key->Value = strdup (Default);
286 }
287 return key->Value;
288 }
289 /* If getting the information, then don't write the information
290 to the INI file, need to run a couple of tests with windog */
291 /* No key found */
292 if (set){
293 new_key (section, KeyName, Default);
294 return 0;
295 }
296 }
297
298 /* Non existent section */
299 if (set && Default){
300 section = (TSecHeader *) xmalloc (sizeof (TSecHeader), "GSP3");
301 section->AppName = strdup (AppName);
302 section->Keys = 0;
303 new_key (section, KeyName, Default);
304 section->link = Current->Section;
305 Current->Section = section;
306 }
307 return Default;
308 }
309
310 short GetSetProfile (int set, char * AppName, char * KeyName, char * Default,
311 char * ReturnedString, short Size, char * FileName)
312
313 {
314 char *s;
315
316 s = GetSetProfileChar (set, AppName, KeyName, Default, FileName);
317 if (!set){
318 ReturnedString [Size-1] = 0;
319 strncpy (ReturnedString, s, Size-1);
320 }
321 return 1;
322 }
323
324 short GetPrivateProfileString (char * AppName, char * KeyName,
325 char * Default, char * ReturnedString,
326 short Size, char * FileName)
327 {
328 return (GetSetProfile (0, AppName, KeyName, Default, ReturnedString, Size, FileName));
329 }
330
331 char *get_profile_string (char *AppName, char *KeyName, char *Default,
332 char *FileName)
333 {
334 return GetSetProfileChar (0, AppName, KeyName, Default, FileName);
335 }
336
337 #if 0
338 int GetProfileString (char * AppName, char * KeyName, char * Default,
339 char * ReturnedString, int Size)
340 {
341 return GetPrivateProfileString (AppName, KeyName, Default,
342 ReturnedString, Size, INIFILE);
343 }
344 #endif
345
346 int GetPrivateProfileInt (char * AppName, char * KeyName, int Default,
347 char * File)
348 {
349 static char IntBuf [15];
350 static char buf [15];
351
352 sprintf (buf, "%d", Default);
353
354 /* Check the exact semantic with the SDK */
355 GetPrivateProfileString (AppName, KeyName, buf, IntBuf, 15, File);
356 if (!strcasecmp (IntBuf, "true"))
357 return 1;
358 if (!strcasecmp (IntBuf, "yes"))
359 return 1;
360 return atoi (IntBuf);
361 }
362
363 #if 0
364 int GetProfileInt (char * AppName, char * KeyName, int Default)
365 {
366 return GetPrivateProfileInt (AppName, KeyName, Default, INIFILE);
367 }
368 #endif
369
370 int WritePrivateProfileString (char * AppName, char * KeyName, char * String,
371 char * FileName)
372 {
373 return GetSetProfile (1, AppName, KeyName, String, "", 0, FileName);
374 }
375
376 #if 0
377 int WriteProfileString (char * AppName, char * KeyName, char * String)
378 {
379 return (WritePrivateProfileString (AppName, KeyName, String, INIFILE));
380 }
381 #endif
382
383 static void dump_keys (FILE * profile, TKeys * p)
384 {
385 char *t;
386 if (!p)
387 return;
388 dump_keys (profile, p->link);
389 t = str_untranslate_newline_dup (p->Value);
390 fprintf (profile, "%s=%s\n", p->KeyName, t);
391 free (t);
392 }
393
394 static void dump_sections (FILE *profile, TSecHeader *p)
395 {
396 if (!p)
397 return;
398 dump_sections (profile, p->link);
399 if (p->AppName [0]){
400 fprintf (profile, "\n[%s]\n", p->AppName);
401 dump_keys (profile, p->Keys);
402 }
403 }
404
405 static void dump_profile (TProfile *p)
406 {
407 FILE *profile;
408
409 if (!p)
410 return;
411 dump_profile (p->link);
412 /* .ado: p->FileName can be empty, it's better to jump over */
413 if (p->FileName[0] != (char) 0)
414 if ((profile = fopen (p->FileName, "w")) != NULL){
415 dump_sections (profile, p->Section);
416 fclose (profile);
417 }
418 }
419
420 /*
421 * Must be called at the end of wine run
422 */
423
424 void sync_profiles (void)
425 {
426 dump_profile (Base);
427 }
428
429 static void free_keys (TKeys *p)
430 {
431 if (!p)
432 return;
433 free_keys (p->link);
434 free (p->KeyName);
435 free (p->Value);
436 free (p);
437 }
438
439 static void free_sections (TSecHeader *p)
440 {
441 if (!p)
442 return;
443 free_sections (p->link);
444 free_keys (p->Keys);
445 free (p->AppName);
446 p->link = 0;
447 p->Keys = 0;
448 free (p);
449 }
450
451 static void free_profile (TProfile *p)
452 {
453 if (!p)
454 return;
455 free_profile (p->link);
456 free_sections (p->Section);
457 free (p->FileName);
458 free (p);
459 }
460
461 void free_profile_name (char *s)
462 {
463 TProfile *p;
464
465 if (!s)
466 return;
467
468 for (p = Base; p; p = p->link){
469 if (strcmp (s, p->FileName) == 0){
470 free_sections (p->Section);
471 p->Section = 0;
472 p->FileName [0] = 0;
473 return;
474 }
475 }
476 }
477
478 void free_profiles (void)
479 {
480 free_profile (Base);
481 }
482
483 void *profile_init_iterator (char *appname, char *file)
484 {
485 TProfile *New;
486 TSecHeader *section;
487
488 if (!is_loaded (file, &section)){
489 New = (TProfile *) xmalloc (sizeof (TProfile), "GetSetProfile");
490 New->link = Base;
491 New->FileName = strdup (file);
492 New->Section = load (file);
493 Base = New;
494 section = New->Section;
495 Current = New;
496 }
497 for (; section; section = section->link){
498 if (strcasecmp (section->AppName, appname))
499 continue;
500 return section->Keys;
501 }
502 return 0;
503 }
504
505 void *profile_iterator_next (void *s, char **key, char **value)
506 {
507 TKeys *keys = (TKeys *) s;
508
509 if (keys){
510 *key = keys->KeyName;
511 *value = keys->Value;
512 keys = keys->link;
513 }
514 return keys;
515 }
516
517 void profile_clean_section (char *appname, char *file)
518 {
519 TSecHeader *section;
520
521 /* We assume the user has called one of the other initialization funcs */
522 if (!is_loaded (file, &section)){
523 fprintf (stderr,"Warning: profile_clean_section called before init\n");
524 return;
525 }
526 /* We only disable the section, so it will still be freed, but it */
527 /* won't be find by further walks of the structure */
528
529 for (; section; section = section->link){
530 if (strcasecmp (section->AppName, appname))
531 continue;
532 section->AppName [0] = 0;
533 }
534 }
535
536 int profile_has_section (char *section_name, char *profile)
537 {
538 TSecHeader *section;
539
540 /* We assume the user has called one of the other initialization funcs */
541 if (!is_loaded (profile, &section)){
542 return 0;
543 }
544 for (; section; section = section->link){
545 if (strcasecmp (section->AppName, section_name))
546 continue;
547 return 1;
548 }
549 return 0;
550 }
551
552 void profile_forget_profile (char *file)
553 {
554 TProfile *p;
555
556 for (p = Base; p; p = p->link){
557 if (strcasecmp (file, p->FileName))
558 continue;
559 p->FileName [0] = 0;
560 }
561 }
562
563