/* * 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/ * Lots of other minor things, including spoiling the indentation. * aeb - 940315 */ #include #include #include #include #include #include /* not always in */ 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 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 /bin in his path and the directory * /bin/man exists -- the directory /bin/man will be added * to the manpath. * Try also /man ?and ?, and, if LANG is set, /$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"); }