Logo Search packages:      
Sourcecode: mathomatic version File versions

main.c

/*
 * Algebraic manipulator program.
 *
 * Mathomatic Copyright (c) 1996 George Gesslein II.
 *
 * Currently, this program only supports binary and unary operators.
 * Unary operators are implemented as a binary operation with a dummy operand.
 *
 * In the storage format, each level of parenthesis is indicated
 * by a level number (origin 1).  The deeper the level, the
 * higher the level number.
 *
 * The storage format for expressions is a fixed size array of elements
 * "token_type", which may be a CONSTANT, VARIABLE, or OPERATOR.
 * The array always alternates between operand (CONSTANT or VARIABLE)
 * and OPERATOR.  There is a separate integer for each array which
 * contains the current length of the expression stored in the array.
 * This length is always odd.
 *
 * Only one POWER operator is allowed per level in the storage format,
 * and no other operators may be on that level.  Same with the FACTORIAL
 * and MODULUS operators.
 *
 * Any number of TIMES and DIVIDE operators may be on the same
 * level, because they are simple multiplicative class operators.
 * The same for PLUS and MINUS.
 */

#include "am.h"
#include <signal.h>
#if   READLINE
#include <readline/readline.h>
#endif
#if   LINUX
#include <fenv.h>
#endif
#if   UNIX || CYGWIN
#include <sys/ioctl.h>
#include <termios.h>
#endif

void        fphandler();
void        inthandler();
void        alarmhandler();
void        resizehandler();
void        exit_program();

int         n_tokens = DEFAULT_N_TOKENS;
int         n_equations;
int         cur_equation;

int         n_lhs[N_EQUATIONS];
int         n_rhs[N_EQUATIONS];

token_type  *lhs[N_EQUATIONS];
token_type  *rhs[N_EQUATIONS];

int         n_tlhs;
int         n_trhs;

token_type  *tlhs;
token_type  *trhs;

token_type  *scratch;

char        *var_names[MAX_VAR_NAMES];

/* Set the following to "true" if you want upper and lower case variables. */
int         case_sensitive_flag;

/* Set the following to "true" to always display equations in fraction format. */
int         groupall = true;

int         in_calc_cmd;            /* true if in calculate command (force approximations) */
int         preserve_roots = true;  /* true if we are to preserve 2^.5, etc. */
int         true_modulus;           /* true for mathematically correct modulus */
int         screen_columns = 80;
int         screen_rows = 24;
int         finance_option;         /* for displaying dollars and cents */
#if   !SILENT
int         debug_level;
#endif
int         domain_check;
int         color_flag = true;      /* true for color mode */
int         html_flag;        /* true for HTML mode */
int         partial_flag;           /* true for partial unfactoring of algebraic fractions */
int         symb_flag;        /* true for "simplify symbolic" */
int         high_prec;        /* true while saving equations */
int         input_column;
int         sign_flag;        /* true when all "sign" variables are to compare equal */
int         piping_in_flag;         /* true if input is not a terminal */
char        *tmp_file = "mathxxx.tmp";
double            small_epsilon;          /* for small accumulated round-off errors */
double            epsilon;          /* for larger accumulated round-off errors */
char        var_str[MAX_VAR_LEN+80];      /* temp storage for variable names */
char        prompt_str[MAX_VAR_LEN+80];   /* temp storage for prompt strings */
char        *dir_path;        /* directory path to the executable */

/* The following are for integer factoring (filled by factor_one()). */
double            unique[64];       /* storage for the unique factors */
int         ucnt[64];         /* number of times the factor occurs */
int         uno;              /* number of unique factors stored in unique[] */

sign_array_type   sign_array;       /* for keeping track of unique "sign" variables */

FILE        *gfp;             /* global output file pointer */

jmp_buf           jmp_save;

int         test_mode;        /* test mode flag (-t) */

#if   CYGWIN
char  *
dirname1(cp)
char  *cp;
{
      int   i;

      i = strlen(cp);
      while (i >= 0 && cp[i] != '\\' && cp[i] != '/')
            i--;
      if (i < 0)
            return(".");
      cp[i] = '\0';
      return(cp);
}
#endif

