Bug Summary

File:math-equation.c
Warning:line 850, 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-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 -fdebug-compilation-dir=/rootdir/src -fcoverage-compilation-dir=/rootdir/src -resource-dir /usr/lib/llvm-19/lib/clang/19 -D HAVE_CONFIG_H -I . -I .. -D VERSION="1.25.0" -D LOCALE_DIR="/usr/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/sysprof-6 -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/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -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-19/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -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.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/2025-08-18-162928-15666-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 GType 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_pointer (
&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_pointer
((&static_g_define_type_id), (gpointer) (guintptr) (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)((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)((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)((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)g_strdup_inline (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 G_GNUC_UNUSED__attribute__ ((__unused__)),
433 const gchar *text,
434 gpointer data)
435{
436 if (text != NULL((void*)0)) {
437 MathEquation *equation = data;
438
439 math_equation_insert(equation, text);
440 }
441}
442
443
444void
445math_equation_paste(MathEquation *equation)
446{
447 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)
;
448 ctk_clipboard_request_text(ctk_clipboard_get(CDK_NONE((CdkAtom)((gpointer) (gulong) (0)))), on_paste, equation);
449}
450
451
452void
453math_equation_undo(MathEquation *equation)
454{
455 GList *link;
456 MathEquationState *state;
457
458 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)
;
459
460 if (!equation->priv->undo_stack) {
461 math_equation_set_status(equation,
462 /* Error shown when trying to undo with no undo history */
463 _("No undo history")gettext ("No undo history"));
464 return;
465 }
466
467 link = equation->priv->undo_stack;
468 equation->priv->undo_stack = g_list_remove_link(equation->priv->undo_stack, link);
469 state = link->data;
470 g_list_free(link);
471
472 equation->priv->redo_stack = g_list_prepend(equation->priv->redo_stack, get_current_state(equation));
473
474 apply_state(equation, state);
475 free_state(state);
476}
477
478
479void
480math_equation_redo(MathEquation *equation)
481{
482 GList *link;
483 MathEquationState *state;
484
485 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)
;
486
487 if (!equation->priv->redo_stack) {
488 math_equation_set_status(equation,
489 /* Error shown when trying to redo with no redo history */
490 _("No redo history")gettext ("No redo history"));
491 return;
492 }
493
494 link = equation->priv->redo_stack;
495 equation->priv->redo_stack = g_list_remove_link(equation->priv->redo_stack, link);
496 state = link->data;
497 g_list_free(link);
498
499 equation->priv->undo_stack = g_list_prepend(equation->priv->undo_stack, get_current_state(equation));
500
501 apply_state(equation, state);
502 free_state(state);
503}
504
505
506gunichar
507math_equation_get_digit_text(MathEquation *equation, guint digit)
508{
509 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)
;
510 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)
;
511
512 return equation->priv->digits[digit];
513}
514
515
516void
517math_equation_set_accuracy(MathEquation *equation, gint accuracy)
518{
519 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)
;
520
521 if (mp_serializer_get_trailing_digits(equation->priv->serializer) == accuracy)
522 return;
523 mp_serializer_set_trailing_digits(equation->priv->serializer, accuracy);
524 reformat_display(equation);
525 g_object_notify(G_OBJECT(equation)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), (((GType) ((20) << (2))))))))
, "accuracy");
526}
527
528
529gint
530math_equation_get_accuracy(MathEquation *equation)
531{
532 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)
;
533
534 return mp_serializer_get_trailing_digits(equation->priv->serializer);
535}
536
537
538void
539math_equation_set_show_thousands_separators(MathEquation *equation, gboolean visible)
540{
541 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)
;
542
543 if (mp_serializer_get_show_thousands_separators(equation->priv->serializer) == visible)
544 return;
545
546 mp_serializer_set_show_thousands_separators(equation->priv->serializer, visible);
547 reformat_display(equation);
548 g_object_notify(G_OBJECT(equation)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), (((GType) ((20) << (2))))))))
, "show-thousands-separators");
549}
550
551
552gboolean
553math_equation_get_show_thousands_separators(MathEquation *equation)
554{
555 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)
;
556 return mp_serializer_get_show_thousands_separators(equation->priv->serializer);
557}
558
559
560void
561math_equation_set_show_trailing_zeroes(MathEquation *equation, gboolean visible)
562{
563 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)
;
564
565 if (mp_serializer_get_show_trailing_zeroes(equation->priv->serializer) == visible)
566 return;
567
568 mp_serializer_set_show_trailing_zeroes(equation->priv->serializer, visible);
569 reformat_display(equation);
570 g_object_notify(G_OBJECT(equation)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), (((GType) ((20) << (2))))))))
, "show-trailing-zeroes");
571}
572
573
574gboolean
575math_equation_get_show_trailing_zeroes(MathEquation *equation)
576{
577 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)
;
578 return mp_serializer_get_show_trailing_zeroes(equation->priv->serializer);
579}
580
581
582void
583math_equation_set_number_format(MathEquation *equation, MpDisplayFormat format)
584{
585 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)
;
586
587 if (mp_serializer_get_number_format(equation->priv->serializer) == format)
588 return;
589
590 mp_serializer_set_number_format(equation->priv->serializer, format);
591 reformat_display(equation);
592 g_object_notify(G_OBJECT(equation)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), (((GType) ((20) << (2))))))))
, "number-format");
593}
594
595
596MpDisplayFormat
597math_equation_get_number_format(MathEquation *equation)
598{
599 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)
;
600 return mp_serializer_get_number_format(equation->priv->serializer);
601}
602
603
604void
605math_equation_set_base(MathEquation *equation, gint base)
606{
607 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)
;
608
609 if (mp_serializer_get_base(equation->priv->serializer) == base)
610 return;
611
612 mp_serializer_set_base(equation->priv->serializer, base);
613 reformat_display(equation);
614 g_object_notify(G_OBJECT(equation)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), (((GType) ((20) << (2))))))))
, "base");
615}
616
617
618gint
619math_equation_get_base(MathEquation *equation)
620{
621 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)
;
622 return mp_serializer_get_base(equation->priv->serializer);
623}
624
625
626void
627math_equation_set_word_size(MathEquation *equation, gint word_size)
628{
629 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)
;
630
631 if (equation->priv->word_size == word_size)
632 return;
633
634 equation->priv->word_size = word_size;
635 g_object_notify(G_OBJECT(equation)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), (((GType) ((20) << (2))))))))
, "word-size");
636}
637
638
639gint
640math_equation_get_word_size(MathEquation *equation)
641{
642 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)
;
643 return equation->priv->word_size;
644}
645
646
647void
648math_equation_set_angle_units(MathEquation *equation, MPAngleUnit angle_units)
649{
650 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)
;
651
652 if (equation->priv->angle_units == angle_units)
653 return;
654
655 equation->priv->angle_units = angle_units;
656 g_object_notify(G_OBJECT(equation)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), (((GType) ((20) << (2))))))))
, "angle-units");
657}
658
659
660MPAngleUnit
661math_equation_get_angle_units(MathEquation *equation)
662{
663 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)
;
664 return equation->priv->angle_units;
665}
666
667
668void
669math_equation_set_source_currency(MathEquation *equation, const gchar *currency)
670{
671 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)
;
672 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)
;
673
674 if (strcmp(equation->priv->source_currency, currency) == 0)
675 return;
676 g_free(equation->priv->source_currency);
677 equation->priv->source_currency = g_strdup(currency)g_strdup_inline (currency);
678 g_settings_set_string(g_settings_var, "source-currency",
679 math_equation_get_source_currency(equation));
680}
681
682
683const gchar *
684math_equation_get_source_currency(MathEquation *equation)
685{
686 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)
;
687 return equation->priv->source_currency;
688}
689
690
691void
692math_equation_set_target_currency(MathEquation *equation, const gchar *currency)
693{
694 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)
;
695 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)
;
696
697 if (strcmp(equation->priv->target_currency, currency) == 0)
698 return;
699 g_free(equation->priv->target_currency);
700 equation->priv->target_currency = g_strdup(currency)g_strdup_inline (currency);
701 g_settings_set_string(g_settings_var, "target-currency",
702 math_equation_get_target_currency(equation));
703}
704
705
706const gchar *
707math_equation_get_target_currency(MathEquation *equation)
708{
709 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)
;
710 return equation->priv->target_currency;
711}
712
713
714void
715math_equation_set_source_units(MathEquation *equation, const gchar *units)
716{
717 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)
;
718 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)
;
719
720 if (strcmp(equation->priv->source_units, units) == 0)
721 return;
722
723 g_free(equation->priv->source_units);
724 equation->priv->source_units = g_strdup(units)g_strdup_inline (units);
725 g_settings_set_string(g_settings_var, "source-units",
726 math_equation_get_source_units(equation));
727}
728
729const gchar *
730math_equation_get_source_units(MathEquation *equation)
731{
732 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)
;
733 return equation->priv->source_units;
734}
735
736
737void
738math_equation_set_target_units(MathEquation *equation, const gchar *units)
739{
740 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)
;
741 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)
;
742
743 if (strcmp(equation->priv->target_units, units) == 0)
744 return;
745
746 g_free(equation->priv->target_units);
747 equation->priv->target_units = g_strdup(units)g_strdup_inline (units);
748 g_settings_set_string(g_settings_var, "target-units",
749 math_equation_get_target_units(equation));
750}
751
752
753const gchar *
754math_equation_get_target_units(MathEquation *equation)
755{
756 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)
;
757 return equation->priv->target_units;
758}
759
760
761void
762math_equation_set_status(MathEquation *equation, const gchar *status)
763{
764 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)
;
765 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)
;
766
767 if (strcmp(equation->priv->state.status, status) == 0)
768 return;
769
770 g_free(equation->priv->state.status);
771 equation->priv->state.status = g_strdup(status)g_strdup_inline (status);
772 g_object_notify(G_OBJECT(equation)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), (((GType) ((20) << (2))))))))
, "status");
773}
774
775
776const gchar *
777math_equation_get_status(MathEquation *equation)
778{
779 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)
;
780 return equation->priv->state.status;
781}
782
783
784gboolean
785math_equation_is_empty(MathEquation *equation)
786{
787 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)
;
788 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;
789}
790
791
792gboolean
793math_equation_is_result(MathEquation *equation)
794{
795 char *text;
796 gboolean result;
797
798 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)
;
799
800 text = math_equation_get_equation(equation);
801 result = strcmp(text, "ans") == 0;
802 g_free(text);
803
804 return result;
805}
806
807
808gchar *
809math_equation_get_display(MathEquation *equation)
810{
811 CtkTextIter start, end;
812
813 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)
;
814
815 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);
816 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));
817}
818
819
820gchar *
821math_equation_get_equation(MathEquation *equation)
822{
823 gchar *text;
824 GString *eq_text;
825 gint ans_start = -1, ans_end = -1, offset;
826 const gchar *read_iter;
827 gboolean last_is_digit = FALSE(0);
828
829 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)
;
830
831 text = math_equation_get_display(equation);
832 eq_text = g_string_sized_new(strlen(text));
833
834 if (equation->priv->ans_start)
835 get_ans_offsets(equation, &ans_start, &ans_end);
836
837 for (read_iter = text, offset = 0; *read_iter != '\0'; read_iter = g_utf8_next_char(read_iter)((read_iter) + g_utf8_skip[*(const guchar *)(read_iter)]), offset++) {
838 gunichar c;
839 gboolean is_digit, next_is_digit;
840
841 c = g_utf8_get_char(read_iter);
842 is_digit = g_unichar_isdigit(c);
843 next_is_digit = g_unichar_isdigit(g_utf8_get_char(g_utf8_next_char(read_iter)((read_iter) + g_utf8_skip[*(const guchar *)(read_iter)])));
844
845 /* Replace ans text with variable */
846 if (offset == ans_start) {
847 g_string_append(eq_text, "ans")(__builtin_constant_p ("ans") ? __extension__ ({ const char *
const __val = ("ans"); g_string_append_len_inline (eq_text, __val
, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !(__val
))) : (gssize) -1); }) : g_string_append_len_inline (eq_text,
"ans", (gssize) -1))
;
848 read_iter = g_utf8_offset_to_pointer(read_iter, ans_end - ans_start - 1);
849 offset += ans_end - ans_start - 1;
850 is_digit = FALSE(0);
Value stored to 'is_digit' is never read
851 continue;
852 }
853
854 /* Ignore thousands separators */
855 if (c == mp_serializer_get_thousands_separator(equation->priv->serializer) && last_is_digit && next_is_digit)
856 ;
857 /* Substitute radix character */
858 else if (c == mp_serializer_get_radix(equation->priv->serializer) && (last_is_digit || next_is_digit))
859 g_string_append_unichar(eq_text, '.');
860 else
861 g_string_append_unichar(eq_text, c);
862
863 last_is_digit = is_digit;
864 }
865 g_free(text);
866
867 text = eq_text->str;
868 g_string_free(eq_text, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((eq_text
), ((0))) : g_string_free_and_steal (eq_text)) : (g_string_free
) ((eq_text), ((0))))
;
869
870 return text;
871}
872
873
874gboolean
875math_equation_get_number(MathEquation *equation, MPNumber *z)
876{
877 gboolean result;
878
879 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)
;
880 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)
;
881
882 if (math_equation_is_result(equation)) {
883 mp_set_from_mp(math_equation_get_answer(equation), z);
884 return TRUE(!(0));
885 }
886 else {
887 gchar *text;
888
889 text = math_equation_get_equation(equation);
890 result = !mp_serializer_from_string(equation->priv->serializer, text, z);
891 g_free(text);
892 return result;
893 }
894}
895
896
897MpSerializer *
898math_equation_get_serializer(MathEquation *equation)
899{
900 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)
;
901 return equation->priv->serializer;
902}
903
904
905void
906math_equation_set_number_mode(MathEquation *equation, NumberMode mode)
907{
908 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)
;
909
910 if (equation->priv->number_mode == mode)
911 return;
912
913 equation->priv->can_super_minus = mode == SUPERSCRIPT;
914
915 equation->priv->number_mode = mode;
916 g_object_notify(G_OBJECT(equation)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), (((GType) ((20) << (2))))))))
, "number-mode");
917}
918
919
920NumberMode
921math_equation_get_number_mode(MathEquation *equation)
922{
923 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)
;
924 return equation->priv->number_mode;
925}
926
927
928gboolean
929math_equation_in_solve(MathEquation *equation)
930{
931 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)
;
932 return equation->priv->in_solve;
933}
934
935
936const MPNumber *
937math_equation_get_answer(MathEquation *equation)
938{
939 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)
;
940 return &equation->priv->state.ans;
941}
942
943
944void
945math_equation_store(MathEquation *equation, const gchar *name)
946{
947 MPNumber t;
948
949 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)
;
950 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)
;
951
952 if (!math_equation_get_number(equation, &t))
953 math_equation_set_status(equation, _("No sane value to store")gettext ("No sane value to store"));
954 else
955 math_variables_set(equation->priv->variables, name, &t);
956}
957
958
959void
960math_equation_recall(MathEquation *equation, const gchar *name)
961{
962 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)
;
963 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)
;
964 math_equation_insert(equation, name);
965}
966
967
968void
969math_equation_set(MathEquation *equation, const gchar *text)
970{
971 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)
;
972 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)
;
973 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);
974 clear_ans(equation, FALSE(0));
975}
976
977
978void
979math_equation_set_number(MathEquation *equation, const MPNumber *x)
980{
981 char *text;
982 CtkTextIter start, end;
983
984 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)
;
985 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)
;
986
987 /* Show the number in the user chosen format */
988 text = mp_serializer_to_string(equation->priv->serializer, x);
989 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);
990 mp_set_from_mp(x, &equation->priv->state.ans);
991
992 /* Mark this text as the answer variable */
993 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);
994 clear_ans(equation, FALSE(0));
995 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));
996 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)));
997 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);
998 g_free(text);
999}
1000
1001
1002void
1003math_equation_insert(MathEquation *equation, const gchar *text)
1004{
1005 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)
;
1006 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)
;
1007
1008 /* Replace ** with ^ (not on all keyboards) */
1009 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 ()))))))
) &&
1010 strcmp(text, "×") == 0 && equation->priv->state.entered_multiply) {
1011 CtkTextIter iter;
1012
1013 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 ()))))))
));
1014 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)));
1015 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);
1016 return;
1017 }
1018
1019 /* Can't enter superscript minus after entering digits */
1020 if (strstr("⁰¹²³⁴⁵⁶⁷⁸⁹", text) != NULL((void*)0) || strcmp("⁻", text) == 0)
1021 equation->priv->can_super_minus = FALSE(0);
1022
1023 /* Disable super/subscript mode when finished entering */
1024 if (strstr("⁻⁰¹²³⁴⁵⁶⁷⁸⁹₀₁₂₃₄₅₆₇₈₉", text) == NULL((void*)0))
1025 math_equation_set_number_mode(equation, NORMAL);
1026
1027 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));
1028 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);
1029}
1030
1031
1032void
1033math_equation_insert_digit(MathEquation *equation, guint digit)
1034{
1035 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)
;
1036 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)
;
1037
1038 if (equation->priv->number_mode == NORMAL || digit >= 10) {
1039 gchar buffer[7];
1040 gint len;
1041 len = g_unichar_to_utf8(math_equation_get_digit_text(equation, digit), buffer);
1042 buffer[len] = '\0';
1043 math_equation_insert(equation, buffer);
1044 }
1045 else if (equation->priv->number_mode == SUPERSCRIPT) {
1046 static const char *superscript_digits[] = {"⁰", "¹", "²", "³", "⁴", "⁵", "⁶", "⁷", "⁸", "⁹", NULL((void*)0)};
1047
1048 math_equation_insert(equation, superscript_digits[digit]);
1049 }
1050 else if (equation->priv->number_mode == SUBSCRIPT) {
1051 static const char *subscript_digits[] = {"₀", "₁", "₂", "₃", "₄", "₅", "₆", "₇", "₈", "₉", NULL((void*)0)};
1052
1053 math_equation_insert(equation, subscript_digits[digit]);
1054 }
1055}
1056
1057
1058void
1059math_equation_insert_numeric_point(MathEquation *equation)
1060{
1061 gchar buffer[7];
1062 gint len;
1063
1064 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)
;
1065
1066 len = g_unichar_to_utf8(mp_serializer_get_radix(equation->priv->serializer), buffer);
1067 buffer[len] = '\0';
1068 math_equation_insert(equation, buffer);
1069}
1070
1071
1072void
1073math_equation_insert_number(MathEquation *equation, const MPNumber *x)
1074{
1075 char *text;
1076
1077 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)
;
1078 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)
;
1079
1080 text = mp_serializer_to_string(equation->priv->serializer, x);
1081 math_equation_insert(equation, text);
1082 g_free(text);
1083}
1084
1085
1086void
1087math_equation_insert_exponent(MathEquation *equation)
1088{
1089 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)
;
1090 math_equation_insert(equation, "×10");
1091 math_equation_set_number_mode(equation, SUPERSCRIPT);
1092}
1093
1094
1095void
1096math_equation_insert_subtract(MathEquation *equation)
1097{
1098 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)
;
1099 if (equation->priv->number_mode == SUPERSCRIPT && equation->priv->can_super_minus) {
1100 math_equation_insert(equation, "⁻");
1101 equation->priv->can_super_minus = FALSE(0);
1102 }
1103 else {
1104 math_equation_insert(equation, "−");
1105 math_equation_set_number_mode(equation, NORMAL);
1106 }
1107}
1108
1109
1110static int
1111variable_is_defined(const char *name, void *data)
1112{
1113 MathEquation *equation = data;
1114 char *c, *lower_name;
1115
1116 lower_name = strdup(name);
1117 for (c = lower_name; *c; c++)
1118 *c = tolower(*c);
1119
1120 if (strcmp(lower_name, "rand") == 0 ||
1121 strcmp(lower_name, "ans") == 0) {
1122 g_free(lower_name);
1123 return 1;
1124 }
1125 g_free(lower_name);
1126
1127 return math_variables_get(equation->priv->variables, name) != NULL((void*)0);
1128}
1129
1130
1131static int
1132get_variable(const char *name, MPNumber *z, void *data)
1133{
1134 char *c, *lower_name;
1135 int result = 1;
1136 MathEquation *equation = data;
1137 MPNumber *t;
1138
1139 lower_name = strdup(name);
1140 for (c = lower_name; *c; c++)
1141 *c = tolower(*c);
1142
1143 if (strcmp(lower_name, "rand") == 0)
1144 mp_set_from_random(z);
1145 else if (strcmp(lower_name, "ans") == 0)
1146 mp_set_from_mp(&equation->priv->state.ans, z);
1147 else {
1148 t = math_variables_get(equation->priv->variables, name);
1149 if (t)
1150 mp_set_from_mp(t, z);
1151 else
1152 result = 0;
1153 }
1154
1155 free(lower_name);
1156
1157 return result;
1158}
1159
1160
1161static void
1162set_variable(const char *name, const MPNumber *x, void *data)
1163{
1164 MathEquation *equation = data;
1165 /* FIXME: Don't allow writing to built-in variables, e.g. ans, rand, sin, ... */
1166 math_variables_set(equation->priv->variables, name, x);
1167}
1168
1169
1170static int
1171convert (const MPNumber *x,
1172 const char *x_units,
1173 const char *z_units,
1174 MPNumber *z,
1175 void *data G_GNUC_UNUSED__attribute__ ((__unused__)))
1176{
1177 return unit_manager_convert_by_symbol(unit_manager_get_default(), x, x_units, z_units, z);
1178}
1179
1180
1181static int
1182parse(MathEquation *equation, const char *text, MPNumber *z, char **error_token)
1183{
1184 MPEquationOptions options;
1185
1186 memset(&options, 0, sizeof(options));
1187 options.base = mp_serializer_get_base(equation->priv->serializer);
1188 options.wordlen = equation->priv->word_size;
1189 options.angle_units = equation->priv->angle_units;
1190 options.variable_is_defined = variable_is_defined;
1191 options.get_variable = get_variable;
1192 options.set_variable = set_variable;
1193 options.convert = convert;
1194 options.callback_data = equation;
1195
1196 return mp_equation_parse(text, &options, z, error_token);
1197}
1198
1199
1200/*
1201 * Executed in separate thread. It is thus not a good idea to write to anything
1202 * in MathEquation but the async queue from here.
1203 */
1204static gpointer
1205math_equation_solve_real(gpointer data)
1206{
1207 MathEquation *equation = MATH_EQUATION(data)((((MathEquation*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), (math_equation_get_type())))))
;
1208 SolveData *solvedata = g_slice_new0(SolveData)((SolveData*) g_slice_alloc0 (sizeof (SolveData)));
1209
1210 gint n_brackets = 0, result;
1211 gchar *c, *text, *error_token;
1212 GString *equation_text;
1213 MPNumber z;
1214
1215 text = math_equation_get_equation(equation);
1216 equation_text = g_string_new(text);
1217 g_free(text);
1218 /* Count the number of brackets and automatically add missing closing brackets */
1219 for (c = equation_text->str; *c; c++) {
1220 if (*c == '(')
1221 n_brackets++;
1222 else if (*c == ')')
1223 n_brackets--;
1224 }
1225 while (n_brackets > 0) {
1226 g_string_append_c(equation_text, ')')g_string_append_c_inline (equation_text, ')');
1227 n_brackets--;
1228 }
1229
1230
1231 result = parse(equation, equation_text->str, &z, &error_token);
1232 g_string_free(equation_text, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(equation_text), ((!(0)))) : g_string_free_and_steal (equation_text
)) : (g_string_free) ((equation_text), ((!(0)))))
;
1233
1234 switch (result) {
1235 case PARSER_ERR_NONE:
1236 solvedata->number_result = g_slice_new(MPNumber)((MPNumber*) g_slice_alloc (sizeof (MPNumber)));
1237 mp_set_from_mp(&z, solvedata->number_result);
1238 break;
1239
1240 case PARSER_ERR_OVERFLOW:
1241 solvedata->error = g_strdup(/* Error displayed to user when they perform a bitwise operation on numbers greater than the current word */g_strdup_inline (gettext ("Overflow. Try a bigger word size")
)
1242 _("Overflow. Try a bigger word size"))g_strdup_inline (gettext ("Overflow. Try a bigger word size")
)
;
1243 break;
1244
1245 case PARSER_ERR_UNKNOWN_VARIABLE:
1246 solvedata->error = g_strdup_printf(/* Error displayed to user when they an unknown variable is entered */
1247 _("Unknown variable '%s'")gettext ("Unknown variable '%s'"), error_token);
1248 break;
1249
1250 case PARSER_ERR_UNKNOWN_FUNCTION:
1251 solvedata->error = g_strdup_printf(/* Error displayed to user when an unknown function is entered */
1252 _("Function '%s' is not defined")gettext ("Function '%s' is not defined"), error_token);
1253 break;
1254
1255 case PARSER_ERR_UNKNOWN_CONVERSION:
1256 solvedata->error = g_strdup(/* Error displayed to user when an conversion with unknown units is attempted */g_strdup_inline (gettext ("Unknown conversion"))
1257 _("Unknown conversion"))g_strdup_inline (gettext ("Unknown conversion"));
1258 break;
1259
1260 case PARSER_ERR_MP:
1261 if (mp_get_error())
1262 solvedata->error = g_strdup(mp_get_error())g_strdup_inline (mp_get_error());
1263 else if (error_token)
1264 solvedata->error = g_strdup_printf(/* Uncategorized error. Show error token to user*/
1265 _("Malformed expression at token '%s'")gettext ("Malformed expression at token '%s'"), error_token);
1266 else
1267 solvedata->error = g_strdup (/* Unknown error. */g_strdup_inline (gettext ("Malformed expression"))
1268 _("Malformed expression"))g_strdup_inline (gettext ("Malformed expression"));
1269 break;
1270
1271 default:
1272 solvedata->error = g_strdup(/* Error displayed to user when they enter an invalid calculation */g_strdup_inline (gettext ("Malformed expression"))
1273 _("Malformed expression"))g_strdup_inline (gettext ("Malformed expression"));
1274 break;
1275 }
1276 g_async_queue_push(equation->priv->queue, solvedata);
1277
1278 return NULL((void*)0);
1279}
1280
1281
1282static gboolean
1283math_equation_show_in_progress(gpointer data)
1284{
1285 MathEquation *equation = MATH_EQUATION(data)((((MathEquation*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), (math_equation_get_type())))))
;
1286 if (equation->priv->in_solve)
1287 math_equation_set_status(equation, _("Calculating")gettext ("Calculating"));
1288 return false0;
1289}
1290
1291
1292static gboolean
1293math_equation_look_for_answer(gpointer data)
1294{
1295 MathEquation *equation = MATH_EQUATION(data)((((MathEquation*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), (math_equation_get_type())))))
;
1296 SolveData *result = g_async_queue_try_pop(equation->priv->queue);
1297
1298 if (result == NULL((void*)0))
1299 return true1;
1300
1301 equation->priv->in_solve = false0;
1302
1303 if (!result->error)
1304 math_equation_set_status(equation, "");
1305
1306 if (result->error != NULL((void*)0)) {
1307 math_equation_set_status(equation, result->error);
1308 g_free(result->error);
1309 }
1310 else if (result->number_result != NULL((void*)0)) {
1311 math_equation_set_number(equation, result->number_result);
1312 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)
;
1313 }
1314 else if (result->text_result != NULL((void*)0)) {
1315 math_equation_set(equation, result->text_result);
1316 g_free(result->text_result);
1317 }
1318 g_slice_free(SolveData, result)do { if (1) g_slice_free1 (sizeof (SolveData), (result)); else
(void) ((SolveData*) 0 == (result)); } while (0)
;
1319
1320 return false0;
1321}
1322
1323
1324void
1325math_equation_solve(MathEquation *equation)
1326{
1327 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)
;
1328
1329 // FIXME: should replace calculation or give error message
1330 if (equation->priv->in_solve)
1331 return;
1332
1333 if (math_equation_is_empty(equation))
1334 return;
1335
1336 /* If showing a result return to the equation that caused it */
1337 // FIXME: Result may not be here due to solve (i.e. the user may have entered "ans")
1338 if (math_equation_is_result(equation)) {
1339 math_equation_undo(equation);
1340 return;
1341 }
1342
1343 equation->priv->in_solve = true1;
1344
1345 math_equation_set_number_mode(equation, NORMAL);
1346 g_thread_new("", math_equation_solve_real, equation);
1347
1348 g_timeout_add(50, math_equation_look_for_answer, equation);
1349 g_timeout_add(100, math_equation_show_in_progress, equation);
1350}
1351
1352
1353static gpointer
1354math_equation_factorize_real(gpointer data)
1355{
1356 GString *text;
1357 GList *factors, *factor;
1358 MPNumber x;
1359 MathEquation *equation = MATH_EQUATION(data)((((MathEquation*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), (math_equation_get_type())))))
;
1360 SolveData *result = g_slice_new0(SolveData)((SolveData*) g_slice_alloc0 (sizeof (SolveData)));
1361
1362 math_equation_get_number(equation, &x);
1363 factors = mp_factorize(&x);
1364
1365 text = g_string_new("");
1366
1367 for (factor = factors; factor; factor = factor->next) {
1368 gchar *temp;
1369 MPNumber *n;
1370
1371 n = factor->data;
1372 temp = mp_serializer_to_string(equation->priv->serializer, n);
1373 g_string_append(text, temp)(__builtin_constant_p (temp) ? __extension__ ({ const char * const
__val = (temp); g_string_append_len_inline (text, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (text, temp, (gssize) -
1))
;
1374 if (factor->next)
1375 g_string_append(text, "×")(__builtin_constant_p ("×") ? __extension__ ({ const char * const
__val = ("×"); g_string_append_len_inline (text, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (text, "×", (gssize) -
1))
;
1376 g_slice_free(MPNumber, n)do { if (1) g_slice_free1 (sizeof (MPNumber), (n)); else (void
) ((MPNumber*) 0 == (n)); } while (0)
;
1377 g_free(temp);
1378 }
1379 g_list_free(factors);
1380
1381 result->text_result = g_strndup(text->str, text->len);
1382 g_async_queue_push(equation->priv->queue, result);
1383 g_string_free(text, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(text), ((!(0)))) : g_string_free_and_steal (text)) : (g_string_free
) ((text), ((!(0)))))
;
1384
1385 return NULL((void*)0);
1386}
1387
1388
1389void
1390math_equation_factorize(MathEquation *equation)
1391{
1392 MPNumber x;
1393
1394 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)
;
1395
1396 // FIXME: should replace calculation or give error message
1397 if (equation->priv->in_solve)
1398 return;
1399
1400 if (!math_equation_get_number(equation, &x) || !mp_is_integer(&x)) {
1401 /* Error displayed when trying to factorize a non-integer value */
1402 math_equation_set_status(equation, _("Need an integer to factorize")gettext ("Need an integer to factorize"));
1403 return;
1404 }
1405
1406 equation->priv->in_solve = true1;
1407
1408 g_thread_new("", math_equation_factorize_real, equation);
1409
1410 g_timeout_add(50, math_equation_look_for_answer, equation);
1411 g_timeout_add(100, math_equation_show_in_progress, equation);
1412}
1413
1414
1415void
1416math_equation_delete(MathEquation *equation)
1417{
1418 gint cursor;
1419 CtkTextIter start, end;
1420
1421 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)
;
1422
1423 g_object_get(G_OBJECT(equation)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), (((GType) ((20) << (2))))))))
, "cursor-position", &cursor, NULL((void*)0));
1424 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 ()))))))
))
1425 return;
1426
1427 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);
1428 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);
1429 ctk_text_buffer_delete(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, &start, &end);
1430}
1431
1432
1433void
1434math_equation_backspace(MathEquation *equation)
1435{
1436 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)
;
1437
1438 /* Can't delete empty display */
1439 if (math_equation_is_empty(equation))
1440 return;
1441
1442 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 ()))))))
))
1443 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));
1444 else {
1445 CtkTextIter iter;
1446 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 ()))))))
));
1447 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)));
1448 }
1449}
1450
1451
1452void
1453math_equation_clear(MathEquation *equation)
1454{
1455 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)
;
1456
1457 math_equation_set_number_mode(equation, NORMAL);
1458 ctk_text_buffer_set_text(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, "", -1);
1459 clear_ans(equation, FALSE(0));
1460}
1461
1462
1463void
1464math_equation_shift(MathEquation *equation, gint count)
1465{
1466 MPNumber z;
1467
1468 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)
;
1469
1470 if (!math_equation_get_number(equation, &z)) {
1471 math_equation_set_status(equation,
1472 /* This message is displayed in the status bar when a bit
1473 shift operation is performed and the display does not contain a number */
1474 _("No sane value to bitwise shift")gettext ("No sane value to bitwise shift"));
1475 return;
1476 }
1477
1478 mp_shift(&z, count, &z);
1479 math_equation_set_number(equation, &z);
1480}
1481
1482
1483void
1484math_equation_toggle_bit(MathEquation *equation, guint bit)
1485{
1486 MPNumber x;
1487 guint64 bits;
1488 gboolean result;
1489
1490 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)
;
1491
1492 result = math_equation_get_number(equation, &x);
1493 if (result) {
1494 MPNumber max;
1495 mp_set_from_unsigned_integer(G_MAXUINT64(0xffffffffffffffffUL), &max);
1496 if (mp_is_negative(&x) || mp_is_greater_than(&x, &max))
1497 result = FALSE(0);
1498 else
1499 bits = mp_cast_to_unsigned_int(&x);
1500 }
1501
1502 if (!result) {
1503 math_equation_set_status(equation,
1504 /* Message displayed when cannot toggle bit in display*/
1505 _("Displayed value not an integer")gettext ("Displayed value not an integer"));
1506 return;
1507 }
1508
1509 bits ^= (1LL << (63 - bit));
1510
1511 mp_set_from_unsigned_integer(bits, &x);
1512
1513 // FIXME: Only do this if in ans format, otherwise set text in same format as previous number
1514 math_equation_set_number(equation, &x);
1515}
1516
1517
1518static void
1519math_equation_set_property(GObject *object,
1520 guint prop_id,
1521 const GValue *value,
1522 GParamSpec *pspec)
1523{
1524 MathEquation *self;
1525
1526 self = MATH_EQUATION(object)((((MathEquation*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((object)), (math_equation_get_type())))))
;
1527
1528 switch (prop_id) {
1529 case PROP_STATUS:
1530 math_equation_set_status(self, g_value_get_string(value));
1531 break;
1532 case PROP_DISPLAY:
1533 math_equation_set(self, g_value_get_string(value));
1534 break;
1535 case PROP_NUMBER_MODE:
1536 math_equation_set_number_mode(self, g_value_get_int(value));
1537 break;
1538 case PROP_ACCURACY:
1539 math_equation_set_accuracy(self, g_value_get_int(value));
1540 break;
1541 case PROP_SHOW_THOUSANDS_SEPARATORS:
1542 math_equation_set_show_thousands_separators(self, g_value_get_boolean(value));
1543 break;
1544 case PROP_SHOW_TRAILING_ZEROES:
1545 math_equation_set_show_trailing_zeroes(self, g_value_get_boolean(value));
1546 break;
1547 case PROP_NUMBER_FORMAT:
1548 math_equation_set_number_format(self, g_value_get_int(value));
1549 break;
1550 case PROP_BASE:
1551 math_equation_set_base(self, g_value_get_int(value));
1552 break;
1553 case PROP_WORD_SIZE:
1554 math_equation_set_word_size(self, g_value_get_int(value));
1555 break;
1556 case PROP_ANGLE_UNITS:
1557 math_equation_set_angle_units(self, g_value_get_int(value));
1558 break;
1559 case PROP_SOURCE_CURRENCY:
1560 math_equation_set_source_currency(self, g_value_get_string(value));
1561 break;
1562 case PROP_TARGET_CURRENCY:
1563 math_equation_set_target_currency(self, g_value_get_string(value));
1564 break;
1565 case PROP_SOURCE_UNITS:
1566 math_equation_set_source_units(self, g_value_get_string(value));
1567 break;
1568 case PROP_TARGET_UNITS:
1569 math_equation_set_target_units(self, g_value_get_string(value));
1570 break;
1571 default:
1572 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", 1572, ("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)
;
1573 break;
1574 }
1575}
1576
1577
1578static void
1579math_equation_get_property(GObject *object,
1580 guint prop_id,
1581 GValue *value,
1582 GParamSpec *pspec)
1583{
1584 MathEquation *self;
1585 gchar *text;
1586
1587 self = MATH_EQUATION(object)((((MathEquation*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((object)), (math_equation_get_type())))))
;
1588
1589 switch (prop_id) {
1590 case PROP_STATUS:
1591 g_value_set_string(value, self->priv->state.status);
1592 break;
1593 case PROP_DISPLAY:
1594 text = math_equation_get_display(self);
1595 g_value_set_string(value, text);
1596 g_free(text);
1597 break;
1598 case PROP_EQUATION:
1599 text = math_equation_get_equation(self);
1600 g_value_set_string(value, text);
1601 g_free(text);
1602 break;
1603 case PROP_NUMBER_MODE:
1604 g_value_set_enum(value, self->priv->number_mode);
1605 break;
1606 case PROP_ACCURACY:
1607 g_value_set_int(value, mp_serializer_get_trailing_digits(self->priv->serializer));
1608 break;
1609 case PROP_SHOW_THOUSANDS_SEPARATORS:
1610 g_value_set_boolean(value, mp_serializer_get_show_thousands_separators(self->priv->serializer));
1611 break;
1612 case PROP_SHOW_TRAILING_ZEROES:
1613 g_value_set_boolean(value, mp_serializer_get_show_trailing_zeroes(self->priv->serializer));
1614 break;
1615 case PROP_NUMBER_FORMAT:
1616 g_value_set_enum(value, mp_serializer_get_number_format(self->priv->serializer));
1617 break;
1618 case PROP_BASE:
1619 g_value_set_int(value, math_equation_get_base(self));
1620 break;
1621 case PROP_WORD_SIZE:
1622 g_value_set_int(value, self->priv->word_size);
1623 break;
1624 case PROP_ANGLE_UNITS:
1625 g_value_set_enum(value, self->priv->angle_units);
1626 break;
1627 case PROP_SOURCE_CURRENCY:
1628 g_value_set_string(value, self->priv->source_currency);
1629 break;
1630 case PROP_TARGET_CURRENCY:
1631 g_value_set_string(value, self->priv->target_currency);
1632 break;
1633 case PROP_SOURCE_UNITS:
1634 g_value_set_string(value, self->priv->source_units);
1635 break;
1636 case PROP_TARGET_UNITS:
1637 g_value_set_string(value, self->priv->target_units);
1638 break;
1639 case PROP_SERIALIZER:
1640 g_value_set_object(value, self->priv->serializer);
1641 break;
1642 default:
1643 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", 1643, ("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)
;
1644 break;
1645 }
1646}
1647
1648
1649static void
1650math_equation_constructed(GObject *object)
1651{
1652 CtkTextBuffer *parent_class;
1653 parent_class = g_type_class_peek_parent(MATH_EQUATION_GET_CLASS(object)((((MathEquationClass*) (((GTypeInstance*) ((object)))->g_class
))))
);
1654 if (G_OBJECT_CLASS(parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((parent_class)), (((GType) ((20) << (2))))))))
->constructed)
1655 G_OBJECT_CLASS(parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((parent_class)), (((GType) ((20) << (2))))))))
->constructed(object);
1656
1657 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));
1658}
1659
1660
1661static void
1662math_equation_class_init(MathEquationClass *klass)
1663{
1664 static GEnumValue number_mode_values[] =
1665 {
1666 {NORMAL, "normal", "normal"},
1667 {SUPERSCRIPT, "superscript", "superscript"},
1668 {SUBSCRIPT, "subscript", "subscript"},
1669 {0, NULL((void*)0), NULL((void*)0)}
1670 };
1671 static GEnumValue angle_unit_values[] =
1672 {
1673 {MP_RADIANS, "radians", "radians"},
1674 {MP_DEGREES, "degrees", "degrees"},
1675 {MP_GRADIANS, "gradians", "gradians"},
1676 {0, NULL((void*)0), NULL((void*)0)}
1677 };
1678 GObjectClass *object_class = G_OBJECT_CLASS(klass)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((klass)), (((GType) ((20) << (2))))))))
;
1679
1680 object_class->get_property = math_equation_get_property;
1681 object_class->set_property = math_equation_set_property;
1682 object_class->constructed = math_equation_constructed;
1683
1684 number_mode_type = g_enum_register_static("NumberMode", number_mode_values);
1685 number_format_type = math_mp_display_format_get_type();
1686 angle_unit_type = g_enum_register_static("AngleUnit", angle_unit_values);
1687
1688 g_object_class_install_property(object_class,
1689 PROP_STATUS,
1690 g_param_spec_string("status",
1691 "status",
1692 "Equation status",
1693 "",
1694 G_PARAM_READWRITE));
1695 g_object_class_install_property(object_class,
1696 PROP_DISPLAY,
1697 g_param_spec_string("display",
1698 "display",
1699 "Displayed equation text",
1700 "",
1701 G_PARAM_READWRITE));
1702 g_object_class_install_property(object_class,
1703 PROP_EQUATION,
1704 g_param_spec_string("equation",
1705 "equation",
1706 "Equation text",
1707 "",
1708 G_PARAM_READABLE));
1709 g_object_class_install_property(object_class,
1710 PROP_NUMBER_MODE,
1711 g_param_spec_enum("number-mode",
1712 "number-mode",
1713 "Input number mode",
1714 number_mode_type,
1715 NORMAL,
1716 G_PARAM_READWRITE));
1717 g_object_class_install_property(object_class,
1718 PROP_ACCURACY,
1719 g_param_spec_int("accuracy",
1720 "accuracy",
1721 "Display accuracy",
1722 0, 20, 9,
1723 G_PARAM_READWRITE));
1724 g_object_class_install_property(object_class,
1725 PROP_SHOW_THOUSANDS_SEPARATORS,
1726 g_param_spec_boolean("show-thousands-separators",
1727 "show-thousands-separators",
1728 "Show thousands separators",
1729 TRUE(!(0)),
1730 G_PARAM_READWRITE));
1731 g_object_class_install_property(object_class,
1732 PROP_SHOW_TRAILING_ZEROES,
1733 g_param_spec_boolean("show-trailing-zeroes",
1734 "show-trailing-zeroes",
1735 "Show trailing zeroes",
1736 FALSE(0),
1737 G_PARAM_READWRITE));
1738 g_object_class_install_property(object_class,
1739 PROP_NUMBER_FORMAT,
1740 g_param_spec_enum("number-format",
1741 "number-format",
1742 "Display format",
1743 number_format_type,
1744 MP_DISPLAY_FORMAT_FIXED,
1745 G_PARAM_READWRITE));
1746 g_object_class_install_property(object_class,
1747 PROP_BASE,
1748 g_param_spec_int("base",
1749 "base",
1750 "Default number base (derived from number-format)",
1751 2, 16, 10,
1752 G_PARAM_READWRITE));
1753 g_object_class_install_property(object_class,
1754 PROP_WORD_SIZE,
1755 g_param_spec_int("word-size",
1756 "word-size",
1757 "Word size in bits",
1758 8, 64, 64,
1759 G_PARAM_READWRITE));
1760 g_object_class_install_property(object_class,
1761 PROP_ANGLE_UNITS,
1762 g_param_spec_enum("angle-units",
1763 "angle-units",
1764 "Angle units",
1765 angle_unit_type,
1766 MP_DEGREES,
1767 G_PARAM_READWRITE));
1768 g_object_class_install_property(object_class,
1769 PROP_SOURCE_CURRENCY,
1770 g_param_spec_string("source-currency",
1771 "source-currency",
1772 "Source Currency",
1773 "",
1774 G_PARAM_READWRITE));
1775 g_object_class_install_property(object_class,
1776 PROP_TARGET_CURRENCY,
1777 g_param_spec_string("target-currency",
1778 "target-currency",
1779 "target Currency",
1780 "",
1781 G_PARAM_READWRITE));
1782 g_object_class_install_property(object_class,
1783 PROP_SOURCE_UNITS,
1784 g_param_spec_string("source-units",
1785 "source-units",
1786 "Source Units",
1787 "",
1788 G_PARAM_READWRITE));
1789 g_object_class_install_property(object_class,
1790 PROP_TARGET_UNITS,
1791 g_param_spec_string("target-units",
1792 "target-units",
1793 "target Units",
1794 "",
1795 G_PARAM_READWRITE));
1796 g_object_class_install_property(object_class,
1797 PROP_SERIALIZER,
1798 g_param_spec_object("serializer",
1799 "serializer",
1800 "Serializer",
1801 MP_TYPE_SERIALIZER(mp_serializer_get_type()),
1802 G_PARAM_READABLE));
1803}
1804
1805
1806static void
1807pre_insert_text_cb (MathEquation *equation,
1808 CtkTextIter *location,
1809 gchar *text,
1810 gint len G_GNUC_UNUSED__attribute__ ((__unused__)),
1811 gpointer user_data G_GNUC_UNUSED__attribute__ ((__unused__)))
1812{
1813 gunichar c;
1814 gint cursor;
1815
1816 if (equation->priv->in_reformat)
1817 return;
1818
1819 /* If following a delete then have already pushed undo stack (CtkTextBuffer
1820 doesn't indicate replace operations so we have to infer them) */
1821 if (!equation->priv->in_delete)
1822 math_equation_push_undo_stack(equation);
1823
1824 /* Clear result on next digit entered if cursor at end of line */
1825 c = g_utf8_get_char(text);
1826 g_object_get(G_OBJECT(equation)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), (((GType) ((20) << (2))))))))
, "cursor-position", &cursor, NULL((void*)0));
1827 if ((g_unichar_isdigit(c) || c == mp_serializer_get_radix(equation->priv->serializer)) &&
1828 math_equation_is_result(equation) &&
1829 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 ()))))))
)) {
1830 ctk_text_buffer_set_text(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, "", -1);
1831 clear_ans(equation, FALSE(0));
1832 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);
1833 }
1834
1835 if (equation->priv->ans_start) {
1836 gint ans_start, ans_end;
1837 gint offset;
1838
1839 offset = ctk_text_iter_get_offset(location);
1840 get_ans_offsets(equation, &ans_start, &ans_end);
1841
1842 /* Inserted inside ans */
1843 if (offset > ans_start && offset < ans_end)
1844 clear_ans(equation, TRUE(!(0)));
1845 }
1846}
1847
1848
1849static gboolean
1850on_delete(MathEquation *equation)
1851{
1852 equation->priv->in_delete = FALSE(0);
1853 return FALSE(0);
1854}
1855
1856
1857static void
1858pre_delete_range_cb(MathEquation *equation,
1859 CtkTextIter *start,
1860 CtkTextIter *end,
1861 gpointer user_data G_GNUC_UNUSED__attribute__ ((__unused__)))
1862{
1863 if (equation->priv->in_reformat)
1864 return;
1865
1866 math_equation_push_undo_stack(equation);
1867
1868 equation->priv->in_delete = TRUE(!(0));
1869 g_idle_add((GSourceFunc)on_delete, equation);
1870
1871 if (equation->priv->ans_start) {
1872 gint ans_start, ans_end;
1873 gint start_offset, end_offset;
1874
1875 start_offset = ctk_text_iter_get_offset(start);
1876 end_offset = ctk_text_iter_get_offset(end);
1877 get_ans_offsets(equation, &ans_start, &ans_end);
1878
1879 /* Deleted part of ans */
1880 if (start_offset < ans_end && end_offset > ans_start)
1881 clear_ans(equation, TRUE(!(0)));
1882 }
1883}
1884
1885
1886static void
1887insert_text_cb(MathEquation *equation,
1888 CtkTextIter *location G_GNUC_UNUSED__attribute__ ((__unused__)),
1889 gchar *text,
1890 gint len G_GNUC_UNUSED__attribute__ ((__unused__)),
1891 gpointer user_data G_GNUC_UNUSED__attribute__ ((__unused__)))
1892{
1893 if (equation->priv->in_reformat)
1894 return;
1895
1896 equation->priv->state.entered_multiply = strcmp(text, "×") == 0;
1897
1898 /* Update thousands separators */
1899 reformat_separators(equation);
1900
1901 g_object_notify(G_OBJECT(equation)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), (((GType) ((20) << (2))))))))
, "display");
1902}
1903
1904
1905static void
1906delete_range_cb (MathEquation *equation,
1907 CtkTextIter *start G_GNUC_UNUSED__attribute__ ((__unused__)),
1908 CtkTextIter *end G_GNUC_UNUSED__attribute__ ((__unused__)),
1909 gpointer user_data G_GNUC_UNUSED__attribute__ ((__unused__)))
1910{
1911 if (equation->priv->in_reformat)
1912 return;
1913
1914 equation->priv->state.entered_multiply = FALSE(0);
1915
1916 /* Update thousands separators */
1917 reformat_separators(equation);
1918
1919 // FIXME: A replace will emit this both for delete-range and insert-text, can it be avoided?
1920 g_object_notify(G_OBJECT(equation)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), (((GType) ((20) << (2))))))))
, "display");
1921}
1922
1923
1924static void
1925math_equation_init(MathEquation *equation)
1926{
1927 /* Digits localized for the given language */
1928 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");
1929 const char *default_digits[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"};
1930 gchar **digits;
1931 /* Default to using untranslated digits, this is because it doesn't make sense in most languages and we need to make this optional.
1932 * See https://bugzilla.gnome.org/show_bug.cgi?id=632661 */
1933 gboolean use_default_digits = TRUE(!(0));
1934 int i;
1935
1936 equation->priv = math_equation_get_instance_private (equation);
1937
1938 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)
;
1939 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)
;
1940 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
)
;
1941 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
)
;
1942
1943 digits = g_strsplit(digit_values, ",", -1);
1944 for (i = 0; i < 16; i++) {
1945 if (use_default_digits || digits[i] == NULL((void*)0)) {
1946 use_default_digits = TRUE(!(0));
1947 equation->priv->digits[i] = g_utf8_get_char(default_digits[i]);
1948 }
1949 else
1950 equation->priv->digits[i] = g_utf8_get_char(digits[i]);
1951 }
1952 g_strfreev(digits);
1953
1954 equation->priv->variables = math_variables_new();
1955
1956 equation->priv->state.status = g_strdup("")g_strdup_inline ("");
1957 equation->priv->word_size = 32;
1958 equation->priv->angle_units = MP_DEGREES;
1959 // FIXME: Pick based on locale
1960 equation->priv->source_currency = g_strdup("")g_strdup_inline ("");
1961 equation->priv->target_currency = g_strdup("")g_strdup_inline ("");
1962 equation->priv->source_units = g_strdup("")g_strdup_inline ("");
1963 equation->priv->target_units = g_strdup("")g_strdup_inline ("");
1964 equation->priv->serializer = mp_serializer_new(MP_DISPLAY_FORMAT_AUTOMATIC, 10, 9);
1965 equation->priv->queue = g_async_queue_new();
1966
1967 mp_set_from_integer(0, &equation->priv->state.ans);
1968}