diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2014-09-13 09:43:21 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2014-09-13 09:43:21 -0700 |
commit | 5280f9a0cd1f9ba200422ebba65d1e0133410995 (patch) | |
tree | bf85ce4e320a769d7e0903ff52ccfde13a422666 /src/manpath.c | |
download | man-5280f9a0cd1f9ba200422ebba65d1e0133410995.tar.gz man-5280f9a0cd1f9ba200422ebba65d1e0133410995.tar.bz2 man-5280f9a0cd1f9ba200422ebba65d1e0133410995.zip |
Initial.man-1.6g
Diffstat (limited to 'src/manpath.c')
-rw-r--r-- | src/manpath.c | 412 |
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"); +} |