int
main(argc, argv)
int   argc;
char  **argv;
{
      extern char *optarg;
      extern int  optind;

      int         i;
      char        *cp;
      double            numerator, denominator;
      double            multiplier;
      int         coption;
#if   UNIX || CYGWIN
      struct winsize    ws;
#endif

#if   CYGWIN
      dir_path = strdup(dirname1(argv[0]));
#endif
      piping_in_flag = !isatty(0);
      init_gvars();
      gfp = stdout;
      setbuf(stdout, NULL);         /* make standard output unbuffered */
      small_epsilon =   0.000000000000005;      /* don't increase this */
      epsilon =   0.00000000000005; /* the correct value for doubles */

#if   UNIX || CYGWIN
      ws.ws_col = 0;
      ws.ws_row = 0;
      ioctl(1, TIOCGWINSZ, &ws);
      if (ws.ws_col) {
            screen_columns = ws.ws_col;
      }
      if (ws.ws_row) {
            screen_rows = ws.ws_row;
      }
#endif
      coption = false;
      while ((i = getopt(argc, argv, "tchm:")) >= 0) {
            switch (i) {
            case 'c':
                  coption = true;
                  break;
            case 'h':
                  html_flag = true;
                  break;
            case 'm':
                  multiplier = atof(optarg);
                  if (multiplier <= 0.0 || (n_tokens = (int) (multiplier * DEFAULT_N_TOKENS)) <= 0) {
                        printf(_("Invalid memory multiplier specified!\n"));
                        exit(1);
                  }
                  break;
            case 't':
                  test_mode = true;
                  break;
            default:
                  exit(1);
            }
      }
      if (test_mode || html_flag) {
            screen_columns = 0;
            screen_rows = 0;
      }
      if (html_flag) {
            printf("<pre><font size=\"+1\">\n");
      }
      if (!test_mode) {
            printf(_("\nMathomatic Version %s\n"), VERSION);
            printf(_("Copyright (C) 1987-2005 George Gesslein II.\n"));
      }
      init_mem();
#if   !SECURE
      if (!test_mode && !load_rc()) {
            printf(_("Error loading set options from \"%s\".\n"), RC_FILE);
      }
#endif
      if (test_mode) {
            color_flag = false;
      } else if (coption) {
            color_flag = !color_flag;
      }
      printf("\n");
      default_color();
      if ((i = setjmp(jmp_save)) != 0) {
            clean_up();
            switch (i) {
            case 3:
                  break;
            case 13:
                  printf(_("Operation abruptly aborted.\n"));
                  break;
            case 14:
                  printf(_("Expression too big!\n"));
            default:
                  printf(_("Operation aborted.\n"));
            }
      } else {
#if   LINUX
            feenableexcept(FE_INVALID | FE_OVERFLOW);
#endif
            signal(SIGFPE, fphandler);
            signal(SIGINT, inthandler);
#if   UNIX || CYGWIN
            signal(SIGWINCH, resizehandler);
#endif
#if   TIMEOUT_SECONDS
            signal(SIGALRM, alarmhandler);
            alarm(TIMEOUT_SECONDS);
#endif
            if (!f_to_fraction(0.5, &numerator, &denominator)
                || !f_to_fraction(1.0/3.0, &numerator, &denominator)) {
                  printf(_("Cannot convert floating point values to fractions.\n"));
            }
#if   !SECURE
            for (i = optind; i < argc; i++) {
                  if (!read_in(argv[i])) {
                        exit_program(1);
                  }
            }
#endif
      }
      for (;;) {
            sprintf(prompt_str, "%d%s", cur_equation + 1, html_flag ? HTML_PROMPT : PROMPT);
            if ((cp = getstring((char *) tlhs, n_tokens * sizeof(token_type))) == NULL)
                  break;
            process(cp);
      }
      exit_program(0);
}

/*
 * Allocate the equation spaces.
 */
init_mem()
{
      int   i;
      char  *junk;

      if ((junk = malloc(8192)) == NULL
          || (scratch = (token_type *) malloc((n_tokens + 10) * sizeof(token_type))) == NULL) {
            printf(_("Not enough memory.\n"));
            exit(1);
      }
      if ((tlhs = (token_type *) malloc(n_tokens * sizeof(token_type))) == NULL
          || (trhs = (token_type *) malloc(n_tokens * sizeof(token_type))) == NULL) {
            printf(_("Not enough memory.\n"));
            exit(1);
      }
      for (i = 0; i < N_EQUATIONS; i++) {
            lhs[i] = (token_type *) malloc(n_tokens * sizeof(token_type));
            if (lhs[i] == NULL)
                  break;
            rhs[i] = (token_type *) malloc(n_tokens * sizeof(token_type));
            if (rhs[i] == NULL) {
                  free((char *) lhs[i]);
                  break;
            }
      }
      free(junk);
      n_equations = i;
      if (n_equations == 0) {
            printf(_("Not enough memory.\n"));
            exit(1);
      }
      clear("all");
      if (!test_mode) {
            printf(_("%d equation spaces allocated (total size is %ld KBytes).\n"),
                n_equations, ((long) n_tokens * sizeof(token_type) * 2L * n_equations) / 1000L);
      }
}

