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"));
703 WMAppendDataBytes(data
, buf
, len
);
705 plist
= WMCreatePLData(data
);
713 getPLArray(PLData
*pldata
)
718 WMPropList
*array
, *obj
;
720 array
= WMCreatePLArray(NULL
);
723 c
= getNonSpaceChar(pldata
);
725 COMPLAIN(pldata
, _("unterminated PropList array"));
728 } else if (c
== ')') {
730 } else if (c
== ',') {
731 /* continue normally */
733 COMPLAIN(pldata
, _("missing or unterminated PropList array"));
741 obj
= getPropList(pldata
);
743 COMPLAIN(pldata
, _("could not get PropList array element"));
747 WMAddToPLArray(array
, obj
);
748 WMReleasePropList(obj
);
752 WMReleasePropList(array
);
761 getPLDictionary(PLData
*pldata
)
765 WMPropList
*dict
, *key
, *value
;
767 dict
= WMCreatePLDictionary(NULL
, NULL
);
770 c
= getNonSpaceChar(pldata
);
772 COMPLAIN(pldata
, _("unterminated PropList dictionary"));
779 DPUT("getting PropList dictionary key");
781 key
= getPLData(pldata
);
782 } else if (c
== '"') {
783 key
= getPLQString(pldata
);
784 } else if (ISSTRINGABLE(c
)) {
786 key
= getPLString(pldata
);
789 COMPLAIN(pldata
, _("missing PropList dictionary key"));
791 COMPLAIN(pldata
, _("missing PropList dictionary entry key "
792 "or unterminated dictionary"));
799 COMPLAIN(pldata
, _("error parsing PropList dictionary key"));
804 c
= getNonSpaceChar(pldata
);
806 WMReleasePropList(key
);
807 COMPLAIN(pldata
, _("missing = in PropList dictionary entry"));
812 DPUT("getting PropList dictionary entry value for key");
813 value
= getPropList(pldata
);
815 COMPLAIN(pldata
, _("error parsing PropList dictionary entry value"));
816 WMReleasePropList(key
);
821 c
= getNonSpaceChar(pldata
);
823 COMPLAIN(pldata
, _("missing ; in PropList dictionary entry"));
824 WMReleasePropList(key
);
825 WMReleasePropList(value
);
830 WMPutInPLDictionary(dict
, key
, value
);
831 WMReleasePropList(key
);
832 WMReleasePropList(value
);
836 WMReleasePropList(dict
);
845 getPropList(PLData
*pldata
)
850 c
= getNonSpaceChar(pldata
);
854 DPUT("End of PropList");
859 DPUT("Getting PropList dictionary");
860 plist
= getPLDictionary(pldata
);
864 DPUT("Getting PropList srrsy");
865 plist
= getPLArray(pldata
);
869 DPUT("Getting PropList data");
870 plist
= getPLData(pldata
);
874 DPUT("Getting PropList quoted string");
875 plist
= getPLQString(pldata
);
879 if (ISSTRINGABLE(c
)) {
880 DPUT("Getting PropList string");
882 plist
= getPLString(pldata
);
884 COMPLAIN(pldata
, _("was expecting a string, data, array or "
885 "dictionary. If it's a string, try enclosing "
887 if (c
=='#' || c
=='/') {
888 wwarning(_("Comments are not allowed inside WindowMaker owned"
901 WMPLSetCaseSensitive(Bool caseSensitiveness
)
903 caseSensitive
= caseSensitiveness
;
908 WMCreatePLString(char *str
)
912 wassertrv(str
!=NULL
, NULL
);
914 plist
= (WMPropList
*)wmalloc(sizeof(W_PropList
));
916 plist
->type
= WPLString
;
917 plist
->d
.string
= wstrdup(str
);
918 plist
->retainCount
= 1;
925 WMCreatePLData(WMData
*data
)
929 wassertrv(data
!=NULL
, NULL
);
931 plist
= (WMPropList
*)wmalloc(sizeof(W_PropList
));
933 plist
->type
= WPLData
;
934 plist
->d
.data
= WMRetainData(data
);
935 plist
->retainCount
= 1;
942 WMCreatePLDataWithBytes(unsigned char *bytes
, unsigned int length
)
946 wassertrv(bytes
!=NULL
, NULL
);
948 plist
= (WMPropList
*)wmalloc(sizeof(W_PropList
));
950 plist
->type
= WPLData
;
951 plist
->d
.data
= WMCreateDataWithBytes(bytes
, length
);
952 plist
->retainCount
= 1;
959 WMCreatePLDataWithBytesNoCopy(unsigned char *bytes
, unsigned int length
,
960 WMFreeDataProc
*destructor
)
964 wassertrv(bytes
!=NULL
, NULL
);
966 plist
= (WMPropList
*)wmalloc(sizeof(W_PropList
));
968 plist
->type
= WPLData
;
969 plist
->d
.data
= WMCreateDataWithBytesNoCopy(bytes
, length
, destructor
);
970 plist
->retainCount
= 1;
977 WMCreatePLArray(WMPropList
*elem
, ...)
979 WMPropList
*plist
, *nelem
;
982 plist
= (WMPropList
*)wmalloc(sizeof(W_PropList
));
983 plist
->type
= WPLArray
;
984 plist
->d
.array
= WMCreateArray(4);
985 plist
->retainCount
= 1;
990 WMAddToArray(plist
->d
.array
, WMRetainPropList(elem
));
995 nelem
= va_arg(ap
, WMPropList
*);
1000 WMAddToArray(plist
->d
.array
, WMRetainPropList(nelem
));
1006 WMCreatePLDictionary(WMPropList
*key
, WMPropList
*value
, ...)
1008 WMPropList
*plist
, *nkey
, *nvalue
, *k
, *v
;
1011 plist
= (WMPropList
*)wmalloc(sizeof(W_PropList
));
1012 plist
->type
= WPLDictionary
;
1013 plist
->d
.dict
= WMCreateHashTable(WMPropListHashCallbacks
);
1014 plist
->retainCount
= 1;
1019 WMHashInsert(plist
->d
.dict
, WMRetainPropList(key
), WMRetainPropList(value
));
1021 va_start(ap
, value
);
1024 nkey
= va_arg(ap
, WMPropList
*);
1029 nvalue
= va_arg(ap
, WMPropList
*);
1034 if (WMHashGetItemAndKey(plist
->d
.dict
, nkey
, (void**)&v
, (void**)&k
)) {
1035 WMHashRemove(plist
->d
.dict
, k
);
1036 WMReleasePropList(k
);
1037 WMReleasePropList(v
);
1039 WMHashInsert(plist
->d
.dict
, WMRetainPropList(nkey
),
1040 WMRetainPropList(nvalue
));
1046 WMRetainPropList(WMPropList
*plist
)
1048 WMPropList
*key
, *value
;
1052 plist
->retainCount
++;
1054 switch(plist
->type
) {
1059 for (i
=0; i
<WMGetArrayItemCount(plist
->d
.array
); i
++) {
1060 WMRetainPropList(WMGetFromArray(plist
->d
.array
, i
));
1064 e
= WMEnumerateHashTable(plist
->d
.dict
);
1065 while (WMNextHashEnumeratorItemAndKey(&e
, (void**)&value
, (void**)&key
)) {
1066 WMRetainPropList(key
);
1067 WMRetainPropList(value
);
1071 wwarning(_("Used proplist functions on non-WMPropLists objects"));
1072 wassertrv(False
, NULL
);
1081 WMReleasePropList(WMPropList
*plist
)
1083 WMPropList
*key
, *value
;
1087 plist
->retainCount
--;
1089 switch(plist
->type
) {
1091 if (plist
->retainCount
< 1) {
1092 wfree(plist
->d
.string
);
1097 if (plist
->retainCount
< 1) {
1098 WMReleaseData(plist
->d
.data
);
1103 for (i
=0; i
<WMGetArrayItemCount(plist
->d
.array
); i
++) {
1104 WMReleasePropList(WMGetFromArray(plist
->d
.array
, i
));
1106 if (plist
->retainCount
< 1) {
1107 WMFreeArray(plist
->d
.array
);
1112 e
= WMEnumerateHashTable(plist
->d
.dict
);
1113 while (WMNextHashEnumeratorItemAndKey(&e
, (void**)&value
, (void**)&key
)) {
1114 WMReleasePropList(key
);
1115 WMReleasePropList(value
);
1117 if (plist
->retainCount
< 1) {
1118 WMFreeHashTable(plist
->d
.dict
);
1123 wwarning(_("Used proplist functions on non-WMPropLists objects"));
1131 WMInsertInPLArray(WMPropList
*plist
, int index
, WMPropList
*item
)
1133 wassertr(plist
->type
==WPLArray
);
1135 retainPropListByCount(item
, plist
->retainCount
);
1136 WMInsertInArray(plist
->d
.array
, index
, item
);
1141 WMAddToPLArray(WMPropList
*plist
, WMPropList
*item
)
1143 wassertr(plist
->type
==WPLArray
);
1145 retainPropListByCount(item
, plist
->retainCount
);
1146 WMAddToArray(plist
->d
.array
, item
);
1151 WMDeleteFromPLArray(WMPropList
*plist
, int index
)
1155 wassertr(plist
->type
==WPLArray
);
1157 item
= WMGetFromArray(plist
->d
.array
, index
);
1159 WMDeleteFromArray(plist
->d
.array
, index
);
1160 releasePropListByCount(item
, plist
->retainCount
);
1166 WMRemoveFromPLArray(WMPropList
*plist
, WMPropList
*item
)
1171 wassertr(plist
->type
==WPLArray
);
1173 for (i
=0; i
<WMGetArrayItemCount(plist
->d
.array
); i
++) {
1174 iPtr
= WMGetFromArray(plist
->d
.array
, i
);
1175 if (WMIsPropListEqualTo(item
, iPtr
)) {
1176 WMDeleteFromArray(plist
->d
.array
, i
);
1177 releasePropListByCount(iPtr
, plist
->retainCount
);
1185 WMPutInPLDictionary(WMPropList
*plist
, WMPropList
*key
, WMPropList
*value
)
1187 wassertr(plist
->type
==WPLDictionary
);
1189 /*WMRetainPropList(key);*/
1190 WMRemoveFromPLDictionary(plist
, key
);
1191 retainPropListByCount(key
, plist
->retainCount
);
1192 retainPropListByCount(value
, plist
->retainCount
);
1193 WMHashInsert(plist
->d
.dict
, key
, value
);
1194 /*WMReleasePropList(key);*/
1199 WMRemoveFromPLDictionary(WMPropList
*plist
, WMPropList
*key
)
1203 wassertr(plist
->type
==WPLDictionary
);
1205 if (WMHashGetItemAndKey(plist
->d
.dict
, key
, (void**)&v
, (void**)&k
)) {
1206 WMHashRemove(plist
->d
.dict
, k
);
1207 releasePropListByCount(k
, plist
->retainCount
);
1208 releasePropListByCount(v
, plist
->retainCount
);
1214 WMMergePLDictionaries(WMPropList
*dest
, WMPropList
*source
, Bool recursive
)
1216 WMPropList
*key
, *value
, *dvalue
;
1219 wassertr(source
->type
==WPLDictionary
&& dest
->type
==WPLDictionary
);
1224 e
= WMEnumerateHashTable(source
->d
.dict
);
1225 while (WMNextHashEnumeratorItemAndKey(&e
, (void**)&value
, (void**)&key
)) {
1226 if (recursive
&& value
->type
==WPLDictionary
) {
1227 dvalue
= WMHashGet(dest
->d
.dict
, key
);
1228 if (dvalue
&& dvalue
->type
==WPLDictionary
) {
1229 WMMergePLDictionaries(dvalue
, value
, True
);
1231 WMPutInPLDictionary(dest
, key
, value
);
1234 WMPutInPLDictionary(dest
, key
, value
);
1243 WMSubtractPLDictionaries(WMPropList
*dest
, WMPropList
*source
, Bool recursive
)
1245 WMPropList
*key
, *value
, *dvalue
;
1248 wassertr(source
->type
==WPLDictionary
&& dest
->type
==WPLDictionary
);
1250 if (source
== dest
) {
1251 WMPropList
*keys
= WMGetPLDictionaryKeys(dest
);
1254 for (i
=0; i
<WMGetArrayItemCount(keys
->d
.array
); i
++) {
1255 WMRemoveFromPLDictionary(dest
, WMGetFromArray(keys
->d
.array
, i
));
1260 e
= WMEnumerateHashTable(source
->d
.dict
);
1261 while (WMNextHashEnumeratorItemAndKey(&e
, (void**)&value
, (void**)&key
)) {
1262 dvalue
= WMHashGet(dest
->d
.dict
, key
);
1265 if (WMIsPropListEqualTo(value
, dvalue
)) {
1266 WMRemoveFromPLDictionary(dest
, key
);
1267 } else if (recursive
&& value
->type
==WPLDictionary
&&
1268 dvalue
->type
==WPLDictionary
) {
1269 WMSubtractPLDictionaries(dvalue
, value
, True
);
1278 WMGetPropListItemCount(WMPropList
*plist
)
1280 switch(plist
->type
) {
1283 return 0; /* should this be 1 instead? */
1285 return WMGetArrayItemCount(plist
->d
.array
);
1287 return (int)WMCountHashTable(plist
->d
.dict
);
1289 wwarning(_("Used proplist functions on non-WMPropLists objects"));
1290 wassertrv(False
, 0);
1299 WMIsPLString(WMPropList
*plist
)
1301 return (plist
->type
== WPLString
);
1306 WMIsPLData(WMPropList
*plist
)
1308 return (plist
->type
== WPLData
);
1313 WMIsPLArray(WMPropList
*plist
)
1315 return (plist
->type
== WPLArray
);
1320 WMIsPLDictionary(WMPropList
*plist
)
1322 return (plist
->type
== WPLDictionary
);
1327 WMIsPropListEqualTo(WMPropList
*plist
, WMPropList
*other
)
1329 WMPropList
*key1
, *item1
, *item2
;
1330 WMHashEnumerator enumerator
;
1333 if (plist
->type
!= other
->type
)
1336 switch(plist
->type
) {
1338 if (caseSensitive
) {
1339 return (strcmp(plist
->d
.string
, other
->d
.string
) == 0);
1341 return (strcasecmp(plist
->d
.string
, other
->d
.string
) == 0);
1344 return WMIsDataEqualToData(plist
->d
.data
, other
->d
.data
);
1346 n
= WMGetArrayItemCount(plist
->d
.array
);
1347 if (n
!= WMGetArrayItemCount(other
->d
.array
))
1349 for (i
=0; i
<n
; i
++) {
1350 item1
= WMGetFromArray(plist
->d
.array
, i
);
1351 item2
= WMGetFromArray(other
->d
.array
, i
);
1352 if (!WMIsPropListEqualTo(item1
, item2
))
1357 if (WMCountHashTable(plist
->d
.dict
) != WMCountHashTable(other
->d
.dict
))
1359 enumerator
= WMEnumerateHashTable(plist
->d
.dict
);
1360 while (WMNextHashEnumeratorItemAndKey(&enumerator
, (void**)&item1
,
1362 item2
= WMHashGet(other
->d
.dict
, key1
);
1363 if (!item2
|| !item1
|| !WMIsPropListEqualTo(item1
, item2
))
1368 wwarning(_("Used proplist functions on non-WMPropLists objects"));
1369 wassertrv(False
, False
);
1378 WMGetFromPLString(WMPropList
*plist
)
1380 wassertrv(plist
->type
==WPLString
, NULL
);
1382 return plist
->d
.string
;
1387 WMGetFromPLData(WMPropList
*plist
)
1389 wassertrv(plist
->type
==WPLData
, NULL
);
1391 return plist
->d
.data
;
1395 const unsigned char*
1396 WMGetPLDataBytes(WMPropList
*plist
)
1398 wassertrv(plist
->type
==WPLData
, NULL
);
1400 return WMDataBytes(plist
->d
.data
);
1405 WMGetPLDataLength(WMPropList
*plist
)
1407 wassertrv(plist
->type
==WPLData
, 0);
1409 return WMGetDataLength(plist
->d
.data
);
1414 WMGetFromPLArray(WMPropList
*plist
, int index
)
1416 wassertrv(plist
->type
==WPLArray
, NULL
);
1418 return WMGetFromArray(plist
->d
.array
, index
);
1423 WMGetFromPLDictionary(WMPropList
*plist
, WMPropList
*key
)
1425 wassertrv(plist
->type
==WPLDictionary
, NULL
);
1427 return WMHashGet(plist
->d
.dict
, key
);
1432 WMGetPLDictionaryKeys(WMPropList
*plist
)
1434 WMPropList
*array
, *key
;
1435 WMHashEnumerator enumerator
;
1437 wassertrv(plist
->type
==WPLDictionary
, NULL
);
1439 array
= (WMPropList
*)wmalloc(sizeof(W_PropList
));
1440 array
->type
= WPLArray
;
1441 array
->d
.array
= WMCreateArray(WMCountHashTable(plist
->d
.dict
));
1442 array
->retainCount
= 1;
1444 enumerator
= WMEnumerateHashTable(plist
->d
.dict
);
1445 while ((key
= WMNextHashEnumeratorKey(&enumerator
))) {
1446 WMAddToArray(array
->d
.array
, WMRetainPropList(key
));
1454 WMShallowCopyPropList(WMPropList
*plist
)
1456 WMPropList
*ret
= NULL
;
1457 WMPropList
*key
, *item
;
1462 switch(plist
->type
) {
1464 ret
= WMCreatePLString(plist
->d
.string
);
1467 data
= WMCreateDataWithData(plist
->d
.data
);
1468 ret
= WMCreatePLData(data
);
1469 WMReleaseData(data
);
1472 ret
= (WMPropList
*)wmalloc(sizeof(W_PropList
));
1473 ret
->type
= WPLArray
;
1474 ret
->d
.array
= WMCreateArrayWithArray(plist
->d
.array
);
1475 ret
->retainCount
= 1;
1477 for(i
=0; i
<WMGetArrayItemCount(ret
->d
.array
); i
++)
1478 WMRetainPropList(WMGetFromArray(ret
->d
.array
, i
));
1482 ret
= WMCreatePLDictionary(NULL
, NULL
);
1483 e
= WMEnumerateHashTable(plist
->d
.dict
);
1484 while (WMNextHashEnumeratorItemAndKey(&e
, (void**)&item
, (void**)&key
)) {
1485 WMPutInPLDictionary(ret
, key
, item
);
1489 wwarning(_("Used proplist functions on non-WMPropLists objects"));
1490 wassertrv(False
, NULL
);
1499 WMDeepCopyPropList(WMPropList
*plist
)
1501 WMPropList
*ret
= NULL
;
1502 WMPropList
*key
, *item
;
1507 switch(plist
->type
) {
1509 ret
= WMCreatePLString(plist
->d
.string
);
1512 data
= WMCreateDataWithData(plist
->d
.data
);
1513 ret
= WMCreatePLData(data
);
1514 WMReleaseData(data
);
1517 ret
= WMCreatePLArray(NULL
);
1518 for(i
=0; i
<WMGetArrayItemCount(plist
->d
.array
); i
++) {
1519 item
= WMDeepCopyPropList(WMGetFromArray(plist
->d
.array
, i
));
1520 WMAddToArray(ret
->d
.array
, item
);
1524 ret
= WMCreatePLDictionary(NULL
, NULL
);
1525 e
= WMEnumerateHashTable(plist
->d
.dict
);
1526 /* While we copy an existing dictionary there is no way that we can
1527 * have duplicate keys, so we don't need to first remove a key/value
1528 * pair before inserting the new key/value.
1530 while (WMNextHashEnumeratorItemAndKey(&e
, (void**)&item
, (void**)&key
)) {
1531 WMHashInsert(ret
->d
.dict
, WMDeepCopyPropList(key
),
1532 WMDeepCopyPropList(item
));
1536 wwarning(_("Used proplist functions on non-WMPropLists objects"));
1537 wassertrv(False
, NULL
);
1546 WMCreatePropListFromDescription(char *desc
)
1548 WMPropList
*plist
= NULL
;
1551 pldata
= (PLData
*) wmalloc(sizeof(PLData
));
1552 memset(pldata
, 0, sizeof(PLData
));
1554 pldata
->lineNumber
= 1;
1556 plist
= getPropList(pldata
);
1558 if (getNonSpaceChar(pldata
)!=0 && plist
) {
1559 COMPLAIN(pldata
, _("extra data after end of property list"));
1561 * We can't just ignore garbage after the end of the description
1562 * (especially if the description was read from a file), because
1563 * the "garbage" can be the real data and the real garbage is in
1564 * fact in the beginning of the file (which is now inside plist)
1566 WMReleasePropList(plist
);
1577 WMGetPropListDescription(WMPropList
*plist
, Bool indented
)
1579 return (indented
? indentedDescription(plist
, 0) : description(plist
));
1584 WMReadPropListFromFile(char *file
)
1586 WMPropList
*plist
= NULL
;
1592 f
= fopen(file
, "r");
1594 /* let the user print the error message if he really needs to */
1595 /*wsyserror(_("could not open domain file '%s' for reading"), file);*/
1599 if (stat(file
, &stbuf
)==0) {
1600 length
= (size_t) stbuf
.st_size
;
1602 wsyserror(_("could not get size for file '%s'"), file
);
1607 pldata
= (PLData
*) wmalloc(sizeof(PLData
));
1608 memset(pldata
, 0, sizeof(PLData
));
1609 pldata
->ptr
= (char*) wmalloc(length
+1);
1610 pldata
->filename
= file
;
1611 pldata
->lineNumber
= 1;
1613 if (fread(pldata
->ptr
, length
, 1, f
) != 1) {
1614 wsyserror(_("error reading from file '%s'"), file
);
1619 pldata
->ptr
[length
] = 0;
1621 plist
= getPropList(pldata
);
1623 if (getNonSpaceChar(pldata
)!=0 && plist
) {
1624 COMPLAIN(pldata
, _("extra data after end of property list"));
1626 * We can't just ignore garbage after the end of the description
1627 * (especially if the description was read from a file), because
1628 * the "garbage" can be the real data and the real garbage is in
1629 * fact in the beginning of the file (which is now inside plist)
1631 WMReleasePropList(plist
);
1644 /* TODO: review this function's code */
1647 WMWritePropListToFile(WMPropList
*plist
, char *path
, Bool atomically
)
1658 /* Use the path name of the destination file as a prefix for the
1659 * mkstemp() call so that we can be sure that both files are on
1660 * the same filesystem and the subsequent rename() will work. */
1661 thePath
= wstrconcat(path
, ".XXXXXX");
1664 if ((fd
= mkstemp(thePath
)) < 0) {
1665 wsyserror(_("mkstemp (%s) failed"), thePath
);
1670 fchmod(fd
, 0644 & ~mask
);
1671 if ((theFile
= fdopen(fd
, "w")) == NULL
) {
1675 if (mktemp(thePath
) == NULL
) {
1676 wsyserror(_("mktemp (%s) failed"), thePath
);
1679 theFile
= fopen(thePath
, "wb");
1682 thePath
= wstrdup(path
);
1683 theFile
= fopen(thePath
, "wb");
1686 if (theFile
== NULL
) {
1687 wsyserror(_("open (%s) failed"), thePath
);
1691 desc
= indentedDescription(plist
, 0);
1693 if (fprintf(theFile
, "%s\n", desc
) != strlen(desc
)+1) {
1694 wsyserror(_("writing to file: %s failed"), thePath
);
1701 if (fclose(theFile
) != 0) {
1702 wsyserror(_("fclose (%s) failed"), thePath
);
1706 /* If we used a temporary file, we still need to rename() it be the
1707 * real file. Also, we need to try to retain the file attributes of
1708 * the original file we are overwriting (if we are) */
1710 if (rename(thePath
, path
) != 0) {
1711 wsyserror(_("rename ('%s' to '%s') failed"), thePath
, path
);