[comp.os.minix] ic

tholm@uvicctr.UUCP (Terrence W. Holm) (05/18/88)

EFTH Minix report #13  - May 1988 -  ic(1)     [part 2 of 3]



echo x - ic.c
gres '^X' '' > ic.c << '/'
X/****************************************************************/
X/*								*/
X/*	ic.c							*/
X/*								*/
X/*		The main loop of the "Integer Calculator".	*/
X/*								*/
X/****************************************************************/
X/*  origination         1988-Apr-6               T. Holm	*/
X/*  added Exec_Shell()  1988-Apr-11		 T. Holm	*/
X/*  added "s+"		1988-Apr-18		 T. Holm	*/
X/*  added cmd line args 1988-May-13		 T. Holm	*/
X/****************************************************************/
X
X
X
X
X
X
X#include <stdio.h>
X#include <signal.h>
X
X#include "ic.h"
X
X
X
X
Xstatic char copyright[] = { "ic(tm)    (c) Terrence W. Holm 1988" };
X
X
X
X
X/****************************************************************/
X/*								*/
X/*	main()							*/
X/*								*/
X/*		Initialize. Enter the main processing loop.	*/
X/*								*/
X/****************************************************************/
X
X
Xmain( argc, argv )
X  int   argc;
X  char *argv[];
X
X  {
X  ic_state  state;		/*  This state record is passed	*/
X				/*  to most subroutines		*/
X
X  Init_State( &state );
X
X
X  state.scratch_pad = (FILE *) NULL;	/*  No 'w' command yet	*/
X
X
X
X  Init_Getc( argc, argv );	/*  Refs to command line args	*/
X
X
X
X  if ( Init_Termcap() == NULL )
X    {
X    fprintf( stderr, "ic requires a termcap entry\n" );
X    exit( 1 );
X    }
X
X
X  Save_Term();		/*  Save terminal characteristics	*/
X
X
X  /*  The following conditional is always TRUE under Minix,	*/
X  /*  this is a bug.						*/
X
X  if ( signal( SIGINT, SIG_IGN ) != SIG_IGN )
X    {
X    signal( SIGINT,  Sigint );
X    signal( SIGQUIT, Sigint );
X    }
X
X
X  Set_Term(); 		/*  Setup terminal characteristics	*/
X
X
X
X  Draw_Screen( &state );
X
X  while (1)
X    {
X    int  rc = Process( &state, Get_Char() );
X
X    if ( rc == EOF )
X      break;
X
X    if ( rc == ERROR )
X      putchar( BELL );
X    }
X
X
X  Reset_Term();		/*  Restore terminal characteristics	*/
X
X  exit( OK );
X  }
X
X
X
X
X
X
X
X
X/****************************************************************/
X/*								*/
X/*	Init_State()						*/
X/*								*/
X/*		Initialize the state record.			*/
X/*								*/
X/****************************************************************/
X
X
XInit_State( s )
X  ic_state  *s;
X
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
X
X
X
X
X/****************************************************************/
X/*								*/
X/*	Sigint()						*/
X/*								*/
X/*		Terminate the program on an interrupt (^C)	*/
X/*		or quit (^\) signal.				*/
X/*								*/
X/****************************************************************/
X
X
XSigint()
X
X  {
X  Reset_Term();		/*  Restore terminal characteristics	*/
X
X  exit( 1 );
X  }
X
X
X
X
X
X
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/****************************************************************/
X
X
Xint Process( s, c )
X  ic_state  *s;
X  int    c;
X
X  {
X  switch ( c )
X    {
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
X		return( Enter_Numeric( s, (int) c - '0' ) );
X
X
X    case 'a' :
X    case 'b' :
X    case 'c' :
X    case 'd' :
X    case 'e' :
X    case 'f' :
X
X		return( Enter_Numeric( s, (int) c - 'a' + 10 ) );
X
X
X    case 'h' :  case '?' :		/*  Help		*/
X
X		Draw_Help_Screen();
X
X		Get_Char();
X
X		Draw_Screen( s );
X		return( OK );
X
X
X    case 'i' :				/*  Set input base	*/
X
X		{
X		int numeral;
X
X		Draw_Prompt( "Base?" );
X
X		numeral = Get_Base( Get_Char() );
X
X		Erase_Prompt();
X
X		if ( numeral == ERROR  ||  numeral == ASCII )
X		  return( ERROR );
X
X		s->input_base = numeral;
X		s->mode       = LAST_WAS_FUNCTION;
X
X		Draw_Screen( s );
X		return( OK );
X		}
X
X
X    case 'l' :  case ESC_PGDN :		/*  Get last tos value	 */
X
X  		if ( s->mode != LAST_WAS_ENTER )
X		  Push( s );
X
X		s->stack[0] = s->last_tos;
X
X		s->mode = LAST_WAS_FUNCTION;
X
X		Draw_Stack( s );
X		return( OK );
X
X
X    case 'm' :				/*  Invoke a Minix shell */
X
X		Reset_Term();
X
X		Exec_Shell();
X
X		Set_Term();
X
X		Draw_Screen( s );
X		return( OK );
X
X
X    case 'o' :				/*  Set output base	*/
X
X		{
X		int numeral;
X
X		Draw_Prompt( "Base?" );
X
X		numeral = Get_Base( Get_Char() );
X
X		Erase_Prompt();
X
X		if ( numeral == ERROR )
X		  return( ERROR );
X
X		s->output_base = numeral;
X		s->mode        = LAST_WAS_FUNCTION;
X
X		Draw_Screen( s );
X		return( OK );
X		}
X
X
X    case 'p' :  case ESC_DOWN :		/*  Pop: Roll down stack */
X
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
X		s->mode = LAST_WAS_FUNCTION;
X
X		Draw_Stack( s );
X		return( OK );
X		}
X
X
X    case 'q' :  case ESC_END :  	/*  Quit		 */
X    case EOF :  case CTRL_D  :
X
X		return( EOF );
X
X
X    case 'r' :  case ESC_LEFT :		/*  Recall from register */
X
X		{
X		int numeral;
X
X		Draw_Prompt( "Register?" );
X
X		numeral = Get_Char() - '0';
X
X		Erase_Prompt();
X
X		if (  numeral < 0  ||  numeral >= REGISTERS  ||
X		    ((1 << numeral) & s->register_mask) == 0   )
X		  return( ERROR );
X	
X  		if ( s->mode != LAST_WAS_ENTER )
X		  Push( s );
X
X		s->stack[0] = s->registers[numeral];
X
X		s->mode = LAST_WAS_FUNCTION;
X
X		Draw_Stack( s );
X		return( OK );
X		}
X
X
X    case 's' :  case ESC_RIGHT :	/*  Store in register,	*/
X					/*  or accumulate if	*/
X					/*  "s+" is typed.	*/
X
X		{
X		int c;
X		int numeral;
X
X
X		Draw_Prompt( "Register?" );
X
X		c = Get_Char();
X
X		if ( c == ESC_PLUS )
X		  c = '+';		/*  Allow keypad '+' 	*/
X
X
X		if ( c == '+' )
X		  {
X		  Draw_Prompt( "Accumulator?" );
X		  numeral = Get_Char() - '0';
X		  }
X		else
X		  numeral = c - '0';
X
X		Erase_Prompt();
X
X
X		if (  numeral < 0  ||  numeral >= REGISTERS  )
X		  return( ERROR );
X	
X
X		if (  c != '+'  ||  (s->register_mask & (1 << numeral)) == 0  )
X		  {
X		  s->register_mask |= 1 << numeral;
X		  s->registers[numeral] = s->stack[0];
X		  }
X		else
X		  s->registers[numeral] += s->stack[0];
X
X
X		s->mode = LAST_WAS_FUNCTION;
X
X		Draw_Registers( s );
X		return( OK );
X		}
X
X
X    case 't' :				/*  Translate from ASCII */
X
X		{
X		long int numeral;
X
X		Draw_Prompt( "Character?" );
X
X		numeral = (long int) Getc();
X
X		Erase_Prompt();
X
X  		if ( s->mode != LAST_WAS_ENTER )
X		  Push( s );
X
X		s->stack[0] = numeral;
X
X		s->mode = LAST_WAS_FUNCTION;
X
X		Draw_Stack( s );
X		return( OK );
X		}
X
X
X    case 'w' :  case ESC_PGUP :		/*  Write tos to a file	*/
X
X		{
X		if ( (int) s->scratch_pad == NULL )
X		  {
X		  /*  Try to open a scratch pad file  */
X
X		  strcpy( s->file_name, "./pad" );
X
X		  if ( (s->scratch_pad=fopen(s->file_name,"w")) == NULL )
X		    {
X		    /*  Unsuccessful, try in /tmp  */
X		    char *id;
X
X		    strcpy( s->file_name, "/tmp/pad_" );
X
X		    if ( (id=cuserid(NULL)) == NULL )
X		      return( ERROR );
X
X		    strcat( s->file_name, id );
X
X		    if ( (s->scratch_pad=fopen(s->file_name,"w")) == NULL )
X		      return( ERROR );
X		    }
X
X		  Draw_Screen( s );
X		  }
X
X
X		/*  We have a successfully opened file  */
X
X		Print_Number( s->scratch_pad, s->stack[0], s->output_base );
X		putc( '\n', s->scratch_pad );
X		fflush( s->scratch_pad );
X
X		s->mode = LAST_WAS_FUNCTION;
X
X		return( OK );
X		}
X
X
X    case 'x' :  case ESC_UP :		/*  Exchange top of stack */
X
X		{
X		long int temp = s->stack[0];
X
X		if ( s->stack_size < 2 )
X		  return( ERROR );
X
X		s->stack[0] = s->stack[1];
X		s->stack[1] = temp;
X
X		s->mode = LAST_WAS_FUNCTION;
X
X		Draw_Stack( s );
X		return( OK );
X		}
X
X
X    case 'z' :  case ESC_HOME:		/*  Clear all		*/
X
X		Init_State( s );
X
X		Draw_Screen( s );
X		return( OK );
X
X
X    case BS  :  case DEL :		/*  Clear top of stack  */
X
X		s->stack[0] = 0;
X
X		s->mode = LAST_WAS_ENTER;
X
X		Draw_Top_of_Stack( s );
X		return( OK );
X
X
X    case '\n' :				/*  Enter		*/
X
X		Push( s );
X
X		s->mode = LAST_WAS_ENTER;
X
X		Draw_Stack( s );
X		return( OK );
X
X
X    case '.' :				/*  Change sign		*/
X
X		s->last_tos = s->stack[0];
X
X		s->stack[0] = - s->stack[0];
X
X		s->mode = LAST_WAS_FUNCTION;
X
X		Draw_Top_of_Stack( s );
X		return( OK );
X
X
X    case '+' :  case ESC_PLUS :		/*  Add			*/
X
X		if ( s->stack_size < 2 )
X		  return( ERROR );
X
X		s->last_tos = s->stack[0];
X
X		Pop( s );
X
X		s->stack[0] += s->last_tos;
X
X		s->mode = LAST_WAS_FUNCTION;
X
X		Draw_Stack( s );
X		return( OK );
X
X
X    case '-' :  case ESC_MINUS :	/*  Subtract		*/
X
X		if ( s->stack_size < 2 )
X		  return( ERROR );
X
X		s->last_tos = s->stack[0];
X
X		Pop( s );
X
X		s->stack[0] -= s->last_tos;
X
X		s->mode = LAST_WAS_FUNCTION;
X
X		Draw_Stack( s );
X		return( OK );
X
X
X    case '*' :				/*  Multiply		*/
X
X		if ( s->stack_size < 2 )
X		  return( ERROR );
X
X		s->last_tos = s->stack[0];
X
X		Pop( s );
X
X		s->stack[0] *= s->last_tos;
X
X		s->mode = LAST_WAS_FUNCTION;
X
X		Draw_Stack( s );
X		return( OK );
X
X
X    case '/' :				/*  Divide		*/
X
X		if ( s->stack_size < 2  ||  s->stack[0] == 0 )
X		  return( ERROR );
X
X		s->last_tos = s->stack[0];
X
X		Pop( s );
X
X		s->stack[0] /= s->last_tos;
X
X		s->mode = LAST_WAS_FUNCTION;
X
X		Draw_Stack( s );
X		return( OK );
X
X
X    case '%' :  case ESC_5 :		/*  Remainder		*/
X
X		if ( s->stack_size < 2  ||  s->stack[0] == 0 )
X		  return( ERROR );
X
X		s->last_tos = s->stack[0];
X
X		Pop( s );
X
X		s->stack[0] %= s->last_tos;
X
X		s->mode = LAST_WAS_FUNCTION;
X
X		Draw_Stack( s );
X		return( OK );
X
X
X    case '~' :				/*  Not			*/
X
X		s->last_tos = s->stack[0];
X
X		s->stack[0] = ~ s->stack[0];
X
X		s->mode = LAST_WAS_FUNCTION;
X
X		Draw_Top_of_Stack( s );
X		return( OK );
X
X
X    case '&' :				/*  And			*/
X
X		if ( s->stack_size < 2 )
X		  return( ERROR );
X
X		s->last_tos = s->stack[0];
X
X		Pop( s );
X
X		s->stack[0] &= s->last_tos;
X
X		s->mode = LAST_WAS_FUNCTION;
X
X		Draw_Stack( s );
X		return( OK );
X
X
X    case '|' :				/*  Or			*/
X
X		if ( s->stack_size < 2 )
X		  return( ERROR );
X
X		s->last_tos = s->stack[0];
X
X		Pop( s );
X
X		s->stack[0] |= s->last_tos;
X
X		s->mode = LAST_WAS_FUNCTION;
X
X		Draw_Stack( s );
X		return( OK );
X
X
X    case '^' :				/*  Exclusive-or	*/
X
X		if ( s->stack_size < 2 )
X		  return( ERROR );
X
X		s->last_tos = s->stack[0];
X
X		Pop( s );
X
X		s->stack[0] ^= s->last_tos;
X
X		s->mode = LAST_WAS_FUNCTION;
X
X		Draw_Stack( s );
X		return( OK );
X
X
X    default:
X		return( ERROR );
X    }
X  }
X
X

