(file) Return to like.c CVS log (file) (dir) Up to [OMI] / omi / wql

  1 krisbash 1.1 #include "like.h"
  2              #include <ctype.h>
  3 krisbash 1.2 #include <pal/intsafe.h>
  4 krisbash 1.1 
  5              #if defined(CONFIG_POSIX)
  6              # include <wctype.h>
  7              #endif
  8              
  9              #include <pal/strings.h>
 10              
 11              #define WILDCARD MI_T('%')
 12              #define ANYSINGLECHAR MI_T('_')
 13              
 14              #ifdef _PREFAST_
 15              #pragma prefast (push)
 16              #pragma prefast (disable: 26018)
 17              #pragma prefast (disable: 26001)
 18              #endif
 19              
 20              enum
 21              {
 22                  NO_MATCH = 0,
 23                  MATCHED_WITH_WILDCARD_CHAR = 1,
 24                  MATCHED_WITH_ONE_CHAR = 2,
 25 krisbash 1.1 };
 26              
 27              MI_INLINE ZChar _Toupper(ZChar c)
 28              {
 29              #if (MI_CHAR_TYPE == 1)
 30                  return toupper(c);
 31              #else
 32                  return towupper(c);
 33              #endif
 34              }
 35              
 36              MI_INLINE void _FinalizeMatchState(
 37                  unsigned char** matchState)
 38              {
 39                  if (*matchState != NULL)
 40                  {
 41                      PAL_Free(*matchState);
 42                      *matchState = NULL;
 43                  }
 44              }
 45              
 46 krisbash 1.1 static int _EnsureMatchState(
 47                  size_t stringLength,
 48                  unsigned char** matchState)
 49              {
 50 krisbash 1.2     size_t buffersize = 0;
 51 krisbash 1.1 
 52                  _FinalizeMatchState(matchState);
 53              
 54 krisbash 1.2     if (SizeTMult(stringLength + (size_t) 1, 2, &buffersize) != S_OK)
 55                      return MI_FALSE;
 56              
 57                  if (SizeTMult(buffersize, sizeof(unsigned char), &buffersize) != S_OK)
 58                      return MI_FALSE;
 59              
 60 krisbash 1.1     /* allocate buffer, which is 2 times (the string length + 1) */
 61 krisbash 1.2     *matchState = PAL_Malloc(buffersize);
 62 krisbash 1.1 
 63                  if ( *matchState == NULL )
 64                      return MI_FALSE;
 65              
 66                  /* cleanup the memory */
 67                  memset(*matchState, 0, sizeof(unsigned char) * buffersize);
 68              
 69                  /* start from [0,0], which is always matched */
 70                  (*matchState)[0] = MATCHED_WITH_ONE_CHAR;
 71              
 72                  return MI_TRUE;
 73              }
 74              
 75              static void _SwitchRow(
 76 krisbash 1.2     size_t rowSize,
 77                  unsigned char** currentRow,
 78 krisbash 1.1     unsigned char** previousRow)
 79              {
 80                  unsigned char* tempRow = *currentRow;
 81              
 82                  *currentRow = *previousRow;
 83                  *previousRow = tempRow;
 84                  /* cleanup the current row */
 85                  memset(*currentRow, 0, rowSize);
 86              }
 87              
 88              static int _MatchSet (
 89 krisbash 1.2     const ZChar* pattern,
 90                  const ZChar* string,
 91 krisbash 1.1     int *skip)
 92              {
 93                  int bFnd;
 94                  const ZChar* pos;
 95                  int notinset;
 96                  int matched;
 97                  ZChar lastchar;
 98              
 99                  /*this tells whether ']' is found or not */
100                  bFnd = MI_FALSE;
101              
102                  /* Skip the opening '['. */
103                  pos = pattern+1;
104              
105                  /* See if we are matching a [^] set. */
106                  notinset = (*pos == '^');
107 krisbash 1.2     if (notinset)
108 krisbash 1.1         pos++;
109              
110                  /* See if the target character matches any character in the set. */
111                  matched = MI_FALSE;
112                  lastchar = '\0';
113              
114                  while (*pos && *pos != ']' && !matched)
115                  {
116                      /* A range of characters is indicated by a '-' unless it's the first */
117                      /* character in the set (in which case it's just a character to be */
118                      /* matched. */
119                      if (*pos == '-' && lastchar != '\0')
120                      {
121                          pos++;
122                          if (*pos && *pos != ']')
123                          {
124 krisbash 1.2                 matched = (_Toupper(*string) >= lastchar &&
125 krisbash 1.1                     _Toupper(*string) <= _Toupper(*pos));
126                              lastchar = _Toupper(*pos);
127                              pos++;
128                          }
129                      }
130                      else
131                      {
132                          /* Match a normal character in the set. */
133                          lastchar = _Toupper(*pos);
134                          matched = (_Toupper(*pos) == _Toupper(*string));
135 krisbash 1.2             if (!matched)
136 krisbash 1.1                 pos++;
137                      }
138                  }
139              
140                  /* Find the trailing ']'.  If the set did not contain a closing ']' */
141                  /* we return a failed match. */
142                  while (*pos && *pos != ']') pos++;
143                  if (*pos == ']')
144                  {
145                      pos++;
146                      bFnd = MI_TRUE;
147                  }
148                  /*If ']' is not found and we reach end of string match is false */
149                  /*since this is invalid pattern */
150 krisbash 1.2     if (!*pos && !bFnd)
151 krisbash 1.1         matched = MI_FALSE;
152              
153                  /* Done. */
154                  *skip = (int)(pos-pattern);
155                  return matched == !notinset;
156              }
157              
158              MI_Boolean WQL_MatchLike(
159                  _In_z_ const ZChar* pattern,
160                  _In_z_ const ZChar* string,
161                  ZChar escape)
162              {
163                  size_t stringLength;
164                  size_t rowLength;
165                  const ZChar* orgString;
166                  unsigned char* matchState = NULL;
167                  unsigned char* currentRow;
168                  unsigned char* previousRow;
169              
170                  if (!(*pattern) || !(*string))
171                  {
172 krisbash 1.1         /* skip any trailing wildcard characters */
173                      while (*pattern == WILDCARD) pattern++;
174 krisbash 1.2         if (!(*pattern) && !(*string))
175 krisbash 1.1             return MI_TRUE;
176                      return MI_FALSE;
177                  }
178              
179                  stringLength = Tcslen(string);
180                  rowLength = stringLength + 1;
181                  orgString = string;
182              
183                  if (!_EnsureMatchState(stringLength, &matchState))
184                      return MI_FALSE;
185              
186                  currentRow = matchState + rowLength;
187                  previousRow = matchState;
188                  while (*pattern)
189                  {
190                      /* Wildcard match. */
191                      if (*pattern == WILDCARD)
192                      {
193                          size_t c;
194              
195                          /* skip any continuous wildcard characters */
196 krisbash 1.1             while (*(pattern + 1) == WILDCARD) pattern++;
197              
198                          for (c = 0; c <= stringLength; c++)
199                          {
200                              unsigned char match = previousRow[c];
201                              size_t matchedPos;
202              
203                              if (match == NO_MATCH)
204                              {
205                                  continue;
206                              }
207                              /* found a prior pattern char matched, */
208                              /* then mark that the current wildcard */
209                              /* matching the remaining part of target string */
210                              if (match == MATCHED_WITH_ONE_CHAR)
211                              {
212                                  matchedPos = c + 1;
213                                  /* current wild char still match, but it should be */
214                                  /* the same as its preivous pattern char, I.E., */
215                                  /* matched one char */
216                                  currentRow[c] = MATCHED_WITH_ONE_CHAR;
217 krisbash 1.1                 }
218                              else
219                              {
220                                  /* if previous one is a wildcard match, */
221                                  /* then this wildcard has the same matching result */
222                                  /* with preivous char */
223                                  matchedPos = c;
224                              }
225                              for (; matchedPos <= stringLength; matchedPos++)
226                              {
227                                  currentRow[matchedPos] = MATCHED_WITH_WILDCARD_CHAR;
228                              }
229                              break;
230                          }
231                          _SwitchRow(rowLength, &currentRow, &previousRow);
232                          pattern++;
233                      }
234                      /* Set match. */
235                      else if (*pattern == '[')
236                      {
237                          size_t c;
238 krisbash 1.1             int foundMatch = MI_FALSE;
239                          int foundSkip = 0;
240              
241                          /* find all matching points based on the */
242                          /* previous matching result */
243                          for (c = 0; c <= stringLength; c++)
244                          {
245                              unsigned char match = previousRow[c];
246                              int skip;
247                              const ZChar* currentString;
248              
249                              if (match == NO_MATCH)
250                              {
251                                  continue;
252                              }
253                              currentString = orgString + c;
254                              if (match == MATCHED_WITH_WILDCARD_CHAR)
255                              {
256                                  /* match the current char if preivous is a wildchar match */
257                                  /* otherwise match the next char */
258                                  currentString --;
259 krisbash 1.1                 }
260                              else if (c == stringLength)
261                              {
262                                  /* no match since no char left in target string */
263                                  break;
264                              }
265                              if (_MatchSet (pattern, currentString, &skip))
266                              {
267                                  size_t matchedPos;
268              
269                                  if (!foundMatch)
270                                  {
271                                      foundMatch = MI_TRUE;
272                                      foundSkip = skip;
273                                  }
274                                  /* mark the current pattern char mataching result */
275                                  matchedPos = (size_t)(currentString - orgString) + 1;
276                                  currentRow[matchedPos] = MATCHED_WITH_ONE_CHAR;
277                              }
278                          }
279                          _SwitchRow(rowLength, &currentRow, &previousRow);
280 krisbash 1.1             /* no match */
281                          if (!foundMatch)
282                          {
283                              break;
284                          }
285                          pattern += foundSkip;
286                      }
287                      /* Single character match. */
288                      else
289                      {
290                          size_t c;
291                          int foundMatch = MI_FALSE;
292              
293                          if (escape != '\0' && *pattern == escape)
294                          {
295                              pattern++;
296                          }
297              
298                          /* find all matching points based on the */
299                          /* previous matching result */
300                          for (c = 0; c <= stringLength; c++)
301 krisbash 1.1             {
302                              unsigned char match = previousRow[c];
303                              const ZChar* currentString;
304              
305                              if (match == NO_MATCH)
306                              {
307                                  continue;
308                              }
309                              currentString = orgString + c;
310                              if (match == MATCHED_WITH_WILDCARD_CHAR)
311                              {
312                                  /* match the current char if preivous is a wildchar match, */
313                                  /* otherwise match the next char */
314                                  currentString --;
315                              }
316                              else if (c == stringLength)
317                              {
318                                  /* no match since no char left in target string */
319                                  break;
320                              }
321              
322 krisbash 1.2                 if (_Toupper(*pattern) == _Toupper(*currentString) ||
323 krisbash 1.1                     *pattern == ANYSINGLECHAR)
324                              {
325                                  size_t matchedPos;
326              
327                                  if (!foundMatch)
328                                  {
329                                      foundMatch = MI_TRUE;
330                                  }
331              
332                                  /* mark the current pattern char mataching result */
333                                  matchedPos = (size_t)(currentString - orgString) + 1;
334                                  currentRow[matchedPos] = MATCHED_WITH_ONE_CHAR;
335                              }
336                          }
337                          _SwitchRow(rowLength, &currentRow, &previousRow);
338                          /* no match */
339                          if (!foundMatch)
340                          {
341                              break;
342                          }
343              
344 krisbash 1.1             pattern ++;
345                      }
346                  }
347              
348                  /* Matched if the last pattern char mattached the last target string char */
349                  /* NoMatch otherwise */
350                  {
351                      MI_Boolean flag = (previousRow[stringLength] != 0) ? MI_TRUE : MI_FALSE;
352                      PAL_Free(matchState);
353                      return flag;
354                  }
355              }
356              
357              #ifdef _PREFAST_
358              #pragma prefast (pop)
359              #endif

ViewCVS 0.9.2