Logo Search packages:      
Sourcecode: w3mmee version File versions  Download package

menu.c

/* 
 * w3m menu.c
 */
#include <stdio.h>

#include "fm.h"
#include "menu.h"
#include "func.h"
#include "myctype.h"
#include "regex.h"

#ifdef USE_MENU

#ifndef USE_MENU_BUFFER
static int call_menu_func(int key, int c);
#endif

#ifdef KANJI_SYMBOLS

#ifdef MANY_CHARSET
extern char **FRAME;
#else
static char *FRAME[] =
{
#ifdef MENU_THIN_FRAME
    "┌", "─", "┐",
    "│", "  ", "│",
    "└", "─", "┘",
#else                   /* not MENU_THIN_FRAME */
    "┏", "━", "┓",
    "┃", "  ", "┃",
    "┗", "━", "┛",
#endif                        /* not MENU_THIN_FRAME */
    ":", ":"};
#endif

#define G_start
/**/
#define G_end    /**/

#else                   /* not KANJI_SYMBOLS */
static char *N_FRAME[] =
{
    "+", "-", "+",
    "|", " ", "|",
    "+", "-", "+",
    ":", ":"};

static char *G_FRAME[] =
{
    "l", "q", "k",
    "x", " ", "x",
    "m", "q", "j",
    ":", ":"};

static char **FRAME = NULL;
static int graph_mode = FALSE;

#define G_start  {if (graph_mode) graphstart();}
#define G_end    {if (graph_mode) graphend();}
#endif                        /* not KANJI_SYMBOLS */

static KeyTabItem w3mDefaultMenuKeyTab[] = {
#ifndef USE_MENU_BUFFER
#ifdef __EMX__
  K_SET_FUNC(K_GEN(0, K_CTL_ATMARK), FUNCNAME_mPc),
#endif
  K_SET_FUNC(K_GEN(0, K_CTL_A), FUNCNAME_mTop),
  K_SET_FUNC(K_GEN(0, K_CTL_B), FUNCNAME_mPrev),
#endif
  K_SET_FUNC(K_GEN(0, K_CTL_C), FUNCNAME_mClose),
#ifndef USE_MENU_BUFFER
  K_SET_FUNC(K_GEN(0, K_CTL_E), FUNCNAME_mLast),
  K_SET_FUNC(K_GEN(0, K_CTL_F), FUNCNAME_mNext),
#endif
  K_SET_FUNC(K_GEN(0, K_CTL_H), FUNCNAME_mCancel),
  K_SET_FUNC(K_GEN(0, K_CTL_J), FUNCNAME_mOk),
  K_SET_FUNC(K_GEN(0, K_CTL_M), FUNCNAME_mOk),
#ifndef USE_MENU_BUFFER
  K_SET_FUNC(K_GEN(0, K_CTL_N), FUNCNAME_mDown),
  K_SET_FUNC(K_GEN(0, K_CTL_P), FUNCNAME_mUp),
  K_SET_FUNC(K_GEN(0, K_CTL_V), FUNCNAME_mNext),
  K_SET_FUNC(K_GEN(0, K_CTL_Z), FUNCNAME_mSusp),
  K_SET_FUNC(K_GEN(0, K_CTL_LBRACKET), FUNCNAME_mEsc),
#endif
  K_SET_FUNC(K_GEN(0, K_SPACE), FUNCNAME_mOk),
#ifndef USE_MENU_BUFFER
  K_SET_FUNC(K_GEN(0, K_SYM_SLASH), FUNCNAME_mSrchF),
  K_SET_FUNC(K_GEN(0, K_SYM_QUESTION), FUNCNAME_mSrchB),
  K_SET_FUNC(K_GEN(0, K_ALPHA_N), FUNCNAME_mSrchP),
  K_SET_FUNC(K_GEN(0, K_ALPHA_h), FUNCNAME_mSrchP),
  K_SET_FUNC(K_GEN(0, K_ALPHA_j), FUNCNAME_mDown),
  K_SET_FUNC(K_GEN(0, K_ALPHA_k), FUNCNAME_mUp),
  K_SET_FUNC(K_GEN(0, K_ALPHA_l), FUNCNAME_mOk),
  K_SET_FUNC(K_GEN(0, K_ALPHA_n), FUNCNAME_mSrchN),
#endif
  K_SET_FUNC(K_GEN(0, K_DELETE), FUNCNAME_mCancel),
#ifndef USE_MENU_BUFFER
  K_SET_FUNC(K_GEN(0, K_ESC | K_ALPHA_O), FUNCNAME_mEscB),
  K_SET_FUNC(K_GEN(0, K_ESC | K_SYM_LBRACKET), FUNCNAME_mEscB),
  K_SET_FUNC(K_GEN(0, K_ESC | K_ALPHA_v), FUNCNAME_mPrev),
  K_SET_FUNC(K_GEN(0, K_UP), FUNCNAME_mUp),
  K_SET_FUNC(K_GEN(0, K_DOWN), FUNCNAME_mDown),
#endif
  K_SET_FUNC(K_GEN(0, K_RIGHT), FUNCNAME_mOk),
  K_SET_FUNC(K_GEN(0, K_LEFT), FUNCNAME_mCancel),
  K_SET_FUNC(K_GEN(0, K_PocketBSD_INS), FUNCNAME_mClose),
  K_SET_FUNC(K_GEN(0, K_FreeBSD_CONSOLE_INS), FUNCNAME_mClose),
#ifndef USE_MENU_BUFFER
  K_SET_FUNC(K_GEN(0, K_XTERM_MOUSE), FUNCNAME_mMouse),
#endif
  K_SET_FUNC(K_GEN(0, K_PAD_INS), FUNCNAME_mClose),
#ifndef USE_MENU_BUFFER
  K_SET_FUNC(K_GEN(0, K_PAD_PGUP), FUNCNAME_mBack),
  K_SET_FUNC(K_GEN(0, K_PAD_PGDN), FUNCNAME_mFore),
#endif
  K_SET_FUNC(K_GEN(0, K_PAD_HELP), FUNCNAME_mClose),
#ifdef USE_MOUSE
  K_SET_FUNC(K_GEN(0, K_MOUSE(CLICK) + MOUSE_BTN1_DOWN), FUNCNAME_mPositional),
  K_SET_FUNC(K_GEN(0, K_MOUSE(CLICK) + MOUSE_BTN3_DOWN), FUNCNAME_mPositional),
  K_SET_FUNC(K_GEN(0, K_MOUSE(DCLICK) + MOUSE_BTN1_DOWN), FUNCNAME_mPositional),
  K_SET_FUNC(K_GEN(0, K_MOUSE(DCLICK) + MOUSE_BTN3_DOWN), FUNCNAME_mPositional),
#ifdef USE_MENU_BUFFER
  K_SET_FUNC(K_GEN(0, K_MOUSE(DRAG) + MOUSE_BTN2_DOWN), FUNCNAME_mMoveMenu),
  K_SET_FUNC(K_GEN(0, K_MOUSE(MOVE) + MOUSE_BTN2_DOWN), FUNCNAME_mMoveMenu),
#endif
#endif
};

KeyTabList w3mDefaultMenuKeyTabList = {
  NULL,
  w3mDefaultMenuKeyTab,
  sizeof(w3mDefaultMenuKeyTab) / sizeof(w3mDefaultMenuKeyTab[0]),
  sizeof(w3mDefaultMenuKeyTab) / sizeof(w3mDefaultMenuKeyTab[0]),
};

#ifndef USE_MENU_BUFFER
#ifdef __EMX__
static int (*MenuPcKeymap[256])(char c)={
//                  Null
  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
//                                          S-Tab
  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
// A-q        A-w   A-E   A-r   A-t   A-y   A-u   A-i
  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
// A-o        A-p   A-[   A-]               A-a   A-s
  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
// A-d        A-f   A-g   A-h   A-j   A-k   A-l   A-;
  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
// A-'    A-'             A-\         A-x   A-c   A-v
  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mPrev,
// A-b        A-n   A-m   A-,   A-.   A-/         A-+
  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
//                  F1    F2    F3    F4    F5
  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
// F6   F7    F8    F9    F10               Home
  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mTop,
// Up   PgUp        A-/   Left        5     Right       C-*   End
  mUp,        mUp,        mNull,  mCancel,mNull,  mOk,        mNull,  mLast,
// Down       PgDn        Ins   Del   S-F1        S-F2        S-F3        S-F4
  mDown,  mDown,  mClose, mCancel,mNull,  mNull,  mNull,  mNull,
// S-F5       S-F6        S-F7        S-F8        S-F9        S-F10       C-F1        C-F2
  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
// C-F3       C-F4        C-F5        C-F6        C-F7        C-F8        C-F9        C-F10
  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
// A-F1       A-F2        A-F3        A-F4        A-F5        A-F6        A-F7        A-F8
  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
// A-F9       A-F10       PrtSc       C-Left  C-Right C-End   C-PgDn  C-Home
  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
// A-1        A-2   A-3   A-4   A-5   A-6   A-7/8       A-9
  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
// A-0        A -   A-=         C-PgUp  F11       F12   S-F11
  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
// S-F12  C-F11     C-F12       A-F11       A-F12       C-Up        C-/   C-5
  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
// S-*        C-Down  C-Ins     C-Del       C-Tab       C -   C-+
  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,
//                        A -   A-Tab       A-Enter
  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,   // 160
  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,   // 168
  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,   // 176
  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,   // 184
  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,   // 192
  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,   // 200
  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,   // 208
  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,   // 216
  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,   // 224
  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,   // 232
  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,   // 240
  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull,  mNull      // 248
};
#endif
#endif

