/**************************************** * Computer Algebra System SINGULAR * ****************************************/ /* * ABSTRACT: input from ttys, simulating fgets */ #ifdef HAVE_CONFIG_H #include "singularconfig.h" #endif /* HAVE_CONFIG_H */ #include #include // #include // #include #ifdef HAVE_FEREAD #include #include #include #include #include #include #if 0 #include #else #ifdef SunOS_5 /* solaris special, found with v 5.7 */ #define _XOPEN_SOURCE_EXTENDED #include "/usr/xpg4/include/term.h" #endif #if 0 #ifndef SunOS_5 #include #endif #elif HAVE_TERMCAP_H #ifndef SunOS_5 #include #endif #endif #if defined(HAVE_TERMIOS_H) && ! defined(TCSANOW) #include #endif #if defined(HAVE_TERM_H) && ! defined(TCSANOW) #include #endif #endif #ifndef STDIN_FILENO #define STDIN_FILENO 0 #endif #ifndef STDOUT_FILENO #define STDOUT_FILENO 1 #endif #define feCTRL(C) ((C) & 0x1F) /* character */ struct termios fe_saved_attributes; static BOOLEAN fe_stdout_is_tty; static BOOLEAN fe_stdin_is_tty; BOOLEAN fe_use_fgets=FALSE; static BOOLEAN fe_is_initialized=FALSE; static int pagelength = 24; FILE * fe_echo; /*the output file for echoed characters*/ #define fe_hist_max 32 char ** fe_hist=NULL; short fe_hist_pos; BOOLEAN fe_is_raw_tty=0; int fe_cursor_pos; /* 0..colmax-1*/ int fe_cursor_line; /* 0..pagelength-1*/ #ifndef HAVE_ATEXIT int on_exit(void (*f)(int, void *), void *arg); #ifdef HAVE_FEREAD void fe_reset_fe (int i, void *v) #endif #else #ifdef HAVE_FEREAD void fe_reset_fe (void) #endif #endif { if (fe_stdin_is_tty) { int i; if (fe_is_raw_tty) { tcsetattr (STDIN_FILENO, TCSANOW, &fe_saved_attributes); fe_is_raw_tty=0; } if (fe_hist!=NULL) { for(i=fe_hist_max-1;i>=0;i--) { if (fe_hist[i] != NULL) omFree((ADDRESS)fe_hist[i]); } omFreeSize((ADDRESS)fe_hist,fe_hist_max*sizeof(char *)); fe_hist=NULL; } if (!fe_stdout_is_tty) { fclose(fe_echo); } } } void fe_temp_reset (void) { if (fe_is_raw_tty) { tcsetattr (STDIN_FILENO, TCSANOW, &fe_saved_attributes); fe_is_raw_tty=0; } } void fe_temp_set (void) { if(fe_is_raw_tty==0) { struct termios tattr; /* Set the funny terminal modes. */ tcgetattr (STDIN_FILENO, &tattr); tattr.c_lflag &= ~(ICANON|ECHO); /* Clear ICANON and ECHO. */ tattr.c_cc[VMIN] = 1; tattr.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &tattr); fe_is_raw_tty=1; } } static char termcap_buff[2048]; static int fe_out_char(int c) { fputc(c,fe_echo); return c; } void fe_init (void) { fe_is_initialized=TRUE; if ((!fe_use_fgets) && (isatty (STDIN_FILENO))) { /* Make sure stdin is a terminal. */ char *term=getenv("TERM"); /*setup echo*/ if(isatty(STDOUT_FILENO)) { fe_stdout_is_tty=1; fe_echo=stdout; } else { fe_stdout_is_tty=0; fe_echo = fopen( ttyname(fileno(stdin)), "w" ); } /* Save the terminal attributes so we can restore them later. */ { struct termios tattr; tcgetattr (STDIN_FILENO, &fe_saved_attributes); #ifdef HAVE_FEREAD #ifdef HAVE_ATEXIT atexit(fe_reset_fe); #else on_exit(fe_reset_fe,NULL); #endif #endif /* Set the funny terminal modes. */ tcgetattr (STDIN_FILENO, &tattr); tattr.c_lflag &= ~(ICANON|ECHO); /* Clear ICANON and ECHO. */ tattr.c_cc[VMIN] = 1; tattr.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &tattr); /*ospeed=cfgetospeed(&tattr);*/ } if(term==NULL) { printf("need TERM\n"); } else if(tgetent(termcap_buff,term)<=0) { printf("could not access termcap data base\n"); } else { #ifndef ix86_Win extern char *BC; extern char *UP; extern char PC; #endif /* OB: why this ? HS: char t_buf[128] does not work with glibc2 systems */ char *t_buf=(char *)omAlloc(128); /*char t_buf[128];*/ char *temp; char** t_buf_ptr= &t_buf; /* Extract information that termcap functions use. */ temp = tgetstr ("pc", t_buf_ptr); PC = (temp!=NULL) ? *temp : '\0'; BC=tgetstr("le",t_buf_ptr); UP=tgetstr("up",t_buf_ptr); /* Extract information we will use */ colmax=tgetnum("co"); pagelength=tgetnum("li"); fe_cursor_line=pagelength-1; /* init screen */ temp = tgetstr ("ti", t_buf_ptr); #if 0 if (temp!=NULL) tputs(temp,1,fe_out_char); #endif /* printf("TERM=%s, co=%d, li=%d\n",term,colmax,pagelength);*/ } fe_stdin_is_tty=1; fe_is_raw_tty=1; /* setup history */ fe_hist=(char **)omAlloc0(fe_hist_max*sizeof(char *)); omMarkAsStaticAddr(fe_hist); fe_hist_pos=0; } else { fe_stdin_is_tty=0; fe_echo=stdout; } } /* delete to end of line */ static void fe_ctrl_k(char *s,int i) { int j=i; while(s[j]!='\0') { fputc(' ',fe_echo); j++; } while(j>i) { fputc('\b',fe_echo); j--; } } /* delete the line */ static void fe_ctrl_u(char *s,int *i) { fe_ctrl_k(s,*i); while((*i)>0) { (*i)--; fputc('\b',fe_echo); fputc(' ',fe_echo); fputc('\b',fe_echo); } } /*2 * add s to the history * if s is no the previous one, duplicate it */ static void fe_add_hist(char *s) { if (s[0]!='\0') /* skip empty lines */ { /* compare this line*/ if (fe_hist_pos!=0) { if ((fe_hist[fe_hist_pos-1]!=NULL) && (strcmp(fe_hist[fe_hist_pos-1],s)==0)) return; } else { if ((fe_hist[fe_hist_max-1]!=NULL) && (strcmp(fe_hist[fe_hist_max-1],s)==0)) return; } /* normal case: enter a new line */ /* first free the slot at position fe_hist_pos */ if (fe_hist[fe_hist_pos]!=NULL) { omFree((ADDRESS)fe_hist[fe_hist_pos]); } /* and store a duplicate */ fe_hist[fe_hist_pos]=omStrDup(s); omMarkAsStaticAddr(fe_hist[fe_hist_pos]); /* increment fe_hist_pos in a circular manner */ fe_hist_pos++; if (fe_hist_pos==fe_hist_max) fe_hist_pos=0; } } static void fe_get_hist(char *s, int size, int *pos,int change, int incr) { if (change) fe_add_hist(s); do { (*pos)+=incr; if((*pos)>=fe_hist_max) (*pos)-=fe_hist_max; else if((*pos)<0) (*pos)+=fe_hist_max; } while (((*pos)!=0)&&(fe_hist[(*pos)]==NULL)); memset(s,0,size); if (fe_hist[(*pos)]!=NULL) { strncpy(s,fe_hist[(*pos)],size-2); } } static int fe_getchar() { char c='\0'; while (1!=read (STDIN_FILENO, &c, 1)); if (c == 033) { /* check for CSI */ c='\0'; while((-1 == read (STDIN_FILENO, &c, 1)) && (errno == EINTR)); if (c == '[') { /* get command character */ c='\0'; while((-1 == read (STDIN_FILENO, &c, 1)) && (errno == EINTR)); switch (c) { case 'D': /* left arrow key */ c = feCTRL('B')/*002*/; break; case 'C': /* right arrow key */ c = feCTRL('F')/*006*/; break; case 'A': /* up arrow key */ c = feCTRL('P')/*020*/; break; case 'B': /* down arrow key */ c = feCTRL('N')/*016*/; break; } } } return c; } static void fe_set_cursor(char *s,int i) { char tgoto_buf[40]; if (0)/*(fe_cursor_pos>1) && (i>0))*/ { /*fputs(tgoto(tgetstr("cm",&tgoto_buf),fe_cursor_pos-1,fe_cursor_line),fe_echo);*/ tputs( tgoto(tgetstr("cm",(char **)&tgoto_buf),fe_cursor_pos-1,fe_cursor_line), pagelength,fe_out_char); fputc(s[i-1],fe_echo); } else { /*fputs( tgoto(tgetstr("cm",&tgoto_buf),fe_cursor_pos,fe_cursor_line),fe_echo);*/ tputs(tgoto(tgetstr("cm",(char **)&tgoto_buf),fe_cursor_pos,fe_cursor_line), pagelength,fe_out_char); } fflush(fe_echo); } char * fe_fgets_stdin_fe(char *pr,char *s, int size) { if(!fe_is_initialized) fe_init(); if (fe_stdin_is_tty) { int h=fe_hist_pos; int change=0; char c; int i=0; if (fe_is_raw_tty==0) { fe_temp_set(); } fputs(pr,fe_echo); fflush(fe_echo); fe_cursor_pos=strlen(pr); /* prompt */ memset(s,0,size); loop { c=fe_getchar(); switch(c) { case feCTRL('M'): case feCTRL('J'): { fd_set fdset; struct timeval tv; int sel; fe_add_hist(s); i=strlen(s); if (i=colmax) { fe_set_cursor(s,i); } else { while(j>i) { fputc('\b',fe_echo); j--; } } } change=1; fflush(fe_echo); break; } case feCTRL('A'): /* move the cursor to the beginning of the line */ { if (i>=colmax-strlen(pr)) { while (i>=colmax-strlen(pr)) { i-=colmax; fe_cursor_line--; } i=0; fe_cursor_pos=strlen(pr); fe_set_cursor(s,i); } else { while(i>0) { i--; fputc('\b',fe_echo); } fe_cursor_pos=strlen(pr); } break; } case feCTRL('E'): /* move the cursor to the end of the line */ { while(s[i]!='\0') { fputc(s[i],fe_echo); i++; fe_cursor_pos++; if(fe_cursor_pos>=colmax) { fe_cursor_pos=0; if(fe_cursor_line!=(pagelength-1)) fe_cursor_line++; } } break; } case feCTRL('B'): /* move the cursor backward one character */ { if (i>0) { i--; fputc('\b',fe_echo); fe_cursor_pos--; if(fe_cursor_pos<0) { fe_cursor_pos=colmax-1; fe_cursor_line--; } } break; } case feCTRL('F'): /* move the cursor forward one character */ { if(s[i]!='\0') { fputc(s[i],fe_echo); i++; fe_cursor_pos++; if(fe_cursor_pos>=colmax) { fe_cursor_pos=0; if(fe_cursor_line!=(pagelength-1)) fe_cursor_line++; } } break; } case feCTRL('U'): /* delete entire input line */ { fe_ctrl_u(s,&i); fe_cursor_pos=strlen(pr); memset(s,0,size); change=1; break; } #if 0 case feCTRL('W'): /* test hist. */ { int i; PrintS("\nstart hist\n"); for(i=0;i"); else PrintS(" "); PrintS(fe_hist[i]); PrintLn(); } } Print("end hist, next_pos=%d\n",fe_hist_pos); break; } #endif case feCTRL('K'): /* delete up to the end of the line */ { fe_ctrl_k(s,i); memset(&(s[i]),'\0',size-i); /* s[i]='\0';*/ change=1; break; } case feCTRL('L'): /* redraw screen */ { char t_buf[40]; char *t=t_buf; fe_cursor_line=i/colmax; /*fputs(tgetstr("cl",&t),fe_echo);*/ tputs(tgetstr("cl",&t),pagelength,fe_out_char); fflush(fe_echo); fputs(pr,fe_echo); fputs(s,fe_echo); fe_set_cursor(s,i); break; } case feCTRL('P'): /* previous line */ { fe_ctrl_u(s,&i); fe_get_hist(s,size,&h,change,-1); while(s[i]!='\0') { fputc(s[i],fe_echo); i++; } fe_cursor_pos=strlen(pr)+i/*strlen(s)*/; change=0; break; } case feCTRL('N'): /* next line */ { fe_ctrl_u(s,&i); fe_get_hist(s,size,&h,change,1); while(s[i]!='\0') { fputc(s[i],fe_echo); i++; } fe_cursor_pos=strlen(pr)+i/*strlen(s)*/; change=0; break; } default: { if ((c>=' ')&&(c<=126)) { fputc (c,fe_echo); fe_cursor_pos++; if(fe_cursor_pos>=colmax) { fe_cursor_pos=0; if(fe_cursor_line!=(pagelength-1)) fe_cursor_line++; } if (s[i]!='\0') { /* shift by 1 to the right */ int j=i; int l; while ((s[j]!='\0')&&(ji) { s[j]=s[j-1]; j--; } /* display */ fwrite(s+i+1,l,1,fe_echo); fflush(fe_echo); /* set cursor */ if(fe_cursor_pos+l>=colmax) { while(fe_cursor_pos+l>=colmax) { fe_cursor_line--; l-=colmax; } fe_set_cursor(s,i); } else { while(l>0) { l--; fputc('\b',fe_echo); } } fflush(fe_echo); } if (i ",b,200); // if (!m_eof) break; // printf(">>%s<<\n",b); // } // // return 0; //} #endif /* ================================================================ */ #if defined(HAVE_DYN_RL) #include //#include //#include //#include //#include //#include //#include //#include #include typedef char **CPPFunction (); char *(*fe_filename_completion_function)(); /* 3 */ char *(* fe_readline) (); /* 4 */ void (*fe_add_history) (); /* 5 */ char ** fe_rl_readline_name; /* 6 */ char **fe_rl_line_buffer; /* 7 */ char **(*fe_completion_matches)(); /* 8 */ CPPFunction **fe_rl_attempted_completion_function; /* 9 */ FILE ** fe_rl_outstream; /* 10 */ int (*fe_write_history) (); /* 11 */ int (*fe_history_total_bytes) (); /* 12 */ void (*fe_using_history) (); /* 13 */ int (*fe_read_history) (); /* 14 */ void * fe_rl_hdl=NULL; char *command_generator (char *text, int state); /* Attempt to complete on the contents of TEXT. START and END show the * region of TEXT that contains the word to complete. We can use the * entire line in case we want to do some simple parsing. Return the * array of matches, or NULL if there aren't any. */ char ** singular_completion (char *text, int start, int end) { /* If this word is not in a string, then it may be a command to complete. Otherwise it may be the name of a file in the current directory. */ char **m; if ((*fe_rl_line_buffer)[start-1]=='"') return (*fe_completion_matches) (text, *fe_filename_completion_function); m=(*fe_completion_matches) (text, command_generator); if (m==NULL) { m=(char **)malloc(2*sizeof(char*)); m[0]=(char *)malloc(end-start+2); strncpy(m[0],text,end-start+1); m[1]=NULL; } return m; } int fe_init_dyn_rl() { int res=0; loop { fe_rl_hdl=dynl_open("libreadline.so"); if (fe_rl_hdl==NULL) fe_rl_hdl=dynl_open("libreadline.so.2"); if (fe_rl_hdl==NULL) fe_rl_hdl=dynl_open("libreadline.so.3"); if (fe_rl_hdl==NULL) fe_rl_hdl=dynl_open("libreadline.so.4"); if (fe_rl_hdl==NULL) fe_rl_hdl=dynl_open("libreadline.so.5"); if (fe_rl_hdl==NULL) fe_rl_hdl=dynl_open("libreadline.so.6"); if (fe_rl_hdl==NULL) fe_rl_hdl=dynl_open("libreadline.so.7"); if (fe_rl_hdl==NULL) { return 1;} fe_filename_completion_function= dynl_sym(fe_rl_hdl, "filename_completion_function"); if (fe_filename_completion_function==NULL) { res=3; break; } fe_readline=dynl_sym(fe_rl_hdl,"readline"); if (fe_readline==NULL) { res=4; break; } fe_add_history=dynl_sym(fe_rl_hdl,"add_history"); if (fe_add_history==NULL) { res=5; break; } fe_rl_readline_name=(char**)dynl_sym(fe_rl_hdl,"rl_readline_name"); if (fe_rl_readline_name==NULL) { res=6; break; } fe_rl_line_buffer=(char**)dynl_sym(fe_rl_hdl,"rl_line_buffer"); if (fe_rl_line_buffer==NULL) { res=7; break; } fe_completion_matches=dynl_sym(fe_rl_hdl,"completion_matches"); if (fe_completion_matches==NULL) { res=8; break; } fe_rl_attempted_completion_function= dynl_sym(fe_rl_hdl,"rl_attempted_completion_function"); if (fe_rl_attempted_completion_function==NULL) { res=9; break; } fe_rl_outstream=(FILE**)dynl_sym(fe_rl_hdl,"rl_outstream"); if (fe_rl_outstream==NULL) { res=10; break; } fe_write_history=dynl_sym(fe_rl_hdl,"write_history"); if (fe_write_history==NULL) { res=11; break; } fe_history_total_bytes=dynl_sym(fe_rl_hdl,"history_total_bytes"); if (fe_history_total_bytes==NULL) { res=12; break; } fe_using_history=dynl_sym(fe_rl_hdl,"using_history"); if (fe_using_history==NULL) { res=13; break; } fe_read_history=dynl_sym(fe_rl_hdl,"read_history"); if (fe_read_history==NULL) { res=14; break; } return 0; } dynl_close(fe_rl_hdl); if (res==0) { char *p; /* more init stuff: */ /* Allow conditional parsing of the ~/.inputrc file. */ (*fe_rl_readline_name) = "Singular"; /* Tell the completer that we want a crack first. */ (*fe_rl_attempted_completion_function) = (CPPFunction *)singular_completion; /* try to read a history */ (*fe_using_history)(); p = getenv("SINGULARHIST"); if (p != NULL) { (*fe_read_history) (p); } } return res; } #endif /* ===================================================================*/ /* = fe_reset_input_mode (all possibilities) = */ /* ===================================================================*/ #if defined(HAVE_READLINE) && !defined(HAVE_FEREAD) && !defined(HAVE_DYN_RL) extern int history_total_bytes(); extern int write_history (const char *); #endif void fe_reset_input_mode () { #if defined(HAVE_DYN_RL) char *p = getenv("SINGULARHIST"); if ((p != NULL) && (fe_history_total_bytes != NULL)) { if((*fe_history_total_bytes)()!=0) (*fe_write_history) (p); } #endif #if defined(HAVE_READLINE) && !defined(HAVE_FEREAD) && !defined(HAVE_DYN_RL) char *p = getenv("SINGULARHIST"); if (p != NULL) { if(history_total_bytes()!=0) write_history (p); } #endif #if defined(HAVE_FEREAD) #ifndef HAVE_ATEXIT fe_reset_fe(NULL,NULL); #else fe_reset_fe(); #endif #endif }