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