1 /*
2 * libzvbi -- Miscellaneous cows and chickens
3 *
4 * Copyright (C) 2000-2003 I�aki Garc�a Etxebarria
5 * Copyright (C) 2001-2007 Michael H. Schimek
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301 USA.
21 */
22
23 /* $Id: misc.c,v 1.13 2008/02/19 00:35:20 mschimek Exp $ */
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <ctype.h>
30 #include <errno.h>
31
32 #include "misc.h"
33
34 #ifdef ZAPPING8
35 const char vbi_intl_domainname[] = PACKAGE;
36 #else
37 # include "version.h"
38 # if 2 == VBI_VERSION_MINOR
39 const char _zvbi_intl_domainname[] = PACKAGE;
40 # else
41 const char vbi_intl_domainname[] = PACKAGE;
42 # endif
43 #endif
44
45 _vbi_log_hook _vbi_global_log;
46
47 /**
48 * @internal
49 * Number of set bits.
50 */
51 unsigned int
_vbi_popcnt(uint32_t x)52 _vbi_popcnt (uint32_t x)
53 {
54 x -= ((x >> 1) & 0x55555555);
55 x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
56 x = (x + (x >> 4)) & 0x0F0F0F0F;
57 return ((uint32_t)(x * 0x01010101)) >> 24;
58 }
59
60 /**
61 * @internal
62 * @param dst The string will be stored in this buffer.
63 * @param src NUL-terminated string to be copied.
64 * @param size Maximum number of bytes to be copied, including the
65 * terminating NUL (i.e. this is the size of the @a dst buffer).
66 *
67 * Copies @a src to @a dst, but no more than @a size - 1 characters.
68 * Always NUL-terminates @a dst, unless @a size is zero.
69 *
70 * strlcpy() is a BSD extension. Don't call this function
71 * directly, we #define strlcpy if necessary.
72 *
73 * @returns
74 * strlen (src).
75 */
76 size_t
_vbi_strlcpy(char * dst,const char * src,size_t size)77 _vbi_strlcpy (char * dst,
78 const char * src,
79 size_t size)
80 {
81 const char *src1;
82
83 assert (NULL != dst);
84 assert (NULL != src);
85
86 src1 = src;
87
88 if (likely (size > 1)) {
89 char *end = dst + size - 1;
90
91 do {
92 if (unlikely (0 == (*dst++ = *src++)))
93 goto finish;
94 } while (dst < end);
95
96 *dst = 0;
97 } else if (size > 0) {
98 *dst = 0;
99 }
100
101 while (*src++)
102 ;
103
104 finish:
105 return src - src1 - 1;
106 }
107
108 /**
109 * @internal
110 * strndup() is a BSD/GNU extension. Don't call this function
111 * directly, we #define strndup if necessary.
112 */
113 char *
_vbi_strndup(const char * s,size_t len)114 _vbi_strndup (const char * s,
115 size_t len)
116 {
117 size_t n;
118 char *r;
119
120 if (NULL == s)
121 return NULL;
122
123 n = strlen (s);
124 len = MIN (len, n);
125
126 r = vbi_malloc (len + 1);
127
128 if (r) {
129 memcpy (r, s, len);
130 r[len] = 0;
131 }
132
133 return r;
134 }
135
136 /**
137 * @internal
138 * vasprintf() is a BSD/GNU extension. Don't call this function
139 * directly, we #define vasprintf if necessary.
140 */
141 int
_vbi_vasprintf(char ** dstp,const char * templ,va_list ap)142 _vbi_vasprintf (char ** dstp,
143 const char * templ,
144 va_list ap)
145 {
146 char *buf;
147 unsigned long size;
148 va_list ap2;
149 int temp;
150
151 assert (NULL != dstp);
152 assert (NULL != templ);
153
154 temp = errno;
155
156 buf = NULL;
157 size = 64;
158
159 __va_copy (ap2, ap);
160
161 for (;;) {
162
163 char *buf2;
164 long len;
165
166 if (!(buf2 = vbi_realloc (buf, size)))
167 break;
168
169 buf = buf2;
170
171 len = vsnprintf (buf, size, templ, ap);
172
173 if (len < 0) {
174 /* Not enough. */
175 size *= 2;
176 } else if ((unsigned long) len < size) {
177 *dstp = buf;
178 errno = temp;
179 return len;
180 } else {
181 /* Size needed. */
182 size = len + 1;
183 }
184
185 /* vsnprintf() may advance ap. */
186 __va_copy (ap, ap2);
187 }
188
189 vbi_free (buf);
190 buf = NULL;
191
192 /* According to "man 3 asprintf" GNU's version leaves *dstp
193 undefined on error, so don't count on it. FreeBSD's
194 asprintf NULLs *dstp, which is safer. */
195 *dstp = NULL;
196 errno = temp;
197
198 return -1;
199 }
200
201 /**
202 * @internal
203 * asprintf() is a GNU extension. Don't call this function
204 * directly, we #define asprintf if necessary.
205 */
206 int
_vbi_asprintf(char ** dstp,const char * templ,...)207 _vbi_asprintf (char ** dstp,
208 const char * templ,
209 ...)
210 {
211 va_list ap;
212 int len;
213
214 va_start (ap, templ);
215
216 /* May fail, returning -1. */
217 len = vasprintf (dstp, templ, ap);
218
219 va_end (ap);
220
221 return len;
222 }
223
224 /** @internal */
225 vbi_bool
_vbi_keyword_lookup(int * value,const char ** inout_s,const _vbi_key_value_pair * table,unsigned int n_pairs)226 _vbi_keyword_lookup (int * value,
227 const char ** inout_s,
228 const _vbi_key_value_pair *table,
229 unsigned int n_pairs)
230 {
231 const char *s;
232 unsigned int i;
233
234 assert (NULL != value);
235 assert (NULL != inout_s);
236 assert (NULL != *inout_s);
237 assert (NULL != table);
238
239 s = *inout_s;
240
241 while (isspace (*s))
242 ++s;
243
244 if (isdigit (*s)) {
245 long val;
246 char *end;
247
248 val = strtol (s, &end, 10);
249
250 for (i = 0; NULL != table[i].key; ++i) {
251 if (val == table[i].value) {
252 *value = val;
253 *inout_s = end;
254 return TRUE;
255 }
256 }
257 } else {
258 for (i = 0; i < n_pairs; ++i) {
259 size_t len = strlen (table[i].key);
260
261 if (0 == strncasecmp (s, table[i].key, len)
262 && !isalnum (s[len])) {
263 *value = table[i].value;
264 *inout_s = s + len;
265 return TRUE;
266 }
267 }
268 }
269
270 return FALSE;
271 }
272
273 void
_vbi_shrink_vector_capacity(void ** vector,size_t * capacity,size_t min_capacity,size_t element_size)274 _vbi_shrink_vector_capacity (void ** vector,
275 size_t * capacity,
276 size_t min_capacity,
277 size_t element_size)
278 {
279 void *new_vec;
280 size_t new_capacity;
281
282 if (min_capacity >= *capacity)
283 return;
284
285 new_capacity = min_capacity;
286
287 new_vec = vbi_realloc (*vector, new_capacity * element_size);
288 if (unlikely (NULL == new_vec))
289 return;
290
291 *vector = new_vec;
292 *capacity = new_capacity;
293 }
294
295 vbi_bool
_vbi_grow_vector_capacity(void ** vector,size_t * capacity,size_t min_capacity,size_t element_size)296 _vbi_grow_vector_capacity (void ** vector,
297 size_t * capacity,
298 size_t min_capacity,
299 size_t element_size)
300 {
301 void *new_vec;
302 size_t old_capacity;
303 size_t new_capacity;
304 size_t max_capacity;
305
306 assert (min_capacity > 0);
307 assert (element_size > 0);
308
309 max_capacity = SIZE_MAX / element_size;
310
311 if (unlikely (min_capacity > max_capacity)) {
312 goto failed;
313 }
314
315 old_capacity = *capacity;
316
317 if (unlikely (old_capacity > max_capacity - (1 << 16))) {
318 new_capacity = max_capacity;
319 } else if (old_capacity >= (1 << 16)) {
320 new_capacity = MAX (min_capacity, old_capacity + (1 << 16));
321 } else {
322 new_capacity = MAX (min_capacity, old_capacity * 2);
323 }
324
325 new_vec = vbi_realloc (*vector, new_capacity * element_size);
326 if (unlikely (NULL == new_vec)) {
327 if (new_capacity <= min_capacity)
328 goto failed;
329
330 new_capacity = min_capacity;
331
332 new_vec = vbi_realloc (*vector, new_capacity * element_size);
333 if (unlikely (NULL == new_vec))
334 goto failed;
335 }
336
337 *vector = new_vec;
338 *capacity = new_capacity;
339
340 return TRUE;
341
342 failed:
343 errno = ENOMEM;
344
345 return FALSE;
346 }
347
348 /**
349 * @ingroup Basic
350 *
351 * Log function printing messages on standard output.
352 *
353 * @since 0.2.22
354 */
355 void
vbi_log_on_stderr(vbi_log_mask level,const char * context,const char * message,void * user_data)356 vbi_log_on_stderr (vbi_log_mask level,
357 const char * context,
358 const char * message,
359 void * user_data)
360 {
361 vbi_log_mask max_level;
362
363 /* This function exists in libzvbi 0.2 with vbi_ prefix and
364 in libzvbi 0.3 and Zapping with vbi_ prefix (so I can
365 use both versions in Zapping until 0.3 is finished). */
366 if (0 == strncmp (context, "vbi_", 4)) {
367 context += 4;
368 /* Not "vbi_" to prevent an accidental s/vbi_/vbi_. */
369 } else if (0 == strncmp (context, "vbi" "3_", 5)) {
370 context += 5;
371 }
372
373 if (NULL != user_data) {
374 max_level = * (vbi_log_mask *) user_data;
375 if (level > max_level)
376 return;
377 }
378
379 fprintf (stderr, "libzvbi:%s: %s\n", context, message);
380 }
381
382 /** @internal */
383 void
_vbi_log_vprintf(vbi_log_fn log_fn,void * user_data,vbi_log_mask mask,const char * source_file,const char * context,const char * templ,va_list ap)384 _vbi_log_vprintf (vbi_log_fn log_fn,
385 void * user_data,
386 vbi_log_mask mask,
387 const char * source_file,
388 const char * context,
389 const char * templ,
390 va_list ap)
391 {
392 char ctx_buffer[160];
393 char *msg_buffer;
394 int saved_errno;
395 unsigned int i;
396 int r;
397
398 assert (NULL != source_file);
399 assert (NULL != context);
400 assert (NULL != templ);
401
402 if (NULL == log_fn)
403 return;
404
405 saved_errno = errno;
406
407 for (i = 0; i < N_ELEMENTS (ctx_buffer) - 2; ++i) {
408 int c = source_file[i];
409
410 if ('.' == c)
411 break;
412
413 ctx_buffer[i] = c;
414 }
415
416 ctx_buffer[i++] = ':';
417
418 strlcpy (ctx_buffer + i, context,
419 N_ELEMENTS (ctx_buffer) - i);
420
421 r = vasprintf (&msg_buffer, templ, ap);
422 if (r > 1 && NULL != msg_buffer) {
423 log_fn (mask, ctx_buffer, msg_buffer, user_data);
424
425 vbi_free (msg_buffer);
426 msg_buffer = NULL;
427 }
428
429 errno = saved_errno;
430 }
431
432 /** @internal */
433 void
_vbi_log_printf(vbi_log_fn log_fn,void * user_data,vbi_log_mask mask,const char * source_file,const char * context,const char * templ,...)434 _vbi_log_printf (vbi_log_fn log_fn,
435 void * user_data,
436 vbi_log_mask mask,
437 const char * source_file,
438 const char * context,
439 const char * templ,
440 ...)
441 {
442 va_list ap;
443
444 va_start (ap, templ);
445
446 _vbi_log_vprintf (log_fn, user_data, mask,
447 source_file, context, templ, ap);
448
449 va_end (ap);
450 }
451
452 /*
453 Local variables:
454 c-set-style: K&R
455 c-basic-offset: 8
456 End:
457 */
458