📄 ic.c
字号:
/*****************************************************************//* *//* 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 <sys/wait.h>#include <signal.h>#include <string.h>#include <stdlib.h>#include <unistd.h>#include <stdio.h>#include "ic.h"static char copyright[] = {"ic (c) Terrence W. Holm 1988"};/****************************************************************//* *//* main() *//* *//* Initialize. Enter the main processing loop. *//* *//****************************************************************/int main(argc, argv)int argc;char *argv[];{ ic_state state; /* This state record is passed to most procs */ 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. *//* *//****************************************************************/void 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 (s->scratch_pad == (FILE *) 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(0); } s->mode = LAST_WAS_NUMERIC; return(OK);}/*****************************************************************//* *//* Push( state ) *//* *//* Push up the stack one level. *//* *//*****************************************************************/void 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. *//* *//*****************************************************************/void 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. *//* *//****************************************************************/void 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;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -