~profzoom/ubuntu/quantal/wmaker/bug-1079925

« back to all changes in this revision

Viewing changes to WINGs/proplist.c

  • Committer: Bazaar Package Importer
  • Author(s): Marcelo E. Magallon
  • Date: 2004-11-10 14:05:30 UTC
  • Revision ID: james.westby@ubuntu.com-20041110140530-qpd66b5lm38x7apk
Tags: upstream-0.91.0
ImportĀ upstreamĀ versionĀ 0.91.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
 
 
3
#include <string.h>
 
4
#include <stdarg.h>
 
5
#include <stdio.h>
 
6
#include <stdlib.h>
 
7
#include <sys/types.h>
 
8
#include <sys/stat.h>
 
9
#include <unistd.h>
 
10
#include <ctype.h>
 
11
 
 
12
#include "WUtil.h"
 
13
#include "wconfig.h"
 
14
 
 
15
 
 
16
 
 
17
typedef enum {
 
18
    WPLString     = 0x57504c01,
 
19
    WPLData       = 0x57504c02,
 
20
    WPLArray      = 0x57504c03,
 
21
    WPLDictionary = 0x57504c04
 
22
} WPLType;
 
23
 
 
24
 
 
25
typedef struct W_PropList {
 
26
    WPLType type;
 
27
 
 
28
    union {
 
29
        char *string;
 
30
        WMData *data;
 
31
        WMArray *array;
 
32
        WMHashTable *dict;
 
33
    } d;
 
34
 
 
35
    int retainCount;
 
36
} W_PropList;
 
37
 
 
38
 
 
39
typedef struct PLData {
 
40
    char *ptr;
 
41
    int pos;
 
42
    char *filename;
 
43
    int lineNumber;
 
44
} PLData;
 
45
 
 
46
 
 
47
typedef struct StringBuffer {
 
48
    char *str;
 
49
    int size;
 
50
} StringBuffer;
 
51
 
 
52
 
 
53
static unsigned hashPropList(WMPropList *plist);
 
54
static WMPropList* getPLString(PLData *pldata);
 
55
static WMPropList* getPLQString(PLData *pldata);
 
56
static WMPropList* getPLData(PLData *pldata);
 
57
static WMPropList* getPLArray(PLData *pldata);
 
58
static WMPropList* getPLDictionary(PLData *pldata);
 
59
static WMPropList* getPropList(PLData *pldata);
 
60
 
 
61
 
 
62
 
 
63
typedef unsigned (*hashFunc)(const void*);
 
64
typedef Bool (*isEqualFunc)(const void*, const void*);
 
65
typedef void* (*retainFunc)(const void*);
 
66
typedef void (*releaseFunc)(const void*);
 
67
 
 
68
static const WMHashTableCallbacks WMPropListHashCallbacks = {
 
69
    (hashFunc)hashPropList,
 
70
    (isEqualFunc)WMIsPropListEqualTo,
 
71
    (retainFunc)NULL,
 
72
    (releaseFunc)NULL
 
73
};
 
74
 
 
75
 
 
76
 
 
77
static Bool caseSensitive = True;
 
78
 
 
79
 
 
80
 
 
81
#define BUFFERSIZE           8192
 
82
#define BUFFERSIZE_INCREMENT 1024
 
83
 
 
84
 
 
85
#if 0
 
86
# define DPUT(s) puts(s)
 
87
#else
 
88
# define DPUT(s)
 
89
#endif
 
90
 
 
91
#define COMPLAIN(pld, msg) wwarning(_("syntax error in %s %s, line %i: %s"),\
 
92
    (pld)->filename ? "file" : "PropList",\
 
93
    (pld)->filename ? (pld)->filename : "description",\
 
94
    (pld)->lineNumber, msg)
 
95
 
 
96
#define ISSTRINGABLE(c) (isalnum(c) || (c)=='.' || (c)=='_' || (c)=='/' \
 
97
    || (c)=='+')
 
98
 
 
99
#define CHECK_BUFFER_SIZE(buf, ptr) \
 
100
    if ((ptr) >= (buf).size-1) {\
 
101
    (buf).size += BUFFERSIZE_INCREMENT;\
 
102
    (buf).str = wrealloc((buf).str, (buf).size);\
 
103
    }
 
104
 
 
105
 
 
106
#define inrange(ch, min, max) ((ch)>=(min) && (ch)<=(max))
 
107
#define noquote(ch) (inrange(ch, 'a', 'z') || inrange(ch, 'A', 'Z') || inrange(ch, '0', '9') || ((ch)=='_') || ((ch)=='.') || ((ch)=='$'))
 
108
#define charesc(ch) (inrange(ch, 0x07, 0x0c) || ((ch)=='"') || ((ch)=='\\'))
 
109
#define numesc(ch) (((ch)<=0x06) || inrange(ch, 0x0d, 0x1f) || ((ch)>0x7e))
 
110
#define ishexdigit(ch) (inrange(ch, 'a', 'f') || inrange(ch, 'A', 'F') || inrange(ch, '0', '9'))
 
111
#define char2num(ch) (inrange(ch,'0','9') ? ((ch)-'0') : (inrange(ch,'a','f') ? ((ch)-0x57) : ((ch)-0x37)))
 
112
#define num2char(num) ((num) < 0xa ? ((num)+'0') : ((num)+0x57))
 
113
 
 
114
 
 
115
 
 
116
#define MaxHashLength 64
 
117
 
 
118
static unsigned
 
119
hashPropList(WMPropList *plist)
 
120
{
 
121
    unsigned ret = 0;
 
122
    unsigned ctr = 0;
 
123
    const char *key;
 
124
    int i, len;
 
125
 
 
126
    switch (plist->type) {
 
127
    case WPLString:
 
128
        key = plist->d.string;
 
129
        len = WMIN(strlen(key), MaxHashLength);
 
130
        for (i=0; i<len; i++) {
 
131
            ret ^= tolower(key[i]) << ctr;
 
132
            ctr = (ctr + 1) % sizeof (char *);
 
133
        }
 
134
        /*while (*key) {
 
135
         ret ^= tolower(*key++) << ctr;
 
136
         ctr = (ctr + 1) % sizeof (char *);
 
137
         }*/
 
138
        break;
 
139
 
 
140
    case WPLData:
 
141
        key = WMDataBytes(plist->d.data);
 
142
        len = WMIN(WMGetDataLength(plist->d.data), MaxHashLength);
 
143
        for (i=0; i<len; i++) {
 
144
            ret ^= key[i] << ctr;
 
145
            ctr = (ctr + 1) % sizeof (char *);
 
146
        }
 
147
        break;
 
148
 
 
149
    default:
 
150
        wwarning(_("Only string or data is supported for a proplist dictionary key"));
 
151
        wassertrv(False, 0);
 
152
        break;
 
153
    }
 
154
 
 
155
    return ret;
 
156
}
 
157
 
 
158
static WMPropList*
 
159
retainPropListByCount(WMPropList *plist, int count)
 
160
{
 
161
    WMPropList *key, *value;
 
162
    WMHashEnumerator e;
 
163
    int i;
 
164
 
 
165
    plist->retainCount += count;
 
166
 
 
167
    switch(plist->type) {
 
168
    case WPLString:
 
169
    case WPLData:
 
170
        break;
 
171
    case WPLArray:
 
172
        for (i=0; i<WMGetArrayItemCount(plist->d.array); i++) {
 
173
            retainPropListByCount(WMGetFromArray(plist->d.array, i), count);
 
174
        }
 
175
        break;
 
176
    case WPLDictionary:
 
177
        e = WMEnumerateHashTable(plist->d.dict);
 
178
        while (WMNextHashEnumeratorItemAndKey(&e, (void**)&value, (void**)&key)) {
 
179
            retainPropListByCount(key, count);
 
180
            retainPropListByCount(value, count);
 
181
        }
 
182
        break;
 
183
    default:
 
184
        wwarning(_("Used proplist functions on non-WMPropLists objects"));
 
185
        wassertrv(False, NULL);
 
186
        break;
 
187
    }
 
188
 
 
189
    return plist;
 
190
}
 
191
 
 
192
 
 
193
static void
 
194
releasePropListByCount(WMPropList *plist, int count)
 