/* --- SelectMenu --- */

static Menu SelectMenu;

static MenuItem SelectMenuDefaultItem[] = {
/* type        label           variable value func     popup keys data  */
    {MENU_NOP, "-- ", NULL, 0, nulcmd, NULL, "", NULL},
#if LANG == JA
    {MENU_MFUNC, "選択されたバッファを削除 (D)", NULL, FUNCNAME_smDelBuf, NULL, NULL, "D", NULL},
#else                   /* LANG != JA */
    {MENU_MFUNC, N_("Delete selected buffer (D)"), NULL, FUNCNAME_smDelBuf, NULL, NULL, "D", NULL},
#endif                        /* LANG != JA */
    {MENU_END, "", NULL, 0, nulcmd, NULL, "", NULL},
};

static MenuItem *SelectMenuItem = SelectMenuDefaultItem;
static int SelectV = 0;
static void initSelectMenu(void);
static void smChBuf(void);

/* --- SelectMenu (END) --- */

/* --- MainMenu --- */

static Menu MainMenu;

static MenuItem MainMenuItem[] = {
/* type        label           variable value func     popup keys data  */
#if LANG == JA
    {MENU_FUNC, "戻る         (b)", NULL, 0, backBf, NULL, "b", NULL},
    {MENU_POPUP, "バッファ選択 (s)", NULL, 0, NULL, &SelectMenu, "s", NULL},
    {MENU_FUNC, "ソースを表示 (v)", NULL, 0, vwSrc, NULL, "v V", NULL},
    {MENU_FUNC, "ソースを編集 (e)", NULL, 0, editBf, NULL, "e E", NULL},
    {MENU_FUNC, "ソースを保存 (S)", NULL, 0, svSrc, NULL, "S", NULL},
    {MENU_FUNC, "再読み込み   (r)", NULL, 0, reload, NULL, "r R", NULL},
    {MENU_NOP,  "────────", NULL, 0, nulcmd, NULL, "", NULL},
    {MENU_FUNC, "リンクを表示 (a)", NULL, 0, followA, NULL, "a", NULL},
    {MENU_FUNC, "リンクを保存 (A)", NULL, 0, svA, NULL, "A", NULL},
    {MENU_FUNC, "画像を表示   (i)", NULL, 0, followI, NULL, "i", NULL},
    {MENU_FUNC, "画像を保存   (I)", NULL, 0, svI, NULL, "I", NULL},
    {MENU_FUNC, "フレーム表示 (f)", NULL, 0, rFrame, NULL, "f F", NULL},
    {MENU_NOP,  "────────", NULL, 0, nulcmd, NULL, "", NULL},
    {MENU_FUNC, "ブックマーク (B)", NULL, 0, ldBmark, NULL, "B", NULL},
    {MENU_FUNC, "ヘルプ       (h)", NULL, 0, ldhelp, NULL, "h H", NULL},
    {MENU_FUNC, "オプション   (o)", NULL, 0, ldOpt, NULL, "o O", NULL},
    {MENU_NOP,  "────────", NULL, 0, nulcmd, NULL, "", NULL},
    {MENU_FUNC, "エラーログ   (l)", NULL, 0, vwErrLog, NULL, "l L", NULL},
    {MENU_FUNC, "プロセス一覧 (p)", NULL, 0, procList, NULL, "p P", NULL},
    {MENU_NOP,  "────────", NULL, 0, nulcmd, NULL, "", NULL},
    {MENU_FUNC, "終了         (q)", NULL, 0, qquitfm, NULL, "q Q", NULL},
#else                   /* LANG != JA */
    {MENU_FUNC, N_(" Back         (b) "), NULL, 0, backBf, NULL, "b", NULL},
    {MENU_POPUP, N_(" Select Buffer(s) "), NULL, 0, NULL, &SelectMenu, "s", NULL},
    {MENU_FUNC, N_(" View Source  (v) "), NULL, 0, vwSrc, NULL, "v V", NULL},
    {MENU_FUNC, N_(" Edit Source  (e) "), NULL, 0, editBf, NULL, "e E", NULL},
    {MENU_FUNC, N_(" Save Source  (S) "), NULL, 0, svSrc, NULL, "S", NULL},
    {MENU_FUNC, N_(" Reload       (r) "), NULL, 0, reload, NULL, "r R", NULL},
    {MENU_NOP, " ---------------- ", NULL, 0, nulcmd, NULL, "", NULL},
    {MENU_FUNC, N_(" Go Link      (a) "), NULL, 0, followA, NULL, "a", NULL},
    {MENU_FUNC, N_(" Save Link    (A) "), NULL, 0, svA, NULL, "A", NULL},
    {MENU_FUNC, N_(" View Image   (i) "), NULL, 0, followI, NULL, "i", NULL},
    {MENU_FUNC, N_(" Save Image   (I) "), NULL, 0, svI, NULL, "I", NULL},
    {MENU_FUNC, N_(" View Frame   (f) "), NULL, 0, rFrame, NULL, "f F", NULL},
    {MENU_NOP, " ---------------- ", NULL, 0, nulcmd, NULL, "", NULL},
    {MENU_FUNC, N_(" Bookmark     (B) "), NULL, 0, ldBmark, NULL, "B", NULL},
    {MENU_FUNC, N_(" Help         (h) "), NULL, 0, ldhelp, NULL, "h H", NULL},
    {MENU_FUNC, N_(" Option       (o) "), NULL, 0, ldOpt, NULL, "o O", NULL},
    {MENU_NOP, " ---------------- ", NULL, 0, nulcmd, NULL, "", NULL},
    {MENU_FUNC, N_(" Error Log    (l) "), NULL, 0, vwErrLog, NULL, "l L", NULL},
    {MENU_FUNC, N_(" Process List (p) "), NULL, 0, procList, NULL, "p P", NULL},
    {MENU_NOP, " ---------------- ", NULL, 0, nulcmd, NULL, "", NULL},
    {MENU_FUNC, N_(" Quit         (q) "), NULL, 0, qquitfm, NULL, "q Q", NULL},
#endif                        /* LANG != JA */
    {MENU_END, "", NULL, 0, nulcmd, NULL, "", NULL},
};

/* --- MainMenu (END) --- */

extern btri_string_tab_t w3mFuncTab[];
extern FuncList w3mFuncList[];
static MenuList *w3mMenuList;

#define mvaddch(y, x, c)        (move(y, x), addch(c))
#define mvaddstr(y, x, str)     (move(y, x), addstr(str))
#define mvaddnstr(y, x, str, n) (move(y, x), addnstr_sup(str, n))

#ifdef USE_MENU_BUFFER
void
select_menu_line(Buffer *b, Line *old)
{
    if (b && b->menu && old != b->currentLine) {
      Line *new;

      for (; old && !old->real_linenumber ; old = old->prev)
          ;

      for (new = b->currentLine ; new && !new->real_linenumber ; new = new->prev)
          ;

      if (new != old) {
          int i;

          if (old)
            do {
                if (old->menu_item)
                  old->menu_item->type &= ~MENU_SELECTED;

                for (i = old->len ; i > 0 ;)
                  old->propBuf[--i] &= ~PE_STAND;
            } while ((old = old->next) && !old->real_linenumber);

          if (new)
            do {
                if (new->menu_item)
                  new->menu_item->type |= MENU_SELECTED;

                for (i = new->len ; i > 0 ;)
                  new->propBuf[--i] |= PE_STAND;
            } while ((new = new->next) && !new->real_linenumber);

          b->redraw_mode = B_FORCE_REDRAW;
      }
    }
}
#endif

