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 #pragma once
25 
26 #include <cstring>
27 // I had to move this here, because I really needed to avoid including ink_platform.h in here,
28 // because of a conflict on linux/tcp.h vs netinet/tcp.h.
29 #include <limits.h> // NOLINT(modernize-deprecated-headers)
30 
31 #include "tscore/ink_defs.h"
32 #include "tscore/ink_apidefs.h"
33 
34 typedef unsigned int CTypeResult;
35 
36 // Set this to 0 to disable SI
37 // decimal multipliers
38 #define USE_SI_MULTIPLIERS 1
39 
40 #define is_char_BIT (1 << 0)
41 #define is_upalpha_BIT (1 << 1)
42 #define is_loalpha_BIT (1 << 2)
43 #define is_alpha_BIT (1 << 3)
44 #define is_digit_BIT (1 << 4)
45 #define is_ctl_BIT (1 << 5)
46 #define is_ws_BIT (1 << 6)
47 #define is_hex_BIT (1 << 7)
48 #define is_pchar_BIT (1 << 8)
49 #define is_extra_BIT (1 << 9)
50 #define is_safe_BIT (1 << 10)
51 #define is_unsafe_BIT (1 << 11)
52 #define is_national_BIT (1 << 12)
53 #define is_reserved_BIT (1 << 13)
54 #define is_unreserved_BIT (1 << 14)
55 #define is_punct_BIT (1 << 15)
56 #define is_end_of_url_BIT (1 << 16)
57 #define is_tspecials_BIT (1 << 17)
58 #define is_spcr_BIT (1 << 18)
59 #define is_splf_BIT (1 << 19)
60 #define is_wslfcr_BIT (1 << 20)
61 #define is_eow_BIT (1 << 21)
62 #define is_token_BIT (1 << 22)
63 #define is_uri_BIT (1 << 23)
64 #define is_sep_BIT (1 << 24)
65 #define is_empty_BIT (1 << 25)
66 #define is_alnum_BIT (1 << 26)
67 #define is_space_BIT (1 << 27)
68 #define is_control_BIT (1 << 28)
69 #define is_mime_sep_BIT (1 << 29)
70 #define is_http_field_name_BIT (1 << 30)
71 /* shut up the DEC compiler */
72 #define is_http_field_value_BIT (((CTypeResult)1) << 31)
73 
74 extern ink_undoc_liapi const CTypeResult parseRulesCType[];
75 inkcoreapi extern const char parseRulesCTypeToUpper[];
76 inkcoreapi extern const char parseRulesCTypeToLower[];
77 
78 class ParseRules
79 {
80 public:
81   ParseRules();
82 
83   ////////////////////////////
84   // whitespace definitions //
85   ////////////////////////////
86 
87   enum {
88     CHAR_SP = 32, /* space           */
89     CHAR_HT = 9,  /* horizontal tab  */
90     CHAR_LF = 10, /* line feed       */
91     CHAR_VT = 11, /* vertical tab    */
92     CHAR_NP = 12, /* new page        */
93     CHAR_CR = 13  /* carriage return */
94   };
95 
96   /////////////////////
97   // character tests //
98   /////////////////////
99 
100   static CTypeResult is_type(char c, uint32_t bit);
101 
102   static CTypeResult is_char(char c);             // ASCII 0-127
103   static CTypeResult is_upalpha(char c);          // A-Z
104   static CTypeResult is_loalpha(char c);          // a-z
105   static CTypeResult is_alpha(char c);            // A-Z,a-z
106   static CTypeResult is_digit(char c);            // 0-9
107   static CTypeResult is_ctl(char c);              // ASCII 0-31,127 (includes ws)
108   static CTypeResult is_hex(char c);              // 0-9,A-F,a-f
109   static CTypeResult is_ws(char c);               // SP,HT
110   static CTypeResult is_cr(char c);               // CR
111   static CTypeResult is_lf(char c);               // LF
112   static CTypeResult is_spcr(char c);             // SP,CR
113   static CTypeResult is_splf(char c);             // SP,LF
114   static CTypeResult is_wslfcr(char c);           // SP,HT,LF,CR
115   static CTypeResult is_tspecials(char c);        // HTTP chars that need quoting
116   static CTypeResult is_token(char c);            // token (not CTL or specials)
117   static CTypeResult is_extra(char c);            // !,*,QUOT,(,),COMMA
118   static CTypeResult is_safe(char c);             // [$-_.+]
119   static CTypeResult is_unsafe(char c);           // SP,DBLQUOT,#,%,<,>
120   static CTypeResult is_national(char c);         // {,},|,BACKSLASH,^,~,[,],`
121   static CTypeResult is_reserved(char c);         // :,/,?,:,@,&,=
122   static CTypeResult is_unreserved(char c);       // alpha,digit,safe,extra,nat.
123   static CTypeResult is_punct(char c);            // !"#$%&'()*+,-./:;<>=?@_{}|~
124   static CTypeResult is_end_of_url(char c);       // NUL,CR,SP
125   static CTypeResult is_eow(char c);              // NUL,CR,LF
126   static CTypeResult is_uri(char c);              // A-Z,a-z,0-9 :/?#[]@!$&'()*+,;=-._~%
127   static CTypeResult is_sep(char c);              // nullptr,COMMA,':','!',wslfcr
128   static CTypeResult is_empty(char c);            // wslfcr,#
129   static CTypeResult is_alnum(char c);            // 0-9,A-Z,a-z
130   static CTypeResult is_space(char c);            // ' ' HT,VT,NP,CR,LF
131   static CTypeResult is_control(char c);          // 0-31 127
132   static CTypeResult is_mime_sep(char c);         // ()<>,;\"/[]?{} \t
133   static CTypeResult is_http_field_name(char c);  // not : or mime_sep except for @
134   static CTypeResult is_http_field_value(char c); // not CR, LF, comma, or "
135 
136   //////////////////
137   // string tests //
138   //////////////////
139 
140   static CTypeResult is_escape(const char *seq); // %<hex><hex>
141   static CTypeResult is_uchar(const char *seq);  // starts unreserved or is escape
142   static CTypeResult is_pchar(const char *seq);  // uchar,:,@,&,=,+ (see code)
143 
144   ///////////////////
145   // unimplemented //
146   ///////////////////
147 
148   // static CTypeResult   is_comment(const char * str);
149   // static CTypeResult   is_ctext(const char * str);
150 
151   ////////////////
152   // operations //
153   ////////////////
154 
155   static CTypeResult strncasecmp_eow(const char *s1, const char *s2, int n);
156   static const char *strcasestr(const char *s1, const char *s2);
157   static int strlen_eow(const char *s);
158   static const char *strstr_eow(const char *s1, const char *s2);
159 
160   static char ink_toupper(char c);
161   static char ink_tolower(char c);
162   static const char *memchr(const char *s, char c, int max_length);
163   static const char *strchr(const char *s, char c);
164 
165   // noncopyable
166   ParseRules(const ParseRules &) = delete;
167   ParseRules &operator=(const ParseRules &) = delete;
168 };
169 
170 /* * * * * * * * * * * * * * * * * * * * * * * * * * * *
171  * inline functions definitions
172  * * * * * * * * * * * * * * * * * * * * * * * * * * * */
173 
174 inline CTypeResult
is_type(char c,uint32_t bitmask)175 ParseRules::is_type(char c, uint32_t bitmask)
176 {
177   return (parseRulesCType[(unsigned char)c] & bitmask);
178 }
179 
180 inline CTypeResult
is_char(char c)181 ParseRules::is_char(char c)
182 {
183 #ifndef COMPILE_PARSE_RULES
184   return (parseRulesCType[(unsigned char)c] & is_char_BIT);
185 #else
186   return ((c & 0x80) == 0);
187 #endif
188 }
189 
190 inline CTypeResult
is_upalpha(char c)191 ParseRules::is_upalpha(char c)
192 {
193 #ifndef COMPILE_PARSE_RULES
194   return (parseRulesCType[(unsigned char)c] & is_upalpha_BIT);
195 #else
196   return (c >= 'A' && c <= 'Z');
197 #endif
198 }
199 
200 inline CTypeResult
is_loalpha(char c)201 ParseRules::is_loalpha(char c)
202 {
203 #ifndef COMPILE_PARSE_RULES
204   return (parseRulesCType[(unsigned char)c] & is_loalpha_BIT);
205 #else
206   return (c >= 'a' && c <= 'z');
207 #endif
208 }
209 
210 inline CTypeResult
is_alpha(char c)211 ParseRules::is_alpha(char c)
212 {
213 #ifndef COMPILE_PARSE_RULES
214   return (parseRulesCType[(unsigned char)c] & is_alpha_BIT);
215 #else
216   return (is_upalpha(c) || is_loalpha(c));
217 #endif
218 }
219 
220 inline CTypeResult
is_digit(char c)221 ParseRules::is_digit(char c)
222 {
223 #ifndef COMPILE_PARSE_RULES
224   return (parseRulesCType[(unsigned char)c] & is_digit_BIT);
225 #else
226   return (c >= '0' && c <= '9');
227 #endif
228 }
229 
230 inline CTypeResult
is_alnum(char c)231 ParseRules::is_alnum(char c)
232 {
233 #ifndef COMPILE_PARSE_RULES
234   return (parseRulesCType[(unsigned char)c] & is_alnum_BIT);
235 #else
236   return (is_alpha(c) || is_digit(c));
237 #endif
238 }
239 
240 inline CTypeResult
is_ctl(char c)241 ParseRules::is_ctl(char c)
242 {
243 #ifndef COMPILE_PARSE_RULES
244   return (parseRulesCType[(unsigned char)c] & is_ctl_BIT);
245 #else
246   return ((!(c & 0x80) && c <= 31) || c == 127);
247 #endif
248 }
249 
250 inline CTypeResult
is_ws(char c)251 ParseRules::is_ws(char c)
252 {
253 #ifndef COMPILE_PARSE_RULES
254   return (parseRulesCType[(unsigned char)c] & is_ws_BIT);
255 #else
256   return (c == CHAR_SP || c == CHAR_HT);
257 #endif
258 }
259 
260 inline CTypeResult
is_hex(char c)261 ParseRules::is_hex(char c)
262 {
263 #ifndef COMPILE_PARSE_RULES
264   return (parseRulesCType[(unsigned char)c] & is_hex_BIT);
265 #else
266   return ((c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f') || (c >= '0' && c <= '9'));
267 #endif
268 }
269 
270 inline CTypeResult
is_cr(char c)271 ParseRules::is_cr(char c)
272 {
273   return (c == CHAR_CR);
274 }
275 
276 inline CTypeResult
is_lf(char c)277 ParseRules::is_lf(char c)
278 {
279   return (c == CHAR_LF);
280 }
281 
282 inline CTypeResult
is_splf(char c)283 ParseRules::is_splf(char c)
284 {
285 #ifndef COMPILE_PARSE_RULES
286   return (parseRulesCType[(unsigned char)c] & is_splf_BIT);
287 #else
288   return (c == CHAR_SP || c == CHAR_LF);
289 #endif
290 }
291 
292 inline CTypeResult
is_spcr(char c)293 ParseRules::is_spcr(char c)
294 {
295 #ifndef COMPILE_PARSE_RULES
296   return (parseRulesCType[(unsigned char)c] & is_spcr_BIT);
297 #else
298   return (c == CHAR_SP || c == CHAR_CR);
299 #endif
300 }
301 
302 inline CTypeResult
is_wslfcr(char c)303 ParseRules::is_wslfcr(char c)
304 {
305 #ifndef COMPILE_PARSE_RULES
306   return (parseRulesCType[(unsigned char)c] & is_wslfcr_BIT);
307 #else
308   return ParseRules::is_ws(c) || ParseRules::is_splf(c) || ParseRules::is_spcr(c);
309 #endif
310 }
311 
312 inline CTypeResult
is_extra(char c)313 ParseRules::is_extra(char c)
314 {
315 #ifndef COMPILE_PARSE_RULES
316   return (parseRulesCType[(unsigned char)c] & is_extra_BIT);
317 #else
318   switch (c) {
319   case '!':
320   case '*':
321   case '\'':
322   case '(':
323   case ')':
324   case ',':
325     return (true);
326   }
327   return (false);
328 #endif
329 }
330 
331 inline CTypeResult
is_safe(char c)332 ParseRules::is_safe(char c)
333 {
334 #ifndef COMPILE_PARSE_RULES
335   return (parseRulesCType[(unsigned char)c] & is_safe_BIT);
336 #else
337   return (c == '$' || c == '-' || c == '_' || c == '.' || c == '+');
338 #endif
339 }
340 
341 inline CTypeResult
is_unsafe(char c)342 ParseRules::is_unsafe(char c)
343 {
344 #ifndef COMPILE_PARSE_RULES
345   return (parseRulesCType[(unsigned char)c] & is_unsafe_BIT);
346 #else
347   if (is_ctl(c))
348     return (true);
349 
350   switch (c) {
351   case ' ':
352   case '\"':
353   case '#':
354   case '%':
355   case '<':
356   case '>':
357     return (true);
358   }
359   return (false);
360 #endif
361 }
362 
363 inline CTypeResult
is_reserved(char c)364 ParseRules::is_reserved(char c)
365 {
366 #ifndef COMPILE_PARSE_RULES
367   return (parseRulesCType[(unsigned char)c] & is_reserved_BIT);
368 #else
369   switch (c) {
370   case ';':
371   case '/':
372   case '?':
373   case ':':
374   case '@':
375   case '&':
376   case '=':
377     return (true);
378   }
379   return (false);
380 #endif
381 }
382 
383 inline CTypeResult
is_national(char c)384 ParseRules::is_national(char c)
385 {
386 #ifndef COMPILE_PARSE_RULES
387   return (parseRulesCType[(unsigned char)c] & is_national_BIT);
388 #else
389   switch (c) {
390   case '{':
391   case '}':
392   case '|':
393   case '\\':
394   case '^':
395   case '~':
396   case '[':
397   case ']':
398   case '`':
399     return (true);
400   }
401   return (false);
402 #endif
403 }
404 
405 inline CTypeResult
is_unreserved(char c)406 ParseRules::is_unreserved(char c)
407 {
408 #ifndef COMPILE_PARSE_RULES
409   return (parseRulesCType[(unsigned char)c] & is_unreserved_BIT);
410 #else
411   return (is_alpha(c) || is_digit(c) || is_safe(c) || is_extra(c) || is_national(c));
412 #endif
413 }
414 
415 inline CTypeResult
is_punct(char c)416 ParseRules::is_punct(char c)
417 {
418 #ifndef COMPILE_PARSE_RULES
419   return (parseRulesCType[(unsigned char)c] & is_punct_BIT);
420 #else
421   switch (c) {
422   case '!':
423   case '"':
424   case '#':
425   case '%':
426   case '&':
427   case '\'':
428   case '(':
429   case ')':
430   case '*':
431   case '+':
432   case ',':
433   case '-':
434   case '.':
435   case '/':
436   case ':':
437   case ';':
438   case '<':
439   case '=':
440   case '>':
441   case '?':
442   case '@':
443   case '[':
444   case '\\':
445   case ']':
446   case '^':
447   case '_':
448   case '`':
449   case '{':
450   case '|':
451   case '}':
452   case '~':
453     return (true);
454   }
455   return (false);
456 #endif
457 }
458 
459 inline CTypeResult
is_end_of_url(char c)460 ParseRules::is_end_of_url(char c)
461 {
462 #ifndef COMPILE_PARSE_RULES
463   return (parseRulesCType[(unsigned char)c] & is_end_of_url_BIT);
464 #else
465   return (c == '\0' || c == '\n' || c == ' ' || ParseRules::is_ctl(c));
466 #endif
467 }
468 
469 inline CTypeResult
is_escape(const char * seq)470 ParseRules::is_escape(const char *seq)
471 {
472   return (seq[0] == '%' && is_hex(seq[1]) && is_hex(seq[2]));
473 }
474 
475 inline CTypeResult
is_uchar(const char * seq)476 ParseRules::is_uchar(const char *seq)
477 {
478   return (is_unreserved(seq[0]) || is_escape(seq));
479 }
480 
481 //
482 // have to cheat on this one
483 //
484 inline CTypeResult
is_pchar(const char * seq)485 ParseRules::is_pchar(const char *seq)
486 {
487 #ifndef COMPILE_PARSE_RULES
488   if (*seq != '%')
489     return (parseRulesCType[(uint8_t)*seq] & is_pchar_BIT);
490   else
491     return is_hex(seq[1]) && is_hex(seq[2]);
492 #else
493   if (is_unreserved(*seq))
494     return (true);
495 
496   switch (seq[0]) {
497   case ':':
498   case '@':
499   case '&':
500   case '=':
501   case '+':
502     return (true);
503   }
504   return (false);
505 #endif
506 }
507 
508 inline CTypeResult
is_tspecials(char c)509 ParseRules::is_tspecials(char c)
510 {
511 #ifndef COMPILE_PARSE_RULES
512   return (parseRulesCType[(unsigned char)c] & is_tspecials_BIT);
513 #else
514   switch (c) {
515   case '(':
516   case ')':
517   case '<':
518   case '>':
519   case '@':
520   case ',':
521   case ';':
522   case ':':
523   case '\\':
524   case '"':
525   case '/':
526   case '[':
527   case ']':
528   case '?':
529   case '=':
530   case '{':
531   case '}':
532   case CHAR_SP:
533   case CHAR_HT:
534     return (true);
535   }
536   return (false);
537 #endif
538 }
539 
540 inline CTypeResult
is_token(char c)541 ParseRules::is_token(char c)
542 {
543 #ifndef COMPILE_PARSE_RULES
544   return (parseRulesCType[(unsigned char)c] & is_token_BIT);
545 #else
546   return (is_char(c) && !(is_ctl(c) || is_tspecials(c)));
547 #endif
548 }
549 
550 inline char
ink_toupper(char c)551 ParseRules::ink_toupper(char c)
552 {
553 #ifndef COMPILE_PARSE_RULES
554   return parseRulesCTypeToUpper[(unsigned char)c];
555 #else
556   int up_case            = c;
557   const int up_case_diff = 'a' - 'A';
558 
559   if (c >= 'a' && c <= 'z') {
560     up_case = c - up_case_diff;
561   }
562   return (up_case);
563 #endif
564 }
565 
566 inline char
ink_tolower(char c)567 ParseRules::ink_tolower(char c)
568 {
569 #ifndef COMPILE_PARSE_RULES
570   return parseRulesCTypeToLower[(unsigned char)c];
571 #else
572   int lo_case            = c;
573   const int lo_case_diff = 'a' - 'A';
574 
575   if (c >= 'A' && c <= 'Z') {
576     lo_case = c + lo_case_diff;
577   }
578   return (lo_case);
579 #endif
580 }
581 
582 inline CTypeResult
is_eow(char c)583 ParseRules::is_eow(char c)
584 {
585 #ifndef COMPILE_PARSE_RULES
586   return (parseRulesCType[(unsigned char)c] & is_eow_BIT);
587 #else
588   return (c == '\0' || c == '\r' || c == '\n');
589 #endif
590 }
591 
592 inline CTypeResult
is_uri(char c)593 ParseRules::is_uri(char c)
594 {
595 #ifndef COMPILE_PARSE_RULES
596   return (parseRulesCType[(unsigned char)c] & is_uri_BIT);
597 #else
598   if (is_alnum(c))
599     return (true);
600 
601   switch (c) {
602   case ':':
603   case '/':
604   case '?':
605   case '#':
606   case '[':
607   case ']':
608   case '@':
609   case '!':
610   case '$':
611   case '&':
612   case '\'':
613   case '(':
614   case ')':
615   case '*':
616   case '+':
617   case ',':
618   case ';':
619   case '=':
620   case '-':
621   case '.':
622   case '_':
623   case '~':
624   case '%':
625     return (true);
626   }
627   return (false);
628 #endif
629 }
630 
631 inline CTypeResult
is_sep(char c)632 ParseRules::is_sep(char c)
633 {
634 #ifndef COMPILE_PARSE_RULES
635   return (parseRulesCType[(unsigned char)c] & is_sep_BIT);
636 #else
637   return (!c || c == ',' || c == ':' || c == '!' || is_wslfcr(c));
638 #endif
639 }
640 
641 inline CTypeResult
is_empty(char c)642 ParseRules::is_empty(char c)
643 {
644 #ifndef COMPILE_PARSE_RULES
645   return (parseRulesCType[(unsigned char)c] & is_empty_BIT);
646 #else
647   return (c == '#' || is_wslfcr(c));
648 #endif
649 }
650 
651 inline CTypeResult
is_space(char c)652 ParseRules::is_space(char c)
653 {
654 #ifndef COMPILE_PARSE_RULES
655   return (parseRulesCType[(unsigned char)c] & is_space_BIT);
656 #else
657   switch (c) {
658   case CHAR_SP:
659   case CHAR_HT:
660   case CHAR_LF:
661   case CHAR_VT:
662   case CHAR_NP:
663   case CHAR_CR:
664     return (true);
665   }
666   return (false);
667 #endif
668 }
669 
670 inline CTypeResult
is_control(char c)671 ParseRules::is_control(char c)
672 {
673 #ifndef COMPILE_PARSE_RULES
674   return (parseRulesCType[(unsigned char)c] & is_control_BIT);
675 #else
676   if (((unsigned char)c) < 32 || ((unsigned char)c) == 127)
677     return true;
678   return false;
679 #endif
680 }
681 
682 inline CTypeResult
is_mime_sep(char c)683 ParseRules::is_mime_sep(char c)
684 {
685 #ifndef COMPILE_PARSE_RULES
686   return (parseRulesCType[(unsigned char)c] & is_mime_sep_BIT);
687 #else
688   if ((c == '(') || (c == ')') || (c == '<') || (c == '>') || (c == '@') || (c == ',') || (c == ';') || (c == '\\') ||
689       (c == '\"') || (c == '/') || (c == '[') || (c == ']') || (c == '?') || (c == '{') || (c == '}') || (c == ' ') || (c == '\t'))
690     return true;
691   return false;
692 #endif
693 }
694 
695 inline CTypeResult
is_http_field_name(char c)696 ParseRules::is_http_field_name(char c)
697 {
698 #ifndef COMPILE_PARSE_RULES
699   return (parseRulesCType[(unsigned char)c] & is_http_field_name_BIT);
700 #else
701   if ((c == ':') || (is_mime_sep(c) && (c != '@')))
702     return false;
703   return true;
704 #endif
705 }
706 
707 inline CTypeResult
is_http_field_value(char c)708 ParseRules::is_http_field_value(char c)
709 {
710 #ifndef COMPILE_PARSE_RULES
711   return (CTypeResult)(parseRulesCType[(unsigned char)c] & is_http_field_value_BIT);
712 #else
713   switch (c) {
714   case CHAR_CR:
715   case CHAR_LF:
716   case '\"':
717   case ',':
718     return false;
719   }
720   return true;
721 #endif
722 }
723 
724 //////////////////////////////////////////////////////////////////////////////
725 //
726 //      inline CTypeResult ParseRules::strncasecmp_eol(s1, s2, count)
727 //
728 //      This wacky little function compares if two strings <s1> and <s2> match
729 //      (case-insensitively) up to <count> characters long, stopping not only
730 //      at the end of string ('\0'), but also at end of line (CR or LF).
731 //
732 //////////////////////////////////////////////////////////////////////////////
733 
734 inline CTypeResult
strncasecmp_eow(const char * s1,const char * s2,int count)735 ParseRules::strncasecmp_eow(const char *s1, const char *s2, int count)
736 {
737   for (int i = 0; i < count; i++) {
738     const char &a = s1[i];
739     const char &b = s2[i];
740 
741     ///////////////////////////////////////////////////////////////
742     // if they are different; only match if both are terminators //
743     ///////////////////////////////////////////////////////////////
744     if (ink_tolower(a) != ink_tolower(b))
745       return (is_eow(a) && is_eow(b));
746   }
747   return (true);
748 }
749 
750 //////////////////////////////////////////////////////////////////////////////
751 //
752 //  strlen_eow()
753 //
754 //  return the length of a string
755 //////////////////////////////////////////////////////////////////////////////
756 inline int
strlen_eow(const char * s)757 ParseRules::strlen_eow(const char *s)
758 {
759   for (int i = 0; true; i++) {
760     if (is_eow(s[i]))
761       return (i);
762   }
763 }
764 
765 //////////////////////////////////////////////////////////////////////////////
766 //
767 //  strstr_eow()
768 //
769 //  This function is the same as strstr(), except that it accepts strings
770 //  that are terminated with '\r', '\n' or null.
771 //  It returns a pointer to the first occurrence of s2 within s1 (or null).
772 //////////////////////////////////////////////////////////////////////////////
773 inline const char *
strstr_eow(const char * s1,const char * s2)774 ParseRules::strstr_eow(const char *s1, const char *s2)
775 {
776   int i1;
777 
778   int s2_len = strlen_eow(s2);
779 
780   for (i1 = 0; !is_eow(s1[i1]); i1++)
781     if (ink_tolower(s1[i1]) == ink_tolower(s2[0]))
782       if (strncasecmp_eow(&s1[i1], &s2[0], s2_len))
783         return (&s1[i1]);
784 
785   return (nullptr);
786 }
787 
788 inline const char *
strcasestr(const char * s1,const char * s2)789 ParseRules::strcasestr(const char *s1, const char *s2)
790 {
791   int i1;
792 
793   size_t s2_len = strlen(s2);
794 
795   for (i1 = 0; s1[i1] != '\0'; i1++)
796     if (ink_tolower(s1[i1]) == ink_tolower(s2[0]))
797       if (strncasecmp_eow(&s1[i1], &s2[0], (int)s2_len))
798         return (&s1[i1]);
799 
800   return (nullptr);
801 }
802 
803 inline const char *
memchr(const char * s,char c,int max_length)804 ParseRules::memchr(const char *s, char c, int max_length)
805 {
806   for (int i = 0; i < max_length; i++)
807     if (s[i] == c)
808       return (&s[i]);
809   return (nullptr);
810 }
811 
812 inline const char *
strchr(const char * s,char c)813 ParseRules::strchr(const char *s, char c)
814 {
815   for (int i = 0; s[i] != '\0'; i++)
816     if (s[i] == c)
817       return (&s[i]);
818   return (nullptr);
819 }
820 
821 static inline int
ink_get_hex(char c)822 ink_get_hex(char c)
823 {
824   if (ParseRules::is_digit(c))
825     return (int)(c - '0');
826   c = ParseRules::ink_tolower(c);
827   return (int)((c - 'a') + 10);
828 }
829 
830 int64_t ink_atoi64(const char *, const char **end = nullptr);
831 uint64_t ink_atoui64(const char *);
832 int64_t ink_atoi64(const char *, int);
833 
834 static inline int
ink_atoi(const char * str)835 ink_atoi(const char *str)
836 {
837   int64_t val = ink_atoi64(str);
838 
839   if (val > INT_MAX)
840     return INT_MAX;
841   else if (val < INT_MIN)
842     return INT_MIN;
843   else
844     return static_cast<int>(val);
845 }
846 
847 static inline int
ink_atoi(const char * str,int len)848 ink_atoi(const char *str, int len)
849 {
850   int64_t val = ink_atoi64(str, len);
851 
852   if (val > INT_MAX)
853     return INT_MAX;
854   else if (val < INT_MIN)
855     return INT_MIN;
856   else
857     return static_cast<int>(val);
858 }
859 
860 static inline unsigned int
ink_atoui(const char * str)861 ink_atoui(const char *str)
862 {
863   uint64_t val = ink_atoui64(str);
864 
865   if (val > INT_MAX)
866     return INT_MAX;
867   else
868     return static_cast<int>(val);
869 }
870