bfu.c (61168B)
1 /* bfu.c 2 * (c) 2002 Mikulas Patocka 3 * This file is a part of the Links program, released under GPL. 4 */ 5 6 #include <limits.h> 7 8 #include "links.h" 9 10 unsigned char m_bar = 0; 11 12 static void menu_func(struct window *, struct links_event *, int); 13 static void mainmenu_func(struct window *, struct links_event *, int); 14 15 struct memory_list * 16 getml(void *p, ...) 17 { 18 struct memory_list *ml; 19 va_list ap; 20 int n = 0; 21 void *q = p; 22 va_start(ap, p); 23 while (q) { 24 if (n == INT_MAX) 25 overalloc(); 26 n++; 27 q = va_arg(ap, void *); 28 } 29 if ((unsigned)n 30 > (INT_MAX - sizeof(struct memory_list)) / sizeof(void *)) 31 overalloc(); 32 ml = xmalloc(sizeof(struct memory_list) + n * sizeof(void *)); 33 ml->n = n; 34 n = 0; 35 q = p; 36 va_end(ap); 37 va_start(ap, p); 38 while (q) { 39 ml->p[n++] = q; 40 q = va_arg(ap, void *); 41 } 42 va_end(ap); 43 return ml; 44 } 45 46 void 47 add_to_ml(struct memory_list **ml, ...) 48 { 49 struct memory_list *nml; 50 va_list ap; 51 int n = 0; 52 void *q; 53 if (!*ml) { 54 *ml = xmalloc(sizeof(struct memory_list)); 55 (*ml)->n = 0; 56 } 57 va_start(ap, ml); 58 while (va_arg(ap, void *)) { 59 if (n == INT_MAX) 60 overalloc(); 61 n++; 62 } 63 if ((unsigned)n + (unsigned)((*ml)->n) 64 > (INT_MAX - sizeof(struct memory_list)) / sizeof(void *)) 65 overalloc(); 66 nml = xrealloc(*ml, sizeof(struct memory_list) 67 + (n + (*ml)->n) * sizeof(void *)); 68 va_end(ap); 69 va_start(ap, ml); 70 while ((q = va_arg(ap, void *))) 71 nml->p[nml->n++] = q; 72 *ml = nml; 73 va_end(ap); 74 } 75 76 void 77 freeml(struct memory_list *ml) 78 { 79 int i; 80 if (!ml) 81 return; 82 for (i = 0; i < ml->n; i++) 83 free(ml->p[i]); 84 free(ml); 85 } 86 87 static inline int 88 txtlen(unsigned char *s) 89 { 90 return strlen((char *)s); 91 } 92 93 static unsigned 94 select_hotkey(struct terminal *term, unsigned char *text, unsigned char *hotkey, 95 unsigned *hotkeys, int n) 96 { 97 unsigned c; 98 if (hotkey == M_BAR) 99 return 0; 100 if (text) { 101 text = stracpy(get_text_translation(text, term)); 102 charset_upcase_string(&text, 0); 103 } 104 hotkey = get_text_translation(hotkey, term); 105 while (1) { 106 int i; 107 c = GET_TERM_CHAR(term, &hotkey); 108 if (!c) 109 break; 110 c = charset_upcase(c, 0); 111 for (i = 0; i < n; i++) 112 if (hotkeys[i] == c) 113 continue; 114 if (!text || strchr((char *)text, c)) 115 break; 116 } 117 free(text); 118 return c; 119 } 120 121 void 122 do_menu_selected(struct terminal *term, struct menu_item *items, void *data, 123 int selected, void (*free_function)(void *), void *free_data) 124 { 125 int i; 126 struct menu *menu; 127 for (i = 0; items[i].text; i++) 128 if (i == (INT_MAX - sizeof(struct menu)) / sizeof(unsigned)) 129 overalloc(); 130 menu = 131 xmalloc(sizeof(struct menu) + (!i ? 0 : i - 1) * sizeof(unsigned)); 132 menu->selected = selected; 133 menu->view = 0; 134 menu->ni = i; 135 menu->items = items; 136 menu->data = data; 137 menu->free_function = free_function; 138 menu->free_data = free_data; 139 for (i = 0; i < menu->ni; i++) 140 menu->hotkeys[i] = select_hotkey( 141 term, items[i].text, items[i].hotkey, menu->hotkeys, i); 142 add_window(term, menu_func, menu); 143 } 144 145 void 146 do_menu(struct terminal *term, struct menu_item *items, void *data) 147 { 148 do_menu_selected(term, items, data, 0, NULL, NULL); 149 } 150 151 static void 152 select_menu(struct terminal *term, struct menu *menu) 153 { 154 struct menu_item *it; 155 void (*func)(struct terminal *, void *, void *); 156 void *data1; 157 void *data2; 158 if (menu->selected < 0 || menu->selected >= menu->ni) 159 return; 160 it = &menu->items[menu->selected]; 161 func = it->func; 162 data1 = it->data; 163 data2 = menu->data; 164 if (it->hotkey == M_BAR) 165 return; 166 flush_terminal(term); 167 if (!it->in_m) { 168 struct window *win = NULL; 169 struct list_head *lwin; 170 foreach (struct window, win, lwin, term->windows) { 171 if (win->handler != menu_func 172 && win->handler != mainmenu_func) 173 break; 174 lwin = lwin->prev; 175 delete_window(win); 176 } 177 } 178 func(term, data1, data2); 179 } 180 181 static unsigned char * 182 get_rtext(unsigned char *rtext) 183 { 184 if (!strcmp(cast_const_char rtext, ">")) 185 return MENU_SUBMENU; 186 return rtext; 187 } 188 189 static void 190 count_menu_size(struct terminal *term, struct menu *menu) 191 { 192 int sx = term->x; 193 int sy = term->y; 194 int mx = 4; 195 int my; 196 for (my = 0; my < menu->ni; my++) { 197 int s; 198 s = txtlen(get_text_translation(menu->items[my].text, term)) 199 + txtlen(get_text_translation( 200 get_rtext(menu->items[my].rtext), term)) 201 + MENU_HOTKEY_SPACE 202 * (get_text_translation( 203 get_rtext(menu->items[my].rtext), term)[0] 204 != 0); 205 s += 4; 206 if (s > mx) 207 mx = s; 208 } 209 my += 2; 210 if (mx > sx) 211 mx = sx; 212 if (my > sy) 213 my = sy; 214 menu->nview = my - 2; 215 menu->xw = mx; 216 menu->yw = my; 217 if ((menu->x = menu->xp) < 0) 218 menu->x = 0; 219 if ((menu->y = menu->yp) < 0) 220 menu->y = 0; 221 if (menu->x + mx > sx) 222 menu->x = sx - mx; 223 if (menu->y + my > sy) 224 menu->y = sy - my; 225 } 226 227 static void 228 scroll_menu(struct menu *menu, int d) 229 { 230 int c = 0; 231 int w = menu->nview; 232 int scr_i = SCROLL_ITEMS > (w - 1) / 2 ? (w - 1) / 2 : SCROLL_ITEMS; 233 if (scr_i < 0) 234 scr_i = 0; 235 if (w < 0) 236 w = 0; 237 menu->selected += d; 238 while (1) { 239 if (c++ > menu->ni) { 240 menu->selected = -1; 241 menu->view = 0; 242 return; 243 } 244 if (menu->selected < 0) 245 menu->selected = 0; 246 if (menu->selected >= menu->ni) 247 menu->selected = menu->ni - 1; 248 if (menu->ni && menu->items[menu->selected].hotkey != M_BAR) 249 break; 250 menu->selected += d; 251 } 252 if (menu->selected < menu->view + scr_i) 253 menu->view = menu->selected - scr_i; 254 if (menu->selected >= menu->view + w - scr_i - 1) 255 menu->view = menu->selected - w + scr_i + 1; 256 if (menu->view > menu->ni - w) 257 menu->view = menu->ni - w; 258 if (menu->view < 0) 259 menu->view = 0; 260 } 261 262 static void 263 display_menu_txt(struct terminal *term, void *menu_) 264 { 265 struct menu *menu = (struct menu *)menu_; 266 int p, s; 267 fill_area(term, menu->x + 1, menu->y + 1, menu->xw - 2, menu->yw - 2, 268 ' ', COLOR_MENU_TEXT); 269 draw_frame(term, menu->x, menu->y, menu->xw, menu->yw, COLOR_MENU_FRAME, 270 1); 271 set_window_ptr(menu->win, menu->x, menu->y); 272 for (p = menu->view, s = menu->y + 1; 273 p < menu->ni && p < menu->view + menu->yw - 2; p++, s++) { 274 int x; 275 int h = 0; 276 unsigned c; 277 unsigned char *tmptext = 278 get_text_translation(menu->items[p].text, term); 279 unsigned char co; 280 if (p == menu->selected) { 281 h = 1; 282 co = COLOR_MENU_SELECTED; 283 } else 284 co = COLOR_MENU_TEXT; 285 if (h) { 286 set_cursor(term, menu->x + 1, s, term->x - 1, 287 term->y - 1); 288 /*set_window_ptr(menu->win, menu->x+3, s+1);*/ 289 set_window_ptr(menu->win, menu->x + menu->xw, s); 290 fill_area(term, menu->x + 1, s, menu->xw - 2, 1, ' ', 291 co); 292 } 293 if (menu->items[p].hotkey != M_BAR || (tmptext[0])) { 294 unsigned char *rt = get_text_translation( 295 get_rtext(menu->items[p].rtext), term); 296 int l = strlen((char *)rt); 297 for (x = 0;; x++) { 298 c = GET_TERM_CHAR(term, &rt); 299 if (!c) 300 break; 301 if (menu->xw - 4 >= l - x) 302 set_char(term, 303 menu->x + menu->xw - 2 - l + x, 304 s, c, co); 305 } 306 for (x = 0; x < menu->xw - 4; x++) { 307 c = GET_TERM_CHAR(term, &tmptext); 308 if (!c) 309 break; 310 if (!h 311 && charset_upcase(c, 0) 312 == menu->hotkeys[p]) { 313 h = 1; 314 set_char(term, menu->x + x + 2, s, c, 315 COLOR_MENU_HOTKEY); 316 } else 317 set_char(term, menu->x + x + 2, s, c, 318 co); 319 } 320 } else { 321 set_char(term, menu->x, s, 0xc3, 322 COLOR_MENU_FRAME | ATTR_FRAME); 323 fill_area(term, menu->x + 1, s, menu->xw - 2, 1, 0xc4, 324 COLOR_MENU_FRAME | ATTR_FRAME); 325 set_char(term, menu->x + menu->xw - 1, s, 0xb4, 326 COLOR_MENU_FRAME | ATTR_FRAME); 327 } 328 } 329 } 330 331 static void 332 menu_func(struct window *win, struct links_event *ev, int fwd) 333 { 334 int s = 0; 335 int xp, yp; 336 struct menu *menu = win->data; 337 menu->win = win; 338 switch ((int)ev->ev) { 339 case EV_INIT: 340 case EV_RESIZE: 341 get_parent_ptr(win, &menu->xp, &menu->yp); 342 count_menu_size(win->term, menu); 343 goto xxx; 344 case EV_REDRAW: 345 get_parent_ptr(win, &xp, &yp); 346 if (xp != menu->xp || yp != menu->yp) { 347 menu->xp = xp; 348 menu->yp = yp; 349 count_menu_size(win->term, menu); 350 } 351 xxx: 352 menu->selected--; 353 scroll_menu(menu, 1); 354 draw_to_window(win, display_menu_txt, menu); 355 break; 356 case EV_MOUSE: 357 if ((ev->b & BM_ACT) == B_MOVE) 358 break; 359 if ((ev->b & BM_BUTT) == B_FOURTH 360 || (ev->b & BM_BUTT) == B_FIFTH) { 361 if ((ev->b & BM_ACT) == B_DOWN) 362 goto go_lr; 363 break; 364 } 365 if ((ev->b & BM_BUTT) == B_SIXTH) 366 break; 367 368 if (ev->x < menu->x || ev->x >= menu->x + menu->xw 369 || ev->y < menu->y || ev->y >= menu->y + menu->yw) { 370 struct window *w1 = NULL; 371 struct list_head *w1l; 372 foreachfrom (struct window, w1, w1l, win->term->windows, 373 &win->list_entry) { 374 struct menu *m1; 375 if (w1->handler == mainmenu_func) { 376 if (ev->y < 1) 377 goto del; 378 break; 379 } 380 if (w1->handler != menu_func) 381 break; 382 m1 = w1->data; 383 if (ev->x > m1->x && ev->x < m1->x + m1->xw - 1 384 && ev->y > m1->y 385 && ev->y < m1->y + m1->yw - 1) 386 goto del; 387 } 388 if ((ev->b & BM_ACT) == B_DOWN) 389 goto del; 390 if (0) 391 del: 392 delete_window_ev(win, ev); 393 } else { 394 if (!(ev->x < menu->x || ev->x >= menu->x + menu->xw 395 || ev->y < menu->y + 1 396 || ev->y >= menu->y + menu->yw - 1)) { 397 int s = ev->y - menu->y - 1 + menu->view; 398 if (s >= 0 && s < menu->ni 399 && menu->items[s].hotkey != M_BAR) { 400 menu->selected = s; 401 scroll_menu(menu, 0); 402 draw_to_window(win, display_menu_txt, 403 menu); 404 if ((ev->b & BM_ACT) == B_UP) 405 select_menu(win->term, menu); 406 } 407 } 408 } 409 break; 410 case EV_KBD: 411 if (ev->y & KBD_PASTING) 412 break; 413 if (ev->x == KBD_LEFT || ev->x == KBD_RIGHT) { 414 go_lr: 415 if (win->list_entry.next == &win->term->windows) 416 goto mm; 417 if (list_struct(win->list_entry.next, struct window) 418 ->handler 419 == mainmenu_func) 420 goto mm; 421 if (ev->ev == EV_MOUSE && (ev->b & BM_BUTT) == B_FIFTH) 422 goto mm; 423 if (ev->ev == EV_KBD && ev->x == KBD_RIGHT) 424 goto enter; 425 delete_window(win); 426 break; 427 } 428 if (ev->x == KBD_ESC) { 429 if (win->list_entry.next == &win->term->windows) 430 ev = NULL; 431 else if (list_struct(win->list_entry.next, 432 struct window) 433 ->handler 434 != mainmenu_func) 435 ev = NULL; 436 delete_window_ev(win, ev); 437 break; 438 } 439 if (KBD_ESCAPE_MENU(ev->x) || ev->y & KBD_ALT) { 440 mm: 441 delete_window_ev(win, ev); 442 break; 443 } 444 if (ev->x == KBD_UP) 445 scroll_menu(menu, -1); 446 else if (ev->x == KBD_DOWN) 447 scroll_menu(menu, 1); 448 else if (ev->x == KBD_HOME 449 || (upcase(ev->x) == 'A' && ev->y & KBD_CTRL)) { 450 menu->selected = -1; 451 scroll_menu(menu, 1); 452 } else if (ev->x == KBD_END 453 || (upcase(ev->x) == 'E' && ev->y & KBD_CTRL)) { 454 menu->selected = menu->ni; 455 scroll_menu(menu, -1); 456 } else if (ev->x == KBD_PAGE_UP 457 || (upcase(ev->x) == 'B' && ev->y & KBD_CTRL)) { 458 if ((menu->selected -= menu->yw - 3) < -1) 459 menu->selected = -1; 460 if ((menu->view -= menu->yw - 2) < 0) 461 menu->view = 0; 462 scroll_menu(menu, -1); 463 } else if (ev->x == KBD_PAGE_DOWN 464 || (upcase(ev->x) == 'F' && ev->y & KBD_CTRL)) { 465 if ((menu->selected += menu->yw - 3) > menu->ni) 466 menu->selected = menu->ni; 467 if ((menu->view += menu->yw - 2) 468 >= menu->ni - menu->yw + 2) 469 menu->view = menu->ni - menu->yw + 2; 470 scroll_menu(menu, 1); 471 } else if (ev->x > ' ') { 472 int i; 473 for (i = 0; i < menu->ni; i++) { 474 if (charset_upcase(ev->x, 0) 475 == menu->hotkeys[i]) { 476 menu->selected = i; 477 scroll_menu(menu, 0); 478 s = 1; 479 } 480 } 481 } 482 draw_to_window(win, display_menu_txt, menu); 483 if (s || ev->x == KBD_ENTER || ev->x == ' ') 484 enter: 485 select_menu(win->term, menu); 486 break; 487 case EV_ABORT: 488 if (menu->items->free_i) { 489 int i; 490 for (i = 0; i < menu->ni; i++) { 491 if (menu->items[i].free_i & MENU_FREE_TEXT) 492 free(menu->items[i].text); 493 if (menu->items[i].free_i & MENU_FREE_RTEXT) 494 free(menu->items[i].rtext); 495 if (menu->items[i].free_i & MENU_FREE_HOTKEY) 496 free(menu->items[i].hotkey); 497 } 498 if (menu->items->free_i & MENU_FREE_ITEMS) 499 free(menu->items); 500 } 501 if (menu->free_function) 502 register_bottom_half(menu->free_function, 503 menu->free_data); 504 break; 505 } 506 } 507 508 void 509 do_mainmenu(struct terminal *term, struct menu_item *items, void *data, int sel) 510 { 511 int i; 512 struct mainmenu *menu; 513 for (i = 0; items[i].text; i++) 514 if (i == (INT_MAX - sizeof(struct mainmenu)) / sizeof(unsigned)) 515 overalloc(); 516 menu = xmalloc(sizeof(struct mainmenu) 517 + (!i ? 0 : i - 1) * sizeof(unsigned)); 518 menu->selected = sel == -1 ? 0 : sel; 519 menu->ni = i; 520 menu->items = items; 521 menu->data = data; 522 for (i = 0; i < menu->ni; i++) 523 menu->hotkeys[i] = select_hotkey(term, NULL, items[i].hotkey, 524 menu->hotkeys, i); 525 add_window(term, mainmenu_func, menu); 526 if (sel != -1) { 527 struct links_event ev = { EV_KBD, KBD_ENTER, 0, 0 }; 528 struct window *win = 529 list_struct(term->windows.next, struct window); 530 win->handler(win, (struct links_event *)&ev, 0); 531 } 532 } 533 534 static void 535 display_mainmenu(struct terminal *term, void *menu_) 536 { 537 struct mainmenu *menu = (struct mainmenu *)menu_; 538 int i; 539 int p = 2; 540 fill_area(term, 0, 0, term->x, 1, ' ', COLOR_MAINMENU); 541 for (i = 0; i < menu->ni; i++) { 542 int s = 0; 543 unsigned c; 544 unsigned char *tmptext = 545 get_text_translation(menu->items[i].text, term); 546 unsigned char co; 547 if (i == menu->selected) { 548 s = 1; 549 co = COLOR_MAINMENU_SELECTED; 550 } else { 551 co = COLOR_MAINMENU; 552 } 553 if (i == menu->selected) { 554 fill_area(term, p, 0, 2, 1, ' ', co); 555 menu->sp = p; 556 set_cursor(term, p, 0, term->x - 1, term->y - 1); 557 set_window_ptr(menu->win, p, 1); 558 } 559 p += 2; 560 for (;; p++) { 561 c = GET_TERM_CHAR(term, &tmptext); 562 if (!c) 563 break; 564 if (!s && charset_upcase(c, 0) == menu->hotkeys[i]) { 565 s = 1; 566 set_char(term, p, 0, c, COLOR_MAINMENU_HOTKEY); 567 } else { 568 set_char(term, p, 0, c, co); 569 } 570 } 571 if (i == menu->selected) 572 fill_area(term, p, 0, 2, 1, ' ', co); 573 p += 2; 574 } 575 } 576 577 static void 578 select_mainmenu(struct terminal *term, struct mainmenu *menu) 579 { 580 struct menu_item *it; 581 if (menu->selected < 0 || menu->selected >= menu->ni) 582 return; 583 it = &menu->items[menu->selected]; 584 if (it->hotkey == M_BAR) 585 return; 586 if (!it->in_m) { 587 struct window *win = NULL; 588 struct list_head *lwin; 589 foreach (struct window, win, lwin, term->windows) { 590 if (win->handler != menu_func 591 && win->handler != mainmenu_func) 592 break; 593 lwin = lwin->prev; 594 delete_window(win); 595 } 596 } 597 it->func(term, it->data, menu->data); 598 } 599 600 static void 601 mainmenu_func(struct window *win, struct links_event *ev, int fwd) 602 { 603 int s = 0; 604 int in_menu; 605 struct mainmenu *menu = win->data; 606 menu->win = win; 607 switch ((int)ev->ev) { 608 case EV_INIT: 609 case EV_RESIZE: 610 /* FALLTHROUGH */ 611 case EV_REDRAW: 612 draw_to_window(win, display_mainmenu, menu); 613 break; 614 case EV_MOUSE: 615 in_menu = ev->x >= 0 && ev->x < win->term->x && ev->y >= 0 616 && ev->y < 1; 617 if ((ev->b & BM_ACT) == B_MOVE) 618 break; 619 if ((ev->b & BM_BUTT) == B_FOURTH) { 620 if ((ev->b & BM_ACT) == B_DOWN) 621 goto go_left; 622 break; 623 } 624 if ((ev->b & BM_BUTT) == B_FIFTH) { 625 if ((ev->b & BM_ACT) == B_DOWN) 626 goto go_right; 627 break; 628 } 629 if ((ev->b & BM_BUTT) == B_SIXTH) { 630 break; 631 } 632 if ((ev->b & BM_ACT) == B_DOWN && !in_menu) 633 delete_window_ev(win, ev); 634 else if (in_menu) { 635 int i; 636 int p = 2; 637 for (i = 0; i < menu->ni; i++) { 638 int o = p; 639 unsigned char *tmptext = get_text_translation( 640 menu->items[i].text, win->term); 641 p += txtlen(tmptext) + 4; 642 if (ev->x >= o && ev->x < p) { 643 menu->selected = i; 644 draw_to_window(win, display_mainmenu, 645 menu); 646 if ((ev->b & BM_ACT) == B_UP 647 || menu->items[s].in_m) 648 select_mainmenu(win->term, 649 menu); 650 break; 651 } 652 } 653 } 654 break; 655 case EV_KBD: 656 if (ev->y & KBD_PASTING) 657 break; 658 if (ev->x == ' ' || ev->x == KBD_ENTER || ev->x == KBD_DOWN 659 || ev->x == KBD_UP || ev->x == KBD_PAGE_DOWN 660 || (upcase(ev->x) == 'F' && ev->y & KBD_CTRL) 661 || ev->x == KBD_PAGE_UP 662 || (upcase(ev->x) == 'B' && ev->y & KBD_CTRL)) { 663 select_mainmenu(win->term, menu); 664 break; 665 } else if (ev->x == KBD_LEFT) { 666 go_left: 667 if (!menu->selected--) 668 menu->selected = menu->ni - 1; 669 s = 1; 670 if (fwd) 671 s = 2; 672 } else if (ev->x == KBD_RIGHT) { 673 go_right: 674 if (++menu->selected >= menu->ni) 675 menu->selected = 0; 676 s = 1; 677 if (fwd) 678 s = 2; 679 } else if (ev->x == KBD_HOME 680 || (upcase(ev->x) == 'A' && ev->y & KBD_CTRL)) { 681 menu->selected = 0; 682 s = 1; 683 } else if (ev->x == KBD_END 684 || (upcase(ev->x) == 'E' && ev->y & KBD_CTRL)) { 685 menu->selected = menu->ni - 1; 686 s = 1; 687 } else if (ev->x > ' ') { 688 int i; 689 s = 1; 690 for (i = 0; i < menu->ni; i++) { 691 if (charset_upcase(ev->x, 0) 692 == menu->hotkeys[i]) { 693 menu->selected = i; 694 s = 2; 695 } 696 } 697 } 698 if (!s) { 699 delete_window_ev(win, KBD_ESCAPE_MENU(ev->x) 700 || ev->y & KBD_ALT 701 ? ev 702 : NULL); 703 break; 704 } 705 draw_to_window(win, display_mainmenu, menu); 706 if (s == 2) 707 select_mainmenu(win->term, menu); 708 break; 709 case EV_ABORT: 710 break; 711 } 712 } 713 714 struct menu_item * 715 new_menu(int free_i) 716 { 717 struct menu_item *mi; 718 mi = mem_calloc(sizeof(struct menu_item)); 719 mi->free_i = free_i; 720 return mi; 721 } 722 723 void 724 add_to_menu(struct menu_item **mi, unsigned char *text, unsigned char *rtext, 725 unsigned char *hotkey, 726 void (*func)(struct terminal *, void *, void *), void *data, 727 int in_m, int pos) 728 { 729 struct menu_item *mii; 730 int n; 731 if (pos != -1) { 732 n = pos; 733 if ((*mi)[n].text) 734 internal("invalid menu position %d", n); 735 } else 736 for (n = 0; (*mi)[n].text; n++) 737 if (n == INT_MAX) 738 overalloc(); 739 if (((unsigned)n + 2) > INT_MAX / sizeof(struct menu_item)) 740 overalloc(); 741 mii = xrealloc(*mi, (n + 2) * sizeof(struct menu_item)); 742 *mi = mii; 743 memcpy(mii + n + 1, mii + n, sizeof(struct menu_item)); 744 mii[n].text = text; 745 mii[n].rtext = rtext; 746 mii[n].hotkey = hotkey; 747 mii[n].func = func; 748 mii[n].data = data; 749 mii[n].in_m = in_m; 750 } 751 752 void 753 do_dialog(struct terminal *term, struct dialog *dlg, struct memory_list *ml) 754 { 755 struct dialog_data *dd; 756 struct dialog_item *d; 757 int n = 0; 758 for (d = dlg->items; d->type != D_END; d++) { 759 if (n == INT_MAX) 760 overalloc(); 761 n++; 762 } 763 if ((unsigned)n > (INT_MAX - sizeof(struct dialog_data)) 764 / sizeof(struct dialog_item_data)) 765 overalloc(); 766 dd = mem_calloc(sizeof(struct dialog_data) 767 + sizeof(struct dialog_item_data) * n); 768 dd->dlg = dlg; 769 dd->n = n; 770 dd->ml = ml; 771 add_window(term, dialog_func, dd); 772 } 773 774 void 775 display_dlg_item(struct dialog_data *dlg, struct dialog_item_data *di, int sel) 776 { 777 struct terminal *term = dlg->win->term; 778 unsigned char co; 779 unsigned char *text, *t; 780 int vposlen, cposlen; 781 782 switch (di->item->type) { 783 case D_CHECKBOX: 784 /* radio or checkbox */ 785 if (di->checked) 786 print_text(term, di->x, di->y, 3, cast_uchar "[X]", 787 COLOR_DIALOG_CHECKBOX); 788 else 789 print_text(term, di->x, di->y, 3, cast_uchar "[ ]", 790 COLOR_DIALOG_CHECKBOX); 791 if (sel) { 792 set_cursor(term, di->x + 1, di->y, di->x + 1, di->y); 793 set_window_ptr(dlg->win, di->x, di->y); 794 } 795 break; 796 case D_FIELD: 797 case D_FIELD_PASS: 798 fill_area(term, di->x, di->y, di->l, 1, ' ', 799 COLOR_DIALOG_FIELD); 800 if (di->vpos > di->cpos) 801 di->vpos = di->cpos; 802 vposlen = strlen((char *)(di->cdata + di->vpos)); 803 cposlen = strlen((char *)(di->cdata + di->cpos)); 804 if (!di->l) { 805 di->vpos = di->cpos; 806 vposlen = cposlen; 807 } else { 808 while (vposlen - cposlen > di->l - 1) { 809 t = di->cdata + di->vpos; 810 GET_TERM_CHAR(term, &t); 811 di->vpos = (int)(t - di->cdata); 812 vposlen--; 813 } 814 } 815 if (di->item->type == D_FIELD_PASS) { 816 t = xmalloc(vposlen + 1); 817 memset(t, '*', vposlen); 818 t[vposlen] = 0; 819 } else { 820 t = di->cdata + di->vpos; 821 } 822 print_text(term, di->x, di->y, di->l, t, 823 COLOR_DIALOG_FIELD_TEXT); 824 if (di->item->type == D_FIELD_PASS) 825 free(t); 826 if (sel) { 827 set_cursor(term, di->x + vposlen - cposlen, di->y, 828 di->x + vposlen - cposlen, di->y); 829 set_window_ptr(dlg->win, di->x, di->y); 830 } 831 break; 832 case D_BUTTON: 833 co = sel ? COLOR_DIALOG_BUTTON_SELECTED : COLOR_DIALOG_BUTTON; 834 text = get_text_translation(di->item->text, term); 835 print_text(term, di->x, di->y, 2, cast_uchar "[ ", co); 836 print_text(term, di->x + 2, di->y, strlen((char *)text), text, 837 co); 838 print_text(term, di->x + 2 + strlen((char *)text), di->y, 2, 839 cast_uchar " ]", co); 840 if (sel) { 841 set_cursor(term, di->x + 2, di->y, di->x + 2, di->y); 842 set_window_ptr(dlg->win, di->x, di->y); 843 } 844 break; 845 default: 846 internal("display_dlg_item: unknown item: %d", di->item->type); 847 } 848 } 849 850 struct dspd { 851 struct dialog_data *dlg; 852 struct dialog_item_data *di; 853 int sel; 854 }; 855 856 static void 857 u_display_dlg_item(struct terminal *term, void *p) 858 { 859 struct dspd *d = p; 860 display_dlg_item(d->dlg, d->di, d->sel); 861 } 862 863 static void 864 x_display_dlg_item(struct dialog_data *dlg, struct dialog_item_data *di, 865 int sel) 866 { 867 struct dspd dspd; 868 dspd.dlg = dlg; 869 dspd.di = di; 870 dspd.sel = sel; 871 draw_to_window(dlg->win, u_display_dlg_item, &dspd); 872 } 873 874 static void 875 dlg_select_item(struct dialog_data *dlg, struct dialog_item_data *di) 876 { 877 if (di->item->type == D_CHECKBOX) { 878 if (!di->item->gid) 879 di->checked = *(int *)di->cdata = !*(int *)di->cdata; 880 else { 881 int i; 882 for (i = 0; i < dlg->n; i++) { 883 if (dlg->items[i].item->type == D_CHECKBOX 884 && dlg->items[i].item->gid 885 == di->item->gid) { 886 *(int *)dlg->items[i].cdata = 887 di->item->gnum; 888 dlg->items[i].checked = 0; 889 x_display_dlg_item(dlg, &dlg->items[i], 890 0); 891 } 892 } 893 di->checked = 1; 894 } 895 x_display_dlg_item(dlg, di, 1); 896 } else if (di->item->type == D_BUTTON) 897 di->item->fn(dlg, di); 898 } 899 900 static unsigned char * 901 dlg_get_history_string(struct terminal *term, struct history_item *hi, int l) 902 { 903 unsigned char *s; 904 int ch = 0; 905 s = stracpy(hi->str); 906 if (strlen(cast_const_char s) >= (size_t)l) 907 s[l - 1] = 0; 908 if (!ch) { 909 int r = (int)strlen(cast_const_char s); 910 unsigned char *p = s; 911 while (r) { 912 int chl = utf8chrlen(*p); 913 if (chl > r) { 914 *p = 0; 915 break; 916 } 917 p += chl; 918 r -= chl; 919 } 920 } 921 return s; 922 } 923 924 static void 925 dlg_set_history(struct terminal *term, struct dialog_item_data *di) 926 { 927 unsigned char *s; 928 if (di->cur_hist == &di->history) 929 s = stracpy(cast_uchar ""); 930 else 931 s = dlg_get_history_string( 932 term, list_struct(di->cur_hist, struct history_item), 933 di->item->dlen); 934 strcpy(cast_char di->cdata, cast_const_char s); 935 di->cpos = (int)strlen(cast_const_char s); 936 di->vpos = 0; 937 free(s); 938 } 939 940 static int 941 dlg_mouse(struct dialog_data *dlg, struct dialog_item_data *di, 942 struct links_event *ev) 943 { 944 switch (di->item->type) { 945 case D_BUTTON: 946 if (ev->y != di->y || ev->x < di->x 947 || ev->x >= di->x 948 + strlen((char *)get_text_translation( 949 di->item->text, dlg->win->term)) 950 + 4) 951 return 0; 952 if (dlg->selected != di - dlg->items) { 953 x_display_dlg_item(dlg, &dlg->items[dlg->selected], 0); 954 dlg->selected = (int)(di - dlg->items); 955 x_display_dlg_item(dlg, di, 1); 956 } 957 if ((ev->b & BM_ACT) == B_UP) 958 dlg_select_item(dlg, di); 959 return 1; 960 case D_FIELD: 961 case D_FIELD_PASS: 962 if (ev->y != di->y || ev->x < di->x || ev->x >= di->x + di->l) 963 return 0; 964 int p, u; 965 unsigned char *t = di->cdata; 966 p = di->x - di->vpos; 967 while (1) { 968 di->cpos = (int)(t - di->cdata); 969 if (!*t) 970 break; 971 GET_UTF_8(t, u); 972 if (!u) 973 continue; 974 p++; 975 if (p > ev->x) 976 break; 977 } 978 if (dlg->selected != di - dlg->items) { 979 x_display_dlg_item(dlg, &dlg->items[dlg->selected], 0); 980 dlg->selected = (int)(di - dlg->items); 981 x_display_dlg_item(dlg, di, 1); 982 } else 983 x_display_dlg_item(dlg, di, 1); 984 return 1; 985 case D_CHECKBOX: 986 if (ev->y != di->y || ev->x < di->x || ev->x >= di->x + 3) 987 return 0; 988 if (dlg->selected != di - dlg->items) { 989 x_display_dlg_item(dlg, &dlg->items[dlg->selected], 0); 990 dlg->selected = (int)(di - dlg->items); 991 x_display_dlg_item(dlg, di, 1); 992 } 993 if ((ev->b & BM_ACT) == B_UP) 994 dlg_select_item(dlg, di); 995 return 1; 996 } 997 return 0; 998 } 999 1000 static void 1001 redraw_dialog_items(struct terminal *term, void *dlg_) 1002 { 1003 struct dialog_data *dlg = (struct dialog_data *)dlg_; 1004 int i; 1005 for (i = 0; i < dlg->n; i++) 1006 display_dlg_item(dlg, &dlg->items[i], i == dlg->selected); 1007 } 1008 1009 static void 1010 redraw_dialog(struct terminal *term, void *dlg_) 1011 { 1012 struct dialog_data *dlg = (struct dialog_data *)dlg_; 1013 dlg->dlg->fn(dlg); 1014 redraw_dialog_items(term, dlg); 1015 } 1016 1017 static void 1018 tab_compl(struct terminal *term, void *hi_, void *win_) 1019 { 1020 struct history_item *hi = (struct history_item *)hi_; 1021 struct window *win = (struct window *)win_; 1022 struct links_event ev = { EV_REDRAW, 0, 0, 0 }; 1023 struct dialog_item_data *di = 1024 &((struct dialog_data *)win->data) 1025 ->items[((struct dialog_data *)win->data)->selected]; 1026 unsigned char *s = dlg_get_history_string(term, hi, di->item->dlen); 1027 strcpy(cast_char di->cdata, cast_const_char s); 1028 di->cpos = (int)strlen(cast_const_char s); 1029 di->vpos = 0; 1030 free(s); 1031 ev.x = term->x; 1032 ev.y = term->y; 1033 dialog_func(win, &ev, 0); 1034 } 1035 1036 static void 1037 do_tab_compl(struct terminal *term, struct list_head *history, 1038 struct window *win) 1039 { 1040 unsigned char *cdata = 1041 ((struct dialog_data *)win->data) 1042 ->items[((struct dialog_data *)win->data)->selected] 1043 .cdata; 1044 int l = (int)strlen(cast_const_char cdata), n = 0; 1045 struct history_item *hi = NULL; 1046 struct list_head *lhi; 1047 struct menu_item *items = NULL; 1048 foreach (struct history_item, hi, lhi, *history) { 1049 unsigned char *s = dlg_get_history_string(term, hi, INT_MAX); 1050 if (!strncmp(cast_const_char cdata, cast_const_char s, l)) { 1051 if (!(n & (ALLOC_GR - 1))) { 1052 if ((unsigned)n 1053 > INT_MAX / sizeof(struct menu_item) 1054 - ALLOC_GR - 1) 1055 overalloc(); 1056 items = xrealloc( 1057 items, (n + ALLOC_GR + 1) 1058 * sizeof(struct menu_item)); 1059 } 1060 items[n].text = s; 1061 items[n].rtext = cast_uchar ""; 1062 items[n].hotkey = cast_uchar ""; 1063 items[n].func = tab_compl; 1064 items[n].rtext = cast_uchar ""; 1065 items[n].data = hi; 1066 items[n].in_m = 0; 1067 items[n].free_i = MENU_FREE_ITEMS | MENU_FREE_TEXT; 1068 if (n == INT_MAX) 1069 overalloc(); 1070 n++; 1071 } else 1072 free(s); 1073 } 1074 if (n == 1) { 1075 tab_compl(term, items->data, win); 1076 free(items->text); 1077 free(items); 1078 return; 1079 } 1080 if (n) { 1081 memset(&items[n], 0, sizeof(struct menu_item)); 1082 do_menu_selected(term, items, win, n - 1, NULL, NULL); 1083 } 1084 } 1085 1086 void 1087 dialog_func(struct window *win, struct links_event *ev, int fwd) 1088 { 1089 int i; 1090 struct terminal *term = win->term; 1091 struct dialog_data *dlg = win->data; 1092 struct dialog_item_data *di; 1093 1094 dlg->win = win; 1095 1096 /* Use nonstandard event handlers */ 1097 if (dlg->dlg->handle_event 1098 && dlg->dlg->handle_event(dlg, ev) == EVENT_PROCESSED) { 1099 return; 1100 } 1101 1102 switch ((int)ev->ev) { 1103 case EV_INIT: 1104 for (i = 0; i < dlg->n; i++) { 1105 struct dialog_item_data *di = &dlg->items[i]; 1106 memset(di, 0, sizeof(struct dialog_item_data)); 1107 di->item = &dlg->dlg->items[i]; 1108 di->cdata = xmalloc(di->item->dlen); 1109 if (di->item->dlen) 1110 memcpy(di->cdata, di->item->data, 1111 di->item->dlen); 1112 if (di->item->type == D_CHECKBOX) { 1113 if (di->item->gid) { 1114 if (*(int *)di->cdata == di->item->gnum) 1115 di->checked = 1; 1116 } else if (*(int *)di->cdata) 1117 di->checked = 1; 1118 } 1119 init_list(di->history); 1120 di->cur_hist = &di->history; 1121 if (di->item->type == D_FIELD 1122 || di->item->type == D_FIELD_PASS) { 1123 if (di->item->history) { 1124 struct history_item *j = NULL; 1125 struct list_head *lj; 1126 foreach (struct history_item, j, lj, 1127 di->item->history->items) { 1128 struct history_item *hi; 1129 size_t sl = strlen( 1130 cast_const_char j->str); 1131 if (sl > INT_MAX 1132 - sizeof( 1133 struct 1134 history_item)) 1135 overalloc(); 1136 hi = xmalloc( 1137 sizeof(struct history_item) 1138 + sl); 1139 strcpy(cast_char hi->str, 1140 cast_const_char j->str); 1141 add_to_list(di->history, hi); 1142 } 1143 } 1144 di->cpos = 1145 (int)strlen(cast_const_char di->cdata); 1146 } 1147 } 1148 dlg->selected = 0; 1149 /*-fallthrough*/ 1150 case EV_RESIZE: 1151 /* this must be really called twice !!! */ 1152 draw_to_window(dlg->win, redraw_dialog, dlg); 1153 /*-fallthrough*/ 1154 case EV_REDRAW: 1155 draw_to_window(dlg->win, redraw_dialog, dlg); 1156 break; 1157 case EV_MOUSE: 1158 if ((ev->b & BM_ACT) == B_MOVE) 1159 break; 1160 if ((ev->b & BM_BUTT) == B_FOURTH) { 1161 if ((ev->b & BM_ACT) == B_DOWN) 1162 goto go_prev; 1163 break; 1164 } 1165 if ((ev->b & BM_BUTT) == B_FIFTH) { 1166 if ((ev->b & BM_ACT) == B_DOWN) 1167 goto go_next; 1168 break; 1169 } 1170 if ((ev->b & BM_BUTT) == B_SIXTH) { 1171 if ((ev->b & BM_ACT) == B_DOWN) 1172 goto go_enter; 1173 break; 1174 } 1175 for (i = 0; i < dlg->n; i++) 1176 if (dlg_mouse(dlg, &dlg->items[i], ev)) 1177 break; 1178 if ((ev->b & BM_ACT) == B_DOWN 1179 && (ev->b & BM_BUTT) == B_MIDDLE) { 1180 /* don't delete this!!! it's here because of jump from 1181 * mouse event */ 1182 di = &dlg->items[dlg->selected]; 1183 if (di->item->type == D_FIELD 1184 || di->item->type == D_FIELD_PASS) 1185 goto clipbd_paste; 1186 } 1187 break; 1188 case EV_KBD: 1189 di = &dlg->items[dlg->selected]; 1190 if (ev->y & KBD_PASTING) { 1191 if (!((di->item->type == D_FIELD 1192 || di->item->type == D_FIELD_PASS) 1193 && (ev->x >= ' ' 1194 && !(ev->y & (KBD_CTRL | KBD_ALT))))) 1195 break; 1196 } 1197 if (di->item->type == D_FIELD 1198 || di->item->type == D_FIELD_PASS) { 1199 if (ev->x == KBD_UP 1200 && di->cur_hist->prev != &di->history) { 1201 di->cur_hist = di->cur_hist->prev; 1202 dlg_set_history(term, di); 1203 goto dsp_f; 1204 } 1205 if (ev->x == KBD_DOWN && di->cur_hist != &di->history) { 1206 di->cur_hist = di->cur_hist->next; 1207 dlg_set_history(term, di); 1208 goto dsp_f; 1209 } 1210 if (ev->x == KBD_RIGHT) { 1211 if ((size_t)di->cpos 1212 < strlen(cast_const_char di->cdata)) { 1213 int u; 1214 unsigned char *p = di->cdata + di->cpos; 1215 GET_UTF_8(p, u); 1216 di->cpos = (int)(p - di->cdata); 1217 } 1218 goto dsp_f; 1219 } 1220 if (ev->x == KBD_LEFT) { 1221 if (di->cpos > 0) { 1222 unsigned char *p = di->cdata + di->cpos; 1223 BACK_UTF_8(p, di->cdata); 1224 di->cpos = (int)(p - di->cdata); 1225 } 1226 goto dsp_f; 1227 } 1228 if (ev->x == KBD_HOME 1229 || (upcase(ev->x) == 'A' && ev->y & KBD_CTRL)) { 1230 di->cpos = 0; 1231 goto dsp_f; 1232 } 1233 if (ev->x == KBD_END 1234 || (upcase(ev->x) == 'E' && ev->y & KBD_CTRL)) { 1235 di->cpos = 1236 (int)strlen(cast_const_char di->cdata); 1237 goto dsp_f; 1238 } 1239 if (ev->x >= ' ' && !(ev->y & (KBD_CTRL | KBD_ALT))) { 1240 unsigned char *u; 1241 u = encode_utf_8(ev->x); 1242 if (strlen(cast_const_char di->cdata) 1243 + strlen(cast_const_char u) 1244 < (size_t)di->item->dlen) { 1245 memmove( 1246 di->cdata + di->cpos 1247 + strlen(cast_const_char u), 1248 di->cdata + di->cpos, 1249 strlen(cast_const_char di->cdata) 1250 - di->cpos + 1); 1251 memcpy(&di->cdata[di->cpos], u, 1252 strlen(cast_const_char u)); 1253 di->cpos += 1254 (int)strlen(cast_const_char u); 1255 } 1256 goto dsp_f; 1257 } 1258 if (ev->x == KBD_BS) { 1259 if (di->cpos) { 1260 int s = 1; 1261 unsigned u; 1262 unsigned char *p, *pp; 1263 p = di->cdata; 1264 a: 1265 pp = p; 1266 GET_UTF_8(p, u); 1267 if (p < di->cdata + di->cpos) 1268 goto a; 1269 s = (int)(p - pp); 1270 memmove( 1271 di->cdata + di->cpos - s, 1272 di->cdata + di->cpos, 1273 strlen(cast_const_char di->cdata) 1274 - di->cpos + s); 1275 di->cpos -= s; 1276 } 1277 goto dsp_f; 1278 } 1279 if (ev->x == KBD_DEL 1280 || (upcase(ev->x) == 'D' && ev->y & KBD_CTRL)) { 1281 if ((size_t)di->cpos 1282 < strlen(cast_const_char di->cdata)) { 1283 int s = 1; 1284 unsigned u; 1285 unsigned char *p = di->cdata + di->cpos; 1286 GET_UTF_8(p, u); 1287 s = (int)(p - (di->cdata + di->cpos)); 1288 memmove( 1289 di->cdata + di->cpos, 1290 di->cdata + di->cpos + s, 1291 strlen(cast_const_char di->cdata) 1292 - di->cpos + s); 1293 } 1294 goto dsp_f; 1295 } 1296 if (upcase(ev->x) == 'U' && ev->y & KBD_CTRL) { 1297 unsigned char *a = memacpy(di->cdata, di->cpos); 1298 if (a) { 1299 set_clipboard_text(term, a); 1300 free(a); 1301 } 1302 memmove( 1303 di->cdata, di->cdata + di->cpos, 1304 strlen(cast_const_char di->cdata + di->cpos) 1305 + 1); 1306 di->cpos = 0; 1307 goto dsp_f; 1308 } 1309 if (upcase(ev->x) == 'K' && ev->y & KBD_CTRL) { 1310 set_clipboard_text(term, di->cdata + di->cpos); 1311 di->cdata[di->cpos] = 0; 1312 goto dsp_f; 1313 } 1314 /* Copy to clipboard */ 1315 if ((ev->x == KBD_INS && ev->y & KBD_CTRL) 1316 || (upcase(ev->x) == 'B' && ev->y & KBD_CTRL) 1317 || ev->x == KBD_COPY) { 1318 set_clipboard_text(term, di->cdata); 1319 break; /* We don't need to redraw */ 1320 } 1321 /* FIXME -- why keyboard shortcuts with shift don't 1322 * works??? */ 1323 /* Cut to clipboard */ 1324 if ((ev->x == KBD_DEL && ev->y & KBD_SHIFT) 1325 || (upcase(ev->x) == 'X' && ev->y & KBD_CTRL) 1326 || ev->x == KBD_CUT) { 1327 set_clipboard_text(term, di->cdata); 1328 di->cdata[0] = 0; 1329 di->cpos = 0; 1330 goto dsp_f; 1331 } 1332 /* Paste from clipboard */ 1333 if ((ev->x == KBD_INS && ev->y & KBD_SHIFT) 1334 || (upcase(ev->x) == 'V' && ev->y & KBD_CTRL) 1335 || ev->x == KBD_PASTE) { 1336 unsigned char *clipboard; 1337 clipbd_paste: 1338 clipboard = get_clipboard_text(term); 1339 if (clipboard) { 1340 unsigned char *nl = clipboard; 1341 while ((nl = cast_uchar strchr( 1342 cast_const_char nl, '\n'))) 1343 *nl = ' '; 1344 if (strlen(cast_const_char di->cdata) 1345 + strlen(cast_const_char 1346 clipboard) 1347 < (size_t)di->item->dlen 1348 || strlen(cast_const_char di->cdata) 1349 + strlen(cast_const_char 1350 clipboard) 1351 < strlen(cast_const_char di 1352 ->cdata)) { 1353 1354 memmove( 1355 di->cdata + di->cpos 1356 + strlen(cast_const_char 1357 clipboard), 1358 di->cdata + di->cpos, 1359 strlen(cast_const_char di 1360 ->cdata) 1361 - di->cpos + 1); 1362 memcpy(&di->cdata[di->cpos], 1363 clipboard, 1364 strlen(cast_const_char 1365 clipboard)); 1366 di->cpos += (int)strlen( 1367 cast_const_char clipboard); 1368 } 1369 free(clipboard); 1370 } 1371 goto dsp_f; 1372 } 1373 if ((upcase(ev->x) == 'W' && ev->y & KBD_CTRL) 1374 || ev->x == KBD_FIND) { 1375 do_tab_compl(term, &di->history, win); 1376 goto dsp_f; 1377 } 1378 goto gh; 1379 dsp_f: 1380 x_display_dlg_item(dlg, di, 1); 1381 break; 1382 } 1383 if ((ev->x == KBD_ENTER && di->item->type == D_BUTTON) 1384 || ev->x == ' ') { 1385 dlg_select_item(dlg, di); 1386 break; 1387 } 1388 gh: 1389 if (ev->x > ' ') 1390 for (i = 0; i < dlg->n; i++) { 1391 unsigned char *tx = get_text_translation( 1392 dlg->dlg->items[i].text, term); 1393 if (dlg->dlg->items[i].type == D_BUTTON 1394 && charset_upcase(GET_TERM_CHAR(term, &tx), 1395 0) 1396 == charset_upcase(ev->x, 0)) 1397 goto sel; 1398 } 1399 if (ev->x == KBD_ENTER) { 1400 go_enter: 1401 for (i = 0; i < dlg->n; i++) 1402 if (dlg->dlg->items[i].type == D_BUTTON 1403 && dlg->dlg->items[i].gid & B_ENTER) 1404 goto sel; 1405 break; 1406 } 1407 if (ev->x == KBD_ESC) { 1408 for (i = 0; i < dlg->n; i++) 1409 if (dlg->dlg->items[i].type == D_BUTTON 1410 && dlg->dlg->items[i].gid & B_ESC) 1411 goto sel; 1412 break; 1413 } 1414 if (0) { 1415 sel: 1416 if (dlg->selected != i) { 1417 x_display_dlg_item( 1418 dlg, &dlg->items[dlg->selected], 0); 1419 x_display_dlg_item(dlg, &dlg->items[i], 1); 1420 dlg->selected = i; 1421 } 1422 dlg_select_item(dlg, &dlg->items[i]); 1423 break; 1424 } 1425 if (((ev->x == KBD_TAB && !ev->y) || ev->x == KBD_DOWN 1426 || ev->x == KBD_RIGHT) 1427 && dlg->n > 1) { 1428 go_next: 1429 x_display_dlg_item(dlg, &dlg->items[dlg->selected], 0); 1430 if ((++dlg->selected) >= dlg->n) 1431 dlg->selected = 0; 1432 x_display_dlg_item(dlg, &dlg->items[dlg->selected], 1); 1433 break; 1434 } 1435 if (((ev->x == KBD_TAB && ev->y) || ev->x == KBD_UP 1436 || ev->x == KBD_LEFT) 1437 && dlg->n > 1) { 1438 go_prev: 1439 x_display_dlg_item(dlg, &dlg->items[dlg->selected], 0); 1440 if ((--dlg->selected) < 0) 1441 dlg->selected = dlg->n - 1; 1442 x_display_dlg_item(dlg, &dlg->items[dlg->selected], 1); 1443 break; 1444 } 1445 break; 1446 case EV_ABORT: 1447 /* Moved this line up so that the dlg would have access to its 1448 member vars before they get freed. */ 1449 if (dlg->dlg->abort) 1450 dlg->dlg->abort(dlg); 1451 for (i = 0; i < dlg->n; i++) { 1452 struct dialog_item_data *di = &dlg->items[i]; 1453 free(di->cdata); 1454 free_list(struct history_item, di->history); 1455 } 1456 freeml(dlg->ml); 1457 } 1458 } 1459 1460 /* gid and gnum are 100 times greater than boundaries (e.g. if gid==1 boundary 1461 * is 0.01) */ 1462 int 1463 check_float(struct dialog_data *dlg, struct dialog_item_data *di) 1464 { 1465 char *end; 1466 double d = strtod(cast_const_char di->cdata, &end); 1467 if (!*di->cdata || *end 1468 || di->cdata[strspn(cast_const_char di->cdata, "0123456789.")] 1469 || *di->cdata == (unsigned char)'.') { 1470 msg_box(dlg->win->term, NULL, TEXT_(T_BAD_NUMBER), AL_CENTER, 1471 TEXT_(T_NUMBER_EXPECTED), MSG_BOX_END, NULL, 1, 1472 TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC); 1473 return 1; 1474 } 1475 if (d < 0 || d > di->item->gnum || 100 * d < di->item->gid 1476 || 100 * d > di->item->gnum) { 1477 msg_box(dlg->win->term, NULL, TEXT_(T_BAD_NUMBER), AL_CENTER, 1478 TEXT_(T_NUMBER_OUT_OF_RANGE), MSG_BOX_END, NULL, 1, 1479 TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC); 1480 return 1; 1481 } 1482 return 0; 1483 } 1484 1485 int 1486 check_number(struct dialog_data *dlg, struct dialog_item_data *di) 1487 { 1488 char *end; 1489 long l = strtol(cast_const_char di->cdata, &end, 10); 1490 if (!*di->cdata || *end) { 1491 msg_box(dlg->win->term, NULL, TEXT_(T_BAD_NUMBER), AL_CENTER, 1492 TEXT_(T_NUMBER_EXPECTED), MSG_BOX_END, NULL, 1, 1493 TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC); 1494 return 1; 1495 } 1496 if (l < di->item->gid || l > di->item->gnum) { 1497 msg_box(dlg->win->term, NULL, TEXT_(T_BAD_NUMBER), AL_CENTER, 1498 TEXT_(T_NUMBER_OUT_OF_RANGE), MSG_BOX_END, NULL, 1, 1499 TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC); 1500 return 1; 1501 } 1502 return 0; 1503 } 1504 1505 int 1506 check_hex_number(struct dialog_data *dlg, struct dialog_item_data *di) 1507 { 1508 char *end; 1509 long l = strtol(cast_const_char di->cdata, &end, 16); 1510 if (!*di->cdata || *end) { 1511 msg_box(dlg->win->term, NULL, TEXT_(T_BAD_NUMBER), AL_CENTER, 1512 TEXT_(T_NUMBER_EXPECTED), MSG_BOX_END, NULL, 1, 1513 TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC); 1514 return 1; 1515 } 1516 if (l < di->item->gid || l > di->item->gnum) { 1517 msg_box(dlg->win->term, NULL, TEXT_(T_BAD_NUMBER), AL_CENTER, 1518 TEXT_(T_NUMBER_OUT_OF_RANGE), MSG_BOX_END, NULL, 1, 1519 TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC); 1520 return 1; 1521 } 1522 return 0; 1523 } 1524 1525 int 1526 check_nonempty(struct dialog_data *dlg, struct dialog_item_data *di) 1527 { 1528 unsigned char *p; 1529 for (p = di->cdata; *p; p++) 1530 if (*p > ' ') 1531 return 0; 1532 msg_box(dlg->win->term, NULL, TEXT_(T_BAD_STRING), AL_CENTER, 1533 TEXT_(T_EMPTY_STRING_NOT_ALLOWED), MSG_BOX_END, NULL, 1, 1534 TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC); 1535 return 1; 1536 } 1537 1538 static int 1539 check_local_ip_address_internal(struct dialog_data *dlg, 1540 struct dialog_item_data *di, int pf) 1541 { 1542 int s; 1543 int rs; 1544 unsigned char *p = di->cdata; 1545 if (!*p) { 1546 return 0; 1547 } 1548 if (pf == PF_INET6) 1549 rs = numeric_ipv6_address((char *)p, NULL, NULL); 1550 else 1551 rs = numeric_ip_address((char *)p, NULL); 1552 if (rs) { 1553 msg_box(dlg->win->term, NULL, TEXT_(T_BAD_IP_ADDRESS), 1554 AL_CENTER, TEXT_(T_INVALID_IP_ADDRESS_SYNTAX), 1555 MSG_BOX_END, NULL, 1, TEXT_(T_CANCEL), msg_box_null, 1556 B_ENTER | B_ESC); 1557 return 1; 1558 } 1559 s = socket_and_bind(pf, p); 1560 if (s != -1) 1561 EINTRLOOP(rs, close(s)); 1562 else { 1563 if (1 1564 #ifdef ENFILE 1565 && errno != ENFILE 1566 #endif 1567 #ifdef EMFILE 1568 && errno != EMFILE 1569 #endif 1570 #ifdef ENOBUFS 1571 && errno != ENOBUFS 1572 #endif 1573 #ifdef ENOMEM 1574 && errno != ENOMEM 1575 #endif 1576 ) { 1577 unsigned char *er = stracpy(cast_uchar strerror(errno)); 1578 unsigned char *ad = stracpy(p); 1579 msg_box(dlg->win->term, getml(er, ad, NULL), 1580 TEXT_(T_BAD_IP_ADDRESS), AL_CENTER, 1581 TEXT_(T_UNABLE_TO_USE_LOCAL_IP_ADDRESS), 1582 cast_uchar " ", ad, cast_uchar ": ", er, 1583 MSG_BOX_END, NULL, 1, TEXT_(T_CANCEL), 1584 msg_box_null, B_ENTER | B_ESC); 1585 return 1; 1586 } 1587 } 1588 return 0; 1589 } 1590 1591 int 1592 check_local_ip_address(struct dialog_data *dlg, struct dialog_item_data *di) 1593 { 1594 return check_local_ip_address_internal(dlg, di, PF_INET); 1595 } 1596 1597 int 1598 check_local_ipv6_address(struct dialog_data *dlg, struct dialog_item_data *di) 1599 { 1600 return check_local_ip_address_internal(dlg, di, PF_INET6); 1601 } 1602 1603 int 1604 cancel_dialog(struct dialog_data *dlg, struct dialog_item_data *di) 1605 { 1606 delete_window(dlg->win); 1607 return 0; 1608 } 1609 1610 int 1611 check_dialog(struct dialog_data *dlg) 1612 { 1613 int i; 1614 for (i = 0; i < dlg->n; i++) 1615 if (dlg->dlg->items[i].type == D_CHECKBOX 1616 || dlg->dlg->items[i].type == D_FIELD 1617 || dlg->dlg->items[i].type == D_FIELD_PASS) 1618 if (dlg->dlg->items[i].fn 1619 && dlg->dlg->items[i].fn(dlg, &dlg->items[i])) { 1620 dlg->selected = i; 1621 draw_to_window(dlg->win, redraw_dialog_items, 1622 dlg); 1623 return 1; 1624 } 1625 return 0; 1626 } 1627 1628 void 1629 get_dialog_data(struct dialog_data *dlg) 1630 { 1631 int i; 1632 for (i = 0; i < dlg->n; i++) { 1633 void *p1 = dlg->dlg->items[i].data; 1634 void *p2 = dlg->items[i].cdata; 1635 int l = dlg->dlg->items[i].dlen; 1636 if (l) 1637 memcpy(p1, p2, l); 1638 } 1639 } 1640 1641 int 1642 ok_dialog(struct dialog_data *dlg, struct dialog_item_data *di) 1643 { 1644 void (*fn)(void *) = dlg->dlg->refresh; 1645 void *data = dlg->dlg->refresh_data; 1646 if (check_dialog(dlg)) 1647 return 1; 1648 get_dialog_data(dlg); 1649 if (fn) 1650 fn(data); 1651 return cancel_dialog(dlg, di); 1652 } 1653 1654 void 1655 center_dlg(struct dialog_data *dlg) 1656 { 1657 dlg->x = (dlg->win->term->x - dlg->xw) / 2; 1658 dlg->y = (dlg->win->term->y - dlg->yw) / 2; 1659 } 1660 1661 void 1662 draw_dlg(struct dialog_data *dlg) 1663 { 1664 int i, tpos; 1665 struct terminal *term = dlg->win->term; 1666 1667 fill_area(term, dlg->x, dlg->y, dlg->xw, dlg->yw, ' ', COLOR_DIALOG); 1668 draw_frame(term, dlg->x + DIALOG_LEFT_BORDER, 1669 dlg->y + DIALOG_TOP_BORDER, dlg->xw - 2 * DIALOG_LEFT_BORDER, 1670 dlg->yw - 2 * DIALOG_TOP_BORDER, COLOR_DIALOG_FRAME, 1671 DIALOG_FRAME); 1672 i = strlen((char *)get_text_translation(dlg->dlg->title, term)); 1673 tpos = (dlg->xw - i) / 2; 1674 print_text(term, tpos + dlg->x - 1, dlg->y + DIALOG_TOP_BORDER, 1, 1675 cast_uchar " ", COLOR_DIALOG_TITLE); 1676 print_text(term, tpos + dlg->x, dlg->y + DIALOG_TOP_BORDER, i, 1677 get_text_translation(dlg->dlg->title, term), 1678 COLOR_DIALOG_TITLE); 1679 print_text(term, tpos + dlg->x + i, dlg->y + DIALOG_TOP_BORDER, 1, 1680 cast_uchar " ", COLOR_DIALOG_TITLE); 1681 } 1682 1683 void 1684 max_text_width(struct terminal *term, unsigned char *text, int *width, 1685 int align) 1686 { 1687 text = get_text_translation(text, term); 1688 do { 1689 int c = 0; 1690 while (*text && *text != '\n') { 1691 int u; 1692 GET_UTF_8(text, u); 1693 c++; 1694 } 1695 if (c > *width) 1696 *width = c; 1697 } while (*(text++)); 1698 } 1699 1700 void 1701 min_text_width(struct terminal *term, unsigned char *text, int *width, 1702 int align) 1703 { 1704 text = get_text_translation(text, term); 1705 do { 1706 int c = 0; 1707 while (*text && *text != '\n' && *text != ' ') { 1708 int u; 1709 GET_UTF_8(text, u); 1710 c++; 1711 } 1712 if (c > *width) 1713 *width = c; 1714 } while (*(text++)); 1715 } 1716 1717 int 1718 dlg_format_text(struct dialog_data *dlg, struct terminal *term, 1719 unsigned char *text, int x, int *y, int w, int *rw, 1720 unsigned char co, int align) 1721 { 1722 int xx = x; 1723 text = get_text_translation(text, dlg->win->term); 1724 for (;;) { 1725 unsigned char *t1; 1726 unsigned ch; 1727 int cx, lbr; 1728 1729 t1 = text; 1730 cx = 0; 1731 lbr = 0; 1732 next_chr: 1733 ch = GET_TERM_CHAR(dlg->win->term, &t1); 1734 if (ch == ' ') { 1735 lbr = cx; 1736 } 1737 if (ch && ch != '\n') { 1738 if (cx == w) { 1739 if (!lbr) 1740 lbr = cx; 1741 goto print_line; 1742 } 1743 cx++; 1744 goto next_chr; 1745 } 1746 if (!ch && !cx) 1747 break; 1748 lbr = cx; 1749 print_line: 1750 if (rw && lbr > *rw) 1751 *rw = lbr; 1752 xx = x; 1753 if ((align & AL_MASK) == AL_CENTER) { 1754 xx += (w - lbr) / 2; 1755 } 1756 for (; lbr--; xx++) { 1757 ch = GET_TERM_CHAR(dlg->win->term, &text); 1758 if (term) 1759 set_char(term, xx, *y, ch, co); 1760 } 1761 xx++; 1762 if (*text == ' ' || *text == '\n') 1763 text++; 1764 (*y)++; 1765 } 1766 return xx - x; 1767 } 1768 1769 void 1770 max_buttons_width(struct terminal *term, struct dialog_item_data *butt, int n, 1771 int *width) 1772 { 1773 int w = -2; 1774 int i; 1775 for (i = 0; i < n; i++) 1776 w += txtlen(get_text_translation((butt++)->item->text, term)) 1777 + 6; 1778 if (w > *width) 1779 *width = w; 1780 } 1781 1782 void 1783 min_buttons_width(struct terminal *term, struct dialog_item_data *butt, int n, 1784 int *width) 1785 { 1786 int i; 1787 for (i = 0; i < n; i++) { 1788 int w = txtlen(get_text_translation((butt++)->item->text, term)) 1789 + 4; 1790 if (w > *width) 1791 *width = w; 1792 } 1793 } 1794 1795 void 1796 dlg_format_buttons(struct dialog_data *dlg, struct terminal *term, 1797 struct dialog_item_data *butt, int n, int x, int *y, int w, 1798 int *rw, int align) 1799 { 1800 int i1 = 0; 1801 while (i1 < n) { 1802 int i2 = i1 + 1; 1803 int mw; 1804 while (i2 < n) { 1805 mw = 0; 1806 max_buttons_width(dlg->win->term, butt + i1, 1807 i2 - i1 + 1, &mw); 1808 if (mw <= w) 1809 i2++; 1810 else 1811 break; 1812 } 1813 mw = 0; 1814 max_buttons_width(dlg->win->term, butt + i1, i2 - i1, &mw); 1815 if (rw && mw > *rw) 1816 if ((*rw = mw) > w) 1817 *rw = w; 1818 if (term) { 1819 int i; 1820 int p = x 1821 + ((align & AL_MASK) == AL_CENTER ? (w - mw) / 2 1822 : 0); 1823 for (i = i1; i < i2; i++) { 1824 butt[i].x = p; 1825 butt[i].y = *y; 1826 p += (butt[i].l = txtlen(get_text_translation( 1827 butt[i].item->text, 1828 dlg->win->term)) 1829 + 4) 1830 + 2; 1831 } 1832 } 1833 *y += 2; 1834 i1 = i2; 1835 } 1836 } 1837 1838 void 1839 dlg_format_checkbox(struct dialog_data *dlg, struct terminal *term, 1840 struct dialog_item_data *chkb, int x, int *y, int w, 1841 int *rw, unsigned char *text) 1842 { 1843 int k = 4; 1844 if (term) { 1845 chkb->x = x; 1846 chkb->y = *y; 1847 } 1848 if (rw) 1849 *rw -= k; 1850 dlg_format_text(dlg, term, text, x + k, y, w - k, rw, 1851 COLOR_DIALOG_CHECKBOX_TEXT, AL_LEFT | AL_NOBRLEXP); 1852 if (rw) 1853 *rw += k; 1854 } 1855 1856 void 1857 dlg_format_checkboxes(struct dialog_data *dlg, struct terminal *term, 1858 struct dialog_item_data *chkb, int n, int x, int *y, 1859 int w, int *rw, unsigned char *const *texts) 1860 { 1861 while (n) { 1862 dlg_format_checkbox(dlg, term, chkb, x, y, w, rw, texts[0]); 1863 texts++; 1864 chkb++; 1865 n--; 1866 } 1867 } 1868 1869 void 1870 checkboxes_width(struct terminal *term, unsigned char *const *texts, int n, 1871 int *w, 1872 void (*fn)(struct terminal *, unsigned char *, int *, int)) 1873 { 1874 int k = 4; 1875 while (n--) { 1876 *w -= k; 1877 fn(term, get_text_translation(texts[0], term), w, 0); 1878 *w += k; 1879 texts++; 1880 } 1881 } 1882 1883 void 1884 dlg_format_field(struct dialog_data *dlg, struct terminal *term, 1885 struct dialog_item_data *item, int x, int *y, int w, int *rw, 1886 int align) 1887 { 1888 if (term) { 1889 item->x = x; 1890 item->y = *y; 1891 item->l = w; 1892 if (rw && item->l > *rw) 1893 if ((*rw = item->l) > w) 1894 *rw = w; 1895 } 1896 (*y)++; 1897 } 1898 1899 void 1900 dlg_format_text_and_field(struct dialog_data *dlg, struct terminal *term, 1901 unsigned char *text, struct dialog_item_data *item, 1902 int x, int *y, int w, int *rw, unsigned char co, 1903 int align) 1904 { 1905 dlg_format_text(dlg, term, text, x, y, w, rw, co, align); 1906 dlg_format_field(dlg, term, item, x, y, w, rw, align); 1907 } 1908 1909 #if 0 1910 /* Layout for generic boxes */ 1911 void dlg_format_box(struct terminal *term, struct terminal *t2, struct dialog_item_data *item, int x, int *y, int w, int *rw, int align) { 1912 item->x = x; 1913 item->y = *y; 1914 item->l = w; 1915 if (rw && item->l > *rw) if ((*rw = item->l) > w) *rw = w; 1916 (*y) += item->item->gid; 1917 } 1918 #endif 1919 1920 void 1921 max_group_width(struct terminal *term, unsigned char *const *texts, 1922 struct dialog_item_data *item, int n, int *w) 1923 { 1924 int ww = 0; 1925 while (n--) { 1926 int wx = 1927 item->item->type == D_CHECKBOX ? 4 1928 : item->item->type == D_BUTTON 1929 ? txtlen(get_text_translation(item->item->text, term)) 1930 + 4 1931 : item->item->dlen; 1932 wx += txtlen(get_text_translation(texts[0], term)) + 1; 1933 if (n) 1934 wx++; 1935 ww += wx; 1936 texts++; 1937 item++; 1938 } 1939 if (ww > *w) 1940 *w = ww; 1941 } 1942 1943 void 1944 min_group_width(struct terminal *term, unsigned char *const *texts, 1945 struct dialog_item_data *item, int n, int *w) 1946 { 1947 while (n--) { 1948 int wx = 1949 item->item->type == D_CHECKBOX ? 4 1950 : item->item->type == D_BUTTON 1951 ? txtlen(get_text_translation(item->item->text, term)) 1952 + 4 1953 : item->item->dlen + 1; 1954 wx += txtlen(get_text_translation(texts[0], term)); 1955 if (wx > *w) 1956 *w = wx; 1957 texts++; 1958 item++; 1959 } 1960 } 1961 1962 void 1963 dlg_format_group(struct dialog_data *dlg, struct terminal *term, 1964 unsigned char *const *texts, struct dialog_item_data *item, 1965 int n, int x, int *y, int w, int *rw) 1966 { 1967 int nx = 0; 1968 while (n--) { 1969 int wx = item->item->type == D_CHECKBOX ? 3 1970 : item->item->type == D_BUTTON 1971 ? txtlen(get_text_translation(item->item->text, 1972 dlg->win->term)) 1973 + 4 1974 : item->item->dlen; 1975 int sl; 1976 if (get_text_translation(texts[0], dlg->win->term)[0]) 1977 sl = txtlen( 1978 get_text_translation(texts[0], dlg->win->term)) 1979 + 1; 1980 else 1981 sl = 0; 1982 wx += sl; 1983 if (nx && nx + wx > w) { 1984 nx = 0; 1985 (*y) += 2; 1986 } 1987 if (term) { 1988 print_text( 1989 term, x + nx + 4 * (item->item->type == D_CHECKBOX), 1990 *y, 1991 strlen((char *)get_text_translation( 1992 texts[0], dlg->win->term)), 1993 get_text_translation(texts[0], dlg->win->term), 1994 COLOR_DIALOG_TEXT); 1995 item->x = 1996 x + nx + sl * (item->item->type != D_CHECKBOX); 1997 item->y = *y; 1998 if (item->item->type == D_FIELD 1999 || item->item->type == D_FIELD_PASS) 2000 item->l = item->item->dlen; 2001 } 2002 if (rw && nx + wx > *rw) 2003 if ((*rw = nx + wx) > w) 2004 *rw = w; 2005 nx += wx + 1; 2006 texts++; 2007 item++; 2008 } 2009 (*y)++; 2010 } 2011 2012 void 2013 checkbox_list_fn(struct dialog_data *dlg) 2014 { 2015 struct terminal *term = dlg->win->term; 2016 int n_checkboxes; 2017 int max = 0, min = 0; 2018 int w, rw; 2019 int y = 0; 2020 for (n_checkboxes = 0; 2021 ((unsigned char **)dlg->dlg->udata)[n_checkboxes]; n_checkboxes++) 2022 ; 2023 checkboxes_width(term, dlg->dlg->udata, n_checkboxes, &max, 2024 max_text_width); 2025 checkboxes_width(term, dlg->dlg->udata, n_checkboxes, &min, 2026 min_text_width); 2027 max_buttons_width(term, dlg->items + n_checkboxes, 2028 dlg->n - n_checkboxes, &max); 2029 min_buttons_width(term, dlg->items + n_checkboxes, 2030 dlg->n - n_checkboxes, &min); 2031 w = term->x * 9 / 10 - 2 * DIALOG_LB; 2032 if (w > max) 2033 w = max; 2034 if (w < min) 2035 w = min; 2036 if (w > term->x - 2 * DIALOG_LB) 2037 w = term->x - 2 * DIALOG_LB; 2038 if (w < 5) 2039 w = 5; 2040 rw = 0; 2041 dlg_format_checkboxes(dlg, NULL, dlg->items, n_checkboxes, 0, &y, w, 2042 &rw, dlg->dlg->udata); 2043 y++; 2044 dlg_format_buttons(dlg, NULL, dlg->items + n_checkboxes, 2045 dlg->n - n_checkboxes, 0, &y, w, &rw, AL_CENTER); 2046 w = rw; 2047 dlg->xw = rw + 2 * DIALOG_LB; 2048 dlg->yw = y + 2 * DIALOG_TB; 2049 center_dlg(dlg); 2050 draw_dlg(dlg); 2051 y = dlg->y + DIALOG_TB + 1; 2052 dlg_format_checkboxes(dlg, term, dlg->items, n_checkboxes, 2053 dlg->x + DIALOG_LB, &y, w, NULL, dlg->dlg->udata); 2054 y++; 2055 dlg_format_buttons(dlg, term, dlg->items + n_checkboxes, 2056 dlg->n - n_checkboxes, dlg->x + DIALOG_LB, &y, w, 2057 &rw, AL_CENTER); 2058 } 2059 2060 void 2061 group_fn(struct dialog_data *dlg) 2062 { 2063 struct terminal *term = dlg->win->term; 2064 int max = 0, min = 0; 2065 int w, rw; 2066 int y = 0; 2067 max_group_width(term, dlg->dlg->udata, dlg->items, dlg->n - 2, &max); 2068 min_group_width(term, dlg->dlg->udata, dlg->items, dlg->n - 2, &min); 2069 max_buttons_width(term, dlg->items + dlg->n - 2, 2, &max); 2070 min_buttons_width(term, dlg->items + dlg->n - 2, 2, &min); 2071 w = term->x * 9 / 10 - 2 * DIALOG_LB; 2072 if (w > max) 2073 w = max; 2074 if (w < min) 2075 w = min; 2076 if (w > term->x - 2 * DIALOG_LB) 2077 w = term->x - 2 * DIALOG_LB; 2078 if (w < 1) 2079 w = 1; 2080 rw = 0; 2081 dlg_format_group(dlg, NULL, dlg->dlg->udata, dlg->items, dlg->n - 2, 0, 2082 &y, w, &rw); 2083 y++; 2084 dlg_format_buttons(dlg, NULL, dlg->items + dlg->n - 2, 2, 0, &y, w, &rw, 2085 AL_CENTER); 2086 w = rw; 2087 dlg->xw = rw + 2 * DIALOG_LB; 2088 dlg->yw = y + 2 * DIALOG_TB; 2089 center_dlg(dlg); 2090 draw_dlg(dlg); 2091 y = dlg->y + DIALOG_TB + 1; 2092 dlg_format_group(dlg, term, dlg->dlg->udata, dlg->items, dlg->n - 2, 2093 dlg->x + DIALOG_LB, &y, w, NULL); 2094 y++; 2095 dlg_format_buttons(dlg, term, dlg->items + dlg->n - 2, 2, 2096 dlg->x + DIALOG_LB, &y, w, &rw, AL_CENTER); 2097 } 2098 2099 void 2100 msg_box_fn(struct dialog_data *dlg) 2101 { 2102 struct terminal *term = dlg->win->term; 2103 int max = 0, min = 0; 2104 int w, rw; 2105 int y = 0; 2106 unsigned char **ptr; 2107 unsigned char *text = NULL; 2108 size_t textl = 0; 2109 2110 for (ptr = dlg->dlg->udata; *ptr; ptr++) 2111 textl = 2112 add_to_str(&text, textl, get_text_translation(*ptr, term)); 2113 max_text_width(term, text, &max, dlg->dlg->align); 2114 min_text_width(term, text, &min, dlg->dlg->align); 2115 max_buttons_width(term, dlg->items, dlg->n, &max); 2116 min_buttons_width(term, dlg->items, dlg->n, &min); 2117 w = term->x * 9 / 10 - 2 * DIALOG_LB; 2118 if (w > max) 2119 w = max; 2120 if (w < min) 2121 w = min; 2122 if (w > term->x - 2 * DIALOG_LB) 2123 w = term->x - 2 * DIALOG_LB; 2124 if (w < 1) 2125 w = 1; 2126 rw = 0; 2127 dlg_format_text(dlg, NULL, text, 0, &y, w, &rw, COLOR_DIALOG_TEXT, 2128 dlg->dlg->align); 2129 y++; 2130 dlg_format_buttons(dlg, NULL, dlg->items, dlg->n, 0, &y, w, &rw, 2131 AL_CENTER); 2132 w = rw; 2133 dlg->xw = rw + 2 * DIALOG_LB; 2134 dlg->yw = y + 2 * DIALOG_TB; 2135 center_dlg(dlg); 2136 draw_dlg(dlg); 2137 y = dlg->y + DIALOG_TB + 1; 2138 dlg_format_text(dlg, term, text, dlg->x + DIALOG_LB, &y, w, NULL, 2139 COLOR_DIALOG_TEXT, dlg->dlg->align); 2140 y++; 2141 dlg_format_buttons(dlg, term, dlg->items, dlg->n, dlg->x + DIALOG_LB, 2142 &y, w, NULL, AL_CENTER); 2143 free(text); 2144 } 2145 2146 static int 2147 msg_box_button(struct dialog_data *dlg, struct dialog_item_data *di) 2148 { 2149 msg_button_fn msg_fn = di->item->u.msg_fn; 2150 void *data = dlg->dlg->udata2; 2151 msg_fn(data); 2152 cancel_dialog(dlg, di); 2153 return 0; 2154 } 2155 2156 void 2157 msg_box_null(void *data) 2158 { 2159 } 2160 2161 /* coverity[+free : arg-1] */ 2162 void 2163 msg_box(struct terminal *term, struct memory_list *ml, unsigned char *title, 2164 int align, /*unsigned char *text, ..., void *data, int n,*/...) 2165 { 2166 struct dialog *dlg; 2167 int i; 2168 int n; 2169 unsigned char *text; 2170 unsigned char **udata; 2171 void *udata2; 2172 int udatan; 2173 va_list ap; 2174 va_start(ap, align); 2175 udata = NULL; 2176 udatan = 0; 2177 do { 2178 text = va_arg(ap, unsigned char *); 2179 udatan++; 2180 if ((unsigned)udatan > INT_MAX / sizeof(unsigned char *)) 2181 overalloc(); 2182 udata = xrealloc(udata, udatan * sizeof(unsigned char *)); 2183 udata[udatan - 1] = text; 2184 } while (text); 2185 udata2 = va_arg(ap, void *); 2186 n = va_arg(ap, int); 2187 if ((unsigned)n 2188 > (INT_MAX - sizeof(struct dialog)) / sizeof(struct dialog_item) 2189 - 1) 2190 overalloc(); 2191 dlg = mem_calloc(sizeof(struct dialog) 2192 + (n + 1) * sizeof(struct dialog_item)); 2193 dlg->title = title; 2194 dlg->fn = msg_box_fn; 2195 dlg->udata = udata; 2196 dlg->udata2 = udata2; 2197 dlg->align = align; 2198 for (i = 0; i < n; i++) { 2199 unsigned char *m; 2200 msg_button_fn msg_fn; 2201 int flags; 2202 m = va_arg(ap, unsigned char *); 2203 msg_fn = va_arg(ap, msg_button_fn); 2204 flags = va_arg(ap, int); 2205 if (!m) { 2206 i--; 2207 n--; 2208 continue; 2209 } 2210 dlg->items[i].type = D_BUTTON; 2211 dlg->items[i].gid = flags; 2212 dlg->items[i].fn = msg_box_button; 2213 dlg->items[i].dlen = 0; 2214 dlg->items[i].text = m; 2215 dlg->items[i].u.msg_fn = msg_fn; 2216 } 2217 va_end(ap); 2218 dlg->items[i].type = D_END; 2219 add_to_ml(&ml, dlg, udata, NULL); 2220 do_dialog(term, dlg, ml); 2221 } 2222 2223 void 2224 add_to_history(struct terminal *term, struct history *h, unsigned char *t) 2225 { 2226 struct history_item *hi, *hs = NULL; 2227 struct list_head *lhs; 2228 size_t l; 2229 if (!h || !t || !*t) 2230 return; 2231 l = strlen(cast_const_char t); 2232 if (l > INT_MAX - sizeof(struct history_item)) 2233 overalloc(); 2234 hi = xmalloc(sizeof(struct history_item) + l); 2235 memcpy(hi->str, t, l + 1); 2236 if (term) 2237 foreach (struct history_item, hs, lhs, h->items) 2238 if (!strcmp(cast_const_char hs->str, 2239 cast_const_char hi->str)) { 2240 lhs = lhs->prev; 2241 del_from_list(hs); 2242 free(hs); 2243 h->n--; 2244 } 2245 add_to_list(h->items, hi); 2246 h->n++; 2247 while (h->n > MAX_HISTORY_ITEMS) { 2248 struct history_item *hd; 2249 if (list_empty(h->items)) { 2250 internal("history is empty"); 2251 h->n = 0; 2252 return; 2253 } 2254 hd = list_struct(h->items.prev, struct history_item); 2255 del_from_list(hd); 2256 free(hd); 2257 h->n--; 2258 } 2259 } 2260 2261 static int 2262 input_field_cancel(struct dialog_data *dlg, struct dialog_item_data *di) 2263 { 2264 input_field_button_fn fn = di->item->u.input_fn; 2265 void *data = dlg->dlg->udata2; 2266 unsigned char *text = dlg->items->cdata; 2267 fn(data, text); 2268 cancel_dialog(dlg, di); 2269 return 0; 2270 } 2271 2272 static int 2273 input_field_ok(struct dialog_data *dlg, struct dialog_item_data *di) 2274 { 2275 input_field_button_fn fn = di->item->u.input_fn; 2276 void *data = dlg->dlg->udata2; 2277 unsigned char *text = dlg->items->cdata; 2278 if (check_dialog(dlg)) 2279 return 1; 2280 add_to_history(dlg->win->term, dlg->dlg->items->history, text); 2281 fn(data, text); 2282 ok_dialog(dlg, di); 2283 return 0; 2284 } 2285 2286 static void 2287 input_field_fn(struct dialog_data *dlg) 2288 { 2289 struct terminal *term = dlg->win->term; 2290 int max = 0, min = 0; 2291 int w, rw; 2292 int y = -1; 2293 max_text_width(term, dlg->dlg->udata, &max, AL_LEFT); 2294 min_text_width(term, dlg->dlg->udata, &min, AL_LEFT); 2295 max_buttons_width(term, dlg->items + 1, dlg->n - 1, &max); 2296 min_buttons_width(term, dlg->items + 1, dlg->n - 1, &min); 2297 if (max < dlg->dlg->items->dlen) 2298 max = dlg->dlg->items->dlen; 2299 w = term->x * 9 / 10 - 2 * DIALOG_LB; 2300 if (w > max) 2301 w = max; 2302 if (w < min) 2303 w = min; 2304 rw = w; 2305 dlg_format_text_and_field(dlg, NULL, dlg->dlg->udata, dlg->items, 0, &y, 2306 w, &rw, COLOR_DIALOG_TEXT, AL_LEFT); 2307 y++; 2308 dlg_format_buttons(dlg, NULL, dlg->items + 1, dlg->n - 1, 0, &y, w, &rw, 2309 AL_CENTER); 2310 w = rw; 2311 dlg->xw = rw + 2 * DIALOG_LB; 2312 dlg->yw = y + 2 * DIALOG_TB; 2313 center_dlg(dlg); 2314 draw_dlg(dlg); 2315 y = dlg->y + DIALOG_TB; 2316 dlg_format_text_and_field(dlg, term, dlg->dlg->udata, dlg->items, 2317 dlg->x + DIALOG_LB, &y, w, NULL, 2318 COLOR_DIALOG_TEXT, AL_LEFT); 2319 y++; 2320 dlg_format_buttons(dlg, term, dlg->items + 1, dlg->n - 1, 2321 dlg->x + DIALOG_LB, &y, w, NULL, AL_CENTER); 2322 } 2323 2324 void 2325 input_field_null(void) 2326 { 2327 } 2328 2329 /* coverity[+free : arg-1] */ 2330 void 2331 input_field(struct terminal *term, struct memory_list *ml, unsigned char *title, 2332 unsigned char *text, void *data, struct history *history, int l, 2333 unsigned char *def, int min, int max, 2334 int (*check)(struct dialog_data *, struct dialog_item_data *), 2335 int n, ...) 2336 { 2337 struct dialog *dlg; 2338 unsigned char *field; 2339 va_list va; 2340 int i; 2341 if ((unsigned)n > INT_MAX / sizeof(struct dialog_item) - 2) 2342 overalloc(); 2343 if ((unsigned)l > INT_MAX - sizeof(struct dialog) 2344 - (2 + n) * sizeof(struct dialog_item)) 2345 overalloc(); 2346 dlg = mem_calloc(sizeof(struct dialog) 2347 + (2 + n) * sizeof(struct dialog_item) + l); 2348 *(field = (unsigned char *)dlg + sizeof(struct dialog) 2349 + (2 + n) * sizeof(struct dialog_item)) = 0; 2350 if (def) { 2351 if (strlen(cast_const_char def) + 1 > (size_t)l) 2352 memcpy(field, def, l - 1); 2353 else 2354 strcpy(cast_char field, cast_const_char def); 2355 } 2356 dlg->title = title; 2357 dlg->fn = input_field_fn; 2358 dlg->udata = text; 2359 dlg->udata2 = data; 2360 dlg->items[0].type = D_FIELD; 2361 dlg->items[0].gid = min; 2362 dlg->items[0].gnum = max; 2363 dlg->items[0].fn = check; 2364 dlg->items[0].history = history; 2365 dlg->items[0].dlen = l; 2366 dlg->items[0].data = field; 2367 va_start(va, n); 2368 for (i = 1; i <= n; i++) { 2369 dlg->items[i].type = D_BUTTON; 2370 dlg->items[i].gid = i == 1 ? B_ENTER : i == n ? B_ESC : 0; 2371 dlg->items[i].fn = 2372 i != n || n == 1 ? input_field_ok : input_field_cancel; 2373 dlg->items[i].dlen = 0; 2374 dlg->items[i].text = va_arg(va, unsigned char *); 2375 dlg->items[i].u.input_fn = va_arg(va, input_field_button_fn); 2376 } 2377 va_end(va); 2378 2379 dlg->items[i].type = D_END; 2380 add_to_ml(&ml, dlg, NULL); 2381 do_dialog(term, dlg, ml); 2382 } 2383 2384 int 2385 find_msg_box(struct terminal *term, unsigned char *title, 2386 int (*sel)(void *, void *), void *data) 2387 { 2388 struct window *win = NULL; 2389 struct list_head *lwin; 2390 foreach (struct window, win, lwin, term->windows) 2391 if (win->handler == dialog_func) { 2392 struct dialog_data *dd = win->data; 2393 struct dialog *d = dd->dlg; 2394 if (d->fn != msg_box_fn) 2395 continue; 2396 if (d->title == title) { 2397 if (sel && !sel(data, d->udata2)) 2398 continue; 2399 return 1; 2400 } 2401 } 2402 return 0; 2403 }