small highlighting correction...
[midnight-commander.git] / src / profile.c
blob407ca508072887813138b3e92a3b1b4007e0d205
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 STRSIZE 4096
33 #define overflow (next == &CharBuffer [STRSIZE-1])
35 enum { FirstBrace, OnSecHeader, IgnoreToEOL, KeyDef, KeyDefOnKey, KeyValue };
37 typedef struct TKeys {
38 char *KeyName;
39 char *Value;
40 struct TKeys *link;
41 } TKeys;
43 typedef struct TSecHeader {
44 char *AppName;
45 TKeys *Keys;
46 struct TSecHeader *link;
47 } TSecHeader;
49 typedef struct TProfile {
50 char *FileName;
51 TSecHeader *Section;
52 struct TProfile *link;
53 } TProfile;
55 static TProfile *Base = 0;
57 static TProfile *
58 find_loaded (char *FileName, TSecHeader ** section)
60 TProfile *p = Base;
62 while (p) {
63 if (!g_strcasecmp (FileName, p->FileName)) {
64 *section = p->Section;
65 return p;
67 p = p->link;
69 return NULL;
72 #define TRANSLATION_CHAR '\200'
74 static char *
75 str_untranslate_newline_dup (char *s)
77 int l = 0;
78 char *p = s, *q;
79 g_return_val_if_fail(s, NULL);
80 while (*p) {
81 l++;
82 l += (*p == '\n' || *p == TRANSLATION_CHAR);
83 p++;
85 q = p = g_malloc (l + 1);
86 if (!q)
87 return 0;
88 for (;;) {
89 switch (*s) {
90 case '\n':
91 *p++ = TRANSLATION_CHAR;
92 *p++ = 'n';
93 break;
94 case TRANSLATION_CHAR:
95 if (s[1] == 'n' || s[1] == TRANSLATION_CHAR)
96 *p++ = TRANSLATION_CHAR;
97 *p++ = TRANSLATION_CHAR;
98 break;
99 case '\0':
100 *p = '\0';
101 return q;
102 break;
103 default:
104 *p++ = *s;
106 s++;
108 return 0; /* not reached */
111 static char *
112 str_translate_newline_dup (char *s)
114 char *p, *q;
115 g_return_val_if_fail(s,NULL);
116 q = p = g_malloc (strlen (s) + 1);
117 if (!q)
118 return 0;
119 while (*s) {
120 if (*s == TRANSLATION_CHAR) {
121 switch (*(++s)) {
122 case 'n':
123 *p++ = '\n';
124 break;
125 case TRANSLATION_CHAR:
126 *p++ = TRANSLATION_CHAR;
127 break;
128 case '\0':
129 *p++ = TRANSLATION_CHAR;
130 *p++ = '\0';
131 return q;
132 default:
133 *p++ = TRANSLATION_CHAR;
134 *p++ = *s;
136 } else {
137 *p++ = *s;
139 s++;
141 *p = '\0';
142 return q; /* not reached */
145 static TSecHeader *load (char *file)
147 FILE *f;
148 int state;
149 TSecHeader *SecHeader = 0;
150 char CharBuffer [STRSIZE];
151 char *next = ""; /* Not needed */
152 int c;
154 if ((f = fopen (file, "r"))==NULL)
155 return NULL;
157 state = FirstBrace;
158 while ((c = getc (f)) != EOF){
159 if (c == '\r') /* Ignore Carriage Return */
160 continue;
162 switch (state){
164 case OnSecHeader:
165 if (c == ']' || overflow){
166 *next = '\0';
167 next = CharBuffer;
168 SecHeader->AppName = g_strdup (CharBuffer);
169 state = IgnoreToEOL;
170 } else
171 *next++ = c;
172 break;
174 case IgnoreToEOL:
175 if (c == '\n'){
176 state = KeyDef;
177 next = CharBuffer;
179 break;
181 case FirstBrace:
182 case KeyDef:
183 case KeyDefOnKey:
184 if (c == '['){
185 TSecHeader *temp;
187 temp = SecHeader;
188 SecHeader = g_new (TSecHeader, 1);
189 SecHeader->link = temp;
190 SecHeader->Keys = 0;
191 state = OnSecHeader;
192 next = CharBuffer;
193 break;
195 if (state == FirstBrace) /* On first pass, don't allow dangling keys */
196 break;
198 if ((c == ' ' && state != KeyDefOnKey) || c == '\t')
199 break;
201 if (c == '\n' || overflow) /* Abort Definition */
202 next = CharBuffer;
204 if (c == '=' || overflow){
205 TKeys *temp;
207 temp = SecHeader->Keys;
208 *next = '\0';
209 SecHeader->Keys =g_new (TKeys, 1);
210 SecHeader->Keys->link = temp;
211 SecHeader->Keys->KeyName = g_strdup (CharBuffer);
212 state = KeyValue;
213 next = CharBuffer;
214 } else {
215 *next++ = c;
216 state = KeyDefOnKey;
218 break;
220 case KeyValue:
221 if (overflow || c == '\n'){
222 *next = '\0';
223 SecHeader->Keys->Value = str_translate_newline_dup (CharBuffer);
224 state = c == '\n' ? KeyDef : IgnoreToEOL;
225 next = CharBuffer;
226 #ifdef DEBUG
227 printf ("[%s] (%s)=%s\n", SecHeader->AppName,
228 SecHeader->Keys->KeyName, SecHeader->Keys->Value);
229 #endif
230 } else
231 *next++ = c;
232 break;
234 } /* switch */
236 } /* while ((c = getc (f)) != EOF) */
237 if (c == EOF && state == KeyValue){
238 *next = '\0';
239 SecHeader->Keys->Value = str_translate_newline_dup (CharBuffer);
241 fclose (f);
242 return SecHeader;
245 static void new_key (TSecHeader *section, char *KeyName, char *Value)
247 TKeys *key;
249 key = g_new (TKeys, 1);
250 key->KeyName = g_strdup (KeyName);
251 key->Value = g_strdup (Value);
252 key->link = section->Keys;
253 section->Keys = key;
256 static char *
257 GetSetProfileChar (int set, const char *AppName, char *KeyName,
258 char *Default, char *FileName)
261 TProfile *Current;
262 TSecHeader *section;
263 TKeys *key;
265 Current = find_loaded (FileName, &section);
266 if (!Current) {
267 Current = g_new (TProfile, 1);
268 Current->link = Base;
269 Current->FileName = g_strdup (FileName);
270 Current->Section = load (FileName);
271 Base = Current;
272 section = Current->Section;
275 /* Start search */
276 for (; section; section = section->link){
277 if (section->AppName == 0 || g_strcasecmp (section->AppName, AppName))
278 continue;
279 for (key = section->Keys; key; key = key->link){
280 if ( g_strcasecmp (key->KeyName, KeyName))
281 continue;
282 if (set){
283 g_free (key->Value);
284 key->Value = g_strdup (Default);
286 return key->Value;
288 /* If getting the information, then don't write the information
289 to the INI file, need to run a couple of tests with windog */
290 /* No key found */
291 if (set){
292 new_key (section, KeyName, Default);
293 return 0;
297 /* Non existent section */
298 if (set && Default){
299 section = g_new (TSecHeader, 1);
300 section->AppName = g_strdup (AppName);
301 section->Keys = 0;
302 new_key (section, KeyName, Default);
303 section->link = Current->Section;
304 Current->Section = section;
306 return Default;
309 static short GetSetProfile (int set, const char * AppName, char * KeyName,
310 char * Default, char * ReturnedString,
311 short Size, char * FileName)
314 char *s;
316 s = GetSetProfileChar (set, AppName, KeyName, Default, FileName);
317 if (!set){
318 ReturnedString [Size-1] = 0;
319 strncpy (ReturnedString, s, Size-1);
321 return 1;
324 short GetPrivateProfileString (const char * AppName, char * KeyName,
325 char * Default, char * ReturnedString,
326 short Size, char * FileName)
328 return (GetSetProfile (0, AppName, KeyName, Default, ReturnedString, Size, FileName));
331 char *get_profile_string (const char *AppName, char *KeyName, char *Default,
332 char *FileName)
334 return GetSetProfileChar (0, AppName, KeyName, Default, FileName);
337 int GetPrivateProfileInt (const char * AppName, char * KeyName, int Default,
338 char * File)
340 static char IntBuf [BUF_TINY];
341 static char buf [BUF_TINY];
343 g_snprintf (buf, sizeof (buf), "%d", Default);
345 /* Check the exact semantic with the SDK */
346 GetPrivateProfileString (AppName, KeyName, buf, IntBuf, BUF_TINY, File);
347 if (! g_strcasecmp (IntBuf, "true"))
348 return 1;
349 if (! g_strcasecmp (IntBuf, "yes"))
350 return 1;
351 return (int) atol (IntBuf);
354 int WritePrivateProfileString (const char * AppName, char * KeyName, char * String,
355 char * FileName)
357 return GetSetProfile (1, AppName, KeyName, String, "", 0, FileName);
360 static void dump_keys (FILE * profile, TKeys * p)
362 char *t;
363 if (!p)
364 return;
365 dump_keys (profile, p->link);
366 t = str_untranslate_newline_dup (p->Value);
367 fprintf (profile, "%s=%s\n", p->KeyName, t);
368 g_free (t);
371 static void dump_sections (FILE *profile, TSecHeader *p)
373 if (!p)
374 return;
375 dump_sections (profile, p->link);
376 if (p->AppName [0]){
377 fprintf (profile, "\n[%s]\n", p->AppName);
378 dump_keys (profile, p->Keys);
382 static void dump_profile (TProfile *p)
384 FILE *profile;
386 if (!p)
387 return;
388 dump_profile (p->link);
389 /* .ado: p->FileName can be empty, it's better to jump over */
390 if (p->FileName[0] != (char) 0)
391 if ((profile = fopen (p->FileName, "w")) != NULL){
392 dump_sections (profile, p->Section);
393 fclose (profile);
398 * Must be called at the end of wine run
401 void sync_profiles (void)
403 dump_profile (Base);
406 static void free_keys (TKeys *p)
408 if (!p)
409 return;
410 free_keys (p->link);
411 g_free (p->KeyName);
412 g_free (p->Value);
413 g_free (p);
416 static void free_sections (TSecHeader *p)
418 if (!p)
419 return;
420 free_sections (p->link);
421 free_keys (p->Keys);
422 g_free (p->AppName);
423 p->link = 0;
424 p->Keys = 0;
425 g_free (p);
428 static void free_profile (TProfile *p)
430 if (!p)
431 return;
432 free_profile (p->link);
433 free_sections (p->Section);
434 g_free (p->FileName);
435 g_free (p);
438 void free_profile_name (char *s)
440 TProfile *p;
442 if (!s)
443 return;
445 for (p = Base; p; p = p->link){
446 if (strcmp (s, p->FileName) == 0){
447 free_sections (p->Section);
448 p->Section = 0;
449 p->FileName [0] = 0;
450 return;
455 void free_profiles (void)
457 free_profile (Base);
460 void *profile_init_iterator (char *appname, char *file)
462 TProfile *Current;
463 TSecHeader *section;
465 Current = find_loaded (file, &section);
466 if (!Current) {
467 Current = g_new (TProfile, 1);
468 Current->link = Base;
469 Current->FileName = g_strdup (file);
470 Current->Section = load (file);
471 Base = Current;
472 section = Current->Section;
474 for (; section; section = section->link){
475 if ( g_strcasecmp (section->AppName, appname))
476 continue;
477 return section->Keys;
479 return 0;
482 void *profile_iterator_next (void *s, char **key, char **value)
484 TKeys *keys = (TKeys *) s;
486 if (keys){
487 *key = keys->KeyName;
488 *value = keys->Value;
489 keys = keys->link;
491 return keys;
494 void profile_clean_section (char *appname, char *file)
496 TSecHeader *section;
498 /* We assume the user has called one of the other initialization funcs */
499 if (!find_loaded (file, &section)){
500 fprintf (stderr,"Warning: profile_clean_section called before init\n");
501 return;
503 /* We only disable the section, so it will still be freed, but it */
504 /* won't be find by further walks of the structure */
506 for (; section; section = section->link){
507 if ( g_strcasecmp (section->AppName, appname))
508 continue;
509 section->AppName [0] = 0;
513 int profile_has_section (char *section_name, char *profile)
515 TSecHeader *section;
517 /* We assume the user has called one of the other initialization funcs */
518 if (!find_loaded (profile, &section)){
519 return 0;
521 for (; section; section = section->link){
522 if ( g_strcasecmp (section->AppName, section_name))
523 continue;
524 return 1;
526 return 0;
529 void profile_forget_profile (char *file)
531 TProfile *p;
533 for (p = Base; p; p = p->link){
534 if ( g_strcasecmp (file, p->FileName))
535 continue;
536 p->FileName [0] = 0;