Logo Search packages:      
Sourcecode: mathomatic version File versions

list.c

/*
 * Algebraic manipulator expression display routines.
 *
 * Copyright (c) 1996 George Gesslein II.
 */

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

static int  flist();
static int  flist_recurse();

int   cur_color = -1;

/* ANSI color code array */
static int  carray[] = {
      32, 33, 31, 35, 34, 36, 37
};

/* HTML color array */
static char *html_carray[] = {
      "#00FF00",
      "#FFFF00",
      "#FF9000",
      "#FF0000",
      "#FF00FF",
      "#00FFFF",
      "#0000FF"
};

reset_attr()
{
      cur_color = -1;
      if (html_flag) {
            printf("</font>");
      } else if (color_flag) {
            printf("\033[0m");
      }
}

set_color(color)
int   color;
{
      if (gfp != stdout)
            return;
      if (cur_color == color)
            return;
      if (html_flag) {
            if (color_flag)
                  printf("</font><font color=\"%s\">", html_carray[color%ARR_CNT(html_carray)]);
      } else if (color_flag) {
            printf("\033[%dm", carray[color%ARR_CNT(carray)]);
      }
      cur_color = color;
}

default_color()
{
      set_color(0);
}

/*
 * Display the equation stored in equation space "n" in single line format.
 */
int
list1_sub(n, export_flag)
int   n;
int   export_flag;
{
      if (n_lhs[n] <= 0)
            return false;
      if (!export_flag) {
            fprintf(gfp, "#%d: ", n + 1);
      }
      list_proc(lhs[n], n_lhs[n], export_flag);
      fprintf(gfp, " = ");
      list_proc(rhs[n], n_rhs[n], export_flag);
      if (high_prec) {
#if   CYGWIN
            fprintf(gfp, "\r\n");
#else
            fprintf(gfp, "\n");
#endif
      } else {
            fprintf(gfp, "\n\n");
      }
      return true;
}

/*
 * Display the equation stored in equation space "n".
 */
int
list_sub(n)
int   n;
{
      if (n_lhs[n] <= 0)
            return false;
      if (groupall) {
            group_sub(n);
            flist_sub(n);
      } else {
            list1_sub(n, false);
      }
      return true;
}

#if   !SILENT
list_debug(level, p1, n1, p2, n2)
int         level;
token_type  *p1;
int         n1;
token_type  *p2;
int         n2;
{
      if (debug_level >= level) {
            printf(_("debug %d: "), level);
            list_proc(p1, n1, false);
            if (p2 && n2 > 0) {
                  printf(" = ");
                  list_proc(p2, n2, false);
            }
            printf("\n");
      }
}
#endif

/*
 * Output a variable name if "out_flag" is true.
 * ASCII variable name is stored in global "var_str".
 * Make it C language compatible if "c_flag" is true.
 *
 * Return length of variable name (number of ASCII characters).
 *
 * If "c_flag == 2", assume Java.  If "c_flag == -1", create
 * an exportable variable name.
 */
