Minix1.5/commands/ic/ic.c

Compare this file to the similar file:
Show the results in this format:

/****************************************************************/
/*								*/
/*	ic.c							*/
/*								*/
/*		The main loop of the "Integer Calculator".	*/
/*								*/
/****************************************************************/
/*  origination          1988-Apr-6   	    Terrence W. Holm	*/
/*  added Exec_Shell()   1988-Apr-11	    Terrence W. Holm	*/
/*  added "s+"		 1988-Apr-18	    Terrence W. Holm	*/
/*  added cmd line args  1988-May-13	    Terrence W. Holm	*/
/*  'i' also does 'o'	 1988-May-28	    Terrence W. Holm	*/
/*  if ~dec:unsigned *%/ 1988-Jul-10	    Terrence W. Holm	*/
/****************************************************************/






#include <sys/types.h>
#include <signal.h>
#include <stdio.h>

#include "ic.h"




static char copyright[] = { "ic    (c) Terrence W. Holm 1988" };



/****************************************************************/
/*								*/
/*	main()							*/
/*								*/
/*		Initialize. Enter the main processing loop.	*/
/*								*/
/****************************************************************/


main( argc, argv )
  int   argc;
  char *argv[];

  {
  ic_state  state;		/*  This state record is passed	*/
				/*  to most subroutines		*/

  Init_State( &state );


  state.scratch_pad = (FILE *) NULL;	/*  No 'w' command yet	*/



  Init_Getc( argc, argv );	/*  Refs to command line args	*/



  if ( Init_Termcap() == 0 )
    {
    fprintf( stderr, "ic requires a termcap entry\n" );
    exit( 1 );
    }


  Save_Term();		/*  Save terminal characteristics	*/


  if ( signal( SIGINT, SIG_IGN ) != SIG_IGN )
    {
    signal( SIGINT,  Sigint );
    signal( SIGQUIT, Sigint );
    }


  Set_Term(); 		/*  Setup terminal characteristics	*/



  Draw_Screen( &state );

  while (1)
    {
    int  rc = Process( &state, Get_Char() );

    if ( rc == EOF )
      break;

    if ( rc == ERROR )
      putchar( BELL );
    }


  Reset_Term();		/*  Restore terminal characteristics	*/

  exit( OK );
  }








/****************************************************************/
/*								*/
/*	Init_State()						*/
/*								*/
/*		Initialize the state record.			*/
/*								*/
/****************************************************************/


Init_State( s )
  ic_state  *s;

  {
  s->stack[0]      = 0;
  s->stack_size    = 1;
  s->register_mask = 0x000;
  s->last_tos      = 0;
  s->mode          = LAST_WAS_ENTER;
  s->input_base    = DECIMAL;
  s->output_base   = DECIMAL;
  }








/****************************************************************/
/*								*/
/*	Sigint()						*/
/*								*/
/*		Terminate the program on an interrupt (^C)	*/
/*		or quit (^\) signal.				*/
/*								*/
/****************************************************************/


void Sigint(sig)
int sig;
  {
  Reset_Term();		/*  Restore terminal characteristics	*/

  exit( 1 );
  }








/****************************************************************/
/*								*/
/*	Process( state, input_char )				*/
/*								*/
/*		Determine the function requested by the 	*/
/*		input character. Returns OK, EOF or ERROR.	*/
/*								*/
/****************************************************************/


