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