Merge pull request #110 from tesselode/fixes
[wdl/wdl-ol.git] / WDL / has_strings.h
blob868ffcd75ef2bfc6d0757eeddee358d49a424cec
1 #ifndef _WDL_HASSTRINGS_H_
2 #define _WDL_HASSTRINGS_H_
4 #ifndef WDL_HASSTRINGS_EXPORT
5 #define WDL_HASSTRINGS_EXPORT
6 #endif
8 static bool hasStrings_isNonWordChar(int c)
10 // treat as whitespace when searching for " foo "
11 switch (c)
13 case ' ':
14 case '\t':
15 case '.':
16 case '/':
17 case '\\':
19 return true;
21 default:
22 return false;
26 WDL_HASSTRINGS_EXPORT bool WDL_hasStrings(const char *name, const LineParser *lp)
28 if (!lp) return true;
29 const int ntok = lp->getnumtokens();
30 if (ntok<1) return true;
32 char stack[1024]; // &1=not bit, 0x10 = ignoring subscopes, &2= state when 0x10 set
33 int stacktop = 0;
34 stack[0]=0;
36 int x,ln;
37 const int strlen_name = (int)strlen(name);
38 char matched_local=-1; // -1 = first eval for scope, 0=did not pass scope, 1=OK, 2=ignore rest of scope
39 for (x = 0; x < ntok; x ++)
41 const char *n=lp->gettoken_str(x);
43 if (n[0] == '(' && !n[1] && !lp->gettoken_quotingchar(x))
45 if (!(matched_local&1))
47 stack[stacktop] |= matched_local | 0x10;
48 matched_local=2; // ignore subscope
50 else
52 matched_local = -1; // new scope
55 if (stacktop < (int)sizeof(stack) - 1) stack[++stacktop] = 0;
57 else if (stacktop && n[0] == ')' && !n[1] && !lp->gettoken_quotingchar(x))
59 if (stack[--stacktop]&0x10)
61 // restore state
62 matched_local = stack[stacktop]&2;
64 else
66 matched_local = (matched_local != 0 ? 1 : 0) ^ (stack[stacktop]&1);
68 stack[stacktop] = 0;
70 else if (matched_local != 2 && !strcmp(n,"OR"))
72 matched_local = (matched_local > 0) ? 2 : -1;
73 stack[stacktop] = 0;
75 else if (matched_local&1) // matches 1, -1
77 if (!strcmp(n,"NOT"))
79 stack[stacktop]^=1;
81 else if ((ln=(int)strlen(n))>0)
83 int lt=strlen_name;
84 const char *t=name;
85 // ^foo -- string starts (or follows \1 separator with) foo
86 // foo$ -- string ends with foo (or is immediately followed by \1 separator)
87 // " foo ", "foo ", " foo" include end of string/start of string has whitespace
88 int wc_left = 0; // 1=require \1 or start of string, 2=require space or \1 or start
89 int wc_right = 0; // 1=require \1 or \0, 2 = require space or \1 or \0
90 // perhaps wc_left/wc_right of 2 should also match non-alnum characters in addition to space?
91 if (ln>1)
93 switch (*n)
95 case ' ':
96 if (*++n != ' ') wc_left=2;
97 // else { multiple characters of whitespace = literal whitespace search (two spaces requires a single space, etc) }
99 ln--;
100 break;
101 case '^':
102 ln--;
103 n++;
104 wc_left=1;
105 break;
108 if (ln>1)
110 switch (n[ln-1])
112 case ' ':
113 if (n[--ln - 1] != ' ') wc_right=2;
114 // else { multiple characters of whitespace = literal whitespace search (two spaces requires a single space, etc) }
115 break;
116 case '$':
117 ln--;
118 wc_right++;
119 break;
122 if (!wc_left && !wc_right && *n)
124 switch (lp->gettoken_quotingchar(x))
126 case '\'':
127 case '"':
128 { // if a quoted string has no whitespace in it, treat as whole word search
129 const char *p = n;
130 while (*p && *p != ' ' && *p != '\t') p++;
131 if (!*p) wc_left=wc_right=2;
133 break;
138 if (wc_left>0)
140 unsigned char lastchar = 1;
141 while (lt>=ln)
143 if ((lastchar < 2 || (wc_left>1 && hasStrings_isNonWordChar(lastchar))) && !strnicmp(t,n,ln))
145 if (wc_right == 0) break;
146 const unsigned char nc=((const unsigned char*)t)[ln];
147 if (nc < 2 || (wc_right > 1 && hasStrings_isNonWordChar(nc))) break;
149 lastchar = *(unsigned char*)t++;
150 lt--;
153 else
155 while (lt>=ln)
157 if (!strnicmp(t,n,ln))
159 if (wc_right == 0) break;
160 const unsigned char nc=((const unsigned char*)t)[ln];
161 if (nc < 2 || (wc_right > 1 && hasStrings_isNonWordChar(nc))) break;
163 t++;
164 lt--;
168 matched_local = ((lt-ln)>=0) ^ (stack[stacktop]&1);
169 stack[stacktop]=0;
173 while (stacktop > 0)
175 if (stack[--stacktop] & 0x10) matched_local=stack[stacktop]&2;
176 else matched_local = (matched_local > 0 ? 1 : 0) ^ (stack[stacktop]&1);
179 return matched_local!=0;
182 WDL_HASSTRINGS_EXPORT bool WDL_makeSearchFilter(const char *flt, LineParser *lp)
184 if (WDL_NOT_NORMALLY(!lp)) return false;
186 if (WDL_NOT_NORMALLY(!flt)) flt="";
188 #ifdef WDL_LINEPARSER_HAS_LINEPARSERINT
189 if (lp->parse_ex(flt,true,false,true)) // allow unterminated quotes
190 #else
191 if (lp->parse_ex(flt,true,false))
192 #endif
194 if (*flt) lp->set_one_token(flt); // failed parsing search string, search as a single token
197 return lp->getnumtokens()>0;
200 #endif