Logo Search packages:      
Sourcecode: mathomatic version File versions

cmds.c

/*
 * Algebraic manipulator commands.
 *
 * Copyright (c) 1996 George Gesslein II.
 */

#include "am.h"
#include "externs.h"

int         opt_en[N_EQUATIONS];
int         last_temp_var = 0;

#define     OPT_MIN_SIZE      5     /* Minimum size of repeated expressions to find in "optimize" command. */

/*
 * 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);
}

int
sum_product(cp, product_flag)
char  *cp;
int   product_flag;
{
      int   i, j;
      int   found;
      long  v;
      char  *cp1;
      double      d1, d2;
      int   result_en;
      int   n;
      int   count_down;

      v = 0L;
      if (notdefined(cur_equation)) {
            return false;
      }
      if (*cp == '\0') {
            for (j = 0; j < n_rhs[cur_equation]; j++) {
                  if (rhs[cur_equation][j].kind == VARIABLE) {
                        if ((rhs[cur_equation][j].token.variable & VAR_MASK) <= SIGN)
                              continue;
                        if (v) {
                              if (v != rhs[cur_equation][j].token.variable) {
                                    v = 0L;
                                    break;
                              }
                        } else {
                              v = rhs[cur_equation][j].token.variable;
                        }
                  }
            }
            if (v == 0L) {
                  if (!prompt_var(&v))
                        return false;
            }
      } else {
            cp = parse_var2(&v, cp);
            if (cp == NULL) {
                  return false;
            }
      }
      result_en = next_espace();
      found = false;
      for (j = 0; j < n_rhs[cur_equation]; j++) {
            if (rhs[cur_equation][j].kind == VARIABLE) {
                  if (rhs[cur_equation][j].token.variable == v)
                        found = true;
            }
      }
      if (!found) {
            printf(_("Variable not found in RHS.\n"));
            return false;
      }
      if (*cp) {
            cp1 = cp;
      } else {
            list_var(v, false, false);
            strcpy(prompt_str, var_str);
            strcat(prompt_str, " = ");
            if ((cp1 = getstring((char *) scratch, n_tokens * sizeof(token_type))) == NULL)
                  return false;
      }
      d1 = strtod(cp1, &cp);
      if (cp1 == cp || fmod(d1, 1.0) != 0.0) {
            printf(_("Error: not an integer.\n"));
            return false;
      }
      cp = skip_space(cp);
      if (*cp) {
            cp1 = cp;
      } else {
            strcpy(prompt_str, _("To: "));
            if ((cp1 = getstring((char *) scratch, n_tokens * sizeof(token_type))) == NULL)
                  return false;
      }
      d2 = strtod(cp1, &cp);
      if (cp1 == cp || fmod(d2, 1.0) != 0.0) {
            printf(_("Error: not an integer.\n"));
            return false;
      }
      if (extra_garbage(cp))
            return false;
      count_down = (d2 < d1);
      rhs[result_en][0].kind = CONSTANT;
      rhs[result_en][0].level = 1;
      if (product_flag) {
            rhs[result_en][0].token.constant = 1.0;
      } else {
            rhs[result_en][0].token.constant = 0.0;
      }
      n = 1;
      for (; count_down ? (d1 >= d2) : (d1 <= d2); count_down ? (d1 -= 1.0) : (d1 += 1.0)) {
            if (n + 1 + n_rhs[cur_equation] > n_tokens) {
                  error_huge();
            }
            blt(tlhs, rhs[cur_equation], n_rhs[cur_equation] * sizeof(token_type));
            n_tlhs = n_rhs[cur_equation];
            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 = d1;
                  }
            }
            for (i = 0; i < n_tlhs; i++) {
                  tlhs[i].level++;
            }
            for (i = 0; i < n; i++) {
                  rhs[result_en][i].level++;
            }
            rhs[result_en][n].kind = OPERATOR;
            rhs[result_en][n].level = 1;
            if (product_flag) {
                  rhs[result_en][n].token.operatr = TIMES;
            } else {
                  rhs[result_en][n].token.operatr = PLUS;
            }
            n++;
            blt(&rhs[result_en][n], tlhs, n_tlhs * sizeof(token_type));
            n += n_tlhs;
            calc_simp(rhs[result_en], &n);
      }
      if (n == 1 && rhs[result_en][0].kind == CONSTANT) {
            list_proc(rhs[result_en], n, false);
            fprintf(gfp, "\n");
      } else {
            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];
            cur_equation = result_en;
            list_sub(result_en);
      }
      return true;
}

/*
 * This function is for the "optimize" command.
 * It finds and substitutes all occurrences of "en"
 * in "equation".
 * It should be called repeatedly until it returns false.
 */
