GNU libmicrohttpd  0.9.75
mhd_str.c
Go to the documentation of this file.
1 /*
2  This file is part of libmicrohttpd
3  Copyright (C) 2015, 2016 Karlson2k (Evgeny Grin)
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Lesser General Public
7  License as published by the Free Software Foundation; either
8  version 2.1 of the License, or (at your option) any later version.
9 
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Lesser General Public License for more details.
14 
15  You should have received a copy of the GNU Lesser General Public
16  License along with this library; if not, write to the Free Software
17  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19 
26 #include "mhd_str.h"
27 
28 #ifdef HAVE_STDBOOL_H
29 #include <stdbool.h>
30 #endif /* HAVE_STDBOOL_H */
31 #include <string.h>
32 
33 #include "mhd_assert.h"
34 #include "mhd_limits.h"
35 #include "mhd_assert.h"
36 
37 #ifdef MHD_FAVOR_SMALL_CODE
38 #ifdef _MHD_static_inline
39 #undef _MHD_static_inline
40 #endif /* _MHD_static_inline */
41 /* Do not force inlining and do not use macro functions, use normal static
42  functions instead.
43  This may give more flexibility for size optimizations. */
44 #define _MHD_static_inline static
45 #ifndef INLINE_FUNC
46 #define INLINE_FUNC 1
47 #endif /* !INLINE_FUNC */
48 #endif /* MHD_FAVOR_SMALL_CODE */
49 
50 /*
51  * Block of functions/macros that use US-ASCII charset as required by HTTP
52  * standards. Not affected by current locale settings.
53  */
54 
55 #ifdef INLINE_FUNC
56 
57 #if 0 /* Disable unused functions. */
64 _MHD_static_inline bool
65 isasciilower (char c)
66 {
67  return (c >= 'a') && (c <= 'z');
68 }
69 
70 
71 #endif /* Disable unused functions. */
72 
73 
80 _MHD_static_inline bool
81 isasciiupper (char c)
82 {
83  return (c >= 'A') && (c <= 'Z');
84 }
85 
86 
87 #if 0 /* Disable unused functions. */
94 _MHD_static_inline bool
95 isasciialpha (char c)
96 {
97  return isasciilower (c) || isasciiupper (c);
98 }
99 
100 
101 #endif /* Disable unused functions. */
102 
103 
110 _MHD_static_inline bool
111 isasciidigit (char c)
112 {
113  return (c >= '0') && (c <= '9');
114 }
115 
116 
117 #if 0 /* Disable unused functions. */
124 _MHD_static_inline bool
125 isasciixdigit (char c)
126 {
127  return isasciidigit (c) ||
128  ( (c >= 'A') && (c <= 'F') ) ||
129  ( (c >= 'a') && (c <= 'f') );
130 }
131 
132 
139 _MHD_static_inline bool
140 isasciialnum (char c)
141 {
142  return isasciialpha (c) || isasciidigit (c);
143 }
144 
145 
146 #endif /* Disable unused functions. */
147 
148 
149 #if 0 /* Disable unused functions. */
159 _MHD_static_inline char
160 toasciilower (char c)
161 {
162  return isasciiupper (c) ? (c - 'A' + 'a') : c;
163 }
164 
165 
175 _MHD_static_inline char
176 toasciiupper (char c)
177 {
178  return isasciilower (c) ? (c - 'a' + 'A') : c;
179 }
180 
181 
182 #endif /* Disable unused functions. */
183 
184 
185 #if defined(MHD_FAVOR_SMALL_CODE) /* Used only in MHD_str_to_uvalue_n_() */
192 _MHD_static_inline int
193 todigitvalue (char c)
194 {
195  if (isasciidigit (c))
196  return (unsigned char) (c - '0');
197 
198  return -1;
199 }
200 
201 
202 #endif /* MHD_FAVOR_SMALL_CODE */
203 
204 
211 _MHD_static_inline int
212 toxdigitvalue (char c)
213 {
214  if (isasciidigit (c))
215  return (unsigned char) (c - '0');
216  if ( (c >= 'A') && (c <= 'F') )
217  return (unsigned char) (c - 'A' + 10);
218  if ( (c >= 'a') && (c <= 'f') )
219  return (unsigned char) (c - 'a' + 10);
220 
221  return -1;
222 }
223 
224 
232 _MHD_static_inline bool
233 charsequalcaseless (const char c1, const char c2)
234 {
235  return ( (c1 == c2) ||
236  (isasciiupper (c1) ?
237  ((c1 - 'A' + 'a') == c2) :
238  ((c1 == (c2 - 'A' + 'a')) && isasciiupper (c2))) );
239 }
240 
241 
242 #else /* !INLINE_FUNC */
243 
244 
252 #define isasciilower(c) (((char) (c)) >= 'a' && ((char) (c)) <= 'z')
253 
254 
262 #define isasciiupper(c) (((char) (c)) >= 'A' && ((char) (c)) <= 'Z')
263 
264 
272 #define isasciialpha(c) (isasciilower (c) || isasciiupper (c))
273 
274 
282 #define isasciidigit(c) (((char) (c)) >= '0' && ((char) (c)) <= '9')
283 
284 
292 #define isasciixdigit(c) (isasciidigit ((c)) || \
293  (((char) (c)) >= 'A' && ((char) (c)) <= 'F') || \
294  (((char) (c)) >= 'a' && ((char) (c)) <= 'f') )
295 
296 
304 #define isasciialnum(c) (isasciialpha (c) || isasciidigit (c))
305 
306 
316 #define toasciilower(c) ((isasciiupper (c)) ? (((char) (c)) - 'A' + 'a') : \
317  ((char) (c)))
318 
319 
329 #define toasciiupper(c) ((isasciilower (c)) ? (((char) (c)) - 'a' + 'A') : \
330  ((char) (c)))
331 
332 
339 #define todigitvalue(c) (isasciidigit (c) ? (int) (((char) (c)) - '0') : \
340  (int) (-1))
341 
342 
348 #define toxdigitvalue(c) (isasciidigit (c) ? (int) (((char) (c)) - '0') : \
349  ( (((char) (c)) >= 'A' && ((char) (c)) <= 'F') ? \
350  (int) (((unsigned char) (c)) - 'A' + 10) : \
351  ( (((char) (c)) >= 'a' && ((char) (c)) <= 'f') ? \
352  (int) (((unsigned char) (c)) - 'a' + 10) : \
353  (int) (-1) )))
354 
362 #define charsequalcaseless(c1, c2) \
363  ( ((c1) == (c2)) || \
364  (isasciiupper (c1) ? \
365  (((c1) - 'A' + 'a') == (c2)) : \
366  (((c1) == ((c2) - 'A' + 'a')) && isasciiupper (c2))) )
367 
368 #endif /* !INLINE_FUNC */
369 
370 
371 #ifndef MHD_FAVOR_SMALL_CODE
379 int
380 MHD_str_equal_caseless_ (const char *str1,
381  const char *str2)
382 {
383  while (0 != (*str1))
384  {
385  const char c1 = *str1;
386  const char c2 = *str2;
387  if (charsequalcaseless (c1, c2))
388  {
389  str1++;
390  str2++;
391  }
392  else
393  return 0;
394  }
395  return 0 == (*str2);
396 }
397 
398 
399 #endif /* ! MHD_FAVOR_SMALL_CODE */
400 
401 
413 int
414 MHD_str_equal_caseless_n_ (const char *const str1,
415  const char *const str2,
416  size_t maxlen)
417 {
418  size_t i;
419 
420  for (i = 0; i < maxlen; ++i)
421  {
422  const char c1 = str1[i];
423  const char c2 = str2[i];
424  if (0 == c2)
425  return 0 == c1;
426  if (charsequalcaseless (c1, c2))
427  continue;
428  else
429  return 0;
430  }
431  return ! 0;
432 }
433 
434 
444 bool
445 MHD_str_equal_caseless_bin_n_ (const char *const str1,
446  const char *const str2,
447  size_t len)
448 {
449  size_t i;
450 
451  for (i = 0; i < len; ++i)
452  {
453  const char c1 = str1[i];
454  const char c2 = str2[i];
455  if (charsequalcaseless (c1, c2))
456  continue;
457  else
458  return 0;
459  }
460  return ! 0;
461 }
462 
463 
477 bool
479  const char *const token,
480  size_t token_len)
481 {
482  if (0 == token_len)
483  return false;
484 
485  while (0 != *str)
486  {
487  size_t i;
488  /* Skip all whitespaces and empty tokens. */
489  while (' ' == *str || '\t' == *str || ',' == *str)
490  str++;
491 
492  /* Check for token match. */
493  i = 0;
494  while (1)
495  {
496  const char sc = *(str++);
497  const char tc = token[i++];
498 
499  if (0 == sc)
500  return false;
501  if (! charsequalcaseless (sc, tc))
502  break;
503  if (i >= token_len)
504  {
505  /* Check whether substring match token fully or
506  * has additional unmatched chars at tail. */
507  while (' ' == *str || '\t' == *str)
508  str++;
509  /* End of (sub)string? */
510  if ((0 == *str) || (',' == *str) )
511  return true;
512  /* Unmatched chars at end of substring. */
513  break;
514  }
515  }
516  /* Find next substring. */
517  while (0 != *str && ',' != *str)
518  str++;
519  }
520  return false;
521 }
522 
523 
552 bool
554  size_t str_len,
555  const char *const token,
556  const size_t token_len,
557  char *buf,
558  ssize_t *buf_size)
559 {
560  const char *s1;
561  char *s2;
562  size_t t_pos;
563  bool token_removed;
564 
565  mhd_assert (NULL == memchr (token, 0, token_len));
566  mhd_assert (NULL == memchr (token, ' ', token_len));
567  mhd_assert (NULL == memchr (token, '\t', token_len));
568  mhd_assert (NULL == memchr (token, ',', token_len));
569  mhd_assert (0 <= *buf_size);
570 
571  s1 = str;
572  s2 = buf;
573  token_removed = false;
574 
575  while ((size_t) (s1 - str) < str_len)
576  {
577  const char *cur_token;
578  size_t copy_size;
579 
580  /* Skip any initial whitespaces and empty tokens */
581  while ( ((size_t) (s1 - str) < str_len) &&
582  ((' ' == *s1) || ('\t' == *s1) || (',' == *s1)) )
583  s1++;
584 
585  /* 's1' points to the first char of token in the input string or
586  * points just beyond the end of the input string */
587 
588  if ((size_t) (s1 - str) >= str_len)
589  break; /* Nothing to copy, end of the input string */
590 
591  /* 's1' points to the first char of token in the input string */
592 
593  cur_token = s1; /* the first char of input token */
594 
595  /* Check the token with case-insensetive match */
596  t_pos = 0;
597  while ( ((size_t) (s1 - str) < str_len) && (token_len > t_pos) &&
598  (charsequalcaseless (*s1, token[t_pos])) )
599  {
600  s1++;
601  t_pos++;
602  }
603  /* s1 may point just beyond the end of the input string */
604  if ( (token_len == t_pos) && (0 != token_len) )
605  {
606  /* 'token' matched, check that current input token does not have
607  * any suffixes */
608  while ( ((size_t) (s1 - str) < str_len) &&
609  ((' ' == *s1) || ('\t' == *s1)) )
610  s1++;
611  /* 's1' points to the first non-whitespace char after the token matched
612  * requested token or points just beyond the end of the input string after
613  * the requested token */
614  if (((size_t) (s1 - str) == str_len) || (',' == *s1))
615  {/* full token match, do not copy current token to the output */
616  token_removed = true;
617  continue;
618  }
619  }
620 
621  /* 's1' points to first non-whitespace char, to some char after
622  * first non-whitespace char in the token in the input string, to
623  * the ',', or just beyond the end of the input string */
624  /* The current token in the input string does not match the token
625  * to exclude, it must be copied to the output string */
626  /* the current token size excluding leading whitespaces and current char */
627  copy_size = (size_t) (s1 - cur_token);
628  if (buf == s2)
629  { /* The first token to copy to the output */
630  if (buf + *buf_size < s2 + copy_size)
631  { /* Not enough space in the output buffer */
632  *buf_size = (ssize_t) -1;
633  return false;
634  }
635  }
636  else
637  { /* Some token was already copied to the output buffer */
638  if (buf + *buf_size < s2 + copy_size + 2)
639  { /* Not enough space in the output buffer */
640  *buf_size = (ssize_t) -1;
641  return false;
642  }
643  *(s2++) = ',';
644  *(s2++) = ' ';
645  }
646  /* Copy non-matched token to the output */
647  if (0 != copy_size)
648  {
649  memcpy (s2, cur_token, copy_size);
650  s2 += copy_size;
651  }
652 
653  while ( ((size_t) (s1 - str) < str_len) && (',' != *s1))
654  {
655  /* 's1' points to first non-whitespace char, to some char after
656  * first non-whitespace char in the token in the input string */
657  /* Copy all non-whitespace chars from the current token in
658  * the input string */
659  while ( ((size_t) (s1 - str) < str_len) &&
660  (',' != *s1) && (' ' != *s1) && ('\t' != *s1) )
661  {
662  if (buf + *buf_size <= s2) /* '<= s2' equals '< s2 + 1' */
663  { /* Not enough space in the output buffer */
664  *buf_size = (ssize_t) -1;
665  return false;
666  }
667  *(s2++) = *(s1++);
668  }
669  /* 's1' points to some whitespace char in the token in the input
670  * string, to the ',', or just beyond the end of the input string */
671  /* Skip all whitespaces */
672  while ( ((size_t) (s1 - str) < str_len) &&
673  ((' ' == *s1) || ('\t' == *s1)) )
674  s1++;
675 
676  /* 's1' points to the first non-whitespace char in the input string
677  * after whitespace chars, to the ',', or just beyond the end of
678  * the input string */
679  if (((size_t) (s1 - str) < str_len) && (',' != *s1))
680  { /* Not the end of the current token */
681  if (buf + *buf_size <= s2) /* '<= s2' equals '< s2 + 1' */
682  { /* Not enough space in the output buffer */
683  *buf_size = (ssize_t) -1;
684  return false;
685  }
686  *(s2++) = ' ';
687  }
688  }
689  }
690  mhd_assert (((ssize_t) (s2 - buf)) <= *buf_size);
691  *buf_size = (ssize_t) (s2 - buf);
692  return token_removed;
693 }
694 
695 
719 bool
721  size_t *str_len,
722  const char *const tokens,
723  const size_t tokens_len)
724 {
725  const char *const t = tokens;
726  size_t pt;
727  bool token_removed;
728 
729  mhd_assert (NULL == memchr (tokens, 0, tokens_len));
730 
731  token_removed = false;
732  pt = 0;
733 
734  while (pt < tokens_len && *str_len != 0)
735  {
736  const char *tkn;
737  size_t tkn_len;
738 
739  /* Skip any initial whitespaces and empty tokens in 'tokens' */
740  while ( (pt < tokens_len) &&
741  ((' ' == t[pt]) || ('\t' == t[pt]) || (',' == t[pt])) )
742  pt++;
743 
744  if (pt >= tokens_len)
745  break; /* No more tokens, nothing to remove */
746 
747  /* Found non-whitespace char which is not a comma */
748  tkn = t + pt;
749  do
750  {
751  do
752  {
753  pt++;
754  } while (pt < tokens_len &&
755  (' ' != t[pt] && '\t' != t[pt] && ',' != t[pt]));
756  /* Found end of the token string, space, tab, or comma */
757  tkn_len = pt - (size_t) (tkn - t);
758 
759  /* Skip all spaces and tabs */
760  while (pt < tokens_len && (' ' == t[pt] || '\t' == t[pt]))
761  pt++;
762  /* Found end of the token string or non-whitespace char */
763  } while(pt < tokens_len && ',' != t[pt]);
764 
765  /* 'tkn' is the input token with 'tkn_len' chars */
766  mhd_assert (0 != tkn_len);
767 
768  if (*str_len == tkn_len)
769  {
770  if (MHD_str_equal_caseless_bin_n_ (str, tkn, tkn_len))
771  {
772  *str_len = 0;
773  token_removed = true;
774  }
775  continue;
776  }
777  /* 'tkn' cannot match part of 'str' if length of 'tkn' is larger
778  * than length of 'str'.
779  * It's know that 'tkn' is not equal to the 'str' (was checked previously).
780  * As 'str' is normalized when 'tkn' is not equal to the 'str'
781  * it is required that 'str' to be at least 3 chars larger then 'tkn'
782  * (the comma, the space and at least one additional character for the next
783  * token) to remove 'tkn' from the 'str'. */
784  if (*str_len > tkn_len + 2)
785  { /* Remove 'tkn' from the input string */
786  size_t pr;
787  size_t pw;
789  pr = 0;
790  pw = 0;
791 
792  do
793  {
794  mhd_assert (pr >= pw);
795  mhd_assert ((*str_len) >= (pr + tkn_len));
796  if ( ( ((*str_len) == (pr + tkn_len)) || (',' == str[pr + tkn_len]) ) &&
797  MHD_str_equal_caseless_bin_n_ (str + pr, tkn, tkn_len) )
798  {
799  /* current token in the input string matches the 'tkn', skip it */
800  mhd_assert ((*str_len == pr + tkn_len) || \
801  (' ' == str[pr + tkn_len + 1])); /* 'str' must be normalized */
802  token_removed = true;
803  /* Advance to the next token in the input string or beyond
804  * the end of the input string. */
805  pr += tkn_len + 2;
806  }
807  else
808  {
809  /* current token in the input string does not match the 'tkn',
810  * copy to the output */
811  if (0 != pw)
812  { /* not the first output token, add ", " to separate */
813  if (pr != pw + 2)
814  {
815  str[pw++] = ',';
816  str[pw++] = ' ';
817  }
818  else
819  pw += 2; /* 'str' is not yet modified in this round */
820  }
821  do
822  {
823  if (pr != pw)
824  str[pw] = str[pr];
825  pr++;
826  pw++;
827  } while (pr < *str_len && ',' != str[pr]);
828  /* Advance to the next token in the input string or beyond
829  * the end of the input string. */
830  pr += 2;
831  }
832  /* 'pr' should point to the next token in the input string or beyond
833  * the end of the input string */
834  if ((*str_len) < (pr + tkn_len))
835  { /* The rest of the 'str + pr' is too small to match 'tkn' */
836  if ((*str_len) > pr)
837  { /* Copy the rest of the string */
838  size_t copy_size;
839  copy_size = *str_len - pr;
840  if (0 != pw)
841  { /* not the first output token, add ", " to separate */
842  if (pr != pw + 2)
843  {
844  str[pw++] = ',';
845  str[pw++] = ' ';
846  }
847  else
848  pw += 2; /* 'str' is not yet modified in this round */
849  }
850  if (pr != pw)
851  memmove (str + pw, str + pr, copy_size);
852  pw += copy_size;
853  }
854  *str_len = pw;
855  break;
856  }
857  mhd_assert ((' ' != str[0]) && ('\t' != str[0]));
858  mhd_assert ((0 == pr) || (3 <= pr));
859  mhd_assert ((0 == pr) || (' ' == str[pr - 1]));
860  mhd_assert ((0 == pr) || (',' == str[pr - 2]));
861  } while (1);
862  }
863  }
864 
865  return token_removed;
866 }
867 
868 
869 #ifndef MHD_FAVOR_SMALL_CODE
870 /* Use individual function for each case */
871 
882 size_t
883 MHD_str_to_uint64_ (const char *str,
884  uint64_t *out_val)
885 {
886  const char *const start = str;
887  uint64_t res;
888 
889  if (! str || ! out_val || ! isasciidigit (str[0]))
890  return 0;
891 
892  res = 0;
893  do
894  {
895  const int digit = (unsigned char) (*str) - '0';
896  if ( (res > (UINT64_MAX / 10)) ||
897  ( (res == (UINT64_MAX / 10)) &&
898  ((uint64_t) digit > (UINT64_MAX % 10)) ) )
899  return 0;
900 
901  res *= 10;
902  res += digit;
903  str++;
904  } while (isasciidigit (*str));
905 
906  *out_val = res;
907  return str - start;
908 }
909 
910 
924 size_t
925 MHD_str_to_uint64_n_ (const char *str,
926  size_t maxlen,
927  uint64_t *out_val)
928 {
929  uint64_t res;
930  size_t i;
931 
932  if (! str || ! maxlen || ! out_val || ! isasciidigit (str[0]))
933  return 0;
934 
935  res = 0;
936  i = 0;
937  do
938  {
939  const int digit = (unsigned char) str[i] - '0';
940 
941  if ( (res > (UINT64_MAX / 10)) ||
942  ( (res == (UINT64_MAX / 10)) &&
943  ((uint64_t) digit > (UINT64_MAX % 10)) ) )
944  return 0;
945 
946  res *= 10;
947  res += digit;
948  i++;
949  } while ( (i < maxlen) &&
950  isasciidigit (str[i]) );
951 
952  *out_val = res;
953  return i;
954 }
955 
956 
967 size_t
968 MHD_strx_to_uint32_ (const char *str,
969  uint32_t *out_val)
970 {
971  const char *const start = str;
972  uint32_t res;
973  int digit;
974 
975  if (! str || ! out_val)
976  return 0;
977 
978  res = 0;
979  digit = toxdigitvalue (*str);
980  while (digit >= 0)
981  {
982  if ( (res < (UINT32_MAX / 16)) ||
983  ((res == (UINT32_MAX / 16)) && ( (uint32_t) digit <= (UINT32_MAX
984  % 16)) ) )
985  {
986  res *= 16;
987  res += digit;
988  }
989  else
990  return 0;
991  str++;
992  digit = toxdigitvalue (*str);
993  }
994 
995  if (str - start > 0)
996  *out_val = res;
997  return str - start;
998 }
999 
1000 
1014 size_t
1015 MHD_strx_to_uint32_n_ (const char *str,
1016  size_t maxlen,
1017  uint32_t *out_val)
1018 {
1019  size_t i;
1020  uint32_t res;
1021  int digit;
1022  if (! str || ! out_val)
1023  return 0;
1024 
1025  res = 0;
1026  i = 0;
1027  while (i < maxlen && (digit = toxdigitvalue (str[i])) >= 0)
1028  {
1029  if ( (res > (UINT32_MAX / 16)) ||
1030  ((res == (UINT32_MAX / 16)) && ( (uint32_t) digit > (UINT32_MAX
1031  % 16)) ) )
1032  return 0;
1033 
1034  res *= 16;
1035  res += digit;
1036  i++;
1037  }
1038 
1039  if (i)
1040  *out_val = res;
1041  return i;
1042 }
1043 
1044 
1055 size_t
1056 MHD_strx_to_uint64_ (const char *str,
1057  uint64_t *out_val)
1058 {
1059  const char *const start = str;
1060  uint64_t res;
1061  int digit;
1062  if (! str || ! out_val)
1063  return 0;
1064 
1065  res = 0;
1066  digit = toxdigitvalue (*str);
1067  while (digit >= 0)
1068  {
1069  if ( (res < (UINT64_MAX / 16)) ||
1070  ((res == (UINT64_MAX / 16)) && ( (uint64_t) digit <= (UINT64_MAX
1071  % 16)) ) )
1072  {
1073  res *= 16;
1074  res += digit;
1075  }
1076  else
1077  return 0;
1078  str++;
1079  digit = toxdigitvalue (*str);
1080  }
1081 
1082  if (str - start > 0)
1083  *out_val = res;
1084  return str - start;
1085 }
1086 
1087 
1101 size_t
1102 MHD_strx_to_uint64_n_ (const char *str,
1103  size_t maxlen,
1104  uint64_t *out_val)
1105 {
1106  size_t i;
1107  uint64_t res;
1108  int digit;
1109  if (! str || ! out_val)
1110  return 0;
1111 
1112  res = 0;
1113  i = 0;
1114  while (i < maxlen && (digit = toxdigitvalue (str[i])) >= 0)
1115  {
1116  if ( (res > (UINT64_MAX / 16)) ||
1117  ((res == (UINT64_MAX / 16)) && ( (uint64_t) digit > (UINT64_MAX
1118  % 16)) ) )
1119  return 0;
1120 
1121  res *= 16;
1122  res += digit;
1123  i++;
1124  }
1125 
1126  if (i)
1127  *out_val = res;
1128  return i;
1129 }
1130 
1131 
1132 #else /* MHD_FAVOR_SMALL_CODE */
1133 
1151 size_t
1152 MHD_str_to_uvalue_n_ (const char *str,
1153  size_t maxlen,
1154  void *out_val,
1155  size_t val_size,
1156  uint64_t max_val,
1157  int base)
1158 {
1159  size_t i;
1160  uint64_t res;
1161  int digit;
1162  const uint64_t max_v_div_b = max_val / base;
1163  const uint64_t max_v_mod_b = max_val % base;
1164  /* 'digit->value' must be function, not macro */
1165  int (*const dfunc)(char) = (base == 16) ?
1167 
1168  if (! str || ! out_val ||
1169  ((base != 16) && (base != 10)) )
1170  return 0;
1171 
1172  res = 0;
1173  i = 0;
1174  while (maxlen > i && 0 <= (digit = dfunc (str[i])))
1175  {
1176  if ( ((max_v_div_b) < res) ||
1177  (( (max_v_div_b) == res) && ( (max_v_mod_b) < (uint64_t) digit) ) )
1178  return 0;
1179 
1180  res *= base;
1181  res += digit;
1182  i++;
1183  }
1184 
1185  if (i)
1186  {
1187  if (8 == val_size)
1188  *(uint64_t *) out_val = res;
1189  else if (4 == val_size)
1190  *(uint32_t *) out_val = (uint32_t) res;
1191  else
1192  return 0;
1193  }
1194  return i;
1195 }
1196 
1197 
1198 #endif /* MHD_FAVOR_SMALL_CODE */
1199 
1200 
1201 size_t
1202 MHD_uint32_to_strx (uint32_t val,
1203  char *buf,
1204  size_t buf_size)
1205 {
1206  size_t o_pos = 0;
1207  int digit_pos = 8;
1208  int digit;
1209 
1210  /* Skip leading zeros */
1211  do
1212  {
1213  digit_pos--;
1214  digit = (int) (val >> 28);
1215  val <<= 4;
1216  } while ((0 == digit) && (0 != digit_pos));
1217 
1218  while (o_pos < buf_size)
1219  {
1220  buf[o_pos++] = (digit <= 9) ? ('0' + (char) digit) :
1221  ('A' + (char) digit - 10);
1222  if (0 == digit_pos)
1223  return o_pos;
1224  digit_pos--;
1225  digit = (int) (val >> 28);
1226  val <<= 4;
1227  }
1228  return 0; /* The buffer is too small */
1229 }
1230 
1231 
1232 #ifndef MHD_FAVOR_SMALL_CODE
1233 size_t
1234 MHD_uint16_to_str (uint16_t val,
1235  char *buf,
1236  size_t buf_size)
1237 {
1238  char *chr;
1239  /* The biggest printable number is 65535 */
1240  uint16_t divisor = UINT16_C (10000);
1241  int digit;
1242 
1243  chr = buf;
1244  digit = (int) (val / divisor);
1245  mhd_assert (digit < 10);
1246 
1247  /* Do not print leading zeros */
1248  while ((0 == digit) && (1 < divisor))
1249  {
1250  divisor /= 10;
1251  digit = (int) (val / divisor);
1252  mhd_assert (digit < 10);
1253  }
1254 
1255  while (0 != buf_size)
1256  {
1257  *chr = (char) digit + '0';
1258  chr++;
1259  buf_size--;
1260  if (1 == divisor)
1261  return (size_t) (chr - buf);
1262  val %= divisor;
1263  divisor /= 10;
1264  digit = (int) (val / divisor);
1265  mhd_assert (digit < 10);
1266  }
1267  return 0; /* The buffer is too small */
1268 }
1269 
1270 
1271 #endif /* !MHD_FAVOR_SMALL_CODE */
1272 
1273 
1274 size_t
1275 MHD_uint64_to_str (uint64_t val,
1276  char *buf,
1277  size_t buf_size)
1278 {
1279  char *chr;
1280  /* The biggest printable number is 18446744073709551615 */
1281  uint64_t divisor = UINT64_C (10000000000000000000);
1282  int digit;
1283 
1284  chr = buf;
1285  digit = (int) (val / divisor);
1286  mhd_assert (digit < 10);
1287 
1288  /* Do not print leading zeros */
1289  while ((0 == digit) && (1 < divisor))
1290  {
1291  divisor /= 10;
1292  digit = (int) (val / divisor);
1293  mhd_assert (digit < 10);
1294  }
1295 
1296  while (0 != buf_size)
1297  {
1298  *chr = (char) digit + '0';
1299  chr++;
1300  buf_size--;
1301  if (1 == divisor)
1302  return (size_t) (chr - buf);
1303  val %= divisor;
1304  divisor /= 10;
1305  digit = (int) (val / divisor);
1306  mhd_assert (digit < 10);
1307  }
1308  return 0; /* The buffer is too small */
1309 }
1310 
1311 
1312 size_t
1314  uint8_t min_digits,
1315  char *buf,
1316  size_t buf_size)
1317 {
1318  size_t pos;
1319  int digit;
1320  mhd_assert (3 >= min_digits);
1321  if (0 == buf_size)
1322  return 0;
1323 
1324  pos = 0;
1325  digit = val / 100;
1326  if (0 == digit)
1327  {
1328  if (3 <= min_digits)
1329  buf[pos++] = '0';
1330  }
1331  else
1332  {
1333  buf[pos++] = '0' + digit;
1334  val %= 100;
1335  min_digits = 2;
1336  }
1337 
1338  if (buf_size <= pos)
1339  return 0;
1340  digit = val / 10;
1341  if (0 == digit)
1342  {
1343  if (2 <= min_digits)
1344  buf[pos++] = '0';
1345  }
1346  else
1347  {
1348  buf[pos++] = '0' + digit;
1349  val %= 10;
1350  }
1351 
1352  if (buf_size <= pos)
1353  return 0;
1354  buf[pos++] = '0' + val;
1355  return pos;
1356 }
#define mhd_assert(CHK)
Definition: mhd_assert.h:39
#define UINT64_MAX
Definition: mhd_limits.h:81
#define UINT32_MAX
Definition: mhd_limits.h:73
int MHD_str_equal_caseless_(const char *str1, const char *str2)
Definition: mhd_str.c:346
size_t MHD_strx_to_uint32_(const char *str, uint32_t *out_val)
Definition: mhd_str.c:558
size_t MHD_str_to_uint64_n_(const char *str, size_t maxlen, uint64_t *out_val)
Definition: mhd_str.c:515
size_t MHD_strx_to_uint64_n_(const char *str, size_t maxlen, uint64_t *out_val)
Definition: mhd_str.c:692
int MHD_str_equal_caseless_n_(const char *const str1, const char *const str2, size_t maxlen)
Definition: mhd_str.c:378
size_t MHD_str_to_uint64_(const char *str, uint64_t *out_val)
Definition: mhd_str.c:473
bool MHD_str_has_token_caseless_(const char *str, const char *const token, size_t token_len)
Definition: mhd_str.c:412
size_t MHD_strx_to_uint64_(const char *str, uint64_t *out_val)
Definition: mhd_str.c:646
size_t MHD_strx_to_uint32_n_(const char *str, size_t maxlen, uint32_t *out_val)
Definition: mhd_str.c:605
#define NULL
Definition: reason_phrase.c:30
macros for mhd_assert()
limits values definitions
#define toasciilower(c)
Definition: mhd_str.c:316
size_t MHD_uint8_to_str_pad(uint8_t val, uint8_t min_digits, char *buf, size_t buf_size)
Definition: mhd_str.c:1313
bool MHD_str_remove_tokens_caseless_(char *str, size_t *str_len, const char *const tokens, const size_t tokens_len)
Definition: mhd_str.c:720
size_t MHD_uint16_to_str(uint16_t val, char *buf, size_t buf_size)
Definition: mhd_str.c:1234
size_t MHD_uint64_to_str(uint64_t val, char *buf, size_t buf_size)
Definition: mhd_str.c:1275
#define charsequalcaseless(c1, c2)
Definition: mhd_str.c:362
#define isasciialnum(c)
Definition: mhd_str.c:304
#define toxdigitvalue(c)
Definition: mhd_str.c:348
bool MHD_str_remove_token_caseless_(const char *str, size_t str_len, const char *const token, const size_t token_len, char *buf, ssize_t *buf_size)
Definition: mhd_str.c:553
#define toasciiupper(c)
Definition: mhd_str.c:329
#define isasciilower(c)
Definition: mhd_str.c:252
#define isasciidigit(c)
Definition: mhd_str.c:282
bool MHD_str_equal_caseless_bin_n_(const char *const str1, const char *const str2, size_t len)
Definition: mhd_str.c:445
size_t MHD_uint32_to_strx(uint32_t val, char *buf, size_t buf_size)
Definition: mhd_str.c:1202
#define isasciiupper(c)
Definition: mhd_str.c:262
#define isasciialpha(c)
Definition: mhd_str.c:272
#define isasciixdigit(c)
Definition: mhd_str.c:292
#define todigitvalue(c)
Definition: mhd_str.c:339
Header for string manipulating helpers.