Change to the linux kernel coding style
[wmaker-crm.git] / WINGs / proplist.c
Commit [+]AuthorDateLineData
2d5a0620 dan2001-09-06 00:55:18 +00001
2d5a0620 dan2001-09-06 00:55:18 +00002#include <string.h>
86f3e2fd dan2001-09-06 14:16:11 +00003#include <stdarg.h>
49e59ab3 dan2001-09-10 03:56:00 +00004#include <stdio.h>
5#include <stdlib.h>
6#include <sys/types.h>
7#include <sys/stat.h>
8#include <unistd.h>
9#include <ctype.h>
86f3e2fd dan2001-09-06 14:16:11 +000010
2d5a0620 dan2001-09-06 00:55:18 +000011#include "WUtil.h"
12#include "wconfig.h"
13
2d5a0620 dan2001-09-06 00:55:18 +000014typedef enum {
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020015 WPLString = 0x57504c01,
16 WPLData = 0x57504c02,
17 WPLArray = 0x57504c03,
18 WPLDictionary = 0x57504c04
2d5a0620 dan2001-09-06 00:55:18 +000019} WPLType;
20
2d5a0620 dan2001-09-06 00:55:18 +000021typedef struct W_PropList {
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020022 WPLType type;
2d5a0620 dan2001-09-06 00:55:18 +000023
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020024 union {
25 char *string;
26 WMData *data;
27 WMArray *array;
28 WMHashTable *dict;
29 } d;
2d5a0620 dan2001-09-06 00:55:18 +000030
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020031 int retainCount;
2d5a0620 dan2001-09-06 00:55:18 +000032} W_PropList;
33
0c365cfb dan2001-09-17 01:55:23 +000034typedef struct PLData {
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020035 char *ptr;
36 int pos;
37 char *filename;
38 int lineNumber;
0c365cfb dan2001-09-17 01:55:23 +000039} PLData;
40
0c365cfb dan2001-09-17 01:55:23 +000041typedef struct StringBuffer {
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020042 char *str;
43 int size;
0c365cfb dan2001-09-17 01:55:23 +000044} StringBuffer;
2d5a0620 dan2001-09-06 00:55:18 +000045
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020046static unsigned hashPropList(WMPropList * plist);
47static WMPropList *getPLString(PLData * pldata);
48static WMPropList *getPLQString(PLData * pldata);
49static WMPropList *getPLData(PLData * pldata);
50static WMPropList *getPLArray(PLData * pldata);
51static WMPropList *getPLDictionary(PLData * pldata);
52static WMPropList *getPropList(PLData * pldata);
aedbe70f dan2001-09-14 00:24:15 +000053
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020054typedef unsigned (*hashFunc) (const void *);
55typedef Bool(*isEqualFunc) (const void *, const void *);
56typedef void *(*retainFunc) (const void *);
57typedef void (*releaseFunc) (const void *);
86f3e2fd dan2001-09-06 14:16:11 +000058
59static const WMHashTableCallbacks WMPropListHashCallbacks = {
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020060 (hashFunc) hashPropList,
61 (isEqualFunc) WMIsPropListEqualTo,
62 (retainFunc) NULL,
63 (releaseFunc) NULL
86f3e2fd dan2001-09-06 14:16:11 +000064};
65
aedbe70f dan2001-09-14 00:24:15 +000066static Bool caseSensitive = True;
2d5a0620 dan2001-09-06 00:55:18 +000067
0c365cfb dan2001-09-17 01:55:23 +000068#define BUFFERSIZE 8192
69#define BUFFERSIZE_INCREMENT 1024
70
0c365cfb dan2001-09-17 01:55:23 +000071#if 0
72# define DPUT(s) puts(s)
73#else
74# define DPUT(s)
75#endif
76
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)
81
82#define ISSTRINGABLE(c) (isalnum(c) || (c)=='.' || (c)=='_' || (c)=='/' \
83 || (c)=='+')
84
85#define CHECK_BUFFER_SIZE(buf, ptr) \
86 if ((ptr) >= (buf).size-1) {\
6830b057 dan2004-10-12 21:28:27 +000087 (buf).size += BUFFERSIZE_INCREMENT;\
88 (buf).str = wrealloc((buf).str, (buf).size);\
0c365cfb dan2001-09-17 01:55:23 +000089 }
90
0c365cfb dan2001-09-17 01:55:23 +000091#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))
98
aedbe70f dan2001-09-14 00:24:15 +000099#define MaxHashLength 64
100
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200101static unsigned hashPropList(WMPropList * plist)
2d5a0620 dan2001-09-06 00:55:18 +0000102{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200103 unsigned ret = 0;
104 unsigned ctr = 0;
105 const char *key;
106 int i, len;
107
108 switch (plist->type) {
109 case WPLString:
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 *);
115 }
116 /*while (*key) {
117 ret ^= tolower(*key++) << ctr;
118 ctr = (ctr + 1) % sizeof (char *);
119 } */
120 break;
121
122 case WPLData:
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 *);
128 }
129 break;
130
131 default:
132 wwarning(_("Only string or data is supported for a proplist dictionary key"));
133 wassertrv(False, 0);
134 break;
135 }
136
137 return ret;
aedbe70f dan2001-09-14 00:24:15 +0000138}
49e59ab3 dan2001-09-10 03:56:00 +0000139
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200140static WMPropList *retainPropListByCount(WMPropList * plist, int count)
49e59ab3 dan2001-09-10 03:56:00 +0000141{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200142 WMPropList *key, *value;
143 WMHashEnumerator e;
144 int i;
145
146 plist->retainCount += count;
147
148 switch (plist->type) {
149 case WPLString:
150 case WPLData:
151 break;
152 case WPLArray:
153 for (i = 0; i < WMGetArrayItemCount(plist->d.array); i++) {
154 retainPropListByCount(WMGetFromArray(plist->d.array, i), count);
155 }
156 break;
157 case WPLDictionary:
158 e = WMEnumerateHashTable(plist->d.dict);
159 while (WMNextHashEnumeratorItemAndKey(&e, (void **)&value, (void **)&key)) {
160 retainPropListByCount(key, count);
161 retainPropListByCount(value, count);
162 }
163 break;
164 default:
165 wwarning(_("Used proplist functions on non-WMPropLists objects"));
166 wassertrv(False, NULL);
167 break;
168 }
169
170 return plist;
49e59ab3 dan2001-09-10 03:56:00 +0000171}
172
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200173static void releasePropListByCount(WMPropList * plist, int count)
49e59ab3 dan2001-09-10 03:56:00 +0000174{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200175 WMPropList *key, *value;
176 WMHashEnumerator e;
177 int i;
178
179 plist->retainCount -= count;
180
181 switch (plist->type) {
182 case WPLString:
183 if (plist->retainCount < 1) {
184 wfree(plist->d.string);
185 wfree(plist);
186 }
187 break;
188 case WPLData:
189 if (plist->retainCount < 1) {
190 WMReleaseData(plist->d.data);
191 wfree(plist);
192 }
193 break;
194 case WPLArray:
195 for (i = 0; i < WMGetArrayItemCount(plist->d.array); i++) {
196 releasePropListByCount(WMGetFromArray(plist->d.array, i), count);
197 }
198 if (plist->retainCount < 1) {
199 WMFreeArray(plist->d.array);
200 wfree(plist);
201 }
202 break;
203 case WPLDictionary:
204 e = WMEnumerateHashTable(plist->d.dict);
205 while (WMNextHashEnumeratorItemAndKey(&e, (void **)&value, (void **)&key)) {
206 releasePropListByCount(key, count);
207 releasePropListByCount(value, count);
208 }
209 if (plist->retainCount < 1) {
210 WMFreeHashTable(plist->d.dict);
211 wfree(plist);
212 }
213 break;
214 default:
215 wwarning(_("Used proplist functions on non-WMPropLists objects"));
216 wassertr(False);
217 break;
218 }
49e59ab3 dan2001-09-10 03:56:00 +0000219}
220
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200221static char *dataDescription(WMPropList * plist)
49e59ab3 dan2001-09-10 03:56:00 +0000222{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200223 const unsigned char *data;
224 char *retVal;
225 int i, j, length;
226
227 data = WMDataBytes(plist->d.data);
228 length = WMGetDataLength(plist->d.data);
229
230 retVal = (char *)wmalloc(2 * length + length / 4 + 3);
231
232 retVal[0] = '<';
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 */
238 retVal[j++] = ' ';
239 }
240 }
241 retVal[j++] = '>';
242 retVal[j] = '\0';
243
244 return retVal;
49e59ab3 dan2001-09-10 03:56:00 +0000245}
246
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200247static char *stringDescription(WMPropList * plist)
49e59ab3 dan2001-09-10 03:56:00 +0000248{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200249 const char *str;
250 char *retVal, *sPtr, *dPtr;
251 int len, quote;
252 unsigned char ch;
253
254 str = plist->d.string;
255
256 if (strlen(str) == 0) {
257 return wstrdup("\"\"");
258 }
259
260 /* FIXME: make this work with unichars. */
261
262 quote = 0;
263 sPtr = (char *)str;
264 len = 0;
265 while ((ch = *sPtr)) {
266 if (!noquote(ch)) {
267 quote = 1;
268 if (charesc(ch))
269 len++;
270 else if (numesc(ch))
271 len += 3;
272 }
273 sPtr++;
274 len++;
275 }
276
277 if (quote)
278 len += 2;
279
280 retVal = (char *)wmalloc(len + 1);
281
282 sPtr = (char *)str;
283 dPtr = retVal;
284
285 if (quote)
286 *dPtr++ = '"';
287
288 while ((ch = *sPtr)) {
289 if (charesc(ch)) {
290 *(dPtr++) = '\\';
291 switch (ch) {
292 case '\a':
293 *dPtr = 'a';
294 break;
295 case '\b':
296 *dPtr = 'b';
297 break;
298 case '\t':
299 *dPtr = 't';
300 break;
301 case '\n':
302 *dPtr = 'n';
303 break;
304 case '\v':
305 *dPtr = 'v';
306 break;
307 case '\f':
308 *dPtr = 'f';
309 break;
310 default:
311 *dPtr = ch; /* " or \ */
312 }
313 } else if (numesc(ch)) {
314 *(dPtr++) = '\\';
315 *(dPtr++) = '0' + ((ch >> 6) & 07);
316 *(dPtr++) = '0' + ((ch >> 3) & 07);
317 *dPtr = '0' + (ch & 07);
318 } else {
319 *dPtr = ch;
320 }
321 sPtr++;
322 dPtr++;
323 }
324
325 if (quote)
326 *dPtr++ = '"';
327
328 *dPtr = '\0';
329
330 return retVal;
49e59ab3 dan2001-09-10 03:56:00 +0000331}
332
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200333static char *description(WMPropList * plist)
49e59ab3 dan2001-09-10 03:56:00 +0000334{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200335 WMPropList *key, *val;
336 char *retstr = NULL;
337 char *str, *tmp, *skey, *sval;
338 WMHashEnumerator e;
339 int i;
340
341 switch (plist->type) {
342 case WPLString:
343 retstr = stringDescription(plist);
344 break;
345 case WPLData:
346 retstr = dataDescription(plist);
347 break;
348 case WPLArray:
349 retstr = wstrdup("(");
350 for (i = 0; i < WMGetArrayItemCount(plist->d.array); i++) {
351 str = description(WMGetFromArray(plist->d.array, i));
352 if (i == 0) {
353 retstr = wstrappend(retstr, str);
354 } else {
355 tmp = (char *)wmalloc(strlen(retstr) + strlen(str) + 3);
356 sprintf(tmp, "%s, %s", retstr, str);
357 wfree(retstr);
358 retstr = tmp;
359 }
360 wfree(str);
361 }
362 retstr = wstrappend(retstr, ")");
363 break;
364 case WPLDictionary:
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);
372 wfree(skey);
373 wfree(sval);
374 wfree(retstr);
375 retstr = tmp;
376 }
377 retstr = wstrappend(retstr, "}");
378 break;
379 default:
380 wwarning(_("Used proplist functions on non-WMPropLists objects"));
381 wassertrv(False, NULL);
382 break;
383 }
384
385 return retstr;
49e59ab3 dan2001-09-10 03:56:00 +0000386}
387
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200388static char *indentedDescription(WMPropList * plist, int level)
49e59ab3 dan2001-09-10 03:56:00 +0000389{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200390 WMPropList *key, *val;
391 char *retstr = NULL;
392 char *str, *tmp, *skey, *sval;
393 WMHashEnumerator e;
394 int i;
395
396 if (plist->type == WPLArray /* || plist->type==WPLDictionary */ ) {
397 retstr = description(plist);
398
399 if (retstr && ((2 * (level + 1) + strlen(retstr)) <= 77)) {
400 return retstr;
401 } else if (retstr) {
402 wfree(retstr);
403 retstr = NULL;
404 }
405 }
406
407 switch (plist->type) {
408 case WPLString:
409 retstr = stringDescription(plist);
410 break;
411 case WPLData:
412 retstr = dataDescription(plist);
413 break;
414 case WPLArray:
415 retstr = wstrdup("(\n");
416 for (i = 0; i < WMGetArrayItemCount(plist->d.array); i++) {
417 str = indentedDescription(WMGetFromArray(plist->d.array, i), level + 1);
418 if (i == 0) {
419 tmp = (char *)wmalloc(2 * (level + 1) + strlen(retstr) + strlen(str) + 1);
420 sprintf(tmp, "%s%*s%s", retstr, 2 * (level + 1), "", str);
421 wfree(retstr);
422 retstr = tmp;
423 } else {
424 tmp = (char *)wmalloc(2 * (level + 1) + strlen(retstr) + strlen(str) + 3);
425 sprintf(tmp, "%s,\n%*s%s", retstr, 2 * (level + 1), "", str);
426 wfree(retstr);
427 retstr = tmp;
428 }
429 wfree(str);
430 }
431 tmp = (char *)wmalloc(strlen(retstr) + 2 * level + 3);
432 sprintf(tmp, "%s\n%*s)", retstr, 2 * level, "");
433 wfree(retstr);
434 retstr = tmp;
435 break;
436 case WPLDictionary:
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)
443 + strlen(sval) + 6);
444 sprintf(tmp, "%s%*s%s = %s;\n", retstr, 2 * (level + 1), "", skey, sval);
445 wfree(skey);
446 wfree(sval);
447 wfree(retstr);
448 retstr = tmp;
449 }
450 tmp = (char *)wmalloc(strlen(retstr) + 2 * level + 2);
451 sprintf(tmp, "%s%*s}", retstr, 2 * level, "");
452 wfree(retstr);
453 retstr = tmp;
454 break;
455 default:
456 wwarning(_("Used proplist functions on non-WMPropLists objects"));
457 wassertrv(False, NULL);
458 break;
459 }
460
461 return retstr;
2d5a0620 dan2001-09-06 00:55:18 +0000462}
463
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200464static INLINE int getChar(PLData * pldata)
0c365cfb dan2001-09-17 01:55:23 +0000465{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200466 int c;
0c365cfb dan2001-09-17 01:55:23 +0000467
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200468 c = pldata->ptr[pldata->pos];
469 if (c == 0) {
470 return 0;
471 }
0c365cfb dan2001-09-17 01:55:23 +0000472
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200473 pldata->pos++;
0c365cfb dan2001-09-17 01:55:23 +0000474
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200475 if (c == '\n')
476 pldata->lineNumber++;
0c365cfb dan2001-09-17 01:55:23 +0000477
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200478 return c;
0c365cfb dan2001-09-17 01:55:23 +0000479}
480
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200481static INLINE int getNonSpaceChar(PLData * pldata)
0c365cfb dan2001-09-17 01:55:23 +0000482{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200483 int c;
484
485 while (1) {
486 c = pldata->ptr[pldata->pos];
487 if (c == 0) {
488 break;
489 }
490 pldata->pos++;
491 if (c == '\n') {
492 pldata->lineNumber++;
493 } else if (!isspace(c)) {
494 break;
495 }
496 }
497
498 return c;
0c365cfb dan2001-09-17 01:55:23 +0000499}
500
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200501static char *unescapestr(char *src)
0c365cfb dan2001-09-17 01:55:23 +0000502{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200503 char *dest = wmalloc(strlen(src) + 1);
504 char *sPtr, *dPtr;
505 char ch;
506
507 for (sPtr = src, dPtr = dest; *sPtr; sPtr++, dPtr++) {
508 if (*sPtr != '\\') {
509 *dPtr = *sPtr;
510 } else {
511 ch = *(++sPtr);
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;
517 } else {
518 switch (ch) {
519 case 'a':
520 *dPtr = '\a';
521 break;
522 case 'b':
523 *dPtr = '\b';
524 break;
525 case 't':
526 *dPtr = '\t';
527 break;
528 case 'r':
529 *dPtr = '\r';
530 break;
531 case 'n':
532 *dPtr = '\n';
533 break;
534 case 'v':
535 *dPtr = '\v';
536 break;
537 case 'f':
538 *dPtr = '\f';
539 break;
540 default:
541 *dPtr = *sPtr;
542 }
543 }
544 }
545 }
546
547 *dPtr = 0;
548
549 return dest;
0c365cfb dan2001-09-17 01:55:23 +0000550}
551
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200552static WMPropList *getPLString(PLData * pldata)
0c365cfb dan2001-09-17 01:55:23 +0000553{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200554 WMPropList *plist;
555 StringBuffer sBuf;
556 int ptr = 0;
557 int c;
558
559 sBuf.str = wmalloc(BUFFERSIZE);
560 sBuf.size = BUFFERSIZE;
561
562 while (1) {
563 c = getChar(pldata);
564 if (ISSTRINGABLE(c)) {
565 CHECK_BUFFER_SIZE(sBuf, ptr);
566 sBuf.str[ptr++] = c;
567 } else {
568 if (c != 0) {
569 pldata->pos--;
570 }
571 break;
572 }
573 }
574
575 sBuf.str[ptr] = 0;
576
577 if (ptr == 0) {
578 plist = NULL;
579 } else {
580 char *tmp = unescapestr(sBuf.str);
581 plist = WMCreatePLString(tmp);
582 wfree(tmp);
583 }
584
585 wfree(sBuf.str);
586
587 return plist;
0c365cfb dan2001-09-17 01:55:23 +0000588}
589
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200590static WMPropList *getPLQString(PLData * pldata)
0c365cfb dan2001-09-17 01:55:23 +0000591{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200592 WMPropList *plist;
593 int ptr = 0, escaping = 0, ok = 1;
594 int c;
595 StringBuffer sBuf;
596
597 sBuf.str = wmalloc(BUFFERSIZE);
598 sBuf.size = BUFFERSIZE;
599
600 while (1) {
601 c = getChar(pldata);
602 if (!escaping) {
603 if (c == '\\') {
604 escaping = 1;
605 continue;
606 } else if (c == '"') {
607 break;
608 }
609 } else {
610 CHECK_BUFFER_SIZE(sBuf, ptr);
611 sBuf.str[ptr++] = '\\';
612 escaping = 0;
613 }
614
615 if (c == 0) {
616 COMPLAIN(pldata, _("unterminated PropList string"));
617 ok = 0;
618 break;
619 } else {
620 CHECK_BUFFER_SIZE(sBuf, ptr);
621 sBuf.str[ptr++] = c;
622 }
623 }
624
625 sBuf.str[ptr] = 0;
626
627 if (!ok) {
628 plist = NULL;
629 } else {
630 char *tmp = unescapestr(sBuf.str);
631 plist = WMCreatePLString(tmp);
632 wfree(tmp);
633 }
634
635 wfree(sBuf.str);
636
637 return plist;
0c365cfb dan2001-09-17 01:55:23 +0000638}
639
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200640static WMPropList *getPLData(PLData * pldata)
0c365cfb dan2001-09-17 01:55:23 +0000641{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200642 int ok = 1;
643 int len = 0;
644 int c1, c2;
645 unsigned char buf[BUFFERSIZE], byte;
646 WMPropList *plist;
647 WMData *data;
648
649 data = WMCreateDataWithCapacity(0);
650
651 while (1) {
652 c1 = getNonSpaceChar(pldata);
653 if (c1 == 0) {
654 COMPLAIN(pldata, _("unterminated PropList data"));
655 ok = 0;
656 break;
657 } else if (c1 == '>') {
658 break;
659 } else if (ishexdigit(c1)) {
660 c2 = getNonSpaceChar(pldata);
661 if (c2 == 0 || c2 == '>') {
662 COMPLAIN(pldata, _("unterminated PropList data (missing hexdigit)"));
663 ok = 0;
664 break;
665 } else if (ishexdigit(c2)) {
666 byte = char2num(c1) << 4;
667 byte |= char2num(c2);
668 buf[len++] = byte;
669 if (len == sizeof(buf)) {
670 WMAppendDataBytes(data, buf, len);
671 len = 0;
672 }
673 } else {
674 COMPLAIN(pldata, _("non hexdigit character in PropList data"));
675 ok = 0;
676 break;
677 }
678 } else {
679 COMPLAIN(pldata, _("non hexdigit character in PropList data"));
680 ok = 0;
681 break;
682 }
683 }
684
685 if (!ok) {
686 WMReleaseData(data);
687 return NULL;
688 }
689
690 if (len > 0)
691 WMAppendDataBytes(data, buf, len);
692
693 plist = WMCreatePLData(data);
694 WMReleaseData(data);
695
696 return plist;
0c365cfb dan2001-09-17 01:55:23 +0000697}
698
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200699static WMPropList *getPLArray(PLData * pldata)
0c365cfb dan2001-09-17 01:55:23 +0000700{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200701 Bool first = True;
702 int ok = 1;
703 int c;
704 WMPropList *array, *obj;
705
706 array = WMCreatePLArray(NULL);
707
708 while (1) {
709 c = getNonSpaceChar(pldata);
710 if (c == 0) {
711 COMPLAIN(pldata, _("unterminated PropList array"));
712 ok = 0;
713 break;
714 } else if (c == ')') {
715 break;
716 } else if (c == ',') {
717 /* continue normally */
718 } else if (!first) {
719 COMPLAIN(pldata, _("missing or unterminated PropList array"));
720 ok = 0;
721 break;
722 } else {
723 pldata->pos--;
724 }
725 first = False;
726
727 obj = getPropList(pldata);
728 if (!obj) {
729 COMPLAIN(pldata, _("could not get PropList array element"));
730 ok = 0;
731 break;
732 }
733 WMAddToPLArray(array, obj);
734 WMReleasePropList(obj);
735 }
736
737 if (!ok) {
738 WMReleasePropList(array);
739 array = NULL;
740 }
741
742 return array;
0c365cfb dan2001-09-17 01:55:23 +0000743}
744
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200745static WMPropList *getPLDictionary(PLData * pldata)
0c365cfb dan2001-09-17 01:55:23 +0000746{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200747 int ok = 1;
748 int c;
749 WMPropList *dict, *key, *value;
750
751 dict = WMCreatePLDictionary(NULL, NULL);
752
753 while (1) {
754 c = getNonSpaceChar(pldata);
755 if (c == 0) {
756 COMPLAIN(pldata, _("unterminated PropList dictionary"));
757 ok = 0;
758 break;
759 } else if (c == '}') {
760 break;
761 }
762
763 DPUT("getting PropList dictionary key");
764 if (c == '<') {
765 key = getPLData(pldata);
766 } else if (c == '"') {
767 key = getPLQString(pldata);
768 } else if (ISSTRINGABLE(c)) {
769 pldata->pos--;
770 key = getPLString(pldata);
771 } else {
772 if (c == '=') {
773 COMPLAIN(pldata, _("missing PropList dictionary key"));
774 } else {
775 COMPLAIN(pldata, _("missing PropList dictionary entry key "
776 "or unterminated dictionary"));
777 }
778 ok = 0;
779 break;
780 }
781
782 if (!key) {
783 COMPLAIN(pldata, _("error parsing PropList dictionary key"));
784 ok = 0;
785 break;
786 }
787
788 c = getNonSpaceChar(pldata);
789 if (c != '=') {
790 WMReleasePropList(key);
791 COMPLAIN(pldata, _("missing = in PropList dictionary entry"));
792 ok = 0;
793 break;
794 }
795
796 DPUT("getting PropList dictionary entry value for key");
797 value = getPropList(pldata);
798 if (!value) {
799 COMPLAIN(pldata, _("error parsing PropList dictionary entry value"));
800 WMReleasePropList(key);
801 ok = 0;
802 break;
803 }
804
805 c = getNonSpaceChar(pldata);
806 if (c != ';') {
807 COMPLAIN(pldata, _("missing ; in PropList dictionary entry"));
808 WMReleasePropList(key);
809 WMReleasePropList(value);
810 ok = 0;
811 break;
812 }
813
814 WMPutInPLDictionary(dict, key, value);
815 WMReleasePropList(key);
816 WMReleasePropList(value);
817 }
818
819 if (!ok) {
820 WMReleasePropList(dict);
821 dict = NULL;
822 }
823
824 return dict;
0c365cfb dan2001-09-17 01:55:23 +0000825}
826
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200827static WMPropList *getPropList(PLData * pldata)
0c365cfb dan2001-09-17 01:55:23 +0000828{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200829 WMPropList *plist;
830 int c;
831
832 c = getNonSpaceChar(pldata);
833
834 switch (c) {
835 case 0:
836 DPUT("End of PropList");
837 plist = NULL;
838 break;
839
840 case '{':
841 DPUT("Getting PropList dictionary");
842 plist = getPLDictionary(pldata);
843 break;
844
845 case '(':
846 DPUT("Getting PropList array");
847 plist = getPLArray(pldata);
848 break;
849
850 case '<':
851 DPUT("Getting PropList data");
852 plist = getPLData(pldata);
853 break;
854
855 case '"':
856 DPUT("Getting PropList quoted string");
857 plist = getPLQString(pldata);
858 break;
859
860 default:
861 if (ISSTRINGABLE(c)) {
862 DPUT("Getting PropList string");
863 pldata->pos--;
864 plist = getPLString(pldata);
865 } else {
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."));
870 }
871 plist = NULL;
872 }
873 break;
874 }
875
876 return plist;
0c365cfb dan2001-09-17 01:55:23 +0000877}
878
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200879void WMPLSetCaseSensitive(Bool caseSensitiveness)
86f3e2fd dan2001-09-06 14:16:11 +0000880{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200881 caseSensitive = caseSensitiveness;
86f3e2fd dan2001-09-06 14:16:11 +0000882}
883
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200884WMPropList *WMCreatePLString(char *str)
2d5a0620 dan2001-09-06 00:55:18 +0000885{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200886 WMPropList *plist;
2d5a0620 dan2001-09-06 00:55:18 +0000887
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200888 wassertrv(str != NULL, NULL);
2d5a0620 dan2001-09-06 00:55:18 +0000889
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200890 plist = (WMPropList *) wmalloc(sizeof(W_PropList));
2d5a0620 dan2001-09-06 00:55:18 +0000891
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200892 plist->type = WPLString;
893 plist->d.string = wstrdup(str);
894 plist->retainCount = 1;
2d5a0620 dan2001-09-06 00:55:18 +0000895
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200896 return plist;
2d5a0620 dan2001-09-06 00:55:18 +0000897}
898
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200899WMPropList *WMCreatePLData(WMData * data)
2d5a0620 dan2001-09-06 00:55:18 +0000900{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200901 WMPropList *plist;
2d5a0620 dan2001-09-06 00:55:18 +0000902
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200903 wassertrv(data != NULL, NULL);
2d5a0620 dan2001-09-06 00:55:18 +0000904
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200905 plist = (WMPropList *) wmalloc(sizeof(W_PropList));
2d5a0620 dan2001-09-06 00:55:18 +0000906
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200907 plist->type = WPLData;
908 plist->d.data = WMRetainData(data);
909 plist->retainCount = 1;
2d5a0620 dan2001-09-06 00:55:18 +0000910
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200911 return plist;
2d5a0620 dan2001-09-06 00:55:18 +0000912}
913
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200914WMPropList *WMCreatePLDataWithBytes(unsigned char *bytes, unsigned int length)
2d5a0620 dan2001-09-06 00:55:18 +0000915{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200916 WMPropList *plist;
2d5a0620 dan2001-09-06 00:55:18 +0000917
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200918 wassertrv(bytes != NULL, NULL);
2d5a0620 dan2001-09-06 00:55:18 +0000919
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200920 plist = (WMPropList *) wmalloc(sizeof(W_PropList));
2d5a0620 dan2001-09-06 00:55:18 +0000921
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200922 plist->type = WPLData;
923 plist->d.data = WMCreateDataWithBytes(bytes, length);
924 plist->retainCount = 1;
2d5a0620 dan2001-09-06 00:55:18 +0000925
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200926 return plist;
2d5a0620 dan2001-09-06 00:55:18 +0000927}
928
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200929WMPropList *WMCreatePLDataWithBytesNoCopy(unsigned char *bytes, unsigned int length, WMFreeDataProc * destructor)
2d5a0620 dan2001-09-06 00:55:18 +0000930{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200931 WMPropList *plist;
2d5a0620 dan2001-09-06 00:55:18 +0000932
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200933 wassertrv(bytes != NULL, NULL);
2d5a0620 dan2001-09-06 00:55:18 +0000934
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200935 plist = (WMPropList *) wmalloc(sizeof(W_PropList));
2d5a0620 dan2001-09-06 00:55:18 +0000936
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200937 plist->type = WPLData;
938 plist->d.data = WMCreateDataWithBytesNoCopy(bytes, length, destructor);
939 plist->retainCount = 1;
2d5a0620 dan2001-09-06 00:55:18 +0000940
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200941 return plist;
2d5a0620 dan2001-09-06 00:55:18 +0000942}
943
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200944WMPropList *WMCreatePLArray(WMPropList * elem, ...)
86f3e2fd dan2001-09-06 14:16:11 +0000945{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200946 WMPropList *plist, *nelem;
947 va_list ap;
86f3e2fd dan2001-09-06 14:16:11 +0000948
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200949 plist = (WMPropList *) wmalloc(sizeof(W_PropList));
950 plist->type = WPLArray;
951 plist->d.array = WMCreateArray(4);
952 plist->retainCount = 1;
86f3e2fd dan2001-09-06 14:16:11 +0000953
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200954 if (!elem)
955 return plist;
86f3e2fd dan2001-09-06 14:16:11 +0000956
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200957 WMAddToArray(plist->d.array, WMRetainPropList(elem));
86f3e2fd dan2001-09-06 14:16:11 +0000958
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200959 va_start(ap, elem);
86f3e2fd dan2001-09-06 14:16:11 +0000960
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200961 while (1) {
962 nelem = va_arg(ap, WMPropList *);
963 if (!nelem) {
964 va_end(ap);
965 return plist;
966 }
967 WMAddToArray(plist->d.array, WMRetainPropList(nelem));
968 }
86f3e2fd dan2001-09-06 14:16:11 +0000969}
970
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200971WMPropList *WMCreatePLDictionary(WMPropList * key, WMPropList * value, ...)
86f3e2fd dan2001-09-06 14:16:11 +0000972{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200973 WMPropList *plist, *nkey, *nvalue, *k, *v;
974 va_list ap;
975
976 plist = (WMPropList *) wmalloc(sizeof(W_PropList));
977 plist->type = WPLDictionary;
978 plist->d.dict = WMCreateHashTable(WMPropListHashCallbacks);
979 plist->retainCount = 1;
980
981 if (!key || !value)
982 return plist;
983
984 WMHashInsert(plist->d.dict, WMRetainPropList(key), WMRetainPropList(value));
985
986 va_start(ap, value);
987
988 while (1) {
989 nkey = va_arg(ap, WMPropList *);
990 if (!nkey) {
991 va_end(ap);
992 return plist;
993 }
994 nvalue = va_arg(ap, WMPropList *);
995 if (!nvalue) {
996 va_end(ap);
997 return plist;
998 }
999 if (WMHashGetItemAndKey(plist->d.dict, nkey, (void **)&v, (void **)&k)) {
1000 WMHashRemove(plist->d.dict, k);
1001 WMReleasePropList(k);
1002 WMReleasePropList(v);
1003 }
1004 WMHashInsert(plist->d.dict, WMRetainPropList(nkey), WMRetainPropList(nvalue));
1005 }
49e59ab3 dan2001-09-10 03:56:00 +00001006}
1007
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001008WMPropList *WMRetainPropList(WMPropList * plist)
8bb50a63 dan2001-10-03 02:05:53 +00001009{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001010 WMPropList *key, *value;
1011 WMHashEnumerator e;
1012 int i;
1013
1014 plist->retainCount++;
1015
1016 switch (plist->type) {
1017 case WPLString:
1018 case WPLData:
1019 break;
1020 case WPLArray:
1021 for (i = 0; i < WMGetArrayItemCount(plist->d.array); i++) {
1022 WMRetainPropList(WMGetFromArray(plist->d.array, i));
1023 }
1024 break;
1025 case WPLDictionary:
1026 e = WMEnumerateHashTable(plist->d.dict);
1027 while (WMNextHashEnumeratorItemAndKey(&e, (void **)&value, (void **)&key)) {
1028 WMRetainPropList(key);
1029 WMRetainPropList(value);
1030 }
1031 break;
1032 default:
1033 wwarning(_("Used proplist functions on non-WMPropLists objects"));
1034 wassertrv(False, NULL);
1035 break;
1036 }
1037
1038 return plist;
8bb50a63 dan2001-10-03 02:05:53 +00001039}
1040
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001041void WMReleasePropList(WMPropList * plist)
8bb50a63 dan2001-10-03 02:05:53 +00001042{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001043 WMPropList *key, *value;
1044 WMHashEnumerator e;
1045 int i;
1046
1047 plist->retainCount--;
1048
1049 switch (plist->type) {
1050 case WPLString:
1051 if (plist->retainCount < 1) {
1052 wfree(plist->d.string);
1053 wfree(plist);
1054 }
1055 break;
1056 case WPLData:
1057 if (plist->retainCount < 1) {
1058 WMReleaseData(plist->d.data);
1059 wfree(plist);
1060 }
1061 break;
1062 case WPLArray:
1063 for (i = 0; i < WMGetArrayItemCount(plist->d.array); i++) {
1064 WMReleasePropList(WMGetFromArray(plist->d.array, i));
1065 }
1066 if (plist->retainCount < 1) {
1067 WMFreeArray(plist->d.array);
1068 wfree(plist);
1069 }
1070 break;
1071 case WPLDictionary:
1072 e = WMEnumerateHashTable(plist->d.dict);
1073 while (WMNextHashEnumeratorItemAndKey(&e, (void **)&value, (void **)&key)) {
1074 WMReleasePropList(key);
1075 WMReleasePropList(value);
1076 }
1077 if (plist->retainCount < 1) {
1078 WMFreeHashTable(plist->d.dict);
1079 wfree(plist);
1080 }
1081 break;
1082 default:
1083 wwarning(_("Used proplist functions on non-WMPropLists objects"));
1084 wassertr(False);
1085 break;
1086 }
8bb50a63 dan2001-10-03 02:05:53 +00001087}
1088
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001089void WMInsertInPLArray(WMPropList * plist, int index, WMPropList * item)
49e59ab3 dan2001-09-10 03:56:00 +00001090{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001091 wassertr(plist->type == WPLArray);
49e59ab3 dan2001-09-10 03:56:00 +00001092
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001093 retainPropListByCount(item, plist->retainCount);
1094 WMInsertInArray(plist->d.array, index, item);
49e59ab3 dan2001-09-10 03:56:00 +00001095}
1096
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001097void WMAddToPLArray(WMPropList * plist, WMPropList * item)
49e59ab3 dan2001-09-10 03:56:00 +00001098{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001099 wassertr(plist->type == WPLArray);
49e59ab3 dan2001-09-10 03:56:00 +00001100
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001101 retainPropListByCount(item, plist->retainCount);
1102 WMAddToArray(plist->d.array, item);
49e59ab3 dan2001-09-10 03:56:00 +00001103}
1104
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001105void WMDeleteFromPLArray(WMPropList * plist, int index)
49e59ab3 dan2001-09-10 03:56:00 +00001106{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001107 WMPropList *item;
49e59ab3 dan2001-09-10 03:56:00 +00001108
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001109 wassertr(plist->type == WPLArray);
49e59ab3 dan2001-09-10 03:56:00 +00001110
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001111 item = WMGetFromArray(plist->d.array, index);
1112 if (item != NULL) {
1113 WMDeleteFromArray(plist->d.array, index);
1114 releasePropListByCount(item, plist->retainCount);
1115 }
49e59ab3 dan2001-09-10 03:56:00 +00001116}
1117
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001118void WMRemoveFromPLArray(WMPropList * plist, WMPropList * item)
aedbe70f dan2001-09-14 00:24:15 +00001119{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001120 WMPropList *iPtr;
1121 int i;
1122
1123 wassertr(plist->type == WPLArray);
1124
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);
1130 break;
1131 }
1132 }
aedbe70f dan2001-09-14 00:24:15 +00001133}
1134
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001135void WMPutInPLDictionary(WMPropList * plist, WMPropList * key, WMPropList * value)
49e59ab3 dan2001-09-10 03:56:00 +00001136{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001137 wassertr(plist->type == WPLDictionary);
1138
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); */
49e59ab3 dan2001-09-10 03:56:00 +00001145}
1146
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001147void WMRemoveFromPLDictionary(WMPropList * plist, WMPropList * key)
49e59ab3 dan2001-09-10 03:56:00 +00001148{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001149 WMPropList *k, *v;
49e59ab3 dan2001-09-10 03:56:00 +00001150
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001151 wassertr(plist->type == WPLDictionary);
49e59ab3 dan2001-09-10 03:56:00 +00001152
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001153 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);
1157 }
49e59ab3 dan2001-09-10 03:56:00 +00001158}
1159
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001160WMPropList *WMMergePLDictionaries(WMPropList * dest, WMPropList * source, Bool recursive)
49e59ab3 dan2001-09-10 03:56:00 +00001161{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001162 WMPropList *key, *value, *dvalue;
1163 WMHashEnumerator e;
1164
1165 wassertr(source->type == WPLDictionary && dest->type == WPLDictionary);
1166
1167 if (source == dest)
1168 return dest;
1169
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);
1176 } else {
1177 WMPutInPLDictionary(dest, key, value);
1178 }
1179 } else {
1180 WMPutInPLDictionary(dest, key, value);
1181 }
1182 }
1183
1184 return dest;
86f3e2fd dan2001-09-06 14:16:11 +00001185}
1186
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001187WMPropList *WMSubtractPLDictionaries(WMPropList * dest, WMPropList * source, Bool recursive)
41996df7 dan2001-12-20 22:16:01 +00001188{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001189 WMPropList *key, *value, *dvalue;
1190 WMHashEnumerator e;
1191
1192 wassertr(source->type == WPLDictionary && dest->type == WPLDictionary);
1193
1194 if (source == dest) {
1195 WMPropList *keys = WMGetPLDictionaryKeys(dest);
1196 int i;
1197
1198 for (i = 0; i < WMGetArrayItemCount(keys->d.array); i++) {
1199 WMRemoveFromPLDictionary(dest, WMGetFromArray(keys->d.array, i));
1200 }
1201 return dest;
1202 }
1203
1204 e = WMEnumerateHashTable(source->d.dict);
1205 while (WMNextHashEnumeratorItemAndKey(&e, (void **)&value, (void **)&key)) {
1206 dvalue = WMHashGet(dest->d.dict, key);
1207 if (!dvalue)
1208 continue;
1209 if (WMIsPropListEqualTo(value, dvalue)) {
1210 WMRemoveFromPLDictionary(dest, key);
1211 } else if (recursive && value->type == WPLDictionary && dvalue->type == WPLDictionary) {
1212 WMSubtractPLDictionaries(dvalue, value, True);
1213 }
1214 }
1215
1216 return dest;
41996df7 dan2001-12-20 22:16:01 +00001217}
1218
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001219int WMGetPropListItemCount(WMPropList * plist)
86f3e2fd dan2001-09-06 14:16:11 +00001220{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001221 switch (plist->type) {
1222 case WPLString:
1223 case WPLData:
1224 return 0; /* should this be 1 instead? */
1225 case WPLArray:
1226 return WMGetArrayItemCount(plist->d.array);
1227 case WPLDictionary:
1228 return (int)WMCountHashTable(plist->d.dict);
1229 default:
1230 wwarning(_("Used proplist functions on non-WMPropLists objects"));
1231 wassertrv(False, 0);
1232 break;
1233 }
1234
1235 return 0;
86f3e2fd dan2001-09-06 14:16:11 +00001236}
86f3e2fd dan2001-09-06 14:16:11 +00001237
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001238Bool WMIsPLString(WMPropList * plist)
86f3e2fd dan2001-09-06 14:16:11 +00001239{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001240 return (plist->type == WPLString);
86f3e2fd dan2001-09-06 14:16:11 +00001241}
1242
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001243Bool WMIsPLData(WMPropList * plist)
86f3e2fd dan2001-09-06 14:16:11 +00001244{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001245 return (plist->type == WPLData);
86f3e2fd dan2001-09-06 14:16:11 +00001246}
1247
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001248Bool WMIsPLArray(WMPropList * plist)
86f3e2fd dan2001-09-06 14:16:11 +00001249{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001250 return (plist->type == WPLArray);
86f3e2fd dan2001-09-06 14:16:11 +00001251}
1252
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001253Bool WMIsPLDictionary(WMPropList * plist)
86f3e2fd dan2001-09-06 14:16:11 +00001254{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001255 return (plist->type == WPLDictionary);
86f3e2fd dan2001-09-06 14:16:11 +00001256}
1257
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001258Bool WMIsPropListEqualTo(WMPropList * plist, WMPropList * other)
2d5a0620 dan2001-09-06 00:55:18 +00001259{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001260 WMPropList *key1, *item1, *item2;
1261 WMHashEnumerator enumerator;
1262 int n, i;
1263
1264 if (plist->type != other->type)
1265 return False;
1266
1267 switch (plist->type) {
1268 case WPLString:
1269 if (caseSensitive) {
1270 return (strcmp(plist->d.string, other->d.string) == 0);
1271 } else {
1272 return (strcasecmp(plist->d.string, other->d.string) == 0);
1273 }
1274 case WPLData:
1275 return WMIsDataEqualToData(plist->d.data, other->d.data);
1276 case WPLArray:
1277 n = WMGetArrayItemCount(plist->d.array);
1278 if (n != WMGetArrayItemCount(other->d.array))
1279 return False;
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))
1284 return False;
1285 }
1286 return True;
1287 case WPLDictionary:
1288 if (WMCountHashTable(plist->d.dict) != WMCountHashTable(other->d.dict))
1289 return False;
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))
1294 return False;
1295 }
1296 return True;
1297 default:
1298 wwarning(_("Used proplist functions on non-WMPropLists objects"));
1299 wassertrv(False, False);
1300 break;
1301 }
1302
1303 return False;
2d5a0620 dan2001-09-06 00:55:18 +00001304}
1305
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001306char *WMGetFromPLString(WMPropList * plist)
49e59ab3 dan2001-09-10 03:56:00 +00001307{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001308 wassertrv(plist->type == WPLString, NULL);
49e59ab3 dan2001-09-10 03:56:00 +00001309
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001310 return plist->d.string;
49e59ab3 dan2001-09-10 03:56:00 +00001311}
1312
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001313WMData *WMGetFromPLData(WMPropList * plist)
49e59ab3 dan2001-09-10 03:56:00 +00001314{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001315 wassertrv(plist->type == WPLData, NULL);
49e59ab3 dan2001-09-10 03:56:00 +00001316
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001317 return plist->d.data;
49e59ab3 dan2001-09-10 03:56:00 +00001318}
1319
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001320const unsigned char *WMGetPLDataBytes(WMPropList * plist)
49e59ab3 dan2001-09-10 03:56:00 +00001321{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001322 wassertrv(plist->type == WPLData, NULL);
49e59ab3 dan2001-09-10 03:56:00 +00001323
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001324 return WMDataBytes(plist->d.data);
49e59ab3 dan2001-09-10 03:56:00 +00001325}
1326
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001327int WMGetPLDataLength(WMPropList * plist)
49e59ab3 dan2001-09-10 03:56:00 +00001328{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001329 wassertrv(plist->type == WPLData, 0);
49e59ab3 dan2001-09-10 03:56:00 +00001330
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001331 return WMGetDataLength(plist->d.data);
49e59ab3 dan2001-09-10 03:56:00 +00001332}
1333
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001334WMPropList *WMGetFromPLArray(WMPropList * plist, int index)
49e59ab3 dan2001-09-10 03:56:00 +00001335{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001336 wassertrv(plist->type == WPLArray, NULL);
49e59ab3 dan2001-09-10 03:56:00 +00001337
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001338 return WMGetFromArray(plist->d.array, index);
49e59ab3 dan2001-09-10 03:56:00 +00001339}
1340
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001341WMPropList *WMGetFromPLDictionary(WMPropList * plist, WMPropList * key)
49e59ab3 dan2001-09-10 03:56:00 +00001342{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001343 wassertrv(plist->type == WPLDictionary, NULL);
49e59ab3 dan2001-09-10 03:56:00 +00001344
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001345 return WMHashGet(plist->d.dict, key);
49e59ab3 dan2001-09-10 03:56:00 +00001346}
1347
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001348WMPropList *WMGetPLDictionaryKeys(WMPropList * plist)
49e59ab3 dan2001-09-10 03:56:00 +00001349{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001350 WMPropList *array, *key;
1351 WMHashEnumerator enumerator;
49e59ab3 dan2001-09-10 03:56:00 +00001352
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001353 wassertrv(plist->type == WPLDictionary, NULL);
49e59ab3 dan2001-09-10 03:56:00 +00001354
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001355 array = (WMPropList *) wmalloc(sizeof(W_PropList));
1356 array->type = WPLArray;
1357 array->d.array = WMCreateArray(WMCountHashTable(plist->d.dict));
1358 array->retainCount = 1;
49e59ab3 dan2001-09-10 03:56:00 +00001359
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001360 enumerator = WMEnumerateHashTable(plist->d.dict);
1361 while ((key = WMNextHashEnumeratorKey(&enumerator))) {
1362 WMAddToArray(array->d.array, WMRetainPropList(key));
1363 }
49e59ab3 dan2001-09-10 03:56:00 +00001364
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001365 return array;
49e59ab3 dan2001-09-10 03:56:00 +00001366}
1367
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001368WMPropList *WMShallowCopyPropList(WMPropList * plist)
49e59ab3 dan2001-09-10 03:56:00 +00001369{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001370 WMPropList *ret = NULL;
1371 WMPropList *key, *item;
1372 WMHashEnumerator e;
1373 WMData *data;
1374 int i;
1375
1376 switch (plist->type) {
1377 case WPLString:
1378 ret = WMCreatePLString(plist->d.string);
1379 break;
1380 case WPLData:
1381 data = WMCreateDataWithData(plist->d.data);
1382 ret = WMCreatePLData(data);
1383 WMReleaseData(data);
1384 break;
1385 case WPLArray:
1386 ret = (WMPropList *) wmalloc(sizeof(W_PropList));
1387 ret->type = WPLArray;
1388 ret->d.array = WMCreateArrayWithArray(plist->d.array);
1389 ret->retainCount = 1;
1390
1391 for (i = 0; i < WMGetArrayItemCount(ret->d.array); i++)
1392 WMRetainPropList(WMGetFromArray(ret->d.array, i));
1393
1394 break;
1395 case WPLDictionary:
1396 ret = WMCreatePLDictionary(NULL, NULL);
1397 e = WMEnumerateHashTable(plist->d.dict);
1398 while (WMNextHashEnumeratorItemAndKey(&e, (void **)&item, (void **)&key)) {
1399 WMPutInPLDictionary(ret, key, item);
1400 }
1401 break;
1402 default:
1403 wwarning(_("Used proplist functions on non-WMPropLists objects"));
1404 wassertrv(False, NULL);
1405 break;
1406 }
1407
1408 return ret;
49e59ab3 dan2001-09-10 03:56:00 +00001409}
1410
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001411WMPropList *WMDeepCopyPropList(WMPropList * plist)
49e59ab3 dan2001-09-10 03:56:00 +00001412{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001413 WMPropList *ret = NULL;
1414 WMPropList *key, *item;
1415 WMHashEnumerator e;
1416 WMData *data;
1417 int i;
1418
1419 switch (plist->type) {
1420 case WPLString:
1421 ret = WMCreatePLString(plist->d.string);
1422 break;
1423 case WPLData:
1424 data = WMCreateDataWithData(plist->d.data);
1425 ret = WMCreatePLData(data);
1426 WMReleaseData(data);
1427 break;
1428 case WPLArray:
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);
1433 }
1434 break;
1435 case WPLDictionary:
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.
1441 */
1442 while (WMNextHashEnumeratorItemAndKey(&e, (void **)&item, (void **)&key)) {
1443 WMHashInsert(ret->d.dict, WMDeepCopyPropList(key), WMDeepCopyPropList(item));
1444 }
1445 break;
1446 default:
1447 wwarning(_("Used proplist functions on non-WMPropLists objects"));
1448 wassertrv(False, NULL);
1449 break;
1450 }
1451
1452 return ret;
49e59ab3 dan2001-09-10 03:56:00 +00001453}
1454
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001455WMPropList *WMCreatePropListFromDescription(char *desc)
0c365cfb dan2001-09-17 01:55:23 +00001456{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001457 WMPropList *plist = NULL;
1458 PLData *pldata;
1459
1460 pldata = (PLData *) wmalloc(sizeof(PLData));
1461 memset(pldata, 0, sizeof(PLData));
1462 pldata->ptr = desc;
1463 pldata->lineNumber = 1;
1464
1465 plist = getPropList(pldata);
1466
1467 if (getNonSpaceChar(pldata) != 0 && plist) {
1468 COMPLAIN(pldata, _("extra data after end of property list"));
1469 /*
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)
1474 */
1475 WMReleasePropList(plist);
1476 plist = NULL;
1477 }
1478
1479 wfree(pldata);
1480
1481 return plist;
0c365cfb dan2001-09-17 01:55:23 +00001482}
1483
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001484char *WMGetPropListDescription(WMPropList * plist, Bool indented)
8bb50a63 dan2001-10-03 02:05:53 +00001485{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001486 return (indented ? indentedDescription(plist, 0) : description(plist));
8bb50a63 dan2001-10-03 02:05:53 +00001487}
1488
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001489WMPropList *WMReadPropListFromFile(char *file)
0c365cfb dan2001-09-17 01:55:23 +00001490{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001491 WMPropList *plist = NULL;
1492 PLData *pldata;
1493 FILE *f;
1494 struct stat stbuf;
1495 size_t length;
1496
1497 f = fopen(file, "rb");
1498 if (!f) {
1499 /* let the user print the error message if he really needs to */
1500 /*wsyserror(_("could not open domain file '%s' for reading"), file); */
1501 return NULL;
1502 }
1503
1504 if (stat(file, &stbuf) == 0) {
1505 length = (size_t) stbuf.st_size;
1506 } else {
1507 wsyserror(_("could not get size for file '%s'"), file);
1508 fclose(f);
1509 return NULL;
1510 }
1511
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;
1517
1518 if (fread(pldata->ptr, length, 1, f) != 1) {
1519 if (ferror(f)) {
1520 wsyserror(_("error reading from file '%s'"), file);
1521 }
1522 plist = NULL;
1523 goto cleanup;
1524 }
1525
1526 pldata->ptr[length] = 0;
1527
1528 plist = getPropList(pldata);
1529
1530 if (getNonSpaceChar(pldata) != 0 && plist) {
1531 COMPLAIN(pldata, _("extra data after end of property list"));
1532 /*
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)
1537 */
1538 WMReleasePropList(plist);
1539 plist = NULL;
1540 }
1541
1542 cleanup:
1543 wfree(pldata->ptr);
1544 wfree(pldata);
1545 fclose(f);
1546
1547 return plist;
0c365cfb dan2001-09-17 01:55:23 +00001548}
2d5a0620 dan2001-09-06 00:55:18 +00001549
558d0fbd dan2001-10-02 00:45:25 +00001550/* TODO: review this function's code */
1551
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001552Bool WMWritePropListToFile(WMPropList * plist, char *path, Bool atomically)
558d0fbd dan2001-10-02 00:45:25 +00001553{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001554 char *thePath = NULL;
1555 char *desc;
1556 FILE *theFile;
558d0fbd dan2001-10-02 00:45:25 +00001557
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001558 if (atomically) {
558d0fbd dan2001-10-02 00:45:25 +00001559#ifdef HAVE_MKSTEMP
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001560 int fd, mask;
558d0fbd dan2001-10-02 00:45:25 +00001561#endif
1562
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001563 /* 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");
558d0fbd dan2001-10-02 00:45:25 +00001567
1568#ifdef HAVE_MKSTEMP
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001569 if ((fd = mkstemp(thePath)) < 0) {
1570 wsyserror(_("mkstemp (%s) failed"), thePath);
1571 goto failure;
1572 }
1573 mask = umask(0);
1574 umask(mask);
1575 fchmod(fd, 0644 & ~mask);
1576 if ((theFile = fdopen(fd, "wb")) == NULL) {
1577 close(fd);
1578 }
558d0fbd dan2001-10-02 00:45:25 +00001579#else
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001580 if (mktemp(thePath) == NULL) {
1581 wsyserror(_("mktemp (%s) failed"), thePath);
1582 goto failure;
1583 }
1584 theFile = fopen(thePath, "wb");
558d0fbd dan2001-10-02 00:45:25 +00001585#endif
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001586 } else {
1587 thePath = wstrdup(path);
1588 theFile = fopen(thePath, "wb");
1589 }
1590
1591 if (theFile == NULL) {
1592 wsyserror(_("open (%s) failed"), thePath);
1593 goto failure;
1594 }
1595
1596 desc = indentedDescription(plist, 0);
1597
1598 if (fprintf(theFile, "%s\n", desc) != strlen(desc) + 1) {
1599 wsyserror(_("writing to file: %s failed"), thePath);
1600 wfree(desc);
1601 goto failure;
1602 }
1603
1604 wfree(desc);
1605
1606 if (fclose(theFile) != 0) {
1607 wsyserror(_("fclose (%s) failed"), thePath);
1608 goto failure;
1609 }
1610
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) */
1614 if (atomically) {
1615 if (rename(thePath, path) != 0) {
1616 wsyserror(_("rename ('%s' to '%s') failed"), thePath, path);
1617 goto failure;
1618 }
1619 }
1620
1621 wfree(thePath);
1622 return True;
1623
1624 failure:
1625 if (atomically) {
1626 unlink(thePath);
1627 wfree(thePath);
1628 }
1629
1630 return False;
558d0fbd dan2001-10-02 00:45:25 +00001631}