X
X
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/****************************************************************/
X
X
Xint Enter_Numeric( s, numeral )
X  ic_state *s;
X  int   numeral;
X
X  {
X  if ( numeral >= s->input_base )
X    return( ERROR );
X
X
X  switch ( s->mode )
X    {
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();
X    }
X
X  s->mode = LAST_WAS_NUMERIC;
X
X  return( OK );
X  }
X
X
X
X
X
X
X
X
X/****************************************************************/
X/*								*/
X/*	Push( state )						*/
X/*								*/
X/*		Push up the stack one level.			*/
X/*								*/
X/****************************************************************/
X
X
XPush( s )
X  ic_state *s;
X
X  {
X  int i;
X
X  if ( s->stack_size == STACK_SIZE ) 
X    --s->stack_size;
X
X  for ( i = s->stack_size;  i > 0;  --i )
X    s->stack[i] = s->stack[i-1];
X
X  ++s->stack_size;
X  }
X
X
X
X
X
X
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/****************************************************************/
X
X
XPop( s )
X  ic_state *s;
X
X  {
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_size;
X  }
X
X
X
X
X
X
X
X
X/****************************************************************/
X/*								*/
X/*	Exec_Shell()						*/
X/*								*/
X/*		Fork off a sub-process to exec() the shell.	*/
X/*								*/
X/****************************************************************/
X
X
XExec_Shell()
X
X  {
X  int pid = fork();
X
X  if ( pid == -1 )
X    return;
X
X
X  if ( pid == 0 )
X    {
X    /*  The child process  */
X
X    extern char **environ;
X    char *shell  =  getenv( "SHELL" );
X
X    if ( shell == NULL )
X      shell = "/bin/sh";
X
X    execle( shell, shell, 0, environ );
X
X    perror( shell );
X    exit( 127 );
X    }
X
X
X  /*  The parent process: ignore signals, wait for sub-process	*/
X
X  signal( SIGINT,  SIG_IGN );
X  signal( SIGQUIT, SIG_IGN );
X
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
X  return;
X  }
/
--------------------------------------------------------------------
               Edwin L. Froese
                  (in London for the month)

               Terrence W. Holm
                  {uw-beaver,ubc-cs}!uvicctr!sirius!tholm