int
find_more(equation, np, en)
token_type  *equation;
int         *np;        /* length of "equation" */
int         en;         /* equation number */
{
      int   i, j, k;
      int   level;
      int   diff_sign;
      int   found_se;
      long  v;

      found_se = true;
      for (level = 1; 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
                      && se_compare(&equation[k], j - k,
                      rhs[en], n_rhs[en], &diff_sign)) {
                        v = lhs[en][0].token.variable;
                        if (diff_sign) {
                              blt(&equation[i+2], &equation[j], (*np - j) * sizeof(token_type));
                              *np -= (j - (i + 2));
                              equation[k].level = level + 1;
                              equation[k].kind = CONSTANT;
                              equation[k].token.constant = -1.0;
                              k++;
                              equation[k].level = level + 1;
                              equation[k].kind = OPERATOR;
                              equation[k].token.operatr = TIMES;
                              k++;
                              equation[k].level = level + 1;
                              equation[k].kind = VARIABLE;
                              equation[k].token.variable = v;
                        } 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 = v;
                        }
                        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.
 */
int
opt_es(equation, np)
token_type  *equation;
int         *np;
{
      int   i, j, k;
      int   i1, j1, k1;
      int   i2;
      int   level, level1;
      int   diff_sign;
      int   found_se, found_se1;
      long  v;

      found_se = true;
      for (level = 1; 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) {
                        found_se1 = true;
                        for (level1 = 1; found_se1; level1++) {
                              for (i1 = 1, found_se1 = false; i1 < *np; i1 = j1 + 2) {
                                    for (j1 = i1; j1 < *np && equation[j1].level > level1; j1 += 2) {
                                    }
                                    if (j1 == i1) {
                                          continue;
                                    }
                                    found_se1 = true;
                                    if (i1 <= j)
                                          continue;
                                    k1 = i1 - 1;
                                    if ((j1 - k1) >= OPT_MIN_SIZE
                                        && se_compare(&equation[k], j - k,
                                        &equation[k1], j1 - k1, &diff_sign)) {
                                          if (last_temp_var > MAX_SUBSCRIPT) {
                                                last_temp_var = 0;
                                          }
                                          v = V_TEMP + (((long) last_temp_var) << VAR_SHIFT);
                                          last_temp_var++;
                                          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[j1], (*np - j1) * sizeof(token_type));
                                                *np -= (j1 - (i1 + 2));
                                                equation[k1].level = level1 + 1;
                                                equation[k1].kind = CONSTANT;
                                                equation[k1].token.constant = -1.0;
                                                k1++;
                                                equation[k1].level = level1 + 1;
                                                equation[k1].kind = OPERATOR;
                                                equation[k1].token.operatr = TIMES;
                                                k1++;
                                                equation[k1].level = level1 + 1;
                                                equation[k1].kind = VARIABLE;
                                                equation[k1].token.variable = v;
                                          } else {
                                                blt(&equation[i1], &equation[j1], (*np - j1) * sizeof(token_type));
                                                *np -= (j1 - 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;
      int   i1;
      int   rv;

      if ((i = get_default_en(cp)) < 0)
            return false;
      rv = false;
      opt_en[0] = -1;
      simp_sub(i);
      for (j = 0; j < n_lhs[i]; j += 2) {
            if (lhs[i][j].kind == VARIABLE
                && (lhs[i][j].token.variable & VAR_MASK) == V_TEMP) {
                  rv = true;
            }
      }
      for (j = 0; j < n_rhs[i]; j += 2) {
            if (rhs[i][j].kind == VARIABLE
                && (rhs[i][j].token.variable & VAR_MASK) == V_TEMP) {
                  rv = true;
            }
      }
      if (rv) {
            printf(_("Temporary variable \"temp\" already in use in specified equation.\n"));
            printf(_("Please rename.\n"));
            return false;
      }
      while (opt_es(lhs[i], &n_lhs[i])) {
            rv = true;
      }
      while (opt_es(rhs[i], &n_rhs[i])) {
            rv = true;
      }
      if (rv) {
            for (i1 = 0; opt_en[i1] >= 0; i1++) {
                  for (j = 0; 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 (j = 0; opt_en[j] >= 0; j++) {
                  list_sub(opt_en[j]);
            }
            list_sub(i);
      } else {
            printf(_("Unable to find any repeated expressions.\n"));
      }
      return rv;
}

/*
 * The set command.
 */
int
set_cmd(cp)
char  *cp;
{
      char  buf[MAX_CMD_LEN];

      if (*cp == '\0') {
            printf(_("Options are set as follows:\n\n"));
#if   !SILENT
            printf("debug_level = %d\n", debug_level);
#endif
            if (!case_sensitive_flag) {
                  printf("no ");
            }
            printf("case_sensitive\n");

            if (!color_flag) {
                  printf("no ");
            }
            printf("color\n");

            printf("columns = %d\n", screen_columns);

            if (!groupall) {
                  printf("no ");
            }
            printf("display2d\n");

            if (!preserve_roots) {
                  printf("no ");
            }
            printf("preserve_roots\n");

            if (!true_modulus) {
                  printf("no ");
            }
            printf("true_modulus\n");

            if (!finance_option) {
                  printf("no ");
            }
            printf("finance\n");

#if   !SECURE
            if (getcwd(buf, sizeof(buf))) {
                  printf("directory = %s\n", buf);
            }
#endif
            return true;
      }
      return set_options(cp);
}

int
isno(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 "set" command.
 *
 * Return false if error.
 */
int
set_options(cp)
char  *cp;
{
      int   negate;

      cp = skip_space(cp);
      if (*cp == '\0') {
            return true;
      }
      negate = isno(cp);
      if (negate) {
            cp = skip_param(cp);
      }
#if   !SECURE
      if (strncasecmp(cp, "dir", 3) == 0) {
            cp = skip_param(cp);
            if (chdir(cp)) {
                  printf(_("Error changing directory.\n"));
                  return false;
            }
            return true;
      }
#endif
#if   !SILENT
      if (strncasecmp(cp, "debug", 5) == 0) {
            cp = skip_param(cp);
            negate = (negate || isno(cp));
            if (negate) {
                  debug_level = 0;
            } else {
                  if (*cp == '\0') {
                        printf(_("Please specify a debug level number.\n"));
                        return false;
                  }
                  debug_level = atoi(cp);
            }
            return true;
      }
#endif
      if (strncasecmp(cp, "columns", 7) == 0) {
            cp = skip_param(cp);
            negate = (negate || isno(cp));
            if (negate) {
                  screen_columns = 0;
            } else {
                  if (*cp == '\0') {
                        printf(_("Please specify how wide the screen is in columns.\n"));
                        return false;
                  }
                  screen_columns = atoi(cp);
            }
            return true;
      }
      if (strncasecmp(cp, "case", 4) == 0) {
            cp = skip_param(cp);
            negate = (negate || isno(cp));
            case_sensitive_flag = !negate;
            return true;
      }
      if (strncasecmp(cp, "display2d", 7) == 0) {
            cp = skip_param(cp);
            negate = (negate || isno(cp));
            groupall = !negate;
            return true;
      }
      if (strncasecmp(cp, "preserve", 8) == 0) {
            cp = skip_param(cp);
            negate = (negate || isno(cp));
            preserve_roots = !negate;
            return true;
      }
      if (strncasecmp(cp, "true", 4) == 0) {
            cp = skip_param(cp);
            negate = (negate || isno(cp));
            true_modulus = !negate;
            return true;
      }
      if (strncasecmp(cp, "color", 5) == 0) {
            cp = skip_param(cp);
            negate = (negate || isno(cp));
            color_flag = !negate;
            return true;
      }
      if (strncasecmp(cp, "finance", 7) == 0) {
            cp = skip_param(cp);
            negate = (negate || isno(cp));
            finance_option = !negate;
            return true;
      }
      printf(_("Unknown set option \"%s\".\n"), cp);
      return false;
}

/*
 * The pause command.
 */
int
pause_cmd(cp)
char  *cp;
{
      char  *cp1;
      char  buf[100];

      strcpy(prompt_str, _(" ==== Please press Enter ==== "));
      if ((cp1 = getstring(buf, sizeof(buf))) == NULL) {
            return false;
      }
      if (strncasecmp(cp1, "quit", 4) == 0
          || strncasecmp(cp1, "abort", 5) == 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(&cp, &i, &j)) {
            return false;
      }
      if (extra_garbage(cp))
            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();
                  blt(lhs[k], lhs[i1], n_lhs[i1] * sizeof(token_type));
                  n_lhs[k] = n_lhs[i1];
                  blt(rhs[k], rhs[i1], n_rhs[i1] * sizeof(token_type));
                  n_rhs[k] = n_rhs[i1];
                  list_sub(k);
            }
      }
      return true;
}

int
complex_sub(cp, imag_flag)
char  *cp;
int   imag_flag;
{
      int   i, j, k;
      int   beg;
      int   found_imag;
      int   has_imag, has_real;

      if ((i = get_default_en(cp)) < 0)
            return false;
      if (n_lhs[i] != 1) {
            printf(_("Please solve this equation first.\n"));
            return false;
      }
      j = next_espace();
      uf_simp(rhs[i], &n_rhs[i]);
      factorv(rhs[i], &n_rhs[i], (long) IMAGINARY);
      partial_flag = false;
      uf_simp(rhs[i], &n_rhs[i]);
      partial_flag = true;
      n_rhs[j] = 1;
      rhs[j][0].level = 1;
      rhs[j][0].kind = CONSTANT;
      rhs[j][0].token.constant = 0.0;
      has_imag = false;
      has_real = false;
      k = 0;
      for (beg = k; beg < n_rhs[i]; beg = k, k++) {
            found_imag = false;
            for (;; k++) {
                  if (k >= n_rhs[i])
                        break;
                  if (rhs[i][k].level == 1 && rhs[i][k].kind == OPERATOR
                      && (rhs[i][k].token.operatr == PLUS || rhs[i][k].token.operatr == MINUS)) {
                        break;
                  }
                  if (rhs[i][k].kind == VARIABLE && rhs[i][k].token.variable == IMAGINARY) {
                        found_imag = true;
                  }
            }
            if (found_imag)
                  has_imag = true;
            else
                  has_real = true;
            if (found_imag == imag_flag) {
                  if (beg == 0) {
                        n_rhs[j] = 0;
                  }
                  blt(&rhs[j][n_rhs[j]], &rhs[i][beg], (k - beg) * sizeof(token_type));
                  n_rhs[j] += (k - beg);
            }
      }
      if (!has_imag) {
            printf(_("No imaginary parts found.  Equation is not complex.\n"));
            return false;
      }
      if (!has_real) {
            printf(_("No real parts found.  Equation is not complex.\n"));
            return false;
      }
      blt(lhs[j], lhs[i], n_lhs[i] * sizeof(token_type));
      n_lhs[j] = n_lhs[i];
      simp_divide(rhs[j], &n_rhs[j], 0L);
      cur_equation = j;
      list_sub(cur_equation);
      return true;
}

/*
 * The real command.
 */
int
real(cp)
char  *cp;
{
      return complex_sub(cp, false);
}

/*
 * The imaginary command.
 */
int
imaginary(cp)
char  *cp;
{
      return complex_sub(cp, true);
}

/*
 * Do simplifications and approximations for the calculate command.
 */
calc_simp(equation, np)
token_type  *equation;
int         *np;
{
      in_calc_cmd = true;
      subst_constants(equation, np);
      simp_side(equation, np);
      uf_simp(equation, np);
      factorv(equation, np, (long) IMAGINARY);
      simp_side(equation, np);
      uf_simp(equation, np);
      in_calc_cmd = false;
}

/*
 * The tally command.
 */
int
tally(cp)
char  *cp;
{
      int   i;

      if (extra_garbage(cp))
            return false;
      trhs[0].kind = CONSTANT;
      trhs[0].level = 1;
      trhs[0].token.constant = 0.0;
      n_trhs = 1;
      for (;;) {
            printf(_("Running total = "));
            list_proc(trhs, n_trhs, false);
            printf("\n");
            strcpy(prompt_str, _("Enter value: "));
            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);
      }
      return true;
}

/*
 * The calculate command.
 */
int
calculate(cp)
char  *cp;
{
      int         i, j, k;
      long        last_v;
      long        v;
      long        counter;
      long        counter_max;
      sign_array_type   sa_mark;
      sign_array_type   sa_value;
      int         iterations;
      long        it_v;
      int         found;
      int         n;

      iterations = 1;
      it_v = 0;
      i = cur_equation;
      if (notdefined(i))
            return false;
      if (*cp) {
            cp = parse_var2(&it_v, cp);
            if (cp == NULL) {
                  return false;
            }
            iterations = atoi(cp);
            if (iterations <= 0) {
                  printf(_("Invalid number of iterations.\n"));
                  return false;
            }
            cp = skip_num(cp);
            if (extra_garbage(cp))
                  return false;
      }
      if (it_v) {
            found = false;
            for (j = 0; j < n_rhs[i]; j++) {
                  if (rhs[i][j].kind == VARIABLE) {
                        if (rhs[i][j].token.variable == it_v)
                              found = true;
                  }
            }
            if (!found) {
                  printf(_("Iteration variable not found in RHS.\n"));
                  return false;
            }
      }
      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_rhs[i]; j += 2) {
                  if (rhs[i][j].kind == VARIABLE && rhs[i][j].token.variable > IMAGINARY) {
                        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 ((v & VAR_MASK) == SIGN || v == it_v) {
                  continue;
            }
            list_var(v, false, false);
            sprintf(prompt_str, _("Enter %s: "), var_str);
            if (!get_expr(tlhs, &n_tlhs)) {
                  continue;
            }
            for (j = 0; j < n_tlhs; j++)
                  if (tlhs[j].kind == VARIABLE)
                        tlhs[j].token.variable = -tlhs[j].token.variable;
            subst_var_with_exp(trhs, &n_trhs, tlhs, n_tlhs, v);
      }
      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, false, false);
            sprintf(prompt_str, _("Enter initial %s: "), var_str);
            while (!get_expr(scratch, &n))
                  ;
            blt(tlhs, trhs, n_trhs * sizeof(token_type));
            n_tlhs = n_trhs;
            for (j = 0; j < iterations; j++) {
                  blt(trhs, tlhs, n_tlhs * sizeof(token_type));
                  n_trhs = n_tlhs;
                  subst_var_with_exp(trhs, &n_trhs, scratch, n, it_v);
                  calc_simp(trhs, &n_trhs);
                  blt(scratch, trhs, n_trhs * sizeof(token_type));
                  n = n_trhs;
            }
      } else {
            simp_side(trhs, &n_trhs);
      }
      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) - 1;
      counter = 0;
      for (; 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), true, false);
                        fprintf(gfp, " = ");
                        if (sa_value[j]) {
                              fprintf(gfp, "-1");
                        } else {
                              fprintf(gfp, "1");
                        }
                        k = true;
                  }
            }
            if (k)
                  fprintf(gfp, ":\n");
            calc_simp(tlhs, &n_tlhs);
            fprintf(gfp, " ");
            list_proc(lhs[i], n_lhs[i], false);
            fprintf(gfp, " = ");
            list_proc(tlhs, n_tlhs, false);
            fprintf(gfp, "\n");
      }
      return true;
}

