1 : /* ***** BEGIN LICENSE BLOCK *****
2 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 : *
4 : * The contents of this file are subject to the Mozilla Public License Version
5 : * 1.1 (the "License"); you may not use this file except in compliance with
6 : * the License. You may obtain a copy of the License at
7 : * http://www.mozilla.org/MPL/
8 : *
9 : * Software distributed under the License is distributed on an "AS IS" basis,
10 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 : * for the specific language governing rights and limitations under the
12 : * License.
13 : *
14 : * The Original Code is Mozilla.
15 : *
16 : * The Initial Developer of the Original Code is Darin Fisher.
17 : * Portions created by the Initial Developer are Copyright (C) 2003
18 : * the Initial Developer. All Rights Reserved.
19 : *
20 : * Contributor(s):
21 : * Darin Fisher <darin@meer.net>
22 : *
23 : * Alternatively, the contents of this file may be used under the terms of
24 : * either the GNU General Public License Version 2 or later (the "GPL"), or
25 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 : * in which case the provisions of the GPL or the LGPL are applicable instead
27 : * of those above. If you wish to allow use of your version of this file only
28 : * under the terms of either the GPL or the LGPL, and not to allow others to
29 : * use your version of this file under the terms of the MPL, indicate your
30 : * decision by deleting the provisions above and replace them with the notice
31 : * and other provisions required by the GPL or the LGPL. If you do not delete
32 : * the provisions above, a recipient may use your version of this file under
33 : * the terms of any one of the MPL, the GPL or the LGPL.
34 : *
35 : * ***** END LICENSE BLOCK ***** */
36 :
37 : #include <stdlib.h>
38 : #include <string.h>
39 : #include <ctype.h>
40 : #include "prefread.h"
41 : #include "nsString.h"
42 : #include "nsUTF8Utils.h"
43 :
44 : #ifdef TEST_PREFREAD
45 : #include <stdio.h>
46 : #define NS_WARNING(_s) printf(">>> " _s "!\n")
47 : #define NS_NOTREACHED(_s) NS_WARNING(_s)
48 : #else
49 : #include "nsDebug.h" // for NS_WARNING
50 : #endif
51 :
52 : /* pref parser states */
53 : enum {
54 : PREF_PARSE_INIT,
55 : PREF_PARSE_MATCH_STRING,
56 : PREF_PARSE_UNTIL_NAME,
57 : PREF_PARSE_QUOTED_STRING,
58 : PREF_PARSE_UNTIL_COMMA,
59 : PREF_PARSE_UNTIL_VALUE,
60 : PREF_PARSE_INT_VALUE,
61 : PREF_PARSE_COMMENT_MAYBE_START,
62 : PREF_PARSE_COMMENT_BLOCK,
63 : PREF_PARSE_COMMENT_BLOCK_MAYBE_END,
64 : PREF_PARSE_ESC_SEQUENCE,
65 : PREF_PARSE_HEX_ESCAPE,
66 : PREF_PARSE_UTF16_LOW_SURROGATE,
67 : PREF_PARSE_UNTIL_OPEN_PAREN,
68 : PREF_PARSE_UNTIL_CLOSE_PAREN,
69 : PREF_PARSE_UNTIL_SEMICOLON,
70 : PREF_PARSE_UNTIL_EOL
71 : };
72 :
73 : #define UTF16_ESC_NUM_DIGITS 4
74 : #define HEX_ESC_NUM_DIGITS 2
75 : #define BITS_PER_HEX_DIGIT 4
76 :
77 : static const char kUserPref[] = "user_pref";
78 : static const char kPref[] = "pref";
79 : static const char kTrue[] = "true";
80 : static const char kFalse[] = "false";
81 :
82 : /**
83 : * pref_GrowBuf
84 : *
85 : * this function will increase the size of the buffer owned
86 : * by the given pref parse state. We currently use a simple
87 : * doubling algorithm, but the only hard requirement is that
88 : * it increase the buffer by at least the size of the ps->esctmp
89 : * buffer used for escape processing (currently 6 bytes).
90 : *
91 : * this buffer is used to store partial pref lines. it is
92 : * freed when the parse state is destroyed.
93 : *
94 : * @param ps
95 : * parse state instance
96 : *
97 : * this function updates all pointers that reference an
98 : * address within lb since realloc may relocate the buffer.
99 : *
100 : * @return false if insufficient memory.
101 : */
102 : static bool
103 14214 : pref_GrowBuf(PrefParseState *ps)
104 : {
105 : int bufLen, curPos, valPos;
106 :
107 14214 : bufLen = ps->lbend - ps->lb;
108 14214 : curPos = ps->lbcur - ps->lb;
109 14214 : valPos = ps->vb - ps->lb;
110 :
111 14214 : if (bufLen == 0)
112 8530 : bufLen = 128; /* default buffer size */
113 : else
114 5684 : bufLen <<= 1; /* double buffer size */
115 :
116 : #ifdef TEST_PREFREAD
117 : fprintf(stderr, ">>> realloc(%d)\n", bufLen);
118 : #endif
119 :
120 14214 : ps->lb = (char*) realloc(ps->lb, bufLen);
121 14214 : if (!ps->lb)
122 0 : return false;
123 :
124 14214 : ps->lbcur = ps->lb + curPos;
125 14214 : ps->lbend = ps->lb + bufLen;
126 14214 : ps->vb = ps->lb + valPos;
127 :
128 14214 : return true;
129 : }
130 :
131 : /**
132 : * pref_DoCallback
133 : *
134 : * this function is called when a complete pref name-value pair has
135 : * been extracted from the input data.
136 : *
137 : * @param ps
138 : * parse state instance
139 : *
140 : * @return false to indicate a fatal error.
141 : */
142 : static bool
143 2358889 : pref_DoCallback(PrefParseState *ps)
144 : {
145 : PrefValue value;
146 :
147 2358889 : switch (ps->vtype) {
148 : case PREF_STRING:
149 777296 : value.stringVal = ps->vb;
150 777296 : break;
151 : case PREF_INT:
152 582619 : if ((ps->vb[0] == '-' || ps->vb[0] == '+') && ps->vb[1] == '\0') {
153 0 : NS_WARNING("malformed integer value");
154 0 : return false;
155 : }
156 582619 : value.intVal = atoi(ps->vb);
157 582619 : break;
158 : case PREF_BOOL:
159 998974 : value.boolVal = (ps->vb == kTrue);
160 998974 : break;
161 : default:
162 0 : break;
163 : }
164 2358889 : (*ps->reader)(ps->closure, ps->lb, value, ps->vtype, ps->fdefault);
165 2358889 : return true;
166 : }
167 :
168 : void
169 8531 : PREF_InitParseState(PrefParseState *ps, PrefReader reader, void *closure)
170 : {
171 8531 : memset(ps, 0, sizeof(*ps));
172 8531 : ps->reader = reader;
173 8531 : ps->closure = closure;
174 8531 : }
175 :
176 : void
177 8531 : PREF_FinalizeParseState(PrefParseState *ps)
178 : {
179 8531 : if (ps->lb)
180 8530 : free(ps->lb);
181 8531 : }
182 :
183 : /**
184 : * Pseudo-BNF
185 : * ----------
186 : * function = LJUNK function-name JUNK function-args
187 : * function-name = "user_pref" | "pref"
188 : * function-args = "(" JUNK pref-name JUNK "," JUNK pref-value JUNK ")" JUNK ";"
189 : * pref-name = quoted-string
190 : * pref-value = quoted-string | "true" | "false" | integer-value
191 : * JUNK = *(WS | comment-block | comment-line)
192 : * LJUNK = *(WS | comment-block | comment-line | bcomment-line)
193 : * WS = SP | HT | LF | VT | FF | CR
194 : * SP = <US-ASCII SP, space (32)>
195 : * HT = <US-ASCII HT, horizontal-tab (9)>
196 : * LF = <US-ASCII LF, linefeed (10)>
197 : * VT = <US-ASCII HT, vertical-tab (11)>
198 : * FF = <US-ASCII FF, form-feed (12)>
199 : * CR = <US-ASCII CR, carriage return (13)>
200 : * comment-block = <C/C++ style comment block>
201 : * comment-line = <C++ style comment line>
202 : * bcomment-line = <bourne-shell style comment line>
203 : */
204 : bool
205 8531 : PREF_ParseBuf(PrefParseState *ps, const char *buf, int bufLen)
206 : {
207 : const char *end;
208 : char c;
209 : char udigit;
210 : int state;
211 :
212 8531 : state = ps->state;
213 220056400 : for (end = buf + bufLen; buf != end; ++buf) {
214 220047869 : c = *buf;
215 220047869 : switch (state) {
216 : /* initial state */
217 : case PREF_PARSE_INIT:
218 7268481 : if (ps->lbcur != ps->lb) { /* reset state */
219 2358887 : ps->lbcur = ps->lb;
220 2358887 : ps->vb = NULL;
221 2358887 : ps->vtype = PREF_INVALID;
222 2358887 : ps->fdefault = false;
223 : }
224 7268481 : switch (c) {
225 : case '/': /* begin comment block or line? */
226 1503420 : state = PREF_PARSE_COMMENT_MAYBE_START;
227 1503420 : break;
228 : case '#': /* accept shell style comments */
229 2 : state = PREF_PARSE_UNTIL_EOL;
230 2 : break;
231 : case 'u': /* indicating user_pref */
232 : case 'p': /* indicating pref */
233 2358889 : ps->smatch = (c == 'u' ? kUserPref : kPref);
234 2358889 : ps->sindex = 1;
235 2358889 : ps->nextstate = PREF_PARSE_UNTIL_OPEN_PAREN;
236 2358889 : state = PREF_PARSE_MATCH_STRING;
237 2358889 : break;
238 : /* else skip char */
239 : }
240 7268481 : break;
241 :
242 : /* string matching */
243 : case PREF_PARSE_MATCH_STRING:
244 10416189 : if (c == ps->smatch[ps->sindex++]) {
245 : /* if we've matched all characters, then move to next state. */
246 10416189 : if (ps->smatch[ps->sindex] == '\0') {
247 3357863 : state = ps->nextstate;
248 3357863 : ps->nextstate = PREF_PARSE_INIT; /* reset next state */
249 : }
250 : /* else wait for next char */
251 : }
252 : else {
253 0 : NS_WARNING("malformed pref file");
254 0 : return false;
255 : }
256 10416189 : break;
257 :
258 : /* quoted string parsing */
259 : case PREF_PARSE_QUOTED_STRING:
260 : /* we assume that the initial quote has already been consumed */
261 96046059 : if (ps->lbcur == ps->lbend && !pref_GrowBuf(ps))
262 0 : return false; /* out of memory */
263 96046059 : if (c == '\\')
264 160573 : state = PREF_PARSE_ESC_SEQUENCE;
265 95885486 : else if (c == ps->quotechar) {
266 3136185 : *ps->lbcur++ = '\0';
267 3136185 : state = ps->nextstate;
268 3136185 : ps->nextstate = PREF_PARSE_INIT; /* reset next state */
269 : }
270 : else
271 92749301 : *ps->lbcur++ = c;
272 96046059 : break;
273 :
274 : /* name parsing */
275 : case PREF_PARSE_UNTIL_NAME:
276 2358889 : if (c == '\"' || c == '\'') {
277 2358889 : ps->fdefault = (ps->smatch == kPref);
278 2358889 : ps->quotechar = c;
279 2358889 : ps->nextstate = PREF_PARSE_UNTIL_COMMA; /* return here when done */
280 2358889 : state = PREF_PARSE_QUOTED_STRING;
281 : }
282 0 : else if (c == '/') { /* allow embedded comment */
283 0 : ps->nextstate = state; /* return here when done with comment */
284 0 : state = PREF_PARSE_COMMENT_MAYBE_START;
285 : }
286 0 : else if (!isspace(c)) {
287 0 : NS_WARNING("malformed pref file");
288 0 : return false;
289 : }
290 2358889 : break;
291 :
292 : /* parse until we find a comma separating name and value */
293 : case PREF_PARSE_UNTIL_COMMA:
294 2371678 : if (c == ',') {
295 2358889 : ps->vb = ps->lbcur;
296 2358889 : state = PREF_PARSE_UNTIL_VALUE;
297 : }
298 12789 : else if (c == '/') { /* allow embedded comment */
299 0 : ps->nextstate = state; /* return here when done with comment */
300 0 : state = PREF_PARSE_COMMENT_MAYBE_START;
301 : }
302 12789 : else if (!isspace(c)) {
303 0 : NS_WARNING("malformed pref file");
304 0 : return false;
305 : }
306 2371678 : break;
307 :
308 : /* value parsing */
309 : case PREF_PARSE_UNTIL_VALUE:
310 : /* the pref value type is unknown. so, we scan for the first
311 : * character of the value, and determine the type from that. */
312 6732756 : if (c == '\"' || c == '\'') {
313 777296 : ps->vtype = PREF_STRING;
314 777296 : ps->quotechar = c;
315 777296 : ps->nextstate = PREF_PARSE_UNTIL_CLOSE_PAREN;
316 777296 : state = PREF_PARSE_QUOTED_STRING;
317 : }
318 5955460 : else if (c == 't' || c == 'f') {
319 998974 : ps->vb = (char *) (c == 't' ? kTrue : kFalse);
320 998974 : ps->vtype = PREF_BOOL;
321 998974 : ps->smatch = ps->vb;
322 998974 : ps->sindex = 1;
323 998974 : ps->nextstate = PREF_PARSE_UNTIL_CLOSE_PAREN;
324 998974 : state = PREF_PARSE_MATCH_STRING;
325 : }
326 4956486 : else if (isdigit(c) || (c == '-') || (c == '+')) {
327 582619 : ps->vtype = PREF_INT;
328 : /* write c to line buffer... */
329 582619 : if (ps->lbcur == ps->lbend && !pref_GrowBuf(ps))
330 0 : return false; /* out of memory */
331 582619 : *ps->lbcur++ = c;
332 582619 : state = PREF_PARSE_INT_VALUE;
333 : }
334 4373867 : else if (c == '/') { /* allow embedded comment */
335 0 : ps->nextstate = state; /* return here when done with comment */
336 0 : state = PREF_PARSE_COMMENT_MAYBE_START;
337 : }
338 4373867 : else if (!isspace(c)) {
339 0 : NS_WARNING("malformed pref file");
340 0 : return false;
341 : }
342 6732756 : break;
343 : case PREF_PARSE_INT_VALUE:
344 : /* grow line buffer if necessary... */
345 1189403 : if (ps->lbcur == ps->lbend && !pref_GrowBuf(ps))
346 0 : return false; /* out of memory */
347 1189403 : if (isdigit(c))
348 606784 : *ps->lbcur++ = c;
349 : else {
350 582619 : *ps->lbcur++ = '\0'; /* stomp null terminator; we are done. */
351 582619 : if (c == ')')
352 582619 : state = PREF_PARSE_UNTIL_SEMICOLON;
353 0 : else if (c == '/') { /* allow embedded comment */
354 0 : ps->nextstate = PREF_PARSE_UNTIL_CLOSE_PAREN;
355 0 : state = PREF_PARSE_COMMENT_MAYBE_START;
356 : }
357 0 : else if (isspace(c))
358 0 : state = PREF_PARSE_UNTIL_CLOSE_PAREN;
359 : else {
360 0 : NS_WARNING("malformed pref file");
361 0 : return false;
362 : }
363 : }
364 1189403 : break;
365 :
366 : /* comment parsing */
367 : case PREF_PARSE_COMMENT_MAYBE_START:
368 1503420 : switch (c) {
369 : case '*': /* comment block */
370 11370 : state = PREF_PARSE_COMMENT_BLOCK;
371 11370 : break;
372 : case '/': /* comment line */
373 1492050 : state = PREF_PARSE_UNTIL_EOL;
374 1492050 : break;
375 : default:
376 : /* pref file is malformed */
377 0 : NS_WARNING("malformed pref file");
378 0 : return false;
379 : }
380 1503420 : break;
381 : case PREF_PARSE_COMMENT_BLOCK:
382 5081972 : if (c == '*')
383 119376 : state = PREF_PARSE_COMMENT_BLOCK_MAYBE_END;
384 5081972 : break;
385 : case PREF_PARSE_COMMENT_BLOCK_MAYBE_END:
386 142112 : switch (c) {
387 : case '/':
388 11370 : state = ps->nextstate;
389 11370 : ps->nextstate = PREF_PARSE_INIT;
390 11370 : break;
391 : case '*': /* stay in this state */
392 22736 : break;
393 : default:
394 108006 : state = PREF_PARSE_COMMENT_BLOCK;
395 : }
396 142112 : break;
397 :
398 : /* string escape sequence parsing */
399 : case PREF_PARSE_ESC_SEQUENCE:
400 : /* not necessary to resize buffer here since we should be writing
401 : * only one character and the resize check would have been done
402 : * for us in the previous state */
403 160573 : switch (c) {
404 : case '\"':
405 : case '\'':
406 : case '\\':
407 8526 : break;
408 : case 'r':
409 0 : c = '\r';
410 0 : break;
411 : case 'n':
412 0 : c = '\n';
413 0 : break;
414 : case 'x': /* hex escape -- always interpreted as Latin-1 */
415 : case 'u': /* UTF16 escape */
416 152047 : ps->esctmp[0] = c;
417 152047 : ps->esclen = 1;
418 152047 : ps->utf16[0] = ps->utf16[1] = 0;
419 : ps->sindex = (c == 'x' ) ?
420 : HEX_ESC_NUM_DIGITS :
421 152047 : UTF16_ESC_NUM_DIGITS;
422 152047 : state = PREF_PARSE_HEX_ESCAPE;
423 152047 : continue;
424 : default:
425 0 : NS_WARNING("preserving unexpected JS escape sequence");
426 : /* Invalid escape sequence so we do have to write more than
427 : * one character. Grow line buffer if necessary... */
428 0 : if ((ps->lbcur+1) == ps->lbend && !pref_GrowBuf(ps))
429 0 : return false; /* out of memory */
430 0 : *ps->lbcur++ = '\\'; /* preserve the escape sequence */
431 0 : break;
432 : }
433 8526 : *ps->lbcur++ = c;
434 8526 : state = PREF_PARSE_QUOTED_STRING;
435 8526 : break;
436 :
437 : /* parsing a hex (\xHH) or utf16 escape (\uHHHH) */
438 : case PREF_PARSE_HEX_ESCAPE:
439 608188 : if ( c >= '0' && c <= '9' )
440 439089 : udigit = (c - '0');
441 169099 : else if ( c >= 'A' && c <= 'F' )
442 169099 : udigit = (c - 'A') + 10;
443 0 : else if ( c >= 'a' && c <= 'f' )
444 0 : udigit = (c - 'a') + 10;
445 : else {
446 : /* bad escape sequence found, write out broken escape as-is */
447 0 : NS_WARNING("preserving invalid or incomplete hex escape");
448 0 : *ps->lbcur++ = '\\'; /* original escape slash */
449 0 : if ((ps->lbcur + ps->esclen) >= ps->lbend && !pref_GrowBuf(ps))
450 0 : return false;
451 0 : for (int i = 0; i < ps->esclen; ++i)
452 0 : *ps->lbcur++ = ps->esctmp[i];
453 :
454 : /* push the non-hex character back for re-parsing. */
455 : /* (++buf at the top of the loop keeps this safe) */
456 0 : --buf;
457 0 : state = PREF_PARSE_QUOTED_STRING;
458 0 : continue;
459 : }
460 :
461 : /* have a digit */
462 608188 : ps->esctmp[ps->esclen++] = c; /* preserve it */
463 608188 : ps->utf16[1] <<= BITS_PER_HEX_DIGIT;
464 608188 : ps->utf16[1] |= udigit;
465 608188 : ps->sindex--;
466 608188 : if (ps->sindex == 0) {
467 : /* have the full escape. Convert to UTF8 */
468 152047 : int utf16len = 0;
469 152047 : if (ps->utf16[0]) {
470 : /* already have a high surrogate, this is a two char seq */
471 0 : utf16len = 2;
472 : }
473 152047 : else if (0xD800 == (0xFC00 & ps->utf16[1])) {
474 : /* a high surrogate, can't convert until we have the low */
475 0 : ps->utf16[0] = ps->utf16[1];
476 0 : ps->utf16[1] = 0;
477 0 : state = PREF_PARSE_UTF16_LOW_SURROGATE;
478 0 : break;
479 : }
480 : else {
481 : /* a single utf16 character */
482 152047 : ps->utf16[0] = ps->utf16[1];
483 152047 : utf16len = 1;
484 : }
485 :
486 : /* actual conversion */
487 : /* make sure there's room, 6 bytes is max utf8 len (in */
488 : /* theory; 4 bytes covers the actual utf16 range) */
489 152047 : if (ps->lbcur+6 >= ps->lbend && !pref_GrowBuf(ps))
490 0 : return false;
491 :
492 152047 : ConvertUTF16toUTF8 converter(ps->lbcur);
493 152047 : converter.write(ps->utf16, utf16len);
494 152047 : ps->lbcur += converter.Size();
495 152047 : state = PREF_PARSE_QUOTED_STRING;
496 : }
497 608188 : break;
498 :
499 : /* looking for beginning of utf16 low surrogate */
500 : case PREF_PARSE_UTF16_LOW_SURROGATE:
501 0 : if (ps->sindex == 0 && c == '\\') {
502 0 : ++ps->sindex;
503 : }
504 0 : else if (ps->sindex == 1 && c == 'u') {
505 : /* escape sequence is correct, now parse hex */
506 0 : ps->sindex = UTF16_ESC_NUM_DIGITS;
507 0 : ps->esctmp[0] = 'u';
508 0 : ps->esclen = 1;
509 0 : state = PREF_PARSE_HEX_ESCAPE;
510 : }
511 : else {
512 : /* didn't find expected low surrogate. Ignore high surrogate
513 : * (it would just get converted to nothing anyway) and start
514 : * over with this character */
515 0 : --buf;
516 0 : if (ps->sindex == 1)
517 0 : state = PREF_PARSE_ESC_SEQUENCE;
518 : else
519 0 : state = PREF_PARSE_QUOTED_STRING;
520 0 : continue;
521 : }
522 0 : break;
523 :
524 : /* function open and close parsing */
525 : case PREF_PARSE_UNTIL_OPEN_PAREN:
526 : /* tolerate only whitespace and embedded comments */
527 2358889 : if (c == '(')
528 2358889 : state = PREF_PARSE_UNTIL_NAME;
529 0 : else if (c == '/') {
530 0 : ps->nextstate = state; /* return here when done with comment */
531 0 : state = PREF_PARSE_COMMENT_MAYBE_START;
532 : }
533 0 : else if (!isspace(c)) {
534 0 : NS_WARNING("malformed pref file");
535 0 : return false;
536 : }
537 2358889 : break;
538 : case PREF_PARSE_UNTIL_CLOSE_PAREN:
539 : /* tolerate only whitespace and embedded comments */
540 1776270 : if (c == ')')
541 1776270 : state = PREF_PARSE_UNTIL_SEMICOLON;
542 0 : else if (c == '/') {
543 0 : ps->nextstate = state; /* return here when done with comment */
544 0 : state = PREF_PARSE_COMMENT_MAYBE_START;
545 : }
546 0 : else if (!isspace(c)) {
547 0 : NS_WARNING("malformed pref file");
548 0 : return false;
549 : }
550 1776270 : break;
551 :
552 : /* function terminator ';' parsing */
553 : case PREF_PARSE_UNTIL_SEMICOLON:
554 : /* tolerate only whitespace and embedded comments */
555 2358889 : if (c == ';') {
556 2358889 : if (!pref_DoCallback(ps))
557 0 : return false;
558 2358889 : state = PREF_PARSE_INIT;
559 : }
560 0 : else if (c == '/') {
561 0 : ps->nextstate = state; /* return here when done with comment */
562 0 : state = PREF_PARSE_COMMENT_MAYBE_START;
563 : }
564 0 : else if (!isspace(c)) {
565 0 : NS_WARNING("malformed pref file");
566 0 : return false;
567 : }
568 2358889 : break;
569 :
570 : /* eol parsing */
571 : case PREF_PARSE_UNTIL_EOL:
572 : /* need to handle mac, unix, or dos line endings.
573 : * PREF_PARSE_INIT will eat the next \n in case
574 : * we have \r\n. */
575 79674101 : if (c == '\r' || c == '\n' || c == 0x1A) {
576 1492052 : state = ps->nextstate;
577 1492052 : ps->nextstate = PREF_PARSE_INIT; /* reset next state */
578 : }
579 79674101 : break;
580 : }
581 : }
582 8531 : ps->state = state;
583 8531 : return true;
584 : }
585 :
586 : #ifdef TEST_PREFREAD
587 :
588 : static void
589 : pref_reader(void *closure,
590 : const char *pref,
591 : PrefValue val,
592 : PrefType type,
593 : bool defPref)
594 : {
595 : printf("%spref(\"%s\", ", defPref ? "" : "user_", pref);
596 : switch (type) {
597 : case PREF_STRING:
598 : printf("\"%s\");\n", val.stringVal);
599 : break;
600 : case PREF_INT:
601 : printf("%i);\n", val.intVal);
602 : break;
603 : case PREF_BOOL:
604 : printf("%s);\n", val.boolVal == false ? "false" : "true");
605 : break;
606 : }
607 : }
608 :
609 : int
610 : main(int argc, char **argv)
611 : {
612 : PrefParseState ps;
613 : char buf[4096]; /* i/o buffer */
614 : FILE *fp;
615 : int n;
616 :
617 : if (argc == 1) {
618 : printf("usage: prefread file.js\n");
619 : return -1;
620 : }
621 :
622 : fp = fopen(argv[1], "r");
623 : if (!fp) {
624 : printf("failed to open file\n");
625 : return -1;
626 : }
627 :
628 : PREF_InitParseState(&ps, pref_reader, NULL);
629 :
630 : while ((n = fread(buf, 1, sizeof(buf), fp)) > 0)
631 : PREF_ParseBuf(&ps, buf, n);
632 :
633 : PREF_FinalizeParseState(&ps);
634 :
635 : fclose(fp);
636 : return 0;
637 : }
638 :
639 : #endif /* TEST_PREFREAD */
|