Bug Summary

File:math-equation.c
Warning:line 846, column 14
Value stored to 'is_digit' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name math-equation.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/src -resource-dir /usr/lib/llvm-14/lib/clang/14.0.6 -D HAVE_CONFIG_H -I . -I .. -D VERSION="1.25.0" -D LOCALE_DIR="/usr/local/share/locale" -D GETTEXT_PACKAGE="cafe-calc" -I /usr/include/ctk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/uuid -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/libxml2 -internal-isystem /usr/lib/llvm-14/lib/clang/14.0.6/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/12/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir=/rootdir/src -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2022-12-31-023204-15734-1 -x c math-equation.c
1/*
2 * Copyright (C) 1987-2008 Sun Microsystems, Inc. All Rights Reserved.
3 * Copyright (C) 2008-2011 Robert Ancell
4 *
5 * This program is free software: you can redistribute it and/or modify it under
6 * the terms of the GNU General Public License as published by the Free Software
7 * Foundation, either version 2 of the License, or (at your option) any later
8 * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
9 * license.
10 */
11
12#include <stdlib.h>
13#include <stdio.h>
14#include <string.h>
15#include <ctype.h>
16#include <math.h>
17#include <errno(*__errno_location ()).h>
18#include <glib.h>
19#include <glib/gi18n.h>
20
21#include "math-equation.h"
22
23#include "mp.h"
24#include "mp-equation.h"
25#include "mp-serializer.h"
26#include "mp-enums.h"
27#include "unit-manager.h"
28#include "utility.h"
29
30enum {
31 PROP_0,
32 PROP_STATUS,
33 PROP_DISPLAY,
34 PROP_EQUATION,
35 PROP_NUMBER_MODE,
36 PROP_ACCURACY,
37 PROP_SHOW_THOUSANDS_SEPARATORS,
38 PROP_SHOW_TRAILING_ZEROES,
39 PROP_NUMBER_FORMAT,
40 PROP_BASE,
41 PROP_WORD_SIZE,
42 PROP_ANGLE_UNITS,
43 PROP_SOURCE_CURRENCY,
44 PROP_TARGET_CURRENCY,
45 PROP_SOURCE_UNITS,
46 PROP_TARGET_UNITS,
47 PROP_SERIALIZER
48};
49
50static GType number_mode_type, number_format_type, angle_unit_type;
51
52#define MAX_DIGITS512 512
53
54/* Expression mode state */
55typedef struct {
56 MPNumber ans; /* Previously calculated answer */
57 gchar *expression; /* Expression entered by user */
58 gint ans_start, ans_end; /* Start and end characters for ans variable in expression */
59 gint cursor; /* ??? */
60 NumberMode number_mode; /* ??? */
61 gboolean can_super_minus; /* TRUE if entering minus can generate a superscript minus */
62 gboolean entered_multiply; /* Last insert was a multiply character */
63 gchar *status; /* Equation status */
64} MathEquationState;
65
66struct MathEquationPrivate
67{
68 CtkTextTag *ans_tag;
69
70 gint word_size; /* Word size in bits */
71 MPAngleUnit angle_units; /* Units for trigonometric functions */
72 char *source_currency;
73 char *target_currency;
74 char *source_units;
75 char *target_units;
76 NumberMode number_mode; /* ??? */
77 gboolean can_super_minus; /* TRUE if entering minus can generate a superscript minus */
78
79 gunichar digits[16]; /* Localized digits */
80
81 CtkTextMark *ans_start, *ans_end;
82
83 MathEquationState state; /* Equation state */
84 GList *undo_stack; /* History of expression mode states */
85 GList *redo_stack;
86 gboolean in_undo_operation;
87
88 gboolean in_reformat;
89
90 gboolean in_delete;
91
92 gboolean in_solve;
93
94 MathVariables *variables;
95 MpSerializer *serializer;
96
97 GAsyncQueue *queue;
98};
99
100typedef struct {
101 MPNumber *number_result;
102 gchar *text_result;
103 gchar *error;
104} SolveData;
105
106G_DEFINE_TYPE_WITH_PRIVATE (MathEquation, math_equation, CTK_TYPE_TEXT_BUFFER)static void math_equation_init (MathEquation *self); static void
math_equation_class_init (MathEquationClass *klass); static GType
math_equation_get_type_once (void); static gpointer math_equation_parent_class
= ((void*)0); static gint MathEquation_private_offset; static
void math_equation_class_intern_init (gpointer klass) { math_equation_parent_class
= g_type_class_peek_parent (klass); if (MathEquation_private_offset
!= 0) g_type_class_adjust_private_offset (klass, &MathEquation_private_offset
); math_equation_class_init ((MathEquationClass*) klass); } __attribute__
((__unused__)) static inline gpointer math_equation_get_instance_private
(MathEquation *self) { return (((gpointer) ((guint8*) (self)
+ (glong) (MathEquation_private_offset)))); } GType math_equation_get_type
(void) { static gsize static_g_define_type_id = 0; if ((__extension__
({ _Static_assert (sizeof *(&static_g_define_type_id) ==
sizeof (gpointer), "Expression evaluates to false"); (void) (
0 ? (gpointer) *(&static_g_define_type_id) : ((void*)0));
(!(__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(*(&static_g_define_type_id)) gapg_temp_newval; __typeof__
((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id
); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5)
; gapg_temp_newval; })) && g_once_init_enter (&static_g_define_type_id
)); }))) { GType g_define_type_id = math_equation_get_type_once
(); (__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); 0 ?
(void) (*(&static_g_define_type_id) = (g_define_type_id)
) : (void) 0; g_once_init_leave ((&static_g_define_type_id
), (gsize) (g_define_type_id)); })); } return static_g_define_type_id
; } __attribute__ ((__noinline__)) static GType math_equation_get_type_once
(void) { GType g_define_type_id = g_type_register_static_simple
((ctk_text_buffer_get_type ()), g_intern_static_string ("MathEquation"
), sizeof (MathEquationClass), (GClassInitFunc)(void (*)(void
)) math_equation_class_intern_init, sizeof (MathEquation), (GInstanceInitFunc
)(void (*)(void)) math_equation_init, (GTypeFlags) 0); { {{ MathEquation_private_offset
= g_type_add_instance_private (g_define_type_id, sizeof (MathEquationPrivate
)); };} } return g_define_type_id; }
;
107
108
109MathEquation *
110math_equation_new()
111{
112 return g_object_new(math_equation_get_type(), NULL((void*)0));
113}
114
115
116MathVariables *
117math_equation_get_variables(MathEquation *equation)
118{
119 return equation->priv->variables;
120}
121
122
123static void
124get_ans_offsets(MathEquation *equation, gint *start, gint *end)
125{
126 CtkTextIter iter;
127
128 if (!equation->priv->ans_start) {
129 *start = *end = -1;
130 return;
131 }
132
133 ctk_text_buffer_get_iter_at_mark(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, &iter, equation->priv->ans_start);
134 *start = ctk_text_iter_get_offset(&iter);
135 ctk_text_buffer_get_iter_at_mark(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, &iter, equation->priv->ans_end);
136 *end = ctk_text_iter_get_offset(&iter);
137}
138
139
140static void
141reformat_ans(MathEquation *equation)
142{
143 if (!equation->priv->ans_start)
144 return;
145
146 gchar *orig_ans_text;
147 gchar *ans_text;
148 CtkTextIter ans_start, ans_end;
149
150 ctk_text_buffer_get_iter_at_mark(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, &ans_start, equation->priv->ans_start);
151 ctk_text_buffer_get_iter_at_mark(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, &ans_end, equation->priv->ans_end);
152 orig_ans_text = ctk_text_buffer_get_text(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, &ans_start, &ans_end, FALSE(0));
153 ans_text = mp_serializer_to_string(equation->priv->serializer, &equation->priv->state.ans);
154 if (strcmp(orig_ans_text, ans_text) != 0) {
155 gint start;
156
157 equation->priv->in_undo_operation = TRUE(!(0));
158 equation->priv->in_reformat = TRUE(!(0));
159
160 start = ctk_text_iter_get_offset(&ans_start);
161 ctk_text_buffer_delete(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, &ans_start, &ans_end);
162 ctk_text_buffer_insert_with_tags(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, &ans_end, ans_text, -1, equation->priv->ans_tag, NULL((void*)0));
163
164 /* There seems to be a bug in the marks as they alternate being the correct and incorrect ways. Reset them */
165 ctk_text_buffer_get_iter_at_offset(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, &ans_start, start);
166 ctk_text_buffer_move_mark(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, equation->priv->ans_start, &ans_start);
167 ctk_text_buffer_move_mark(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, equation->priv->ans_end, &ans_end);
168
169 equation->priv->in_reformat = FALSE(0);
170 equation->priv->in_undo_operation = FALSE(0);
171 }
172 ctk_text_buffer_get_iter_at_mark(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, &ans_start, equation->priv->ans_start);
173 ctk_text_buffer_get_iter_at_mark(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, &ans_end, equation->priv->ans_end);
174 g_free(orig_ans_text);
175 g_free(ans_text);
176}
177
178
179static gint
180count_digits(MathEquation *equation, const gchar *text)
181{
182 const gchar *read_iter;
183 gint count = 0;
184
185 read_iter = text;
186 while (*read_iter != '\0') {
187 if (!g_unichar_isdigit(g_utf8_get_char(read_iter)))
188 return count;
189
190 read_iter = g_utf8_next_char(read_iter)(char *)((read_iter) + g_utf8_skip[*(const guchar *)(read_iter
)])
;
191
192 /* Allow a thousands separator between digits follow a digit */
193 if (g_utf8_get_char(read_iter) == mp_serializer_get_thousands_separator(equation->priv->serializer)) {
194 read_iter = g_utf8_next_char(read_iter)(char *)((read_iter) + g_utf8_skip[*(const guchar *)(read_iter
)])
;
195 if (!g_unichar_isdigit(g_utf8_get_char(read_iter)))
196 return count;
197 }
198
199 count++;
200 }
201
202 return count;
203}
204
205
206static void
207reformat_separators(MathEquation *equation)
208{
209 gchar *text, *read_iter;
210 gint ans_start, ans_end;
211 gint offset, digit_offset = 0;
212 gboolean in_number = FALSE(0), in_radix = FALSE(0), last_is_tsep = FALSE(0);
213
214 equation->priv->in_undo_operation = TRUE(!(0));
215 equation->priv->in_reformat = TRUE(!(0));
216
217 text = math_equation_get_display(equation);
218 get_ans_offsets(equation, &ans_start, &ans_end);
219 for (read_iter = text, offset = 0; *read_iter != '\0'; read_iter = g_utf8_next_char(read_iter)(char *)((read_iter) + g_utf8_skip[*(const guchar *)(read_iter
)])
, offset++) {
220 gunichar c;
221 gboolean expect_tsep;
222
223 /* See what digit this character is */
224 c = g_utf8_get_char(read_iter);
225
226 expect_tsep = math_equation_get_base(equation) == 10 &&
227 mp_serializer_get_show_thousands_separators(equation->priv->serializer) &&
228 in_number && !in_radix && !last_is_tsep &&
229 digit_offset > 0 && digit_offset % mp_serializer_get_thousands_separator_count(equation->priv->serializer) == 0;
230 last_is_tsep = FALSE(0);
231
232 /* Don't mess with ans */
233 if (offset >= ans_start && offset <= ans_end) {
234 in_number = in_radix = FALSE(0);
235 continue;
236 }
237 if (g_unichar_isdigit(c)) {
238 if (!in_number)
239 digit_offset = count_digits(equation, read_iter);
240 in_number = TRUE(!(0));
241
242 /* Expected a thousands separator between these digits - insert it */
243 if (expect_tsep) {
244 CtkTextIter iter;
245 gchar buffer[7];
246 gint len;
247
248 ctk_text_buffer_get_iter_at_offset(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, &iter, offset);
249 len = g_unichar_to_utf8(mp_serializer_get_thousands_separator(equation->priv->serializer), buffer);
250 buffer[len] = '\0';
251 ctk_text_buffer_insert(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, &iter, buffer, -1);
252 offset++;
253 last_is_tsep = TRUE(!(0));
254 }
255
256 digit_offset--;
257 }
258 else if (c == mp_serializer_get_radix(equation->priv->serializer)) {
259 in_number = in_radix = TRUE(!(0));
260 }
261 else if (c == mp_serializer_get_thousands_separator(equation->priv->serializer)) {
262 /* Didn't expect thousands separator - delete it */
263 if (!expect_tsep && in_number) {
264 CtkTextIter start, end;
265 ctk_text_buffer_get_iter_at_offset(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, &start, offset);
266 ctk_text_buffer_get_iter_at_offset(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, &end, offset + 1);
267 ctk_text_buffer_delete(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, &start, &end);
268 offset--;
269 }
270 else
271 last_is_tsep = TRUE(!(0));
272 }
273 else {
274 in_number = in_radix = FALSE(0);
275 }
276 }
277
278 g_free(text);
279
280 equation->priv->in_reformat = FALSE(0);
281 equation->priv->in_undo_operation = FALSE(0);
282}
283
284
285static void
286reformat_display(MathEquation *equation)
287{
288 /* Change ans */
289 reformat_ans(equation);
290
291 /* Add/remove thousands separators */
292 reformat_separators(equation);
293}
294
295
296static MathEquationState *
297get_current_state(MathEquation *equation)
298{
299 MathEquationState *state;
300 gint ans_start = -1, ans_end = -1;
301
302 state = g_malloc0(sizeof(MathEquationState));
303
304 if (equation->priv->ans_start)
305 {
306 CtkTextIter iter;
307 ctk_text_buffer_get_iter_at_mark(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, &iter, equation->priv->ans_start);
308 ans_start = ctk_text_iter_get_offset(&iter);
309 ctk_text_buffer_get_iter_at_mark(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, &iter, equation->priv->ans_end);
310 ans_end = ctk_text_iter_get_offset(&iter);
311 }
312
313 mp_set_from_mp(&equation->priv->state.ans, &state->ans);
314 state->expression = math_equation_get_display(equation);
315 state->ans_start = ans_start;
316 state->ans_end = ans_end;
317 g_object_get(G_OBJECT(equation)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), (((GType) ((20) << (2))))))))
, "cursor-position", &state->cursor, NULL((void*)0));
318 state->number_mode = equation->priv->number_mode;
319 state->can_super_minus = equation->priv->can_super_minus;
320 state->entered_multiply = equation->priv->state.entered_multiply;
321 state->status = g_strdup(equation->priv->state.status);
322
323 return state;
324}
325
326
327static void
328free_state(MathEquationState *state)
329{
330 g_free(state->expression);
331 g_free(state->status);
332 g_free(state);
333}
334
335
336static void
337math_equation_push_undo_stack(MathEquation *equation)
338{
339 GList *link;
340 MathEquationState *state;
341
342 if (equation->priv->in_undo_operation)
343 return;
344
345 math_equation_set_status(equation, "");
346
347 /* Can't redo anymore */
348 for (link = equation->priv->redo_stack; link; link = link->next) {
349 state = link->data;
350 free_state(state);
351 }
352 g_list_free(equation->priv->redo_stack);
353 equation->priv->redo_stack = NULL((void*)0);
354
355 state = get_current_state(equation);
356 equation->priv->undo_stack = g_list_prepend(equation->priv->undo_stack, state);
357}
358
359
360static void
361clear_ans(MathEquation *equation, gboolean remove_tag)
362{
363 if (!equation->priv->ans_start)
364 return;
365
366 if (remove_tag) {
367 CtkTextIter start, end;
368
369 ctk_text_buffer_get_iter_at_mark(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, &start, equation->priv->ans_start);
370 ctk_text_buffer_get_iter_at_mark(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, &end, equation->priv->ans_end);
371 ctk_text_buffer_remove_tag(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, equation->priv->ans_tag, &start, &end);
372 }
373
374 ctk_text_buffer_delete_mark(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, equation->priv->ans_start);
375 ctk_text_buffer_delete_mark(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, equation->priv->ans_end);
376 equation->priv->ans_start = NULL((void*)0);
377 equation->priv->ans_end = NULL((void*)0);
378}
379
380
381static void
382apply_state(MathEquation *equation, MathEquationState *state)
383{
384 CtkTextIter cursor;
385
386 /* Disable undo detection */
387 equation->priv->in_undo_operation = TRUE(!(0));
388
389 mp_set_from_mp(&state->ans, &equation->priv->state.ans);
390
391 ctk_text_buffer_set_text(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, state->expression, -1);
392 ctk_text_buffer_get_iter_at_offset(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, &cursor, state->cursor);
393 ctk_text_buffer_place_cursor(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, &cursor);
394 clear_ans(equation, FALSE(0));
395 if (state->ans_start >= 0) {
396 CtkTextIter start, end;
397
398 ctk_text_buffer_get_iter_at_offset(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, &start, state->ans_start);
399 equation->priv->ans_start = ctk_text_buffer_create_mark(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, NULL((void*)0), &start, FALSE(0));
400 ctk_text_buffer_get_iter_at_offset(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, &end, state->ans_end);
401 equation->priv->ans_end = ctk_text_buffer_create_mark(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, NULL((void*)0), &end, TRUE(!(0)));
402 ctk_text_buffer_apply_tag(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, equation->priv->ans_tag, &start, &end);
403 }
404
405 math_equation_set_number_mode(equation, state->number_mode);
406 equation->priv->can_super_minus = state->can_super_minus;
407 equation->priv->state.entered_multiply = state->entered_multiply;
408 math_equation_set_status(equation, state->status);
409
410 equation->priv->in_undo_operation = FALSE(0);
411}
412
413
414void
415math_equation_copy(MathEquation *equation)
416{
417 CtkTextIter start, end;
418 gchar *text;
419
420 g_return_if_fail(equation != NULL)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return; } } while (0)
;
421
422 if (!ctk_text_buffer_get_selection_bounds(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, &start, &end))
423 ctk_text_buffer_get_bounds(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, &start, &end);
424
425 text = ctk_text_buffer_get_text(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, &start, &end, FALSE(0));
426 ctk_clipboard_set_text(ctk_clipboard_get(CDK_NONE((CdkAtom)((gpointer) (gulong) (0)))), g_str_to_ascii (text, "C"), -1);
427 g_free(text);
428}
429
430
431static void
432on_paste(CtkClipboard *clipboard, const gchar *text, gpointer data)
433{
434 MathEquation *equation = data;
435 if (text != NULL((void*)0))
436 math_equation_insert(equation, text);
437}
438
439
440void
441math_equation_paste(MathEquation *equation)
442{
443 g_return_if_fail(equation != NULL)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return; } } while (0)
;
444 ctk_clipboard_request_text(ctk_clipboard_get(CDK_NONE((CdkAtom)((gpointer) (gulong) (0)))), on_paste, equation);
445}
446
447
448void
449math_equation_undo(MathEquation *equation)
450{
451 GList *link;
452 MathEquationState *state;
453
454 g_return_if_fail(equation != NULL)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return; } } while (0)
;
455
456 if (!equation->priv->undo_stack) {
457 math_equation_set_status(equation,
458 /* Error shown when trying to undo with no undo history */
459 _("No undo history")gettext ("No undo history"));
460 return;
461 }
462
463 link = equation->priv->undo_stack;
464 equation->priv->undo_stack = g_list_remove_link(equation->priv->undo_stack, link);
465 state = link->data;
466 g_list_free(link);
467
468 equation->priv->redo_stack = g_list_prepend(equation->priv->redo_stack, get_current_state(equation));
469
470 apply_state(equation, state);
471 free_state(state);
472}
473
474
475void
476math_equation_redo(MathEquation *equation)
477{
478 GList *link;
479 MathEquationState *state;
480
481 g_return_if_fail(equation != NULL)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return; } } while (0)
;
482
483 if (!equation->priv->redo_stack) {
484 math_equation_set_status(equation,
485 /* Error shown when trying to redo with no redo history */
486 _("No redo history")gettext ("No redo history"));
487 return;
488 }
489
490 link = equation->priv->redo_stack;
491 equation->priv->redo_stack = g_list_remove_link(equation->priv->redo_stack, link);
492 state = link->data;
493 g_list_free(link);
494
495 equation->priv->undo_stack = g_list_prepend(equation->priv->undo_stack, get_current_state(equation));
496
497 apply_state(equation, state);
498 free_state(state);
499}
500
501
502gunichar
503math_equation_get_digit_text(MathEquation *equation, guint digit)
504{
505 g_return_val_if_fail(equation != NULL, '?')do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return ('?'); } } while (0)
;
506 g_return_val_if_fail(digit < 16, '?')do { if ((digit < 16)) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "digit < 16");
return ('?'); } } while (0)
;
507
508 return equation->priv->digits[digit];
509}
510
511
512void
513math_equation_set_accuracy(MathEquation *equation, gint accuracy)
514{
515 g_return_if_fail(equation != NULL)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return; } } while (0)
;
516
517 if (mp_serializer_get_trailing_digits(equation->priv->serializer) == accuracy)
518 return;
519 mp_serializer_set_trailing_digits(equation->priv->serializer, accuracy);
520 reformat_display(equation);
521 g_object_notify(G_OBJECT(equation)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), (((GType) ((20) << (2))))))))
, "accuracy");
522}
523
524
525gint
526math_equation_get_accuracy(MathEquation *equation)
527{
528 g_return_val_if_fail(equation != NULL, 0)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return (0); } } while (0)
;
529
530 return mp_serializer_get_trailing_digits(equation->priv->serializer);
531}
532
533
534void
535math_equation_set_show_thousands_separators(MathEquation *equation, gboolean visible)
536{
537 g_return_if_fail(equation != NULL)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return; } } while (0)
;
538
539 if (mp_serializer_get_show_thousands_separators(equation->priv->serializer) == visible)
540 return;
541
542 mp_serializer_set_show_thousands_separators(equation->priv->serializer, visible);
543 reformat_display(equation);
544 g_object_notify(G_OBJECT(equation)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), (((GType) ((20) << (2))))))))
, "show-thousands-separators");
545}
546
547
548gboolean
549math_equation_get_show_thousands_separators(MathEquation *equation)
550{
551 g_return_val_if_fail(equation != NULL, FALSE)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return ((0)); } } while (0)
;
552 return mp_serializer_get_show_thousands_separators(equation->priv->serializer);
553}
554
555
556void
557math_equation_set_show_trailing_zeroes(MathEquation *equation, gboolean visible)
558{
559 g_return_if_fail(equation != NULL)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return; } } while (0)
;
560
561 if (mp_serializer_get_show_trailing_zeroes(equation->priv->serializer) == visible)
562 return;
563
564 mp_serializer_set_show_trailing_zeroes(equation->priv->serializer, visible);
565 reformat_display(equation);
566 g_object_notify(G_OBJECT(equation)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), (((GType) ((20) << (2))))))))
, "show-trailing-zeroes");
567}
568
569
570gboolean
571math_equation_get_show_trailing_zeroes(MathEquation *equation)
572{
573 g_return_val_if_fail(equation != NULL, FALSE)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return ((0)); } } while (0)
;
574 return mp_serializer_get_show_trailing_zeroes(equation->priv->serializer);
575}
576
577
578void
579math_equation_set_number_format(MathEquation *equation, MpDisplayFormat format)
580{
581 g_return_if_fail(equation != NULL)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return; } } while (0)
;
582
583 if (mp_serializer_get_number_format(equation->priv->serializer) == format)
584 return;
585
586 mp_serializer_set_number_format(equation->priv->serializer, format);
587 reformat_display(equation);
588 g_object_notify(G_OBJECT(equation)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), (((GType) ((20) << (2))))))))
, "number-format");
589}
590
591
592MpDisplayFormat
593math_equation_get_number_format(MathEquation *equation)
594{
595 g_return_val_if_fail(equation != NULL, MP_DISPLAY_FORMAT_AUTOMATIC)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return (MP_DISPLAY_FORMAT_AUTOMATIC); } } while (0)
;
596 return mp_serializer_get_number_format(equation->priv->serializer);
597}
598
599
600void
601math_equation_set_base(MathEquation *equation, gint base)
602{
603 g_return_if_fail(equation != NULL)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return; } } while (0)
;
604
605 if (mp_serializer_get_base(equation->priv->serializer) == base)
606 return;
607
608 mp_serializer_set_base(equation->priv->serializer, base);
609 reformat_display(equation);
610 g_object_notify(G_OBJECT(equation)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), (((GType) ((20) << (2))))))))
, "base");
611}
612
613
614gint
615math_equation_get_base(MathEquation *equation)
616{
617 g_return_val_if_fail(equation != NULL, 10)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return (10); } } while (0)
;
618 return mp_serializer_get_base(equation->priv->serializer);
619}
620
621
622void
623math_equation_set_word_size(MathEquation *equation, gint word_size)
624{
625 g_return_if_fail(equation != NULL)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return; } } while (0)
;
626
627 if (equation->priv->word_size == word_size)
628 return;
629
630 equation->priv->word_size = word_size;
631 g_object_notify(G_OBJECT(equation)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), (((GType) ((20) << (2))))))))
, "word-size");
632}
633
634
635gint
636math_equation_get_word_size(MathEquation *equation)
637{
638 g_return_val_if_fail(equation != NULL, 64)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return (64); } } while (0)
;
639 return equation->priv->word_size;
640}
641
642
643void
644math_equation_set_angle_units(MathEquation *equation, MPAngleUnit angle_units)
645{
646 g_return_if_fail(equation != NULL)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return; } } while (0)
;
647
648 if (equation->priv->angle_units == angle_units)
649 return;
650
651 equation->priv->angle_units = angle_units;
652 g_object_notify(G_OBJECT(equation)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), (((GType) ((20) << (2))))))))
, "angle-units");
653}
654
655
656MPAngleUnit
657math_equation_get_angle_units(MathEquation *equation)
658{
659 g_return_val_if_fail(equation != NULL, MP_DEGREES)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return (MP_DEGREES); } } while (0)
;
660 return equation->priv->angle_units;
661}
662
663
664void
665math_equation_set_source_currency(MathEquation *equation, const gchar *currency)
666{
667 g_return_if_fail(equation != NULL)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return; } } while (0)
;
668 g_return_if_fail(currency != NULL)do { if ((currency != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "currency != NULL"
); return; } } while (0)
;
669
670 if (strcmp(equation->priv->source_currency, currency) == 0)
671 return;
672 g_free(equation->priv->source_currency);
673 equation->priv->source_currency = g_strdup(currency);
674 g_settings_set_string(g_settings_var, "source-currency",
675 math_equation_get_source_currency(equation));
676}
677
678
679const gchar *
680math_equation_get_source_currency(MathEquation *equation)
681{
682 g_return_val_if_fail(equation != NULL, NULL)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return (((void*)0)); } } while (0)
;
683 return equation->priv->source_currency;
684}
685
686
687void
688math_equation_set_target_currency(MathEquation *equation, const gchar *currency)
689{
690 g_return_if_fail(equation != NULL)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return; } } while (0)
;
691 g_return_if_fail(currency != NULL)do { if ((currency != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "currency != NULL"
); return; } } while (0)
;
692
693 if (strcmp(equation->priv->target_currency, currency) == 0)
694 return;
695 g_free(equation->priv->target_currency);
696 equation->priv->target_currency = g_strdup(currency);
697 g_settings_set_string(g_settings_var, "target-currency",
698 math_equation_get_target_currency(equation));
699}
700
701
702const gchar *
703math_equation_get_target_currency(MathEquation *equation)
704{
705 g_return_val_if_fail(equation != NULL, NULL)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return (((void*)0)); } } while (0)
;
706 return equation->priv->target_currency;
707}
708
709
710void
711math_equation_set_source_units(MathEquation *equation, const gchar *units)
712{
713 g_return_if_fail(equation != NULL)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return; } } while (0)
;
714 g_return_if_fail(units != NULL)do { if ((units != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "units != NULL");
return; } } while (0)
;
715
716 if (strcmp(equation->priv->source_units, units) == 0)
717 return;
718
719 g_free(equation->priv->source_units);
720 equation->priv->source_units = g_strdup(units);
721 g_settings_set_string(g_settings_var, "source-units",
722 math_equation_get_source_units(equation));
723}
724
725const gchar *
726math_equation_get_source_units(MathEquation *equation)
727{
728 g_return_val_if_fail(equation != NULL, NULL)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return (((void*)0)); } } while (0)
;
729 return equation->priv->source_units;
730}
731
732
733void
734math_equation_set_target_units(MathEquation *equation, const gchar *units)
735{
736 g_return_if_fail(equation != NULL)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return; } } while (0)
;
737 g_return_if_fail(units != NULL)do { if ((units != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "units != NULL");
return; } } while (0)
;
738
739 if (strcmp(equation->priv->target_units, units) == 0)
740 return;
741
742 g_free(equation->priv->target_units);
743 equation->priv->target_units = g_strdup(units);
744 g_settings_set_string(g_settings_var, "target-units",
745 math_equation_get_target_units(equation));
746}
747
748
749const gchar *
750math_equation_get_target_units(MathEquation *equation)
751{
752 g_return_val_if_fail(equation != NULL, NULL)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return (((void*)0)); } } while (0)
;
753 return equation->priv->target_units;
754}
755
756
757void
758math_equation_set_status(MathEquation *equation, const gchar *status)
759{
760 g_return_if_fail(equation != NULL)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return; } } while (0)
;
761 g_return_if_fail(status != NULL)do { if ((status != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "status != NULL")
; return; } } while (0)
;
762
763 if (strcmp(equation->priv->state.status, status) == 0)
764 return;
765
766 g_free(equation->priv->state.status);
767 equation->priv->state.status = g_strdup(status);
768 g_object_notify(G_OBJECT(equation)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), (((GType) ((20) << (2))))))))
, "status");
769}
770
771
772const gchar *
773math_equation_get_status(MathEquation *equation)
774{
775 g_return_val_if_fail(equation != NULL, NULL)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return (((void*)0)); } } while (0)
;
776 return equation->priv->state.status;
777}
778
779
780gboolean
781math_equation_is_empty(MathEquation *equation)
782{
783 g_return_val_if_fail(equation != NULL, FALSE)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return ((0)); } } while (0)
;
784 return ctk_text_buffer_get_char_count(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
) == 0;
785}
786
787
788gboolean
789math_equation_is_result(MathEquation *equation)
790{
791 char *text;
792 gboolean result;
793
794 g_return_val_if_fail(equation != NULL, FALSE)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return ((0)); } } while (0)
;
795
796 text = math_equation_get_equation(equation);
797 result = strcmp(text, "ans") == 0;
798 g_free(text);
799
800 return result;
801}
802
803
804gchar *
805math_equation_get_display(MathEquation *equation)
806{
807 CtkTextIter start, end;
808
809 g_return_val_if_fail(equation != NULL, NULL)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return (((void*)0)); } } while (0)
;
810
811 ctk_text_buffer_get_bounds(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, &start, &end);
812 return ctk_text_buffer_get_text(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, &start, &end, FALSE(0));
813}
814
815
816gchar *
817math_equation_get_equation(MathEquation *equation)
818{
819 gchar *text;
820 GString *eq_text;
821 gint ans_start = -1, ans_end = -1, offset;
822 const gchar *read_iter;
823 gboolean last_is_digit = FALSE(0);
824
825 g_return_val_if_fail(equation != NULL, NULL)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return (((void*)0)); } } while (0)
;
826
827 text = math_equation_get_display(equation);
828 eq_text = g_string_sized_new(strlen(text));
829
830 if (equation->priv->ans_start)
831 get_ans_offsets(equation, &ans_start, &ans_end);
832
833 for (read_iter = text, offset = 0; *read_iter != '\0'; read_iter = g_utf8_next_char(read_iter)(char *)((read_iter) + g_utf8_skip[*(const guchar *)(read_iter
)])
, offset++) {
834 gunichar c;
835 gboolean is_digit, next_is_digit;
836
837 c = g_utf8_get_char(read_iter);
838 is_digit = g_unichar_isdigit(c);
839 next_is_digit = g_unichar_isdigit(g_utf8_get_char(g_utf8_next_char(read_iter)(char *)((read_iter) + g_utf8_skip[*(const guchar *)(read_iter
)])
));
840
841 /* Replace ans text with variable */
842 if (offset == ans_start) {
843 g_string_append(eq_text, "ans");
844 read_iter = g_utf8_offset_to_pointer(read_iter, ans_end - ans_start - 1);
845 offset += ans_end - ans_start - 1;
846 is_digit = FALSE(0);
Value stored to 'is_digit' is never read
847 continue;
848 }
849
850 /* Ignore thousands separators */
851 if (c == mp_serializer_get_thousands_separator(equation->priv->serializer) && last_is_digit && next_is_digit)
852 ;
853 /* Substitute radix character */
854 else if (c == mp_serializer_get_radix(equation->priv->serializer) && (last_is_digit || next_is_digit))
855 g_string_append_unichar(eq_text, '.');
856 else
857 g_string_append_unichar(eq_text, c);
858
859 last_is_digit = is_digit;
860 }
861 g_free(text);
862
863 text = eq_text->str;
864 g_string_free(eq_text, FALSE(0));
865
866 return text;
867}
868
869
870gboolean
871math_equation_get_number(MathEquation *equation, MPNumber *z)
872{
873 gchar *text;
874 gboolean result;
875
876 g_return_val_if_fail(equation != NULL, FALSE)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return ((0)); } } while (0)
;
877 g_return_val_if_fail(z != NULL, FALSE)do { if ((z != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "z != NULL"); return
((0)); } } while (0)
;
878
879 if (math_equation_is_result(equation)) {
880 mp_set_from_mp(math_equation_get_answer(equation), z);
881 return TRUE(!(0));
882 }
883 else {
884 text = math_equation_get_equation(equation);
885 result = !mp_serializer_from_string(equation->priv->serializer, text, z);
886 g_free(text);
887 return result;
888 }
889}
890
891
892MpSerializer *
893math_equation_get_serializer(MathEquation *equation)
894{
895 g_return_val_if_fail(equation != NULL, NULL)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return (((void*)0)); } } while (0)
;
896 return equation->priv->serializer;
897}
898
899
900void
901math_equation_set_number_mode(MathEquation *equation, NumberMode mode)
902{
903 g_return_if_fail(equation != NULL)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return; } } while (0)
;
904
905 if (equation->priv->number_mode == mode)
906 return;
907
908 equation->priv->can_super_minus = mode == SUPERSCRIPT;
909
910 equation->priv->number_mode = mode;
911 g_object_notify(G_OBJECT(equation)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), (((GType) ((20) << (2))))))))
, "number-mode");
912}
913
914
915NumberMode
916math_equation_get_number_mode(MathEquation *equation)
917{
918 g_return_val_if_fail(equation != NULL, NORMAL)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return (NORMAL); } } while (0)
;
919 return equation->priv->number_mode;
920}
921
922
923gboolean
924math_equation_in_solve(MathEquation *equation)
925{
926 g_return_val_if_fail(equation != NULL, FALSE)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return ((0)); } } while (0)
;
927 return equation->priv->in_solve;
928}
929
930
931const MPNumber *
932math_equation_get_answer(MathEquation *equation)
933{
934 g_return_val_if_fail(equation != NULL, FALSE)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return ((0)); } } while (0)
;
935 return &equation->priv->state.ans;
936}
937
938
939void
940math_equation_store(MathEquation *equation, const gchar *name)
941{
942 MPNumber t;
943
944 g_return_if_fail(equation != NULL)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return; } } while (0)
;
945 g_return_if_fail(name != NULL)do { if ((name != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "name != NULL"); return
; } } while (0)
;
946
947 if (!math_equation_get_number(equation, &t))
948 math_equation_set_status(equation, _("No sane value to store")gettext ("No sane value to store"));
949 else
950 math_variables_set(equation->priv->variables, name, &t);
951}
952
953
954void
955math_equation_recall(MathEquation *equation, const gchar *name)
956{
957 g_return_if_fail(equation != NULL)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return; } } while (0)
;
958 g_return_if_fail(name != NULL)do { if ((name != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "name != NULL"); return
; } } while (0)
;
959 math_equation_insert(equation, name);
960}
961
962
963void
964math_equation_set(MathEquation *equation, const gchar *text)
965{
966 g_return_if_fail(equation != NULL)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return; } } while (0)
;
967 g_return_if_fail(text != NULL)do { if ((text != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "text != NULL"); return
; } } while (0)
;
968 ctk_text_buffer_set_text(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, text, -1);
969 clear_ans(equation, FALSE(0));
970}
971
972
973void
974math_equation_set_number(MathEquation *equation, const MPNumber *x)
975{
976 char *text;
977 CtkTextIter start, end;
978
979 g_return_if_fail(equation != NULL)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return; } } while (0)
;
980 g_return_if_fail(x != NULL)do { if ((x != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "x != NULL"); return
; } } while (0)
;
981
982 /* Show the number in the user chosen format */
983 text = mp_serializer_to_string(equation->priv->serializer, x);
984 ctk_text_buffer_set_text(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, text, -1);
985 mp_set_from_mp(x, &equation->priv->state.ans);
986
987 /* Mark this text as the answer variable */
988 ctk_text_buffer_get_bounds(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, &start, &end);
989 clear_ans(equation, FALSE(0));
990 equation->priv->ans_start = ctk_text_buffer_create_mark(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, NULL((void*)0), &start, FALSE(0));
991 equation->priv->ans_end = ctk_text_buffer_create_mark(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, NULL((void*)0), &end, TRUE(!(0)));
992 ctk_text_buffer_apply_tag(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, equation->priv->ans_tag, &start, &end);
993 g_free(text);
994}
995
996
997void
998math_equation_insert(MathEquation *equation, const gchar *text)
999{
1000 g_return_if_fail(equation != NULL)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return; } } while (0)
;
1001 g_return_if_fail(text != NULL)do { if ((text != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "text != NULL"); return
; } } while (0)
;
1002
1003 /* Replace ** with ^ (not on all keyboards) */
1004 if (!ctk_text_buffer_get_has_selection(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
) &&
1005 strcmp(text, "×") == 0 && equation->priv->state.entered_multiply) {
1006 CtkTextIter iter;
1007
1008 ctk_text_buffer_get_iter_at_mark(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, &iter, ctk_text_buffer_get_insert(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
));
1009 ctk_text_buffer_backspace(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, &iter, TRUE(!(0)), TRUE(!(0)));
1010 ctk_text_buffer_insert_at_cursor(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, "^", -1);
1011 return;
1012 }
1013
1014 /* Can't enter superscript minus after entering digits */
1015 if (strstr("⁰¹²³⁴⁵⁶⁷⁸⁹", text) != NULL((void*)0) || strcmp("⁻", text) == 0)
1016 equation->priv->can_super_minus = FALSE(0);
1017
1018 /* Disable super/subscript mode when finished entering */
1019 if (strstr("⁻⁰¹²³⁴⁵⁶⁷⁸⁹₀₁₂₃₄₅₆₇₈₉", text) == NULL((void*)0))
1020 math_equation_set_number_mode(equation, NORMAL);
1021
1022 ctk_text_buffer_delete_selection(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, FALSE(0), FALSE(0));
1023 ctk_text_buffer_insert_at_cursor(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, text, -1);
1024}
1025
1026
1027void
1028math_equation_insert_digit(MathEquation *equation, guint digit)
1029{
1030 static const char *subscript_digits[] = {"₀", "₁", "₂", "₃", "₄", "₅", "₆", "₇", "₈", "₉", NULL((void*)0)};
1031 static const char *superscript_digits[] = {"⁰", "¹", "²", "³", "⁴", "⁵", "⁶", "⁷", "⁸", "⁹", NULL((void*)0)};
1032
1033 g_return_if_fail(equation != NULL)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return; } } while (0)
;
1034 g_return_if_fail(digit < 16)do { if ((digit < 16)) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "digit < 16");
return; } } while (0)
;
1035
1036 if (equation->priv->number_mode == NORMAL || digit >= 10) {
1037 gchar buffer[7];
1038 gint len;
1039 len = g_unichar_to_utf8(math_equation_get_digit_text(equation, digit), buffer);
1040 buffer[len] = '\0';
1041 math_equation_insert(equation, buffer);
1042 }
1043 else if (equation->priv->number_mode == SUPERSCRIPT)
1044 math_equation_insert(equation, superscript_digits[digit]);
1045 else if (equation->priv->number_mode == SUBSCRIPT)
1046 math_equation_insert(equation, subscript_digits[digit]);
1047}
1048
1049
1050void
1051math_equation_insert_numeric_point(MathEquation *equation)
1052{
1053 gchar buffer[7];
1054 gint len;
1055
1056 g_return_if_fail(equation != NULL)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return; } } while (0)
;
1057
1058 len = g_unichar_to_utf8(mp_serializer_get_radix(equation->priv->serializer), buffer);
1059 buffer[len] = '\0';
1060 math_equation_insert(equation, buffer);
1061}
1062
1063
1064void
1065math_equation_insert_number(MathEquation *equation, const MPNumber *x)
1066{
1067 char *text;
1068
1069 g_return_if_fail(equation != NULL)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return; } } while (0)
;
1070 g_return_if_fail(x != NULL)do { if ((x != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "x != NULL"); return
; } } while (0)
;
1071
1072 text = mp_serializer_to_string(equation->priv->serializer, x);
1073 math_equation_insert(equation, text);
1074 g_free(text);
1075}
1076
1077
1078void
1079math_equation_insert_exponent(MathEquation *equation)
1080{
1081 g_return_if_fail(equation != NULL)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return; } } while (0)
;
1082 math_equation_insert(equation, "×10");
1083 math_equation_set_number_mode(equation, SUPERSCRIPT);
1084}
1085
1086
1087void
1088math_equation_insert_subtract(MathEquation *equation)
1089{
1090 g_return_if_fail(equation != NULL)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return; } } while (0)
;
1091 if (equation->priv->number_mode == SUPERSCRIPT && equation->priv->can_super_minus) {
1092 math_equation_insert(equation, "⁻");
1093 equation->priv->can_super_minus = FALSE(0);
1094 }
1095 else {
1096 math_equation_insert(equation, "−");
1097 math_equation_set_number_mode(equation, NORMAL);
1098 }
1099}
1100
1101
1102static int
1103variable_is_defined(const char *name, void *data)
1104{
1105 MathEquation *equation = data;
1106 char *c, *lower_name;
1107
1108 lower_name = strdup(name);
1109 for (c = lower_name; *c; c++)
1110 *c = tolower(*c);
1111
1112 if (strcmp(lower_name, "rand") == 0 ||
1113 strcmp(lower_name, "ans") == 0) {
1114 g_free(lower_name);
1115 return 1;
1116 }
1117 g_free(lower_name);
1118
1119 return math_variables_get(equation->priv->variables, name) != NULL((void*)0);
1120}
1121
1122
1123static int
1124get_variable(const char *name, MPNumber *z, void *data)
1125{
1126 char *c, *lower_name;
1127 int result = 1;
1128 MathEquation *equation = data;
1129 MPNumber *t;
1130
1131 lower_name = strdup(name);
1132 for (c = lower_name; *c; c++)
1133 *c = tolower(*c);
1134
1135 if (strcmp(lower_name, "rand") == 0)
1136 mp_set_from_random(z);
1137 else if (strcmp(lower_name, "ans") == 0)
1138 mp_set_from_mp(&equation->priv->state.ans, z);
1139 else {
1140 t = math_variables_get(equation->priv->variables, name);
1141 if (t)
1142 mp_set_from_mp(t, z);
1143 else
1144 result = 0;
1145 }
1146
1147 free(lower_name);
1148
1149 return result;
1150}
1151
1152
1153static void
1154set_variable(const char *name, const MPNumber *x, void *data)
1155{
1156 MathEquation *equation = data;
1157 /* FIXME: Don't allow writing to built-in variables, e.g. ans, rand, sin, ... */
1158 math_variables_set(equation->priv->variables, name, x);
1159}
1160
1161
1162static int
1163convert(const MPNumber *x, const char *x_units, const char *z_units, MPNumber *z, void *data)
1164{
1165 return unit_manager_convert_by_symbol(unit_manager_get_default(), x, x_units, z_units, z);
1166}
1167
1168
1169static int
1170parse(MathEquation *equation, const char *text, MPNumber *z, char **error_token)
1171{
1172 MPEquationOptions options;
1173
1174 memset(&options, 0, sizeof(options));
1175 options.base = mp_serializer_get_base(equation->priv->serializer);
1176 options.wordlen = equation->priv->word_size;
1177 options.angle_units = equation->priv->angle_units;
1178 options.variable_is_defined = variable_is_defined;
1179 options.get_variable = get_variable;
1180 options.set_variable = set_variable;
1181 options.convert = convert;
1182 options.callback_data = equation;
1183
1184 return mp_equation_parse(text, &options, z, error_token);
1185}
1186
1187
1188/*
1189 * Executed in separate thread. It is thus not a good idea to write to anything
1190 * in MathEquation but the async queue from here.
1191 */
1192static gpointer
1193math_equation_solve_real(gpointer data)
1194{
1195 MathEquation *equation = MATH_EQUATION(data)((((MathEquation*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), (math_equation_get_type())))))
;
1196 SolveData *solvedata = g_slice_new0(SolveData)((SolveData*) g_slice_alloc0 (sizeof (SolveData)));
1197
1198 gint n_brackets = 0, result;
1199 gchar *c, *text, *error_token;
1200 GString *equation_text;
1201 MPNumber z;
1202
1203 text = math_equation_get_equation(equation);
1204 equation_text = g_string_new(text);
1205 g_free(text);
1206 /* Count the number of brackets and automatically add missing closing brackets */
1207 for (c = equation_text->str; *c; c++) {
1208 if (*c == '(')
1209 n_brackets++;
1210 else if (*c == ')')
1211 n_brackets--;
1212 }
1213 while (n_brackets > 0) {
1214 g_string_append_c(equation_text, ')')g_string_append_c_inline (equation_text, ')');
1215 n_brackets--;
1216 }
1217
1218
1219 result = parse(equation, equation_text->str, &z, &error_token);
1220 g_string_free(equation_text, TRUE(!(0)));
1221
1222 switch (result) {
1223 case PARSER_ERR_NONE:
1224 solvedata->number_result = g_slice_new(MPNumber)((MPNumber*) g_slice_alloc (sizeof (MPNumber)));
1225 mp_set_from_mp(&z, solvedata->number_result);
1226 break;
1227
1228 case PARSER_ERR_OVERFLOW:
1229 solvedata->error = g_strdup(/* Error displayed to user when they perform a bitwise operation on numbers greater than the current word */
1230 _("Overflow. Try a bigger word size")gettext ("Overflow. Try a bigger word size"));
1231 break;
1232
1233 case PARSER_ERR_UNKNOWN_VARIABLE:
1234 solvedata->error = g_strdup_printf(/* Error displayed to user when they an unknown variable is entered */
1235 _("Unknown variable '%s'")gettext ("Unknown variable '%s'"), error_token);
1236 break;
1237
1238 case PARSER_ERR_UNKNOWN_FUNCTION:
1239 solvedata->error = g_strdup_printf(/* Error displayed to user when an unknown function is entered */
1240 _("Function '%s' is not defined")gettext ("Function '%s' is not defined"), error_token);
1241 break;
1242
1243 case PARSER_ERR_UNKNOWN_CONVERSION:
1244 solvedata->error = g_strdup(/* Error displayed to user when an conversion with unknown units is attempted */
1245 _("Unknown conversion")gettext ("Unknown conversion"));
1246 break;
1247
1248 case PARSER_ERR_MP:
1249 if (mp_get_error())
1250 solvedata->error = g_strdup(mp_get_error());
1251 else if (error_token)
1252 solvedata->error = g_strdup_printf(/* Uncategorized error. Show error token to user*/
1253 _("Malformed expression at token '%s'")gettext ("Malformed expression at token '%s'"), error_token);
1254 else
1255 solvedata->error = g_strdup (/* Unknown error. */
1256 _("Malformed expression")gettext ("Malformed expression"));
1257 break;
1258
1259 default:
1260 solvedata->error = g_strdup(/* Error displayed to user when they enter an invalid calculation */
1261 _("Malformed expression")gettext ("Malformed expression"));
1262 break;
1263 }
1264 g_async_queue_push(equation->priv->queue, solvedata);
1265
1266 return NULL((void*)0);
1267}
1268
1269
1270static gboolean
1271math_equation_show_in_progress(gpointer data)
1272{
1273 MathEquation *equation = MATH_EQUATION(data)((((MathEquation*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), (math_equation_get_type())))))
;
1274 if (equation->priv->in_solve)
1275 math_equation_set_status(equation, _("Calculating")gettext ("Calculating"));
1276 return false0;
1277}
1278
1279
1280static gboolean
1281math_equation_look_for_answer(gpointer data)
1282{
1283 MathEquation *equation = MATH_EQUATION(data)((((MathEquation*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), (math_equation_get_type())))))
;
1284 SolveData *result = g_async_queue_try_pop(equation->priv->queue);
1285
1286 if (result == NULL((void*)0))
1287 return true1;
1288
1289 equation->priv->in_solve = false0;
1290
1291 if (!result->error)
1292 math_equation_set_status(equation, "");
1293
1294 if (result->error != NULL((void*)0)) {
1295 math_equation_set_status(equation, result->error);
1296 g_free(result->error);
1297 }
1298 else if (result->number_result != NULL((void*)0)) {
1299 math_equation_set_number(equation, result->number_result);
1300 g_slice_free(MPNumber, result->number_result)do { if (1) g_slice_free1 (sizeof (MPNumber), (result->number_result
)); else (void) ((MPNumber*) 0 == (result->number_result))
; } while (0)
;
1301 }
1302 else if (result->text_result != NULL((void*)0)) {
1303 math_equation_set(equation, result->text_result);
1304 g_free(result->text_result);
1305 }
1306 g_slice_free(SolveData, result)do { if (1) g_slice_free1 (sizeof (SolveData), (result)); else
(void) ((SolveData*) 0 == (result)); } while (0)
;
1307
1308 return false0;
1309}
1310
1311
1312void
1313math_equation_solve(MathEquation *equation)
1314{
1315 g_return_if_fail(equation != NULL)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return; } } while (0)
;
1316
1317 // FIXME: should replace calculation or give error message
1318 if (equation->priv->in_solve)
1319 return;
1320
1321 if (math_equation_is_empty(equation))
1322 return;
1323
1324 /* If showing a result return to the equation that caused it */
1325 // FIXME: Result may not be here due to solve (i.e. the user may have entered "ans")
1326 if (math_equation_is_result(equation)) {
1327 math_equation_undo(equation);
1328 return;
1329 }
1330
1331 equation->priv->in_solve = true1;
1332
1333 math_equation_set_number_mode(equation, NORMAL);
1334 g_thread_new("", math_equation_solve_real, equation);
1335
1336 g_timeout_add(50, math_equation_look_for_answer, equation);
1337 g_timeout_add(100, math_equation_show_in_progress, equation);
1338}
1339
1340
1341static gpointer
1342math_equation_factorize_real(gpointer data)
1343{
1344 GString *text;
1345 GList *factors, *factor;
1346 MPNumber x;
1347 MathEquation *equation = MATH_EQUATION(data)((((MathEquation*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), (math_equation_get_type())))))
;
1348 SolveData *result = g_slice_new0(SolveData)((SolveData*) g_slice_alloc0 (sizeof (SolveData)));
1349
1350 math_equation_get_number(equation, &x);
1351 factors = mp_factorize(&x);
1352
1353 text = g_string_new("");
1354
1355 for (factor = factors; factor; factor = factor->next) {
1356 gchar *temp;
1357 MPNumber *n;
1358
1359 n = factor->data;
1360 temp = mp_serializer_to_string(equation->priv->serializer, n);
1361 g_string_append(text, temp);
1362 if (factor->next)
1363 g_string_append(text, "×");
1364 g_slice_free(MPNumber, n)do { if (1) g_slice_free1 (sizeof (MPNumber), (n)); else (void
) ((MPNumber*) 0 == (n)); } while (0)
;
1365 g_free(temp);
1366 }
1367 g_list_free(factors);
1368
1369 result->text_result = g_strndup(text->str, text->len);
1370 g_async_queue_push(equation->priv->queue, result);
1371 g_string_free(text, TRUE(!(0)));
1372
1373 return NULL((void*)0);
1374}
1375
1376
1377void
1378math_equation_factorize(MathEquation *equation)
1379{
1380 MPNumber x;
1381
1382 g_return_if_fail(equation != NULL)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return; } } while (0)
;
1383
1384 // FIXME: should replace calculation or give error message
1385 if (equation->priv->in_solve)
1386 return;
1387
1388 if (!math_equation_get_number(equation, &x) || !mp_is_integer(&x)) {
1389 /* Error displayed when trying to factorize a non-integer value */
1390 math_equation_set_status(equation, _("Need an integer to factorize")gettext ("Need an integer to factorize"));
1391 return;
1392 }
1393
1394 equation->priv->in_solve = true1;
1395
1396 g_thread_new("", math_equation_factorize_real, equation);
1397
1398 g_timeout_add(50, math_equation_look_for_answer, equation);
1399 g_timeout_add(100, math_equation_show_in_progress, equation);
1400}
1401
1402
1403void
1404math_equation_delete(MathEquation *equation)
1405{
1406 gint cursor;
1407 CtkTextIter start, end;
1408
1409 g_return_if_fail(equation != NULL)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return; } } while (0)
;
1410
1411 g_object_get(G_OBJECT(equation)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), (((GType) ((20) << (2))))))))
, "cursor-position", &cursor, NULL((void*)0));
1412 if (cursor >= ctk_text_buffer_get_char_count(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
))
1413 return;
1414
1415 ctk_text_buffer_get_iter_at_offset(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, &start, cursor);
1416 ctk_text_buffer_get_iter_at_offset(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, &end, cursor+1);
1417 ctk_text_buffer_delete(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, &start, &end);
1418}
1419
1420
1421void
1422math_equation_backspace(MathEquation *equation)
1423{
1424 g_return_if_fail(equation != NULL)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return; } } while (0)
;
1425
1426 /* Can't delete empty display */
1427 if (math_equation_is_empty(equation))
1428 return;
1429
1430 if (ctk_text_buffer_get_has_selection(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
))
1431 ctk_text_buffer_delete_selection(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, FALSE(0), FALSE(0));
1432 else {
1433 CtkTextIter iter;
1434 ctk_text_buffer_get_iter_at_mark(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, &iter, ctk_text_buffer_get_insert(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
));
1435 ctk_text_buffer_backspace(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, &iter, TRUE(!(0)), TRUE(!(0)));
1436 }
1437}
1438
1439
1440void
1441math_equation_clear(MathEquation *equation)
1442{
1443 g_return_if_fail(equation != NULL)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return; } } while (0)
;
1444
1445 math_equation_set_number_mode(equation, NORMAL);
1446 ctk_text_buffer_set_text(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, "", -1);
1447 clear_ans(equation, FALSE(0));
1448}
1449
1450
1451void
1452math_equation_shift(MathEquation *equation, gint count)
1453{
1454 MPNumber z;
1455
1456 g_return_if_fail(equation != NULL)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return; } } while (0)
;
1457
1458 if (!math_equation_get_number(equation, &z)) {
1459 math_equation_set_status(equation,
1460 /* This message is displayed in the status bar when a bit
1461 shift operation is performed and the display does not contain a number */
1462 _("No sane value to bitwise shift")gettext ("No sane value to bitwise shift"));
1463 return;
1464 }
1465
1466 mp_shift(&z, count, &z);
1467 math_equation_set_number(equation, &z);
1468}
1469
1470
1471void
1472math_equation_toggle_bit(MathEquation *equation, guint bit)
1473{
1474 MPNumber x;
1475 guint64 bits;
1476 gboolean result;
1477
1478 g_return_if_fail(equation != NULL)do { if ((equation != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "equation != NULL"
); return; } } while (0)
;
1479
1480 result = math_equation_get_number(equation, &x);
1481 if (result) {
1482 MPNumber max;
1483 mp_set_from_unsigned_integer(G_MAXUINT64(0xffffffffffffffffUL), &max);
1484 if (mp_is_negative(&x) || mp_is_greater_than(&x, &max))
1485 result = FALSE(0);
1486 else
1487 bits = mp_cast_to_unsigned_int(&x);
1488 }
1489
1490 if (!result) {
1491 math_equation_set_status(equation,
1492 /* Message displayed when cannot toggle bit in display*/
1493 _("Displayed value not an integer")gettext ("Displayed value not an integer"));
1494 return;
1495 }
1496
1497 bits ^= (1LL << (63 - bit));
1498
1499 mp_set_from_unsigned_integer(bits, &x);
1500
1501 // FIXME: Only do this if in ans format, otherwise set text in same format as previous number
1502 math_equation_set_number(equation, &x);
1503}
1504
1505
1506static void
1507math_equation_set_property(GObject *object,
1508 guint prop_id,
1509 const GValue *value,
1510 GParamSpec *pspec)
1511{
1512 MathEquation *self;
1513
1514 self = MATH_EQUATION(object)((((MathEquation*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((object)), (math_equation_get_type())))))
;
1515
1516 switch (prop_id) {
1517 case PROP_STATUS:
1518 math_equation_set_status(self, g_value_get_string(value));
1519 break;
1520 case PROP_DISPLAY:
1521 math_equation_set(self, g_value_get_string(value));
1522 break;
1523 case PROP_NUMBER_MODE:
1524 math_equation_set_number_mode(self, g_value_get_int(value));
1525 break;
1526 case PROP_ACCURACY:
1527 math_equation_set_accuracy(self, g_value_get_int(value));
1528 break;
1529 case PROP_SHOW_THOUSANDS_SEPARATORS:
1530 math_equation_set_show_thousands_separators(self, g_value_get_boolean(value));
1531 break;
1532 case PROP_SHOW_TRAILING_ZEROES:
1533 math_equation_set_show_trailing_zeroes(self, g_value_get_boolean(value));
1534 break;
1535 case PROP_NUMBER_FORMAT:
1536 math_equation_set_number_format(self, g_value_get_int(value));
1537 break;
1538 case PROP_BASE:
1539 math_equation_set_base(self, g_value_get_int(value));
1540 break;
1541 case PROP_WORD_SIZE:
1542 math_equation_set_word_size(self, g_value_get_int(value));
1543 break;
1544 case PROP_ANGLE_UNITS:
1545 math_equation_set_angle_units(self, g_value_get_int(value));
1546 break;
1547 case PROP_SOURCE_CURRENCY:
1548 math_equation_set_source_currency(self, g_value_get_string(value));
1549 break;
1550 case PROP_TARGET_CURRENCY:
1551 math_equation_set_target_currency(self, g_value_get_string(value));
1552 break;
1553 case PROP_SOURCE_UNITS:
1554 math_equation_set_source_units(self, g_value_get_string(value));
1555 break;
1556 case PROP_TARGET_UNITS:
1557 math_equation_set_target_units(self, g_value_get_string(value));
1558 break;
1559 default:
1560 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec)do { GObject *_glib__object = (GObject*) ((object)); GParamSpec
*_glib__pspec = (GParamSpec*) ((pspec)); guint _glib__property_id
= ((prop_id)); g_warning ("%s:%d: invalid %s id %u for \"%s\" of type '%s' in '%s'"
, "math-equation.c", 1560, ("property"), _glib__property_id, _glib__pspec
->name, g_type_name ((((((GTypeClass*) (((GTypeInstance*) (
_glib__pspec))->g_class))->g_type)))), (g_type_name (((
(((GTypeClass*) (((GTypeInstance*) (_glib__object))->g_class
))->g_type)))))); } while (0)
;
1561 break;
1562 }
1563}
1564
1565
1566static void
1567math_equation_get_property(GObject *object,
1568 guint prop_id,
1569 GValue *value,
1570 GParamSpec *pspec)
1571{
1572 MathEquation *self;
1573 gchar *text;
1574
1575 self = MATH_EQUATION(object)((((MathEquation*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((object)), (math_equation_get_type())))))
;
1576
1577 switch (prop_id) {
1578 case PROP_STATUS:
1579 g_value_set_string(value, self->priv->state.status);
1580 break;
1581 case PROP_DISPLAY:
1582 text = math_equation_get_display(self);
1583 g_value_set_string(value, text);
1584 g_free(text);
1585 break;
1586 case PROP_EQUATION:
1587 text = math_equation_get_equation(self);
1588 g_value_set_string(value, text);
1589 g_free(text);
1590 break;
1591 case PROP_NUMBER_MODE:
1592 g_value_set_enum(value, self->priv->number_mode);
1593 break;
1594 case PROP_ACCURACY:
1595 g_value_set_int(value, mp_serializer_get_trailing_digits(self->priv->serializer));
1596 break;
1597 case PROP_SHOW_THOUSANDS_SEPARATORS:
1598 g_value_set_boolean(value, mp_serializer_get_show_thousands_separators(self->priv->serializer));
1599 break;
1600 case PROP_SHOW_TRAILING_ZEROES:
1601 g_value_set_boolean(value, mp_serializer_get_show_trailing_zeroes(self->priv->serializer));
1602 break;
1603 case PROP_NUMBER_FORMAT:
1604 g_value_set_enum(value, mp_serializer_get_number_format(self->priv->serializer));
1605 break;
1606 case PROP_BASE:
1607 g_value_set_int(value, math_equation_get_base(self));
1608 break;
1609 case PROP_WORD_SIZE:
1610 g_value_set_int(value, self->priv->word_size);
1611 break;
1612 case PROP_ANGLE_UNITS:
1613 g_value_set_enum(value, self->priv->angle_units);
1614 break;
1615 case PROP_SOURCE_CURRENCY:
1616 g_value_set_string(value, self->priv->source_currency);
1617 break;
1618 case PROP_TARGET_CURRENCY:
1619 g_value_set_string(value, self->priv->target_currency);
1620 break;
1621 case PROP_SOURCE_UNITS:
1622 g_value_set_string(value, self->priv->source_units);
1623 break;
1624 case PROP_TARGET_UNITS:
1625 g_value_set_string(value, self->priv->target_units);
1626 break;
1627 case PROP_SERIALIZER:
1628 g_value_set_object(value, self->priv->serializer);
1629 break;
1630 default:
1631 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec)do { GObject *_glib__object = (GObject*) ((object)); GParamSpec
*_glib__pspec = (GParamSpec*) ((pspec)); guint _glib__property_id
= ((prop_id)); g_warning ("%s:%d: invalid %s id %u for \"%s\" of type '%s' in '%s'"
, "math-equation.c", 1631, ("property"), _glib__property_id, _glib__pspec
->name, g_type_name ((((((GTypeClass*) (((GTypeInstance*) (
_glib__pspec))->g_class))->g_type)))), (g_type_name (((
(((GTypeClass*) (((GTypeInstance*) (_glib__object))->g_class
))->g_type)))))); } while (0)
;
1632 break;
1633 }
1634}
1635
1636
1637static void
1638math_equation_constructed(GObject *object)
1639{
1640 CtkTextBuffer *parent_class;
1641 parent_class = g_type_class_peek_parent(MATH_EQUATION_GET_CLASS(object)((((MathEquationClass*) (((GTypeInstance*) ((object)))->g_class
))))
);
1642 if (G_OBJECT_CLASS(parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((parent_class)), (((GType) ((20) << (2))))))))
->constructed)
1643 G_OBJECT_CLASS(parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((parent_class)), (((GType) ((20) << (2))))))))
->constructed(object);
1644
1645 MATH_EQUATION(object)((((MathEquation*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((object)), (math_equation_get_type())))))
->priv->ans_tag = ctk_text_buffer_create_tag(CTK_TEXT_BUFFER(object)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((object)), ((ctk_text_buffer_get_type ()))))))
, NULL((void*)0), "weight", PANGO_WEIGHT_BOLD, NULL((void*)0));
1646}
1647
1648
1649static void
1650math_equation_class_init(MathEquationClass *klass)
1651{
1652 static GEnumValue number_mode_values[] =
1653 {
1654 {NORMAL, "normal", "normal"},
1655 {SUPERSCRIPT, "superscript", "superscript"},
1656 {SUBSCRIPT, "subscript", "subscript"},
1657 {0, NULL((void*)0), NULL((void*)0)}
1658 };
1659 static GEnumValue angle_unit_values[] =
1660 {
1661 {MP_RADIANS, "radians", "radians"},
1662 {MP_DEGREES, "degrees", "degrees"},
1663 {MP_GRADIANS, "gradians", "gradians"},
1664 {0, NULL((void*)0), NULL((void*)0)}
1665 };
1666 GObjectClass *object_class = G_OBJECT_CLASS(klass)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((klass)), (((GType) ((20) << (2))))))))
;
1667
1668 object_class->get_property = math_equation_get_property;
1669 object_class->set_property = math_equation_set_property;
1670 object_class->constructed = math_equation_constructed;
1671
1672 number_mode_type = g_enum_register_static("NumberMode", number_mode_values);
1673 number_format_type = math_mp_display_format_get_type();
1674 angle_unit_type = g_enum_register_static("AngleUnit", angle_unit_values);
1675
1676 g_object_class_install_property(object_class,
1677 PROP_STATUS,
1678 g_param_spec_string("status",
1679 "status",
1680 "Equation status",
1681 "",
1682 G_PARAM_READWRITE));
1683 g_object_class_install_property(object_class,
1684 PROP_DISPLAY,
1685 g_param_spec_string("display",
1686 "display",
1687 "Displayed equation text",
1688 "",
1689 G_PARAM_READWRITE));
1690 g_object_class_install_property(object_class,
1691 PROP_EQUATION,
1692 g_param_spec_string("equation",
1693 "equation",
1694 "Equation text",
1695 "",
1696 G_PARAM_READABLE));
1697 g_object_class_install_property(object_class,
1698 PROP_NUMBER_MODE,
1699 g_param_spec_enum("number-mode",
1700 "number-mode",
1701 "Input number mode",
1702 number_mode_type,
1703 NORMAL,
1704 G_PARAM_READWRITE));
1705 g_object_class_install_property(object_class,
1706 PROP_ACCURACY,
1707 g_param_spec_int("accuracy",
1708 "accuracy",
1709 "Display accuracy",
1710 0, 20, 9,
1711 G_PARAM_READWRITE));
1712 g_object_class_install_property(object_class,
1713 PROP_SHOW_THOUSANDS_SEPARATORS,
1714 g_param_spec_boolean("show-thousands-separators",
1715 "show-thousands-separators",
1716 "Show thousands separators",
1717 TRUE(!(0)),
1718 G_PARAM_READWRITE));
1719 g_object_class_install_property(object_class,
1720 PROP_SHOW_TRAILING_ZEROES,
1721 g_param_spec_boolean("show-trailing-zeroes",
1722 "show-trailing-zeroes",
1723 "Show trailing zeroes",
1724 FALSE(0),
1725 G_PARAM_READWRITE));
1726 g_object_class_install_property(object_class,
1727 PROP_NUMBER_FORMAT,
1728 g_param_spec_enum("number-format",
1729 "number-format",
1730 "Display format",
1731 number_format_type,
1732 MP_DISPLAY_FORMAT_FIXED,
1733 G_PARAM_READWRITE));
1734 g_object_class_install_property(object_class,
1735 PROP_BASE,
1736 g_param_spec_int("base",
1737 "base",
1738 "Default number base (derived from number-format)",
1739 2, 16, 10,
1740 G_PARAM_READWRITE));
1741 g_object_class_install_property(object_class,
1742 PROP_WORD_SIZE,
1743 g_param_spec_int("word-size",
1744 "word-size",
1745 "Word size in bits",
1746 8, 64, 64,
1747 G_PARAM_READWRITE));
1748 g_object_class_install_property(object_class,
1749 PROP_ANGLE_UNITS,
1750 g_param_spec_enum("angle-units",
1751 "angle-units",
1752 "Angle units",
1753 angle_unit_type,
1754 MP_DEGREES,
1755 G_PARAM_READWRITE));
1756 g_object_class_install_property(object_class,
1757 PROP_SOURCE_CURRENCY,
1758 g_param_spec_string("source-currency",
1759 "source-currency",
1760 "Source Currency",
1761 "",
1762 G_PARAM_READWRITE));
1763 g_object_class_install_property(object_class,
1764 PROP_TARGET_CURRENCY,
1765 g_param_spec_string("target-currency",
1766 "target-currency",
1767 "target Currency",
1768 "",
1769 G_PARAM_READWRITE));
1770 g_object_class_install_property(object_class,
1771 PROP_SOURCE_UNITS,
1772 g_param_spec_string("source-units",
1773 "source-units",
1774 "Source Units",
1775 "",
1776 G_PARAM_READWRITE));
1777 g_object_class_install_property(object_class,
1778 PROP_TARGET_UNITS,
1779 g_param_spec_string("target-units",
1780 "target-units",
1781 "target Units",
1782 "",
1783 G_PARAM_READWRITE));
1784 g_object_class_install_property(object_class,
1785 PROP_SERIALIZER,
1786 g_param_spec_object("serializer",
1787 "serializer",
1788 "Serializer",
1789 MP_TYPE_SERIALIZER(mp_serializer_get_type()),
1790 G_PARAM_READABLE));
1791}
1792
1793
1794static void
1795pre_insert_text_cb(MathEquation *equation,
1796 CtkTextIter *location,
1797 gchar *text,
1798 gint len,
1799 gpointer user_data)
1800{
1801 gunichar c;
1802 gint cursor;
1803
1804 if (equation->priv->in_reformat)
1805 return;
1806
1807 /* If following a delete then have already pushed undo stack (CtkTextBuffer
1808 doesn't indicate replace operations so we have to infer them) */
1809 if (!equation->priv->in_delete)
1810 math_equation_push_undo_stack(equation);
1811
1812 /* Clear result on next digit entered if cursor at end of line */
1813 c = g_utf8_get_char(text);
1814 g_object_get(G_OBJECT(equation)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), (((GType) ((20) << (2))))))))
, "cursor-position", &cursor, NULL((void*)0));
1815 if ((g_unichar_isdigit(c) || c == mp_serializer_get_radix(equation->priv->serializer)) &&
1816 math_equation_is_result(equation) &&
1817 cursor >= ctk_text_buffer_get_char_count(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
)) {
1818 ctk_text_buffer_set_text(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, "", -1);
1819 clear_ans(equation, FALSE(0));
1820 ctk_text_buffer_get_end_iter(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, location);
1821 }
1822
1823 if (equation->priv->ans_start) {
1824 gint ans_start, ans_end;
1825 gint offset;
1826
1827 offset = ctk_text_iter_get_offset(location);
1828 get_ans_offsets(equation, &ans_start, &ans_end);
1829
1830 /* Inserted inside ans */
1831 if (offset > ans_start && offset < ans_end)
1832 clear_ans(equation, TRUE(!(0)));
1833 }
1834}
1835
1836
1837static gboolean
1838on_delete(MathEquation *equation)
1839{
1840 equation->priv->in_delete = FALSE(0);
1841 return FALSE(0);
1842}
1843
1844
1845static void
1846pre_delete_range_cb(MathEquation *equation,
1847 CtkTextIter *start,
1848 CtkTextIter *end,
1849 gpointer user_data)
1850{
1851 if (equation->priv->in_reformat)
1852 return;
1853
1854 math_equation_push_undo_stack(equation);
1855
1856 equation->priv->in_delete = TRUE(!(0));
1857 g_idle_add((GSourceFunc)on_delete, equation);
1858
1859 if (equation->priv->ans_start) {
1860 gint ans_start, ans_end;
1861 gint start_offset, end_offset;
1862
1863 start_offset = ctk_text_iter_get_offset(start);
1864 end_offset = ctk_text_iter_get_offset(end);
1865 get_ans_offsets(equation, &ans_start, &ans_end);
1866
1867 /* Deleted part of ans */
1868 if (start_offset < ans_end && end_offset > ans_start)
1869 clear_ans(equation, TRUE(!(0)));
1870 }
1871}
1872
1873
1874static void
1875insert_text_cb(MathEquation *equation,
1876 CtkTextIter *location,
1877 gchar *text,
1878 gint len,
1879 gpointer user_data)
1880{
1881 if (equation->priv->in_reformat)
1882 return;
1883
1884 equation->priv->state.entered_multiply = strcmp(text, "×") == 0;
1885
1886 /* Update thousands separators */
1887 reformat_separators(equation);
1888
1889 g_object_notify(G_OBJECT(equation)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), (((GType) ((20) << (2))))))))
, "display");
1890}
1891
1892
1893static void
1894delete_range_cb(MathEquation *equation,
1895 CtkTextIter *start,
1896 CtkTextIter *end,
1897 gpointer user_data)
1898{
1899 if (equation->priv->in_reformat)
1900 return;
1901
1902 equation->priv->state.entered_multiply = FALSE(0);
1903
1904 /* Update thousands separators */
1905 reformat_separators(equation);
1906
1907 // FIXME: A replace will emit this both for delete-range and insert-text, can it be avoided?
1908 g_object_notify(G_OBJECT(equation)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), (((GType) ((20) << (2))))))))
, "display");
1909}
1910
1911
1912static void
1913math_equation_init(MathEquation *equation)
1914{
1915 /* Digits localized for the given language */
1916 const char *digit_values = _("0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F")gettext ("0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F");
1917 const char *default_digits[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"};
1918 gchar **digits;
1919 /* Default to using untranslated digits, this is because it doesn't make sense in most languages and we need to make this optional.
1920 * See https://bugzilla.gnome.org/show_bug.cgi?id=632661 */
1921 gboolean use_default_digits = TRUE(!(0));
1922 int i;
1923
1924 equation->priv = math_equation_get_instance_private (equation);
1925
1926 g_signal_connect(equation, "insert-text", G_CALLBACK(pre_insert_text_cb), equation)g_signal_connect_data ((equation), ("insert-text"), (((GCallback
) (pre_insert_text_cb))), (equation), ((void*)0), (GConnectFlags
) 0)
;
1927 g_signal_connect(equation, "delete-range", G_CALLBACK(pre_delete_range_cb), equation)g_signal_connect_data ((equation), ("delete-range"), (((GCallback
) (pre_delete_range_cb))), (equation), ((void*)0), (GConnectFlags
) 0)
;
1928 g_signal_connect_after(equation, "insert-text", G_CALLBACK(insert_text_cb), equation)g_signal_connect_data ((equation), ("insert-text"), (((GCallback
) (insert_text_cb))), (equation), ((void*)0), G_CONNECT_AFTER
)
;
1929 g_signal_connect_after(equation, "delete-range", G_CALLBACK(delete_range_cb), equation)g_signal_connect_data ((equation), ("delete-range"), (((GCallback
) (delete_range_cb))), (equation), ((void*)0), G_CONNECT_AFTER
)
;
1930
1931 digits = g_strsplit(digit_values, ",", -1);
1932 for (i = 0; i < 16; i++) {
1933 if (use_default_digits || digits[i] == NULL((void*)0)) {
1934 use_default_digits = TRUE(!(0));
1935 equation->priv->digits[i] = g_utf8_get_char(default_digits[i]);
1936 }
1937 else
1938 equation->priv->digits[i] = g_utf8_get_char(digits[i]);
1939 }
1940 g_strfreev(digits);
1941
1942 equation->priv->variables = math_variables_new();
1943
1944 equation->priv->state.status = g_strdup("");
1945 equation->priv->word_size = 32;
1946 equation->priv->angle_units = MP_DEGREES;
1947 // FIXME: Pick based on locale
1948 equation->priv->source_currency = g_strdup("");
1949 equation->priv->target_currency = g_strdup("");
1950 equation->priv->source_units = g_strdup("");
1951 equation->priv->target_units = g_strdup("");
1952 equation->priv->serializer = mp_serializer_new(MP_DISPLAY_FORMAT_AUTOMATIC, 10, 9);
1953 equation->priv->queue = g_async_queue_new();
1954
1955 mp_set_from_integer(0, &equation->priv->state.ans);
1956}