/*
 * The clear command.
 */
int
clear(cp)
char  *cp;
{
      int   i, j;

      if (is_all(cp)) {
            cur_equation = 0;
            for (i = 0; i < n_equations; i++) {
                  n_lhs[i] = 0;
            }
            for (i = 0; var_names[i]; i++) {
                  free(var_names[i]);
            }
            var_names[0] = NULL;
      } else {
            if (!get_range(&cp, &i, &j)) {
                  return false;
            }
            if (extra_garbage(cp))
                  return false;
            for (; i <= j; i++) {
                  n_lhs[i] = 0;
            }
      }
      return true;
}

int
compare_rhs(i, j, diff_signp)
int   i, j;
int   *diff_signp;
{
      int   rv;

      sign_flag = true;
      rv = se_compare(rhs[i], n_rhs[i], rhs[i], n_rhs[i], diff_signp);
      sign_flag = false;
      if (!rv || *diff_signp) {
            printf(_("Error in compare function or too many terms to compare!\n"));
            longjmp(jmp_save, 2);
      }
      sign_flag = true;
      rv = se_compare(rhs[i], n_rhs[i], rhs[j], n_rhs[j], diff_signp);
      sign_flag = false;
      return rv;
}

/*
 * The compare command.
 */
int
compare(cp)
char  *cp;
{
      int         i, j;
      token_type  want;
      int         diff_sign;
      int         already_solved;

      i = atoi(cp) - 1;
      cp = skip_num(cp);
      if (notdefined(i)) {
            return false;
      }
      if (strcmp_tospace(cp, "with") == 0) {
            cp = skip_space(cp + 4);
      }
      if ((j = get_default_en(cp)) < 0) {
            return false;
      }
      if (i == j) {
            printf(_("Cannot compare an equation with itself.\n"));
            return false;
      }
      printf(_("Comparing equation #%d with #%d...\n"), i + 1, j + 1);
      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;
            }
            printf(_("Simplifying both equations...\n"));
            simpa_side(rhs[i], &n_rhs[i], false, false);
            list_sub(i);
            simpa_side(rhs[j], &n_rhs[j], false, false);
            list_sub(j);
            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;
            }
      }
      printf(_("Solving both equations for zero and unfactoring...\n"));
      want.level = 1;
      want.kind = CONSTANT;
      want.token.constant = 0.0;
      if (!solve_sub(&want, 1, lhs[i], &n_lhs[i], rhs[i], &n_rhs[i])
          || !solve_sub(&want, 1, lhs[j], &n_lhs[j], rhs[j], &n_rhs[j])) {
            printf(_("Can't solve for zero!\n"));
            return false;
      }
      uf_simp(rhs[i], &n_rhs[i]);
      uf_simp(rhs[j], &n_rhs[j]);
      if (compare_rhs(i, j, &diff_sign)) {
            printf(_("Equations are identical.\n"));
            return true;
      }
      printf(_("Simplifying both equations...\n"));
      simpa_side(rhs[i], &n_rhs[i], false, false);
      simpa_side(rhs[j], &n_rhs[j], false, false);
      if (compare_rhs(i, j, &diff_sign)) {
            printf(_("Equations are identical.\n"));
            return true;
      }
      if (!solve_sub(&want, 1, lhs[i], &n_lhs[i], rhs[i], &n_rhs[i])
          || !solve_sub(&want, 1, lhs[j], &n_lhs[j], rhs[j], &n_rhs[j])) {
            printf(_("Can't solve for zero!\n"));
            return false;
      }
      uf_simp(rhs[i], &n_rhs[i]);
      uf_simp(rhs[j], &n_rhs[j]);
      if (compare_rhs(i, j, &diff_sign)) {
            printf(_("Equations are identical.\n"));
            return true;
      }
      printf(_("Equations may differ.\n"));
      return false;
