/* ---------------------------------------------------------------------- */
/*		CONFIGURATION						  */
/* ---------------------------------------------------------------------- */

#include "pcstdio.h"
#include "pcdefs.h"

/*
#define PRECONFIG 1		/* define for preconfigured terminals */
*/

#define  HXOS 7  /* offset for hex letters from numbers */
#define MAXHEX  0xff  /* largest hex code allowed */
#define STRLEN 70 /* maximum string input string length */
#define HC   4     /* max no. of chars in one hex code */

#ifdef IBM
#define color	Tinnul
#define c_axis	Tdeinnul
#define c_comd	Tdcpnul
#define c_neg	Tclsnul
#define c_norm	Teosnul
#define c_form	Teolnul

char *c_av[] = {
	"Black        ",
	"Blue         ",
	"Green        ",
	"Cyan         ",
	"Red          ",
	"Magenta      ",
	"Brown        ",
	"Light Grey   ",
	"Dark Grey    ",
	"Light Blue   ",
	"Light Green  ",
	"Light Cyan   ",
	"Light Red    ",
	"Light Magenta",
	"Yellow       ",
	"White        "
};
#endif

char *hithere = "Perfect Calc Configuration Program 1.09\n";

/* information from PC.OVL -- EXACTLY 512 bytes last 2 records */
int Tlines, Tcols;
char Tinstr[LIN];  int Tinnul;
char Tdeinstr[LDEIN];  int Tdeinnul;
char Tdcpstr[LDCP];  int Tdcpnul;
char Tclsstr[LCLS];  int Tclsnul;
char Teosstr[LEOS];  int Teosnul;
char Teolstr[LEOL];  int Teolnul;
char Trvstr[LRV];
char Tnvstr[LNV];
int prtwidth;
char Pinstr[LPIN], Pdeinstr[LPDEIN];
char Tbottom[LBOTTOM];
int Keys[LKEYS];

/* Individual terminal parameters -- add new ones at end here! */
struct term
{   char *tname;			/* terminal name */
    int tlines, tcols;			/* # lines & columns */
    char *tinstr;  int tinnul;		/* initialization string */
    char *tdeinstr;  int tdeinnul;	/* de-initialization string */
    char *tdcpstr;  int tdcpnul;	/* direct cursor positioning */
    char *tclsstr;  int tclsnul;	/* home and clear screen */
    char *teosstr;  int teosnul;	/* clear to end of screen */
    char *teolstr;  int teolnul;	/* clear to end of line */
    char *trvstr;  char *tnvstr;	/* inverse, normal video */
    int arrows[4];			/* arrow key codes */
};

#define NUMTERM 19			/* number of terminal definitions */
struct term Term[] = {
    {   "ADDS Viewpoint                  ",
	24, 80,
	"",		0,
	"",		0,
	"Y%+ &+ ",	0,
	"",		0,
	"k",		0,
	"K",		0,
	"0P",	"0@",
	016, 020, 006, 002	
    },

    {	"ANSI Standard                   ",
	24, 80,
	"[?7l",	0,
	"[z",		30,
	"[%@;&@H",	0,	
	"[2J",	0,
	"[J",		0,
	"[K",		0,
	"[7m", "[m",		
	016, 020, 006, 002	
    },

    {	"BEEHive 150                     ",
	24, 80,
	"",		0,
	"",		0,
	"F%+ &+ ",	0,
	"E",		0,
	"",		0,
	"",		0,
	"",	"",
	016, 020, 006, 002
    },

    {	"DEC VT-52 and VT-100            ",
	24, 80,
	"",		0,
	"",		0,
	"Y%+ &+ ",	0,
	"E",		0,
	"J",		0,	
	"K",		0,
	"",	"",
	016, 020, 006, 002
    },

    {	"Hazeltine 1500                  ",
	24, 79,
	"",		0,
	"",		0,
	"~&%",	0,	
	"~",		0,
	"",		0,
	"~",		0,
	"",	"",
	016, 020, 006, 002
    },
 
    {	"HDS Concept 100                 ",
	24, 79,
	"U",		0,
	"",		0,
	"a%+ &+ ",	1,
	"",		48,
	"",		0,
	"",		16,
	"",	"",		
	274, 273, 275, 276
    },

