man-db-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Man-db-devel] [PATCH v4] Add fallback pager if the compile time default


From: nsajko
Subject: [Man-db-devel] [PATCH v4] Add fallback pager if the compile time default is not executable
Date: Sun, 24 Dec 2017 04:09:02 -0800 (PST)

>A problem with man-db's man is that in the case of the user giving no
>configuration via conf files, argv, or environment variables; man
>defaults to less as pager (PAGER); but less may not be present on the
>system. Sure, other pagers may be selected in aforementioned ways, but
>then the defaults are overrided, making that unsuitable for
>install-time configuration.
>
>This patch makes man check (if that becomes relevant) if PAGER is
>executable, further defaulting to cat (which is basically ubiquitous,
>being in original Unix, POSIX, and GNU Coreutils) if it is not. Thus
>the poor beginner Unix users without less installed will  be able to
>get man pages.
>
>Regards,
>Neven

The same thing, but without using sh.

And also a documentation update.

In version 4 of the patch a memory leak is plugged.

diff --git a/man/man1/man.man1 b/man/man1/man.man1
index 4df2823f..23a059e0 100644
--- a/man/man1/man.man1
+++ b/man/man1/man.man1
@@ -874,7 +874,12 @@ Specify which output pager to use.
 By default,
 .B %man%
 uses
-.BR "%pager%" .
+.BR "%pager%" ,
+further falling back to
+.BR "%cat%"
+in case
+.BR "%pager%"
+is not found or is not executable.
 This option overrides the
 .RB $ MANPAGER
 environment variable, which in turn overrides the
@@ -1240,7 +1245,11 @@ is used in preference), its value is used as the name of 
the program used to
 display the manual page.
 By default,
 .B %pager%
-is used.
+is used, with a further fallback to
+.B %cat%
+if
+.B %pager%
+were not to be found.

 The value may be a simple command name or a command with arguments, and may
 use shell quoting (backslashes, single quotes, or double quotes).
diff --git a/src/man.c b/src/man.c
index 6bc9642c..83cd511a 100644
--- a/src/man.c
+++ b/src/man.c
@@ -4020,6 +4020,84 @@ static const char **get_section_list (void)
        }
 }

+static void append_char(char *a, int *i, char c)
+{
+       a[*i] = c;
+       (*i)++;
+}
+
+// Returns the first token of a libpipeline/sh-style command. See SUSv4TC2:
+// 2.2 Shell Command Language: Quoting, but restrict to \'" as special symbols.
+//
+// Free the returned value.
+//
+// Examples:
+// sh_lang_first_word ("echo 3") returns "echo"
+// sh_lang_first_word ("'e ho' 3") returns "e ho"
+// sh_lang_first_word ("e\\cho 3") returns "echo"
+// sh_lang_first_word ("e\\\ncho 3") returns "echo"
+// sh_lang_first_word ("\"echo t\" 3") returns "echo t"
+// sh_lang_first_word ("\"ech\\o t\" 3") returns "ech\\o t"
+// sh_lang_first_word ("\"ech\\\\o t\" 3") returns "ech\\o t"
+// sh_lang_first_word ("\"ech\\\no t\" 3") returns "echo t"
+static char *sh_lang_first_word(const char *cmd)
+{
+       int i = 0, o = 0;
+       char *r = xmalloc (strlen (cmd) + 1);
+
+       while (i < strlen (cmd)) {
+               if (cmd[i] == '\\') {
+                       // Escape Character (Backslash)
+                       i++;
+                       if (i == strlen (cmd)) {
+                               break;
+                       }
+                       if (cmd[i] != '\n') {
+                               append_char (r, &o, cmd[i]);
+                       }
+               } else if (cmd[i] == '\'') {
+                       // Single-Quotes
+                       i++;
+                       while (i < strlen (cmd) && cmd[i] != '\'') {
+                               append_char (r, &o, cmd[i]);
+                               i++;
+                       }
+               } else if (cmd[i] == '"') {
+                       // Double-Quotes
+                       i++;
+                       while (i < strlen (cmd)) {
+                               if (cmd[i] == '\\') {
+                                       if (cmd[i+1] == '"' ||
+                                           cmd[i+1] == '\\') {
+                                               i++;
+                                               append_char (r, &o, cmd[i]);
+                                       } else if (cmd[i+1] == '\n') {
+                                               i++;
+                                       } else {
+                                               append_char (r, &o, cmd[i]);
+                                       }
+                               } else if (cmd[i] == '"') {
+                                       break;
+                               } else {
+                                       append_char (r, &o, cmd[i]);
+                               }
+
+                               i++;
+                       }
+               } else if (cmd[i] == '\t' || cmd[i] == ' ' || cmd[i] == '\n') {
+                       break;
+               } else {
+                       append_char (r, &o, cmd[i]);
+               }
+
+               i++;
+       }
+
+       append_char (r, &o, '\0');
+
+       return r;
+}
+
 int main (int argc, char *argv[])
 {
        int argc_env, exit_status = OK;
@@ -4115,13 +4193,24 @@ int main (int argc, char *argv[])
        if (htmlout)
                pager = html_pager;
 #endif /* TROFF_IS_GROFF */
+
        if (pager == NULL) {
                pager = getenv ("MANPAGER");
-               if (pager == NULL) {
-                       pager = getenv ("PAGER");
-                       if (pager == NULL)
-                               pager = get_def_user ("pager", PAGER);
+       }
+       if (pager == NULL) {
+               pager = getenv ("PAGER");
+       }
+       if (pager == NULL) {
+               pager = get_def_user ("pager", NULL);
+       }
+       if (pager == NULL) {
+               char *t = sh_lang_first_word (PAGER);
+               if (pathsearch_executable (t)) {
+                       pager = PAGER;
+               } else {
+                       pager = "";
                }
+               free (t);
        }
        if (*pager == '\0')
                pager = get_def_user ("cat", CAT);

reply via email to

[Prev in Thread] Current Thread [Next in Thread]