times_neg1:
      if (!diff_sign && lhs[i][0].token.variable == lhs[j][0].token.variable) {
            printf(_("Equations are identical.\n"));
            return true;
      }
      printf(_("Variable ("));
      list_proc(lhs[i], n_lhs[i], false);
      printf(_(") in the first equation is equal to ("));
      if (diff_sign) {
            printf("-");
      }
      list_proc(lhs[j], n_lhs[j], false);
      printf(_(") in the second equation.\n"));
      return(!diff_sign);
}

/*
 * The divide command.
 */
int
divide_cmd(cp)
char  *cp;
{
      long  v, v_tmp;
      int   i, j;
      int   nl, nr;
      double      d1, d2;
      double      d3, d4;

      v = 0;
      if (*cp) {
            cp = parse_var2(&v, cp);
            if (cp == NULL) {
                  return false;
            }
            if (extra_garbage(cp))
                  return false;
      }
      i = next_espace();
      strcpy(prompt_str, _("Enter dividend: "));
      if (!get_expr(rhs[i], &nr)) {
            return false;
      }
      strcpy(prompt_str, _("Enter divisor: "));
      if (!get_expr(lhs[i], &nl)) {
            return false;
      }
      printf("\n");
      simp_loop(lhs[i], &nl);
      simp_loop(rhs[i], &nr);
      uf_simp(lhs[i], &nl);
      uf_simp(rhs[i], &nr);
      if (nl == 1 && lhs[i][0].kind == CONSTANT
          && nr == 1 && rhs[i][0].kind == CONSTANT) {
            d1 = rhs[i][0].token.constant;
            d2 = lhs[i][0].token.constant;
            d4 = modf(d1 / d2, &d3);
            printf(_("Result of numerical division: %.14g\n"), d1 / d2);
            printf(_("Quotient: %.14g, Remainder: %.14g\n"), d3, d4 * d2);
            ngcd(d1, d2);
            return true;
      }
      v_tmp = v;
      if (poly_div(rhs[i], nr, lhs[i], nl, &v_tmp)) {
            simp_divide(tlhs, &n_tlhs, 0L);
            simp_divide(trhs, &n_trhs, 0L);
            list_var(v_tmp, false, false);
            printf(_("Polynomial division successful using variable (%s).\n"), var_str);
            printf(_("The quotient is:\n"));
            list_proc(tlhs, n_tlhs, false);
            printf(_("\n\nThe remainder is:\n"));
            list_proc(trhs, n_trhs, false);
            printf("\n");
      } else {
            printf(_("Polynomial division failed.\n"));
      }
      printf("\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, 0L);
            printf(_("Found polynomial Greatest Common Divisor (iterations = %d):\n"), j);
            list_proc(trhs, n_trhs, false);
            printf("\n");
      } else {
            printf(_("No univariate polynomial GCD found.\n"));
      }
      return true;
}