    {   "Heath/Zenith 19                 ",
        25, 80,
	"x1tw",	0,
	"z",		30,
	"Y%+ &+ ",	0,
	"E",		0,
	"J",		0,
	"K",		0,
	"p", "q",
	0302, 0301, 0303, 0304
    },

    {	"Intertec Superbrain             ",
	24, 80,
	"",		0,
	"",		0,
	"Y%&",	0,
	"~k",	0,
	"~k",		0,
	"~K",		0,
	"",	"",
	016, 020, 006, 002
    },

    {   "Lear-Seigler ADM-3a             ",
	24, 79,
	"",		0,
	"",		0,
	"=%+ &+ ",	0,
	"\032", 	0,
	"",		0,
	"",		0,
	"",	"",
	016, 020, 006, 002	/* no arrow keys */
    },

    {	"Lear-Siegler ADM-31             ",
	24, 79,
	"",		0,
	"",		0,
	"=%+ &+ ",	0,
	"*",		0,
	"Y",		0,
	"T",		0,
	"G4",	"G0",		
	016, 020, 006, 002	
    },

    {  "Perkin-Elmer Bantam 550          ",
	24, 80,
	"",		0,
	"",		0,
	"X%+ Y&+ ",	0,
	"K",		0,
	"J",		0,	
	"I",		0,
	"",	"",		
	016, 020, 006, 002	
    },

    {  "Perkin-Elmer Fox 1100            ",
	24, 80,
	"",		0,
	"",		0,
	"X%+ Y&+ ",	0,
	"K",		0,
	"J",		0,	
	"I",		0,
	"",	"",		
	016, 020, 006, 002	
    },

    {	"Processor Technology SOL        ",
	16, 64,
	"",		0,
	"",		0,
	"%+ &+ ",0,
	"",		0,
	"",		0,
	"",		0,
	"",	"",
	016, 020, 006, 002
    },

    {   "Soroc IQ120                     ",
	24, 79,
	"",		0,
	"",		0,
	"=%+ &+ ",	0,
	"*",		0,
	"Y",		0,	
	"T",		0,
	")",	"(",		
	016, 020, 006, 002	
    },

    {	"Teleray 1061                    ",
	24, 79,
	"",		0,
	"",		0,
	"Y%+ &+ ",	0,
	"j",		0,
	"J",		0,
	"K",		0,
	"RD",	"R@",	
	016, 020, 006, 002	
    },

    {	"Televideo 912, 920              ",
        24, 79,
        "",             0,
        "",		0,
	"=%+ &+ ",    0,
	"+",		0,
	"Y",		0,
	"T",		0,
	"",	"",
	016, 020, 006, 002	/* unable to use arrow keys */
    },

    {   "Televideo 950                   ",
	24, 79,
	"",		0,
	"",		0,
	"=%+ &+ ",	0,	
	"+",		0,	
	"Y",		0,
	"T",		0,
	"GD",	"G@",
	016, 020, 006, 002
    },

    {   "Vector Graphics                 ",
	24, 79,
        "", 		0,
	"",		0,
	"%&",		0,
	"",		0,
	"",		0,
	"",		0,
	"",	"",	
	016, 020, 006, 002
    },

    {	"Xitec SCT-100                   ",
	16, 64,
	"",		0,
	"",		0,
	"=%+@&+@",	0,	
	"",		0,
	"",		0,
	"",		0,
	"",	"",		
	016, 020, 006, 002	
    }

};

int keybuf, changed;
char *term_char[10] = {
	"Number of lines",
	"Number of columns",
	"Initialization string",
	"Deinitialization string",
	"Direct cursor positioning string",
	"Home and clear entire screen string",
	"Clear to end of screen string",
	"Clear to end of line string",
	"Reverse video, underline, or highlight string",
	"End reverse video, underline, or highlight string"
};
int hxflg = -1; /* -1 ask question, 1 enter hex codes, 0 enter ascii */

