- added strcasecmp() to WINGs (only on systems that don't have it)
[wmaker-crm.git] / WINGs / userdefaults.c
blob892d7f659fdf36063232efe0cc65431ee8f251e5
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>
10 #include "wconfig.h"
12 #include "WINGs.h"
16 typedef struct W_UserDefaults {
17 WMPropList *defaults;
19 WMPropList *appDomain;
21 WMPropList *searchListArray;
22 WMPropList **searchList; /* cache for searchListArray */
24 char dirty;
26 char dontSync;
28 char *path; /* where is db located */
30 time_t timestamp; /* last modification time */
32 struct W_UserDefaults *next;
34 } UserDefaults;
37 static UserDefaults *sharedUserDefaults = NULL;
39 char *WMUserDefaultsDidChangeNotification = "WMUserDefaultsDidChangeNotification";
43 extern char *WMGetApplicationName();
45 #define DEFAULTS_DIR "/Defaults"
47 #define UD_SYNC_INTERVAL 2000
51 char*
52 wusergnusteppath()
54 static char *path = NULL;
55 char *gspath;
56 int pathlen;
58 if (!path) {
59 gspath = getenv("GNUSTEP_USER_ROOT");
60 if (gspath) {
61 gspath = wexpandpath(gspath);
62 pathlen = strlen(gspath) + 4;
63 path = wmalloc(pathlen);
64 strcpy(path, gspath);
65 wfree(gspath);
66 } else {
67 pathlen = strlen(wgethomedir()) + 10;
68 path = wmalloc(pathlen);
69 strcpy(path, wgethomedir());
70 strcat(path, "/GNUstep");
74 return path;
78 char*
79 wdefaultspathfordomain(char *domain)
81 char *path;
82 char *gspath;
84 gspath = wusergnusteppath();
85 path = wmalloc(strlen(gspath)+strlen(DEFAULTS_DIR)+strlen(domain)+4);
86 strcpy(path, gspath);
87 strcat(path, DEFAULTS_DIR);
88 strcat(path, "/");
89 strcat(path, domain);
91 return path;
95 static void
96 #ifndef HAVE_ATEXIT
97 saveDefaultsChanges(int foo, void *bar)
98 #else
99 saveDefaultsChanges(void)
100 #endif
102 /* save the user defaults databases */
103 UserDefaults *tmp = sharedUserDefaults;
105 while (tmp) {
106 WMSynchronizeUserDefaults(tmp);
107 tmp = tmp->next;
112 /* set to save changes in defaults when program is exited */
113 static void
114 registerSaveOnExit(void)
116 static Bool registeredSaveOnExit = False;
118 if (!registeredSaveOnExit) {
119 #ifndef HAVE_ATEXIT
120 on_exit(saveDefaultsChanges, (void*)NULL);
121 #else
122 atexit(saveDefaultsChanges);
123 #endif
124 registeredSaveOnExit = True;
129 static void
130 synchronizeUserDefaults(void *foo)
132 UserDefaults *database = sharedUserDefaults;
134 while (database) {
135 if (!database->dontSync)
136 WMSynchronizeUserDefaults(database);
137 database = database->next;
139 WMAddTimerHandler(UD_SYNC_INTERVAL, synchronizeUserDefaults, NULL);
143 static void
144 addSynchronizeTimerHandler(void)
146 static Bool initialized = False;
148 if (!initialized) {
149 WMAddTimerHandler(UD_SYNC_INTERVAL, synchronizeUserDefaults, NULL);
150 initialized = True;
155 void
156 WMEnableUDPeriodicSynchronization(WMUserDefaults *database, Bool enable)
158 database->dontSync = !enable;
162 void
163 WMSynchronizeUserDefaults(WMUserDefaults *database)
165 Bool fileIsNewer = False, release = False, notify = False;
166 WMPropList *plF, *key;
167 char *path;
168 struct stat stbuf;
170 if (!database->path) {
171 path = wdefaultspathfordomain(WMGetApplicationName());
172 release = True;
173 } else {
174 path = database->path;
177 if (stat(path, &stbuf) >= 0 && stbuf.st_mtime > database->timestamp)
178 fileIsNewer = True;
180 if (database->appDomain && (database->dirty || fileIsNewer)) {
181 if (database->dirty && fileIsNewer) {
182 plF = WMReadPropListFromFile(path);
183 if (plF) {
184 plF = WMMergePLDictionaries(plF, database->appDomain);
185 WMReleasePropList(database->appDomain);
186 database->appDomain = plF;
187 key = database->searchList[0];
188 WMPutInPLDictionary(database->defaults, key, plF);
189 notify = True;
190 } else {
191 /* something happened with the file. just overwrite it */
192 wwarning(_("cannot read domain from file '%s' when syncing"),
193 path);
194 WMWritePropListToFile(database->appDomain, path, True);
196 } else if (database->dirty) {
197 WMWritePropListToFile(database->appDomain, path, True);
198 } else if (fileIsNewer) {
199 plF = WMReadPropListFromFile(path);
200 if (plF) {
201 WMReleasePropList(database->appDomain);
202 database->appDomain = plF;
203 key = database->searchList[0];
204 WMPutInPLDictionary(database->defaults, key, plF);
205 notify = True;
206 } else {
207 /* something happened with the file. just overwrite it */
208 wwarning(_("cannot read domain from file '%s' when syncing"),
209 path);
210 WMWritePropListToFile(database->appDomain, path, True);
214 database->dirty = 0;
216 if (stat(path, &stbuf) >= 0)
217 database->timestamp = stbuf.st_mtime;
219 if (notify) {
220 WMPostNotificationName(WMUserDefaultsDidChangeNotification,
221 database, NULL);
225 if (release)
226 wfree(path);
231 void
232 WMSaveUserDefaults(WMUserDefaults *database)
234 if (database->appDomain) {
235 struct stat stbuf;
236 char *path;
237 Bool release = False;
239 if (!database->path) {
240 path = wdefaultspathfordomain(WMGetApplicationName());
241 release = True;
242 } else {
243 path = database->path;
245 WMWritePropListToFile(database->appDomain, path, True);
246 database->dirty = 0;
247 if (stat(path, &stbuf) >= 0)
248 database->timestamp = stbuf.st_mtime;
249 if (release)
250 wfree(path);
255 WMUserDefaults*
256 WMGetStandardUserDefaults(void)
258 WMUserDefaults *defaults;
259 WMPropList *domain;
260 WMPropList *key;
261 struct stat stbuf;
262 char *path;
263 int i;
265 if (sharedUserDefaults) {
266 defaults = sharedUserDefaults;
267 while (defaults) {
268 /* Trick, path == NULL only for StandardUserDefaults db */
269 if (defaults->path == NULL)
270 return defaults;
271 defaults = defaults->next;
275 /* we didn't found the database we are looking for. Go read it. */
276 defaults = wmalloc(sizeof(WMUserDefaults));
277 memset(defaults, 0, sizeof(WMUserDefaults));
279 defaults->defaults = WMCreatePLDictionary(NULL, NULL, NULL);
281 defaults->searchList = wmalloc(sizeof(WMPropList*)*3);
283 /* application domain */
284 key = WMCreatePLString(WMGetApplicationName());
285 defaults->searchList[0] = key;
287 /* temporary kluge */
288 if (strcmp(WMGetApplicationName(), "WindowMaker")==0) {
289 domain = NULL;
290 path = NULL;
291 } else {
292 path = wdefaultspathfordomain(WMGetFromPLString(key));
294 if (stat(path, &stbuf) >= 0)
295 defaults->timestamp = stbuf.st_mtime;
297 domain = WMReadPropListFromFile(path);
300 if (!domain)
301 domain = WMCreatePLDictionary(NULL, NULL, NULL);
303 if (path)
304 wfree(path);
306 defaults->appDomain = domain;
308 if (domain)
309 WMPutInPLDictionary(defaults->defaults, key, domain);
311 /* global domain */
312 key = WMCreatePLString("WMGLOBAL");
313 defaults->searchList[1] = key;
315 path = wdefaultspathfordomain(WMGetFromPLString(key));
317 domain = WMReadPropListFromFile(path);
319 wfree(path);
321 if (!domain)
322 domain = WMCreatePLDictionary(NULL, NULL, NULL);
324 if (domain)
325 WMPutInPLDictionary(defaults->defaults, key, domain);
327 /* terminate list */
328 defaults->searchList[2] = NULL;
330 defaults->searchListArray = WMCreatePLArray(NULL,NULL);
332 i = 0;
333 while (defaults->searchList[i]) {
334 WMAddToPLArray(defaults->searchListArray,
335 defaults->searchList[i]);
336 i++;
339 if (sharedUserDefaults)
340 defaults->next = sharedUserDefaults;
341 sharedUserDefaults = defaults;
343 addSynchronizeTimerHandler();
344 registerSaveOnExit();
346 return defaults;
350 WMUserDefaults*
351 WMGetDefaultsFromPath(char *path)
353 WMUserDefaults *defaults;
354 WMPropList *domain;
355 WMPropList *key;
356 struct stat stbuf;
357 char *name;
358 int i;
360 assert(path != NULL);
362 if (sharedUserDefaults) {
363 defaults = sharedUserDefaults;
364 while (defaults) {
365 if (defaults->path && strcmp(defaults->path, path) == 0)
366 return defaults;
367 defaults = defaults->next;
371 /* we didn't found the database we are looking for. Go read it. */
372 defaults = wmalloc(sizeof(WMUserDefaults));
373 memset(defaults, 0, sizeof(WMUserDefaults));
375 defaults->defaults = WMCreatePLDictionary(NULL, NULL, NULL);
377 defaults->searchList = wmalloc(sizeof(WMPropList*)*2);
379 /* the domain we want, go in the first position */
380 name = strrchr(path, '/');
381 if (!name)
382 name = path;
383 else
384 name++;
386 key = WMCreatePLString(name);
387 defaults->searchList[0] = key;
389 if (stat(path, &stbuf) >= 0)
390 defaults->timestamp = stbuf.st_mtime;
392 domain = WMReadPropListFromFile(path);
394 if (!domain)
395 domain = WMCreatePLDictionary(NULL, NULL, NULL);
397 defaults->path = wstrdup(path);
399 defaults->appDomain = domain;
401 if (domain)
402 WMPutInPLDictionary(defaults->defaults, key, domain);
404 /* terminate list */
405 defaults->searchList[1] = NULL;
407 defaults->searchListArray = WMCreatePLArray(NULL,NULL);
409 i = 0;
410 while (defaults->searchList[i]) {
411 WMAddToPLArray(defaults->searchListArray,
412 defaults->searchList[i]);
413 i++;
416 if (sharedUserDefaults)
417 defaults->next = sharedUserDefaults;
418 sharedUserDefaults = defaults;
420 addSynchronizeTimerHandler();
421 registerSaveOnExit();
423 return defaults;
427 /* Returns a WMPropList array with all keys in the user defaults database.
428 * Free the array with WMReleasePropList() when no longer needed,
429 * but do not free the elements of the array! They're just references. */
430 WMPropList*
431 WMGetUDKeys(WMUserDefaults *database)
433 return WMGetPLDictionaryKeys(database->appDomain);
437 WMPropList*
438 WMGetUDObjectForKey(WMUserDefaults *database, char *defaultName)
440 WMPropList *domainName, *domain;
441 WMPropList *object = NULL;
442 WMPropList *key = WMCreatePLString(defaultName);
443 int i = 0;
445 while (database->searchList[i] && !object) {
446 domainName = database->searchList[i];
447 domain = WMGetFromPLDictionary(database->defaults, domainName);
448 if (domain) {
449 object = WMGetFromPLDictionary(domain, key);
451 i++;
453 WMReleasePropList(key);
455 return object;
459 void
460 WMSetUDObjectForKey(WMUserDefaults *database, WMPropList *object,
461 char *defaultName)
463 WMPropList *key = WMCreatePLString(defaultName);
465 database->dirty = 1;
467 WMPutInPLDictionary(database->appDomain, key, object);
468 WMReleasePropList(key);
472 void
473 WMRemoveUDObjectForKey(WMUserDefaults *database, char *defaultName)
475 WMPropList *key = WMCreatePLString(defaultName);
477 database->dirty = 1;
479 WMRemoveFromPLDictionary(database->appDomain, key);
481 WMReleasePropList(key);
485 char*
486 WMGetUDStringForKey(WMUserDefaults *database, char *defaultName)
488 WMPropList *val;
490 val = WMGetUDObjectForKey(database, defaultName);
492 if (!val)
493 return NULL;
495 if (!WMIsPLString(val))
496 return NULL;
498 return WMGetFromPLString(val);
503 WMGetUDIntegerForKey(WMUserDefaults *database, char *defaultName)
505 WMPropList *val;
506 char *str;
507 int value;
509 val = WMGetUDObjectForKey(database, defaultName);
511 if (!val)
512 return 0;
514 if (!WMIsPLString(val))
515 return 0;
517 str = WMGetFromPLString(val);
518 if (!str)
519 return 0;
521 if (sscanf(str, "%i", &value)!=1)
522 return 0;
524 return value;
529 float
530 WMGetUDFloatForKey(WMUserDefaults *database, char *defaultName)
532 WMPropList *val;
533 char *str;
534 float value;
536 val = WMGetUDObjectForKey(database, defaultName);
538 if (!val || !WMIsPLString(val))
539 return 0.0;
541 if (!(str = WMGetFromPLString(val)))
542 return 0.0;
544 if (sscanf(str, "%f", &value)!=1)
545 return 0.0;
547 return value;
552 Bool
553 WMGetUDBoolForKey(WMUserDefaults *database, char *defaultName)
555 WMPropList *val;
556 int value;
557 char *str;
559 val = WMGetUDObjectForKey(database, defaultName);
561 if (!val)
562 return False;
564 if (!WMIsPLString(val))
565 return False;
567 str = WMGetFromPLString(val);
568 if (!str)
569 return False;
571 if (sscanf(str, "%i", &value)==1 && value!=0)
572 return True;
574 if (strcasecmp(str, "YES")==0)
575 return True;
577 if (strcasecmp(str, "Y")==0)
578 return True;
580 return False;
584 void
585 WMSetUDIntegerForKey(WMUserDefaults *database, int value, char *defaultName)
587 WMPropList *object;
588 char buffer[128];
590 sprintf(buffer, "%i", value);
591 object = WMCreatePLString(buffer);
593 WMSetUDObjectForKey(database, object, defaultName);
594 WMReleasePropList(object);
600 void
601 WMSetUDStringForKey(WMUserDefaults *database, char *value, char *defaultName)
603 WMPropList *object;
605 object = WMCreatePLString(value);
607 WMSetUDObjectForKey(database, object, defaultName);
608 WMReleasePropList(object);
613 void
614 WMSetUDFloatForKey(WMUserDefaults *database, float value, char *defaultName)
616 WMPropList *object;
617 char buffer[128];
619 sprintf(buffer, "%f", value);
620 object = WMCreatePLString(buffer);
622 WMSetUDObjectForKey(database, object, defaultName);
623 WMReleasePropList(object);
628 void
629 WMSetUDBoolForKey(WMUserDefaults *database, Bool value, char *defaultName)
631 static WMPropList *yes = NULL, *no = NULL;
633 if (!yes) {
634 yes = WMCreatePLString("YES");
635 no = WMCreatePLString("NO");
638 WMSetUDObjectForKey(database, value ? yes : no, defaultName);
642 WMPropList*
643 WMGetUDSearchList(WMUserDefaults *database)
645 return database->searchListArray;
649 void
650 WMSetUDSearchList(WMUserDefaults *database, WMPropList *list)
652 int i, c;
654 if (database->searchList) {
655 i = 0;
656 while (database->searchList[i]) {
657 WMReleasePropList(database->searchList[i]);
658 i++;
660 wfree(database->searchList);
662 if (database->searchListArray) {
663 WMReleasePropList(database->searchListArray);
666 c = WMGetPropListItemCount(list);
667 database->searchList = wmalloc(sizeof(WMPropList*)*(c+1));
669 for (i=0; i<c; i++) {
670 database->searchList[i] = WMGetFromPLArray(list, i);
673 database->searchListArray = WMDeepCopyPropList(list);