/*
 * The eliminate command.
 */
int
eliminate(cp)
char  *cp;
{
      long  v;
      int   i;
      int   n;
      int   using_flag;
      char  used[N_EQUATIONS];
      int   did_something;
      int   vc;
      long  last_v, v1;
      long  va[MAX_VARS];

      did_something = false;
      vc = 0;
      for (i = 0; i < ARR_CNT(used); i++)
            used[i] = false;
      if (notdefined(cur_equation)) {
            return false;
      }
      if (is_all(cp)) {
            cp = skip_param(cp);
            if (extra_garbage(cp))
                  return false;
            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;
                  }
            }
      }
next_var:
      if (*cp) {
            cp = parse_var2(&v, cp);
            if (cp == NULL) {
                  return false;
            }
      } else if (vc) {
            v = va[--vc];
      } else {
            if (did_something) {
                  list_sub(cur_equation);
            }
            return did_something;
      }
      if (!found_variable(cur_equation, v)) {
            list_var(v, false, false);
            printf(_("Variable (%s) not found in current equation.\n"), var_str);
            goto next_var;
      }
      using_flag = (strcmp_tospace(cp, "using") == 0);
      if (using_flag) {
            cp = skip_space(cp + 5);
            i = atoi(cp) - 1;
            cp = skip_num(cp);
            if (notdefined(i)) {
                  return false;
            }
            if (i == cur_equation) {
                  printf(_("Error: source and destination equations are the same equation.\n"));
                  return false;
            }
            if (!elim_sub(i, v))
                  goto next_var;
      } else {
            n = 1;
            i = cur_equation;
            for (;; n++) {
                  if (n >= n_equations) {
                        list_var(v, false, false);
                        printf(_("Variable (%s) not found in any other equation.\n"), var_str);
                        goto next_var;
                  }
                  if (i <= 0)
                        i = n_equations - 1;
                  else
                        i--;
                  if (used[i])
                        continue;
                  if (found_variable(i, v)) {
                        if (elim_sub(i, v))
                              break;
                  }
            }
      }
      did_something = true;
      simp_sub(cur_equation);
      used[i] = true;
      goto next_var;
}

/*
 * Return true if equation number "i" is solved for a variable.
 */
int
solved_equation(i)
int   i;
{
      int   k;

      if (n_lhs[i] != 1 || lhs[i][0].kind != VARIABLE)
            return false;
      for (k = 0; k < n_rhs[i]; k += 2) {
            if (rhs[i][k].kind == VARIABLE
                && rhs[i][k].token.variable == lhs[i][0].token.variable) {
                  return false;
            }
      }
      return true;
}

/*
 * Return true if variable "v" exists in equation number "i".
 */
int
found_variable(i, v)
int   i;
long  v;
{
      int   j;

      if (n_lhs[i] <= 0)
            return false;
      for (j = 0; j < n_lhs[i]; j += 2) {
            if (lhs[i][j].kind == VARIABLE && lhs[i][j].token.variable == v) {
                  return true;
            }
      }
      for (j = 0; j < n_rhs[i]; j += 2) {
            if (rhs[i][j].kind == VARIABLE && rhs[i][j].token.variable == v) {
                  return true;
            }
      }
      return false;
}

/*
 * Substitute every instance of "v" in "equation" with "exp".
 */
subst_var_with_exp(equation, np, exp, len, v)
token_type  *equation;
int         *np;        /* pointer to equation length */
token_type  *exp;
int         len;        /* exp length */
long        v;
{
      int   i, j, k;
      int   level;

      for (j = *np - 1; j >= 0; j--) {
            if (equation[j].kind == VARIABLE && equation[j].token.variable == v) {
                  level = equation[j].level;
                  if (*np + len - 1 > n_tokens) {
                        error_huge();
                  }
                  blt(&equation[j+len], &equation[j+1], (*np - (j + 1)) * sizeof(token_type));
                  *np += len - 1;
                  blt(&equation[j], exp, len * sizeof(token_type));
                  for (k = j; k < j + len; k++)
                        equation[k].level += level;
            }
      }
}

