588
606
display_init(GCDisplay *display)
592
610
memset(display, 0, sizeof(GCDisplay));
594
display->show_zeroes = FALSE;
595
display->show_tsep = FALSE;
596
display->format = DEC;
597
display->accuracy = 9;
598
display->word_size = 32;
599
display->angle_unit = MP_DEGREES;
601
for (i = 0; i < UNDO_HISTORY_LENGTH; i++) {
614
if (get_boolean_resource(R_ZEROES, &i))
615
display->show_zeroes = i;
617
display->show_zeroes = FALSE;
619
if (get_boolean_resource(R_TSEP, &i))
620
display->show_tsep = i;
622
display->show_tsep = FALSE;
624
if (get_enumerated_resource(R_DISPLAY, display_types, &i))
625
display->format = (DisplayFormat) i;
627
display->format = FIX;
629
for (i = 0; i < UNDO_HISTORY_LENGTH; i++)
602
630
display->h.e[i].expression = strdup("");
603
display->h.e[i].ans_start = -1;
604
display->h.e[i].ans_end = -1;
610
display_set_accuracy(GCDisplay *display, int accuracy)
634
void display_set_accuracy(GCDisplay *display, int accuracy)
612
display->accuracy = accuracy;
636
set_int_resource(R_ACCURACY, accuracy);
613
637
get_state(display)->cursor = -1;
614
display_refresh(display);
638
display_refresh(display);
619
display_set_show_thousands_separator(GCDisplay *display, gboolean visible)
642
void display_set_show_thousands_separator(GCDisplay *display, gboolean visible)
621
644
display->show_tsep = visible;
645
set_boolean_resource(R_TSEP, visible);
622
646
display_set_cursor(display, -1);
623
647
display_refresh(display);
628
display_set_show_trailing_zeroes(GCDisplay *display, gboolean visible)
651
void display_set_show_trailing_zeroes(GCDisplay *display, gboolean visible)
630
653
display->show_zeroes = visible;
631
get_state(display)->cursor = -1;
632
display_refresh(display);
637
display_set_format(GCDisplay *display, DisplayFormat format)
639
display->format = format;
640
get_state(display)->cursor = -1;
641
display_refresh(display);
646
display_set_word_size(GCDisplay *display, int word_size)
648
display->word_size = word_size;
653
display_set_angle_unit(GCDisplay *display, MPAngleUnit angle_unit)
655
display->angle_unit = angle_unit;
654
set_boolean_resource(R_ZEROES, visible);
655
get_state(display)->cursor = -1;
656
display_refresh(display);
660
void display_set_base(GCDisplay *display, int base)
662
display->base = base;
663
get_state(display)->cursor = -1;
664
display_refresh(display);
668
void display_set_format(GCDisplay *display, DisplayFormat type)
670
v->display.format = type;
671
set_enumerated_resource(R_DISPLAY, display_types, (int) type);
672
get_state(display)->cursor = -1;
673
display_refresh(display);
659
677
/* Convert engineering or scientific number in the given base. */
661
make_eng_sci(GCDisplay *display, char *target, int target_len, const MPNumber *x, int base_)
679
make_eng_sci(GCDisplay *display, char *target, int target_len, const MPNumber *MPnumber, int base)
663
char fixed[MAX_DIGITS], *c;
664
MPNumber t, z, base, base3, base10, base10inv, mantissa;
665
int eng, exponent = 0;
667
const char *super_digits[] = {"⁰", "¹", "²", "³", "⁴", "⁵", "⁶", "⁷", "⁸", "⁹"};
669
string = g_string_sized_new(target_len);
671
eng = display->format == ENG;
674
if (mp_is_negative(x))
675
g_string_append(string, "−");
676
mp_set_from_mp(&z, &mantissa);
678
mp_set_from_integer(base_, &base);
679
mp_xpowy_integer(&base, 3, &base3);
680
mp_xpowy_integer(&base, 10, &base10);
681
mp_set_from_integer(1, &t);
682
mp_divide(&t, &base10, &base10inv);
684
if (!mp_is_zero(&mantissa)) {
685
while (!eng && mp_is_greater_equal(&mantissa, &base10)) {
687
mp_multiply(&mantissa, &base10inv, &mantissa);
690
while ((!eng && mp_is_greater_equal(&mantissa, &base)) ||
691
(eng && (mp_is_greater_equal(&mantissa, &base3) || exponent % 3 != 0))) {
693
mp_divide(&mantissa, &base, &mantissa);
696
while (!eng && mp_is_less_than(&mantissa, &base10inv)) {
698
mp_multiply(&mantissa, &base10, &mantissa);
701
mp_set_from_integer(1, &t);
702
while (mp_is_less_than(&mantissa, &t) || (eng && exponent % 3 != 0)) {
704
mp_multiply(&mantissa, &base, &mantissa);
708
mp_cast_to_string(&mantissa, base_, display->accuracy, !display->show_zeroes, fixed, MAX_DIGITS);
709
g_string_append(string, fixed);
710
g_string_append_printf(string, "×10");
712
exponent = -exponent;
713
g_string_append(string, "⁻");
715
snprintf(fixed, MAX_DIGITS, "%d", exponent);
716
for (c = fixed; *c; c++)
717
g_string_append(string, super_digits[*c - '0']);
719
strncpy(target, string->str, target_len);
720
g_string_free(string, TRUE);
681
static char digits[] = "0123456789ABCDEF";
682
char fixed[MAX_DIGITS], *optr;
683
MPNumber MP1, MPatmp, MPval;
684
MPNumber MP1base, MP3base, MP10base;
686
MPNumber MPmant; /* Mantissa. */
687
int ddig; /* Number of digits in exponent. */
688
int eng = 0; /* Set if this is an engineering number. */
689
int exp = 0; /* Exponent */
691
if (display->format == ENG) {
695
mp_abs(MPnumber, &MPval);
696
mp_set_from_integer(0, &MP1);
697
if (mp_is_less_than(MPnumber, &MP1)) {
701
mp_set_from_mp(&MPval, &MPmant);
703
mp_set_from_integer(base, &MP1base);
704
mp_xpowy_integer(&MP1base, 3, &MP3base);
705
mp_xpowy_integer(&MP1base, 10, &MP10base);
707
mp_set_from_integer(1, &MP1);
708
mp_divide(&MP1, &MP10base, &MPatmp);
710
mp_set_from_integer(0, &MP1);
711
if (!mp_is_equal(&MPmant, &MP1)) {
712
while (!eng && mp_is_greater_equal(&MPmant, &MP10base)) {
714
mp_multiply(&MPmant, &MPatmp, &MPmant);
717
while ((!eng && mp_is_greater_equal(&MPmant, &MP1base)) ||
718
(eng && (mp_is_greater_equal(&MPmant, &MP3base) || exp % 3 != 0))) {
720
mp_divide(&MPmant, &MP1base, &MPmant);
723
while (!eng && mp_is_less_than(&MPmant, &MPatmp)) {
725
mp_multiply(&MPmant, &MP10base, &MPmant);
728
mp_set_from_integer(1, &MP1);
729
while (mp_is_less_than(&MPmant, &MP1) || (eng && exp % 3 != 0)) {
731
mp_multiply(&MPmant, &MP1base, &MPmant);
735
mp_cast_to_string(&MPmant, base, v->accuracy, !v->display.show_zeroes, fixed, MAX_DIGITS);
737
for (i = 0; i < len; i++) {
751
mp_set_from_string("0.5", 10, &MP1);
752
mp_add_integer(&MP1, exp, &MPval);
753
mp_set_from_integer(1, &MP1);
754
for (ddig = 0; mp_is_greater_equal(&MPval, &MP1); ddig++) {
755
mp_divide(&MPval, &MP1base, &MPval);
763
mp_multiply(&MPval, &MP1base, &MPval);
764
dval = mp_cast_to_int(&MPval);
765
*optr++ = digits[dval];
767
mp_add_integer(&MPval, dval, &MPval);
724
/* Convert MP number to character string. */
773
/* Convert MP number to character string in the given base. */
726
display_make_number(GCDisplay *display, char *target, int target_len, const MPNumber *x)
728
switch(display->format) {
730
mp_cast_to_string(x, 10, display->accuracy, !display->show_zeroes, target, target_len);
733
mp_cast_to_string(x, 2, display->accuracy, !display->show_zeroes, target, target_len);
736
mp_cast_to_string(x, 8, display->accuracy, !display->show_zeroes, target, target_len);
739
mp_cast_to_string(x, 16, display->accuracy, !display->show_zeroes, target, target_len);
742
make_eng_sci(display, target, target_len, x, 10);
745
make_eng_sci(display, target, target_len, x, 10);
752
variable_is_defined(const char *name)
754
char *c, *lower_name;
756
lower_name = strdup(name);
757
for (c = lower_name; *c; c++)
760
if (strcmp(lower_name, "rand") == 0 ||
761
strcmp(lower_name, "ans") == 0) {
767
return register_get_value(name) != NULL;
772
get_variable(const char *name, MPNumber *z, void *data)
774
char *c, *lower_name;
776
GCDisplay *display = data;
779
lower_name = strdup(name);
780
for (c = lower_name; *c; c++)
783
if (strcmp(lower_name, "rand") == 0)
784
mp_set_from_random(z);
785
else if (strcmp(lower_name, "ans") == 0)
786
mp_set_from_mp(display_get_answer(display), z);
788
t = register_get_value(name);
790
mp_set_from_mp(t, z);
802
set_variable(const char *name, const MPNumber *x, void *data)
804
/* FIXME: Don't allow writing to built-in variables, e.g. ans, rand, sin, ... */
805
register_set_value(name, x);
810
convert(const MPNumber *x, const char *x_units, const char *z_units, MPNumber *z, void *data)
812
/* Update currency if necessary */
813
if (currency_rates_needs_update())
814
currency_download_rates();
815
currency_load_rates();
816
if (currency_get_index(x_units) >= 0 && currency_get_index(z_units) >= 0)
775
display_make_number(GCDisplay *display, char *target, int target_len, const MPNumber *x, int base, int ignoreError)
779
/* NOTE: display_make_number can currently set v->error when converting to a double.
780
* This is to provide the same look&feel as V3 even though gcalctool
781
* now does internal arithmetic to "infinite" precision.
783
* XXX: Needs to be improved. Shouldn't need to convert to a double in
784
* order to do these tests.
787
double number = mp_cast_to_double(x);
790
if (v->error && !ignoreError) {
818
currency_convert(x, currency_get_index(x_units), currency_get_index(z_units), z);
827
parse(GCDisplay *display, const char *text, MPNumber *z, char **error_token)
829
MPEquationOptions options;
831
memset(&options, 0, sizeof(options));
832
options.wordlen = display->word_size;
833
options.angle_units = display->angle_unit;
834
options.variable_is_defined = variable_is_defined;
835
options.get_variable = get_variable;
836
options.set_variable = set_variable;
837
options.convert = convert;
838
options.callback_data = display;
840
return mp_equation_parse(text, &options, z, error_token);
845
do_paste(GCDisplay *display, int cursor_start, int cursor_end, const char *text)
848
char c, *output, *clean_text;
850
/* Copy input to modify, no operation can make the clean string longer than
851
* the original string */
852
clean_text = strdup(text);
855
for (input = text; *input; input++) {
856
/* If the clipboard buffer contains any occurances of the "thousands
857
* separator", remove them.
859
if (v->tsep[0] != '\0' && strncmp(input, v->tsep, strlen(v->tsep)) == 0) {
860
input += strlen(v->tsep) - 1;
864
/* Replace radix with "." */
865
else if (strncmp(input, v->radix, strlen(v->radix)) == 0) {
866
input += strlen(v->radix) - 1;
870
/* Replace tabs with spaces */
871
else if (*input == '\t') {
875
/* Terminate on newlines */
876
else if (*input == '\r' || *input == '\n') {
880
/* If an "A", "B", "C", "D" or "F" character is encountered, it
881
* will be converted to its lowercase equivalent. If an "E" is
882
* found, and the next character is a "-" or a "+", then it
883
* remains as an upper case "E" (it's assumed to be a possible
884
* exponential number), otherwise its converted to a lower case
885
* "e". See bugs #455889 and #469245 for more details.
887
else if (*input >= 'A' && *input <= 'F') {
890
if (*(input+1) != '-' && *(input+1) != '+')
904
display_insert(display, cursor_start, cursor_end, clean_text);
909
do_insert_character(GCDisplay *display, const unsigned char *text)
913
mp_set_from_integer(0, &value);
915
mp_add_integer(&value, text[i], &value);
917
mp_shift(&value, 8, &value);
923
display_set_number(display, &value);
927
/* Perform bitwise shift on display value. */
929
do_shift(GCDisplay *display, int count)
933
if (!display_is_usable_number(display, &z)) {
934
/* Translators: This message is displayed in the status bar when a bit
935
shift operation is performed and the display does not contain a number */
936
ui_set_statusbar(_("No sane value to bitwise shift"));
939
mp_shift(&z, count, display_get_answer(display));
940
display_set_answer(display);
950
if (!display_is_usable_number(&v->display, &value)) {
951
/* Translators: Error displayed when trying to factorize a non-integer value */
952
ui_set_statusbar(_("Need an integer to factorize"));
955
display_clear(&v->display);
957
GList *factors = mp_factorize(&value);
959
display_insert_number(&v->display, -1, -1, factors->data);
960
g_slice_free(MPNumber, factors->data);
962
GList *list = factors->next;
963
for (; list != NULL; list = list->next) {
964
display_insert(&v->display, -1, -1, "×");
965
display_insert_number(&v->display, -1, -1, list->data);
966
g_slice_free(MPNumber, list->data);
968
g_list_free(factors);
973
do_sto(GCDisplay *display, const char *name)
977
if (!display_is_usable_number(display, &t))
978
ui_set_statusbar(_("No sane value to store"));
980
register_set_value(name, &t);
985
display_do_function(GCDisplay *display, int function, gpointer arg, int cursor_start, int cursor_end)
993
display_pop(display);
997
display_unpop(display);
1004
display_push(display);
1006
display_set_cursor(display, cursor_start);
1007
ans = display_get_answer(display);
1009
ui_set_statusbar("");
1013
display_clear(display);
1017
do_shift(display, GPOINTER_TO_INT (arg));
1021
do_factorize(display, GPOINTER_TO_INT (arg));
1025
do_paste(display, cursor_start, cursor_end, (const char *)arg);
1028
case FN_INSERT_CHARACTER:
1029
do_insert_character(display, (const unsigned char *)arg);
1033
do_sto(display, (const char *)arg);
1037
display_insert(display, cursor_start, cursor_end, (const char *)arg);
1041
display_backspace(display, cursor_start, cursor_end);
1045
display_delete(display, cursor_start, cursor_end);
1049
if (display_get_unsigned_integer(display, &bit_value)) {
1050
char buf[MAX_DISPLAY];
1053
bit_value ^= (1LL << (63 - GPOINTER_TO_INT (arg)));
1055
/* FIXME: Convert to string since we don't support setting MP numbers from 64 bit integers */
1056
SNPRINTF(buf, MAX_DISPLAY, "%" G_GUINT64_FORMAT, bit_value);
1057
mp_set_from_string(buf, &MP);
1058
display_set_number(display, &MP);
1063
/* If showing a result display the calculation that caused
1065
/* TODO: Work out why two undo steps are required and why
1066
* the cursor must be taken from the first undo */
1067
if (display_is_result(display)) {
1068
display_pop(display);
1069
if (display_is_undo_step(display)) {
1070
display_pop(display);
1074
} else if (display_is_empty(display)) {
1077
/* Solve the equation */
1081
const char *message = NULL;
1082
char *text, *error_token;
1084
text = get_expression (display);
1085
result = parse(display,
1092
case PARSER_ERR_NONE:
1093
mp_set_from_mp(&z, ans);
1094
display_set_answer(display);
1097
case PARSER_ERR_OVERFLOW:
1098
/* Translators: Error displayed to user when they perform a bitwise operation on numbers greater than the current word */
1099
message = _("Overflow. Try a bigger word size");
1102
case PARSER_ERR_UNKNOWN_VARIABLE:
1103
/* Translators: Error displayed to user when they an unknown variable is entered */
1104
message = g_strdup_printf(_("Unknown variable '%s'"), error_token);
1108
case PARSER_ERR_UNKNOWN_FUNCTION:
1109
/* Translators: Error displayed to user when an unknown function is entered */
1110
message = g_strdup_printf(_("Function '%s' is not defined"), error_token);
1114
case PARSER_ERR_UNKNOWN_CONVERSION:
1115
/* Translators: Error displayed to user when an conversion with unknown units is attempted */
1116
message = g_strdup_printf(_("Unknown conversion"));
1120
message = mp_get_error();
1124
/* Translators: Error displayed to user when they enter an invalid calculation */
1125
message = _("Malformed expression");
1129
ui_set_statusbar(message);
1134
/* Start new equation when entering digits after existing result */
1135
if(display_is_result(display) && g_unichar_isdigit(g_utf8_get_char((char*)arg)))
1136
display_clear(display);
1138
display_insert(display, cursor_start, cursor_end, (const char *)arg);
1142
enabled = display_get_unsigned_integer(display, &bit_value);
1143
ui_set_bitfield(enabled, bit_value);
798
max_fix = 1.298074214e+33;
801
max_fix = 2.037035976e+90;
804
max_fix = 1.000000000e+100;
808
max_fix = 2.582249878e+120;
812
// FIXME: Do this based on the number of digits, not actual values
813
if ((display->format == ENG) ||
814
(display->format == SCI) ||
815
(display->format == FIX && val != 0.0 && (val > max_fix))) {
816
make_eng_sci(display, target, target_len, x, base);
818
mp_cast_to_string(x, base, v->accuracy, !v->display.show_zeroes, target, target_len);