device: renew dhcp leases on awake for software devices
[NetworkManager.git] / shared / nm-glib.h
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /*
3  * This program is free software; you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as published by
5  * the Free Software Foundation; either version 2 of the License, or
6  * (at your option) any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License 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  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16  *
17  * Copyright 2008 - 2011 Red Hat, Inc.
18  */
19
20 #ifndef __NM_GLIB_H__
21 #define __NM_GLIB_H__
22
23
24 #include <gio/gio.h>
25 #include <string.h>
26
27 #ifdef __clang__
28
29 #undef G_GNUC_BEGIN_IGNORE_DEPRECATIONS
30 #undef G_GNUC_END_IGNORE_DEPRECATIONS
31
32 #define G_GNUC_BEGIN_IGNORE_DEPRECATIONS \
33     _Pragma("clang diagnostic push") \
34     _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"")
35
36 #define G_GNUC_END_IGNORE_DEPRECATIONS \
37     _Pragma("clang diagnostic pop")
38
39 #endif
40
41 static inline void
42 __g_type_ensure (GType type)
43 {
44 #if !GLIB_CHECK_VERSION(2,34,0)
45         if (G_UNLIKELY (type == (GType)-1))
46                 g_error ("can't happen");
47 #else
48         G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
49         g_type_ensure (type);
50         G_GNUC_END_IGNORE_DEPRECATIONS;
51 #endif
52 }
53 #define g_type_ensure __g_type_ensure
54
55 #if !GLIB_CHECK_VERSION(2,34,0)
56
57 #define g_clear_pointer(pp, destroy) \
58     G_STMT_START {                                                                 \
59         G_STATIC_ASSERT (sizeof *(pp) == sizeof (gpointer));                       \
60         /* Only one access, please */                                              \
61         gpointer *_pp = (gpointer *) (pp);                                         \
62         gpointer _p;                                                               \
63         /* This assignment is needed to avoid a gcc warning */                     \
64         GDestroyNotify _destroy = (GDestroyNotify) (destroy);                      \
65                                                                                    \
66         _p = *_pp;                                                                 \
67         if (_p)                                                                    \
68         {                                                                          \
69             *_pp = NULL;                                                           \
70             _destroy (_p);                                                         \
71         }                                                                          \
72     } G_STMT_END
73
74 /* These are used to clean up the output of test programs; we can just let
75  * them no-op in older glib.
76  */
77 #define g_test_expect_message(log_domain, log_level, pattern)
78 #define g_test_assert_expected_messages()
79
80 #else
81
82 /* We build with -DGLIB_MAX_ALLOWED_VERSION set to 2.32 to make sure we don't
83  * accidentally use new API that we shouldn't. But we don't want warnings for
84  * the APIs that we emulate above.
85  */
86
87 #define g_test_expect_message(domain, level, format...) \
88         G_STMT_START { \
89                 G_GNUC_BEGIN_IGNORE_DEPRECATIONS \
90                 g_test_expect_message (domain, level, format); \
91                 G_GNUC_END_IGNORE_DEPRECATIONS \
92         } G_STMT_END
93
94 #define g_test_assert_expected_messages_internal(domain, file, line, func) \
95         G_STMT_START { \
96                 G_GNUC_BEGIN_IGNORE_DEPRECATIONS \
97                 g_test_assert_expected_messages_internal (domain, file, line, func); \
98                 G_GNUC_END_IGNORE_DEPRECATIONS \
99         } G_STMT_END
100
101 #endif
102
103
104 #if GLIB_CHECK_VERSION (2, 35, 0)
105 /* For glib >= 2.36, g_type_init() is deprecated.
106  * But since 2.35.1 (7c42ab23b55c43ab96d0ac2124b550bf1f49c1ec) this function
107  * does nothing. Replace the call with empty statement. */
108 #define nm_g_type_init()     G_STMT_START { (void) 0; } G_STMT_END
109 #else
110 #define nm_g_type_init()     G_STMT_START { g_type_init (); } G_STMT_END
111 #endif
112
113
114 /* g_test_initialized() is only available since glib 2.36. */
115 #if !GLIB_CHECK_VERSION (2, 36, 0)
116 #define g_test_initialized() (g_test_config_vars->test_initialized)
117 #endif
118
119 /* g_assert_cmpmem() is only available since glib 2.46. */
120 #if !GLIB_CHECK_VERSION (2, 45, 7)
121 #define g_assert_cmpmem(m1, l1, m2, l2) G_STMT_START {\
122                                              gconstpointer __m1 = m1, __m2 = m2; \
123                                              int __l1 = l1, __l2 = l2; \
124                                              if (__l1 != __l2) \
125                                                g_assertion_message_cmpnum (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
126                                                                            #l1 " (len(" #m1 ")) == " #l2 " (len(" #m2 "))", __l1, "==", __l2, 'i'); \
127                                              else if (memcmp (__m1, __m2, __l1) != 0) \
128                                                g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
129                                                                     "assertion failed (" #m1 " == " #m2 ")"); \
130                                         } G_STMT_END
131 #endif
132
133 /* Rumtime check for glib version. First do a compile time check which
134  * (if satisfied) shortcuts the runtime check. */
135 #define nm_glib_check_version(major, minor, micro) \
136     (   GLIB_CHECK_VERSION ((major), (minor), (micro)) \
137      || (   (   glib_major_version > (major)) \
138          || (   glib_major_version == (major) \
139              && glib_minor_version > (minor)) \
140          || (   glib_major_version == (major) \
141              && glib_minor_version == (minor) \
142              && glib_micro_version >= (micro))))
143
144 /* g_test_skip() is only available since glib 2.38. Add a compatibility wrapper. */
145 inline static void
146 __nmtst_g_test_skip (const gchar *msg)
147 {
148 #if GLIB_CHECK_VERSION (2, 38, 0)
149         G_GNUC_BEGIN_IGNORE_DEPRECATIONS
150         g_test_skip (msg);
151         G_GNUC_END_IGNORE_DEPRECATIONS
152 #else
153         g_debug ("%s", msg);
154 #endif
155 }
156 #define g_test_skip __nmtst_g_test_skip
157
158
159 /* g_test_add_data_func_full() is only available since glib 2.34. Add a compatibility wrapper. */
160 inline static void
161 __g_test_add_data_func_full (const char     *testpath,
162                              gpointer        test_data,
163                              GTestDataFunc   test_func,
164                              GDestroyNotify  data_free_func)
165 {
166 #if GLIB_CHECK_VERSION (2, 34, 0)
167         G_GNUC_BEGIN_IGNORE_DEPRECATIONS
168         g_test_add_data_func_full (testpath, test_data, test_func, data_free_func);
169         G_GNUC_END_IGNORE_DEPRECATIONS
170 #else
171         g_return_if_fail (testpath != NULL);
172         g_return_if_fail (testpath[0] == '/');
173         g_return_if_fail (test_func != NULL);
174
175         g_test_add_vtable (testpath, 0, test_data, NULL,
176                            (GTestFixtureFunc) test_func,
177                            (GTestFixtureFunc) data_free_func);
178 #endif
179 }
180 #define g_test_add_data_func_full __g_test_add_data_func_full
181
182
183 #if !GLIB_CHECK_VERSION (2, 34, 0)
184 #define G_DEFINE_QUARK(QN, q_n)               \
185 GQuark                                        \
186 q_n##_quark (void)                            \
187 {                                             \
188         static GQuark q;                          \
189                                               \
190         if G_UNLIKELY (q == 0)                    \
191                 q = g_quark_from_static_string (#QN); \
192                                               \
193         return q;                                 \
194 }
195 #endif
196
197
198 static inline gboolean
199 nm_g_hash_table_replace (GHashTable *hash, gpointer key, gpointer value)
200 {
201         /* glib 2.40 added a return value indicating whether the key already existed
202          * (910191597a6c2e5d5d460e9ce9efb4f47d9cc63c). */
203 #if GLIB_CHECK_VERSION(2, 40, 0)
204         return g_hash_table_replace (hash, key, value);
205 #else
206         gboolean contained = g_hash_table_contains (hash, key);
207
208         g_hash_table_replace (hash, key, value);
209         return !contained;
210 #endif
211 }
212
213 static inline gboolean
214 nm_g_hash_table_insert (GHashTable *hash, gpointer key, gpointer value)
215 {
216         /* glib 2.40 added a return value indicating whether the key already existed
217          * (910191597a6c2e5d5d460e9ce9efb4f47d9cc63c). */
218 #if GLIB_CHECK_VERSION(2, 40, 0)
219         return g_hash_table_insert (hash, key, value);
220 #else
221         gboolean contained = g_hash_table_contains (hash, key);
222
223         g_hash_table_insert (hash, key, value);
224         return !contained;
225 #endif
226 }
227
228 static inline gboolean
229 nm_g_hash_table_add (GHashTable *hash, gpointer key)
230 {
231         /* glib 2.40 added a return value indicating whether the key already existed
232          * (910191597a6c2e5d5d460e9ce9efb4f47d9cc63c). */
233 #if GLIB_CHECK_VERSION(2, 40, 0)
234         return g_hash_table_add (hash, key);
235 #else
236         gboolean contained = g_hash_table_contains (hash, key);
237
238         g_hash_table_add (hash, key);
239         return !contained;
240 #endif
241 }
242
243 #if !GLIB_CHECK_VERSION(2, 40, 0) || defined (NM_GLIB_COMPAT_H_TEST)
244 static inline void
245 _nm_g_ptr_array_insert (GPtrArray *array,
246                         gint       index_,
247                         gpointer   data)
248 {
249         g_return_if_fail (array);
250         g_return_if_fail (index_ >= -1);
251         g_return_if_fail (index_ <= (gint) array->len);
252
253         g_ptr_array_add (array, data);
254
255         if (index_ != -1 && index_ != (gint) (array->len - 1)) {
256                 memmove (&(array->pdata[index_ + 1]),
257                          &(array->pdata[index_]),
258                          (array->len - index_ - 1) * sizeof (gpointer));
259                 array->pdata[index_] = data;
260         }
261 }
262 #endif
263 #if !GLIB_CHECK_VERSION(2, 40, 0)
264 #define g_ptr_array_insert(array, index, data) G_STMT_START { _nm_g_ptr_array_insert (array, index, data); } G_STMT_END
265 #else
266 #define g_ptr_array_insert(array, index, data) \
267         G_STMT_START { \
268                 G_GNUC_BEGIN_IGNORE_DEPRECATIONS \
269                 g_ptr_array_insert (array, index, data); \
270                 G_GNUC_END_IGNORE_DEPRECATIONS \
271         } G_STMT_END
272 #endif
273
274
275 #if !GLIB_CHECK_VERSION (2, 40, 0)
276 inline static gboolean
277 _g_key_file_save_to_file (GKeyFile     *key_file,
278                           const gchar  *filename,
279                           GError      **error)
280 {
281         gchar *contents;
282         gboolean success;
283         gsize length;
284
285         g_return_val_if_fail (key_file != NULL, FALSE);
286         g_return_val_if_fail (filename != NULL, FALSE);
287         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
288
289         contents = g_key_file_to_data (key_file, &length, NULL);
290         g_assert (contents != NULL);
291
292         success = g_file_set_contents (filename, contents, length, error);
293         g_free (contents);
294
295         return success;
296 }
297 #define g_key_file_save_to_file(key_file, filename, error) \
298         _g_key_file_save_to_file (key_file, filename, error)
299 #else
300 #define g_key_file_save_to_file(key_file, filename, error) \
301         ({ \
302                 gboolean _success; \
303                 \
304                 G_GNUC_BEGIN_IGNORE_DEPRECATIONS \
305                 _success = g_key_file_save_to_file (key_file, filename, error); \
306                 G_GNUC_END_IGNORE_DEPRECATIONS \
307                 _success; \
308         })
309 #endif
310
311
312 #if GLIB_CHECK_VERSION (2, 36, 0)
313 #define g_credentials_get_unix_pid(creds, error) \
314         G_GNUC_EXTENSION ({ \
315                 G_GNUC_BEGIN_IGNORE_DEPRECATIONS \
316                         (g_credentials_get_unix_pid) ((creds), (error)); \
317                 G_GNUC_END_IGNORE_DEPRECATIONS \
318         })
319 #else
320 #define g_credentials_get_unix_pid(creds, error) \
321         G_GNUC_EXTENSION ({ \
322                 struct ucred *native_creds; \
323                  \
324                 native_creds = g_credentials_get_native ((creds), G_CREDENTIALS_TYPE_LINUX_UCRED); \
325                 g_assert (native_creds); \
326                 native_creds->pid; \
327         })
328 #endif
329
330
331 #if !GLIB_CHECK_VERSION(2, 40, 0) || defined (NM_GLIB_COMPAT_H_TEST)
332 static inline gpointer *
333 _nm_g_hash_table_get_keys_as_array (GHashTable *hash_table,
334                                     guint      *length)
335 {
336         GHashTableIter iter;
337         gpointer key, *ret;
338         guint i = 0;
339
340         g_return_val_if_fail (hash_table, NULL);
341
342         ret = g_new0 (gpointer, g_hash_table_size (hash_table) + 1);
343         g_hash_table_iter_init (&iter, hash_table);
344
345         while (g_hash_table_iter_next (&iter, &key, NULL))
346                 ret[i++] = key;
347
348         ret[i] = NULL;
349
350         if (length)
351                 *length = i;
352
353         return ret;
354 }
355 #endif
356 #if !GLIB_CHECK_VERSION(2, 40, 0)
357 #define g_hash_table_get_keys_as_array(hash_table, length) \
358         G_GNUC_EXTENSION ({ \
359                 _nm_g_hash_table_get_keys_as_array (hash_table, length); \
360         })
361 #else
362 #define g_hash_table_get_keys_as_array(hash_table, length) \
363         G_GNUC_EXTENSION ({ \
364                 G_GNUC_BEGIN_IGNORE_DEPRECATIONS \
365                         (g_hash_table_get_keys_as_array) ((hash_table), (length)); \
366                 G_GNUC_END_IGNORE_DEPRECATIONS \
367         })
368 #endif
369
370 #ifndef g_info
371 /* g_info was only added with 2.39.2 */
372 #define g_info(...)     g_log (G_LOG_DOMAIN,         \
373                                G_LOG_LEVEL_INFO,     \
374                                __VA_ARGS__)
375 #endif
376
377 #endif  /* __NM_GLIB_H__ */