int
list_var(v, out_flag, c_flag)
long  v;
int   out_flag;
int   c_flag;
{
      int         i, j;
      long        l1;

      var_str[0] = '\0';
      switch (v & VAR_MASK) {
      case V_NULL:
            break;
      case SIGN:
            strcat(var_str, "sign");
            break;
      case IMAGINARY:
            if (c_flag < 0)
                  strcat(var_str, "%I");
            else
                  strcat(var_str, "i#");
            break;
      case V_E:
            switch (c_flag) {
            case -1:
                  strcat(var_str, "%E");
                  break;
            case 0:
                  strcat(var_str, "e#");
                  break;
            case 1:
                  strcat(var_str, "E");
                  break;
            case 2:
                  strcat(var_str, "Math.E");
                  break;
            }
            break;
      case V_PI:
            switch (c_flag) {
            case -1:
                  strcat(var_str, "%PI");
                  break;
            case 0:
                  strcat(var_str, "pi");
                  break;
            case 1:
                  strcat(var_str, "PI");
                  break;
            case 2:
                  strcat(var_str, "Math.PI");
                  break;
            }
            break;
      case MATCH_ANY:
            strcat(var_str, "all");
            break;
      case SPECIAL:
            strcat(var_str, "answer");
            break;
      case V_TEMP:
            strcat(var_str, "temp");
            break;
      case V_INTEGER:
            strcat(var_str, "integer");
            break;
      default:
            j = (v & VAR_MASK) - VAR_OFFSET;
            if (j < 0 || var_names[j] == NULL) {
                  strcat(var_str, "bad_variable");
            } else {
                  strcat(var_str, var_names[j]);
            }
            break;
      }
      j = (v >> VAR_SHIFT) & SUBSCRIPT_MASK;
      if (j) {
            j--;
            sprintf(&var_str[strlen(var_str)], "%d", j);
      }
      l1 = v;
      i = 0;
      while ((l1 -= PRIME_INCREMENT) >= 0 && i < 20) {
            if (!c_flag)
                  strcat(var_str, "'");
            i++;
      }
      if (i && c_flag) {
            if (i == 1) {
                  strcat(var_str, "_prime");
            } else {
                  sprintf(&var_str[strlen(var_str)], "_%dprimes", i);
            }
      }
      if (v & PERCENT_CHANGE) {
            strcat(var_str, "_percent_change");
      }
      if (out_flag) {
            fprintf(gfp, "%s", var_str);
      }
      return(strlen(var_str));
}

/*
 * Display an expression in single line format.
 */
list_proc(equation, n, export_flag)
token_type  *equation;
int         n;
int         export_flag;
{
      int   i,j,k,l;
      int   min1;
      int   cur_level;
      char  *cp;

      cur_level = min1 = min_level(equation, n);
      for (i = 0; i < n; i++) {
            j = cur_level - equation[i].level;
            k = abs(j);
            for (l = 1; l <= k; l++) {
                  if (j > 0) {
                        cur_level--;
                        fprintf(gfp, ")");
                        set_color(cur_level-min1);
                  } else {
                        cur_level++;
                        set_color(cur_level-min1);
                        fprintf(gfp, "(");
                  }
            }
            switch (equation[i].kind) {
            case CONSTANT:
                  if (high_prec) {
                        fprintf(gfp, "%.20g", equation[i].token.constant);
                  } else if (finance_option) {
                        fprintf(gfp, "%.2f", equation[i].token.constant);
                  } else {
                        fprintf(gfp, "%.12g", equation[i].token.constant);
                  }
                  break;
            case VARIABLE:
                  list_var(equation[i].token.variable, true, export_flag ? -1 : 0);
                  break;
            case OPERATOR:
                  cp = _("(unknown operator)");
                  switch (equation[i].token.operatr) {
                  case PLUS:
                        cp = " + ";
                        break;
                  case MINUS:
                        cp = " - ";
                        break;
                  case TIMES:
                        cp = "*";
                        break;
                  case DIVIDE:
                        cp = "/";
                        break;
                  case MODULUS:
                        cp = " % ";
                        break;
                  case POWER:
                        cp = "^";
                        break;
                  case FACTORIAL:
                        cp = "!";
                        i++;
                        break;
                  }
                  fprintf(gfp, "%s", cp);
                  break;
            }
      }
      j = cur_level - min1;
      for (; j > 0;) {
            fprintf(gfp, ")");
            j--;
            set_color(j);
      }
}

/*
 * Return true if expression is a valid integer expression for
 * list_c_code().
 */
int
int_expr(equation, n)
token_type  *equation;
int         n;
{
      int   i;

      for (i = 0; i < n; i++) {
            switch (equation[i].kind) {
            case CONSTANT:
                  if (fmod(equation[i].token.constant, 1.0)) {
                        return false;
                  }
                  break;
            case OPERATOR:
                  switch (equation[i].token.operatr) {
                  case POWER:
                        if (equation[i+1].level == equation[i].level
                            && equation[i-1].level == equation[i].level
                            && equation[i+1].kind == CONSTANT
                            && equation[i+1].token.constant == 2.0) {
                              continue;
                        }
                        return false;
                  }
                  break;
            }
      }
      return true;
}

