]> mj.ucw.cz Git - libucw.git/blob - ucw/strtonum-gen.h
c21a9880297343579d51b2126ab55821a2c14db2
[libucw.git] / ucw / strtonum-gen.h
1 /*
2  *      UCW Library -- Conversions of Strings to Numbers
3  *
4  *      (c) 2010 Daniel Fiala <danfiala@ucw.cz>
5  *
6  *      This software may be freely distributed and used according to the terms
7  *      of the GNU Lesser General Public License.
8  */
9
10 /* This is not a normall header file, it is generator of a function for converting strings to integers
11  * of a certain type. This file should be used only by ucw/stronum.c .
12  */
13
14 #define STN_DECLARE(type, suffix) STN_DECLARE_CONVERTOR(type, suffix)
15
16 #define S_HELPER2(name, suffix) name##suffix
17 #define S_HELPER1(name, suffix) S_HELPER2(name, suffix)
18 #define S(name) S_HELPER1(name, STN_SUFFIX)
19
20 #define STN_MAX ((STN_TYPE)(-1))
21 static const STN_TYPE S(tops)[STN_DBASES_MASK+1] = { [2] = STN_MAX/2, [8] = STN_MAX/8, [10] = STN_MAX/10, [16] = STN_MAX/16 };
22
23 STN_DECLARE(STN_TYPE, STN_SUFFIX)
24 {
25   const char *p = str;
26   const char *err = NULL;
27
28   uns sign, base;
29   err = str_to_num_init(&p, flags, &sign, &base);
30   const char *parse_string(void)
31   {
32     const STN_TYPE max = STN_MAX;
33     const STN_TYPE top = S(tops)[base];
34     if (!top)
35       {
36         return err_unknown_base;
37       }
38
39     const STN_TYPE sign_max = ((flags & STN_SIGNED) || sign) ? max/2 + sign : max;
40
41     STN_TYPE val = 0;
42     uns digits = 0;
43     int overflow = 0;
44     for (;; p++)
45       {
46         const uns c = (byte)*p;
47
48         if (c == '_')
49           {
50             if (flags & STN_UNDERSCORE)
51               continue;
52             else
53               break;
54           }
55
56         const uns d = get_digit(c);
57         if (d >= base)
58           break;
59         digits++;
60         if (overflow)
61           continue;
62
63         STN_TYPE v = val;
64         if ( (overflow = (v > top || (v *= base) > sign_max - d)) )
65           continue;
66         val = v + d;
67       }
68
69     if (!overflow)
70       {
71         if (!digits)
72           {
73             return err_no_digits;
74           }
75
76         if (sign)
77           {
78             val = -val;
79           }
80       }
81     else
82       {
83         if (flags & STN_TRUNC)
84           val = sign_max;
85         else
86           {
87             return err_numeric_overflow;
88           }
89       }
90
91     if ((flags & STN_ZCHAR) && *p)
92       {
93         return err_invalid_character;
94       }
95
96     if (num)
97       *num = val;
98
99     return NULL;
100   }
101   if (!err)
102     err = parse_string();
103
104   if (next)
105     *next = p;
106
107   return err;
108 }
109
110 #undef STN_MAX
111 #undef S
112 #undef S_HELPER1
113 #undef S_HELPER2
114 #undef STN_TYPE
115 #undef STN_SUFFIX
116 #undef STN_DECLARE