18 WPLString
= 0x57504c01,
20 WPLArray
= 0x57504c03,
21 WPLDictionary
= 0x57504c04
25 typedef struct W_PropList
{
39 typedef struct PLData
{
47 typedef struct StringBuffer
{
53 static unsigned hashPropList(WMPropList
*plist
);
54 static WMPropList
* getPLString(PLData
*pldata
);
55 static WMPropList
* getPLQString(PLData
*pldata
);
56 static WMPropList
* getPLData(PLData
*pldata
);
57 static WMPropList
* getPLArray(PLData
*pldata
);
58 static WMPropList
* getPLDictionary(PLData
*pldata
);
59 static WMPropList
* getPropList(PLData
*pldata
);
63 typedef unsigned (*hashFunc
)(const void*);
64 typedef Bool (*isEqualFunc
)(const void*, const void*);
65 typedef void* (*retainFunc
)(const void*);
66 typedef void (*releaseFunc
)(const void*);
68 static const WMHashTableCallbacks WMPropListHashCallbacks
= {
69 (hashFunc
)hashPropList
,
70 (isEqualFunc
)WMIsPropListEqualTo
,
77 static Bool caseSensitive
= True
;
81 #define BUFFERSIZE 8192
82 #define BUFFERSIZE_INCREMENT 1024
86 # define DPUT(s) puts(s)
91 #define COMPLAIN(pld, msg) wwarning(_("syntax error in %s %s, line %i: %s"),\
92 (pld)->filename ? "file" : "PropList",\
93 (pld)->filename ? (pld)->filename : "description",\
94 (pld)->lineNumber, msg)
96 #define ISSTRINGABLE(c) (isalnum(c) || (c)=='.' || (c)=='_' || (c)=='/' \
99 #define CHECK_BUFFER_SIZE(buf, ptr) \
100 if ((ptr) >= (buf).size-1) {\
101 (buf).size += BUFFERSIZE_INCREMENT;\
102 (buf).str = wrealloc((buf).str, (buf).size);\
106 #define inrange(ch, min, max) ((ch)>=(min) && (ch)<=(max))
107 #define noquote(ch) (inrange(ch, 'a', 'z') || inrange(ch, 'A', 'Z') || inrange(ch, '0', '9') || ((ch)=='_') || ((ch)=='.') || ((ch)=='$'))
108 #define charesc(ch) (inrange(ch, 0x07, 0x0c) || ((ch)=='"') || ((ch)=='\\'))
109 #define numesc(ch) (((ch)<=0x06) || inrange(ch, 0x0d, 0x1f) || ((ch)>0x7e))
110 #define ishexdigit(ch) (inrange(ch, 'a', 'f') || inrange(ch, 'A', 'F') || inrange(ch, '0', '9'))
111 #define char2num(ch) (inrange(ch,'0','9') ? ((ch)-'0') : (inrange(ch,'a','f') ? ((ch)-0x57) : ((ch)-0x37)))
112 #define num2char(num) ((num) < 0xa ? ((num)+'0') : ((num)+0x57))
116 #define MaxHashLength 64
119 hashPropList(WMPropList
*plist
)
126 switch (plist
->type
) {
128 key
= plist
->d
.string
;
129 len
= WMIN(strlen(key
), MaxHashLength
);
130 for (i
=0; i
<len
; i
++) {
131 ret
^= tolower(key
[i
]) << ctr
;
132 ctr
= (ctr
+ 1) % sizeof (char *);
135 ret ^= tolower(*key++) << ctr;
136 ctr = (ctr + 1) % sizeof (char *);
141 key
= WMDataBytes(plist
->d
.data
);
142 len
= WMIN(WMGetDataLength(plist
->d
.data
), MaxHashLength
);
143 for (i
=0; i
<len
; i
++) {
144 ret
^= key
[i
] << ctr
;
145 ctr
= (ctr
+ 1) % sizeof (char *);
150 wwarning(_("Only string or data is supported for a proplist dictionary key"));
159 retainPropListByCount(WMPropList
*plist
, int count
)
161 WMPropList
*key
, *value
;
165 plist
->retainCount
+= count
;
167 switch(plist
->type
) {
172 for (i
=0; i
<WMGetArrayItemCount(plist
->d
.array
); i
++) {
173 retainPropListByCount(WMGetFromArray(plist
->d
.array
, i
), count
);
177 e
= WMEnumerateHashTable(plist
->d
.dict
);
178 while (WMNextHashEnumeratorItemAndKey(&e
, (void**)&value
, (void**)&key
)) {
179 retainPropListByCount(key
, count
);
180 retainPropListByCount(value
, count
);
184 wwarning(_("Used proplist functions on non-WMPropLists objects"));
185 wassertrv(False
, NULL
);
194 releasePropListByCount(WMPropList
*plist
, int count
)
196 WMPropList
*key
, *value
;
200 plist
->retainCount
-= count
;
202 switch(plist
->type
) {
204 if (plist
->retainCount
< 1) {
205 wfree(plist
->d
.string
);
210 if (plist
->retainCount
< 1) {
211 WMReleaseData(plist
->d
.data
);
216 for (i
=0; i
<WMGetArrayItemCount(plist
->d
.array
); i
++) {
217 releasePropListByCount(WMGetFromArray(plist
->d
.array
, i
), count
);
219 if (plist
->retainCount
< 1) {
220 WMFreeArray(plist
->d
.array
);
225 e
= WMEnumerateHashTable(plist
->d
.dict
);
226 while (WMNextHashEnumeratorItemAndKey(&e
, (void**)&value
, (void**)&key
)) {
227 releasePropListByCount(key
, count
);
228 releasePropListByCount(value
, count
);
230 if (plist
->retainCount
< 1) {
231 WMFreeHashTable(plist
->d
.dict
);
236 wwarning(_("Used proplist functions on non-WMPropLists objects"));
244 dataDescription(WMPropList
*plist
)
246 const unsigned char *data
;
250 data
= WMDataBytes(plist
->d
.data
);
251 length
= WMGetDataLength(plist
->d
.data
);
253 retVal
= (char*)wmalloc(2*length
+length
/4+3);
256 for (i
=0, j
=1; i
<length
; i
++) {
257 retVal
[j
++] = num2char((data
[i
]>>4) & 0x0f);
258 retVal
[j
++] = num2char(data
[i
] & 0x0f);
259 if ((i
& 0x03)==3 && i
!=length
-1) {
260 /* if we've just finished a 32-bit int, add a space */
272 stringDescription(WMPropList
*plist
)
275 char *retVal
, *sPtr
, *dPtr
;
279 str
= plist
->d
.string
;
281 if (strlen(str
) == 0) {
282 return wstrdup("\"\"");
285 /* FIXME: make this work with unichars. */
290 while ((ch
= *sPtr
)) {
305 retVal
= (char*)wmalloc(len
+1);
313 while ((ch
= *sPtr
)) {
317 case '\a': *dPtr
= 'a'; break;
318 case '\b': *dPtr
= 'b'; break;
319 case '\t': *dPtr
= 't'; break;
320 case '\n': *dPtr
= 'n'; break;
321 case '\v': *dPtr
= 'v'; break;
322 case '\f': *dPtr
= 'f'; break;
323 default: *dPtr
= ch
; /* " or \ */
325 } else if (numesc(ch
)) {
327 *(dPtr
++) = '0' + ((ch
>>6)&07);
328 *(dPtr
++) = '0' + ((ch
>>3)&07);
329 *dPtr
= '0' + (ch
&07);
347 description(WMPropList
*plist
)
349 WMPropList
*key
, *val
;
351 char *str
, *tmp
, *skey
, *sval
;
355 switch (plist
->type
) {
357 retstr
= stringDescription(plist
);
360 retstr
= dataDescription(plist
);
363 retstr
= wstrdup("(");
364 for (i
=0; i
<WMGetArrayItemCount(plist
->d
.array
); i
++) {
365 str
= description(WMGetFromArray(plist
->d
.array
, i
));
367 retstr
= wstrappend(retstr
, str
);
369 tmp
= (char *)wmalloc(strlen(retstr
)+strlen(str
)+3);
370 sprintf(tmp
, "%s, %s", retstr
, str
);
376 retstr
= wstrappend(retstr
, ")");
379 retstr
= wstrdup("{");
380 e
= WMEnumerateHashTable(plist
->d
.dict
);
381 while (WMNextHashEnumeratorItemAndKey(&e
, (void**)&val
, (void**)&key
)) {
382 skey
= description(key
);
383 sval
= description(val
);
384 tmp
= (char*)wmalloc(strlen(retstr
)+strlen(skey
)+strlen(sval
)+5);
385 sprintf(tmp
, "%s%s = %s;", retstr
, skey
, sval
);
391 retstr
= wstrappend(retstr
, "}");
394 wwarning(_("Used proplist functions on non-WMPropLists objects"));
395 wassertrv(False
, NULL
);
404 indentedDescription(WMPropList
*plist
, int level
)
406 WMPropList
*key
, *val
;
408 char *str
, *tmp
, *skey
, *sval
;
412 if (plist
->type
==WPLArray
/* || plist->type==WPLDictionary*/) {
413 retstr
= description(plist
);
415 if (retstr
&& ((2*(level
+1) + strlen(retstr
)) <= 77)) {
423 switch (plist
->type
) {
425 retstr
= stringDescription(plist
);
428 retstr
= dataDescription(plist
);
431 retstr
= wstrdup("(\n");
432 for (i
=0; i
<WMGetArrayItemCount(plist
->d
.array
); i
++) {
433 str
= indentedDescription(WMGetFromArray(plist
->d
.array
, i
),
436 tmp
= (char*)wmalloc(2*(level
+1)+strlen(retstr
)+strlen(str
)+1);
437 sprintf(tmp
, "%s%*s%s", retstr
, 2*(level
+1), "", str
);
441 tmp
= (char*)wmalloc(2*(level
+1)+strlen(retstr
)+strlen(str
)+3);
442 sprintf(tmp
, "%s,\n%*s%s", retstr
, 2*(level
+1), "", str
);
448 tmp
= (char*)wmalloc(strlen(retstr
) + 2*level
+ 3);
449 sprintf(tmp
, "%s\n%*s)", retstr
, 2*level
, "");
454 retstr
= wstrdup("{\n");
455 e
= WMEnumerateHashTable(plist
->d
.dict
);
456 while (WMNextHashEnumeratorItemAndKey(&e
, (void**)&val
, (void**)&key
)) {
457 skey
= indentedDescription(key
, level
+1);
458 sval
= indentedDescription(val
, level
+1);
459 tmp
= (char*)wmalloc(2*(level
+1) + strlen(retstr
) + strlen(skey
)
461 sprintf(tmp
, "%s%*s%s = %s;\n", retstr
, 2*(level
+1), "",
468 tmp
= (char*)wmalloc(strlen(retstr
) + 2*level
+ 2);
469 sprintf(tmp
, "%s%*s}", retstr
, 2*level
, "");
474 wwarning(_("Used proplist functions on non-WMPropLists objects"));
475 wassertrv(False
, NULL
);
484 getChar(PLData
*pldata
)
488 c
= pldata
->ptr
[pldata
->pos
];
496 pldata
->lineNumber
++;
503 getNonSpaceChar(PLData
*pldata
)
508 c
= pldata
->ptr
[pldata
->pos
];
514 pldata
->lineNumber
++;
515 } else if (!isspace(c
)) {
525 unescapestr(char *src
)
527 char *dest
= wmalloc(strlen(src
)+1);
532 for (sPtr
=src
, dPtr
=dest
; *sPtr
; sPtr
++, dPtr
++) {
537 if((ch
>='0') && (ch
<='3')) {
538 /* assume next 2 chars are octal too */
539 *dPtr
= ((ch
& 07) << 6);
540 *dPtr
|= ((*(++sPtr
)&07)<<3);
541 *dPtr
|= *(++sPtr
)&07;
544 case 'a' : *dPtr
= '\a'; break;
545 case 'b' : *dPtr
= '\b'; break;
546 case 't' : *dPtr
= '\t'; break;
547 case 'r' : *dPtr
= '\r'; break;
548 case 'n' : *dPtr
= '\n'; break;
549 case 'v' : *dPtr
= '\v'; break;
550 case 'f' : *dPtr
= '\f'; break;
551 default : *dPtr
= *sPtr
;
564 getPLString(PLData
*pldata
)
571 sBuf
.str
= wmalloc(BUFFERSIZE
);
572 sBuf
.size
= BUFFERSIZE
;
576 if (ISSTRINGABLE(c
)) {
577 CHECK_BUFFER_SIZE(sBuf
, ptr
);
592 char *tmp
= unescapestr(sBuf
.str
);
593 plist
= WMCreatePLString(tmp
);
604 getPLQString(PLData
*pldata
)
607 int ptr
= 0, escaping
= 0, ok
= 1;
611 sBuf
.str
= wmalloc(BUFFERSIZE
);
612 sBuf
.size
= BUFFERSIZE
;
620 } else if (c
== '"') {
624 CHECK_BUFFER_SIZE(sBuf
, ptr
);
625 sBuf
.str
[ptr
++] = '\\';
630 COMPLAIN(pldata
, _("unterminated PropList string"));
634 CHECK_BUFFER_SIZE(sBuf
, ptr
);
644 char *tmp
= unescapestr(sBuf
.str
);
645 plist
= WMCreatePLString(tmp
);
656 getPLData(PLData
*pldata
)
661 unsigned char buf
[BUFFERSIZE
], byte
;
665 data
= WMCreateDataWithCapacity(0);
668 c1
= getNonSpaceChar(pldata
);
670 COMPLAIN(pldata
, _("unterminated PropList data"));
673 } else if (c1
=='>') {
675 } else if (ishexdigit(c1
)) {
676 c2
= getNonSpaceChar(pldata
);
677 if (c2
==0 || c2
=='>') {
678 COMPLAIN(pldata
, _("unterminated PropList data (missing hexdigit)"));
681 } else if (ishexdigit(c2
)) {
682 byte
= char2num(c1
) << 4;
683 byte
|= char2num(c2
);
685 if (len
== sizeof(buf
)) {
686 WMAppendDataBytes(data
, buf
, len
);
690 COMPLAIN(pldata
, _("non hexdigit character in PropList data"));
695 COMPLAIN(pldata
, _("non hexdigit character in PropList data"));
707 WMAppendDataBytes(data
, buf
, len
);
709 plist
= WMCreatePLData(data
);
717 getPLArray(PLData
*pldata
)
722 WMPropList
*array
, *obj
;
724 array
= WMCreatePLArray(NULL
);
727 c
= getNonSpaceChar(pldata
);
729 COMPLAIN(pldata
, _("unterminated PropList array"));
732 } else if (c
== ')') {
734 } else if (c
== ',') {
735 /* continue normally */
737 COMPLAIN(pldata
, _("missing or unterminated PropList array"));
745 obj
= getPropList(pldata
);
747 COMPLAIN(pldata
, _("could not get PropList array element"));
751 WMAddToPLArray(array
, obj
);
752 WMReleasePropList(obj
);
756 WMReleasePropList(array
);
765 getPLDictionary(PLData
*pldata
)
769 WMPropList
*dict
, *key
, *value
;
771 dict
= WMCreatePLDictionary(NULL
, NULL
);
774 c
= getNonSpaceChar(pldata
);
776 COMPLAIN(pldata
, _("unterminated PropList dictionary"));
783 DPUT("getting PropList dictionary key");
785 key
= getPLData(pldata
);
786 } else if (c
== '"') {
787 key
= getPLQString(pldata
);
788 } else if (ISSTRINGABLE(c
)) {
790 key
= getPLString(pldata
);
793 COMPLAIN(pldata
, _("missing PropList dictionary key"));
795 COMPLAIN(pldata
, _("missing PropList dictionary entry key "
796 "or unterminated dictionary"));
803 COMPLAIN(pldata
, _("error parsing PropList dictionary key"));
808 c
= getNonSpaceChar(pldata
);
810 WMReleasePropList(key
);
811 COMPLAIN(pldata
, _("missing = in PropList dictionary entry"));
816 DPUT("getting PropList dictionary entry value for key");
817 value
= getPropList(pldata
);
819 COMPLAIN(pldata
, _("error parsing PropList dictionary entry value"));
820 WMReleasePropList(key
);
825 c
= getNonSpaceChar(pldata
);
827 COMPLAIN(pldata
, _("missing ; in PropList dictionary entry"));
828 WMReleasePropList(key
);
829 WMReleasePropList(value
);
834 WMPutInPLDictionary(dict
, key
, value
);
835 WMReleasePropList(key
);
836 WMReleasePropList(value
);
840 WMReleasePropList(dict
);
849 getPropList(PLData
*pldata
)
854 c
= getNonSpaceChar(pldata
);
858 DPUT("End of PropList");
863 DPUT("Getting PropList dictionary");
864 plist
= getPLDictionary(pldata
);
868 DPUT("Getting PropList srrsy");
869 plist
= getPLArray(pldata
);
873 DPUT("Getting PropList data");
874 plist
= getPLData(pldata
);
878 DPUT("Getting PropList quoted string");
879 plist
= getPLQString(pldata
);
883 if (ISSTRINGABLE(c
)) {
884 DPUT("Getting PropList string");
886 plist
= getPLString(pldata
);
888 COMPLAIN(pldata
, _("was expecting a string, data, array or "
889 "dictionary. If it's a string, try enclosing "
891 if (c
=='#' || c
=='/') {
892 wwarning(_("Comments are not allowed inside WindowMaker owned"
905 WMPLSetCaseSensitive(Bool caseSensitiveness
)
907 caseSensitive
= caseSensitiveness
;
912 WMCreatePLString(char *str
)
916 wassertrv(str
!=NULL
, NULL
);
918 plist
= (WMPropList
*)wmalloc(sizeof(W_PropList
));
920 plist
->type
= WPLString
;
921 plist
->d
.string
= wstrdup(str
);
922 plist
->retainCount
= 1;
929 WMCreatePLData(WMData
*data
)
933 wassertrv(data
!=NULL
, NULL
);
935 plist
= (WMPropList
*)wmalloc(sizeof(W_PropList
));
937 plist
->type
= WPLData
;
938 plist
->d
.data
= WMRetainData(data
);
939 plist
->retainCount
= 1;
946 WMCreatePLDataWithBytes(unsigned char *bytes
, unsigned int length
)
950 wassertrv(bytes
!=NULL
, NULL
);
952 plist
= (WMPropList
*)wmalloc(sizeof(W_PropList
));
954 plist
->type
= WPLData
;
955 plist
->d
.data
= WMCreateDataWithBytes(bytes
, length
);
956 plist
->retainCount
= 1;
963 WMCreatePLDataWithBytesNoCopy(unsigned char *bytes
, unsigned int length
,
964 WMFreeDataProc
*destructor
)
968 wassertrv(bytes
!=NULL
, NULL
);
970 plist
= (WMPropList
*)wmalloc(sizeof(W_PropList
));
972 plist
->type
= WPLData
;
973 plist
->d
.data
= WMCreateDataWithBytesNoCopy(bytes
, length
, destructor
);
974 plist
->retainCount
= 1;
981 WMCreatePLArray(WMPropList
*elem
, ...)
983 WMPropList
*plist
, *nelem
;
986 plist
= (WMPropList
*)wmalloc(sizeof(W_PropList
));
987 plist
->type
= WPLArray
;
988 plist
->d
.array
= WMCreateArray(4);
989 plist
->retainCount
= 1;
994 WMAddToArray(plist
->d
.array
, WMRetainPropList(elem
));
999 nelem
= va_arg(ap
, WMPropList
*);
1004 WMAddToArray(plist
->d
.array
, WMRetainPropList(nelem
));
1010 WMCreatePLDictionary(WMPropList
*key
, WMPropList
*value
, ...)
1012 WMPropList
*plist
, *nkey
, *nvalue
, *k
, *v
;
1015 plist
= (WMPropList
*)wmalloc(sizeof(W_PropList
));
1016 plist
->type
= WPLDictionary
;
1017 plist
->d
.dict
= WMCreateHashTable(WMPropListHashCallbacks
);
1018 plist
->retainCount
= 1;
1023 WMHashInsert(plist
->d
.dict
, WMRetainPropList(key
), WMRetainPropList(value
));
1025 va_start(ap
, value
);
1028 nkey
= va_arg(ap
, WMPropList
*);
1033 nvalue
= va_arg(ap
, WMPropList
*);
1038 if (WMHashGetItemAndKey(plist
->d
.dict
, nkey
, (void**)&v
, (void**)&k
)) {
1039 WMHashRemove(plist
->d
.dict
, k
);
1040 WMReleasePropList(k
);
1041 WMReleasePropList(v
);
1043 WMHashInsert(plist
->d
.dict
, WMRetainPropList(nkey
),
1044 WMRetainPropList(nvalue
));
1050 WMRetainPropList(WMPropList
*plist
)
1052 WMPropList
*key
, *value
;
1056 plist
->retainCount
++;
1058 switch(plist
->type
) {
1063 for (i
=0; i
<WMGetArrayItemCount(plist
->d
.array
); i
++) {
1064 WMRetainPropList(WMGetFromArray(plist
->d
.array
, i
));
1068 e
= WMEnumerateHashTable(plist
->d
.dict
);
1069 while (WMNextHashEnumeratorItemAndKey(&e
, (void**)&value
, (void**)&key
)) {
1070 WMRetainPropList(key
);
1071 WMRetainPropList(value
);
1075 wwarning(_("Used proplist functions on non-WMPropLists objects"));
1076 wassertrv(False
, NULL
);
1085 WMReleasePropList(WMPropList
*plist
)
1087 WMPropList
*key
, *value
;
1091 plist
->retainCount
--;
1093 switch(plist
->type
) {
1095 if (plist
->retainCount
< 1) {
1096 wfree(plist
->d
.string
);
1101 if (plist
->retainCount
< 1) {
1102 WMReleaseData(plist
->d
.data
);
1107 for (i
=0; i
<WMGetArrayItemCount(plist
->d
.array
); i
++) {
1108 WMReleasePropList(WMGetFromArray(plist
->d
.array
, i
));
1110 if (plist
->retainCount
< 1) {
1111 WMFreeArray(plist
->d
.array
);
1116 e
= WMEnumerateHashTable(plist
->d
.dict
);
1117 while (WMNextHashEnumeratorItemAndKey(&e
, (void**)&value
, (void**)&key
)) {
1118 WMReleasePropList(key
);
1119 WMReleasePropList(value
);
1121 if (plist
->retainCount
< 1) {
1122 WMFreeHashTable(plist
->d
.dict
);
1127 wwarning(_("Used proplist functions on non-WMPropLists objects"));
1135 WMInsertInPLArray(WMPropList
*plist
, int index
, WMPropList
*item
)
1137 wassertr(plist
->type
==WPLArray
);
1139 retainPropListByCount(item
, plist
->retainCount
);
1140 WMInsertInArray(plist
->d
.array
, index
, item
);
1145 WMAddToPLArray(WMPropList
*plist
, WMPropList
*item
)
1147 wassertr(plist
->type
==WPLArray
);
1149 retainPropListByCount(item
, plist
->retainCount
);
1150 WMAddToArray(plist
->d
.array
, item
);
1155 WMDeleteFromPLArray(WMPropList
*plist
, int index
)
1159 wassertr(plist
->type
==WPLArray
);
1161 item
= WMGetFromArray(plist
->d
.array
, index
);
1163 WMDeleteFromArray(plist
->d
.array
, index
);
1164 releasePropListByCount(item
, plist
->retainCount
);
1170 WMRemoveFromPLArray(WMPropList
*plist
, WMPropList
*item
)
1175 wassertr(plist
->type
==WPLArray
);
1177 for (i
=0; i
<WMGetArrayItemCount(plist
->d
.array
); i
++) {
1178 iPtr
= WMGetFromArray(plist
->d
.array
, i
);
1179 if (WMIsPropListEqualTo(item
, iPtr
)) {
1180 WMDeleteFromArray(plist
->d
.array
, i
);
1181 releasePropListByCount(iPtr
, plist
->retainCount
);
1189 WMPutInPLDictionary(WMPropList
*plist
, WMPropList
*key
, WMPropList
*value
)
1191 wassertr(plist
->type
==WPLDictionary
);
1193 /*WMRetainPropList(key);*/
1194 WMRemoveFromPLDictionary(plist
, key
);
1195 retainPropListByCount(key
, plist
->retainCount
);
1196 retainPropListByCount(value
, plist
->retainCount
);
1197 WMHashInsert(plist
->d
.dict
, key
, value
);
1198 /*WMReleasePropList(key);*/
1203 WMRemoveFromPLDictionary(WMPropList
*plist
, WMPropList
*key
)
1207 wassertr(plist
->type
==WPLDictionary
);
1209 if (WMHashGetItemAndKey(plist
->d
.dict
, key
, (void**)&v
, (void**)&k
)) {
1210 WMHashRemove(plist
->d
.dict
, k
);
1211 releasePropListByCount(k
, plist
->retainCount
);
1212 releasePropListByCount(v
, plist
->retainCount
);
1218 WMMergePLDictionaries(WMPropList
*dest
, WMPropList
*source
, Bool recursive
)
1220 WMPropList
*key
, *value
, *dvalue
;
1223 wassertr(source
->type
==WPLDictionary
&& dest
->type
==WPLDictionary
);
1228 e
= WMEnumerateHashTable(source
->d
.dict
);
1229 while (WMNextHashEnumeratorItemAndKey(&e
, (void**)&value
, (void**)&key
)) {
1230 if (recursive
&& value
->type
==WPLDictionary
) {
1231 dvalue
= WMHashGet(dest
->d
.dict
, key
);
1232 if (dvalue
&& dvalue
->type
==WPLDictionary
) {
1233 WMMergePLDictionaries(dvalue
, value
, True
);
1235 WMPutInPLDictionary(dest
, key
, value
);
1238 WMPutInPLDictionary(dest
, key
, value
);
1247 WMSubtractPLDictionaries(WMPropList
*dest
, WMPropList
*source
, Bool recursive
)
1249 WMPropList
*key
, *value
, *dvalue
;
1252 wassertr(source
->type
==WPLDictionary
&& dest
->type
==WPLDictionary
);
1254 if (source
== dest
) {
1255 WMPropList
*keys
= WMGetPLDictionaryKeys(dest
);
1258 for (i
=0; i
<WMGetArrayItemCount(keys
->d
.array
); i
++) {
1259 WMRemoveFromPLDictionary(dest
, WMGetFromArray(keys
->d
.array
, i
));
1264 e
= WMEnumerateHashTable(source
->d
.dict
);
1265 while (WMNextHashEnumeratorItemAndKey(&e
, (void**)&value
, (void**)&key
)) {
1266 dvalue
= WMHashGet(dest
->d
.dict
, key
);
1269 if (WMIsPropListEqualTo(value
, dvalue
)) {
1270 WMRemoveFromPLDictionary(dest
, key
);
1271 } else if (recursive
&& value
->type
==WPLDictionary
&&
1272 dvalue
->type
==WPLDictionary
) {
1273 WMSubtractPLDictionaries(dvalue
, value
, True
);
1282 WMGetPropListItemCount(WMPropList
*plist
)
1284 switch(plist
->type
) {
1287 return 0; /* should this be 1 instead? */
1289 return WMGetArrayItemCount(plist
->d
.array
);
1291 return (int)WMCountHashTable(plist
->d
.dict
);
1293 wwarning(_("Used proplist functions on non-WMPropLists objects"));
1294 wassertrv(False
, 0);
1303 WMIsPLString(WMPropList
*plist
)
1305 return (plist
->type
== WPLString
);
1310 WMIsPLData(WMPropList
*plist
)
1312 return (plist
->type
== WPLData
);
1317 WMIsPLArray(WMPropList
*plist
)
1319 return (plist
->type
== WPLArray
);
1324 WMIsPLDictionary(WMPropList
*plist
)
1326 return (plist
->type
== WPLDictionary
);
1331 WMIsPropListEqualTo(WMPropList
*plist
, WMPropList
*other
)
1333 WMPropList
*key1
, *item1
, *item2
;
1334 WMHashEnumerator enumerator
;
1337 if (plist
->type
!= other
->type
)
1340 switch(plist
->type
) {
1342 if (caseSensitive
) {
1343 return (strcmp(plist
->d
.string
, other
->d
.string
) == 0);
1345 return (strcasecmp(plist
->d
.string
, other
->d
.string
) == 0);
1348 return WMIsDataEqualToData(plist
->d
.data
, other
->d
.data
);
1350 n
= WMGetArrayItemCount(plist
->d
.array
);
1351 if (n
!= WMGetArrayItemCount(other
->d
.array
))
1353 for (i
=0; i
<n
; i
++) {
1354 item1
= WMGetFromArray(plist
->d
.array
, i
);
1355 item2
= WMGetFromArray(other
->d
.array
, i
);
1356 if (!WMIsPropListEqualTo(item1
, item2
))
1361 if (WMCountHashTable(plist
->d
.dict
) != WMCountHashTable(other
->d
.dict
))
1363 enumerator
= WMEnumerateHashTable(plist
->d
.dict
);
1364 while (WMNextHashEnumeratorItemAndKey(&enumerator
, (void**)&item1
,
1366 item2
= WMHashGet(other
->d
.dict
, key1
);
1367 if (!item2
|| !item1
|| !WMIsPropListEqualTo(item1
, item2
))
1372 wwarning(_("Used proplist functions on non-WMPropLists objects"));
1373 wassertrv(False
, False
);
1382 WMGetFromPLString(WMPropList
*plist
)
1384 wassertrv(plist
->type
==WPLString
, NULL
);
1386 return plist
->d
.string
;
1391 WMGetFromPLData(WMPropList
*plist
)
1393 wassertrv(plist
->type
==WPLData
, NULL
);
1395 return plist
->d
.data
;
1399 const unsigned char*
1400 WMGetPLDataBytes(WMPropList
*plist
)
1402 wassertrv(plist
->type
==WPLData
, NULL
);
1404 return WMDataBytes(plist
->d
.data
);
1409 WMGetPLDataLength(WMPropList
*plist
)
1411 wassertrv(plist
->type
==WPLData
, 0);
1413 return WMGetDataLength(plist
->d
.data
);
1418 WMGetFromPLArray(WMPropList
*plist
, int index
)
1420 wassertrv(plist
->type
==WPLArray
, NULL
);
1422 return WMGetFromArray(plist
->d
.array
, index
);
1427 WMGetFromPLDictionary(WMPropList
*plist
, WMPropList
*key
)
1429 wassertrv(plist
->type
==WPLDictionary
, NULL
);
1431 return WMHashGet(plist
->d
.dict
, key
);
1436 WMGetPLDictionaryKeys(WMPropList
*plist
)
1438 WMPropList
*array
, *key
;
1439 WMHashEnumerator enumerator
;
1441 wassertrv(plist
->type
==WPLDictionary
, NULL
);
1443 array
= (WMPropList
*)wmalloc(sizeof(W_PropList
));
1444 array
->type
= WPLArray
;
1445 array
->d
.array
= WMCreateArray(WMCountHashTable(plist
->d
.dict
));
1446 array
->retainCount
= 1;
1448 enumerator
= WMEnumerateHashTable(plist
->d
.dict
);
1449 while ((key
= WMNextHashEnumeratorKey(&enumerator
))) {
1450 WMAddToArray(array
->d
.array
, WMRetainPropList(key
));
1458 WMShallowCopyPropList(WMPropList
*plist
)
1460 WMPropList
*ret
= NULL
;
1461 WMPropList
*key
, *item
;
1466 switch(plist
->type
) {
1468 ret
= WMCreatePLString(plist
->d
.string
);
1471 data
= WMCreateDataWithData(plist
->d
.data
);
1472 ret
= WMCreatePLData(data
);
1473 WMReleaseData(data
);
1476 ret
= (WMPropList
*)wmalloc(sizeof(W_PropList
));
1477 ret
->type
= WPLArray
;
1478 ret
->d
.array
= WMCreateArrayWithArray(plist
->d
.array
);
1479 ret
->retainCount
= 1;
1481 for(i
=0; i
<WMGetArrayItemCount(ret
->d
.array
); i
++)
1482 WMRetainPropList(WMGetFromArray(ret
->d
.array
, i
));
1486 ret
= WMCreatePLDictionary(NULL
, NULL
);
1487 e
= WMEnumerateHashTable(plist
->d
.dict
);
1488 while (WMNextHashEnumeratorItemAndKey(&e
, (void**)&item
, (void**)&key
)) {
1489 WMPutInPLDictionary(ret
, key
, item
);
1493 wwarning(_("Used proplist functions on non-WMPropLists objects"));
1494 wassertrv(False
, NULL
);
1503 WMDeepCopyPropList(WMPropList
*plist
)
1505 WMPropList
*ret
= NULL
;
1506 WMPropList
*key
, *item
;
1511 switch(plist
->type
) {
1513 ret
= WMCreatePLString(plist
->d
.string
);
1516 data
= WMCreateDataWithData(plist
->d
.data
);
1517 ret
= WMCreatePLData(data
);
1518 WMReleaseData(data
);
1521 ret
= WMCreatePLArray(NULL
);
1522 for(i
=0; i
<WMGetArrayItemCount(plist
->d
.array
); i
++) {
1523 item
= WMDeepCopyPropList(WMGetFromArray(plist
->d
.array
, i
));
1524 WMAddToArray(ret
->d
.array
, item
);
1528 ret
= WMCreatePLDictionary(NULL
, NULL
);
1529 e
= WMEnumerateHashTable(plist
->d
.dict
);
1530 /* While we copy an existing dictionary there is no way that we can
1531 * have duplicate keys, so we don't need to first remove a key/value
1532 * pair before inserting the new key/value.
1534 while (WMNextHashEnumeratorItemAndKey(&e
, (void**)&item
, (void**)&key
)) {
1535 WMHashInsert(ret
->d
.dict
, WMDeepCopyPropList(key
),
1536 WMDeepCopyPropList(item
));
1540 wwarning(_("Used proplist functions on non-WMPropLists objects"));
1541 wassertrv(False
, NULL
);
1550 WMCreatePropListFromDescription(char *desc
)
1552 WMPropList
*plist
= NULL
;
1555 pldata
= (PLData
*) wmalloc(sizeof(PLData
));
1556 memset(pldata
, 0, sizeof(PLData
));
1558 pldata
->lineNumber
= 1;
1560 plist
= getPropList(pldata
);
1562 if (getNonSpaceChar(pldata
)!=0 && plist
) {
1563 COMPLAIN(pldata
, _("extra data after end of property list"));
1565 * We can't just ignore garbage after the end of the description
1566 * (especially if the description was read from a file), because
1567 * the "garbage" can be the real data and the real garbage is in
1568 * fact in the beginning of the file (which is now inside plist)
1570 WMReleasePropList(plist
);
1581 WMGetPropListDescription(WMPropList
*plist
, Bool indented
)
1583 return (indented
? indentedDescription(plist
, 0) : description(plist
));
1588 WMReadPropListFromFile(char *file
)
1590 WMPropList
*plist
= NULL
;
1596 f
= fopen(file
, "rb");
1598 /* let the user print the error message if he really needs to */
1599 /*wsyserror(_("could not open domain file '%s' for reading"), file);*/
1603 if (stat(file
, &stbuf
)==0) {
1604 length
= (size_t) stbuf
.st_size
;
1606 wsyserror(_("could not get size for file '%s'"), file
);
1611 pldata
= (PLData
*) wmalloc(sizeof(PLData
));
1612 memset(pldata
, 0, sizeof(PLData
));
1613 pldata
->ptr
= (char*) wmalloc(length
+1);
1614 pldata
->filename
= file
;
1615 pldata
->lineNumber
= 1;
1617 if (fread(pldata
->ptr
, length
, 1, f
) != 1) {
1618 wsyserror(_("error reading from file '%s'"), file
);
1623 pldata
->ptr
[length
] = 0;
1625 plist
= getPropList(pldata
);
1627 if (getNonSpaceChar(pldata
)!=0 && plist
) {
1628 COMPLAIN(pldata
, _("extra data after end of property list"));
1630 * We can't just ignore garbage after the end of the description
1631 * (especially if the description was read from a file), because
1632 * the "garbage" can be the real data and the real garbage is in
1633 * fact in the beginning of the file (which is now inside plist)
1635 WMReleasePropList(plist
);
1648 /* TODO: review this function's code */
1651 WMWritePropListToFile(WMPropList
*plist
, char *path
, Bool atomically
)
1662 /* Use the path name of the destination file as a prefix for the
1663 * mkstemp() call so that we can be sure that both files are on
1664 * the same filesystem and the subsequent rename() will work. */
1665 thePath
= wstrconcat(path
, ".XXXXXX");
1668 if ((fd
= mkstemp(thePath
)) < 0) {
1669 wsyserror(_("mkstemp (%s) failed"), thePath
);
1674 fchmod(fd
, 0644 & ~mask
);
1675 if ((theFile
= fdopen(fd
, "wb")) == NULL
) {
1679 if (mktemp(thePath
) == NULL
) {
1680 wsyserror(_("mktemp (%s) failed"), thePath
);
1683 theFile
= fopen(thePath
, "wb");
1686 thePath
= wstrdup(path
);
1687 theFile
= fopen(thePath
, "wb");
1690 if (theFile
== NULL
) {
1691 wsyserror(_("open (%s) failed"), thePath
);
1695 desc
= indentedDescription(plist
, 0);
1697 if (fprintf(theFile
, "%s\n", desc
) != strlen(desc
)+1) {
1698 wsyserror(_("writing to file: %s failed"), thePath
);
1705 if (fclose(theFile
) != 0) {
1706 wsyserror(_("fclose (%s) failed"), thePath
);
1710 /* If we used a temporary file, we still need to rename() it be the
1711 * real file. Also, we need to try to retain the file attributes of
1712 * the original file we are overwriting (if we are) */
1714 if (rename(thePath
, path
) != 0) {
1715 wsyserror(_("rename ('%s' to '%s') failed"), thePath
, path
);