/*
 * Display C or Java code for an expression.
 */
list_c_code(equation, n, java_flag, int_flag)
token_type  *equation;
int         n;
int         java_flag;
int         int_flag;
{
      int   i,j,k,l;
      int   min1;
      int   cur_level;
      char  *cp;
      int   i1;
      char  buf[50];

      min1 = min_level(equation, n);
      if (n > 1)
            min1--;
      cur_level = min1;
      for (i = 0; i < n; i++) {
            j = cur_level - equation[i].level;
            k = abs(j);
            for (l = 1; l <= k; l++) {
                  if (j > 0) {
                        cur_level--;
                        fprintf(gfp, ")");
                  } else {
                        cur_level++;
                        for (i1 = i + 1; i1 < n && equation[i1].level >= cur_level; i1 += 2) {
                              if (equation[i1].level == cur_level) {
                                    switch (equation[i1].token.operatr) {
                                    case POWER:
                                          if (equation[i1-1].level == cur_level
                                              && equation[i1+1].level == cur_level
                                              && equation[i1+1].kind == CONSTANT
                                              && equation[i1+1].token.constant == 2.0) {
                                                equation[i1].token.operatr = TIMES;
                                                equation[i1+1].kind = equation[i1-1].kind;
                                                equation[i1+1].token = equation[i1-1].token;
                                          } else {
                                                if (java_flag) {
                                                      fprintf(gfp, "Math.pow");
                                                } else {
                                                      fprintf(gfp, "pow");
                                                }
                                          }
                                          break;
                                    case FACTORIAL:
                                          if (java_flag) {
                                                fprintf(gfp, "MathSupport.fact");
                                          } else {
                                                fprintf(gfp, "fact");
                                          }
                                          break;
                                    }
                                    break;
                              }
                        }
                        fprintf(gfp, "(");
                  }
            }
            switch (equation[i].kind) {
            case CONSTANT:
                  if (int_flag) {
                        fprintf(gfp, "%.0f", equation[i].token.constant);
                  } else {
                        sprintf(buf, "%#.16g", equation[i].token.constant);
                        j = strlen(buf) - 1;
                        for (; j >= 0; j--) {
                              if (buf[j] == '0')
                                    continue;
                              if (buf[j] == '.')
                                    buf[j+2] = '\0';
                              else
                                    break;
                        }
                        fprintf(gfp, "%s", buf);
                  }
                  break;
            case VARIABLE:
                  list_var(equation[i].token.variable, true, (java_flag ? 2 : 1));
                  break;
            case OPERATOR:
                  cp = _("(unknown operator)");
                  switch (equation[i].token.operatr) {
                  case PLUS:
                        cp = " + ";
                        break;
                  case MINUS:
                        cp = " - ";
                        break;
                  case TIMES:
                        cp = " * ";
                        break;
                  case DIVIDE:
                        cp = " / ";
                        break;
                  case MODULUS:
                        cp = " % ";
                        break;
                  case POWER:
                        cp = ", ";
                        break;
                  case FACTORIAL:
                        cp = "";
                        i++;
                        break;
                  }
                  fprintf(gfp, "%s", cp);
                  break;
            }
      }
      j = cur_level - min1;
      for (; j > 0;) {
            fprintf(gfp, ")");
            j--;
      }
}

int   cur_line;
int   cur_pos;

/*
 * Display the equation at equation number "n" in fraction format.
 */
