Imported Upstream version 3.2.0
[debian/amanda] / common-src / glib-util.c
1 /*
2  * Copyright (c) 2007, 2008, 2009, 2010 Zmanda, Inc.  All Rights Reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License version 2 as published
6  * by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
11  * for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16  *
17  * Contact information: Zmanda Inc., 465 S. Mathilda Ave., Suite 300
18  * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
19  */
20
21 /*
22  * Utilities that aren't quite included in glib
23  *
24  * Author: Dustin J. Mitchell <dustin@zmanda.com>, Ian Turner <ian@zmanda.com>
25  */
26
27 #include "amanda.h"
28 #include "glib-util.h"
29 #include "conffile.h" /* For find_multiplier. */
30
31 #ifdef HAVE_LIBCURL
32 #include <curl/curl.h>
33 #endif
34
35 void
36 glib_init(void) {
37     static gboolean did_glib_init = FALSE;
38     if (did_glib_init) return;
39     did_glib_init = TRUE;
40
41     /* set up libcurl (this must happen before threading 
42      * is initialized) */
43 #ifdef HAVE_LIBCURL
44 # ifdef G_THREADS_ENABLED
45     g_assert(!g_thread_supported()); /* assert threads aren't initialized yet */
46 # endif
47     g_assert(curl_global_init(CURL_GLOBAL_ALL) == 0);
48 #endif
49
50     /* do a version check */
51 #if GLIB_CHECK_VERSION(2,6,0)
52     {
53         const char *glib_err = glib_check_version(GLIB_MAJOR_VERSION,
54                                                   GLIB_MINOR_VERSION,
55                                                   GLIB_MICRO_VERSION);
56         if (glib_err) {
57             error(_("%s: Amanda was compiled with glib-%d.%d.%d"), glib_err,
58                     GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION);
59             exit(1); /* glib_init may be called before error handling is set up */
60         }
61     }
62 #endif
63
64     /* Initialize glib's type system.  On glib >= 2.24, this will initialize
65      * threads, so it must be done after curl is initialized. */
66     g_type_init();
67
68     /* And set up glib's threads */
69 #if defined(G_THREADS_ENABLED) && !defined(G_THREADS_IMPL_NONE)
70     if (!g_thread_supported())
71         g_thread_init(NULL);
72 #endif
73 }
74
75 typedef enum {
76     FLAG_STRING_NAME,
77     FLAG_STRING_SHORT_NAME,
78     FLAG_STRING_NICK
79 } FlagString;
80
81 static char ** g_flags_to_strv(int value, GType type, FlagString source);
82
83 void
84 _glib_util_foreach_glue(gpointer data, gpointer func)
85 {
86     void (*one_arg_fn)(gpointer) = (void (*)(gpointer))func;
87     one_arg_fn(data);
88 }
89
90 GValue* g_value_unset_init(GValue* value, GType type) {
91     g_return_val_if_fail(value != NULL, NULL);
92
93     if (G_IS_VALUE(value)) {
94         g_value_unset(value);
95     }
96     g_value_init(value, type);
97     return value;
98 }
99
100 GValue* g_value_unset_copy(const GValue * from, GValue * to) {
101     g_return_val_if_fail(from != NULL, NULL);
102     g_return_val_if_fail(to != NULL, NULL);
103
104     g_value_unset_init(to, G_VALUE_TYPE(from));
105     g_value_copy(from, to);
106     return to;
107 }
108
109 void g_list_free_full(GList * list) {
110     GList * cur = list;
111
112     while (cur != NULL) {
113         gpointer data = cur->data;
114         amfree(data);
115         cur = g_list_next(cur);
116     }
117
118     g_list_free(list);
119 }
120
121 void g_slist_free_full(GSList * list) {
122     GSList * cur = list;
123
124     while (cur != NULL) {
125         gpointer data = cur->data;
126         amfree(data);
127         cur = g_slist_next(cur);
128     }
129
130     g_slist_free(list);
131 }
132
133 void g_slist_free_full_gpointer(gpointer list) {
134     g_slist_free_full((GSList *)list);
135 }
136
137 void g_queue_free_full(GQueue * queue) {
138     while (!g_queue_is_empty(queue)) {
139         gpointer data;
140         data = g_queue_pop_head(queue);
141         amfree(data);
142     }
143     g_queue_free(queue);
144 }
145
146 void g_ptr_array_free_full(GPtrArray * array) {
147     size_t i;
148
149     for (i = 0; i < array->len; i ++) {
150         amfree(g_ptr_array_index(array, i));
151     }
152     g_ptr_array_free(array, TRUE);
153 }
154
155 gboolean g_value_compare(GValue * a, GValue * b) {
156     if (a == NULL && b == NULL)
157         return TRUE;
158     if (a == NULL || b == NULL)
159         return FALSE;
160     if (G_VALUE_TYPE(a) != G_VALUE_TYPE(b))
161         return FALSE;
162     if (g_value_fits_pointer(a) && g_value_fits_pointer(b)) {
163         return g_value_peek_pointer(a) == g_value_peek_pointer(b);
164     } else {
165         /* Since there is no builtin comparison function, we resort to
166            comparing serialized strings. Yuck. */
167         char * a_str;
168         char * b_str;
169         gboolean rval;
170         a_str = g_strdup_value_contents(a);
171         b_str = g_strdup_value_contents(b);
172         rval = (0 == strcmp(a_str, b_str));
173         amfree(a_str);
174         amfree(b_str);
175         return rval;
176     }
177     
178     g_assert_not_reached();
179 }
180
181 static gboolean
182 g_value_set_boolean_from_string(
183     GValue * val,
184     char * str)
185 {
186     int b = string_to_boolean(str);
187
188     if (b == -1)
189         return FALSE;
190
191     g_value_set_boolean(val, b);
192     return TRUE;
193 }
194
195 static gboolean g_value_set_int_from_string(GValue * val, char * string) {
196     long int strto_result;
197     char * strto_end;
198     gint64 multiplier;
199     strto_result = strtol(string, &strto_end, 0);
200     multiplier = find_multiplier(strto_end);
201     if (multiplier == G_MAXINT64) {
202         if (strto_result >= 0) {
203             g_value_set_int(val, G_MAXINT);
204         } else {
205             g_value_set_int(val, G_MININT);
206         }
207         return TRUE;
208     } else if (*string == '\0' || multiplier == 0
209                || strto_result < G_MININT / multiplier
210                || strto_result > G_MAXINT / multiplier) {
211         return FALSE;
212     } else { 
213         g_value_set_int(val, (int)(strto_result * multiplier));
214         return TRUE;
215     }
216 }
217
218 static gboolean g_value_set_uint_from_string(GValue * val, char * string) {
219     unsigned long int strto_result;
220     char * strto_end;
221     guint64 multiplier;
222     strto_result = strtoul(string, &strto_end, 0);
223     multiplier = find_multiplier(strto_end); /* casts */
224     if (multiplier == G_MAXINT64) {
225         g_value_set_uint(val, G_MAXUINT);
226         return TRUE;
227     } else if (multiplier == 0 || *string == '\0' ||
228                strto_result > G_MAXUINT / multiplier) {
229         return FALSE;
230     } else {
231         g_value_set_uint(val, (guint)(strto_result * multiplier));
232         return TRUE;
233     }
234 }
235
236 static gboolean g_value_set_uint64_from_string(GValue * val, char * string) {
237     unsigned long long int strto_result;
238     char * strto_end;
239     guint64 multiplier;
240     strto_result = strtoull(string, &strto_end, 0);
241     multiplier = find_multiplier(strto_end); /* casts */
242     if (multiplier == G_MAXINT64) {
243         g_value_set_uint64(val, G_MAXUINT64);
244         return TRUE;
245     } else if (multiplier == 0 || *string == '\0' ||
246         strto_result > G_MAXUINT64 / multiplier) {
247         return FALSE;
248     } else {
249         g_value_set_uint64(val, (guint64)(strto_result * multiplier));
250         return TRUE;
251     }
252 }
253
254 /* Flags can contain multiple values. We assume here that values are like
255  * C identifiers (that is, they match /[A-Za-z_][A-Za-z0-9_]+/), although
256  * that doesn't seem to be a requirement of GLib. With that assumption in
257  * mind, we look for the format "FLAG_1 | FLAG_2 | ... | FLAG_N". */
258 static gboolean g_value_set_flags_from_string(GValue * val, char * string) {
259     guint value = 0;
260     char * strtok_saveptr;
261     char * string_copy;
262     char * strtok_first_arg;
263     const char delim[] = " \t,|";
264     GFlagsClass * flags_class;
265     
266     flags_class = (GFlagsClass*) g_type_class_ref(G_VALUE_TYPE(val));
267     g_return_val_if_fail(flags_class != NULL, FALSE);
268     g_return_val_if_fail(G_IS_FLAGS_CLASS(flags_class), FALSE);
269
270     /* Don't let strtok stop on original. */
271     strtok_first_arg = string_copy = strdup(string);
272     
273     for (;;) {
274         GFlagsValue * flag_value;
275         char * token = strtok_r(strtok_first_arg, delim, &strtok_saveptr);
276         strtok_first_arg = NULL;
277
278         if (token == NULL) {
279             break;
280         }
281         
282         flag_value = g_flags_get_value_by_name(flags_class, token);
283         if (flag_value == NULL) {
284             flag_value = g_flags_get_value_by_nick(flags_class, token);
285         }
286         if (flag_value == NULL) {
287             g_fprintf(stderr, _("Invalid flag %s for type %s\n"), token,
288                     g_type_name(G_VALUE_TYPE(val)));
289             continue;
290         }
291
292         value |= flag_value->value;
293     }
294     
295     amfree(string_copy);
296     
297     if (value == 0) {
298         g_fprintf(stderr, _("No valid flags for type %s in string %s\n"),
299                 g_type_name(G_VALUE_TYPE(val)), string);
300         return FALSE;
301     }
302     
303     g_value_set_flags(val, value);
304     return TRUE;
305
306 }
307
308 /* This function really ought not to be part of Amanda. In my (Ian's) opinion,
309    serialization and deserialization should be a part of the GValue
310    interface. But it's not, and here we are. */
311 gboolean g_value_set_from_string(GValue * val, char * string) {
312     g_return_val_if_fail(val != NULL, FALSE);
313     g_return_val_if_fail(G_IS_VALUE(val), FALSE);
314
315     if (G_VALUE_HOLDS_BOOLEAN(val)) {
316         return g_value_set_boolean_from_string(val, string);
317     } else if (G_VALUE_HOLDS_INT(val)) {
318         return g_value_set_int_from_string(val, string);
319     } else if (G_VALUE_HOLDS_UINT(val)) {
320         return g_value_set_uint_from_string(val, string);
321     } else if (G_VALUE_HOLDS_UINT64(val)) {
322         return g_value_set_uint64_from_string(val, string);
323     } else if (G_VALUE_HOLDS_STRING(val)) {
324         g_value_set_string(val, string);
325         return TRUE;
326     } else if (G_VALUE_HOLDS_FLAGS(val)) {
327         return g_value_set_flags_from_string(val, string);
328     }
329
330     return TRUE;
331 }
332
333 gint
334 g_compare_strings(
335     gconstpointer a,
336     gconstpointer b)
337 {
338     return strcmp((char *)a, (char *)b);
339 }
340
341 char * g_strjoinv_and_free(char ** strv, const char * seperator) {
342     char * rval = g_strjoinv(seperator, strv);
343     g_strfreev(strv);
344     return rval;
345 }
346
347 char ** g_flags_name_to_strv(int value, GType type) {
348     return g_flags_to_strv(value, type, FLAG_STRING_NAME);
349 }
350
351 char ** g_flags_short_name_to_strv(int value, GType type) {
352     return g_flags_to_strv(value, type, FLAG_STRING_SHORT_NAME);
353 }
354
355 char ** g_flags_nick_to_strv(int value, GType type) {
356     return g_flags_to_strv(value, type, FLAG_STRING_NICK);
357 }
358
359 static char * get_name_from_value(GFlagsValue * value, FlagString source) {
360     switch (source) {
361     case FLAG_STRING_NAME:
362     case FLAG_STRING_SHORT_NAME:
363         return strdup(value->value_name);
364     case FLAG_STRING_NICK:
365         return strdup(value->value_nick);
366     default:
367         return NULL;
368     }
369 }
370
371 /* If freed and notfreed have a common prefix that is different from freed,
372    then return that and free freed. Otherwise, return freed. */
373 static char * find_common_prefix(char * freed, const char * notfreed) {
374     char * freed_ptr = freed;
375     const char * notfreed_ptr = notfreed;
376
377     if (freed == NULL) {
378         if (notfreed == NULL) {
379             return NULL;
380         } else {
381             return strdup(notfreed);
382         }
383     } else if (notfreed == NULL) {
384         amfree(freed);
385         return strdup("");
386     }
387
388     while (*freed_ptr == *notfreed_ptr) {
389         freed_ptr ++;
390         notfreed_ptr ++;
391     }
392
393     *freed_ptr = '\0';
394     return freed;
395 }
396
397 static char ** g_flags_to_strv(int value, GType type,
398                                FlagString source) {
399     GPtrArray * rval;
400     GFlagsValue * flagsvalue;
401     char * common_prefix = NULL;
402     int common_prefix_len;
403     GFlagsClass * class;
404
405     g_return_val_if_fail(G_TYPE_IS_FLAGS(type), NULL);
406     g_return_val_if_fail((class = g_type_class_ref(type)) != NULL, NULL);
407     g_return_val_if_fail(G_IS_FLAGS_CLASS(class), NULL);
408         
409     rval = g_ptr_array_new();
410     for (flagsvalue = class->values;
411          flagsvalue->value_name != NULL;
412          flagsvalue ++) {
413         if (source == FLAG_STRING_SHORT_NAME) {
414             common_prefix = find_common_prefix(common_prefix,
415                                                flagsvalue->value_name);
416         }
417                                                
418         if ((flagsvalue->value == 0 && value == 0) ||
419             (flagsvalue->value != 0 && (value & flagsvalue->value))) {
420             g_ptr_array_add(rval, get_name_from_value(flagsvalue, source));
421         }
422     }
423
424     if (source == FLAG_STRING_SHORT_NAME && common_prefix != NULL &&
425         ((common_prefix_len = strlen(common_prefix))) > 0) {
426         char * old;
427         char * new;
428         guint i;
429         for (i = 0; i < rval->len; i ++) {
430             old = g_ptr_array_index(rval, i);
431             new = strdup(old + common_prefix_len);
432             g_ptr_array_index(rval, i) = new;
433             g_free(old);
434         }
435     }
436     
437     g_ptr_array_add(rval, NULL);
438
439     amfree(common_prefix);
440     return (char**)g_ptr_array_free(rval, FALSE);
441 }
442
443 char * g_english_strjoinv(char ** strv, const char * conjunction) {
444     int length;
445     char * last;
446     char * joined;
447     char * rval;
448     strv = g_strdupv(strv);
449
450     length = g_strv_length(strv);
451
452     if (length == 1)
453         return stralloc(strv[0]);
454
455     last = strv[length - 1];
456     strv[length - 1] = NULL;
457     
458     joined = g_strjoinv(", ", strv);
459     rval = g_strdup_printf("%s, %s %s", joined, conjunction, last);
460
461     g_free(joined);
462     g_free(last);
463     g_strfreev(strv);
464     return rval;
465 }
466
467 char * g_english_strjoinv_and_free(char ** strv, const char * conjunction) {
468     char * rval = g_english_strjoinv(strv, conjunction);
469     g_strfreev(strv);
470     return rval;   
471 }
472
473 #if !(GLIB_CHECK_VERSION(2,6,0))
474 guint g_strv_length(gchar ** strv) {
475     int rval = 0;
476
477     if (G_UNLIKELY(strv == NULL))
478         return 0;
479
480     while (*strv != NULL) {
481         rval ++;
482         strv ++;
483     }
484     return rval;
485 }
486 #endif /* GLIB_CHECK_VERSION(2.6.0) */
487
488 #if !GLIB_CHECK_VERSION(2,4,0)
489 void
490 g_ptr_array_foreach (GPtrArray *array,
491                      GFunc      func,
492                      gpointer   user_data)
493 {
494   guint i;
495
496   g_return_if_fail (array);
497
498   for (i = 0; i < array->len; i++)
499     (*func) (array->pdata[i], user_data);
500 }
501 #endif
502
503 guint
504 g_str_amanda_hash(
505         gconstpointer key)
506 {
507     /* modified version of glib's hash function, copyright
508      * GLib Team and others 1997-2000. */
509     const char *p;
510     guint h = 0;
511
512     for (p = key; *p != '\0'; p++)
513         h = (h << 5) - h + (('_' == *p) ? '-' : g_ascii_tolower(*p));
514
515     return h;
516 }
517
518 gboolean
519 g_str_amanda_equal(
520         gconstpointer v1,
521         gconstpointer v2)
522 {
523     const gchar *p1 = v1, *p2 = v2;
524     while (*p1) {
525         /* letting '-' == '_' */
526         if (!('-' == *p1 || '_' == *p1) || !('-' == *p2 || '_' == *p2))
527             if (g_ascii_tolower(*p1) != g_ascii_tolower(*p2))
528                 return FALSE;
529
530         p1++;
531         p2++;
532     }
533
534     /* p1 is at '\0' is p2 too? */
535     return *p2? FALSE : TRUE;
536 }