more code for proplist handling (almost finished)
[wmaker-crm.git] / WINGs / proplist.c
blob511628fe10b19a5bb29d7105e1eaad4ae757f834
3 #include <string.h>
4 #include <stdarg.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <unistd.h>
10 #include <ctype.h>
12 #include "WUtil.h"
13 #include "wconfig.h"
17 typedef enum {
18 WPLString = 0x57504c01,
19 WPLData = 0x57504c02,
20 WPLArray = 0x57504c03,
21 WPLDictionary = 0x57504c04
22 } WPLType;
25 typedef struct W_PropList {
26 WPLType type;
28 union {
29 char *string;
30 WMData *data;
31 WMArray *array;
32 WMHashTable *dict;
33 } d;
35 int retainCount;
36 } W_PropList;
40 static unsigned hashPropList(WMPropList *plist);
44 typedef unsigned (*hashFunc)(const void*);
45 typedef Bool (*isEqualFunc)(const void*, const void*);
46 typedef void* (*retainFunc)(const void*);
47 typedef void (*releaseFunc)(const void*);
49 static const WMHashTableCallbacks WMPropListHashCallbacks = {
50 (hashFunc)hashPropList,
51 (isEqualFunc)WMIsPropListEqualToPropList,
52 (retainFunc)NULL,
53 (releaseFunc)NULL
57 static WMCompareDataProc *strCmp = (WMCompareDataProc*) strcmp;
60 #define MaxHashLength 64
63 static unsigned
64 hashPropList(WMPropList *plist)
66 unsigned ret = 0;
67 unsigned ctr = 0;
68 const char *key;
69 int i, len;
71 switch (plist->type) {
72 case WPLString:
73 key = plist->d.string;
74 len = WMIN(strlen(key), MaxHashLength);
75 for (i=0; i<len; i++) {
76 ret ^= tolower(key[i]) << ctr;
77 ctr = (ctr + 1) % sizeof (char *);
79 /*while (*key) {
80 ret ^= tolower(*key++) << ctr;
81 ctr = (ctr + 1) % sizeof (char *);
82 }*/
83 return ret;
84 /*return strlen(plist->d.string);*/
86 case WPLData:
87 key = WMDataBytes(plist->d.data);
88 len = WMIN(WMGetDataLength(plist->d.data), MaxHashLength);
89 for (i=0; i<len; i++) {
90 ret ^= key[i] << ctr;
91 ctr = (ctr + 1) % sizeof (char *);
93 return ret;
94 /*return WMGetDataLength(plist->d.data);*/
96 default:
97 wwarning(_("Only string or data is supported for a proplist dictionary key"));
98 wassertrv(False, 0);
102 /*WMSetPropListStringComparisonCaseSensitive
103 WMSetPropListStringComparerIsCaseSensitive
104 WMSetPLStringComparisonCaseSensitive*/
106 static WMPropList*
107 retainPropListByCount(WMPropList *plist, int count)
109 WMPropList *key, *value;
110 WMHashEnumerator e;
111 int i;
113 plist->retainCount += count;
115 switch(plist->type) {
116 case WPLString:
117 case WPLData:
118 break;
119 case WPLArray:
120 for (i=0; i<WMGetArrayItemCount(plist->d.array); i++) {
121 retainPropListByCount(WMGetFromArray(plist->d.array, i), count);
123 break;
124 case WPLDictionary:
125 e = WMEnumerateHashTable(plist->d.dict);
126 while (WMNextHashEnumeratorItemAndKey(&e, (void**)&value, (void**)&key)) {
127 retainPropListByCount(key, count);
128 retainPropListByCount(value, count);
130 break;
131 default:
132 wwarning(_("Used proplist functions on non-WMPropLists objects"));
133 wassertrv(False, NULL);
136 return plist;
140 static void
141 releasePropListByCount(WMPropList *plist, int count)
143 WMPropList *key, *value;
144 WMHashEnumerator e;
145 int i;
147 plist->retainCount -= count;
149 switch(plist->type) {
150 case WPLString:
151 if (plist->retainCount < 1) {
152 wfree(plist->d.string);
153 wfree(plist);
155 break;
156 case WPLData:
157 if (plist->retainCount < 1) {
158 WMReleaseData(plist->d.data);
159 wfree(plist);
161 break;
162 case WPLArray:
163 for (i=0; i<WMGetArrayItemCount(plist->d.array); i++) {
164 releasePropListByCount(WMGetFromArray(plist->d.array, i), count);
166 if (plist->retainCount < 1) {
167 WMFreeArray(plist->d.array);
168 wfree(plist);
170 break;
171 case WPLDictionary:
172 e = WMEnumerateHashTable(plist->d.dict);
173 while (WMNextHashEnumeratorItemAndKey(&e, (void**)&value, (void**)&key)) {
174 releasePropListByCount(key, count);
175 releasePropListByCount(value, count);
177 if (plist->retainCount < 1) {
178 WMFreeHashTable(plist->d.dict);
179 wfree(plist);
181 break;
182 default:
183 wwarning(_("Used proplist functions on non-WMPropLists objects"));
184 wassertr(False);
189 #define num2char(num) ((num) < 0xa ? ((num)+'0') : ((num)+0x57))
191 static char*
192 dataDescription(WMPropList *plist)
194 const unsigned char *data;
195 char *retVal;
196 int i, j, length;
198 data = WMDataBytes(plist->d.data);
199 length = WMGetDataLength(plist->d.data);
201 retVal = (char*)wmalloc(2*length+length/4+3);
203 retVal[0] = '<';
204 for (i=0, j=1; i<length; i++) {
205 retVal[j++] = num2char((data[i]>>4) & 0x0f);
206 retVal[j++] = num2char(data[i] & 0x0f);
207 if ((i & 0x03)==3 && i!=length-1) {
208 /* if we've just finished a 32-bit int, add a space */
209 retVal[j++] = ' ';
212 retVal[j++] = '>';
213 retVal[j] = '\0';
215 return retVal;
219 static char*
220 stringDescription(WMPropList *plist)
222 const char *str;
223 char *retVal, *sPtr, *dPtr;
224 int len, quote;
225 unsigned char ch;
227 str = plist->d.string;
229 if (strlen(str) == 0) {
230 return wstrdup("\"\"");
233 /* FIXME: make this work with unichars. */
235 #define inrange(ch, min, max) ((ch)>=(min) && (ch)<=(max))
236 #define noquote(ch) (inrange(ch, 'a', 'z') || inrange(ch, 'A', 'Z') || inrange(ch, '0', '9') || ((ch)=='_') || ((ch)=='.') || ((ch)=='$'))
237 #define charesc(ch) (inrange(ch, 0x07, 0x0c) || ((ch)=='"') || ((ch)=='\\'))
238 #define numesc(ch) (((ch)<=0x06) || inrange(ch, 0x0d, 0x1f) || ((ch)>0x7e))
240 quote = 0;
241 sPtr = (char*) str;
242 len = 0;
243 while ((ch = *sPtr)) {
244 if (!noquote(ch)) {
245 quote = 1;
246 if (charesc(ch))
247 len++;
248 else if (numesc(ch))
249 len += 3;
251 sPtr++;
252 len++;
255 if (quote)
256 len += 2;
258 retVal = (char*)wmalloc(len+1);
260 sPtr = (char*) str;
261 dPtr = retVal;
263 if (quote)
264 *dPtr++ = '"';
266 while ((ch = *sPtr)) {
267 if (charesc(ch)) {
268 *(dPtr++) = '\\';
269 switch (ch) {
270 case '\a': *dPtr = 'a'; break;
271 case '\b': *dPtr = 'b'; break;
272 case '\t': *dPtr = 't'; break;
273 case '\n': *dPtr = 'n'; break;
274 case '\v': *dPtr = 'v'; break;
275 case '\f': *dPtr = 'f'; break;
276 default: *dPtr = ch; /* " or \ */
278 } else if (numesc(ch)) {
279 *(dPtr++) = '\\';
280 *(dPtr++) = '0' + ((ch>>6)&07);
281 *(dPtr++) = '0' + ((ch>>3)&07);
282 *dPtr = '0' + (ch&07);
283 } else {
284 *dPtr = ch;
286 sPtr++;
287 dPtr++;
290 if (quote)
291 *dPtr++ = '"';
293 *dPtr = '\0';
295 return retVal;
299 static char*
300 description(WMPropList *plist)
302 WMPropList *key, *val;
303 char *retstr, *str, *tmp, *skey, *sval;
304 WMHashEnumerator e;
305 int i;
307 switch (plist->type) {
308 case WPLString:
309 return stringDescription(plist);
310 case WPLData:
311 return dataDescription(plist);
312 case WPLArray:
313 retstr = wstrdup("(");
314 for (i=0; i<WMGetArrayItemCount(plist->d.array); i++) {
315 str = description(WMGetFromArray(plist->d.array, i));
316 if (i==0) {
317 retstr = wstrappend(retstr, str);
318 } else {
319 tmp = (char *)wmalloc(strlen(retstr)+strlen(str)+3);
320 sprintf(tmp, "%s, %s", retstr, str);
321 wfree(retstr);
322 retstr = tmp;
324 wfree(str);
326 retstr = wstrappend(retstr, ")");
327 break;
328 case WPLDictionary:
329 retstr = wstrdup("{");
330 e = WMEnumerateHashTable(plist->d.dict);
331 while (WMNextHashEnumeratorItemAndKey(&e, (void**)&val, (void**)&key)) {
332 skey = description(key);
333 sval = description(val);
334 tmp = (char*)wmalloc(strlen(retstr)+strlen(skey)+strlen(sval)+5);
335 sprintf(tmp, "%s%s = %s;", retstr, skey, sval);
336 wfree(skey);
337 wfree(sval);
338 wfree(retstr);
339 retstr = tmp;
341 retstr = wstrappend(retstr, "}");
342 break;
343 default:
344 wwarning(_("Used proplist functions on non-WMPropLists objects"));
345 wassertrv(False, NULL);
348 return retstr;
352 static char*
353 indentedDescription(WMPropList *plist, int level)
355 WMPropList *key, *val;
356 char *retstr, *str, *tmp, *skey, *sval;
357 WMHashEnumerator e;
358 int i;
360 switch (plist->type) {
361 case WPLString:
362 return stringDescription(plist);
363 case WPLData:
364 return dataDescription(plist);
365 case WPLArray:
366 retstr = wstrdup("(\n");
367 for (i=0; i<WMGetArrayItemCount(plist->d.array); i++) {
368 str = indentedDescription(WMGetFromArray(plist->d.array, i),
369 level+1);
370 if (i==0) {
371 tmp = (char*)wmalloc(2*(level+1)+strlen(retstr)+strlen(str)+1);
372 sprintf(tmp, "%s%*s%s", retstr, 2*(level+1), "", str);
373 wfree(retstr);
374 retstr = tmp;
375 } else {
376 tmp = (char*)wmalloc(2*(level+1)+strlen(retstr)+strlen(str)+3);
377 sprintf(tmp, "%s,\n%*s%s", retstr, 2*(level+1), "", str);
378 wfree(retstr);
379 retstr = tmp;
381 wfree(str);
383 tmp = (char*)wmalloc(strlen(retstr) + 2*level + 3);
384 sprintf(tmp, "%s\n%*s)", retstr, 2*level, "");
385 wfree(retstr);
386 retstr = tmp;
387 break;
388 case WPLDictionary:
389 retstr = wstrdup("{\n");
390 e = WMEnumerateHashTable(plist->d.dict);
391 while (WMNextHashEnumeratorItemAndKey(&e, (void**)&val, (void**)&key)) {
392 skey = indentedDescription(key, level+1);
393 sval = indentedDescription(val, level+1);
394 tmp = (char*)wmalloc(2*(level+1) + strlen(retstr) + strlen(skey)
395 + strlen(sval) + 6);
396 sprintf(tmp, "%s%*s%s = %s;\n", retstr, 2*(level+1), "",
397 skey, sval);
398 wfree(skey);
399 wfree(sval);
400 wfree(retstr);
401 retstr = tmp;
403 tmp = (char*)wmalloc(strlen(retstr) + 2*level + 2);
404 sprintf(tmp, "%s%*s}", retstr, 2*level, "");
405 wfree(retstr);
406 retstr = tmp;
407 break;
408 default:
409 wwarning(_("Used proplist functions on non-WMPropLists objects"));
410 wassertrv(False, NULL);
413 return retstr;
417 void
418 WMSetPropListStringComparer(WMCompareDataProc *comparer)
420 if (!comparer)
421 strCmp = (WMCompareDataProc*) strcmp;
422 else
423 strCmp = comparer;
427 WMPropList*
428 WMCreatePropListString(char *str)
430 WMPropList *plist;
432 wassertrv(str!=NULL, NULL);
434 plist = (WMPropList*)wmalloc(sizeof(W_PropList));
436 plist->type = WPLString;
437 plist->d.string = wstrdup(str);
438 plist->retainCount = 1;
440 return plist;
444 WMPropList*
445 WMCreatePropListDataWithBytes(unsigned char *bytes, unsigned int length)
447 WMPropList *plist;
449 wassertrv(bytes!=NULL, NULL);
451 plist = (WMPropList*)wmalloc(sizeof(W_PropList));
453 plist->type = WPLData;
454 plist->d.data = WMCreateDataWithBytes(bytes, length);
455 plist->retainCount = 1;
457 return plist;
461 WMPropList*
462 WMCreatePropListDataWithBytesNoCopy(unsigned char *bytes, unsigned int length,
463 WMFreeDataProc *destructor)
465 WMPropList *plist;
467 wassertrv(bytes!=NULL, NULL);
469 plist = (WMPropList*)wmalloc(sizeof(W_PropList));
471 plist->type = WPLData;
472 plist->d.data = WMCreateDataWithBytesNoCopy(bytes, length, destructor);
473 plist->retainCount = 1;
475 return plist;
479 WMPropList*
480 WMCreatePropListDataWithData(WMData *data)
482 WMPropList *plist;
484 wassertrv(data!=NULL, NULL);
486 plist = (WMPropList*)wmalloc(sizeof(W_PropList));
488 plist->type = WPLData;
489 plist->d.data = WMRetainData(data);
490 plist->retainCount = 1;
492 return plist;
496 WMPropList*
497 WMCreatePropListArrayFromElements(WMPropList *elem, ...)
499 WMPropList *plist, *nelem;
500 va_list ap;
502 plist = (WMPropList*)wmalloc(sizeof(W_PropList));
503 plist->type = WPLArray;
504 plist->d.array = WMCreateArray(4);
505 plist->retainCount = 1;
507 if (!elem)
508 return plist;
510 WMAddToArray(plist->d.array, WMRetainPropList(elem));
512 va_start(ap, elem);
514 while (1) {
515 nelem = va_arg(ap, WMPropList*);
516 if(!nelem) {
517 va_end(ap);
518 return plist;
520 WMAddToArray(plist->d.array, WMRetainPropList(nelem));
525 WMPropList*
526 WMCreatePropListDictionaryFromEntries(WMPropList *key, WMPropList *value, ...)
528 WMPropList *plist, *nkey, *nvalue, *k, *v;
529 va_list ap;
531 plist = (WMPropList*)wmalloc(sizeof(W_PropList));
532 plist->type = WPLDictionary;
533 plist->d.dict = WMCreateHashTable(WMPropListHashCallbacks);
534 plist->retainCount = 1;
536 if (!key || !value)
537 return plist;
539 WMHashInsert(plist->d.dict, WMRetainPropList(key), WMRetainPropList(value));
541 va_start(ap, value);
543 while (1) {
544 nkey = va_arg(ap, WMPropList*);
545 if (!nkey) {
546 va_end(ap);
547 return plist;
549 nvalue = va_arg(ap, WMPropList*);
550 if (!nvalue) {
551 va_end(ap);
552 return plist;
554 if (WMHashGetItemAndKey(plist->d.dict, nkey, (void**)&v, (void**)&k)) {
555 WMHashRemove(plist->d.dict, k);
556 WMReleasePropList(k);
557 WMReleasePropList(v);
559 WMHashInsert(plist->d.dict, WMRetainPropList(nkey),
560 WMRetainPropList(nvalue));
565 void
566 WMInsertPropListArrayElement(WMPropList *plist, WMPropList *item, int index)
568 wassertr(plist->type==WPLArray);
570 retainPropListByCount(item, plist->retainCount);
571 WMInsertInArray(plist->d.array, index, item);
575 void
576 WMAppendPropListArrayElement(WMPropList *plist, WMPropList *item)
578 wassertr(plist->type==WPLArray);
580 retainPropListByCount(item, plist->retainCount);
581 WMAddToArray(plist->d.array, item);
585 void
586 WMRemovePropListArrayElement(WMPropList *plist, int index)
588 WMPropList *item;
590 wassertr(plist->type==WPLArray);
592 item = WMGetFromArray(plist->d.array, index);
593 if (item != NULL) {
594 WMDeleteFromArray(plist->d.array, index);
595 releasePropListByCount(item, plist->retainCount);
600 void
601 WMInsertPropListDictionaryEntry(WMPropList *plist, WMPropList *key,
602 WMPropList *value)
604 wassertr(plist->type==WPLDictionary);
606 WMRemovePropListDictionaryEntry(plist, key);
607 retainPropListByCount(key, plist->retainCount);
608 retainPropListByCount(value, plist->retainCount);
609 WMHashInsert(plist->d.dict, key, value);
613 void
614 WMRemovePropListDictionaryEntry(WMPropList *plist, WMPropList *key)
616 WMPropList *k, *v;
618 wassertr(plist->type==WPLDictionary);
620 if (WMHashGetItemAndKey(plist->d.dict, key, (void**)&v, (void**)&k)) {
621 WMHashRemove(plist->d.dict, k);
622 releasePropListByCount(k, plist->retainCount);
623 releasePropListByCount(v, plist->retainCount);
628 WMPropList*
629 WMMergePropListDictionaries(WMPropList *dest, WMPropList *source)
631 WMPropList *key, *value;
632 WMHashEnumerator e;
634 wassertr(source->type==WPLDictionary && dest->type==WPLDictionary);
636 e = WMEnumerateHashTable(source->d.dict);
637 while (WMNextHashEnumeratorItemAndKey(&e, (void**)&value, (void**)&key)) {
638 WMInsertPropListDictionaryEntry(dest, key, value);
641 return dest;
645 WMPropList*
646 WMRetainPropList(WMPropList *plist)
648 WMPropList *key, *value;
649 WMHashEnumerator e;
650 int i;
652 plist->retainCount++;
654 switch(plist->type) {
655 case WPLString:
656 case WPLData:
657 break;
658 case WPLArray:
659 for (i=0; i<WMGetArrayItemCount(plist->d.array); i++) {
660 WMRetainPropList(WMGetFromArray(plist->d.array, i));
662 break;
663 case WPLDictionary:
664 e = WMEnumerateHashTable(plist->d.dict);
665 while (WMNextHashEnumeratorItemAndKey(&e, (void**)&value, (void**)&key)) {
666 WMRetainPropList(key);
667 WMRetainPropList(value);
669 break;
670 default:
671 wwarning(_("Used proplist functions on non-WMPropLists objects"));
672 wassertrv(False, NULL);
675 return plist;
679 void
680 WMReleasePropList(WMPropList *plist)
682 WMPropList *key, *value;
683 WMHashEnumerator e;
684 int i;
686 plist->retainCount--;
688 switch(plist->type) {
689 case WPLString:
690 if (plist->retainCount < 1) {
691 wfree(plist->d.string);
692 wfree(plist);
694 break;
695 case WPLData:
696 if (plist->retainCount < 1) {
697 WMReleaseData(plist->d.data);
698 wfree(plist);
700 break;
701 case WPLArray:
702 for (i=0; i<WMGetArrayItemCount(plist->d.array); i++) {
703 WMReleasePropList(WMGetFromArray(plist->d.array, i));
705 if (plist->retainCount < 1) {
706 WMFreeArray(plist->d.array);
707 wfree(plist);
709 break;
710 case WPLDictionary:
711 e = WMEnumerateHashTable(plist->d.dict);
712 while (WMNextHashEnumeratorItemAndKey(&e, (void**)&value, (void**)&key)) {
713 WMReleasePropList(key);
714 WMReleasePropList(value);
716 if (plist->retainCount < 1) {
717 WMFreeHashTable(plist->d.dict);
718 wfree(plist);
720 break;
721 default:
722 wwarning(_("Used proplist functions on non-WMPropLists objects"));
723 wassertr(False);
728 Bool
729 WMPropListIsString(WMPropList *plist)
731 return (plist->type == WPLString);
735 Bool
736 WMPropListIsData(WMPropList *plist)
738 return (plist->type == WPLData);
742 Bool
743 WMPropListIsArray(WMPropList *plist)
745 return (plist->type == WPLArray);
749 Bool
750 WMPropListIsDictionary(WMPropList *plist)
752 return (plist->type == WPLDictionary);
756 Bool
757 WMPropListIsSimple(WMPropList *plist)
759 return (plist->type==WPLString || plist->type==WPLData);
763 Bool
764 WMPropListIsCompound(WMPropList *plist)
766 return (plist->type==WPLArray || plist->type==WPLDictionary);
770 Bool
771 WMIsPropListEqualToPropList(WMPropList *plist, WMPropList *other)
773 WMPropList *key1, *item1, *item2;
774 WMHashEnumerator enumerator;
775 int n, i;
777 if (plist->type != other->type)
778 return False;
780 switch(plist->type) {
781 case WPLString:
782 return (strCmp(plist->d.string, other->d.string) == 0);
783 case WPLData:
784 return WMIsDataEqualToData(plist->d.data, other->d.data);
785 case WPLArray:
786 n = WMGetArrayItemCount(plist->d.array);
787 if (n != WMGetArrayItemCount(other->d.array))
788 return False;
789 for (i=0; i<n; i++) {
790 item1 = WMGetFromArray(plist->d.array, i);
791 item2 = WMGetFromArray(other->d.array, i);
792 if (!WMIsPropListEqualToPropList(item1, item2))
793 return False;
795 return True;
796 case WPLDictionary:
797 if (WMCountHashTable(plist->d.dict) != WMCountHashTable(other->d.dict))
798 return False;
799 enumerator = WMEnumerateHashTable(plist->d.dict);
800 while (WMNextHashEnumeratorItemAndKey(&enumerator, (void**)&item1,
801 (void**)&key1)) {
802 item2 = WMHashGet(other->d.dict, key1);
803 if (!item2 || !item1 || !WMIsPropListEqualToPropList(item1, item2))
804 return False;
806 return True;
807 default:
808 wwarning(_("Used proplist functions on non-WMPropLists objects"));
809 wassertrv(False, False);
812 return False;
817 WMGetPropListNumberOfElements(WMPropList *plist)
819 switch(plist->type) {
820 case WPLString:
821 case WPLData:
822 return 0; /* should this be 1 instead? */
823 case WPLArray:
824 return WMGetArrayItemCount(plist->d.array);
825 case WPLDictionary:
826 return (int)WMCountHashTable(plist->d.dict);
827 default:
828 wwarning(_("Used proplist functions on non-WMPropLists objects"));
829 wassertrv(False, 0);
834 char*
835 WMGetPropListString(WMPropList *plist)
837 wassertrv(plist->type==WPLString, NULL);
839 return plist->d.string;
843 WMData*
844 WMGetPropListData(WMPropList *plist)
846 wassertrv(plist->type==WPLData, NULL);
848 return plist->d.data;
852 const unsigned char*
853 WMGetPropListDataBytes(WMPropList *plist)
855 wassertrv(plist->type==WPLData, NULL);
857 return WMDataBytes(plist->d.data);
862 WMGetPropListDataLength(WMPropList *plist)
864 wassertrv(plist->type==WPLData, 0);
866 return WMGetDataLength(plist->d.data);
870 WMPropList*
871 WMGetPropListArrayElement(WMPropList *plist, int index)
873 wassertrv(plist->type==WPLArray, NULL);
875 return WMGetFromArray(plist->d.array, index);
879 WMPropList*
880 WMGetPropListDictionaryEntry(WMPropList *plist, WMPropList *key)
882 wassertrv(plist->type==WPLDictionary, NULL);
884 return WMHashGet(plist->d.dict, key);
888 WMPropList*
889 WMGetPropListAllDictionaryKeys(WMPropList *plist)
891 WMPropList *array, *key;
892 WMHashEnumerator enumerator;
894 wassertrv(plist->type==WPLDictionary, NULL);
896 array = (WMPropList*)wmalloc(sizeof(W_PropList));
897 array->type = WPLArray;
898 array->d.array = WMCreateArray(WMCountHashTable(plist->d.dict));
899 array->retainCount = 1;
901 enumerator = WMEnumerateHashTable(plist->d.dict);
902 while ((key = WMNextHashEnumeratorKey(&enumerator))) {
903 WMAddToArray(array->d.array, WMRetainPropList(key));
906 return array;
910 char*
911 WMGetPropListDescription(WMPropList *plist, Bool indented)
913 return (indented ? indentedDescription(plist, 0) : description(plist));
918 /* TODO: review this function's code */
920 Bool
921 WMSavePropListToFile(WMPropList *plist, char *path, Bool atomically)
923 char *thePath=NULL;
924 char *description;
925 FILE *theFile;
927 if (atomically) {
928 #ifdef HAVE_MKSTEMP
929 int fd, mask;
930 #endif
932 /* Use the path name of the destination file as a prefix for the
933 * mkstemp() call so that we can be sure that both files are on
934 * the same filesystem and the subsequent rename() will work. */
935 thePath = wstrconcat(path, ".XXXXXX");
937 #ifdef HAVE_MKSTEMP
938 if ((fd = mkstemp(thePath)) < 0) {
939 wsyserror(_("mkstemp (%s) failed"), thePath);
940 goto failure;
942 mask = umask(0);
943 umask(mask);
944 fchmod(fd, 0644 & ~mask);
945 if ((theFile = fdopen(fd, "w")) == NULL) {
946 close(fd);
948 #else
949 if (mktemp(thePath) == NULL) {
950 wsyserror(_("mktemp (%s) failed"), thePath);
951 goto failure;
953 theFile = fopen(thePath, "wb");
954 #endif
955 } else {
956 thePath = wstrdup(path);
957 theFile = fopen(thePath, "wb");
960 if (theFile == NULL) {
961 wsyserror(_("open (%s) failed"), thePath);
962 goto failure;
965 description = indentedDescription(plist, 0);
967 if (fprintf(theFile, "%s\n", description) != strlen(description)+1) {
968 wsyserror(_("writing to file: %s failed"), thePath);
969 wfree(description);
970 goto failure;
973 wfree(description);
975 if (fclose(theFile) != 0) {
976 wsyserror(_("fclose (%s) failed"), thePath);
977 goto failure;
980 /* If we used a temporary file, we still need to rename() it be the
981 * real file. Also, we need to try to retain the file attributes of
982 * the original file we are overwriting (if we are) */
983 if (atomically) {
984 if (rename(thePath, path) != 0) {
985 wsyserror(_("rename ('%s' to '%s') failed"), thePath, path);
986 goto failure;
990 wfree(thePath);
991 return True;
993 failure:
994 if (atomically) {
995 unlink(thePath);
996 wfree(thePath);
999 return False;
1003 WMPropList*
1004 WMShallowCopyPropList(WMPropList *plist)
1006 WMPropList *ret, *key, *item;
1007 WMHashEnumerator e;
1008 int i;
1010 switch(plist->type) {
1011 case WPLString:
1012 case WPLData:
1013 return WMDeepCopyPropList(plist);
1014 case WPLArray:
1015 ret = (WMPropList*)wmalloc(sizeof(W_PropList));
1016 ret->type = WPLArray;
1017 ret->d.array = WMCreateArrayWithArray(plist->d.array);
1018 ret->retainCount = 1;
1020 for(i=0; i<WMGetArrayItemCount(ret->d.array); i++)
1021 WMRetainPropList(WMGetFromArray(ret->d.array, i));
1023 return ret;
1024 case WPLDictionary:
1025 ret = WMCreatePropListDictionaryFromEntries(NULL, NULL);
1026 e = WMEnumerateHashTable(plist->d.dict);
1027 while (WMNextHashEnumeratorItemAndKey(&e, (void**)&item, (void**)&key)) {
1028 WMInsertPropListDictionaryEntry(ret, key, item);
1030 return ret;
1031 default:
1032 wwarning(_("Used proplist functions on non-WMPropLists objects"));
1033 wassertrv(False, NULL);
1038 WMPropList*
1039 WMDeepCopyPropList(WMPropList *plist)
1041 WMPropList *ret, *key, *item;
1042 WMHashEnumerator e;
1043 WMData *data;
1044 int i;
1046 switch(plist->type) {
1047 case WPLString:
1048 return WMCreatePropListString(plist->d.string);
1049 case WPLData:
1050 data = WMCreateDataWithData(plist->d.data);
1051 ret = WMCreatePropListDataWithData(data);
1052 WMReleaseData(data);
1053 return ret;
1054 case WPLArray:
1055 ret = WMCreatePropListArrayFromElements(NULL);
1056 for(i=0; i<WMGetArrayItemCount(plist->d.array); i++) {
1057 item = WMDeepCopyPropList(WMGetFromArray(plist->d.array, i));
1058 WMAddToArray(ret->d.array, item);
1060 return ret;
1061 case WPLDictionary:
1062 ret = WMCreatePropListDictionaryFromEntries(NULL, NULL);
1063 e = WMEnumerateHashTable(plist->d.dict);
1064 /* While we copy an existing dictionary there is no way that we can
1065 * have duplicate keys, so we don't need to first remove a key/value
1066 * pair before inserting the new key/value.
1068 while (WMNextHashEnumeratorItemAndKey(&e, (void**)&item, (void**)&key)) {
1069 WMHashInsert(ret->d.dict, WMDeepCopyPropList(key),
1070 WMDeepCopyPropList(item));
1072 return ret;
1073 default:
1074 wwarning(_("Used proplist functions on non-WMPropLists objects"));
1075 wassertrv(False, NULL);