*** empty log message ***
[midnight-commander.git] / src / profile.c
blob5a0b22e1a223c5e5a307f757b0b62d48830fecf0
1 /*
2 * Initialization-File Functions.
4 * From the Wine project
6 Copyright (C) 1993, 1994 Miguel de Icaza.
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.
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.
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 /* "$Id$" */
25 #include <config.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <sys/types.h>
29 #include "global.h"
30 #include "profile.h"
32 #define INIFILE "xxx.ini"
33 #define STRSIZE 4096
34 #define overflow (next == &CharBuffer [STRSIZE-1])
36 enum { FirstBrace, OnSecHeader, IgnoreToEOL, KeyDef, KeyDefOnKey, KeyValue };
38 typedef struct TKeys {
39 char *KeyName;
40 char *Value;
41 struct TKeys *link;
42 } TKeys;
44 typedef struct TSecHeader {
45 char *AppName;
46 TKeys *Keys;
47 struct TSecHeader *link;
48 } TSecHeader;
50 typedef struct TProfile {
51 char *FileName;
52 TSecHeader *Section;
53 struct TProfile *link;
54 } TProfile;
56 TProfile *Current = 0;
57 TProfile *Base = 0;
59 static int is_loaded (char *FileName, TSecHeader **section)
61 TProfile *p = Base;
63 while (p){
64 if (! g_strcasecmp (FileName, p->FileName)){
65 Current = p;
66 *section = p->Section;
67 return 1;
69 p = p->link;
71 return 0;
74 #define TRANSLATION_CHAR '\200'
76 static char *
77 str_untranslate_newline_dup (char *s)
79 int l = 0;
80 char *p = s, *q;
81 g_return_val_if_fail(s, NULL);
82 while (*p) {
83 l++;
84 l += (*p == '\n' || *p == TRANSLATION_CHAR);
85 p++;
87 q = p = g_malloc (l + 1);
88 if (!q)
89 return 0;
90 for (;;) {
91 switch (*s) {
92 case '\n':
93 *p++ = TRANSLATION_CHAR;
94 *p++ = 'n';
95 break;
96 case TRANSLATION_CHAR:
97 if (s[1] == 'n' || s[1] == TRANSLATION_CHAR)
98 *p++ = TRANSLATION_CHAR;
99 *p++ = TRANSLATION_CHAR;
100 break;
101 case '\0':
102 *p = '\0';
103 return q;
104 break;
105 default:
106 *p++ = *s;
108 s++;
110 return 0; /* not reached */
113 static char *
114 str_translate_newline_dup (char *s)
116 char *p, *q;
117 g_return_val_if_fail(s,NULL);
118 q = p = g_malloc (strlen (s) + 1);
119 if (!q)
120 return 0;
121 while (*s) {
122 if (*s == TRANSLATION_CHAR) {
123 switch (*(++s)) {
124 case 'n':
125 *p++ = '\n';
126 break;
127 case TRANSLATION_CHAR:
128 *p++ = TRANSLATION_CHAR;
129 break;
130 case '\0':
131 *p++ = TRANSLATION_CHAR;
132 *p++ = '\0';
133 return q;
134 default:
135 *p++ = TRANSLATION_CHAR;
136 *p++ = *s;
138 } else {
139 *p++ = *s;
141 s++;
143 *p = '\0';
144 return q; /* not reached */
147 static TSecHeader *load (char *file)
149 FILE *f;
150 int state;
151 TSecHeader *SecHeader = 0;
152 char CharBuffer [STRSIZE];
153 char *next = ""; /* Not needed */
154 int c;
156 if ((f = fopen (file, "r"))==NULL)
157 return NULL;
159 state = FirstBrace;
160 while ((c = getc (f)) != EOF){
161 if (c == '\r') /* Ignore Carriage Return */
162 continue;
164 switch (state){
166 case OnSecHeader:
167 if (c == ']' || overflow){
168 *next = '\0';
169 next = CharBuffer;
170 SecHeader->AppName = g_strdup (CharBuffer);
171 state = IgnoreToEOL;
172 } else
173 *next++ = c;
174 break;
176 case IgnoreToEOL:
177 if (c == '\n'){
178 state = KeyDef;
179 next = CharBuffer;
181 break;
183 case FirstBrace:
184 case KeyDef:
185 case KeyDefOnKey:
186 if (c == '['){
187 TSecHeader *temp;
189 temp = SecHeader;
190 SecHeader = g_new (TSecHeader, 1);
191 SecHeader->link = temp;
192 SecHeader->Keys = 0;
193 state = OnSecHeader;
194 next = CharBuffer;
195 break;
197 if (state == FirstBrace) /* On first pass, don't allow dangling keys */
198 break;
200 if ((c == ' ' && state != KeyDefOnKey) || c == '\t')
201 break;
203 if (c == '\n' || overflow) /* Abort Definition */
204 next = CharBuffer;
206 if (c == '=' || overflow){
207 TKeys *temp;
209 temp = SecHeader->Keys;
210 *next = '\0';
211 SecHeader->Keys =g_new (TKeys, 1);
212 SecHeader->Keys->link = temp;
213 SecHeader->Keys->KeyName = g_strdup (CharBuffer);
214 state = KeyValue;
215 next = CharBuffer;
216 } else {
217 *next++ = c;
218 state = KeyDefOnKey;
220 break;
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;
236 } /* switch */
238 } /* while ((c = getc (f)) != EOF) */
239 if (c == EOF && state == KeyValue){
240 *next = '\0';
241 SecHeader->Keys->Value = str_translate_newline_dup (CharBuffer);
243 fclose (f);
244 return SecHeader;
247 static void new_key (TSecHeader *section, char *KeyName, char *Value)
249 TKeys *key;
251 key = g_new (TKeys, 1);
252 key->KeyName = g_strdup (KeyName);
253 key->Value = g_strdup (Value);
254 key->link = section->Keys;
255 section->Keys = key;
258 static char *
259 GetSetProfileChar (int set, const char *AppName, char *KeyName,
260 char *Default, char *FileName)
263 TProfile *New;
264 TSecHeader *section;
265 TKeys *key;
267 if (!is_loaded (FileName, &section)){
268 New = g_new (TProfile, 1);
269 New->link = Base;
270 New->FileName = g_strdup (FileName);
271 New->Section = load (FileName);
272 Base = New;
273 section = New->Section;
274 Current = New;
277 /* Start search */
278 for (; section; section = section->link){
279 if (section->AppName == 0 || g_strcasecmp (section->AppName, AppName))
280 continue;
281 for (key = section->Keys; key; key = key->link){
282 if ( g_strcasecmp (key->KeyName, KeyName))
283 continue;
284 if (set){
285 g_free (key->Value);
286 key->Value = g_strdup (Default);
288 return key->Value;
290 /* If getting the information, then don't write the information
291 to the INI file, need to run a couple of tests with windog */
292 /* No key found */
293 if (set){
294 new_key (section, KeyName, Default);
295 return 0;
299 /* Non existent section */
300 if (set && Default){
301 section = g_new (TSecHeader, 1);
302 section->AppName = g_strdup (AppName);
303 section->Keys = 0;
304 new_key (section, KeyName, Default);
305 section->link = Current->Section;
306 Current->Section = section;
308 return Default;
311 static short GetSetProfile (int set, const char * AppName, char * KeyName,
312 char * Default, char * ReturnedString,
313 short Size, char * FileName)
316 char *s;
318 s = GetSetProfileChar (set, AppName, KeyName, Default, FileName);
319 if (!set){
320 ReturnedString [Size-1] = 0;
321 strncpy (ReturnedString, s, Size-1);
323 return 1;
326 short GetPrivateProfileString (const char * AppName, char * KeyName,
327 char * Default, char * ReturnedString,
328 short Size, char * FileName)
330 return (GetSetProfile (0, AppName, KeyName, Default, ReturnedString, Size, FileName));
333 char *get_profile_string (const char *AppName, char *KeyName, char *Default,
334 char *FileName)
336 return GetSetProfileChar (0, AppName, KeyName, Default, FileName);
339 #if 0
340 int GetProfileString (const char * AppName, char * KeyName, char * Default,
341 char * ReturnedString, int Size)
343 return GetPrivateProfileString (AppName, KeyName, Default,
344 ReturnedString, Size, INIFILE);
346 #endif
348 int GetPrivateProfileInt (const char * AppName, char * KeyName, int Default,
349 char * File)
351 static char IntBuf [BUF_TINY];
352 static char buf [BUF_TINY];
354 g_snprintf (buf, sizeof (buf), "%d", Default);
356 /* Check the exact semantic with the SDK */
357 GetPrivateProfileString (AppName, KeyName, buf, IntBuf, BUF_TINY, File);
358 if (! g_strcasecmp (IntBuf, "true"))
359 return 1;
360 if (! g_strcasecmp (IntBuf, "yes"))
361 return 1;
362 return (int) atol (IntBuf);
365 #if 0
366 int GetProfileInt (const char * AppName, char * KeyName, int Default)
368 return GetPrivateProfileInt (AppName, KeyName, Default, INIFILE);
370 #endif
372 int WritePrivateProfileString (const char * AppName, char * KeyName, char * String,
373 char * FileName)
375 return GetSetProfile (1, AppName, KeyName, String, "", 0, FileName);
378 #if 0
379 int WriteProfileString (const char * AppName, char * KeyName, char * String)
381 return (WritePrivateProfileString (AppName, KeyName, String, INIFILE));
383 #endif
385 static void dump_keys (FILE * profile, TKeys * p)
387 char *t;
388 if (!p)
389 return;
390 dump_keys (profile, p->link);
391 t = str_untranslate_newline_dup (p->Value);
392 fprintf (profile, "%s=%s\n", p->KeyName, t);
393 g_free (t);
396 static void dump_sections (FILE *profile, TSecHeader *p)
398 if (!p)
399 return;
400 dump_sections (profile, p->link);
401 if (p->AppName [0]){
402 fprintf (profile, "\n[%s]\n", p->AppName);
403 dump_keys (profile, p->Keys);
407 static void dump_profile (TProfile *p)
409 FILE *profile;
411 if (!p)
412 return;
413 dump_profile (p->link);
414 /* .ado: p->FileName can be empty, it's better to jump over */
415 if (p->FileName[0] != (char) 0)
416 if ((profile = fopen (p->FileName, "w")) != NULL){
417 dump_sections (profile, p->Section);
418 fclose (profile);
423 * Must be called at the end of wine run
426 void sync_profiles (void)
428 dump_profile (Base);
431 static void free_keys (TKeys *p)
433 if (!p)
434 return;
435 free_keys (p->link);
436 g_free (p->KeyName);
437 g_free (p->Value);
438 g_free (p);
441 static void free_sections (TSecHeader *p)
443 if (!p)
444 return;
445 free_sections (p->link);
446 free_keys (p->Keys);
447 g_free (p->AppName);
448 p->link = 0;
449 p->Keys = 0;
450 g_free (p);
453 static void free_profile (TProfile *p)
455 if (!p)
456 return;
457 free_profile (p->link);
458 free_sections (p->Section);
459 g_free (p->FileName);
460 g_free (p);
463 void free_profile_name (char *s)
465 TProfile *p;
467 if (!s)
468 return;
470 for (p = Base; p; p = p->link){
471 if (strcmp (s, p->FileName) == 0){
472 free_sections (p->Section);
473 p->Section = 0;
474 p->FileName [0] = 0;
475 return;
480 void free_profiles (void)
482 free_profile (Base);
485 void *profile_init_iterator (char *appname, char *file)
487 TProfile *New;
488 TSecHeader *section;
490 if (!is_loaded (file, &section)){
491 New = g_new (TProfile, 1);
492 New->link = Base;
493 New->FileName = g_strdup (file);
494 New->Section = load (file);
495 Base = New;
496 section = New->Section;
497 Current = New;
499 for (; section; section = section->link){
500 if ( g_strcasecmp (section->AppName, appname))
501 continue;
502 return section->Keys;
504 return 0;
507 void *profile_iterator_next (void *s, char **key, char **value)
509 TKeys *keys = (TKeys *) s;
511 if (keys){
512 *key = keys->KeyName;
513 *value = keys->Value;
514 keys = keys->link;
516 return keys;
519 void profile_clean_section (char *appname, char *file)
521 TSecHeader *section;
523 /* We assume the user has called one of the other initialization funcs */
524 if (!is_loaded (file, &section)){
525 fprintf (stderr,"Warning: profile_clean_section called before init\n");
526 return;
528 /* We only disable the section, so it will still be freed, but it */
529 /* won't be find by further walks of the structure */
531 for (; section; section = section->link){
532 if ( g_strcasecmp (section->AppName, appname))
533 continue;
534 section->AppName [0] = 0;
538 int profile_has_section (char *section_name, char *profile)
540 TSecHeader *section;
542 /* We assume the user has called one of the other initialization funcs */
543 if (!is_loaded (profile, &section)){
544 return 0;
546 for (; section; section = section->link){
547 if ( g_strcasecmp (section->AppName, section_name))
548 continue;
549 return 1;
551 return 0;
554 void profile_forget_profile (char *file)
556 TProfile *p;
558 for (p = Base; p; p = p->link){
559 if ( g_strcasecmp (file, p->FileName))
560 continue;
561 p->FileName [0] = 0;