No issues found
1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2 of the License, or (at your option) version 3.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with the program; if not, see <http://www.gnu.org/licenses/>
14 *
15 *
16 * Authors:
17 * Srinivasa Ragavan <sragavan@gnome.org>
18 *
19 * Copyright (C) 2012 Intel Corporation (www.intel.com)
20 *
21 */
22
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <errno.h>
26 #include <unistd.h>
27 #include <ctype.h>
28 #include <math.h>
29 #include <string.h>
30 #include <locale.h>
31
32 #include "evolution-util.h"
33
34 /**
35 * e_flexible_strtod:
36 * @nptr: the string to convert to a numeric value.
37 * @endptr: if non-NULL, it returns the character after
38 * the last character used in the conversion.
39 *
40 * Converts a string to a gdouble value. This function detects
41 * strings either in the standard C locale or in the current locale.
42 *
43 * This function is typically used when reading configuration files or
44 * other non-user input that should not be locale dependent, but may
45 * have been in the past. To handle input from the user you should
46 * normally use the locale-sensitive system strtod function.
47 *
48 * To convert from a double to a string in a locale-insensitive way, use
49 * @g_ascii_dtostr.
50 *
51 * Returns: the gdouble value
52 **/
53
54 gdouble
55 e_flexible_strtod (const gchar *nptr,
56 gchar **endptr)
57 {
58 gchar *fail_pos;
59 gdouble val;
60 struct lconv *locale_data;
61 const gchar *decimal_point;
62 gint decimal_point_len;
63 const gchar *p, *decimal_point_pos;
64 const gchar *end = NULL; /* Silence gcc */
65 gchar *copy, *c;
66
67 g_return_val_if_fail (nptr != NULL, 0);
68
69 fail_pos = NULL;
70
71 locale_data = localeconv ();
72 decimal_point = locale_data->decimal_point;
73 decimal_point_len = strlen (decimal_point);
74
75 g_return_val_if_fail (decimal_point_len != 0, 0);
76
77 decimal_point_pos = NULL;
78 if (!strcmp (decimal_point, "."))
79 return strtod (nptr, endptr);
80
81 p = nptr;
82
83 /* Skip leading space */
84 while (isspace ((guchar) * p))
85 p++;
86
87 /* Skip leading optional sign */
88 if (*p == '+' || *p == '-')
89 p++;
90
91 if (p[0] == '0' &&
92 (p[1] == 'x' || p[1] == 'X')) {
93 p += 2;
94 /* HEX - find the (optional) decimal point */
95
96 while (isxdigit ((guchar) * p))
97 p++;
98
99 if (*p == '.') {
100 decimal_point_pos = p++;
101
102 while (isxdigit ((guchar) * p))
103 p++;
104
105 if (*p == 'p' || *p == 'P')
106 p++;
107 if (*p == '+' || *p == '-')
108 p++;
109 while (isdigit ((guchar) * p))
110 p++;
111 end = p;
112 } else if (strncmp (p, decimal_point, decimal_point_len) == 0) {
113 return strtod (nptr, endptr);
114 }
115 } else {
116 while (isdigit ((guchar) * p))
117 p++;
118
119 if (*p == '.') {
120 decimal_point_pos = p++;
121
122 while (isdigit ((guchar) * p))
123 p++;
124
125 if (*p == 'e' || *p == 'E')
126 p++;
127 if (*p == '+' || *p == '-')
128 p++;
129 while (isdigit ((guchar) * p))
130 p++;
131 end = p;
132 } else if (strncmp (p, decimal_point, decimal_point_len) == 0) {
133 return strtod (nptr, endptr);
134 }
135 }
136 /* For the other cases, we need not convert the decimal point */
137
138 if (!decimal_point_pos)
139 return strtod (nptr, endptr);
140
141 /* We need to convert the '.' to the locale specific decimal point */
142 copy = g_malloc (end - nptr + 1 + decimal_point_len);
143
144 c = copy;
145 memcpy (c, nptr, decimal_point_pos - nptr);
146 c += decimal_point_pos - nptr;
147 memcpy (c, decimal_point, decimal_point_len);
148 c += decimal_point_len;
149 memcpy (c, decimal_point_pos + 1, end - (decimal_point_pos + 1));
150 c += end - (decimal_point_pos + 1);
151 *c = 0;
152
153 val = strtod (copy, &fail_pos);
154
155 if (fail_pos) {
156 if (fail_pos > decimal_point_pos)
157 fail_pos =
158 (gchar *) nptr + (fail_pos - copy) -
159 (decimal_point_len - 1);
160 else
161 fail_pos = (gchar *) nptr + (fail_pos - copy);
162 }
163
164 g_free (copy);
165
166 if (endptr)
167 *endptr = fail_pos;
168
169 return val;
170 }
171
172 /**
173 * e_ascii_dtostr:
174 * @buffer: A buffer to place the resulting string in
175 * @buf_len: The length of the buffer.
176 * @format: The printf-style format to use for the
177 * code to use for converting.
178 * @d: The double to convert
179 *
180 * Converts a double to a string, using the '.' as
181 * decimal_point. To format the number you pass in
182 * a printf-style formating string. Allowed conversion
183 * specifiers are eEfFgG.
184 *
185 * If you want to generates enough precision that converting
186 * the string back using @g_strtod gives the same machine-number
187 * (on machines with IEEE compatible 64bit doubles) use the format
188 * string "%.17g". If you do this it is guaranteed that the size
189 * of the resulting string will never be larger than
190 * @G_ASCII_DTOSTR_BUF_SIZE bytes.
191 *
192 * Returns: the pointer to the buffer with the converted string
193 **/
194 gchar *
195 e_ascii_dtostr (gchar *buffer,
196 gint buf_len,
197 const gchar *format,
198 gdouble d)
199 {
200 struct lconv *locale_data;
201 const gchar *decimal_point;
202 gint decimal_point_len;
203 gchar *p;
204 gint rest_len;
205 gchar format_char;
206
207 g_return_val_if_fail (buffer != NULL, NULL);
208 g_return_val_if_fail (format[0] == '%', NULL);
209 g_return_val_if_fail (strpbrk (format + 1, "'l%") == NULL, NULL);
210
211 format_char = format[strlen (format) - 1];
212
213 g_return_val_if_fail (format_char == 'e' || format_char == 'E' ||
214 format_char == 'f' || format_char == 'F' ||
215 format_char == 'g' || format_char == 'G',
216 NULL);
217
218 if (format[0] != '%')
219 return NULL;
220
221 if (strpbrk (format + 1, "'l%"))
222 return NULL;
223
224 if (!(format_char == 'e' || format_char == 'E' ||
225 format_char == 'f' || format_char == 'F' ||
226 format_char == 'g' || format_char == 'G'))
227 return NULL;
228
229 g_snprintf (buffer, buf_len, format, d);
230
231 locale_data = localeconv ();
232 decimal_point = locale_data->decimal_point;
233 decimal_point_len = strlen (decimal_point);
234
235 g_return_val_if_fail (decimal_point_len != 0, NULL);
236
237 if (strcmp (decimal_point, ".")) {
238 p = buffer;
239
240 if (*p == '+' || *p == '-')
241 p++;
242
243 while (isdigit ((guchar) * p))
244 p++;
245
246 if (strncmp (p, decimal_point, decimal_point_len) == 0) {
247 *p = '.';
248 p++;
249 if (decimal_point_len > 1) {
250 rest_len = strlen (p + (decimal_point_len - 1));
251 memmove (
252 p, p + (decimal_point_len - 1),
253 rest_len);
254 p[rest_len] = 0;
255 }
256 }
257 }
258
259 return buffer;
260 }
261
262 /**
263 * e_builder_get_widget:
264 * @builder: a #GtkBuilder
265 * @widget_name: name of a widget in @builder
266 *
267 * Gets the widget named @widget_name. Note that this function does not
268 * increment the reference count of the returned widget. If @widget_name
269 * could not be found in the @builder<!-- -->'s object tree, a run-time
270 * warning is emitted since this usually indicates a programming error.
271 *
272 * This is a convenience function to work around the awkwardness of
273 * #GtkBuilder returning #GObject pointers, when the vast majority of
274 * the time you want a #GtkWidget pointer.
275 *
276 * If you need something from @builder other than a #GtkWidget, or you
277 * want to test for the existence of some widget name without incurring
278 * a run-time warning, use gtk_builder_get_object().
279 *
280 * Returns: the widget named @widget_name, or %NULL
281 **/
282 GtkWidget *
283 e_builder_get_widget (GtkBuilder *builder,
284 const gchar *widget_name)
285 {
286 GObject *object;
287
288 g_return_val_if_fail (GTK_IS_BUILDER (builder), NULL);
289 g_return_val_if_fail (widget_name != NULL, NULL);
290
291 object = gtk_builder_get_object (builder, widget_name);
292 if (object == NULL) {
293 g_warning ("Could not find widget '%s'", widget_name);
294 return NULL;
295 }
296
297 return GTK_WIDGET (object);
298 }
299
300 /**
301 * e_load_ui_builder_definition:
302 * @builder: a #GtkBuilder
303 * @basename: basename of the UI definition file
304 *
305 * Loads a UI definition into @builder from Evolution's UI directory.
306 * Failure here is fatal, since the application can't function without
307 * its UI definitions.
308 **/
309 void
310 e_load_ui_builder_definition (GtkBuilder *builder,
311 const gchar *basename)
312 {
313 gchar *filename;
314 GError *error = NULL;
315
316 g_return_if_fail (GTK_IS_BUILDER (builder));
317 g_return_if_fail (basename != NULL);
318
319 filename = g_build_filename (EVOLUTION_UIDIR, basename, NULL);
320 gtk_builder_add_from_file (builder, filename, &error);
321 g_free (filename);
322
323 if (error != NULL) {
324 g_error ("%s: %s", basename, error->message);
325 g_assert_not_reached ();
326 }
327 }