1 /** @file
2
3 A brief file description
4
5 @section license License
6
7 Licensed to the Apache Software Foundation (ASF) under one
8 or more contributor license agreements. See the NOTICE file
9 distributed with this work for additional information
10 regarding copyright ownership. The ASF licenses this file
11 to you under the Apache License, Version 2.0 (the
12 "License"); you may not use this file except in compliance
13 with the License. You may obtain a copy of the License at
14
15 http://www.apache.org/licenses/LICENSE-2.0
16
17 Unless required by applicable law or agreed to in writing, software
18 distributed under the License is distributed on an "AS IS" BASIS,
19 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 See the License for the specific language governing permissions and
21 limitations under the License.
22 */
23
24 /****************************************************************************
25
26 ink_string.h
27
28 String and text processing routines for libts
29
30 ****************************************************************************/
31
32 #pragma once
33
34 #include <cstdio>
35 #include <memory.h>
36 #include <strings.h>
37 #include <string_view>
38
39 #include "tscore/ink_assert.h"
40 #include "tscore/ink_error.h"
41 #include "tscore/ParseRules.h"
42 #include "tscore/ink_apidefs.h"
43
44 /*===========================================================================*
45
46 Function Prototypes
47
48 *===========================================================================*/
49 /* these are supposed to be fast */
50
51 inkcoreapi char *ink_memcpy_until_char(char *dst, char *src, unsigned int n, unsigned char c);
52 inkcoreapi char *ink_string_concatenate_strings(char *dest, ...);
53 inkcoreapi char *ink_string_concatenate_strings_n(char *dest, int n, ...);
54 inkcoreapi char *ink_string_append(char *dest, char *src, int n);
55
56 /*
57 * Copy src to string dst of size siz. At most siz-1 characters
58 * will be copied. Always NUL terminates (unless siz == 0).
59 * Returns strlen(src); if retval >= siz, truncation occurred.
60 */
61 #if HAVE_STRLCPY
62 #define ink_strlcpy strlcpy
63 #else
64 size_t ink_strlcpy(char *dst, const char *str, size_t siz);
65 #endif
66 /*
67 * Appends src to string dst of size siz (unlike strncat, siz is the
68 * full size of dst, not space left). At most siz-1 characters
69 * will be copied. Always NUL terminates (unless siz <= strlen(dst)).
70 * Returns strlen(src) + MIN(siz, strlen(initial dst)).
71 * If retval >= siz, truncation occurred.
72 */
73 #if HAVE_STRLCAT
74 #define ink_strlcat strlcat
75 #else
76 size_t ink_strlcat(char *dst, const char *str, size_t siz);
77 #endif
78
79 /* Convert from UTF-8 to latin-1/iso-8859-1. This can be lossy. */
80 void ink_utf8_to_latin1(const char *in, int inlen, char *out, int *outlen);
81
82 /*===========================================================================*
83
84 Inline Functions
85
86 *===========================================================================*/
87
88 // inline int ptr_len_casecmp(const char* p1, int l1, const char* p2, int l2)
89 //
90 // strcasecmp() functionality for two ptr length pairs
91 //
92 inline int
ptr_len_casecmp(const char * p1,int l1,const char * p2,int l2)93 ptr_len_casecmp(const char *p1, int l1, const char *p2, int l2)
94 {
95 if (l1 < l2) {
96 return -1;
97 } else if (l1 > l2) {
98 return 1;
99 }
100
101 while (l1) {
102 char p1c = ParseRules::ink_tolower(*p1);
103 char p2c = ParseRules::ink_tolower(*p2);
104
105 if (p1c != p2c) {
106 if (p1c > p2c) {
107 return 1;
108 } else {
109 return -1;
110 }
111 }
112
113 p1++;
114 p2++;
115 l1--;
116 }
117
118 return 0;
119 }
120
121 // inline const char* ptr_len_str(const char* p1, int l1, const char* str)
122 //
123 // strstr() like functionality for the ptr, len pairs
124 //
125 inline const char *
ptr_len_str(const char * p1,int l1,const char * str)126 ptr_len_str(const char *p1, int l1, const char *str)
127 {
128 if (str && str[0]) {
129 int str_index = 0;
130 const char *match_start = nullptr;
131
132 while (l1 > 0) {
133 if (*p1 == str[str_index]) {
134 // If this is the start of a match,
135 // record it;
136 if (str_index == 0) {
137 match_start = p1;
138 }
139 // Check to see if we are finished;
140 str_index++;
141 if (str[str_index] == '\0') {
142 return match_start;
143 }
144 } else if (str_index > 0) {
145 l1 += (p1 - match_start);
146 p1 = match_start;
147 str_index = 0;
148 }
149
150 p1++;
151 l1--;
152 }
153 }
154 return nullptr;
155 }
156
157 // int ptr_len_ncmp(const char* p1, int l1, const char* str, int n) {
158 //
159 // strncmp like functionality for comparing a ptr,len pair with
160 // a null terminated string for n chars
161 //
162 inline int
ptr_len_ncmp(const char * p1,int l1,const char * str,int n)163 ptr_len_ncmp(const char *p1, int l1, const char *str, int n)
164 {
165 while (l1 > 0 && n > 0) {
166 if (*str == '\0') {
167 return 1;
168 }
169
170 char p1c = *p1;
171 char strc = *str;
172
173 if (p1c != strc) {
174 if (p1c > strc) {
175 return 1;
176 } else if (p1c < strc) {
177 return -1;
178 }
179 }
180
181 p1++;
182 l1--;
183 n--;
184 str++;
185 }
186
187 // If we've scanned our nchars, the match
188 // otherwise we're here because str is longer
189 // than p1
190
191 if (n == 0) {
192 return 0;
193 } else {
194 return -1;
195 }
196 }
197
198 // int ptr_len_ncasecmp(const char* p1, int l1, const char* str, int n) {
199 //
200 // strncasecmp like functionality for comparing a ptr,len pair with
201 // a null terminated string for n chars
202 //
203 inline int
ptr_len_ncasecmp(const char * p1,int l1,const char * str,int n)204 ptr_len_ncasecmp(const char *p1, int l1, const char *str, int n)
205 {
206 while (l1 > 0 && n > 0) {
207 if (*str == '\0') {
208 return 1;
209 }
210
211 char p1c = ParseRules::ink_tolower(*p1);
212 char strc = ParseRules::ink_tolower(*str);
213
214 if (p1c != strc) {
215 if (p1c > strc) {
216 return 1;
217 } else if (p1c < strc) {
218 return -1;
219 }
220 }
221
222 p1++;
223 l1--;
224 n--;
225 str++;
226 }
227
228 // If we've scanned our nchars, the match
229 // otherwise we're here because str is longer
230 // than p1
231
232 if (n == 0) {
233 return 0;
234 } else {
235 return -1;
236 }
237 }
238
239 // int ptr_len_casecmp(const char* p1, int l1, const char* str) {
240 //
241 // strcasecmp like functionality for comparing a ptr,len pair with
242 // a null terminated string
243 //
244 inline int
ptr_len_casecmp(const char * p1,int l1,const char * str)245 ptr_len_casecmp(const char *p1, int l1, const char *str)
246 {
247 while (l1 > 0) {
248 if (*str == '\0') {
249 return 1;
250 }
251
252 char p1c = ParseRules::ink_tolower(*p1);
253 char strc = ParseRules::ink_tolower(*str);
254
255 if (p1c != strc) {
256 if (p1c > strc) {
257 return 1;
258 } else if (p1c < strc) {
259 return -1;
260 }
261 }
262
263 p1++;
264 l1--;
265 str++;
266 }
267
268 // Since we're out of characters in p1
269 // str needs to be finished for the strings
270 // to get equal
271 if (*str == '\0') {
272 return 0;
273 } else {
274 return -1;
275 }
276 }
277
278 // char* ptr_len_pbrk(const char* p1, int l1, const char* str)
279 //
280 // strpbrk() like functionality for ptr & len pair strings
281 //
282 inline char *
ptr_len_pbrk(const char * p1,int l1,const char * str)283 ptr_len_pbrk(const char *p1, int l1, const char *str)
284 {
285 while (l1 > 0) {
286 const char *str_cur = str;
287
288 while (*str_cur != '\0') {
289 if (*p1 == *str_cur) {
290 return (char *)p1;
291 }
292 str_cur++;
293 }
294
295 p1++;
296 l1--;
297 }
298
299 return nullptr;
300 }
301
302 // Specialized "itoa", that is optimized for small integers, and use snprintf() otherwise.
303 // On error, we'll return 0, and nothing is written to the buffer.
304 // TODO: Do these really need to be inline?
305 inline int
ink_small_itoa(int val,char * buf,int buf_len)306 ink_small_itoa(int val, char *buf, int buf_len)
307 {
308 ink_assert(buf_len > 5);
309 ink_assert((val >= 0) && (val < 100000));
310
311 if (val < 10) { // 0 - 9
312 buf[0] = '0' + val;
313 return 1;
314 } else if (val < 100) { // 10 - 99
315 buf[1] = '0' + (val % 10);
316 val /= 10;
317 buf[0] = '0' + (val % 10);
318 return 2;
319 } else if (val < 1000) { // 100 - 999
320 buf[2] = '0' + (val % 10);
321 val /= 10;
322 buf[1] = '0' + (val % 10);
323 val /= 10;
324 buf[0] = '0' + (val % 10);
325 return 3;
326 } else if (val < 10000) { // 1000 - 9999
327 buf[3] = '0' + (val % 10);
328 val /= 10;
329 buf[2] = '0' + (val % 10);
330 val /= 10;
331 buf[1] = '0' + (val % 10);
332 val /= 10;
333 buf[0] = '0' + (val % 10);
334 return 4;
335 } else { // 10000 - 99999
336 buf[4] = '0' + (val % 10);
337 val /= 10;
338 buf[3] = '0' + (val % 10);
339 val /= 10;
340 buf[2] = '0' + (val % 10);
341 val /= 10;
342 buf[1] = '0' + (val % 10);
343 val /= 10;
344 buf[0] = '0' + (val % 10);
345 return 5;
346 }
347 }
348
349 inline int
ink_fast_itoa(int32_t val,char * buf,int buf_len)350 ink_fast_itoa(int32_t val, char *buf, int buf_len)
351 {
352 if ((val < 0) || (val > 99999)) {
353 int ret = snprintf(buf, buf_len, "%d", val);
354
355 return (ret >= 0 ? ret : 0);
356 }
357
358 return ink_small_itoa((int)val, buf, buf_len);
359 }
360
361 inline int
ink_fast_uitoa(uint32_t val,char * buf,int buf_len)362 ink_fast_uitoa(uint32_t val, char *buf, int buf_len)
363 {
364 if (val > 99999) {
365 int ret = snprintf(buf, buf_len, "%u", val);
366
367 return (ret >= 0 ? ret : 0);
368 }
369
370 return ink_small_itoa((int)val, buf, buf_len);
371 }
372
373 inline int
ink_fast_ltoa(int64_t val,char * buf,int buf_len)374 ink_fast_ltoa(int64_t val, char *buf, int buf_len)
375 {
376 if ((val < 0) || (val > 99999)) {
377 int ret = snprintf(buf, buf_len, "%" PRId64 "", val);
378
379 return (ret >= 0 ? ret : 0);
380 }
381
382 return ink_small_itoa((int)val, buf, buf_len);
383 }
384
385 /// Check for prefix.
386 /// @return @c true if @a lhs is a prefix (ignoring case) of @a rhs.
387 inline bool
IsNoCasePrefixOf(std::string_view const & lhs,std::string_view const & rhs)388 IsNoCasePrefixOf(std::string_view const &lhs, std::string_view const &rhs)
389 {
390 return lhs.size() <= rhs.size() && 0 == strncasecmp(lhs.data(), rhs.data(), lhs.size());
391 }
392
393 /// Check for prefix.
394 /// @return @c true if @a lhs is a prefix of @a rhs.
395 inline bool
IsPrefixOf(std::string_view const & lhs,std::string_view const & rhs)396 IsPrefixOf(std::string_view const &lhs, std::string_view const &rhs)
397 {
398 return lhs.size() <= rhs.size() && 0 == memcmp(lhs.data(), rhs.data(), lhs.size());
399 }
400