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-21/lib/clang/21 -D HAVE_CONFIG_H -I . -I .. -D VERSION="2.0.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/cairo -I /usr/include/cdk-pixbuf-2.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/atk-1.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/fribidi -I /usr/include/pixman-1 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/gio-unix-2.0 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/libxml2 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -internal-isystem /usr/lib/llvm-21/lib/clang/21/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/15/../../../../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 security.ArrayBound -analyzer-checker unix.cstring.NotNullTerminated -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -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/2026-08-16-115530-15302-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 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)
;
878 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)
;
879
880 if (math_equation_is_result(equation)) {
881 mp_set_from_mp(math_equation_get_answer(equation), z);
882 return TRUE(!(0));
883 }
884 else {
885 gchar *text;
886 gboolean result;
887
888 text = math_equation_get_equation(equation);
889 result = !mp_serializer_from_string(equation->priv->serializer, text, z);
890 g_free(text);
891 return result;
892 }
893}
894
895
896MpSerializer *
897math_equation_get_serializer(MathEquation *equation)
898{
899 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)
;
900 return equation->priv->serializer;
901}
902
903
904void
905math_equation_set_number_mode(MathEquation *equation, NumberMode mode)
906{
907 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)
;
908
909 if (equation->priv->number_mode == mode)
910 return;
911
912 equation->priv->can_super_minus = mode == SUPERSCRIPT;
913
914 equation->priv->number_mode = mode;
915 g_object_notify(G_OBJECT(equation)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), (((GType) ((20) << (2))))))))
, "number-mode");
916}
917
918
919NumberMode
920math_equation_get_number_mode(MathEquation *equation)
921{
922 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)
;
923 return equation->priv->number_mode;
924}
925
926
927gboolean
928math_equation_in_solve(MathEquation *equation)
929{
930 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)
;
931 return equation->priv->in_solve;
932}
933
934
935const MPNumber *
936math_equation_get_answer(MathEquation *equation)
937{
938 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)
;
939 return &equation->priv->state.ans;
940}
941
942
943void
944math_equation_store(MathEquation *equation, const gchar *name)
945{
946 MPNumber t;
947
948 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)
;
949 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)
;
950
951 if (!math_equation_get_number(equation, &t))
952 math_equation_set_status(equation, _("No sane value to store")gettext ("No sane value to store"));
953 else
954 math_variables_set(equation->priv->variables, name, &t);
955}
956
957
958void
959math_equation_recall(MathEquation *equation, const gchar *name)
960{
961 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)
;
962 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)
;
963 math_equation_insert(equation, name);
964}
965
966
967void
968math_equation_set(MathEquation *equation, const gchar *text)
969{
970 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)
;
971 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)
;
972 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);
973 clear_ans(equation, FALSE(0));
974}
975
976
977void
978math_equation_set_number(MathEquation *equation, const MPNumber *x)
979{
980 char *text;
981 CtkTextIter start, end;
982
983 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)
;
984 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)
;
985
986 /* Show the number in the user chosen format */
987 text = mp_serializer_to_string(equation->priv->serializer, x);
988 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);
989 mp_set_from_mp(x, &equation->priv->state.ans);
990
991 /* Mark this text as the answer variable */
992 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);
993 clear_ans(equation, FALSE(0));
994 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));
995 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)));
996 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);
997 g_free(text);
998}
999
1000
1001void
1002math_equation_insert(MathEquation *equation, const gchar *text)
1003{
1004 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)
;
1005 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)
;
1006
1007 /* Replace ** with ^ (not on all keyboards) */
1008 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 ()))))))
) &&
1009 strcmp(text, "×") == 0 && equation->priv->state.entered_multiply) {
1010 CtkTextIter iter;
1011
1012 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 ()))))))
));
1013 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)));
1014 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);
1015 return;
1016 }
1017
1018 /* Can't enter superscript minus after entering digits */
1019 if (strstr("⁰¹²³⁴⁵⁶⁷⁸⁹", text) != NULL((void*)0) || strcmp("⁻", text) == 0)
1020 equation->priv->can_super_minus = FALSE(0);
1021
1022 /* Disable super/subscript mode when finished entering */
1023 if (strstr("⁻⁰¹²³⁴⁵⁶⁷⁸⁹₀₁₂₃₄₅₆₇₈₉", text) == NULL((void*)0))
1024 math_equation_set_number_mode(equation, NORMAL);
1025
1026 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));
1027 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);
1028}
1029
1030
1031void
1032math_equation_insert_digit(MathEquation *equation, guint digit)
1033{
1034 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)
;
1035 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)
;
1036
1037 if (equation->priv->number_mode == NORMAL || digit >= 10) {
1038 gchar buffer[7];
1039 gint len;
1040 len = g_unichar_to_utf8(math_equation_get_digit_text(equation, digit), buffer);
1041 buffer[len] = '\0';
1042 math_equation_insert(equation, buffer);
1043 }
1044 else if (equation->priv->number_mode == SUPERSCRIPT) {
1045 static const char *superscript_digits[] = {"⁰", "¹", "²", "³", "⁴", "⁵", "⁶", "⁷", "⁸", "⁹", NULL((void*)0)};
1046
1047 math_equation_insert(equation, superscript_digits[digit]);
1048 }
1049 else if (equation->priv->number_mode == SUBSCRIPT) {
1050 static const char *subscript_digits[] = {"₀", "₁", "₂", "₃", "₄", "₅", "₆", "₇", "₈", "₉", NULL((void*)0)};
1051
1052 math_equation_insert(equation, subscript_digits[digit]);
1053 }
1054}
1055
1056
1057void
1058math_equation_insert_numeric_point(MathEquation *equation)
1059{
1060 gchar buffer[7];
1061 gint len;
1062
1063 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)
;
1064
1065 len = g_unichar_to_utf8(mp_serializer_get_radix(equation->priv->serializer), buffer);
1066 buffer[len] = '\0';
1067 math_equation_insert(equation, buffer);
1068}
1069
1070
1071void
1072math_equation_insert_number(MathEquation *equation, const MPNumber *x)
1073{
1074 char *text;
1075
1076 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)
;
1077 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)
;
1078
1079 text = mp_serializer_to_string(equation->priv->serializer, x);
1080 math_equation_insert(equation, text);
1081 g_free(text);
1082}
1083
1084
1085void
1086math_equation_insert_exponent(MathEquation *equation)
1087{
1088 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)
;
1089 math_equation_insert(equation, "×10");
1090 math_equation_set_number_mode(equation, SUPERSCRIPT);
1091}
1092
1093
1094void
1095math_equation_insert_subtract(MathEquation *equation)
1096{
1097 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)
;
1098 if (equation->priv->number_mode == SUPERSCRIPT && equation->priv->can_super_minus) {
1099 math_equation_insert(equation, "⁻");
1100 equation->priv->can_super_minus = FALSE(0);
1101 }
1102 else {
1103 math_equation_insert(equation, "−");
1104 math_equation_set_number_mode(equation, NORMAL);
1105 }
1106}
1107
1108
1109static int
1110variable_is_defined(const char *name, void *data)
1111{
1112 MathEquation *equation = data;
1113 char *c, *lower_name;
1114
1115 lower_name = strdup(name);
1116 for (c = lower_name; *c; c++)
1117 *c = tolower(*c);
1118
1119 if (strcmp(lower_name, "rand") == 0 ||
1120 strcmp(lower_name, "ans") == 0) {
1121 g_free(lower_name);
1122 return 1;
1123 }
1124 g_free(lower_name);
1125
1126 return math_variables_get(equation->priv->variables, name) != NULL((void*)0);
1127}
1128
1129
1130static int
1131get_variable(const char *name, MPNumber *z, void *data)
1132{
1133 char *c, *lower_name;
1134 int result = 1;
1135 MathEquation *equation = data;
1136 MPNumber *t;
1137
1138 lower_name = strdup(name);
1139 for (c = lower_name; *c; c++)
1140 *c = tolower(*c);
1141
1142 if (strcmp(lower_name, "rand") == 0)
1143 mp_set_from_random(z);
1144 else if (strcmp(lower_name, "ans") == 0)
1145 mp_set_from_mp(&equation->priv->state.ans, z);
1146 else {
1147 t = math_variables_get(equation->priv->variables, name);
1148 if (t)
1149 mp_set_from_mp(t, z);
1150 else
1151 result = 0;
1152 }
1153
1154 free(lower_name);
1155
1156 return result;
1157}
1158
1159
1160static void
1161set_variable(const char *name, const MPNumber *x, void *data)
1162{
1163 MathEquation *equation = data;
1164 /* FIXME: Don't allow writing to built-in variables, e.g. ans, rand, sin, ... */
1165 math_variables_set(equation->priv->variables, name, x);
1166}
1167
1168
1169static int
1170convert (const MPNumber *x,
1171 const char *x_units,
1172 const char *z_units,
1173 MPNumber *z,
1174 void *data G_GNUC_UNUSED__attribute__ ((__unused__)))
1175{
1176 return unit_manager_convert_by_symbol(unit_manager_get_default(), x, x_units, z_units, z);
1177}
1178
1179
1180static int
1181parse(MathEquation *equation, const char *text, MPNumber *z, char **error_token)
1182{
1183 MPEquationOptions options;
1184
1185 memset(&options, 0, sizeof(options));
1186 options.base = mp_serializer_get_base(equation->priv->serializer);
1187 options.wordlen = equation->priv->word_size;
1188 options.angle_units = equation->priv->angle_units;
1189 options.variable_is_defined = variable_is_defined;
1190 options.get_variable = get_variable;
1191 options.set_variable = set_variable;
1192 options.convert = convert;
1193 options.callback_data = equation;
1194
1195 return mp_equation_parse(text, &options, z, error_token);
1196}
1197
1198
1199/*
1200 * Executed in separate thread. It is thus not a good idea to write to anything
1201 * in MathEquation but the async queue from here.
1202 */
1203static gpointer
1204math_equation_solve_real(gpointer data)
1205{
1206 MathEquation *equation = MATH_EQUATION(data)((((MathEquation*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), (math_equation_get_type())))))
;
1207 SolveData *solvedata = g_slice_new0(SolveData)((SolveData*) g_slice_alloc0 ((sizeof (SolveData) > 0 ? sizeof
(SolveData) : 1)))
;
1208
1209 gint n_brackets = 0, result;
1210 gchar *c, *text, *error_token;
1211 GString *equation_text;
1212 MPNumber z;
1213
1214 text = math_equation_get_equation(equation);
1215 equation_text = g_string_new(text);
1216 g_free(text);
1217 /* Count the number of brackets and automatically add missing closing brackets */
1218 for (c = equation_text->str; *c; c++) {
1219 if (*c == '(')
1220 n_brackets++;
1221 else if (*c == ')')
1222 n_brackets--;
1223 }
1224 while (n_brackets > 0) {
1225 g_string_append_c(equation_text, ')')g_string_append_c_inline (equation_text, ')');
1226 n_brackets--;
1227 }
1228
1229
1230 result = parse(equation, equation_text->str, &z, &error_token);
1231 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)))))
;
1232
1233 switch (result) {
1234 case PARSER_ERR_NONE:
1235 solvedata->number_result = g_slice_new(MPNumber)((MPNumber*) g_slice_alloc ((sizeof (MPNumber) > 0 ? sizeof
(MPNumber) : 1)))
;
1236 mp_set_from_mp(&z, solvedata->number_result);
1237 break;
1238
1239 case PARSER_ERR_OVERFLOW:
1240 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")
)
1241 _("Overflow. Try a bigger word size"))g_strdup_inline (gettext ("Overflow. Try a bigger word size")
)
;
1242 break;
1243
1244 case PARSER_ERR_UNKNOWN_VARIABLE:
1245 solvedata->error = g_strdup_printf(/* Error displayed to user when they an unknown variable is entered */
1246 _("Unknown variable '%s'")gettext ("Unknown variable '%s'"), error_token);
1247 break;
1248
1249 case PARSER_ERR_UNKNOWN_FUNCTION:
1250 solvedata->error = g_strdup_printf(/* Error displayed to user when an unknown function is entered */
1251 _("Function '%s' is not defined")gettext ("Function '%s' is not defined"), error_token);
1252 break;
1253
1254 case PARSER_ERR_UNKNOWN_CONVERSION:
1255 solvedata->error = g_strdup(/* Error displayed to user when an conversion with unknown units is attempted */g_strdup_inline (gettext ("Unknown conversion"))
1256 _("Unknown conversion"))g_strdup_inline (gettext ("Unknown conversion"));
1257 break;
1258
1259 case PARSER_ERR_MP:
1260 if (mp_get_error())
1261 solvedata->error = g_strdup(mp_get_error())g_strdup_inline (mp_get_error());
1262 else if (error_token)
1263 solvedata->error = g_strdup_printf(/* Uncategorized error. Show error token to user*/
1264 _("Malformed expression at token '%s'")gettext ("Malformed expression at token '%s'"), error_token);
1265 else
1266 solvedata->error = g_strdup (/* Unknown error. */g_strdup_inline (gettext ("Malformed expression"))
1267 _("Malformed expression"))g_strdup_inline (gettext ("Malformed expression"));
1268 break;
1269
1270 default:
1271 solvedata->error = g_strdup(/* Error displayed to user when they enter an invalid calculation */g_strdup_inline (gettext ("Malformed expression"))
1272 _("Malformed expression"))g_strdup_inline (gettext ("Malformed expression"));
1273 break;
1274 }
1275 g_async_queue_push(equation->priv->queue, solvedata);
1276
1277 return NULL((void*)0);
1278}
1279
1280
1281static gboolean
1282math_equation_show_in_progress(gpointer data)
1283{
1284 MathEquation *equation = MATH_EQUATION(data)((((MathEquation*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), (math_equation_get_type())))))
;
1285 if (equation->priv->in_solve)
1286 math_equation_set_status(equation, _("Calculating")gettext ("Calculating"));
1287 return false0;
1288}
1289
1290
1291static gboolean
1292math_equation_look_for_answer(gpointer data)
1293{
1294 MathEquation *equation = MATH_EQUATION(data)((((MathEquation*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), (math_equation_get_type())))))
;
1295 SolveData *result = g_async_queue_try_pop(equation->priv->queue);
1296
1297 if (result == NULL((void*)0))
1298 return true1;
1299
1300 equation->priv->in_solve = false0;
1301
1302 if (!result->error)
1303 math_equation_set_status(equation, "");
1304
1305 if (result->error != NULL((void*)0)) {
1306 math_equation_set_status(equation, result->error);
1307 g_free(result->error);
1308 }
1309 else if (result->number_result != NULL((void*)0)) {
1310 math_equation_set_number(equation, result->number_result);
1311 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)
;
1312 }
1313 else if (result->text_result != NULL((void*)0)) {
1314 math_equation_set(equation, result->text_result);
1315 g_free(result->text_result);
1316 }
1317 g_slice_free(SolveData, result)do { if (1) g_slice_free1 (sizeof (SolveData), (result)); else
(void) ((SolveData*) 0 == (result)); } while (0)
;
1318
1319 return false0;
1320}
1321
1322
1323void
1324math_equation_solve(MathEquation *equation)
1325{
1326 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)
;
1327
1328 // FIXME: should replace calculation or give error message
1329 if (equation->priv->in_solve)
1330 return;
1331
1332 if (math_equation_is_empty(equation))
1333 return;
1334
1335 /* If showing a result return to the equation that caused it */
1336 // FIXME: Result may not be here due to solve (i.e. the user may have entered "ans")
1337 if (math_equation_is_result(equation)) {
1338 math_equation_undo(equation);
1339 return;
1340 }
1341
1342 equation->priv->in_solve = true1;
1343
1344 math_equation_set_number_mode(equation, NORMAL);
1345 g_thread_new("", math_equation_solve_real, equation);
1346
1347 g_timeout_add(50, math_equation_look_for_answer, equation);
1348 g_timeout_add(100, math_equation_show_in_progress, equation);
1349}
1350
1351
1352static gpointer
1353math_equation_factorize_real(gpointer data)
1354{
1355 GString *text;
1356 GList *factors, *factor;
1357 MPNumber x;
1358 MathEquation *equation = MATH_EQUATION(data)((((MathEquation*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), (math_equation_get_type())))))
;
1359 SolveData *result = g_slice_new0(SolveData)((SolveData*) g_slice_alloc0 ((sizeof (SolveData) > 0 ? sizeof
(SolveData) : 1)))
;
1360
1361 math_equation_get_number(equation, &x);
1362 factors = mp_factorize(&x);
1363
1364 text = g_string_new("");
1365
1366 for (factor = factors; factor; factor = factor->next) {
1367 gchar *temp;
1368 MPNumber *n;
1369
1370 n = factor->data;
1371 temp = mp_serializer_to_string(equation->priv->serializer, n);
1372 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))
;
1373 if (factor->next)
1374 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))
;
1375 g_slice_free(MPNumber, n)do { if (1) g_slice_free1 (sizeof (MPNumber), (n)); else (void
) ((MPNumber*) 0 == (n)); } while (0)
;
1376 g_free(temp);
1377 }
1378 g_list_free(factors);
1379
1380 result->text_result = g_strndup(text->str, text->len);
1381 g_async_queue_push(equation->priv->queue, result);
1382 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)))))
;
1383
1384 return NULL((void*)0);
1385}
1386
1387
1388void
1389math_equation_factorize(MathEquation *equation)
1390{
1391 MPNumber x;
1392
1393 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)
;
1394
1395 // FIXME: should replace calculation or give error message
1396 if (equation->priv->in_solve)
1397 return;
1398
1399 if (!math_equation_get_number(equation, &x) || !mp_is_integer(&x)) {
1400 /* Error displayed when trying to factorize a non-integer value */
1401 math_equation_set_status(equation, _("Need an integer to factorize")gettext ("Need an integer to factorize"));
1402 return;
1403 }
1404
1405 equation->priv->in_solve = true1;
1406
1407 g_thread_new("", math_equation_factorize_real, equation);
1408
1409 g_timeout_add(50, math_equation_look_for_answer, equation);
1410 g_timeout_add(100, math_equation_show_in_progress, equation);
1411}
1412
1413
1414void
1415math_equation_delete(MathEquation *equation)
1416{
1417 gint cursor;
1418 CtkTextIter start, end;
1419
1420 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)
;
1421
1422 g_object_get(G_OBJECT(equation)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), (((GType) ((20) << (2))))))))
, "cursor-position", &cursor, NULL((void*)0));
1423 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 ()))))))
))
1424 return;
1425
1426 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);
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 ()))))))
, &end, cursor+1);
1428 ctk_text_buffer_delete(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, &start, &end);
1429}
1430
1431
1432void
1433math_equation_backspace(MathEquation *equation)
1434{
1435 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)
;
1436
1437 /* Can't delete empty display */
1438 if (math_equation_is_empty(equation))
1439 return;
1440
1441 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 ()))))))
))
1442 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));
1443 else {
1444 CtkTextIter iter;
1445 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 ()))))))
));
1446 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)));
1447 }
1448}
1449
1450
1451void
1452math_equation_clear(MathEquation *equation)
1453{
1454 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)
;
1455
1456 math_equation_set_number_mode(equation, NORMAL);
1457 ctk_text_buffer_set_text(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, "", -1);
1458 clear_ans(equation, FALSE(0));
1459}
1460
1461
1462void
1463math_equation_shift(MathEquation *equation, gint count)
1464{
1465 MPNumber z;
1466
1467 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)
;
1468
1469 if (!math_equation_get_number(equation, &z)) {
1470 math_equation_set_status(equation,
1471 /* This message is displayed in the status bar when a bit
1472 shift operation is performed and the display does not contain a number */
1473 _("No sane value to bitwise shift")gettext ("No sane value to bitwise shift"));
1474 return;
1475 }
1476
1477 mp_shift(&z, count, &z);
1478 math_equation_set_number(equation, &z);
1479}
1480
1481
1482void
1483math_equation_toggle_bit(MathEquation *equation, guint bit)
1484{
1485 MPNumber x;
1486 guint64 bits;
1487 gboolean result;
1488
1489 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)
;
1490
1491 result = math_equation_get_number(equation, &x);
1492 if (result) {
1493 MPNumber max;
1494 mp_set_from_unsigned_integer(G_MAXUINT64(0xffffffffffffffffUL), &max);
1495 if (mp_is_negative(&x) || mp_is_greater_than(&x, &max))
1496 result = FALSE(0);
1497 else
1498 bits = mp_cast_to_unsigned_int(&x);
1499 }
1500
1501 if (!result) {
1502 math_equation_set_status(equation,
1503 /* Message displayed when cannot toggle bit in display*/
1504 _("Displayed value not an integer")gettext ("Displayed value not an integer"));
1505 return;
1506 }
1507
1508 bits ^= (1LL << (63 - bit));
1509
1510 mp_set_from_unsigned_integer(bits, &x);
1511
1512 // FIXME: Only do this if in ans format, otherwise set text in same format as previous number
1513 math_equation_set_number(equation, &x);
1514}
1515
1516
1517static void
1518math_equation_set_property(GObject *object,
1519 guint prop_id,
1520 const GValue *value,
1521 GParamSpec *pspec)
1522{
1523 MathEquation *self;
1524
1525 self = MATH_EQUATION(object)((((MathEquation*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((object)), (math_equation_get_type())))))
;
1526
1527 switch (prop_id) {
1528 case PROP_STATUS:
1529 math_equation_set_status(self, g_value_get_string(value));
1530 break;
1531 case PROP_DISPLAY:
1532 math_equation_set(self, g_value_get_string(value));
1533 break;
1534 case PROP_NUMBER_MODE:
1535 math_equation_set_number_mode(self, g_value_get_int(value));
1536 break;
1537 case PROP_ACCURACY:
1538 math_equation_set_accuracy(self, g_value_get_int(value));
1539 break;
1540 case PROP_SHOW_THOUSANDS_SEPARATORS:
1541 math_equation_set_show_thousands_separators(self, g_value_get_boolean(value));
1542 break;
1543 case PROP_SHOW_TRAILING_ZEROES:
1544 math_equation_set_show_trailing_zeroes(self, g_value_get_boolean(value));
1545 break;
1546 case PROP_NUMBER_FORMAT:
1547 math_equation_set_number_format(self, g_value_get_int(value));
1548 break;
1549 case PROP_BASE:
1550 math_equation_set_base(self, g_value_get_int(value));
1551 break;
1552 case PROP_WORD_SIZE:
1553 math_equation_set_word_size(self, g_value_get_int(value));
1554 break;
1555 case PROP_ANGLE_UNITS:
1556 math_equation_set_angle_units(self, g_value_get_int(value));
1557 break;
1558 case PROP_SOURCE_CURRENCY:
1559 math_equation_set_source_currency(self, g_value_get_string(value));
1560 break;
1561 case PROP_TARGET_CURRENCY:
1562 math_equation_set_target_currency(self, g_value_get_string(value));
1563 break;
1564 case PROP_SOURCE_UNITS:
1565 math_equation_set_source_units(self, g_value_get_string(value));
1566 break;
1567 case PROP_TARGET_UNITS:
1568 math_equation_set_target_units(self, g_value_get_string(value));
1569 break;
1570 default:
1571 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", 1571, ("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)
;
1572 break;
1573 }
1574}
1575
1576
1577static void
1578math_equation_get_property(GObject *object,
1579 guint prop_id,
1580 GValue *value,
1581 GParamSpec *pspec)
1582{
1583 MathEquation *self;
1584 gchar *text;
1585
1586 self = MATH_EQUATION(object)((((MathEquation*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((object)), (math_equation_get_type())))))
;
1587
1588 switch (prop_id) {
1589 case PROP_STATUS:
1590 g_value_set_string(value, self->priv->state.status);
1591 break;
1592 case PROP_DISPLAY:
1593 text = math_equation_get_display(self);
1594 g_value_set_string(value, text);
1595 g_free(text);
1596 break;
1597 case PROP_EQUATION:
1598 text = math_equation_get_equation(self);
1599 g_value_set_string(value, text);
1600 g_free(text);
1601 break;
1602 case PROP_NUMBER_MODE:
1603 g_value_set_enum(value, self->priv->number_mode);
1604 break;
1605 case PROP_ACCURACY:
1606 g_value_set_int(value, mp_serializer_get_trailing_digits(self->priv->serializer));
1607 break;
1608 case PROP_SHOW_THOUSANDS_SEPARATORS:
1609 g_value_set_boolean(value, mp_serializer_get_show_thousands_separators(self->priv->serializer));
1610 break;
1611 case PROP_SHOW_TRAILING_ZEROES:
1612 g_value_set_boolean(value, mp_serializer_get_show_trailing_zeroes(self->priv->serializer));
1613 break;
1614 case PROP_NUMBER_FORMAT:
1615 g_value_set_enum(value, mp_serializer_get_number_format(self->priv->serializer));
1616 break;
1617 case PROP_BASE:
1618 g_value_set_int(value, math_equation_get_base(self));
1619 break;
1620 case PROP_WORD_SIZE:
1621 g_value_set_int(value, self->priv->word_size);
1622 break;
1623 case PROP_ANGLE_UNITS:
1624 g_value_set_enum(value, self->priv->angle_units);
1625 break;
1626 case PROP_SOURCE_CURRENCY:
1627 g_value_set_string(value, self->priv->source_currency);
1628 break;
1629 case PROP_TARGET_CURRENCY:
1630 g_value_set_string(value, self->priv->target_currency);
1631 break;
1632 case PROP_SOURCE_UNITS:
1633 g_value_set_string(value, self->priv->source_units);
1634 break;
1635 case PROP_TARGET_UNITS:
1636 g_value_set_string(value, self->priv->target_units);
1637 break;
1638 case PROP_SERIALIZER:
1639 g_value_set_object(value, self->priv->serializer);
1640 break;
1641 default:
1642 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", 1642, ("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)
;
1643 break;
1644 }
1645}
1646
1647
1648static void
1649math_equation_constructed(GObject *object)
1650{
1651 CtkTextBuffer *parent_class;
1652 parent_class = g_type_class_peek_parent(MATH_EQUATION_GET_CLASS(object)((((MathEquationClass*) (((GTypeInstance*) ((object)))->g_class
))))
);
1653 if (G_OBJECT_CLASS(parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((parent_class)), (((GType) ((20) << (2))))))))
->constructed)
1654 G_OBJECT_CLASS(parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((parent_class)), (((GType) ((20) << (2))))))))
->constructed(object);
1655
1656 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));
1657}
1658
1659
1660static void
1661math_equation_class_init(MathEquationClass *klass)
1662{
1663 static GEnumValue number_mode_values[] =
1664 {
1665 {NORMAL, "normal", "normal"},
1666 {SUPERSCRIPT, "superscript", "superscript"},
1667 {SUBSCRIPT, "subscript", "subscript"},
1668 {0, NULL((void*)0), NULL((void*)0)}
1669 };
1670 static GEnumValue angle_unit_values[] =
1671 {
1672 {MP_RADIANS, "radians", "radians"},
1673 {MP_DEGREES, "degrees", "degrees"},
1674 {MP_GRADIANS, "gradians", "gradians"},
1675 {0, NULL((void*)0), NULL((void*)0)}
1676 };
1677 GObjectClass *object_class = G_OBJECT_CLASS(klass)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((klass)), (((GType) ((20) << (2))))))))
;
1678
1679 object_class->get_property = math_equation_get_property;
1680 object_class->set_property = math_equation_set_property;
1681 object_class->constructed = math_equation_constructed;
1682
1683 number_mode_type = g_enum_register_static("NumberMode", number_mode_values);
1684 number_format_type = math_mp_display_format_get_type();
1685 angle_unit_type = g_enum_register_static("AngleUnit", angle_unit_values);
1686
1687 g_object_class_install_property(object_class,
1688 PROP_STATUS,
1689 g_param_spec_string("status",
1690 "status",
1691 "Equation status",
1692 "",
1693 G_PARAM_READWRITE));
1694 g_object_class_install_property(object_class,
1695 PROP_DISPLAY,
1696 g_param_spec_string("display",
1697 "display",
1698 "Displayed equation text",
1699 "",
1700 G_PARAM_READWRITE));
1701 g_object_class_install_property(object_class,
1702 PROP_EQUATION,
1703 g_param_spec_string("equation",
1704 "equation",
1705 "Equation text",
1706 "",
1707 G_PARAM_READABLE));
1708 g_object_class_install_property(object_class,
1709 PROP_NUMBER_MODE,
1710 g_param_spec_enum("number-mode",
1711 "number-mode",
1712 "Input number mode",
1713 number_mode_type,
1714 NORMAL,
1715 G_PARAM_READWRITE));
1716 g_object_class_install_property(object_class,
1717 PROP_ACCURACY,
1718 g_param_spec_int("accuracy",
1719 "accuracy",
1720 "Display accuracy",
1721 0, 20, 9,
1722 G_PARAM_READWRITE));
1723 g_object_class_install_property(object_class,
1724 PROP_SHOW_THOUSANDS_SEPARATORS,
1725 g_param_spec_boolean("show-thousands-separators",
1726 "show-thousands-separators",
1727 "Show thousands separators",
1728 TRUE(!(0)),
1729 G_PARAM_READWRITE));
1730 g_object_class_install_property(object_class,
1731 PROP_SHOW_TRAILING_ZEROES,
1732 g_param_spec_boolean("show-trailing-zeroes",
1733 "show-trailing-zeroes",
1734 "Show trailing zeroes",
1735 FALSE(0),
1736 G_PARAM_READWRITE));
1737 g_object_class_install_property(object_class,
1738 PROP_NUMBER_FORMAT,
1739 g_param_spec_enum("number-format",
1740 "number-format",
1741 "Display format",
1742 number_format_type,
1743 MP_DISPLAY_FORMAT_FIXED,
1744 G_PARAM_READWRITE));
1745 g_object_class_install_property(object_class,
1746 PROP_BASE,
1747 g_param_spec_int("base",
1748 "base",
1749 "Default number base (derived from number-format)",
1750 2, 16, 10,
1751 G_PARAM_READWRITE));
1752 g_object_class_install_property(object_class,
1753 PROP_WORD_SIZE,
1754 g_param_spec_int("word-size",
1755 "word-size",
1756 "Word size in bits",
1757 8, 64, 64,
1758 G_PARAM_READWRITE));
1759 g_object_class_install_property(object_class,
1760 PROP_ANGLE_UNITS,
1761 g_param_spec_enum("angle-units",
1762 "angle-units",
1763 "Angle units",
1764 angle_unit_type,
1765 MP_DEGREES,
1766 G_PARAM_READWRITE));
1767 g_object_class_install_property(object_class,
1768 PROP_SOURCE_CURRENCY,
1769 g_param_spec_string("source-currency",
1770 "source-currency",
1771 "Source Currency",
1772 "",
1773 G_PARAM_READWRITE));
1774 g_object_class_install_property(object_class,
1775 PROP_TARGET_CURRENCY,
1776 g_param_spec_string("target-currency",
1777 "target-currency",
1778 "target Currency",
1779 "",
1780 G_PARAM_READWRITE));
1781 g_object_class_install_property(object_class,
1782 PROP_SOURCE_UNITS,
1783 g_param_spec_string("source-units",
1784 "source-units",
1785 "Source Units",
1786 "",
1787 G_PARAM_READWRITE));
1788 g_object_class_install_property(object_class,
1789 PROP_TARGET_UNITS,
1790 g_param_spec_string("target-units",
1791 "target-units",
1792 "target Units",
1793 "",
1794 G_PARAM_READWRITE));
1795 g_object_class_install_property(object_class,
1796 PROP_SERIALIZER,
1797 g_param_spec_object("serializer",
1798 "serializer",
1799 "Serializer",
1800 MP_TYPE_SERIALIZER(mp_serializer_get_type()),
1801 G_PARAM_READABLE));
1802}
1803
1804
1805static void
1806pre_insert_text_cb (MathEquation *equation,
1807 CtkTextIter *location,
1808 gchar *text,
1809 gint len G_GNUC_UNUSED__attribute__ ((__unused__)),
1810 gpointer user_data G_GNUC_UNUSED__attribute__ ((__unused__)))
1811{
1812 gunichar c;
1813 gint cursor;
1814
1815 if (equation->priv->in_reformat)
1816 return;
1817
1818 /* If following a delete then have already pushed undo stack (CtkTextBuffer
1819 doesn't indicate replace operations so we have to infer them) */
1820 if (!equation->priv->in_delete)
1821 math_equation_push_undo_stack(equation);
1822
1823 /* Clear result on next digit entered if cursor at end of line */
1824 c = g_utf8_get_char(text);
1825 g_object_get(G_OBJECT(equation)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), (((GType) ((20) << (2))))))))
, "cursor-position", &cursor, NULL((void*)0));
1826 if ((g_unichar_isdigit(c) || c == mp_serializer_get_radix(equation->priv->serializer)) &&
1827 math_equation_is_result(equation) &&
1828 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 ()))))))
)) {
1829 ctk_text_buffer_set_text(CTK_TEXT_BUFFER(equation)((((CtkTextBuffer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), ((ctk_text_buffer_get_type ()))))))
, "", -1);
1830 clear_ans(equation, FALSE(0));
1831 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);
1832 }
1833
1834 if (equation->priv->ans_start) {
1835 gint ans_start, ans_end;
1836 gint offset;
1837
1838 offset = ctk_text_iter_get_offset(location);
1839 get_ans_offsets(equation, &ans_start, &ans_end);
1840
1841 /* Inserted inside ans */
1842 if (offset > ans_start && offset < ans_end)
1843 clear_ans(equation, TRUE(!(0)));
1844 }
1845}
1846
1847
1848static gboolean
1849on_delete(MathEquation *equation)
1850{
1851 equation->priv->in_delete = FALSE(0);
1852 return FALSE(0);
1853}
1854
1855
1856static void
1857pre_delete_range_cb(MathEquation *equation,
1858 CtkTextIter *start,
1859 CtkTextIter *end,
1860 gpointer user_data G_GNUC_UNUSED__attribute__ ((__unused__)))
1861{
1862 if (equation->priv->in_reformat)
1863 return;
1864
1865 math_equation_push_undo_stack(equation);
1866
1867 equation->priv->in_delete = TRUE(!(0));
1868 g_idle_add((GSourceFunc)on_delete, equation);
1869
1870 if (equation->priv->ans_start) {
1871 gint ans_start, ans_end;
1872 gint start_offset, end_offset;
1873
1874 start_offset = ctk_text_iter_get_offset(start);
1875 end_offset = ctk_text_iter_get_offset(end);
1876 get_ans_offsets(equation, &ans_start, &ans_end);
1877
1878 /* Deleted part of ans */
1879 if (start_offset < ans_end && end_offset > ans_start)
1880 clear_ans(equation, TRUE(!(0)));
1881 }
1882}
1883
1884
1885static void
1886insert_text_cb(MathEquation *equation,
1887 CtkTextIter *location G_GNUC_UNUSED__attribute__ ((__unused__)),
1888 gchar *text,
1889 gint len G_GNUC_UNUSED__attribute__ ((__unused__)),
1890 gpointer user_data G_GNUC_UNUSED__attribute__ ((__unused__)))
1891{
1892 if (equation->priv->in_reformat)
1893 return;
1894
1895 equation->priv->state.entered_multiply = strcmp(text, "×") == 0;
1896
1897 /* Update thousands separators */
1898 reformat_separators(equation);
1899
1900 g_object_notify(G_OBJECT(equation)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), (((GType) ((20) << (2))))))))
, "display");
1901}
1902
1903
1904static void
1905delete_range_cb (MathEquation *equation,
1906 CtkTextIter *start G_GNUC_UNUSED__attribute__ ((__unused__)),
1907 CtkTextIter *end G_GNUC_UNUSED__attribute__ ((__unused__)),
1908 gpointer user_data G_GNUC_UNUSED__attribute__ ((__unused__)))
1909{
1910 if (equation->priv->in_reformat)
1911 return;
1912
1913 equation->priv->state.entered_multiply = FALSE(0);
1914
1915 /* Update thousands separators */
1916 reformat_separators(equation);
1917
1918 // FIXME: A replace will emit this both for delete-range and insert-text, can it be avoided?
1919 g_object_notify(G_OBJECT(equation)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((equation)), (((GType) ((20) << (2))))))))
, "display");
1920}
1921
1922
1923static void
1924math_equation_init(MathEquation *equation)
1925{
1926 /* Digits localized for the given language */
1927 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");
1928 const char *default_digits[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"};
1929 gchar **digits;
1930 /* Default to using untranslated digits, this is because it doesn't make sense in most languages and we need to make this optional.
1931 * See https://bugzilla.gnome.org/show_bug.cgi?id=632661 */
1932 gboolean use_default_digits = TRUE(!(0));
1933 int i;
1934
1935 equation->priv = math_equation_get_instance_private (equation);
1936
1937 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)
;
1938 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)
;
1939 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
)
;
1940 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
)
;
1941
1942 digits = g_strsplit(digit_values, ",", -1);
1943 for (i = 0; i < 16; i++) {
1944 if (use_default_digits || digits[i] == NULL((void*)0)) {
1945 use_default_digits = TRUE(!(0));
1946 equation->priv->digits[i] = g_utf8_get_char(default_digits[i]);
1947 }
1948 else
1949 equation->priv->digits[i] = g_utf8_get_char(digits[i]);
1950 }
1951 g_strfreev(digits);
1952
1953 equation->priv->variables = math_variables_new();
1954
1955 equation->priv->state.status = g_strdup("")g_strdup_inline ("");
1956 equation->priv->word_size = 32;
1957 equation->priv->angle_units = MP_DEGREES;
1958 // FIXME: Pick based on locale
1959 equation->priv->source_currency = g_strdup("")g_strdup_inline ("");
1960 equation->priv->target_currency = g_strdup("")g_strdup_inline ("");
1961 equation->priv->source_units = g_strdup("")g_strdup_inline ("");
1962 equation->priv->target_units = g_strdup("")g_strdup_inline ("");
1963 equation->priv->serializer = mp_serializer_new(MP_DISPLAY_FORMAT_AUTOMATIC, 10, 9);
1964 equation->priv->queue = g_async_queue_new();
1965
1966 mp_set_from_integer(0, &equation->priv->state.ans);
1967}