int Process( s, c )
  ic_state  *s;
  int    c;

  {
  switch ( c )
    {
    case '0' :
    case '1' :
    case '2' :
    case '3' :
    case '4' :
    case '5' :
    case '6' :
    case '7' :
    case '8' :
    case '9' :

		return( Enter_Numeric( s, (int) c - '0' ) );


    case 'a' :
    case 'b' :
    case 'c' :
    case 'd' :
    case 'e' :
    case 'f' :

		return( Enter_Numeric( s, (int) c - 'a' + 10 ) );


    case 'h' :  case '?' :		/*  Help		*/

		Draw_Help_Screen();

		Get_Char();

		Draw_Screen( s );
		return( OK );


    case 'i' :				/* Set i/p and o/p base	*/

		{
		int numeral;

		Draw_Prompt( "Base?" );

		numeral = Get_Base( Get_Char() );

		Erase_Prompt();

		if ( numeral == ERROR  ||  numeral == ASCII )
		  return( ERROR );

		s->input_base  = numeral;
		s->output_base = numeral;
		s->mode        = LAST_WAS_FUNCTION;

		Draw_Screen( s );
		return( OK );
		}


    case 'l' :  case ESC_PGDN :		/*  Get last tos value	 */

  		if ( s->mode != LAST_WAS_ENTER )
		  Push( s );

		s->stack[0] = s->last_tos;

		s->mode = LAST_WAS_FUNCTION;

		Draw_Stack( s );
		return( OK );


    case 'm' :				/*  Invoke a Minix shell */

		Reset_Term();

		Exec_Shell();

		Set_Term();

		Draw_Screen( s );
		return( OK );


    case 'o' :				/*  Set output base	*/

		{
		int numeral;

		Draw_Prompt( "Base?" );

		numeral = Get_Base( Get_Char() );

		Erase_Prompt();

		if ( numeral == ERROR )
		  return( ERROR );

		s->output_base = numeral;
		s->mode        = LAST_WAS_FUNCTION;

		Draw_Screen( s );
		return( OK );
		}


    case 'p' :  case ESC_DOWN :		/*  Pop: Roll down stack */

		{
		long int temp = s->stack[0];
		int  i;

  		for ( i = 0;  i < s->stack_size-1;  ++i )
    		  s->stack[i] = s->stack[i+1];

		s->stack[ s->stack_size-1 ] = temp;

		s->mode = LAST_WAS_FUNCTION;

		Draw_Stack( s );
		return( OK );
		}


    case 'q' :  case ESC_END :  	/*  Quit		 */
    case EOF :  case CTRL_D  :

		return( EOF );


    case 'r' :  case ESC_LEFT :		/*  Recall from register */

		{
		int numeral;

		Draw_Prompt( "Register?" );

		numeral = Get_Char() - '0';

		Erase_Prompt();

		if (  numeral < 0  ||  numeral >= REGISTERS  ||
		    ((1 << numeral) & s->register_mask) == 0   )
		  return( ERROR );
	
  		if ( s->mode != LAST_WAS_ENTER )
		  Push( s );

		s->stack[0] = s->registers[numeral];

		s->mode = LAST_WAS_FUNCTION;

		Draw_Stack( s );
		return( OK );
		}


    case 's' :  case ESC_RIGHT :	/*  Store in register,	*/
					/*  or accumulate if	*/
					/*  "s+" is typed.	*/

		{
		int c;
		int numeral;


		Draw_Prompt( "Register?" );

		c = Get_Char();

		if ( c == ESC_PLUS )
		  c = '+';		/*  Allow keypad '+' 	*/


		if ( c == '+' )
		  {
		  Draw_Prompt( "Accumulator?" );
		  numeral = Get_Char() - '0';
		  }
		else
		  numeral = c - '0';

		Erase_Prompt();


		if (  numeral < 0  ||  numeral >= REGISTERS  )
		  return( ERROR );
	

		if (  c != '+'  ||  (s->register_mask & (1 << numeral)) == 0  )
		  {
		  s->register_mask |= 1 << numeral;
		  s->registers[numeral] = s->stack[0];
		  }
		else
		  s->registers[numeral] += s->stack[0];


		s->mode = LAST_WAS_FUNCTION;

		Draw_Registers( s );
		return( OK );
		}


    case 't' :				/*  Translate from ASCII */

		{
		long int numeral;

		Draw_Prompt( "Character?" );

		numeral = (long int) Getc();

		Erase_Prompt();

  		if ( s->mode != LAST_WAS_ENTER )
		  Push( s );

		s->stack[0] = numeral;

		s->mode = LAST_WAS_FUNCTION;

		Draw_Stack( s );
		return( OK );
		}


    case 'w' :  case ESC_PGUP :		/*  Write tos to a file	*/

		{
		if ( (int) s->scratch_pad == (int) NULL )
		  {
		  /*  Try to open a scratch pad file  */

		  strcpy( s->file_name, "./pad" );

		  if ( (s->scratch_pad=fopen(s->file_name,"w")) == NULL )
		    {
		    /*  Unsuccessful, try in /tmp  */
		    char *id;

		    strcpy( s->file_name, "/tmp/pad_" );

		    if ( (id=cuserid(NULL)) == NULL )
		      return( ERROR );

		    strcat( s->file_name, id );

		    if ( (s->scratch_pad=fopen(s->file_name,"w")) == NULL )
		      return( ERROR );
		    }

		  Draw_Screen( s );
		  }


		/*  We have a successfully opened file  */

		Print_Number( s->scratch_pad, s->stack[0], s->output_base );
		putc( '\n', s->scratch_pad );
		fflush( s->scratch_pad );

		s->mode = LAST_WAS_FUNCTION;

		return( OK );
		}


    case 'x' :  case ESC_UP :		/*  Exchange top of stack */

		{
		long int temp = s->stack[0];

		if ( s->stack_size < 2 )
		  return( ERROR );

		s->stack[0] = s->stack[1];
		s->stack[1] = temp;

		s->mode = LAST_WAS_FUNCTION;

		Draw_Stack( s );
		return( OK );
		}


    case 'z' :  case ESC_HOME:		/*  Clear all		*/

		Init_State( s );

		Draw_Screen( s );
		return( OK );


    case BS  :  case DEL :		/*  Clear top of stack  */

		s->stack[0] = 0;

		s->mode = LAST_WAS_ENTER;

		Draw_Top_of_Stack( s );
		return( OK );


    case '\n' :				/*  Enter		*/

		Push( s );

		s->mode = LAST_WAS_ENTER;

		Draw_Stack( s );
		return( OK );


    case '.' :				/*  Change sign		*/

		s->last_tos = s->stack[0];

		s->stack[0] = - s->stack[0];

		s->mode = LAST_WAS_FUNCTION;

		Draw_Top_of_Stack( s );
		return( OK );


    case '+' :  case ESC_PLUS :		/*  Add			*/

		if ( s->stack_size < 2 )
		  return( ERROR );

		s->last_tos = s->stack[0];

		Pop( s );

		s->stack[0] += s->last_tos;

		s->mode = LAST_WAS_FUNCTION;

		Draw_Stack( s );
		return( OK );


    case '-' :  case ESC_MINUS :	/*  Subtract		*/

		if ( s->stack_size < 2 )
		  return( ERROR );

		s->last_tos = s->stack[0];

		Pop( s );

		s->stack[0] -= s->last_tos;

		s->mode = LAST_WAS_FUNCTION;

		Draw_Stack( s );
		return( OK );


    case '*' :				/*  Multiply		*/

		if ( s->stack_size < 2 )
		  return( ERROR );

		s->last_tos = s->stack[0];

		Pop( s );

		if ( s->input_base == DECIMAL )
		  s->stack[0] *= s->last_tos;
		else
		  s->stack[0] = (long int)
			 ( UNS(s->stack[0]) * UNS(s->last_tos) );

		s->mode = LAST_WAS_FUNCTION;

		Draw_Stack( s );
		return( OK );


    case '/' :				/*  Divide		*/

		if ( s->stack_size < 2  ||  s->stack[0] == 0 )
		  return( ERROR );

		s->last_tos = s->stack[0];

		Pop( s );

		if ( s->input_base == DECIMAL )
		  s->stack[0] /= s->last_tos;
		else
		  s->stack[0] = (long int)
			 ( UNS(s->stack[0]) / UNS(s->last_tos) );

		s->mode = LAST_WAS_FUNCTION;

		Draw_Stack( s );
		return( OK );


    case '%' :  case ESC_5 :		/*  Remainder		*/

		if ( s->stack_size < 2  ||  s->stack[0] == 0 )
		  return( ERROR );

		s->last_tos = s->stack[0];

		Pop( s );

		if ( s->input_base == DECIMAL )
		  s->stack[0] %= s->last_tos;
		else
		  s->stack[0] = (long int)
			 ( UNS(s->stack[0]) % UNS(s->last_tos) );

		s->mode = LAST_WAS_FUNCTION;

		Draw_Stack( s );
		return( OK );


    case '~' :				/*  Not			*/

		s->last_tos = s->stack[0];

		s->stack[0] = ~ s->stack[0];

		s->mode = LAST_WAS_FUNCTION;

		Draw_Top_of_Stack( s );
		return( OK );


    case '&' :				/*  And			*/

		if ( s->stack_size < 2 )
		  return( ERROR );

		s->last_tos = s->stack[0];

		Pop( s );

		s->stack[0] &= s->last_tos;

		s->mode = LAST_WAS_FUNCTION;

		Draw_Stack( s );
		return( OK );


    case '|' :				/*  Or			*/

		if ( s->stack_size < 2 )
		  return( ERROR );

		s->last_tos = s->stack[0];

		Pop( s );

		s->stack[0] |= s->last_tos;

		s->mode = LAST_WAS_FUNCTION;

		Draw_Stack( s );
		return( OK );


    case '^' :				/*  Exclusive-or	*/

		if ( s->stack_size < 2 )
		  return( ERROR );

		s->last_tos = s->stack[0];

		Pop( s );

		s->stack[0] ^= s->last_tos;

		s->mode = LAST_WAS_FUNCTION;

		Draw_Stack( s );
		return( OK );


    default:
		return( ERROR );
    }
  }








