15 WPLString
= 0x57504c01,
17 WPLArray
= 0x57504c03,
18 WPLDictionary
= 0x57504c04
21 typedef struct W_PropList
{
34 typedef struct PLData
{
41 typedef struct StringBuffer
{
46 static unsigned hashPropList(WMPropList
* plist
);
47 static WMPropList
*getPLString(PLData
* pldata
);
48 static WMPropList
*getPLQString(PLData
* pldata
);
49 static WMPropList
*getPLData(PLData
* pldata
);
50 static WMPropList
*getPLArray(PLData
* pldata
);
51 static WMPropList
*getPLDictionary(PLData
* pldata
);
52 static WMPropList
*getPropList(PLData
* pldata
);
54 typedef unsigned (*hashFunc
) (const void *);
55 typedef Bool(*isEqualFunc
) (const void *, const void *);
56 typedef void *(*retainFunc
) (const void *);
57 typedef void (*releaseFunc
) (const void *);
59 static const WMHashTableCallbacks WMPropListHashCallbacks
= {
60 (hashFunc
) hashPropList
,
61 (isEqualFunc
) WMIsPropListEqualTo
,
66 static Bool caseSensitive
= True
;
68 #define BUFFERSIZE 8192
69 #define BUFFERSIZE_INCREMENT 1024
72 # define DPUT(s) puts(s)
77 #define COMPLAIN(pld, msg) wwarning(_("syntax error in %s %s, line %i: %s"),\
78 (pld)->filename ? "file" : "PropList",\
79 (pld)->filename ? (pld)->filename : "description",\
80 (pld)->lineNumber, msg)
82 #define ISSTRINGABLE(c) (isalnum(c) || (c)=='.' || (c)=='_' || (c)=='/' \
85 #define CHECK_BUFFER_SIZE(buf, ptr) \
86 if ((ptr) >= (buf).size-1) {\
87 (buf).size += BUFFERSIZE_INCREMENT;\
88 (buf).str = wrealloc((buf).str, (buf).size);\
91 #define inrange(ch, min, max) ((ch)>=(min) && (ch)<=(max))
92 #define noquote(ch) (inrange(ch, 'a', 'z') || inrange(ch, 'A', 'Z') || inrange(ch, '0', '9') || ((ch)=='_') || ((ch)=='.') || ((ch)=='$'))
93 #define charesc(ch) (inrange(ch, 0x07, 0x0c) || ((ch)=='"') || ((ch)=='\\'))
94 #define numesc(ch) (((ch)<=0x06) || inrange(ch, 0x0d, 0x1f) || ((ch)>0x7e))
95 #define ishexdigit(ch) (inrange(ch, 'a', 'f') || inrange(ch, 'A', 'F') || inrange(ch, '0', '9'))
96 #define char2num(ch) (inrange(ch,'0','9') ? ((ch)-'0') : (inrange(ch,'a','f') ? ((ch)-0x57) : ((ch)-0x37)))
97 #define num2char(num) ((num) < 0xa ? ((num)+'0') : ((num)+0x57))
99 #define MaxHashLength 64
101 static unsigned hashPropList(WMPropList
* plist
)
108 switch (plist
->type
) {
110 key
= plist
->d
.string
;
111 len
= WMIN(strlen(key
), MaxHashLength
);
112 for (i
= 0; i
< len
; i
++) {
113 ret
^= tolower(key
[i
]) << ctr
;
114 ctr
= (ctr
+ 1) % sizeof(char *);
117 ret ^= tolower(*key++) << ctr;
118 ctr = (ctr + 1) % sizeof (char *);
123 key
= WMDataBytes(plist
->d
.data
);
124 len
= WMIN(WMGetDataLength(plist
->d
.data
), MaxHashLength
);
125 for (i
= 0; i
< len
; i
++) {
126 ret
^= key
[i
] << ctr
;
127 ctr
= (ctr
+ 1) % sizeof(char *);
132 wwarning(_("Only string or data is supported for a proplist dictionary key"));
140 static WMPropList
*retainPropListByCount(WMPropList
* plist
, int count
)
142 WMPropList
*key
, *value
;
146 plist
->retainCount
+= count
;
148 switch (plist
->type
) {
153 for (i
= 0; i
< WMGetArrayItemCount(plist
->d
.array
); i
++) {
154 retainPropListByCount(WMGetFromArray(plist
->d
.array
, i
), count
);
158 e
= WMEnumerateHashTable(plist
->d
.dict
);
159 while (WMNextHashEnumeratorItemAndKey(&e
, (void **)&value
, (void **)&key
)) {
160 retainPropListByCount(key
, count
);
161 retainPropListByCount(value
, count
);
165 wwarning(_("Used proplist functions on non-WMPropLists objects"));
166 wassertrv(False
, NULL
);
173 static void releasePropListByCount(WMPropList
* plist
, int count
)
175 WMPropList
*key
, *value
;
179 plist
->retainCount
-= count
;
181 switch (plist
->type
) {
183 if (plist
->retainCount
< 1) {
184 wfree(plist
->d
.string
);
189 if (plist
->retainCount
< 1) {
190 WMReleaseData(plist
->d
.data
);
195 for (i
= 0; i
< WMGetArrayItemCount(plist
->d
.array
); i
++) {
196 releasePropListByCount(WMGetFromArray(plist
->d
.array
, i
), count
);
198 if (plist
->retainCount
< 1) {
199 WMFreeArray(plist
->d
.array
);
204 e
= WMEnumerateHashTable(plist
->d
.dict
);
205 while (WMNextHashEnumeratorItemAndKey(&e
, (void **)&value
, (void **)&key
)) {
206 releasePropListByCount(key
, count
);
207 releasePropListByCount(value
, count
);
209 if (plist
->retainCount
< 1) {
210 WMFreeHashTable(plist
->d
.dict
);
215 wwarning(_("Used proplist functions on non-WMPropLists objects"));
221 static char *dataDescription(WMPropList
* plist
)
223 const unsigned char *data
;
227 data
= WMDataBytes(plist
->d
.data
);
228 length
= WMGetDataLength(plist
->d
.data
);
230 retVal
= (char *)wmalloc(2 * length
+ length
/ 4 + 3);
233 for (i
= 0, j
= 1; i
< length
; i
++) {
234 retVal
[j
++] = num2char((data
[i
] >> 4) & 0x0f);
235 retVal
[j
++] = num2char(data
[i
] & 0x0f);
236 if ((i
& 0x03) == 3 && i
!= length
- 1) {
237 /* if we've just finished a 32-bit int, add a space */
247 static char *stringDescription(WMPropList
* plist
)
250 char *retVal
, *sPtr
, *dPtr
;
254 str
= plist
->d
.string
;
256 if (strlen(str
) == 0) {
257 return wstrdup("\"\"");
260 /* FIXME: make this work with unichars. */
265 while ((ch
= *sPtr
)) {
280 retVal
= (char *)wmalloc(len
+ 1);
288 while ((ch
= *sPtr
)) {
311 *dPtr
= ch
; /* " or \ */
313 } else if (numesc(ch
)) {
315 *(dPtr
++) = '0' + ((ch
>> 6) & 07);
316 *(dPtr
++) = '0' + ((ch
>> 3) & 07);
317 *dPtr
= '0' + (ch
& 07);
333 static char *description(WMPropList
* plist
)
335 WMPropList
*key
, *val
;
337 char *str
, *tmp
, *skey
, *sval
;
341 switch (plist
->type
) {
343 retstr
= stringDescription(plist
);
346 retstr
= dataDescription(plist
);
349 retstr
= wstrdup("(");
350 for (i
= 0; i
< WMGetArrayItemCount(plist
->d
.array
); i
++) {
351 str
= description(WMGetFromArray(plist
->d
.array
, i
));
353 retstr
= wstrappend(retstr
, str
);
355 tmp
= (char *)wmalloc(strlen(retstr
) + strlen(str
) + 3);
356 sprintf(tmp
, "%s, %s", retstr
, str
);
362 retstr
= wstrappend(retstr
, ")");
365 retstr
= wstrdup("{");
366 e
= WMEnumerateHashTable(plist
->d
.dict
);
367 while (WMNextHashEnumeratorItemAndKey(&e
, (void **)&val
, (void **)&key
)) {
368 skey
= description(key
);
369 sval
= description(val
);
370 tmp
= (char *)wmalloc(strlen(retstr
) + strlen(skey
) + strlen(sval
) + 5);
371 sprintf(tmp
, "%s%s = %s;", retstr
, skey
, sval
);
377 retstr
= wstrappend(retstr
, "}");
380 wwarning(_("Used proplist functions on non-WMPropLists objects"));
381 wassertrv(False
, NULL
);
388 static char *indentedDescription(WMPropList
* plist
, int level
)
390 WMPropList
*key
, *val
;
392 char *str
, *tmp
, *skey
, *sval
;
396 if (plist
->type
== WPLArray
/* || plist->type==WPLDictionary */ ) {
397 retstr
= description(plist
);
399 if (retstr
&& ((2 * (level
+ 1) + strlen(retstr
)) <= 77)) {
407 switch (plist
->type
) {
409 retstr
= stringDescription(plist
);
412 retstr
= dataDescription(plist
);
415 retstr
= wstrdup("(\n");
416 for (i
= 0; i
< WMGetArrayItemCount(plist
->d
.array
); i
++) {
417 str
= indentedDescription(WMGetFromArray(plist
->d
.array
, i
), level
+ 1);
419 tmp
= (char *)wmalloc(2 * (level
+ 1) + strlen(retstr
) + strlen(str
) + 1);
420 sprintf(tmp
, "%s%*s%s", retstr
, 2 * (level
+ 1), "", str
);
424 tmp
= (char *)wmalloc(2 * (level
+ 1) + strlen(retstr
) + strlen(str
) + 3);
425 sprintf(tmp
, "%s,\n%*s%s", retstr
, 2 * (level
+ 1), "", str
);
431 tmp
= (char *)wmalloc(strlen(retstr
) + 2 * level
+ 3);
432 sprintf(tmp
, "%s\n%*s)", retstr
, 2 * level
, "");
437 retstr
= wstrdup("{\n");
438 e
= WMEnumerateHashTable(plist
->d
.dict
);
439 while (WMNextHashEnumeratorItemAndKey(&e
, (void **)&val
, (void **)&key
)) {
440 skey
= indentedDescription(key
, level
+ 1);
441 sval
= indentedDescription(val
, level
+ 1);
442 tmp
= (char *)wmalloc(2 * (level
+ 1) + strlen(retstr
) + strlen(skey
)
444 sprintf(tmp
, "%s%*s%s = %s;\n", retstr
, 2 * (level
+ 1), "", skey
, sval
);
450 tmp
= (char *)wmalloc(strlen(retstr
) + 2 * level
+ 2);
451 sprintf(tmp
, "%s%*s}", retstr
, 2 * level
, "");
456 wwarning(_("Used proplist functions on non-WMPropLists objects"));
457 wassertrv(False
, NULL
);
464 static INLINE
int getChar(PLData
* pldata
)
468 c
= pldata
->ptr
[pldata
->pos
];
476 pldata
->lineNumber
++;
481 static INLINE
int getNonSpaceChar(PLData
* pldata
)
486 c
= pldata
->ptr
[pldata
->pos
];
492 pldata
->lineNumber
++;
493 } else if (!isspace(c
)) {
501 static char *unescapestr(char *src
)
503 char *dest
= wmalloc(strlen(src
) + 1);
507 for (sPtr
= src
, dPtr
= dest
; *sPtr
; sPtr
++, dPtr
++) {
512 if ((ch
>= '0') && (ch
<= '3')) {
513 /* assume next 2 chars are octal too */
514 *dPtr
= ((ch
& 07) << 6);
515 *dPtr
|= ((*(++sPtr
) & 07) << 3);
516 *dPtr
|= *(++sPtr
) & 07;
552 static WMPropList
*getPLString(PLData
* pldata
)
559 sBuf
.str
= wmalloc(BUFFERSIZE
);
560 sBuf
.size
= BUFFERSIZE
;
564 if (ISSTRINGABLE(c
)) {
565 CHECK_BUFFER_SIZE(sBuf
, ptr
);
580 char *tmp
= unescapestr(sBuf
.str
);
581 plist
= WMCreatePLString(tmp
);
590 static WMPropList
*getPLQString(PLData
* pldata
)
593 int ptr
= 0, escaping
= 0, ok
= 1;
597 sBuf
.str
= wmalloc(BUFFERSIZE
);
598 sBuf
.size
= BUFFERSIZE
;
606 } else if (c
== '"') {
610 CHECK_BUFFER_SIZE(sBuf
, ptr
);
611 sBuf
.str
[ptr
++] = '\\';
616 COMPLAIN(pldata
, _("unterminated PropList string"));
620 CHECK_BUFFER_SIZE(sBuf
, ptr
);
630 char *tmp
= unescapestr(sBuf
.str
);
631 plist
= WMCreatePLString(tmp
);
640 static WMPropList
*getPLData(PLData
* pldata
)
645 unsigned char buf
[BUFFERSIZE
], byte
;
649 data
= WMCreateDataWithCapacity(0);
652 c1
= getNonSpaceChar(pldata
);
654 COMPLAIN(pldata
, _("unterminated PropList data"));
657 } else if (c1
== '>') {
659 } else if (ishexdigit(c1
)) {
660 c2
= getNonSpaceChar(pldata
);
661 if (c2
== 0 || c2
== '>') {
662 COMPLAIN(pldata
, _("unterminated PropList data (missing hexdigit)"));
665 } else if (ishexdigit(c2
)) {
666 byte
= char2num(c1
) << 4;
667 byte
|= char2num(c2
);
669 if (len
== sizeof(buf
)) {
670 WMAppendDataBytes(data
, buf
, len
);
674 COMPLAIN(pldata
, _("non hexdigit character in PropList data"));
679 COMPLAIN(pldata
, _("non hexdigit character in PropList data"));
691 WMAppendDataBytes(data
, buf
, len
);
693 plist
= WMCreatePLData(data
);
699 static WMPropList
*getPLArray(PLData
* pldata
)
704 WMPropList
*array
, *obj
;
706 array
= WMCreatePLArray(NULL
);
709 c
= getNonSpaceChar(pldata
);
711 COMPLAIN(pldata
, _("unterminated PropList array"));
714 } else if (c
== ')') {
716 } else if (c
== ',') {
717 /* continue normally */
719 COMPLAIN(pldata
, _("missing or unterminated PropList array"));
727 obj
= getPropList(pldata
);
729 COMPLAIN(pldata
, _("could not get PropList array element"));
733 WMAddToPLArray(array
, obj
);
734 WMReleasePropList(obj
);
738 WMReleasePropList(array
);
745 static WMPropList
*getPLDictionary(PLData
* pldata
)
749 WMPropList
*dict
, *key
, *value
;
751 dict
= WMCreatePLDictionary(NULL
, NULL
);
754 c
= getNonSpaceChar(pldata
);
756 COMPLAIN(pldata
, _("unterminated PropList dictionary"));
759 } else if (c
== '}') {
763 DPUT("getting PropList dictionary key");
765 key
= getPLData(pldata
);
766 } else if (c
== '"') {
767 key
= getPLQString(pldata
);
768 } else if (ISSTRINGABLE(c
)) {
770 key
= getPLString(pldata
);
773 COMPLAIN(pldata
, _("missing PropList dictionary key"));
775 COMPLAIN(pldata
, _("missing PropList dictionary entry key "
776 "or unterminated dictionary"));
783 COMPLAIN(pldata
, _("error parsing PropList dictionary key"));
788 c
= getNonSpaceChar(pldata
);
790 WMReleasePropList(key
);
791 COMPLAIN(pldata
, _("missing = in PropList dictionary entry"));
796 DPUT("getting PropList dictionary entry value for key");
797 value
= getPropList(pldata
);
799 COMPLAIN(pldata
, _("error parsing PropList dictionary entry value"));
800 WMReleasePropList(key
);
805 c
= getNonSpaceChar(pldata
);
807 COMPLAIN(pldata
, _("missing ; in PropList dictionary entry"));
808 WMReleasePropList(key
);
809 WMReleasePropList(value
);
814 WMPutInPLDictionary(dict
, key
, value
);
815 WMReleasePropList(key
);
816 WMReleasePropList(value
);
820 WMReleasePropList(dict
);
827 static WMPropList
*getPropList(PLData
* pldata
)
832 c
= getNonSpaceChar(pldata
);
836 DPUT("End of PropList");
841 DPUT("Getting PropList dictionary");
842 plist
= getPLDictionary(pldata
);
846 DPUT("Getting PropList array");
847 plist
= getPLArray(pldata
);
851 DPUT("Getting PropList data");
852 plist
= getPLData(pldata
);
856 DPUT("Getting PropList quoted string");
857 plist
= getPLQString(pldata
);
861 if (ISSTRINGABLE(c
)) {
862 DPUT("Getting PropList string");
864 plist
= getPLString(pldata
);
866 COMPLAIN(pldata
, _("was expecting a string, data, array or "
867 "dictionary. If it's a string, try enclosing " "it with \"."));
868 if (c
== '#' || c
== '/') {
869 wwarning(_("Comments are not allowed inside WindowMaker owned" " domain files."));
879 void WMPLSetCaseSensitive(Bool caseSensitiveness
)
881 caseSensitive
= caseSensitiveness
;
884 WMPropList
*WMCreatePLString(char *str
)
888 wassertrv(str
!= NULL
, NULL
);
890 plist
= (WMPropList
*) wmalloc(sizeof(W_PropList
));
892 plist
->type
= WPLString
;
893 plist
->d
.string
= wstrdup(str
);
894 plist
->retainCount
= 1;
899 WMPropList
*WMCreatePLData(WMData
* data
)
903 wassertrv(data
!= NULL
, NULL
);
905 plist
= (WMPropList
*) wmalloc(sizeof(W_PropList
));
907 plist
->type
= WPLData
;
908 plist
->d
.data
= WMRetainData(data
);
909 plist
->retainCount
= 1;
914 WMPropList
*WMCreatePLDataWithBytes(unsigned char *bytes
, unsigned int length
)
918 wassertrv(bytes
!= NULL
, NULL
);
920 plist
= (WMPropList
*) wmalloc(sizeof(W_PropList
));
922 plist
->type
= WPLData
;
923 plist
->d
.data
= WMCreateDataWithBytes(bytes
, length
);
924 plist
->retainCount
= 1;
929 WMPropList
*WMCreatePLDataWithBytesNoCopy(unsigned char *bytes
, unsigned int length
, WMFreeDataProc
* destructor
)
933 wassertrv(bytes
!= NULL
, NULL
);
935 plist
= (WMPropList
*) wmalloc(sizeof(W_PropList
));
937 plist
->type
= WPLData
;
938 plist
->d
.data
= WMCreateDataWithBytesNoCopy(bytes
, length
, destructor
);
939 plist
->retainCount
= 1;
944 WMPropList
*WMCreatePLArray(WMPropList
* elem
, ...)
946 WMPropList
*plist
, *nelem
;
949 plist
= (WMPropList
*) wmalloc(sizeof(W_PropList
));
950 plist
->type
= WPLArray
;
951 plist
->d
.array
= WMCreateArray(4);
952 plist
->retainCount
= 1;
957 WMAddToArray(plist
->d
.array
, WMRetainPropList(elem
));
962 nelem
= va_arg(ap
, WMPropList
*);
967 WMAddToArray(plist
->d
.array
, WMRetainPropList(nelem
));
971 WMPropList
*WMCreatePLDictionary(WMPropList
* key
, WMPropList
* value
, ...)
973 WMPropList
*plist
, *nkey
, *nvalue
, *k
, *v
;
976 plist
= (WMPropList
*) wmalloc(sizeof(W_PropList
));
977 plist
->type
= WPLDictionary
;
978 plist
->d
.dict
= WMCreateHashTable(WMPropListHashCallbacks
);
979 plist
->retainCount
= 1;
984 WMHashInsert(plist
->d
.dict
, WMRetainPropList(key
), WMRetainPropList(value
));
989 nkey
= va_arg(ap
, WMPropList
*);
994 nvalue
= va_arg(ap
, WMPropList
*);
999 if (WMHashGetItemAndKey(plist
->d
.dict
, nkey
, (void **)&v
, (void **)&k
)) {
1000 WMHashRemove(plist
->d
.dict
, k
);
1001 WMReleasePropList(k
);
1002 WMReleasePropList(v
);
1004 WMHashInsert(plist
->d
.dict
, WMRetainPropList(nkey
), WMRetainPropList(nvalue
));
1008 WMPropList
*WMRetainPropList(WMPropList
* plist
)
1010 WMPropList
*key
, *value
;
1014 plist
->retainCount
++;
1016 switch (plist
->type
) {
1021 for (i
= 0; i
< WMGetArrayItemCount(plist
->d
.array
); i
++) {
1022 WMRetainPropList(WMGetFromArray(plist
->d
.array
, i
));
1026 e
= WMEnumerateHashTable(plist
->d
.dict
);
1027 while (WMNextHashEnumeratorItemAndKey(&e
, (void **)&value
, (void **)&key
)) {
1028 WMRetainPropList(key
);
1029 WMRetainPropList(value
);
1033 wwarning(_("Used proplist functions on non-WMPropLists objects"));
1034 wassertrv(False
, NULL
);
1041 void WMReleasePropList(WMPropList
* plist
)
1043 WMPropList
*key
, *value
;
1047 plist
->retainCount
--;
1049 switch (plist
->type
) {
1051 if (plist
->retainCount
< 1) {
1052 wfree(plist
->d
.string
);
1057 if (plist
->retainCount
< 1) {
1058 WMReleaseData(plist
->d
.data
);
1063 for (i
= 0; i
< WMGetArrayItemCount(plist
->d
.array
); i
++) {
1064 WMReleasePropList(WMGetFromArray(plist
->d
.array
, i
));
1066 if (plist
->retainCount
< 1) {
1067 WMFreeArray(plist
->d
.array
);
1072 e
= WMEnumerateHashTable(plist
->d
.dict
);
1073 while (WMNextHashEnumeratorItemAndKey(&e
, (void **)&value
, (void **)&key
)) {
1074 WMReleasePropList(key
);
1075 WMReleasePropList(value
);
1077 if (plist
->retainCount
< 1) {
1078 WMFreeHashTable(plist
->d
.dict
);
1083 wwarning(_("Used proplist functions on non-WMPropLists objects"));
1089 void WMInsertInPLArray(WMPropList
* plist
, int index
, WMPropList
* item
)
1091 wassertr(plist
->type
== WPLArray
);
1093 retainPropListByCount(item
, plist
->retainCount
);
1094 WMInsertInArray(plist
->d
.array
, index
, item
);
1097 void WMAddToPLArray(WMPropList
* plist
, WMPropList
* item
)
1099 wassertr(plist
->type
== WPLArray
);
1101 retainPropListByCount(item
, plist
->retainCount
);
1102 WMAddToArray(plist
->d
.array
, item
);
1105 void WMDeleteFromPLArray(WMPropList
* plist
, int index
)
1109 wassertr(plist
->type
== WPLArray
);
1111 item
= WMGetFromArray(plist
->d
.array
, index
);
1113 WMDeleteFromArray(plist
->d
.array
, index
);
1114 releasePropListByCount(item
, plist
->retainCount
);
1118 void WMRemoveFromPLArray(WMPropList
* plist
, WMPropList
* item
)
1123 wassertr(plist
->type
== WPLArray
);
1125 for (i
= 0; i
< WMGetArrayItemCount(plist
->d
.array
); i
++) {
1126 iPtr
= WMGetFromArray(plist
->d
.array
, i
);
1127 if (WMIsPropListEqualTo(item
, iPtr
)) {
1128 WMDeleteFromArray(plist
->d
.array
, i
);
1129 releasePropListByCount(iPtr
, plist
->retainCount
);
1135 void WMPutInPLDictionary(WMPropList
* plist
, WMPropList
* key
, WMPropList
* value
)
1137 wassertr(plist
->type
== WPLDictionary
);
1139 /*WMRetainPropList(key); */
1140 WMRemoveFromPLDictionary(plist
, key
);
1141 retainPropListByCount(key
, plist
->retainCount
);
1142 retainPropListByCount(value
, plist
->retainCount
);
1143 WMHashInsert(plist
->d
.dict
, key
, value
);
1144 /*WMReleasePropList(key); */
1147 void WMRemoveFromPLDictionary(WMPropList
* plist
, WMPropList
* key
)
1151 wassertr(plist
->type
== WPLDictionary
);
1153 if (WMHashGetItemAndKey(plist
->d
.dict
, key
, (void **)&v
, (void **)&k
)) {
1154 WMHashRemove(plist
->d
.dict
, k
);
1155 releasePropListByCount(k
, plist
->retainCount
);
1156 releasePropListByCount(v
, plist
->retainCount
);
1160 WMPropList
*WMMergePLDictionaries(WMPropList
* dest
, WMPropList
* source
, Bool recursive
)
1162 WMPropList
*key
, *value
, *dvalue
;
1165 wassertr(source
->type
== WPLDictionary
&& dest
->type
== WPLDictionary
);
1170 e
= WMEnumerateHashTable(source
->d
.dict
);
1171 while (WMNextHashEnumeratorItemAndKey(&e
, (void **)&value
, (void **)&key
)) {
1172 if (recursive
&& value
->type
== WPLDictionary
) {
1173 dvalue
= WMHashGet(dest
->d
.dict
, key
);
1174 if (dvalue
&& dvalue
->type
== WPLDictionary
) {
1175 WMMergePLDictionaries(dvalue
, value
, True
);
1177 WMPutInPLDictionary(dest
, key
, value
);
1180 WMPutInPLDictionary(dest
, key
, value
);
1187 WMPropList
*WMSubtractPLDictionaries(WMPropList
* dest
, WMPropList
* source
, Bool recursive
)
1189 WMPropList
*key
, *value
, *dvalue
;
1192 wassertr(source
->type
== WPLDictionary
&& dest
->type
== WPLDictionary
);
1194 if (source
== dest
) {
1195 WMPropList
*keys
= WMGetPLDictionaryKeys(dest
);
1198 for (i
= 0; i
< WMGetArrayItemCount(keys
->d
.array
); i
++) {
1199 WMRemoveFromPLDictionary(dest
, WMGetFromArray(keys
->d
.array
, i
));
1204 e
= WMEnumerateHashTable(source
->d
.dict
);
1205 while (WMNextHashEnumeratorItemAndKey(&e
, (void **)&value
, (void **)&key
)) {
1206 dvalue
= WMHashGet(dest
->d
.dict
, key
);
1209 if (WMIsPropListEqualTo(value
, dvalue
)) {
1210 WMRemoveFromPLDictionary(dest
, key
);
1211 } else if (recursive
&& value
->type
== WPLDictionary
&& dvalue
->type
== WPLDictionary
) {
1212 WMSubtractPLDictionaries(dvalue
, value
, True
);
1219 int WMGetPropListItemCount(WMPropList
* plist
)
1221 switch (plist
->type
) {
1224 return 0; /* should this be 1 instead? */
1226 return WMGetArrayItemCount(plist
->d
.array
);
1228 return (int)WMCountHashTable(plist
->d
.dict
);
1230 wwarning(_("Used proplist functions on non-WMPropLists objects"));
1231 wassertrv(False
, 0);
1238 Bool
WMIsPLString(WMPropList
* plist
)
1240 return (plist
->type
== WPLString
);
1243 Bool
WMIsPLData(WMPropList
* plist
)
1245 return (plist
->type
== WPLData
);
1248 Bool
WMIsPLArray(WMPropList
* plist
)
1250 return (plist
->type
== WPLArray
);
1253 Bool
WMIsPLDictionary(WMPropList
* plist
)
1255 return (plist
->type
== WPLDictionary
);
1258 Bool
WMIsPropListEqualTo(WMPropList
* plist
, WMPropList
* other
)
1260 WMPropList
*key1
, *item1
, *item2
;
1261 WMHashEnumerator enumerator
;
1264 if (plist
->type
!= other
->type
)
1267 switch (plist
->type
) {
1269 if (caseSensitive
) {
1270 return (strcmp(plist
->d
.string
, other
->d
.string
) == 0);
1272 return (strcasecmp(plist
->d
.string
, other
->d
.string
) == 0);
1275 return WMIsDataEqualToData(plist
->d
.data
, other
->d
.data
);
1277 n
= WMGetArrayItemCount(plist
->d
.array
);
1278 if (n
!= WMGetArrayItemCount(other
->d
.array
))
1280 for (i
= 0; i
< n
; i
++) {
1281 item1
= WMGetFromArray(plist
->d
.array
, i
);
1282 item2
= WMGetFromArray(other
->d
.array
, i
);
1283 if (!WMIsPropListEqualTo(item1
, item2
))
1288 if (WMCountHashTable(plist
->d
.dict
) != WMCountHashTable(other
->d
.dict
))
1290 enumerator
= WMEnumerateHashTable(plist
->d
.dict
);
1291 while (WMNextHashEnumeratorItemAndKey(&enumerator
, (void **)&item1
, (void **)&key1
)) {
1292 item2
= WMHashGet(other
->d
.dict
, key1
);
1293 if (!item2
|| !item1
|| !WMIsPropListEqualTo(item1
, item2
))
1298 wwarning(_("Used proplist functions on non-WMPropLists objects"));
1299 wassertrv(False
, False
);
1306 char *WMGetFromPLString(WMPropList
* plist
)
1308 wassertrv(plist
->type
== WPLString
, NULL
);
1310 return plist
->d
.string
;
1313 WMData
*WMGetFromPLData(WMPropList
* plist
)
1315 wassertrv(plist
->type
== WPLData
, NULL
);
1317 return plist
->d
.data
;
1320 const unsigned char *WMGetPLDataBytes(WMPropList
* plist
)
1322 wassertrv(plist
->type
== WPLData
, NULL
);
1324 return WMDataBytes(plist
->d
.data
);
1327 int WMGetPLDataLength(WMPropList
* plist
)
1329 wassertrv(plist
->type
== WPLData
, 0);
1331 return WMGetDataLength(plist
->d
.data
);
1334 WMPropList
*WMGetFromPLArray(WMPropList
* plist
, int index
)
1336 wassertrv(plist
->type
== WPLArray
, NULL
);
1338 return WMGetFromArray(plist
->d
.array
, index
);
1341 WMPropList
*WMGetFromPLDictionary(WMPropList
* plist
, WMPropList
* key
)
1343 wassertrv(plist
->type
== WPLDictionary
, NULL
);
1345 return WMHashGet(plist
->d
.dict
, key
);
1348 WMPropList
*WMGetPLDictionaryKeys(WMPropList
* plist
)
1350 WMPropList
*array
, *key
;
1351 WMHashEnumerator enumerator
;
1353 wassertrv(plist
->type
== WPLDictionary
, NULL
);
1355 array
= (WMPropList
*) wmalloc(sizeof(W_PropList
));
1356 array
->type
= WPLArray
;
1357 array
->d
.array
= WMCreateArray(WMCountHashTable(plist
->d
.dict
));
1358 array
->retainCount
= 1;
1360 enumerator
= WMEnumerateHashTable(plist
->d
.dict
);
1361 while ((key
= WMNextHashEnumeratorKey(&enumerator
))) {
1362 WMAddToArray(array
->d
.array
, WMRetainPropList(key
));
1368 WMPropList
*WMShallowCopyPropList(WMPropList
* plist
)
1370 WMPropList
*ret
= NULL
;
1371 WMPropList
*key
, *item
;
1376 switch (plist
->type
) {
1378 ret
= WMCreatePLString(plist
->d
.string
);
1381 data
= WMCreateDataWithData(plist
->d
.data
);
1382 ret
= WMCreatePLData(data
);
1383 WMReleaseData(data
);
1386 ret
= (WMPropList
*) wmalloc(sizeof(W_PropList
));
1387 ret
->type
= WPLArray
;
1388 ret
->d
.array
= WMCreateArrayWithArray(plist
->d
.array
);
1389 ret
->retainCount
= 1;
1391 for (i
= 0; i
< WMGetArrayItemCount(ret
->d
.array
); i
++)
1392 WMRetainPropList(WMGetFromArray(ret
->d
.array
, i
));
1396 ret
= WMCreatePLDictionary(NULL
, NULL
);
1397 e
= WMEnumerateHashTable(plist
->d
.dict
);
1398 while (WMNextHashEnumeratorItemAndKey(&e
, (void **)&item
, (void **)&key
)) {
1399 WMPutInPLDictionary(ret
, key
, item
);
1403 wwarning(_("Used proplist functions on non-WMPropLists objects"));
1404 wassertrv(False
, NULL
);
1411 WMPropList
*WMDeepCopyPropList(WMPropList
* plist
)
1413 WMPropList
*ret
= NULL
;
1414 WMPropList
*key
, *item
;
1419 switch (plist
->type
) {
1421 ret
= WMCreatePLString(plist
->d
.string
);
1424 data
= WMCreateDataWithData(plist
->d
.data
);
1425 ret
= WMCreatePLData(data
);
1426 WMReleaseData(data
);
1429 ret
= WMCreatePLArray(NULL
);
1430 for (i
= 0; i
< WMGetArrayItemCount(plist
->d
.array
); i
++) {
1431 item
= WMDeepCopyPropList(WMGetFromArray(plist
->d
.array
, i
));
1432 WMAddToArray(ret
->d
.array
, item
);
1436 ret
= WMCreatePLDictionary(NULL
, NULL
);
1437 e
= WMEnumerateHashTable(plist
->d
.dict
);
1438 /* While we copy an existing dictionary there is no way that we can
1439 * have duplicate keys, so we don't need to first remove a key/value
1440 * pair before inserting the new key/value.
1442 while (WMNextHashEnumeratorItemAndKey(&e
, (void **)&item
, (void **)&key
)) {
1443 WMHashInsert(ret
->d
.dict
, WMDeepCopyPropList(key
), WMDeepCopyPropList(item
));
1447 wwarning(_("Used proplist functions on non-WMPropLists objects"));
1448 wassertrv(False
, NULL
);
1455 WMPropList
*WMCreatePropListFromDescription(char *desc
)
1457 WMPropList
*plist
= NULL
;
1460 pldata
= (PLData
*) wmalloc(sizeof(PLData
));
1461 memset(pldata
, 0, sizeof(PLData
));
1463 pldata
->lineNumber
= 1;
1465 plist
= getPropList(pldata
);
1467 if (getNonSpaceChar(pldata
) != 0 && plist
) {
1468 COMPLAIN(pldata
, _("extra data after end of property list"));
1470 * We can't just ignore garbage after the end of the description
1471 * (especially if the description was read from a file), because
1472 * the "garbage" can be the real data and the real garbage is in
1473 * fact in the beginning of the file (which is now inside plist)
1475 WMReleasePropList(plist
);
1484 char *WMGetPropListDescription(WMPropList
* plist
, Bool indented
)
1486 return (indented
? indentedDescription(plist
, 0) : description(plist
));
1489 WMPropList
*WMReadPropListFromFile(char *file
)
1491 WMPropList
*plist
= NULL
;
1497 f
= fopen(file
, "rb");
1499 /* let the user print the error message if he really needs to */
1500 /*wsyserror(_("could not open domain file '%s' for reading"), file); */
1504 if (stat(file
, &stbuf
) == 0) {
1505 length
= (size_t) stbuf
.st_size
;
1507 wsyserror(_("could not get size for file '%s'"), file
);
1512 pldata
= (PLData
*) wmalloc(sizeof(PLData
));
1513 memset(pldata
, 0, sizeof(PLData
));
1514 pldata
->ptr
= (char *)wmalloc(length
+ 1);
1515 pldata
->filename
= file
;
1516 pldata
->lineNumber
= 1;
1518 if (fread(pldata
->ptr
, length
, 1, f
) != 1) {
1520 wsyserror(_("error reading from file '%s'"), file
);
1526 pldata
->ptr
[length
] = 0;
1528 plist
= getPropList(pldata
);
1530 if (getNonSpaceChar(pldata
) != 0 && plist
) {
1531 COMPLAIN(pldata
, _("extra data after end of property list"));
1533 * We can't just ignore garbage after the end of the description
1534 * (especially if the description was read from a file), because
1535 * the "garbage" can be the real data and the real garbage is in
1536 * fact in the beginning of the file (which is now inside plist)
1538 WMReleasePropList(plist
);
1550 /* TODO: review this function's code */
1552 Bool
WMWritePropListToFile(WMPropList
* plist
, char *path
, Bool atomically
)
1554 char *thePath
= NULL
;
1563 /* Use the path name of the destination file as a prefix for the
1564 * mkstemp() call so that we can be sure that both files are on
1565 * the same filesystem and the subsequent rename() will work. */
1566 thePath
= wstrconcat(path
, ".XXXXXX");
1569 if ((fd
= mkstemp(thePath
)) < 0) {
1570 wsyserror(_("mkstemp (%s) failed"), thePath
);
1575 fchmod(fd
, 0644 & ~mask
);
1576 if ((theFile
= fdopen(fd
, "wb")) == NULL
) {
1580 if (mktemp(thePath
) == NULL
) {
1581 wsyserror(_("mktemp (%s) failed"), thePath
);
1584 theFile
= fopen(thePath
, "wb");
1587 thePath
= wstrdup(path
);
1588 theFile
= fopen(thePath
, "wb");
1591 if (theFile
== NULL
) {
1592 wsyserror(_("open (%s) failed"), thePath
);
1596 desc
= indentedDescription(plist
, 0);
1598 if (fprintf(theFile
, "%s\n", desc
) != strlen(desc
) + 1) {
1599 wsyserror(_("writing to file: %s failed"), thePath
);
1606 if (fclose(theFile
) != 0) {
1607 wsyserror(_("fclose (%s) failed"), thePath
);
1611 /* If we used a temporary file, we still need to rename() it be the
1612 * real file. Also, we need to try to retain the file attributes of
1613 * the original file we are overwriting (if we are) */
1615 if (rename(thePath
, path
) != 0) {
1616 wsyserror(_("rename ('%s' to '%s') failed"), thePath
, path
);