main()
{ int chan;
  printf(hithere);
  printf("\nThis program configures Perfect Calc to your system.\n");
  printf("It reads and writes the file PC.OVL on your default disk\n");
  printf("drive, normally drive A.  If you need to exit and change the\n");
  printf("current default drive, type a Control-C now; otherwise, type a\n");
  printf("<CR> (carriage return) to continue: ");  fflush(stdout);
  if (getch() != '\r') exit(1);

  if ((chan=open("PC.OVL", 0x8000)) == -1)
  {   printf("\007Cannot find PC.OVL on default disk.  Do you have the\n");
      printf("correct disk selected?  Exiting to operating system...\n");
      exit(1);
  }
  if(lseek(chan, -512L, 2) == -1 || read(chan, &Tlines, 512) != 512)
  {   printf("\007Cannot read PC.OVL.  Try again using a backup copy.\n");
      printf("Exiting to operating system...\n");  exit(1);
  }
  close(chan);
  while (1)
  { printf("\nMain menu:\n");
    printf("\t1 - Configure terminal\n");
    printf("\t2 - Configure printer\n");
    printf("\t3 - Change command keys\n");
    printf("\t4 - Update (write) PC.OVL file\n");
    printf("\t5 - Exit configuration program\n");
#ifndef PRECONFIG
    printf("\nNew users should perform only steps 1, possibly 2, 4, and 5\n");
    printf("in order.  Experienced users may wish to perform step 3.\n");
#endif
    printf("Your choice: ");
    switch(getint())
#ifdef PRECONFIG
    {   case 1:
    printf("\nThis version of Perfect Calc comes preconfigured for your\n");
    printf("your terminal.  Skip this menu item.\n");  break;
#else
    {	case 1: GetTerm();  break;
#endif
	case 2: SetPrinter();  break;
	case 3: Comd();  break;
	case 4: if ((chan=open("PC.OVL", 0x8001)) == -1 
		    || lseek(chan, -512L, 2) == -1
		    || write(chan, &Tlines, 512) == -1)
		{   printf("\007Cannot update PC.OVL.  Your disk may be ");
		    printf("write-protected or full.\n");
		    printf("Exiting to operating system...\n");  exit(1);
		}
		printf("Update of PC.OVL complete.\n");
		close(chan);  changed = 0;  break;
	case 5: if (!changed || Ask("Exit without updating PC.OVL? "))
		{   printf("Exiting to operating system...\n");  exit(1);   }
		break;
	default:printf("\007Please select 1-5 only!\n");
    }
  }
}

getint()	/* read an integer from the terminal */
{   int n, c;
    fflush(stdout);
    n = 0;  while ((c=getchar()) >= '0' && c <= '9') n = n*10 + c - '0';
    return(n);
}

Ask(ques)	/* ask user a question and return TRUE or FALSE */
char *ques;
{   int ans;
    printf(ques);  fflush(stdout);
    while ((ans = tolower(getch())) != 'y' && ans != 'n')
    {   printf("\007\nPlease answer Yes or No: ");  fflush(stdout);   }
    if (ans == 'y') printf("Yes\n");  else printf("No\n");
    return(ans == 'y');
}

tolower(c)
char c;
{   return((c >= 'A' && c <= 'Z')? c + ('a' - 'A') : c);   }

#ifdef IBM
GetTerm()
{   int i;
    printf("Are you using a monochrome display of any type (Answer 'Yes'\n");
    printf("even if you have a color graphics adapter card driving a\n");
    if(Ask("monochrome graphics monitor.)? "))
    {   printf("Perfect Calc is already configured for your display.\n");
	printf("Please skip this menu item.  Returning to main menu...\n");
	color = 0;  return;
    }
    color = 1;		/* activate color -- dummy! */
    while (1)
    { printf("\nColor Selection Menu:\n");
      printf("(You MAY but do NOT have to change colors using this menu.\n");
      printf("Available colors are:\n");
      for (i=1; i <= 5; i++)
	printf("    %d - %s\t%d - %s\t%d - %s\n", i, c_av[i], i+5,
		c_av[i+5], i+10, c_av[i+10]);
      printf("Current color selections:\n");
      printf("\t1 - Axis color = %s\n", c_av[c_axis]);
      printf("\t2 - Command line color = %s\n", c_av[c_comd]);
      printf("\t3 - Negative numeric entry color = %s\n", c_av[c_neg]);
      printf("\t4 - Normal entry color = %s\n", c_av[c_norm]);
      printf("\t5 - Formula color = %s\n", c_av[c_form]);
      printf("Please select an item 1-5 to change; type <CR> alone\n");
      printf("to return to the main menu.  Your choice: ");
      switch (getint())
      { case 0:	printf("Returning to main menu...\n");  return;
	case 1: printf("Axis color = ");  c_axis = getcolor();
		changed = 1;  break;
	case 2: printf("Command line color = ");  c_comd = getcolor();
		changed = 1;  break;
	case 3: printf("Negative numeric entry color = ");  c_neg = getcolor();
		changed = 1;  break;
	case 4: printf("Normal entry color = ");  c_norm = getcolor();
		changed = 1;  break;
	case 5: printf("Formula color = ");  c_form = getcolor();
		changed = 1;  break;
	default: printf("Please type 1-5 or <CR>: ");  fflush(stdout);  break;
      }
    }
}

getcolor()
{   int c;
    while ((c=getint()) < 1 || c > 15)
        printf("\007Please type 1-15 from the above color chart: ");
    return(c);
}

#else
GetTerm()	/* usual terminal selection menu */
{   int choice;
    int limit;
    int oddterm = (NUMTERM+1) % 2;
    int temp;
    limit = (NUMTERM+1) / 2;
    if ( oddterm ) limit++;
    printf("\nTerminal Selection Menu:");
    for (choice = 0; choice < limit; choice++)
    {   printf("\n%2d - %s", choice+1, Term[choice].tname);
        if ( (temp=choice+limit) < NUMTERM )
             printf(" %2d - %s", temp+1, Term[temp].tname);
	  else if (temp == NUMTERM) printf(" %2d - Other", NUMTERM+1);
    }
    printf("\n\nPlease select your terminal or computer type listed above.\n");
    printf("If it is not listed or you wish to edit your current\n");
    printf("parameters, select \"Other.\"  Your choice: ");
 gc:if (!(choice=getint())) return;
      else if (choice <= NUMTERM) MakTerm(&Term[choice-1].tname);
	else if (choice == NUMTERM+1) DefTerm();
	  else {printf("Please select 1-%d only: ", NUMTERM+1);  goto gc;}
}

MakTerm(t)	/* move terminal parameters to configuration globals */
struct term *t;
{   Tlines = t->tlines;  Tcols = t->tcols;
    copystr(t->tinstr, Tinstr);  Tinnul = t->tinnul;
    copystr(t->tdeinstr, Tdeinstr);  Tdeinnul = t->tdeinnul;
    copystr(t->tdcpstr, Tdcpstr);  Tdcpnul = t->tdcpnul;
    copystr(t->tclsstr, Tclsstr);  Tclsnul = t->tclsnul;
    copystr(t->teosstr, Teosstr);  Teosnul = t->teosnul;
    copystr(t->teolstr, Teolstr);  Teolnul = t->teolnul;
    copystr(t->trvstr, Trvstr);  copystr(t->tnvstr, Tnvstr);
    Keys[5] = t->arrows[0];  Keys[7] = t->arrows[1];
    Keys[9] = t->arrows[2];  Keys[11] = t->arrows[3];
}

DefTerm()	/* define a new terminal type */
{ char str[80];  int i, par;
  printf("\nThis selection allows you to enter your terminal's screen\n");
  printf("characteristics directly.  You may need its user's manual\n");
  printf("to complete this operation!\n");
  ChooseHex();
  while (1)
  { OutTerm();
    printf("\n\nPlease choose a parameter 1-10 to change.  Type <CR> when\n");
    printf("you have finished your changes to go back to the Main menu.\n");
    printf("Your choice: ");
    switch (par=getint())
    {   case 0:	printf("Returning to Main menu...\n");  return;
	case 1:	printf("%s = (decimal) ", term_char[0]);  Tlines = getint();
		changed = 1;  break;
	case 2: printf("%s = (decimal) ", term_char[1]);  Tcols = getint();
		changed = 1;  break;
	case 3: Tinnul = getTstr(term_char[par-1],Tinstr,LIN,1);  break;
	case 4: Tdeinnul = getTstr(term_char[par-1],Tdeinstr,LDEIN,1);  break;
	case 5:
  printf("\nThis one is more complicated.  Please type your terminal's\n");
  printf("direct cursor positioning string using the following notation:");
  printf("\n\n\t");  putchar('%');
  printf("+c = line number plus bias of character code of 'c'\n");
  printf("\t\t\tor\n\t");  putchar('%');
  printf("@  = line number as a sequence of ASCII characters\n");
  printf("\n\t&+c = column number plus bias of character code of 'c'\n");
  printf("\t\t\tor\n");
  printf("\t&@  = column number as a sequence of ASCII characters\n");
  printf("\nFor example, the common ADM-3a cursor positioning string,\n");
  printf("in English, is \"ESCAPE followed by equal sign followed by line\n");
  printf("number plus 32 (decimal) followed by column number plus 32\"\n");
  printf("Using Perfect Calc's conventions, it would be the string:\n");
  printf("  \"^[=");  putchar('%');  printf("+ &+ \"\n");
  printf("(or, in hex, 1BH 3DH 25H 2BH 20H 26H 2BH 20H)\n\n"); 
		Tdcpnul = getTstr(term_char[par-1],Tdcpstr,LDCP,1);  break;
	case 6: Tclsnul = getTstr(term_char[par-1],Tclsstr,LCLS,1);  break;
	case 7: Teosnul = getTstr(term_char[par-1],Teosstr,LEOS,1);  break;
	case 8: Teolnul = getTstr(term_char[par-1],Teolstr,LEOL,1);  break;
	case 9: getTstr(term_char[par-1],Trvstr,LRV,0);  break;
	case 10: getTstr(term_char[par-1],Tnvstr,LNV,0);  break;
	default: printf("Please type 1-10 or <CR>: ");  fflush(stdout);  break;
    }
  }
}
#endif

getTstr(desc,str,n,getnul)  /* get a terminal char string (< n chars long)*/
char *desc, *str;  int n, getnul;
{   static int c, i;  static char *sp;
    if (hxflg) readhex(desc,str,n);
      else readasci(desc,str,n);
    changed = 1;
    if (getnul)
    {	printf("\nNumber of NULs for padding after this string = ");
	i = getint();  if (i < 0) i = 0;
    }
    return(i);
}

outch(c)	/* echo any character */
char c;
{   if (c < ' ') {putchar('^');  putchar(c+0100); }
      else if (c < 0200) putchar(c);
	else {putchar('~');  outch(c-0200);}
    fflush(stdout);  return(c);
}

readasci(desc,str,n)
char *desc, *str; int n;
{   static int c, i; static char *sp;
 gs:printf("%s = ", desc);  fflush(stdout);  sp = str;
    for (i=1; i<n; i++)
    {   if ((c=getch()) == '\r') break;  outch(*sp++ = c);   }
    if (i >= n) 
    {   printf("\007\nString overflow!  Please enter a shorter string.\n");
	goto gs;
    }
    *sp = 0;
}

readhex(desc,stp,n)
char *desc, *stp; int n;
{  static char *sp, *hp, *hp1, *tp, str[STRLEN+2]={STRLEN}, *cgets();
   static int tempx, i;
gs:printf("%s = ", desc);   fflush(stdout);  sp = str;   tp = stp;
   sp = cgets(str);				/* read in the char string */
   hp = sp;  i = 0;
   while (1)
   {   while (*hp && isdelim(*hp)) hp++;
       if (*hp == 0) break;
       tempx  = makehex(hp);
       if (tempx < 0) 			/* errors */
            goto gs;
       if (++i >= n) break;  *tp++ = tempx; 
       while (islegal(*hp)) hp++;	/* get to next hex chars */
   } if (*hp) {
	printf("\007\nString overflow!  Please enter a shorter string.\n");
	goto gs;
      }

   *tp = 0;
}   

makehex(hp)  /* get hex code from 2 characters pointed to by hp*/
char *hp;
{   static int hex, i;  char j;
    hex = 0;
    for ( i=HC; i && (islegal(j = *hp++)); i--)
        hex =hex * 16 + hexval(j); 
    if (hex > MAXHEX)
        { printf("\007\nHex code too large!  ");
       ag:printf("Please try again, using only\n");
	  printf("2-hex-digit (8 bit) numbers.\n");
          return(-1);
	}
    if ((j != '\0') && !isdelim(j))  /* error condition */
        {  printf("\007\nNon-hex code entered!  ");  goto ag;  }
    return(hex);
}             

hexval(x)
char x;
{   static int y;
    y = toupper(x) - '0';
    return((x > '9') ? y - HXOS : y ); /*HXOS is an offset for hex letters*/
}

islegal(c)  /* check for legal hex codes */
char c;
{  return((c >= '0' && c <= '9')||(c >= 'A' && c <= 'F')||
      (c >= 'a' && c <= 'f'));
}

isdelim(c)   /* skip over delimiters: blank through / (ascii order) */
char c;
{  return((c >= ' ' && c <= '/') || (c == 'H' || c == 'h'));   }

toupper(c)  /* change lower case hex letters to upper */
char c;
{  return ((c >= 'a' && c <= 'f') ? c - ('a' - 'A') : c);  }

/*  NOT USED IN LATTICE VERSION
getstr(sp)
char *sp;
{  static char sp2, c; static int i;
   i = 1;  sp2 = sp; /* sp points to the beginning of the string */
   while (((c = getch()) != '\r') && (i++ < STRLEN-1)) putch(*sp2++ = c);
   if (i >= STRLEN) return (0);
   *sp2 = 0;  return (1);
}
*/