195
{
 
196
    WMPropList *key, *value;
 
197
    WMHashEnumerator e;
 
198
    int i;
 
199
 
 
200
    plist->retainCount -= count;
 
201
 
 
202
    switch(plist->type) {
 
203
    case WPLString:
 
204
        if (plist->retainCount < 1) {
 
205
            wfree(plist->d.string);
 
206
            wfree(plist);
 
207
        }
 
208
        break;
 
209
    case WPLData:
 
210
        if (plist->retainCount < 1) {
 
211
            WMReleaseData(plist->d.data);
 
212
            wfree(plist);
 
213
        }
 
214
        break;
 
215
    case WPLArray:
 
216
        for (i=0; i<WMGetArrayItemCount(plist->d.array); i++) {
 
217
            releasePropListByCount(WMGetFromArray(plist->d.array, i), count);
 
218
        }
 
219
        if (plist->retainCount < 1) {
 
220
            WMFreeArray(plist->d.array);
 
221
            wfree(plist);
 
222
        }
 
223
        break;
 
224
    case WPLDictionary:
 
225
        e = WMEnumerateHashTable(plist->d.dict);
 
226
        while (WMNextHashEnumeratorItemAndKey(&e, (void**)&value, (void**)&key)) {
 
227
            releasePropListByCount(key, count);
 
228
            releasePropListByCount(value, count);
 
229
        }
 
230
        if (plist->retainCount < 1) {
 
231
            WMFreeHashTable(plist->d.dict);
 
232
            wfree(plist);
 
233
        }
 
234
        break;
 
235
    default:
 
236
        wwarning(_("Used proplist functions on non-WMPropLists objects"));
 
237
        wassertr(False);
 
238
        break;
 
239
    }
 
240
}
 
241
 
 
242
 
 
243
static char*
 
244
dataDescription(WMPropList *plist)
 
245
{
 
246
    const unsigned char *data;
 
247
    char *retVal;
 
248
    int i, j, length;
 
249
 
 
250
    data = WMDataBytes(plist->d.data);
 
251
    length = WMGetDataLength(plist->d.data);
 
252
 
 
253
    retVal = (char*)wmalloc(2*length+length/4+3);
 
254
 
 
255
    retVal[0] = '<';
 
256
    for (i=0, j=1; i<length; i++) {
 
257
        retVal[j++] = num2char((data[i]>>4) & 0x0f);
 
258
        retVal[j++] = num2char(data[i] & 0x0f);
 
259
        if ((i & 0x03)==3 && i!=length-1) {
 
260
            /* if we've just finished a 32-bit int, add a space */
 
261
            retVal[j++] = ' ';
 
262
        }
 
263
    }
 
264
    retVal[j++] = '>';
 
265
    retVal[j] = '\0';
 
266
 
 
267
    return retVal;
 
268
}
 
269
 
 
270
 
 
271
static char*
 
272
stringDescription(WMPropList *plist)
 
273
{
 
274
    const char *str;
 
275
    char *retVal, *sPtr, *dPtr;
 
276
    int len, quote;
 
277
    unsigned char ch;
 
278
 
 
279
    str = plist->d.string;
 
280
 
 
281
    if (strlen(str) == 0) {
 
282
        return wstrdup("\"\"");
 
283
    }
 
284
 
 
285
    /* FIXME: make this work with unichars. */
 
286
 
 
287
    quote = 0;
 
288
    sPtr = (char*) str;
 
289
    len = 0;
 
290
    while ((ch = *sPtr)) {
 
291
        if (!noquote(ch)) {
 
292
            quote = 1;
 
293
            if (charesc(ch))
 
294
                len++;
 
295
            else if (numesc(ch))
 
296
                len += 3;
 
297
        }
 
298
        sPtr++;
 
299
        len++;
 
300
    }
 
301
 
 
302
    if (quote)
 
303
        len += 2;
 
304
 
 
305
    retVal = (char*)wmalloc(len+1);
 
306
 
 
307
    sPtr = (char*) str;
 
308
    dPtr = retVal;
 
309
 
 
310
    if (quote)
 
311
        *dPtr++ = '"';
 
312
 
 
313
    while ((ch = *sPtr)) {
 
314
        if (charesc(ch)) {
 
315
            *(dPtr++) = '\\';
 
316
            switch (ch) {
 
317
            case '\a': *dPtr = 'a'; break;
 
318
            case '\b': *dPtr = 'b'; break;
 
319
            case '\t': *dPtr = 't'; break;
 
320
            case '\n': *dPtr = 'n'; break;
 
321
            case '\v': *dPtr = 'v'; break;
 
322
            case '\f': *dPtr = 'f'; break;
 
323
            default: *dPtr = ch;  /* " or \ */
 
324
            }
 
325
        } else if (numesc(ch)) {
 
326
            *(dPtr++) = '\\';
 
327
            *(dPtr++) = '0' + ((ch>>6)&07);
 
328
            *(dPtr++) = '0' + ((ch>>3)&07);
 
329
            *dPtr = '0' + (ch&07);
 
330
        } else {
 
331
            *dPtr = ch;
 
332
        }
 
333
        sPtr++;
 
334
        dPtr++;
 
335
    }
 
336
 
 
337
    if (quote)
 
338
        *dPtr++ = '"';
 
339
 
 
340
    *dPtr = '\0';
 
341
 
 
342
    return retVal;
 
343
}
 
344
 
 
345
 
 
346
static char*
 
347
description(WMPropList *plist)
 
348
{
 
349
    WMPropList *key, *val;
 
350
    char *retstr = NULL;
 
351
    char *str, *tmp, *skey, *sval;
 
352
    WMHashEnumerator e;
 
353
    int i;
 
354
 
 
355
    switch (plist->type) {
 
356
    case WPLString:
 
357
        retstr = stringDescription(plist);
 
358
        break;
 
359
    case WPLData:
 
360
        retstr = dataDescription(plist);
 
361
        break;
 
362
    case WPLArray:
 
363
        retstr = wstrdup("(");
 
364
        for (i=0; i<WMGetArrayItemCount(plist->d.array); i++) {
 
365
            str = description(WMGetFromArray(plist->d.array, i));
 
366
            if (i==0) {
 
367
                retstr = wstrappend(retstr, str);
 
368
            } else {
 
369
                tmp = (char *)wmalloc(strlen(retstr)+strlen(str)+3);
 
370
                sprintf(tmp, "%s, %s", retstr, str);
 
371
                wfree(retstr);
 
372
                retstr = tmp;
 
373
            }
 
374
            wfree(str);
 
375
        }
 
376
        retstr = wstrappend(retstr, ")");
 
377
        break;
 
378
    case WPLDictionary:
 
379
        retstr = wstrdup("{");
 
380
        e = WMEnumerateHashTable(plist->d.dict);
 
381
        while (WMNextHashEnumeratorItemAndKey(&e, (void**)&val, (void**)&key)) {
 
382
            skey = description(key);
 
383
            sval = description(val);
 
384
            tmp = (char*)wmalloc(strlen(retstr)+strlen(skey)+strlen(sval)+5);
 
385
            sprintf(tmp, "%s%s = %s;", retstr, skey, sval);
 
386
            wfree(skey);
 
387
            wfree(sval);
 
388
            wfree(retstr);
 
389
            retstr = tmp;
 
390
        }
 
391
        retstr = wstrappend(retstr, "}");
 
392
        break;
 
393
    default:
 
394
        wwarning(_("Used proplist functions on non-WMPropLists objects"));
 
395
        wassertrv(False, NULL);
 
396
        break;
 
397
    }
 
398
 
 
399
    return retstr;
 
400
}
 
401
 
 
402
 
 
403
static char*
 
404
indentedDescription(WMPropList *plist, int level)
 
