1 /* search.c - searching subroutines using dfa, kwset and regex for grep.
2 Copyright 1992, 1998, 2000 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17 02111-1307, USA. */
18
19 /* Written August 1992 by Mike Haertel. */
20
21 /* $FreeBSD: stable/12/gnu/usr.bin/grep/search.c 343988 2019-02-10 23:45:14Z pfg $ */
22
23 #ifndef _GNU_SOURCE
24 # define _GNU_SOURCE 1
25 #endif
26 #ifdef HAVE_CONFIG_H
27 # include <config.h>
28 #endif
29 #include <assert.h>
30 #include <sys/types.h>
31 #if defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H && defined HAVE_MBRTOWC
32 /* We can handle multibyte string. */
33 # define MBS_SUPPORT
34 # include <wchar.h>
35 # include <wctype.h>
36 #endif
37
38 #include "system.h"
39 #include "grep.h"
40 #include "regex.h"
41 #include "dfa.h"
42 #include "kwset.h"
43 #include "error.h"
44 #include "xalloc.h"
45 #ifdef HAVE_LIBPCRE
46 # include <pcre.h>
47 #endif
48 #ifdef HAVE_LANGINFO_CODESET
49 # include <langinfo.h>
50 #endif
51
52 #define NCHAR (UCHAR_MAX + 1)
53
54 /* For -w, we also consider _ to be word constituent. */
55 #define WCHAR(C) (ISALNUM(C) || (C) == '_')
56
57 /* DFA compiled regexp. */
58 static struct dfa dfa;
59
60 /* The Regex compiled patterns. */
61 static struct patterns
62 {
63 /* Regex compiled regexp. */
64 struct re_pattern_buffer regexbuf;
65 struct re_registers regs; /* This is here on account of a BRAIN-DEAD
66 Q@#%!# library interface in regex.c. */
67 } patterns0;
68
69 struct patterns *patterns;
70 size_t pcount;
71
72 /* KWset compiled pattern. For Ecompile and Gcompile, we compile
73 a list of strings, at least one of which is known to occur in
74 any string matching the regexp. */
75 static kwset_t kwset;
76
77 /* Number of compiled fixed strings known to exactly match the regexp.
78 If kwsexec returns < kwset_exact_matches, then we don't need to
79 call the regexp matcher at all. */
80 static int kwset_exact_matches;
81
82 /* UTF-8 encoding allows some optimizations that we can't otherwise
83 assume in a multibyte encoding. */
84 static int using_utf8;
85
86 static void kwsinit PARAMS ((void));
87 static void kwsmusts PARAMS ((void));
88 static void Gcompile PARAMS ((char const *, size_t));
89 static void Ecompile PARAMS ((char const *, size_t));
90 static size_t EGexecute PARAMS ((char const *, size_t, size_t *, int ));
91 static void Fcompile PARAMS ((char const *, size_t));
92 static size_t Fexecute PARAMS ((char const *, size_t, size_t *, int));
93 static void Pcompile PARAMS ((char const *, size_t ));
94 static size_t Pexecute PARAMS ((char const *, size_t, size_t *, int));
95
96 void
check_utf8(void)97 check_utf8 (void)
98 {
99 #ifdef HAVE_LANGINFO_CODESET
100 if (strcmp (nl_langinfo (CODESET), "UTF-8") == 0)
101 using_utf8 = 1;
102 #endif
103 }
104
105 void
dfaerror(char const * mesg)106 dfaerror (char const *mesg)
107 {
108 error (2, 0, mesg);
109 }
110
111 static void
kwsinit(void)112 kwsinit (void)
113 {
114 static char trans[NCHAR];
115 size_t i;
116
117 if (match_icase)
118 for (i = 0; i < NCHAR; ++i)
119 trans[i] = TOLOWER (i);
120
121 if (!(kwset = kwsalloc (match_icase ? trans : (char *) 0)))
122 error (2, 0, _("memory exhausted"));
123 }
124
125 /* If the DFA turns out to have some set of fixed strings one of
126 which must occur in the match, then we build a kwset matcher
127 to find those strings, and thus quickly filter out impossible
128 matches. */
129 static void
kwsmusts(void)130 kwsmusts (void)
131 {
132 struct dfamust const *dm;
133 char const *err;
134
135 if (dfa.musts)
136 {
137 kwsinit ();
138 /* First, we compile in the substrings known to be exact
139 matches. The kwset matcher will return the index
140 of the matching string that it chooses. */
141 for (dm = dfa.musts; dm; dm = dm->next)
142 {
143 if (!dm->exact)
144 continue;
145 ++kwset_exact_matches;
146 if ((err = kwsincr (kwset, dm->must, strlen (dm->must))) != 0)
147 error (2, 0, err);
148 }
149 /* Now, we compile the substrings that will require
150 the use of the regexp matcher. */
151 for (dm = dfa.musts; dm; dm = dm->next)
152 {
153 if (dm->exact)
154 continue;
155 if ((err = kwsincr (kwset, dm->must, strlen (dm->must))) != 0)
156 error (2, 0, err);
157 }
158 if ((err = kwsprep (kwset)) != 0)
159 error (2, 0, err);
160 }
161 }
162
163 static void
Gcompile(char const * pattern,size_t size)164 Gcompile (char const *pattern, size_t size)
165 {
166 const char *err;
167 char const *sep;
168 size_t total = size;
169 char const *motif = pattern;
170
171 check_utf8 ();
172 re_set_syntax (RE_SYNTAX_GREP | RE_HAT_LISTS_NOT_NEWLINE | (match_icase ? RE_ICASE : 0));
173 dfasyntax (RE_SYNTAX_GREP | RE_HAT_LISTS_NOT_NEWLINE, match_icase, eolbyte);
174
175 /* For GNU regex compiler we have to pass the patterns separately to detect
176 errors like "[\nallo\n]\n". The patterns here are "[", "allo" and "]"
177 GNU regex should have raise a syntax error. The same for backref, where
178 the backref should have been local to each pattern. */
179 do
180 {
181 size_t len;
182 sep = memchr (motif, '\n', total);
183 if (sep)
184 {
185 len = sep - motif;
186 sep++;
187 total -= (len + 1);
188 }
189 else
190 {
191 len = total;
192 total = 0;
193 }
194
195 patterns = realloc (patterns, (pcount + 1) * sizeof (*patterns));
196 if (patterns == NULL)
197 error (2, errno, _("memory exhausted"));
198
199 patterns[pcount] = patterns0;
200
201 if ((err = re_compile_pattern (motif, len,
202 &(patterns[pcount].regexbuf))) != 0)
203 error (2, 0, err);
204 pcount++;
205
206 motif = sep;
207 } while (sep && total != 0);
208
209 /* In the match_words and match_lines cases, we use a different pattern
210 for the DFA matcher that will quickly throw out cases that won't work.
211 Then if DFA succeeds we do some hairy stuff using the regex matcher
212 to decide whether the match should really count. */
213 if (match_words || match_lines)
214 {
215 /* In the whole-word case, we use the pattern:
216 \(^\|[^[:alnum:]_]\)\(userpattern\)\([^[:alnum:]_]|$\).
217 In the whole-line case, we use the pattern:
218 ^\(userpattern\)$. */
219
220 static char const line_beg[] = "^\\(";
221 static char const line_end[] = "\\)$";
222 static char const word_beg[] = "\\(^\\|[^[:alnum:]_]\\)\\(";
223 static char const word_end[] = "\\)\\([^[:alnum:]_]\\|$\\)";
224 char *n = xmalloc (sizeof word_beg - 1 + size + sizeof word_end);
225 size_t i;
226 strcpy (n, match_lines ? line_beg : word_beg);
227 i = strlen (n);
228 memcpy (n + i, pattern, size);
229 i += size;
230 strcpy (n + i, match_lines ? line_end : word_end);
231 i += strlen (n + i);
232 pattern = n;
233 size = i;
234 }
235
236 dfacomp (pattern, size, &dfa, 1);
237 kwsmusts ();
238 }
239
240 static void
Ecompile(char const * pattern,size_t size)241 Ecompile (char const *pattern, size_t size)
242 {
243 const char *err;
244 const char *sep;
245 size_t total = size;
246 char const *motif = pattern;
247
248 check_utf8 ();
249 if (strcmp (matcher, "awk") == 0)
250 {
251 re_set_syntax (RE_SYNTAX_AWK | (match_icase ? RE_ICASE : 0));
252 dfasyntax (RE_SYNTAX_AWK, match_icase, eolbyte);
253 }
254 else
255 {
256 re_set_syntax (RE_SYNTAX_POSIX_EGREP | (match_icase ? RE_ICASE : 0));
257 dfasyntax (RE_SYNTAX_POSIX_EGREP, match_icase, eolbyte);
258 }
259
260 /* For GNU regex compiler we have to pass the patterns separately to detect
261 errors like "[\nallo\n]\n". The patterns here are "[", "allo" and "]"
262 GNU regex should have raise a syntax error. The same for backref, where
263 the backref should have been local to each pattern. */
264 do
265 {
266 size_t len;
267 sep = memchr (motif, '\n', total);
268 if (sep)
269 {
270 len = sep - motif;
271 sep++;
272 total -= (len + 1);
273 }
274 else
275 {
276 len = total;
277 total = 0;
278 }
279
280 patterns = realloc (patterns, (pcount + 1) * sizeof (*patterns));
281 if (patterns == NULL)
282 error (2, errno, _("memory exhausted"));
283 patterns[pcount] = patterns0;
284
285 if ((err = re_compile_pattern (motif, len,
286 &(patterns[pcount].regexbuf))) != 0)
287 error (2, 0, err);
288 pcount++;
289
290 motif = sep;
291 } while (sep && total != 0);
292
293 /* In the match_words and match_lines cases, we use a different pattern
294 for the DFA matcher that will quickly throw out cases that won't work.
295 Then if DFA succeeds we do some hairy stuff using the regex matcher
296 to decide whether the match should really count. */
297 if (match_words || match_lines)
298 {
299 /* In the whole-word case, we use the pattern:
300 (^|[^[:alnum:]_])(userpattern)([^[:alnum:]_]|$).
301 In the whole-line case, we use the pattern:
302 ^(userpattern)$. */
303
304 static char const line_beg[] = "^(";
305 static char const line_end[] = ")$";
306 static char const word_beg[] = "(^|[^[:alnum:]_])(";
307 static char const word_end[] = ")([^[:alnum:]_]|$)";
308 char *n = xmalloc (sizeof word_beg - 1 + size + sizeof word_end);
309 size_t i;
310 strcpy (n, match_lines ? line_beg : word_beg);
311 i = strlen(n);
312 memcpy (n + i, pattern, size);
313 i += size;
314 strcpy (n + i, match_lines ? line_end : word_end);
315 i += strlen (n + i);
316 pattern = n;
317 size = i;
318 }
319
320 dfacomp (pattern, size, &dfa, 1);
321 kwsmusts ();
322 }
323
324 static size_t
EGexecute(char const * buf,size_t size,size_t * match_size,int exact)325 EGexecute (char const *buf, size_t size, size_t *match_size, int exact)
326 {
327 register char const *buflim, *beg, *end;
328 char eol = eolbyte;
329 int backref;
330 ptrdiff_t start, len;
331 struct kwsmatch kwsm;
332 size_t i, ret_val;
333 static int use_dfa;
334 static int use_dfa_checked = 0;
335 #ifdef MBS_SUPPORT
336 const char *last_char = NULL;
337 int mb_cur_max = MB_CUR_MAX;
338 mbstate_t mbs;
339 memset (&mbs, '\0', sizeof (mbstate_t));
340 #endif /* MBS_SUPPORT */
341
342 if (!use_dfa_checked)
343 {
344 char *grep_use_dfa = getenv ("GREP_USE_DFA");
345 if (!grep_use_dfa)
346 {
347 #ifdef MBS_SUPPORT
348 /* Turn off DFA when processing multibyte input. */
349 use_dfa = (MB_CUR_MAX == 1);
350 #else
351 use_dfa = 1;
352 #endif /* MBS_SUPPORT */
353 }
354 else
355 {
356 use_dfa = atoi (grep_use_dfa);
357 }
358
359 use_dfa_checked = 1;
360 }
361
362 buflim = buf + size;
363
364 for (beg = end = buf; end < buflim; beg = end)
365 {
366 if (!exact)
367 {
368 if (kwset)
369 {
370 /* Find a possible match using the KWset matcher. */
371 #ifdef MBS_SUPPORT
372 size_t bytes_left = 0;
373 #endif /* MBS_SUPPORT */
374 size_t offset;
375 #ifdef MBS_SUPPORT
376 /* kwsexec doesn't work with match_icase and multibyte input. */
377 if (match_icase && mb_cur_max > 1)
378 /* Avoid kwset */
379 offset = 0;
380 else
381 #endif /* MBS_SUPPORT */
382 offset = kwsexec (kwset, beg, buflim - beg, &kwsm);
383 if (offset == (size_t) -1)
384 goto failure;
385 #ifdef MBS_SUPPORT
386 if (mb_cur_max > 1 && !using_utf8)
387 {
388 bytes_left = offset;
389 while (bytes_left)
390 {
391 size_t mlen = mbrlen (beg, bytes_left, &mbs);
392
393 last_char = beg;
394 if (mlen == (size_t) -1 || mlen == 0)
395 {
396 /* Incomplete character: treat as single-byte. */
397 memset (&mbs, '\0', sizeof (mbstate_t));
398 beg++;
399 bytes_left--;
400 continue;
401 }
402
403 if (mlen == (size_t) -2)
404 {
405 /* Offset points inside multibyte character:
406 * no good. */
407 memset (&mbs, '\0', sizeof (mbstate_t));
408 break;
409 }
410
411 beg += mlen;
412 bytes_left -= mlen;
413 }
414 }
415 else
416 #endif /* MBS_SUPPORT */
417 beg += offset;
418 /* Narrow down to the line containing the candidate, and
419 run it through DFA. */
420 end = memchr(beg, eol, buflim - beg);
421 end++;
422 #ifdef MBS_SUPPORT
423 if (mb_cur_max > 1 && bytes_left)
424 continue;
425 #endif /* MBS_SUPPORT */
426 while (beg > buf && beg[-1] != eol)
427 --beg;
428 if (
429 #ifdef MBS_SUPPORT
430 !(match_icase && mb_cur_max > 1) &&
431 #endif /* MBS_SUPPORT */
432 (kwsm.index < kwset_exact_matches))
433 goto success_in_beg_and_end;
434 if (use_dfa &&
435 dfaexec (&dfa, beg, end - beg, &backref) == (size_t) -1)
436 continue;
437 }
438 else
439 {
440 /* No good fixed strings; start with DFA. */
441 #ifdef MBS_SUPPORT
442 size_t bytes_left = 0;
443 #endif /* MBS_SUPPORT */
444 size_t offset = 0;
445 if (use_dfa)
446 offset = dfaexec (&dfa, beg, buflim - beg, &backref);
447 if (offset == (size_t) -1)
448 break;
449 /* Narrow down to the line we've found. */
450 #ifdef MBS_SUPPORT
451 if (mb_cur_max > 1 && !using_utf8)
452 {
453 bytes_left = offset;
454 while (bytes_left)
455 {
456 size_t mlen = mbrlen (beg, bytes_left, &mbs);
457
458 last_char = beg;
459 if (mlen == (size_t) -1 || mlen == 0)
460 {
461 /* Incomplete character: treat as single-byte. */
462 memset (&mbs, '\0', sizeof (mbstate_t));
463 beg++;
464 bytes_left--;
465 continue;
466 }
467
468 if (mlen == (size_t) -2)
469 {
470 /* Offset points inside multibyte character:
471 * no good. */
472 memset (&mbs, '\0', sizeof (mbstate_t));
473 break;
474 }
475
476 beg += mlen;
477 bytes_left -= mlen;
478 }
479 }
480 else
481 #endif /* MBS_SUPPORT */
482 beg += offset;
483 end = memchr (beg, eol, buflim - beg);
484 end++;
485 #ifdef MBS_SUPPORT
486 if (mb_cur_max > 1 && bytes_left)
487 continue;
488 #endif /* MBS_SUPPORT */
489 while (beg > buf && beg[-1] != eol)
490 --beg;
491 }
492 /* Successful, no backreferences encountered! */
493 if (use_dfa && !backref)
494 goto success_in_beg_and_end;
495 }
496 else
497 end = beg + size;
498
499 /* If we've made it to this point, this means DFA has seen
500 a probable match, and we need to run it through Regex. */
501 for (i = 0; i < pcount; i++)
502 {
503 patterns[i].regexbuf.not_eol = 0;
504 if (0 <= (start = re_search (&(patterns[i].regexbuf), beg,
505 end - beg - 1, 0,
506 end - beg - 1, &(patterns[i].regs))))
507 {
508 len = patterns[i].regs.end[0] - start;
509 if (exact && !match_words)
510 goto success_in_start_and_len;
511 if ((!match_lines && !match_words)
512 || (match_lines && len == end - beg - 1))
513 goto success_in_beg_and_end;
514 /* If -w, check if the match aligns with word boundaries.
515 We do this iteratively because:
516 (a) the line may contain more than one occurence of the
517 pattern, and
518 (b) Several alternatives in the pattern might be valid at a
519 given point, and we may need to consider a shorter one to
520 find a word boundary. */
521 if (match_words)
522 while (start >= 0)
523 {
524 int lword_match = 0;
525 if (start == 0)
526 lword_match = 1;
527 else
528 {
529 assert (start > 0);
530 #ifdef MBS_SUPPORT
531 if (mb_cur_max > 1)
532 {
533 const char *s;
534 size_t mr;
535 wchar_t pwc;
536
537 /* Locate the start of the multibyte character
538 before the match position (== beg + start). */
539 if (using_utf8)
540 {
541 /* UTF-8 is a special case: scan backwards
542 until we find a 7-bit character or a
543 lead byte. */
544 s = beg + start - 1;
545 while (s > buf
546 && (unsigned char) *s >= 0x80
547 && (unsigned char) *s <= 0xbf)
548 --s;
549 }
550 else
551 {
552 /* Scan forwards to find the start of the
553 last complete character before the
554 match position. */
555 size_t bytes_left = start - 1;
556 s = beg;
557 while (bytes_left > 0)
558 {
559 mr = mbrlen (s, bytes_left, &mbs);
560 if (mr == (size_t) -1 || mr == 0)
561 {
562 memset (&mbs, '\0', sizeof (mbs));
563 s++;
564 bytes_left--;
565 continue;
566 }
567 if (mr == (size_t) -2)
568 {
569 memset (&mbs, '\0', sizeof (mbs));
570 break;
571 }
572 s += mr;
573 bytes_left -= mr;
574 }
575 }
576 mr = mbrtowc (&pwc, s, beg + start - s, &mbs);
577 if (mr == (size_t) -2 || mr == (size_t) -1 ||
578 mr == 0)
579 {
580 memset (&mbs, '\0', sizeof (mbstate_t));
581 lword_match = 1;
582 }
583 else if (!(iswalnum (pwc) || pwc == L'_')
584 && mr == beg + start - s)
585 lword_match = 1;
586 }
587 else
588 #endif /* MBS_SUPPORT */
589 if (!WCHAR ((unsigned char) beg[start - 1]))
590 lword_match = 1;
591 }
592
593 if (lword_match)
594 {
595 int rword_match = 0;
596 if (start + len == end - beg - 1)
597 rword_match = 1;
598 else
599 {
600 #ifdef MBS_SUPPORT
601 if (mb_cur_max > 1)
602 {
603 wchar_t nwc;
604 int mr;
605
606 mr = mbtowc (&nwc, beg + start + len,
607 end - beg - start - len - 1);
608 if (mr <= 0)
609 {
610 memset (&mbs, '\0', sizeof (mbstate_t));
611 rword_match = 1;
612 }
613 else if (!iswalnum (nwc) && nwc != L'_')
614 rword_match = 1;
615 }
616 else
617 #endif /* MBS_SUPPORT */
618 if (!WCHAR ((unsigned char) beg[start + len]))
619 rword_match = 1;
620 }
621
622 if (rword_match)
623 {
624 if (!exact)
625 /* Returns the whole line. */
626 goto success_in_beg_and_end;
627 else
628 /* Returns just this word match. */
629 goto success_in_start_and_len;
630 }
631 }
632 if (len > 0)
633 {
634 /* Try a shorter length anchored at the same place. */
635 --len;
636 patterns[i].regexbuf.not_eol = 1;
637 len = re_match (&(patterns[i].regexbuf), beg,
638 start + len, start,
639 &(patterns[i].regs));
640 }
641 if (len <= 0)
642 {
643 /* Try looking further on. */
644 if (start == end - beg - 1)
645 break;
646 ++start;
647 patterns[i].regexbuf.not_eol = 0;
648 start = re_search (&(patterns[i].regexbuf), beg,
649 end - beg - 1,
650 start, end - beg - 1 - start,
651 &(patterns[i].regs));
652 len = patterns[i].regs.end[0] - start;
653 }
654 }
655 }
656 } /* for Regex patterns. */
657 } /* for (beg = end ..) */
658
659 failure:
660 return (size_t) -1;
661
662 success_in_beg_and_end:
663 len = end - beg;
664 start = beg - buf;
665 /* FALLTHROUGH */
666
667 success_in_start_and_len:
668 *match_size = len;
669 return start;
670 }
671
672 #ifdef MBS_SUPPORT
673 static int f_i_multibyte; /* whether we're using the new -Fi MB method */
674 static struct
675 {
676 wchar_t **patterns;
677 size_t count, maxlen;
678 unsigned char *match;
679 } Fimb;
680 #endif
681
682 static void
Fcompile(char const * pattern,size_t size)683 Fcompile (char const *pattern, size_t size)
684 {
685 int mb_cur_max = MB_CUR_MAX;
686 char const *beg, *lim, *err;
687
688 check_utf8 ();
689 #ifdef MBS_SUPPORT
690 /* Support -F -i for UTF-8 input. */
691 if (match_icase && mb_cur_max > 1)
692 {
693 mbstate_t mbs;
694 wchar_t *wcpattern = xmalloc ((size + 1) * sizeof (wchar_t));
695 const char *patternend = pattern;
696 size_t wcsize;
697 kwset_t fimb_kwset = NULL;
698 char *starts = NULL;
699 wchar_t *wcbeg, *wclim;
700 size_t allocated = 0;
701
702 memset (&mbs, '\0', sizeof (mbs));
703 # ifdef __GNU_LIBRARY__
704 wcsize = mbsnrtowcs (wcpattern, &patternend, size, size, &mbs);
705 if (patternend != pattern + size)
706 wcsize = (size_t) -1;
707 # else
708 {
709 char *patterncopy = xmalloc (size + 1);
710
711 memcpy (patterncopy, pattern, size);
712 patterncopy[size] = '\0';
713 patternend = patterncopy;
714 wcsize = mbsrtowcs (wcpattern, &patternend, size, &mbs);
715 if (patternend != patterncopy + size)
716 wcsize = (size_t) -1;
717 free (patterncopy);
718 }
719 # endif
720 if (wcsize + 2 <= 2)
721 {
722 fimb_fail:
723 free (wcpattern);
724 free (starts);
725 if (fimb_kwset)
726 kwsfree (fimb_kwset);
727 free (Fimb.patterns);
728 Fimb.patterns = NULL;
729 }
730 else
731 {
732 if (!(fimb_kwset = kwsalloc (NULL)))
733 error (2, 0, _("memory exhausted"));
734
735 starts = xmalloc (mb_cur_max * 3);
736 wcbeg = wcpattern;
737 do
738 {
739 int i;
740 size_t wclen;
741
742 if (Fimb.count >= allocated)
743 {
744 if (allocated == 0)
745 allocated = 128;
746 else
747 allocated *= 2;
748 Fimb.patterns = xrealloc (Fimb.patterns,
749 sizeof (wchar_t *) * allocated);
750 }
751 Fimb.patterns[Fimb.count++] = wcbeg;
752 for (wclim = wcbeg;
753 wclim < wcpattern + wcsize && *wclim != L'\n'; ++wclim)
754 *wclim = towlower (*wclim);
755 *wclim = L'\0';
756 wclen = wclim - wcbeg;
757 if (wclen > Fimb.maxlen)
758 Fimb.maxlen = wclen;
759 if (wclen > 3)
760 wclen = 3;
761 if (wclen == 0)
762 {
763 if ((err = kwsincr (fimb_kwset, "", 0)) != 0)
764 error (2, 0, err);
765 }
766 else
767 for (i = 0; i < (1 << wclen); i++)
768 {
769 char *p = starts;
770 int j, k;
771
772 for (j = 0; j < wclen; ++j)
773 {
774 wchar_t wc = wcbeg[j];
775 if (i & (1 << j))
776 {
777 wc = towupper (wc);
778 if (wc == wcbeg[j])
779 continue;
780 }
781 k = wctomb (p, wc);
782 if (k <= 0)
783 goto fimb_fail;
784 p += k;
785 }
786 if ((err = kwsincr (fimb_kwset, starts, p - starts)) != 0)
787 error (2, 0, err);
788 }
789 if (wclim < wcpattern + wcsize)
790 ++wclim;
791 wcbeg = wclim;
792 }
793 while (wcbeg < wcpattern + wcsize);
794 f_i_multibyte = 1;
795 kwset = fimb_kwset;
796 free (starts);
797 Fimb.match = xmalloc (Fimb.count);
798 if ((err = kwsprep (kwset)) != 0)
799 error (2, 0, err);
800 return;
801 }
802 }
803 #endif /* MBS_SUPPORT */
804
805
806 kwsinit ();
807 beg = pattern;
808 do
809 {
810 for (lim = beg; lim < pattern + size && *lim != '\n'; ++lim)
811 ;
812 if ((err = kwsincr (kwset, beg, lim - beg)) != 0)
813 error (2, 0, err);
814 if (lim < pattern + size)
815 ++lim;
816 beg = lim;
817 }
818 while (beg < pattern + size);
819
820 if ((err = kwsprep (kwset)) != 0)
821 error (2, 0, err);
822 }
823
824 #ifdef MBS_SUPPORT
825 static int
Fimbexec(const char * buf,size_t size,size_t * plen,int exact)826 Fimbexec (const char *buf, size_t size, size_t *plen, int exact)
827 {
828 size_t len, letter, i;
829 int ret = -1;
830 mbstate_t mbs;
831 wchar_t wc;
832 int patterns_left;
833
834 assert (match_icase && f_i_multibyte == 1);
835 assert (MB_CUR_MAX > 1);
836
837 memset (&mbs, '\0', sizeof (mbs));
838 memset (Fimb.match, '\1', Fimb.count);
839 letter = len = 0;
840 patterns_left = 1;
841 while (patterns_left && len <= size)
842 {
843 size_t c;
844
845 patterns_left = 0;
846 if (len < size)
847 {
848 c = mbrtowc (&wc, buf + len, size - len, &mbs);
849 if (c + 2 <= 2)
850 return ret;
851
852 wc = towlower (wc);
853 }
854 else
855 {
856 c = 1;
857 wc = L'\0';
858 }
859
860 for (i = 0; i < Fimb.count; i++)
861 {
862 if (Fimb.match[i])
863 {
864 if (Fimb.patterns[i][letter] == L'\0')
865 {
866 /* Found a match. */
867 *plen = len;
868 if (!exact && !match_words)
869 return 0;
870 else
871 {
872 /* For -w or exact look for longest match. */
873 ret = 0;
874 Fimb.match[i] = '\0';
875 continue;
876 }
877 }
878
879 if (Fimb.patterns[i][letter] == wc)
880 patterns_left = 1;
881 else
882 Fimb.match[i] = '\0';
883 }
884 }
885
886 len += c;
887 letter++;
888 }
889
890 return ret;
891 }
892 #endif /* MBS_SUPPORT */
893
894 static size_t
Fexecute(char const * buf,size_t size,size_t * match_size,int exact)895 Fexecute (char const *buf, size_t size, size_t *match_size, int exact)
896 {
897 register char const *beg, *try, *end;
898 register size_t len;
899 char eol = eolbyte;
900 struct kwsmatch kwsmatch;
901 size_t ret_val;
902 #ifdef MBS_SUPPORT
903 int mb_cur_max = MB_CUR_MAX;
904 mbstate_t mbs;
905 memset (&mbs, '\0', sizeof (mbstate_t));
906 const char *last_char = NULL;
907 #endif /* MBS_SUPPORT */
908
909 for (beg = buf; beg <= buf + size; ++beg)
910 {
911 size_t offset;
912 offset = kwsexec (kwset, beg, buf + size - beg, &kwsmatch);
913
914 if (offset == (size_t) -1)
915 goto failure;
916 #ifdef MBS_SUPPORT
917 if (mb_cur_max > 1 && !using_utf8)
918 {
919 size_t bytes_left = offset;
920 while (bytes_left)
921 {
922 size_t mlen = mbrlen (beg, bytes_left, &mbs);
923
924 last_char = beg;
925 if (mlen == (size_t) -1 || mlen == 0)
926 {
927 /* Incomplete character: treat as single-byte. */
928 memset (&mbs, '\0', sizeof (mbstate_t));
929 beg++;
930 bytes_left--;
931 continue;
932 }
933
934 if (mlen == (size_t) -2)
935 {
936 /* Offset points inside multibyte character: no good. */
937 memset (&mbs, '\0', sizeof (mbstate_t));
938 break;
939 }
940
941 beg += mlen;
942 bytes_left -= mlen;
943 }
944
945 if (bytes_left)
946 {
947 beg += bytes_left;
948 continue;
949 }
950 }
951 else
952 #endif /* MBS_SUPPORT */
953 beg += offset;
954 #ifdef MBS_SUPPORT
955 /* For f_i_multibyte, the string at beg now matches first 3 chars of
956 one of the search strings (less if there are shorter search strings).
957 See if this is a real match. */
958 if (f_i_multibyte
959 && Fimbexec (beg, buf + size - beg, &kwsmatch.size[0], exact))
960 goto next_char;
961 #endif /* MBS_SUPPORT */
962 len = kwsmatch.size[0];
963 if (exact && !match_words)
964 goto success_in_beg_and_len;
965 if (match_lines)
966 {
967 if (beg > buf && beg[-1] != eol)
968 goto next_char;
969 if (beg + len < buf + size && beg[len] != eol)
970 goto next_char;
971 goto success;
972 }
973 else if (match_words)
974 {
975 while (1)
976 {
977 int word_match = 0;
978 if (beg > buf)
979 {
980 #ifdef MBS_SUPPORT
981 if (mb_cur_max > 1)
982 {
983 const char *s;
984 int mr;
985 wchar_t pwc;
986
987 if (using_utf8)
988 {
989 s = beg - 1;
990 while (s > buf
991 && (unsigned char) *s >= 0x80
992 && (unsigned char) *s <= 0xbf)
993 --s;
994 }
995 else
996 s = last_char;
997 mr = mbtowc (&pwc, s, beg - s);
998 if (mr <= 0)
999 memset (&mbs, '\0', sizeof (mbstate_t));
1000 else if ((iswalnum (pwc) || pwc == L'_')
1001 && mr == (int) (beg - s))
1002 goto next_char;
1003 }
1004 else
1005 #endif /* MBS_SUPPORT */
1006 if (WCHAR ((unsigned char) beg[-1]))
1007 goto next_char;
1008 }
1009 #ifdef MBS_SUPPORT
1010 if (mb_cur_max > 1)
1011 {
1012 wchar_t nwc;
1013 int mr;
1014
1015 mr = mbtowc (&nwc, beg + len, buf + size - beg - len);
1016 if (mr <= 0)
1017 {
1018 memset (&mbs, '\0', sizeof (mbstate_t));
1019 word_match = 1;
1020 }
1021 else if (!iswalnum (nwc) && nwc != L'_')
1022 word_match = 1;
1023 }
1024 else
1025 #endif /* MBS_SUPPORT */
1026 if (beg + len >= buf + size || !WCHAR ((unsigned char) beg[len]))
1027 word_match = 1;
1028 if (word_match)
1029 {
1030 if (!exact)
1031 /* Returns the whole line now we know there's a word match. */
1032 goto success;
1033 else
1034 /* Returns just this word match. */
1035 goto success_in_beg_and_len;
1036 }
1037 if (len > 0)
1038 {
1039 /* Try a shorter length anchored at the same place. */
1040 --len;
1041 offset = kwsexec (kwset, beg, len, &kwsmatch);
1042
1043 if (offset == -1)
1044 goto next_char; /* Try a different anchor. */
1045 #ifdef MBS_SUPPORT
1046 if (mb_cur_max > 1 && !using_utf8)
1047 {
1048 size_t bytes_left = offset;
1049 while (bytes_left)
1050 {
1051 size_t mlen = mbrlen (beg, bytes_left, &mbs);
1052
1053 last_char = beg;
1054 if (mlen == (size_t) -1 || mlen == 0)
1055 {
1056 /* Incomplete character: treat as single-byte. */
1057 memset (&mbs, '\0', sizeof (mbstate_t));
1058 beg++;
1059 bytes_left--;
1060 continue;
1061 }
1062
1063 if (mlen == (size_t) -2)
1064 {
1065 /* Offset points inside multibyte character:
1066 * no good. */
1067 memset (&mbs, '\0', sizeof (mbstate_t));
1068 break;
1069 }
1070
1071 beg += mlen;
1072 bytes_left -= mlen;
1073 }
1074
1075 if (bytes_left)
1076 {
1077 memset (&mbs, '\0', sizeof (mbstate_t));
1078 goto next_char; /* Try a different anchor. */
1079 }
1080 }
1081 else
1082 #endif /* MBS_SUPPORT */
1083 beg += offset;
1084 #ifdef MBS_SUPPORT
1085 /* The string at beg now matches first 3 chars of one of
1086 the search strings (less if there are shorter search
1087 strings). See if this is a real match. */
1088 if (f_i_multibyte
1089 && Fimbexec (beg, len - offset, &kwsmatch.size[0],
1090 exact))
1091 goto next_char;
1092 #endif /* MBS_SUPPORT */
1093 len = kwsmatch.size[0];
1094 }
1095 }
1096 }
1097 else
1098 goto success;
1099 next_char:;
1100 #ifdef MBS_SUPPORT
1101 /* Advance to next character. For MB_CUR_MAX == 1 case this is handled
1102 by ++beg above. */
1103 if (mb_cur_max > 1)
1104 {
1105 if (using_utf8)
1106 {
1107 unsigned char c = *beg;
1108 if (c >= 0xc2)
1109 {
1110 if (c < 0xe0)
1111 ++beg;
1112 else if (c < 0xf0)
1113 beg += 2;
1114 else if (c < 0xf8)
1115 beg += 3;
1116 else if (c < 0xfc)
1117 beg += 4;
1118 else if (c < 0xfe)
1119 beg += 5;
1120 }
1121 }
1122 else
1123 {
1124 size_t l = mbrlen (beg, buf + size - beg, &mbs);
1125
1126 last_char = beg;
1127 if (l + 2 >= 2)
1128 beg += l - 1;
1129 else
1130 memset (&mbs, '\0', sizeof (mbstate_t));
1131 }
1132 }
1133 #endif /* MBS_SUPPORT */
1134 }
1135
1136 failure:
1137 return -1;
1138
1139 success:
1140 #ifdef MBS_SUPPORT
1141 if (mb_cur_max > 1 && !using_utf8)
1142 {
1143 end = beg + len;
1144 while (end < buf + size)
1145 {
1146 size_t mlen = mbrlen (end, buf + size - end, &mbs);
1147 if (mlen == (size_t) -1 || mlen == (size_t) -2 || mlen == 0)
1148 {
1149 memset (&mbs, '\0', sizeof (mbstate_t));
1150 mlen = 1;
1151 }
1152 if (mlen == 1 && *end == eol)
1153 break;
1154
1155 end += mlen;
1156 }
1157 }
1158 else
1159 #endif /* MBS_SUPPORT */
1160 end = memchr (beg + len, eol, (buf + size) - (beg + len));
1161
1162 end++;
1163 while (buf < beg && beg[-1] != eol)
1164 --beg;
1165 len = end - beg;
1166 /* FALLTHROUGH */
1167
1168 success_in_beg_and_len:
1169 *match_size = len;
1170 return beg - buf;
1171 }
1172
1173 #if HAVE_LIBPCRE
1174 /* Compiled internal form of a Perl regular expression. */
1175 static pcre *cre;
1176
1177 /* Additional information about the pattern. */
1178 static pcre_extra *extra;
1179 #endif
1180
1181 static void
Pcompile(char const * pattern,size_t size)1182 Pcompile (char const *pattern, size_t size)
1183 {
1184 #if !HAVE_LIBPCRE
1185 error (2, 0, _("The -P option is not supported"));
1186 #else
1187 int e;
1188 char const *ep;
1189 char *re = xmalloc (4 * size + 7);
1190 int flags = PCRE_MULTILINE | (match_icase ? PCRE_CASELESS : 0);
1191 char const *patlim = pattern + size;
1192 char *n = re;
1193 char const *p;
1194 char const *pnul;
1195
1196 /* FIXME: Remove this restriction. */
1197 if (eolbyte != '\n')
1198 error (2, 0, _("The -P and -z options cannot be combined"));
1199
1200 *n = '\0';
1201 if (match_lines)
1202 strcpy (n, "^(");
1203 if (match_words)
1204 strcpy (n, "\\b(");
1205 n += strlen (n);
1206
1207 /* The PCRE interface doesn't allow NUL bytes in the pattern, so
1208 replace each NUL byte in the pattern with the four characters
1209 "\000", removing a preceding backslash if there are an odd
1210 number of backslashes before the NUL.
1211
1212 FIXME: This method does not work with some multibyte character
1213 encodings, notably Shift-JIS, where a multibyte character can end
1214 in a backslash byte. */
1215 for (p = pattern; (pnul = memchr (p, '\0', patlim - p)); p = pnul + 1)
1216 {
1217 memcpy (n, p, pnul - p);
1218 n += pnul - p;
1219 for (p = pnul; pattern < p && p[-1] == '\\'; p--)
1220 continue;
1221 n -= (pnul - p) & 1;
1222 strcpy (n, "\\000");
1223 n += 4;
1224 }
1225
1226 memcpy (n, p, patlim - p);
1227 n += patlim - p;
1228 *n = '\0';
1229 if (match_words)
1230 strcpy (n, ")\\b");
1231 if (match_lines)
1232 strcpy (n, ")$");
1233
1234 cre = pcre_compile (re, flags, &ep, &e, pcre_maketables ());
1235 if (!cre)
1236 error (2, 0, ep);
1237
1238 extra = pcre_study (cre, 0, &ep);
1239 if (ep)
1240 error (2, 0, ep);
1241
1242 free (re);
1243 #endif
1244 }
1245
1246 static size_t
Pexecute(char const * buf,size_t size,size_t * match_size,int exact)1247 Pexecute (char const *buf, size_t size, size_t *match_size, int exact)
1248 {
1249 #if !HAVE_LIBPCRE
1250 abort ();
1251 return -1;
1252 #else
1253 /* This array must have at least two elements; everything after that
1254 is just for performance improvement in pcre_exec. */
1255 int sub[300];
1256
1257 int e = pcre_exec (cre, extra, buf, size, 0, 0,
1258 sub, sizeof sub / sizeof *sub);
1259
1260 if (e <= 0)
1261 {
1262 switch (e)
1263 {
1264 case PCRE_ERROR_NOMATCH:
1265 return -1;
1266
1267 case PCRE_ERROR_NOMEMORY:
1268 error (2, 0, _("Memory exhausted"));
1269
1270 default:
1271 abort ();
1272 }
1273 }
1274 else
1275 {
1276 /* Narrow down to the line we've found. */
1277 char const *beg = buf + sub[0];
1278 char const *end = buf + sub[1];
1279 char const *buflim = buf + size;
1280 char eol = eolbyte;
1281 if (!exact)
1282 {
1283 end = memchr (end, eol, buflim - end);
1284 end++;
1285 while (buf < beg && beg[-1] != eol)
1286 --beg;
1287 }
1288
1289 *match_size = end - beg;
1290 return beg - buf;
1291 }
1292 #endif
1293 }
1294
1295 struct matcher const matchers[] = {
1296 { "default", Gcompile, EGexecute },
1297 { "grep", Gcompile, EGexecute },
1298 { "egrep", Ecompile, EGexecute },
1299 { "awk", Ecompile, EGexecute },
1300 { "fgrep", Fcompile, Fexecute },
1301 { "perl", Pcompile, Pexecute },
1302 { "", 0, 0 },
1303 };
1304