"Fossies" - the Fresh Open Source Software Archive

Member "links-1.03/bfu.c" (19 Nov 2011, 46954 Bytes) of archive /linux/www/links-1.03.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: 2.8_vs_1.03.

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