1 /*
2  *	(c) Copyright 1990, Kim Fabricius Storm.  All rights reserved.
3  *      Copyright (c) 1996-2005 Michael T Pins.  All rights reserved.
4  *
5  *	String/Subject matching routines.
6  */
7 
8 #include <ctype.h>
9 #include "config.h"
10 #include "global.h"
11 #include "regexp.h"
12 
13 int             case_fold_search = 1;
14 
15 #define MAXFOLD	256		/* max length of any string */
16 
17 /*
18  *	Systems which have a tolower(c) function which is defined for
19  *	all characters, but no _tolower(c) macro which works for
20  *	isupper(c) only, may define HAVE_GENERIC_TOLOWER -- it
21  *	may give a slight speed-up, but is not mandatory.
22  */
23 
24 #ifndef HAVE_GENERIC_TOLOWER
25 
26 #ifndef _tolower
27 #define _tolower(c) tolower(c)
28 #endif
29 
30 #endif
31 
32 void
fold_string(register char * mask)33 fold_string(register char *mask)
34 {				/* convert mask to lower-case */
35     register char   c;
36 
37     for (; (c = *mask); mask++) {
38 
39 #ifdef _tolower
40 	if (!isascii(c) || !isupper(c))
41 	    continue;
42 	*mask = _tolower(c);
43 #else
44 	*mask = tolower(c);
45 #endif
46     }
47 }
48 
49 static int
streq_fold(register char * mask,register char * str)50 streq_fold(register char *mask, register char *str)
51 {				/* mask is prefix of str - FOLD */
52     register char   c = 0, d;
53 
54     while ((d = *mask++)) {
55 	if ((c = *str++) == NUL)
56 	    return 0;
57 	if (c == d)
58 	    continue;
59 
60 #ifdef _tolower
61 	if (!isascii(c) || !isupper(c) || _tolower(c) != (unsigned) d)
62 	    return 0;
63 #else
64 	if (tolower(c) != d)
65 	    return 0;
66 #endif
67     }
68     return c == NUL ? 1 : 2;
69 }
70 
71 int
strmatch_fold(char * mask,register char * str)72 strmatch_fold(char *mask, register char *str)
73 {				/* mask occurs anywhere in str - FOLD */
74     register char   c, m1 = *mask++;
75 
76     for (;;) {
77 	while ((c = *str++)) {	/* find first occ. of mask[0] in str. */
78 	    if (c == m1)
79 		break;
80 
81 #ifdef _tolower
82 	    if (!isascii(c) || !isupper(c))
83 		continue;
84 	    if (_tolower(c) == (unsigned) m1)
85 		break;
86 #else
87 	    if (tolower(c) == m1)
88 		break;
89 #endif
90 	}
91 	if (c == NUL)
92 	    return 0;
93 	if (streq_fold(mask, str))
94 	    return 1;
95     }
96 }
97 
98 int
strmatch(char * mask,register char * str)99 strmatch(char *mask, register char *str)
100 {				/* mask occurs anywhere in str - CASE */
101     register char  *q, *m;
102     register char   m1 = *mask;
103 
104     for (; *str; str++) {
105 	if (*str != m1)
106 	    continue;
107 
108 	q = str;
109 	m = mask;
110 	do
111 	    if (*++m == NUL)
112 		return 1;
113 	while (*++q == *m);
114     }
115     return 0;
116 }
117 
118 int
strmatch_cf(char * mask,char * str)119 strmatch_cf(char *mask, char *str)
120 {				/* fold if case_fold_search is set */
121     if (case_fold_search)
122 	return strmatch_fold(mask, str);
123 
124     return strmatch(mask, str);
125 }
126 
127 /*
128  *	case insensitive regexp matching
129  */
130 
131 int
regexec_fold(register regexp * prog,char * string)132 regexec_fold(register regexp * prog, char *string)
133 {
134     char            buf[256];
135     register char   c, *bp, *str, *maxb;
136 
137     bp = buf, maxb = &buf[255];
138     str = string;
139     while (bp < maxb && (c = *str++) != NUL)
140 
141 #ifdef _tolower
142 	*bp++ = (!isascii(c) || !isupper(c)) ? c : _tolower(c);
143 #else
144 	*bp++ = tolower(c);
145 #endif
146 
147     *bp = NUL;
148 
149     if (!regexec(prog, buf))
150 	return 0;
151 
152     prog->startp[0] = string + (prog->startp[0] - buf);
153     prog->endp[0] = string + (prog->endp[0] - buf);
154     return 1;
155 }
156 
157 int
regexec_cf(register regexp * prog,char * string)158 regexec_cf(register regexp * prog, char *string)
159 {
160     if (case_fold_search)
161 	return regexec_fold(prog, string);
162 
163     return regexec(prog, string);
164 }
165