405
{
 
406
    WMPropList *key, *val;
 
407
    char *retstr = NULL;
 
408
    char *str, *tmp, *skey, *sval;
 
409
    WMHashEnumerator e;
 
410
    int i;
 
411
 
 
412
    if (plist->type==WPLArray/* || plist->type==WPLDictionary*/) {
 
413
        retstr = description(plist);
 
414
 
 
415
        if (retstr && ((2*(level+1) + strlen(retstr)) <= 77)) {
 
416
            return retstr;
 
417
        } else if (retstr) {
 
418
            wfree(retstr);
 
419
            retstr = NULL;
 
420
        }
 
421
    }
 
422
 
 
423
    switch (plist->type) {
 
424
    case WPLString:
 
425
        retstr = stringDescription(plist);
 
426
        break;
 
427
    case WPLData:
 
428
        retstr = dataDescription(plist);
 
429
        break;
 
430
    case WPLArray:
 
431
        retstr = wstrdup("(\n");
 
432
        for (i=0; i<WMGetArrayItemCount(plist->d.array); i++) {
 
433
            str = indentedDescription(WMGetFromArray(plist->d.array, i),
 
434
                                      level+1);
 
435
            if (i==0) {
 
436
                tmp = (char*)wmalloc(2*(level+1)+strlen(retstr)+strlen(str)+1);
 
437
                sprintf(tmp, "%s%*s%s", retstr, 2*(level+1), "", str);
 
438
                wfree(retstr);
 
439
                retstr = tmp;
 
440
            } else {
 
441
                tmp = (char*)wmalloc(2*(level+1)+strlen(retstr)+strlen(str)+3);
 
442
                sprintf(tmp, "%s,\n%*s%s", retstr, 2*(level+1), "", str);
 
443
                wfree(retstr);
 
444
                retstr = tmp;
 
445
            }
 
446
            wfree(str);
 
447
        }
 
448
        tmp = (char*)wmalloc(strlen(retstr) + 2*level + 3);
 
449
        sprintf(tmp, "%s\n%*s)", retstr, 2*level, "");
 
450
        wfree(retstr);
 
451
        retstr = tmp;
 
452
        break;
 
453
    case WPLDictionary:
 
454
        retstr = wstrdup("{\n");
 
455
        e = WMEnumerateHashTable(plist->d.dict);
 
456
        while (WMNextHashEnumeratorItemAndKey(&e, (void**)&val, (void**)&key)) {
 
457
            skey = indentedDescription(key, level+1);
 
458
            sval = indentedDescription(val, level+1);
 
459
            tmp = (char*)wmalloc(2*(level+1) + strlen(retstr) + strlen(skey)
 
460
                                 + strlen(sval) + 6);
 
461
            sprintf(tmp, "%s%*s%s = %s;\n", retstr, 2*(level+1), "",
 
462
                    skey, sval);
 
463
            wfree(skey);
 
464
            wfree(sval);
 
465
            wfree(retstr);
 
466
            retstr = tmp;
 
467
        }
 
468
        tmp = (char*)wmalloc(strlen(retstr) + 2*level + 2);
 
469
        sprintf(tmp, "%s%*s}", retstr, 2*level, "");
 
470
        wfree(retstr);
 
471
        retstr = tmp;
 
472
        break;
 
473
    default:
 
474
        wwarning(_("Used proplist functions on non-WMPropLists objects"));
 
475
        wassertrv(False, NULL);
 
476
        break;
 
477
    }
 
478
 
 
479
    return retstr;
 
480
}
 
481
 
 
482
 
 
483
static INLINE int
 
484
getChar(PLData *pldata)
 
485
{
 
486
    int c;
 
487
 
 
488
    c = pldata->ptr[pldata->pos];
 
489
    if (c==0) {
 
490
        return 0;
 
491
    }
 
492
 
 
493
    pldata->pos++;
 
494
 
 
495
    if (c == '\n')
 
496
        pldata->lineNumber++;
 
497
 
 
498
    return c;
 
499
}
 
500
 
 
501
 
 
502
static INLINE int
 
503
getNonSpaceChar(PLData *pldata)
 
504
{
 
505
    int c;
 
506
 
 
507
    while (1) {
 
508
        c = pldata->ptr[pldata->pos];
 
509
        if (c==0) {
 
510
            break;
 
511
        }
 
512
        pldata->pos++;
 
513
        if (c == '\n') {
 
514
            pldata->lineNumber++;
 
515
        } else if (!isspace(c)) {
 
516
            break;
 
517
        }
 
518
    }
 
519
 
 
520
    return c;
 
521
}
 
522
 
 
523
 
 
524
static char*
 
525
unescapestr(char *src)
 
526
{
 
527
    char *dest = wmalloc(strlen(src)+1);
 
528
    char *sPtr, *dPtr;
 
529
    char ch;
 
530
 
 
531
 
 
532
    for (sPtr=src, dPtr=dest; *sPtr;  sPtr++, dPtr++) {
 
533
        if(*sPtr != '\\') {
 
534
            *dPtr = *sPtr;
 
535
        } else {
 
536
            ch = *(++sPtr);
 
537
            if((ch>='0') && (ch<='3')) {
 
538
                /* assume next 2 chars are octal too */
 
539
                *dPtr = ((ch & 07) << 6);
 
540
                *dPtr |= ((*(++sPtr)&07)<<3);
 
541
                *dPtr |= *(++sPtr)&07;
 
542
            } else {
 
543
                switch(ch) {
 
544
                case 'a' : *dPtr = '\a'; break;
 
545
                case 'b' : *dPtr = '\b'; break;
 
546
                case 't' : *dPtr = '\t'; break;
 
547
                case 'r' : *dPtr = '\r'; break;
 
548
                case 'n' : *dPtr = '\n'; break;
 
549
                case 'v' : *dPtr = '\v'; break;
 
550
                case 'f' : *dPtr = '\f'; break;
 
551
                default  : *dPtr = *sPtr;
 
552
                }
 
553
            }
 
554
        }
 
555
    }
 
556
 
 
557
    *dPtr = 0;
 
558
 
 
559
    return dest;
 
560
}
 
561
 
 
562
 
 
563
static WMPropList*
 
564
getPLString(PLData *pldata)
 
565
{
 
566
    WMPropList *plist;
 
567
    StringBuffer sBuf;
 
568
    int ptr = 0;
 
569
    int c;
 
570
 
 
571
    sBuf.str = wmalloc(BUFFERSIZE);
 
572
    sBuf.size = BUFFERSIZE;
 
573
 
 
574
    while (1) {
 
575
        c = getChar(pldata);
 
576
        if (ISSTRINGABLE(c)) {
 
577
            CHECK_BUFFER_SIZE(sBuf, ptr);
 
578
            sBuf.str[ptr++] = c;
 
579
        } else {
 
580
            if (c != 0) {
 
581
                pldata->pos--;
 
582
            }
 
583
            break;
 
584
        }
 
585
    }
 
586
 
 
587
    sBuf.str[ptr] = 0;
 
588
 
 
589
    if (ptr == 0) {
 
590
        plist = NULL;
 
591
    } else {
 
592
        char *tmp = unescapestr(sBuf.str);
 
593
        plist = WMCreatePLString(tmp);
 
594
        wfree(tmp);
 
595
    }
 
596
 
 
597
    wfree(sBuf.str);
 
598
 
 
599
    return plist;
 
600
}
 
601
 
 
602
 
 
603
static WMPropList*
 
604
getPLQString(PLData *pldata)
 
605
{
 
606
    WMPropList *plist;
 
607
    int ptr = 0, escaping = 0, ok = 1;
 
608
    int c;
 
609
    StringBuffer sBuf;
 
610
 
 
611
    sBuf.str = wmalloc(BUFFERSIZE);
 
612
    sBuf.size = BUFFERSIZE;
 
613
 
 
614
    while (1) {
 
615
        c = getChar(pldata);
 
616
        if (!escaping) {
 
617
            if (c == '\\') {
 
618
                escaping = 1;
 
619
                continue;
 
620
            } else if (c == '"') {
 
621
                break;
 
622
            }
 
623
        } else {
 
624
            CHECK_BUFFER_SIZE(sBuf, ptr);
 
625
            sBuf.str[ptr++] = '\\';
 
626
            escaping = 0;
 
627
        }
 
628
 
 
629
        if (c == 0) {
 
630
            COMPLAIN(pldata, _("unterminated PropList string"));
 
631
            ok = 0;
 
632
            break;
 
633
        } else {
 
634
            CHECK_BUFFER_SIZE(sBuf, ptr);
 
635
            sBuf.str[ptr++] = c;
 
636
        }
 
637
    }
 
638
 
 
639
    sBuf.str[ptr] = 0;
 
640
 
 
641
    if (!ok) {
 
642
        plist = NULL;
 
643
    } else {
 
644
        char *tmp = unescapestr(sBuf.str);
 
645
        plist = WMCreatePLString(tmp);
 
646
        wfree(tmp);
 
647
    }
 
648
 
 
649
    wfree(sBuf.str);
 
650
 
 
651
    return plist;
 
652
}
 