/****************************************************************/
/*								*/
/*	Enter_Numeric( state, numeral )				*/
/*								*/
/*		A numeral (0 to 15) has been typed.		*/
/*		If a number is currently being entered		*/
/*		then shift it over and add this to the		*/
/*		display. If the last operation was a function	*/
/*		then push up the stack first. If the last	*/
/*		key was "ENTER", then clear out the top of	*/
/*		the stack and put the numeral there.		*/
/*								*/
/*		Returns OK or ERROR.				*/
/*								*/
/****************************************************************/


int Enter_Numeric( s, numeral )
  ic_state *s;
  int   numeral;

  {
  if ( numeral >= s->input_base )
    return( ERROR );


  switch ( s->mode )
    {
    case LAST_WAS_FUNCTION :
		Push( s );
		s->stack[0] = numeral;
		Draw_Stack( s );
		break;

    case LAST_WAS_NUMERIC :
		s->stack[0] = s->stack[0] * s->input_base + numeral;
		Draw_Top_of_Stack( s );
		break;

    case LAST_WAS_ENTER :
		s->stack[0] = numeral;
		Draw_Top_of_Stack( s );
		break;

    default:
		fprintf( stderr, "Internal failure (mode)\n" );
		Sigint();
    }

  s->mode = LAST_WAS_NUMERIC;

  return( OK );
  }








