1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/modules/libpref/src/prefread.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,607 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include <stdlib.h> 1.9 +#include <string.h> 1.10 +#include <ctype.h> 1.11 +#include "prefread.h" 1.12 +#include "nsString.h" 1.13 +#include "nsUTF8Utils.h" 1.14 + 1.15 +#ifdef TEST_PREFREAD 1.16 +#include <stdio.h> 1.17 +#define NS_WARNING(_s) printf(">>> " _s "!\n") 1.18 +#define NS_NOTREACHED(_s) NS_WARNING(_s) 1.19 +#else 1.20 +#include "nsDebug.h" // for NS_WARNING 1.21 +#endif 1.22 + 1.23 +/* pref parser states */ 1.24 +enum { 1.25 + PREF_PARSE_INIT, 1.26 + PREF_PARSE_MATCH_STRING, 1.27 + PREF_PARSE_UNTIL_NAME, 1.28 + PREF_PARSE_QUOTED_STRING, 1.29 + PREF_PARSE_UNTIL_COMMA, 1.30 + PREF_PARSE_UNTIL_VALUE, 1.31 + PREF_PARSE_INT_VALUE, 1.32 + PREF_PARSE_COMMENT_MAYBE_START, 1.33 + PREF_PARSE_COMMENT_BLOCK, 1.34 + PREF_PARSE_COMMENT_BLOCK_MAYBE_END, 1.35 + PREF_PARSE_ESC_SEQUENCE, 1.36 + PREF_PARSE_HEX_ESCAPE, 1.37 + PREF_PARSE_UTF16_LOW_SURROGATE, 1.38 + PREF_PARSE_UNTIL_OPEN_PAREN, 1.39 + PREF_PARSE_UNTIL_CLOSE_PAREN, 1.40 + PREF_PARSE_UNTIL_SEMICOLON, 1.41 + PREF_PARSE_UNTIL_EOL 1.42 +}; 1.43 + 1.44 +#define UTF16_ESC_NUM_DIGITS 4 1.45 +#define HEX_ESC_NUM_DIGITS 2 1.46 +#define BITS_PER_HEX_DIGIT 4 1.47 + 1.48 +static const char kUserPref[] = "user_pref"; 1.49 +static const char kPref[] = "pref"; 1.50 +static const char kTrue[] = "true"; 1.51 +static const char kFalse[] = "false"; 1.52 + 1.53 +/** 1.54 + * pref_GrowBuf 1.55 + * 1.56 + * this function will increase the size of the buffer owned 1.57 + * by the given pref parse state. We currently use a simple 1.58 + * doubling algorithm, but the only hard requirement is that 1.59 + * it increase the buffer by at least the size of the ps->esctmp 1.60 + * buffer used for escape processing (currently 6 bytes). 1.61 + * 1.62 + * this buffer is used to store partial pref lines. it is 1.63 + * freed when the parse state is destroyed. 1.64 + * 1.65 + * @param ps 1.66 + * parse state instance 1.67 + * 1.68 + * this function updates all pointers that reference an 1.69 + * address within lb since realloc may relocate the buffer. 1.70 + * 1.71 + * @return false if insufficient memory. 1.72 + */ 1.73 +static bool 1.74 +pref_GrowBuf(PrefParseState *ps) 1.75 +{ 1.76 + int bufLen, curPos, valPos; 1.77 + 1.78 + bufLen = ps->lbend - ps->lb; 1.79 + curPos = ps->lbcur - ps->lb; 1.80 + valPos = ps->vb - ps->lb; 1.81 + 1.82 + if (bufLen == 0) 1.83 + bufLen = 128; /* default buffer size */ 1.84 + else 1.85 + bufLen <<= 1; /* double buffer size */ 1.86 + 1.87 +#ifdef TEST_PREFREAD 1.88 + fprintf(stderr, ">>> realloc(%d)\n", bufLen); 1.89 +#endif 1.90 + 1.91 + ps->lb = (char*) realloc(ps->lb, bufLen); 1.92 + if (!ps->lb) 1.93 + return false; 1.94 + 1.95 + ps->lbcur = ps->lb + curPos; 1.96 + ps->lbend = ps->lb + bufLen; 1.97 + ps->vb = ps->lb + valPos; 1.98 + 1.99 + return true; 1.100 +} 1.101 + 1.102 +/** 1.103 + * pref_DoCallback 1.104 + * 1.105 + * this function is called when a complete pref name-value pair has 1.106 + * been extracted from the input data. 1.107 + * 1.108 + * @param ps 1.109 + * parse state instance 1.110 + * 1.111 + * @return false to indicate a fatal error. 1.112 + */ 1.113 +static bool 1.114 +pref_DoCallback(PrefParseState *ps) 1.115 +{ 1.116 + PrefValue value; 1.117 + 1.118 + switch (ps->vtype) { 1.119 + case PREF_STRING: 1.120 + value.stringVal = ps->vb; 1.121 + break; 1.122 + case PREF_INT: 1.123 + if ((ps->vb[0] == '-' || ps->vb[0] == '+') && ps->vb[1] == '\0') { 1.124 + NS_WARNING("malformed integer value"); 1.125 + return false; 1.126 + } 1.127 + value.intVal = atoi(ps->vb); 1.128 + break; 1.129 + case PREF_BOOL: 1.130 + value.boolVal = (ps->vb == kTrue); 1.131 + break; 1.132 + default: 1.133 + break; 1.134 + } 1.135 + (*ps->reader)(ps->closure, ps->lb, value, ps->vtype, ps->fdefault); 1.136 + return true; 1.137 +} 1.138 + 1.139 +void 1.140 +PREF_InitParseState(PrefParseState *ps, PrefReader reader, void *closure) 1.141 +{ 1.142 + memset(ps, 0, sizeof(*ps)); 1.143 + ps->reader = reader; 1.144 + ps->closure = closure; 1.145 +} 1.146 + 1.147 +void 1.148 +PREF_FinalizeParseState(PrefParseState *ps) 1.149 +{ 1.150 + if (ps->lb) 1.151 + free(ps->lb); 1.152 +} 1.153 + 1.154 +/** 1.155 + * Pseudo-BNF 1.156 + * ---------- 1.157 + * function = LJUNK function-name JUNK function-args 1.158 + * function-name = "user_pref" | "pref" 1.159 + * function-args = "(" JUNK pref-name JUNK "," JUNK pref-value JUNK ")" JUNK ";" 1.160 + * pref-name = quoted-string 1.161 + * pref-value = quoted-string | "true" | "false" | integer-value 1.162 + * JUNK = *(WS | comment-block | comment-line) 1.163 + * LJUNK = *(WS | comment-block | comment-line | bcomment-line) 1.164 + * WS = SP | HT | LF | VT | FF | CR 1.165 + * SP = <US-ASCII SP, space (32)> 1.166 + * HT = <US-ASCII HT, horizontal-tab (9)> 1.167 + * LF = <US-ASCII LF, linefeed (10)> 1.168 + * VT = <US-ASCII HT, vertical-tab (11)> 1.169 + * FF = <US-ASCII FF, form-feed (12)> 1.170 + * CR = <US-ASCII CR, carriage return (13)> 1.171 + * comment-block = <C/C++ style comment block> 1.172 + * comment-line = <C++ style comment line> 1.173 + * bcomment-line = <bourne-shell style comment line> 1.174 + */ 1.175 +bool 1.176 +PREF_ParseBuf(PrefParseState *ps, const char *buf, int bufLen) 1.177 +{ 1.178 + const char *end; 1.179 + char c; 1.180 + char udigit; 1.181 + int state; 1.182 + 1.183 + state = ps->state; 1.184 + for (end = buf + bufLen; buf != end; ++buf) { 1.185 + c = *buf; 1.186 + switch (state) { 1.187 + /* initial state */ 1.188 + case PREF_PARSE_INIT: 1.189 + if (ps->lbcur != ps->lb) { /* reset state */ 1.190 + ps->lbcur = ps->lb; 1.191 + ps->vb = nullptr; 1.192 + ps->vtype = PREF_INVALID; 1.193 + ps->fdefault = false; 1.194 + } 1.195 + switch (c) { 1.196 + case '/': /* begin comment block or line? */ 1.197 + state = PREF_PARSE_COMMENT_MAYBE_START; 1.198 + break; 1.199 + case '#': /* accept shell style comments */ 1.200 + state = PREF_PARSE_UNTIL_EOL; 1.201 + break; 1.202 + case 'u': /* indicating user_pref */ 1.203 + case 'p': /* indicating pref */ 1.204 + ps->smatch = (c == 'u' ? kUserPref : kPref); 1.205 + ps->sindex = 1; 1.206 + ps->nextstate = PREF_PARSE_UNTIL_OPEN_PAREN; 1.207 + state = PREF_PARSE_MATCH_STRING; 1.208 + break; 1.209 + /* else skip char */ 1.210 + } 1.211 + break; 1.212 + 1.213 + /* string matching */ 1.214 + case PREF_PARSE_MATCH_STRING: 1.215 + if (c == ps->smatch[ps->sindex++]) { 1.216 + /* if we've matched all characters, then move to next state. */ 1.217 + if (ps->smatch[ps->sindex] == '\0') { 1.218 + state = ps->nextstate; 1.219 + ps->nextstate = PREF_PARSE_INIT; /* reset next state */ 1.220 + } 1.221 + /* else wait for next char */ 1.222 + } 1.223 + else { 1.224 + NS_WARNING("malformed pref file"); 1.225 + return false; 1.226 + } 1.227 + break; 1.228 + 1.229 + /* quoted string parsing */ 1.230 + case PREF_PARSE_QUOTED_STRING: 1.231 + /* we assume that the initial quote has already been consumed */ 1.232 + if (ps->lbcur == ps->lbend && !pref_GrowBuf(ps)) 1.233 + return false; /* out of memory */ 1.234 + if (c == '\\') 1.235 + state = PREF_PARSE_ESC_SEQUENCE; 1.236 + else if (c == ps->quotechar) { 1.237 + *ps->lbcur++ = '\0'; 1.238 + state = ps->nextstate; 1.239 + ps->nextstate = PREF_PARSE_INIT; /* reset next state */ 1.240 + } 1.241 + else 1.242 + *ps->lbcur++ = c; 1.243 + break; 1.244 + 1.245 + /* name parsing */ 1.246 + case PREF_PARSE_UNTIL_NAME: 1.247 + if (c == '\"' || c == '\'') { 1.248 + ps->fdefault = (ps->smatch == kPref); 1.249 + ps->quotechar = c; 1.250 + ps->nextstate = PREF_PARSE_UNTIL_COMMA; /* return here when done */ 1.251 + state = PREF_PARSE_QUOTED_STRING; 1.252 + } 1.253 + else if (c == '/') { /* allow embedded comment */ 1.254 + ps->nextstate = state; /* return here when done with comment */ 1.255 + state = PREF_PARSE_COMMENT_MAYBE_START; 1.256 + } 1.257 + else if (!isspace(c)) { 1.258 + NS_WARNING("malformed pref file"); 1.259 + return false; 1.260 + } 1.261 + break; 1.262 + 1.263 + /* parse until we find a comma separating name and value */ 1.264 + case PREF_PARSE_UNTIL_COMMA: 1.265 + if (c == ',') { 1.266 + ps->vb = ps->lbcur; 1.267 + state = PREF_PARSE_UNTIL_VALUE; 1.268 + } 1.269 + else if (c == '/') { /* allow embedded comment */ 1.270 + ps->nextstate = state; /* return here when done with comment */ 1.271 + state = PREF_PARSE_COMMENT_MAYBE_START; 1.272 + } 1.273 + else if (!isspace(c)) { 1.274 + NS_WARNING("malformed pref file"); 1.275 + return false; 1.276 + } 1.277 + break; 1.278 + 1.279 + /* value parsing */ 1.280 + case PREF_PARSE_UNTIL_VALUE: 1.281 + /* the pref value type is unknown. so, we scan for the first 1.282 + * character of the value, and determine the type from that. */ 1.283 + if (c == '\"' || c == '\'') { 1.284 + ps->vtype = PREF_STRING; 1.285 + ps->quotechar = c; 1.286 + ps->nextstate = PREF_PARSE_UNTIL_CLOSE_PAREN; 1.287 + state = PREF_PARSE_QUOTED_STRING; 1.288 + } 1.289 + else if (c == 't' || c == 'f') { 1.290 + ps->vb = (char *) (c == 't' ? kTrue : kFalse); 1.291 + ps->vtype = PREF_BOOL; 1.292 + ps->smatch = ps->vb; 1.293 + ps->sindex = 1; 1.294 + ps->nextstate = PREF_PARSE_UNTIL_CLOSE_PAREN; 1.295 + state = PREF_PARSE_MATCH_STRING; 1.296 + } 1.297 + else if (isdigit(c) || (c == '-') || (c == '+')) { 1.298 + ps->vtype = PREF_INT; 1.299 + /* write c to line buffer... */ 1.300 + if (ps->lbcur == ps->lbend && !pref_GrowBuf(ps)) 1.301 + return false; /* out of memory */ 1.302 + *ps->lbcur++ = c; 1.303 + state = PREF_PARSE_INT_VALUE; 1.304 + } 1.305 + else if (c == '/') { /* allow embedded comment */ 1.306 + ps->nextstate = state; /* return here when done with comment */ 1.307 + state = PREF_PARSE_COMMENT_MAYBE_START; 1.308 + } 1.309 + else if (!isspace(c)) { 1.310 + NS_WARNING("malformed pref file"); 1.311 + return false; 1.312 + } 1.313 + break; 1.314 + case PREF_PARSE_INT_VALUE: 1.315 + /* grow line buffer if necessary... */ 1.316 + if (ps->lbcur == ps->lbend && !pref_GrowBuf(ps)) 1.317 + return false; /* out of memory */ 1.318 + if (isdigit(c)) 1.319 + *ps->lbcur++ = c; 1.320 + else { 1.321 + *ps->lbcur++ = '\0'; /* stomp null terminator; we are done. */ 1.322 + if (c == ')') 1.323 + state = PREF_PARSE_UNTIL_SEMICOLON; 1.324 + else if (c == '/') { /* allow embedded comment */ 1.325 + ps->nextstate = PREF_PARSE_UNTIL_CLOSE_PAREN; 1.326 + state = PREF_PARSE_COMMENT_MAYBE_START; 1.327 + } 1.328 + else if (isspace(c)) 1.329 + state = PREF_PARSE_UNTIL_CLOSE_PAREN; 1.330 + else { 1.331 + NS_WARNING("malformed pref file"); 1.332 + return false; 1.333 + } 1.334 + } 1.335 + break; 1.336 + 1.337 + /* comment parsing */ 1.338 + case PREF_PARSE_COMMENT_MAYBE_START: 1.339 + switch (c) { 1.340 + case '*': /* comment block */ 1.341 + state = PREF_PARSE_COMMENT_BLOCK; 1.342 + break; 1.343 + case '/': /* comment line */ 1.344 + state = PREF_PARSE_UNTIL_EOL; 1.345 + break; 1.346 + default: 1.347 + /* pref file is malformed */ 1.348 + NS_WARNING("malformed pref file"); 1.349 + return false; 1.350 + } 1.351 + break; 1.352 + case PREF_PARSE_COMMENT_BLOCK: 1.353 + if (c == '*') 1.354 + state = PREF_PARSE_COMMENT_BLOCK_MAYBE_END; 1.355 + break; 1.356 + case PREF_PARSE_COMMENT_BLOCK_MAYBE_END: 1.357 + switch (c) { 1.358 + case '/': 1.359 + state = ps->nextstate; 1.360 + ps->nextstate = PREF_PARSE_INIT; 1.361 + break; 1.362 + case '*': /* stay in this state */ 1.363 + break; 1.364 + default: 1.365 + state = PREF_PARSE_COMMENT_BLOCK; 1.366 + } 1.367 + break; 1.368 + 1.369 + /* string escape sequence parsing */ 1.370 + case PREF_PARSE_ESC_SEQUENCE: 1.371 + /* not necessary to resize buffer here since we should be writing 1.372 + * only one character and the resize check would have been done 1.373 + * for us in the previous state */ 1.374 + switch (c) { 1.375 + case '\"': 1.376 + case '\'': 1.377 + case '\\': 1.378 + break; 1.379 + case 'r': 1.380 + c = '\r'; 1.381 + break; 1.382 + case 'n': 1.383 + c = '\n'; 1.384 + break; 1.385 + case 'x': /* hex escape -- always interpreted as Latin-1 */ 1.386 + case 'u': /* UTF16 escape */ 1.387 + ps->esctmp[0] = c; 1.388 + ps->esclen = 1; 1.389 + ps->utf16[0] = ps->utf16[1] = 0; 1.390 + ps->sindex = (c == 'x' ) ? 1.391 + HEX_ESC_NUM_DIGITS : 1.392 + UTF16_ESC_NUM_DIGITS; 1.393 + state = PREF_PARSE_HEX_ESCAPE; 1.394 + continue; 1.395 + default: 1.396 + NS_WARNING("preserving unexpected JS escape sequence"); 1.397 + /* Invalid escape sequence so we do have to write more than 1.398 + * one character. Grow line buffer if necessary... */ 1.399 + if ((ps->lbcur+1) == ps->lbend && !pref_GrowBuf(ps)) 1.400 + return false; /* out of memory */ 1.401 + *ps->lbcur++ = '\\'; /* preserve the escape sequence */ 1.402 + break; 1.403 + } 1.404 + *ps->lbcur++ = c; 1.405 + state = PREF_PARSE_QUOTED_STRING; 1.406 + break; 1.407 + 1.408 + /* parsing a hex (\xHH) or utf16 escape (\uHHHH) */ 1.409 + case PREF_PARSE_HEX_ESCAPE: 1.410 + if ( c >= '0' && c <= '9' ) 1.411 + udigit = (c - '0'); 1.412 + else if ( c >= 'A' && c <= 'F' ) 1.413 + udigit = (c - 'A') + 10; 1.414 + else if ( c >= 'a' && c <= 'f' ) 1.415 + udigit = (c - 'a') + 10; 1.416 + else { 1.417 + /* bad escape sequence found, write out broken escape as-is */ 1.418 + NS_WARNING("preserving invalid or incomplete hex escape"); 1.419 + *ps->lbcur++ = '\\'; /* original escape slash */ 1.420 + if ((ps->lbcur + ps->esclen) >= ps->lbend && !pref_GrowBuf(ps)) 1.421 + return false; 1.422 + for (int i = 0; i < ps->esclen; ++i) 1.423 + *ps->lbcur++ = ps->esctmp[i]; 1.424 + 1.425 + /* push the non-hex character back for re-parsing. */ 1.426 + /* (++buf at the top of the loop keeps this safe) */ 1.427 + --buf; 1.428 + state = PREF_PARSE_QUOTED_STRING; 1.429 + continue; 1.430 + } 1.431 + 1.432 + /* have a digit */ 1.433 + ps->esctmp[ps->esclen++] = c; /* preserve it */ 1.434 + ps->utf16[1] <<= BITS_PER_HEX_DIGIT; 1.435 + ps->utf16[1] |= udigit; 1.436 + ps->sindex--; 1.437 + if (ps->sindex == 0) { 1.438 + /* have the full escape. Convert to UTF8 */ 1.439 + int utf16len = 0; 1.440 + if (ps->utf16[0]) { 1.441 + /* already have a high surrogate, this is a two char seq */ 1.442 + utf16len = 2; 1.443 + } 1.444 + else if (0xD800 == (0xFC00 & ps->utf16[1])) { 1.445 + /* a high surrogate, can't convert until we have the low */ 1.446 + ps->utf16[0] = ps->utf16[1]; 1.447 + ps->utf16[1] = 0; 1.448 + state = PREF_PARSE_UTF16_LOW_SURROGATE; 1.449 + break; 1.450 + } 1.451 + else { 1.452 + /* a single utf16 character */ 1.453 + ps->utf16[0] = ps->utf16[1]; 1.454 + utf16len = 1; 1.455 + } 1.456 + 1.457 + /* actual conversion */ 1.458 + /* make sure there's room, 6 bytes is max utf8 len (in */ 1.459 + /* theory; 4 bytes covers the actual utf16 range) */ 1.460 + if (ps->lbcur+6 >= ps->lbend && !pref_GrowBuf(ps)) 1.461 + return false; 1.462 + 1.463 + ConvertUTF16toUTF8 converter(ps->lbcur); 1.464 + converter.write(ps->utf16, utf16len); 1.465 + ps->lbcur += converter.Size(); 1.466 + state = PREF_PARSE_QUOTED_STRING; 1.467 + } 1.468 + break; 1.469 + 1.470 + /* looking for beginning of utf16 low surrogate */ 1.471 + case PREF_PARSE_UTF16_LOW_SURROGATE: 1.472 + if (ps->sindex == 0 && c == '\\') { 1.473 + ++ps->sindex; 1.474 + } 1.475 + else if (ps->sindex == 1 && c == 'u') { 1.476 + /* escape sequence is correct, now parse hex */ 1.477 + ps->sindex = UTF16_ESC_NUM_DIGITS; 1.478 + ps->esctmp[0] = 'u'; 1.479 + ps->esclen = 1; 1.480 + state = PREF_PARSE_HEX_ESCAPE; 1.481 + } 1.482 + else { 1.483 + /* didn't find expected low surrogate. Ignore high surrogate 1.484 + * (it would just get converted to nothing anyway) and start 1.485 + * over with this character */ 1.486 + --buf; 1.487 + if (ps->sindex == 1) 1.488 + state = PREF_PARSE_ESC_SEQUENCE; 1.489 + else 1.490 + state = PREF_PARSE_QUOTED_STRING; 1.491 + continue; 1.492 + } 1.493 + break; 1.494 + 1.495 + /* function open and close parsing */ 1.496 + case PREF_PARSE_UNTIL_OPEN_PAREN: 1.497 + /* tolerate only whitespace and embedded comments */ 1.498 + if (c == '(') 1.499 + state = PREF_PARSE_UNTIL_NAME; 1.500 + else if (c == '/') { 1.501 + ps->nextstate = state; /* return here when done with comment */ 1.502 + state = PREF_PARSE_COMMENT_MAYBE_START; 1.503 + } 1.504 + else if (!isspace(c)) { 1.505 + NS_WARNING("malformed pref file"); 1.506 + return false; 1.507 + } 1.508 + break; 1.509 + case PREF_PARSE_UNTIL_CLOSE_PAREN: 1.510 + /* tolerate only whitespace and embedded comments */ 1.511 + if (c == ')') 1.512 + state = PREF_PARSE_UNTIL_SEMICOLON; 1.513 + else if (c == '/') { 1.514 + ps->nextstate = state; /* return here when done with comment */ 1.515 + state = PREF_PARSE_COMMENT_MAYBE_START; 1.516 + } 1.517 + else if (!isspace(c)) { 1.518 + NS_WARNING("malformed pref file"); 1.519 + return false; 1.520 + } 1.521 + break; 1.522 + 1.523 + /* function terminator ';' parsing */ 1.524 + case PREF_PARSE_UNTIL_SEMICOLON: 1.525 + /* tolerate only whitespace and embedded comments */ 1.526 + if (c == ';') { 1.527 + if (!pref_DoCallback(ps)) 1.528 + return false; 1.529 + state = PREF_PARSE_INIT; 1.530 + } 1.531 + else if (c == '/') { 1.532 + ps->nextstate = state; /* return here when done with comment */ 1.533 + state = PREF_PARSE_COMMENT_MAYBE_START; 1.534 + } 1.535 + else if (!isspace(c)) { 1.536 + NS_WARNING("malformed pref file"); 1.537 + return false; 1.538 + } 1.539 + break; 1.540 + 1.541 + /* eol parsing */ 1.542 + case PREF_PARSE_UNTIL_EOL: 1.543 + /* need to handle mac, unix, or dos line endings. 1.544 + * PREF_PARSE_INIT will eat the next \n in case 1.545 + * we have \r\n. */ 1.546 + if (c == '\r' || c == '\n' || c == 0x1A) { 1.547 + state = ps->nextstate; 1.548 + ps->nextstate = PREF_PARSE_INIT; /* reset next state */ 1.549 + } 1.550 + break; 1.551 + } 1.552 + } 1.553 + ps->state = state; 1.554 + return true; 1.555 +} 1.556 + 1.557 +#ifdef TEST_PREFREAD 1.558 + 1.559 +static void 1.560 +pref_reader(void *closure, 1.561 + const char *pref, 1.562 + PrefValue val, 1.563 + PrefType type, 1.564 + bool defPref) 1.565 +{ 1.566 + printf("%spref(\"%s\", ", defPref ? "" : "user_", pref); 1.567 + switch (type) { 1.568 + case PREF_STRING: 1.569 + printf("\"%s\");\n", val.stringVal); 1.570 + break; 1.571 + case PREF_INT: 1.572 + printf("%i);\n", val.intVal); 1.573 + break; 1.574 + case PREF_BOOL: 1.575 + printf("%s);\n", val.boolVal == false ? "false" : "true"); 1.576 + break; 1.577 + } 1.578 +} 1.579 + 1.580 +int 1.581 +main(int argc, char **argv) 1.582 +{ 1.583 + PrefParseState ps; 1.584 + char buf[4096]; /* i/o buffer */ 1.585 + FILE *fp; 1.586 + int n; 1.587 + 1.588 + if (argc == 1) { 1.589 + printf("usage: prefread file.js\n"); 1.590 + return -1; 1.591 + } 1.592 + 1.593 + fp = fopen(argv[1], "r"); 1.594 + if (!fp) { 1.595 + printf("failed to open file\n"); 1.596 + return -1; 1.597 + } 1.598 + 1.599 + PREF_InitParseState(&ps, pref_reader, nullptr); 1.600 + 1.601 + while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) 1.602 + PREF_ParseBuf(&ps, buf, n); 1.603 + 1.604 + PREF_FinalizeParseState(&ps); 1.605 + 1.606 + fclose(fp); 1.607 + return 0; 1.608 +} 1.609 + 1.610 +#endif /* TEST_PREFREAD */