"Fossies" - the Fresh Open Source Software Archive 
Member "teapot-2.3.0/display.c" (6 Feb 2012, 26279 Bytes) of package /linux/privat/old/teapot-2.3.0.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "display.c" see the
Fossies "Dox" file reference documentation.
1 #ifndef NO_POSIX_SOURCE
2 #undef _POSIX_SOURCE
3 #define _POSIX_SOURCE 1
4 #undef _POSIX_C_SOURCE
5 #define _POSIX_C_SOURCE 2
6 #endif
7
8 #include <sys/types.h>
9 #include <sys/wait.h>
10 #include <assert.h>
11 #include <ctype.h>
12 #include <limits.h>
13 #ifdef ENABLE_UTF8
14 #include <ncursesw/curses.h>
15 #else
16 #include <curses.h>
17 #endif
18 #include <errno.h>
19 #include <pwd.h>
20 #include <termios.h>
21 #include <signal.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 #ifdef NEED_BCOPY
27 #define memmove(dst,src,len) bcopy(src,dst,len)
28 #endif
29 #ifdef OLD_REALLOC
30 #define realloc(s,l) myrealloc(s,l)
31 #endif
32
33 #ifdef DMALLOC
34 #include "dmalloc.h"
35 #endif
36
37
38 #include "complete.h"
39 #include "default.h"
40 #include "display.h"
41 #include "eval.h"
42 #include "main.h"
43 #include "misc.h"
44 #include "sheet.h"
45 #include "utf8.h"
46
47 static Key wgetc(void);
48
49 /* redraw -- redraw whole screen */
50 static void redraw(void)
51 {
52 (void)touchwin(curscr);
53 (void)wrefresh(curscr);
54 }
55
56
57 /* do_attribute -- set cell attributes */
58 static int do_attribute(Sheet *cursheet)
59 {
60
61 MenuChoice mainmenu[5];
62 MenuChoice adjmenu[11];
63 int c;
64
65 /* create menus */
66 adjmenu[0].str=mystrmalloc(_("lL)eft")); adjmenu[0].c='\0';
67 adjmenu[1].str=mystrmalloc(_("rR)ight")); adjmenu[1].c='\0';
68 adjmenu[2].str=mystrmalloc(_("cC)entered")); adjmenu[2].c='\0';
69 adjmenu[3].str=mystrmalloc(_("11).23e1 <-> 12.3")); adjmenu[3].c='\0';
70 adjmenu[4].str=mystrmalloc(_("pP)recision")); adjmenu[4].c='\0';
71 adjmenu[5].str=mystrmalloc(_("sS)hadow")); adjmenu[5].c='\0';
72 adjmenu[6].str=mystrmalloc(_("bB)old")); adjmenu[6].c='\0';
73 adjmenu[7].str=mystrmalloc(_("uU)nderline")); adjmenu[7].c='\0';
74 adjmenu[8].str=mystrmalloc(_("oO)utput special characters")); adjmenu[8].c='\0';
75 adjmenu[9].str=(char*)0;
76
77 mainmenu[0].str=mystrmalloc(_("rR)epresentation")); mainmenu[0].c='\0';
78 mainmenu[1].str=mystrmalloc(_("lL)abel")); mainmenu[1].c='\0';
79 mainmenu[2].str=mystrmalloc(_("oLo)ck")); mainmenu[2].c='\0';
80 mainmenu[3].str=mystrmalloc(_("iI)gnore")); mainmenu[3].c='\0';
81 mainmenu[4].str=(char*)0;
82
83 do
84 {
85 c = line_menu(cursheet->mark1x==-1 ? _("Cell attribute:") : _("Block attribute:"),mainmenu,0);
86 if (cursheet->mark1x==-1 && c!=2 && locked(cursheet,cursheet->curx,cursheet->cury,cursheet->curz)) line_msg(_("Cell attribute:"),_("Cell is locked"));
87 else
88 {
89 switch (c)
90 {
91 case -2:
92 case -1: c = KEY_CANCEL; break;
93 case 0:
94 {
95 switch (c=line_menu(cursheet->mark1x==-1 ? _("Cell attribute:") : _("Block attribute:"),adjmenu,0))
96 {
97 case -2:
98 case -1: c = K_INVALID; break;
99 case 0: c = ADJUST_LEFT; break;
100 case 1: c = ADJUST_RIGHT; break;
101 case 2: c = ADJUST_CENTER; break;
102 case 3: c = ADJUST_SCIENTIFIC; break;
103 case 4: c = ADJUST_PRECISION; break;
104 case 5: c = ADJUST_SHADOW; break;
105 case 6: c = ADJUST_BOLD; break;
106 case 7: c = ADJUST_UNDERLINE; break;
107 case 8: c = ADJUST_TRANSPARENT; break;
108 default: assert(0);
109 }
110 break;
111 }
112 case 1: c = ADJUST_LABEL; break;
113 case 2: c = ADJUST_LOCK; break;
114 case 3: c = ADJUST_IGNORE; break;
115 default: assert(0);
116 }
117 }
118 } while (c == K_INVALID);
119 if (c == KEY_CANCEL) c = K_INVALID;
120
121 /* free menus */
122 free(mainmenu[0].str);
123 free(mainmenu[1].str);
124 free(mainmenu[2].str);
125 free(mainmenu[3].str);
126 free(adjmenu[0].str);
127 free(adjmenu[1].str);
128 free(adjmenu[2].str);
129 free(adjmenu[3].str);
130 free(adjmenu[4].str);
131 free(adjmenu[5].str);
132 free(adjmenu[6].str);
133 free(adjmenu[7].str);
134 free(adjmenu[8].str);
135
136 return c;
137 }
138 /* do_file -- file menu */
139 static int do_file(Sheet *cursheet)
140 {
141
142 MenuChoice menu[4];
143 int c;
144
145
146 menu[0].str=mystrmalloc(_("lL)oad")); menu[0].c='\0';
147 menu[1].str=mystrmalloc(_("sS)ave")); menu[1].c='\0';
148 menu[2].str=mystrmalloc(_("nN)ame")); menu[2].c='\0';
149 menu[3].str=(char*)0;
150 c=0;
151 do
152 {
153 switch (c=line_menu(_("File:"),menu,0))
154 {
155 case -2:
156 case -1: c = KEY_CANCEL; break;
157 case 0: c = K_LOADMENU; break;
158 case 1: c = K_SAVEMENU; break;
159 case 2: c = K_NAME; break;
160 default: assert(0);
161 }
162 } while (c == K_INVALID);
163 if (c == KEY_CANCEL) c = K_INVALID;
164 free(menu[0].str);
165 free(menu[1].str);
166 free(menu[2].str);
167 return c;
168 }
169
170
171 /* do_shell -- spawn a shell */
172 static int do_shell(void)
173 {
174 pid_t pid;
175 struct sigaction interrupt;
176
177 refresh();
178 interrupt.sa_flags=0;
179 sigemptyset(&interrupt.sa_mask);
180 interrupt.sa_handler=SIG_IGN;
181 sigaction(SIGINT,&interrupt,(struct sigaction *)0);
182 sigaction(SIGQUIT,&interrupt,(struct sigaction *)0);
183 switch (pid=fork())
184 {
185 /* -1 */
186 case -1: line_msg(_("Spawn sub shell"),strerror(errno)); break;
187
188 /* 0 */
189 case 0:
190 {
191 const char *shell;
192
193 if ((shell=getenv("SHELL"))==(const char*)0)
194 {
195 struct passwd *pwd;
196
197 if ((pwd=getpwuid(getuid()))==(struct passwd*)0)
198 {
199 shell="/bin/sh";
200 }
201 else
202 {
203 shell=pwd->pw_shell;
204 }
205 }
206 line_msg((const char*)0,_("Sub shell started"));
207 move(LINES-1,0);
208 curs_set(1);
209 refresh();
210 reset_shell_mode();
211 puts("\n");
212 interrupt.sa_handler=SIG_DFL;
213 sigaction(SIGINT,&interrupt,(struct sigaction *)0);
214 sigaction(SIGQUIT,&interrupt,(struct sigaction *)0);
215 execl(shell,shell,(const char*)0);
216 exit(127);
217 break;
218 }
219
220 /* default */
221 default:
222 {
223 pid_t r;
224 int status;
225
226 while ((r=wait(&status))!=-1 && r!=pid);
227 reset_prog_mode();
228 interrupt.sa_handler=SIG_DFL;
229 sigaction(SIGINT,&interrupt,(struct sigaction *)0);
230 sigaction(SIGQUIT,&interrupt,(struct sigaction *)0);
231 clear();
232 refresh();
233 curs_set(0);
234 redraw();
235 }
236
237 }
238 return -1;
239 }
240
241
242 /* do_block -- block menu */
243 static int do_block(Sheet *cursheet)
244 {
245 MenuChoice block[9];
246 int c;
247
248 block[0].str=mystrmalloc(_("ecle)ar")); block[0].c='\0';
249 block[1].str=mystrmalloc(_("iI)nsert")); block[1].c='\0';
250 block[2].str=mystrmalloc(_("dD)elete")); block[2].c='\0';
251 block[3].str=mystrmalloc(_("mM)ove")); block[3].c='\0';
252 block[4].str=mystrmalloc(_("cC)opy")); block[4].c='\0';
253 block[5].str=mystrmalloc(_("fF)ill")); block[5].c='\0';
254 block[6].str=mystrmalloc(_("sS)ort")); block[6].c='\0';
255 block[7].str=mystrmalloc(_("rMir)ror")); block[7].c='\0';
256 block[8].str=(char*)0;
257 c=0;
258 do
259 {
260 switch (c=line_menu(_("Block menu:"),block,0))
261 {
262 case -2:
263 case -1: c = KEY_CANCEL; break;
264 case 0: c = BLOCK_CLEAR; break;
265 case 1: c = BLOCK_INSERT; break;
266 case 2: c = BLOCK_DELETE; break;
267 case 3: c = BLOCK_MOVE; break;
268 case 4: c = BLOCK_COPY; break;
269 case 5: c = BLOCK_FILL; break;
270 case 6: c = BLOCK_SORT; break;
271 case 7: c = BLOCK_MIRROR; break;
272 }
273 } while (c == K_INVALID);
274 if (c == KEY_CANCEL) c = K_INVALID;
275 free(block[0].str);
276 free(block[1].str);
277 free(block[2].str);
278 free(block[3].str);
279 free(block[4].str);
280 free(block[5].str);
281 free(block[6].str);
282 free(block[7].str);
283 return c;
284 }
285
286
287 int show_menu(Sheet *cursheet)
288 {
289
290 MenuChoice menu[9];
291 int c = K_INVALID;
292
293
294 menu[0].str=mystrmalloc(_("aA)ttributes")); menu[0].c='\0';
295 menu[1].str=mystrmalloc(_("wW)idth")); menu[1].c='\0';
296 menu[2].str=mystrmalloc(_("bB)lock")); menu[2].c='\0';
297 menu[3].str=mystrmalloc(_("fF)ile")); menu[3].c='\0';
298 menu[4].str=mystrmalloc(_("gG)oto")); menu[4].c='\0';
299 menu[5].str=mystrmalloc(_("sS)hell")); menu[5].c='\0';
300 menu[6].str=mystrmalloc(_("vV)ersion")); menu[6].c='\0';
301 menu[7].str=mystrmalloc(_("qQ)uit")); menu[7].c='\0';
302 menu[8].str=(char*)0;
303
304 do
305 {
306 switch (c=line_menu(_("Main menu:"),menu,0))
307 {
308 case -2:
309 case -1: c = KEY_CANCEL; break;
310 case 0: c = do_attribute(cursheet); break;
311 case 1: c = K_COLWIDTH; break;
312 case 2: c = do_block(cursheet); break;
313 case 3: c = do_file(cursheet); break;
314 case 4: c = K_GOTO; break;
315 case 5: do_shell(); c = KEY_CANCEL; break;
316 case 6: c = K_ABOUT; break;
317 case 7: c = K_QUIT; break;
318 default: assert(0);
319 }
320 } while (c == K_INVALID);
321 if (c == KEY_CANCEL) c = K_INVALID;
322
323 free(menu[0].str);
324 free(menu[1].str);
325 free(menu[2].str);
326 free(menu[3].str);
327 free(menu[4].str);
328 free(menu[5].str);
329 free(menu[6].str);
330 free(menu[7].str);
331
332 return c;
333 }
334
335 /* do_bg -- background teapot */
336 static void do_bg(void)
337 {
338 struct termios t;
339
340 if (tcgetattr(0,&t)==0 && t.c_cc[VSUSP]!=_POSIX_VDISABLE)
341 {
342 line_msg((const char*)0,_("Teapot stopped"));
343 move(LINES-1,0);
344 curs_set(1);
345 refresh();
346 reset_shell_mode();
347 puts("\n");
348 kill(getpid(),SIGSTOP);
349 clear();
350 refresh();
351 reset_prog_mode();
352 curs_set(0);
353 }
354 else line_msg((const char*)0,_("The susp character is undefined"));
355 }
356
357
358
359 void display_main(Sheet *cursheet)
360 {
361 Key k;
362 int quit = 0;
363
364 cursheet->maxx=COLS;
365 cursheet->maxy=LINES-1;
366
367 do
368 {
369 quit = 0;
370 redraw_sheet(cursheet);
371 k=wgetc();
372 wmove(stdscr,LINES-1,0);
373 wclrtoeol(stdscr);
374 switch ((int)k)
375 {
376 case KEY_SUSPEND:
377 case '\032': do_bg(); k = K_INVALID; break;
378 case '\014': redraw(); k = K_INVALID; break;
379 case KEY_F(0):
380 case KEY_F(10): k = show_menu(cursheet); break;
381 }
382 } while (k == K_INVALID || !do_sheetcmd(cursheet,k,0) || doanyway(cursheet,_("Sheet modified, leave anyway?"))!=1);
383 }
384
385 void display_init(Sheet *cursheet, int always_redraw)
386 {
387 initscr();
388 curs_set(0);
389 noecho();
390 raw();
391 nonl();
392 keypad(stdscr,TRUE);
393 clear();
394 refresh();
395 #ifdef HAVE_TYPEAHEAD
396 if (always_redraw) typeahead(-1);
397 #endif
398 }
399
400 void display_end(void)
401 {
402 curs_set(1);
403 echo();
404 noraw();
405 refresh();
406 endwin();
407 }
408
409 void redraw_cell(Sheet *sheet, int x, int y, int z)
410 {
411 redraw_sheet(sheet);
412 }
413
414 /* redraw_sheet -- draw a sheet with cell cursor */
415 void redraw_sheet(Sheet *sheet)
416 {
417
418 int width,col,x,y,again;
419 char pbuf[80];
420 char *buf=malloc(128);
421 size_t bufsz=128;
422 const char *label;
423 char *err;
424 char moveonly;
425
426 assert(sheet!=(Sheet*)0);
427 assert(sheet->curx>=0);
428 assert(sheet->cury>=0);
429 assert(sheet->curz>=0);
430 assert(sheet->offx>=0);
431 assert(sheet->offy>=0);
432
433 /* correct offsets to keep cursor visible */
434 while (shadowed(sheet,sheet->curx,sheet->cury,sheet->curz))
435 {
436 --(sheet->curx);
437 assert(sheet->curx>=0);
438 }
439 if (sheet->cury-sheet->offy>(sheet->maxy-2-header)) sheet->offy=sheet->cury-sheet->maxy+2+header;
440 if (sheet->cury<sheet->offy) sheet->offy=sheet->cury;
441 if (sheet->curx<sheet->offx) sheet->offx=sheet->curx;
442 do
443 {
444 again=0;
445 for (width=4*header,x=sheet->offx,col=0; width<=sheet->maxx; width+=columnwidth(sheet,x,sheet->curz),++x,++col);
446 --col;
447 sheet->width=col;
448 if (sheet->curx!=sheet->offx)
449 {
450 if (col==0) { ++sheet->offx; again=1; }
451 else if (sheet->curx-sheet->offx>=col) { ++sheet->offx; again=1; }
452 }
453 } while (again);
454
455 if (header) {
456 (void)wattron(stdscr,DEF_NUMBER);
457
458 /* draw x numbers */
459 for (width=4; width<sheet->maxx; ++width) mvwaddch(stdscr,0+sheet->oriy,sheet->orix+width,(chtype)(unsigned char)' ');
460 for (width=4,x=sheet->offx; width<sheet->maxx; width+=col,++x)
461 {
462 col=columnwidth(sheet,x,sheet->curz);
463 if (bufsz<(size_t)(col*UTF8SZ+1)) buf=realloc(buf,bufsz=(size_t)(col*UTF8SZ+1));
464 snprintf(buf,bufsz,"%d",x);
465 if (mbslen(buf)>col) {
466 buf[col-1]='$';
467 buf[col]='\0';
468 }
469 adjust(CENTER,buf,(size_t)col);
470 assert(sheet->maxx>=width);
471 if ((sheet->maxx-width)<col) buf[sheet->maxx-width]='\0';
472 mvwaddstr(stdscr,sheet->oriy,sheet->orix+width,buf);
473 }
474
475 /* draw y numbers */
476 for (y=1; y<(sheet->maxy-1); ++y) (void)mvwprintw(stdscr,sheet->oriy+y,sheet->orix,"%-4d",y-1+sheet->offy);
477
478 (void)wattroff(stdscr,DEF_NUMBER);
479
480 /* draw z number */
481 (void)mvwprintw(stdscr,sheet->oriy,sheet->orix,"%3d",sheet->curz);
482 }
483
484 /* draw elements */
485 for (y=header; y<sheet->maxy-1; ++y) for (width=4*header,x=sheet->offx; width<sheet->maxx; width+=columnwidth(sheet,x,sheet->curz),++x)
486 {
487 size_t size,realsize,fill,cutoff;
488 int realx;
489
490 realx=x;
491 cutoff=0;
492 if (x==sheet->offx) while (shadowed(sheet,realx,y-header+sheet->offy,sheet->curz))
493 {
494 --realx;
495 cutoff+=columnwidth(sheet,realx,sheet->curz);
496 }
497 if ((size=cellwidth(sheet,realx,y-header+sheet->offy,sheet->curz)))
498 {
499 int invert;
500
501 if (bufsz<(size*UTF8SZ+1)) buf=realloc(buf,bufsz=(size*UTF8SZ+1));
502 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);
503 adjust(getadjust(sheet,realx,y-header+sheet->offy,sheet->curz),buf,size);
504 assert(size>=cutoff);
505 if (width+((int)(size-cutoff))>=sheet->maxx)
506 {
507 *(buf+cutoff+sheet->maxx-width)='\0';
508 realsize=sheet->maxx-width+cutoff;
509 }
510 else realsize=size;
511 invert=
512 (
513 (sheet->mark1x!=-1) &&
514 ((x>=sheet->mark1x && x<=sheet->mark2x) || (x>=sheet->mark2x && x<=sheet->mark1x)) &&
515 ((y-header+sheet->offy>=sheet->mark1y && y-header+sheet->offy<=sheet->mark2y) || (y-header+sheet->offy>=sheet->mark2y && y-header+sheet->offy<=sheet->mark1y)) &&
516 ((sheet->curz>=sheet->mark1z && sheet->curz<=sheet->mark2z) || (sheet->curz>=sheet->mark2z && sheet->curz<=sheet->mark1z))
517 );
518 if (x==sheet->curx && (y-header+sheet->offy)==sheet->cury) invert=(sheet->marking ? 1 : 1-invert);
519 if (invert) (void)wattron(stdscr,DEF_CELLCURSOR);
520 if (isbold(sheet,realx,y-header+sheet->offy,sheet->curz)) wattron(stdscr,A_BOLD);
521 if (underlined(sheet,realx,y-header+sheet->offy,sheet->curz)) wattron(stdscr,A_UNDERLINE);
522 (void)mvwaddstr(stdscr,sheet->oriy+y,sheet->orix+width,buf+cutoff);
523 for (fill=mbslen(buf+cutoff); fill<realsize; ++fill) (void)waddch(stdscr,(chtype)(unsigned char)' ');
524 wstandend(stdscr);
525 }
526 }
527
528 /* draw contents of current element */
529 if (bufsz<(unsigned int)(sheet->maxx*UTF8SZ+1)) buf=realloc(buf,bufsz=(sheet->maxx*UTF8SZ+1));
530 label=getlabel(sheet,sheet->curx,sheet->cury,sheet->curz);
531 assert(label!=(const char*)0);
532 moveonly=sheet->moveonly ? *_("V") : *_("E");
533 if (*label=='\0') sprintf(pbuf,"%c @(%d,%d,%d)=",moveonly,sheet->curx,sheet->cury,sheet->curz);
534 else sprintf(pbuf,"%c @(%s)=",moveonly,label);
535 (void)strncpy(buf,pbuf,bufsz);
536 buf[bufsz-1] = 0;
537 if ((err=geterror(sheet,sheet->curx,sheet->cury,sheet->curz))!=(const char*)0)
538 {
539 (void)strncpy(buf, err, bufsz);
540 free(err);
541 }
542 else
543 {
544 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));
545 if (getcont(sheet,sheet->curx,sheet->cury,sheet->curz,1) && mbslen(buf) < (size_t)(sheet->maxx+1-4))
546 {
547 strcat(buf," -> ");
548 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));
549 }
550 }
551 *mbspos(buf, sheet->maxx) = 0;
552 (void)mvwaddstr(stdscr,sheet->oriy+sheet->maxy-1,sheet->orix,buf);
553 for (col=mbslen(buf); col<sheet->maxx; ++col) (void)waddch(stdscr,' ');
554 }
555
556
557 /* line_file -- line editor function for file name entry */
558 const char *line_file(const char *file, const char *pattern, const char *title, int create)
559 {
560 static char buf[PATH_MAX] = "";
561 int rc;
562 size_t dummy1 = 0, dummy2 = 0;
563
564 if (file) strncpy(buf, file, sizeof(buf));
565 buf[sizeof(buf)-1] = 0;
566 rc = line_edit((Sheet*)0, buf, sizeof(buf), title, &dummy1, &dummy2);
567 if (rc < 0) return NULL;
568 return buf;
569 }
570
571
572 /* line_edit -- line editor function */
573 int line_edit(Sheet *sheet, char *buf, size_t size, const char *prompt, size_t *x, size_t *offx)
574 {
575 size_t promptlen;
576 char *src, *dest;
577 int i,mx,my,insert;
578 chtype c;
579
580 assert(buf!=(char*)0);
581 assert(prompt!=(char*)0);
582 assert(x!=(size_t*)0);
583 assert(offx!=(size_t*)0);
584
585 (void)curs_set(1);
586 mx=COLS;
587 my=LINES;
588 promptlen=mbslen(prompt)+1;
589 (void)mvwaddstr(stdscr,LINES-1,0,prompt); (void)waddch(stdscr,(chtype)(unsigned char)' ');
590 insert=1;
591
592 do {
593 /* correct offx to cursor stays visible */
594 if (*x<*offx) *offx=*x;
595 if ((*x-*offx)>(mx-promptlen-1)) *offx=*x-mx+promptlen+1;
596
597 /* display buffer */
598 (void)wmove(stdscr,LINES-1,(int)promptlen);
599 src = mbspos(buf, *offx);
600 dest = mbspos(buf, *offx+COLS-promptlen);
601 for (; *src && src < dest; src++) (void)waddch(stdscr,(chtype)(unsigned char)(*src));
602 if (i!=mx) (void)wclrtoeol(stdscr);
603
604 /* show cursor */
605 (void)wmove(stdscr,LINES-1,(int)(*x-*offx+promptlen));
606
607 src = dest = mbspos(buf, *x);
608 c=wgetc();
609 if (sheet!=(Sheet*)0 && sheet->moveonly) switch (c) {
610 /* ^o -- switch back to line editor */
611 case '\t':
612 case '\017': sheet->moveonly=0; break;
613
614 /* v -- insert value of current cell */
615 case 'v': {
616 char valbuf[1024];
617
618 printvalue(valbuf,sizeof(valbuf),0,1,getscientific(sheet,sheet->curx,sheet->cury,sheet->curz),-1,sheet,sheet->curx,sheet->cury,sheet->curz);
619 if (strlen(buf)+strlen(valbuf) >= (size-1)) break;
620 (void)memmove(src+strlen(valbuf), src, strlen(src));
621 (void)memcpy(src, valbuf, strlen(valbuf));
622 (*x) += mbslen(valbuf);
623 break;
624 }
625
626 /* p -- insert position of current cell */
627 case 'p': {
628 char valbuf[1024];
629
630 sprintf(valbuf,"(%d,%d,%d)",sheet->curx,sheet->cury,sheet->curz);
631 if (strlen(buf)+strlen(valbuf) >= (size-1)) break;
632 (void)memmove(src+strlen(valbuf), src, strlen(src));
633 (void)memcpy(src, valbuf, strlen(valbuf));
634 (*x) += mbslen(valbuf);
635 break;
636 }
637
638 /* default -- move around in sheet */
639 default:
640 (void)do_sheetcmd(sheet,c,1);
641 redraw_sheet(sheet);
642 break;
643
644 } else switch (c) {
645 /* UP */
646 case K_UP: break;
647
648 /* LEFT */
649 case K_LEFT: if (*x > 0) (*x)--; break;
650
651 /* RIGHT */
652 case K_RIGHT: if (*x < mbslen(buf)) (*x)++; break;
653
654 /* BACKSPACE */
655 case K_BACKSPACE:
656 if (*x > 0) {
657 memmove(mbspos(src, -1), src, strlen(src)+1);
658 (*x)--;
659 }
660 break;
661
662 /* C-i -- file name completion */
663 case '\t':
664 completefile(buf, src, size);
665 break;
666
667 /* DC */
668 case K_DC:
669 src = mbspos(dest, 1);
670 if (*x < strlen(buf)) memmove(dest, src, strlen(src)+1);
671 break;
672
673 /* HOME */
674 case K_HOME:
675 *x = 0;
676 break;
677
678 /* END */
679 case K_END:
680 *x = mbslen(buf);
681 break;
682
683 /* IC */
684 case KEY_IC:
685 insert=1-insert;
686 break;
687
688 /* EIC */
689 case KEY_EIC:
690 insert=0;
691 break;
692
693 /* control t */
694 case '\024':
695 if (*x > 0) {
696 char c, *end;
697
698 dest = mbspos(src, -1);
699 if (*x == mbslen(buf)) {
700 src = dest;
701 dest = mbspos(src, -1);
702 (*x)--;
703 }
704 end = mbspos(src, 1);
705
706 while (src != end) {
707 c = *src;
708 memmove(dest+1, dest, src-dest);
709 *dest = c;
710 src++;
711 dest++;
712 }
713 (*x)++;
714 }
715 break;
716
717 /* control backslash */
718 case '\034': {
719 int level;
720 char open = 0, close = 0, dir = 1;
721
722 switch (*dest) {
723 case ')': dir = -1;
724 case '(': open = '('; close = ')'; break;
725 case '}': dir = -1;
726 case '{': open = '{'; close = '}'; break;
727 case ']': dir = -1;
728 case '[': open = '['; close = ']'; break;
729 default: break;
730 }
731
732 level = dir;
733 while (*dest && level) {
734 dest += dir;
735 if (*dest == open) level--;
736 else if (*dest == close) level++;
737 }
738 if (!level) *x = mbslen(buf)-mbslen(dest);
739 break;
740 }
741
742 /* DL */
743 case KEY_DL:
744 *src = '\0';
745 break;
746
747 /* control o */
748 case '\017':
749 if (sheet!=(Sheet*)0) sheet->moveonly=1;
750 break;
751
752 /* default */
753 default:
754 if (((unsigned int)c) < ' ' || ((unsigned int)c) >= 256) break;
755 if (strlen(buf) >= (size-1)) {
756 if (is_mbcont(c)) {
757 dest = mbspos(src, -1);
758 memmove(dest, src, strlen(src)+1);
759 }
760 break;
761 }
762 if (insert || is_mbcont(c)) memmove(src+1, src, strlen(src)+1);
763 else {
764 if (is_mbchar(*src)) memmove(src+1, mbspos(src, 1), strlen(mbspos(src, 1))+1);
765 if (!*src) *(src+1) = '\0';
766 }
767 *src = (char)c;
768 if (!is_mbcont(c)) (*x)++;
769 break;
770 }
771
772 } while (c != K_ENTER && c != KEY_CANCEL && (c != K_UP || (sheet!=(Sheet*)0 && sheet->moveonly)));
773
774 if (sheet) sheet->moveonly=0;
775 (void)curs_set(0);
776 (void)wmove(stdscr,LINES-1,0);
777 (void)wclrtoeol(stdscr);
778
779 switch (c) {
780 case KEY_CANCEL: return -1;
781 case K_UP: return -2;
782 default: return 0;
783 }
784 }
785
786 /* line_ok -- one line yes/no menu */
787 int line_ok(const char *prompt, int curx)
788 {
789
790 MenuChoice menu[3];
791 int result;
792
793
794
795 assert(curx==0 || curx==1);
796
797 menu[0].str=mystrmalloc(_("nN)o")); menu[0].c='\0';
798 menu[1].str=mystrmalloc(_("yY)es")); menu[1].c='\0';
799 menu[2].str=(char*)0;
800 result=line_menu(prompt,menu,curx);
801 free(menu[0].str);
802 free(menu[1].str);
803 return (result);
804 }
805
806 /* line_menu -- one line menu */
807 /* Notes */
808 /*
809
810 The choices are terminated by the last element having a (const char*)str
811 field. Each item can be chosen by tolower(*str) or by the key stored in
812 the c field. Use a space as first character of str, if you only want the
813 function key to work.
814
815 */
816
817 int line_menu(const char *prompt, const MenuChoice *choice, int curx)
818 {
819
820 int maxx,x,width,offx;
821 chtype c;
822 size_t promptlen;
823
824
825
826 assert(prompt!=(const char*)0);
827 assert(choice!=(const MenuChoice*)0);
828 assert(curx>=0);
829
830 mvwaddstr(stdscr,LINES-1,0,prompt);
831 promptlen = mbslen(prompt);
832 for (maxx=0; (choice+maxx)->str!=(const char*)0; ++maxx);
833 offx=0;
834 do
835 {
836 (void)wmove(stdscr,LINES-1,(int)promptlen);
837 /* correct offset so choice is visible */
838 if (curx<=offx) offx=curx;
839 else do
840 {
841 for (width=promptlen,x=offx; x<maxx && width+((int)mbslen((choice+x)->str+1))+1<=COLS; width+=((int)(mbslen((choice+x)->str)))+1,++x);
842 --x;
843 if (x<curx) ++offx;
844 } while (x<curx);
845
846 /* show visible choices */
847 for (width=promptlen,x=offx; x<maxx && width+((int)mbslen((choice+x)->str+1))+1<=COLS; width+=mbslen((choice+x)->str+1)+1,++x)
848 {
849 (void)waddch(stdscr,(chtype)(unsigned char)' ');
850 if (x==curx) (void)wattron(stdscr,DEF_MENU);
851 (void)waddstr(stdscr,(char*)(choice+x)->str+1);
852 if (x==curx) (void)wattroff(stdscr,DEF_MENU);
853 }
854
855 if (width<COLS) (void)wclrtoeol(stdscr);
856 switch (c=wgetc())
857 {
858 /* KEY_LEFT -- move to previous item */
859 case K_BACKSPACE:
860 case K_LEFT: if (curx>0) --curx; else curx=maxx-1; break;
861
862 /* Space, Tab, KEY_RIGHT -- move to next item */
863 case ' ':
864 case '\t':
865 case K_RIGHT: if (curx<(maxx-1)) ++curx; else curx=0; break;
866
867 /* default -- search choice keys */
868 default:
869 {
870 int i;
871
872 for (i=0; (choice+i)->str!=(const char*)0; ++i)
873 {
874 if ((c<256 && tolower(c)==*((choice+i)->str)) || (choice+i)->c==c)
875 {
876 c=K_ENTER;
877 curx=i;
878 }
879 }
880 }
881
882 }
883 }
884 while (c!=K_ENTER && c!=K_DOWN && c!=KEY_CANCEL && c!=K_UP);
885 (void)wmove(stdscr,LINES-1,0);
886 (void)wclrtoeol(stdscr);
887 switch (c)
888 {
889 case KEY_CANCEL: return -1;
890 case K_UP: return -2;
891 default: return curx;
892 }
893 }
894
895 /* line_msg -- one line message which will be cleared by someone else */
896 void line_msg(const char *prompt, const char *msg)
897 {
898
899 int width;
900
901
902
903 assert(msg!=(const char*)0);
904 if (!*msg) msg = _("Use F0, F10 or / for menu");
905
906 if (!batch)
907 {
908 width=1;
909 mvwaddch(stdscr,LINES-1,0,(chtype)(unsigned char)'[');
910 if (prompt!=(const char*)0)
911 {
912 for (; width<COLS && *prompt!='\0'; ++width,++prompt) (void)waddch(stdscr,(chtype)(unsigned char)(*prompt));
913 if (width<COLS) { (void)waddch(stdscr,(chtype)(unsigned char)' '); ++width; }
914 }
915 for (; width<COLS && *msg!='\0'; ++width,++msg) (void)waddch(stdscr,(chtype)(unsigned char)(*msg));
916 if (width<COLS) (void)waddch(stdscr,(chtype)(unsigned char)']');
917 if (width+1<COLS) (void)wclrtoeol(stdscr);
918 }
919 else
920 {
921 if (prompt) fprintf(stderr,_("line %u: %s %s\n"),batchln,prompt,msg);
922 else fprintf(stderr,_("line %u: %s\n"),batchln,msg);
923 exit(1);
924 }
925 }
926
927
928 void show_text(const char *text)
929 {
930 int i;
931 char *end, *stripped;
932
933 stripped = striphtml(text);
934 text = stripped-1;
935
936 while (text) {
937 (void)clear();
938 for (i = 0; i < LINES-2 && text; i++) {
939 end = strchr(++text, '\n');
940 if (*text == '\f') break;
941 if (end) *end = 0;
942 (void)move(i,(COLS-mbslen(text))/2);
943 (void)addstr(text);
944 text = end;
945 }
946 (void)move(i+1, (COLS-29)/2); (void)addstr(_("[ Press any key to continue ]"));
947 (void)refresh();
948 (void)getch();
949 }
950
951 free(stripped);
952 }
953
954 /* keypressed -- get keypress, if there is one */
955 int keypressed(void)
956 {
957 (void)nodelay(stdscr,TRUE);
958 if (getch()==ERR)
959 {
960 (void)nodelay(stdscr,FALSE);
961 return 0;
962 }
963 else
964 {
965 (void)nodelay(stdscr,FALSE);
966 return 1;
967 }
968 }
969
970
971 /* wgetc */
972 static Key wgetc(void)
973 {
974
975 chtype c;
976
977
978 doupdate();
979 refresh();
980 switch (c=wgetch(stdscr))
981 {
982 /* LEFT */
983 case KEY_LEFT:
984 case '\02': return K_LEFT;
985
986 /* RIGHT */
987 case KEY_RIGHT:
988 case '\06': return K_RIGHT;
989
990 /* UP */
991 case KEY_UP:
992 case '\020': return K_UP;
993
994 /* DOWN */
995 case KEY_DOWN:
996 case '\016': return K_DOWN;
997
998 /* BACKSPACE */
999 case KEY_BACKSPACE:
1000 case '\010': return K_BACKSPACE;
1001
1002 /* DC */
1003 case KEY_DC:
1004 case '\04':
1005 case '\177': return K_DC;
1006
1007 /* CANCEL */
1008 case '\03':
1009 case '\07': return KEY_CANCEL;
1010
1011 /* ENTER */
1012 case KEY_ENTER:
1013 case '\r':
1014 case '\n': return K_ENTER;
1015
1016 /* HOME */
1017 case KEY_HOME:
1018 case '\01': return K_HOME;
1019
1020 /* END */
1021 case KEY_END:
1022 case '\05': return K_END;
1023
1024 /* DL */
1025 case '\013': return KEY_DL;
1026
1027 /* NPAGE */
1028 case KEY_NPAGE:
1029 case '\026': return K_NPAGE;
1030
1031 /* PPAGE */
1032 case KEY_PPAGE: return K_PPAGE;
1033
1034 /* Control Y, copy */
1035 case '\031': return K_COPY;
1036
1037 /* Control R, recalculate sheet */
1038 case '\022': return K_RECALC;
1039
1040 /* Control S, clock sheet */
1041 case '\023': return K_CLOCK;
1042
1043 /* Control X, get one more key */
1044 case '\030':
1045 {
1046 switch (wgetch(stdscr))
1047 {
1048 /* C-x < -- BPAGE */
1049 case KEY_PPAGE:
1050 case '<': return K_BPAGE;
1051
1052 /* C-x > -- FPAGE */
1053 case KEY_NPAGE:
1054 case '>': return K_FPAGE;
1055
1056 /* C-x C-c -- QUIT */
1057 case '\03': return K_QUIT;
1058
1059 /* C-x C-s -- SAVE */
1060 case '\023': return K_SAVE;
1061
1062 /* C-x C-r -- LOAD */
1063 case '\022': return K_LOAD;
1064
1065 /* default -- INVALID, general invalid value */
1066 default: return K_INVALID;
1067
1068 }
1069 }
1070
1071 /* ESC, get one more key */
1072 case '\033':
1073 {
1074 switch (wgetch(stdscr))
1075 {
1076 /* M-v -- PPAGE */
1077 case 'v': return K_PPAGE;
1078
1079 /* M-Enter -- MENTER */
1080 case KEY_ENTER:
1081 case '\r':
1082 case '\n': return K_MENTER;
1083
1084 /* M-z -- SAVEQUIT */
1085 case 'z': return K_SAVEQUIT;
1086
1087 /* default -- INVALID, general invalid value */
1088 default: return K_INVALID;
1089
1090 }
1091 }
1092
1093 /* _("Load sheet file format:") */
1094 case KEY_F(2): return K_LOADMENU;
1095
1096 /* _("Save sheet file format:") */
1097 case KEY_F(3): return K_SAVEMENU;
1098
1099 /* default */
1100 default: return c;
1101
1102 }
1103 }
1104
1105
1106 void find_helpfile(char *buf, int size, const char *argv0)
1107 {
1108 strncpy(buf, HELPFILE, size);
1109 buf[size-1] = 0;
1110 }