aboutsummaryrefslogblamecommitdiffstats
path: root/libevolution-utils/evolution-util.c
blob: 3bba779a090d793f5f784d0a3cb51d09f625018f (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16















                                                                             
                                                      








































































































































































































































                                                                                


                                                                       







                                                

































































                                                                         
/*
 * 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 <http://www.gnu.org/licenses/>
 *
 *
 * Authors:
 *      Srinivasa Ragavan <sragavan@gnome.org>
 *
 * Copyright (C) 2012 Intel Corporation (www.intel.com)
 *
 */

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <ctype.h>
#include <math.h>
#include <string.h>
#include <locale.h>

#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 ();
    }
}