/* 1992.10.3 守屋一成(morip)作 */
/* 1993.6.27 一部変更 */
/* 1994.2.13 複素数に拡張、ユーザ定数が使用可能 */
/* 1995.2.12 行列化、対話モード導入 */
/* 1995.8.12 ヒストリ機能追加、ソース分割、名称変更 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/extender.h>
#include "expanl.h"

#define RIGHT 0x1c
#define LEFT 0x1d
#define UP 0x1e
#define DOWN 0x1f
#define BS 0x8
#define CR 0xd

#define LANG 'j'

struct his{
  char *exp;
  struct his *pre;
  struct his *next;
};

typedef struct his histry;

char *keyinput(void);
char *strinsert(char *, char, int);
char *strdelete(char *, int);

char *strdelete(char *expression, int loc)
{
  int n;
  
  for (n = loc; n <= strlen(expression); n++) {
    expression[n - 1] = expression[n];
  }
  
  return expression;
}

char *strinsert(char *expression, char c, int loc)
{
  int n;
  
  for (n = strlen(expression) + 1; n > loc; n--) {
    expression[n] = expression[n - 1];
  }
  expression[n] = c;
  
  return expression;
}

char *keyinput(void)
{
  int i, l, j, k, f, len;
  char c, tmp[256], expression[256];
  histry *sw, *tmph, *pre, *next;
  static histry *last = NULL;
  
  pre = last;
  next = NULL;
  sw = last;
  f = 0;
  i = 0;
  l = 0;
  expression[0] = '\0';
  tmp[0] = '\0';
  while ((c = _dos_keyboard_input_without_echo()) != CR) {
    if (c < 0x20) {
      switch(c) {
        case UP:
          tmph = pre;
          len = strlen(tmp);
          if (len != 0) {
            k = 2;
            while (tmph != NULL) {
              k = 1;
              for (j = 0; j < len; j++) {
                if (tmp[j] != *((tmph->exp) + j)) {
                  k = 0;
                  sw = tmph->pre;
                  break;
                }
              }
              if (k == 1) {
                f = 1;
                sw = NULL;
                break;
              }
              tmph = tmph->pre;
            }
            if (tmph == NULL && k == 0) {
              if (f == 0) {
                sw = pre;
              }
              tmph = sw;
            }
          }
          else {
            sw = tmph->pre;
          }
          if (tmph != NULL) {
            strcpy(expression, tmph->exp);
            pre = tmph->pre;
            next = tmph->next;
            
            for (j = 0; j < l; j++) {
              putchar('\b');
            }
            for (j = 0; j < i; j++) {
              putchar(' ');
            }
            for (j = 0; j < i; j++) {
              putchar('\b');
            }
            i = strlen(expression);
            l = i;
            printf("%s", expression);
          }
          break;
        case DOWN:
          tmph = next;
          len = strlen(tmp);
          if (len != 0) {
            k = 2;
            while (tmph != NULL) {
              k = 1;
              for (j = 0; j < len; j++) {
                if (tmp[j] != *((tmph->exp) + j)) {
                  k = 0;
                  sw = tmph->next;
                  break;
                }
              }
              if (k == 1) {
                sw = NULL;
                break;
              }
              tmph = tmph->next;
            }
            if (tmph == NULL && k == 0) {
              if (f == 0) {
                sw = next;
              }
              tmph = sw;
            }
          }
          else {
            sw = tmph->next;
          }
          if (tmph != NULL) {
            strcpy(expression, tmph->exp);
            pre = tmph->pre;
            next = tmph->next;
            
            for (j = 0; j < l; j++) {
              putchar(LEFT);
            }
            for (j = 0; j < i; j++) {
              putchar(' ');
            }
            for (j = 0; j < i; j++) {
              putchar(LEFT);
            }
            i = strlen(expression);
            l = i;
            printf("%s", expression);
          }
          else if (tmph == NULL && pre != last) {
            strcpy(expression, tmp);
            pre = last;
            next = NULL;
            
            for (j = 0; j < l; j++) {
              putchar(LEFT);
            }
            for (j = 0; j < i; j++) {
              putchar(' ');
            }
            for (j = 0; j < i; j++) {
              putchar(LEFT);
            }
            i = strlen(expression);
            l = i;
            printf("%s", expression);
          }
            
          break;
        case RIGHT:
          l++;
          if (l > i) {
            l = i;
          }
          else {
            putchar(RIGHT);
          }
          break;
        case LEFT:
          l--;
          if (l < 0) {
            l = 0;
          }
          else {
            putchar(LEFT);
          }
          break;
        case BS:
          if (l != 0) {
            strdelete(expression, l);
            i--;
            l--;
            putchar(LEFT);
            printf("%s ", expression + l);
            for (j = -1; j < strlen(expression + l); j++) {
              putchar(LEFT);
            }
            strcpy(tmp, expression);
            pre = last;
            sw = pre;
            f = 0;
          }
          break;
      }
    }
    else {
      strinsert(expression, c, l);
      printf("%s", expression + l);
      len = strlen(expression + l);
      for (j = 1; j < len; j++) {
        putchar(LEFT);
      }
      strcpy(tmp, expression);
      pre = last;
      sw = pre;
      f = 0;
      i++;
      l++;
    }
  }
  if (strlen(expression) != 0) {
    pre = last;
    j = 0;
    if (pre != NULL) {
      while (strcmp(expression, pre->exp) != 0) {
        if ((pre = pre->pre) == NULL) {
          j = 1;
          break;
        }
      }
    }
    else {
      j = 1;
    }
    
    if (j == 1) {
      tmph = last;
      if (tmph != NULL) {
        while (tmph->pre != NULL) {
          tmph = tmph->pre;
        }
      }
      
      while ((pre = (histry *)malloc(sizeof(histry))) == NULL) {
        if (tmph != NULL) {
          free(tmph->exp);
          next = tmph->next;
          free(tmph);
          if (next != NULL) {
            next->pre = NULL;
            tmph = next;
          }
          else {
            last = NULL;
            tmph = NULL;
          }
        }
        else {
          puts("No more memories.\n");
          exit(1);
        }
      }
      while ((pre->exp = (char *)malloc((strlen(expression) + 1) * sizeof(char))) == NULL) {
        if (tmph != NULL && tmph != pre) {
          free(tmph->exp);
          next = tmph->next;
          free(tmph);
          if (next != NULL) {
            next->pre = NULL;
            tmph = next;
          }
          else {
            last = NULL;
            tmph = NULL;
          }
        }
        else {
          puts("No more memories.\n");
          exit(1);
        }
      }
      strcpy(pre->exp, expression);
    }
    else {
      if (pre->pre != NULL) {
        (pre->pre)->next = pre->next;
      }
      if (pre->next != NULL) {
        (pre->next)->pre = pre->pre;
      }
      else {
        last = last->pre;
      }
    }
    pre->pre = last;
    pre->next = NULL;
    if (last != NULL) {
      last->next = pre;
    }
    last = pre;
  }
  
  return expression;
}

void main(int argc, char *argv[])
{
  int i;
  char expression[256];
  matrix ansr;
  
  for(i = 0; i <= UCN - 1; i++) {
    cnst[i].name[0] = '\0';
  }
  
  if (argc == 1) {
    printf("\n>> ");
    strcpy(expression, keyinput());
    while (strcmp(expression, "quit") != 0) {
      ansr = expanl(expression);
      
      if (strlen(expression) != 0) {
        if (mathcalerr != 0) {
          printf("\n%s\n", emessage(LANG));
        }
        else {
          printf("\n%s=\n", expression);
          mprintf(ansr);
        }
      }
      printf("\n>> ");
      
      strcpy(expression, keyinput());
    }
  }
  else {
    for (i = 1; i <= argc - 1; i++) {
      ansr = expanl(argv[i]);
      
      if (mathcalerr != 0) {
        printf("\n%s\n", emessage(LANG));
      }
      else {
        printf("\n%s=\n", argv[i]);
        mprintf(ansr);
      }
    }
  }
}
