1 /* proplist.c- Hand made proplist parser.
2 * The one in libPropList causes wmaker to crash if an error is found in
3 * the parsed file. This parser is also more rigid: it will not accept any
4 * property lists with errors, but will print more descriptive error messages
5 * and will hopefully not crash.
7 * Window Maker window manager
9 * Copyright (c) 1998 Alfredo K. Kojima
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
28 #include "WindowMaker.h"
38 #define DPUT(s) puts(s)
44 #define INITIAL_BUFFER_SIZE (16*1024)
46 #define BUFFER_SIZE_INCREMENT 1024
49 static int line_number
= 1;
50 static int buffer_size
= 0;
51 static char *buffer
= NULL
;
52 static char *file_name
;
55 static proplist_t
get_object(FILE *f
);
56 static proplist_t
get_array(FILE *f
);
57 static proplist_t
get_string(FILE *f
);
58 static proplist_t
get_qstring(FILE *f
);
59 static proplist_t
get_dictionary(FILE *f
);
76 get_non_space_char(FILE *f
)
97 unescapestr(char *src
)
99 char *dest
= wmalloc(strlen(src
)+1);
100 char *src_ptr
, *dest_ptr
;
104 for (src_ptr
=src
, dest_ptr
=dest
; *src_ptr
; src_ptr
++, dest_ptr
++)
107 *dest_ptr
= *src_ptr
;
111 if((ch
>='0') && (ch
<='3')) /* assume next 2 chars are octal too */
113 *dest_ptr
= ((ch
& 07) << 6);
114 *dest_ptr
|= ((*(++src_ptr
)&07)<<3);
115 *dest_ptr
|= *(++src_ptr
)&07;
121 case 'a' : *dest_ptr
= '\a'; break;
122 case 'b' : *dest_ptr
= '\b'; break;
123 case 't' : *dest_ptr
= '\t'; break;
124 case 'r' : *dest_ptr
= '\r'; break;
125 case 'n' : *dest_ptr
= '\n'; break;
126 case 'v' : *dest_ptr
= '\v'; break;
127 case 'f' : *dest_ptr
= '\f'; break;
128 default : *dest_ptr
= *src_ptr
;
139 #define CHECK_BUFFER_SIZE(ptr) \
140 if ((ptr) >= buffer_size-1) {\
141 buffer_size += BUFFER_SIZE_INCREMENT;\
142 buffer = wrealloc(buffer, buffer_size);\
146 #define ISSTRINGABLE(c) (isalnum(c) || (c)=='.' || (c)=='_' || (c)=='/' \
151 #define COMPLAIN(msg) wwarning(_("syntax error in %s, line %i:%s"), \
152 file_name, line_number, msg)
173 CHECK_BUFFER_SIZE(ptr
);
174 buffer
[ptr
++] = '\\';
180 COMPLAIN(_("unterminated string"));
183 CHECK_BUFFER_SIZE(ptr
);
193 char *tmp
= unescapestr(buffer
);
194 proplist_t pl
= PLMakeString(tmp
);
210 if (ISSTRINGABLE(c
)) {
211 CHECK_BUFFER_SIZE(ptr
);
225 char *tmp
= unescapestr(buffer
);
226 proplist_t pl
= PLMakeString(tmp
);
240 proplist_t list
, obj
;
242 list
= PLMakeArrayFromElements(NULL
);
245 c
= get_non_space_char(f
);
247 COMPLAIN(_("unterminated array"));
253 /* continue normally */
256 COMPLAIN(_("missing , in array or unterminated array"));
267 COMPLAIN(_("could not get array element"));
271 list
= PLAppendArrayElement(list
, obj
);
285 get_dictionary(FILE *f
)
289 proplist_t dict
, key
, value
;
291 dict
= PLMakeDictionaryFromEntries(NULL
, NULL
);
294 c
= get_non_space_char(f
);
297 COMPLAIN(_("unterminated dictionary"));
307 DPUT("getting dict key");
309 key
= get_qstring(f
);
310 else if (ISSTRINGABLE(c
)) {
315 COMPLAIN(_("missing dictionary key"));
317 COMPLAIN(_("missing dictionary entry key or unterminated dictionary"));
323 COMPLAIN(_("error parsing dictionary key"));
329 c
= get_non_space_char(f
);
332 COMPLAIN(_("missing = in dictionary entry"));
336 DPUT("getting dict entry data");
338 value
= get_object(f
);
341 COMPLAIN(_("error parsing dictionary entry value"));
349 c
= get_non_space_char(f
);
351 COMPLAIN(_("missing ; in dictionary entry"));
357 dict
= PLInsertDictionaryEntry(dict
, key
, value
);
376 COMPLAIN("the data datatype is not yet implemented");
391 c
= get_non_space_char(f
);
402 DPUT("getting dictionary");
403 pl
= get_dictionary(f
);
408 DPUT("getting arrray");
414 DPUT("getting data");
420 DPUT("getting qstring");
426 if (ISSTRINGABLE(c
)) {
427 DPUT("getting string");
432 COMPLAIN(_("was expecting a string, dictionary, data or array. If it's a string, try enclosing it with \"."));
433 if (c
=='#' || c
=='/') {
434 wwarning(_("Comments are not allowed inside WindowMaker owned domain files."));
446 ReadProplistFromFile(char *file
)
449 proplist_t pl
= NULL
;
451 f
= fopen(file
, "r");
453 wsyserror(_("could not open domain file %s"), file
);
459 buffer_size
= INITIAL_BUFFER_SIZE
;
460 buffer
= wmalloc(buffer_size
);
464 /* check for illegal characters after EOF */
465 if (get_non_space_char(f
)!=EOF
&& pl
) {
466 COMPLAIN(_("extra data after end of file"));
468 * We can't just ignore garbage after the file because the "garbage"
469 * could be the data and the real garbage be in the beginning of
470 * the file (wich is now, inside pl)
483 fpl
= PLMakeString(file
);
484 PLSetFilename(pl
, fpl
);