about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--CHANGES20
-rw-r--r--WWW/Library/Implementation/HTTCP.c6
-rwxr-xr-xconfig.guess34
-rw-r--r--lynx_help/Lynx_users_guide.html14
-rw-r--r--src/GridText.c132
-rw-r--r--src/GridText.h9
-rw-r--r--src/HTML.c68
-rw-r--r--src/LYBookmark.c4
-rw-r--r--src/LYForms.c14
-rw-r--r--src/LYGlobalDefs.h3
-rw-r--r--src/LYMainLoop.c56
-rw-r--r--src/LYOptions.c11
-rw-r--r--src/LYrcFile.c3
-rw-r--r--userdefs.h12
14 files changed, 280 insertions, 106 deletions
diff --git a/CHANGES b/CHANGES
index bdf23d11..2b0d937d 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,9 +1,23 @@
--- $LynxId: CHANGES,v 1.1107 2022/03/31 23:30:44 tom Exp $
+-- $LynxId: CHANGES,v 1.1112 2022/06/12 17:05:20 tom Exp $
 ===============================================================================
 Changes since Lynx 2.8 release
 ===============================================================================
 
-2022-03-31 (2.9.0dev.11)
+2022-06-12 (2.9.0dev.11)
+* improve line-breaks and whitespace for Japanese characters -KH
+  + permit line breaks after any Japanese character (enabled by
+    --enable-wcwidth-support configuration and only called on last byte of
+    multibyte UTF-8 sequence)
+  + avoid adding spaces when joining lines after Japanese characters.
+* add new "Minimal" user mode, to minimize on-screen help/status.
+  Eliminates the URL on the bottom line, the forward/backward indicator in the
+  upper left, and most status-line messages - Paul G Fox
+* add PREVENT_KEYBOARD_WRAPAROUND symbol to userdefs.h 
+  Undefing this will allow cursor to wrap from bottom to/from top, when there's
+  more content than a single page.  (It can already wrap when the content
+  already fits on a page.) - Paul G Fox
+* modify NSL-fork to call freeaddrinfo only if getaddrinfo returns successfully
+  (patch by Rajeev V Pillai)
 * add ".br", ".lz", ".lzip", and ".xz" to binary-suffixes list -TD
 * changes for using brotli stream decompression -TD
 * changes for working with SOCKS5 on Windows 10 -GV, -TD
@@ -18,7 +32,7 @@ Changes since Lynx 2.8 release
   CF_FIX_WARNINGS, CF_MAKEFLAGS, CF_NCURSES_CONFIG, CF_NCURSES_LIBS,
   CF_PKG_CONFIG, CF_SIZECHANGE, CF_TRY_XOPEN_SOURCE, CF_WITH_PATH,
   CF_XOPEN_SOURCE
-* update config.guess (2022-01-09), config.sub (2022-01-03)
+* update config.guess (2022-05-25), config.sub (2022-01-03)
 
 2021-10-24 (2.9.0dev.10)
 * several fixes for problems found using asan2 with fuzzer-generated data
diff --git a/WWW/Library/Implementation/HTTCP.c b/WWW/Library/Implementation/HTTCP.c
index 29529c7e..a3bfda62 100644
--- a/WWW/Library/Implementation/HTTCP.c
+++ b/WWW/Library/Implementation/HTTCP.c
@@ -1,5 +1,5 @@
 /*
- * $LynxId: HTTCP.c,v 1.162 2022/03/12 16:45:47 tom Exp $
+ * $LynxId: HTTCP.c,v 1.163 2022/04/01 23:18:35 Rajeev.V.Pillai Exp $
  *
  *			Generic Communication Code		HTTCP.c
  *			==========================
@@ -1583,7 +1583,7 @@ static void really_getaddrinfo(const char *host,
     hints.ai_family = PF_UNSPEC;
     hints.ai_socktype = SOCK_STREAM;
     error = getaddrinfo(host, port, &hints, &res);
-    if (error || !res) {
+    if (error) {
 	CTRACE((tfp, "HTGetAddrInfo: getaddrinfo(%s, %s): %s\n", host, port,
 		gai_strerror(error)));
     } else {
@@ -1606,8 +1606,8 @@ static void really_getaddrinfo(const char *host,
 	} else {
 	    statuses->h_length = (int) (((LYNX_ADDRINFO *) (*result))->ai_addrlen);
 	}
+	freeaddrinfo(res);
     }
-    freeaddrinfo(res);
 }
 #endif /* NSL_FORK */
 
diff --git a/config.guess b/config.guess
index 7f76b622..1817bdce 100755
--- a/config.guess
+++ b/config.guess
@@ -4,7 +4,7 @@
 
 # shellcheck disable=SC2006,SC2268 # see below for rationale
 
-timestamp='2022-01-09'
+timestamp='2022-05-25'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -1151,16 +1151,27 @@ EOF
 	;;
     x86_64:Linux:*:*)
 	set_cc_for_build