void
fphandler(sig)
int   sig;
{
      printf(_("Floating point exception!\n"));
#if   LINUX
      feenableexcept(FE_INVALID | FE_OVERFLOW);
#endif
      signal(SIGFPE, fphandler);
      longjmp(jmp_save, 2);
}

#if   MATHERR           /* define this if matherr() function is supported (it usually isn't) */
int
matherr(x)
struct exception  *x;
{
      switch (x->type) {
      case DOMAIN:
            if (domain_check) {
                  domain_check = false;
                  return 1;
            }
            printf(_("Domain error in constant!\n"));
            break;
      case SING:
            printf(_("Singularity error in constant!\n"));
            break;
      case OVERFLOW:
            printf(_("Overflow error in constant!\n"));
            break;
      case UNDERFLOW:
            printf(_("Underflow error in constant!\n"));
            break;
      case TLOSS:
            printf(_("Total loss of significance in constant!\n"));
            break;
      case PLOSS:
            printf(_("Partial loss of significance in constant!\n"));
            break;
      default:
            printf(_("Unknown error in constant!\n"));
            break;
      }
      longjmp(jmp_save, 2);
}

check_err()
{
}
#else
check_err()
{
      switch (errno) {
      case EDOM:
            errno = 0;
            if (domain_check) {
                  domain_check = false;
            } else {
                  printf(_("Domain error in constant!\n"));
                  longjmp(jmp_save, 2);
            }
            break;
      case ERANGE:
            errno = 0;
            printf(_("Overflow error in constant!\n"));
            longjmp(jmp_save, 2);
            break;
      }
}
#endif

/*
 * Control-C handler.
 */
void
inthandler(sig)
int   sig;
{
      exit_program(0);
}

#if   TIMEOUT_SECONDS
/*
 * Alarm signal handler.
 */
void
alarmhandler(sig)
int   sig;
{
      printf(_("timeout\n"));
      exit_program(0);
}
#endif

#if   UNIX || CYGWIN
/*
 * Window resize handler.
 */
void
resizehandler(sig)
int   sig;
{
      struct winsize    ws;

      ws.ws_col = 0;
      ws.ws_row = 0;
      ioctl(1, TIOCGWINSZ, &ws);
      if (ws.ws_col && screen_columns) {
            screen_columns = ws.ws_col;
      }
      if (ws.ws_row && screen_rows) {
            screen_rows = ws.ws_row;
      }
}
#endif

/*
 * Exit this program and return to the Operating System.
 */
void
exit_program(exit_value)
int   exit_value;
{
      printf("\n");
      reset_attr();
      printf(_("Thank you for using Mathomatic!\n"));
      printf(_("Please visit \"http://www.mathomatic.com\" for info and latest versions.\n"));
      printf(_("- For more and updated info on Debian systems,\n  please visit: \"http://packages.qa.debian.org/m/mathomatic.html\".\n"));
      if (html_flag) {
            printf("</pre>\n");
      }
      exit(exit_value);
}

/*
 * Common routine to output a prompt
 * and get a line of input from stdin.
 * All Mathomatic input comes from this routine,
 * except for file reading.
 *
 * Returns "string".
 */
char  *
getstring(string, n)
char  *string;    /* storage for input string */
int   n;          /* maximum size of "string" in bytes */
{
      int   i;
      char  *cp;

      if (piping_in_flag)
            prompt_str[0] = '\0';
      input_column = strlen(prompt_str);
#if   READLINE
      if (!html_flag) {
            cp = readline(prompt_str);
            if (cp == NULL)
                  exit_program(0);
            strncpy(string, cp, n);
            string[n-1] = '\0';
            if (string[0]) {
                  add_history(cp);
            } else {
                  free(cp);
            }
      } else {
            printf("%s", prompt_str);
            if (fgets(string, n, stdin) == NULL)
                  exit_program(0);
      }
#else
      printf("%s", prompt_str);
      if (fgets(string, n, stdin) == NULL)
            exit_program(0);
#endif
      cp = string;
      i = strlen(cp) - 1;
      while (i >= 0 && (cp[i] == '\n' || cp[i] == '\r')) {
            cp[i--] = '\0';
      }
      return string;
}

Generated by  Doxygen 1.6.0   Back to index