#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef __APPLE__
#include <stdbool.h>
#include <xcselect.h>
#endif
extern char *index(const char *, int);
extern char *rindex(const char *, int);
#include "defs.h"
#include "gripes.h"
#include "man.h"
#include "man-config.h"
#include "man-getopt.h"
#include "manpath.h"
#include "util.h"
char **mandirlist;
static int mandirlistlth = 0;
static int mandirlistmax = 0;
static void
split (char *string, void (*fn)(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 (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);
}
}
static int
is_directory (char *path) {
struct stat sb;
if (stat (path, &sb) != 0)
return -1;
return ((sb.st_mode & S_IFDIR) == S_IFDIR);
}
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;
t[len] = 0;
if ((sp = rindex (t, '/')) != NULL) {
*sp = 0;
len = sp - t;
} else {
strcpy (t + len, "/..");
len += 3;
}
#if defined(__APPLE__)
strcpy (t + len, "/share/man");
if (is_directory (t) == 1)
return t;
#endif
strcpy (t + len, "/man");
if (is_directory (t) == 1)
return t;
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;
}
static void
add_to_list (char *dir, char *lang, int perrs) {
int status;
char cwd[BUFSIZ];
char **dp;
if (!lang)
lang = "";
if (*dir != '/') {
if (!getcwd(cwd, sizeof(cwd)))
return;
if (cwd[0] != '/')
return;
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;
}
}
if (strstr(dir, "/../"))
return;
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[6] == '.') {
char lang2[6];
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 {
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);
}
}
static void
get_manpath_from_pathdir (char *dir, int perrs) {
char *t;
struct dirs *dlp;
if (debug)
gripe (PATH_DIR, dir);
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) {
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);
#ifdef __APPLE__
xcselect_manpaths *xcp;
const char *path;
unsigned i, count;
xcp = xcselect_get_manpaths(NULL);
if (xcp != NULL) {
count = xcselect_manpaths_get_num_paths(xcp);
for (i = 0; i < count; i++) {
path = xcselect_manpaths_get_path(xcp, i);
if (path != NULL) {
add_to_mandirlist((char *)path, perrs);
}
}
xcselect_manpaths_free(xcp);
}
#endif
}
static void
to_mandirlist(char *s, int perrs) {
char *path;
if (*s) {
add_to_mandirlist (s, perrs);
} else {
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 = "";
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");
}