int
elim_sub(i, v)
int   i;
long  v;
{
      token_type  want;

#if   !SILENT
      list_var(v, false, false);
      printf(_("Solving equation #%d for (%s)...\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])) {
#if   !SILENT
            printf(_("Solve failed.\n"));
#endif
            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);
      return true;
}

/*
 * The group command.
 *
 * Displays equations in fraction format.
 */
int
group_cmd(cp)
char  *cp;
{
      int   i, j;
      jmp_buf     save_save;
      int   factor_flag;

      factor_flag = false;
      if (strcmp_tospace(cp, "factor") == 0) {
            factor_flag = true;
            cp = skip_param(cp);
      }
      if (!get_range(&cp, &i, &j)) {
            return false;
      }
      if (extra_garbage(cp))
            return false;
      blt(save_save, jmp_save, sizeof(jmp_save));
      if (setjmp(jmp_save) != 0) {
            i++;
            printf(_("Skipping equation #%d.\n"), i);
      }
      for (; i <= j; i++) {
            if (n_lhs[i] > 0) {
                  group_sub(i);
                  if (factor_flag) {
                        factor_int(lhs[i], &n_lhs[i]);
                        factor_int(rhs[i], &n_rhs[i]);
                  }
                  flist_sub(i);
            }
      }
      blt(jmp_save, save_save, sizeof(jmp_save));
      return true;
}

/*
 * The list command.
 */
int
list_cmd(cp)
char  *cp;
{
      int   i, j;
      int   export_flag;

      export_flag = false;
      if (strcmp_tospace(cp, "export") == 0) {
            cp = skip_param(cp);
            export_flag = true;
      }
      if (!get_range(&cp, &i, &j)) {
            return false;
      }
      if (extra_garbage(cp))
            return false;
      for (; i <= j; i++) {
            if (n_lhs[i] > 0) {
                  list1_sub(i, export_flag);
            }
      }
      return true;
}

/*
 * The code command.
 */
int
list_code(cp)
char  *cp;
{
      int   i, j;
      int   java_flag;
      int   int_flag;

      java_flag = false;
      int_flag = false;
      if (strcmp_tospace(cp, "c") == 0) {
            cp = skip_param(cp);
      } else if (strcmp_tospace(cp, "java") == 0) {
            cp = skip_param(cp);
            java_flag = true;
      } else if (strcmp_tospace(cp, "integer") == 0) {
            cp = skip_param(cp);
            int_flag = true;
      }
      if (!get_range(&cp, &i, &j)) {
            return false;
      }
      if (extra_garbage(cp))
            return false;
      for (; i <= j; i++) {
            if (n_lhs[i] > 0) {
                  if (n_lhs[i] != 1 || lhs[i][0].kind != VARIABLE) {
                        printf(_("LHS is not a variable in equation #%d.\n"), i + 1);
                        continue;
                  }
                  in_calc_cmd = true;
                  if (int_flag) {
                        elim_loop(rhs[i], &n_rhs[i]);
                        uf_repeat_always(rhs[i], &n_rhs[i]);
                  }
                  group_sub(i);
                  in_calc_cmd = false;
                  if (int_flag) {
                        if (!int_expr(rhs[i], n_rhs[i])) {
                              printf(_("Equation #%d is not an integer equation.\n"), i + 1);
                              continue;
                        }
                  }
                  list_c_code(lhs[i], n_lhs[i], java_flag, int_flag);
                  fprintf(gfp, " = ");
                  list_c_code(rhs[i], n_rhs[i], java_flag, int_flag);
                  fprintf(gfp, ";\n\n");
            }
      }
      return true;
}

/*
 * The replace command.
 */
int
replace(cp)
char  *cp;
{
      int   i, j;
      int   n;
      long  last_v;
      long  v;
      char  *cp_start;
      long  va[MAX_VARS];
      int   vc;
      int   found;
      char  *cp1;

      cp_start = cp;
      i = cur_equation;
      if (notdefined(i)) {
            return false;
      }
      for (vc = 0; (cp != NULL) && *cp; vc++) {
            if (strcmp_tospace(cp, "with") == 0) {
                  if (vc)
                        break;
                  return false;
            }
            if (vc >= ARR_CNT(va)) {
                  printf(_("Too many variables specified!\n"));
                  return false;
            }
            cp = parse_var2(&va[vc], cp);
            if (cp == NULL) {
                  return false;
            }
            if (!found_variable(i, va[vc])) {
                  list_var(va[vc], false, false);
                  printf(_("Variable (%s) not found in current equation.\n"), var_str);
                  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++) {
                  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++) {
                  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_space(cp + 4);
                        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_garbage(cp1))
                              return false;
                        goto do_this;
                  }
            }
            list_var(v, false, false);
            sprintf(prompt_str, _("Enter %s: "), var_str);
            if (!get_expr(scratch, &n)) {
                  continue;
            }
do_this:
            for (j = 0; j < n; j++) {
                  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);
      }
      for (j = 0; j < n_tlhs; j++)
            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++)
            if (trhs[j].kind == VARIABLE && trhs[j].token.variable < 0)
                  trhs[j].token.variable = -trhs[j].token.variable;
      simp_loop(tlhs, &n_tlhs);
      simp_loop(trhs, &n_trhs);
      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));
      list_sub(i);
      return true;
}

/*
 * The sensitivity command.
 */
int
sensitivity(cp)
char  *cp;
{
      long  va[MAX_VARS];
      char  fa[ARR_CNT(va)];
      int   vc;
      int   i, j, k;
      int   n;
      int   er;
      int   level;
      token_type  *ep;
      token_type  want;

      if (notdefined(cur_equation)) {
            return false;
      }
      if (*cp == '\0') {
            if (!prompt_var(&va[0]))
                  return false;
            vc = 1;
      } else {
            for (vc = 0; (cp != NULL) && *cp; vc++) {
                  if (vc >= ARR_CNT(va)) {
                        printf(_("Too many variables specified!\n"));
                        return false;
                  }
                  cp = parse_var2(&va[vc], cp);
                  if (cp == NULL) {
                        return false;
                  }
            }
      }
      for (i = 0; i < vc; i++) {
            if ((va[i] & VAR_MASK) <= SIGN || (va[i] & PERCENT_CHANGE)) {
                  printf(_("One of the variables specified is not a normal variable!\n"));
                  return false;
            }
            fa[i] = false;
      }
      i = next_espace();
      er = !solved_equation(cur_equation);
      if (!er) {
            er = ((lhs[cur_equation][0].token.variable & VAR_MASK) <= SIGN
                || (lhs[cur_equation][0].token.variable & PERCENT_CHANGE));
      }
      if (er) {
            printf(_("Please solve this equation for a normal variable and try again.\n"));
            return false;
      }
      n = n_rhs[cur_equation];
      blt(rhs[i], rhs[cur_equation], n * sizeof(token_type));
      n_rhs[i] = n;
      blt(lhs[i], rhs[cur_equation], n * sizeof(token_type));
      for (j = n_rhs[i] - 1; j >= 0; j--) {
            if (rhs[i][j].kind == VARIABLE) {
                  for (k = 0; k < vc; k++) {
                        if (rhs[i][j].token.variable == va[k])
                              break;
                  }
                  if (k >= vc)
                        continue;
                  fa[k] = true;
                  if (n_rhs[i] + 6 > n_tokens) {
                        error_huge();
                  }
                  blt(&rhs[i][j+7], &rhs[i][j+1], (n_rhs[i] - (j + 1)) * sizeof(token_type));
                  n_rhs[i] += 6;
                  level = ++rhs[i][j].level;
                  ep = &rhs[i][j+1];
                  ep->level = level;
                  ep->kind = OPERATOR;
                  ep->token.operatr = TIMES;
                  ep++;
                  ep->level = level + 1;
                  ep->kind = CONSTANT;
                  ep->token.constant = 1.0;
                  ep++;
                  ep->level = level + 1;
                  ep->kind = OPERATOR;
                  ep->token.operatr = PLUS;
                  ep++;
                  ep->level = level + 2;
                  ep->kind = VARIABLE;
                  ep->token.variable = va[k] | PERCENT_CHANGE;
                  ep++;
                  ep->level = level + 2;
                  ep->kind = OPERATOR;
                  ep->token.operatr = DIVIDE;
                  ep++;
                  ep->level = level + 2;
                  ep->kind = CONSTANT;
                  ep->token.constant = 100.0;
            }
      }
      er = false;
      for (j = 0; j < vc; j++) {
            if (!fa[j]) {
                  list_var(va[j], false, false);
                  printf(_("Variable (%s) not found in RHS.\n"), var_str);
                  er = true;
            }
      }
      if (er) {
            return false;
      }
      for (j = 0; j < n; j++)
            lhs[i][j].level++;
      if (n + 6 > n_tokens) {
            error_huge();
      }
      ep = &lhs[i][n];
      ep->level = 1;
      ep->kind = OPERATOR;
      ep->token.operatr = TIMES;
      ep++;
      ep->level = 2;
      ep->kind = CONSTANT;
      ep->token.constant = 1.0;
      ep++;
      ep->level = 2;
      ep->kind = OPERATOR;
      ep->token.operatr = PLUS;
      ep++;
      ep->level = 3;
      ep->kind = VARIABLE;
      want.level = 1;
      want.kind = VARIABLE;
      want.token.variable = lhs[cur_equation][0].token.variable | PERCENT_CHANGE;
      ep->token.variable = want.token.variable;
      ep++;
      ep->level = 3;
      ep->kind = OPERATOR;
      ep->token.operatr = DIVIDE;
      ep++;
      ep->level = 3;
      ep->kind = CONSTANT;
      ep->token.constant = 100.0;
      n += 6;
      if (!solve_sub(&want, 1, lhs[i], &n, rhs[i], &n_rhs[i])) {
            printf(_("Solve failed!\n"));
            return false;
      }
      n_lhs[i] = n;
      cur_equation = i;
      list_sub(cur_equation);
      return true;
}

