Subversion Repositories wimsdev

Rev

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

  1. /*    Copyright (C) 1998-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 *bufprep(char *p)
  19. {
  20. /*  singlespace(p); strip_trailing_spaces(p); return find_word_start(p); */
  21.     nospace(p); return p;
  22. }
  23.  
  24. char *parend(char *p)
  25. {
  26.     char *pp; int t;
  27.     t=0; for(pp=p;*pp;pp++) {
  28.         if(*pp=='(') t++;
  29.         if(*pp==')') {t--; if(t==0) return pp; if(t<0) return NULL;}
  30.     }
  31.     return NULL;
  32. }
  33.  
  34. char *relation_type[]={
  35.     "sametext","samecase",
  36.     "in",  "wordof","itemof","lineof","varof","variableof"
  37. };
  38. #define total_relations (sizeof(relation_type)/sizeof(relation_type[0]))
  39.  
  40.         /* Compares two string. Returns 1 if yes, 0 if no, -1 if error.
  41.          * In fact, -1 will occur only if module_error() is modified to
  42.          * return instead of abort. */
  43.         /* TODO: quoted string. */
  44. int compare(char *p, int numeric, int lvl)
  45. {
  46.     char *p1, *p2, *pp, *pt;
  47.     char *r1, *r2;
  48.     int i, l, k, r, neg, gotl;
  49.    
  50.         /* Check global pairs of parentheses */
  51.     p2=strip_trailing_spaces(p);
  52.     p1=find_word_start(p);
  53.     if(lvl==0 && p2-p1>=MAX_LINELEN-1) module_error("parm_too_long");
  54.     while(*p1=='(' && *p2==')' && p2==parend(p1)) {
  55.         lvl=0; p1=find_word_start(++p1);
  56.         do p2--; while(p2>=p1 && myisspace(*p2));
  57.         p2[1]=0;
  58.     }
  59.     gotl=100; r1=r2=p1; r=-1; neg=0;
  60.     for(pp=p1; *pp; pp++) {
  61.         if(*pp==')') {badpar: module_error("unmatched_parentheses"); return -1;}
  62.         if(*pp=='(') {
  63.             pp=parend(pp); if(pp==NULL) goto badpar;
  64.             continue;
  65.         }
  66.         if(gotl>3) {
  67.             switch(*pp) {
  68.                 case '<': {
  69.                     gotl=3; r1=pp; r2=r1+1; r=102; neg=0;
  70.                     if(*r2=='=') {r2++; r=103; neg=1;}
  71.                     if(*r2=='>') {
  72.                         r2++; neg=1;
  73.                         if(numeric) r=101; else r=0;
  74.                     }
  75.                     break;
  76.                 }
  77.                 case '>': {
  78.                     gotl=3; r1=pp; r2=r1+1; r=103; neg=0;
  79.                     if(*r2=='=') {r2++; r=102; neg=1;}
  80.                     break;
  81.                 }
  82.                 case '=': {
  83.                     gotl=3; neg=0; r1=pp; r2=r1+1; if(*r2=='=') r2++;
  84.                     if(numeric) r=101; else r=0;
  85.                     break;
  86.                 }
  87.                 case '!': {
  88.                     if(pp[1]=='=') {
  89.                         gotl=3; r1=pp; r2=pp+2; neg=1;
  90.                         if(numeric) r=101; else r=0;
  91.                     }
  92.                     break;
  93.                 }
  94.             }
  95.             if(r2>p1) {
  96.                 if(lvl==2) break;
  97.                 pp=r2-1; continue;
  98.             }
  99.         }
  100.         if(!myisspace(*pp)) continue;
  101.         pp=find_word_start(pp);
  102.         if(gotl>3) {
  103.             if(pp[0]=='i' && pp[1]=='s') {k=2; neg=0; goto isnot;}
  104.             if(pp[0]=='n' && pp[1]=='o' && pp[2]=='t') {k=3; neg=1; goto isnot;}
  105.             goto rel;
  106.             isnot:
  107.             if(strchr("siwlv",pp[k])==NULL) goto rel;
  108.             pt=pp; pp+=k; l=0;
  109.             for(i=0;i<total_relations;i++) {
  110.                 l=strlen(relation_type[i]);
  111.                 if(strncmp(pp, relation_type[i], l)==0 &&
  112.                    ((!myisalnum(pp[l]) && pp[l]!='_') || pp[l]==0)) break;
  113.             }
  114.             if(i>=total_relations) {pp--; continue;}
  115.             gotl=3; r=i+1; pp+=l; r1=pt; r2=pp;
  116.             if(lvl==2) break; else {pp--; continue;}
  117.         }
  118.         rel:
  119.         if(*pp!='|' && *pp!='&' && *pp!='a' && *pp!='o')
  120.             {pp--; continue;}
  121.         if(gotl>2 &&
  122.            ((myisspace(pp[3]) && strncmp(pp,"and",3)==0) ||
  123.             (myisspace(pp[2]) && strncmp(pp,"&&",2)==0))) {
  124.             gotl=2; r1=pp; pp=r2=find_word_end(r1);
  125.             if(lvl==1) break; else {pp--;continue;}
  126.         }
  127.         if(gotl>1 && myisspace(pp[2]) &&
  128.            (strncmp(pp,"or",2)==0 || strncmp(pp,"||",2)==0)) {
  129.             gotl=1; r1=pp; r2=pp=r1+2; break;
  130.         }
  131.     }
  132.     if(gotl>20) {
  133.         setvar(error_data_string,"relation not defined");
  134.         module_error("comp_syntax"); return -1;
  135.     }
  136.    
  137.     switch(gotl) {
  138.         case 1: {       /* or */
  139.             *r1=0; i=compare(p1,numeric,1); if(i) return i;
  140.             else return compare(r2,numeric,0);
  141.         }
  142.         case 2: {       /* and */
  143.             *r1=0; i=compare(p1,numeric,2); if(i<=0) return i;
  144.             else return compare(r2,numeric,1);
  145.         }
  146.         case 3: {       /* atomic comparison */
  147.             if(r<100) { /* textual comparison */
  148.                 char buf1[MAX_LINELEN+1], buf2[MAX_LINELEN+1];
  149.                 while(r1>p1 && myisspace(r1[-1])) r1--;
  150.                 memmove(buf1,p1,r1-p1); buf1[r1-p1]=0;
  151.                 r2=find_word_start(r2);
  152.                 while(p2>=r2 && myisspace(*p2)) p2--;
  153.                 memmove(buf2,r2,p2+1-r2); buf2[p2+1-r2]=0;
  154.                 substitute(buf1); substitute(buf2);
  155.                 switch(r) {
  156.                     case 0: {   /* equal */
  157.                         if(strcmp(buf1,buf2)==0) return 1^neg; else return neg;
  158.                     }
  159.                     case 1: {   /* sametext */
  160.                         deaccent(buf1); deaccent(buf2);
  161.                         if(strcasecmp(bufprep(buf1),bufprep(buf2))==0)
  162.                           return 1^neg;
  163.                         else return neg;
  164.                     }
  165.                     case 2: {   /* samecase */
  166.                         if(strcmp(bufprep(buf1),bufprep(buf2))==0)
  167.                           return 1^neg;
  168.                         else return neg;
  169.                     }
  170.                     case 3: {   /* in */
  171.                         if(strstr(buf2,buf1)!=NULL) return 1^neg; else return neg;
  172.                     }
  173.                     case 4: {   /* wordof */
  174.                         if(wordchr(buf2,buf1)!=NULL) return 1^neg; else return neg;
  175.                     }
  176.                     case 5: {   /* itemof */
  177.                         if(itemchr(buf2,buf1)!=NULL) return 1^neg; else return neg;
  178.                     }
  179.                     case 6: {   /* lineof */
  180.                         if(linechr(buf2,buf1)!=NULL) return 1^neg; else return neg;
  181.                     }
  182.                     case 7:
  183.                     case 8: {   /* varof */
  184.                         if(varchr(buf2,buf1)!=NULL) return 1^neg; else return neg;
  185.                     }
  186.                 }
  187.             }
  188.             else {      /* numerical comparison */
  189.                 double d1, d2, sum, diff, prec;
  190.                 *r1=0;
  191.                 d1=evalue(p1); d2=evalue(r2);
  192.                 sum=d1+d2; if(sum<0) sum=-sum;
  193.                 diff=d1-d2; if(diff<0) diff=-diff;
  194.                 prec=evalue(getvar("wims_compare_precision"));  /* Move string name to header! */
  195.                 diff=diff*prec;
  196.                 if(prec>0 && prec<1E10) sum=sum+1/prec;
  197.                 switch(r) {
  198.                     case 101: { /* = */
  199.                         if(sum>=diff) return 1^neg; else return neg;
  200.                     }
  201.                     case 102: { /* < */
  202.                         if(d1<d2) return 1^neg; else return neg;
  203.                     }
  204.                     case 103: { /* > */
  205.                         if(d1>d2) return 1^neg; else return neg;
  206.                     }
  207.                     default: break;     /* should never occur */
  208.                 }
  209.             }
  210.         }
  211.     }
  212.     internal_error("compare(): this should never happen.");
  213.     return -1;
  214. }
  215.  
  216.