/* * Copyright (c) 2007, Novell Inc. * * This program is licensed under the BSD license, read LICENSE.BSD * for further information */ #define _GNU_SOURCE #include #include #include #include #include #include "util.h" void solv_oom(size_t num, size_t len) { if (num) fprintf(stderr, "Out of memory allocating %zu*%zu bytes!\n", num, len); else fprintf(stderr, "Out of memory allocating %zu bytes!\n", len); abort(); exit(1); } void * solv_malloc(size_t len) { void *r = malloc(len ? len : 1); if (!r) solv_oom(0, len); return r; } void * solv_malloc2(size_t num, size_t len) { if (len && (num * len) / len != num) solv_oom(num, len); return solv_malloc(num * len); } void * solv_realloc(void *old, size_t len) { if (old == 0) old = malloc(len ? len : 1); else old = realloc(old, len ? len : 1); if (!old) solv_oom(0, len); return old; } void * solv_realloc2(void *old, size_t num, size_t len) { if (len && (num * len) / len != num) solv_oom(num, len); return solv_realloc(old, num * len); } void * solv_calloc(size_t num, size_t len) { void *r; if (num == 0 || len == 0) r = malloc(1); else r = calloc(num, len); if (!r) solv_oom(num, len); return r; } /* this was solv_realloc2(old, len, size), but we now overshoot * for huge len sizes */ void * solv_extend_realloc(void *old, size_t len, size_t size, size_t block) { size_t xblock = (block + 1) << 5; len = (len + block) & ~block; if (len >= xblock && xblock) { xblock <<= 1; while (len >= xblock && xblock) xblock <<= 1; if (xblock) { size_t nlen; xblock = (xblock >> 5) - 1; nlen = (len + xblock) & ~xblock; if (nlen > len) len = nlen; } } return solv_realloc2(old, len, size); } void * solv_free(void *mem) { if (mem) free(mem); return 0; } char * solv_strdup(const char *s) { char *r; if (!s) return 0; r = strdup(s); if (!r) solv_oom(0, strlen(s)); return r; } unsigned int solv_timems(unsigned int subtract) { struct timeval tv; unsigned int r; if (gettimeofday(&tv, 0)) return 0; r = (((unsigned int)tv.tv_sec >> 16) * 1000) << 16; r += ((unsigned int)tv.tv_sec & 0xffff) * 1000; r += (unsigned int)tv.tv_usec / 1000; return r - subtract; } /* bsd's qsort_r has different arguments, so we define our own version in case we need to do some clever mapping see also: http://sources.redhat.com/ml/libc-alpha/2008-12/msg00003.html */ #if (defined(__GLIBC__) || defined(__NEWLIB__)) && (defined(HAVE_QSORT_R) || defined(HAVE___QSORT_R)) void solv_sort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *, void *), void *compard) { # if defined(HAVE_QSORT_R) qsort_r(base, nmemb, size, compar, compard); # else /* backported for SLE10-SP2 */ __qsort_r(base, nmemb, size, compar, compard); # endif } #elif defined(HAVE_QSORT_R) /* not glibc, but has qsort_r() */ struct solv_sort_data { int (*compar)(const void *, const void *, void *); void *compard; }; static int solv_sort_helper(void *compard, const void *a, const void *b) { struct solv_sort_data *d = compard; return (*d->compar)(a, b, d->compard); } void solv_sort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *, void *), void *compard) { struct solv_sort_data d; d.compar = compar; d.compard = compard; qsort_r(base, nmemb, size, &d, solv_sort_helper); } #else /* not glibc and no qsort_r() */ /* use own version of qsort if none available */ #include "qsort_r.c" #endif char * solv_dupjoin(const char *str1, const char *str2, const char *str3) { int l1, l2, l3; char *s, *str; l1 = str1 ? strlen(str1) : 0; l2 = str2 ? strlen(str2) : 0; l3 = str3 ? strlen(str3) : 0; s = str = solv_malloc(l1 + l2 + l3 + 1); if (l1) { strcpy(s, str1); s += l1; } if (l2) { strcpy(s, str2); s += l2; } if (l3) { strcpy(s, str3); s += l3; } *s = 0; return str; } char * solv_dupappend(const char *str1, const char *str2, const char *str3) { char *str = solv_dupjoin(str1, str2, str3); solv_free((void *)str1); return str; } int solv_hex2bin(const char **strp, unsigned char *buf, int bufl) { const char *str = *strp; int i; for (i = 0; i < bufl; i++) { int c = *str; int d; if (c >= '0' && c <= '9') d = c - '0'; else if (c >= 'a' && c <= 'f') d = c - ('a' - 10); else if (c >= 'A' && c <= 'F') d = c - ('A' - 10); else break; c = str[1]; d <<= 4; if (c >= '0' && c <= '9') d |= c - '0'; else if (c >= 'a' && c <= 'f') d |= c - ('a' - 10); else if (c >= 'A' && c <= 'F') d |= c - ('A' - 10); else break; buf[i] = d; str += 2; } *strp = str; return i; } char * solv_bin2hex(const unsigned char *buf, int l, char *str) { int i; for (i = 0; i < l; i++, buf++) { int c = *buf >> 4; *str++ = c < 10 ? c + '0' : c + ('a' - 10); c = *buf & 15; *str++ = c < 10 ? c + '0' : c + ('a' - 10); } *str = 0; return str; } size_t solv_validutf8(const char *buf) { const unsigned char *p; int x; for (p = (const unsigned char *)buf; (x = *p) != 0; p++) { if (x < 0x80) continue; if (x < 0xc0) break; if (x < 0xe0) { /* one byte to follow */ if ((p[1] & 0xc0) != 0x80) break; if ((x & 0x1e) == 0) break; /* not minimal */ p += 1; continue; } if (x < 0xf0) { /* two bytes to follow */ if ((p[1] & 0xc0) != 0x80 || (p[2] & 0xc0) != 0x80) break; if ((x & 0x0f) == 0 && (p[1] & 0x20) == 0) break; /* not minimal */ if (x == 0xed && (p[1] & 0x20) != 0) break; /* d800-dfff surrogate */ if (x == 0xef && p[1] == 0xbf && (p[2] == 0xbe || p[2] == 0xbf)) break; /* fffe or ffff */ p += 2; continue; } if (x < 0xf8) { /* three bytes to follow */ if ((p[1] & 0xc0) != 0x80 || (p[2] & 0xc0) != 0x80 || (p[3] & 0xc0) != 0x80) break; if ((x & 0x07) == 0 && (p[1] & 0x30) == 0) break; /* not minimal */ if ((x & 0x07) > 4 || ((x & 0x07) == 4 && (p[1] & 0x30) != 0)) break; /* above 0x10ffff */ p += 3; continue; } break; /* maybe valid utf8, but above 0x10ffff */ } return (const char *)p - buf; } char * solv_latin1toutf8(const char *buf) { int l = 1; const char *p; char *r, *rp; for (p = buf; *p; p++) if ((*(const unsigned char *)p & 128) != 0) l++; r = rp = solv_malloc(p - buf + l); for (p = buf; *p; p++) { if ((*(const unsigned char *)p & 128) != 0) { *rp++ = *(const unsigned char *)p & 64 ? 0xc3 : 0xc2; *rp++ = *p & 0xbf; } else *rp++ = *p; } *rp = 0; return r; } char * solv_replacebadutf8(const char *buf, int replchar) { size_t l, nl; const char *p; char *r = 0, *rp = 0; int repllen, replin; if (replchar < 0 || replchar > 0x10ffff) replchar = 0xfffd; if (!replchar) repllen = replin = 0; else if (replchar < 0x80) { repllen = 1; replin = (replchar & 0x40) | 0x80; } else if (replchar < 0x800) { repllen = 2; replin = 0x40; } else if (replchar < 0x10000) { repllen = 3; replin = 0x60; } else { repllen = 4; replin = 0x70; } for (;;) { for (p = buf, nl = 0; *p; ) { l = solv_validutf8(p); if (rp && l) { memcpy(rp, p, l); rp += l; } nl += l; p += l; if (!*p) break; /* found a bad char, replace with replchar */ if (rp && replchar) { switch (repllen) { case 4: *rp++ = (replchar >> 18 & 0x3f) | 0x80; case 3: *rp++ = (replchar >> 12 & 0x3f) | 0x80; case 2: *rp++ = (replchar >> 6 & 0x3f) | 0x80; default: *rp++ = (replchar & 0x3f) | 0x80; } rp[-repllen] ^= replin; } nl += repllen; p++; while ((*(const unsigned char *)p & 0xc0) == 0x80) p++; } if (rp) break; r = rp = solv_malloc(nl + 1); } *rp = 0; return r; }