/*
* Mathomatic commands that don't belong anywhere else.
*
* Copyright (C) 1987-2007 George Gesslein II.
*/
#include "includes.h"
#define OPT_MIN_SIZE 7 /* Minimum size of repeated expressions to find in optimize command. */
static int sum_product();
static int complex_func();
static int elim_sub();
#if !LIBRARY
static int edit_sub();
static int find_more();
static int opt_es();
/* Global variables for the optimize command. */
static int opt_en[N_EQUATIONS];
static int last_temp_var = 0;
#endif
/*
* The version command.
*/
int
version_cmd(cp)
char *cp; /* the command line argument */
{
#if LIBRARY
free(result_str);
result_str = strdup(VERSION);
#endif
return version_report();
}
/*
* Report version number, compile flags, and memory usage.
*/
int
version_report()
{
fprintf(gfp, _("Mathomatic version %s, written by George Gesslein II.\nCompile flags used: "), VERSION);
#if __STDC__
fprintf(gfp, "__STDC__ ");
#endif
#if UNIX
fprintf(gfp, "UNIX ");
#endif
#if CYGWIN
fprintf(gfp, "CYGWIN ");
#endif
#if READLINE
fprintf(gfp, "READLINE ");
#endif
#if SILENT
fprintf(gfp, "SILENT ");
#endif
#if LIBRARY
fprintf(gfp, "LIBRARY ");
#endif
#if SECURE
fprintf(gfp, "SECURE ");
#endif
#if TIMEOUT_SECONDS
fprintf(gfp, "TIMEOUT_SECONDS=%d ", TIMEOUT_SECONDS);
#endif
#if I18N
fprintf(gfp, "I18N ");
#endif
fprintf(gfp, _("\nMaximum memory usage: %lld kilobytes\n"), (long long) (N_EQUATIONS + 3LL) * n_tokens * sizeof(token_type) * 2LL / 1000LL);
return true;
}
/*
* The solve command.
*/
int
solve_cmd(cp)
char *cp;
{
int i;
char buf[MAX_CMD_LEN];
if (cur_equation < 0 || cur_equation >= n_equations || n_lhs[cur_equation] <= 0 || n_rhs[cur_equation] <= 0) {
error(_("No current equation."));
return false;
}
i = next_espace();
if (*cp == '\0') {
my_strlcpy(prompt_str, _("Enter variable or 0: "), sizeof(prompt_str));
if ((cp = get_string(buf, sizeof(buf))) == NULL) {
return false;
}
if (!case_sensitive_flag) {
str_tolower(cp);
}
}
if (parse_equation(i, cp)) {
if (n_lhs[i] && n_rhs[i]) {
error(_("Invalid argument."));
} else {
if (solve(i, cur_equation)) {
return return_result(cur_equation);
}
}
}
n_lhs[i] = 0;
n_rhs[i] = 0;
return false;
}
/*
* The sum command.
*/
int
sum_cmd(cp)
char *cp;
{
return sum_product(cp, false);
}
/*
* The product command.
*/
int
product_cmd(cp)
char *cp;
{
return sum_product(cp, true);
}
/*
* Common function for the sum and product commands.
*/
static int
sum_product(cp, product_flag)
char *cp; /* the command line */
int product_flag; /* true for product, otherwise sum */
{
int i;
long v = 0;
double start, end, step = 1.0;
int result_en;
int n, ns;
token_type *dest, *source;
int count_down; /* if true, count down, otherwise count up */
char *cp1, buf[MAX_CMD_LEN];
if (current_not_defined()) {
return false;
}
result_en = next_espace();
if (n_rhs[cur_equation]) {
ns = n_rhs[cur_equation];
source = rhs[cur_equation];
dest = rhs[result_en];
} else {
ns = n_lhs[cur_equation];
source = lhs[cur_equation];
dest = lhs[result_en];
}
if (*cp) {
cp = parse_var2(&v, cp);
if (cp == NULL) {
return false;
}
}
if (no_vars(source, ns, &v)) {
error(_("Current expression contains no variables."));
return false;
}
if (v == 0) {
if (!prompt_var(&v)) {
return false;
}
}
if (!found_var(source, ns, v)) {
error(_("Variable not found."));
return false;
}
if (*cp) {
if (*cp == '=') {
cp1 = skip_space(cp + 1);
} else {
cp1 = cp;
}
} else {
list_var(v, 0);
snprintf(prompt_str, sizeof(prompt_str), "%s = ", var_str);
if ((cp1 = get_string(buf, sizeof(buf))) == NULL)
return false;
}
start = strtod(cp1, &cp);
if (cp1 == cp || fabs(start) >= MAX_K_INTEGER) {
error(_("Invalid number."));
return false;
}
cp = skip_space(cp);
if (strcmp_tospace(cp, "to") == 0) {
cp = skip_param(cp);
}
if (*cp) {
cp1 = cp;
} else {
my_strlcpy(prompt_str, _("To: "), sizeof(prompt_str));
if ((cp1 = get_string(buf, sizeof(buf))) == NULL)
return false;
}
end = strtod(cp1, &cp);
if (cp1 == cp || fabs(end) >= MAX_K_INTEGER) {
error(_("Invalid number."));
return false;
}
cp = skip_space(cp);
if (*cp) {
cp1 = cp;
step = fabs(strtod(cp1, &cp));
if (step <= 0.0 || step >= MAX_K_INTEGER || cp1 == cp) {
error(_("Invalid step."));
return false;
}
}
if (extra_characters(cp))
return false;
count_down = (end < start);
if (fmod(fabs(start - end) / step, 1.0)) {
error(_("Warning: end value not reached."));
}
if (product_flag) {
dest[0] = one_token;
} else {
dest[0] = zero_token;
}
n = 1;
for (; count_down ? (start >= end) : (start <= end); count_down ? (start -= step) : (start += step)) {
if (n + 1 + ns > n_tokens) {
error_huge();
}
blt(tlhs, source, ns * sizeof(token_type));
n_tlhs = ns;
for (i = 0; i < n_tlhs; i += 2) {
if (tlhs[i].kind == VARIABLE && tlhs[i].token.variable == v) {
tlhs[i].kind = CONSTANT;
tlhs[i].token.constant = start;
}
}
for (i = 0; i < n_tlhs; i++) {
tlhs[i].level++;
}
for (i = 0; i < n; i++) {
dest[i].level++;
}
dest[n].kind = OPERATOR;
dest[n].level = 1;
if (product_flag) {
dest[n].token.operatr = TIMES;
} else {
dest[n].token.operatr = PLUS;
}
n++;
blt(&dest[n], tlhs, n_tlhs * sizeof(token_type));
n += n_tlhs;
calc_simp(dest, &n);
}
if (n_rhs[cur_equation]) {
n_rhs[result_en] = n;
blt(lhs[result_en], lhs[cur_equation], n_lhs[cur_equation] * sizeof(token_type));
n_lhs[result_en] = n_lhs[cur_equation];
} else {
n_lhs[result_en] = n;
}
return return_result(result_en);
}
#if !LIBRARY
/*
* This function is for the "optimize" command.
* It finds and substitutes all occurrences of the RHS of "en" in "equation".
* It should be called repeatedly until it returns false.
*/
static int
find_more(equation, np, en)
token_type *equation; /* expression to search */
int *np; /* pointer to length of expression */
int en; /* equation space number */
{
int i, j, k;
int level;
int diff_sign;
int found_se; /* found sub-expression flag */
if (*np <= 0 || !solved_equation(en)) {
return false;
}
for (level = 1, found_se = true; found_se; level++) {
for (i = 1, found_se = false; i < *np; i = j + 2) {
for (j = i; j < *np && equation[j].level >= level; j += 2)
;
if (j == i) {
continue;
}
found_se = true;
k = i - 1;
if (se_compare(&equation[k], j - k, rhs[en], n_rhs[en], &diff_sign)) {
if (diff_sign) {
blt(&equation[i+2], &equation[j], (*np - j) * sizeof(token_type));
*np -= (j - (i + 2));
level++;
equation[k].level = level;
equation[k].kind = CONSTANT;
equation[k].token.constant = -1.0;
k++;
equation[k].level = level;
equation[k].kind = OPERATOR;
equation[k].token.operatr = TIMES;
k++;
} else {
blt(&equation[i], &equation[j], (*np - j) * sizeof(token_type));
*np -= (j - i);
}
equation[k].level = level;
equation[k].kind = VARIABLE;
equation[k].token.variable = lhs[en][0].token.variable;
return true;
}
}
}
return false;
}
/*
* This function is for the "optimize" command.
* It finds and replaces all repeated expressions in "equation" with temporary variables.
* It also creates a new equation for each temporary variable.
* It should be called repeatedly until it returns false.
*/
static int
opt_es(equation, np)
token_type *equation;
int *np;
{
int i, j, k, i1, i2, jj1, k1;
int level, level1;
int diff_sign;
int found_se, found_se1; /* found sub-expression flags */
long v;
char temp_buf[50];
if (*np <= 0) {
return false;
}
for (level = 1, found_se = true; found_se; level++) {
for (i = 1, found_se = false; i < *np; i = j + 2) {
for (j = i; j < *np && equation[j].level > level; j += 2)
;
if (j == i) {
continue;
}
found_se = true;
k = i - 1;
if ((j - k) < OPT_MIN_SIZE) {
continue;
}
found_se1 = true;
for (level1 = 1; found_se1; level1++) {
for (i1 = 1, found_se1 = false; i1 < *np; i1 = jj1 + 2) {
for (jj1 = i1; jj1 < *np && equation[jj1].level > level1; jj1 += 2) {
}
if (jj1 == i1) {
continue;
}
found_se1 = true;
if (i1 <= j)
continue;
k1 = i1 - 1;
if ((jj1 - k1) >= OPT_MIN_SIZE
&& se_compare(&equation[k], j - k, &equation[k1], jj1 - k1, &diff_sign)) {
snprintf(temp_buf, sizeof(temp_buf), "temp%d", last_temp_var);
if (parse_var(&v, temp_buf) == NULL) {
return false; /* can't create "temp" variable */
}
last_temp_var++;
if (last_temp_var < 0) {
last_temp_var = 0;
}
i2 = next_espace();
lhs[i2][0].level = 1;
lhs[i2][0].kind = VARIABLE;
lhs[i2][0].token.variable = v;
n_lhs[i2] = 1;
blt(rhs[i2], &equation[k], (j - k) * sizeof(token_type));
n_rhs[i2] = j - k;
if (diff_sign) {
blt(&equation[i1+2], &equation[jj1], (*np - jj1) * sizeof(token_type));
*np -= (jj1 - (i1 + 2));
level1++;
equation[k1].level = level1;
equation[k1].kind = CONSTANT;
equation[k1].token.constant = -1.0;
k1++;
equation[k1].level = level1;
equation[k1].kind = OPERATOR;
equation[k1].token.operatr = TIMES;
k1++;
} else {
blt(&equation[i1], &equation[jj1], (*np - jj1) * sizeof(token_type));
*np -= (jj1 - i1);
}
equation[k1].level = level1;
equation[k1].kind = VARIABLE;
equation[k1].token.variable = v;
blt(&equation[i], &equation[j], (*np - j) * sizeof(token_type));
*np -= j - i;
equation[k].level = level;
equation[k].kind = VARIABLE;
equation[k].token.variable = v;
while (find_more(equation, np, i2))
;
simp_loop(rhs[i2], &n_rhs[i2]);
simp_loop(equation, np);
for (i = 0; opt_en[i] >= 0; i++)
;
opt_en[i] = i2;
opt_en[i+1] = -1;
return true;
}
}
}
}
}
return false;
}
/*
* The optimize command.
*/
int
optimize_cmd(cp)
char *cp;
{
int i, j, k, i1;
int start, stop;
int rv = false, flag;
int start_en;
if (!get_range_eol(&cp, &start, &stop)) {
return false;
}
opt_en[0] = -1;
start_en = 0;
for (j = i = start; i <= stop; i++) {
if (n_lhs[i]) {
j = i;
simp_sub(i);
}
}
stop = j;
do {
flag = false;
for (i = start; i <= stop; i++) {
for (j = start; j <= stop; j++) {
if (i != j) {
while (find_more(rhs[i], &n_rhs[i], j)) {
flag = true;
rv = true;
}
}
}
}
} while (flag);
for (i = start; i <= stop; i++) {
if (n_lhs[i] == 0)
continue;
do {
flag = false;
simp_sub(i);
for (j = 0; opt_en[j] >= 0; j++) {
simp_sub(opt_en[j]);
if (i != opt_en[j]) {
while (find_more(lhs[i], &n_lhs[i], opt_en[j]))
flag = true;
while (find_more(rhs[i], &n_rhs[i], opt_en[j]))
flag = true;
}
}
} while (flag);
while (opt_es(lhs[i], &n_lhs[i])) {
rv = true;
}
while (opt_es(rhs[i], &n_rhs[i])) {
rv = true;
}
if (rv) {
for (i1 = start_en; opt_en[i1] >= 0; i1++) {
for (j = start_en; opt_en[j] >= 0; j++) {
for (k = j + 1; opt_en[k] >= 0; k++) {
while (find_more(rhs[opt_en[k]], &n_rhs[opt_en[k]], opt_en[j]))
;
while (find_more(rhs[opt_en[j]], &n_rhs[opt_en[j]], opt_en[k]))
;
}
}
while (opt_es(rhs[opt_en[i1]], &n_rhs[opt_en[i1]]))
;
}
for (; opt_en[start_en] >= 0; start_en++) {
list_sub(opt_en[start_en]);
}
list_sub(i);
}
}
if (!rv) {
error(_("Unable to find any repeated expressions."));
}
return rv;
}
#endif
#if READLINE
/*
* The push command.
*/
int
push_cmd(cp)
char *cp;
{
int i, j;
if (!get_range_eol(&cp, &i, &j)) {
return false;
}
for (; i <= j; i++) {
if (!push_en(i)) {
error(_("Push failed."));
return false;
}
}
debug_string(0, _("Expression(s) pushed. Press the UP key to access."));
return true;
}
/*
* Push an equation space into the readline history.
*
* Return true if successful.
*/
int
push_en(en)
int en; /* equation space number */
{
if (readline_enabled) {
high_prec = true;
add_history(list_equation(en, false));
high_prec = false;
return true;
} else {
return false;
}
}
#endif
/*
* Display current working directory.
*
* Return true if successful.
*/
int
display_current_directory()
{
#if !SECURE
char buf[MAX_CMD_LEN];
if (getcwd(buf, sizeof(buf))) {
fprintf(gfp, "directory = %s\n", buf);
return true;
}
#endif
return false;
}
/*
* Output the current set options in a format suitable for RC_FILE.
*/
void
output_options()
{
if (!autosolve) {
fprintf(gfp, "no ");
}
fprintf(gfp, "autosolve\n");
if (!autocalc) {
fprintf(gfp, "no ");
}
fprintf(gfp, "autocalc\n");
#if !SILENT
fprintf(gfp, "debug_level = %d\n", debug_level);
#endif
if (!case_sensitive_flag) {
fprintf(gfp, "no ");
}
fprintf(gfp, "case_sensitive\n");
if (!color_flag) {
fprintf(gfp, "no ");
}
fprintf(gfp, "color\n");
if (!bold_colors) {
fprintf(gfp, "no ");
}
fprintf(gfp, "bold_colors\n");
if (!display2d) {
fprintf(gfp, "no ");
}
fprintf(gfp, "display2d\n");
if (!preserve_roots) {
fprintf(gfp, "no ");
}
fprintf(gfp, "preserve_roots\n");
if (!true_modulus) {
fprintf(gfp, "no ");
}
fprintf(gfp, "true_modulus\n");
fprintf(gfp, "finance = %d\n", finance_option);
if (!factor_int_flag) {
fprintf(gfp, "no ");
}
fprintf(gfp, "factor_integers\n");
if (!right_associative_power) {
fprintf(gfp, "no ");
}
fprintf(gfp, "right_associative_power\n");
fprintf(gfp, "special_variable_character = %c\n", special_variable_character);
}
/*
* Return true if "cp" points to a negative word.
*/
int
is_no(cp)
char *cp;
{
if (strcmp_tospace(cp, "no") == 0
|| strcmp_tospace(cp, "off") == 0
|| strcmp_tospace(cp, "false") == 0) {
return true;
}
return false;
}
/*
* Handle parsing of options for the set command.
*
* Return false if error.
*/
int
set_options(cp)
char *cp;
{
int i;
int negate;
char *cp1;
next_option:
cp = skip_space(cp);
if (*cp == '\0') {
return true;
}
negate = is_no(cp);
if (negate) {
cp = skip_param(cp);
}
#if !SECURE
if (strncasecmp(cp, "dir", 3) == 0) {
cp = skip_param(cp);
if (*cp == '\0') {
cp1 = getenv("HOME");
if (cp1) {
cp = cp1;
}
}
if (chdir(cp)) {
error(_("Error changing directory."));
return false;
}
display_current_directory();
return true;
}
#endif
#if !SILENT
if (strncasecmp(cp, "debug", 5) == 0) {
cp = skip_param(cp);
if (negate) {
debug_level = 0;
} else {
i = decstrtol(cp, &cp1);
if (cp == cp1) {
error(_("Please specify the debug level number."));
return false;
}
cp = cp1;
debug_level = i;
}
goto next_option;
}
#endif
if (strncasecmp(cp, "special", 7) == 0) {
cp = skip_param(cp);
if (negate) {
special_variable_character = '\0';
} else {
if (*cp == '\0' || cp[1]) {
error(_("Please specify a single character."));
return false;
}
special_variable_character = *cp;
}
return true;
}
if (strncasecmp(cp, "columns", 7) == 0) {
cp = skip_param(cp);
if (negate) {
screen_columns = 0;
} else {
if ((i = decstrtol(cp, &cp1)) < 0 || cp == cp1) {
error(_("Please specify how wide the screen is in columns."));
return false;
}
cp = cp1;
screen_columns = i;
}
goto next_option;
}
if (strncasecmp(cp, "autosolve", 9) == 0) {
cp = skip_param(cp);
autosolve = !negate;
goto next_option;
}
if (strncasecmp(cp, "autocalc", 8) == 0) {
cp = skip_param(cp);
autocalc = !negate;
goto next_option;
}
if (strncasecmp(cp, "case", 4) == 0) {
cp = skip_param(cp);
case_sensitive_flag = !negate;
goto next_option;
}
if (strncasecmp(cp, "display2d", 7) == 0) {
cp = skip_param(cp);
display2d = !negate;
goto next_option;
}
if (strncasecmp(cp, "preserve", 8) == 0) {
cp = skip_param(cp);
preserve_roots = !negate;
goto next_option;
}
if (strncasecmp(cp, "true_modulus", 4) == 0) {
cp = skip_param(cp);
true_modulus = !negate;
goto next_option;
}
if (strncasecmp(cp, "color", 5) == 0) {
cp = skip_param(cp);
color_flag = !negate;
cur_color = -1;
goto next_option;
}
if (strncasecmp(cp, "bold", 4) == 0) {
cp = skip_param(cp);
bold_colors = !negate;
cur_color = -1;
goto next_option;
}
if (strncasecmp(cp, "finance", 7) == 0) {
cp = skip_param(cp);
if (negate) {
finance_option = 0;
} else {
i = decstrtol(cp, &cp1);
if (cp == cp1) {
i = 2;
}
if (i > 50) {
error(_("Maximum is 50."));
return false;
}
cp = cp1;
finance_option = i;
}
goto next_option;
}
if (strncasecmp(cp, "factor_integers", 6) == 0) {
cp = skip_param(cp);
factor_int_flag = !negate;
goto next_option;
}
if (strncasecmp(cp, "right_associative_power", 5) == 0) {
cp = skip_param(cp);
right_associative_power = !negate;
goto next_option;
}
error(_("Unknown set option."));
return false;
}
/*
* The set command.
*/
int
set_cmd(cp)
char *cp;
{
if (*cp == '\0') {
fprintf(gfp, _("Options are set as follows:\n\n"));
output_options();
fprintf(gfp, "columns = %d\n", screen_columns);
display_current_directory();
return true;
}
return set_options(cp);
}
/*
* The echo command.
*/
int
echo_cmd(cp)
char *cp;
{
fprintf(gfp, "%s\n", cp);
return true;
}
/*
* The pause command.
*/
int
pause_cmd(cp)
char *cp;
{
char *cp1;
char buf[MAX_CMD_LEN];
if (test_mode) {
return true;
}
if (*cp == '\0') {
cp = _("Please press Enter");
}
snprintf(prompt_str, sizeof(prompt_str), " ==== %s ==== ", cp);
if ((cp1 = get_string(buf, sizeof(buf))) == NULL) {
return false;
}
if (strncasecmp(cp1, "quit", 4) == 0) {
return false;
}
if (strncasecmp(cp1, "exit", 4) == 0) {
return false;
}
return true;
}
/*
* The copy command.
*/
int
copy_cmd(cp)
char *cp;
{
int i, j, k;
int i1;
char exists[N_EQUATIONS];
if (!get_range_eol(&cp, &i, &j)) {
return false;
}
for (i1 = 0; i1 < N_EQUATIONS; i1++) {
exists[i1] = false;
}
for (i1 = i; i1 <= j; i1++) {
if (n_lhs[i1] > 0) {
exists[i1] = true;
}
}
for (i1 = i; i1 <= j; i1++) {
if (exists[i1]) {
k = next_espace();
copy_espace(i1, k);
return_result(k);
}
}
return true;
}
/*
* Common function for the imaginary and real commands.
*/
static int
complex_func(cp, imag_flag)
char *cp; /* the command line */
int imag_flag; /* if true, copy the imaginary part, otherwise copy the real part */
{
int i, j, k;
int beg;
int found_imag;
int has_imag, has_real;
token_type *source, *dest;
int n1, *nps, *np;
long v;
if (current_not_defined()) {
return false;
}
i = cur_equation;
j = next_espace();
if (n_rhs[i]) {
source = rhs[i];
nps = &n_rhs[i];
dest = rhs[j];
np = &n_rhs[j];
} else {
source = lhs[i];
nps = &n_lhs[i];
dest = lhs[j];
np = &n_lhs[j];
}
v = IMAGINARY;
if (*cp) {
cp = parse_var2(&v, cp);
if (cp == NULL) {
return false;
}
if (extra_characters(cp))
return false;
}
simp_loop(source, nps);
uf_simp(source, nps);
factorv(source, nps, v);
partial_flag = false;
uf_simp(source, nps);
partial_flag = true;
n1 = 1;
dest[0] = zero_token;
has_imag = has_real = false;
for (beg = k = 0; beg < *nps; beg = k, k++) {
found_imag = false;
for (; k < *nps; k++) {
if (source[k].level == 1 && source[k].kind == OPERATOR
&& (source[k].token.operatr == PLUS || source[k].token.operatr == MINUS)) {
break;
}
if (source[k].kind == VARIABLE && source[k].token.variable == v) {
found_imag = true;
}
}
if (found_imag)
has_imag = true;
else
has_real = true;
if (found_imag == imag_flag) {
if (beg == 0) {
n1 = 0;
}
blt(&dest[n1], &source[beg], (k - beg) * sizeof(token_type));
n1 += (k - beg);
}
}
if (!has_imag || !has_real) {
error(_("Failed, expression is not a mix."));
return false;
}
simp_divide(dest, &n1);
if (n_rhs[i]) {
blt(lhs[j], lhs[i], n_lhs[i] * sizeof(token_type));
n_lhs[j] = n_lhs[i];
}
*np = n1;
cur_equation = j;
return return_result(cur_equation);
}
/*
* The real command.
*/
int
real_cmd(cp)
char *cp;
{
return complex_func(cp, false);
}
/*
* The imaginary command.
*/
int
imaginary_cmd(cp)
char *cp;
{
return complex_func(cp, true);
}
#if !LIBRARY
/*
* The tally command.
*/
int
tally_cmd(cp)
char *cp;
{
int i;
double count;
int arithmetic_mean = false;
if (strncasecmp(cp, "average", 4) == 0) {
arithmetic_mean = true;
cp = skip_param(cp);
}
if (extra_characters(cp)) {
return false;
}
trhs[0] = zero_token;
n_trhs = 1;
for (count = 0.0;; count++) {
fprintf(gfp, _("Running total = "));
list_proc(trhs, n_trhs, false);
fprintf(gfp, "\n");
if (count > 0.0) {
if (arithmetic_mean) {
/* calculate and display the average */
blt(tlhs, trhs, n_trhs * sizeof(token_type));
n_tlhs = n_trhs;
if ((n_tlhs + 2) > n_tokens) {
error_huge();
}
for (i = 0; i < n_tlhs; i++) {
tlhs[i].level++;
}
tlhs[n_tlhs].kind = OPERATOR;
tlhs[n_tlhs].level = 1;
tlhs[n_tlhs].token.operatr = DIVIDE;
n_tlhs++;
tlhs[n_tlhs].kind = CONSTANT;
tlhs[n_tlhs].level = 1;
tlhs[n_tlhs].token.constant = count;
n_tlhs++;
calc_simp(tlhs, &n_tlhs);
fprintf(gfp, _("Average = "));
list_proc(tlhs, n_tlhs, false);
fprintf(gfp, "\n");
}
}
fprintf(gfp, "\n");
my_strlcpy(prompt_str, _("Enter value: "), sizeof(prompt_str));
if (!get_expr(tlhs, &n_tlhs)) {
break;
}
if ((n_trhs + 1 + n_tlhs) > n_tokens) {
error_huge();
}
for (i = 0; i < n_tlhs; i++) {
tlhs[i].level++;
}
for (i = 0; i < n_trhs; i++) {
trhs[i].level++;
}
trhs[n_trhs].kind = OPERATOR;
trhs[n_trhs].level = 1;
trhs[n_trhs].token.operatr = PLUS;
n_trhs++;
blt(&trhs[n_trhs], tlhs, n_tlhs * sizeof(token_type));
n_trhs += n_tlhs;
calc_simp(trhs, &n_trhs);
}
fprintf(gfp, _("End.\n"));
return true;
}
#endif
#if !LIBRARY
/*
* The calculate command.
*
* Temporarily plug values into the RHS of the current equation,
* unless there is no RHS, then use LHS.
*/
int
calculate_cmd(cp)
char *cp;
{
int i, j, k;
long v, last_v, it_v = 0;
long counter, counter_max;
sign_array_type sa_mark;
sign_array_type sa_value;
long l, iterations = 1;
token_type *source;
int n;
int diff_sign;
char buf[MAX_CMD_LEN];
if (current_not_defined()) {
return false;
}
i = cur_equation;
if (n_rhs[i]) {
source = rhs[i];
n = n_rhs[i];
} else {
source = lhs[i];
n = n_lhs[i];
}
if (*cp) {
cp = parse_var2(&it_v, cp);
if (cp == NULL) {
return false;
}
if (!found_var(source, n, it_v)) {
error(_("Specified iteration variable not found."));
return false;
}
if (*cp == '\0') {
my_strlcpy(prompt_str, _("Enter number of iterations: "), sizeof(prompt_str));
if ((cp = get_string(buf, sizeof(buf))) == NULL)
return false;
}
iterations = decstrtol(cp, &cp);
if (*cp || iterations <= 0) {
error(_("Invalid number of iterations."));
return false;
}
}
n_trhs = n;
blt(trhs, source, n_trhs * sizeof(token_type));
last_v = 0;
for (;;) {
v = -1;
for (j = 0; j < n; j += 2) {
if (source[j].kind == VARIABLE) {
if (source[j].token.variable > last_v
&& (v == -1 || source[j].token.variable < v))
v = source[j].token.variable;
}
}
if (v == -1)
break;
last_v = v;
if ((v & VAR_MASK) <= SIGN || v == it_v) {
continue;
}
list_var(v, 0);
snprintf(prompt_str, sizeof(prompt_str), _("Enter %s: "), var_str);
if (!get_expr(tlhs, &n_tlhs)) {
continue;
}
/* disguise all variables in the entered expression by making them negative: */
for (j = 0; j < n_tlhs; j += 2)
if (tlhs[j].kind == VARIABLE)
tlhs[j].token.variable = -tlhs[j].token.variable;
subst_var_with_exp(trhs, &n_trhs, tlhs, n_tlhs, v);
}
/* restore disguised variables: */
for (j = 0; j < n_trhs; j += 2)
if (trhs[j].kind == VARIABLE && trhs[j].token.variable < 0)
trhs[j].token.variable = -trhs[j].token.variable;
if (it_v) {
list_var(it_v, 0);
snprintf(prompt_str, sizeof(prompt_str), _("Enter initial %s: "), var_str);
while (!get_expr(tes, &n_tes))
;
calc_simp(tes, &n_tes);
blt(tlhs, trhs, n_trhs * sizeof(token_type));
n_tlhs = n_trhs;
for (l = 0; l < iterations; l++) {
blt(trhs, tlhs, n_tlhs * sizeof(token_type));
n_trhs = n_tlhs;
subst_var_with_exp(trhs, &n_trhs, tes, n_tes, it_v);
calc_simp(trhs, &n_trhs);
if (se_compare(trhs, n_trhs, tes, n_tes, &diff_sign) && !diff_sign) {
fprintf(gfp, _("Convergence reached after %ld iterations.\n"), l + 1);
break;
}
blt(tes, trhs, n_trhs * sizeof(token_type));
n_tes = n_trhs;
}
}
calc_simp(trhs, &n_trhs);
fprintf(gfp, "\n");
for (j = 0; j < ARR_CNT(sa_mark); j++)
sa_mark[j] = false;
for (j = 0; j < n_trhs; j += 2) {
if (trhs[j].kind == VARIABLE && (trhs[j].token.variable & VAR_MASK) == SIGN) {
sa_mark[(trhs[j].token.variable >> VAR_SHIFT) & SUBSCRIPT_MASK] = true;
}
}
for (j = 0, k = 0; j < ARR_CNT(sa_mark); j++) {
if (sa_mark[j]) {
k++;
}
}
counter_max = (1L << k) - 1L;
for (counter = 0; counter <= counter_max; counter++) {
blt(tlhs, trhs, n_trhs * sizeof(token_type));
n_tlhs = n_trhs;
for (j = 0, k = 0; j < ARR_CNT(sa_mark); j++) {
if (sa_mark[j]) {
sa_value[j] = (((1L << k) & counter) != 0);
k++;
}
}
for (j = 0; j < n_tlhs; j += 2) {
if (tlhs[j].kind == VARIABLE && (tlhs[j].token.variable & VAR_MASK) == SIGN) {
if (sa_value[(tlhs[j].token.variable >> VAR_SHIFT) & SUBSCRIPT_MASK]) {
tlhs[j].kind = CONSTANT;
tlhs[j].token.constant = -1.0;
} else {
tlhs[j].kind = CONSTANT;
tlhs[j].token.constant = 1.0;
}
}
}
for (j = 0, k = false; j < ARR_CNT(sa_mark); j++) {
if (sa_mark[j]) {
if (k) {
fprintf(gfp, ", ");
} else {
fprintf(gfp, _("Solution #%ld with "), counter + 1);
}
list_var((long) SIGN + (((long) j) << VAR_SHIFT), 0);
fprintf(gfp, "%s = ", var_str);
if (sa_value[j]) {
fprintf(gfp, "-1");
} else {
fprintf(gfp, "1");
}
k = true;
}
}
if (k)
fprintf(gfp, ":\n");
calc_simp(tlhs, &n_tlhs);
if (factor_int_flag) {
factor_int(tlhs, &n_tlhs);
}
fprintf(gfp, " ");
if (n_rhs[i]) {
list_proc(lhs[i], n_lhs[i], false);
fprintf(gfp, " = ");
}
list_proc(tlhs, n_tlhs, false);
fprintf(gfp, "\n\n");
}
return true;
}
#endif
/*
* The clear command.
*/
int
clear_cmd(cp)
char *cp;
{
int i, j;
char *cp1;
do {
cp1 = cp;
if (is_all(cp)) {
clear_all();
return true;
} else {
if (!get_range(&cp, &i, &j)) {
return false;
}
if (*cp && cp == cp1) {
error(_("Invalid argument."));
return false;
}
for (; i <= j; i++) {
n_lhs[i] = 0;
n_rhs[i] = 0;
}
}
} while (*cp);
return true;
}
static int
compare_rhs(i, j, diff_signp)
int i, j;
int *diff_signp;
{
int rv;
rv = se_compare(rhs[i], n_rhs[i], rhs[i], n_rhs[i], diff_signp);
if (!rv || *diff_signp) {
error(_("Error in compare function or too many terms to compare."));
return false;
}
sign_flag = true;
rv = se_compare(rhs[i], n_rhs[i], rhs[j], n_rhs[j], diff_signp);
sign_flag = false;
return rv;
}
static int
compare_lhs(i, j)
int i, j;
{
int rv;
int diff_sign;
rv = se_compare(lhs[i], n_lhs[i], lhs[i], n_lhs[i], &diff_sign);
if (!rv || diff_sign) {
error(_("Error in compare function or too many terms to compare."));
return false;
}
sign_flag = true;
rv = se_compare(lhs[i], n_lhs[i], lhs[j], n_lhs[j], &diff_sign);
sign_flag = false;
return(rv && !diff_sign);
}
/*
* The compare command.
*/
int
compare_cmd(cp)
char *cp;
{
int i, j;
int diff_sign;
int already_solved;
i = decstrtol(cp, &cp) - 1;
if (not_defined(i)) {
return false;
}
if (strcmp_tospace(cp, "with") == 0) {
cp = skip_param(cp);
}
if ((j = get_default_en(cp)) < 0) {
return false;
}
if (i == j) {
error(_("Cannot compare an equation with itself."));
return false;
}
#if !SILENT
fprintf(gfp, _("Comparing #%d with #%d...\n"), i + 1, j + 1);
#endif
if (n_rhs[i] == 0 || n_rhs[j] == 0) {
if (n_rhs[i] == 0 && n_rhs[j] == 0) {
simp_loop(lhs[i], &n_lhs[i]);
simp_loop(lhs[j], &n_lhs[j]);
if (compare_lhs(i, j)) {
fprintf(gfp, _("Expressions are identical.\n"));
return true;
}
debug_string(0, _("Simplifying both expressions..."));
simpa_side(lhs[i], &n_lhs[i], true, false);
simpa_side(lhs[j], &n_lhs[j], true, false);
#if !SILENT
if (debug_level >= 0) {
list_sub(i);
list_sub(j);
}
#endif
if (compare_lhs(i, j)) {
fprintf(gfp, _("Expressions are identical.\n"));
return true;
}
uf_simp(lhs[i], &n_lhs[i]);
uf_simp(lhs[j], &n_lhs[j]);
if (compare_lhs(i, j)) {
fprintf(gfp, _("Expressions are identical.\n"));
return true;
}
fprintf(gfp, _("Expressions differ.\n"));
return false;
}
error(_("Cannot compare an expression with an equation."));
return false;
}
already_solved = (solved_equation(i) && solved_equation(j));
if (already_solved) {
simp_loop(rhs[i], &n_rhs[i]);
simp_loop(rhs[j], &n_rhs[j]);
if (compare_rhs(i, j, &diff_sign)) {
goto times_neg1;
}
debug_string(0, _("Simplifying both equations..."));
simpa_side(rhs[i], &n_rhs[i], true, false);
simpa_side(rhs[j], &n_rhs[j], true, false);
#if !SILENT
if (debug_level >= 0) {
list_sub(i);
list_sub(j);
}
#endif
if (compare_rhs(i, j, &diff_sign)) {
goto times_neg1;
}
uf_simp(rhs[i], &n_rhs[i]);
uf_simp(rhs[j], &n_rhs[j]);
if (compare_rhs(i, j, &diff_sign)) {
goto times_neg1;
}
}
debug_string(0, _("Solving both equations for zero and unfactoring..."));
if (solve_sub(&zero_token, 1, lhs[i], &n_lhs[i], rhs[i], &n_rhs[i]) <= 0
|| solve_sub(&zero_token, 1, lhs[j], &n_lhs[j], rhs[j], &n_rhs[j]) <= 0) {
error(_("Can't solve for zero!"));
return false;
}
uf_simp(rhs[i], &n_rhs[i]);
uf_simp(rhs[j], &n_rhs[j]);
if (compare_rhs(i, j, &diff_sign)) {
fprintf(gfp, _("Equations are identical.\n"));
return true;
}
debug_string(0, _("Simplifying both equations..."));
simpa_side(rhs[i], &n_rhs[i], true, false);
simpa_side(rhs[j], &n_rhs[j], true, false);
if (compare_rhs(i, j, &diff_sign)) {
fprintf(gfp, _("Equations are identical.\n"));
return true;
}
if (solve_sub(&zero_token, 1, lhs[i], &n_lhs[i], rhs[i], &n_rhs[i]) <= 0
|| solve_sub(&zero_token, 1, lhs[j], &n_lhs[j], rhs[j], &n_rhs[j]) <= 0) {
error(_("Can't solve for zero!"));
return false;
}
uf_simp(rhs[i], &n_rhs[i]);
uf_simp(rhs[j], &n_rhs[j]);
if (compare_rhs(i, j, &diff_sign)) {
fprintf(gfp, _("Equations are identical.\n"));
return true;
}
fprintf(gfp, _("Equations differ.\n"));
return false;
times_neg1:
if (!diff_sign && lhs[i][0].token.variable == lhs[j][0].token.variable) {
fprintf(gfp, _("Equations are identical.\n"));
return true;
}
fprintf(gfp, _("Variable ("));
list_proc(lhs[i], n_lhs[i], false);
fprintf(gfp, _(") in the first equation is equal to ("));
if (diff_sign) {
fprintf(gfp, "-");
}
list_proc(lhs[j], n_lhs[j], false);
fprintf(gfp, _(") in the second equation.\n"));
return(!diff_sign);
}
#if !LIBRARY
/*
* The divide command.
*/
int
divide_cmd(cp)
char *cp;
{
long v, v_tmp;
int i, j;
int nl, nr;
double d1, d2, d3, d4;
complexs c1, c2, c3;
v = 0;
if (*cp) {
cp = parse_var2(&v, cp);
if (cp == NULL) {
return false;
}
if (extra_characters(cp))
return false;
}
i = next_espace();
my_strlcpy(prompt_str, _("Enter dividend: "), sizeof(prompt_str));
if (!get_expr(rhs[i], &nr)) {
return false;
}
my_strlcpy(prompt_str, _("Enter divisor: "), sizeof(prompt_str));
if (!get_expr(lhs[i], &nl)) {
return false;
}
fprintf(gfp, "\n");
calc_simp(lhs[i], &nl);
calc_simp(rhs[i], &nr);
if (get_constant(rhs[i], nr, &d1) && get_constant(lhs[i], nl, &d2)) {
d4 = modf(d1 / d2, &d3);
fprintf(gfp, _("Result of numerical division: %.*g/%.*g = %.*g\n"), precision, d1, precision, d2, precision, d1 / d2);
fprintf(gfp, _("Quotient: %.*g, Remainder: %.*g\n"), precision, d3, precision, d4 * d2);
d1 = fabs(d1);
d2 = fabs(d2);
d3 = gcd_verified(d1, d2);
if (d3 <= 0.0) {
fprintf(gfp, _("No GCD found.\n"));
return true;
}
fprintf(gfp, _("Greatest Common Divisor (GCD) = %.*g\n"), precision, d3);
fprintf(gfp, _("Least Common Multiple (LCM) = %.*g\n"), precision, (d1 * d2) / d3);
return true;
}
if (parse_complex(rhs[i], nr, &c1) && parse_complex(lhs[i], nl, &c2)) {
c3 = complex_div(c1, c2);
fprintf(gfp, _("Result of complex number division:\n"));
fprintf(gfp, "%.*g %+.*g*i\n\n", precision, c3.re, precision, c3.im);
return true;
}
v_tmp = v;
if (poly_div(rhs[i], nr, lhs[i], nl, &v_tmp)) {
simp_divide(tlhs, &n_tlhs);
simp_divide(trhs, &n_trhs);
list_var(v_tmp, 0);
fprintf(gfp, _("Polynomial division successful using base variable (%s).\n"), var_str);
fprintf(gfp, _("The quotient is:\n"));
list_proc(tlhs, n_tlhs, false);
fprintf(gfp, _("\n\nThe remainder is:\n"));
list_proc(trhs, n_trhs, false);
fprintf(gfp, "\n");
} else {
fprintf(gfp, _("Polynomial division failed.\n"));
}
fprintf(gfp, "\n");
j = poly_gcd(rhs[i], nr, lhs[i], nl, v);
if (!j) {
j = poly_gcd(lhs[i], nl, rhs[i], nr, v);
}
if (j) {
simp_divide(trhs, &n_trhs);
fprintf(gfp, _("Polynomial GCD (Euclidean algorithm iterations = %d):\n"), j);
list_proc(trhs, n_trhs, false);
fprintf(gfp, "\n");
} else {
fprintf(gfp, _("No univariate polynomial GCD found.\n"));
}
return true;
}
#endif
/*
* The eliminate command.
*/
int
eliminate_cmd(cp)
char *cp;
{
long v, last_v, v1, va[MAX_VARS];
int i, n;
int using_flag, did_something = false;
char used[N_EQUATIONS];
int vc = 0;
if (*cp == '\0') {
error(_("Please specify the variables to eliminate or \"all\" for all variables."));
return false;
}
for (i = 0; i < ARR_CNT(used); i++)
used[i] = false;
if (current_not_defined()) {
return false;
}
next_var:
if (vc) {
v = va[--vc];
} else if (*cp) {
if (is_all(cp)) {
cp = skip_param(cp);
vc = 0;
last_v = 0;
for (;;) {
v1 = -1;
for (i = 0; i < n_lhs[cur_equation]; i += 2) {
if (lhs[cur_equation][i].kind == VARIABLE
&& lhs[cur_equation][i].token.variable > last_v) {
if (v1 == -1 || lhs[cur_equation][i].token.variable < v1) {
v1 = lhs[cur_equation][i].token.variable;
}
}
}
for (i = 0; i < n_rhs[cur_equation]; i += 2) {
if (rhs[cur_equation][i].kind == VARIABLE
&& rhs[cur_equation][i].token.variable > last_v) {
if (v1 == -1 || rhs[cur_equation][i].token.variable < v1) {
v1 = rhs[cur_equation][i].token.variable;
}
}
}
if (v1 == -1)
break;
last_v = v1;
if ((v1 & VAR_MASK) > SIGN) {
if (vc >= ARR_CNT(va)) {
break;
}
va[vc++] = v1;
}
}
goto next_var;
}
cp = parse_var2(&v, cp);
if (cp == NULL) {
return false;
}
} else {
if (did_something) {
did_something = return_result(cur_equation);
} else {
error(_("No substitutions made."));
}
return did_something;
}
if (!var_in_equation(cur_equation, v)) {
#if !SILENT
list_var(v, 0);
printf(_("Variable (%s) not found in current equation.\n"), var_str);
#endif
goto next_var;
}
using_flag = (strcmp_tospace(cp, "using") == 0);
if (using_flag) {
cp = skip_param(cp);
i = decstrtol(cp, &cp) - 1;
if (not_defined(i)) {
return false;
}
if (i == cur_equation) {
error(_("Error: source and destination are the same."));
return false;
}
if (!elim_sub(i, v))
goto next_var;
} else {
n = 1;
i = cur_equation;
for (;; n++) {
if (n >= n_equations) {
goto next_var;
}
if (i <= 0)
i = n_equations - 1;
else
i--;
if (used[i])
continue;
if (n_lhs[i] && n_rhs[i] && var_in_equation(i, v)) {
if (elim_sub(i, v))
break;
}
}
}
did_something = true;
used[i] = true;
goto next_var;
}
static int
elim_sub(i, v)
int i;
long v;
{
token_type want;
#if !SILENT
if (debug_level >= 0) {
list_var(v, 0);
printf(_("Solving equation #%d for (%s) and substituting into the current equation...\n"), i + 1, var_str);
}
#endif
want.level = 1;
want.kind = VARIABLE;
want.token.variable = v;
if (solve_sub(&want, 1, lhs[i], &n_lhs[i], rhs[i], &n_rhs[i]) <= 0) {
debug_string(0, _("Solve failed."));
return false;
}
subst_var_with_exp(rhs[cur_equation], &n_rhs[cur_equation], rhs[i], n_rhs[i], v);
subst_var_with_exp(lhs[cur_equation], &n_lhs[cur_equation], rhs[i], n_rhs[i], v);
simp_sub(cur_equation);
return true;
}
/*
* The display command.
*
* Displays equations in multi-line fraction format.
*/
int
display_cmd(cp)
char *cp;
{
int i, j;
int factor_flag;
factor_flag = (strcmp_tospace(cp, "factor") == 0);
if (factor_flag) {
cp = skip_param(cp);
}
if (!get_range_eol(&cp, &i, &j)) {
return false;
}
for (; i <= j; i++) {
if (n_lhs[i] > 0) {
make_fractions_and_group(i);
if (factor_flag || factor_int_flag) {
factor_int_sub(i);
}
#if LIBRARY
if (gfp == stdout) {
free(result_str);
result_str = list_equation(i, false);
return(result_str != NULL);
}
#endif
flist_sub(i);
}
}
return true;
}
/*
* The list command.
*/
int
list_cmd(cp)
char *cp;
{
int i, j;
char *cp1;
int export_flag = 0;
if (strncasecmp(cp, "export", 4) == 0) {
export_flag = 2;
cp = skip_param(cp);
} else if (strncasecmp(cp, "maxima", 4) == 0) {
export_flag = 1;
cp = skip_param(cp);
}
do {
cp1 = cp;
if (!get_range(&cp, &i, &j)) {
return false;
}
if (*cp && cp == cp1) {
error(_("Invalid argument."));
return false;
}
for (; i <= j; i++) {
if (factor_int_flag) {
factor_int_sub(i);
}
#if LIBRARY
if (gfp == stdout) {
free(result_str);
result_str = list_equation(i, export_flag);
return(result_str != NULL);
}
#endif
list1_sub(i, export_flag);
}
} while (*cp);
return true;
}
#if !LIBRARY
/*
* The code command.
*/
int
code_cmd(cp)
char *cp;
{
int i, j;
int language = 0;
int int_flag = false, displayed = false;
char *cp1;
if (strcmp_tospace(cp, "c") == 0 || strcmp_tospace(cp, "c++") == 0) {
cp = skip_param(cp);
} else if (strcmp_tospace(cp, "java") == 0) {
cp = skip_param(cp);
language = 1;
} else if (strcmp_tospace(cp, "python") == 0) {
cp = skip_param(cp);
language = 2;
} else if (strcmp_tospace(cp, "int") == 0 || strcmp_tospace(cp, "integer") == 0) {
cp = skip_param(cp);
int_flag = true;
}
do {
cp1 = cp;
if (!get_range(&cp, &i, &j)) {
return false;
}
if (*cp && cp == cp1) {
error(_("Invalid argument."));
return false;
}
for (; i <= j; i++) {
if (n_lhs[i] > 0) {
if (n_rhs[i] == 0 || n_lhs[i] != 1 || lhs[i][0].kind != VARIABLE) {
error(_("Not a solved equation."));
continue;
}
approximate_roots = true;
simp_i(rhs[i], &n_rhs[i]);
approximate_roots = false;
if (int_flag) {
uf_repeat_always(rhs[i], &n_rhs[i]);
}
make_fractions_and_group(i);
if (int_flag) {
if (!int_expr(rhs[i], n_rhs[i])) {
error(_("Not an integer equation."));
continue;
}
}
list_c_equation(i, language, int_flag);
displayed = true;
}
}
} while (*cp);
return displayed;
}
#endif
/*
* The approximate command.
*/
int
approximate_cmd(cp)
char *cp;
{
int i, j;
char *cp1;
do {
cp1 = cp;
if (!get_range(&cp, &i, &j)) {
return false;
}
if (*cp && cp == cp1) {
error(_("Invalid argument."));
return false;
}
for (; i <= j; i++) {
if (n_lhs[i]) {
subst_constants(lhs[i], &n_lhs[i]);
subst_constants(rhs[i], &n_rhs[i]);
approximate_roots = true;
simp_sub(i);
approximate_roots = false;
return_result(i);
}
}
} while (*cp);
return true;
}
/*
* The replace command.
*/
int
replace_cmd(cp)
char *cp;
{
int i, j;
int n;
long last_v, v;
char *cp_start;
long va[MAX_VARS];
int vc;
int found;
char *cp1;
cp_start = cp;
if (strcmp_tospace(cp, "constants") == 0) {
cp = skip_param(cp);
return approximate_cmd(cp);
}
if (current_not_defined()) {
return false;
}
i = cur_equation;
for (vc = 0; *cp; vc++) {
if (strcmp_tospace(cp, "with") == 0) {
if (vc)
break;
error(_("No variables specified."));
return false;
}
if (vc >= ARR_CNT(va)) {
error(_("Too many variables specified."));
return false;
}
cp = parse_var2(&va[vc], cp);
if (cp == NULL) {
return false;
}
if (!var_in_equation(i, va[vc])) {
error(_("Variable not found."));
return false;
}
}
n_tlhs = n_lhs[i];
blt(tlhs, lhs[i], n_tlhs * sizeof(token_type));
n_trhs = n_rhs[i];
blt(trhs, rhs[i], n_trhs * sizeof(token_type));
last_v = 0;
for (;;) {
v = -1;
for (j = 0; j < n_lhs[i]; j += 2) {
if (lhs[i][j].kind == VARIABLE) {
if (lhs[i][j].token.variable > last_v
&& (v == -1 || lhs[i][j].token.variable < v))
v = lhs[i][j].token.variable;
}
}
for (j = 0; j < n_rhs[i]; j += 2) {
if (rhs[i][j].kind == VARIABLE) {
if (rhs[i][j].token.variable > last_v
&& (v == -1 || rhs[i][j].token.variable < v))
v = rhs[i][j].token.variable;
}
}
if (v == -1) {
break;
}
last_v = v;
if (vc) {
found = false;
for (j = 0; j < vc; j++) {
if (v == va[j])
found = true;
}
if (!found)
continue;
if (*cp) {
if (strcmp_tospace(cp, "with") != 0) {
return false;
}
cp1 = skip_param(cp);
input_column += (cp1 - cp_start);
if (!case_sensitive_flag) {
str_tolower(cp1);
}
if ((cp1 = parse_section(scratch, &n, cp1)) == NULL || n <= 0) {
return false;
}
if (extra_characters(cp1))
return false;
goto do_this;
}
}
list_var(v, 0);
snprintf(prompt_str, sizeof(prompt_str), _("Enter %s: "), var_str);
if (!get_expr(scratch, &n)) {
continue;
}
do_this:
/* disguise all variables in the entered expression by making them negative: */
for (j = 0; j < n; j += 2) {
if (scratch[j].kind == VARIABLE) {
scratch[j].token.variable = -scratch[j].token.variable;
}
}
subst_var_with_exp(tlhs, &n_tlhs, scratch, n, v);
subst_var_with_exp(trhs, &n_trhs, scratch, n, v);
}
/* restore disguised variables: */
for (j = 0; j < n_tlhs; j += 2)
if (tlhs[j].kind == VARIABLE && tlhs[j].token.variable < 0)
tlhs[j].token.variable = -tlhs[j].token.variable;
for (j = 0; j < n_trhs; j += 2)
if (trhs[j].kind == VARIABLE && trhs[j].token.variable < 0)
trhs[j].token.variable = -trhs[j].token.variable;
n_lhs[i] = n_tlhs;
blt(lhs[i], tlhs, n_tlhs * sizeof(token_type));
n_rhs[i] = n_trhs;
blt(rhs[i], trhs, n_trhs * sizeof(token_type));
simp_sub(i);
return return_result(i);
}
/*
* The simplify command.
*/
int
simplify_cmd(cp)
char *cp;
{
int i, j;
int quick_flag = false, symb = false, frac_flag = false;
for (;; cp = skip_param(cp)) {
if (strncasecmp(cp, "symbolic", 4) == 0) {
symb = true;
continue;
}
if (strncasecmp(cp, "quick", 4) == 0) {
quick_flag = true;
continue;
}
if (strncasecmp(cp, "fraction", 4) == 0) {
frac_flag = true;
continue;
}
break;
}
if (!get_range_eol(&cp, &i, &j)) {
return false;
}
symb_flag = symb;
for (; i <= j; i++) {
if (n_lhs[i]) {
simpa_side(lhs[i], &n_lhs[i], quick_flag, frac_flag);
simpa_side(rhs[i], &n_rhs[i], quick_flag, frac_flag);
return_result(i);
}
}
symb_flag = false;
return true;
}
/*
* The factor command.
*/
int
factor_cmd(cp)
char *cp;
{
int i, j;
int i1, count;
long v;
double d;
char *cp_start, buf[MAX_CMD_LEN];
int valid_range = false;
cp_start = cp;
if (strncasecmp(cp, "number", 6) == 0) {
cp = skip_param(cp);
} else {
valid_range = get_range(&cp, &i, &j);
if (!valid_range) {
cp = cp_start;
}
}
if (!valid_range) {
if (*cp == '\0') {
my_strlcpy(prompt_str, _("Enter integers to factor: "), sizeof(prompt_str));
cp = get_string(buf, sizeof(buf));
if (cp == NULL)
return false;
}
for (count = 1; *cp; count++) {
d = strtod(cp, &cp);
cp = skip_space(cp);
if (!factor_one(d)) {
error(_("Not a valid integer or number too large."));
return false;
}
display_unique();
}
return true;
}
v = 0;
do {
if (*cp) {
if ((cp = parse_var2(&v, cp)) == NULL) {
return false;
}
}
for (i1 = i; i1 <= j; i1++) {
if (n_lhs[i1]) {
simpv_side(lhs[i1], &n_lhs[i1], v);
simpv_side(rhs[i1], &n_rhs[i1], v);
}
}
} while (*cp);
for (i1 = i; i1 <= j; i1++) {
return_result(i1);
}
return true;
}
/*
* The unfactor command.
*/
int
unfactor_cmd(cp)
char *cp;
{
int i, j;
int fully_flag;
fully_flag = (strncasecmp(cp, "fully", 4) == 0);
if (fully_flag) {
cp = skip_param(cp);
}
if (!get_range_eol(&cp, &i, &j)) {
return false;
}
partial_flag = !fully_flag;
for (; i <= j; i++) {
if (n_lhs[i]) {
uf_simp(lhs[i], &n_lhs[i]);
uf_simp(rhs[i], &n_rhs[i]);
return_result(i);
}
}
partial_flag = true;
return true;
}
/*
* The fraction command.
*/
int
fraction_cmd(cp)
char *cp;
{
int i, j;
if (!get_range_eol(&cp, &i, &j)) {
return false;
}
for (; i <= j; i++) {
if (n_lhs[i]) {
frac_side(lhs[i], &n_lhs[i]);
frac_side(rhs[i], &n_rhs[i]);
return_result(i);
}
}
return true;
}
#if !LIBRARY
/*
* The quit command.
*/
int
quit_cmd(cp)
char *cp;
{
if (extra_characters(cp))
return false;
exit_program(0);
return false;
}
#endif
#if !SECURE
/*
* The read command.
*/
int
read_cmd(cp)
char *cp;
{
int rv;
FILE *fp;
char buf[MAX_CMD_LEN];
if (*cp == '\0') {
error(_("No file specified."));
return false;
}
fp = NULL;
snprintf(buf, sizeof(buf), "%s.in", cp);
fp = fopen(buf, "r");
if (fp == NULL) {
fp = fopen(cp, "r");
if (fp == NULL) {
error(_("Can't open input file."));
return false;
}
} else {
cp = buf;
}
rv = read_sub(fp);
if (rv) {
printf(_("Read operation aborted.\n"));
} else {
printf(_("Finished reading file \"%s\".\n"), cp);
}
fclose(fp);
return(!rv);
}
/*
* Read and process Mathomatic input from a file pointer.
*
* Return zero if no error, non-zero if aborted.
*/
int
read_sub(fp)
FILE *fp;
{
int rv;
jmp_buf save_save;
char *cp;
blt(save_save, jmp_save, sizeof(jmp_save));
if ((rv = setjmp(jmp_save)) != 0) {
clean_up();
if (rv == 14) {
error(_("Expression too large."));
}
} else {
while ((cp = fgets((char *) tlhs, n_tokens * sizeof(token_type), fp)) != NULL) {
default_color();
input_column = printf("%d%s", cur_equation + 1, html_flag ? HTML_PROMPT : PROMPT);
printf("%s", cp);
if (gfp != stdout) {
fprintf(gfp, "%d%s%s", cur_equation + 1, html_flag ? HTML_PROMPT : PROMPT, cp);
}
set_error_level(cp);
if (!process(cp)) {
longjmp(jmp_save, 3);
}
}
}
blt(jmp_save, save_save, sizeof(jmp_save));
return rv;
}
#endif
#if (UNIX || CYGWIN) && !SECURE && !LIBRARY
/*
* The edit command.
*/
int
edit_cmd(cp)
char *cp;
{
FILE *fp;
int fd;
int rv;
char tmp_file[MAX_CMD_LEN];
if (*cp == '\0') {
#if CYGWIN
my_strlcpy(tmp_file, "mathomatic.tmp", sizeof(tmp_file));
fp = fopen(tmp_file, "w+");
if (fp == NULL) {
error(_("Can't create temporary file."));
return false;
}
#else
my_strlcpy(tmp_file, TMP_FILE, sizeof(tmp_file));
fd = mkstemp(tmp_file);
if (fd < 0 || (fp = fdopen(fd, "w+")) == NULL) {
error(_("Can't create temporary file."));
return false;
}
#endif
gfp = fp;
high_prec = true;
list_cmd("all");
high_prec = false;
gfp = stdout;
fclose(fp);
rv = edit_sub(tmp_file);
unlink(tmp_file);
return rv;
} else {
if (access(cp, 6)) {
error(_("You can only edit existing/writable files or all equations."));
return false;
}
return edit_sub(cp);
}
}
static int
edit_sub(cp)
char *cp;
{
char cl[MAX_CMD_LEN]; /* command line */
char *cp1;
edit_again:
cp1 = getenv("EDITOR");
if (cp1 == NULL) {
#if CYGWIN
cp1 = "notepad";
#else
error("EDITOR environment variable not set.");
return false;
#endif
}
snprintf(cl, sizeof(cl), "%s %s", cp1, cp);
if (shell_out(cl)) {
error("Error executing editor, check EDITOR environment variable.");
printf(_("Command line = \"%s\".\n"), cl);
return false;
}
clear_all();
if (!read_cmd(cp)) {
if (pause_cmd(_("Prepare to run the editor"))) {
goto edit_again;
}
}
return true;
}
#endif
#if !SECURE
/*
* The save command.
*/
int
save_cmd(cp)
char *cp;
{
FILE *fp;
int rv;
if (*cp == '\0') {
error(_("No file specified."));
return false;
}
#if !SILENT
if (access(cp, 0) == 0) {
snprintf(prompt_str, sizeof(prompt_str), _("\"%s\" exists, overwrite (y/n)? "), cp);
if (!get_yes_no()) {
printf(_("Command aborted.\n"));
return false;
}
}
#endif
fp = fopen(cp, "w");
if (fp == NULL) {
error(_("Can't create specified file."));
return false;
}
gfp = fp;
high_prec = true;
rv = list_cmd("all");
high_prec = false;
gfp = stdout;
if (fclose(fp))
rv = false;
if (rv) {
#if !SILENT
printf(_("All equations saved in file: \"%s\".\n"), cp);
#endif
} else {
error(_("Error encountered while saving equations."));
}
return rv;
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1