[gcalctool] Add string serializer class from parts of mp-convert and math-equation
- From: Robin Sonefors <rsonefors src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gcalctool] Add string serializer class from parts of mp-convert and math-equation
- Date: Mon, 4 Oct 2010 19:59:13 +0000 (UTC)
commit 492223c3f9e503686d62e74c48b994e7588f2cee
Author: Robin Sonefors <ozamosi flukkost nu>
Date: Mon Oct 4 21:51:20 2010 +0200
Add string serializer class from parts of mp-convert and math-equation
Put back thousands separators support, fixes #628908
configure.ac | 4 +
src/Makefile.am | 21 ++-
src/gcalccmd.c | 7 +-
src/gcalctool.c | 4 +-
src/math-buttons.c | 22 ++-
src/math-enums.c.template | 36 ++++
src/math-enums.h.template | 25 +++
src/math-equation.c | 163 ++++++---------
src/math-equation.h | 12 +-
src/math-variables.c | 3 +-
src/mp-binary.c | 7 +-
src/mp-convert.c | 247 ++---------------------
src/mp-equation-lexer.l | 1 -
src/mp-serializer.c | 508 +++++++++++++++++++++++++++++++++++++++++++++
src/mp-serializer.h | 72 +++++++
src/mp.h | 18 --
src/unittest.c | 3 +-
17 files changed, 770 insertions(+), 383 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index cf8b052..3ae6096 100644
--- a/configure.ac
+++ b/configure.ac
@@ -49,8 +49,12 @@ PKG_CHECK_MODULES(GCALCTOOL, [
PKG_CHECK_MODULES(GCALCCMD, [
glib-2.0
+ gobject-2.0
])
+GLIB_MKENUMS=`$PKG_CONFIG --variable=glib_mkenums glib-2.0`
+AC_SUBST(GLIB_MKENUMS)
+
AC_CHECK_LIB(m, log)
dnl ###########################################################################
diff --git a/src/Makefile.am b/src/Makefile.am
index 6875200..db74fe0 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -24,6 +24,8 @@ gcalctool_SOURCES = \
math-variables.h \
math-window.c \
math-window.h \
+ math-enums.c \
+ math-enums.h \
mp.c \
mp.h \
mp-binary.c \
@@ -37,6 +39,8 @@ gcalctool_SOURCES = \
mp-equation-lexer.h \
mp-equation-parser.c \
mp-equation-parser.h \
+ mp-serializer.c \
+ mp-serializer.h \
financial.c \
financial.h \
unittest.c \
@@ -53,7 +57,11 @@ gcalccmd_SOURCES = \
mp-trigonometric.c \
mp-equation.c \
mp-equation-parser.c \
- mp-equation-lexer.c
+ mp-equation-lexer.c \
+ mp-serializer.c \
+ mp-serializer.h\
+ math-enums.c \
+ math-enums.h
gcalccmd_LDADD = \
$(GCALCCMD_LIBS) \
@@ -63,7 +71,9 @@ CLEANFILES = \
mp-equation-parser.h \
mp-equation-parser.c \
mp-equation-lexer.c \
- mp-equation-lexer.h
+ mp-equation-lexer.h \
+ math-enums.c \
+ math-enums.h
# Generate parser files
mp-equation-parser.c mp-equation-parser.h: mp-equation-parser.y mp-equation-lexer.h
@@ -78,6 +88,13 @@ mp-equation-parser.o: mp-equation-lexer.h
mp-equation-lexer.o: mp-equation-parser.h
mp-equation.c: mp-equation-lexer.h mp-equation-parser.h
+# Generate enum types
+math-enums.h: math-enums.h.template
+ $(AM_V_GEN)$(GLIB_MKENUMS) --template $(srcdir)/math-enums.h.template $(srcdir)/mp-serializer.h > math-enums.h
+
+math-enums.c: math-enums.c.template math-enums.h
+ $(AM_V_GEN)$(GLIB_MKENUMS) --template $(srcdir)/math-enums.c.template $(srcdir)/mp-serializer.h > math-enums.c
+
# Install a symlink between gcalctool and gnome-calculator
install-exec-hook:
test -e "$(DESTDIR)$(bindir)/gnome-calculator" \
diff --git a/src/gcalccmd.c b/src/gcalccmd.c
index 2812952..e7a6509 100644
--- a/src/gcalccmd.c
+++ b/src/gcalccmd.c
@@ -23,8 +23,10 @@
#include <string.h>
#include <sys/types.h>
#include <time.h>
+#include <locale.h>
#include "mp-equation.h"
+#include "mp-serializer.h"
#define MAXLINE 1024
@@ -48,7 +50,7 @@ solve(const char *equation)
else if (ret)
fprintf(stderr, "Error %d\n", ret);
else {
- mp_cast_to_string(&z, 10, 10, 9, 1, TRUE, result_str, MAXLINE);
+ mp_serializer_to_specific_string(&z, 10, 9, true, true, result_str, MAXLINE);
printf("%s\n", result_str);
}
}
@@ -79,6 +81,9 @@ main(int argc, char **argv)
/* Seed random number generator. */
srand48((long) time((time_t *) 0));
+ g_type_init ();
+ setlocale(LC_NUMERIC, "");
+
equation = (char *) malloc(MAXLINE * sizeof(char));
while (1) {
printf("> ");
diff --git a/src/gcalctool.c b/src/gcalctool.c
index e2d8b45..1bb4f87 100644
--- a/src/gcalctool.c
+++ b/src/gcalctool.c
@@ -20,6 +20,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#include <locale.h>
#include "currency.h"
#include "unittest.h"
@@ -61,7 +62,7 @@ solve(const char *equation)
exit(1);
}
else {
- mp_cast_to_string(&result, 10, 10, 9, 1, TRUE, result_str, 1024);
+ mp_serializer_to_specific_string(&result, options.base, 9, true, true, result_str, 1024);
printf("%s\n", result_str);
exit(0);
}
@@ -212,6 +213,7 @@ main(int argc, char **argv)
gchar *source_currency, *target_currency;
g_type_init();
+ setlocale(LC_NUMERIC, "");
bindtextdomain(GETTEXT_PACKAGE, LOCALE_DIR);
bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
diff --git a/src/math-buttons.c b/src/math-buttons.c
index 81b3057..ab0b200 100644
--- a/src/math-buttons.c
+++ b/src/math-buttons.c
@@ -21,6 +21,7 @@
#include "math-buttons.h"
#include "financial.h"
#include "currency.h"
+#include "mp-serializer.h"
enum {
PROP_0,
@@ -422,10 +423,10 @@ update_angle_label (MathButtons *buttons)
mp_set_from_mp(&x, &input);
mp_set_from_integer(mp_is_negative(&input) ? -1 : 1, &fraction);
}
- mp_cast_to_string(&input, 10, 10, 2, false, true, input_text, 1024);
+ mp_serializer_to_specific_string(&input, 10, 2, false, true, input_text, 1024);
mp_multiply_integer(&fraction, 360, &output);
- mp_cast_to_string(&output, 10, 10, 2, false, true, output_text, 1024);
+ mp_serializer_to_specific_string(&output, 10, 2, false, true, output_text, 1024);
label = g_strdup_printf(_("%s radians = %s degrees"), input_text, output_text);
break;
case MP_GRADIANS:
@@ -442,10 +443,10 @@ update_angle_label (MathButtons *buttons)
mp_set_from_integer(mp_is_negative(&input) ? -1 : 1, &fraction);
}
- mp_cast_to_string(&input, 10, 10, 2, false, true, input_text, 1024);
+ mp_serializer_to_specific_string(&input, 10, 2, false, true, input_text, 1024);
mp_multiply_integer(&fraction, 360, &output);
- mp_cast_to_string(&output, 10, 10, 2, false, true, output_text, 1024);
+ mp_serializer_to_specific_string(&output, 10, 2, false, true, output_text, 1024);
label = g_strdup_printf(_("%s gradians = %s degrees"), input_text, output_text);
break;
}
@@ -543,8 +544,8 @@ update_currency_label(MathButtons *buttons)
const char *source_symbol, *target_symbol;
int i;
- mp_cast_to_string(&x, 10, 10, 2, false, true, input_text, 1024);
- mp_cast_to_string(&value, 10, 10, 2, false, true, output_text, 1024);
+ mp_serializer_to_specific_string(&x, 10, 2, false, true, input_text, 1024);
+ mp_serializer_to_specific_string(&value, 10, 2, false, true, output_text, 1024);
for (i = 0; strcmp(math_equation_get_source_currency(buttons->priv->equation), currency_names[i].short_name) != 0; i++);
source_symbol = currency_names[i].symbol;
@@ -861,8 +862,10 @@ load_mode(MathButtons *buttons, ButtonMode mode)
g_free(name);
}
widget = GET_WIDGET(builder, "calc_numeric_point_button");
- if (widget)
- gtk_button_set_label(GTK_BUTTON(widget), math_equation_get_numeric_point_text(buttons->priv->equation));
+ if (widget) {
+ MpSerializer *serializer = math_equation_get_serializer(buttons->priv->equation);
+ gtk_button_set_label(GTK_BUTTON(widget), mp_serializer_get_numeric_point_text(serializer));
+ }
widget = GET_WIDGET(builder, "calc_superscript_button");
if (widget) {
@@ -1194,7 +1197,8 @@ make_register_menu_item(MathButtons *buttons, const gchar *name, const MPNumber
GtkWidget *item, *label;
if (value) {
- display_make_number(buttons->priv->equation, text, 1024, value);
+ MpSerializer *serializer = math_equation_get_serializer(buttons->priv->equation);
+ mp_serializer_to_standard_string(serializer, value, text, 1024);
mstr = g_strdup_printf("<span weight=\"bold\">%s</span> = %s", name, text);
}
else
diff --git a/src/math-enums.c.template b/src/math-enums.c.template
new file mode 100644
index 0000000..3b83c71
--- /dev/null
+++ b/src/math-enums.c.template
@@ -0,0 +1,36 @@
+/*** BEGIN file-header ***/
+#include "mp-serializer.h"
+#include "math-enums.h"
+
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+/* enumerations from "@filename@" */
+/*** END file-production ***/
+
+/*** BEGIN value-header ***/
+GType
+math_ enum_name@_get_type (void)
+{
+ static GType etype = 0;
+ if (G_UNLIKELY(etype == 0)) {
+ static const G Type@Value values[] = {
+/*** END value-header ***/
+
+/*** BEGIN value-production ***/
+ { @VALUENAME@, "@VALUENAME@", "@valuenick@" },
+/*** END value-production ***/
+
+/*** BEGIN value-tail ***/
+ { 0, NULL, NULL }
+ };
+ etype = g_ type@_register_static (g_intern_static_string ("@EnumName@"), values);
+ }
+ return etype;
+}
+
+/*** END value-tail ***/
+
+/*** BEGIN file-tail ***/
+
+/*** END file-tail ***/
diff --git a/src/math-enums.h.template b/src/math-enums.h.template
new file mode 100644
index 0000000..f192bf8
--- /dev/null
+++ b/src/math-enums.h.template
@@ -0,0 +1,25 @@
+/*** BEGIN file-header ***/
+
+#ifndef __MATH_ENUMS_H__
+#define __MATH_ENUMS_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+
+/* enumerations from "@filename@" */
+/*** END file-production ***/
+
+/*** BEGIN value-header ***/
+GType math_ enum_name@_get_type (void) G_GNUC_CONST;
+#define @ENUMPREFIX _TYPE_@ENUMSHORT@ (math_ enum_name@_get_type ())
+/*** END value-header ***/
+
+/*** BEGIN file-tail ***/
+G_END_DECLS
+
+#endif /* __MATH_ENUMS_H__ */
+/*** END file-tail ***/
diff --git a/src/math-equation.c b/src/math-equation.c
index 010f25d..fc04ddb 100644
--- a/src/math-equation.c
+++ b/src/math-equation.c
@@ -24,14 +24,14 @@
#include <math.h>
#include <errno.h>
#include <glib.h>
-#include <langinfo.h>
-#include <locale.h>
#include "math-equation.h"
#include "mp.h"
#include "mp-equation.h"
+#include "mp-serializer.h"
#include "currency.h"
+#include "math-enums.h"
enum {
@@ -48,7 +48,8 @@ enum {
PROP_WORD_SIZE,
PROP_ANGLE_UNITS,
PROP_SOURCE_CURRENCY,
- PROP_TARGET_CURRENCY
+ PROP_TARGET_CURRENCY,
+ PROP_SERIALIZER
};
static GType number_mode_type, number_format_type, angle_unit_type;
@@ -71,22 +72,14 @@ struct MathEquationPrivate
{
GtkTextTag *ans_tag;
- gint show_tsep; /* Set if the thousands separator should be shown. */
- gint show_zeroes; /* Set if trailing zeroes should be shown. */
- DisplayFormat format; /* Number display mode. */
- gint accuracy; /* Number of digits to show */
gint word_size; /* Word size in bits */
MPAngleUnit angle_units; /* Units for trigonometric functions */
char *source_currency;
char *target_currency;
- gint base; /* Numeric base */
NumberMode number_mode; /* ??? */
gboolean can_super_minus; /* TRUE if entering minus can generate a superscript minus */
const char *digits[16]; /* Localized digit values */
- const char *radix; /* Locale specific radix string. */
- const char *tsep; /* Locale specific thousands separator. */
- gint tsep_count; /* Number of digits between separator. */
GtkTextMark *ans_start, *ans_end;
@@ -100,6 +93,7 @@ struct MathEquationPrivate
gboolean in_delete;
MathVariables *variables;
+ MpSerializer *serializer;
};
G_DEFINE_TYPE (MathEquation, math_equation, GTK_TYPE_TEXT_BUFFER);
@@ -149,7 +143,7 @@ reformat_ans(MathEquation *equation)
gtk_text_buffer_get_iter_at_mark(GTK_TEXT_BUFFER(equation), &ans_start, equation->priv->ans_start);
gtk_text_buffer_get_iter_at_mark(GTK_TEXT_BUFFER(equation), &ans_end, equation->priv->ans_end);
orig_ans_text = gtk_text_buffer_get_text(GTK_TEXT_BUFFER(equation), &ans_start, &ans_end, FALSE);
- display_make_number(equation, ans_text, MAX_DIGITS, &equation->priv->state.ans);
+ mp_serializer_to_standard_string(equation->priv->serializer, &equation->priv->state.ans, ans_text, MAX_DIGITS);
if (strcmp(orig_ans_text, ans_text) != 0) {
gint start;
@@ -173,7 +167,7 @@ reformat_ans(MathEquation *equation)
g_free(orig_ans_text);
}
-
+#if 0
/* NOTE: Not efficent but easy to write */
// FIXME: This is just a lexer - use the same lexer as the solver
static void
@@ -320,7 +314,7 @@ reformat_separators(MathEquation *equation)
g_free(text);
#endif
}
-
+#endif
static void
reformat_display(MathEquation *equation, gint old_base)
@@ -329,10 +323,10 @@ reformat_display(MathEquation *equation, gint old_base)
reformat_ans(equation);
/* Add/remove base suffixes if have changed base */
- reformat_base(equation, old_base);
+ //reformat_base(equation, old_base);
/* Add/remove thousands separators */
- reformat_separators(equation);
+ //reformat_separators(equation);
}
@@ -542,26 +536,14 @@ math_equation_get_digit_text(MathEquation *equation, guint digit)
}
-const gchar *
-math_equation_get_numeric_point_text(MathEquation *equation)
-{
- return equation->priv->radix;
-}
-
-
-const gchar *math_equation_get_thousands_separator_text(MathEquation *equation)
-{
- return equation->priv->tsep;
-}
-
-
void
math_equation_set_accuracy(MathEquation *equation, gint accuracy)
{
- if (equation->priv->accuracy == accuracy)
+ gint old_accuracy = mp_serializer_get_accuracy(equation->priv->serializer);
+ if (old_accuracy == accuracy)
return;
- equation->priv->accuracy = accuracy;
- reformat_display(equation, equation->priv->base);
+ mp_serializer_set_accuracy(equation->priv->serializer, accuracy);
+ reformat_display(equation, mp_serializer_get_base(equation->priv->serializer));
g_object_notify(G_OBJECT(equation), "accuracy");
}
@@ -569,17 +551,18 @@ math_equation_set_accuracy(MathEquation *equation, gint accuracy)
gint
math_equation_get_accuracy(MathEquation *equation)
{
- return equation->priv->accuracy;
+ return mp_serializer_get_accuracy(equation->priv->serializer);
}
void
math_equation_set_show_thousands_separators(MathEquation *equation, gboolean visible)
{
- if ((equation->priv->show_tsep && visible) || (!equation->priv->show_tsep && !visible))
+ gboolean old_visible = mp_serializer_get_show_thousands_separators(equation->priv->serializer);
+ if (old_visible == visible)
return;
- equation->priv->show_tsep = visible;
- reformat_display(equation, equation->priv->base);
+ mp_serializer_set_show_thousands_separators(equation->priv->serializer, visible);
+ reformat_display(equation, mp_serializer_get_base(equation->priv->serializer));
g_object_notify(G_OBJECT(equation), "show-thousands-separators");
}
@@ -587,17 +570,18 @@ math_equation_set_show_thousands_separators(MathEquation *equation, gboolean vis
gboolean
math_equation_get_show_thousands_separators(MathEquation *equation)
{
- return equation->priv->show_tsep;
+ return mp_serializer_get_show_thousands_separators(equation->priv->serializer);
}
void
math_equation_set_show_trailing_zeroes(MathEquation *equation, gboolean visible)
{
- if ((equation->priv->show_zeroes && visible) || (!equation->priv->show_zeroes && !visible))
+ gboolean old_visible = mp_serializer_get_show_trailing_zeroes(equation->priv->serializer);
+ if (old_visible == visible)
return;
- equation->priv->show_zeroes = visible;
- reformat_display(equation, equation->priv->base);
+ mp_serializer_set_show_trailing_zeroes(equation->priv->serializer, visible);
+ reformat_display(equation, mp_serializer_get_base(equation->priv->serializer));
g_object_notify(G_OBJECT(equation), "show-trailing-zeroes");
}
@@ -605,18 +589,19 @@ math_equation_set_show_trailing_zeroes(MathEquation *equation, gboolean visible)
gboolean
math_equation_get_show_trailing_zeroes(MathEquation *equation)
{
- return equation->priv->show_zeroes;
+ return mp_serializer_get_show_trailing_zeroes(equation->priv->serializer);
}
void
math_equation_set_number_format(MathEquation *equation, DisplayFormat format)
{
- if (equation->priv->format == format)
+ DisplayFormat old_format = mp_serializer_get_number_format(equation->priv->serializer);
+ if (old_format == format)
return;
- equation->priv->format = format;
- reformat_display(equation, equation->priv->base);
+ mp_serializer_set_number_format(equation->priv->serializer, format);
+ reformat_display(equation, mp_serializer_get_base(equation->priv->serializer));
g_object_notify(G_OBJECT(equation), "number-format");
}
@@ -624,20 +609,19 @@ math_equation_set_number_format(MathEquation *equation, DisplayFormat format)
DisplayFormat
math_equation_get_number_format(MathEquation *equation)
{
- return equation->priv->format;
+ return mp_serializer_get_number_format(equation->priv->serializer);
}
void
math_equation_set_base(MathEquation *equation, gint base)
{
- gint old_base;
+ gint old_base = mp_serializer_get_base(equation->priv->serializer);
- if (equation->priv->base == base)
+ if (old_base == base)
return;
- old_base = equation->priv->base;
- equation->priv->base = base;
+ mp_serializer_set_base(equation->priv->serializer, base);
reformat_display(equation, old_base);
g_object_notify(G_OBJECT(equation), "base");
}
@@ -646,7 +630,7 @@ math_equation_set_base(MathEquation *equation, gint base)
gint
math_equation_get_base(MathEquation *equation)
{
- return equation->priv->base;
+ return mp_serializer_get_base(equation->priv->serializer);
}
@@ -803,12 +787,17 @@ math_equation_get_number(MathEquation *equation, MPNumber *z)
gboolean result;
text = math_equation_get_display(equation);
- result = !mp_set_from_string(text, equation->priv->base, z);
+ result = !mp_serializer_from_string(equation->priv->serializer, text, z);
g_free (text);
return result;
}
+MpSerializer*
+math_equation_get_serializer(MathEquation *equation)
+{
+ return equation->priv->serializer;
+}
void
math_equation_set_number_mode(MathEquation *equation, NumberMode mode)
@@ -872,7 +861,7 @@ math_equation_set_number(MathEquation *equation, const MPNumber *x)
GtkTextIter start, end;
/* Show the number in the user chosen format */
- display_make_number(equation, text, MAX_DIGITS, x);
+ mp_serializer_to_standard_string(equation->priv->serializer, x, text, MAX_DIGITS);
gtk_text_buffer_set_text(GTK_TEXT_BUFFER(equation), text, -1);
mp_set_from_mp(x, &equation->priv->state.ans);
@@ -936,7 +925,7 @@ math_equation_insert_digit(MathEquation *equation, guint digit)
void
math_equation_insert_numeric_point(MathEquation *equation)
{
- math_equation_insert(equation, math_equation_get_numeric_point_text(equation));
+ math_equation_insert(equation, mp_serializer_get_numeric_point_text(equation->priv->serializer));
}
@@ -944,7 +933,7 @@ void
math_equation_insert_number(MathEquation *equation, const MPNumber *x)
{
char text[MAX_DIGITS];
- display_make_number(equation, text, MAX_DIGITS, x);
+ mp_serializer_to_standard_string(equation->priv->serializer, x, text, MAX_DIGITS);
math_equation_insert(equation, text);
}
@@ -1044,7 +1033,7 @@ parse(MathEquation *equation, const char *text, MPNumber *z, char **error_token)
MPEquationOptions options;
memset(&options, 0, sizeof(options));
- options.base = equation->priv->base;
+ options.base = mp_serializer_get_base(equation->priv->serializer);
options.wordlen = equation->priv->word_size;
options.angle_units = equation->priv->angle_units;
options.variable_is_defined = variable_is_defined;
@@ -1163,7 +1152,7 @@ math_equation_factorize(MathEquation *equation)
MPNumber *n;
n = factor->data;
- display_make_number(equation, temp, MAX_DIGITS, n);
+ mp_serializer_to_standard_string(equation->priv->serializer, n, temp, MAX_DIGITS);
g_string_append(text, temp);
if (factor->next)
g_string_append(text, "Ã?");
@@ -1269,25 +1258,6 @@ math_equation_toggle_bit(MathEquation *equation, guint bit)
}
-/* Convert MP number to character string. */
-//FIXME: What to do with this?
-void
-display_make_number(MathEquation *equation, char *target, int target_len, const MPNumber *x)
-{
- switch(equation->priv->format) {
- case FIX:
- mp_cast_to_string(x, equation->priv->base, equation->priv->base, equation->priv->accuracy, !equation->priv->show_zeroes, true, target, target_len);
- break;
- case SCI:
- mp_cast_to_exponential_string(x, equation->priv->base, equation->priv->base, equation->priv->accuracy, !equation->priv->show_zeroes, false, true, target, target_len);
- break;
- case ENG:
- mp_cast_to_exponential_string(x, equation->priv->base, equation->priv->base, equation->priv->accuracy, !equation->priv->show_zeroes, true, true, target, target_len);
- break;
- }
-}
-
-
static void
math_equation_set_property(GObject *object,
guint prop_id,
@@ -1371,16 +1341,16 @@ math_equation_get_property(GObject *object,
g_value_set_enum(value, self->priv->number_mode);
break;
case PROP_ACCURACY:
- g_value_set_int(value, self->priv->accuracy);
+ g_value_set_int(value, mp_serializer_get_accuracy(self->priv->serializer));
break;
case PROP_SHOW_THOUSANDS_SEPARATORS:
- g_value_set_boolean(value, self->priv->show_tsep);
+ g_value_set_boolean(value, mp_serializer_get_show_thousands_separators(self->priv->serializer));
break;
case PROP_SHOW_TRAILING_ZEROES:
- g_value_set_boolean(value, self->priv->show_zeroes);
+ g_value_set_boolean(value, mp_serializer_get_show_trailing_zeroes(self->priv->serializer));
break;
case PROP_NUMBER_FORMAT:
- g_value_set_enum(value, self->priv->format);
+ g_value_set_enum(value, mp_serializer_get_number_format(self->priv->serializer));
break;
case PROP_BASE:
g_value_set_int(value, math_equation_get_base(self));
@@ -1397,6 +1367,9 @@ math_equation_get_property(GObject *object,
case PROP_TARGET_CURRENCY:
g_value_set_string(value, self->priv->target_currency);
break;
+ case PROP_SERIALIZER:
+ g_value_set_object(value, self->priv->serializer);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -1414,13 +1387,6 @@ math_equation_class_init (MathEquationClass *klass)
{SUBSCRIPT, "subscript", "subscript"},
{0, NULL, NULL}
};
- static GEnumValue number_format_values[] =
- {
- {FIX, "fixed-point", "fixed-point"},
- {SCI, "scientific", "scientific"},
- {ENG, "engineering", "engineering"},
- {0, NULL, NULL}
- };
static GEnumValue angle_unit_values[] =
{
{MP_RADIANS, "radians", "radians"},
@@ -1436,7 +1402,7 @@ math_equation_class_init (MathEquationClass *klass)
g_type_class_add_private (klass, sizeof (MathEquationPrivate));
number_mode_type = g_enum_register_static("NumberMode", number_mode_values);
- number_format_type = g_enum_register_static("DisplayFormat", number_format_values);
+ number_format_type = math_display_format_get_type();
angle_unit_type = g_enum_register_static("AngleUnit", angle_unit_values);
g_object_class_install_property(object_class,
@@ -1533,6 +1499,13 @@ math_equation_class_init (MathEquationClass *klass)
"target Currency",
"",
G_PARAM_READWRITE));
+ g_object_class_install_property(object_class,
+ PROP_SERIALIZER,
+ g_param_spec_object("serializer",
+ "serializer",
+ "Serializer",
+ MP_TYPE_SERIALIZER,
+ G_PARAM_READABLE));
}
@@ -1648,7 +1621,6 @@ math_equation_init(MathEquation *equation)
/* Digits localized for the given language */
const char *digit_values = _("0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F");
const char *default_digits[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"};
- gchar *radix, *tsep;
gchar **digits;
gboolean use_default_digits = FALSE;
int i;
@@ -1675,28 +1647,15 @@ math_equation_init(MathEquation *equation)
}
g_strfreev(digits);
- setlocale(LC_NUMERIC, "");
-
- radix = nl_langinfo(RADIXCHAR);
- equation->priv->radix = *radix ? g_locale_to_utf8(radix, -1, NULL, NULL, NULL) : g_strdup(".");
- tsep = nl_langinfo(THOUSEP);
- equation->priv->tsep = *tsep ? g_locale_to_utf8(tsep, -1, NULL, NULL, NULL) : g_strdup(",");
-
- equation->priv->tsep_count = 3;
-
equation->priv->variables = math_variables_new();
equation->priv->state.status = g_strdup("");
- equation->priv->show_zeroes = FALSE;
- equation->priv->show_tsep = FALSE;
- equation->priv->format = FIX;
- equation->priv->accuracy = 9;
equation->priv->word_size = 32;
equation->priv->angle_units = MP_DEGREES;
// FIXME: Pick based on locale
equation->priv->source_currency = g_strdup(currency_names[0].short_name);
equation->priv->target_currency = g_strdup(currency_names[0].short_name);
- equation->priv->base = 10;
+ equation->priv->serializer = mp_serializer_new();
mp_set_from_integer(0, &equation->priv->state.ans);
}
diff --git a/src/math-equation.h b/src/math-equation.h
index e93137d..93f495c 100644
--- a/src/math-equation.h
+++ b/src/math-equation.h
@@ -24,6 +24,7 @@
#include <gtk/gtk.h>
#include "mp.h"
#include "math-variables.h"
+#include "mp-serializer.h"
G_BEGIN_DECLS
@@ -42,13 +43,6 @@ typedef struct
GtkTextBufferClass parent_class;
} MathEquationClass;
-/* Number display mode. */
-typedef enum {
- FIX,
- SCI,
- ENG
-} DisplayFormat;
-
typedef enum {
NORMAL,
SUPERSCRIPT,
@@ -104,6 +98,7 @@ void math_equation_set_target_currency(MathEquation *equation, const gchar *curr
const gchar *math_equation_get_target_currency(MathEquation *equation);
const MPNumber *math_equation_get_answer(MathEquation *equation);
+MpSerializer *math_equation_get_serializer(MathEquation *equation);
void math_equation_copy(MathEquation *equation);
void math_equation_paste(MathEquation *equation);
@@ -127,7 +122,4 @@ void math_equation_clear(MathEquation *equation);
void math_equation_shift(MathEquation *equation, gint count);
void math_equation_toggle_bit(MathEquation *equation, guint bit);
-//FIXME: Obsolete
-void display_make_number(MathEquation *equation, char *target, int target_len, const MPNumber *x);
-
#endif /* MATH_EQUATION_H */
diff --git a/src/math-variables.c b/src/math-variables.c
index 53ef1af..58a9815 100644
--- a/src/math-variables.c
+++ b/src/math-variables.c
@@ -20,6 +20,7 @@
#include <string.h>
#include "math-variables.h"
+#include "mp-serializer.h"
struct MathVariablesPrivate
@@ -97,7 +98,7 @@ registers_save(MathVariables *variables)
MPNumber *value = val;
char number[1024];
- mp_cast_to_string(value, 10, 10, 50, TRUE, FALSE, number, 1024);
+ mp_serializer_to_specific_string(value, 10, 50, true, false, number, 1024);
fprintf(f, "%s=%s\n", name, number);
}
fclose(f);
diff --git a/src/mp-binary.c b/src/mp-binary.c
index c2a6d16..6c8811c 100644
--- a/src/mp-binary.c
+++ b/src/mp-binary.c
@@ -21,6 +21,7 @@
#include "mp.h"
#include "mp-private.h"
+#include "mp-serializer.h"
// FIXME: Make dynamic
#define MAX_DIGITS 1000
@@ -45,8 +46,8 @@ mp_bitwise(const MPNumber *x, const MPNumber *y, int (*bitwise_operator)(int, in
char text1[MAX_DIGITS], text2[MAX_DIGITS], text_out[MAX_DIGITS], text_out2[MAX_DIGITS];
int offset1, offset2, offset_out;
- mp_cast_to_string(x, 16, 16, 0, 0, FALSE, text1, MAX_DIGITS);
- mp_cast_to_string(y, 16, 16, 0, 0, FALSE, text2, MAX_DIGITS);
+ mp_serializer_to_specific_string(x, 16, 0, false, false, text1, MAX_DIGITS);
+ mp_serializer_to_specific_string(y, 16, 0, false, false, text2, MAX_DIGITS);
offset1 = strlen(text1) - 1;
offset2 = strlen(text2) - 1;
offset_out = wordlen / 4 - 1;
@@ -156,7 +157,7 @@ mp_mask(const MPNumber *x, int wordlen, MPNumber *z)
size_t len, offset;
/* Convert to a hexadecimal string and use last characters */
- mp_cast_to_string(x, 16, 16, 0, 0, FALSE, text, MAX_DIGITS);
+ mp_serializer_to_specific_string(x, 16, 0, false, false, text, MAX_DIGITS);
len = strlen(text);
offset = wordlen / 4;
offset = len > offset ? len - offset: 0;
diff --git a/src/mp-convert.c b/src/mp-convert.c
index bbdb8fc..8ef633e 100644
--- a/src/mp-convert.c
+++ b/src/mp-convert.c
@@ -507,233 +507,6 @@ mp_cast_to_double(const MPNumber *x)
}
}
-
-static const char*
-mp_radix_char()
-{
- static const char* radix = NULL;
- if (radix == NULL) {
- radix = nl_langinfo(RADIXCHAR);
- radix = *radix ? g_locale_to_utf8(radix, -1, NULL, NULL, NULL) : g_strdup(".");
- }
- return radix;
-}
-
-
-static void
-mp_cast_to_string_real(const MPNumber *x, int default_base, int base, int accuracy, bool trim_zeroes, bool force_sign, bool localize_radix, GString *string)
-{
- static char digits[] = "0123456789ABCDEF";
- MPNumber number, integer_component, fractional_component, temp;
- int i, last_non_zero;
-
- if (mp_is_negative(x))
- mp_abs(x, &number);
- else
- mp_set_from_mp(x, &number);
-
- /* Add rounding factor */
- mp_set_from_integer(base, &temp);
- mp_xpowy_integer(&temp, -(accuracy+1), &temp);
- mp_multiply_integer(&temp, base, &temp);
- mp_divide_integer(&temp, 2, &temp);
- mp_add(&number, &temp, &number);
-
- /* Split into integer and fractional component */
- mp_floor(&number, &integer_component);
- mp_fractional_component(&number, &fractional_component);
-
- /* Write out the integer component least significant digit to most */
- mp_set_from_mp(&integer_component, &temp);
- do {
- MPNumber t, t2, t3;
- int64_t d;
-
- mp_divide_integer(&temp, base, &t);
- mp_floor(&t, &t);
- mp_multiply_integer(&t, base, &t2);
-
- mp_subtract(&temp, &t2, &t3);
-
- d = mp_cast_to_int(&t3);
- g_string_prepend_c(string, d < 16 ? digits[d] : '?');
-
- mp_set_from_mp(&t, &temp);
- } while (!mp_is_zero(&temp));
-
- last_non_zero = string->len;
-
- /* Allow user to change locale without breaking saved numbers */
- if (localize_radix)
- g_string_append(string, mp_radix_char());
- else
- g_string_append_c(string, '.');
-
- /* Write out the fractional component */
- mp_set_from_mp(&fractional_component, &temp);
- for (i = accuracy; i > 0 && !mp_is_zero(&temp); i--) {
- int d;
- MPNumber digit;
-
- mp_multiply_integer(&temp, base, &temp);
- mp_floor(&temp, &digit);
- d = mp_cast_to_int(&digit);
-
- g_string_append_c(string, digits[d]);
-
- if(d != 0)
- last_non_zero = string->len;
- mp_subtract(&temp, &digit, &temp);
- }
-
- /* Strip trailing zeroes */
- if (trim_zeroes || accuracy == 0)
- g_string_truncate(string, last_non_zero);
-
- /* Add sign on non-zero values */
- if (strcmp(string->str, "0") != 0 || force_sign) {
- if (mp_is_negative(x))
- g_string_prepend(string, "â??");
- else if (force_sign)
- g_string_prepend(string, "+");
- }
-
- /* Append base suffix if not in default base */
- if (base != default_base) {
- const char *digits[] = {"â??", "â??", "â??", "â??", "â??", "â??", "â??", "â??", "â??", "â??"};
- int multiplier = 1;
- int b = base;
-
- while (base / multiplier != 0)
- multiplier *= 10;
- while (multiplier != 1) {
- int d;
- multiplier /= 10;
- d = b / multiplier;
- g_string_append(string, digits[d]);
- b -= d * multiplier;
- }
- }
-}
-
-
-void
-mp_cast_to_string(const MPNumber *x, int default_base, int base, int accuracy, bool trim_zeroes, bool localize_radix, char *buffer, int buffer_length)
-{
- GString *string;
- MPNumber x_real;
-
- string = g_string_sized_new(buffer_length);
-
- mp_real_component(x, &x_real);
- mp_cast_to_string_real(&x_real, default_base, base, accuracy, trim_zeroes, FALSE, localize_radix, string);
- if (mp_is_complex(x)) {
- GString *s;
- gboolean force_sign = TRUE;
- MPNumber x_im;
-
- mp_imaginary_component(x, &x_im);
-
- if (strcmp(string->str, "0") == 0) {
- g_string_assign(string, "");
- force_sign = false;
- }
-
- s = g_string_sized_new(buffer_length);
- mp_cast_to_string_real(&x_im, default_base, 10, accuracy, trim_zeroes, force_sign, localize_radix, s);
- if (strcmp(s->str, "0") == 0 || strcmp(s->str, "+0") == 0 || strcmp(s->str, "â??0") == 0) {
- /* Ignore */
- }
- else if (strcmp(s->str, "1") == 0) {
- g_string_append(string, "i");
- }
- else if (strcmp(s->str, "+1") == 0) {
- g_string_append(string, "+i");
- }
- else if (strcmp(s->str, "â??1") == 0) {
- g_string_append(string, "â??i");
- }
- else {
- if (strcmp(s->str, "+0") == 0)
- g_string_append(string, "+");
- else if (strcmp(s->str, "0") != 0)
- g_string_append(string, s->str);
-
- g_string_append(string, "i");
- }
- g_string_free(s, TRUE);
- }
-
- // FIXME: Check for truncation
- strncpy(buffer, string->str, buffer_length);
- g_string_free(string, TRUE);
-}
-
-
-void
-mp_cast_to_exponential_string(const MPNumber *x, int default_base, int base_, int max_digits, bool trim_zeroes, bool eng_format, bool localize_radix, char *buffer, int buffer_length)
-{
- char fixed[1024], *c;
- MPNumber t, z, base, base3, base10, base10inv, mantissa;
- int exponent = 0;
- GString *string;
- const char *super_digits[] = {"�", "¹", "²", "³", "�", "�", "�", "�", "�", "�"};
-
- string = g_string_sized_new(buffer_length);
-
- mp_abs(x, &z);
- if (mp_is_negative(x))
- g_string_append(string, "â??");
- mp_set_from_mp(&z, &mantissa);
-
- mp_set_from_integer(base_, &base);
- mp_xpowy_integer(&base, 3, &base3);
- mp_xpowy_integer(&base, 10, &base10);
- mp_set_from_integer(1, &t);
- mp_divide(&t, &base10, &base10inv);
-
- if (!mp_is_zero(&mantissa)) {
- while (!eng_format && mp_is_greater_equal(&mantissa, &base10)) {
- exponent += 10;
- mp_multiply(&mantissa, &base10inv, &mantissa);
- }
-
- while ((!eng_format && mp_is_greater_equal(&mantissa, &base)) ||
- (eng_format && (mp_is_greater_equal(&mantissa, &base3) || exponent % 3 != 0))) {
- exponent += 1;
- mp_divide(&mantissa, &base, &mantissa);
- }
-
- while (!eng_format && mp_is_less_than(&mantissa, &base10inv)) {
- exponent -= 10;
- mp_multiply(&mantissa, &base10, &mantissa);
- }
-
- mp_set_from_integer(1, &t);
- while (mp_is_less_than(&mantissa, &t) || (eng_format && exponent % 3 != 0)) {
- exponent -= 1;
- mp_multiply(&mantissa, &base, &mantissa);
- }
- }
-
- mp_cast_to_string(&mantissa, default_base, base_, max_digits, trim_zeroes, localize_radix, fixed, 1024);
- g_string_append(string, fixed);
- if (exponent != 0) {
- g_string_append_printf(string, "Ã?10"); // FIXME: Use the current base
- if (exponent < 0) {
- exponent = -exponent;
- g_string_append(string, "â?»");
- }
- snprintf(fixed, 1024, "%d", exponent);
- for (c = fixed; *c; c++)
- g_string_append(string, super_digits[*c - '0']);
- }
-
- strncpy(buffer, string->str, buffer_length);
- g_string_free(string, TRUE);
-}
-
-
static int
char_val(char **c, int base)
{
@@ -856,10 +629,16 @@ mp_set_from_string(const char *str, int default_base, MPNumber *z)
int numerators[] = { 1, 1, 2, 1, 3, 1, 2, 3, 4, 1, 5, 1, 3, 5, 7};
int denominators[] = { 2, 3, 3, 4, 4, 5, 5, 5, 5, 6, 6, 8, 8, 8, 8};
static const char *tsep = NULL;
+ static const char *radix = NULL;
+
+ if (radix == NULL) {
+ radix = nl_langinfo(RADIXCHAR);
+ radix = *radix ? g_locale_to_utf8(radix, -1, NULL, NULL, NULL) : g_strdup(".");
+ }
if (tsep == NULL) {
tsep = nl_langinfo(THOUSEP);
- tsep = *tsep ? g_locale_to_utf8(tsep, -1, NULL, NULL, NULL) : g_strdup(",");
+ tsep = *tsep ? g_locale_to_utf8(tsep, -1, NULL, NULL, NULL) : tsep;
}
if (strstr(str, "°"))
@@ -900,11 +679,6 @@ mp_set_from_string(const char *str, int default_base, MPNumber *z)
/* Convert integer part */
mp_set_from_integer(0, z);
while (1) {
- if (strncmp(c, tsep, strlen(tsep)) == 0) {
- c += strlen(tsep);
- continue;
- }
-
i = char_val((char **)&c, base);
if (i < 0)
break;
@@ -913,6 +687,11 @@ mp_set_from_string(const char *str, int default_base, MPNumber *z)
return true;
mp_multiply_integer(z, base, z);
mp_add_integer(z, i, z);
+
+ // Must be after the first digit, as locales with tsep = ' ' becomes
+ // buggy otherwise.
+ if (*tsep && strncmp(c, tsep, strlen(tsep)) == 0)
+ c += strlen(tsep);
}
/* Look for fraction characters, e.g. â?? */
@@ -932,7 +711,7 @@ mp_set_from_string(const char *str, int default_base, MPNumber *z)
* english '.', since at least europeans frequently use '.' despite ','
* being the correct one for their locale.
*/
- if (*c == '.' || strncmp(c, mp_radix_char(), strlen(mp_radix_char())) == 0) {
+ if (*c == '.' || strncmp(c, radix, strlen(radix)) == 0) {
has_fraction = TRUE;
c++;
}
diff --git a/src/mp-equation-lexer.l b/src/mp-equation-lexer.l
index 6318a81..5d55861 100644
--- a/src/mp-equation-lexer.l
+++ b/src/mp-equation-lexer.l
@@ -26,7 +26,6 @@
*/
#include <stdlib.h>
-#include <locale.h>
#include <string.h>
#include <sys/types.h>
diff --git a/src/mp-serializer.c b/src/mp-serializer.c
new file mode 100644
index 0000000..8d466a0
--- /dev/null
+++ b/src/mp-serializer.c
@@ -0,0 +1,508 @@
+/* Copyright (c) 2010 Robin Sonefors
+ *
+ * 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 2, 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <langinfo.h>
+#include <glib.h>
+#include <glib-object.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "mp-serializer.h"
+
+#include "math-enums.h"
+
+enum {
+ PROP_0,
+ PROP_SHOW_THOUSANDS_SEPARATORS,
+ PROP_SHOW_TRAILING_ZEROES,
+ PROP_NUMBER_FORMAT,
+ PROP_BASE,
+};
+
+static GType number_format_type;
+
+struct MpSerializerPrivate
+{
+ gint accuracy; /* Number of digits to show */
+ DisplayFormat format; /* Number display mode. */
+ gint show_tsep; /* Set if the thousands separator should be shown. */
+ gint show_zeroes; /* Set if trailing zeroes should be shown. */
+
+ gint base; /* Numeric base */
+
+ char *tsep; /* Locale specific thousands separator. */
+ char *radix; /* Locale specific radix string. */
+ gint tsep_count; /* Number of digits between separator. */
+};
+
+
+G_DEFINE_TYPE(MpSerializer, mp_serializer, G_TYPE_OBJECT);
+
+MpSerializer *
+mp_serializer_new()
+{
+ return g_object_new(mp_serializer_get_type(), NULL);
+}
+
+static void
+mp_cast_to_string_real(MpSerializer *serializer, const MPNumber *x, int base, bool force_sign, GString *string)
+{
+ static char digits[] = "0123456789ABCDEF";
+ MPNumber number, integer_component, fractional_component, temp;
+ int i, last_non_zero;
+
+ if (mp_is_negative(x))
+ mp_abs(x, &number);
+ else
+ mp_set_from_mp(x, &number);
+
+ /* Add rounding factor */
+ mp_set_from_integer(base, &temp);
+ mp_xpowy_integer(&temp, -(serializer->priv->accuracy+1), &temp);
+ mp_multiply_integer(&temp, base, &temp);
+ mp_divide_integer(&temp, 2, &temp);
+ mp_add(&number, &temp, &number);
+
+ /* Split into integer and fractional component */
+ mp_floor(&number, &integer_component);
+ mp_fractional_component(&number, &fractional_component);
+
+ /* Write out the integer component least significant digit to most */
+ mp_set_from_mp(&integer_component, &temp);
+ i = 0;
+ do {
+ MPNumber t, t2, t3;
+ int64_t d;
+
+ mp_divide_integer(&temp, base, &t);
+ mp_floor(&t, &t);
+ mp_multiply_integer(&t, base, &t2);
+
+ mp_subtract(&temp, &t2, &t3);
+
+ d = mp_cast_to_int(&t3);
+ g_string_prepend_c(string, d < 16 ? digits[d] : '?');
+
+ i++;
+ if (serializer->priv->show_tsep && i == serializer->priv->tsep_count)
+ g_string_prepend(string, serializer->priv->tsep);
+
+ mp_set_from_mp(&t, &temp);
+ } while (!mp_is_zero(&temp));
+
+ last_non_zero = string->len;
+
+ g_string_append(string, serializer->priv->radix);
+
+ /* Write out the fractional component */
+ mp_set_from_mp(&fractional_component, &temp);
+ for (i = serializer->priv->accuracy; i > 0 && !mp_is_zero(&temp); i--) {
+ int d;
+ MPNumber digit;
+
+ mp_multiply_integer(&temp, base, &temp);
+ mp_floor(&temp, &digit);
+ d = mp_cast_to_int(&digit);
+
+ g_string_append_c(string, digits[d]);
+
+ if(d != 0)
+ last_non_zero = string->len;
+ mp_subtract(&temp, &digit, &temp);
+ }
+
+ /* Strip trailing zeroes */
+ if (!serializer->priv->show_zeroes || serializer->priv->accuracy == 0)
+ g_string_truncate(string, last_non_zero);
+
+ /* Add sign on non-zero values */
+ if (strcmp(string->str, "0") != 0 || force_sign) {
+ if (mp_is_negative(x))
+ g_string_prepend(string, "â??");
+ else if (force_sign)
+ g_string_prepend(string, "+");
+ }
+
+ /* Append base suffix if not in default base */
+ if (base != serializer->priv->base) {
+ const char *digits[] = {"â??", "â??", "â??", "â??", "â??", "â??", "â??", "â??", "â??", "â??"};
+ int multiplier = 1;
+ int b = base;
+
+ while (base / multiplier != 0)
+ multiplier *= 10;
+ while (multiplier != 1) {
+ int d;
+ multiplier /= 10;
+ d = b / multiplier;
+ g_string_append(string, digits[d]);
+ b -= d * multiplier;
+ }
+ }
+}
+
+
+static void
+mp_cast_to_string(MpSerializer *serializer, const MPNumber *x, char *buffer, int buffer_length)
+{
+ GString *string;
+ MPNumber x_real;
+
+ string = g_string_sized_new(buffer_length);
+
+ mp_real_component(x, &x_real);
+ mp_cast_to_string_real(serializer, &x_real, serializer->priv->base, false, string);
+ if (mp_is_complex(x)) {
+ GString *s;
+ gboolean force_sign = true;
+ MPNumber x_im;
+
+ mp_imaginary_component(x, &x_im);
+
+ if (strcmp(string->str, "0") == 0) {
+ g_string_assign(string, "");
+ force_sign = false;
+ }
+
+ s = g_string_sized_new(buffer_length);
+ mp_cast_to_string_real(serializer, &x_im, 10, force_sign, s);
+ if (strcmp(s->str, "0") == 0 || strcmp(s->str, "+0") == 0 || strcmp(s->str, "â??0") == 0) {
+ /* Ignore */
+ }
+ else if (strcmp(s->str, "1") == 0) {
+ g_string_append(string, "i");
+ }
+ else if (strcmp(s->str, "+1") == 0) {
+ g_string_append(string, "+i");
+ }
+ else if (strcmp(s->str, "â??1") == 0) {
+ g_string_append(string, "â??i");
+ }
+ else {
+ if (strcmp(s->str, "+0") == 0)
+ g_string_append(string, "+");
+ else if (strcmp(s->str, "0") != 0)
+ g_string_append(string, s->str);
+
+ g_string_append(string, "i");
+ }
+ g_string_free(s, TRUE);
+ }
+
+ // FIXME: Check for truncation
+ strncpy(buffer, string->str, buffer_length);
+ g_string_free(string, TRUE);
+}
+
+
+static void
+mp_cast_to_exponential_string(MpSerializer *serializer, const MPNumber *x, bool eng_format, char *buffer, int buffer_length)
+{
+ char fixed[1024], *c;
+ MPNumber t, z, base, base3, base10, base10inv, mantissa;
+ int exponent = 0;
+ GString *string;
+ const char *super_digits[] = {"�", "¹", "²", "³", "�", "�", "�", "�", "�", "�"};
+
+ string = g_string_sized_new(buffer_length);
+
+ mp_abs(x, &z);
+ if (mp_is_negative(x))
+ g_string_append(string, "â??");
+ mp_set_from_mp(&z, &mantissa);
+
+ mp_set_from_integer(serializer->priv->base, &base);
+ mp_xpowy_integer(&base, 3, &base3);
+ mp_xpowy_integer(&base, 10, &base10);
+ mp_set_from_integer(1, &t);
+ mp_divide(&t, &base10, &base10inv);
+
+ if (!mp_is_zero(&mantissa)) {
+ while (!eng_format && mp_is_greater_equal(&mantissa, &base10)) {
+ exponent += 10;
+ mp_multiply(&mantissa, &base10inv, &mantissa);
+ }
+
+ while ((!eng_format && mp_is_greater_equal(&mantissa, &base)) ||
+ (eng_format && (mp_is_greater_equal(&mantissa, &base3) || exponent % 3 != 0))) {
+ exponent += 1;
+ mp_divide(&mantissa, &base, &mantissa);
+ }
+
+ while (!eng_format && mp_is_less_than(&mantissa, &base10inv)) {
+ exponent -= 10;
+ mp_multiply(&mantissa, &base10, &mantissa);
+ }
+
+ mp_set_from_integer(1, &t);
+ while (mp_is_less_than(&mantissa, &t) || (eng_format && exponent % 3 != 0)) {
+ exponent -= 1;
+ mp_multiply(&mantissa, &base, &mantissa);
+ }
+ }
+
+ mp_cast_to_string(serializer, &mantissa, fixed, 1024);
+ g_string_append(string, fixed);
+ if (exponent != 0) {
+ g_string_append_printf(string, "Ã?10"); // FIXME: Use the current base
+ if (exponent < 0) {
+ exponent = -exponent;
+ g_string_append(string, "â?»");
+ }
+ snprintf(fixed, 1024, "%d", exponent);
+ for (c = fixed; *c; c++)
+ g_string_append(string, super_digits[*c - '0']);
+ }
+
+ strncpy(buffer, string->str, buffer_length);
+ g_string_free(string, TRUE);
+}
+
+
+void
+mp_serializer_to_standard_string(MpSerializer *serializer, const MPNumber *x, char *target, int target_len)
+{
+ switch(serializer->priv->format) {
+ case FIX:
+ mp_cast_to_string(serializer, x, target, target_len);
+ break;
+ case SCI:
+ mp_cast_to_exponential_string(serializer, x, false, target, target_len);
+ break;
+ case ENG:
+ mp_cast_to_exponential_string(serializer, x, true, target, target_len);
+ break;
+ }
+}
+
+void
+mp_serializer_to_specific_string(const MPNumber *x, int base, int accuracy, bool trim_zeroes, bool localize, char *target, int target_len)
+{
+ MpSerializer *serializer = mp_serializer_new ();
+ if (!localize) {
+ g_free(serializer->priv->radix);
+ serializer->priv->radix = g_strdup(".");
+ serializer->priv->show_tsep = false;
+ }
+ serializer->priv->base = base;
+ serializer->priv->accuracy = accuracy;
+ serializer->priv->show_zeroes = !trim_zeroes;
+ mp_serializer_to_standard_string(serializer, x, target, target_len);
+ g_object_unref(serializer);
+}
+
+bool
+mp_serializer_from_string(MpSerializer *serializer, const char *str, MPNumber *z)
+{
+ return mp_set_from_string(str, serializer->priv->base, z);
+}
+
+void
+mp_serializer_set_base(MpSerializer *serializer, gint base)
+{
+ serializer->priv->base = base;
+}
+
+int
+mp_serializer_get_base(MpSerializer *serializer)
+{
+ return serializer->priv->base;
+}
+
+const gchar *
+mp_serializer_get_numeric_point_text(MpSerializer *serializer)
+{
+ return serializer->priv->radix;
+}
+
+
+const gchar *
+mp_serializer_get_thousands_separator_text(MpSerializer *serializer)
+{
+ return serializer->priv->tsep;
+}
+
+void
+mp_serializer_set_show_thousands_separators(MpSerializer *serializer, gboolean visible)
+{
+ serializer->priv->show_tsep = visible;
+}
+
+
+gboolean
+mp_serializer_get_show_thousands_separators(MpSerializer *serializer)
+{
+ return serializer->priv->show_tsep;
+}
+
+
+void
+mp_serializer_set_show_trailing_zeroes(MpSerializer *serializer, gboolean visible)
+{
+ serializer->priv->show_zeroes = visible;
+}
+
+
+gboolean
+mp_serializer_get_show_trailing_zeroes(MpSerializer *serializer)
+{
+ return serializer->priv->show_zeroes;
+}
+
+
+int
+mp_serializer_get_accuracy(MpSerializer *serializer)
+{
+ return serializer->priv->accuracy;
+}
+
+void
+mp_serializer_set_accuracy(MpSerializer *serializer, int accuracy)
+{
+ serializer->priv->accuracy = accuracy;
+}
+
+DisplayFormat
+mp_serializer_get_number_format(MpSerializer *serializer)
+{
+ return serializer->priv->format;
+}
+
+void
+mp_serializer_set_number_format(MpSerializer *serializer, DisplayFormat format)
+{
+ serializer->priv->format = format;
+}
+
+static void
+mp_serializer_set_property(GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ MpSerializer *self = MP_SERIALIZER(object);
+
+ switch (prop_id) {
+ case PROP_SHOW_THOUSANDS_SEPARATORS:
+ mp_serializer_set_show_thousands_separators(self, g_value_get_boolean(value));
+ break;
+ case PROP_SHOW_TRAILING_ZEROES:
+ mp_serializer_set_show_trailing_zeroes(self, g_value_get_boolean(value));
+ break;
+ case PROP_BASE:
+ mp_serializer_set_base(self, g_value_get_int(value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+mp_serializer_get_property(GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ MpSerializer *self = MP_SERIALIZER(object);
+
+ switch (prop_id) {
+ case PROP_SHOW_THOUSANDS_SEPARATORS:
+ g_value_set_boolean(value, mp_serializer_get_show_thousands_separators(self));
+ break;
+ case PROP_SHOW_TRAILING_ZEROES:
+ g_value_set_boolean(value, mp_serializer_get_show_trailing_zeroes(self));
+ break;
+ case PROP_BASE:
+ g_value_set_int(value, mp_serializer_get_base(self));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+mp_serializer_finalize (GObject *gobject)
+{
+ MpSerializer *serializer = MP_SERIALIZER(gobject);
+ g_free(serializer->priv->radix);
+ g_free(serializer->priv->tsep);
+}
+
+static void
+mp_serializer_class_init (MpSerializerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ object_class->get_property = mp_serializer_get_property;
+ object_class->set_property = mp_serializer_set_property;
+ object_class->finalize = mp_serializer_finalize;
+
+ g_type_class_add_private (klass, sizeof(MpSerializerPrivate));
+
+ number_format_type = math_display_format_get_type();
+
+ g_object_class_install_property(object_class,
+ PROP_SHOW_THOUSANDS_SEPARATORS,
+ g_param_spec_boolean("show-thousands-separators",
+ "show-thousands-separators",
+ "Show thousands separators",
+ TRUE,
+ G_PARAM_READWRITE));
+ g_object_class_install_property(object_class,
+ PROP_SHOW_TRAILING_ZEROES,
+ g_param_spec_boolean("show-trailing-zeroes",
+ "show-trailing-zeroes",
+ "Show trailing zeroes",
+ FALSE,
+ G_PARAM_READWRITE));
+ g_object_class_install_property(object_class,
+ PROP_BASE,
+ g_param_spec_int("base",
+ "base",
+ "Default number base (derived from number-format)",
+ 2, 16, 10,
+ G_PARAM_READWRITE));
+ g_object_class_install_property(object_class,
+ PROP_NUMBER_FORMAT,
+ g_param_spec_enum("number-format",
+ "number-format",
+ "Display format",
+ number_format_type,
+ FIX,
+ G_PARAM_READWRITE));
+}
+
+static void
+mp_serializer_init(MpSerializer *serializer)
+{
+ gchar *radix, *tsep;
+ serializer->priv = G_TYPE_INSTANCE_GET_PRIVATE(serializer, mp_serializer_get_type(), MpSerializerPrivate);
+
+ radix = nl_langinfo(RADIXCHAR);
+ serializer->priv->radix = *radix ? g_locale_to_utf8(radix, -1, NULL, NULL, NULL) : g_strdup(".");
+ tsep = nl_langinfo(THOUSEP);
+ serializer->priv->tsep = *tsep ? g_locale_to_utf8(tsep, -1, NULL, NULL, NULL) : g_strdup("");
+
+ serializer->priv->tsep_count = 3;
+ serializer->priv->base = 10;
+ serializer->priv->accuracy = 9;
+ serializer->priv->show_zeroes = FALSE;
+ serializer->priv->show_tsep = FALSE;
+ serializer->priv->format = FIX;
+}
diff --git a/src/mp-serializer.h b/src/mp-serializer.h
new file mode 100644
index 0000000..3490183
--- /dev/null
+++ b/src/mp-serializer.h
@@ -0,0 +1,72 @@
+/* Copyright (c) 2010 Robin Sonefors
+ *
+ * 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 2, 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef MP_SERIALIZER_H
+#define MP_SERIALIZER_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "mp.h"
+
+G_BEGIN_DECLS
+
+#define MP_TYPE_SERIALIZER (mp_serializer_get_type())
+#define MP_SERIALIZER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), mp_serializer_get_type(), MpSerializer))
+
+typedef struct MpSerializerPrivate MpSerializerPrivate;
+
+typedef struct {
+ GObject parent;
+ MpSerializerPrivate *priv;
+} MpSerializer;
+
+typedef struct {
+ GObjectClass parent;
+} MpSerializerClass;
+
+/* Number display mode. */
+typedef enum {
+ FIX,
+ SCI,
+ ENG
+} DisplayFormat;
+
+GType mp_serializer_get_type(void);
+MpSerializer *mp_serializer_new(void);
+
+void mp_serializer_to_standard_string(MpSerializer *serializer, const MPNumber *z, char *target, int target_len);
+void mp_serializer_to_specific_string(const MPNumber *z, int base, int accuracy, bool trim_zeroes, bool localize, char *target, int target_len);
+bool mp_serializer_from_string(MpSerializer *serializer, const char *str, MPNumber *z);
+
+const gchar* mp_serializer_get_numeric_point_text(MpSerializer *serializer);
+const gchar* mp_serializer_get_thousands_separator_text(MpSerializer *serializer);
+void mp_serializer_set_base(MpSerializer *serializer, int base);
+int mp_serializer_get_base(MpSerializer *serializer);
+gboolean mp_serializer_get_show_trailing_zeroes(MpSerializer *serializer);
+void mp_serializer_set_show_trailing_zeroes(MpSerializer *serializer, gboolean visible);
+gboolean mp_serializer_get_show_thousands_separators(MpSerializer *serializer);
+void mp_serializer_set_show_thousands_separators(MpSerializer *serializer, gboolean visible);
+int mp_serializer_get_accuracy(MpSerializer *serializer);
+void mp_serializer_set_accuracy(MpSerializer *serializer, int accuracy);
+DisplayFormat mp_serializer_get_number_format(MpSerializer *serializer);
+void mp_serializer_set_number_format(MpSerializer *serializer, DisplayFormat format);
+
+G_END_DECLS
+
+#endif /* MP_SERIALIZER_H */
diff --git a/src/mp.h b/src/mp.h
index bca77c9..423aa0a 100644
--- a/src/mp.h
+++ b/src/mp.h
@@ -270,24 +270,6 @@ int64_t mp_cast_to_int(const MPNumber *x);
/* Returns x as a native unsigned integer */
uint64_t mp_cast_to_unsigned_int(const MPNumber *x);
-/* Converts x to a string representation.
- * The string is written into 'buffer' which is guaranteed to be at least 'buffer_length' octets in size.
- * If not enough space is available the string is truncated.
- * The numbers are written in 'base' (e.g. 10).
- * If 'trim_zeroes' is non-zero then strip off trailing zeroes.
- * Fractional components are truncated at 'max_digits' digits.
- */
-void mp_cast_to_string(const MPNumber *x, int default_base, int base, int max_digits, bool trim_zeroes, bool localize_radix, char *buffer, int buffer_length);
-
-/* Converts x to a string representation in exponential form.
- * The string is written into 'buffer' which is guaranteed to be at least 'buffer_length' octets in size.
- * If not enough space is available the string is truncated.
- * The numbers are written in 'base' (e.g. 10).
- * If 'trim_zeroes' is non-zero then strip off trailing zeroes.
- * Fractional components are truncated at 'max_digits' digits.
- */
-void mp_cast_to_exponential_string(const MPNumber *x, int default_base, int base, int max_digits, bool trim_zeroes, bool eng_format, bool localize_radix, char *buffer, int buffer_length);
-
/* Sets z = sin x */
void mp_sin(const MPNumber *x, MPAngleUnit unit, MPNumber *z);
diff --git a/src/unittest.c b/src/unittest.c
index 417813f..30de463 100644
--- a/src/unittest.c
+++ b/src/unittest.c
@@ -23,6 +23,7 @@
#include "unittest.h"
#include "mp-equation.h"
+#include "mp-serializer.h"
static MPEquationOptions options;
@@ -83,7 +84,7 @@ test(char *expression, char *expected, int expected_error)
error = mp_equation_parse(expression, &options, &result, NULL);
if(error == 0) {
- mp_cast_to_string(&result, options.base, options.base, 9, 1, TRUE, result_str, 1024);
+ mp_serializer_to_specific_string(&result, options.base, 9, true, false, result_str, 1024);
if(expected_error != 0)
fail("'%s' -> %s, expected error %s", expression, result_str, error_code_to_string(expected_error));
else if(strcmp(result_str, expected) != 0)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]