/****************************************************************/
/*								*/
/*	Push( state )						*/
/*								*/
/*		Push up the stack one level.			*/
/*								*/
/****************************************************************/


Push( s )
  ic_state *s;

  {
  int i;

  if ( s->stack_size == STACK_SIZE ) 
    --s->stack_size;

  for ( i = s->stack_size;  i > 0;  --i )
    s->stack[i] = s->stack[i-1];

  ++s->stack_size;
  }








/****************************************************************/
/*								*/
/*	Pop( state )						*/
/*								*/
/*		Pop the stack down one level.			*/
/*		This routine is only called with 		*/
/*		the stack size > 1.				*/
/*								*/
/****************************************************************/


Pop( s )
  ic_state *s;

  {
  int i;

  for ( i = 0;  i < s->stack_size-1;  ++i )
    s->stack[i] = s->stack[i+1];

  --s->stack_size;
  }








/****************************************************************/
/*								*/
/*	Exec_Shell()						*/
/*								*/
/*		Fork off a sub-process to exec() the shell.	*/
/*								*/
/****************************************************************/


Exec_Shell()

  {
  int pid = fork();

  if ( pid == -1 )
    return;


  if ( pid == 0 )
    {
    /*  The child process  */

    extern char **environ;
    char *shell  =  getenv( "SHELL" );

    if ( shell == NULL )
      shell = "/bin/sh";

    execle( shell, shell, (char *) 0, environ );

    perror( shell );
    exit( 127 );
    }


  /*  The parent process: ignore signals, wait for sub-process	*/

  signal( SIGINT,  SIG_IGN );
  signal( SIGQUIT, SIG_IGN );

  {
  int  status;
  int  w;

  while ( (w=wait(&status)) != pid  &&  w != -1 );
  }

  signal( SIGINT,  Sigint );
  signal( SIGQUIT, Sigint );

  return;
  }