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