+	CPU=$UNAME_MACHINE
 	LIBCABI=$LIBC
 	if test "$CC_FOR_BUILD" != no_compiler_found; then
-	    if (echo '#ifdef __ILP32__'; echo IS_X32; echo '#endif') | \
-		(CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
-		grep IS_X32 >/dev/null
-	    then
-		LIBCABI=${LIBC}x32
-	    fi
+	    ABI=64
+	    sed 's/^	    //' << EOF > "$dummy.c"
+	    #ifdef __i386__
+	    ABI=x86
+	    #else
+	    #ifdef __ILP32__
+	    ABI=x32
+	    #endif
+	    #endif
+EOF
+	    cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'`
+	    eval "$cc_set_abi"
+	    case $ABI in
+		x86) CPU=i686 ;;
+		x32) LIBCABI=${LIBC}x32 ;;
+	    esac
 	fi
-	GUESS=$UNAME_MACHINE-pc-linux-$LIBCABI
+	GUESS=$CPU-pc-linux-$LIBCABI
 	;;
     xtensa*:Linux:*:*)
 	GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
@@ -1367,8 +1378,11 @@ EOF
     BePC:Haiku:*:*)	# Haiku running on Intel PC compatible.
 	GUESS=i586-pc-haiku
 	;;
-    x86_64:Haiku:*:*)
-	GUESS=x86_64-unknown-haiku
+    ppc:Haiku:*:*)	# Haiku running on Apple PowerPC
+	GUESS=powerpc-apple-haiku
+	;;
+    *:Haiku:*:*)	# Haiku modern gcc (not bound by BeOS compat)
+	GUESS=$UNAME_MACHINE-unknown-haiku
 	;;
     SX-4:SUPER-UX:*:*)
 	GUESS=sx4-nec-superux$UNAME_RELEASE
diff --git a/lynx_help/Lynx_users_guide.html b/lynx_help/Lynx_users_guide.html
index a58355cd..bf4d682b 100644
--- a/lynx_help/Lynx_users_guide.html
+++ b/lynx_help/Lynx_users_guide.html
@@ -1,4 +1,4 @@
-<!-- $LynxId: Lynx_users_guide.html,v 1.155 2021/07/09 00:27:04 tom Exp $ -->
+<!-- $LynxId: Lynx_users_guide.html,v 1.156 2022/04/02 00:23:06 tom Exp $ -->
 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
 <html>
 <head>
@@ -1853,8 +1853,8 @@
     </dt>
 
     <dd>
-      <p>There are three possible choices: Novice, Intermediate,
-      and Advanced.</p>
+      <p>There are four possible choices: Novice, Intermediate,
+      Advanced, and Minimal.</p>
 
       <dl>
         <dt>Novice</dt>
@@ -1876,6 +1876,14 @@
           <p>Advanced mode displays the URL of the currently
           selected link at the bottom of the screen.</p>
         </dd>
+
+        <dt>Minimal</dt>
+
+        <dd>
+          <p>Minimal mode eliminates the URL on the bottom line,
+          the forward/backward indicator in the upper left, and
+          most status-line messages.</p>
+        </dd>
       </dl>
     </dd>
 
diff --git a/src/GridText.c b/src/GridText.c
index 7a36b47c..246d64e7 100644
--- a/src/GridText.c
+++ b/src/GridText.c
@@ -1,5 +1,5 @@
 /*
- * $LynxId: GridText.c,v 1.334 2021/10/24 16:13:59 tom Exp $
+ * $LynxId: GridText.c,v 1.340 2022/06/12 16:45:35 tom Exp $
  *
  *		Character grid hypertext object
  *		===============================
@@ -453,7 +453,11 @@ struct _HText {
     HTList *hidden_links;	/* Content-less links ... */
     int hiddenlinkflag;		/*  ... and how to treat them */
     BOOL no_cache;		/* Always refresh? */
+#ifdef EXP_JAPANESE_SPACES
+    char LastChars[7];		/* utf-8 buffer */
+#else
     char LastChar;		/* For absorbing white space */
+#endif
 
 /* For Internal use: */
     HTStyle *style;		/* Current style */
@@ -600,12 +604,11 @@ char star_string[MAX_LINE + 1];
 
 static int ctrl_chars_on_this_line = 0;		/* num of ctrl chars in current line */
 static int utfxtra_on_this_line = 0;	/* num of UTF-8 extra bytes in line,
-
 					   they *also* count as ctrl chars. */
 #ifdef EXP_WCWIDTH_SUPPORT
 static int utfxtracells_on_this_line = 0;	/* num of UTF-8 extra cells in line */
-static int utfextracells(const char *s);
 #endif
+
 #ifdef WIDEC_CURSES
 # ifdef EXP_WCWIDTH_SUPPORT	/* TODO: support for !WIDEC_CURSES */
 #define UTFXTRA_ON_THIS_LINE utfxtracells_on_this_line
