1 /*
2 Qalculate (CLI)
3
4 Copyright (C) 2003-2007, 2008, 2016-2021 Hanna Knutsson (hanna.knutsson@protonmail.com)
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10 */
11
12 #include "support.h"
13 #include <libqalculate/qalculate.h>
14 #include <sys/stat.h>
15 #include <unistd.h>
16 #include <time.h>
17 #include <dirent.h>
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <vector>
21 #include <list>
22 #ifdef HAVE_LIBREADLINE
23 # include <readline/readline.h>
24 # include <readline/history.h>
25 #endif
26 #ifdef _WIN32
27 #define WIN32_LEAN_AND_MEAN
28 # include <windows.h>
29 # include <VersionHelpers.h>
30 #endif
31
32 #include <libqalculate/MathStructure-support.h>
33
34 using std::string;
35 using std::cout;
36 using std::vector;
37 using std::endl;
38 using std::iterator;
39 using std::cerr;
40 using std::list;
41
42 class ViewThread : public Thread {
43 protected:
44 virtual void run();
45 };
46
47 class CommandThread : public Thread {
48 protected:
49 virtual void run();
50 };
51
52 MathStructure *mstruct, *parsed_mstruct, mstruct_exact;
53 KnownVariable *vans[5], *v_memory;
54 string result_text, parsed_text, original_expression;
55 vector<string> alt_results;
56 bool load_global_defs, fetch_exchange_rates_at_startup, first_time, save_mode_on_exit, save_defs_on_exit;
57 int auto_update_exchange_rates;
58 PrintOptions printops, saved_printops;
59 bool complex_angle_form = false, saved_caf = false;
60 EvaluationOptions evalops, saved_evalops;
61 Number saved_custom_output_base, saved_custom_input_base;
62 AssumptionType saved_assumption_type;
63 AssumptionSign saved_assumption_sign;
64 int saved_precision;
65 int saved_binary_prefixes;
66 bool saved_interval, saved_adaptive_interval_display, saved_variable_units_enabled;
67 bool adaptive_interval_display;
68 Thread *view_thread, *command_thread;
69 bool command_aborted = false;
70 volatile bool b_busy = false;
71 string expression_str;
72 bool expression_executed = false;
73 bool avoid_recalculation = false;
74 bool hide_parse_errors = false;
75 ParsingMode nonrpn_parsing_mode = PARSING_MODE_ADAPTIVE, saved_parsing_mode;
76 bool rpn_mode = false, saved_rpn_mode = false;
77 bool caret_as_xor = false, saved_caret_as_xor = false;
78 bool use_readline = true;
79 bool interactive_mode;
80 int colorize = 0;
81 int force_color = -1;
82 bool ask_questions = false;
83 bool canfetch = true;
84 bool programmers_mode = false;
85 int b_decimal_comma = -1;
86 long int i_maxtime = 0;
87 struct timeval t_end;
88 int dual_fraction = -1, saved_dual_fraction = -1;
89 int dual_approximation = -1, saved_dual_approximation = -1;
90 bool tc_set = false;
91
92 bool ignore_locale = false;
93
94 bool result_only;
95
96 static char buffer[100000];
97
98 void setResult(Prefix *prefix = NULL, bool update_parse = false, bool goto_input = true, size_t stack_index = 0, bool register_moved = false, bool noprint = false);
99 void execute_expression(bool goto_input = true, bool do_mathoperation = false, MathOperation op = OPERATION_ADD, MathFunction *f = NULL, bool do_stack = false, size_t stack_index = 0, bool check_exrates = true);
100 void execute_command(int command_type, bool show_result = true);
101 void load_preferences();
102 bool save_preferences(bool mode = false);
103 bool save_mode();
104 void set_saved_mode();
105 bool save_defs();
106 void result_display_updated();
107 void result_format_updated();
108 void result_action_executed();
109 void result_prefix_changed(Prefix *prefix = NULL);
110 void expression_format_updated(bool reparse);
111 void expression_calculation_updated();
112 bool display_errors(bool goto_input = false, int cols = 0);
113 void replace_result_cis(string &resstr);
114
115 FILE *cfile;
116
117 enum {
118 COMMAND_FACTORIZE,
119 COMMAND_EXPAND,
120 COMMAND_EXPAND_PARTIAL_FRACTIONS,
121 COMMAND_EVAL
122 };
123
124 #define EQUALS_IGNORECASE_AND_LOCAL(x,y,z) (equalsIgnoreCase(x, y) || equalsIgnoreCase(x, z))
125
126 #define DO_WIN_FORMAT IsWindows10OrGreater()
127
128 #ifdef _WIN32
129 # define DO_FORMAT (force_color > 0 || (force_color != 0 && !cfile && colorize && interactive_mode))
130 #else
131 # define DO_FORMAT (force_color > 0 || (force_color != 0 && !cfile && interactive_mode))
132 #endif
133 #define DO_COLOR (force_color >= 0 ? force_color : (!cfile && colorize && interactive_mode ? colorize : 0))
134
contains_unicode_char(const char * str)135 bool contains_unicode_char(const char *str) {
136 for(int i = strlen(str) - 1; i >= 0; i--) {
137 if(str[i] < 0) return true;
138 }
139 return false;
140 }
141 #ifdef _WIN32
utf8wchar(const char * str)142 LPWSTR utf8wchar(const char *str) {
143 size_t len = strlen(str) + 1;
144 int size_needed = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0);
145 LPWSTR wstr = (LPWSTR) LocalAlloc(LPTR, sizeof(WCHAR) * size_needed);
146 MultiByteToWideChar(CP_UTF8, 0, str, len, wstr, size_needed);
147 return wstr;
148 }
149 # define PUTS_UNICODE(x) if(!contains_unicode_char(x)) {puts(x);} else if(printops.use_unicode_signs) {fputws(utf8wchar(x), stdout); puts("");} else {char *gstr = locale_from_utf8(x); if(gstr) {puts(gstr); free(gstr);} else {puts(x);}}
150 # define FPUTS_UNICODE(x, y) if(!contains_unicode_char(x)) {fputs(x, y);} else if(printops.use_unicode_signs) {fputws(utf8wchar(x), y);} else {char *gstr = locale_from_utf8(x); if(gstr) {fputs(gstr, y); free(gstr);} else {fputs(x, y);}}
151 #else
152 # define PUTS_UNICODE(x) if(printops.use_unicode_signs || !contains_unicode_char(x)) {puts(x);} else {char *gstr = locale_from_utf8(x); if(gstr) {puts(gstr); free(gstr);} else {puts(x);}}
153 # define FPUTS_UNICODE(x, y) if(printops.use_unicode_signs || !contains_unicode_char(x)) {fputs(x, y);} else {char *gstr = locale_from_utf8(x); if(gstr) {fputs(gstr, y); free(gstr);} else {fputs(x, y);}}
154 #endif
155
update_message_print_options()156 void update_message_print_options() {
157 PrintOptions message_printoptions = printops;
158 message_printoptions.interval_display = INTERVAL_DISPLAY_PLUSMINUS;
159 message_printoptions.show_ending_zeroes = false;
160 message_printoptions.base = 10;
161 if(printops.min_exp < -10 || printops.min_exp > 10 || ((printops.min_exp == EXP_PRECISION || printops.min_exp == EXP_NONE) && PRECISION > 10)) message_printoptions.min_exp = 10;
162 else if(printops.min_exp == EXP_NONE) message_printoptions.min_exp = EXP_PRECISION;
163 if(PRECISION > 10) {
164 message_printoptions.use_max_decimals = true;
165 message_printoptions.max_decimals = 10;
166 }
167 CALCULATOR->setMessagePrintOptions(message_printoptions);
168 }
169
unicode_length_check(const char * str)170 size_t unicode_length_check(const char *str) {
171 size_t l = strlen(str), l2 = 0;
172 for(size_t i = 0; i < l; i++) {
173 if(str[i] == '\033') {
174 do {
175 i++;
176 } while(i < l && str[i] != 'm');
177 } else if(str[i] > 0 || (unsigned char) str[i] >= 0xC0) {
178 l2++;
179 }
180 }
181 return l2;
182 }
183
s2b(const string & str)184 int s2b(const string &str) {
185 if(str.empty()) return -1;
186 if(EQUALS_IGNORECASE_AND_LOCAL(str, "yes", _("yes"))) return 1;
187 if(EQUALS_IGNORECASE_AND_LOCAL(str, "no", _("no"))) return 0;
188 if(EQUALS_IGNORECASE_AND_LOCAL(str, "true", _("true"))) return 1;
189 if(EQUALS_IGNORECASE_AND_LOCAL(str, "false", _("false"))) return 0;
190 if(EQUALS_IGNORECASE_AND_LOCAL(str, "on", _("on"))) return 1;
191 if(EQUALS_IGNORECASE_AND_LOCAL(str, "off", _("off"))) return 0;
192 if(str.find_first_not_of(SPACES NUMBERS) != string::npos) return -1;
193 int i = s2i(str);
194 if(i > 0) return 1;
195 return 0;
196 }
197
is_answer_variable(Variable * v)198 bool is_answer_variable(Variable *v) {
199 return v == vans[0] || v == vans[1] || v == vans[2] || v == vans[3] || v == vans[4];
200 }
201
equalsIgnoreCaseFirst(const string & str1,const char * str2)202 bool equalsIgnoreCaseFirst(const string &str1, const char *str2) {
203 if(str1.length() < 1 || strlen(str2) < 1) return false;
204 if((str1[0] < 0 && str1.length() > 1) || (str2[0] < 0 && strlen(str2) > 1)) {
205 size_t iu1 = 1, iu2 = 1;
206 if(str1[0] < 0) {
207 while(iu1 < str1.length() && str1[iu1] < 0) {
208 iu1++;
209 }
210 }
211 if(str2[0] < 0) {
212 while(iu2 < strlen(str2) && str2[iu2] < 0) {
213 iu2++;
214 }
215 }
216 bool isequal = (iu1 == iu2);
217 if(isequal) {
218 for(size_t i = 0; i < iu1; i++) {
219 if(str1[i] != str2[i]) {
220 isequal = false;
221 break;
222 }
223 }
224 }
225 if(!isequal) {
226 char *gstr1 = utf8_strdown(str1.c_str(), iu1);
227 char *gstr2 = utf8_strdown(str2, iu2);
228 if(!gstr1 || !gstr2) return false;
229 bool b = strcmp(gstr1, gstr2) == 0;
230 free(gstr1);
231 free(gstr2);
232 return b;
233 }
234 } else if(str1.length() != 1 || (str1[0] != str2[0] && !((str1[0] >= 'a' && str1[0] <= 'z') && str1[0] - 32 == str2[0]) && !((str1[0] <= 'Z' && str1[0] >= 'A') && str1[0] + 32 == str2[0]))) {
235 return false;
236 }
237 return true;
238 }
239
ask_question(const char * question,bool default_answer=false)240 bool ask_question(const char *question, bool default_answer = false) {
241 FPUTS_UNICODE(question, stdout);
242 while(true) {
243 #ifdef HAVE_LIBREADLINE
244 char *rlbuffer = readline(" ");
245 if(!rlbuffer) return false;
246 string str = rlbuffer;
247 free(rlbuffer);
248 #else
249 fputs(" ", stdout);
250 if(!fgets(buffer, 1000, stdin)) return false;
251 string str = buffer;
252 #endif
253 remove_blank_ends(str);
254 if(equalsIgnoreCaseFirst(str, "yes") || equalsIgnoreCaseFirst(str, _("yes")) || EQUALS_IGNORECASE_AND_LOCAL(str, "yes", _("yes"))) {
255 return true;
256 } else if(equalsIgnoreCaseFirst(str, "no") || equalsIgnoreCaseFirst(str, _("no")) || EQUALS_IGNORECASE_AND_LOCAL(str, "no", _("no"))) {
257 return false;
258 } else if(str.empty()) {
259 return default_answer;
260 } else {
261 FPUTS_UNICODE(_("Please answer yes or no"), stdout);
262 FPUTS_UNICODE(":", stdout);
263 }
264 }
265 }
266
set_assumption(const string & str,bool last_of_two=false)267 void set_assumption(const string &str, bool last_of_two = false) {
268 if(EQUALS_IGNORECASE_AND_LOCAL(str, "unknown", _("unknown")) || str == "0") {
269 if(!last_of_two) {
270 CALCULATOR->defaultAssumptions()->setSign(ASSUMPTION_SIGN_UNKNOWN);
271 } else {
272 CALCULATOR->defaultAssumptions()->setType(ASSUMPTION_TYPE_NUMBER);
273 }
274 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "real", _("real"))) {
275 CALCULATOR->defaultAssumptions()->setType(ASSUMPTION_TYPE_REAL);
276 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "number", _("number")) || str == "num") {
277 CALCULATOR->defaultAssumptions()->setType(ASSUMPTION_TYPE_NUMBER);
278 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "rational", _("rational")) || str == "rat") {
279 CALCULATOR->defaultAssumptions()->setType(ASSUMPTION_TYPE_RATIONAL);
280 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "integer", _("integer")) || str == "int") {
281 CALCULATOR->defaultAssumptions()->setType(ASSUMPTION_TYPE_INTEGER);
282 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "non-zero", _("non-zero")) || str == "nz") {
283 CALCULATOR->defaultAssumptions()->setSign(ASSUMPTION_SIGN_NONZERO);
284 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "positive", _("positive")) || str == "pos") {
285 CALCULATOR->defaultAssumptions()->setSign(ASSUMPTION_SIGN_POSITIVE);
286 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "non-negative", _("non-negative")) || str == "nneg") {
287 CALCULATOR->defaultAssumptions()->setSign(ASSUMPTION_SIGN_NONNEGATIVE);
288 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "negative", _("negative")) || str == "neg") {
289 CALCULATOR->defaultAssumptions()->setSign(ASSUMPTION_SIGN_NEGATIVE);
290 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "non-positive", _("non-positive")) || str == "npos") {
291 CALCULATOR->defaultAssumptions()->setSign(ASSUMPTION_SIGN_NONPOSITIVE);
292 } else {
293 PUTS_UNICODE(_("Unrecognized assumption."));
294 return;
295 }
296 }
297
298 vector<const string*> matches;
299
300 #ifdef __cplusplus
301 extern "C" {
302 #endif
303
304 #ifdef HAVE_LIBREADLINE
305
qalc_completion(const char * text,int index)306 char *qalc_completion(const char *text, int index) {
307 if(index == 0) {
308 if(strlen(text) < 1) return NULL;
309 matches.clear();
310 bool b_match;
311 size_t l = strlen(text);
312 for(size_t i = 0; i < CALCULATOR->functions.size(); i++) {
313 if(CALCULATOR->functions[i]->isActive()) {
314 ExpressionItem *item = CALCULATOR->functions[i];
315 const ExpressionName *ename = NULL;
316 b_match = false;
317 for(size_t name_i = 1; name_i <= item->countNames() && !b_match; name_i++) {
318 ename = &item->getName(name_i);
319 if(ename && l <= ename->name.length()) {
320 b_match = true;
321 for(size_t i2 = 0; i2 < l; i2++) {
322 if(ename->name[i2] != text[i2]) {
323 b_match = false;
324 break;
325 }
326 }
327 }
328 }
329 if(b_match && ename) {
330 if(ename->completion_only) ename = &item->preferredInputName(ename->abbreviation, printops.use_unicode_signs);
331 matches.push_back(&ename->name);
332 }
333 }
334 }
335 for(size_t i = 0; i < CALCULATOR->variables.size(); i++) {
336 if(CALCULATOR->variables[i]->isActive()) {
337 ExpressionItem *item = CALCULATOR->variables[i];
338 const ExpressionName *ename = NULL;
339 b_match = false;
340 for(size_t name_i = 1; name_i <= item->countNames() && !b_match; name_i++) {
341 ename = &item->getName(name_i);
342 if(ename && l <= ename->name.length()) {
343 b_match = true;
344 for(size_t i2 = 0; i2 < l; i2++) {
345 if(ename->name[i2] != text[i2]) {
346 b_match = false;
347 break;
348 }
349 }
350 }
351 }
352 if(b_match && ename) {
353 if(ename->completion_only) ename = &item->preferredInputName(ename->abbreviation, printops.use_unicode_signs);
354 matches.push_back(&ename->name);
355 }
356 }
357 }
358 for(size_t i = 0; i < CALCULATOR->units.size(); i++) {
359 if(CALCULATOR->units[i]->isActive() && CALCULATOR->units[i]->subtype() != SUBTYPE_COMPOSITE_UNIT) {
360 ExpressionItem *item = CALCULATOR->units[i];
361 const ExpressionName *ename = NULL;
362 b_match = false;
363 for(size_t name_i = 1; name_i <= item->countNames() && !b_match; name_i++) {
364 ename = &item->getName(name_i);
365 if(ename && l <= ename->name.length()) {
366 b_match = true;
367 for(size_t i2 = 0; i2 < l; i2++) {
368 if(ename->name[i2] != text[i2]) {
369 b_match = false;
370 break;
371 }
372 }
373 }
374 }
375 if(b_match && ename) {
376 if(ename->completion_only) ename = &item->preferredInputName(ename->abbreviation, printops.use_unicode_signs);
377 matches.push_back(&ename->name);
378 }
379 }
380 }
381 }
382 if(index >= 0 && index < (int) matches.size()) {
383 char *cstr = (char*) malloc(sizeof(char) *matches[index]->length() + 1);
384 strcpy(cstr, matches[index]->c_str());
385 return cstr;
386 }
387 return NULL;
388 }
389
390 #endif
391
392 #ifdef __cplusplus
393 }
394 #endif
395
396 int enable_unicode = -1;
397
handle_exit()398 void handle_exit() {
399 CALCULATOR->abort();
400 if(enable_unicode >= 0) {
401 printops.use_unicode_signs = !enable_unicode;
402 }
403 if(interactive_mode) {
404 if(save_mode_on_exit) {
405 save_mode();
406 } else {
407 save_preferences();
408 }
409 if(save_defs_on_exit) {
410 save_defs();
411 }
412 }
413 if(!view_thread->write(NULL)) view_thread->cancel();
414 if(command_thread->running && (!command_thread->write(0) || !command_thread->write(NULL))) command_thread->cancel();
415 CALCULATOR->terminateThreads();
416 }
417
418 #ifdef HAVE_LIBREADLINE
rlcom_tab(int,int)419 int rlcom_tab(int, int) {
420 rl_complete_internal('!');
421 return 0;
422 }
423 #endif
424
countRows(const char * str,int cols)425 int countRows(const char *str, int cols) {
426 int l = strlen(str);
427 if(l == 0) return 1;
428 int r = 1, c = 0;
429 for(int i = 0; i < l; i++) {
430 if(str[i] == '\033') {
431 do {
432 i++;
433 } while(i < l && str[i] != 'm');
434 } else if(str[i] > 0 || (unsigned char) str[i] >= 0xC0) {
435 if(str[i] == '\n') {
436 r++;
437 c = 0;
438 } else {
439 if(c == cols) {
440 r++;
441 c = 0;
442 }
443 c++;
444 }
445 }
446 }
447 return r;
448 }
449
addLineBreaks(string & str,int cols,bool expr=false,size_t indent=0,size_t result_start=0)450 int addLineBreaks(string &str, int cols, bool expr = false, size_t indent = 0, size_t result_start = 0) {
451 if(cols <= 0) return 1;
452 int r = 1;
453 size_t c = 0;
454 size_t lb_point = string::npos;
455 size_t or_point = string::npos;
456 int b_or = 0;
457 if(expr && str.find("||") != string::npos) b_or = 2;
458 else if(expr && str.find(_("or")) != string::npos) b_or = 1;
459 for(size_t i = 0; i < str.length(); i++) {
460 if(r != 1 && c == indent) {
461 if(str[i] == ' ') {
462 str.erase(i, 1);
463 if(i < result_start) result_start--;
464 if(i >= str.length()) break;
465 } else if(expr && printops.use_unicode_signs && printops.digit_grouping != DIGIT_GROUPING_NONE && str[i] <= 0 && (unsigned char) str[i] >= 0xC0) {
466 size_t l = 1;
467 while(i + l < str.length() && str[i + l] <= 0 && (unsigned char) str[i + l] < 0xC0) l++;
468 if(str.substr(i, l) == " ") {
469 str.erase(i, l);
470 if(i < result_start) result_start--;
471 if(i >= str.length()) break;
472 }
473 }
474 }
475 while(str[i] == '\033') {
476 do {
477 i++;
478 } while(i < str.length() && str[i] != 'm');
479 i++;
480 if(i >= str.length()) break;
481 }
482 if(str[i] > 0 || (unsigned char) str[i] >= 0xC0) {
483 if(str[i] == '\n') {
484 r++;
485 c = 0;
486 lb_point = string::npos;
487 } else {
488 if(c > indent) {
489 if(is_in(" \t", str[i])) {
490 if(!expr || printops.digit_grouping == DIGIT_GROUPING_NONE || i + 1 == str.length() || is_not_in("0123456789", str[i + 1]) || is_not_in("0123456789", str[i - 1])) {
491 if(expr || (c - indent) > (cols - indent) / 2) lb_point = i;
492 if(i > result_start && b_or == 1 && str.length() > i + strlen("or") + 2 && str.substr(i + 1, strlen(_("or"))) == _("or") && str[i + strlen(_("or")) + 1] == ' ') or_point = i + strlen(_("or")) + 1;
493 else if(i > result_start && b_or == 2 && str.length() > i + 2 + 2 && str.substr(i + 1, 2) == "||" && str[i + 2 + 1] == ' ') or_point = i + 2 + 1;
494 }
495 } else if(expr && !printops.spacious && (c - indent) > (cols - indent) / 2 && c < (size_t) cols && is_in("+-*", str[i]) && i + 1 != str.length() && str[i - 1] != '^' && str[i - 1] != ' ' && str[i - 1] != '=' && is_not_in(" \t.;,", str[i + 1])) {
496 lb_point = i + 1;
497 }
498 }
499 if(c == (size_t) cols || or_point != string::npos) {
500 if(or_point != string::npos) lb_point = or_point;
501 if(lb_point == string::npos) {
502 if(expr && printops.digit_grouping != DIGIT_GROUPING_NONE) {
503 if(i > 3 && str[i] <= '9' && str[i] >= '0' && str[i - 1] <= '9' && str[i - 1] >= '0') {
504 if(str[i - 2] == ' ' && str[i - 3] <= '9' && str[i - 3] >= '0') i -= 2;
505 else if(str[i - 3] == ' ' && str[i - 4] <= '9' && str[i - 4] >= '0') i -= 3;
506 else if((str[i - 2] == '.' || str[i - 2] == ',') && str[i - 3] <= '9' && str[i - 3] >= '0') i--;
507 else if((str[i - 3] == '.' || str[i - 3] == ',') && str[i - 4] <= '9' && str[i - 4] >= '0') i -= 2;
508 else if(printops.use_unicode_signs && i > 6) {
509 size_t i2 = str.find(" ", i - 6);
510 if(i2 != string::npos && i2 > 0 && i2 < i && str[i2 - 1] <= '9' && str[i2 - 1] >= '0') {
511 i = i2;
512 }
513 }
514 } else if(i > 4 && (str[i] == '.' || str[i] == ',') && str[i - 1] <= '9' && str[i - 1] >= '0' && str[i - 4] == str[i] && str[i - 5] <= '9' && str[i - 5] >= '0') {
515 i -= 3;
516 }
517 }
518 str.insert(i, "\n");
519 result_start++;
520 for(size_t i2 = 0; i2 < indent; i2++) {
521 i++;
522 if(i < result_start) result_start++;
523 str.insert(i, " ");
524 }
525 c = indent;
526 } else if(str[lb_point] == ' ' || str[lb_point] == '\t') {
527 str[lb_point] = '\n';
528 for(size_t i2 = 0; i2 < indent; i2++) {
529 lb_point++;
530 if(i < result_start) result_start++;
531 str.insert(lb_point, " ");
532 }
533 i = lb_point;
534 c = indent;
535 } else {
536 str.insert(lb_point, "\n");
537 result_start++;
538 for(size_t i2 = 0; i2 < indent; i2++) {
539 lb_point++;
540 if(i < result_start) result_start++;
541 str.insert(lb_point, " ");
542 }
543 i = lb_point;
544 c = indent;
545 }
546 lb_point = string::npos;
547 or_point = string::npos;
548 r++;
549 } else {
550 if(str[i] == '\t') c += 8;
551 else c++;
552 }
553 }
554 } else if(expr && !printops.spacious && printops.use_unicode_signs && i + 1 < str.length() && (str[i + 1] > 0 || (unsigned char) str[i + 1] >= 0xC0)) {
555 if(c > indent && (c - indent) > (cols - indent) / 2 && is_not_in(" \t.;,", str[i + 1])) {
556 size_t index = i;
557 while(index > 0 && str[index - 1] <= 0) {
558 index--;
559 if((unsigned char) str[index] >= 0xC0) break;
560 }
561 if(index > 0 && str[index - 1] != '^' && str[index - 1] != ' ' && str[index - 1] != '=') {
562 string unichar = str.substr(index, i - index + 1);
563 if(unichar == SIGN_MULTIPLICATION || unichar == SIGN_MULTIDOT || unichar == SIGN_MIDDLEDOT || unichar == SIGN_MULTIBULLET || unichar == SIGN_SMALLCIRCLE || unichar == SIGN_DIVISION_SLASH || unichar == SIGN_DIVISION || unichar == SIGN_MINUS || unichar == SIGN_PLUS) lb_point = i + 1;
564 }
565 }
566 }
567 }
568 return r;
569 }
570
check_exchange_rates()571 bool check_exchange_rates() {
572 int i = CALCULATOR->exchangeRatesUsed();
573 if(i == 0) return false;
574 if(CALCULATOR->checkExchangeRatesDate(auto_update_exchange_rates > 0 ? auto_update_exchange_rates : 7, false, auto_update_exchange_rates == 0 || (auto_update_exchange_rates < 0 && !ask_questions), i)) return false;
575 if(auto_update_exchange_rates == 0 || (auto_update_exchange_rates < 0 && !ask_questions)) return false;
576 bool b = false;
577 if(auto_update_exchange_rates < 0) {
578 string ask_str;
579 int cx = snprintf(buffer, 1000, _("It has been %s day(s) since the exchange rates last were updated."), i2s((int) floor(difftime(time(NULL), CALCULATOR->getExchangeRatesTime(i)) / 86400)).c_str());
580 if(cx >= 0 && cx < 1000) {
581 ask_str = buffer;
582 ask_str += "\n";
583 }
584 ask_str += _("Do you wish to update the exchange rates now?");
585 b = ask_question(ask_str.c_str());
586 }
587 if(b || auto_update_exchange_rates > 0) {
588 if(auto_update_exchange_rates <= 0) i = -1;
589 CALCULATOR->fetchExchangeRates(15, i);
590 CALCULATOR->loadExchangeRates();
591 return true;
592 }
593 return false;
594 }
595
596
597 #ifdef HAVE_LIBREADLINE
598 # define CHECK_IF_SCREEN_FILLED if(check_sf) {rcount++; if(rcount + 2 >= rows) {FPUTS_UNICODE(_("\nPress Enter to continue."), stdout); fflush(stdout); sf_c = rl_read_key(); if(sf_c != '\n' && sf_c != '\r') {check_sf = false;} else {puts(""); if(sf_c == '\r') {puts("");} rcount = 1;}}}
599 # define CHECK_IF_SCREEN_FILLED_PUTS_RP(x, rplus) {str_lb = x; int cr = 0; if(!cfile) {cr = addLineBreaks(str_lb, cols);} if(check_sf) {if(rcount + cr + 1 + rplus >= rows) {rcount += 2; while(rcount < rows) {puts(""); rcount++;} FPUTS_UNICODE(_("\nPress Enter to continue."), stdout); fflush(stdout); sf_c = rl_read_key(); if(sf_c != '\n' && sf_c != '\r') {check_sf = false;} else {rcount = 0; if(str_lb.empty() || str_lb[0] != '\n') {puts(""); if(sf_c == '\r') {puts("");} rcount++;}}} if(check_sf) {rcount += cr;}} PUTS_UNICODE(str_lb.c_str());}
600 # define CHECK_IF_SCREEN_FILLED_PUTS(x) CHECK_IF_SCREEN_FILLED_PUTS_RP(x, 0)
601 # define INIT_SCREEN_CHECK int rows = 0, cols = 0, rcount = 0; bool check_sf = (cfile == NULL); char sf_c; string str_lb; if(!cfile) rl_get_screen_size(&rows, &cols);
602 # define INIT_COLS int rows = 0, cols = 0; if(!cfile) rl_get_screen_size(&rows, &cols);
603 # define CHECK_IF_SCREEN_FILLED_HEADING_S(x) str = "\n"; BEGIN_UNDERLINED(str); str += x; END_UNDERLINED(str); CHECK_IF_SCREEN_FILLED_PUTS_RP(str.c_str(), 1);
604 # define CHECK_IF_SCREEN_FILLED_HEADING(x) str = "\n"; BEGIN_UNDERLINED(str); BEGIN_BOLD(str); str += x; END_UNDERLINED(str); END_BOLD(str); CHECK_IF_SCREEN_FILLED_PUTS_RP(str.c_str(), 1);
605 #else
606 # define CHECK_IF_SCREEN_FILLED
607 # define CHECK_IF_SCREEN_FILLED_PUTS(x) str_lb = x; if(!cfile) {addLineBreaks(str_lb, cols);} PUTS_UNICODE(str_lb.c_str());
608 # define INIT_SCREEN_CHECK string str_lb; int cols = 80;
609 # define INIT_COLS int cols = (cfile ? 0 : 80);
610 # define CHECK_IF_SCREEN_FILLED_HEADING_S(x) str = "\n"; BEGIN_UNDERLINED(str); str += x; END_UNDERLINED(str); PUTS_UNICODE(str.c_str());
611 # define CHECK_IF_SCREEN_FILLED_HEADING(x) puts(""); str = "\n"; BEGIN_UNDERLINED(str); BEGIN_BOLD(str); str += x; END_UNDERLINED(str); END_BOLD(str); PUTS_UNICODE(str.c_str());
612 #endif
613
614 #define SET_BOOL(x) {int v = s2b(svalue); if(v < 0) {PUTS_UNICODE(_("Illegal value."));} else if(x != v) {x = v;}}
615 #define SET_BOOL_D(x) {int v = s2b(svalue); if(v < 0) {PUTS_UNICODE(_("Illegal value."));} else if(x != v) {x = v; result_display_updated();}}
616 #define SET_BOOL_E(x) {int v = s2b(svalue); if(v < 0) {PUTS_UNICODE(_("Illegal value."));} else if(x != v) {x = v; expression_calculation_updated();}}
617 #define SET_BOOL_PV(x) {int v = s2b(svalue); if(v < 0) {PUTS_UNICODE(_("Illegal value."));} else if(x != v) {x = v; expression_format_updated(v);}}
618 #define SET_BOOL_PT(x) {int v = s2b(svalue); if(v < 0) {PUTS_UNICODE(_("Illegal value."));} else if(x != v) {x = v; expression_format_updated(true);}}
619 #define SET_BOOL_PF(x) {int v = s2b(svalue); if(v < 0) {PUTS_UNICODE(_("Illegal value."));} else if(x != v) {x = v; expression_format_updated(false);}}
620
set_option(string str)621 void set_option(string str) {
622 remove_blank_ends(str);
623 string svalue, svar;
624 bool empty_value = false;
625 size_t i_underscore = str.find("_");
626 size_t index;
627 if(i_underscore != string::npos) {
628 index = str.find_first_of(SPACES);
629 if(index != string::npos && i_underscore > index) i_underscore = string::npos;
630 }
631 if(i_underscore == string::npos) index = str.find_last_of(SPACES);
632 if(index != string::npos) {
633 svar = str.substr(0, index);
634 remove_blank_ends(svar);
635 svalue = str.substr(index + 1);
636 remove_blank_ends(svalue);
637 } else {
638 svar = str;
639 }
640 if(i_underscore != string::npos) gsub("_", " ", svar);
641 if(svalue.empty()) {
642 empty_value = true;
643 svalue = "1";
644 } else {
645 gsub(SIGN_MINUS, "-", svalue);
646 }
647
648 set_option_place:
649 if(EQUALS_IGNORECASE_AND_LOCAL(svar, "base", _("base")) || EQUALS_IGNORECASE_AND_LOCAL(svar, "input base", _("input base")) || svar == "inbase" || EQUALS_IGNORECASE_AND_LOCAL(svar, "output base", _("output base")) || svar == "outbase") {
650 int v = 0;
651 bool b_in = EQUALS_IGNORECASE_AND_LOCAL(svar, "input base", _("input base")) || svar == "inbase";
652 bool b_out = EQUALS_IGNORECASE_AND_LOCAL(svar, "output base", _("output base")) || svar == "outbase";
653 if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "roman", _("roman"))) v = BASE_ROMAN_NUMERALS;
654 else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "bijective", _("bijective")) || str == "b26" || str == "B26") v = BASE_BIJECTIVE_26;
655 else if(equalsIgnoreCase(svalue, "fp32") || equalsIgnoreCase(svalue, "binary32") || equalsIgnoreCase(svalue, "float")) {if(b_in) v = 0; else v = BASE_FP32;}
656 else if(equalsIgnoreCase(svalue, "fp64") || equalsIgnoreCase(svalue, "binary64") || equalsIgnoreCase(svalue, "double")) {if(b_in) v = 0; else v = BASE_FP64;}
657 else if(equalsIgnoreCase(svalue, "fp16") || equalsIgnoreCase(svalue, "binary16")) {if(b_in) v = 0; else v = BASE_FP16;}
658 else if(equalsIgnoreCase(svalue, "fp80")) {if(b_in) v = 0; else v = BASE_FP80;}
659 else if(equalsIgnoreCase(svalue, "fp128") || equalsIgnoreCase(svalue, "binary128")) {if(b_in) v = 0; else v = BASE_FP128;}
660 else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "time", _("time"))) {if(b_in) v = 0; else v = BASE_TIME;}
661 else if(equalsIgnoreCase(svalue, "hex") || EQUALS_IGNORECASE_AND_LOCAL(svalue, "hexadecimal", _("hexadecimal"))) v = BASE_HEXADECIMAL;
662 else if(equalsIgnoreCase(svalue, "golden") || equalsIgnoreCase(svalue, "golden ratio") || svalue == "φ") v = BASE_GOLDEN_RATIO;
663 else if(equalsIgnoreCase(svalue, "supergolden") || equalsIgnoreCase(svalue, "supergolden ratio") || svalue == "ψ") v = BASE_SUPER_GOLDEN_RATIO;
664 else if(equalsIgnoreCase(svalue, "pi") || svalue == "π") v = BASE_PI;
665 else if(svalue == "e") v = BASE_E;
666 else if(svalue == "sqrt(2)" || svalue == "sqrt 2" || svalue == "sqrt2" || svalue == "√2") v = BASE_SQRT2;
667 else if(equalsIgnoreCase(svalue, "unicode")) v = BASE_UNICODE;
668 else if(equalsIgnoreCase(svalue, "duo") || EQUALS_IGNORECASE_AND_LOCAL(svalue, "duodecimal", _("duodecimal"))) v = 12;
669 else if(equalsIgnoreCase(svalue, "bin") || EQUALS_IGNORECASE_AND_LOCAL(svalue, "binary", _("binary"))) v = BASE_BINARY;
670 else if(equalsIgnoreCase(svalue, "oct") || EQUALS_IGNORECASE_AND_LOCAL(svalue, "octal", _("octal"))) v = BASE_OCTAL;
671 else if(equalsIgnoreCase(svalue, "dec") || EQUALS_IGNORECASE_AND_LOCAL(svalue, "decimal", _("decimal"))) v = BASE_DECIMAL;
672 else if(equalsIgnoreCase(svalue, "sexa") || EQUALS_IGNORECASE_AND_LOCAL(svalue, "sexagesimal", _("sexagesimal"))) {if(b_in) v = 0; else v = BASE_SEXAGESIMAL;}
673 else if(!b_in && !b_out && (index = svalue.find_first_of(SPACES)) != string::npos) {
674 str = svalue;
675 svalue = str.substr(index + 1, str.length() - (index + 1));
676 remove_blank_ends(svalue);
677 svar += " ";
678 str = str.substr(0, index);
679 remove_blank_ends(str);
680 svar += str;
681 gsub("_", " ", svar);
682 if(EQUALS_IGNORECASE_AND_LOCAL(svar, "base display", _("base display"))) {
683 goto set_option_place;
684 }
685 if(expression_executed) {
686 expression_executed = false;
687 set_option(string("outbase ") + str);
688 expression_executed = true;
689 } else {
690 set_option(string("outbase ") + str);
691 }
692 set_option(string("inbase ") + svalue);
693 return;
694 } else if(!empty_value) {
695 MathStructure m;
696 EvaluationOptions eo = evalops;
697 eo.parse_options.base = 10;
698 eo.approximation = APPROXIMATION_TRY_EXACT;
699 CALCULATOR->beginTemporaryStopMessages();
700 CALCULATOR->calculate(&m, CALCULATOR->unlocalizeExpression(svalue, eo.parse_options), 500, eo);
701 if(CALCULATOR->endTemporaryStopMessages()) {
702 v = 0;
703 } else if(m.isInteger() && m.number() >= 2 && m.number() <= 36) {
704 v = m.number().intValue();
705 } else if(m.isNumber() && (b_in || ((!m.number().isNegative() || m.number().isInteger()) && (m.number() > 1 || m.number() < -1)))) {
706 v = BASE_CUSTOM;
707 if(b_in) CALCULATOR->setCustomInputBase(m.number());
708 else CALCULATOR->setCustomOutputBase(m.number());
709 }
710 }
711 if(v == 0) {
712 PUTS_UNICODE(_("Illegal base."));
713 } else if(b_in) {
714 evalops.parse_options.base = v;
715 expression_format_updated(false);
716 } else {
717 printops.base = v;
718 result_format_updated();
719 }
720 } else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "assumptions", _("assumptions")) || svar == "ass") {
721 size_t i = svalue.find_first_of(SPACES);
722 if(i != string::npos) {
723 set_assumption(svalue.substr(0, i), false);
724 set_assumption(svalue.substr(i + 1, svalue.length() - (i + 1)), true);
725 } else {
726 set_assumption(svalue, false);
727 }
728 string value;
729 switch(CALCULATOR->defaultAssumptions()->sign()) {
730 case ASSUMPTION_SIGN_POSITIVE: {value = _("positive"); break;}
731 case ASSUMPTION_SIGN_NONPOSITIVE: {value = _("non-positive"); break;}
732 case ASSUMPTION_SIGN_NEGATIVE: {value = _("negative"); break;}
733 case ASSUMPTION_SIGN_NONNEGATIVE: {value = _("non-negative"); break;}
734 case ASSUMPTION_SIGN_NONZERO: {value = _("non-zero"); break;}
735 default: {}
736 }
737 if(!value.empty() && CALCULATOR->defaultAssumptions()->type() != ASSUMPTION_TYPE_NONE) value += " ";
738 switch(CALCULATOR->defaultAssumptions()->type()) {
739 case ASSUMPTION_TYPE_INTEGER: {value += _("integer"); break;}
740 case ASSUMPTION_TYPE_RATIONAL: {value += _("rational"); break;}
741 case ASSUMPTION_TYPE_REAL: {value += _("real"); break;}
742 case ASSUMPTION_TYPE_COMPLEX: {value += _("complex"); break;}
743 case ASSUMPTION_TYPE_NUMBER: {value += _("number"); break;}
744 case ASSUMPTION_TYPE_NONMATRIX: {value += _("non-matrix"); break;}
745 default: {}
746 }
747 if(value.empty()) value = _("unknown");
748 FPUTS_UNICODE(_("assumptions"), stdout); fputs(": ", stdout); PUTS_UNICODE(value.c_str());
749 expression_calculation_updated();
750 }
751 else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "all prefixes", _("all prefixes")) || svar == "allpref") SET_BOOL_D(printops.use_all_prefixes)
752 else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "color", _("color"))) {
753 int v = -1;
754 // light color
755 if(svalue == "2" || EQUALS_IGNORECASE_AND_LOCAL(svalue, "light", _("light"))) v = 2;
756 else if(svalue == "1" || EQUALS_IGNORECASE_AND_LOCAL(svalue, "default", _("default"))) v = 1;
757 else v = s2b(svalue);
758 if(v < 0 || v > 2) {
759 PUTS_UNICODE(_("Illegal value."));
760 } else {
761 colorize = v;
762 result_display_updated();
763 }
764 } else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "complex numbers", _("complex numbers")) || svar == "cplx") SET_BOOL_E(evalops.allow_complex)
765 else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "excessive parentheses", _("excessive parentheses")) || svar == "expar") SET_BOOL_D(printops.excessive_parenthesis)
766 else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "functions", _("functions")) || svar == "func") SET_BOOL_PV(evalops.parse_options.functions_enabled)
767 else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "infinite numbers", _("infinite numbers")) || svar == "inf") SET_BOOL_E(evalops.allow_infinite)
768 else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "show negative exponents", _("show negative exponents")) || svar == "negexp") SET_BOOL_D(printops.negative_exponents)
769 else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "minus last", _("minus last")) || svar == "minlast") {
770 {int v = s2b(svalue); if(v < 0) {PUTS_UNICODE(_("Illegal value."));} else if(printops.sort_options.minus_last != v) {printops.sort_options.minus_last = v; result_display_updated();}}
771 } else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "assume nonzero denominators", _("assume nonzero denominators")) || svar == "nzd") SET_BOOL_E(evalops.assume_denominators_nonzero)
772 else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "warn nonzero denominators", _("warn nonzero denominators")) || svar == "warnnzd") SET_BOOL_E(evalops.warn_about_denominators_assumed_nonzero)
773 else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "prefixes", _("prefixes")) || svar == "pref") SET_BOOL_D(printops.use_unit_prefixes)
774 else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "binary prefixes", _("binary prefixes")) || svar == "binpref") {
775 bool b = CALCULATOR->usesBinaryPrefixes() > 0;
776 SET_BOOL(b)
777 if(b != (CALCULATOR->usesBinaryPrefixes() > 0)) {
778 CALCULATOR->useBinaryPrefixes(b ? 1 : 0);
779 result_display_updated();
780 }
781 } else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "denominator prefixes", _("denominator prefixes")) || svar == "denpref") SET_BOOL_D(printops.use_denominator_prefix)
782 else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "place units separately", _("place units separately")) || svar == "unitsep") SET_BOOL_D(printops.place_units_separately)
783 else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "calculate variables", _("calculate variables")) || svar == "calcvar") SET_BOOL_E(evalops.calculate_variables)
784 else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "calculate functions", _("calculate functions")) || svar == "calcfunc") SET_BOOL_E(evalops.calculate_functions)
785 else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "sync units", _("sync units")) || svar == "sync") SET_BOOL_E(evalops.sync_units)
786 else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "temperature calculation", _("temperature calculation")) || svar == "temp") {
787 int v = -1;
788 if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "relative", _("relative"))) v = TEMPERATURE_CALCULATION_RELATIVE;
789 else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "hybrid", _("hybrid"))) v = TEMPERATURE_CALCULATION_HYBRID;
790 else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "absolute", _("absolute"))) v = TEMPERATURE_CALCULATION_ABSOLUTE;
791 else if(svalue.find_first_not_of(SPACES NUMBERS) == string::npos) {
792 v = s2i(svalue);
793 }
794 if(v < 0 || v > 2) {
795 PUTS_UNICODE(_("Illegal value."));
796 } else {
797 CALCULATOR->setTemperatureCalculationMode((TemperatureCalculationMode) v);
798 expression_calculation_updated();
799 tc_set = true;
800 }
801 } else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "round to even", _("round to even")) || svar == "rndeven") SET_BOOL_D(printops.round_halfway_to_even)
802 else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "rpn syntax", _("rpn syntax")) || svar == "rpnsyn") {
803 bool b = (evalops.parse_options.parsing_mode == PARSING_MODE_RPN);
804 SET_BOOL(b)
805 if(b != (evalops.parse_options.parsing_mode == PARSING_MODE_RPN)) {
806 if(b) {
807 nonrpn_parsing_mode = evalops.parse_options.parsing_mode;
808 evalops.parse_options.parsing_mode = PARSING_MODE_RPN;
809 } else {
810 evalops.parse_options.parsing_mode = nonrpn_parsing_mode;
811 }
812 expression_format_updated(false);
813 }
814 } else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "rpn", _("rpn")) && svalue.find(" ") == string::npos) {SET_BOOL(rpn_mode) if(!rpn_mode) CALCULATOR->clearRPNStack();}
815 else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "short multiplication", _("short multiplication")) || svar == "shortmul") SET_BOOL_D(printops.short_multiplication)
816 else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "lowercase e", _("lowercase e")) || svar == "lowe") SET_BOOL_D(printops.lower_case_e)
817 else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "lowercase numbers", _("lowercase numbers")) || svar == "lownum") SET_BOOL_D(printops.lower_case_numbers)
818 else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "imaginary j", _("imaginary j")) || svar == "imgj") {
819 bool b = CALCULATOR->getVariableById(VARIABLE_ID_I)->hasName("j") > 0;
820 SET_BOOL(b)
821 if(b != (CALCULATOR->getVariableById(VARIABLE_ID_I)->hasName("j") > 0)) {
822 if(b) {
823 ExpressionName ename = CALCULATOR->getVariableById(VARIABLE_ID_I)->getName(1);
824 ename.name = "j";
825 ename.reference = false;
826 CALCULATOR->getVariableById(VARIABLE_ID_I)->addName(ename, 1, true);
827 CALCULATOR->getVariableById(VARIABLE_ID_I)->setChanged(false);
828 } else {
829 CALCULATOR->getVariableById(VARIABLE_ID_I)->clearNonReferenceNames();
830 CALCULATOR->getVariableById(VARIABLE_ID_I)->setChanged(false);
831 }
832 result_display_updated();
833 }
834 } else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "base display", _("base display")) || svar == "basedisp") {
835 int v = -1;
836 if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "none", _("none"))) v = BASE_DISPLAY_NONE;
837 else if(empty_value || EQUALS_IGNORECASE_AND_LOCAL(svalue, "normal", _("normal"))) v = BASE_DISPLAY_NORMAL;
838 else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "alternative", _("alternative"))) v = BASE_DISPLAY_ALTERNATIVE;
839 else if(svalue.find_first_not_of(SPACES NUMBERS) == string::npos) {
840 v = s2i(svalue);
841 }
842 if(v < 0 || v > 2) {
843 PUTS_UNICODE(_("Illegal value."));
844 } else {
845 printops.base_display = (BaseDisplay) v;
846 result_display_updated();
847 }
848 } else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "two's complement", _("two's complement")) || svar == "twos") SET_BOOL_D(printops.twos_complement)
849 else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "hexadecimal two's", _("hexadecimal two's")) || svar == "hextwos") SET_BOOL_D(printops.hexadecimal_twos_complement)
850 else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "digit grouping", _("digit grouping")) || svar =="group") {
851 int v = -1;
852 if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "off", _("off"))) v = DIGIT_GROUPING_NONE;
853 else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "none", _("none"))) v = DIGIT_GROUPING_NONE;
854 else if(empty_value || EQUALS_IGNORECASE_AND_LOCAL(svalue, "standard", _("standard")) || EQUALS_IGNORECASE_AND_LOCAL(svalue, "on", _("on"))) v = DIGIT_GROUPING_STANDARD;
855 else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "locale", _("locale"))) v = DIGIT_GROUPING_LOCALE;
856 else if(svalue.find_first_not_of(SPACES NUMBERS) == string::npos) {
857 v = s2i(svalue);
858 }
859 if(v < DIGIT_GROUPING_NONE || v > DIGIT_GROUPING_LOCALE) {
860 PUTS_UNICODE(_("Illegal value."));
861 } else {
862 printops.digit_grouping = (DigitGrouping) v;
863 result_display_updated();
864 }
865 } else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "spell out logical", _("spell out logical")) || svar == "spellout") SET_BOOL_D(printops.spell_out_logical_operators)
866 else if((EQUALS_IGNORECASE_AND_LOCAL(svar, "ignore dot", _("ignore dot")) || svar == "nodot") && CALCULATOR->getDecimalPoint() != DOT) SET_BOOL_PF(evalops.parse_options.dot_as_separator)
867 else if((EQUALS_IGNORECASE_AND_LOCAL(svar, "ignore comma", _("ignore comma")) || svar == "nocomma") && CALCULATOR->getDecimalPoint() != COMMA) {
868 SET_BOOL(evalops.parse_options.comma_as_separator)
869 CALCULATOR->useDecimalPoint(evalops.parse_options.comma_as_separator);
870 expression_format_updated(false);
871 } else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "decimal comma", _("decimal comma"))) {
872 int v = -2;
873 if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "off", _("off"))) v = 0;
874 else if(empty_value || EQUALS_IGNORECASE_AND_LOCAL(svalue, "on", _("on"))) v = 1;
875 else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "locale", _("locale"))) v = -1;
876 else if(svalue.find_first_not_of(SPACES MINUS NUMBERS) == string::npos) {
877 v = s2i(svalue);
878 }
879 if(v < -1 || v > 1) {
880 PUTS_UNICODE(_("Illegal value."));
881 } else {
882 b_decimal_comma = v;
883 if(b_decimal_comma > 0) CALCULATOR->useDecimalComma();
884 else if(b_decimal_comma == 0) CALCULATOR->useDecimalPoint(evalops.parse_options.comma_as_separator);
885 if(v >= 0) {
886 expression_format_updated(false);
887 result_display_updated();
888 }
889 }
890 } else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "limit implicit multiplication", _("limit implicit multiplication")) || svar == "limimpl") {
891 int v = s2b(svalue); if(v < 0) {PUTS_UNICODE(_("Illegal value."));} else {printops.limit_implicit_multiplication = v; evalops.parse_options.limit_implicit_multiplication = v; expression_format_updated(true);}
892 } else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "spacious", _("spacious")) || svar == "space") SET_BOOL_D(printops.spacious)
893 else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "unicode", _("unicode")) || svar == "uni") {
894 int v = s2b(svalue); if(v < 0) {PUTS_UNICODE(_("Illegal value."));} else {printops.use_unicode_signs = v; result_display_updated();}
895 enable_unicode = -1;
896 } else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "units", _("units")) || svar == "unit") SET_BOOL_PV(evalops.parse_options.units_enabled)
897 else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "unknowns", _("unknowns")) || svar == "unknown") SET_BOOL_PV(evalops.parse_options.unknowns_enabled)
898 else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "variables", _("variables")) || svar == "var") SET_BOOL_PV(evalops.parse_options.variables_enabled)
899 else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "abbreviations", _("abbreviations")) || svar == "abbr" || svar == "abbrev") SET_BOOL_D(printops.abbreviate_names)
900 else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "show ending zeroes", _("show ending zeroes")) || svar == "zeroes") SET_BOOL_D(printops.show_ending_zeroes)
901 else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "repeating decimals", _("repeating decimals")) || svar == "repdeci") SET_BOOL_D(printops.indicate_infinite_series)
902 else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "angle unit", _("angle unit")) || svar == "angle") {
903 int v = -1;
904 if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "rad", _("rad")) || EQUALS_IGNORECASE_AND_LOCAL(svalue, "radians", _("radians"))) v = ANGLE_UNIT_RADIANS;
905 else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "deg", _("deg")) || EQUALS_IGNORECASE_AND_LOCAL(svalue, "degrees", _("degrees"))) v = ANGLE_UNIT_DEGREES;
906 else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "gra", _("gra")) || EQUALS_IGNORECASE_AND_LOCAL(svalue, "gradians", _("gradians"))) v = ANGLE_UNIT_GRADIANS;
907 else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "none", _("none"))) v = ANGLE_UNIT_NONE;
908 else if(!empty_value && svalue.find_first_not_of(SPACES NUMBERS) == string::npos) {
909 v = s2i(svalue);
910 }
911 if(v < 0 || v > 3) {
912 PUTS_UNICODE(_("Illegal value."));
913 } else {
914 evalops.parse_options.angle_unit = (AngleUnit) v;
915 hide_parse_errors = true;
916 expression_format_updated(true);
917 hide_parse_errors = false;
918 }
919 } else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "caret as xor", _("caret as xor")) || equalsIgnoreCase(svar, "xor^")) SET_BOOL_PT(caret_as_xor)
920 else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "parsing mode", _("parsing mode")) || svar == "parse" || svar == "syntax") {
921 int v = -1;
922 if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "adaptive", _("adaptive"))) v = PARSING_MODE_ADAPTIVE;
923 else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "implicit first", _("implicit first"))) v = PARSING_MODE_IMPLICIT_MULTIPLICATION_FIRST;
924 else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "conventional", _("conventional"))) v = PARSING_MODE_CONVENTIONAL;
925 // chain calculation mode (parsing mode)
926 else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "chain", _("chain"))) v = PARSING_MODE_CHAIN;
927 else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "rpn", _("rpn"))) v = PARSING_MODE_RPN;
928 else if(!empty_value && svalue.find_first_not_of(SPACES NUMBERS) == string::npos) {
929 v = s2i(svalue);
930 }
931 if(v < PARSING_MODE_ADAPTIVE || v > PARSING_MODE_RPN) {
932 PUTS_UNICODE(_("Illegal value."));
933 } else {
934 evalops.parse_options.parsing_mode = (ParsingMode) v;
935 expression_format_updated(true);
936 }
937 } else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "update exchange rates", _("update exchange rates")) || svar == "upxrates") {
938 if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "never", _("never"))) {
939 auto_update_exchange_rates = 0;
940 } else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "ask", _("ask"))) {
941 auto_update_exchange_rates = -1;
942 } else {
943 int v = s2i(svalue);
944 if(empty_value) v = 7;
945 if(v < 0) auto_update_exchange_rates = -1;
946 else auto_update_exchange_rates = v;
947 }
948 } else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "multiplication sign", _("multiplication sign")) || svar == "mulsign") {
949 int v = -1;
950 if(svalue == SIGN_MULTIDOT || svalue == ".") v = MULTIPLICATION_SIGN_DOT;
951 else if(svalue == SIGN_MIDDLEDOT) v = MULTIPLICATION_SIGN_ALTDOT;
952 else if(svalue == SIGN_MULTIPLICATION || svalue == "x") v = MULTIPLICATION_SIGN_X;
953 else if(svalue == "*") v = MULTIPLICATION_SIGN_ASTERISK;
954 else if(!empty_value && svalue.find_first_not_of(SPACES NUMBERS) == string::npos) {
955 v = s2i(svalue);
956 }
957 if(v < MULTIPLICATION_SIGN_ASTERISK || v > MULTIPLICATION_SIGN_ALTDOT) {
958 PUTS_UNICODE(_("Illegal value."));
959 } else {
960 printops.multiplication_sign = (MultiplicationSign) v;
961 result_display_updated();
962 }
963 } else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "division sign", _("division sign")) || svar == "divsign") {
964 int v = -1;
965 if(svalue == SIGN_DIVISION_SLASH) v = DIVISION_SIGN_DIVISION_SLASH;
966 else if(svalue == SIGN_DIVISION) v = DIVISION_SIGN_DIVISION;
967 else if(svalue == "/") v = DIVISION_SIGN_SLASH;
968 else if(!empty_value && svalue.find_first_not_of(SPACES NUMBERS) == string::npos) {
969 v = s2i(svalue);
970 }
971 if(v < 0 || v > 2) {
972 PUTS_UNICODE(_("Illegal value."));
973 } else {
974 printops.division_sign = (DivisionSign) v;
975 result_display_updated();
976 }
977 } else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "approximation", _("approximation")) || svar == "appr" || svar == "approx") {
978 int v = -1;
979 if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "exact", _("exact"))) v = APPROXIMATION_EXACT;
980 else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "auto", _("auto"))) v = -1;
981 else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "dual", _("dual"))) v = APPROXIMATION_APPROXIMATE + 1;
982 else if(empty_value || EQUALS_IGNORECASE_AND_LOCAL(svalue, "try exact", _("try exact")) || svalue == "try") v = APPROXIMATION_TRY_EXACT;
983 else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "approximate", _("approximate")) || svalue == "approx") v = APPROXIMATION_APPROXIMATE;
984 else if(svalue.find_first_not_of(SPACES NUMBERS) == string::npos) {
985 v = s2i(svalue);
986 }
987 if(v > APPROXIMATION_APPROXIMATE + 1) {
988 PUTS_UNICODE(_("Illegal value."));
989 } else {
990 if(v < 0) {
991 evalops.approximation = APPROXIMATION_TRY_EXACT;
992 dual_approximation = -1;
993 } else if(v == APPROXIMATION_APPROXIMATE + 1) {
994 evalops.approximation = APPROXIMATION_TRY_EXACT;
995 dual_approximation = 1;
996 } else {
997 evalops.approximation = (ApproximationMode) v;
998 dual_approximation = 0;
999 }
1000 expression_calculation_updated();
1001 }
1002 } else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "interval calculation", _("interval calculation")) || svar == "ic" || EQUALS_IGNORECASE_AND_LOCAL(svar, "uncertainty propagation", _("uncertainty propagation")) || svar == "up") {
1003 int v = -1;
1004 if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "variance formula", _("variance formula")) || EQUALS_IGNORECASE_AND_LOCAL(svalue, "variance", _("variance"))) v = INTERVAL_CALCULATION_VARIANCE_FORMULA;
1005 else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "interval arithmetic", _("interval arithmetic")) || svalue == "iv") v = INTERVAL_CALCULATION_INTERVAL_ARITHMETIC;
1006 else if(!empty_value && svalue.find_first_not_of(SPACES NUMBERS) == string::npos) {
1007 v = s2i(svalue);
1008 }
1009 if(v < INTERVAL_CALCULATION_NONE || v > INTERVAL_CALCULATION_SIMPLE_INTERVAL_ARITHMETIC) {
1010 PUTS_UNICODE(_("Illegal value."));
1011 } else {
1012 evalops.interval_calculation = (IntervalCalculation) v;
1013 expression_calculation_updated();
1014 }
1015 } else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "autoconversion", _("autoconversion")) || svar == "conv") {
1016 int v = -1;
1017 MixedUnitsConversion muc = MIXED_UNITS_CONVERSION_DEFAULT;
1018 if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "none", _("none"))) {v = POST_CONVERSION_NONE; muc = MIXED_UNITS_CONVERSION_NONE;}
1019 else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "best", _("best"))) v = POST_CONVERSION_OPTIMAL_SI;
1020 else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "optimalsi", _("optimalsi")) || svalue == "si") v = POST_CONVERSION_OPTIMAL_SI;
1021 else if(empty_value || EQUALS_IGNORECASE_AND_LOCAL(svalue, "optimal", _("optimal"))) v = POST_CONVERSION_OPTIMAL;
1022 else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "base", _("base"))) v = POST_CONVERSION_BASE;
1023 else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "mixed", _("mixed"))) v = POST_CONVERSION_OPTIMAL + 1;
1024 else if(svalue.find_first_not_of(SPACES NUMBERS) == string::npos) {
1025 v = s2i(svalue);
1026 if(v == 1) v = 3;
1027 else if(v == 3) v = 1;
1028 }
1029 if(v == POST_CONVERSION_OPTIMAL + 1) {
1030 v = POST_CONVERSION_NONE;
1031 muc = MIXED_UNITS_CONVERSION_DEFAULT;
1032 } else if(v == 0) {
1033 v = POST_CONVERSION_NONE;
1034 muc = MIXED_UNITS_CONVERSION_NONE;
1035 }
1036 if(v < 0 || v > POST_CONVERSION_OPTIMAL) {
1037 PUTS_UNICODE(_("Illegal value."));
1038 } else {
1039 evalops.auto_post_conversion = (AutoPostConversion) v;
1040 evalops.mixed_units_conversion = muc;
1041 expression_calculation_updated();
1042 }
1043 } else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "currency conversion", _("currency conversion")) || svar == "curconv") SET_BOOL_E(evalops.local_currency_conversion)
1044 else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "algebra mode", _("algebra mode")) || svar == "alg") {
1045 int v = -1;
1046 if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "none", _("none"))) v = STRUCTURING_NONE;
1047 else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "simplify", _("simplify")) || EQUALS_IGNORECASE_AND_LOCAL(svalue, "expand", _("expand"))) v = STRUCTURING_SIMPLIFY;
1048 else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "factorize", _("factorize")) || svalue == "factor") v = STRUCTURING_FACTORIZE;
1049 else if(!empty_value && svalue.find_first_not_of(SPACES NUMBERS) == string::npos) {
1050 v = s2i(svalue);
1051 }
1052 if(v < 0 || v > STRUCTURING_FACTORIZE) {
1053 PUTS_UNICODE(_("Illegal value."));
1054 } else {
1055 evalops.structuring = (StructuringMode) v;
1056 printops.allow_factorization = (evalops.structuring == STRUCTURING_FACTORIZE);
1057 expression_calculation_updated();
1058 }
1059 } else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "exact", _("exact"))) {
1060 int v = s2b(svalue);
1061 if(v < 0) {
1062 PUTS_UNICODE(_("Illegal value."));
1063 } else if(v > 0) {
1064 evalops.approximation = APPROXIMATION_EXACT;
1065 expression_calculation_updated();
1066 } else {
1067 evalops.approximation = APPROXIMATION_TRY_EXACT;
1068 expression_calculation_updated();
1069 }
1070 } else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "ignore locale", _("ignore locale"))) {
1071 int v = s2b(svalue);
1072 if(v < 0) {
1073 PUTS_UNICODE(_("Illegal value."));
1074 } else if(v != ignore_locale) {
1075 if(v > 0) {
1076 ignore_locale = true;
1077 } else {
1078 ignore_locale = false;
1079 }
1080 PUTS_UNICODE("Please restart the program for the change to take effect.");
1081 }
1082 } else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "save mode", _("save mode"))) {
1083 int v = s2b(svalue);
1084 if(v < 0) {
1085 PUTS_UNICODE(_("Illegal value."));
1086 } else if(v > 0) {
1087 save_mode_on_exit = true;
1088 } else {
1089 save_mode_on_exit = false;
1090 }
1091 } else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "save definitions", _("save definitions")) || svar == "save defs") {
1092 int v = s2b(svalue);
1093 if(v < 0) {
1094 PUTS_UNICODE(_("Illegal value."));
1095 } else if(v > 0) {
1096 save_defs_on_exit = true;
1097 } else {
1098 save_defs_on_exit = false;
1099 }
1100 } else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "scientific notation", _("scientific notation")) || svar == "exp mode" || svar == "exp") {
1101 int v = -1;
1102 bool valid = true;
1103 if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "off", _("off"))) v = EXP_NONE;
1104 else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "auto", _("auto"))) v = EXP_PRECISION;
1105 else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "pure", _("pure"))) v = EXP_PURE;
1106 else if(empty_value || EQUALS_IGNORECASE_AND_LOCAL(svalue, "scientific", _("scientific"))) v = EXP_SCIENTIFIC;
1107 else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "engineering", _("engineering"))) v = EXP_BASE_3;
1108 else if(svalue.find_first_not_of(SPACES NUMBERS MINUS) == string::npos) v = s2i(svalue);
1109 else valid = false;
1110 if(valid) {
1111 printops.min_exp = v;
1112 result_format_updated();
1113 } else {
1114 PUTS_UNICODE(_("Illegal value."));
1115 }
1116 } else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "precision", _("precision")) || svar == "prec") {
1117 int v = 0;
1118 if(!empty_value && svalue.find_first_not_of(SPACES NUMBERS) == string::npos) v = s2i(svalue);
1119 if(v < 1) {
1120 PUTS_UNICODE(_("Illegal value."));
1121 } else {
1122 CALCULATOR->setPrecision(v);
1123 expression_calculation_updated();
1124 }
1125 } else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "interval display", _("interval display")) || svar == "ivdisp") {
1126 int v = -1;
1127 if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "adaptive", _("adaptive"))) v = 0;
1128 else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "significant", _("significant"))) v = INTERVAL_DISPLAY_SIGNIFICANT_DIGITS + 1;
1129 else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "interval", _("interval"))) v = INTERVAL_DISPLAY_INTERVAL + 1;
1130 else if(empty_value || EQUALS_IGNORECASE_AND_LOCAL(svalue, "plusminus", _("plusminus"))) v = INTERVAL_DISPLAY_PLUSMINUS + 1;
1131 else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "midpoint", _("midpoint"))) v = INTERVAL_DISPLAY_MIDPOINT + 1;
1132 else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "upper", _("upper"))) v = INTERVAL_DISPLAY_UPPER + 1;
1133 else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "lower", _("lower"))) v = INTERVAL_DISPLAY_LOWER + 1;
1134 else if(svalue.find_first_not_of(SPACES NUMBERS) == string::npos) {
1135 v = s2i(svalue);
1136 }
1137 if(v == 0) {
1138 adaptive_interval_display = true;
1139 printops.interval_display = INTERVAL_DISPLAY_SIGNIFICANT_DIGITS;
1140 result_format_updated();
1141 } else {
1142 v--;
1143 if(v < INTERVAL_DISPLAY_SIGNIFICANT_DIGITS || v > INTERVAL_DISPLAY_UPPER) {
1144 PUTS_UNICODE(_("Illegal value."));
1145 } else {
1146 adaptive_interval_display = false;
1147 printops.interval_display = (IntervalDisplay) v;
1148 result_format_updated();
1149 }
1150 }
1151 } else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "interval arithmetic", _("interval arithmetic")) || svar == "ia" || svar == "interval") {
1152 bool b = CALCULATOR->usesIntervalArithmetic();
1153 SET_BOOL(b)
1154 if(b != CALCULATOR->usesIntervalArithmetic()) {
1155 CALCULATOR->useIntervalArithmetic(b);
1156 expression_calculation_updated();
1157 }
1158 } else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "variable units", _("variable units")) || svar == "varunits") {
1159 bool b = CALCULATOR->variableUnitsEnabled();
1160 SET_BOOL(b)
1161 if(b != CALCULATOR->variableUnitsEnabled()) {
1162 CALCULATOR->setVariableUnitsEnabled(b);
1163 expression_calculation_updated();
1164 }
1165 } else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "max decimals", _("max decimals")) || svar == "maxdeci") {
1166 int v = -1;
1167 if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "off", _("off"))) v = -1;
1168 else if(!empty_value && svalue.find_first_not_of(SPACES NUMBERS) == string::npos) v = s2i(svalue);
1169 if(v < 0) {
1170 printops.use_max_decimals = false;
1171 result_format_updated();
1172 } else {
1173 printops.max_decimals = v;
1174 printops.use_max_decimals = true;
1175 result_format_updated();
1176 }
1177 } else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "min decimals", _("min decimals")) || svar == "mindeci") {
1178 int v = -1;
1179 if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "off", _("off"))) v = -1;
1180 else if(!empty_value && svalue.find_first_not_of(SPACES NUMBERS) == string::npos) v = s2i(svalue);
1181 if(v < 0) {
1182 printops.min_decimals = 0;
1183 printops.use_min_decimals = false;
1184 result_format_updated();
1185 } else {
1186 printops.min_decimals = v;
1187 printops.use_min_decimals = true;
1188 result_format_updated();
1189 }
1190 } else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "fractions", _("fractions")) || svar == "fr") {
1191 int v = -1;
1192 if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "off", _("off"))) v = FRACTION_DECIMAL;
1193 else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "auto", _("auto"))) v = -1;
1194 else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "exact", _("exact"))) v = FRACTION_DECIMAL_EXACT;
1195 else if(empty_value || EQUALS_IGNORECASE_AND_LOCAL(svalue, "on", _("on"))) v = FRACTION_FRACTIONAL;
1196 else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "combined", _("combined")) || EQUALS_IGNORECASE_AND_LOCAL(svalue, "mixed", _("mixed"))) v = FRACTION_COMBINED;
1197 else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "long", _("long"))) v = FRACTION_COMBINED + 1;
1198 else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "dual", _("dual"))) v = FRACTION_COMBINED + 2;
1199 else if(svalue.find_first_not_of(SPACES NUMBERS) == string::npos) {
1200 v = s2i(svalue);
1201 }
1202 if(v > FRACTION_COMBINED + 2) {
1203 PUTS_UNICODE(_("Illegal value."));
1204 } else {
1205 printops.restrict_fraction_length = (v == FRACTION_FRACTIONAL || v == FRACTION_COMBINED);
1206 if(v < 0) dual_fraction = -1;
1207 else if(v == FRACTION_COMBINED + 2) dual_fraction = 1;
1208 else dual_fraction = 0;
1209 if(v == FRACTION_COMBINED + 1) v = FRACTION_FRACTIONAL;
1210 else if(v < 0 || v == FRACTION_COMBINED + 2) v = FRACTION_DECIMAL;
1211 printops.number_fraction_format = (NumberFractionFormat) v;
1212 result_format_updated();
1213 }
1214 } else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "complex form", _("complex form")) || svar == "cplxform") {
1215 int v = -1;
1216 if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "rectangular", _("rectangular")) || EQUALS_IGNORECASE_AND_LOCAL(svalue, "cartesian", _("cartesian")) || svalue == "rect") v = COMPLEX_NUMBER_FORM_RECTANGULAR;
1217 else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "exponential", _("exponential")) || svalue == "exp") v = COMPLEX_NUMBER_FORM_EXPONENTIAL;
1218 else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "polar", _("polar"))) v = COMPLEX_NUMBER_FORM_POLAR;
1219 else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "angle", _("angle")) || EQUALS_IGNORECASE_AND_LOCAL(svalue, "phasor", _("phasor"))) v = COMPLEX_NUMBER_FORM_CIS + 1;
1220 else if(svar == "cis") v = COMPLEX_NUMBER_FORM_CIS;
1221 else if(!empty_value && svalue.find_first_not_of(SPACES NUMBERS) == string::npos) {
1222 v = s2i(svalue);
1223 }
1224 if(v < 0 || v > 4) {
1225 PUTS_UNICODE(_("Illegal value."));
1226 } else {
1227 complex_angle_form = (v > 3);
1228 if(v == 4) v--;
1229 evalops.complex_number_form = (ComplexNumberForm) v;
1230 expression_calculation_updated();
1231 }
1232 } else if(EQUALS_IGNORECASE_AND_LOCAL(svar, "read precision", _("read precision")) || svar == "readprec") {
1233 int v = -1;
1234 if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "off", _("off"))) v = DONT_READ_PRECISION;
1235 else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "always", _("always"))) v = ALWAYS_READ_PRECISION;
1236 else if(empty_value || EQUALS_IGNORECASE_AND_LOCAL(svalue, "when decimals", _("when decimals")) || EQUALS_IGNORECASE_AND_LOCAL(svalue, "on", _("on"))) v = READ_PRECISION_WHEN_DECIMALS;
1237 else if(svalue.find_first_not_of(SPACES NUMBERS) == string::npos) {
1238 v = s2i(svalue);
1239 }
1240 if(v < 0 || v > 2) {
1241 PUTS_UNICODE(_("Illegal value."));
1242 } else {
1243 evalops.parse_options.read_precision = (ReadPrecisionMode) v;
1244 expression_format_updated(true);
1245 }
1246 } else {
1247 if(i_underscore == string::npos) {
1248 if(index != string::npos) {
1249 if((index = svar.find_last_of(SPACES)) != string::npos) {
1250 svar = svar.substr(0, index);
1251 remove_blank_ends(svar);
1252 str = str.substr(index + 1);
1253 remove_blank_ends(str);
1254 svalue = str;
1255 gsub("_", " ", svar);
1256 gsub(SIGN_MINUS, "-", svalue);
1257 goto set_option_place;
1258 }
1259 }
1260 if(!empty_value && !svalue.empty()) {
1261 svar += " ";
1262 svar += svalue;
1263 svalue = "1";
1264 empty_value = true;
1265 goto set_option_place;
1266 }
1267 }
1268 PUTS_UNICODE(_("Unrecognized option."));
1269 }
1270 }
1271
1272 #define STR_AND_TABS(x) str = x; pctl = unicode_length(str); if(pctl >= 32) {str += "\t";} else if(pctl >= 24) {str += "\t\t";} else if(pctl >= 16) {str += "\t\t\t";} else if(pctl >= 8) {str += "\t\t\t\t";} else {str += "\t\t\t\t\t";}
1273 #define STR_AND_TABS_T1(x) str = x; pctl = unicode_length(str); str += "\t";
1274 #define STR_AND_TABS_T2(x) str = x; pctl = unicode_length(str); if(pctl >= 8) {str += "\t";} else {str += "\t\t";}
1275 #define STR_AND_TABS_T3(x) str = x; pctl = unicode_length(str); if(pctl >= 16) {str += "\t";} else if(pctl >= 8) {str += "\t\t";} else {str += "\t\t\t";}
1276 #define STR_AND_TABS_T4(x) str = x; pctl = unicode_length(str); if(pctl >= 24) {str += "\t";} else if(pctl >= 16) {str += "\t\t";} else if(pctl >= 8) {str += "\t\t\t";} else {str += "\t\t\t\t";}
1277
1278 #define BEGIN_BOLD(x) if(DO_FORMAT) {x += "\033[1m";}
1279 #define END_BOLD(x) if(DO_FORMAT) {x += "\033[0m";}
1280 #define BEGIN_UNDERLINED(x) if(DO_FORMAT) {x += "\033[4m";}
1281 #define END_UNDERLINED(x) if(DO_FORMAT) {x += "\033[0m";}
1282 #define BEGIN_ITALIC(x) if(DO_FORMAT) {x += "\033[3m";}
1283 #define END_ITALIC(x) if(DO_FORMAT) {x += "\033[23m";}
1284 #define PUTS_BOLD(x) if(!DO_FORMAT) {str = x;} else {str = "\033[1m"; str += x; str += "\033[0m";} PUTS_UNICODE(str.c_str());
1285 #define PUTS_ITALIC(x) if(!DO_FORMAT) {str = x;} else {str = "\033[3m"; str += x; str += "\033[23m";} PUTS_UNICODE(str.c_str());
1286 #define PUTS_UNDERLINED(x) if(!DO_FORMAT) {str = x;} else {str = "\033[4m"; str += x; str += "\033[0m";} PUTS_UNICODE(str.c_str());
1287
equalsIgnoreCase(const string & str1,const string & str2,size_t i2,size_t i2_end,size_t minlength)1288 bool equalsIgnoreCase(const string &str1, const string &str2, size_t i2, size_t i2_end, size_t minlength) {
1289 if(str1.empty() || str2.empty()) return false;
1290 size_t l = 0;
1291 if(i2_end == string::npos) i2_end = str2.length();
1292 for(size_t i1 = 0;; i1++, i2++) {
1293 if(i2 >= i2_end) {
1294 return i1 >= str1.length();
1295 }
1296 if(i1 >= str1.length()) break;
1297 if((str1[i1] < 0 && i1 + 1 < str1.length()) || (str2[i2] < 0 && i2 + 1 < str2.length())) {
1298 size_t iu1 = 1, iu2 = 1;
1299 if(str1[i1] < 0) {
1300 while(iu1 + i1 < str1.length() && str1[i1 + iu1] < 0) {
1301 iu1++;
1302 }
1303 }
1304 if(str2[i2] < 0) {
1305 while(iu2 + i2 < str2.length() && str2[i2 + iu2] < 0) {
1306 iu2++;
1307 }
1308 }
1309 bool isequal = (iu1 == iu2);
1310 if(isequal) {
1311 for(size_t i = 0; i < iu1; i++) {
1312 if(str1[i1 + i] != str2[i2 + i]) {
1313 isequal = false;
1314 break;
1315 }
1316 }
1317 }
1318 if(!isequal) {
1319 char *gstr1 = utf8_strdown(str1.c_str() + (sizeof(char) * i1), iu1);
1320 char *gstr2 = utf8_strdown(str2.c_str() + (sizeof(char) * i2), iu2);
1321 if(!gstr1 || !gstr2) return false;
1322 bool b = strcmp(gstr1, gstr2) == 0;
1323 free(gstr1);
1324 free(gstr2);
1325 if(!b) return false;
1326 }
1327 i1 += iu1 - 1;
1328 i2 += iu2 - 1;
1329 } else if(str1[i1] != str2[i2] && !((str1[i1] >= 'a' && str1[i1] <= 'z') && str1[i1] - 32 == str2[i2]) && !((str1[i1] <= 'Z' && str1[i1] >= 'A') && str1[i1] + 32 == str2[i2])) {
1330 return false;
1331 }
1332 l++;
1333 }
1334 return l >= minlength;
1335 }
1336
key_exact(int i1,int i2)1337 int key_exact(int i1, int i2) {
1338 #ifdef HAVE_LIBREADLINE
1339 if(rl_end > 0) {
1340 rl_point = rl_end;
1341 return 0;
1342 }
1343 #endif
1344 FPUTS_UNICODE(_("set"), stdout); fputs(" ", stdout); FPUTS_UNICODE(_("approximation"), stdout); fputs(" ", stdout);
1345 if(evalops.approximation == APPROXIMATION_EXACT) {
1346 evalops.approximation = APPROXIMATION_TRY_EXACT;
1347 dual_approximation = 0;
1348 PUTS_UNICODE(_("try exact"));
1349 } else if(dual_approximation) {
1350 evalops.approximation = APPROXIMATION_EXACT;
1351 PUTS_UNICODE(_("exact"));
1352 } else {
1353 evalops.approximation = APPROXIMATION_TRY_EXACT;
1354 dual_approximation = -1;
1355 PUTS_UNICODE(_("auto"));
1356 }
1357 expression_calculation_updated();
1358 fputs("> ", stdout);
1359 return 0;
1360 }
1361
key_fraction(int,int)1362 int key_fraction(int, int) {
1363 #ifdef HAVE_LIBREADLINE
1364 if(rl_end > 0) {
1365 if(rl_point < rl_end) rl_point++;
1366 return 0;
1367 }
1368 #endif
1369 FPUTS_UNICODE(_("set"), stdout); fputs(" ", stdout); FPUTS_UNICODE(_("fraction"), stdout); fputs(" ", stdout);
1370 if(dual_fraction) {
1371 dual_fraction = 0;
1372 printops.number_fraction_format = FRACTION_COMBINED;
1373 PUTS_UNICODE(_("mixed"));
1374 } else if(printops.number_fraction_format == FRACTION_FRACTIONAL) {
1375 dual_fraction = 0;
1376 printops.number_fraction_format = FRACTION_DECIMAL;
1377 PUTS_UNICODE(_("off"));
1378 } else if(printops.number_fraction_format == FRACTION_COMBINED) {
1379 dual_fraction = 0;
1380 printops.number_fraction_format = FRACTION_FRACTIONAL;
1381 PUTS_UNICODE(_("on"));
1382 } else {
1383 dual_fraction = -1;
1384 printops.number_fraction_format = FRACTION_DECIMAL;
1385 PUTS_UNICODE(_("auto"));
1386 }
1387 printops.restrict_fraction_length = (printops.number_fraction_format == FRACTION_FRACTIONAL || printops.number_fraction_format == FRACTION_COMBINED);
1388 result_format_updated();
1389 fputs("> ", stdout);
1390 return 0;
1391 }
1392
key_save(int,int)1393 int key_save(int, int) {
1394 #ifdef HAVE_LIBREADLINE
1395 if(rl_end > 0) {
1396 rl_point = 0;
1397 return 0;
1398 }
1399 #endif
1400 string name;
1401 string cat = CALCULATOR->temporaryCategory();
1402 string title;
1403 bool b = true;
1404 #ifdef HAVE_LIBREADLINE
1405 rl_clear_visible_line();
1406 #endif
1407 FPUTS_UNICODE(_("Name"), stdout);
1408 #ifdef HAVE_LIBREADLINE
1409 char *rlbuffer = readline(": ");
1410 if(!rlbuffer) return 1;
1411 name = rlbuffer;
1412 free(rlbuffer);
1413 #else
1414 fputs(": ", stdout);
1415 if(!fgets(buffer, 1000, stdin)) return 1;
1416 name = buffer;
1417 #endif
1418 remove_blank_ends(name);
1419
1420 if(!CALCULATOR->variableNameIsValid(name)) {
1421 name = CALCULATOR->convertToValidVariableName(name);
1422 if(!CALCULATOR->variableNameIsValid(name)) {
1423 PUTS_UNICODE(_("Illegal name."));
1424 b = false;
1425 } else {
1426 size_t l = name.length() + strlen(_("Illegal name. Save as %s instead (default: no)?"));
1427 char *cstr = (char*) malloc(sizeof(char) * (l + 1));
1428 snprintf(cstr, l, _("Illegal name. Save as %s instead (default: no)?"), name.c_str());
1429 if(!ask_question(cstr)) {
1430 b = false;
1431 }
1432 free(cstr);
1433 }
1434 }
1435 Variable *v = NULL;
1436 if(b) v = CALCULATOR->getActiveVariable(name);
1437 if(b && ((!v && CALCULATOR->variableNameTaken(name)) || (v && (!v->isKnown() || !v->isLocal() || v->category() != CALCULATOR->temporaryCategory())))) {
1438 b = ask_question(_("A unit or variable with the same name already exists.\nDo you want to overwrite it (default: no)?"));
1439 }
1440 if(b) {
1441 if(v && v->isLocal() && v->isKnown()) {
1442 if(!title.empty()) v->setTitle(title);
1443 ((KnownVariable*) v)->set(*mstruct);
1444 if(v->countNames() == 0) {
1445 ExpressionName ename(name);
1446 ename.reference = true;
1447 v->setName(ename, 1);
1448 } else {
1449 v->setName(name, 1);
1450 }
1451 } else {
1452 CALCULATOR->addVariable(new KnownVariable(cat, name, *mstruct, title));
1453 }
1454 }
1455 fputs("> ", stdout);
1456 #ifdef HAVE_LIBREADLINE
1457 rlbuffer = readline("");
1458 if(rlbuffer) free(rlbuffer);
1459 #endif
1460 return 0;
1461 }
1462
title_matches(ExpressionItem * item,const string & str,size_t minlength=0)1463 bool title_matches(ExpressionItem *item, const string &str, size_t minlength = 0) {
1464 const string &title = item->title(true);
1465 size_t i = 0;
1466 while(true) {
1467 while(true) {
1468 if(i >= title.length()) return false;
1469 if(title[i] != ' ') break;
1470 i++;
1471 }
1472 size_t i2 = title.find(' ', i);
1473 if(equalsIgnoreCase(str, title, i, i2, minlength)) {
1474 return true;
1475 }
1476 if(i2 == string::npos) break;
1477 i = i2 + 1;
1478 }
1479 return false;
1480 }
name_matches(ExpressionItem * item,const string & str)1481 bool name_matches(ExpressionItem *item, const string &str) {
1482 for(size_t i2 = 1; i2 <= item->countNames(); i2++) {
1483 if(item->getName(i2).case_sensitive) {
1484 if(str == item->getName(i2).name.substr(0, str.length())) {
1485 return true;
1486 }
1487 } else {
1488 if(equalsIgnoreCase(str, item->getName(i2).name, 0, str.length(), 0)) {
1489 return true;
1490 }
1491 }
1492 }
1493 return false;
1494 }
name_matches(Prefix * prefix,const string & str)1495 bool name_matches(Prefix *prefix, const string &str) {
1496 if(str == prefix->unicodeName(false).substr(0, str.length())) return true;
1497 if(str == prefix->shortName(false).substr(0, str.length())) return true;
1498 if(equalsIgnoreCase(str, prefix->longName(false, false), 0, str.length(), 0)) return true;
1499 return false;
1500 }
country_matches(Unit * u,const string & str,size_t minlength=0)1501 bool country_matches(Unit *u, const string &str, size_t minlength = 0) {
1502 const string &countries = u->countries();
1503 size_t i = 0;
1504 while(true) {
1505 while(true) {
1506 if(i >= countries.length()) return false;
1507 if(countries[i] != ' ') break;
1508 i++;
1509 }
1510 size_t i2 = countries.find(',', i);
1511 if(equalsIgnoreCase(str, countries, i, i2, minlength)) {
1512 return true;
1513 }
1514 if(i2 == string::npos) break;
1515 i = i2 + 1;
1516 }
1517 return false;
1518 }
1519
show_calendars(const QalculateDateTime & date,bool indentation=true)1520 void show_calendars(const QalculateDateTime &date, bool indentation = true) {
1521 string str, calstr;
1522 int pctl;
1523 bool b_fail;
1524 long int y, m, d;
1525 STR_AND_TABS((indentation ? string(" ") + _("Calendar") : _("Calendar"))); str += _("Day"); str += ", "; str += _("Month"); str += ", "; str += _("Year"); PUTS_UNICODE(str.c_str());
1526 #define PUTS_CALENDAR(x, c) calstr = ""; BEGIN_BOLD(calstr); STR_AND_TABS((indentation ? string(" ") + x : x)); calstr += str; END_BOLD(calstr); b_fail = !dateToCalendar(date, y, m, d, c); if(b_fail) {calstr += _("failed");} else {calstr += i2s(d); calstr += " "; calstr += monthName(m, c, true); calstr += " "; calstr += i2s(y);} FPUTS_UNICODE(calstr.c_str(), stdout);
1527 PUTS_CALENDAR(string(_("Gregorian:")), CALENDAR_GREGORIAN); puts("");
1528 PUTS_CALENDAR(string(_("Hebrew:")), CALENDAR_HEBREW); puts("");
1529 PUTS_CALENDAR(string(_("Islamic:")), CALENDAR_ISLAMIC); puts("");
1530 PUTS_CALENDAR(string(_("Persian:")), CALENDAR_PERSIAN); puts("");
1531 PUTS_CALENDAR(string(_("Indian national:")), CALENDAR_INDIAN); puts("");
1532 PUTS_CALENDAR(string(_("Chinese:")), CALENDAR_CHINESE);
1533 long int cy, yc, st, br;
1534 chineseYearInfo(y, cy, yc, st, br);
1535 if(!b_fail) {FPUTS_UNICODE((string(" (") + chineseStemName(st) + string(" ") + chineseBranchName(br) + ")").c_str(), stdout);}
1536 puts("");
1537 PUTS_CALENDAR(string(_("Julian:")), CALENDAR_JULIAN); puts("");
1538 PUTS_CALENDAR(string(_("Revised julian:")), CALENDAR_MILANKOVIC); puts("");
1539 PUTS_CALENDAR(string(_("Coptic:")), CALENDAR_COPTIC); puts("");
1540 PUTS_CALENDAR(string(_("Ethiopian:")), CALENDAR_ETHIOPIAN); puts("");
1541 //PUTS_CALENDAR(string(_("Egyptian:")), CALENDAR_EGYPTIAN);
1542 }
1543
1544
list_defs(bool in_interactive,char list_type=0,string search_str="")1545 void list_defs(bool in_interactive, char list_type = 0, string search_str = "") {
1546 #ifdef HAVE_LIBREADLINE
1547 int rows, cols, rcount = 0;
1548 bool check_sf = (cfile == NULL);
1549 char sf_c;
1550 if(in_interactive && !cfile) {
1551 rl_get_screen_size(&rows, &cols);
1552 } else {
1553 cols = 80;
1554 }
1555 #else
1556 int cols = 80;
1557 #endif
1558 string str_lb;
1559 string str;
1560 if(!search_str.empty()) {
1561 int max_l = 0;
1562 list<string> name_list;
1563 int i_end = 0;
1564 size_t i2 = 0;
1565 if(list_type == 'v') i2 = 1;
1566 else if(list_type == 'u' || list_type == 'c') i2 = 2;
1567 else if(list_type == 'p') i2 = 3;
1568 for(; i2 <= 3; i2++) {
1569 if(i2 == 0) i_end = CALCULATOR->functions.size();
1570 else if(i2 == 1) i_end = CALCULATOR->variables.size();
1571 else if(i2 == 2) i_end = CALCULATOR->units.size();
1572 else if(i2 == 3) i_end = CALCULATOR->prefixes.size();
1573 ExpressionItem *item = NULL;
1574 string name_str, name_str2;
1575 for(int i = 0; i < i_end; i++) {
1576 if(i2 == 0) item = CALCULATOR->functions[i];
1577 else if(i2 == 1) item = CALCULATOR->variables[i];
1578 else if(i2 == 2) item = CALCULATOR->units[i];
1579 if(i2 == 3) {
1580 if(name_matches(CALCULATOR->prefixes[i], search_str)) {
1581 Prefix *prefix = CALCULATOR->prefixes[i];
1582 name_str = "";
1583 if(printops.use_unicode_signs && !prefix->unicodeName(false).empty()) name_str += prefix->unicodeName(false);
1584 if(!prefix->shortName(false, false).empty()) {if(!name_str.empty()) name_str += " / "; name_str += prefix->shortName(false, false);}
1585 if(!prefix->longName(false, false).empty()) {if(!name_str.empty()) name_str += " / "; name_str += prefix->longName();}
1586 if((int) name_str.length() > max_l) max_l = name_str.length();
1587 name_list.push_front(name_str);
1588 }
1589 } else if((!item->isHidden() || (i2 == 2 && ((Unit*) item)->isCurrency())) && item->isActive() && (i2 != 2 || (item->subtype() != SUBTYPE_COMPOSITE_UNIT)) && (list_type != 'c' || ((Unit*) item)->isCurrency())) {
1590 bool b_match = name_matches(item, search_str);
1591 if(!b_match && title_matches(item, search_str, list_type == 'c' ? 0 : 3)) b_match = true;
1592 if(!b_match && i2 == 2 && country_matches((Unit*) item, search_str, list_type == 'c' ? 0 : 3)) b_match = true;
1593 if(b_match) {
1594 const ExpressionName &ename1 = item->preferredInputName(false, false);
1595 name_str = ename1.name;
1596 size_t name_i = 1;
1597 while(true) {
1598 const ExpressionName &ename = item->getName(name_i);
1599 if(ename == empty_expression_name) break;
1600 if(ename != ename1 && !ename.avoid_input && !ename.plural && (!ename.unicode || printops.use_unicode_signs) && !ename.completion_only) {
1601 name_str += " / ";
1602 name_str += ename.name;
1603 }
1604 name_i++;
1605 }
1606 if(!item->title(false).empty()) {
1607 name_str += " (";
1608 name_str += item->title(false);
1609 name_str += ")";
1610 }
1611 if((int) name_str.length() > max_l) max_l = name_str.length();
1612 name_list.push_front(name_str);
1613 }
1614 }
1615 }
1616 if(list_type != 0) break;
1617 }
1618 if(name_list.empty()) {
1619 PUTS_UNICODE(_("No matching item found."));
1620 puts("");
1621 } else {
1622 name_list.sort();
1623 list<string>::iterator it = name_list.begin();
1624 list<string>::iterator it_e = name_list.end();
1625 int c = 0;
1626 int max_tabs = (max_l / 8) + 1;
1627 int max_c = cols / (max_tabs * 8);
1628 if(cfile) max_c = 0;
1629 while(it != it_e) {
1630 c++;
1631 if(c >= max_c) {
1632 c = 0;
1633 if(max_c == 1 && in_interactive) {CHECK_IF_SCREEN_FILLED}
1634 PUTS_UNICODE(it->c_str());
1635 } else {
1636 if(c == 1 && in_interactive) {CHECK_IF_SCREEN_FILLED}
1637 int l = unicode_length_check(it->c_str());
1638 int nr_of_tabs = max_tabs - (l / 8);
1639 for(int tab_nr = 0; tab_nr < nr_of_tabs; tab_nr++) {
1640 *it += "\t";
1641 }
1642 FPUTS_UNICODE(it->c_str(), stdout);
1643 }
1644 ++it;
1645 }
1646 if(c > 0) puts("");
1647 if(in_interactive) {CHECK_IF_SCREEN_FILLED}
1648 puts("");
1649 if(in_interactive) {CHECK_IF_SCREEN_FILLED}
1650 if(in_interactive) {CHECK_IF_SCREEN_FILLED_PUTS(_("For more information about a specific function, variable, unit, or prefix, please use the info command (in interactive mode)."));}
1651 else {PUTS_UNICODE(_("For more information about a specific function, variable, unit, or prefix, please use the info command (in interactive mode)."));}
1652 puts("");
1653 }
1654 } else if(list_type == 0) {
1655 puts("");
1656 if(in_interactive) {CHECK_IF_SCREEN_FILLED;}
1657 bool b_variables = false, b_functions = false, b_units = false;
1658 ParseOptions pa = evalops.parse_options; pa.base = 10;
1659 for(size_t i = 0; i < CALCULATOR->variables.size(); i++) {
1660 Variable *v = CALCULATOR->variables[i];
1661 if((v->isLocal() || v->hasChanged()) && v->isActive() && (!is_answer_variable(v) || !v->representsUndefined())) {
1662 int pctl;
1663 if(!b_variables) {
1664 b_variables = true;
1665 PUTS_BOLD(_("Variables:"));
1666 if(in_interactive) {CHECK_IF_SCREEN_FILLED}
1667 STR_AND_TABS(_("Name"))
1668 str += _("Value");
1669 PUTS_UNICODE(str.c_str());
1670 if(in_interactive) {CHECK_IF_SCREEN_FILLED}
1671 }
1672 STR_AND_TABS(v->preferredInputName(false, false).name.c_str())
1673 FPUTS_UNICODE(str.c_str(), stdout);
1674 string value;
1675 if(v->isKnown()) {
1676 bool is_relative = false;
1677 if(((KnownVariable*) v)->isExpression()) {
1678 value = CALCULATOR->localizeExpression(((KnownVariable*) v)->expression(), pa);
1679 if(!((KnownVariable*) v)->uncertainty(&is_relative).empty()) {
1680 if(is_relative) {value += " ("; value += _("relative uncertainty"); value += ": ";}
1681 else value += SIGN_PLUSMINUS;
1682 value += CALCULATOR->localizeExpression(((KnownVariable*) v)->uncertainty());
1683 if(is_relative) {value += ")";}
1684 }
1685 if(!((KnownVariable*) v)->unit().empty() && ((KnownVariable*) v)->unit() != "auto") {
1686 value += " ";
1687 value += CALCULATOR->localizeExpression(((KnownVariable*) v)->unit(), pa);
1688 }
1689 if(value.length() > 40) {
1690 value = value.substr(0, 30);
1691 value += "...";
1692 }
1693 FPUTS_UNICODE(value.c_str(), stdout);
1694 if(!is_relative && ((KnownVariable*) v)->uncertainty().empty() && v->isApproximate() && ((KnownVariable*) v)->expression().find(SIGN_PLUSMINUS) == string::npos && ((KnownVariable*) v)->expression().find(CALCULATOR->getFunctionById(FUNCTION_ID_INTERVAL)->referenceName()) == string::npos) {
1695 fputs(" (", stdout);
1696 FPUTS_UNICODE(_("approximate"), stdout);
1697 fputs(")", stdout);
1698
1699 }
1700 } else {
1701 if(((KnownVariable*) v)->get().isMatrix()) {
1702 value = _("matrix");
1703 } else if(((KnownVariable*) v)->get().isVector()) {
1704 value = _("vector");
1705 } else {
1706 PrintOptions po;
1707 po.interval_display = INTERVAL_DISPLAY_PLUSMINUS;
1708 value = CALCULATOR->print(((KnownVariable*) v)->get(), 30, po);
1709 }
1710 FPUTS_UNICODE(value.c_str(), stdout);
1711 if(v->isApproximate() && ((KnownVariable*) v)->get().containsInterval(true, false, false, 0, true) <= 0) {
1712 fputs(" (", stdout);
1713 FPUTS_UNICODE(_("approximate"), stdout);
1714 fputs(")", stdout);
1715 }
1716 }
1717
1718 } else {
1719 if(((UnknownVariable*) v)->assumptions()) {
1720 switch(((UnknownVariable*) v)->assumptions()->sign()) {
1721 case ASSUMPTION_SIGN_POSITIVE: {value = _("positive"); break;}
1722 case ASSUMPTION_SIGN_NONPOSITIVE: {value = _("non-positive"); break;}
1723 case ASSUMPTION_SIGN_NEGATIVE: {value = _("negative"); break;}
1724 case ASSUMPTION_SIGN_NONNEGATIVE: {value = _("non-negative"); break;}
1725 case ASSUMPTION_SIGN_NONZERO: {value = _("non-zero"); break;}
1726 default: {}
1727 }
1728 if(!value.empty() && ((UnknownVariable*) v)->assumptions()->type() != ASSUMPTION_TYPE_NONE) value += " ";
1729 switch(((UnknownVariable*) v)->assumptions()->type()) {
1730 case ASSUMPTION_TYPE_INTEGER: {value += _("integer"); break;}
1731 case ASSUMPTION_TYPE_RATIONAL: {value += _("rational"); break;}
1732 case ASSUMPTION_TYPE_REAL: {value += _("real"); break;}
1733 case ASSUMPTION_TYPE_COMPLEX: {value += _("complex"); break;}
1734 case ASSUMPTION_TYPE_NUMBER: {value += _("number"); break;}
1735 case ASSUMPTION_TYPE_NONMATRIX: {value += _("non-matrix"); break;}
1736 default: {}
1737 }
1738 if(value.empty()) value = _("unknown");
1739 } else {
1740 value = _("default assumptions");
1741 }
1742 FPUTS_UNICODE(value.c_str(), stdout);
1743 }
1744 puts("");
1745 if(in_interactive) {CHECK_IF_SCREEN_FILLED}
1746 }
1747 }
1748 for(size_t i = 0; i < CALCULATOR->functions.size(); i++) {
1749 MathFunction *f = CALCULATOR->functions[i];
1750 if((f->isLocal() || f->hasChanged()) && f->isActive()) {
1751 if(!b_functions) {
1752 if(b_variables) puts("");
1753 if(in_interactive) {CHECK_IF_SCREEN_FILLED}
1754 if(in_interactive) {CHECK_IF_SCREEN_FILLED}
1755 b_functions = true;
1756 PUTS_BOLD(_("Functions:"));
1757 }
1758 puts(f->preferredInputName(false, false).name.c_str());
1759 if(in_interactive) {CHECK_IF_SCREEN_FILLED}
1760 }
1761 }
1762 for(size_t i = 0; i < CALCULATOR->units.size(); i++) {
1763 Unit *u = CALCULATOR->units[i];
1764 if((u->isLocal() || u->hasChanged()) && u->isActive()) {
1765 if(!b_units) {
1766 if(b_variables || b_functions) puts("");
1767 if(in_interactive) {CHECK_IF_SCREEN_FILLED}
1768 if(in_interactive) {CHECK_IF_SCREEN_FILLED}
1769 b_units = true;
1770 PUTS_BOLD(_("Units:"));
1771 }
1772 puts(u->preferredInputName(false, false).name.c_str());
1773 if(in_interactive) {CHECK_IF_SCREEN_FILLED}
1774 }
1775 }
1776 if(!b_variables && !b_functions && !b_units) {
1777 PUTS_UNICODE(_("No local variables, functions or units have been defined."));
1778 if(in_interactive) {CHECK_IF_SCREEN_FILLED}
1779 }
1780 puts("");
1781 if(in_interactive) {CHECK_IF_SCREEN_FILLED}
1782 if(in_interactive) {CHECK_IF_SCREEN_FILLED_PUTS(_("For more information about a specific function, variable, unit, or prefix, please use the info command (in interactive mode)."));}
1783 else {PUTS_UNICODE(_("For more information about a specific function, variable, unit, or prefix, please use the info command (in interactive mode)."));}
1784 puts("");
1785 } else {
1786 int max_l = 0;
1787 list<string> name_list;
1788 int i_end = 0;
1789 if(list_type == 'f') i_end = CALCULATOR->functions.size();
1790 if(list_type == 'v') i_end = CALCULATOR->variables.size();
1791 if(list_type == 'u') i_end = CALCULATOR->units.size();
1792 if(list_type == 'c') i_end = CALCULATOR->units.size();
1793 if(list_type == 'p') i_end = CALCULATOR->prefixes.size();
1794 ExpressionItem *item = NULL;
1795 string name_str, name_str2;
1796 for(int i = 0; i < i_end; i++) {
1797 if(list_type == 'f') item = CALCULATOR->functions[i];
1798 else if(list_type == 'v') item = CALCULATOR->variables[i];
1799 else if(list_type == 'u') item = CALCULATOR->units[i];
1800 else if(list_type == 'c') item = CALCULATOR->units[i];
1801 if(list_type == 'p') {
1802 Prefix *prefix = CALCULATOR->prefixes[i];
1803 name_str = "";
1804 if(printops.use_unicode_signs && !prefix->unicodeName(false).empty()) name_str += prefix->unicodeName(false);
1805 if(!prefix->shortName(false, false).empty()) {if(!name_str.empty()) name_str += " / "; name_str += prefix->shortName(false, false);}
1806 if(!prefix->longName(false, false).empty()) {if(!name_str.empty()) name_str += " / "; name_str += prefix->longName();}
1807 if((int) name_str.length() > max_l) max_l = name_str.length();
1808 name_list.push_front(name_str);
1809 } else if((!item->isHidden() || list_type == 'c') && item->isActive() && (list_type != 'u' || (item->subtype() != SUBTYPE_COMPOSITE_UNIT && ((Unit*) item)->baseUnit() != CALCULATOR->getUnitById(UNIT_ID_EURO))) && (list_type != 'c' || ((Unit*) item)->isCurrency())) {
1810 const ExpressionName &ename1 = item->preferredInputName(false, false);
1811 name_str = ename1.name;
1812 size_t name_i = 1;
1813 while(true) {
1814 const ExpressionName &ename = item->getName(name_i);
1815 if(ename == empty_expression_name) break;
1816 if(ename != ename1 && !ename.avoid_input && !ename.plural && (!ename.unicode || printops.use_unicode_signs) && !ename.completion_only) {
1817 name_str += " / ";
1818 name_str += ename.name;
1819 }
1820 name_i++;
1821 }
1822 if(list_type == 'c' && !item->title(false).empty()) {
1823 name_str += " (";
1824 name_str += item->title(false);
1825 name_str += ")";
1826 }
1827 if((int) name_str.length() > max_l) max_l = name_str.length();
1828 name_list.push_front(name_str);
1829 }
1830 }
1831 name_list.sort();
1832 list<string>::iterator it = name_list.begin();
1833 list<string>::iterator it_e = name_list.end();
1834 int c = 0;
1835 int max_tabs = (max_l / 8) + 1;
1836 int max_c = cols / (max_tabs * 8);
1837 if(cfile) max_c = 0;
1838 while(it != it_e) {
1839 c++;
1840 if(c >= max_c) {
1841 c = 0;
1842 if(max_c == 1 && in_interactive) {CHECK_IF_SCREEN_FILLED}
1843 PUTS_UNICODE(it->c_str());
1844 } else {
1845 if(c == 1 && in_interactive) {CHECK_IF_SCREEN_FILLED}
1846 int l = unicode_length_check(it->c_str());
1847 int nr_of_tabs = max_tabs - (l / 8);
1848 for(int tab_nr = 0; tab_nr < nr_of_tabs; tab_nr++) {
1849 *it += "\t";
1850 }
1851 FPUTS_UNICODE(it->c_str(), stdout);
1852 }
1853 ++it;
1854 }
1855 if(c > 0) puts("");
1856 if(in_interactive) {CHECK_IF_SCREEN_FILLED}
1857 puts("");
1858 if(in_interactive) {CHECK_IF_SCREEN_FILLED}
1859 if(in_interactive) {CHECK_IF_SCREEN_FILLED_PUTS(_("For more information about a specific function, variable, unit, or prefix, please use the info command (in interactive mode)."));}
1860 else {PUTS_UNICODE(_("For more information about a specific function, variable, unit, or prefix, please use the info command (in interactive mode)."));}
1861 puts("");
1862 }
1863 }
1864
1865 bool do_imaginary_j = false;
1866
main(int argc,char * argv[])1867 int main(int argc, char *argv[]) {
1868
1869 string calc_arg;
1870 vector<string> set_option_strings;
1871 bool calc_arg_begun = false;
1872 string command_file;
1873 cfile = NULL;
1874 interactive_mode = false;
1875 result_only = false;
1876 bool load_units = true, load_functions = true, load_variables = true, load_currencies = true, load_datasets = true;
1877 load_global_defs = true;
1878 #ifdef _WIN32
1879 printops.use_unicode_signs = false;
1880 #else
1881 printops.use_unicode_signs = true;
1882 #endif
1883 fetch_exchange_rates_at_startup = false;
1884 char list_type = 'n';
1885 string search_str;
1886
1887 #ifdef ENABLE_NLS
1888 string filename = buildPath(getLocalDir(), "qalc.cfg");
1889 FILE *file = fopen(filename.c_str(), "r");
1890 char line[10000];
1891 string stmp;
1892 if(file) {
1893 while(true) {
1894 if(fgets(line, 10000, file) == NULL) break;
1895 if(strcmp(line, "ignore_locale=1\n") == 0) {
1896 ignore_locale = true;
1897 break;
1898 } else if(strcmp(line, "ignore_locale=0\n") == 0) {
1899 break;
1900 }
1901 }
1902 fclose(file);
1903 }
1904 if(!ignore_locale) {
1905 bindtextdomain(GETTEXT_PACKAGE, getPackageLocaleDir().c_str());
1906 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
1907 textdomain(GETTEXT_PACKAGE);
1908 }
1909 #endif
1910
1911 if(!ignore_locale) setlocale(LC_ALL, "");
1912
1913 for(int i = 1; i < argc; i++) {
1914 string svalue, svar;
1915 if(calc_arg_begun) {
1916 calc_arg += " ";
1917 } else {
1918 svar = argv[i];
1919 size_t i2 = svar.find_first_of(NUMBERS "=");
1920 if(i2 != string::npos && i2 != 0 && svar[0] != '+' && (svar[i2] == '=' || i2 == 2) && (svar[i2] != '=' || i2 != svar.length() - 1)) {
1921 svalue = svar.substr(svar[i2] == '=' ? i2 + 1 : i2);
1922 svar = svar.substr(0, i2);
1923 }
1924 }
1925 if(!calc_arg_begun && (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "-help") == 0 || strcmp(argv[i], "--help") == 0)) {
1926 PUTS_UNICODE(_("usage: qalc [options] [expression]"));
1927 printf("\n");
1928 PUTS_UNICODE(_("where options are:"));
1929 fputs("\n\t-b, -base", stdout); fputs(" ", stdout); FPUTS_UNICODE(_("BASE"), stdout); fputs("\n", stdout);
1930 fputs("\t", stdout); PUTS_UNICODE(_("set the number base for results and, optionally, expressions"));
1931 fputs("\n\t-c, -color\n", stdout);
1932 fputs("\t", stdout); PUTS_UNICODE(_("use colors to hightlight different elements of expressions and results"));
1933 #ifdef HAVE_LIBCURL
1934 fputs("\n\t-e, -exrates\n", stdout);
1935 fputs("\t", stdout); PUTS_UNICODE(_("update exchange rates"));
1936 #endif
1937 fputs("\n\t-f, -file", stdout); fputs(" ", stdout); FPUTS_UNICODE(_("FILE"), stdout); fputs("\n", stdout);
1938 fputs("\t", stdout); PUTS_UNICODE(_("execute commands from a file first"));
1939 fputs("\n\t-i, -interactive\n", stdout);
1940 fputs("\t", stdout); PUTS_UNICODE(_("start in interactive mode"));
1941 fputs("\n\t-l, -list", stdout); fputs(" [", stdout); FPUTS_UNICODE(_("SEARCH TERM"), stdout); fputs("]\n", stdout);
1942 fputs("\t", stdout); PUTS_UNICODE(_("displays a list of all user-defined or matching variables, functions, units, and prefixes"));
1943 fputs("\n\t--list-functions", stdout); fputs(" [", stdout); FPUTS_UNICODE(_("SEARCH TERM"), stdout); fputs("]\n", stdout);
1944 fputs("\t", stdout); PUTS_UNICODE(_("displays a list of all or matching functions"));
1945 fputs("\n\t--list-prefixes", stdout); fputs(" [", stdout); FPUTS_UNICODE(_("SEARCH TERM"), stdout); fputs("]\n", stdout);
1946 fputs("\t", stdout); PUTS_UNICODE(_("displays a list of all or matching prefixes"));
1947 fputs("\n\t--list-units", stdout); fputs(" [", stdout); FPUTS_UNICODE(_("SEARCH TERM"), stdout); fputs("]\n", stdout);
1948 fputs("\t", stdout); PUTS_UNICODE(_("displays a list of all or matching units"));
1949 fputs("\n\t--list-variables", stdout); fputs(" [", stdout); FPUTS_UNICODE(_("SEARCH TERM"), stdout); fputs("]\n", stdout);
1950 fputs("\t", stdout); PUTS_UNICODE(_("displays a list of all or matching variables"));
1951 fputs("\n\t-m, -time", stdout); fputs(" ", stdout); FPUTS_UNICODE(_("MILLISECONDS"), stdout); fputs("\n", stdout);
1952 fputs("\t", stdout); PUTS_UNICODE(_("terminate calculation and display of result after specified amount of time"));
1953 fputs("\n\t-n, -nodefs\n", stdout);
1954 fputs("\t", stdout); PUTS_UNICODE(_("do not load any functions, units, or variables from file"));
1955 fputs("\n\t-nocurrencies\n", stdout);
1956 fputs("\t", stdout); PUTS_UNICODE(_("do not load any global currencies from file"));
1957 fputs("\n\t-nodatasets\n", stdout);
1958 fputs("\t", stdout); PUTS_UNICODE(_("do not load any global data sets from file"));
1959 fputs("\n\t-nofunctions\n", stdout);
1960 fputs("\t", stdout); PUTS_UNICODE(_("do not load any global functions from file"));
1961 fputs("\n\t-nounits\n", stdout);
1962 fputs("\t", stdout); PUTS_UNICODE(_("do not load any global units from file"));
1963 fputs("\n\t-novariables\n", stdout);
1964 fputs("\t", stdout); PUTS_UNICODE(_("do not load any global variables from file"));
1965 fputs("\n\t-p", stdout); fputs(" [", stdout); FPUTS_UNICODE(_("BASE"), stdout); fputs("]\n", stdout);
1966 fputs("\t", stdout); PUTS_UNICODE(_("start in programming mode (same as -b \"BASE BASE\" -s \"xor^\", with base conversion)"));
1967 fputs("\n\t-s, -set", stdout); fputs(" \"", stdout); FPUTS_UNICODE(_("OPTION"), stdout); fputs(" ", stdout); FPUTS_UNICODE(_("VALUE"), stdout); fputs("\"\n", stdout);
1968 fputs("\t", stdout); PUTS_UNICODE(_("as set command in interactive program session (e.g. -set \"base 16\")"));
1969 fputs("\n\t-t, -terse\n", stdout);
1970 fputs("\t", stdout); PUTS_UNICODE(_("reduce output to just the result of the input expression"));
1971 fputs("\n\t-/+u8\n", stdout);
1972 fputs("\t", stdout); PUTS_UNICODE(_("switch unicode support on/off"));
1973 fputs("\n\t-v, -version\n", stdout);
1974 fputs("\t", stdout); PUTS_UNICODE(_("show application version and exit"));
1975 puts("");
1976 FPUTS_UNICODE(_("The program will start in interactive mode if no expression and no file is specified (or interactive mode is explicitly selected)."), stdout); fputs(" ", stdout); PUTS_UNICODE(_("Type help in interactive mode for information about available commands."));
1977 puts("");
1978 #ifdef _WIN32
1979 PUTS_UNICODE(_("For more information about mathematical expression and different options, and a complete list of functions, variables, and units, see the relevant sections in the manual of the graphical user interface (available at https://qalculate.github.io/manual/index.html)."));
1980 #else
1981 PUTS_UNICODE(_("For more information about mathematical expression and different options, please consult the man page, or the relevant sections in the manual of the graphical user interface (available at https://qalculate.github.io/manual/index.html), which also includes a complete list of functions, variables, and units."));
1982 #endif
1983 puts("");
1984 return 0;
1985 } else if(!calc_arg_begun && strcmp(argv[i], "-u8") == 0) {
1986 enable_unicode = 1;
1987 } else if(!calc_arg_begun && strcmp(argv[i], "+u8") == 0) {
1988 enable_unicode = 0;
1989 #ifdef HAVE_LIBCURL
1990 } else if(!calc_arg_begun && (strcmp(argv[i], "-exrates") == 0 || strcmp(argv[i], "--exrates") == 0 || strcmp(argv[i], "-e") == 0)) {
1991 fetch_exchange_rates_at_startup = true;
1992 #endif
1993 } else if(!calc_arg_begun && (svar == "-base" || svar == "--base" || svar == "-b")) {
1994 string set_base_str = "base ";
1995 if(!svalue.empty()) {
1996 set_base_str += svalue;
1997 } else if(i + 1 < argc) {
1998 i++;
1999 set_base_str += argv[i];
2000 }
2001 set_option_strings.push_back(set_base_str);
2002 } else if(!calc_arg_begun && (svar == "-c" || svar == "-color" || svar == "--color")) {
2003 if(!svalue.empty()) {
2004 force_color = s2i(svalue);
2005 } else {
2006 force_color = 1;
2007 }
2008 } else if(!calc_arg_begun && svar == "-p") {
2009 programmers_mode = true;
2010 string set_base_str = "base ";
2011 if(!svalue.empty()) {
2012 set_base_str += svalue;
2013 set_base_str += " ";
2014 set_base_str += svalue;
2015 } else {
2016 i++;
2017 if(i < argc) {
2018 set_base_str += argv[i];
2019 set_base_str += " ";
2020 set_base_str += argv[i];
2021 }
2022 }
2023 set_option_strings.push_back(set_base_str);
2024 set_option_strings.push_back("xor^ 1");
2025 } else if(!calc_arg_begun && (strcmp(argv[i], "+p") == 0)) {
2026 set_option_strings.push_back("base 10 10");
2027 set_option_strings.push_back("xor^ 0");
2028 } else if(!calc_arg_begun && (strcmp(argv[i], "-terse") == 0 || strcmp(argv[i], "--terse") == 0 || strcmp(argv[i], "-t") == 0)) {
2029 result_only = true;
2030 } else if(!calc_arg_begun && (strcmp(argv[i], "-version") == 0 || strcmp(argv[i], "--version") == 0 || strcmp(argv[i], "-v") == 0)) {
2031 puts(VERSION);
2032 return 0;
2033 } else if(!calc_arg_begun && (strcmp(argv[i], "-interactive") == 0 || strcmp(argv[i], "--interactive") == 0 || strcmp(argv[i], "-i") == 0)) {
2034 interactive_mode = true;
2035 } else if(!calc_arg_begun && (svar == "-list" || svar == "--list" || svar == "-l")) {
2036 list_type = 0;
2037 if(!svalue.empty()) {
2038 search_str = svalue;
2039 remove_blank_ends(search_str);
2040 } else if(i + 1 < argc && strlen(argv[i + 1]) > 0 && argv[i + 1][0] != '-' && argv[i + 1][0] != '+') {
2041 i++;
2042 search_str = argv[i];
2043 remove_blank_ends(search_str);
2044 }
2045 } else if(!calc_arg_begun && svar == "--list-functions") {
2046 list_type = 'f';
2047 if(!svalue.empty()) {
2048 search_str = svalue;
2049 remove_blank_ends(search_str);
2050 } else if(i + 1 < argc && strlen(argv[i + 1]) > 0 && argv[i + 1][0] != '-' && argv[i + 1][0] != '+') {
2051 i++;
2052 search_str = argv[i];
2053 remove_blank_ends(search_str);
2054 }
2055 } else if(!calc_arg_begun && svar == "--list-units") {
2056 list_type = 'u';
2057 if(!svalue.empty()) {
2058 search_str = svalue;
2059 remove_blank_ends(search_str);
2060 } else if(i + 1 < argc && strlen(argv[i + 1]) > 0 && argv[i + 1][0] != '-' && argv[i + 1][0] != '+') {
2061 i++;
2062 search_str = argv[i];
2063 remove_blank_ends(search_str);
2064 }
2065 } else if(!calc_arg_begun && svar == "--list-variables") {
2066 list_type = 'v';
2067 if(!svalue.empty()) {
2068 search_str = svalue;
2069 remove_blank_ends(search_str);
2070 } else if(i + 1 < argc && strlen(argv[i + 1]) > 0 && argv[i + 1][0] != '-' && argv[i + 1][0] != '+') {
2071 i++;
2072 search_str = argv[i];
2073 remove_blank_ends(search_str);
2074 }
2075 } else if(!calc_arg_begun && svar == "--list-prefixes") {
2076 list_type = 'p';
2077 if(!svalue.empty()) {
2078 search_str = svalue;
2079 remove_blank_ends(search_str);
2080 } else if(i + 1 < argc && strlen(argv[i + 1]) > 0 && argv[i + 1][0] != '-' && argv[i + 1][0] != '+') {
2081 i++;
2082 search_str = argv[i];
2083 remove_blank_ends(search_str);
2084 }
2085 } else if(!calc_arg_begun && strcmp(argv[i], "-nounits") == 0) {
2086 load_units = false;
2087 } else if(!calc_arg_begun && strcmp(argv[i], "-nocurrencies") == 0) {
2088 load_currencies = false;
2089 } else if(!calc_arg_begun && strcmp(argv[i], "-nofunctions") == 0) {
2090 load_functions = false;
2091 } else if(!calc_arg_begun && strcmp(argv[i], "-novariables") == 0) {
2092 load_variables = false;
2093 } else if(!calc_arg_begun && strcmp(argv[i], "-nodatasets") == 0) {
2094 load_datasets = false;
2095 } else if(!calc_arg_begun && (strcmp(argv[i], "-nodefs") == 0 || strcmp(argv[i], "-n") == 0)) {
2096 load_global_defs = false;
2097 } else if(!calc_arg_begun && (svar == "-time" || svar == "--time" || svar == "-m")) {
2098 if(!svalue.empty()) {
2099 i_maxtime += strtol(svalue.c_str(), NULL, 10);
2100 if(i_maxtime < 0) i_maxtime = 0;
2101 } else if(i + 1 < argc) {
2102 i++;
2103 i_maxtime += strtol(argv[i], NULL, 10);
2104 if(i_maxtime < 0) i_maxtime = 0;
2105 }
2106 } else if(!calc_arg_begun && (svar == "-set" || svar == "--set" || svar == "-s")) {
2107 if(!svalue.empty()) {
2108 set_option_strings.push_back(svalue);
2109 } else if(i + 1 < argc) {
2110 i++;
2111 set_option_strings.push_back(argv[i]);
2112 } else {
2113 PUTS_UNICODE(_("No option and value specified for set command."));
2114 }
2115 } else if(!calc_arg_begun && (svar == "-file" || svar == "-f" || svar == "--file")) {
2116 if(!svalue.empty()) {
2117 command_file = svalue;
2118 remove_blank_ends(svalue);
2119 } else if(i + 1 < argc) {
2120 i++;
2121 command_file = argv[i];
2122 remove_blank_ends(command_file);
2123 } else {
2124 PUTS_UNICODE(_("No file specified."));
2125 }
2126 } else {
2127 calc_arg += argv[i];
2128 calc_arg_begun = true;
2129 }
2130 }
2131
2132 b_busy = false;
2133
2134 //create the almighty Calculator object
2135 new Calculator(ignore_locale);
2136
2137 //load application specific preferences
2138 load_preferences();
2139
2140 if(result_only) {
2141 dual_approximation = 0;
2142 dual_fraction = 0;
2143 }
2144
2145 for(size_t i = 0; i < set_option_strings.size(); i++) {
2146 set_option(set_option_strings[i]);
2147 }
2148
2149 if(enable_unicode >= 0) {
2150 if(printops.use_unicode_signs == enable_unicode) {
2151 enable_unicode = -1;
2152 } else {
2153 printops.use_unicode_signs = enable_unicode;
2154 }
2155 }
2156
2157 mstruct = new MathStructure();
2158 mstruct_exact.setUndefined();
2159 parsed_mstruct = new MathStructure();
2160
2161 canfetch = CALCULATOR->canFetch();
2162
2163 string str;
2164 #ifdef HAVE_LIBREADLINE
2165 static char* rlbuffer;
2166 #endif
2167
2168 ask_questions = (command_file.empty() || interactive_mode) && !result_only;
2169
2170 //exchange rates
2171 if(fetch_exchange_rates_at_startup && canfetch) {
2172 CALCULATOR->fetchExchangeRates(15);
2173 }
2174 if(load_global_defs && load_currencies && canfetch) {
2175 CALCULATOR->setExchangeRatesWarningEnabled(!interactive_mode && (!command_file.empty() || (result_only && !calc_arg.empty())));
2176 CALCULATOR->loadExchangeRates();
2177 }
2178
2179 string ans_str = _("ans");
2180 vans[0] = (KnownVariable*) CALCULATOR->addVariable(new KnownVariable(CALCULATOR->temporaryCategory(), ans_str, m_undefined, _("Last Answer"), false));
2181 vans[0]->addName(_("answer"));
2182 vans[0]->addName(ans_str + "1");
2183 vans[1] = (KnownVariable*) CALCULATOR->addVariable(new KnownVariable(CALCULATOR->temporaryCategory(), ans_str + "2", m_undefined, _("Answer 2"), false));
2184 vans[2] = (KnownVariable*) CALCULATOR->addVariable(new KnownVariable(CALCULATOR->temporaryCategory(), ans_str + "3", m_undefined, _("Answer 3"), false));
2185 vans[3] = (KnownVariable*) CALCULATOR->addVariable(new KnownVariable(CALCULATOR->temporaryCategory(), ans_str + "4", m_undefined, _("Answer 4"), false));
2186 vans[4] = (KnownVariable*) CALCULATOR->addVariable(new KnownVariable(CALCULATOR->temporaryCategory(), ans_str + "5", m_undefined, _("Answer 5"), false));
2187 v_memory = new KnownVariable(CALCULATOR->temporaryCategory(), "", m_zero, _("Memory"), true, true);
2188 ExpressionName ename;
2189 ename.name = "MR";
2190 ename.case_sensitive = true;
2191 ename.abbreviation = true;
2192 v_memory->addName(ename);
2193 ename.name = "MRC";
2194 v_memory->addName(ename);
2195 CALCULATOR->addVariable(v_memory);
2196
2197 //load global definitions
2198 if(load_global_defs) {
2199 bool b = true;
2200 if(load_units && !CALCULATOR->loadGlobalPrefixes()) b = false;
2201 if(load_units && !CALCULATOR->loadGlobalUnits()) b = false;
2202 else if(!load_units && load_currencies && !CALCULATOR->loadGlobalCurrencies()) b = false;
2203 if(load_functions && !CALCULATOR->loadGlobalFunctions()) b = false;
2204 if(load_datasets && !CALCULATOR->loadGlobalDataSets()) b = false;
2205 if(load_variables && !CALCULATOR->loadGlobalVariables()) b = false;
2206 if(!b) {PUTS_UNICODE(_("Failed to load global definitions!"));}
2207 }
2208
2209 //load local definitions
2210 CALCULATOR->loadLocalDefinitions();
2211
2212 if(do_imaginary_j && CALCULATOR->getVariableById(VARIABLE_ID_I)->hasName("j") == 0) {
2213 ExpressionName ename = CALCULATOR->getVariableById(VARIABLE_ID_I)->getName(1);
2214 ename.name = "j";
2215 ename.reference = false;
2216 CALCULATOR->getVariableById(VARIABLE_ID_I)->addName(ename, 1, true);
2217 CALCULATOR->getVariableById(VARIABLE_ID_I)->setChanged(false);
2218 }
2219
2220 if(!result_only) {
2221 int cols = 0;
2222 if(!command_file.empty()) {
2223 #ifdef HAVE_LIBREADLINE
2224 int rows = 0;
2225 rl_get_screen_size(&rows, &cols);
2226 #else
2227 cols = 80;
2228 #endif
2229 }
2230 display_errors(false, cols);
2231 }
2232
2233 if(list_type != 'n') {
2234 CALCULATOR->terminateThreads();
2235 list_defs(false, list_type, search_str);
2236 return 0;
2237 }
2238
2239 //reset
2240 result_text = "0";
2241 parsed_text = "0";
2242
2243 view_thread = new ViewThread;
2244 command_thread = new CommandThread;
2245
2246 if(!command_file.empty()) {
2247 if(command_file == "-") {
2248 cfile = stdin;
2249 } else {
2250 cfile = fopen(command_file.c_str(), "r");
2251 if(!cfile) {
2252 printf(_("Could not open \"%s\".\n"), command_file.c_str());
2253 if(!interactive_mode) {
2254 if(!view_thread->write(NULL)) view_thread->cancel();
2255 CALCULATOR->terminateThreads();
2256 return 0;
2257 }
2258 }
2259 }
2260 }
2261
2262 if(i_maxtime > 0) {
2263 #ifndef CLOCK_MONOTONIC
2264 gettimeofday(&t_end, NULL);
2265 #else
2266 struct timespec ts;
2267 clock_gettime(CLOCK_MONOTONIC, &ts);
2268 t_end.tv_sec = ts.tv_sec;
2269 t_end.tv_usec = ts.tv_nsec / 1000;
2270 #endif
2271 long int usecs = t_end.tv_usec + (long int) i_maxtime * 1000;
2272 t_end.tv_usec = usecs % 1000000;
2273 t_end.tv_sec += usecs / 1000000;
2274 }
2275
2276 if(!interactive_mode && (cfile || !calc_arg.empty())) {
2277 MathFunction *f = CALCULATOR->getFunctionById(FUNCTION_ID_PLOT);
2278 if(f) f->setDefaultValue(7, "1");
2279 }
2280
2281 if(!cfile && !calc_arg.empty()) {
2282 if(calc_arg.length() > 2 && ((calc_arg[0] == '\"' && calc_arg.find('\"', 1) == calc_arg.length() - 1) || (calc_arg[0] == '\'' && calc_arg.find('\'', 1) == calc_arg.length() - 1))) {
2283 calc_arg = calc_arg.substr(1, calc_arg.length() - 2);
2284 }
2285 if(!printops.use_unicode_signs && contains_unicode_char(calc_arg.c_str())) {
2286 char *gstr = locale_to_utf8(calc_arg.c_str());
2287 if(gstr) {
2288 expression_str = gstr;
2289 free(gstr);
2290 } else {
2291 expression_str = calc_arg;
2292 }
2293 } else {
2294 expression_str = calc_arg;
2295 }
2296 size_t index = expression_str.find_first_of(ID_WRAPS);
2297 if(index != string::npos) {
2298 printf(_("Illegal character, \'%c\', in expression."), expression_str[index]);
2299 puts("");
2300 } else {
2301 use_readline = false;
2302 execute_expression(interactive_mode);
2303 }
2304 if(!interactive_mode) {
2305 if(!view_thread->write(NULL)) view_thread->cancel();
2306 CALCULATOR->terminateThreads();
2307 return 0;
2308 }
2309 i_maxtime = 0;
2310 use_readline = true;
2311 } else if(!cfile) {
2312 ask_questions = !result_only;
2313 interactive_mode = true;
2314 i_maxtime = 0;
2315 }
2316 #ifdef _WIN32
2317 DWORD outMode = 0;
2318 HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
2319 if(DO_WIN_FORMAT) {
2320 GetConsoleMode(hOut, &outMode);
2321 SetConsoleMode(hOut, outMode | DISABLE_NEWLINE_AUTO_RETURN | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
2322 }
2323 #endif
2324
2325 #ifdef HAVE_LIBREADLINE
2326 rl_catch_signals = 1;
2327 rl_catch_sigwinch = rl_readline_version >= 0x0500;
2328 rl_readline_name = "qalc";
2329 rl_basic_word_break_characters = NOT_IN_NAMES NUMBERS;
2330 rl_completion_entry_function = qalc_completion;
2331 if(interactive_mode) {
2332 rl_bind_key('\t', rlcom_tab);
2333 rl_bind_keyseq("\\C-e", key_exact);
2334 rl_bind_keyseq("\\C-f", key_fraction);
2335 rl_bind_keyseq("\\C-a", key_save);
2336 }
2337 #endif
2338
2339 string scom;
2340 size_t slen, ispace;
2341
2342 while(true) {
2343 if(cfile) {
2344 if(i_maxtime < 0 || !fgets(buffer, 100000, cfile)) {
2345 if(cfile != stdin) {
2346 fclose(cfile);
2347 }
2348 cfile = NULL;
2349 if(!calc_arg.empty()) {
2350 if(!printops.use_unicode_signs && contains_unicode_char(calc_arg.c_str())) {
2351 char *gstr = locale_to_utf8(calc_arg.c_str());
2352 if(gstr) {
2353 expression_str = gstr;
2354 free(gstr);
2355 } else {
2356 expression_str = calc_arg;
2357 }
2358 } else {
2359 expression_str = calc_arg;
2360 }
2361 size_t index = expression_str.find_first_of(ID_WRAPS);
2362 if(index != string::npos) {
2363 printf(_("Illegal character, \'%c\', in expression."), expression_str[index]);
2364 puts("");
2365 } else {
2366 execute_expression(interactive_mode);
2367 }
2368 }
2369 if(!interactive_mode) break;
2370 i_maxtime = 0;
2371 continue;
2372 }
2373 if(!printops.use_unicode_signs && contains_unicode_char(buffer)) {
2374 char *gstr = locale_to_utf8(buffer);
2375 if(gstr) {
2376 str = gstr;
2377 free(gstr);
2378 } else {
2379 str = buffer;
2380 }
2381 } else {
2382 str = buffer;
2383 }
2384 remove_blank_ends(str);
2385 if(str.empty() || str[0] == '#' || (str.length() >= 2 && str[0] == '/' && str[1] == '/')) continue;
2386 } else {
2387 #ifdef HAVE_LIBREADLINE
2388 rlbuffer = readline("> ");
2389 if(rlbuffer == NULL) break;
2390 if(!printops.use_unicode_signs && contains_unicode_char(rlbuffer)) {
2391 char *gstr = locale_to_utf8(rlbuffer);
2392 if(gstr) {
2393 str = gstr;
2394 free(gstr);
2395 } else {
2396 str = rlbuffer;
2397 }
2398 } else {
2399 str = rlbuffer;
2400 }
2401 #else
2402 fputs("> ", stdout);
2403 if(!fgets(buffer, 100000, stdin)) {
2404 str = "";
2405 } else if(!printops.use_unicode_signs && contains_unicode_char(buffer)) {
2406 char *gstr = locale_to_utf8(buffer);
2407 if(gstr) {
2408 str = gstr;
2409 free(gstr);
2410 } else {
2411 str = buffer;
2412 }
2413 } else {
2414 str = buffer;
2415 }
2416 #endif
2417 }
2418 bool explicit_command = (!str.empty() && str[0] == '/');
2419 if(explicit_command) str.erase(0, 1);
2420 remove_blank_ends(str);
2421 if(rpn_mode && explicit_command && str.empty()) {str = "/"; explicit_command = false;}
2422 slen = str.length();
2423 ispace = str.find_first_of(SPACES);
2424 if(ispace == string::npos) {
2425 scom = "";
2426 } else {
2427 scom = str.substr(0, ispace);
2428 }
2429 //The qalc command "set" as in "set precision 10". The original text string for commands is kept in addition to the translation.
2430 if(EQUALS_IGNORECASE_AND_LOCAL(scom, "set", _("set"))) {
2431 str = str.substr(ispace + 1, slen - (ispace + 1));
2432 set_option(str);
2433 //qalc command
2434 } else if(EQUALS_IGNORECASE_AND_LOCAL(scom, "save", _("save")) || EQUALS_IGNORECASE_AND_LOCAL(scom, "store", _("store")) || EQUALS_IGNORECASE_AND_LOCAL(str, "store", _("store"))) {
2435 if(scom.empty()) {
2436 FPUTS_UNICODE(_("Name"), stdout);
2437 #ifdef HAVE_LIBREADLINE
2438 char *rlbuffer = readline(": ");
2439 if(!rlbuffer) {
2440 str = "";
2441 } else {
2442 str = rlbuffer;
2443 free(rlbuffer);
2444 }
2445 #else
2446 fputs(": ", stdout);
2447 if(!fgets(buffer, 1000, stdin)) str = "";
2448 else str = buffer;
2449 #endif
2450 } else {
2451 str = str.substr(ispace + 1, slen - (ispace + 1));
2452 }
2453 remove_blank_ends(str);
2454 if(EQUALS_IGNORECASE_AND_LOCAL(str, "mode", _("mode"))) {
2455 if(save_mode()) {
2456 PUTS_UNICODE(_("mode saved"));
2457 }
2458 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "definitions", _("definitions"))) {
2459 if(save_defs()) {
2460 PUTS_UNICODE(_("definitions saved"));
2461 }
2462 } else if(!str.empty()) {
2463 string name = str, cat, title;
2464 if(str[0] == '\"') {
2465 size_t i = str.find('\"', 1);
2466 if(i != string::npos) {
2467 name = str.substr(1, i - 1);
2468 str = str.substr(i + 1, str.length() - (i + 1));
2469 remove_blank_ends(str);
2470 } else {
2471 str = "";
2472 }
2473 } else {
2474 size_t i = str.find_first_of(SPACES, 1);
2475 if(i != string::npos) {
2476 name = str.substr(0, i);
2477 str = str.substr(i + 1, str.length() - (i + 1));
2478 remove_blank_ends(str);
2479 } else {
2480 str = "";
2481 }
2482 }
2483 bool catset = false;
2484 if(str.empty()) {
2485 cat = CALCULATOR->temporaryCategory();
2486 } else {
2487 if(str[0] == '\"') {
2488 size_t i = str.find('\"', 1);
2489 if(i != string::npos) {
2490 cat = str.substr(1, i - 1);
2491 title = str.substr(i + 1, str.length() - (i + 1));
2492 remove_blank_ends(title);
2493 }
2494 } else {
2495 size_t i = str.find_first_of(SPACES, 1);
2496 if(i != string::npos) {
2497 cat = str.substr(0, i);
2498 title = str.substr(i + 1, str.length() - (i + 1));
2499 remove_blank_ends(title);
2500 }
2501 }
2502 catset = true;
2503 }
2504 bool b = true;
2505 if(!CALCULATOR->variableNameIsValid(name)) {
2506 name = CALCULATOR->convertToValidVariableName(name);
2507 if(!CALCULATOR->variableNameIsValid(name)) {
2508 PUTS_UNICODE(_("Illegal name."));
2509 b = false;
2510 } else {
2511 size_t l = name.length() + strlen(_("Illegal name. Save as %s instead (default: no)?"));
2512 char *cstr = (char*) malloc(sizeof(char) * (l + 1));
2513 snprintf(cstr, l, _("Illegal name. Save as %s instead (default: no)?"), name.c_str());
2514 if(!ask_question(cstr)) {
2515 b = false;
2516 }
2517 free(cstr);
2518 }
2519 }
2520 Variable *v = NULL;
2521 if(b) v = CALCULATOR->getActiveVariable(name);
2522 if(b && ((!v && CALCULATOR->variableNameTaken(name)) || (v && (!v->isKnown() || !v->isLocal() || v->category() != CALCULATOR->temporaryCategory())))) {
2523 b = ask_question(_("A unit or variable with the same name already exists.\nDo you want to overwrite it (default: no)?"));
2524 }
2525 if(b) {
2526 if(v && v->isLocal() && v->isKnown()) {
2527 if(catset) v->setCategory(cat);
2528 if(!title.empty()) v->setTitle(title);
2529 ((KnownVariable*) v)->set(*mstruct);
2530 if(v->countNames() == 0) {
2531 ExpressionName ename(name);
2532 ename.reference = true;
2533 v->setName(ename, 1);
2534 } else {
2535 v->setName(name, 1);
2536 }
2537 } else {
2538 CALCULATOR->addVariable(new KnownVariable(cat, name, *mstruct, title));
2539 }
2540 }
2541 }
2542 //qalc command
2543 } else if(EQUALS_IGNORECASE_AND_LOCAL(scom, "variable", _("variable"))) {
2544 str = str.substr(ispace + 1, slen - (ispace + 1));
2545 remove_blank_ends(str);
2546 string name = str, expr;
2547 if(str[0] == '\"') {
2548 size_t i = str.find('\"', 1);
2549 if(i != string::npos) {
2550 name = str.substr(1, i - 1);
2551 str = str.substr(i + 1, str.length() - (i + 1));
2552 remove_blank_ends(str);
2553 } else {
2554 str = "";
2555 }
2556 } else {
2557 size_t i = str.find_first_of(SPACES, 1);
2558 if(i != string::npos) {
2559 name = str.substr(0, i);
2560 str = str.substr(i + 1, str.length() - (i + 1));
2561 remove_blank_ends(str);
2562 } else {
2563 str = "";
2564 }
2565 }
2566 if(str.length() >= 2 && str[0] == '\"' && str[str.length() - 1] == '\"') str = str.substr(1, str.length() - 2);
2567 expr = str;
2568 bool b = true;
2569 if(!CALCULATOR->variableNameIsValid(name)) {
2570 name = CALCULATOR->convertToValidVariableName(name);
2571 if(!CALCULATOR->variableNameIsValid(name)) {
2572 PUTS_UNICODE(_("Illegal name."));
2573 b = false;
2574 } else {
2575 size_t l = name.length() + strlen(_("Illegal name. Save as %s instead (default: no)?"));
2576 char *cstr = (char*) malloc(sizeof(char) * (l + 1));
2577 snprintf(cstr, l, _("Illegal name. Save as %s instead (default: no)?"), name.c_str());
2578 if(!ask_question(cstr)) {
2579 b = false;
2580 }
2581 free(cstr);
2582 }
2583 }
2584 Variable *v = NULL;
2585 if(b) v = CALCULATOR->getActiveVariable(name);
2586 if(b && ((!v && CALCULATOR->variableNameTaken(name)) || (v && (!v->isKnown() || !v->isLocal() || v->category() != CALCULATOR->temporaryCategory())))) {
2587 b = ask_question(_("A unit or variable with the same name already exists.\nDo you want to overwrite it (default: no)?"));
2588 }
2589 if(b) {
2590 if(v && v->isLocal() && v->isKnown()) {
2591 ((KnownVariable*) v)->set(expr);
2592 if(v->countNames() == 0) {
2593 ExpressionName ename(name);
2594 ename.reference = true;
2595 v->setName(ename, 1);
2596 } else {
2597 v->setName(name, 1);
2598 }
2599 } else {
2600 CALCULATOR->addVariable(new KnownVariable("", name, expr));
2601 }
2602 }
2603 //qalc command
2604 } else if(EQUALS_IGNORECASE_AND_LOCAL(scom, "function", _("function"))) {
2605 str = str.substr(ispace + 1, slen - (ispace + 1));
2606 remove_blank_ends(str);
2607 string name = str, expr;
2608 if(str[0] == '\"') {
2609 size_t i = str.find('\"', 1);
2610 if(i != string::npos) {
2611 name = str.substr(1, i - 1);
2612 str = str.substr(i + 1, str.length() - (i + 1));
2613 remove_blank_ends(str);
2614 } else {
2615 str = "";
2616 }
2617 } else {
2618 size_t i = str.find_first_of(SPACES, 1);
2619 if(i != string::npos) {
2620 name = str.substr(0, i);
2621 str = str.substr(i + 1, str.length() - (i + 1));
2622 remove_blank_ends(str);
2623 } else {
2624 str = "";
2625 }
2626 }
2627 if(str.length() >= 2 && str[0] == '\"' && str[str.length() - 1] == '\"') str = str.substr(1, str.length() - 2);
2628 expr = str;
2629 bool b = true;
2630 if(!CALCULATOR->functionNameIsValid(name)) {
2631 name = CALCULATOR->convertToValidFunctionName(name);
2632 if(!CALCULATOR->functionNameIsValid(name)) {
2633 PUTS_UNICODE(_("Illegal name."));
2634 b = false;
2635 } else {
2636 size_t l = name.length() + strlen(_("Illegal name. Save as %s instead (default: no)?"));
2637 char *cstr = (char*) malloc(sizeof(char) * (l + 1));
2638 snprintf(cstr, l, _("Illegal name. Save as %s instead (default: no)?"), name.c_str());
2639 if(!ask_question(cstr)) {
2640 b = false;
2641 }
2642 free(cstr);
2643 }
2644 }
2645 if(b && CALCULATOR->functionNameTaken(name)) {
2646 if(!ask_question(_("A function with the same name already exists.\nDo you want to overwrite it (default: no)?"))) {
2647 b = false;
2648 }
2649 }
2650 if(b) {
2651 if(expr.find("\\") == string::npos) {
2652 gsub("x", "\\x", expr);
2653 gsub("y", "\\y", expr);
2654 gsub("z", "\\z", expr);
2655 }
2656 MathFunction *f = CALCULATOR->getActiveFunction(name);
2657 if(f && f->isLocal() && f->subtype() == SUBTYPE_USER_FUNCTION) {
2658 ((UserFunction*) f)->setFormula(expr);
2659 if(f->countNames() == 0) {
2660 ExpressionName ename(name);
2661 ename.reference = true;
2662 f->setName(ename, 1);
2663 } else {
2664 f->setName(name, 1);
2665 }
2666 } else {
2667 CALCULATOR->addFunction(new UserFunction("", name, expr));
2668 }
2669 }
2670 //qalc command
2671 } else if(EQUALS_IGNORECASE_AND_LOCAL(scom, "delete", _("delete"))) {
2672 str = str.substr(ispace + 1, slen - (ispace + 1));
2673 remove_blank_ends(str);
2674 Variable *v = CALCULATOR->getActiveVariable(str);
2675 if(v && v->isLocal()) {
2676 v->destroy();
2677 } else {
2678 MathFunction *f = CALCULATOR->getActiveFunction(str);
2679 if(f && f->isLocal()) {
2680 f->destroy();
2681 } else {
2682 PUTS_UNICODE(_("No user-defined variable or function with the specified name exist."));
2683 }
2684 }
2685 //qalc command
2686 } else if(EQUALS_IGNORECASE_AND_LOCAL(scom, "assume", _("assume"))) {
2687 string str2 = "assumptions ";
2688 set_option(str2 + str.substr(ispace + 1, slen - (ispace + 1)));
2689 //qalc command
2690 } else if(EQUALS_IGNORECASE_AND_LOCAL(scom, "base", _("base"))) {
2691 set_option(str);
2692 //qalc command
2693 } else if(EQUALS_IGNORECASE_AND_LOCAL(scom, "rpn", _("rpn"))) {
2694 str = str.substr(ispace + 1, slen - (ispace + 1));
2695 remove_blank_ends(str);
2696 if(EQUALS_IGNORECASE_AND_LOCAL(str, "syntax", _("syntax"))) {
2697 if(evalops.parse_options.parsing_mode != PARSING_MODE_RPN) {
2698 nonrpn_parsing_mode = evalops.parse_options.parsing_mode;
2699 evalops.parse_options.parsing_mode = PARSING_MODE_RPN;
2700 expression_format_updated(false);
2701 }
2702 rpn_mode = false;
2703 CALCULATOR->clearRPNStack();
2704 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "stack", _("stack"))) {
2705 if(evalops.parse_options.parsing_mode == PARSING_MODE_RPN) {
2706 evalops.parse_options.parsing_mode = nonrpn_parsing_mode;
2707 expression_format_updated(false);
2708 }
2709 rpn_mode = true;
2710 } else {
2711 int v = s2b(str);
2712 if(v < 0) {
2713 PUTS_UNICODE(_("Illegal value."));
2714 } else {
2715 rpn_mode = v;
2716 }
2717 if((evalops.parse_options.parsing_mode == PARSING_MODE_RPN) != rpn_mode) {
2718 if(rpn_mode) {
2719 nonrpn_parsing_mode = evalops.parse_options.parsing_mode;
2720 evalops.parse_options.parsing_mode = PARSING_MODE_RPN;
2721 } else {
2722 evalops.parse_options.parsing_mode = nonrpn_parsing_mode;
2723 }
2724 expression_format_updated(false);
2725 }
2726 if(!rpn_mode) CALCULATOR->clearRPNStack();
2727 }
2728 //qalc command
2729 } else if(canfetch && EQUALS_IGNORECASE_AND_LOCAL(str, "exrates", _("exrates"))) {
2730 CALCULATOR->fetchExchangeRates(15);
2731 CALCULATOR->loadExchangeRates();
2732 INIT_COLS
2733 display_errors(false, cols);
2734 } else if(str == "M+") {
2735 if(mstruct) {
2736 MathStructure m = v_memory->get();
2737 m.calculateAdd(*mstruct, evalops);
2738 v_memory->set(m);
2739 }
2740 } else if(str == "M-" || str == "M−") {
2741 if(mstruct) {
2742 MathStructure m = v_memory->get();
2743 m.calculateSubtract(*mstruct, evalops);
2744 v_memory->set(m);
2745 }
2746 } else if(str == "MS") {
2747 if(mstruct) v_memory->set(*mstruct);
2748 } else if(str == "MC") {
2749 v_memory->set(m_zero);
2750 //qalc command
2751 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "stack", _("stack"))) {
2752 if(CALCULATOR->RPNStackSize() == 0) {
2753 PUTS_UNICODE(_("The RPN stack is empty."));
2754 } else {
2755 puts("");
2756 MathStructure m;
2757 for(size_t i = 1; i <= CALCULATOR->RPNStackSize(); i++) {
2758 m = *CALCULATOR->getRPNRegister(i);
2759 m.removeDefaultAngleUnit(evalops);
2760 m.format(printops);
2761 string regstr = m.print(printops, DO_FORMAT, DO_COLOR, TAG_TYPE_TERMINAL);
2762 if(complex_angle_form) replace_result_cis(regstr);
2763 if(printops.use_unicode_signs) gsub(" ", " ", str);
2764 printf(" %i:\t%s\n", (int) i, regstr.c_str());
2765 }
2766 puts("");
2767 }
2768 //qalc command
2769 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "swap", _("swap"))) {
2770 if(CALCULATOR->RPNStackSize() == 0) {
2771 PUTS_UNICODE(_("The RPN stack is empty."));
2772 } else if(CALCULATOR->RPNStackSize() == 1) {
2773 PUTS_UNICODE(_("The RPN stack only contains one value."));
2774 } else {
2775 CALCULATOR->moveRPNRegisterUp(2);
2776 }
2777 //qalc command
2778 } else if(EQUALS_IGNORECASE_AND_LOCAL(scom, "swap", _("swap"))) {
2779 if(CALCULATOR->RPNStackSize() == 0) {
2780 PUTS_UNICODE(_("The RPN stack is empty."));
2781 } else if(CALCULATOR->RPNStackSize() == 1) {
2782 PUTS_UNICODE(_("The RPN stack only contains one value."));
2783 } else {
2784 int index1 = 0, index2 = 0;
2785 str = str.substr(ispace + 1, slen - (ispace + 1));
2786 string str2 = "";
2787 remove_blank_ends(str);
2788 ispace = str.find_first_of(SPACES);
2789 if(ispace != string::npos) {
2790 str2 = str.substr(ispace + 1, str.length() - (ispace + 1));
2791 str = str.substr(0, ispace);
2792 remove_blank_ends(str2);
2793 remove_blank_ends(str);
2794 }
2795 index1 = s2i(str);
2796 if(str2.empty()) index2 = 1;
2797 else index2 = s2i(str2);
2798 if(index1 < 0) index1 = (int) CALCULATOR->RPNStackSize() + 1 + index1;
2799 if(index2 < 0) index2 = (int) CALCULATOR->RPNStackSize() + 1 + index2;
2800 if(index1 <= 0 || index1 > (int) CALCULATOR->RPNStackSize() || (!str2.empty() && (index2 <= 0 || index2 > (int) CALCULATOR->RPNStackSize()))) {
2801 PUTS_UNICODE(_("The specified RPN stack index does not exist."));
2802 } else if(index1 > index2) {
2803 CALCULATOR->moveRPNRegister((size_t) index2, (size_t) index1);
2804 CALCULATOR->moveRPNRegister((size_t) index1 - 1, (size_t) index2);
2805 } else if(index1 != index2) {
2806 CALCULATOR->moveRPNRegister((size_t) index1, (size_t) index2);
2807 CALCULATOR->moveRPNRegister((size_t) index2 - 1, (size_t) index1);
2808 }
2809 }
2810 //qalc command
2811 } else if(EQUALS_IGNORECASE_AND_LOCAL(scom, "move", _("move"))) {
2812 if(CALCULATOR->RPNStackSize() == 0) {
2813 PUTS_UNICODE(_("The RPN stack is empty."));
2814 } else if(CALCULATOR->RPNStackSize() == 1) {
2815 PUTS_UNICODE(_("The RPN stack only contains one value."));
2816 } else {
2817 int index1 = 0, index2 = 0;
2818 str = str.substr(ispace + 1, slen - (ispace + 1));
2819 string str2 = "";
2820 remove_blank_ends(str);
2821 ispace = str.find_first_of(SPACES);
2822 if(ispace != string::npos) {
2823 str2 = str.substr(ispace + 1, str.length() - (ispace + 1));
2824 str = str.substr(0, ispace);
2825 remove_blank_ends(str2);
2826 remove_blank_ends(str);
2827 }
2828 index1 = s2i(str);
2829 if(str2.empty()) index2 = 1;
2830 else index2 = s2i(str2);
2831 if(index1 < 0) index1 = (int) CALCULATOR->RPNStackSize() + 1 + index1;
2832 if(index2 < 0) index2 = (int) CALCULATOR->RPNStackSize() + 1 + index2;
2833 if(index1 <= 0 || index1 > (int) CALCULATOR->RPNStackSize() || (!str2.empty() && (index2 <= 0 || index2 > (int) CALCULATOR->RPNStackSize()))) {
2834 PUTS_UNICODE(_("The specified RPN stack index does not exist."));
2835 } else {
2836 CALCULATOR->moveRPNRegister((size_t) index1, (size_t) index2);
2837 }
2838 }
2839 //qalc command
2840 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "rotate", _("rotate"))) {
2841 if(CALCULATOR->RPNStackSize() == 0) {
2842 PUTS_UNICODE(_("The RPN stack is empty."));
2843 } else if(CALCULATOR->RPNStackSize() == 1) {
2844 PUTS_UNICODE(_("The RPN stack only contains one value."));
2845 } else {
2846 CALCULATOR->moveRPNRegister(1, CALCULATOR->RPNStackSize());
2847 }
2848 //qalc command
2849 } else if(EQUALS_IGNORECASE_AND_LOCAL(scom, "rotate", _("rotate"))) {
2850 if(CALCULATOR->RPNStackSize() == 0) {
2851 PUTS_UNICODE(_("The RPN stack is empty."));
2852 } else if(CALCULATOR->RPNStackSize() == 1) {
2853 PUTS_UNICODE(_("The RPN stack only contains one value."));
2854 } else {
2855 str = str.substr(ispace + 1, slen - (ispace + 1));
2856 remove_blank_ends(str);
2857 if(EQUALS_IGNORECASE_AND_LOCAL(str, "up", _("up"))) {
2858 CALCULATOR->moveRPNRegister(1, CALCULATOR->RPNStackSize());
2859 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "down", _("down"))) {
2860 CALCULATOR->moveRPNRegister(CALCULATOR->RPNStackSize(), 1);
2861 } else {
2862 PUTS_UNICODE(_("Illegal value."));
2863 }
2864 }
2865 //qalc command
2866 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "copy", _("copy"))) {
2867 if(CALCULATOR->RPNStackSize() == 0) {
2868 PUTS_UNICODE(_("The RPN stack is empty."));
2869 } else {
2870 CALCULATOR->RPNStackEnter(new MathStructure(*CALCULATOR->getRPNRegister(1)));
2871 }
2872 //qalc command
2873 } else if(EQUALS_IGNORECASE_AND_LOCAL(scom, "copy", _("copy"))) {
2874 if(CALCULATOR->RPNStackSize() == 0) {
2875 PUTS_UNICODE(_("The RPN stack is empty."));
2876 } else {
2877 str = str.substr(ispace + 1, slen - (ispace + 1));
2878 remove_blank_ends(str);
2879 int index1 = s2i(str);
2880 if(index1 < 0) index1 = (int) CALCULATOR->RPNStackSize() + 1 + index1;
2881 if(index1 <= 0 || index1 > (int) CALCULATOR->RPNStackSize()) {
2882 PUTS_UNICODE(_("The specified RPN stack index does not exist."));
2883 } else {
2884 CALCULATOR->RPNStackEnter(new MathStructure(*CALCULATOR->getRPNRegister((size_t) index1)));
2885 }
2886 }
2887 //qalc command
2888 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "clear stack", _("clear stack"))) {
2889 CALCULATOR->clearRPNStack();
2890 //qalc command
2891 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "pop", _("pop"))) {
2892 if(CALCULATOR->RPNStackSize() == 0) {
2893 PUTS_UNICODE(_("The RPN stack is empty."));
2894 } else {
2895 CALCULATOR->deleteRPNRegister(1);
2896 }
2897 //qalc command
2898 } else if(EQUALS_IGNORECASE_AND_LOCAL(scom, "pop", _("pop"))) {
2899 if(CALCULATOR->RPNStackSize() == 0) {
2900 PUTS_UNICODE(_("The RPN stack is empty."));
2901 } else {
2902 str = str.substr(ispace + 1, slen - (ispace + 1));
2903 int index1 = s2i(str);
2904 if(index1 < 0) index1 = (int) CALCULATOR->RPNStackSize() + 1 + index1;
2905 if(index1 <= 0 || index1 > (int) CALCULATOR->RPNStackSize()) {
2906 PUTS_UNICODE(_("The specified RPN stack index does not exist."));
2907 } else {
2908 CALCULATOR->deleteRPNRegister((size_t) index1);
2909 }
2910 }
2911 //qalc command
2912 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "exact", _("exact"))) {
2913 if(evalops.approximation != APPROXIMATION_EXACT) {
2914 evalops.approximation = APPROXIMATION_EXACT;
2915 expression_calculation_updated();
2916 }
2917 //qalc command
2918 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "approximate", _("approximate")) || str == "approx") {
2919 if(evalops.approximation == APPROXIMATION_TRY_EXACT) {
2920 if(dual_approximation < 0) dual_approximation = 0;
2921 else dual_approximation = -1;
2922 }
2923 evalops.approximation = APPROXIMATION_TRY_EXACT;
2924 expression_calculation_updated();
2925 //qalc command
2926 } else if(EQUALS_IGNORECASE_AND_LOCAL(scom, "convert", _("convert")) || EQUALS_IGNORECASE_AND_LOCAL(scom, "to", _("to")) || (str.length() > 2 && str[0] == '-' && str[1] == '>') || (str.length() > 3 && str[0] == '\xe2' && ((str[1] == '\x86' && str[2] == '\x92') || (str[1] == '\x9e' && (unsigned char) str[2] >= 148 && (unsigned char) str[2] <= 191)))) {
2927 if(!scom.empty() && (EQUALS_IGNORECASE_AND_LOCAL(scom, "convert", _("convert")) || EQUALS_IGNORECASE_AND_LOCAL(scom, "to", _("to")))) {
2928 str = str.substr(ispace + 1, slen - (ispace + 1));
2929 } else if(str[0] == '-') {
2930 str = str.substr(2, slen - 2);
2931 } else {
2932 str = str.substr(3, slen - 3);
2933 }
2934 remove_blank_ends(str);
2935 string str1, str2;
2936 size_t ispace2 = str.find_first_of(SPACES);
2937 if(ispace2 != string::npos) {
2938 str1 = str.substr(0, ispace2);
2939 remove_blank_ends(str1);
2940 str2 = str.substr(ispace2 + 1);
2941 remove_blank_ends(str2);
2942 }
2943 remove_duplicate_blanks(str);
2944 if(equalsIgnoreCase(str, "hex") || EQUALS_IGNORECASE_AND_LOCAL(str, "hexadecimal", _("hexadecimal"))) {
2945 int save_base = printops.base;
2946 printops.base = BASE_HEXADECIMAL;
2947 setResult(NULL, false);
2948 printops.base = save_base;
2949 } else if(equalsIgnoreCase(str, "bin") || EQUALS_IGNORECASE_AND_LOCAL(str, "binary", _("binary"))) {
2950 int save_base = printops.base;
2951 printops.base = BASE_BINARY;
2952 setResult(NULL, false);
2953 printops.base = save_base;
2954 } else if(equalsIgnoreCase(str, "dec") || EQUALS_IGNORECASE_AND_LOCAL(str, "decimal", _("decimal"))) {
2955 int save_base = printops.base;
2956 printops.base = BASE_DECIMAL;
2957 setResult(NULL, false);
2958 printops.base = save_base;
2959 } else if(equalsIgnoreCase(str, "oct") || EQUALS_IGNORECASE_AND_LOCAL(str, "octal", _("octal"))) {
2960 int save_base = printops.base;
2961 printops.base = BASE_OCTAL;
2962 setResult(NULL, false);
2963 printops.base = save_base;
2964 } else if(equalsIgnoreCase(str, "duo") || EQUALS_IGNORECASE_AND_LOCAL(str, "duodecimal", _("duodecimal"))) {
2965 int save_base = printops.base;
2966 printops.base = BASE_DUODECIMAL;
2967 setResult(NULL, false);
2968 printops.base = save_base;
2969 } else if(equalsIgnoreCase(str, "roman") || equalsIgnoreCase(str, _("roman"))) {
2970 int save_base = printops.base;
2971 printops.base = BASE_ROMAN_NUMERALS;
2972 setResult(NULL, false);
2973 printops.base = save_base;
2974 } else if(equalsIgnoreCase(str, "bijective") || equalsIgnoreCase(str, _("bijective"))) {
2975 int save_base = printops.base;
2976 printops.base = BASE_BIJECTIVE_26;
2977 setResult(NULL, false);
2978 printops.base = save_base;
2979 } else if(equalsIgnoreCase(str, "sexa") || EQUALS_IGNORECASE_AND_LOCAL(str, "sexagesimal", _("sexagesimal"))) {
2980 int save_base = printops.base;
2981 printops.base = BASE_SEXAGESIMAL;
2982 setResult(NULL, false);
2983 printops.base = save_base;
2984 } else if(equalsIgnoreCase(str, "fp32") || equalsIgnoreCase(str, "binary32") || equalsIgnoreCase(str, "float")) {
2985 int save_base = printops.base;
2986 printops.base = BASE_FP32;
2987 setResult(NULL, false);
2988 printops.base = save_base;
2989 } else if(equalsIgnoreCase(str, "fp64") || equalsIgnoreCase(str, "binary64") || equalsIgnoreCase(str, "double")) {
2990 int save_base = printops.base;
2991 printops.base = BASE_FP64;
2992 setResult(NULL, false);
2993 printops.base = save_base;
2994 } else if(equalsIgnoreCase(str, "fp16") || equalsIgnoreCase(str, "binary16")) {
2995 int save_base = printops.base;
2996 printops.base = BASE_FP16;
2997 setResult(NULL, false);
2998 printops.base = save_base;
2999 } else if(equalsIgnoreCase(str, "fp80")) {
3000 int save_base = printops.base;
3001 printops.base = BASE_FP80;
3002 setResult(NULL, false);
3003 printops.base = save_base;
3004 } else if(equalsIgnoreCase(str, "fp128") || equalsIgnoreCase(str, "binary128")) {
3005 int save_base = printops.base;
3006 printops.base = BASE_FP128;
3007 setResult(NULL, false);
3008 printops.base = save_base;
3009 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "time", _("time"))) {
3010 int save_base = printops.base;
3011 printops.base = BASE_TIME;
3012 setResult(NULL, false);
3013 printops.base = save_base;
3014 } else if(equalsIgnoreCase(str, "unicode")) {
3015 int save_base = printops.base;
3016 printops.base = BASE_UNICODE;
3017 setResult(NULL, false);
3018 printops.base = save_base;
3019 } else if(equalsIgnoreCase(str, "utc") || equalsIgnoreCase(str, "gmt")) {
3020 printops.time_zone = TIME_ZONE_UTC;
3021 setResult(NULL, false);
3022 printops.time_zone = TIME_ZONE_LOCAL;
3023 } else if(str.length() > 3 && equalsIgnoreCase(str.substr(0, 3), "bin") && is_in(NUMBERS, str[3])) {
3024 int save_base = printops.base;
3025 printops.base = BASE_BINARY;
3026 printops.binary_bits = s2i(str.substr(3));
3027 setResult(NULL, false);
3028 printops.base = save_base;
3029 printops.binary_bits = 0;
3030 } else if(str.length() > 3 && equalsIgnoreCase(str.substr(0, 3), "hex") && is_in(NUMBERS, str[3])) {
3031 int save_base = printops.base;
3032 printops.base = BASE_HEXADECIMAL;
3033 printops.binary_bits = s2i(str.substr(3));
3034 setResult(NULL, false);
3035 printops.base = save_base;
3036 printops.binary_bits = 0;
3037 } else if(str.length() > 3 && (equalsIgnoreCase(str.substr(0, 3), "utc") || equalsIgnoreCase(str.substr(0, 3), "gmt"))) {
3038 string to_str = str.substr(3);
3039 remove_blanks(to_str);
3040 bool b_minus = false;
3041 if(to_str[0] == '+') {
3042 to_str.erase(0, 1);
3043 } else if(to_str[0] == '-') {
3044 b_minus = true;
3045 to_str.erase(0, 1);
3046 } else if(to_str.find(SIGN_MINUS) == 0) {
3047 b_minus = true;
3048 to_str.erase(0, strlen(SIGN_MINUS));
3049 }
3050 unsigned int tzh = 0, tzm = 0;
3051 int itz = 0;
3052 if(!str.empty() && sscanf(to_str.c_str(), "%2u:%2u", &tzh, &tzm) > 0) {
3053 itz = tzh * 60 + tzm;
3054 if(b_minus) itz = -itz;
3055 } else {
3056 CALCULATOR->error(true, _("Time zone parsing failed."), NULL);
3057 }
3058 printops.time_zone = TIME_ZONE_CUSTOM;
3059 printops.custom_time_zone = itz;
3060 setResult(NULL, false);
3061 printops.custom_time_zone = 0;
3062 printops.time_zone = TIME_ZONE_LOCAL;
3063 } else if(str == "CET") {
3064 printops.time_zone = TIME_ZONE_CUSTOM;
3065 printops.custom_time_zone = 60;
3066 setResult(NULL, false);
3067 printops.custom_time_zone = 0;
3068 printops.time_zone = TIME_ZONE_LOCAL;
3069 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "rectangular", _("rectangular")) || EQUALS_IGNORECASE_AND_LOCAL(str, "cartesian", _("cartesian")) || str == "rect") {
3070 avoid_recalculation = false;
3071 ComplexNumberForm cnf_bak = evalops.complex_number_form;
3072 bool caf_bak = complex_angle_form;
3073 complex_angle_form = false;
3074 evalops.complex_number_form = COMPLEX_NUMBER_FORM_EXPONENTIAL;
3075 hide_parse_errors = true;
3076 if(rpn_mode) execute_command(COMMAND_EVAL);
3077 else execute_expression();
3078 hide_parse_errors = false;
3079 evalops.complex_number_form = cnf_bak;
3080 complex_angle_form = caf_bak;
3081 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "exponential", _("exponential")) || str == "exp") {
3082 avoid_recalculation = false;
3083 ComplexNumberForm cnf_bak = evalops.complex_number_form;
3084 bool caf_bak = complex_angle_form;
3085 complex_angle_form = false;
3086 evalops.complex_number_form = COMPLEX_NUMBER_FORM_EXPONENTIAL;
3087 hide_parse_errors = true;
3088 if(rpn_mode) execute_command(COMMAND_EVAL);
3089 else execute_expression();
3090 hide_parse_errors = false;
3091 evalops.complex_number_form = cnf_bak;
3092 complex_angle_form = caf_bak;
3093 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "polar", _("polar"))) {
3094 avoid_recalculation = false;
3095 ComplexNumberForm cnf_bak = evalops.complex_number_form;
3096 bool caf_bak = complex_angle_form;
3097 complex_angle_form = false;
3098 evalops.complex_number_form = COMPLEX_NUMBER_FORM_POLAR;
3099 hide_parse_errors = true;
3100 if(rpn_mode) execute_command(COMMAND_EVAL);
3101 else execute_expression();
3102 hide_parse_errors = false;
3103 evalops.complex_number_form = cnf_bak;
3104 complex_angle_form = caf_bak;
3105 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "angle", _("angle")) || EQUALS_IGNORECASE_AND_LOCAL(str, "phasor", _("phasor"))) {
3106 avoid_recalculation = false;
3107 ComplexNumberForm cnf_bak = evalops.complex_number_form;
3108 bool caf_bak = complex_angle_form;
3109 complex_angle_form = true;
3110 evalops.complex_number_form = COMPLEX_NUMBER_FORM_CIS;
3111 hide_parse_errors = true;
3112 if(rpn_mode) execute_command(COMMAND_EVAL);
3113 else execute_expression();
3114 hide_parse_errors = false;
3115 evalops.complex_number_form = cnf_bak;
3116 complex_angle_form = caf_bak;
3117 } else if(str == "cis") {
3118 avoid_recalculation = false;
3119 ComplexNumberForm cnf_bak = evalops.complex_number_form;
3120 bool caf_bak = complex_angle_form;
3121 complex_angle_form = false;
3122 evalops.complex_number_form = COMPLEX_NUMBER_FORM_CIS;
3123 hide_parse_errors = true;
3124 if(rpn_mode) execute_command(COMMAND_EVAL);
3125 else execute_expression();
3126 hide_parse_errors = false;
3127 evalops.complex_number_form = cnf_bak;
3128 complex_angle_form = caf_bak;
3129 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "bases", _("bases"))) {
3130 int save_base = printops.base;
3131 string save_result_text = result_text;
3132 string base_str;
3133 int cols = 0;
3134 if(interactive_mode && !cfile) {
3135 base_str = "\n ";
3136 #ifdef HAVE_LIBREADLINE
3137 int rows = 0;
3138 rl_get_screen_size(&rows, &cols);
3139 #else
3140 cols = 80;
3141 #endif
3142 }
3143 base_str += result_text;
3144 if(save_base != BASE_BINARY) {
3145 base_str += " = ";
3146 printops.base = BASE_BINARY;
3147 setResult(NULL, false, true, 0, false, true);
3148 base_str += result_text;
3149 }
3150 if(save_base != BASE_OCTAL) {
3151 base_str += " = ";
3152 printops.base = BASE_OCTAL;
3153 setResult(NULL, false, true, 0, false, true);
3154 base_str += result_text;
3155 }
3156 if(save_base != BASE_DECIMAL) {
3157 base_str += " = ";
3158 printops.base = BASE_DECIMAL;
3159 setResult(NULL, false, true, 0, false, true);
3160 base_str += result_text;
3161 }
3162 if(save_base != BASE_HEXADECIMAL) {
3163 base_str += " = ";
3164 printops.base = BASE_HEXADECIMAL;
3165 setResult(NULL, false, true, 0, false, true);
3166 base_str += result_text;
3167 }
3168 if(interactive_mode && !cfile) {
3169 base_str += "\n";
3170 addLineBreaks(base_str, cols, true, 2, base_str.length());
3171 }
3172 PUTS_UNICODE(base_str.c_str());
3173 printops.base = save_base;
3174 result_text = save_result_text;
3175 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "calendar", _("calendars"))) {
3176 QalculateDateTime date;
3177 if(mstruct->isDateTime()) {
3178 date.set(*mstruct->datetime());
3179 } else {
3180 date.setToCurrentDate();
3181 }
3182 puts("");
3183 show_calendars(date);
3184 puts("");
3185 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "fraction", _("fraction")) || str == "frac") {
3186 NumberFractionFormat save_format = printops.number_fraction_format;
3187 bool save_rfl = printops.restrict_fraction_length;
3188 printops.restrict_fraction_length = false;
3189 printops.number_fraction_format = FRACTION_COMBINED;
3190 setResult(NULL, false);
3191 printops.restrict_fraction_length = save_rfl;
3192 printops.number_fraction_format = save_format;
3193 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "factors", _("factors")) || str == "factor") {
3194 execute_command(COMMAND_FACTORIZE);
3195 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "partial fraction", _("partial fraction")) || str == "partial") {
3196 execute_command(COMMAND_EXPAND_PARTIAL_FRACTIONS);
3197 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "best", _("best")) || EQUALS_IGNORECASE_AND_LOCAL(str, "optimal", _("optimal"))) {
3198 CALCULATOR->resetExchangeRatesUsed();
3199 MathStructure mstruct_new(CALCULATOR->convertToOptimalUnit(*mstruct, evalops, true));
3200 if(check_exchange_rates()) mstruct->set(CALCULATOR->convertToOptimalUnit(*mstruct, evalops, true));
3201 else mstruct->set(mstruct_new);
3202 result_action_executed();
3203 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "base", _("base"))) {
3204 CALCULATOR->resetExchangeRatesUsed();
3205 MathStructure mstruct_new(CALCULATOR->convertToBaseUnits(*mstruct, evalops));
3206 if(check_exchange_rates()) mstruct->set(CALCULATOR->convertToBaseUnits(*mstruct, evalops));
3207 else mstruct->set(mstruct_new);
3208 result_action_executed();
3209 } else if(EQUALS_IGNORECASE_AND_LOCAL(str1, "base", _("base"))) {
3210 int save_base = printops.base;
3211 Number save_nr = CALCULATOR->customOutputBase();
3212 if(equalsIgnoreCase(str2, "golden") || equalsIgnoreCase(str2, "golden ratio") || str2 == "φ") printops.base = BASE_GOLDEN_RATIO;
3213 else if(equalsIgnoreCase(str2, "unicode")) printops.base = BASE_UNICODE;
3214 else if(equalsIgnoreCase(str2, "supergolden") || equalsIgnoreCase(str2, "supergolden ratio") || str2 == "ψ") printops.base = BASE_SUPER_GOLDEN_RATIO;
3215 else if(equalsIgnoreCase(str2, "pi") || str2 == "π") printops.base = BASE_PI;
3216 else if(str2 == "e") printops.base = BASE_E;
3217 else if(str2 == "sqrt(2)" || str2 == "sqrt 2" || str2 == "sqrt2" || str2 == "√2") printops.base = BASE_SQRT2;
3218 else {
3219 EvaluationOptions eo = evalops;
3220 eo.parse_options.base = 10;
3221 MathStructure m;
3222 eo.approximation = APPROXIMATION_TRY_EXACT;
3223 CALCULATOR->beginTemporaryStopMessages();
3224 CALCULATOR->calculate(&m, CALCULATOR->unlocalizeExpression(str2, eo.parse_options), 500, eo);
3225 if(CALCULATOR->endTemporaryStopMessages()) {
3226 printops.base = BASE_CUSTOM;
3227 CALCULATOR->setCustomOutputBase(nr_zero);
3228 } else if(m.isInteger() && m.number() >= 2 && m.number() <= 36) {
3229 printops.base = m.number().intValue();
3230 } else {
3231 printops.base = BASE_CUSTOM;
3232 CALCULATOR->setCustomOutputBase(m.number());
3233 }
3234 }
3235 setResult(NULL, false);
3236 CALCULATOR->setCustomOutputBase(save_nr);
3237 printops.base = save_base;
3238 } else {
3239 bool save_pre = printops.use_unit_prefixes;
3240 bool save_all = printops.use_all_prefixes;
3241 bool save_cur = printops.use_prefixes_for_currencies;
3242 bool save_allu = printops.use_prefixes_for_all_units;
3243 bool save_den = printops.use_denominator_prefix;
3244 int save_bin = CALCULATOR->usesBinaryPrefixes();
3245 if(str[0] == '?' || (str.length() > 1 && str[1] == '?' && (str[0] == 'a' || str[0] == 'd'))) {
3246
3247 printops.use_unit_prefixes = true;
3248 printops.use_prefixes_for_currencies = true;
3249 printops.use_prefixes_for_all_units = true;
3250 if(str[0] == 'a') printops.use_all_prefixes = true;
3251 else if(str[0] == 'd') CALCULATOR->useBinaryPrefixes(0);
3252 } else if(str.length() > 1 && str[1] == '?' && str[0] == 'b') {
3253 printops.use_unit_prefixes = true;
3254 int i = has_information_unit(*mstruct);
3255 CALCULATOR->useBinaryPrefixes(i > 0 ? 1 : 2);
3256 if(i == 1) {
3257 printops.use_denominator_prefix = false;
3258 } else if(i > 1) {
3259 printops.use_denominator_prefix = true;
3260 } else {
3261 printops.use_prefixes_for_currencies = true;
3262 printops.use_prefixes_for_all_units = true;
3263 }
3264 }
3265 CALCULATOR->resetExchangeRatesUsed();
3266 ParseOptions pa = evalops.parse_options; pa.base = 10;
3267 MathStructure mstruct_new(CALCULATOR->convert(*mstruct, CALCULATOR->unlocalizeExpression(str, pa), evalops));
3268 if(check_exchange_rates()) mstruct->set(CALCULATOR->convert(*mstruct, CALCULATOR->unlocalizeExpression(str, pa), evalops));
3269 else mstruct->set(mstruct_new);
3270 result_action_executed();
3271 printops.use_unit_prefixes = save_pre;
3272 printops.use_all_prefixes = save_all;
3273 printops.use_prefixes_for_currencies = save_cur;
3274 printops.use_prefixes_for_all_units = save_allu;
3275 printops.use_denominator_prefix = save_den;
3276 CALCULATOR->useBinaryPrefixes(save_bin);
3277 }
3278 //qalc command
3279 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "factor", _("factor"))) {
3280 execute_command(COMMAND_FACTORIZE);
3281 //qalc command
3282 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "partial fraction", _("partial fraction"))) {
3283 execute_command(COMMAND_EXPAND_PARTIAL_FRACTIONS);
3284 //qalc command
3285 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "simplify", _("simplify")) || EQUALS_IGNORECASE_AND_LOCAL(str, "expand", _("expand"))) {
3286 execute_command(COMMAND_EXPAND);
3287 //qalc command
3288 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "mode", _("mode"))) {
3289 INIT_SCREEN_CHECK
3290
3291 int pctl;
3292
3293 CHECK_IF_SCREEN_FILLED_HEADING(_("Algebraic Mode"));
3294
3295 #define PRINT_AND_COLON_TABS(x, s) str = x; pctl = unicode_length_check(x); if(strlen(s) > 0) {str += " (" s ")"; pctl += unicode_length_check(" (" s ")");} do {str += '\t'; pctl += 8;} while(pctl < 48);
3296
3297 PRINT_AND_COLON_TABS(_("algebra mode"), "alg");
3298 switch(evalops.structuring) {
3299 case STRUCTURING_NONE: {str += _("none"); break;}
3300 case STRUCTURING_FACTORIZE: {str += _("factorize"); break;}
3301 default: {str += _("expand"); break;}
3302 }
3303 CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3304 PRINT_AND_COLON_TABS(_("assume nonzero denominators"), "nzd"); str += b2oo(evalops.assume_denominators_nonzero, false); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3305 PRINT_AND_COLON_TABS(_("warn nonzero denominators"), "warnnzd"); str += b2oo(evalops.warn_about_denominators_assumed_nonzero, false); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3306 string value;
3307 switch(CALCULATOR->defaultAssumptions()->sign()) {
3308 case ASSUMPTION_SIGN_POSITIVE: {value = _("positive"); break;}
3309 case ASSUMPTION_SIGN_NONPOSITIVE: {value = _("non-positive"); break;}
3310 case ASSUMPTION_SIGN_NEGATIVE: {value = _("negative"); break;}
3311 case ASSUMPTION_SIGN_NONNEGATIVE: {value = _("non-negative"); break;}
3312 case ASSUMPTION_SIGN_NONZERO: {value = _("non-zero"); break;}
3313 default: {}
3314 }
3315 if(!value.empty() && CALCULATOR->defaultAssumptions()->type() != ASSUMPTION_TYPE_NONE) value += " ";
3316 switch(CALCULATOR->defaultAssumptions()->type()) {
3317 case ASSUMPTION_TYPE_INTEGER: {value += _("integer"); break;}
3318 case ASSUMPTION_TYPE_RATIONAL: {value += _("rational"); break;}
3319 case ASSUMPTION_TYPE_REAL: {value += _("real"); break;}
3320 case ASSUMPTION_TYPE_COMPLEX: {value += _("complex"); break;}
3321 case ASSUMPTION_TYPE_NUMBER: {value += _("number"); break;}
3322 case ASSUMPTION_TYPE_NONMATRIX: {value += _("non-matrix"); break;}
3323 default: {}
3324 }
3325 if(value.empty()) value = _("unknown");
3326 PRINT_AND_COLON_TABS(_("assumptions"), "ass"); str += value; CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3327
3328 CHECK_IF_SCREEN_FILLED_HEADING(_("Calculation"));
3329
3330 PRINT_AND_COLON_TABS(_("angle unit"), "angle");
3331 switch(evalops.parse_options.angle_unit) {
3332 case ANGLE_UNIT_RADIANS: {str += _("rad"); break;}
3333 case ANGLE_UNIT_DEGREES: {str += _("rad"); break;}
3334 case ANGLE_UNIT_GRADIANS: {str += _("gra"); break;}
3335 default: {str += _("none"); break;}
3336 }
3337 CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3338 PRINT_AND_COLON_TABS(_("approximation"), "appr");
3339 switch(evalops.approximation) {
3340 case APPROXIMATION_EXACT: {str += _("exact"); break;}
3341 case APPROXIMATION_TRY_EXACT: {
3342 if(dual_approximation < 0) {
3343 str += _("auto"); break;
3344 } else if(dual_approximation > 0) {
3345 str += _("dual"); break;
3346 } else {
3347 str += _("try exact"); break;
3348 }
3349 }
3350 default: {str += _("approximate"); break;}
3351 }
3352 CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3353 PRINT_AND_COLON_TABS(_("interval arithmetic"), "ia"); str += b2oo(CALCULATOR->usesIntervalArithmetic(), false); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3354 PRINT_AND_COLON_TABS(_("interval calculation"), "ic");
3355 switch(evalops.interval_calculation) {
3356 case INTERVAL_CALCULATION_NONE: {str += _("none"); break;}
3357 case INTERVAL_CALCULATION_VARIANCE_FORMULA: {str += _("variance formula"); break;}
3358 case INTERVAL_CALCULATION_INTERVAL_ARITHMETIC: {str += _("interval arithmetic"); break;}
3359 case INTERVAL_CALCULATION_SIMPLE_INTERVAL_ARITHMETIC: {str += _("simplified"); break;}
3360 }
3361 CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3362 PRINT_AND_COLON_TABS(_("precision"), "prec") str += i2s(CALCULATOR->getPrecision()); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3363
3364 CHECK_IF_SCREEN_FILLED_HEADING(_("Enabled Objects"));
3365
3366 PRINT_AND_COLON_TABS(_("calculate functions"), "calcfunc"); str += b2oo(evalops.calculate_functions, false); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3367 PRINT_AND_COLON_TABS(_("calculate variables"), "calcvar"); str += b2oo(evalops.calculate_variables, false); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3368 PRINT_AND_COLON_TABS(_("complex numbers"), "cplx"); str += b2oo(evalops.allow_complex, false); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3369 PRINT_AND_COLON_TABS(_("functions"), "func"); str += b2oo(evalops.parse_options.functions_enabled, false); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3370 PRINT_AND_COLON_TABS(_("infinite numbers"), "inf"); str += b2oo(evalops.allow_infinite, false); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3371 PRINT_AND_COLON_TABS(_("units"), ""); str += b2oo(evalops.parse_options.units_enabled, false); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3372 PRINT_AND_COLON_TABS(_("unknowns"), ""); str += b2oo(evalops.parse_options.unknowns_enabled, false); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3373 PRINT_AND_COLON_TABS(_("variables"), "var"); str += b2oo(evalops.parse_options.variables_enabled, false); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3374 PRINT_AND_COLON_TABS(_("variable units"), "varunit"); str += b2oo(CALCULATOR->variableUnitsEnabled(), false); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3375
3376 CHECK_IF_SCREEN_FILLED_HEADING(_("Generic Display Options"));
3377
3378 PRINT_AND_COLON_TABS(_("abbreviations"), "abbr"); str += b2oo(printops.abbreviate_names, false); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3379 PRINT_AND_COLON_TABS(_("color"), "");
3380 switch(colorize) {
3381 case 0: {str += _("off"); break;}
3382 case 2: {str += _("light"); break;}
3383 default: {str += _("default"); break;}
3384 }
3385 CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3386 PRINT_AND_COLON_TABS(_("division sign"), "divsign");
3387 switch(printops.division_sign) {
3388 case DIVISION_SIGN_DIVISION_SLASH: {str += SIGN_DIVISION_SLASH; break;}
3389 case DIVISION_SIGN_DIVISION: {str += SIGN_DIVISION; break;}
3390 default: {str += "/"; break;}
3391 }
3392 CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3393 PRINT_AND_COLON_TABS(_("excessive parentheses"), "expar"); str += b2oo(printops.excessive_parenthesis, false); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3394 PRINT_AND_COLON_TABS(_("minus last"), "minlast"); str += b2oo(printops.sort_options.minus_last, false); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3395 PRINT_AND_COLON_TABS(_("multiplication sign"), "mulsign");
3396 switch(printops.multiplication_sign) {
3397 case MULTIPLICATION_SIGN_X: {str += SIGN_MULTIPLICATION; break;}
3398 case MULTIPLICATION_SIGN_DOT: {str += SIGN_MULTIDOT; break;}
3399 case MULTIPLICATION_SIGN_ALTDOT: {str += SIGN_MIDDLEDOT; break;}
3400 default: {str += "*"; break;}
3401 }
3402 CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3403 PRINT_AND_COLON_TABS(_("short multiplication"), "shortmul"); str += b2oo(printops.short_multiplication, false); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3404 PRINT_AND_COLON_TABS(_("spacious"), "space"); str += b2oo(printops.spacious, false); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3405 PRINT_AND_COLON_TABS(_("spell out logical"), "spellout"); str += b2oo(printops.spell_out_logical_operators, false); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3406 PRINT_AND_COLON_TABS(_("unicode"), "uni"); str += b2oo(printops.use_unicode_signs, false); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3407
3408 CHECK_IF_SCREEN_FILLED_HEADING(_("Numerical Display"));
3409
3410 PRINT_AND_COLON_TABS(_("base"), "");
3411 switch(printops.base) {
3412 case BASE_ROMAN_NUMERALS: {str += _("roman"); break;}
3413 case BASE_BIJECTIVE_26: {str += _("bijective"); break;}
3414 case BASE_SEXAGESIMAL: {str += _("sexagesimal"); break;}
3415 case BASE_FP16: {str += "fp16"; break;}
3416 case BASE_FP32: {str += "fp32"; break;}
3417 case BASE_FP64: {str += "fp64"; break;}
3418 case BASE_FP80: {str += "fp80"; break;}
3419 case BASE_FP128: {str += "fp128"; break;}
3420 case BASE_TIME: {str += _("time"); break;}
3421 case BASE_GOLDEN_RATIO: {str += "golden"; break;}
3422 case BASE_SUPER_GOLDEN_RATIO: {str += "supergolden"; break;}
3423 case BASE_E: {str += "e"; break;}
3424 case BASE_PI: {str += "pi"; break;}
3425 case BASE_SQRT2: {str += "sqrt(2)"; break;}
3426 case BASE_UNICODE: {str += "Unicode"; break;}
3427 case BASE_CUSTOM: {str += CALCULATOR->customOutputBase().print(CALCULATOR->messagePrintOptions()); break;}
3428 default: {str += i2s(printops.base);}
3429 }
3430 CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3431 PRINT_AND_COLON_TABS(_("base display"), "basedisp");
3432 switch(printops.base_display) {
3433 case BASE_DISPLAY_NONE: {str += _("none"); break;}
3434 case BASE_DISPLAY_NORMAL: {str += _("normal"); break;}
3435 case BASE_DISPLAY_ALTERNATIVE: {str += _("alternative"); break;}
3436 }
3437 CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3438 PRINT_AND_COLON_TABS(_("complex form"), "cplxform");
3439 switch(evalops.complex_number_form) {
3440 case COMPLEX_NUMBER_FORM_RECTANGULAR: {str += _("rectangular"); break;}
3441 case COMPLEX_NUMBER_FORM_EXPONENTIAL: {str += _("exponential"); break;}
3442 case COMPLEX_NUMBER_FORM_POLAR: {str += _("polar"); break;}
3443 case COMPLEX_NUMBER_FORM_CIS: {if(complex_angle_form) {str += _("angle");} else {str += "cis";} break;}
3444 }
3445 CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3446 PRINT_AND_COLON_TABS(_("decimal comma"), "");
3447 if(b_decimal_comma < 0) {str += _("locale");}
3448 else if(b_decimal_comma == 0) {str += _("off");}
3449 else {str += _("on");}
3450 CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3451 PRINT_AND_COLON_TABS(_("digit grouping"), "group");
3452 switch(printops.digit_grouping) {
3453 case DIGIT_GROUPING_NONE: {str += _("off"); break;}
3454 case DIGIT_GROUPING_STANDARD: {str += _("standard"); break;}
3455 case DIGIT_GROUPING_LOCALE: {str += _("locale"); break;}
3456 }
3457 CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3458 PRINT_AND_COLON_TABS(_("fractions"), "fr");
3459 if(dual_fraction < 0) {
3460 str += _("auto");
3461 } else if(dual_fraction > 0) {
3462 str += _("dual");
3463 } else {
3464 switch(printops.number_fraction_format) {
3465 case FRACTION_DECIMAL: {str += _("off"); break;}
3466 case FRACTION_DECIMAL_EXACT: {str += _("exact"); break;}
3467 case FRACTION_FRACTIONAL: {if(printops.restrict_fraction_length) {str += _("on");} else {str += _("long");} break;}
3468 case FRACTION_COMBINED: {str += _("mixed"); break;}
3469 }
3470 }
3471 CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3472 PRINT_AND_COLON_TABS(_("hexadecimal two's"), "hextwos"); str += b2oo(printops.hexadecimal_twos_complement, false); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3473 PRINT_AND_COLON_TABS(_("imaginary j"), "imgj"); str += b2oo(CALCULATOR->getVariableById(VARIABLE_ID_I)->hasName("j") > 0, false); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3474 PRINT_AND_COLON_TABS(_("interval display"), "ivdisp");
3475 if(adaptive_interval_display) {
3476 str += _("adaptive");
3477 } else {
3478 switch(printops.interval_display) {
3479 case INTERVAL_DISPLAY_SIGNIFICANT_DIGITS: {str += _("significant"); break;}
3480 case INTERVAL_DISPLAY_INTERVAL: {str += _("interval"); break;}
3481 case INTERVAL_DISPLAY_PLUSMINUS: {str += _("plusminus"); break;}
3482 case INTERVAL_DISPLAY_MIDPOINT: {str += _("midpoint"); break;}
3483 case INTERVAL_DISPLAY_LOWER: {str += _("lower"); break;}
3484 case INTERVAL_DISPLAY_UPPER: {str += _("upper"); break;}
3485 default: {str += i2s(printops.interval_display + 1); break;}
3486 }
3487 }
3488 CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3489 PRINT_AND_COLON_TABS(_("lowercase e"), "lowe"); str += b2oo(printops.lower_case_e, false); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3490 PRINT_AND_COLON_TABS(_("lowercase numbers"), "lownum"); str += b2oo(printops.lower_case_numbers, false); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3491 PRINT_AND_COLON_TABS(_("max decimals"), "maxdeci");
3492 if(printops.use_max_decimals && printops.max_decimals >= 0) {
3493 str += i2s(printops.max_decimals);
3494 } else {
3495 str += _("off");
3496 }
3497 CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3498 PRINT_AND_COLON_TABS(_("min decimals"), "mindeci");
3499 if(printops.use_min_decimals && printops.min_decimals > 0) {
3500 str += i2s(printops.min_decimals);
3501 } else {
3502 str += _("off");
3503 }
3504 CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3505 PRINT_AND_COLON_TABS(_("repeating decimals"), "repdeci"); str += b2oo(printops.indicate_infinite_series, false); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3506 PRINT_AND_COLON_TABS(_("round to even"), "rndeven"); str += b2oo(printops.round_halfway_to_even, false); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3507 PRINT_AND_COLON_TABS(_("scientific notation"), "exp");
3508 switch(printops.min_exp) {
3509 case EXP_NONE: {str += _("off"); break;}
3510 case EXP_PRECISION: {str += _("auto"); break;}
3511 case EXP_PURE: {str += _("pure"); break;}
3512 case EXP_SCIENTIFIC: {str += _("scientific"); break;}
3513 case EXP_BASE_3: {str += _("engineering"); break;}
3514 default: {str += i2s(printops.min_exp); break;}
3515 }
3516 CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3517 PRINT_AND_COLON_TABS(_("show ending zeroes"), "zeroes"); str += b2oo(printops.show_ending_zeroes, false); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3518 PRINT_AND_COLON_TABS(_("two's complement"), "twos"); str += b2oo(printops.twos_complement, false); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3519
3520 CHECK_IF_SCREEN_FILLED_HEADING(_("Parsing"));
3521
3522 PRINT_AND_COLON_TABS(_("caret as xor"), "xor^"); str += b2oo(caret_as_xor, false); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3523 PRINT_AND_COLON_TABS(_("decimal comma"), "");
3524 if(b_decimal_comma < 0) {str += _("locale");}
3525 else if(b_decimal_comma == 0) {str += _("off");}
3526 else {str += _("on");}
3527 CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3528 if(CALCULATOR->getDecimalPoint() != COMMA) {
3529 PRINT_AND_COLON_TABS(_("ignore comma"), ""); str += b2oo(evalops.parse_options.comma_as_separator, false); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3530 }
3531 if(CALCULATOR->getDecimalPoint() != DOT) {
3532 PRINT_AND_COLON_TABS(_("ignore dot"), ""); str += b2oo(evalops.parse_options.dot_as_separator, false); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3533 }
3534 PRINT_AND_COLON_TABS(_("imaginary j"), "imgj"); str += b2oo(CALCULATOR->getVariableById(VARIABLE_ID_I)->hasName("j") > 0, false); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3535 PRINT_AND_COLON_TABS(_("input base"), "inbase");
3536 switch(evalops.parse_options.base) {
3537 case BASE_ROMAN_NUMERALS: {str += _("roman"); break;}
3538 case BASE_BIJECTIVE_26: {str += _("bijective"); break;}
3539 case BASE_GOLDEN_RATIO: {str += "golden"; break;}
3540 case BASE_SUPER_GOLDEN_RATIO: {str += "supergolden"; break;}
3541 case BASE_E: {str += "e"; break;}
3542 case BASE_PI: {str += "pi"; break;}
3543 case BASE_SQRT2: {str += "sqrt(2)"; break;}
3544 case BASE_UNICODE: {str += "Unicode"; break;}
3545 case BASE_CUSTOM: {str += CALCULATOR->customOutputBase().print(CALCULATOR->messagePrintOptions()); break;}
3546 default: {str += i2s(evalops.parse_options.base);}
3547 }
3548 CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3549 PRINT_AND_COLON_TABS(_("limit implicit multiplication"), "limimpl"); str += b2oo(evalops.parse_options.limit_implicit_multiplication, false); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3550 PRINT_AND_COLON_TABS(_("parsing mode"), "parse");
3551 switch(evalops.parse_options.parsing_mode) {
3552 case PARSING_MODE_ADAPTIVE: {str += _("adaptive"); break;}
3553 case PARSING_MODE_IMPLICIT_MULTIPLICATION_FIRST: {str += _("implicit first"); break;}
3554 case PARSING_MODE_CONVENTIONAL: {str += _("conventional"); break;}
3555 case PARSING_MODE_CHAIN: {str += _("chain"); break;}
3556 case PARSING_MODE_RPN: {str += _("rpn"); break;}
3557 }
3558 CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3559 PRINT_AND_COLON_TABS(_("read precision"), "readprec");
3560 switch(evalops.parse_options.read_precision) {
3561 case DONT_READ_PRECISION: {str += _("off"); break;}
3562 case ALWAYS_READ_PRECISION: {str += _("always"); break;}
3563 case READ_PRECISION_WHEN_DECIMALS: {str += _("when decimals"); break;}
3564 }
3565 CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3566
3567 CHECK_IF_SCREEN_FILLED_HEADING(_("Units"));
3568
3569 CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3570 PRINT_AND_COLON_TABS(_("all prefixes"), "allpref"); str += b2oo(printops.use_all_prefixes, false); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3571 PRINT_AND_COLON_TABS(_("autoconversion"), "conv");
3572 switch(evalops.auto_post_conversion) {
3573 case POST_CONVERSION_NONE: {
3574 if(evalops.mixed_units_conversion > MIXED_UNITS_CONVERSION_NONE) {str += _("mixed");}
3575 else {str += _("none");}
3576 break;
3577 }
3578 case POST_CONVERSION_OPTIMAL: {str += _("optimal"); break;}
3579 case POST_CONVERSION_BASE: {str += _("base"); break;}
3580 case POST_CONVERSION_OPTIMAL_SI: {str += _("optimalsi"); break;}
3581 }
3582 CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3583 PRINT_AND_COLON_TABS(_("binary prefixes"), "binpref"); str += b2oo(CALCULATOR->usesBinaryPrefixes() > 0, false); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3584 PRINT_AND_COLON_TABS(_("currency conversion"), "curconv"); str += b2oo(evalops.local_currency_conversion, false); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3585 PRINT_AND_COLON_TABS(_("denominator prefixes"), "denpref"); str += b2oo(printops.use_denominator_prefix, false); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3586 PRINT_AND_COLON_TABS(_("place units separately"), "unitsep"); str += b2oo(printops.place_units_separately, false); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3587 PRINT_AND_COLON_TABS(_("prefixes"), "pref"); str += b2oo(printops.use_unit_prefixes, false); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3588 PRINT_AND_COLON_TABS(_("show negative exponents"), "negexp"); str += b2oo(printops.negative_exponents, false); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3589 PRINT_AND_COLON_TABS(_("sync units"), "sync"); str += b2oo(evalops.sync_units, false); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3590 PRINT_AND_COLON_TABS(_("temperature calculation"), "temp");
3591 switch(CALCULATOR->getTemperatureCalculationMode()) {
3592 case TEMPERATURE_CALCULATION_RELATIVE: {str += _("relative"); break;}
3593 case TEMPERATURE_CALCULATION_ABSOLUTE: {str += _("absolute"); break;}
3594 default: {str += _("hybrid"); break;}
3595 }
3596 PRINT_AND_COLON_TABS(_("update exchange rates"), "upxrates");
3597 switch(auto_update_exchange_rates) {
3598 case -1: {str += _("ask"); break;}
3599 case 0: {str += _("never"); break;}
3600 default: {str += i2s(auto_update_exchange_rates); break;}
3601 }
3602 CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3603
3604 CHECK_IF_SCREEN_FILLED_HEADING(_("Other"));
3605
3606 PRINT_AND_COLON_TABS(_("ignore locale"), ""); str += b2yn(ignore_locale, false); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3607 PRINT_AND_COLON_TABS(_("rpn"), ""); str += b2oo(rpn_mode, false); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3608 PRINT_AND_COLON_TABS(_("save definitions"), ""); str += b2yn(save_defs_on_exit, false); CHECK_IF_SCREEN_FILLED_PUTS(str.c_str())
3609 PRINT_AND_COLON_TABS(_("save mode"), ""); str += b2yn(save_mode_on_exit, false);
3610 puts("");
3611 //qalc command
3612 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "help", _("help")) || str == "?") {
3613 INIT_SCREEN_CHECK
3614 CHECK_IF_SCREEN_FILLED_PUTS("");
3615 CHECK_IF_SCREEN_FILLED_PUTS(_("Enter a mathematical expression or a command and press enter."));
3616 CHECK_IF_SCREEN_FILLED_PUTS(_("Complete functions, units and variables with the tabulator key."));
3617 CHECK_IF_SCREEN_FILLED_PUTS("");
3618 CHECK_IF_SCREEN_FILLED_PUTS(_("Available commands are:"));
3619 CHECK_IF_SCREEN_FILLED_PUTS("");
3620 PUTS_UNICODE(_("approximate")); CHECK_IF_SCREEN_FILLED
3621 FPUTS_UNICODE(_("assume"), stdout); fputs(" ", stdout); PUTS_UNICODE(_("ASSUMPTIONS")); CHECK_IF_SCREEN_FILLED
3622 FPUTS_UNICODE(_("base"), stdout); fputs(" ", stdout); PUTS_UNICODE(_("BASE")); CHECK_IF_SCREEN_FILLED
3623 FPUTS_UNICODE(_("delete"), stdout); fputs(" ", stdout); PUTS_UNICODE(_("NAME")); CHECK_IF_SCREEN_FILLED
3624 PUTS_UNICODE(_("exact")); CHECK_IF_SCREEN_FILLED
3625 PUTS_UNICODE(_("expand")); CHECK_IF_SCREEN_FILLED
3626 if(canfetch) {
3627 FPUTS_UNICODE(_("exrates"), stdout);
3628 }
3629 puts(""); CHECK_IF_SCREEN_FILLED
3630 PUTS_UNICODE(_("factor")); CHECK_IF_SCREEN_FILLED
3631 FPUTS_UNICODE(_("find"), stdout); fputs("/", stdout); FPUTS_UNICODE(_("list"), stdout); fputs(" [", stdout); FPUTS_UNICODE(_("NAME"), stdout); puts("]"); CHECK_IF_SCREEN_FILLED;
3632 FPUTS_UNICODE(_("function"), stdout); fputs(" ", stdout); FPUTS_UNICODE(_("NAME"), stdout); fputs(" ", stdout); PUTS_UNICODE(_("EXPRESSION")); CHECK_IF_SCREEN_FILLED
3633 FPUTS_UNICODE(_("info"), stdout); fputs(" ", stdout); PUTS_UNICODE(_("NAME")); CHECK_IF_SCREEN_FILLED
3634 PUTS_UNICODE(_("MC/MS/M+/M- (memory operations)")); CHECK_IF_SCREEN_FILLED
3635 PUTS_UNICODE(_("mode")); CHECK_IF_SCREEN_FILLED
3636 PUTS_UNICODE(_("partial fraction")); CHECK_IF_SCREEN_FILLED
3637 FPUTS_UNICODE(_("save"), stdout); fputs("/", stdout); FPUTS_UNICODE(_("store"), stdout); fputs(" ", stdout); FPUTS_UNICODE(_("NAME"), stdout); fputs(" [", stdout); FPUTS_UNICODE(_("CATEGORY"), stdout); fputs("] [", stdout); FPUTS_UNICODE(_("TITLE"), stdout); puts("]"); CHECK_IF_SCREEN_FILLED
3638 PUTS_UNICODE(_("save definitions")); CHECK_IF_SCREEN_FILLED
3639 PUTS_UNICODE(_("save mode")); CHECK_IF_SCREEN_FILLED
3640 FPUTS_UNICODE(_("set"), stdout); fputs(" ", stdout); FPUTS_UNICODE(_("OPTION"), stdout); fputs(" ", stdout); PUTS_UNICODE(_("VALUE")); CHECK_IF_SCREEN_FILLED
3641 FPUTS_UNICODE(_("to"), stdout); fputs("/", stdout); FPUTS_UNICODE(_("convert"), stdout); fputs("/->", stdout); fputs(" ", stdout); PUTS_UNICODE(_("UNIT or \"TO\" COMMAND")); CHECK_IF_SCREEN_FILLED
3642 FPUTS_UNICODE(_("variable"), stdout); fputs(" ", stdout); FPUTS_UNICODE(_("NAME"), stdout); fputs(" ", stdout); FPUTS_UNICODE(_("EXPRESSION"), stdout); CHECK_IF_SCREEN_FILLED_PUTS("");
3643 FPUTS_UNICODE(_("quit"), stdout); fputs("/", stdout); PUTS_UNICODE(_("exit")); CHECK_IF_SCREEN_FILLED_PUTS("");
3644 PUTS_UNICODE(_("Commands for RPN mode:")); CHECK_IF_SCREEN_FILLED
3645 FPUTS_UNICODE(_("rpn"), stdout); fputs(" ", stdout); PUTS_UNICODE(_("STATE")); CHECK_IF_SCREEN_FILLED
3646 PUTS_UNICODE(_("stack")); CHECK_IF_SCREEN_FILLED
3647 PUTS_UNICODE(_("clear stack")); CHECK_IF_SCREEN_FILLED
3648 FPUTS_UNICODE(_("copy"), stdout); fputs(" [", stdout); FPUTS_UNICODE(_("INDEX"), stdout); puts("]"); CHECK_IF_SCREEN_FILLED
3649 FPUTS_UNICODE(_("move"), stdout); fputs(" ", stdout); FPUTS_UNICODE(_("INDEX 1"), stdout); fputs(" ", stdout); PUTS_UNICODE(_("INDEX 2")); CHECK_IF_SCREEN_FILLED
3650 FPUTS_UNICODE(_("pop"), stdout); fputs(" [", stdout); FPUTS_UNICODE(_("INDEX"), stdout); puts("]"); CHECK_IF_SCREEN_FILLED
3651 FPUTS_UNICODE(_("rotate"), stdout); fputs(" [", stdout); FPUTS_UNICODE(_("DIRECTION"), stdout); puts("]"); CHECK_IF_SCREEN_FILLED
3652 FPUTS_UNICODE(_("swap"), stdout); fputs(" [", stdout); FPUTS_UNICODE(_("INDEX 1"), stdout); fputs("] [", stdout); FPUTS_UNICODE(_("INDEX 2"), stdout); puts("]"); CHECK_IF_SCREEN_FILLED
3653 CHECK_IF_SCREEN_FILLED_PUTS("");
3654 CHECK_IF_SCREEN_FILLED_PUTS(_("Type help COMMAND for more information (example: help save)."));
3655 CHECK_IF_SCREEN_FILLED_PUTS(_("Type info NAME for information about a function, variable, unit, or prefix (example: info sin)."));
3656 CHECK_IF_SCREEN_FILLED_PUTS(_("When a line begins with '/', the following text is always interpreted as a command."));
3657 CHECK_IF_SCREEN_FILLED_PUTS("");
3658 #ifdef _WIN32
3659 CHECK_IF_SCREEN_FILLED_PUTS(_("For more information about mathematical expression and different options, and a complete list of functions, variables, and units, see the relevant sections in the manual of the graphical user interface (available at https://qalculate.github.io/manual/index.html)."));
3660 #else
3661 CHECK_IF_SCREEN_FILLED_PUTS(_("For more information about mathematical expression and different options, please consult the man page, or the relevant sections in the manual of the graphical user interface (available at https://qalculate.github.io/manual/index.html), which also includes a complete list of functions, variables, and units."));
3662 #endif
3663 puts("");
3664 //qalc command
3665 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "list", _("list"))) {
3666 list_defs(true);
3667 } else if(EQUALS_IGNORECASE_AND_LOCAL(scom, "list", _("list")) || EQUALS_IGNORECASE_AND_LOCAL(scom, "find", _("find"))) {
3668 str = str.substr(ispace + 1);
3669 remove_blank_ends(str);
3670 size_t i = str.find_first_of(SPACES);
3671 string str1, str2;
3672 if(i == string::npos) {
3673 str1 = str;
3674 } else {
3675 str1 = str.substr(0, i);
3676 str2 = str.substr(i + 1);
3677 remove_blank_ends(str2);
3678 }
3679 char list_type = 0;
3680 if(EQUALS_IGNORECASE_AND_LOCAL(str1, "currencies", _("currencies"))) list_type = 'c';
3681 else if(EQUALS_IGNORECASE_AND_LOCAL(str1, "functions", _("functions"))) list_type = 'f';
3682 else if(EQUALS_IGNORECASE_AND_LOCAL(str1, "variables", _("variables"))) list_type = 'v';
3683 else if(EQUALS_IGNORECASE_AND_LOCAL(str1, "units", _("units"))) list_type = 'u';
3684 else if(EQUALS_IGNORECASE_AND_LOCAL(str1, "prefixes", _("prefixes"))) list_type = 'p';
3685 else if(!str2.empty()) {
3686 if(equalsIgnoreCase(str, _("currencies"))) list_type = 'c';
3687 else if(equalsIgnoreCase(str, _("functions"))) list_type = 'f';
3688 else if(equalsIgnoreCase(str, _("variables"))) list_type = 'v';
3689 else if(equalsIgnoreCase(str, _("units"))) list_type = 'u';
3690 else if(equalsIgnoreCase(str, _("prefixes"))) list_type = 'p';
3691 if(list_type != 0) str2 = "";
3692 } else str2 = str;
3693 list_defs(true, list_type, str2);
3694 //qalc command
3695 } else if(EQUALS_IGNORECASE_AND_LOCAL(scom, "info", _("info"))) {
3696 int pctl;
3697 #define PRINT_AND_COLON_TABS_INFO(x) FPUTS_UNICODE(x, stdout); pctl = unicode_length_check(x); if(pctl >= 23) fputs(":\t", stdout); else if(pctl >= 15) fputs(":\t\t", stdout); else if(pctl >= 7) fputs(":\t\t\t", stdout); else fputs(":\t\t\t\t", stdout);
3698 #define STR_AND_COLON_TABS_INFO(x) pctl = unicode_length(x); if(pctl >= 23) x += ":\t"; else if(pctl >= 15) x += ":\t\t"; else if(pctl >= 7) x += ":\t\t\t"; else x += ":\t\t\t\t";
3699 str = str.substr(ispace + 1, slen - (ispace + 1));
3700 remove_blank_ends(str);
3701 show_info:
3702 string name = str;
3703 ExpressionItem *item = CALCULATOR->getActiveExpressionItem(name);
3704 Prefix *prefix = CALCULATOR->getPrefix(name);
3705 if(!item && !prefix) {
3706 PUTS_UNICODE(_("No function, variable, unit, or prefix with specified name exist."));
3707 } else {
3708 INIT_SCREEN_CHECK
3709 CHECK_IF_SCREEN_FILLED_PUTS("");
3710 ParseOptions pa = evalops.parse_options; pa.base = 10;
3711 for(size_t i = 0; i < 2; i++) {
3712 if(i == 1) item = CALCULATOR->getActiveExpressionItem(name, item);
3713 if(!item) break;
3714 switch(item->type()) {
3715 case TYPE_FUNCTION: {
3716 MathFunction *f = (MathFunction*) item;
3717 Argument *arg;
3718 Argument default_arg;
3719 string str2;
3720 str = _("Function");
3721 if(!f->title(false).empty()) {
3722 str += ": ";
3723 str += f->title();
3724 }
3725 CHECK_IF_SCREEN_FILLED_PUTS(str.c_str());
3726 CHECK_IF_SCREEN_FILLED_PUTS("");
3727 const ExpressionName *ename = &f->preferredName(false, printops.use_unicode_signs);
3728 str = ename->name;
3729 int iargs = f->maxargs();
3730 if(iargs < 0) {
3731 iargs = f->minargs() + 1;
3732 }
3733 str += "(";
3734 if(iargs != 0) {
3735 for(int i2 = 1; i2 <= iargs; i2++) {
3736 if(i2 > f->minargs()) {
3737 str += "[";
3738 }
3739 if(i2 > 1) {
3740 str += CALCULATOR->getComma();
3741 str += " ";
3742 }
3743 arg = f->getArgumentDefinition(i2);
3744 if(arg && !arg->name().empty()) {
3745 str2 = arg->name();
3746 } else {
3747 str2 = _("argument");
3748 str2 += " ";
3749 str2 += i2s(i2);
3750 }
3751 str += str2;
3752 if(i2 > f->minargs()) {
3753 str += "]";
3754 }
3755 }
3756 if(f->maxargs() < 0) {
3757 str += CALCULATOR->getComma();
3758 str += " ...";
3759 }
3760 }
3761 str += ")";
3762 CHECK_IF_SCREEN_FILLED_PUTS(str.c_str());
3763 for(size_t i2 = 1; i2 <= f->countNames(); i2++) {
3764 if(&f->getName(i2) != ename) {
3765 CHECK_IF_SCREEN_FILLED_PUTS(f->getName(i2).name.c_str());
3766 }
3767 }
3768 if(f->subtype() == SUBTYPE_DATA_SET) {
3769 CHECK_IF_SCREEN_FILLED_PUTS("");
3770 snprintf(buffer, 1000, _("Retrieves data from the %s data set for a given object and property. If \"info\" is typed as property, all properties of the object will be listed."), f->title().c_str());
3771 CHECK_IF_SCREEN_FILLED_PUTS(buffer);
3772 }
3773 if(!f->description().empty()) {
3774 CHECK_IF_SCREEN_FILLED_PUTS("");
3775 CHECK_IF_SCREEN_FILLED_PUTS(f->description().c_str());
3776 }
3777 if(!f->example(true).empty()) {
3778 CHECK_IF_SCREEN_FILLED_PUTS("");
3779 str = _("Example:"); str += " "; str += f->example(false, ename->name);
3780 CHECK_IF_SCREEN_FILLED_PUTS(str.c_str());
3781 }
3782 if(f->subtype() == SUBTYPE_DATA_SET && !((DataSet*) f)->copyright().empty()) {
3783 CHECK_IF_SCREEN_FILLED_PUTS("");
3784 CHECK_IF_SCREEN_FILLED_PUTS(((DataSet*) f)->copyright().c_str());
3785 }
3786 if(iargs) {
3787 CHECK_IF_SCREEN_FILLED_PUTS("");
3788 CHECK_IF_SCREEN_FILLED_PUTS(_("Arguments"));
3789 for(int i2 = 1; i2 <= iargs; i2++) {
3790 arg = f->getArgumentDefinition(i2);
3791 if(arg && !arg->name().empty()) {
3792 str = arg->name();
3793 } else {
3794 str = i2s(i2);
3795 }
3796 str += ": ";
3797 if(arg) {
3798 str2 = arg->printlong();
3799 } else {
3800 str2 = default_arg.printlong();
3801 }
3802 if(printops.use_unicode_signs) {
3803 gsub(">=", SIGN_GREATER_OR_EQUAL, str2);
3804 gsub("<=", SIGN_LESS_OR_EQUAL, str2);
3805 gsub("!=", SIGN_NOT_EQUAL, str2);
3806 }
3807 if(i2 > f->minargs()) {
3808 str2 += " (";
3809 //optional argument, in description
3810 str2 += _("optional");
3811 if(!f->getDefaultValue(i2).empty() && f->getDefaultValue(i2) != "\"\"") {
3812 str2 += ", ";
3813 //argument default, in description
3814 str2 += _("default: ");
3815 str2 += f->getDefaultValue(i2);
3816 }
3817 str2 += ")";
3818 }
3819 str += str2;
3820 CHECK_IF_SCREEN_FILLED_PUTS(str.c_str());
3821 }
3822 }
3823 if(!f->condition().empty()) {
3824 CHECK_IF_SCREEN_FILLED_PUTS("");
3825 str = _("Requirement");
3826 str += ": ";
3827 str += f->printCondition();
3828 if(printops.use_unicode_signs) {
3829 gsub(">=", SIGN_GREATER_OR_EQUAL, str);
3830 gsub("<=", SIGN_LESS_OR_EQUAL, str);
3831 gsub("!=", SIGN_NOT_EQUAL, str);
3832 }
3833 CHECK_IF_SCREEN_FILLED_PUTS(str.c_str());
3834 }
3835 if(f->subtype() == SUBTYPE_DATA_SET) {
3836 DataSet *ds = (DataSet*) f;
3837 CHECK_IF_SCREEN_FILLED_PUTS("");
3838 CHECK_IF_SCREEN_FILLED_PUTS(_("Properties"));
3839 DataPropertyIter it;
3840 DataProperty *dp = ds->getFirstProperty(&it);
3841 while(dp) {
3842 if(!dp->isHidden()) {
3843 if(!dp->title(false).empty()) {
3844 str = dp->title();
3845 str += ": ";
3846 }
3847 for(size_t i = 1; i <= dp->countNames(); i++) {
3848 if(i > 1) str += ", ";
3849 str += dp->getName(i);
3850 }
3851 if(dp->isKey()) {
3852 str += " (";
3853 str += _("key");
3854 str += ")";
3855 }
3856 if(!dp->description().empty()) {
3857 str += "\n";
3858 str += dp->description();
3859 }
3860 CHECK_IF_SCREEN_FILLED_PUTS(str.c_str());
3861 }
3862 dp = ds->getNextProperty(&it);
3863 }
3864 }
3865 if(f->subtype() == SUBTYPE_USER_FUNCTION) {
3866 CHECK_IF_SCREEN_FILLED_PUTS("");
3867 ParseOptions pa = evalops.parse_options; pa.base = 10;
3868 str = _("Expression:"); str += " "; str += CALCULATOR->unlocalizeExpression(((UserFunction*) f)->formula(), pa);
3869 CHECK_IF_SCREEN_FILLED_PUTS(str.c_str());
3870 }
3871 CHECK_IF_SCREEN_FILLED_PUTS("");
3872 break;
3873 }
3874 case TYPE_UNIT: {
3875 if(!item->title(false).empty()) {
3876 PRINT_AND_COLON_TABS_INFO(_("Unit"));
3877 FPUTS_UNICODE(item->title().c_str(), stdout);
3878 } else {
3879 FPUTS_UNICODE(_("Unit"), stdout);
3880 }
3881 CHECK_IF_SCREEN_FILLED_PUTS("");
3882 PRINT_AND_COLON_TABS_INFO(_("Names"));
3883 if(item->subtype() != SUBTYPE_COMPOSITE_UNIT) {
3884 const ExpressionName *ename = &item->preferredName(true, printops.use_unicode_signs);
3885 FPUTS_UNICODE(ename->name.c_str(), stdout);
3886 for(size_t i2 = 1; i2 <= item->countNames(); i2++) {
3887 if(&item->getName(i2) != ename && !item->getName(i2).completion_only) {
3888 fputs(" / ", stdout);
3889 FPUTS_UNICODE(item->getName(i2).name.c_str(), stdout);
3890 }
3891 }
3892 }
3893 CHECK_IF_SCREEN_FILLED_PUTS("");
3894 switch(item->subtype()) {
3895 case SUBTYPE_BASE_UNIT: {
3896 break;
3897 }
3898 case SUBTYPE_ALIAS_UNIT: {
3899 AliasUnit *au = (AliasUnit*) item;
3900 PRINT_AND_COLON_TABS_INFO(_("Base Unit"));
3901 string base_unit = au->firstBaseUnit()->print(false, printops.abbreviate_names, printops.use_unicode_signs);
3902 if(au->firstBaseExponent() != 1) {
3903 if(au->firstBaseUnit()->subtype() == SUBTYPE_COMPOSITE_UNIT) {base_unit.insert(0, 1, '('); base_unit += ")";}
3904 if(printops.use_unicode_signs && au->firstBaseExponent() == 2) base_unit += SIGN_POWER_2;
3905 else if(printops.use_unicode_signs && au->firstBaseExponent() == 3) base_unit += SIGN_POWER_3;
3906 else {
3907 base_unit += POWER;
3908 base_unit += i2s(au->firstBaseExponent());
3909 }
3910 }
3911 CHECK_IF_SCREEN_FILLED_PUTS(base_unit.c_str());
3912 PRINT_AND_COLON_TABS_INFO(_("Relation"));
3913 FPUTS_UNICODE(CALCULATOR->localizeExpression(au->expression(), pa).c_str(), stdout);
3914 bool is_relative = false;
3915 if(!au->uncertainty(&is_relative).empty()) {
3916 CHECK_IF_SCREEN_FILLED_PUTS("");
3917 if(is_relative) {PRINT_AND_COLON_TABS_INFO(_("Relative uncertainty"));}
3918 else {PRINT_AND_COLON_TABS_INFO(_("Uncertainty"));}
3919 CHECK_IF_SCREEN_FILLED_PUTS(CALCULATOR->localizeExpression(au->uncertainty(), pa).c_str())
3920 } else if(item->isApproximate()) {
3921 fputs(" (", stdout);
3922 FPUTS_UNICODE(_("approximate"), stdout);
3923 fputs(")", stdout);
3924
3925 }
3926 if(!au->inverseExpression().empty()) {
3927 CHECK_IF_SCREEN_FILLED_PUTS("");
3928 PRINT_AND_COLON_TABS_INFO(_("Inverse Relation"));
3929 FPUTS_UNICODE(CALCULATOR->localizeExpression(au->inverseExpression(), pa).c_str(), stdout);
3930 if(au->uncertainty().empty() && item->isApproximate()) {
3931 fputs(" (", stdout);
3932 FPUTS_UNICODE(_("approximate"), stdout);
3933 fputs(")", stdout);
3934 }
3935 }
3936 CHECK_IF_SCREEN_FILLED_PUTS("");
3937 break;
3938 }
3939 case SUBTYPE_COMPOSITE_UNIT: {
3940 PRINT_AND_COLON_TABS_INFO(_("Base Units"));
3941 CHECK_IF_SCREEN_FILLED_PUTS(((CompositeUnit*) item)->print(false, true, printops.use_unicode_signs).c_str());
3942 break;
3943 }
3944 }
3945 if(!item->description().empty()) {
3946 CHECK_IF_SCREEN_FILLED_PUTS("");
3947 CHECK_IF_SCREEN_FILLED_PUTS(item->description().c_str());
3948 }
3949 CHECK_IF_SCREEN_FILLED_PUTS("");
3950 break;
3951 }
3952 case TYPE_VARIABLE: {
3953 if(!item->title(false).empty()) {
3954 PRINT_AND_COLON_TABS_INFO(_("Variable"));
3955 FPUTS_UNICODE(item->title().c_str(), stdout);
3956 } else {
3957 FPUTS_UNICODE(_("Variable"), stdout);
3958 }
3959 CHECK_IF_SCREEN_FILLED_PUTS("");
3960 PRINT_AND_COLON_TABS_INFO(_("Names"));
3961 const ExpressionName *ename = &item->preferredName(false, printops.use_unicode_signs);
3962 FPUTS_UNICODE(ename->name.c_str(), stdout);
3963 for(size_t i2 = 1; i2 <= item->countNames(); i2++) {
3964 if(&item->getName(i2) != ename && !item->getName(i2).completion_only) {
3965 fputs(" / ", stdout);
3966 FPUTS_UNICODE(item->getName(i2).name.c_str(), stdout);
3967 }
3968 }
3969 Variable *v = (Variable*) item;
3970 string value;
3971 if(is_answer_variable(v)) {
3972 value = _("a previous result");
3973 } else if(v->isKnown()) {
3974 if(((KnownVariable*) v)->isExpression()) {
3975 ParseOptions pa = evalops.parse_options; pa.base = 10;
3976 value = CALCULATOR->localizeExpression(((KnownVariable*) v)->expression(), pa);
3977 } else {
3978 if(((KnownVariable*) v)->get().isMatrix()) {
3979 value = _("matrix");
3980 } else if(((KnownVariable*) v)->get().isVector()) {
3981 value = _("vector");
3982 } else {
3983 PrintOptions po;
3984 po.interval_display = INTERVAL_DISPLAY_PLUSMINUS;
3985 value = CALCULATOR->print(((KnownVariable*) v)->get(), 30, po);
3986 }
3987 }
3988 } else {
3989 if(((UnknownVariable*) v)->assumptions()) {
3990 switch(((UnknownVariable*) v)->assumptions()->sign()) {
3991 case ASSUMPTION_SIGN_POSITIVE: {value = _("positive"); break;}
3992 case ASSUMPTION_SIGN_NONPOSITIVE: {value = _("non-positive"); break;}
3993 case ASSUMPTION_SIGN_NEGATIVE: {value = _("negative"); break;}
3994 case ASSUMPTION_SIGN_NONNEGATIVE: {value = _("non-negative"); break;}
3995 case ASSUMPTION_SIGN_NONZERO: {value = _("non-zero"); break;}
3996 default: {}
3997 }
3998 if(!value.empty() && ((UnknownVariable*) v)->assumptions()->type() != ASSUMPTION_TYPE_NONE) value += " ";
3999 switch(((UnknownVariable*) v)->assumptions()->type()) {
4000 case ASSUMPTION_TYPE_INTEGER: {value += _("integer"); break;}
4001 case ASSUMPTION_TYPE_RATIONAL: {value += _("rational"); break;}
4002 case ASSUMPTION_TYPE_REAL: {value += _("real"); break;}
4003 case ASSUMPTION_TYPE_COMPLEX: {value += _("complex"); break;}
4004 case ASSUMPTION_TYPE_NUMBER: {value += _("number"); break;}
4005 case ASSUMPTION_TYPE_NONMATRIX: {value += _("non-matrix"); break;}
4006 default: {}
4007 }
4008 if(value.empty()) value = _("unknown");
4009 } else {
4010 value = _("default assumptions");
4011 }
4012 }
4013 CHECK_IF_SCREEN_FILLED_PUTS("");
4014 bool is_relative = false;
4015 if(v->isKnown() && ((KnownVariable*) v)->isExpression() && !((KnownVariable*) v)->uncertainty(&is_relative).empty()) {
4016 PRINT_AND_COLON_TABS_INFO(_("Value"));
4017 FPUTS_UNICODE(value.c_str(), stdout);
4018 CHECK_IF_SCREEN_FILLED_PUTS("");
4019 if(is_relative) {PRINT_AND_COLON_TABS_INFO(_("Relative uncertainty"));}
4020 else {PRINT_AND_COLON_TABS_INFO(_("Uncertainty"));}
4021 CHECK_IF_SCREEN_FILLED_PUTS(CALCULATOR->localizeExpression(((KnownVariable*) v)->uncertainty(), pa).c_str())
4022 } else {
4023 string value_pre = _("Value");
4024 STR_AND_COLON_TABS_INFO(value_pre);
4025 value.insert(0, value_pre);
4026 bool b_approx = item->isApproximate();
4027 if(b_approx && v->isKnown()) {
4028 if(((KnownVariable*) v)->isExpression()) {
4029 b_approx = ((KnownVariable*) v)->expression().find(SIGN_PLUSMINUS) == string::npos && ((KnownVariable*) v)->expression().find(CALCULATOR->getFunctionById(FUNCTION_ID_INTERVAL)->referenceName()) == string::npos;
4030 } else {
4031 b_approx = ((KnownVariable*) v)->get().containsInterval(true, false, false, 0, true) <= 0;
4032 }
4033 }
4034 if(b_approx) {
4035 value += " (";
4036 value += _("approximate");
4037 value += ")";
4038 }
4039 int tabs = 0;
4040 for(size_t i = 0; i < value_pre.length(); i++) {
4041 if(value_pre[i] == '\t') {
4042 if(tabs == 0) tabs += (7 - ((i - 1) % 8));
4043 else tabs += 7;
4044 }
4045 }
4046 INIT_COLS
4047 addLineBreaks(value, cols, true, unicode_length(value_pre) + tabs, unicode_length(value_pre) + tabs);
4048 CHECK_IF_SCREEN_FILLED_PUTS(value.c_str());
4049 }
4050 if(v->isKnown() && ((KnownVariable*) v)->isExpression() && !((KnownVariable*) v)->unit().empty()) {
4051 PRINT_AND_COLON_TABS_INFO(_("Unit"));
4052 CHECK_IF_SCREEN_FILLED_PUTS(CALCULATOR->localizeExpression(((KnownVariable*) v)->unit(), pa).c_str())
4053 }
4054 if(!item->description().empty()) {
4055 fputs("\n", stdout);
4056 FPUTS_UNICODE(item->description().c_str(), stdout);
4057 fputs("\n", stdout);
4058 }
4059 CHECK_IF_SCREEN_FILLED_PUTS("");
4060 break;
4061 }
4062 }
4063 }
4064 if(prefix) {
4065 FPUTS_UNICODE(_("Prefix"), stdout);
4066 CHECK_IF_SCREEN_FILLED_PUTS("");
4067 PRINT_AND_COLON_TABS_INFO(_("Names"));
4068 string names;
4069 if(printops.use_unicode_signs && !prefix->unicodeName(false).empty()) names += prefix->unicodeName(false);
4070 if(!prefix->shortName(false, false).empty()) {if(!names.empty()) names += " / "; names += prefix->shortName(false, false);}
4071 if(!prefix->longName(false, false).empty()) {if(!names.empty()) names += " / "; names += prefix->longName();}
4072 CHECK_IF_SCREEN_FILLED_PUTS(names.c_str());
4073 PRINT_AND_COLON_TABS_INFO(_("Value"));
4074 fputs(prefix->value().print().c_str(), stdout);
4075 if(prefix->type() == PREFIX_BINARY) {
4076 fputs(" (2^", stdout);
4077 fputs(i2s(((BinaryPrefix*) prefix)->exponent()).c_str(), stdout);
4078 fputs(")", stdout);
4079 }
4080 CHECK_IF_SCREEN_FILLED_PUTS("");
4081 CHECK_IF_SCREEN_FILLED_PUTS("");
4082 }
4083 }
4084 } else if(EQUALS_IGNORECASE_AND_LOCAL(scom, "help", _("help"))) {
4085 str = str.substr(ispace + 1, slen - (ispace + 1));
4086 remove_blank_ends(str);
4087 remove_duplicate_blanks(str);
4088 if(EQUALS_IGNORECASE_AND_LOCAL(str, "factor", _("factor"))) {
4089 puts("");
4090 PUTS_UNICODE(_("Factorizes the current result."));
4091 puts("");
4092 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "partial fraction", _("partial fraction"))) {
4093 puts("");
4094 PUTS_UNICODE(_("Applies partial fraction decomposition to the current result."));
4095 puts("");
4096 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "simplify", _("simplify")) || EQUALS_IGNORECASE_AND_LOCAL(str, "expand", _("expand"))) {
4097 puts("");
4098 PUTS_UNICODE(_("Expands the current result."));
4099 puts("");
4100 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "set", _("set"))) {
4101 INIT_SCREEN_CHECK
4102 #define STR_AND_TABS_SET(x, s) str = "- "; BEGIN_BOLD(str); str += x; END_BOLD(str); if(strlen(s) > 0) {str += " ("; str += s; str += ")";} str += "\n";
4103 #define SET_DESCRIPTION(s) if(strlen(s) > 0) {BEGIN_ITALIC(str); str += s; END_ITALIC(str); str += "\n";}
4104 #define STR_AND_TABS_BOOL(s, sh, d, v) STR_AND_TABS_SET(s, sh); SET_DESCRIPTION(d); str += "("; str += _("on"); if(v) {str += "*";} str += ", "; str += _("off"); if(!v) {str += "*";} str += ")"; CHECK_IF_SCREEN_FILLED_PUTS(str.c_str());
4105 #define STR_AND_TABS_YESNO(s, sh, d, v) STR_AND_TABS_SET(s, sh); SET_DESCRIPTION(d); str += "("; str += _("yes"); if(v) {str += "*";} str += ", "; str += _("no"); if(!v) {str += "*";} str += ")"; CHECK_IF_SCREEN_FILLED_PUTS(str.c_str());
4106 #define STR_AND_TABS_2(s, sh, d, v, s0, s1, s2) STR_AND_TABS_SET(s, sh); SET_DESCRIPTION(d); str += "(0"; if(v == 0) {str += "*";} str += " = "; str += s0; str += ", 1"; if(v == 1) {str += "*";} str += " = "; str += s1; str += ", 2"; if(v == 2) {str += "*";} str += " = "; str += s2; str += ")"; CHECK_IF_SCREEN_FILLED_PUTS(str.c_str());
4107 #define STR_AND_TABS_2b(s, sh, d, v, s0, s1) STR_AND_TABS_SET(s, sh); SET_DESCRIPTION(d); str += "(1"; if(v == 1) {str += "*";} str += " = "; str += s0; str += ", 2"; if(v == 2) {str += "*";} str += " = "; str += s1; str += ")"; CHECK_IF_SCREEN_FILLED_PUTS(str.c_str());
4108 #define STR_AND_TABS_3(s, sh, d, v, s0, s1, s2, s3) STR_AND_TABS_SET(s, sh); SET_DESCRIPTION(d); str += "(0"; if(v == 0) {str += "*";} str += " = "; str += s0; str += ", 1"; if(v == 1) {str += "*";} str += " = "; str += s1; str += ", 2"; if(v == 2) {str += "*";} str += " = "; str += s2; str += ", 3"; if(v == 3) {str += "*";} str += " = "; str += s3; str += ")"; CHECK_IF_SCREEN_FILLED_PUTS(str.c_str());
4109 #define STR_AND_TABS_4(s, sh, d, v, s0, s1, s2, s3, s4) STR_AND_TABS_SET(s, sh); SET_DESCRIPTION(d); str += "(0"; if(v == 0) {str += "*";} str += " = "; str += s0; str += ", 1"; if(v == 1) {str += "*";} str += " = "; str += s1; str += ", 2"; if(v == 2) {str += "*";} str += " = "; str += s2; str += ", 3"; if(v == 3) {str += "*";} str += " = "; str += s3; str += ", 4"; if(v == 4) {str += "*";} str += " = "; str += s4; str += ")"; CHECK_IF_SCREEN_FILLED_PUTS(str.c_str());
4110 #define STR_AND_TABS_4M(s, sh, d, v, sm, s0, s1, s2, s3) STR_AND_TABS_SET(s, sh); SET_DESCRIPTION(d); str += "(-1"; if(v == -1) {str += "*";} str += " = "; str += sm; str += ", 0"; if(v == 0) {str += "*";} str += " = "; str += s0; str += ", 1"; if(v == 1) {str += "*";} str += " = "; str += s1; str += ", 2"; if(v == 2) {str += "*";} str += " = "; str += s2; if(v == 3) {str += "*";} str += " = "; str += s3; str += ")"; CHECK_IF_SCREEN_FILLED_PUTS(str.c_str());
4111 #define STR_AND_TABS_6M(s, sh, d, v, sm, s0, s1, s2, s3, s4, s5) STR_AND_TABS_SET(s, sh); SET_DESCRIPTION(d); str += "(-1"; if(v == -1) {str += "*";} str += " = "; str += sm; str += ", 0"; if(v == 0) {str += "*";} str += " = "; str += s0; str += ", 1"; if(v == 1) {str += "*";} str += " = "; str += s1; str += ", 2"; if(v == 2) {str += "*";} str += " = "; str += s2; str += ", 3"; if(v == 3) {str += "*";} str += " = "; str += s3; str += ", 4"; if(v == 4) {str += "*";} str += " = "; str += s4; str += ", 4"; if(v == 5) {str += "*";} str += " = "; str += s5; str += ")"; CHECK_IF_SCREEN_FILLED_PUTS(str.c_str());
4112 #define STR_AND_TABS_7(s, sh, d, v, s0, s1, s2, s3, s4, s5, s6) STR_AND_TABS_SET(s, sh); SET_DESCRIPTION(d); str += "(0"; if(v == 0) {str += "*";} str += " = "; str += s0; str += ", 1"; if(v == 1) {str += "*";} str += " = "; str += s1; str += ", 2"; if(v == 2) {str += "*";} str += " = "; str += s2; str += ", 3"; if(v == 3) {str += "*";} str += " = "; str += s3; str += ", 4"; if(v == 4) {str += "*";} str += " = "; str += s4; str += ", 5"; if(v == 5) {str += "*";} str += " = "; str += s5; str += ", 6"; if(v == 6) {str += "*";} str += " = "; str += s6; str += ")"; CHECK_IF_SCREEN_FILLED_PUTS(str.c_str());
4113 CHECK_IF_SCREEN_FILLED_PUTS("");
4114 CHECK_IF_SCREEN_FILLED_PUTS(_("Sets the value of an option."));
4115 CHECK_IF_SCREEN_FILLED_PUTS(_("Example: set base 16."));
4116 CHECK_IF_SCREEN_FILLED_PUTS("");
4117 CHECK_IF_SCREEN_FILLED_PUTS(_("Available options and accepted values are (the current value is marked with '*'):"));
4118
4119 CHECK_IF_SCREEN_FILLED_HEADING_S(_("Algebraic Mode"));
4120
4121 STR_AND_TABS_2b(_("algebra mode"), "alg", _("Determines if the expression is factorized or not after calculation."), evalops.structuring, _("expand"), _("factorize"));
4122 STR_AND_TABS_BOOL(_("assume nonzero denominators"), "nzd", _("Determines if unknown values will be assumed non-zero (x/x=1)."), evalops.assume_denominators_nonzero);
4123 STR_AND_TABS_BOOL(_("warn nonzero denominators"), "warnnzd", _("Display a message after a value has been assumed non-zero."), evalops.warn_about_denominators_assumed_nonzero);
4124 Assumptions *ass = CALCULATOR->defaultAssumptions();
4125 STR_AND_TABS_SET(_("assumptions"), "ass");
4126 SET_DESCRIPTION(_("Default assumptions for unknown variables."));
4127 str += "(";
4128 str += _("unknown");
4129 if(ass->sign() == ASSUMPTION_SIGN_UNKNOWN) str += "*";
4130 str += ", "; str += _("non-zero");
4131 if(ass->sign() == ASSUMPTION_SIGN_NONZERO) str += "*";
4132 str += ", "; str += _("positive");
4133 if(ass->sign() == ASSUMPTION_SIGN_POSITIVE) str += "*";
4134 str += ", "; str += _("negative");
4135 if(ass->sign() == ASSUMPTION_SIGN_NEGATIVE) str += "*";
4136 str += ", "; str += _("non-positive");
4137 if(ass->sign() == ASSUMPTION_SIGN_NONPOSITIVE) str += "*";
4138 str += ", "; str += _("non-negative");
4139 if(ass->sign() == ASSUMPTION_SIGN_NONNEGATIVE) str += "*";
4140 str += " + "; str += _("number");
4141 if(ass->type() == ASSUMPTION_TYPE_NUMBER) str += "*";
4142 str += ", "; str += _("real");
4143 if(ass->type() == ASSUMPTION_TYPE_REAL) str += "*";
4144 str += ", "; str += _("rational");
4145 if(ass->type() == ASSUMPTION_TYPE_RATIONAL) str += "*";
4146 str += ", "; str += _("integer");
4147 if(ass->type() == ASSUMPTION_TYPE_INTEGER) str += "*";
4148 str += ")";
4149 CHECK_IF_SCREEN_FILLED_PUTS(str.c_str());
4150
4151 CHECK_IF_SCREEN_FILLED_HEADING_S(_("Calculation"));
4152
4153 STR_AND_TABS_3(_("angle unit"), "angle", "Default angle unit for trigonometric functions.", evalops.parse_options.angle_unit, _("none"), _("radians"), _("degrees"), _("gradians"));
4154 int appr = evalops.approximation;
4155 if(dual_approximation < 0) appr = -1;
4156 else if(dual_approximation > 0) appr = 3;
4157 STR_AND_TABS_4M(_("approximation"), "appr", _("How approximate variables and calculations are handled. In exact mode approximate values will not be calculated."), appr, _("auto"), _("exact"), _("try exact"), _("approximate"), _("dual"));
4158 STR_AND_TABS_BOOL(_("interval arithmetic"), "ia", _("If activated, interval arithmetic determines the final precision of calculations (avoids wrong results after loss of significance) with approximate functions and/or irrational numbers."), CALCULATOR->usesIntervalArithmetic());
4159 STR_AND_TABS_2b(_("interval calculation"), "ic", _("Determines the method used for interval calculation / uncertainty propagation."), evalops.interval_calculation, _("variance formula"), _("interval arithmetic"));
4160 STR_AND_TABS_SET(_("precision"), "prec");
4161 SET_DESCRIPTION(_("Specifies the default number of significant digits displayed and determines the precision used for approximate calculations."));
4162 str += "(> 0) "; str += i2s(CALCULATOR->getPrecision()); str += "*"; CHECK_IF_SCREEN_FILLED_PUTS(str.c_str());
4163
4164 CHECK_IF_SCREEN_FILLED_HEADING_S(_("Enabled Objects"));
4165
4166 STR_AND_TABS_BOOL(_("calculate functions"), "calcfunc", "", evalops.calculate_functions);
4167 STR_AND_TABS_BOOL(_("calculate variables"), "calcvar", "", evalops.calculate_variables);
4168 STR_AND_TABS_BOOL(_("complex numbers"), "cplx", "", evalops.allow_complex);
4169 STR_AND_TABS_BOOL(_("functions"), "func", "", evalops.parse_options.functions_enabled);
4170 STR_AND_TABS_BOOL(_("infinite numbers"), "inf", "", evalops.allow_infinite);
4171 STR_AND_TABS_BOOL(_("units"), "", "", evalops.parse_options.units_enabled);
4172 STR_AND_TABS_BOOL(_("unknowns"), "", _("Interprete undefined symbols in expressions as unknown variables."), evalops.parse_options.unknowns_enabled);
4173 STR_AND_TABS_BOOL(_("variables"), "var", "", evalops.parse_options.variables_enabled);
4174 STR_AND_TABS_BOOL(_("variable units"), "varunit", _("If activated physical constants include units (e.g. c = 299 792 458 m∕s)."), CALCULATOR->variableUnitsEnabled());
4175
4176 CHECK_IF_SCREEN_FILLED_HEADING_S(_("Generic Display Options"));
4177
4178 STR_AND_TABS_BOOL(_("abbreviations"), "abbr", _("Use abbreviated names for units and variables."), printops.abbreviate_names);
4179 STR_AND_TABS_2(_("color"), "", _("Use colors to highlight different elements of expressions and results."), colorize, _("off"), _("default"), _("light"));
4180 STR_AND_TABS_2(_("division sign"), "divsign", "", printops.division_sign, "/", SIGN_DIVISION_SLASH, SIGN_DIVISION);
4181 STR_AND_TABS_BOOL(_("excessive parentheses"), "expar", "", printops.excessive_parenthesis);
4182 STR_AND_TABS_BOOL(_("minus last"), "minlast", _("Always place negative values last."), printops.sort_options.minus_last);
4183 STR_AND_TABS_3(_("multiplication sign"), "mulsign", "", printops.multiplication_sign, "*", SIGN_MULTIDOT, SIGN_MULTIPLICATION, SIGN_MIDDLEDOT);
4184 STR_AND_TABS_BOOL(_("short multiplication"), "shortmul", "", printops.short_multiplication);
4185 STR_AND_TABS_BOOL(_("spacious"), "space", _("Add extra space around operators."), printops.spacious);
4186 STR_AND_TABS_BOOL(_("spell out logical"), "spellout", "", printops.spell_out_logical_operators);
4187 STR_AND_TABS_BOOL(_("unicode"), "uni", _("Display Unicode characters."), printops.use_unicode_signs);
4188
4189 CHECK_IF_SCREEN_FILLED_HEADING_S(_("Numerical Display"));
4190
4191 STR_AND_TABS_SET(_("base"), ""); str += "(-1114112 - 1114112"; str += ", "; str += _("bin");
4192 if(printops.base == BASE_BINARY) str += "*";
4193 str += ", "; str += _("oct");
4194 if(printops.base == BASE_OCTAL) str += "*";
4195 str += ", "; str += _("dec");
4196 if(printops.base == BASE_DECIMAL) str += "*";
4197 str += ", "; str += _("hex");
4198 if(printops.base == BASE_HEXADECIMAL) str += "*";
4199 str += ", "; str += _("sexa");
4200 if(printops.base == BASE_SEXAGESIMAL) str += "*";
4201 str += ", "; str += _("time");
4202 if(printops.base == BASE_TIME) str += "*";
4203 str += ", "; str += _("roman");
4204 if(printops.base == BASE_ROMAN_NUMERALS) str += "*";
4205 str += ")";
4206 if(printops.base == BASE_CUSTOM) {str += " "; str += CALCULATOR->customOutputBase().print(CALCULATOR->messagePrintOptions()); str += "*";}
4207 else if(printops.base == BASE_UNICODE) {str += " "; str += "Unicode"; str += "*";}
4208 else if(printops.base == BASE_GOLDEN_RATIO) {str += " "; str += "golden"; str += "*";}
4209 else if(printops.base == BASE_SUPER_GOLDEN_RATIO) {str += " "; str += "supergolden"; str += "*";}
4210 else if(printops.base == BASE_E) {str += " "; str += "e"; str += "*";}
4211 else if(printops.base == BASE_PI) {str += " "; str += "pi"; str += "*";}
4212 else if(printops.base == BASE_SQRT2) {str += " "; str += "sqrt(2)"; str += "*";}
4213 else if(printops.base > 2 && printops.base <= 36 && printops.base != BASE_OCTAL && printops.base != BASE_DECIMAL && printops.base != BASE_HEXADECIMAL) {str += " "; str += i2s(printops.base); str += "*";}
4214 CHECK_IF_SCREEN_FILLED_PUTS(str.c_str());
4215 STR_AND_TABS_2(_("base display"), "basedisp", "", printops.base_display, _("none"), _("normal"), _("alternative"));
4216 STR_AND_TABS_4(_("complex form"), "cplxform", "", evalops.complex_number_form + (complex_angle_form ? 1 : 0), _("rectangular"), _("exponential"), _("polar"), "cis", _("angle"));
4217 STR_AND_TABS_SET(_("decimal comma"), "");
4218 SET_DESCRIPTION(_("Determines the default decimal separator."));
4219 str += "(";
4220 str += _("locale");
4221 if(b_decimal_comma < 0) str += "*";
4222 str += ", "; str += _("off");
4223 if(b_decimal_comma == 0) str += "*";
4224 str += ", "; str += _("on");
4225 if(b_decimal_comma > 0) str += "*";
4226 str += ")";
4227 CHECK_IF_SCREEN_FILLED_PUTS(str.c_str());
4228 STR_AND_TABS_2(_("digit grouping"), "group", "", printops.digit_grouping, _("off"), _("standard"), _("locale"));
4229 int nff = printops.number_fraction_format;
4230 if(dual_fraction < 0) nff = -1;
4231 else if(dual_fraction > 0) nff = 5;
4232 else if(!printops.restrict_fraction_length && printops.number_fraction_format == FRACTION_FRACTIONAL) nff = 4;
4233 STR_AND_TABS_6M(_("fractions"), "fr", _("Determines how rational numbers are displayed (e.g. 5/4 = 1 + 1/4 = 1.25). 'long' removes limits on the size of the numerator and denonimator."), nff, _("auto"), _("off"), _("exact"), _("on"), _("mixed"), _("long"), _("dual"));
4234 STR_AND_TABS_BOOL(_("hexadecimal two's"), "hextwos", _("Enables two's complement representation for display of negative hexadecimal numbers."), printops.twos_complement);
4235 STR_AND_TABS_BOOL(_("imaginary j"), "imgj", _("Use 'j' (instead of 'i') as default symbol for the imaginary unit."), (CALCULATOR->getVariableById(VARIABLE_ID_I)->hasName("j") > 0));
4236 STR_AND_TABS_7(_("interval display"), "ivdisp", "", (adaptive_interval_display ? 0 : printops.interval_display + 1), _("adaptive"), _("significant"), _("interval"), _("plusminus"), _("midpoint"), _("upper"), _("lower"))
4237 STR_AND_TABS_BOOL(_("lowercase e"), "lowe", _("Use lowercase e for E-notation (5e2 = 5 * 10^2)."), printops.lower_case_e);
4238 STR_AND_TABS_BOOL(_("lowercase numbers"), "lownum", _("Use lowercase letters for number bases > 10."), printops.lower_case_numbers);
4239 STR_AND_TABS_SET(_("max decimals"), "maxdeci");
4240 str += "(";
4241 str += _("off");
4242 if(printops.max_decimals < 0 || !printops.use_max_decimals) str += "*";
4243 str += ", >= 0)";
4244 if(printops.max_decimals >= 0 && printops.use_max_decimals) {str += " "; str += i2s(printops.max_decimals); str += "*";}
4245 CHECK_IF_SCREEN_FILLED_PUTS(str.c_str());
4246 STR_AND_TABS_SET(_("min decimals"), "mindeci");
4247 str += "(";
4248 str += _("off");
4249 if(printops.min_decimals < 0 || !printops.use_min_decimals) str += "*";
4250 str += ", >= 0)";
4251 if(printops.min_decimals >= 0 && printops.use_min_decimals) {str += " "; str += i2s(printops.min_decimals); str += "*";}
4252 CHECK_IF_SCREEN_FILLED_PUTS(str.c_str());
4253 STR_AND_TABS_BOOL(_("repeating decimals"), "repdeci", _("If activated, 1/6 is displayed as '0.1 666...', otherwise as '0.166667'."), printops.indicate_infinite_series);
4254 STR_AND_TABS_BOOL(_("round to even"), "rndeven", _("Determines whether halfway numbers are rounded upwards or towards the nearest even integer."), printops.round_halfway_to_even);
4255 STR_AND_TABS_SET(_("scientific notation"), "exp");
4256 SET_DESCRIPTION(_("Determines how scientific notation are used (e.g. 5 543 000 = 5.543E6)."));
4257 str += "(0 = ";
4258 str += _("off");
4259 if(printops.min_exp == EXP_NONE) str += "*";
4260 str += ", -1 = "; str += _("auto");
4261 if(printops.min_exp == EXP_PRECISION) str += "*";
4262 str += ", -3 = "; str += _("engineering");
4263 if(printops.min_exp == EXP_BASE_3) str += "*";
4264 str += ", 1 = "; str += _("pure");
4265 if(printops.min_exp == EXP_PURE) str += "*";
4266 str += ", 3 = "; str += _("scientific");
4267 if(printops.min_exp == EXP_SCIENTIFIC) str += "*";
4268 str += ", >= 0)";
4269 if(printops.min_exp != EXP_NONE && printops.min_exp != EXP_NONE && printops.min_exp != EXP_PRECISION && printops.min_exp != EXP_BASE_3 && printops.min_exp != EXP_PURE && printops.min_exp != EXP_SCIENTIFIC) {str += " "; str += i2s(printops.min_exp); str += "*";}
4270 CHECK_IF_SCREEN_FILLED_PUTS(str.c_str());
4271 STR_AND_TABS_BOOL(_("show ending zeroes"), "zeroes", _("If actived, zeroes are kept at the end of approximate numbers."), printops.show_ending_zeroes);
4272 STR_AND_TABS_BOOL(_("two's complement"), "twos", _("Enables two's complement representation for display of negative binary numbers."), printops.twos_complement);
4273
4274 CHECK_IF_SCREEN_FILLED_HEADING_S(_("Parsing"));
4275
4276 STR_AND_TABS_BOOL(_("caret as xor"), "xor^", _("Use ^ as bitwise exclusive OR operator."), caret_as_xor);
4277 STR_AND_TABS_SET(_("decimal comma"), "");
4278 SET_DESCRIPTION(_("Determines the default decimal separator."));
4279 str += "(";
4280 str += _("locale");
4281 if(b_decimal_comma < 0) str += "*";
4282 str += ", "; str += _("off");
4283 if(b_decimal_comma == 0) str += "*";
4284 str += ", "; str += _("on");
4285 if(b_decimal_comma > 0) str += "*";
4286 str += ")";
4287 CHECK_IF_SCREEN_FILLED_PUTS(str.c_str());
4288 if(CALCULATOR->getDecimalPoint() != COMMA) {
4289 STR_AND_TABS_BOOL(_("ignore comma"), "", _("Allows use of ',' as thousands separator."), evalops.parse_options.comma_as_separator);
4290 }
4291 if(CALCULATOR->getDecimalPoint() != DOT) {
4292 STR_AND_TABS_BOOL(_("ignore dot"), "", _("Allows use of '.' as thousands separator."), evalops.parse_options.dot_as_separator);
4293 }
4294 STR_AND_TABS_BOOL(_("imaginary j"), "imgj", _("Use 'j' (instead of 'i') as default symbol for the imaginary unit."), (CALCULATOR->getVariableById(VARIABLE_ID_I)->hasName("j") > 0));
4295 STR_AND_TABS_SET(_("input base"), "inbase"); str += "(-1114112 - 1114112"; str += ", "; str += _("bin");
4296 if(evalops.parse_options.base == BASE_BINARY) str += "*";
4297 str += ", "; str += _("oct");
4298 if(evalops.parse_options.base == BASE_OCTAL) str += "*";
4299 str += ", "; str += _("dec");
4300 if(evalops.parse_options.base == BASE_DECIMAL) str += "*";
4301 str += ", "; str += _("hex");
4302 if(evalops.parse_options.base == BASE_HEXADECIMAL) str += "*";
4303 str += ", "; str += _("roman");
4304 if(evalops.parse_options.base == BASE_ROMAN_NUMERALS) str += "*";
4305 str += ")";
4306 if(evalops.parse_options.base == BASE_CUSTOM) {str += " "; str += CALCULATOR->customInputBase().print(CALCULATOR->messagePrintOptions()); str += "*";}
4307 else if(evalops.parse_options.base == BASE_UNICODE) {str += " "; str += "Unicode"; str += "*";}
4308 else if(evalops.parse_options.base == BASE_GOLDEN_RATIO) {str += " "; str += "golden"; str += "*";}
4309 else if(evalops.parse_options.base == BASE_SUPER_GOLDEN_RATIO) {str += " "; str += "supergolden ratio"; str += "*";}
4310 else if(evalops.parse_options.base == BASE_E) {str += " "; str += "e"; str += "*";}
4311 else if(evalops.parse_options.base == BASE_PI) {str += " "; str += "pi"; str += "*";}
4312 else if(evalops.parse_options.base == BASE_SQRT2) {str += " "; str += "sqrt(2)"; str += "*";}
4313 else if(evalops.parse_options.base > 2 && evalops.parse_options.base != BASE_OCTAL && evalops.parse_options.base != BASE_DECIMAL && evalops.parse_options.base != BASE_HEXADECIMAL) {str += " "; str += i2s(evalops.parse_options.base); str += "*";}
4314 CHECK_IF_SCREEN_FILLED_PUTS(str.c_str());
4315 STR_AND_TABS_BOOL(_("limit implicit multiplication"), "limimpl", "", evalops.parse_options.limit_implicit_multiplication);
4316 STR_AND_TABS_4(_("parsing mode"), "syntax", _("See 'help parsing mode'."), evalops.parse_options.parsing_mode, _("adaptive"), _("implicit first"), _("conventional"), _("chain"), _("rpn"));
4317 STR_AND_TABS_2(_("read precision"), "readprec", _("If activated, numbers be interpreted as approximate with precision equal to the number of significant digits (3.20 = 3.20+/-0.005)."), evalops.parse_options.read_precision, _("off"), _("always"), _("when decimals"))
4318
4319 CHECK_IF_SCREEN_FILLED_HEADING_S(_("Units"));
4320
4321 STR_AND_TABS_BOOL(_("all prefixes"), "allpref", _("Enables automatic use of hecto, deca, deci, and centi."), printops.use_all_prefixes);
4322 STR_AND_TABS_SET(_("autoconversion"), "conv");
4323 SET_DESCRIPTION(_("Controls automatic unit conversion of the result. 'optimalsi' always converts non-SI units, while 'optimal' only converts to more optimal unit expressions, with less units and exponents."));
4324 str += "(";
4325 str += (_("none"));
4326 if(evalops.auto_post_conversion == POST_CONVERSION_NONE && evalops.mixed_units_conversion == MIXED_UNITS_CONVERSION_NONE) str += "*";
4327 str += ", "; str += _("optimal");
4328 if(evalops.auto_post_conversion == POST_CONVERSION_OPTIMAL) str += "*";
4329 str += ", "; str += _("base");
4330 if(evalops.auto_post_conversion == POST_CONVERSION_BASE) str += "*";
4331 str += ", "; str += _("optimalsi");
4332 if(evalops.auto_post_conversion == POST_CONVERSION_OPTIMAL_SI) str += "*";
4333 str += ", "; str += _("mixed");
4334 if(evalops.auto_post_conversion == POST_CONVERSION_NONE && evalops.mixed_units_conversion > MIXED_UNITS_CONVERSION_NONE) str += "*";
4335 str += ")";
4336 CHECK_IF_SCREEN_FILLED_PUTS(str.c_str());
4337 STR_AND_TABS_BOOL(_("binary prefixes"), "binpref", _("If activated, binary prefixes are used by default for information units."), (CALCULATOR->usesBinaryPrefixes() > 0));
4338 STR_AND_TABS_BOOL(_("currency conversion"), "curconv", _("Enables automatic conversion to the local currency when optimal unit conversion is enabled."), evalops.local_currency_conversion);
4339 STR_AND_TABS_BOOL(_("denominator prefixes"), "denpref", _("Enables automatic use of prefixes in the denominator of unit expressions."), printops.use_denominator_prefix);
4340 STR_AND_TABS_BOOL(_("place units separately"), "unitsep", _("If activated, units are separated from variables at the end of the result."), printops.place_units_separately);
4341 STR_AND_TABS_BOOL(_("prefixes"), "pref", _("Enables automatic use of prefixes in the result."), printops.use_unit_prefixes);
4342 STR_AND_TABS_BOOL(_("show negative exponents"), "negexp", _("Use negative exponents instead of division for units in result (m/s = m*s^-1)."), printops.negative_exponents);
4343 STR_AND_TABS_BOOL(_("sync units"), "sync", "", evalops.sync_units);
4344 STR_AND_TABS_2(_("temperature calculation"), "temp", _("Determines how expressions with temperature units are calculated (hybrid acts as absolute if the expression contains different temperature units, otherwise as relative)."), CALCULATOR->getTemperatureCalculationMode(), _("hybrid"), _("absolute"), _("relative"));
4345 STR_AND_TABS_SET(_("update exchange rates"), "upxrates");
4346 str += "(-1 = "; str += _("ask"); if(auto_update_exchange_rates < 0) str += "*";
4347 str += ", 0 = "; str += _("never"); if(auto_update_exchange_rates == 0) str += "*";
4348 str += ", > 0 = "; str += _("days");
4349 str += ")";
4350 if(auto_update_exchange_rates > 0) {str += " "; str += i2s(auto_update_exchange_rates); str += "*";}
4351 CHECK_IF_SCREEN_FILLED_PUTS(str.c_str());
4352
4353 CHECK_IF_SCREEN_FILLED_HEADING_S(_("Other"));
4354
4355 STR_AND_TABS_YESNO(_("ignore locale"), "", _("Ignore system language and use English (requires restart)."), ignore_locale);
4356 STR_AND_TABS_BOOL(_("rpn"), "", _("Activates the Reverse Polish Notation stack."), rpn_mode);
4357 STR_AND_TABS_YESNO(_("save definitions"), "", _("Save functions, units, and variables on exit."), save_defs_on_exit);
4358 STR_AND_TABS_YESNO(_("save mode"), "", _("Save settings on exit."), save_mode_on_exit);
4359 puts("");
4360 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "assume", _("assume"))) {
4361 puts("");
4362 PUTS_UNICODE(_("Set default assumptions for unknown variables."));
4363 Assumptions *ass = CALCULATOR->defaultAssumptions();
4364 str = "("; str += _("unknown");
4365 if(ass->sign() == ASSUMPTION_SIGN_UNKNOWN) str += "*";
4366 str += ", "; str += _("non-zero");
4367 if(ass->sign() == ASSUMPTION_SIGN_NONZERO) str += "*";
4368 str += ", "; str += _("positive");
4369 if(ass->sign() == ASSUMPTION_SIGN_POSITIVE) str += "*";
4370 str += ", "; str += _("negative");
4371 if(ass->sign() == ASSUMPTION_SIGN_NEGATIVE) str += "*";
4372 str += ", "; str += _("non-positive");
4373 if(ass->sign() == ASSUMPTION_SIGN_NONPOSITIVE) str += "*";
4374 str += ", "; str += _("non-negative");
4375 if(ass->sign() == ASSUMPTION_SIGN_NONNEGATIVE) str += "*";
4376 str += " +\n"; str += _("number");
4377 if(ass->type() == ASSUMPTION_TYPE_NUMBER) str += "*";
4378 str += ", "; str += _("real");
4379 if(ass->type() == ASSUMPTION_TYPE_REAL) str += "*";
4380 str += ", "; str += _("rational");
4381 if(ass->type() == ASSUMPTION_TYPE_RATIONAL) str += "*";
4382 str += ", "; str += _("integer");
4383 if(ass->type() == ASSUMPTION_TYPE_INTEGER) str += "*";
4384 str += ")";
4385 PUTS_UNICODE(str.c_str());
4386 puts("");
4387 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "save", _("save")) || EQUALS_IGNORECASE_AND_LOCAL(str, "store", _("store"))) {
4388 puts("");
4389 PUTS_UNICODE(_("Saves the current result in a variable with the specified name. You may optionally also provide a category (default \"Temporary\") and a title."));
4390 PUTS_UNICODE(_("If name equals \"mode\" or \"definitions\", the current mode and definitions, respectively, will be saved."));
4391 puts("");
4392 PUTS_UNICODE(_("Example: store var1."));
4393 puts("");
4394 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "variable", _("variable"))) {
4395 puts("");
4396 PUTS_UNICODE(_("Create a variables with the specified name and expression."));
4397 puts("");
4398 PUTS_UNICODE(_("Example: variable var1 pi / 2."));
4399 puts("");
4400 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "function", _("function"))) {
4401 puts("");
4402 PUTS_UNICODE(_("Creates a function with the specified name and expression."));
4403 PUTS_UNICODE(_("Use '\\x', '\\y', '\\z', '\\a', etc. for arguments in the expression."));
4404 puts("");
4405 PUTS_UNICODE(_("Example: function func1 5*\\x."));
4406 puts("");
4407 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "delete", _("delete"))) {
4408 puts("");
4409 PUTS_UNICODE(_("Removes the user-defined variable or function with the specified name."));
4410 puts("");
4411 PUTS_UNICODE(_("Example: delete var1."));
4412 puts("");
4413 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "mode", _("mode"))) {
4414 puts("");
4415 PUTS_UNICODE(_("Displays the current mode."));
4416 puts("");
4417 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "list", _("list")) || EQUALS_IGNORECASE_AND_LOCAL(str, "find", _("find"))) {
4418 puts("");
4419 PUTS_UNICODE(_("Displays a list of variables, functions, units, and prefixes."));
4420 PUTS_UNICODE(_("Enter with argument 'currencies', 'functions', 'variables', 'units', or 'prefixes' to show a list of all currencies, functions, variables, units, or prefixes. Enter a search term to find matching variables, functions, units, and/or prefixes. If command is called with no argument all user-definied objects are listed."));
4421 puts("");
4422 PUTS_UNICODE(_("Example: list functions."));
4423 PUTS_UNICODE(_("Example: find dinar."));
4424 PUTS_UNICODE(_("Example: find variables planck."));
4425 puts("");
4426 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "info", _("info"))) {
4427 puts("");
4428 PUTS_UNICODE(_("Displays information about a function, variable, unit, or prefix."));
4429 puts("");
4430 PUTS_UNICODE(_("Example: info sin."));
4431 puts("");
4432 } else if(canfetch && EQUALS_IGNORECASE_AND_LOCAL(str, "exrates", _("exrates"))) {
4433 puts("");
4434 PUTS_UNICODE(_("Downloads current exchange rates from the Internet."));
4435 puts("");
4436 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "rpn", _("rpn"))) {
4437 puts("");
4438 PUTS_UNICODE(_("(De)activates the Reverse Polish Notation stack and syntax."));
4439 puts("");
4440 PUTS_UNICODE(_("\"syntax\" activates only the RPN syntax and \"stack\" enables the RPN stack."));
4441 puts("");
4442 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "clear stack", _("clear stack"))) {
4443 puts("");
4444 PUTS_UNICODE(_("Clears the entire RPN stack."));
4445 puts("");
4446 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "pop", _("pop"))) {
4447 puts("");
4448 PUTS_UNICODE(_("Removes the top of the RPN stack or the value at the specified index."));
4449 puts("");
4450 PUTS_UNICODE(_("Index 1 is the top of stack and negative index values counts from the bottom of the stack."));
4451 puts("");
4452 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "stack", _("stack"))) {
4453 puts("");
4454 PUTS_UNICODE(_("Displays the RPN stack."));
4455 puts("");
4456 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "swap", _("swap"))) {
4457 puts("");
4458 PUTS_UNICODE(_("Swaps position of values on the RPN stack."));
4459 puts("");
4460 FPUTS_UNICODE(_("If no index is specified, the values on the top of the stack (index 1 and index 2) will be swapped and if only one index is specified, the value at this index will be swapped with the top value."), stdout);
4461 fputs(" ", stdout);
4462 PUTS_UNICODE(_("Index 1 is the top of stack and negative index values counts from the bottom of the stack."));
4463 puts("");
4464 PUTS_UNICODE(_("Example: swap 2 4"));
4465 puts("");
4466 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "copy", _("copy"))) {
4467 puts("");
4468 PUTS_UNICODE(_("Duplicates a value on the RPN stack to the top of the stack."));
4469 puts("");
4470 FPUTS_UNICODE(_("If no index is specified, the top of the stack is duplicated."), stdout);
4471 fputs(" ", stdout);
4472 PUTS_UNICODE(_("Index 1 is the top of stack and negative index values counts from the bottom of the stack."));
4473 puts("");
4474 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "rotate", _("rotate"))) {
4475 puts("");
4476 PUTS_UNICODE(_("Rotates the RPN stack up (default) or down."));
4477 puts("");
4478 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "move", _("move"))) {
4479 puts("");
4480 PUTS_UNICODE(_("Changes the position of a value on the RPN stack."));
4481 puts("");
4482 PUTS_UNICODE(_("Index 1 is the top of stack and negative index values counts from the bottom of the stack."));
4483 puts("");
4484 PUTS_UNICODE(_("Example: move 2 4"));
4485 puts("");
4486 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "base", _("base"))) {
4487 puts("");
4488 PUTS_UNICODE(_("Sets the result number base (equivalent to set base)."));
4489 puts("");
4490 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "exact", _("exact"))) {
4491 puts("");
4492 PUTS_UNICODE(_("Equivalent to set approximation exact."));
4493 puts("");
4494 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "approximate", _("approximate"))) {
4495 puts("");
4496 PUTS_UNICODE(_("Equivalent to set approximation try exact."));
4497 puts("");
4498 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "convert", _("convert")) || EQUALS_IGNORECASE_AND_LOCAL(str, "to", _("to")) || str == "->" || str == "→" || (str.length() == 3 && str[0] == '\xe2' && str[1] == '\x9e' && (unsigned char) str[2] >= 0x94 && (unsigned char) str[2] <= 0xbf)) {
4499 INIT_SCREEN_CHECK
4500 CHECK_IF_SCREEN_FILLED_PUTS("");
4501 CHECK_IF_SCREEN_FILLED_PUTS(_("Converts the current result (equivalent to using \"to\" at the end of an expression)."));
4502 CHECK_IF_SCREEN_FILLED_PUTS("");
4503 CHECK_IF_SCREEN_FILLED_PUTS(_("Possible values:"));
4504 CHECK_IF_SCREEN_FILLED_PUTS("");
4505 CHECK_IF_SCREEN_FILLED_PUTS(_("- a unit or unit expression (e.g. meter or km/h)"));
4506 CHECK_IF_SCREEN_FILLED_PUTS(_("prepend with ? to request the optimal prefix"));
4507 CHECK_IF_SCREEN_FILLED_PUTS(_("prepend with b? to request the optimal binary prefix"));
4508 CHECK_IF_SCREEN_FILLED_PUTS(_("prepend with + or - to force/disable use of mixed units"));
4509 CHECK_IF_SCREEN_FILLED_PUTS(_("- a variable or physical constant (e.g. c)"));
4510 CHECK_IF_SCREEN_FILLED_PUTS(_("- base (convert to base units)"));
4511 CHECK_IF_SCREEN_FILLED_PUTS(_("- optimal (convert to optimal unit)"));
4512 CHECK_IF_SCREEN_FILLED_PUTS(_("- mixed (convert to mixed units, e.g. hours + minutes)"));
4513 CHECK_IF_SCREEN_FILLED_PUTS("");
4514 CHECK_IF_SCREEN_FILLED_PUTS(_("- bin / binary (show as binary number)"));
4515 CHECK_IF_SCREEN_FILLED_PUTS(_("- bin# (show as binary number with specified number of bits)"));
4516 CHECK_IF_SCREEN_FILLED_PUTS(_("- oct / octal (show as octal number)"));
4517 CHECK_IF_SCREEN_FILLED_PUTS(_("- duo / duodecimal (show as duodecimal number)"));
4518 CHECK_IF_SCREEN_FILLED_PUTS(_("- hex / hexadecimal (show as hexadecimal number)"));
4519 CHECK_IF_SCREEN_FILLED_PUTS(_("- hex# (show as hexadecimal number with specified number of bits)"));
4520 CHECK_IF_SCREEN_FILLED_PUTS(_("- sex / sexagesimal (show as sexagesimal number)"));
4521 CHECK_IF_SCREEN_FILLED_PUTS(_("- bijective (shown in bijective base-26)"));
4522 CHECK_IF_SCREEN_FILLED_PUTS(_("- fp16, fp32, fp64, fp80, fp128 (show in binary floating-point format)"));
4523 CHECK_IF_SCREEN_FILLED_PUTS(_("- roman (show as roman numerals)"));
4524 CHECK_IF_SCREEN_FILLED_PUTS(_("- time (show in time format)"));
4525 CHECK_IF_SCREEN_FILLED_PUTS(_("- unicode"));
4526 CHECK_IF_SCREEN_FILLED_PUTS(_("- base # (show in specified number base)"));
4527 CHECK_IF_SCREEN_FILLED_PUTS(_("- bases (show as binary, octal, decimal and hexadecimal number)"));
4528 CHECK_IF_SCREEN_FILLED_PUTS("");
4529 CHECK_IF_SCREEN_FILLED_PUTS(_("- rectangular / cartesian (show complex numbers in rectangular form)"));
4530 CHECK_IF_SCREEN_FILLED_PUTS(_("- exponential (show complex numbers in exponential form)"));
4531 CHECK_IF_SCREEN_FILLED_PUTS(_("- polar (show complex numbers in polar form)"));
4532 CHECK_IF_SCREEN_FILLED_PUTS(_("- cis (show complex numbers in cis form)"));
4533 CHECK_IF_SCREEN_FILLED_PUTS(_("- angle / phasor (show complex numbers in angle/phasor notation)"));
4534 CHECK_IF_SCREEN_FILLED_PUTS("");
4535 CHECK_IF_SCREEN_FILLED_PUTS(_("- fraction (show result as mixed fraction)"));
4536 CHECK_IF_SCREEN_FILLED_PUTS(_("- factors (factorize result)"));
4537 CHECK_IF_SCREEN_FILLED_PUTS("");
4538 CHECK_IF_SCREEN_FILLED_PUTS(_("- UTC (show date and time in UTC time zone)"));
4539 CHECK_IF_SCREEN_FILLED_PUTS(_("- UTC+/-hh[:mm] (show date and time in specified time zone)"));
4540 CHECK_IF_SCREEN_FILLED_PUTS(_("- calendars"));
4541 CHECK_IF_SCREEN_FILLED_PUTS("");
4542 CHECK_IF_SCREEN_FILLED_PUTS(_("Example: to ?g"));
4543 CHECK_IF_SCREEN_FILLED_PUTS("");
4544 if(EQUALS_IGNORECASE_AND_LOCAL(str, "to", _("to"))) {
4545 CHECK_IF_SCREEN_FILLED_PUTS(_("This command can also be typed directly at the end of the mathematical expression (e.g. 5 ft + 2 in to meter)."));
4546 CHECK_IF_SCREEN_FILLED_PUTS("");
4547 }
4548 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "quit", _("quit")) || EQUALS_IGNORECASE_AND_LOCAL(str, "exit", _("exit"))) {
4549 puts("");
4550 PUTS_UNICODE(_("Terminates this program."));
4551 puts("");
4552 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "parsing mode", _("parsing mode")) || str == "parse" || str == "syntax") {
4553 puts("");
4554 PUTS_BOLD(_("conventional"));
4555 PUTS_UNICODE(_("Implicit multiplication does not differ from explicit multiplication (\"12/2(1+2) = 12/2*3 = 18\", \"5x/5y = 5*x/5*y = xy\")."));
4556 puts("");
4557 PUTS_BOLD(_("implicit first"));
4558 PUTS_UNICODE(_("Implicit multiplication is parsed before explicit multiplication (\"12/2(1+2) = 12/(2*3) = 2\", \"5x/5y = (5*x)/(5*y) = x/y\")."));
4559 puts("");
4560 PUTS_BOLD(_("adaptive"));
4561 PUTS_UNICODE(_("The default adaptive mode works as the \"implicit first\" mode, unless spaces are found (\"1/5x = 1/(5*x)\", but \"1/5 x = (1/5)*x\"). In the adaptive mode unit expressions are parsed separately (\"5 m/5 m/s = (5*m)/(5*(m/s)) = 1 s\")."));
4562 puts("");
4563 PUTS_UNICODE(_("Function arguments without parentheses are an exception, where implicit multiplication in front of variables and units is parsed first regardless of mode (\"sqrt 2x = sqrt(2x)\")."));
4564 puts("");
4565 PUTS_BOLD(_("rpn"));
4566 PUTS_UNICODE(_("Parse expressions using reverse Polish notation (\"1 2 3+* = 1*(2+3) = 5\")"));
4567 puts("");
4568 PUTS_BOLD(_("chain"));
4569 PUTS_UNICODE(_("Perform operations from left to right, as the immediate execution mode of a traditional calculator (\"1+2*3 = (1+2)*3 = 9\")"));
4570 puts("");
4571 } else {
4572 goto show_info;
4573 }
4574 //qalc command
4575 } else if(EQUALS_IGNORECASE_AND_LOCAL(str, "quit", _("quit")) || EQUALS_IGNORECASE_AND_LOCAL(str, "exit", _("exit"))) {
4576 #ifdef HAVE_LIBREADLINE
4577 if(!cfile) {
4578 free(rlbuffer);
4579 }
4580 #endif
4581 break;
4582 } else if(explicit_command) {
4583 if(!scom.empty() && ((canfetch && EQUALS_IGNORECASE_AND_LOCAL(scom, "exrates", _("exrates"))) || EQUALS_IGNORECASE_AND_LOCAL(scom, "stack", _("stack")) || EQUALS_IGNORECASE_AND_LOCAL(scom, "exact", _("exact")) || EQUALS_IGNORECASE_AND_LOCAL(scom, "approximate", _("approximate")) || str == "approx" || EQUALS_IGNORECASE_AND_LOCAL(scom, "factor", _("factor")) || EQUALS_IGNORECASE_AND_LOCAL(scom, "simplify", _("simplify")) || EQUALS_IGNORECASE_AND_LOCAL(scom, "expand", _("expand")) || EQUALS_IGNORECASE_AND_LOCAL(scom, "mode", _("mode")) || EQUALS_IGNORECASE_AND_LOCAL(scom, "quit", _("quit")) || EQUALS_IGNORECASE_AND_LOCAL(scom, "exit", _("exit")))) {
4584 str = "";
4585 BEGIN_BOLD(str)
4586 str += scom;
4587 END_BOLD(str)
4588 snprintf(buffer, 1000, _("%s does not accept any arguments."), str.c_str());
4589 PUTS_UNICODE(buffer)
4590 } else if(scom.empty() && (EQUALS_IGNORECASE_AND_LOCAL(str, "set", _("set")) || EQUALS_IGNORECASE_AND_LOCAL(str, "save", _("save")) || EQUALS_IGNORECASE_AND_LOCAL(str, "store", _("store")) || EQUALS_IGNORECASE_AND_LOCAL(str, "variable", _("variable")) || EQUALS_IGNORECASE_AND_LOCAL(str, "function", _("function")) || EQUALS_IGNORECASE_AND_LOCAL(str, "delete", _("delete")) || EQUALS_IGNORECASE_AND_LOCAL(str, "assume", _("assume")) || EQUALS_IGNORECASE_AND_LOCAL(str, "base", _("base")) || EQUALS_IGNORECASE_AND_LOCAL(str, "rpn", _("rpn")) || EQUALS_IGNORECASE_AND_LOCAL(str, "move", _("move")) || EQUALS_IGNORECASE_AND_LOCAL(str, "convert", _("convert")) || EQUALS_IGNORECASE_AND_LOCAL(str, "to", _("to")) || EQUALS_IGNORECASE_AND_LOCAL(str, "find", _("find")) || EQUALS_IGNORECASE_AND_LOCAL(str, "info", _("info")))) {
4591 BEGIN_BOLD(scom)
4592 scom += str;
4593 END_BOLD(scom)
4594 snprintf(buffer, 1000, _("%s requires at least one argument."), scom.c_str());
4595 PUTS_UNICODE(buffer)
4596 } else {
4597 PUTS_UNICODE(_("Unknown command."));
4598 }
4599 puts("");
4600 } else {
4601 size_t index = str.find_first_of(ID_WRAPS);
4602 if(index != string::npos) {
4603 printf(_("Illegal character, \'%c\', in expression."), str[index]);
4604 puts("");
4605 } else {
4606 expression_str = str;
4607 execute_expression();
4608 }
4609 }
4610 #ifdef HAVE_LIBREADLINE
4611 if(!cfile) {
4612 for(int i = history_length - 1; i >= 0; i--) {
4613 HIST_ENTRY *hist = history_get(i + history_base);
4614 if(hist && hist->line && strcmp(hist->line, rlbuffer) == 0) {
4615 hist = remove_history(i);
4616 if(hist) free_history_entry(hist);
4617 break;
4618 }
4619 }
4620 add_history(rlbuffer);
4621 free(rlbuffer);
4622 }
4623 #endif
4624 }
4625 if(cfile && cfile != stdin) {
4626 fclose(cfile);
4627 }
4628
4629 handle_exit();
4630
4631 #ifdef _WIN32
4632 if(DO_WIN_FORMAT) SetConsoleMode(hOut, outMode);
4633 #endif
4634
4635 return 0;
4636
4637 }
4638
RPNRegisterAdded(string,int=0)4639 void RPNRegisterAdded(string, int = 0) {}
RPNRegisterRemoved(int)4640 void RPNRegisterRemoved(int) {}
RPNRegisterChanged(string,int)4641 void RPNRegisterChanged(string, int) {}
4642
display_errors(bool goto_input,int cols)4643 bool display_errors(bool goto_input, int cols) {
4644 if(!CALCULATOR->message()) return false;
4645 while(true) {
4646 if(!hide_parse_errors || (CALCULATOR->message()->stage() != MESSAGE_STAGE_PARSING && CALCULATOR->message()->stage() != MESSAGE_STAGE_CONVERSION_PARSING)) {
4647 MessageType mtype = CALCULATOR->message()->type();
4648 string str;
4649 if(goto_input) str += " ";
4650 if(DO_COLOR && mtype == MESSAGE_ERROR) str += (DO_COLOR == 2 ? "\033[0;91m" : "\033[0;31m");
4651 if(DO_COLOR && mtype == MESSAGE_WARNING) str += (DO_COLOR == 2 ? "\033[0;94m" : "\033[0;34m");
4652 if(mtype == MESSAGE_ERROR) {
4653 str += _("error"); str += ": ";
4654 } else if(mtype == MESSAGE_WARNING) {
4655 str += _("warning"); str += ": ";
4656 }
4657 size_t indent = 0;
4658 if(!str.empty()) indent = unicode_length_check(str.c_str());
4659 else if(goto_input) indent = 2;
4660 if(DO_COLOR && (mtype == MESSAGE_ERROR || mtype == MESSAGE_WARNING)) str += "\033[0m";
4661 BEGIN_ITALIC(str)
4662 str += CALCULATOR->message()->message();
4663 END_ITALIC(str)
4664 if(cols) addLineBreaks(str, cols, true, indent, str.length());
4665 PUTS_UNICODE(str.c_str())
4666 }
4667 if(!CALCULATOR->nextMessage()) break;
4668 }
4669 return true;
4670 }
4671
on_abort_display()4672 void on_abort_display() {
4673 CALCULATOR->abort();
4674 }
4675
4676 bool exact_comparison = false;
4677
run()4678 void ViewThread::run() {
4679
4680 while(true) {
4681
4682 void *x = NULL;
4683 if(!read(&x) || !x) break;
4684 MathStructure *mresult = (MathStructure*) x;
4685 x = NULL;
4686 if(!read(&x)) break;
4687 CALCULATOR->startControl();
4688 MathStructure *mparse = (MathStructure*) x;
4689 PrintOptions po;
4690 if(mparse) {
4691 if(!read(&po.is_approximate)) break;
4692 if(!read<bool>(&po.preserve_format)) break;
4693 po.show_ending_zeroes = false;
4694 po.lower_case_e = printops.lower_case_e;
4695 po.lower_case_numbers = printops.lower_case_numbers;
4696 po.base_display = printops.base_display;
4697 po.twos_complement = printops.twos_complement;
4698 po.hexadecimal_twos_complement = printops.hexadecimal_twos_complement;
4699 po.base = evalops.parse_options.base;
4700 po.allow_non_usable = DO_FORMAT;
4701 Number nr_base;
4702 if(po.base == BASE_CUSTOM && (CALCULATOR->usesIntervalArithmetic() || CALCULATOR->customInputBase().isRational()) && (CALCULATOR->customInputBase().isInteger() || !CALCULATOR->customInputBase().isNegative()) && (CALCULATOR->customInputBase() > 1 || CALCULATOR->customInputBase() < -1)) {
4703 nr_base = CALCULATOR->customOutputBase();
4704 CALCULATOR->setCustomOutputBase(CALCULATOR->customInputBase());
4705 } else if(po.base == BASE_CUSTOM || (po.base < BASE_CUSTOM && !CALCULATOR->usesIntervalArithmetic() && po.base != BASE_UNICODE)) {
4706 po.base = 10;
4707 po.min_exp = 6;
4708 po.use_max_decimals = true;
4709 po.max_decimals = 5;
4710 po.preserve_format = false;
4711 }
4712 po.abbreviate_names = false;
4713 po.digit_grouping = printops.digit_grouping;
4714 po.use_unicode_signs = printops.use_unicode_signs;
4715 po.multiplication_sign = printops.multiplication_sign;
4716 po.division_sign = printops.division_sign;
4717 po.short_multiplication = false;
4718 po.excessive_parenthesis = true;
4719 po.improve_division_multipliers = false;
4720 po.restrict_to_parent_precision = false;
4721 po.spell_out_logical_operators = printops.spell_out_logical_operators;
4722 po.interval_display = INTERVAL_DISPLAY_PLUSMINUS;
4723 MathStructure mp(*mparse);
4724 mp.format(po);
4725 parsed_text = mp.print(po, DO_FORMAT, DO_COLOR, TAG_TYPE_TERMINAL);
4726 if(po.use_unicode_signs) gsub(" ", " ", parsed_text);
4727 if(po.base == BASE_CUSTOM) {
4728 CALCULATOR->setCustomOutputBase(nr_base);
4729 }
4730 }
4731
4732 po = printops;
4733
4734 po.allow_non_usable = DO_FORMAT;
4735
4736 print_dual(*mresult, original_expression, mparse ? *mparse : *parsed_mstruct, mstruct_exact, result_text, alt_results, po, evalops, dual_fraction < 0 ? AUTOMATIC_FRACTION_AUTO : (dual_fraction > 0 ? AUTOMATIC_FRACTION_DUAL : AUTOMATIC_FRACTION_OFF), dual_approximation < 0 ? AUTOMATIC_APPROXIMATION_AUTO : (dual_fraction > 0 ? AUTOMATIC_APPROXIMATION_DUAL : AUTOMATIC_APPROXIMATION_OFF), complex_angle_form, &exact_comparison, mparse != NULL, DO_FORMAT, DO_COLOR, TAG_TYPE_TERMINAL);
4737
4738 b_busy = false;
4739 CALCULATOR->stopControl();
4740
4741 }
4742
4743 }
4744
wait_for_key_press(int timeout_ms)4745 static bool wait_for_key_press(int timeout_ms) {
4746 #ifdef _WIN32
4747 return WaitForSingleObject(GetStdHandle(STD_INPUT_HANDLE), timeout_ms) == WAIT_OBJECT_0;
4748 #else
4749 fd_set in_set;
4750 struct timeval timeout;
4751
4752 timeout.tv_sec = 0;
4753 timeout.tv_usec = timeout_ms * 1000;
4754
4755 FD_ZERO(&in_set);
4756 FD_SET(STDIN_FILENO, &in_set);
4757 return select(FD_SETSIZE, &in_set, NULL, NULL, &timeout) > 0;
4758 #endif
4759 }
4760
add_equals(string & strout,bool b_exact,size_t * i_result_u=NULL,size_t * i_result=NULL)4761 void add_equals(string &strout, bool b_exact, size_t *i_result_u = NULL, size_t *i_result = NULL) {
4762 if(b_exact) {
4763 strout += " = ";
4764 if(i_result_u) *i_result_u = unicode_length_check(strout.c_str());
4765 if(i_result) *i_result = strout.length();
4766 } else {
4767 if(printops.use_unicode_signs) {
4768 strout += " " SIGN_ALMOST_EQUAL " ";
4769 if(i_result_u) *i_result_u = unicode_length_check(strout.c_str());
4770 if(i_result) *i_result = strout.length();
4771 } else {
4772 strout += " = ";
4773 if(i_result_u) *i_result_u = unicode_length_check(strout.c_str());
4774 if(i_result) *i_result = strout.length();
4775 strout += _("approx.");
4776 strout += " ";
4777 }
4778 }
4779 }
4780
setResult(Prefix * prefix,bool update_parse,bool goto_input,size_t stack_index,bool register_moved,bool noprint)4781 void setResult(Prefix *prefix, bool update_parse, bool goto_input, size_t stack_index, bool register_moved, bool noprint) {
4782
4783 if(i_maxtime < 0) return;
4784
4785 b_busy = true;
4786
4787 if(!view_thread->running && !view_thread->start()) {b_busy = false; return;}
4788
4789 if(!interactive_mode || cfile) goto_input = false;
4790
4791 string prev_result_text = result_text;
4792 bool prev_approximate = *printops.is_approximate;
4793 result_text = "?";
4794
4795 if(update_parse) {
4796 parsed_text = _("aborted");
4797 }
4798
4799 if(!rpn_mode) stack_index = 0;
4800 if(stack_index != 0) {
4801 update_parse = false;
4802 }
4803 if(register_moved) {
4804 update_parse = false;
4805 }
4806
4807 if(register_moved) {
4808 result_text = _("RPN Register Moved");
4809 }
4810
4811 printops.prefix = prefix;
4812
4813 bool parsed_approx = false;
4814 if(stack_index == 0) {
4815 if(!view_thread->write((void*) mstruct)) {b_busy = false; view_thread->cancel(); return;}
4816 } else {
4817 MathStructure *mreg = CALCULATOR->getRPNRegister(stack_index + 1);
4818 if(!view_thread->write((void*) mreg)) {b_busy = false; view_thread->cancel(); return;}
4819 }
4820 if(update_parse) {
4821 if(adaptive_interval_display) {
4822 if((parsed_mstruct && parsed_mstruct->containsFunctionId(FUNCTION_ID_UNCERTAINTY)) || expression_str.find("+/-") != string::npos || expression_str.find("+/" SIGN_MINUS) != string::npos || expression_str.find("±") != string::npos) printops.interval_display = INTERVAL_DISPLAY_PLUSMINUS;
4823 else if(parsed_mstruct && parsed_mstruct->containsFunctionId(FUNCTION_ID_INTERVAL)) printops.interval_display = INTERVAL_DISPLAY_INTERVAL;
4824 else printops.interval_display = INTERVAL_DISPLAY_SIGNIFICANT_DIGITS;
4825 }
4826 if(!view_thread->write((void *) parsed_mstruct)) {b_busy = false; view_thread->cancel(); return;}
4827 bool *parsed_approx_p = &parsed_approx;
4828 if(!view_thread->write(parsed_approx_p)) {b_busy = false; view_thread->cancel(); return;}
4829 if(!view_thread->write(prev_result_text == _("RPN Operation") ? false : true)) {b_busy = false; view_thread->cancel(); return;}
4830 } else {
4831 if(printops.base != BASE_DECIMAL && dual_approximation <= 0) mstruct_exact.setUndefined();
4832 if(!view_thread->write((void *) NULL)) {b_busy = false; view_thread->cancel(); return;}
4833 }
4834
4835 bool has_printed = false;
4836
4837 if(i_maxtime != 0) {
4838 #ifndef CLOCK_MONOTONIC
4839 struct timeval tv;
4840 gettimeofday(&tv, NULL);
4841 long int i_timeleft = ((long int) t_end.tv_sec - tv.tv_sec) * 1000 + (t_end.tv_usec - tv.tv_usec) / 1000;
4842 #else
4843 struct timespec tv;
4844 clock_gettime(CLOCK_MONOTONIC, &tv);
4845 long int i_timeleft = ((long int) t_end.tv_sec - tv.tv_sec) * 1000 + (t_end.tv_usec - tv.tv_nsec / 1000) / 1000;
4846 #endif
4847 while(b_busy && view_thread->running && i_timeleft > 0) {
4848 sleep_ms(10);
4849 i_timeleft -= 10;
4850 }
4851 if(b_busy && view_thread->running) {
4852 on_abort_display();
4853 i_maxtime = -1;
4854 }
4855 } else {
4856
4857 int i = 0;
4858 while(b_busy && view_thread->running && i < 75) {
4859 sleep_ms(10);
4860 i++;
4861 }
4862 i = 0;
4863
4864 if(b_busy && view_thread->running && !cfile) {
4865 if(!result_only) {
4866 FPUTS_UNICODE(_("Processing (press Enter to abort)"), stdout);
4867 has_printed = true;
4868 fflush(stdout);
4869 }
4870 }
4871 #ifdef HAVE_LIBREADLINE
4872 int c = 0;
4873 #else
4874 char c = 0;
4875 #endif
4876 while(b_busy && view_thread->running) {
4877 if(cfile) {
4878 sleep_ms(100);
4879 } else {
4880 if(wait_for_key_press(100)) {
4881 #ifdef HAVE_LIBREADLINE
4882 if(use_readline) {
4883 c = rl_read_key();
4884 } else {
4885 if(read(STDIN_FILENO, &c, 1) == -1) c = 0;
4886 }
4887 #else
4888 if(read(STDIN_FILENO, &c, 1) == -1) c = 0;
4889 #endif
4890 if(c == '\n' || c == '\r') {
4891 on_abort_display();
4892 has_printed = false;
4893 }
4894 } else {
4895 if(!result_only) {
4896 printf(".");
4897 fflush(stdout);
4898 }
4899 sleep_ms(100);
4900 }
4901 }
4902 }
4903 }
4904
4905 printops.prefix = NULL;
4906
4907 if(noprint) {
4908 return;
4909 }
4910
4911 b_busy = true;
4912
4913 if(has_printed) printf("\n");
4914 if(goto_input) printf("\n");
4915
4916 if(register_moved) {
4917 update_parse = true;
4918 parsed_text = result_text;
4919 }
4920
4921 int cols = 0;
4922
4923 if(goto_input) {
4924 #ifdef HAVE_LIBREADLINE
4925 int rows = 0;
4926 rl_get_screen_size(&rows, &cols);
4927 #else
4928 cols = 80;
4929 #endif
4930 }
4931
4932 if(!result_only) display_errors(goto_input, cols);
4933
4934 if(stack_index != 0) {
4935 RPNRegisterChanged(result_text, stack_index);
4936 } else {
4937 string strout, sextra;
4938 if(goto_input) strout += " ";
4939 size_t i_result = 0, i_result_u = 0, i_result2 = 0, i_result_u2 = 0;
4940 if(!result_only) {
4941 if(mstruct->isComparison() || mstruct->isLogicalAnd() || mstruct->isLogicalOr()) strout += LEFT_PARENTHESIS;
4942 if(update_parse) {
4943 strout += parsed_text;
4944 } else {
4945 strout += prev_result_text;
4946 }
4947 if(mstruct->isComparison() || mstruct->isLogicalAnd() || mstruct->isLogicalOr()) strout += RIGHT_PARENTHESIS;
4948 }
4949 for(size_t i = 0; i < alt_results.size(); i++) {
4950 if(i != 0) add_equals(strout, true);
4951 else if(!result_only) add_equals(strout, update_parse || !prev_approximate, &i_result_u, &i_result);
4952 if(mstruct->isComparison() || mstruct->isLogicalAnd() || mstruct->isLogicalOr()) strout += LEFT_PARENTHESIS;
4953 strout += alt_results[i];
4954 if(mstruct->isComparison() || mstruct->isLogicalAnd() || mstruct->isLogicalOr()) strout += RIGHT_PARENTHESIS;
4955 }
4956 if(!alt_results.empty()) {
4957 if(!result_only && goto_input && i_result_u > (size_t) cols / 2 && unicode_length_check(strout.c_str()) > (size_t) cols) {
4958 strout[i_result - 1] = '\n';
4959 strout.insert(i_result, " ");
4960 i_result_u = 2;
4961 }
4962 add_equals(strout, !(*printops.is_approximate) && !mstruct->isApproximate(), &i_result_u2, &i_result2);
4963 } else if(!result_only) {
4964 add_equals(strout, (update_parse || !prev_approximate) && (exact_comparison || (!(*printops.is_approximate) && !mstruct->isApproximate())), &i_result_u, &i_result);
4965 i_result_u2 = i_result_u;
4966 i_result2 = i_result;
4967 }
4968 if((!result_only || !alt_results.empty()) && (mstruct->isComparison() || mstruct->isLogicalAnd() || (mstruct->isLogicalOr() && !goto_input))) {
4969 strout += LEFT_PARENTHESIS;
4970 strout += result_text.c_str();
4971 strout += RIGHT_PARENTHESIS;
4972 } else {
4973 strout += result_text.c_str();
4974 }
4975 if(goto_input) {
4976 if(!result_only) {
4977 if(i_result_u == 2 && i_result_u != i_result_u2) {
4978 strout[i_result2 - 1] = '\n';
4979 strout.insert(i_result2, " ");
4980 } else if(i_result_u2 > (size_t) cols / 2 && unicode_length_check(strout.c_str()) > (size_t) cols) {
4981 if(i_result != i_result2) {
4982 strout[i_result2 - 1] = '\n';
4983 strout.insert(i_result2, " ");
4984 }
4985 strout[i_result - 1] = '\n';
4986 strout.insert(i_result, " ");
4987 i_result_u = 2;
4988 }
4989 }
4990 addLineBreaks(strout, cols, true, result_only ? 2 : i_result_u, i_result);
4991 strout += "\n";
4992 }
4993 PUTS_UNICODE(strout.c_str());
4994 }
4995
4996 b_busy = false;
4997 }
4998
viewresult(Prefix * prefix=NULL)4999 void viewresult(Prefix *prefix = NULL) {
5000 setResult(prefix);
5001 }
5002
result_display_updated()5003 void result_display_updated() {
5004 update_message_print_options();
5005 if(expression_executed) setResult(NULL, false);
5006 }
result_format_updated()5007 void result_format_updated() {
5008 update_message_print_options();
5009 if(expression_executed) setResult(NULL, false);
5010 }
result_action_executed()5011 void result_action_executed() {
5012 if(expression_executed) {
5013 printops.allow_factorization = (evalops.structuring == STRUCTURING_FACTORIZE);
5014 setResult(NULL, false);
5015 }
5016 }
result_prefix_changed(Prefix * prefix)5017 void result_prefix_changed(Prefix *prefix) {
5018 if(expression_executed) setResult(prefix, false);
5019 }
expression_calculation_updated()5020 void expression_calculation_updated() {
5021 if(expression_executed && !avoid_recalculation && !rpn_mode) {
5022 if(parsed_mstruct) {
5023 for(size_t i = 0; i < 5; i++) {
5024 if(parsed_mstruct->contains(vans[i])) return;
5025 }
5026 }
5027 hide_parse_errors = true;
5028 execute_expression();
5029 hide_parse_errors = false;
5030 }
5031 }
expression_format_updated(bool reparse)5032 void expression_format_updated(bool reparse) {
5033 if(rpn_mode) reparse = false;
5034 if(!reparse && !rpn_mode) {
5035 avoid_recalculation = true;
5036 }
5037 if(expression_executed && reparse) {
5038 if(parsed_mstruct) {
5039 for(size_t i = 0; i < 5; i++) {
5040 if(parsed_mstruct->contains(vans[i])) return;
5041 }
5042 }
5043 execute_expression();
5044 }
5045 }
5046
on_abort_command()5047 void on_abort_command() {
5048 CALCULATOR->abort();
5049 int msecs = 5000;
5050 while(b_busy && msecs > 0) {
5051 sleep_ms(10);
5052 msecs -= 10;
5053 }
5054 if(b_busy) {
5055 command_thread->cancel();
5056 b_busy = false;
5057 CALCULATOR->stopControl();
5058 command_aborted = true;
5059 }
5060 }
5061
run()5062 void CommandThread::run() {
5063
5064 enableAsynchronousCancel();
5065
5066 while(true) {
5067 int command_type = 0;
5068 if(!read(&command_type)) break;
5069 void *x = NULL;
5070 if(!read(&x) || !x) break;
5071 void *x2 = NULL;
5072 if(!read(&x2)) break;
5073 CALCULATOR->startControl();
5074 switch(command_type) {
5075 case COMMAND_FACTORIZE: {
5076 if(!((MathStructure*) x)->integerFactorize()) {
5077 ((MathStructure*) x)->structure(STRUCTURING_FACTORIZE, evalops, true);
5078 }
5079 if(x2 && !((MathStructure*) x2)->integerFactorize()) {
5080 ((MathStructure*) x2)->structure(STRUCTURING_FACTORIZE, evalops, true);
5081 }
5082 break;
5083 }
5084 case COMMAND_EXPAND_PARTIAL_FRACTIONS: {
5085 ((MathStructure*) x)->expandPartialFractions(evalops);
5086 if(x2) ((MathStructure*) x2)->expandPartialFractions(evalops);
5087 break;
5088 }
5089 case COMMAND_EXPAND: {
5090 ((MathStructure*) x)->expand(evalops);
5091 if(x2) ((MathStructure*) x2)->expand(evalops);
5092 break;
5093 }
5094 case COMMAND_EVAL: {
5095 ((MathStructure*) x)->eval(evalops);
5096 if(x2) ((MathStructure*) x2)->eval(evalops);
5097 break;
5098 }
5099 }
5100 b_busy = false;
5101 CALCULATOR->stopControl();
5102
5103 }
5104 }
5105
execute_command(int command_type,bool show_result)5106 void execute_command(int command_type, bool show_result) {
5107
5108 if(i_maxtime < 0) return;
5109
5110 b_busy = true;
5111 command_aborted = false;
5112
5113 if(!command_thread->running && !command_thread->start()) {b_busy = false; return;}
5114
5115 if(!command_thread->write(command_type)) {command_thread->cancel(); b_busy = false; return;}
5116 MathStructure *mfactor = new MathStructure(*mstruct);
5117 MathStructure *mfactor2 = NULL;
5118 if(!mstruct_exact.isUndefined()) mfactor2 = new MathStructure(mstruct_exact);
5119 if(!command_thread->write((void *) mfactor) || !command_thread->write((void *) mfactor2)) {
5120 command_thread->cancel();
5121 mfactor->unref();
5122 if(mfactor2) mfactor2->unref();
5123 b_busy = false;
5124 return;
5125 }
5126
5127 if(i_maxtime != 0) {
5128 #ifndef CLOCK_MONOTONIC
5129 struct timeval tv;
5130 gettimeofday(&tv, NULL);
5131 long int i_timeleft = ((long int) t_end.tv_sec - tv.tv_sec) * 1000 + (t_end.tv_usec - tv.tv_usec) / 1000;
5132 #else
5133 struct timespec tv;
5134 clock_gettime(CLOCK_MONOTONIC, &tv);
5135 long int i_timeleft = ((long int) t_end.tv_sec - tv.tv_sec) * 1000 + (t_end.tv_usec - tv.tv_nsec / 1000) / 1000;
5136 #endif
5137 while(b_busy && command_thread->running && i_timeleft > 0) {
5138 sleep_ms(10);
5139 i_timeleft -= 10;
5140 }
5141 if(b_busy && command_thread->running) {
5142 on_abort_command();
5143 i_maxtime = -1;
5144 printf(_("aborted"));
5145 printf("\n");
5146 }
5147 } else {
5148
5149 int i = 0;
5150 bool has_printed = false;
5151 while(b_busy && command_thread->running && i < 75) {
5152 sleep_ms(10);
5153 i++;
5154 }
5155 i = 0;
5156
5157 if(b_busy && command_thread->running && !cfile) {
5158 if(!result_only) {
5159 switch(command_type) {
5160 case COMMAND_FACTORIZE: {
5161 FPUTS_UNICODE(_("Factorizing (press Enter to abort)"), stdout);
5162 break;
5163 }
5164 case COMMAND_EXPAND_PARTIAL_FRACTIONS: {
5165 FPUTS_UNICODE(_("Expanding partial fractions…"), stdout);
5166 break;
5167 }
5168 case COMMAND_EXPAND: {
5169 FPUTS_UNICODE(_("Expanding (press Enter to abort)"), stdout);
5170 break;
5171 }
5172 case COMMAND_EVAL: {
5173 FPUTS_UNICODE(_("Calculating (press Enter to abort)"), stdout);
5174 break;
5175 }
5176 }
5177 has_printed = true;
5178 fflush(stdout);
5179 }
5180 }
5181 #ifdef HAVE_LIBREADLINE
5182 int c = 0;
5183 #else
5184 char c = 0;
5185 #endif
5186 while(b_busy && command_thread->running) {
5187 if(cfile) {
5188 sleep_ms(100);
5189 } else {
5190 if(wait_for_key_press(100)) {
5191 #ifdef HAVE_LIBREADLINE
5192 if(use_readline) {
5193 c = rl_read_key();
5194 } else {
5195 if(read(STDIN_FILENO, &c, 1) == -1) c = 0;
5196 }
5197 #else
5198 if(read(STDIN_FILENO, &c, 1) == -1) c = 0;
5199 #endif
5200 if(c == '\n' || c == '\r') {
5201 on_abort_command();
5202 }
5203 } else {
5204 if(!result_only) {
5205 printf(".");
5206 fflush(stdout);
5207 }
5208 sleep_ms(100);
5209 }
5210 }
5211 }
5212
5213 if(has_printed) printf("\n");
5214
5215 }
5216
5217 b_busy = false;
5218
5219 if(!command_aborted) {
5220 if(mfactor2) mstruct_exact.set(*mfactor2);
5221 mstruct->unref();
5222 mstruct = mfactor;
5223 switch(command_type) {
5224 case COMMAND_FACTORIZE: {
5225 printops.allow_factorization = true;
5226 break;
5227 }
5228 case COMMAND_EXPAND: {
5229 printops.allow_factorization = false;
5230 break;
5231 }
5232 default: {
5233 printops.allow_factorization = (evalops.structuring == STRUCTURING_FACTORIZE);
5234 }
5235 }
5236 if(show_result) setResult(NULL, false);
5237 }
5238
5239 }
5240
contains_temperature_unit_q(const MathStructure & m)5241 bool contains_temperature_unit_q(const MathStructure &m) {
5242 if(m.isUnit()) {
5243 return m.unit() == CALCULATOR->getUnitById(UNIT_ID_CELSIUS) || m.unit() == CALCULATOR->getUnitById(UNIT_ID_FAHRENHEIT);
5244 }
5245 if(m.isVariable() && m.variable()->isKnown()) {
5246 return contains_temperature_unit_q(((KnownVariable*) m.variable())->get());
5247 }
5248 if(m.isFunction() && m.function()->id() == FUNCTION_ID_STRIP_UNITS) return false;
5249 for(size_t i = 0; i < m.size(); i++) {
5250 if(contains_temperature_unit_q(m[i])) return true;
5251 }
5252 return false;
5253 }
test_ask_tc(MathStructure & m)5254 bool test_ask_tc(MathStructure &m) {
5255 if(tc_set || !contains_temperature_unit_q(m)) return false;
5256 MathStructure *mp = &m;
5257 if(m.isMultiplication() && m.size() == 2 && m[0].isMinusOne()) mp = &m[1];
5258 else if(m.isNegate()) mp = &m[0];
5259 if(mp->isUnit_exp()) return false;
5260 if(mp->isMultiplication() && mp->size() > 0 && mp->last().isUnit_exp()) {
5261 bool b = false;
5262 for(size_t i = 0; i < mp->size() - 1; i++) {
5263 if(contains_temperature_unit_q((*mp)[i])) {b = true; break;}
5264 }
5265 if(!b) return false;
5266 }
5267 return true;
5268 }
ask_tc()5269 bool ask_tc() {
5270 INIT_COLS
5271 string str = _("The expression is ambiguous. Please select temperature calculation mode (the mode can later be changed using \"set temp\" command).");
5272 addLineBreaks(str, cols, true);
5273 PUTS_UNICODE(str.c_str());
5274 puts("");
5275 str = ""; BEGIN_BOLD(str); str += "0 = "; str += _("hybrid"); END_BOLD(str); str += " ("; str += _("default"); str += ")";
5276 PUTS_UNICODE(str.c_str());
5277 string s_eg = "(1 °C + 1 °C ≈ 2 °C, 1 °C + 5 °F ≈ 274 K + 258 K ≈ 532 K, 2 °C − 1 °C = 1 °C, 1 °C − 5 °F = 16 K, 1 °C + 1 K = 2 °C)";
5278 if(!printops.use_unicode_signs) {gsub("°", "o", s_eg); gsub("≈", "=", s_eg);}
5279 addLineBreaks(s_eg, cols, true);
5280 PUTS_ITALIC(s_eg);
5281 puts("");
5282 str = ""; BEGIN_BOLD(str); str += "1 = "; str += _("absolute"); END_BOLD(str);
5283 PUTS_UNICODE(str.c_str());
5284 s_eg = "(1 °C + 1 °C ≈ 274 K + 274 K ≈ 548 K, 1 °C + 5 °F ≈ 274 K + 258 K ≈ 532 K, 2 °C − 1 °C = 1 K, 1 °C − 5 °F = 16 K, 1 °C + 1 K = 2 °C)";
5285 if(!printops.use_unicode_signs) {gsub("°", "o", s_eg); gsub("≈", "=", s_eg);}
5286 addLineBreaks(s_eg, cols, true);
5287 PUTS_ITALIC(s_eg);
5288 puts("");
5289 str = ""; BEGIN_BOLD(str); str += "2 = "; str += _("relative"); END_BOLD(str);
5290 PUTS_UNICODE(str.c_str());
5291 s_eg = "(1 °C + 1 °C = 2 °C, 1 °C + 5 °F = 1 °C + 5 °R ≈ 277 K, 2 °C − 1 °C = 1 °C, 1 °C − 5 °F = 1 °C - 5 °R ≈ −2 °C, 1 °C + 1 K = 2 °C)";
5292 if(!printops.use_unicode_signs) {gsub("°", "o", s_eg); gsub("≈", "=", s_eg);}
5293 addLineBreaks(s_eg, cols, true);
5294 PUTS_ITALIC(s_eg);
5295 puts("");
5296 FPUTS_UNICODE(_("Temperature calculation mode"), stdout);
5297 tc_set = true;
5298 while(true) {
5299 #ifdef HAVE_LIBREADLINE
5300 char *rlbuffer = readline(": ");
5301 if(!rlbuffer) return false;
5302 string svalue = rlbuffer;
5303 free(rlbuffer);
5304 #else
5305 fputs(": ", stdout);
5306 if(!fgets(buffer, 1000, stdin)) return false;
5307 string svalue = buffer;
5308 #endif
5309 remove_blank_ends(svalue);
5310 int v = -1;
5311 if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "relative", _("relative"))) v = TEMPERATURE_CALCULATION_RELATIVE;
5312 else if(svalue.empty() || EQUALS_IGNORECASE_AND_LOCAL(svalue, "hybrid", _("hybrid"))) v = TEMPERATURE_CALCULATION_HYBRID;
5313 else if(EQUALS_IGNORECASE_AND_LOCAL(svalue, "absolute", _("absolute"))) v = TEMPERATURE_CALCULATION_ABSOLUTE;
5314 else if(svalue.find_first_not_of(SPACES NUMBERS) == string::npos) {
5315 v = s2i(svalue);
5316 }
5317 if(v >= 0 && v <= 2) {
5318 if(v != CALCULATOR->getTemperatureCalculationMode()) {
5319 CALCULATOR->setTemperatureCalculationMode((TemperatureCalculationMode) v);
5320 return true;
5321 }
5322 break;
5323 } else {
5324 FPUTS_UNICODE(_("Temperature calculation mode"), stdout);
5325 }
5326 }
5327 return false;
5328 }
5329
5330
execute_expression(bool goto_input,bool do_mathoperation,MathOperation op,MathFunction * f,bool do_stack,size_t stack_index,bool check_exrates)5331 void execute_expression(bool goto_input, bool do_mathoperation, MathOperation op, MathFunction *f, bool do_stack, size_t stack_index, bool check_exrates) {
5332
5333 if(i_maxtime < 0) return;
5334
5335 string str, str_conv;
5336 bool do_bases = programmers_mode, do_factors = false, do_expand = false, do_pfe = false, do_calendars = false, do_binary_prefixes = false;
5337 avoid_recalculation = false;
5338 if(!interactive_mode) goto_input = false;
5339
5340 int save_base = printops.base;
5341 bool save_pre = printops.use_unit_prefixes;
5342 bool save_cur = printops.use_prefixes_for_currencies;
5343 bool save_den = printops.use_denominator_prefix;
5344 bool save_allu = printops.use_prefixes_for_all_units;
5345 bool save_all = printops.use_all_prefixes;
5346 int save_bin = CALCULATOR->usesBinaryPrefixes();
5347 ComplexNumberForm save_complex_number_form = evalops.complex_number_form;
5348 bool caf_bak = complex_angle_form;
5349 bool b_units_saved = evalops.parse_options.units_enabled;
5350 AutoPostConversion save_auto_post_conversion = evalops.auto_post_conversion;
5351 MixedUnitsConversion save_mixed_units_conversion = evalops.mixed_units_conversion;
5352 NumberFractionFormat save_format = printops.number_fraction_format;
5353 bool save_rfl = printops.restrict_fraction_length;
5354 Number save_cbase;
5355 bool custom_base_set = false;
5356 bool had_to_expression = false;
5357
5358 if(do_stack) {
5359 } else {
5360 str = expression_str;
5361 string to_str = CALCULATOR->parseComments(str, evalops.parse_options);
5362 if(!to_str.empty() && str.empty()) return;
5363 string from_str = str;
5364 if(CALCULATOR->separateToExpression(from_str, to_str, evalops, true)) {
5365 had_to_expression = true;
5366 remove_duplicate_blanks(to_str);
5367 string str_left;
5368 string to_str1, to_str2;
5369 while(true) {
5370 CALCULATOR->separateToExpression(to_str, str_left, evalops, true);
5371 remove_blank_ends(to_str);
5372 size_t ispace = to_str.find_first_of(SPACES);
5373 if(ispace != string::npos) {
5374 to_str1 = to_str.substr(0, ispace);
5375 remove_blank_ends(to_str1);
5376 to_str2 = to_str.substr(ispace + 1);
5377 remove_blank_ends(to_str2);
5378 }
5379 if(equalsIgnoreCase(to_str, "hex") || EQUALS_IGNORECASE_AND_LOCAL(to_str, "hexadecimal", _("hexadecimal"))) {
5380 printops.base = BASE_HEXADECIMAL;
5381 } else if(equalsIgnoreCase(to_str, "bin") || EQUALS_IGNORECASE_AND_LOCAL(to_str, "binary", _("binary"))) {
5382 printops.base = BASE_BINARY;
5383 } else if(equalsIgnoreCase(to_str, "dec") || EQUALS_IGNORECASE_AND_LOCAL(to_str, "decimal", _("decimal"))) {
5384 printops.base = BASE_DECIMAL;
5385 } else if(equalsIgnoreCase(to_str, "oct") || EQUALS_IGNORECASE_AND_LOCAL(to_str, "octal", _("octal"))) {
5386 printops.base = BASE_OCTAL;
5387 } else if(equalsIgnoreCase(to_str, "duo") || EQUALS_IGNORECASE_AND_LOCAL(to_str, "duodecimal", _("duodecimal"))) {
5388 printops.base = BASE_DUODECIMAL;
5389 } else if(equalsIgnoreCase(to_str, "roman") || equalsIgnoreCase(to_str, _("roman"))) {
5390 printops.base = BASE_ROMAN_NUMERALS;
5391 } else if(equalsIgnoreCase(to_str, "bijective") || equalsIgnoreCase(to_str, _("bijective"))) {
5392 printops.base = BASE_BIJECTIVE_26;
5393 } else if(equalsIgnoreCase(to_str, "sexa") || equalsIgnoreCase(to_str, "sexagesimal") || equalsIgnoreCase(to_str, _("sexagesimal"))) {
5394 printops.base = BASE_SEXAGESIMAL;
5395 } else if(equalsIgnoreCase(to_str, "fp32") || equalsIgnoreCase(to_str, "binary32") || equalsIgnoreCase(to_str, "float")) {
5396 printops.base = BASE_FP32;
5397 } else if(equalsIgnoreCase(to_str, "fp64") || equalsIgnoreCase(to_str, "binary64") || equalsIgnoreCase(to_str, "double")) {
5398 printops.base = BASE_FP64;
5399 } else if(equalsIgnoreCase(to_str, "fp16") || equalsIgnoreCase(to_str, "binary16")) {
5400 printops.base = BASE_FP16;
5401 } else if(equalsIgnoreCase(to_str, "fp80")) {
5402 printops.base = BASE_FP80;
5403 } else if(equalsIgnoreCase(to_str, "fp128") || equalsIgnoreCase(to_str, "binary128")) {
5404 printops.base = BASE_FP128;
5405 } else if(equalsIgnoreCase(to_str, "time") || equalsIgnoreCase(to_str, _("time"))) {
5406 printops.base = BASE_TIME;
5407 } else if(equalsIgnoreCase(str, "unicode")) {
5408 printops.base = BASE_UNICODE;
5409 } else if(equalsIgnoreCase(to_str, "utc") || equalsIgnoreCase(to_str, "gmt")) {
5410 printops.time_zone = TIME_ZONE_UTC;
5411 } else if(to_str.length() > 3 && equalsIgnoreCase(to_str.substr(0, 3), "bin") && is_in(NUMBERS, to_str[3])) {
5412 printops.base = BASE_BINARY;
5413 printops.binary_bits = s2i(to_str.substr(3));
5414 } else if(to_str.length() > 3 && equalsIgnoreCase(to_str.substr(0, 3), "hex") && is_in(NUMBERS, to_str[3])) {
5415 printops.base = BASE_HEXADECIMAL;
5416 printops.binary_bits = s2i(to_str.substr(3));
5417 } else if(to_str.length() > 3 && (equalsIgnoreCase(to_str.substr(0, 3), "utc") || equalsIgnoreCase(to_str.substr(0, 3), "gmt"))) {
5418 to_str = to_str.substr(3);
5419 remove_blanks(to_str);
5420 bool b_minus = false;
5421 if(to_str[0] == '+') {
5422 to_str.erase(0, 1);
5423 } else if(to_str[0] == '-') {
5424 b_minus = true;
5425 to_str.erase(0, 1);
5426 } else if(to_str.find(SIGN_MINUS) == 0) {
5427 b_minus = true;
5428 to_str.erase(0, strlen(SIGN_MINUS));
5429 }
5430 unsigned int tzh = 0, tzm = 0;
5431 int itz = 0;
5432 if(!to_str.empty() && sscanf(to_str.c_str(), "%2u:%2u", &tzh, &tzm) > 0) {
5433 itz = tzh * 60 + tzm;
5434 if(b_minus) itz = -itz;
5435 } else {
5436 CALCULATOR->error(true, _("Time zone parsing failed."), NULL);
5437 }
5438 printops.time_zone = TIME_ZONE_CUSTOM;
5439 printops.custom_time_zone = itz;
5440 } else if(to_str == "CET") {
5441 printops.time_zone = TIME_ZONE_CUSTOM;
5442 printops.custom_time_zone = 60;
5443 } else if(EQUALS_IGNORECASE_AND_LOCAL(to_str, "fraction", _("fraction")) || to_str == "frac") {
5444 printops.restrict_fraction_length = false;
5445 printops.number_fraction_format = FRACTION_COMBINED;
5446 } else if(EQUALS_IGNORECASE_AND_LOCAL(to_str, "factors", _("factors")) || to_str == "factor") {
5447 do_factors = true;
5448 } else if(equalsIgnoreCase(to_str, "partial fraction") || equalsIgnoreCase(to_str, _("partial fraction")) || to_str == "partial") {
5449 do_pfe = true;
5450 } else if(EQUALS_IGNORECASE_AND_LOCAL(to_str, "bases", _("bases"))) {
5451 do_bases = true;
5452 } else if(EQUALS_IGNORECASE_AND_LOCAL(to_str, "calendars", _("calendars"))) {
5453 do_calendars = true;
5454 } else if(EQUALS_IGNORECASE_AND_LOCAL(to_str, "rectangular", _("rectangular")) || EQUALS_IGNORECASE_AND_LOCAL(to_str, "cartesian", _("cartesian")) || to_str == "rect") {
5455 complex_angle_form = false;
5456 evalops.complex_number_form = COMPLEX_NUMBER_FORM_RECTANGULAR;
5457 } else if(EQUALS_IGNORECASE_AND_LOCAL(to_str, "exponential", _("exponential")) || to_str == "exp") {
5458 complex_angle_form = false;
5459 evalops.complex_number_form = COMPLEX_NUMBER_FORM_EXPONENTIAL;
5460 } else if(EQUALS_IGNORECASE_AND_LOCAL(to_str, "polar", _("polar"))) {
5461 complex_angle_form = false;
5462 evalops.complex_number_form = COMPLEX_NUMBER_FORM_POLAR;
5463 } else if(EQUALS_IGNORECASE_AND_LOCAL(to_str, "angle", _("angle")) || EQUALS_IGNORECASE_AND_LOCAL(to_str, "phasor", _("phasor"))) {
5464 complex_angle_form = true;
5465 evalops.complex_number_form = COMPLEX_NUMBER_FORM_CIS;
5466 } else if(to_str == "cis") {
5467 complex_angle_form = false;
5468 evalops.complex_number_form = COMPLEX_NUMBER_FORM_CIS;
5469 } else if(EQUALS_IGNORECASE_AND_LOCAL(to_str, "optimal", _("optimal"))) {
5470 evalops.parse_options.units_enabled = true;
5471 evalops.auto_post_conversion = POST_CONVERSION_OPTIMAL_SI;
5472 str_conv = "";
5473 } else if(EQUALS_IGNORECASE_AND_LOCAL(to_str, "base", _("base"))) {
5474 evalops.parse_options.units_enabled = true;
5475 evalops.auto_post_conversion = POST_CONVERSION_BASE;
5476 str_conv = "";
5477 } else if(EQUALS_IGNORECASE_AND_LOCAL(to_str1, "base", _("base"))) {
5478 if(to_str2 == "b26" || to_str2 == "B26") printops.base = BASE_BIJECTIVE_26;
5479 else if(equalsIgnoreCase(to_str2, "golden") || equalsIgnoreCase(to_str2, "golden ratio") || to_str2 == "φ") printops.base = BASE_GOLDEN_RATIO;
5480 else if(equalsIgnoreCase(to_str2, "unicode")) printops.base = BASE_UNICODE;
5481 else if(equalsIgnoreCase(to_str2, "supergolden") || equalsIgnoreCase(to_str2, "supergolden ratio") || to_str2 == "ψ") printops.base = BASE_SUPER_GOLDEN_RATIO;
5482 else if(equalsIgnoreCase(to_str2, "pi") || to_str2 == "π") printops.base = BASE_PI;
5483 else if(to_str2 == "e") printops.base = BASE_E;
5484 else if(to_str2 == "sqrt(2)" || to_str2 == "sqrt 2" || to_str2 == "sqrt2" || to_str2 == "√2") printops.base = BASE_SQRT2;
5485 else {
5486 EvaluationOptions eo = evalops;
5487 eo.parse_options.base = 10;
5488 MathStructure m;
5489 eo.approximation = APPROXIMATION_TRY_EXACT;
5490 CALCULATOR->beginTemporaryStopMessages();
5491 CALCULATOR->calculate(&m, CALCULATOR->unlocalizeExpression(to_str2, eo.parse_options), 500, eo);
5492 if(CALCULATOR->endTemporaryStopMessages()) {
5493 printops.base = BASE_CUSTOM;
5494 custom_base_set = true;
5495 save_cbase = CALCULATOR->customOutputBase();
5496 CALCULATOR->setCustomOutputBase(nr_zero);
5497 } else if(m.isInteger() && m.number() >= 2 && m.number() <= 36) {
5498 printops.base = m.number().intValue();
5499 } else {
5500 printops.base = BASE_CUSTOM;
5501 custom_base_set = true;
5502 save_cbase = CALCULATOR->customOutputBase();
5503 CALCULATOR->setCustomOutputBase(m.number());
5504 }
5505 }
5506 } else if(EQUALS_IGNORECASE_AND_LOCAL(to_str, "mixed", _("mixed"))) {
5507 evalops.auto_post_conversion = POST_CONVERSION_NONE;
5508 evalops.mixed_units_conversion = MIXED_UNITS_CONVERSION_FORCE_INTEGER;
5509 } else {
5510 evalops.parse_options.units_enabled = true;
5511 if((to_str[0] == '?' && (!printops.use_unit_prefixes || !printops.use_prefixes_for_currencies || !printops.use_prefixes_for_all_units)) || (to_str.length() > 1 && to_str[1] == '?' && to_str[0] == 'a' && (!printops.use_unit_prefixes || !printops.use_prefixes_for_currencies || !printops.use_all_prefixes || !printops.use_prefixes_for_all_units)) || (to_str.length() > 1 && to_str[1] == '?' && to_str[0] == 'd' && (!printops.use_unit_prefixes || !printops.use_prefixes_for_currencies || !printops.use_prefixes_for_all_units || CALCULATOR->usesBinaryPrefixes() > 0))) {
5512 printops.use_unit_prefixes = true;
5513 printops.use_prefixes_for_currencies = true;
5514 printops.use_prefixes_for_all_units = true;
5515 if(to_str[0] == 'a') printops.use_all_prefixes = true;
5516 else if(to_str[0] == 'd') CALCULATOR->useBinaryPrefixes(0);
5517 } else if(to_str.length() > 1 && to_str[1] == '?' && to_str[0] == 'b') {
5518 do_binary_prefixes = true;
5519 }
5520 if(!str_conv.empty()) str_conv += " to ";
5521 str_conv += to_str;
5522 }
5523 if(str_left.empty()) break;
5524 to_str = str_left;
5525 }
5526 str = from_str;
5527 if(!str_conv.empty()) {
5528 str += " to ";
5529 str += str_conv;
5530 }
5531 }
5532 size_t i = str.find_first_of(SPACES LEFT_PARENTHESIS);
5533 if(i != string::npos) {
5534 to_str = str.substr(0, i);
5535 if(to_str == "factor" || EQUALS_IGNORECASE_AND_LOCAL(to_str, "factorize", _("factorize"))) {
5536 str = str.substr(i + 1);
5537 do_factors = true;
5538 } else if(EQUALS_IGNORECASE_AND_LOCAL(to_str, "expand", _("expand"))) {
5539 str = str.substr(i + 1);
5540 do_expand = true;
5541 }
5542 }
5543 }
5544
5545 if(caret_as_xor) gsub("^", "⊻", str);
5546
5547 expression_executed = true;
5548
5549 b_busy = true;
5550
5551 size_t stack_size = 0;
5552
5553 CALCULATOR->resetExchangeRatesUsed();
5554
5555 MathStructure to_struct;
5556
5557 if(do_stack) {
5558 stack_size = CALCULATOR->RPNStackSize();
5559 CALCULATOR->setRPNRegister(stack_index + 1, CALCULATOR->unlocalizeExpression(str, evalops.parse_options), 0, evalops, parsed_mstruct, NULL);
5560 } else if(rpn_mode) {
5561 stack_size = CALCULATOR->RPNStackSize();
5562 if(do_mathoperation) {
5563 if(f) CALCULATOR->calculateRPN(f, 0, evalops, parsed_mstruct);
5564 else CALCULATOR->calculateRPN(op, 0, evalops, parsed_mstruct);
5565 } else {
5566 string str2 = CALCULATOR->unlocalizeExpression(str, evalops.parse_options);
5567 CALCULATOR->parseSigns(str2);
5568 remove_blank_ends(str2);
5569 if(str2.length() == 1) {
5570 do_mathoperation = true;
5571 switch(str2[0]) {
5572 case '^': {CALCULATOR->calculateRPN(OPERATION_RAISE, 0, evalops, parsed_mstruct); break;}
5573 case '+': {CALCULATOR->calculateRPN(OPERATION_ADD, 0, evalops, parsed_mstruct); break;}
5574 case '-': {CALCULATOR->calculateRPN(OPERATION_SUBTRACT, 0, evalops, parsed_mstruct); break;}
5575 case '*': {CALCULATOR->calculateRPN(OPERATION_MULTIPLY, 0, evalops, parsed_mstruct); break;}
5576 case '/': {CALCULATOR->calculateRPN(OPERATION_DIVIDE, 0, evalops, parsed_mstruct); break;}
5577 case '&': {CALCULATOR->calculateRPN(OPERATION_BITWISE_AND, 0, evalops, parsed_mstruct); break;}
5578 case '|': {CALCULATOR->calculateRPN(OPERATION_BITWISE_OR, 0, evalops, parsed_mstruct); break;}
5579 case '~': {CALCULATOR->calculateRPNBitwiseNot(0, evalops, parsed_mstruct); break;}
5580 case '!': {CALCULATOR->calculateRPN(CALCULATOR->getFunctionById(FUNCTION_ID_FACTORIAL), 0, evalops, parsed_mstruct); break;}
5581 case '>': {CALCULATOR->calculateRPN(OPERATION_GREATER, 0, evalops, parsed_mstruct); break;}
5582 case '<': {CALCULATOR->calculateRPN(OPERATION_LESS, 0, evalops, parsed_mstruct); break;}
5583 case '=': {CALCULATOR->calculateRPN(OPERATION_EQUALS, 0, evalops, parsed_mstruct); break;}
5584 case '\\': {
5585 MathFunction *fdiv = CALCULATOR->getActiveFunction("div");
5586 if(fdiv) {
5587 CALCULATOR->calculateRPN(fdiv, 0, evalops, parsed_mstruct);
5588 break;
5589 }
5590 }
5591 default: {do_mathoperation = false;}
5592 }
5593 } else if(str2.length() == 2) {
5594 if(str2 == "**") {
5595 CALCULATOR->calculateRPN(OPERATION_RAISE, 0, evalops, parsed_mstruct);
5596 do_mathoperation = true;
5597 } else if(str2 == "!!") {
5598 CALCULATOR->calculateRPN(CALCULATOR->getFunctionById(FUNCTION_ID_DOUBLE_FACTORIAL), 0, evalops, parsed_mstruct);
5599 do_mathoperation = true;
5600 } else if(str2 == "!=" || str == "=!" || str == "<>") {
5601 CALCULATOR->calculateRPN(OPERATION_NOT_EQUALS, 0, evalops, parsed_mstruct);
5602 do_mathoperation = true;
5603 } else if(str2 == "<=" || str == "=<") {
5604 CALCULATOR->calculateRPN(OPERATION_EQUALS_LESS, 0, evalops, parsed_mstruct);
5605 do_mathoperation = true;
5606 } else if(str2 == ">=" || str == "=>") {
5607 CALCULATOR->calculateRPN(OPERATION_EQUALS_GREATER, 0, evalops, parsed_mstruct);
5608 do_mathoperation = true;
5609 } else if(str2 == "==") {
5610 CALCULATOR->calculateRPN(OPERATION_EQUALS, 0, evalops, parsed_mstruct);
5611 do_mathoperation = true;
5612 } else if(str2 == "//") {
5613 MathFunction *fdiv = CALCULATOR->getActiveFunction("div");
5614 if(fdiv) {
5615 CALCULATOR->calculateRPN(fdiv, 0, evalops, parsed_mstruct);
5616 do_mathoperation = true;
5617 }
5618 }
5619 } else if(str2.length() == 3) {
5620 if(str2 == "⊻") {
5621 CALCULATOR->calculateRPN(OPERATION_BITWISE_XOR, 0, evalops, parsed_mstruct);
5622 do_mathoperation = true;
5623 }
5624 }
5625 if(!do_mathoperation) {
5626 bool had_nonnum = false, test_function = true;
5627 int in_par = 0;
5628 for(size_t i = 0; i < str2.length(); i++) {
5629 if(is_in(NUMBERS, str2[i])) {
5630 if(!had_nonnum || in_par) {
5631 test_function = false;
5632 break;
5633 }
5634 } else if(str2[i] == '(') {
5635 if(in_par || !had_nonnum) {
5636 test_function = false;
5637 break;
5638 }
5639 in_par = i;
5640 } else if(str2[i] == ')') {
5641 if(i != str2.length() - 1) {
5642 test_function = false;
5643 break;
5644 }
5645 } else if(str2[i] == ' ') {
5646 if(!in_par) {
5647 test_function = false;
5648 break;
5649 }
5650 } else if(is_in(NOT_IN_NAMES, str2[i])) {
5651 test_function = false;
5652 break;
5653 } else {
5654 if(in_par) {
5655 test_function = false;
5656 break;
5657 }
5658 had_nonnum = true;
5659 }
5660 }
5661 f = NULL;
5662 if(test_function) {
5663 if(in_par) f = CALCULATOR->getActiveFunction(str2.substr(0, in_par));
5664 else f = CALCULATOR->getActiveFunction(str2);
5665 }
5666 if(f && f->minargs() > 0) {
5667 do_mathoperation = true;
5668 original_expression = "";
5669 CALCULATOR->calculateRPN(f, 0, evalops, parsed_mstruct);
5670 } else {
5671 original_expression = str2;
5672 CALCULATOR->RPNStackEnter(str2, 0, evalops, parsed_mstruct, NULL);
5673 }
5674 }
5675 }
5676 } else {
5677 original_expression = CALCULATOR->unlocalizeExpression(str, evalops.parse_options);
5678 CALCULATOR->calculate(mstruct, original_expression, 0, evalops, parsed_mstruct, &to_struct);
5679 }
5680
5681 calculation_wait:
5682
5683 int has_printed = 0;
5684
5685 if(i_maxtime != 0) {
5686 #ifndef CLOCK_MONOTONIC
5687 struct timeval tv;
5688 gettimeofday(&tv, NULL);
5689 long int i_timeleft = ((long int) t_end.tv_sec - tv.tv_sec) * 1000 + (t_end.tv_usec - tv.tv_usec) / 1000;
5690 #else
5691 struct timespec tv;
5692 clock_gettime(CLOCK_MONOTONIC, &tv);
5693 long int i_timeleft = ((long int) t_end.tv_sec - tv.tv_sec) * 1000 + (t_end.tv_usec - tv.tv_nsec / 1000) / 1000;
5694 #endif
5695 while(CALCULATOR->busy() && i_timeleft > 0) {
5696 sleep_ms(10);
5697 i_timeleft -= 10;
5698 }
5699 if(CALCULATOR->busy()) {
5700 CALCULATOR->abort();
5701 avoid_recalculation = true;
5702 i_maxtime = -1;
5703 printf(_("aborted"));
5704 printf("\n");
5705 }
5706 } else {
5707
5708 int i = 0;
5709 while(CALCULATOR->busy() && i < 75) {
5710 sleep_ms(10);
5711 i++;
5712 }
5713 i = 0;
5714
5715 if(CALCULATOR->busy() && !cfile) {
5716 if(!result_only) {
5717 FPUTS_UNICODE(_("Calculating (press Enter to abort)"), stdout);
5718 fflush(stdout);
5719 has_printed = 1;
5720 }
5721 }
5722 #ifdef HAVE_LIBREADLINE
5723 int c = 0;
5724 #else
5725 char c = 0;
5726 #endif
5727 while(CALCULATOR->busy()) {
5728 if(cfile) {
5729 sleep_ms(100);
5730 } else {
5731 if(wait_for_key_press(100)) {
5732 #ifdef HAVE_LIBREADLINE
5733 if(use_readline) {
5734 c = rl_read_key();
5735 } else {
5736 if(read(STDIN_FILENO, &c, 1) == -1) c = 0;
5737 }
5738 #else
5739 if(read(STDIN_FILENO, &c, 1) == -1) c = 0;
5740 #endif
5741 if(c == '\n' || c == '\r') {
5742 CALCULATOR->abort();
5743 avoid_recalculation = true;
5744 has_printed = 0;
5745 }
5746 } else {
5747 if(!result_only) {
5748 has_printed++;
5749 printf(".");
5750 fflush(stdout);
5751 }
5752 sleep_ms(100);
5753 }
5754 }
5755 }
5756 }
5757
5758 bool units_changed = false;
5759
5760 if(!avoid_recalculation && !do_mathoperation && !str_conv.empty() && to_struct.containsType(STRUCT_UNIT, true) && !mstruct->containsType(STRUCT_UNIT) && !parsed_mstruct->containsType(STRUCT_UNIT, false, true, true) && !CALCULATOR->hasToExpression(str_conv, false, evalops)) {
5761 to_struct.unformat();
5762 to_struct = CALCULATOR->convertToOptimalUnit(to_struct, evalops, true);
5763 fix_to_struct(to_struct);
5764 if(!to_struct.isZero()) {
5765 mstruct->multiply(to_struct);
5766 PrintOptions po = printops;
5767 po.negative_exponents = false;
5768 to_struct.format(po);
5769 if(to_struct.isMultiplication() && to_struct.size() >= 2) {
5770 if(to_struct[0].isOne()) to_struct.delChild(1, true);
5771 else if(to_struct[1].isOne()) to_struct.delChild(2, true);
5772 }
5773 parsed_mstruct->multiply(to_struct);
5774 to_struct.clear();
5775 CALCULATOR->calculate(mstruct, 0, evalops, CALCULATOR->unlocalizeExpression(str_conv, evalops.parse_options));
5776 int had_printed = has_printed;
5777 if(has_printed) printf("\n");
5778 units_changed = true;
5779 goto calculation_wait;
5780 has_printed += had_printed;
5781 }
5782 }
5783
5784 // Always perform conversion to optimal (SI) unit when the expression is a number multiplied by a unit and input equals output
5785 if(!rpn_mode && !avoid_recalculation && !had_to_expression && ((evalops.approximation == APPROXIMATION_EXACT && evalops.auto_post_conversion != POST_CONVERSION_NONE) || evalops.auto_post_conversion == POST_CONVERSION_OPTIMAL) && parsed_mstruct && mstruct && ((parsed_mstruct->isMultiplication() && parsed_mstruct->size() == 2 && (*parsed_mstruct)[0].isNumber() && (*parsed_mstruct)[1].isUnit_exp() && parsed_mstruct->equals(*mstruct)) || (parsed_mstruct->isNegate() && (*parsed_mstruct)[0].isMultiplication() && (*parsed_mstruct)[0].size() == 2 && (*parsed_mstruct)[0][0].isNumber() && (*parsed_mstruct)[0][1].isUnit_exp() && mstruct->isMultiplication() && mstruct->size() == 2 && (*mstruct)[1] == (*parsed_mstruct)[0][1] && (*mstruct)[0].isNumber() && (*parsed_mstruct)[0][0].number() == -(*mstruct)[0].number()) || (parsed_mstruct->isUnit_exp() && parsed_mstruct->equals(*mstruct)))) {
5786 Unit *u = NULL;
5787 MathStructure *munit = NULL;
5788 if(mstruct->isMultiplication()) munit = &(*mstruct)[1];
5789 else munit = mstruct;
5790 if(munit->isUnit()) u = munit->unit();
5791 else u = (*munit)[0].unit();
5792 if(u && u->isCurrency()) {
5793 if(evalops.local_currency_conversion && CALCULATOR->getLocalCurrency() && u != CALCULATOR->getLocalCurrency()) {
5794 ApproximationMode abak = evalops.approximation;
5795 if(evalops.approximation == APPROXIMATION_EXACT) evalops.approximation = APPROXIMATION_TRY_EXACT;
5796 mstruct->set(CALCULATOR->convertToOptimalUnit(*mstruct, evalops, true));
5797 evalops.approximation = abak;
5798 }
5799 } else if(u && u->subtype() != SUBTYPE_BASE_UNIT && !u->isSIUnit()) {
5800 MathStructure mbak(*mstruct);
5801 if(evalops.auto_post_conversion == POST_CONVERSION_OPTIMAL) {
5802 if(munit->isUnit() && u->referenceName() == "oF") {
5803 u = CALCULATOR->getActiveUnit("oC");
5804 if(u) mstruct->set(CALCULATOR->convert(*mstruct, u, evalops, true, false));
5805 } else {
5806 mstruct->set(CALCULATOR->convertToOptimalUnit(*mstruct, evalops, true));
5807 }
5808 }
5809 if(evalops.approximation == APPROXIMATION_EXACT && (evalops.auto_post_conversion != POST_CONVERSION_OPTIMAL || mstruct->equals(mbak))) {
5810 evalops.approximation = APPROXIMATION_TRY_EXACT;
5811 if(evalops.auto_post_conversion == POST_CONVERSION_BASE) mstruct->set(CALCULATOR->convertToBaseUnits(*mstruct, evalops));
5812 else mstruct->set(CALCULATOR->convertToOptimalUnit(*mstruct, evalops, true));
5813 evalops.approximation = APPROXIMATION_EXACT;
5814 }
5815 }
5816 }
5817
5818 if(rpn_mode && (!do_stack || stack_index == 0)) {
5819 mstruct->unref();
5820 mstruct = CALCULATOR->getRPNRegister(1);
5821 if(!mstruct) mstruct = new MathStructure();
5822 else mstruct->ref();
5823 }
5824
5825 if(!avoid_recalculation && !do_mathoperation && ((ask_questions && test_ask_tc(*parsed_mstruct) && ask_tc()) || (check_exrates && check_exchange_rates()))) {
5826 if(has_printed) printf("\n");
5827 b_busy = false;
5828 execute_expression(goto_input, do_mathoperation, op, f, rpn_mode, do_stack ? stack_index : 0, false);
5829 evalops.auto_post_conversion = save_auto_post_conversion;
5830 evalops.mixed_units_conversion = save_mixed_units_conversion;
5831 evalops.parse_options.units_enabled = b_units_saved;
5832 if(custom_base_set) CALCULATOR->setCustomOutputBase(save_cbase);
5833 evalops.complex_number_form = save_complex_number_form;
5834 complex_angle_form = caf_bak;
5835 printops.custom_time_zone = 0;
5836 printops.time_zone = TIME_ZONE_LOCAL;
5837 printops.binary_bits = 0;
5838 printops.base = save_base;
5839 printops.use_unit_prefixes = save_pre;
5840 printops.use_prefixes_for_currencies = save_cur;
5841 printops.use_prefixes_for_all_units = save_allu;
5842 printops.use_all_prefixes = save_all;
5843 printops.use_denominator_prefix = save_den;
5844 printops.restrict_fraction_length = save_rfl;
5845 printops.number_fraction_format = save_format;
5846 CALCULATOR->useBinaryPrefixes(save_bin);
5847 return;
5848 }
5849
5850 mstruct_exact.setUndefined();
5851
5852 if((!do_calendars || !mstruct->isDateTime()) && (dual_approximation > 0 || printops.base == BASE_DECIMAL) && !do_bases && !avoid_recalculation && !units_changed && i_maxtime >= 0) {
5853 long int i_timeleft = 0;
5854 #ifndef CLOCK_MONOTONIC
5855 if(i_maxtime) {struct timeval tv; gettimeofday(&tv, NULL); i_timeleft = ((long int) t_end.tv_sec - tv.tv_sec) * 1000 + (t_end.tv_usec - tv.tv_usec) / 1000;}
5856 #else
5857 if(i_maxtime) {struct timespec tv; clock_gettime(CLOCK_MONOTONIC, &tv); i_timeleft = ((long int) t_end.tv_sec - tv.tv_sec) * 1000 + (t_end.tv_usec - tv.tv_nsec / 1000) / 1000;}
5858 #endif
5859 if(i_maxtime) {
5860 if(i_timeleft < i_maxtime / 2) i_timeleft = -1;
5861 else i_timeleft -= 10;
5862 } else {
5863 if(has_printed > 10) i_timeleft = -1;
5864 else if(has_printed) i_timeleft = 500;
5865 else i_timeleft = mstruct->containsType(STRUCT_COMPARISON) ? 2000 : 1000;
5866 }
5867 if(i_timeleft > 0) {
5868 calculate_dual_exact(mstruct_exact, mstruct, original_expression, parsed_mstruct, evalops, dual_approximation < 0 ? AUTOMATIC_APPROXIMATION_AUTO : (dual_approximation > 0 ? AUTOMATIC_APPROXIMATION_DUAL : AUTOMATIC_APPROXIMATION_OFF), i_timeleft, 5);
5869 }
5870 if(i_maxtime) {struct timespec tv; clock_gettime(CLOCK_MONOTONIC, &tv); i_timeleft = ((long int) t_end.tv_sec - tv.tv_sec) * 1000 + (t_end.tv_usec - tv.tv_nsec / 1000) / 1000;}
5871 }
5872 if(has_printed) printf("\n");
5873
5874 b_busy = false;
5875
5876 if(do_factors || do_expand || do_pfe) {
5877 if(do_stack && stack_index != 0) {
5878 MathStructure *save_mstruct = mstruct;
5879 mstruct = CALCULATOR->getRPNRegister(stack_index + 1);
5880 execute_command(do_pfe ? COMMAND_EXPAND_PARTIAL_FRACTIONS : (do_expand ? COMMAND_EXPAND : COMMAND_FACTORIZE), false);
5881 mstruct = save_mstruct;
5882 } else {
5883 execute_command(do_pfe ? COMMAND_EXPAND_PARTIAL_FRACTIONS : (do_expand ? COMMAND_EXPAND : COMMAND_FACTORIZE), false);
5884 }
5885 }
5886
5887 //update "ans" variables
5888 if(!do_stack || stack_index == 0) {
5889 MathStructure m4(vans[3]->get());
5890 m4.replace(vans[4], vans[4]->get());
5891 vans[4]->set(m4);
5892 MathStructure m3(vans[2]->get());
5893 m3.replace(vans[3], vans[4]);
5894 vans[3]->set(m3);
5895 MathStructure m2(vans[1]->get());
5896 m2.replace(vans[2], vans[3]);
5897 vans[2]->set(m2);
5898 MathStructure m1(vans[0]->get());
5899 m1.replace(vans[1], vans[2]);
5900 vans[1]->set(m1);
5901 mstruct->replace(vans[0], vans[1]);
5902 vans[0]->set(*mstruct);
5903 }
5904
5905 if(do_stack && stack_index > 0) {
5906 } else if(rpn_mode && do_mathoperation) {
5907 result_text = _("RPN Operation");
5908 } else {
5909 result_text = str;
5910 }
5911 printops.allow_factorization = (evalops.structuring == STRUCTURING_FACTORIZE);
5912 if(rpn_mode && (!do_stack || stack_index == 0)) {
5913 if(CALCULATOR->RPNStackSize() < stack_size) {
5914 RPNRegisterRemoved(1);
5915 } else if(CALCULATOR->RPNStackSize() > stack_size) {
5916 RPNRegisterAdded("");
5917 }
5918 }
5919
5920 if(do_calendars && mstruct->isDateTime()) {
5921 setResult(NULL, (!do_stack || stack_index == 0), false, do_stack ? stack_index : 0, false, true);
5922 if(goto_input) printf("\n");
5923 show_calendars(*mstruct->datetime(), goto_input);
5924 if(goto_input) printf("\n");
5925 } else if(do_bases) {
5926 printops.base = BASE_BINARY;
5927 setResult(NULL, (!do_stack || stack_index == 0), false, do_stack ? stack_index : 0, false, true);
5928 string base_str = result_text;
5929 base_str += " = ";
5930 printops.base = BASE_OCTAL;
5931 setResult(NULL, false, false, do_stack ? stack_index : 0, false, true);
5932 base_str += result_text;
5933 base_str += " = ";
5934 printops.base = BASE_DECIMAL;
5935 setResult(NULL, false, false, do_stack ? stack_index : 0, false, true);
5936 base_str += result_text;
5937 base_str += " = ";
5938 printops.base = BASE_HEXADECIMAL;
5939 setResult(NULL, false, false, do_stack ? stack_index : 0, false, true);
5940 base_str += result_text;
5941 if(has_printed) printf("\n");
5942 if(goto_input) printf("\n");
5943 if(!result_only) {
5944 string prestr = parsed_text;
5945 if(goto_input) prestr.insert(0, " ");
5946 if(!(*printops.is_approximate) && !mstruct->isApproximate()) {
5947 prestr += " = ";
5948 } else {
5949 if(printops.use_unicode_signs) {
5950 prestr += " " SIGN_ALMOST_EQUAL " ";
5951 } else {
5952 prestr += " = ";
5953 prestr += _("approx.");
5954 prestr += " ";
5955 }
5956 }
5957 base_str = prestr + base_str;
5958 }
5959 result_text = base_str;
5960 if(goto_input) {
5961 int cols = 0;
5962 #ifdef HAVE_LIBREADLINE
5963 int rows = 0;
5964 rl_get_screen_size(&rows, &cols);
5965 #else
5966 cols = 80;
5967 #endif
5968 addLineBreaks(base_str, cols, false, 2, base_str.length());
5969 }
5970 PUTS_UNICODE(base_str.c_str());
5971 if(goto_input) printf("\n");
5972 } else {
5973 if(do_binary_prefixes) {
5974 int i = 0;
5975 if(!do_stack || stack_index == 0) i = has_information_unit(*mstruct);
5976 CALCULATOR->useBinaryPrefixes(i > 0 ? 1 : 2);
5977 printops.use_unit_prefixes = true;
5978 if(i == 1) {
5979 printops.use_denominator_prefix = false;
5980 } else if(i > 1) {
5981 printops.use_denominator_prefix = true;
5982 } else {
5983 printops.use_prefixes_for_currencies = true;
5984 printops.use_prefixes_for_all_units = true;
5985 }
5986 }
5987 setResult(NULL, (!do_stack || stack_index == 0), goto_input, do_stack ? stack_index : 0);
5988 }
5989
5990 evalops.auto_post_conversion = save_auto_post_conversion;
5991 evalops.mixed_units_conversion = save_mixed_units_conversion;
5992 evalops.parse_options.units_enabled = b_units_saved;
5993 if(custom_base_set) CALCULATOR->setCustomOutputBase(save_cbase);
5994 evalops.complex_number_form = save_complex_number_form;
5995 complex_angle_form = caf_bak;
5996 printops.custom_time_zone = 0;
5997 printops.time_zone = TIME_ZONE_LOCAL;
5998 printops.binary_bits = 0;
5999 printops.base = save_base;
6000 printops.use_unit_prefixes = save_pre;
6001 printops.use_prefixes_for_currencies = save_cur;
6002 printops.use_prefixes_for_all_units = save_allu;
6003 printops.use_all_prefixes = save_all;
6004 printops.use_denominator_prefix = save_den;
6005 printops.restrict_fraction_length = save_rfl;
6006 printops.number_fraction_format = save_format;
6007 CALCULATOR->useBinaryPrefixes(save_bin);
6008
6009 }
6010
6011 /*
6012 save mode to file
6013 */
save_mode()6014 bool save_mode() {
6015 return save_preferences(true);
6016 }
6017
6018 /*
6019 remember current mode
6020 */
set_saved_mode()6021 void set_saved_mode() {
6022 saved_precision = CALCULATOR->getPrecision();
6023 saved_binary_prefixes = CALCULATOR->usesBinaryPrefixes();
6024 saved_interval = CALCULATOR->usesIntervalArithmetic();
6025 saved_adaptive_interval_display = adaptive_interval_display;
6026 saved_variable_units_enabled = CALCULATOR->variableUnitsEnabled();
6027 saved_printops = printops;
6028 saved_printops.allow_factorization = (evalops.structuring == STRUCTURING_FACTORIZE);
6029 saved_caf = complex_angle_form;
6030 saved_evalops = evalops;
6031 saved_parsing_mode = (evalops.parse_options.parsing_mode == PARSING_MODE_RPN ? nonrpn_parsing_mode : evalops.parse_options.parsing_mode);
6032 saved_rpn_mode = rpn_mode;
6033 saved_caret_as_xor = caret_as_xor;
6034 saved_dual_fraction = dual_fraction;
6035 saved_dual_approximation = dual_approximation;
6036 saved_assumption_type = CALCULATOR->defaultAssumptions()->type();
6037 saved_assumption_sign = CALCULATOR->defaultAssumptions()->sign();
6038 saved_custom_output_base = CALCULATOR->customOutputBase();
6039 saved_custom_input_base = CALCULATOR->customInputBase();
6040 }
6041
6042
load_preferences()6043 void load_preferences() {
6044
6045 printops.is_approximate = new bool(false);
6046 printops.prefix = NULL;
6047 printops.use_min_decimals = false;
6048 printops.use_denominator_prefix = true;
6049 printops.min_decimals = 0;
6050 printops.use_max_decimals = false;
6051 printops.max_decimals = 2;
6052 printops.base = 10;
6053 printops.min_exp = EXP_PRECISION;
6054 printops.negative_exponents = false;
6055 printops.sort_options.minus_last = true;
6056 printops.indicate_infinite_series = false;
6057 printops.show_ending_zeroes = true;
6058 printops.digit_grouping = DIGIT_GROUPING_NONE;
6059 printops.round_halfway_to_even = false;
6060 printops.number_fraction_format = FRACTION_DECIMAL;
6061 printops.restrict_fraction_length = false;
6062 printops.abbreviate_names = true;
6063 #ifdef _WIN32
6064 printops.use_unicode_signs = false;
6065 #else
6066 printops.use_unicode_signs = true;
6067 #endif
6068 printops.use_unit_prefixes = true;
6069 printops.spacious = true;
6070 printops.short_multiplication = true;
6071 printops.limit_implicit_multiplication = false;
6072 printops.place_units_separately = true;
6073 printops.use_all_prefixes = false;
6074 printops.excessive_parenthesis = false;
6075 printops.allow_non_usable = DO_FORMAT;
6076 printops.lower_case_numbers = false;
6077 printops.lower_case_e = false;
6078 printops.base_display = BASE_DISPLAY_NORMAL;
6079 printops.twos_complement = true;
6080 printops.hexadecimal_twos_complement = false;
6081 printops.division_sign = DIVISION_SIGN_SLASH;
6082 printops.multiplication_sign = MULTIPLICATION_SIGN_X;
6083 printops.allow_factorization = false;
6084 printops.spell_out_logical_operators = true;
6085 printops.interval_display = INTERVAL_DISPLAY_SIGNIFICANT_DIGITS;
6086
6087 evalops.parse_options.parsing_mode = PARSING_MODE_ADAPTIVE;
6088 evalops.approximation = APPROXIMATION_TRY_EXACT;
6089 evalops.sync_units = true;
6090 evalops.structuring = STRUCTURING_SIMPLIFY;
6091 evalops.parse_options.unknowns_enabled = false;
6092 evalops.parse_options.read_precision = DONT_READ_PRECISION;
6093 evalops.parse_options.base = BASE_DECIMAL;
6094 evalops.allow_complex = true;
6095 evalops.allow_infinite = true;
6096 evalops.auto_post_conversion = POST_CONVERSION_OPTIMAL;
6097 evalops.assume_denominators_nonzero = true;
6098 evalops.warn_about_denominators_assumed_nonzero = true;
6099 evalops.parse_options.angle_unit = ANGLE_UNIT_RADIANS;
6100 evalops.parse_options.dot_as_separator = CALCULATOR->default_dot_as_separator;
6101 evalops.parse_options.comma_as_separator = false;
6102 evalops.mixed_units_conversion = MIXED_UNITS_CONVERSION_DEFAULT;
6103 evalops.complex_number_form = COMPLEX_NUMBER_FORM_RECTANGULAR;
6104 evalops.local_currency_conversion = true;
6105 evalops.interval_calculation = INTERVAL_CALCULATION_VARIANCE_FORMULA;
6106 b_decimal_comma = -1;
6107
6108 dual_fraction = -1;
6109 dual_approximation = -1;
6110
6111 CALCULATOR->setPrecision(10);
6112
6113 complex_angle_form = false;
6114
6115 ignore_locale = false;
6116
6117 adaptive_interval_display = true;
6118
6119 CALCULATOR->useIntervalArithmetic(true);
6120
6121 CALCULATOR->setTemperatureCalculationMode(TEMPERATURE_CALCULATION_HYBRID);
6122 tc_set = false;
6123
6124 CALCULATOR->useBinaryPrefixes(0);
6125
6126 rpn_mode = false;
6127
6128 save_mode_on_exit = true;
6129 save_defs_on_exit = true;
6130 auto_update_exchange_rates = -1;
6131 first_time = false;
6132
6133 #ifdef _WIN32
6134 colorize = DO_WIN_FORMAT;
6135 #else
6136 colorize = 1;
6137 #endif
6138
6139 FILE *file = NULL;
6140 #ifdef HAVE_LIBREADLINE
6141 string historyfile = buildPath(getLocalDir(), "qalc.history");
6142 string oldhistoryfile;
6143 #endif
6144 string oldfilename;
6145 string filename = buildPath(getLocalDir(), "qalc.cfg");
6146 file = fopen(filename.c_str(), "r");
6147 if(!file) {
6148 #ifndef _WIN32
6149 oldfilename = buildPath(getOldLocalDir(), "qalc.cfg");
6150 file = fopen(oldfilename.c_str(), "r");
6151 #endif
6152 if(!file) {
6153 first_time = true;
6154 save_preferences(true);
6155 update_message_print_options();
6156 return;
6157 }
6158 #ifdef HAVE_LIBREADLINE
6159 # ifndef _WIN32
6160 oldhistoryfile = buildPath(getOldLocalDir(), "qalc.history");
6161 # endif
6162 #endif
6163 makeDir(getLocalDir());
6164 }
6165
6166 #ifdef HAVE_LIBREADLINE
6167 stifle_history(100);
6168 if(!oldhistoryfile.empty()) {
6169 read_history(oldhistoryfile.c_str());
6170 move_file(oldhistoryfile.c_str(), historyfile.c_str());
6171 } else {
6172 read_history(historyfile.c_str());
6173 }
6174 #endif
6175
6176
6177 int version_numbers[] = {3, 17, 0};
6178
6179 if(file) {
6180 char line[10000];
6181 string stmp, svalue, svar;
6182 size_t i;
6183 int v;
6184 while(true) {
6185 if(fgets(line, 10000, file) == NULL) break;
6186 stmp = line;
6187 remove_blank_ends(stmp);
6188 if((i = stmp.find_first_of("=")) != string::npos) {
6189 svar = stmp.substr(0, i);
6190 remove_blank_ends(svar);
6191 svalue = stmp.substr(i + 1, stmp.length() - (i + 1));
6192 remove_blank_ends(svalue);
6193 v = s2i(svalue);
6194 if(svar == "version") {
6195 parse_qalculate_version(svalue, version_numbers);
6196 } else if(svar == "save_mode_on_exit") {
6197 save_mode_on_exit = v;
6198 } else if(svar == "save_definitions_on_exit") {
6199 save_defs_on_exit = v;
6200 } else if(svar == "ignore_locale") {
6201 ignore_locale = v;
6202 } else if(svar == "colorize") {
6203 #ifdef _WIN32
6204 if(version_numbers[0] > 3 || (version_numbers[0] == 3 && (version_numbers[1] > 13 || (version_numbers[1] == 13 && version_numbers[2] > 0))) || !DO_WIN_FORMAT) {
6205 colorize = v;
6206 }
6207 #else
6208 colorize = v;
6209 #endif
6210 } else if(svar == "fetch_exchange_rates_at_startup") {
6211 if(auto_update_exchange_rates < 0 && v) auto_update_exchange_rates = 1;
6212 } else if(svar == "auto_update_exchange_rates") {
6213 auto_update_exchange_rates = v;
6214 } else if(svar == "min_deci") {
6215 printops.min_decimals = v;
6216 } else if(svar == "use_min_deci") {
6217 printops.use_min_decimals = v;
6218 } else if(svar == "max_deci") {
6219 printops.max_decimals = v;
6220 } else if(svar == "use_max_deci") {
6221 printops.use_max_decimals = v;
6222 } else if(svar == "precision") {
6223 if(v == 8 && (version_numbers[0] < 3 || (version_numbers[0] == 3 && version_numbers[1] <= 12))) v = 10;
6224 CALCULATOR->setPrecision(v);
6225 } else if(svar == "interval_arithmetic") {
6226 if(version_numbers[0] >= 3) CALCULATOR->useIntervalArithmetic(v);
6227 } else if(svar == "interval_display") {
6228 if(v == 0) {
6229 adaptive_interval_display = true;
6230 printops.interval_display = INTERVAL_DISPLAY_SIGNIFICANT_DIGITS;
6231 } else {
6232 v--;
6233 if(v >= INTERVAL_DISPLAY_SIGNIFICANT_DIGITS && v <= INTERVAL_DISPLAY_UPPER) {
6234 printops.interval_display = (IntervalDisplay) v;
6235 adaptive_interval_display = false;
6236 }
6237 }
6238 } else if(svar == "min_exp") {
6239 printops.min_exp = v;
6240 } else if(svar == "negative_exponents") {
6241 printops.negative_exponents = v;
6242 } else if(svar == "sort_minus_last") {
6243 printops.sort_options.minus_last = v;
6244 } else if(svar == "spacious") {
6245 printops.spacious = v;
6246 } else if(svar == "excessive_parenthesis") {
6247 printops.excessive_parenthesis = v;
6248 } else if(svar == "short_multiplication") {
6249 printops.short_multiplication = v;
6250 } else if(svar == "limit_implicit_multiplication") {
6251 evalops.parse_options.limit_implicit_multiplication = v;
6252 printops.limit_implicit_multiplication = v;
6253 } else if(svar == "parsing_mode") {
6254 if(v >= PARSING_MODE_ADAPTIVE && v <= PARSING_MODE_RPN) {
6255 if(evalops.parse_options.parsing_mode == PARSING_MODE_RPN && v != PARSING_MODE_RPN) {
6256 nonrpn_parsing_mode = (ParsingMode) v;
6257 } else {
6258 evalops.parse_options.parsing_mode = (ParsingMode) v;
6259 }
6260 }
6261 } else if(svar == "place_units_separately") {
6262 printops.place_units_separately = v;
6263 } else if(svar == "variable_units_enabled") {
6264 CALCULATOR->setVariableUnitsEnabled(v);
6265 } else if(svar == "use_prefixes") {
6266 printops.use_unit_prefixes = v;
6267 } else if(svar == "use_prefixes_for_all_units") {
6268 printops.use_prefixes_for_all_units = v;
6269 } else if(svar == "use_prefixes_for_currencies") {
6270 printops.use_prefixes_for_currencies = v;
6271 } else if(svar == "number_fraction_format") {
6272 if(version_numbers[0] > 3 || (version_numbers[0] == 3 && (version_numbers[1] > 14 || (version_numbers[1] == 14 && version_numbers[2] > 0)))) {
6273 if(v >= FRACTION_DECIMAL && v <= FRACTION_COMBINED) {
6274 printops.number_fraction_format = (NumberFractionFormat) v;
6275 printops.restrict_fraction_length = (v >= FRACTION_FRACTIONAL);
6276 dual_fraction = 0;
6277 } else if(v == FRACTION_COMBINED + 1) {
6278 printops.number_fraction_format = FRACTION_FRACTIONAL;
6279 printops.restrict_fraction_length = false;
6280 dual_fraction = 0;
6281 } else if(v == FRACTION_COMBINED + 2) {
6282 printops.number_fraction_format = FRACTION_DECIMAL;
6283 dual_fraction = 1;
6284 } else if(v < 0) {
6285 printops.number_fraction_format = FRACTION_DECIMAL;
6286 dual_fraction = -1;
6287 }
6288 }
6289 } else if(svar == "complex_number_form") {
6290 if(v == COMPLEX_NUMBER_FORM_CIS + 1) {
6291 evalops.complex_number_form = COMPLEX_NUMBER_FORM_CIS;
6292 complex_angle_form = true;
6293 } else if(v >= COMPLEX_NUMBER_FORM_RECTANGULAR && v <= COMPLEX_NUMBER_FORM_CIS) {
6294 evalops.complex_number_form = (ComplexNumberForm) v;
6295 complex_angle_form = false;
6296 }
6297 } else if(svar == "number_base") {
6298 printops.base = v;
6299 } else if(svar == "custom_number_base") {
6300 CALCULATOR->beginTemporaryStopMessages();
6301 MathStructure m;
6302 CALCULATOR->calculate(&m, svalue, 500);
6303 CALCULATOR->endTemporaryStopMessages();
6304 CALCULATOR->setCustomOutputBase(m.number());
6305 } else if(svar == "number_base_expression") {
6306 evalops.parse_options.base = v;
6307 } else if(svar == "custom_number_base_expression") {
6308 CALCULATOR->beginTemporaryStopMessages();
6309 MathStructure m;
6310 CALCULATOR->calculate(&m, svalue, 500);
6311 CALCULATOR->endTemporaryStopMessages();
6312 CALCULATOR->setCustomInputBase(m.number());
6313 } else if(svar == "read_precision") {
6314 if(v >= DONT_READ_PRECISION && v <= READ_PRECISION_WHEN_DECIMALS) {
6315 evalops.parse_options.read_precision = (ReadPrecisionMode) v;
6316 }
6317 } else if(svar == "assume_denominators_nonzero") {
6318 if(version_numbers[0] == 0 && (version_numbers[1] < 9 || (version_numbers[1] == 9 && version_numbers[2] == 0))) {
6319 v = true;
6320 }
6321 evalops.assume_denominators_nonzero = v;
6322 } else if(svar == "warn_about_denominators_assumed_nonzero") {
6323 evalops.warn_about_denominators_assumed_nonzero = v;
6324 } else if(svar == "structuring") {
6325 if(v >= STRUCTURING_NONE && v <= STRUCTURING_FACTORIZE) {
6326 evalops.structuring = (StructuringMode) v;
6327 printops.allow_factorization = (evalops.structuring == STRUCTURING_FACTORIZE);
6328 }
6329 } else if(svar == "angle_unit") {
6330 if(version_numbers[0] == 0 && (version_numbers[1] < 7 || (version_numbers[1] == 7 && version_numbers[2] == 0))) {
6331 v++;
6332 }
6333 if(v >= ANGLE_UNIT_NONE && v <= ANGLE_UNIT_GRADIANS) {
6334 evalops.parse_options.angle_unit = (AngleUnit) v;
6335 }
6336 } else if(svar == "caret_as_xor") {
6337 caret_as_xor = v;
6338 } else if(svar == "functions_enabled") {
6339 evalops.parse_options.functions_enabled = v;
6340 } else if(svar == "variables_enabled") {
6341 evalops.parse_options.variables_enabled = v;
6342 } else if(svar == "calculate_variables") {
6343 evalops.calculate_variables = v;
6344 } else if(svar == "calculate_functions") {
6345 evalops.calculate_functions = v;
6346 } else if(svar == "sync_units") {
6347 evalops.sync_units = v;
6348 } else if(svar == "temperature_calculation") {
6349 CALCULATOR->setTemperatureCalculationMode((TemperatureCalculationMode) v);
6350 tc_set = true;
6351 } else if(svar == "unknownvariables_enabled") {
6352 evalops.parse_options.unknowns_enabled = v;
6353 } else if(svar == "units_enabled") {
6354 evalops.parse_options.units_enabled = v;
6355 } else if(svar == "allow_complex") {
6356 evalops.allow_complex = v;
6357 } else if(svar == "allow_infinite") {
6358 evalops.allow_infinite = v;
6359 } else if(svar == "use_short_units") {
6360 printops.abbreviate_names = v;
6361 } else if(svar == "abbreviate_names") {
6362 printops.abbreviate_names = v;
6363 } else if(svar == "all_prefixes_enabled") {
6364 printops.use_all_prefixes = v;
6365 } else if(svar == "denominator_prefix_enabled") {
6366 printops.use_denominator_prefix = v;
6367 } else if(svar == "use_binary_prefixes") {
6368 CALCULATOR->useBinaryPrefixes(v);
6369 } else if(svar == "auto_post_conversion") {
6370 if(v >= POST_CONVERSION_NONE && v <= POST_CONVERSION_OPTIMAL) {
6371 evalops.auto_post_conversion = (AutoPostConversion) v;
6372 }
6373 if(v == POST_CONVERSION_NONE && version_numbers[0] == 0 && (version_numbers[1] < 9 || (version_numbers[1] == 9 && version_numbers[2] <= 12))) {
6374 evalops.auto_post_conversion = POST_CONVERSION_OPTIMAL;
6375 }
6376 } else if(svar == "mixed_units_conversion") {
6377 if(v >= MIXED_UNITS_CONVERSION_NONE && v <= MIXED_UNITS_CONVERSION_FORCE_ALL) {
6378 evalops.mixed_units_conversion = (MixedUnitsConversion) v;
6379 }
6380 } else if(svar == "local_currency_conversion") {
6381 evalops.local_currency_conversion = v;
6382 } else if(svar == "use_unicode_signs") {
6383 #ifdef _WIN32
6384 printops.use_unicode_signs = v;
6385 #else
6386 if(version_numbers[0] > 3 || (version_numbers[0] == 3 && version_numbers[1] > 10)) {
6387 printops.use_unicode_signs = v;
6388 }
6389 #endif
6390 } else if(svar == "lower_case_numbers") {
6391 printops.lower_case_numbers = v;
6392 } else if(svar == "lower_case_e") {
6393 printops.lower_case_e = v;
6394 } else if(svar == "imaginary_j") {
6395 do_imaginary_j = v;
6396 } else if(svar == "base_display") {
6397 if(v >= BASE_DISPLAY_NONE && v <= BASE_DISPLAY_ALTERNATIVE) printops.base_display = (BaseDisplay) v;
6398 } else if(svar == "twos_complement") {
6399 printops.twos_complement = v;
6400 } else if(svar == "hexadecimal_twos_complement") {
6401 printops.hexadecimal_twos_complement = v;
6402 } else if(svar == "spell_out_logical_operators") {
6403 printops.spell_out_logical_operators = v;
6404 } else if(svar == "decimal_comma") {
6405 b_decimal_comma = v;
6406 if(v == 0) CALCULATOR->useDecimalPoint(evalops.parse_options.comma_as_separator);
6407 else if(v > 0) CALCULATOR->useDecimalComma();
6408 } else if(svar == "dot_as_separator") {
6409 evalops.parse_options.dot_as_separator = v;
6410 } else if(svar == "comma_as_separator") {
6411 evalops.parse_options.comma_as_separator = v;
6412 if(CALCULATOR->getDecimalPoint() != COMMA) {
6413 CALCULATOR->useDecimalPoint(evalops.parse_options.comma_as_separator);
6414 }
6415 } else if(svar == "multiplication_sign") {
6416 if(version_numbers[0] > 3 || (version_numbers[0] == 3 && version_numbers[1] > 10)) {
6417 if(v >= MULTIPLICATION_SIGN_ASTERISK && v <= MULTIPLICATION_SIGN_ALTDOT) printops.multiplication_sign = (MultiplicationSign) v;
6418 }
6419 } else if(svar == "division_sign") {
6420 if(v >= DIVISION_SIGN_SLASH && v <= DIVISION_SIGN_DIVISION) printops.division_sign = (DivisionSign) v;
6421 } else if(svar == "indicate_infinite_series") {
6422 printops.indicate_infinite_series = v;
6423 } else if(svar == "show_ending_zeroes") {
6424 if(version_numbers[0] > 2 || (version_numbers[0] == 2 && version_numbers[1] >= 9)) printops.show_ending_zeroes = v;
6425 } else if(svar == "digit_grouping") {
6426 if(v >= DIGIT_GROUPING_NONE && v <= DIGIT_GROUPING_LOCALE) {
6427 printops.digit_grouping = (DigitGrouping) v;
6428 }
6429 } else if(svar == "round_halfway_to_even") {
6430 printops.round_halfway_to_even = v;
6431 } else if(svar == "approximation") {
6432 if(version_numbers[0] > 3 || (version_numbers[0] == 3 && (version_numbers[1] > 14 || (version_numbers[1] == 14 && version_numbers[2] > 0)))) {
6433 if(v >= APPROXIMATION_EXACT && v <= APPROXIMATION_APPROXIMATE) {
6434 evalops.approximation = (ApproximationMode) v;
6435 } else if(v == APPROXIMATION_APPROXIMATE + 1) {
6436 evalops.approximation = APPROXIMATION_TRY_EXACT;
6437 dual_approximation = 1;
6438 } else if(v < 0) {
6439 if(v == -2) evalops.approximation = APPROXIMATION_EXACT;
6440 else evalops.approximation = APPROXIMATION_TRY_EXACT;
6441 dual_approximation = -1;
6442 }
6443 }
6444 } else if(svar == "interval_calculation") {
6445 if(v >= INTERVAL_CALCULATION_NONE && v <= INTERVAL_CALCULATION_SIMPLE_INTERVAL_ARITHMETIC) {
6446 evalops.interval_calculation = (IntervalCalculation) v;
6447 }
6448 } else if(svar == "in_rpn_mode") {
6449 rpn_mode = v;
6450 } else if(svar == "rpn_syntax") {
6451 if(v) {
6452 nonrpn_parsing_mode = evalops.parse_options.parsing_mode;
6453 evalops.parse_options.parsing_mode = PARSING_MODE_RPN;
6454 } else {
6455 evalops.parse_options.parsing_mode = nonrpn_parsing_mode;
6456 }
6457 } else if(svar == "default_assumption_type") {
6458 if(v >= ASSUMPTION_TYPE_NONE && v <= ASSUMPTION_TYPE_INTEGER) {
6459 if(v < ASSUMPTION_TYPE_NUMBER && version_numbers[0] < 1) v = ASSUMPTION_TYPE_NUMBER;
6460 if(v == ASSUMPTION_TYPE_COMPLEX && version_numbers[0] < 2) v = ASSUMPTION_TYPE_NUMBER;
6461 CALCULATOR->defaultAssumptions()->setType((AssumptionType) v);
6462 }
6463 } else if(svar == "default_assumption_sign") {
6464 if(v >= ASSUMPTION_SIGN_UNKNOWN && v <= ASSUMPTION_SIGN_NONZERO) {
6465 if(v == ASSUMPTION_SIGN_NONZERO && version_numbers[0] == 0 && (version_numbers[1] < 9 || (version_numbers[1] == 9 && version_numbers[2] == 0))) {
6466 v = ASSUMPTION_SIGN_UNKNOWN;
6467 }
6468 CALCULATOR->defaultAssumptions()->setSign((AssumptionSign) v);
6469 }
6470 }
6471 }
6472 }
6473 fclose(file);
6474 if(!oldfilename.empty()) {
6475 move_file(oldfilename.c_str(), filename.c_str());
6476 }
6477 update_message_print_options();
6478 } else {
6479 first_time = true;
6480 save_preferences(true);
6481 update_message_print_options();
6482 return;
6483 }
6484 //remember start mode for when we save preferences
6485 set_saved_mode();
6486 }
6487
6488 /*
6489 save preferences to ~/.config/qalculate/qalc.cfg
6490 set mode to true to save current calculator mode
6491 */
save_preferences(bool mode)6492 bool save_preferences(bool mode) {
6493 FILE *file = NULL;
6494 makeDir(getLocalDir());
6495 #ifdef HAVE_LIBREADLINE
6496 write_history(buildPath(getLocalDir(), "qalc.history").c_str());
6497 #endif
6498 string filename = buildPath(getLocalDir(), "qalc.cfg");
6499 file = fopen(filename.c_str(), "w+");
6500 if(file == NULL) {
6501 fprintf(stderr, _("Couldn't write preferences to\n%s"), filename.c_str());
6502 return false;
6503 }
6504 fprintf(file, "\n[General]\n");
6505 fprintf(file, "version=%s\n", VERSION);
6506 fprintf(file, "save_mode_on_exit=%i\n", save_mode_on_exit);
6507 fprintf(file, "save_definitions_on_exit=%i\n", save_defs_on_exit);
6508 fprintf(file, "ignore_locale=%i\n", ignore_locale);
6509 fprintf(file, "colorize=%i\n", colorize);
6510 fprintf(file, "auto_update_exchange_rates=%i\n", auto_update_exchange_rates);
6511 fprintf(file, "spacious=%i\n", printops.spacious);
6512 fprintf(file, "excessive_parenthesis=%i\n", printops.excessive_parenthesis);
6513 fprintf(file, "short_multiplication=%i\n", printops.short_multiplication);
6514 fprintf(file, "use_unicode_signs=%i\n", printops.use_unicode_signs);
6515 fprintf(file, "lower_case_numbers=%i\n", printops.lower_case_numbers);
6516 fprintf(file, "lower_case_e=%i\n", printops.lower_case_e);
6517 fprintf(file, "imaginary_j=%i\n", CALCULATOR->getVariableById(VARIABLE_ID_I)->hasName("j") > 0);
6518 fprintf(file, "base_display=%i\n", printops.base_display);
6519 fprintf(file, "twos_complement=%i\n", printops.twos_complement);
6520 fprintf(file, "hexadecimal_twos_complement=%i\n", printops.hexadecimal_twos_complement);
6521 fprintf(file, "spell_out_logical_operators=%i\n", printops.spell_out_logical_operators);
6522 fprintf(file, "digit_grouping=%i\n", printops.digit_grouping);
6523 fprintf(file, "decimal_comma=%i\n", b_decimal_comma);
6524 fprintf(file, "dot_as_separator=%i\n", evalops.parse_options.dot_as_separator);
6525 fprintf(file, "comma_as_separator=%i\n", evalops.parse_options.comma_as_separator);
6526 fprintf(file, "multiplication_sign=%i\n", printops.multiplication_sign);
6527 fprintf(file, "division_sign=%i\n", printops.division_sign);
6528 if(mode) {
6529 int saved_df = 0, saved_da = 0;
6530 if(result_only && dual_fraction == 0) saved_df = saved_dual_fraction;
6531 if(result_only && dual_approximation == 0) saved_da = saved_dual_approximation;
6532 if(programmers_mode) {
6533 int saved_inbase = saved_evalops.parse_options.base;
6534 int saved_outbase = saved_printops.base;
6535 bool saved_caret = saved_caret_as_xor;
6536 set_saved_mode();
6537 saved_evalops.parse_options.base = saved_inbase;
6538 saved_printops.base = saved_outbase;
6539 saved_caret_as_xor = saved_caret;
6540 } else {
6541 set_saved_mode();
6542 }
6543 if(saved_df != 0) saved_dual_fraction = saved_df;
6544 if(saved_da != 0) saved_dual_approximation = saved_da;
6545 }
6546 fprintf(file, "\n[Mode]\n");
6547 fprintf(file, "min_deci=%i\n", saved_printops.min_decimals);
6548 fprintf(file, "use_min_deci=%i\n", saved_printops.use_min_decimals);
6549 fprintf(file, "max_deci=%i\n", saved_printops.max_decimals);
6550 fprintf(file, "use_max_deci=%i\n", saved_printops.use_max_decimals);
6551 fprintf(file, "precision=%i\n", saved_precision);
6552 fprintf(file, "interval_arithmetic=%i\n", saved_interval);
6553 if(saved_adaptive_interval_display) fprintf(file, "interval_display=%i\n", 0);
6554 else fprintf(file, "interval_display=%i\n", saved_printops.interval_display + 1);
6555 fprintf(file, "min_exp=%i\n", saved_printops.min_exp);
6556 fprintf(file, "negative_exponents=%i\n", saved_printops.negative_exponents);
6557 fprintf(file, "sort_minus_last=%i\n", saved_printops.sort_options.minus_last);
6558 if(saved_dual_fraction < 0) fprintf(file, "number_fraction_format=%i\n", -1);
6559 else if(saved_dual_fraction > 0) fprintf(file, "number_fraction_format=%i\n", FRACTION_COMBINED + 2);
6560 else fprintf(file, "number_fraction_format=%i\n", !saved_printops.restrict_fraction_length && saved_printops.number_fraction_format == FRACTION_FRACTIONAL ? FRACTION_COMBINED + 1 : saved_printops.number_fraction_format);
6561 fprintf(file, "complex_number_form=%i\n", (saved_caf && saved_evalops.complex_number_form == COMPLEX_NUMBER_FORM_CIS) ? saved_evalops.complex_number_form + 1 : saved_evalops.complex_number_form);
6562 fprintf(file, "use_prefixes=%i\n", saved_printops.use_unit_prefixes);
6563 fprintf(file, "use_prefixes_for_all_units=%i\n", saved_printops.use_prefixes_for_all_units);
6564 fprintf(file, "use_prefixes_for_currencies=%i\n", saved_printops.use_prefixes_for_currencies);
6565 fprintf(file, "use_binary_prefixes=%i\n", saved_binary_prefixes);
6566 fprintf(file, "abbreviate_names=%i\n", saved_printops.abbreviate_names);
6567 fprintf(file, "all_prefixes_enabled=%i\n", saved_printops.use_all_prefixes);
6568 fprintf(file, "denominator_prefix_enabled=%i\n", saved_printops.use_denominator_prefix);
6569 fprintf(file, "place_units_separately=%i\n", saved_printops.place_units_separately);
6570 fprintf(file, "auto_post_conversion=%i\n", saved_evalops.auto_post_conversion);
6571 fprintf(file, "mixed_units_conversion=%i\n", saved_evalops.mixed_units_conversion);
6572 fprintf(file, "local_currency_conversion=%i\n", saved_evalops.local_currency_conversion);
6573 fprintf(file, "number_base=%i\n", saved_printops.base);
6574 if(saved_printops.base == BASE_CUSTOM) fprintf(file, "custom_number_base=%s\n", saved_custom_output_base.print(CALCULATOR->save_printoptions).c_str());
6575 fprintf(file, "number_base_expression=%i\n", saved_evalops.parse_options.base);
6576 if(saved_evalops.parse_options.base == BASE_CUSTOM) fprintf(file, "custom_number_base_expression=%s\n", saved_custom_input_base.print(CALCULATOR->save_printoptions).c_str());
6577 fprintf(file, "read_precision=%i\n", saved_evalops.parse_options.read_precision);
6578 fprintf(file, "assume_denominators_nonzero=%i\n", saved_evalops.assume_denominators_nonzero);
6579 fprintf(file, "warn_about_denominators_assumed_nonzero=%i\n", saved_evalops.warn_about_denominators_assumed_nonzero);
6580 fprintf(file, "structuring=%i\n", saved_evalops.structuring);
6581 fprintf(file, "angle_unit=%i\n", saved_evalops.parse_options.angle_unit);
6582 fprintf(file, "caret_as_xor=%i\n", saved_caret_as_xor);
6583 fprintf(file, "functions_enabled=%i\n", saved_evalops.parse_options.functions_enabled);
6584 fprintf(file, "variables_enabled=%i\n", saved_evalops.parse_options.variables_enabled);
6585 fprintf(file, "calculate_variables=%i\n", saved_evalops.calculate_variables);
6586 fprintf(file, "calculate_functions=%i\n", saved_evalops.calculate_functions);
6587 fprintf(file, "variable_units_enabled=%i\n", saved_variable_units_enabled);
6588 fprintf(file, "sync_units=%i\n", saved_evalops.sync_units);
6589 if(tc_set) fprintf(file, "temperature_calculation=%i\n", CALCULATOR->getTemperatureCalculationMode());
6590 fprintf(file, "unknownvariables_enabled=%i\n", saved_evalops.parse_options.unknowns_enabled);
6591 fprintf(file, "units_enabled=%i\n", saved_evalops.parse_options.units_enabled);
6592 fprintf(file, "allow_complex=%i\n", saved_evalops.allow_complex);
6593 fprintf(file, "allow_infinite=%i\n", saved_evalops.allow_infinite);
6594 fprintf(file, "indicate_infinite_series=%i\n", saved_printops.indicate_infinite_series);
6595 fprintf(file, "show_ending_zeroes=%i\n", saved_printops.show_ending_zeroes);
6596 fprintf(file, "round_halfway_to_even=%i\n", saved_printops.round_halfway_to_even);
6597 if(saved_dual_approximation < 0) fprintf(file, "approximation=%i\n", saved_evalops.approximation == APPROXIMATION_EXACT ? -2 : -1);
6598 else if(saved_dual_approximation > 0) fprintf(file, "approximation=%i\n", APPROXIMATION_APPROXIMATE + 1);
6599 else fprintf(file, "approximation=%i\n", saved_evalops.approximation);
6600 fprintf(file, "interval_calculation=%i\n", saved_evalops.interval_calculation);
6601 fprintf(file, "in_rpn_mode=%i\n", saved_rpn_mode);
6602 fprintf(file, "rpn_syntax=%i\n", saved_evalops.parse_options.parsing_mode == PARSING_MODE_RPN);
6603 fprintf(file, "limit_implicit_multiplication=%i\n", saved_evalops.parse_options.limit_implicit_multiplication);
6604 fprintf(file, "parsing_mode=%i\n", saved_parsing_mode);
6605 fprintf(file, "default_assumption_type=%i\n", CALCULATOR->defaultAssumptions()->type());
6606 fprintf(file, "default_assumption_sign=%i\n", CALCULATOR->defaultAssumptions()->sign());
6607
6608 fclose(file);
6609 return true;
6610
6611 }
6612
6613 /*
6614 save definitions to ~/.qalculate/qalculate.cfg
6615 the hard work is done in the Calculator class
6616 */
save_defs()6617 bool save_defs() {
6618 if(!CALCULATOR->saveDefinitions()) {
6619 PUTS_UNICODE(_("Couldn't write definitions"));
6620 return false;
6621 }
6622 return true;
6623 }
6624
6625
6626
6627