]> mj.ucw.cz Git - libucw.git/blob - ucw/strtonum-gen.h
UCW::CGI: When a file is uploaded, its original name can be obtained
[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 static const char *S(parse_string)(const char **pp, const uns flags, const uns sign, const uns base, STN_TYPE *num)
26 {
27   const STN_TYPE max = STN_MAX;
28   const STN_TYPE top = S(tops)[base];
29   if (!top)
30     return "Unknown base";
31
32   const STN_TYPE sign_max = ((flags & STN_SIGNED) || sign) ? max/2 + sign : max;
33
34   STN_TYPE val = 0;
35   uns digits = 0;
36   int overflow = 0;
37   for (;; (*pp)++)
38     {
39       const uns c = (byte)**pp;
40
41       if (c == '_')
42         {
43           if (flags & STN_UNDERSCORE)
44             continue;
45           else
46             break;
47         }
48
49       const uns d = get_digit(c);
50       if (d >= base)
51         break;
52
53       digits++;
54
55       if (overflow)
56         continue;
57
58       STN_TYPE v = val;
59       if ( (overflow = (v > top || (v *= base) > sign_max - d)) )
60         continue;
61       val = v + d;
62     }
63
64   if (!overflow)
65     {
66       if (!digits)
67         return "Number contains no digits";
68
69       if (sign)
70         val = -val;
71     }
72   else
73     {
74       if (flags & STN_TRUNC)
75         val = sign_max;
76       else
77         return "Numeric overflow";
78     }
79
80   if ((flags & STN_WHOLE) && **pp)
81     return "Invalid character";
82
83   if (num)
84     *num = val;
85
86   return NULL;
87 }
88
89 STN_DECLARE(STN_TYPE, STN_SUFFIX)
90 {
91   const char *err = NULL;
92
93   uns sign, base;
94   err = str_to_num_init(&str, flags, &sign, &base);
95
96   if (!err)
97     err = S(parse_string)(&str, flags, sign, base, num);
98
99   if (next)
100     *next = str;
101
102   return err;
103 }
104
105 #undef STN_MAX
106 #undef S
107 #undef S_HELPER1
108 #undef S_HELPER2
109 #undef STN_TYPE
110 #undef STN_SUFFIX
111 #undef STN_DECLARE