#ifndef NO_POSIX_SOURCE #undef _POSIX_SOURCE #define _POSIX_SOURCE 1 #undef _POSIX_C_SOURCE #define _POSIX_C_SOURCE 2 #endif #include #include #include #include #include #ifdef ENABLE_UTF8 #include #else #include #endif #include #include #include #include #include #include #include #include #ifdef NEED_BCOPY #define memmove(dst,src,len) bcopy(src,dst,len) #endif #ifdef OLD_REALLOC #define realloc(s,l) myrealloc(s,l) #endif #ifdef DMALLOC #include "dmalloc.h" #endif #include "complete.h" #include "default.h" #include "display.h" #include "eval.h" #include "main.h" #include "misc.h" #include "sheet.h" #include "utf8.h" static Key wgetc(void); /* redraw -- redraw whole screen */ static void redraw(void) { (void)touchwin(curscr); (void)wrefresh(curscr); } /* do_attribute -- set cell attributes */ static int do_attribute(Sheet *cursheet) { MenuChoice mainmenu[5]; MenuChoice adjmenu[11]; int c; /* create menus */ adjmenu[0].str=mystrmalloc(_("lL)eft")); adjmenu[0].c='\0'; adjmenu[1].str=mystrmalloc(_("rR)ight")); adjmenu[1].c='\0'; adjmenu[2].str=mystrmalloc(_("cC)entered")); adjmenu[2].c='\0'; adjmenu[3].str=mystrmalloc(_("11).23e1 <-> 12.3")); adjmenu[3].c='\0'; adjmenu[4].str=mystrmalloc(_("pP)recision")); adjmenu[4].c='\0'; adjmenu[5].str=mystrmalloc(_("sS)hadow")); adjmenu[5].c='\0'; adjmenu[6].str=mystrmalloc(_("bB)old")); adjmenu[6].c='\0'; adjmenu[7].str=mystrmalloc(_("uU)nderline")); adjmenu[7].c='\0'; adjmenu[8].str=mystrmalloc(_("oO)utput special characters")); adjmenu[8].c='\0'; adjmenu[9].str=(char*)0; mainmenu[0].str=mystrmalloc(_("rR)epresentation")); mainmenu[0].c='\0'; mainmenu[1].str=mystrmalloc(_("lL)abel")); mainmenu[1].c='\0'; mainmenu[2].str=mystrmalloc(_("oLo)ck")); mainmenu[2].c='\0'; mainmenu[3].str=mystrmalloc(_("iI)gnore")); mainmenu[3].c='\0'; mainmenu[4].str=(char*)0; do { c = line_menu(cursheet->mark1x==-1 ? _("Cell attribute:") : _("Block attribute:"),mainmenu,0); if (cursheet->mark1x==-1 && c!=2 && locked(cursheet,cursheet->curx,cursheet->cury,cursheet->curz)) line_msg(_("Cell attribute:"),_("Cell is locked")); else { switch (c) { case -2: case -1: c = KEY_CANCEL; break; case 0: { switch (c=line_menu(cursheet->mark1x==-1 ? _("Cell attribute:") : _("Block attribute:"),adjmenu,0)) { case -2: case -1: c = K_INVALID; break; case 0: c = ADJUST_LEFT; break; case 1: c = ADJUST_RIGHT; break; case 2: c = ADJUST_CENTER; break; case 3: c = ADJUST_SCIENTIFIC; break; case 4: c = ADJUST_PRECISION; break; case 5: c = ADJUST_SHADOW; break; case 6: c = ADJUST_BOLD; break; case 7: c = ADJUST_UNDERLINE; break; case 8: c = ADJUST_TRANSPARENT; break; default: assert(0); } break; } case 1: c = ADJUST_LABEL; break; case 2: c = ADJUST_LOCK; break; case 3: c = ADJUST_IGNORE; break; default: assert(0); } } } while (c == K_INVALID); if (c == KEY_CANCEL) c = K_INVALID; /* free menus */ free(mainmenu[0].str); free(mainmenu[1].str); free(mainmenu[2].str); free(mainmenu[3].str); free(adjmenu[0].str); free(adjmenu[1].str); free(adjmenu[2].str); free(adjmenu[3].str); free(adjmenu[4].str); free(adjmenu[5].str); free(adjmenu[6].str); free(adjmenu[7].str); free(adjmenu[8].str); return c; } /* do_file -- file menu */ static int do_file(Sheet *cursheet) { MenuChoice menu[4]; int c; menu[0].str=mystrmalloc(_("lL)oad")); menu[0].c='\0'; menu[1].str=mystrmalloc(_("sS)ave")); menu[1].c='\0'; menu[2].str=mystrmalloc(_("nN)ame")); menu[2].c='\0'; menu[3].str=(char*)0; c=0; do { switch (c=line_menu(_("File:"),menu,0)) { case -2: case -1: c = KEY_CANCEL; break; case 0: c = K_LOADMENU; break; case 1: c = K_SAVEMENU; break; case 2: c = K_NAME; break; default: assert(0); } } while (c == K_INVALID); if (c == KEY_CANCEL) c = K_INVALID; free(menu[0].str); free(menu[1].str); free(menu[2].str); return c; } /* do_shell -- spawn a shell */ static int do_shell(void) { pid_t pid; struct sigaction interrupt; refresh(); interrupt.sa_flags=0; sigemptyset(&interrupt.sa_mask); interrupt.sa_handler=SIG_IGN; sigaction(SIGINT,&interrupt,(struct sigaction *)0); sigaction(SIGQUIT,&interrupt,(struct sigaction *)0); switch (pid=fork()) { /* -1 */ case -1: line_msg(_("Spawn sub shell"),strerror(errno)); break; /* 0 */ case 0: { const char *shell; if ((shell=getenv("SHELL"))==(const char*)0) { struct passwd *pwd; if ((pwd=getpwuid(getuid()))==(struct passwd*)0) { shell="/bin/sh"; } else { shell=pwd->pw_shell; } } line_msg((const char*)0,_("Sub shell started")); move(LINES-1,0); curs_set(1); refresh(); reset_shell_mode(); puts("\n"); interrupt.sa_handler=SIG_DFL; sigaction(SIGINT,&interrupt,(struct sigaction *)0); sigaction(SIGQUIT,&interrupt,(struct sigaction *)0); execl(shell,shell,(const char*)0); exit(127); break; } /* default */ default: { pid_t r; int status; while ((r=wait(&status))!=-1 && r!=pid); reset_prog_mode(); interrupt.sa_handler=SIG_DFL; sigaction(SIGINT,&interrupt,(struct sigaction *)0); sigaction(SIGQUIT,&interrupt,(struct sigaction *)0); clear(); refresh(); curs_set(0); redraw(); } } return -1; } /* do_block -- block menu */ static int do_block(Sheet *cursheet) { MenuChoice block[9]; int c; block[0].str=mystrmalloc(_("ecle)ar")); block[0].c='\0'; block[1].str=mystrmalloc(_("iI)nsert")); block[1].c='\0'; block[2].str=mystrmalloc(_("dD)elete")); block[2].c='\0'; block[3].str=mystrmalloc(_("mM)ove")); block[3].c='\0'; block[4].str=mystrmalloc(_("cC)opy")); block[4].c='\0'; block[5].str=mystrmalloc(_("fF)ill")); block[5].c='\0'; block[6].str=mystrmalloc(_("sS)ort")); block[6].c='\0'; block[7].str=mystrmalloc(_("rMir)ror")); block[7].c='\0'; block[8].str=(char*)0; c=0; do { switch (c=line_menu(_("Block menu:"),block,0)) { case -2: case -1: c = KEY_CANCEL; break; case 0: c = BLOCK_CLEAR; break; case 1: c = BLOCK_INSERT; break; case 2: c = BLOCK_DELETE; break; case 3: c = BLOCK_MOVE; break; case 4: c = BLOCK_COPY; break; case 5: c = BLOCK_FILL; break; case 6: c = BLOCK_SORT; break; case 7: c = BLOCK_MIRROR; break; } } while (c == K_INVALID); if (c == KEY_CANCEL) c = K_INVALID; free(block[0].str); free(block[1].str); free(block[2].str); free(block[3].str); free(block[4].str); free(block[5].str); free(block[6].str); free(block[7].str); return c; } int show_menu(Sheet *cursheet) { MenuChoice menu[9]; int c = K_INVALID; menu[0].str=mystrmalloc(_("aA)ttributes")); menu[0].c='\0'; menu[1].str=mystrmalloc(_("wW)idth")); menu[1].c='\0'; menu[2].str=mystrmalloc(_("bB)lock")); menu[2].c='\0'; menu[3].str=mystrmalloc(_("fF)ile")); menu[3].c='\0'; menu[4].str=mystrmalloc(_("gG)oto")); menu[4].c='\0'; menu[5].str=mystrmalloc(_("sS)hell")); menu[5].c='\0'; menu[6].str=mystrmalloc(_("vV)ersion")); menu[6].c='\0'; menu[7].str=mystrmalloc(_("qQ)uit")); menu[7].c='\0'; menu[8].str=(char*)0; do { switch (c=line_menu(_("Main menu:"),menu,0)) { case -2: case -1: c = KEY_CANCEL; break; case 0: c = do_attribute(cursheet); break; case 1: c = K_COLWIDTH; break; case 2: c = do_block(cursheet); break; case 3: c = do_file(cursheet); break; case 4: c = K_GOTO; break; case 5: do_shell(); c = KEY_CANCEL; break; case 6: c = K_ABOUT; break; case 7: c = K_QUIT; break; default: assert(0); } } while (c == K_INVALID); if (c == KEY_CANCEL) c = K_INVALID; free(menu[0].str); free(menu[1].str); free(menu[2].str); free(menu[3].str); free(menu[4].str); free(menu[5].str); free(menu[6].str); free(menu[7].str); return c; } /* do_bg -- background teapot */ static void do_bg(void) { struct termios t; if (tcgetattr(0,&t)==0 && t.c_cc[VSUSP]!=_POSIX_VDISABLE) { line_msg((const char*)0,_("Teapot stopped")); move(LINES-1,0); curs_set(1); refresh(); reset_shell_mode(); puts("\n"); kill(getpid(),SIGSTOP); clear(); refresh(); reset_prog_mode(); curs_set(0); } else line_msg((const char*)0,_("The susp character is undefined")); } void display_main(Sheet *cursheet) { Key k; int quit = 0; cursheet->maxx=COLS; cursheet->maxy=LINES-1; do { quit = 0; redraw_sheet(cursheet); k=wgetc(); wmove(stdscr,LINES-1,0); wclrtoeol(stdscr); switch ((int)k) { case KEY_SUSPEND: case '\032': do_bg(); k = K_INVALID; break; case '\014': redraw(); k = K_INVALID; break; case KEY_F(0): case KEY_F(10): k = show_menu(cursheet); break; } } while (k == K_INVALID || !do_sheetcmd(cursheet,k,0) || doanyway(cursheet,_("Sheet modified, leave anyway?"))!=1); } void display_init(Sheet *cursheet, int always_redraw) { initscr(); curs_set(0); noecho(); raw(); nonl(); keypad(stdscr,TRUE); clear(); refresh(); #ifdef HAVE_TYPEAHEAD if (always_redraw) typeahead(-1); #endif } void display_end(void) { curs_set(1); echo(); noraw(); refresh(); endwin(); } void redraw_cell(Sheet *sheet, int x, int y, int z) { redraw_sheet(sheet); } /* redraw_sheet -- draw a sheet with cell cursor */ void redraw_sheet(Sheet *sheet) { int width,col,x,y,again; char pbuf[80]; char *buf=malloc(128); size_t bufsz=128; const char *label; char *err; char moveonly; assert(sheet!=(Sheet*)0); assert(sheet->curx>=0); assert(sheet->cury>=0); assert(sheet->curz>=0); assert(sheet->offx>=0); assert(sheet->offy>=0); /* correct offsets to keep cursor visible */ while (shadowed(sheet,sheet->curx,sheet->cury,sheet->curz)) { --(sheet->curx); assert(sheet->curx>=0); } if (sheet->cury-sheet->offy>(sheet->maxy-2-header)) sheet->offy=sheet->cury-sheet->maxy+2+header; if (sheet->curyoffy) sheet->offy=sheet->cury; if (sheet->curxoffx) sheet->offx=sheet->curx; do { again=0; for (width=4*header,x=sheet->offx,col=0; width<=sheet->maxx; width+=columnwidth(sheet,x,sheet->curz),++x,++col); --col; sheet->width=col; if (sheet->curx!=sheet->offx) { if (col==0) { ++sheet->offx; again=1; } else if (sheet->curx-sheet->offx>=col) { ++sheet->offx; again=1; } } } while (again); if (header) { (void)wattron(stdscr,DEF_NUMBER); /* draw x numbers */ for (width=4; widthmaxx; ++width) mvwaddch(stdscr,0+sheet->oriy,sheet->orix+width,(chtype)(unsigned char)' '); for (width=4,x=sheet->offx; widthmaxx; width+=col,++x) { col=columnwidth(sheet,x,sheet->curz); if (bufsz<(size_t)(col*UTF8SZ+1)) buf=realloc(buf,bufsz=(size_t)(col*UTF8SZ+1)); snprintf(buf,bufsz,"%d",x); if (mbslen(buf)>col) { buf[col-1]='$'; buf[col]='\0'; } adjust(CENTER,buf,(size_t)col); assert(sheet->maxx>=width); if ((sheet->maxx-width)maxx-width]='\0'; mvwaddstr(stdscr,sheet->oriy,sheet->orix+width,buf); } /* draw y numbers */ for (y=1; y<(sheet->maxy-1); ++y) (void)mvwprintw(stdscr,sheet->oriy+y,sheet->orix,"%-4d",y-1+sheet->offy); (void)wattroff(stdscr,DEF_NUMBER); /* draw z number */ (void)mvwprintw(stdscr,sheet->oriy,sheet->orix,"%3d",sheet->curz); } /* draw elements */ for (y=header; ymaxy-1; ++y) for (width=4*header,x=sheet->offx; widthmaxx; width+=columnwidth(sheet,x,sheet->curz),++x) { size_t size,realsize,fill,cutoff; int realx; realx=x; cutoff=0; if (x==sheet->offx) while (shadowed(sheet,realx,y-header+sheet->offy,sheet->curz)) { --realx; cutoff+=columnwidth(sheet,realx,sheet->curz); } if ((size=cellwidth(sheet,realx,y-header+sheet->offy,sheet->curz))) { int invert; if (bufsz<(size*UTF8SZ+1)) buf=realloc(buf,bufsz=(size*UTF8SZ+1)); printvalue(buf,(size*UTF8SZ+1),size,quote,getscientific(sheet,realx,y-header+sheet->offy,sheet->curz),getprecision(sheet,realx,y-header+sheet->offy,sheet->curz),sheet,realx,y-header+sheet->offy,sheet->curz); adjust(getadjust(sheet,realx,y-header+sheet->offy,sheet->curz),buf,size); assert(size>=cutoff); if (width+((int)(size-cutoff))>=sheet->maxx) { *(buf+cutoff+sheet->maxx-width)='\0'; realsize=sheet->maxx-width+cutoff; } else realsize=size; invert= ( (sheet->mark1x!=-1) && ((x>=sheet->mark1x && x<=sheet->mark2x) || (x>=sheet->mark2x && x<=sheet->mark1x)) && ((y-header+sheet->offy>=sheet->mark1y && y-header+sheet->offy<=sheet->mark2y) || (y-header+sheet->offy>=sheet->mark2y && y-header+sheet->offy<=sheet->mark1y)) && ((sheet->curz>=sheet->mark1z && sheet->curz<=sheet->mark2z) || (sheet->curz>=sheet->mark2z && sheet->curz<=sheet->mark1z)) ); if (x==sheet->curx && (y-header+sheet->offy)==sheet->cury) invert=(sheet->marking ? 1 : 1-invert); if (invert) (void)wattron(stdscr,DEF_CELLCURSOR); if (isbold(sheet,realx,y-header+sheet->offy,sheet->curz)) wattron(stdscr,A_BOLD); if (underlined(sheet,realx,y-header+sheet->offy,sheet->curz)) wattron(stdscr,A_UNDERLINE); (void)mvwaddstr(stdscr,sheet->oriy+y,sheet->orix+width,buf+cutoff); for (fill=mbslen(buf+cutoff); fillmaxx*UTF8SZ+1)) buf=realloc(buf,bufsz=(sheet->maxx*UTF8SZ+1)); label=getlabel(sheet,sheet->curx,sheet->cury,sheet->curz); assert(label!=(const char*)0); moveonly=sheet->moveonly ? *_("V") : *_("E"); if (*label=='\0') sprintf(pbuf,"%c @(%d,%d,%d)=",moveonly,sheet->curx,sheet->cury,sheet->curz); else sprintf(pbuf,"%c @(%s)=",moveonly,label); (void)strncpy(buf,pbuf,bufsz); buf[bufsz-1] = 0; if ((err=geterror(sheet,sheet->curx,sheet->cury,sheet->curz))!=(const char*)0) { (void)strncpy(buf, err, bufsz); free(err); } else { print(buf+strlen(buf),bufsz-strlen(buf),0,1,getscientific(sheet,sheet->curx,sheet->cury,sheet->curz),-1,getcont(sheet,sheet->curx,sheet->cury,sheet->curz,0)); if (getcont(sheet,sheet->curx,sheet->cury,sheet->curz,1) && mbslen(buf) < (size_t)(sheet->maxx+1-4)) { strcat(buf," -> "); print(buf+strlen(buf),bufsz-strlen(buf),0,1,getscientific(sheet,sheet->curx,sheet->cury,sheet->curz),-1,getcont(sheet,sheet->curx,sheet->cury,sheet->curz,1)); } } *mbspos(buf, sheet->maxx) = 0; (void)mvwaddstr(stdscr,sheet->oriy+sheet->maxy-1,sheet->orix,buf); for (col=mbslen(buf); colmaxx; ++col) (void)waddch(stdscr,' '); } /* line_file -- line editor function for file name entry */ const char *line_file(const char *file, const char *pattern, const char *title, int create) { static char buf[PATH_MAX] = ""; int rc; size_t dummy1 = 0, dummy2 = 0; if (file) strncpy(buf, file, sizeof(buf)); buf[sizeof(buf)-1] = 0; rc = line_edit((Sheet*)0, buf, sizeof(buf), title, &dummy1, &dummy2); if (rc < 0) return NULL; return buf; } /* line_edit -- line editor function */ int line_edit(Sheet *sheet, char *buf, size_t size, const char *prompt, size_t *x, size_t *offx) { size_t promptlen; char *src, *dest; int i,mx,my,insert; chtype c; assert(buf!=(char*)0); assert(prompt!=(char*)0); assert(x!=(size_t*)0); assert(offx!=(size_t*)0); (void)curs_set(1); mx=COLS; my=LINES; promptlen=mbslen(prompt)+1; (void)mvwaddstr(stdscr,LINES-1,0,prompt); (void)waddch(stdscr,(chtype)(unsigned char)' '); insert=1; do { /* correct offx to cursor stays visible */ if (*x<*offx) *offx=*x; if ((*x-*offx)>(mx-promptlen-1)) *offx=*x-mx+promptlen+1; /* display buffer */ (void)wmove(stdscr,LINES-1,(int)promptlen); src = mbspos(buf, *offx); dest = mbspos(buf, *offx+COLS-promptlen); for (; *src && src < dest; src++) (void)waddch(stdscr,(chtype)(unsigned char)(*src)); if (i!=mx) (void)wclrtoeol(stdscr); /* show cursor */ (void)wmove(stdscr,LINES-1,(int)(*x-*offx+promptlen)); src = dest = mbspos(buf, *x); c=wgetc(); if (sheet!=(Sheet*)0 && sheet->moveonly) switch (c) { /* ^o -- switch back to line editor */ case '\t': case '\017': sheet->moveonly=0; break; /* v -- insert value of current cell */ case 'v': { char valbuf[1024]; printvalue(valbuf,sizeof(valbuf),0,1,getscientific(sheet,sheet->curx,sheet->cury,sheet->curz),-1,sheet,sheet->curx,sheet->cury,sheet->curz); if (strlen(buf)+strlen(valbuf) >= (size-1)) break; (void)memmove(src+strlen(valbuf), src, strlen(src)); (void)memcpy(src, valbuf, strlen(valbuf)); (*x) += mbslen(valbuf); break; } /* p -- insert position of current cell */ case 'p': { char valbuf[1024]; sprintf(valbuf,"(%d,%d,%d)",sheet->curx,sheet->cury,sheet->curz); if (strlen(buf)+strlen(valbuf) >= (size-1)) break; (void)memmove(src+strlen(valbuf), src, strlen(src)); (void)memcpy(src, valbuf, strlen(valbuf)); (*x) += mbslen(valbuf); break; } /* default -- move around in sheet */ default: (void)do_sheetcmd(sheet,c,1); redraw_sheet(sheet); break; } else switch (c) { /* UP */ case K_UP: break; /* LEFT */ case K_LEFT: if (*x > 0) (*x)--; break; /* RIGHT */ case K_RIGHT: if (*x < mbslen(buf)) (*x)++; break; /* BACKSPACE */ case K_BACKSPACE: if (*x > 0) { memmove(mbspos(src, -1), src, strlen(src)+1); (*x)--; } break; /* C-i -- file name completion */ case '\t': completefile(buf, src, size); break; /* DC */ case K_DC: src = mbspos(dest, 1); if (*x < strlen(buf)) memmove(dest, src, strlen(src)+1); break; /* HOME */ case K_HOME: *x = 0; break; /* END */ case K_END: *x = mbslen(buf); break; /* IC */ case KEY_IC: insert=1-insert; break; /* EIC */ case KEY_EIC: insert=0; break; /* control t */ case '\024': if (*x > 0) { char c, *end; dest = mbspos(src, -1); if (*x == mbslen(buf)) { src = dest; dest = mbspos(src, -1); (*x)--; } end = mbspos(src, 1); while (src != end) { c = *src; memmove(dest+1, dest, src-dest); *dest = c; src++; dest++; } (*x)++; } break; /* control backslash */ case '\034': { int level; char open = 0, close = 0, dir = 1; switch (*dest) { case ')': dir = -1; case '(': open = '('; close = ')'; break; case '}': dir = -1; case '{': open = '{'; close = '}'; break; case ']': dir = -1; case '[': open = '['; close = ']'; break; default: break; } level = dir; while (*dest && level) { dest += dir; if (*dest == open) level--; else if (*dest == close) level++; } if (!level) *x = mbslen(buf)-mbslen(dest); break; } /* DL */ case KEY_DL: *src = '\0'; break; /* control o */ case '\017': if (sheet!=(Sheet*)0) sheet->moveonly=1; break; /* default */ default: if (((unsigned int)c) < ' ' || ((unsigned int)c) >= 256) break; if (strlen(buf) >= (size-1)) { if (is_mbcont(c)) { dest = mbspos(src, -1); memmove(dest, src, strlen(src)+1); } break; } if (insert || is_mbcont(c)) memmove(src+1, src, strlen(src)+1); else { if (is_mbchar(*src)) memmove(src+1, mbspos(src, 1), strlen(mbspos(src, 1))+1); if (!*src) *(src+1) = '\0'; } *src = (char)c; if (!is_mbcont(c)) (*x)++; break; } } while (c != K_ENTER && c != KEY_CANCEL && (c != K_UP || (sheet!=(Sheet*)0 && sheet->moveonly))); if (sheet) sheet->moveonly=0; (void)curs_set(0); (void)wmove(stdscr,LINES-1,0); (void)wclrtoeol(stdscr); switch (c) { case KEY_CANCEL: return -1; case K_UP: return -2; default: return 0; } } /* line_ok -- one line yes/no menu */ int line_ok(const char *prompt, int curx) { MenuChoice menu[3]; int result; assert(curx==0 || curx==1); menu[0].str=mystrmalloc(_("nN)o")); menu[0].c='\0'; menu[1].str=mystrmalloc(_("yY)es")); menu[1].c='\0'; menu[2].str=(char*)0; result=line_menu(prompt,menu,curx); free(menu[0].str); free(menu[1].str); return (result); } /* line_menu -- one line menu */ /* Notes */ /* The choices are terminated by the last element having a (const char*)str field. Each item can be chosen by tolower(*str) or by the key stored in the c field. Use a space as first character of str, if you only want the function key to work. */ int line_menu(const char *prompt, const MenuChoice *choice, int curx) { int maxx,x,width,offx; chtype c; size_t promptlen; assert(prompt!=(const char*)0); assert(choice!=(const MenuChoice*)0); assert(curx>=0); mvwaddstr(stdscr,LINES-1,0,prompt); promptlen = mbslen(prompt); for (maxx=0; (choice+maxx)->str!=(const char*)0; ++maxx); offx=0; do { (void)wmove(stdscr,LINES-1,(int)promptlen); /* correct offset so choice is visible */ if (curx<=offx) offx=curx; else do { for (width=promptlen,x=offx; xstr+1))+1<=COLS; width+=((int)(mbslen((choice+x)->str)))+1,++x); --x; if (xstr+1))+1<=COLS; width+=mbslen((choice+x)->str+1)+1,++x) { (void)waddch(stdscr,(chtype)(unsigned char)' '); if (x==curx) (void)wattron(stdscr,DEF_MENU); (void)waddstr(stdscr,(char*)(choice+x)->str+1); if (x==curx) (void)wattroff(stdscr,DEF_MENU); } if (width0) --curx; else curx=maxx-1; break; /* Space, Tab, KEY_RIGHT -- move to next item */ case ' ': case '\t': case K_RIGHT: if (curx<(maxx-1)) ++curx; else curx=0; break; /* default -- search choice keys */ default: { int i; for (i=0; (choice+i)->str!=(const char*)0; ++i) { if ((c<256 && tolower(c)==*((choice+i)->str)) || (choice+i)->c==c) { c=K_ENTER; curx=i; } } } } } while (c!=K_ENTER && c!=K_DOWN && c!=KEY_CANCEL && c!=K_UP); (void)wmove(stdscr,LINES-1,0); (void)wclrtoeol(stdscr); switch (c) { case KEY_CANCEL: return -1; case K_UP: return -2; default: return curx; } } /* line_msg -- one line message which will be cleared by someone else */ void line_msg(const char *prompt, const char *msg) { int width; assert(msg!=(const char*)0); if (!*msg) msg = _("Use F0, F10 or / for menu"); if (!batch) { width=1; mvwaddch(stdscr,LINES-1,0,(chtype)(unsigned char)'['); if (prompt!=(const char*)0) { for (; width -- FPAGE */ case KEY_NPAGE: case '>': return K_FPAGE; /* C-x C-c -- QUIT */ case '\03': return K_QUIT; /* C-x C-s -- SAVE */ case '\023': return K_SAVE; /* C-x C-r -- LOAD */ case '\022': return K_LOAD; /* default -- INVALID, general invalid value */ default: return K_INVALID; } } /* ESC, get one more key */ case '\033': { switch (wgetch(stdscr)) { /* M-v -- PPAGE */ case 'v': return K_PPAGE; /* M-Enter -- MENTER */ case KEY_ENTER: case '\r': case '\n': return K_MENTER; /* M-z -- SAVEQUIT */ case 'z': return K_SAVEQUIT; /* default -- INVALID, general invalid value */ default: return K_INVALID; } } /* _("Load sheet file format:") */ case KEY_F(2): return K_LOADMENU; /* _("Save sheet file format:") */ case KEY_F(3): return K_SAVEMENU; /* default */ default: return c; } } void find_helpfile(char *buf, int size, const char *argv0) { strncpy(buf, HELPFILE, size); buf[size-1] = 0; }