/*
* general_functions.c - this and that.
* part of galculator
* (c) 2002-2007 Simon Floery (chimaira@users.sf.net)
*
* 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 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 Library 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 <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#include "galculator.h"
#include "general_functions.h"
#include "math_functions.h"
#include "calc_basic.h"
#include "display.h"
#include "config_file.h"
#include "callbacks.h"
#include "ui.h"
#include "flex_parser.h"
#include <gtk/gtk.h>
#include <glade/glade.h>
double error_unsupported_inv (double dummy)
{
error_message (_("unsupported inverse function"));
return dummy;
}
double error_unsupported_hyp (double dummy)
{
error_message (_("unsupported hyperbolic function"));
return dummy;
}
void error_message (char *format_string, ...)
{
va_list ap;
fprintf (stderr, "[%s] ", PROG_NAME);
va_start(ap, format_string);
vfprintf (stderr, format_string, ap);
va_end(ap);
fprintf (stderr, ". %s\n", BUG_REPORT);
}
/* the last entered number is removed. it is impossible to remove the last operation:
* this would be a quite difficult taks, as every possible computation is done asap.
* so if you entered 1+2- and you want to correct to 1+2/ calc_basic would have already
* calculated 1+2=3 and set the tree to 3-. you would have to make a backup of the tree!*/
void clear ()
{
display_result_set (CLEARED_DISPLAY, TRUE, 0.);
if (current_status.notation == CS_FORMULA) ui_formula_entry_set ("");
}
/* backspace. if formula_entry is active, backspace works anyway. but if we
* press GUI's backspace button this gives the expected result.
*/
void backspace ()
{
if (current_status.notation == CS_FORMULA) ui_formula_entry_backspace();
else display_result_backspace(current_status.number);
}
/* clear all: display ("0"), calc_tree ... */
void all_clear ()
{
clear();
switch (current_status.notation) {
case CS_PAN:
alg_free(main_alg);
main_alg = alg_init(0);
break;
case CS_RPN:
rpn_free();
rpn_init(prefs.stack_size, 0);
display_stack_remove();
display_stack_create();
/* it's a stack lifting disabling functon */
current_status.rpn_stack_lift_enabled = FALSE;
break;
case CS_FORMULA:
alg_free(main_alg);
rpn_free();
display_stack_remove();
break;
default:
fprintf (stderr, _("[%s] unknown notation mode in function \"all_clear\". %s\n"), PROG_NAME, BUG_REPORT);
}
display_module_bracket_label_update (RESET);
}
/* axtof: convert string to float
* works up to base 19. only for integers!
* a number is called negative, if its msb is set!
*/
double axtof (char *bin_string, int base, int nr_bits, gboolean is_signed)
{
double return_value=0;
int counter;
char *lower_bin_string;
lower_bin_string = g_ascii_strdown(bin_string, -1);
/* according to man strtod, inf should be there in every case */
if (strstr (lower_bin_string, "inf") != NULL) return INFINITY;
for (counter = strlen (lower_bin_string) - 1; counter >= 0; counter--) {
if (lower_bin_string[counter] - '0' < 10) \
return_value += (lower_bin_string[counter] - '0') * pow (base, strlen (lower_bin_string) - 1 - counter);
else if (lower_bin_string[counter] - 'a' < 10) \
return_value += (lower_bin_string[counter] - 'a' + 10) * pow (base, strlen (lower_bin_string) - 1 - counter);
else fprintf (stderr, _("[%s] failed to convert char %c in function \"axtof\". %s\n"), PROG_NAME, lower_bin_string[counter], BUG_REPORT);
}
g_free (lower_bin_string);
/* handle negative numbers. */
/* if most significant bit is set, its a negative number. using */
if (is_signed == TRUE)
if (return_value >= pow (2, nr_bits - 1))
return_value = (-1) * (pow (2, nr_bits) - return_value);
return return_value;
}
/* rem: my own remainder function to deal with precision problems */
int rem (double x, long long int y)
{
return x - ((long long int)(x/((double)y)))*y;
}
/* ftoax - number to string conversion.
* works up to base 19. only for integers!
* see axtof for details about what is a negative number.
*/
char *ftoax (double x, int base, int nr_bits, gboolean is_signed)
{
char *return_string;
int length=0, counter, remainder;
double localx;
/* handle huge values --> infinity */
if (is_signed == TRUE) {
if (x < (-1)*pow (2, nr_bits - 1)) return g_strdup(MY_INFINITY_STRING);
if (x >= pow (2, nr_bits - 1)) return g_strdup(MY_INFINITY_STRING);
/* handle negative numbers */
if (x < 0) x = pow (2, nr_bits) + x;
} else {
if (x >= pow (2, nr_bits)) return g_strdup(MY_INFINITY_STRING);
if (x < 0) return g_strdup(MY_INFINITY_STRING);
}
/* doing it this way and not with logs as this is much more numerical stable */
localx = x;
while ((localx=floor(localx/(double)base)) >= 1) length++;
length+=2;
localx = x;
return_string = (char *) malloc (length * sizeof(char));
return_string [length-1] = '\0';
for (counter = length-2; counter >= 0; counter--) {
remainder = rem (localx, base);
if (remainder < 10) return_string[counter] = '0' + remainder;
else if (remainder < 20) return_string[counter] = 'A' + remainder - 10;
else fprintf (stderr, _("[%s] failed to convert %f in function \"ftoax\". %s\n"), PROG_NAME, x, BUG_REPORT);
localx = floor (localx / (double)base);
}
return return_string;
}
char *add_leading_zeros (char *string, int multiple)
{
char *new_string;
int length, offset, counter;
/* I don't want "0" to become "000000000" or whatever */
if (strcmp (string, "0") == 0) return g_strdup(string);
if (strcmp (string, MY_INFINITY_STRING) == 0) return g_strdup(string);
length = strlen(string);
offset = (multiple - length%multiple)%multiple;
length += offset;
new_string = (char *) malloc ((length + 1) * sizeof(char));
for (counter = 0; counter < offset; counter++)
new_string[counter] = '0';
for (counter = offset; counter <= length; counter++)
new_string[counter] = string[counter-offset];
free (string);
return new_string;
}
/*
* preference dialog sets. these are handler for the big configuration struct.
*/
void set_button_font (GladeXML *xml, char *button_name, void *new_label)
{
GtkButton *button;
char **string_var;
string_var = new_label;
button = (GtkButton *) glade_xml_get_widget (xml, button_name);
if (button) gtk_font_button_set_font_name (GTK_FONT_BUTTON(button), *string_var);
}
void set_checkbutton (GladeXML *xml, char *checkbutton_name, void *is_active)
{
GtkToggleButton *toggle_button;
gboolean *bool_var;
bool_var = is_active;
toggle_button = (GtkToggleButton *) glade_xml_get_widget (xml, checkbutton_name);
if (toggle_button) {
gtk_toggle_button_set_active (toggle_button, *bool_var);
/* they say there is no good reason. i say there is */
gtk_toggle_button_toggled (toggle_button);
}
}
void set_spinbutton (GladeXML *xml, char *spinbutton_name, void *value)
{
GtkSpinButton *spin_button;
int *int_var;
int_var = value;
/*d_var = (double) *int_var;*/
spin_button = (GtkSpinButton *) glade_xml_get_widget (xml, spinbutton_name);
if (spin_button) gtk_spin_button_set_value (spin_button, *int_var);
}
void set_optmenu (GladeXML *xml, char *optmenu_name, void *index)
{
GtkOptionMenu *opt_menu;
int *int_var;
int_var = index;
opt_menu = (GtkOptionMenu *) glade_xml_get_widget (xml, optmenu_name);
if (opt_menu) gtk_option_menu_set_history (opt_menu, *int_var);
}
/*
*
*/
void set_button_color (GladeXML *xml, char *button_name, void *color_string)
{
GtkWidget *button;
char **string_var;
GdkColor color;
/* dereference */
string_var = color_string;
gdk_color_parse (*string_var, &color);
button = glade_xml_get_widget (xml, button_name);
if (button) gtk_color_button_set_color (GTK_COLOR_BUTTON(button), &color);
}
void set_stacksize (GladeXML *xml, char *name, void *stack_size)
{
int *size;
GtkToggleButton *tb;
/* name is NULL */
size = stack_size;
if (*size == RPN_FINITE_STACK)
tb = (GtkToggleButton *) glade_xml_get_widget (xml, "finite_stack_size");
else tb = (GtkToggleButton *) glade_xml_get_widget (xml, "infinite_stack_size");
gtk_toggle_button_set_active (tb, TRUE);
}
void set_entry (GladeXML *xml, char *entry_name, void *entry_text)
{
GtkEntry *entry;
char **string_var;
string_var = entry_text;
entry = (GtkEntry *) glade_xml_get_widget (xml, entry_name);
if (entry) gtk_entry_set_text (entry, *string_var);
}
/*
* convert given GdkColor to a string so that gdk_color_parse gives the
* same color again. Formerly called gdk_color_to_string but since version 2.12
* gdk features that function by itself.
*/
char *convert_gdk_color_to_string (GdkColor color)
{
return g_strdup_printf ("#%04X%04X%04X", color.red, color.green, color.blue);
}
/*
* "apply"
*/
void apply_preferences (s_preferences prefs)
{
GtkWidget *menu_item;
/* not view specific */
set_widget_visibility (main_window_xml, "menubar", prefs.show_menu);
menu_item = glade_xml_get_widget (main_window_xml, "show_menubar1");
gtk_check_menu_item_set_active ((GtkCheckMenuItem *) menu_item, prefs.show_menu);
switch (prefs.mode) {
case BASIC_MODE:
menu_item =
glade_xml_get_widget (main_window_xml, "basic_mode");
break;
case SCIENTIFIC_MODE:
menu_item =
glade_xml_get_widget (main_window_xml, "scientific_mode");
break;
case PAPER_MODE:
menu_item =
glade_xml_get_widget (main_window_xml, "paper_mode");
break;
default:
error_message ("Unknown mode %i in \"apply_preferences\"", prefs.mode);
}
gtk_menu_item_activate ((GtkMenuItem *) menu_item);
/* view specific */
/* display_update_tags ();
display_set_bkg_color (prefs.bkg_color);
set_all_buttons_size (prefs.button_width, prefs.button_height);
if (prefs.custom_button_font == TRUE) button_font = g_strdup (prefs.button_font);
else button_font = g_strdup ("");
set_all_buttons_font (button_font);
g_free (button_font);
*/
}
/*
* this function changes the foreground color for all states to the given string
*/
void gtk_widget_really_modify_fg (GtkWidget *widget, GdkColor color)
{
gtk_widget_modify_fg (widget, GTK_STATE_NORMAL, &color);
gtk_widget_modify_fg (widget, GTK_STATE_ACTIVE, &color);
gtk_widget_modify_fg (widget, GTK_STATE_PRELIGHT, &color);
gtk_widget_modify_fg (widget, GTK_STATE_SELECTED, &color);
gtk_widget_modify_fg (widget, GTK_STATE_INSENSITIVE, &color);
}
gboolean is_valid_number (int number_base, char number)
{
char *valid_numbers[4]={"1234567890", "1234567890abcdef", "12345670", "01"};
return ((strchr (valid_numbers[number_base], g_ascii_tolower (number)) != NULL) \
|| (number == dec_point[0]));
}
/*
* activate_menu_item - activates menu item with widget name item_name
*/
void activate_menu_item (char *item_name)
{
GtkMenuItem *menu_item;
menu_item = (GtkMenuItem *) glade_xml_get_widget (main_window_xml, \
g_strstrip (g_ascii_strdown (item_name, -1)));
if (menu_item)
/* as we use this only for menu boxes, a simple activate is enough.
* the extra magic in src/callbacks.c::on_scientific_mode_activate
* is necessary only for checkboxmenuitems.
*/
gtk_menu_item_activate ((GtkMenuItem *) menu_item);
else fprintf (stderr, _("[%s] failed to find widget %s in function \"activate_menu_item\". %s\n"), PROG_NAME, item_name, BUG_REPORT);
}
/* get_number_string - converts value to a string, with repect to base. returned
* string should be freed.
*/
char *get_display_number_string (double value, int base)
{
char *string_value;
switch (base) {
case CS_DEC:
string_value = g_strdup_printf ("%.*g", get_display_number_length(current_status.number), value);
break;
case CS_HEX:
string_value = ftoax (value, 16, prefs.hex_bits, prefs.hex_signed);
break;
case CS_OCT:
string_value = ftoax (value, 8, prefs.oct_bits, prefs.oct_signed);
break;
case CS_BIN:
string_value = ftoax (value, 2, prefs.bin_bits, prefs.bin_signed);
if (prefs.bin_fixed == TRUE)
string_value = add_leading_zeros (string_value,
prefs.bin_length);
break;
default:
string_value = g_strdup(_("unknown number base"));
fprintf (stderr, _("[%s] unknown number base in function \"get_display_number_string\". %s\n"), PROG_NAME, BUG_REPORT);
}
return string_value;
}
/* get_display_number_length - returns the maximum length of a number in current
* mode.
*/
int get_display_number_length (int base)
{
switch (base) {
case CS_DEC:
return DISPLAY_RESULT_PRECISION;
case CS_HEX:
return prefs.hex_bits/4;
case CS_OCT:
return prefs.oct_bits/3;
case CS_BIN:
return prefs.bin_bits/1;
default:
fprintf (stderr, _("[%s] unknown number base in function \"get_display_number_length\". %s\n"), PROG_NAME, BUG_REPORT);
return 0;
}
}
/* gfunc_f1. The parenthesis open (PAN) resp swapxy (RPN) button is special. It
* has to be operation and gfunc button both in one. There (see also
* ui.c::set_basic_object_data it gets both information. in both cases
* it is connected to on_gfunc_button_clicked, which calls this function,
* which itseld seperates on behalf of current notation, how to continue.
* gfunc_f2 is the same. If there will be more buttons of this kind, we
* should consider introducing a new button class.
*/
void gfunc_f1 (GtkToggleButton *button)
{
double *stack;
if (current_status.notation == CS_PAN)
on_operation_button_clicked (button, NULL);
else {
display_result_set_double (rpn_stack_swapxy(
display_result_get_double(current_status.number)), current_status.number);
stack = rpn_stack_get (RPN_FINITE_STACK);
display_stack_set_yzt_double (stack, current_status.number);
free (stack);
current_status.rpn_stack_lift_enabled = TRUE;
current_status.calc_entry_start_new = TRUE;
}
}
/* gfunc_f2. see gfunc1
*/
void gfunc_f2 (GtkToggleButton *button)
{
double *stack;
if (current_status.notation == CS_PAN)
on_operation_button_clicked (button, NULL);
else {
display_result_set_double (rpn_stack_rolldown(
display_result_get_double(current_status.number)), current_status.number);
stack = rpn_stack_get (RPN_FINITE_STACK);
display_stack_set_yzt_double (stack, current_status.number);
free (stack);
current_status.rpn_stack_lift_enabled = TRUE;
current_status.calc_entry_start_new = TRUE;
}
}
/* rpn_stack_lift. The terminology used here originates from HP 15 Owner's
* handbook. If a button doesn't terminate digit entry, it "starts" one.
* Therefore those buttons have to push result on the stack, if stack lift is
* enabled (current_status.rpn_stack_lift_enabled).
* Buttons not terminating digit entry are:
* 0-9, A-F, ., EE, const, MR
*/
void rpn_stack_lift ()
{
double *stack;
if ((current_status.notation == CS_RPN) &&
(current_status.rpn_stack_lift_enabled == TRUE)) {
rpn_stack_push (display_result_get_double (current_status.number));
stack = rpn_stack_get (RPN_FINITE_STACK);
display_stack_set_yzt_double (stack, current_status.number);
free (stack);
current_status.rpn_stack_lift_enabled = FALSE;
}
}
void remember_display_values()
{
char *stack[3];
if (prefs.rem_display == TRUE) {
display_result_set (prefs.rem_valuex, TRUE, string2double(prefs.rem_valuex, current_status.number));
/* for the result setting the display string is enough */
if (current_status.notation == CS_RPN) {
stack[0] = prefs.rem_valuey;
stack[1] = prefs.rem_valuez;
stack[2] = prefs.rem_valuet;
display_stack_set_yzt (stack);
/* for the stack we have to update calc_basic */
rpn_stack_push (string2double(stack[2], current_status.number));
rpn_stack_push (string2double(stack[1], current_status.number));
rpn_stack_push (string2double(stack[0], current_status.number));
}
}
}
/*
* string2double - this function makes a string to double conversion with
* respect to supplied number base. if number base < 0 we try to
* determine from string which should have then a 0? prefix.
* it uses axtof.
*/
double string2double (char *string, int number_base)
{
char *end_ptr;
double ret_val;
switch (number_base) {
case CS_DEC:
ret_val = strtod(string, &end_ptr);
if (*end_ptr != '\0')
fprintf (stderr, _("[%s] failed to convert %s to a number properly in function \"string2double\". Have you changed your locales? %s\n"), PACKAGE, string, BUG_REPORT);
return ret_val;
break;
case CS_HEX:
return axtof(string, 16, prefs.hex_bits,
prefs.hex_signed);
break;
case CS_OCT:
return axtof(string, 8, prefs.oct_bits,
prefs.oct_signed);
break;
case CS_BIN:
return axtof(string, 2, prefs.bin_bits,
prefs.bin_signed);
break;
default:
fprintf (stderr, _("[%s] unknown number base in function \"string2double\". %s\n"), PROG_NAME, BUG_REPORT);
}
return 0;
}
/* string_separator. insert separator.
* string - the string to modify
* separate - whether to do sth at all
* block_length - insert separator all block_length chars
* separator - separator char to insert
* dpoint - char representing the decimal point
* we do not free string here as it might be used later on!
*/
char *string_add_separator (char* string, gboolean separate, int block_length, char separator, char dpoint)
{
int int_length=0, frac_length=0, counter=0, new_counter=0, offset;
char *new_string;
if (!separate) return g_strdup(string);
/* at first, get length of parts pre- and succeeding the decimal point */
while ((string[int_length] != '\0') && (string[int_length] != dpoint) && (string[int_length] != 'e'))
int_length++;
if (string[int_length] == dpoint)
while ((string[int_length + frac_length + 1] != '\0') && (string[int_length + frac_length + 1] != 'e')) frac_length++;
/* then allocate memory for new string holding separators */
new_string = (char *) malloc ((strlen(string) + (int_length-1)/block_length +
(frac_length-1)/block_length + 1) * sizeof(char));
/* then copy from string to new_string and insert separators */
while ((string[counter] != '\0') && (string[counter] != dpoint) && (string[counter] != 'e')) {
/* > ( == ) is horrible, yes, but somehow cool. avoids space
* between sign char '-' and leading digit
*/
if ((counter > (*string == '-')) && ((int_length % block_length) == (counter % block_length))) {
new_string[new_counter] = separator;
new_counter++;
}
new_string[new_counter] = string[counter];
new_counter++;
counter++;
}
if ((string[int_length] != '\0') && (string[int_length] != 'e')) {
/* copy decimal point */
new_string[new_counter] = string[counter];
new_counter++;
counter++;
offset = counter;
while ((string[counter] != '\0') && (string[counter] != 'e')) {
if (((counter - offset) > 0) && ((counter - offset) % block_length == 0)) {
new_string[new_counter] = separator;
new_counter++;
}
new_string[new_counter] = string[counter];
new_counter++;
counter++;
}
}
while (string[counter] != '\0') new_string[new_counter++] = string[counter++];
new_string[new_counter] = '\0';
return new_string;
}
/* string_del_separator. removes separator from string, in place.
*/
char *string_del_separator (char *string, char separator)
{
int counter=0, new_counter=0;
while (string[counter] != '\0') {
if (string[counter] == separator) {
counter++;
continue;
}
string[new_counter] = string[counter];
counter++;
new_counter++;
}
string[new_counter] = '\0';
return string;
}
void set_button_label_and_tooltip (GladeXML *xml, char *button_name,
char *label, char *tooltip)
{
GtkWidget *w;
GtkTooltipsData *tooltip_data;
w = glade_xml_get_widget (xml, button_name);
if (w) {
gtk_button_set_label ((GtkButton *)w, label);
tooltip_data = gtk_tooltips_data_get (w);
g_free (tooltip_data->tip_text);
tooltip_data->tip_text = g_strdup (tooltip);
}
}
GtkWidget *formula_entry_is_active (GtkWidget *window_widget)
{
GtkWidget *active_widget=NULL, *main_window=NULL;
main_window = glade_xml_get_widget (main_window_xml, "main_window");
if (main_window != NULL)
active_widget = gtk_window_get_focus ((GtkWindow *)main_window);
if (active_widget != NULL)
if ((strcmp (gtk_widget_get_name (gtk_widget_get_toplevel(window_widget)),"main_window") == 0) &&
(strcmp (gtk_widget_get_name (active_widget), "formula_entry") == 0))
return active_widget;
return NULL;
}
/* sometimes it makes no sense to check for the toplevel widget's name, e.g.
* for menuitems. then use this func.
*/
GtkWidget *formula_entry_is_active_no_toplevel_check ()
{
GtkWidget *active_widget=NULL, *main_window=NULL;
main_window = glade_xml_get_widget (main_window_xml, "main_window");
if (main_window)
active_widget = gtk_window_get_focus ((GtkWindow *) main_window);
if (active_widget)
if (strcmp (gtk_widget_get_name (active_widget), "formula_entry") == 0)
return active_widget;
return NULL;
}
s_flex_parser_result compute_user_function (char *expression, char *variable, char *value)
{
int nr_constants;
s_flex_parser_result result;
nr_constants = 0;
while (constant[nr_constants].name != NULL) nr_constants++;
constant = (s_constant *) realloc (constant, (nr_constants + 2) * sizeof(s_constant));
constant[nr_constants + 1].name = NULL;
constant[nr_constants].name = variable;
constant[nr_constants].value = value;
constant[nr_constants].desc = NULL;
result = flex_parser(expression);
constant = (s_constant *) realloc (constant, (nr_constants + 1) * sizeof(s_constant));
constant[nr_constants].name = NULL;
return result;
}
double x2rad (double x)
{
switch (current_status.angle){
case CS_DEG:
return deg2rad(x);
case CS_RAD:
return x;
case CS_GRAD:
return grad2rad (x);
default:
fprintf (stderr, _("[%s] unknown angle base in function \"x2rad\". %s\n"), PROG_NAME, BUG_REPORT);
}
return x;
}
double rad2x (double rad)
{
switch (current_status.angle) {
case CS_DEG:
return rad2deg(rad);
case CS_RAD:
return rad;
case CS_GRAD:
return rad2grad(rad);
default:
fprintf (stderr, _("[%s] unknown angle base in function \"rad2x\". %s\n"), PROG_NAME, BUG_REPORT);
}
return rad;
}
gboolean get_sep (int number_base)
{
switch (number_base) {
case CS_DEC:
return prefs.dec_sep;
case CS_HEX:
return prefs.hex_sep;
case CS_OCT:
return prefs.oct_sep;
case CS_BIN:
return prefs.bin_sep;
default:
fprintf (stderr, _("[%s] unknown number base in function \"get_sep\". %s\n"), PROG_NAME, BUG_REPORT);
}
return 0;
}
int get_sep_length (int number_base)
{
switch (number_base) {
case CS_DEC:
return prefs.dec_sep_length;
case CS_HEX:
return prefs.hex_sep_length;
case CS_OCT:
return prefs.oct_sep_length;
case CS_BIN:
return prefs.bin_sep_length;
default:
fprintf (stderr, _("[%s] unknown number base in function \"get_sep_length\". %s\n"), PROG_NAME, BUG_REPORT);
}
return 0;
}
char get_sep_char (int number_base)
{
switch (number_base) {
case CS_DEC:
return prefs.dec_sep_char[0];
case CS_HEX:
return prefs.hex_sep_char[0];
case CS_OCT:
return prefs.oct_sep_char[0];
case CS_BIN:
return prefs.bin_sep_char[0];
default:
fprintf (stderr, _("[%s] unknown number base in function \"get_sep_char\". %s\n"), PROG_NAME, BUG_REPORT);
}
return 0;
}
void prefs_sep_char_changed (GtkEditable *editable, char *prefs_sep, int number_base)
{
char *sep, *result, **stack;
sep = gtk_editable_get_chars (editable, 0, -1);
if (strlen(sep) > 0) {
if ((is_valid_number(number_base, *sep)) ||
((number_base == CS_DEC) && ((*sep == '-') ||
(*sep == 'e') || (*sep == dec_point[0]))) ||
!isascii(*sep))
gtk_editable_delete_text (editable, 0, -1);
else {
result = display_result_get();
stack = display_stack_get_yzt();
if (prefs_sep) g_free (prefs_sep);
prefs_sep = g_strdup(sep);
if (number_base == current_status.number) {
display_result_set(result, FALSE, -1.);
display_stack_set_yzt(stack);
}
g_free (result);
g_free (stack);
}
}
g_free (sep);
}
/*
* change_option - changes CURRENT_STATUS (!) and updates the display in classic
* view. The last but one function in the signal handling cascade of changing
* base etc.
*/
void change_option (int new_status, int opt_group)
{
int old_status;
switch (opt_group) {
case DISPLAY_OPT_NUMBER:
old_status = current_status.number;
if (old_status == new_status) return;
current_status.number = new_status;
if (prefs.mode != PAPER_MODE) display_change_option (old_status, new_status, DISPLAY_OPT_NUMBER);
break;
case DISPLAY_OPT_ANGLE:
old_status = current_status.angle;
if (old_status == new_status) return;
current_status.angle = new_status;
if (prefs.mode != PAPER_MODE) display_change_option (old_status, new_status, DISPLAY_OPT_ANGLE);
break;
case DISPLAY_OPT_NOTATION:
old_status = current_status.notation;
if (old_status == new_status) return;
current_status.notation = new_status;
if (prefs.mode != PAPER_MODE) display_change_option (old_status, new_status, DISPLAY_OPT_NOTATION);
break;
default:
error_message (_("unknown display option in function \"change_option\""));
}
current_status.calc_entry_start_new = TRUE;
}
syntax highlighted by Code2HTML, v. 0.9.1