echo x - Makefile
sed '/^X/s///' > Makefile << '/'
X# Makefile for ic
X
XCFLAGS	= -O -D_POSIX_SOURCE -D_MINIX
XO=o
X
XOBJ   = ic.$O ic_input.$O ic_output.$O 
X
Xic:	$(OBJ)
X	@rm -rf ic
X	@echo Start linking ic
X	@cc  $(OBJ) -o ic >/dev/null
X	@chmem =8192 ic
X
X$(ICOBJ): ic.h
X
Xclean:
X	@rm -f *.o *.s ic *.bak core
/
echo x - ic.c
sed '/^X/s///' > ic.c << '/'
X/*****************************************************************/
X/*								 */
X/*	ic.c							 */
X/*								 */
X/*		The main loop of the "Integer Calculator". 	 */
X/*								 */
X/*****************************************************************/
X/*  origination          1988-Apr-6   	    Terrence W. Holm 	 */
X/*  added Exec_Shell()   1988-Apr-11	    Terrence W. Holm 	 */
X/*  added "s+"		 1988-Apr-18	    Terrence W. Holm 	 */
X/*  added cmd line args  1988-May-13	    Terrence W. Holm 	 */
X/*  'i' also does 'o'	 1988-May-28	    Terrence W. Holm 	 */
X/*  if ~dec:unsigned *%/ 1988-Jul-10	    Terrence W. Holm 	 */
X/*****************************************************************/
X#include <sys/types.h>
X#include <sys/wait.h>
X#include <signal.h>
X#include <string.h>
X#include <stdlib.h>
X#include <unistd.h>
X#include <stdio.h>
X#include "ic.h"
X
Xstatic char copyright[] = {"ic    (c) Terrence W. Holm 1988"};
X
X/****************************************************************/
X/*							 */
X/*	main()						 */
X/*							 */
X/*		Initialize. Enter the main processing loop. */
X/*							 */
X/****************************************************************/
Xint main(argc, argv)
Xint argc;
Xchar *argv[];
X{
X  ic_state state;		/* This state record is passed to most procs */
X
X  Init_State(&state);
X  state.scratch_pad = (FILE *) NULL;	/* No 'w' command yet	 */
X  Init_Getc(argc, argv);	/* Refs to command line args	 */
X
X  if (Init_Termcap() == 0) {
X	fprintf(stderr, "ic requires a termcap entry\n");
X	exit(1);
X  }
X  Save_Term();			/* Save terminal characteristics */
X
X  if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
X	signal(SIGINT, Sigint);
X	signal(SIGQUIT, Sigint);
X  }
X  Set_Term();			/* Setup terminal characteristics */
X  Draw_Screen(&state);
X  while (1) {
X	int rc = Process(&state, Get_Char());
X
X	if (rc == EOF) break;
X	if (rc == ERROR) putchar(BELL);
X  }
X
X  Reset_Term();			/* Restore terminal characteristics */
X  exit(OK);
X}
X
X/****************************************************************/
X/*							 	*/
X/*	Init_State()					 	*/
X/*							 	*/
X/*		Initialize the state record.		 	*/
X/*							 	*/
X/****************************************************************/
Xvoid Init_State(s)
Xic_state *s;
X{
X  s->stack[0] = 0;
X  s->stack_size = 1;
X  s->register_mask = 0x000;
X  s->last_tos = 0;
X  s->mode = LAST_WAS_ENTER;
X  s->input_base = DECIMAL;
X  s->output_base = DECIMAL;
X}
X
X/*****************************************************************/
X/*								 */
X/*	Sigint()						 */
X/*								 */
X/*		Terminate the program on an interrupt (^C) 	 */
X/*		or quit (^\) signal.			 	 */
X/*							 	 */
X/*****************************************************************/
Xvoid Sigint(sig)
Xint sig;
X{
X  Reset_Term();			/* Restore terminal characteristics */
X  exit(1);
X}
X
X/*****************************************************************/
X/*								 */
X/*	Process( state, input_char )				 */
X/*								 */
X/*		Determine the function requested by the  	 */
X/*		input character. Returns OK, EOF or ERROR. 	 */
X/*							 	 */
X/******************************************************************/
Xint Process(s, c)
Xic_state *s;
Xint c;
X{
X  switch (c) {
X      case '0':
X      case '1':
X      case '2':
X      case '3':
X      case '4':
X      case '5':
X      case '6':
X      case '7':
X      case '8':
X      case '9':
X	return(Enter_Numeric(s, (int) c - '0'));
X
X      case 'a':
X      case 'b':
X      case 'c':
X      case 'd':
X      case 'e':
X      case 'f':
X	return(Enter_Numeric(s, (int) c - 'a' + 10));
X
X      case 'h':
X      case '?':			/* Help	*/
X
X	Draw_Help_Screen();
X	Get_Char();
X	Draw_Screen(s);
X	return(OK);
X
X      case 'i':			/* Set i/p and o/p base	 */
X	{
X		int numeral;
X
X		Draw_Prompt("Base?");
X		numeral = Get_Base(Get_Char());
X		Erase_Prompt();
X		if (numeral == ERROR || numeral == ASCII) return(ERROR);
X		s->input_base = numeral;
X		s->output_base = numeral;
X		s->mode = LAST_WAS_FUNCTION;
X		Draw_Screen(s);
X		return(OK);
X	}
X
X      case 'l':
X      case ESC_PGDN:		/* Get last tos value */
X	if (s->mode != LAST_WAS_ENTER) Push(s);
X	s->stack[0] = s->last_tos;
X	s->mode = LAST_WAS_FUNCTION;
X	Draw_Stack(s);
X	return(OK);
X
X      case 'm':			/* Invoke a Minix shell */
X	Reset_Term();
X	Exec_Shell();
X	Set_Term();
X	Draw_Screen(s);
X	return(OK);
X
X      case 'o':			/* Set output base */
X	{
X		int numeral;
X
X		Draw_Prompt("Base?");
X		numeral = Get_Base(Get_Char());
X		Erase_Prompt();
X		if (numeral == ERROR) return(ERROR);
X		s->output_base = numeral;
X		s->mode = LAST_WAS_FUNCTION;
X		Draw_Screen(s);
X		return(OK);
X	}
X
X      case 'p':
X      case ESC_DOWN:		/* Pop: Roll down stack */
X	{
X		long int temp = s->stack[0];
X		int i;
X
X		for (i = 0; i < s->stack_size - 1; ++i)
X			s->stack[i] = s->stack[i + 1];
X
X		s->stack[s->stack_size - 1] = temp;
X		s->mode = LAST_WAS_FUNCTION;
X		Draw_Stack(s);
X		return(OK);
X	}
X
X      case 'q':
X      case ESC_END:		/* Quit		 */
X      case EOF:
X      case CTRL_D:
X	return(EOF);
X
X      case 'r':
X      case ESC_LEFT:		/* Recall from register */
X	{
X		int numeral;
X
X		Draw_Prompt("Register?");
X		numeral = Get_Char() - '0';
X		Erase_Prompt();
X		if (numeral < 0 || numeral >= REGISTERS ||
X				    ((1 << numeral) & s->register_mask) == 0)
X			return(ERROR);
X
X		if (s->mode != LAST_WAS_ENTER) Push(s);
X		s->stack[0] = s->registers[numeral];
X		s->mode = LAST_WAS_FUNCTION;
X		Draw_Stack(s);
X		return(OK);
X	}
X
X      case 's':
X      case ESC_RIGHT:		 /* Store in register,  */
X			 	 /* Or accumulate if "s+" is typed */
X	{
X		int c;
X		int numeral;
X
X		Draw_Prompt("Register?");
X		c = Get_Char();
X		if (c == ESC_PLUS)
X			c = '+';	/* Allow keypad '+' */
X		if (c == '+') {
X			Draw_Prompt("Accumulator?");
X			numeral = Get_Char() - '0';
X		} else
X			numeral = c - '0';
X		Erase_Prompt();
X		if (numeral < 0 || numeral >= REGISTERS) return(ERROR);
X
X		if (c != '+' || (s->register_mask & (1 << numeral)) == 0) {
X			s->register_mask |= 1 << numeral;
X			s->registers[numeral] = s->stack[0];
X		} else
X			s->registers[numeral] += s->stack[0];
X		s->mode = LAST_WAS_FUNCTION;
X		Draw_Registers(s);
X		return(OK);
X	}
X
X      case 't':			/* Translate from ASCII */
X	{
X		long int numeral;
X
X		Draw_Prompt("Character?");
X		numeral = (long int) Getc();
X		Erase_Prompt();
X		if (s->mode != LAST_WAS_ENTER) Push(s);
X		s->stack[0] = numeral;
X		s->mode = LAST_WAS_FUNCTION;
X		Draw_Stack(s);
X		return(OK);
X	}
X
X      case 'w':
X      case ESC_PGUP:		/* Write tos to a file */
X	{
X		if ((int) s->scratch_pad == (int) NULL) {
X			/* Try to open a scratch pad file  */
X			strcpy(s->file_name, "./pad");
X			if ((s->scratch_pad = fopen(s->file_name,"w")) ==NULL){
X				/* Unsuccessful, try in /tmp  */
X				char *id;
X
X				strcpy(s->file_name, "/tmp/pad_");
X				if ((id = cuserid(NULL)) == NULL)
X					return(ERROR);
X				strcat(s->file_name, id);
X				if ((s->scratch_pad = fopen(s->file_name, "w")) == NULL)
X					return(ERROR);
X			}
X			Draw_Screen(s);
X		}
X
X		/* We have a successfully opened file  */
X		Print_Number(s->scratch_pad, s->stack[0], s->output_base);
X		putc('\n', s->scratch_pad);
X		fflush(s->scratch_pad);
X		s->mode = LAST_WAS_FUNCTION;
X		return(OK);
X	}
X
X      case 'x':
X      case ESC_UP:		/* Exchange top of stack */
X	{
X		long int temp = s->stack[0];
X
X		if (s->stack_size < 2) return(ERROR);
X		s->stack[0] = s->stack[1];
X		s->stack[1] = temp;
X		s->mode = LAST_WAS_FUNCTION;
X		Draw_Stack(s);
X		return(OK);
X	}
X
X      case 'z':
X      case ESC_HOME:		/* Clear all */
X	Init_State(s);
X	Draw_Screen(s);
X	return(OK);
X
X      case BS:
X      case DEL:			/* Clear top of stack */
X	s->stack[0] = 0;
X	s->mode = LAST_WAS_ENTER;
X	Draw_Top_of_Stack(s);
X	return(OK);
X
X      case '\n':		/* Enter */
X	Push(s);
X	s->mode = LAST_WAS_ENTER;
X	Draw_Stack(s);
X	return(OK);
X
X      case '.':			/* Change sign */
X
X	s->last_tos = s->stack[0];
X	s->stack[0] = -s->stack[0];
X	s->mode = LAST_WAS_FUNCTION;
X	Draw_Top_of_Stack(s);
X	return(OK);
X
X      case '+':
X      case ESC_PLUS:		/* Add */
X	if (s->stack_size < 2) return(ERROR);
X	s->last_tos = s->stack[0];
X	Pop(s);
X	s->stack[0] += s->last_tos;
X	s->mode = LAST_WAS_FUNCTION;
X	Draw_Stack(s);
X	return(OK);
X
X      case '-':
X      case ESC_MINUS:		/* Subtract */
X	if (s->stack_size < 2) return(ERROR);
X	s->last_tos = s->stack[0];
X	Pop(s);
X	s->stack[0] -= s->last_tos;
X	s->mode = LAST_WAS_FUNCTION;
X	Draw_Stack(s);
X	return(OK);
X
X      case '*':			/* Multiply */
X	if (s->stack_size < 2) return(ERROR);
X	s->last_tos = s->stack[0];
X	Pop(s);
X	if (s->input_base == DECIMAL)
X		s->stack[0] *= s->last_tos;
X	else
X		s->stack[0] = (long int) (UNS(s->stack[0]) * UNS(s->last_tos));
X	s->mode = LAST_WAS_FUNCTION;
X	Draw_Stack(s);
X	return(OK);
X
X      case '/':			/* Divide */
X	if (s->stack_size < 2 || s->stack[0] == 0) return(ERROR);
X	s->last_tos = s->stack[0];
X	Pop(s);
X	if (s->input_base == DECIMAL)
X		s->stack[0] /= s->last_tos;
X	else
X		s->stack[0] = (long int) (UNS(s->stack[0]) / UNS(s->last_tos));
X	s->mode = LAST_WAS_FUNCTION;
X	Draw_Stack(s);
X	return(OK);
X
X      case '%':
X      case ESC_5:		/* Remainder */
X
X	if (s->stack_size < 2 || s->stack[0] == 0) return(ERROR);
X	s->last_tos = s->stack[0];
X	Pop(s);
X	if (s->input_base == DECIMAL)
X		s->stack[0] %= s->last_tos;
X	else
X		s->stack[0] = (long int) (UNS(s->stack[0]) % UNS(s->last_tos));
X	s->mode = LAST_WAS_FUNCTION;
X	Draw_Stack(s);
X	return(OK);
X
X      case '~':			/* Not */
X	s->last_tos = s->stack[0];
X	s->stack[0] = ~s->stack[0];
X	s->mode = LAST_WAS_FUNCTION;
X	Draw_Top_of_Stack(s);
X	return(OK);
X
X      case '&':			/* And */
X	if (s->stack_size < 2) return(ERROR);
X	s->last_tos = s->stack[0];
X	Pop(s);
X	s->stack[0] &= s->last_tos;
X	s->mode = LAST_WAS_FUNCTION;
X	Draw_Stack(s);
X	return(OK);
X
X      case '|':			/* Or */
X	if (s->stack_size < 2) return(ERROR);
X	s->last_tos = s->stack[0];
X	Pop(s);
X	s->stack[0] |= s->last_tos;
X	s->mode = LAST_WAS_FUNCTION;
X	Draw_Stack(s);
X	return(OK);
X
X      case '^':			/* Exclusive-or */
X	if (s->stack_size < 2) return(ERROR);
X	s->last_tos = s->stack[0];
X	Pop(s);
X	s->stack[0] ^= s->last_tos;
X	s->mode = LAST_WAS_FUNCTION;
X	Draw_Stack(s);
X	return(OK);
X
X      default:	
X	return(ERROR);
X  }
X}
X
X/*****************************************************************/
X/*								 */
X/*	Enter_Numeric( state, numeral )				 */
X/*								 */
X/*		A numeral (0 to 15) has been typed.		 */
X/*		If a number is currently being entered	 	 */
X/*		then shift it over and add this to the		 */
X/*		display. If the last operation was a function    */
X/*		then push up the stack first. If the last 	 */
X/*		key was "ENTER", then clear out the top of	 */
X/*		the stack and put the numeral there.		 */
X/*								 */
X/*		Returns OK or ERROR.				 */
X/*								 */
X/*****************************************************************/
Xint Enter_Numeric(s, numeral)
Xic_state *s;
Xint numeral;
X{
X  if (numeral >= s->input_base) return(ERROR);
X
X  switch (s->mode) {
X      case LAST_WAS_FUNCTION:
X	Push(s);
X	s->stack[0] = numeral;
X	Draw_Stack(s);
X	break;
X
X      case LAST_WAS_NUMERIC:
X	s->stack[0] = s->stack[0] * s->input_base + numeral;
X	Draw_Top_of_Stack(s);
X	break;
X
X      case LAST_WAS_ENTER:
X	s->stack[0] = numeral;
X	Draw_Top_of_Stack(s);
X	break;
X
X      default:
X	fprintf(stderr, "Internal failure (mode)\n");
X	Sigint(0);
X  }
X
X  s->mode = LAST_WAS_NUMERIC;
X  return(OK);
X}
X
X/*****************************************************************/
X/*								 */
X/*	Push( state )						 */
X/*								 */
X/*		Push up the stack one level.			 */
X/*								 */
X/*****************************************************************/
Xvoid Push(s)
Xic_state *s;
X{
X  int i;
X
X  if (s->stack_size == STACK_SIZE) --s->stack_size;
X  for (i = s->stack_size; i > 0; --i) s->stack[i] = s->stack[i - 1];
X  ++s->stack_size;
X}
X
X/*****************************************************************/
X/*								 */
X/*	Pop( state )						 */
X/*								 */
X/*		Pop the stack down one level.			 */
X/*		This routine is only called with 		 */
X/*		the stack size > 1.				 */
X/*								 */
X/*****************************************************************/
Xvoid Pop(s)
Xic_state *s;
X{
X  int i;
X
X  for (i = 0; i < s->stack_size - 1; ++i) s->stack[i] = s->stack[i + 1];
X  --s->stack_size;
X}
X
X/****************************************************************/
X/*							  	*/
X/*	Exec_Shell()					  	*/
X/*							  	*/
X/*		Fork off a sub-process to exec() the shell.  	*/
X/*							  	*/
X/****************************************************************/
X
Xvoid Exec_Shell()
X{
X  int pid = fork();
X
X  if (pid == -1) return;
X  if (pid == 0) {
X	/* The child process  */
X	extern char **environ;
X	char *shell = getenv("SHELL");
X
X	if (shell == NULL) shell = "/bin/sh";
X	execle(shell, shell, (char *) 0, environ);
X	perror(shell);
X	exit(127);
X  }
X
X  /* The parent process: ignore signals, wait for sub-process	 */
X  signal(SIGINT, SIG_IGN);
X  signal(SIGQUIT, SIG_IGN);
X  {
X	int status;
X	int w;
X
X	while ((w = wait(&status)) != pid && w != -1);
X  }
X
X  signal(SIGINT, Sigint);
X  signal(SIGQUIT, Sigint);
X  return;
X}
/
echo x - ic.h
sed '/^X/s///' > ic.h << '/'
X/****************************************************************/
X/*								*/
X/*	ic.h							*/
X/*								*/
X/*		Definitions for the "Integer Calculator".	*/
X/*								*/
X/****************************************************************/
X/*  origination         1988-Apr-6         Terrence W. Holm	*/
X/****************************************************************/
X
X/****************************************************************/
X/*								*/
X/*	ic(1)							*/
X/*								*/
X/* This is a simple RPN calculator, used for small calculations */
X/* and base conversions. All calculations are done using 32 bit */
X/* integers.							*/
X/*								*/
X/* Commands are available for stack operations, saving results, */
X/* arithmetic and logical operations, and escaping to the Minix */
X/* shell.							*/
X/*								*/
X/* The program requires termcap(3), but otherwise should run	*/
X/* under all Unix (tm) variants.				*/
X/*								*/
X/* See the ic(1) man page.					*/
X/*								*/
X/****************************************************************/
X
X/****************************************************************/
X/*								*/
X/*	ic 		   Copyright  Terrence W. Holm  1988	*/
X/*								*/
X/* This program was written for users of the Minix operating	*/
X/* system, and in the spirit of other public domain software	*/
X/* written for said system, this source code is made available	*/
X/* at no cost to everyone.					*/
X/*								*/
X/* This program (one .h, three .c and a "man" page) may be	*/
X/* copied and/or modified subject to (1) no charge must be	*/
X/* made for distribution, other than for the medium, (2) all	*/
X/* modified sources must be clearly marked as such, (3) all	*/
X/* sources must carry this copyright.				*/
X/*								*/
X/****************************************************************/
X
X/****************************************************************/
X/*								*/
X/*	files							*/
X/*								*/
X/*	    ic.h		Definitions			*/
X/*	    ic.c		The main loop			*/
X/*	    ic_input.c		Character input routines	*/
X/*	    ic_output.c		Output routines			*/
X/*								*/
X/*	    ic.1		"Man" page			*/
X/*	    Makefile		For "make"			*/
X/*								*/
X/****************************************************************/
X
X#define   UNS(x)	((unsigned long)(x))
X#define   STACK_SIZE 	6		/*  Max # of levels	*/
X#define   REGISTERS	10		/*  Registers 0 to 9	*/
X#define	  LAST_WAS_ENTER    1		/*  Numeric input modes	*/
X#define	  LAST_WAS_NUMERIC  2
X#define	  LAST_WAS_FUNCTION 3
X#define   ASCII		-1		/*  Input and output	*/
X#define   BINARY  	2		/*  modes		*/
X#define   OCTAL		8
X#define	  DECIMAL	10
X#define   HEXADECIMAL	16
X#define   OK		0		/*  Return codes	*/
X#define   ERROR		1
X
X#define   CTRL_D	'\004'		/*  ASCII ^D		*/
X#define   BELL		'\007'		/*  ASCII bell code     */
X#define   BS		'\010'		/*  ASCII back space	*/
X#define	  ESCAPE  	'\033'		/*  ASCII escape code	*/
X#define   DEL           '\177'		/*  ASCII delete code   */
X
X/*  Input escape codes generated by the	Minix console.	*/
X/*  Format: ESC [ X. Shows character equivalent for ic.	*/
X#define   ESC_HOME	'H' + 0x80  	/*   z			*/
X#define   ESC_UP	'A' + 0x80  	/*   x			*/
X#define   ESC_PGUP	'V' + 0x80	/*   w			*/
X#define   ESC_LEFT	'D' + 0x80	/*   r			*/
X#define   ESC_5		'G' + 0x80	/*   %                  */
X#define   ESC_RIGHT	'C' + 0x80	/*   s			*/
X#define   ESC_END	'Y' + 0x80	/*   q			*/
X#define   ESC_DOWN	'B' + 0x80	/*   p			*/
X#define   ESC_PGDN	'U' + 0x80	/*   l			*/
X#define   ESC_PLUS	'T' + 0x80	/*   +			*/
X#define   ESC_MINUS	'S' + 0x80	/*   -			*/
X
X/*  Move positions for the output display.		*/
X#define   STACK_COLUMN	4
X#define   STACK_LINE	7
X#define   REG_COLUMN	STACK_COLUMN+36
X#define   REG_LINE	3
X#define   STATUS_COLUMN	6
X#define   STATUS_LINE   0
X#define   WAIT_COLUMN   0
X#define   WAIT_LINE     14
X
Xtypedef  struct  ic_state		/*  State of int. calc.	*/
X{
X  long int stack[ STACK_SIZE ];		/*  The stack		*/
X  long int registers[ REGISTERS ];	/*  The registers	*/
X  int  stack_size;			/*  Current size (>= 1)	*/
X  int  register_mask;			/*  In use bit mask	*/
X  long int last_tos;			/*  For 'L' command	*/
X  int  mode;				/*  Last key type. See	*/
X					/*  LAST_WAS_ENTER, etc	*/
X  int  input_base;			/*  Current i/o base,	*/
X  int  output_base;			/*  ASCII, BINARY, etc	*/
X  
X  FILE *scratch_pad;			/*  For 'w' command	*/
X  char  file_name[20];			/*  "pad" or "/tmp/pad"	*/
X} ic_state;
X
X/* ic.c */
X_PROTOTYPE(int main, (int argc, char *argv []));
X_PROTOTYPE(void Init_State, (ic_state *s ));
X_PROTOTYPE(void Sigint, (int sig ));
X_PROTOTYPE(int Process, (ic_state *s, int c ));
X_PROTOTYPE(int Enter_Numeric, (ic_state *s, int numeral ));
X_PROTOTYPE(void Push, (ic_state *s ));
X_PROTOTYPE(void Pop, (ic_state *s ));
X_PROTOTYPE(void Exec_Shell, (void));
X
X/* ic_input.c */
X_PROTOTYPE(void Save_Term, (void));
X_PROTOTYPE(void Set_Term, (void));
X_PROTOTYPE(void Reset_Term, (void));
X_PROTOTYPE(int Get_Char, (void));
X_PROTOTYPE(void Init_Getc, (int argc, char *argv []));
X_PROTOTYPE(int Getc, (void));
X_PROTOTYPE(int Get_Base, (int code ));
X
X/* ic_output.c */
X_PROTOTYPE(int Init_Termcap, (void));
X_PROTOTYPE(void Move, (int column, int line ));
X_PROTOTYPE(void Puts, (char *string ));
X_PROTOTYPE(void Putchar, (int c ));
X_PROTOTYPE(void Draw_Help_Screen, (void));
X_PROTOTYPE(void Draw_Prompt, (char *string ));
X_PROTOTYPE(void Erase_Prompt, (void));
X_PROTOTYPE(void Draw_Screen, (ic_state *s ));
X_PROTOTYPE(void Draw_Stack, (ic_state *s ));
X_PROTOTYPE(void Draw_Registers, (ic_state *s ));
X_PROTOTYPE(void Draw_Top_of_Stack, (ic_state *s ));
X_PROTOTYPE(void Print_Number, (FILE *stream, long int numb, int output_base ));
/
echo x - ic_input.c
sed '/^X/s///' > ic_input.c << '/'
X/****************************************************************/
X/*								*/
X/*	ic_input.c						*/
X/*								*/
X/*		Character input routines for the		*/
X/*		"Integer Calculator".				*/
X/*								*/
X/****************************************************************/
X/*  origination          1988-Apr-7         Terrence W. Holm	*/
X/*  added cmd line args  1988-May-13	    Terrence W. Holm	*/
X/****************************************************************/
X#include <stdio.h>
X#include <ctype.h>
X#include <sgtty.h>
X
X#include "ic.h"
X
Xstatic struct sgttyb saved_mode;
Xstatic struct tchars saved_chars;
X
X/****************************************************************/
X/*								*/
X/*	Save_Term()						*/
X/*								*/
X/*		Save the current terminal characteristics.	*/
X/*								*/
X/****************************************************************/
Xvoid Save_Term()
X{
X  ioctl(0, TIOCGETP, &saved_mode);
X  ioctl(0, TIOCGETC, (struct sgttyb *) & saved_chars);
X}
X
X/****************************************************************/
X/*								*/
X/*	Set_Term()						*/
X/*								*/
X/*		Set up the terminal characteristics for ic.	*/
X/*								*/
X/****************************************************************/
Xvoid Set_Term()
X{
X  struct sgttyb ic_mode;
X  struct tchars ic_chars;
X
X  ic_mode = saved_mode;
X  ic_chars = saved_chars;
X
X  /* No tab expansion, no echo, cbreak mode			 */
X  ic_mode.sg_flags = (ic_mode.sg_flags & ~XTABS & ~ECHO) | CBREAK;
X
X  /* Change the interrupt character to ^C, ignore ^S & ^Q 	 */
X  ic_chars.t_intrc = '\003';
X  ic_chars.t_startc = '\377';
X  ic_chars.t_stopc = '\377';
X
X  ioctl(0, TIOCSETP, &ic_mode);
X  ioctl(0, TIOCSETC, (struct sgttyb *) & ic_chars);
X}
X
X/****************************************************************/
X/*								*/
X/*	Reset_Term()						*/
X/*								*/
X/*		Restore the terminal characteristics.		*/
X/*								*/
X/****************************************************************/
Xvoid Reset_Term()
X{
X  ioctl(0, TIOCSETP, &saved_mode);
X  ioctl(0, TIOCSETC, (struct sgttyb *) & saved_chars);
X}
X
X/****************************************************************/
X/*								*/
X/*	Get_Char()						*/
X/*								*/
X/*		Return the next input character. Upper case	*/
X/*		is mapped to lower case. Escape sequences	*/
X/*		are mapped to special codes (msb set).		*/
X/*								*/
X/****************************************************************/
Xint Get_Char()
X{
X  int c;
X
X  /* Fflush() used because Minix does not automatically	flush the output. */
X  fflush(stdout);
X  if ((c = Getc()) == EOF) return(EOF);
X  c &= 0x7f;
X  if (isupper(c)) return(tolower(c));
X
X  if (c == ESCAPE)
X	if ((c = Getc()) != '[') {
X		ungetc(c, stdin);
X		return(ESCAPE);
X	} else {
X		c = Getc() | 0x80;
X
X		if (c == ESC_HOME || c == ESC_UP || c == ESC_PGUP ||
X		    c == ESC_LEFT || c == ESC_5 || c == ESC_RIGHT ||
X		    c == ESC_END || c == ESC_DOWN || c == ESC_PGDN ||
X		    c == ESC_PLUS || c == ESC_MINUS)
X			return(c);
X		else
X			return(ESCAPE);
X	}
X
X  return(c);
X}
X
X/****************************************************************/
X/*								*/
X/*	Init_Getc( argc, argv )					*/
X/*								*/
X/*		Give Getc() references to the command line	*/
X/*		arguments.					*/
X/*								*/
X/****************************************************************/
Xstatic int args_remaining;
Xstatic char **args_pointer;
Xstatic int args_index;
X
Xvoid Init_Getc(argc, argv)
Xint argc;
Xchar *argv[];
X{
X  args_remaining = argc - 1;
X  args_pointer = &argv[1];
X  args_index = 0;
X}
X
X/****************************************************************/
X/*								*/
X/*	Getc()							*/
X/*								*/
X/*		Get the next input character from the command	*/
X/*		line if there is some more, else from stdin.	*/
X/*								*/
X/****************************************************************/
Xint Getc()
X{
X  int c;
X
X  if (args_remaining > 0)
X	if ((c = args_pointer[0][args_index++]) == '\0') {
X		--args_remaining;
X		++args_pointer;
X		args_index = 0;
X
X		if (args_remaining > 0) return('\n');
X	} else
X		return(c);
X
X  return(getchar());
X}
X
X/****************************************************************/
X/*								*/
X/*	Get_Base( character )					*/
X/*								*/
X/*		Return an appropriate base number for the	*/
X/*		given character code. Used by 'i' and 'o'.	*/
X/*								*/
X/****************************************************************/
Xint Get_Base(code)
Xchar code;
X{
X  switch (code) {
X      case 'h':
X	return(HEXADECIMAL);
X
X      case 'd':
X	return(DECIMAL);
X
X      case 'o':
X	return(OCTAL);
X
X      case 'b':
X	return(BINARY);
X
X      case 'a':
X	return(ASCII);
X
X      default:	return(ERROR);
X  }
X}
/
echo x - ic_output.c
sed '/^X/s///' > ic_output.c << '/'
X/****************************************************************/
X/*								*/
X/*	ic_output.c						*/
X/*								*/
X/*		Output routines for the "Integer Calculator".	*/
X/*								*/
X/****************************************************************/
X/*   origination        1988-Apr-6          Terrence W. Holm	*/
X/****************************************************************/
X
X#include <stdlib.h>
X#include <termcap.h>
X#include <stdio.h>
X#include "ic.h"
X
X/****************************************************************/
X/*   		Code for handling termcap			*/
X/****************************************************************/
X#define  TC_BUFFER  1024	/* Size of termcap(3) buffer	 */
X#define  TC_STRINGS  200	/* Enough room for cm,cl,so,se	 */
X
Xstatic char *Tmove;		/* (cm) - Format for tgoto	 */
Xstatic char *Tclr_all;		/* (cl) - String to clear screen */
Xstatic char *Treverse;		/* (so) - String to reverse mode */
Xstatic char *Tnormal;		/* (se) - String to undo reverse */
X
X/****************************************************************/
X/*								*/
X/*	Init_Termcap()						*/
X/*								*/
X/*		Initializes the external variables for the	*/
X/*		current terminal.				*/
X/*								*/
X/*		NULL is returned on error conditions.		*/
X/*								*/
X/****************************************************************/
Xint Init_Termcap()
X{
X  char *term;
X  char buffer[TC_BUFFER];
X  static char strings[TC_STRINGS];
X  char *s = &strings[0];
X
X  term = getenv("TERM");
X  if (term == NULL) return(0);
X  if (tgetent(buffer, term) != 1) return(0);
X  if ((Tmove = tgetstr("cm", &s)) == NULL) return(0);
X  if ((Tclr_all = tgetstr("cl", &s)) == NULL) return(0);
X  if ((Treverse = tgetstr("so", &s)) == NULL) {
X	Treverse = s;
X	*s = '\0';
X	++s;
X  }
X  if ((Tnormal = tgetstr("se", &s)) == NULL) {
X	Tnormal = s;
X	*s = '\0';
X	++s;
X  }
X  return(EOF);
X}
X
X/****************************************************************/
X/*								*/
X/*	Move( column, line )					*/
X/*								*/
X/*		Use the termcap string to move the cursor.	*/
X/*								*/
X/****************************************************************/
Xvoid Move(column, line)
Xint column;
Xint line;
X{
X  Puts(tgoto(Tmove, column, line));
X}
X
X/****************************************************************/
X/*								*/
X/*	Puts( string )						*/
X/*								*/
X/*		Write the given termcap string to the standard	*/
X/*		output device.					*/
X/*								*/
X/****************************************************************/
Xvoid Puts(string)
Xchar *string;
X{
X  tputs(string, 1, Putchar);
X}
X
Xvoid Putchar(c)
Xchar c;
X{
X  putchar(c);
X}
X
X/****************************************************************/
X/*   		       Output routines				*/
X/****************************************************************/
X/****************************************************************/
X/*								*/
X/*	Draw_Help_Screen()					*/
X/*								*/
X/****************************************************************/
Xvoid Draw_Help_Screen()
X{
X  Puts(Tclr_all);		/* Clear the screen  */
X
X  printf("\n\n                             ");
X  Puts(Treverse);
X  printf("IC  COMMANDS");
X  Puts(Tnormal);
X  printf("\n\n\n");
X
X  printf("         h   Help                            ENTER Push stack\n");
X  printf("         i   Input base  (h d o b)            DEL  Clear entry\n");
X  printf("  PGDN   l   Last top of stack\n");
X  printf("         m   Minix shell                       .   Change sign\n");
X  printf("         o   Output base (h d o b a)           +   Add\n");
X  printf("  DOWN   p   Pop stack                         -   Subtract\n");
X  printf("  END    q   Quit                              *   Multiply\n");
X  printf("  LEFT   r   Recall (0-9)                      /   Divide\n");
X  printf("  RIGHT  s   Store [+] (0-9)                   %%   Remainder\n");
X  printf("         t   Translate (char)                  ~   Not\n");
X  printf("  PGUP   w   Write top to scratch pad          &   And\n");
X  printf("  UP     x   Exchange top of stack             |   Or\n");
X  printf("  HOME   z   Zero all state                    ^   Exclusive-or\n\n\n");
X
X  printf("\n\nPress a key to continue...");
X}
X
X/****************************************************************/
X/*								*/
X/*	Draw_Prompt( string )					*/
X/*								*/
X/*		Write a message in the "wait" area.		*/
X/*								*/
X/****************************************************************/
Xvoid Draw_Prompt(string)
Xchar *string;
X{
X  Move(WAIT_COLUMN, WAIT_LINE);
X  Puts(Treverse);
X  printf(string);
X  Puts(Tnormal);
X}
X
X/****************************************************************/
X/*								*/
X/*	Erase_Prompt()						*/
X/*								*/
X/*		Erase the message in the "wait" area.		*/
X/*								*/
X/****************************************************************/
Xvoid Erase_Prompt()
X{
X  Move(WAIT_COLUMN, WAIT_LINE);
X  printf("           ");
X  Move(WAIT_COLUMN, WAIT_LINE);
X}
X
X/****************************************************************/
X/*								*/
X/*	Draw_Screen( state )					*/
X/*								*/
X/*		Redraw everything.				*/
X/*								*/
X/****************************************************************/
Xvoid Draw_Screen(s)
Xic_state *s;
X{
X  Puts(Tclr_all);		/* Clear the screen  */
X  Draw_Stack(s);
X  Draw_Registers(s);
X  Move(STATUS_COLUMN, STATUS_LINE);
X  printf("Input base = %2d    ", s->input_base);
X  if (s->output_base == ASCII)
X	printf("Output is ASCII     ");
X  else
X	printf("Output base = %2d    ", s->output_base);
X  if ((int) s->scratch_pad != 0) printf("Scratch file = %s", s->file_name);
X  Move(WAIT_COLUMN, WAIT_LINE);
X}
X
X/****************************************************************/
X/*								*/
X/*	Draw_Stack( state )					*/
X/*								*/
X/*		Redraw the stack.				*/
X/*								*/
X/****************************************************************/
Xvoid Draw_Stack(s)
Xic_state *s;
X{
X  int i;
X
X  for (i = STACK_SIZE - 1; i >= 0; --i) {
X	Move(STACK_COLUMN, STACK_LINE + STACK_SIZE - 1 - i);
X
X	if (i >= s->stack_size)
X		printf("%*c", s->output_base == BINARY ? 32 : 17, ' ');
X	else
X		Print_Number(stdout, s->stack[i], s->output_base);
X  }
X
X  Move(WAIT_COLUMN, WAIT_LINE);
X}
X
X/****************************************************************/
X/*								*/
X/*	Draw_Registers( state )					*/
X/*								*/
X/*		Redraw the registers. Note that only registers	*/
X/*		in use are displayed. A register only drops	*/
X/*		out of use after a 'z' command, which will	*/
X/*		explicitly clear the display, thus we never	*/
X/*		have to "wipe off" a value, as the		*/
X/*		Draw_Stack() routine must.			*/
X/*								*/
X/****************************************************************/
Xvoid Draw_Registers(s)
Xic_state *s;
X{
X  int i;
X
X  for (i = 0; i < REGISTERS; ++i) {
X	if ((1 << i) & s->register_mask) {
X		Move(REG_COLUMN, REG_LINE + i);
X		Print_Number(stdout, s->registers[i], s->output_base);
X		printf(" (r%1d)", i);
X	}
X  }
X
X  Move(WAIT_COLUMN, WAIT_LINE);
X}
X
X/****************************************************************/
X/*								*/
X/*	Draw_Top_of_Stack( state )				*/
X/*								*/
X/*		Redraw only the entry on the top of the stack.	*/
X/*								*/
X/****************************************************************/
Xvoid Draw_Top_of_Stack(s)
Xic_state *s;
X{
X  Move(STACK_COLUMN, STACK_LINE + STACK_SIZE - 1);
X  Print_Number(stdout, s->stack[0], s->output_base);
X  Move(WAIT_COLUMN, WAIT_LINE);
X}
X
X/****************************************************************/
X/*								*/
X/*	Print_Number( stream, number, output_base )		*/
X/*								*/
X/*		Output the "number" to "stream" in the		*/
X/*		specified "output_base".			*/
X/*								*/
X/****************************************************************/
Xvoid Print_Number(stream, number, output_base)
XFILE *stream;
Xlong int number;
Xint output_base;
X{
X  switch (output_base) {
X      case HEXADECIMAL:
X	fprintf(stream, "%12lx", number);
X	break;
X
X      case DECIMAL:
X	fprintf(stream, "%12ld", number);
X	break;
X
X      case OCTAL:
X	fprintf(stream, "%12lo", number);
X	break;
X
X      case BINARY:{
X		unsigned long int mask;
X		char pad = ' ';
X
X		for (mask = 0x80000000; mask > 1; mask >>= 1)
X			putc((mask & number) ? (pad = '0', '1') : pad, stream);
X
X		putc((0x01 & number) ? '1' : '0', stream);
X
X		break;
X	}
X
X      case ASCII:{
X		char c = number & 0x7f;
X
X		if ((number & ~0x7fL) == 0)
X			fprintf(stream, "%15c", ' ');
X		else
X			fprintf(stream, "%12lx + ", number & ~0x7fL);
X
X		if (c < ' ')
X			fprintf(stream, "^%c", c + '@');
X		else if (c == ' ')
X			fprintf(stream, "sp");
X		else if (c < 0x7f)
X			fprintf(stream, " %c", c);
X		else
X			fprintf(stream, "^?");
X
X		break;
X	}
X
X      default:
X	fprintf(stderr, "Internal failure (output base)\n");
X	Sigint(0);
X  }
X}
/
