Rev 10 | Rev 8155 | 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) 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++) { |
||
7673 | bpr | 28 | if(*pp=='(') t++; |
29 | if(*pp==')') {t--; if(t==0) return pp; if(t<0) return NULL;} |
||
10 | reyssat | 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 | |||
7673 | bpr | 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. */ |
||
10 | reyssat | 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; |
||
7673 | bpr | 49 | |
50 | /* Check global pairs of parentheses */ |
||
10 | reyssat | 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)) { |
||
7673 | bpr | 55 | lvl=0; p1=find_word_start(++p1); |
56 | do p2--; while(p2>=p1 && myisspace(*p2)); |
||
57 | p2[1]=0; |
||
10 | reyssat | 58 | } |
59 | gotl=100; r1=r2=p1; r=-1; neg=0; |
||
60 | for(pp=p1; *pp; pp++) { |
||
7673 | bpr | 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 | } |
||
10 | reyssat | 131 | } |
132 | if(gotl>20) { |
||
7673 | bpr | 133 | setvar(error_data_string,"relation not defined"); |
134 | module_error("comp_syntax"); return -1; |
||
10 | reyssat | 135 | } |
7673 | bpr | 136 | |
10 | reyssat | 137 | switch(gotl) { |
7673 | bpr | 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 | } |
||
10 | reyssat | 211 | } |
212 | internal_error("compare(): this should never happen."); |
||
213 | return -1; |
||
214 | } |
||
215 |