544c191c34
--- MAJOR NEW FEATURES --- * apropos(1): improve POSIX compliance by accepting case-insensitive extended regular expressions by default * new -O tag[=term] output option (open a page at the definition of a term) * tbl(7) -T html: spanning and horizontal and vertical alignment of cells * tbl(7) -T html: draw lines on the edges of table cells * tbl(7) -T utf8: render lines with the Unicode box drawing characters * mandoc is now able to handle the manual pages of the groff package. --- MINOR NEW FEATURES --- * -T html: new option -O toc (table of contents) * -T html: second argument to -O man to support local and remote links * mdoc(7) .Bd -centered now fills the text contained in it * man-ext .SY and .YS macros (synopsis block) * man-ext .TQ macro (tagged paragraph without vertical space before it) * tbl(7) \& explicit alignment indicator * roff(7) .shift, .while, and .return requests * roff(7) .char request (output glyph definition) * roff(7) .nop request (no operation) * roff(7) .ft request: handle the CB, CI, and CR fonts * roff(7) .if c conditional (character available) * roff(7) \\$@ escape sequence (insert all macro arguments, quoted) * roff(7) \*(.T predefined string (interpolate output device name) * roff(7) \[charNNN] escape sequence (for printable ASCII characters) * roff(7) \# escape sequence (line continuation with comment) --- HTML OUTPUT SYNTAX CORRECTIONS --- * Render .br and \p as <br/>, not as an empty <div>. * Render .Pp and .PP as <p> and automatically close it when needed. * Stop writing empty list elements for non-compact .Bl -tag lists. * Do not put <p> inside <a> if .UR or .MT contain .PP. * Implement tooltips purely in CSS rather than abusing title= attributes. --- MINOR FUNCTIONAL IMPROVEMENTS --- * many improvements to the handling of fill and no-fill mode * tbl(7): better column widths in the presence of horizontal spans * several minor improvements to escape sequence handling * several minor improvements to manual font handling * portability: autodetect need for _GNU_SOURCE or _OPENBSD_SOURCE * portability: autodetect whether less(1) supports the -T option * large numbers of bugfixes of diverse kinds --- STRUCTURAL IMPROVEMENTS --- * Disentangle eqn(7) and tbl(7) from other parser header files, and clean up some parser data structures. * Substantially simplify error and warning message infrastructure. --- THANKS TO --- * John Gardner for crucial help implementing tooltips in CSS. * Alexander Bluhm, Raphael Graf, Ted Unangst (OpenBSD) and Daniel Sabogal (Alpine Linux) for patches. * Anthony Bentley and Jason McIntyre (OpenBSD) for documentation patches, suggesting new features, bug reports, and useful discussions. * Kyle Evans and Baptiste Daroussin (FreeBSD) for minor patches. * Pali Rohar for suggesting multiple new features and for reporting several bugs and missing features. * Klemens Nanni (OpenBSD) for suggesting multiple new features. * Kristaps Dzonsons (bsd.lv), Marc Espie (OpenBSD), Adam Kalisz, and Laura Morales for suggesting new features. * Wolfram Schneider and Yuri Pankov (FreeBSD) for reporting missing features. * Edward Tomasz Napierala (FreeBSD) for suggesting a feature improvement. * Thomas Klausner (NetBSD) and Sevan Janiyan (SmartOS) for bug reports and release testing. * Bryan Steele, Janne Johansson, Kurt Mosiejczuk, Mike Belopuhov, Theo Buehler, Todd Miller (OpenBSD), Andreas Gustafsson, Christos Zoulas, Robert Elz (NetBSD), Kurt Jaeger (FreeBSD), Fabio Scotoni, Kelvin Sherlock, Mark Harris, Orestis Ioannou, Raf Czlonka, and Sean Farrell for bug reports. * Ulrich Spoerlein (FreeBSD), Leah Neukirchen (Void Linux), Matej Cepl (openSUSE), and Jan Stary (MacOS X) for release testing. * Brian Callahan and Stuart Henderson (OpenBSD) for help with the OpenBSD groff port. * Bertrand Garrigues, Branden Robinson, Ralph Corderoy, and Werner Lemberg (GNU troff) for checking groff patches. * Scott Cheloha, Theo de Raadt (OpenBSD) and Natanael Copa (Alpine Linux) for useful discussions.
245 lines
5.4 KiB
C
245 lines
5.4 KiB
C
/* Id: roff_term.c,v 1.19 2019/01/04 03:24:33 schwarze Exp */
|
|
/*
|
|
* Copyright (c) 2010,2014,2015,2017-2019 Ingo Schwarze <schwarze@openbsd.org>
|
|
*
|
|
* 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.
|
|
*/
|
|
#include <sys/types.h>
|
|
|
|
#include <assert.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "mandoc.h"
|
|
#include "roff.h"
|
|
#include "out.h"
|
|
#include "term.h"
|
|
|
|
#define ROFF_TERM_ARGS struct termp *p, const struct roff_node *n
|
|
|
|
typedef void (*roff_term_pre_fp)(ROFF_TERM_ARGS);
|
|
|
|
static void roff_term_pre_br(ROFF_TERM_ARGS);
|
|
static void roff_term_pre_ce(ROFF_TERM_ARGS);
|
|
static void roff_term_pre_ft(ROFF_TERM_ARGS);
|
|
static void roff_term_pre_ll(ROFF_TERM_ARGS);
|
|
static void roff_term_pre_mc(ROFF_TERM_ARGS);
|
|
static void roff_term_pre_po(ROFF_TERM_ARGS);
|
|
static void roff_term_pre_sp(ROFF_TERM_ARGS);
|
|
static void roff_term_pre_ta(ROFF_TERM_ARGS);
|
|
static void roff_term_pre_ti(ROFF_TERM_ARGS);
|
|
|
|
static const roff_term_pre_fp roff_term_pre_acts[ROFF_MAX] = {
|
|
roff_term_pre_br, /* br */
|
|
roff_term_pre_ce, /* ce */
|
|
roff_term_pre_br, /* fi */
|
|
roff_term_pre_ft, /* ft */
|
|
roff_term_pre_ll, /* ll */
|
|
roff_term_pre_mc, /* mc */
|
|
roff_term_pre_br, /* nf */
|
|
roff_term_pre_po, /* po */
|
|
roff_term_pre_ce, /* rj */
|
|
roff_term_pre_sp, /* sp */
|
|
roff_term_pre_ta, /* ta */
|
|
roff_term_pre_ti, /* ti */
|
|
};
|
|
|
|
|
|
void
|
|
roff_term_pre(struct termp *p, const struct roff_node *n)
|
|
{
|
|
assert(n->tok < ROFF_MAX);
|
|
(*roff_term_pre_acts[n->tok])(p, n);
|
|
}
|
|
|
|
static void
|
|
roff_term_pre_br(ROFF_TERM_ARGS)
|
|
{
|
|
term_newln(p);
|
|
if (p->flags & TERMP_BRIND) {
|
|
p->tcol->offset = p->tcol->rmargin;
|
|
p->tcol->rmargin = p->maxrmargin;
|
|
p->trailspace = 0;
|
|
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
|
|
p->flags |= TERMP_NOSPACE;
|
|
}
|
|
}
|
|
|
|
static void
|
|
roff_term_pre_ce(ROFF_TERM_ARGS)
|
|
{
|
|
const struct roff_node *nc1, *nc2;
|
|
|
|
roff_term_pre_br(p, n);
|
|
p->flags |= n->tok == ROFF_ce ? TERMP_CENTER : TERMP_RIGHT;
|
|
nc1 = n->child->next;
|
|
while (nc1 != NULL) {
|
|
nc2 = nc1;
|
|
do {
|
|
nc2 = nc2->next;
|
|
} while (nc2 != NULL && (nc2->type != ROFFT_TEXT ||
|
|
(nc2->flags & NODE_LINE) == 0));
|
|
while (nc1 != nc2) {
|
|
if (nc1->type == ROFFT_TEXT)
|
|
term_word(p, nc1->string);
|
|
else
|
|
roff_term_pre(p, nc1);
|
|
nc1 = nc1->next;
|
|
}
|
|
p->flags |= TERMP_NOSPACE;
|
|
term_flushln(p);
|
|
}
|
|
p->flags &= ~(TERMP_CENTER | TERMP_RIGHT);
|
|
}
|
|
|
|
static void
|
|
roff_term_pre_ft(ROFF_TERM_ARGS)
|
|
{
|
|
const char *cp;
|
|
|
|
cp = n->child->string;
|
|
switch (mandoc_font(cp, (int)strlen(cp))) {
|
|
case ESCAPE_FONTBOLD:
|
|
term_fontrepl(p, TERMFONT_BOLD);
|
|
break;
|
|
case ESCAPE_FONTITALIC:
|
|
term_fontrepl(p, TERMFONT_UNDER);
|
|
break;
|
|
case ESCAPE_FONTBI:
|
|
term_fontrepl(p, TERMFONT_BI);
|
|
break;
|
|
case ESCAPE_FONTPREV:
|
|
term_fontlast(p);
|
|
break;
|
|
case ESCAPE_FONTROMAN:
|
|
case ESCAPE_FONTCW:
|
|
term_fontrepl(p, TERMFONT_NONE);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
roff_term_pre_ll(ROFF_TERM_ARGS)
|
|
{
|
|
term_setwidth(p, n->child != NULL ? n->child->string : NULL);
|
|
}
|
|
|
|
static void
|
|
roff_term_pre_mc(ROFF_TERM_ARGS)
|
|
{
|
|
if (p->col) {
|
|
p->flags |= TERMP_NOBREAK;
|
|
term_flushln(p);
|
|
p->flags &= ~(TERMP_NOBREAK | TERMP_NOSPACE);
|
|
}
|
|
if (n->child != NULL) {
|
|
p->mc = n->child->string;
|
|
p->flags |= TERMP_NEWMC;
|
|
} else
|
|
p->flags |= TERMP_ENDMC;
|
|
}
|
|
|
|
static void
|
|
roff_term_pre_po(ROFF_TERM_ARGS)
|
|
{
|
|
struct roffsu su;
|
|
static int po, polast;
|
|
int ponew;
|
|
|
|
if (n->child != NULL &&
|
|
a2roffsu(n->child->string, &su, SCALE_EM) != NULL) {
|
|
ponew = term_hen(p, &su);
|
|
if (*n->child->string == '+' ||
|
|
*n->child->string == '-')
|
|
ponew += po;
|
|
} else
|
|
ponew = polast;
|
|
polast = po;
|
|
po = ponew;
|
|
|
|
ponew = po - polast + (int)p->tcol->offset;
|
|
p->tcol->offset = ponew > 0 ? ponew : 0;
|
|
}
|
|
|
|
static void
|
|
roff_term_pre_sp(ROFF_TERM_ARGS)
|
|
{
|
|
struct roffsu su;
|
|
int len;
|
|
|
|
if (n->child != NULL) {
|
|
if (a2roffsu(n->child->string, &su, SCALE_VS) == NULL)
|
|
su.scale = 1.0;
|
|
len = term_vspan(p, &su);
|
|
} else
|
|
len = 1;
|
|
|
|
if (len < 0)
|
|
p->skipvsp -= len;
|
|
else
|
|
while (len--)
|
|
term_vspace(p);
|
|
|
|
roff_term_pre_br(p, n);
|
|
}
|
|
|
|
static void
|
|
roff_term_pre_ta(ROFF_TERM_ARGS)
|
|
{
|
|
term_tab_set(p, NULL);
|
|
for (n = n->child; n != NULL; n = n->next)
|
|
term_tab_set(p, n->string);
|
|
}
|
|
|
|
static void
|
|
roff_term_pre_ti(ROFF_TERM_ARGS)
|
|
{
|
|
struct roffsu su;
|
|
const char *cp;
|
|
int len, sign;
|
|
|
|
roff_term_pre_br(p, n);
|
|
|
|
if (n->child == NULL)
|
|
return;
|
|
cp = n->child->string;
|
|
if (*cp == '+') {
|
|
sign = 1;
|
|
cp++;
|
|
} else if (*cp == '-') {
|
|
sign = -1;
|
|
cp++;
|
|
} else
|
|
sign = 0;
|
|
|
|
if (a2roffsu(cp, &su, SCALE_EM) == NULL)
|
|
return;
|
|
len = term_hen(p, &su);
|
|
|
|
if (sign == 0) {
|
|
p->ti = len - p->tcol->offset;
|
|
p->tcol->offset = len;
|
|
} else if (sign == 1) {
|
|
p->ti = len;
|
|
p->tcol->offset += len;
|
|
} else if ((size_t)len < p->tcol->offset) {
|
|
p->ti = -len;
|
|
p->tcol->offset -= len;
|
|
} else {
|
|
p->ti = -p->tcol->offset;
|
|
p->tcol->offset = 0;
|
|
}
|
|
}
|