copystr(s1,s2)
char *s1, *s2;
{   while (*s1) *s2++ = *s1++;  *s2 = 0;  changed = 1;  }


ChooseHex()
{ if (hxflg == -1)
  { printf("\nStrings (used for screen or printer characteristics)\n");
    printf("may be entered and displayed using either actual keystrokes\n");
    printf("from your terminal or hex codes.\n");
    printf("(For example, ESCAPE can be entered either by typing that key\n");
    printf("on your keyboard (and seeing it echoed as '^[') or by typing\n");
    printf("the hex code 1B.)  Do you want to use hex codes for entering\n");
    if (hxflg = Ask("all strings? "))
    { printf("Please note that you should use decimal integers whenever\n");
      printf("actual numeric values are requested.\n");
    }   /* just do above once per run */
  }
}


OutTerm()
{   printf("\nCurrent terminal characteristics selected:");
    printf("\n    1 - %s = %d (decimal)", term_char[0], Tlines);
    printf("\n    2 - %s = %d (decimal)", term_char[1], Tcols);
    printf("\n    3 - %s = ", term_char[2]);  outstr(Tinstr); prnul(Tinnul);
    printf("\n    4 - %s = ",term_char[3]);  outstr(Tdeinstr); prnul(Tdeinnul);
    printf("\n    5 - %s = ", term_char[4]);  outstr(Tdcpstr);  prnul(Tdcpnul);
    printf("\n    6 - %s = ", term_char[5]);  outstr(Tclsstr);  prnul(Tclsnul);
    printf("\n    7 - %s = ", term_char[6]);  outstr(Teosstr);  prnul(Teosnul);
    printf("\n    8 - %s = ", term_char[7]);  outstr(Teolstr);  prnul(Teolnul);
    printf("\n    9 - %s = ", term_char[8]);  outstr(Trvstr);
    printf("\n   10 - %s = ", term_char[9]);  outstr(Tnvstr);
    fflush(stdout);
}

