
/* 
 * 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:                */
