]> mj.ucw.cz Git - libucw.git/blob - ucw/strtonum-gen.h
079548ffe04e32dd8c941f5454b5d9df69896c59
[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   const char *parse_string(void)
34   {
35     const STN_TYPE max = STN_MAX;
36     const STN_TYPE top = S(tops)[base];
37     if (!top)
38       {
39         return err_unknown_base;
40       }
41
42     const STN_TYPE sign_max = ((flags & STN_SIGNED) || sign) ? max/2 + sign : max;
43
44     STN_TYPE val = 0;
45     uns digits = 0;
46     int overflow = 0;
47     for (;; p++)
48       {
49         const uns c = (byte)*p;
50
51         if (c == '_')
52           {
53             if (flags & STN_UNDERSCORE)
54               continue;
55             else
56               break;
57           }
58
59         const uns d = get_digit(c);
60         if (d >= base)
61           break;
62         digits++;
63         if (overflow)
64           continue;
65
66         STN_TYPE v = val;
67         if ( (overflow = (v > top || (v *= base) > sign_max - d)) )
68           continue;
69         val = v + d;
70       }
71
72     if (!overflow)
73       {
74         if (!digits)
75           {
76             return err_no_digits;
77           }
78
79         if (sign)
80           {
81             val = -val;
82           }
83       }
84     else
85       {
86         if (flags & STN_TRUNC)
87           val = sign_max;
88         else
89           {
90             return err_numeric_overflow;
91           }
92       }
93
94     if ((flags & STN_ZCHAR) && *p)
95       {
96         return err_invalid_character;
97       }
98
99     if (num)
100       *num = val;
101
102     return NULL;
103   }
104
105   if (!err)
106     err = parse_string();
107
108   if (next)
109     *next = p;
110
111   return err;
112 }
113
114 #undef STN_MAX
115 #undef S
116 #undef S_HELPER1
117 #undef S_HELPER2
118 #undef STN_TYPE
119 #undef STN_SUFFIX
120 #undef STN_DECLARE