"Fossies" - the Fresh Open Source Software Archive

Member "links-1.04/bfu.c" (22 Apr 2018, 48407 Bytes) of package /linux/www/links-1.04.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 "bfu.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.03_vs_1.04.

    1 #include "links.h"
    2 
    3 struct memory_list *getml(void *p, ...)
    4 {
    5     struct memory_list *ml;
    6     va_list ap;
    7     int n = 0;
    8     void *q = p;
    9     va_start(ap, p);
   10     while (q) {
   11         if (n == MAXINT) overalloc();
   12         n++, q = va_arg(ap, void *);
   13     }
   14     if ((unsigned)n > (MAXINT - sizeof(struct memory_list)) / sizeof(void *)) overalloc();
   15     ml = mem_alloc(sizeof(struct memory_list) + n * sizeof(void *));
   16     ml->n = n;
   17     n = 0;
   18     q = p;
   19     va_end(ap);
   20     va_start(ap, p);
   21     while (q) ml->p[n++] = q, q = va_arg(ap, void *);
   22     va_end(ap);
   23     return ml;
   24 }
   25 
   26 void add_to_ml(struct memory_list **ml, ...)
   27 {
   28     struct memory_list *nml;
   29     va_list ap;
   30     int n = 0;
   31     void *q;
   32     if (!*ml) {
   33         *ml = mem_alloc(sizeof(struct memory_list));
   34         (*ml)->n = 0;
   35     }
   36     va_start(ap, ml);
   37     while ((q = va_arg(ap, void *))) {
   38         if (n == MAXINT) overalloc();
   39         n++;
   40     }
   41     if ((unsigned)n + (unsigned)((*ml)->n) > (MAXINT - sizeof(struct memory_list)) / sizeof(void *)) overalloc();
   42     nml = mem_realloc(*ml, sizeof(struct memory_list) + (n + (*ml)->n) * sizeof(void *));
   43     va_end(ap);
   44     va_start(ap, ml);
   45     while ((q = va_arg(ap, void *))) nml->p[nml->n++] = q;
   46     *ml = nml;
   47     va_end(ap);
   48 }
   49 
   50 void freeml(struct memory_list *ml)
   51 {
   52     int i;
   53     if (!ml) return;
   54     for (i = 0; i < ml->n; i++) mem_free(ml->p[i]);
   55     mem_free(ml);
   56 }
   57 
   58 unsigned char m_bar = 0;
   59 
   60 void menu_func(struct window *, struct event *, int);
   61 void mainmenu_func(struct window *, struct event *, int);
   62 void dialog_func(struct window *, struct event *, int);
   63 
   64 unsigned char select_hotkey(struct terminal *term, unsigned char *text, unsigned char *hotkey, unsigned char *hotkeys, int n)
   65 {
   66     unsigned char c;
   67     if (hotkey == M_BAR) return 0;
   68     if (text) {
   69         text = stracpy(_(text, term));
   70         charset_upcase_string(&text, term->spec->charset);
   71     }
   72     hotkey = _(hotkey, term);
   73     while (1) {
   74         int i;
   75         c = *hotkey++;
   76         if (!c) break;
   77         c = charset_upcase(c, term->spec->charset);
   78         for (i = 0; i < n; i++) if (hotkeys[i] == c) goto cont;
   79         if (!text || strchr(text, c)) break;
   80         cont:;
   81     }
   82     if (text) mem_free(text);
   83     return c;
   84 }
   85 void do_menu_selected(struct terminal *term, struct menu_item *items, void *data, int selected, void (*free_function)(void *), void *free_data)
   86 {
   87     int i;
   88     struct menu *menu;
   89     for (i = 0; items[i].text; i++) if (i == MAXINT - sizeof(struct menu)) overalloc();
   90     menu = mem_alloc(sizeof(struct menu) + (!i ? 0 : i - 1));
   91     menu->selected = selected;
   92     menu->view = 0;
   93     menu->ni = i;
   94     menu->items = items;
   95     menu->data = data;
   96     menu->free_function = free_function;
   97     menu->free_data = free_data;
   98     for (i = 0; i < menu->ni; i++)
   99         menu->hotkeys[i] = select_hotkey(term, items[i].text, items[i].hotkey, menu->hotkeys, i);
  100     add_window(term, menu_func, menu);
  101 }
  102 
  103 void do_menu(struct terminal *term, struct menu_item *items, void *data)
  104 {
  105     do_menu_selected(term, items, data, 0, NULL, NULL);
  106 }
  107 
  108 void select_menu(struct terminal *term, struct menu *menu)
  109 {
  110     struct menu_item *it;
  111     void (*func)(struct terminal *, void *, void *);
  112     void *data1;
  113     void *data2;
  114     if (menu->selected < 0 || menu->selected >= menu->ni) return;
  115     it = &menu->items[menu->selected];
  116     func = it->func;
  117     data1 = it->data;
  118     data2 = menu->data;
  119     if (it->hotkey == M_BAR) return;
  120     if (!it->in_m) {
  121         struct window *win, *win1;
  122         for (win = term->windows.next; (void *)win != &term->windows && (win->handler == menu_func || win->handler == mainmenu_func); win1 = win->next, delete_window(win), win = win1) ;
  123     }
  124     func(term, data1, data2);
  125 }
  126 
  127 void count_menu_size(struct terminal *term, struct menu *menu)
  128 {
  129     int sx = term->x;
  130     int sy = term->y;
  131     int mx = 4;
  132     int my;
  133     for (my = 0; my < menu->ni; my++) {
  134         int s = strlen(_(menu->items[my].text, term)) + strlen(_(menu->items[my].rtext, term)) + MENU_HOTKEY_SPACE * (_(menu->items[my].rtext, term)[0] != 0) + 4;
  135         if (s > mx) mx = s;
  136     }
  137     my += 2;
  138     if (mx > sx) mx = sx;
  139     if (my > sy) my = sy;
  140     menu->xw = mx;
  141     menu->yw = my;
  142     if ((menu->x = menu->xp) < 0) menu->x = 0;
  143     if ((menu->y = menu->yp) < 0) menu->y = 0;
  144     if (menu->x + mx > sx) menu->x = sx - mx;
  145     if (menu->y + my > sy) menu->y = sy - my;
  146 }
  147 
  148 void scroll_menu(struct menu *menu, int d)
  149 {
  150     int c = 0;
  151     int w = menu->yw - 2;
  152     int scr_i = SCROLL_ITEMS > (w-1)/2 ? (w-1)/2 : SCROLL_ITEMS;
  153     if (scr_i < 0) scr_i = 0;
  154     if (w < 0) w = 0;
  155     menu->selected += d;
  156     while (1) {
  157         if (c++ > menu->ni) {
  158             menu->selected = -1;
  159             menu->view = 0;
  160             return;
  161         }
  162         if (menu->selected < 0) menu->selected = 0;
  163         if (menu->selected >= menu->ni) menu->selected = menu->ni - 1;
  164         /*if (menu->selected < 0) menu->selected = menu->ni - 1;
  165         if (menu->selected >= menu->ni) menu->selected = 0;*/
  166         if (menu->ni && menu->items[menu->selected].hotkey != M_BAR) break;
  167         menu->selected += d;
  168     }
  169     /*debug("1:%d %d %d %d", menu->ni, w, menu->view, menu->selected);*/
  170     if (menu->selected < menu->view + scr_i) menu->view = menu->selected - scr_i;
  171     if (menu->selected >= menu->view + w - scr_i - 1) menu->view = menu->selected - w + scr_i + 1;
  172     if (menu->view > menu->ni - w) menu->view = menu->ni - w;
  173     if (menu->view < 0) menu->view = 0;
  174     /*debug("2:%d %d %d %d", menu->ni, w, menu->view, menu->selected);*/
  175 }
  176 
  177 void display_menu(struct terminal *term, struct menu *menu)
  178 {
  179     int p, s;
  180     fill_area(term, menu->x+1, menu->y+1, menu->xw-2, menu->yw-2, COLOR_MENU_TEXT | ' ');
  181     draw_frame(term, menu->x, menu->y, menu->xw, menu->yw, COLOR_MENU_FRAME, 1);
  182     for (p = menu->view, s = menu->y + 1; p < menu->ni && p < menu->view + menu->yw - 2; p++, s++) {
  183         int x;
  184         int h = 0;
  185         unsigned char c;
  186         unsigned char *tmptext = _(menu->items[p].text, term);
  187         int co = p == menu->selected ? h = 1, COLOR_MENU_SELECTED : COLOR_MENU_TEXT;
  188         if (h) {
  189             set_cursor(term, menu->x+1, s, term->x - 1, term->y - 1);
  190             /*set_window_ptr(menu->win, menu->x+3, s+1);*/
  191             set_window_ptr(menu->win, menu->x+menu->xw, s);
  192             fill_area(term, menu->x+1, s, menu->xw-2, 1, co | ' ');
  193         }
  194         if (menu->items[p].hotkey != M_BAR || (tmptext && tmptext[0])) {
  195             int l = strlen(_(menu->items[p].rtext, term));
  196             for (x = l - 1; x >= 0 && menu->xw - 4 >= l - x && (c = _(menu->items[p].rtext, term)[x]); x--)
  197                 set_char(term, menu->x + menu->xw - 2 - l + x, s, c | co);
  198             for (x = 0; x < menu->xw - 4 && (c = tmptext[x]); x++)
  199                 set_char(term, menu->x + x + 2, s, !h && charset_upcase(c, term->spec->charset) == menu->hotkeys[p] ? h = 1, COLOR_MENU_HOTKEY | c : co | c);
  200         } else {
  201             set_char(term, menu->x, s, COLOR_MENU_FRAME | ATTR_FRAME | 0xc3);
  202             fill_area(term, menu->x+1, s, menu->xw-2, 1, COLOR_MENU_FRAME | ATTR_FRAME | 0xc4);
  203             set_char(term, menu->x+menu->xw-1, s, COLOR_MENU_FRAME | ATTR_FRAME | 0xb4);
  204         }
  205     }
  206     redraw_from_window(menu->win);
  207 }
  208 
  209 void menu_func(struct window *win, struct event *ev, int fwd)
  210 {
  211     int s = 0;
  212     struct menu *menu = win->data;
  213     struct window *w1;
  214     menu->win = win;
  215     switch ((int)ev->ev) {
  216         case EV_INIT:
  217         case EV_RESIZE:
  218         case EV_REDRAW:
  219             get_parent_ptr(win, &menu->xp, &menu->yp);
  220             count_menu_size(win->term, menu);
  221             menu->selected--;
  222             scroll_menu(menu, 1);
  223         /*case EV_REDRAW:*/
  224             display_menu(win->term, menu);
  225             break;
  226         case EV_MOUSE:
  227             if (ev->x < menu->x || ev->x >= menu->x+menu->xw || ev->y < menu->y || ev->y >= menu->y+menu->yw) {
  228                 if ((ev->b & BM_ACT) == B_DOWN) del:delete_window_ev(win, ev);
  229                 else for (w1 = win; (void *)w1 != &win->term->windows; w1 = w1->next) {
  230                     struct menu *m1;
  231                     if (w1->handler == mainmenu_func) {
  232                         if (!ev->y) goto del;
  233                         break;
  234                     }
  235                     if (w1->handler != menu_func) break;
  236                     m1 = w1->data;
  237                     if (ev->x > m1->x && ev->x < m1->x+m1->xw-1 && ev->y > m1->y && ev->y < m1->y+m1->yw-1) goto del;
  238                 }
  239             } else {
  240                 if (!(ev->x < menu->x || ev->x >= menu->x+menu->xw || ev->y < menu->y+1 || ev->y >= menu->y+menu->yw-1)) {
  241                     int s = ev->y - menu->y-1 + menu->view;
  242                     if (s >= 0 && s < menu->ni && menu->items[s].hotkey != M_BAR) {
  243                         menu->selected = s;
  244                         scroll_menu(menu, 0);
  245                         display_menu(win->term, menu);
  246                         if ((ev->b & BM_ACT) == B_UP/* || menu->items[s].in_m*/) select_menu(win->term, menu);
  247                     }
  248                 }
  249             }
  250             break;
  251         case EV_KBD:
  252             switch (kbd_action(KM_MENU, ev)) {
  253                 case ACT_LEFT:
  254                 case ACT_RIGHT:
  255                     if ((void *)win->next != &win->term->windows && win->next->handler == mainmenu_func) goto mm;
  256                     /*for (w1 = win; (void *)w1 != &win->term->windows; w1 = w1->next) {
  257                         if (w1->handler == mainmenu_func) goto mm;
  258                         if (w1->handler != menu_func) break;
  259                     }*/
  260                     if (kbd_action(KM_MENU, ev) == ACT_RIGHT) goto enter;
  261                     delete_window(win);
  262                     goto break2;
  263                 case ACT_UP: scroll_menu(menu, -1); break;
  264                 case ACT_DOWN: scroll_menu(menu, 1); break;
  265                 case ACT_HOME: menu->selected = -1, scroll_menu(menu, 1); break;
  266                 case ACT_END: menu->selected = menu->ni, scroll_menu(menu, -1); break;
  267                 case ACT_PAGE_UP:
  268                     if ((menu->selected -= menu->yw - 3) < -1) menu->selected = -1;
  269                     if ((menu->view -= menu->yw - 2) < 0) menu->view = 0;
  270                     scroll_menu(menu, -1);
  271                     break;
  272                 case ACT_PAGE_DOWN:
  273                     if ((menu->selected += menu->yw - 3) > menu->ni) menu->selected = menu->ni;
  274                     if ((menu->view += menu->yw - 2) >= menu->ni - menu->yw + 2) menu->view = menu->ni - menu->yw + 2;
  275                     scroll_menu(menu, 1);
  276                     break;
  277                 default:
  278                     if ((ev->x >= KBD_F1 && ev->x <= KBD_F12) || ev->y == KBD_ALT) {
  279                         mm:
  280                         delete_window_ev(win, ev);
  281                         goto break2;
  282                     }
  283                     if (ev->x == KBD_ESC) {
  284                         delete_window_ev(win, (void *)win->next != &win->term->windows && win->next->handler == mainmenu_func ? ev : NULL);
  285                         goto break2;
  286                     }
  287                     if (ev->x > ' ' && ev->x < 256) {
  288                         int i;
  289                         for (i = 0; i < menu->ni; i++) {
  290                             if (charset_upcase(ev->x, win->term->spec->charset) == menu->hotkeys[i]) {
  291                                 menu->selected = i;
  292                                 scroll_menu(menu, 0);
  293                                 s = 1;
  294                             }
  295                         }
  296                     }
  297                     break;
  298             }
  299             display_menu(win->term, menu);
  300             if (s || ev->x == KBD_ENTER || ev->x == ' ') {
  301                 enter:
  302                 select_menu(win->term, menu);
  303             }
  304             break2:
  305             break;
  306         case EV_ABORT:
  307             if (menu->items->free_i) {
  308                 int i;
  309                 for (i = 0; i < menu->ni; i++) {
  310                     if (menu->items[i].free_i & 2) mem_free(menu->items[i].text);
  311                     if (menu->items[i].free_i & 4) mem_free(menu->items[i].rtext);
  312                 }
  313                 mem_free(menu->items);
  314             }
  315             if (menu->free_function)
  316                 register_bottom_half(menu->free_function, menu->free_data);
  317             break;
  318     }
  319 }
  320 
  321 void do_mainmenu(struct terminal *term, struct menu_item *items, void *data, int sel)
  322 {
  323     int i;
  324     struct mainmenu *menu;
  325     for (i = 0; items[i].text; i++) if (i == MAXINT - sizeof(struct mainmenu)) overalloc();
  326     menu = mem_alloc(sizeof(struct mainmenu) + (!i ? 0 : i - 1));
  327     menu->selected = sel == -1 ? 0 : sel;
  328     menu->ni = i;
  329     menu->items = items;
  330     menu->data = data;
  331     for (i = 0; i < menu->ni; i++)
  332         menu->hotkeys[i] = select_hotkey(term, NULL, items[i].hotkey, menu->hotkeys, i);
  333     add_window(term, mainmenu_func, menu);
  334     if (sel != -1) {
  335         struct event ev = {EV_KBD, KBD_ENTER, 0, 0};
  336         struct window *win = term->windows.next;
  337         win->handler(win, &ev, 0);
  338     }
  339 }
  340 
  341 void display_mainmenu(struct terminal *term, struct mainmenu *menu)
  342 {
  343     int i;
  344     int p = 2;
  345     fill_area(term, 0, 0, term->x, 1, COLOR_MAINMENU | ' ');
  346     for (i = 0; i < menu->ni; i++) {
  347         int s = 0;
  348         int j;
  349         unsigned char c;
  350         unsigned char *tmptext = _(menu->items[i].text, term);
  351         int co = i == menu->selected ? s = 1, COLOR_MAINMENU_SELECTED : COLOR_MAINMENU;
  352         if (s) {
  353             fill_area(term, p, 0, 2, 1, co | ' ');
  354             fill_area(term, p+strlen(tmptext)+2, 0, 2, 1, co | ' ');
  355             menu->sp = p;
  356             set_cursor(term, p, 0, term->x - 1, term->y - 1);
  357             set_window_ptr(menu->win, p, 1);
  358         }
  359         p += 2;
  360         for (j = 0; (c = tmptext[j]); j++, p++)
  361             set_char(term, p, 0, (!s && charset_upcase(c, term->spec->charset) == menu->hotkeys[i] ? s = 1, COLOR_MAINMENU_HOTKEY : co) | c);
  362         p += 2;
  363     }
  364     redraw_from_window(menu->win);
  365 }
  366 
  367 void select_mainmenu(struct terminal *term, struct mainmenu *menu)
  368 {
  369     struct menu_item *it;
  370     if (menu->selected < 0 || menu->selected >= menu->ni) return;
  371     it = &menu->items[menu->selected];
  372     if (it->hotkey == M_BAR) return;
  373     if (!it->in_m) {
  374         struct window *win, *win1;
  375         for (win = term->windows.next; (void *)win != &term->windows && (win->handler == menu_func || win->handler == mainmenu_func); win1 = win->next, delete_window(win), win = win1) ;
  376     }
  377     it->func(term, it->data, menu->data);
  378 }
  379 
  380 void mainmenu_func(struct window *win, struct event *ev, int fwd)
  381 {
  382     int s = 0;
  383     struct mainmenu *menu = win->data;
  384     menu->win = win;
  385     switch ((int)ev->ev) {
  386         case EV_INIT:
  387         case EV_RESIZE:
  388         case EV_REDRAW:
  389             display_mainmenu(win->term, menu);
  390             break;
  391         case EV_MOUSE:
  392             if ((ev->b & BM_ACT) == B_DOWN && ev->y) delete_window_ev(win, ev);
  393             else if (!ev->y) {
  394                 int i;
  395                 int p = 2;
  396                 for (i = 0; i < menu->ni; i++) {
  397                     int o = p;
  398                     unsigned char *tmptext = _(menu->items[i].text, win->term);
  399                     p += strlen(tmptext) + 4;
  400                     if (ev->x >= o && ev->x < p) {
  401                         menu->selected = i;
  402                         display_mainmenu(win->term, menu);
  403                         if ((ev->b & BM_ACT) == B_UP || menu->items[s].in_m) select_mainmenu(win->term, menu);
  404                         break;
  405                     }
  406                 }
  407             }
  408             break;
  409         case EV_KBD:
  410             if (ev->x == ' ' || ev->x == KBD_ENTER || ev->x == KBD_DOWN || ev->x == KBD_UP || ev->x == KBD_PAGE_DOWN || ev->x == KBD_PAGE_UP) {
  411                 select_mainmenu(win->term, menu);
  412                 break;
  413             }
  414             if (ev->x == KBD_LEFT) {
  415                 if (!menu->selected--) menu->selected = menu->ni - 1;
  416                 s = 1;
  417             }
  418             if (ev->x == KBD_RIGHT) {
  419                 if (++menu->selected >= menu->ni) menu->selected = 0;
  420                 s = 1;
  421             }
  422             if (ev->x == KBD_HOME) {
  423                 menu->selected = 0;
  424                 s = 1;
  425             }
  426             if (ev->x == KBD_END) {
  427                 menu->selected = menu->ni - 1;
  428                 s = 1;
  429             }
  430             if ((ev->x == KBD_LEFT || ev->x == KBD_RIGHT) && fwd) {
  431                 display_mainmenu(win->term, menu);
  432                 select_mainmenu(win->term, menu);
  433                 break;
  434             }
  435             if (ev->x > ' ' && ev->x < 256) {
  436                 int i;
  437                 s = 1;
  438                 for (i = 0; i < menu->ni; i++) {
  439                     if (charset_upcase(ev->x, win->term->spec->charset) == menu->hotkeys[i]) {
  440                         menu->selected = i;
  441                         s = 2;
  442                     }
  443                 }
  444             } else if (!s) {
  445                 delete_window_ev(win, (ev->x >= KBD_F1 && ev->x <= KBD_F12) || ev->y & KBD_ALT ? ev : NULL);
  446                 break;
  447             }
  448             display_mainmenu(win->term, menu);
  449             if (s == 2) select_mainmenu(win->term, menu);
  450             break;
  451         case EV_ABORT:
  452             break;
  453     }
  454 }
  455 
  456 struct menu_item *new_menu(int free_i)
  457 {
  458     struct menu_item *mi;
  459     mi = mem_alloc(sizeof(struct menu_item));
  460     memset(mi, 0, sizeof(struct menu_item));
  461     mi->free_i = free_i;
  462     return mi;
  463 }
  464 
  465 void add_to_menu(struct menu_item **mi, unsigned char *text, unsigned char *rtext, unsigned char *hotkey, void (*func)(struct terminal *, void *, void *), void *data, int in_m)
  466 {
  467     struct menu_item *mii;
  468     int n;
  469     for (n = 0; (*mi)[n].text; n++) if (n == MAXINT) overalloc();
  470     if (((unsigned)n + 2) > MAXINT / sizeof(struct menu_item)) overalloc();
  471     mii = mem_realloc(*mi, (n + 2) * sizeof(struct menu_item));
  472     *mi = mii;
  473     memcpy(mii + n + 1, mii + n, sizeof(struct menu_item));
  474     mii[n].text = text;
  475     mii[n].rtext = rtext;
  476     mii[n].hotkey = hotkey;
  477     mii[n].func = func;
  478     mii[n].data = data;
  479     mii[n].in_m = in_m;
  480 }
  481 
  482 void do_dialog(struct terminal *term, struct dialog *dlg, struct memory_list *ml)
  483 {
  484     struct dialog_data *dd;
  485     struct dialog_item *d;
  486     int n = 0;
  487     for (d = dlg->items; d->type != D_END; d++) {
  488         if (n == MAXINT) overalloc();
  489         n++;
  490     }
  491     if ((unsigned)n > (MAXINT - sizeof(struct dialog_data)) / sizeof(struct dialog_item_data)) overalloc();
  492     dd = mem_alloc(sizeof(struct dialog_data) + sizeof(struct dialog_item_data) * n);
  493     dd->dlg = dlg;
  494     dd->n = n;
  495     dd->ml = ml;
  496     add_window(term, dialog_func, dd);
  497 }
  498 
  499 void display_dlg_item(struct dialog_data *dlg, struct dialog_item_data *di, int sel)
  500 {
  501     struct terminal *term = dlg->win->term;
  502     switch(di->item->type) {
  503         int co;
  504         unsigned char *text;
  505         case D_CHECKBOX:
  506             if (di->checked) print_text(term, di->x, di->y, 3, "[X]", COLOR_DIALOG_CHECKBOX);
  507             else print_text(term, di->x, di->y, 3, "[ ]", COLOR_DIALOG_CHECKBOX);
  508             if (sel) {
  509                 set_cursor(term, di->x + 1, di->y, di->x + 1, di->y);
  510                 set_window_ptr(dlg->win, di->x, di->y);
  511             }
  512             break;
  513         case D_FIELD_PASS:
  514         case D_FIELD:
  515             if (di->vpos + di->l <= di->cpos) di->vpos = di->cpos - di->l + 1;
  516             if (di->vpos > di->cpos) di->vpos = di->cpos;
  517             if (di->vpos < 0) di->vpos = 0;
  518             fill_area(term, di->x, di->y, di->l, 1, COLOR_DIALOG_FIELD | ' ');
  519             if (di->item->type == D_FIELD) {
  520                 print_text(term, di->x, di->y, strlen(di->cdata + di->vpos) <= (size_t)di->l ? (int)strlen(di->cdata + di->vpos) : di->l, di->cdata + di->vpos, COLOR_DIALOG_FIELD_TEXT);
  521             } else {
  522                 fill_area(term, di->x, di->y, strlen(di->cdata + di->vpos) <= (size_t)di->l ? (int)strlen(di->cdata + di->vpos) : di->l, 1, COLOR_DIALOG_FIELD_TEXT | '*');
  523             }
  524             if (sel) {
  525                 set_cursor(term, di->x + di->cpos - di->vpos, di->y, di->x + di->cpos - di->vpos, di->y);
  526                 set_window_ptr(dlg->win, di->x, di->y);
  527             }
  528             break;
  529         case D_BUTTON:
  530             co = sel ? COLOR_DIALOG_BUTTON_SELECTED : COLOR_DIALOG_BUTTON;
  531             text = _(di->item->text, term);
  532             print_text(term, di->x, di->y, 2, "[ ", co);
  533             print_text(term, di->x + 2, di->y, strlen(text), text, co);
  534             print_text(term, di->x + 2 + strlen(text), di->y, 2, " ]", co);
  535             if (sel) {
  536                 set_cursor(term, di->x + 2, di->y, di->x + 2, di->y);
  537                 set_window_ptr(dlg->win, di->x, di->y);
  538             }
  539             break;
  540         case D_BOX:
  541             /* Draw a hierarchy box */
  542             show_dlg_item_box(dlg, di);
  543             break;
  544         default:
  545             internal("Tried to draw unknown");
  546     }
  547 }
  548 
  549 void dlg_select_item(struct dialog_data *dlg, struct dialog_item_data *di)
  550 {
  551     if (di->item->type == D_CHECKBOX) {
  552         if (!di->item->gid) di -> checked = *(int *)di->cdata = !*(int *)di->cdata;
  553         else {
  554             int i;
  555             for (i = 0; i < dlg->n; i++) {
  556                 if (dlg->items[i].item->type == D_CHECKBOX && dlg->items[i].item->gid == di->item->gid) {
  557                     *(int *)dlg->items[i].cdata = di->item->gnum;
  558                     dlg->items[i].checked = 0;
  559                     display_dlg_item(dlg, &dlg->items[i], 0);
  560                 }
  561             }
  562             di->checked = 1;
  563         }
  564         display_dlg_item(dlg, di, 1);
  565     }
  566     else if (di->item->type == D_BUTTON) di->item->fn(dlg, di);
  567 }
  568 
  569 void dlg_set_history(struct dialog_item_data *di)
  570 {
  571     unsigned char *s = "";
  572     size_t l;
  573     if ((void *)di->cur_hist != &di->history) s = di->cur_hist->d;
  574     if ((l = strlen(s)) >= (size_t)di->item->dlen) l = di->item->dlen - 1;
  575     memcpy(di->cdata, s, l);
  576     di->cdata[l] = 0;
  577     di->cpos = l;
  578     di->vpos = 0;
  579 }
  580 
  581 int dlg_mouse(struct dialog_data *dlg, struct dialog_item_data *di, struct event *ev)
  582 {
  583     switch (di->item->type) {
  584         case D_BUTTON:
  585             if (ev->y != di->y || ev->x < di->x || (size_t)ev->x >= di->x + strlen(_(di->item->text, dlg->win->term)) + 4) return 0;
  586             display_dlg_item(dlg, &dlg->items[dlg->selected], 0);
  587             dlg->selected = di - dlg->items;
  588             display_dlg_item(dlg, di, 1);
  589             if ((ev->b & BM_ACT) == B_UP) dlg_select_item(dlg, di);
  590             return 1;
  591         case D_FIELD_PASS:
  592         case D_FIELD:
  593             if (ev->y != di->y || ev->x < di->x || ev->x >= di->x + di->l) return 0;
  594             if ((size_t)(di->cpos = di->vpos + ev->x - di->x) > strlen(di->cdata)) di->cpos = strlen(di->cdata);
  595             display_dlg_item(dlg, &dlg->items[dlg->selected], 0);
  596             dlg->selected = di - dlg->items;
  597             display_dlg_item(dlg, di, 1);
  598             return 1;
  599         case D_CHECKBOX:
  600             if (ev->y != di->y || ev->x < di->x || ev->x >= di->x + 3) return 0;
  601             display_dlg_item(dlg, &dlg->items[dlg->selected], 0);
  602             dlg->selected = di - dlg->items;
  603             display_dlg_item(dlg, di, 1);
  604             if ((ev->b & BM_ACT) == B_UP) dlg_select_item(dlg, di);
  605             return 1;
  606         case D_BOX:
  607             if ((ev->b & BM_ACT) == B_UP) {
  608                 if ( (ev->y >= di->y)  && (ev->x >= di->x && ev->x <= di->l + di->x) ) {
  609                     /* Clicked in the box. */
  610                     int offset;
  611                     offset = ev->y - di->y;
  612                     box_sel_set_visible(di, offset);
  613                     display_dlg_item(dlg, di, 1);
  614                     return 1;
  615                 }
  616             } /*else if ((ev->b & BM_ACT) == B_DRAG) {
  617                 debug("drag");
  618             }*/
  619     }
  620     return 0;
  621 }
  622 
  623 void redraw_dialog(struct dialog_data *dlg)
  624 {
  625     int i;
  626     struct terminal *term = dlg->win->term;
  627     draw_frame(term, dlg->x + DIALOG_LEFT_BORDER, dlg->y + DIALOG_TOP_BORDER, dlg->xw - 2 * DIALOG_LEFT_BORDER, dlg->yw - 2 * DIALOG_TOP_BORDER, COLOR_DIALOG_FRAME, DIALOG_FRAME);
  628     i = strlen(_(dlg->dlg->title, term));
  629     print_text(term, (dlg->xw - i) / 2 + dlg->x - 1, dlg->y + DIALOG_TOP_BORDER, 1, " ", COLOR_DIALOG_TITLE);
  630     print_text(term, (dlg->xw - i) / 2 + dlg->x, dlg->y + DIALOG_TOP_BORDER, i, _(dlg->dlg->title, term), COLOR_DIALOG_TITLE);
  631     print_text(term, (dlg->xw - i) / 2 + dlg->x + i, dlg->y + DIALOG_TOP_BORDER, 1, " ", COLOR_DIALOG_TITLE);
  632     for (i = 0; i < dlg->n; i++) display_dlg_item(dlg, &dlg->items[i], i == dlg->selected);
  633     redraw_from_window(dlg->win);
  634 }
  635 
  636 void tab_compl(struct terminal *term, unsigned char *item, struct window *win)
  637 {
  638     struct event ev = {EV_REDRAW, 0, 0, 0};
  639     struct dialog_item_data *di = &((struct dialog_data*)win->data)->items[((struct dialog_data*)win->data)->selected];
  640     size_t l = strlen(item);
  641     if (l >= (size_t)di->item->dlen) l = di->item->dlen - 1;
  642     memcpy(di->cdata, item, l);
  643     di->cdata[l] = 0;
  644     di->cpos = l;
  645     di->vpos = 0;
  646     ev.x = term->x;
  647     ev.y = term->y;
  648     dialog_func(win, &ev, 0);
  649 }
  650 
  651 void do_tab_compl(struct terminal *term, struct list_head *history, struct window *win)
  652 {
  653     unsigned char *cdata = ((struct dialog_data*)win->data)->items[((struct dialog_data*)win->data)->selected].cdata;
  654     int l = strlen(cdata), n = 0;
  655     struct history_item *hi;
  656     struct menu_item *items = DUMMY;
  657     foreach(hi, *history) if (!strncmp(cdata, hi->d, l)) {
  658         if (!(n & (ALLOC_GR - 1))) {
  659             if ((unsigned)n > MAXINT / sizeof(struct menu_item) - ALLOC_GR - 1) overalloc();
  660             items = mem_realloc(items, (n + ALLOC_GR + 1) * sizeof(struct menu_item));
  661         }
  662         items[n].text = hi->d;
  663         items[n].rtext = "";
  664         items[n].hotkey = "";
  665         items[n].func = (void(*)(struct terminal *, void *, void *))tab_compl;
  666         items[n].rtext = "";
  667         items[n].data = hi->d;
  668         items[n].in_m = 0;
  669         items[n].free_i = 1;
  670         if (n == MAXINT) overalloc();
  671         n++;
  672     }
  673     if (n == 1) {
  674         tab_compl(term, items->data, win);
  675         mem_free(items);
  676         return;
  677     }
  678     if (n) {
  679         memset(&items[n], 0, sizeof(struct menu_item));
  680         do_menu_selected(term, items, win, n - 1, NULL, NULL);
  681     }
  682 }
  683 
  684 void dialog_func(struct window *win, struct event *ev, int fwd)
  685 {
  686     int i;
  687     struct terminal *term = win->term;
  688     struct dialog_data *dlg = win->data;
  689     struct dialog_item_data *di;
  690 
  691     dlg->win = win;
  692 
  693     /* Use nonstandard event handlers */
  694     if (dlg->dlg->handle_event && ((dlg->dlg->handle_event)(dlg, ev) == EVENT_PROCESSED) ) {
  695         return;
  696     }
  697     
  698     switch ((int)ev->ev) {
  699         case EV_INIT:
  700             for (i = 0; i < dlg->n; i++) {
  701                 /* volatile because of a compiler bug */
  702                 struct dialog_item_data * volatile di = &dlg->items[i];
  703                 memset(di, 0, sizeof(struct dialog_item_data));
  704                 di->item = &dlg->dlg->items[i];
  705                 di->cdata = mem_alloc(di->item->dlen);
  706                 memcpy(di->cdata, di->item->data, di->item->dlen);
  707                 if (di->item->type == D_CHECKBOX) {
  708                     if (di->item->gid) {
  709                         if (*(int *)di->cdata == di->item->gnum) di->checked = 1;
  710                     } else if (*(int *)di->cdata) di->checked = 1;
  711                 } 
  712                 if (di->item->type == D_BOX) {
  713                     /* Freed in bookmark_dialog_abort_handler() */
  714                     di->cdata = mem_alloc( sizeof(struct dlg_data_item_data_box) );
  715                     ((struct dlg_data_item_data_box*)di->cdata)->sel = -1;
  716                     ((struct dlg_data_item_data_box*)di->cdata)->box_top = 0;
  717                     ((struct dlg_data_item_data_box*)di->cdata)->list_len = -1;
  718 
  719                     init_list(((struct dlg_data_item_data_box*)di->cdata)->items);
  720                 }
  721                 init_list(di->history);
  722                 di->cur_hist = (struct history_item *)&di->history;
  723                 if (di->item->type == D_FIELD || di->item->type == D_FIELD_PASS) {
  724                     if (di->item->history) {
  725                         struct history_item *j;
  726                         foreach(j, di->item->history->items) {
  727                             struct history_item *hi;
  728                             hi = mem_alloc(sizeof(struct history_item) + strlen(j->d) + 1);
  729                             strcpy(hi->d, j->d);
  730                             add_to_list(di->history, hi);
  731                         }
  732                     }
  733                     di->cpos = strlen(di->cdata);
  734                 }
  735             }
  736             dlg->selected = 0;
  737             /*-fallthrough*/
  738         case EV_RESIZE:
  739         case EV_REDRAW:
  740             dlg->dlg->fn(dlg);
  741             redraw_dialog(dlg);
  742             break;
  743         case EV_MOUSE:
  744             for (i = 0; i < dlg->n; i++) if (dlg_mouse(dlg, &dlg->items[i], ev)) break;
  745             break;
  746         case EV_KBD:
  747             di = &dlg->items[dlg->selected];
  748             if (di->item->type == D_FIELD || di->item->type == D_FIELD_PASS) {
  749                 switch (kbd_action(KM_EDIT, ev)) {
  750                     case ACT_UP:
  751                         if ((void *)di->cur_hist->prev != &di->history) {
  752                             di->cur_hist = di->cur_hist->prev;
  753                             dlg_set_history(di);
  754                             goto dsp_f;
  755                         }
  756                         break;
  757                     case ACT_DOWN:
  758                         if ((void *)di->cur_hist != &di->history) {
  759                             di->cur_hist = di->cur_hist->next;
  760                             dlg_set_history(di);
  761                             goto dsp_f;
  762                         }
  763                         break;
  764                     case ACT_RIGHT:
  765                         if ((size_t)di->cpos < strlen(di->cdata)) di->cpos++;
  766                         goto dsp_f;
  767                     case ACT_LEFT:
  768                         if (di->cpos > 0) di->cpos--;
  769                         goto dsp_f;
  770                     case ACT_HOME:
  771                         di->cpos = 0;
  772                         goto dsp_f;
  773                     case ACT_END:
  774                         di->cpos = strlen(di->cdata);
  775                         goto dsp_f;
  776                     case ACT_BACKSPACE:
  777                         if (di->cpos) {
  778                             memmove(di->cdata + di->cpos - 1, di->cdata + di->cpos, strlen(di->cdata) - di->cpos + 1);
  779                             di->cpos--;
  780                         }
  781                         goto dsp_f;
  782                     case ACT_DELETE:
  783                         if ((size_t)di->cpos < strlen(di->cdata))
  784                             memmove(di->cdata + di->cpos, di->cdata + di->cpos + 1, strlen(di->cdata) - di->cpos + 1);
  785                         goto dsp_f;
  786                     case ACT_KILL_TO_BOL:
  787                         memmove(di->cdata, di->cdata + di->cpos, strlen(di->cdata + di->cpos) + 1);
  788                         di->cpos = 0;
  789                         goto dsp_f;
  790                     case ACT_KILL_TO_EOL:
  791                         di->cdata[di->cpos] = 0;
  792                         goto dsp_f;
  793                         case ACT_COPY_CLIPBOARD:
  794                         /* Copy to clipboard */
  795                         set_clipboard_text(di->cdata);
  796                         break;  /* We don't need to redraw */
  797                     case ACT_CUT_CLIPBOARD:
  798                         /* Cut to clipboard */                      
  799                         set_clipboard_text(di->cdata);
  800                         di->cdata[0] = 0;
  801                         di->cpos = 0;
  802                         goto dsp_f;
  803                     case ACT_PASTE_CLIPBOARD: {
  804                         /* Paste from clipboard */
  805                         unsigned char *clipboard = get_clipboard_text();
  806                         if (clipboard) {
  807                             unsigned char *nl = clipboard;
  808                             while ((nl = strchr(nl, '\n'))) *nl = ' ';
  809                             safe_strncpy(di->cdata, clipboard, di->item->dlen);
  810                             di->cpos = strlen(di->cdata);
  811                             mem_free(clipboard);
  812                         }
  813                         goto dsp_f;
  814                     }
  815                     case ACT_AUTO_COMPLETE: 
  816                         do_tab_compl(term, &di->history, win);
  817                         goto dsp_f;
  818                     default:
  819                         if (ev->x >= ' ' && ev->x < 0x100 && !ev->y) {
  820                             if (strlen(di->cdata) + 1 < (size_t)di->item->dlen) {
  821                                 memmove(di->cdata + di->cpos + 1, di->cdata + di->cpos, strlen(di->cdata) - di->cpos + 1);
  822                                 di->cdata[di->cpos++] = ev->x;
  823                             }
  824                             goto dsp_f;
  825                         }
  826                 }
  827                 goto gh;
  828                 dsp_f:
  829                 display_dlg_item(dlg, di, 1);
  830                 redraw_from_window(dlg->win);
  831                 break;
  832             }
  833             if ((ev->x == KBD_ENTER && di->item->type == D_BUTTON) || ev->x == ' ') {
  834                 dlg_select_item(dlg, di);
  835                 break;
  836             }
  837             gh:
  838             if (ev->x > ' ' && ev->x < 0x100) for (i = 0; i < dlg->n; i++)
  839                 if (dlg->dlg->items[i].type == D_BUTTON && charset_upcase(_(dlg->dlg->items[i].text, term)[0], term->spec->charset) == charset_upcase(ev->x, term->spec->charset)) {
  840                     sel:
  841                     if (dlg->selected != i) {
  842                         display_dlg_item(dlg, &dlg->items[dlg->selected], 0);
  843                         display_dlg_item(dlg, &dlg->items[i], 1);
  844                         dlg->selected = i;
  845                     }
  846                     dlg_select_item(dlg, &dlg->items[i]);
  847                     goto bla;
  848             }
  849             if (ev->x == KBD_ENTER) for (i = 0; i < dlg->n; i++)
  850                 if (dlg->dlg->items[i].type == D_BUTTON && dlg->dlg->items[i].gid & B_ENTER) goto sel;
  851             if (ev->x == KBD_ESC) for (i = 0; i < dlg->n; i++)
  852                 if (dlg->dlg->items[i].type == D_BUTTON && dlg->dlg->items[i].gid & B_ESC) goto sel;
  853             if ((ev->x == KBD_TAB && !ev->y) || ev->x == KBD_DOWN || ev->x == KBD_RIGHT) {
  854                 display_dlg_item(dlg, &dlg->items[dlg->selected], 0);
  855                 if ((++dlg->selected) >= dlg->n) dlg->selected = 0;
  856                 display_dlg_item(dlg, &dlg->items[dlg->selected], 1);
  857                 redraw_from_window(dlg->win);
  858                 break;
  859             }
  860             if ((ev->x == KBD_TAB && ev->y) || ev->x == KBD_UP || ev->x == KBD_LEFT) {
  861                 display_dlg_item(dlg, &dlg->items[dlg->selected], 0);
  862                 if ((--dlg->selected) < 0) dlg->selected = dlg->n - 1;
  863                 display_dlg_item(dlg, &dlg->items[dlg->selected], 1);
  864                 redraw_from_window(dlg->win);
  865                 break;
  866             }
  867             break;
  868         case EV_ABORT:
  869             /* Moved this line up so that the dlg would have access to its 
  870                 member vars before they get freed. */ 
  871             if (dlg->dlg->abort) dlg->dlg->abort(dlg);
  872             for (i = 0; i < dlg->n; i++) {
  873                 struct dialog_item_data *di = &dlg->items[i];
  874                 if (di->cdata) mem_free(di->cdata);
  875                 free_list(di->history);
  876             }
  877             freeml(dlg->ml);
  878     }
  879     bla:;
  880 }
  881 
  882 int check_number(struct dialog_data *dlg, struct dialog_item_data *di)
  883 {
  884     unsigned char *end;
  885     long l = strtol(di->cdata, (char **)(void *)&end, 10);
  886     if (!*di->cdata || *end) {
  887         msg_box(dlg->win->term, NULL, TEXT_(T_BAD_NUMBER), AL_CENTER, TEXT_(T_NUMBER_EXPECTED), NULL, 1, TEXT_(T_CANCEL), NULL, B_ENTER | B_ESC);
  888         return 1;
  889     }
  890     if (l < di->item->gid || l > di->item->gnum) {
  891         msg_box(dlg->win->term, NULL, TEXT_(T_BAD_NUMBER), AL_CENTER, TEXT_(T_NUMBER_OUT_OF_RANGE), NULL, 1, TEXT_(T_CANCEL), NULL, B_ENTER | B_ESC);
  892         return 1;
  893     }
  894     return 0;
  895 }
  896 
  897 int check_nonempty(struct dialog_data *dlg, struct dialog_item_data *di)
  898 {
  899     unsigned char *p;
  900     for (p = di->cdata; *p; p++) if (*p > ' ') return 0;
  901     msg_box(dlg->win->term, NULL, TEXT_(T_BAD_STRING), AL_CENTER, TEXT_(T_EMPTY_STRING_NOT_ALLOWED), NULL, 1, TEXT_(T_CANCEL), NULL, B_ENTER | B_ESC);
  902     return 1;
  903 }
  904 
  905 int cancel_dialog(struct dialog_data *dlg, struct dialog_item_data *di)
  906 {
  907     /*struct dialog *dl = dlg->dlg;*/
  908     delete_window(dlg->win);
  909     /*mem_free(dl);*/
  910     return 0;
  911 }
  912 
  913 int check_dialog(struct dialog_data *dlg)
  914 {
  915     int i;
  916     for (i = 0; i < dlg->n; i++)
  917         if (dlg->dlg->items[i].type == D_CHECKBOX || dlg->dlg->items[i].type == D_FIELD || dlg->dlg->items[i].type == D_FIELD_PASS)
  918             if (dlg->dlg->items[i].fn && dlg->dlg->items[i].fn(dlg, &dlg->items[i])) {
  919                 dlg->selected = i;
  920                 redraw_dialog(dlg);
  921                 return 1;
  922             }
  923     return 0;
  924 }
  925 
  926 void get_dialog_data(struct dialog_data *dlg)
  927 {
  928     int i;
  929     for (i = 0; i < dlg->n; i++) {
  930         /* volatile because of a compiler bug */
  931         void * volatile p1 = dlg->dlg->items[i].data;
  932         void * volatile p2 = dlg->items[i].cdata;
  933         volatile int l = dlg->dlg->items[i].dlen;
  934         memcpy(p1, p2, l);
  935     }
  936 }
  937 
  938 int ok_dialog(struct dialog_data *dlg, struct dialog_item_data *di)
  939 {
  940     void (*fn)(void *) = dlg->dlg->refresh;
  941     void *data = dlg->dlg->refresh_data;
  942     if (check_dialog(dlg)) return 1;
  943     get_dialog_data(dlg);
  944     if (fn) fn(data);
  945     return cancel_dialog(dlg, di);
  946 }
  947 
  948 void center_dlg(struct dialog_data *dlg)
  949 {
  950     dlg->x = (dlg->win->term->x - dlg->xw) / 2;
  951     dlg->y = (dlg->win->term->y - dlg->yw) / 2;
  952 }
  953 
  954 void draw_dlg(struct dialog_data *dlg)
  955 {
  956     fill_area(dlg->win->term, dlg->x, dlg->y, dlg->xw, dlg->yw, COLOR_DIALOG | ' ');
  957 }
  958 
  959 void max_text_width(struct terminal *term, unsigned char *text, int *width)
  960 {
  961     text = _(text, term);
  962     do {
  963         int c = 0;
  964         while (*text && *text != '\n') text++, c++;
  965         if (c > *width) *width = c;
  966     } while (*(text++));
  967 }
  968 
  969 void min_text_width(struct terminal *term, unsigned char *text, int *width)
  970 {
  971     text = _(text, term);
  972     do {
  973         int c = 0;
  974         while (*text && *text != '\n' && *text != ' ') text++, c++;
  975         if (c > *width) *width = c;
  976     } while (*(text++));
  977 }
  978 
  979 void dlg_format_text(struct terminal *term, struct terminal *t2, unsigned char *text, int x, int *y, int w, int *rw, int co, int align)
  980 {
  981     text = _(text, t2);
  982     do {
  983         unsigned char *tx;
  984         unsigned char *tt = text;
  985         int s;
  986         int xx = x;
  987         do {
  988             while (*text && *text != '\n' && *text != ' ') {
  989                 /*if (term) set_char(term, xx, *y, co | *text);*/
  990                 text++, xx++;
  991             }
  992             tx = ++text;
  993             xx++;
  994             if (*(text - 1) != ' ') break;
  995             while (*tx && *tx != '\n' && *tx != ' ') tx++;
  996         } while (tx - text + xx - x <= w);
  997         s = (align & AL_MASK) == AL_CENTER ? (w - (xx - 1 - x)) / 2 : 0;
  998         if (s < 0) s = 0;
  999         while (tt < text - 1) {
 1000             if (s >= w) {
 1001                 s = 0, (*y)++;
 1002                 if (rw) *rw = w;
 1003                 rw = NULL;
 1004             }
 1005             if (term) set_char(term, x + s, *y, co | *tt);
 1006             s++, tt++;
 1007         }
 1008         if (rw && xx - 1 - x > *rw) *rw = xx - 1 - x;
 1009         (*y)++;
 1010     } while (*(text - 1));
 1011 }
 1012 
 1013 void max_buttons_width(struct terminal *term, struct dialog_item_data *butt, int n, int *width)
 1014 {
 1015     int w = -2;
 1016     int i;
 1017     for (i = 0; i < n; i++) w += strlen(_((butt++)->item->text, term)) + 6;
 1018     if (w > *width) *width = w;
 1019 }
 1020 
 1021 void min_buttons_width(struct terminal *term, struct dialog_item_data *butt, int n, int *width)
 1022 {
 1023     int i;
 1024     for (i = 0; i < n; i++) {
 1025         int w = strlen(_((butt++)->item->text, term)) + 4;
 1026         if (w > *width) *width = w;
 1027     }
 1028 }
 1029 
 1030 void dlg_format_buttons(struct terminal *term, struct terminal *t2, struct dialog_item_data *butt, int n, int x, int *y, int w, int *rw, int align)
 1031 {
 1032     int i1 = 0;
 1033     while (i1 < n) {
 1034         int i2 = i1 + 1;
 1035         int mw;
 1036         while (i2 < n) {
 1037             mw = 0;
 1038             max_buttons_width(t2, butt + i1, i2 - i1 + 1, &mw);
 1039             if (mw <= w) i2++;
 1040             else break;
 1041         }
 1042         mw = 0;
 1043         max_buttons_width(t2, butt + i1, i2 - i1, &mw);
 1044         if (rw && mw > *rw) if ((*rw = mw) > w) *rw = w;
 1045         if (term) {
 1046             int i;
 1047             int p = x + ((align & AL_MASK) == AL_CENTER ? (w - mw) / 2 : 0);
 1048             for (i = i1; i < i2; i++) {
 1049                 butt[i].x = p;
 1050                 butt[i].y = *y;
 1051                 p += (butt[i].l = strlen(_(butt[i].item->text, t2)) + 4) + 2;
 1052             }
 1053         }
 1054         *y += 2;
 1055         i1 = i2;
 1056     }
 1057 }
 1058 
 1059 void dlg_format_checkbox(struct terminal *term, struct terminal *t2, struct dialog_item_data *chkb, int x, int *y, int w, int *rw, unsigned char *text)
 1060 {
 1061     if (term) {
 1062         chkb->x = x;
 1063         chkb->y = *y;
 1064     }
 1065     if (rw) *rw -= 4;
 1066     dlg_format_text(term, t2, text, x + 4, y, w - 4, rw, COLOR_DIALOG_CHECKBOX_TEXT, AL_LEFT);
 1067     if (rw) *rw += 4;
 1068 }
 1069 
 1070 void dlg_format_checkboxes(struct terminal *term, struct terminal *t2, struct dialog_item_data *chkb, int n, int x, int *y, int w, int *rw, unsigned char **texts)
 1071 {
 1072     while (n) {
 1073         dlg_format_checkbox(term, t2, chkb, x, y, w, rw, _(texts[0], t2));
 1074         texts++; chkb++; n--;
 1075     }
 1076 }
 1077 
 1078 void checkboxes_width(struct terminal *term, unsigned char **texts, int *w, void (*fn)(struct terminal *, unsigned char *, int *))
 1079 {
 1080     while (texts[0]) {
 1081         *w -= 4;
 1082         fn(term, _(texts[0], term), w);
 1083         *w += 4;
 1084         texts++;
 1085     }
 1086 }
 1087 
 1088 void dlg_format_field(struct terminal *term, struct terminal *t2, struct dialog_item_data *item, int x, int *y, int w, int *rw, int align)
 1089 {
 1090     item->x = x;
 1091     item->y = *y;
 1092     item->l = w;
 1093     if (rw && item->l > *rw) if ((*rw = item->l) > w) *rw = w;
 1094     (*y)++;
 1095 }
 1096 
 1097 /* Layout for generic boxes */
 1098 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) {
 1099     item->x = x;
 1100     item->y = *y;
 1101     item->l = w;
 1102     if (rw && item->l > *rw) if ((*rw = item->l) > w) *rw = w;
 1103     (*y) += item->item->gid;
 1104 }
 1105 
 1106 void max_group_width(struct terminal *term, unsigned char **texts, struct dialog_item_data *item, int n, int *w)
 1107 {
 1108     int ww = 0;
 1109     while (n--) {
 1110         int wx = item->item->type == D_CHECKBOX ? 4 : item->item->type == D_BUTTON ? strlen(_(item->item->text, term)) + 5 : (size_t)item->item->dlen + 1;
 1111         wx += strlen(_(texts[0], term));
 1112         if (n) wx++;
 1113         ww += wx;
 1114         texts++;
 1115         item++;
 1116     }
 1117     if (ww > *w) *w = ww;
 1118 }
 1119 
 1120 void min_group_width(struct terminal *term, unsigned char **texts, struct dialog_item_data *item, int n, int *w)
 1121 {
 1122     while (n--) {
 1123         int wx = item->item->type == D_CHECKBOX ? 4 : item->item->type == D_BUTTON ? strlen(_(item->item->text, term)) + 5 : (size_t)item->item->dlen + 1;
 1124         wx += strlen(_(texts[0], term));
 1125         if (wx > *w) *w = wx;
 1126         texts++;
 1127         item++;
 1128     }
 1129 }
 1130 
 1131 void dlg_format_group(struct terminal *term, struct terminal *t2, unsigned char **texts, struct dialog_item_data *item, int n, int x, int *y, int w, int *rw)
 1132 {
 1133     int nx = 0;
 1134     while (n--) {
 1135         int sl;
 1136         int wx = item->item->type == D_CHECKBOX ? 4 : item->item->type == D_BUTTON ? strlen(_(item->item->text, t2)) + 5 : (size_t)item->item->dlen + 1;
 1137         if (_(texts[0], t2)[0]) sl = strlen(_(texts[0], t2));
 1138         else sl = -1;
 1139         wx += sl;
 1140         if (nx && nx + wx > w) {
 1141             nx = 0;
 1142             (*y) += 2;
 1143         }
 1144         if (term) {
 1145             print_text(term, x + nx + 4 * (item->item->type == D_CHECKBOX), *y, strlen(_(texts[0], t2)), _(texts[0], t2), COLOR_DIALOG_TEXT);
 1146             item->x = x + nx + (sl + 1) * (item->item->type != D_CHECKBOX);
 1147             item->y = *y;
 1148             if (item->item->type == D_FIELD || item->item->type == D_FIELD_PASS) item->l = item->item->dlen;
 1149         }
 1150         if (rw && nx + wx > *rw) if ((*rw = nx + wx) > w) *rw = w;
 1151         nx += wx + 1;
 1152         texts++;
 1153         item++;
 1154     }
 1155     (*y)++;
 1156 }
 1157 
 1158 void checkbox_list_fn(struct dialog_data *dlg)
 1159 {
 1160     struct terminal *term = dlg->win->term;
 1161     int max = 0, min = 0;
 1162     int w, rw;
 1163     int y = 0;
 1164     checkboxes_width(term, dlg->dlg->udata, &max, max_text_width);
 1165     checkboxes_width(term, dlg->dlg->udata, &min, min_text_width);
 1166     max_buttons_width(term, dlg->items + dlg->n - 2, 2, &max);
 1167     min_buttons_width(term, dlg->items + dlg->n - 2, 2, &min);
 1168     w = term->x * 9 / 10 - 2 * DIALOG_LB;
 1169     if (w > max) w = max;
 1170     if (w < min) w = min;
 1171     if (w > term->x - 2 * DIALOG_LB) w = term->x - 2 * DIALOG_LB;
 1172     if (w < 5) w = 5;
 1173     rw = 0;
 1174     dlg_format_checkboxes(NULL, term, dlg->items, dlg->n - 2, 0, &y, w, &rw, dlg->dlg->udata);
 1175     y++;
 1176     dlg_format_buttons(NULL, term, dlg->items + dlg->n - 2, 2, 0, &y, w, &rw, AL_CENTER);
 1177     w = rw;
 1178     dlg->xw = rw + 2 * DIALOG_LB;
 1179     dlg->yw = y + 2 * DIALOG_TB;
 1180     center_dlg(dlg);
 1181     draw_dlg(dlg);
 1182     y = dlg->y + DIALOG_TB + 1;
 1183     dlg_format_checkboxes(term, term, dlg->items, dlg->n - 2, dlg->x + DIALOG_LB, &y, w, NULL, dlg->dlg->udata);
 1184     y++;
 1185     dlg_format_buttons(term, term, dlg->items + dlg->n - 2, 2, dlg->x + DIALOG_LB, &y, w, &rw, AL_CENTER);
 1186 }
 1187 
 1188 void group_fn(struct dialog_data *dlg)
 1189 {
 1190     struct terminal *term = dlg->win->term;
 1191     int max = 0, min = 0;
 1192     int w, rw;
 1193     int y = 0;
 1194     max_group_width(term, dlg->dlg->udata, dlg->items, dlg->n - 2, &max);
 1195     min_group_width(term, dlg->dlg->udata, dlg->items, dlg->n - 2, &min);
 1196     max_buttons_width(term, dlg->items + dlg->n - 2, 2, &max);
 1197     min_buttons_width(term, dlg->items + dlg->n - 2, 2, &min);
 1198     w = term->x * 9 / 10 - 2 * DIALOG_LB;
 1199     if (w > max) w = max;
 1200     if (w < min) w = min;
 1201     if (w > term->x - 2 * DIALOG_LB) w = term->x - 2 * DIALOG_LB;
 1202     if (w < 1) w = 1;
 1203     rw = 0;
 1204     dlg_format_group(NULL, term, dlg->dlg->udata, dlg->items, dlg->n - 2, 0, &y, w, &rw);
 1205     y++;
 1206     dlg_format_buttons(NULL, term, dlg->items + dlg->n - 2, 2, 0, &y, w, &rw, AL_CENTER);
 1207     w = rw;
 1208     dlg->xw = rw + 2 * DIALOG_LB;
 1209     dlg->yw = y + 2 * DIALOG_TB;
 1210     center_dlg(dlg);
 1211     draw_dlg(dlg);
 1212     y = dlg->y + DIALOG_TB + 1;
 1213     dlg_format_group(term, term, dlg->dlg->udata, dlg->items, dlg->n - 2, dlg->x + DIALOG_LB, &y, w, NULL);
 1214     y++;
 1215     dlg_format_buttons(term, term, dlg->items + dlg->n - 2, 2, dlg->x + DIALOG_LB, &y, w, &rw, AL_CENTER);
 1216 }
 1217 
 1218 void msg_box_fn(struct dialog_data *dlg)
 1219 {
 1220     struct terminal *term = dlg->win->term;
 1221     int max = 0, min = 0;
 1222     int w, rw;
 1223     int y = 0;
 1224     unsigned char **ptr;
 1225     unsigned char *text = init_str();
 1226     int textl = 0;
 1227     for (ptr = dlg->dlg->udata; *ptr; ptr++) add_to_str(&text, &textl, _(*ptr, term));
 1228     max_text_width(term, text, &max);
 1229     min_text_width(term, text, &min);
 1230     max_buttons_width(term, dlg->items, dlg->n, &max);
 1231     min_buttons_width(term, dlg->items, dlg->n, &min);
 1232     w = term->x * 9 / 10 - 2 * DIALOG_LB;
 1233     if (w > max) w = max;
 1234     if (w < min) w = min;
 1235     if (w > term->x - 2 * DIALOG_LB) w = term->x - 2 * DIALOG_LB;
 1236     if (w < 1) w = 1;
 1237     rw = 0;
 1238     dlg_format_text(NULL, term, text, 0, &y, w, &rw, COLOR_DIALOG_TEXT, dlg->dlg->align);
 1239     y++;
 1240     dlg_format_buttons(NULL, term, dlg->items, dlg->n, 0, &y, w, &rw, AL_CENTER);
 1241     w = rw;
 1242     dlg->xw = rw + 2 * DIALOG_LB;
 1243     dlg->yw = y + 2 * DIALOG_TB;
 1244     center_dlg(dlg);
 1245     draw_dlg(dlg);
 1246     y = dlg->y + DIALOG_TB + 1;
 1247     dlg_format_text(term, term, text, dlg->x + DIALOG_LB, &y, w, NULL, COLOR_DIALOG_TEXT, dlg->dlg->align);
 1248     y++;
 1249     dlg_format_buttons(term, term, dlg->items, dlg->n, dlg->x + DIALOG_LB, &y, w, NULL, AL_CENTER);
 1250     mem_free(text);
 1251 }
 1252 
 1253 int msg_box_button(struct dialog_data *dlg, struct dialog_item_data *di)
 1254 {
 1255     void (*fn)(void *) = (void (*)(void *))di->item->udata;
 1256     void *data = dlg->dlg->udata2;
 1257     /*struct dialog *dl = dlg->dlg;*/
 1258     if (fn) fn(data);
 1259     cancel_dialog(dlg, di);
 1260     return 0;
 1261 }
 1262 
 1263 /* coverity[+free : arg-1] */
 1264 void msg_box(struct terminal *term, struct memory_list *ml, unsigned char *title, int align, /*unsigned char *text, void *data, int n,*/ ...)
 1265 {
 1266     struct dialog *dlg;
 1267     int i;
 1268     int n;
 1269     unsigned char *text;
 1270     unsigned char **udata;
 1271     void *udata2;
 1272     int udatan;
 1273     va_list ap;
 1274     va_start(ap, align);
 1275     udata = DUMMY;
 1276     udatan = 0;
 1277     do {
 1278         text = va_arg(ap, unsigned char *);
 1279         na_kovarne__to_je_narez:
 1280         udatan++;
 1281         if ((unsigned)udatan > MAXINT / sizeof(unsigned char *)) overalloc();
 1282         udata = mem_realloc(udata, udatan * sizeof(unsigned char *));
 1283         udata[udatan - 1] = text;
 1284         if (text && !(align & AL_EXTD_TEXT)) {
 1285             text = NULL;
 1286             goto na_kovarne__to_je_narez;
 1287         }
 1288     } while (text);
 1289     udata2 = va_arg(ap, void *);
 1290     n = va_arg(ap, int);
 1291     if ((unsigned)n > (MAXINT - sizeof(struct dialog)) / sizeof(struct dialog_item) - 1) overalloc();
 1292     dlg = mem_alloc(sizeof(struct dialog) + (n + 1) * sizeof(struct dialog_item));
 1293     memset(dlg, 0, sizeof(struct dialog) + (n + 1) * sizeof(struct dialog_item));
 1294     dlg->title = title;
 1295     dlg->fn = msg_box_fn;
 1296     dlg->udata = udata;
 1297     dlg->udata2 = udata2;
 1298     dlg->align = align;
 1299     for (i = 0; i < n; i++) {
 1300         unsigned char *m;
 1301         void (*fn)(void *);
 1302         int flags;
 1303         m = va_arg(ap, unsigned char *);
 1304         fn = va_arg(ap, void *);
 1305         flags = va_arg(ap, int);
 1306         if (!m) {
 1307             i--, n--;
 1308             continue;
 1309         }
 1310         dlg->items[i].type = D_BUTTON;
 1311         dlg->items[i].gid = flags;
 1312         dlg->items[i].fn = msg_box_button;
 1313         dlg->items[i].dlen = 0;
 1314         dlg->items[i].text = m;
 1315         dlg->items[i].udata = fn;
 1316     }
 1317     va_end(ap);
 1318     dlg->items[i].type = D_END;
 1319     add_to_ml(&ml, dlg, udata, NULL);
 1320     do_dialog(term, dlg, ml);
 1321 }
 1322 
 1323 void add_to_history(struct history *h, unsigned char *t, int check_duplicates)
 1324 {
 1325     struct history_item *hi, *hs;
 1326     size_t l;
 1327     if (!h || !t || !*t) return;
 1328     l = strlen(t);
 1329     if (l > MAXINT - sizeof(struct history_item)) overalloc();
 1330     hi = mem_alloc(sizeof(struct history_item) + l);
 1331     memcpy(hi->d, t, l + 1);
 1332     if (check_duplicates) foreach(hs, h->items) if (!strcmp(hs->d, t)) {
 1333         struct history_item *hd = hs;
 1334         hs = hs->prev;
 1335         del_from_list(hd);
 1336         mem_free(hd);
 1337         h->n--;
 1338     }
 1339     add_to_list(h->items, hi);
 1340     h->n++;
 1341     while (h->n > MAX_HISTORY_ITEMS) {
 1342         struct history_item *hd = h->items.prev;
 1343         if ((void *)hd == &h->items) {
 1344             internal("history is empty");
 1345             h->n = 0;
 1346             return;
 1347         }
 1348         del_from_list(hd);
 1349         mem_free(hd);
 1350         h->n--;
 1351     }
 1352 }
 1353 
 1354 int input_field_cancel(struct dialog_data *dlg, struct dialog_item_data *di)
 1355 {
 1356     void (*fn)(void *) = di->item->udata;
 1357     void *data = dlg->dlg->udata2;
 1358     if (fn) fn(data);
 1359     cancel_dialog(dlg, di);
 1360     return 0;
 1361 }
 1362 
 1363 int input_field_ok(struct dialog_data *dlg, struct dialog_item_data *di)
 1364 {
 1365     void (*fn)(void *, unsigned char *) = di->item->udata;
 1366     void *data = dlg->dlg->udata2;
 1367     unsigned char *text = dlg->items->cdata;
 1368     if (check_dialog(dlg)) return 1;
 1369     add_to_history(dlg->dlg->items->history, text, 1);
 1370     if (fn) fn(data, text);
 1371     ok_dialog(dlg, di);
 1372     return 0;
 1373 }
 1374 
 1375 void input_field_fn(struct dialog_data *dlg)
 1376 {
 1377     struct terminal *term = dlg->win->term;
 1378     int max = 0, min = 0;
 1379     int w, rw;
 1380     int y = -1;
 1381     max_text_width(term, dlg->dlg->udata, &max);
 1382     min_text_width(term, dlg->dlg->udata, &min);
 1383     max_buttons_width(term, dlg->items + 1, 2, &max);
 1384     min_buttons_width(term, dlg->items + 1, 2, &min);
 1385     if (max < dlg->dlg->items->dlen) max = dlg->dlg->items->dlen;
 1386     w = term->x * 9 / 10 - 2 * DIALOG_LB;
 1387     if (w > max) w = max;
 1388     if (w < min) w = min;
 1389     rw = 0; /* !!! FIXME: input field */
 1390     dlg_format_text(NULL, term, dlg->dlg->udata, 0, &y, w, &rw, COLOR_DIALOG_TEXT, AL_LEFT);
 1391     dlg_format_field(NULL, term, dlg->items, 0, &y, w, &rw, AL_LEFT);
 1392     y++;
 1393     dlg_format_buttons(NULL, term, dlg->items + 1, 2, 0, &y, w, &rw, AL_CENTER);
 1394     w = rw;
 1395     dlg->xw = rw + 2 * DIALOG_LB;
 1396     dlg->yw = y + 2 * DIALOG_TB;
 1397     center_dlg(dlg);
 1398     draw_dlg(dlg);
 1399     y = dlg->y + DIALOG_TB;
 1400     dlg_format_text(term, term, dlg->dlg->udata, dlg->x + DIALOG_LB, &y, w, NULL, COLOR_DIALOG_TEXT, AL_LEFT);
 1401     dlg_format_field(term, term, dlg->items, dlg->x + DIALOG_LB, &y, w, NULL, AL_LEFT);
 1402     y++;
 1403     dlg_format_buttons(term, term, dlg->items + 1, 2, dlg->x + DIALOG_LB, &y, w, NULL, AL_CENTER);
 1404 }
 1405 
 1406 /* coverity[+free : arg-1] */
 1407 void input_field(struct terminal *term, struct memory_list *ml, unsigned char *title, unsigned char *text, unsigned char *okbutton, unsigned char *cancelbutton, void *data, struct history *history, int l, unsigned char *def, int min, int max, int (*check)(struct dialog_data *, struct dialog_item_data *), void (*fn)(void *, unsigned char *), void (*cancelfn)(void *))
 1408 {
 1409     struct dialog *dlg;
 1410     unsigned char *field;
 1411     if ((unsigned)l > MAXINT - sizeof(struct dialog) - 4 * sizeof(struct dialog_item)) overalloc();
 1412     dlg = mem_alloc(sizeof(struct dialog) + 4 * sizeof(struct dialog_item) + l);
 1413     memset(dlg, 0, sizeof(struct dialog) + 4 * sizeof(struct dialog_item) + l);
 1414     *(field = (unsigned char *)dlg + sizeof(struct dialog) + 4 * sizeof(struct dialog_item)) = 0;
 1415     if (def) {
 1416         if (strlen(def) + 1 > (size_t)l) memcpy(field, def, l - 1);
 1417         else strcpy(field, def);
 1418     }
 1419     dlg->title = title;
 1420     dlg->fn = input_field_fn;
 1421     dlg->udata = text;
 1422     dlg->udata2 = data;
 1423     dlg->items[0].type = D_FIELD;
 1424     dlg->items[0].gid = min;
 1425     dlg->items[0].gnum = max;
 1426     dlg->items[0].fn = check;
 1427     dlg->items[0].history = history;
 1428     dlg->items[0].dlen = l;
 1429     dlg->items[0].data = field;
 1430     dlg->items[1].type = D_BUTTON;
 1431     dlg->items[1].gid = B_ENTER;
 1432     dlg->items[1].fn = input_field_ok;
 1433     dlg->items[1].dlen = 0;
 1434     dlg->items[1].text = okbutton;
 1435     dlg->items[1].udata = fn;
 1436     dlg->items[2].type = D_BUTTON;
 1437     dlg->items[2].gid = B_ESC;
 1438     dlg->items[2].fn = input_field_cancel;
 1439     dlg->items[2].dlen = 0;
 1440     dlg->items[2].text = cancelbutton;
 1441     dlg->items[2].udata = cancelfn;
 1442     dlg->items[3].type = D_END;
 1443     add_to_ml(&ml, dlg, NULL);
 1444     do_dialog(term, dlg, ml);
 1445 }
 1446 
 1447 
 1448 /* Sets the selected item to one that is visible.*/
 1449 void box_sel_set_visible(struct dialog_item_data *box_item_data, int offset) {
 1450     struct dlg_data_item_data_box *box;
 1451     int sel;
 1452     
 1453     box = (struct dlg_data_item_data_box *)(box_item_data->item->data);
 1454     if (offset > box_item_data->item->gid || offset < 0) {
 1455         return;
 1456     }
 1457     /*debug("offset: %d", offset);*/
 1458     sel = box->box_top + offset;
 1459     if (sel > box->list_len) {
 1460         box->sel = box->list_len - 1;
 1461     } else {
 1462         box->sel = sel;
 1463     }
 1464 }
 1465 
 1466 /* Moves the selected item [dist] thingies. If [dist] is out of the current 
 1467     range, the selected item is moved to the extreme (ie, the top or bottom) 
 1468 */
 1469 void box_sel_move(struct dialog_item_data *box_item_data, int dist) {
 1470     struct dlg_data_item_data_box *box;
 1471     int new_sel;
 1472     int new_top;
 1473     
 1474     box = (struct dlg_data_item_data_box *)(box_item_data->item->data);
 1475 
 1476     new_sel = box->sel + dist; 
 1477     new_top = box->box_top;
 1478 
 1479     /* Ensure that the selection is in range */
 1480     if (new_sel < 0)
 1481         new_sel = 0;
 1482     else if (new_sel >= box->list_len)
 1483         new_sel = box->list_len - 1;
 1484     
 1485     /* Ensure that the display box is over the item */
 1486     if ( new_sel >= (new_top + box_item_data->item->gid) ) {
 1487         /* Move it down */
 1488         new_top = new_sel - box_item_data->item->gid + 1;
 1489 #ifdef DEBUG
 1490         if (new_top < 0)
 1491             debug("Newly calculated box_top is an extremely wrong value (%d). It should not be below zero.", new_top);
 1492 #endif  
 1493     } else if ( new_sel < new_top ) {
 1494         /* Move the display up (if necessary) */    
 1495         new_top = new_sel;
 1496     }
 1497     
 1498     box->sel = new_sel;
 1499     box->box_top = new_top;
 1500 }
 1501 
 1502 
 1503 /* Displays a dialog box */
 1504 void show_dlg_item_box(struct dialog_data *dlg, struct dialog_item_data *box_item_data) {
 1505     struct terminal *term = dlg->win->term;
 1506     struct dlg_data_item_data_box *box;
 1507     struct box_item *citem; /* Item currently being shown */
 1508     int n;  /* Index of item currently being displayed */
 1509 
 1510     box = (struct dlg_data_item_data_box *)(box_item_data->item->data);
 1511     /* FIXME: Counting here SHOULD be unnecessary */
 1512     n = 0;
 1513 
 1514     fill_area(term, box_item_data->x, box_item_data->y, box_item_data->l, box_item_data->item->gid, COLOR_DIALOG_FIELD | ' ');
 1515 
 1516     foreach (citem, box->items) {
 1517         int len; /* Length of the current text field. */
 1518         len = strlen(citem->text);
 1519         if (len > box_item_data->l) {
 1520             len = box_item_data->l;
 1521         }
 1522 
 1523         /* Is the current item in the region to be displayed? */
 1524         if ( (n >= box->box_top) && (n < (box->box_top + box_item_data->item->gid)) ) {
 1525             print_text(term, box_item_data->x, box_item_data->y + n - box->box_top, len, citem->text, n == box->sel ? COLOR_DIALOG_BUTTON_SELECTED : COLOR_DIALOG_FIELD_TEXT);
 1526 
 1527         }
 1528         n++;
 1529     }
 1530 
 1531     box->list_len = n;
 1532 }