653
 
 
654
 
 
655
static WMPropList*
 
656
getPLData(PLData *pldata)
 
657
{
 
658
    int ok = 1;
 
659
    int len = 0;
 
660
    int c1, c2;
 
661
    unsigned char buf[BUFFERSIZE], byte;
 
662
    WMPropList *plist;
 
663
    WMData *data;
 
664
 
 
665
    data = WMCreateDataWithCapacity(0);
 
666
 
 
667
    while (1) {
 
668
        c1 = getNonSpaceChar(pldata);
 
669
        if (c1 == 0) {
 
670
            COMPLAIN(pldata, _("unterminated PropList data"));
 
671
            ok = 0;
 
672
            break;
 
673
        } else if (c1=='>') {
 
674
            break;
 
675
        } else if (ishexdigit(c1)) {
 
676
            c2 = getNonSpaceChar(pldata);
 
677
            if (c2==0 || c2=='>') {
 
678
                COMPLAIN(pldata, _("unterminated PropList data (missing hexdigit)"));
 
679
                ok = 0;
 
680
                break;
 
681
            } else if (ishexdigit(c2)) {
 
682
                byte = char2num(c1) << 4;
 
683
                byte |= char2num(c2);
 
684
                buf[len++] = byte;
 
685
                if (len == sizeof(buf)) {
 
686
                    WMAppendDataBytes(data, buf, len);
 
687
                    len = 0;
 
688
                }
 
689
            } else {
 
690
                COMPLAIN(pldata, _("non hexdigit character in PropList data"));
 
691
                ok = 0;
 
692
                break;
 
693
            }
 
694
        } else {
 
695
            COMPLAIN(pldata, _("non hexdigit character in PropList data"));
 
696
            ok = 0;
 
697
            break;
 
698
        }
 
699
    }
 
700
 
 
701
    if (!ok) {
 
702
        WMReleaseData(data);
 
703
        return NULL;
 
704
    }
 
705
 
 
706
    if (len > 0)
 
707
        WMAppendDataBytes(data, buf, len);
 
708
 
 
709
    plist = WMCreatePLData(data);
 
710
    WMReleaseData(data);
 
711
 
 
712
    return plist;
 
713
}
 
714
 
 
715
 
 
716
static WMPropList*
 
717
getPLArray(PLData *pldata)
 
718
{
 
719
    Bool first = True;
 
720
    int ok=1;
 
721
    int c;
 
722
    WMPropList *array, *obj;
 
723
 
 
724
    array = WMCreatePLArray(NULL);
 
725
 
 
726
    while (1) {
 
727
        c = getNonSpaceChar(pldata);
 
728
        if (c == 0) {
 
729
            COMPLAIN(pldata, _("unterminated PropList array"));
 
730
            ok = 0;
 
731
            break;
 
732
        } else if (c == ')') {
 
733
            break;
 
734
        } else if (c == ',') {
 
735
            /* continue normally */
 
736
        } else if (!first) {
 
737
            COMPLAIN(pldata, _("missing or unterminated PropList array"));
 
738
            ok = 0;
 
739
            break;
 
740
        } else {
 
741
            pldata->pos--;
 
742
        }
 
743
        first = False;
 
744
 
 
745
        obj = getPropList(pldata);
 
746
        if (!obj) {
 
747
            COMPLAIN(pldata, _("could not get PropList array element"));
 
748
            ok = 0;
 
749
            break;
 
750
        }
 
751
        WMAddToPLArray(array, obj);
 
752
        WMReleasePropList(obj);
 
753
    }
 
754
 
 
755
    if (!ok) {
 
756
        WMReleasePropList(array);
 
757
        array = NULL;
 
758
    }
 
759
 
 
760
    return array;
 
761
}
 
762
 
 
763
 
 
764
static WMPropList*
 
765
getPLDictionary(PLData *pldata)
 
766
{
 
767
    int ok = 1;
 
768
    int c;
 
769
    WMPropList *dict, *key, *value;
 
770
 
 
771
    dict = WMCreatePLDictionary(NULL, NULL);
 
772
 
 
773
    while (1) {
 
774
        c = getNonSpaceChar(pldata);
 
775
        if (c==0) {
 
776
            COMPLAIN(pldata, _("unterminated PropList dictionary"));
 
777
            ok = 0;
 
778
            break;
 
779
        } else if (c=='}') {
 
780
            break;
 
781
        }
 
782
 
 
783
        DPUT("getting PropList dictionary key");
 
784
        if (c == '<') {
 
785
            key = getPLData(pldata);
 
786
        } else if (c == '"') {
 
787
            key = getPLQString(pldata);
 
788
        } else if (ISSTRINGABLE(c)) {
 
789
            pldata->pos--;
 
790
            key = getPLString(pldata);
 
791
        } else {
 
792
            if (c == '=') {
 
793
                COMPLAIN(pldata, _("missing PropList dictionary key"));
 
794
            } else {
 
795
                COMPLAIN(pldata, _("missing PropList dictionary entry key "
 
796
                                   "or unterminated dictionary"));
 
797
            }
 
798
            ok = 0;
 
799
            break;
 
800
        }
 
801
 
 
802
        if (!key) {
 
803
            COMPLAIN(pldata, _("error parsing PropList dictionary key"));
 
804
            ok = 0;
 
805
            break;
 
806
        }
 
807
 
 
808
        c = getNonSpaceChar(pldata);
 
809
        if (c != '=') {
 
810
            WMReleasePropList(key);
 
811
            COMPLAIN(pldata, _("missing = in PropList dictionary entry"));
 
812
            ok = 0;
 
813
            break;
 
814
        }
 
815
 
 
816
        DPUT("getting PropList dictionary entry value for key");
 
817
        value = getPropList(pldata);
 
818
        if (!value) {
 
819
            COMPLAIN(pldata, _("error parsing PropList dictionary entry value"));
 
820
            WMReleasePropList(key);
 
821
            ok = 0;
 
822
            break;
 
823
        }
 
824
 
 
825
        c = getNonSpaceChar(pldata);
 
826
        if (c != ';') {
 
827
            COMPLAIN(pldata, _("missing ; in PropList dictionary entry"));
 
828
            WMReleasePropList(key);
 
829
            WMReleasePropList(value);
 
830
            ok = 0;
 
831
            break;
 
832
        }
 
833
 
 
834
        WMPutInPLDictionary(dict, key, value);
 
835
        WMReleasePropList(key);
 
836
        WMReleasePropList(value);
 
837
    }
 
838
 
 
839
    if (!ok) {
 
840
        WMReleasePropList(dict);
 
841
        dict = NULL;
 
842
    }
 
843
 
 
844
    return dict;
 
845
}
 
846
 
 
847
 
 
848
static WMPropList*
 
849
getPropList(PLData *pldata)
 
850
{
 
851
    WMPropList *plist;
 
852
    int c;
 
853
 
 
854
    c = getNonSpaceChar(pldata);
 
855
 
 
856
    switch(c) {
 
857
    case 0:
 
858
        DPUT("End of PropList");
 
859
        plist = NULL;
 
860
        break;
 
861
 
 
862
    case '{':
 
863
        DPUT("Getting PropList dictionary");
 
864
        plist = getPLDictionary(pldata);
 
865
        break;
 
866
 
 
867
    case '(':
 
868
        DPUT("Getting PropList array");
 
869
        plist = getPLArray(pldata);
 
870
        break;
 
871
 
 
872
    case '<':
 
873
        DPUT("Getting PropList data");
 
874
        plist = getPLData(pldata);
 
875
        break;
 
876
 
 
877
    case '"':
 
878
        DPUT("Getting PropList quoted string");
 
879
        plist = getPLQString(pldata);
 
880
        break;
 
881
 
 
882
    default:
 
883
        if (ISSTRINGABLE(c)) {
 
884
            DPUT("Getting PropList string");
 
885
            pldata->pos--;
 
886
            plist = getPLString(pldata);
 
887
        } else {
 
888
            COMPLAIN(pldata, _("was expecting a string, data, array or "
 
889
                               "dictionary. If it's a string, try enclosing "
 
890
                               "it with \"."));
 
891
            if (c=='#' || c=='/') {
 
892
                wwarning(_("Comments are not allowed inside WindowMaker owned"
 
893
                           " domain files."));
 
894
            }
 
895
            plist = NULL;
 
896
        }
 
897
        break;
 
898
    }
 
899
 
 
900
    return plist;
 
901
}
 