@@ -736,6 +739,47 @@ static void *LY_check_calloc(size_t nmemb, size_t size)
 
 #endif /* CHECK_FREE_MEM */
 
+#ifdef EXP_WCWIDTH_SUPPORT
+static int utfextracells(const char *s)
+{
+    UCode_t ucs = UCGetUniFromUtf8String(&s);
+    int result = 0;
+
+    if (ucs > 0) {
+	int cells = wcwidth((wchar_t) ucs);
+
+	if (cells > 1)
+	    result = (cells - 1);
+    }
+    return result;
+}
+
+static void permit_split_after_CJchar(HText *text, const char *s, unsigned short pos)
+{
+    /* Can split after almost any CJ char (Korean uses space) */
+    /* TODO: UAX#14 Unicode Line Breaking Algorithm (use ICU4C?) */
+    if (isUTF8CJChar(s))
+	text->permissible_split = pos;
+}
+#endif /* EXP_WCWIDTH_SUPPORT */
+
+#if defined(EXP_WCWIDTH_SUPPORT) || defined(EXP_JAPANESE_SPACES)
+BOOL isUTF8CJChar(const char *s)
+{
+    UCode_t u = UCGetUniFromUtf8String(&s);
+
+    if ((u >= 0x4e00 && u <= 0x9fff) ||		/* CJK Unified Ideographs */
+	(u >= 0x3000 && u <= 0x30ff) ||		/* CJK Symbols and Punctuation, Hiragana, Katakana */
+	(u >= 0xff00 && u <= 0xffef) ||		/* Halfwidth and Fullwidth Forms. Fullwidth ?! are often used */
+    /* rare characters */
+	(u >= 0x3400 && u <= 0x4dbf) ||		/* CJK Unified Ideographs Extension A */
+	(u >= 0xf900 && u <= 0xfaff) ||		/* CJK Compatibility Ideographs */
+	(u >= 0x20000 && u <= 0x3ffff))		/* {Supplementary,Tertiary} Ideographic Plane */
+	return YES;
+    return NO;
+}
+#endif /* EXP_WCWIDTH_SUPPORT || EXP_JAPANESE_SPACES */
+
 #ifdef USE_COLOR_STYLE
 /*
  * Color style information is stored with the multibyte-character offset into
@@ -1133,7 +1177,11 @@ HText *HText_new(HTParentAnchor *anchor)
 				 anchor->post_data)
 				? YES
 				: NO);
+#ifdef EXP_JAPANESE_SPACES
+    memset(self->LastChars, 0, sizeof(self->LastChars));
+#else
     self->LastChar = '\0';
+#endif
 
 #ifndef USE_PRETTYSRC
     if (HTOutputFormat == WWW_SOURCE)
@@ -1776,7 +1824,8 @@ static void display_title(HText *text)
 #endif
     }
 #ifdef USE_COLOR_STYLE
-    if (s_forw_backw != NOSTYLE && (nhist || nhist_extra > 1)) {
+    if (s_forw_backw != NOSTYLE && user_mode != MINIMAL_MODE &&
+	(nhist || nhist_extra > 1)) {
 	chtype c = nhist ? ACS_LARROW : ' ';
 
 	/* turn the FORWBACKW.ARROW style on */
@@ -2866,7 +2915,7 @@ static void split_line(HText *text, unsigned split)
 #ifdef EXP_WCWIDTH_SUPPORT
     utfxtracells_on_this_line = 0;
 #endif
-    text->LastChar = ' ';
+    HText_setLastChar(text, ' ');
 
 #ifdef DEBUG_APPCH
     CTRACE((tfp, "GridText: split_line(%p,%d) called\n", text, split));
@@ -4165,8 +4214,10 @@ void HText_appendCharacter(HText *text, int ch)
 		    utff--;
 		utf_xlen = UTF_XLEN(line->data[utff]);
 
-		if (line->size - utff == utf_xlen + 1)	/* have last byte */
+		if (line->size - utff == utf_xlen + 1) {	/* have last byte */
 		    utfxtracells_on_this_line += utfextracells(&(line->data[utff]));
+		    permit_split_after_CJchar(text, &(line->data[utff]), line->size);
+		}
 	    }
 #endif
 	    return;
@@ -4645,7 +4696,24 @@ void HText_setLastChar(HText *text, int ch)
     if (!text)
 	return;
 
+#ifdef EXP_JAPANESE_SPACES
+    if (IS_UTF_EXTRA(ch) && IS_UTF_FIRST(text->LastChars[0])) {
+	int i;
+
+	for (i = 1;
+	     text->LastChars[i] != '\0' && i < sizeof(text->LastChars) - 1;
+	     i++) {
+	    ;
+	}
+	text->LastChars[i] = (char) ch;
+	text->LastChars[i + 1] = '\0';
+	return;
+    }
+    memset(text->LastChars, 0, sizeof(text->LastChars));
+    text->LastChars[0] = (char) ch;
+#else
     text->LastChar = (char) ch;