int
flist_sub(n)
int   n;
{
      int   i;
      int   sind;
      char  buf[30];
      int   len;
      int   len2, len3;
      int   pos;
      int   high, low;
      int   max_line;
      int   min_line;
      int   max2_line, min2_line;

      if (n_lhs[n] <= 0)
            return false;
      len = sprintf(buf, "#%d: ", n + 1);
      cur_line = 0;
      cur_pos = 0;
      sind = n_rhs[n];
      len += flist(lhs[n], n_lhs[n], false, 0, &max_line, &min_line);
      len += 3;
make_smaller:
      len2 = flist(rhs[n], sind, false, 0, &high, &low);
      if (screen_columns && (len + len2) >= screen_columns && sind > 0) {
            for (sind--; sind > 0; sind--) {
                  if (rhs[n][sind].level == 1 && rhs[n][sind].kind == OPERATOR) {
                        switch (rhs[n][sind].token.operatr) {
                        case PLUS:
                        case MINUS:
                        case TIMES:
                        case MODULUS:
                        case POWER:
                              goto make_smaller;
                        }
                  }
            }
            goto make_smaller;
      }
      if (high > max_line)
            max_line = high;
      if (low < min_line)
            min_line = low;
      len3 = flist(&rhs[n][sind], n_rhs[n] - sind, false, 0, &max2_line, &min2_line);
      if (screen_columns && max(len + len2, len3) >= screen_columns) {
            list1_sub(n, false);
            return true;
      }
      fprintf(gfp, "\n");
      for (i = max_line; i >= min_line; i--) {
            cur_line = i;
            cur_pos = 0;
            if (i == 0) {
                  fprintf(gfp, "%s", buf);
                  cur_pos = strlen(buf);
            }
            pos = strlen(buf);
            pos += flist(lhs[n], n_lhs[n], true, pos, &high, &low);
            if (i == 0) {
                  fprintf(gfp, "%s", " = ");
                  cur_pos += 3;
            }
            pos += 3;
            flist(rhs[n], sind, true, pos, &high, &low);
            fprintf(gfp, "\n");
      }
      if (sind < n_rhs[n]) {
            fprintf(gfp, "\n");
            for (i = max2_line; i >= min2_line; i--) {
                  cur_line = i;
                  cur_pos = 0;
                  flist(&rhs[n][sind], n_rhs[n] - sind, true, 0, &high, &low);
                  fprintf(gfp, "\n");
            }
      }
      fprintf(gfp, "\n");
      return true;
}

static int
flist(equation, n, out_flag, pos, highp, lowp)
token_type  *equation;
int         n;
int         out_flag;
int         pos;
int         *highp, *lowp;
{
      int   i;

      i = flist_recurse(equation, n, out_flag, 0, pos, 1, highp, lowp);
      if (out_flag) {
            set_color(0);
      }
      return i;
}

