Reverted the use of bool in favour of gboolean
[midnight-commander.git] / src / profile.c
blob07c201ec27df557c7597f3ec334cced23355967f
1 /*
2 * Initialization-File Functions.
4 * From the Wine project
6 Copyright (C) 1993, 1994, 1998, 1999, 2000, 2002, 2003, 2004, 2005,
7 2007 Free Software Foundation, Inc.
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24 #include <config.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/types.h>
31 #include <mhl/memory.h>
32 #include <mhl/string.h>
34 #include "global.h"
35 #include "profile.h"
37 #define STRSIZE 4096
38 #define overflow (next == &CharBuffer [STRSIZE-1])
40 enum { FirstBrace, OnSecHeader, IgnoreToEOL, KeyDef, KeyDefOnKey, KeyValue };
42 typedef struct TKeys {
43 char *KeyName;
44 char *Value;
45 struct TKeys *link;
46 } TKeys;
48 typedef struct TSecHeader {
49 char *AppName;
50 TKeys *Keys;
51 struct TSecHeader *link;
52 } TSecHeader;
54 typedef struct TProfile {
55 char *FileName;
56 TSecHeader *Section;
57 struct TProfile *link;
58 } TProfile;
60 static TProfile *Base = 0;
62 static TProfile *
63 find_loaded (const char *FileName, TSecHeader ** section)
65 TProfile *p = Base;
67 while (p) {
68 if (!g_strcasecmp (FileName, p->FileName)) {
69 *section = p->Section;
70 return p;
72 p = p->link;
74 return NULL;
77 #define TRANSLATION_CHAR '\200'
79 static char *
80 str_untranslate_newline_dup (char *s)
82 int l = 0;
83 char *p = s, *q;
84 g_return_val_if_fail(s, NULL);
85 while (*p) {
86 l++;
87 l += (*p == '\n' || *p == TRANSLATION_CHAR);
88 p++;
90 q = p = g_malloc (l + 1);
91 if (!q)
92 return 0;
93 for (;;) {
94 switch (*s) {
95 case '\n':
96 *p++ = TRANSLATION_CHAR;
97 *p++ = 'n';
98 break;
99 case TRANSLATION_CHAR:
100 if (s[1] == 'n' || s[1] == TRANSLATION_CHAR)
101 *p++ = TRANSLATION_CHAR;
102 *p++ = TRANSLATION_CHAR;
103 break;
104 case '\0':
105 *p = '\0';
106 return q;
107 break;
108 default:
109 *p++ = *s;
111 s++;
113 return 0; /* not reached */
116 static char *
117 str_translate_newline_dup (char *s)
119 char *p, *q;
120 g_return_val_if_fail(s,NULL);
121 q = p = g_malloc (strlen (s) + 1);
122 if (!q)
123 return 0;
124 while (*s) {
125 if (*s == TRANSLATION_CHAR) {
126 switch (*(++s)) {
127 case 'n':
128 *p++ = '\n';
129 break;
130 case TRANSLATION_CHAR:
131 *p++ = TRANSLATION_CHAR;
132 break;
133 case '\0':
134 *p++ = TRANSLATION_CHAR;
135 *p++ = '\0';
136 return q;
137 default:
138 *p++ = TRANSLATION_CHAR;
139 *p++ = *s;
141 } else {
142 *p++ = *s;
144 s++;
146 *p = '\0';
147 return q; /* not reached */
150 static TSecHeader *load (const char *file)
152 FILE *f;
153 int state;
154 TSecHeader *SecHeader = 0;
155 char CharBuffer [STRSIZE];
156 char *next = NULL; /* Not needed */
157 int c;
159 if ((f = fopen (file, "r"))==NULL)
160 return NULL;
162 state = FirstBrace;
163 while ((c = getc (f)) != EOF){
164 if (c == '\r') /* Ignore Carriage Return */
165 continue;
167 switch (state){
169 case OnSecHeader:
170 if (c == ']' || overflow){
171 *next = '\0';
172 next = CharBuffer;
173 SecHeader->AppName = g_strdup (CharBuffer);
174 state = IgnoreToEOL;
175 } else
176 *next++ = c;
177 break;
179 case IgnoreToEOL:
180 if (c == '\n'){
181 state = KeyDef;
182 next = CharBuffer;
184 break;
186 case FirstBrace:
187 case KeyDef:
188 case KeyDefOnKey:
189 if (c == '['){
190 TSecHeader *temp;
192 temp = SecHeader;
193 SecHeader = g_new (TSecHeader, 1);
194 SecHeader->link = temp;
195 SecHeader->Keys = 0;
196 state = OnSecHeader;
197 next = CharBuffer;
198 break;
200 if (state == FirstBrace) /* On first pass, don't allow dangling keys */
201 break;
203 if ((c == ' ' && state != KeyDefOnKey) || c == '\t')
204 break;
206 if (c == '\n' || overflow) {
207 /* Abort Definition */
208 next = CharBuffer;
209 break;
212 if (c == '=' || overflow){
213 TKeys *temp;
215 temp = SecHeader->Keys;
216 *next = '\0';
217 SecHeader->Keys =g_new (TKeys, 1);
218 SecHeader->Keys->link = temp;
219 SecHeader->Keys->KeyName = g_strdup (CharBuffer);
220 state = KeyValue;
221 next = CharBuffer;
222 } else {
223 *next++ = c;
224 state = KeyDefOnKey;
226 break;
228 case KeyValue:
229 if (overflow || c == '\n'){
230 *next = '\0';
231 SecHeader->Keys->Value = str_translate_newline_dup (CharBuffer);
232 state = c == '\n' ? KeyDef : IgnoreToEOL;
233 next = CharBuffer;
234 #ifdef DEBUG
235 printf ("[%s] (%s)=%s\n", SecHeader->AppName,
236 SecHeader->Keys->KeyName, SecHeader->Keys->Value);
237 #endif
238 } else
239 *next++ = c;
240 break;
242 } /* switch */
244 } /* while ((c = getc (f)) != EOF) */
246 switch (state) {
247 case KeyValue:
248 *next = '\0';
249 SecHeader->Keys->Value = str_translate_newline_dup (CharBuffer);
250 break;
251 case OnSecHeader: { /* Broken initialization file */
252 TSecHeader *link = SecHeader->link;
253 g_free (SecHeader);
254 SecHeader = link;
255 fprintf (stderr, "Warning: Corrupted initialization file `%s'\n",
256 file);
257 break;
261 fclose (f);
262 return SecHeader;
265 static void new_key (TSecHeader *section, const char *KeyName, const char *Value)
267 TKeys *key;
269 key = g_new (TKeys, 1);
270 key->KeyName = g_strdup (KeyName);
271 key->Value = g_strdup (Value);
272 key->link = section->Keys;
273 section->Keys = key;
276 static const char *
277 GetSetProfileChar (int set, const char *AppName, const char *KeyName,
278 const char *Default, const char *FileName)
281 TProfile *Current;
282 TSecHeader *section;
283 TKeys *key;
285 Current = find_loaded (FileName, &section);
286 if (!Current) {
287 Current = g_new (TProfile, 1);
288 Current->link = Base;
289 Current->FileName = g_strdup (FileName);
290 Current->Section = load (FileName);
291 Base = Current;
292 section = Current->Section;
295 /* Start search */
296 for (; section; section = section->link){
297 if (section->AppName == 0 || g_strcasecmp (section->AppName, AppName))
298 continue;
299 for (key = section->Keys; key; key = key->link){
300 if ( g_strcasecmp (key->KeyName, KeyName))
301 continue;
302 if (set){
303 g_free (key->Value);
304 key->Value = g_strdup (Default);
306 return key->Value;
308 /* If getting the information, then don't write the information
309 to the INI file, need to run a couple of tests with windog */
310 /* No key found */
311 if (set){
312 new_key (section, KeyName, Default);
313 return 0;
317 /* Non existent section */
318 if (set && Default){
319 section = g_new (TSecHeader, 1);
320 section->AppName = g_strdup (AppName);
321 section->Keys = 0;
322 new_key (section, KeyName, Default);
323 section->link = Current->Section;
324 Current->Section = section;
326 return Default;
329 static short GetSetProfile (int set, const char * AppName, const char * KeyName,
330 const char * Default, char * ReturnedString,
331 short Size, const char * FileName)
334 const char *s;
336 s = GetSetProfileChar (set, AppName, KeyName, Default, FileName);
337 if (!set)
338 g_strlcpy (ReturnedString, s, Size);
340 return 1;
343 short GetPrivateProfileString (const char * AppName, const char * KeyName,
344 const char * Default, char * ReturnedString,
345 short Size, const char * FileName)
347 return (GetSetProfile (0, AppName, KeyName, Default, ReturnedString, Size, FileName));
350 const char *get_profile_string (const char *AppName, const char *KeyName, const char *Default,
351 const char *FileName)
353 return GetSetProfileChar (0, AppName, KeyName, Default, FileName);
356 int GetPrivateProfileInt (const char * AppName, const char * KeyName, int Default,
357 const char * File)
359 char IntBuf [BUF_TINY];
360 char buf [BUF_TINY];
362 snprintf (buf, sizeof (buf), "%d", Default);
364 /* Check the exact semantic with the SDK */
365 GetPrivateProfileString (AppName, KeyName, buf, IntBuf, BUF_TINY, File);
366 if (! g_strcasecmp (IntBuf, "true"))
367 return 1;
368 if (! g_strcasecmp (IntBuf, "yes"))
369 return 1;
370 return (int) atol (IntBuf);
373 int WritePrivateProfileString (const char * AppName, const char * KeyName, const char * String,
374 const char * FileName)
376 return GetSetProfile (1, AppName, KeyName, String, NULL, 0, FileName);
379 static void dump_keys (FILE * profile, TKeys * p)
381 char *t;
382 if (!p)
383 return;
384 dump_keys (profile, p->link);
385 t = str_untranslate_newline_dup (p->Value);
386 fprintf (profile, "%s=%s\n", p->KeyName, t);
387 g_free (t);
390 static void dump_sections (FILE *profile, TSecHeader *p)
392 if (!p)
393 return;
394 dump_sections (profile, p->link);
395 if (p->AppName [0]){
396 fprintf (profile, "\n[%s]\n", p->AppName);
397 dump_keys (profile, p->Keys);
401 static void dump_profile (TProfile *p)
403 FILE *profile;
405 if (!p)
406 return;
407 dump_profile (p->link);
408 /* .ado: p->FileName can be empty, it's better to jump over */
409 if (p->FileName[0] != (char) 0)
410 if ((profile = fopen (p->FileName, "w")) != NULL){
411 dump_sections (profile, p->Section);
412 fclose (profile);
417 * Must be called at the end of wine run
420 void sync_profiles (void)
422 dump_profile (Base);
425 static void free_keys (TKeys *p)
427 if (!p)
428 return;
429 free_keys (p->link);
430 g_free (p->KeyName);
431 g_free (p->Value);
432 g_free (p);
435 static void free_sections (TSecHeader *p)
437 if (!p)
438 return;
439 free_sections (p->link);
440 free_keys (p->Keys);
441 g_free (p->AppName);
442 p->link = 0;
443 p->Keys = 0;
444 g_free (p);
447 static void free_profile (TProfile *p)
449 if (!p)
450 return;
451 free_profile (p->link);
452 free_sections (p->Section);
453 g_free (p->FileName);
454 g_free (p);
457 void free_profile_name (const char *s)
459 TProfile *p;
461 if (!s)
462 return;
464 for (p = Base; p; p = p->link){
465 if (strcmp (s, p->FileName) == 0){
466 free_sections (p->Section);
467 p->Section = 0;
468 p->FileName [0] = 0;
469 return;
474 void free_profiles (void)
476 free_profile (Base);
479 void *profile_init_iterator (const char *appname, const char *file)
481 TProfile *Current;
482 TSecHeader *section;
484 Current = find_loaded (file, &section);
485 if (!Current) {
486 Current = g_new (TProfile, 1);
487 Current->link = Base;
488 Current->FileName = g_strdup (file);
489 Current->Section = load (file);
490 Base = Current;
491 section = Current->Section;
493 for (; section; section = section->link){
494 if ( g_strcasecmp (section->AppName, appname))
495 continue;
496 return section->Keys;
498 return 0;
501 void *profile_iterator_next (void *s, char **key, char **value)
503 TKeys *keys = (TKeys *) s;
505 if (keys){
506 *key = keys->KeyName;
507 *value = keys->Value;
508 keys = keys->link;
510 return keys;
513 void profile_clean_section (const char *appname, const char *file)
515 TSecHeader *section;
517 /* We assume the user has called one of the other initialization funcs */
518 if (!find_loaded (file, &section)){
519 fprintf (stderr,"Warning: profile_clean_section called before init\n");
520 return;
522 /* We only disable the section, so it will still be freed, but it */
523 /* won't be find by further walks of the structure */
525 for (; section; section = section->link){
526 if ( g_strcasecmp (section->AppName, appname))
527 continue;
528 section->AppName [0] = 0;
532 int profile_has_section (const char *section_name, const char *profile)
534 TSecHeader *section;
536 /* We assume the user has called one of the other initialization funcs */
537 if (!find_loaded (profile, &section)){
538 return 0;
540 for (; section; section = section->link){
541 if ( g_strcasecmp (section->AppName, section_name))
542 continue;
543 return 1;
545 return 0;
548 void profile_forget_profile (const char *file)
550 TProfile *p;
552 for (p = Base; p; p = p->link){
553 if ( g_strcasecmp (file, p->FileName))
554 continue;
555 p->FileName [0] = 0;