--- XMakefile.orig	Sat Dec 28 01:33:51 2002
+++ XMakefile	Wed Jan 22 02:02:56 2003
@@ -1,9 +1,9 @@
 # $Id: XMakefile,v 1.34 2002/12/27 16:07:44 ukai Exp $
 SRCS=main.c file.c buffer.c display.c etc.c search.c linein.c table.c local.c \
-	form.c map.c frame.c rc.c menu.c mailcap.c image.c\
+	form.c map.c frame.c rc.c menu.c mailcap.c image.c bmedit.c\
 	func.c cookie.c history.c backend.c $(KEYBIND_SRC)
 OBJS=main.o file.o buffer.o display.o etc.o search.o linein.o table.o local.o\
-	form.o map.o frame.o rc.o menu.o mailcap.o image.o\
+	form.o map.o frame.o rc.o menu.o mailcap.o image.o bmedit.o\
 	func.o cookie.o history.o backend.o $(KEYBIND_OBJ)
 LSRCS=terms.c conv.c url.c ftp.c anchor.c mimehead.c parsetagx.c\
 	tagtable.c istream.c news.c
--- funcname.tab.orig	Wed Dec 11 01:17:53 2002
+++ funcname.tab	Wed Jan 22 02:02:56 2003
@@ -24,6 +24,7 @@
 DOWNLOAD	svSrc
 DOWNLOAD_LIST	ldDL
 EDIT		editBf
+EDIT_BOOKMARK	editBmark
 EDIT_SCREEN	editScr
 END		goLineL
 ESCBMAP		escbmap
--- main.c.orig	Mon Jan 20 09:35:35 2003
+++ main.c	Wed Jan 22 02:02:56 2003
@@ -3982,6 +3982,14 @@
 		request);
 }
 
+void
+editBmark(void)
+{
+    edit_bookmark();
+    displayBuffer(Currentbuf, B_FORCE_REDRAW);
+}
+
+
 /* option setting */
 void
 ldOpt(void)
--- proto.h.orig	Wed Jan 22 01:46:14 2003
+++ proto.h	Wed Jan 22 02:02:56 2003
@@ -79,6 +79,7 @@
 extern void gorURL(void);
 extern void ldBmark(void);
 extern void adBmark(void);
+extern void editBmark(void);
 extern void ldOpt(void);
 extern void setOpt(void);
 extern void pginfo(void);
@@ -724,6 +725,8 @@
 #endif
 
 extern void dispVer(void);
+
+extern void edit_bookmark(void);
 
 #ifdef USE_INCLUDED_SRAND48
 void srand48(long);
