18 WPLString
= 0x57504c01,
20 WPLArray
= 0x57504c03,
21 WPLDictionary
= 0x57504c04
24 typedef struct W_PropList
{
37 typedef struct PLData
{
44 typedef struct StringBuffer
{
49 static unsigned hashPropList(WMPropList
* plist
);
50 static WMPropList
*getPLString(PLData
* pldata
);
51 static WMPropList
*getPLQString(PLData
* pldata
);
52 static WMPropList
*getPLData(PLData
* pldata
);
53 static WMPropList
*getPLArray(PLData
* pldata
);
54 static WMPropList
*getPLDictionary(PLData
* pldata
);
55 static WMPropList
*getPropList(PLData
* pldata
);
57 typedef unsigned (*hashFunc
) (const void *);
58 typedef Bool(*isEqualFunc
) (const void *, const void *);
59 typedef void *(*retainFunc
) (const void *);
60 typedef void (*releaseFunc
) (const void *);
62 static const WMHashTableCallbacks WMPropListHashCallbacks
= {
63 (hashFunc
) hashPropList
,
64 (isEqualFunc
) WMIsPropListEqualTo
,
69 static Bool caseSensitive
= True
;
71 #define BUFFERSIZE 8192
72 #define BUFFERSIZE_INCREMENT 1024
75 # define DPUT(s) puts(s)
80 #define COMPLAIN(pld, msg) wwarning(_("syntax error in %s %s, line %i: %s"),\
81 (pld)->filename ? "file" : "PropList",\
82 (pld)->filename ? (pld)->filename : "description",\
83 (pld)->lineNumber, msg)
85 #define ISSTRINGABLE(c) (isalnum(c) || (c)=='.' || (c)=='_' || (c)=='/' \
88 #define CHECK_BUFFER_SIZE(buf, ptr) \
89 if ((ptr) >= (buf).size-1) {\
90 (buf).size += BUFFERSIZE_INCREMENT;\
91 (buf).str = wrealloc((buf).str, (buf).size);\
94 #define inrange(ch, min, max) ((ch)>=(min) && (ch)<=(max))
95 #define noquote(ch) (inrange(ch, 'a', 'z') || inrange(ch, 'A', 'Z') || inrange(ch, '0', '9') || ((ch)=='_') || ((ch)=='.') || ((ch)=='$'))
96 #define charesc(ch) (inrange(ch, 0x07, 0x0c) || ((ch)=='"') || ((ch)=='\\'))
97 #define numesc(ch) (((ch)<=0x06) || inrange(ch, 0x0d, 0x1f) || ((ch)>0x7e))
98 #define ishexdigit(ch) (inrange(ch, 'a', 'f') || inrange(ch, 'A', 'F') || inrange(ch, '0', '9'))
99 #define char2num(ch) (inrange(ch,'0','9') ? ((ch)-'0') : (inrange(ch,'a','f') ? ((ch)-0x57) : ((ch)-0x37)))
100 #define num2char(num) ((num) < 0xa ? ((num)+'0') : ((num)+0x57))
102 #define MaxHashLength 64
104 static unsigned hashPropList(WMPropList
* plist
)
111 switch (plist
->type
) {
113 key
= plist
->d
.string
;
114 len
= WMIN(strlen(key
), MaxHashLength
);
115 for (i
= 0; i
< len
; i
++) {
116 ret
^= tolower(key
[i
]) << ctr
;
117 ctr
= (ctr
+ 1) % sizeof(char *);
120 ret ^= tolower(*key++) << ctr;
121 ctr = (ctr + 1) % sizeof (char *);
126 key
= WMDataBytes(plist
->d
.data
);
127 len
= WMIN(WMGetDataLength(plist
->d
.data
), MaxHashLength
);
128 for (i
= 0; i
< len
; i
++) {
129 ret
^= key
[i
] << ctr
;
130 ctr
= (ctr
+ 1) % sizeof(char *);
135 wwarning(_("Only string or data is supported for a proplist dictionary key"));
143 static WMPropList
*retainPropListByCount(WMPropList
* plist
, int count
)
145 WMPropList
*key
, *value
;
149 plist
->retainCount
+= count
;
151 switch (plist
->type
) {
156 for (i
= 0; i
< WMGetArrayItemCount(plist
->d
.array
); i
++) {
157 retainPropListByCount(WMGetFromArray(plist
->d
.array
, i
), count
);
161 e
= WMEnumerateHashTable(plist
->d
.dict
);
162 while (WMNextHashEnumeratorItemAndKey(&e
, (void **)&value
, (void **)&key
)) {
163 retainPropListByCount(key
, count
);
164 retainPropListByCount(value
, count
);
168 wwarning(_("Used proplist functions on non-WMPropLists objects"));
169 wassertrv(False
, NULL
);
176 static void releasePropListByCount(WMPropList
* plist
, int count
)
178 WMPropList
*key
, *value
;
182 plist
->retainCount
-= count
;
184 switch (plist
->type
) {
186 if (plist
->retainCount
< 1) {
187 wfree(plist
->d
.string
);
192 if (plist
->retainCount
< 1) {
193 WMReleaseData(plist
->d
.data
);
198 for (i
= 0; i
< WMGetArrayItemCount(plist
->d
.array
); i
++) {
199 releasePropListByCount(WMGetFromArray(plist
->d
.array
, i
), count
);
201 if (plist
->retainCount
< 1) {
202 WMFreeArray(plist
->d
.array
);
207 e
= WMEnumerateHashTable(plist
->d
.dict
);
208 while (WMNextHashEnumeratorItemAndKey(&e
, (void **)&value
, (void **)&key
)) {
209 releasePropListByCount(key
, count
);
210 releasePropListByCount(value
, count
);
212 if (plist
->retainCount
< 1) {
213 WMFreeHashTable(plist
->d
.dict
);
218 wwarning(_("Used proplist functions on non-WMPropLists objects"));
224 static char *dataDescription(WMPropList
* plist
)
226 const unsigned char *data
;
230 data
= WMDataBytes(plist
->d
.data
);
231 length
= WMGetDataLength(plist
->d
.data
);
233 retVal
= (char *)wmalloc(2 * length
+ length
/ 4 + 3);
236 for (i
= 0, j
= 1; i
< length
; i
++) {
237 retVal
[j
++] = num2char((data
[i
] >> 4) & 0x0f);
238 retVal
[j
++] = num2char(data
[i
] & 0x0f);
239 if ((i
& 0x03) == 3 && i
!= length
- 1) {
240 /* if we've just finished a 32-bit int, add a space */
250 static char *stringDescription(WMPropList
* plist
)
253 char *retVal
, *sPtr
, *dPtr
;
257 str
= plist
->d
.string
;
259 if (strlen(str
) == 0) {
260 return wstrdup("\"\"");
263 /* FIXME: make this work with unichars. */
268 while ((ch
= *sPtr
)) {
283 retVal
= (char *)wmalloc(len
+ 1);
291 while ((ch
= *sPtr
)) {
314 *dPtr
= ch
; /* " or \ */
316 } else if (numesc(ch
)) {
318 *(dPtr
++) = '0' + ((ch
>> 6) & 07);
319 *(dPtr
++) = '0' + ((ch
>> 3) & 07);
320 *dPtr
= '0' + (ch
& 07);
336 static char *description(WMPropList
* plist
)
338 WMPropList
*key
, *val
;
340 char *str
, *tmp
, *skey
, *sval
;
344 switch (plist
->type
) {
346 retstr
= stringDescription(plist
);
349 retstr
= dataDescription(plist
);
352 retstr
= wstrdup("(");
353 for (i
= 0; i
< WMGetArrayItemCount(plist
->d
.array
); i
++) {
354 str
= description(WMGetFromArray(plist
->d
.array
, i
));
356 retstr
= wstrappend(retstr
, str
);
358 tmp
= (char *)wmalloc(strlen(retstr
) + strlen(str
) + 3);
359 sprintf(tmp
, "%s, %s", retstr
, str
);
365 retstr
= wstrappend(retstr
, ")");
368 retstr
= wstrdup("{");
369 e
= WMEnumerateHashTable(plist
->d
.dict
);
370 while (WMNextHashEnumeratorItemAndKey(&e
, (void **)&val
, (void **)&key
)) {
371 skey
= description(key
);
372 sval
= description(val
);
373 tmp
= (char *)wmalloc(strlen(retstr
) + strlen(skey
) + strlen(sval
) + 5);
374 sprintf(tmp
, "%s%s = %s;", retstr
, skey
, sval
);
380 retstr
= wstrappend(retstr
, "}");
383 wwarning(_("Used proplist functions on non-WMPropLists objects"));
384 wassertrv(False
, NULL
);
391 static char *indentedDescription(WMPropList
* plist
, int level
)
393 WMPropList
*key
, *val
;
395 char *str
, *tmp
, *skey
, *sval
;
399 if (plist
->type
== WPLArray
/* || plist->type==WPLDictionary */ ) {
400 retstr
= description(plist
);
402 if (retstr
&& ((2 * (level
+ 1) + strlen(retstr
)) <= 77)) {
410 switch (plist
->type
) {
412 retstr
= stringDescription(plist
);
415 retstr
= dataDescription(plist
);
418 retstr
= wstrdup("(\n");
419 for (i
= 0; i
< WMGetArrayItemCount(plist
->d
.array
); i
++) {
420 str
= indentedDescription(WMGetFromArray(plist
->d
.array
, i
), level
+ 1);
422 tmp
= (char *)wmalloc(2 * (level
+ 1) + strlen(retstr
) + strlen(str
) + 1);
423 sprintf(tmp
, "%s%*s%s", retstr
, 2 * (level
+ 1), "", str
);
427 tmp
= (char *)wmalloc(2 * (level
+ 1) + strlen(retstr
) + strlen(str
) + 3);
428 sprintf(tmp
, "%s,\n%*s%s", retstr
, 2 * (level
+ 1), "", str
);
434 tmp
= (char *)wmalloc(strlen(retstr
) + 2 * level
+ 3);
435 sprintf(tmp
, "%s\n%*s)", retstr
, 2 * level
, "");
440 retstr
= wstrdup("{\n");
441 e
= WMEnumerateHashTable(plist
->d
.dict
);
442 while (WMNextHashEnumeratorItemAndKey(&e
, (void **)&val
, (void **)&key
)) {
443 skey
= indentedDescription(key
, level
+ 1);
444 sval
= indentedDescription(val
, level
+ 1);
445 tmp
= (char *)wmalloc(2 * (level
+ 1) + strlen(retstr
) + strlen(skey
)
447 sprintf(tmp
, "%s%*s%s = %s;\n", retstr
, 2 * (level
+ 1), "", skey
, sval
);
453 tmp
= (char *)wmalloc(strlen(retstr
) + 2 * level
+ 2);
454 sprintf(tmp
, "%s%*s}", retstr
, 2 * level
, "");
459 wwarning(_("Used proplist functions on non-WMPropLists objects"));
460 wassertrv(False
, NULL
);
467 static INLINE
int getChar(PLData
* pldata
)
471 c
= pldata
->ptr
[pldata
->pos
];
479 pldata
->lineNumber
++;
484 static INLINE
int getNonSpaceChar(PLData
* pldata
)
489 c
= pldata
->ptr
[pldata
->pos
];
495 pldata
->lineNumber
++;
496 } else if (!isspace(c
)) {
504 static char *unescapestr(char *src
)
506 char *dest
= wmalloc(strlen(src
) + 1);
510 for (sPtr
= src
, dPtr
= dest
; *sPtr
; sPtr
++, dPtr
++) {
515 if ((ch
>= '0') && (ch
<= '3')) {
516 /* assume next 2 chars are octal too */
517 *dPtr
= ((ch
& 07) << 6);
518 *dPtr
|= ((*(++sPtr
) & 07) << 3);
519 *dPtr
|= *(++sPtr
) & 07;
555 static WMPropList
*getPLString(PLData
* pldata
)
562 sBuf
.str
= wmalloc(BUFFERSIZE
);
563 sBuf
.size
= BUFFERSIZE
;
567 if (ISSTRINGABLE(c
)) {
568 CHECK_BUFFER_SIZE(sBuf
, ptr
);
583 char *tmp
= unescapestr(sBuf
.str
);
584 plist
= WMCreatePLString(tmp
);
593 static WMPropList
*getPLQString(PLData
* pldata
)
596 int ptr
= 0, escaping
= 0, ok
= 1;
600 sBuf
.str
= wmalloc(BUFFERSIZE
);
601 sBuf
.size
= BUFFERSIZE
;
609 } else if (c
== '"') {
613 CHECK_BUFFER_SIZE(sBuf
, ptr
);
614 sBuf
.str
[ptr
++] = '\\';
619 COMPLAIN(pldata
, _("unterminated PropList string"));
623 CHECK_BUFFER_SIZE(sBuf
, ptr
);
633 char *tmp
= unescapestr(sBuf
.str
);
634 plist
= WMCreatePLString(tmp
);
643 static WMPropList
*getPLData(PLData
* pldata
)
648 unsigned char buf
[BUFFERSIZE
], byte
;
652 data
= WMCreateDataWithCapacity(0);
655 c1
= getNonSpaceChar(pldata
);
657 COMPLAIN(pldata
, _("unterminated PropList data"));
660 } else if (c1
== '>') {
662 } else if (ishexdigit(c1
)) {
663 c2
= getNonSpaceChar(pldata
);
664 if (c2
== 0 || c2
== '>') {
665 COMPLAIN(pldata
, _("unterminated PropList data (missing hexdigit)"));
668 } else if (ishexdigit(c2
)) {
669 byte
= char2num(c1
) << 4;
670 byte
|= char2num(c2
);
672 if (len
== sizeof(buf
)) {
673 WMAppendDataBytes(data
, buf
, len
);
677 COMPLAIN(pldata
, _("non hexdigit character in PropList data"));
682 COMPLAIN(pldata
, _("non hexdigit character in PropList data"));
694 WMAppendDataBytes(data
, buf
, len
);
696 plist
= WMCreatePLData(data
);
702 static WMPropList
*getPLArray(PLData
* pldata
)
707 WMPropList
*array
, *obj
;
709 array
= WMCreatePLArray(NULL
);
712 c
= getNonSpaceChar(pldata
);
714 COMPLAIN(pldata
, _("unterminated PropList array"));
717 } else if (c
== ')') {
719 } else if (c
== ',') {
720 /* continue normally */
722 COMPLAIN(pldata
, _("missing or unterminated PropList array"));
730 obj
= getPropList(pldata
);
732 COMPLAIN(pldata
, _("could not get PropList array element"));
736 WMAddToPLArray(array
, obj
);
737 WMReleasePropList(obj
);
741 WMReleasePropList(array
);
748 static WMPropList
*getPLDictionary(PLData
* pldata
)
752 WMPropList
*dict
, *key
, *value
;
754 dict
= WMCreatePLDictionary(NULL
, NULL
);
757 c
= getNonSpaceChar(pldata
);
759 COMPLAIN(pldata
, _("unterminated PropList dictionary"));
762 } else if (c
== '}') {
766 DPUT("getting PropList dictionary key");
768 key
= getPLData(pldata
);
769 } else if (c
== '"') {
770 key
= getPLQString(pldata
);
771 } else if (ISSTRINGABLE(c
)) {
773 key
= getPLString(pldata
);
776 COMPLAIN(pldata
, _("missing PropList dictionary key"));
778 COMPLAIN(pldata
, _("missing PropList dictionary entry key "
779 "or unterminated dictionary"));
786 COMPLAIN(pldata
, _("error parsing PropList dictionary key"));
791 c
= getNonSpaceChar(pldata
);
793 WMReleasePropList(key
);
794 COMPLAIN(pldata
, _("missing = in PropList dictionary entry"));
799 DPUT("getting PropList dictionary entry value for key");
800 value
= getPropList(pldata
);
802 COMPLAIN(pldata
, _("error parsing PropList dictionary entry value"));
803 WMReleasePropList(key
);
808 c
= getNonSpaceChar(pldata
);
810 COMPLAIN(pldata
, _("missing ; in PropList dictionary entry"));
811 WMReleasePropList(key
);
812 WMReleasePropList(value
);
817 WMPutInPLDictionary(dict
, key
, value
);
818 WMReleasePropList(key
);
819 WMReleasePropList(value
);
823 WMReleasePropList(dict
);
830 static WMPropList
*getPropList(PLData
* pldata
)
835 c
= getNonSpaceChar(pldata
);
839 DPUT("End of PropList");
844 DPUT("Getting PropList dictionary");
845 plist
= getPLDictionary(pldata
);
849 DPUT("Getting PropList array");
850 plist
= getPLArray(pldata
);
854 DPUT("Getting PropList data");
855 plist
= getPLData(pldata
);
859 DPUT("Getting PropList quoted string");
860 plist
= getPLQString(pldata
);
864 if (ISSTRINGABLE(c
)) {
865 DPUT("Getting PropList string");
867 plist
= getPLString(pldata
);
869 COMPLAIN(pldata
, _("was expecting a string, data, array or "
870 "dictionary. If it's a string, try enclosing " "it with \"."));
871 if (c
== '#' || c
== '/') {
872 wwarning(_("Comments are not allowed inside WindowMaker owned" " domain files."));
882 void WMPLSetCaseSensitive(Bool caseSensitiveness
)
884 caseSensitive
= caseSensitiveness
;
887 WMPropList
*WMCreatePLString(char *str
)
891 wassertrv(str
!= NULL
, NULL
);
893 plist
= (WMPropList
*) wmalloc(sizeof(W_PropList
));
895 plist
->type
= WPLString
;
896 plist
->d
.string
= wstrdup(str
);
897 plist
->retainCount
= 1;
902 WMPropList
*WMCreatePLData(WMData
* data
)
906 wassertrv(data
!= NULL
, NULL
);
908 plist
= (WMPropList
*) wmalloc(sizeof(W_PropList
));
910 plist
->type
= WPLData
;
911 plist
->d
.data
= WMRetainData(data
);
912 plist
->retainCount
= 1;
917 WMPropList
*WMCreatePLDataWithBytes(unsigned char *bytes
, unsigned int length
)
921 wassertrv(bytes
!= NULL
, NULL
);
923 plist
= (WMPropList
*) wmalloc(sizeof(W_PropList
));
925 plist
->type
= WPLData
;
926 plist
->d
.data
= WMCreateDataWithBytes(bytes
, length
);
927 plist
->retainCount
= 1;
932 WMPropList
*WMCreatePLDataWithBytesNoCopy(unsigned char *bytes
, unsigned int length
, WMFreeDataProc
* destructor
)
936 wassertrv(bytes
!= NULL
, NULL
);
938 plist
= (WMPropList
*) wmalloc(sizeof(W_PropList
));
940 plist
->type
= WPLData
;
941 plist
->d
.data
= WMCreateDataWithBytesNoCopy(bytes
, length
, destructor
);
942 plist
->retainCount
= 1;
947 WMPropList
*WMCreatePLArray(WMPropList
* elem
, ...)
949 WMPropList
*plist
, *nelem
;
952 plist
= (WMPropList
*) wmalloc(sizeof(W_PropList
));
953 plist
->type
= WPLArray
;
954 plist
->d
.array
= WMCreateArray(4);
955 plist
->retainCount
= 1;
960 WMAddToArray(plist
->d
.array
, WMRetainPropList(elem
));
965 nelem
= va_arg(ap
, WMPropList
*);
970 WMAddToArray(plist
->d
.array
, WMRetainPropList(nelem
));
974 WMPropList
*WMCreatePLDictionary(WMPropList
* key
, WMPropList
* value
, ...)
976 WMPropList
*plist
, *nkey
, *nvalue
, *k
, *v
;
979 plist
= (WMPropList
*) wmalloc(sizeof(W_PropList
));
980 plist
->type
= WPLDictionary
;
981 plist
->d
.dict
= WMCreateHashTable(WMPropListHashCallbacks
);
982 plist
->retainCount
= 1;
987 WMHashInsert(plist
->d
.dict
, WMRetainPropList(key
), WMRetainPropList(value
));
992 nkey
= va_arg(ap
, WMPropList
*);
997 nvalue
= va_arg(ap
, WMPropList
*);
1002 if (WMHashGetItemAndKey(plist
->d
.dict
, nkey
, (void **)&v
, (void **)&k
)) {
1003 WMHashRemove(plist
->d
.dict
, k
);
1004 WMReleasePropList(k
);
1005 WMReleasePropList(v
);
1007 WMHashInsert(plist
->d
.dict
, WMRetainPropList(nkey
), WMRetainPropList(nvalue
));
1011 WMPropList
*WMRetainPropList(WMPropList
* plist
)
1013 WMPropList
*key
, *value
;
1017 plist
->retainCount
++;
1019 switch (plist
->type
) {
1024 for (i
= 0; i
< WMGetArrayItemCount(plist
->d
.array
); i
++) {
1025 WMRetainPropList(WMGetFromArray(plist
->d
.array
, i
));
1029 e
= WMEnumerateHashTable(plist
->d
.dict
);
1030 while (WMNextHashEnumeratorItemAndKey(&e
, (void **)&value
, (void **)&key
)) {
1031 WMRetainPropList(key
);
1032 WMRetainPropList(value
);
1036 wwarning(_("Used proplist functions on non-WMPropLists objects"));
1037 wassertrv(False
, NULL
);
1044 void WMReleasePropList(WMPropList
* plist
)
1046 WMPropList
*key
, *value
;
1050 plist
->retainCount
--;
1052 switch (plist
->type
) {
1054 if (plist
->retainCount
< 1) {
1055 wfree(plist
->d
.string
);
1060 if (plist
->retainCount
< 1) {
1061 WMReleaseData(plist
->d
.data
);
1066 for (i
= 0; i
< WMGetArrayItemCount(plist
->d
.array
); i
++) {
1067 WMReleasePropList(WMGetFromArray(plist
->d
.array
, i
));
1069 if (plist
->retainCount
< 1) {
1070 WMFreeArray(plist
->d
.array
);
1075 e
= WMEnumerateHashTable(plist
->d
.dict
);
1076 while (WMNextHashEnumeratorItemAndKey(&e
, (void **)&value
, (void **)&key
)) {
1077 WMReleasePropList(key
);
1078 WMReleasePropList(value
);
1080 if (plist
->retainCount
< 1) {
1081 WMFreeHashTable(plist
->d
.dict
);
1086 wwarning(_("Used proplist functions on non-WMPropLists objects"));
1092 void WMInsertInPLArray(WMPropList
* plist
, int index
, WMPropList
* item
)
1094 wassertr(plist
->type
== WPLArray
);
1096 retainPropListByCount(item
, plist
->retainCount
);
1097 WMInsertInArray(plist
->d
.array
, index
, item
);
1100 void WMAddToPLArray(WMPropList
* plist
, WMPropList
* item
)
1102 wassertr(plist
->type
== WPLArray
);
1104 retainPropListByCount(item
, plist
->retainCount
);
1105 WMAddToArray(plist
->d
.array
, item
);
1108 void WMDeleteFromPLArray(WMPropList
* plist
, int index
)
1112 wassertr(plist
->type
== WPLArray
);
1114 item
= WMGetFromArray(plist
->d
.array
, index
);
1116 WMDeleteFromArray(plist
->d
.array
, index
);
1117 releasePropListByCount(item
, plist
->retainCount
);
1121 void WMRemoveFromPLArray(WMPropList
* plist
, WMPropList
* item
)
1126 wassertr(plist
->type
== WPLArray
);
1128 for (i
= 0; i
< WMGetArrayItemCount(plist
->d
.array
); i
++) {
1129 iPtr
= WMGetFromArray(plist
->d
.array
, i
);
1130 if (WMIsPropListEqualTo(item
, iPtr
)) {
1131 WMDeleteFromArray(plist
->d
.array
, i
);
1132 releasePropListByCount(iPtr
, plist
->retainCount
);
1138 void WMPutInPLDictionary(WMPropList
* plist
, WMPropList
* key
, WMPropList
* value
)
1140 wassertr(plist
->type
== WPLDictionary
);
1142 /*WMRetainPropList(key); */
1143 WMRemoveFromPLDictionary(plist
, key
);
1144 retainPropListByCount(key
, plist
->retainCount
);
1145 retainPropListByCount(value
, plist
->retainCount
);
1146 WMHashInsert(plist
->d
.dict
, key
, value
);
1147 /*WMReleasePropList(key); */
1150 void WMRemoveFromPLDictionary(WMPropList
* plist
, WMPropList
* key
)
1154 wassertr(plist
->type
== WPLDictionary
);
1156 if (WMHashGetItemAndKey(plist
->d
.dict
, key
, (void **)&v
, (void **)&k
)) {
1157 WMHashRemove(plist
->d
.dict
, k
);
1158 releasePropListByCount(k
, plist
->retainCount
);
1159 releasePropListByCount(v
, plist
->retainCount
);
1163 WMPropList
*WMMergePLDictionaries(WMPropList
* dest
, WMPropList
* source
, Bool recursive
)
1165 WMPropList
*key
, *value
, *dvalue
;
1168 wassertr(source
->type
== WPLDictionary
&& dest
->type
== WPLDictionary
);
1173 e
= WMEnumerateHashTable(source
->d
.dict
);
1174 while (WMNextHashEnumeratorItemAndKey(&e
, (void **)&value
, (void **)&key
)) {
1175 if (recursive
&& value
->type
== WPLDictionary
) {
1176 dvalue
= WMHashGet(dest
->d
.dict
, key
);
1177 if (dvalue
&& dvalue
->type
== WPLDictionary
) {
1178 WMMergePLDictionaries(dvalue
, value
, True
);
1180 WMPutInPLDictionary(dest
, key
, value
);
1183 WMPutInPLDictionary(dest
, key
, value
);
1190 WMPropList
*WMSubtractPLDictionaries(WMPropList
* dest
, WMPropList
* source
, Bool recursive
)
1192 WMPropList
*key
, *value
, *dvalue
;
1195 wassertr(source
->type
== WPLDictionary
&& dest
->type
== WPLDictionary
);
1197 if (source
== dest
) {
1198 WMPropList
*keys
= WMGetPLDictionaryKeys(dest
);
1201 for (i
= 0; i
< WMGetArrayItemCount(keys
->d
.array
); i
++) {
1202 WMRemoveFromPLDictionary(dest
, WMGetFromArray(keys
->d
.array
, i
));
1207 e
= WMEnumerateHashTable(source
->d
.dict
);
1208 while (WMNextHashEnumeratorItemAndKey(&e
, (void **)&value
, (void **)&key
)) {
1209 dvalue
= WMHashGet(dest
->d
.dict
, key
);
1212 if (WMIsPropListEqualTo(value
, dvalue
)) {
1213 WMRemoveFromPLDictionary(dest
, key
);
1214 } else if (recursive
&& value
->type
== WPLDictionary
&& dvalue
->type
== WPLDictionary
) {
1215 WMSubtractPLDictionaries(dvalue
, value
, True
);
1222 int WMGetPropListItemCount(WMPropList
* plist
)
1224 switch (plist
->type
) {
1227 return 0; /* should this be 1 instead? */
1229 return WMGetArrayItemCount(plist
->d
.array
);
1231 return (int)WMCountHashTable(plist
->d
.dict
);
1233 wwarning(_("Used proplist functions on non-WMPropLists objects"));
1234 wassertrv(False
, 0);
1241 Bool
WMIsPLString(WMPropList
* plist
)
1243 return (plist
->type
== WPLString
);
1246 Bool
WMIsPLData(WMPropList
* plist
)
1248 return (plist
->type
== WPLData
);
1251 Bool
WMIsPLArray(WMPropList
* plist
)
1253 return (plist
->type
== WPLArray
);
1256 Bool
WMIsPLDictionary(WMPropList
* plist
)
1258 return (plist
->type
== WPLDictionary
);
1261 Bool
WMIsPropListEqualTo(WMPropList
* plist
, WMPropList
* other
)
1263 WMPropList
*key1
, *item1
, *item2
;
1264 WMHashEnumerator enumerator
;
1267 if (plist
->type
!= other
->type
)
1270 switch (plist
->type
) {
1272 if (caseSensitive
) {
1273 return (strcmp(plist
->d
.string
, other
->d
.string
) == 0);
1275 return (strcasecmp(plist
->d
.string
, other
->d
.string
) == 0);
1278 return WMIsDataEqualToData(plist
->d
.data
, other
->d
.data
);
1280 n
= WMGetArrayItemCount(plist
->d
.array
);
1281 if (n
!= WMGetArrayItemCount(other
->d
.array
))
1283 for (i
= 0; i
< n
; i
++) {
1284 item1
= WMGetFromArray(plist
->d
.array
, i
);
1285 item2
= WMGetFromArray(other
->d
.array
, i
);
1286 if (!WMIsPropListEqualTo(item1
, item2
))
1291 if (WMCountHashTable(plist
->d
.dict
) != WMCountHashTable(other
->d
.dict
))
1293 enumerator
= WMEnumerateHashTable(plist
->d
.dict
);
1294 while (WMNextHashEnumeratorItemAndKey(&enumerator
, (void **)&item1
, (void **)&key1
)) {
1295 item2
= WMHashGet(other
->d
.dict
, key1
);
1296 if (!item2
|| !item1
|| !WMIsPropListEqualTo(item1
, item2
))
1301 wwarning(_("Used proplist functions on non-WMPropLists objects"));
1302 wassertrv(False
, False
);
1309 char *WMGetFromPLString(WMPropList
* plist
)
1311 wassertrv(plist
->type
== WPLString
, NULL
);
1313 return plist
->d
.string
;
1316 WMData
*WMGetFromPLData(WMPropList
* plist
)
1318 wassertrv(plist
->type
== WPLData
, NULL
);
1320 return plist
->d
.data
;
1323 const unsigned char *WMGetPLDataBytes(WMPropList
* plist
)
1325 wassertrv(plist
->type
== WPLData
, NULL
);
1327 return WMDataBytes(plist
->d
.data
);
1330 int WMGetPLDataLength(WMPropList
* plist
)
1332 wassertrv(plist
->type
== WPLData
, 0);
1334 return WMGetDataLength(plist
->d
.data
);
1337 WMPropList
*WMGetFromPLArray(WMPropList
* plist
, int index
)
1339 wassertrv(plist
->type
== WPLArray
, NULL
);
1341 return WMGetFromArray(plist
->d
.array
, index
);
1344 WMPropList
*WMGetFromPLDictionary(WMPropList
* plist
, WMPropList
* key
)
1346 wassertrv(plist
->type
== WPLDictionary
, NULL
);
1348 return WMHashGet(plist
->d
.dict
, key
);
1351 WMPropList
*WMGetPLDictionaryKeys(WMPropList
* plist
)
1353 WMPropList
*array
, *key
;
1354 WMHashEnumerator enumerator
;
1356 wassertrv(plist
->type
== WPLDictionary
, NULL
);
1358 array
= (WMPropList
*) wmalloc(sizeof(W_PropList
));
1359 array
->type
= WPLArray
;
1360 array
->d
.array
= WMCreateArray(WMCountHashTable(plist
->d
.dict
));
1361 array
->retainCount
= 1;
1363 enumerator
= WMEnumerateHashTable(plist
->d
.dict
);
1364 while ((key
= WMNextHashEnumeratorKey(&enumerator
))) {
1365 WMAddToArray(array
->d
.array
, WMRetainPropList(key
));
1371 WMPropList
*WMShallowCopyPropList(WMPropList
* plist
)
1373 WMPropList
*ret
= NULL
;
1374 WMPropList
*key
, *item
;
1379 switch (plist
->type
) {
1381 ret
= WMCreatePLString(plist
->d
.string
);
1384 data
= WMCreateDataWithData(plist
->d
.data
);
1385 ret
= WMCreatePLData(data
);
1386 WMReleaseData(data
);
1389 ret
= (WMPropList
*) wmalloc(sizeof(W_PropList
));
1390 ret
->type
= WPLArray
;
1391 ret
->d
.array
= WMCreateArrayWithArray(plist
->d
.array
);
1392 ret
->retainCount
= 1;
1394 for (i
= 0; i
< WMGetArrayItemCount(ret
->d
.array
); i
++)
1395 WMRetainPropList(WMGetFromArray(ret
->d
.array
, i
));
1399 ret
= WMCreatePLDictionary(NULL
, NULL
);
1400 e
= WMEnumerateHashTable(plist
->d
.dict
);
1401 while (WMNextHashEnumeratorItemAndKey(&e
, (void **)&item
, (void **)&key
)) {
1402 WMPutInPLDictionary(ret
, key
, item
);
1406 wwarning(_("Used proplist functions on non-WMPropLists objects"));
1407 wassertrv(False
, NULL
);
1414 WMPropList
*WMDeepCopyPropList(WMPropList
* plist
)
1416 WMPropList
*ret
= NULL
;
1417 WMPropList
*key
, *item
;
1422 switch (plist
->type
) {
1424 ret
= WMCreatePLString(plist
->d
.string
);
1427 data
= WMCreateDataWithData(plist
->d
.data
);
1428 ret
= WMCreatePLData(data
);
1429 WMReleaseData(data
);
1432 ret
= WMCreatePLArray(NULL
);
1433 for (i
= 0; i
< WMGetArrayItemCount(plist
->d
.array
); i
++) {
1434 item
= WMDeepCopyPropList(WMGetFromArray(plist
->d
.array
, i
));
1435 WMAddToArray(ret
->d
.array
, item
);
1439 ret
= WMCreatePLDictionary(NULL
, NULL
);
1440 e
= WMEnumerateHashTable(plist
->d
.dict
);
1441 /* While we copy an existing dictionary there is no way that we can
1442 * have duplicate keys, so we don't need to first remove a key/value
1443 * pair before inserting the new key/value.
1445 while (WMNextHashEnumeratorItemAndKey(&e
, (void **)&item
, (void **)&key
)) {
1446 WMHashInsert(ret
->d
.dict
, WMDeepCopyPropList(key
), WMDeepCopyPropList(item
));
1450 wwarning(_("Used proplist functions on non-WMPropLists objects"));
1451 wassertrv(False
, NULL
);
1458 WMPropList
*WMCreatePropListFromDescription(char *desc
)
1460 WMPropList
*plist
= NULL
;
1463 pldata
= (PLData
*) wmalloc(sizeof(PLData
));
1464 memset(pldata
, 0, sizeof(PLData
));
1466 pldata
->lineNumber
= 1;
1468 plist
= getPropList(pldata
);
1470 if (getNonSpaceChar(pldata
) != 0 && plist
) {
1471 COMPLAIN(pldata
, _("extra data after end of property list"));
1473 * We can't just ignore garbage after the end of the description
1474 * (especially if the description was read from a file), because
1475 * the "garbage" can be the real data and the real garbage is in
1476 * fact in the beginning of the file (which is now inside plist)
1478 WMReleasePropList(plist
);
1487 char *WMGetPropListDescription(WMPropList
* plist
, Bool indented
)
1489 return (indented
? indentedDescription(plist
, 0) : description(plist
));
1492 WMPropList
*WMReadPropListFromFile(char *file
)
1494 WMPropList
*plist
= NULL
;
1500 f
= fopen(file
, "rb");
1502 /* let the user print the error message if he really needs to */
1503 /*wsyserror(_("could not open domain file '%s' for reading"), file); */
1507 if (stat(file
, &stbuf
) == 0) {
1508 length
= (size_t) stbuf
.st_size
;
1510 wsyserror(_("could not get size for file '%s'"), file
);
1515 pldata
= (PLData
*) wmalloc(sizeof(PLData
));
1516 memset(pldata
, 0, sizeof(PLData
));
1517 pldata
->ptr
= (char *)wmalloc(length
+ 1);
1518 pldata
->filename
= file
;
1519 pldata
->lineNumber
= 1;
1521 if (fread(pldata
->ptr
, length
, 1, f
) != 1) {
1523 wsyserror(_("error reading from file '%s'"), file
);
1529 pldata
->ptr
[length
] = 0;
1531 plist
= getPropList(pldata
);
1533 if (getNonSpaceChar(pldata
) != 0 && plist
) {
1534 COMPLAIN(pldata
, _("extra data after end of property list"));
1536 * We can't just ignore garbage after the end of the description
1537 * (especially if the description was read from a file), because
1538 * the "garbage" can be the real data and the real garbage is in
1539 * fact in the beginning of the file (which is now inside plist)
1541 WMReleasePropList(plist
);
1553 /* TODO: review this function's code */
1555 Bool
WMWritePropListToFile(WMPropList
* plist
, char *path
)
1557 char *thePath
= NULL
;
1564 if (!wmkdirhier(path
))
1567 /* Use the path name of the destination file as a prefix for the
1568 * mkstemp() call so that we can be sure that both files are on
1569 * the same filesystem and the subsequent rename() will work. */
1570 thePath
= wstrconcat(path
, ".XXXXXX");
1573 if ((fd
= mkstemp(thePath
)) < 0) {
1574 wsyserror(_("mkstemp (%s) failed"), thePath
);
1579 fchmod(fd
, 0644 & ~mask
);
1580 if ((theFile
= fdopen(fd
, "wb")) == NULL
) {
1584 if (mktemp(thePath
) == NULL
) {
1585 wsyserror(_("mktemp (%s) failed"), thePath
);
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 (void)fsync(fileno(theFile
));
1607 if (fclose(theFile
) != 0) {
1608 wsyserror(_("fclose (%s) failed"), thePath
);
1612 /* If we used a temporary file, we still need to rename() it be the
1613 * real file. Also, we need to try to retain the file attributes of
1614 * the original file we are overwriting (if we are) */
1615 if (rename(thePath
, path
) != 0) {
1616 wsyserror(_("rename ('%s' to '%s') failed"), thePath
, path
);
1630 * create a directory hierarchy
1632 * if the last octet of `path' is `/', the full path is
1633 * assumed to be a directory; otherwise path is assumed to be a
1634 * file, and the last component is stripped off. the rest is the
1635 * the hierarchy to be created.
1637 * refuses to create anything outside $GNUSTEP_USER_ROOT
1639 * returns 1 on success, 0 on failure
1641 int wmkdirhier(const char *path
)
1643 char *t
, *thePath
= NULL
, buf
[1024];
1647 /* Only create directories under $GNUSTEP_USER_ROOT */
1648 if ((t
= wusergnusteppath()) == NULL
)
1650 if (strncmp(path
, t
, strlen(t
)) != 0)
1653 thePath
= wstrdup(path
);
1654 /* Strip the trailing component if it is a file */
1655 p
= strlen(thePath
);
1656 while (p
&& thePath
[p
] != '/')
1657 thePath
[p
--] = '\0';
1661 /* Shortcut if it already exists */
1662 if (stat(thePath
, &st
) == 0) {
1664 if (S_ISDIR(st
.st_mode
)) {
1665 /* Is a directory alright */
1668 /* Exists, but not a directory, the caller
1669 * might just as well abort now */
1674 memset(buf
, 0, sizeof(buf
));
1675 strncpy(buf
, t
, sizeof(buf
) - 1);
1677 plen
= strlen(thePath
);
1680 while (p
++ < plen
&& thePath
[p
] != '/')
1683 strncpy(buf
, thePath
, p
);
1684 if (mkdir(buf
, 0777) == -1 && errno
== EEXIST
&&
1685 stat(buf
, &st
) == 0 && !S_ISDIR(st
.st_mode
)) {
1686 wsyserror(_("Could not create component %s"), buf
);
1697 * remove a directory hierarchy
1699 * refuses to remove anything outside $GNUSTEP_USER_ROOT
1701 * returns 1 on success, 0 on failure
1703 * TODO: revisit what's error and what's not
1705 * with inspirations from OpenBSD's bin/rm/rm.c
1707 int wrmdirhier(const char *path
)
1715 /* Only remove directories under $GNUSTEP_USER_ROOT */
1716 if ((t
= wusergnusteppath()) == NULL
)
1718 if (strncmp(path
, t
, strlen(t
)) != 0)
1721 /* Shortcut if it doesn't exist to begin with */
1722 if (stat(path
, &st
) == -1)
1725 ptree
[0] = (char *)path
;
1728 if (!(fts
= fts_open(ptree
, FTS_PHYSICAL
, NULL
)))
1731 while ((p
= fts_read(fts
)) != NULL
) {
1732 switch(p
->fts_info
) {
1741 unlink(p
->fts_path
);