/* * Copyright (C) 2012 - Juan Ferrer Toribio * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include "gvn-value.h" #include "gvn-misc.h" /** * SECTION: gvn-value * @Short_description: additional value manipulation functions * @Title: GvnValue * @See_also: #DbForm, #DbConn * * This functions are intended to expand or ease the use of the original GObject * library #GValue utilites. **/ //+++++++++++++++++++++++++++++++++++++++++++++++++++ Private static void gvn_value_new_from_string_real (GValue * value, GType type, const gchar * string, gsize len) { switch (type) { case G_TYPE_BOOLEAN: g_value_set_boolean (value, atoi (string)); break; case G_TYPE_CHAR: g_value_set_schar (value, atoi (string)); break; case G_TYPE_INT: g_value_set_int (value, atoi (string)); break; case G_TYPE_UINT: g_value_set_uint (value, (guint) atoi (string)); break; case G_TYPE_LONG: g_value_set_long (value, g_ascii_strtoll (string, NULL, 0)); break; case G_TYPE_ULONG: g_value_set_ulong (value, g_ascii_strtoull (string, NULL, 0)); break; case G_TYPE_FLOAT: g_value_set_float (value, atof (string)); break; case G_TYPE_DOUBLE: g_value_set_double (value, g_ascii_strtod (string, NULL)); break; case G_TYPE_STRING: g_value_set_string (value, string); break; default: { if (len == -1) len = strlen (string); if (type == G_TYPE_DATE) { GDate * date = g_date_new (); g_date_set_parse (date, string); if (g_date_valid (date)) g_value_take_boxed (value, date); else { g_warning ("Gvn: Can't transform string to GDate"); g_date_free (date); } } else if (type == G_TYPE_DATE_TIME) { GDateTime * datetime; gchar ** dt = g_strsplit_set (string, " -:", 0); if (g_strv_length (dt) >= 6) datetime = g_date_time_new_local (atoi (dt[0]), atoi (dt[1]), atoi (dt[2]), atoi (dt[3]), atoi (dt[4]), atoi (dt[5])); else g_warning ("Gvn: Can't transform string to GDateTime"); g_value_take_boxed (value, datetime); g_strfreev (dt); } else if (type == G_TYPE_BYTES) { if (len > 0) g_value_take_boxed (value, g_bytes_new (string, len)); else g_warning ("Gvn: Can't transform string to GBytes"); } else if (type != GVN_TYPE_NULL) g_return_if_reached (); } } } static void gvn_value_transform_string_to_any (const GValue * src, GValue * dst) { gvn_value_new_from_string_real (dst, G_VALUE_TYPE (dst), g_value_get_string (src), -1); } static void gvn_value_transform_null_to_any (const GValue * src, GValue * dst) {} static void gvn_value_transform_any_to_null (const GValue * src, GValue * dst) { gvn_value_set_null (dst); } static void gvn_value_transform_date_to_string (const GValue * src, GValue * dst) { GDate * date = g_value_get_boxed (src); if (date) { g_value_take_string (dst, g_strdup_printf ("%04u-%02u-%02u" ,g_date_get_year (date) ,g_date_get_month (date) ,g_date_get_day (date) )); } else g_value_take_string (dst, NULL); } static void gvn_value_transform_date_time_to_string (const GValue * src, GValue * dst) { gpointer date = g_value_get_boxed (src); if (date) g_value_take_string (dst, g_date_time_format (date, "%Y-%m-%d %T")); else g_value_take_string (dst, NULL); } static void gvn_value_transform_date_time_to_date (const GValue * src, GValue * dst) { GDateTime * date_time = g_value_get_boxed (src); if (date_time) { GDate * date = g_date_new_dmy ( g_date_time_get_day_of_month (date_time) ,g_date_time_get_month (date_time) ,g_date_time_get_year (date_time) ); g_value_take_boxed (dst, date); } else g_value_take_boxed (dst, NULL); } static void gvn_value_transform_date_to_date_time (const GValue * src, GValue * dst) { GDate * date = g_value_get_boxed (src); if (date) { GDateTime * date_time = g_date_time_new_local ( g_date_get_year (date) ,g_date_get_month (date) ,g_date_get_day (date) ,0 ,0 ,0.0 ); g_value_take_boxed (dst, date_time); } else g_value_take_boxed (dst, NULL); } //+++++++++++++++++++++++++++++++++++++++++++++++++++ Public /** * gvn_value_new: * @type: the type of new #GValue * * Creates a new #GValue * * Return value: a #GValue. **/ GValue * gvn_value_new (GType type) { GValue * value = g_new0 (GValue, 1); return g_value_init (value, type); } /** * gvn_value_is_null: * @value: the value to be checked * * Checks if a @value is of type GVN_TYPE_NULL * * Return value: %TRUE if its NULL, %FALSE otherwise. **/ /** * gvn_value_set_null: * @value: the value to be nulled * * Checks if a @value is of type GVN_TYPE_NULL, if not, sets it. **/ void gvn_value_set_null (GValue * value) { g_return_if_fail (G_IS_VALUE (value)); if (!gvn_value_is_null (value)) { g_value_unset (value); g_value_init (value, GVN_TYPE_NULL); } } /** * gvn_value_new_from_string: * @value: an uninitilized #GValue * @string: a string to be converted * @length: length of @string or -1 if its null terminated * @type: the type to be converted * * Creates a new @value from a string **/ void gvn_value_new_from_string (GValue * value, GType type, const gchar * string, gsize len) { g_return_if_fail (string != NULL); g_value_init (value, type); gvn_value_new_from_string_real (value, type, string, len); } /** * gvn_value_new_valist: * @value: an uninitilized #GValue * @type: the type of value * @content: a pointer to the value content * * Initializes the @value with the specified type and content. **/ void gvn_value_new_with_content (GValue * value, GType type, gpointer content) { g_value_init (value, type); switch (type) { case G_TYPE_BOOLEAN: g_value_set_boolean (value, *((gboolean *) content)); break; case G_TYPE_CHAR: g_value_set_schar (value, *((gint8 *) content)); break; case G_TYPE_INT: g_value_set_int (value, *((gint *) content)); break; case G_TYPE_UINT: g_value_set_uint (value, *((guint *) content)); break; case G_TYPE_LONG: g_value_set_long (value, *((glong *) content)); break; case G_TYPE_ULONG: g_value_set_ulong (value, *((gulong *) content)); break; case G_TYPE_FLOAT: g_value_set_float (value, *((gfloat *) content)); break; case G_TYPE_DOUBLE: g_value_set_double (value, *((gdouble *) content)); break; case G_TYPE_STRING: g_value_set_string (value, (gchar *) content); break; default: if (type == G_TYPE_DATE || type == G_TYPE_DATE_TIME || type == G_TYPE_BYTES) g_value_set_boxed (value, content); else if (G_TYPE_IS_OBJECT (type)) g_value_set_object (value, content); else if (type != GVN_TYPE_NULL) g_return_if_reached (); } } /** * gvn_value_get_valist: * @value: the type of value * @va: a string to be converted * * Sets the value of the initilized @value with the value of next * element in @va **/ void gvn_value_get_valist (const GValue * value, va_list va) { GType type = G_VALUE_TYPE (value); switch (type) { case G_TYPE_BOOLEAN: *va_arg (va, gboolean*) = g_value_get_boolean (value); break; case G_TYPE_CHAR: *va_arg (va, gint8*) = g_value_get_schar (value); break; case G_TYPE_INT: *va_arg (va, gint*) = g_value_get_int (value); break; case G_TYPE_UINT: *va_arg (va, guint*) = g_value_get_uint (value); break; case G_TYPE_LONG: *va_arg (va, glong*) = g_value_get_long (value); break; case G_TYPE_ULONG: *va_arg (va, gulong*) = g_value_get_ulong (value); break; case G_TYPE_FLOAT: *va_arg (va, gfloat*) = g_value_get_float (value); break; case G_TYPE_DOUBLE: *va_arg (va, gdouble*) = g_value_get_double (value); break; case G_TYPE_STRING: *va_arg (va, gchar**) = g_value_dup_string (value); break; default: if (type == G_TYPE_DATE || type == G_TYPE_DATE_TIME || type == G_TYPE_BYTES) *va_arg (va, gpointer*) = g_value_dup_boxed (value); else if (G_TYPE_IS_OBJECT (type)) *va_arg (va, gpointer*) = g_value_dup_object (value); else if (type != GVN_TYPE_NULL) g_return_if_reached (); } } /** * gvn_value_compare: * @a: a #GValue to be compared * @b: a #GValue to be compared * * Does the same as g_value_compare0(), but returns a %gboolean. * * Return value: %TRUE if two values are equal, %FALSE otherwise. **/ /** * gvn_value_compare0: * @a: #GValue to be compared * @b: #GValue to be compared * * Compares a and b. The two values ​​must be of the same type or GVN_TYPE_NULL. * * Return value: -1, 0 or 1, if @a is <, == or > than @b. **/ gint gvn_value_compare0 (const GValue * a, const GValue * b) { GType a_type = G_VALUE_TYPE (a); gboolean a_is_val = G_IS_VALUE (a); gboolean b_is_val = G_IS_VALUE (b); if (!(a_is_val && b_is_val)) { if (a_is_val) return 1; if (b_is_val) return -1; } else if (a_type == G_VALUE_TYPE (b)) { switch (a_type) { case G_TYPE_FLOAT: { gfloat aux = g_value_get_float (a) - g_value_get_float (b); return (aux > 0.0) ? 1 : (aux < 0.0) ? -1 : 0; } case G_TYPE_DOUBLE: { gdouble aux = g_value_get_double (a) - g_value_get_double (b); return (aux > 0.0) ? 1 : (aux < 0.0) ? -1 : 0; } case G_TYPE_INT: return g_value_get_int (a) - g_value_get_int (b); case G_TYPE_UINT: return (gint) (g_value_get_uint (a) - g_value_get_uint (b)); case G_TYPE_LONG: return (gint) (g_value_get_long (a) - g_value_get_long (b)); case G_TYPE_ULONG: return (gint) (g_value_get_ulong (a) - g_value_get_ulong (b)); case G_TYPE_BOOLEAN: return (gint) (g_value_get_boolean (a) - g_value_get_boolean (b)); case G_TYPE_CHAR: return (gint) (g_value_get_schar (a) - g_value_get_schar (b)); case G_TYPE_STRING: return g_strcmp0 (g_value_get_string (a), g_value_get_string (b)); default: if (a_type == GVN_TYPE_NULL) return 0; if (G_TYPE_FUNDAMENTAL (a_type) == G_TYPE_BOXED) { gpointer a_boxed = g_value_get_boxed (a); gpointer b_boxed = g_value_get_boxed (b); if (!a_boxed) return (gint) (a_boxed - b_boxed); if (!b_boxed) return (gint) (a_boxed - b_boxed); if (a_type == G_TYPE_DATE) return g_date_compare (a_boxed, b_boxed); if (a_type == G_TYPE_DATE_TIME) return g_date_time_compare (a_boxed, b_boxed); else if (a_type == G_TYPE_BYTES) return (gint) (a_boxed - b_boxed); } g_warning (_("Attempting to compare invalid types: %s\n"), g_type_name (a_type)); } } else if (gvn_value_is_null (a)) return -1; else if (gvn_value_is_null (b)) return 1; return 1; } /** * gvn_value_copy: * @src: source #GValue * @dst: destination #GValue * * Copies the value of @src into @dst. This function also works with #GvnNull * values. **/ void gvn_value_copy (const GValue * src, GValue * dst) { g_return_if_fail (G_IS_VALUE (src)); g_return_if_fail (G_IS_VALUE (dst)); if (G_VALUE_TYPE (src) != G_VALUE_TYPE (dst)) { g_value_unset (dst); g_value_init (dst, G_VALUE_TYPE (src)); } g_value_copy (src, dst); } /** * gvn_value_ccopy: * @src: source #GValue * @dst: destination #GValue * * Compares @src with @dst, if they are different copies the value of @src into * @dst. This function also works with #GvnNull values. * * Return value: %TRUE if they are copied, %FALSE if they are equals. **/ gboolean gvn_value_ccopy (const GValue * src, GValue * dst) { if (gvn_value_compare (src, dst)) return FALSE; gvn_value_copy (src, dst); return TRUE; } /* * Checks the validity of @format attending to the valid specifier characters in * @specifiers, the other flags in the format string won't be checked. */ gboolean format_valid (const gchar * format, const gchar * specifiers) { gboolean started = FALSE; gint i, j; if (format && specifiers) for (i = 0; format[i] != '\0'; i++) { if (format[i] == '%') { started = TRUE; continue; } else if (started && format[i] == ' ') break; for (j = 0; specifiers[j] != '\0'; j++) if (started && format[i] == specifiers[j] && (format[i+1] == ' ' || format[i+1] == '\0')) return TRUE; } return FALSE; } /** * gvn_value_to_format_string: * @src: source #GValue * @format: a format string * @dst: destination #GValue * * Sets the content of @dst to a string value depending on the type of @src and * according to @format. @format must be a valid format string as the used by * the printf() family of functions and, in the case of dates, the ones used by * strftime(). See g_ascii_formatd() and g_date_time_format(). The output may * vary depending on the locale. * * The accepted types are #gboolean, #guint, #gint, #gfloat, #gdouble, #guchar, * #gchar, #gchararray, #GDate and #GDateTime, any other types may have an * unexpected output. **/ void gvn_value_to_format_string (const GValue * src, const gchar * format, GValue * dst) { GType type = G_VALUE_TYPE (src); g_value_init (dst, G_TYPE_STRING); switch (type) { case G_TYPE_BOOLEAN: { gboolean b = g_value_get_boolean (src); g_value_set_string (dst, b ? _("Yes") : _("No")); break; } case G_TYPE_INT: { gchar * str; gint i = g_value_get_int (src); str = g_strdup_printf (format_valid (format, "duoXxp") ? format : "%d", i); g_value_set_string (dst, str); g_free (str); break; } case G_TYPE_UINT: { gchar * str; guint u = g_value_get_uint (src); str = g_strdup_printf (format_valid (format, "udoXxp") ? format : "%u", u); g_value_set_string (dst, str); g_free (str); break; } case G_TYPE_FLOAT: case G_TYPE_DOUBLE: { gdouble dec; gchar buffer [G_ASCII_DTOSTR_BUF_SIZE]; if (type == G_TYPE_FLOAT) dec = (gdouble) g_value_get_float (src); else dec = g_value_get_double (src); g_ascii_formatd (buffer, G_ASCII_DTOSTR_BUF_SIZE, format_valid (format, "fFeEgGaA") ? format : "%.2f", dec); g_value_set_string (dst, buffer); break; } default: if (type == G_TYPE_DATE) { gchar buffer[120]; GDate * date = g_value_get_boxed (src); g_date_strftime (buffer, 120, format ? format : "%Y-%m-%d", date); g_value_set_string (dst, buffer); } else if (type == G_TYPE_DATE_TIME) { gchar * str; GDateTime * dt = g_value_get_boxed (src); str = g_date_time_format (dt, format ? format : "%Y-%m-%d %T"); g_value_set_string (dst, str); g_free (str); } else if (!gvn_value_is_null (src)) g_value_transform (src, dst); else g_value_set_string (dst, ""); } } /** * gvn_type_init: * * Initializes library types, also calls g_type_init(). **/ void gvn_type_init () { gint n; GType types[] = { G_TYPE_BOOLEAN ,G_TYPE_CHAR ,G_TYPE_INT ,G_TYPE_UINT ,G_TYPE_LONG ,G_TYPE_ULONG ,G_TYPE_FLOAT ,G_TYPE_DOUBLE ,G_TYPE_STRING ,G_TYPE_DATE ,G_TYPE_DATE_TIME ,G_TYPE_BYTES ,G_TYPE_NONE }; for (n = 0; types[n] != G_TYPE_NONE; n++) { g_value_register_transform_func (types[n], GVN_TYPE_NULL, gvn_value_transform_any_to_null ); g_value_register_transform_func (GVN_TYPE_NULL, types[n], gvn_value_transform_null_to_any ); g_value_register_transform_func (G_TYPE_STRING, types[n], gvn_value_transform_string_to_any ); } g_value_register_transform_func (G_TYPE_DATE, G_TYPE_STRING, gvn_value_transform_date_to_string ); g_value_register_transform_func (G_TYPE_DATE_TIME, G_TYPE_STRING, gvn_value_transform_date_time_to_string ); g_value_register_transform_func (G_TYPE_DATE_TIME, G_TYPE_DATE, gvn_value_transform_date_time_to_date ); g_value_register_transform_func (G_TYPE_DATE, G_TYPE_DATE_TIME, gvn_value_transform_date_to_date_time ); }