--- bmedit.c.orig	Wed Jan 22 02:02:56 2003
+++ bmedit.c	Wed Jan 22 02:02:56 2003
@@ -0,0 +1,854 @@
+#include "fm.h"
+#include "myctype.h"
+
+#define BM_TITLE   1
+#define BM_SECTION 2
+#define BM_ITEM	3
+#define BM_URL	 4
+
+typedef struct _BmLine {
+    int type;
+    char *label;
+    int y;
+    struct _BmLine *prev;
+    struct _BmLine *next;
+} BmLine;
+
+static void bmNull(), bmEsc(),
+    bmDown1(), bmUp1(), bmMoveD(), bmMoveU(), bmPrev(), bmNext(),
+    bmNextI(), bmPrevI(), bmLineF(), bmLineL(),
+    bmEdit(), bmDel(), bmPaste(), bmAdd(), bmNew(),
+    bmLoad(), bmSave(), bmBack(), bmQuit(), bmExit();
+
+static void (*BmKeymap[128])() = {
+/*          C-a     C-b                     C-e     C-f             */
+    bmNull, bmLineF,bmMoveU,bmNull, bmNull, bmLineL,bmMoveD,bmNull,
+/*          C-i     C-j                     C-m     C-n             */
+    bmNull, bmNextI,bmEdit, bmNull, bmNull, bmEdit, bmMoveD,bmNull,
+/*  C-p                                             C-v             */
+    bmMoveU,bmNull, bmNull, bmNull, bmNull, bmNull, bmPaste,bmNull,
+/*  C-x                     C-[                                     */
+    bmDel,  bmNull, bmNull, bmEsc,  bmNull, bmNull, bmNull, bmNull,
+/*  SPC                                                             */
+    bmNext, bmNull, bmNull, bmNull, bmNull, bmNull, bmNull, bmNull,
+    bmNull, bmNull, bmNull, bmNull, bmNull, bmNull, bmNull, bmNull,
+    bmNull, bmNull, bmNull, bmNull, bmNull, bmNull, bmNull, bmNull,
+    bmNull, bmNull, bmNull, bmNull, bmNull, bmNull, bmNull, bmNull,
+/*          A       B               D       E               G       */
+    bmNull, bmAdd,  bmBack, bmNull, bmDel,  bmEdit, bmNull, bmLineL,
+/*                  J       K                       N               */
+    bmNull, bmNull, bmUp1,  bmDown1,bmNull, bmNull, bmNew,  bmNull,
+/*  P       Q       R       S                                       */
+    bmPaste,bmExit, bmLoad, bmSave, bmNull, bmNull, bmNull, bmNull,
+    bmNull, bmNull, bmNull, bmNull, bmNull, bmNull, bmNull, bmNull,
+/*          a       b               d       e               g       */
+    bmNull, bmAdd,  bmPrev, bmNull, bmDel,  bmEdit, bmNull, bmLineF,
+/*                  j       k                       n               */
+    bmNull, bmNull, bmMoveD,bmMoveU,bmNull, bmNull, bmNew,  bmNull,
+/*  p       q       r       s                                       */
+    bmPaste,bmQuit, bmLoad, bmSave, bmNull, bmNull, bmNull, bmNull,
+    bmNull, bmNull, bmNull, bmNull, bmNull, bmNull, bmNull, bmNull,
+};
+
+static void displayBmLine();
+static void displayModeLine();
+static void writeBmLine(BmLine *line, int under);
+static void arrangeBmLine();
+static void clearBmLine(BmLine *line);
+
+static BmLine *FirstLine = NULL, *LastLine, *CurrentLine, *BufferLine = NULL;
+static int offset, ret_state, save_state, exist;
+
+extern Hist *URLHist;
+
+void
+edit_bookmark(void)
+{
+    char c;
+
+    bmLoad();
+
+    ret_state = FALSE;
+    while (1) {
+	c = getch();
+	if (!(c & 0x80))
+	    (*BmKeymap[(int)c])();
+	if (ret_state)
+	    break;
+    }
+}
+
+void
+displayBmLine() {
+    BmLine *line;
+
+    clear();
+    for (line = FirstLine; line != NULL; line = line->next)
+	writeBmLine(line, FALSE);
+    writeBmLine(CurrentLine, TRUE);
+
+    displayModeLine();
+}
+
+void
+displayModeLine()
+{
+    move(LINES - 1, 0);
+    standout();
+    addstr("Editing bookmark: a)dd, B)ack, d)elete, e)dit, n)ew, p)aste, r)eset, s)ave");
+    standend();
+    refresh();
+}
+
+void
+writeBmLine(BmLine *line, int under) {
+    int y;
+
+    if (line == NULL)
+	return;
+    y = line->y - offset;
+    if (y < 0 || y >= LINES - 1)
+	return;
+
+    switch(line->type) {
+    case BM_TITLE:
+	move(y, 0);
+	clrtoeol();
+	if (under)
+	    underline();
+	bold();
+	addnstr(line->label, COLS - 1);
+	boldend();
+	if (under)
+	    underlineend();
+	break;
+    case BM_SECTION:
+	move(y, 0);
+	clrtoeol();
+	if (under)
+	    underline();
+	bold();
+	addnstr(html_unquote(line->label), COLS - 1);
+	boldend();
+	if (under)
+	    underlineend();
+	break;
+    case BM_ITEM:
+	move(y, 0);
+#if LANG == JA
+	addstr(" ¡¦ ");
+#else
+	addstr("  * ");
+#endif
+	clrtoeol();
+	if (under)
+	    underline();
+	addnstr(html_unquote(line->label), COLS - 5);
+	if (under)
+	    underlineend();
+	break;
+    case BM_URL:
+	move(y, 4);
+	clrtoeol();
+	if (under)
+	    underline();
+#ifdef USE_COLOR
+	if (useColor)
+	    setfcolor(anchor_color);
+#endif
+	addnstr(line->label, COLS - 5);
+#ifdef USE_COLOR
+	if (useColor)
+	    setfcolor(basic_color);
+#endif
+	if (under)
+	    underlineend();
+	break;
+    }
+}
+
+void
+arrangeBmLine() {
+    BmLine *line;
+    int n;
+
+    n = 0;
+    for (line = FirstLine; line != NULL; line = line->next) {
+	switch(line->type) {
+	case BM_TITLE:
+	    line->y = n;
+	    n++;
+	    break;
+	case BM_SECTION:
+	    n++;
+	    line->y = n;
+	    n += 2;
+	    break;
+	case BM_ITEM:
+	    line->y = n;
+	    n++;
+	    break;
+	case BM_URL:
+	    line->y = n;
+	    n++;
+	    break;
+	}
+    }
+}
+
+void
+clearBmLine(BmLine *line) {
+    BmLine *next;
+
+    for (; line != NULL; line = next)
+	next = line->next;
+}
+
+void
+bmNull()
+{
+}
+
+void
+bmEsc()
+{
+    char c;
+
+    switch(c = getch()) {
+    case '[':
+    case 'O':
+	switch(c = getch()) {
+	case 'A':
+	    bmMoveU();
+	    return;
+	case 'B':
+	    bmMoveD();
+	    return;
+	}
+	break;
+    case '\t':
+	bmPrevI();
+	break;
+    }
+}
+
+void
+bmDown1()
+{
+    BmLine *line;
+
+    if (offset <= 0)
+	return;
+
+    offset--;
+    if (CurrentLine->y - offset >= LINES - 1) {
+	for (line = CurrentLine->prev; line != NULL; line = line->prev) {
+	    if (line->type != 0 && line->y - offset < LINES - 1) {
+		CurrentLine = line;
+		break;
+	    }
+	}
+	if (line->y - offset < 0)
+	    offset = line->y;
+    }
+    displayBmLine();
+}
+
+void
+bmUp1()
+{
+    BmLine *line;
+
+    if (offset >= LastLine->y)
+	return;
+
+    offset++;
+    if (CurrentLine->y - offset < 0) {
+	for (line = CurrentLine->next; line != NULL; line = line->next) {
+	    if (line->type != 0 && line->y - offset >= 0) {
+		CurrentLine = line;
+		break;
+	    }
+	}
+	if (line->y - offset >= LINES - 1)
+	    offset = line->y - (LINES - 1) + 1;
+    }
+    displayBmLine();
+}
+
+void
+bmMoveD()
+{
+    BmLine *line;
+
+    if (CurrentLine->next == NULL)
+	return;
+
+    for (line = CurrentLine->next; line != NULL; line = line->next) {
+	if (line->type != 0) {
+	    if (line->y - offset >= LINES - 1) {
+		CurrentLine = line;
+		offset += (LINES - 1) / 2;
+		displayBmLine();
+	    }
+	    else {
+		writeBmLine(CurrentLine, FALSE);
+		CurrentLine = line;
+		writeBmLine(CurrentLine, TRUE);
+		refresh();
+	    }
+	    break;
+	}
+    }
+}
+
+void
+bmMoveU()
+{
+    BmLine *line;
+
+    if (CurrentLine->prev == NULL)
+	return;
+
+    for (line = CurrentLine->prev; line != NULL; line = line->prev) {
+	if (line->type != 0) {
+	    if (line->y - offset < 0) {
+		CurrentLine = line;
+		offset -= (LINES - 1) / 2;
+		if (offset < 0)
+		  offset = 0;
+		displayBmLine();
+	    }
+	    else {
+		writeBmLine(CurrentLine, FALSE);
+		CurrentLine = line;
+		writeBmLine(CurrentLine, TRUE);
+		refresh();
+	    }
+	    break;
+	}
+    }
+}
+
+void
+bmNextI()
+{
+    BmLine *line;
+
+    if (CurrentLine->next == NULL)
+	return;
+
+    for (line = CurrentLine->next; line != NULL; line = line->next) {
+	if (line->type == BM_ITEM) {
+	    if (line->y - offset >= LINES - 1) {
+		CurrentLine = line;
+		offset += (LINES - 1) / 2;
+		displayBmLine();
+	    }
+	    else {
+		writeBmLine(CurrentLine, FALSE);
+		CurrentLine = line;
+		writeBmLine(CurrentLine, TRUE);
+		refresh();
+	    }
+	    break;
+	}
+    }
+}
+
+void
+bmPrevI()
+{
+    BmLine *line;
+
+    if (CurrentLine->prev == NULL)
+	return;
+
+    for (line = CurrentLine->prev; line != NULL; line = line->prev) {
+	if (line->type == BM_ITEM) {
+	    if (line->y - offset < 0) {
+		CurrentLine = line;
+		offset -= (LINES - 1) / 2;
+		if (offset < 0)
+		    offset = 0;
+		displayBmLine();
+	    }
+	    else {
+		writeBmLine(CurrentLine, FALSE);
+		CurrentLine = line;
+		writeBmLine(CurrentLine, TRUE);
+		refresh();
+	    }
+	    break;
+	}
+    }
+}
+
+void
+bmPrev()
+{
+    BmLine *line;
+
+    if (offset == 0)
+	return;
+    offset -= LINES - 1;
+    if (offset < 0)
+	offset = 0;
+    for (line = FirstLine; line != NULL; line = line->next) {
+	if (line->type != 0 && line->y - offset >= 0) {
+	    CurrentLine = line;
+	    break;
+	}
+    }
+    displayBmLine();
+}
+
+void
+bmNext()
+{
+    BmLine *line;
+
+    if (LastLine->y - offset <= LINES - 1)
+	return;
+
+    offset += LINES - 1;
+    for (line = FirstLine; line != NULL; line = line->next) {
+	if (line->type != 0 && line->y - offset >= 0) {
+	    CurrentLine = line;
+	    break;
+	}
+    }
+    displayBmLine();
+}
+
+void
+bmLineF()
+{
+    BmLine *line;
+
+    if (offset == 0)
+	return;
+    offset = 0;
+    for (line = FirstLine; line != NULL; line = line->next) {
+	if (line->type != 0) {
+	    CurrentLine = line;
+	    break;
+	}
+    }
+    displayBmLine();
+}
+
+void
+bmLineL()
+{
+    BmLine *line;
+
+    offset = LastLine->y - (LINES - 1) / 2;
+    for (line = LastLine; line != NULL; line = line->prev) {
+	if (line->type != 0) {
+	    CurrentLine = line;
+	    break;
+	}
+    }
+    displayBmLine();
+}
+
+void
+bmEdit()
+{
+    BmLine *line = CurrentLine;
+    char *str;
+
+    switch(line->type) {
+    case BM_SECTION:
+	str = inputStr("Section: ", line->label);
+	break;
+    case BM_ITEM:
+	str = inputStr("Title: ", line->label);
+	break;
+    case BM_URL:
+	str = inputLineHist("URL: ", line->label, IN_URL, URLHist);
+	break;
+    default:
+	return;
+    }
+    if (str) {
+	line->label = str;
+	save_state = FALSE;
+	writeBmLine(line, TRUE);
+    }
+    displayModeLine();
+}
+
+void
+bmDel()
+{
+    BmLine *line = CurrentLine, *prev, *next;
+
+    switch(line->type) {
+    case BM_SECTION:
+	BufferLine = line;
+	prev = line->prev;
+	for (next = line->next; next != NULL; next = next->next) {
+	    if (next->type == BM_SECTION) {
+		if (next->prev != NULL)
+		    next->prev->next = NULL;
+		break;
+	    }
+	}
+	break;
+    case BM_ITEM:
+	BufferLine = line;
+	prev = line->prev;
+	next = line->next->next;
+	break;
+    case BM_URL:
+	BufferLine = line->prev;
+	prev = line->prev->prev;
+	next = line->next;
+	break;
+    default:
+	return;
+    }
+    prev->next = next;
+    if (next != NULL) {
+	CurrentLine = next;
+	next->prev = prev;
+    }
+    else {
+	LastLine = prev;
+	CurrentLine = prev;
+    }
+
+    save_state = FALSE;
+    arrangeBmLine();
+    displayBmLine();
+}
+
+void
+bmPaste()
+{
+    BmLine *line = CurrentLine, *next;
+
+    if (BufferLine == NULL)
+	return;
+    switch(BufferLine->type) {
+    case BM_SECTION:
+	switch(line->type) {
+	case BM_SECTION:
+	case BM_ITEM:
+	case BM_URL:
+	    for (; line->next != NULL; line = line->next) {
+		if (line->next->type == BM_SECTION)
+		    break;
+	    }
+	case BM_TITLE:
+	    next = line->next;
+	    line->next = BufferLine;
+	    BufferLine->prev = line;
+	    for (; line->next != NULL; line = line->next)
+		;
+	    line->next = next;
+	    if (next != NULL)
+		next->prev = line;
+	    else
+		LastLine = line;
+	    break;
+	default:
+	    return;
+	}
+	break;
+    case BM_ITEM:
+	switch(line->type) {
+	case BM_ITEM:
+	    line = line->next;
+	case BM_SECTION:
+	case BM_URL:
+	    next = line->next;
+	    line->next = BufferLine;
+	    BufferLine->prev = line;
+	    line = BufferLine->next;
+	    line->next = next;
+	    if (next != NULL)
+		next->prev = line;
+	    else
+		LastLine = line;
+	    break;
+	default:
+	    return;
+	}
+	break;
+    }
+    CurrentLine = BufferLine;
+    BufferLine = NULL;
+
+    save_state = FALSE;
+    arrangeBmLine();
+    if (CurrentLine->y - offset >= LINES - 1)
+	offset += (LINES - 1) / 2;
+    displayBmLine();
+}
+
+void
+bmAdd()
+{
+    BmLine *line = CurrentLine, *next, *new;
+    char *label, *url;
+
+    switch(line->type) {
+    case BM_ITEM:
+	line = line->next;
+    case BM_SECTION:
+    case BM_URL:
+	break;
+    default:
+	return;
+    }
+    label = inputStr("New Title: ", NULL);
+    if (label == NULL || *label == '\0') {
+	displayModeLine();
+	return;
+    }
+    url = inputLineHist("New URL: ", NULL, IN_URL, URLHist);
+    if (url == NULL || *url == '\0') {
+	displayModeLine();
+	return;
+    }
+
+    next = line->next;
+    CurrentLine = new = New(BmLine);
+    new->type = BM_ITEM;
+    new->label = label;
+    line->next = new;
+    new->prev = line;
+    new->next = New(BmLine);
+    new->next->prev = new;
+    new = new->next;
+    new->type = BM_URL;
+    new->label = url;
+    new->next = next;
+    if (next != NULL)
+	next->prev = new;
+    else
+	LastLine = new;
+
+    save_state = FALSE;
+    arrangeBmLine();
+    if (CurrentLine->y - offset >= LINES - 1)
+	offset += (LINES - 1) / 2;
+    displayBmLine();
+}
+
+void
+bmNew()
+{
+    BmLine *line = CurrentLine, *next, *new;
+    char *label;
+
+    switch(line->type) {
+    case BM_SECTION:
+    case BM_ITEM:
+    case BM_URL:
+	for (; line->next != NULL; line = line->next) {
+	    if (line->next->type == BM_SECTION)
+		break;
+	}
+    case BM_TITLE:
+	break;
+    default:
+	return;
+    }
+
+    label = inputStr("New Section: ", NULL);
+    if (label == NULL || *label == '\0') {
+	displayModeLine();
+	return;
+    }
+
+    next = line->next;
+    CurrentLine = new = New(BmLine);
+    new->type = BM_SECTION;
+    new->label = label;
+    line->next = new;
+    new->prev = line;
+    new->next = next;
+    if (next != NULL)
+	next->prev = new;
+    else
+	LastLine = new;
+
+    save_state = FALSE;
+    arrangeBmLine();
+    if (CurrentLine->y - offset >= LINES - 1)
+	offset += (LINES - 1) / 2;
+    displayBmLine();
+}
+
+void
+bmLoad()
+{
+    FILE *f;
+    BmLine *line;
+    Str tmp;
+    char *p, *url, *label;
+
+    clearBmLine(FirstLine);
+    clearBmLine(BufferLine);
+
+    line = FirstLine = New(BmLine);
+    line->label = "Bookmarks";
+    line->type = BM_TITLE;
+    line->prev = NULL;
+    line->next = NULL;
+
+    f = fopen(BookmarkFile, "r");
+    if (f != NULL) {
+	exist = TRUE;
+	while (tmp = Strfgets(f), tmp->length > 0) {
+	    if (!Strncasecmp_charp(tmp, "<h2>", 4)) {
+		Strshrinkfirst(tmp, 4);
+		p = tmp->ptr;
+		while (*p != '\0' && IS_SPACE(*p))
+		    p++;
+		label = p;
+		while (*p != '\0' && *p != '<')
+		    p++;
+		*p = '\0';
+		line->next = New(BmLine);
+		line->next->prev = line;
+		line = line->next;
+		line->type = BM_SECTION;
+		line->label = label;
+		line->next = NULL;
+	    }
+	    else if (!Strncasecmp_charp(tmp, "<li>", 4)) {
+		Strshrinkfirst(tmp, 4);
+		p = tmp->ptr;
+		while (*p != '\0' && *p != '"')
+		    p++;
+		if (*p++ == '\0')
+		    continue;
+		url = p;
+		while (*p != '\0' && *p != '"')
+		    p++;
+		*p = '\0';
+		p++;
+		while (*p != '\0' && *p != '>')
+		    p++;
+		if (*p++ == '\0')
+		    continue;
+		while (*p != '\0' && IS_SPACE(*p))
+		    p++;
+		label = p;
+		while (*p != '\0' && *p != '<')
+		    p++;
+		*p = '\0';
+		line->next = New(BmLine);
+		line->next->prev = line;
+		line = line->next;
+		line->type = BM_ITEM;
+		line->label = label;
+		line->next = New(BmLine);
+		line->next->prev = line;
+		line = line->next;
+		line->type = BM_URL;
+		line->label = url;
+		line->next = NULL;
+	    }
+	}
+	fclose(f);
+    }
+    else {
+	exist = FALSE;
+    }
+
+    offset = 0;
+    CurrentLine = FirstLine;
+    LastLine = line;
+    save_state = TRUE;
+
+    arrangeBmLine();
+    displayBmLine();
+}
+
+void
+bmSave()
+{
+    Str bak;
+    FILE *f;
+    Str msg;
+    BmLine *line;
+
+    if (exist) {
+	bak = Strnew_charp(BookmarkFile);
+	Strcat_charp(bak, ".bak");
+	rename(BookmarkFile, bak->ptr);
+    }
+
+    f = fopen(BookmarkFile, "w");
+    if (f != NULL) {
+	fprintf(f, "<html><head><title>Bookmarks</title></head>\n");
+	fprintf(f, "<body>\n<h1>Bookmarks</h1>\n");
+	for (line = FirstLine; line != NULL; line = line->next) {
+	    switch(line->type) {
+	    case BM_SECTION:
+		fprintf(f, "<h2>%s</h2>\n<ul>\n", line->label);
+		break;
+	    case BM_ITEM:
+		fprintf(f, "<li><a href=\"%s\">%s</a>\n", line->next->label,
+			line->label);
+		break;
+	    case BM_URL:
+		if (line->next == NULL || line->next->type == BM_SECTION)
+		    fprintf(f, "<!--End of section (do not delete this comment)-->\n</ul>\n");
+		break;
+	    }
+	}
+	fprintf(f, "</body>\n</html>\n");
+	fclose(f);
+	msg = Sprintf("Save to %s\n", BookmarkFile);
+    }
+    else {
+	msg = Sprintf("Can't save to %s\n", BookmarkFile);
+    }
+    disp_message(msg->ptr, 0);
+    if (! ret_state)
+	displayModeLine();
+    save_state = TRUE;
+}
+
+void
+bmBack()
+{
+    char *ans;
+
+    ret_state = TRUE;
+    if (! save_state) {
+	ans = inputAnswer("Save to your bookmark? (y/n)");
+	if (ans && tolower(*ans) == 'y')
+	    bmSave();
+    }
+}
+
+void
+bmQuit()
+{
+    char *ans;
+
+    ans = inputAnswer("Do you want to exit w3m? (y/n)");
+    if (ans && tolower(*ans) == 'y') {
+	if (! save_state) {
+	    ans = inputAnswer("Save to your bookmark? (y/n)");
+	    if (ans && tolower(*ans) == 'y')
+		bmSave();
+	}
+	quitfm();
+    }
+    displayModeLine();
+}
+
+void
+bmExit()
+{
+    quitfm();
+}
