parser.c

changeset 2
e14a1aba4c56
parent 1
6e704fc09528
child 5
f878a9ffa3e0
equal deleted inserted replaced
1:6e704fc09528 2:e14a1aba4c56
16 #define MAX_TOKENS 32 16 #define MAX_TOKENS 32
17 #define MAX_NEST 16 17 #define MAX_NEST 16
18 18
19 19
20 enum{ 20 enum{
21 P_NONE=1,
21 P_EOF, 22 P_EOF,
22 P_OK, 23 P_STMT,
23 P_ERROR, 24 P_STMT_NS,
25 P_STMT_SECT,
24 P_BEG_SECT, 26 P_BEG_SECT,
25 P_END_SECT 27 P_END_SECT
26 }; 28 };
27 29
28 30
42 44
43 45
44 /* */ 46 /* */
45 47
46 48
47 static int read_statement(const ConfOpt **opt_ret, Token *tokens, 49 static int read_statement(Tokenizer *tokz, Token *tokens, int *ntok_ret)
48 int *ntok_ret, Tokenizer *tokz,
49 const ConfOpt *options)
50 { 50 {
51 int ntokens=0; 51 int ntokens=0;
52 Token *tok=NULL; 52 Token *tok=NULL;
53 const ConfOpt *opt=NULL; 53 int had_comma=0; /* 0 - no, 1 - yes, 2 - not had, not expected */
54 int had_comma=0; 54 int retval=0;
55 int retval=P_OK;
56 int e=0; 55 int e=0;
57 int e_line=0;
58 56
59 while(1){ 57 while(1){
58 tok=&tokens[ntokens];
59
60 if(!tokz_get_token(tokz, tok)){
61 e=1;
62 continue;
63 }
64
60 if(ntokens==MAX_TOKENS-1){ 65 if(ntokens==MAX_TOKENS-1){
61 e=E_TOKZ_TOKEN_LIMIT; 66 e=E_TOKZ_TOKEN_LIMIT;
62 goto ret_err; 67 tokz_warn_error(tokz, tok->line, e);
63 } 68 if(!(tokz->flags&TOKZ_ERROR_TOLERANT))
64 69 break;
65 tok=&tokens[ntokens]; 70 }else{
66 71 ntokens++;
67 if(!tokz_get_token(tokz, tok)) 72 }
68 goto ret_err;
69
70 ntokens++;
71 73
72 if(!TOK_IS_OP(tok)){ 74 if(!TOK_IS_OP(tok)){
73 if(ntokens==1 && !had_comma){ 75 if(ntokens==1 && !had_comma){
74 if(!TOK_IS_IDENT(tok)){ 76 /*if(!TOK_IS_IDENT(tok)){
75 e=E_TOKZ_IDENTIFIER_EXPECTED; 77 e=E_TOKZ_IDENTIFIER_EXPECTED;
76 goto ret_err; 78 goto handle_error;
77 } 79 }*/
78 80
79 /* find the option */
80 for(opt=options; opt->optname; opt++){
81 if(strcmp(opt->optname, TOK_IDENT_VAL(tok))==0)
82 break;
83 }
84
85 if(opt->optname==NULL){
86 /* common opt? include, etc. */
87 for(opt=common_opts; opt->optname; opt++){
88 if(strcmp(opt->optname, TOK_IDENT_VAL(tok))==0)
89 break;
90 }
91 if(opt->optname==NULL){
92 e=E_TOKZ_UNKNOWN_OPTION;
93 e_line=tok->line;
94 retval=P_ERROR;
95 }
96 }
97
98 had_comma=2; 81 had_comma=2;
99 }else{ 82 }else{
100 if(!had_comma){ 83 if(had_comma==0)
101 e=E_TOKZ_SYNTAX; 84 goto syntax;
102 goto ret_err;
103 }
104 85
105 had_comma=0; 86 had_comma=0;
106 } 87 }
107 continue; 88 continue;
108 } 89 }
109 90
110 /* It is an operator */ 91 /* It is an operator */
92 ntokens--;
111 93
112 switch(TOK_OP_VAL(tok)){ 94 switch(TOK_OP_VAL(tok)){
113 case OP_SCOLON: 95 case OP_SCOLON:
114 if(opt){ 96 retval=(ntokens==0 ? P_NONE : P_STMT_NS);
115 if(had_comma || opt->opts){
116 e=E_TOKZ_SYNTAX;
117 goto ret_err;
118 }
119 goto ret_success;
120 }
121 break; 97 break;
122 98
123 case OP_NEXTLINE: 99 case OP_NEXTLINE:
124 if(had_comma==1){ 100 retval=(ntokens==0 ? P_NONE : P_STMT);
125 e=E_TOKZ_SYNTAX; 101 break;
126 e_line=tok->line-1; 102
127 goto ret_err2; 103 case OP_L_BRC:
128 } 104 retval=(ntokens==0 ? P_BEG_SECT : P_STMT_SECT);
129 105 break;
130 if(opt && !opt->opts) 106
131 goto ret_success; 107 case OP_R_BRC:
132 break; 108 if(ntokens==0){
133 109 retval=P_END_SECT;
110 }else{
111 tokz_unget_token(tokz, tok);
112 retval=P_STMT_NS;
113 }
114 break;
115
134 case OP_EOF: 116 case OP_EOF:
117 retval=(ntokens==0 ? P_EOF : P_STMT_NS);
118
135 if(had_comma==1){ 119 if(had_comma==1){
136 e=E_TOKZ_UNEXPECTED_EOF; 120 e=E_TOKZ_UNEXPECTED_EOF;
137 goto ret_err; 121 goto handle_error;
138 } 122 }
139 123
140 if(opt && opt->opts){ 124 goto end;
141 e=E_TOKZ_UNEXPECTED_EOF;
142 goto ret_err;
143 }
144
145 retval=P_EOF;
146 goto ret_success;
147
148 case OP_R_BRC:
149 if(had_comma==1){
150 e=E_TOKZ_SYNTAX;
151 goto ret_err;
152 }
153
154 if(opt && opt->opts){
155 e=E_TOKZ_SYNTAX;
156 goto ret_err;
157 }
158
159 retval=P_END_SECT;
160 goto ret_success;
161
162 case OP_L_BRC:
163 if(had_comma==1 || !opt || !opt->opts){
164 e=E_TOKZ_SYNTAX;
165 goto ret_err;
166 }
167
168 retval=P_BEG_SECT;
169 goto ret_success;
170 125
171 case OP_COMMA: 126 case OP_COMMA:
172 if(had_comma){ 127 if(had_comma!=0)
173 e=E_TOKZ_SYNTAX; 128 goto syntax;
174 goto ret_err; 129
175 }
176 had_comma=1; 130 had_comma=1;
177 break; 131 continue;
178 132
179 default: 133 default:
180 e=E_TOKZ_SYNTAX; 134 goto syntax;
181 goto ret_err; 135 }
182 } 136
183 137 if(had_comma!=1)
184 ntokens--; 138 break;
185 } 139
186 140 syntax:
187 ret_err: 141 e=E_TOKZ_SYNTAX;
188 e_line=tok->line; 142 handle_error:
189 ret_err2: 143 tokz_warn_error(tokz, tok->line, e);
190 retval=P_ERROR; 144
191 145 if(!(tokz->flags&TOKZ_ERROR_TOLERANT) || retval!=0)
192 ret_success: 146 break;
193 if(retval==P_ERROR && e!=0) 147 }
194 tokz_warn_error(tokz, e_line, e); 148
195 149 end:
196 *opt_ret=opt; 150 if(e!=0)
151 retval=-retval;
152
197 *ntok_ret=ntokens; 153 *ntok_ret=ntokens;
198 154
199 return retval; 155 return retval;
200 } 156 }
201 157
202 158
159 static bool find_beg_sect(Tokenizer *tokz)
160 {
161 Token tok;
162
163 while(tokz_get_token(tokz, &tok)){
164 if(TOK_IS_OP(&tok)){
165 if(TOK_OP_VAL(&tok)==OP_NEXTLINE)
166 continue;
167
168 if(TOK_OP_VAL(&tok)==OP_SCOLON)
169 return FALSE;
170
171 if(TOK_OP_VAL(&tok)==OP_L_BRC)
172 return TRUE;
173 }
174
175 tokz_unget_token(tokz, &tok);
176 break;
177 }
178 return FALSE;
179 }
180
181
203 /* */ 182 /* */
204 183
205 184
206 static bool call_end_sect(Tokenizer *tokz, const ConfOpt *options) 185 static const ConfOpt* lookup_option(const ConfOpt *opts, const char *name)
186 {
187 while(opts->optname!=NULL){
188 if(strcmp(opts->optname, name)==0)
189 return opts;
190 opts++;
191 }
192 return NULL;
193 }
194
195
196 static bool call_end_sect(Tokenizer *tokz, const ConfOpt *opts)
207 { 197 {
208 bool retval=TRUE; 198 opts=lookup_option(opts, "#end");
209 199 if(opts!=NULL)
210 while(options->optname){ 200 return opts->fn(tokz, 0, NULL);
211 if(strcmp(options->optname, "#end")==0){ 201
212 retval=options->fn(tokz, 0, NULL); 202 return TRUE;
213 break; 203 }
214 } 204
215 options++; 205
216 } 206 static bool call_cancel_sect(Tokenizer *tokz, const ConfOpt *opts)
217 207 {
218 return retval; 208 opts=lookup_option(opts, "#cancel");
219 } 209 if(opts!=NULL)
220 210 return opts->fn(tokz, 0, NULL);
221 211
222 static void call_cancel_sect(Tokenizer *tokz, const ConfOpt *options) 212 return TRUE;
223 {
224 while(options->optname){
225 if(strcmp(options->optname, "#cancel")==0){
226 options->fn(tokz, 0, NULL);
227 break;
228 }
229 options++;
230 }
231 } 213 }
232 214
233 215
234 /* */ 216 /* */
235 217
236 218
237 /* Does the parsing work
238 */
239 bool parse_config_tokz(Tokenizer *tokz, const ConfOpt *options) 219 bool parse_config_tokz(Tokenizer *tokz, const ConfOpt *options)
240 { 220 {
241 Token tokens[MAX_TOKENS]; 221 Token tokens[MAX_TOKENS];
242 bool alloced_optstack=FALSE; 222 bool alloced_optstack=FALSE;
243 int i, t, ntokens; 223 int i, t, ntokens=0;
244 int init_nest_lvl; 224 int init_nest_lvl;
245 bool had_error=FALSE; 225 bool had_error;
226 int errornest=0;
246 227
247 /* Allocate tokz->optstack if it does not yet exist (if it does, 228 /* Allocate tokz->optstack if it does not yet exist (if it does,
248 * we have been called from an option handler) 229 * we have been called from an option handler)
249 */ 230 */
250 if(!tokz->optstack){ 231 if(!tokz->optstack){
261 init_nest_lvl=tokz->nest_lvl; 242 init_nest_lvl=tokz->nest_lvl;
262 } 243 }
263 244
264 tokz->optstack[init_nest_lvl]=options; 245 tokz->optstack[init_nest_lvl]=options;
265 246
266 for(i=0;i<MAX_TOKENS;i++) 247 for(i=0; i<MAX_TOKENS; i++)
267 tok_init(&tokens[i]); 248 tok_init(&tokens[i]);
268 249
269 250
270 /* The loop 251 /* The loop
271 */ 252 */
272 while(1){ 253 while(1){
273 t=read_statement(&options, tokens, &ntokens, 254 had_error=FALSE;
274 tokz, tokz->optstack[tokz->nest_lvl]); 255
275
276 had_error=(t==P_ERROR);
277
278 /* Check that arguments are ok */
279 if(!had_error && options)
280 had_error=!check_args(tokz, tokens, ntokens, options->argfmt);
281
282 if(tokz->flags&TOKZ_PARSER_INDENT_MODE)
283 verbose_indent(tokz->nest_lvl);
284
285 /* New section? */
286 if(t==P_BEG_SECT){
287 if(tokz->nest_lvl==MAX_NEST-1){
288 tokz_warn_error(tokz, tokz->line, E_TOKZ_MAX_NEST);
289 had_error=TRUE;
290 while(ntokens--)
291 tok_free(&tokens[ntokens]);
292 break;
293 }else{
294 tokz->optstack[++tokz->nest_lvl]=options->opts;
295 }
296 }
297
298 /* call the handler */
299 if(!had_error && options && options->fn)
300 had_error=!options->fn(tokz, ntokens-1, tokens);
301
302 /* free the tokens */ 256 /* free the tokens */
303 while(ntokens--) 257 while(ntokens--)
304 tok_free(&tokens[ntokens]); 258 tok_free(&tokens[ntokens]);
305 259
306 switch(t){ 260 /* read the tokens */
307 case P_BEG_SECT: 261 t=read_statement(tokz, tokens, &ntokens);
308 if(!had_error) 262
309 continue; 263 if((had_error=t<0))
310 /* #cancel handler should not be called when 264 t=-t;
311 * error occured in section begin handler */ 265
312 tokz->nest_lvl--; 266 switch(t){
313 break; 267 case P_STMT:
314 268 case P_STMT_NS:
269 case P_STMT_SECT:
270
271 if(errornest)
272 had_error=TRUE;
273 else if(tokz->flags&TOKZ_PARSER_INDENT_MODE)
274 verbose_indent(tokz->nest_lvl);
275
276 if(!TOK_IS_IDENT(tokens+0)){
277 had_error=TRUE;
278 tokz_warn_error(tokz, tokens->line,
279 E_TOKZ_IDENTIFIER_EXPECTED);
280 }
281
282 if(had_error)
283 break;
284
285 if(t==P_STMT){
286 if(find_beg_sect(tokz))
287 t=P_STMT_SECT;
288 }
289
290 options=lookup_option(tokz->optstack[tokz->nest_lvl],
291 TOK_IDENT_VAL(tokens+0));
292 if(options==NULL)
293 options=lookup_option(common_opts, TOK_IDENT_VAL(tokens+0));
294
295 if(options==NULL){
296 had_error=TRUE;
297 tokz_warn_error(tokz, tokens->line, E_TOKZ_UNKNOWN_OPTION);
298 }else{
299 had_error=!check_args(tokz, tokens, ntokens, options->argfmt);
300 }
301
302 if(had_error)
303 break;
304
305 if(options->opts!=NULL){
306 if(t!=P_STMT_SECT){
307 had_error=TRUE;
308 tokz_warn_error(tokz, tokz->line, E_TOKZ_LBRACE_EXPECTED);
309 }else if(tokz->nest_lvl==MAX_NEST-1){
310 tokz_warn_error(tokz, tokz->line, E_TOKZ_MAX_NEST);
311 had_error=TRUE;
312 }else{
313 tokz->optstack[++tokz->nest_lvl]=options->opts;
314 }
315 }else if(t==P_STMT_SECT){
316 had_error=TRUE;
317 tokz_warn_error(tokz, tokz->line, E_TOKZ_SYNTAX);
318 }
319
320 if(!had_error && options->fn!=NULL){
321 had_error=!options->fn(tokz, ntokens, tokens);
322 if(t==P_STMT_SECT && had_error)
323 tokz->nest_lvl--;
324 }
325 break;
326
315 case P_EOF: 327 case P_EOF:
316 if(tokz_popf(tokz)){ 328 if(tokz_popf(tokz)){
317 if(!had_error) 329 break;
318 continue; 330 }else if(tokz->nest_lvl>0 || errornest>0){
319 }else if(tokz->nest_lvl>0){
320 tokz_warn_error(tokz, 0, E_TOKZ_UNEXPECTED_EOF); 331 tokz_warn_error(tokz, 0, E_TOKZ_UNEXPECTED_EOF);
321 had_error=TRUE; 332 had_error=TRUE;
322 }else if(!had_error){ 333 }
323 had_error=!call_end_sect(tokz, tokz->optstack[0]); 334 goto eof;
324 } 335
325 break; 336 case P_BEG_SECT:
326 337 had_error=TRUE;
338 errornest++;
339 tokz_warn_error(tokz, tokz->line, E_TOKZ_SYNTAX);
340 break;
341
327 case P_END_SECT: 342 case P_END_SECT:
343 if(errornest!=0){
344 errornest--;
345 break;
346 }
347
328 if(tokz->nest_lvl==0){ 348 if(tokz->nest_lvl==0){
329 tokz_warn_error(tokz, tokz->line, E_TOKZ_SYNTAX); 349 tokz_warn_error(tokz, tokz->line, E_TOKZ_SYNTAX);
330 had_error=TRUE; 350 had_error=TRUE;
331 break; 351 break;
332 } 352 }
335 had_error=!call_end_sect(tokz, tokz->optstack[tokz->nest_lvl]); 355 had_error=!call_end_sect(tokz, tokz->optstack[tokz->nest_lvl]);
336 356
337 tokz->nest_lvl--; 357 tokz->nest_lvl--;
338 358
339 if(tokz->nest_lvl<init_nest_lvl) 359 if(tokz->nest_lvl<init_nest_lvl)
340 break; 360 goto eof;
341 361 }
342 /* fall thru */ 362
343 363 if(!had_error)
344 default: 364 continue;
345 if(!had_error) 365
346 continue; 366 if(t==P_STMT_SECT)
347 } 367 errornest++;
348 break; 368
349 } 369 if(!(tokz->flags&TOKZ_ERROR_TOLERANT))
350 370 break;
351 /* On error, call all the #cancel-handlers */ 371 }
352 while(had_error && tokz->nest_lvl>=init_nest_lvl){ 372
353 call_cancel_sect(tokz, tokz->optstack[tokz->nest_lvl]); 373 eof:
374 /* free the tokens */
375 while(ntokens--)
376 tok_free(&tokens[ntokens]);
377
378 while(tokz->nest_lvl>=init_nest_lvl){
379 if(tokz->flags&TOKZ_ERROR_TOLERANT || !had_error)
380 call_end_sect(tokz, tokz->optstack[tokz->nest_lvl]);
381 else
382 call_cancel_sect(tokz, tokz->optstack[tokz->nest_lvl]);
354 tokz->nest_lvl--; 383 tokz->nest_lvl--;
355 } 384 }
356 385
357 /* Free optstack if it was alloced by this call */ 386 /* Free optstack if it was alloced by this call */
358 if(alloced_optstack){ 387 if(alloced_optstack){
369 398
370 399
371 /* */ 400 /* */
372 401
373 402
374 bool parse_config(const char *fname, const ConfOpt *options) 403 bool parse_config(const char *fname, const ConfOpt *options, int flags)
375 { 404 {
376 Tokenizer *tokz; 405 Tokenizer *tokz;
377 bool ret; 406 bool ret;
378 407
379 tokz=tokz_open(fname); 408 tokz=tokz_open(fname);
380 409
381 if(tokz==NULL) 410 if(tokz==NULL)
382 return FALSE; 411 return FALSE;
412
413 tokz->flags|=flags&~TOKZ_READ_COMMENTS;
383 414
384 ret=parse_config_tokz(tokz, options); 415 ret=parse_config_tokz(tokz, options);
385 416
386 tokz_close(tokz); 417 tokz_close(tokz);
387 418
388 return ret; 419 return ret;
389 } 420 }
390 421
391 422
392 bool parse_config_file(FILE *file, const ConfOpt *options) 423 bool parse_config_file(FILE *file, const ConfOpt *options, int flags)
393 { 424 {
394 Tokenizer *tokz; 425 Tokenizer *tokz;
395 bool ret; 426 bool ret;
396 427
397 tokz=tokz_open_file(file); 428 tokz=tokz_open_file(file);
398 429
399 if(tokz==NULL) 430 if(tokz==NULL)
400 return FALSE; 431 return FALSE;
432
433 tokz->flags|=flags&~TOKZ_READ_COMMENTS;
401 434
402 ret=parse_config_tokz(tokz, options); 435 ret=parse_config_tokz(tokz, options);
403 436
404 tokz_close(tokz); 437 tokz_close(tokz);
405 438
410 /* 443 /*
411 * Argument validity checking stuff 444 * Argument validity checking stuff
412 */ 445 */
413 446
414 447
415 static bool arg_match(Token *tok, char c) 448 static int arg_match(Token *tok, char c)
416 { 449 {
417 static const char chs[]={0, 'l', 'd', 'c', 's', 'i', 0, 0}; 450 static const char chs[]={0, 'l', 'd', 'c', 's', 'i', 0, 0};
418 char c2; 451 char c2;
419 452
420 if(c=='.' || c=='*') 453 if(c=='.' || c=='*')
421 return TRUE; 454 return 0;
422 455
423 c2=chs[tok->type]; 456 c2=chs[tok->type];
424 457
425 if(c2==c) 458 if(c2==c)
426 return TRUE; 459 return 0;
427 460
428 if(c2=='c' && c=='l'){ 461 if(c2=='c' && c=='l'){
429 TOK_SET_LONG(tok, TOK_CHAR_VAL(tok)); 462 TOK_SET_LONG(tok, TOK_CHAR_VAL(tok));
430 return TRUE; 463 return 0;
431 } 464 }
432 465
433 if(c2=='l' && c=='c'){ 466 if(c2=='l' && c=='c'){
434 TOK_SET_CHAR(tok, TOK_LONG_VAL(tok)); 467 TOK_SET_CHAR(tok, TOK_LONG_VAL(tok));
435 return TRUE; 468 return 0;
436 } 469 }
437 470
438 if(c2=='l' && c=='d'){ 471 if(c2=='l' && c=='d'){
439 TOK_SET_DOUBLE(tok, TOK_LONG_VAL(tok)); 472 TOK_SET_DOUBLE(tok, TOK_LONG_VAL(tok));
440 return TRUE; 473 return 0;
441 } 474 }
442 475
443 return FALSE; 476 return E_TOKZ_INVALID_ARGUMENT;
444 } 477 }
445 478
446 479
447 static bool check_argument(const char **pret, Token *tok, const char *p) 480 static int check_argument(const char **pret, Token *tok, const char *p)
448 { 481 {
449 int mode=0; 482 int mode;
450 483 int e=E_TOKZ_TOO_MANY_ARGS;
484
485 again:
486 mode=0;
487
451 if(*p=='*'){ 488 if(*p=='*'){
452 *pret=p; 489 *pret=p;
453 return TRUE; 490 return 0;
454 }else if(*p=='?'){ 491 }else if(*p=='?'){
455 mode=1; 492 mode=1;
456 p++; 493 p++;
457 }else if(*p==':'){ 494 }else if(*p==':'){
458 mode=2; 495 mode=2;
461 *pret=p; 498 *pret=p;
462 return arg_match(tok, *(p-1)); 499 return arg_match(tok, *(p-1));
463 } 500 }
464 501
465 while(*p!='\0'){ 502 while(*p!='\0'){
466 if(arg_match(tok, *p)){ 503 e=arg_match(tok, *p);
504 if(e==0){
467 p++; 505 p++;
468 while(mode==2 && *p==':'){ 506 while(mode==2 && *p==':'){
469 if(*++p=='\0') 507 if(*++p=='\0')
470 break; /* invalid argument format string it is... */ 508 break; /* Invalid argument format string, though... */
471 p++; 509 p++;
472 } 510 }
473 *pret=p; 511 *pret=p;
474 return TRUE; 512 return 0;
475 } 513 }
476 514
477 if(mode==0) 515 if(mode==0)
478 break; 516 break;
479 517
480 p++; 518 p++;
481 519
482 if(mode==1){ 520 if(mode==1)
483 *pret=p; 521 goto again;
484 return TRUE; 522
485 } 523 /* mode==2 */
486 524
487 if(*p!=':') 525 if(*p!=':')
488 break; 526 break;
489 p++; 527 p++;
528 e=E_TOKZ_TOO_MANY_ARGS;
490 } 529 }
491 530
492 *pret=p; 531 *pret=p;
493 return FALSE; 532 return e;
494 } 533 }
495 534
496 535
497 static bool args_at_end(const char *p) 536 static bool args_at_end(const char *p)
498 { 537 {
514 553
515 static bool check_args(const Tokenizer *tokz, Token *tokens, int ntokens, 554 static bool check_args(const Tokenizer *tokz, Token *tokens, int ntokens,
516 const char *fmt) 555 const char *fmt)
517 { 556 {
518 int i; 557 int i;
519 558 int e;
520 if(fmt==NULL) 559
521 return ntokens==2; 560 if(fmt==NULL){
522 561 if(ntokens!=1)
523 for(i=1; i<ntokens-1; i++){ 562 tokz_warn_error(tokz, tokens[0].line, E_TOKZ_TOO_MANY_ARGS);
524 if(!check_argument(&fmt, &tokens[i], fmt)){ 563 return ntokens==1;
525 tokz_warn_error(tokz, tokens[i].line, 564 }
526 *fmt!='\0' ? E_TOKZ_INVALID_ARGUMENT 565
527 : E_TOKZ_TOO_MANY_ARGS); 566 for(i=1; i<ntokens; i++){
567 e=check_argument(&fmt, &tokens[i], fmt);
568 if(e!=0){
569 tokz_warn_error(tokz, tokens[i].line, e);
528 return FALSE; 570 return FALSE;
529 } 571 }
530 } 572 }
531 573
532 if(!args_at_end(fmt)){ 574 if(!args_at_end(fmt)){

mercurial