Bug Summary

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