#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 extern char *strdup(const char* s); #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) { int c; Cell *cc = curcell(cursheet); do { MarkState ms = getmarkstate(cursheet); const char* prompt = _("Block attribute"); if (ms == UNMARKED) prompt = _("Cell attribute"); const char *mainmenu[] = { _("jJ)ustify"), _("fF)loats"), _("tT)ypeface"), _("mM)isc"), _("lL)abel"), _("kLock)"), NULL }; c = line_menu(prompt, mainmenu, 0); /* There is a magic number "5" in the next line, presumably it represents the selection of the lock attribute in the list of items above, in which lock does indeed appear at index 5 */ if (ms == UNMARKED && c != 5 && locked(cc)) line_msg(_("Cell attribute:"), _("Cell is locked")); else { switch (c) { case -2: case -1: c = KEY_CANCEL; break; case 0: { const char *justifymenu[] = { _("lL)eft"), _("rR)ight"), _("cC)entered"), NULL }; switch (c = line_menu(prompt, justifymenu, getadjust(cc))) { 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; default: assert(0); } break; } case 1: { const char *floatmenu[] = { _("dD)ecimal"), _("sS)cientific"), _("cC)ompact"), _("hH)exact"), _("pP)recision"), NULL }; switch (c = line_menu(prompt, floatmenu, getfltformat(cc))) { case -2: case -1: c = K_INVALID; break; case 0: c = ADJUST_DECIMAL; break; case 1: c = ADJUST_SCIENTIFIC; break; case 2: c = ADJUST_COMPACT; break; case 3: c = ADJUST_HEXACT; break; case 4: c = ADJUST_PRECISION; break; default: assert(0); } break; } case 2: { const char *typemenu[] = { _("bB)old"), _("uU)nderline"), _("fF)oreground"), _("kBack)ground"), NULL }; switch (c = line_menu(prompt, typemenu, 0)) { case -2: case -1: c = K_INVALID; break; case 0: c = ADJUST_BOLD; break; case 1: c = ADJUST_UNDERLINE; break; case 2: c = ADJUST_FOREGROUND; break; case 3: c = ADJUST_BACKGROUND; break; default: assert(0); } break; } case 3: { const char *miscmenu[] = { _("sS)hadow"), _("iI)gnore"), _("oO)utput special characters"), NULL }; switch (c = line_menu(prompt, miscmenu, 0)) { case -2: case -1: c = K_INVALID; break; case 0: c = ADJUST_SHADOW; break; case 1: c = ADJUST_IGNORE; break; case 2: c = ADJUST_TRANSPARENT; break; default: assert(0); } break; } case 4: c = ADJUST_LABEL; break; case 5: c = ADJUST_LOCK; break; default: assert(0); } } } while (c == K_INVALID); if (c == KEY_CANCEL) c = K_INVALID; return c; } /* do_file -- file menu */ static int do_file(Sheet *cursheet) { int c = 0; do { const char *menu[] = { _("lL)oad"), _("sS)ave"), _("nN)ame"), NULL }; 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; 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) { int c = 0; do { const char* block[] = { _("ecle)ar"), _("iI)nsert"), _("dD)elete"), _("mM)ove"), _("cC)opy"), _("fF)ill"), _("sS)ort"), _("rMir)ror"), NULL }; 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; return c; } int show_menu(Sheet *cursheet) { int c = K_INVALID; do { const char* menu[] = { _("aA)ttributes"), _("wW)idth"), _("bB)lock"), _("fF)ile"), _("gG)oto"), _("sS)hell"), _("vV)ersion"), _("qQ)uit"), NULL }; 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; 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); } #define CHANNEL_MAX 1000 typedef short CursesColor[3]; void display_init(Sheet *cursheet, int always_redraw) { initscr(); start_color(); init_color(DefaultCN[BACKGROUND], CHANNEL_MAX, CHANNEL_MAX, CHANNEL_MAX); assume_default_colors(COLOR_BLACK, DefaultCN[BACKGROUND]); if (debug_level > 1) printf("Terminal has colors: %d, #colors:%d, #pairs:%d", has_colors(), COLORS, COLOR_PAIRS); curs_set(0); noecho(); raw(); nonl(); keypad(stdscr,TRUE); clear(); refresh(); #ifdef HAVE_TYPEAHEAD if (always_redraw) typeahead(-1); #endif /* allocate and initialize the palette */ if (COLORS < cursheet->max_colors) { cursheet->max_colors = COLORS; } cursheet->palette = (void *)malloc(cursheet->max_colors*sizeof(CursesColor)); memset(cursheet->palette, '\0', cursheet->max_colors*sizeof(CursesColor)); CursesColor *palt = (CursesColor *)(cursheet->palette); for (size_t i = 0; i <= DefaultCN[BACKGROUND]; ++i) (void)color_content(i, &(palt[i][0]), &(palt[i][1]), &(palt[i][2])); } void display_end(Sheet* sheet) { curs_set(1); echo(); noraw(); refresh(); endwin(); free(sheet->palette); } void redraw_cell(Sheet *sheet, const Location at ) { 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; Location tmp; Cell *cell; MarkState ms; char *err; char moveonly; assert(sheet!=(Sheet*)0); assert(IN_OCTANT(sheet->cur)); assert(sheet->offx>=0); assert(sheet->offy>=0); /* correct offsets to keep cursor visible */ while (shadowed(curcell(sheet))) { --(sheet->cur[X]); assert(sheet->cur[X] >= 0); } if (sheet->cur[Y] - sheet->offy > (sheet->maxy - 2 - header)) sheet->offy = sheet->cur[Y] - sheet->maxy + 2 + header; if (sheet->cur[Y] < sheet->offy) sheet->offy = sheet->cur[Y]; if (sheet->cur[X] < sheet->offx) sheet->offx = sheet->cur[X]; do { again=0; for (width = 4*header, x = sheet->offx, col=0; width <= sheet->maxx; width += columnwidth(sheet, x, sheet->cur[Z]), ++x, ++col); --col; sheet->width = col; if (sheet->cur[X] != sheet->offx) { if (col==0) { ++sheet->offx; again=1; } else if (sheet->cur[X] - sheet->offx >= col) { ++sheet->offx; again=1; } } } while (again); unsigned short curcp = 1; init_pair(curcp, DefaultCN[FOREGROUND], COLOR_YELLOW); if (header) { (void)wattron(stdscr,DEF_NUMBER); /* draw x numbers */ for (width=4; width < sheet->maxx; ++width) mvwaddch(stdscr, 0+sheet->oriy, sheet->orix+width, (chtype)(unsigned char)' '); for (width=4, x=sheet->offx; widthmaxx; width+=col,++x) { unsigned short usecp = 0; if (x == sheet->cur[X]) usecp = curcp; col = columnwidth(sheet, x, sheet->cur[Z]); 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'; wcolor_set(stdscr, usecp, NULL); mvwaddstr(stdscr,sheet->oriy,sheet->orix+width,buf); wcolor_set(stdscr, 0, NULL); } /* draw y numbers */ for (y=1; y<(sheet->maxy-1); ++y) { unsigned short usecp = 0; int realy = y-1+sheet->offy; if (realy == sheet->cur[Y]) usecp = curcp; wcolor_set(stdscr, usecp, NULL); (void)mvwprintw(stdscr,sheet->oriy+y,sheet->orix,"%-4d",y-1+sheet->offy); wcolor_set(stdscr, 0, NULL); } (void)wattroff(stdscr,DEF_NUMBER); /* draw z number */ (void)mvwprintw(stdscr, sheet->oriy, sheet->orix, "%3d", sheet->cur[Z]); } ++curcp; /* draw elements */ for (y=header; ymaxy-1; ++y) for (width = 4*header, x = sheet->offx; width < sheet->maxx; width += columnwidth(sheet, x, sheet->cur[Z]),++x) { size_t size,realsize,fill,cutoff; int realx; realx = x; cutoff = 0; if (x == sheet->offx) while (SHADOWEDC(sheet,realx,y-header+sheet->offy,sheet->cur[Z])) { --realx; cutoff+=columnwidth(sheet, realx, sheet->cur[Z]); } tmp[X] = realx; tmp[Y] = y - header + sheet->offy; tmp[Z] = sheet->cur[Z]; cell = safe_cell_at(sheet, tmp); if ((size = cellwidth(sheet, tmp))) { bool invert; if (bufsz < (size*UTF8SZ+1)) buf = realloc(buf, bufsz=(size*UTF8SZ+1)); printvalue(buf, (size*UTF8SZ + 1), size, quote, getfltformat(cell), getprecision(cell), sheet, tmp); adjust(getadjust(cell), 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; ms = getmarkstate(sheet); int usecp = 0; ColorNum fg = getcolor(cell, FOREGROUND); ColorNum bg = getcolor(cell, BACKGROUND); while (usecp < curcp) { unsigned short pfg, pbg; pair_content(usecp, &pfg, &pbg); if (fg == pfg && bg == pbg) break; ++usecp; } if (usecp == curcp) init_pair(curcp++, fg, bg); wcolor_set(stdscr, usecp, NULL); invert = (ms != UNMARKED) && loc_in_box(tmp, sheet->mark1, sheet->mark2); if (x == sheet->cur[X] && (y-header+sheet->offy) == sheet->cur[Y]) invert = (ms == MARKING) ? true : !invert; if (invert) (void)wattron(stdscr,DEF_CELLCURSOR); if (isbold(cell)) wattron(stdscr,A_BOLD); if (underlined(cell)) 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(curcell(sheet)); assert(label != (const char*)0); moveonly = sheet->moveonly ? *_("V") : *_("E"); if (*label=='\0') sprintf(pbuf, "%c @(%d,%d,%d)=", moveonly, sheet->cur[X], sheet->cur[Y], sheet->cur[Z]); else sprintf(pbuf, "%c @(%s)=", moveonly, label); (void)strncpy(buf,pbuf,bufsz); buf[bufsz-1] = 0; if ((err=geterror(sheet,sheet->cur)) != (const char*)0) { (void)strncpy(buf, err, bufsz); free(err); } else { cell = curcell(sheet); Token bc = gettok(cell, BASE_CONT); printtok(buf+strlen(buf), bufsz-strlen(buf), 0, QUOTE_STRING, FLT_COMPACT, 0, TRUNCATED_ERROR, &bc); Token ic = gettok(cell, ITER_CONT); if (ic.type != EMPTY && mbslen(buf) < (size_t)(sheet->maxx+1-4)) { strcat(buf," -> "); printtok(buf+strlen(buf), bufsz-strlen(buf), 0, QUOTE_STRING, FLT_COMPACT, 0, TRUNCATED_ERROR, &ic); } } *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, QUOTE_STRING, FLT_COMPACT, 0, sheet, sheet->cur); 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->cur[X], sheet->cur[Y], sheet->cur[Z]); 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) { assert(curx == 0 || curx == 1); const char* menu[] = { _("nN)o"), _("yY)es"), NULL }; return line_menu(prompt, menu, curx); } /* line_binary -- two choices with cancel */ int line_binary(const char *prompt, const char* op1, const char* op2, int curx) { int result; assert(curx == 0 || curx == 1); const char* menu[] = { _("cC)ancel"), op1, op2, NULL }; return line_menu(prompt, menu, curx+1) - 1; } /* 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 char **choice, int curx) { assert(prompt != NULL); assert(choice != (const char **)0); assert(curx >= 0); mvwaddstr(stdscr,LINES-1,0,prompt); size_t promptlen = mbslen(prompt); int maxx = 0; while (choice[maxx] != NULL) ++maxx; int offx = 0; chtype c; do { int x, width; (void)wmove(stdscr, LINES-1, (int)promptlen); /* correct offset so choice is visible */ if (curx <= offx) offx = curx; else do { width = promptlen; x = offx; while (x < maxx && width + ((int)mbslen(choice[x]+1)) + 1 <= COLS) { width += (int)(mbslen(choice[x]+1)) + 1; ++x; } --x; if (x < curx) ++offx; } while (x < curx); /* show visible choices */ for (width = promptlen, x = offx; x < maxx && width + ((int)mbslen(choice[x]+1)) + 1 <= COLS; width += mbslen(choice[x]+1) + 1, ++x) { (void)waddch(stdscr, (chtype)(unsigned char)' '); if (x == curx) (void)wattron(stdscr, DEF_MENU); (void)waddstr(stdscr, (char*)(choice[x]+1)); if (x == curx) (void)wattroff(stdscr,DEF_MENU); } if (width < COLS) (void)wclrtoeol(stdscr); switch (c = wgetc()) { /* KEY_LEFT -- move to previous item */ case K_BACKSPACE: case K_LEFT: if (curx > 0) --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: { for (int i = 0; i < maxx; ++i) if (c < 256 && tolower(c) == choice[i][0]) { 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; }