api documentation for ec_parse
[protos/libecoli.git] / src / ecoli_string.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2016, Olivier MATZ <zer0@droids-corp.org>
3  */
4
5 #include <stdarg.h>
6 #include <stddef.h>
7 #include <string.h>
8 #include <stdio.h>
9 #include <errno.h>
10 #include <limits.h>
11 #include <stdint.h>
12 #include <ctype.h>
13
14 #include <ecoli_assert.h>
15 #include <ecoli_malloc.h>
16 #include <ecoli_string.h>
17
18 /* count the number of identical chars at the beginning of 2 strings */
19 size_t ec_strcmp_count(const char *s1, const char *s2)
20 {
21         size_t i = 0;
22
23         while (s1[i] && s2[i] && s1[i] == s2[i])
24                 i++;
25
26         return i;
27 }
28
29 int ec_str_startswith(const char *s, const char *beginning)
30 {
31         size_t len;
32
33         len = ec_strcmp_count(s, beginning);
34         if (beginning[len] == '\0')
35                 return 1;
36
37         return 0;
38 }
39
40 int ec_vasprintf(char **buf, const char *fmt, va_list ap)
41 {
42         char dummy;
43         int buflen, ret;
44         va_list aq;
45
46         va_copy(aq, ap);
47         *buf = NULL;
48         ret = vsnprintf(&dummy, 1, fmt, aq);
49         va_end(aq);
50         if (ret < 0)
51                 return ret;
52
53         buflen = ret + 1;
54         *buf = ec_malloc(buflen);
55         if (*buf == NULL)
56                 return -1;
57
58         va_copy(aq, ap);
59         ret = vsnprintf(*buf, buflen, fmt, aq);
60         va_end(aq);
61
62         ec_assert_print(ret < buflen, "invalid return value for vsnprintf");
63         if (ret < 0) {
64                 free(*buf);
65                 *buf = NULL;
66                 return -1;
67         }
68
69         return ret;
70 }
71
72 int ec_asprintf(char **buf, const char *fmt, ...)
73 {
74         va_list ap;
75         int ret;
76
77         va_start(ap, fmt);
78         ret = ec_vasprintf(buf, fmt, ap);
79         va_end(ap);
80
81         return ret;
82 }
83
84 bool ec_str_is_space(const char *s)
85 {
86         while (*s) {
87                 if (!isspace(*s))
88                         return false;
89                 s++;
90         }
91         return true;
92 }
93
94 int ec_str_parse_llint(const char *str, unsigned int base, int64_t min,
95                 int64_t max, int64_t *val)
96 {
97         char *endptr;
98         int save_errno = errno;
99
100         errno = 0;
101         *val = strtoll(str, &endptr, base);
102
103         if ((errno == ERANGE && (*val == LLONG_MAX || *val == LLONG_MIN)) ||
104                         (errno != 0 && *val == 0))
105                 return -1;
106
107         if (*val < min) {
108                 errno = ERANGE;
109                 return -1;
110         }
111
112         if (*val > max) {
113                 errno = ERANGE;
114                 return -1;
115         }
116
117         if (*endptr != 0) {
118                 errno = EINVAL;
119                 return -1;
120         }
121
122         errno = save_errno;
123         return 0;
124 }
125
126 int ec_str_parse_ullint(const char *str, unsigned int base, uint64_t min,
127                         uint64_t max, uint64_t *val)
128 {
129         char *endptr;
130         int save_errno = errno;
131
132         /* since a negative input is silently converted to a positive
133          * one by strtoull(), first check that it is positive */
134         if (strchr(str, '-'))
135                 return -1;
136
137         errno = 0;
138         *val = strtoull(str, &endptr, base);
139
140         if ((errno == ERANGE && *val == ULLONG_MAX) ||
141                         (errno != 0 && *val == 0))
142                 return -1;
143
144         if (*val < min)
145                 return -1;
146
147         if (*val > max)
148                 return -1;
149
150         if (*endptr != 0)
151                 return -1;
152
153         errno = save_errno;
154         return 0;
155 }