902
 
 
903
 
 
904
void
 
905
WMPLSetCaseSensitive(Bool caseSensitiveness)
 
906
{
 
907
    caseSensitive = caseSensitiveness;
 
908
}
 
909
 
 
910
 
 
911
WMPropList*
 
912
WMCreatePLString(char *str)
 
913
{
 
914
    WMPropList *plist;
 
915
 
 
916
    wassertrv(str!=NULL, NULL);
 
917
 
 
918
    plist = (WMPropList*)wmalloc(sizeof(W_PropList));
 
919
 
 
920
    plist->type = WPLString;
 
921
    plist->d.string = wstrdup(str);
 
922
    plist->retainCount = 1;
 
923
 
 
924
    return plist;
 
925
}
 
926
 
 
927
 
 
928
WMPropList*
 
929
WMCreatePLData(WMData *data)
 
930
{
 
931
    WMPropList *plist;
 
932
 
 
933
    wassertrv(data!=NULL, NULL);
 
934
 
 
935
    plist = (WMPropList*)wmalloc(sizeof(W_PropList));
 
936
 
 
937
    plist->type = WPLData;
 
938
    plist->d.data = WMRetainData(data);
 
939
    plist->retainCount = 1;
 
940
 
 
941
    return plist;
 
942
}
 
943
 
 
944
 
 
945
WMPropList*
 
946
WMCreatePLDataWithBytes(unsigned char *bytes, unsigned int length)
 
947
{
 
948
    WMPropList *plist;
 
949
 
 
950
    wassertrv(bytes!=NULL, NULL);
 
951
 
 
952
    plist = (WMPropList*)wmalloc(sizeof(W_PropList));
 
953
 
 
954
    plist->type = WPLData;
 
955
    plist->d.data = WMCreateDataWithBytes(bytes, length);
 
956
    plist->retainCount = 1;
 
957
 
 
958
    return plist;
 
959
}
 
960
 
 
961
 
 
962
WMPropList*
 
963
WMCreatePLDataWithBytesNoCopy(unsigned char *bytes, unsigned int length,
 
964
                              WMFreeDataProc *destructor)
 
965
{
 
966
    WMPropList *plist;
 
967
 
 
968
    wassertrv(bytes!=NULL, NULL);
 
969
 
 
970
    plist = (WMPropList*)wmalloc(sizeof(W_PropList));
 
971
 
 
972
    plist->type = WPLData;
 
973
    plist->d.data = WMCreateDataWithBytesNoCopy(bytes, length, destructor);
 
974
    plist->retainCount = 1;
 
975
 
 
976
    return plist;
 
977
}
 
978
 
 
979
 
 
980
WMPropList*
 
981
WMCreatePLArray(WMPropList *elem, ...)
 
982
{
 
983
    WMPropList *plist, *nelem;
 
984
    va_list ap;
 
985
 
 
986
    plist = (WMPropList*)wmalloc(sizeof(W_PropList));
 
987
    plist->type = WPLArray;
 
988
    plist->d.array = WMCreateArray(4);
 
989
    plist->retainCount = 1;
 
990
 
 
991
    if (!elem)
 
992
        return plist;
 
993
 
 
994
    WMAddToArray(plist->d.array, WMRetainPropList(elem));
 
995
 
 
996
    va_start(ap, elem);
 
997
 
 
998
    while (1) {
 
999
        nelem = va_arg(ap, WMPropList*);
 
1000
        if(!nelem) {
 
1001
            va_end(ap);
 
1002
            return plist;
 
1003
        }
 
1004
        WMAddToArray(plist->d.array, WMRetainPropList(nelem));
 
1005
    }
 
1006
}
 
1007
 
 
1008
 
 
1009
WMPropList*
 
1010
WMCreatePLDictionary(WMPropList *key, WMPropList *value, ...)
 
1011
{
 
1012
    WMPropList *plist, *nkey, *nvalue, *k, *v;
 
1013
    va_list ap;
 
1014
 
 
1015
    plist = (WMPropList*)wmalloc(sizeof(W_PropList));
 
1016
    plist->type = WPLDictionary;
 
1017
    plist->d.dict = WMCreateHashTable(WMPropListHashCallbacks);
 
1018
    plist->retainCount = 1;
 
1019
 
 
1020
    if (!key || !value)
 
1021
        return plist;
 
1022
 
 
1023
    WMHashInsert(plist->d.dict, WMRetainPropList(key), WMRetainPropList(value));
 
1024
 
 
1025
    va_start(ap, value);
 
1026
 
 
1027
    while (1) {
 
1028
        nkey = va_arg(ap, WMPropList*);
 
1029
        if (!nkey) {
 
1030
            va_end(ap);
 
1031
            return plist;
 
1032
        }
 
1033
        nvalue = va_arg(ap, WMPropList*);
 
1034
        if (!nvalue) {
 
1035
            va_end(ap);
 
1036
            return plist;
 
1037
        }
 
1038
        if (WMHashGetItemAndKey(plist->d.dict, nkey, (void**)&v, (void**)&k)) {
 
1039
            WMHashRemove(plist->d.dict, k);
 
1040
            WMReleasePropList(k);
 
1041
            WMReleasePropList(v);
 
1042
        }
 
1043
        WMHashInsert(plist->d.dict, WMRetainPropList(nkey),
 
1044
                     WMRetainPropList(nvalue));
 
1045
    }
 
1046
}
 
1047
 
 
1048
 
 
1049
WMPropList*
 
1050
WMRetainPropList(WMPropList *plist)
 
1051
{
 
1052
    WMPropList *key, *value;
 
1053
    WMHashEnumerator e;
 
1054
    int i;
 
1055
 
 
1056
    plist->retainCount++;
 
1057
 
 
1058
    switch(plist->type) {
 
1059
    case WPLString:
 
1060
    case WPLData:
 
1061
        break;
 
1062
    case WPLArray:
 
1063
        for (i=0; i<WMGetArrayItemCount(plist->d.array); i++) {
 
1064
            WMRetainPropList(WMGetFromArray(plist->d.array, i));
 
1065
        }
 
1066
        break;
 
1067
    case WPLDictionary:
 
1068
        e = WMEnumerateHashTable(plist->d.dict);
 
1069
        while (WMNextHashEnumeratorItemAndKey(&e, (void**)&value, (void**)&key)) {
 
1070
            WMRetainPropList(key);
 
1071
            WMRetainPropList(value);
 
1072
        }
 
1073
        break;
 
1074
    default:
 
1075
        wwarning(_("Used proplist functions on non-WMPropLists objects"));
 
1076
        wassertrv(False, NULL);
 
1077
        break;
 
1078
    }
 
1079
 
 
1080
    return plist;
 
1081
}
 
1082
 
 
1083
 
 
1084
void
 
1085
WMReleasePropList(WMPropList *plist)
 
1086
{
 
1087
    WMPropList *key, *value;
 
1088
    WMHashEnumerator e;
 
1089
    int i;
 
1090
 
 
1091
    plist->retainCount--;
 
1092
 
 
1093
    switch(plist->type) {
 
1094
    case WPLString:
 
1095
        if (plist->retainCount < 1) {
 
1096
            wfree(plist->d.string);
 
1097
            wfree(plist);
 
1098
        }
 
1099
        break;
 
1100
    case WPLData:
 
1101
        if (plist->retainCount < 1) {
 
1102
            WMReleaseData(plist->d.data);
 
1103
            wfree(plist);
 
1104
        }
 
1105
        break;
 
1106
    case WPLArray:
 
1107
        for (i=0; i<WMGetArrayItemCount(plist->d.array); i++) {
 
1108
            WMReleasePropList(WMGetFromArray(plist->d.array, i));
 
1109
        }
 
1110
        if (plist->retainCount < 1) {
 
1111
            WMFreeArray(plist->d.array);
 
1112
            wfree(plist);
 
1113
        }
 
1114
        break;
 
1115
    case WPLDictionary:
 
1116
        e = WMEnumerateHashTable(plist->d.dict);
 
1117
        while (WMNextHashEnumeratorItemAndKey(&e, (void**)&value, (void**)&key)) {
 
1118
            WMReleasePropList(key);
 
1119
            WMReleasePropList(value);
 
1120
        }
 
1121
        if (plist->retainCount < 1) {
 
1122
            WMFreeHashTable(plist->d.dict);
 
1123
            wfree(plist);
 
1124
        }
 
1125
        break;
 
1126
    default:
 
1127
        wwarning(_("Used proplist functions on non-WMPropLists objects"));
 
1128
        wassertr(False);
 
1129
        break;
 
1130
    }
 
1131
}
 