/*
 * The simplify command.
 */
int
simplify(cp)
char  *cp;
{
      int   i, j;
      int   poly_flag;
      int   quick_flag;
      int   symb;

      poly_flag = false;
      quick_flag = false;
      symb = false;
check_again:
      if (strncasecmp(cp, "poly", 4) == 0) {
            poly_flag = true;
            cp = skip_param(cp);
            goto check_again;
      }
      if (strncasecmp(cp, "symbolic", 4) == 0) {
            symb = true;
            cp = skip_param(cp);
            goto check_again;
      }
      if (strncasecmp(cp, "quick", 4) == 0) {
            quick_flag = true;
            cp = skip_param(cp);
            goto check_again;
      }
      if (!get_range(&cp, &i, &j)) {
            return false;
      }
      if (extra_garbage(cp))
            return false;
      symb_flag = symb;
      for (; i <= j; i++) {
            if (n_lhs[i] > 0) {
                  simpa_sub(i, poly_flag, quick_flag);
                  list_sub(i);
            }
      }
      symb_flag = false;
      return true;
}

/*
 * The factor command.
 */
int
factor(cp)
char  *cp;
{
      int   i, j;
      int   i1;
      long  v;
      double      d;

      if (strncasecmp(cp, "number", 6) == 0) {
            cp = skip_param(cp);
next_number:
            if (*cp == '\0') {
                  strcpy(prompt_str, _("Enter integers to factor: "));
                  cp = getstring((char *) scratch, n_tokens * sizeof(token_type));
                  if (cp == NULL)
                        return false;
            }
            d = strtod(cp, &cp);
            cp = skip_space(cp);
            if (!factor_one(d)) {
                  printf(_("Not a valid integer.\n"));
                  return false;
            }
            printf(_("%.0f = "), d);
            for (i = 0; i < uno;) {
                  printf(_("%.0f"), unique[i]);
                  if (ucnt[i] > 1) {
                        printf("^%d", ucnt[i]);
                  }
                  i++;
                  if (i < uno) {
                        printf(" * ");
                  }
            }
            printf("\n");
            if (d != multiply_out_unique()) {
                  printf(_("Error in computation!\n"));
                  return false;
            }
            if (*cp)
                  goto next_number;
            return true;
      }
      v = 0;
      if (!get_range(&cp, &i, &j)) {
            return false;
      }
      do {
            if (*cp) {
                  if ((cp = parse_var2(&v, cp)) == NULL) {
                        return false;
                  }
            }
            for (i1 = i; i1 <= j; i1++) {
                  if (n_lhs[i1] > 0) {
                        simpv_side(lhs[i1], &n_lhs[i1], v);
                        simpv_side(rhs[i1], &n_rhs[i1], v);
                  }
            }
      } while (*cp);
      for (i1 = i; i1 <= j; i1++) {
            list_sub(i1);
      }
      return true;
}

/*
 * The unfactor command.
 */
int
unfactor(cp)
char  *cp;
{
      int   i, j;
      int   fully_flag;

      fully_flag = false;
      if (strncasecmp(cp, "fully", 4) == 0) {
            fully_flag = true;
            cp = skip_param(cp);
      }
      if (!get_range(&cp, &i, &j)) {
            return false;
      }
      if (extra_garbage(cp))
            return false;
      partial_flag = !fully_flag;
      for (; i <= j; i++) {
            if (n_lhs[i] > 0) {
                  uf_simp(lhs[i], &n_lhs[i]);
                  uf_simp(rhs[i], &n_rhs[i]);
                  list_sub(i);
            }
      }
      partial_flag = true;
      return true;
}

/*
 * The quit command.
 */
int
quit(cp)
char  *cp;
{
      exit_program(0);
      return false;
}

#if   !SECURE
/*
 * The read command.
 */
int
read_in(cp)
char  *cp;
{
      int   rv;
      FILE  *fp;
      jmp_buf     save_save;
      char  buf[MAX_CMD_LEN];

      if (*cp == '\0') {
            return false;
      }
      fp = NULL;
      if (strlen(cp) < (sizeof(buf) - 5)) {
            strcpy(buf, cp);
            strcat(buf, ".in");
            fp = fopen(buf, "r");
      }
      if (fp == NULL) {
            fp = fopen(cp, "r");
            if (fp == NULL) {
                  printf(_("Can't open file \"%s\".\n"), cp);
                  return false;
            }
      }
      blt(save_save, jmp_save, sizeof(jmp_save));
      if ((rv = setjmp(jmp_save)) != 0) {
            clean_up();
            if (rv == 14)
                  printf(_("Expression too big!\n"));
            printf(_("Read operation aborted.\n"));
            goto end_read;
      }
      while (cp = fgets((char *) tlhs, n_tokens * sizeof(token_type), fp)) {
            input_column = printf("%d%s", cur_equation + 1, html_flag ? HTML_PROMPT : PROMPT);
            printf("%s", cp);
            if (!process(cp)) {
                  longjmp(jmp_save, 3);
            }
      }
end_read:
      blt(jmp_save, save_save, sizeof(jmp_save));
      fclose(fp);
      return(!rv);
}