void
new_menu(Menu *menu, MenuItem *item
#ifdef USE_MENU_BUFFER
       , BufferView *view
#endif
       )
{
    int i, l, key;
    char *p, *q;
    KeyTabList menu_tab = {NULL, NULL, 0, 0}, sel_tab = {NULL, NULL, 0, 0};
#ifdef USE_MENU_BUFFER
    Buffer *newBuf;
    CheckTypeEnv ctenv;
    Line *pl, *cl;
    int cols, lastline, width;
#endif

#ifndef USE_MENU_BUFFER
    menu->item = item;
    menu->cursorX = 0;
    menu->cursorY = 0;
    menu->x = 0;
    menu->y = 0;
    menu->nitem = 0;
    menu->offset = 0;
    menu->active = 0;
#endif
    menu->initial = 0;
    menu->select = 0;

    if (!item)
      return;

    menu_tab.next = w3mMenuKeyTabList;

#ifdef USE_MENU_BUFFER
    if ((cols = COLS) <= 0)
      cols = 80;

    if ((lastline = LASTLINE) <= 0)
      lastline = 23;

    if (menu->owner) {
      newBuf = menu->owner;
      clearBuffer(newBuf);

      if (!(view = newBuf->view))
          newBuf->view = view = initBufferView(NULL, NULL, NULL, 0, 0, cols, lastline, 0, 0);
    }
    else {
      if (!view)
          view = initBufferView(NULL, NULL, NULL, 0, 0, cols, lastline, 0, 0);

      menu->owner = newBuf = newBuffer(view);
      newBuf->menu = menu;
    }

    init_ctenv(&ctenv, newBuf, cols - newBuf->rmargin - newBuf->lmargin - FRAME_WIDTH * 2
#ifdef USE_ANSI_COLOR
             , TRUE
#endif
             );

    for (pl = newBuf->lastLine, i = width = 0 ; i <= K_FUNC_MAX && item[i].type != MENU_END ; ++i) {
      if ((p = item[i].keys)) {
          if (item[i].type & MENU_MFUNC)
            for (p = allocStr(p, -1) ; *p ;) {
                q = getQWord(&p);

                if ((key = getKey(q)) >= 0)
                  addToKeyTab(&menu_tab, key, item[i].value);
            }
          else
            for (p = allocStr(p, -1) ; *p ;) {
                q = getQWord(&p);

                if ((key = getKey(q)) >= 0) {
                  addToKeyTab(&menu_tab, key, FUNCNAME_mSelect);
                  addToKeyTab(&sel_tab, key, i);
                }
            }
      }

      Plainlineproc(newBuf, 0, &ctenv, item[i].label, item[i].label + strlen(item[i].label), TRUE, &l);

      if (pl)
          cl = pl->next;
      else
          cl = newBuf->firstLine;

      do {
          if (cl->width < 0)
            cl->width = COLPOS(cl, cl->len);

          if (width < cl->width)
            width = cl->width;

          cl->menu_item = item + i;
          pl = cl;
      } while ((cl = cl->next));
    }

    if ((width + newBuf->rmargin + newBuf->lmargin) % FRAME_WIDTH)
      width = (width + newBuf->rmargin + newBuf->lmargin + FRAME_WIDTH - 1) / FRAME_WIDTH * FRAME_WIDTH - newBuf->rmargin - newBuf->lmargin;

    if (width != view->width - newBuf->rmargin - newBuf->lmargin) {
      view->width = width + newBuf->rmargin + newBuf->lmargin;

      if (view->width > cols - FRAME_WIDTH * 2)
          view->width = (cols + FRAME_WIDTH - 1) / FRAME_WIDTH * FRAME_WIDTH - FRAME_WIDTH * 2;
    }

    if (newBuf->lastLine->linenumber != view->height) {
      view->height = newBuf->lastLine->linenumber;

      if (view->height > lastline - 2)
          view->height = lastline - 2;
    }

    if (!newBuf->currentLine)
      newBuf->currentLine = newBuf->firstLine;

    if (!newBuf->topLine)
      newBuf->topLine = newBuf->firstLine;

    select_menu_line(newBuf, NULL);
#else
    for (i = 0; i <= K_FUNC_MAX && item[i].type != MENU_END; i++)
      ;
    menu->nitem = i;
    menu->height = menu->nitem;
    menu->width = 0;
    for (i = 0; i < menu->nitem; i++) {
      if ((p = item[i].keys) != NULL) {
          if (item[i].type & MENU_MFUNC)
            for (p = allocStr(p, -1) ; *p ;) {
                q = getQWord(&p);
                if ((key = getKey(q)) >= 0)
                  addToKeyTab(&menu_tab, key, item[i].value);
            }
          else
            for (p = allocStr(p, -1) ; *p ;) {
                q = getQWord(&p);
                if ((key = getKey(q)) >= 0) {
                  addToKeyTab(&menu_tab, key, FUNCNAME_mSelect);
                  addToKeyTab(&sel_tab, key, i);
                }
            }
      }
#ifdef MANY_CHARSET
      l = ttyfix_width(item[i].label);
#else
      l = strlen(item[i].label);
#endif
      if (l > menu->width)
          menu->width = l;
    }
#endif

    menu->keymap = copyKeyTabList(&menu_tab);
    menu->keyselect = copyKeyTabList(&sel_tab);
}

#ifdef USE_MENU_BUFFER
static int
select_menu_item(Buffer *b, int mselect)
{
    Line *l;

    if ((l = b->currentLine))
      for (; !l->real_linenumber && l->prev ; l = l->prev)
          ;

    gotoRealLineMaybe(b, mselect + 1, 0);

    if (b->currentLine && b->currentLine->real_linenumber != mselect + 1)
      return FALSE;

    arrangeCursor(b);

    if (l != b->currentLine) {
      int i;

      if (l)
          do {
            for (i = l->len ; i > 0 ;)
                l->propBuf[--i] &= ~PE_STAND;
          } while ((l = l->next) && !l->real_linenumber);

      l = b->currentLine;

      do {
          for (i = l->len ; i > 0 ;)
            l->propBuf[--i] |= PE_STAND;
      } while ((l = l->next) && !l->real_linenumber);

      b->redraw_mode = B_FORCE_REDRAW;
    }

    return TRUE;
}
#endif

void
geom_menu(Menu *menu, int mselect)
{
    int win_x, win_y, win_w, win_h;
#ifdef USE_MENU_BUFFER
    Buffer *buf;
    BufferView *v;
    int y;

    if (mselect < 0)
      mselect = menu->select;
    else
      menu->select = mselect;

    buf = menu->owner;
    select_menu_item(buf, mselect);
    v = buf->view;
    win_x = v->rootX - FRAME_WIDTH;
    win_w = v->width + 2 * FRAME_WIDTH;

    if (win_x + win_w > COLS)
      win_x = COLS - win_w;

    if (win_x < 0) {
      win_x = 0;

      if (win_w > COLS) {
          v->width = COLS - 2 * FRAME_WIDTH;
          v->width -= v->width % FRAME_WIDTH;
          win_w = v->width + 2 * FRAME_WIDTH;
      }
    }

    v->rootX = win_x + FRAME_WIDTH;

    if ((v->height = buf->lastLine->linenumber) > LASTLINE - 2)
      v->height = LASTLINE - 2;

    y = buf->currentLine->linenumber - 1;
    win_y = v->rootY - y - 1;
    win_h = v->height + 2;

    if (win_y < 0) {
      win_y = 0;

      if (win_h > LASTLINE) {
          win_h = LASTLINE;
          v->height = win_h - 2;
      }
    }
    else if (win_y + win_h > LASTLINE) {
      win_h = LASTLINE - win_y;

      if ((v->height = win_h - 2) <= y)
          --win_y;
    }

    if ((buf->topLine = lineSkip(buf, buf->currentLine, win_y + 1 - v->rootY, FALSE)) &&
      buf->lastLine->linenumber - buf->topLine->linenumber + 1 < v->height)
      v->height = buf->lastLine->linenumber - buf->topLine->linenumber + 1;

    arrangeLine(buf);
    v->rootY = win_y + 1;
    buf->redraw_mode = B_FORCE_REDRAW;
#else
    menu->select = mselect;

    if (menu->width % FRAME_WIDTH)
      menu->width = (menu->width / FRAME_WIDTH + 1) * FRAME_WIDTH;
    win_x = menu->x - FRAME_WIDTH;
    win_w = menu->width + 2 * FRAME_WIDTH;
    if (win_x + win_w > COLS)
      win_x = COLS - win_w;
    if (win_x < 0) {
      win_x = 0;
      if (win_w > COLS) {
          menu->width = COLS - 2 * FRAME_WIDTH;
          menu->width -= menu->width % FRAME_WIDTH;
          win_w = menu->width + 2 * FRAME_WIDTH;
      }
    }
    menu->x = win_x + FRAME_WIDTH;

    win_y = menu->y - mselect - 1;
    win_h = menu->height + 2;
    if (win_y + win_h > LASTLINE)
      win_y = LASTLINE - win_h;
    if (win_y < 0) {
      win_y = 0;
      if (win_y + win_h > LASTLINE) {
          win_h = LASTLINE - win_y;
          menu->height = win_h - 2;
          if (menu->height <= mselect)
            menu->offset = mselect - menu->height + 1;
      }
    }
    menu->y = win_y + 1;
#endif
}

void
draw_all_menu(Menu *menu)
{
    if (menu->parent != NULL)
      draw_all_menu(menu->parent);
    draw_menu(menu);
}

