summaryrefslogtreecommitdiffstats
path: root/src/manpath.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/manpath.c')
-rw-r--r--src/manpath.c412
1 files changed, 412 insertions, 0 deletions
diff --git a/src/manpath.c b/src/manpath.c
new file mode 100644
index 0000000..90d520e
--- /dev/null
+++ b/src/manpath.c
@@ -0,0 +1,412 @@
+/*
+ * manpath.c
+ *
+ * Copyright (c) 1990, 1991, John W. Eaton.
+ *
+ * You may distribute under the terms of the GNU General Public
+ * License as specified in the file COPYING that comes with the man
+ * distribution.
+ *
+ * John W. Eaton
+ * jwe@che.utexas.edu
+ * Department of Chemical Engineering
+ * The University of Texas at Austin
+ * Austin, Texas 78712
+ *
+ * Changed PATH->manpath algorithm
+ * Added: an empty string in MANPATH denotes the system path
+ * Added: use LANG to search in /usr/man/<locale>
+ * Lots of other minor things, including spoiling the indentation.
+ * aeb - 940315
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+/* not always in <string.h> */
+extern char *index(const char *, int);
+extern char *rindex(const char *, int);
+
+#include "defs.h"
+#include "gripes.h"
+#include "man.h" /* for debug */
+#include "man-config.h" /* for cfdirlist */
+#include "man-getopt.h" /* for alt_system, opt_manpath */
+#include "manpath.h"
+#include "util.h" /* my_malloc, my_strdup */
+
+char **mandirlist;
+static int mandirlistlth = 0;
+static int mandirlistmax = 0;
+
+/*
+ * Input: a string, with : as separator
+ * For each entry in the string, call fn.
+ */
+static void
+split (char *string, void (*fn)(char *, int), int perrs) {
+ char *p, *q, *r;
+
+ if (string) {
+ p = my_strdup(string);
+ for (q = p; ; ) {
+ if ((r = index(q, ':'))==(char*)0)
+ r=index(q,'\01');
+ if (r) {
+ *r = 0;
+ fn (q, perrs);
+ q = r+1;
+ } else {
+ fn (q, perrs);
+ break;
+ }
+ }
+ free (p);
+ }
+}
+
+static void
+split2 (char *s, char *string, void (*fn)(char *, char *, int), int perrs) {
+ char *p, *q, *r;
+
+ if (string) {
+ p = my_strdup(string);
+ for (q = p; ; ) {
+ r = index(q, ':');
+ if (r) {
+ *r = 0;
+ fn (s, q, perrs);
+ q = r+1;
+ } else {
+ fn (s, q, perrs);
+ break;
+ }
+ }
+ free (p);
+ }
+}
+
+/*
+ * Is path a directory?
+ * -1: error, 0: no, 1: yes.
+ */
+static int
+is_directory (char *path) {
+ struct stat sb;
+
+ if (stat (path, &sb) != 0)
+ return -1;
+
+ return ((sb.st_mode & S_IFDIR) == S_IFDIR);
+}
+
+/*
+ * Check to see if the current directory has man or MAN
+ * or ../man or ../man1 or ../man8 subdirectories.
+ */
+static char *
+find_man_subdir (char *p) {
+ int len;
+ char *t, *sp;
+
+ len = strlen (p);
+
+ t = my_malloc ((unsigned) len + 20);
+
+ memcpy (t, p, len);
+ strcpy (t + len, "/man");
+
+ if (is_directory (t) == 1)
+ return t;
+
+ strcpy (t + len, "/MAN");
+
+ if (is_directory (t) == 1)
+ return t;
+
+ /* find parent directory */
+ t[len] = 0;
+ if ((sp = rindex (t, '/')) != NULL) {
+ *sp = 0;
+ len = sp - t;
+ } else {
+ strcpy (t + len, "/..");
+ len += 3;
+ }
+
+ /* look for the situation with packagedir/bin and packagedir/man */
+ strcpy (t + len, "/man");
+
+ if (is_directory (t) == 1)
+ return t;
+
+ /* look for the situation with pkg/bin and pkg/man1 or pkg/man8 */
+ /* (looking for all man[1-9] would probably be a waste of stats) */
+ strcpy (t + len, "/man1");
+
+ if (is_directory (t) == 1) {
+ t[len] = 0;
+ return t;
+ }
+
+ strcpy (t + len, "/man8");
+
+ if (is_directory (t) == 1) {
+ t[len] = 0;
+ return t;
+ }
+
+ free (t);
+ return NULL;
+}
+
+/*
+ * Add a directory to the manpath list if it isn't already there.
+ */
+static void
+add_to_list (char *dir, char *lang, int perrs) {
+ int status;
+ char cwd[BUFSIZ];
+ char **dp;
+
+ if (!lang)
+ lang = "";
+
+ /* only add absolute paths */
+ if (*dir != '/') {
+ if (!getcwd(cwd, sizeof(cwd)))
+ return; /* cwd not readable, or pathname very long */
+ if (cwd[0] != '/')
+ return; /* strange.. */
+ if (strlen(dir) + strlen(lang) + strlen(cwd) + 3 > sizeof(cwd))
+ return;
+ if (!strncmp (dir, "./", 2))
+ dir += 2;
+ while (!strncmp (dir, "../", 3)) {
+ char *p = rindex (cwd, '/');
+ if (p > cwd)
+ *p = 0;
+ else
+ cwd[1] = 0;
+ dir += 3;
+ }
+ strcat (cwd, "/");
+ strcat (cwd, dir);
+ if (*lang) {
+ strcat (cwd, "/");
+ strcat (cwd, lang);
+ }
+ dir = cwd;
+ } else if (*lang) {
+ if (strlen(dir) + strlen(lang) + 2 > sizeof(cwd))
+ return;
+ strcpy (cwd, dir);
+ strcat (cwd, "/");
+ strcat (cwd, lang);
+ dir = cwd;
+ }
+
+ if (mandirlist) {
+ for (dp = mandirlist; *dp; dp++) {
+ if (!strcmp (*dp, dir))
+ return;
+ }
+ }
+
+ /*
+ * Avoid trickery: no /../ in path.
+ */
+ if (strstr(dir, "/../"))
+ return;
+
+ /*
+ * Not found -- add it.
+ */
+ status = is_directory(dir);
+
+ if (status < 0 && perrs) {
+ gripe (CANNOT_STAT, dir);
+ } else if (status == 0 && perrs) {
+ gripe (IS_NO_DIR, dir);
+ } else if (status == 1) {
+ if (debug)
+ gripe (ADDING_TO_MANPATH, dir);
+
+ if (!mandirlist || mandirlistlth+1 >= mandirlistmax) {
+ int i, ct = mandirlistmax + 100;
+ char **p = (char **) my_malloc(ct * sizeof(char *));
+
+ if (mandirlist) {
+ for (i=0; i<mandirlistlth; i++)
+ p[i] = mandirlist[i];
+ free(mandirlist);
+ }
+ mandirlistmax = ct;
+ mandirlist = p;
+ }
+ mandirlist[mandirlistlth++] = my_strdup (dir);
+ mandirlist[mandirlistlth] = 0;
+ }
+}
+
+static void
+add_to_mandirlist_x (char *dir, char *lang, int perrs) {
+ add_to_list(dir, lang, perrs);
+ if (lang && strlen(lang) > 5 && lang[5] == '.') {
+ char lang2[6]; /* e.g. zh_CN from zh_CN.GB2312 */
+
+ strncpy(lang2,lang,5);
+ lang2[5] = 0;
+ add_to_list(dir, lang2, perrs);
+ }
+ if (lang && strlen(lang) > 2) {
+ char lang2[3];
+
+ strncpy(lang2,lang,2);
+ lang2[2] = 0;
+ add_to_list(dir, lang2, perrs);
+ }
+}
+
+static void
+add_to_mandirlist (char *dir, int perrs) {
+ char *lang;
+
+ if (alt_system) {
+ add_to_list(dir, alt_system_name, perrs);
+ } else {
+ /* We cannot use "lang = setlocale(LC_MESSAGES, NULL)" or so:
+ the return value of setlocale is an opaque string. */
+ /* POSIX prescribes the order: LC_ALL, LC_MESSAGES, LANG */
+ if((lang = getenv("LC_ALL")) != NULL)
+ split2(dir, lang, add_to_mandirlist_x, perrs);
+ if((lang = getenv("LC_MESSAGES")) != NULL)
+ split2(dir, lang, add_to_mandirlist_x, perrs);
+ if((lang = getenv("LANG")) != NULL)
+ split2(dir, lang, add_to_mandirlist_x, perrs);
+ if((lang = getenv("LANGUAGE")) != NULL)
+ split2(dir, lang, add_to_mandirlist_x, perrs);
+ add_to_mandirlist_x(dir, 0, perrs);
+ }
+}
+
+/*
+ * For each directory in the user's path, see if it is one of the
+ * directories listed in the man.conf file. If so, and it is
+ * not already in the manpath, add it. If the directory is not listed
+ * in the man.conf file, see if there is a subdirectory `man' or
+ * `MAN'. If so, and it is not already in the manpath, add it.
+ *
+ * Example: user has <dir>/bin in his path and the directory
+ * <dir>/bin/man exists -- the directory <dir>/bin/man will be added
+ * to the manpath.
+ * Try also <dir>/man ?and <dir>?, and, if LANG is set, <dir>/$LANG/man.
+ * aeb - 940320
+ */
+static void
+get_manpath_from_pathdir (char *dir, int perrs) {
+ char *t;
+ struct dirs *dlp;
+
+ if (debug)
+ gripe (PATH_DIR, dir);
+
+ /*
+ * The directory we're working on is in the config file.
+ * If we haven't added it to the list yet, do.
+ */
+ if (*dir) {
+ for (dlp = cfdirlist.nxt; dlp; dlp = dlp->nxt) {
+ if (!strcmp (dir, dlp->bindir)) {
+ if (debug)
+ gripe (IS_IN_CONFIG);
+
+ add_to_mandirlist (dlp->mandir, perrs);
+ return;
+ }
+ }
+ }
+
+ if (!noautopath) {
+ /*
+ * The directory we're working on isn't in the config file.
+ * See if it has man or MAN subdirectories. If so, and this
+ * subdirectory hasn't been added to the list, do. (Try also
+ * a few other places nearby.)
+ */
+ if (debug)
+ gripe (IS_NOT_IN_CONFIG);
+
+ t = find_man_subdir (dir);
+ if (t != NULL) {
+ if (debug)
+ gripe (MAN_NEARBY);
+
+ add_to_mandirlist (t, perrs);
+ free (t);
+ } else {
+ if (debug)
+ gripe (NO_MAN_NEARBY);
+ }
+ }
+}
+
+static void
+add_default_manpath (int perrs) {
+ struct dirs *dlp;
+
+ if (debug)
+ gripe (ADDING_MANDIRS);
+
+ for (dlp = cfdirlist.nxt; dlp; dlp = dlp->nxt)
+ if (dlp->mandatory)
+ add_to_mandirlist (dlp->mandir, perrs);
+}
+
+static void
+to_mandirlist(char *s, int perrs) {
+ char *path;
+
+ if (*s) {
+ add_to_mandirlist (s, perrs);
+ } else {
+ /* empty substring: insert default path */
+ if((path = getenv ("PATH")) != NULL)
+ split (path, get_manpath_from_pathdir, perrs);
+ add_default_manpath (perrs);
+ }
+}
+
+void
+init_manpath () {
+ static int done = 0;
+
+ if (!done) {
+ char *manp;
+
+ if ((manp = opt_manpath) == NULL &&
+ (manp = getenv ("manpath")) == NULL &&
+ (manp = getenv ("MANPATH")) == NULL)
+ manp = ""; /* default path */
+ split (manp, to_mandirlist, 0);
+ done = 1;
+ }
+}
+
+void
+prmanpath () {
+ char **dp, **dp0;
+
+ if (mandirlist) {
+ for (dp0 = dp = mandirlist; *dp; dp++) {
+ if (dp != dp0)
+ printf(":");
+ printf("%s", *dp);
+ }
+ }
+ printf("\n");
+}