/*
 * Load $HOME/.mathomaticrc
 *
 * Return false if error encountered.
 */
int
load_rc()
{
      int   i;
      FILE  *fp;
      char  buf[MAX_CMD_LEN];
      char  *cp;
      int   rv;

#if   CYGWIN
      strcpy(buf, dir_path);
      strcat(buf, "/");
      strcat(buf, RC_FILE);
      fp = fopen(buf, "r");
      if (fp == NULL) {
            return true;
      }
#else
      cp = getenv("HOME");
      if (cp == NULL)
            return true;
      strcpy(buf, cp);
      strcat(buf, "/");
      strcat(buf, RC_FILE);
      fp = fopen(buf, "r");
      if (fp == NULL)
            return true;
#endif
      rv = true;
      while (cp = fgets(buf, sizeof(buf), fp)) {
            i = strlen(cp) - 1;
            while (i >= 0 && (cp[i] == '\n' || cp[i] == '\r')) {
                  cp[i--] = '\0';
            }
            for (i = 0; cp[i]; i++) {
                  if (cp[i] == ';') {
                        cp[i] = '\0';
                        break;
                  }
            }
            if (!set_options(cp))
                  rv = false;
      }
      fclose(fp);
      return rv;
}
#endif

#if   (UNIX || CYGWIN) && !SECURE
/*
 * The edit command.
 */
int
edit(cp)
char  *cp;
{
      FILE  *fp;
      int   rv;

      if (*cp == '\0') {
            fp = fopen(tmp_file, "w");
            if (fp == NULL) {
                  printf(_("Can't create temporary file '%s'.\n"), tmp_file);
                  return false;
            }
            gfp = fp;
            high_prec = true;
            rv = list_cmd("all");
            high_prec = false;
            gfp = stdout;
            if (fclose(fp)) {
                  printf(_("Error writing temporary file.\n"));
                  return false;
            }
            rv = edit_sub(tmp_file);
            return rv;
      } else {
            if (access(cp, 6)) {
                  printf(_("You can only edit existing/writable files or all equations.\n"));
                  return false;
            }
            return edit_sub(cp);
      }
}

int
edit_sub(cp)
char  *cp;
{
      char  cl[MAX_CMD_LEN];
      char  *cp1;
      char  *editor_keyword = "EDITOR";

edit_again:
      cp1 = getenv(editor_keyword);
      if (cp1 == NULL) {
#if   CYGWIN
            cp1 = "notepad";
#else
            printf(_("%s environment variable not set.\n"), editor_keyword);
            return false;
#endif
      }
      strcpy(cl, cp1);
      strcat(cl, " ");
      strcat(cl, cp);
      if (shell_out(cl)) {
            printf(_("Error executing editor.  Check %s environment variable.\n"), editor_keyword);
            return false;
      }
      default_color();
      clear("all");
      if (!read_in(cp)) {
            printf(_("Prepare to run the editor.\n"));
            if (pause_cmd("")) {
                  goto edit_again;
            }
      }
      unlink(tmp_file);
      return true;
}
#endif

#if   !SECURE
/*
 * The save command.
 */
int
save(cp)
char  *cp;
{
      FILE  *fp;
      char  *cp1;
      int   rv;

      if (*cp == '\0') {
            return false;
      }
      if (access(cp, 0) == 0) {
            do {
                  sprintf(prompt_str, _("'%s' exists.  Overwrite (Y/N)? "), cp);
                  if ((cp1 = getstring((char *) trhs, n_tokens * sizeof(token_type))) == NULL) {
                        return false;
                  }
                  str_tolower(cp1);
                  if (*cp1 == 'n') {
                        printf(_("Command aborted.\n"));
                        return true;
                  }
            } while (*cp1 != 'y');
      }
      fp = fopen(cp, "w");
      if (fp == NULL) {
            printf(_("Can't create file '%s'.\n"), cp);
            return false;
      }
      gfp = fp;
      high_prec = true;
      rv = list_cmd("all");
      high_prec = false;
      gfp = stdout;
      if (fclose(fp))
            rv = false;
      if (rv) {
            printf(_("All equations saved in file: '%s'.\n"), cp);
      } else {
            printf(_("Error encountered while saving equations.\n"));
      }
      return rv;
}
#endif

/*
 * Get default equation number from a command parameter string.
 * The equation number must be the only parameter.
 * Return -1 on error.
 */
int
get_default_en(cp)
char  *cp;
{
      int   i;

      if (*cp == '\0')
            i = cur_equation;
      else {
            i = atoi(cp) - 1;
            cp = skip_num(cp);
            if (extra_garbage(cp))
                  return -1;
      }
      if (notdefined(i)) {
            return -1;
      }
      return i;
}

/*
 * Get an expression from the user.
 * Return true if successful.
 */
int
get_expr(equation, np)
token_type  *equation;
int         *np;
{
      char  buf[2000];
      char  *cp1;

      for (;;) {
            if ((cp1 = getstring(buf, sizeof(buf))) == NULL) {
                  return false;
            }
            if (!case_sensitive_flag) {
                  str_tolower(cp1);
            }
            set_error_level(cp1);
            cp1 = parse_section(equation, np, cp1);
            if (cp1)
                  break;
      }
      return(*np > 0);
}

/*
 * Prompt for a variable from the user.
 * Return true if successful.
 */
int
prompt_var(vp)
long  *vp;
{
      char  buf[MAX_VAR_LEN+80];
      char  *cp1;

      strcpy(prompt_str, _("Enter variable: "));
      if ((cp1 = getstring(buf, sizeof(buf))) == NULL) {
            return false;
      }
      cp1 = parse_var2(vp, cp1);
      if (cp1 == NULL)
            return false;
      if (*cp1) {
            printf(_("Only one variable may be specified.\n"));
            return false;
      }
      return true;
}

/*
 * Return true and display a message if equation "i" is undefined.
 */
int
notdefined(i)
int   i;
{
      if (i < 0 || i >= n_equations) {
            printf(_("Invalid equation number.\n"));
            return true;
      }
      if (n_lhs[i] <= 0) {
            printf(_("Undefined equation.\n"));
            return true;
      }
      return false;
}

Generated by  Doxygen 1.6.0   Back to index