void
draw_menu(Menu *menu)
{
#ifdef USE_MENU_BUFFER
    Buffer *b;
    BufferView *v;
#endif
    int x, oy, y, w;
    int i, j;

#ifndef KANJI_SYMBOLS
    if (FRAME == NULL) {
      if (graph_ok()) {
          graph_mode = TRUE;
          FRAME = G_FRAME;
      }
      else {
          FRAME = N_FRAME;
      }
    }
#endif                        /* not KANJI_SYMBOLS */

#ifdef USE_MENU_BUFFER
    b = menu->owner;
    v = b->view;
    x = v->rootX - FRAME_WIDTH;
    w = v->width + 2 * FRAME_WIDTH;
    oy = y = v->rootY - 1;

    if (b->topLine && b->topLine->linenumber > 1) {
      G_start;
      mvaddstr(y, x, FRAME[3]);
      G_end;

      for (i = FRAME_WIDTH ; i < w - FRAME_WIDTH ; i += FRAME_WIDTH)
          mvaddstr(y, x + i, FRAME[4]);

      G_start;
      mvaddstr(y, x + i, FRAME[5]);
      G_end;
      i = (w / 2 - 1) / FRAME_WIDTH * FRAME_WIDTH;
      mvaddstr(y, x + i, FRAME[9]);
    }
    else {
      G_start;
      mvaddstr(y, x, FRAME[0]);

      for (i = FRAME_WIDTH ; i < w - FRAME_WIDTH ; i += FRAME_WIDTH)
          mvaddstr(y, x + i, FRAME[1]);

      mvaddstr(y, x + i, FRAME[2]);
      G_end;
    }

    for (j = 0 ; j < v->height ; ++j) {
      ++y;
      G_start;
      mvaddstr(y, x, FRAME[3]);
      mvaddstr(y, x + w - FRAME_WIDTH, FRAME[5]);
      G_end;
    }

    ++y;

    if (b->lastLine && b->lastLine->linenumber - b->topLine->linenumber < LASTLINE) {
      G_start;
      mvaddstr(y, x, FRAME[6]);

      for (i = FRAME_WIDTH ; i < w - FRAME_WIDTH ; i += FRAME_WIDTH)
          mvaddstr(y, x + i, FRAME[7]);

      mvaddstr(y, x + i, FRAME[8]);
      G_end;
    }
    else {
      G_start;
      mvaddstr(y, x, FRAME[3]);
      G_end;

      for (i = FRAME_WIDTH ; i < w - FRAME_WIDTH ; i += FRAME_WIDTH)
          mvaddstr(y, x + i, FRAME[4]);

      G_start;
      mvaddstr(y, x + i, FRAME[5]);
      G_end;
      i = (w / 2 - 1) / FRAME_WIDTH * FRAME_WIDTH;
      mvaddstr(y, x + i, FRAME[10]);
    }

    displayBuffer(b, B_FORCE_REDRAW);
#else
    x = menu->x - FRAME_WIDTH;
    w = menu->width + 2 * FRAME_WIDTH;
    oy = y = menu->y - 1;

    if (menu->offset == 0) {
      G_start;
      mvaddstr(y, x, FRAME[0]);
      for (i = FRAME_WIDTH; i < w - FRAME_WIDTH; i += FRAME_WIDTH)
          mvaddstr(y, x + i, FRAME[1]);
      mvaddstr(y, x + i, FRAME[2]);
      G_end;
    }
    else {
      G_start;
      mvaddstr(y, x, FRAME[3]);
      G_end;
      for (i = FRAME_WIDTH; i < w - FRAME_WIDTH; i += FRAME_WIDTH)
          mvaddstr(y, x + i, FRAME[4]);
      G_start;
      mvaddstr(y, x + i, FRAME[5]);
      G_end;
      i = (w / 2 - 1) / FRAME_WIDTH * FRAME_WIDTH;
      mvaddstr(y, x + i, FRAME[9]);
    }

    for (j = 0; j < menu->height; j++) {
      y++;
      G_start;
      mvaddstr(y, x, FRAME[3]);
      G_end;
      draw_menu_item(menu, menu->offset + j);
      G_start;
      mvaddstr(y, x + w - FRAME_WIDTH, FRAME[5]);
      G_end;
    }
    y++;
    if (menu->offset + menu->height == menu->nitem) {
      G_start;
      mvaddstr(y, x, FRAME[6]);
      for (i = FRAME_WIDTH; i < w - FRAME_WIDTH; i += FRAME_WIDTH)
          mvaddstr(y, x + i, FRAME[7]);
      mvaddstr(y, x + i, FRAME[8]);
      G_end;
    }
    else {
      G_start;
      mvaddstr(y, x, FRAME[3]);
      G_end;
      for (i = FRAME_WIDTH; i < w - FRAME_WIDTH; i += FRAME_WIDTH)
          mvaddstr(y, x + i, FRAME[4]);
      G_start;
      mvaddstr(y, x + i, FRAME[5]);
      G_end;
      i = (w / 2 - 1) / FRAME_WIDTH * FRAME_WIDTH;
      mvaddstr(y, x + i, FRAME[10]);
    }
#endif
}

#ifndef USE_MENU_BUFFER
void
draw_menu_item(Menu *menu, int mselect)
{
    mvaddnstr(menu->y + mselect - menu->offset, menu->x,
            menu->item[mselect].label, menu->width);
}
#endif

int
select_menu(Menu *menu, int mselect)
{
#ifdef USE_MENU_BUFFER
    Buffer *b;

    if ((b = menu->owner) && select_menu_item(b, mselect))
      return mselect;

    return MENU_NOTHING;
#else
    if (mselect < 0 || mselect >= menu->nitem) {
      refresh();
#ifdef USE_IMAGE
      if (activeImage)
          drawImage();
#endif
      return (MENU_NOTHING);
    }
    if (mselect < menu->offset)
      up_menu(menu, menu->offset - mselect);
    else if (mselect >= menu->offset + menu->height)
      down_menu(menu, mselect - menu->offset - menu->height + 1);

    if (menu->select >= menu->offset &&
      menu->select < menu->offset + menu->height)
      draw_menu_item(menu, menu->select);
    menu->select = mselect;
    standout();
    draw_menu_item(menu, menu->select);
    standend();
    move(menu->y + mselect - menu->offset, menu->x);
    toggle_stand();
    refresh();
#ifdef USE_IMAGE
    if (activeImage)
      drawImage();
#endif

    return (menu->select);
#endif
}

void
goto_menu(Menu *menu, int mselect, int down)
{
#ifdef USE_MENU_BUFFER
    Buffer *b;

    if ((b = menu->owner)) {
      Line *l;

      if (mselect < 0)
          mselect = 0;

      gotoRealLineMaybe(b, mselect + 1, 1);
      l = b->currentLine;

      for (; l && !l->real_linenumber ; l = l->prev)
          ;

      if (l && l->real_linenumber == mselect + 1) {
          MenuItem *mi;

          while ((mi = l->menu_item) &&
               (mi->type == MENU_NOP || mi->type == MENU_MFUNC))
            if (down > 0) {
                while ((l = l->next) && !l->real_linenumber)
                  ;

                if (!l)
                  break;

                ++mselect;
            }
            else if (down < 0) {
                while ((l = l->prev) && !l->real_linenumber)
                  ;

                if (!l)
                  break;

                --mselect;
            }
            else
                return;

          select_menu_item(b, mselect);
      }
    }
#else
    int select_in;
    if (mselect >= menu->nitem)
      mselect = menu->nitem - 1;
    else if (mselect < 0)
      mselect = 0;
    select_in = mselect;
    while (menu->item[mselect].type == MENU_NOP || menu->item[mselect].type == MENU_MFUNC) {
      if (down > 0) {
          if (++mselect >= menu->nitem)
          {
            down_menu(menu, select_in - menu->select);
            mselect = menu->select;
            break;
          }
      }
      else if (down < 0) {
          if (--mselect < 0)
          {
            up_menu(menu, menu->select - select_in);
            mselect = menu->select;
            break;
          }
      }
      else {
          return;
      }
    }
    select_menu(menu, mselect);
#endif
}

#ifndef USE_MENU_BUFFER
void
up_menu(Menu *menu, int n)
{
    if (n < 0 || menu->offset == 0)
      return;
    menu->offset -= n;
    if (menu->offset < 0)
      menu->offset = 0;

    draw_menu(menu);
}

void
down_menu(Menu *menu, int n)
{
    if (n < 0 || menu->offset + menu->height == menu->nitem)
      return;
    menu->offset += n;
    if (menu->offset + menu->height > menu->nitem)
      menu->offset = menu->nitem - menu->height;

    draw_menu(menu);
}

int
action_menu(Menu *menu)
{
    char c;
    int mselect;
    MenuItem item;
    CookedEvent cev;

    if (menu->active == 0) {
      if (menu->parent != NULL)
          menu->parent->active = 0;
      return (0);
    }
    draw_all_menu(menu);
    select_menu(menu, menu->select);
    while (1) {
#ifdef USE_MOUSE
      if (use_mouse)
          mouse_active();
#endif                        /* USE_MOUSE */
      if (!getevent(&cev))
        continue;
#ifdef USE_MOUSE
      if (use_mouse) {
          mouse_inactive();
#if defined(USE_GPM) || defined(USE_SYSMOUSE)
          if (cev.type == cooked_event_mouse) {
            mselect = process_mMouse(cev.what, cev.x, cev.y);
            if (mselect != MENU_NOTHING)
            break;
            continue;
          }
#endif                        /* defined(USE_GPM) || defined(USE_SYSMOUSE) */
      }
#endif                        /* USE_MOUSE */
      c = cev.what;
      if (IS_ASCII(c)) {      /* Ascii */
          mselect = call_menu_func(0, c);
          if (mselect != MENU_NOTHING)
            break;
      }
    }
    if (!checkCurrentbuf()) {
      Buffer *buf;

      if ((buf = loadVisualStartPage(FALLBACK_PAGE_TITLE)))
          pushBuffer(buf);
    }
    if (mselect >= 0 && mselect < menu->nitem) {
      item = menu->item[mselect];
      if (item.type & MENU_POPUP) {
          popup_menu(menu, item.popup);
          return (1);
      }
      if (menu->parent != NULL)
          menu->parent->active = 0;
      if (item.type & MENU_VALUE)
          *item.variable = item.value;
      if (item.type & MENU_FUNC) {
          CurrentKey = 0;
          ForcedKeyData = CurrentKeyData = NULL;
          TargetX = TargetY = PrevTargetX = PrevTargetY = -1;
          CurrentCmdData = item.data;
          (*item.func) ();
          CurrentCmdData = NULL;
      }
    }
    else if (mselect == MENU_CLOSE) {
      if (menu->parent != NULL)
          menu->parent->active = 0;
    }
    return (0);
}
#endif

