modules/libpref/src/prefread.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial