Rev 3808 | Rev 8161 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
10 | reyssat | 1 | /* Copyright (C) 2002-2003 XIAO, Gang of Universite de Nice - Sophia Antipolis |
2 | * |
||
3 | * This program is free software; you can redistribute it and/or modify |
||
4 | * it under the terms of the GNU General Public License as published by |
||
5 | * the Free Software Foundation; either version 2 of the License, or |
||
6 | * (at your option) any later version. |
||
7 | * |
||
8 | * This program is distributed in the hope that it will be useful, |
||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
11 | * GNU General Public License for more details. |
||
12 | * |
||
13 | * You should have received a copy of the GNU General Public License |
||
14 | * along with this program; if not, write to the Free Software |
||
15 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
||
16 | */ |
||
17 | |||
18 | /* Block parsing routines |
||
19 | * Return value: |
||
20 | * 0 if no match. |
||
21 | * 1 if match. |
||
22 | * -1 if error. */ |
||
23 | |||
24 | struct npool { |
||
25 | listtype nextblock,last; |
||
26 | } npool[MAX_POOLS]; |
||
27 | int nextnpool, currnpool; |
||
28 | |||
29 | void outval(char *tit, char *val) |
||
30 | { |
||
31 | char *p, l, r; |
||
32 | val=find_word_start(val); |
||
33 | strip_trailing_spaces(val); |
||
34 | if(*val==0) { |
||
35 | snprintf(outptr,sizeof(outbuf)-(outptr-outbuf)-1,"%s=_EMPTY_ ",tit); |
||
36 | goto outend; |
||
37 | } |
||
38 | if(*find_word_end(val)==0) { |
||
39 | snprintf(outptr,sizeof(outbuf)-(outptr-outbuf)-1,"%s=%s ",tit,val); |
||
40 | } |
||
41 | else { |
||
42 | l='('; r=')'; |
||
43 | if(strchr(val,l)!=NULL || strchr(val,r)!=NULL) { |
||
44 | l='['; r=']'; |
||
45 | if(strchr(val,l)!=NULL || strchr(val,r)!=NULL) { |
||
46 | l='{'; r='}'; |
||
47 | if(strchr(val,l)!=NULL || strchr(val,r)!=NULL) { |
||
48 | l='"'; r='"'; |
||
49 | if(strchr(val,l)!=NULL || strchr(val,r)!=NULL) { |
||
50 | l=r=' '; |
||
51 | for(p=val;*p;p++) if(*p==' ') *p='_'; |
||
52 | } |
||
53 | } |
||
54 | } |
||
55 | } |
||
56 | snprintf(outptr,sizeof(outbuf)-(outptr-outbuf)-1,"%s=%c%s%c ",tit,l,val,r); |
||
57 | } |
||
58 | outend: outptr+=strlen(outptr); |
||
59 | } |
||
60 | |||
61 | void cleartag(struct poolstruct *pl) |
||
62 | { |
||
63 | int i, len, level; |
||
64 | listtype *tag; |
||
65 | len=pl->len; tag=pl->tag; level=pl->ind2; |
||
66 | if(level==0) { |
||
67 | memset(tag,0,pl->len*sizeof(listtype)); |
||
68 | } |
||
69 | else for(i=0; i<len; i++) { |
||
70 | if(tag[i]>=level) tag[i]=0; |
||
71 | } |
||
72 | } |
||
73 | |||
74 | struct poolstruct *getpool(struct block *blk) |
||
75 | { |
||
76 | struct poolstruct *pl; |
||
77 | |||
78 | if(nextpool>=MAX_POOLS) error("pool_overflow"); |
||
79 | pl=poolbuf+nextpool; |
||
80 | pl->lastpool=blk->pool; |
||
81 | blk->pool=nextpool; nextpool++; |
||
82 | pl->block=blk-blockbuf; |
||
83 | pl->string=NULL; |
||
84 | pl->ind1=pl->ind2=pl->dirty=pl->len=0; |
||
85 | return pl; |
||
86 | } |
||
87 | |||
88 | void putpool(struct poolstruct *pl) |
||
89 | { |
||
90 | nextpool--; |
||
91 | if(nextpool!=pl-poolbuf) error("internal_error pool leaking"); |
||
92 | blockbuf[pl->block].pool=pl->lastpool; |
||
93 | } |
||
94 | |||
95 | int mt_this(struct block *blk, char *start, int level) |
||
96 | { |
||
97 | int r; |
||
98 | if(level > MAX_LEVELS) error("level_overflow %.20s",start); |
||
99 | start=find_word_start(start); |
||
3813 | kbelabas | 100 | if(debug>=2) fprintf(stderr,"lvl=%d. Checking against block %d for %.10s.\n",level,(int)(blk-blockbuf),start); |
10 | reyssat | 101 | r = blk->fn(blk,start,level); |
3813 | kbelabas | 102 | if(debug) fprintf(stderr,"lvl=%d. Tested %d block %d for %.10s.\n",level,r,(int)(blk-blockbuf),start); |
10 | reyssat | 103 | return r; |
104 | } |
||
105 | |||
106 | int mt_next(struct block *blk, char *start, int level) |
||
107 | { |
||
108 | int r,cp,next; |
||
109 | next=blk->nextblock; |
||
110 | cp=currnpool; |
||
111 | if(next==-2) { |
||
112 | do { |
||
113 | next=npool[currnpool].nextblock; currnpool=npool[currnpool].last; |
||
114 | } |
||
115 | while (next==-2 && currnpool>0); |
||
116 | if(next==-2) error("internal_error npool disorder"); |
||
3813 | kbelabas | 117 | if(debug>=3) fprintf(stderr,"Calling macro %d: next=%d.\n", |
118 | (int)(blk-blockbuf),next); |
||
10 | reyssat | 119 | } |
120 | if(next<0) { |
||
121 | if(*start) return 0; else return 1; |
||
122 | } |
||
123 | r=mt_this(blockbuf+next,start,level); |
||
124 | currnpool=cp; |
||
125 | return r; |
||
126 | } |
||
127 | |||
128 | int mt_string(struct block *blk, char *start, int level) |
||
129 | { |
||
130 | char *p; |
||
131 | int r; |
||
132 | if(blk->len>0) { |
||
133 | if(memcmp(blk->string,start,blk->len)!=0) return 0; |
||
134 | p=start+blk->len; if(*p && !myisspace(*p)) return 0; |
||
135 | } |
||
136 | else p=start; |
||
137 | r = mt_next(blk,p,level+1); |
||
138 | if(debug) fprintf(stderr,"Strcmp %d %.20s. <-> %.20s.\n",r, blk->string,start); |
||
139 | return r; |
||
140 | } |
||
141 | |||
142 | int mt_dic(struct block *blk, char *start, int level) |
||
143 | { |
||
144 | int i,t; |
||
145 | struct entry *et; |
||
146 | char *p; |
||
147 | |||
148 | i=blk->lind1; |
||
149 | t=search_dic(entry+dic[i].start,dic[i].len,sizeof(entry[0]),start); |
||
150 | if(t>=0) { |
||
151 | et=entry+(dic[i].start+t); |
||
3808 | kbelabas | 152 | if(itemchr((char*)et->replace,blk->string)==NULL) return 0; |
10 | reyssat | 153 | p=start+et->olen; |
154 | return mt_next(blk,p,level+1); |
||
155 | } |
||
156 | switch(dic[i].unknown_type) { |
||
157 | case unk_leave: { |
||
158 | if(memcmp(start,blk->string,blk->len)==0 || |
||
159 | (start[blk->len]!=0 && !myisspace(start[blk->len]))) |
||
160 | return 0; |
||
161 | return mt_next(blk,find_word_start(start+blk->len),level+1); |
||
162 | } |
||
163 | case unk_replace: { |
||
164 | if(strcmp(dic[i].unknown,blk->string)!=0) return 0; |
||
165 | return mt_next(blk,start,level+1); |
||
166 | } |
||
167 | case unk_delete: return 0; |
||
168 | } |
||
169 | return 0; |
||
170 | } |
||
171 | |||
172 | int _permpick1(struct block *blk, char *start, int level) |
||
173 | { |
||
174 | int i, j, k, r, re; |
||
175 | struct poolstruct *pl; |
||
176 | |||
177 | level++; |
||
178 | for(i=blk->pool+1; i<nextpool;i++) poolbuf[i].dirty++; |
||
179 | pl=poolbuf+blk->pool; |
||
180 | i=blk->lists[pl->ind1][pl->ind2]; |
||
181 | pl->ind2++; cleartag(pl); |
||
182 | ppstart: |
||
183 | if(i>=blk->len) { /* optional match */ |
||
184 | i-=blk->len; |
||
185 | r=mt_next(blk,start,level); |
||
186 | if(r) goto end; |
||
187 | } |
||
188 | if(i>=0) { |
||
189 | r=mt_this(blockbuf+blk->sublock+i,start,level); |
||
190 | goto end; |
||
191 | } |
||
192 | r=0; |
||
193 | switch(i) { |
||
194 | case -1: { /* any */ |
||
195 | any: |
||
196 | for(k=blk->lstart;k<blk->len;k++) { |
||
197 | pl->tag[k]=pl->ind2; |
||
198 | r=mt_this(blockbuf+blk->sublock+k,start,level); |
||
199 | cleartag(pl); |
||
200 | if(r) break; |
||
201 | } |
||
202 | goto end; |
||
203 | } |
||
204 | case -2: { /* any unused */ |
||
205 | unused: |
||
206 | for(k=blk->lstart;k<blk->len;k++) { |
||
207 | if(pl->tag[k]>0) continue; |
||
208 | pl->tag[k]=pl->ind2; |
||
209 | r=mt_this(blockbuf+blk->sublock+k,start,level); |
||
210 | cleartag(pl); |
||
211 | if(r) break; |
||
212 | } |
||
213 | goto end; |
||
214 | } |
||
215 | case -3: { /* any unused bigger */ |
||
216 | unused_bigger: |
||
217 | for(k=blk->len-1;k>=blk->lstart && pl->tag[k]==0;k--); |
||
218 | for(k++;k<blk->len;k++) { |
||
219 | pl->tag[k]=pl->ind2; |
||
220 | r=mt_this(blockbuf+blk->sublock+k,start,level); |
||
221 | cleartag(pl); |
||
222 | if(r) break; |
||
223 | } |
||
224 | goto end; |
||
225 | } |
||
226 | case -4: { /* any unused smaller; not used */ |
||
227 | unused_smaller: |
||
228 | for(j=0; j<blk->len && pl->tag[j]==0;j++); |
||
229 | for(k=blk->lstart;k<j;k++) { |
||
230 | pl->tag[k]=pl->ind2; |
||
231 | r=mt_this(blockbuf+blk->sublock+k,start,level); |
||
232 | cleartag(pl); |
||
233 | if(r) break; |
||
234 | } |
||
235 | goto end; |
||
236 | } |
||
237 | case -5: { /* repeat */ |
||
238 | re=pl->ind2-1; |
||
239 | if(pl->ind2<2 || pl->string >= start) goto end; |
||
240 | pl->string=start; |
||
241 | r=mt_next(blk,start,level); |
||
242 | if(r) goto end; |
||
243 | pl->ind2=re; |
||
244 | i=blk->lists[pl->ind1][pl->ind2 - 1]; |
||
245 | goto ppstart; |
||
246 | } |
||
247 | case -6: { |
||
248 | r=mt_next(blk,start,level); |
||
249 | if(r) goto end; |
||
250 | goto any; |
||
251 | } |
||
252 | case -7: { |
||
253 | r=mt_next(blk,start,level); |
||
254 | if(r) goto end; |
||
255 | goto unused; |
||
256 | } |
||
257 | case -8: { |
||
258 | r=mt_next(blk,start,level); |
||
259 | if(r) goto end; |
||
260 | goto unused_bigger; |
||
261 | } |
||
262 | case -9: { |
||
263 | r=mt_next(blk,start,level); |
||
264 | if(r) goto end; |
||
265 | goto unused_smaller; |
||
266 | } |
||
267 | case -10: { /* unused. */ |
||
268 | goto end; |
||
269 | } |
||
270 | case -11: { /* unused. */ |
||
271 | goto end; |
||
272 | } |
||
273 | case -12: { /* insertion */ |
||
274 | if(pl->tag[0]==0) { |
||
275 | pl->tag[0]=pl->ind2; |
||
276 | r=mt_this(blockbuf+blk->sublock,start,level); |
||
277 | cleartag(pl); |
||
278 | if(r) goto end; |
||
279 | } |
||
280 | r=_permpick1(blk,start,level+1); |
||
281 | goto end; |
||
282 | } |
||
283 | case -13: { /* insertion end */ |
||
284 | if(pl->tag[0]) r=mt_next(blk,start,level+1); |
||
285 | else r=0; |
||
286 | goto end; |
||
287 | } |
||
288 | } |
||
289 | end: |
||
290 | if(r==0) pl->ind2--; |
||
291 | for(i=blk->pool+1; i<nextpool;i++) if(poolbuf[i].dirty) poolbuf[i].dirty--; |
||
292 | return r; |
||
293 | } |
||
294 | |||
295 | int mt_permpick(struct block *blk, char *start, int level) |
||
296 | { |
||
297 | int r, n, newpool; |
||
298 | struct poolstruct *pl; |
||
299 | |||
300 | newpool=n=0; |
||
301 | pl=poolbuf+blk->pool; |
||
302 | if(pl==poolbuf || pl->dirty>0) { |
||
303 | pl=getpool(blk); newpool=1; |
||
304 | n=pl->len=blk->len; |
||
305 | if(nexttag + n >= MAX_BLOCKS) error("tag_overflow"); |
||
306 | pl->tag=tagbuf+nexttag; nexttag+=n; |
||
307 | } |
||
308 | if(pl->ind1==0 && pl->ind2==0) { |
||
309 | for(r=0;pl->ind1<blk->lcnt;pl->ind1++,pl->ind2=0){ |
||
310 | r=_permpick1(blk,start,level); |
||
311 | if(r) break; |
||
312 | } |
||
313 | pl->ind1=pl->ind2=0; |
||
314 | if(newpool) { |
||
315 | putpool(pl); nexttag-=n; |
||
316 | } |
||
317 | return r; |
||
318 | } |
||
319 | if(pl->ind2>=blk->listlen[pl->ind1]) { |
||
320 | return mt_next(blk,start,level); |
||
321 | } |
||
322 | return _permpick1(blk,start,level); |
||
323 | } |
||
324 | |||
325 | int mt_neg(struct block *blk, char *start, int level) |
||
326 | { |
||
327 | int r, newpool; |
||
328 | struct poolstruct *pl; |
||
329 | |||
330 | newpool=0; |
||
331 | pl=poolbuf+blk->pool; |
||
332 | if(pl==poolbuf || pl->dirty>0) { |
||
333 | pl=getpool(blk); newpool=1; |
||
334 | } |
||
335 | if(pl->ind2) return 1; |
||
336 | pl->ind2=1; |
||
337 | r=mt_this(blockbuf+blk->sublock,start,level+1); |
||
338 | pl->ind2=0; if(newpool) putpool(pl); |
||
339 | if(r==0) return mt_next(blk,start,level+1); |
||
340 | if(r==1) return 0; |
||
341 | else return r; |
||
342 | } |
||
343 | |||
344 | int mt_nomatch(struct block *blk, char *start, int level) |
||
345 | { |
||
346 | return 0; |
||
347 | } |
||
348 | |||
349 | void getnpool(int b) |
||
350 | { |
||
351 | if(nextnpool>=MAX_POOLS) error("npool_overflow"); |
||
352 | npool[nextnpool].nextblock=b; |
||
353 | npool[nextnpool].last=currnpool; |
||
354 | currnpool=nextnpool; |
||
355 | nextnpool++; |
||
356 | } |
||
357 | |||
358 | void putnpool(void) |
||
359 | { |
||
360 | if(nextnpool<=0) error("npool_underflow"); |
||
361 | nextnpool--; |
||
362 | } |
||
363 | |||
364 | int mt_m(struct block *blk, char *start, int level) |
||
365 | { |
||
366 | int i,r,pl,b,e,cp; |
||
367 | char *bkstart; |
||
368 | |||
369 | if(blk->string>=start) return 0; |
||
370 | bkstart=blk->string; blk->string=start; |
||
371 | cp=currnpool; |
||
372 | getnpool(blk->nextblock); |
||
373 | b=blk->sublock; pl=blockbuf[b].mpool; blockbuf[b].mpool=nextpool+1; |
||
374 | e=blockbuf[b].mend; |
||
375 | if(pl>0) for(i=pl-1;i<nextpool;i++) { |
||
376 | if(poolbuf[i].block>=b && poolbuf[i].block<e) poolbuf[i].dirty++; |
||
377 | } |
||
378 | if(debug>=3) fprintf(stderr, "Entering macro %d npool=%d, next=%d.\n", |
||
379 | b, currnpool, npool[currnpool].nextblock); |
||
380 | r = mt_this(blockbuf+b,start,level+1); |
||
381 | if(pl>0) for(i=pl-1;i<nextpool;i++) { |
||
382 | if(poolbuf[i].block>=b && poolbuf[i].block<e && poolbuf[i].dirty>0) poolbuf[i].dirty--; |
||
383 | } |
||
384 | blockbuf[b].mpool=pl; |
||
385 | putnpool(); currnpool=cp; blk->string=bkstart; |
||
386 | if(debug>=3) fprintf(stderr, "macro %d returns %d, npool=%d, next=%d.\n", |
||
387 | b, r, nextnpool, npool[nextnpool].nextblock); |
||
388 | return r; |
||
389 | } |
||
390 | |||
391 | int mt_out(struct block *blk, char *start, int level) |
||
392 | { |
||
393 | int r, l, newpool; |
||
394 | char buf[MAX_LINELEN+1]; |
||
395 | struct poolstruct *pl; |
||
396 | |||
397 | newpool=0; |
||
398 | pl=poolbuf+blk->pool; |
||
399 | if(pl==poolbuf || pl->dirty>0) { |
||
400 | pl=getpool(blk); newpool=1; |
||
401 | } |
||
402 | if(pl->ind2) { |
||
403 | pl->string=start; |
||
404 | return mt_next(blk,start,level+1); |
||
405 | } |
||
406 | pl->ind2++; |
||
407 | r=mt_this(blockbuf+blk->sublock,start,level+1); |
||
408 | pl->ind2=0; if(newpool) putpool(pl); |
||
409 | if(r) { |
||
410 | l=pl->string - start; |
||
411 | if(l>=0 && l<MAX_LINELEN) { |
||
412 | memmove(buf,start,l); buf[l]=0; |
||
413 | outval(blk->string, buf); |
||
414 | } |
||
415 | } |
||
416 | return r; |
||
417 | } |
||
418 | |||
419 | int mt_w(struct block *blk, char *start, int level) |
||
420 | { |
||
421 | char *p1, *p2; |
||
422 | char buf[MAX_NAMELEN+1]; |
||
423 | int l; |
||
424 | p1=find_word_start(start); p2=find_word_end(p1); l=p2-p1; |
||
425 | if(*p2) p2++; |
||
426 | if(l>=MAX_NAMELEN) return 0; |
||
427 | memmove(buf,p1,l); buf[l]=0; |
||
428 | if(wordchr(wbuf,buf)==NULL) return 0; |
||
429 | return mt_next(blk,p2,level+1); |
||
430 | } |
||
431 | |||
432 | int mt_wild(struct block *blk, char *start, int level) |
||
433 | { |
||
434 | char *p; |
||
435 | int i,l,r; |
||
436 | |||
437 | l=blk->lstart; |
||
438 | for(i=0,p=find_word_start(start);i<l;i++,p=find_word_start(find_word_end(p))) { |
||
439 | if(*p==0) return 0; |
||
440 | } |
||
441 | l=blk->len; |
||
442 | if(l==0) return mt_next(blk,p,level+1); |
||
443 | for(i=0; i<=l && *p; i++, p=find_word_start(find_word_end(p))) { |
||
444 | r=mt_next(blk,p,level+1); |
||
445 | if(r) return r; |
||
446 | } |
||
447 | if(i<=l) return mt_next(blk,p,level+1); |
||
448 | else return 0; |
||
449 | } |
||
450 | |||
451 | int match(char *p) |
||
452 | { |
||
453 | int i; |
||
454 | outptr=outbuf; *outptr=0; nextpool=nextnpool=1; nexttag=0; |
||
455 | currnpool=0; |
||
456 | for(i=0;i<nextblock;i++) blockbuf[i].pool=blockbuf[i].mpool=0; |
||
457 | return mt_this(blockbuf,find_word_start(p),0); |
||
458 | } |
||
459 |