more updates to the proplist code
[wmaker-crm.git] / WINGs / proplist.c
blobc65e6c356c59f723d7a1648b496b1a51c464cb3c
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;
41 static unsigned hashPropList(WMPropList *plist);
45 typedef unsigned (*hashFunc)(const void*);
46 typedef Bool (*isEqualFunc)(const void*, const void*);
47 typedef void* (*retainFunc)(const void*);
48 typedef void (*releaseFunc)(const void*);
50 static const WMHashTableCallbacks WMPropListHashCallbacks = {
51 (hashFunc)hashPropList,
52 (isEqualFunc)WMPLIsEqualToPL,
53 (retainFunc)NULL,
54 (releaseFunc)NULL
59 static Bool caseSensitive = True;
63 #define MaxHashLength 64
65 static unsigned
66 hashPropList(WMPropList *plist)
68 unsigned ret = 0;
69 unsigned ctr = 0;
70 const char *key;
71 int i, len;
73 switch (plist->type) {
74 case WPLString:
75 key = plist->d.string;
76 len = WMIN(strlen(key), MaxHashLength);
77 for (i=0; i<len; i++) {
78 ret ^= tolower(key[i]) << ctr;
79 ctr = (ctr + 1) % sizeof (char *);
81 /*while (*key) {
82 ret ^= tolower(*key++) << ctr;
83 ctr = (ctr + 1) % sizeof (char *);
84 }*/
85 break;
87 case WPLData:
88 key = WMDataBytes(plist->d.data);
89 len = WMIN(WMGetDataLength(plist->d.data), MaxHashLength);
90 for (i=0; i<len; i++) {
91 ret ^= key[i] << ctr;
92 ctr = (ctr + 1) % sizeof (char *);
94 break;
96 default:
97 wwarning(_("Only string or data is supported for a proplist dictionary key"));
98 wassertrv(False, 0);
99 break;
102 return ret;
105 static WMPropList*
106 retainPropListByCount(WMPropList *plist, int count)
108 WMPropList *key, *value;
109 WMHashEnumerator e;
110 int i;
112 plist->retainCount += count;
114 switch(plist->type) {
115 case WPLString:
116 case WPLData:
117 break;
118 case WPLArray:
119 for (i=0; i<WMGetArrayItemCount(plist->d.array); i++) {
120 retainPropListByCount(WMGetFromArray(plist->d.array, i), count);
122 break;
123 case WPLDictionary:
124 e = WMEnumerateHashTable(plist->d.dict);
125 while (WMNextHashEnumeratorItemAndKey(&e, (void**)&value, (void**)&key)) {
126 retainPropListByCount(key, count);
127 retainPropListByCount(value, count);
129 break;
130 default:
131 wwarning(_("Used proplist functions on non-WMPropLists objects"));
132 wassertrv(False, NULL);
133 break;
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);
185 break;
190 #define num2char(num) ((num) < 0xa ? ((num)+'0') : ((num)+0x57))
192 static char*
193 dataDescription(WMPropList *plist)
195 const unsigned char *data;
196 char *retVal;
197 int i, j, length;
199 data = WMDataBytes(plist->d.data);
200 length = WMGetDataLength(plist->d.data);
202 retVal = (char*)wmalloc(2*length+length/4+3);
204 retVal[0] = '<';
205 for (i=0, j=1; i<length; i++) {
206 retVal[j++] = num2char((data[i]>>4) & 0x0f);
207 retVal[j++] = num2char(data[i] & 0x0f);
208 if ((i & 0x03)==3 && i!=length-1) {
209 /* if we've just finished a 32-bit int, add a space */
210 retVal[j++] = ' ';
213 retVal[j++] = '>';
214 retVal[j] = '\0';
216 return retVal;
220 static char*
221 stringDescription(WMPropList *plist)
223 const char *str;
224 char *retVal, *sPtr, *dPtr;
225 int len, quote;
226 unsigned char ch;
228 str = plist->d.string;
230 if (strlen(str) == 0) {
231 return wstrdup("\"\"");
234 /* FIXME: make this work with unichars. */
236 #define inrange(ch, min, max) ((ch)>=(min) && (ch)<=(max))
237 #define noquote(ch) (inrange(ch, 'a', 'z') || inrange(ch, 'A', 'Z') || inrange(ch, '0', '9') || ((ch)=='_') || ((ch)=='.') || ((ch)=='$'))
238 #define charesc(ch) (inrange(ch, 0x07, 0x0c) || ((ch)=='"') || ((ch)=='\\'))
239 #define numesc(ch) (((ch)<=0x06) || inrange(ch, 0x0d, 0x1f) || ((ch)>0x7e))
241 quote = 0;
242 sPtr = (char*) str;
243 len = 0;
244 while ((ch = *sPtr)) {
245 if (!noquote(ch)) {
246 quote = 1;
247 if (charesc(ch))
248 len++;
249 else if (numesc(ch))
250 len += 3;
252 sPtr++;
253 len++;
256 if (quote)
257 len += 2;
259 retVal = (char*)wmalloc(len+1);
261 sPtr = (char*) str;
262 dPtr = retVal;
264 if (quote)
265 *dPtr++ = '"';
267 while ((ch = *sPtr)) {
268 if (charesc(ch)) {
269 *(dPtr++) = '\\';
270 switch (ch) {
271 case '\a': *dPtr = 'a'; break;
272 case '\b': *dPtr = 'b'; break;
273 case '\t': *dPtr = 't'; break;
274 case '\n': *dPtr = 'n'; break;
275 case '\v': *dPtr = 'v'; break;
276 case '\f': *dPtr = 'f'; break;
277 default: *dPtr = ch; /* " or \ */
279 } else if (numesc(ch)) {
280 *(dPtr++) = '\\';
281 *(dPtr++) = '0' + ((ch>>6)&07);
282 *(dPtr++) = '0' + ((ch>>3)&07);
283 *dPtr = '0' + (ch&07);
284 } else {
285 *dPtr = ch;
287 sPtr++;
288 dPtr++;
291 if (quote)
292 *dPtr++ = '"';
294 *dPtr = '\0';
296 return retVal;
300 static char*
301 description(WMPropList *plist)
303 WMPropList *key, *val;
304 char *retstr = NULL;
305 char *str, *tmp, *skey, *sval;
306 WMHashEnumerator e;
307 int i;
309 switch (plist->type) {
310 case WPLString:
311 retstr = stringDescription(plist);
312 break;
313 case WPLData:
314 retstr = dataDescription(plist);
315 break;
316 case WPLArray:
317 retstr = wstrdup("(");
318 for (i=0; i<WMGetArrayItemCount(plist->d.array); i++) {
319 str = description(WMGetFromArray(plist->d.array, i));
320 if (i==0) {
321 retstr = wstrappend(retstr, str);
322 } else {
323 tmp = (char *)wmalloc(strlen(retstr)+strlen(str)+3);
324 sprintf(tmp, "%s, %s", retstr, str);
325 wfree(retstr);
326 retstr = tmp;
328 wfree(str);
330 retstr = wstrappend(retstr, ")");
331 break;
332 case WPLDictionary:
333 retstr = wstrdup("{");
334 e = WMEnumerateHashTable(plist->d.dict);
335 while (WMNextHashEnumeratorItemAndKey(&e, (void**)&val, (void**)&key)) {
336 skey = description(key);
337 sval = description(val);
338 tmp = (char*)wmalloc(strlen(retstr)+strlen(skey)+strlen(sval)+5);
339 sprintf(tmp, "%s%s = %s;", retstr, skey, sval);
340 wfree(skey);
341 wfree(sval);
342 wfree(retstr);
343 retstr = tmp;
345 retstr = wstrappend(retstr, "}");
346 break;
347 default:
348 wwarning(_("Used proplist functions on non-WMPropLists objects"));
349 wassertrv(False, NULL);
350 break;
353 return retstr;
357 static char*
358 indentedDescription(WMPropList *plist, int level)
360 WMPropList *key, *val;
361 char *retstr = NULL;
362 char *str, *tmp, *skey, *sval;
363 WMHashEnumerator e;
364 int i;
366 switch (plist->type) {
367 case WPLString:
368 retstr = stringDescription(plist);
369 break;
370 case WPLData:
371 retstr = dataDescription(plist);
372 break;
373 case WPLArray:
374 retstr = wstrdup("(\n");
375 for (i=0; i<WMGetArrayItemCount(plist->d.array); i++) {
376 str = indentedDescription(WMGetFromArray(plist->d.array, i),
377 level+1);
378 if (i==0) {
379 tmp = (char*)wmalloc(2*(level+1)+strlen(retstr)+strlen(str)+1);
380 sprintf(tmp, "%s%*s%s", retstr, 2*(level+1), "", str);
381 wfree(retstr);
382 retstr = tmp;
383 } else {
384 tmp = (char*)wmalloc(2*(level+1)+strlen(retstr)+strlen(str)+3);
385 sprintf(tmp, "%s,\n%*s%s", retstr, 2*(level+1), "", str);
386 wfree(retstr);
387 retstr = tmp;
389 wfree(str);
391 tmp = (char*)wmalloc(strlen(retstr) + 2*level + 3);
392 sprintf(tmp, "%s\n%*s)", retstr, 2*level, "");
393 wfree(retstr);
394 retstr = tmp;
395 break;
396 case WPLDictionary:
397 retstr = wstrdup("{\n");
398 e = WMEnumerateHashTable(plist->d.dict);
399 while (WMNextHashEnumeratorItemAndKey(&e, (void**)&val, (void**)&key)) {
400 skey = indentedDescription(key, level+1);
401 sval = indentedDescription(val, level+1);
402 tmp = (char*)wmalloc(2*(level+1) + strlen(retstr) + strlen(skey)
403 + strlen(sval) + 6);
404 sprintf(tmp, "%s%*s%s = %s;\n", retstr, 2*(level+1), "",
405 skey, sval);
406 wfree(skey);
407 wfree(sval);
408 wfree(retstr);
409 retstr = tmp;
411 tmp = (char*)wmalloc(strlen(retstr) + 2*level + 2);
412 sprintf(tmp, "%s%*s}", retstr, 2*level, "");
413 wfree(retstr);
414 retstr = tmp;
415 break;
416 default:
417 wwarning(_("Used proplist functions on non-WMPropLists objects"));
418 wassertrv(False, NULL);
419 break;
422 return retstr;
426 void
427 WMPLSetCaseSensitive(Bool useCase)
429 caseSensitive = useCase;
433 WMPropList*
434 WMPLCreateString(char *str)
436 WMPropList *plist;
438 wassertrv(str!=NULL, NULL);
440 plist = (WMPropList*)wmalloc(sizeof(W_PropList));
442 plist->type = WPLString;
443 plist->d.string = wstrdup(str);
444 plist->retainCount = 1;
446 return plist;
450 WMPropList*
451 WMPLCreateData(WMData *data)
453 WMPropList *plist;
455 wassertrv(data!=NULL, NULL);
457 plist = (WMPropList*)wmalloc(sizeof(W_PropList));
459 plist->type = WPLData;
460 plist->d.data = WMRetainData(data);
461 plist->retainCount = 1;
463 return plist;
467 WMPropList*
468 WMPLCreateDataWithBytes(unsigned char *bytes, unsigned int length)
470 WMPropList *plist;
472 wassertrv(bytes!=NULL, NULL);
474 plist = (WMPropList*)wmalloc(sizeof(W_PropList));
476 plist->type = WPLData;
477 plist->d.data = WMCreateDataWithBytes(bytes, length);
478 plist->retainCount = 1;
480 return plist;
484 WMPropList*
485 WMPLCreateDataWithBytesNoCopy(unsigned char *bytes, unsigned int length,
486 WMFreeDataProc *destructor)
488 WMPropList *plist;
490 wassertrv(bytes!=NULL, NULL);
492 plist = (WMPropList*)wmalloc(sizeof(W_PropList));
494 plist->type = WPLData;
495 plist->d.data = WMCreateDataWithBytesNoCopy(bytes, length, destructor);
496 plist->retainCount = 1;
498 return plist;
502 WMPropList*
503 WMPLCreateArray(WMPropList *elem, ...)
505 WMPropList *plist, *nelem;
506 va_list ap;
508 plist = (WMPropList*)wmalloc(sizeof(W_PropList));
509 plist->type = WPLArray;
510 plist->d.array = WMCreateArray(4);
511 plist->retainCount = 1;
513 if (!elem)
514 return plist;
516 WMAddToArray(plist->d.array, WMPLRetain(elem));
518 va_start(ap, elem);
520 while (1) {
521 nelem = va_arg(ap, WMPropList*);
522 if(!nelem) {
523 va_end(ap);
524 return plist;
526 WMAddToArray(plist->d.array, WMPLRetain(nelem));
531 WMPropList*
532 WMPLCreateDictionary(WMPropList *key, WMPropList *value, ...)
534 WMPropList *plist, *nkey, *nvalue, *k, *v;
535 va_list ap;
537 plist = (WMPropList*)wmalloc(sizeof(W_PropList));
538 plist->type = WPLDictionary;
539 plist->d.dict = WMCreateHashTable(WMPropListHashCallbacks);
540 plist->retainCount = 1;
542 if (!key || !value)
543 return plist;
545 WMHashInsert(plist->d.dict, WMPLRetain(key), WMPLRetain(value));
547 va_start(ap, value);
549 while (1) {
550 nkey = va_arg(ap, WMPropList*);
551 if (!nkey) {
552 va_end(ap);
553 return plist;
555 nvalue = va_arg(ap, WMPropList*);
556 if (!nvalue) {
557 va_end(ap);
558 return plist;
560 if (WMHashGetItemAndKey(plist->d.dict, nkey, (void**)&v, (void**)&k)) {
561 WMHashRemove(plist->d.dict, k);
562 WMPLRelease(k);
563 WMPLRelease(v);
565 WMHashInsert(plist->d.dict, WMPLRetain(nkey), WMPLRetain(nvalue));
570 void
571 WMPLInsertInArray(WMPropList *plist, int index, WMPropList *item)
573 wassertr(plist->type==WPLArray);
575 retainPropListByCount(item, plist->retainCount);
576 WMInsertInArray(plist->d.array, index, item);
580 void
581 WMPLAddToArray(WMPropList *plist, WMPropList *item)
583 wassertr(plist->type==WPLArray);
585 retainPropListByCount(item, plist->retainCount);
586 WMAddToArray(plist->d.array, item);
590 void
591 WMPLDeleteFromArray(WMPropList *plist, int index)
593 WMPropList *item;
595 wassertr(plist->type==WPLArray);
597 item = WMGetFromArray(plist->d.array, index);
598 if (item != NULL) {
599 WMDeleteFromArray(plist->d.array, index);
600 releasePropListByCount(item, plist->retainCount);
605 void
606 WMPLRemoveFromArray(WMPropList *plist, WMPropList *item)
608 WMPropList *iPtr;
609 int i;
611 wassertr(plist->type==WPLArray);
613 for (i=0; i<WMGetArrayItemCount(plist->d.array); i++) {
614 iPtr = WMGetFromArray(plist->d.array, i);
615 if (WMPLIsEqualToPL(item, iPtr)) {
616 WMDeleteFromArray(plist->d.array, i);
617 releasePropListByCount(iPtr, plist->retainCount);
618 break;
624 void
625 WMPLPutInDictionary(WMPropList *plist, WMPropList *key, WMPropList *value)
627 wassertr(plist->type==WPLDictionary);
629 WMPLRemoveFromDictionary(plist, key);
630 retainPropListByCount(key, plist->retainCount);
631 retainPropListByCount(value, plist->retainCount);
632 WMHashInsert(plist->d.dict, key, value);
636 void
637 WMPLRemoveFromDictionary(WMPropList *plist, WMPropList *key)
639 WMPropList *k, *v;
641 wassertr(plist->type==WPLDictionary);
643 if (WMHashGetItemAndKey(plist->d.dict, key, (void**)&v, (void**)&k)) {
644 WMHashRemove(plist->d.dict, k);
645 releasePropListByCount(k, plist->retainCount);
646 releasePropListByCount(v, plist->retainCount);
651 WMPropList*
652 WMPLMergeDictionaries(WMPropList *dest, WMPropList *source)
654 WMPropList *key, *value;
655 WMHashEnumerator e;
657 wassertr(source->type==WPLDictionary && dest->type==WPLDictionary);
659 e = WMEnumerateHashTable(source->d.dict);
660 while (WMNextHashEnumeratorItemAndKey(&e, (void**)&value, (void**)&key)) {
661 WMPLPutInDictionary(dest, key, value);
664 return dest;
668 WMPropList*
669 WMPLRetain(WMPropList *plist)
671 WMPropList *key, *value;
672 WMHashEnumerator e;
673 int i;
675 plist->retainCount++;
677 switch(plist->type) {
678 case WPLString:
679 case WPLData:
680 break;
681 case WPLArray:
682 for (i=0; i<WMGetArrayItemCount(plist->d.array); i++) {
683 WMPLRetain(WMGetFromArray(plist->d.array, i));
685 break;
686 case WPLDictionary:
687 e = WMEnumerateHashTable(plist->d.dict);
688 while (WMNextHashEnumeratorItemAndKey(&e, (void**)&value, (void**)&key)) {
689 WMPLRetain(key);
690 WMPLRetain(value);
692 break;
693 default:
694 wwarning(_("Used proplist functions on non-WMPropLists objects"));
695 wassertrv(False, NULL);
696 break;
699 return plist;
703 void
704 WMPLRelease(WMPropList *plist)
706 WMPropList *key, *value;
707 WMHashEnumerator e;
708 int i;
710 plist->retainCount--;
712 switch(plist->type) {
713 case WPLString:
714 if (plist->retainCount < 1) {
715 wfree(plist->d.string);
716 wfree(plist);
718 break;
719 case WPLData:
720 if (plist->retainCount < 1) {
721 WMReleaseData(plist->d.data);
722 wfree(plist);
724 break;
725 case WPLArray:
726 for (i=0; i<WMGetArrayItemCount(plist->d.array); i++) {
727 WMPLRelease(WMGetFromArray(plist->d.array, i));
729 if (plist->retainCount < 1) {
730 WMFreeArray(plist->d.array);
731 wfree(plist);
733 break;
734 case WPLDictionary:
735 e = WMEnumerateHashTable(plist->d.dict);
736 while (WMNextHashEnumeratorItemAndKey(&e, (void**)&value, (void**)&key)) {
737 WMPLRelease(key);
738 WMPLRelease(value);
740 if (plist->retainCount < 1) {
741 WMFreeHashTable(plist->d.dict);
742 wfree(plist);
744 break;
745 default:
746 wwarning(_("Used proplist functions on non-WMPropLists objects"));
747 wassertr(False);
748 break;
753 Bool
754 WMPLIsString(WMPropList *plist)
756 return (plist->type == WPLString);
760 Bool
761 WMPLIsData(WMPropList *plist)
763 return (plist->type == WPLData);
767 Bool
768 WMPLIsArray(WMPropList *plist)
770 return (plist->type == WPLArray);
774 Bool
775 WMPLIsDictionary(WMPropList *plist)
777 return (plist->type == WPLDictionary);
781 Bool
782 WMPLIsEqualToPL(WMPropList *plist, WMPropList *other)
784 WMPropList *key1, *item1, *item2;
785 WMHashEnumerator enumerator;
786 int n, i;
788 if (plist->type != other->type)
789 return False;
791 switch(plist->type) {
792 case WPLString:
793 if (caseSensitive) {
794 return (strcmp(plist->d.string, other->d.string) == 0);
795 } else {
796 return (strcasecmp(plist->d.string, other->d.string) == 0);
798 case WPLData:
799 return WMIsDataEqualToData(plist->d.data, other->d.data);
800 case WPLArray:
801 n = WMGetArrayItemCount(plist->d.array);
802 if (n != WMGetArrayItemCount(other->d.array))
803 return False;
804 for (i=0; i<n; i++) {
805 item1 = WMGetFromArray(plist->d.array, i);
806 item2 = WMGetFromArray(other->d.array, i);
807 if (!WMPLIsEqualToPL(item1, item2))
808 return False;
810 return True;
811 case WPLDictionary:
812 if (WMCountHashTable(plist->d.dict) != WMCountHashTable(other->d.dict))
813 return False;
814 enumerator = WMEnumerateHashTable(plist->d.dict);
815 while (WMNextHashEnumeratorItemAndKey(&enumerator, (void**)&item1,
816 (void**)&key1)) {
817 item2 = WMHashGet(other->d.dict, key1);
818 if (!item2 || !item1 || !WMPLIsEqualToPL(item1, item2))
819 return False;
821 return True;
822 default:
823 wwarning(_("Used proplist functions on non-WMPropLists objects"));
824 wassertrv(False, False);
825 break;
828 return False;
833 WMPLGetItemCount(WMPropList *plist)
835 switch(plist->type) {
836 case WPLString:
837 case WPLData:
838 return 0; /* should this be 1 instead? */
839 case WPLArray:
840 return WMGetArrayItemCount(plist->d.array);
841 case WPLDictionary:
842 return (int)WMCountHashTable(plist->d.dict);
843 default:
844 wwarning(_("Used proplist functions on non-WMPropLists objects"));
845 wassertrv(False, 0);
846 break;
849 return 0;
853 char*
854 WMPLGetString(WMPropList *plist)
856 wassertrv(plist->type==WPLString, NULL);
858 return plist->d.string;
862 WMData*
863 WMPLGetData(WMPropList *plist)
865 wassertrv(plist->type==WPLData, NULL);
867 return plist->d.data;
871 const unsigned char*
872 WMPLGetDataBytes(WMPropList *plist)
874 wassertrv(plist->type==WPLData, NULL);
876 return WMDataBytes(plist->d.data);
881 WMPLGetDataLength(WMPropList *plist)
883 wassertrv(plist->type==WPLData, 0);
885 return WMGetDataLength(plist->d.data);
889 WMPropList*
890 WMPLGetFromArray(WMPropList *plist, int index)
892 wassertrv(plist->type==WPLArray, NULL);
894 return WMGetFromArray(plist->d.array, index);
898 WMPropList*
899 WMPLGetFromDictionary(WMPropList *plist, WMPropList *key)
901 wassertrv(plist->type==WPLDictionary, NULL);
903 return WMHashGet(plist->d.dict, key);
907 WMPropList*
908 WMPLGetDictionaryKeys(WMPropList *plist)
910 WMPropList *array, *key;
911 WMHashEnumerator enumerator;
913 wassertrv(plist->type==WPLDictionary, NULL);
915 array = (WMPropList*)wmalloc(sizeof(W_PropList));
916 array->type = WPLArray;
917 array->d.array = WMCreateArray(WMCountHashTable(plist->d.dict));
918 array->retainCount = 1;
920 enumerator = WMEnumerateHashTable(plist->d.dict);
921 while ((key = WMNextHashEnumeratorKey(&enumerator))) {
922 WMAddToArray(array->d.array, WMPLRetain(key));
925 return array;
929 char*
930 WMPLGetDescription(WMPropList *plist, Bool indented)
932 return (indented ? indentedDescription(plist, 0) : description(plist));
937 /* TODO: review this function's code */
939 Bool
940 WMPLWriteToFile(WMPropList *plist, char *path, Bool atomically)
942 char *thePath=NULL;
943 char *description;
944 FILE *theFile;
946 if (atomically) {
947 #ifdef HAVE_MKSTEMP
948 int fd, mask;
949 #endif
951 /* Use the path name of the destination file as a prefix for the
952 * mkstemp() call so that we can be sure that both files are on
953 * the same filesystem and the subsequent rename() will work. */
954 thePath = wstrconcat(path, ".XXXXXX");
956 #ifdef HAVE_MKSTEMP
957 if ((fd = mkstemp(thePath)) < 0) {
958 wsyserror(_("mkstemp (%s) failed"), thePath);
959 goto failure;
961 mask = umask(0);
962 umask(mask);
963 fchmod(fd, 0644 & ~mask);
964 if ((theFile = fdopen(fd, "w")) == NULL) {
965 close(fd);
967 #else
968 if (mktemp(thePath) == NULL) {
969 wsyserror(_("mktemp (%s) failed"), thePath);
970 goto failure;
972 theFile = fopen(thePath, "wb");
973 #endif
974 } else {
975 thePath = wstrdup(path);
976 theFile = fopen(thePath, "wb");
979 if (theFile == NULL) {
980 wsyserror(_("open (%s) failed"), thePath);
981 goto failure;
984 description = indentedDescription(plist, 0);
986 if (fprintf(theFile, "%s\n", description) != strlen(description)+1) {
987 wsyserror(_("writing to file: %s failed"), thePath);
988 wfree(description);
989 goto failure;
992 wfree(description);
994 if (fclose(theFile) != 0) {
995 wsyserror(_("fclose (%s) failed"), thePath);
996 goto failure;
999 /* If we used a temporary file, we still need to rename() it be the
1000 * real file. Also, we need to try to retain the file attributes of
1001 * the original file we are overwriting (if we are) */
1002 if (atomically) {
1003 if (rename(thePath, path) != 0) {
1004 wsyserror(_("rename ('%s' to '%s') failed"), thePath, path);
1005 goto failure;
1009 wfree(thePath);
1010 return True;
1012 failure:
1013 if (atomically) {
1014 unlink(thePath);
1015 wfree(thePath);
1018 return False;
1022 WMPropList*
1023 WMPLShallowCopy(WMPropList *plist)
1025 WMPropList *ret = NULL;
1026 WMPropList *key, *item;
1027 WMHashEnumerator e;
1028 WMData *data;
1029 int i;
1031 switch(plist->type) {
1032 case WPLString:
1033 ret = WMPLCreateString(plist->d.string);
1034 break;
1035 case WPLData:
1036 data = WMCreateDataWithData(plist->d.data);
1037 ret = WMPLCreateData(data);
1038 WMReleaseData(data);
1039 break;
1040 case WPLArray:
1041 ret = (WMPropList*)wmalloc(sizeof(W_PropList));
1042 ret->type = WPLArray;
1043 ret->d.array = WMCreateArrayWithArray(plist->d.array);
1044 ret->retainCount = 1;
1046 for(i=0; i<WMGetArrayItemCount(ret->d.array); i++)
1047 WMPLRetain(WMGetFromArray(ret->d.array, i));
1049 break;
1050 case WPLDictionary:
1051 ret = WMPLCreateDictionary(NULL, NULL);
1052 e = WMEnumerateHashTable(plist->d.dict);
1053 while (WMNextHashEnumeratorItemAndKey(&e, (void**)&item, (void**)&key)) {
1054 WMPLPutInDictionary(ret, key, item);
1056 break;
1057 default:
1058 wwarning(_("Used proplist functions on non-WMPropLists objects"));
1059 wassertrv(False, NULL);
1060 break;
1063 return ret;
1067 WMPropList*
1068 WMPLDuplicate(WMPropList *plist)
1070 WMPropList *ret = NULL;
1071 WMPropList *key, *item;
1072 WMHashEnumerator e;
1073 WMData *data;
1074 int i;
1076 switch(plist->type) {
1077 case WPLString:
1078 ret = WMPLCreateString(plist->d.string);
1079 break;
1080 case WPLData:
1081 data = WMCreateDataWithData(plist->d.data);
1082 ret = WMPLCreateData(data);
1083 WMReleaseData(data);
1084 break;
1085 case WPLArray:
1086 ret = WMPLCreateArray(NULL);
1087 for(i=0; i<WMGetArrayItemCount(plist->d.array); i++) {
1088 item = WMPLDuplicate(WMGetFromArray(plist->d.array, i));
1089 WMAddToArray(ret->d.array, item);
1091 break;
1092 case WPLDictionary:
1093 ret = WMPLCreateDictionary(NULL, NULL);
1094 e = WMEnumerateHashTable(plist->d.dict);
1095 /* While we copy an existing dictionary there is no way that we can
1096 * have duplicate keys, so we don't need to first remove a key/value
1097 * pair before inserting the new key/value.
1099 while (WMNextHashEnumeratorItemAndKey(&e, (void**)&item, (void**)&key)) {
1100 WMHashInsert(ret->d.dict, WMPLDuplicate(key), WMPLDuplicate(item));
1102 break;
1103 default:
1104 wwarning(_("Used proplist functions on non-WMPropLists objects"));
1105 wassertrv(False, NULL);
1106 break;
1109 return ret;