Back to index

wims  3.65+svn20090927
match.c
Go to the documentation of this file.
00001 /*    Copyright (C) 2002-2003 XIAO, Gang of Universite de Nice - Sophia Antipolis
00002  *
00003  *  This program is free software; you can redistribute it and/or modify
00004  *  it under the terms of the GNU General Public License as published by
00005  *  the Free Software Foundation; either version 2 of the License, or
00006  *  (at your option) any later version.
00007  *
00008  *  This program is distributed in the hope that it will be useful,
00009  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00010  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011  *  GNU General Public License for more details.
00012  *
00013  *  You should have received a copy of the GNU General Public License
00014  *  along with this program; if not, write to the Free Software
00015  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00016  */
00017 
00018        /* Block parsing routines
00019         * Return value:
00020         * 0 if no match.
00021         * 1 if match.
00022         * -1 if error. */
00023 
00024 struct npool {
00025     listtype nextblock,last;
00026 } npool[MAX_POOLS];
00027 int nextnpool, currnpool;
00028 
00029 void outval(char *tit, char *val)
00030 {
00031     char *p, l, r;
00032     val=find_word_start(val);
00033     strip_trailing_spaces(val);
00034     if(*val==0) {
00035        snprintf(outptr,sizeof(outbuf)-(outptr-outbuf)-1,"%s=_EMPTY_ ",tit);
00036        goto outend;
00037     }
00038     if(*find_word_end(val)==0) {
00039        snprintf(outptr,sizeof(outbuf)-(outptr-outbuf)-1,"%s=%s ",tit,val);
00040     }
00041     else {
00042        l='('; r=')';
00043        if(strchr(val,l)!=NULL || strchr(val,r)!=NULL) {
00044            l='['; r=']';
00045            if(strchr(val,l)!=NULL || strchr(val,r)!=NULL) {
00046               l='{'; r='}';
00047               if(strchr(val,l)!=NULL || strchr(val,r)!=NULL) {
00048                   l='"'; r='"';
00049                   if(strchr(val,l)!=NULL || strchr(val,r)!=NULL) {
00050                      l=r=' ';
00051                      for(p=val;*p;p++) if(*p==' ') *p='_';
00052                   }
00053               }
00054            }
00055        }
00056        snprintf(outptr,sizeof(outbuf)-(outptr-outbuf)-1,"%s=%c%s%c ",tit,l,val,r);
00057     }
00058     outend: outptr+=strlen(outptr);
00059 }
00060 
00061 void cleartag(struct poolstruct *pl)
00062 {
00063     int i, len, level;
00064     listtype *tag;
00065     len=pl->len; tag=pl->tag; level=pl->ind2;
00066     if(level==0) {
00067        memset(tag,0,pl->len*sizeof(listtype));
00068     }
00069     else for(i=0; i<len; i++) {
00070        if(tag[i]>=level) tag[i]=0;
00071     }
00072 }
00073 
00074 struct poolstruct *getpool(struct block *blk)
00075 {
00076     struct poolstruct *pl;
00077     
00078     if(nextpool>=MAX_POOLS) error("pool_overflow");
00079     pl=poolbuf+nextpool;
00080     pl->lastpool=blk->pool;
00081     blk->pool=nextpool; nextpool++;
00082     pl->block=blk-blockbuf;
00083     pl->string=NULL;
00084     pl->ind1=pl->ind2=pl->dirty=pl->len=0;
00085     return pl;
00086 }
00087 
00088 void putpool(struct poolstruct *pl)
00089 {
00090     nextpool--;
00091     if(nextpool!=pl-poolbuf) error("internal_error pool leaking");
00092     blockbuf[pl->block].pool=pl->lastpool;
00093 }
00094 
00095 int mt_this(struct block *blk, char *start, int level)
00096 {
00097     int r;
00098     if(level > MAX_LEVELS) error("level_overflow %.20s",start);
00099     start=find_word_start(start);
00100     if(debug>=2) fprintf(stderr,"lvl=%d. Checking against block %d for %.10s.\n",level,blk-blockbuf,start);
00101     r = blk->fn(blk,start,level);
00102     if(debug) fprintf(stderr,"lvl=%d. Tested %d block %d for %.10s.\n",level,r,blk-blockbuf,start);
00103     return r;
00104 }
00105 
00106 int mt_next(struct block *blk, char *start, int level)
00107 {
00108     int r,cp,next;
00109     next=blk->nextblock;
00110     cp=currnpool;
00111     if(next==-2) {
00112        do {
00113            next=npool[currnpool].nextblock; currnpool=npool[currnpool].last;
00114        }
00115        while (next==-2 && currnpool>0);
00116        if(next==-2) error("internal_error npool disorder");
00117        if(debug>=3) fprintf(stderr,"Calling macro %d: next=%d.\n",
00118                           blk-blockbuf,next);
00119     }
00120     if(next<0) {
00121        if(*start) return 0; else return 1;
00122     }
00123     r=mt_this(blockbuf+next,start,level);
00124     currnpool=cp;
00125     return r;
00126 }
00127 
00128 int mt_string(struct block *blk, char *start, int level)
00129 {
00130     char *p;
00131     int r;
00132     if(blk->len>0) {
00133        if(memcmp(blk->string,start,blk->len)!=0) return 0;
00134        p=start+blk->len; if(*p && !myisspace(*p)) return 0;
00135     }
00136     else p=start;
00137     r = mt_next(blk,p,level+1);
00138     if(debug) fprintf(stderr,"Strcmp %d %.20s. <-> %.20s.\n",r, blk->string,start);
00139     return r;
00140 }
00141 
00142 int mt_dic(struct block *blk, char *start, int level)
00143 {
00144     int i,t;
00145     struct entry *et;
00146     char *p;
00147     
00148     i=blk->lind1;
00149     t=search_dic(entry+dic[i].start,dic[i].len,sizeof(entry[0]),start);
00150     if(t>=0) {
00151        et=entry+(dic[i].start+t);
00152        if(itemchr(et->replace,blk->string)==NULL) return 0;
00153        p=start+et->olen;
00154        return mt_next(blk,p,level+1);
00155     }
00156     switch(dic[i].unknown_type) {
00157        case unk_leave: {
00158            if(memcmp(start,blk->string,blk->len)==0 ||
00159               (start[blk->len]!=0 && !myisspace(start[blk->len])))
00160              return 0;
00161            return mt_next(blk,find_word_start(start+blk->len),level+1);          
00162        }
00163        case unk_replace: {
00164            if(strcmp(dic[i].unknown,blk->string)!=0) return 0;
00165            return mt_next(blk,start,level+1);
00166        }
00167        case unk_delete: return 0;
00168     }
00169     return 0;
00170 }
00171 
00172 int _permpick1(struct block *blk, char *start, int level)
00173 {
00174     int i, j, k, r, re;
00175     struct poolstruct *pl;
00176     
00177     level++;
00178     for(i=blk->pool+1; i<nextpool;i++) poolbuf[i].dirty++;
00179     pl=poolbuf+blk->pool;
00180     i=blk->lists[pl->ind1][pl->ind2];
00181     pl->ind2++; cleartag(pl);
00182 ppstart:
00183     if(i>=blk->len) {              /* optional match */
00184        i-=blk->len;
00185        r=mt_next(blk,start,level);
00186        if(r) goto end;
00187     }
00188     if(i>=0) {
00189        r=mt_this(blockbuf+blk->sublock+i,start,level);
00190        goto end;
00191     }
00192     r=0;
00193     switch(i) {
00194        case -1: {    /* any */
00195            any:
00196            for(k=blk->lstart;k<blk->len;k++) {
00197               pl->tag[k]=pl->ind2;
00198               r=mt_this(blockbuf+blk->sublock+k,start,level);
00199               cleartag(pl);
00200               if(r) break;
00201            }
00202            goto end;
00203        }
00204        case -2: {    /* any unused */
00205            unused:
00206            for(k=blk->lstart;k<blk->len;k++) {
00207               if(pl->tag[k]>0) continue;
00208               pl->tag[k]=pl->ind2;
00209               r=mt_this(blockbuf+blk->sublock+k,start,level);
00210               cleartag(pl);
00211               if(r) break;
00212            }
00213            goto end;
00214        }
00215        case -3: {    /* any unused bigger */
00216            unused_bigger:
00217            for(k=blk->len-1;k>=blk->lstart && pl->tag[k]==0;k--);
00218            for(k++;k<blk->len;k++) {
00219               pl->tag[k]=pl->ind2;
00220               r=mt_this(blockbuf+blk->sublock+k,start,level);
00221               cleartag(pl);
00222               if(r) break;
00223            }
00224            goto end;
00225        }
00226        case -4: {    /* any unused smaller; not used */
00227            unused_smaller:
00228            for(j=0; j<blk->len && pl->tag[j]==0;j++);
00229            for(k=blk->lstart;k<j;k++) {
00230               pl->tag[k]=pl->ind2;
00231               r=mt_this(blockbuf+blk->sublock+k,start,level);
00232               cleartag(pl);
00233               if(r) break;
00234            }
00235            goto end;
00236        }
00237        case -5: {    /* repeat */
00238            re=pl->ind2-1;
00239            if(pl->ind2<2 || pl->string >= start) goto end;
00240            pl->string=start;
00241            r=mt_next(blk,start,level);
00242            if(r) goto end;
00243            pl->ind2=re;
00244            i=blk->lists[pl->ind1][pl->ind2 - 1];
00245            goto ppstart;
00246        }
00247        case -6: {
00248            r=mt_next(blk,start,level);
00249            if(r) goto end;
00250            goto any;
00251        }
00252        case -7: {
00253            r=mt_next(blk,start,level);
00254            if(r) goto end;
00255            goto unused;
00256        }
00257        case -8: {
00258            r=mt_next(blk,start,level);
00259            if(r) goto end;
00260            goto unused_bigger;
00261        }
00262        case -9: {
00263            r=mt_next(blk,start,level);
00264            if(r) goto end;
00265            goto unused_smaller;
00266        }
00267        case -10: {   /* unused. */
00268            goto end;
00269        }
00270        case -11: {   /* unused. */
00271            goto end;
00272        }
00273        case -12: {   /* insertion */
00274            if(pl->tag[0]==0) {
00275               pl->tag[0]=pl->ind2;
00276               r=mt_this(blockbuf+blk->sublock,start,level);
00277               cleartag(pl);
00278               if(r) goto end;
00279            }
00280            r=_permpick1(blk,start,level+1);
00281            goto end;
00282        }
00283        case -13: {   /* insertion end */
00284            if(pl->tag[0]) r=mt_next(blk,start,level+1);
00285            else r=0;
00286            goto end;
00287        }
00288     }
00289 end:
00290     if(r==0) pl->ind2--;
00291     for(i=blk->pool+1; i<nextpool;i++) if(poolbuf[i].dirty) poolbuf[i].dirty--;
00292     return r;
00293 }
00294 
00295 int mt_permpick(struct block *blk, char *start, int level)
00296 {
00297     int r, n, newpool;
00298     struct poolstruct *pl;
00299     
00300     newpool=n=0;
00301     pl=poolbuf+blk->pool;
00302     if(pl==poolbuf || pl->dirty>0) {
00303        pl=getpool(blk); newpool=1;
00304        n=pl->len=blk->len;
00305        if(nexttag + n >= MAX_BLOCKS) error("tag_overflow");
00306        pl->tag=tagbuf+nexttag; nexttag+=n;
00307     }
00308     if(pl->ind1==0 && pl->ind2==0) {
00309        for(r=0;pl->ind1<blk->lcnt;pl->ind1++,pl->ind2=0){
00310            r=_permpick1(blk,start,level);
00311            if(r) break;
00312        }
00313        pl->ind1=pl->ind2=0;
00314        if(newpool) {
00315            putpool(pl); nexttag-=n;
00316        }
00317        return r;
00318     }
00319     if(pl->ind2>=blk->listlen[pl->ind1]) {
00320        return mt_next(blk,start,level);
00321     }
00322     return _permpick1(blk,start,level);
00323 }
00324 
00325 int mt_neg(struct block *blk, char *start, int level)
00326 {
00327     int r, newpool;
00328     struct poolstruct *pl;
00329     
00330     newpool=0;
00331     pl=poolbuf+blk->pool;
00332     if(pl==poolbuf || pl->dirty>0) {
00333        pl=getpool(blk); newpool=1;
00334     }
00335     if(pl->ind2) return 1;
00336     pl->ind2=1;
00337     r=mt_this(blockbuf+blk->sublock,start,level+1);
00338     pl->ind2=0;      if(newpool) putpool(pl);
00339     if(r==0) return mt_next(blk,start,level+1);
00340     if(r==1) return 0;
00341     else return r;
00342 }
00343 
00344 int mt_nomatch(struct block *blk, char *start, int level)
00345 {
00346     return 0;
00347 }
00348 
00349 void getnpool(int b)
00350 {
00351     if(nextnpool>=MAX_POOLS) error("npool_overflow");
00352     npool[nextnpool].nextblock=b;
00353     npool[nextnpool].last=currnpool;
00354     currnpool=nextnpool;
00355     nextnpool++;
00356 }
00357 
00358 void putnpool(void)
00359 {
00360     if(nextnpool<=0) error("npool_underflow");
00361     nextnpool--;
00362 }
00363 
00364 int mt_m(struct block *blk, char *start, int level)
00365 {
00366     int i,r,pl,b,e,cp;
00367     char *bkstart;
00368     
00369     if(blk->string>=start) return 0;
00370     bkstart=blk->string; blk->string=start;
00371     cp=currnpool;
00372     getnpool(blk->nextblock);
00373     b=blk->sublock; pl=blockbuf[b].mpool; blockbuf[b].mpool=nextpool+1;
00374     e=blockbuf[b].mend;
00375     if(pl>0) for(i=pl-1;i<nextpool;i++) {
00376        if(poolbuf[i].block>=b && poolbuf[i].block<e) poolbuf[i].dirty++;
00377     }
00378     if(debug>=3) fprintf(stderr, "Entering macro %d npool=%d, next=%d.\n",
00379                       b, currnpool, npool[currnpool].nextblock);
00380     r = mt_this(blockbuf+b,start,level+1);
00381     if(pl>0) for(i=pl-1;i<nextpool;i++) {
00382        if(poolbuf[i].block>=b && poolbuf[i].block<e && poolbuf[i].dirty>0) poolbuf[i].dirty--;
00383     }
00384     blockbuf[b].mpool=pl;
00385     putnpool(); currnpool=cp; blk->string=bkstart;
00386     if(debug>=3) fprintf(stderr, "macro %d returns %d, npool=%d, next=%d.\n",
00387                       b, r, nextnpool, npool[nextnpool].nextblock);
00388     return r;
00389 }
00390 
00391 int mt_out(struct block *blk, char *start, int level)
00392 {
00393     int r, l, newpool;
00394     char buf[MAX_LINELEN+1];
00395     struct poolstruct *pl;
00396     
00397     newpool=0;
00398     pl=poolbuf+blk->pool;
00399     if(pl==poolbuf || pl->dirty>0) {
00400        pl=getpool(blk); newpool=1;
00401     }
00402     if(pl->ind2) {
00403        pl->string=start;
00404        return mt_next(blk,start,level+1);
00405     }
00406     pl->ind2++;
00407     r=mt_this(blockbuf+blk->sublock,start,level+1);
00408     pl->ind2=0;      if(newpool) putpool(pl);
00409     if(r) {
00410        l=pl->string - start;
00411        if(l>=0 && l<MAX_LINELEN) {
00412            memmove(buf,start,l); buf[l]=0;
00413            outval(blk->string, buf);
00414        }
00415     }
00416     return r;
00417 }
00418 
00419 int mt_w(struct block *blk, char *start, int level)
00420 {
00421     char *p1, *p2;
00422     char buf[MAX_NAMELEN+1];
00423     int l;
00424     p1=find_word_start(start); p2=find_word_end(p1); l=p2-p1;
00425     if(*p2) p2++;
00426     if(l>=MAX_NAMELEN) return 0;
00427     memmove(buf,p1,l); buf[l]=0;
00428     if(wordchr(wbuf,buf)==NULL) return 0;
00429     return mt_next(blk,p2,level+1);
00430 }
00431 
00432 int mt_wild(struct block *blk, char *start, int level)
00433 {
00434     char *p;
00435     int i,l,r;
00436 
00437     l=blk->lstart;
00438     for(i=0,p=find_word_start(start);i<l;i++,p=find_word_start(find_word_end(p))) {
00439        if(*p==0) return 0;
00440     }
00441     l=blk->len;
00442     if(l==0) return mt_next(blk,p,level+1);
00443     for(i=0; i<=l && *p; i++, p=find_word_start(find_word_end(p))) {
00444        r=mt_next(blk,p,level+1);
00445        if(r) return r;
00446     }
00447     if(i<=l) return mt_next(blk,p,level+1);
00448     else return 0;
00449 }
00450 
00451 int match(char *p)
00452 {
00453     int i;
00454     outptr=outbuf; *outptr=0; nextpool=nextnpool=1; nexttag=0;
00455     currnpool=0;
00456     for(i=0;i<nextblock;i++) blockbuf[i].pool=blockbuf[i].mpool=0;
00457     return mt_this(blockbuf,find_word_start(p),0);
00458 }
00459