Path: utzoo!utgpu!water!watmath!clyde!att!osu-cis!tut.cis.ohio-state.edu!bloom-beacon!mit-eddie!uw-beaver!ssc-vax!uvicctr!tholm From: tholm@uvicctr.UUCP (Terrence W. Holm) Newsgroups: comp.os.minix Subject: ic(1), part 2 of 3 Message-ID: <416@uvicctr.UUCP> Date: 17 May 88 23:42:11 GMT Reply-To: tholm@uvicctr.UUCP (Terrence W. Holm) Organization: University of Victoria, Victoria B.C. Canada Lines: 851 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 X#include 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