summaryrefslogtreecommitdiffstats
path: root/src/LYCurses.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/LYCurses.c')
-rw-r--r--src/LYCurses.c3277
1 files changed, 3277 insertions, 0 deletions
diff --git a/src/LYCurses.c b/src/LYCurses.c
new file mode 100644
index 0000000..8857d1c
--- /dev/null
+++ b/src/LYCurses.c
@@ -0,0 +1,3277 @@
+/* $LynxId: LYCurses.c,v 1.200 2023/01/02 23:52:18 tom Exp $ */
+#include <HTUtils.h>
+#include <HTAlert.h>
+
+#ifdef __MINGW32__
+#ifdef UNIX
+#undef UNIX
+#endif /* UNIX */
+#endif /* __MINGW32__ */
+
+#ifdef __DJGPP__
+#include <pc.h>
+#endif /* __DJGPP__ */
+
+#include <LYCurses.h>
+#include <LYStyle.h>
+#include <LYUtils.h>
+#include <LYGlobalDefs.h>
+#include <LYSignal.h>
+#include <LYClean.h>
+#include <LYReadCFG.h>
+#include <LYStrings.h>
+#include <LYCharSets.h>
+#include <UCAux.h>
+#include <HTFont.h>
+
+#include <LYexit.h>
+#include <LYLeaks.h>
+
+#ifdef VMS
+#include <LYMainLoop.h>
+#endif
+
+#if defined(VMS) && defined(__GNUC__)
+#include <gnu_hacks.h>
+#undef LINES
+#undef COLS
+#define LINES lines
+#define COLS cols
+extern int _NOSHARE(LINES);
+extern int _NOSHARE(COLS);
+#endif /* VMS && __GNUC__ */
+
+#ifdef USE_COLOR_STYLE
+#include <AttrList.h>
+#include <LYHash.h>
+#endif
+
+#ifdef NEED_WCHAR_H
+#include <wchar.h>
+#endif
+
+#if defined(COLOR_CURSES)
+int lynx_has_color = FALSE;
+#endif
+
+#ifdef HAVE_XCURSES
+char *XCursesProgramName = "Lynx";
+#endif
+
+#ifdef PDCURSES
+#undef HAVE_NEWTERM /* not needed, since /dev/tty is unused */
+#endif
+
+#if defined(USE_COLOR_STYLE) && !defined(USE_COLOR_TABLE)
+#define COLOR_BKGD ((s_normal != NOSTYLE) ? hashStyles[s_normal].color : A_NORMAL)
+#else
+#define COLOR_BKGD ((COLOR_PAIRS >= 9) ? (chtype) get_color_pair(9) : A_NORMAL)
+#endif
+
+#ifdef USE_CURSES_PADS
+WINDOW *LYwin = 0;
+int LYshiftWin = 0;
+int LYwideLines = FALSE;
+int LYtableCols = 0; /* in 1/12 of screen width */
+BOOLEAN LYuseCursesPads = TRUE; /* use pads for left/right shifting */
+#endif
+
+/*
+ * These are routines to start and stop curses and to cleanup the screen at the
+ * end.
+ */
+
+static int dumbterm(char *terminal);
+BOOLEAN LYCursesON = FALSE;
+
+#if defined(USE_BLINK) && defined(__EMX__)
+static void make_blink_boldbg(void);
+#endif
+
+#if defined(USE_COLOR_TABLE) || defined(USE_SLANG)
+int Current_Attr;
+static int Masked_Attr;
+#endif
+
+#ifdef USE_SLANG
+unsigned Lynx_Color_Flags = 0;
+BOOLEAN FullRefresh = FALSE;
+int curscr = 0;
+
+void LY_SLrefresh(void)
+{
+ if (FullRefresh) {
+ SLsmg_suspend_smg();
+ SLsmg_resume_smg();
+ FullRefresh = FALSE;
+ } else {
+ SLsmg_refresh();
+ }
+
+ return;
+}
+
+/* the following renamed from LY_SLclear since it is more like erase()
+ described in curses man pages than like clear(); but for USE_SLANG
+ clear() is still a macro calling this, and will do the same thing as
+ erase(). - kw */
+void LY_SLerase(void)
+{
+ SLsmg_gotorc(0, 0);
+ SLsmg_erase_eos();
+}
+
+#ifdef VMS
+void VTHome(void)
+{
+ printf("\033[;H");
+
+ return;
+}
+#endif /* VMS */
+
+void LYaddAttr(int a)
+{
+ Current_Attr |= a;
+ SLsmg_set_color((SLsmg_Color_Type) (Current_Attr & ~Masked_Attr));
+}
+
+void LYsubAttr(int a)
+{
+ Current_Attr &= ~a;
+ SLsmg_set_color((SLsmg_Color_Type) (Current_Attr & ~Masked_Attr));
+}
+
+static void lynx_setup_attrs(void)
+{
+ static int monoattr[] =
+ {
+ 0,
+ SLTT_BOLD_MASK,
+ SLTT_REV_MASK,
+ SLTT_REV_MASK | SLTT_BOLD_MASK,
+ SLTT_ULINE_MASK,
+ SLTT_ULINE_MASK | SLTT_BOLD_MASK,
+ SLTT_ULINE_MASK | SLTT_REV_MASK,
+ SLTT_ULINE_MASK | SLTT_BOLD_MASK | SLTT_REV_MASK
+ };
+ int n;
+
+ for (n = 1; n <= 7; n++)
+ SLtt_set_mono(n, NULL, (SLtt_Char_Type) (monoattr[n] & ~Masked_Attr));
+}
+
+void lynx_setup_colors(void)
+{
+ CTRACE((tfp, "lynx_setup_colors\n"));
+ SLtt_set_color(0, NULL, DEFAULT_FG, DEFAULT_BG);
+ SLtt_set_color(1, NULL, "blue", DEFAULT_BG); /* bold */
+ SLtt_set_color(2, NULL, "yellow", "blue"); /* reverse */
+ SLtt_set_color(4, NULL, "magenta", DEFAULT_BG); /* underline */
+ /*
+ * The other objects are '|'ed together to get rest.
+ */
+ SLtt_set_color(3, NULL, "green", DEFAULT_BG); /* bold-reverse */
+ SLtt_set_color(5, NULL, "blue", DEFAULT_BG); /* bold-underline */
+ SLtt_set_color(6, NULL, "red", DEFAULT_BG); /* reverse-underline */
+ SLtt_set_color(7, NULL, "magenta", "cyan"); /* reverse-underline-bold */
+ /*
+ * Now set monochrome attributes.
+ */
+ lynx_setup_attrs();
+}
+
+static void sl_suspend(int sig)
+{
+#ifdef SIGSTOP
+#ifndef VMS
+ int r, c;
+
+ lynx_enable_mouse(0);
+ if (sig == SIGTSTP)
+ SLsmg_suspend_smg();
+ SLang_reset_tty();
+ kill(getpid(), SIGSTOP);
+#if SLANG_VERSION > 9929
+ SLang_init_tty(-1, 0, 1);
+#else
+ SLang_init_tty(3, 0, 1);
+#endif /* SLANG_VERSION > 9929 */
+ signal(SIGTSTP, sl_suspend);
+#if defined(REAL_UNIX_SYSTEM) && !defined(__CYGWIN__)
+ SLtty_set_suspend_state(1);
+#endif
+ if (sig == SIGTSTP)
+ SLsmg_resume_smg();
+ /*
+ * Get new window size in case it changed.
+ */
+ r = SLtt_Screen_Rows;
+ c = SLtt_Screen_Cols;
+ size_change(0);
+ if ((r != SLtt_Screen_Rows) || (c != SLtt_Screen_Cols)) {
+ recent_sizechange = TRUE;
+ }
+ lynx_enable_mouse(1);
+#endif /* !VMS */
+#endif /* SIGSTOP */
+ return;
+}
+#else
+
+#ifdef FANCY_CURSES
+
+#ifndef VMS
+/* *INDENT-OFF* */
+/* definitions for the mono attributes we can use */
+static struct {
+ const char *name;
+ int code;
+} Mono_Attrs[7] =
+{
+ { "normal", A_NORMAL },
+ { "bold", A_BOLD },
+ { "reverse", A_REVERSE },
+ { "underline", A_UNDERLINE },
+ { "standout", A_STANDOUT },
+ { "blink", A_BLINK },
+ { "dim", A_DIM },
+};
+/* *INDENT-ON* */
+
+int string_to_attr(const char *name)
+{
+ unsigned i;
+
+ for (i = 0; i < TABLESIZE(Mono_Attrs); i++) {
+ if (!strcasecomp(Mono_Attrs[i].name, name)) {
+ return Mono_Attrs[i].code;
+ }
+ }
+ return 0;
+}
+#endif /* VMS */
+
+#ifdef USE_COLOR_STYLE
+static char *attr_to_string(int code)
+{
+ static char *result;
+
+ if (code >= 0) {
+ unsigned i;
+ int pair = PAIR_NUMBER((unsigned) code);
+ int bold = (pair != 0 && ((unsigned) code & A_BOLD) != 0);
+
+ StrAllocCopy(result, "");
+
+ if (bold)
+ code &= (int) ~A_BOLD;
+
+ for (i = 0; i < TABLESIZE(Mono_Attrs); i++) {
+ if (Mono_Attrs[i].code & code) {
+ if (non_empty(result))
+ StrAllocCat(result, "+");
+ StrAllocCat(result, Mono_Attrs[i].name);
+ }
+ }
+ if (pair != 0) {
+ short f, b;
+
+ if (pair_content((short) pair, &f, &b) != ERR) {
+ if (non_empty(result))
+ StrAllocCat(result, "+");
+ StrAllocCat(result, lookup_color(bold ? f + COLORS : f));
+ StrAllocCat(result, "/");
+ StrAllocCat(result, lookup_color(b));
+ }
+ }
+ } else {
+ FREE(result);
+ }
+ return result;
+}
+#endif /* USE_COLOR_STYLE */
+#endif /* FANCY_CURSES */
+#endif /* USE_SLANG */
+
+/*
+ * This function boxes windows for (n)curses.
+ */
+void LYbox(WINDOW * win, int formfield GCC_UNUSED)
+{
+#ifdef USE_SLANG
+ SLsmg_draw_box(win->top_y,
+ win->left_x,
+ (unsigned) win->height,
+ (unsigned) win->width + 4);
+#else
+#ifdef VMS
+ /*
+ * This should work for VAX-C and DEC-C, since they both have the same
+ * win._max_y and win._max_x members -TD
+ *
+ * (originally VMSbox by FM)
+ */
+ int i;
+
+ wmove(win, 0, 0);
+ waddstr(win, "\033)0\016l");
+ for (i = 1; i < win->_max_x; i++)
+ waddch(win, 'q');
+ waddch(win, 'k');
+ for (i = 1; i < win->_max_y - 1; i++) {
+ wmove(win, i, 0);
+ waddch(win, 'x');
+ wmove(win, i, win->_max_x - 1);
+ waddch(win, 'x');
+ }
+ wmove(win, i, 0);
+ waddch(win, 'm');
+ for (i = 1; i < win->_max_x; i++)
+ waddch(win, 'q');
+ waddstr(win, "j\017");
+#else /* !VMS */
+ int boxvert, boxhori;
+
+ UCSetBoxChars(current_char_set, &boxvert, &boxhori, BOXVERT, BOXHORI);
+#ifdef CSS
+ if (formfield)
+ wcurses_css(win, "frame", ABS_ON);
+#endif
+ /*
+ * If we don't have explicitly specified characters for either vertical or
+ * horizontal lines, the characters that box() would use for the corners
+ * probably also won't work well. So we specify our own ASCII characters
+ * for the corners and call wborder() instead of box(). - kw
+ */
+ LynxWChangeStyle(win, s_menu_frame, STACK_ON);
+#ifdef HAVE_WBORDER
+ if (!boxvert || !boxhori) {
+ box(win,
+ (chtype) boxvert,
+ (chtype) boxhori);
+ } else if (boxvert == '*' || boxhori == '*') {
+ wborder(win,
+ (chtype) boxvert,
+ (chtype) boxvert,
+ (chtype) boxhori,
+ (chtype) boxhori,
+ '*', '*', '*', '*');
+ } else {
+ wborder(win,
+ (chtype) boxvert,
+ (chtype) boxvert,
+ (chtype) boxhori,
+ (chtype) boxhori,
+ '/', '\\', '\\', '/');
+ }
+#else
+ box(win, boxvert, boxhori);
+#endif
+ LynxWChangeStyle(win, s_menu_frame, STACK_OFF);
+#ifdef CSS
+ if (formfield)
+ wcurses_css(win, "frame", ABS_OFF);
+#endif
+#endif /* VMS */
+ wrefresh(win);
+#endif /* USE_SLANG */
+}
+
+#if defined(USE_COLOR_STYLE)
+/* Ok, explanation of the USE_COLOR_STYLE styles. The basic styles (ie non
+ * HTML) are set the same as the SLANG version for ease of programming. The
+ * other styles are simply the HTML enum from HTMLDTD.h + 16.
+ */
+HTCharStyle displayStyles[DSTYLE_ELEMENTS];
+
+/*
+ * set a style's attributes - RP
+ */
+void setStyle(int style,
+ int color,
+ int cattr,
+ int mono)
+{
+ displayStyles[style].color = color;
+ displayStyles[style].cattr = cattr;
+ displayStyles[style].mono = mono;
+}
+
+void setHashStyle(int style,
+ int color,
+ int cattr,
+ int mono,
+ const char *element)
+{
+ bucket *ds = &hashStyles[style];
+
+ CTRACE2(TRACE_STYLE,
+ (tfp, "CSS(SET): <%s> hash=%d, ca=%#x, ma=%#x\n",
+ element, style, (unsigned) color, (unsigned) mono));
+
+ ds->used = TRUE;
+ ds->color = color;
+ ds->cattr = cattr;
+ ds->mono = mono;
+}
+
+/*
+ * set the curses attributes to be color or mono - RP
+ */
+static void LYAttrset(WINDOW * win, int color,
+ int mono)
+{
+ char *shown = NULL;
+
+ if (lynx_has_color
+ && LYShowColor >= SHOW_COLOR_ON
+ && color >= 0) {
+ CTRACE2(TRACE_STYLE, (tfp, "CSS:LYAttrset color %#x -> (%s)\n",
+ (unsigned) color,
+ shown = attr_to_string(color)));
+ (void) wattrset(win, color);
+ } else if (mono >= 0) {
+ CTRACE2(TRACE_STYLE, (tfp, "CSS:LYAttrset mono %#x -> (%s)\n",
+ (unsigned) mono,
+ shown = attr_to_string(mono)));
+ (void) wattrset(win, mono);
+ } else {
+ CTRACE2(TRACE_STYLE, (tfp, "CSS:LYAttrset (A_NORMAL)\n"));
+ (void) wattrset(win, A_NORMAL);
+ }
+ if (shown != NULL)
+ (void) attr_to_string(-1);
+}
+
+void curses_w_style(WINDOW * win, int style,
+ int dir)
+{
+ int YP, XP;
+ bucket *ds;
+ BOOL free_ds = TRUE;
+
+ switch (style) {
+ case NOSTYLE:
+ ds = nostyle_bucket();
+ break;
+ default:
+ ds = &hashStyles[style];
+ free_ds = FALSE;
+ break;
+ }
+
+ if (!ds->used) {
+ CTRACE2(TRACE_STYLE, (tfp, "CSS.CS:Style %d not configured\n", style));
+ if (free_ds)
+ free(ds);
+ return;
+ }
+
+ CTRACE2(TRACE_STYLE, (tfp, "CSS.CS:<%s%s> style %d color %#x\n",
+ (dir ? "" : "/"),
+ ds->name,
+ style,
+ (unsigned) ds->color));
+
+ getyx(win, YP, XP);
+
+ if (style == s_normal && dir) {
+ LYAttrset(win, ds->color, ds->mono);
+ if (win == LYwin)
+ SetCachedStyle(YP, XP, (unsigned) s_normal);
+ if (free_ds)
+ free(ds);
+ return;
+ }
+
+ switch (dir) {
+ /* ABS_OFF is the same as STACK_OFF for the moment */
+ case STACK_OFF:
+ if (last_colorattr_ptr) {
+ int last_attr = last_styles[--last_colorattr_ptr];
+
+ LYAttrset(win, last_attr, last_attr);
+ } else
+ LYAttrset(win, A_NORMAL, -1);
+ break;
+
+ case STACK_ON: /* remember the current attributes */
+ if (last_colorattr_ptr >= MAX_LAST_STYLES) {
+ CTRACE2(TRACE_STYLE, (tfp, "........... %s (0x%x) %s\r\n",
+ "attribute cache FULL, dropping last",
+ (unsigned) last_styles[last_colorattr_ptr],
+ "in LynxChangeStyle(curses_w_style)"));
+ last_colorattr_ptr = MAX_LAST_STYLES - 1;
+ }
+ last_styles[last_colorattr_ptr++] = (int) LYgetattrs(win);
+ /* don't cache style changes for active links */
+ /* FALL THROUGH */
+ case ABS_ON: /* change without remembering the previous style */
+ /* don't cache style changes for active links and edits */
+ if (style != s_alink
+ && style != s_curedit
+ && style != s_aedit
+ && style != s_aedit_sel
+ && style != s_aedit_pad
+ && style != s_aedit_arr) {
+ CTRACE2(TRACE_STYLE, (tfp, "CACHED: <%s> @(%d,%d)\n",
+ ds->name, YP, XP));
+ if (win == LYwin)
+ SetCachedStyle(YP, XP, (unsigned) style);
+ }
+ LYAttrset(win, ds->color, ds->mono);
+ break;
+ }
+
+ if (free_ds)
+ free(ds);
+
+ return;
+}
+
+/*
+ * wrapper function to set on-screen styles - RP
+ */
+void wcurses_css(WINDOW * win, char *name,
+ int dir)
+{
+ int try_again = 1;
+
+ while (try_again) {
+ int tmpHash = color_style_1(name);
+
+ CTRACE2(TRACE_STYLE, (tfp, "CSSTRIM:trying to set [%s] style - ", name));
+ if (tmpHash == NOSTYLE) {
+ char *pclass = strrchr(name, '.');
+
+ CTRACE2(TRACE_STYLE, (tfp, "undefined, trimming at %p\n", (void *) pclass));
+ if (pclass)
+ *pclass = '\0';
+ else
+ try_again = 0;
+ } else {
+ CTRACE2(TRACE_STYLE, (tfp, "ok (%d)\n", tmpHash));
+ curses_w_style(win, tmpHash, dir);
+ try_again = 0;
+ }
+ }
+}
+
+void curses_css(char *name,
+ int dir)
+{
+ wcurses_css(LYwin, name, dir);
+}
+
+void curses_style(int style,
+ int dir)
+{
+ curses_w_style(LYwin, style, dir);
+}
+#endif /* USE_COLOR_STYLE */
+
+static BOOL lynx_called_initscr = FALSE;
+
+#if defined(USE_COLOR_TABLE) && defined(COLOR_CURSES)
+#define COLOR_CFG_MAX 8
+
+/*
+ * This block of code is designed to produce the same color effects using SVr4
+ * curses as the slang library's implementation in this module. That maps the
+ * SGR codes into a 0-7 index into the color table, with special treatment for
+ * backgrounds. There's a bit of convoluted (but necessary) code handling the
+ * special case of initialization before 'initscr()' is called.
+ * 1997/1/19 - T.E.Dickey <dickey@clark.net>
+ */
+/* *INDENT-OFF* */
+#define COLOR_CFG(c) c, (c) == DEFAULT_COLOR
+static struct {
+ int fg, dft_fg, bg, dft_bg;
+} lynx_color_cfg[] = {
+ /*0*/ { COLOR_CFG(DEFAULT_FG), COLOR_CFG(DEFAULT_BG)},
+ /*1*/ { COLOR_CFG(COLOR_BLUE), COLOR_CFG(DEFAULT_BG)},
+ /*2*/ { COLOR_CFG((COLOR_YELLOW)+8), COLOR_CFG(COLOR_BLUE)},
+ /*3*/ { COLOR_CFG(COLOR_GREEN), COLOR_CFG(DEFAULT_BG)},
+ /*4*/ { COLOR_CFG(COLOR_MAGENTA), COLOR_CFG(DEFAULT_BG)},
+ /*5*/ { COLOR_CFG(COLOR_BLUE), COLOR_CFG(DEFAULT_BG)},
+ /*6*/ { COLOR_CFG(COLOR_RED), COLOR_CFG(DEFAULT_BG)},
+ /*7*/ { COLOR_CFG(COLOR_MAGENTA), COLOR_CFG(COLOR_CYAN)}
+};
+/* *INDENT-ON* */
+
+#define COLOR_PAIRS_MAX (COLOR_CFG_MAX * 3 + 1)
+
+/*
+ * Hold the codes for color-pairs here until 'initscr()' is called.
+ */
+static struct {
+ int fg;
+ int bg;
+} lynx_color_pairs[COLOR_PAIRS_MAX];
+
+/*
+ * If we find an exact match for the given default colors, force curses to use
+ * color pair 0, which corresponds to the terminal's default colors. Normally
+ * curses assumes white-on-black, but we can override the assumption with this
+ * function.
+ */
+static int get_color_pair(int n)
+{
+#ifdef USE_CURSES_PAIR_0
+ if ((n < (int) TABLESIZE(lynx_color_pairs))
+ && lynx_color_pairs[n].fg == default_fg
+ && lynx_color_pairs[n].bg == default_bg)
+ return 0;
+#endif
+ return (int) COLOR_PAIR(n);
+}
+
+/*
+ * Lynx "knows" about 16 colors. ANSI colors (and most color terminal
+ * emulators) only go to 8, though some curses implementations (ncurses and
+ * PDCurses) handle 16. If lynx's configuration calls for a color past the
+ * number of colors that the terminal handles (COLORS), map the extra value
+ * to bold.
+ */
+#define is_boldc(c) ((c) > (COLORS-1))
+#define map2bold(c) (is_boldc(c) ? ((c) & (COLORS-1)) : (c))
+
+/*
+ * Return the extra color as A_BOLD.
+ * If there is no extra color, return A_NORMAL.
+ */
+static int lynx_color_cfg_attr(int code)
+{
+ int result = A_NORMAL;
+
+ if (code >= 0 && code < COLOR_CFG_MAX) {
+ int fg = lynx_color_cfg[code].fg;
+
+ if (is_boldc(fg) && (fg & COLORS))
+ result = A_BOLD;
+ }
+ return result;
+}
+
+static int encode_color_attr(int color_attr)
+{
+ int result;
+ int code = 0;
+ int offs = 1;
+
+ if ((unsigned) color_attr & A_BOLD)
+ code |= 1;
+ if ((unsigned) color_attr & (A_REVERSE | A_DIM))
+ code |= 2;
+ if ((unsigned) color_attr & A_UNDERLINE)
+ code |= 4;
+ result = lynx_color_cfg_attr(code);
+
+ if (code + offs < COLOR_PAIRS) {
+ result |= get_color_pair(code + offs);
+ }
+ return result;
+}
+
+static int decode_mono_code(int mono_code)
+{
+ unsigned result = 0;
+
+ if (mono_code & 1)
+ result |= A_BOLD;
+ if (mono_code & 2)
+ result |= A_REVERSE;
+ if (mono_code & 4)
+ result |= A_UNDERLINE;
+
+ return (int) result;
+}
+
+/*
+ * Map the SGR attributes (0-7) into ANSI colors, modified with the actual BOLD
+ * attribute to get 16 colors.
+ */
+int LYgetTableAttr(void)
+{
+ int result;
+
+ if (lynx_has_color && LYShowColor >= SHOW_COLOR_ON) {
+ result = encode_color_attr(Current_Attr);
+ } else {
+ result = Current_Attr;
+ }
+ return result & ~Masked_Attr;
+}
+
+#ifdef USE_COLOR_STYLE
+/*
+ * Return a string that corresponds to the attributes that would be returned by
+ * LYgetTableAttr().
+ */
+char *LYgetTableString(int code)
+{
+ int mask = decode_mono_code(code);
+ int second = encode_color_attr(mask);
+ int pair = PAIR_NUMBER((unsigned) second);
+ int mono = (int) ((unsigned) mask & A_ATTRIBUTES);
+ int fg = lynx_color_pairs[pair].fg;
+ int bg = lynx_color_pairs[pair].bg;
+ unsigned n;
+ char *result = 0;
+
+ CTRACE((tfp, "LYgetTableString(%d)\n", code));
+
+ if (fg == 0 && bg == 0) {
+ fg = COLOR_WHITE;
+ }
+
+ CTRACE((tfp, "%#x -> %#x (mono %#x pair %d) fg=%d, bg=%d\n",
+ (unsigned) mask,
+ (unsigned) second,
+ (unsigned) mono,
+ pair, fg, bg));
+
+ for (n = 0; n < TABLESIZE(Mono_Attrs); ++n) {
+ if ((Mono_Attrs[n].code & mono) != 0) {
+ if (result != 0)
+ StrAllocCat(result, "+");
+ StrAllocCat(result, Mono_Attrs[n].name);
+ }
+ }
+ if (result == 0)
+ StrAllocCopy(result, "normal");
+ StrAllocCat(result, ":");
+ StrAllocCat(result, lookup_color(fg));
+ if (bg >= 0) {
+ StrAllocCat(result, ":");
+ StrAllocCat(result, lookup_color(bg));
+ }
+ CTRACE((tfp, "->%s\n", result));
+ return result;
+}
+#endif
+
+/*
+ * Initialize a curses color-pair based on our configured color values.
+ */
+static void lynx_init_color_pair(int n)
+{
+#ifdef USE_COLOR_STYLE
+ (void) n; /* we only use lynx_color_pairs[] data */
+#else
+ int m;
+
+ if (lynx_called_initscr) {
+ for (m = 0; m <= 16; m += 8) {
+ int pair = n + m + 1;
+
+ if (pair < COLOR_PAIRS)
+ init_pair((short) pair,
+ (short) map2bold(lynx_color_pairs[pair].fg),
+ (short) map2bold(lynx_color_pairs[pair].bg));
+ }
+ if (n == 0 && LYShowColor >= SHOW_COLOR_ON) {
+ wbkgd(LYwin, COLOR_BKGD | ' ');
+ }
+ }
+#endif
+}
+
+static void lynx_map_color(int n)
+{
+ int j;
+
+ CTRACE((tfp, "lynx_map_color(%d)\n", n));
+
+ if (n + 1 < (int) TABLESIZE(lynx_color_pairs)
+ && n < (int) TABLESIZE(lynx_color_cfg)) {
+ for (j = n + 1; j < COLOR_PAIRS_MAX; j += COLOR_CFG_MAX) {
+ lynx_color_pairs[j].fg = lynx_color_cfg[n].fg;
+ lynx_color_pairs[j].bg = lynx_color_cfg[n].bg;
+ }
+
+ /* special case (does not apply to 3rd set) */
+ lynx_color_pairs[n + 1 + COLOR_CFG_MAX].bg = lynx_color_cfg[0].bg;
+ }
+
+ lynx_init_color_pair(n);
+}
+
+/*
+ * Change a configured color value. This may be called before initscr(), so
+ * we may not be able to call init_pair() to finish the change.
+ */
+int lynx_chg_color(int color,
+ int fg,
+ int bg)
+{
+ CTRACE((tfp, "lynx_chg_color(color=%d, fg=%d, bg=%d)\n", color, fg, bg));
+
+ if (fg == ERR_COLOR || bg == ERR_COLOR)
+ return -1;
+ if (color >= 0 && color < COLOR_CFG_MAX) {
+ lynx_color_cfg[color].fg = fg;
+ lynx_color_cfg[color].bg = bg;
+ lynx_map_color(color);
+ } else {
+ return -1;
+ }
+ return 0;
+}
+
+void lynx_set_color(int a)
+{
+ if (lynx_has_color && LYShowColor >= SHOW_COLOR_ON) {
+ (void) wattrset(LYwin, lynx_color_cfg_attr(a)
+ | (((a + 1) < COLOR_PAIRS)
+ ? get_color_pair(a + 1)
+ : (int) A_NORMAL));
+ }
+}
+
+void lynx_standout(int flag)
+{
+ if (flag)
+ LYaddAttr(A_REVERSE);
+ else
+ LYsubAttr(A_REVERSE);
+}
+
+static void lynx_init_colors(void)
+{
+ if (lynx_has_color) {
+ size_t n;
+
+ CTRACE((tfp, "lynx_init_colors (default %d/%d)\n",
+ default_fg, default_bg));
+
+ lynx_color_cfg[0].fg = default_fg;
+ lynx_color_cfg[0].bg = default_bg;
+
+ for (n = 0; n < TABLESIZE(lynx_color_cfg); n++) {
+ lynx_init_color_pair((int) n);
+ }
+ } else if (LYShowColor != SHOW_COLOR_NEVER) {
+ LYShowColor = SHOW_COLOR_OFF;
+ }
+}
+
+void lynx_setup_colors(void)
+{
+ int n;
+
+ CTRACE((tfp, "lynx_setup_colors\n"));
+#ifdef USE_DEFAULT_COLORS
+ if (!LYuse_default_colors) {
+ for (n = 0; n < COLOR_CFG_MAX; n++) {
+ if (lynx_color_cfg[n].dft_fg)
+ lynx_color_cfg[n].fg = COLOR_BLACK;
+ if (lynx_color_cfg[n].dft_bg)
+ lynx_color_cfg[n].bg = COLOR_WHITE;
+ }
+ }
+#endif
+ for (n = 0; n < COLOR_CFG_MAX; n++)
+ lynx_map_color(n);
+}
+#endif /* USE_COLOR_TABLE */
+
+void LYnoVideo(int a)
+{
+ CTRACE((tfp, "LYnoVideo(%d)\n", a));
+#ifdef USE_SLANG
+ if (a & 1)
+ Masked_Attr |= (int) SLTT_BOLD_MASK;
+ if (a & 2)
+ Masked_Attr |= (int) SLTT_REV_MASK;
+ if (a & 4)
+ Masked_Attr |= (int) SLTT_ULINE_MASK;
+ lynx_setup_attrs();
+#else
+#ifdef USE_COLOR_TABLE
+ Masked_Attr = decode_mono_code(a);
+#endif
+#endif
+}
+
+#define NEWTERM_NAME "newterm"
+
+#ifndef USE_SLANG
+static WINDOW *my_subwindow;
+
+#define delete_subwindow() if (my_subwindow) { delwin(my_subwindow); my_subwindow = NULL; }
+#endif
+
+#ifdef WIDEC_CURSES
+static WINDOW *fake_win;
+static int fake_max;
+
+#define delete_fake_win() if (fake_win) { delwin(fake_win); fake_win = NULL; fake_max = 0; }
+#else
+#define delete_fake_win() /* nothing */
+#endif
+
+#if !defined(VMS) && !defined(USE_SLANG)
+#if defined(NCURSES) && defined(HAVE_RESIZETERM)
+
+static SCREEN *LYscreen = NULL;
+
+static void delete_screen(SCREEN * screen)
+{
+ delete_fake_win();
+ delete_subwindow();
+ delscreen(screen);
+}
+
+#define LYDELSCR() /* ncurses does not need this */
+
+#elif defined(HAVE_NEWTERM) && defined(HAVE_DELSCREEN)
+
+static SCREEN *LYscreen = NULL;
+
+#if defined(USE_DEFAULT_COLORS)
+static void delete_screen(SCREEN * screen)
+{
+ delete_fake_win();
+ delete_subwindow();
+ delscreen(screen);
+}
+#endif
+
+#define LYDELSCR() { \
+if (recent_sizechange) { \
+ CTRACE((tfp, "Screen size: delscreen()\n")); \
+ delete_screen(LYscreen); \
+ LYscreen = NULL; } }
+
+#else /* HAVE_NEWTERM */
+
+ /*
+ * If newterm is not defined, assume a curses subset which
+ * supports only initscr. --gil
+ */
+static WINDOW *LYscreen = NULL;
+
+#undef NEWTERM_NAME
+#define NEWTERM_NAME "initscr"
+#undef newterm
+#define newterm(type, out, in) (initscr())
+#define LYDELSCR() /* nothing */
+#endif /* HAVE_NEWTERM */
+
+#else /* !defined(VMS) && !defined(USE_SLANG) */
+
+ /*
+ * Provide last recourse definitions of LYscreen and LYDELSCR for
+ * stop_curses, which only tests LYscreen for zero/nonzero but
+ * never uses it as a pointer or L-value.
+ */
+#define LYscreen TRUE
+#define LYDELSCR() /* nothing */
+#endif /* !defined(VMS) && !defined(USE_SLANG) */
+
+#if defined(PDCURSES) && defined(PDC_BUILD) && PDC_BUILD >= 2401
+int saved_scrsize_x = 0;
+int saved_scrsize_y = 0;
+
+int saved_scrsize_x2 = 0;
+int saved_scrsize_y2 = 0;
+int saved_winpos_x2 = 0;
+int saved_winpos_y2 = 0;
+
+static int LYresize_term(int nlines, int ncols)
+{
+#ifdef _WINDOWS
+ HANDLE hConsole;
+ CONSOLE_SCREEN_BUFFER_INFO csbi;
+ SMALL_RECT srWindowRect;
+
+ hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
+ GetConsoleScreenBufferInfo(hConsole, &csbi);
+ srWindowRect.Right = min(ncols, csbi.dwSize.X) - 1;
+ srWindowRect.Bottom = min(nlines, csbi.dwSize.Y) - 1;
+ srWindowRect.Left = srWindowRect.Top = (SHORT) 0;
+ SetConsoleWindowInfo(hConsole, TRUE, &srWindowRect);
+#endif
+ return resize_term(nlines, ncols);
+}
+#endif
+
+#ifdef USE_MAXSCREEN_TOGGLE
+static HWND currentWindowHandle = NULL;
+static char dummyWindowTitle[256];
+
+static int CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
+{
+ char this_title[256];
+
+ (void) lParam;
+ if (GetWindowText(hwnd, this_title, sizeof(this_title) - 1) &&
+ (strncmp(dummyWindowTitle, this_title, 256) == 0)) {
+ currentWindowHandle = hwnd;
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static void setCurrentWindowHandle(void)
+{
+ char org_title[256];
+ DWORD pid;
+ int i;
+
+ if (currentWindowHandle != NULL) {
+ return;
+ }
+ pid = GetCurrentProcessId();
+ sprintf(dummyWindowTitle, "Lynx for Win32 (pid=%ld)", pid);
+ GetConsoleTitle(org_title, sizeof(org_title) - 1);
+ SetConsoleTitle(dummyWindowTitle);
+ for (i = 0; i < 10; i++) {
+ EnumWindows(EnumWindowsProc, (LPARAM) 0);
+ if (currentWindowHandle != NULL) {
+ break;
+ }
+ CTRACE((tfp,
+ "Failed to get current window handle. Try again...(%d)\n", i));
+ Sleep(100);
+ }
+ SetConsoleTitle(org_title);
+}
+
+static void moveWindowHXY(HWND hwnd, int x, int y)
+{
+ int win_height, win_width;
+ RECT winrect;
+
+ GetWindowRect(hwnd, &winrect);
+ win_width = winrect.right - winrect.left;
+ win_height = winrect.bottom - winrect.top;
+
+ if ((x != winrect.left) || (y != winrect.top)) {
+ MoveWindow(hwnd, x, y, win_width, win_height, TRUE);
+ CTRACE((tfp, "move window from (%d,%d) to (%d,%d).\n",
+ (int) winrect.left,
+ (int) winrect.top, x, y));
+ }
+}
+
+static void adjustWindowPos(void)
+{
+ int disp_height, disp_width, win_height, win_width;
+ int newwin_left, newwin_top;
+ RECT winrect;
+ DWORD pid;
+
+ setCurrentWindowHandle();
+ if (currentWindowHandle == NULL) {
+ return;
+ }
+ GetWindowThreadProcessId(currentWindowHandle, &pid);
+ disp_width = GetSystemMetrics(SM_CXFULLSCREEN);
+ disp_height = GetSystemMetrics(SM_CYFULLSCREEN);
+ Sleep(100); /* If not, GetWindowRect sometimes return wrong value. */
+ GetWindowRect(currentWindowHandle, &winrect);
+ win_width = winrect.right - winrect.left;
+ win_height = winrect.bottom - winrect.top;
+ CTRACE((tfp, "Display Size: (%4d,%3d)\n", disp_width, disp_height));
+ CTRACE((tfp, "Orig WinRect: (%4d,%4d,%3d,%3d), ",
+ (int) winrect.left, (int) winrect.right,
+ (int) winrect.top, (int) winrect.bottom));
+ CTRACE((tfp, "Size: (%4d,%3d)\n", win_width, win_height));
+
+ newwin_left = winrect.left;
+ newwin_top = winrect.top;
+ if (disp_width < winrect.right) {
+ if (win_width <= disp_width) {
+ newwin_left = disp_width - win_width;
+ } else {
+ newwin_left = 0;
+ }
+ }
+ if (disp_height < winrect.bottom) {
+ if (win_height <= disp_height) {
+ newwin_top = disp_height - win_height;
+ } else {
+ newwin_top = 0;
+ }
+ }
+
+ moveWindowHXY(currentWindowHandle, newwin_left, newwin_top);
+}
+
+void maxmizeWindowSize(void)
+{
+ RECT winrect;
+ HANDLE hConsole;
+ COORD coordScreen;
+
+ setCurrentWindowHandle();
+ if (currentWindowHandle == NULL) {
+ return;
+ }
+ GetWindowRect(currentWindowHandle, &winrect);
+ saved_winpos_x2 = winrect.left;
+ saved_winpos_y2 = winrect.top;
+
+ hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
+ coordScreen = GetLargestConsoleWindowSize(hConsole);
+
+ LYcols = scrsize_x = coordScreen.X - 1;
+ LYlines = scrsize_y = coordScreen.Y - 1;
+ LYlines--;
+ CTRACE((tfp, "Request maximum screen size: %dx%d\n",
+ scrsize_x, scrsize_y));
+ LYresize_term(scrsize_y, scrsize_x);
+ Sleep(100);
+ moveWindowHXY(currentWindowHandle, 0, 0);
+ LYlines = LYscreenHeight();
+ LYcols = LYscreenWidth();
+ CTRACE((tfp, "...actual maximum screen size: %dx%d\n",
+ LYcols, LYlines));
+ LYStatusLine = -1;
+ recent_sizechange = TRUE;
+}
+
+void recoverWindowSize(void)
+{
+ if ((0 < saved_scrsize_x2) && (0 < saved_scrsize_y2)) {
+ LYcols = scrsize_x = saved_scrsize_x2;
+ LYlines = scrsize_y = saved_scrsize_y2;
+ LYlines--;
+ LYStatusLine = -1;
+ wclear(curscr);
+ doupdate();
+ LYresize_term(scrsize_y, scrsize_x);
+
+ setCurrentWindowHandle();
+ if (currentWindowHandle != NULL) {
+ Sleep(100);
+ moveWindowHXY(currentWindowHandle, saved_winpos_x2, saved_winpos_y2);
+ }
+ recent_sizechange = TRUE;
+ } else {
+ CTRACE((tfp, "scrsize_{xy} is not saved yet.\n"));
+ }
+}
+#endif
+
+#if defined(USE_DEFAULT_COLORS)
+void restart_curses(void)
+{
+ SCREEN *oldscreen = LYscreen;
+
+ if (!(LYscreen = newterm(NULL, stdout, stdin))) { /* start curses */
+ fprintf(tfp, "%s\n",
+ gettext("Terminal reinitialisation failed - unknown terminal type?"));
+ exit_immediately(EXIT_FAILURE);
+ }
+
+ /* force xterm mouse-mode off in the physical terminal */
+ lynx_enable_mouse(0);
+ keypad(LYwin, FALSE);
+ wrefresh(LYwin);
+
+ LYwin = stdscr;
+ /* re-enable xterm mouse-mode in the new screen */
+ keypad(LYwin, TRUE);
+ lynx_enable_mouse(1);
+
+#if defined(USE_KEYMAPS)
+ if (-1 == lynx_initialize_keymaps()) {
+ endwin();
+ exit_immediately(EXIT_FAILURE);
+ }
+#endif
+ if (has_colors()) {
+ start_color();
+ }
+
+ delete_screen(oldscreen);
+}
+#endif
+
+void start_curses(void)
+{
+#ifdef USE_SLANG
+ static int slinit;
+
+ if (LYCursesON) {
+ CTRACE((tfp, "start_curses: Hmm, already ON.\n"));
+ return;
+ }
+
+ if (slinit == 0) {
+#if defined(HAVE_TTYNAME)
+ if (isatty(fileno(stdout)) && LYReopenInput() < 0) {
+ fprintf(stderr, "Cannot open tty input\n");
+ exit_immediately(EXIT_FAILURE);
+ }
+#endif
+#if defined(USE_KEYMAPS)
+ if (-1 == lynx_initialize_keymaps())
+ exit_immediately(EXIT_FAILURE);
+#else
+ SLtt_get_terminfo();
+#endif
+#if (defined(__DJGPP__) && !defined(DJGPP_KEYHANDLER)) || defined(__CYGWIN__)
+ SLkp_init();
+#endif /* __DJGPP__ && !DJGPP_KEYHANDLER */
+
+#if defined(REAL_UNIX_SYSTEM) && !defined(__CYGWIN__)
+#if SLANG_VERSION >= 9935
+ SLang_TT_Read_FD = fileno(stdin);
+#endif /* SLANG_VERSION >= 9935 */
+#endif /* REAL_UNIX_SYSTEM && !__CYGWIN__ */
+
+#if !defined(USE_KEYMAPS) && defined(ENHANCED_LINEEDIT) && defined(ESCDELAY)
+ /* way to get ESC that's not part of a recognized sequence through */
+ ESCDELAY = 2000;
+#endif
+ /*
+ * Check whether a saved show_color:off override is in effect. - kw
+ */
+ if (LYrcShowColor == SHOW_COLOR_NEVER) {
+ SLtt_Use_Ansi_Colors = 0;
+ }
+ /*
+ * Check whether we're forcing color on. - FM
+ */
+ if ((LYShowColor > 1) && (Lynx_Color_Flags & SL_LYNX_USE_COLOR))
+ SLtt_Use_Ansi_Colors = 1;
+ /*
+ * Check whether a -nocolor override is in effect. - kw
+ */
+ if (Lynx_Color_Flags & SL_LYNX_OVERRIDE_COLOR)
+ SLtt_Use_Ansi_Colors = 0;
+ /*
+ * Make sure our flags are in register. - FM
+ */
+ if (SLtt_Use_Ansi_Colors == 1) {
+ if (LYShowColor != SHOW_COLOR_ALWAYS) {
+ LYShowColor = SHOW_COLOR_ON;
+ }
+ } else {
+ if (LYShowColor != SHOW_COLOR_NEVER) {
+ LYShowColor = SHOW_COLOR_OFF;
+ }
+ }
+ size_change(0);
+
+#if (defined(VMS) || defined(REAL_UNIX_SYSTEM)) && !defined(__CYGWIN__)
+ if ((Masked_Attr & (int) SLTT_ULINE_MASK) == 0) {
+ SLtt_add_color_attribute(4, SLTT_ULINE_MASK);
+ SLtt_add_color_attribute(5, SLTT_ULINE_MASK);
+ }
+ /*
+ * If set, the blink escape sequence will turn on high intensity
+ * background (rxvt and maybe Linux console).
+ */
+ SLtt_Blink_Mode = term_blink_is_boldbg;
+#endif /* (VMS || REAL_UNIX_SYSTEM) && !__CYGWIN__ */
+ }
+#ifdef __DJGPP__
+ _eth_init();
+#endif /* __DJGPP__ */
+
+ slinit = 1;
+ Current_Attr = 0;
+#ifndef VMS
+#if SLANG_VERSION > 9929
+ SLang_init_tty(-1, 0, 1);
+#else
+ SLang_init_tty(3, 0, 1);
+#endif /* SLANG_VERSION > 9929 */
+#endif /* !VMS */
+ SLsmg_init_smg();
+ SLsmg_Display_Eight_Bit = LYlowest_eightbit[current_char_set];
+ if (SLsmg_Display_Eight_Bit > 191)
+ SLsmg_Display_Eight_Bit = 191; /* may print ctrl chars otherwise - kw */
+ scrollok(0, 0);
+ SLsmg_Backspace_Moves = 1;
+#if SLANG_VERSION > 10306
+ SLsmg_touch_screen();
+#endif
+#ifndef VMS
+#if defined(REAL_UNIX_SYSTEM) && !defined(__CYGWIN__)
+ SLtty_set_suspend_state(1);
+#endif /* REAL_UNIX_SYSTEM && !__CYGWIN__ */
+#ifdef SIGTSTP
+ if (!no_suspend)
+ signal(SIGTSTP, sl_suspend);
+#endif /* SIGTSTP */
+ signal(SIGINT, cleanup_sig);
+#endif /* !VMS */
+
+ lynx_enable_mouse(1);
+
+#else /* USE_SLANG; Now using curses: */
+ int keypad_on = 0;
+
+#ifdef VMS
+ /*
+ * If we are VMS then do initscr() every time start_curses() is called!
+ */
+ CTRACE((tfp, "Screen size: initscr()\n"));
+ initscr(); /* start curses */
+#else /* Unix: */
+
+#if defined(HAVE_TTYNAME)
+ if (isatty(fileno(stdout)) && LYReopenInput() < 0) {
+ fprintf(stderr, "Cannot open tty input\n");
+ exit_immediately(EXIT_FAILURE);
+ }
+#endif
+
+#ifdef __CYGWIN__
+ /*
+ * Workaround for buggy Cygwin, which breaks subprocesses of a
+ * full-screen application (tested with cygwin dll, dated
+ * 2002/6/23 -TD)
+ */
+ if (!lynx_called_initscr) {
+ FILE *fp = fopen("/dev/tty", "w");
+
+ if (fp != 0)
+ stdout = fp;
+ }
+#endif
+
+ if (!LYscreen) {
+ /*
+ * If we're not VMS then only do initscr() one time, and one time only!
+ */
+#if defined(HAVE_NEWTERM)
+#if !(defined(NCURSES) && !defined(HAVE_RESIZETERM))
+ BOOLEAN savesize;
+
+ savesize = recent_sizechange;
+ size_change(0);
+ recent_sizechange = savesize; /* avoid extra redraw */
+#if defined(__MVS__)
+ {
+ /*
+ * The requirement to do this may be a bug in OS/390.
+ *
+ * Put screen geometry in environment variables used by
+ * XOpen curses before calling newterm(). I believe this
+ * completes work left unfinished by AJL & FM -- gil
+ */
+ static char lines_putenv[] = "LINES=abcde", cols_putenv[] = "COLUMNS=abcde";
+
+ sprintf(lines_putenv + 6, "%d", LYlines & 0xfff);
+ sprintf(cols_putenv + 8, "%d", LYcols & 0xfff);
+ putenv(lines_putenv);
+ putenv(cols_putenv);
+ CTRACE((tfp, "start_curses putenv %s, %s\n", lines_putenv, cols_putenv));
+ }
+#endif /* defined(__MVS__) */
+#endif /* !(defined(NCURSES) && defined(HAVE_RESIZETERM)) */
+ CTRACE((tfp, "Screen size: %s()\n", NEWTERM_NAME));
+ if (!(LYscreen = newterm(NULL, stdout, stdin))) { /* start curses */
+ fprintf(tfp, "%s\n",
+ gettext("Terminal initialisation failed - unknown terminal type?"));
+ exit_immediately(EXIT_FAILURE);
+ }
+#else
+ CTRACE((tfp, "Screen size: initscr()\n"));
+ initscr();
+#endif /* HAVE_NEWTERM */
+ lynx_called_initscr = TRUE;
+ LYlines = LYscreenHeight();
+ LYcols = LYscreenWidth();
+
+#if defined(SIGWINCH) && defined(NCURSES_VERSION)
+ size_change(0);
+ recent_sizechange = FALSE; /* prevent mainloop drawing 1st doc twice */
+#endif /* SIGWINCH */
+ CTRACE((tfp, "Screen size is now %d x %d\n", LYcols, LYlines));
+
+#ifdef USE_CURSES_PADS
+ if (LYuseCursesPads) {
+ CTRACE((tfp, "using curses-pads\n"));
+ LYwin = newpad(LYlines, MAX_COLS);
+ LYshiftWin = 0;
+ LYwideLines = FALSE;
+ } else {
+ LYwin = stdscr;
+ }
+#endif
+
+#if defined(USE_KEYMAPS) && defined(NCURSES_VERSION)
+# ifdef HAVE_KEYPAD
+ /* Need to switch keypad on before initializing keymaps, otherwise
+ when the keypad is switched on, some keybindings may be overridden. */
+ keypad(LYwin, TRUE);
+ keypad_on = 1;
+# endif /* HAVE_KEYPAD */
+
+ if (-1 == lynx_initialize_keymaps()) {
+ endwin();
+ exit_immediately(EXIT_FAILURE);
+ }
+#endif /* ncurses-keymaps */
+
+ /*
+ * This is a workaround for a bug in SVr4 curses, observed on Solaris
+ * 2.4: if your terminal's alternate-character set contains codes in
+ * the range 128-255, they'll be sign-extended in the acs_map[] table,
+ * which in turn causes their values to be emitted as 255 (0xff).
+ * "Fix" this by forcing the table to 8-bit codes (it has to be
+ * anyway).
+ */
+#if defined(ALT_CHAR_SET) && !defined(NCURSES_VERSION)
+ {
+ int n;
+
+ for (n = 0; n < 128; n++)
+ if (ALT_CHAR_SET[n] & 0x80) {
+ ALT_CHAR_SET[n] &= 0xff;
+ ALT_CHAR_SET[n] |= A_ALTCHARSET;
+ }
+ }
+#endif
+
+#if defined(USE_COLOR_STYLE) || defined(USE_COLOR_TABLE)
+ if (has_colors()) {
+ lynx_has_color = TRUE;
+ start_color();
+
+#ifndef COLORS
+ /* map2boldc() relies on COLORS being a power of 2 */
+ if (COLORS > 16)
+ COLORS = 16;
+ if (COLORS < 8)
+ COLORS = 2;
+ if (COLORS > 8 && COLORS != 16)
+ COLORS = 8;
+#endif
+
+#ifdef USE_DEFAULT_COLORS
+ update_default_colors();
+ if (LYuse_default_colors) {
+#if defined(EXP_ASSUMED_COLOR) && defined(USE_COLOR_TABLE)
+ /*
+ * Adjust the color mapping table to match the ASSUMED_COLOR
+ * setting in lynx.cfg
+ */
+ if (assume_default_colors(default_fg, default_bg) != OK) {
+ default_fg = COLOR_WHITE;
+ default_bg = COLOR_BLACK;
+ }
+ CTRACE((tfp, "initializing default colors %d/%d\n",
+ default_fg, default_bg));
+ if (default_fg >= 0 || default_bg >= 0) {
+ unsigned n;
+
+ for (n = 0; n < TABLESIZE(lynx_color_cfg); n++) {
+ if (default_fg >= 0 && lynx_color_cfg[n].fg < 0)
+ lynx_color_cfg[n].fg = default_fg;
+ if (default_bg >= 0 && lynx_color_cfg[n].bg < 0)
+ lynx_color_cfg[n].bg = default_bg;
+ CTRACE((tfp, "color_cfg[%u] = %d/%d\n", n,
+ lynx_color_cfg[n].fg,
+ lynx_color_cfg[n].bg));
+ }
+ lynx_setup_colors();
+ }
+#else
+#if defined(HAVE_USE_DEFAULT_COLORS)
+ if (!default_color_reset) {
+ if (lynx_called_initscr) {
+ if (LYuse_default_colors && (use_default_colors() == OK)) {
+ default_fg = DEFAULT_COLOR;
+ default_bg = DEFAULT_COLOR;
+ } else {
+ default_fg = COLOR_WHITE;
+ default_bg = COLOR_BLACK;
+ default_color_reset = TRUE;
+ }
+ }
+ }
+#endif /* HAVE_USE_DEFAULT_COLORS */
+#endif /* EXP_ASSUMED_COLOR */
+ }
+#endif /* USE_DEFAULT_COLORS */
+ }
+#endif /* USE_COLOR_STYLE || USE_COLOR_TABLE */
+
+#ifdef USE_COLOR_STYLE
+ /* Curses forgets color settings when we call delscreen() */
+ if (non_empty(lynx_lss_file) && LYCanReadFile(lynx_lss_file)) {
+ style_readFromFile(lynx_lss_file);
+ }
+ parse_userstyles();
+#endif
+#ifdef USE_COLOR_TABLE
+ lynx_init_colors();
+#endif
+ }
+#ifdef __DJGPP__
+ _eth_init();
+#endif /* __DJGPP__ */
+#endif /* not VMS */
+
+#ifdef VMS
+ crmode();
+ raw();
+#else
+#ifdef HAVE_CBREAK
+ cbreak();
+#else
+ crmode();
+#endif /* HAVE_CBREAK */
+ signal(SIGINT, cleanup_sig);
+#endif /* VMS */
+
+ noecho();
+
+#ifdef HAVE_KEYPAD
+ if (!keypad_on)
+ keypad(LYwin, TRUE);
+#endif /* HAVE_KEYPAD */
+
+ lynx_enable_mouse(1);
+
+ fflush(stdin);
+ fflush(stdout);
+ fflush(stderr);
+#endif /* USE_SLANG */
+
+#if defined(WIN_EX)
+ LYclear();
+#endif
+
+#if defined(USE_BLINK) && defined(__EMX__)
+ if (term_blink_is_boldbg) /* Now actually make it so! */
+ make_blink_boldbg();
+#endif
+
+ LYCursesON = TRUE;
+#if defined(PDCURSES) && defined(PDC_BUILD) && PDC_BUILD >= 2401
+ if ((scrsize_x != 0) && (scrsize_y != 0)) {
+ if (saved_scrsize_x == 0) {
+ saved_scrsize_x = COLS;
+ saved_scrsize_y = LINES + 1;
+ }
+ CTRACE((tfp, "resize_term: x=%d, y=%d\n", scrsize_x, scrsize_y));
+ CTRACE((tfp, "saved terminal size: x=%d, y=%d\n", saved_scrsize_x, saved_scrsize_y));
+ LYresize_term(scrsize_y, scrsize_x);
+ LYlines = LYscreenHeight();
+ LYcols = LYscreenWidth();
+ LYStatusLine = -1;
+ LYclear();
+#ifdef _WINDOWS
+ adjustWindowPos();
+#endif
+ }
+ if (saved_scrsize_x2 == 0) {
+ if (saved_scrsize_x == 0) {
+ saved_scrsize_x2 = COLS;
+ saved_scrsize_y2 = LINES + 1;
+ } else {
+ saved_scrsize_x2 = scrsize_x;
+ saved_scrsize_y2 = scrsize_y;
+ }
+ }
+#endif
+ CTRACE((tfp, "start_curses: done.\n"));
+} /* end of start_curses() */
+
+void lynx_enable_mouse(int state)
+{
+#ifdef USE_MOUSE
+/***********************************************************************/
+
+#if defined(WIN_EX)
+/* modify lynx_enable_mouse() for pdcurses configuration so that mouse support
+ is disabled unless -use_mouse is specified
+*/
+ HANDLE hConIn = INVALID_HANDLE_VALUE;
+
+ hConIn = GetStdHandle(STD_INPUT_HANDLE);
+ if (LYUseMouse == 0) {
+ SetConsoleMode(hConIn, ENABLE_WINDOW_INPUT);
+ FlushConsoleInputBuffer(hConIn);
+ return;
+ }
+#endif
+
+ (void) state;
+
+ if (LYUseMouse == 0)
+ return;
+
+#if defined(USE_SLANG)
+ SLtt_set_mouse_mode(state, 0);
+ SLtt_flush_output();
+#else
+
+#if defined(WIN_EX) && defined(PDCURSES)
+ if (state) {
+ SetConsoleMode(hConIn, ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT);
+ FlushConsoleInputBuffer(hConIn);
+ }
+#else
+#if defined(NCURSES)
+ if (state) {
+ /* Compensate for small value of maxclick in ncurses. */
+ static int was = 0;
+
+ if (!was) {
+ int old = mouseinterval(-1);
+
+ was++;
+ if (old < 200) /* Default 166 */
+ mouseinterval(300);
+ }
+ /* Inform ncurses which mouse events we're interested in.
+ * We shouldn't need to include BUTTONn_PRESSED and BUTTONn_RELEASED
+ * events, since ncurses should translate them to click events. - kw
+ * However, if we do not include them, then ncurses effectively
+ * ignores mouseinterval(), thus translates *any* sequence of
+ * press/release to a click, which leads to inconveniences.
+ * We special-case these events in LYStrings.c.
+ */
+ mousemask(BUTTON_CTRL | BUTTON_ALT
+ | BUTTON1_PRESSED | BUTTON1_RELEASED
+ | BUTTON1_CLICKED
+ | BUTTON1_DOUBLE_CLICKED | BUTTON1_TRIPLE_CLICKED
+ | BUTTON2_PRESSED | BUTTON2_RELEASED
+ | BUTTON2_CLICKED
+ | BUTTON3_PRESSED | BUTTON3_RELEASED
+ | BUTTON3_CLICKED
+ | BUTTON3_DOUBLE_CLICKED | BUTTON3_TRIPLE_CLICKED
+#if NCURSES_MOUSE_VERSION >= 2
+ | BUTTON4_PRESSED | BUTTON4_RELEASED
+ | BUTTON4_CLICKED
+ | BUTTON4_DOUBLE_CLICKED | BUTTON4_TRIPLE_CLICKED
+ | BUTTON5_PRESSED | BUTTON5_RELEASED
+ | BUTTON5_CLICKED
+ | BUTTON5_DOUBLE_CLICKED | BUTTON5_TRIPLE_CLICKED
+#endif
+ ,NULL);
+ } else
+ mousemask(0, NULL);
+#endif /* NCURSES */
+#endif /* WIN_EX and PDCURSES */
+
+#if defined(PDCURSES)
+ if (state)
+ mouse_set(
+ BUTTON1_CLICKED | BUTTON1_PRESSED | BUTTON1_RELEASED |
+ BUTTON2_CLICKED | BUTTON2_PRESSED | BUTTON2_RELEASED |
+ BUTTON3_CLICKED | BUTTON3_PRESSED | BUTTON3_RELEASED);
+#endif
+#endif /* NOT USE_SLANG */
+
+/***********************************************************************/
+#endif /* USE_MOUSE */
+}
+
+/*
+ * SVr4 curses (and ncurses) initialize the terminal I/O to raw mode, and
+ * simulate other modes in the library. This means that when running, it
+ * simulates the OCRNL setting. Normally that is not a problem. However, when
+ * spawning a subprocess (e.g., xli), the subprocess may write to the screen.
+ * Fine so far - curses resets the terminal I/O to the normal state on exit.
+ * But the subprocess's messages can still be coming to the screen when lynx
+ * returns to the screen mode. This function delays restoring OCRNL until
+ * after the first getch() call.
+ *
+ * The OCRNL setting is controlled by nl()/nonl() of course - but we do not
+ * want to give up that optimization since it would be a bit slower. (Note -
+ * slang does not use this optimization; if it did, the same screen glitch
+ * would occur).
+ *
+ * FIXME: for simplicity, only ncurses is implemented here - the TTY and
+ * SET_TTY definitions are ncurses-specific. The same effect could be done for
+ * other curses implementations, since the "cur_term->Nttyb" part is common to
+ * SVr4 curses.
+ */
+void lynx_nl2crlf(int normal GCC_UNUSED)
+{
+#if defined(NCURSES_VERSION_PATCH) && defined(SET_TTY) && defined(TERMIOS) && defined(ONLCR)
+ static struct termios saved_tty;
+ static int did_save = FALSE;
+ static int waiting = FALSE;
+ static int can_fix = TRUE;
+
+ if (!did_save) {
+ if (cur_term == 0) {
+ can_fix = FALSE;
+ } else {
+ tcgetattr(fileno(stdout), &saved_tty);
+ did_save = TRUE;
+ if ((saved_tty.c_oflag & ONLCR))
+ can_fix = FALSE;
+#if NCURSES_VERSION_PATCH < 20010529
+ /* workaround for optimizer bug with nonl() */
+ if ((tigetstr("cud1") != 0 && *tigetstr("cud1") == '\n')
+ || (tigetstr("ind") != 0 && *tigetstr("ind") == '\n'))
+ can_fix = FALSE;
+#endif
+ }
+ }
+ if (can_fix) {
+ if (normal) {
+ if (!waiting) {
+ struct termios alter_tty = saved_tty;
+
+ alter_tty.c_oflag |= ONLCR;
+ tcsetattr(fileno(stdout), TCSAFLUSH, &alter_tty);
+ def_prog_mode();
+ waiting = TRUE;
+ nonl();
+ }
+ } else {
+ if (waiting) {
+ tcsetattr(fileno(stdout), TCSAFLUSH, &saved_tty);
+ def_prog_mode();
+ waiting = FALSE;
+ nl();
+ LYrefresh();
+ }
+ }
+ }
+#endif
+}
+
+void stop_curses(void)
+{
+ if (LYCursesON) {
+#ifdef USE_COLOR_STYLE
+ FreeCachedStyles();
+#endif
+ echo();
+ }
+#if defined(PDCURSES) && defined(PDC_BUILD) && PDC_BUILD >= 2401
+ resetty();
+#endif
+
+#ifdef __DJGPP__
+ _eth_release();
+#endif /* __DJGPP__ */
+
+/* ifdef's for non-Unix curses or slang */
+#if defined(__MINGW32__)
+ {
+ chtype bb;
+
+ bb = getbkgd(stdscr);
+ bkgdset(0);
+ clear();
+ refresh();
+ bkgdset(bb);
+ }
+#if defined(PDCURSES)
+ endwin();
+#endif /* PDCURSES */
+
+#elif defined(DOSPATH) && !(defined(USE_SLANG) || defined(_WIN_CC))
+
+#if defined(PDCURSES)
+ endwin();
+#endif /* PDCURSES */
+
+#ifdef __DJGPP__
+ ScreenClear();
+#elif !defined(PDCURSES) /* some flavor of win32? */
+ clrscr();
+#endif /* win32 */
+
+#else /* Unix, etc */
+
+ if (LYCursesON == TRUE) {
+ lynx_nl2crlf(TRUE);
+ lynx_enable_mouse(0);
+ if (LYscreen || lynx_called_initscr) {
+ endwin(); /* stop curses */
+ LYDELSCR();
+ }
+ } else {
+#ifdef SH_EX
+ int i;
+
+ for (i = 0; i <= 3; i++) {
+ printf("\r\n");
+ }
+#endif
+ }
+
+ fflush(stdout);
+#endif /* ifdef's for non-Unix curses or slang */
+ fflush(stderr);
+
+ LYCursesON = FALSE;
+ CTRACE((tfp, "stop_curses: done.\n"));
+
+#if defined(SIGTSTP) && defined(USE_SLANG)
+#ifndef VMS
+ if (!no_suspend)
+ signal(SIGTSTP, SIG_DFL);
+#endif /* !VMS */
+#endif /* SIGTSTP && USE_SLANG */
+
+#ifndef VMS
+ signal(SIGINT, SIG_DFL);
+#endif /* !VMS */
+}
+
+#ifdef VMS
+
+#ifdef USE_SLANG
+extern void longname(char *, char *);
+#endif /* USE_SLANG */
+
+/*
+ * Check terminal type, start curses & setup terminal.
+ */
+BOOLEAN setup(char *terminal)
+{
+ int c;
+ int status;
+ char *dummy = 0, *cp, term[81];
+
+ /*
+ * If the display was not set by a command line option then see if it is
+ * available from the environment.
+ */
+ if ((cp = LYgetXDisplay()) != 0) {
+ StrAllocCopy(x_display, cp);
+ } else {
+ FREE(x_display);
+ }
+
+ /*
+ * Get terminal type, and convert to lower case.
+ */
+ term[0] = '\0';
+ longname(dummy, term);
+ if (term[0] == '\0' &&
+ (non_empty(form_get_data) ||
+ non_empty(form_post_data))) {
+ /*
+ * Some yoyo used these under conditions which require -dump, so force
+ * that mode here. - FM
+ */
+ dump_output_immediately = TRUE;
+ LYcols = DFT_COLS;
+ if (keypad_mode == NUMBERS_AS_ARROWS)
+ keypad_mode = LINKS_ARE_NUMBERED;
+ status = mainloop();
+ exit_immediately(status);
+ }
+ LYLowerCase(term);
+
+ printf("%s%s\n", gettext("Terminal ="), term);
+ if ((strlen(term) < 5) ||
+ StrNCmp(term, "vt", 2) || !isdigit(term[2])) {
+ printf("%s\n",
+ gettext("You must use a vt100, 200, etc. terminal with this program."));
+ printf(CONFIRM_PROCEED, "n/y");
+ c = getchar();
+ if (c != 'y' && c != 'Y') {
+ printf("\n");
+ return (FALSE);
+ }
+ strcpy(term, "vt100");
+ }
+
+ ttopen();
+ start_curses();
+
+ LYlines = LYscreenHeight();
+ LYcols = LYscreenWidth();
+
+ return (TRUE);
+}
+
+#else /* Not VMS: */
+
+/*
+ * Check terminal type, start curses & setup terminal.
+ */
+BOOLEAN setup(char *terminal)
+{
+ char *term_putenv = NULL;
+ char *buffer = NULL;
+ char *cp;
+
+ /*
+ * If the display was not set by a command line option then see if it is
+ * available from the environment .
+ */
+ if ((cp = LYgetXDisplay()) != NULL) {
+ StrAllocCopy(x_display, cp);
+ } else {
+ FREE(x_display);
+ }
+
+ if (terminal != NULL) {
+ HTSprintf0(&term_putenv, "TERM=%.106s", terminal);
+ (void) putenv(term_putenv);
+ }
+
+ /*
+ * Query the terminal type.
+ */
+ if (dumbterm(LYGetEnv("TERM"))) {
+ printf("\n\n %s\n\n", gettext("Your Terminal type is unknown!"));
+ printf(" %s [vt100] ", gettext("Enter a terminal type:"));
+
+ if (LYSafeGets(&buffer, stdin) != 0) {
+ LYTrimLeading(buffer);
+ LYTrimTrailing(buffer);
+ }
+
+ if (isEmpty(buffer))
+ StrAllocCopy(buffer, "vt100");
+
+ HTSprintf0(&term_putenv, "TERM=%.106s", buffer);
+ FREE(buffer);
+
+ (void) putenv(term_putenv);
+ printf("\n%s %s\n", gettext("TERMINAL TYPE IS SET TO"),
+ LYGetEnv("TERM"));
+ LYSleepMsg();
+ }
+
+ start_curses();
+
+#ifdef HAVE_TTYTYPE
+ /*
+ * Account for lossage on the 'sun' terminal type (80x24) Sun text console
+ * driver. It only supports reverse video, but all SGR sequences produce
+ * that same reverse video, and the terminfo entry lists different SGRs for
+ * 'bold' and 'rev'. As a result, the current link is indistinguishable
+ * from all other links. The workaround here is to disable the 'rev'
+ * capability.
+ */
+ if ((StrNCmp((const char *) ttytype, "sun", 3) == 0)) {
+ LYnoVideo(2);
+ }
+#endif /* HAVE_TTYTYPE */
+
+ LYlines = LYscreenHeight();
+ LYcols = LYscreenWidth();
+
+ return (1);
+}
+
+static int dumbterm(char *terminal)
+{
+ int dumb = FALSE;
+
+ /*
+ * Began checking for terminal == NULL in case that TERM environment
+ * variable is not set. Thanks to Dick Wesseling (ftu@fi.ruu.nl).
+ */
+ if (terminal == NULL ||
+ !strcasecomp(terminal, "network") ||
+ !strcasecomp(terminal, "unknown") ||
+ !strcasecomp(terminal, "dialup") ||
+ !strcasecomp(terminal, "dumb") ||
+ !strcasecomp(terminal, "switch") ||
+ !strcasecomp(terminal, "ethernet"))
+ dumb = TRUE;
+ return (dumb);
+}
+
+#ifdef FANCY_CURSES
+#ifndef USE_COLOR_STYLE
+#ifdef USE_COLOR_TABLE
+static void LYsetWAttr(WINDOW * win)
+{
+ (void) wattrset(win, LYgetTableAttr());
+}
+
+void LYaddWAttr(WINDOW * win, int a)
+{
+ Current_Attr |= a;
+ LYsetWAttr(win);
+}
+
+void LYaddAttr(int a)
+{
+ LYaddWAttr(LYwin, a);
+}
+
+void LYsubWAttr(WINDOW * win, int a)
+{
+ Current_Attr &= ~a;
+ LYsetWAttr(win);
+}
+
+void LYsubAttr(int a)
+{
+ LYsubWAttr(LYwin, a);
+}
+#endif /* USE_COLOR_TABLE */
+#endif /* !USE_COLOR_STYLE */
+#endif /* FANCY_CURSES */
+#endif /* VMS */
+
+/* Use this rather than the 'wprintw()' function to write a blank-padded
+ * string to the given window, since someone's asserted that printw doesn't
+ * handle 8-bit characters unlike addstr (though more info would be useful).
+ *
+ * We're blank-filling so that with SVr4 curses, it'll show the background
+ * color to a uniform width in the popup-menu.
+ */
+#ifndef USE_SLANG
+void LYpaddstr(WINDOW * the_window, int width, const char *the_string)
+{
+ int y, x1, x2;
+ int length = (int) strlen(the_string);
+
+#ifdef WIDEC_CURSES
+ int actual = (int) LYstrCells(the_string);
+#endif
+
+ getyx(the_window, y, x1);
+ (void) y;
+ if (width + x1 > LYcolLimit)
+ width = LYcolLimit - x1;
+#ifdef WIDEC_CURSES
+ if (actual > width) {
+ actual = width;
+ /* FIXME: a binary search might be faster */
+ while (LYstrExtent(the_string, length, length) > actual) {
+ --length;
+ }
+ }
+#endif
+ LYwaddnstr(the_window, the_string, (size_t) length);
+ getyx(the_window, y, x2);
+ width -= (x2 - x1);
+ while (width-- > 0)
+ waddstr(the_window, " ");
+}
+
+/*
+ * Work around limitation of curses's order-of-refresh by setting a pointer to
+ * the topmost window that should be displayed.
+ *
+ * FIXME: the associated call on 'keypad()' is not needed for Unix, but
+ * something in the OS/2 EMX port requires it.
+ */
+void LYsubwindow(WINDOW * param)
+{
+ if (param != 0) {
+ my_subwindow = param;
+#if defined(NCURSES) || defined(PDCURSES)
+ keypad(my_subwindow, TRUE);
+#if defined(USE_COLOR_STYLE)
+ LynxWChangeStyle(my_subwindow, s_menu_bg, STACK_ON);
+ {
+ long b = LYgetattrs(my_subwindow);
+
+ wbkgd(my_subwindow, (chtype) (b | ' '));
+ }
+ LynxWChangeStyle(my_subwindow, s_menu_bg, STACK_OFF);
+#elif defined(HAVE_GETBKGD) /* not defined in ncurses 1.8.7 */
+ wbkgd(my_subwindow, getbkgd(LYwin));
+#endif
+#endif
+ scrollok(my_subwindow, TRUE);
+ } else {
+ touchwin(LYwin);
+ delwin(my_subwindow);
+ my_subwindow = 0;
+ }
+}
+
+WINDOW *LYtopwindow(void)
+{
+ return (my_subwindow ? my_subwindow : LYwin);
+}
+#endif
+
+WINDOW *LYstartPopup(int *top_y,
+ int *left_x,
+ int *height,
+ int *width)
+{
+ WINDOW *form_window = 0;
+
+#ifdef USE_SLANG
+ static WINDOW fake_window;
+
+ if (*left_x < 1 || (*left_x + *width + 4) >= LYcolLimit) {
+ *left_x = 1;
+ *width = LYcolLimit - 5;
+ }
+
+ SLsmg_fill_region(*top_y,
+ *left_x - 1,
+ (unsigned) *height,
+ (unsigned) *width + 4,
+ ' ');
+ form_window = &fake_window;
+ form_window->top_y = *top_y;
+ form_window->left_x = *left_x;
+ form_window->height = *height;
+ form_window->width = *width;
+#else
+ if (*left_x > 0 && (*left_x + *width + 4) < LYcolLimit)
+ form_window = newwin(*height, *width + 4, *top_y, *left_x - 1);
+ if (form_window == 0) {
+ if (*width > LYcolLimit - 4) {
+ *width = LYcolLimit - 4;
+ *left_x = 1;
+ } else {
+ *left_x = LYcolLimit - 4 - *width;
+ if (*left_x <= 0)
+ *left_x = 1;
+ }
+ form_window = newwin(*height, *width + 4, *top_y, *left_x - 1);
+ }
+ if (form_window == 0) {
+ HTAlert(POPUP_FAILED);
+ } else {
+ LYsubwindow(form_window);
+ }
+#endif /* USE_SLANG */
+ return form_window;
+}
+
+void LYstartTargetEmphasis(void)
+{
+#ifdef USE_COLOR_STYLE
+ if (s_whereis != NOSTYLE) {
+ curses_style(s_whereis, STACK_ON);
+ return;
+ }
+#endif
+#if defined(FANCY_CURSES) || defined(USE_SLANG)
+ lynx_start_bold();
+ lynx_start_reverse();
+#endif /* FANCY_CURSES || USE_SLANG */
+ lynx_start_underline();
+}
+
+void LYstopTargetEmphasis(void)
+{
+#ifdef USE_COLOR_STYLE
+ if (s_whereis != NOSTYLE) {
+ curses_style(s_whereis, STACK_OFF);
+ return;
+ }
+#endif
+ lynx_stop_underline();
+#if defined(FANCY_CURSES) || defined(USE_SLANG)
+ lynx_stop_reverse();
+ lynx_stop_bold();
+#endif /* FANCY_CURSES || USE_SLANG */
+}
+
+/*
+ * Accommodate the different flavors of touchline
+ */
+void LYtouchline(int row)
+{
+#if defined(HAVE_WREDRAWLN) && !defined(NCURSES_VERSION)
+ wredrawln(LYwin, row, 1);
+#else
+#if defined(HAVE_TOUCHLINE)
+ /* touchline() is not available on VMS before version 7.0, and then only on
+ * Alpha, since prior ports of curses were broken. BSD touchline() has a
+ * 4th parameter since it is used internally by touchwin().
+ */
+#if defined(HAVE_BSD_TOUCHLINE)
+ touchline(LYwin, row, 0, COLS);
+#else
+ touchline(LYwin, row, 1);
+#endif
+#else
+#if !defined(USE_SLANG)
+ touchwin(LYwin);
+#else
+ SLsmg_touch_lines(row, 1);
+#endif
+#endif
+#endif
+}
+
+/*
+ * Wrapper for waddnstr().
+ */
+void LYwaddnstr(WINDOW * w GCC_UNUSED,
+ const char *src,
+ size_t len)
+{
+ int y0, x0;
+ int y, x;
+ size_t inx;
+
+ (void) y;
+ (void) y0;
+#ifdef USE_CURSES_PADS
+ /*
+ * If we've configured to use pads for left/right scrolling, that can
+ * interfere with calls to this function that assume they're wrapping.
+ * Writing to a pad which is wider than the screen will simply not wrap.
+ *
+ * Link-highlighting uses wrapping. You can see this by viewing the
+ * options screen in a terminal which is narrower than 80 columns.
+ *
+ * Check for that case, and use curses's wrapping in a derived window to
+ * simplify things, e.g., in case the string contains multibyte or
+ * multicolumn characters.
+ */
+ getyx(LYwin, y0, x0);
+
+ if (LYuseCursesPads
+ && (LYwin == w)
+ && (LYshiftWin == 0)
+ && LYwideLines == FALSE
+ && ((int) len > (LYcolLimit - x0))
+ && (y0 >= 0)
+ && (x0 >= 0)
+ && (x0 < LYcolLimit)) {
+ WINDOW *sub = derwin(LYwin, LYlines, LYcolLimit, 0, 0);
+
+ if (sub != 0) {
+ wmove(sub, y0, x0);
+ LYwideLines = TRUE;
+ LYwaddnstr(sub, src, len);
+ getyx(sub, y0, x0);
+ delwin(sub);
+ wmove(LYwin, y0, x0);
+ }
+ LYwideLines = FALSE;
+
+ return;
+ }
+#endif
+ /*
+ * We only want to trace this function for the color-style code. It would
+ * be too much logging if not needed.
+ */
+#ifdef USE_COLOR_STYLE
+ if (TRACE) {
+ LYGetYX(y, x);
+ CTRACE2(TRACE_STYLE, (tfp, "[%2d,%2d] LYwaddnstr(%.*s, %u)\n",
+ y, x, (int) len, src, (unsigned) len));
+ }
+#endif
+ LYGetYX(y0, x0);
+
+ for (inx = 0; inx < len; ++inx) {
+ /*
+ * Do tab-expansion relative to the base of the string (rather than
+ * the screen) so that tabs in a TEXTAREA will look right.
+ */
+ if (src[inx] == '\t') {
+ LYGetYX(y, x);
+ while ((++x - x0) % 8)
+ waddch(w, ' ');
+ waddch(w, ' ');
+ } else {
+ waddch(w, UCH(src[inx]));
+ }
+ }
+}
+
+/*
+ * Determine the number of cells the given string would take up on the screen,
+ * limited (in the case of wide characters) by the maxCells parameter.
+ *
+ * If the returnCellNum parameter is TRUE, return the number of cells;
+ * otherwise, return the length (limited by the len parameter) of the prefix of
+ * the string that fits in maxCells cells.
+ */
+static
+int LYstrExtent0(const char *string,
+ int len,
+ int maxCells GCC_UNUSED,
+ int retCellNum GCC_UNUSED)
+{
+ int used, result;
+
+ if (isEmpty(string)) {
+ used = ((len > 0) ? len : 0);
+ } else {
+ used = ((len < 0) ? (int) strlen(string) : len);
+ }
+ result = used;
+#ifdef WIDEC_CURSES
+ if (non_empty(string) && used > 0 && lynx_called_initscr) {
+ if (fake_max < maxCells) {
+ fake_max = (maxCells + 1) * 2;
+ if (fake_win != 0) {
+ delwin(fake_win);
+ fake_win = 0;
+ }
+ }
+ if (fake_win == 0) {
+ fake_win = newwin(2, fake_max, 0, 0);
+ }
+ if (fake_win != 0) {
+ int new_x = 0;
+ int new_y = 0;
+ int x = 0;
+ int n;
+
+ wmove(fake_win, 0, 0);
+ for (n = 0; n < used; ++n) {
+ if (IsNormalChar(string[n])) {
+ waddch(fake_win, UCH(string[n]));
+ getyx(fake_win, new_y, new_x);
+ if (new_y > 0 || new_x > maxCells)
+ break;
+ x = new_x;
+ }
+ }
+ result = (retCellNum ? x : n);
+ }
+ }
+#endif
+ return result;
+}
+
+/*
+ * Determine the number of cells the given string would take up on the screen,
+ * limited by the maxCells parameter. This is used for constructing aligned
+ * text in the options and similar forms.
+ *
+ * FIXME: make this account for wrapping, too.
+ * FIXME: make this useful for "lynx -dump", which hasn't initialized curses.
+ */
+int LYstrExtent(const char *string, int len, int maxCells)
+{
+ int result = LYstrExtent0(string, len, maxCells, TRUE);
+
+ return (result > maxCells ? maxCells : result);
+}
+
+/*
+ * Return the number of cells in the first 'len' bytes of the string.
+ *
+ * This relies upon the coincidence that multicell characters use at least as
+ * many bytes as cells. But we have to account for tab, which can use 8, and
+ * control characters which use 2.
+ */
+int LYstrExtent2(const char *string, int len)
+{
+ return LYstrExtent(string, len, 8 * len);
+}
+
+/*
+ * Determine the longest prefix of a string that fits in a given number of
+ * cells and return its length.
+ */
+int LYstrFittable(const char *string, int maxCells)
+{
+ return LYstrExtent0(string, -1, maxCells, FALSE);
+}
+
+/*
+ * Returns the total number of cells that the string would use.
+ */
+int LYstrCells(const char *string)
+{
+ return LYstrExtent2(string, (int) strlen(string));
+}
+
+#ifdef VMS
+/*
+ * Cut-down termio --
+ * Do character-oriented stream input for Jeff.
+ * Code ripped off from Micro-Emacs 3.7 by Daniel Lawrence.
+ *
+ * Ever-so-slightly modified by Kathryn Huxtable. 29-Jan-1991.
+ * Cut down for Lou. 8 Sep 1992.
+ * Cut down farther for Lou. 19 Apr 1993.
+ * We don't set PASSALL or PASTHRU since we don't
+ * want to block CTRL/C, CTRL/Y, CTRL/S or CTRL/Q.
+ * Simply setting NOECHO and doing timed reads
+ * is sufficient.
+ * Further mods by Fote. 29-June-1993
+ * ttopen() and ttclose() are now terminal initialization
+ * and restoration procedures, called once at startup
+ * and at exit, respectively, of the LYNX image.
+ * ttclose() should be called before an exit from LYNX
+ * no matter how the exit is invoked.
+ * setup(terminal) does the ttopen().
+ * cleanup() calls cleanup_files() and ttclose().
+ * ttgetc() now handles NOECHO and NOFLITR (instead of
+ * setting the terminal itself to NOECHO in ttopen()).
+ * VMSsignal() added for handling both Ctrl-C *and* Ctrl-Y
+ * interrupts, and disabling system response to Ctrl-T.
+ * Further mods by Fote. 15-Dec-1993
+ * Added edit handler in ttopen() which will invoke
+ * VMSexit() and behave intelligently on ACCVIO's.
+ * Further mods by Fote. 29-Dec-1993
+ * Simplified ttgetc().
+ * Further mods by Fote. 16-Jan-1994
+ * Added code in ttopen() which will invoke VMSVersion()
+ * to get the version of VMS as VersionVMS for use by
+ * by new or modified interrupt or spawning routines.
+ * Further mods by Fote. 27-Jan-1994
+ * Added back a typeahead() which supports 'z' or 'Z' as
+ * an "Zap transfer" command via HTCheckForInterrupt()
+ * in LYUtils.c.
+ */
+
+#include <descrip.h>
+#include <iodef.h>
+#include <ssdef.h>
+#include <msgdef.h>
+#include <ttdef.h>
+#include <tt2def.h>
+#include <libclidef.h>
+#include <lib$routines.h>
+#include <starlet.h>
+#include <clidef.h>
+#include <syidef.h>
+#ifdef signal
+#undef signal
+#endif /* signal */
+#include <signal.h>
+#ifdef system
+#undef system
+#endif /* system */
+#include <processes.h>
+#include <LYVMSdef.h>
+
+#define EFN 0 /* Event flag */
+
+static unsigned char buffer[20]; /* Input buffer */
+static int in_pos, in_len; /* For escape sequences */
+static int oldmode[3]; /* Old TTY mode bits */
+static int newmode[3]; /* New TTY mode bits */
+static short iochan; /* TTY I/O channel */
+static $DESCRIPTOR(term_nam_dsc, "TT"); /* Descriptor for iochan */
+static unsigned long mask = LIB$M_CLI_CTRLY | LIB$M_CLI_CTRLT; /* ^Y and ^T */
+static unsigned long old_msk; /* Saved control mask */
+static short trap_flag = FALSE; /* TRUE if AST is set */
+BOOLEAN DidCleanup = FALSE; /* Exit handler flag */
+static char VersionVMS[20]; /* Version of VMS */
+
+int VMSVersion(char *VerString,
+ int VerLen)
+{
+ unsigned long status, itm_cod = SYI$_VERSION;
+ int i, verlen = 0;
+ struct dsc$descriptor version;
+ char *m;
+
+ version.dsc$a_pointer = VerString;
+ version.dsc$w_length = VerLen - 1;
+ version.dsc$b_dtype = DSC$K_DTYPE_B;
+ version.dsc$b_class = DSC$K_CLASS_S;
+
+ status = lib$getsyi(&itm_cod, 0, &version, &verlen, 0, 0);
+ if (!(status & 1) || verlen == 0)
+ return 0;
+
+ /*
+ * Cut out trailing spaces
+ */
+ for (m = VerString + verlen, i = verlen - 1; i > 0 && VerString[i] == ' '; --i)
+ *(--m) = '\0';
+
+ return strlen(VerString) + 1; /* Transmit ending 0 too */
+}
+
+void VMSexit(void)
+{
+ /*
+ * If we get here and DidCleanup is not set, it was via an ACCVIO, or
+ * outofmemory forced exit, so make *sure* we attempt a cleanup and reset
+ * the terminal.
+ */
+ if (!DidCleanup) {
+ if (LYOutOfMemory == FALSE) {
+ fprintf(stderr,
+ gettext("\nA Fatal error has occurred in %s Ver. %s\n"),
+ LYNX_NAME, LYNX_VERSION);
+ fprintf(stderr,
+ gettext("\nPlease notify your system administrator to confirm a bug, and if\n\
+confirmed, to notify the lynx-dev list. Bug reports should have concise\n\
+descriptions of the command and/or URL which causes the problem, the\n\
+operating system name with version number, the TCPIP implementation, the\n\
+TRACEBACK if it can be captured, and any other relevant information.\n"));
+
+ if (LYTraceLogFP == NULL) {
+ fprintf(stderr, RETURN_TO_CLEANUP);
+ (void) getchar();
+ }
+ } else if (LYCursesON) {
+ HTAlert(MEMORY_EXHAUSTED_ABORT);
+ }
+ cleanup();
+ }
+ if (LYOutOfMemory == TRUE) {
+ printf("\r\n%s\r\n\r\n", MEMORY_EXHAUSTED_ABORT);
+ fflush(stdout);
+ fflush(stderr);
+ }
+}
+
+/*
+ * TTOPEN --
+ * This function is called once to set up the terminal
+ * device streams. It translates TT until it finds
+ * the terminal, then assigns a channel to it, sets it
+ * to EDIT, and sets up the Ctrl-C and Ctrl-Y interrupt
+ * handling.
+ */
+int ttopen(void)
+{
+ int iosb[2];
+ int status;
+ static unsigned long condition;
+ static struct _exit_block {
+ unsigned long forward;
+ unsigned long address;
+ unsigned long zero;
+ unsigned long condition;
+ } exit_handler_block;
+
+ status = sys$assign(&term_nam_dsc, &iochan, 0, 0);
+ if (status != SS$_NORMAL)
+ exit_immediately(status);
+
+ status = sys$qiow(EFN, iochan, IO$_SENSEMODE, &iosb, 0, 0,
+ &oldmode, sizeof(oldmode), 0, 0, 0, 0);
+ if (status != SS$_NORMAL)
+ exit_immediately(status);
+
+ status = iosb[0] & 0xFFFF;
+ if (status != SS$_NORMAL)
+ exit_immediately(status);
+
+ newmode[0] = oldmode[0];
+ newmode[1] = oldmode[1];
+ newmode[2] = oldmode[2] | TT2$M_EDIT;
+
+ status = sys$qiow(EFN, iochan, IO$_SETMODE, &iosb, 0, 0,
+ &newmode, sizeof(newmode), 0, 0, 0, 0);
+ if (status != SS$_NORMAL)
+ exit_immediately(status);
+
+ status = iosb[0] & 0xFFFF;
+ if (status != SS$_NORMAL)
+ exit_immediately(status);
+
+ /*
+ * Declare the exit handler block.
+ */
+ exit_handler_block.forward = 0;
+ exit_handler_block.address = (unsigned long) &VMSexit;
+ exit_handler_block.zero = 0;
+ exit_handler_block.condition = (unsigned long) &condition;
+ status = sys$dclexh(&exit_handler_block);
+ if (status != SS$_NORMAL)
+ exit_immediately(status);
+
+ /*
+ * Set the AST.
+ */
+ lib$disable_ctrl(&mask, &old_msk);
+ trap_flag = TRUE;
+ status = sys$qiow(EFN, iochan,
+ IO$_SETMODE | IO$M_CTRLCAST | IO$M_CTRLYAST,
+ &iosb, 0, 0,
+ &cleanup_sig, SIGINT, 0, 0, 0, 0);
+ if (status != SS$_NORMAL) {
+ lib$enable_ctrl(&old_msk);
+ exit_immediately(status);
+ }
+
+ /*
+ * Get the version of VMS.
+ */
+ if (VMSVersion(VersionVMS, 20) < 3)
+ /*
+ * Load zeros on error.
+ */
+ strcpy(VersionVMS, "V0.0-0");
+
+ return (0);
+} /* ttopen */
+
+/*
+ * TTCLOSE --
+ * This function gets called just before we go back home
+ * to the command interpreter. It puts the terminal back
+ * in a reasonable state.
+ */
+int ttclose(void)
+{
+ int status;
+ int iosb[1];
+
+ status = sys$qiow(EFN, iochan, IO$_SETMODE, &iosb, 0, 0,
+ &oldmode, sizeof(oldmode), 0, 0, 0, 0);
+
+ if (status != SS$_NORMAL || (iosb[0] & 0xFFFF) != SS$_NORMAL)
+ exit_immediately(status);
+
+ if (trap_flag) {
+ status = sys$dassgn(iochan);
+ status = lib$enable_ctrl(&old_msk);
+ trap_flag = FALSE;
+ }
+ return (0);
+} /* ttclose */
+
+/*
+ * TTGETC --
+ * Read a character from the terminal, with NOECHO and NOFILTR.
+ */
+int ttgetc(void)
+{
+ int status;
+ unsigned short iosb[4];
+
+ if (in_pos < in_len)
+ return (buffer[in_pos++]);
+
+ status = sys$qiow(EFN, iochan,
+ IO$_READVBLK | IO$M_NOECHO | IO$M_NOFILTR,
+ &iosb, 0, 0,
+ &buffer, 1, 0, 0, 0, 0);
+ if ((status & 1) == 1)
+ status = iosb[0];
+ if (status == SS$_PARTESCAPE) {
+ /*
+ * Escape sequence in progress. Fake a successful read.
+ */
+ status = 1;
+ }
+ if ((status & 1) != 1 && status != SS$_DATAOVERUN)
+ exit_immediately(status);
+ in_pos = 1;
+ in_len = iosb[1] + iosb[3];
+ return (buffer[0]);
+}
+
+/*
+ * TYPEAHEAD -- Fote Macrides 27-Jan-1994
+ * Check whether a keystroke has been entered, and return
+ * it, or -1 if none was entered.
+ */
+int typeahead(void)
+{
+ int status;
+ unsigned short iosb[4];
+
+ if (dump_output_immediately)
+ return -1;
+
+ if (in_pos < in_len)
+ return (buffer[in_pos++]);
+
+ again:
+ status = sys$qiow(EFN, iochan,
+ IO$_READVBLK | IO$M_TIMED | IO$M_NOECHO | IO$M_NOFILTR,
+ &iosb, 0, 0,
+ &buffer, 1, 0, 0, 0, 0);
+ if ((status & 1) == 1)
+ status = iosb[0];
+ if (status == SS$_PARTESCAPE) {
+ /*
+ * Escape sequence in progress, finish reading it.
+ */
+ goto again;
+ }
+
+ in_pos = 1;
+ in_len = iosb[1] + iosb[3];
+ if (status == SS$_TIMEOUT || status == SS$_DATAOVERUN)
+ return (-1);
+ return (buffer[0]);
+}
+
+/*
+ * VMSSIGNAL -- Fote Macrides 29-Jun-1993
+ * Sets up AST for both Ctrl-C and Ctrl-Y, with system response
+ * to Ctrl-T disabled. If called with a sig other than SIGINT,
+ * it will use the C library's system(sig, func).
+ * The equivalent of VMSsignal(SIGINT, cleanup_sig) is done on
+ * initialization by ttopen(), so don't do it again.
+ * VMSsignal(SIGINT, SIG_DFL) is treated as a call to ttclose().
+ * Call VMSsignal(SIGINT, SIG_IGN) before system() calls to
+ * enable Ctrl-C and Ctrl-Y in the subprocess, and then call
+ * VMSsignal(SIG_INT, cleanup_sig) on return from the subprocess.
+ * For func's which set flags and do not invoke an exit from
+ * LYNX, the func should reassert itself.
+ * The VMS signal() calls do not fully emulate the Unix calls,
+ * and VMSsignal() is just a "helper", also not a full emulation.
+ */
+
+void VMSsignal(int sig,
+ void (*func) ())
+{
+ int status;
+ short iosb[4];
+ static int SIG_IGN_flag;
+
+ /*
+ * Pass all signals other than SIGINT to signal().
+ * Also pass SIGINT to signal() if we're dumping.
+ */
+ if (sig != SIGINT || dump_output_immediately) {
+ signal(sig, func);
+ return;
+ }
+
+ /*
+ * If func is SIG_DFL, treat it as ttclose().
+ */
+ if (func == SIG_DFL) {
+ ttclose();
+ return;
+ }
+
+ /*
+ * Clear any previous AST.
+ */
+ if (trap_flag) {
+ status = sys$dassgn(iochan);
+ status = lib$enable_ctrl(&old_msk);
+ trap_flag = FALSE;
+ }
+
+ /*
+ * If func is SIG_IGN, leave the TT channel closed and the system response
+ * to interrupts enabled for system() calls.
+ */
+ if (func == SIG_IGN)
+ return;
+
+ /*
+ * If we get to here, we have a LYNX func, so set the AST.
+ */
+ lib$disable_ctrl(&mask, &old_msk);
+ trap_flag = TRUE;
+ status = sys$assign(&term_nam_dsc, &iochan, 0, 0);
+ status = sys$qiow(EFN, iochan,
+ IO$_SETMODE | IO$M_CTRLCAST | IO$M_CTRLYAST,
+ &iosb, 0, 0,
+ func, SIGINT, 0, 0, 0, 0);
+
+} /* VMSsignal */
+
+/*
+ * DCLspawn_exception, spawn_DCLprocess, DCLsystem -- F.Macrides 16-Jan-1994
+ * Exception-handler routines for regulating interrupts and enabling
+ * Control-T during spawns. Includes TRUSTED flag for versions of VMS
+ * which require it in captive accounts. This code should be used
+ * instead of the VAXC or DECC system(), by including LYUtils.h in
+ * modules which have system() calls. It helps ensure that we return
+ * to Lynx instead of breaking out to DCL if a user issues interrupts
+ * or generates an ACCVIO during spawns.
+ */
+#ifdef __DECC
+static unsigned int DCLspawn_exception(void *sigarr,
+ void *mecharr)
+#else
+static int DCLspawn_exception(void *sigarr,
+ void *mecharr)
+#endif /* __DECC */
+{
+ int status;
+
+ status = lib$sig_to_ret(sigarr, mecharr);
+ return (SS$_UNWIND);
+}
+
+static int spawn_DCLprocess(char *command)
+{
+ int status;
+ unsigned long Status = 0;
+
+ /*
+ * Keep DECC from complaining.
+ */
+ struct dsc$descriptor_s command_desc;
+
+ command_desc.dsc$w_length = strlen(command);
+ command_desc.dsc$b_class = DSC$K_CLASS_S;
+ command_desc.dsc$b_dtype = DSC$K_DTYPE_T;
+ command_desc.dsc$a_pointer = command;
+
+ VAXC$ESTABLISH(DCLspawn_exception);
+
+#ifdef __ALPHA /** OpenVMS/AXP lacked the TRUSTED flag before v6.1 **/
+ if (VersionVMS[1] > '6' ||
+ (VersionVMS[1] == '6' && VersionVMS[2] == '.' &&
+ VersionVMS[3] >= '1'))
+#else
+ if (VersionVMS[1] >= '6')
+#endif /* __ALPHA */
+ {
+ /*
+ * Include TRUSTED flag.
+ */
+ unsigned long trusted = CLI$M_TRUSTED;
+
+ status = lib$spawn(&command_desc, 0, 0, &trusted,
+ 0, 0, &Status);
+ /*
+ * If it was invalid, try again without the flag.
+ */
+ if (status == LIB$_INVARG)
+ status = lib$spawn(&command_desc, 0, 0, 0,
+ 0, 0, &Status);
+ } else
+ status = lib$spawn(&command_desc, 0, 0, 0,
+ 0, 0, &Status);
+ /*
+ * Return -1 on error.
+ */
+ if ((status & 1) != 1 || (Status & 1) != 1)
+ return (-1);
+ /*
+ * Return 0 on success.
+ */
+ return (0);
+}
+
+int DCLsystem(char *command)
+{
+ int status;
+
+ VMSsignal(SIGINT, SIG_IGN);
+ status = spawn_DCLprocess(command);
+ VMSsignal(SIGINT, cleanup_sig);
+ /*
+ * Returns 0 on success, -1 any error.
+ */
+ return (status);
+}
+#endif /* VMS */
+
+/*
+ * Return the physical screen dimensions that we're allowed to use.
+ */
+int LYscreenHeight(void)
+{
+ int result = LINES;
+
+ if (result <= 0)
+ result = DFT_ROWS;
+ return result;
+}
+
+int LYscreenWidth(void)
+{
+ int result = COLS;
+
+#if defined(PDCURSES_EXP) && defined(WIN_EX) && defined(CJK_EX) /* 1999/08/26 (Thu) 17:53:38 */
+ {
+ extern int current_codepage; /* PDCurses lib. */
+
+ if (current_codepage == 932)
+ result--;
+ }
+#endif
+ if (result <= 0)
+ result = DFT_COLS;
+ return result;
+}
+
+/*
+ * Set the window's background color (make the pad's color agree), e.g., when
+ * we have just parsed it from the config file, or after clearing the screen.
+ */
+void LYnormalColor(void)
+{
+#if defined(USE_COLOR_STYLE) && defined(USE_CURSES_PADS)
+ if (LYwin != stdscr) {
+ int color = displayStyles[DSTYLE_NORMAL].color;
+
+ if (color >= 0) {
+ wbkgd(LYwin, (chtype) (color | ' '));
+ LYrefresh();
+ }
+ }
+#endif
+}
+
+/*
+ * The functions ifdef'd with USE_CURSES_PADS are implemented that way so we
+ * don't break the slang configuration.
+ */
+void LYclear(void)
+{
+#ifdef USE_CURSES_PADS
+ wclear(LYwin);
+#else
+ clear();
+#endif
+ LYnormalColor();
+}
+
+void LYclrtoeol(void)
+{
+#ifdef USE_CURSES_PADS
+ wclrtoeol(LYwin);
+#else
+ clrtoeol();
+#endif
+}
+
+void LYerase(void)
+{
+#ifdef USE_CURSES_PADS
+ werase(LYwin);
+#else
+ erase();
+#endif
+ LYnormalColor();
+}
+
+void LYmove(int y, int x)
+{
+#ifdef USE_CURSES_PADS
+ wmove(LYwin, y, x);
+#else
+ move(y, x);
+#endif
+}
+
+void LYrefresh(void)
+{
+#ifdef USE_CURSES_PADS
+ if (LYwin != stdscr) {
+ /*
+ * Workaround for special case where lynx is prompting for a mailto,
+ * and has a subject line that is wider than the screen. The
+ * wnoutrefresh() call resets newscr's position to match stdscr's,
+ * which happens to be the window's origin because we were not updating
+ * that, and other stray wmove's in lynx fail because the coordinate
+ * is on/after the right margin. Force things to look ok here.
+ */
+ int y, x;
+
+ getyx(LYwin, y, x);
+ if (y < 0)
+ y = 0;
+ if (x < 0)
+ x = 0;
+ if (x > LYcolLimit)
+ x = LYcolLimit;
+ wmove(stdscr, y, x);
+
+ wnoutrefresh(stdscr);
+ pnoutrefresh(LYwin, 0, LYshiftWin, 0, 0, LYlines, LYscreenWidth() - 1);
+
+ /*
+ * Keep a popup window visible. This can happen if the user presses
+ * '/' to do a search within a popup.
+ */
+ if (my_subwindow != 0) {
+ touchwin(my_subwindow);
+ wnoutrefresh(my_subwindow);
+ }
+ doupdate();
+ } else {
+ refresh();
+ }
+#else
+ refresh();
+#endif
+}
+
+void lynx_force_repaint(void)
+{
+ clearok(curscr, TRUE);
+}
+
+void lynx_start_title_color(void)
+{
+#ifdef SH_EX
+ lynx_start_reverse();
+#endif
+}
+
+void lynx_stop_title_color(void)
+{
+#ifdef SH_EX
+ lynx_stop_reverse();
+#endif
+}
+
+void lynx_start_link_color(int flag,
+ int pending)
+{
+ if (flag) {
+ /* makes some terminals work wrong because
+ * they can't handle two attributes at the
+ * same time
+ */
+ /* lynx_start_bold(); */
+ lynx_start_reverse();
+#if defined(USE_SLANG)
+#ifndef __DJGPP__
+ if (SLtt_Use_Ansi_Colors)
+#endif /* !__DJGPP__ */
+ lynx_start_underline();
+#endif /* USE_SLANG */
+#if defined(FANCY_CURSES) && defined(COLOR_CURSES)
+ if (lynx_has_color && LYShowColor >= SHOW_COLOR_ON)
+ lynx_start_underline();
+#endif /* USE_SLANG */
+ } else {
+ lynx_start_bold();
+ /*
+ * Make sure when flag is OFF that "unhighlighted" links will be
+ * underlined if appropriate. - LE & FM
+ */
+ if (pending)
+ lynx_start_underline();
+ }
+}
+
+void lynx_stop_link_color(int flag,
+ int pending GCC_UNUSED)
+{
+#ifdef USE_COLOR_STYLE
+ LynxChangeStyle(flag == TRUE ? s_alink : s_a, ABS_OFF);
+#else
+ if (flag) {
+ lynx_stop_reverse();
+#if defined(USE_SLANG)
+#ifndef __DJGPP__
+ if (SLtt_Use_Ansi_Colors)
+#endif /* !__DJGPP__ */
+ lynx_stop_underline();
+#endif /* USE_SLANG */
+#if defined(FANCY_CURSES) && defined(COLOR_CURSES)
+ if (lynx_has_color && LYShowColor >= SHOW_COLOR_ON)
+ lynx_stop_underline();
+#endif /* FANCY_CURSES && COLOR_CURSES */
+ } else {
+ lynx_stop_bold();
+ /*
+ * If underlining was turned on above, turn it off. - LE & FM
+ */
+ if (pending)
+ lynx_stop_underline();
+ }
+#endif
+}
+
+/* FIXME: consider inlining these */
+
+void lynx_stop_target_color(void)
+{
+ lynx_stop_underline();
+ lynx_stop_reverse();
+ lynx_stop_bold();
+}
+
+void lynx_start_target_color(void)
+{
+ lynx_start_bold();
+ lynx_start_reverse();
+ lynx_start_underline();
+}
+
+void lynx_start_status_color(void)
+{
+#if defined(USE_COLOR_TABLE) && defined(COLOR_CURSES)
+ if (lynx_has_color && LYShowColor >= SHOW_COLOR_ON)
+ lynx_set_color(2);
+ else
+#endif
+ lynx_start_reverse();
+}
+
+void lynx_stop_status_color(void)
+{
+#if defined(USE_COLOR_TABLE) && defined(COLOR_CURSES)
+ if (lynx_has_color && LYShowColor >= SHOW_COLOR_ON)
+ lynx_set_color(0);
+ else
+#endif
+ lynx_stop_reverse();
+}
+
+void lynx_start_h1_color(void)
+{
+ if (bold_H1 || bold_headers)
+ lynx_start_bold();
+}
+
+void lynx_stop_h1_color(void)
+{
+ if (bold_H1 || bold_headers)
+ lynx_stop_bold();
+}
+
+void lynx_start_prompt_color(void)
+{
+ lynx_start_reverse();
+}
+
+void lynx_stop_prompt_color(void)
+{
+ lynx_stop_reverse();
+}
+
+void lynx_start_radio_color(void)
+{
+ lynx_start_bold();
+}
+
+void lynx_stop_radio_color(void)
+{
+ lynx_stop_bold();
+}
+
+void lynx_stop_all_colors(void)
+{
+ lynx_stop_underline();
+ lynx_stop_reverse();
+ lynx_stop_bold();
+}
+
+/*
+ * Wrappers for LYUnderlineLinks flag.
+ */
+void lynx_start_bold(void)
+{
+ start_bold();
+}
+
+void lynx_start_reverse(void)
+{
+ start_reverse();
+}
+
+void lynx_start_underline(void)
+{
+ start_underline();
+}
+
+void lynx_stop_bold(void)
+{
+ stop_bold();
+}
+
+void lynx_stop_reverse(void)
+{
+ stop_reverse();
+}
+
+void lynx_stop_underline(void)
+{
+ stop_underline();
+}
+
+void LYSetDisplayLines(void)
+{
+ if (!no_title) {
+ if (user_mode == NOVICE_MODE)
+ display_lines = LYlines - 4;
+ else
+ display_lines = LYlines - 2;
+ } else if (user_mode == NOVICE_MODE) {
+ display_lines = LYlines - 3;
+ } else {
+ display_lines = LYlines - 1;
+ }
+}
+
+/*
+ * If LYShowCursor is ON, move the cursor to the left of the current option, so
+ * that blind users, who are most likely to have LYShowCursor ON, will have
+ * it's string spoken or passed to the braille interface as each option is made
+ * current. Otherwise, move it to the bottom, right column of the screen, to
+ * "hide" the cursor as for the main document, and let sighted users rely on
+ * the current option's highlighting or color without the distraction of a
+ * blinking cursor in the window. - FM
+ */
+void LYstowCursor(WINDOW * win, int row, int col)
+{
+ if (LYShowCursor) {
+ wmove(win, row, col);
+ } else {
+ LYHideCursor();
+ }
+#ifdef USE_SLANG
+ SLsmg_refresh();
+#else
+ wrefresh(win);
+#endif /* USE_SLANG */
+}
+
+#if defined(USE_BLINK) && defined(__EMX__) /* Can't put it earlier due to BOOLEAN conflict */
+# define BOOLEAN os2BOOLEAN
+# define INCL_VIO
+# include "os2.h"
+static void make_blink_boldbg(void)
+{
+ VIOINTENSITY buf; /* VIO windows have it anyway, */
+
+ /* but FS session need a switch */
+ buf.cb = sizeof(buf);
+ buf.type = 2; /* VIOINTENSITY request */
+ buf.fs = 1; /* Intensity == boldbg */
+ VioSetState(&buf, 0);
+}
+#endif
+
+#if defined(HAVE_WATTR_GET)
+/*
+ * getattrs() is not in X/Open curses, but it is more convenient than this.
+ */
+long LYgetattrs(WINDOW * win)
+{
+ long result;
+
+#if ( defined(HAVE_GETATTRS) && ( !defined(NCURSES_VERSION_MAJOR) || NCURSES_VERSION_MAJOR < 5 ) )
+
+ result = getattrs(win);
+#else
+ attr_t attrs = 0;
+ short pair = 0;
+
+ /*
+ * FIXME: this ignores the color-pair, which for most implementations is
+ * not stored in the attribute value.
+ */
+ (void) (wattr_get) (win, &attrs, &pair, NULL);
+ result = (long) attrs;
+#endif
+ return result;
+}
+#endif /* HAVE_WATTR_GET */
+
+#if defined(NCURSES_VERSION_PATCH) && NCURSES_VERSION_PATCH > 20021012
+#ifndef HAVE_USE_LEGACY_CODING
+/*
+ * Between ncurses 5.3 and 5.4 as part of fixes for wide-character mode, the
+ * locale support no longer allows characters in the range 128-159 to be
+ * treated as printable characters. Here is a workaround to fool
+ * waddch_nosync() into treating "all" 8-bit characters as printable.
+ */
+NCURSES_CONST char *unctrl(chtype ch)
+{
+ static char result[3];
+ unsigned data = (unsigned char) ch;
+
+ if (data < 32) {
+ result[0] = '^';
+ result[1] = ch | '@';
+ result[2] = 0;
+ } else if (data == 127) {
+ result[0] = '^';
+ result[1] = '?';
+ result[2] = 0;
+ } else {
+ result[0] = data;
+ result[1] = 0;
+ }
+ return result;
+}
+#endif /* HAVE_USE_LEGACY_CODING */
+#endif