- /*    Copyright (C) 1998-2003 XIAO, Gang of Universite de Nice - Sophia Antipolis 
-  * 
-  *  This program is free software; you can redistribute it and/or modify 
-  *  it under the terms of the GNU General Public License as published by 
-  *  the Free Software Foundation; either version 2 of the License, or 
-  *  (at your option) any later version. 
-  * 
-  *  This program is distributed in the hope that it will be useful, 
-  *  but WITHOUT ANY WARRANTY; without even the implied warranty of 
-  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
-  *  GNU General Public License for more details. 
-  * 
-  *  You should have received a copy of the GNU General Public License 
-  *  along with this program; if not, write to the Free Software 
-  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
-  */ 
- #include "libwims.h" 
-   
- char t_buf[4][MAX_LINELEN+1]; 
- char maskbuf[MAX_LINELEN+1]; 
-   
- /* internal routine. */ 
- void _text_cut(char *p, char *w) 
- { 
-     char *p1, *p2; 
-     p1=wordchr(p,w); if(p1==NULL) error("syntax_error"); 
-     *- p1 =0;-  p2 =- find_word_start (- p1 +strlen(- w ));
 
-     ovlstrcpy(t_buf[0],p); ovlstrcpy(t_buf[1],p2); 
-     strip_trailing_spaces(t_buf[0]); 
-     substitute(t_buf[0]); substitute(t_buf[1]); 
- } 
-   
- /* Extract characters in buf[0] which are identical to 
-  * corresponding characters in buf[1]. */ 
- void text_common(char *p) 
- { 
-     int i,j,n1,n2; 
-     _text_cut(p,"and"); 
-     if(n2<n1) n1=n2; 
-     for(i=j=0;i<n1;i++) { 
-       if(t_buf[0][i]==t_buf[1][i] && maskbuf[i]!='0') p[j++]=t_buf[0][i]; 
-     } 
-     p[j]=0; 
- } 
-   
- /* Returns a mask string composed of '0's and '1's, where 
-  * '0' means corresponding positions of buf[0] and buf[1] are 
-  * equal. 
-  */ 
- void text_compare(char *p) 
- { 
-     int min,max, i; 
-     _text_cut(p,"and"); 
-     if(min>max) { 
-       i=min; min=max; max=i; 
-     } 
-     for(i=0; i<min; i++) { 
-       if(t_buf[0][i]==t_buf[1][i]) p[i]='0'; else p[i]='1'; 
-     } 
-     for(; i<max; i++) p[i]='1'; 
-     p[max]=0; 
- } 
-   
- /* copy text according to mask. */ 
- void text_copy(char *p) 
- { 
-     int i, j, n; 
-   
-     strip_trailing_spaces(t_buf[0]); substitute(t_buf[0]); 
-     for(i=j=0;i<n;i++) { 
-       if(maskbuf[i]!='0') p[j++]=t_buf[0][i]; 
-     } 
-     p[j]=0; 
- } 
-   
- /* returns count of characters in buf[1] which appear in buf[0]. */ 
- void text_count(char *p) 
- { 
-     int i, n, c; 
-     _text_cut(p,"in"); 
-     for(i=c=0;i<n;i++) { 
-       if(strchr(- t_buf [0],- t_buf [1][- i ])!=- NULL  &&-  maskbuf [- i ]!='0')-  c ++;
 
-     } 
- } 
-   
- /* Extract characters in buf[0] which are different than 
-  * corresponding characters in buf[1]. 
-  */ 
- void text_diff(char *p) 
- { 
-     int i,j,n1,n2; 
-     _text_cut(p,"from"); 
-     if(n2<n1) n1=n2; 
-     for(i=j=0;i<n1;i++) { 
-       if(t_buf[0][i]!=t_buf[1][i] && maskbuf[i]!='0') p[j++]=t_buf[0][i]; 
-     } 
-     p[j]=0; 
- } 
-   
- /* put chars in buf[0] in a new string, into positions 
-  * corresponding to '1's in the mask buf[1]. 
-  * Positions corresponding to '0's are filled by space. 
-  * Fill stops at the end of buf[0]. If buf[1] is 
-  * too short, it is reused from the start. 
-  * FIXME: using 0 as a mask gives a bug 
-  */ 
- /* 
-    @@ !text expand abcdef mask 01 
-    @@ a b c d e f 
-    @@ !text expand abcdef mask 011 
-    @@ ab cd e 
-    @@ !text expand abcdefg using 101110 
-    @@ a bcd e fg 
-  */ 
- void text_expand(char *p) 
- { 
-     int i,j,k,n1,n2; 
-     _text_cut(p,"using"); 
-     if(n2==0) {p[0]=0; return;} 
-     for(i=j=k=0;i<n1 && j<MAX_LINELEN;j++,k=j%n2) { 
-       if(t_buf[1][k]=='0') p[j]=' '; 
-       else p[j]=t_buf[0][i++]; 
-     } 
-     p[j]=0; 
- } 
-   
- /* character by character replacement of buf[1] by buf[0], 
-  * replacing only mask-effective chars. 
-  * The resulting string is as long as buf[1], and the replacement 
-  * stops when chars buf[0] has run out. 
-  */ 
- /* 
-   @@ !text insert abcefg into hijkl mask 10100 
-   @@ aibkl 
-  */ 
- void text_insert(char *p) 
- { 
-     int i,j,n1,n2; 
-     _text_cut(p,"into"); 
-     for(i=j=0; i<n2 && j<n1; i++) { 
-       if(maskbuf[i]!='0') t_buf[1][i]=t_buf[0][j++]; 
-     } 
- } 
-   
- #define MAX_TLEN 96 
-   
- /* interact of two strings according to rules 
-  * defined a table. 
-  */ 
- void text_interact(char *p) 
- { 
-     char *table, *dline, *tline[MAX_TLEN]; 
-     char *p1, *p2; 
-     int i,j1,j2,k,l,l2,n; 
-   
-     table=wordchr(p,"table"); 
-     if(table==NULL) error("syntax_error"); 
-     *table=0; strip_trailing_spaces(p); 
-     table =- find_word_start (- table +strlen("table"));
-     snprintf(- t_buf [2],- MAX_LINELEN ,"%s",- table );
 
-     _text_cut(p,"and"); 
-     strip_trailing_spaces(t_buf[2]); substitute(t_buf[2]); 
-     n=linenum(t_buf[2])-1; 
-     if(n>=MAX_TLEN) error("text_bad_table"); 
-     p2 =strchr(- t_buf [2],'\n'); if(- p2 !=- NULL ) *- p2 ++=0;
-     if(strlen(- t_buf [2])!=- n )-  error ("text_bad_table");
 
-     dline=t_buf[2]; 
-     for(i=0,p1=p2;i<n;i++,p1=p2) { 
-       if(p1==NULL) error("text_bad_table"); 
-       if(p2!=NULL) *p2++=0; 
-       if(strlen(- p1 )!=- n )-  error ("text_bad_table");
 
-       tline[i]=p1; 
-     } 
-     for(i=k=0;i<l;i++) { 
-       if(maskbuf[i]!='0') { 
-           if(p1==NULL || p2==NULL) continue; 
-           j1=p1-dline; j2=p2-dline; 
-           if(j1>=n || j2>=n) continue; /* should not occur */ 
-           p[k++]=tline[j1][j2]; 
-       } 
-     } 
-     p[k]=0; 
- } 
-   
- /* returns a mask string composed of '0's and '1's, where 
-  * '0' means corresponding char in buf[1] appears in buf[0]. 
-  */ 
- /* 
-    @@ !text mark a in abcaefa 
-    @@ 001001 
-  */ 
- void text_mark(char *p) 
- { 
-     int i, n; 
-     _text_cut(p,"in"); 
-     for(i=0;i<n;i++) { 
-       if(strchr(- t_buf [0],- t_buf [1][- i ])!=- NULL )-  p [- i ]='1';
 
-       else p[i]='0'; 
-     } 
-     p[i]=0; 
- } 
-   
- /* Returns a string whose characters are the maximum 
-  * of the two corresponding chars in buf[0] and buf[1]. 
-  * Length of the string is the longuest one. 
-  */ 
- void text_max(char *p) 
- { 
-     int min,max, i, j, k; 
-     _text_cut(p,"and"); 
-     if(min>max) { 
-       i=min; min=max; max=i; j=0; 
-     } 
-     else j=1; 
-     for(i=k=0; i<min; i++) { 
-       if(maskbuf[i]=='0') continue; 
-       if((unsigned char)t_buf[0][i]>(unsigned char)t_buf[1][i]) 
-           p[k++]=t_buf[0][i]; 
-       else p[k++]=t_buf[1][i]; 
-     } 
-     for(;i<max;i++) { 
-       if(maskbuf[i]!='0') p[k++]=t_buf[j][i]; 
-     } 
-     p[k]=0; 
- } 
-   
- /* Returns a string whose characters are the minimum 
-  * of the two corresponding chars in buf[0] and buf[1]. 
-  * Length of the string is the shortest one. 
-  */ 
- void text_min(char *p) 
- { 
-     int min,max, i,k; 
-     _text_cut(p,"and"); 
-     if(min>max) { 
-       i=min; min=max; max=i; 
-     } 
-     for(i=k=0; i<min; i++) { 
-       if(maskbuf[i]=='0') continue; 
-       if((unsigned char)t_buf[0][i]< (unsigned char)t_buf[1][i]) 
-           p[k++]=t_buf[0][i]; 
-       else p[k++]=t_buf[1][i]; 
-     } 
-     p[k]=0; 
- } 
-   
- /* extract chars in buf[0] which occur in buf[1]. */ 
- void text_occur(char *p) 
- { 
-     int i,j,n; 
-     char buf[MAX_LINELEN+1]; 
-     _text_cut(p,"in"); 
-     for(i=0;i<n;i++) { 
-       char *pp; 
-       if(maskbuf[i]=='0') continue; 
-       pp =strchr(- t_buf [0],- t_buf [1][- i ]);
-       if(pp!=NULL) buf[pp - t_buf[0]]=1; 
-     } 
-     for(i=j=0;i<n;i++) { 
-       if(buf[i]) p[j++]=t_buf[0][i]; 
-     } 
-     p[j]=0; 
- } 
-   
- /* remove characters of buf[1] in buf[0]. */ 
- void text_remove(char *p) 
- { 
-     int i, j, n; 
-     _text_cut(p,"in"); 
-     for(i=j=0;i<n;i++) { 
-       if(strchr(- t_buf [0],- t_buf [1][- i ])==- NULL 
 
-          && maskbuf[i]!='0') p[j++]=t_buf[1][i]; 
-     } 
-     p[j]=0; 
- } 
-   
- /* Cyclic reordering of text. */ 
- void text_reorder(char *p) 
- { 
-     int i,j,k,l,n,t; 
-     int list[10240]; 
-     char buf[MAX_LINELEN+1]; 
-     _text_cut(p,"by"); *p=0; 
-     n=itemnum(t_buf[1]); if(n<=0 || n>=10240) return; 
-     for(i=0;i<n;i++) { 
-         buf[0]=0; fnd_item(t_buf[1],i+1,buf); 
-       j =atoi(- buf ); if(- j <=0 ||-  j >- n ) return;
-       list[i]=j; 
-     } 
-     for(i=l=0;l<t && i<t+n;i++) { 
-       j=i/n; k=j*n+list[i%n]; 
-       if(k>t || k<=0) continue; 
-       p[l++]=t_buf[0][k-1]; 
-     } 
-     p[l]=0; 
- } 
-   
- /* repeat a string to a given length. */ 
- void text_repeat(char *p) 
- { 
-     int n,i,k; 
-     _text_cut(p,"to"); 
-     n=strevalue(t_buf[1]); if(n>MAX_LINELEN) n=MAX_LINELEN; 
-     if(n<0) n=0; 
-     k =strlen(- t_buf [0]); if(- k <=0) {*- p =0; return;}
-     for(i=0;i<n;i++) { 
-       p[i]=t_buf[0][i%k]; 
-     } 
-     p[i]=0; 
- } 
-   
- /* reverse a string */ 
- void text_reverse(char *p) 
- { 
-     int i,n; 
-     char buf[MAX_LINELEN+1]; 
-     snprintf(- t_buf [0],sizeof(- t_buf [0]),"%s",- p );
 
-     substitute(t_buf[0]); 
-     n =strlen(- t_buf [0]); if(- n >- MAX_LINELEN )-  n =- MAX_LINELEN ;
-     for(i=0;i<n;i++) buf[i]=t_buf[0][n-1-i]; 
-     buf[n]=0; 
-     ovlstrcpy(p,buf); 
- } 
-   
- /* remove characters of buf[1] not in buf[0]. */ 
- void text_select(char *p) 
- { 
-     int i, j, n; 
-     _text_cut(p,"in"); 
-     for(i=j=0;i<n;i++) { 
-       if(strchr(- t_buf [0],- t_buf [1][- i ])!=- NULL 
 
-          && maskbuf[i]!='0') p[j++]=t_buf[1][i]; 
-     } 
-     p[j]=0; 
- } 
-   
- /* tag: bit 0 is mask. */ 
- struct { 
-     char *name; 
-     int tag; 
-     void (*routine) (char *p); 
- } text_proc[]={ 
-       {"appear",    1,  text_occur}, 
-       {"common",    1,  text_common}, 
-       {"compare",   0,  text_compare}, 
-       {"copy",      1,  text_copy}, 
-       {"count",     1,  text_count}, 
-       {"delete",    1,  text_remove}, 
-       {"diff",      1,  text_diff}, 
-       {"differ",    1,  text_diff}, 
-       {"drop",      1,  text_remove}, 
-       {"expand",    0,  text_expand}, 
-       {"extract",   1,  text_select}, 
-       {"insert",    1,  text_insert}, 
-       {"interact",  1,  text_interact}, 
-       {"mark",      0,  text_mark}, 
-       {"max",       1,  text_max}, 
-       {"min",       1,  text_min}, 
-       {"occur",     1,  text_occur}, 
-       {"occurrence",1,  text_occur}, 
-       {"pick",      1,  text_select}, 
-       {"pickup",    1,  text_select}, 
-       {"remove",    1,  text_remove}, 
-       {"reorder",   0,  text_reorder}, 
-       {"repeat",    0,  text_repeat}, 
-       {"reverse",   0,  text_reverse}, 
-       {"select",    1,  text_select} 
- }; 
- #define TEXT_PROC_NO (sizeof(text_proc)/sizeof(text_proc[0])) 
-   
- int textab_verify(void) { 
-     return verify_order(text_proc,TEXT_PROC_NO,sizeof(text_proc[0])); 
- } 
-   
- /* main entry point for text routines */ 
- void text(char *p) 
- { 
-     int i,j,n; 
-     char *p1, *p2; 
-     char c,cc; 
-     char buf[MAX_LINELEN+1]; 
-     p1=find_word_start(p); p2=find_word_end(p1); 
-     if(p2<=p1 || *p2==0) error("syntax_error"); 
-     *p2=0; 
-     i=search_list(text_proc,TEXT_PROC_NO,sizeof(text_proc[0]),p1); 
-     if(i<0) error("syntax_error"); 
-     snprintf(- buf ,sizeof(- buf ),"%s",- find_word_start (- p2 +1));
 
-     if((text_proc[i].tag&1)!=0 && (p1=wordchr(buf,"mask"))!=NULL) { 
-       *p1=0; strip_trailing_spaces(buf); 
-       p2 =- find_word_start (- p1 +strlen("mask"));
-       strip_trailing_spaces(p2); 
-       snprintf(- maskbuf ,sizeof(- maskbuf ),"%s",- p2 );
 
-       substitute(maskbuf); 
-       n =strlen(- maskbuf ); if(- n ==0) goto-  zeromask ;
-       c=maskbuf[n-1]; cc=0; 
-       if(c=='+') cc='1'; if(c=='-') cc='0'; 
-       if(- cc !=0) memset(- maskbuf +- n -1,- cc ,sizeof(- maskbuf )-- n );
 
-       else for(j=n;j<MAX_LINELEN;j++) maskbuf[j]=maskbuf[j%n]; 
-       maskbuf[sizeof(maskbuf)-1]=0; 
-     } 
-     else-  zeromask : memset(- maskbuf ,0,sizeof(- maskbuf ));
 
-     text_proc[i].routine(buf); 
-     buf[MAX_LINELEN]=0;ovlstrcpy(p,buf); 
- } 
-