outstr(str)	/* output a string to the terminal */
char *str;
{   if (!hxflg) while (*str) outch(*str++);
    else {  while (*str) printf("%2xH ", *str++ & 0xFF);  fflush(stdout);  }
}

prnul(n)	/* print # NULs */
int n;
{   if (n) printf("\n        NULs sent after above string = %d", n);   }

SetPrinter()
{ ChooseHex(); 
  while (1)
  { printf("\nCurrent Printer Configuration:\n");
    printf("\n\t1 - Printer width = %d", prtwidth);
    printf("\n\t2 - Printer initialization string = ");  outstr(Pinstr);
    printf("\n\t3 - Printer deinitialization string = ");  outstr(Pdeinstr);
    printf("\n\nPlease select one of the above to change, or type <CR>\n");
    printf("to go back to the Main menu.  Your choice: ");
    switch (getint())
    {   case 0: printf("Returning to Main menu...\n");  return;
	case 1: printf("Printer width = ");
		prtwidth = getint();  changed = 1;  break;
	case 2: getTstr("Printer initialization string", Pinstr, LPIN,0);
		break;
	case 3: getTstr("Printer deinitialization string", Pdeinstr, LPDEIN,0);
		break;
	default:printf("\007Please type 1-3 only!");  break;
    }
  }
}

