Change to the linux kernel coding style
[wmaker-crm.git] / WINGs / proplist.c
1
2 #include <string.h>
3 #include <stdarg.h>
4 #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>
10
11 #include "WUtil.h"
12 #include "wconfig.h"
13
14 typedef enum {
15 WPLString = 0x57504c01,
16 WPLData = 0x57504c02,
17 WPLArray = 0x57504c03,
18 WPLDictionary = 0x57504c04
19 } WPLType;
20
21 typedef struct W_PropList {
22 WPLType type;
23
24 union {
25 char *string;
26 WMData *data;
27 WMArray *array;
28 WMHashTable *dict;
29 } d;
30
31 int retainCount;
32 } W_PropList;
33
34 typedef struct PLData {
35 char *ptr;
36 int pos;
37 char *filename;
38 int lineNumber;
39 } PLData;
40
41 typedef struct StringBuffer {
42 char *str;
43 int size;
44 } StringBuffer;
45
46 static unsigned hashPropList(WMPropList * plist);
47 static WMPropList *getPLString(PLData * pldata);
48 static WMPropList *getPLQString(PLData * pldata);
49 static WMPropList *getPLData(PLData * pldata);
50 static WMPropList *getPLArray(PLData * pldata);
51 static WMPropList *getPLDictionary(PLData * pldata);
52 static WMPropList *getPropList(PLData * pldata);
53
54 typedef unsigned (*hashFunc) (const void *);
55 typedef Bool(*isEqualFunc) (const void *, const void *);
56 typedef void *(*retainFunc) (const void *);
57 typedef void (*releaseFunc) (const void *);
58
59 static const WMHashTableCallbacks WMPropListHashCallbacks = {
60 (hashFunc) hashPropList,
61 (isEqualFunc) WMIsPropListEqualTo,
62 (retainFunc) NULL,
63 (releaseFunc) NULL
64 };
65
66 static Bool caseSensitive = True;
67
68 #define BUFFERSIZE 8192
69 #define BUFFERSIZE_INCREMENT 1024
70
71 #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) {\
87 (buf).size += BUFFERSIZE_INCREMENT;\
88 (buf).str = wrealloc((buf).str, (buf).size);\
89 }
90
91 #define inrange(ch, min, max) ((ch)>=(min) && (ch)<=(max))
92 #define noquote(ch) (inrange(ch, 'a', 'z') || inrange(ch, 'A', 'Z') || inrange(ch, '0', '9') || ((ch)=='_') || ((ch)=='.') || ((ch)=='$'))
93 #define charesc(ch) (inrange(ch, 0x07, 0x0c) || ((ch)=='"') || ((ch)=='\\'))
94 #define numesc(ch) (((ch)<=0x06) || inrange(ch, 0x0d, 0x1f) || ((ch)>0x7e))
95 #define ishexdigit(ch) (inrange(ch, 'a', 'f') || inrange(ch, 'A', 'F') || inrange(ch, '0', '9'))
96 #define char2num(ch) (inrange(ch,'0','9') ? ((ch)-'0') : (inrange(ch,'a','f') ? ((ch)-0x57) : ((ch)-0x37)))
97 #define num2char(num) ((num) < 0xa ? ((num)+'0') : ((num)+0x57))
98
99 #define MaxHashLength 64
100
101 static unsigned hashPropList(WMPropList * plist)
102 {
103 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;
138 }
139
140 static WMPropList *retainPropListByCount(WMPropList * plist, int count)
141 {
142 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;
171 }
172
173 static void releasePropListByCount(WMPropList * plist, int count)
174 {
175 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 }
219 }
220
221 static char *dataDescription(WMPropList * plist)
222 {
223 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;
245 }
246
247 static char *stringDescription(WMPropList * plist)
248 {
249 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;
331 }
332
333 static char *description(WMPropList * plist)
334 {
335 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;
386 }
387
388 static char *indentedDescription(WMPropList * plist, int level)
389 {
390 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;
462 }
463
464 static INLINE int getChar(PLData * pldata)
465 {
466 int c;
467
468 c = pldata->ptr[pldata->pos];
469 if (c == 0) {
470 return 0;
471 }
472
473 pldata->pos++;
474
475 if (c == '\n')
476 pldata->lineNumber++;
477
478 return c;
479 }
480
481 static INLINE int getNonSpaceChar(PLData * pldata)
482 {
483 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;
499 }
500
501 static char *unescapestr(char *src)
502 {
503 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;
550 }
551
552 static WMPropList *getPLString(PLData * pldata)
553 {
554 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;
588 }
589
590 static WMPropList *getPLQString(PLData * pldata)
591 {
592 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;
638 }
639
640 static WMPropList *getPLData(PLData * pldata)
641 {
642 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;
697 }
698
699 static WMPropList *getPLArray(PLData * pldata)
700 {
701 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;
743 }
744
745 static WMPropList *getPLDictionary(PLData * pldata)
746 {
747 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;
825 }
826
827 static WMPropList *getPropList(PLData * pldata)
828 {
829 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;
877 }
878
879 void WMPLSetCaseSensitive(Bool caseSensitiveness)
880 {
881 caseSensitive = caseSensitiveness;
882 }
883
884 WMPropList *WMCreatePLString(char *str)
885 {
886 WMPropList *plist;
887
888 wassertrv(str != NULL, NULL);
889
890 plist = (WMPropList *) wmalloc(sizeof(W_PropList));
891
892 plist->type = WPLString;
893 plist->d.string = wstrdup(str);
894 plist->retainCount = 1;
895
896 return plist;
897 }
898
899 WMPropList *WMCreatePLData(WMData * data)
900 {
901 WMPropList *plist;
902
903 wassertrv(data != NULL, NULL);
904
905 plist = (WMPropList *) wmalloc(sizeof(W_PropList));
906
907 plist->type = WPLData;
908 plist->d.data = WMRetainData(data);
909 plist->retainCount = 1;
910
911 return plist;
912 }
913
914 WMPropList *WMCreatePLDataWithBytes(unsigned char *bytes, unsigned int length)
915 {
916 WMPropList *plist;
917
918 wassertrv(bytes != NULL, NULL);
919
920 plist = (WMPropList *) wmalloc(sizeof(W_PropList));
921
922 plist->type = WPLData;
923 plist->d.data = WMCreateDataWithBytes(bytes, length);
924 plist->retainCount = 1;
925
926 return plist;
927 }
928
929 WMPropList *WMCreatePLDataWithBytesNoCopy(unsigned char *bytes, unsigned int length, WMFreeDataProc * destructor)
930 {
931 WMPropList *plist;
932
933 wassertrv(bytes != NULL, NULL);
934
935 plist = (WMPropList *) wmalloc(sizeof(W_PropList));
936
937 plist->type = WPLData;
938 plist->d.data = WMCreateDataWithBytesNoCopy(bytes, length, destructor);
939 plist->retainCount = 1;
940
941 return plist;
942 }
943
944 WMPropList *WMCreatePLArray(WMPropList * elem, ...)
945 {
946 WMPropList *plist, *nelem;
947 va_list ap;
948
949 plist = (WMPropList *) wmalloc(sizeof(W_PropList));
950 plist->type = WPLArray;
951 plist->d.array = WMCreateArray(4);
952 plist->retainCount = 1;
953
954 if (!elem)
955 return plist;
956
957 WMAddToArray(plist->d.array, WMRetainPropList(elem));
958
959 va_start(ap, elem);
960
961 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 }
969 }
970
971 WMPropList *WMCreatePLDictionary(WMPropList * key, WMPropList * value, ...)
972 {
973 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 }
1006 }
1007
1008 WMPropList *WMRetainPropList(WMPropList * plist)
1009 {
1010 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;
1039 }
1040
1041 void WMReleasePropList(WMPropList * plist)
1042 {
1043 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 }
1087 }
1088
1089 void WMInsertInPLArray(WMPropList * plist, int index, WMPropList * item)
1090 {
1091 wassertr(plist->type == WPLArray);
1092
1093 retainPropListByCount(item, plist->retainCount);
1094 WMInsertInArray(plist->d.array, index, item);
1095 }
1096
1097 void WMAddToPLArray(WMPropList * plist, WMPropList * item)
1098 {
1099 wassertr(plist->type == WPLArray);
1100
1101 retainPropListByCount(item, plist->retainCount);
1102 WMAddToArray(plist->d.array, item);
1103 }
1104
1105 void WMDeleteFromPLArray(WMPropList * plist, int index)
1106 {
1107 WMPropList *item;
1108
1109 wassertr(plist->type == WPLArray);
1110
1111 item = WMGetFromArray(plist->d.array, index);
1112 if (item != NULL) {
1113 WMDeleteFromArray(plist->d.array, index);
1114 releasePropListByCount(item, plist->retainCount);
1115 }
1116 }
1117
1118 void WMRemoveFromPLArray(WMPropList * plist, WMPropList * item)
1119 {
1120 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 }
1133 }
1134
1135 void WMPutInPLDictionary(WMPropList * plist, WMPropList * key, WMPropList * value)
1136 {
1137 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); */
1145 }
1146
1147 void WMRemoveFromPLDictionary(WMPropList * plist, WMPropList * key)
1148 {
1149 WMPropList *k, *v;
1150
1151 wassertr(plist->type == WPLDictionary);
1152
1153 if (WMHashGetItemAndKey(plist->d.dict, key, (void **)&v, (void **)&k)) {
1154 WMHashRemove(plist->d.dict, k);
1155 releasePropListByCount(k, plist->retainCount);
1156 releasePropListByCount(v, plist->retainCount);
1157 }
1158 }
1159
1160 WMPropList *WMMergePLDictionaries(WMPropList * dest, WMPropList * source, Bool recursive)
1161 {
1162 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;
1185 }
1186
1187 WMPropList *WMSubtractPLDictionaries(WMPropList * dest, WMPropList * source, Bool recursive)
1188 {
1189 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;
1217 }
1218
1219 int WMGetPropListItemCount(WMPropList * plist)
1220 {
1221 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;
1236 }
1237
1238 Bool WMIsPLString(WMPropList * plist)
1239 {
1240 return (plist->type == WPLString);
1241 }
1242
1243 Bool WMIsPLData(WMPropList * plist)
1244 {
1245 return (plist->type == WPLData);
1246 }
1247
1248 Bool WMIsPLArray(WMPropList * plist)
1249 {
1250 return (plist->type == WPLArray);
1251 }
1252
1253 Bool WMIsPLDictionary(WMPropList * plist)
1254 {
1255 return (plist->type == WPLDictionary);
1256 }
1257
1258 Bool WMIsPropListEqualTo(WMPropList * plist, WMPropList * other)
1259 {
1260 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;
1304 }
1305
1306 char *WMGetFromPLString(WMPropList * plist)
1307 {
1308 wassertrv(plist->type == WPLString, NULL);
1309
1310 return plist->d.string;
1311 }
1312
1313 WMData *WMGetFromPLData(WMPropList * plist)
1314 {
1315 wassertrv(plist->type == WPLData, NULL);
1316
1317 return plist->d.data;
1318 }
1319
1320 const unsigned char *WMGetPLDataBytes(WMPropList * plist)
1321 {
1322 wassertrv(plist->type == WPLData, NULL);
1323
1324 return WMDataBytes(plist->d.data);
1325 }
1326
1327 int WMGetPLDataLength(WMPropList * plist)
1328 {
1329 wassertrv(plist->type == WPLData, 0);
1330
1331 return WMGetDataLength(plist->d.data);
1332 }
1333
1334 WMPropList *WMGetFromPLArray(WMPropList * plist, int index)
1335 {
1336 wassertrv(plist->type == WPLArray, NULL);
1337
1338 return WMGetFromArray(plist->d.array, index);
1339 }
1340
1341 WMPropList *WMGetFromPLDictionary(WMPropList * plist, WMPropList * key)
1342 {
1343 wassertrv(plist->type == WPLDictionary, NULL);
1344
1345 return WMHashGet(plist->d.dict, key);
1346 }
1347
1348 WMPropList *WMGetPLDictionaryKeys(WMPropList * plist)
1349 {
1350 WMPropList *array, *key;
1351 WMHashEnumerator enumerator;
1352
1353 wassertrv(plist->type == WPLDictionary, NULL);
1354
1355 array = (WMPropList *) wmalloc(sizeof(W_PropList));
1356 array->type = WPLArray;
1357 array->d.array = WMCreateArray(WMCountHashTable(plist->d.dict));
1358 array->retainCount = 1;
1359
1360 enumerator = WMEnumerateHashTable(plist->d.dict);
1361 while ((key = WMNextHashEnumeratorKey(&enumerator))) {
1362 WMAddToArray(array->d.array, WMRetainPropList(key));
1363 }
1364
1365 return array;
1366 }
1367
1368 WMPropList *WMShallowCopyPropList(WMPropList * plist)
1369 {
1370 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;
1409 }
1410
1411 WMPropList *WMDeepCopyPropList(WMPropList * plist)
1412 {
1413 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;
1453 }
1454
1455 WMPropList *WMCreatePropListFromDescription(char *desc)
1456 {
1457 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;
1482 }
1483
1484 char *WMGetPropListDescription(WMPropList * plist, Bool indented)
1485 {
1486 return (indented ? indentedDescription(plist, 0) : description(plist));
1487 }
1488
1489 WMPropList *WMReadPropListFromFile(char *file)
1490 {
1491 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;
1548 }
1549
1550 /* TODO: review this function's code */
1551
1552 Bool WMWritePropListToFile(WMPropList * plist, char *path, Bool atomically)
1553 {
1554 char *thePath = NULL;
1555 char *desc;
1556 FILE *theFile;
1557
1558 if (atomically) {
1559 #ifdef HAVE_MKSTEMP
1560 int fd, mask;
1561 #endif
1562
1563 /* Use the path name of the destination file as a prefix for the
1564 * mkstemp() call so that we can be sure that both files are on
1565 * the same filesystem and the subsequent rename() will work. */
1566 thePath = wstrconcat(path, ".XXXXXX");
1567
1568 #ifdef HAVE_MKSTEMP
1569 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 }
1579 #else
1580 if (mktemp(thePath) == NULL) {
1581 wsyserror(_("mktemp (%s) failed"), thePath);
1582 goto failure;
1583 }
1584 theFile = fopen(thePath, "wb");
1585 #endif
1586 } 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;
1631 }