- /* "2>&1" is added so that nroff errors are shown in pager too.
- * Otherwise it may show just empty screen */
- cmd = xasprintf(cat ? "%s '%s' | %s"
- : "%s '%s' | gtbl | nroff -Tlatin1 -mandoc 2>&1 | %s",
- unpacker, man_filename, pager);
+ if (man) { /* man page, not cat page */
+ /* Is this a link to another manpage? */
+ /* The link has the following on the first line: */
+ /* ".so another_man_page" */
+
+ struct stat sb;
+ char *line;
+ char *linkname, *p;
+
+ /* On my system:
+ * man1/genhostid.1.gz: 203 bytes - smallest real manpage
+ * man2/path_resolution.2.gz: 114 bytes - largest link
+ */
+ xstat(man_filename, &sb);
+ if (sb.st_size > 300) /* err on the safe side */
+ goto ordinary_manpage;
+
+ line = xmalloc_open_zipped_read_close(man_filename, NULL);
+ if (!line || !is_prefixed_with(line, ".so ")) {
+ free(line);
+ goto ordinary_manpage;
+ }
+ /* Example: man2/path_resolution.2.gz contains
+ * ".so man7/path_resolution.7\n<junk>"
+ */
+ *strchrnul(line, '\n') = '\0';
+ linkname = skip_whitespace(&line[4]);
+
+ /* If link has no slashes, we just replace man page name.
+ * If link has slashes (however many), we go back *once*.
+ * ".so zzz/ggg/page.3" does NOT go back two levels. */
+ p = strrchr(man_filename, '/');
+ if (!p)
+ goto ordinary_manpage;
+ *p = '\0';
+ if (strchr(linkname, '/')) {
+ p = strrchr(man_filename, '/');
+ if (!p)
+ goto ordinary_manpage;
+ *p = '\0';
+ }
+
+ /* Links do not have .gz extensions, even if manpage
+ * is compressed */
+ man_filename = xasprintf("%s/%s", man_filename, linkname);
+ free(line);
+ /* Note: we leak "new" man_filename string as well... */
+ if (show_manpage(man_filename, man, level + 1))
+ return 1;
+ /* else: show the link, it's better than nothing */
+ }
+
+ ordinary_manpage:
+ close(STDIN_FILENO);
+ open_zipped(man_filename, /*fail_if_not_compressed:*/ 0); /* guaranteed to use fd 0 (STDIN_FILENO) */
+ if (man) {
+ int w = get_terminal_width(-1);
+ if (w > 10)
+ w -= 2;
+ /* "2>&1" is added so that nroff errors are shown in pager too.
+ * Otherwise it may show just empty screen.
+ */
+ cmd = xasprintf("%s | %s -rLL=%un -rLT=%un 2>&1 | %s",
+ G.tbl, G.nroff, w, w,
+ G.pager);
+ } else {
+ cmd = xstrdup(G.pager);
+ }