1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.haxx.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ***************************************************************************/
22
23 #include "curl_setup.h"
24
25 #include <curl/curl.h>
26
27 #include "strcase.h"
28
29 /* Portable, consistent toupper (remember EBCDIC). Do not use toupper() because
30 its behavior is altered by the current locale. */
Curl_raw_toupper(char in)31 char Curl_raw_toupper(char in)
32 {
33 #if !defined(CURL_DOES_CONVERSIONS)
34 if(in >= 'a' && in <= 'z')
35 return (char)('A' + in - 'a');
36 #else
37 switch(in) {
38 case 'a':
39 return 'A';
40 case 'b':
41 return 'B';
42 case 'c':
43 return 'C';
44 case 'd':
45 return 'D';
46 case 'e':
47 return 'E';
48 case 'f':
49 return 'F';
50 case 'g':
51 return 'G';
52 case 'h':
53 return 'H';
54 case 'i':
55 return 'I';
56 case 'j':
57 return 'J';
58 case 'k':
59 return 'K';
60 case 'l':
61 return 'L';
62 case 'm':
63 return 'M';
64 case 'n':
65 return 'N';
66 case 'o':
67 return 'O';
68 case 'p':
69 return 'P';
70 case 'q':
71 return 'Q';
72 case 'r':
73 return 'R';
74 case 's':
75 return 'S';
76 case 't':
77 return 'T';
78 case 'u':
79 return 'U';
80 case 'v':
81 return 'V';
82 case 'w':
83 return 'W';
84 case 'x':
85 return 'X';
86 case 'y':
87 return 'Y';
88 case 'z':
89 return 'Z';
90 }
91 #endif
92
93 return in;
94 }
95
96
97 /* Portable, consistent tolower (remember EBCDIC). Do not use tolower() because
98 its behavior is altered by the current locale. */
Curl_raw_tolower(char in)99 char Curl_raw_tolower(char in)
100 {
101 #if !defined(CURL_DOES_CONVERSIONS)
102 if(in >= 'A' && in <= 'Z')
103 return (char)('a' + in - 'A');
104 #else
105 switch(in) {
106 case 'A':
107 return 'a';
108 case 'B':
109 return 'b';
110 case 'C':
111 return 'c';
112 case 'D':
113 return 'd';
114 case 'E':
115 return 'e';
116 case 'F':
117 return 'f';
118 case 'G':
119 return 'g';
120 case 'H':
121 return 'h';
122 case 'I':
123 return 'i';
124 case 'J':
125 return 'j';
126 case 'K':
127 return 'k';
128 case 'L':
129 return 'l';
130 case 'M':
131 return 'm';
132 case 'N':
133 return 'n';
134 case 'O':
135 return 'o';
136 case 'P':
137 return 'p';
138 case 'Q':
139 return 'q';
140 case 'R':
141 return 'r';
142 case 'S':
143 return 's';
144 case 'T':
145 return 't';
146 case 'U':
147 return 'u';
148 case 'V':
149 return 'v';
150 case 'W':
151 return 'w';
152 case 'X':
153 return 'x';
154 case 'Y':
155 return 'y';
156 case 'Z':
157 return 'z';
158 }
159 #endif
160
161 return in;
162 }
163
164
165 /*
166 * Curl_strcasecompare() is for doing "raw" case insensitive strings. This is
167 * meant to be locale independent and only compare strings we know are safe
168 * for this. See
169 * https://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for some
170 * further explanation to why this function is necessary.
171 *
172 * The function is capable of comparing a-z case insensitively even for
173 * non-ascii.
174 *
175 * @unittest: 1301
176 */
177
Curl_strcasecompare(const char * first,const char * second)178 int Curl_strcasecompare(const char *first, const char *second)
179 {
180 while(*first && *second) {
181 if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second))
182 /* get out of the loop as soon as they don't match */
183 break;
184 first++;
185 second++;
186 }
187 /* we do the comparison here (possibly again), just to make sure that if the
188 loop above is skipped because one of the strings reached zero, we must not
189 return this as a successful match */
190 return (Curl_raw_toupper(*first) == Curl_raw_toupper(*second));
191 }
192
Curl_safe_strcasecompare(const char * first,const char * second)193 int Curl_safe_strcasecompare(const char *first, const char *second)
194 {
195 if(first && second)
196 /* both pointers point to something then compare them */
197 return Curl_strcasecompare(first, second);
198
199 /* if both pointers are NULL then treat them as equal */
200 return (NULL == first && NULL == second);
201 }
202
203 /*
204 * @unittest: 1301
205 */
Curl_strncasecompare(const char * first,const char * second,size_t max)206 int Curl_strncasecompare(const char *first, const char *second, size_t max)
207 {
208 while(*first && *second && max) {
209 if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second)) {
210 break;
211 }
212 max--;
213 first++;
214 second++;
215 }
216 if(0 == max)
217 return 1; /* they are equal this far */
218
219 return Curl_raw_toupper(*first) == Curl_raw_toupper(*second);
220 }
221
222 /* Copy an upper case version of the string from src to dest. The
223 * strings may overlap. No more than n characters of the string are copied
224 * (including any NUL) and the destination string will NOT be
225 * NUL-terminated if that limit is reached.
226 */
Curl_strntoupper(char * dest,const char * src,size_t n)227 void Curl_strntoupper(char *dest, const char *src, size_t n)
228 {
229 if(n < 1)
230 return;
231
232 do {
233 *dest++ = Curl_raw_toupper(*src);
234 } while(*src++ && --n);
235 }
236
237 /* Copy a lower case version of the string from src to dest. The
238 * strings may overlap. No more than n characters of the string are copied
239 * (including any NUL) and the destination string will NOT be
240 * NUL-terminated if that limit is reached.
241 */
Curl_strntolower(char * dest,const char * src,size_t n)242 void Curl_strntolower(char *dest, const char *src, size_t n)
243 {
244 if(n < 1)
245 return;
246
247 do {
248 *dest++ = Curl_raw_tolower(*src);
249 } while(*src++ && --n);
250 }
251
252 /* --- public functions --- */
253
curl_strequal(const char * first,const char * second)254 int curl_strequal(const char *first, const char *second)
255 {
256 return Curl_strcasecompare(first, second);
257 }
curl_strnequal(const char * first,const char * second,size_t max)258 int curl_strnequal(const char *first, const char *second, size_t max)
259 {
260 return Curl_strncasecompare(first, second, max);
261 }
262