malloc
[protos/libecoli.git] / lib / ecoli_tk_int.c
1 /*
2  * Copyright (c) 2016, Olivier MATZ <zer0@droids-corp.org>
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  *     * Redistributions of source code must retain the above copyright
8  *       notice, this list of conditions and the following disclaimer.
9  *     * Redistributions in binary form must reproduce the above copyright
10  *       notice, this list of conditions and the following disclaimer in the
11  *       documentation and/or other materials provided with the distribution.
12  *     * Neither the name of the University of California, Berkeley nor the
13  *       names of its contributors may be used to endorse or promote products
14  *       derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include <stdio.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <limits.h>
32 #include <ctype.h>
33 #include <errno.h>
34
35 #include <ecoli_malloc.h>
36 #include <ecoli_tk.h>
37 #include <ecoli_tk_int.h>
38 #include <ecoli_test.h>
39
40 static size_t parse_llint(struct ec_tk_int *tk, const char *str,
41         long long *val)
42 {
43         char *endptr;
44
45         errno = 0;
46         *val = strtoll(str, &endptr, tk->base);
47
48         /* starts with a space */
49         if (isspace(str[0]))
50                 return 0;
51
52         /* out of range */
53         if ((errno == ERANGE && (*val == LLONG_MAX || *val == LLONG_MIN)) ||
54                         (errno != 0 && *val == 0))
55                 return 0;
56
57         if (*val < tk->min || *val > tk->max)
58                 return 0;
59
60         return endptr - str;
61 }
62
63 static struct ec_parsed_tk *parse(const struct ec_tk *gen_tk,
64         const char *str)
65 {
66         struct ec_tk_int *tk = (struct ec_tk_int *)gen_tk;
67         struct ec_parsed_tk *parsed_tk;
68         long long val;
69         size_t len;
70
71         len = parse_llint(tk, str, &val);
72         if (len == 0)
73                 return NULL;
74
75         parsed_tk = ec_parsed_tk_new(gen_tk);
76         if (parsed_tk == NULL)
77                 return NULL;
78
79         parsed_tk->str = ec_strndup(str, len);
80
81         return parsed_tk;
82 }
83
84 static struct ec_tk_ops int_ops = {
85         .parse = parse,
86 };
87
88 struct ec_tk *ec_tk_int_new(const char *id, long long int min,
89         long long int max, unsigned int base)
90 {
91         struct ec_tk_int *tk = NULL;
92
93         tk = (struct ec_tk_int *)ec_tk_new(id, &int_ops, sizeof(*tk));
94         if (tk == NULL)
95                 return NULL;
96
97         tk->min = min;
98         tk->max = max;
99         tk->base = base;
100
101         return &tk->gen;
102 }
103
104 long long ec_tk_int_getval(struct ec_tk *gen_tk, const char *str)
105 {
106         struct ec_tk_int *tk = (struct ec_tk_int *)gen_tk;
107         long long val = 0;
108
109         // XXX check type here
110         // if gen_tk->type != int fail
111
112         parse_llint(tk, str, &val);
113
114         return val;
115 }
116
117 static int testcase(void)
118 {
119         struct ec_parsed_tk *p;
120         struct ec_tk *tk;
121         const char *s;
122         int ret = 0;
123
124         tk = ec_tk_int_new(NULL, 0, 256, 0);
125         if (tk == NULL) {
126                 printf("cannot create tk\n");
127                 return -1;
128         }
129         ret |= EC_TEST_CHECK_TK_PARSE(tk, "0", "0");
130         ret |= EC_TEST_CHECK_TK_PARSE(tk, "256", "256");
131         ret |= EC_TEST_CHECK_TK_PARSE(tk, "0x100", "0x100");
132         ret |= EC_TEST_CHECK_TK_PARSE(tk, "-1", NULL);
133         ret |= EC_TEST_CHECK_TK_PARSE(tk, "0x101", NULL);
134         ret |= EC_TEST_CHECK_TK_PARSE(tk, " 1", NULL);
135
136         p = ec_tk_parse(tk, "0");
137         s = ec_parsed_tk_to_string(p);
138         if (s == NULL) {
139                 TEST_ERR();
140         } else {
141                 if (ec_tk_int_getval(tk, s) != 0)
142                         TEST_ERR();
143         }
144
145         p = ec_tk_parse(tk, "10");
146         s = ec_parsed_tk_to_string(p);
147         if (s == NULL) {
148                 TEST_ERR();
149         } else {
150                 if (ec_tk_int_getval(tk, s) != 10)
151                         TEST_ERR();
152         }
153
154         ec_tk_free(tk);
155
156         tk = ec_tk_int_new(NULL, -1, LLONG_MAX, 16);
157         if (tk == NULL) {
158                 printf("cannot create tk\n");
159                 return -1;
160         }
161         ret |= EC_TEST_CHECK_TK_PARSE(tk, "0", "0");
162         ret |= EC_TEST_CHECK_TK_PARSE(tk, "-1", "-1");
163         ret |= EC_TEST_CHECK_TK_PARSE(tk, "7fffffffffffffff",
164                 "7fffffffffffffff");
165         ret |= EC_TEST_CHECK_TK_PARSE(tk, "0x7fffffffffffffff",
166                 "0x7fffffffffffffff");
167         ret |= EC_TEST_CHECK_TK_PARSE(tk, "-2", NULL);
168
169         p = ec_tk_parse(tk, "10");
170         s = ec_parsed_tk_to_string(p);
171         if (s == NULL) {
172                 TEST_ERR();
173         } else {
174                 if (ec_tk_int_getval(tk, s) != 16)
175                         TEST_ERR();
176         }
177
178         ec_tk_free(tk);
179
180         tk = ec_tk_int_new(NULL, LLONG_MIN, 0, 10);
181         if (tk == NULL) {
182                 printf("cannot create tk\n");
183                 return -1;
184         }
185         ret |= EC_TEST_CHECK_TK_PARSE(tk, "0", "0");
186         ret |= EC_TEST_CHECK_TK_PARSE(tk, "-1", "-1");
187         ret |= EC_TEST_CHECK_TK_PARSE(tk, "-9223372036854775808",
188                 "-9223372036854775808");
189         ret |= EC_TEST_CHECK_TK_PARSE(tk, "0x0", "0");
190         ret |= EC_TEST_CHECK_TK_PARSE(tk, "1", NULL);
191         ec_tk_free(tk);
192
193         /* /\* test completion *\/ */
194         /* tk = ec_tk_int_new(NULL, "foo"); */
195         /* if (tk == NULL) { */
196         /*      printf("cannot create tk\n"); */
197         /*      return -1; */
198         /* } */
199         /* ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "", "foo"); */
200         /* ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "f", "oo"); */
201         /* ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "foo", ""); */
202         /* ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "x", NULL); */
203         /* ec_tk_free(tk); */
204
205         return ret;
206 }
207
208 static struct ec_test test = {
209         .name = "tk_int",
210         .test = testcase,
211 };
212
213 EC_REGISTER_TEST(test);