void
popup_menu(Menu *parent, Menu *menu)
{
#ifdef USE_MENU_BUFFER
    Buffer *b;
    BufferView *v;

    if (!(b = menu->owner) || !(v = b->view))
      return;
#else
    int active = 1, save_popup;

    if (menu->item == NULL || menu->nitem == 0)
      return;
    if (menu->active)
      return;
    menu->active = 1;
    menu->offset = 0;
#endif
    menu->parent = parent;
    menu->select = menu->initial;
#ifdef USE_MENU_BUFFER
    if (parent)
      guess_menu_xy(parent, v->width, &v->rootX, &v->rootY);

    geom_menu(menu, menu->select);
#else
    if (parent != NULL) {
      menu->cursorX = parent->cursorX;
      menu->cursorY = parent->cursorY;
      guess_menu_xy(parent, menu->width, &menu->x, &menu->y);
    }
    geom_menu(menu, menu->select);
#endif

    CurrentMenu = menu;
#ifdef USE_MENU_BUFFER
    menu->current = Currentbuf;
    Currentbuf = b;
    menu->save_popup = CurrentMenuPopup;
    CurrentMenuPopup = TRUE;
    draw_all_menu(menu);
#else
    while (active) {
      save_popup = CurrentMenuPopup;
      CurrentMenuPopup = TRUE;
      active = action_menu(CurrentMenu);
      CurrentMenuPopup = save_popup;
      displayCurrentView(NULL);
    }
    menu->active = 0;
    CurrentMenu = parent;
#endif
}

#ifdef USE_MENU_BUFFER
void
popdown_menu(int close_p, int selected)
{
    Menu *m;
    MenuItem *mi;

    while (CurrentMenu && CurrentMenuPopup) {
      m = CurrentMenu;
      CurrentMenuPopup = m->save_popup;
      CurrentMenu = m->parent;
      Currentbuf = m->current;

      if (selected && m->owner && m->owner->currentLine && (mi = m->owner->currentLine->menu_item)) {
          if (mi->type & MENU_POPUP) {
            popup_menu(m, mi->popup);
            return;
          }

          if (mi->type & MENU_VALUE)
            *mi->variable = mi->value;

          if (mi->type & MENU_FUNC) {
            CurrentKey = 0;
            ForcedKeyData = CurrentKeyData = NULL;
            TargetX = TargetY = PrevTargetX = PrevTargetY = -1;
            CurrentCmdData = mi->data;
            mi->func();
            CurrentCmdData = NULL;
          }
      }

      if (!close_p)
          break;

      selected = FALSE;
    }

    if (!(CurrentMenu && CurrentMenuPopup))
      displayCurrentView(NULL);
}
#endif

void
guess_menu_xy(Menu *parent, short width, short *x, short *y)
{
#ifdef USE_MENU_BUFFER
    Buffer *b;
    BufferView *v;

    if (!(b = parent->owner) || !(v = b->view))
      return;

    *x = v->rootX + v->width + FRAME_WIDTH - 1;

    if (*x + width + FRAME_WIDTH > COLS) {
      *x = COLS - width - FRAME_WIDTH;

      if ((v->rootX + v->width / 2 > *x) &&
          (v->rootX + v->width / 2 > COLS / 2))
          *x = v->rootX - width - FRAME_WIDTH + 1;
    }

    *y = v->rootY + b->cursorY;
#else
    *x = parent->x + parent->width + FRAME_WIDTH - 1;
    if (*x + width + FRAME_WIDTH > COLS) {
      *x = COLS - width - FRAME_WIDTH;
      if ((parent->x + parent->width / 2 > *x) &&
          (parent->x + parent->width / 2 > COLS / 2))
          *x = parent->x - width - FRAME_WIDTH + 1;
    }
    *y = parent->y + parent->select - parent->offset;
#endif
}

void
new_option_menu(Menu *menu, char **label, int *variable, void (*func)(void), MenuItem *more)
{
    int i, nitem, m;
    char **p;
    MenuItem *item;

    if (label == NULL || *label == NULL)
      return;

    for (i = 0, p = label; *p != NULL; i++, p++)
      ;
    m = nitem = i;

    if (more)
      for (item = more ; item->type != MENU_END ; ++m, ++item)
          ;

    item = New_N(MenuItem, m + 1);

    for (i = 0, p = label; i < nitem; i++, p++) {
      if (func != NULL)
          item[i].type = MENU_VALUE | MENU_FUNC;
      else
          item[i].type = MENU_VALUE;
      item[i].label = *p;
      item[i].variable = variable;
      item[i].value = i;
      item[i].func = func;
      item[i].popup = NULL;
      item[i].keys = "";
    }
    for (; i < m ; ++i)
      item[i] = more[i - nitem];
    item[i].type = MENU_END;

    new_menu(menu, item
#ifdef USE_MENU_BUFFER
           , NULL
#endif
           );
}

/* PENDING */
/* --- MenuFunctions --- */

#ifdef USE_MENU_BUFFER

static int
updown_menu(int i)
{
    int n = 0;

    if (CurrentMenu && CurrentMenuPopup) {
      Menu *m;
      BufferView *v;

      if (i > 0)
          for (; i > 0 ; --i) {
            for (m = CurrentMenu ; m ; m = m->parent)
                if (m->owner && (v = m->owner->view) && v->rootY > 1) {
                  --(v->rootY);
                  ++n;
                }
          }
      else if (i < 0)
          for (i = -i ; i > 0 ; --i)
            for (m = CurrentMenu ; m ; m = m->parent)
                if (m->owner && (v = m->owner->view) && v->rootY + v->height + 1 < LASTLINE) {
                  ++(v->rootY);
                  ++n;
                }
    }

    return n;
}

void
mUpMenu(void)
{
    if (updown_menu(searchKeyNum())) {
      displayCurrentView(NULL);
      draw_all_menu(CurrentMenu);
    }
}

void
mDownMenu(void)
{
    if (updown_menu(-searchKeyNum())) {
      displayCurrentView(NULL);
      draw_all_menu(CurrentMenu);
    }
}

static int
leftright_menu(int i)
{
    int n = 0;

    if (CurrentMenu && CurrentMenuPopup) {
      Menu *m;
      BufferView *v;

      if (i > 0)
          for (; i > 0 ; --i) {
            for (m = CurrentMenu ; m ; m = m->parent)
                if (m->owner && (v = m->owner->view) && v->rootX > FRAME_WIDTH) {
                  --(v->rootX);
                  ++n;
                }
          }
      else if (i < 0)
          for (i = -i ; i > 0 ; --i)
            for (m = CurrentMenu ; m ; m = m->parent)
                if (m->owner && (v = m->owner->view) && v->rootX + v->width + FRAME_WIDTH < COLS) {
                  ++(v->rootX);
                  ++n;
                }
    }

    return n;
}

void
mLeftMenu(void)
{
    if (leftright_menu(searchKeyNum())) {
      displayCurrentView(NULL);
      draw_all_menu(CurrentMenu);
    }
}

void
mRightMenu(void)
{
    if (leftright_menu(-searchKeyNum())) {
      displayCurrentView(NULL);
      draw_all_menu(CurrentMenu);
    }
}

void
mMoveMenu(void)
{
    int x, y, n = 0;

    if (!CurrentMenu || !CurrentMenuPopup ||
      ((TargetX < 0 || TargetY < 0) && !inputTargetXY(TRUE)) ||
      TargetX < 0 || TargetX >= COLS ||
      TargetY < 0 || TargetY >= LASTLINE ||
      PrevTargetX < 0 || PrevTargetX >= COLS ||
      PrevTargetY < 0 || PrevTargetY >= LASTLINE)
      return;

    if ((y = TargetY - PrevTargetY))
      n += updown_menu(-y);

    if ((x = TargetX - PrevTargetX))
      n += leftright_menu(-x);

    if (n) {
      displayCurrentView(NULL);
      draw_all_menu(CurrentMenu);
    }
}

void
mSelect(void)
{
    if (CurrentMenu && CurrentMenuPopup && CurrentMenu->keyselect) {
      int i;

      if ((i = lookupKeyIndex(CurrentKey, CurrentMenu->keyselect)) >= 0 &&
          select_menu(CurrentMenu, K_GET_FUNC(CurrentMenu->keyselect->key_table[i])) != MENU_NOTHING)
          popdown_menu(TRUE, TRUE);
    }
}

void
mOk(void)
{
    MenuItem *mi;

    if (CurrentMenu && CurrentMenuPopup && CurrentMenu->owner && CurrentMenu->owner->currentLine &&
      (mi = CurrentMenu->owner->currentLine->menu_item) &&
      mi->type != MENU_NOP && mi->type != MENU_MFUNC)
      popdown_menu(TRUE, TRUE);
}

void
mCancel(void)
{
    popdown_menu(FALSE, FALSE);
}

void
mClose(void)
{
    popdown_menu(TRUE, FALSE);
}

#ifdef USE_MOUSE
void
mPositional(void)
{
    if (TargetX >= 0 && TargetY >= 0) {
      int x, y;
      Menu *menu;
      Buffer *b;
      BufferView *v;

      x = TargetX;
      y = TargetY;
      menu = CurrentMenu;
      b = menu->owner;
      v = b->view;

      if (x < v->rootX - FRAME_WIDTH ||
          x >= v->rootX + v->width + FRAME_WIDTH ||
          y < v->rootY - 1 ||
          y >= v->rootY + v->height + 1)
          popdown_menu(FALSE, FALSE);
      else if ((x >= v->rootX - FRAME_WIDTH &&
              x < v->rootX) ||
             (x >= v->rootX + v->width &&
              x < v->rootX + v->width + FRAME_WIDTH))
          ;
      else if (y == v->rootY - 1)
          movU();
      else if (y == v->rootY + v->height)
          movD();
      else {
          Line *l;
          MenuItem *mi;

          cursorXY(b, TargetX - b->view->rootX, TargetY - b->view->rootY);

          for (l = Currentbuf->currentLine ; l && !l->real_linenumber ; l = l->prev)
            ;

          if (l && (mi = l->menu_item)) {
            if (mi->type == MENU_NOP || mi->type == MENU_MFUNC)
                return;

            if (select_menu(menu, l->real_linenumber - 1) != MENU_NOTHING)
                popdown_menu(TRUE, TRUE);
          }
      }
    }
}
#endif

