Subversion Repositories wimsdev

Rev

Rev 3808 | Rev 8161 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  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. char cpbuf[MAX_LINELEN+1];
  19. char *cpnext;
  20. int noaddw=0;
  21.  
  22. char Mbuf[MAX_LINELEN+1];
  23. char *Mnext;
  24. struct {
  25.     char *Mptr;
  26.     int blkptr;
  27. } Mind[MAX_BLOCKS];
  28. int Mcnt;
  29.  
  30. struct liststruct {
  31.     listtype lcnt;
  32.     listtype *listlen;
  33.     listtype *list;
  34. } clist;
  35.  
  36. void cp_oneblock(char *p, struct block *blk, int next);
  37.  
  38.         /* debugger: show the detail of blocks */
  39. void showblocks(void)
  40. {
  41.     int i, j, k;
  42.     struct block *blk;
  43.     if(!debug) return;
  44.     for(i=0;i<nextblock;i++) {
  45.         blk=blockbuf+i;
  46.         fprintf(stderr,"Block %2d: next=%2d.    ",i,blk->nextblock);
  47.         if(blk->fn==mt_string) {
  48.             fprintf(stderr,"String %s.\n",blk->string);
  49.             continue;
  50.         }
  51.         if(blk->fn==mt_permpick) {
  52.             fprintf(stderr,"Permpick %d items %d lists starting %d\n",
  53.                    blk->len, blk->lcnt, blk->sublock);
  54.             for(j=0;j<blk->lcnt;j++) {
  55.                 fprintf(stderr,"        list %d: ", j);
  56.                 for(k=0;k<blk->listlen[j];k++)
  57.                   fprintf(stderr,"%d ",blk->lists[j][k]);
  58.                 fprintf(stderr,"\n");
  59.             }
  60.             continue;
  61.         }
  62.         if(blk->fn==mt_m) {
  63.             fprintf(stderr,"Macro starting %d ending %d\n", blk->sublock,
  64.                     blockbuf[blk->sublock].mend);
  65.             continue;
  66.         }
  67.         if(blk->fn==mt_neg) {
  68.             fprintf(stderr,"Neg starting %d\n", blk->sublock);
  69.             continue;
  70.         }
  71.         if(blk->fn==mt_dic) {
  72.             fprintf(stderr,"Dic %s.\n", blk->string);
  73.             continue;
  74.         }
  75.         if(blk->fn==mt_w) {
  76.             fprintf(stderr,"Word list.\n");
  77.             continue;
  78.         }
  79.         if(blk->fn==mt_wild) {
  80.             fprintf(stderr,"Wild min=%d, max=%d.\n", blk->lstart, blk->len+blk->lstart);
  81.             continue;
  82.         }
  83.         if(blk->fn==mt_out) {
  84.             fprintf(stderr,"Output for \"%s\", sub=%d.\n", blk->string,blk->sublock);
  85.             continue;
  86.         }
  87.         fprintf(stderr,"Unknown type!\n");
  88.     }
  89.    
  90. }
  91.  
  92.         /* remove punctuations */
  93. void depunct(char *p,char *str)
  94. {
  95.     char *pp;
  96.     for(pp=p; *pp; pp++) {
  97.         if(strchr(str,*pp)==NULL) continue;
  98.         if(*pp=='.' && pp>p && isdigit(pp[-1]) && isdigit(pp[1])) continue;
  99.         *pp=' ';
  100.     }
  101. }
  102.  
  103.         /* p must have MAX_LINELEN */
  104. void isolate_punct(char *p)
  105. {
  106.     char buf[MAX_LINELEN+1];
  107.     char *p1, *p2;
  108.     for(p1=p, p2=buf; *p1 && p2<buf+MAX_LINELEN; p1++) {
  109.         if(myisalnum(*p1) || (*p1&128) || *p1==' ' || *p1=='_') {
  110.             *p2++=*p1; continue;
  111.         }
  112.         if((*p1=='.' || *p1==',') && p1>p && isdigit(p1[-1]) && isdigit(p1[1])) {
  113.             *p2++=*p1; continue;
  114.         }
  115.         if(p2>buf && !myisspace(p2[-1])) *p2++=' ';
  116.         *p2++=*p1;
  117.         if(p1[1] && !myisspace(p1[1])) *p2++=' ';
  118.     }
  119.     if(p2>=buf+MAX_LINELEN) error("string_too_long");
  120.     *p2=0;
  121.     snprintf(p,MAX_LINELEN,"%s",buf);
  122. }
  123.  
  124. void alphaonly(char *p)
  125. {
  126.     char *pp;
  127.     for(pp=p; *pp; pp++) if(!myisalpha(*pp)) *pp=' ';
  128. }
  129.  
  130. void alnumonly(char *p)
  131. {
  132.     char *pp;
  133.     for(pp=p; *pp; pp++) if(!myisalnum(*pp)) *pp=' ';
  134. }
  135.  
  136.         /* buffer must have MAX_LINELEN */
  137. void strfold(char *p)
  138. {
  139.     char *pp;
  140.     singlespace(p);
  141.     if(noaddw&2) goto fend;
  142.     if(options&op_nocase) for(pp=p; *pp; pp++) *pp=tolower(*pp);
  143.     if(options&op_reaccent) reaccent(p);
  144.     if(options&op_deaccent) deaccent(p);
  145.     if(options&op_alphaonly) alphaonly(p);
  146.     if(options&op_alnumonly) alnumonly(p);
  147.     isolate_punct(p);
  148.     if(options&op_nopunct) depunct(p,char_punct);
  149.     if(options&op_nomath) depunct(p,char_math);
  150.     if(options&op_noparenth) depunct(p,char_parenth);
  151.     if(options&op_nocs) depunct(p,char_cs);
  152.     if(options&op_noquote) depunct(p,char_quote);
  153.     if(suffixcnt>0) suffix_translate(p);
  154.     _translate(p,transdic);
  155.    
  156. fend:
  157.     singlespace(p);strip_trailing_spaces(p);
  158.     if(myisspace(*p)) ovlstrcpy(p,find_word_start(p));
  159. }
  160.  
  161.         /* at entry p must point to an atom start! */
  162. char *find_atom_end(char *p)
  163. {
  164.     char *pp;
  165.     if(*p=='[') {
  166.         pp=find_matching(p+1,']');
  167.         if(pp!=NULL) return pp+1;
  168.         else error("unmatched_parentheses %.20s",p);
  169.     }
  170.     return find_word_end(p);
  171. }
  172.  
  173. #define find_atom_start(x) find_word_start(x)
  174. #define next_atom(x) find_atom_start(find_atom_end(x))
  175.  
  176.         /* p must have MAX_LINELEN */
  177. void macro_trans(char *p)
  178. {
  179.     char *atoms[MAX_BLOCKS], *atom2[MAX_BLOCKS];
  180.     char tbuf[MAX_LINELEN+1], ttbuf[MAX_LINELEN+1], vbuf[8];
  181.     char *pt, *pp, *pe, *p1, *p2, *p3;
  182.     char *pt1, *pt2;
  183.     int i,k,m,n,repcnt,start,min;
  184.    
  185.     if(dic[macrodic].len<=0) return;
  186.     repcnt=start=0; pt=p;
  187.     recalc:
  188.     repcnt++;
  189.     if(repcnt>=MAX_BLOCKS) error("macro_level_overflow %.20s",p);
  190.     for(i=start, pp=find_atom_start(pt); i<MAX_BLOCKS && *pp; pp=next_atom(pp), i++)
  191.       atoms[i]=pp;
  192.     if(i>=MAX_BLOCKS-1) error("block_overflow %.20s",p);
  193.     atoms[i]=pp+strlen(pp);
  194.     for(k=0;k<i;k++) {
  195.         pp=atoms[k]; switch(*pp) {
  196.             case '[': {
  197.                 pe=find_atom_end(pp); pp++;
  198.                 if(pe[-1]!=']') break;
  199.                 if(myislower(*pp)) {
  200.                     for(p1=pp;myisalnum(*p1) || *p1=='_'; p1++);
  201.                     if(*p1!=':') break;
  202.                     *p1++=0; pe[-1]=0;
  203.                     for(m=0,p2=p1;*p2;m++,p2=p3) {
  204.                         p3=find_item_end(p2); if(*p3) *p3++=0;
  205.                         atom2[m]=p2;
  206.                     }
  207.                     if(m==0) m=1;
  208.                     snprintf(tbuf,sizeof(tbuf),"%s",pp);
  209.                     _translate(tbuf,macrodic);
  210.                     if(tbuf[0]==0) error("bad_macro %.50s",pp);
  211.                     for(p1=strchr(tbuf,'@'); p1; p1=strchr(p1,'@')) {
  212.                         for(p2=p1+1;isdigit(*p2) || *p2=='-';p2++);
  213.                         if(p2==p1+1 || p2>p1+6) error("syntax_error %.20s",p1);
  214.                         memmove(vbuf,p1,p2-p1); vbuf[p2-p1]=0;
  215.                         n=atoi(vbuf+1);
  216.                         if(n<=0 || n>m) error("wrong_parmcnt macro %.50s",pp);
  217.                         string_modify(tbuf,p1,p2,atom2[n-1]);
  218.                     }
  219.                     n=strlen(tbuf); if(n<MAX_LINELEN) {
  220.                         tbuf[n++]=' '; tbuf[n]=0;
  221.                     }
  222.                     string_modify(p,pp-1,pe,tbuf); pt=pp-1; start=k;
  223.                     goto recalc;
  224.                 }
  225.                 break;
  226.             }
  227.             case '_': {
  228.                 pe=find_word_end(pp);
  229.                 if(pe-pp>MAX_NAMELEN) error("name_too_long %.20s",pp);
  230.                 memmove(tbuf,pp,pe-pp); tbuf[pe-pp]=0;
  231.                 _translate(tbuf,macrodic);
  232.                 if(tbuf[0]==0) break;
  233.                 pt1=pp; pt2=find_atom_end(pt1); min=k;
  234.                 for(p1=strchr(tbuf,'@'); p1; p1=strchr(p1,'@')) {
  235.                     for(p2=p1+1;isdigit(*p2) || *p2=='-';p2++);
  236.                     if(p2==p1+1 || p2>p1+6) error("syntax_error %.20s",p1);
  237.                     memmove(vbuf,p1,p2-p1); vbuf[p2-p1]=0;
  238.                     n=atoi(vbuf+1);
  239.                     if(n<-4 || n==0 || n>4) error("bad_macro %.20s",atoms[k]);
  240.                     n+=k;
  241.                     if(n<0 || n>=i) error("bad_macro_position %.20s",atoms[k]);
  242.                     p3=find_atom_end(atoms[n]);
  243.                     if(p3>pt2) pt2=p3;
  244.                     if(atoms[n]<pt1) {min=n;pt1=atoms[n];}
  245.                     memmove(ttbuf,atoms[n],p3-atoms[n]); ttbuf[p3-atoms[n]]=' ';
  246.                     ttbuf[p3-atoms[n]+1]=0;
  247.                     string_modify(tbuf,p1,p2,ttbuf);
  248.                 }
  249.                 string_modify(p,pt1,pt2,tbuf); pt=pt1; start=min;
  250.                 goto recalc;
  251.             }
  252.             default: break;
  253.         }
  254.     }
  255. }
  256.  
  257. char *add2cp(char *p)
  258. {
  259.     char *pp, *p1, *p2, buf[MAX_LINELEN+1];
  260.     int l;
  261.     snprintf(buf,sizeof(buf),"%s",p); strfold(buf); l=strlen(buf);
  262.     if((cpnext-cpbuf)+l>=MAX_LINELEN) error("string_too_long");
  263.     pp=cpnext; memmove(pp,buf,l+1); cpnext+=l+1;
  264.     if(!noaddw) for(p1=find_word_start(buf); *p1; p1=find_word_start(p2)) {
  265.         p2=find_word_end(p1); l=p2-p1;
  266.         if(*p2) *p2++=0;
  267.         if(wordchr(wbuf,p1)!=NULL) continue;
  268.         if(wptr-wbuf>=sizeof(wbuf)-l-2) continue;
  269.         if(wptr>wbuf) *wptr++=' ';
  270.         memmove(wptr,p1,l); wptr+=l; *wptr=0;
  271.     }
  272.     return pp;
  273. }
  274.  
  275. void cp_string(char *p, struct block *blk, int next)
  276. {
  277.     blk->fn=mt_string;
  278.     blk->string=add2cp(p);
  279.     blk->len=strlen(blk->string);
  280.     blk->nextblock=next;
  281.     if(blk==blockbuf+nextblock) nextblock++;
  282. }
  283.  
  284.         /* p must have MAX_LINELEN */
  285. void cp_cutline(char *p, struct block *blk, int next)
  286. {
  287.     char *p1, *p2, *p3;
  288.     char buf[MAX_LINELEN+1];
  289.     int l, ll, n, idx, start, end;
  290.     struct block *b;
  291.  
  292.     if(debug>=3) fprintf(stderr,"Cutline %d/%d for %.15s.\n",
  293.                          (int)(blk-blockbuf), nextblock, p);
  294.     for(p1=strstr(p,"[|]"); p1; p1=strstr(p1,"[|]")) memmove(p1," | ",3);
  295.     macro_trans(p);
  296.     singlespace(p);
  297.     p=find_word_start(p); strip_trailing_spaces(p);
  298.     l=0; p3=p; do {
  299.         p1=find_word_start(p3);
  300.         if(*p1) l++;
  301.         p2=strparchr(p1,'[');
  302.         if(p2!=NULL) p3=find_matching(p2+1,']');
  303.         if(p3==NULL) error("unmatched_parentheses %.20s",p);
  304.         if(p2!=NULL && p2>p1) l++;
  305.         p3++;
  306.     } while(p2!=NULL);
  307.     if(l==0) {
  308.         buf[0]=0; cp_string(buf,blk,next);
  309.         return;
  310.     }
  311.     idx=start=nextblock; nextblock+=l-1; end=nextblock;
  312.     if(nextblock > MAX_BLOCKS) error("block_overflow %.20s",p);
  313.     for(p1=find_word_start(p); *p1; p1=find_word_start(p3)) {
  314.         p2=strparchr(p1,'[');
  315.         if(p2==NULL) p2=p1+strlen(p1);
  316.         ll=p2-p1;
  317.         if(ll>0) {
  318.             memmove(buf,p1,ll); buf[ll]=0;
  319.             if(idx==start) b=blk; else b=blockbuf+idx-1;
  320.             if(idx<end) n=idx; else n=next;
  321.             if(debug>=3) fprintf(stderr,"String block %d/%d for %.15s.\n",
  322.                          (int)(b-blockbuf), nextblock, buf);
  323.             cp_string(buf,b,n);
  324.             idx++;
  325.         }
  326.         if(*p2=='[') {
  327.             p2++; p3=find_matching(p2,']');
  328.             memmove(buf,p2,p3-p2); buf[p3-p2]=0; p3++;
  329.             if(idx==start) b=blk; else b=blockbuf+idx-1;
  330.             if(idx<end) n=idx; else n=next;
  331.             cp_oneblock(buf,b,n);
  332.             idx++;
  333.         }
  334.         else p3=p2;
  335.     }
  336. }
  337.  
  338. unsigned int objnum(char *p, char delim)
  339. {
  340.     int i; char *p1, *p2;
  341.  
  342.     if(*p==0) return 1;
  343.     i=0;
  344.     for(p1=p; p1; p1=p2, i++) {
  345.         p2=strparchr(p1,delim); if(p2) p2++;
  346.     }
  347.     return i;
  348. }
  349.  
  350. void _permpick(char *p, int n, struct block *blk, int next, char delim)
  351. {
  352.     int i, t, idx;
  353.     char buf[MAX_LINELEN+1];
  354.     char *pp, *pe;
  355.    
  356.     idx=nextblock; nextblock+=n;
  357.     if(nextblock > MAX_BLOCKS) error("block_overflow %.20s",p);
  358.     blk->len=n;
  359.     blk->sublock=idx;
  360.     blk->fn=mt_permpick;
  361.     blk->lcnt=clist.lcnt;
  362.     blk->nextblock=next;
  363.     if(nextlist+n > MAX_LISTS) error("list_overflow %.20s",p);
  364.     blk->listlen=listbuf+nextlist; nextlist+=n;
  365.     for(i=t=0; i<clist.lcnt; i++) {
  366.         blk->listlen[i]=clist.listlen[i];
  367.         blk->lists[i]=listbuf+nextlist+t;
  368.         t+=clist.listlen[i];
  369.     }
  370.     if(nextlist+t > MAX_LISTS) error("list_overflow %.20s",p);
  371.     memmove(listbuf+nextlist,clist.list,t*sizeof(listtype));
  372.     nextlist+=t;
  373.     for(i=0, pp=find_word_start(p);i<n;i++,idx++,pp=find_word_start(pe)) {
  374.         pe=strparchr(pp,delim);
  375.         if(pe==NULL) pe=pp+strlen(pp); else *pe++=0;
  376.         snprintf(buf,sizeof(buf),"%s",pp);
  377.         cp_cutline(buf,blockbuf+idx,next);
  378.     }
  379. }
  380.  
  381.         /* alt for two flavours */
  382. void _alt(char *p, struct block *blk, int next, char delim)
  383. {
  384.     int n;
  385.     listtype ltab[]={-1};
  386.     listtype len[]={1};
  387.    
  388.     clist.lcnt=1; clist.listlen=len; clist.list=ltab;
  389.     n=objnum(p,delim); if(n==0) n=1;
  390.     _permpick(p,n,blk,next,delim);
  391. }
  392.  
  393. void cp_alt(char *p, struct block *blk, int next)
  394. {
  395.     _alt(p,blk,next,',');
  396. }
  397.  
  398. void cp_alt2(char *p, struct block *blk, int next)
  399. {
  400.     _alt(p,blk,next,'|');
  401. }
  402.  
  403. void cp_aperm(char *p, struct block *blk, int next)
  404. {
  405.     int i, n;
  406.     listtype ltab[MAX_BLOCKS];
  407.     listtype len;
  408.  
  409.     n=objnum(p,','); if(n<4) error("wrong_parmcnt ins %.20s",p);
  410.     if(n>=MAX_BLOCKS/2) error("block_overflow %.20s",p);
  411.     clist.lcnt=1; len=2*n-5; clist.listlen=&len;
  412.     for(i=0;i<n-2;i++) ltab[2*i]=-2;
  413.     for(i=0;i<n-4;i++) ltab[2*i+1]=0;
  414.     ltab[len-2]=1;
  415.     clist.list=ltab;
  416.     _permpick(p,n,blk,blk-blockbuf,',');
  417.     blk->lstart=2;
  418. }
  419.  
  420. void cp_apick(char *p, struct block *blk, int next)
  421. {
  422.     int i, n, t;
  423.     char *p1;
  424.     listtype ltab[MAX_BLOCKS];
  425.     listtype len;
  426.  
  427.     n=objnum(p,','); if(n<4) error("wrong_parmcnt ins %.20s",p);
  428.     if(n>=MAX_BLOCKS/2) error("block_overflow %.20s",p);
  429.     p1=find_item_end(p); if(*p1) *p1++=0;
  430.     t=atoi(p); if(t<=0 || t>n-3) error("syntax_error ins %.20s",p);
  431.     clist.lcnt=1; len=2*t-1; clist.listlen=&len;
  432.     for(i=0;i<t;i++) ltab[2*i]=-2;
  433.     for(i=0;i<t-1;i++) ltab[2*i+1]=0;
  434.     ltab[len-2]=1;
  435.     clist.list=ltab;
  436.     _permpick(p1,n,blk,blk-blockbuf,',');
  437.     blk->lstart=2;
  438. }
  439.  
  440. void cp_dic(char *p, struct block *blk, int next)
  441. {
  442.     int i, n;
  443.     char *p1, *p2;
  444.     n=objnum(p,',');
  445.     if(n!=1) error("wrong_parmcnt dic %.20s",p);
  446.     p1=find_word_start(p); p2=find_word_end(p1);
  447.     if(*p2) *p2++=0;
  448.     p2=find_word_start(p2);
  449.     i=getdic(p1);
  450.     if(i<0) error("bad_dictionary %.20s",p1);
  451.     noaddw=3;
  452.     blk->string=add2cp(p2);
  453.     noaddw=0;
  454.     blk->len=strlen(blk->string);
  455.     blk->lind1=i;
  456.     blk->fn=mt_dic;
  457.     blk->nextblock=next;
  458. }
  459.  
  460. void cp_dperm(char *p, struct block *blk, int next)
  461. {
  462.     int n;
  463.     listtype ltab[]={0,1,2,2,3,0};
  464.     listtype len[]={3,3};
  465.    
  466.     clist.lcnt=2; clist.listlen=len; clist.list=ltab;
  467.     n=objnum(p,',');
  468.     if(n!=4) error("wrong_parmcnt dperm %.20s",p);
  469.     _permpick(p,n,blk,blk-blockbuf,',');
  470. }
  471.  
  472. void cp_ins(char *p, struct block *blk, int next)
  473. {
  474.     int i, n;
  475.     listtype ltab[MAX_BLOCKS];
  476.     listtype len;
  477.  
  478.     n=objnum(p,','); if(n<3) error("wrong_parmcnt ins %.20s",p);
  479.     if(n>=MAX_BLOCKS/2) error("block_overflow %.20s",p);
  480.     clist.lcnt=1; len=2*n-2; clist.listlen=&len;
  481.     for(i=1;i<n;i++) ltab[2*i-2]=i;
  482.     for(i=1;i<len;i+=2) ltab[i]=-12;
  483.     ltab[len-1]=-13;
  484.     clist.list=ltab;
  485.     _permpick(p,n,blk,blk-blockbuf,',');
  486.     blk->lstart=1;
  487. }
  488.  
  489. void cp_iperm(char *p, struct block *blk, int next)
  490. {
  491.     int n;
  492.     listtype ltab[]={0,1,2,2,1,0};
  493.     listtype len[]={3,3};
  494.  
  495.     clist.lcnt=2; clist.listlen=len; clist.list=ltab;
  496.     n=objnum(p,',');
  497.     if(n!=3) error("wrong_parmcnt iperm %.20s",p);
  498.     _permpick(p,n,blk,blk-blockbuf,',');
  499. }
  500.  
  501. void cp_m(char *p, struct block *blk, int next)
  502. {
  503.     int i, idx;
  504.     char buf[MAX_LINELEN+1];
  505.    
  506.     i=objnum(p,','); if(i!=1) error("wrong_parmcnt m %.20s",p);
  507.     blk->fn=mt_m;
  508.     blk->string=NULL;
  509.     blk->len=1;
  510.     blk->nextblock=next;
  511.     p=find_word_start(p);singlespace(p);strip_trailing_spaces(p);
  512.     for(i=0;i<Mcnt && strcmp(p,Mind[i].Mptr)!=0;i++);
  513.     if(nextblock >= MAX_BLOCKS-2) error("block_overflow %.20s",p);
  514.     if(i<Mcnt) blk->sublock=Mind[i].blkptr;
  515.     else {
  516.         i=strlen(p);
  517.         if(Mnext-Mbuf+i >= MAX_LINELEN-1) error("Mbuf_overflow %.20s",p);
  518.         if(Mcnt >= MAX_BLOCKS) error("Mind_overflow %.20s",p);
  519.         Mind[Mcnt].Mptr=Mnext; Mind[Mcnt].blkptr=nextblock;
  520.         Mcnt++;
  521.         memcpy(Mnext,p,i+1); Mnext+=i+1;
  522.         idx=nextblock; blk->sublock=idx; nextblock++;
  523.         snprintf(buf,sizeof(buf),"%s",p);
  524.         cp_cutline(buf,blockbuf+idx,-2);
  525.         blockbuf[idx].mend=nextblock;
  526.     }
  527. }
  528.  
  529. void cp_neg(char *p, struct block *blk, int next)
  530. {
  531.     int n, idx;
  532.     char buf[MAX_LINELEN+1];
  533.     n=objnum(p,','); if(n==0) n=1;
  534.     if(n>1) error("wrong_parmcnt neg %.20s",p);
  535.     blk->fn=mt_neg;
  536.     blk->len=1;
  537.     blk->nextblock=next;
  538.     if(nextblock >= MAX_BLOCKS) error("block_overflow %.20s",p);
  539.     idx=nextblock; blk->sublock=idx; nextblock++;
  540.     snprintf(buf,sizeof(buf),"%s",p);
  541.     cp_cutline(buf,blockbuf+idx,blk-blockbuf);
  542. }
  543.  
  544. void cp_none(char *p, struct block *blk, int next)
  545. {
  546.     blk->fn=mt_nomatch;
  547.     blk->string="";
  548.     blk->nextblock=next;
  549. }
  550.  
  551. void _pick(char *p, struct block *blk, int next, int type)
  552. {
  553.     int i, n, t, v;
  554.     listtype ltab[MAX_BLOCKS];
  555.     listtype len;
  556.     char *p1;
  557.  
  558.     n=objnum(p,','); n--;
  559.     if(n<2) error("wrong_parmcnt pick %.20s",p);
  560.     if(n>=MAX_BLOCKS) error("block_overflow %.20s",p);
  561.     p1=strparchr(p,','); *p1++=0;
  562.     p=find_word_start(p); v=0;
  563.     if(*p=='-') {p++; type-=5;}
  564.     else if(*p=='+') {v=2; p++;}
  565.     t=atoi(p); if(t<1 || t>MAX_PICKS || t>n) error("bad_pickcnt %.20s",p);
  566.     clist.lcnt=1; len=t+v; clist.listlen=&len;
  567.     for(i=0;i<t;i++) ltab[i]=type;
  568.     if(v) {ltab[i++]=-6; ltab[i]=-5;}
  569.     clist.list=ltab;
  570.     _permpick(p1,n,blk,blk-blockbuf,',');
  571. }
  572.  
  573. void cp_out(char *p, struct block *blk, int next)
  574. {
  575.     char buf[MAX_LINELEN+1];
  576.     char *p1;
  577.     int n, idx;
  578.     n=objnum(p,','); if(n!=2) error("wrong_parmcnt out %.20s",p);
  579.     p1=strparchr(p,','); if(p1) *p1++=0; else p1=p+strlen(p);
  580.     p=find_word_start(p); *find_word_end(p)=0;
  581.     noaddw=3;
  582.     blk->string=add2cp(p);
  583.     noaddw=0;
  584.     blk->len=strlen(blk->string);
  585.     blk->fn=mt_out;
  586.     blk->nextblock=next;
  587.     if(nextblock >= MAX_BLOCKS) error("block_overflow %.20s",p);
  588.     idx=nextblock; blk->sublock=idx; nextblock++;
  589.     snprintf(buf,sizeof(buf),"%s",p1);
  590.     cp_cutline(buf,blockbuf+idx,blk-blockbuf);
  591. }
  592.  
  593. void cp_opick(char *p, struct block *blk, int next)
  594. {
  595.     _pick(p,blk,next,-3);
  596. }
  597.  
  598. void cp_perm(char *p, struct block *blk, int next)
  599. {
  600.     int i, n;
  601.     listtype ltab[MAX_BLOCKS];
  602.     listtype len;
  603.  
  604.     n=objnum(p,','); if(n==0) n=1;
  605.     if(n>=MAX_BLOCKS) error("block_overflow %.20s",p);
  606.     clist.lcnt=1; len=n; clist.listlen=&len;
  607.     for(i=0;i<n;i++) ltab[i]=-2;
  608.     clist.list=ltab;
  609.     _permpick(p,n,blk,blk-blockbuf,',');
  610. }
  611.  
  612. void cp_pick(char *p, struct block *blk, int next)
  613. {
  614.     _pick(p,blk,next,-2);
  615. }
  616.  
  617. void cp_rep(char *p, struct block *blk, int next)
  618. {
  619.     int n;
  620.     listtype ltab[]={-1,-5};
  621.     listtype len[]={2};
  622.  
  623.     clist.lcnt=1; clist.listlen=len; clist.list=ltab;
  624.     n=objnum(p,','); if(n==0) n=1;
  625.     _permpick(p,n,blk,blk-blockbuf,',');
  626. }
  627.  
  628. void cp_w(char *p, struct block *blk, int next)
  629. {
  630.     items2words(p);
  631.     blk->string=add2cp(p);
  632.     blk->fn=mt_w;
  633.     blk->nextblock=next;
  634. }
  635.  
  636. void cp_wild(char *p, struct block *blk, int next)
  637. {
  638.     int n, min, max;
  639.     char *pp, *pe;
  640.     n=objnum(p,','); if(n!=1) error("wrong_parmcnt wild %.20s\n",p);
  641.     blk->string="";
  642.     max=min=0;
  643.     for(pp=find_word_start(p); *pp; pp=find_word_start(pe)) {
  644.         pe=find_word_end(pp);
  645.         if(pp[0]!='*') error("syntax_error wild %.20s\n",p);
  646.         if(pp[1]!='*') {
  647.             min++; continue;
  648.         }
  649.         if(isdigit(pp[2])) max+=atoi(pp+2);
  650.         else max=MAX_BLOCKS;
  651.     }
  652.     blk->len=max;
  653.     blk->lstart=min;
  654.     blk->fn=mt_wild;
  655.     blk->nextblock=next;
  656. }
  657.  
  658. struct {
  659.     char *name;
  660.     void (*fn) (char *p, struct block *blk, int next);
  661. } builtin[]={
  662.         {"Alt",         cp_alt},
  663.         {"Aperm",       cp_aperm},
  664.         {"Apick",       cp_apick},
  665.         {"Dic",         cp_dic},
  666.         {"Dperm",       cp_dperm},
  667.         {"Ins",         cp_ins},
  668.         {"Iperm",       cp_iperm},
  669.         {"M",           cp_m},
  670.         {"Neg",         cp_neg},
  671.         {"Nomatch",     cp_none},
  672.         {"None",        cp_none},
  673.         {"Not",         cp_neg},
  674.         {"Opick",       cp_opick},
  675.         {"Out",         cp_out},
  676.         {"Perm",        cp_perm},
  677.         {"Pick",        cp_pick},
  678.         {"Rep",         cp_rep},
  679.         {"W",           cp_w},
  680.         {"Wild",        cp_wild},
  681. };
  682.  
  683. #define builtincnt (sizeof(builtin)/sizeof(builtin[0]))
  684.  
  685.         /* p must have MAX_LINELEN */
  686. void cp_oneblock(char *p, struct block *blk, int next)
  687. {
  688.     char *pp, *pe;
  689.     int i;
  690.     if(debug>=3) fprintf(stderr,"Oneblock %d/%d for %.15s.\n",
  691.                          (int)(blk-blockbuf), nextblock, p);
  692.     if(myisupper(*p)) {
  693.         for(pe=p; pe-p < MAX_BINAME && myisalpha(*pe); pe++);
  694.         if(*pe==':') {
  695.             *pe++=0;
  696.             i=search_list(builtin,builtincnt,sizeof(builtin[0]),p);
  697.             if(i<0) error("unknown_cmd %.20s",p);
  698.             builtin[i].fn(pe,blk,next);
  699.             blk->nextblock=next;
  700.             return;
  701.         }
  702.     }
  703.     if(*p=='*') {
  704.         cp_wild(p,blk,next);
  705.         return;
  706.     }
  707.     pp=strparchr(p,'|'); if(pp==NULL) {
  708.         cp_cutline(p,blk,next);
  709.     }
  710.     else cp_alt2(p,blk,next);
  711. }
  712.  
  713.         /* p must have MAX_LINELEN */
  714. void compile(char *p)
  715. {
  716.     nextblock=1; nextlist=0;
  717.     cpnext=cpbuf;
  718.     memset(blockbuf,0,sizeof(blockbuf));
  719.     cp_oneblock(p,blockbuf,-1);
  720.     showblocks();
  721. }
  722.  
  723.