Imported Upstream version 0.6.10
[platform/upstream/libsolv.git] / src / util.c
1 /*
2  * Copyright (c) 2007, Novell Inc.
3  *
4  * This program is licensed under the BSD license, read LICENSE.BSD
5  * for further information
6  */
7
8 #define _GNU_SOURCE
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <unistd.h>
13 #include <string.h>
14 #include <sys/time.h>
15
16 #include "util.h"
17
18 void
19 solv_oom(size_t num, size_t len)
20 {
21   if (num)
22     fprintf(stderr, "Out of memory allocating %zu*%zu bytes!\n", num, len);
23   else
24     fprintf(stderr, "Out of memory allocating %zu bytes!\n", len);
25   abort();
26   exit(1);
27 }
28
29 void *
30 solv_malloc(size_t len)
31 {
32   void *r = malloc(len ? len : 1);
33   if (!r)
34     solv_oom(0, len);
35   return r;
36 }
37
38 void *
39 solv_malloc2(size_t num, size_t len)
40 {
41   if (len && (num * len) / len != num)
42     solv_oom(num, len);
43   return solv_malloc(num * len);
44 }
45
46 void *
47 solv_realloc(void *old, size_t len)
48 {
49   if (old == 0)
50     old = malloc(len ? len : 1);
51   else
52     old = realloc(old, len ? len : 1);
53   if (!old)
54     solv_oom(0, len);
55   return old;
56 }
57
58 void *
59 solv_realloc2(void *old, size_t num, size_t len)
60 {
61   if (len && (num * len) / len != num)
62     solv_oom(num, len);
63   return solv_realloc(old, num * len);
64 }
65
66 void *
67 solv_calloc(size_t num, size_t len)
68 {
69   void *r;
70   if (num == 0 || len == 0)
71     r = malloc(1);
72   else
73     r = calloc(num, len);
74   if (!r)
75     solv_oom(num, len);
76   return r;
77 }
78
79 void *
80 solv_free(void *mem)
81 {
82   if (mem)
83     free(mem);
84   return 0;
85 }
86
87 char *
88 solv_strdup(const char *s)
89 {
90   char *r;
91   if (!s)
92     return 0;
93   r = strdup(s);
94   if (!r)
95     solv_oom(0, strlen(s));
96   return r;
97 }
98
99 unsigned int
100 solv_timems(unsigned int subtract)
101 {
102   struct timeval tv;
103   unsigned int r;
104
105   if (gettimeofday(&tv, 0))
106     return 0;
107   r = (((unsigned int)tv.tv_sec >> 16) * 1000) << 16;
108   r += ((unsigned int)tv.tv_sec & 0xffff) * 1000;
109   r += (unsigned int)tv.tv_usec / 1000;
110   return r - subtract;
111 }
112
113 /* bsd's qsort_r has different arguments, so we define our
114    own version in case we need to do some clever mapping
115
116    see also: http://sources.redhat.com/ml/libc-alpha/2008-12/msg00003.html
117  */
118 #if defined(__GLIBC__) && (defined(HAVE_QSORT_R) || defined(HAVE___QSORT_R))
119
120 void
121 solv_sort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *, void *), void *compard)
122 {
123 # if defined(HAVE_QSORT_R)
124   qsort_r(base, nmemb, size, compar, compard);
125 # else
126   /* backported for SLE10-SP2 */
127   __qsort_r(base, nmemb, size, compar, compard);
128 # endif
129
130 }
131
132 #elif defined(HAVE_QSORT_R) /* not glibc, but has qsort_r() */
133
134 struct solv_sort_data {
135   int (*compar)(const void *, const void *, void *);
136   void *compard;
137 };
138
139 static int
140 solv_sort_helper(void *compard, const void *a, const void *b)
141 {
142   struct solv_sort_data *d = compard;
143   return (*d->compar)(a, b, d->compard);
144 }
145
146 void
147 solv_sort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *, void *), void *compard)
148 {
149   struct solv_sort_data d;
150   d.compar = compar;
151   d.compard = compard;
152   qsort_r(base, nmemb, size, &d, solv_sort_helper);
153 }
154
155 #else /* not glibc and no qsort_r() */
156 /* use own version of qsort if none available */
157 #include "qsort_r.c"
158 #endif
159
160 char *
161 solv_dupjoin(const char *str1, const char *str2, const char *str3)
162 {
163   int l1, l2, l3;
164   char *s, *str;
165   l1 = str1 ? strlen(str1) : 0;
166   l2 = str2 ? strlen(str2) : 0;
167   l3 = str3 ? strlen(str3) : 0;
168   s = str = solv_malloc(l1 + l2 + l3 + 1);
169   if (l1)
170     {
171       strcpy(s, str1);
172       s += l1;
173     }
174   if (l2)
175     {
176       strcpy(s, str2);
177       s += l2;
178     }
179   if (l3)
180     {
181       strcpy(s, str3);
182       s += l3;
183     }
184   *s = 0;
185   return str;
186 }
187
188 char *
189 solv_dupappend(const char *str1, const char *str2, const char *str3)
190 {
191   char *str = solv_dupjoin(str1, str2, str3);
192   solv_free((void *)str1);
193   return str;
194 }
195
196 int
197 solv_hex2bin(const char **strp, unsigned char *buf, int bufl)
198 {
199   const char *str = *strp;
200   int i;
201
202   for (i = 0; i < bufl; i++)
203     {
204       int c = *str;
205       int d;
206       if (c >= '0' && c <= '9')
207         d = c - '0';
208       else if (c >= 'a' && c <= 'f')
209         d = c - ('a' - 10);
210       else if (c >= 'A' && c <= 'F')
211         d = c - ('A' - 10);
212       else
213         break;
214       c = *++str;
215       d <<= 4;
216       if (c >= '0' && c <= '9')
217         d |= c - '0';
218       else if (c >= 'a' && c <= 'f')
219         d |= c - ('a' - 10);
220       else if (c >= 'A' && c <= 'F')
221         d |= c - ('A' - 10);
222       else
223         break;
224       buf[i] = d;
225       ++str;
226     }
227   *strp = str;
228   return i;
229 }
230
231 char *
232 solv_bin2hex(const unsigned char *buf, int l, char *str)
233 {
234   int i;
235   for (i = 0; i < l; i++, buf++)
236     {
237       int c = *buf >> 4;
238       *str++ = c < 10 ? c + '0' : c + ('a' - 10);
239       c = *buf & 15;
240       *str++ = c < 10 ? c + '0' : c + ('a' - 10);
241     }
242   *str = 0;
243   return str;
244 }
245
246 size_t
247 solv_validutf8(const char *buf)
248 {
249   const unsigned char *p;
250   int x;
251
252   for (p = (const unsigned char *)buf; (x = *p) != 0; p++)
253     {
254       if (x < 0x80)
255         continue;
256       if (x < 0xc0)
257         break;
258       if (x < 0xe0)
259         {
260           /* one byte to follow */
261           if ((p[1] & 0xc0) != 0x80)
262             break;
263           if ((x & 0x1e) == 0)
264             break;      /* not minimal */
265           p += 1;
266           continue;
267         }
268       if (x < 0xf0)
269         {
270           /* two bytes to follow */
271           if ((p[1] & 0xc0) != 0x80 || (p[2] & 0xc0) != 0x80)
272             break;
273           if ((x & 0x0f) == 0 && (p[1] & 0x20) == 0)
274             break;      /* not minimal */
275           if (x == 0xed && (p[1] & 0x20) != 0)
276             break;      /* d800-dfff surrogate */
277           if (x == 0xef && p[1] == 0xbf && (p[2] == 0xbe || p[2] == 0xbf))
278             break;      /* fffe or ffff */
279           p += 2;
280           continue;
281         }
282       if (x < 0xf8)
283         {
284           /* three bytes to follow */
285           if ((p[1] & 0xc0) != 0x80 || (p[2] & 0xc0) != 0x80 || (p[3] & 0xc0) != 0x80)
286             break;
287           if ((x & 0x07) == 0 && (p[1] & 0x30) == 0)
288             break;      /* not minimal */
289           if ((x & 0x07) > 4 || ((x & 0x07) == 4 && (p[1] & 0x30) != 0))
290             break;      /* above 0x10ffff */
291           p += 3;
292           continue;
293         }
294       break;    /* maybe valid utf8, but above 0x10ffff */
295     }
296   return (const char *)p - buf;
297 }
298
299 char *
300 solv_latin1toutf8(const char *buf)
301 {
302   int l = 1;
303   const char *p;
304   char *r, *rp;
305
306   for (p = buf; *p; p++)
307     if ((*(const unsigned char *)p & 128) != 0)
308       l++;
309   r = rp = solv_malloc(p - buf + l);
310   for (p = buf; *p; p++)
311     {
312       if ((*(const unsigned char *)p & 128) != 0)
313         {
314           *rp++ = *(const unsigned char *)p & 64 ? 0xc3 : 0xc2;
315           *rp++ = *p & 0xbf;
316         }
317       else
318         *rp++ = *p;
319     }
320   *rp = 0;
321   return r;
322 }
323
324 char *
325 solv_replacebadutf8(const char *buf, int replchar)
326 {
327   size_t l, nl;
328   const char *p;
329   char *r = 0, *rp = 0;
330   int repllen, replin;
331
332   if (replchar < 0 || replchar > 0x10ffff)
333     replchar = 0xfffd;
334   if (!replchar)
335     repllen = replin = 0;
336   else if (replchar < 0x80)
337     {
338       repllen = 1;
339       replin = (replchar & 0x40) | 0x80;
340     }
341   else if (replchar < 0x800)
342     {
343       repllen = 2;
344       replin = 0x40;
345     }
346   else if (replchar < 0x10000)
347     {
348       repllen = 3;
349       replin = 0x60;
350     }
351   else
352     {
353       repllen = 4;
354       replin = 0x70;
355     }
356   for (;;)
357     {
358       for (p = buf, nl = 0; *p; )
359         {
360           l = solv_validutf8(p);
361           if (rp && l)
362             {
363               memcpy(rp, p, l);
364               rp += l;
365             }
366           nl += l;
367           p += l;
368           if (!*p)
369             break;
370           /* found a bad char, replace with replchar */
371           if (rp && replchar)
372             {
373               switch (repllen)
374                 {
375                 case 4:
376                   *rp++ = (replchar >> 18 & 0x3f) | 0x80;
377                 case 3:
378                   *rp++ = (replchar >> 12 & 0x3f) | 0x80;
379                 case 2:
380                   *rp++ = (replchar >> 6  & 0x3f) | 0x80;
381                 default:
382                   *rp++ = (replchar       & 0x3f) | 0x80;
383                 }
384               rp[-repllen] ^= replin;
385             }
386           nl += repllen;
387           p++;
388           while ((*(const unsigned char *)p & 0xc0) == 0x80)
389             p++;
390         }
391       if (rp)
392         break;
393       r = rp = solv_malloc(nl + 1);
394     }
395   *rp = 0;
396   return r;
397 }
398