#else /* if !defined(USE_MENU_BUFFER) */

static int
call_menu_func(int key, int c)
{
  if (K_LEN(key) < K_LEN_MAX) {
    FuncList *fl;

    key = K_GEN(key, c);

    if ((fl = lookupKey(key, CurrentMenu->keymap)))
      return fl->func.menu_func(key);
  }

  return MENU_NOTHING;
}

static int
call_menu_func_nostroke(int key, int c)
{
  FuncList *fl;

  key = K_OVER(key, c);

  if ((fl = lookupKey(key, CurrentMenu->keymap)))
    return fl->func.menu_func(key);

  return MENU_NOTHING;
}

int
mNextchar(int key)
{
  return call_menu_func(key, (unsigned char)getch());
}


#ifdef __EMX__
int
mPc(int c)
{
  c = (unsigned char)getch();
  return(MenuPcKeymap[(int)c](c));
}
#endif

int
mEsc(int key)
{
  int c;

  c = (unsigned int)getch();

  if (IS_ASCII(c))
    return call_menu_func_nostroke(key, K_ESC | c);

  return MENU_NOTHING;
}

static int
mEscD(int key, char c)
{
    int d;

    d = (int) c - (int) '0';
    c = getch();
    if (IS_DIGIT(c)) {
      d = d * 10 + (int) c - (int) '0';
      c = getch();
    }
    if (c == '~')
      return call_menu_func_nostroke(key, K_ESCD | d);
    else
      return (MENU_NOTHING);
}

int
mEscB(int key)
{
  int c;

  c = (unsigned char)getch();

  if (IS_DIGIT(c))
    return mEscD(key, c);
  else
    return call_menu_func_nostroke(key, K_ESCB | c);
}

int
mNull(int key)
{
    return (MENU_NOTHING);
}

int
mSelect(int key)
{
  if (CurrentMenu->keyselect) {
    int i;

    if ((i = lookupKeyIndex(key, CurrentMenu->keyselect)) >= 0)
      return select_menu(CurrentMenu, K_GET_FUNC(CurrentMenu->keyselect->key_table[i]));
  }

  return (MENU_NOTHING);
}

int
mDown(int c)
{
    if (CurrentMenu->select >= CurrentMenu->nitem - 1)
      return (MENU_NOTHING);
    goto_menu(CurrentMenu, CurrentMenu->select + 1, 1);
    return (MENU_NOTHING);
}

int
mUp(int c)
{
    if (CurrentMenu->select <= 0)
      return (MENU_NOTHING);
    goto_menu(CurrentMenu, CurrentMenu->select - 1, -1);
    return (MENU_NOTHING);
}

int
mLast(int c)
{
    goto_menu(CurrentMenu, CurrentMenu->nitem - 1, -1);
    return (MENU_NOTHING);
}

int
mTop(int c)
{
    goto_menu(CurrentMenu, 0, 1);
    return (MENU_NOTHING);
}

int
mNext(int c)
{
    int mselect = CurrentMenu->select + CurrentMenu->height;

    if (mselect >= CurrentMenu->nitem)
      return mLast(c);
    down_menu(CurrentMenu, CurrentMenu->height);
    goto_menu(CurrentMenu, mselect, -1);
    return (MENU_NOTHING);
}

int
mPrev(int c)
{
    int mselect = CurrentMenu->select - CurrentMenu->height;

    if (mselect < 0)
      return mTop(c);
    up_menu(CurrentMenu, CurrentMenu->height);
    goto_menu(CurrentMenu, mselect, 1);
    return (MENU_NOTHING);
}

int
mFore(int c)
{
    if (CurrentMenu->select >= CurrentMenu->nitem - 1)
      return MENU_NOTHING;
    goto_menu(CurrentMenu, CurrentMenu->select + CurrentMenu->height - 1,
            CurrentMenu->height + 1);
    return (MENU_NOTHING);
}

int
mBack(int c)
{
    if (CurrentMenu->select <= 0)
      return (MENU_NOTHING);
    goto_menu(CurrentMenu, CurrentMenu->select - CurrentMenu->height + 1,
            -1 - CurrentMenu->height);
    return (MENU_NOTHING);
}

int
mOk(int c)
{
    int mselect = CurrentMenu->select;

    if (CurrentMenu->item[mselect].type == MENU_NOP ||
      CurrentMenu->item[mselect].type == MENU_MFUNC)
      return (MENU_NOTHING);
    return (mselect);
}

int
mCancel(int c)
{
    return (MENU_CANCEL);
}

int
mClose(int c)
{
    return (MENU_CLOSE);
}

int
mSusp(int c)
{
    susp();
    draw_all_menu(CurrentMenu);
    select_menu(CurrentMenu, CurrentMenu->select);
    return (MENU_NOTHING);
}

static char *SearchString = NULL;

int (*menuSearchRoutine)(Menu *, char *, int);

static int
menuForwardSearch(Menu *menu, char *str, int from)
{
    int i;
    char* p;
    if ((p = regexCompile(str, IgnoreCase)) != NULL) {
      message(p);
      return -1;
    }
    if (from < 0)
      from = 0;
    for (i = from; i < menu->nitem; i++)
      if (menu->item[i].type != MENU_NOP &&
          menu->item[i].type != MENU_MFUNC &&
          regexMatch(menu->item[i].label, -1))
          return i;
    return -1;
}

static int
menu_search_forward(Menu *menu, int from)
{
    char *str;
    int found;
    str = inputStrHist("Forward: ", NULL, TextHist);
    if (str != NULL && *str == '\0')
      str = SearchString;
    if (str == NULL || *str == '\0')
      return -1;
    SearchString = str;
    menuSearchRoutine = menuForwardSearch;
    found = menuForwardSearch(menu, SearchString, from + 1);
    if (WrapSearch && found == -1)
        found = menuForwardSearch(menu, SearchString, 0);
    if (found >= 0)
        return found;
    disp_message("Not found", TRUE);
    return -1;
}

int
mSrchF(int c)
{
    int mselect;
    mselect = menu_search_forward(CurrentMenu, CurrentMenu->select);
    if (mselect >= 0)
      goto_menu(CurrentMenu, mselect, 1);
    return (MENU_NOTHING);
}

static int
menuBackwardSearch(Menu *menu, char *str, int from)
{
    int i;
    char* p;
    if ((p = regexCompile(str, IgnoreCase)) != NULL) {
      message(p);
      return -1;
    }
    if (from >= menu->nitem)
      from = menu->nitem - 1;
    for (i = from; i >= 0; i--)
      if (menu->item[i].type != MENU_NOP &&
          menu->item[i].type != MENU_MFUNC &&
          regexMatch(menu->item[i].label, -1))
            return i;
    return -1;
}

static int
menu_search_backward(Menu *menu, int from)
{
    char *str;
    int found;
    str = inputStrHist("Backward: ", NULL, TextHist);
    if (str != NULL && *str == '\0')
      str = SearchString;
    if (str == NULL || *str == '\0')
      return (MENU_NOTHING);
    SearchString = str;
    menuSearchRoutine = menuBackwardSearch;
    found = menuBackwardSearch(menu, SearchString, from - 1);
    if (WrapSearch && found == -1)
        found = menuBackwardSearch(menu, SearchString, menu->nitem);
    if (found >= 0)
        return found;
    disp_message("Not found", TRUE);
    return -1;
}

int
mSrchB(int c)
{
    int mselect;
    mselect = menu_search_backward(CurrentMenu, CurrentMenu->select);
    if (mselect >= 0)
      goto_menu(CurrentMenu, mselect, -1);
    return (MENU_NOTHING);
}

static int
menu_search_next_previous(Menu *menu, int from, int reverse)
{
    int found;
    static int (*routine[2])(Menu *, char *, int) = {
      menuForwardSearch, menuBackwardSearch
    };

    if (menuSearchRoutine == NULL) {
      disp_message("No previous regular expression", TRUE);
      return -1;
    }
    if (reverse != 0)
      reverse = 1;
    if (menuSearchRoutine == menuBackwardSearch)
      reverse ^= 1;
    from += reverse ? -1 : 1;
    found = (*routine[reverse])(menu, SearchString, from);
    if (WrapSearch && found == -1)
        found = (*routine[reverse])(menu, SearchString, reverse * menu->nitem);
    if (found >= 0)
        return found;
    disp_message("Not found", TRUE);
    return -1;
}

int
mSrchN(int c)
{
    int mselect;
    mselect = menu_search_next_previous(CurrentMenu, CurrentMenu->select, 0);
    if (mselect >= 0)
      goto_menu(CurrentMenu, mselect, 1);
    return (MENU_NOTHING);
}

int
mSrchP(int c)
{
    int mselect;
    mselect = menu_search_next_previous(CurrentMenu, CurrentMenu->select, 1);
    if (mselect >= 0)
      goto_menu(CurrentMenu, mselect, -1);
    return (MENU_NOTHING);
}

