├── .gitignore ├── COPYING ├── README.md ├── autoload.php ├── examples ├── example.1 └── example.html ├── lib ├── Block │ ├── DefinitionList.php │ ├── EndPreformatted.php │ ├── IP.php │ ├── P.php │ ├── Preformatted.php │ ├── RE.php │ ├── RS.php │ ├── SY.php │ ├── Section.php │ ├── TH.php │ ├── TP.php │ ├── TS.php │ ├── TabTable.php │ ├── Template.php │ ├── Text.php │ ├── ad.php │ ├── ce.php │ ├── fc.php │ └── ti.php ├── Blocks.php ├── DOM.php ├── Indentation.php ├── Inline │ ├── AlternatingFont.php │ ├── EQ.php │ ├── FontOneInputLine.php │ ├── Link.php │ ├── LinkEnd.php │ ├── MR.php │ ├── OP.php │ ├── PS.php │ ├── URL.php │ ├── VerticalSpace.php │ └── ft.php ├── Man.php ├── Manner.php ├── Massage │ ├── Block.php │ ├── Body.php │ ├── DIV.php │ ├── DL.php │ ├── DT.php │ ├── HTMLList.php │ ├── Indents.php │ ├── LI.php │ ├── P.php │ ├── PRE.php │ ├── Remap.php │ └── Tidy.php ├── Node.php ├── PreformattedOutput.php ├── Preprocessor.php ├── Replace.php ├── Request.php ├── Request │ ├── Skippable.php │ └── Unhandled.php ├── Roff.php ├── Roff │ ├── Alias.php │ ├── Char.php │ ├── Comment.php │ ├── Condition.php │ ├── Glyph.php │ ├── Loop.php │ ├── Macro.php │ ├── Register.php │ ├── Rename.php │ ├── Skipped.php │ ├── StringRequest.php │ ├── Template.php │ ├── Translation.php │ ├── Unit.php │ ├── am.php │ ├── asRequest.php │ ├── cc.php │ ├── de.php │ ├── di.php │ ├── doRequest.php │ ├── ec.php │ ├── eo.php │ ├── nop.php │ └── returnRequest.php ├── Text.php └── TextContent.php ├── manner.php ├── run_tests.php └── tests ├── 0in.1 ├── 0in.1.html ├── BR.1 ├── BR.1.html ├── FONT.1 ├── FONT.1.html ├── FontOneInputLine.1 ├── FontOneInputLine.1.html ├── IPs.1 ├── IPs.1.html ├── MT.1 ├── MT.1.html ├── NOP.1 ├── NOP.1.html ├── SbC2.1 ├── SbC2.1.html ├── SbCylinder.3iv ├── SbCylinder.3iv.html ├── SoXtWalkViewer-b.3 ├── SoXtWalkViewer-b.3.html ├── SoXtWalkViewer.3 ├── SoXtWalkViewer.3.html ├── ZN.1 ├── ZN.1.html ├── apropos.1 ├── apropos.1.html ├── atop.1 ├── atop.1.html ├── b.1 ├── b.1.html ├── bash_fonts.1 ├── bash_fonts.1.html ├── bash_sm.1 ├── bash_sm.1.html ├── br_in_tp.1 ├── br_in_tp.1.html ├── bull.1 ├── bull.1.html ├── c.3 ├── c.3.html ├── callerid.conf.5 ├── callerid.conf.5.html ├── cc.1 ├── cc.1.html ├── cef5conv.1 ├── cef5conv.1.html ├── chars.1 ├── chars.1.html ├── ci.2 ├── ci.2.html ├── comment_after_font.1 ├── comment_after_font.1.html ├── comp.1 ├── comp.1.html ├── cpupower-monitor.1 ├── cpupower-monitor.1.html ├── customVb.1 ├── customVb.1.html ├── digit_space.1 ├── digit_space.1.html ├── dir.1 ├── dir.1.html ├── eh.1 ├── eh.1.html ├── ep.1 ├── ep.1.html ├── eqn.1 ├── eqn.1.html ├── ex.1 ├── ex.1.html ├── fortune.6 ├── fortune.6.html ├── gawk.1b ├── gawk.1b.html ├── gcc.1 ├── gcc.1.html ├── gdiffmk.1 ├── gdiffmk.1.html ├── gifsicle.1 ├── gifsicle.1.html ├── glue-validator.1 ├── glue-validator.1.html ├── gmusicbrowser.1 ├── gmusicbrowser.1.html ├── gpp.1 ├── gpp.1.html ├── groff_mm.7 ├── groff_mm.7.html ├── hg.1 ├── hg.1.html ├── indentation-a.1 ├── indentation-a.1.html ├── innxbatch.8 ├── innxbatch.8.html ├── iostat.1 ├── iostat.1.html ├── ksh.1 ├── ksh.1.html ├── links2.1 ├── links2.1.html ├── listA.1 ├── listA.1.html ├── logical_or.1 ├── logical_or.1.html ├── lsmcli.1 ├── lsmcli.1.html ├── mdadm.8 ├── mdadm.8.html ├── mplayer.1 ├── mplayer.1.html ├── nawk.1 ├── nawk.1.html ├── nf.1 ├── nf.1.html ├── ovn-sb.5 ├── ovn-sb.5.html ├── pmcpp.1 ├── pmcpp.1.html ├── pmdapipe.1 ├── pmdapipe.1.html ├── portage.5 ├── portage.5.html ├── pp.1 ├── pp.1.html ├── pp_in_pre.1 ├── pp_in_pre.1.html ├── prefontspace.2 ├── prefontspace.2.html ├── proc.5 ├── proc.5.html ├── ps.1 ├── ps.1.html ├── rc.4 ├── rc.4.html ├── rc.4b ├── rc.4b.html ├── rc.4c ├── rc.4c.html ├── rc.4d ├── rc.4d.html ├── rc.4e ├── rc.4e.html ├── rc.4f ├── rc.4f.html ├── re_syntax.n ├── re_syntax.n.html ├── repl.1 ├── repl.1.html ├── roff.7 ├── roff.7.html ├── rs.1 ├── rs.1.html ├── screen.1 ├── screen.1.html ├── sh.1 ├── sh.1.html ├── simple.1 ├── simple.1.html ├── soft_hyphen.1 ├── soft_hyphen.1.html ├── sox.1 ├── sox.1.html ├── sox.1b ├── sox.1b.html ├── spaces.1 ├── spaces.1.html ├── tcpdump_rses.1 ├── tcpdump_rses.1.html ├── ti.1 ├── ti.1.html ├── tp.1 ├── tp.1.html ├── tpthennewline.1 ├── tpthennewline.1.html ├── tr.1 ├── tr.1.html ├── trailingTP.1 ├── trailingTP.1.html ├── ttylink.1 ├── ttylink.1.html ├── units.1 ├── units.1.html ├── url.1 ├── url.1.html ├── warnquota.conf.5 ├── warnquota.conf.5.html ├── while.1 ├── while.1.html ├── xpaenv.n ├── xpaenv.n.html ├── xterm.1 ├── xterm.1.html ├── zct.1 └── zct.1.html /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | -------------------------------------------------------------------------------- /autoload.php: -------------------------------------------------------------------------------- 1 | . 19 | */ 20 | declare(strict_types=1); 21 | 22 | /** 23 | * An example of a project-specific implementation. 24 | * 25 | * After registering this autoload function with SPL, the following line 26 | * would cause the function to attempt to load the \Foo\Bar\Baz\Qux class 27 | * from /path/to/project/src/Baz/Qux.php: 28 | * 29 | * new \Foo\Bar\Baz\Qux; 30 | * 31 | * @param string $class The fully-qualified class name. 32 | * @return void 33 | */ 34 | spl_autoload_register( 35 | function ($class) { 36 | // project-specific namespace prefix 37 | $prefix = 'Manner\\'; 38 | 39 | // base directory for the namespace prefix 40 | $base_dir = __DIR__ . '/lib/'; 41 | 42 | // does the class use the namespace prefix? 43 | $len = strlen($prefix); 44 | if (strncmp($prefix, $class, $len) !== 0) { 45 | // no, move to the next registered autoloader 46 | return; 47 | } 48 | 49 | // get the relative class name 50 | $relative_class = mb_substr($class, $len); 51 | 52 | // replace the namespace prefix with the base directory, replace namespace 53 | // separators with directory separators in the relative class name, append 54 | // with .php 55 | $file = $base_dir . str_replace('\\', '/', $relative_class) . '.php'; 56 | 57 | // if the file exists, require it 58 | if (file_exists($file)) { 59 | require $file; 60 | } 61 | } 62 | ); -------------------------------------------------------------------------------- /examples/example.1: -------------------------------------------------------------------------------- 1 | .TH EXAMPLE "1" "June 2024" "manner" "Example Man Page" 2 | 3 | .SH NAME 4 | example \- sample man page 5 | 6 | .SH SYNOPSIS 7 | .B example 8 | [\fI\,OPTION\/\fR]... 9 | 10 | .SH DESCRIPTION 11 | .\" This is a comment 12 | .PP 13 | Not a real command or man page! 14 | .TP 15 | \fB\-a\fR, \fB\-\-all\fR 16 | a sample option 17 | .TP 18 | \fB\-b\fR, \fB\-\-ball\fR 19 | another sample option 20 | .PP 21 | 22 | .TS 23 | tab(@); 24 | l l. 25 | T{ 26 | Column 1 27 | T}@T{ 28 | Column 2 29 | T} 30 | _ 31 | T{ 32 | row1 33 | T}@T{ 34 | This is some tabular date 35 | T} 36 | T{ 37 | this is the second row 38 | T}@T{ 39 | translated to an HTML
| Column 1 | 32 |Column 2 | 33 |
| row1 | 36 |This is some tabular date | 37 |
| this is the second row | 40 |translated to an HTML <table> | 41 |
s can't go inside
element.
69 | Node::remove($dt->firstChild);
70 | self::tidy($dt);
71 | }
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/lib/Massage/HTMLList.php:
--------------------------------------------------------------------------------
1 | .
19 | */
20 | declare(strict_types=1);
21 |
22 | namespace Manner\Massage;
23 |
24 | use DOMElement;
25 | use DOMException;
26 | use DOMNode;
27 | use DOMText;
28 | use Manner\DOM;
29 | use Manner\Node;
30 |
31 | class HTMLList
32 | {
33 |
34 | public const array CHAR_PREFIXES = ['*', 'o', '·', '+', '-', '○'];
35 |
36 | private static function getBulletRegex(): string
37 | {
38 | return '~^\s*[' . preg_quote(implode('', HTMLList::CHAR_PREFIXES), '~') . ']\s~u';
39 | }
40 |
41 | public static function startsWithBullet(string $text): bool
42 | {
43 | return (bool)preg_match(self::getBulletRegex(), $text);
44 | }
45 |
46 | public static function pruneBulletChar(DOMElement $li): void
47 | {
48 | $firstTextNode = self::getFirstNonEmptyTextNode($li);
49 | if ($firstTextNode) {
50 | $firstTextNode->textContent = preg_replace(self::getBulletRegex(), '', $firstTextNode->textContent);
51 | }
52 | }
53 |
54 | public static function removeLonePs(DOMElement $list): void
55 | {
56 | $child = $list->firstChild;
57 | while ($child) {
58 | if ($child->childNodes->length === 1 && DOM::isTag($child->firstChild, 'p')) {
59 | DOM::extractContents($child, $child->firstChild);
60 | $child->removeChild($child->firstChild);
61 | Node::addClass($child, 'p');
62 | }
63 | $child = $child->nextSibling;
64 | }
65 | }
66 |
67 | /**
68 | * @throws DOMException
69 | */
70 | public static function checkElementForLIs(DOMElement $li): bool
71 | {
72 | $foundInnerLI = false;
73 |
74 | $child = $li->firstChild;
75 |
76 | do {
77 | if (
78 | DOM::isTag($child, 'br') &&
79 | $child->nextSibling &&
80 | ($child->nextSibling instanceof DOMText || DOM::isInlineElement($child->nextSibling)) &&
81 | self::startsWithBullet($child->nextSibling->textContent)
82 | ) {
83 | $foundInnerLI = true;
84 |
85 | $newLI = $li->ownerDocument->createElement('li');
86 | while ($li->firstChild) {
87 | if ($li->firstChild === $child) {
88 | $li->removeChild($child); // remove the
89 | break;
90 | }
91 | $newLI->appendChild($li->firstChild);
92 | }
93 | $li->parentNode->insertBefore($newLI, $li);
94 | self::pruneBulletChar($li);
95 | $child = $li->firstChild;
96 | } elseif (DOM::isTag($child, 'p') && self::startsWithBullet($child->textContent)) {
97 | $foundInnerLI = true;
98 |
99 | $newLI = $li->ownerDocument->createElement('li');
100 | while ($li->firstChild) {
101 | if ($li->firstChild === $child) {
102 | Node::remove($child); // remove the
103 | break;
104 | }
105 | $newLI->appendChild($li->firstChild);
106 | }
107 | $li->parentNode->insertBefore($newLI, $li);
108 | self::pruneBulletChar($li);
109 | $child = $li->firstChild;
110 | } else {
111 | $child = $child->nextSibling;
112 | }
113 | } while ($child);
114 |
115 | return $foundInnerLI;
116 | }
117 |
118 | private static function getFirstNonEmptyTextNode(?DOMNode $domNode): ?DOMText
119 | {
120 | if ($domNode instanceof DOMText) {
121 | if (mb_trim($domNode->textContent) === '') {
122 | $domNode->parentNode->removeChild($domNode);
123 |
124 | return null;
125 | }
126 |
127 | return $domNode;
128 | }
129 |
130 | foreach ($domNode->childNodes as $node) {
131 | if ($el = self::getFirstNonEmptyTextNode($node)) {
132 | return $el;
133 | }
134 | }
135 |
136 | return null;
137 | }
138 |
139 | }
140 |
--------------------------------------------------------------------------------
/lib/Massage/Indents.php:
--------------------------------------------------------------------------------
1 | .
19 | */
20 | declare(strict_types=1);
21 |
22 | namespace Manner\Massage;
23 |
24 | use DOMDocument;
25 | use DOMXPath;
26 | use Exception;
27 | use Manner\DOM;
28 | use Manner\Indentation;
29 | use Manner\Node;
30 |
31 | class Indents
32 | {
33 |
34 | /**
35 | * @param DOMXPath $xpath
36 | * @throws Exception
37 | */
38 | public static function recalculate(DOMXPath $xpath): void
39 | {
40 | $divs = $xpath->query('//div[@left-margin="0"]');
41 | foreach ($divs as $div) {
42 | // See tests/warnquota.conf.5
43 | if (DOM::isTag($div->previousSibling, 'p') && DOM::isTag($div->firstChild, 'p')) {
44 | $div->previousSibling->appendChild($div->ownerDocument->createElement('br'));
45 | DOM::extractContents($div->previousSibling, $div->firstChild);
46 | Node::remove($div->firstChild);
47 | }
48 | Node::remove($div);
49 | }
50 |
51 | $divs = $xpath->query('//div[@left-margin]');
52 | foreach ($divs as $div) {
53 | $leftMargin = (int)$div->getAttribute('left-margin');
54 |
55 | $parentNode = $div->parentNode;
56 |
57 | while ($parentNode) {
58 | if ($parentNode instanceof DOMDocument || $parentNode->tagName === 'div') {
59 | break;
60 | }
61 | if (Indentation::isSet($parentNode)) {
62 | $leftMargin -= Indentation::get($parentNode);
63 | }
64 | $parentNode = $parentNode->parentNode;
65 | }
66 | Indentation::set($div, $leftMargin);
67 | $div->removeAttribute('left-margin');
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/lib/Massage/LI.php:
--------------------------------------------------------------------------------
1 | .
19 | */
20 | declare(strict_types=1);
21 |
22 | namespace Manner\Massage;
23 |
24 | use DOMElement;
25 | use Manner\DOM;
26 | use Manner\Node;
27 |
28 | class LI
29 | {
30 |
31 | public static function tidy(DOMElement $li): void
32 | {
33 | while ($li->lastChild && (Node::isTextAndEmpty($li->lastChild) || DOM::isTag($li->lastChild, 'br'))) {
34 | $li->removeChild($li->lastChild);
35 | }
36 |
37 | if (mb_trim($li->textContent) === '') {
38 | $li->parentNode->removeChild($li);
39 | }
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/lib/Massage/P.php:
--------------------------------------------------------------------------------
1 | .
19 | */
20 | declare(strict_types=1);
21 |
22 | namespace Manner\Massage;
23 |
24 | use DOMElement;
25 | use DOMXPath;
26 | use Exception;
27 | use Manner\DOM;
28 | use Manner\Indentation;
29 | use Manner\Node;
30 |
31 | class P
32 | {
33 |
34 | public static function removeEmpty(DOMXPath $xpath): void
35 | {
36 | $ps = $xpath->query('//p');
37 | foreach ($ps as $p) {
38 | if (!$p->firstChild || mb_trim($p->textContent) === '') {
39 | $p->parentNode->removeChild($p);
40 | }
41 | }
42 | }
43 |
44 | /**
45 | * @param DOMElement $p
46 | * @throws Exception
47 | */
48 | public static function tidy(DOMElement $p): void
49 | {
50 | // Change two br tags in a row to a new paragraph.
51 |
52 | $indent = Indentation::get($p);
53 | $pChild = $p->firstChild;
54 |
55 | while ($pChild) {
56 | if (DOM::isTag($pChild, 'br') && DOM::isTag($pChild->nextSibling, 'br')) {
57 | $newP = $p->ownerDocument->createElement('p');
58 | if ($indent) {
59 | Indentation::set($newP, $indent);
60 | }
61 | while ($p->firstChild) {
62 | if ($p->firstChild === $pChild) {
63 | break;
64 | }
65 | $newP->appendChild($p->firstChild);
66 | }
67 | $p->parentNode->insertBefore($newP, $p);
68 | $p->removeChild($p->firstChild); // 1st
69 | $p->removeChild($p->firstChild); // 2nd
70 | self::tidy($p);
71 | self::tidy($newP);
72 |
73 | return;
74 | }
75 | $pChild = $pChild->nextSibling;
76 | }
77 |
78 | while ($p->lastChild && (Node::isTextAndEmpty($p->lastChild) || DOM::isTag($p->lastChild, 'br'))) {
79 | $p->removeChild($p->lastChild);
80 | }
81 |
82 | if (mb_trim($p->textContent) === '') {
83 | $p->parentNode->removeChild($p);
84 | }
85 | }
86 |
87 | }
88 |
--------------------------------------------------------------------------------
/lib/Massage/PRE.php:
--------------------------------------------------------------------------------
1 | .
19 | */
20 | declare(strict_types=1);
21 |
22 | namespace Manner\Massage;
23 |
24 | use DOMElement;
25 | use DOMText;
26 | use Manner\Node;
27 | use Manner\Text;
28 |
29 | class PRE
30 | {
31 |
32 | public static function tidy(DOMElement $el): void
33 | {
34 | while ($el->lastChild && Node::isTextAndEmpty($el->lastChild)) {
35 | $el->removeChild($el->lastChild);
36 | }
37 |
38 | if (!$el->lastChild) {
39 | $el->parentNode->removeChild($el);
40 |
41 | return;
42 | }
43 |
44 | if ($el->lastChild->nodeType === XML_TEXT_NODE) {
45 | $el->replaceChild(new DOMText(mb_rtrim($el->lastChild->textContent)), $el->lastChild);
46 | }
47 |
48 | if (Text::trimAndRemoveZWSUTF8($el->textContent) === '') {
49 | $el->parentNode->removeChild($el);
50 | }
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/lib/Massage/Remap.php:
--------------------------------------------------------------------------------
1 | .
19 | */
20 | declare(strict_types=1);
21 |
22 | namespace Manner\Massage;
23 |
24 | use DOMElement;
25 | use DOMXPath;
26 | use Exception;
27 | use Manner\Blocks;
28 | use Manner\DOM;
29 | use Manner\Indentation;
30 |
31 | class Remap
32 | {
33 |
34 | /**
35 | * @param DOMXPath $xpath
36 | * @throws Exception
37 | */
38 | public static function doAll(DOMXPath $xpath): void
39 | {
40 | $divs = $xpath->query('//div[@remap]');
41 | /** @var DOMElement $div */
42 | /** @var DOMElement $p */
43 | foreach ($divs as $div) {
44 | if ($div->getAttribute('remap') === 'IP') {
45 | $indentVal = Indentation::get($div);
46 |
47 | $remapChild = $div->firstChild;
48 | if ($remapChild) {
49 | $next = false;
50 | do {
51 | if (DOM::isTag($remapChild, BLOCKS::BLOCK_ELEMENTS)) {
52 | $next = $remapChild->nextSibling;
53 | $remapChild->removeAttribute('implicit');
54 | $indentVal && Indentation::add($remapChild, $indentVal);
55 | $div->parentNode->insertBefore($remapChild, $div);
56 | } else {
57 | $p = $div->ownerDocument->createElement('p');
58 | $p = $div->parentNode->insertBefore($p, $div);
59 | $indentVal && Indentation::add($p, $indentVal);
60 | while ($remapChild && !DOM::isTag($remapChild, BLOCKS::BLOCK_ELEMENTS)) {
61 | $next = $remapChild->nextSibling;
62 | $p->appendChild($remapChild);
63 | $remapChild = $next;
64 | }
65 | }
66 | } while ($remapChild = $next);
67 | }
68 |
69 | $div->parentNode->removeChild($div);
70 | } else {
71 | throw new Exception('Unexpected value for remap.');
72 | }
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/lib/Preprocessor.php:
--------------------------------------------------------------------------------
1 | .
19 | */
20 | declare(strict_types=1);
21 |
22 | namespace Manner;
23 |
24 | class Preprocessor
25 | {
26 |
27 | public static function strip(array $lines): array
28 | {
29 | $linesNoComments = [];
30 | $linePrefix = '';
31 |
32 | for ($i = 0; $i < count($lines); ++$i) {
33 | $line = $linePrefix . $lines[$i];
34 | $linePrefix = '';
35 |
36 | // Everything up to and including the next newline is ignored. This is interpreted in copy mode. This is like \" except that the terminating newline is ignored as well.
37 | if (preg_match('~(^|.*?[^\\\\])\\\\#~u', $line, $matches)) {
38 | $linePrefix = $matches[1];
39 | continue;
40 | }
41 |
42 | // Workaround for lots of broken tcl man pages (section n, Tk_*, Tcl_*, others...):
43 | $line = Replace::preg('~^\.\s*el\s?\\\\}~u', '.el \\{', $line);
44 |
45 | // Don't worry about changes in point size for now (see rc.1 for digit instead of +- in \s10):
46 | $line = Replace::preg('~(?.
19 | */
20 | declare(strict_types=1);
21 |
22 | namespace Manner;
23 |
24 | class Replace
25 | {
26 |
27 | public static function preg($pattern, $replacement, string $subject, $limit = -1, &$count = null): array|string
28 | {
29 | $newStr = preg_replace($pattern, $replacement, $subject, $limit, $count);
30 |
31 | if (is_null($newStr)) {
32 | return self::preg($pattern, $replacement, self::ignoreBadChars($subject), $limit, $count);
33 | }
34 |
35 | return $newStr;
36 | }
37 |
38 | public static function pregCallback($pattern, callable $callback, string $subject, $limit = -1, &$count = null)
39 | {
40 | $newStr = preg_replace_callback($pattern, $callback, $subject, $limit, $count);
41 |
42 | if (is_null($newStr)) {
43 | return (self::pregCallback($pattern, $callback, self::ignoreBadChars($subject), $limit, $count));
44 | }
45 |
46 | return $newStr;
47 | }
48 |
49 | /**
50 | * See https://stackoverflow.com/a/3742879
51 | * @param string $string
52 | * @return string
53 | */
54 | private static function ignoreBadChars(string $string): string
55 | {
56 | return iconv('UTF-8', 'UTF-8//IGNORE', $string);
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/lib/Request/Skippable.php:
--------------------------------------------------------------------------------
1 | .
19 | */
20 | declare(strict_types=1);
21 |
22 | namespace Manner\Request;
23 |
24 | use DOMElement;
25 | use Manner\Block\Template;
26 |
27 | class Skippable implements Template
28 | {
29 |
30 | public static function checkAppend(
31 | DOMElement $parentNode,
32 | array &$lines,
33 | array $request,
34 | bool $needOneLineOnly = false
35 | ): ?DOMElement {
36 | array_shift($lines);
37 |
38 | return null;
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/lib/Request/Unhandled.php:
--------------------------------------------------------------------------------
1 | .
19 | */
20 | declare(strict_types=1);
21 |
22 | namespace Manner\Request;
23 |
24 | use DOMElement;
25 | use Exception;
26 | use Manner\Block\Template;
27 |
28 | class Unhandled implements Template
29 | {
30 |
31 | // Unhandled:
32 | public const array requests = [
33 | 'ab',
34 | 'aln',
35 | 'am1',
36 | 'ami',
37 | 'ami1',
38 | 'asciify',
39 | 'backtrace',
40 | 'blm',
41 | 'box',
42 | 'boxa',
43 | 'brp',
44 | 'break',
45 | 'c2',
46 | 'cf',
47 | 'ch',
48 | 'chop',
49 | 'class',
50 | 'composite',
51 | 'continue',
52 | 'da',
53 | 'dei',
54 | 'dei1',
55 | 'device',
56 | 'devicem',
57 | 'do',
58 | 'dt',
59 | 'ecr',
60 | 'ecs',
61 | 'fc',
62 | 'fzoom',
63 | 'gcolor',
64 | 'hcode',
65 | 'hla',
66 | 'hlm',
67 | 'hpf',
68 | 'hpfa',
69 | 'hpfcode',
70 | 'kern',
71 | 'lc', // leader repetition glyph.
72 | 'length',
73 | 'linetabs',
74 | 'lg',
75 | 'lsm',
76 | 'ls',
77 | 'ne',
78 | 'nm',
79 | 'nn',
80 | 'nroff',
81 | 'nx',
82 | 'open',
83 | 'opena',
84 | 'os',
85 | 'output',
86 | 'pev',
87 | 'pi',
88 | 'pm',
89 | 'pn',
90 | 'pnr',
91 | 'psbb',
92 | 'pso',
93 | 'ptr',
94 | 'pvs',
95 | 'rd',
96 | 'return',
97 | 'rn',
98 | 'rnn',
99 | 'rr',
100 | 'sizes',
101 | 'special',
102 | 'spreadwarn',
103 | 'sty',
104 | 'substring',
105 | 'sv',
106 | 'sy',
107 | 'tc',
108 | 'tkf',
109 | 'tl',
110 | 'trf',
111 | 'trin',
112 | 'trnt',
113 | 'troff',
114 | 'uf',
115 | 'unformat',
116 | 'vpt',
117 | 'warnscale',
118 | 'write',
119 | 'writec',
120 | 'writem',
121 | ];
122 |
123 | /**
124 | * @param DOMElement $parentNode
125 | * @param array $lines
126 | * @param array $request
127 | * @param bool $needOneLineOnly
128 | * @return DOMElement|null
129 | * @throws Exception
130 | */
131 | public static function checkAppend(
132 | DOMElement $parentNode,
133 | array &$lines,
134 | array $request,
135 | bool $needOneLineOnly = false
136 | ): ?DOMElement {
137 | throw new Exception('Unhandled request ' . $request['raw_line']);
138 | }
139 |
140 | }
141 |
--------------------------------------------------------------------------------
/lib/Roff.php:
--------------------------------------------------------------------------------
1 | .
19 | */
20 | declare(strict_types=1);
21 |
22 | namespace Manner;
23 |
24 | use DOMElement;
25 | use Exception;
26 |
27 | class Roff
28 | {
29 |
30 | /**
31 | * @param DOMElement $parentNode
32 | * @param array $lines
33 | * @param bool $stopOnContent
34 | * @return bool
35 | * @throws Exception
36 | */
37 | public static function parse(
38 | DOMElement $parentNode,
39 | array &$lines,
40 | bool $stopOnContent = false
41 | ): bool {
42 | while ($request = Request::getLine($lines)) {
43 | if ($stopOnContent) {
44 | // \c: Interrupt text processing (groff.7)
45 | if (in_array($request['raw_line'], ['\\c'])) {
46 | array_shift($lines);
47 |
48 | // Man::instance()->runPostOutputCallbacks();
49 | return true;
50 | }
51 |
52 | if (in_array($request['request'], ['SH', 'SS', 'TP', 'br', 'sp', 'ne', 'PP', 'RS', 'RE', 'P', 'LP'])) {
53 | return false;
54 | }
55 |
56 | if ($request['raw_line'] === '') {
57 | array_shift($lines);
58 | continue;
59 | }
60 | }
61 |
62 | $request['class'] = Request::getClass($request, $lines);
63 |
64 | if ($newParent = PreformattedOutput::handle($parentNode, $lines, $request)) {
65 | // NB: still need $stopOnContent check below (so no continue)
66 | if ($newParent instanceof DOMElement) {
67 | $parentNode = $newParent;
68 | }
69 | } else {
70 | /** @var Block\Template $class */
71 | $class = $request['class'];
72 | $newParent = $class::checkAppend($parentNode, $lines, $request, $stopOnContent);
73 | if (!is_null($newParent)) {
74 | $parentNode = $newParent;
75 | }
76 | }
77 |
78 | if ($request['class'] === '\Manner\Block\Text' || $parentNode->textContent !== '') {
79 | if ($stopOnContent) {
80 | return true;
81 | }
82 | if ($request['class'] !== '\Manner\Inline\FontOneInputLine') { // TODO: hack? fix?
83 | $newParent = Man::instance()->runPostOutputCallbacks();
84 | if (!is_null($newParent)) {
85 | $parentNode = $newParent;
86 | }
87 | }
88 | }
89 | }
90 |
91 | return !$stopOnContent;
92 | }
93 |
94 | }
95 |
--------------------------------------------------------------------------------
/lib/Roff/Alias.php:
--------------------------------------------------------------------------------
1 | .
19 | */
20 | declare(strict_types=1);
21 |
22 | namespace Manner\Roff;
23 |
24 | use Manner\Man;
25 |
26 | class Alias implements Template
27 | {
28 |
29 | public static function evaluate(array $request, array &$lines, ?array $macroArguments): void
30 | {
31 | array_shift($lines);
32 | Man::instance()->addAlias($request['arguments'][0], $request['arguments'][1]);
33 | }
34 |
35 | public static function check(string $requestName): string
36 | {
37 | $aliases = Man::instance()->getAliases();
38 | if (array_key_exists($requestName, $aliases)) {
39 | $requestName = $aliases[$requestName];
40 | }
41 |
42 | return $requestName;
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/lib/Roff/Char.php:
--------------------------------------------------------------------------------
1 | .
19 | */
20 | declare(strict_types=1);
21 |
22 | namespace Manner\Roff;
23 |
24 | use Manner\Man;
25 |
26 | class Char implements Template
27 | {
28 |
29 | public static function evaluate(array $request, array &$lines, ?array $macroArguments): void
30 | {
31 | array_shift($lines);
32 | if (count($request['arguments']) === 2) {
33 | Man::instance()->setEntity($request['arguments'][0], $request['arguments'][1]);
34 | }
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/lib/Roff/Comment.php:
--------------------------------------------------------------------------------
1 | .
19 | */
20 | declare(strict_types=1);
21 |
22 | namespace Manner\Roff;
23 |
24 | use Exception;
25 | use Manner\Replace;
26 |
27 | class Comment
28 | {
29 |
30 | /**
31 | * @param array $lines
32 | * @return bool
33 | * @throws Exception
34 | */
35 | public static function checkLine(array &$lines): bool
36 | {
37 | // Skip full-line comments
38 | // See mscore.1 for full-line comments starting with '."
39 | // See cal3d_converter.1 for full-line comments starting with '''
40 | // See e.g. flow-import.1 for comment starting with .\\"
41 | // See e.g. card.1 for comment starting with ."
42 | // See e.g. node.1 for comment starting with .\
43 | // See e.g. units.1 for comment in a .de starting with . \"
44 | if (preg_match('~^([\'.]?\\\\?\\\\"|\.?\s*\\\\"|\'\."\'|\'\'\'|\."|\.\\\\\s+)~u', $lines[0], $matches)) {
45 | array_shift($lines);
46 |
47 | return true;
48 | }
49 |
50 | // \" is start of a comment. Everything up to the end of the line is ignored.
51 | // Some man pages get this wrong and expect \" to be printed (see fox-calculator.1),
52 | // but this behaviour is consistent with what the man command renders:
53 | $lines[0] = Replace::preg('~(^|.*?[^\\\\])\\\\".*$~u', '$1', $lines[0], -1, $replacements);
54 | if ($replacements > 0) {
55 | $lines[0] = mb_rtrim($lines[0], "\t");
56 |
57 | // Look at this same line again:
58 | return true;
59 | }
60 |
61 | if (preg_match('~^[\'.]\s*ig(?:\s+(?.*)|$)~u', $lines[0], $matches)) {
62 | array_shift($lines);
63 | $delimiter = empty($matches['delimiter']) ? '..' : ('.' . $matches['delimiter']);
64 | while (count($lines)) {
65 | $line = array_shift($lines);
66 | if ($line === $delimiter) {
67 | return true;
68 | }
69 | }
70 | throw new Exception($matches[0] . ' with no corresponding "' . $delimiter . '"');
71 | }
72 |
73 | return false;
74 | }
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/lib/Roff/Loop.php:
--------------------------------------------------------------------------------
1 | .
19 | */
20 | declare(strict_types=1);
21 |
22 | namespace Manner\Roff;
23 |
24 | use Exception;
25 |
26 | class Loop implements Template
27 | {
28 |
29 | /**
30 | * @param array $request
31 | * @param array $lines
32 | * @param array|null $macroArguments
33 | * @throws Exception
34 | */
35 | public static function evaluate(array $request, array &$lines, ?array $macroArguments): void
36 | {
37 | array_shift($lines);
38 |
39 | if (mb_strlen($request['raw_arg_string']) === 0) {
40 | return; // Just skip
41 | }
42 |
43 | if (preg_match(
44 | '~^' . Condition::CONDITION_REGEX . ' \\\\{\s*(.*)$~u',
45 | $request['raw_arg_string'],
46 | $matches
47 | )
48 | ) {
49 | $unrollOne = Condition::test($matches[1], $macroArguments);
50 | $newLines = Condition::ifBlock($lines, $matches[2], $unrollOne);
51 |
52 | if ($unrollOne) {
53 | $newLines = [...$newLines, '.while ' . $matches[1] . ' \\{', ...$newLines, '\\}'];
54 | array_splice($lines, 0, 0, $newLines);
55 | }
56 | }
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/lib/Roff/Macro.php:
--------------------------------------------------------------------------------
1 | .
19 | */
20 | declare(strict_types=1);
21 |
22 | namespace Manner\Roff;
23 |
24 | use Manner\Man;
25 | use Manner\Request;
26 |
27 | class Macro
28 | {
29 |
30 | public static function applyReplacements(string $string, array &$arguments, bool $fullLine = false): string
31 | {
32 | if ($fullLine) {
33 | $request = Request::peepAt($string);
34 | if ($request['name'] === 'shift') {
35 | $argsToShift = 1;
36 | if (preg_match('~^\d+$~', $request['raw_arg_string'])) {
37 | $argsToShift = (int)$request['raw_arg_string'];
38 | }
39 | for ($i = 0; $i < $argsToShift; ++$i) {
40 | array_shift($arguments);
41 | }
42 | Man::instance()->setRegister('.$', (string)count($arguments));
43 |
44 | return '.';
45 | }
46 | }
47 |
48 | // \$x - Macro or string argument with one-digit number x in the range 1 to 9.
49 | for ($n = 1; $n < 10; ++$n) {
50 | $string = str_replace('\\$' . $n, @$arguments[$n - 1] ?: '', $string);
51 | }
52 |
53 | // \$* : In a macro or string, the concatenation of all the arguments separated by spaces.
54 | $string = str_replace('\\$*', implode(' ', $arguments), $string);
55 |
56 | // \$@ : In a macro or string, the concatenation of all the arguments with each surrounded by double quotes, and separated by spaces.
57 | return str_replace('\\$@', '"' . implode('" "', $arguments) . '"', $string);
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/lib/Roff/Register.php:
--------------------------------------------------------------------------------
1 | .
19 | */
20 | declare(strict_types=1);
21 |
22 | namespace Manner\Roff;
23 |
24 | use Exception;
25 | use Manner\Man;
26 | use Manner\Replace;
27 |
28 | class Register implements Template
29 | {
30 |
31 | /**
32 | * @param array $request
33 | * @param array $lines
34 | * @param array|null $macroArguments
35 | * @throws Exception
36 | */
37 | public static function evaluate(array $request, array &$lines, ?array $macroArguments): void
38 | {
39 | $man = Man::instance();
40 | array_shift($lines);
41 |
42 | // Remove register
43 | if ($request['request'] === 'rr') {
44 | if (count($request['arguments']) === 1) {
45 | $man->unsetRegister($request['arguments'][0]);
46 | }
47 |
48 | return;
49 | }
50 |
51 | // .nr register ±N [M]
52 | // Define or modify register using ±N with auto-increment M
53 |
54 | if (count($request['arguments']) < 2) {
55 | return;
56 | }
57 |
58 | // Step might be in $request['arguments'][2] - but we just assume step is 1 for now.
59 |
60 | // Normalize here: a unit value may be concatenated when the register is used.
61 | $registerValue = Unit::normalize($request['arguments'][1], 'u', 'u');
62 | $man->setRegister($request['arguments'][0], $registerValue);
63 | }
64 |
65 | public static function substitute(string $string, array &$replacements): string
66 | {
67 | return Replace::pregCallback(
68 | '~(?J)(?(?:\\\\\\\\)*)\\\\n(?\+)?(?:\[(?[^]]+)]|\((?..)|(?.))~u',
69 | function ($matches) use (&$replacements) {
70 | if (isset($replacements[$matches['reg']])) {
71 | if ($matches['op'] === '+') {
72 | $replacements[$matches['reg']] = (int)$replacements[$matches['reg']] + 1;
73 | }
74 |
75 | return $matches['bspairs'] . $replacements[$matches['reg']];
76 | } else {
77 | // Match groff's behaviour: unset registers are 0
78 | return $matches['bspairs'] . '0';
79 | }
80 | },
81 | $string
82 | );
83 | }
84 |
85 | }
86 |
--------------------------------------------------------------------------------
/lib/Roff/Rename.php:
--------------------------------------------------------------------------------
1 | .
19 | */
20 | declare(strict_types=1);
21 |
22 | namespace Manner\Roff;
23 |
24 | class Rename implements Template
25 | {
26 |
27 | public static function evaluate(array $request, array &$lines, ?array $macroArguments): void
28 | {
29 | array_shift($lines); // Just ignore for now!
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/lib/Roff/Template.php:
--------------------------------------------------------------------------------
1 | .
19 | */
20 | declare(strict_types=1);
21 |
22 | namespace Manner\Roff;
23 |
24 | interface Template
25 | {
26 |
27 | public static function evaluate(array $request, array &$lines, ?array $macroArguments): void;
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/lib/Roff/Translation.php:
--------------------------------------------------------------------------------
1 | .
19 | */
20 | declare(strict_types=1);
21 |
22 | namespace Manner\Roff;
23 |
24 | use Manner\Man;
25 | use Manner\TextContent;
26 |
27 | class Translation implements Template
28 | {
29 |
30 | public static function evaluate(array $request, array &$lines, ?array $macroArguments): void
31 | {
32 | array_shift($lines);
33 |
34 | if (count($request['arguments']) === 1) {
35 | $man = Man::instance();
36 |
37 | $translate = $request['arguments'][0];
38 | $translate = TextContent::interpretString($translate, false);
39 |
40 | $chrArray = preg_split('~~u', $translate, -1, PREG_SPLIT_NO_EMPTY);
41 |
42 | for ($j = 0; $j < count($chrArray); $j += 2) {
43 | // "If there is an odd number of arguments, the last one is translated to an unstretchable space (‘\ ’)."
44 | $man->setCharTranslation($chrArray[$j], $j === count($chrArray) - 1 ? ' ' : $chrArray[$j + 1]);
45 | }
46 | }
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/lib/Roff/am.php:
--------------------------------------------------------------------------------
1 | .
19 | */
20 | declare(strict_types=1);
21 |
22 | namespace Manner\Roff;
23 |
24 | use Exception;
25 |
26 | class am implements Template
27 | {
28 |
29 | /**
30 | * @param array $request
31 | * @param array $lines
32 | * @param array|null $macroArguments
33 | * @throws Exception
34 | */
35 | public static function evaluate(array $request, array &$lines, ?array $macroArguments): void
36 | {
37 | array_shift($lines);
38 |
39 | if (
40 | !count($request['arguments'])
41 | || ($request['arguments'][0] !== 'URL' && $request['arguments'][0] !== 'MTO')
42 | ) {
43 | throw new Exception('Unexpected .am arguments: ' . print_r($request['arguments'], true));
44 | }
45 | }
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/lib/Roff/asRequest.php:
--------------------------------------------------------------------------------
1 | .
19 | */
20 | declare(strict_types=1);
21 |
22 | namespace Manner\Roff;
23 |
24 | use Manner\Man;
25 |
26 | // Can't just be called "as"
27 | class asRequest implements Template
28 | {
29 |
30 | public static function evaluate(array $request, array &$lines, ?array $macroArguments): void
31 | {
32 | array_shift($lines);
33 |
34 | if (count($request['arguments']) === 2) {
35 | $man = Man::instance();
36 | $stringName = $request['arguments'][0];
37 | $appendVal = $man->applyAllReplacements($request['arguments'][1]);
38 | $appendVal = Macro::applyReplacements($appendVal, $macroArguments);
39 | $string = $man->getString($stringName);
40 | $man->addString($stringName, $string . $appendVal);
41 | }
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/lib/Roff/cc.php:
--------------------------------------------------------------------------------
1 | .
19 | */
20 | declare(strict_types=1);
21 |
22 | namespace Manner\Roff;
23 |
24 | use Manner\Man;
25 |
26 | class cc implements Template
27 | {
28 |
29 | public static function evaluate(array $request, array &$lines, ?array $macroArguments): void
30 | {
31 | array_shift($lines);
32 |
33 | $char = count($request['arguments']) ? $request['arguments'][0] : '.';
34 |
35 | Man::instance()->control_char = $char;
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/lib/Roff/de.php:
--------------------------------------------------------------------------------
1 | .
19 | */
20 | declare(strict_types=1);
21 |
22 | namespace Manner\Roff;
23 |
24 | use Exception;
25 | use Manner\Man;
26 | use Manner\Request;
27 |
28 | class de implements Template
29 | {
30 |
31 | /**
32 | * @param array $request
33 | * @param array $lines
34 | * @param array|null $macroArguments
35 | * @throws Exception
36 | */
37 | public static function evaluate(array $request, array &$lines, ?array $macroArguments): void
38 | {
39 | // shift .de
40 | array_shift($lines);
41 |
42 | if (!preg_match('~^([^\s"]+)\s*$~u', $request['arg_string'], $matches)) {
43 | throw new Exception('Unexpected argument in \Roff\de: ' . $request['arg_string']);
44 | }
45 |
46 | $newMacro = $matches[1];
47 | $macroLines = [];
48 | $foundEnd = false;
49 |
50 | // We don't want to handle the lines at this stage (e.g. a conditional in the macro), so don't iterate with
51 | // Request::getLine()
52 | while (count($lines)) {
53 | $line = array_shift($lines);
54 | $request = Request::peepAt($line);
55 | if (
56 | $request['name'] === '.' ||
57 | ($newMacro === 'P!' && $line === '.') // work around bug in Xm*.3 man pages
58 | ) {
59 | $foundEnd = true;
60 | break;
61 | }
62 | $macroLines[] = Request::massageLine($line);
63 | }
64 |
65 | if (!$foundEnd) {
66 | throw new Exception('Macro definition for "' . $matches[1] . '" does not follow expected pattern.');
67 | }
68 |
69 | // Don't override these macros.
70 | // djvm e.g. does something dodgy when overriding .SS, just use normal .SS handling for it.
71 | // .URL: we can do a better job with the semantic info.
72 | // .BB & .EB: see criu.8: does something tricky with .di across macros.
73 | $protectedMacros = ['SS', 'MTO', 'URL', 'SY', 'YS', 'SH', 'TP', 'RS', 'RE', 'BB', 'EB', 'MR'];
74 |
75 | if (!in_array($newMacro, $protectedMacros)) {
76 | Man::instance()->addMacro($newMacro, $macroLines);
77 | }
78 | }
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/lib/Roff/di.php:
--------------------------------------------------------------------------------
1 | .
19 | */
20 | declare(strict_types=1);
21 |
22 | namespace Manner\Roff;
23 |
24 | use Exception;
25 | use Manner\Request;
26 |
27 | class di implements Template
28 | {
29 |
30 | /**
31 | * @param array $request
32 | * @param array $lines
33 | * @param array|null $macroArguments
34 | * @throws Exception
35 | */
36 | public static function evaluate(array $request, array &$lines, ?array $macroArguments): void
37 | {
38 | array_shift($lines);
39 |
40 | // We don't want to handle the lines at this stage as a fresh call to .di call a new \Request\di, so don't iterate
41 | // with Request::getLine()
42 | while ($line = array_shift($lines)) {
43 | if (Request::peepAt($line)['name'] === 'di') {
44 | return;
45 | }
46 | }
47 | throw new Exception('.di with no end .di');
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/lib/Roff/doRequest.php:
--------------------------------------------------------------------------------
1 | .
19 | */
20 | declare(strict_types=1);
21 |
22 | namespace Manner\Roff;
23 |
24 | /**
25 | * .do: "Interpret .name with compatibility mode disabled." (e.g. .do if ... )
26 | * NB: we many pick up new .do calls e.g. in conditional statements.
27 | */
28 | class doRequest implements Template
29 | {
30 |
31 | public static function evaluate(array $request, array &$lines, ?array $macroArguments): void
32 | {
33 | $lines[0] = '.' . $request['raw_arg_string'];
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/lib/Roff/ec.php:
--------------------------------------------------------------------------------
1 | .
19 | */
20 | declare(strict_types=1);
21 |
22 | namespace Manner\Roff;
23 |
24 | use Manner\Man;
25 |
26 | /**
27 | * Sets/resets the escape character, only ever used to reset after not being changed in body of man pages.
28 | */
29 | class ec implements Template
30 | {
31 |
32 | public static function evaluate(array $request, array &$lines, ?array $macroArguments): void
33 | {
34 | array_shift($lines);
35 | Man::instance()->escape_char = count($request['arguments']) ? $request['arguments'][0] : '\\';
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/lib/Roff/eo.php:
--------------------------------------------------------------------------------
1 | .
19 | */
20 | declare(strict_types=1);
21 |
22 | namespace Manner\Roff;
23 |
24 | use Manner\Man;
25 |
26 | /**
27 | * Turn off escape character mechanism.
28 | */
29 | class eo implements Template
30 | {
31 |
32 | public static function evaluate(array $request, array &$lines, ?array $macroArguments): void
33 | {
34 | array_shift($lines);
35 | Man::instance()->escape_char = null;
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/lib/Roff/nop.php:
--------------------------------------------------------------------------------
1 | .
19 | */
20 | declare(strict_types=1);
21 |
22 | namespace Manner\Roff;
23 |
24 | class nop implements Template
25 | {
26 |
27 | public static function evaluate(array $request, array &$lines, ?array $macroArguments): void
28 | {
29 | $lines[0] = $request['raw_arg_string'];
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/lib/Roff/returnRequest.php:
--------------------------------------------------------------------------------
1 | .
19 | */
20 | declare(strict_types=1);
21 |
22 | namespace Manner\Roff;
23 |
24 | class returnRequest implements Template
25 | {
26 |
27 | public static function evaluate(array $request, array &$lines, ?array $macroArguments): void
28 | {
29 | array_shift($lines);
30 |
31 | while (count($lines) && !is_null($lines[0])) {
32 | array_shift($lines);
33 | }
34 |
35 | // shift the null
36 | array_shift($lines);
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/lib/Text.php:
--------------------------------------------------------------------------------
1 | .
19 | */
20 | declare(strict_types=1);
21 |
22 | namespace Manner;
23 |
24 | class Text
25 | {
26 |
27 | public const string ZERO_WIDTH_SPACE_UTF8 = "\xE2\x80\x8B";
28 | public const string ZERO_WIDTH_SPACE_HTML = '';
29 |
30 | public static function trimAndRemoveZWSUTF8(?string $str): string
31 | {
32 | if (is_null($str)) {
33 | return "";
34 | }
35 |
36 | return mb_trim(str_replace(Text::ZERO_WIDTH_SPACE_UTF8, '', $str));
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/manner.php:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 | .
19 | */
20 | declare(strict_types=1);
21 |
22 | use Manner\Manner;
23 |
24 | require_once 'autoload.php';
25 |
26 | if (empty($argv[1])) {
27 | exit('no file.');
28 | }
29 |
30 | $filePath = $argv[1];
31 |
32 | if (!is_file($filePath)) {
33 | exit($filePath . ' is not a file.');
34 | }
35 |
36 | $fileLines = file($filePath, FILE_IGNORE_NEW_LINES);
37 |
38 | try {
39 | Manner::roffToHTML($fileLines);
40 | } catch (Exception $e) {
41 | echo PHP_EOL, PHP_EOL, $e->getMessage(), PHP_EOL;
42 | echo $e->getTraceAsString(), PHP_EOL;
43 | exit(1);
44 | }
45 |
--------------------------------------------------------------------------------
/run_tests.php:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 | .
19 | */
20 | declare(strict_types=1);
21 |
22 | use Manner\Manner;
23 |
24 | require_once 'autoload.php';
25 |
26 | /**
27 | * @param $filePath
28 | * @throws Exception
29 | */
30 | function runTest($filePath): void
31 | {
32 | if (!is_file($filePath)) {
33 | exit($filePath . ' is not a file.');
34 | }
35 |
36 | $expectedOutputPath = $filePath . '.html';
37 |
38 | if (!is_file($expectedOutputPath)) {
39 | exit($expectedOutputPath . ' is not a file.');
40 | }
41 |
42 | $fileLines = file($filePath, FILE_IGNORE_NEW_LINES);
43 |
44 | ob_start();
45 | Manner::roffToHTML($fileLines, null, true);
46 | $actualOutput = ob_get_contents();
47 | ob_end_clean();
48 |
49 | if ($actualOutput !== file_get_contents($expectedOutputPath)) {
50 | echo $filePath, PHP_EOL;
51 | echo '---------------------------', PHP_EOL;
52 | echo implode(PHP_EOL, $fileLines), PHP_EOL;
53 | echo '---------------------------', PHP_EOL;
54 | echo 'Expected:', PHP_EOL;
55 | echo file_get_contents($expectedOutputPath);
56 | echo '---------------------------', PHP_EOL;
57 | echo 'Got:', PHP_EOL;
58 | echo $actualOutput, PHP_EOL;
59 | }
60 | }
61 |
62 | $dir = new DirectoryIterator(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'tests');
63 | foreach ($dir as $fileInfo) {
64 | if ($fileInfo->isDot()) {
65 | continue;
66 | }
67 | if ($fileInfo->getExtension() === 'html') {
68 | continue;
69 | }
70 | runTest($fileInfo->getRealPath());
71 | }
72 |
--------------------------------------------------------------------------------
/tests/0in.1:
--------------------------------------------------------------------------------
1 | .TH 0IN 1
2 | .SH OPTIONS
3 |
4 | The first non-option argument to 0install is the particular sub-command you
5 | want to perform; these are described in detail in the next section.
6 |
7 | However,
8 |
--------------------------------------------------------------------------------
/tests/0in.1.html:
--------------------------------------------------------------------------------
1 | 0IN
OPTIONS
The first non-option argument to 0install is the particular sub-command you want to perform; these are described in detail in the next section.
However,
2 |
--------------------------------------------------------------------------------
/tests/BR.1:
--------------------------------------------------------------------------------
1 | .TH BR
2 | .SH HEADING
3 | See
4 | .BR man (1)
5 |
--------------------------------------------------------------------------------
/tests/BR.1.html:
--------------------------------------------------------------------------------
1 | BR
HEADING
See man(1)
2 |
--------------------------------------------------------------------------------
/tests/FONT.1:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .SH H
3 | .de FONT
4 | . ds result \&
5 | . while (\\n[.$] >= 2) \{\
6 | . as result \,\f[\\$1]\\$2
7 | . if !"\\$1"P" .as result \f[P]\""
8 | . shift 2
9 | . \}
10 | . if (\\n[.$] = 1) .as result \,\f[\\$1]
11 | . nh
12 | . nop \\*[result]\&
13 | . hy
14 | ..
15 | .FONT B \[rs]*[ I B ]
16 |
--------------------------------------------------------------------------------
/tests/FONT.1.html:
--------------------------------------------------------------------------------
1 | A
H
\*[<colorname>]
2 |
--------------------------------------------------------------------------------
/tests/FontOneInputLine.1:
--------------------------------------------------------------------------------
1 | .TH test
2 | .SH HEADING
3 | .B bold
4 | .I
5 | em
6 |
--------------------------------------------------------------------------------
/tests/FontOneInputLine.1.html:
--------------------------------------------------------------------------------
1 | test
HEADING
bold em
2 |
--------------------------------------------------------------------------------
/tests/IPs.1:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .SH H
3 | .IP * 4
4 | A
5 | .
6 | .IP "" 0
7 | .
8 | .P
9 | New para
10 |
--------------------------------------------------------------------------------
/tests/IPs.1.html:
--------------------------------------------------------------------------------
1 | A
H
- A
New para
2 |
--------------------------------------------------------------------------------
/tests/MT.1:
--------------------------------------------------------------------------------
1 | .TH MT
2 | .PP
3 | Mail comments, suggestions and bug reports to
4 | .MT shaleh@\:\:valinux.\:com
5 | Sean 'Shaleh' Perry
6 | .ME .
7 |
--------------------------------------------------------------------------------
/tests/MT.1.html:
--------------------------------------------------------------------------------
1 | MT
Mail comments, suggestions and bug reports to Sean 'Shaleh' Perry.
2 |
--------------------------------------------------------------------------------
/tests/NOP.1:
--------------------------------------------------------------------------------
1 | .TH NOP
2 | .de1 NOP
3 | . it 1 an-trap
4 | . if \\n[.$] \,\\$*\/
5 | ..
6 | .NOP hey
7 |
--------------------------------------------------------------------------------
/tests/NOP.1.html:
--------------------------------------------------------------------------------
1 | NOP
hey
2 |
--------------------------------------------------------------------------------
/tests/SbC2.1:
--------------------------------------------------------------------------------
1 | '\"! tbl | mmdoc
2 | '\"macro stdmacro
3 | . ds Cr \fB
4 | . ds Cb \fB
5 | .TH SbCylinder(3IV)
6 | .SH NAME
7 | .ds Pt \*(Cr
8 | .ie \w'\*(Pt'>=20n \{\
9 | .ne 3
10 | \*(Pt
11 | .ti 0.5i
12 | \c\
13 | \}
14 | .el\{\
15 | .ne 2
16 | \*(Pt \c\
17 | \}
18 | \*(CbSbCyl
19 |
--------------------------------------------------------------------------------
/tests/SbC2.1.html:
--------------------------------------------------------------------------------
1 | SbCylinder(3IV)
NAME
SbCyl
2 |
--------------------------------------------------------------------------------
/tests/SbCylinder.3iv:
--------------------------------------------------------------------------------
1 | '\"! tbl | mmdoc
2 | '\"macro stdmacro
3 | .ie n \{\
4 | . ds Cr \fB
5 | . ds Cb \fB
6 | .\}
7 | .el \{\
8 | . ds Cr \f7
9 | . ds Cb \f8
10 | .\}
11 | .TH SbCylinder(3IV)
12 | .SH SYNOPSIS
13 | .ps -1
14 | \*(Cr#include
15 |
--------------------------------------------------------------------------------
/tests/SbCylinder.3iv.html:
--------------------------------------------------------------------------------
1 | SbCylinder(3IV)
SYNOPSIS
#include <Inventor/SbLinear.h>
2 |
--------------------------------------------------------------------------------
/tests/SoXtWalkViewer-b.3:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .SH H
3 | .if \w'a b'>=2n \{\
4 | .ti 1
5 | \c\
6 | \}
7 | A
8 |
--------------------------------------------------------------------------------
/tests/SoXtWalkViewer-b.3.html:
--------------------------------------------------------------------------------
1 | A
H
A
2 |
--------------------------------------------------------------------------------
/tests/SoXtWalkViewer.3:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .SH H
3 | .ds Pt \*(Crvirtual void
4 | .if \w'\*(Pt'>=24n \{\
5 | .ti 1
6 | \c\
7 | \}
8 | A
9 |
--------------------------------------------------------------------------------
/tests/SoXtWalkViewer.3.html:
--------------------------------------------------------------------------------
1 | A
H
A
2 |
--------------------------------------------------------------------------------
/tests/ZN.1:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .SH H
3 | .de ZN
4 | .ie t \fB\^\\$1\^\fR\\$2
5 | .el \fI\^\\$1\^\fP\\$2
6 | ..
7 | .IP A
8 | .ZN B
9 | .LP
10 | .ZN C
11 | D
12 | .ZN
13 |
--------------------------------------------------------------------------------
/tests/ZN.1.html:
--------------------------------------------------------------------------------
1 | A
H
- A
B
C D
2 |
--------------------------------------------------------------------------------
/tests/apropos.1:
--------------------------------------------------------------------------------
1 | .TH blah 1
2 | .SH OPTIONS
3 | .TP
4 | A
5 | B
6 | .\"
7 | .\" Due to the rather silly limit of 6 args per request in some `native'
8 | .\" *roff compilers, we have do the following to get the two-line
9 | .\" hanging tag on one line. .PP to begin a new paragraph, then the
10 | .\" tag, then .RS (start relative indent), the text, finally .RE
11 | .\" (end relative indent).
12 | .\"
13 | .PP
14 | A
15 | .RS
16 | Sentence 1
17 |
18 | Sentence 2
19 | .RE
20 | .TP
21 | A
22 | B
23 |
--------------------------------------------------------------------------------
/tests/apropos.1.html:
--------------------------------------------------------------------------------
1 | blah
OPTIONS
- A
B
- A
Sentence 1
Sentence 2
- A
B
2 |
--------------------------------------------------------------------------------
/tests/atop.1:
--------------------------------------------------------------------------------
1 | .TH atop
2 | .SH HEADING
3 | .PP
4 | .TP 4
5 | term
6 | def
7 | .PP
8 |
--------------------------------------------------------------------------------
/tests/atop.1.html:
--------------------------------------------------------------------------------
1 | atop
HEADING
- term
def
2 |
--------------------------------------------------------------------------------
/tests/b.1:
--------------------------------------------------------------------------------
1 | .TH blah
2 | .SH NAME
3 | .B
4 | A
5 | .B "
6 | B
7 |
--------------------------------------------------------------------------------
/tests/b.1.html:
--------------------------------------------------------------------------------
1 | blah
NAME
A B
2 |
--------------------------------------------------------------------------------
/tests/bash_fonts.1:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .SH H
3 | to "\fB$1\fP\fIc\fP\fB$2\fP\fIc\fP\fB...\fP", where
4 | .I c
5 | is
6 |
--------------------------------------------------------------------------------
/tests/bash_fonts.1.html:
--------------------------------------------------------------------------------
1 | A
H
to "$1c$2c...", where c is
2 |
--------------------------------------------------------------------------------
/tests/bash_sm.1:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .SH H
3 | .SM
4 | \fBCOMMAND EXECUTION ENVIRONMENT\fP
5 | below).
6 | Variable
7 |
--------------------------------------------------------------------------------
/tests/bash_sm.1.html:
--------------------------------------------------------------------------------
1 | A
H
COMMAND EXECUTION ENVIRONMENT below). Variable
2 |
--------------------------------------------------------------------------------
/tests/br_in_tp.1:
--------------------------------------------------------------------------------
1 | .TH BRinTP 1
2 | .SH Heading
3 | .TP
4 | term
5 | A
6 | .br
7 | B
8 |
--------------------------------------------------------------------------------
/tests/br_in_tp.1.html:
--------------------------------------------------------------------------------
1 | BRinTP
Heading
- term
A
B
2 |
--------------------------------------------------------------------------------
/tests/bull.1:
--------------------------------------------------------------------------------
1 | .TH BULL 1
2 | .SH BLAH
3 | a\c
4 |
5 | heh
6 |
--------------------------------------------------------------------------------
/tests/bull.1.html:
--------------------------------------------------------------------------------
1 | BULL
BLAH
a heh
2 |
--------------------------------------------------------------------------------
/tests/c.3:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .SH H
3 | . ds Cr \fB
4 | .ds Pt \*(Crvirtual void
5 | .ie \w'\*(Pt'>=24n \{\
6 | .ne 3
7 | \*(Pt
8 | .ti 0.5i
9 | \c\
10 | \}
11 | .el\{\
12 | .ne 2
13 | \*(Pt \c\
14 | \}
15 | B
16 |
--------------------------------------------------------------------------------
/tests/c.3.html:
--------------------------------------------------------------------------------
1 | A
H
virtual void B
2 |
--------------------------------------------------------------------------------
/tests/callerid.conf.5:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .TP
3 | \\$1
4 | flags...
5 |
--------------------------------------------------------------------------------
/tests/callerid.conf.5.html:
--------------------------------------------------------------------------------
1 | A
- \$1
flags...
2 |
--------------------------------------------------------------------------------
/tests/cc.1:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .SH H
3 | .nf
4 | .cc |
5 | mode = LIST
6 | separator = "|"
7 | main prompt = "sqlite> "
8 | continue prompt = " ...> "
9 | |cc .
10 | .sp
11 | .fi
12 |
--------------------------------------------------------------------------------
/tests/cc.1.html:
--------------------------------------------------------------------------------
1 | A
H
mode = LIST
2 | separator = "|"
3 | main prompt = "sqlite> "
4 | continue prompt = " ...> "
5 |
--------------------------------------------------------------------------------
/tests/cef5conv.1:
--------------------------------------------------------------------------------
1 | .TH cef5conv
2 | .if n \{\
3 | .de C
4 | \\$1
5 | ..
6 | .\}
7 | .SH AUTHOR
8 | Werner Lemberg
9 | .C
10 |
--------------------------------------------------------------------------------
/tests/cef5conv.1.html:
--------------------------------------------------------------------------------
1 | cef5conv
AUTHOR
Werner Lemberg
2 |
--------------------------------------------------------------------------------
/tests/chars.1:
--------------------------------------------------------------------------------
1 | .TH chars
2 | .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
3 | .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
4 | .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
5 | .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
6 |
7 | . ds d- d\h'-1'\(ga
8 | . ds D- D\h'-1'\(hy
9 | . ds th \o'bp'
10 | . ds Th \o'LP'
11 |
12 | \*(d-
13 |
14 | \*(D-
15 |
16 | \*(th
17 |
18 | \*(Th
19 |
--------------------------------------------------------------------------------
/tests/chars.1.html:
--------------------------------------------------------------------------------
1 | chars
ð
Ð
Þ
þ
2 |
--------------------------------------------------------------------------------
/tests/ci.2:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .SH H
3 | .nr n \w'\(bu'+2n-1/1n
4 | .ds n \nn
5 | \*n
6 | ." .if \n(.g .if r an-tag-sep .ds n \w'\(bu'u+\n[an-tag-sep]u
7 | ." \*n
8 |
--------------------------------------------------------------------------------
/tests/ci.2.html:
--------------------------------------------------------------------------------
1 | A
H
2.7142857142857
2 |
--------------------------------------------------------------------------------
/tests/comment_after_font.1:
--------------------------------------------------------------------------------
1 | .TH comment
2 | .de NS
3 | .sp
4 | .in +4
5 | .nf
6 | .ft C \" Courier
7 | ..
8 | .de NE
9 | .fi
10 | .ft R
11 | .in -4
12 | ..
13 | .NS
14 | hey
15 | .NE
16 |
--------------------------------------------------------------------------------
/tests/comment_after_font.1.html:
--------------------------------------------------------------------------------
1 | comment
hey
2 |
--------------------------------------------------------------------------------
/tests/comp.1:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .SH H
3 | Text
4 | .EX
5 | .ta \w'Escape 'u +\w'Returns 'u
6 | .I "Escape Returns Description"
7 | fcc string Any folders specified with `\-fcc\ folder'
8 | subject string Any text specified with `\-subject\ text'
9 | .EE
10 | Text
11 |
--------------------------------------------------------------------------------
/tests/comp.1.html:
--------------------------------------------------------------------------------
1 | A
H
Text
EscapeReturnsDescriptionfccstringAny folders specified with `-fcc folder'subjectstringAny text specified with `-subject text'
Text
2 |
--------------------------------------------------------------------------------
/tests/cpupower-monitor.1:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .SH Options
3 | .PP
4 | \-l
5 | .RS 4
6 | List available monitors...
7 | .RS 2
8 | .IP \(bu
9 | The amount of...
10 | .IP \(bu
11 | The name and...
12 | .RS 4
13 | .IP \(bu
14 | [T] \-> Thread
15 | .IP \(bu
16 | [C] \-> Core
17 | .RE
18 | .RE
19 | .RE
20 |
--------------------------------------------------------------------------------
/tests/cpupower-monitor.1.html:
--------------------------------------------------------------------------------
1 | A
Options
- -l
List available monitors...
- The amount of...
The name and...
- [T] -> Thread
- [C] -> Core
2 |
--------------------------------------------------------------------------------
/tests/customVb.1:
--------------------------------------------------------------------------------
1 | .TH customVb
2 | .de Vb \" Begin verbatim text
3 | .ft CW
4 | .nf
5 | .ne \\$1
6 | ..
7 | .de Ve \" End verbatim text
8 | .ft R
9 | .fi
10 | ..
11 | .IP A 4
12 | B
13 | .IP C 4
14 | D
15 | .Sp
16 | .Vb 3
17 | E: verbose bit
18 | .Ve
19 | .Sp
20 | F
21 | .IP G 4
22 | H
23 |
--------------------------------------------------------------------------------
/tests/customVb.1.html:
--------------------------------------------------------------------------------
1 | customVb
- A
B
- C
D
E: verbose bit
F
- G
H
2 |
--------------------------------------------------------------------------------
/tests/digit_space.1:
--------------------------------------------------------------------------------
1 | .TH hey 1
2 | .SH H
3 | .PP
4 | a\0b
5 | .PP
6 | .BR c \0 d
7 | .TP
8 | .BI e \0 f \0 g
9 | .TP
10 |
--------------------------------------------------------------------------------
/tests/digit_space.1.html:
--------------------------------------------------------------------------------
1 | hey
H
a b
c d
e f g
2 |
--------------------------------------------------------------------------------
/tests/dir.1:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .SH H
3 | .TP
4 | \fB\-\-group\-directories\-first\fR
5 | group directories before files;
6 | .IP
7 | can be augmented with
8 |
--------------------------------------------------------------------------------
/tests/dir.1.html:
--------------------------------------------------------------------------------
1 | A
H
- --group-directories-first
group directories before files;
can be augmented with
2 |
--------------------------------------------------------------------------------
/tests/eh.1:
--------------------------------------------------------------------------------
1 | .TH EH 1
2 | .SH BLAH
3 | OPTIONS\c
4 | a).
5 |
6 | By
7 |
--------------------------------------------------------------------------------
/tests/eh.1.html:
--------------------------------------------------------------------------------
1 | EH
BLAH
OPTIONSa).
By
2 |
--------------------------------------------------------------------------------
/tests/ep.1:
--------------------------------------------------------------------------------
1 | .TH ep
2 | .ds EP \fIC\fP
3 | A
4 | B \*(EP.
5 |
--------------------------------------------------------------------------------
/tests/ep.1.html:
--------------------------------------------------------------------------------
1 | ep
A B C.
2 |
--------------------------------------------------------------------------------
/tests/eqn.1:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .SH H
3 | .RS
4 | .TP
5 | .B fat_offset
6 | The...
7 | .RS
8 | .IP
9 | .EX
10 |
11 | .EE
12 | .RE
13 | .TP
14 | .B over_hang
15 | A fraction bar...
16 | .RE
17 |
--------------------------------------------------------------------------------
/tests/eqn.1.html:
--------------------------------------------------------------------------------
1 | A
H
- fat_offset
The...
<mstyle mathvariant='double-struck'>
- over_hang
A fraction bar...
2 |
--------------------------------------------------------------------------------
/tests/ex.1:
--------------------------------------------------------------------------------
1 | .TH E 1
2 | .SH BUGS
3 | Version 2.23 changed the
4 | .B \-s
5 | option to be non-greedy, for example:
6 | .PP
7 | .EX
8 | \fBprintf "a:b:c\\n1::3\\n" | column -t -s ':'\fR
9 | .EE
10 | .PP
11 | Old output:
12 | .EX
13 | a b c
14 | 1 3
15 | .EE
16 | .PP
17 | New output (since util-linux 2.23):
18 | .EX
19 | a b c
20 | 1 3
21 | .EE
22 |
--------------------------------------------------------------------------------
/tests/ex.1.html:
--------------------------------------------------------------------------------
1 | E
BUGS
Version 2.23 changed the -s option to be non-greedy, for example:
printf "a:b:c\n1::3\n" | column -t -s ':'
Old output:
a b c
2 | 1 3
New output (since util-linux 2.23):
a b c
3 | 1 3
4 |
--------------------------------------------------------------------------------
/tests/fortune.6:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .SH H
3 | .TP
4 | term
5 | start
6 | .sp
7 | .RS
8 | new para
9 | .RE
10 |
--------------------------------------------------------------------------------
/tests/fortune.6.html:
--------------------------------------------------------------------------------
1 | A
H
- term
start
new para
2 |
--------------------------------------------------------------------------------
/tests/gawk.1b:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .SH H
3 | .BI \e n\fR,
4 | where
5 |
--------------------------------------------------------------------------------
/tests/gawk.1b.html:
--------------------------------------------------------------------------------
1 | A
H
\n, where
2 |
--------------------------------------------------------------------------------
/tests/gcc.1:
--------------------------------------------------------------------------------
1 | .TH gcc
2 | .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
3 | A B \*(C+ D
4 |
--------------------------------------------------------------------------------
/tests/gcc.1.html:
--------------------------------------------------------------------------------
1 | gcc
A B C++ D
2 |
--------------------------------------------------------------------------------
/tests/gdiffmk.1:
--------------------------------------------------------------------------------
1 | .TH A
2 | .SH H
3 | This document was written and is maintained by
4 | .MT MBianchi@Foveal.com
5 | Mike Bianchi
6 | .MT .
7 |
--------------------------------------------------------------------------------
/tests/gdiffmk.1.html:
--------------------------------------------------------------------------------
1 | A
H
This document was written and is maintained by Mike Bianchi
2 |
--------------------------------------------------------------------------------
/tests/gifsicle.1:
--------------------------------------------------------------------------------
1 | .TH GIFSICLE 1 "5 May 2012" "Version \*V"
2 | .SH SYNOPSIS
3 | A
4 | '
5 | .
6 |
--------------------------------------------------------------------------------
/tests/gifsicle.1.html:
--------------------------------------------------------------------------------
1 | GIFSICLE
SYNOPSIS
A
2 |
--------------------------------------------------------------------------------
/tests/glue-validator.1:
--------------------------------------------------------------------------------
1 | .TH GLUE_VALIDATOR 1
2 | .SH OPTIONS
3 | .IP "-t --test"
4 | The test class [glue1|glue2].
5 | .PP
6 | Server Mode: ...
7 | .IP "-h --host"
8 | Hostname of the LDAP server.
9 |
--------------------------------------------------------------------------------
/tests/glue-validator.1.html:
--------------------------------------------------------------------------------
1 | GLUE_VALIDATOR
OPTIONS
- -t --test
The test class [glue1|glue2].
Server Mode: ...
- -h --host
Hostname of the LDAP server.
2 |
--------------------------------------------------------------------------------
/tests/gmusicbrowser.1:
--------------------------------------------------------------------------------
1 | .TH gmusicbrowser
2 | .B
3 | .TP
4 | A
5 | B
6 |
--------------------------------------------------------------------------------
/tests/gmusicbrowser.1.html:
--------------------------------------------------------------------------------
1 | gmusicbrowser
- A
B
2 |
--------------------------------------------------------------------------------
/tests/gpp.1:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .SH H
3 | .P
4 | Moreover, all of these matching subsets except `\\w' and `\\W' can be
5 |
--------------------------------------------------------------------------------
/tests/gpp.1.html:
--------------------------------------------------------------------------------
1 | A
H
Moreover, all of these matching subsets except `\w' and `\W' can be
2 |
--------------------------------------------------------------------------------
/tests/groff_mm.7:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .SH H
3 | .BI AL\ \fR[\fPtype\ \fR[\fPtext-indent\ \fR[\fP1\fR]]]\fP
4 |
--------------------------------------------------------------------------------
/tests/groff_mm.7.html:
--------------------------------------------------------------------------------
1 | A
H
AL [type [text-indent [1]]]
2 |
--------------------------------------------------------------------------------
/tests/hg.1:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .SH H
3 | A
4 | .sp
5 | .nf
6 | .ft C
7 | B
8 | .ft P
9 | .fi
10 | C
11 |
--------------------------------------------------------------------------------
/tests/hg.1.html:
--------------------------------------------------------------------------------
1 | A
H
A
B
C
2 |
--------------------------------------------------------------------------------
/tests/indentation-a.1:
--------------------------------------------------------------------------------
1 | .TH Indentation-A 1
2 | .SH Heading
3 | .TP
4 | term
5 | stuff
6 | .RS
7 | .TP 20
8 | wide
9 | apart
10 | .RE
11 | .IP
12 | indented para
13 |
--------------------------------------------------------------------------------
/tests/indentation-a.1.html:
--------------------------------------------------------------------------------
1 | Indentation-A
Heading
- term
stuff
- wide
apart
indented para
2 |
--------------------------------------------------------------------------------
/tests/innxbatch.8:
--------------------------------------------------------------------------------
1 | .TH innxbatch
2 | .ds R$ A
3 | \*(R$
4 | .ds R$ B
5 | \*(R$
6 | .nf
7 | .ds R$ C
8 | \*(R$
9 | .ds R$ D
10 | \*(R$
11 | .fi
12 |
--------------------------------------------------------------------------------
/tests/innxbatch.8.html:
--------------------------------------------------------------------------------
1 | innxbatch
A B
C
2 | D
3 |
--------------------------------------------------------------------------------
/tests/iostat.1:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .SH H
3 | .IP Report
4 | The report has the following format:
5 |
6 | .B %user
7 | .RS
8 | .RS
9 | Show the percentage of CPU utilization that occurred while
10 | .RE
11 |
12 | .B %nice
13 | .RS
14 | Show the percentage of CPU utilization that occurred while
15 | .RE
16 |
17 | .B %system
18 | .RS
19 | Show the percentage of CPU utilization that occurred while
20 | .RE
21 | .RE
22 |
--------------------------------------------------------------------------------
/tests/iostat.1.html:
--------------------------------------------------------------------------------
1 | A
H
- Report
The report has the following format:
- %user
Show the percentage of CPU utilization that occurred while
- %nice
Show the percentage of CPU utilization that occurred while
- %system
Show the percentage of CPU utilization that occurred while
2 |
--------------------------------------------------------------------------------
/tests/ksh.1:
--------------------------------------------------------------------------------
1 | .nr Z 1 \" set to 1 when command name is ksh, 2 for ksh93
2 | .if \nZ=0 \{\
3 | .TH SH 1
4 | .\}
5 | .if \nZ=1 \{\
6 | .TH KSH 1
7 | .\}
8 | .SH H
9 |
--------------------------------------------------------------------------------
/tests/ksh.1.html:
--------------------------------------------------------------------------------
1 | KSH
H
2 |
--------------------------------------------------------------------------------
/tests/links2.1:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .SH FILES
3 | .TP
4 | .IP "~/.links/links.cfg"
5 | Per-user configfile, automatically created by
6 | .B links.
7 | .TP
8 | ~/.links/links.cfg
9 | Per-user configfile, automatically created by
10 | .B links.
11 |
--------------------------------------------------------------------------------
/tests/links2.1.html:
--------------------------------------------------------------------------------
1 | A
FILES
- ~/.links/links.cfg
Per-user configfile, automatically created by links.
- ~/.links/links.cfg
Per-user configfile, automatically created by links.
2 |
--------------------------------------------------------------------------------
/tests/listA.1:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .SH H
3 | Something:
4 | .RS 4
5 | \(bu one
6 | .RE
7 | .RS 4
8 | \(bu two
9 | .RE
10 | .RS 4
11 | \(bu three
12 | .RE
13 |
--------------------------------------------------------------------------------
/tests/listA.1.html:
--------------------------------------------------------------------------------
1 | A
H
Something:
- one
- two
- three
2 |
--------------------------------------------------------------------------------
/tests/logical_or.1:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .SH H
3 | .if (1:(0)) yep
4 |
--------------------------------------------------------------------------------
/tests/logical_or.1.html:
--------------------------------------------------------------------------------
1 | A
H
yep
2 |
--------------------------------------------------------------------------------
/tests/lsmcli.1:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .SH H
3 | You can pass...
4 | .RS 4
5 | * Using a
6 | .br
7 | * Using b
8 | .br
9 | * Add c
10 | .RS 4
11 | blah
12 |
--------------------------------------------------------------------------------
/tests/lsmcli.1.html:
--------------------------------------------------------------------------------
1 | A
H
You can pass...
- Using a
- Using b
Add c
blah
2 |
--------------------------------------------------------------------------------
/tests/mdadm.8:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .ie '1.2'0.90'
3 | Bad
4 | .el
5 | Good
6 |
--------------------------------------------------------------------------------
/tests/mdadm.8.html:
--------------------------------------------------------------------------------
1 | A
Good
2 |
--------------------------------------------------------------------------------
/tests/mplayer.1:
--------------------------------------------------------------------------------
1 | .TH mplayer
2 | .de IPs
3 | .IP "\\$1" 5
4 | ..
5 | .IPs
6 | mplayer \-http\-header\-fields 'Field1: value1','Field2: value2' http://localhost:1234
7 |
--------------------------------------------------------------------------------
/tests/mplayer.1.html:
--------------------------------------------------------------------------------
1 | mplayer
mplayer -http-header-fields 'Field1: value1','Field2: value2' http://localhost:1234
2 |
--------------------------------------------------------------------------------
/tests/nawk.1:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .SH H
3 | .TP
4 | .EX
5 | /start/, /stop/
6 | .EE
7 | Print all lines between start/stop pairs.
8 |
--------------------------------------------------------------------------------
/tests/nawk.1.html:
--------------------------------------------------------------------------------
1 | A
H
- /start/, /stop/
Print all lines between start/stop pairs.
2 |
--------------------------------------------------------------------------------
/tests/nf.1:
--------------------------------------------------------------------------------
1 | .TH nf
2 | .nf
3 | A
4 | .ds R$ B
5 | \*(R$
6 | .ds R$ C
7 | \*(R$
8 |
--------------------------------------------------------------------------------
/tests/nf.1.html:
--------------------------------------------------------------------------------
1 | nf
A
2 | B
3 | C
4 |
--------------------------------------------------------------------------------
/tests/ovn-sb.5:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .SH H
3 | .IP
4 | The following actions are defined:
5 | .RS
6 | .TP
7 | \fBct_snat;\fR
8 | .TQ .5in
9 | \fBct_snat(\fIIP\fB);\fR
10 | \fBct_snat\fR sends the packet...
11 | .RS
12 | .IP \(bu
13 | On a gateway router...
14 | .IP \(bu
15 | On a distributed...
16 | .RE
17 | .IP
18 | \fBct_snat(\fIIP\fB)\fR sends the packet
19 |
--------------------------------------------------------------------------------
/tests/ovn-sb.5.html:
--------------------------------------------------------------------------------
1 | A
H
The following actions are defined:
- ct_snat;
- ct_snat(IP);
ct_snat sends the packet...
- On a gateway router...
- On a distributed...
ct_snat(IP) sends the packet
2 |
--------------------------------------------------------------------------------
/tests/pmcpp.1:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .SH H
3 | \fB#shell '\fIcommand\fB'
4 | .br
5 | The shell
6 |
--------------------------------------------------------------------------------
/tests/pmcpp.1.html:
--------------------------------------------------------------------------------
1 | A
H
#shell 'command'
The shell
2 |
--------------------------------------------------------------------------------
/tests/pmdapipe.1:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .SH H
3 | .PP
4 | Each command configuration line is of the form:
5 | .TP
6 | \&
7 | \f2instance\f1 \f2username\f1 \f2command\f1 \f2options\f1
8 | .PP
9 | Where
10 |
--------------------------------------------------------------------------------
/tests/pmdapipe.1.html:
--------------------------------------------------------------------------------
1 | A
H
Each command configuration line is of the form:
instance username command options
Where
2 |
--------------------------------------------------------------------------------
/tests/portage.5:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .nr step 1 1
3 | .IP \n[step]. 3
4 | A
5 | .IP \n+[step].
6 | B
7 | .IP \n+[step].
8 | C
9 |
--------------------------------------------------------------------------------
/tests/portage.5.html:
--------------------------------------------------------------------------------
1 | A
- A
- B
- C
2 |
--------------------------------------------------------------------------------
/tests/pp.1:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .SH H
3 | Text
4 | .PP
5 | .SH A
6 |
--------------------------------------------------------------------------------
/tests/pp.1.html:
--------------------------------------------------------------------------------
1 | A
H
Text
A
2 |
--------------------------------------------------------------------------------
/tests/pp_in_pre.1:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .SH H
3 | .nf
4 | A
5 | .PP
6 | tool.
7 | .nf
8 | $ setreg 1 true
9 | .fi
10 | .PP
11 | Another option to ease updates is to synchronize your machine trust store
12 |
13 |
--------------------------------------------------------------------------------
/tests/pp_in_pre.1.html:
--------------------------------------------------------------------------------
1 | A
H
A
2 |
3 | tool.
4 | $ setreg 1 true
Another option to ease updates is to synchronize your machine trust store
5 |
--------------------------------------------------------------------------------
/tests/prefontspace.2:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .SH H
3 | .ft B
4 | .nf
5 | hey
6 | .fi
7 |
--------------------------------------------------------------------------------
/tests/prefontspace.2.html:
--------------------------------------------------------------------------------
1 | A
H
hey
2 |
--------------------------------------------------------------------------------
/tests/proc.5:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .SH H
3 | .IP
4 | For...
5 | .nf
6 | pos: 0
7 | .fi
8 | event
9 |
--------------------------------------------------------------------------------
/tests/proc.5.html:
--------------------------------------------------------------------------------
1 | A
H
For...
pos: 0
event
2 |
--------------------------------------------------------------------------------
/tests/ps.1:
--------------------------------------------------------------------------------
1 | .TH PS 1 "July 28, 2004" "Linux" "Linux User's Manual"
2 | .nr OptSize (16u)
3 | .de opt
4 | . TP \\n[OptSize]
5 | . BI \\$*
6 | ..
7 | .opt A
8 | B
9 |
--------------------------------------------------------------------------------
/tests/ps.1.html:
--------------------------------------------------------------------------------
1 | PS
- A
B
2 |
--------------------------------------------------------------------------------
/tests/rc.4:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .de Cr
3 | .Xf R R \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6"
4 | ..
5 | .de Xf
6 | .if !"\\$4"" .Xf \\$2 \\$1 "\\$3\\f\\$1\\$4" "\\$5" "\\$6" "\\$7" "\\$8" "\\$9"
7 | .if "\\$4"" \\$3\fR
8 | ..
9 | A
10 | .Cr $^foo ,
11 | B
12 | .Cr "$""foo"
13 | C
14 |
--------------------------------------------------------------------------------
/tests/rc.4.html:
--------------------------------------------------------------------------------
1 | A
A $^foo, B $"foo C
2 |
--------------------------------------------------------------------------------
/tests/rc.4b:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .de Cr
3 | .Xf R R \& "\\$1" "\\$2" "\\$3"
4 | ..
5 | .de Xf
6 | .if !"\\$4"" .Xf \\$2 \\$1 "\\$3\\f\\$1\\$4" "\\$5" "\\$6
7 | .if "\\$4"" \\$3\fR
8 | ..
9 | A
10 | .Cr $^foo ,
11 |
--------------------------------------------------------------------------------
/tests/rc.4b.html:
--------------------------------------------------------------------------------
1 | A
A $^foo,
2 |
--------------------------------------------------------------------------------
/tests/rc.4c:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .de Cr
3 | .Xf R R \& "\\$1"
4 | ..
5 | .de Xf
6 | .if !"\\$4"" .Xf \\$2 \\$1 "\\$3\\f\\$1\\$4"
7 | .if "\\$4"" \\$3\fR
8 | ..
9 | A
10 | .Cr B
11 |
--------------------------------------------------------------------------------
/tests/rc.4c.html:
--------------------------------------------------------------------------------
1 | A
A B
2 |
--------------------------------------------------------------------------------
/tests/rc.4d:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .de Xf
3 | .if "\\$1"Q" B
4 | ..
5 | A
6 | .Xf Q
7 |
--------------------------------------------------------------------------------
/tests/rc.4d.html:
--------------------------------------------------------------------------------
1 | A
A B
2 |
--------------------------------------------------------------------------------
/tests/rc.4e:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | A
3 | .if "Q"Q" B
4 |
--------------------------------------------------------------------------------
/tests/rc.4e.html:
--------------------------------------------------------------------------------
1 | A
A B
2 |
--------------------------------------------------------------------------------
/tests/rc.4f:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .SH A"
3 | .SH "A"B"
4 |
--------------------------------------------------------------------------------
/tests/rc.4f.html:
--------------------------------------------------------------------------------
1 | A
A"
A B"
2 |
--------------------------------------------------------------------------------
/tests/re_syntax.n:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .SH H
3 | .ie '\w'o''\w'\C'^o''' .ds qo \C'^o'
4 | .el .ds qo u
5 | A: \*(qo
6 |
--------------------------------------------------------------------------------
/tests/re_syntax.n.html:
--------------------------------------------------------------------------------
1 | A
H
A: ô
2 |
--------------------------------------------------------------------------------
/tests/repl.1:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .SH H
3 | .PP
4 | .fc ^ ~
5 | .nf
6 | .ta \w'/etc/nmh/ExtraBigFileName 'u
7 | ^/etc/nmh/replcomps~^The standard reply template
8 | ^or /replcomps~^Rather than the standard template
9 | .fi
10 |
--------------------------------------------------------------------------------
/tests/repl.1.html:
--------------------------------------------------------------------------------
1 | A
H
/etc/nmh/replcomps The standard reply template or <mh-dir>/replcomps Rather than the standard template
2 |
--------------------------------------------------------------------------------
/tests/roff.7:
--------------------------------------------------------------------------------
1 | .TH ROFF 7 "4 November 2014" "Groff Version 1.22.3"
2 | .de Esc
3 | . ds @1 \\$1
4 | . shift
5 | . nop \f[B]\[rs]\\*[@1]\f[]\\$*
6 | . rm @1
7 | ..
8 | .
9 | .de QuotedChar
10 | . ds @1 \\$1
11 | . shift
12 | . nop \[oq]\f[B]\\*[@1]\f[]\[cq]\\$*
13 | . rm @1
14 | ..
15 | .P
16 | .I Escape sequences
17 | are
18 | .I roff
19 | elements starting with a backslash
20 | .QuotedChar \[rs] .
21 | .
22 | They can be inserted anywhere, also in the midst of text in a line.
23 | .
24 | They are used to implement various features, including the insertion of
25 | non-\f[CR]ASCII\f[] characters with
26 | .Esc ( ,
27 | font changes with
28 | .Esc f ,
29 | in-line comments with
30 | .Esc \[dq] ,
31 | the escaping of special control characters like
32 | .Esc \[rs] ,
33 | and many other features.
34 |
--------------------------------------------------------------------------------
/tests/roff.7.html:
--------------------------------------------------------------------------------
1 | ROFF
Escape sequences are roff elements starting with a backslash ‘\’. They can be inserted anywhere, also in the midst of text in a line. They are used to implement various features, including the insertion of non-ASCII characters with \(, font changes with \f, in-line comments with \", the escaping of special control characters like \\, and many other features.
2 |
--------------------------------------------------------------------------------
/tests/rs.1:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .SH H
3 | .TP
4 | A
5 | Some text.
6 | .RS
7 | C
8 | .TP
9 | D
10 | E
11 | .RE
12 | F
13 | .TP
14 | G
15 | H
16 |
--------------------------------------------------------------------------------
/tests/rs.1.html:
--------------------------------------------------------------------------------
1 | A
H
- A
Some text.
C
- D
E
F
- G
H
2 |
--------------------------------------------------------------------------------
/tests/sh.1:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .SH A B
3 | .SH "A B"
4 | .SH
5 | A B
6 | .SH \
7 |
--------------------------------------------------------------------------------
/tests/sh.1.html:
--------------------------------------------------------------------------------
1 | A
A B
A B
A B
2 |
--------------------------------------------------------------------------------
/tests/simple.1:
--------------------------------------------------------------------------------
1 | .TH simple
2 | .SH HEADING
3 | .SS SUBHEADING
4 | .PP
5 | Paragraph
6 | of
7 | Text
8 |
--------------------------------------------------------------------------------
/tests/simple.1.html:
--------------------------------------------------------------------------------
1 | simple
HEADING
SUBHEADING
Paragraph of Text
2 |
--------------------------------------------------------------------------------
/tests/soft_hyphen.1:
--------------------------------------------------------------------------------
1 | .TH man 1
2 | .SH H
3 | .ie c \[shc] \
4 | . ds softhyphen \[shc]
5 | .el \
6 | . ds softhyphen \(hy
7 | A\*[softhyphen]B
8 |
--------------------------------------------------------------------------------
/tests/soft_hyphen.1.html:
--------------------------------------------------------------------------------
1 | man
H
A-B
2 |
--------------------------------------------------------------------------------
/tests/sox.1:
--------------------------------------------------------------------------------
1 | .TH sox
2 | .ds RA \(->
3 | The overall SoX processing chain can be summarised as follows:
4 | .TS
5 | center;
6 | l.
7 | Input(s) \*(RA Combiner \*(RA Effects \*(RA Output(s)
8 | .TE
9 |
--------------------------------------------------------------------------------
/tests/sox.1.html:
--------------------------------------------------------------------------------
1 | sox
The overall SoX processing chain can be summarised as follows:
Input(s) → Combiner → Effects → Output(s)
2 |
--------------------------------------------------------------------------------
/tests/sox.1b:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .if 1 .ds m " -
3 | A\*mB
4 |
--------------------------------------------------------------------------------
/tests/sox.1b.html:
--------------------------------------------------------------------------------
1 | A
A - B
2 |
--------------------------------------------------------------------------------
/tests/spaces.1:
--------------------------------------------------------------------------------
1 | .TH spaces 1
2 | .SH HEADING
3 | .nf
4 | .B " hey"
5 | .fi
6 |
--------------------------------------------------------------------------------
/tests/spaces.1.html:
--------------------------------------------------------------------------------
1 | spaces
HEADING
hey
2 |
--------------------------------------------------------------------------------
/tests/tcpdump_rses.1:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .SH H
3 | .TP
4 | .B \-l
5 | Make stdout line buffered.
6 | .IP
7 | .RS
8 | .RS
9 | .nf
10 | \fBtcpdump \-l | tee dat\fP
11 | .fi
12 | .RE
13 | .RE
14 | .IP
15 | or
16 | .IP
17 | .RS
18 | .RS
19 | .nf
20 | \fBtcpdump \-l > dat & tail \-f dat\fP
21 | .fi
22 | .RE
23 | .RE
24 | .IP
25 | Note that on Windows
26 |
--------------------------------------------------------------------------------
/tests/tcpdump_rses.1.html:
--------------------------------------------------------------------------------
1 | A
H
- -l
Make stdout line buffered.
tcpdump -l | tee dat
or
tcpdump -l > dat & tail -f dat
Note that on Windows
2 |
--------------------------------------------------------------------------------
/tests/ti.1:
--------------------------------------------------------------------------------
1 | .TH Hey 1 1
2 | .SH HEADING
3 | A
4 | .ti 1
5 | B
6 | C
7 | .P
8 | D
9 |
--------------------------------------------------------------------------------
/tests/ti.1.html:
--------------------------------------------------------------------------------
1 | Hey
HEADING
A
B C
D
2 |
--------------------------------------------------------------------------------
/tests/tp.1:
--------------------------------------------------------------------------------
1 | .TH tp
2 | .TP
3 | term
4 | definition
5 |
--------------------------------------------------------------------------------
/tests/tp.1.html:
--------------------------------------------------------------------------------
1 | tp
- term
definition
2 |
--------------------------------------------------------------------------------
/tests/tpthennewline.1:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .SH HEADING
3 | .TP
4 |
5 | .B A
6 | B
7 |
--------------------------------------------------------------------------------
/tests/tpthennewline.1.html:
--------------------------------------------------------------------------------
1 | A
HEADING
- A
B
2 |
--------------------------------------------------------------------------------
/tests/tr.1:
--------------------------------------------------------------------------------
1 | .TH tr
2 | .SH A
3 | .tr Q"
4 | .ds ms backup [QQ]
5 | .PP
6 | .B "\*(ms"
7 | .tr QQ
8 |
--------------------------------------------------------------------------------
/tests/tr.1.html:
--------------------------------------------------------------------------------
1 | tr
A
backup [""]
2 |
--------------------------------------------------------------------------------
/tests/trailingTP.1:
--------------------------------------------------------------------------------
1 | .TH trailingTP
2 | .SH OPTIONS
3 | .TP 5
4 | .B A
5 | B
6 | .TP 5
7 | New paragraph
8 | .SH FILES
9 |
--------------------------------------------------------------------------------
/tests/trailingTP.1.html:
--------------------------------------------------------------------------------
1 | trailingTP
OPTIONS
- A
B
New paragraph
FILES
2 |
--------------------------------------------------------------------------------
/tests/ttylink.1:
--------------------------------------------------------------------------------
1 | .TH ttylink
2 | Something \X'tty: link http://example.com/'\fI\%blah\fP\X'tty: link' else
3 |
--------------------------------------------------------------------------------
/tests/ttylink.1.html:
--------------------------------------------------------------------------------
1 | ttylink
Something blah else
2 |
--------------------------------------------------------------------------------
/tests/units.1:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .SH H
3 | .PP
4 | .nr a 1n
5 | a register is \na
6 | .PP
7 | .nr b 1i
8 | b register is \nb
9 | .PP
10 | .nr c 1in
11 | c register is \nc
12 | .PP
13 | .nr d \nc
14 | d register is \nd
15 |
--------------------------------------------------------------------------------
/tests/units.1.html:
--------------------------------------------------------------------------------
1 | A
H
a register is 21
b register is 240
c register is 240
d register is 240
2 |
--------------------------------------------------------------------------------
/tests/url.1:
--------------------------------------------------------------------------------
1 | .de URL
2 | \\$2 \(la \\$1 \(ra\\$3
3 | ..
4 | .TH URL
5 | .P
6 | URL:
7 | .URL "http://www.example.com/"
8 | .P
9 | UR/UE:
10 | .UR https://example.com/something
11 | Some Project
12 | .UE .
--------------------------------------------------------------------------------
/tests/url.1.html:
--------------------------------------------------------------------------------
1 | URL
UR/UE: Some Project.
2 |
--------------------------------------------------------------------------------
/tests/warnquota.conf.5:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .SH EXAMPLE
3 | .PP
4 | # comment
5 | .RS 0
6 | FROM = root@example.com
7 | .RS 0
8 | SUPPORT = support@example.com
9 | .RS 0
10 | PHONE = 1234
11 | .SH FILES
12 |
--------------------------------------------------------------------------------
/tests/warnquota.conf.5.html:
--------------------------------------------------------------------------------
1 | A
EXAMPLE
# comment
FROM = root@example.com
SUPPORT = support@example.com
PHONE = 1234
FILES
2 |
--------------------------------------------------------------------------------
/tests/while.1:
--------------------------------------------------------------------------------
1 | .TH while
2 | .de XB
3 | . while \\n[.$] \{\
4 | \$1
5 | . shift
6 | . \}
7 | ..
8 | .XB a b c d
9 |
--------------------------------------------------------------------------------
/tests/while.1.html:
--------------------------------------------------------------------------------
1 | while
a b c d
2 |
--------------------------------------------------------------------------------
/tests/xpaenv.n:
--------------------------------------------------------------------------------
1 | .TH xpaenv n
2 | .SH Description
3 | .IP "\(bu" 4
4 | \&\fB\s-1XPA_ACL\s0\fR
5 | .sp
6 | If something something \fI\s-1XPA_ACL\s0\fR is \fItrue\fR, then
7 | .IP "\(bu" 4
8 | \&\fB\s-1XPA_ACLFILE\s0\fR
9 | .sp
10 | If something else
11 |
--------------------------------------------------------------------------------
/tests/xpaenv.n.html:
--------------------------------------------------------------------------------
1 | xpaenv
Description
XPA_ACL
If something something XPA_ACL is true, then
XPA_ACLFILE
If something else
2 |
--------------------------------------------------------------------------------
/tests/xterm.1:
--------------------------------------------------------------------------------
1 | .TH xterm 1
2 | .de bP
3 | .ie n .IP \(bu 4
4 | .el .IP \(bu 2
5 | ..
6 | .bP
7 | hey
8 |
--------------------------------------------------------------------------------
/tests/xterm.1.html:
--------------------------------------------------------------------------------
1 | xterm
- hey
2 |
--------------------------------------------------------------------------------
/tests/zct.1:
--------------------------------------------------------------------------------
1 | .TH A 1
2 | .SH H
3 | .TS
4 | tab(:);
5 | c s s s c s s s, n n n nw4 n n n n.
6 | inp:out
7 | 1:1:2:2:4:4:3:3
8 | 1:1:2:2:4:4:3:3
9 | 3:3:4:4:2:2:1:1
10 | 3:3:4:4:2:2:1:1
11 | .TE
12 |
--------------------------------------------------------------------------------
/tests/zct.1.html:
--------------------------------------------------------------------------------
1 | A
H
inp out 1 1 2 2 4 4 3 3 1 1 2 2 4 4 3 3 3 3 4 4 2 2 1 1 3 3 4 4 2 2 1 1
2 |
--------------------------------------------------------------------------------