tholm@uvicctr.UUCP (Terrence W. Holm) (05/18/88)

EFTH Minix report #13  - May 1988 -  ic(1)     [part 3 of 3]



echo x - ic_input.c
gres '^X' '' > 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               T. Holm	*/
X/*  added cmd line args  1988-May-13		  T. Holm	*/
X/****************************************************************/
X
X
X
X#include <stdio.h>
X#include <ctype.h>
X#include <sgtty.h>
X
X#include "ic.h"
X
X
X
X
Xstatic struct sgttyb saved_mode;
Xstatic struct tchars saved_chars;
X
X
X
X
X
X
X/****************************************************************/
X/*								*/
X/*	Save_Term()						*/
X/*								*/
X/*		Save the current terminal characteristics.	*/
X/*								*/
X/****************************************************************/
X
X
XSave_Term()
X
X  {
X  ioctl( 0, TIOCGETP, &saved_mode  );
X  ioctl( 0, TIOCGETC, &saved_chars );
X  }
X
X
X
X
X
X
X
X
X/****************************************************************/
X/*								*/
X/*	Set_Term()						*/
X/*								*/
X/*		Set up the terminal characteristics for ic.	*/
X/*								*/
X/****************************************************************/
X
X
XSet_Term()
X
X  {
X  struct sgttyb ic_mode;
X  struct tchars ic_chars;
X
X  ic_mode  = saved_mode;
X  ic_chars = saved_chars;
X
X
X  /*  No tab expansion, no echo, cbreak mode			*/
X
X  ic_mode.sg_flags = ic_mode.sg_flags & ~XTABS & ~ECHO  |  CBREAK;
X
X
X  /*  Change the interrupt character to ^C, ignore ^S & ^Q 	*/
X
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, &ic_chars );
X  }
X
X
X
X
X
X
X
X
X/****************************************************************/
X/*								*/
X/*	Reset_Term()						*/
X/*								*/
X/*		Restore the terminal characteristics.		*/
X/*								*/
X/****************************************************************/
X
X
XReset_Term()
X
X  {
X  ioctl( 0, TIOCSETP, &saved_mode  );
X  ioctl( 0, TIOCSETC, &saved_chars );
X  }
X
X
X
X
X
X
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/****************************************************************/
X
X
Xint Get_Char()
X
X  {
X  int c;
X
X
X  /*  fflush() used because Minix does not automatically	*/
X  /*  flush the output.						*/
X
X  fflush( stdout );
X
X
X  if ( (c = Getc()) == EOF )
X    return( EOF );
X  
X  c &= 0x7f;
X
X
X  if ( isupper(c) )
X    return( tolower(c) );
X
X
X  if ( c == ESCAPE )
X    if ( (c=Getc()) != '[' )
X      {
X      ungetc( c, stdin );
X      return( ESCAPE );
X      }
X    else
X      {
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
X  return( c );
X  }
X
X
X
X
X
X
X
X
X/****************************************************************/
X/*								*/
X/*	Init_Getc( argc, argv )					*/
X/*								*/
X/*		Give Getc() references to the command line	*/
X/*		arguments.					*/
X/*								*/
X/****************************************************************/
X
X
X
Xstatic int    args_remaining;
Xstatic char **args_pointer;
Xstatic int    args_index;
X
X
X
XInit_Getc( argc, argv )
X  int   argc;
X  char *argv[];
X
X  {
X  args_remaining = argc - 1;
X  args_pointer   = &argv[1];
X  args_index     = 0;
X  }
X
X
X
X
X
X
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/****************************************************************/
X
X
Xint Getc()
X
X  {
X  int c;
X
X  if ( args_remaining > 0 )
X    if ( (c = args_pointer[ 0 ][ args_index++ ]) == '\0' )
X      {
X      --args_remaining;
X      ++args_pointer;
X      args_index = 0;
X
X      if ( args_remaining > 0 )
X        return( '\n' );
X      }
X    else
X      return( c );
X
X  return( getchar() );
X  }
X
X
X
X
X
X
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/****************************************************************/
X
X
Xint Get_Base( code )
X  char code;
X
X  {
X  switch ( code )
X    {
X    case 'h' :		return( HEXADECIMAL );
X
X    case 'd' :		return( DECIMAL     );
X
X    case 'o' :		return( OCTAL       );
X
X    case 'b' :		return( BINARY      );
X
X    case 'a' :  	return( ASCII       );
X
X    default  :		return( ERROR       );
X    }
X  }
/
echo x - ic_output.c
gres '^X' '' > ic_output.c << '/'
X/****************************************************************/
X/*								*/
X/*	ic_output.c						*/
X/*								*/
X/*		Output routines for the "Integer Calculator".	*/
X/*								*/
X/****************************************************************/
X/*   origination        1988-Apr-6               T. Holm	*/
X/****************************************************************/
X
X
X
X
X#include <stdio.h>
X
X#include "ic.h"
X
X
X
X
X
X
X/****************************************************************/
X/*   		Code for handling termcap			*/
X/****************************************************************/
X
X
X#define  TC_BUFFER  1024	/* Size of termcap(3) buffer	*/
X#define  TC_STRINGS  200	/* Enough room for cm,cl,so,se	*/
X
X
X
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
X
X
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/****************************************************************/
X
X
XInit_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
X  if ( term == NULL )
X    return( NULL );
X
X  if ( tgetent( buffer, term ) != 1 )
X    return( NULL );
X
X
X
X  if ( (Tmove=tgetstr( "cm", &s )) == NULL )
X    return( NULL );
X
X  if ( (Tclr_all=tgetstr( "cl", &s )) == NULL )
X    return( NULL );
X
X  if ( (Treverse=tgetstr( "so", &s )) == NULL )
X    {
X    Treverse = s;
X    *s = '\0';
X    ++s;
X    }
X
X  if ( (Tnormal=tgetstr( "se", &s )) == NULL )
X    {
X    Tnormal = s;
X    *s = '\0';
X    ++s;
X    }
X
X  return( EOF );
X  }
X
X
X
X
X
X
X
X
X/****************************************************************/
X/*								*/
X/*	Move( column, line )					*/
X/*								*/
X/*		Use the termcap string to move the cursor.	*/
X/*								*/
X/****************************************************************/
X
X
XMove( column, line )
X  int  column;
X  int  line;
X
X  {
X  Puts( tgoto( Tmove, column, line ) );
X  }
X
X
X
X
X
X
X
X
X/****************************************************************/
X/*								*/
X/*	Puts( string )						*/
X/*								*/
X/*		Write the given termcap string to the standard	*/
X/*		output device.					*/
X/*								*/
X/****************************************************************/
X
X
XPuts( string )
X  char  *string;
X
X  {
X  int Putchar();
X
X  tputs( string, 1, Putchar );
X  }
X
X
XPutchar( c )
X  char  c;
X
X  {
X  putchar( c );
X  }
X
X
X
X
X
X
X
X
X/****************************************************************/
X/*   		       Output routines				*/
X/****************************************************************/
X
X
X
X
X/****************************************************************/
X/*								*/
X/*	Draw_Help_Screen()					*/
X/*								*/
X/****************************************************************/
X
X
XDraw_Help_Screen()
X
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
X
X
X
X
X/****************************************************************/
X/*								*/
X/*	Draw_Prompt( string )					*/
X/*								*/
X/*		Write a message in the "wait" area.		*/
X/*								*/
X/****************************************************************/
X
X
XDraw_Prompt( string )
X  char  *string;
X
X  {
X  Move( WAIT_COLUMN, WAIT_LINE );
X
X  Puts( Treverse );
X  printf( string );
X  Puts( Tnormal );
X  }
X
X
X
X
X
X
X
X
X/****************************************************************/
X/*								*/
X/*	Erase_Prompt()						*/
X/*								*/
X/*		Erase the message in the "wait" area.		*/
X/*								*/
X/****************************************************************/
X
XErase_Prompt()
X
X  {
X  Move( WAIT_COLUMN, WAIT_LINE );
X
X  printf( "              " );
X
X  Move( WAIT_COLUMN, WAIT_LINE );
X  }
X
X
X
X
X
X
X
X
X/****************************************************************/
X/*								*/
X/*	Draw_Screen( state )					*/
X/*								*/
X/*		Redraw everything.				*/
X/*								*/
X/****************************************************************/
X
X
XDraw_Screen( s )
X  ic_state *s;
X
X  {
X  Puts( Tclr_all );		/*  Clear the screen  */
X
X  Draw_Stack( s );
X  Draw_Registers( s );
X
X
X  Move( STATUS_COLUMN, STATUS_LINE );
X
X  printf( "Input base = %2d    ", s->input_base );
X
X  if ( s->output_base == ASCII )
X    printf( "Output is ASCII     " );
X  else
X    printf( "Output base = %2d    ", s->output_base );
X
X  if ( (int) s->scratch_pad != NULL )
X    printf( "Scratch file = %s", s->file_name );
X
X  Move( WAIT_COLUMN, WAIT_LINE );
X  }
X
X
X
X
X
X
X
X
X/****************************************************************/
X/*								*/
X/*	Draw_Stack( state )					*/
X/*								*/
X/*		Redraw the stack.				*/
X/*								*/
X/****************************************************************/
X
X
XDraw_Stack( s )
X  ic_state *s;
X
X  {
X  int i;
X
X  for ( i = STACK_SIZE-1;  i >= 0;  --i )
X    {
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
X
X
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/****************************************************************/
X
X
XDraw_Registers( s )
X  ic_state *s;
X
X  {
X  int i;
X
X  for ( i = 0;  i < REGISTERS;  ++i )
X    {
X    if ( (1 << i) & s->register_mask  )
X      {
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
X
X
X
X
X/****************************************************************/
X/*								*/
X/*	Draw_Top_of_Stack( state )				*/
X/*								*/
X/*		Redraw only the entry on the top of the stack.	*/
X/*								*/
X/****************************************************************/
X
X
XDraw_Top_of_Stack( s )
X  ic_state *s;
X
X  {
X  Move( STACK_COLUMN, STACK_LINE + STACK_SIZE - 1 );
X
X  Print_Number( stdout, s->stack[0], s->output_base );
X
X  Move( WAIT_COLUMN, WAIT_LINE );
X  }
X
X
X
X
X
X
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/****************************************************************/
X
X
XPrint_Number( stream, number, output_base )
X  FILE    *stream;
X  long int number;
X  int      output_base;
X
X  {
X  switch ( output_base )
X    {
X    case HEXADECIMAL :	fprintf( stream, "%12X", number );
X			break;
X
X
X    case DECIMAL :	fprintf( stream, "%12D", number );
X			break;
X
X
X    case OCTAL :	fprintf( stream, "%12O", number );
X			break;
X
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
X    case ASCII :	{
X			char c = number & 0x7f;
X
X			if ( (number & ~ 0x7fL) == 0 )
X			  fprintf( stream, "%15c", ' ' );
X			else
X    			  fprintf( stream, "%12X + ", 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 :		fprintf( stderr, "Internal failure (output base)\n" );
X			Sigint();
X    }
X  }
/
--------------------------------------------------------------------
               Edwin L. Froese
                  (in London for the month)

               Terrence W. Holm
                  {uw-beaver,ubc-cs}!uvicctr!sirius!tholm

kenf@aplcen.UUCP (7784) (05/20/88)

The following hardware combination works with Minix:
Compaq Portable with nec v20, Seagate st-251 hard drive
and Western Digital WD1002a-WX1 Hard Disk Controller.

A few hints, use the Western Digital superbios to low level 
format the disk.  Do so dynamically and use value of 821 for
the write precomp and reduced write current cylinder.  The drive 
has 820 cylinders and 6 heads. defaults work for all else.

After the low level format I used Disk Manager tm which came
with the Seagate to partition the drive.  Use the DM /m for 
manual and use just the partition menu. DO NOT USE DISK MANAGER
TO INITALIZE THE DISK.  This wipes out all the good parameters 
that the controller put out there and the Minix HD driver is going 
to look for. I set the disk up with partition one set for Minix
at 10 meg. 2 and 3 become dos drives d and e, and partition 4
is the dos bootable, c.  Don't forget to tell the low level format
program where the bad tracks are.

As I said, this all worked for me, and now Minix talks to 
my hard disk :-)}

			Ken Firestone
			kenf@aplcen

holm@ubc-bdcvax.UUCP (Terrence W. Holm) (02/02/89)

EFTH MINIX report #66  - February 1989 -  ic(1)


Ic(1) is an integer calculator. It was originally posted
as EFTH report #13 (May 1988). I find it very useful for
bin/oct/dec/hex conversions and perhaps others have also.
I am giving everyone who originally missed it another
chance to download it.

		Terrence W. Holm
		  holm@bdc.ubc.ca


----------------------------------------------------------
echo x - Makefile
gres '^X' '' > Makefile << '/'
XCFLAGS	= -F -T.
XICOBJ   = ic.s ic_input.s ic_output.s
X
Xic:	$(ICOBJ)
X	cc -T. $(ICOBJ) -o ic
X	chmem =5000 ic
X
X$(ICOBJ): ic.h
X
Xprint:
X		pr ic.h ic.c ic_input.c ic_output.c\
X		Makefile | lpr
/
echo x - ic.1
gres '^X' '' > ic.1 << '/'
XNAME
X    ic(1)		- integer calculator
X
XSYNOPSIS
X    ic  [ args ] ...
X
XDESCRIPTION
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    The standard input is usually a keyboard and the standard output 
X    requires a device with a "termcap" entry.
X
X    The program starts by interpreting any <args> as commands, where
X    the separation between arguments is considered to be the same as
X    the ENTER key. For example, "ic 692 784+". After reading the
X    arguments input is from the keyboard.
X
X
X    STACK OPERATIONS
X
X    The operation of this program is similar to an RPN calculator.
X    A six level stack is used. The ENTER key pushes the stack up one 
X    level. For example, "12+5" is entered as "12 ENTER 5 +".
X
X    The top two entries on the stack are exchanged by the 'x' 
X    command, and the stack is rolled down one (popped) by the
X    'p' key.
X
X    The top of the stack may be cleared by pressing the back-space
X    key. The whole stack and the registers are initialized by a 'z'.
X
X
X    NUMERIC ENTRY
X
X    The input and output bases are initially decimal, but they may
X    be changed using the 'i' and 'o' commands. The 'i' command changes
X    both bases, but the 'o' command changes just the output base.
X    These commands take a one character argument of 'h', 'd', 'o' or
X    'b' to change to Hexadecimal, Decimal, Octal or Binary. While the 
X    input base is hexadecimal the letters 'a' through 'f' are used 
X    to represent the decimal values 10 through 15.
X
X    When the input base is decimal: multiply, divide and remainder
X    are signed, otherwise they are performed unsigned.
X
X    The output base may also be changed to ASCII ('a'), this causes
X    the least significant 7 bits of a value to be displayed as a
X    character. To input an ASCII value the translate ('t') command
X    may be used, it accepts one character as its argument.
X
X
X    CALCULATIONS
X
X    The arithmetic operations supported are: Negate ('.'), Add ('+'), 
X    Subtract ('-'), Multiply ('*'), Divide ('/'), and Remainder ('%').
X    The logical operations available are: Not ('~'), And ('&'), Or ('|'), 
X    and Exclusive-or ('^').
X
X    After one of these operations the last top of stack value is
X    saved. It may be restored by pressing 'l' (L).
X
X
X    SAVING RESULTS
X
X    Ten temporary registers are available. The Store ('s') command
X    followed by a digit ('0'..'9') will copy the top of the stack
X    to the specified register. The Recall ('r') command pushes the
X    contents of a register onto the top of the stack.
X
X    If the Store command is followed by a '+' preceding the digit, then
X    the top of the stack will be added to the specified "accumulator"
X    register.
X
X    Values may also be written to a file. The 'w' command writes the
X    top of the stack, using the current output base, to a file called 
X    "pad" in the current directory.  If the user does not have write 
X    access to the current directory then the file "/tmp/pad_$USER" is 
X    used as the scratch pad. The scratch pad file is erased on the
X    first use of the 'w' command within each new invocation of "ic".
X
X
X    LEAVING THE PROGRAM
X
X    The Quit ('q') key causes an immediate exit. (End of file on
X    standard input, the SIGINT and the SIGQUIT interrupts also terminate
X    the program.)
X
X    The 'm' command temporarily leaves "ic" by invoking the Minix "sh"
X    shell as a sub-process.
X
X    For help while using "ic", hit the 'h' key. If an erroneous key
X    is pressed the bell will sound.
X
X
X    COMMAND SUMMARY
X
X    Note that many commands have an alternative key-code available
X    on the extended AT keyboard. This aids entry by including most
X    commands on the right side of the keyboard.
X
X	ENTER	    Enter (push up)
X	BS (DEL)    Clear top of stack
X
X	h	    Help
X	i	    Input base  (h, d, o, b)
X	l  (PGDN)   Last top of stack
X	m	    Minix shell
X	o	    Output base (h, d, o, b, a)
X	p  (DOWN)   Pop stack (roll down)
X	q  (END)    Quit
X	r  (LEFT)   Recall (0-9)
X	s  (RIGHT)  Store [+] (0-9)
X	t	    Translate (char)
X	w  (PGUP)   Write top of stack to scratch pad
X	x  (UP)     Exchange top of stack
X	z  (HOME)   Zero all state
X
X	.	    Change sign
X	+  (+)	    Add
X	-  (-)	    Subtract
X	*	    Multiply
X	/	    Divide
X	%  (sh/5)   Remainder
X
X	~	    Not
X	&	    And
X	|	    Or
X	^	    Exclusive-or
X
XFILES
X    ./pad
X    /tmp/pad_$USER
X
XSEE ALSO
X    dc(1), expr(1)
X
XAUTHOR
X    Terrence W. Holm
/
echo x - ic.c
gres '^X' '' > 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
X
X
X
X
X
X#include <stdio.h>
X#include <signal.h>
X
X#include "ic.h"
X
X
X
X
Xstatic char copyright[] = { "ic    (c) Terrence W. Holm 1988" };
X
X
X
X
X/****************************************************************/
X/*								*/
X/*	main()							*/
X/*								*/
X/*		Initialize. Enter the main processing loop.	*/
X/*								*/
X/****************************************************************/
X
X
Xmain( argc, argv )
X  int   argc;
X  char *argv[];
X
X  {
X  ic_state  state;		/*  This state record is passed	*/
X				/*  to most subroutines		*/
X
X  Init_State( &state );
X
X
X  state.scratch_pad = (FILE *) NULL;	/*  No 'w' command yet	*/
X
X
X
X  Init_Getc( argc, argv );	/*  Refs to command line args	*/
X
X
X
X  if ( Init_Termcap() == NULL )
X    {
X    fprintf( stderr, "ic requires a termcap entry\n" );
X    exit( 1 );
X    }
X
X
X  Save_Term();		/*  Save terminal characteristics	*/
X
X
X  if ( signal( SIGINT, SIG_IGN ) != SIG_IGN )
X    {
X    signal( SIGINT,  Sigint );
X    signal( SIGQUIT, Sigint );
X    }
X
X
X  Set_Term(); 		/*  Setup terminal characteristics	*/
X
X
X
X  Draw_Screen( &state );
X
X  while (1)
X    {
X    int  rc = Process( &state, Get_Char() );
X
X    if ( rc == EOF )
X      break;
X
X    if ( rc == ERROR )
X      putchar( BELL );
X    }
X
X
X  Reset_Term();		/*  Restore terminal characteristics	*/
X
X  exit( OK );
X  }
X
X
X
X
X
X
X
X
X/****************************************************************/
X/*								*/
X/*	Init_State()						*/
X/*								*/
X/*		Initialize the state record.			*/
X/*								*/
X/****************************************************************/
X
X
XInit_State( s )
X  ic_state  *s;
X
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
X
X
X
X
X/****************************************************************/
X/*								*/
X/*	Sigint()						*/
X/*								*/
X/*		Terminate the program on an interrupt (^C)	*/
X/*		or quit (^\) signal.				*/
X/*								*/
X/****************************************************************/
X
X
XSigint()
X
X  {
X  Reset_Term();		/*  Restore terminal characteristics	*/
X
X  exit( 1 );
X  }
X
X
X
X
X
X
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/****************************************************************/
X
X
Xint Process( s, c )
X  ic_state  *s;
X  int    c;
X
X  {
X  switch ( c )
X    {
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
X		return( Enter_Numeric( s, (int) c - '0' ) );
X
X
X    case 'a' :
X    case 'b' :
X    case 'c' :
X    case 'd' :
X    case 'e' :
X    case 'f' :
X
X		return( Enter_Numeric( s, (int) c - 'a' + 10 ) );
X
X
X    case 'h' :  case '?' :		/*  Help		*/
X
X		Draw_Help_Screen();
X
X		Get_Char();
X
X		Draw_Screen( s );
X		return( OK );
X
X
X    case 'i' :				/* Set i/p and o/p base	*/
X
X		{
X		int numeral;
X
X		Draw_Prompt( "Base?" );
X
X		numeral = Get_Base( Get_Char() );
X
X		Erase_Prompt();
X
X		if ( numeral == ERROR  ||  numeral == ASCII )
X		  return( ERROR );
X
X		s->input_base  = numeral;
X		s->output_base = numeral;
X		s->mode        = LAST_WAS_FUNCTION;
X
X		Draw_Screen( s );
X		return( OK );
X		}
X
X
X    case 'l' :  case ESC_PGDN :		/*  Get last tos value	 */
X
X  		if ( s->mode != LAST_WAS_ENTER )
X		  Push( s );
X
X		s->stack[0] = s->last_tos;
X
X		s->mode = LAST_WAS_FUNCTION;
X
X		Draw_Stack( s );
X		return( OK );
X
X
X    case 'm' :				/*  Invoke a Minix shell */
X
X		Reset_Term();
X
X		Exec_Shell();
X
X		Set_Term();
X
X		Draw_Screen( s );
X		return( OK );
X
X
X    case 'o' :				/*  Set output base	*/
X
X		{
X		int numeral;
X
X		Draw_Prompt( "Base?" );
X
X		numeral = Get_Base( Get_Char() );
X
X		Erase_Prompt();
X
X		if ( numeral == ERROR )
X		  return( ERROR );
X
X		s->output_base = numeral;
X		s->mode        = LAST_WAS_FUNCTION;
X
X		Draw_Screen( s );
X		return( OK );
X		}
X
X
X    case 'p' :  case ESC_DOWN :		/*  Pop: Roll down stack */
X
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
X		s->mode = LAST_WAS_FUNCTION;
X
X		Draw_Stack( s );
X		return( OK );
X		}
X
X
X    case 'q' :  case ESC_END :  	/*  Quit		 */
X    case EOF :  case CTRL_D  :
X
X		return( EOF );
X
X
X    case 'r' :  case ESC_LEFT :		/*  Recall from register */
X
X		{
X		int numeral;
X
X		Draw_Prompt( "Register?" );
X
X		numeral = Get_Char() - '0';
X
X		Erase_Prompt();
X
X		if (  numeral < 0  ||  numeral >= REGISTERS  ||
X		    ((1 << numeral) & s->register_mask) == 0   )
X		  return( ERROR );
X	
X  		if ( s->mode != LAST_WAS_ENTER )
X		  Push( s );
X
X		s->stack[0] = s->registers[numeral];
X
X		s->mode = LAST_WAS_FUNCTION;
X
X		Draw_Stack( s );
X		return( OK );
X		}
X
X
X    case 's' :  case ESC_RIGHT :	/*  Store in register,	*/
X					/*  or accumulate if	*/
X					/*  "s+" is typed.	*/
X
X		{
X		int c;
X		int numeral;
X
X
X		Draw_Prompt( "Register?" );
X
X		c = Get_Char();
X
X		if ( c == ESC_PLUS )
X		  c = '+';		/*  Allow keypad '+' 	*/
X
X
X		if ( c == '+' )
X		  {
X		  Draw_Prompt( "Accumulator?" );
X		  numeral = Get_Char() - '0';
X		  }
X		else
X		  numeral = c - '0';
X
X		Erase_Prompt();
X
X
X		if (  numeral < 0  ||  numeral >= REGISTERS  )
X		  return( ERROR );
X	
X
X		if (  c != '+'  ||  (s->register_mask & (1 << numeral)) == 0  )
X		  {
X		  s->register_mask |= 1 << numeral;
X		  s->registers[numeral] = s->stack[0];
X		  }
X		else
X		  s->registers[numeral] += s->stack[0];
X
X
X		s->mode = LAST_WAS_FUNCTION;
X
X		Draw_Registers( s );
X		return( OK );
X		}
X
X
X    case 't' :				/*  Translate from ASCII */
X
X		{
X		long int numeral;
X
X		Draw_Prompt( "Character?" );
X
X		numeral = (long int) Getc();
X
X		Erase_Prompt();
X
X  		if ( s->mode != LAST_WAS_ENTER )
X		  Push( s );
X
X		s->stack[0] = numeral;
X
X		s->mode = LAST_WAS_FUNCTION;
X
X		Draw_Stack( s );
X		return( OK );
X		}
X
X
X    case 'w' :  case ESC_PGUP :		/*  Write tos to a file	*/
X
X		{
X		if ( (int) s->scratch_pad == NULL )
X		  {
X		  /*  Try to open a scratch pad file  */
X
X		  strcpy( s->file_name, "./pad" );
X
X		  if ( (s->scratch_pad=fopen(s->file_name,"w")) == NULL )
X		    {
X		    /*  Unsuccessful, try in /tmp  */
X		    char *id;
X
X		    strcpy( s->file_name, "/tmp/pad_" );
X
X		    if ( (id=cuserid(NULL)) == NULL )
X		      return( ERROR );
X
X		    strcat( s->file_name, id );
X
X		    if ( (s->scratch_pad=fopen(s->file_name,"w")) == NULL )
X		      return( ERROR );
X		    }
X
X		  Draw_Screen( s );
X		  }
X
X
X		/*  We have a successfully opened file  */
X
X		Print_Number( s->scratch_pad, s->stack[0], s->output_base );
X		putc( '\n', s->scratch_pad );
X		fflush( s->scratch_pad );
X
X		s->mode = LAST_WAS_FUNCTION;
X
X		return( OK );
X		}
X
X
X    case 'x' :  case ESC_UP :		/*  Exchange top of stack */
X
X		{
X		long int temp = s->stack[0];
X
X		if ( s->stack_size < 2 )
X		  return( ERROR );
X
X		s->stack[0] = s->stack[1];
X		s->stack[1] = temp;
X
X		s->mode = LAST_WAS_FUNCTION;
X
X		Draw_Stack( s );
X		return( OK );
X		}
X
X
X    case 'z' :  case ESC_HOME:		/*  Clear all		*/
X
X		Init_State( s );
X
X		Draw_Screen( s );
X		return( OK );
X
X
X    case BS  :  case DEL :		/*  Clear top of stack  */
X
X		s->stack[0] = 0;
X
X		s->mode = LAST_WAS_ENTER;
X
X		Draw_Top_of_Stack( s );
X		return( OK );
X
X
X    case '\n' :				/*  Enter		*/
X
X		Push( s );
X
X		s->mode = LAST_WAS_ENTER;
X
X		Draw_Stack( s );
X		return( OK );
X
X
X    case '.' :				/*  Change sign		*/
X
X		s->last_tos = s->stack[0];
X
X		s->stack[0] = - s->stack[0];
X
X		s->mode = LAST_WAS_FUNCTION;
X
X		Draw_Top_of_Stack( s );
X		return( OK );
X
X
X    case '+' :  case ESC_PLUS :		/*  Add			*/
X
X		if ( s->stack_size < 2 )
X		  return( ERROR );
X
X		s->last_tos = s->stack[0];
X
X		Pop( s );
X
X		s->stack[0] += s->last_tos;
X
X		s->mode = LAST_WAS_FUNCTION;
X
X		Draw_Stack( s );
X		return( OK );
X
X
X    case '-' :  case ESC_MINUS :	/*  Subtract		*/
X
X		if ( s->stack_size < 2 )
X		  return( ERROR );
X
X		s->last_tos = s->stack[0];
X
X		Pop( s );
X
X		s->stack[0] -= s->last_tos;
X
X		s->mode = LAST_WAS_FUNCTION;
X
X		Draw_Stack( s );
X		return( OK );
X
X
X    case '*' :				/*  Multiply		*/
X
X		if ( s->stack_size < 2 )
X		  return( ERROR );
X
X		s->last_tos = s->stack[0];
X
X		Pop( s );
X
X		if ( s->input_base == DECIMAL )
X		  s->stack[0] *= s->last_tos;
X		else
X		  s->stack[0] = (long int)
X			 ( UNS(s->stack[0]) * UNS(s->last_tos) );
X
X		s->mode = LAST_WAS_FUNCTION;
X
X		Draw_Stack( s );
X		return( OK );
X
X
X    case '/' :				/*  Divide		*/
X
X		if ( s->stack_size < 2  ||  s->stack[0] == 0 )
X		  return( ERROR );
X
X		s->last_tos = s->stack[0];
X
X		Pop( s );
X
X		if ( s->input_base == DECIMAL )
X		  s->stack[0] /= s->last_tos;
X		else
X		  s->stack[0] = (long int)
X			 ( UNS(s->stack[0]) / UNS(s->last_tos) );
X
X		s->mode = LAST_WAS_FUNCTION;
X
X		Draw_Stack( s );
X		return( OK );
X
X
X    case '%' :  case ESC_5 :		/*  Remainder		*/
X
X		if ( s->stack_size < 2  ||  s->stack[0] == 0 )
X		  return( ERROR );
X
X		s->last_tos = s->stack[0];
X
X		Pop( s );
X
X		if ( s->input_base == DECIMAL )
X		  s->stack[0] %= s->last_tos;
X		else
X		  s->stack[0] = (long int)
X			 ( UNS(s->stack[0]) % UNS(s->last_tos) );
X
X		s->mode = LAST_WAS_FUNCTION;
X
X		Draw_Stack( s );
X		return( OK );
X
X
X    case '~' :				/*  Not			*/
X
X		s->last_tos = s->stack[0];
X
X		s->stack[0] = ~ s->stack[0];
X
X		s->mode = LAST_WAS_FUNCTION;
X
X		Draw_Top_of_Stack( s );
X		return( OK );
X
X
X    case '&' :				/*  And			*/
X
X		if ( s->stack_size < 2 )
X		  return( ERROR );
X
X		s->last_tos = s->stack[0];
X
X		Pop( s );
X
X		s->stack[0] &= s->last_tos;
X
X		s->mode = LAST_WAS_FUNCTION;
X
X		Draw_Stack( s );
X		return( OK );
X
X
X    case '|' :				/*  Or			*/
X
X		if ( s->stack_size < 2 )
X		  return( ERROR );
X
X		s->last_tos = s->stack[0];
X
X		Pop( s );
X
X		s->stack[0] |= s->last_tos;
X
X		s->mode = LAST_WAS_FUNCTION;
X
X		Draw_Stack( s );
X		return( OK );
X
X
X    case '^' :				/*  Exclusive-or	*/
X
X		if ( s->stack_size < 2 )
X		  return( ERROR );
X
X		s->last_tos = s->stack[0];
X
X		Pop( s );
X
X		s->stack[0] ^= s->last_tos;
X
X		s->mode = LAST_WAS_FUNCTION;
X
X		Draw_Stack( s );
X		return( OK );
X
X
X    default:
X		return( ERROR );
X    }
X  }
X
X
X
X
X
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/****************************************************************/
X
X
Xint Enter_Numeric( s, numeral )
X  ic_state *s;
X  int   numeral;
X
X  {
X  if ( numeral >= s->input_base )
X    return( ERROR );
X
X
X  switch ( s->mode )
X    {
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();
X    }
X
X  s->mode = LAST_WAS_NUMERIC;
X
X  return( OK );
X  }
X
X
X
X
X
X
X
X
X/****************************************************************/
X/*								*/
X/*	Push( state )						*/
X/*								*/
X/*		Push up the stack one level.			*/
X/*								*/
X/****************************************************************/
X
X
XPush( s )
X  ic_state *s;
X
X  {
X  int i;
X
X  if ( s->stack_size == STACK_SIZE ) 
X    --s->stack_size;
X
X  for ( i = s->stack_size;  i > 0;  --i )
X    s->stack[i] = s->stack[i-1];
X
X  ++s->stack_size;
X  }
X
X
X
X
X
X
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/****************************************************************/
X
X
XPop( s )
X  ic_state *s;
X
X  {
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_size;
X  }
X
X
X
X
X
X
X
X
X/****************************************************************/
X/*								*/
X/*	Exec_Shell()						*/
X/*								*/
X/*		Fork off a sub-process to exec() the shell.	*/
X/*								*/
X/****************************************************************/
X
X
XExec_Shell()
X
X  {
X  int pid = fork();
X
X  if ( pid == -1 )
X    return;
X
X
X  if ( pid == 0 )
X    {
X    /*  The child process  */
X
X    extern char **environ;
X    char *shell  =  getenv( "SHELL" );
X
X    if ( shell == NULL )
X      shell = "/bin/sh";
X
------------------------------------------------------------------

holm@ubc-bdcvax.UUCP (Terrence W. Holm) (02/02/89)

---------------------------------------------------------------
X    execle( shell, shell, (char *) 0, environ );
X
X    perror( shell );
X    exit( 127 );
X    }
X
X
X  /*  The parent process: ignore signals, wait for sub-process	*/
X
X  signal( SIGINT,  SIG_IGN );
X  signal( SIGQUIT, SIG_IGN );
X
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
X  return;
X  }
/
echo x - ic.h
gres '^X' '' > 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
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
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
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
X
X
X
X#define   UNS(x)	((unsigned long)(x))
X
X#define   STACK_SIZE 	6		/*  Max # of levels	*/
X#define   REGISTERS	10		/*  Registers 0 to 9	*/
X
X
X#define	  LAST_WAS_ENTER    1		/*  Numeric input modes	*/
X#define	  LAST_WAS_NUMERIC  2
X#define	  LAST_WAS_FUNCTION 3
X
X
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
X
X#define   OK		0		/*  Return codes	*/
X#define   ERROR		1
X
X
X
X
X
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
X
X
X	/*  Input escape codes generated by the	Minix console.	*/
X	/*  Format: ESC [ X. Shows character equivalent for ic.	*/
X
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
X
X
X	/*  Move positions for the output display.		*/
X
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
X
X
X
X
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
X  int  stack_size;			/*  Current size (>= 1)	*/
X  int  register_mask;			/*  In use bit mask	*/
X
X  long int last_tos;			/*  For 'L' command	*/
X
X  int  mode;				/*  Last key type. See	*/
X					/*  LAST_WAS_ENTER, etc	*/
X
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
X
X
X
X
Xint   Sigint();
Xint   Process();
Xint   Enter_Numeric();
Xint   Get_Char();
Xint   Get_Base();
Xchar *getenv();
Xchar *tgetstr();
Xchar *tgoto();
Xchar *cuserid();
XFILE *fopen();
/
echo x - ic_input.c
gres '^X' '' > 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
X
X
X#include <stdio.h>
X#include <ctype.h>
X#include <sgtty.h>
X
X#include "ic.h"
X
X
X
X
Xstatic struct sgttyb saved_mode;
Xstatic struct tchars saved_chars;
X
X
X
X
X
X
X/****************************************************************/
X/*								*/
X/*	Save_Term()						*/
X/*								*/
X/*		Save the current terminal characteristics.	*/
X/*								*/
X/****************************************************************/
X
X
XSave_Term()
X
X  {
X  ioctl( 0, TIOCGETP, &saved_mode  );
X  ioctl( 0, TIOCGETC, &saved_chars );
X  }
X
X
X
X
X
X
X
X
X/****************************************************************/
X/*								*/
X/*	Set_Term()						*/
X/*								*/
X/*		Set up the terminal characteristics for ic.	*/
X/*								*/
X/****************************************************************/
X
X
XSet_Term()
X
X  {
X  struct sgttyb ic_mode;
X  struct tchars ic_chars;
X
X  ic_mode  = saved_mode;
X  ic_chars = saved_chars;
X
X
X  /*  No tab expansion, no echo, cbreak mode			*/
X
X  ic_mode.sg_flags = ic_mode.sg_flags & ~XTABS & ~ECHO  |  CBREAK;
X
X
X  /*  Change the interrupt character to ^C, ignore ^S & ^Q 	*/
X
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, &ic_chars );
X  }
X
X
X
X
X
X
X
X
X/****************************************************************/
X/*								*/
X/*	Reset_Term()						*/
X/*								*/
X/*		Restore the terminal characteristics.		*/
X/*								*/
X/****************************************************************/
X
X
XReset_Term()
X
X  {
X  ioctl( 0, TIOCSETP, &saved_mode  );
X  ioctl( 0, TIOCSETC, &saved_chars );
X  }
X
X
X
X
X
X
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/****************************************************************/
X
X
Xint Get_Char()
X
X  {
X  int c;
X
X
X  /*  fflush() used because Minix does not automatically	*/
X  /*  flush the output.						*/
X
X  fflush( stdout );
X
X
X  if ( (c = Getc()) == EOF )
X    return( EOF );
X  
X  c &= 0x7f;
X
X
X  if ( isupper(c) )
X    return( tolower(c) );
X
X
X  if ( c == ESCAPE )
X    if ( (c=Getc()) != '[' )
X      {
X      ungetc( c, stdin );
X      return( ESCAPE );
X      }
X    else
X      {
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
X  return( c );
X  }
X
X
X
X
X
X
X
X
X/****************************************************************/
X/*								*/
X/*	Init_Getc( argc, argv )					*/
X/*								*/
X/*		Give Getc() references to the command line	*/
X/*		arguments.					*/
X/*								*/
X/****************************************************************/
X
X
X
Xstatic int    args_remaining;
Xstatic char **args_pointer;
Xstatic int    args_index;
X
X
X
XInit_Getc( argc, argv )
X  int   argc;
X  char *argv[];
X
X  {
X  args_remaining = argc - 1;
X  args_pointer   = &argv[1];
X  args_index     = 0;
X  }
X
X
X
X
X
X
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/****************************************************************/
X
X
Xint Getc()
X
X  {
X  int c;
X
X  if ( args_remaining > 0 )
X    if ( (c = args_pointer[ 0 ][ args_index++ ]) == '\0' )
X      {
X      --args_remaining;
X      ++args_pointer;
X      args_index = 0;
X
X      if ( args_remaining > 0 )
X        return( '\n' );
X      }
X    else
X      return( c );
X
X  return( getchar() );
X  }
X
X
X
X
X
X
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/****************************************************************/
X
X
Xint Get_Base( code )
X  char code;
X
X  {
X  switch ( code )
X    {
X    case 'h' :		return( HEXADECIMAL );
X
X    case 'd' :		return( DECIMAL     );
X
X    case 'o' :		return( OCTAL       );
X
X    case 'b' :		return( BINARY      );
X
X    case 'a' :  	return( ASCII       );
X
X    default  :		return( ERROR       );
X    }
X  }
/
echo x - ic_output.c
gres '^X' '' > 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
X
X
X#include <stdio.h>
X
X#include "ic.h"
X
X
X
X
X
X
X/****************************************************************/
X/*   		Code for handling termcap			*/
X/****************************************************************/
X
X
X#define  TC_BUFFER  1024	/* Size of termcap(3) buffer	*/
X#define  TC_STRINGS  200	/* Enough room for cm,cl,so,se	*/
X
X
X
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
X
X
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/****************************************************************/
X
X
XInit_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
X  if ( term == NULL )
X    return( NULL );
X
X  if ( tgetent( buffer, term ) != 1 )
X    return( NULL );
X
X
X
X  if ( (Tmove=tgetstr( "cm", &s )) == NULL )
X    return( NULL );
X
X  if ( (Tclr_all=tgetstr( "cl", &s )) == NULL )
X    return( NULL );
X
X  if ( (Treverse=tgetstr( "so", &s )) == NULL )
X    {
X    Treverse = s;
X    *s = '\0';
X    ++s;
X    }
X
X  if ( (Tnormal=tgetstr( "se", &s )) == NULL )
X    {
X    Tnormal = s;
X    *s = '\0';
X    ++s;
X    }
X
X  return( EOF );
X  }
X
X
X
X
X
X
X
X
X/****************************************************************/
X/*								*/
X/*	Move( column, line )					*/
X/*								*/
X/*		Use the termcap string to move the cursor.	*/
X/*								*/
X/****************************************************************/
X
X
XMove( column, line )
X  int  column;
X  int  line;
X
X  {
X  Puts( tgoto( Tmove, column, line ) );
X  }
X
X
X
X
X
X
X
X
X/****************************************************************/
X/*								*/
X/*	Puts( string )						*/
X/*								*/
X/*		Write the given termcap string to the standard	*/
X/*		output device.					*/
X/*								*/
X/****************************************************************/
X
X
XPuts( string )
X  char  *string;
X
X  {
X  int Putchar();
X
X  tputs( string, 1, Putchar );
X  }
X
X
XPutchar( c )
X  char  c;
X
X  {
X  putchar( c );
X  }
X
X
X
X
X
X
X
X
X/****************************************************************/
X/*   		       Output routines				*/
X/****************************************************************/
X
X
X
X
X/****************************************************************/
X/*								*/
X/*	Draw_Help_Screen()					*/
X/*								*/
X/****************************************************************/
X
X
XDraw_Help_Screen()
X
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
X
X
X
X
X/****************************************************************/
X/*								*/
X/*	Draw_Prompt( string )					*/
X/*								*/
X/*		Write a message in the "wait" area.		*/
X/*								*/
X/****************************************************************/
X
X
XDraw_Prompt( string )
X  char  *string;
X
X  {
X  Move( WAIT_COLUMN, WAIT_LINE );
X
X  Puts( Treverse );
X  printf( string );
X  Puts( Tnormal );
X  }
X
X
X
X
X
X
X
X
X/****************************************************************/
X/*								*/
X/*	Erase_Prompt()						*/
X/*								*/
X/*		Erase the message in the "wait" area.		*/
X/*								*/
X/****************************************************************/
X
XErase_Prompt()
X
X  {
X  Move( WAIT_COLUMN, WAIT_LINE );
X
X  printf( "              " );
X
X  Move( WAIT_COLUMN, WAIT_LINE );
X  }
X
X
X
X
X
X
X
X
X/****************************************************************/
X/*								*/
X/*	Draw_Screen( state )					*/
X/*								*/
X/*		Redraw everything.				*/
X/*								*/
X/****************************************************************/
X
X
XDraw_Screen( s )
X  ic_state *s;
X
X  {
X  Puts( Tclr_all );		/*  Clear the screen  */
X
X  Draw_Stack( s );
X  Draw_Registers( s );
X
X
X  Move( STATUS_COLUMN, STATUS_LINE );
X
X  printf( "Input base = %2d    ", s->input_base );
X
X  if ( s->output_base == ASCII )
X    printf( "Output is ASCII     " );
X  else
X    printf( "Output base = %2d    ", s->output_base );
X
X  if ( (int) s->scratch_pad != NULL )
X    printf( "Scratch file = %s", s->file_name );
X
X  Move( WAIT_COLUMN, WAIT_LINE );
X  }
X
X
X
X
X
X
X
X
X/****************************************************************/
X/*								*/
X/*	Draw_Stack( state )					*/
X/*								*/
X/*		Redraw the stack.				*/
X/*								*/
X/****************************************************************/
X
X
XDraw_Stack( s )
X  ic_state *s;
X
X  {
X  int i;
X
X  for ( i = STACK_SIZE-1;  i >= 0;  --i )
X    {
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
X
X
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/****************************************************************/
X
X
XDraw_Registers( s )
X  ic_state *s;
X
X  {
X  int i;
X
X  for ( i = 0;  i < REGISTERS;  ++i )
X    {
X    if ( (1 << i) & s->register_mask  )
X      {
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
X
X
X
X
X/****************************************************************/
X/*								*/
X/*	Draw_Top_of_Stack( state )				*/
X/*								*/
X/*		Redraw only the entry on the top of the stack.	*/
X/*								*/
X/****************************************************************/
X
X
XDraw_Top_of_Stack( s )
X  ic_state *s;
X
X  {
X  Move( STACK_COLUMN, STACK_LINE + STACK_SIZE - 1 );
X
X  Print_Number( stdout, s->stack[0], s->output_base );
X
X  Move( WAIT_COLUMN, WAIT_LINE );
X  }
X
X
X
X
X
X
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/****************************************************************/
X
X
XPrint_Number( stream, number, output_base )
X  FILE    *stream;
X  long int number;
X  int      output_base;
X
X  {
X  switch ( output_base )
X    {
X    case HEXADECIMAL :	fprintf( stream, "%12lx", number );
X			break;
X
X
X    case DECIMAL :	fprintf( stream, "%12ld", number );
X			break;
X
X
X    case OCTAL :	fprintf( stream, "%12lo", number );
X			break;
X
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
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 :		fprintf( stderr, "Internal failure (output base)\n" );
X			Sigint();
X    }
X  }
/
----------------------------------------------------------