build: depends on cairo-gobject if introspection is enabled
[adg.git] / src / adg / adg-utils.c
bloba2f1577e2a4c0c20dc2f057a715cbbe616ee76e4
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007,2008,2009,2010,2011,2012,2013 Nicola Fontana <ntd at entidi.it>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
21 /**
22 * SECTION:adg-utils
23 * @Section_Id:utilities
24 * @title: Utilities
25 * @short_description: Assorted macros and functions
27 * Collection of macros and functions that do not fit inside any other topic.
29 * Since: 1.0
30 **/
32 /**
33 * ADG_DIR_RIGHT:
35 * Symbolic constant for the right direction (in radians).
37 * Since: 1.0
38 **/
40 /**
41 * ADG_DIR_DOWN:
43 * Symbolic constant for the down direction (in radians).
45 * Since: 1.0
46 **/
48 /**
49 * ADG_DIR_LEFT:
51 * Symbolic constant for the left direction (in radians).
53 * Since: 1.0
54 **/
56 /**
57 * ADG_DIR_UP:
59 * Symbolic constant for the up direction (in radians).
61 * Since: 1.0
62 **/
64 /**
65 * ADG_UTF8_DIAMETER:
67 * String constant that embeds a UTF-8 encoded diameter (U+2300).
68 * It can be used to prefix diameter quotes, such as:
70 * |[
71 * adg_dim_set_value(dim, ADG_UTF8_DIAMETER "<>");
72 * ]|
74 * Since: 1.0
75 **/
77 /**
78 * ADG_UTF8_DEGREE:
80 * String constant that embeds a UTF-8 encoded degree symbol (U+00B0).
81 * It is used to suffix by the default implementation of #AdgADim to
82 * suffix the set value, but can be also used manually:
84 * |[
85 * adg_dim_set_value(dim, "<>" ADG_UTF8_DEGREE);
86 * ]|
88 * Since: 1.0
89 **/
92 #include "adg-internal.h"
93 #include <string.h>
94 #include <limits.h>
97 #if GLIB_CHECK_VERSION(2, 16, 0)
98 #else
99 /**
100 * g_strcmp0:
101 * @s1: a C string or %NULL
102 * @s2: another C string or %NULL
104 * Compares @s1 and @s2 like strcmp(). Handles %NULL
105 * gracefully by sorting it before non-%NULL strings.
106 * This is a backward compatibility fallback for GLib
107 * prior to 2.16.0
109 * Returns: -1, 0 or 1, if @s1 is <, == or > than @s2.
111 * Since: 1.0
114 g_strcmp0(const char *s1, const char *s2)
116 if (!s1)
117 return -(s1 != s2);
119 if (!s2)
120 return s1 != s2;
122 return strcmp(s1, s2);
124 #endif
127 * adg_is_string_empty:
128 * @str: the subject string
130 * Checks if @str is an empty string, that is if is %NULL or if
131 * its first character is %'\0'.
133 * Returns: %TRUE if @str is an empty string, %FALSE otherwise
135 * Since: 1.0
137 gboolean
138 adg_is_string_empty(const gchar *str)
140 return str == NULL || str[0] == '\0';
144 * adg_is_enum_value:
145 * @value: the enum value to check
146 * @enum_type: a #GEnum based type
148 * Checks if @value is a valid @enum_type value.
150 * Returns: %TRUE if @value is a valid @enum_type, %FALSE otherwise
152 * Since: 1.0
154 gboolean
155 adg_is_enum_value(int value, GType enum_type)
157 GEnumClass *enum_class;
158 gboolean found;
160 enum_class = g_type_class_ref(enum_type);
161 g_return_val_if_fail(enum_class != NULL, FALSE);
163 found = FALSE;
165 if (value >= enum_class->minimum && value <= enum_class->maximum) {
166 GEnumValue *enum_value;
167 guint n;
169 for (n = 0; !found && n < enum_class->n_values; ++n) {
170 enum_value = enum_class->values + n;
171 found = value == enum_value->value;
175 g_type_class_unref(enum_class);
177 return found;
181 * adg_is_boolean_value:
182 * @value: the gboolean value to check
184 * Checks if @value is a valid #gboolean value, that is if it is %TRUE
185 * or %FALSE. No other values are accepted.
187 * Returns: %TRUE if @value is a valid #gboolean, %FALSE otherwise
189 * Since: 1.0
191 gboolean
192 adg_is_boolean_value(gboolean value)
194 return value == TRUE || value == FALSE;
198 * adg_string_replace:
199 * @str: the original string
200 * @from: the substring to replace
201 * @to: the replacement string
203 * Replaces @from with @to inside @str and returns the result as a
204 * newly allocated string.
206 * @str and @from must be non-null valid C strings while @to can be
207 * %NULL, in which case an empty string ("") will be implied.
209 * Returns: a newly allocated string to be freed with g_free() or
210 * %NULL on errors
212 * Since: 1.0
214 gchar *
215 adg_string_replace(const gchar *str, const gchar *from, const gchar *to)
217 gchar *result;
218 int from_len;
219 gchar *ptr, *old_result;
221 g_return_val_if_fail(str != NULL, NULL);
222 g_return_val_if_fail(from != NULL, NULL);
224 from_len = strlen(from);
226 g_return_val_if_fail(from_len > 0, NULL);
228 if (to == NULL)
229 to = "";
231 result = g_strdup(str);
233 while ((ptr = strstr(result, from)) != NULL) {
234 *ptr = '\0';
235 old_result = result;
236 result = g_strconcat(old_result, to, ptr + from_len, NULL);
237 g_free(old_result);
240 return result;
244 * _adg_dgettext:
245 * @domain: the translation domain to use, or %NULL to use
246 * the domain set with textdomain()
247 * @msgid: message to translate
249 * A variant of dgettext() (or of g_dgettext(), if available) that
250 * initialize the ADG localization infrastructure.
252 * Returns: The translated string
254 * Since: 1.0
256 const gchar *
257 _adg_dgettext(const gchar *domain, const gchar *msgid)
259 static gboolean initialized = FALSE;
261 if (G_UNLIKELY(!initialized)) {
262 bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
263 bindtextdomain(GETTEXT_PACKAGE "-properties", LOCALEDIR);
264 initialized = TRUE;
267 #if GLIB_CHECK_VERSION(2, 18, 0)
268 return g_dgettext(domain, msgid);
269 #else
270 return dgettext(domain, msgid);
271 #endif
275 * _adg_dpgettext:
276 * @domain: the translation domain to use, or %NULL to use
277 * the domain set with textdomain()
278 * @msgctxtid: a combined message context and message id, separated
279 * by a \004 character
280 * @msgidoffset: the offset of the message id in @msgctxid
282 * This function is basically a duplicate of g_dpgettext() but using
283 * _adg_dgettext() internally instead of g_dgettext().
285 * Returns: The translated string
287 * Since: 1.0
289 const gchar *
290 _adg_dpgettext(const gchar *domain, const gchar *msgctxtid, gsize msgidoffset)
292 const gchar *translation;
293 gchar *sep;
295 translation = _adg_dgettext(domain, msgctxtid);
297 if (translation == msgctxtid) {
298 if (msgidoffset > 0)
299 return msgctxtid + msgidoffset;
301 sep = strchr(msgctxtid, '|');
303 if (sep) {
304 /* try with '\004' instead of '|', in case
305 * xgettext -kQ_:1g was used
307 gchar *tmp = g_alloca(strlen(msgctxtid) + 1);
308 strcpy(tmp, msgctxtid);
309 tmp[sep - msgctxtid] = '\004';
311 translation = _adg_dgettext(domain, tmp);
313 if (translation == tmp)
314 return sep + 1;
318 return translation;
322 * adg_find_file:
323 * @file: the file to search
324 * @...: a NULL terminated list of paths where to look for
325 * file existence.
327 * Searches @file in the provided paths and returns the full
328 * path to the first existing match. The check is performed
329 * using g_file_test() with the G_FILE_TEST_EXISTS test.
331 * This function has been picked up from the ntdisp project:
332 * http://dev.entidi.com/p/ntdisp/
334 * Returns: a newly allocated string containing the path
335 * or NULL on errors. Free it with g_free() when
336 * no longer needed.
338 * Since: 1.0
340 gchar *
341 adg_find_file(const gchar *file, ...)
343 va_list var_args;
344 gchar *path;
345 const gchar *base;
347 va_start(var_args, file);
349 while ((base = va_arg(var_args, const gchar *)) != NULL) {
350 path = g_build_filename(base, file, NULL);
351 if (g_file_test(path, G_FILE_TEST_EXISTS))
352 return path;
353 g_free(path);
356 return NULL;
360 * adg_scale_factor:
361 * @scale: a string identifying the scale
363 * Converts a scale in the form x:y (where x and y are respectively
364 * two positive integers representing the numerator and denominator
365 * of a fraction) into its approximate double representation. Any
366 * garbage following x or y will be silently ignored, meaning that
367 * x+garbage:y+garbage is equivalent to x:y. Furthermore, the postfix
368 * :y can be omitted, in which case (double) x will be returned.
370 * x and y are converted by using atoi(), so refer to your C library
371 * documentation for details on the algorithm used.
373 * Returns: the (possibly approximated) double conversion of @scale
374 * or %0 on errors.
376 gdouble
377 adg_scale_factor(const gchar *scale)
379 gint numerator, denominator;
380 const gchar *ptr;
382 g_return_val_if_fail(scale != NULL, 0);
384 numerator = atoi(scale);
385 if (numerator <= 0)
386 return 0;
388 ptr = strchr(scale, ':');
389 if (ptr == NULL)
390 return numerator;
392 denominator = atoi(ptr + 1);
393 if (denominator <= 0)
394 return 0;
396 return (gdouble) numerator / (gdouble) denominator;