1 #ifndef _WDL_HASSTRINGS_H_
2 #define _WDL_HASSTRINGS_H_
4 #ifndef WDL_HASSTRINGS_EXPORT
5 #define WDL_HASSTRINGS_EXPORT
8 static bool hasStrings_isNonWordChar(int c
)
10 // treat as whitespace when searching for " foo "
26 WDL_HASSTRINGS_EXPORT
bool WDL_hasStrings(const char *name
, const LineParser
*lp
)
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
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
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)
62 matched_local
= stack
[stacktop
]&2;
66 matched_local
= (matched_local
!= 0 ? 1 : 0) ^ (stack
[stacktop
]&1);
70 else if (matched_local
!= 2 && !strcmp(n
,"OR"))
72 matched_local
= (matched_local
> 0) ? 2 : -1;
75 else if (matched_local
&1) // matches 1, -1
81 else if ((ln
=(int)strlen(n
))>0)
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?
96 if (*++n
!= ' ') wc_left
=2;
97 // else { multiple characters of whitespace = literal whitespace search (two spaces requires a single space, etc) }
113 if (n
[--ln
- 1] != ' ') wc_right
=2;
114 // else { multiple characters of whitespace = literal whitespace search (two spaces requires a single space, etc) }
122 if (!wc_left
&& !wc_right
&& *n
)
124 switch (lp
->gettoken_quotingchar(x
))
128 { // if a quoted string has no whitespace in it, treat as whole word search
130 while (*p
&& *p
!= ' ' && *p
!= '\t') p
++;
131 if (!*p
) wc_left
=wc_right
=2;
140 unsigned char lastchar
= 1;
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
++;
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;
168 matched_local
= ((lt
-ln
)>=0) ^ (stack
[stacktop
]&1);
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
191 if (lp
->parse_ex(flt
,true,false))
194 if (*flt
) lp
->set_one_token(flt
); // failed parsing search string, search as a single token
197 return lp
->getnumtokens()>0;