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