1132
 
 
1133
 
 
1134
void
 
1135
WMInsertInPLArray(WMPropList *plist, int index, WMPropList *item)
 
1136
{
 
1137
    wassertr(plist->type==WPLArray);
 
1138
 
 
1139
    retainPropListByCount(item, plist->retainCount);
 
1140
    WMInsertInArray(plist->d.array, index, item);
 
1141
}
 
1142
 
 
1143
 
 
1144
void
 
1145
WMAddToPLArray(WMPropList *plist, WMPropList *item)
 
1146
{
 
1147
    wassertr(plist->type==WPLArray);
 
1148
 
 
1149
    retainPropListByCount(item, plist->retainCount);
 
1150
    WMAddToArray(plist->d.array, item);
 
1151
}
 
1152
 
 
1153
 
 
1154
void
 
1155
WMDeleteFromPLArray(WMPropList *plist, int index)
 
1156
{
 
1157
    WMPropList *item;
 
1158
 
 
1159
    wassertr(plist->type==WPLArray);
 
1160
 
 
1161
    item = WMGetFromArray(plist->d.array, index);
 
1162
    if (item != NULL) {
 
1163
        WMDeleteFromArray(plist->d.array, index);
 
1164
        releasePropListByCount(item, plist->retainCount);
 
1165
    }
 
1166
}
 
1167
 
 
1168
 
 
1169
void
 
1170
WMRemoveFromPLArray(WMPropList *plist, WMPropList *item)
 
1171
{
 
1172
    WMPropList *iPtr;
 
1173
    int i;
 
1174
 
 
1175
    wassertr(plist->type==WPLArray);
 
1176
 
 
1177
    for (i=0; i<WMGetArrayItemCount(plist->d.array); i++) {
 
1178
        iPtr = WMGetFromArray(plist->d.array, i);
 
1179
        if (WMIsPropListEqualTo(item, iPtr)) {
 
1180
            WMDeleteFromArray(plist->d.array, i);
 
1181
            releasePropListByCount(iPtr, plist->retainCount);
 
1182
            break;
 
1183
        }
 
1184
    }
 
1185
}
 
1186
 
 
1187
 
 
1188
void
 
1189
WMPutInPLDictionary(WMPropList *plist, WMPropList *key, WMPropList *value)
 
1190
{
 
1191
    wassertr(plist->type==WPLDictionary);
 
1192
 
 
1193
    /*WMRetainPropList(key);*/
 
1194
    WMRemoveFromPLDictionary(plist, key);
 
1195
    retainPropListByCount(key, plist->retainCount);
 
1196
    retainPropListByCount(value, plist->retainCount);
 
1197
    WMHashInsert(plist->d.dict, key, value);
 
1198
    /*WMReleasePropList(key);*/
 
1199
}
 
1200
 
 
1201
 
 
1202
void
 
1203
WMRemoveFromPLDictionary(WMPropList *plist, WMPropList *key)
 
1204
{
 
1205
    WMPropList *k, *v;
 
1206
 
 
1207
    wassertr(plist->type==WPLDictionary);
 
1208
 
 
1209
    if (WMHashGetItemAndKey(plist->d.dict, key, (void**)&v, (void**)&k)) {
 
1210
        WMHashRemove(plist->d.dict, k);
 
1211
        releasePropListByCount(k, plist->retainCount);
 
1212
        releasePropListByCount(v, plist->retainCount);
 
1213
    }
 
1214
}
 
1215
 
 
1216
 
 
1217
WMPropList*
 
1218
WMMergePLDictionaries(WMPropList *dest, WMPropList *source, Bool recursive)
 
1219
{
 
1220
    WMPropList *key, *value, *dvalue;
 
1221
    WMHashEnumerator e;
 
1222
 
 
1223
    wassertr(source->type==WPLDictionary && dest->type==WPLDictionary);
 
1224
 
 
1225
    if (source == dest)
 
1226
        return dest;
 
1227
 
 
1228
    e = WMEnumerateHashTable(source->d.dict);
 
1229
    while (WMNextHashEnumeratorItemAndKey(&e, (void**)&value, (void**)&key)) {
 
1230
        if (recursive && value->type==WPLDictionary) {
 
1231
            dvalue = WMHashGet(dest->d.dict, key);
 
1232
            if (dvalue && dvalue->type==WPLDictionary) {
 
1233
                WMMergePLDictionaries(dvalue, value, True);
 
1234
            } else {
 
1235
                WMPutInPLDictionary(dest, key, value);
 
1236
            }
 
1237
        } else {
 
1238
            WMPutInPLDictionary(dest, key, value);
 
1239
        }
 
1240
    }
 
1241
 
 
1242
    return dest;
 
1243
}
 
1244
 
 
1245
 
 
1246
WMPropList*
 
1247
WMSubtractPLDictionaries(WMPropList *dest, WMPropList *source, Bool recursive)
 
1248
{
 
1249
    WMPropList *key, *value, *dvalue;
 
1250
    WMHashEnumerator e;
 
1251
 
 
1252
    wassertr(source->type==WPLDictionary && dest->type==WPLDictionary);
 
1253
 
 
1254
    if (source == dest) {
 
1255
        WMPropList *keys = WMGetPLDictionaryKeys(dest);
 
1256
        int i;
 
1257
 
 
1258
        for (i=0; i<WMGetArrayItemCount(keys->d.array); i++) {
 
1259
            WMRemoveFromPLDictionary(dest, WMGetFromArray(keys->d.array, i));
 
1260
        }
 
1261
        return dest;
 
1262
    }
 
1263
 
 
1264
    e = WMEnumerateHashTable(source->d.dict);
 
1265
    while (WMNextHashEnumeratorItemAndKey(&e, (void**)&value, (void**)&key)) {
 
1266
        dvalue = WMHashGet(dest->d.dict, key);
 
1267
        if (!dvalue)
 
1268
            continue;
 
1269
        if (WMIsPropListEqualTo(value, dvalue)) {
 
1270
            WMRemoveFromPLDictionary(dest, key);
 
1271
        } else if (recursive && value->type==WPLDictionary &&
 
1272
                   dvalue->type==WPLDictionary) {
 
1273
            WMSubtractPLDictionaries(dvalue, value, True);
 
1274
        }
 
1275
    }
 
1276
 
 
1277
    return dest;
 
1278
}
 
1279
 
 
1280
 
 
1281
int
 
1282
WMGetPropListItemCount(WMPropList *plist)
 
1283
{
 
1284
    switch(plist->type) {
 
1285
    case WPLString:
 
1286
    case WPLData:
 
1287
        return 0; /* should this be 1 instead? */
 
1288
    case WPLArray:
 
1289
        return WMGetArrayItemCount(plist->d.array);
 
1290
    case WPLDictionary:
 
1291
        return (int)WMCountHashTable(plist->d.dict);
 
1292
    default:
 
1293
        wwarning(_("Used proplist functions on non-WMPropLists objects"));
 
1294
        wassertrv(False, 0);
 
1295
        break;
 
1296
    }
 
1297
 
 
1298
    return 0;
 
1299
}
 
1300
 
 
1301
 
 
1302
Bool
 
1303
WMIsPLString(WMPropList *plist)
 
1304
{
 
1305
    return (plist->type == WPLString);
 
1306
}
 
1307
 
 
1308
 
 
1309
Bool
 
1310
WMIsPLData(WMPropList *plist)
 
1311
{
 
1312
    return (plist->type == WPLData);
 
1313
}
 
1314
 
 
1315
 
 
1316
Bool
 
1317
WMIsPLArray(WMPropList *plist)
 
1318
{
 
1319
    return (plist->type == WPLArray);
 
1320
}
 
