commit 2797b6fcde19e154f16a6eac512783ba6942fdcc Author: G. Branden Robinson AuthorDate: Thu Feb 8 21:37:31 2024 -0600 Commit: G. Branden Robinson CommitDate: Tue Feb 27 00:49:40 2024 -0600 [grotty]: Add terminfo support (3/x). diff --git a/configure.ac b/configure.ac index 2493fcebf..ff1730253 100644 --- a/configure.ac +++ b/configure.ac @@ -158,6 +158,9 @@ GROFF_URW_FONTS_PATH # use groff's own malloc-based allocator for C++ new/delete operators GROFF_USE_GROFF_ALLOCATOR +# grotty uses curses +GROFF_CURSES + # other random stuff GROFF_BROKEN_SPOOLER_FLAGS GROFF_PAGE diff --git a/m4/groff.m4 b/m4/groff.m4 index ebbe60d52..7fb58266a 100644 --- a/m4/groff.m4 +++ b/m4/groff.m4 @@ -1934,3 +1934,13 @@ [test "$enableval" = yes && groff_use_own_allocator=yes], [groff_use_own_allocator=no]) ]) + + +# Search for curses/terminfo library used by grotty. +# +# TODO: This needs be to generalized to check for other curses +# implementations, not just ncurses. + +AC_DEFUN([GROFF_CURSES], [ + PKG_CHECK_MODULES([CURSES], [ncurses]) +]) diff --git a/src/devices/grotty/grotty.am b/src/devices/grotty/grotty.am index a9d2fe1c1..9e0540686 100644 --- a/src/devices/grotty/grotty.am +++ b/src/devices/grotty/grotty.am @@ -21,7 +21,7 @@ grotty_LDADD = $(LIBM) \ libdriver.a \ libgroff.a \ lib/libgnu.a \ - -lcurses + $(CURSES_LIBS) man1_MANS += src/devices/grotty/grotty.1 EXTRA_DIST += \ src/devices/grotty/grotty.1.man \ commit ab225c488699920d93a8883689b8abd357b4c204 Author: G. Branden Robinson AuthorDate: Mon Feb 26 20:18:03 2024 -0600 Commit: G. Branden Robinson CommitDate: Tue Feb 27 00:49:40 2024 -0600 [grotty]: Check for adequate color capability. * src/devices/grotty/tty.cpp: Add new global Boolean `want_colors`; default `true`. (tty_printer::put_color): Return early if `want_colors` is false. (initialize_terminal): Check for terminfo `colors` capability. If absent or fewer than 8 colors supported, throw capability warning diagnostic and set `want_colors` to "false". Tested with TERM values of "xtermc", "xtermm", "xterm-mono", "xterm-16color", "xterm-256color", "dumb", "vt100-nav", "vt100-nam", "vt100", "vt420", and "vt525". The last seems to falsely report lack of color support, which does not square with the DEC VT525 I used to operate. Will report to ncurses maintainer. diff --git a/src/devices/grotty/tty.cpp b/src/devices/grotty/tty.cpp index 66d74ae5f..6f9bcbfbb 100644 --- a/src/devices/grotty/tty.cpp +++ b/src/devices/grotty/tty.cpp @@ -60,6 +60,7 @@ static bool want_reverse_video_for_italics = false; static bool do_reverse_video; static bool want_overstriking_drawing_scheme = false; static bool want_capability_warnings = false; +static bool want_colors = true; static void initialize_terminal(); static void usage(FILE *stream); @@ -697,6 +698,8 @@ void tty_printer::put_char(output_character wc) void tty_printer::put_color(schar color_index, int back) { + if (!want_colors) + return; if (color_index == DEFAULT_COLOR_IDX) { putstring(SGR_DEFAULT); // set bold and underline again @@ -994,6 +997,15 @@ static void initialize_terminal() want_overstriking_drawing_scheme = false; } + // Support for fewer than 8 colors is as good as none as far as we're + // concerned; tty.tmac expects the 8 "ANSI" color names. + ret = tigetnum("colors"); + if (ret < 8) { + if (want_capability_warnings) + warning("terminal type '%1' lacks color support", terminal_type); + want_colors = false; + } + if (want_overstriking_drawing_scheme) { do_sgr_italics = false; do_reverse_video = false; commit 402a2583296c556957613730572723f3992ad292 Author: G. Branden Robinson AuthorDate: Mon Feb 26 20:45:24 2024 -0600 Commit: G. Branden Robinson CommitDate: Mon Feb 26 20:45:24 2024 -0600 XXX [grotty]: Add terminfo support (4/x). diff --git a/src/devices/grotty/tty.cpp b/src/devices/grotty/tty.cpp index edc926f3e..66d74ae5f 100644 --- a/src/devices/grotty/tty.cpp +++ b/src/devices/grotty/tty.cpp @@ -48,19 +48,20 @@ typedef unsigned int output_character; static bool want_horizontal_tabs = false; static bool want_form_feeds = false; -static bool want_emboldening_by_overstriking = true; +static bool want_emboldening_by_overstriking = true; // TODO: false static bool do_bold; -static bool want_italics_by_underlining = true; +static bool want_italics_by_underlining = true; // TODO: false static bool do_underline; static bool want_glyph_composition_by_overstriking = true; static bool allow_drawing_commands = true; -static bool want_sgr_italics = false; +static bool want_sgr_italics = false; // TODO: true static bool do_sgr_italics; static bool want_reverse_video_for_italics = false; static bool do_reverse_video; static bool want_overstriking_drawing_scheme = false; +static bool want_capability_warnings = false; -static void update_options(); +static void initialize_terminal(); static void usage(FILE *stream); static int hline_char = '-'; @@ -920,9 +921,80 @@ printer *make_printer() return new tty_printer(); } -static void update_options() +static void initialize_terminal() { - if (use_overstriking_drawing_scheme) { + int err; + + char *terminal_type = strdup(getenv("TERM")); + int ret = setupterm(NULL /* use TERM */, STDOUT_FILENO, &err); + size_t len = strlen(terminal_type); + + if (len == 0) + fatal("TERM environment variable must be set; aborting"); + + if (OK == ret) { + ; + } + else if (ERR == ret) { + switch (err) { + case -1: + fatal("terminfo database entry not found; aborting"); + break; + case 0: + fatal("entry for '%1' not found in terminal database; aborting", + terminal_type); + case 1: + // POSIX calls this case "Success". As an extension, to ncurses + // it means a hardcopy terminal. While fatal for many terminfo + // applications, we're fine with it. + break; + default: + fatal("terminfo interface is nonstandard; aborting"); + } + } + else + fatal("terminfo interface is nonstandard; aborting"); + + if (tigetflag("hc")) { + // hardcopy terminal + do_sgr_italics = false; + do_reverse_video = false; + + if (want_sgr_italics) { + if (want_capability_warnings) + warning("terminal type '%1' is incapable of SGR italics", + terminal_type); + want_sgr_italics = false; + } + } + else + if (want_sgr_italics) + if ((tigetstr("sitm") == 0 /* nullptr */) + || (tigetstr("ritm") == 0 /* nullptr */)) { + if (want_capability_warnings) + warning("terminal type '%1' is incapable of SGR italics", + terminal_type); + want_sgr_italics = false; + } + + // X/Open Curses Issue 7 defines "os" as "Terminal overstrikes on + // hard-copy terminal". However, ncurses's terminfo database defines + // it for graphical terminals as well; see entries for wy99gt-tek, + // wy370-tek, tek, tek4013, gt40, and so on. We therefore regard it + // as generally relevant. + if (tigetflag("os")) { + // can overstrike + do_bold = want_emboldening_by_overstriking; + do_underline = want_italics_by_underlining; + } + else + if (want_overstriking_drawing_scheme && want_capability_warnings) { + warning("terminal type %1 is incapable of overstriking", + terminal_type); + want_overstriking_drawing_scheme = false; + } + + if (want_overstriking_drawing_scheme) { do_sgr_italics = false; do_reverse_video = false; bold_underline_mode = bold_underline_mode_option; @@ -930,12 +1002,15 @@ static void update_options() do_underline = want_italics_by_underlining; } else { + // TODO: check for `sitm` capability do_sgr_italics = want_sgr_italics; do_reverse_video = want_reverse_video_for_italics; bold_underline_mode = BOLD_MODE|UNDERLINE_MODE; do_bold = true; do_underline = true; } + + free(terminal_type); } int main(int argc, char **argv) @@ -952,8 +1027,8 @@ int main(int argc, char **argv) { "version", no_argument, 0, 'v' }, { NULL, 0, 0, 0 } }; - while ((c = getopt_long(argc, argv, "bBcdfF:hiI:oruUv", long_options, NULL)) - != EOF) + while ((c = getopt_long(argc, argv, "bBcdfF:hiI:oruUvw", long_options, + NULL)) != EOF) switch(c) { case 'v': printf("GNU grotty (groff) version %s\n", Version_string); @@ -1008,6 +1083,9 @@ int main(int argc, char **argv) // Ignore \D commands. allow_drawing_commands = false; break; + case 'w': + want_capability_warnings = true; + break; case CHAR_MAX + 1: // --help usage(stdout); break; @@ -1018,7 +1096,7 @@ int main(int argc, char **argv) default: assert(0 == "unhandled getopt_long return value"); } - update_options(); + initialize_terminal(); if (optind >= argc) do_file("-"); else { commit 8d2aa9f635e284ce4ad82d63eb7a9b042b49380b Author: G. Branden Robinson AuthorDate: Mon Feb 26 20:31:55 2024 -0600 Commit: G. Branden Robinson CommitDate: Mon Feb 26 20:31:55 2024 -0600 XXX [grotty]: Add terminfo support (3/x). * src/devices/grotty/tty.cpp: Rename global Boolean `use_overstriking_drawing_scheme` to `want_overstriking_drawing_scheme` for consistency with other, similar globals and to reflect forthcoming intentions for its semantics. diff --git a/src/devices/grotty/tty.cpp b/src/devices/grotty/tty.cpp index 0b24a9f21..edc926f3e 100644 --- a/src/devices/grotty/tty.cpp +++ b/src/devices/grotty/tty.cpp @@ -58,7 +58,7 @@ static bool want_sgr_italics = false; static bool do_sgr_italics; static bool want_reverse_video_for_italics = false; static bool do_reverse_video; -static bool use_overstriking_drawing_scheme = false; +static bool want_overstriking_drawing_scheme = false; static void update_options(); static void usage(FILE *stream); @@ -288,7 +288,7 @@ tty_printer::~tty_printer() void tty_printer::make_underline(int w) { - if (use_overstriking_drawing_scheme) { + if (want_overstriking_drawing_scheme) { if (!w) warning("can't underline zero-width character"); else { @@ -311,7 +311,7 @@ void tty_printer::make_underline(int w) void tty_printer::make_bold(output_character c, int w) { - if (use_overstriking_drawing_scheme) { + if (want_overstriking_drawing_scheme) { if (!w) warning("can't print zero-width character in bold"); else { @@ -466,7 +466,7 @@ void tty_printer::special(char *arg, const environment *env, char type) void tty_printer::special_link(const char *arg, const environment *env) { static bool is_link_active = false; - if (use_overstriking_drawing_scheme) + if (want_overstriking_drawing_scheme) return; for (const char *s = OSC8; *s != '\0'; s++) simple_add_char(*s, env); @@ -819,7 +819,7 @@ void tty_printer::end_page(int page_length) break; if (is_continuously_underlining) make_underline(p->w); - else if (!use_overstriking_drawing_scheme + else if (!want_overstriking_drawing_scheme && is_underlining) { if (do_sgr_italics) putstring(SGR_NO_ITALIC); @@ -836,7 +836,8 @@ void tty_printer::end_page(int page_length) for (; hpos < p->hpos; hpos++) { if (is_continuously_underlining) make_underline(p->w); - else if (!use_overstriking_drawing_scheme && is_underlining) { + else if (!want_overstriking_drawing_scheme + && is_underlining) { if (do_sgr_italics) putstring(SGR_NO_ITALIC); else if (do_reverse_video) @@ -850,7 +851,7 @@ void tty_printer::end_page(int page_length) } assert(hpos == p->hpos); if (p->mode & COLOR_CHANGE) { - if (!use_overstriking_drawing_scheme) { + if (!want_overstriking_drawing_scheme) { if (p->fore_color_idx != curr_fore_idx) { put_color(p->fore_color_idx, 0); curr_fore_idx = p->fore_color_idx; @@ -864,7 +865,7 @@ void tty_printer::end_page(int page_length) } if (p->mode & UNDERLINE_MODE) make_underline(p->w); - else if (!use_overstriking_drawing_scheme && is_underlining) { + else if (!want_overstriking_drawing_scheme && is_underlining) { if (do_sgr_italics) putstring(SGR_NO_ITALIC); else if (do_reverse_video) @@ -875,11 +876,11 @@ void tty_printer::end_page(int page_length) } if (p->mode & BOLD_MODE) make_bold(p->code, p->w); - else if (!use_overstriking_drawing_scheme && is_boldfacing) { + else if (!want_overstriking_drawing_scheme && is_boldfacing) { putstring(SGR_NO_BOLD); is_boldfacing = false; } - if (!use_overstriking_drawing_scheme) { + if (!want_overstriking_drawing_scheme) { if (p->fore_color_idx != curr_fore_idx) { put_color(p->fore_color_idx, 0); curr_fore_idx = p->fore_color_idx; @@ -892,7 +893,7 @@ void tty_printer::end_page(int page_length) put_char(p->code); hpos += p->w / font::hor; } - if (!use_overstriking_drawing_scheme + if (!want_overstriking_drawing_scheme && (is_boldfacing || is_underlining || curr_fore_idx != DEFAULT_COLOR_IDX || curr_back_idx != DEFAULT_COLOR_IDX)) @@ -942,7 +943,7 @@ int main(int argc, char **argv) program_name = argv[0]; static char stderr_buf[BUFSIZ]; if (getenv("GROFF_NO_SGR")) - use_overstriking_drawing_scheme = true; + want_overstriking_drawing_scheme = true; setbuf(stderr, stderr_buf); setlocale(LC_CTYPE, ""); int c; @@ -971,7 +972,7 @@ int main(int argc, char **argv) break; case 'c': // Use old scheme for emboldening and underline. - use_overstriking_drawing_scheme = true; + want_overstriking_drawing_scheme = true; break; case 'u': // Do not underline. commit e69472ed536af3873124eaf9462e12fa6c145cd1 Author: G. Branden Robinson AuthorDate: Mon Feb 26 20:29:14 2024 -0600 Commit: G. Branden Robinson CommitDate: Mon Feb 26 20:29:14 2024 -0600 [grotty]: Add terminfo support (2/x). * src/devices/grotty/grotty.am (grotty_LDADD): Link with `-lcurses`. * src/devices/grotty/tty.cpp: Import symbols from curses.h and term.h. diff --git a/src/devices/grotty/grotty.am b/src/devices/grotty/grotty.am index 14921c562..a9d2fe1c1 100644 --- a/src/devices/grotty/grotty.am +++ b/src/devices/grotty/grotty.am @@ -20,7 +20,8 @@ grotty_SOURCES = src/devices/grotty/tty.cpp grotty_LDADD = $(LIBM) \ libdriver.a \ libgroff.a \ - lib/libgnu.a + lib/libgnu.a \ + -lcurses man1_MANS += src/devices/grotty/grotty.1 EXTRA_DIST += \ src/devices/grotty/grotty.1.man \ diff --git a/src/devices/grotty/tty.cpp b/src/devices/grotty/tty.cpp index 9501c656a..0b24a9f21 100644 --- a/src/devices/grotty/tty.cpp +++ b/src/devices/grotty/tty.cpp @@ -21,6 +21,9 @@ along with this program. If not, see . */ #include "device.h" #include "ptable.h" +#include +#include + typedef signed char schar; declare_ptable(schar) commit 751b7a757589e529e8a8685dd6568c941517f246 Author: G. Branden Robinson AuthorDate: Thu Feb 8 01:04:28 2024 -0600 Commit: G. Branden Robinson CommitDate: Mon Feb 26 20:26:07 2024 -0600 [grotty]: Add terminfo support (1/x). Rename `tty_printer` class member variable `lines` to `grotty_lines`, necessitated by curses library linkage. C++ name spacing does not help us here because ncurses defines `lines` as a preprocessor macro. (Curses exposes _every_ terminal capability as a global symbol; see Curses Issue 7, ยง7.1.3, "Defined Capabilities", p. 340 or term_variables(3ncurses).) * src/devices/grotty/tty.cpp (class tty_printer): (tty_printer::tty_printer): (tty_printer::add_char): (tty_printer::end_page): Do it. diff --git a/src/devices/grotty/tty.cpp b/src/devices/grotty/tty.cpp index c9f386e37..9501c656a 100644 --- a/src/devices/grotty/tty.cpp +++ b/src/devices/grotty/tty.cpp @@ -172,7 +172,7 @@ public: class tty_printer : public printer { - tty_glyph **lines; + tty_glyph **grotty_lines; int nlines; int cached_v; int cached_vpos; @@ -271,16 +271,16 @@ tty_printer::tty_printer() : cached_v(0) (void)tty_color(color::MAX_COLOR_VAL, 0, color::MAX_COLOR_VAL, &dummy, 5); (void)tty_color(0, color::MAX_COLOR_VAL, color::MAX_COLOR_VAL, &dummy, 6); nlines = 66; - lines = new tty_glyph *[nlines]; + grotty_lines = new tty_glyph *[nlines]; for (int i = 0; i < nlines; i++) - lines[i] = 0; + grotty_lines[i] = 0; is_continuously_underlining = false; } tty_printer::~tty_printer() { current_lineno = 0; // At this point, we've read all the input. - delete[] lines; + delete[] grotty_lines; } void tty_printer::make_underline(int w) @@ -373,11 +373,11 @@ void tty_printer::add_char(output_character c, int w, " quantum"); vpos = v / font::vert; if (vpos > nlines) { - tty_glyph **old_lines = lines; - lines = new tty_glyph *[vpos + 1]; - memcpy(lines, old_lines, nlines * sizeof(tty_glyph *)); + tty_glyph **old_lines = grotty_lines; + grotty_lines = new tty_glyph *[vpos + 1]; + memcpy(grotty_lines, old_lines, nlines * sizeof(tty_glyph *)); for (int i = nlines; i <= vpos; i++) - lines[i] = 0; + grotty_lines[i] = 0; delete[] old_lines; nlines = vpos + 1; } @@ -404,7 +404,7 @@ void tty_printer::add_char(output_character c, int w, // at each hpos, and otherwise in order of occurrence. tty_glyph **pp; - for (pp = lines + (vpos - 1); *pp; pp = &(*pp)->next) + for (pp = grotty_lines + (vpos - 1); *pp; pp = &(*pp)->next) if ((*pp)->hpos < hpos || ((*pp)->hpos == hpos && (*pp)->order() >= g->order())) break; @@ -743,24 +743,24 @@ void tty_printer::end_page(int page_length) int lines_per_page = page_length / font::vert; int last_line; for (last_line = nlines; last_line > 0; last_line--) - if (lines[last_line - 1]) + if (grotty_lines[last_line - 1]) break; #if 0 if (last_line > lines_per_page) { error("characters past last line discarded"); do { --last_line; - while (lines[last_line]) { - tty_glyph *tem = lines[last_line]; - lines[last_line] = tem->next; + while (grotty_lines[last_line]) { + tty_glyph *tem = grotty_lines[last_line]; + grotty_lines[last_line] = tem->next; delete tem; } } while (last_line > lines_per_page); } #endif for (int i = 0; i < last_line; i++) { - tty_glyph *p = lines[i]; - lines[i] = 0; + tty_glyph *p = grotty_lines[i]; + grotty_lines[i] = 0; tty_glyph *g = 0; while (p) { tty_glyph *tem = p->next; commit 78051586a1db7610300b408cf32450166ef29474 Author: G. Branden Robinson AuthorDate: Mon Feb 26 16:28:00 2024 -0600 Commit: G. Branden Robinson CommitDate: Mon Feb 26 16:28:00 2024 -0600 doc/groff.texi.in: Fix inter-word spacing. diff --git a/doc/groff.texi.in b/doc/groff.texi.in index cedb5362a..33402d2ba 100644 --- a/doc/groff.texi.in +++ b/doc/groff.texi.in @@ -6471,7 +6471,7 @@ @node Numeric Expressions For vertical motions, the @code{|} operator specifies a distance from the first text baseline on the page or in the current -diversion,@footnote{@xref{Diversions}.} using the current vertical +diversion,@footnote{@xref{Diversions}.} using the current vertical spacing. @Example @@ -7541,7 +7541,7 @@ @node Setting Registers (directly) to output. @xref{Gtroff Internals}. Further surprise can occur if you use registers like -@code{.k},@footnote{@xref{Page Motions}.} whose values are not +@code{.k},@footnote{@xref{Page Motions}.} whose values are not determined until they are interpolated. @Example @@ -14978,7 +14978,7 @@ @node The Implicit Page Trap @cindex ejection, page If, after starting GNU @code{troff} without loading a macro package, you use the @code{ptr} request to dump a list of the active traps to the -standard error stream,@footnote{@xref{Debugging}.} nothing is reported. +standard error stream,@footnote{@xref{Debugging}.} nothing is reported. Yet the @code{.t} register will report a steadily decreasing value with every output line your document produces, and once the value of @code{.t} gets to within @code{.V} of zero, you will notice that commit 107179f0bf5f9e5ea6de208513b0cd01b4e855f7 Author: G. Branden Robinson AuthorDate: Sun Feb 25 23:26:51 2024 -0600 Commit: G. Branden Robinson CommitDate: Mon Feb 26 16:04:36 2024 -0600 groff_man*(7): Clarify and tighten wording. Also fix duplicate word. Also tweak dead-tree pagination. diff --git a/tmac/groff_man.7.man.in b/tmac/groff_man.7.man.in index 3540b048b..4f0142aa7 100644 --- a/tmac/groff_man.7.man.in +++ b/tmac/groff_man.7.man.in @@ -422,7 +422,7 @@ .SS "Document structure macros" .RI [ footer-middle \~\c .RI [ footer-inside \~\c .RI [ header-middle ]]] -Determine the contents of the page header and footer. +Populate the page header and footer. _ifstyle()dnl . .I roff @@ -494,7 +494,7 @@ .SS "Document structure macros" .I an.tmac will supply text for it. . -The macro package may also abbreviate +This package may abbreviate .I identifier and .I footer-inside @@ -505,7 +505,7 @@ .SS "Document structure macros" if they would overrun the space available in the header and footer, respectively. . -For HTML output, +In HTML output, headers and footers are suppressed. . . @@ -2170,7 +2170,7 @@ .SS "Horizontal and vertical spacing" and the deprecated .BR .HP . . -The default inter-section and inter-paragraph spacing is +The default inter-section and inter-paragraph spacing is 1v for terminals and 0.4v for typesetters. _ifstyle()dnl \(lqv\(rq is a unit of vertical distance, @@ -3967,12 +3967,13 @@ .SH Notes The .MR man 1 librarian is designed to permit convenient access to man pages, -resolving topics to man page identifiers and sections. +resolving topics to man page identifiers. . Thus, you can type -.RB \(lq "man fprintf" \(rq -without having to know whether the installed document uses +.RB \(lq "man fprintf" \(rq, +and other pages can refer to it, +without knowing whether the installed document uses \(lqprintf\(rq, \(lqfprintf\(rq, or even \(lqc_printf\(rq @@ -4251,6 +4252,8 @@ .SH Notes .TE . . +.br +.ne 4v .IP \(bu Why doesn't the package provide a string to insert an ellipsis? .