1 /*
2  *  Copyright (C) 2004-2011 Christos Tsantilas
3  *
4  *  This program is free software; you can redistribute it and/or
5  *  modify it under the terms of the GNU Lesser General Public
6  *  License as published by the Free Software Foundation; either
7  *  version 2.1 of the License, or (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  *  Lesser General Public License for more details.
13  *
14  *  You should have received a copy of the GNU Lesser General Public
15  *  License along with this library; if not, write to the Free Software
16  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17  *  MA  02110-1301  USA.
18  */
19 
20 #include "common.h"
21 #include "c-icap.h"
22 #include "array.h"
23 #include "util.h"
24 #include <ctype.h>
25 #include <errno.h>
26 #include <limits.h>
27 
ci_strnstr(const char * s,const char * find,size_t slen)28 const char *ci_strnstr(const char *s, const char *find, size_t slen)
29 {
30     size_t len = strlen(find);
31 
32     if (len == 0)
33         return NULL;
34 
35     while (len <= slen) {
36         if (*s == *find && strncmp(s, find, len) == 0 )
37             return s;
38         s++,slen--;
39     }
40     return NULL;
41 }
42 
ci_strcasestr(const char * str,const char * find)43 const char *ci_strcasestr(const char *str, const char *find)
44 {
45     const char *s, *c, *f;
46     for (s = str; *s != '\0'; ++s) {
47         for (f = find, c = s; ; ++f, ++c) {
48             if (*f == '\0') /*find matched s*/
49                 return s;
50             if (*c == '\0') /*find is longer than the remaining string */
51                 return NULL;
52             if (tolower(*c) != tolower(*f))
53                 break;
54         }
55     }
56     return NULL;
57 }
58 
ci_strncasestr(const char * s,const char * find,size_t slen)59 const char *ci_strncasestr(const char *s, const char *find, size_t slen)
60 {
61     size_t len = strlen(find);
62 
63     if (len == 0)
64         return NULL;
65 
66     while (len <= slen) {
67         if (tolower(*s) == tolower(*find) && strncasecmp(s, find, len) == 0 )
68             return s;
69         s++,slen--;
70     }
71     return NULL;
72 }
73 
74 static const char *atol_err_erange = "ERANGE";
75 static const char *atol_err_conversion = "CONVERSION_ERROR";
76 static const char *atol_err_nonumber = "NO_DIGITS_ERROR";
77 
ci_atol_ext(const char * str,const char ** error)78 long int ci_atol_ext(const char *str, const char **error)
79 {
80     char *e;
81 
82     long int val;
83     errno = 0;
84     val = strtol(str, &e, 10);
85 
86     if (error) {
87         *error = NULL;
88 
89         if (errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
90             *error = atol_err_erange;
91         else if (errno != 0 && val == 0)
92             *error = atol_err_conversion;
93         else if (e == str)
94             *error = atol_err_nonumber;
95 
96         if (*error)
97             return 0;
98     }
99 
100     if (val) {
101         if (*e == 'k' || * e == 'K')
102             val = val * 1024;
103         else if (*e == 'm' || * e == 'M')
104             val = val * 1024 * 1024;
105     }
106     return val;
107 }
108 
ci_str_trim(char * str)109 void ci_str_trim(char *str)
110 {
111     char *s, *e;
112 
113     if (!str)
114         return;
115 
116     s = str;
117     e = NULL;
118     while (isspace(*s)) {
119         e = s;
120         while (*e != '\0') {
121             *e = *(e+1);
122             e++;
123         }
124     }
125 
126     /*if (e) e--;  else */
127     e = str+strlen(str);
128     e--;
129     while (isspace(*e) && e >= str) {*e = '\0'; --e;};
130 }
131 
ci_str_trim2(char * s)132 char *ci_str_trim2(char *s)
133 {
134     char *e;
135 
136     if (!s)
137         return NULL;
138 
139     while (isspace(*s)) ++s;
140     e = s + strlen(s);
141     e--;
142     while (isspace(*e) && e >= s) {*e = '\0'; --e;};
143     return s;
144 }
145 
ci_strerror(int error,char * buf,size_t buflen)146 char * ci_strerror(int error, char *buf, size_t buflen)
147 {
148 #if defined(STRERROR_R_CHAR_P)
149     return strerror_r(error, buf, buflen);
150 #elif defined(HAVE_STRERROR_R)
151     if (strerror_r(error,  buf, buflen) == 0)
152         return buf;
153 #else
154     snprintf(buf, buflen, "%d", error);
155     return buf;
156 
157 #endif
158 }
159 
160 /*
161   TODO: support escaped chars,
162 */
ci_parse_key_value_list(const char * str,char sep)163 ci_dyn_array_t *ci_parse_key_value_list(const char *str, char sep)
164 {
165     char *s, *e, *k, *v;
166     ci_dyn_array_t *args_array;
167     s = strdup(str);
168     if (!s)
169         return NULL;
170 
171     args_array = ci_dyn_array_new(1024);
172     k = s;
173     while (k) {
174         if ((e = strchr(k, sep))) {
175             *e = '\0';
176             e++;
177         }
178         if ((v = strchr(k, '='))) {
179             *v = '\0';
180             ++v;
181         }
182         k = ci_str_trim2(k);
183         if (v)
184             v = ci_str_trim2(v);
185         if (*k) {
186             ci_dyn_array_add(args_array, k, v ? v : "", v ? strlen(v) + 1 : 1);
187         }
188         k = (e && *e) ? e : NULL;
189     }
190     free(s);
191     return args_array;
192 }
193