| 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){ |
| 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; |
| 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)){ |