[gcalctool] Support conversions in display
- From: Robert Ancell <rancell src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gcalctool] Support conversions in display
- Date: Tue, 27 Oct 2009 02:01:01 +0000 (UTC)
commit d44a18eeba84b483e37ffc61a982f293a0a42a5b
Author: Robert Ancell <robert ancell gmail com>
Date: Tue Oct 27 13:00:54 2009 +1100
Support conversions in display
ChangeLog | 4 +
src/currency.h | 5 ++
src/display.c | 176 ++++++++++++++++++++++++++++++++++++++++++++++
src/mp-equation-lexer.l | 2 +
src/mp-equation-parser.y | 17 ++++-
src/mp-equation.c | 2 +
src/mp-equation.h | 4 +
7 files changed, 209 insertions(+), 1 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index f753fce..0d8218b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -9,6 +9,10 @@ gcalctool change history.
2009-10-27 Robert Ancell <robert ancell gmail com>
+ * Support conversions in display (e.g. "1 AUD in USD" or "6.2 inches in meters")
+
+2009-10-27 Robert Ancell <robert ancell gmail com>
+
* README:
NEWS:
configure.in:
diff --git a/src/currency.h b/src/currency.h
index c08c216..2ac8488 100644
--- a/src/currency.h
+++ b/src/currency.h
@@ -1,3 +1,6 @@
+#ifndef CURRENCY_H
+#define CURRENCY_H
+
#include <glib/gi18n.h>
#include "mp.h"
@@ -72,3 +75,5 @@ void currency_convert(const MPNumber *from_amount,
/* Frees up all allocated resources */
void currency_free_resources();
+
+#endif /* CURRENCY_H */
diff --git a/src/display.c b/src/display.c
index 6038bc6..08f9240 100644
--- a/src/display.c
+++ b/src/display.c
@@ -31,6 +31,7 @@
#include "ui.h"
#include "mp-equation.h"
#include "register.h"
+#include "currency.h"
static GCDisplayState *
get_state(GCDisplay *display)
@@ -753,6 +754,175 @@ set_variable(const char *name, const MPNumber *x, void *data)
static int
+do_convert(const char *units[][2], const MPNumber *x, const char *x_units, const char *z_units, MPNumber *z)
+{
+ int x_index, z_index;
+ MPNumber x_factor, z_factor;
+
+ for (x_index = 0; units[x_index][0] != NULL && strcmp(units[x_index][0], x_units) != 0; x_index++);
+ if (units[x_index][0] == NULL)
+ return 0;
+ for (z_index = 0; units[z_index][0] != NULL && strcmp(units[z_index][0], z_units) != 0; z_index++);
+ if (units[z_index][0] == NULL)
+ return 0;
+
+ mp_set_from_string(units[x_index][1], &x_factor);
+ mp_set_from_string(units[z_index][1], &z_factor);
+ mp_multiply(x, &x_factor, z);
+ mp_divide(z, &z_factor, z);
+
+ return 1;
+}
+
+
+static int
+convert(const MPNumber *x, const char *x_units, const char *z_units, MPNumber *z, void *data)
+{
+ const char *length_units[][2] = {
+ {"parsec", "30857000000000000"},
+ {"parsecs", "30857000000000000"},
+ {"pc", "30857000000000000"},
+ {"lightyear", "9460730472580800"},
+ {"lightyears", "9460730472580800"},
+ {"ly", "9460730472580800"},
+ {"au", "149597870691"},
+ {"nm", "1852000"},
+ {"mile", "1609.344"},
+ {"miles", "1609.344"},
+ {"m", "1609.344"},
+ {"kilometer", "1000"},
+ {"kilometers", "1000"},
+ {"km", "1000"},
+ {"kms", "1000"},
+ {"cable", "219.456"},
+ {"cables", "219.456"},
+ {"cb", "219.456"},
+ {"fathom", "1.8288"},
+ {"fathoms", "1.8288"},
+ {"ftm", "1.8288"},
+ {"meter", "1"},
+ {"meters", "1"},
+ {"m", "1"},
+ {"yard", "0.9144"},
+ {"yd", "0.9144"},
+ {"foot", "0.3048"},
+ {"feet", "0.3048"},
+ {"ft", "0.3048"},
+ {"inch", "0.0254"},
+ {"inches", "0.0254"},
+ {"centimeter", "0.01"},
+ {"centimeters", "0.01"},
+ {"cm", "0.01"},
+ {"cms", "0.01"},
+ {"millimeter", "0.001"},
+ {"millimeters", "0.001"},
+ {"mm", "0.001"},
+ {"micrometer", "0.000001"},
+ {"micrometers", "0.000001"},
+ {"um", "0.000001"},
+ {"nanometer", "0.000000001"},
+ {"nanometers", "0.000000001"},
+ {NULL, NULL}
+ };
+
+ const char *area_units[][2] = {
+ {"hectare", "10000"},
+ {"hectares", "10000"},
+ {"acre", "4046.8564224"},
+ {"acres", "4046.8564224"},
+ {"m²", "1"},
+ {"cm²", "0.001"},
+ {NULL, NULL}
+ };
+
+ const char *volume_units[][2] = {
+ {"cm³", "1000"},
+ {"gallon", "3.785412"},
+ {"gallons", "3.785412"},
+ {"gal", "3.785412"},
+ {"litre", "1"},
+ {"litres", "1"},
+ {"liter", "1"},
+ {"liters", "1"},
+ {"L", "1"},
+ {"quart", "0.9463529"},
+ {"quarts", "0.9463529"},
+ {"qt", "0.9463529"},
+ {"pint", "0.4731765"},
+ {"pints", "0.4731765"},
+ {"pt", "0.4731765"},
+ {"millilitre", "0.001"},
+ {"millilitres", "0.001"},
+ {"milliliter", "0.001"},
+ {"milliliters", "0.001"},
+ {"mL", "0.001"},
+ {"m³", "0.001"},
+ {NULL, NULL}
+ };
+
+ const char *weight_units[][2] = {
+ {"tonne", "1000"},
+ {"tonnes", "1000"},
+ {"kilograms", "1"},
+ {"kilogramme", "1"},
+ {"kilogrammes", "1"},
+ {"kg", "1"},
+ {"kgs", "1"},
+ {"pound", "0.45359237"},
+ {"pounds", "0.45359237"},
+ {"lb", "0.45359237"},
+ {"ounce", "0.002834952"},
+ {"ounces", "0.002834952"},
+ {"oz", "0.002834952"},
+ {"gram", "0.001"},
+ {"grams", "0.001"},
+ {"gramme", "0.001"},
+ {"grammes", "0.001"},
+ {"g", "0.001"},
+ {NULL, NULL}
+ };
+
+ const char *time_units[][2] = {
+ {"year", "31557600"},
+ {"years", "31557600"},
+ {"day", "86400"},
+ {"days", "86400"},
+ {"hour", "3600"},
+ {"hours", "3600"},
+ {"minute", "60"},
+ {"minutes", "60"},
+ {"second", "1"},
+ {"seconds", "1"},
+ {"s", "1"},
+ {"millisecond", "0.001"},
+ {"milliseconds", "0.001"},
+ {"ms", "0.001"},
+ {"microsecond", "0.000001"},
+ {"microseconds", "0.000001"},
+ {"us", "0.000001"},
+ {NULL, NULL}
+ };
+
+ /* See if currency */
+ currency_load_rates();
+ if (currency_get_index(x_units) >= 0 && currency_get_index(z_units) >= 0)
+ {
+ currency_convert(x, currency_get_index(x_units), currency_get_index(z_units), z);
+ return 1;
+ }
+
+ if (do_convert(length_units, x, x_units, z_units, z) ||
+ do_convert(area_units, x, x_units, z_units, z) ||
+ do_convert(volume_units, x, x_units, z_units, z) ||
+ do_convert(weight_units, x, x_units, z_units, z) ||
+ do_convert(time_units, x, x_units, z_units, z))
+ return 1;
+
+ return 0;
+}
+
+
+static int
parse(GCDisplay *display, const char *text, MPNumber *z, char **error_token)
{
MPEquationOptions options;
@@ -762,6 +932,7 @@ parse(GCDisplay *display, const char *text, MPNumber *z, char **error_token)
options.angle_units = display->angle_unit;
options.get_variable = get_variable;
options.set_variable = set_variable;
+ options.convert = convert;
options.callback_data = display;
return mp_equation_parse(text, &options, z, error_token);
@@ -1038,6 +1209,11 @@ display_do_function(GCDisplay *display, int function, gpointer arg, int cursor_s
free(error_token);
break;
+ case PARSER_ERR_UNKNOWN_CONVERSION:
+ /* Translators: Error displayed to user when an conversion with unknown units is attempted */
+ message = g_strdup_printf(_("Unknown conversion"));
+ break;
+
case PARSER_ERR_MP:
message = mp_get_error();
break;
diff --git a/src/mp-equation-lexer.l b/src/mp-equation-lexer.l
index fc39e89..c3f7318 100644
--- a/src/mp-equation-lexer.l
+++ b/src/mp-equation-lexer.l
@@ -70,6 +70,7 @@ AND "â?§"|[aA][nN][dD]
OR "â?¨"|[oO][rR]
XOR "â??"|[xX][oO][rR]
NOT "¬"|"~"|[nN][oO][tT]
+IN [iI][nN]
%%
@@ -85,6 +86,7 @@ NOT "¬"|"~"|[nN][oO][tT]
{AND} {return tAND;}
{OR} {return tOR;}
{XOR} {return tXOR;}
+{IN} {return tIN;}
{NUMBER} {if (mp_set_from_string(yytext, &yylval->int_t) != 0) REJECT; return tNUMBER;}
{SUP_NUM} {yylval->integer = super_atoi(yytext); return tSUPNUM; }
{SUB_NUM} {yylval->integer = sub_atoi(yytext); return tSUBNUM; }
diff --git a/src/mp-equation-parser.y b/src/mp-equation-parser.y
index 43b502f..d398e19 100644
--- a/src/mp-equation-parser.y
+++ b/src/mp-equation-parser.y
@@ -70,6 +70,16 @@ static void do_not(yyscan_t yyscanner, const MPNumber *x, MPNumber *z)
mp_not(x, _mp_equation_get_extra(yyscanner)->options->wordlen, z);
}
+static void do_conversion(yyscan_t yyscanner, const MPNumber *x, const char *x_units, const char *z_units, MPNumber *z)
+{
+ void *data = _mp_equation_get_extra(yyscanner)->options->callback_data;
+
+ if (_mp_equation_get_extra(yyscanner)->options->convert == NULL
+ || !_mp_equation_get_extra(yyscanner)->options->convert(x, x_units, z_units, z, data)) {
+ set_error(yyscanner, PARSER_ERR_UNKNOWN_CONVERSION);
+ }
+}
+
%}
%pure-parser
@@ -96,7 +106,8 @@ static void do_not(yyscan_t yyscanner, const MPNumber *x, MPNumber *z)
%left BOOLEAN_OPERATOR
%left PERCENTAGE
%left UNARY_MINUS
-%right '^' tINVERSE '!'
+%right '^' tINVERSE '!' '|'
+%left tIN
%type <int_t> exp variable
%start statement
@@ -107,8 +118,12 @@ statement:
exp { set_result(yyscanner, &$1); }
| exp '=' { set_result(yyscanner, &$1); }
| tVARIABLE '=' exp {set_variable(yyscanner, $1, &$3); set_result(yyscanner, &$3); }
+| tNUMBER tVARIABLE tIN tVARIABLE { MPNumber t; do_conversion(yyscanner, &$1, $2, $4, &t); set_result(yyscanner, &t); free($2); free($4); }
+| tVARIABLE tIN tVARIABLE { MPNumber x, t; mp_set_from_integer(1, &x); do_conversion(yyscanner, &x, $1, $3, &t); set_result(yyscanner, &t); free($1); free($3); }
;
+/* |x| gets confused and thinks = |x|(...||) */
+
exp:
'(' exp ')' {mp_set_from_mp(&$2, &$$);}
| '|' exp '|' {mp_abs(&$2, &$$);}
diff --git a/src/mp-equation.c b/src/mp-equation.c
index 1edfec4..03567d5 100644
--- a/src/mp-equation.c
+++ b/src/mp-equation.c
@@ -267,6 +267,8 @@ mp_error_code_to_string(MPErrorCode error_code)
return "PARSER_ERR_UNKNOWN_VARIABLE";
case PARSER_ERR_UNKNOWN_FUNCTION:
return "PARSER_ERR_UNKNOWN_FUNCTION";
+ case PARSER_ERR_UNKNOWN_CONVERSION:
+ return "PARSER_ERR_UNKNOWN_CONVERSION";
case PARSER_ERR_MP:
return "PARSER_ERR_MP";
default:
diff --git a/src/mp-equation.h b/src/mp-equation.h
index 666353d..4f1ad2e 100644
--- a/src/mp-equation.h
+++ b/src/mp-equation.h
@@ -29,6 +29,7 @@ typedef enum
PARSER_ERR_OVERFLOW,
PARSER_ERR_UNKNOWN_VARIABLE,
PARSER_ERR_UNKNOWN_FUNCTION,
+ PARSER_ERR_UNKNOWN_CONVERSION,
PARSER_ERR_MP
} MPErrorCode;
@@ -54,6 +55,9 @@ typedef struct {
/* Function to solve functions */
int (*get_function)(const char *name, const MPNumber *x, MPNumber *z, void *data);
+
+ /* Function to convert units */
+ int (*convert)(const MPNumber *x, const char *x_units, const char *z_units, MPNumber *z, void *data);
} MPEquationOptions;
MPErrorCode mp_equation_parse(const char *expression, MPEquationOptions *options, MPNumber *result, char **error_token);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]