#ifdef USE_MOUSE
int
mPositional(int key)
{
  int x, y, mselect;
  Menu *menu;

  if (TargetX < 0 || TargetY < 0)
    return (MENU_NOTHING);

  x = TargetX;
  y = TargetY;
  menu = CurrentMenu;

  if (x < menu->x - FRAME_WIDTH ||
      x >= menu->x + menu->width + FRAME_WIDTH ||
      y < menu->y - 1 ||
      y >= menu->y + menu->height + 1) {
    return (MENU_CANCEL);
  }
  else if ((x >= menu->x - FRAME_WIDTH &&
          x < menu->x) ||
         (x >= menu->x + menu->width &&
          x < menu->x + menu->width + FRAME_WIDTH)) {
    return (MENU_NOTHING);
  }
  else if (y == menu->y - 1) {
    mPrev(key);
    return (MENU_NOTHING);
  }
  else if (y == menu->y + menu->height) {
    mNext(key);
    return (MENU_NOTHING);
  }
  else {
    mselect = y - menu->y + menu->offset;
    if (menu->item[mselect].type == MENU_NOP ||
      menu->item[mselect].type == MENU_MFUNC)
      return (MENU_NOTHING);
    return (select_menu(menu, mselect));
  }
}

void
process_menu_mouse(int key, void *arg)
{
  int *p_select;
  FuncList *fl;

  p_select = arg;
  *p_select = MENU_NOTHING;
  key = K_GEN(0, key);

  if ((fl = lookupKey(key, w3mMenuKeyTabList)) &&
      ((Currentbuf && Currentbuf != NO_BUFFER) ||
       (fl - w3mFuncList) == FUNCNAME_quitfm || (fl - w3mFuncList) == FUNCNAME_qquitfm))
    *p_select = fl->func.menu_func(key);
}

int
mMouse(int key)
{
    int btn, x, y, mselect = MENU_NOTHING;

    btn = (unsigned char)getch() - 32;
    x = (unsigned char)getch() - 33;
    if (x < 0)
      x += 0x100;
    y = (unsigned char)getch() - 33;
    if (y < 0)
      y += 0x100;

    if (x >= 0 && x < COLS && y >= 0 && y < LASTLINE)
      process_mouse(btn, x, y, process_menu_mouse, &mselect);

    return mselect;
}
#endif                        /* not USE_MOUSE */

#endif /* !defined(USE_MENU_BUFFER) */

/* --- MenuFunctions (END) --- */

/* --- MainMenu --- */

void
popupMenu(short x, short y, Menu *menu)
{
#ifdef USE_MENU_BUFFER
    Buffer *b;

    initSelectMenu();

    if ((b = menu->owner)) {
      BufferView *v;

      if ((v = b->view)) {
          v->rootX = x + FRAME_WIDTH + 1;
          v->rootY = y + 2;
          cursorXY(b,
                 Currentbuf->view->rootX + Currentbuf->lmargin + Currentbuf->cursorX - v->rootX,
                 Currentbuf->view->rootY + Currentbuf->cursorY - v->rootY);
          popup_menu(NULL, menu);
      }
    }
#else
    initSelectMenu();
    menu->cursorX = Currentbuf->view->rootX + Currentbuf->lmargin + Currentbuf->cursorX;
    menu->cursorY = Currentbuf->view->rootY + Currentbuf->cursorY;
    menu->x = x + FRAME_WIDTH + 1;
    menu->y = y + 2;
    popup_menu(NULL, menu);
#endif
}

void
mainMenu(short x, short y)
{
    popupMenu(x, y, &MainMenu);
}

void
mainMn(void)
{
    Menu *menu = &MainMenu;
    char *data;
    int n;

    if (TargetX >= 0 && TargetY >= 0)
      gotoXY();

    data = searchKeyData();
    if (data != NULL) {
      n = getMenuN(w3mMenuList, data);
      if (n < 0)
          return;
      menu = w3mMenuList[n].menu;
    }
    popupMenu(Currentbuf->view->rootX + Currentbuf->lmargin + Currentbuf->cursorX,
            Currentbuf->view->rootY + Currentbuf->cursorY, menu);
}

/* --- MainMenu (END) --- */

/* --- SelectMenu --- */

void
selMn(void)
{
    if (TargetX >= 0 && TargetY >= 0)
      gotoXY();

    popupMenu(Currentbuf->view->rootX + Currentbuf->lmargin + Currentbuf->cursorX,
            Currentbuf->view->rootY + Currentbuf->cursorY, &SelectMenu);
}

static char *
smTitle(char *format, char *title, ParsedURL *url, int indent)
{
    Str label;

    if (indent) {
      label = Strnew_size(indent + sizeof("+"));
      memset(label->ptr, ' ', indent - 1);
      label->length = indent - 1;
      label->ptr[label->length] = '\0';
      Strcat_char(label, '+');
      Strcat(label, Sprintf(format, title));
    }
    else
      label = Sprintf(format, title);

    if (url && url->file)
      switch (url->scheme) {
      case SCM_LOCAL:
      case SCM_LOCAL_CGI:
          if (strcmp(url->file, "-")) {
            Strcat_char(label, ' ');
            Strcat_charp(label, conv_from_system(url->real_file));
          }
          break;
      case SCM_MISSING:
          break;
      default:
          Strcat_char(label, ' ');
          Strcat(label, parsedURL2Str(url));
          break;
      }

    return label->ptr;
}

static void
initSelectMenuLoop(BufferView *v, int *sel, char **label, int indent, int *n)
{
    int i, col, row;

    for (; v ; v = v->down)
      if (v->frameset) {
          if (label)
            label[*n] = (v->frameset->origin ? 
                       smTitle("[%s]", v->frameset->origin->buffername, &v->frameset->origin->currentURL, indent) :
                       smTitle("[%s]", "", NULL, indent));

          ++(*n);

          for (i = 0, row = 0 ; row < v->nrows ; ++row) {
            if (!v->rowv[row]) {
                i += v->ncols;
                continue;
            }

            for (col = 0 ; col < v->ncols ; ++col, ++i) {
                if (!v->colv[col])
                  continue;

                initSelectMenuLoop(v->subv[i].top, sel, label, indent + 1, n);
            }
          }
      }
      else if (v->top) {
          Buffer *buf;

          for (buf = v->top ; buf ; buf = buf->down)
            if (buf->bufferprop & BP_VISIBLE) {
                if (label)
                  label[*n] = smTitle("<%s>", buf->buffername, buf->filename ? &buf->currentURL : NULL, indent);

                if (sel && buf == Currentbuf)
                  *sel = *n;

                ++(*n);
            }
      }
}

static void
initSelectMenu(void)
{
    int nitem = 0, i;
    char **label;

    SelectV = -1;
    initSelectMenuLoop(TopViewList.top, &SelectV, NULL, 0, &nitem);
    label = New_N(char *, nitem + 1);
    i = 0;
    initSelectMenuLoop(TopViewList.top, NULL, label, 0, &i);
    label[i] = NULL;
    new_option_menu(&SelectMenu, label, &SelectV, smChBuf, SelectMenuItem);
    SelectMenu.initial = SelectV;

    if (Currentbuf && Currentbuf->bufferprop & BP_VISIBLE) {
#ifdef USE_MENU_BUFFER
      cursorXY(SelectMenu.owner,
             Currentbuf->view->rootX + Currentbuf->lmargin + Currentbuf->cursorX,
             Currentbuf->view->rootY + Currentbuf->cursorY);
#else
      SelectMenu.cursorX = Currentbuf->view->rootX + Currentbuf->lmargin + Currentbuf->cursorX;
      SelectMenu.cursorY = Currentbuf->view->rootY + Currentbuf->cursorY;
#endif
    }
    else {
#ifdef USE_MENU_BUFFER
      cursorXY(SelectMenu.owner, 0, 0);
#else
      SelectMenu.cursorX = SelectMenu.cursorY = 0;
#endif
    }

#ifndef USE_MENU_BUFFER
    SelectMenu.item[nitem].type = MENU_NOP;
#endif
}

static Buffer *
smChBufLoop(BufferView *v, int sel, int *n, int clr)
{
    int i, col, row;
    Buffer *buf;

    for (; v ; v = v->down) {
      if (!clr && *n > sel)
          return NULL;

      if (v->frameset) {
          ++(*n);

          for (i = 0, row = 0 ; row < v->nrows ; ++row) {
            if (!v->rowv[row]) {
                i += v->ncols;
                continue;
            }

            for (col = 0 ; col < v->ncols ; ++col, ++i) {
                if (!v->colv[col])
                  continue;

                if ((buf = smChBufLoop(v->subv[i].top, sel, n, clr)))
                  return buf;

                if (!clr && *n > sel)
                  return NULL;
            }
          }
      }
      else if (v->top)
          for (buf = v->top ; buf ; buf = buf->down)
            if (buf->bufferprop & BP_VISIBLE) {
                if (clr) {
                  if (!Currentbuf ||
                      Currentbuf->view->root != v->root ||
                      !buf->up)
                      tmpClearBuffer(buf);
                }
                else if (*n == sel)
                  return buf;

                ++(*n);
            }
    }

    return NULL;
}

#ifdef USE_MENU_BUFFER
static int
isSelectable(int mselect)
{
    Line *l;

    for (l = SelectMenu.owner->lastLine ; l && !l->real_linenumber ; l = l->prev)
      ;

    return l && mselect < l->real_linenumber - 1;
}
#endif

