Imported Upstream version 0.6.27
[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 /* this was solv_realloc2(old, len, size), but we now overshoot
80  * for huge len sizes */
81 void *
82 solv_extend_realloc(void *old, size_t len, size_t size, size_t block)
83 {
84   size_t xblock = (block + 1) << 5;
85   len = (len + block) & ~block;
86   if (len >= xblock && xblock)
87     {
88       xblock <<= 1;
89       while (len >= xblock && xblock)
90         xblock <<= 1;
91       if (xblock)
92         {
93           size_t nlen;
94           xblock = (xblock >> 5) - 1;
95           nlen = (len + xblock) & ~xblock;
96           if (nlen > len)
97             len = nlen;
98         }
99     }
100   return solv_realloc2(old, len, size);
101 }
102
103 void *
104 solv_free(void *mem)
105 {
106   if (mem)
107     free(mem);
108   return 0;
109 }
110
111 char *
112 solv_strdup(const char *s)
113 {
114   char *r;
115   if (!s)
116     return 0;
117   r = strdup(s);
118   if (!r)
119     solv_oom(0, strlen(s));
120   return r;
121 }
122
123 unsigned int
124 solv_timems(unsigned int subtract)
125 {
126   struct timeval tv;
127   unsigned int r;
128
129   if (gettimeofday(&tv, 0))
130     return 0;
131   r = (((unsigned int)tv.tv_sec >> 16) * 1000) << 16;
132   r += ((unsigned int)tv.tv_sec & 0xffff) * 1000;
133   r += (unsigned int)tv.tv_usec / 1000;
134   return r - subtract;
135 }
136
137 /* bsd's qsort_r has different arguments, so we define our
138    own version in case we need to do some clever mapping
139
140    see also: http://sources.redhat.com/ml/libc-alpha/2008-12/msg00003.html
141  */
142 #if defined(__GLIBC__) && (defined(HAVE_QSORT_R) || defined(HAVE___QSORT_R))
143
144 void
145 solv_sort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *, void *), void *compard)
146 {
147 # if defined(HAVE_QSORT_R)
148   qsort_r(base, nmemb, size, compar, compard);
149 # else
150   /* backported for SLE10-SP2 */
151   __qsort_r(base, nmemb, size, compar, compard);
152 # endif
153
154 }
155
156 #elif defined(HAVE_QSORT_R) /* not glibc, but has qsort_r() */
157
158 struct solv_sort_data {
159   int (*compar)(const void *, const void *, void *);
160   void *compard;
161 };
162
163 static int
164 solv_sort_helper(void *compard, const void *a, const void *b)
165 {
166   struct solv_sort_data *d = compard;
167   return (*d->compar)(a, b, d->compard);
168 }
169
170 void
171 solv_sort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *, void *), void *compard)
172 {
173   struct solv_sort_data d;
174   d.compar = compar;
175   d.compard = compard;
176   qsort_r(base, nmemb, size, &d, solv_sort_helper);
177 }
178
179 #else /* not glibc and no qsort_r() */
180 /* use own version of qsort if none available */
181 #include "qsort_r.c"
182 #endif
183
184 char *
185 solv_dupjoin(const char *str1, const char *str2, const char *str3)
186 {
187   int l1, l2, l3;
188   char *s, *str;
189   l1 = str1 ? strlen(str1) : 0;
190   l2 = str2 ? strlen(str2) : 0;
191   l3 = str3 ? strlen(str3) : 0;
192   s = str = solv_malloc(l1 + l2 + l3 + 1);
193   if (l1)
194     {
195       strcpy(s, str1);
196       s += l1;
197     }
198   if (l2)
199     {
200       strcpy(s, str2);
201       s += l2;
202     }
203   if (l3)
204     {
205       strcpy(s, str3);
206       s += l3;
207     }
208   *s = 0;
209   return str;
210 }
211
212 char *
213 solv_dupappend(const char *str1, const char *str2, const char *str3)
214 {
215   char *str = solv_dupjoin(str1, str2, str3);
216   solv_free((void *)str1);
217   return str;
218 }
219
220 int
221 solv_hex2bin(const char **strp, unsigned char *buf, int bufl)
222 {
223   const char *str = *strp;
224   int i;
225
226   for (i = 0; i < bufl; i++)
227     {
228       int c = *str;
229       int d;
230       if (c >= '0' && c <= '9')
231         d = c - '0';
232       else if (c >= 'a' && c <= 'f')
233         d = c - ('a' - 10);
234       else if (c >= 'A' && c <= 'F')
235         d = c - ('A' - 10);
236       else
237         break;
238       c = str[1];
239       d <<= 4;
240       if (c >= '0' && c <= '9')
241         d |= c - '0';
242       else if (c >= 'a' && c <= 'f')
243         d |= c - ('a' - 10);
244       else if (c >= 'A' && c <= 'F')
245         d |= c - ('A' - 10);
246       else
247         break;
248       buf[i] = d;
249       str += 2;
250     }
251   *strp = str;
252   return i;
253 }
254
255 char *
256 solv_bin2hex(const unsigned char *buf, int l, char *str)
257 {
258   int i;
259   for (i = 0; i < l; i++, buf++)
260     {
261       int c = *buf >> 4;
262       *str++ = c < 10 ? c + '0' : c + ('a' - 10);
263       c = *buf & 15;
264       *str++ = c < 10 ? c + '0' : c + ('a' - 10);
265     }
266   *str = 0;
267   return str;
268 }
269
270 size_t
271 solv_validutf8(const char *buf)
272 {
273   const unsigned char *p;
274   int x;
275
276   for (p = (const unsigned char *)buf; (x = *p) != 0; p++)
277     {
278       if (x < 0x80)
279         continue;
280       if (x < 0xc0)
281         break;
282       if (x < 0xe0)
283         {
284           /* one byte to follow */
285           if ((p[1] & 0xc0) != 0x80)
286             break;
287           if ((x & 0x1e) == 0)
288             break;      /* not minimal */
289           p += 1;
290           continue;
291         }
292       if (x < 0xf0)
293         {
294           /* two bytes to follow */
295           if ((p[1] & 0xc0) != 0x80 || (p[2] & 0xc0) != 0x80)
296             break;
297           if ((x & 0x0f) == 0 && (p[1] & 0x20) == 0)
298             break;      /* not minimal */
299           if (x == 0xed && (p[1] & 0x20) != 0)
300             break;      /* d800-dfff surrogate */
301           if (x == 0xef && p[1] == 0xbf && (p[2] == 0xbe || p[2] == 0xbf))
302             break;      /* fffe or ffff */
303           p += 2;
304           continue;
305         }
306       if (x < 0xf8)
307         {
308           /* three bytes to follow */
309           if ((p[1] & 0xc0) != 0x80 || (p[2] & 0xc0) != 0x80 || (p[3] & 0xc0) != 0x80)
310             break;
311           if ((x & 0x07) == 0 && (p[1] & 0x30) == 0)
312             break;      /* not minimal */
313           if ((x & 0x07) > 4 || ((x & 0x07) == 4 && (p[1] & 0x30) != 0))
314             break;      /* above 0x10ffff */
315           p += 3;
316           continue;
317         }
318       break;    /* maybe valid utf8, but above 0x10ffff */
319     }
320   return (const char *)p - buf;
321 }
322
323 char *
324 solv_latin1toutf8(const char *buf)
325 {
326   int l = 1;
327   const char *p;
328   char *r, *rp;
329
330   for (p = buf; *p; p++)
331     if ((*(const unsigned char *)p & 128) != 0)
332       l++;
333   r = rp = solv_malloc(p - buf + l);
334   for (p = buf; *p; p++)
335     {
336       if ((*(const unsigned char *)p & 128) != 0)
337         {
338           *rp++ = *(const unsigned char *)p & 64 ? 0xc3 : 0xc2;
339           *rp++ = *p & 0xbf;
340         }
341       else
342         *rp++ = *p;
343     }
344   *rp = 0;
345   return r;
346 }
347
348 char *
349 solv_replacebadutf8(const char *buf, int replchar)
350 {
351   size_t l, nl;
352   const char *p;
353   char *r = 0, *rp = 0;
354   int repllen, replin;
355
356   if (replchar < 0 || replchar > 0x10ffff)
357     replchar = 0xfffd;
358   if (!replchar)
359     repllen = replin = 0;
360   else if (replchar < 0x80)
361     {
362       repllen = 1;
363       replin = (replchar & 0x40) | 0x80;
364     }
365   else if (replchar < 0x800)
366     {
367       repllen = 2;
368       replin = 0x40;
369     }
370   else if (replchar < 0x10000)
371     {
372       repllen = 3;
373       replin = 0x60;
374     }
375   else
376     {
377       repllen = 4;
378       replin = 0x70;
379     }
380   for (;;)
381     {
382       for (p = buf, nl = 0; *p; )
383         {
384           l = solv_validutf8(p);
385           if (rp && l)
386             {
387               memcpy(rp, p, l);
388               rp += l;
389             }
390           nl += l;
391           p += l;
392           if (!*p)
393             break;
394           /* found a bad char, replace with replchar */
395           if (rp && replchar)
396             {
397               switch (repllen)
398                 {
399                 case 4:
400                   *rp++ = (replchar >> 18 & 0x3f) | 0x80;
401                 case 3:
402                   *rp++ = (replchar >> 12 & 0x3f) | 0x80;
403                 case 2:
404                   *rp++ = (replchar >> 6  & 0x3f) | 0x80;
405                 default:
406                   *rp++ = (replchar       & 0x3f) | 0x80;
407                 }
408               rp[-repllen] ^= replin;
409             }
410           nl += repllen;
411           p++;
412           while ((*(const unsigned char *)p & 0xc0) == 0x80)
413             p++;
414         }
415       if (rp)
416         break;
417       r = rp = solv_malloc(nl + 1);
418     }
419   *rp = 0;
420   return r;
421 }
422