1
/* ***** BEGIN LICENSE BLOCK *****
2
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
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/
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
14
* The Original Code is Mozilla.
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.
21
* Darin Fisher <darin@meer.net>
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.
35
* ***** END LICENSE BLOCK ***** */
44
#define NS_WARNING(_s) printf(">>> " _s "!\n")
45
#define NS_NOTREACHED(_s) NS_WARNING(_s)
47
#include "nsDebug.h" // for NS_WARNING
50
/* pref parser states */
53
PREF_PARSE_MATCH_STRING,
54
PREF_PARSE_UNTIL_NAME,
55
PREF_PARSE_QUOTED_STRING,
56
PREF_PARSE_UNTIL_COMMA,
57
PREF_PARSE_UNTIL_VALUE,
59
PREF_PARSE_COMMENT_MAYBE_START,
60
PREF_PARSE_COMMENT_BLOCK,
61
PREF_PARSE_COMMENT_BLOCK_MAYBE_END,
62
PREF_PARSE_ESC_SEQUENCE,
63
PREF_PARSE_UNTIL_OPEN_PAREN,
64
PREF_PARSE_UNTIL_CLOSE_PAREN,
65
PREF_PARSE_UNTIL_SEMICOLON,
69
static const char kUserPref[] = "user_pref";
70
static const char kPref[] = "pref";
71
static const char kTrue[] = "true";
72
static const char kFalse[] = "false";
77
* this function will increase the size of the buffer owned
78
* by the given pref parse state. the only requirement is
79
* that it increase the buffer by at least one byte, but we
80
* use a simple doubling algorithm.
82
* this buffer is used to store partial pref lines. it is
83
* freed when the parse state is destroyed.
86
* parse state instance
88
* this function updates all pointers that reference an
89
* address within lb since realloc may relocate the buffer.
91
* @return PR_FALSE if insufficient memory.
94
pref_GrowBuf(PrefParseState *ps)
96
int bufLen, curPos, valPos;
98
bufLen = ps->lbend - ps->lb;
99
curPos = ps->lbcur - ps->lb;
100
valPos = ps->vb - ps->lb;
103
bufLen = 128; /* default buffer size */
105
bufLen <<= 1; /* double buffer size */
108
fprintf(stderr, ">>> realloc(%d)\n", bufLen);
111
ps->lb = (char*) realloc(ps->lb, bufLen);
115
ps->lbcur = ps->lb + curPos;
116
ps->lbend = ps->lb + bufLen;
117
ps->vb = ps->lb + valPos;
125
* this function is called when a complete pref name-value pair has
126
* been extracted from the input data.
129
* parse state instance
131
* @return PR_FALSE to indicate a fatal error.
134
pref_DoCallback(PrefParseState *ps)
140
value.stringVal = ps->vb;
143
if ((ps->vb[0] == '-' || ps->vb[0] == '+') && ps->vb[1] == '\0') {
144
NS_WARNING("malformed integer value");
147
value.intVal = atoi(ps->vb);
150
value.boolVal = (ps->vb == kTrue);
155
(*ps->reader)(ps->closure, ps->lb, value, ps->vtype, ps->fdefault);
160
PREF_InitParseState(PrefParseState *ps, PrefReader reader, void *closure)
162
memset(ps, 0, sizeof(*ps));
164
ps->closure = closure;
168
PREF_FinalizeParseState(PrefParseState *ps)
177
* function = LJUNK function-name JUNK function-args
178
* function-name = "user_pref" | "pref"
179
* function-args = "(" JUNK pref-name JUNK "," JUNK pref-value JUNK ")" JUNK ";"
180
* pref-name = quoted-string
181
* pref-value = quoted-string | "true" | "false" | integer-value
182
* JUNK = *(WS | comment-block | comment-line)
183
* LJUNK = *(WS | comment-block | comment-line | bcomment-line)
184
* WS = SP | HT | LF | VT | FF | CR
185
* SP = <US-ASCII SP, space (32)>
186
* HT = <US-ASCII HT, horizontal-tab (9)>
187
* LF = <US-ASCII LF, linefeed (10)>
188
* VT = <US-ASCII HT, vertical-tab (11)>
189
* FF = <US-ASCII FF, form-feed (12)>
190
* CR = <US-ASCII CR, carriage return (13)>
191
* comment-block = <C/C++ style comment block>
192
* comment-line = <C++ style comment line>
193
* bcomment-line = <bourne-shell style comment line>
196
PREF_ParseBuf(PrefParseState *ps, const char *buf, int bufLen)
203
for (end = buf + bufLen; buf != end; ++buf) {
207
case PREF_PARSE_INIT:
208
if (ps->lbcur != ps->lb) { /* reset state */
211
ps->vtype = PREF_INVALID;
212
ps->fdefault = PR_FALSE;
215
case '/': /* begin comment block or line? */
216
state = PREF_PARSE_COMMENT_MAYBE_START;
218
case '#': /* accept shell style comments */
219
state = PREF_PARSE_UNTIL_EOL;
221
case 'u': /* indicating user_pref */
222
case 'p': /* indicating pref */
223
ps->smatch = (c == 'u' ? kUserPref : kPref);
225
ps->nextstate = PREF_PARSE_UNTIL_OPEN_PAREN;
226
state = PREF_PARSE_MATCH_STRING;
232
/* string matching */
233
case PREF_PARSE_MATCH_STRING:
234
if (c == ps->smatch[ps->sindex++]) {
235
/* if we've matched all characters, then move to next state. */
236
if (ps->smatch[ps->sindex] == '\0') {
237
state = ps->nextstate;
238
ps->nextstate = PREF_PARSE_INIT; /* reset next state */
240
/* else wait for next char */
243
NS_WARNING("malformed pref file");
248
/* quoted string parsing */
249
case PREF_PARSE_QUOTED_STRING:
250
/* we assume that the initial quote has already been consumed */
251
if (ps->lbcur == ps->lbend && !pref_GrowBuf(ps))
252
return PR_FALSE; /* out of memory */
254
state = PREF_PARSE_ESC_SEQUENCE;
255
else if (c == ps->quotechar) {
257
state = ps->nextstate;
258
ps->nextstate = PREF_PARSE_INIT; /* reset next state */
265
case PREF_PARSE_UNTIL_NAME:
266
if (c == '\"' || c == '\'') {
267
ps->fdefault = (ps->smatch == kPref);
269
ps->nextstate = PREF_PARSE_UNTIL_COMMA; /* return here when done */
270
state = PREF_PARSE_QUOTED_STRING;
272
else if (c == '/') { /* allow embedded comment */
273
ps->nextstate = state; /* return here when done with comment */
274
state = PREF_PARSE_COMMENT_MAYBE_START;
276
else if (!isspace(c)) {
277
NS_WARNING("malformed pref file");
282
/* parse until we find a comma separating name and value */
283
case PREF_PARSE_UNTIL_COMMA:
286
state = PREF_PARSE_UNTIL_VALUE;
288
else if (c == '/') { /* allow embedded comment */
289
ps->nextstate = state; /* return here when done with comment */
290
state = PREF_PARSE_COMMENT_MAYBE_START;
292
else if (!isspace(c)) {
293
NS_WARNING("malformed pref file");
299
case PREF_PARSE_UNTIL_VALUE:
300
/* the pref value type is unknown. so, we scan for the first
301
* character of the value, and determine the type from that. */
302
if (c == '\"' || c == '\'') {
303
ps->vtype = PREF_STRING;
305
ps->nextstate = PREF_PARSE_UNTIL_CLOSE_PAREN;
306
state = PREF_PARSE_QUOTED_STRING;
308
else if (c == 't' || c == 'f') {
309
ps->vb = (char *) (c == 't' ? kTrue : kFalse);
310
ps->vtype = PREF_BOOL;
313
ps->nextstate = PREF_PARSE_UNTIL_CLOSE_PAREN;
314
state = PREF_PARSE_MATCH_STRING;
316
else if (isdigit(c) || (c == '-') || (c == '+')) {
317
ps->vtype = PREF_INT;
318
/* write c to line buffer... */
319
if (ps->lbcur == ps->lbend && !pref_GrowBuf(ps))
320
return PR_FALSE; /* out of memory */
322
state = PREF_PARSE_INT_VALUE;
324
else if (c == '/') { /* allow embedded comment */
325
ps->nextstate = state; /* return here when done with comment */
326
state = PREF_PARSE_COMMENT_MAYBE_START;
328
else if (!isspace(c)) {
329
NS_WARNING("malformed pref file");
333
case PREF_PARSE_INT_VALUE:
334
/* grow line buffer if necessary... */
335
if (ps->lbcur == ps->lbend && !pref_GrowBuf(ps))
336
return PR_FALSE; /* out of memory */
340
*ps->lbcur++ = '\0'; /* stomp null terminator; we are done. */
342
state = PREF_PARSE_UNTIL_SEMICOLON;
343
else if (c == '/') { /* allow embedded comment */
344
ps->nextstate = PREF_PARSE_UNTIL_CLOSE_PAREN;
345
state = PREF_PARSE_COMMENT_MAYBE_START;
348
state = PREF_PARSE_UNTIL_CLOSE_PAREN;
350
NS_WARNING("malformed pref file");
356
/* comment parsing */
357
case PREF_PARSE_COMMENT_MAYBE_START:
359
case '*': /* comment block */
360
state = PREF_PARSE_COMMENT_BLOCK;
362
case '/': /* comment line */
363
state = PREF_PARSE_UNTIL_EOL;
366
/* pref file is malformed */
367
NS_WARNING("malformed pref file");
371
case PREF_PARSE_COMMENT_BLOCK:
373
state = PREF_PARSE_COMMENT_BLOCK_MAYBE_END;
375
case PREF_PARSE_COMMENT_BLOCK_MAYBE_END:
378
state = ps->nextstate;
379
ps->nextstate = PREF_PARSE_INIT;
381
case '*': /* stay in this state */
384
state = PREF_PARSE_COMMENT_BLOCK;
388
/* string escape sequence parsing */
389
case PREF_PARSE_ESC_SEQUENCE:
390
/* not necessary to resize buffer here since we should be writing
391
* only one character and the resize check would have been done
392
* for us in the previous state */
404
NS_WARNING("preserving unexpected JS escape sequence");
405
/* grow line buffer if necessary... */
406
if (ps->lbcur == ps->lbend && !pref_GrowBuf(ps))
407
return PR_FALSE; /* out of memory */
408
*ps->lbcur++ = '\\'; /* preserve the escape sequence */
412
state = PREF_PARSE_QUOTED_STRING;
415
/* function open and close parsing */
416
case PREF_PARSE_UNTIL_OPEN_PAREN:
417
/* tolerate only whitespace and embedded comments */
419
state = PREF_PARSE_UNTIL_NAME;
421
ps->nextstate = state; /* return here when done with comment */
422
state = PREF_PARSE_COMMENT_MAYBE_START;
424
else if (!isspace(c)) {
425
NS_WARNING("malformed pref file");
429
case PREF_PARSE_UNTIL_CLOSE_PAREN:
430
/* tolerate only whitespace and embedded comments */
432
state = PREF_PARSE_UNTIL_SEMICOLON;
434
ps->nextstate = state; /* return here when done with comment */
435
state = PREF_PARSE_COMMENT_MAYBE_START;
437
else if (!isspace(c)) {
438
NS_WARNING("malformed pref file");
443
/* function terminator ';' parsing */
444
case PREF_PARSE_UNTIL_SEMICOLON:
445
/* tolerate only whitespace and embedded comments */
447
if (!pref_DoCallback(ps))
449
state = PREF_PARSE_INIT;
452
ps->nextstate = state; /* return here when done with comment */
453
state = PREF_PARSE_COMMENT_MAYBE_START;
455
else if (!isspace(c)) {
456
NS_WARNING("malformed pref file");
462
case PREF_PARSE_UNTIL_EOL:
463
/* need to handle mac, unix, or dos line endings.
464
* PREF_PARSE_INIT will eat the next \n in case
466
if (c == '\r' || c == '\n' || c == 0x1A) {
467
state = ps->nextstate;
468
ps->nextstate = PREF_PARSE_INIT; /* reset next state */
480
pref_reader(void *closure,
486
printf("%spref(\"%s\", ", defPref ? "" : "user_", pref);
489
printf("\"%s\");\n", val.stringVal);
492
printf("%i);\n", val.intVal);
495
printf("%s);\n", val.boolVal == PR_FALSE ? "false" : "true");
501
main(int argc, char **argv)
504
char buf[4096]; /* i/o buffer */
509
printf("usage: prefread file.js\n");
513
fp = fopen(argv[1], "r");
515
printf("failed to open file\n");
519
PREF_InitParseState(&ps, pref_reader, NULL);
521
while ((n = fread(buf, 1, sizeof(buf), fp)) > 0)
522
PREF_ParseBuf(&ps, buf, n);
524
PREF_FinalizeParseState(&ps);
530
#endif /* TEST_PREFREAD */