6320a1dea9e49549dcdb2850bae982e44b861f34
[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_queue_free_full(GQueue * queue) {
134     while (!g_queue_is_empty(queue)) {
135         gpointer data;
136         data = g_queue_pop_head(queue);
137         amfree(data);
138     }
139     g_queue_free(queue);
140 }
141
142 void g_ptr_array_free_full(GPtrArray * array) {
143     size_t i;
144
145     for (i = 0; i < array->len; i ++) {
146         amfree(g_ptr_array_index(array, i));
147     }
148     g_ptr_array_free(array, TRUE);
149 }
150
151 gboolean g_value_compare(GValue * a, GValue * b) {
152     if (a == NULL && b == NULL)
153         return TRUE;
154     if (a == NULL || b == NULL)
155         return FALSE;
156     if (G_VALUE_TYPE(a) != G_VALUE_TYPE(b))
157         return FALSE;
158     if (g_value_fits_pointer(a) && g_value_fits_pointer(b)) {
159         return g_value_peek_pointer(a) == g_value_peek_pointer(b);
160     } else {
161         /* Since there is no builtin comparison function, we resort to
162            comparing serialized strings. Yuck. */
163         char * a_str;
164         char * b_str;
165         gboolean rval;
166         a_str = g_strdup_value_contents(a);
167         b_str = g_strdup_value_contents(b);
168         rval = (0 == strcmp(a_str, b_str));
169         amfree(a_str);
170         amfree(b_str);
171         return rval;
172     }
173     
174     g_assert_not_reached();
175 }
176
177 static gboolean
178 g_value_set_boolean_from_string(
179     GValue * val,
180     char * str)
181 {
182     int b = string_to_boolean(str);
183
184     if (b == -1)
185         return FALSE;
186
187     g_value_set_boolean(val, b);
188     return TRUE;
189 }
190
191 static gboolean g_value_set_int_from_string(GValue * val, char * string) {
192     long int strto_result;
193     char * strto_end;
194     gint64 multiplier;
195     strto_result = strtol(string, &strto_end, 0);
196     multiplier = find_multiplier(strto_end);
197     if (multiplier == G_MAXINT64) {
198         if (strto_result >= 0) {
199             g_value_set_int(val, G_MAXINT);
200         } else {
201             g_value_set_int(val, G_MININT);
202         }
203         return TRUE;
204     } else if (*string == '\0' || multiplier == 0
205                || strto_result < G_MININT / multiplier
206                || strto_result > G_MAXINT / multiplier) {
207         return FALSE;
208     } else { 
209         g_value_set_int(val, (int)(strto_result * multiplier));
210         return TRUE;
211     }
212 }
213
214 static gboolean g_value_set_uint_from_string(GValue * val, char * string) {
215     unsigned long int strto_result;
216     char * strto_end;
217     guint64 multiplier;
218     strto_result = strtoul(string, &strto_end, 0);
219     multiplier = find_multiplier(strto_end); /* casts */
220     if (multiplier == G_MAXINT64) {
221         g_value_set_uint(val, G_MAXUINT);
222         return TRUE;
223     } else if (multiplier == 0 || *string == '\0' ||
224                strto_result > G_MAXUINT / multiplier) {
225         return FALSE;
226     } else {
227         g_value_set_uint(val, (guint)(strto_result * multiplier));
228         return TRUE;
229     }
230 }
231
232 static gboolean g_value_set_uint64_from_string(GValue * val, char * string) {
233     unsigned long long int strto_result;
234     char * strto_end;
235     guint64 multiplier;
236     strto_result = strtoull(string, &strto_end, 0);
237     multiplier = find_multiplier(strto_end); /* casts */
238     if (multiplier == G_MAXINT64) {
239         g_value_set_uint64(val, G_MAXUINT64);
240         return TRUE;
241     } else if (multiplier == 0 || *string == '\0' ||
242         strto_result > G_MAXUINT64 / multiplier) {
243         return FALSE;
244     } else {
245         g_value_set_uint64(val, (guint64)(strto_result * multiplier));
246         return TRUE;
247     }
248 }
249
250 /* Flags can contain multiple values. We assume here that values are like
251  * C identifiers (that is, they match /[A-Za-z_][A-Za-z0-9_]+/), although
252  * that doesn't seem to be a requirement of GLib. With that assumption in
253  * mind, we look for the format "FLAG_1 | FLAG_2 | ... | FLAG_N". */
254 static gboolean g_value_set_flags_from_string(GValue * val, char * string) {
255     guint value = 0;
256     char * strtok_saveptr;
257     char * string_copy;
258     char * strtok_first_arg;
259     const char delim[] = " \t,|";
260     GFlagsClass * flags_class;
261     
262     flags_class = (GFlagsClass*) g_type_class_ref(G_VALUE_TYPE(val));
263     g_return_val_if_fail(flags_class != NULL, FALSE);
264     g_return_val_if_fail(G_IS_FLAGS_CLASS(flags_class), FALSE);
265
266     /* Don't let strtok stop on original. */
267     strtok_first_arg = string_copy = strdup(string);
268     
269     for (;;) {
270         GFlagsValue * flag_value;
271         char * token = strtok_r(strtok_first_arg, delim, &strtok_saveptr);
272         strtok_first_arg = NULL;
273
274         if (token == NULL) {
275             break;
276         }
277         
278         flag_value = g_flags_get_value_by_name(flags_class, token);
279         if (flag_value == NULL) {
280             flag_value = g_flags_get_value_by_nick(flags_class, token);
281         }
282         if (flag_value == NULL) {
283             g_fprintf(stderr, _("Invalid flag %s for type %s\n"), token,
284                     g_type_name(G_VALUE_TYPE(val)));
285             continue;
286         }
287
288         value |= flag_value->value;
289     }
290     
291     amfree(string_copy);
292     
293     if (value == 0) {
294         g_fprintf(stderr, _("No valid flags for type %s in string %s\n"),
295                 g_type_name(G_VALUE_TYPE(val)), string);
296         return FALSE;
297     }
298     
299     g_value_set_flags(val, value);
300     return TRUE;
301
302 }
303
304 /* This function really ought not to be part of Amanda. In my (Ian's) opinion,
305    serialization and deserialization should be a part of the GValue
306    interface. But it's not, and here we are. */
307 gboolean g_value_set_from_string(GValue * val, char * string) {
308     g_return_val_if_fail(val != NULL, FALSE);
309     g_return_val_if_fail(G_IS_VALUE(val), FALSE);
310
311     if (G_VALUE_HOLDS_BOOLEAN(val)) {
312         return g_value_set_boolean_from_string(val, string);
313     } else if (G_VALUE_HOLDS_INT(val)) {
314         return g_value_set_int_from_string(val, string);
315     } else if (G_VALUE_HOLDS_UINT(val)) {
316         return g_value_set_uint_from_string(val, string);
317     } else if (G_VALUE_HOLDS_UINT64(val)) {
318         return g_value_set_uint64_from_string(val, string);
319     } else if (G_VALUE_HOLDS_STRING(val)) {
320         g_value_set_string(val, string);
321         return TRUE;
322     } else if (G_VALUE_HOLDS_FLAGS(val)) {
323         return g_value_set_flags_from_string(val, string);
324     }
325
326     return TRUE;
327 }
328
329 gint
330 g_compare_strings(
331     gconstpointer a,
332     gconstpointer b)
333 {
334     return strcmp((char *)a, (char *)b);
335 }
336
337 char * g_strjoinv_and_free(char ** strv, const char * seperator) {
338     char * rval = g_strjoinv(seperator, strv);
339     g_strfreev(strv);
340     return rval;
341 }
342
343 char ** g_flags_name_to_strv(int value, GType type) {
344     return g_flags_to_strv(value, type, FLAG_STRING_NAME);
345 }
346
347 char ** g_flags_short_name_to_strv(int value, GType type) {
348     return g_flags_to_strv(value, type, FLAG_STRING_SHORT_NAME);
349 }
350
351 char ** g_flags_nick_to_strv(int value, GType type) {
352     return g_flags_to_strv(value, type, FLAG_STRING_NICK);
353 }
354
355 static char * get_name_from_value(GFlagsValue * value, FlagString source) {
356     switch (source) {
357     case FLAG_STRING_NAME:
358     case FLAG_STRING_SHORT_NAME:
359         return strdup(value->value_name);
360     case FLAG_STRING_NICK:
361         return strdup(value->value_nick);
362     default:
363         return NULL;
364     }
365 }
366
367 /* If freed and notfreed have a common prefix that is different from freed,
368    then return that and free freed. Otherwise, return freed. */
369 static char * find_common_prefix(char * freed, const char * notfreed) {
370     char * freed_ptr = freed;
371     const char * notfreed_ptr = notfreed;
372
373     if (freed == NULL) {
374         if (notfreed == NULL) {
375             return NULL;
376         } else {
377             return strdup(notfreed);
378         }
379     } else if (notfreed == NULL) {
380         amfree(freed);
381         return strdup("");
382     }
383
384     while (*freed_ptr == *notfreed_ptr) {
385         freed_ptr ++;
386         notfreed_ptr ++;
387     }
388
389     *freed_ptr = '\0';
390     return freed;
391 }
392
393 static char ** g_flags_to_strv(int value, GType type,
394                                FlagString source) {
395     GPtrArray * rval;
396     GFlagsValue * flagsvalue;
397     char * common_prefix = NULL;
398     int common_prefix_len;
399     GFlagsClass * class;
400
401     g_return_val_if_fail(G_TYPE_IS_FLAGS(type), NULL);
402     g_return_val_if_fail((class = g_type_class_ref(type)) != NULL, NULL);
403     g_return_val_if_fail(G_IS_FLAGS_CLASS(class), NULL);
404         
405     rval = g_ptr_array_new();
406     for (flagsvalue = class->values;
407          flagsvalue->value_name != NULL;
408          flagsvalue ++) {
409         if (source == FLAG_STRING_SHORT_NAME) {
410             common_prefix = find_common_prefix(common_prefix,
411                                                flagsvalue->value_name);
412         }
413                                                
414         if ((flagsvalue->value == 0 && value == 0) ||
415             (flagsvalue->value != 0 && (value & flagsvalue->value))) {
416             g_ptr_array_add(rval, get_name_from_value(flagsvalue, source));
417         }
418     }
419
420     if (source == FLAG_STRING_SHORT_NAME && common_prefix != NULL &&
421         ((common_prefix_len = strlen(common_prefix))) > 0) {
422         char * old;
423         char * new;
424         guint i;
425         for (i = 0; i < rval->len; i ++) {
426             old = g_ptr_array_index(rval, i);
427             new = strdup(old + common_prefix_len);
428             g_ptr_array_index(rval, i) = new;
429             g_free(old);
430         }
431     }
432     
433     g_ptr_array_add(rval, NULL);
434
435     amfree(common_prefix);
436     return (char**)g_ptr_array_free(rval, FALSE);
437 }
438
439 char * g_english_strjoinv(char ** strv, const char * conjunction) {
440     int length;
441     char * last;
442     char * joined;
443     char * rval;
444     strv = g_strdupv(strv);
445
446     length = g_strv_length(strv);
447
448     if (length == 1)
449         return stralloc(strv[0]);
450
451     last = strv[length - 1];
452     strv[length - 1] = NULL;
453     
454     joined = g_strjoinv(", ", strv);
455     rval = g_strdup_printf("%s, %s %s", joined, conjunction, last);
456
457     g_free(joined);
458     g_free(last);
459     g_strfreev(strv);
460     return rval;
461 }
462
463 char * g_english_strjoinv_and_free(char ** strv, const char * conjunction) {
464     char * rval = g_english_strjoinv(strv, conjunction);
465     g_strfreev(strv);
466     return rval;   
467 }
468
469 #if !(GLIB_CHECK_VERSION(2,6,0))
470 guint g_strv_length(gchar ** strv) {
471     int rval = 0;
472
473     if (G_UNLIKELY(strv == NULL))
474         return 0;
475
476     while (*strv != NULL) {
477         rval ++;
478         strv ++;
479     }
480     return rval;
481 }
482 #endif /* GLIB_CHECK_VERSION(2.6.0) */
483
484 #if !GLIB_CHECK_VERSION(2,4,0)
485 void
486 g_ptr_array_foreach (GPtrArray *array,
487                      GFunc      func,
488                      gpointer   user_data)
489 {
490   guint i;
491
492   g_return_if_fail (array);
493
494   for (i = 0; i < array->len; i++)
495     (*func) (array->pdata[i], user_data);
496 }
497 #endif
498
499 guint
500 g_str_case_hash(
501         gconstpointer key)
502 {
503     /* modified version of glib's hash function, copyright
504      * GLib Team and others 1997-2000. */
505     const char *p = key;
506     guint h = g_ascii_toupper(*p);
507
508     if (h)
509         for (p += 1; *p != '\0'; p++)
510             h = (h << 5) - h + g_ascii_toupper(*p);
511
512     return h;
513 }
514
515 gboolean
516 g_str_case_equal(
517         gconstpointer v1,
518         gconstpointer v2)
519 {
520     return (0 == g_ascii_strcasecmp((char *)v1, (char *)v2));
521 }