static int
flist_recurse(equation, n, out_flag, line, pos, cur_level, highp, lowp)
token_type  *equation;
int         n;
int         out_flag;
int         line;
int         pos;
int         cur_level;
int         *highp, *lowp;
{
      int   i,j,k,l;
      int   l1, l2;
      int   ii;
      int   stop_at;
      int   div_loc;
      int   len_div;
      int   level;
      int   start_level;
      int   oflag;
      int   len, len1, len2;
      int   high, low;
      char  buf[500];

      len = 0;
      start_level = cur_level;
      *highp = line;
      *lowp = line;
      if (n <= 0) {
            return 0;
      }
      oflag = (out_flag && line == cur_line);
      if (oflag) {
            set_color(cur_level-1);
            for (; cur_pos < pos; cur_pos++) {
                  fprintf(gfp, " ");
            }
      }
      ii = 0;
check_again:
      stop_at = n;
      div_loc = -1;
      for (i = ii; i < n; i++) {
            if (equation[i].kind == OPERATOR && equation[i].token.operatr == DIVIDE) {
                  level = equation[i].level;
                  for (j = i - 2; j > 0; j -= 2) {
                        if (equation[j].level < level)
                              break;
                  }
                  j++;
                  if (div_loc < 0) {
                        div_loc = i;
                        stop_at = j;
                  } else {
                        if (j < stop_at) {
                              div_loc = i;
                              stop_at = j;
                        } else if (j == stop_at) {
                              if (level < equation[div_loc].level)
                                    div_loc = i;
                        }
                  }
            }
      }
      for (i = ii; i < n; i++) {
            if (i == stop_at) {
                  j = cur_level - equation[div_loc].level;
                  k = abs(j) - 1;
            } else {
                  j = cur_level - equation[i].level;
                  k = abs(j);
            }
            for (l = 1; l <= k; l++) {
                  if (j > 0) {
                        cur_level--;
                        len++;
                        if (oflag) {
                              fprintf(gfp, ")");
                              set_color(cur_level-1);
                        }
                  } else {
                        cur_level++;
                        len++;
                        if (oflag) {
                              set_color(cur_level-1);
                              fprintf(gfp, "(");
                        }
                  }
            }
            if (i == stop_at) {
                  level = equation[div_loc].level;
                  len1 = flist_recurse(&equation[stop_at], div_loc - stop_at, false, line + 1, pos + len, level, &high, &low);
                  l1 = (2 * (line + 1)) - low;
                  for (j = div_loc + 2; j < n; j += 2) {
                        if (equation[j].level <= level)
                              break;
                  }
                  len2 = flist_recurse(&equation[div_loc+1], j - (div_loc + 1), false, line - 1, pos + len, level, &high, &low);
                  l2 = (2 * (line - 1)) - high;
                  ii = j;
                  len_div = max(len1, len2);
                  j = 0;
                  if (len1 < len_div) {
                        j = (len_div - len1) / 2;
                  }
                  flist_recurse(&equation[stop_at], div_loc - stop_at, out_flag, l1, pos + len + j, level, &high, &low);
                  if (high > *highp)
                        *highp = high;
                  if (low < *lowp)
                        *lowp = low;
                  if (oflag) {
                        set_color(level-1);
                        for (j = 0; j < len_div; j++) {
                              fprintf(gfp, "-");
                        }
                        set_color(cur_level-1);
                  }
                  j = 0;
                  if (len2 < len_div) {
                        j = (len_div - len2) / 2;
                  }
                  flist_recurse(&equation[div_loc+1], ii - (div_loc + 1), out_flag, l2, pos + len + j, level, &high, &low);
                  if (high > *highp)
                        *highp = high;
                  if (low < *lowp)
                        *lowp = low;
                  len += len_div;
                  goto check_again;
            }
            switch (equation[i].kind) {
            case CONSTANT:
                  if (equation[i].token.constant == 0.0)
                        equation[i].token.constant = 0.0; /* fix -0 */
                  if (finance_option) {
                        len += sprintf(buf, "%.2f", equation[i].token.constant);
                  } else {
                        len += sprintf(buf, "%.12g", equation[i].token.constant);
                  }
                  if (oflag)
                        fprintf(gfp, "%s", buf);
                  break;
            case VARIABLE:
                  len += list_var(equation[i].token.variable, oflag, false);
                  break;
            case OPERATOR:
                  switch (equation[i].token.operatr) {
                  case PLUS:
                        strcpy(buf, " + ");
                        break;
                  case MINUS:
                        strcpy(buf, " - ");
                        break;
                  case TIMES:
                        strcpy(buf, "*");
                        break;
                  case MODULUS:
                        strcpy(buf, " % ");
                        break;
                  case POWER:
                        strcpy(buf, "^");
                        break;
                  case FACTORIAL:
                        strcpy(buf, "!");
                        i++;
                        break;
                  default:
                        strcpy(buf, _("(unknown operator)"));
                        break;
                  }
                  if (oflag)
                        fprintf(gfp, "%s", buf);
                  len += strlen(buf);
                  break;
            }
      }
      j = cur_level - start_level;
      for (; j > 0;) {
            cur_level--;
            len++;
            j--;
            if (oflag) {
                  fprintf(gfp, ")");
                  set_color(cur_level-1);
            }
      }
      if (oflag)
            cur_pos += len;
      return len;
}

Generated by  Doxygen 1.6.0   Back to index