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 }