Comd()
{ int func, new_func, i, c;

 printf("\nThis selection allows you to change the keystroke combinations\n");
 printf("used to perform Perfect Calc's functions. Each function may be\n");
 printf("duplicated by another valid keystroke combination.  For example,\n");
 printf("you may wish to have your arrow keys duplicate Perfect Calc's\n");
 printf("C-F, C-B, C-N, and C-P cursor commands.  Or you may choose\n");
 printf("to activate your terminal's function keys.  For each change you\n");
 printf("wish to make, please type the command to be duplicated followed\n");
 printf("by an alternate one for that function.  (Note that ESC and Ctrl-X\n");
 printf("commands consist of more than one keystroke, but are still\n");
 printf("considered to be a single command.)  Your command will be echoed\n");
 printf("using the Perfect Calc manual's notation.  There are several\n");
 printf("commands which you may NOT change:\n\n");
 printf("\tESC = Escape command prefix\n");
 printf("\tC-X = Control-X command prefix\n");
 printf("\tC-G = Bell/abort command\n");
 printf("\tDEL = Erase last character or function\n");
 printf("\tCR  = Command terminator\n\n");
 printf("To completely change, rather than just duplicate a command, do\n");
 printf("the above sequence TWICE for the same command.  When you have\n");
 printf("finished changing commands, type <CR> alone.\n");
  while (1)
  { printf("\nPresent command:  ");  fflush(stdout);
    if ((func=NextFunc()) < 0)
    {	printf("\007\nThat command is not defined!");  continue;  }
    if (func == 2) break;     /* <CR> alone */
    printf("  will be replaced by:  ");  fflush(stdout);
    if ((new_func=NextFunc()) >= 0)
    {	printf("\007\nThat command is already defined!");  continue;   }
    Keys[func] = keybuf;  changed = 1;
  }
  printf("\nDo you want a status line to continuously appear along the\n");
  printf("bottom of your screen (to label function keys or remind you\n");
  if (Ask("of these changes, for example?  "))
  {ag:printf("\nPlease type the status line now. It will be echoed exactly\n");
    printf("as it will appear on your screen -- feel free to use escape\n");
    printf("sequences or control codes (to go into or out of reverse\n");
    printf("video, for example).  End with a <CR> as usual:\n");
    for (i=0; i<LBOTTOM-1; i++)
	if ((c=getch()) == '\r') break; else putch(Tbottom[i] = c);
    Tbottom[i] = 0;
    if (!Ask("\nIs this line correct? ")) goto ag;  --Tlines;  changed = 1;
  }
  else if ( Tbottom[0] != 0 ) {  Tbottom[0] = 0;  ++Tlines;  changed = 1;  }
  printf("Returning to Main menu...\n");
}

NextFunc()	/* get next function */
{   int i;
    NextKey();
    for(i=0; Keys[i]; i++) if (keybuf == Keys[i]) return(i);
    return(-1);
}

NextKey()	/* Get next key typed */
{gc:keybuf = getch();
 sw:switch (keybuf & 0177)
    {	case ESC:	printf("ESC ");  fflush(stdout);
			keybuf = getch() + 0400;  goto sw;
	case CTRLX:	printf("C-X ");  fflush(stdout);
			keybuf = getch() + 01000;  goto sw;
#ifdef IBM
	case 0:		printf("NULL ");  fflush(stdout);
			keybuf += getch() + 0200;  goto sw;
#endif
	case BEL:
	case DEL:	putch(BEL);  goto gc;
	case '\r':	printf("\n");  return(keybuf);
    }
    outkey(keybuf);  return(keybuf);	/* return single first character */
}

outkey(c)
int c;
{   c &= 0177;  if (c < ' ') {printf("C-");  fflush(stdout);  c += 0100;}
    putch(c);  }
