19 WPLString
= 0x57504c01,
21 WPLArray
= 0x57504c03,
22 WPLDictionary
= 0x57504c04
25 typedef struct W_PropList
{
38 typedef struct PLData
{
45 typedef struct StringBuffer
{
50 static unsigned hashPropList(const void *param
);
51 static WMPropList
*getPLString(PLData
* pldata
);
52 static WMPropList
*getPLQString(PLData
* pldata
);
53 static WMPropList
*getPLData(PLData
* pldata
);
54 static WMPropList
*getPLArray(PLData
* pldata
);
55 static WMPropList
*getPLDictionary(PLData
* pldata
);
56 static WMPropList
*getPropList(PLData
* pldata
);
58 typedef Bool(*isEqualFunc
) (const void *, const void *);
60 static const WMHashTableCallbacks WMPropListHashCallbacks
= {
62 (isEqualFunc
) WMIsPropListEqualTo
,
67 static Bool caseSensitive
= True
;
69 #define BUFFERSIZE 8192
70 #define BUFFERSIZE_INCREMENT 1024
73 # define DPUT(s) puts(s)
78 #define COMPLAIN(pld, msg) wwarning(_("syntax error in %s %s, line %i: %s"),\
79 (pld)->filename ? "file" : "PropList",\
80 (pld)->filename ? (pld)->filename : "description",\
81 (pld)->lineNumber, msg)
83 #define ISSTRINGABLE(c) (isalnum(c) || (c)=='.' || (c)=='_' || (c)=='/' \
86 #define CHECK_BUFFER_SIZE(buf, ptr) \
87 if ((ptr) >= (buf).size-1) {\
88 (buf).size += BUFFERSIZE_INCREMENT;\
89 (buf).str = wrealloc((buf).str, (buf).size);\
92 #define inrange(ch, min, max) ((ch)>=(min) && (ch)<=(max))
93 #define noquote(ch) (inrange(ch, 'a', 'z') || inrange(ch, 'A', 'Z') || inrange(ch, '0', '9') || ((ch)=='_') || ((ch)=='.') || ((ch)=='$'))
94 #define charesc(ch) (inrange(ch, 0x07, 0x0c) || ((ch)=='"') || ((ch)=='\\'))
95 #define numesc(ch) (((ch)<=0x06) || inrange(ch, 0x0d, 0x1f) || ((ch)>0x7e))
96 #define ishexdigit(ch) (inrange(ch, 'a', 'f') || inrange(ch, 'A', 'F') || inrange(ch, '0', '9'))
97 #define char2num(ch) (inrange(ch,'0','9') ? ((ch)-'0') : (inrange(ch,'a','f') ? ((ch)-0x57) : ((ch)-0x37)))
98 #define num2char(num) ((num) < 0xa ? ((num)+'0') : ((num)+0x57))
100 #define MaxHashLength 64
102 static unsigned hashPropList(const void *param
)
104 WMPropList
*plist
= (WMPropList
*) param
;
110 switch (plist
->type
) {
112 key
= plist
->d
.string
;
113 len
= WMIN(strlen(key
), MaxHashLength
);
114 for (i
= 0; i
< len
; i
++) {
115 ret
^= tolower(key
[i
]) << ctr
;
116 ctr
= (ctr
+ 1) % sizeof(char *);
119 ret ^= tolower(*key++) << ctr;
120 ctr = (ctr + 1) % sizeof (char *);
125 key
= WMDataBytes(plist
->d
.data
);
126 len
= WMIN(WMGetDataLength(plist
->d
.data
), MaxHashLength
);
127 for (i
= 0; i
< len
; i
++) {
128 ret
^= key
[i
] << ctr
;
129 ctr
= (ctr
+ 1) % sizeof(char *);
134 wwarning(_("Only string or data is supported for a proplist dictionary key"));
142 static WMPropList
*retainPropListByCount(WMPropList
* plist
, int count
)
144 WMPropList
*key
, *value
;
148 plist
->retainCount
+= count
;
150 switch (plist
->type
) {
155 for (i
= 0; i
< WMGetArrayItemCount(plist
->d
.array
); i
++) {
156 retainPropListByCount(WMGetFromArray(plist
->d
.array
, i
), count
);
160 e
= WMEnumerateHashTable(plist
->d
.dict
);
161 while (WMNextHashEnumeratorItemAndKey(&e
, (void **)&value
, (void **)&key
)) {
162 retainPropListByCount(key
, count
);
163 retainPropListByCount(value
, count
);
167 wwarning(_("Used proplist functions on non-WMPropLists objects"));
168 wassertrv(False
, NULL
);
175 static void releasePropListByCount(WMPropList
* plist
, int count
)
177 WMPropList
*key
, *value
;
181 plist
->retainCount
-= count
;
183 switch (plist
->type
) {
185 if (plist
->retainCount
< 1) {
186 wfree(plist
->d
.string
);
191 if (plist
->retainCount
< 1) {
192 WMReleaseData(plist
->d
.data
);
197 for (i
= 0; i
< WMGetArrayItemCount(plist
->d
.array
); i
++) {
198 releasePropListByCount(WMGetFromArray(plist
->d
.array
, i
), count
);
200 if (plist
->retainCount
< 1) {
201 WMFreeArray(plist
->d
.array
);
206 e
= WMEnumerateHashTable(plist
->d
.dict
);
207 while (WMNextHashEnumeratorItemAndKey(&e
, (void **)&value
, (void **)&key
)) {
208 releasePropListByCount(key
, count
);
209 releasePropListByCount(value
, count
);
211 if (plist
->retainCount
< 1) {
212 WMFreeHashTable(plist
->d
.dict
);
217 wwarning(_("Used proplist functions on non-WMPropLists objects"));
223 static char *dataDescription(WMPropList
* plist
)
225 const unsigned char *data
;
229 data
= WMDataBytes(plist
->d
.data
);
230 length
= WMGetDataLength(plist
->d
.data
);
232 retVal
= (char *)wmalloc(2 * length
+ length
/ 4 + 3);
235 for (i
= 0, j
= 1; i
< length
; i
++) {
236 retVal
[j
++] = num2char((data
[i
] >> 4) & 0x0f);
237 retVal
[j
++] = num2char(data
[i
] & 0x0f);
238 if ((i
& 0x03) == 3 && i
!= length
- 1) {
239 /* if we've just finished a 32-bit int, add a space */
249 static char *stringDescription(WMPropList
* plist
)
252 char *retVal
, *sPtr
, *dPtr
;
256 str
= plist
->d
.string
;
258 if (strlen(str
) == 0) {
259 return wstrdup("\"\"");
262 /* FIXME: make this work with unichars. */
267 while ((ch
= *sPtr
)) {
282 retVal
= (char *)wmalloc(len
+ 1);
290 while ((ch
= *sPtr
)) {
313 *dPtr
= ch
; /* " or \ */
315 } else if (numesc(ch
)) {
317 *(dPtr
++) = '0' + ((ch
>> 6) & 07);
318 *(dPtr
++) = '0' + ((ch
>> 3) & 07);
319 *dPtr
= '0' + (ch
& 07);
335 static char *description(WMPropList
* plist
)
337 WMPropList
*key
, *val
;
339 char *str
, *tmp
, *skey
, *sval
;
343 switch (plist
->type
) {
345 retstr
= stringDescription(plist
);
348 retstr
= dataDescription(plist
);
351 retstr
= wstrdup("(");
352 for (i
= 0; i
< WMGetArrayItemCount(plist
->d
.array
); i
++) {
353 str
= description(WMGetFromArray(plist
->d
.array
, i
));
355 retstr
= wstrappend(retstr
, str
);
357 tmp
= (char *)wmalloc(strlen(retstr
) + strlen(str
) + 3);
358 sprintf(tmp
, "%s, %s", retstr
, str
);
364 retstr
= wstrappend(retstr
, ")");
367 retstr
= wstrdup("{");
368 e
= WMEnumerateHashTable(plist
->d
.dict
);
369 while (WMNextHashEnumeratorItemAndKey(&e
, (void **)&val
, (void **)&key
)) {
370 skey
= description(key
);
371 sval
= description(val
);
372 tmp
= (char *)wmalloc(strlen(retstr
) + strlen(skey
) + strlen(sval
) + 5);
373 sprintf(tmp
, "%s%s = %s;", retstr
, skey
, sval
);
379 retstr
= wstrappend(retstr
, "}");
382 wwarning(_("Used proplist functions on non-WMPropLists objects"));
383 wassertrv(False
, NULL
);
390 static char *indentedDescription(WMPropList
* plist
, int level
)
392 WMPropList
*key
, *val
;
394 char *str
, *tmp
, *skey
, *sval
;
398 if (plist
->type
== WPLArray
/* || plist->type==WPLDictionary */ ) {
399 retstr
= description(plist
);
401 if (retstr
&& ((2 * (level
+ 1) + strlen(retstr
)) <= 77)) {
409 switch (plist
->type
) {
411 retstr
= stringDescription(plist
);
414 retstr
= dataDescription(plist
);
417 retstr
= wstrdup("(\n");
418 for (i
= 0; i
< WMGetArrayItemCount(plist
->d
.array
); i
++) {
419 str
= indentedDescription(WMGetFromArray(plist
->d
.array
, i
), level
+ 1);
421 tmp
= (char *)wmalloc(2 * (level
+ 1) + strlen(retstr
) + strlen(str
) + 1);
422 sprintf(tmp
, "%s%*s%s", retstr
, 2 * (level
+ 1), "", str
);
426 tmp
= (char *)wmalloc(2 * (level
+ 1) + strlen(retstr
) + strlen(str
) + 3);
427 sprintf(tmp
, "%s,\n%*s%s", retstr
, 2 * (level
+ 1), "", str
);
433 tmp
= (char *)wmalloc(strlen(retstr
) + 2 * level
+ 3);
434 sprintf(tmp
, "%s\n%*s)", retstr
, 2 * level
, "");
439 retstr
= wstrdup("{\n");
440 e
= WMEnumerateHashTable(plist
->d
.dict
);
441 while (WMNextHashEnumeratorItemAndKey(&e
, (void **)&val
, (void **)&key
)) {
442 skey
= indentedDescription(key
, level
+ 1);
443 sval
= indentedDescription(val
, level
+ 1);
444 tmp
= (char *)wmalloc(2 * (level
+ 1) + strlen(retstr
) + strlen(skey
)
446 sprintf(tmp
, "%s%*s%s = %s;\n", retstr
, 2 * (level
+ 1), "", skey
, sval
);
452 tmp
= (char *)wmalloc(strlen(retstr
) + 2 * level
+ 2);
453 sprintf(tmp
, "%s%*s}", retstr
, 2 * level
, "");
458 wwarning(_("Used proplist functions on non-WMPropLists objects"));
459 wassertrv(False
, NULL
);
466 static inline int getChar(PLData
* pldata
)
470 c
= pldata
->ptr
[pldata
->pos
];
478 pldata
->lineNumber
++;
483 static inline int getNonSpaceChar(PLData
* pldata
)
488 c
= pldata
->ptr
[pldata
->pos
];
494 pldata
->lineNumber
++;
495 } else if (!isspace(c
)) {
503 static char *unescapestr(const char *src
)
505 char *dest
= wmalloc(strlen(src
) + 1);
509 for (dPtr
= dest
; ; dPtr
++) {
520 } else if ((ch
>= '0') && (ch
<= '7')) {
523 /* Convert octal number to character */
526 if ((ch
>= '0') && (ch
<= '7')) {
528 wch
= (wch
<< 3) | (ch
& 07);
530 if ((ch
>= '0') && (ch
<= '7')) {
532 wch
= (wch
<< 3) | (ch
& 07);
571 static WMPropList
*getPLString(PLData
* pldata
)
578 sBuf
.str
= wmalloc(BUFFERSIZE
);
579 sBuf
.size
= BUFFERSIZE
;
583 if (ISSTRINGABLE(c
)) {
584 CHECK_BUFFER_SIZE(sBuf
, ptr
);
599 char *tmp
= unescapestr(sBuf
.str
);
600 plist
= WMCreatePLString(tmp
);
609 static WMPropList
*getPLQString(PLData
* pldata
)
612 int ptr
= 0, escaping
= 0, ok
= 1;
616 sBuf
.str
= wmalloc(BUFFERSIZE
);
617 sBuf
.size
= BUFFERSIZE
;
625 } else if (c
== '"') {
629 CHECK_BUFFER_SIZE(sBuf
, ptr
);
630 sBuf
.str
[ptr
++] = '\\';
635 COMPLAIN(pldata
, _("unterminated PropList string"));
639 CHECK_BUFFER_SIZE(sBuf
, ptr
);
649 char *tmp
= unescapestr(sBuf
.str
);
650 plist
= WMCreatePLString(tmp
);
659 static WMPropList
*getPLData(PLData
* pldata
)
664 unsigned char buf
[BUFFERSIZE
], byte
;
668 data
= WMCreateDataWithCapacity(0);
671 c1
= getNonSpaceChar(pldata
);
673 COMPLAIN(pldata
, _("unterminated PropList data"));
676 } else if (c1
== '>') {
678 } else if (ishexdigit(c1
)) {
679 c2
= getNonSpaceChar(pldata
);
680 if (c2
== 0 || c2
== '>') {
681 COMPLAIN(pldata
, _("unterminated PropList data (missing hexdigit)"));
684 } else if (ishexdigit(c2
)) {
685 byte
= char2num(c1
) << 4;
686 byte
|= char2num(c2
);
688 if (len
== sizeof(buf
)) {
689 WMAppendDataBytes(data
, buf
, len
);
693 COMPLAIN(pldata
, _("non hexdigit character in PropList data"));
698 COMPLAIN(pldata
, _("non hexdigit character in PropList data"));
710 WMAppendDataBytes(data
, buf
, len
);
712 plist
= WMCreatePLData(data
);
718 static WMPropList
*getPLArray(PLData
* pldata
)
723 WMPropList
*array
, *obj
;
725 array
= WMCreatePLArray(NULL
);
728 c
= getNonSpaceChar(pldata
);
730 COMPLAIN(pldata
, _("unterminated PropList array"));
733 } else if (c
== ')') {
735 } else if (c
== ',') {
736 /* continue normally */
738 COMPLAIN(pldata
, _("missing or unterminated PropList array"));
746 obj
= getPropList(pldata
);
748 COMPLAIN(pldata
, _("could not get PropList array element"));
752 WMAddToPLArray(array
, obj
);
753 WMReleasePropList(obj
);
757 WMReleasePropList(array
);
764 static WMPropList
*getPLDictionary(PLData
* pldata
)
768 WMPropList
*dict
, *key
, *value
;
770 dict
= WMCreatePLDictionary(NULL
, NULL
);
773 c
= getNonSpaceChar(pldata
);
775 COMPLAIN(pldata
, _("unterminated PropList dictionary"));
778 } else if (c
== '}') {
782 DPUT("getting PropList dictionary key");
784 key
= getPLData(pldata
);
785 } else if (c
== '"') {
786 key
= getPLQString(pldata
);
787 } else if (ISSTRINGABLE(c
)) {
789 key
= getPLString(pldata
);
792 COMPLAIN(pldata
, _("missing PropList dictionary key"));
794 COMPLAIN(pldata
, _("missing PropList dictionary entry key "
795 "or unterminated dictionary"));
802 COMPLAIN(pldata
, _("error parsing PropList dictionary key"));
807 c
= getNonSpaceChar(pldata
);
809 WMReleasePropList(key
);
810 COMPLAIN(pldata
, _("missing = in PropList dictionary entry"));
815 DPUT("getting PropList dictionary entry value for key");
816 value
= getPropList(pldata
);
818 COMPLAIN(pldata
, _("error parsing PropList dictionary entry value"));
819 WMReleasePropList(key
);
824 c
= getNonSpaceChar(pldata
);
826 COMPLAIN(pldata
, _("missing ; in PropList dictionary entry"));
827 WMReleasePropList(key
);
828 WMReleasePropList(value
);
833 WMPutInPLDictionary(dict
, key
, value
);
834 WMReleasePropList(key
);
835 WMReleasePropList(value
);
839 WMReleasePropList(dict
);
846 static WMPropList
*getPropList(PLData
* pldata
)
851 c
= getNonSpaceChar(pldata
);
855 DPUT("End of PropList");
860 DPUT("Getting PropList dictionary");
861 plist
= getPLDictionary(pldata
);
865 DPUT("Getting PropList array");
866 plist
= getPLArray(pldata
);
870 DPUT("Getting PropList data");
871 plist
= getPLData(pldata
);
875 DPUT("Getting PropList quoted string");
876 plist
= getPLQString(pldata
);
880 if (ISSTRINGABLE(c
)) {
881 DPUT("Getting PropList string");
883 plist
= getPLString(pldata
);
885 COMPLAIN(pldata
, _("was expecting a string, data, array or "
886 "dictionary. If it's a string, try enclosing " "it with \"."));
887 if (c
== '#' || c
== '/') {
888 wwarning(_("Comments are not allowed inside WindowMaker owned" " domain files."));
898 void WMPLSetCaseSensitive(Bool caseSensitiveness
)
900 caseSensitive
= caseSensitiveness
;
903 WMPropList
*WMCreatePLString(const char *str
)
907 wassertrv(str
!= NULL
, NULL
);
909 plist
= (WMPropList
*) wmalloc(sizeof(W_PropList
));
910 plist
->type
= WPLString
;
911 plist
->d
.string
= wstrdup(str
);
912 plist
->retainCount
= 1;
917 WMPropList
*WMCreatePLData(WMData
* data
)
921 wassertrv(data
!= NULL
, NULL
);
923 plist
= (WMPropList
*) wmalloc(sizeof(W_PropList
));
924 plist
->type
= WPLData
;
925 plist
->d
.data
= WMRetainData(data
);
926 plist
->retainCount
= 1;
931 WMPropList
*WMCreatePLDataWithBytes(const unsigned char *bytes
, unsigned int length
)
935 wassertrv(bytes
!= NULL
, NULL
);
937 plist
= (WMPropList
*) wmalloc(sizeof(W_PropList
));
938 plist
->type
= WPLData
;
939 plist
->d
.data
= WMCreateDataWithBytes(bytes
, length
);
940 plist
->retainCount
= 1;
945 WMPropList
*WMCreatePLDataWithBytesNoCopy(unsigned char *bytes
, unsigned int length
, WMFreeDataProc
* destructor
)
949 wassertrv(bytes
!= NULL
, NULL
);
951 plist
= (WMPropList
*) wmalloc(sizeof(W_PropList
));
952 plist
->type
= WPLData
;
953 plist
->d
.data
= WMCreateDataWithBytesNoCopy(bytes
, length
, destructor
);
954 plist
->retainCount
= 1;
959 WMPropList
*WMCreatePLArray(WMPropList
* elem
, ...)
961 WMPropList
*plist
, *nelem
;
964 plist
= (WMPropList
*) wmalloc(sizeof(W_PropList
));
965 plist
->type
= WPLArray
;
966 plist
->d
.array
= WMCreateArray(4);
967 plist
->retainCount
= 1;
972 WMAddToArray(plist
->d
.array
, WMRetainPropList(elem
));
977 nelem
= va_arg(ap
, WMPropList
*);
982 WMAddToArray(plist
->d
.array
, WMRetainPropList(nelem
));
986 WMPropList
*WMCreatePLDictionary(WMPropList
* key
, WMPropList
* value
, ...)
988 WMPropList
*plist
, *nkey
, *nvalue
, *k
, *v
;
991 plist
= (WMPropList
*) wmalloc(sizeof(W_PropList
));
992 plist
->type
= WPLDictionary
;
993 plist
->d
.dict
= WMCreateHashTable(WMPropListHashCallbacks
);
994 plist
->retainCount
= 1;
999 WMHashInsert(plist
->d
.dict
, WMRetainPropList(key
), WMRetainPropList(value
));
1001 va_start(ap
, value
);
1004 nkey
= va_arg(ap
, WMPropList
*);
1009 nvalue
= va_arg(ap
, WMPropList
*);
1014 if (WMHashGetItemAndKey(plist
->d
.dict
, nkey
, (void **)&v
, (void **)&k
)) {
1015 WMHashRemove(plist
->d
.dict
, k
);
1016 WMReleasePropList(k
);
1017 WMReleasePropList(v
);
1019 WMHashInsert(plist
->d
.dict
, WMRetainPropList(nkey
), WMRetainPropList(nvalue
));
1023 WMPropList
*WMRetainPropList(WMPropList
* plist
)
1025 WMPropList
*key
, *value
;
1029 plist
->retainCount
++;
1031 switch (plist
->type
) {
1036 for (i
= 0; i
< WMGetArrayItemCount(plist
->d
.array
); i
++) {
1037 WMRetainPropList(WMGetFromArray(plist
->d
.array
, i
));
1041 e
= WMEnumerateHashTable(plist
->d
.dict
);
1042 while (WMNextHashEnumeratorItemAndKey(&e
, (void **)&value
, (void **)&key
)) {
1043 WMRetainPropList(key
);
1044 WMRetainPropList(value
);
1048 wwarning(_("Used proplist functions on non-WMPropLists objects"));
1049 wassertrv(False
, NULL
);
1056 void WMReleasePropList(WMPropList
* plist
)
1058 WMPropList
*key
, *value
;
1062 plist
->retainCount
--;
1064 switch (plist
->type
) {
1066 if (plist
->retainCount
< 1) {
1067 wfree(plist
->d
.string
);
1072 if (plist
->retainCount
< 1) {
1073 WMReleaseData(plist
->d
.data
);
1078 for (i
= 0; i
< WMGetArrayItemCount(plist
->d
.array
); i
++) {
1079 WMReleasePropList(WMGetFromArray(plist
->d
.array
, i
));
1081 if (plist
->retainCount
< 1) {
1082 WMFreeArray(plist
->d
.array
);
1087 e
= WMEnumerateHashTable(plist
->d
.dict
);
1088 while (WMNextHashEnumeratorItemAndKey(&e
, (void **)&value
, (void **)&key
)) {
1089 WMReleasePropList(key
);
1090 WMReleasePropList(value
);
1092 if (plist
->retainCount
< 1) {
1093 WMFreeHashTable(plist
->d
.dict
);
1098 wwarning(_("Used proplist functions on non-WMPropLists objects"));
1104 void WMInsertInPLArray(WMPropList
* plist
, int index
, WMPropList
* item
)
1106 wassertr(plist
->type
== WPLArray
);
1108 retainPropListByCount(item
, plist
->retainCount
);
1109 WMInsertInArray(plist
->d
.array
, index
, item
);
1112 void WMAddToPLArray(WMPropList
* plist
, WMPropList
* item
)
1114 wassertr(plist
->type
== WPLArray
);
1116 retainPropListByCount(item
, plist
->retainCount
);
1117 WMAddToArray(plist
->d
.array
, item
);
1120 void WMDeleteFromPLArray(WMPropList
* plist
, int index
)
1124 wassertr(plist
->type
== WPLArray
);
1126 item
= WMGetFromArray(plist
->d
.array
, index
);
1128 WMDeleteFromArray(plist
->d
.array
, index
);
1129 releasePropListByCount(item
, plist
->retainCount
);
1133 void WMRemoveFromPLArray(WMPropList
* plist
, WMPropList
* item
)
1138 wassertr(plist
->type
== WPLArray
);
1140 for (i
= 0; i
< WMGetArrayItemCount(plist
->d
.array
); i
++) {
1141 iPtr
= WMGetFromArray(plist
->d
.array
, i
);
1142 if (WMIsPropListEqualTo(item
, iPtr
)) {
1143 WMDeleteFromArray(plist
->d
.array
, i
);
1144 releasePropListByCount(iPtr
, plist
->retainCount
);
1150 void WMPutInPLDictionary(WMPropList
* plist
, WMPropList
* key
, WMPropList
* value
)
1152 wassertr(plist
->type
== WPLDictionary
);
1154 /*WMRetainPropList(key); */
1155 WMRemoveFromPLDictionary(plist
, key
);
1156 retainPropListByCount(key
, plist
->retainCount
);
1157 retainPropListByCount(value
, plist
->retainCount
);
1158 WMHashInsert(plist
->d
.dict
, key
, value
);
1159 /*WMReleasePropList(key); */
1162 void WMRemoveFromPLDictionary(WMPropList
* plist
, WMPropList
* key
)
1166 wassertr(plist
->type
== WPLDictionary
);
1168 if (WMHashGetItemAndKey(plist
->d
.dict
, key
, (void **)&v
, (void **)&k
)) {
1169 WMHashRemove(plist
->d
.dict
, k
);
1170 releasePropListByCount(k
, plist
->retainCount
);
1171 releasePropListByCount(v
, plist
->retainCount
);
1175 WMPropList
*WMMergePLDictionaries(WMPropList
* dest
, WMPropList
* source
, Bool recursive
)
1177 WMPropList
*key
, *value
, *dvalue
;
1180 wassertrv(source
->type
== WPLDictionary
&& dest
->type
== WPLDictionary
, NULL
);
1185 e
= WMEnumerateHashTable(source
->d
.dict
);
1186 while (WMNextHashEnumeratorItemAndKey(&e
, (void **)&value
, (void **)&key
)) {
1187 if (recursive
&& value
->type
== WPLDictionary
) {
1188 dvalue
= WMHashGet(dest
->d
.dict
, key
);
1189 if (dvalue
&& dvalue
->type
== WPLDictionary
) {
1190 WMMergePLDictionaries(dvalue
, value
, True
);
1192 WMPutInPLDictionary(dest
, key
, value
);
1195 WMPutInPLDictionary(dest
, key
, value
);
1202 WMPropList
*WMSubtractPLDictionaries(WMPropList
* dest
, WMPropList
* source
, Bool recursive
)
1204 WMPropList
*key
, *value
, *dvalue
;
1207 wassertrv(source
->type
== WPLDictionary
&& dest
->type
== WPLDictionary
, NULL
);
1209 if (source
== dest
) {
1210 WMPropList
*keys
= WMGetPLDictionaryKeys(dest
);
1213 for (i
= 0; i
< WMGetArrayItemCount(keys
->d
.array
); i
++) {
1214 WMRemoveFromPLDictionary(dest
, WMGetFromArray(keys
->d
.array
, i
));
1219 e
= WMEnumerateHashTable(source
->d
.dict
);
1220 while (WMNextHashEnumeratorItemAndKey(&e
, (void **)&value
, (void **)&key
)) {
1221 dvalue
= WMHashGet(dest
->d
.dict
, key
);
1224 if (WMIsPropListEqualTo(value
, dvalue
)) {
1225 WMRemoveFromPLDictionary(dest
, key
);
1226 } else if (recursive
&& value
->type
== WPLDictionary
&& dvalue
->type
== WPLDictionary
) {
1227 WMSubtractPLDictionaries(dvalue
, value
, True
);
1234 int WMGetPropListItemCount(WMPropList
* plist
)
1236 switch (plist
->type
) {
1239 return 0; /* should this be 1 instead? */
1241 return WMGetArrayItemCount(plist
->d
.array
);
1243 return (int)WMCountHashTable(plist
->d
.dict
);
1245 wwarning(_("Used proplist functions on non-WMPropLists objects"));
1246 wassertrv(False
, 0);
1253 Bool
WMIsPLString(WMPropList
* plist
)
1255 return (plist
->type
== WPLString
);
1258 Bool
WMIsPLData(WMPropList
* plist
)
1260 return (plist
->type
== WPLData
);
1263 Bool
WMIsPLArray(WMPropList
* plist
)
1265 return (plist
->type
== WPLArray
);
1268 Bool
WMIsPLDictionary(WMPropList
* plist
)
1270 return (plist
->type
== WPLDictionary
);
1273 Bool
WMIsPropListEqualTo(WMPropList
* plist
, WMPropList
* other
)
1275 WMPropList
*key1
, *item1
, *item2
;
1276 WMHashEnumerator enumerator
;
1279 if (plist
->type
!= other
->type
)
1282 switch (plist
->type
) {
1284 if (caseSensitive
) {
1285 return (strcmp(plist
->d
.string
, other
->d
.string
) == 0);
1287 return (strcasecmp(plist
->d
.string
, other
->d
.string
) == 0);
1290 return WMIsDataEqualToData(plist
->d
.data
, other
->d
.data
);
1292 n
= WMGetArrayItemCount(plist
->d
.array
);
1293 if (n
!= WMGetArrayItemCount(other
->d
.array
))
1295 for (i
= 0; i
< n
; i
++) {
1296 item1
= WMGetFromArray(plist
->d
.array
, i
);
1297 item2
= WMGetFromArray(other
->d
.array
, i
);
1298 if (!WMIsPropListEqualTo(item1
, item2
))
1303 if (WMCountHashTable(plist
->d
.dict
) != WMCountHashTable(other
->d
.dict
))
1305 enumerator
= WMEnumerateHashTable(plist
->d
.dict
);
1306 while (WMNextHashEnumeratorItemAndKey(&enumerator
, (void **)&item1
, (void **)&key1
)) {
1307 item2
= WMHashGet(other
->d
.dict
, key1
);
1308 if (!item2
|| !item1
|| !WMIsPropListEqualTo(item1
, item2
))
1313 wwarning(_("Used proplist functions on non-WMPropLists objects"));
1314 wassertrv(False
, False
);
1321 char *WMGetFromPLString(WMPropList
* plist
)
1323 wassertrv(plist
->type
== WPLString
, NULL
);
1325 return plist
->d
.string
;
1328 WMData
*WMGetFromPLData(WMPropList
* plist
)
1330 wassertrv(plist
->type
== WPLData
, NULL
);
1332 return plist
->d
.data
;
1335 const unsigned char *WMGetPLDataBytes(WMPropList
* plist
)
1337 wassertrv(plist
->type
== WPLData
, NULL
);
1339 return WMDataBytes(plist
->d
.data
);
1342 int WMGetPLDataLength(WMPropList
* plist
)
1344 wassertrv(plist
->type
== WPLData
, 0);
1346 return WMGetDataLength(plist
->d
.data
);
1349 WMPropList
*WMGetFromPLArray(WMPropList
* plist
, int index
)
1351 wassertrv(plist
->type
== WPLArray
, NULL
);
1353 return WMGetFromArray(plist
->d
.array
, index
);
1356 WMPropList
*WMGetFromPLDictionary(WMPropList
* plist
, WMPropList
* key
)
1358 wassertrv(plist
->type
== WPLDictionary
, NULL
);
1360 return WMHashGet(plist
->d
.dict
, key
);
1363 WMPropList
*WMGetPLDictionaryKeys(WMPropList
* plist
)
1365 WMPropList
*array
, *key
;
1366 WMHashEnumerator enumerator
;
1368 wassertrv(plist
->type
== WPLDictionary
, NULL
);
1370 array
= (WMPropList
*) wmalloc(sizeof(W_PropList
));
1371 array
->type
= WPLArray
;
1372 array
->d
.array
= WMCreateArray(WMCountHashTable(plist
->d
.dict
));
1373 array
->retainCount
= 1;
1375 enumerator
= WMEnumerateHashTable(plist
->d
.dict
);
1376 while ((key
= WMNextHashEnumeratorKey(&enumerator
))) {
1377 WMAddToArray(array
->d
.array
, WMRetainPropList(key
));
1383 WMPropList
*WMShallowCopyPropList(WMPropList
* plist
)
1385 WMPropList
*ret
= NULL
;
1386 WMPropList
*key
, *item
;
1391 switch (plist
->type
) {
1393 ret
= WMCreatePLString(plist
->d
.string
);
1396 data
= WMCreateDataWithData(plist
->d
.data
);
1397 ret
= WMCreatePLData(data
);
1398 WMReleaseData(data
);
1401 ret
= (WMPropList
*) wmalloc(sizeof(W_PropList
));
1402 ret
->type
= WPLArray
;
1403 ret
->d
.array
= WMCreateArrayWithArray(plist
->d
.array
);
1404 ret
->retainCount
= 1;
1406 for (i
= 0; i
< WMGetArrayItemCount(ret
->d
.array
); i
++)
1407 WMRetainPropList(WMGetFromArray(ret
->d
.array
, i
));
1411 ret
= WMCreatePLDictionary(NULL
, NULL
);
1412 e
= WMEnumerateHashTable(plist
->d
.dict
);
1413 while (WMNextHashEnumeratorItemAndKey(&e
, (void **)&item
, (void **)&key
)) {
1414 WMPutInPLDictionary(ret
, key
, item
);
1418 wwarning(_("Used proplist functions on non-WMPropLists objects"));
1419 wassertrv(False
, NULL
);
1426 WMPropList
*WMDeepCopyPropList(WMPropList
* plist
)
1428 WMPropList
*ret
= NULL
;
1429 WMPropList
*key
, *item
;
1434 switch (plist
->type
) {
1436 ret
= WMCreatePLString(plist
->d
.string
);
1439 data
= WMCreateDataWithData(plist
->d
.data
);
1440 ret
= WMCreatePLData(data
);
1441 WMReleaseData(data
);
1444 ret
= WMCreatePLArray(NULL
);
1445 for (i
= 0; i
< WMGetArrayItemCount(plist
->d
.array
); i
++) {
1446 item
= WMDeepCopyPropList(WMGetFromArray(plist
->d
.array
, i
));
1447 WMAddToArray(ret
->d
.array
, item
);
1451 ret
= WMCreatePLDictionary(NULL
, NULL
);
1452 e
= WMEnumerateHashTable(plist
->d
.dict
);
1453 /* While we copy an existing dictionary there is no way that we can
1454 * have duplicate keys, so we don't need to first remove a key/value
1455 * pair before inserting the new key/value.
1457 while (WMNextHashEnumeratorItemAndKey(&e
, (void **)&item
, (void **)&key
)) {
1458 WMHashInsert(ret
->d
.dict
, WMDeepCopyPropList(key
), WMDeepCopyPropList(item
));
1462 wwarning(_("Used proplist functions on non-WMPropLists objects"));
1463 wassertrv(False
, NULL
);
1470 WMPropList
*WMCreatePropListFromDescription(const char *desc
)
1472 WMPropList
*plist
= NULL
;
1475 pldata
= (PLData
*) wmalloc(sizeof(PLData
));
1477 pldata
->lineNumber
= 1;
1479 plist
= getPropList(pldata
);
1481 if (getNonSpaceChar(pldata
) != 0 && plist
) {
1482 COMPLAIN(pldata
, _("extra data after end of property list"));
1484 * We can't just ignore garbage after the end of the description
1485 * (especially if the description was read from a file), because
1486 * the "garbage" can be the real data and the real garbage is in
1487 * fact in the beginning of the file (which is now inside plist)
1489 WMReleasePropList(plist
);
1498 char *WMGetPropListDescription(WMPropList
* plist
, Bool indented
)
1500 return (indented
? indentedDescription(plist
, 0) : description(plist
));
1503 WMPropList
*WMReadPropListFromFile(const char *file
)
1505 WMPropList
*plist
= NULL
;
1512 f
= fopen(file
, "rb");
1514 /* let the user print the error message if he really needs to */
1515 /*werror(_("could not open domain file '%s' for reading"), file); */
1519 if (stat(file
, &stbuf
) == 0) {
1520 length
= (size_t) stbuf
.st_size
;
1522 werror(_("could not get size for file '%s'"), file
);
1527 read_buf
= wmalloc(length
+ 1);
1528 if (fread(read_buf
, length
, 1, f
) != 1) {
1530 werror(_("error reading from file '%s'"), file
);
1536 read_buf
[length
] = '\0';
1539 pldata
= (PLData
*) wmalloc(sizeof(PLData
));
1540 pldata
->ptr
= read_buf
;
1541 pldata
->filename
= file
;
1542 pldata
->lineNumber
= 1;
1544 plist
= getPropList(pldata
);
1546 if (getNonSpaceChar(pldata
) != 0 && plist
) {
1547 COMPLAIN(pldata
, _("extra data after end of property list"));
1549 * We can't just ignore garbage after the end of the description
1550 * (especially if the description was read from a file), because
1551 * the "garbage" can be the real data and the real garbage is in
1552 * fact in the beginning of the file (which is now inside plist)
1554 WMReleasePropList(plist
);
1564 WMPropList
*WMReadPropListFromPipe(const char *command
)
1572 file
= popen(command
, "r");
1575 werror(_("%s:could not open menu file"), command
);
1579 pldata
= (PLData
*) wmalloc(sizeof(PLData
));
1581 pldata
->filename
= command
;
1582 pldata
->lineNumber
= 1;
1584 /* read from file till EOF or OOM and fill proplist buffer*/
1586 while (fgets(line
, sizeof(line
), file
) != NULL
) {
1587 if (read_buf
== NULL
) {
1588 read_buf
= wmalloc(strlen(line
)+1);
1591 read_buf
= wrealloc(read_buf
,
1592 strlen(line
) + strlen(read_buf
) + 1);
1595 read_buf
= strncat(read_buf
, line
, strlen(line
));
1597 pldata
->ptr
= read_buf
;
1601 plist
= getPropList(pldata
);
1603 if (getNonSpaceChar(pldata
) != 0 && plist
) {
1604 COMPLAIN(pldata
, _("extra data after end of property list"));
1606 * We can't just ignore garbage after the end of the description
1607 * (especially if the description was read from a file), because
1608 * the "garbage" can be the real data and the real garbage is in
1609 * fact in the beginning of the file (which is now inside plist)
1611 WMReleasePropList(plist
);
1621 /* TODO: review this function's code */
1623 Bool
WMWritePropListToFile(WMPropList
* plist
, const char *path
)
1625 char *thePath
= NULL
;
1632 if (!wmkdirhier(path
))
1635 /* Use the path name of the destination file as a prefix for the
1636 * mkstemp() call so that we can be sure that both files are on
1637 * the same filesystem and the subsequent rename() will work. */
1638 thePath
= wstrconcat(path
, ".XXXXXX");
1641 if ((fd
= mkstemp(thePath
)) < 0) {
1642 werror(_("mkstemp (%s) failed"), thePath
);
1647 fchmod(fd
, 0644 & ~mask
);
1648 if ((theFile
= fdopen(fd
, "wb")) == NULL
) {
1652 if (mktemp(thePath
) == NULL
) {
1653 werror(_("mktemp (%s) failed"), thePath
);
1656 theFile
= fopen(thePath
, "wb");
1659 if (theFile
== NULL
) {
1660 werror(_("open (%s) failed"), thePath
);
1664 desc
= indentedDescription(plist
, 0);
1666 if (fprintf(theFile
, "%s\n", desc
) != strlen(desc
) + 1) {
1667 werror(_("writing to file: %s failed"), thePath
);
1674 (void)fsync(fileno(theFile
));
1675 if (fclose(theFile
) != 0) {
1676 werror(_("fclose (%s) failed"), thePath
);
1680 /* If we used a temporary file, we still need to rename() it be the
1681 * real file. Also, we need to try to retain the file attributes of
1682 * the original file we are overwriting (if we are) */
1683 if (rename(thePath
, path
) != 0) {
1684 werror(_("rename ('%s' to '%s') failed"), thePath
, path
);
1698 * create a directory hierarchy
1700 * if the last octet of `path' is `/', the full path is
1701 * assumed to be a directory; otherwise path is assumed to be a
1702 * file, and the last component is stripped off. the rest is the
1703 * the hierarchy to be created.
1705 * refuses to create anything outside $GNUSTEP_USER_ROOT
1707 * returns 1 on success, 0 on failure
1709 int wmkdirhier(const char *path
)
1712 char *thePath
= NULL
, buf
[1024];
1716 /* Only create directories under $GNUSTEP_USER_ROOT */
1717 if ((t
= wusergnusteppath()) == NULL
)
1719 if (strncmp(path
, t
, strlen(t
)) != 0)
1722 thePath
= wstrdup(path
);
1723 /* Strip the trailing component if it is a file */
1724 p
= strlen(thePath
);
1725 while (p
&& thePath
[p
] != '/')
1726 thePath
[p
--] = '\0';
1730 /* Shortcut if it already exists */
1731 if (stat(thePath
, &st
) == 0) {
1733 if (S_ISDIR(st
.st_mode
)) {
1734 /* Is a directory alright */
1737 /* Exists, but not a directory, the caller
1738 * might just as well abort now */
1743 memset(buf
, 0, sizeof(buf
));
1744 strncpy(buf
, t
, sizeof(buf
) - 1);
1746 plen
= strlen(thePath
);
1749 while (p
++ < plen
&& thePath
[p
] != '/')
1752 strncpy(buf
, thePath
, p
);
1753 if (mkdir(buf
, 0777) == -1 && errno
== EEXIST
&&
1754 stat(buf
, &st
) == 0 && !S_ISDIR(st
.st_mode
)) {
1755 werror(_("Could not create component %s"), buf
);
1766 static int wrmdirhier_fn(const char *path
, const struct stat
*st
,
1767 int type
, struct FTW
*ftw
)
1769 /* Parameter not used, but tell the compiler that it is ok */
1782 return unlink(path
);
1795 * remove a directory hierarchy
1797 * refuses to remove anything outside $GNUSTEP_USER_ROOT
1799 * returns 1 on success, 0 on failure
1801 * TODO: revisit what's error and what's not
1803 * with inspirations from OpenBSD's bin/rm/rm.c
1805 int wrmdirhier(const char *path
)
1811 /* Only remove directories under $GNUSTEP_USER_ROOT */
1812 if ((t
= wusergnusteppath()) == NULL
)
1814 if (strncmp(path
, t
, strlen(t
)) != 0)
1817 /* Shortcut if it doesn't exist to begin with */
1818 if (stat(path
, &st
) == -1)
1821 error
= nftw(path
, wrmdirhier_fn
, 1, FTW_PHYS
);