static void
smChBuf(void)
{
    int i = 0;
    Buffer *buf;

    if (SelectV < 0 ||
#ifdef USE_MENU_BUFFER
      !isSelectable(SelectV)
#else
      SelectV >= SelectMenu.nitem
#endif
      )
      return;

    if ((buf = smChBufLoop(TopViewList.top, SelectV, &i, FALSE))) {
      pushBuffer(buf);

      if (clear_buffer) {
          i = 0;
          smChBufLoop(TopViewList.top, SelectV, &i, TRUE);
      }
    }
}

void
reshapeMenu(void)
{
    int x, y, mselect;
#ifdef USE_MENU_BUFFER
    Buffer *b;
    BufferView *v;
    Line *l;

    b = CurrentMenu->owner;
    v = b->view;
    x = v->rootX;
    y = v->rootY;

    for (l = b->currentLine ; l && !l->real_linenumber ; l = l->prev)
      ;

    mselect = l ? l->real_linenumber - 1 : 0;
    initSelectMenu();
    v->rootX = x;
    v->rootY = y;
    geom_menu(CurrentMenu, 0);
    gotoRealLineMaybe(b, mselect + 1, 1);
    select_menu_line(b, l);
    CurrentMenu->select = b->currentLine->real_linenumber - 1;
#else
    x = CurrentMenu->x;
    y = CurrentMenu->y;
    mselect = CurrentMenu->select;

    initSelectMenu();

    CurrentMenu->x = x;
    CurrentMenu->y = y;

    geom_menu(CurrentMenu, 0);

    CurrentMenu->select = (mselect <= CurrentMenu->nitem - 2) ? mselect
      : (CurrentMenu->nitem - 2);
#endif
}

#ifdef USE_MENU_BUFFER
void
smDelBuf(void)
#else
int
smDelBuf(int c)
#endif
{
    int i = 0;
    Buffer *buf;

    if (CurrentMenu != &SelectMenu ||
      CurrentMenu->select < 0 ||
#ifdef USE_MENU_BUFFER
      isSelectable(CurrentMenu->select)
#else
      CurrentMenu->select >= SelectMenu.nitem
#endif
      )
      return
#ifndef USE_MENU_BUFFER
          (MENU_NOTHING)
#endif
          ;

    if ((buf = smChBufLoop(TopViewList.top, CurrentMenu->select, &i, FALSE)))
      delBuffer(buf);

    reshapeMenu();
    displayCurrentView(NULL);
    draw_all_menu(CurrentMenu);
    select_menu(CurrentMenu, CurrentMenu->select);
#ifdef USE_MENU_BUFFER
    if (!checkCurrentbuf())
      popdown_menu(TRUE, FALSE);
#else
    return (checkCurrentbuf() ? MENU_NOTHING : MENU_CLOSE);
#endif
}

/* --- SelectMenu (END) --- */

/* --- OptionMenu --- */

#ifdef USE_MENU_BUFFER
static int
optionMenu_test(void)
{
    return CurrentMenu && CurrentMenuPopup;
}
#endif

void
optionMenu(int x, int y, char **label, int *variable, int initial,
         void (*func)())
{
    Menu menu;
#ifdef USE_MENU_BUFFER
    Buffer *b;
    BufferView *v;
#endif

    memset(&menu, 0, sizeof(menu));
    new_option_menu(&menu, label, variable, func, NULL);
#ifdef USE_MENU_BUFFER
    b = menu.owner;
    cursorXY(b, COLS - 1, LASTLINE);
    v = b->view;
    v->rootX = x;
    v->rootY = y;
    menu.initial = initial;
    popup_menu(NULL, &menu);
    main_loop(optionMenu_test);
#else
    menu.cursorX = COLS - 1;
    menu.cursorY = LASTLINE;
    menu.x = x;
    menu.y = y;
    menu.initial = initial;

    popup_menu(NULL, &menu);
#endif
}

/* --- OptionMenu (END) --- */

/* --- InitMenu --- */

static void
initMenuStart(void)
{
    w3mMenuList = New_N(MenuList, 3);
    w3mMenuList[0].id = "Main";
    w3mMenuList[0].menu = &MainMenu;
    w3mMenuList[0].item = MainMenuItem;
    w3mMenuList[1].id = "Select";
    w3mMenuList[1].menu = &SelectMenu;
    w3mMenuList[1].item = SelectMenuDefaultItem;
    w3mMenuList[2].id = NULL;
}

static void
initMenuFromFile(FILE *mf)
{
    Str line;
    char *p, *s;
    int in_menu, nmenu = 0, nitem = 0, type;
    MenuItem *item = NULL;

    in_menu = 0;
    while (!feof(mf)) {
#ifdef MANY_CHARSET
      line = conv_Str2mbStr(Strfgets(mf), NULL, "!", &tty_mb_r_setup);
#else
      line = Strfgets(mf);
#endif
      Strchop(line);
      Strremovefirstspaces(line);
      if (line->length == 0)
          continue;
      p = line->ptr;
      s = getWord(&p);
      if (*s == '#')          /* comment */
          continue;
      if (in_menu) {
          type = setMenuItem(&item[nitem], s, p);
          if (type == -1)
            continue;   /* error */
          if (type == MENU_END)
            in_menu = 0;
          else {
            nitem++;
            item = New_Reuse(MenuItem, item, (nitem + 1));
            w3mMenuList[nmenu].item = item;
            item[nitem].type = MENU_END;
          }
      }
      else {
          if (strcmp(s, "menu"))    /* error */
            continue;
          s = getQWord(&p);
          if (*s == '\0')     /* error */
            continue;
          in_menu = 1;
          if ((nmenu = getMenuN(w3mMenuList, s)) != -1)
            w3mMenuList[nmenu].item = New(MenuItem);
          else
            nmenu = addMenuList(&w3mMenuList, s);
          item = w3mMenuList[nmenu].item;
          nitem = 0;
          item[nitem].type = MENU_END;
      }
    }
}

static void
initMenuEnd(void)
{
    MenuList *list;

    SelectMenuItem = w3mMenuList[1].item;
    for (list = w3mMenuList; list->id != NULL; list++) {
      if (list->item == NULL)
          continue;
      new_menu(list->menu, list->item
#ifdef USE_MENU_BUFFER
             , NULL
#endif
             );
    }
}

void
initMenu(void)
{
  FILE *f;

  initMenuStart();
#ifdef MANY_CHARSET
  try_cfg_files(W3MMENU, initMenuFromFile, etcFile);
#else
  if ((f = fopen(etcFile(W3MMENU), "rt"))) {
    initMenuFromFile(f);
    fclose(f);
  }
#endif
  if ((f = fopen(rcFile(MENU_FILE), "rt"))) {
    initMenuFromFile(f);
    fclose(f);
  }
  initMenuEnd();
  CurrentCmdData = NULL;
}

int
setMenuItem(MenuItem *item, char *type, char *line)
{
    char *label, *func, *popup, *keys, *data;
    int n;

    if (type == NULL || *type == '\0')    /* error */
      return -1;
    if (strcmp(type, "end") == 0) {
      item->type = MENU_END;
      return MENU_END;
    }
    else if (strcmp(type, "nop") == 0) {
      item->type = MENU_NOP;
      item->label = getQWord(&line);
      return MENU_NOP;
    }
    else if (strcmp(type, "func") == 0) {
      FuncList *fl;

      label = getQWord(&line);
      func = getWord(&line);
      keys = getQWord(&line);
      data = getQWord(&line);
      if (*func == '\0')      /* error */
          return -1;
      item->type = MENU_FUNC;
      item->label = label;
      if (btri_fast_ci_search_str(func, w3mFuncTab, (void **)&fl) != bt_failure) {
          if (!strncasecmp(func, "M:", sizeof("M:") - 1)) {
            item->type = MENU_MFUNC;
            item->value = fl - w3mFuncList;
          }
          else
            item->func = fl->func.main_func;
      }
      else
          item->func = w3mFuncList[FUNCNAME_nulcmd].func.main_func;
      item->keys = keys;
      item->data = data;
      return item->type;
    }
    else if (strcmp(type, "popup") == 0) {
      label = getQWord(&line);
      popup = getQWord(&line);
      keys = getQWord(&line);
      if (*popup == '\0')     /* error */
          return -1;
      item->type = MENU_POPUP;
      item->label = label;
      if ((n = getMenuN(w3mMenuList, popup)) == -1)
          n = addMenuList(&w3mMenuList, popup);
      item->popup = w3mMenuList[n].menu;
      item->keys = keys;
      return MENU_POPUP;
    }
    return -1;                /* error */
}

int
addMenuList(MenuList ** mlist, char *id)
{
    int n;
    MenuList *list = *mlist;

    for (n = 0; list->id != NULL; list++, n++)
      ;
    *mlist = New_Reuse(MenuList, *mlist, (n + 2));
    list = *mlist + n;
    list->id = id;
    list->menu = New(Menu);
    list->item = New(MenuItem);
    (list + 1)->id = NULL;
    return n;
}

int
getMenuN(MenuList *list, char *id)
{
    int n;

    for (n = 0; list->id != NULL; list++, n++) {
      if (strcmp(id, list->id) == 0)
          return n;
    }
    return -1;
}

/* --- InitMenu (END) --- */

#endif                        /* USE_MENU */

/* Local Variables:    */
/* c-basic-offset: 4   */
/* tab-width: 8        */
/* End:                */

Generated by  Doxygen 1.6.0   Back to index