1 /* ########################################################### */
2 /* This Software is licensed under the GPL licensed Version 2, */
3 /* please read http://www.gnu.org/copyleft/gpl.html.           */
4 /* ########################################################### */
5 
6 /* ******************************** */
7 /* Various small utility functions. */
8 /* ******************************** */
9 
10 #include "config.h"
11 #include <stdlib.h>
12 #include <limits.h>
13 #include <string.h>
14 #include <ctype.h>
15 #include <stdarg.h>
16 #include <wctype.h>
17 #include "xmalloc.h"
18 #include "list.h"
19 #include "utils.h"
20 
21 /* ******************* */
22 /* Interval functions. */
23 /* ******************* */
24 
25 /* ======================= */
26 /* Creates a new interval. */
27 /* ======================= */
28 interval_t *
interval_new(void)29 interval_new(void)
30 {
31   interval_t * ret = xmalloc(sizeof(interval_t));
32 
33   return ret;
34 }
35 
36 /* ======================================= */
37 /* Compares 2 intervals as integer couples */
38 /* same return values as for strcmp.       */
39 /* ======================================= */
40 int
interval_comp(void * a,void * b)41 interval_comp(void * a, void * b)
42 {
43   interval_t * ia = (interval_t *)a;
44   interval_t * ib = (interval_t *)b;
45 
46   if (ia->low < ib->low)
47     /* ia: [...      */
48     /* ib:      [... */
49     return -1;
50   if (ia->low > ib->low)
51     /* ia:      [... */
52     /* ib: [...      */
53     return 1;
54   if (ia->high < ib->high)
55     /* ia: ...]      */
56     /* ib:      ...] */
57     return -1;
58   if (ia->high > ib->high)
59     /* ia:      ...] */
60     /* ib: ...]      */
61     return 1;
62 
63   return 0;
64 }
65 
66 /* ================================== */
67 /* Swaps the values of two intervals. */
68 /* ================================== */
69 void
interval_swap(void * a,void * b)70 interval_swap(void * a, void * b)
71 {
72   interval_t * ia = (interval_t *)a;
73   interval_t * ib = (interval_t *)b;
74   long         tmp;
75 
76   tmp     = ia->low;
77   ia->low = ib->low;
78   ib->low = tmp;
79 
80   tmp      = ia->high;
81   ia->high = ib->high;
82   ib->high = tmp;
83 }
84 
85 /* ====================================================================== */
86 /* Merges the intervals from an interval list in order to get the minimum */
87 /* number of intervals to consider.                                       */
88 /* ====================================================================== */
89 void
merge_intervals(ll_t * list)90 merge_intervals(ll_t * list)
91 {
92   ll_node_t * node1, *node2;
93   interval_t *data1, *data2;
94 
95   if (!list || list->len < 2)
96     return;
97   else
98   {
99     /* Step 1: sort the intervals list. */
100     /* """""""""""""""""""""""""""""""" */
101     ll_sort(list, interval_comp, interval_swap);
102 
103     /* Step 2: merge the list by merging the consecutive intervals. */
104     /* """"""""""""""""""""""""""""""""""""""""""""""""""""""""""" */
105     node1 = list->head;
106     node2 = node1->next;
107 
108     while (node2)
109     {
110       data1 = (interval_t *)(node1->data);
111       data2 = (interval_t *)(node2->data);
112 
113       if (data1->high >= data2->low - 1)
114       {
115         /* Interval 1 overlaps interval 2. */
116         /* ''''''''''''''''''''''''''''''' */
117         if (data2->high >= data1->high)
118           data1->high = data2->high;
119         ll_delete(list, node2);
120         free(data2);
121         node2 = node1->next;
122       }
123       else
124       {
125         /* No overlap. */
126         /* ''''''''''' */
127         node1 = node2;
128         node2 = node2->next;
129       }
130     }
131   }
132 }
133 
134 /* ****************** */
135 /* Strings functions. */
136 /* ****************** */
137 
138 /* ========================================================================= */
139 /* Allocates memory and safely concatenate strings. Stolen from a public     */
140 /* domain implementation which can be found here:                            */
141 /* http://openwall.info/wiki/people/solar/software/public-domain-source-code */
142 /* ========================================================================= */
143 char *
concat(const char * s1,...)144 concat(const char * s1, ...)
145 {
146   va_list      args;
147   const char * s;
148   char *       p, *result;
149   size_t       l, m, n;
150 
151   m = n = strlen(s1);
152   va_start(args, s1);
153   while ((s = va_arg(args, char *)))
154   {
155     l = strlen(s);
156     if ((m += l) < l)
157       break;
158   }
159   va_end(args);
160   if (s || m >= INT_MAX)
161     return NULL;
162 
163   result = (char *)xmalloc(m + 1);
164 
165   memcpy(p = result, s1, n);
166   p += n;
167   va_start(args, s1);
168   while ((s = va_arg(args, char *)))
169   {
170     l = strlen(s);
171     if ((n += l) < l || n > m)
172       break;
173     memcpy(p, s, l);
174     p += l;
175   }
176   va_end(args);
177   if (s || m != n || p != result + n)
178   {
179     free(result);
180     return NULL;
181   }
182 
183   *p = 0;
184   return result;
185 }
186 
187 /* =============================================== */
188 /* Is the string str2 a prefix of the string str1? */
189 /* Returns 1 if true, else 0.                      */
190 /* =============================================== */
191 int
strprefix(char * str1,char * str2)192 strprefix(char * str1, char * str2)
193 {
194   while (*str1 != '\0' && *str1 == *str2)
195   {
196     str1++;
197     str2++;
198   }
199 
200   return *str2 == '\0';
201 }
202 
203 /* ========================= */
204 /* Trims leading characters. */
205 /* ========================= */
206 void
ltrim(char * str,const char * trim_str)207 ltrim(char * str, const char * trim_str)
208 {
209   size_t len   = strlen(str);
210   size_t begin = strspn(str, trim_str);
211   size_t i;
212 
213   if (begin > 0)
214     for (i = begin; i <= len; ++i)
215       str[i - begin] = str[i];
216 }
217 
218 /* ==================================================================== */
219 /* Trims trailing characters.                                           */
220 /* All (ASCII) characters in trim_str will be removed.                  */
221 /* The min argument guarantees that the length of the resulting string  */
222 /* will not be smaller than this size if it was larger before, 0 is the */
223 /* usual value here.                                                    */
224 /* Note that when min is greater than 0, tail characters intended to be */
225 /* deleted may remain.                                                  */
226 /* ==================================================================== */
227 void
rtrim(char * str,const char * trim_str,size_t min)228 rtrim(char * str, const char * trim_str, size_t min)
229 {
230   size_t len = strlen(str);
231   while (len > min && strchr(trim_str, str[len - 1]))
232     str[--len] = '\0';
233 }
234 
235 /* ========================================= */
236 /* Case insensitive strcmp.                  */
237 /* from http://c.snippets.org/code/stricmp.c */
238 /* ========================================= */
239 int
my_strcasecmp(const char * str1,const char * str2)240 my_strcasecmp(const char * str1, const char * str2)
241 {
242 #ifdef HAVE_STRCASECMP
243   return strcasecmp(str1, str2);
244 #else
245   int retval = 0;
246 
247   while (1)
248   {
249     retval = tolower(*str1++) - tolower(*str2++);
250 
251     if (retval)
252       break;
253 
254     if (*str1 && *str2)
255       continue;
256     else
257       break;
258   }
259   return retval;
260 #endif
261 }
262 
263 /* ============================================= */
264 /* memmove based strcpy (tolerates overlapping). */
265 /* ============================================= */
266 char *
my_strcpy(char * str1,char * str2)267 my_strcpy(char * str1, char * str2)
268 {
269   if (str1 == NULL || str2 == NULL)
270     return NULL;
271 
272   memmove(str1, str2, strlen(str2) + 1);
273 
274   return str1;
275 }
276 
277 /* ================================ */
278 /* 7 bits aware version of isprint. */
279 /* ================================ */
280 int
isprint7(int i)281 isprint7(int i)
282 {
283   return (i >= 0x20 && i <= 0x7e);
284 }
285 
286 /* ================================ */
287 /* 8 bits aware version of isprint. */
288 /* ================================ */
289 int
isprint8(int i)290 isprint8(int i)
291 {
292   unsigned char c = i & (unsigned char)0xff;
293 
294   return (c >= 0x20 && c < 0x7f) || (c >= (unsigned char)0xa0);
295 }
296 
297 /* ==================================================== */
298 /* Private implementation of wcscasecmp missing in c99. */
299 /* ==================================================== */
300 int
xwcscasecmp(const wchar_t * s1,const wchar_t * s2)301 xwcscasecmp(const wchar_t * s1, const wchar_t * s2)
302 {
303   wchar_t c1, c2;
304 
305   while (*s1)
306   {
307     c1 = towlower(*s1);
308     c2 = towlower(*s2);
309 
310     if (c1 != c2)
311       return (int)(c1 - c2);
312 
313     s1++;
314     s2++;
315   }
316   return (-*s2);
317 }
318 
319 /* ==================================================================== */
320 /* Returns 1 if s can be converted into an integer otherwise returns 0. */
321 /* ==================================================================== */
322 int
is_integer(const char * const s)323 is_integer(const char * const s)
324 {
325   long int n;
326 
327   if (!s || (strspn(s, "0123456789 ") != strlen(s)))
328     return 0;
329 
330   n = strtol(s, NULL, 10);
331 
332   if (errno != ERANGE && n >= INT_MIN && n <= INT_MAX)
333     return 1;
334   else
335     return 0;
336 }
337