+#endif
 }
 
 /*	Get LastChar element in the text object.
@@ -4656,8 +4724,40 @@ char HText_getLastChar(HText *text)
     if (!text)
 	return ('\0');
 
+#ifdef EXP_JAPANESE_SPACES
+    if (IS_UTF_FIRST(text->LastChars[0])) {
+	int i;
+
+	for (i = 1;
+	     text->LastChars[i] != '\0' && i < sizeof(text->LastChars);
+	     i++) {
+	    ;
+	}
+	return ((char) text->LastChars[i - 1]);
+    }
+    return ((char) text->LastChars[0]);
+#else
     return ((char) text->LastChar);
+#endif
+}
+
+#ifdef EXP_JAPANESE_SPACES
+BOOL HText_checkLastChar_needSpaceOnJoinLines(HText *text)
+{
+    if (!text)
+	return YES;
+
+    if (IS_UTF_FIRST(text->LastChars[0]) && isUTF8CJChar(text->LastChars))
+	return NO;
+    if ((HTCJK == CHINESE || HTCJK == JAPANESE) && is8bits(text->LastChars[0])) {
+	/* TODO: support 2nd byte of some SJIS kanji (!is8bits && IS_SJIS_LO) */
+	return NO;
+    }
+    if (text->LastChars[0] != ' ')
+	return YES;
+    return NO;
 }
