~ubuntu-branches/ubuntu/lucid/gcalctool/lucid-updates

« back to all changes in this revision

Viewing changes to src/display.c

  • Committer: Bazaar Package Importer
  • Author(s): Robert Ancell
  • Date: 2010-04-07 19:41:56 UTC
  • mfrom: (1.3.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20100407194156-hgj8g002ffce2de0
Tags: 5.30.0.is.5.28.2-0ubuntu1
Downgrade to 5.28.2 as the new version does not support number bases
as well.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*  Copyright (c) 1987-2008 Sun Microsystems, Inc. All Rights Reserved.
2
 
 *  Copyright (c) 2008-2009 Robert Ancell
 
1
 
 
2
/*  $Header$
3
3
 *
 
4
 *  Copyright (c) 1987-2008 Sun Microsystems, Inc. All Rights Reserved.
 
5
 *  Copyright (c) 2008 Robert Ancell
 
6
 *           
4
7
 *  This program is free software; you can redistribute it and/or modify
5
8
 *  it under the terms of the GNU General Public License as published by
6
9
 *  the Free Software Foundation; either version 2, or (at your option)
7
10
 *  any later version.
8
 
 *
9
 
 *  This program is distributed in the hope that it will be useful, but
 
11
 *           
 
12
 *  This program is distributed in the hope that it will be useful, but 
10
13
 *  WITHOUT ANY WARRANTY; without even the implied warranty of
11
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 
14
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
12
15
 *  General Public License for more details.
13
 
 *
 
16
 *           
14
17
 *  You should have received a copy of the GNU General Public License
15
18
 *  along with this program; if not, write to the Free Software
16
19
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20
23
#include <stdlib.h>
21
24
#include <stdio.h>
22
25
#include <string.h>
23
 
#include <ctype.h>
24
26
#include <math.h>
25
27
#include <errno.h>
 
28
#include <assert.h>
26
29
#include <glib.h>
27
30
 
28
31
#include "display.h"
29
32
 
 
33
#include "get.h"
30
34
#include "mp.h"
 
35
#include "functions.h"
31
36
#include "ui.h"
32
 
#include "mp-equation.h"
 
37
#include "mp-equation.h" // For mp_equation_parse()
33
38
#include "register.h"
34
 
#include "currency.h"
 
39
 
 
40
static const char *display_types[] = { "ENG", "FIX", "SCI", NULL };
35
41
 
36
42
static GCDisplayState *
37
43
get_state(GCDisplay *display)
39
45
    return &(display->h.e[display->h.current]);
40
46
}
41
47
 
 
48
static gboolean
 
49
exp_has_postfix(char *str, char *postfix)
 
50
{
 
51
    int len, plen;
 
52
 
 
53
    if (!str) {
 
54
        return FALSE;
 
55
    }
 
56
 
 
57
    assert(postfix);
 
58
 
 
59
    len = strlen(str);
 
60
    plen = strlen(postfix);
 
61
 
 
62
    if (plen > len) {
 
63
        return FALSE;
 
64
    }
 
65
 
 
66
    return strcasecmp(str + len - plen, postfix) == 0;
 
67
}
 
68
 
 
69
static char *
 
70
str_replace(char *str, char *from, char *to)
 
71
{
 
72
    char output[MAX_DISPLAY];
 
73
    int offset = 0;
 
74
    char *c;
 
75
    int flen = strlen(from);
 
76
    int tlen = strlen(to);
 
77
    
 
78
    for (c = str; *c && offset < MAX_DISPLAY - 1; c++, offset++) {
 
79
        if (strncasecmp(from, c, flen) == 0) {
 
80
            SNPRINTF(output + offset, MAX_DISPLAY - offset, "%s", to);
 
81
            c += flen - 1;
 
82
            offset += tlen - 1;
 
83
        } else {
 
84
            output[offset] = *c;
 
85
        }
 
86
    }
 
87
 
 
88
    if (offset >= MAX_DISPLAY)
 
89
        offset = MAX_DISPLAY - 1;
 
90
    output[offset] = '\0';
 
91
    
 
92
    free(str);
 
93
    
 
94
    return strdup(output);
 
95
}
42
96
 
43
97
/* Add in the thousand separators characters if required and if we are
44
98
 * currently in the decimal numeric base, use the "right" radix character.
46
100
 
47
101
/* Add in the thousand separators characters if required */
48
102
static void
49
 
localize_expression(GCDisplay *display, char *dest, const char *src, int dest_length, int *cursor)
 
103
localize_expression(char *dest, const char *src, int dest_length, int *cursor)
50
104
{
51
105
    GString *output;
52
106
    const char *c, *d;
53
107
    int digit_count = -1, read_cursor, new_cursor;
54
108
    gboolean after_radix = FALSE;
55
 
 
 
109
    
56
110
    if (cursor) {
57
111
        new_cursor = *cursor;
58
112
    } else {
71
125
                    digit_count++;
72
126
                }
73
127
            }
74
 
 
 
128
            
75
129
            g_string_append_unichar(output, g_utf8_get_char(c));
76
 
 
 
130
            
77
131
            /* Insert separator after nth digit */
78
 
            if (display->show_tsep && display->format == DEC &&
 
132
            if (v->display.show_tsep && v->base == 10 &&
79
133
                !after_radix && digit_count > 1 && digit_count % v->tsep_count == 1) {
80
134
                g_string_append(output, v->tsep);
81
135
                if (new_cursor > read_cursor) {
99
153
            g_string_append_unichar(output, g_utf8_get_char(c));
100
154
        }
101
155
    }
102
 
 
 
156
    
103
157
    STRNCPY(dest, output->str, dest_length - 1);
104
158
    g_string_free(output, TRUE);
105
 
 
 
159
    
106
160
    if (cursor != NULL && *cursor != -1) {
107
161
        *cursor = new_cursor;
108
162
    }
112
166
void
113
167
display_clear(GCDisplay *display)
114
168
{
115
 
    GCDisplayState *state;
116
 
 
117
 
    state = get_state(display);
 
169
    v->error = 0;
118
170
    display_set_string(display, "", -1);
119
 
    state->ans_start = -1;
120
 
    state->ans_end = -1;
121
171
}
122
172
 
123
173
 
124
 
static const char *
125
 
get_text(GCDisplay *display)
 
174
const char *
 
175
display_get_text(GCDisplay *display)
126
176
{
127
177
    return get_state(display)->expression;
128
178
}
129
179
 
130
180
 
131
 
static char *
132
 
get_expression(GCDisplay *display)
133
 
{
134
 
    GCDisplayState *state;
135
 
 
136
 
    state = get_state(display);
137
 
    if(state->ans_start >= 0)
138
 
        return g_strdup_printf("%.*sans%s", state->ans_start, state->expression, g_utf8_offset_to_pointer(state->expression, state->ans_end));
139
 
    else
140
 
        return g_strdup(state->expression);
141
 
}
142
 
 
143
 
 
144
 
gboolean
145
 
display_get_integer(GCDisplay *display, gint64 *value)
146
 
{
147
 
    MPNumber t, min, max;
148
 
 
149
 
    if (!display_is_usable_number(display, &t))
150
 
        return FALSE;
151
 
 
152
 
    mp_set_from_integer(G_MININT64, &min);
153
 
    mp_set_from_integer(G_MAXINT64, &max);
154
 
    if (mp_is_less_than(&t, &min) || mp_is_greater_than(&t, &max))
155
 
        return FALSE;
156
 
 
157
 
    *value = mp_cast_to_int(&t);
158
 
    return TRUE;
159
 
}
160
 
 
161
 
 
162
 
gboolean
163
 
display_get_unsigned_integer(GCDisplay *display, guint64 *value)
164
 
{
165
 
    MPNumber t, max;
166
 
 
167
 
    if (!display_is_usable_number(display, &t))
168
 
        return FALSE;
169
 
  
170
 
    mp_set_from_unsigned_integer(G_MAXUINT64, &max);
171
 
    char string[MAX_DIGITS];
172
 
    if (mp_is_negative(&t) || mp_is_greater_than(&t, &max))
173
 
        return FALSE;
174
 
 
175
 
    *value = mp_cast_to_unsigned_int(&t);
176
 
    return TRUE;
177
 
}
178
 
 
179
 
 
180
 
MPNumber *
181
 
display_get_answer(GCDisplay *display)
 
181
gboolean display_get_integer(GCDisplay *display, gint64 *value)
 
182
{
 
183
    const char *text;
 
184
    char buf[MAX_DISPLAY];
 
185
    gchar *endptr;
 
186
    guint bases[] = {2, 8, 10, 16};
 
187
 
 
188
    text = display_get_text(display);
 
189
    if (text[0] == '\0') {
 
190
        text = "0";
 
191
    }
 
192
    else if (display_is_result(display)) {
 
193
        display_make_number(display, buf, MAX_DISPLAY, display_get_answer(display), v->base, FALSE);
 
194
        text = buf;
 
195
    }
 
196
    
 
197
    *value = g_ascii_strtoll(text, &endptr, bases[v->base]);
 
198
    if(*endptr != '\0' || ((*value == G_MAXINT64 || *value == G_MININT64) && errno == ERANGE))
 
199
        return FALSE;
 
200
    return TRUE;
 
201
}
 
202
 
 
203
 
 
204
gboolean display_get_unsigned_integer(GCDisplay *display, guint64 *value)
 
205
{
 
206
    const char *text;
 
207
    char buf[MAX_DISPLAY];
 
208
    gchar *endptr;
 
209
 
 
210
    text = display_get_text(display);
 
211
    if (text[0] == '\0') {
 
212
        text = "0";
 
213
    }
 
214
    else if (display_is_result(display)) {
 
215
        display_make_number(display, buf, MAX_DISPLAY, display_get_answer(display), v->base, FALSE);
 
216
        text = buf;
 
217
    }
 
218
    
 
219
    /* strtoull() treats the string like a 2's complement number which is not what we want */
 
220
    if(strncmp(text, "-", strlen("-")) == 0 || strncmp(text, "−", strlen("−")) == 0)
 
221
        return FALSE;
 
222
 
 
223
    *value = g_ascii_strtoull(text, &endptr, v->base);
 
224
    if(*endptr != '\0' || (*value == G_MAXUINT64 && errno == ERANGE))
 
225
        return FALSE;
 
226
    return TRUE;
 
227
}
 
228
 
 
229
 
 
230
MPNumber *display_get_answer(GCDisplay *display)
182
231
{
183
232
    return &get_state(display)->ans;
184
233
}
191
240
}
192
241
 
193
242
 
194
 
// FIXME: Looses accuracy
195
243
void
196
 
display_set_number(GCDisplay *display, const MPNumber *x)
 
244
display_set_number(GCDisplay *display, const MPNumber *MPval)
197
245
{
198
 
    char text[MAX_DISPLAY];
199
 
    int enabled;
200
 
    guint64 bit_value;
201
 
 
202
 
    display_make_number(display, text, MAX_DISPLAY, x);
203
 
    display_set_string(display, text, -1);
204
 
 
205
 
    enabled = display_get_unsigned_integer(display, &bit_value);
206
 
    ui_set_bitfield(enabled, bit_value);
 
246
   char text[MAX_DISPLAY];
 
247
   display_make_number(display, text, MAX_DISPLAY, MPval, v->base, FALSE);
 
248
   display_set_string(display, text, -1);
207
249
}
208
250
 
209
251
 
210
252
void
211
253
display_set_answer(GCDisplay *display)
212
254
{
213
 
    GCDisplayState *state;
214
 
    char text[MAX_DISPLAY];
215
 
 
216
 
    state = get_state(display);
217
 
    display_make_number(display, text, MAX_DISPLAY, &state->ans);
218
 
    display_set_string(display, text, -1);
219
 
    state->ans_start = 0;
220
 
    state->ans_end = g_utf8_strlen(text, -1);
 
255
    display_set_string(display, "ans", -1);
221
256
}
222
257
 
223
258
 
224
259
static void
225
260
display_make_text(GCDisplay *display, char *localized, int length, int *cursor)
226
261
{
227
 
    char *str;
 
262
    int i;
 
263
    MPNumber MP_reg;
 
264
    char temp[MAX_LOCALIZED], *str, reg[3];
228
265
    GCDisplayState *e;
229
266
 
230
267
    e = get_state(display);
231
 
 
232
 
    /* Substitute answer register */
233
 
    if (display_is_result(display)) {
234
 
        char temp[MAX_LOCALIZED];
235
 
        display_make_number(display, temp, MAX_LOCALIZED, &e->ans);
 
268
    if (display_is_empty(display)) {
 
269
        mp_set_from_integer(0, &MP_reg);
 
270
        display_make_number(display, temp, MAX_LOCALIZED, &MP_reg, v->base, FALSE);
236
271
        str = strdup(temp);
237
 
    }
238
 
    else
 
272
    } else {           
239
273
        str = strdup(e->expression);
240
 
 
241
 
    localize_expression(display, localized, str, length, cursor);
 
274
    }
 
275
        
 
276
    /* Substitute answer register */
 
277
    display_make_number(display, temp, MAX_LOCALIZED, &e->ans, v->base, TRUE);
 
278
    str = str_replace(str, "ans", temp);
 
279
 
 
280
    /* Replace registers with values. */
 
281
    for (i = 0; i < 10; i++) {
 
282
        SNPRINTF(reg, 3, "R%d", i);
 
283
        register_get(i, &MP_reg);
 
284
        display_make_number(display, temp, MAX_LOCALIZED, &MP_reg, v->base, FALSE);
 
285
        str = str_replace(str, reg, temp);
 
286
    }
 
287
 
 
288
    localize_expression(localized, str, length, cursor);
242
289
    free(str);
243
290
}
244
291
 
248
295
{
249
296
    char localized[MAX_LOCALIZED];
250
297
    int cursor;
251
 
 
 
298
    
252
299
    cursor = display_get_cursor(display);
253
300
    display_make_text(display, localized, MAX_LOCALIZED, &cursor);
254
301
    ui_set_display(localized, cursor);
259
306
display_set_string(GCDisplay *display, const char *value, int cursor)
260
307
{
261
308
    GCDisplayState *e;
262
 
 
 
309
    
263
310
    if (value[0] == '\0')
264
311
        cursor = -1;
265
 
 
 
312
    
266
313
    e = get_state(display);
267
314
    free(e->expression);
268
315
    e->expression = strdup(value);
269
316
    e->cursor = cursor;
270
 
 
 
317
    
271
318
    display_refresh(display);
272
319
}
273
320
 
286
333
void
287
334
display_set_error(GCDisplay *display, const char *message)
288
335
{
289
 
    ui_set_statusbar(message);
290
 
}
291
 
 
292
 
 
293
 
void
294
 
display_convert(GCDisplay *display, DisplayFormat format)
295
 
{
296
 
    DisplayFormat old_format;
297
 
 
298
 
    if (!display_is_result (display))
299
 
        return;
300
 
 
301
 
    /* FIXME: A bit hacky... */
302
 
    old_format = display->format;
303
 
    display->format = format;
304
 
    display_set_answer(display);
305
 
    display->format = old_format;
 
336
    ui_set_statusbar(message, "gtk-dialog-error");
306
337
}
307
338
 
308
339
 
332
363
}
333
364
 
334
365
 
335
 
void
336
 
display_clear_stack(GCDisplay *display)
 
366
void display_clear_stack(GCDisplay *display)
337
367
{
338
368
    int i = display->h.begin;
339
369
    while (i != display->h.end) {
348
378
}
349
379
 
350
380
 
351
 
void
352
 
display_push(GCDisplay *display)
 
381
void display_push(GCDisplay *display)
353
382
{
354
383
    int c;
355
 
 
 
384
    
356
385
    if (display->h.current != display->h.end) {
357
386
        int i = display->h.current;
358
387
 
359
388
        do {
360
389
            i = ((i + 1) % UNDO_HISTORY_LENGTH);
361
390
            free(display->h.e[i].expression);
362
 
            display->h.e[i].expression = strdup("ans"); // FIXME: Use actual number
363
 
            display->h.e[i].ans_start = -1;
364
 
            display->h.e[i].ans_end = -1;
 
391
            display->h.e[i].expression = strdup("ans");
365
392
        } while (i != display->h.end);
366
393
    }
367
394
 
380
407
}
381
408
 
382
409
 
383
 
void
384
 
display_pop(GCDisplay *display)
 
410
void display_pop(GCDisplay *display)
385
411
{
386
412
    if (display->h.current != display->h.begin) {
387
413
        display->h.current = ((display->h.current - 1) % UNDO_HISTORY_LENGTH);
388
 
        ui_set_statusbar("");
 
414
        ui_set_statusbar("", "");
389
415
    } else {
390
 
        ui_set_statusbar(_("No undo history"));
 
416
        ui_set_statusbar(_("No undo history"), "gtk-dialog-warning");
391
417
    }
392
418
    update_undo_redo_button_sensitivity(display);
393
 
 
 
419
    
394
420
    display_refresh(display);
395
421
}
396
422
 
400
426
{
401
427
    if (display->h.current != display->h.end) {
402
428
        display->h.current = ((display->h.current + 1) % UNDO_HISTORY_LENGTH);
403
 
        ui_set_statusbar("");
 
429
        ui_set_statusbar("", "");
404
430
    } else {
405
 
        ui_set_statusbar(_("No redo steps"));
 
431
        ui_set_statusbar(_("No redo steps"), "gtk-dialog-warning");
406
432
    }
407
433
    update_undo_redo_button_sensitivity(display);
408
434
    get_state(display)->cursor = -1;
420
446
void
421
447
display_insert(GCDisplay *display, int cursor_start, int cursor_end, const char *text)
422
448
{
423
 
    GCDisplayState *state;   
424
449
    char buf[MAX_DISPLAY];
425
 
 
426
 
    state = get_state(display);
427
 
 
428
 
    /* If inside ans variable then modify number */
429
 
    if (state->ans_start >= 0 && cursor_start >= state->ans_start && cursor_start <= state->ans_end) {
430
 
        state->ans_start = -1;
431
 
        state->ans_end = -1;
432
 
    }
433
 
 
 
450
    
434
451
    if (cursor_start < 0) {
435
 
        SNPRINTF(buf, MAX_DISPLAY, "%s%s", get_text(display), text);
 
452
        SNPRINTF(buf, MAX_DISPLAY, "%s%s", display_get_text(display), text);
436
453
        display_set_string(display, buf, -1);
437
454
    } else {
438
455
        GString *new_text;
439
456
        const char *c;
440
457
        gint cursor, new_cursor;
441
 
 
 
458
        
442
459
        /* Get display text and strip out thousand separators */
443
460
        new_text = g_string_new("");
444
461
        new_cursor = 0;
446
463
            g_string_append(new_text, text);
447
464
            new_cursor += g_utf8_strlen(text, -1);
448
465
        }
449
 
 
 
466
        
450
467
        cursor = 0;
451
468
        for (c = ui_get_display(); *c; c = g_utf8_next_char(c), cursor++) {
452
469
            gboolean use = TRUE;
453
 
 
 
470
            
454
471
            /* Ignore selected part */
455
472
            if (cursor_start != cursor_end && cursor >= cursor_start && cursor < cursor_end)
456
473
                use = FALSE;
457
 
 
458
 
            /* Ignore thousands separators (if one exists) */
 
474
            
 
475
            /* Ignore thousands separators */
459
476
            if (v->tsep[0] != '\0' && strncmp(c, v->tsep, strlen(v->tsep)) == 0)
460
477
                use = FALSE;
461
 
 
 
478
            
462
479
            /* Copy existing text */
463
480
            if (use) {
464
481
                g_string_append_unichar(new_text, g_utf8_get_char(c));
465
482
                if (cursor < cursor_start)
466
483
                    new_cursor++;
467
484
            }
468
 
 
 
485
            
469
486
            /* Insert text */
470
487
            if ((cursor + 1) == cursor_start) {
471
488
                g_string_append(new_text, text);
483
500
display_insert_number(GCDisplay *display, int cursor_start, int cursor_end, const MPNumber *value)
484
501
{
485
502
    char text[MAX_DISPLAY];
486
 
    display_make_number(display, text, MAX_DISPLAY, value);
 
503
    display_make_number(display, text, MAX_DISPLAY, value, v->base, FALSE);
487
504
    display_insert(display, cursor_start, cursor_end, text);
488
505
}
489
506
 
491
508
void
492
509
display_backspace(GCDisplay *display, int cursor_start, int cursor_end)
493
510
{
494
 
    int cursor;
495
 
 
 
511
    char buf[MAX_DISPLAY] = "", buf2[MAX_DISPLAY];
 
512
    GCDisplayState *e = get_state(display);
 
513
    int i, cursor;
 
514
    MPNumber MP_reg;
 
515
    
496
516
    /* Can't delete empty display */
497
517
    if (display_is_empty(display))
498
518
        return;
499
519
 
500
520
    cursor = display_get_cursor(display);
501
 
 
 
521
    
502
522
    /* If cursor is at end of the line then delete the last character preserving accuracy */
503
523
    if (cursor_start < 0) {
504
524
        int len;
 
525
        
505
526
        len = g_utf8_strlen(ui_get_display(), -1);
 
527
        
 
528
        if (exp_has_postfix(e->expression, "ans")) {
 
529
            display_make_number(display, buf, MAX_DISPLAY, &e->ans, v->base, FALSE);
 
530
            e->expression = str_replace(e->expression, "ans", buf);
 
531
        } else {
 
532
            for (i = 0; i < 10; i++) {
 
533
                SNPRINTF(buf, MAX_DISPLAY, "R%d", i);
 
534
                if (exp_has_postfix(e->expression, buf)) {
 
535
                    register_get(i, &MP_reg);
 
536
                    display_make_number(display, buf2, MAX_DISPLAY, &MP_reg, v->base, FALSE);
 
537
                    SNPRINTF(buf, MAX_DISPLAY, "%.*s%s", strlen(e->expression) - 2, e->expression - 2, buf2);
 
538
                    break;
 
539
                }
 
540
            }
 
541
        }
 
542
        
506
543
        display_insert(display, len - 1, len, "");
507
544
    } else if (cursor_start != cursor_end) {
508
545
        display_insert(display, cursor_start, cursor_end, "");
523
560
}
524
561
 
525
562
 
 
563
void
 
564
display_surround(GCDisplay *display, const char *prefix, const char *suffix)
 
565
{
 
566
    char buffer[MAX_DISPLAY];
 
567
    
 
568
    SNPRINTF(buffer, MAX_DISPLAY, "%s%s%s", prefix, display_get_text(display), suffix);
 
569
    display_set_string(display, buffer, -1);
 
570
}
 
571
 
 
572
 
526
573
gboolean
527
574
display_is_empty(GCDisplay *display)
528
575
{
529
 
    return strcmp(get_text(display), "") == 0;
 
576
    return strcmp(display_get_text(display), "") == 0;
530
577
}
531
578
 
532
579
 
533
580
gboolean
534
581
display_is_result(GCDisplay *display)
535
582
{
536
 
    GCDisplayState *state;
537
 
 
538
 
    state = get_state(display);
539
 
    if (state->ans_start == 0 && state->ans_end == g_utf8_strlen(state->expression, -1))
 
583
    if (strcmp(display_get_text(display), "ans") == 0)
540
584
        return TRUE;
541
 
 
 
585
    
542
586
    return FALSE;
543
587
}
544
588
 
553
597
        mp_set_from_mp(display_get_answer(display), z);
554
598
        return TRUE;
555
599
    } else {
556
 
        return mp_set_from_string(get_text(display), z) == 0;
557
 
    }
558
 
}
559
 
 
560
 
 
561
 
gboolean
562
 
display_is_number_with_base(GCDisplay *display)
563
 
{
564
 
    MPNumber t;
565
 
    const char *text;
566
 
    const char *sub_digits[] = { "₀", "₁", "₂", "₃", "₄", "₅", "₆", "₇", "₈", "₉", NULL };
567
 
    int i;
568
 
 
569
 
    if (display_is_empty(display))
570
 
        return FALSE;
571
 
 
572
 
    if (display_is_result(display))
573
 
        return (display->format == BIN || display->format == OCT || display->format == HEX);
574
 
 
575
 
    /* See if it has a subscript suffix */
576
 
    text = get_text(display);
577
 
    text += strlen (text);
578
 
    for (i = 0; sub_digits[i] != NULL; i++) {
579
 
        if (strcmp (text - strlen (sub_digits[i]), sub_digits[i]) == 0)
580
 
            return mp_set_from_string(get_text(display), &t) == 0;
581
 
    }
582
 
 
583
 
    return FALSE;
 
600
        return mp_set_from_string(display_get_text(display), v->base, z) == 0;
 
601
    }
584
602
}
585
603
 
586
604
 
588
606
display_init(GCDisplay *display)
589
607
{
590
608
    int i;
591
 
 
 
609
   
592
610
    memset(display, 0, sizeof(GCDisplay));
593
 
 
594
 
    display->show_zeroes = FALSE;
595
 
    display->show_tsep = FALSE;
596
 
    display->format = DEC;
597
 
    display->accuracy = 9;
598
 
    display->word_size = 32;
599
 
    display->angle_unit = MP_DEGREES;
600
 
 
601
 
    for (i = 0; i < UNDO_HISTORY_LENGTH; i++) {
 
611
   
 
612
    display->base = 10;
 
613
 
 
614
    if (get_boolean_resource(R_ZEROES, &i))
 
615
        display->show_zeroes = i;
 
616
    else
 
617
        display->show_zeroes = FALSE;         
 
618
 
 
619
    if (get_boolean_resource(R_TSEP, &i))
 
620
        display->show_tsep = i;
 
621
    else
 
622
        display->show_tsep = FALSE;
 
623
 
 
624
    if (get_enumerated_resource(R_DISPLAY, display_types, &i))
 
625
       display->format = (DisplayFormat) i;
 
626
    else
 
627
       display->format = FIX;
 
628
 
 
629
    for (i = 0; i < UNDO_HISTORY_LENGTH; i++)
602
630
        display->h.e[i].expression = strdup("");
603
 
        display->h.e[i].ans_start = -1;
604
 
        display->h.e[i].ans_end = -1;
605
 
    }
606
631
}
607
632
 
608
633
 
609
 
void
610
 
display_set_accuracy(GCDisplay *display, int accuracy)
 
634
void display_set_accuracy(GCDisplay *display, int accuracy)
611
635
{
612
 
    display->accuracy = accuracy;
 
636
    set_int_resource(R_ACCURACY, accuracy);
613
637
    get_state(display)->cursor = -1;
614
 
    display_refresh(display);
 
638
    display_refresh(display);   
615
639
}
616
640
 
617
641
 
618
 
void
619
 
display_set_show_thousands_separator(GCDisplay *display, gboolean visible)
 
642
void display_set_show_thousands_separator(GCDisplay *display, gboolean visible)
620
643
{
621
644
    display->show_tsep = visible;
 
645
    set_boolean_resource(R_TSEP, visible);
622
646
    display_set_cursor(display, -1);
623
647
    display_refresh(display);
624
648
}
625
649
 
626
650
 
627
 
void
628
 
display_set_show_trailing_zeroes(GCDisplay *display, gboolean visible)
 
651
void display_set_show_trailing_zeroes(GCDisplay *display, gboolean visible)
629
652
{
630
653
    display->show_zeroes = visible;
631
 
    get_state(display)->cursor = -1;
632
 
    display_refresh(display);
633
 
}
634
 
 
635
 
 
636
 
void
637
 
display_set_format(GCDisplay *display, DisplayFormat format)
638
 
{
639
 
    display->format = format;
640
 
    get_state(display)->cursor = -1;
641
 
    display_refresh(display);
642
 
}
643
 
 
644
 
 
645
 
void
646
 
display_set_word_size(GCDisplay *display, int word_size)
647
 
{
648
 
    display->word_size = word_size;
649
 
}
650
 
 
651
 
 
652
 
void
653
 
display_set_angle_unit(GCDisplay *display, MPAngleUnit angle_unit)
654
 
{
655
 
    display->angle_unit = angle_unit;
 
654
    set_boolean_resource(R_ZEROES, visible);
 
655
    get_state(display)->cursor = -1;
 
656
    display_refresh(display);
 
657
}
 
658
 
 
659
 
 
660
void display_set_base(GCDisplay *display, int base)
 
661
{
 
662
    display->base = base;
 
663
    get_state(display)->cursor = -1;
 
664
    display_refresh(display);
 
665
}
 
666
 
 
667
 
 
668
void display_set_format(GCDisplay *display, DisplayFormat type)
 
669
{
 
670
    v->display.format = type;
 
671
    set_enumerated_resource(R_DISPLAY, display_types, (int) type);
 
672
    get_state(display)->cursor = -1;
 
673
    display_refresh(display);
656
674
}
657
675
 
658
676
 
659
677
/* Convert engineering or scientific number in the given base. */
660
678
static void
661
 
make_eng_sci(GCDisplay *display, char *target, int target_len, const MPNumber *x, int base_)
 
679
make_eng_sci(GCDisplay *display, char *target, int target_len, const MPNumber *MPnumber, int base)
662
680
{
663
 
    char fixed[MAX_DIGITS], *c;
664
 
    MPNumber t, z, base, base3, base10, base10inv, mantissa;
665
 
    int eng, exponent = 0;
666
 
    GString *string;
667
 
    const char *super_digits[] = {"⁰", "¹", "²", "³", "⁴", "⁵", "⁶", "⁷", "⁸", "⁹"};
668
 
 
669
 
    string = g_string_sized_new(target_len);
670
 
 
671
 
    eng = display->format == ENG;
672
 
 
673
 
    mp_abs(x, &z);
674
 
    if (mp_is_negative(x))
675
 
        g_string_append(string, "−");
676
 
    mp_set_from_mp(&z, &mantissa);
677
 
 
678
 
    mp_set_from_integer(base_, &base);
679
 
    mp_xpowy_integer(&base, 3, &base3);
680
 
    mp_xpowy_integer(&base, 10, &base10);
681
 
    mp_set_from_integer(1, &t);
682
 
    mp_divide(&t, &base10, &base10inv);
683
 
 
684
 
    if (!mp_is_zero(&mantissa)) {
685
 
        while (!eng && mp_is_greater_equal(&mantissa, &base10)) {
686
 
            exponent += 10;
687
 
            mp_multiply(&mantissa, &base10inv, &mantissa);
688
 
        }
689
 
 
690
 
        while ((!eng &&  mp_is_greater_equal(&mantissa, &base)) ||
691
 
                (eng && (mp_is_greater_equal(&mantissa, &base3) || exponent % 3 != 0))) {
692
 
            exponent += 1;
693
 
            mp_divide(&mantissa, &base, &mantissa);
694
 
        }
695
 
 
696
 
        while (!eng && mp_is_less_than(&mantissa, &base10inv)) {
697
 
            exponent -= 10;
698
 
            mp_multiply(&mantissa, &base10, &mantissa);
699
 
        }
700
 
 
701
 
        mp_set_from_integer(1, &t);
702
 
        while (mp_is_less_than(&mantissa, &t) || (eng && exponent % 3 != 0)) {
703
 
            exponent -= 1;
704
 
            mp_multiply(&mantissa, &base, &mantissa);
705
 
        }
706
 
    }
707
 
 
708
 
    mp_cast_to_string(&mantissa, base_, display->accuracy, !display->show_zeroes, fixed, MAX_DIGITS);
709
 
    g_string_append(string, fixed);
710
 
    g_string_append_printf(string, "×10");
711
 
    if (exponent < 0) {
712
 
        exponent = -exponent;
713
 
        g_string_append(string, "⁻");
714
 
    }
715
 
    snprintf(fixed, MAX_DIGITS, "%d", exponent);
716
 
    for (c = fixed; *c; c++)
717
 
        g_string_append(string, super_digits[*c - '0']);
718
 
 
719
 
    strncpy(target, string->str, target_len);
720
 
    g_string_free(string, TRUE);
 
681
    static char digits[] = "0123456789ABCDEF";   
 
682
    char fixed[MAX_DIGITS], *optr;
 
683
    MPNumber MP1, MPatmp, MPval;
 
684
    MPNumber MP1base, MP3base, MP10base;
 
685
    int i, dval, len;
 
686
    MPNumber MPmant;            /* Mantissa. */
 
687
    int ddig;                   /* Number of digits in exponent. */
 
688
    int eng = 0;                /* Set if this is an engineering number. */
 
689
    int exp = 0;                /* Exponent */
 
690
    
 
691
    if (display->format == ENG) {
 
692
        eng = 1;
 
693
    }
 
694
    optr = target;
 
695
    mp_abs(MPnumber, &MPval);
 
696
    mp_set_from_integer(0, &MP1);
 
697
    if (mp_is_less_than(MPnumber, &MP1)) {
 
698
        strcpy(optr, "−");
 
699
        optr += strlen("−");
 
700
    }
 
701
    mp_set_from_mp(&MPval, &MPmant);
 
702
 
 
703
    mp_set_from_integer(base, &MP1base);
 
704
    mp_xpowy_integer(&MP1base, 3, &MP3base);
 
705
    mp_xpowy_integer(&MP1base, 10, &MP10base);
 
706
 
 
707
    mp_set_from_integer(1, &MP1);
 
708
    mp_divide(&MP1, &MP10base, &MPatmp);
 
709
 
 
710
    mp_set_from_integer(0, &MP1);
 
711
    if (!mp_is_equal(&MPmant, &MP1)) {
 
712
        while (!eng && mp_is_greater_equal(&MPmant, &MP10base)) {
 
713
            exp += 10;
 
714
            mp_multiply(&MPmant, &MPatmp, &MPmant);
 
715
        }
 
716
 
 
717
        while ((!eng &&  mp_is_greater_equal(&MPmant, &MP1base)) ||
 
718
                (eng && (mp_is_greater_equal(&MPmant, &MP3base) || exp % 3 != 0))) {
 
719
            exp += 1;
 
720
            mp_divide(&MPmant, &MP1base, &MPmant);
 
721
        }
 
722
 
 
723
        while (!eng && mp_is_less_than(&MPmant, &MPatmp)) {
 
724
            exp -= 10;
 
725
            mp_multiply(&MPmant, &MP10base, &MPmant);
 
726
        }
 
727
 
 
728
        mp_set_from_integer(1, &MP1);
 
729
        while (mp_is_less_than(&MPmant, &MP1) || (eng && exp % 3 != 0)) {
 
730
            exp -= 1;
 
731
            mp_multiply(&MPmant, &MP1base, &MPmant);
 
732
        }
 
733
    }
 
734
 
 
735
    mp_cast_to_string(&MPmant, base, v->accuracy, !v->display.show_zeroes, fixed, MAX_DIGITS);
 
736
    len = strlen(fixed);
 
737
    for (i = 0; i < len; i++) {
 
738
        *optr++ = fixed[i];
 
739
    }
 
740
 
 
741
    *optr++ = 'e';
 
742
 
 
743
    if (exp < 0) {
 
744
        exp = -exp;
 
745
        strcpy(optr, "−");
 
746
        optr += strlen("−");
 
747
    } else {
 
748
        *optr++ = '+';
 
749
    }
 
750
 
 
751
    mp_set_from_string("0.5", 10, &MP1);
 
752
    mp_add_integer(&MP1, exp, &MPval);
 
753
    mp_set_from_integer(1, &MP1);
 
754
    for (ddig = 0; mp_is_greater_equal(&MPval, &MP1); ddig++) {
 
755
        mp_divide(&MPval, &MP1base, &MPval);
 
756
    }
 
757
 
 
758
    if (ddig == 0) {
 
759
        *optr++ = '0';
 
760
    }
 
761
 
 
762
    while (ddig-- > 0) {
 
763
        mp_multiply(&MPval, &MP1base, &MPval);
 
764
        dval = mp_cast_to_int(&MPval);
 
765
        *optr++ = digits[dval];
 
766
        dval = -dval;
 
767
        mp_add_integer(&MPval, dval, &MPval);
 
768
    }
 
769
    *optr++  = '\0';
721
770
}
722
771
 
723
772
 
724
 
/* Convert MP number to character string. */
 
773
/* Convert MP number to character string in the given base. */
725
774
void
726
 
display_make_number(GCDisplay *display, char *target, int target_len, const MPNumber *x)
727
 
{
728
 
    switch(display->format) {
729
 
    case DEC:
730
 
        mp_cast_to_string(x, 10, display->accuracy, !display->show_zeroes, target, target_len);
731
 
        break;
732
 
    case BIN:
733
 
        mp_cast_to_string(x, 2, display->accuracy, !display->show_zeroes, target, target_len);
734
 
        break;
735
 
    case OCT:
736
 
        mp_cast_to_string(x, 8, display->accuracy, !display->show_zeroes, target, target_len);
737
 
        break;
738
 
    case HEX:
739
 
        mp_cast_to_string(x, 16, display->accuracy, !display->show_zeroes, target, target_len);
740
 
        break;
741
 
    case SCI:
742
 
        make_eng_sci(display, target, target_len, x, 10);
743
 
        break;
744
 
    case ENG:
745
 
        make_eng_sci(display, target, target_len, x, 10);
746
 
        break;
747
 
    }
748
 
}
749
 
 
750
 
 
751
 
static int
752
 
variable_is_defined(const char *name)
753
 
{
754
 
    char *c, *lower_name;
755
 
 
756
 
    lower_name = strdup(name);
757
 
    for (c = lower_name; *c; c++)
758
 
        *c = tolower(*c);
759
 
 
760
 
    if (strcmp(lower_name, "rand") == 0 || 
761
 
        strcmp(lower_name, "ans") == 0) {
762
 
        g_free (lower_name);
763
 
        return 1;
764
 
    }
765
 
    g_free (lower_name);
766
 
 
767
 
    return register_get_value(name) != NULL;
768
 
}
769
 
 
770
 
 
771
 
static int
772
 
get_variable(const char *name, MPNumber *z, void *data)
773
 
{
774
 
    char *c, *lower_name;
775
 
    int result = 1;
776
 
    GCDisplay *display = data;
777
 
    MPNumber *t;
778
 
 
779
 
    lower_name = strdup(name);
780
 
    for (c = lower_name; *c; c++)
781
 
        *c = tolower(*c);
782
 
 
783
 
    if (strcmp(lower_name, "rand") == 0)
784
 
        mp_set_from_random(z);
785
 
    else if (strcmp(lower_name, "ans") == 0)
786
 
        mp_set_from_mp(display_get_answer(display), z);
787
 
    else {
788
 
        t = register_get_value(name);
789
 
        if (t)
790
 
            mp_set_from_mp(t, z);
791
 
        else
792
 
            result = 0;
793
 
    }
794
 
 
795
 
    free(lower_name);
796
 
 
797
 
    return result;
798
 
}
799
 
 
800
 
 
801
 
static void
802
 
set_variable(const char *name, const MPNumber *x, void *data)
803
 
{
804
 
    /* FIXME: Don't allow writing to built-in variables, e.g. ans, rand, sin, ... */
805
 
    register_set_value(name, x);
806
 
}
807
 
 
808
 
 
809
 
static int
810
 
convert(const MPNumber *x, const char *x_units, const char *z_units, MPNumber *z, void *data)
811
 
{   
812
 
    /* Update currency if necessary */
813
 
    if (currency_rates_needs_update())
814
 
        currency_download_rates();
815
 
    currency_load_rates();
816
 
    if (currency_get_index(x_units) >= 0 && currency_get_index(z_units) >= 0)
 
775
display_make_number(GCDisplay *display, char *target, int target_len, const MPNumber *x, int base, int ignoreError)
 
776
{
 
777
    double val, max_fix;
 
778
    
 
779
    /*  NOTE: display_make_number can currently set v->error when converting to a double.
 
780
     *        This is to provide the same look&feel as V3 even though gcalctool
 
781
     *        now does internal arithmetic to "infinite" precision.
 
782
     *
 
783
     *  XXX:  Needs to be improved. Shouldn't need to convert to a double in
 
784
     *        order to do these tests.
 
785
     */
 
786
 
 
787
    double number = mp_cast_to_double(x);
 
788
 
 
789
    val = fabs(number);
 
790
    if (v->error && !ignoreError) {
 
791
        target[0] = '\0';
 
792
        return;
 
793
    }
 
794
 
 
795
    switch (base)
817
796
    {
818
 
        currency_convert(x, currency_get_index(x_units), currency_get_index(z_units), z);
819
 
        return 1;
820
 
    }
821
 
 
822
 
    return 0;
823
 
}
824
 
 
825
 
 
826
 
static int
827
 
parse(GCDisplay *display, const char *text, MPNumber *z, char **error_token)
828
 
{
829
 
    MPEquationOptions options;
830
 
 
831
 
    memset(&options, 0, sizeof(options));
832
 
    options.wordlen = display->word_size;
833
 
    options.angle_units = display->angle_unit;
834
 
    options.variable_is_defined = variable_is_defined;
835
 
    options.get_variable = get_variable;
836
 
    options.set_variable = set_variable;
837
 
    options.convert = convert;
838
 
    options.callback_data = display;
839
 
 
840
 
    return mp_equation_parse(text, &options, z, error_token);
841
 
}
842
 
 
843
 
 
844
 
static void
845
 
do_paste(GCDisplay *display, int cursor_start, int cursor_end, const char *text)
846
 
{
847
 
    const char *input;
848
 
    char c, *output, *clean_text;
849
 
 
850
 
    /* Copy input to modify, no operation can make the clean string longer than
851
 
     * the original string */
852
 
    clean_text = strdup(text);
853
 
 
854
 
    output = clean_text;
855
 
    for (input = text; *input; input++) {
856
 
        /* If the clipboard buffer contains any occurances of the "thousands
857
 
         * separator", remove them.
858
 
         */
859
 
        if (v->tsep[0] != '\0' && strncmp(input, v->tsep, strlen(v->tsep)) == 0) {
860
 
            input += strlen(v->tsep) - 1;
861
 
            continue;
862
 
        }
863
 
 
864
 
        /* Replace radix with "." */
865
 
        else if (strncmp(input, v->radix, strlen(v->radix)) == 0) {
866
 
            input += strlen(v->radix) - 1;
867
 
            c = '.';
868
 
        }
869
 
 
870
 
        /* Replace tabs with spaces */
871
 
        else if (*input == '\t') {
872
 
            c = ' ';
873
 
        }
874
 
 
875
 
        /* Terminate on newlines */
876
 
        else if (*input == '\r' || *input == '\n') {
877
 
            c = '\0';
878
 
        }
879
 
 
880
 
        /* If an "A", "B", "C", "D" or "F" character is encountered, it
881
 
         * will be converted to its lowercase equivalent. If an "E" is
882
 
         * found,  and the next character is a "-" or a "+", then it
883
 
         * remains as an upper case "E" (it's assumed to be a possible
884
 
         * exponential number), otherwise its converted to a lower case
885
 
         * "e". See bugs #455889 and #469245 for more details.
886
 
         */
887
 
        else if (*input >= 'A' && *input <= 'F') {
888
 
            c = *input;
889
 
            if (*input == 'E') {
890
 
                if (*(input+1) != '-' && *(input+1) != '+')
891
 
                    c = tolower(*input);
892
 
            }
893
 
            else
894
 
                c = tolower(*input);
895
 
        }
896
 
 
897
 
        else
898
 
            c = *input;
899
 
 
900
 
        *output++ = c;
901
 
    }
902
 
    *output++ = '\0';
903
 
 
904
 
    display_insert(display, cursor_start, cursor_end, clean_text);
905
 
}
906
 
 
907
 
 
908
 
static void
909
 
do_insert_character(GCDisplay *display, const unsigned char *text)
910
 
{
911
 
    MPNumber value;
912
 
    int i = 0;
913
 
    mp_set_from_integer(0, &value);
914
 
    while (TRUE) {
915
 
        mp_add_integer(&value, text[i], &value);
916
 
        if (text[i+1]) {
917
 
            mp_shift(&value, 8, &value);
918
 
            i++;
919
 
        } else {
920
 
            break;
921
 
        }
922
 
    }
923
 
    display_set_number(display, &value);
924
 
}
925
 
 
926
 
 
927
 
/* Perform bitwise shift on display value. */
928
 
static void
929
 
do_shift(GCDisplay *display, int count)
930
 
{
931
 
    MPNumber z;
932
 
 
933
 
    if (!display_is_usable_number(display, &z)) {
934
 
        /* Translators: This message is displayed in the status bar when a bit
935
 
           shift operation is performed and the display does not contain a number */
936
 
        ui_set_statusbar(_("No sane value to bitwise shift"));
937
 
    }
938
 
    else {
939
 
        mp_shift(&z, count, display_get_answer(display));
940
 
        display_set_answer(display);
941
 
    }
942
 
}
943
 
 
944
 
 
945
 
void
946
 
do_factorize()
947
 
{
948
 
    MPNumber value;
949
 
 
950
 
    if (!display_is_usable_number(&v->display, &value)) {
951
 
        /* Translators: Error displayed when trying to factorize a non-integer value */
952
 
        ui_set_statusbar(_("Need an integer to factorize"));
953
 
        return;
954
 
    }
955
 
    display_clear(&v->display);
956
 
 
957
 
    GList *factors = mp_factorize(&value);
958
 
 
959
 
    display_insert_number(&v->display, -1, -1, factors->data);
960
 
    g_slice_free(MPNumber, factors->data);
961
 
 
962
 
    GList *list = factors->next;
963
 
    for (; list != NULL; list = list->next) {
964
 
            display_insert(&v->display, -1, -1, "×");
965
 
            display_insert_number(&v->display, -1, -1, list->data);
966
 
            g_slice_free(MPNumber, list->data);
967
 
    }
968
 
    g_list_free(factors);
969
 
}
970
 
 
971
 
 
972
 
static void
973
 
do_sto(GCDisplay *display, const char *name)
974
 
{
975
 
    MPNumber t;
976
 
 
977
 
    if (!display_is_usable_number(display, &t))
978
 
        ui_set_statusbar(_("No sane value to store"));
979
 
    else
980
 
        register_set_value(name, &t);
981
 
}
982
 
 
983
 
 
984
 
void
985
 
display_do_function(GCDisplay *display, int function, gpointer arg, int cursor_start, int cursor_end)
986
 
{
987
 
    MPNumber *ans;
988
 
    int enabled;
989
 
    guint64 bit_value;
990
 
 
991
 
    switch (function) {
992
 
        case FN_UNDO:
993
 
            display_pop(display);
994
 
            return;
995
 
 
996
 
        case FN_REDO:
997
 
            display_unpop(display);
998
 
            return;
999
 
 
1000
 
        default:
1001
 
            break;
1002
 
    }
1003
 
 
1004
 
    display_push(display);
1005
 
 
1006
 
    display_set_cursor(display, cursor_start);
1007
 
    ans = display_get_answer(display);
1008
 
 
1009
 
    ui_set_statusbar("");
1010
 
 
1011
 
    switch (function) {
1012
 
        case FN_CLEAR:
1013
 
            display_clear(display);
1014
 
            break;
1015
 
 
1016
 
        case FN_SHIFT:
1017
 
            do_shift(display, GPOINTER_TO_INT (arg));
1018
 
            break;
1019
 
 
1020
 
        case FN_FACTORIZE:
1021
 
            do_factorize(display, GPOINTER_TO_INT (arg));
1022
 
            break;
1023
 
 
1024
 
        case FN_PASTE:
1025
 
            do_paste(display, cursor_start, cursor_end, (const char *)arg);
1026
 
            return;
1027
 
 
1028
 
        case FN_INSERT_CHARACTER:
1029
 
            do_insert_character(display, (const unsigned char *)arg);
1030
 
            return;
1031
 
 
1032
 
        case FN_STORE:
1033
 
            do_sto(display, (const char *)arg);
1034
 
            return;
1035
 
 
1036
 
        case FN_RECALL:
1037
 
            display_insert(display, cursor_start, cursor_end, (const char *)arg);
1038
 
            break;
1039
 
 
1040
 
        case FN_BACKSPACE:
1041
 
            display_backspace(display, cursor_start, cursor_end);
1042
 
            break;
1043
 
 
1044
 
        case FN_DELETE:
1045
 
            display_delete(display, cursor_start, cursor_end);
1046
 
            break;
1047
 
 
1048
 
        case FN_TOGGLE_BIT:
1049
 
            if (display_get_unsigned_integer(display, &bit_value)) {
1050
 
                char buf[MAX_DISPLAY];
1051
 
                MPNumber MP;
1052
 
 
1053
 
                bit_value ^= (1LL << (63 - GPOINTER_TO_INT (arg)));
1054
 
 
1055
 
                /* FIXME: Convert to string since we don't support setting MP numbers from 64 bit integers */
1056
 
                SNPRINTF(buf, MAX_DISPLAY, "%" G_GUINT64_FORMAT, bit_value);
1057
 
                mp_set_from_string(buf, &MP);
1058
 
                display_set_number(display, &MP);
1059
 
            }
1060
 
            break;
1061
 
 
1062
 
        case FN_CALCULATE:
1063
 
            /* If showing a result display the calculation that caused
1064
 
             * this result */
1065
 
            /* TODO: Work out why two undo steps are required and why
1066
 
             * the cursor must be taken from the first undo */
1067
 
            if (display_is_result(display)) {
1068
 
                display_pop(display);
1069
 
                if (display_is_undo_step(display)) {
1070
 
                    display_pop(display);
1071
 
                }
1072
 
 
1073
 
            /* Do nothing */
1074
 
            } else if (display_is_empty(display)) {
1075
 
                ;
1076
 
 
1077
 
            /* Solve the equation */
1078
 
            } else {
1079
 
                MPNumber z;
1080
 
                int result;
1081
 
                const char *message = NULL;
1082
 
                char *text, *error_token;
1083
 
 
1084
 
                text = get_expression (display);
1085
 
                result = parse(display,
1086
 
                               text,
1087
 
                               &z,
1088
 
                               &error_token);
1089
 
                g_free(text);
1090
 
 
1091
 
                switch (result) {
1092
 
                    case PARSER_ERR_NONE:
1093
 
                        mp_set_from_mp(&z, ans);
1094
 
                        display_set_answer(display);
1095
 
                        break;
1096
 
 
1097
 
                    case PARSER_ERR_OVERFLOW:
1098
 
                        /* Translators: Error displayed to user when they perform a bitwise operation on numbers greater than the current word */
1099
 
                        message = _("Overflow. Try a bigger word size");
1100
 
                        break;
1101
 
 
1102
 
                    case PARSER_ERR_UNKNOWN_VARIABLE:
1103
 
                        /* Translators: Error displayed to user when they an unknown variable is entered */
1104
 
                        message = g_strdup_printf(_("Unknown variable '%s'"), error_token);
1105
 
                        free(error_token);
1106
 
                        break;
1107
 
 
1108
 
                    case PARSER_ERR_UNKNOWN_FUNCTION:
1109
 
                        /* Translators: Error displayed to user when an unknown function is entered */
1110
 
                        message = g_strdup_printf(_("Function '%s' is not defined"), error_token);
1111
 
                        free(error_token);
1112
 
                        break;
1113
 
 
1114
 
                    case PARSER_ERR_UNKNOWN_CONVERSION:
1115
 
                        /* Translators: Error displayed to user when an conversion with unknown units is attempted */
1116
 
                        message = g_strdup_printf(_("Unknown conversion"));
1117
 
                        break;
1118
 
 
1119
 
                    case PARSER_ERR_MP:
1120
 
                        message = mp_get_error();
1121
 
                        break;
1122
 
 
1123
 
                    default:
1124
 
                        /* Translators: Error displayed to user when they enter an invalid calculation */
1125
 
                        message = _("Malformed expression");
1126
 
                        break;
1127
 
                }
1128
 
                if (message)
1129
 
                    ui_set_statusbar(message);
1130
 
            }
1131
 
            break;
1132
 
 
1133
 
        case FN_TEXT:
1134
 
            /* Start new equation when entering digits after existing result */
1135
 
            if(display_is_result(display) && g_unichar_isdigit(g_utf8_get_char((char*)arg)))
1136
 
                display_clear(display);
1137
 
 
1138
 
            display_insert(display, cursor_start, cursor_end, (const char *)arg);
1139
 
            break;
1140
 
    }
1141
 
 
1142
 
    enabled = display_get_unsigned_integer(display, &bit_value);
1143
 
    ui_set_bitfield(enabled, bit_value);
 
797
    case 2:
 
798
        max_fix = 1.298074214e+33;
 
799
        break;
 
800
    case 8:
 
801
        max_fix = 2.037035976e+90;
 
802
        break;
 
803
    case 10:
 
804
        max_fix = 1.000000000e+100;
 
805
        break;
 
806
    default:
 
807
    case 16:
 
808
        max_fix = 2.582249878e+120;
 
809
        break;
 
810
    }
 
811
    
 
812
    // FIXME: Do this based on the number of digits, not actual values
 
813
    if ((display->format == ENG) ||
 
814
        (display->format == SCI) ||
 
815
        (display->format == FIX && val != 0.0 && (val > max_fix))) {
 
816
        make_eng_sci(display, target, target_len, x, base);
 
817
    } else {
 
818
        mp_cast_to_string(x, base, v->accuracy, !v->display.show_zeroes, target, target_len);
 
819
    }
1144
820
}