/* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with the program; if not, see * * * Authors: * Srinivasa Ragavan * * Copyright (C) 2012 Intel Corporation (www.intel.com) * */ #include #include #include #include #include #include #include #include #include "evolution-util.h" /** * e_flexible_strtod: * @nptr: the string to convert to a numeric value. * @endptr: if non-NULL, it returns the character after * the last character used in the conversion. * * Converts a string to a gdouble value. This function detects * strings either in the standard C locale or in the current locale. * * This function is typically used when reading configuration files or * other non-user input that should not be locale dependent, but may * have been in the past. To handle input from the user you should * normally use the locale-sensitive system strtod function. * * To convert from a double to a string in a locale-insensitive way, use * @g_ascii_dtostr. * * Returns: the gdouble value **/ gdouble e_flexible_strtod (const gchar *nptr, gchar **endptr) { gchar *fail_pos; gdouble val; struct lconv *locale_data; const gchar *decimal_point; gint decimal_point_len; const gchar *p, *decimal_point_pos; const gchar *end = NULL; /* Silence gcc */ gchar *copy, *c; g_return_val_if_fail (nptr != NULL, 0); fail_pos = NULL; locale_data = localeconv (); decimal_point = locale_data->decimal_point; decimal_point_len = strlen (decimal_point); g_return_val_if_fail (decimal_point_len != 0, 0); decimal_point_pos = NULL; if (!strcmp (decimal_point, ".")) return strtod (nptr, endptr); p = nptr; /* Skip leading space */ while (isspace ((guchar) * p)) p++; /* Skip leading optional sign */ if (*p == '+' || *p == '-') p++; if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { p += 2; /* HEX - find the (optional) decimal point */ while (isxdigit ((guchar) * p)) p++; if (*p == '.') { decimal_point_pos = p++; while (isxdigit ((guchar) * p)) p++; if (*p == 'p' || *p == 'P') p++; if (*p == '+' || *p == '-') p++; while (isdigit ((guchar) * p)) p++; end = p; } else if (strncmp (p, decimal_point, decimal_point_len) == 0) { return strtod (nptr, endptr); } } else { while (isdigit ((guchar) * p)) p++; if (*p == '.') { decimal_point_pos = p++; while (isdigit ((guchar) * p)) p++; if (*p == 'e' || *p == 'E') p++; if (*p == '+' || *p == '-') p++; while (isdigit ((guchar) * p)) p++; end = p; } else if (strncmp (p, decimal_point, decimal_point_len) == 0) { return strtod (nptr, endptr); } } /* For the other cases, we need not convert the decimal point */ if (!decimal_point_pos) return strtod (nptr, endptr); /* We need to convert the '.' to the locale specific decimal point */ copy = g_malloc (end - nptr + 1 + decimal_point_len); c = copy; memcpy (c, nptr, decimal_point_pos - nptr); c += decimal_point_pos - nptr; memcpy (c, decimal_point, decimal_point_len); c += decimal_point_len; memcpy (c, decimal_point_pos + 1, end - (decimal_point_pos + 1)); c += end - (decimal_point_pos + 1); *c = 0; val = strtod (copy, &fail_pos); if (fail_pos) { if (fail_pos > decimal_point_pos) fail_pos = (gchar *) nptr + (fail_pos - copy) - (decimal_point_len - 1); else fail_pos = (gchar *) nptr + (fail_pos - copy); } g_free (copy); if (endptr) *endptr = fail_pos; return val; } /** * e_ascii_dtostr: * @buffer: A buffer to place the resulting string in * @buf_len: The length of the buffer. * @format: The printf-style format to use for the * code to use for converting. * @d: The double to convert * * Converts a double to a string, using the '.' as * decimal_point. To format the number you pass in * a printf-style formating string. Allowed conversion * specifiers are eEfFgG. * * If you want to generates enough precision that converting * the string back using @g_strtod gives the same machine-number * (on machines with IEEE compatible 64bit doubles) use the format * string "%.17g". If you do this it is guaranteed that the size * of the resulting string will never be larger than * @G_ASCII_DTOSTR_BUF_SIZE bytes. * * Returns: the pointer to the buffer with the converted string **/ gchar * e_ascii_dtostr (gchar *buffer, gint buf_len, const gchar *format, gdouble d) { struct lconv *locale_data; const gchar *decimal_point; gint decimal_point_len; gchar *p; gint rest_len; gchar format_char; g_return_val_if_fail (buffer != NULL, NULL); g_return_val_if_fail (format[0] == '%', NULL); g_return_val_if_fail (strpbrk (format + 1, "'l%") == NULL, NULL); format_char = format[strlen (format) - 1]; g_return_val_if_fail (format_char == 'e' || format_char == 'E' || format_char == 'f' || format_char == 'F' || format_char == 'g' || format_char == 'G', NULL); if (format[0] != '%') return NULL; if (strpbrk (format + 1, "'l%")) return NULL; if (!(format_char == 'e' || format_char == 'E' || format_char == 'f' || format_char == 'F' || format_char == 'g' || format_char == 'G')) return NULL; g_snprintf (buffer, buf_len, format, d); locale_data = localeconv (); decimal_point = locale_data->decimal_point; decimal_point_len = strlen (decimal_point); g_return_val_if_fail (decimal_point_len != 0, NULL); if (strcmp (decimal_point, ".")) { p = buffer; if (*p == '+' || *p == '-') p++; while (isdigit ((guchar) * p)) p++; if (strncmp (p, decimal_point, decimal_point_len) == 0) { *p = '.'; p++; if (decimal_point_len > 1) { rest_len = strlen (p + (decimal_point_len - 1)); memmove (p, p + (decimal_point_len - 1), rest_len); p[rest_len] = 0; } } } return buffer; } /** * e_builder_get_widget: * @builder: a #GtkBuilder * @widget_name: name of a widget in @builder * * Gets the widget named @widget_name. Note that this function does not * increment the reference count of the returned widget. If @widget_name * could not be found in the @builder's object tree, a run-time * warning is emitted since this usually indicates a programming error. * * This is a convenience function to work around the awkwardness of * #GtkBuilder returning #GObject pointers, when the vast majority of * the time you want a #GtkWidget pointer. * * If you need something from @builder other than a #GtkWidget, or you * want to test for the existence of some widget name without incurring * a run-time warning, use gtk_builder_get_object(). * * Returns: the widget named @widget_name, or %NULL **/ GtkWidget * e_builder_get_widget (GtkBuilder *builder, const gchar *widget_name) { GObject *object; g_return_val_if_fail (GTK_IS_BUILDER (builder), NULL); g_return_val_if_fail (widget_name != NULL, NULL); object = gtk_builder_get_object (builder, widget_name); if (object == NULL) { g_warning ("Could not find widget '%s'", widget_name); return NULL; } return GTK_WIDGET (object); } /** * e_load_ui_builder_definition: * @builder: a #GtkBuilder * @basename: basename of the UI definition file * * Loads a UI definition into @builder from Evolution's UI directory. * Failure here is fatal, since the application can't function without * its UI definitions. **/ void e_load_ui_builder_definition (GtkBuilder *builder, const gchar *basename) { gchar *filename; GError *error = NULL; g_return_if_fail (GTK_IS_BUILDER (builder)); g_return_if_fail (basename != NULL); filename = g_build_filename (EVOLUTION_UIDIR, basename, NULL); gtk_builder_add_from_file (builder, filename, &error); g_free (filename); if (error != NULL) { g_error ("%s: %s", basename, error->message); g_assert_not_reached (); } }