+#endif
 
 /*		Simple table handling - private
  *		-------------------------------
@@ -5201,7 +5301,7 @@ static void add_link_number(HText *text, TextAnchor *a, int save_position)
 	&& (text->source ? !psrcview_no_anchor_numbering : 1)
 #endif
 	&& links_are_numbered()) {
-	char saved_lastchar = text->LastChar;
+	char saved_lastchar = HText_getLastChar(text);
 	int saved_linenum = text->Lines;
 	HTAnchor *link_dest;
 	char *link_text;
@@ -5219,7 +5319,7 @@ static void add_link_number(HText *text, TextAnchor *a, int save_position)
 	    HText_appendText(text, marker);
 	}
 	if (saved_linenum && text->Lines && saved_lastchar != ' ')
-	    text->LastChar = ']';	/* if marker not after space caused split */
+	    HText_setLastChar(text, ']');	/* if marker not after space caused split */
 	if (save_position) {
 	    a->line_num = text->Lines;
 	    a->line_pos = (short) text->last_line->size;
@@ -14950,19 +15050,3 @@ GLOBALDEF HTProtocol LYLynxCache =
 {"LYNXCACHE", LYHandleCache, 0};
 #endif /* GLOBALDEF_IS_MACRO */
 #endif /* USE_CACHEJAR */
-
-#ifdef EXP_WCWIDTH_SUPPORT
-static int utfextracells(const char *s)
-{
-    UCode_t ucs = UCGetUniFromUtf8String(&s);
-    int result = 0;
-
-    if (ucs > 0) {
-	int cells = wcwidth((wchar_t) ucs);
-
-	if (cells > 1)
-	    result = (cells - 1);
-    }
-    return result;
-}
-#endif
diff --git a/src/GridText.h b/src/GridText.h
index 911de260..9c68d3db 100644
--- a/src/GridText.h
+++ b/src/GridText.h
@@ -1,5 +1,5 @@
 /*
- * $LynxId: GridText.h,v 1.69 2012/02/12 23:25:38 tom Exp $
+ * $LynxId: GridText.h,v 1.70 2022/06/12 16:38:03 KIHARA.Hideto Exp $
  *
  * Specialities of GridText as subclass of HText
  */
@@ -93,6 +93,9 @@ US-ASCII control characters <32 which are not defined in Unicode standard
 
     extern void HText_setLastChar(HText *text, int ch);
     extern char HText_getLastChar(HText *text);
+#ifdef EXP_JAPANESE_SPACES
+    extern BOOL HText_checkLastChar_needSpaceOnJoinLines(HText *text);
+#endif
 
     extern int HText_sourceAnchors(HText *text);
     extern void HText_setStale(HText *text);
@@ -289,6 +292,10 @@ US-ASCII control characters <32 which are not defined in Unicode standard
     extern HTkcode HText_getSpecifiedKcode(HText *text);
     extern void HText_updateSpecifiedKcode(HText *text, HTkcode kcode);
 
+#if defined(EXP_WCWIDTH_SUPPORT) || defined(EXP_JAPANESE_SPACES)
+    extern BOOL isUTF8CJChar(const char *s);
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/HTML.c b/src/HTML.c
index a0124668..14dfbc56 100644
--- a/src/HTML.c
+++ b/src/HTML.c
@@ -1,5 +1,5 @@
 /*
- * $LynxId: HTML.c,v 1.196 2021/10/24 19:10:57 tom Exp $
+ * $LynxId: HTML.c,v 1.198 2022/06/12 16:48:05 tom Exp $
  *
  *		Structured stream to Rich hypertext converter
  *		============================================
@@ -275,18 +275,6 @@ void LYShowBadHTML(const char *message)
  *			A C T I O N	R O U T I N E S
  */
 
-/* FIXME:  this should be amended to do the substitution only when not in a
- * multibyte stream.
- */
-#ifdef EXP_JAPANESE_SPACES
-#define FIX_JAPANESE_SPACES \
-	(HTCJK == CHINESE || HTCJK == JAPANESE || HTCJK == TAIPEI)
-	/* don't replace '\n' with ' ' if Chinese or Japanese - HN
-	 */
-#else
-#define FIX_JAPANESE_SPACES 0
-#endif
-
 /*	Character handling
  *	------------------
  */
@@ -333,12 +321,26 @@ void HTML_put_character(HTStructured * me, int c)
 	    return;
 	if (c != '\n' && c != '\t' && c != '\r') {
 	    HTChunkPutc(&me->title, uc);
-	} else if (FIX_JAPANESE_SPACES) {
-	    if (c == '\t') {
-		HTChunkPutc(&me->title, ' ');
-	    } else {
+#ifdef EXP_JAPANESE_SPACES
+	} else if (c == '\t') {
+	    HTChunkPutc(&me->title, ' ');
+	    /* don't replace '\n' with ' ' if Chinese or Japanese - HN */
+	} else if (me->title.size > 0 &&
+		   is8bits(me->title.data[me->title.size - 1])) {
+	    if (HTCJK == CHINESE || HTCJK == JAPANESE) {
+		/* TODO: support 2nd byte of SJIS (!is8bits && IS_SJIS_LO) */
 		return;
+	    } else if (IS_UTF8_TTY) {
+		/* find start position of UTF-8 sequence */
+		int i = me->title.size - 1;
+
+		while (i > 0 && (me->title.data[i] & 0xc0) == 0x80)	/* UTF_EXTRA */
+		    i--;
+		if (isUTF8CJChar(&(me->title.data[i])))
+		    return;
 	    }
+	    HTChunkPutc(&me->title, ' ');
+#endif
 	} else {
 	    HTChunkPutc(&me->title, ' ');
 	}
@@ -453,15 +455,17 @@ void HTML_put_character(HTStructured * me, int c)
 		UPDATE_STYLE;
 	    }
 	    if (c == '\n') {
-		if (!FIX_JAPANESE_SPACES) {
-		    if (me->in_word) {
-			if (HText_getLastChar(me->text) != ' ') {
-			    me->inP = TRUE;
-			    me->inLABEL = FALSE;
-			    HText_appendCharacter(me->text, ' ');
-			}
-			me->in_word = NO;
+		if (me->in_word) {
+#ifdef EXP_JAPANESE_SPACES
+		    if (HText_checkLastChar_needSpaceOnJoinLines(me->text)) {
+#else
+		    if (HText_getLastChar(me->text) != ' ') {
+#endif
+			me->inP = TRUE;
+			me->inLABEL = FALSE;
+			HText_appendCharacter(me->text, ' ');
 		    }
+		    me->in_word = NO;
 		}
 
 	    } else if (c == ' ' || c == '\t') {
@@ -607,12 +611,14 @@ void HTML_put_string(HTStructured * me, const char *s)
 		    UPDATE_STYLE;
 		}
 		if (c == '\n') {
-		    if (!FIX_JAPANESE_SPACES) {
-			if (me->in_word) {
-			    if (HText_getLastChar(me->text) != ' ')
-				HText_appendCharacter(me->text, ' ');
-			    me->in_word = NO;
-			}
+		    if (me->in_word) {
+#ifdef EXP_JAPANESE_SPACES
+			if (HText_checkLastChar_needSpaceOnJoinLines(me->text))
+#else
+			if (HText_getLastChar(me->text) != ' ')
+#endif
+			    HText_appendCharacter(me->text, ' ');
+			me->in_word = NO;
 		    }
 
 		} else if (c == ' ' || c == '\t') {
diff --git a/src/LYBookmark.c b/src/LYBookmark.c
index eff9dc70..47531b13 100644
--- a/src/LYBookmark.c
+++ b/src/LYBookmark.c
@@ -1,5 +1,5 @@
 /*
- * $LynxId: LYBookmark.c,v 1.80 2019/01/02 21:14:08 tom Exp $
+ * $LynxId: LYBookmark.c,v 1.81 2022/04/02 00:12:18 Paul.G.Fox Exp $
  */
 #include <HTUtils.h>
 #include <HTAlert.h>
@@ -712,7 +712,7 @@ int select_multi_bookmarks(void)
      * redraws of the screen, if LYMBMAdvnced is TRUE.  '=' will still show the
      * screen and let them do it the "long" way.
      */
-    if (LYMultiBookmarks == MBM_ADVANCED && user_mode == ADVANCED_MODE) {
+    if (LYMultiBookmarks == MBM_ADVANCED && (user_mode == ADVANCED_MODE)) {
 	LYMBM_statusline(MULTIBOOKMARKS_SELECT);
       get_advanced_choice:
 	c = LYgetch();
diff --git a/src/LYForms.c b/src/LYForms.c
index 642aa844..3f9c1110 100644
--- a/src/LYForms.c
+++ b/src/LYForms.c
@@ -1,4 +1,4 @@
-/* $LynxId: LYForms.c,v 1.118 2018/05/08 20:51:57 tom Exp $ */
+/* $LynxId: LYForms.c,v 1.119 2022/04/02 00:13:32 Paul.G.Fox Exp $ */
 #include <HTUtils.h>
 #include <HTCJK.h>
 #include <HTTP.h>
@@ -954,7 +954,9 @@ void show_formlink_statusline(const FormInfo * form,
 	    if (no_mail) {
 		statusline(FORM_LINK_SUBMIT_MAILTO_DIS_MSG);
 	    } else {
-		if (user_mode == ADVANCED_MODE) {
+		if (user_mode == MINIMAL_MODE) {
+		    statusline("");
+		} else if (user_mode == ADVANCED_MODE) {
 		    char *submit_str = NULL;
 
 		    StrAllocCopy(submit_str, FORM_LINK_SUBMIT_MAILTO_PREFIX);
@@ -966,7 +968,9 @@ void show_formlink_statusline(const FormInfo * form,
 		}
 	    }
 	} else if (form->no_cache) {
-	    if (user_mode == ADVANCED_MODE) {
+	    if (user_mode == MINIMAL_MODE) {
+		statusline("");
+	    } else if (user_mode == ADVANCED_MODE) {
 		char *submit_str = NULL;
 
 		StrAllocCopy(submit_str, FORM_LINK_RESUBMIT_PREFIX);
@@ -977,7 +981,9 @@ void show_formlink_statusline(const FormInfo * form,
 		statusline(FORM_LINK_RESUBMIT_MESSAGE);
 	    }
 	} else {
-	    if (user_mode == ADVANCED_MODE) {
+	    if (user_mode == MINIMAL_MODE) {
+		statusline("");
+	    } else if (user_mode == ADVANCED_MODE) {
 		char *submit_str = NULL;
 
 		StrAllocCopy(submit_str, FORM_LINK_SUBMIT_PREFIX);
diff --git a/src/LYGlobalDefs.h b/src/LYGlobalDefs.h
index 9f36d5f9..2802814e 100644
--- a/src/LYGlobalDefs.h
+++ b/src/LYGlobalDefs.h
@@ -1,5 +1,5 @@
 /*
- * $LynxId: LYGlobalDefs.h,v 1.153 2020/02/23 23:10:16 Keith.Bowes Exp $
+ * $LynxId: LYGlobalDefs.h,v 1.154 2022/04/02 00:12:18 Paul.G.Fox Exp $
  *
  * global variable definitions
  */
@@ -151,6 +151,7 @@ extern "C" {
 #define NOVICE_MODE 	  0
 #define INTERMEDIATE_MODE 1
 #define ADVANCED_MODE 	  2
+#define MINIMAL_MODE 	  3
     extern BOOLEAN LYUseNoviceLineTwo;	/* True if TOGGLE_HELP is not mapped */
 
 #define MAX_LINE 1024		/* No window can be wider than this */
diff --git a/src/LYMainLoop.c b/src/LYMainLoop.c
index 01d5b874..b1764ca9 100644
--- a/src/LYMainLoop.c
+++ b/src/LYMainLoop.c
@@ -1,5 +1,5 @@
 /*
- * $LynxId: LYMainLoop.c,v 1.246 2022/04/01 07:55:02 tom Exp $
+ * $LynxId: LYMainLoop.c,v 1.248 2022/04/02 00:12:18 Paul.G.Fox Exp $
  */
 #include <HTUtils.h>
 #include <HTAccess.h>
@@ -50,6 +50,25 @@
 #include <HTCJK.h>
 #endif
 
+#ifdef PREVENT_KEYBOARD_WRAPAROUND
+#define HandleForwardWraparound() \
+	*old_c = real_c; \
+	HTInfoMsg(ALREADY_AT_END)
+#define HandleReverseWraparound() \
+	*old_c = real_c; \
+	HTInfoMsg(ALREADY_AT_BEGIN)
+#else
+#define HandleForwardWraparound() \
+	LYSetNewline(1)
+#define HandleReverseWraparound() \
+	int i; \
+	i = HText_getNumOfLines() - display_lines + 2; \
+	if (i >= 1 && Newline != i) { \
+	    LYSetNewline(i); \
+	    *arrowup = TRUE; \
+	}
+#endif
+
 #define LinkIsTextarea(linkNumber) \
 		(links[linkNumber].type == WWW_FORM_LINK_TYPE && \
 		 links[linkNumber].l_form->type == F_TEXTAREA_TYPE)
@@ -2358,8 +2377,7 @@ static void handle_LYK_DOWN_xxx(int *old_c,
 		--newdoc.link;
 	}
     } else if (*old_c != real_c) {
-	*old_c = real_c;
-	HTInfoMsg(ALREADY_AT_END);
+	HandleForwardWraparound();
     }
 }
 
@@ -2398,8 +2416,7 @@ static void handle_LYK_DOWN_LINK(int *follow_col,
     } else if (more_text) {	/* next page */
 	LYChgNewline(display_lines);
     } else if (*old_c != real_c) {
-	*old_c = real_c;
-	HTInfoMsg(ALREADY_AT_END);
+	HandleForwardWraparound();
     }
 }
 
@@ -4101,8 +4118,7 @@ static void handle_LYK_NEXT_LINK(int c,
     } else if (more_text) {	/* next page */
 	LYChgNewline(display_lines);
     } else if (*old_c != real_c) {
-	*old_c = real_c;
-	HTInfoMsg(ALREADY_AT_END);
+	HandleForwardWraparound();
     }
 }
 
@@ -4175,8 +4191,7 @@ static void handle_LYK_PREV_LINK(int *arrowup,
 	}
 
     } else if (*old_c != real_c) {
-	*old_c = real_c;
-	HTInfoMsg(ALREADY_AT_BEGIN);
+	HandleReverseWraparound();
     }
 }
 
@@ -4860,8 +4875,7 @@ static void handle_LYK_UP_xxx(int *arrowup,
 	    }
 	}
     } else if (*old_c != real_c) {
-	*old_c = real_c;
-	HTInfoMsg(ALREADY_AT_BEGIN);
+	HandleReverseWraparound();
     }
 }
 
@@ -4918,8 +4932,7 @@ static void handle_LYK_UP_LINK(int *follow_col,
 	}
 
     } else if (*old_c != real_c) {
-	*old_c = real_c;
-	HTInfoMsg(ALREADY_AT_BEGIN);
+	HandleReverseWraparound();
     }
 }
 
@@ -6720,7 +6733,7 @@ int mainloop(void)
 		    set_ws_title(p);
 		}
 	    } else {
-		if (user_mode == ADVANCED_MODE) {
+		if (user_mode == ADVANCED_MODE || user_mode == MINIMAL_MODE) {
 		    p = curdoc.title;
 		} else {
 		    p = links[curdoc.link].lname;
@@ -6737,7 +6750,7 @@ int mainloop(void)
 	    }
 	} else {
 	    if (strlen(curdoc.address) < sizeof(temp_buff) - 1) {
-		if (user_mode == ADVANCED_MODE) {
+		if (user_mode == ADVANCED_MODE || user_mode == MINIMAL_MODE) {
 		    str_sjis(temp_buff, curdoc.title);
 		} else {
 		    strcpy(temp_buff, curdoc.address);
@@ -7945,7 +7958,7 @@ static void show_main_statusline(const LinkInfo curlink,
 	       !(curlink.type & WWW_LINK_TYPE)) {
 #else
     } else if (lynx_mode == FORMS_LYNX_MODE && nlinks > 0 &&
-	       !(user_mode == ADVANCED_MODE &&
+	       !((user_mode == ADVANCED_MODE || user_mode == MINIMAL_MODE) &&
 		 (curlink.type & WWW_LINK_TYPE))) {
 #endif /* NORMAL_NON_FORM_LINK_STATUSLINES_FOR_ALL_USER_MODES */
 #endif /* INDICATE_FORMS_MODE_FOR_ALL_LINKS_ON_PAGE */
@@ -7967,7 +7980,7 @@ static void show_main_statusline(const LinkInfo curlink,
 	    lynx_stop_reverse();
 	}
 
-    } else if (user_mode == ADVANCED_MODE && nlinks > 0) {
+    } else if ((user_mode == ADVANCED_MODE) && nlinks > 0) {
 	/*
 	 * Show the URL or, for some internal links, the fragment
 	 */
@@ -7980,6 +7993,11 @@ static void show_main_statusline(const LinkInfo curlink,
 	if (!cp)
 	    cp = curlink.lname;
 	status_link(cp, more_text, is_www_index);
+    } else if ((user_mode == MINIMAL_MODE) && nlinks > 0) {
+	/*
+	 *  no URL
+	 */
+	status_link("", more_text, is_www_index);
     } else if (is_www_index && more_text) {
 	char buf[128];
 
@@ -7995,8 +8013,10 @@ static void show_main_statusline(const LinkInfo curlink,
 	    _statusline(MORE);
 	else
 	    _statusline(MOREHELP);
-    } else {
+    } else if (user_mode != MINIMAL_MODE) {
 	_statusline(HELP);
+    } else {
+	_statusline("");
     }
 
     /* turn off cursor since now it's probably on statusline -HV */
diff --git a/src/LYOptions.c b/src/LYOptions.c
index 58c2f882..1a5848f3 100644
--- a/src/LYOptions.c
+++ b/src/LYOptions.c
@@ -1,4 +1,4 @@
-/* $LynxId: LYOptions.c,v 1.184 2021/07/30 00:17:54 tom Exp $ */
+/* $LynxId: LYOptions.c,v 1.185 2022/04/02 00:13:48 Paul.G.Fox Exp $ */
 #include <HTUtils.h>
 #include <HTFTP.h>
 #include <HTTP.h>		/* 'reloading' flag */
@@ -337,6 +337,7 @@ void LYoptions(void)
 	"Novice",
 	"Intermediate",
 	"Advanced",
+	"Minimal",
 	NULL
     };
 
@@ -572,7 +573,8 @@ void LYoptions(void)
     addlbl("(U)ser mode                  : ");
     LYaddstr((user_mode == NOVICE_MODE) ? "Novice      " :
 	     ((user_mode == INTERMEDIATE_MODE) ? "Intermediate" :
-	      "Advanced    "));
+	      ((user_mode == ADVANCED_MODE) ? "Advanced    " :
+	       "Minimal     ")));
 
     addlbl("  verbose images (!) : ");
     ShowBool(verbose_img);
@@ -1396,13 +1398,13 @@ void LYoptions(void)
 		user_mode = LYChooseEnum(user_mode,
 					 L_User_Mode, -1,
 					 userMode_choices);
-		use_assume_charset = (BOOLEAN) (user_mode >= 2);
+		use_assume_charset = (BOOLEAN) (user_mode == ADVANCED_MODE);
 	    } else {
 		user_mode = LYChoosePopup(user_mode,
 					  L_User_Mode, -1,
 					  userMode_choices,
 					  3, FALSE, FALSE);
-		use_assume_charset = (BOOLEAN) (user_mode >= 2);
+		use_assume_charset = (BOOLEAN) (user_mode == ADVANCED_MODE);
 #if defined(VMS) || defined(USE_SLANG)
 		if (use_assume_charset == old_use_assume_charset) {
 		    LYmove(L_User_Mode, COL_OPTION_VALUES);
@@ -2268,6 +2270,7 @@ static OptValues user_mode_values[] =
     {NOVICE_MODE, N_("Novice"), "Novice"},
     {INTERMEDIATE_MODE, N_("Intermediate"), "Intermediate"},
     {ADVANCED_MODE, N_("Advanced"), "Advanced"},
+    {MINIMAL_MODE, N_("Minimal"), "Minimal"},
     END_OPTIONS
 };
 
diff --git a/src/LYrcFile.c b/src/LYrcFile.c
index be089175..b8cef377 100644
--- a/src/LYrcFile.c
+++ b/src/LYrcFile.c
@@ -1,4 +1,4 @@
-/* $LynxId: LYrcFile.c,v 1.106 2022/03/27 23:01:26 tom Exp $ */
+/* $LynxId: LYrcFile.c,v 1.107 2022/04/02 00:12:18 Paul.G.Fox Exp $ */
 #include <HTUtils.h>
 #include <HTFTP.h>
 #include <LYUtils.h>
@@ -167,6 +167,7 @@ Config_Enum tbl_transfer_rate[] = {
 };
 
 Config_Enum tbl_user_mode[] = {
+    { "MINIMAL",	MINIMAL_MODE },
     { "ADVANCED",	ADVANCED_MODE },
     { "INTERMEDIATE",	INTERMEDIATE_MODE },
     { "NOVICE",		NOVICE_MODE },
diff --git a/userdefs.h b/userdefs.h
index 80d2ede7..e08dcbd3 100644
--- a/userdefs.h
+++ b/userdefs.h
@@ -1,5 +1,5 @@
 /*
- * $LynxId: userdefs.h,v 1.362 2022/03/11 01:29:33 tom Exp $
+ * $LynxId: userdefs.h,v 1.363 2022/04/01 23:56:33 Paul.G.Fox Exp $
  *
  * Lynx - Hypertext navigation system
  *
@@ -1240,6 +1240,16 @@
 #define DEFAULT_KEYPAD_MODE	NUMBERS_AS_ARROWS
 
 /********************************
+ * If PREVENT_KEYBOARD_WRAPAROUND is defined, using the keyboard to
+ * move past the end (or beginning) of a page results in a warning. 
+ * Otherwise, such motions cause the cursor to wrap from bottom to top
+ * (or top to bottom) of page.  Note that for pages which fit
+ * completely on one screen, wraparound always occurs, so this only
+ * affects multi-screen pages.
+ */
+#define PREVENT_KEYBOARD_WRAPAROUND
+
+/********************************
  * The default search.
  * This is a default that can be overridden in lynx.cfg or by the user!
  */