1321
 
 
1322
 
 
1323
Bool
 
1324
WMIsPLDictionary(WMPropList *plist)
 
1325
{
 
1326
    return (plist->type == WPLDictionary);
 
1327
}
 
1328
 
 
1329
 
 
1330
Bool
 
1331
WMIsPropListEqualTo(WMPropList *plist, WMPropList *other)
 
1332
{
 
1333
    WMPropList *key1, *item1, *item2;
 
1334
    WMHashEnumerator enumerator;
 
1335
    int n, i;
 
1336
 
 
1337
    if (plist->type != other->type)
 
1338
        return False;
 
1339
 
 
1340
    switch(plist->type) {
 
1341
    case WPLString:
 
1342
        if (caseSensitive) {
 
1343
            return (strcmp(plist->d.string, other->d.string) == 0);
 
1344
        } else {
 
1345
            return (strcasecmp(plist->d.string, other->d.string) == 0);
 
1346
        }
 
1347
    case WPLData:
 
1348
        return WMIsDataEqualToData(plist->d.data, other->d.data);
 
1349
    case WPLArray:
 
1350
        n = WMGetArrayItemCount(plist->d.array);
 
1351
        if (n != WMGetArrayItemCount(other->d.array))
 
1352
            return False;
 
1353
        for (i=0; i<n; i++) {
 
1354
            item1 = WMGetFromArray(plist->d.array, i);
 
1355
            item2 = WMGetFromArray(other->d.array, i);
 
1356
            if (!WMIsPropListEqualTo(item1, item2))
 
1357
                return False;
 
1358
        }
 
1359
        return True;
 
1360
    case WPLDictionary:
 
1361
        if (WMCountHashTable(plist->d.dict) != WMCountHashTable(other->d.dict))
 
1362
            return False;
 
1363
        enumerator = WMEnumerateHashTable(plist->d.dict);
 
1364
        while (WMNextHashEnumeratorItemAndKey(&enumerator, (void**)&item1,
 
1365
                                              (void**)&key1)) {
 
1366
            item2 = WMHashGet(other->d.dict, key1);
 
1367
            if (!item2 || !item1 || !WMIsPropListEqualTo(item1, item2))
 
1368
                return False;
 
1369
        }
 
1370
        return True;
 
1371
    default:
 
1372
        wwarning(_("Used proplist functions on non-WMPropLists objects"));
 
1373
        wassertrv(False, False);
 
1374
        break;
 
1375
    }
 
1376
 
 
1377
    return False;
 
1378
}
 
1379
 
 
1380
 
 
1381
char*
 
1382
WMGetFromPLString(WMPropList *plist)
 
1383
{
 
1384
    wassertrv(plist->type==WPLString, NULL);
 
1385
 
 
1386
    return plist->d.string;
 
1387
}
 
1388
 
 
1389
 
 
1390
WMData*
 
1391
WMGetFromPLData(WMPropList *plist)
 
1392
{
 
1393
    wassertrv(plist->type==WPLData, NULL);
 
1394
 
 
1395
    return plist->d.data;
 
1396
}
 
1397
 
 
1398
 
 
1399
const unsigned char*
 
1400
WMGetPLDataBytes(WMPropList *plist)
 
1401
{
 
1402
    wassertrv(plist->type==WPLData, NULL);
 
1403
 
 
1404
    return WMDataBytes(plist->d.data);
 
1405
}
 
1406
 
 
1407
 
 
1408
int
 
1409
WMGetPLDataLength(WMPropList *plist)
 
1410
{
 
1411
    wassertrv(plist->type==WPLData, 0);
 
1412
 
 
1413
    return WMGetDataLength(plist->d.data);
 
1414
}
 
1415
 
 
1416
 
 
1417
WMPropList*
 
1418
WMGetFromPLArray(WMPropList *plist, int index)
 
1419
{
 
1420
    wassertrv(plist->type==WPLArray, NULL);
 
1421
 
 
1422
    return WMGetFromArray(plist->d.array, index);
 
1423
}
 
1424
 
 
1425
 
 
1426
WMPropList*
 
1427
WMGetFromPLDictionary(WMPropList *plist, WMPropList *key)
 
1428
{
 
1429
    wassertrv(plist->type==WPLDictionary, NULL);
 
1430
 
 
1431
    return WMHashGet(plist->d.dict, key);
 
1432
}
 
1433
 
 
1434
 
 
1435
WMPropList*
 
1436
WMGetPLDictionaryKeys(WMPropList *plist)
 
1437
{
 
1438
    WMPropList *array, *key;
 
1439
    WMHashEnumerator enumerator;
 
1440
 
 
1441
    wassertrv(plist->type==WPLDictionary, NULL);
 
1442
 
 
1443
    array = (WMPropList*)wmalloc(sizeof(W_PropList));
 
1444
    array->type = WPLArray;
 
1445
    array->d.array = WMCreateArray(WMCountHashTable(plist->d.dict));
 
1446
    array->retainCount = 1;
 
1447
 
 
1448
    enumerator = WMEnumerateHashTable(plist->d.dict);
 
1449
    while ((key = WMNextHashEnumeratorKey(&enumerator))) {
 
1450
        WMAddToArray(array->d.array, WMRetainPropList(key));
 
1451
    }
 
1452
 
 
1453
    return array;
 
1454
}
 
1455
 
 
1456
 
 
1457
WMPropList*
 
1458
WMShallowCopyPropList(WMPropList *plist)
 
1459
{
 
1460
    WMPropList *ret = NULL;
 
1461
    WMPropList *key, *item;
 
1462
    WMHashEnumerator e;
 
1463
    WMData *data;
 
1464
    int i;
 
1465
 
 
1466
    switch(plist->type) {
 
1467
    case WPLString:
 
1468
        ret = WMCreatePLString(plist->d.string);
 
1469
        break;
 
1470
    case WPLData:
 
1471
        data = WMCreateDataWithData(plist->d.data);
 
1472
        ret = WMCreatePLData(data);
 
1473
        WMReleaseData(data);
 
1474
        break;
 
1475
    case WPLArray:
 
1476
        ret = (WMPropList*)wmalloc(sizeof(W_PropList));
 
1477
        ret->type = WPLArray;
 
1478
        ret->d.array = WMCreateArrayWithArray(plist->d.array);
 
1479
        ret->retainCount = 1;
 
1480
 
 
1481
        for(i=0; i<WMGetArrayItemCount(ret->d.array); i++)
 
1482
            WMRetainPropList(WMGetFromArray(ret->d.array, i));
 
1483
 
 
1484
        break;
 
1485
    case WPLDictionary:
 
1486
        ret = WMCreatePLDictionary(NULL, NULL);
 
1487
        e = WMEnumerateHashTable(plist->d.dict);
 
1488
        while (WMNextHashEnumeratorItemAndKey(&e, (void**)&item, (void**)&key)) {
 
1489
            WMPutInPLDictionary(ret, key, item);
 
1490
        }
 
1491
        break;
 
1492
    default:
 
1493
        wwarning(_("Used proplist functions on non-WMPropLists objects"));
 
1494
        wassertrv(False, NULL);
 
1495
        break;
 
1496
    }
 
1497
 
 
1498
    return ret;
 
1499
}
 
1500
 
 
1501
 
 
1502
WMPropList*
 
1503
WMDeepCopyPropList(WMPropList *plist)
 
1504
{
 
1505
    WMPropList *ret = NULL;
 
1506
    WMPropList *key, *item;
 
1507
    WMHashEnumerator e;
 
1508
    WMData *data;
 
1509
    int i;
 
1510
 
 
1511
    switch(plist->type) {
 
1512
    case WPLString:
 
1513
        ret = WMCreatePLString(plist->d.string);
 
1514
        break;
 
1515
    case WPLData:
 
1516
        data = WMCreateDataWithData(plist->d.data);
 
1517
        ret = WMCreatePLData(data);
 
1518
        WMReleaseData(data);
 
1519
        break;
 
1520
    case WPLArray:
 
1521
        ret = WMCreatePLArray(NULL);
 
1522
        for(i=0; i<WMGetArrayItemCount(plist->d.array); i++) {
 
1523
            item = WMDeepCopyPropList(WMGetFromArray(plist->d.array, i));
 
1524
            WMAddToArray(ret->d.array, item);
 
1525
        }
 
1526
        break;
 
1527
    case WPLDictionary:
 
1528
        ret = WMCreatePLDictionary(NULL, NULL);
 
1529
        e = WMEnumerateHashTable(plist->d.dict);
 
1530
        /* While we copy an existing dictionary there is no way that we can
 
1531
         * have duplicate keys, so we don't need to first remove a key/value
 
1532
         * pair before inserting the new key/value.
 
1533
         */
 
1534
        while (WMNextHashEnumeratorItemAndKey(&e, (void**)&item, (void**)&key)) {
 
1535
            WMHashInsert(ret->d.dict, WMDeepCopyPropList(key),
 
1536
                         WMDeepCopyPropList(item));
 
1537
        }
 
1538
        break;
 
1539
    default:
 
1540
        wwarning(_("Used proplist functions on non-WMPropLists objects"));
 
1541
        wassertrv(False, NULL);
 
1542
        break;
 
1543
    }
 
1544
 
 
1545
    return ret;
 
1546
}
 
