docs: updated copyright to 2012
[adg.git] / src / adg / adg-utils.c
blob59b83149ee9118d7fbb5404ac185fbce3bef1d07
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007,2008,2009,2010,2011,2012 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_FORWARD_DECL:
34 * @id: The name of a struct
36 * Forward declaration of struct @id. It is equivalent to a typical
37 * struct forward declaration, for example:
39 * |[
40 * ADG_FORWARD_DECL(test)
41 * ]|
43 * will expand to:
45 * |[
46 * typedef struct _test test
47 * ]|
49 * This macro is needed to fake <command>gtk-doc</command>, because
50 * up to now (v.1.12) it generates two conflicting links when using
51 * forward declarations: the first in the source with the declaration
52 * and the second where the type is defined. Using ADG_FORWARD_DECL()
53 * instead of the usual typedef avoids the parsing of the declaration
54 * in the first file (<command>gtk-doc</command> is not able to do C
55 * preprocessing).
57 * The same principle can be applied in the definition file. Following
58 * the previous example, you can use something like this where struct
59 * _type is defined:
61 * |[
62 * #if 0
63 * // This is declared in another file
64 * typedef struct _type type;
65 * #endif
66 * struct _type {
67 * ...
68 * };
69 * ]|
71 * Since: 1.0
72 **/
74 /**
75 * ADG_DIR_RIGHT:
77 * Symbolic constant for the right direction (in radians).
79 * Since: 1.0
80 **/
82 /**
83 * ADG_DIR_DOWN:
85 * Symbolic constant for the down direction (in radians).
87 * Since: 1.0
88 **/
90 /**
91 * ADG_DIR_LEFT:
93 * Symbolic constant for the left direction (in radians).
95 * Since: 1.0
96 **/
98 /**
99 * ADG_DIR_UP:
101 * Symbolic constant for the up direction (in radians).
103 * Since: 1.0
107 * ADG_UTF8_DIAMETER:
109 * String constant that embeds a UTF-8 encoded diameter (U+2300).
110 * It can be used to prefix diameter quotes, such as:
112 * |[
113 * adg_dim_set_value(dim, ADG_UTF8_DIAMETER "<>");
114 * ]|
116 * Since: 1.0
120 * ADG_UTF8_DEGREE:
122 * String constant that embeds a UTF-8 encoded degree symbol (U+00B0).
123 * It is used to suffix by the default implementation of #AdgADim to
124 * suffix the set value, but can be also used manually:
126 * |[
127 * adg_dim_set_value(dim, "<>" ADG_UTF8_DEGREE);
128 * ]|
130 * Since: 1.0
134 #include "adg-internal.h"
135 #include <string.h>
136 #include <limits.h>
139 #if GLIB_CHECK_VERSION(2, 16, 0)
140 #else
142 * g_strcmp0:
143 * @str1: a C string or %NULL
144 * @str2: another C string or %NULL
146 * Compares @str1 and @str2 like strcmp(). Handles %NULL
147 * gracefully by sorting it before non-%NULL strings.
148 * This is a backward compatibility fallback for GLib
149 * prior to 2.16.0
151 * Returns: -1, 0 or 1, if @str1 is <, == or > than @str2.
153 * Since: 1.0
156 g_strcmp0(const char *str1, const char *str2)
158 if (!str1)
159 return -(str1 != str2);
161 if (!str2)
162 return str1 != str2;
164 return strcmp(str1, str2);
166 #endif
169 * adg_is_string_empty:
170 * @str: the subject string
172 * Checks if @str is an empty string, that is if is %NULL or if
173 * its first character is %'\0'.
175 * Returns: %TRUE if @str is an empty string, %FALSE otherwise
177 * Since: 1.0
179 gboolean
180 adg_is_string_empty(const gchar *str)
182 return str == NULL || str[0] == '\0';
186 * adg_is_enum_value:
187 * @value: the enum value to check
188 * @enum_type: a #GEnum based type
190 * Checks if @value is a valid @enum_type value.
192 * Returns: %TRUE if @value is a valid @enum_type, %FALSE otherwise
194 * Since: 1.0
196 gboolean
197 adg_is_enum_value(int value, GType enum_type)
199 GEnumClass *enum_class;
200 gboolean found;
202 enum_class = g_type_class_ref(enum_type);
203 g_return_val_if_fail(enum_class != NULL, FALSE);
205 found = FALSE;
207 if (value >= enum_class->minimum && value <= enum_class->maximum) {
208 GEnumValue *enum_value;
209 guint n;
211 for (n = 0; !found && n < enum_class->n_values; ++n) {
212 enum_value = enum_class->values + n;
213 found = value == enum_value->value;
217 g_type_class_unref(enum_class);
219 return found;
223 * adg_is_boolean_value:
224 * @value: the gboolean value to check
226 * Checks if @value is a valid #gboolean value, that is if it is %TRUE
227 * or %FALSE. No other values are accepted.
229 * Returns: %TRUE if @value is a valid #gboolean, %FALSE otherwise
231 * Since: 1.0
233 gboolean
234 adg_is_boolean_value(gboolean value)
236 return value == TRUE || value == FALSE;
240 * adg_string_replace:
241 * @str: the original string
242 * @from: the substring to replace
243 * @to: the replacement string
245 * Replaces @from with @to inside @str and returns the result as a
246 * newly allocated string.
248 * @str and @from must be non-null valid C strings while @to can be
249 * %NULL, in which case an empty string ("") will be implied.
251 * Returns: a newly allocated string to be freed with g_free() or
252 * %NULL on errors
254 * Since: 1.0
256 gchar *
257 adg_string_replace(const gchar *str, const gchar *from, const gchar *to)
259 gchar *result;
260 int from_len;
261 gchar *ptr, *old_result;
263 g_return_val_if_fail(str != NULL, NULL);
264 g_return_val_if_fail(from != NULL, NULL);
266 from_len = strlen(from);
268 g_return_val_if_fail(from_len > 0, NULL);
270 if (to == NULL)
271 to = "";
273 result = g_strdup(str);
275 while ((ptr = strstr(result, from)) != NULL) {
276 *ptr = '\0';
277 old_result = result;
278 result = g_strconcat(old_result, to, ptr + from_len, NULL);
279 g_free(old_result);
282 return result;
286 * _adg_dgettext:
287 * @domain: the translation domain to use, or %NULL to use
288 * the domain set with textdomain()
289 * @msgid: message to translate
291 * A variant of dgettext() (or of g_dgettext(), if available) that
292 * initialize the ADG localization infrastructure.
294 * Returns: The translated string
296 * Since: 1.0
298 const gchar *
299 _adg_dgettext(const gchar *domain, const gchar *msgid)
301 static gboolean initialized = FALSE;
303 if (G_UNLIKELY(!initialized)) {
304 bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
305 bindtextdomain(GETTEXT_PACKAGE "-properties", LOCALEDIR);
306 initialized = TRUE;
309 #if GLIB_CHECK_VERSION(2, 18, 0)
310 return g_dgettext(domain, msgid);
311 #else
312 return dgettext(domain, msgid);
313 #endif
317 * _adg_dpgettext:
318 * @domain: the translation domain to use, or %NULL to use
319 * the domain set with textdomain()
320 * @msgctxtid: a combined message context and message id, separated
321 * by a \004 character
322 * @msgidoffset: the offset of the message id in @msgctxid
324 * This function is basically a duplicate of g_dpgettext() but using
325 * _adg_dgettext() internally instead of g_dgettext().
327 * Returns: The translated string
329 * Since: 1.0
331 const gchar *
332 _adg_dpgettext(const gchar *domain, const gchar *msgctxtid, gsize msgidoffset)
334 const gchar *translation;
335 gchar *sep;
337 translation = _adg_dgettext(domain, msgctxtid);
339 if (translation == msgctxtid) {
340 if (msgidoffset > 0)
341 return msgctxtid + msgidoffset;
343 sep = strchr(msgctxtid, '|');
345 if (sep) {
346 /* try with '\004' instead of '|', in case
347 * xgettext -kQ_:1g was used
349 gchar *tmp = g_alloca(strlen(msgctxtid) + 1);
350 strcpy(tmp, msgctxtid);
351 tmp[sep - msgctxtid] = '\004';
353 translation = _adg_dgettext(domain, tmp);
355 if (translation == tmp)
356 return sep + 1;
360 return translation;