BusyBox less doesn't support tag files (-T option), hence we previously disabled tag file support in mandoc at compile-time (HAVE_LESS_T). However, on Alpine it is entirely possible to replace BusyBox less with an implementation that supports tag files (e.g. main/less). In order to support tag files when such an implementation is installed, we need to detect at runtime whether -T is supported. This patch achieves this by invoking the pager once with -T beforehand and checking if it terminates with a non-zero exit status. diff -upr mandoc-1.14.6.orig/configure mandoc-1.14.6/configure --- mandoc-1.14.6.orig/configure 2023-07-02 19:38:31.011639507 +0200 +++ mandoc-1.14.6/configure 2023-07-02 19:38:41.794998501 +0200 @@ -67,7 +67,6 @@ HAVE_FTS_COMPARE_CONST= HAVE_GETLINE= HAVE_GETSUBOPT= HAVE_ISBLANK= -HAVE_LESS_T= HAVE_MKDTEMP= HAVE_MKSTEMPS= HAVE_NANOSLEEP= @@ -363,21 +362,6 @@ fi echo "selected BINM_PAGER=${BINM_PAGER}${manual}" 1>&2 echo "selected BINM_PAGER=${BINM_PAGER}${manual}" 1>&3 -# --- tagging support in the pager --- -if ismanual "${BINM_PAGER} -T" LESS_T ${HAVE_LESS_T}; then - : -elif ${BINM_PAGER} -T /dev/null test-noop.c 1>/dev/null 2>&3; then - HAVE_LESS_T=1 - echo "tested ${BINM_PAGER} -T: yes" 1>&2 - echo "tested ${BINM_PAGER} -T: yes" 1>&3 - echo 1>&3 -else - HAVE_LESS_T=0 - echo "tested ${BINM_PAGER} -T: no" 1>&2 - echo "tested ${BINM_PAGER} -T: no" 1>&3 - echo 1>&3 -fi - # --- wide character and locale support --- if get_locale; then runtest wchar WCHAR "-DUTF8_LOCALE=\"${UTF8_LOCALE}\"" \ @@ -484,7 +468,6 @@ cat << __HEREDOC__ #define HAVE_GETLINE ${HAVE_GETLINE} #define HAVE_GETSUBOPT ${HAVE_GETSUBOPT} #define HAVE_ISBLANK ${HAVE_ISBLANK} -#define HAVE_LESS_T ${HAVE_LESS_T} #define HAVE_MKDTEMP ${HAVE_MKDTEMP} #define HAVE_MKSTEMPS ${HAVE_MKSTEMPS} #define HAVE_NTOHL ${HAVE_NTOHL} diff -upr mandoc-1.14.6.orig/main.c mandoc-1.14.6/main.c --- mandoc-1.14.6.orig/main.c 2023-07-02 19:38:31.011639507 +0200 +++ mandoc-1.14.6/main.c 2023-07-02 19:38:50.635019538 +0200 @@ -1271,6 +1271,44 @@ run_pager(struct outstate *outst, char * } } +static int +supports_tags(const char *pager, char *tagfile) +{ + int fd; + pid_t pid; + int wstatus; + + if (strcmp(pager, "less") != 0) + return 0; + + pid = fork(); + switch (pid) { + case -1: + err(1, "fork"); + case 0: + close(STDIN_FILENO); + fd = open("/dev/null", O_RDWR); + if (fd == -1) + err(1, "open"); + assert(fd == STDIN_FILENO); + + close(STDOUT_FILENO); + dup2(fd, STDOUT_FILENO); + close(STDERR_FILENO); + dup2(fd, STDERR_FILENO); + + /* If the pager doesn't support -T we expect a non-zero exit code */ + execlp(pager, pager, "-T", tagfile, "-", (char *)NULL); + exit(EXIT_FAILURE); + default: + if (waitpid(pid, &wstatus, 0) == -1) + err(1, "waitpid"); + break; + } + + return wstatus == EXIT_SUCCESS; +} + static pid_t spawn_pager(struct outstate *outst, char *tag_target) { @@ -1279,9 +1317,7 @@ spawn_pager(struct outstate *outst, char char *argv[MAX_PAGER_ARGS]; const char *pager; char *cp; -#if HAVE_LESS_T size_t cmdlen; -#endif int argc, use_ofn; pid_t pager_pid; @@ -1316,11 +1352,10 @@ spawn_pager(struct outstate *outst, char /* For less(1), use the tag file. */ use_ofn = 1; -#if HAVE_LESS_T if (*outst->tag_files->tfn != '\0' && (cmdlen = strlen(argv[0])) >= 4) { cp = argv[0] + cmdlen - 4; - if (strcmp(cp, "less") == 0) { + if (supports_tags(pager, outst->tag_files->tfn)) { argv[argc++] = mandoc_strdup("-T"); argv[argc++] = outst->tag_files->tfn; if (tag_target != NULL) { @@ -1330,7 +1365,7 @@ spawn_pager(struct outstate *outst, char } } } -#endif + if (use_ofn) { if (outst->outtype == OUTT_HTML && tag_target != NULL) mandoc_asprintf(&argv[argc], "file://%s#%s",