From f10f0fe3970de778125a29d73e65e63f32c138e1 Mon Sep 17 00:00:00 2001 From: Ingo Schwarze Date: Fri, 13 Mar 2020 15:32:28 +0000 Subject: Split tagging into a validation part including prioritization in tag.{h,c} and {mdoc,man}_validate.c and into a formatting part including command line argument checking in term_tag.{h,c}, html.c, and {mdoc|man}_{term|html}.c. Immediate functional benefits include: * Improved prioritization of automatic tags for .Em and .Sy. * Avoiding bogus automatic tags when .Em, .Fn, or .Sy are explicitly tagged. * Explicit tagging of .Er and .Fl now works in HTML output. * Automatic tagging of .IP and .TP now works in HTML output. But mainly, this patch provides clean earth to build further improvements on. Technical changes: * Main program: Write a tag file for ASCII and UTF-8 output only. * All formatters: There is no more need to delay writing the tags. * mdoc(7)+man(7) formatters: No more need for elaborate syntax tree inspection. * HTML formatter: If available, use the "string" attribute as the tag. * HTML formatter: New function to write permalinks, to reduce code duplication. Style cleanup in the vicinity while here: * mdoc(7) terminal formatter: To set up bold font for children, defer to termp_bold_pre() rather than calling term_fontpush() manually. * mdoc(7) terminal formatter: Garbage collect some duplicate functions. * mdoc(7) HTML formatter: Unify handling, delete redundant functions. * Where possible, use switch statements rather than if cascades. * Get rid of some more Yoda notation. The necessity for such changes was first discussed with kn@, but i didn't bother him with a request to review the resulting -673/+782 line patch. --- Makefile | 21 +-- Makefile.depend | 15 +- html.c | 78 +++++++++-- html.h | 9 +- main.c | 37 ++--- man_html.c | 16 +-- man_term.c | 87 ++---------- man_validate.c | 108 ++++++++++++++- mandoc_headers.3 | 77 ++++++++--- mandoc_html.3 | 137 +++++++++++++++--- mdoc_html.c | 200 ++++++--------------------- mdoc_term.c | 284 +++++++++++--------------------------- mdoc_validate.c | 200 +++++++++++++++++---------- read.c | 13 +- regress/copyless | 14 ++ regress/man/IP/Makefile | 7 +- regress/man/IP/empty.in | 4 +- regress/man/IP/empty.out_ascii | 4 +- regress/man/IP/empty.out_html | 18 +++ regress/man/IP/empty.out_lint | 4 +- regress/man/IP/empty.out_tag | 3 + regress/man/IP/literal.out_html | 8 +- regress/man/IP/tag.in | 18 +++ regress/man/IP/tag.out_ascii | 23 +++ regress/man/IP/tag.out_html | 10 ++ regress/man/IP/tag.out_tag | 2 + regress/man/TP/Makefile | 7 +- regress/man/TP/literal.out_html | 4 +- regress/man/TP/tag.in | 31 +++++ regress/man/TP/tag.out_ascii | 29 ++++ regress/man/TP/tag.out_html | 16 +++ regress/man/TP/tag.out_tag | 3 + regress/man/TP/vert.out_html | 4 +- regress/mdoc/Cm/Makefile | 6 +- regress/mdoc/Cm/tag.in | 21 +++ regress/mdoc/Cm/tag.out_ascii | 17 +++ regress/mdoc/Cm/tag.out_html | 9 ++ regress/mdoc/Cm/tag.out_markdown | 23 +++ regress/mdoc/Cm/tag.out_tag | 4 + regress/mdoc/Dv/Makefile | 6 +- regress/mdoc/Dv/tag.in | 21 +++ regress/mdoc/Dv/tag.out_ascii | 17 +++ regress/mdoc/Dv/tag.out_html | 9 ++ regress/mdoc/Dv/tag.out_markdown | 23 +++ regress/mdoc/Dv/tag.out_tag | 4 + regress/mdoc/Em/Makefile | 6 +- regress/mdoc/Em/tag.in | 23 +++ regress/mdoc/Em/tag.out_ascii | 17 +++ regress/mdoc/Em/tag.out_html | 10 ++ regress/mdoc/Em/tag.out_markdown | 25 ++++ regress/mdoc/Em/tag.out_tag | 5 + regress/mdoc/Er/Makefile | 6 +- regress/mdoc/Er/tag.in | 21 +++ regress/mdoc/Er/tag.out_ascii | 16 +++ regress/mdoc/Er/tag.out_html | 12 ++ regress/mdoc/Er/tag.out_markdown | 25 ++++ regress/mdoc/Er/tag.out_tag | 2 + regress/mdoc/Ev/Makefile | 6 +- regress/mdoc/Ev/tag.in | 21 +++ regress/mdoc/Ev/tag.out_ascii | 17 +++ regress/mdoc/Ev/tag.out_html | 9 ++ regress/mdoc/Ev/tag.out_markdown | 23 +++ regress/mdoc/Ev/tag.out_tag | 4 + regress/mdoc/Fl/Makefile | 7 +- regress/mdoc/Fl/tag.in | 21 +++ regress/mdoc/Fl/tag.out_ascii | 17 +++ regress/mdoc/Fl/tag.out_html | 8 ++ regress/mdoc/Fl/tag.out_markdown | 23 +++ regress/mdoc/Fl/tag.out_tag | 4 + regress/mdoc/Fo/Makefile | 6 +- regress/mdoc/Fo/tag.in | 29 ++++ regress/mdoc/Fo/tag.out_ascii | 17 +++ regress/mdoc/Fo/tag.out_html | 9 ++ regress/mdoc/Fo/tag.out_markdown | 27 ++++ regress/mdoc/Fo/tag.out_tag | 4 + regress/mdoc/Ic/Makefile | 6 +- regress/mdoc/Ic/tag.in | 21 +++ regress/mdoc/Ic/tag.out_ascii | 17 +++ regress/mdoc/Ic/tag.out_html | 9 ++ regress/mdoc/Ic/tag.out_markdown | 23 +++ regress/mdoc/Ic/tag.out_tag | 4 + regress/mdoc/Li/Makefile | 6 +- regress/mdoc/Li/tag.in | 21 +++ regress/mdoc/Li/tag.out_ascii | 17 +++ regress/mdoc/Li/tag.out_html | 9 ++ regress/mdoc/Li/tag.out_markdown | 23 +++ regress/mdoc/Li/tag.out_tag | 4 + regress/mdoc/Makefile | 4 +- regress/mdoc/Ms/Makefile | 6 +- regress/mdoc/Ms/tag.in | 21 +++ regress/mdoc/Ms/tag.out_ascii | 17 +++ regress/mdoc/Ms/tag.out_html | 9 ++ regress/mdoc/Ms/tag.out_markdown | 23 +++ regress/mdoc/Ms/tag.out_tag | 4 + regress/mdoc/No/Makefile | 6 +- regress/mdoc/No/punct.out_lint | 1 + regress/mdoc/No/tag.in | 21 +++ regress/mdoc/No/tag.out_ascii | 17 +++ regress/mdoc/No/tag.out_html | 9 ++ regress/mdoc/No/tag.out_markdown | 23 +++ regress/mdoc/No/tag.out_tag | 4 + regress/mdoc/Sy/Makefile | 6 +- regress/mdoc/Sy/tag.in | 23 +++ regress/mdoc/Sy/tag.out_ascii | 17 +++ regress/mdoc/Sy/tag.out_html | 10 ++ regress/mdoc/Sy/tag.out_markdown | 25 ++++ regress/mdoc/Sy/tag.out_tag | 5 + regress/mdoc/Tg/Makefile | 8 ++ regress/mdoc/Tg/warn.in | 34 +++++ regress/mdoc/Tg/warn.out_ascii | 19 +++ regress/mdoc/Tg/warn.out_html | 11 ++ regress/mdoc/Tg/warn.out_lint | 6 + regress/mdoc/Tg/warn.out_markdown | 30 ++++ regress/mdoc/Tg/warn.out_tag | 5 + regress/regress.pl | 90 ++++++++---- regress/regress.pl.1 | 17 +-- tag.c | 280 ++++++++++--------------------------- tag.h | 29 ++-- term_tag.c | 206 +++++++++++++++++++++++++++ term_tag.h | 35 +++++ tree.c | 12 +- 121 files changed, 2347 insertions(+), 917 deletions(-) create mode 100755 regress/copyless create mode 100644 regress/man/IP/empty.out_html create mode 100644 regress/man/IP/empty.out_tag create mode 100644 regress/man/IP/tag.in create mode 100644 regress/man/IP/tag.out_ascii create mode 100644 regress/man/IP/tag.out_html create mode 100644 regress/man/IP/tag.out_tag create mode 100644 regress/man/TP/tag.in create mode 100644 regress/man/TP/tag.out_ascii create mode 100644 regress/man/TP/tag.out_html create mode 100644 regress/man/TP/tag.out_tag create mode 100644 regress/mdoc/Cm/tag.in create mode 100644 regress/mdoc/Cm/tag.out_ascii create mode 100644 regress/mdoc/Cm/tag.out_html create mode 100644 regress/mdoc/Cm/tag.out_markdown create mode 100644 regress/mdoc/Cm/tag.out_tag create mode 100644 regress/mdoc/Dv/tag.in create mode 100644 regress/mdoc/Dv/tag.out_ascii create mode 100644 regress/mdoc/Dv/tag.out_html create mode 100644 regress/mdoc/Dv/tag.out_markdown create mode 100644 regress/mdoc/Dv/tag.out_tag create mode 100644 regress/mdoc/Em/tag.in create mode 100644 regress/mdoc/Em/tag.out_ascii create mode 100644 regress/mdoc/Em/tag.out_html create mode 100644 regress/mdoc/Em/tag.out_markdown create mode 100644 regress/mdoc/Em/tag.out_tag create mode 100644 regress/mdoc/Er/tag.in create mode 100644 regress/mdoc/Er/tag.out_ascii create mode 100644 regress/mdoc/Er/tag.out_html create mode 100644 regress/mdoc/Er/tag.out_markdown create mode 100644 regress/mdoc/Er/tag.out_tag create mode 100644 regress/mdoc/Ev/tag.in create mode 100644 regress/mdoc/Ev/tag.out_ascii create mode 100644 regress/mdoc/Ev/tag.out_html create mode 100644 regress/mdoc/Ev/tag.out_markdown create mode 100644 regress/mdoc/Ev/tag.out_tag create mode 100644 regress/mdoc/Fl/tag.in create mode 100644 regress/mdoc/Fl/tag.out_ascii create mode 100644 regress/mdoc/Fl/tag.out_html create mode 100644 regress/mdoc/Fl/tag.out_markdown create mode 100644 regress/mdoc/Fl/tag.out_tag create mode 100644 regress/mdoc/Fo/tag.in create mode 100644 regress/mdoc/Fo/tag.out_ascii create mode 100644 regress/mdoc/Fo/tag.out_html create mode 100644 regress/mdoc/Fo/tag.out_markdown create mode 100644 regress/mdoc/Fo/tag.out_tag create mode 100644 regress/mdoc/Ic/tag.in create mode 100644 regress/mdoc/Ic/tag.out_ascii create mode 100644 regress/mdoc/Ic/tag.out_html create mode 100644 regress/mdoc/Ic/tag.out_markdown create mode 100644 regress/mdoc/Ic/tag.out_tag create mode 100644 regress/mdoc/Li/tag.in create mode 100644 regress/mdoc/Li/tag.out_ascii create mode 100644 regress/mdoc/Li/tag.out_html create mode 100644 regress/mdoc/Li/tag.out_markdown create mode 100644 regress/mdoc/Li/tag.out_tag create mode 100644 regress/mdoc/Ms/tag.in create mode 100644 regress/mdoc/Ms/tag.out_ascii create mode 100644 regress/mdoc/Ms/tag.out_html create mode 100644 regress/mdoc/Ms/tag.out_markdown create mode 100644 regress/mdoc/Ms/tag.out_tag create mode 100644 regress/mdoc/No/tag.in create mode 100644 regress/mdoc/No/tag.out_ascii create mode 100644 regress/mdoc/No/tag.out_html create mode 100644 regress/mdoc/No/tag.out_markdown create mode 100644 regress/mdoc/No/tag.out_tag create mode 100644 regress/mdoc/Sy/tag.in create mode 100644 regress/mdoc/Sy/tag.out_ascii create mode 100644 regress/mdoc/Sy/tag.out_html create mode 100644 regress/mdoc/Sy/tag.out_markdown create mode 100644 regress/mdoc/Sy/tag.out_tag create mode 100644 regress/mdoc/Tg/Makefile create mode 100644 regress/mdoc/Tg/warn.in create mode 100644 regress/mdoc/Tg/warn.out_ascii create mode 100644 regress/mdoc/Tg/warn.out_html create mode 100644 regress/mdoc/Tg/warn.out_lint create mode 100644 regress/mdoc/Tg/warn.out_markdown create mode 100644 regress/mdoc/Tg/warn.out_tag create mode 100644 term_tag.c create mode 100644 term_tag.h diff --git a/Makefile b/Makefile index f4e29540..e0b9a66b 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ -# $Id: Makefile,v 1.530 2019/03/06 16:08:41 schwarze Exp $ +# $Id: Makefile,v 1.531 2020/03/13 15:32:28 schwarze Exp $ # +# Copyright (c) 2011, 2013-2020 Ingo Schwarze # Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons -# Copyright (c) 2011, 2013-2019 Ingo Schwarze # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above @@ -134,6 +134,7 @@ SRCS = arch.c \ term_ascii.c \ term_ps.c \ term_tab.c \ + term_tag.c \ tree.c DISTFILES = INSTALL \ @@ -209,6 +210,7 @@ DISTFILES = INSTALL \ tbl_int.h \ tbl_parse.h \ term.h \ + term_tag.h \ $(SRCS) \ $(TESTSRCS) @@ -245,7 +247,8 @@ LIBMANDOC_OBJS = $(LIBMAN_OBJS) \ mandoc_xr.o \ msec.o \ preconv.o \ - read.o + read.o \ + tag.o COMPAT_OBJS = compat_err.o \ compat_fts.o \ @@ -280,6 +283,7 @@ MANDOC_TERM_OBJS = eqn_term.o \ term_ascii.o \ term_ps.o \ term_tab.o \ + term_tag.o \ tbl_term.o DBM_OBJS = dbm.o \ @@ -302,7 +306,6 @@ MAIN_OBJS = $(MANDOC_HTML_OBJS) \ mdoc_man.o \ mdoc_markdown.o \ out.o \ - tag.o \ tree.o CGI_OBJS = $(MANDOC_HTML_OBJS) \ @@ -313,8 +316,7 @@ CGI_OBJS = $(MANDOC_HTML_OBJS) \ MANDOCD_OBJS = $(MANDOC_HTML_OBJS) \ $(MANDOC_TERM_OBJS) \ mandocd.o \ - out.o \ - tag.o + out.o DEMANDOC_OBJS = demandoc.o @@ -393,7 +395,7 @@ distclean: clean clean: rm -f libmandoc.a $(LIBMANDOC_OBJS) $(COMPAT_OBJS) - rm -f mandoc $(MAIN_OBJS) + rm -f mandoc man $(MAIN_OBJS) rm -f man.cgi $(CGI_OBJS) rm -f mandocd catman catman.o $(MANDOCD_OBJS) rm -f demandoc $(DEMANDOC_OBJS) @@ -501,7 +503,7 @@ uninstall: rm -f $(DESTDIR)$(INCLUDEDIR)/tbl.h [ ! -e $(DESTDIR)$(INCLUDEDIR) ] || rmdir $(DESTDIR)$(INCLUDEDIR) -regress: all +regress: all man cd regress && ./regress.pl regress-clean: @@ -517,6 +519,9 @@ libmandoc.a: $(COMPAT_OBJS) $(LIBMANDOC_OBJS) mandoc: $(MAIN_OBJS) libmandoc.a $(CC) -o $@ $(LDFLAGS) $(MAIN_OBJS) libmandoc.a $(LDADD) +man: mandoc + $(LN) mandoc man + man.cgi: $(CGI_OBJS) libmandoc.a $(CC) $(STATIC) -o $@ $(LDFLAGS) $(CGI_OBJS) libmandoc.a $(LDADD) diff --git a/Makefile.depend b/Makefile.depend index 3540aeda..eb8606d5 100644 --- a/Makefile.depend +++ b/Makefile.depend @@ -33,12 +33,12 @@ eqn_html.o: eqn_html.c config.h mandoc.h roff.h eqn.h out.h html.h eqn_term.o: eqn_term.c config.h eqn.h out.h term.h html.o: html.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc.h roff.h out.h html.h manconf.h main.h lib.o: lib.c config.h roff.h libmdoc.h lib.in -main.o: main.c config.h mandoc_aux.h mandoc.h mandoc_xr.h roff.h mdoc.h man.h mandoc_parse.h tag.h main.h manconf.h mansearch.h +main.o: main.c config.h mandoc_aux.h mandoc.h mandoc_xr.h roff.h mdoc.h man.h mandoc_parse.h term_tag.h main.h manconf.h mansearch.h man.o: man.c config.h mandoc_aux.h mandoc.h roff.h man.h libmandoc.h roff_int.h libman.h man_html.o: man_html.c config.h mandoc_aux.h mandoc.h roff.h man.h out.h html.h main.h man_macro.o: man_macro.c config.h mandoc.h roff.h man.h libmandoc.h roff_int.h libman.h -man_term.o: man_term.c config.h mandoc_aux.h mandoc.h roff.h man.h out.h term.h tag.h main.h -man_validate.o: man_validate.c config.h mandoc_aux.h mandoc.h roff.h man.h libmandoc.h roff_int.h libman.h +man_term.o: man_term.c config.h mandoc_aux.h mandoc.h roff.h man.h out.h term.h term_tag.h main.h +man_validate.o: man_validate.c config.h mandoc_aux.h mandoc.h roff.h tag.h man.h libmandoc.h roff_int.h libman.h mandoc.o: mandoc.c config.h mandoc_aux.h mandoc.h roff.h libmandoc.h roff_int.h mandoc_aux.o: mandoc_aux.c config.h mandoc.h mandoc_aux.h mandoc_msg.o: mandoc_msg.c config.h mandoc.h @@ -55,19 +55,19 @@ mdoc_macro.o: mdoc_macro.c config.h mandoc.h roff.h mdoc.h libmandoc.h roff_int. mdoc_man.o: mdoc_man.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h man.h out.h main.h mdoc_markdown.o: mdoc_markdown.c mandoc_aux.h mandoc.h roff.h mdoc.h main.h mdoc_state.o: mdoc_state.c mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h -mdoc_term.o: mdoc_term.c config.h mandoc_aux.h roff.h mdoc.h out.h term.h tag.h main.h -mdoc_validate.o: mdoc_validate.c config.h mandoc_aux.h mandoc.h mandoc_xr.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h +mdoc_term.o: mdoc_term.c config.h mandoc_aux.h roff.h mdoc.h out.h term.h term_tag.h main.h +mdoc_validate.o: mdoc_validate.c config.h mandoc_aux.h mandoc.h mandoc_xr.h roff.h tag.h mdoc.h libmandoc.h roff_int.h libmdoc.h msec.o: msec.c config.h mandoc.h libmandoc.h msec.in out.o: out.c config.h mandoc_aux.h tbl.h out.h preconv.o: preconv.c config.h mandoc.h roff.h mandoc_parse.h libmandoc.h -read.o: read.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h man.h mandoc_parse.h libmandoc.h roff_int.h +read.o: read.c config.h mandoc_aux.h mandoc.h roff.h tag.h mdoc.h man.h mandoc_parse.h libmandoc.h roff_int.h roff.o: roff.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc.h roff.h mandoc_parse.h libmandoc.h roff_int.h tbl_parse.h eqn_parse.h predefs.in roff_html.o: roff_html.c mandoc.h roff.h out.h html.h roff_term.o: roff_term.c mandoc.h roff.h out.h term.h roff_validate.o: roff_validate.c mandoc.h roff.h libmandoc.h roff_int.h soelim.o: soelim.c config.h compat_stringlist.h st.o: st.c config.h mandoc.h roff.h libmdoc.h -tag.o: tag.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc.h tag.h +tag.o: tag.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h roff.h tag.h tbl.o: tbl.c config.h mandoc_aux.h mandoc.h tbl.h libmandoc.h tbl_parse.h tbl_int.h tbl_data.o: tbl_data.c config.h mandoc_aux.h mandoc.h tbl.h libmandoc.h tbl_int.h tbl_html.o: tbl_html.c config.h mandoc.h roff.h tbl.h out.h html.h @@ -78,4 +78,5 @@ term.o: term.c config.h mandoc.h mandoc_aux.h out.h term.h main.h term_ascii.o: term_ascii.c config.h mandoc.h mandoc_aux.h out.h term.h manconf.h main.h term_ps.o: term_ps.c config.h mandoc_aux.h out.h term.h manconf.h main.h term_tab.o: term_tab.c mandoc_aux.h out.h term.h +term_tag.o: term_tag.c config.h mandoc.h roff.h tag.h term_tag.h tree.o: tree.c config.h mandoc.h roff.h mdoc.h man.h tbl.h eqn.h main.h diff --git a/html.c b/html.c index babe237c..769acce8 100644 --- a/html.c +++ b/html.c @@ -1,7 +1,7 @@ -/* $Id: html.c,v 1.263 2020/02/27 22:28:13 schwarze Exp $ */ +/* $Id: html.c,v 1.264 2020/03/13 15:32:28 schwarze Exp $ */ /* - * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons * Copyright (c) 2011-2015, 2017-2020 Ingo Schwarze + * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -14,6 +14,9 @@ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Common functions for mandoc(1) HTML formatters. + * For use by individual formatters and by the main program. */ #include "config.h" @@ -321,6 +324,18 @@ html_fillmode(struct html *h, enum roff_tok want) return had; } +/* + * Allocate a string to be used for the "id=" attribute of an HTML + * element and/or as a segment identifier for a URI in an element. + * The function may fail and return NULL if the node lacks text data + * to create the attribute from. + * If the "unique" argument is 0, the caller is responsible for + * free(3)ing the returned string after using it. + * If the "unique" argument is non-zero, the "id_unique" ohash table + * is used for de-duplication and owns the returned string, so the + * caller must not free(3) it. In this case, it will be freed + * automatically by html_reset() or html_free(). + */ char * html_make_id(const struct roff_node *n, int unique) { @@ -329,14 +344,30 @@ html_make_id(const struct roff_node *n, int unique) unsigned int slot; int suffix; - for (nch = n->child; nch != NULL; nch = nch->next) - if (nch->type != ROFFT_TEXT) - return NULL; - - buf = NULL; - deroff(&buf, n); - if (buf == NULL) - return NULL; + if (n->string != NULL) + buf = mandoc_strdup(n->string); + else { + switch (n->tok) { + case MDOC_Sh: + case MDOC_Ss: + case MDOC_Sx: + case MAN_SH: + case MAN_SS: + for (nch = n->child; nch != NULL; nch = nch->next) + if (nch->type != ROFFT_TEXT) + return NULL; + buf = NULL; + deroff(&buf, n); + if (buf == NULL) + return NULL; + break; + default: + if (n->child->type != ROFFT_TEXT) + return NULL; + buf = mandoc_strdup(n->child->string); + break; + } + } /* * In ID attributes, only use ASCII characters that are @@ -736,6 +767,33 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...) return t; } +/* + * Print an element with an optional "id=" attribute. + * If there is an "id=" attribute, also add a permalink: + * outside if it's a phrasing element, or inside otherwise. + */ +struct tag * +print_otag_id(struct html *h, enum htmltag elemtype, const char *cattr, + struct roff_node *n) +{ + struct tag *ret, *t; + const char *id; + + ret = NULL; + id = NULL; + if (n->flags & NODE_ID) + id = html_make_id(n, 1); + if (id != NULL && htmltags[elemtype].flags & HTML_INPHRASE) + ret = print_otag(h, TAG_A, "chR", "permalink", id); + t = print_otag(h, elemtype, "ci", cattr, id); + if (ret == NULL) { + ret = t; + if (id != NULL) + print_otag(h, TAG_A, "chR", "permalink", id); + } + return ret; +} + static void print_ctag(struct html *h, struct tag *tag) { diff --git a/html.h b/html.h index ac463b97..d9e65912 100644 --- a/html.h +++ b/html.h @@ -1,7 +1,7 @@ -/* $Id: html.h,v 1.106 2020/01/19 18:02:00 schwarze Exp $ */ +/* $Id: html.h,v 1.107 2020/03/13 15:32:28 schwarze Exp $ */ /* + * Copyright (c) 2017, 2018, 2019, 2020 Ingo Schwarze * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons - * Copyright (c) 2017, 2018, 2019 Ingo Schwarze * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -14,6 +14,9 @@ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Internal interfaces for mandoc(1) HTML formatters. + * For use by the individual HTML formatters only. */ enum htmltag { @@ -120,6 +123,8 @@ void print_gen_comment(struct html *, struct roff_node *); void print_gen_decls(struct html *); void print_gen_head(struct html *); struct tag *print_otag(struct html *, enum htmltag, const char *, ...); +struct tag *print_otag_id(struct html *, enum htmltag, const char *, + struct roff_node *); void print_tagq(struct html *, const struct tag *); void print_stagq(struct html *, const struct tag *); void print_text(struct html *, const char *); diff --git a/main.c b/main.c index 862eb9bf..8c3ded9b 100644 --- a/main.c +++ b/main.c @@ -1,7 +1,7 @@ -/* $Id: main.c,v 1.344 2020/02/24 21:16:31 schwarze Exp $ */ +/* $Id: main.c,v 1.345 2020/03/13 15:32:28 schwarze Exp $ */ /* - * Copyright (c) 2008-2012 Kristaps Dzonsons * Copyright (c) 2010-2012, 2014-2020 Ingo Schwarze + * Copyright (c) 2008-2012 Kristaps Dzonsons * Copyright (c) 2010 Joerg Sonnenberger * * Permission to use, copy, modify, and distribute this software for any @@ -15,6 +15,8 @@ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Main program for mandoc(1), man(1), apropos(1), whatis(1), and help(1). */ #include "config.h" @@ -52,7 +54,7 @@ #include "mdoc.h" #include "man.h" #include "mandoc_parse.h" -#include "tag.h" +#include "term_tag.h" #include "main.h" #include "manconf.h" #include "mansearch.h" @@ -598,7 +600,6 @@ main(int argc, char *argv[]) * readable: Maybe it won't be needed after all. */ startdir = open(".", O_RDONLY | O_DIRECTORY); - for (i = 0; i < ressz; i++) { process_onefile(mp, res + i, startdir, &outst, &conf); if (outst.wstop && mandoc_msg_getrc() != MANDOCLEVEL_OK) @@ -608,7 +609,6 @@ main(int argc, char *argv[]) (void)fchdir(startdir); close(startdir); } - if (outst.outdata != NULL) { switch (outst.outtype) { case OUTT_HTML: @@ -617,6 +617,7 @@ main(int argc, char *argv[]) case OUTT_UTF8: case OUTT_LOCALE: case OUTT_ASCII: + term_tag_finish(); ascii_free(outst.outdata); break; case OUTT_PDF: @@ -638,9 +639,8 @@ out: if (outst.tag_files != NULL) { fclose(stdout); - tag_write(); run_pager(outst.tag_files); - tag_unlink(); + term_tag_unlink(); } else if (outst.had_output && outst.outtype != OUTT_LINT) mandoc_msg_summary(); @@ -831,15 +831,16 @@ process_onefile(struct mparse *mp, struct manpage *resp, int startdir, } else fd = STDIN_FILENO; - if (outst->use_pager) { - outst->use_pager = 0; - outst->tag_files = tag_init(conf->output.tag); - } - - if (outst->had_output && outst->outtype <= OUTT_UTF8) { - if (outst->outdata == NULL) - outdata_alloc(outst, &conf->output); - terminal_sepline(outst->outdata); + if (outst->outtype <= OUTT_UTF8) { + if (outst->use_pager) { + outst->use_pager = 0; + outst->tag_files = term_tag_init(conf->output.tag); + } + if (outst->had_output) { + if (outst->outdata == NULL) + outdata_alloc(outst, &conf->output); + terminal_sepline(outst->outdata); + } } if (resp->form == FORM_SRC) @@ -853,7 +854,7 @@ process_onefile(struct mparse *mp, struct manpage *resp, int startdir, if (outst->tag_files != NULL) { mandoc_msg(MANDOCERR_WRITE, 0, 0, "%s: %s", outst->tag_files->ofn, strerror(errno)); - tag_unlink(); + term_tag_unlink(); outst->tag_files = NULL; } else mandoc_msg(MANDOCERR_WRITE, 0, 0, "%s", @@ -1278,7 +1279,7 @@ spawn_pager(struct tag_files *tag_files) _exit(mandoc_msg_getrc()); } close(tag_files->ofd); - assert(tag_files->tfd == -1); + assert(tag_files->tfs == NULL); /* Do not start the pager before controlling the terminal. */ diff --git a/man_html.c b/man_html.c index 8d5e03c4..202df2b7 100644 --- a/man_html.c +++ b/man_html.c @@ -1,7 +1,7 @@ -/* $Id: man_html.c,v 1.176 2020/02/27 01:43:52 schwarze Exp $ */ +/* $Id: man_html.c,v 1.177 2020/03/13 15:32:28 schwarze Exp $ */ /* - * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons * Copyright (c) 2013-2015, 2017-2020 Ingo Schwarze + * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -14,6 +14,8 @@ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * HTML formatter for man(7) used by mandoc(1). */ #include "config.h" @@ -310,7 +312,6 @@ static int man_SH_pre(MAN_ARGS) { const char *class; - char *id; enum htmltag tag; if (n->tok == MAN_SH) { @@ -326,10 +327,8 @@ man_SH_pre(MAN_ARGS) print_otag(h, TAG_SECTION, "c", class); break; case ROFFT_HEAD: - id = html_make_id(n, 1); - print_otag(h, tag, "ci", class, id); - if (id != NULL) - print_otag(h, TAG_A, "chR", "permalink", id); + n->flags |= NODE_ID; + print_otag_id(h, tag, class, n); break; case ROFFT_BODY: break; @@ -489,7 +488,7 @@ man_IP_pre(MAN_ARGS) case ROFFT_HEAD: if (body_elem == TAG_LI) return 0; - print_otag(h, TAG_DT, ""); + print_otag_id(h, TAG_DT, NULL, n); break; case ROFFT_BODY: print_otag(h, body_elem, ""); @@ -497,7 +496,6 @@ man_IP_pre(MAN_ARGS) default: abort(); } - switch(n->tok) { case MAN_IP: /* Only print the first header element. */ if (n->child != NULL) diff --git a/man_term.c b/man_term.c index 4a78d5c4..b71d6bee 100644 --- a/man_term.c +++ b/man_term.c @@ -1,7 +1,7 @@ -/* $Id: man_term.c,v 1.234 2020/02/27 01:43:52 schwarze Exp $ */ +/* $Id: man_term.c,v 1.235 2020/03/13 15:32:28 schwarze Exp $ */ /* - * Copyright (c) 2008-2012 Kristaps Dzonsons * Copyright (c) 2010-2015, 2017-2020 Ingo Schwarze + * Copyright (c) 2008-2012 Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -14,6 +14,9 @@ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Plain text formatter for man(7), used by mandoc(1) + * for ASCII, UTF-8, PostScript, and PDF output. */ #include "config.h" @@ -32,7 +35,7 @@ #include "man.h" #include "out.h" #include "term.h" -#include "tag.h" +#include "term_tag.h" #include "main.h" #define MAXMARGINS 64 /* maximum number of indented scopes */ @@ -94,8 +97,6 @@ static void post_SY(DECL_ARGS); static void post_TP(DECL_ARGS); static void post_UR(DECL_ARGS); -static void tag_man(struct termp *, struct roff_node *); - static const struct man_term_act man_term_acts[MAN_MAX - MAN_TH] = { { NULL, NULL, 0 }, /* TH */ { pre_SH, post_SH, 0 }, /* SH */ @@ -539,10 +540,8 @@ pre_IP(DECL_ARGS) case ROFFT_HEAD: p->tcol->offset = mt->offset; p->tcol->rmargin = mt->offset + len; - if (n->child != NULL) { + if (n->child != NULL) print_man_node(p, mt, n->child, meta); - tag_man(p, n->child); - } return 0; case ROFFT_BODY: p->tcol->offset = mt->offset + len; @@ -622,18 +621,6 @@ pre_TP(DECL_ARGS) while (nn != NULL && (nn->flags & NODE_LINE) == 0) nn = nn->next; - if (nn == NULL) - return 0; - - if (nn->type == ROFFT_TEXT) - tag_man(p, nn); - else if (nn->child != NULL && - nn->child->type == ROFFT_TEXT && - (nn->tok == MAN_B || nn->tok == MAN_BI || - nn->tok == MAN_BR || nn->tok == MAN_I || - nn->tok == MAN_IB || nn->tok == MAN_IR)) - tag_man(p, nn->child); - while (nn != NULL) { print_man_node(p, mt, nn, meta); nn = nn->next; @@ -913,6 +900,9 @@ print_man_node(DECL_ARGS) const struct man_term_act *act; int c; + if (n->flags & NODE_ID) + term_tag_write(n, p->line); + switch (n->type) { case ROFFT_TEXT: /* @@ -1159,60 +1149,3 @@ print_man_head(struct termp *p, const struct roff_meta *meta) } free(title); } - -/* - * Skip leading whitespace, dashes, backslashes, and font escapes, - * then create a tag if the first following byte is a letter. - * Priority is high unless whitespace is present. - */ -static void -tag_man(struct termp *p, struct roff_node *n) -{ - const char *cp, *arg; - int prio, sz; - - assert(n->type == ROFFT_TEXT); - cp = n->string; - prio = TAG_STRONG; - for (;;) { - switch (*cp) { - case ' ': - case '\t': - prio = TAG_WEAK; - /* FALLTHROUGH */ - case '-': - cp++; - break; - case '\\': - cp++; - switch (mandoc_escape(&cp, &arg, &sz)) { - case ESCAPE_FONT: - case ESCAPE_FONTROMAN: - case ESCAPE_FONTITALIC: - case ESCAPE_FONTBOLD: - case ESCAPE_FONTPREV: - case ESCAPE_FONTBI: - break; - case ESCAPE_SPECIAL: - if (sz != 1) - return; - switch (*arg) { - case '&': - case '-': - case 'e': - break; - default: - return; - } - break; - default: - return; - } - break; - default: - if (isalpha((unsigned char)*cp)) - tag_put(cp, prio, p->line); - return; - } - } -} diff --git a/man_validate.c b/man_validate.c index 374793e4..0c2ed8a4 100644 --- a/man_validate.c +++ b/man_validate.c @@ -1,7 +1,7 @@ -/* $Id: man_validate.c,v 1.150 2020/01/19 16:44:50 schwarze Exp $ */ +/* $Id: man_validate.c,v 1.151 2020/03/13 15:32:28 schwarze Exp $ */ /* - * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons * Copyright (c) 2010, 2012-2020 Ingo Schwarze + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -14,6 +14,8 @@ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Validation module for man(7) syntax trees used by mandoc(1). */ #include "config.h" @@ -32,6 +34,7 @@ #include "mandoc_aux.h" #include "mandoc.h" #include "roff.h" +#include "tag.h" #include "man.h" #include "libmandoc.h" #include "roff_int.h" @@ -45,6 +48,7 @@ static void check_abort(CHKARGS) __attribute__((__noreturn__)); static void check_par(CHKARGS); static void check_part(CHKARGS); static void check_root(CHKARGS); +static void check_tag(struct roff_node *, struct roff_node *); static void check_text(CHKARGS); static void post_AT(CHKARGS); @@ -54,6 +58,7 @@ static void post_IP(CHKARGS); static void post_OP(CHKARGS); static void post_SH(CHKARGS); static void post_TH(CHKARGS); +static void post_TP(CHKARGS); static void post_UC(CHKARGS); static void post_UR(CHKARGS); static void post_in(CHKARGS); @@ -62,8 +67,8 @@ static const v_check man_valids[MAN_MAX - MAN_TH] = { post_TH, /* TH */ post_SH, /* SH */ post_SH, /* SS */ - NULL, /* TP */ - NULL, /* TQ */ + post_TP, /* TP */ + post_TP, /* TQ */ check_abort,/* LP */ check_par, /* PP */ check_abort,/* P */ @@ -201,6 +206,66 @@ check_abort(CHKARGS) abort(); } +/* + * Skip leading whitespace, dashes, backslashes, and font escapes, + * then create a tag if the first following byte is a letter. + * Priority is high unless whitespace is present. + */ +static void +check_tag(struct roff_node *n, struct roff_node *nt) +{ + const char *cp, *arg; + int prio, sz; + + if (nt == NULL || nt->type != ROFFT_TEXT) + return; + + cp = nt->string; + prio = TAG_STRONG; + for (;;) { + switch (*cp) { + case ' ': + case '\t': + prio = TAG_WEAK; + /* FALLTHROUGH */ + case '-': + cp++; + break; + case '\\': + cp++; + switch (mandoc_escape(&cp, &arg, &sz)) { + case ESCAPE_FONT: + case ESCAPE_FONTBOLD: + case ESCAPE_FONTITALIC: + case ESCAPE_FONTBI: + case ESCAPE_FONTROMAN: + case ESCAPE_FONTCW: + case ESCAPE_FONTPREV: + case ESCAPE_IGNORE: + break; + case ESCAPE_SPECIAL: + if (sz != 1) + return; + switch (*arg) { + case '-': + case 'e': + break; + default: + return; + } + break; + default: + return; + } + break; + default: + if (isalpha((unsigned char)*cp)) + tag_put(cp, prio, n); + return; + } + } +} + static void check_text(CHKARGS) { @@ -332,12 +397,14 @@ check_par(CHKARGS) static void post_IP(CHKARGS) { - switch (n->type) { case ROFFT_BLOCK: if (n->head->child == NULL && n->body->child == NULL) roff_node_delete(man, n); break; + case ROFFT_HEAD: + check_tag(n, n->child); + break; case ROFFT_BODY: if (n->parent->head->child == NULL && n->child == NULL) mandoc_msg(MANDOCERR_PAR_SKIP, n->line, n->pos, @@ -348,6 +415,37 @@ post_IP(CHKARGS) } } +/* + * The first next-line element in the head is the tag. + * If that's a font macro, use its first child instead. + */ +static void +post_TP(CHKARGS) +{ + struct roff_node *nt; + + if (n->type != ROFFT_HEAD || (nt = n->child) == NULL) + return; + + while ((nt->flags & NODE_LINE) == 0) + if ((nt = nt->next) == NULL) + return; + + switch (nt->tok) { + case MAN_B: + case MAN_BI: + case MAN_BR: + case MAN_I: + case MAN_IB: + case MAN_IR: + nt = nt->child; + break; + default: + break; + } + check_tag(n, nt); +} + static void post_TH(CHKARGS) { diff --git a/mandoc_headers.3 b/mandoc_headers.3 index 1632b07c..36a8a58d 100644 --- a/mandoc_headers.3 +++ b/mandoc_headers.3 @@ -1,6 +1,6 @@ -.\" $Id: mandoc_headers.3,v 1.32 2020/01/20 10:37:15 schwarze Exp $ +.\" $Id: mandoc_headers.3,v 1.33 2020/03/13 15:32:28 schwarze Exp $ .\" -.\" Copyright (c) 2014-2019 Ingo Schwarze +.\" Copyright (c) 2014-2020 Ingo Schwarze .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: January 20 2020 $ +.Dd $Mdocdate: March 13 2020 $ .Dt MANDOC_HEADERS 3 .Os .Sh NAME @@ -232,6 +232,30 @@ and the functions .Fn mandoc_xr_get , and .Fn mandoc_xr_free . +.It Qq Pa tag.h +Internal interfaces to tag syntax tree nodes, +for use by validation modules only. +.Pp +Requires +.In limits.h +for +.Dv INT_MAX . +.Pp +Provides the functions +.Fn tag_alloc , +.Fn tag_put , +.Fn tag_check , +and +.Fn tag_free +and some +.Dv TAG_* +constants. +.Pp +Uses the type +.Vt struct roff_node +from +.Qq Pa roff.h +as an opaque type for function prototypes. .El .Pp The following two require @@ -587,6 +611,33 @@ When this header is included, the same file should not include .Qq Pa html.h or .Qq Pa mansearch.h . +.It Qq Pa tag_term.h +Requires +.In sys/types.h +for +.Vt size_t +and +.In stdio.h +for +.Vt FILE . +.Pp +Provides an interface to generate +.Xr ctags 1 +files for the +.Ic :t +functionality mentioned in +.Xr man 1 . +.Pp +Uses the type +.Vt struct roff_node +from +.Qq Pa roff.h +as an opaque type for function prototypes. +.Pp +When this header is included, the same file should not include +.Qq Pa html.h +or +.Qq Pa mansearch.h . .It Qq Pa html.h Requires .In sys/types.h @@ -629,25 +680,10 @@ from as opaque types for function prototypes. .Pp When this header is included, the same file should not include -.Qq Pa term.h +.Qq Pa term.h , +.Qq Pa tab_term.h , or .Qq Pa mansearch.h . -.It Qq Pa tag.h -Requires -.In sys/types.h -for -.Vt size_t -and -.In limits.h -for -.Dv INT_MAX . -.Pp -Provides an interface to generate -.Xr ctags 1 -files for the -.Ic :t -functionality mentioned in -.Xr man 1 . .It Qq Pa main.h Provides the top level steering functions for all formatters. .Pp @@ -700,6 +736,7 @@ as an opaque type for function prototypes. When this header is included, the same file should not include .Qq Pa out.h , .Qq Pa term.h , +.Qq Pa tab_term.h , or .Qq Pa html.h . .El diff --git a/mandoc_html.3 b/mandoc_html.3 index 32407574..e3d6f88e 100644 --- a/mandoc_html.3 +++ b/mandoc_html.3 @@ -1,4 +1,4 @@ -.\" $Id: mandoc_html.3,v 1.19 2019/01/11 12:56:43 schwarze Exp $ +.\" $Id: mandoc_html.3,v 1.20 2020/03/13 15:32:28 schwarze Exp $ .\" .\" Copyright (c) 2014, 2017, 2018 Ingo Schwarze .\" @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: January 11 2019 $ +.Dd $Mdocdate: March 13 2020 $ .Dt MANDOC_HTML 3 .Os .Sh NAME @@ -53,10 +53,14 @@ .Ft char * .Fo html_make_id .Fa "const struct roff_node *n" +.Fa "int unique" .Fc -.Ft int -.Fo html_strlen -.Fa "const char *cp" +.Ft struct tag * +.Fo print_otag_id +.Fa "struct html *h" +.Fa "enum htmltag tag" +.Fa "const char *cattr" +.Fa "struct roff_node *n" .Fc .Sh DESCRIPTION The mandoc HTML formatter is not a formal library. @@ -257,23 +261,77 @@ functions. .Pp The function .Fn html_make_id -takes a node containing one or more text children -and returns a newly allocated string containing the concatenation -of the child strings, with blanks replaced by underscores. -If the node +allocates a string to be used for the +.Cm id +attribute of an HTML element and/or as a segment identifier for a URI in an +.Aq Ic A +element. +If .Fa n -contains any non-text child node, -.Fn html_make_id -returns +contains a +.Fa string +attribute, it is used; otherwise, child nodes are used. +If +.Fa n +is an +.Ic \&Sh , +.Ic \&Ss , +.Ic \&Sx , +.Ic SH , +or +.Ic SS +node, the resulting string is the concatenation of the child strings; +for other node types, only the first child is used. +Bytes not permitted in URI-fragment strings are replaced by underscores. +If any of the children to be used is not a text node, +no string is generated and .Dv NULL -instead. -The caller is responsible for freeing the returned string. +is returned instead. +If the +.Fa unique +argument is non-zero, deduplication is performed by appending an +underscore and a decimal integer, if necessary. .Pp The function -.Fn html_strlen -counts the number of characters in -.Fa cp . -It is used as a crude estimate of the width needed to display a string. +.Fn print_otag_id +opens a +.Fa tag +element of class +.Fa cattr +for the node +.Fa n . +If the flag +.Dv NODE_ID +is set in +.Fa n , +it attempts to generate an +.Cm id +attribute with +.Fn html_make_id . +If an +.Cm id +attribute is written, +.Fn print_otag_id +also adds an +.Aq Ic A +element of class +.Qq permalink : +outside if +.Fa n +generates a phrasing element, or inside otherwise. +This function is a wrapper around +.Fn html_make_id +and +.Fn print_otag , +fixing the +.Fa unique +argument to 1 and the +.Fa fmt +arguments to +.Qq chR +and +.Qq ci , +respectively. .Pp The functions .Fn print_eqn , @@ -281,6 +339,49 @@ The functions and .Fn print_tblclose are not yet documented. +.Sh RETURN VALUES +The functions +.Fn print_otag +and +.Fn print_otag_id +return a pointer to a new element on the stack of HTML elements. +When +.Fn print_otag_id +opens two elements, a pointer to the outer one is returned. +The memory pointed to is owned by the library and is automatically +.Xr free 3 Ns d +when +.Fn print_tagq +is called on it or when +.Fn print_stagq +is called on a parent element. +.Pp +The function +.Fn html_make_id +returns a newly allocated string or +.Dv NULL +if +.Fa n +lacks text data to create the attribute from. +If the +.Fa unique +argument is 0, the caller is responsible for +.Xr free 3 Ns ing +the returned string after using it. +If the +.Fa unique +argument is non-zero, the +.Va id_unique +ohash table is used for de-duplication and owns the returned string. +In this case, it will be freed automatically by +.Fn html_reset +or +.Fn html_free . +.Pp +In case of +.Xr malloc 3 +failure, these functions do not return but call +.Xr err 3 . .Sh FILES .Bl -tag -width mandoc_aux.c -compact .It Pa main.h diff --git a/mdoc_html.c b/mdoc_html.c index 65bd8e03..8ae8703f 100644 --- a/mdoc_html.c +++ b/mdoc_html.c @@ -1,7 +1,7 @@ -/* $Id: mdoc_html.c,v 1.335 2020/02/27 22:28:13 schwarze Exp $ */ +/* $Id: mdoc_html.c,v 1.336 2020/03/13 15:32:28 schwarze Exp $ */ /* - * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons * Copyright (c) 2014-2020 Ingo Schwarze + * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -14,6 +14,8 @@ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * HTML formatter for mdoc(7) used by mandoc(1). */ #include "config.h" @@ -47,7 +49,6 @@ struct mdoc_html_act { void (*post)(MDOC_ARGS); }; -static char *cond_id(const struct roff_node *); static void print_mdoc_head(const struct roff_meta *, struct html *); static void print_mdoc_node(MDOC_ARGS); @@ -72,9 +73,8 @@ static void mdoc_bk_post(MDOC_ARGS); static int mdoc_bk_pre(MDOC_ARGS); static int mdoc_bl_pre(MDOC_ARGS); static int mdoc_cd_pre(MDOC_ARGS); -static int mdoc_cm_pre(MDOC_ARGS); +static int mdoc_code_pre(MDOC_ARGS); static int mdoc_d1_pre(MDOC_ARGS); -static int mdoc_dv_pre(MDOC_ARGS); static int mdoc_fa_pre(MDOC_ARGS); static int mdoc_fd_pre(MDOC_ARGS); static int mdoc_fl_pre(MDOC_ARGS); @@ -83,20 +83,15 @@ static int mdoc_ft_pre(MDOC_ARGS); static int mdoc_em_pre(MDOC_ARGS); static void mdoc_eo_post(MDOC_ARGS); static int mdoc_eo_pre(MDOC_ARGS); -static int mdoc_er_pre(MDOC_ARGS); -static int mdoc_ev_pre(MDOC_ARGS); static int mdoc_ex_pre(MDOC_ARGS); static void mdoc_fo_post(MDOC_ARGS); static int mdoc_fo_pre(MDOC_ARGS); -static int mdoc_ic_pre(MDOC_ARGS); static int mdoc_igndelim_pre(MDOC_ARGS); static int mdoc_in_pre(MDOC_ARGS); static int mdoc_it_pre(MDOC_ARGS); static int mdoc_lb_pre(MDOC_ARGS); -static int mdoc_li_pre(MDOC_ARGS); static int mdoc_lk_pre(MDOC_ARGS); static int mdoc_mt_pre(MDOC_ARGS); -static int mdoc_ms_pre(MDOC_ARGS); static int mdoc_nd_pre(MDOC_ARGS); static int mdoc_nm_pre(MDOC_ARGS); static int mdoc_no_pre(MDOC_ARGS); @@ -139,19 +134,19 @@ static const struct mdoc_html_act mdoc_html_acts[MDOC_MAX - MDOC_Dd] = { {mdoc_ap_pre, NULL}, /* Ap */ {mdoc_ar_pre, NULL}, /* Ar */ {mdoc_cd_pre, NULL}, /* Cd */ - {mdoc_cm_pre, NULL}, /* Cm */ - {mdoc_dv_pre, NULL}, /* Dv */ - {mdoc_er_pre, NULL}, /* Er */ - {mdoc_ev_pre, NULL}, /* Ev */ + {mdoc_code_pre, NULL}, /* Cm */ + {mdoc_code_pre, NULL}, /* Dv */ + {mdoc_code_pre, NULL}, /* Er */ + {mdoc_code_pre, NULL}, /* Ev */ {mdoc_ex_pre, NULL}, /* Ex */ {mdoc_fa_pre, NULL}, /* Fa */ {mdoc_fd_pre, NULL}, /* Fd */ {mdoc_fl_pre, NULL}, /* Fl */ {mdoc_fn_pre, NULL}, /* Fn */ {mdoc_ft_pre, NULL}, /* Ft */ - {mdoc_ic_pre, NULL}, /* Ic */ + {mdoc_code_pre, NULL}, /* Ic */ {mdoc_in_pre, NULL}, /* In */ - {mdoc_li_pre, NULL}, /* Li */ + {mdoc_code_pre, NULL}, /* Li */ {mdoc_nd_pre, NULL}, /* Nd */ {mdoc_nm_pre, NULL}, /* Nm */ {mdoc_quote_pre, mdoc_quote_post}, /* Op */ @@ -192,7 +187,7 @@ static const struct mdoc_html_act mdoc_html_acts[MDOC_MAX - MDOC_Dd] = { {mdoc_em_pre, NULL}, /* Em */ {mdoc_eo_pre, mdoc_eo_post}, /* Eo */ {mdoc_xx_pre, NULL}, /* Fx */ - {mdoc_ms_pre, NULL}, /* Ms */ + {mdoc_no_pre, NULL}, /* Ms */ {mdoc_no_pre, NULL}, /* No */ {mdoc_ns_pre, NULL}, /* Ns */ {mdoc_xx_pre, NULL}, /* Nx */ @@ -507,20 +502,11 @@ mdoc_root_pre(const struct roff_meta *meta, struct html *h) return 1; } -static char * -cond_id(const struct roff_node *n) +static int +mdoc_code_pre(MDOC_ARGS) { - if (n->child != NULL && - n->child->type == ROFFT_TEXT && - (n->prev == NULL || - (n->prev->type == ROFFT_TEXT && - strcmp(n->prev->string, "|") == 0)) && - (n->parent->tok == MDOC_It || - (n->parent->tok == MDOC_Xo && - n->parent->parent->prev == NULL && - n->parent->parent->parent->tok == MDOC_It))) - return html_make_id(n, 1); - return NULL; + print_otag_id(h, TAG_CODE, roff_name[n->tok], n); + return 1; } static int @@ -583,10 +569,8 @@ mdoc_sh_pre(MDOC_ARGS) print_otag(h, TAG_SECTION, "c", "Sh"); break; case ROFFT_HEAD: - id = html_make_id(n, 1); - print_otag(h, TAG_H1, "ci", "Sh", id); - if (id != NULL) - print_otag(h, TAG_A, "chR", "permalink", id); + n->flags |= NODE_ID; + print_otag_id(h, TAG_H1, "Sh", n); break; case ROFFT_BODY: if (n->sec == SEC_AUTHORS) @@ -601,25 +585,20 @@ mdoc_sh_pre(MDOC_ARGS) static int mdoc_ss_pre(MDOC_ARGS) { - char *id; - switch (n->type) { case ROFFT_BLOCK: html_close_paragraph(h); print_otag(h, TAG_SECTION, "c", "Ss"); - return 1; + break; case ROFFT_HEAD: + n->flags |= NODE_ID; + print_otag_id(h, TAG_H2, "Ss", n); break; case ROFFT_BODY: - return 1; + break; default: abort(); } - - id = html_make_id(n, 1); - print_otag(h, TAG_H2, "ci", "Ss", id); - if (id != NULL) - print_otag(h, TAG_A, "chR", "permalink", id); return 1; } @@ -627,12 +606,8 @@ static int mdoc_fl_pre(MDOC_ARGS) { struct roff_node *nn; - char *id; - - if ((id = cond_id(n)) != NULL) - print_otag(h, TAG_A, "chR", "permalink", id); - print_otag(h, TAG_CODE, "ci", "Fl", id); + print_otag_id(h, TAG_CODE, "Fl", n); print_text(h, "\\-"); if (n->child != NULL || ((nn = roff_node_next(n)) != NULL && @@ -643,17 +618,6 @@ mdoc_fl_pre(MDOC_ARGS) return 1; } -static int -mdoc_cm_pre(MDOC_ARGS) -{ - char *id; - - if ((id = cond_id(n)) != NULL) - print_otag(h, TAG_A, "chR", "permalink", id); - print_otag(h, TAG_CODE, "ci", "Cm", id); - return 1; -} - static int mdoc_nd_pre(MDOC_ARGS) { @@ -926,7 +890,7 @@ mdoc_st_pre(MDOC_ARGS) static int mdoc_em_pre(MDOC_ARGS) { - print_otag(h, TAG_I, "c", "Em"); + print_otag_id(h, TAG_I, "Em", n); return 1; } @@ -1051,45 +1015,6 @@ mdoc_cd_pre(MDOC_ARGS) return 1; } -static int -mdoc_dv_pre(MDOC_ARGS) -{ - char *id; - - if ((id = cond_id(n)) != NULL) - print_otag(h, TAG_A, "chR", "permalink", id); - print_otag(h, TAG_CODE, "ci", "Dv", id); - return 1; -} - -static int -mdoc_ev_pre(MDOC_ARGS) -{ - char *id; - - if ((id = cond_id(n)) != NULL) - print_otag(h, TAG_A, "chR", "permalink", id); - print_otag(h, TAG_CODE, "ci", "Ev", id); - return 1; -} - -static int -mdoc_er_pre(MDOC_ARGS) -{ - char *id; - - id = n->sec == SEC_ERRORS && - (n->parent->tok == MDOC_It || - (n->parent->tok == MDOC_Bq && - n->parent->parent->parent->tok == MDOC_It)) ? - html_make_id(n, 1) : NULL; - - if (id != NULL) - print_otag(h, TAG_A, "chR", "permalink", id); - print_otag(h, TAG_CODE, "ci", "Er", id); - return 1; -} - static int mdoc_fa_pre(MDOC_ARGS) { @@ -1222,7 +1147,7 @@ mdoc_fn_pre(MDOC_ARGS) print_tagq(h, t); } - t = print_otag(h, TAG_CODE, "c", "Fn"); + t = print_otag_id(h, TAG_CODE, "Fn", n); if (sp) print_text(h, sp); @@ -1341,14 +1266,12 @@ mdoc_mt_pre(MDOC_ARGS) for (n = n->child; n; n = n->next) { assert(n->type == ROFFT_TEXT); - mandoc_asprintf(&cp, "mailto:%s", n->string); t = print_otag(h, TAG_A, "ch", "Mt", cp); print_text(h, n->string); print_tagq(h, t); free(cp); } - return 0; } @@ -1357,30 +1280,30 @@ mdoc_fo_pre(MDOC_ARGS) { struct tag *t; - if (n->type == ROFFT_BODY) { + switch (n->type) { + case ROFFT_BLOCK: + synopsis_pre(h, n); + return 1; + case ROFFT_HEAD: + if (n->child != NULL) { + t = print_otag_id(h, TAG_CODE, "Fn", n); + print_text(h, n->child->string); + print_tagq(h, t); + } + return 0; + case ROFFT_BODY: h->flags |= HTML_NOSPACE; print_text(h, "("); h->flags |= HTML_NOSPACE; return 1; - } else if (n->type == ROFFT_BLOCK) { - synopsis_pre(h, n); - return 1; + default: + abort(); } - - if (n->child == NULL) - return 0; - - assert(n->child->string); - t = print_otag(h, TAG_CODE, "c", "Fn"); - print_text(h, n->child->string); - print_tagq(h, t); - return 0; } static void mdoc_fo_post(MDOC_ARGS) { - if (n->type != ROFFT_BODY) return; h->flags |= HTML_NOSPACE; @@ -1430,21 +1353,9 @@ mdoc_in_pre(MDOC_ARGS) assert(n->type == ROFFT_TEXT); print_text(h, n->string); } - return 0; } -static int -mdoc_ic_pre(MDOC_ARGS) -{ - char *id; - - if ((id = cond_id(n)) != NULL) - print_otag(h, TAG_A, "chR", "permalink", id); - print_otag(h, TAG_CODE, "ci", "Ic", id); - return 1; -} - static int mdoc_va_pre(MDOC_ARGS) { @@ -1455,7 +1366,6 @@ mdoc_va_pre(MDOC_ARGS) static int mdoc_ap_pre(MDOC_ARGS) { - h->flags |= HTML_NOSPACE; print_text(h, "\\(aq"); h->flags |= HTML_NOSPACE; @@ -1493,21 +1403,9 @@ mdoc_bf_pre(MDOC_ARGS) return 1; } -static int -mdoc_ms_pre(MDOC_ARGS) -{ - char *id; - - if ((id = cond_id(n)) != NULL) - print_otag(h, TAG_A, "chR", "permalink", id); - print_otag(h, TAG_SPAN, "ci", "Ms", id); - return 1; -} - static int mdoc_igndelim_pre(MDOC_ARGS) { - h->flags |= HTML_IGNDELIM; return 1; } @@ -1515,7 +1413,6 @@ mdoc_igndelim_pre(MDOC_ARGS) static void mdoc_pf_post(MDOC_ARGS) { - if ( ! (n->next == NULL || n->next->flags & NODE_LINE)) h->flags |= HTML_NOSPACE; } @@ -1544,29 +1441,14 @@ mdoc_rs_pre(MDOC_ARGS) static int mdoc_no_pre(MDOC_ARGS) { - char *id; - - if ((id = cond_id(n)) != NULL) - print_otag(h, TAG_A, "chR", "permalink", id); - print_otag(h, TAG_SPAN, "ci", "No", id); - return 1; -} - -static int -mdoc_li_pre(MDOC_ARGS) -{ - char *id; - - if ((id = cond_id(n)) != NULL) - print_otag(h, TAG_A, "chR", "permalink", id); - print_otag(h, TAG_CODE, "ci", "Li", id); + print_otag_id(h, TAG_SPAN, roff_name[n->tok], n); return 1; } static int mdoc_sy_pre(MDOC_ARGS) { - print_otag(h, TAG_B, "c", "Sy"); + print_otag_id(h, TAG_B, "Sy", n); return 1; } diff --git a/mdoc_term.c b/mdoc_term.c index dc03b9aa..ba21097e 100644 --- a/mdoc_term.c +++ b/mdoc_term.c @@ -1,7 +1,7 @@ -/* $Id: mdoc_term.c,v 1.378 2020/02/27 21:43:44 schwarze Exp $ */ +/* $Id: mdoc_term.c,v 1.379 2020/03/13 15:32:28 schwarze Exp $ */ /* - * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons * Copyright (c) 2010, 2012-2020 Ingo Schwarze + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons * Copyright (c) 2013 Franco Fichtner * * Permission to use, copy, modify, and distribute this software for any @@ -15,6 +15,9 @@ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Plain text formatter for mdoc(7), used by mandoc(1) + * for ASCII, UTF-8, PostScript, and PDF output. */ #include "config.h" @@ -33,7 +36,7 @@ #include "mdoc.h" #include "out.h" #include "term.h" -#include "tag.h" +#include "term_tag.h" #include "main.h" struct termpair { @@ -89,11 +92,8 @@ static int termp_bf_pre(DECL_ARGS); static int termp_bk_pre(DECL_ARGS); static int termp_bl_pre(DECL_ARGS); static int termp_bold_pre(DECL_ARGS); -static int termp_cd_pre(DECL_ARGS); static int termp_d1_pre(DECL_ARGS); static int termp_eo_pre(DECL_ARGS); -static int termp_em_pre(DECL_ARGS); -static int termp_er_pre(DECL_ARGS); static int termp_ex_pre(DECL_ARGS); static int termp_fa_pre(DECL_ARGS); static int termp_fd_pre(DECL_ARGS); @@ -115,8 +115,6 @@ static int termp_skip_pre(DECL_ARGS); static int termp_sm_pre(DECL_ARGS); static int termp_pp_pre(DECL_ARGS); static int termp_ss_pre(DECL_ARGS); -static int termp_sy_pre(DECL_ARGS); -static int termp_tag_pre(DECL_ARGS); static int termp_under_pre(DECL_ARGS); static int termp_vt_pre(DECL_ARGS); static int termp_xr_pre(DECL_ARGS); @@ -140,11 +138,11 @@ static const struct mdoc_term_act mdoc_term_acts[MDOC_MAX - MDOC_Dd] = { { termp_an_pre, NULL }, /* An */ { termp_ap_pre, NULL }, /* Ap */ { termp_under_pre, NULL }, /* Ar */ - { termp_cd_pre, NULL }, /* Cd */ + { termp_fd_pre, NULL }, /* Cd */ { termp_bold_pre, NULL }, /* Cm */ { termp_li_pre, NULL }, /* Dv */ - { termp_er_pre, NULL }, /* Er */ - { termp_tag_pre, NULL }, /* Ev */ + { NULL, NULL }, /* Er */ + { NULL, NULL }, /* Ev */ { termp_ex_pre, NULL }, /* Ex */ { termp_fa_pre, NULL }, /* Fa */ { termp_fd_pre, termp_fd_post }, /* Fd */ @@ -191,7 +189,7 @@ static const struct mdoc_term_act mdoc_term_acts[MDOC_MAX - MDOC_Dd] = { { termp_quote_pre, termp_quote_post }, /* Dq */ { NULL, NULL }, /* Ec */ /* FIXME: no space */ { NULL, NULL }, /* Ef */ - { termp_em_pre, NULL }, /* Em */ + { termp_under_pre, NULL }, /* Em */ { termp_eo_pre, termp_eo_post }, /* Eo */ { termp_xx_pre, termp_xx_post }, /* Fx */ { termp_bold_pre, NULL }, /* Ms */ @@ -214,7 +212,7 @@ static const struct mdoc_term_act mdoc_term_acts[MDOC_MAX - MDOC_Dd] = { { termp_quote_pre, termp_quote_post }, /* Sq */ { termp_sm_pre, NULL }, /* Sm */ { termp_under_pre, NULL }, /* Sx */ - { termp_sy_pre, NULL }, /* Sy */ + { termp_bold_pre, NULL }, /* Sy */ { NULL, NULL }, /* Tn */ { termp_xx_pre, termp_xx_post }, /* Ux */ { NULL, NULL }, /* Xc */ @@ -246,8 +244,6 @@ static const struct mdoc_term_act mdoc_term_acts[MDOC_MAX - MDOC_Dd] = { { termp_skip_pre, NULL }, /* Tg */ }; -static int fn_prio = TAG_STRONG; - void terminal_mdoc(void *arg, const struct roff_meta *mdoc) @@ -300,7 +296,6 @@ terminal_mdoc(void *arg, const struct roff_meta *mdoc) static void print_mdoc_nodelist(DECL_ARGS) { - while (n != NULL) { print_mdoc_node(p, pair, meta, n); n = n->next; @@ -341,8 +336,7 @@ print_mdoc_node(DECL_ARGS) npair.ppair = pair; if (n->flags & NODE_ID) - tag_put(n->string == NULL ? n->child->string : n->string, - TAG_MANUAL, p->line); + term_tag_write(n, p->line); /* * Keeps only work until the end of a line. If a keep was @@ -1008,24 +1002,30 @@ termp_nm_pre(DECL_ARGS) p->flags |= TERMP_HANG; } } - - term_fontpush(p, TERMFONT_BOLD); - return 1; + return termp_bold_pre(p, pair, meta, n); } static void termp_nm_post(DECL_ARGS) { - - if (n->type == ROFFT_BLOCK) { + switch (n->type) { + case ROFFT_BLOCK: p->flags &= ~(TERMP_KEEP | TERMP_PREKEEP); - } else if (n->type == ROFFT_HEAD && - NULL != n->next && NULL != n->next->child) { + break; + case ROFFT_HEAD: + if (n->next == NULL || n->next->child == NULL) + break; term_flushln(p); p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG); p->trailspace = 0; - } else if (n->type == ROFFT_BODY && n->child != NULL) - term_flushln(p); + break; + case ROFFT_BODY: + if (n->child != NULL) + term_flushln(p); + break; + default: + break; + } } static int @@ -1033,7 +1033,6 @@ termp_fl_pre(DECL_ARGS) { struct roff_node *nn; - termp_tag_pre(p, pair, meta, n); term_fontpush(p, TERMFONT_BOLD); term_word(p, "\\-"); @@ -1219,24 +1218,22 @@ synopsis_pre(struct termp *p, struct roff_node *n) static int termp_vt_pre(DECL_ARGS) { - - if (n->type == ROFFT_ELEM) { - synopsis_pre(p, n); - return termp_under_pre(p, pair, meta, n); - } else if (n->type == ROFFT_BLOCK) { + switch (n->type) { + case ROFFT_ELEM: + return termp_ft_pre(p, pair, meta, n); + case ROFFT_BLOCK: synopsis_pre(p, n); return 1; - } else if (n->type == ROFFT_HEAD) + case ROFFT_HEAD: return 0; - - return termp_under_pre(p, pair, meta, n); + default: + return termp_under_pre(p, pair, meta, n); + } } static int termp_bold_pre(DECL_ARGS) { - - termp_tag_pre(p, pair, meta, n); term_fontpush(p, TERMFONT_BOLD); return 1; } @@ -1244,7 +1241,6 @@ termp_bold_pre(DECL_ARGS) static int termp_fd_pre(DECL_ARGS) { - synopsis_pre(p, n); return termp_bold_pre(p, pair, meta, n); } @@ -1252,7 +1248,6 @@ termp_fd_pre(DECL_ARGS) static void termp_fd_post(DECL_ARGS) { - term_newln(p); } @@ -1273,23 +1268,14 @@ termp_sh_pre(DECL_ARGS) term_vspace(p); break; case ROFFT_HEAD: - term_fontpush(p, TERMFONT_BOLD); - break; + return termp_bold_pre(p, pair, meta, n); case ROFFT_BODY: p->tcol->offset = term_len(p, p->defindent); term_tab_set(p, NULL); term_tab_set(p, "T"); term_tab_set(p, ".5i"); - switch (n->sec) { - case SEC_DESCRIPTION: - fn_prio = TAG_STRONG; - break; - case SEC_AUTHORS: + if (n->sec == SEC_AUTHORS) p->flags &= ~(TERMP_SPLIT|TERMP_NOSPLIT); - break; - default: - break; - } break; default: break; @@ -1300,7 +1286,6 @@ termp_sh_pre(DECL_ARGS) static void termp_sh_post(DECL_ARGS) { - switch (n->type) { case ROFFT_HEAD: term_newln(p); @@ -1317,15 +1302,13 @@ termp_sh_post(DECL_ARGS) static void termp_lb_post(DECL_ARGS) { - - if (SEC_LIBRARY == n->sec && NODE_LINE & n->flags) + if (n->sec == SEC_LIBRARY && n->flags & NODE_LINE) term_newln(p); } static int termp_d1_pre(DECL_ARGS) { - if (n->type != ROFFT_BLOCK) return 1; term_newln(p); @@ -1339,11 +1322,8 @@ termp_d1_pre(DECL_ARGS) static int termp_ft_pre(DECL_ARGS) { - - /* NB: NODE_LINE does not effect this! */ synopsis_pre(p, n); - term_fontpush(p, TERMFONT_UNDER); - return 1; + return termp_under_pre(p, pair, meta, n); } static int @@ -1352,11 +1332,9 @@ termp_fn_pre(DECL_ARGS) size_t rmargin = 0; int pretty; - pretty = NODE_SYNPRETTY & n->flags; - synopsis_pre(p, n); - - if (NULL == (n = n->child)) + pretty = n->flags & NODE_SYNPRETTY; + if ((n = n->child) == NULL) return 0; if (pretty) { @@ -1370,9 +1348,6 @@ termp_fn_pre(DECL_ARGS) term_word(p, n->string); term_fontpop(p); - if (n->sec == SEC_DESCRIPTION || n->sec == SEC_CUSTOM) - tag_put(n->string, fn_prio++, p->line); - if (pretty) { term_flushln(p); p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG); @@ -1407,7 +1382,6 @@ termp_fn_pre(DECL_ARGS) term_word(p, ";"); term_flushln(p); } - return 0; } @@ -1416,10 +1390,9 @@ termp_fa_pre(DECL_ARGS) { const struct roff_node *nn; - if (n->parent->tok != MDOC_Fo) { - term_fontpush(p, TERMFONT_UNDER); - return 1; - } + if (n->parent->tok != MDOC_Fo) + return termp_under_pre(p, pair, meta, n); + for (nn = n->child; nn != NULL; nn = nn->next) { term_fontpush(p, TERMFONT_UNDER); p->flags |= TERMP_NBRWORD; @@ -1530,9 +1503,8 @@ termp_ss_pre(DECL_ARGS) term_vspace(p); break; case ROFFT_HEAD: - term_fontpush(p, TERMFONT_BOLD); p->tcol->offset = term_len(p, (p->defindent+1)/2); - break; + return termp_bold_pre(p, pair, meta, n); case ROFFT_BODY: p->tcol->offset = term_len(p, p->defindent); term_tab_set(p, NULL); @@ -1552,22 +1524,11 @@ termp_ss_post(DECL_ARGS) term_newln(p); } -static int -termp_cd_pre(DECL_ARGS) -{ - - synopsis_pre(p, n); - term_fontpush(p, TERMFONT_BOLD); - return 1; -} - static int termp_in_pre(DECL_ARGS) { - synopsis_pre(p, n); - - if (NODE_SYNPRETTY & n->flags && NODE_LINE & n->flags) { + if (n->flags & NODE_SYNPRETTY && n->flags & NODE_LINE) { term_fontpush(p, TERMFONT_BOLD); term_word(p, "#include"); term_word(p, "<"); @@ -1575,7 +1536,6 @@ termp_in_pre(DECL_ARGS) term_word(p, "<"); term_fontpush(p, TERMFONT_UNDER); } - p->flags |= TERMP_NOSPACE; return 1; } @@ -1583,21 +1543,17 @@ termp_in_pre(DECL_ARGS) static void termp_in_post(DECL_ARGS) { - - if (NODE_SYNPRETTY & n->flags) + if (n->flags & NODE_SYNPRETTY) term_fontpush(p, TERMFONT_BOLD); - p->flags |= TERMP_NOSPACE; term_word(p, ">"); - - if (NODE_SYNPRETTY & n->flags) + if (n->flags & NODE_SYNPRETTY) term_fontpop(p); } static int termp_pp_pre(DECL_ARGS) { - fn_prio = TAG_STRONG; term_vspace(p); return 0; } @@ -1605,14 +1561,12 @@ termp_pp_pre(DECL_ARGS) static int termp_skip_pre(DECL_ARGS) { - return 0; } static int termp_quote_pre(DECL_ARGS) { - if (n->type != ROFFT_BODY && n->type != ROFFT_ELEM) return 1; @@ -1769,17 +1723,15 @@ termp_eo_post(DECL_ARGS) static int termp_fo_pre(DECL_ARGS) { - size_t rmargin = 0; - int pretty; - - pretty = NODE_SYNPRETTY & n->flags; + size_t rmargin; - if (n->type == ROFFT_BLOCK) { + switch (n->type) { + case ROFFT_BLOCK: synopsis_pre(p, n); return 1; - } else if (n->type == ROFFT_BODY) { - if (pretty) { - rmargin = p->tcol->rmargin; + case ROFFT_BODY: + rmargin = p->tcol->rmargin; + if (n->flags & NODE_SYNPRETTY) { p->tcol->rmargin = p->tcol->offset + term_len(p, 4); p->flags |= TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG; @@ -1787,7 +1739,7 @@ termp_fo_pre(DECL_ARGS) p->flags |= TERMP_NOSPACE; term_word(p, "("); p->flags |= TERMP_NOSPACE; - if (pretty) { + if (n->flags & NODE_SYNPRETTY) { term_flushln(p); p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG); @@ -1796,30 +1748,21 @@ termp_fo_pre(DECL_ARGS) p->tcol->rmargin = rmargin; } return 1; + default: + return termp_bold_pre(p, pair, meta, n); } - - if (NULL == n->child) - return 0; - - /* XXX: we drop non-initial arguments as per groff. */ - - assert(n->child->string); - term_fontpush(p, TERMFONT_BOLD); - term_word(p, n->child->string); - return 0; } static void termp_fo_post(DECL_ARGS) { - if (n->type != ROFFT_BODY) return; p->flags |= TERMP_NOSPACE; term_word(p, ")"); - if (NODE_SYNPRETTY & n->flags) { + if (n->flags & NODE_SYNPRETTY) { p->flags |= TERMP_NOSPACE; term_word(p, ";"); term_flushln(p); @@ -1829,29 +1772,30 @@ termp_fo_post(DECL_ARGS) static int termp_bf_pre(DECL_ARGS) { - - if (n->type == ROFFT_HEAD) + switch (n->type) { + case ROFFT_HEAD: return 0; - else if (n->type != ROFFT_BODY) + case ROFFT_BODY: + break; + default: return 1; - - if (FONT_Em == n->norm->Bf.font) - term_fontpush(p, TERMFONT_UNDER); - else if (FONT_Sy == n->norm->Bf.font) - term_fontpush(p, TERMFONT_BOLD); - else - term_fontpush(p, TERMFONT_NONE); - - return 1; + } + switch (n->norm->Bf.font) { + case FONT_Em: + return termp_under_pre(p, pair, meta, n); + case FONT_Sy: + return termp_bold_pre(p, pair, meta, n); + default: + return termp_li_pre(p, pair, meta, n); + } } static int termp_sm_pre(DECL_ARGS) { - - if (NULL == n->child) + if (n->child == NULL) p->flags ^= TERMP_NONOSPACE; - else if (0 == strcmp("on", n->child->string)) + else if (strcmp(n->child->string, "on") == 0) p->flags &= ~TERMP_NONOSPACE; else p->flags |= TERMP_NONOSPACE; @@ -1865,7 +1809,6 @@ termp_sm_pre(DECL_ARGS) static int termp_ap_pre(DECL_ARGS) { - p->flags |= TERMP_NOSPACE; term_word(p, "'"); p->flags |= TERMP_NOSPACE; @@ -1904,8 +1847,6 @@ termp____post(DECL_ARGS) static int termp_li_pre(DECL_ARGS) { - - termp_tag_pre(p, pair, meta, n); term_fontpush(p, TERMFONT_NONE); return 1; } @@ -1955,7 +1896,6 @@ termp_lk_pre(DECL_ARGS) static int termp_bk_pre(DECL_ARGS) { - switch (n->type) { case ROFFT_BLOCK: break; @@ -1968,106 +1908,46 @@ termp_bk_pre(DECL_ARGS) default: abort(); } - return 1; } static void termp_bk_post(DECL_ARGS) { - if (n->type == ROFFT_BODY) p->flags &= ~(TERMP_KEEP | TERMP_PREKEEP); } +/* + * If we are in an `Rs' and there is a journal present, + * then quote us instead of underlining us (for disambiguation). + */ static void termp__t_post(DECL_ARGS) { - - /* - * If we're in an `Rs' and there's a journal present, then quote - * us instead of underlining us (for disambiguation). - */ - if (n->parent && MDOC_Rs == n->parent->tok && + if (n->parent != NULL && n->parent->tok == MDOC_Rs && n->parent->norm->Rs.quote_T) termp_quote_post(p, pair, meta, n); - termp____post(p, pair, meta, n); } static int termp__t_pre(DECL_ARGS) { - - /* - * If we're in an `Rs' and there's a journal present, then quote - * us instead of underlining us (for disambiguation). - */ - if (n->parent && MDOC_Rs == n->parent->tok && + if (n->parent != NULL && n->parent->tok == MDOC_Rs && n->parent->norm->Rs.quote_T) return termp_quote_pre(p, pair, meta, n); - - term_fontpush(p, TERMFONT_UNDER); - return 1; + else + return termp_under_pre(p, pair, meta, n); } static int termp_under_pre(DECL_ARGS) { - - term_fontpush(p, TERMFONT_UNDER); - return 1; -} - -static int -termp_em_pre(DECL_ARGS) -{ - if (n->child != NULL && - n->child->type == ROFFT_TEXT) - tag_put(n->child->string, TAG_FALLBACK, p->line); term_fontpush(p, TERMFONT_UNDER); return 1; } -static int -termp_sy_pre(DECL_ARGS) -{ - if (n->child != NULL && - n->child->type == ROFFT_TEXT) - tag_put(n->child->string, TAG_FALLBACK, p->line); - term_fontpush(p, TERMFONT_BOLD); - return 1; -} - -static int -termp_er_pre(DECL_ARGS) -{ - - if (n->sec == SEC_ERRORS && - (n->parent->tok == MDOC_It || - (n->parent->tok == MDOC_Bq && - n->parent->parent->parent->tok == MDOC_It))) - tag_put(n->child->string, TAG_STRONG, p->line); - return 1; -} - -static int -termp_tag_pre(DECL_ARGS) -{ - - if (n->child != NULL && - n->child->type == ROFFT_TEXT && - (n->prev == NULL || - (n->prev->type == ROFFT_TEXT && - strcmp(n->prev->string, "|") == 0)) && - (n->parent->tok == MDOC_It || - (n->parent->tok == MDOC_Xo && - n->parent->parent->prev == NULL && - n->parent->parent->parent->tok == MDOC_It))) - tag_put(n->child->string, TAG_STRONG, p->line); - return 1; -} - static int termp_abort_pre(DECL_ARGS) { diff --git a/mdoc_validate.c b/mdoc_validate.c index 0ea41db1..bae3d6b8 100644 --- a/mdoc_validate.c +++ b/mdoc_validate.c @@ -1,7 +1,7 @@ -/* $Id: mdoc_validate.c,v 1.379 2020/02/27 21:43:44 schwarze Exp $ */ +/* $Id: mdoc_validate.c,v 1.380 2020/03/13 15:32:28 schwarze Exp $ */ /* - * Copyright (c) 2008-2012 Kristaps Dzonsons * Copyright (c) 2010-2020 Ingo Schwarze + * Copyright (c) 2008-2012 Kristaps Dzonsons * Copyright (c) 2010 Joerg Sonnenberger * * Permission to use, copy, modify, and distribute this software for any @@ -15,6 +15,8 @@ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Validation module for mdoc(7) syntax trees used by mandoc(1). */ #include "config.h" @@ -35,6 +37,7 @@ #include "mandoc.h" #include "mandoc_xr.h" #include "roff.h" +#include "tag.h" #include "mdoc.h" #include "libmandoc.h" #include "roff_int.h" @@ -82,7 +85,9 @@ static void post_dd(POST_ARGS); static void post_delim(POST_ARGS); static void post_delim_nb(POST_ARGS); static void post_dt(POST_ARGS); +static void post_em(POST_ARGS); static void post_en(POST_ARGS); +static void post_er(POST_ARGS); static void post_es(POST_ARGS); static void post_eoln(POST_ARGS); static void post_ex(POST_ARGS); @@ -113,6 +118,7 @@ static void post_sm(POST_ARGS); static void post_st(POST_ARGS); static void post_std(POST_ARGS); static void post_sx(POST_ARGS); +static void post_tag(POST_ARGS); static void post_tg(POST_ARGS); static void post_useless(POST_ARGS); static void post_xr(POST_ARGS); @@ -137,19 +143,19 @@ static const v_post mdoc_valids[MDOC_MAX - MDOC_Dd] = { NULL, /* Ap */ post_defaults, /* Ar */ NULL, /* Cd */ - post_delim_nb, /* Cm */ - post_delim_nb, /* Dv */ - post_delim_nb, /* Er */ - post_delim_nb, /* Ev */ + post_tag, /* Cm */ + post_tag, /* Dv */ + post_er, /* Er */ + post_tag, /* Ev */ post_ex, /* Ex */ post_fa, /* Fa */ NULL, /* Fd */ - post_delim_nb, /* Fl */ + post_tag, /* Fl */ post_fn, /* Fn */ post_delim_nb, /* Ft */ - post_delim_nb, /* Ic */ + post_tag, /* Ic */ post_delim_nb, /* In */ - post_defaults, /* Li */ + post_tag, /* Li */ post_nd, /* Nd */ post_nm, /* Nm */ post_delim_nb, /* Op */ @@ -187,11 +193,11 @@ static const v_post mdoc_valids[MDOC_MAX - MDOC_Dd] = { NULL, /* Dq */ NULL, /* Ec */ NULL, /* Ef */ - post_delim_nb, /* Em */ + post_em, /* Em */ NULL, /* Eo */ post_xx, /* Fx */ - post_delim_nb, /* Ms */ - NULL, /* No */ + post_tag, /* Ms */ + post_tag, /* No */ post_ns, /* Ns */ post_xx, /* Nx */ post_xx, /* Ox */ @@ -210,7 +216,7 @@ static const v_post mdoc_valids[MDOC_MAX - MDOC_Dd] = { post_delim_nb, /* Sq */ post_sm, /* Sm */ post_sx, /* Sx */ - post_delim_nb, /* Sy */ + post_em, /* Sy */ post_useless, /* Tn */ post_xx, /* Ux */ NULL, /* Xc */ @@ -287,6 +293,8 @@ static const char * const secnames[SEC__MAX] = { NULL }; +static int fn_prio = TAG_STRONG; + /* Validate the subtree rooted at mdoc->last. */ void @@ -1094,8 +1102,11 @@ post_st(POST_ARGS) static void post_tg(POST_ARGS) { - struct roff_node *n, *nch, *nn; - size_t len; + struct roff_node *n; /* The .Tg node. */ + struct roff_node *nch; /* The first child of the .Tg node. */ + struct roff_node *nn; /* The next node after the .Tg node. */ + struct roff_node *nt; /* The TEXT node containing the tag. */ + size_t len; /* The number of bytes in the tag. */ /* Find the next node. */ n = mdoc->last; @@ -1106,30 +1117,26 @@ post_tg(POST_ARGS) } } - /* Add the default argument, if needed. */ - nch = n->child; - if (nch == NULL && nn != NULL && nn->child->type == ROFFT_TEXT) { - mdoc->next = ROFF_NEXT_CHILD; - roff_word_alloc(mdoc, n->line, n->pos, n->next->child->string); - nch = mdoc->last; - nch->flags |= NODE_NOSRC; - mdoc->last = n; - } + /* Find the tag. */ + nt = nch = n->child; + if (nch == NULL && nn != NULL && nn->child != NULL && + nn->child->type == ROFFT_TEXT) + nt = nn->child; - /* Validate the first argument. */ - if (nch == NULL || *nch->string == '\0') + /* Validate the tag. */ + if (nt == NULL || *nt->string == '\0') mandoc_msg(MANDOCERR_MACRO_EMPTY, n->line, n->pos, "Tg"); - if (nch == NULL) { + if (nt == NULL) { roff_node_delete(mdoc, n); return; } - len = strcspn(nch->string, " \t"); - if (nch->string[len] != '\0') - mandoc_msg(MANDOCERR_TG_SPC, nch->line, nch->pos + len + 1, - "Tg %s", nch->string); + len = strcspn(nt->string, " \t\\"); + if (nt->string[len] != '\0') + mandoc_msg(MANDOCERR_TG_SPC, nt->line, + nt->pos + len, "Tg %s", nt->string); /* Keep only the first argument. */ - if (nch->next != NULL) { + if (nch != NULL && nch->next != NULL) { mandoc_msg(MANDOCERR_ARG_EXCESS, nch->next->line, nch->next->pos, "Tg ... %s", nch->next->string); while (nch->next != NULL) @@ -1137,32 +1144,44 @@ post_tg(POST_ARGS) } /* Drop the macro if the first argument is invalid. */ - if (len == 0 || nch->string[len] != '\0') { + if (len == 0 || nt->string[len] != '\0') { roff_node_delete(mdoc, n); return; } - /* By default, write a element. */ - n->flags |= NODE_ID; + /* By default, tag the .Tg node itself. */ if (nn == NULL) - return; + nn = n; /* Explicit tagging of specific macros. */ switch (nn->tok) { case MDOC_Sh: case MDOC_Ss: - if (nn->head->flags & NODE_ID || nn->head->child == NULL) + case MDOC_Fo: + nn = nn->head; + /* FALLTHROUGH */ + case MDOC_Cm: + case MDOC_Dv: + case MDOC_Em: + case MDOC_Er: + case MDOC_Ev: + case MDOC_Fl: + case MDOC_Fn: + case MDOC_Ic: + case MDOC_Li: + case MDOC_Ms: + case MDOC_No: + case MDOC_Sy: + if (nn->child != NULL && (nn->flags & NODE_ID) == 0) break; - n->flags |= NODE_NOPRT; - nn->head->flags |= NODE_ID | NODE_HREF; - assert(nn->head->string == NULL); - nn->head->string = mandoc_strdup(nch->string); - break; + /* FALLTHROUGH */ default: + nn = n; break; } - if (n->flags & NODE_NOPRT) - n->flags &= ~NODE_ID; + tag_put(nt->string, TAG_MANUAL, nn); + if (nn != n) + n->flags |= NODE_NOPRT; } static void @@ -1257,28 +1276,32 @@ post_bf(POST_ARGS) static void post_fname(POST_ARGS) { - const struct roff_node *n; + struct roff_node *n, *nch; const char *cp; size_t pos; - n = mdoc->last->child; - cp = n->string; + n = mdoc->last; + nch = n->child; + cp = nch->string; if (*cp == '(') { if (cp[strlen(cp + 1)] == ')') return; pos = 0; } else { pos = strcspn(cp, "()"); - if (cp[pos] == '\0') + if (cp[pos] == '\0') { + if (n->sec == SEC_DESCRIPTION || + n->sec == SEC_CUSTOM) + tag_put(NULL, fn_prio++, n); return; + } } - mandoc_msg(MANDOCERR_FN_PAREN, n->line, n->pos + pos, "%s", cp); + mandoc_msg(MANDOCERR_FN_PAREN, nch->line, nch->pos + pos, "%s", cp); } static void post_fn(POST_ARGS) { - post_fname(mdoc); post_fa(mdoc); } @@ -1442,38 +1465,29 @@ post_display(POST_ARGS) static void post_defaults(POST_ARGS) { - struct roff_node *nn; + struct roff_node *n; - if (mdoc->last->child != NULL) { + n = mdoc->last; + if (n->child != NULL) { post_delim_nb(mdoc); return; } - - /* - * The `Ar' defaults to "file ..." if no value is provided as an - * argument; the `Mt' and `Pa' macros use "~"; the `Li' just - * gets an empty string. - */ - - nn = mdoc->last; - switch (nn->tok) { + mdoc->next = ROFF_NEXT_CHILD; + switch (n->tok) { case MDOC_Ar: - mdoc->next = ROFF_NEXT_CHILD; - roff_word_alloc(mdoc, nn->line, nn->pos, "file"); - mdoc->last->flags |= NODE_NOSRC; - roff_word_alloc(mdoc, nn->line, nn->pos, "..."); + roff_word_alloc(mdoc, n->line, n->pos, "file"); mdoc->last->flags |= NODE_NOSRC; + roff_word_alloc(mdoc, n->line, n->pos, "..."); break; case MDOC_Pa: case MDOC_Mt: - mdoc->next = ROFF_NEXT_CHILD; - roff_word_alloc(mdoc, nn->line, nn->pos, "~"); - mdoc->last->flags |= NODE_NOSRC; + roff_word_alloc(mdoc, n->line, n->pos, "~"); break; default: abort(); } - mdoc->last = nn; + mdoc->last->flags |= NODE_NOSRC; + mdoc->last = n; } static void @@ -1527,18 +1541,54 @@ post_an(POST_ARGS) } static void -post_en(POST_ARGS) +post_em(POST_ARGS) { + post_tag(mdoc); + tag_put(NULL, TAG_FALLBACK, mdoc->last); +} +static void +post_en(POST_ARGS) +{ post_obsolete(mdoc); if (mdoc->last->type == ROFFT_BLOCK) mdoc->last->norm->Es = mdoc->last_es; } static void -post_es(POST_ARGS) +post_er(POST_ARGS) +{ + struct roff_node *n; + + n = mdoc->last; + if (n->sec == SEC_ERRORS && + (n->parent->tok == MDOC_It || + (n->parent->tok == MDOC_Bq && + n->parent->parent->parent->tok == MDOC_It))) + tag_put(NULL, TAG_STRONG, n); + post_delim_nb(mdoc); +} + +static void +post_tag(POST_ARGS) { + struct roff_node *n; + + n = mdoc->last; + if ((n->prev == NULL || + (n->prev->type == ROFFT_TEXT && + strcmp(n->prev->string, "|") == 0)) && + (n->parent->tok == MDOC_It || + (n->parent->tok == MDOC_Xo && + n->parent->parent->prev == NULL && + n->parent->parent->parent->tok == MDOC_It))) + tag_put(NULL, TAG_STRONG, n); + post_delim_nb(mdoc); +} +static void +post_es(POST_ARGS) +{ post_obsolete(mdoc); mdoc->last_es = mdoc->last; } @@ -1635,8 +1685,8 @@ post_it(POST_ARGS) if ((nch = nit->head->child) != NULL) mandoc_msg(MANDOCERR_ARG_SKIP, nit->line, nit->pos, "It %s", - nch->string == NULL ? roff_name[nch->tok] : - nch->string); + nch->type == ROFFT_TEXT ? nch->string : + roff_name[nch->tok]); break; case LIST_column: cols = (int)nbl->norm->Bl.ncols; @@ -2152,7 +2202,6 @@ post_sx(POST_ARGS) static void post_sh(POST_ARGS) { - post_ignpar(mdoc); switch (mdoc->last->type) { @@ -2384,6 +2433,8 @@ post_sh_head(POST_ARGS) roff_setreg(mdoc->roff, "nS", 0, '='); mdoc->flags &= ~MDOC_SYNOPSIS; } + if (sec == SEC_DESCRIPTION) + fn_prio = TAG_STRONG; /* Mark our last section. */ @@ -2555,6 +2606,7 @@ post_par(POST_ARGS) { struct roff_node *np; + fn_prio = TAG_STRONG; post_prevpar(mdoc); np = mdoc->last; diff --git a/read.c b/read.c index b3858061..dc6c2409 100644 --- a/read.c +++ b/read.c @@ -1,7 +1,7 @@ -/* $Id: read.c,v 1.214 2019/07/10 19:39:01 schwarze Exp $ */ +/* $Id: read.c,v 1.215 2020/03/13 15:32:28 schwarze Exp $ */ /* - * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons * Copyright (c) 2010-2019 Ingo Schwarze + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons * Copyright (c) 2010, 2012 Joerg Sonnenberger * * Permission to use, copy, modify, and distribute this software for any @@ -15,6 +15,12 @@ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Top-level functions of the mandoc(3) parser: + * Parser and input encoding selection, decompression, + * handling of input bytes, characters, lines, and files, + * handling of roff(7) loops and file inclusion, + * and steering of the various parsers. */ #include "config.h" @@ -36,6 +42,7 @@ #include "mandoc_aux.h" #include "mandoc.h" #include "roff.h" +#include "tag.h" #include "mdoc.h" #include "man.h" #include "mandoc_parse.h" @@ -664,6 +671,7 @@ mparse_alloc(int options, enum mandoc_os os_e, const char *os_s) } curp->man->meta.first->tok = TOKEN_NONE; curp->man->meta.os_e = os_e; + tag_alloc(); return curp; } @@ -680,6 +688,7 @@ mparse_reset(struct mparse *curp) void mparse_free(struct mparse *curp) { + tag_free(); roffhash_free(curp->man->mdocmac); roffhash_free(curp->man->manmac); roff_man_free(curp->man); diff --git a/regress/copyless b/regress/copyless new file mode 100755 index 00000000..a00c0009 --- /dev/null +++ b/regress/copyless @@ -0,0 +1,14 @@ +#!/bin/sh +set -e +umask 022 +if [ "$#" -ne 4 ]; then + echo "$0 $*: $# args instead of 4" 1>&2 + exit 1 +fi +if [ "$2" != "-T" ]; then + echo "$0 $*: second arg is not -T" 1>&2 + exit 1 +fi +cut -d ' ' -f 1,3 "$3" > "$1.mandoc_tag" +cp "$4" "$1.mandoc_ascii" +exit 0 diff --git a/regress/man/IP/Makefile b/regress/man/IP/Makefile index 70094e5f..8d607c62 100644 --- a/regress/man/IP/Makefile +++ b/regress/man/IP/Makefile @@ -1,8 +1,9 @@ -# $OpenBSD: Makefile,v 1.10 2020/02/27 01:25:58 schwarze Exp $ +# $OpenBSD: Makefile,v 1.11 2020/03/13 00:31:05 schwarze Exp $ -REGRESS_TARGETS = bullet empty literal longhead manyargs spacing vert width +REGRESS_TARGETS = bullet empty literal longhead manyargs spacing tag vert width +TAG_TARGETS = empty tag UTF8_TARGETS = bullet LINT_TARGETS = empty -HTML_TARGETS = bullet literal +HTML_TARGETS = bullet empty literal tag .include diff --git a/regress/man/IP/empty.in b/regress/man/IP/empty.in index 21c42983..bb814870 100644 --- a/regress/man/IP/empty.in +++ b/regress/man/IP/empty.in @@ -1,8 +1,9 @@ -.\" $OpenBSD: empty.in,v 1.2 2017/07/04 14:53:23 schwarze Exp $ +.\" $OpenBSD: empty.in,v 1.3 2020/03/13 00:31:05 schwarze Exp $ .TH IP-EMPTY 1 "July 17, 2012" .SH NAME IP-empty \- empty indented paragraphs .SH DESCRIPTION +BEGINTEST regular text .IP @@ -25,3 +26,4 @@ text .RE regular text +ENDTEST diff --git a/regress/man/IP/empty.out_ascii b/regress/man/IP/empty.out_ascii index 24ab17fa..b17190ab 100644 --- a/regress/man/IP/empty.out_ascii +++ b/regress/man/IP/empty.out_ascii @@ -6,7 +6,7 @@ NNAAMMEE IP-empty - empty indented paragraphs DDEESSCCRRIIPPTTIIOONN - regular text + BEGINTEST regular text indented text @@ -19,7 +19,7 @@ DDEESSCCRRIIPPTTIIOONN Empty IP is deleted, RS does not cause additional spacing: tag indented text - regular text + regular text ENDTEST diff --git a/regress/man/IP/empty.out_html b/regress/man/IP/empty.out_html new file mode 100644 index 00000000..f2498dba --- /dev/null +++ b/regress/man/IP/empty.out_html @@ -0,0 +1,18 @@ +
+
+
indented text
+
+

Empty IP is deleted:

+
+
+
+
+
indented text
+
+

Empty IP is deleted, RS does not cause additional spacing:

+
+
+
+
indented text
+
+
diff --git a/regress/man/IP/empty.out_lint b/regress/man/IP/empty.out_lint index 6c666c88..3514b94f 100644 --- a/regress/man/IP/empty.out_lint +++ b/regress/man/IP/empty.out_lint @@ -1,2 +1,2 @@ -mandoc: empty.in:13:2: WARNING: skipping paragraph macro: IP empty -mandoc: empty.in:20:2: WARNING: skipping paragraph macro: IP empty +mandoc: empty.in:14:2: WARNING: skipping paragraph macro: IP empty +mandoc: empty.in:21:2: WARNING: skipping paragraph macro: IP empty diff --git a/regress/man/IP/empty.out_tag b/regress/man/IP/empty.out_tag new file mode 100644 index 00000000..f35f1120 --- /dev/null +++ b/regress/man/IP/empty.out_tag @@ -0,0 +1,3 @@ +tag1 15 +tag2 17 +tag 21 diff --git a/regress/man/IP/literal.out_html b/regress/man/IP/literal.out_html index b61fc843..3b9cc429 100644 --- a/regress/man/IP/literal.out_html +++ b/regress/man/IP/literal.out_html @@ -1,5 +1,5 @@
-
tag
+
indented regular text

new regular paragraph

@@ -8,7 +8,7 @@ literal text
-
tag
+
 indented
@@ -32,7 +32,7 @@ literal
 text
 
-
tag
+
 indented
@@ -48,7 +48,7 @@ text
   out of indented paragraph
 

regular text

-
tag
+
indented regular text
 indented
diff --git a/regress/man/IP/tag.in b/regress/man/IP/tag.in
new file mode 100644
index 00000000..038fa969
--- /dev/null
+++ b/regress/man/IP/tag.in
@@ -0,0 +1,18 @@
+.\" $OpenBSD: tag.in,v 1.1 2020/03/13 00:31:05 schwarze Exp $
+.TH IP-TAG 1 "March 10, 2020"
+.SH NAME
+IP-tag \- automatic tagging of indented blocks
+.SH DESCRIPTION
+BEGINTEST
+initial
+text
+.IP " strong" 10n
+text
+.IP "-strong"
+text
+.IP "\&\fI \-weak\fP"
+text
+.IP " strong"
+text
+.PP
+ENDTEST
diff --git a/regress/man/IP/tag.out_ascii b/regress/man/IP/tag.out_ascii
new file mode 100644
index 00000000..afd4f587
--- /dev/null
+++ b/regress/man/IP/tag.out_ascii
@@ -0,0 +1,23 @@
+IP-TAG(1)                   General Commands Manual                  IP-TAG(1)
+
+
+
+NNAAMMEE
+       IP-tag - automatic tagging of indented blocks
+
+DDEESSCCRRIIPPTTIIOONN
+       BEGINTEST initial text
+
+        strong   text
+
+       -strong   text
+
+        _-_w_e_a_k    text
+
+        strong   text
+
+       ENDTEST
+
+
+
+OpenBSD                         March 10, 2020                       IP-TAG(1)
diff --git a/regress/man/IP/tag.out_html b/regress/man/IP/tag.out_html
new file mode 100644
index 00000000..4d25b12b
--- /dev/null
+++ b/regress/man/IP/tag.out_html
@@ -0,0 +1,10 @@
+
+
strong
+
text
+
+
text
+
+
text
+
strong
+
text
+
diff --git a/regress/man/IP/tag.out_tag b/regress/man/IP/tag.out_tag new file mode 100644 index 00000000..5be038db --- /dev/null +++ b/regress/man/IP/tag.out_tag @@ -0,0 +1,2 @@ +strong 13 +weak 15 diff --git a/regress/man/TP/Makefile b/regress/man/TP/Makefile index ca2475b0..9dd2fde7 100644 --- a/regress/man/TP/Makefile +++ b/regress/man/TP/Makefile @@ -1,9 +1,10 @@ -# $OpenBSD: Makefile,v 1.16 2020/02/27 01:25:58 schwarze Exp $ +# $OpenBSD: Makefile,v 1.17 2020/03/13 00:31:05 schwarze Exp $ REGRESS_TARGETS = badarg broken double eof fill indent literal longhead -REGRESS_TARGETS += macrotag manyargs sameline spacing vert width +REGRESS_TARGETS += macrotag manyargs sameline spacing tag vert width +TAG_TARGETS = tag LINT_TARGETS = broken double eof -HTML_TARGETS = literal vert +HTML_TARGETS = literal tag vert # groff-1.22.3 defects: # - If .TP precedes .RE, the latter does not properly reset indentation. diff --git a/regress/man/TP/literal.out_html b/regress/man/TP/literal.out_html index 7f5b1c1f..8b818ed8 100644 --- a/regress/man/TP/literal.out_html +++ b/regress/man/TP/literal.out_html @@ -1,5 +1,5 @@
-
tag
+
regular indented text

regular paragraph

@@ -8,7 +8,7 @@ literal text
-
tag
+
 indented
diff --git a/regress/man/TP/tag.in b/regress/man/TP/tag.in
new file mode 100644
index 00000000..34d1e151
--- /dev/null
+++ b/regress/man/TP/tag.in
@@ -0,0 +1,31 @@
+.\" $OpenBSD: tag.in,v 1.1 2020/03/13 00:31:05 schwarze Exp $
+.TH IP-TAG 1 "March 10, 2020"
+.SH NAME
+IP-tag \- automatic tagging of indented blocks
+.SH DESCRIPTION
+BEGINTEST
+initial
+text
+.TP 10n
+.I " plain"
+text
+.TP
+plain
+text
+.TP
+.I "plain "
+text
+.TP
+\& strong
+text
+.TP
+.B -strong
+text
+.TP
+\&\fI \-weak\fP
+text
+.TP
+.B "strong "
+text
+.PP
+ENDTEST
diff --git a/regress/man/TP/tag.out_ascii b/regress/man/TP/tag.out_ascii
new file mode 100644
index 00000000..4da2efa0
--- /dev/null
+++ b/regress/man/TP/tag.out_ascii
@@ -0,0 +1,29 @@
+IP-TAG(1)                   General Commands Manual                  IP-TAG(1)
+
+
+
+NNAAMMEE
+       IP-tag - automatic tagging of indented blocks
+
+DDEESSCCRRIIPPTTIIOONN
+       BEGINTEST initial text
+
+        _p_l_a_i_n    text
+
+       plain     text
+
+       _p_l_a_i_n     text
+
+        strong   text
+
+       --ssttrroonngg   text
+
+        _-_w_e_a_k    text
+
+       ssttrroonngg    text
+
+       ENDTEST
+
+
+
+OpenBSD                         March 10, 2020                       IP-TAG(1)
diff --git a/regress/man/TP/tag.out_html b/regress/man/TP/tag.out_html
new file mode 100644
index 00000000..3fbbe41d
--- /dev/null
+++ b/regress/man/TP/tag.out_html
@@ -0,0 +1,16 @@
+
+
plain
+
text
+
+
text
+
plain
+
text
+
strong
+
text
+
+
text
+
+
text
+
strong
+
text
+
diff --git a/regress/man/TP/tag.out_tag b/regress/man/TP/tag.out_tag new file mode 100644 index 00000000..88f6cff8 --- /dev/null +++ b/regress/man/TP/tag.out_tag @@ -0,0 +1,3 @@ +plain 13 +strong 19 +weak 21 diff --git a/regress/man/TP/vert.out_html b/regress/man/TP/vert.out_html index 7301819f..1124ed33 100644 --- a/regress/man/TP/vert.out_html +++ b/regress/man/TP/vert.out_html @@ -2,8 +2,8 @@

-
tag
+
text
-
tag
+
text
diff --git a/regress/mdoc/Cm/Makefile b/regress/mdoc/Cm/Makefile index 4b7066ec..7bc3fc20 100644 --- a/regress/mdoc/Cm/Makefile +++ b/regress/mdoc/Cm/Makefile @@ -1,6 +1,8 @@ -# $OpenBSD: Makefile,v 1.3 2014/07/02 20:18:42 schwarze Exp $ +# $OpenBSD: Makefile,v 1.7 2020/03/13 00:31:05 schwarze Exp $ -REGRESS_TARGETS = basic font noarg punct +REGRESS_TARGETS = basic font noarg punct tag +TAG_TARGETS = tag LINT_TARGETS = noarg +HTML_TARGETS = tag .include diff --git a/regress/mdoc/Cm/tag.in b/regress/mdoc/Cm/tag.in new file mode 100644 index 00000000..3db1d1e0 --- /dev/null +++ b/regress/mdoc/Cm/tag.in @@ -0,0 +1,21 @@ +.\" $OpenBSD: tag.in,v 1.1 2020/03/13 00:31:05 schwarze Exp $ +.Dd $Mdocdate: March 13 2020 $ +.Dt CM-TAG 1 +.Os +.Sh NAME +.Nm Cm-tag +.Nd tagging of command modifier macros +.Sh DESCRIPTION +BEGINTEST +.Bl -tag -width Ds +.It Cm one | two +text +.It Xo +.Cm three +.Xc +text +.El +.Tg +.Cm four +.Pp +ENDTEST diff --git a/regress/mdoc/Cm/tag.out_ascii b/regress/mdoc/Cm/tag.out_ascii new file mode 100644 index 00000000..071408c7 --- /dev/null +++ b/regress/mdoc/Cm/tag.out_ascii @@ -0,0 +1,17 @@ +CM-TAG(1) General Commands Manual CM-TAG(1) + +NNAAMMEE + CCmm--ttaagg - tagging of command modifier macros + +DDEESSCCRRIIPPTTIIOONN + BEGINTEST + + oonnee | ttwwoo + text + + tthhrreeee text + ffoouurr + + ENDTEST + +OpenBSD March 13, 2020 OpenBSD diff --git a/regress/mdoc/Cm/tag.out_html b/regress/mdoc/Cm/tag.out_html new file mode 100644 index 00000000..a140fe3e --- /dev/null +++ b/regress/mdoc/Cm/tag.out_html @@ -0,0 +1,9 @@ +
+
+ | +
+
text
+
+
text
+
+ diff --git a/regress/mdoc/Cm/tag.out_markdown b/regress/mdoc/Cm/tag.out_markdown new file mode 100644 index 00000000..893a8fe5 --- /dev/null +++ b/regress/mdoc/Cm/tag.out_markdown @@ -0,0 +1,23 @@ +CM-TAG(1) - General Commands Manual + +# NAME + +**Cm-tag** - tagging of command modifier macros + +# DESCRIPTION + +BEGINTEST + +**one** | **two** + +> text + +**three** + +> text + +**four** + +ENDTEST + +OpenBSD - March 13, 2020 diff --git a/regress/mdoc/Cm/tag.out_tag b/regress/mdoc/Cm/tag.out_tag new file mode 100644 index 00000000..94f0cfb2 --- /dev/null +++ b/regress/mdoc/Cm/tag.out_tag @@ -0,0 +1,4 @@ +one 9 +two 9 +three 12 +four 13 diff --git a/regress/mdoc/Dv/Makefile b/regress/mdoc/Dv/Makefile index cfe3ad0b..979e1826 100644 --- a/regress/mdoc/Dv/Makefile +++ b/regress/mdoc/Dv/Makefile @@ -1,6 +1,8 @@ -# $OpenBSD: Makefile,v 1.2 2014/07/02 20:18:42 schwarze Exp $ +# $OpenBSD: Makefile,v 1.5 2020/03/13 00:31:05 schwarze Exp $ -REGRESS_TARGETS = font noarg +REGRESS_TARGETS = font noarg tag +TAG_TARGETS = tag LINT_TARGETS = noarg +HTML_TARGETS = tag .include diff --git a/regress/mdoc/Dv/tag.in b/regress/mdoc/Dv/tag.in new file mode 100644 index 00000000..b6c79ad1 --- /dev/null +++ b/regress/mdoc/Dv/tag.in @@ -0,0 +1,21 @@ +.\" $OpenBSD: tag.in,v 1.1 2020/03/13 00:31:05 schwarze Exp $ +.Dd $Mdocdate: March 13 2020 $ +.Dt DV-TAG 1 +.Os +.Sh NAME +.Nm Dv-tag +.Nd tagging of defined variable macros +.Sh DESCRIPTION +BEGINTEST +.Bl -tag -width Ds +.It Dv one | two +text +.It Xo +.Dv three +.Xc +text +.El +.Tg +.Dv four +.Pp +ENDTEST diff --git a/regress/mdoc/Dv/tag.out_ascii b/regress/mdoc/Dv/tag.out_ascii new file mode 100644 index 00000000..119e3509 --- /dev/null +++ b/regress/mdoc/Dv/tag.out_ascii @@ -0,0 +1,17 @@ +DV-TAG(1) General Commands Manual DV-TAG(1) + +NNAAMMEE + DDvv--ttaagg - tagging of defined variable macros + +DDEESSCCRRIIPPTTIIOONN + BEGINTEST + + one | two + text + + three text + four + + ENDTEST + +OpenBSD March 13, 2020 OpenBSD diff --git a/regress/mdoc/Dv/tag.out_html b/regress/mdoc/Dv/tag.out_html new file mode 100644 index 00000000..cee78340 --- /dev/null +++ b/regress/mdoc/Dv/tag.out_html @@ -0,0 +1,9 @@ +
+
+ | +
+
text
+
+
text
+
+ diff --git a/regress/mdoc/Dv/tag.out_markdown b/regress/mdoc/Dv/tag.out_markdown new file mode 100644 index 00000000..29b454bb --- /dev/null +++ b/regress/mdoc/Dv/tag.out_markdown @@ -0,0 +1,23 @@ +DV-TAG(1) - General Commands Manual + +# NAME + +**Dv-tag** - tagging of defined variable macros + +# DESCRIPTION + +BEGINTEST + +`one` | `two` + +> text + +`three` + +> text + +`four` + +ENDTEST + +OpenBSD - March 13, 2020 diff --git a/regress/mdoc/Dv/tag.out_tag b/regress/mdoc/Dv/tag.out_tag new file mode 100644 index 00000000..94f0cfb2 --- /dev/null +++ b/regress/mdoc/Dv/tag.out_tag @@ -0,0 +1,4 @@ +one 9 +two 9 +three 12 +four 13 diff --git a/regress/mdoc/Em/Makefile b/regress/mdoc/Em/Makefile index 13de4337..2b500444 100644 --- a/regress/mdoc/Em/Makefile +++ b/regress/mdoc/Em/Makefile @@ -1,6 +1,8 @@ -# $OpenBSD: Makefile,v 1.3 2014/11/17 06:44:35 schwarze Exp $ +# $OpenBSD: Makefile,v 1.6 2020/03/13 00:31:05 schwarze Exp $ -REGRESS_TARGETS = font noarg punct +REGRESS_TARGETS = font noarg punct tag +TAG_TARGETS = tag LINT_TARGETS = noarg punct +HTML_TARGETS = tag .include diff --git a/regress/mdoc/Em/tag.in b/regress/mdoc/Em/tag.in new file mode 100644 index 00000000..70e6eb44 --- /dev/null +++ b/regress/mdoc/Em/tag.in @@ -0,0 +1,23 @@ +.\" $OpenBSD: tag.in,v 1.1 2020/03/13 00:31:05 schwarze Exp $ +.Dd $Mdocdate: March 13 2020 $ +.Dt EM-TAG 1 +.Os +.Sh NAME +.Nm Em-tag +.Nd tagging of emphasis macros +.Sh DESCRIPTION +BEGINTEST +.Bl -tag -width Ds +.It Em one | two +text +.It Xo +.Em three +.Xc +text +.El +.Em four +.Em one +.Tg explicit +.Em five +.Pp +ENDTEST diff --git a/regress/mdoc/Em/tag.out_ascii b/regress/mdoc/Em/tag.out_ascii new file mode 100644 index 00000000..74f8212b --- /dev/null +++ b/regress/mdoc/Em/tag.out_ascii @@ -0,0 +1,17 @@ +EM-TAG(1) General Commands Manual EM-TAG(1) + +NNAAMMEE + EEmm--ttaagg - tagging of emphasis macros + +DDEESSCCRRIIPPTTIIOONN + BEGINTEST + + _o_n_e | _t_w_o + text + + _t_h_r_e_e text + _f_o_u_r _o_n_e _f_i_v_e + + ENDTEST + +OpenBSD March 13, 2020 OpenBSD diff --git a/regress/mdoc/Em/tag.out_html b/regress/mdoc/Em/tag.out_html new file mode 100644 index 00000000..4046673f --- /dev/null +++ b/regress/mdoc/Em/tag.out_html @@ -0,0 +1,10 @@ +
+
| +
+
text
+
+
text
+
+ + one + diff --git a/regress/mdoc/Em/tag.out_markdown b/regress/mdoc/Em/tag.out_markdown new file mode 100644 index 00000000..4c107159 --- /dev/null +++ b/regress/mdoc/Em/tag.out_markdown @@ -0,0 +1,25 @@ +EM-TAG(1) - General Commands Manual + +# NAME + +**Em-tag** - tagging of emphasis macros + +# DESCRIPTION + +BEGINTEST + +*one* | *two* + +> text + +*three* + +> text + +*four* +*one* +*five* + +ENDTEST + +OpenBSD - March 13, 2020 diff --git a/regress/mdoc/Em/tag.out_tag b/regress/mdoc/Em/tag.out_tag new file mode 100644 index 00000000..c2fbaf59 --- /dev/null +++ b/regress/mdoc/Em/tag.out_tag @@ -0,0 +1,5 @@ +one 9 +two 9 +three 12 +four 13 +explicit 13 diff --git a/regress/mdoc/Er/Makefile b/regress/mdoc/Er/Makefile index 1be2a84a..55f6cc76 100644 --- a/regress/mdoc/Er/Makefile +++ b/regress/mdoc/Er/Makefile @@ -1,6 +1,8 @@ -# $OpenBSD: Makefile,v 1.4 2014/07/02 20:18:42 schwarze Exp $ +# $OpenBSD: Makefile,v 1.7 2020/03/13 00:31:05 schwarze Exp $ -REGRESS_TARGETS = noarg font +REGRESS_TARGETS = noarg font tag +TAG_TARGETS = tag LINT_TARGETS = noarg +HTML_TARGETS = tag .include diff --git a/regress/mdoc/Er/tag.in b/regress/mdoc/Er/tag.in new file mode 100644 index 00000000..4227648b --- /dev/null +++ b/regress/mdoc/Er/tag.in @@ -0,0 +1,21 @@ +.\" $OpenBSD: tag.in,v 1.1 2020/03/13 00:31:05 schwarze Exp $ +.Dd $Mdocdate: March 13 2020 $ +.Dt ER-TAG 1 +.Os +.Sh NAME +.Nm Er-tag +.Nd tagging of error number macros +.Sh DESCRIPTION +BEGINTEST +.Bl -tag -width Ds +.It Er one +text +.El +.Tg +.Er two +.Sh ERRORS +.Bl -tag -width Er +.It Bq Er ENOENT +text +.El +ENDTEST diff --git a/regress/mdoc/Er/tag.out_ascii b/regress/mdoc/Er/tag.out_ascii new file mode 100644 index 00000000..62dbf9ca --- /dev/null +++ b/regress/mdoc/Er/tag.out_ascii @@ -0,0 +1,16 @@ +ER-TAG(1) General Commands Manual ER-TAG(1) + +NNAAMMEE + EErr--ttaagg - tagging of error number macros + +DDEESSCCRRIIPPTTIIOONN + BEGINTEST + + one text + two + +EERRRROORRSS + [ENOENT] text + ENDTEST + +OpenBSD March 13, 2020 OpenBSD diff --git a/regress/mdoc/Er/tag.out_html b/regress/mdoc/Er/tag.out_html new file mode 100644 index 00000000..a2c2978f --- /dev/null +++ b/regress/mdoc/Er/tag.out_html @@ -0,0 +1,12 @@ +
+
one
+
text
+
+ +
+
+

+
+
[]
+
text
+
diff --git a/regress/mdoc/Er/tag.out_markdown b/regress/mdoc/Er/tag.out_markdown new file mode 100644 index 00000000..d11eb4b9 --- /dev/null +++ b/regress/mdoc/Er/tag.out_markdown @@ -0,0 +1,25 @@ +ER-TAG(1) - General Commands Manual + +# NAME + +**Er-tag** - tagging of error number macros + +# DESCRIPTION + +BEGINTEST + +`one` + +> text + +`two` + +# ERRORS + +\[`ENOENT`] + +> text + +ENDTEST + +OpenBSD - March 13, 2020 diff --git a/regress/mdoc/Er/tag.out_tag b/regress/mdoc/Er/tag.out_tag new file mode 100644 index 00000000..b00a6718 --- /dev/null +++ b/regress/mdoc/Er/tag.out_tag @@ -0,0 +1,2 @@ +two 10 +ENOENT 13 diff --git a/regress/mdoc/Ev/Makefile b/regress/mdoc/Ev/Makefile index cfe3ad0b..979e1826 100644 --- a/regress/mdoc/Ev/Makefile +++ b/regress/mdoc/Ev/Makefile @@ -1,6 +1,8 @@ -# $OpenBSD: Makefile,v 1.2 2014/07/02 20:18:42 schwarze Exp $ +# $OpenBSD: Makefile,v 1.5 2020/03/13 00:31:05 schwarze Exp $ -REGRESS_TARGETS = font noarg +REGRESS_TARGETS = font noarg tag +TAG_TARGETS = tag LINT_TARGETS = noarg +HTML_TARGETS = tag .include diff --git a/regress/mdoc/Ev/tag.in b/regress/mdoc/Ev/tag.in new file mode 100644 index 00000000..2627fdeb --- /dev/null +++ b/regress/mdoc/Ev/tag.in @@ -0,0 +1,21 @@ +.\" $OpenBSD: tag.in,v 1.1 2020/03/13 00:31:05 schwarze Exp $ +.Dd $Mdocdate: March 13 2020 $ +.Dt EV-TAG 1 +.Os +.Sh NAME +.Nm Ev-tag +.Nd tagging of environment variable macros +.Sh DESCRIPTION +BEGINTEST +.Bl -tag -width Ds +.It Ev one | two +text +.It Xo +.Ev three +.Xc +text +.El +.Tg +.Ev four +.Pp +ENDTEST diff --git a/regress/mdoc/Ev/tag.out_ascii b/regress/mdoc/Ev/tag.out_ascii new file mode 100644 index 00000000..5569d1c8 --- /dev/null +++ b/regress/mdoc/Ev/tag.out_ascii @@ -0,0 +1,17 @@ +EV-TAG(1) General Commands Manual EV-TAG(1) + +NNAAMMEE + EEvv--ttaagg - tagging of environment variable macros + +DDEESSCCRRIIPPTTIIOONN + BEGINTEST + + one | two + text + + three text + four + + ENDTEST + +OpenBSD March 13, 2020 OpenBSD diff --git a/regress/mdoc/Ev/tag.out_html b/regress/mdoc/Ev/tag.out_html new file mode 100644 index 00000000..1e1c92b9 --- /dev/null +++ b/regress/mdoc/Ev/tag.out_html @@ -0,0 +1,9 @@ +
+
+ | +
+
text
+
+
text
+
+ diff --git a/regress/mdoc/Ev/tag.out_markdown b/regress/mdoc/Ev/tag.out_markdown new file mode 100644 index 00000000..f9a6712b --- /dev/null +++ b/regress/mdoc/Ev/tag.out_markdown @@ -0,0 +1,23 @@ +EV-TAG(1) - General Commands Manual + +# NAME + +**Ev-tag** - tagging of environment variable macros + +# DESCRIPTION + +BEGINTEST + +`one` | `two` + +> text + +`three` + +> text + +`four` + +ENDTEST + +OpenBSD - March 13, 2020 diff --git a/regress/mdoc/Ev/tag.out_tag b/regress/mdoc/Ev/tag.out_tag new file mode 100644 index 00000000..94f0cfb2 --- /dev/null +++ b/regress/mdoc/Ev/tag.out_tag @@ -0,0 +1,4 @@ +one 9 +two 9 +three 12 +four 13 diff --git a/regress/mdoc/Fl/Makefile b/regress/mdoc/Fl/Makefile index e4e4a6bc..c061adef 100644 --- a/regress/mdoc/Fl/Makefile +++ b/regress/mdoc/Fl/Makefile @@ -1,6 +1,9 @@ -# $OpenBSD: Makefile,v 1.13 2020/02/27 01:25:58 schwarze Exp $ +# $OpenBSD: Makefile,v 1.14 2020/03/13 00:31:06 schwarze Exp $ -REGRESS_TARGETS = font multiarg noarg parsed punct spacing +REGRESS_TARGETS = font multiarg noarg parsed punct spacing tag +TAG_TARGETS = tag LINT_TARGETS = punct +HTML_TARGETS = tag +SKIP_TMAN = tag .include diff --git a/regress/mdoc/Fl/tag.in b/regress/mdoc/Fl/tag.in new file mode 100644 index 00000000..f7e24b9f --- /dev/null +++ b/regress/mdoc/Fl/tag.in @@ -0,0 +1,21 @@ +.\" $OpenBSD: tag.in,v 1.1 2020/03/13 00:31:06 schwarze Exp $ +.Dd $Mdocdate: March 13 2020 $ +.Dt FL-TAG 1 +.Os +.Sh NAME +.Nm Fl-tag +.Nd tagging of command line option macros +.Sh DESCRIPTION +BEGINTEST +.Bl -tag -width Ds +.It Fl a | b +text +.It Xo +.Fl c +.Xc +text +.El +.Tg +.Fl d +.Pp +ENDTEST diff --git a/regress/mdoc/Fl/tag.out_ascii b/regress/mdoc/Fl/tag.out_ascii new file mode 100644 index 00000000..4fcf803c --- /dev/null +++ b/regress/mdoc/Fl/tag.out_ascii @@ -0,0 +1,17 @@ +FL-TAG(1) General Commands Manual FL-TAG(1) + +NNAAMMEE + FFll--ttaagg - tagging of command line option macros + +DDEESSCCRRIIPPTTIIOONN + BEGINTEST + + --aa | --bb + text + + --cc text + --dd + + ENDTEST + +OpenBSD March 13, 2020 OpenBSD diff --git a/regress/mdoc/Fl/tag.out_html b/regress/mdoc/Fl/tag.out_html new file mode 100644 index 00000000..f67a30c0 --- /dev/null +++ b/regress/mdoc/Fl/tag.out_html @@ -0,0 +1,8 @@ +
+
| +
+
text
+
+
text
+
+ diff --git a/regress/mdoc/Fl/tag.out_markdown b/regress/mdoc/Fl/tag.out_markdown new file mode 100644 index 00000000..1e7c6f14 --- /dev/null +++ b/regress/mdoc/Fl/tag.out_markdown @@ -0,0 +1,23 @@ +FL-TAG(1) - General Commands Manual + +# NAME + +**Fl-tag** - tagging of command line option macros + +# DESCRIPTION + +BEGINTEST + +**-a** | **-b** + +> text + +**-c** + +> text + +**-d** + +ENDTEST + +OpenBSD - March 13, 2020 diff --git a/regress/mdoc/Fl/tag.out_tag b/regress/mdoc/Fl/tag.out_tag new file mode 100644 index 00000000..89a94151 --- /dev/null +++ b/regress/mdoc/Fl/tag.out_tag @@ -0,0 +1,4 @@ +a 9 +b 9 +c 12 +d 13 diff --git a/regress/mdoc/Fo/Makefile b/regress/mdoc/Fo/Makefile index 7770e9a1..ce25ddf3 100644 --- a/regress/mdoc/Fo/Makefile +++ b/regress/mdoc/Fo/Makefile @@ -1,8 +1,10 @@ -# $OpenBSD: Makefile,v 1.17 2020/02/27 01:25:58 schwarze Exp $ +# $OpenBSD: Makefile,v 1.18 2020/03/13 00:31:06 schwarze Exp $ REGRESS_TARGETS = basic break eos font noarg nohead -REGRESS_TARGETS += obsolete punct section transp warn +REGRESS_TARGETS += obsolete punct section tag transp warn +TAG_TARGETS = tag LINT_TARGETS = noarg nohead obsolete punct warn +HTML_TARGETS = tag # groff-1.22.3 defects: # - .Fo without an argument prints unbalanced parentheses diff --git a/regress/mdoc/Fo/tag.in b/regress/mdoc/Fo/tag.in new file mode 100644 index 00000000..29b84ffe --- /dev/null +++ b/regress/mdoc/Fo/tag.in @@ -0,0 +1,29 @@ +.\" $OpenBSD: tag.in,v 1.1 2020/03/13 00:31:06 schwarze Exp $ +.Dd $Mdocdate: March 13 2020 $ +.Dt FO-TAG 1 +.Os +.Sh NAME +.Nm Fo-tag +.Nd tagging of function name macros +.Sh DESCRIPTION +BEGINTEST +.Pp +automatic: +.Fn first +and +.Fn second +.Pp +.Fn second +and +.Fn first +.Pp +explicit: +.Tg e3 +.Fn third +and +.Tg e4 +.Fo fourth +.Fa void +.Fc +.Pp +ENDTEST diff --git a/regress/mdoc/Fo/tag.out_ascii b/regress/mdoc/Fo/tag.out_ascii new file mode 100644 index 00000000..505c0b7a --- /dev/null +++ b/regress/mdoc/Fo/tag.out_ascii @@ -0,0 +1,17 @@ +FO-TAG(1) General Commands Manual FO-TAG(1) + +NNAAMMEE + FFoo--ttaagg - tagging of function name macros + +DDEESSCCRRIIPPTTIIOONN + BEGINTEST + + automatic: ffiirrsstt() and sseeccoonndd() + + sseeccoonndd() and ffiirrsstt() + + explicit: tthhiirrdd() and ffoouurrtthh(_v_o_i_d) + + ENDTEST + +OpenBSD March 13, 2020 OpenBSD diff --git a/regress/mdoc/Fo/tag.out_html b/regress/mdoc/Fo/tag.out_html new file mode 100644 index 00000000..b3508614 --- /dev/null +++ b/regress/mdoc/Fo/tag.out_html @@ -0,0 +1,9 @@ +

automatic: + () + and second()

+

() + and first()

+

explicit: + () + and + (void);

diff --git a/regress/mdoc/Fo/tag.out_markdown b/regress/mdoc/Fo/tag.out_markdown new file mode 100644 index 00000000..273a00d4 --- /dev/null +++ b/regress/mdoc/Fo/tag.out_markdown @@ -0,0 +1,27 @@ +FO-TAG(1) - General Commands Manual + +# NAME + +**Fo-tag** - tagging of function name macros + +# DESCRIPTION + +BEGINTEST + +automatic: +**first**() +and +**second**() + +**second**() +and +**first**() + +explicit: +**third**() +and +**fourth**(*void*) + +ENDTEST + +OpenBSD - March 13, 2020 diff --git a/regress/mdoc/Fo/tag.out_tag b/regress/mdoc/Fo/tag.out_tag new file mode 100644 index 00000000..2387023c --- /dev/null +++ b/regress/mdoc/Fo/tag.out_tag @@ -0,0 +1,4 @@ +first 9 +second 11 +e3 13 +e4 13 diff --git a/regress/mdoc/Ic/Makefile b/regress/mdoc/Ic/Makefile index 33faa380..4a06ee20 100644 --- a/regress/mdoc/Ic/Makefile +++ b/regress/mdoc/Ic/Makefile @@ -1,6 +1,8 @@ -# $OpenBSD: Makefile,v 1.4 2014/07/02 20:18:42 schwarze Exp $ +# $OpenBSD: Makefile,v 1.8 2020/03/13 00:31:06 schwarze Exp $ -REGRESS_TARGETS = font noarg punct +REGRESS_TARGETS = font noarg punct tag +TAG_TARGETS = tag LINT_TARGETS = noarg +HTML_TARGETS = tag .include diff --git a/regress/mdoc/Ic/tag.in b/regress/mdoc/Ic/tag.in new file mode 100644 index 00000000..9d21426e --- /dev/null +++ b/regress/mdoc/Ic/tag.in @@ -0,0 +1,21 @@ +.\" $OpenBSD: tag.in,v 1.1 2020/03/13 00:31:06 schwarze Exp $ +.Dd $Mdocdate: March 13 2020 $ +.Dt IC-TAG 1 +.Os +.Sh NAME +.Nm Ic-tag +.Nd tagging of internal command macros +.Sh DESCRIPTION +BEGINTEST +.Bl -tag -width Ds +.It Ic one | two +text +.It Xo +.Ic three +.Xc +text +.El +.Tg +.Ic four +.Pp +ENDTEST diff --git a/regress/mdoc/Ic/tag.out_ascii b/regress/mdoc/Ic/tag.out_ascii new file mode 100644 index 00000000..513b2638 --- /dev/null +++ b/regress/mdoc/Ic/tag.out_ascii @@ -0,0 +1,17 @@ +IC-TAG(1) General Commands Manual IC-TAG(1) + +NNAAMMEE + IIcc--ttaagg - tagging of internal command macros + +DDEESSCCRRIIPPTTIIOONN + BEGINTEST + + oonnee | ttwwoo + text + + tthhrreeee text + ffoouurr + + ENDTEST + +OpenBSD March 13, 2020 OpenBSD diff --git a/regress/mdoc/Ic/tag.out_html b/regress/mdoc/Ic/tag.out_html new file mode 100644 index 00000000..ad3cc1ef --- /dev/null +++ b/regress/mdoc/Ic/tag.out_html @@ -0,0 +1,9 @@ +
+
+ | +
+
text
+
+
text
+
+ diff --git a/regress/mdoc/Ic/tag.out_markdown b/regress/mdoc/Ic/tag.out_markdown new file mode 100644 index 00000000..c0f13879 --- /dev/null +++ b/regress/mdoc/Ic/tag.out_markdown @@ -0,0 +1,23 @@ +IC-TAG(1) - General Commands Manual + +# NAME + +**Ic-tag** - tagging of internal command macros + +# DESCRIPTION + +BEGINTEST + +**one** | **two** + +> text + +**three** + +> text + +**four** + +ENDTEST + +OpenBSD - March 13, 2020 diff --git a/regress/mdoc/Ic/tag.out_tag b/regress/mdoc/Ic/tag.out_tag new file mode 100644 index 00000000..94f0cfb2 --- /dev/null +++ b/regress/mdoc/Ic/tag.out_tag @@ -0,0 +1,4 @@ +one 9 +two 9 +three 12 +four 13 diff --git a/regress/mdoc/Li/Makefile b/regress/mdoc/Li/Makefile index 7b2a3313..44dcf01c 100644 --- a/regress/mdoc/Li/Makefile +++ b/regress/mdoc/Li/Makefile @@ -1,6 +1,8 @@ -# $OpenBSD: Makefile,v 1.7 2018/12/21 16:58:49 schwarze Exp $ +# $OpenBSD: Makefile,v 1.8 2020/03/13 00:31:06 schwarze Exp $ -REGRESS_TARGETS = arg punct font +REGRESS_TARGETS = arg punct font tag +TAG_TARGETS = tag LINT_TARGETS = punct +HTML_TARGETS = tag .include diff --git a/regress/mdoc/Li/tag.in b/regress/mdoc/Li/tag.in new file mode 100644 index 00000000..0ee9ce82 --- /dev/null +++ b/regress/mdoc/Li/tag.in @@ -0,0 +1,21 @@ +.\" $OpenBSD: tag.in,v 1.1 2020/03/13 00:31:06 schwarze Exp $ +.Dd $Mdocdate: March 13 2020 $ +.Dt LI-TAG 1 +.Os +.Sh NAME +.Nm Li-tag +.Nd tagging of literal font macros +.Sh DESCRIPTION +BEGINTEST +.Bl -tag -width Ds +.It Li one | two +text +.It Xo +.Li three +.Xc +text +.El +.Tg +.Li four +.Pp +ENDTEST diff --git a/regress/mdoc/Li/tag.out_ascii b/regress/mdoc/Li/tag.out_ascii new file mode 100644 index 00000000..e1afda6e --- /dev/null +++ b/regress/mdoc/Li/tag.out_ascii @@ -0,0 +1,17 @@ +LI-TAG(1) General Commands Manual LI-TAG(1) + +NNAAMMEE + LLii--ttaagg - tagging of literal font macros + +DDEESSCCRRIIPPTTIIOONN + BEGINTEST + + one | two + text + + three text + four + + ENDTEST + +OpenBSD March 13, 2020 OpenBSD diff --git a/regress/mdoc/Li/tag.out_html b/regress/mdoc/Li/tag.out_html new file mode 100644 index 00000000..3730caa6 --- /dev/null +++ b/regress/mdoc/Li/tag.out_html @@ -0,0 +1,9 @@ +
+
+ | +
+
text
+
+
text
+
+ diff --git a/regress/mdoc/Li/tag.out_markdown b/regress/mdoc/Li/tag.out_markdown new file mode 100644 index 00000000..6467e16d --- /dev/null +++ b/regress/mdoc/Li/tag.out_markdown @@ -0,0 +1,23 @@ +LI-TAG(1) - General Commands Manual + +# NAME + +**Li-tag** - tagging of literal font macros + +# DESCRIPTION + +BEGINTEST + +`one` | `two` + +> text + +`three` + +> text + +`four` + +ENDTEST + +OpenBSD - March 13, 2020 diff --git a/regress/mdoc/Li/tag.out_tag b/regress/mdoc/Li/tag.out_tag new file mode 100644 index 00000000..94f0cfb2 --- /dev/null +++ b/regress/mdoc/Li/tag.out_tag @@ -0,0 +1,4 @@ +one 9 +two 9 +three 12 +four 13 diff --git a/regress/mdoc/Makefile b/regress/mdoc/Makefile index 86bdcb7a..83bd7fb7 100644 --- a/regress/mdoc/Makefile +++ b/regress/mdoc/Makefile @@ -1,9 +1,9 @@ -# $OpenBSD: Makefile,v 1.32 2017/01/11 17:39:45 schwarze Exp $ +# $OpenBSD: Makefile,v 1.33 2020/03/13 00:31:05 schwarze Exp $ SUBDIR = Ad An Ap Aq Ar At Bd Bf Bk Bl Brq Bx Cd Cm SUBDIR += D1 Db Dd Dl Dq Dt Dv Em Eo Er Ev Ex Fd Fl Fo Ft Ic In Lb Li Lk SUBDIR += Ms Mt Nd Nm No Ns Oo Op Os Ox Pa Pf Pp Qq Rs Rv -SUBDIR += Sh Sm Sq St Sx Sy Tn Ud Ux Va Vt Xr blank break +SUBDIR += Sh Sm Sq St Sx Sy Tg Tn Ud Ux Va Vt Xr blank break .include "../Makefile.sub" .include diff --git a/regress/mdoc/Ms/Makefile b/regress/mdoc/Ms/Makefile index 1be2a84a..618edd3f 100644 --- a/regress/mdoc/Ms/Makefile +++ b/regress/mdoc/Ms/Makefile @@ -1,6 +1,8 @@ -# $OpenBSD: Makefile,v 1.4 2014/07/02 20:18:42 schwarze Exp $ +# $OpenBSD: Makefile,v 1.8 2020/03/13 00:58:48 schwarze Exp $ -REGRESS_TARGETS = noarg font +REGRESS_TARGETS = noarg font tag +TAG_TARGETS = tag LINT_TARGETS = noarg +HTML_TARGETS = tag .include diff --git a/regress/mdoc/Ms/tag.in b/regress/mdoc/Ms/tag.in new file mode 100644 index 00000000..da65a07e --- /dev/null +++ b/regress/mdoc/Ms/tag.in @@ -0,0 +1,21 @@ +.\" $OpenBSD: tag.in,v 1.1 2020/03/13 00:31:06 schwarze Exp $ +.Dd $Mdocdate: March 13 2020 $ +.Dt MS-TAG 1 +.Os +.Sh NAME +.Nm Ms-tag +.Nd tagging of mathematical symbol macros +.Sh DESCRIPTION +BEGINTEST +.Bl -tag -width Ds +.It Ms one | two +text +.It Xo +.Ms three +.Xc +text +.El +.Tg +.Ms four +.Pp +ENDTEST diff --git a/regress/mdoc/Ms/tag.out_ascii b/regress/mdoc/Ms/tag.out_ascii new file mode 100644 index 00000000..2d06f4bf --- /dev/null +++ b/regress/mdoc/Ms/tag.out_ascii @@ -0,0 +1,17 @@ +MS-TAG(1) General Commands Manual MS-TAG(1) + +NNAAMMEE + MMss--ttaagg - tagging of mathematical symbol macros + +DDEESSCCRRIIPPTTIIOONN + BEGINTEST + + oonnee | ttwwoo + text + + tthhrreeee text + ffoouurr + + ENDTEST + +OpenBSD March 13, 2020 OpenBSD diff --git a/regress/mdoc/Ms/tag.out_html b/regress/mdoc/Ms/tag.out_html new file mode 100644 index 00000000..0f24b2ac --- /dev/null +++ b/regress/mdoc/Ms/tag.out_html @@ -0,0 +1,9 @@ +
+
+ | +
+
text
+
+
text
+
+ diff --git a/regress/mdoc/Ms/tag.out_markdown b/regress/mdoc/Ms/tag.out_markdown new file mode 100644 index 00000000..055c3860 --- /dev/null +++ b/regress/mdoc/Ms/tag.out_markdown @@ -0,0 +1,23 @@ +MS-TAG(1) - General Commands Manual + +# NAME + +**Ms-tag** - tagging of mathematical symbol macros + +# DESCRIPTION + +BEGINTEST + +**one** | **two** + +> text + +**three** + +> text + +**four** + +ENDTEST + +OpenBSD - March 13, 2020 diff --git a/regress/mdoc/Ms/tag.out_tag b/regress/mdoc/Ms/tag.out_tag new file mode 100644 index 00000000..94f0cfb2 --- /dev/null +++ b/regress/mdoc/Ms/tag.out_tag @@ -0,0 +1,4 @@ +one 9 +two 9 +three 12 +four 13 diff --git a/regress/mdoc/No/Makefile b/regress/mdoc/No/Makefile index 3110bf2b..35aa4e1e 100644 --- a/regress/mdoc/No/Makefile +++ b/regress/mdoc/No/Makefile @@ -1,6 +1,8 @@ -# $OpenBSD: Makefile,v 1.4 2014/11/17 06:44:35 schwarze Exp $ +# $OpenBSD: Makefile,v 1.7 2020/03/13 00:31:06 schwarze Exp $ -REGRESS_TARGETS = punct spacing +REGRESS_TARGETS = punct spacing tag +TAG_TARGETS = tag LINT_TARGETS = punct +HTML_TARGETS = tag .include diff --git a/regress/mdoc/No/punct.out_lint b/regress/mdoc/No/punct.out_lint index e046da6a..6a65c3b4 100644 --- a/regress/mdoc/No/punct.out_lint +++ b/regress/mdoc/No/punct.out_lint @@ -23,3 +23,4 @@ mandoc: punct.in:72:7: WARNING: skipping empty macro: No mandoc: punct.in:75:7: WARNING: skipping empty macro: No mandoc: punct.in:76:7: WARNING: skipping empty macro: No mandoc: punct.in:84:2: WARNING: skipping empty macro: No +mandoc: punct.in:87:6: STYLE: no blank before trailing delimiter: No a. diff --git a/regress/mdoc/No/tag.in b/regress/mdoc/No/tag.in new file mode 100644 index 00000000..a9d4415f --- /dev/null +++ b/regress/mdoc/No/tag.in @@ -0,0 +1,21 @@ +.\" $OpenBSD: tag.in,v 1.1 2020/03/13 00:31:06 schwarze Exp $ +.Dd $Mdocdate: March 13 2020 $ +.Dt NO-TAG 1 +.Os +.Sh NAME +.Nm No-tag +.Nd tagging of normal font macros +.Sh DESCRIPTION +BEGINTEST +.Bl -tag -width Ds +.It No one | two +text +.It Xo +.No three +.Xc +text +.El +.Tg +.No four +.Pp +ENDTEST diff --git a/regress/mdoc/No/tag.out_ascii b/regress/mdoc/No/tag.out_ascii new file mode 100644 index 00000000..44481b02 --- /dev/null +++ b/regress/mdoc/No/tag.out_ascii @@ -0,0 +1,17 @@ +NO-TAG(1) General Commands Manual NO-TAG(1) + +NNAAMMEE + NNoo--ttaagg - tagging of normal font macros + +DDEESSCCRRIIPPTTIIOONN + BEGINTEST + + one | two + text + + three text + four + + ENDTEST + +OpenBSD March 13, 2020 OpenBSD diff --git a/regress/mdoc/No/tag.out_html b/regress/mdoc/No/tag.out_html new file mode 100644 index 00000000..32696917 --- /dev/null +++ b/regress/mdoc/No/tag.out_html @@ -0,0 +1,9 @@ +
+
+ | +
+
text
+
+
text
+
+ diff --git a/regress/mdoc/No/tag.out_markdown b/regress/mdoc/No/tag.out_markdown new file mode 100644 index 00000000..1590c010 --- /dev/null +++ b/regress/mdoc/No/tag.out_markdown @@ -0,0 +1,23 @@ +NO-TAG(1) - General Commands Manual + +# NAME + +**No-tag** - tagging of normal font macros + +# DESCRIPTION + +BEGINTEST + +one | two + +> text + +three + +> text + +four + +ENDTEST + +OpenBSD - March 13, 2020 diff --git a/regress/mdoc/No/tag.out_tag b/regress/mdoc/No/tag.out_tag new file mode 100644 index 00000000..94f0cfb2 --- /dev/null +++ b/regress/mdoc/No/tag.out_tag @@ -0,0 +1,4 @@ +one 9 +two 9 +three 12 +four 13 diff --git a/regress/mdoc/Sy/Makefile b/regress/mdoc/Sy/Makefile index 36c1859b..752d1382 100644 --- a/regress/mdoc/Sy/Makefile +++ b/regress/mdoc/Sy/Makefile @@ -1,6 +1,8 @@ -# $OpenBSD: Makefile,v 1.5 2014/11/17 06:44:35 schwarze Exp $ +# $OpenBSD: Makefile,v 1.8 2020/03/13 00:31:06 schwarze Exp $ -REGRESS_TARGETS = noarg font punct +REGRESS_TARGETS = noarg font punct tag +TAG_TARGETS = tag LINT_TARGETS = noarg punct +HTML_TARGETS = tag .include diff --git a/regress/mdoc/Sy/tag.in b/regress/mdoc/Sy/tag.in new file mode 100644 index 00000000..1294e17d --- /dev/null +++ b/regress/mdoc/Sy/tag.in @@ -0,0 +1,23 @@ +.\" $OpenBSD: tag.in,v 1.1 2020/03/13 00:31:06 schwarze Exp $ +.Dd $Mdocdate: March 13 2020 $ +.Dt SY-TAG 1 +.Os +.Sh NAME +.Nm Sy-tag +.Nd tagging of symbolic font macros +.Sh DESCRIPTION +BEGINTEST +.Bl -tag -width Ds +.It Sy one | two +text +.It Xo +.Sy three +.Xc +text +.El +.Sy four +.Sy one +.Tg explicit +.Sy five +.Pp +ENDTEST diff --git a/regress/mdoc/Sy/tag.out_ascii b/regress/mdoc/Sy/tag.out_ascii new file mode 100644 index 00000000..3b89cb41 --- /dev/null +++ b/regress/mdoc/Sy/tag.out_ascii @@ -0,0 +1,17 @@ +SY-TAG(1) General Commands Manual SY-TAG(1) + +NNAAMMEE + SSyy--ttaagg - tagging of symbolic font macros + +DDEESSCCRRIIPPTTIIOONN + BEGINTEST + + oonnee | ttwwoo + text + + tthhrreeee text + ffoouurr oonnee ffiivvee + + ENDTEST + +OpenBSD March 13, 2020 OpenBSD diff --git a/regress/mdoc/Sy/tag.out_html b/regress/mdoc/Sy/tag.out_html new file mode 100644 index 00000000..69276a18 --- /dev/null +++ b/regress/mdoc/Sy/tag.out_html @@ -0,0 +1,10 @@ +
+
| +
+
text
+
+
text
+
+ + one + diff --git a/regress/mdoc/Sy/tag.out_markdown b/regress/mdoc/Sy/tag.out_markdown new file mode 100644 index 00000000..5382a5e2 --- /dev/null +++ b/regress/mdoc/Sy/tag.out_markdown @@ -0,0 +1,25 @@ +SY-TAG(1) - General Commands Manual + +# NAME + +**Sy-tag** - tagging of symbolic font macros + +# DESCRIPTION + +BEGINTEST + +**one** | **two** + +> text + +**three** + +> text + +**four** +**one** +**five** + +ENDTEST + +OpenBSD - March 13, 2020 diff --git a/regress/mdoc/Sy/tag.out_tag b/regress/mdoc/Sy/tag.out_tag new file mode 100644 index 00000000..c2fbaf59 --- /dev/null +++ b/regress/mdoc/Sy/tag.out_tag @@ -0,0 +1,5 @@ +one 9 +two 9 +three 12 +four 13 +explicit 13 diff --git a/regress/mdoc/Tg/Makefile b/regress/mdoc/Tg/Makefile new file mode 100644 index 00000000..7f538766 --- /dev/null +++ b/regress/mdoc/Tg/Makefile @@ -0,0 +1,8 @@ +# $OpenBSD: Makefile,v 1.1 2020/03/13 00:31:06 schwarze Exp $ + +REGRESS_TARGETS = warn +TAG_TARGETS = warn +LINT_TARGETS = warn +HTML_TARGETS = warn + +.include diff --git a/regress/mdoc/Tg/warn.in b/regress/mdoc/Tg/warn.in new file mode 100644 index 00000000..e36f4506 --- /dev/null +++ b/regress/mdoc/Tg/warn.in @@ -0,0 +1,34 @@ +.\" $OpenBSD: warn.in,v 1.1 2020/03/13 00:31:06 schwarze Exp $ +.Dd $Mdocdate: March 13 2020 $ +.Dt TG-WARN 1 +.Os +.Sh NAME +.Nm Tg-warn +.Nd warnings about tagging macros +.Sh DESCRIPTION +BEGINTEST +.Pp +.Tg start +initial +text +.Tg +.Ic macro +.Tg "" ignored arguments +too many +.Tg \&badstart +badstart +.Tg badend\& +badend +.Tg "white space" +whitespace +.Tg sub +.Tg double +.Ss Subsection +subtext +.Tg examples +.Sh EXAMPLES +example +text +.Pp +ENDTEST +.Tg diff --git a/regress/mdoc/Tg/warn.out_ascii b/regress/mdoc/Tg/warn.out_ascii new file mode 100644 index 00000000..8dee9aed --- /dev/null +++ b/regress/mdoc/Tg/warn.out_ascii @@ -0,0 +1,19 @@ +TG-WARN(1) General Commands Manual TG-WARN(1) + +NNAAMMEE + TTgg--wwaarrnn - warnings about tagging macros + +DDEESSCCRRIIPPTTIIOONN + BEGINTEST + + initial text mmaaccrroo too many badstart badend whitespace + + SSuubbsseeccttiioonn + subtext + +EEXXAAMMPPLLEESS + example text + + ENDTEST + +OpenBSD March 13, 2020 OpenBSD diff --git a/regress/mdoc/Tg/warn.out_html b/regress/mdoc/Tg/warn.out_html new file mode 100644 index 00000000..b4d3cf74 --- /dev/null +++ b/regress/mdoc/Tg/warn.out_html @@ -0,0 +1,11 @@ +

initial text + + too many badstart badend whitespace

+
+

+

subtext

+
+
+
+

+

example text

diff --git a/regress/mdoc/Tg/warn.out_lint b/regress/mdoc/Tg/warn.out_lint new file mode 100644 index 00000000..39c1f541 --- /dev/null +++ b/regress/mdoc/Tg/warn.out_lint @@ -0,0 +1,6 @@ +mandoc: warn.in:16:2: WARNING: skipping empty macro: Tg +mandoc: warn.in:16:8: ERROR: skipping excess arguments: Tg ... ignored +mandoc: warn.in:18:5: ERROR: skipping tag containing whitespace: Tg \&badstart +mandoc: warn.in:20:11: ERROR: skipping tag containing whitespace: Tg badend\& +mandoc: warn.in:22:10: ERROR: skipping tag containing whitespace: Tg white space +mandoc: warn.in:34:2: WARNING: skipping empty macro: Tg diff --git a/regress/mdoc/Tg/warn.out_markdown b/regress/mdoc/Tg/warn.out_markdown new file mode 100644 index 00000000..87204424 --- /dev/null +++ b/regress/mdoc/Tg/warn.out_markdown @@ -0,0 +1,30 @@ +TG-WARN(1) - General Commands Manual + +# NAME + +**Tg-warn** - warnings about tagging macros + +# DESCRIPTION + +BEGINTEST + +initial +text +**macro** +too many +badstart +badend +whitespace + +## Subsection + +subtext + +# EXAMPLES + +example +text + +ENDTEST + +OpenBSD - March 13, 2020 diff --git a/regress/mdoc/Tg/warn.out_tag b/regress/mdoc/Tg/warn.out_tag new file mode 100644 index 00000000..e1fc141c --- /dev/null +++ b/regress/mdoc/Tg/warn.out_tag @@ -0,0 +1,5 @@ +start 9 +macro 9 +sub 9 +double 11 +examples 14 diff --git a/regress/regress.pl b/regress/regress.pl index 5e7927cb..3c6e64df 100755 --- a/regress/regress.pl +++ b/regress/regress.pl @@ -1,8 +1,8 @@ #!/usr/bin/env perl # -# $Id: regress.pl,v 1.13 2020/01/08 10:37:53 schwarze Exp $ +# $Id: regress.pl,v 1.14 2020/03/13 15:32:31 schwarze Exp $ # -# Copyright (c) 2017 Ingo Schwarze +# Copyright (c) 2017, 2018, 2019, 2020 Ingo Schwarze # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above @@ -120,16 +120,17 @@ sub fail ($$) { my $onlytest = shift // ''; for (@ARGV) { - /^(all|ascii|utf8|man|html|markdown|lint|clean|verbose)$/ + /^(all|ascii|tag|man|utf8|html|markdown|lint|clean|verbose)$/ or usage "$_: invalid modifier"; $targets{$_} = 1; } $targets{all} = 1 - unless $targets{ascii} || $targets{utf8} || $targets{man} || - $targets{html} || $targets{markdown} || + unless $targets{ascii} || $targets{tag} || $targets{man} || + $targets{utf8} || $targets{html} || $targets{markdown} || $targets{lint} || $targets{clean}; -$targets{ascii} = $targets{utf8} = $targets{man} = $targets{html} = - $targets{markdown} = $targets{lint} = 1 if $targets{all}; +$targets{ascii} = $targets{tag} = $targets{man} = $targets{utf8} = + $targets{html} = $targets{markdown} = $targets{lint} = 1 + if $targets{all}; # --- parse Makefiles -------------------------------------------------- @@ -157,7 +158,7 @@ sub parse_makefile ($%) { } my (@regress_tests, @utf8_tests, @lint_tests, @html_tests); -my (%skip_ascii, %skip_man, %skip_markdown); +my (%tag_tests, %skip_ascii, %skip_man, %skip_markdown); foreach my $module (qw(roff char mdoc man tbl eqn)) { my %modvars; parse_makefile "$module/Makefile", \%modvars; @@ -168,36 +169,41 @@ foreach my $module (qw(roff char mdoc man tbl eqn)) { delete $subvars{GOPTS}; delete $subvars{SKIP_GROFF}; delete $subvars{SKIP_GROFF_ASCII}; - my @mandoc = ('../mandoc', split ' ', $subvars{MOPTS}); + my @mopts = split ' ', $subvars{MOPTS}; delete $subvars{MOPTS}; my @regress_testnames; + if (defined $subvars{TAG_TARGETS}) { + $tag_tests{"$module/$subdir/$_"} = 1 + for split ' ', $subvars{TAG_TARGETS}; + delete $subvars{TAG_TARGETS}; + } if (defined $subvars{REGRESS_TARGETS}) { push @regress_testnames, split ' ', $subvars{REGRESS_TARGETS}; push @regress_tests, { NAME => "$module/$subdir/$_", - MANDOC => \@mandoc, + MOPTS => \@mopts, } foreach @regress_testnames; delete $subvars{REGRESS_TARGETS}; } if (defined $subvars{UTF8_TARGETS}) { push @utf8_tests, { NAME => "$module/$subdir/$_", - MANDOC => \@mandoc, + MOPTS => \@mopts, } foreach split ' ', $subvars{UTF8_TARGETS}; delete $subvars{UTF8_TARGETS}; } if (defined $subvars{HTML_TARGETS}) { push @html_tests, { NAME => "$module/$subdir/$_", - MANDOC => \@mandoc, + MOPTS => \@mopts, } foreach split ' ', $subvars{HTML_TARGETS}; delete $subvars{HTML_TARGETS}; } if (defined $subvars{LINT_TARGETS}) { push @lint_tests, { NAME => "$module/$subdir/$_", - MANDOC => \@mandoc, + MOPTS => \@mopts, } foreach split ' ', $subvars{LINT_TARGETS}; delete $subvars{LINT_TARGETS}; } @@ -243,22 +249,44 @@ foreach my $module (qw(roff char mdoc man tbl eqn)) { my $count_total = 0; my $count_ascii = 0; +my $count_tag = 0; my $count_man = 0; my $count_rm = 0; -if ($targets{ascii} || $targets{man}) { - print "Running ascii and man tests "; +if ($targets{ascii} || $targets{tag} || $targets{man}) { + print "Running ascii, tag, and man tests "; print "...\n" if $targets{verbose}; } for my $test (@regress_tests) { my $i = "$test->{NAME}.in"; my $o = "$test->{NAME}.mandoc_ascii"; my $w = "$test->{NAME}.out_ascii"; - if ($targets{ascii} && !$skip_ascii{$test->{NAME}} && + my $to = "$test->{NAME}.mandoc_tag"; + my $tw = "$test->{NAME}.out_tag"; + my $diff_ascii; + if ($targets{tag} && $tag_tests{$test->{NAME}} && $test->{NAME} =~ /^$onlytest/) { - $count_ascii++; + $count_tag++; $count_total++; - sysout $o, @{$test->{MANDOC}}, qw(-I os=OpenBSD -T ascii), $i + local $ENV{MANPAGER} = "./copyless $test->{NAME}"; + my @cmd = (qw(../man -l), @{$test->{MOPTS}}, + qw(-I os=OpenBSD -T ascii), $i); + print "@cmd\n" if $targets{verbose}; + system @cmd + and fail $test->{NAME}, 'tag:man'; + system @diff, $tw, $to + and fail $test->{NAME}, 'tag:diff'; + print "." unless $targets{verbose}; + $diff_ascii = $targets{ascii}; + } elsif ($targets{ascii} && !$skip_ascii{$test->{NAME}} && + $test->{NAME} =~ /^$onlytest/) { + sysout $o, '../mandoc', @{$test->{MOPTS}}, + qw(-I os=OpenBSD -T ascii), $i and fail $test->{NAME}, 'ascii:mandoc'; + $diff_ascii = 1; + } + if ($diff_ascii) { + $count_ascii++; + $count_total++; system @diff, $w, $o and fail $test->{NAME}, 'ascii:diff'; print "." unless $targets{verbose}; @@ -269,9 +297,10 @@ for my $test (@regress_tests) { $test->{NAME} =~ /^$onlytest/) { $count_man++; $count_total++; - sysout $m, @{$test->{MANDOC}}, qw(-I os=OpenBSD -T man), $i + sysout $m, '../mandoc', @{$test->{MOPTS}}, + qw(-I os=OpenBSD -T man), $i and fail $test->{NAME}, 'man:man'; - sysout $mo, @{$test->{MANDOC}}, + sysout $mo, '../mandoc', @{$test->{MOPTS}}, qw(-man -I os=OpenBSD -T ascii -O mdoc), $m and fail $test->{NAME}, 'man:mandoc'; system @diff, $w, $mo @@ -279,13 +308,13 @@ for my $test (@regress_tests) { print "." unless $targets{verbose}; } if ($targets{clean}) { - print "rm $o $m $mo\n" if $targets{verbose}; - $count_rm += unlink $o, $m, $mo; + print "rm $o $to $m $mo\n" if $targets{verbose}; + $count_rm += unlink $o, $to, $m, $mo; } } -if ($targets{ascii} || $targets{man}) { - print "Number of ascii and man tests:" if $targets{verbose}; - print " $count_ascii + $count_man tests run.\n"; +if ($targets{ascii} || $targets{tag} || $targets{man}) { + print "Number of ascii, tag, and man tests:" if $targets{verbose}; + print " $count_ascii + $count_tag + $count_man tests run.\n"; } my $count_utf8 = 0; @@ -300,7 +329,8 @@ for my $test (@utf8_tests) { if ($targets{utf8} && $test->{NAME} =~ /^$onlytest/o) { $count_utf8++; $count_total++; - sysout $o, @{$test->{MANDOC}}, qw(-I os=OpenBSD -T utf8), $i + sysout $o, '../mandoc', @{$test->{MOPTS}}, + qw(-I os=OpenBSD -T utf8), $i and fail $test->{NAME}, 'utf8:mandoc'; system @diff, $w, $o and fail $test->{NAME}, 'utf8:diff'; @@ -328,7 +358,8 @@ for my $test (@html_tests) { if ($targets{html} && $test->{NAME} =~ /^$onlytest/) { $count_html++; $count_total++; - syshtml $o, @{$test->{MANDOC}}, qw(-T html), $i + syshtml $o, '../mandoc', @{$test->{MOPTS}}, + qw(-T html), $i and fail $test->{NAME}, 'html:mandoc'; system @diff, $w, $o and fail $test->{NAME}, 'html:diff'; @@ -357,7 +388,7 @@ for my $test (@regress_tests) { $test->{NAME} =~ /^$onlytest/) { $count_markdown++; $count_total++; - sysout $o, @{$test->{MANDOC}}, + sysout $o, '../mandoc', @{$test->{MOPTS}}, qw(-I os=OpenBSD -T markdown), $i and fail $test->{NAME}, 'markdown:mandoc'; system @diff, $w, $o @@ -386,7 +417,7 @@ for my $test (@lint_tests) { if ($targets{lint} && $test->{NAME} =~ /^$onlytest/) { $count_lint++; $count_total++; - syslint $o, @{$test->{MANDOC}}, + syslint $o, '../mandoc', @{$test->{MOPTS}}, qw(-I os=OpenBSD -T lint -W all), $i and fail $test->{NAME}, 'lint:mandoc'; system @diff, $w, $o @@ -418,6 +449,7 @@ if ($count_total == 1) { } elsif ($count_total) { print "All $count_total tests OK:"; print " $count_ascii ascii" if $count_ascii; + print " $count_tag tag" if $count_tag; print " $count_man man" if $count_man; print " $count_utf8 utf8" if $count_utf8; print " $count_html html" if $count_html; diff --git a/regress/regress.pl.1 b/regress/regress.pl.1 index 04a56912..73db6118 100644 --- a/regress/regress.pl.1 +++ b/regress/regress.pl.1 @@ -1,6 +1,6 @@ -.\" $Id: regress.pl.1,v 1.4 2019/03/06 15:58:11 schwarze Exp $ +.\" $Id: regress.pl.1,v 1.5 2020/03/13 15:32:31 schwarze Exp $ .\" -.\" Copyright (c) 2017 Ingo Schwarze +.\" Copyright (c) 2017, 2019, 2020 Ingo Schwarze .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: March 6 2019 $ +.Dd $Mdocdate: March 13 2020 $ .Dt REGRESS.PL 1 .Os .Sh NAME @@ -78,6 +78,8 @@ output mode. Run subtests for .Fl T Cm markdown output mode. +.It Cm tag +Run subtests for automatic and manual tagging. .It Cm utf8 Run subtests for .Fl T Cm utf8 @@ -146,15 +148,6 @@ subdirectory of the regression suite is not included. It uses a Makefile structure that differs vastly from the rest of the suite. .Sh BUGS -On Oracle Solaris 11, -.Xr diff 1 -does not support the -.Fl a -option. -Delete that option from the following line in this script: -.Pp -.Dl my @diff = qw(diff -au); -.Pp The C library function .Xr wcwidth 3 is known to be buggy on Solaris, which may cause failures in the diff --git a/tag.c b/tag.c index 6df91c8b..50e74f48 100644 --- a/tag.c +++ b/tag.c @@ -1,4 +1,4 @@ -/* $Id: tag.c,v 1.27 2020/01/20 10:37:15 schwarze Exp $ */ +/* $Id: tag.c,v 1.28 2020/03/13 15:32:29 schwarze Exp $ */ /* * Copyright (c) 2015,2016,2018,2019,2020 Ingo Schwarze * @@ -13,134 +13,67 @@ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Functions to tag syntax tree nodes. + * For internal use by mandoc(1) validation modules only. */ #include "config.h" #include #include -#include #include -#include #include -#include -#include #include #include -#include #include "mandoc_aux.h" #include "mandoc_ohash.h" -#include "mandoc.h" +#include "roff.h" #include "tag.h" struct tag_entry { - size_t *lines; - size_t maxlines; - size_t nlines; + struct roff_node **nodes; + size_t maxnodes; + size_t nnodes; int prio; char s[]; }; -static void tag_signal(int) __attribute__((__noreturn__)); - static struct ohash tag_data; -static struct tag_files tag_files; /* - * Prepare for using a pager. - * Not all pagers are capable of using a tag file, - * but for simplicity, create it anyway. + * Set up the ohash table to collect nodes + * where various marked-up terms are documented. */ -struct tag_files * -tag_init(char *tagname) +void +tag_alloc(void) { - struct sigaction sa; - int ofd; - - ofd = -1; - tag_files.tfd = -1; - tag_files.tcpgid = -1; - tag_files.tagname = tagname; - - /* Clean up when dying from a signal. */ - - memset(&sa, 0, sizeof(sa)); - sigfillset(&sa.sa_mask); - sa.sa_handler = tag_signal; - sigaction(SIGHUP, &sa, NULL); - sigaction(SIGINT, &sa, NULL); - sigaction(SIGTERM, &sa, NULL); - - /* - * POSIX requires that a process calling tcsetpgrp(3) - * from the background gets a SIGTTOU signal. - * In that case, do not stop. - */ - - sa.sa_handler = SIG_IGN; - sigaction(SIGTTOU, &sa, NULL); - - /* Save the original standard output for use by the pager. */ - - if ((tag_files.ofd = dup(STDOUT_FILENO)) == -1) { - mandoc_msg(MANDOCERR_DUP, 0, 0, "%s", strerror(errno)); - goto fail; - } + mandoc_ohash_init(&tag_data, 4, offsetof(struct tag_entry, s)); +} - /* Create both temporary output files. */ +void +tag_free(void) +{ + struct tag_entry *entry; + unsigned int slot; - (void)strlcpy(tag_files.ofn, "/tmp/man.XXXXXXXXXX", - sizeof(tag_files.ofn)); - (void)strlcpy(tag_files.tfn, "/tmp/man.XXXXXXXXXX", - sizeof(tag_files.tfn)); - if ((ofd = mkstemp(tag_files.ofn)) == -1) { - mandoc_msg(MANDOCERR_MKSTEMP, 0, 0, - "%s: %s", tag_files.ofn, strerror(errno)); - goto fail; - } - if ((tag_files.tfd = mkstemp(tag_files.tfn)) == -1) { - mandoc_msg(MANDOCERR_MKSTEMP, 0, 0, - "%s: %s", tag_files.tfn, strerror(errno)); - goto fail; - } - if (dup2(ofd, STDOUT_FILENO) == -1) { - mandoc_msg(MANDOCERR_DUP, 0, 0, "%s", strerror(errno)); - goto fail; + entry = ohash_first(&tag_data, &slot); + while (entry != NULL) { + free(entry->nodes); + free(entry); + entry = ohash_next(&tag_data, &slot); } - close(ofd); - - /* - * Set up the ohash table to collect output line numbers - * where various marked-up terms are documented. - */ - - mandoc_ohash_init(&tag_data, 4, offsetof(struct tag_entry, s)); - return &tag_files; - -fail: - tag_unlink(); - if (ofd != -1) - close(ofd); - if (tag_files.ofd != -1) - close(tag_files.ofd); - if (tag_files.tfd != -1) - close(tag_files.tfd); - *tag_files.ofn = '\0'; - *tag_files.tfn = '\0'; - tag_files.ofd = -1; - tag_files.tfd = -1; - tag_files.tagname = NULL; - return NULL; + ohash_delete(&tag_data); } /* - * Set the line number where a term is defined, + * Set a node where a term is defined, * unless it is already defined at a lower priority. */ void -tag_put(const char *s, int prio, size_t line) +tag_put(const char *s, int prio, struct roff_node *n) { struct tag_entry *entry; const char *se; @@ -148,11 +81,14 @@ tag_put(const char *s, int prio, size_t line) unsigned int slot; assert(prio <= TAG_FALLBACK); - if (tag_files.tfd <= 0) - return; - if (s[0] == '\\' && (s[1] == '&' || s[1] == 'e')) - s += 2; + if (s == NULL) { + if (n->child == NULL || n->child->type != ROFFT_TEXT) + return; + s = n->child->string; + if (s[0] == '\\' && (s[1] == '&' || s[1] == 'e')) + s += 2; + } /* * Skip whitespace and escapes and whatever follows, @@ -170,131 +106,67 @@ tag_put(const char *s, int prio, size_t line) slot = ohash_qlookupi(&tag_data, s, &se); entry = ohash_find(&tag_data, slot); - if (entry == NULL) { - - /* Build a new entry. */ + /* Build a new entry. */ + if (entry == NULL) { entry = mandoc_malloc(sizeof(*entry) + len + 1); memcpy(entry->s, s, len); entry->s[len] = '\0'; - entry->lines = NULL; - entry->maxlines = entry->nlines = 0; + entry->nodes = NULL; + entry->maxnodes = entry->nnodes = 0; ohash_insert(&tag_data, slot, entry); + } - } else { - - /* - * Lower priority numbers take precedence, - * but TAG_FALLBACK is special. - * A tag with priority TAG_FALLBACK is only used - * if the tag occurs exactly once. - */ + /* + * Lower priority numbers take precedence. + * If a better entry is already present, ignore the new one. + */ - if (prio == TAG_FALLBACK) { - if (entry->prio == TAG_FALLBACK) - entry->prio = TAG_DELETE; + else if (entry->prio < prio) return; - } - /* A better entry is already present, ignore the new one. */ - - if (entry->prio < prio) - return; + /* + * If the existing entry is worse, clear it. + * In addition, a tag with priority TAG_FALLBACK + * is only used if the tag occurs exactly once. + */ - /* The existing entry is worse, clear it. */ + else if (entry->prio > prio || prio == TAG_FALLBACK) { + while (entry->nnodes > 0) + entry->nodes[--entry->nnodes]->flags &= ~NODE_ID; - if (entry->prio > prio) - entry->nlines = 0; + if (prio == TAG_FALLBACK) { + entry->prio = TAG_DELETE; + return; + } } - /* Remember the new line. */ + /* Remember the new node. */ - if (entry->maxlines == entry->nlines) { - entry->maxlines += 4; - entry->lines = mandoc_reallocarray(entry->lines, - entry->maxlines, sizeof(*entry->lines)); + if (entry->maxnodes == entry->nnodes) { + entry->maxnodes += 4; + entry->nodes = mandoc_reallocarray(entry->nodes, + entry->maxnodes, sizeof(*entry->nodes)); } - entry->lines[entry->nlines++] = line; + entry->nodes[entry->nnodes++] = n; entry->prio = prio; -} - -/* - * Write out the tags file using the previously collected - * information and clear the ohash table while going along. - */ -void -tag_write(void) -{ - FILE *stream; - struct tag_entry *entry; - size_t i; - unsigned int slot; - int empty; - - if (tag_files.tfd <= 0) - return; - if (tag_files.tagname != NULL && ohash_find(&tag_data, - ohash_qlookup(&tag_data, tag_files.tagname)) == NULL) { - mandoc_msg(MANDOCERR_TAG, 0, 0, "%s", tag_files.tagname); - tag_files.tagname = NULL; - } - if ((stream = fdopen(tag_files.tfd, "w")) == NULL) - mandoc_msg(MANDOCERR_FDOPEN, 0, 0, "%s", strerror(errno)); - empty = 1; - entry = ohash_first(&tag_data, &slot); - while (entry != NULL) { - if (stream != NULL && entry->prio < TAG_DELETE) { - for (i = 0; i < entry->nlines; i++) { - fprintf(stream, "%s %s %zu\n", - entry->s, tag_files.ofn, entry->lines[i]); - empty = 0; - } - } - free(entry->lines); - free(entry); - entry = ohash_next(&tag_data, &slot); - } - ohash_delete(&tag_data); - if (stream != NULL) - fclose(stream); - else - close(tag_files.tfd); - tag_files.tfd = -1; - if (empty) { - unlink(tag_files.tfn); - *tag_files.tfn = '\0'; + n->flags |= NODE_ID; + if (n->child == NULL || n->child->string != s || *se != '\0') { + assert(n->string == NULL); + n->string = mandoc_strndup(s, len); } } -void -tag_unlink(void) +enum tag_result +tag_check(const char *test_tag) { - pid_t tc_pgid; + unsigned int slot; - if (tag_files.tcpgid != -1) { - tc_pgid = tcgetpgrp(tag_files.ofd); - if (tc_pgid == tag_files.pager_pid || - tc_pgid == getpgid(0) || - getpgid(tc_pgid) == -1) - (void)tcsetpgrp(tag_files.ofd, tag_files.tcpgid); - } - if (*tag_files.ofn != '\0') - unlink(tag_files.ofn); - if (*tag_files.tfn != '\0') - unlink(tag_files.tfn); -} - -static void -tag_signal(int signum) -{ - struct sigaction sa; - - tag_unlink(); - memset(&sa, 0, sizeof(sa)); - sigemptyset(&sa.sa_mask); - sa.sa_handler = SIG_DFL; - sigaction(signum, &sa, NULL); - kill(getpid(), signum); - /* NOTREACHED */ - _exit(1); + if (ohash_first(&tag_data, &slot) == NULL) + return TAG_EMPTY; + else if (test_tag != NULL && ohash_find(&tag_data, + ohash_qlookup(&tag_data, test_tag)) == NULL) + return TAG_MISS; + else + return TAG_OK; } diff --git a/tag.h b/tag.h index 81ec35b4..0d37a66a 100644 --- a/tag.h +++ b/tag.h @@ -1,4 +1,4 @@ -/* $Id: tag.h,v 1.10 2020/01/20 10:37:15 schwarze Exp $ */ +/* $Id: tag.h,v 1.11 2020/03/13 15:32:29 schwarze Exp $ */ /* * Copyright (c) 2015, 2018, 2019, 2020 Ingo Schwarze * @@ -13,6 +13,9 @@ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Internal interfaces to tag syntax tree nodes. + * For use by mandoc(1) validation modules only. */ /* @@ -25,19 +28,17 @@ #define TAG_FALLBACK (INT_MAX - 1) /* Tag only used if unique. */ #define TAG_DELETE (INT_MAX) /* Tag not used at all. */ - -struct tag_files { - char ofn[20]; - char tfn[20]; - char *tagname; - int ofd; - int tfd; - pid_t tcpgid; - pid_t pager_pid; +/* + * Return values of tag_check(). + */ +enum tag_result { + TAG_OK, /* Argument exists as a tag. */ + TAG_MISS, /* Argument not found. */ + TAG_EMPTY /* No tag exists at all. */ }; -struct tag_files *tag_init(char *); -void tag_put(const char *, int, size_t); -void tag_write(void); -void tag_unlink(void); +void tag_alloc(void); +void tag_put(const char *, int, struct roff_node *); +enum tag_result tag_check(const char *); +void tag_free(void); diff --git a/term_tag.c b/term_tag.c new file mode 100644 index 00000000..cb9fa16d --- /dev/null +++ b/term_tag.c @@ -0,0 +1,206 @@ +/* $Id: term_tag.c,v 1.1 2020/03/13 15:32:29 schwarze Exp $ */ +/* + * Copyright (c) 2015,2016,2018,2019,2020 Ingo Schwarze + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Functions to write a ctags(1) file. + * For use by the mandoc(1) ASCII and UTF-8 formatters only. + */ +#include "config.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "mandoc.h" +#include "roff.h" +#include "tag.h" +#include "term_tag.h" + +static void tag_signal(int) __attribute__((__noreturn__)); + +static struct tag_files tag_files; + + +/* + * Prepare for using a pager. + * Not all pagers are capable of using a tag file, + * but for simplicity, create it anyway. + */ +struct tag_files * +term_tag_init(char *tagname) +{ + struct sigaction sa; + int ofd; /* In /tmp/, dup(2)ed to stdout. */ + int tfd; + + ofd = tfd = -1; + tag_files.tfs = NULL; + tag_files.tcpgid = -1; + tag_files.tagname = tagname; + + /* Clean up when dying from a signal. */ + + memset(&sa, 0, sizeof(sa)); + sigfillset(&sa.sa_mask); + sa.sa_handler = tag_signal; + sigaction(SIGHUP, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + + /* + * POSIX requires that a process calling tcsetpgrp(3) + * from the background gets a SIGTTOU signal. + * In that case, do not stop. + */ + + sa.sa_handler = SIG_IGN; + sigaction(SIGTTOU, &sa, NULL); + + /* Save the original standard output for use by the pager. */ + + if ((tag_files.ofd = dup(STDOUT_FILENO)) == -1) { + mandoc_msg(MANDOCERR_DUP, 0, 0, "%s", strerror(errno)); + goto fail; + } + + /* Create both temporary output files. */ + + (void)strlcpy(tag_files.ofn, "/tmp/man.XXXXXXXXXX", + sizeof(tag_files.ofn)); + (void)strlcpy(tag_files.tfn, "/tmp/man.XXXXXXXXXX", + sizeof(tag_files.tfn)); + if ((ofd = mkstemp(tag_files.ofn)) == -1) { + mandoc_msg(MANDOCERR_MKSTEMP, 0, 0, + "%s: %s", tag_files.ofn, strerror(errno)); + goto fail; + } + if ((tfd = mkstemp(tag_files.tfn)) == -1) { + mandoc_msg(MANDOCERR_MKSTEMP, 0, 0, + "%s: %s", tag_files.tfn, strerror(errno)); + goto fail; + } + if ((tag_files.tfs = fdopen(tfd, "w")) == NULL) { + mandoc_msg(MANDOCERR_FDOPEN, 0, 0, "%s", strerror(errno)); + goto fail; + } + tfd = -1; + if (dup2(ofd, STDOUT_FILENO) == -1) { + mandoc_msg(MANDOCERR_DUP, 0, 0, "%s", strerror(errno)); + goto fail; + } + close(ofd); + return &tag_files; + +fail: + term_tag_unlink(); + if (ofd != -1) + close(ofd); + if (tfd != -1) + close(tfd); + if (tag_files.ofd != -1) { + close(tag_files.ofd); + tag_files.ofd = -1; + } + tag_files.tagname = NULL; + return NULL; +} + +void +term_tag_write(struct roff_node *n, size_t line) +{ + const char *cp; + int len; + + if (tag_files.tfs == NULL) + return; + if (n->string == NULL) + n = n->child; + cp = n->string; + if (cp[0] == '\\' && (cp[1] == '&' || cp[1] == 'e')) + cp += 2; + len = strcspn(cp, " \t\\"); + fprintf(tag_files.tfs, "%.*s %s %zu\n", + len, cp, tag_files.ofn, line); +} + +void +term_tag_finish(void) +{ + if (tag_files.tfs == NULL) + return; + fclose(tag_files.tfs); + tag_files.tfs = NULL; + switch (tag_check(tag_files.tagname)) { + case TAG_EMPTY: + unlink(tag_files.tfn); + *tag_files.tfn = '\0'; + /* FALLTHROUGH */ + case TAG_MISS: + if (tag_files.tagname == NULL) + break; + mandoc_msg(MANDOCERR_TAG, 0, 0, "%s", tag_files.tagname); + tag_files.tagname = NULL; + break; + case TAG_OK: + break; + } +} + +void +term_tag_unlink(void) +{ + pid_t tc_pgid; + + if (tag_files.tcpgid != -1) { + tc_pgid = tcgetpgrp(tag_files.ofd); + if (tc_pgid == tag_files.pager_pid || + tc_pgid == getpgid(0) || + getpgid(tc_pgid) == -1) + (void)tcsetpgrp(tag_files.ofd, tag_files.tcpgid); + } + if (*tag_files.ofn != '\0') { + unlink(tag_files.ofn); + *tag_files.ofn = '\0'; + } + if (*tag_files.tfn != '\0') { + unlink(tag_files.tfn); + *tag_files.tfn = '\0'; + } + if (tag_files.tfs != NULL) { + fclose(tag_files.tfs); + tag_files.tfs = NULL; + } +} + +static void +tag_signal(int signum) +{ + struct sigaction sa; + + term_tag_unlink(); + memset(&sa, 0, sizeof(sa)); + sigemptyset(&sa.sa_mask); + sa.sa_handler = SIG_DFL; + sigaction(signum, &sa, NULL); + kill(getpid(), signum); + /* NOTREACHED */ + _exit(1); +} diff --git a/term_tag.h b/term_tag.h new file mode 100644 index 00000000..1acde47b --- /dev/null +++ b/term_tag.h @@ -0,0 +1,35 @@ +/* $Id: term_tag.h,v 1.1 2020/03/13 15:32:29 schwarze Exp $ */ +/* + * Copyright (c) 2015, 2018, 2019, 2020 Ingo Schwarze + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Internal interfaces to write a ctags(1) file. + * For use by the mandoc(1) ASCII and UTF-8 formatters only. + */ + +struct tag_files { + char ofn[20]; /* Output file name. */ + char tfn[20]; /* Tag file name. */ + char *tagname; /* Target specified with -O. */ + FILE *tfs; /* Tag file object. */ + int ofd; /* Original output file descriptor. */ + pid_t tcpgid; /* Process group controlling the terminal. */ + pid_t pager_pid; /* Process ID of the pager. */ +}; + + +struct tag_files *term_tag_init(char *); +void term_tag_write(struct roff_node *, size_t); +void term_tag_finish(void); +void term_tag_unlink(void); diff --git a/tree.c b/tree.c index c39e89b8..f08695d3 100644 --- a/tree.c +++ b/tree.c @@ -1,7 +1,7 @@ -/* $Id: tree.c,v 1.86 2020/02/27 21:43:45 schwarze Exp $ */ +/* $Id: tree.c,v 1.87 2020/03/13 15:32:29 schwarze Exp $ */ /* - * Copyright (c) 2008, 2009, 2011, 2014 Kristaps Dzonsons * Copyright (c) 2013-2015, 2017-2020 Ingo Schwarze + * Copyright (c) 2008, 2009, 2011, 2014 Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -14,6 +14,9 @@ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Formatting module to let mandoc(1) show + * a human readable representation of the syntax tree. */ #include "config.h" @@ -305,6 +308,11 @@ print_man(const struct roff_node *n, int indent) putchar(')'); if (n->flags & NODE_EOS) putchar('.'); + if (n->flags & NODE_ID) { + printf(" ID"); + if (n->string != NULL) + printf("=%s", n->string); + } if (n->flags & NODE_NOFILL) printf(" NOFILL"); putchar('\n'); -- cgit v1.2.3