Change to the linux kernel coding style
[wmaker-crm.git] / WINGs / userdefaults.c
1
2 #include <stdlib.h>
3 #include <string.h>
4 #include <stdio.h>
5 #include <assert.h>
6 #include <unistd.h>
7 #include <sys/stat.h>
8
9 #include "wconfig.h"
10
11 #include "WINGs.h"
12
13 typedef struct W_UserDefaults {
14         WMPropList *defaults;
15
16         WMPropList *appDomain;
17
18         WMPropList *searchListArray;
19         WMPropList **searchList;        /* cache for searchListArray */
20
21         char dirty;
22
23         char dontSync;
24
25         char *path;             /* where is db located */
26
27         time_t timestamp;       /* last modification time */
28
29         struct W_UserDefaults *next;
30
31 } UserDefaults;
32
33 static UserDefaults *sharedUserDefaults = NULL;
34
35 char *WMUserDefaultsDidChangeNotification = "WMUserDefaultsDidChangeNotification";
36
37 static void synchronizeUserDefaults(void *foo);
38
39 extern char *WMGetApplicationName();
40
41 #define DEFAULTS_DIR "/Defaults"
42
43 char *wusergnusteppath()
44 {
45         static char *path = NULL;
46         char *gspath;
47         int pathlen;
48
49         if (!path) {
50                 gspath = getenv("GNUSTEP_USER_ROOT");
51                 if (gspath) {
52                         gspath = wexpandpath(gspath);
53                         pathlen = strlen(gspath) + 4;
54                         path = wmalloc(pathlen);
55                         strcpy(path, gspath);
56                         wfree(gspath);
57                 } else {
58                         pathlen = strlen(wgethomedir()) + 10;
59                         path = wmalloc(pathlen);
60                         strcpy(path, wgethomedir());
61                         strcat(path, "/GNUstep");
62                 }
63         }
64
65         return path;
66 }
67
68 char *wdefaultspathfordomain(char *domain)
69 {
70         char *path;
71         char *gspath;
72
73         gspath = wusergnusteppath();
74         path = wmalloc(strlen(gspath) + strlen(DEFAULTS_DIR) + strlen(domain) + 4);
75         strcpy(path, gspath);
76         strcat(path, DEFAULTS_DIR);
77         strcat(path, "/");
78         strcat(path, domain);
79
80         return path;
81 }
82
83 static void
84 #ifdef HAVE_ATEXIT
85 saveDefaultsChanges(void)
86 #else
87 saveDefaultsChanges(int foo, void *bar)
88 #endif
89 {
90         /* save the user defaults databases */
91         synchronizeUserDefaults(NULL);
92 }
93
94 /* set to save changes in defaults when program is exited */
95 static void registerSaveOnExit(void)
96 {
97         static Bool registeredSaveOnExit = False;
98
99         if (!registeredSaveOnExit) {
100 #ifdef HAVE_ATEXIT
101                 atexit(saveDefaultsChanges);
102 #else
103                 on_exit(saveDefaultsChanges, (void *)NULL);
104 #endif
105                 registeredSaveOnExit = True;
106         }
107 }
108
109 static void synchronizeUserDefaults(void *foo)
110 {
111         UserDefaults *database = sharedUserDefaults;
112
113         while (database) {
114                 if (!database->dontSync)
115                         WMSynchronizeUserDefaults(database);
116                 database = database->next;
117         }
118 }
119
120 void WMEnableUDPeriodicSynchronization(WMUserDefaults * database, Bool enable)
121 {
122         database->dontSync = !enable;
123 }
124
125 void WMSynchronizeUserDefaults(WMUserDefaults * database)
126 {
127         Bool fileIsNewer = False, release = False, notify = False;
128         WMPropList *plF, *key;
129         char *path;
130         struct stat stbuf;
131
132         if (!database->path) {
133                 path = wdefaultspathfordomain(WMGetApplicationName());
134                 release = True;
135         } else {
136                 path = database->path;
137         }
138
139         if (stat(path, &stbuf) >= 0 && stbuf.st_mtime > database->timestamp)
140                 fileIsNewer = True;
141
142         if (database->appDomain && (database->dirty || fileIsNewer)) {
143                 if (database->dirty && fileIsNewer) {
144                         plF = WMReadPropListFromFile(path);
145                         if (plF) {
146                                 plF = WMMergePLDictionaries(plF, database->appDomain, False);
147                                 WMReleasePropList(database->appDomain);
148                                 database->appDomain = plF;
149                                 key = database->searchList[0];
150                                 WMPutInPLDictionary(database->defaults, key, plF);
151                                 notify = True;
152                         } else {
153                                 /* something happened with the file. just overwrite it */
154                                 wwarning(_("cannot read domain from file '%s' when syncing"), path);
155                                 WMWritePropListToFile(database->appDomain, path, True);
156                         }
157                 } else if (database->dirty) {
158                         WMWritePropListToFile(database->appDomain, path, True);
159                 } else if (fileIsNewer) {
160                         plF = WMReadPropListFromFile(path);
161                         if (plF) {
162                                 WMReleasePropList(database->appDomain);
163                                 database->appDomain = plF;
164                                 key = database->searchList[0];
165                                 WMPutInPLDictionary(database->defaults, key, plF);
166                                 notify = True;
167                         } else {
168                                 /* something happened with the file. just overwrite it */
169                                 wwarning(_("cannot read domain from file '%s' when syncing"), path);
170                                 WMWritePropListToFile(database->appDomain, path, True);
171                         }
172                 }
173
174                 database->dirty = 0;
175
176                 if (stat(path, &stbuf) >= 0)
177                         database->timestamp = stbuf.st_mtime;
178
179                 if (notify) {
180                         WMPostNotificationName(WMUserDefaultsDidChangeNotification, database, NULL);
181                 }
182         }
183
184         if (release)
185                 wfree(path);
186
187 }
188
189 void WMSaveUserDefaults(WMUserDefaults * database)
190 {
191         if (database->appDomain) {
192                 struct stat stbuf;
193                 char *path;
194                 Bool release = False;
195
196                 if (!database->path) {
197                         path = wdefaultspathfordomain(WMGetApplicationName());
198                         release = True;
199                 } else {
200                         path = database->path;
201                 }
202                 WMWritePropListToFile(database->appDomain, path, True);
203                 database->dirty = 0;
204                 if (stat(path, &stbuf) >= 0)
205                         database->timestamp = stbuf.st_mtime;
206                 if (release)
207                         wfree(path);
208         }
209 }
210
211 WMUserDefaults *WMGetStandardUserDefaults(void)
212 {
213         WMUserDefaults *defaults;
214         WMPropList *domain;
215         WMPropList *key;
216         struct stat stbuf;
217         char *path;
218         int i;
219
220         if (sharedUserDefaults) {
221                 defaults = sharedUserDefaults;
222                 while (defaults) {
223                         /* path == NULL only for StandardUserDefaults db */
224                         if (defaults->path == NULL)
225                                 return defaults;
226                         defaults = defaults->next;
227                 }
228         }
229
230         /* we didn't found the database we are looking for. Go read it. */
231         defaults = wmalloc(sizeof(WMUserDefaults));
232         memset(defaults, 0, sizeof(WMUserDefaults));
233
234         defaults->defaults = WMCreatePLDictionary(NULL, NULL);
235
236         defaults->searchList = wmalloc(sizeof(WMPropList *) * 3);
237
238         /* application domain */
239         key = WMCreatePLString(WMGetApplicationName());
240         defaults->searchList[0] = key;
241
242         /* temporary kluge. wmaker handles synchronization itself */
243         if (strcmp(WMGetApplicationName(), "WindowMaker") == 0) {
244                 defaults->dontSync = 1;
245         }
246
247         path = wdefaultspathfordomain(WMGetFromPLString(key));
248
249         if (stat(path, &stbuf) >= 0)
250                 defaults->timestamp = stbuf.st_mtime;
251
252         domain = WMReadPropListFromFile(path);
253
254         if (!domain)
255                 domain = WMCreatePLDictionary(NULL, NULL);
256
257         if (path)
258                 wfree(path);
259
260         defaults->appDomain = domain;
261
262         if (domain)
263                 WMPutInPLDictionary(defaults->defaults, key, domain);
264
265         /* global domain */
266         key = WMCreatePLString("WMGLOBAL");
267         defaults->searchList[1] = key;
268
269         path = wdefaultspathfordomain(WMGetFromPLString(key));
270
271         domain = WMReadPropListFromFile(path);
272
273         wfree(path);
274
275         if (!domain)
276                 domain = WMCreatePLDictionary(NULL, NULL);
277
278         if (domain)
279                 WMPutInPLDictionary(defaults->defaults, key, domain);
280
281         /* terminate list */
282         defaults->searchList[2] = NULL;
283
284         defaults->searchListArray = WMCreatePLArray(NULL, NULL);
285
286         i = 0;
287         while (defaults->searchList[i]) {
288                 WMAddToPLArray(defaults->searchListArray, defaults->searchList[i]);
289                 i++;
290         }
291
292         if (sharedUserDefaults)
293                 defaults->next = sharedUserDefaults;
294         sharedUserDefaults = defaults;
295
296         registerSaveOnExit();
297
298         return defaults;
299 }
300
301 WMUserDefaults *WMGetDefaultsFromPath(char *path)
302 {
303         WMUserDefaults *defaults;
304         WMPropList *domain;
305         WMPropList *key;
306         struct stat stbuf;
307         char *name;
308         int i;
309
310         assert(path != NULL);
311
312         if (sharedUserDefaults) {
313                 defaults = sharedUserDefaults;
314                 while (defaults) {
315                         if (defaults->path && strcmp(defaults->path, path) == 0)
316                                 return defaults;
317                         defaults = defaults->next;
318                 }
319         }
320
321         /* we didn't found the database we are looking for. Go read it. */
322         defaults = wmalloc(sizeof(WMUserDefaults));
323         memset(defaults, 0, sizeof(WMUserDefaults));
324
325         defaults->defaults = WMCreatePLDictionary(NULL, NULL);
326
327         defaults->searchList = wmalloc(sizeof(WMPropList *) * 2);
328
329         /* the domain we want, go in the first position */
330         name = strrchr(path, '/');
331         if (!name)
332                 name = path;
333         else
334                 name++;
335
336         key = WMCreatePLString(name);
337         defaults->searchList[0] = key;
338
339         if (stat(path, &stbuf) >= 0)
340                 defaults->timestamp = stbuf.st_mtime;
341
342         domain = WMReadPropListFromFile(path);
343
344         if (!domain)
345                 domain = WMCreatePLDictionary(NULL, NULL);
346
347         defaults->path = wstrdup(path);
348
349         defaults->appDomain = domain;
350
351         if (domain)
352                 WMPutInPLDictionary(defaults->defaults, key, domain);
353
354         /* terminate list */
355         defaults->searchList[1] = NULL;
356
357         defaults->searchListArray = WMCreatePLArray(NULL, NULL);
358
359         i = 0;
360         while (defaults->searchList[i]) {
361                 WMAddToPLArray(defaults->searchListArray, defaults->searchList[i]);
362                 i++;
363         }
364
365         if (sharedUserDefaults)
366                 defaults->next = sharedUserDefaults;
367         sharedUserDefaults = defaults;
368
369         registerSaveOnExit();
370
371         return defaults;
372 }
373
374 /* Returns a WMPropList array with all keys in the user defaults database.
375  * Free the array with WMReleasePropList() when no longer needed,
376  * but do not free the elements of the array! They're just references. */
377 WMPropList *WMGetUDKeys(WMUserDefaults * database)
378 {
379         return WMGetPLDictionaryKeys(database->appDomain);
380 }
381
382 WMPropList *WMGetUDObjectForKey(WMUserDefaults * database, char *defaultName)
383 {
384         WMPropList *domainName, *domain;
385         WMPropList *object = NULL;
386         WMPropList *key = WMCreatePLString(defaultName);
387         int i = 0;
388
389         while (database->searchList[i] && !object) {
390                 domainName = database->searchList[i];
391                 domain = WMGetFromPLDictionary(database->defaults, domainName);
392                 if (domain) {
393                         object = WMGetFromPLDictionary(domain, key);
394                 }
395                 i++;
396         }
397         WMReleasePropList(key);
398
399         return object;
400 }
401
402 void WMSetUDObjectForKey(WMUserDefaults * database, WMPropList * object, char *defaultName)
403 {
404         WMPropList *key = WMCreatePLString(defaultName);
405
406         database->dirty = 1;
407
408         WMPutInPLDictionary(database->appDomain, key, object);
409         WMReleasePropList(key);
410 }
411
412 void WMRemoveUDObjectForKey(WMUserDefaults * database, char *defaultName)
413 {
414         WMPropList *key = WMCreatePLString(defaultName);
415
416         database->dirty = 1;
417
418         WMRemoveFromPLDictionary(database->appDomain, key);
419
420         WMReleasePropList(key);
421 }
422
423 char *WMGetUDStringForKey(WMUserDefaults * database, char *defaultName)
424 {
425         WMPropList *val;
426
427         val = WMGetUDObjectForKey(database, defaultName);
428
429         if (!val)
430                 return NULL;
431
432         if (!WMIsPLString(val))
433                 return NULL;
434
435         return WMGetFromPLString(val);
436 }
437
438 int WMGetUDIntegerForKey(WMUserDefaults * database, char *defaultName)
439 {
440         WMPropList *val;
441         char *str;
442         int value;
443
444         val = WMGetUDObjectForKey(database, defaultName);
445
446         if (!val)
447                 return 0;
448
449         if (!WMIsPLString(val))
450                 return 0;
451
452         str = WMGetFromPLString(val);
453         if (!str)
454                 return 0;
455
456         if (sscanf(str, "%i", &value) != 1)
457                 return 0;
458
459         return value;
460 }
461
462 float WMGetUDFloatForKey(WMUserDefaults * database, char *defaultName)
463 {
464         WMPropList *val;
465         char *str;
466         float value;
467
468         val = WMGetUDObjectForKey(database, defaultName);
469
470         if (!val || !WMIsPLString(val))
471                 return 0.0;
472
473         if (!(str = WMGetFromPLString(val)))
474                 return 0.0;
475
476         if (sscanf(str, "%f", &value) != 1)
477                 return 0.0;
478
479         return value;
480 }
481
482 Bool WMGetUDBoolForKey(WMUserDefaults * database, char *defaultName)
483 {
484         WMPropList *val;
485         int value;
486         char *str;
487
488         val = WMGetUDObjectForKey(database, defaultName);
489
490         if (!val)
491                 return False;
492
493         if (!WMIsPLString(val))
494                 return False;
495
496         str = WMGetFromPLString(val);
497         if (!str)
498                 return False;
499
500         if (sscanf(str, "%i", &value) == 1 && value != 0)
501                 return True;
502
503         if (strcasecmp(str, "YES") == 0)
504                 return True;
505
506         if (strcasecmp(str, "Y") == 0)
507                 return True;
508
509         return False;
510 }
511
512 void WMSetUDIntegerForKey(WMUserDefaults * database, int value, char *defaultName)
513 {
514         WMPropList *object;
515         char buffer[128];
516
517         sprintf(buffer, "%i", value);
518         object = WMCreatePLString(buffer);
519
520         WMSetUDObjectForKey(database, object, defaultName);
521         WMReleasePropList(object);
522 }
523
524 void WMSetUDStringForKey(WMUserDefaults * database, char *value, char *defaultName)
525 {
526         WMPropList *object;
527
528         object = WMCreatePLString(value);
529
530         WMSetUDObjectForKey(database, object, defaultName);
531         WMReleasePropList(object);
532 }
533
534 void WMSetUDFloatForKey(WMUserDefaults * database, float value, char *defaultName)
535 {
536         WMPropList *object;
537         char buffer[128];
538
539         sprintf(buffer, "%f", value);
540         object = WMCreatePLString(buffer);
541
542         WMSetUDObjectForKey(database, object, defaultName);
543         WMReleasePropList(object);
544 }
545
546 void WMSetUDBoolForKey(WMUserDefaults * database, Bool value, char *defaultName)
547 {
548         static WMPropList *yes = NULL, *no = NULL;
549
550         if (!yes) {
551                 yes = WMCreatePLString("YES");
552                 no = WMCreatePLString("NO");
553         }
554
555         WMSetUDObjectForKey(database, value ? yes : no, defaultName);
556 }
557
558 WMPropList *WMGetUDSearchList(WMUserDefaults * database)
559 {
560         return database->searchListArray;
561 }
562
563 void WMSetUDSearchList(WMUserDefaults * database, WMPropList * list)
564 {
565         int i, c;
566
567         if (database->searchList) {
568                 i = 0;
569                 while (database->searchList[i]) {
570                         WMReleasePropList(database->searchList[i]);
571                         i++;
572                 }
573                 wfree(database->searchList);
574         }
575         if (database->searchListArray) {
576                 WMReleasePropList(database->searchListArray);
577         }
578
579         c = WMGetPropListItemCount(list);
580         database->searchList = wmalloc(sizeof(WMPropList *) * (c + 1));
581
582         for (i = 0; i < c; i++) {
583                 database->searchList[i] = WMGetFromPLArray(list, i);
584         }
585         database->searchList[c] = NULL;
586
587         database->searchListArray = WMDeepCopyPropList(list);
588 }