1547
 
 
1548
 
 
1549
WMPropList*
 
1550
WMCreatePropListFromDescription(char *desc)
 
1551
{
 
1552
    WMPropList *plist = NULL;
 
1553
    PLData *pldata;
 
1554
 
 
1555
    pldata = (PLData*) wmalloc(sizeof(PLData));
 
1556
    memset(pldata, 0, sizeof(PLData));
 
1557
    pldata->ptr = desc;
 
1558
    pldata->lineNumber = 1;
 
1559
 
 
1560
    plist = getPropList(pldata);
 
1561
 
 
1562
    if (getNonSpaceChar(pldata)!=0 && plist) {
 
1563
        COMPLAIN(pldata, _("extra data after end of property list"));
 
1564
        /*
 
1565
         * We can't just ignore garbage after the end of the description
 
1566
         * (especially if the description was read from a file), because
 
1567
         * the "garbage" can be the real data and the real garbage is in
 
1568
         * fact in the beginning of the file (which is now inside plist)
 
1569
         */
 
1570
        WMReleasePropList(plist);
 
1571
        plist = NULL;
 
1572
    }
 
1573
 
 
1574
    wfree(pldata);
 
1575
 
 
1576
    return plist;
 
1577
}
 
1578
 
 
1579
 
 
1580
char*
 
1581
WMGetPropListDescription(WMPropList *plist, Bool indented)
 
1582
{
 
1583
    return (indented ? indentedDescription(plist, 0) : description(plist));
 
1584
}
 
1585
 
 
1586
 
 
1587
WMPropList*
 
1588
WMReadPropListFromFile(char *file)
 
1589
{
 
1590
    WMPropList *plist = NULL;
 
1591
    PLData *pldata;
 
1592
    FILE *f;
 
1593
    struct stat stbuf;
 
1594
    size_t length;
 
1595
 
 
1596
    f = fopen(file, "rb");
 
1597
    if (!f) {
 
1598
        /* let the user print the error message if he really needs to */
 
1599
        /*wsyserror(_("could not open domain file '%s' for reading"), file);*/
 
1600
        return NULL;
 
1601
    }
 
1602
 
 
1603
    if (stat(file, &stbuf)==0) {
 
1604
        length = (size_t) stbuf.st_size;
 
1605
    } else {
 
1606
        wsyserror(_("could not get size for file '%s'"), file);
 
1607
        fclose(f);
 
1608
        return NULL;
 
1609
    }
 
1610
 
 
1611
    pldata = (PLData*) wmalloc(sizeof(PLData));
 
1612
    memset(pldata, 0, sizeof(PLData));
 
1613
    pldata->ptr = (char*) wmalloc(length+1);
 
1614
    pldata->filename = file;
 
1615
    pldata->lineNumber = 1;
 
1616
 
 
1617
    if (fread(pldata->ptr, length, 1, f) != 1) {
 
1618
        if (ferror(f)) {
 
1619
            wsyserror(_("error reading from file '%s'"), file);
 
1620
        }
 
1621
        plist = NULL;
 
1622
        goto cleanup;
 
1623
    }
 
1624
 
 
1625
    pldata->ptr[length] = 0;
 
1626
 
 
1627
    plist = getPropList(pldata);
 
1628
 
 
1629
    if (getNonSpaceChar(pldata)!=0 && plist) {
 
1630
        COMPLAIN(pldata, _("extra data after end of property list"));
 
1631
        /*
 
1632
         * We can't just ignore garbage after the end of the description
 
1633
         * (especially if the description was read from a file), because
 
1634
         * the "garbage" can be the real data and the real garbage is in
 
1635
         * fact in the beginning of the file (which is now inside plist)
 
1636
         */
 
1637
        WMReleasePropList(plist);
 
1638
        plist = NULL;
 
1639
    }
 
1640
 
 
1641
cleanup:
 
1642
    wfree(pldata->ptr);
 
1643
    wfree(pldata);
 
1644
    fclose(f);
 
1645
 
 
1646
    return plist;
 
1647
}
 
1648
 
 
1649
 
 
1650
/* TODO: review this function's code */
 
1651
 
 
1652
Bool
 
1653
WMWritePropListToFile(WMPropList *plist, char *path, Bool atomically)
 
1654
{
 
1655
    char *thePath=NULL;
 
1656
    char *desc;
 
1657
    FILE *theFile;
 
1658
 
 
1659
    if (atomically) {
 
1660
#ifdef  HAVE_MKSTEMP
 
1661
        int fd, mask;
 
1662
#endif
 
1663
 
 
1664
        /* Use the path name of the destination file as a prefix for the
 
1665
         * mkstemp() call so that we can be sure that both files are on
 
1666
         * the same filesystem and the subsequent rename() will work. */
 
1667
        thePath = wstrconcat(path, ".XXXXXX");
 
1668
 
 
1669
#ifdef  HAVE_MKSTEMP
 
1670
        if ((fd = mkstemp(thePath)) < 0) {
 
1671
            wsyserror(_("mkstemp (%s) failed"), thePath);
 
1672
            goto failure;
 
1673
        }
 
1674
        mask = umask(0);
 
1675
        umask(mask);
 
1676
        fchmod(fd, 0644 & ~mask);
 
1677
        if ((theFile = fdopen(fd, "wb")) == NULL) {
 
1678
            close(fd);
 
1679
        }
 
1680
#else
 
1681
        if (mktemp(thePath) == NULL) {
 
1682
            wsyserror(_("mktemp (%s) failed"), thePath);
 
1683
            goto failure;
 
1684
        }
 
1685
        theFile = fopen(thePath, "wb");
 
1686
#endif
 
1687
    } else {
 
1688
        thePath = wstrdup(path);
 
1689
        theFile = fopen(thePath, "wb");
 
1690
    }
 
1691
 
 
1692
    if (theFile == NULL) {
 
1693
        wsyserror(_("open (%s) failed"), thePath);
 
1694
        goto failure;
 
1695
    }
 
1696
 
 
1697
    desc = indentedDescription(plist, 0);
 
1698
 
 
1699
    if (fprintf(theFile, "%s\n", desc) != strlen(desc)+1) {
 
1700
        wsyserror(_("writing to file: %s failed"), thePath);
 
1701
        wfree(desc);
 
1702
        goto failure;
 
1703
    }
 
1704
 
 
1705
    wfree(desc);
 
1706
 
 
1707
    if (fclose(theFile) != 0) {
 
1708
        wsyserror(_("fclose (%s) failed"), thePath);
 
1709
        goto failure;
 
1710
    }
 
1711
 
 
1712
    /* If we used a temporary file, we still need to rename() it be the
 
1713
     * real file.  Also, we need to try to retain the file attributes of
 
1714
     * the original file we are overwriting (if we are) */
 
1715
    if (atomically) {
 
1716
        if (rename(thePath, path) != 0) {
 
1717
            wsyserror(_("rename ('%s' to '%s') failed"), thePath, path);
 
1718
            goto failure;
 
1719
        }
 
1720
    }
 
1721
 
 
1722
    wfree(thePath);
 
1723
    return True;
 
1724
 
 
1725
failure:
 
1726
    if (atomically) {
 
1727
        unlink(thePath);
 
1728
        wfree(thePath);
 
1729
    }
 
1730
 
 
1731
    return False;
 
1732
}
 
1733
 
 
1734