/* File: intrfn.c Copyright (C) 1998-2009 Christophe GRENIER This software is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifdef HAVE_CONFIG_H #include #endif #if defined(DISABLED_FOR_FRAMAC) #undef HAVE_NCURSES #endif #include #if defined(HAVE_NCURSES) #include #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #include #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #ifdef HAVE_SYS_SELECT_H #include #endif #ifdef HAVE_SYS_STAT_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_SYS_CYGWIN_H #include #endif #ifdef HAVE_LIBGEN_H #include #endif #include #include "types.h" #include "common.h" #include "lang.h" #include "intrf.h" #include "intrfn.h" #include "list.h" #include "dir.h" #include "log.h" #include "hdaccess.h" #include "autoset.h" extern char intr_buffer_screen[MAX_LINES][BUFFER_LINE_LENGTH+1]; extern int intr_nbr_line; #define MINIMUM_LINES 24 #define COLUMNS 80 /* Use COLS (actual number of columns) or COLUMNS (number of columns the program has been designed for) ? */ #define INTER_DIR (LINES+16-25) #define GS_DEFAULT -1 #define GS_key_ESCAPE -2 static int wmenuUpdate(WINDOW *window, const int yinfo, int y, int x, const struct MenuItem *menuItems, const unsigned int itemLength, const char *available, const int menuType, unsigned int current); static int wgetch_nodelay(WINDOW *window); int get_string(WINDOW *window, char *str, const int len, const char *def) { int c; int i = 0; int x, y; int use_def = FALSE; curs_set(1); getyx(window, y, x); str[0] = 0; if (def != NULL) { mvwaddstr(window,y, x, def); wmove(window,y, x); use_def = TRUE; } wrefresh(window); while ((c = wgetch(window)) != '\n' && c != key_CR #ifdef PADENTER && c!= PADENTER #endif ) { switch (c) { /* escape is generated by enter from keypad */ /* case key_ESC: wmove(window,y, x); wclrtoeol(window); curs_set(0); wrefresh(window); return GS_key_ESCAPE; */ case KEY_DC: case KEY_BACKSPACE: if (i > 0) { str[--i] = 0; mvwaddch(window, y, x+i, ' '); wmove(window,y, x+i); } else if (use_def) { wclrtoeol(window); use_def = FALSE; } break; default: if (i < len && isprint(c)) { mvwaddch(window, y, x+i, c); if (use_def) { wclrtoeol(window); use_def = FALSE; } str[i++] = c; str[i] = 0; } } wrefresh(window); } curs_set(0); wrefresh(window); if (use_def) return GS_DEFAULT; else return i; } static int wgetch_nodelay(WINDOW *window) { int res; nodelay(window,TRUE); res=wgetch(window); nodelay(window,FALSE); return res; } /* * Actual function which prints the button bar and highlights the active button * Should not be called directly. Call function menuSelect instead. */ static int wmenuUpdate(WINDOW *window, const int yinfo, int y, int x, const struct MenuItem *menuItems, const unsigned int itemLength, const char *available, const int menuType, unsigned int current) { unsigned int i; const unsigned int lmargin = x; const unsigned int ymargin = y; unsigned int lenNameMax=0; for( i = 0; menuItems[i].key!=0; i++ ) if(strchr(available, menuItems[i].key)!=NULL ) { const unsigned int lenName = strlen( menuItems[i].name ); if(lenNameMax=sizeof(buff)) { log_critical("\nBUG: %s\n",mi); } if(lenName >= itemLength) { if( menuType & MENU_BUTTON ) snprintf(buff, sizeof(buff)," [%s]",mi); else snprintf(buff, sizeof(buff)," %s",mi); } else { if( menuType & MENU_BUTTON ) { if(menuType & MENU_VERT) snprintf( buff, sizeof(buff)," [%*s%-*s]", (itemLength - lenNameMax) / 2, "", (itemLength - lenNameMax + 1) / 2 + lenNameMax, mi ); else snprintf( buff, sizeof(buff)," [%*s%-*s]", (itemLength - lenName) / 2, "", (itemLength - lenName + 1) / 2 + lenName, mi ); } else snprintf( buff, sizeof(buff)," %*s%-*s", (itemLength - lenName) / 2, "", (itemLength - lenName + 1) / 2 + lenName, mi ); } /* If current item is selected, highlight it */ if( current == i ) { wattrset(window, A_REVERSE); buff[0]='>'; } /* Print item */ mvwaddstr(window, y, x, buff ); /* Lowlight after selected item */ if( current == i ) { wattroff(window, A_REVERSE); } if(menuType & MENU_VERT_WARN) mvwaddstr(window, y, x+itemLength+4, menuItems[i].desc); /* Calculate position for the next item */ if( menuType & MENU_VERT ) { y += 1; if( y >= yinfo - 1) { y = ymargin; x += (lenName < itemLength?itemLength:lenName) + MENU_SPACING; if( menuType & MENU_BUTTON ) x += 2; } } else { x += (lenName < itemLength?itemLength:lenName) + MENU_SPACING; if( menuType & MENU_BUTTON ) x += 2; if( x + lmargin + 12 > COLUMNS ) { x = lmargin; y ++ ; } } } /* Print the description of selected item */ if(!(menuType & MENU_VERT_WARN)) { const char *mcd = menuItems[current].desc; mvwaddstr(window, yinfo, (COLUMNS - strlen( mcd )) / 2, mcd ); } return y; } /* This function takes a list of menu items, lets the user choose one * * and returns the value keyboard shortcut of the selected menu item */ int wmenuSelect(WINDOW *window, const int yinfo, const int y, const int x, const struct MenuItem *menuItems, const unsigned int itemLength, const char *available, const int menuType, const unsigned int menuDefault) { unsigned int current=menuDefault; return wmenuSelect_ext(window, yinfo, y, x, menuItems, itemLength, available, menuType, ¤t, NULL); } int wmenuSelect_ext(WINDOW *window, const int yinfo, const int y, const int x, const struct MenuItem *menuItems, const unsigned int itemLength, const char *available, const int menuType, unsigned int *current, int *real_key) { unsigned int i; unsigned int ylast = y; int key = 0; /* if( ( menuType & ( MENU_HORIZ | MENU_VERT ) )==0 ) { wprintw(window,"Menu without direction. Defaulting horizontal."); menuType |= MENU_HORIZ; } */ /* Warning: current may be out of bound, not checked */ /* Make sure that the current is one of the available items */ while(strchr(available, menuItems[*current].key)==NULL) { (*current)++ ; if( menuItems[*current].key==0 ) { *current = 0; } } /* Repeat until allowable choice has been made */ while( key==0 ) { /* Display the menu */ ylast = wmenuUpdate( window, yinfo, y, x, menuItems, itemLength, available, menuType, *current ); wrefresh(window); /* Don't put wgetch after the following wclrtoeol */ key = wgetch(window); if(real_key!=NULL) *real_key=key; /* Clear out all prompts and such */ for( i = y; i < ylast; i ++ ) { wmove(window, i, x ); wclrtoeol(window); } wmove(window, yinfo, 0 ); wclrtoeol(window); if(strchr(available, key)==NULL) { if(key=='2') key=KEY_DOWN; else if(key=='4') key=KEY_LEFT; else if(key=='5') key=KEY_ENTER; else if(key=='6') key=KEY_RIGHT; else if(key=='8') key=KEY_UP; } /* Cursor keys */ switch(key) { case KEY_UP: if( (menuType & MENU_VERT)!=0 ) { do { if( (*current)-- == 0 ) { while( menuItems[(*current)+1].key ) (*current) ++ ; } } while( strchr( available, menuItems[*current].key )==NULL ); key = 0; } break; case KEY_DOWN: if( (menuType & MENU_VERT)!=0 ) { do { (*current) ++ ; if( menuItems[*current].key==0 ) *current = 0 ; } while( strchr( available, menuItems[*current].key )==NULL ); key = 0; } break; case KEY_RIGHT: if( (menuType & MENU_HORIZ)!=0 ) { do { (*current) ++ ; if( menuItems[*current].key==0 ) { *current = 0 ; } } while( strchr( available, menuItems[*current].key )==NULL ); key = 0; } break; case KEY_LEFT: if( (menuType & MENU_HORIZ) !=0) { do { if( (*current)-- == 0 ) { while( menuItems[(*current) + 1].key ) (*current) ++ ; } } while( strchr( available, menuItems[*current].key )==NULL ); key = 0; } break; } /* Enter equals to the keyboard shortcut of current menu item */ if((key==13) || (key==10) || (key==KEY_ENTER) || (((menuType & MENU_VERT) != 0) && ((menuType & MENU_VERT_ARROW2VALID) != 0) && (key==KEY_RIGHT || key==KEY_LEFT))) key = menuItems[*current].key; #ifdef PADENTER if(key==PADENTER) key = menuItems[*current].key; #endif /* Is pressed key among acceptable ones */ if( key!=0 && (strchr(available, toupper(key))!=NULL || strchr(available, key)!=NULL)) { const unsigned int old_current=*current; for(i=0; menuItems[i].key != 0 && menuItems[i].key != key; i++); *current=(menuItems[i].key == 0 ? old_current : i); break; } /* Should all keys to be accepted? */ if( key && (menuType & MENU_ACCEPT_OTHERS)!=0 ) break; /* The key has not been accepted so far -> let's reject it */ #ifdef DEBUG if( key ) { wmove(window,5,0); wprintw(window,"key %03X",key); putchar( BELL ); } #endif key = 0; } /* Clear out prompts and such */ for( i = y; i <= ylast; i ++ ) { wmove(window, i, x ); wclrtoeol(window); } wmove(window, yinfo, 0 ); wclrtoeol(window); return key; } /* Function menuSelect takes way too many parameters * * Luckily, most of time we can do with this function */ int wmenuSimple(WINDOW *window,const struct MenuItem *menuItems, const unsigned int menuDefault) { unsigned int i, itemLength = 0; char available[MENU_MAX_ITEMS]; for(i = 0; menuItems[i].key; i++) { const unsigned int j = strlen(menuItems[i].name); if( j > itemLength ) itemLength = j; available[i] = menuItems[i].key; } available[i] = 0; return wmenuSelect(window, 23, 18, 0, menuItems, itemLength, available, MENU_HORIZ | MENU_BUTTON, menuDefault); } /* End of command menu support code */ uint64_t ask_number(const uint64_t val_cur, const uint64_t val_min, const uint64_t val_max, const char * _format, ...) { char res[200]; char res2[200]; char response[128]; char def[128]; va_list ap; va_start(ap,_format); vsnprintf(res,sizeof(res),_format,ap); if(val_min!=val_max) snprintf(res2,sizeof(res2),"(%llu-%llu) :", (long long unsigned)val_min, (long long unsigned)val_max); else res2[0]='\0'; va_end(ap); waddstr(stdscr, res); waddstr(stdscr, res2); wclrtoeol(stdscr); sprintf(def, "%llu", (long long unsigned)val_cur); if (get_string(stdscr, response, sizeof(response), def) > 0) { const uint64_t tmp_val = atouint64(response); if (val_min==val_max || (tmp_val >= val_min && tmp_val <= val_max)) return tmp_val; } return val_cur; } void dump_ncurses(const void *nom_dump, unsigned int lng) { WINDOW *window=newwin(LINES, COLS, 0, 0); /* full screen */ keypad(window, TRUE); /* Need it to get arrow key */ aff_copy(window); dump(window, nom_dump, lng); dump_log(nom_dump,lng); delwin(window); (void) clearok(stdscr, TRUE); #ifdef HAVE_TOUCHWIN touchwin(stdscr); #endif } #define DUMP_MAX_LINES (LINES+15-25) #define DUMP_X 0 #define DUMP_Y 7 #define INTER_DUMP_X DUMP_X #define INTER_DUMP_Y (LINES+23-25) void dump(WINDOW *window, const void *nom_dump,unsigned int lng) { unsigned int nbr_line; unsigned int pos=0; int done=0; unsigned int menu=2; /* default : quit */ const char *options="PNQ"; const struct MenuItem menuDump[]= { { 'P', "Previous",""}, { 'N', "Next","" }, { 'Q',"Quit","Quit dump section"}, { 0, NULL, NULL } }; nbr_line=(lng+0x10-1)/0x10; if(nbr_line <= (unsigned)DUMP_MAX_LINES) { options="Q"; } /* ncurses interface */ mvwaddstr(window,DUMP_Y,DUMP_X,msg_DUMP_HEXA); /* On pourrait utiliser wscrl */ do { unsigned char car; unsigned int i,j; for (i=pos; i= 127)) wprintw(window,"."); else wprintw(window,"%c", car); } else wprintw(window," "); } } switch (wmenuSelect(window, INTER_DUMP_Y+1, INTER_DUMP_Y, INTER_DUMP_X, menuDump, 8, options, MENU_HORIZ | MENU_BUTTON | MENU_ACCEPT_OTHERS, menu)) { case 'p': case 'P': case KEY_UP: if(strchr(options,'N')!=NULL) { menu=0; if(pos>0) pos--; } break; case 'n': case 'N': case KEY_DOWN: if(strchr(options,'N')!=NULL) { menu=1; if(pos (unsigned)(DUMP_MAX_LINES-1)) pos-=DUMP_MAX_LINES-1; else pos=0; } break; case KEY_NPAGE: if(strchr(options,'N')!=NULL) { menu=1; if(pos= 127)) wprintw(window,"."); else wprintw(window,"%c", car1); if(car1!=car2) wattroff(window, A_REVERSE); } else wprintw(window," "); } wprintw(window," "); for(j=0; j<0x08;j++) { if(i*0x08+j= 127)) wprintw(window,"."); else wprintw(window,"%c", car2); if(car1!=car2) wattroff(window, A_REVERSE); } else wprintw(window," "); } } switch (wmenuSelect(window, INTER_DUMP_Y+1, INTER_DUMP_Y, INTER_DUMP_X, menuDump, 8, options, MENU_HORIZ | MENU_BUTTON | MENU_ACCEPT_OTHERS, menu)) { case 'p': case 'P': case KEY_UP: if(strchr(options,'N')!=NULL) { menu=0; if(pos>0) pos--; } break; case 'n': case 'N': case KEY_DOWN: if(strchr(options,'N')!=NULL) { menu=1; if(pos (unsigned)(DUMP_MAX_LINES-1)) pos-=DUMP_MAX_LINES-1; else pos=0; } break; case KEY_NPAGE: if(strchr(options,'N')!=NULL) { menu=1; if(pos0) wprintw(window, "Previous"); if(intr_nbr_line>INTER_MAX_LINES && has_colors()) { for (i=first_line_to_display; i%-*s", COLS, intr_buffer_screen[i]); wattroff(window, A_REVERSE); } else wprintw(window, " %-*s", COLS, intr_buffer_screen[i]); } } else { for (i=first_line_to_display; i0) current_line--; break; case 'n': case 'N': case KEY_DOWN: if(current_lineINTER_MAX_LINES-1) current_line-=INTER_MAX_LINES-1; else current_line=0; break; case KEY_NPAGE: if(current_line+INTER_MAX_LINES-1 < intr_nbr_line-1) current_line+=INTER_MAX_LINES-1; else current_line=intr_nbr_line-1; break; default: if(strchr(options,toupper(key))!=NULL) return toupper(key); break; } if(current_line=first_line_to_display+INTER_MAX_LINES) first_line_to_display=current_line-INTER_MAX_LINES+1; } while(done!=TRUE); return 0; } void aff_part(WINDOW *window,const unsigned int newline,const disk_t *disk_car,const partition_t *partition) { const char *msg; msg=aff_part_aux(newline, disk_car, partition); wprintw(window,"%s",msg); } void aff_LBA2CHS(const disk_t *disk_car, const unsigned long int pos_LBA) { unsigned long int tmp; unsigned long int cylinder, head, sector; tmp=disk_car->geom.sectors_per_head; sector=(pos_LBA%tmp)+1; tmp=pos_LBA/tmp; cylinder=tmp / disk_car->geom.heads_per_cylinder; head=tmp % disk_car->geom.heads_per_cylinder; wprintw(stdscr, "%lu/%lu/%lu", cylinder, head, sector); } int ask_YN(WINDOW *window) { int res; curs_set(1); wrefresh(window); do { res=toupper(wgetch(window)); } while(res!=c_NO && res!=c_YES); curs_set(0); wprintw(window,"%c\n",res); return (res==c_YES); } int ask_confirmation(const char*_format, ...) { va_list ap; int res; WINDOW *window=newwin(LINES, COLS, 0, 0); /* full screen */ aff_copy(window); va_start(ap,_format); vaff_txt(4, window, _format, ap); va_end(ap); res=ask_YN(window); wmove(window, 4, 0); wclrtoeol(window); wrefresh(window); delwin(window); (void) clearok(stdscr, TRUE); #ifdef HAVE_TOUCHWIN touchwin(stdscr); #endif return res; } void not_implemented(const char *msg) { WINDOW *window=newwin(LINES, COLS, 0, 0); /* full screen */ aff_copy(window); wmove(window,7,0); wprintw(window,"Function %s not implemented",msg); log_warning("Function %s not implemented\n",msg); wmove(window,22,0); wattrset(window, A_REVERSE); wprintw(window,"[ Abort ]"); wattroff(window, A_REVERSE); wrefresh(window); while(wgetch(window)==ERR); delwin(window); (void) clearok(stdscr, TRUE); #ifdef HAVE_TOUCHWIN touchwin(stdscr); #endif } #if defined(DJGPP) || defined(__MINGW32__) #else static SCREEN *screenp=NULL; static void get_newterm_aux(void) { if((screenp=newterm(NULL,stdout,stdin))!=NULL) return ; #if defined(TARGET_BSD) if((screenp=newterm("cons25",stdout,stdin))!=NULL) return ; #elif defined(TARGET_LINUX) if((screenp=newterm("linux",stdout,stdin))!=NULL) return ; #elif defined(__CYGWIN__) if((screenp=newterm("cygwin",stdout,stdin))!=NULL) return ; #elif defined(__OS2__) if((screenp=newterm("ansi",stdout,stdin))!=NULL) return ; #elif defined(__APPLE__) if((screenp=newterm("xterm-color",stdout,stdin))!=NULL) return ; #endif } static void get_newterm(const char *prog_name) { char *tmp; char *dirs; char *dirname_prog; get_newterm_aux(); if(screenp!=NULL) return ; #ifdef HAVE_SETENV /* NCurses 5.9 caches the env variables during 1s, so sleep to avoid this cache */ #if defined(NCURSES_VERSION_MAJOR) && defined(NCURSES_VERSION_MINOR) && (NCURSES_VERSION_MAJOR > 5 || (NCURSES_VERSION_MAJOR == 5 && NCURSES_VERSION_MINOR>7)) sleep(2); #endif tmp=strdup(prog_name); dirname_prog= dirname(tmp); dirs=(char *)MALLOC(strlen(dirname_prog)+2+1); #if defined(TARGET_LINUX) sprintf(dirs, "%s:./", dirname_prog); #else sprintf(dirs, "%s:.", dirname_prog); #endif setenv("TERMINFO_DIRS", dirs, 1); get_newterm_aux(); free(dirs); free(tmp); if(screenp!=NULL) return ; unsetenv("TERMINFO_DIRS"); #endif } #endif int start_ncurses(const char *prog_name, const char *real_prog_name) { #if defined(DJGPP) || defined(__MINGW32__) if(initscr()==NULL) { log_critical("initscr() has failed. Exiting\n"); printf("initscr() has failed. Exiting\n"); printf("Press Enter key to quit.\n"); (void)getchar(); return 1; } #else get_newterm(real_prog_name); if(screenp==NULL) { log_critical("Terminfo file is missing.\n"); #if defined(__CYGWIN__) printf("The terminfo file '63\\cygwin' is missing.\n"); #else printf("Terminfo file is missing.\n"); #endif printf("Extract all files and subdirectories before running the program.\n"); printf("Press Enter key to quit.\n"); (void)getchar(); return 1; } #endif /* Should solve a problem with users who redefined the colors */ if(has_colors()) { start_color(); #ifdef HAVE_ASSUME_DEFAULT_COLORS assume_default_colors(COLOR_WHITE,COLOR_BLACK); #endif init_pair(1, COLOR_RED, COLOR_BLACK); init_pair(2, COLOR_GREEN, COLOR_BLACK); } noecho(); #ifndef DJGPP nonl(); /*don't use for Dos version but enter will work with it... dilema */ #endif /* intrflush(stdscr, FALSE); */ cbreak(); curs_set(0); { int quit=0; while(LINES>=8 && LINES 0) return response; return NULL; } int check_enter_key_or_s(WINDOW *window) { switch(wgetch_nodelay(window)) { case KEY_ENTER: #ifdef PADENTER case PADENTER: #endif case '\n': case '\r': case 's': case 'S': return 1; case 'F': return 2; case '+': return 3; } return 0; } void screen_buffer_to_interface(void) { { int i; const int pos=intr_nbr_line-DUMP_MAX_LINES<0?0:intr_nbr_line-DUMP_MAX_LINES; if(intr_nbr_lineend && end-i 0) { min_size = strtoull(response, NULL, 10); } wborder(local_win, ' ', ' ', ' ',' ',' ',' ',' ',' '); wrefresh(local_win); delwin(local_win); return min_size; } const char *ask_string_ncurses(const char *string) { WINDOW *local_win; const int height = 3; const int width = 60; const int starty = (LINES - height) / 2; /* Calculating for a center placement */ const int startx = (COLS - width) / 2; /* of the window */ static char response[128]; local_win = newwin(height, width, starty, startx); keypad(local_win, TRUE); /* Need it to get arrow key */ box(local_win, 0 , 0); /* 0, 0 gives default characters * for the vertical and horizontal * lines */ wmove(local_win,1,1); waddstr(local_win, string); wrefresh(local_win); /* Show that box */ get_string(local_win, response, 120, NULL); wborder(local_win, ' ', ' ', ' ',' ',' ',' ',' ',' '); wrefresh(local_win); delwin(local_win); return &response[0]; } const char *td_curses_version(void) { static char curses_version_string[512]; #ifdef NCURSES_VERSION snprintf(curses_version_string, sizeof(curses_version_string), "ncurses %s", NCURSES_VERSION); return curses_version_string; #elif defined(PDC_BUILD) snprintf(curses_version_string, sizeof(curses_version_string), "pdcurses build %u", PDC_BUILD); return curses_version_string; #else return "unknown version"; #endif } #else #include "log.h" #include "intrfn.h" const char *td_curses_version(void) { return "None"; } void display_message(const char*msg) { log_info("%s",msg); } #endif