diff options
Diffstat (limited to 'librarian/rarian-man.c')
-rw-r--r-- | librarian/rarian-man.c | 617 |
1 files changed, 617 insertions, 0 deletions
diff --git a/librarian/rarian-man.c b/librarian/rarian-man.c new file mode 100644 index 0000000..9ad9c1b --- /dev/null +++ b/librarian/rarian-man.c @@ -0,0 +1,617 @@ +/* + * rarian-man.c + * This file is part of Rarian + * + * Copyright (C) 2007 - Don Scorgie + * + * Rarian is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * Rarian is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <dirent.h> +#include <string.h> +#include <sys/stat.h> +#include "rarian-man.h" +#include "rarian-language.h" +#include "rarian-utils.h" + +/*#ifdef HAVE_LIBGDBM +#include <gdbm.h> +static GDBM_FILE *gdbm_handle; +#endif + +#ifdef HAVE_LIBNDBM +#include <ndbm.h> +static DBM *ndbm_handle; +#endif*/ + +typedef struct _ManLink ManLink; + +struct _ManLink +{ + RrnManEntry *reg; + ManLink *next; + ManLink *prev; +}; + +static char *keys[43] = {"1", "1p", "1g", "1t", "1x", "1ssl", "1m", + "2", + "3", "3o", "3t", "3p", "3blt", "3nas", "3form", "3menu", "3tiff", "3ssl", "3readline", + "3ncurses", "3curses", "3f", "3pm", "3perl", "3qt", "3x", "3X11", + "4", "4x", + "5", "5snmp", "5x", "5ssl", + "6", "6x", + "7", "7gcc", "7x", "7ssl", + "8", "8l", "9", "0p" +}; + +static ManLink *manhead[44]; +static ManLink *mantail[44]; + +static char *avail_dirs[] = { + "man0p", "man1", "man1p", "man2", "man3", + "man3p", "man4", "man5", "man6", "man7", + "man8", "man9", "mann", + NULL + }; + +static char **man_paths = NULL; + +int initialised = FALSE; +int mode = -1; +/* Modes: 0 = default + * 1 = gdbm + * 2 = ndbm + */ + +static void +setup_man_path () +{ + int outfd[2]; + int infd[2]; + + int oldstdin, oldstdout; + fflush(stdin); + fflush(stdout); + fflush(stderr); + + pipe(outfd); // Where the parent is going to write to + pipe(infd); // From where parent is going to read + + oldstdin = dup(0); // Save current stdin + oldstdout = dup(1); // Save stdout + + close(0); + close(1); + + dup2(outfd[0], 0); // Make the read end of outfd pipe as stdin + dup2(infd[1],1); // Make the write end of infd as stdout + + if(!fork()) { + /* Child process */ + char *argv[]={"manpath"}; + close(outfd[0]); // Not required for the child + close(outfd[1]); + close(infd[0]); + close(infd[1]); + execlp("manpath", "manpath", (char *) 0); + exit (0); + } else { + /* Parent process */ + char *input = NULL; + char *colon = NULL; + char *next = NULL; + int i, count = 0; + input = malloc(sizeof(char) * 256); + close(0); // Restore the original std fds of parent + close(1); + dup2(oldstdin, 0); + dup2(oldstdout, 1); + + close(outfd[0]); // These are being used by the child + close(infd[1]); + memset(input, 0, sizeof(char)*255); + + input[read(infd[0],input,255)] = 0; // Read from child's stdout + if (*input != '\0') { + int i; + i = strlen(input); + input[i-1]='\0'; + } + if (!input || *input == '\0') { + char *env = NULL; + env = getenv("MANPATH"); + if (env) + input = strdup(env); + } + if (!input || *input == '\0') { + if (input) + free(input); + /* Hard coded default. Don't argue. */ + input = strdup ("/usr/share/man:/usr/man:/usr/local/share/man:/usr/local/man"); + } + colon = input; + + while (*colon) { + if (*colon == ':') + count++; + colon++; + } + man_paths = malloc (sizeof(char *) * (count+2)); /* 2 is for final string + * + NULL entry */ + colon = input; + for (i=0; i< count; i++) { + next = strchr (colon, ':'); + man_paths[i] = rrn_strndup(colon, next-colon); + colon = next; + colon++; + } + /* Final 2 entries - straight strdup of final entry and NULL */ + man_paths[i] = strdup(colon); + i++; + man_paths[i] = NULL; + free (input); + } + +} +#if 0 +#ifdef HAVE_LIBGDBM +static void +setup_gdbm (char *name) +{ + gdbm_handle = gdbm_open(name, 0, GDBM_READER, 0666, 0); + if (!gdbm_handle) { + sprintf(stderr, "ERROR: GDBM index %s could not be opened. Falling back\n", name); + setup_default(); + } else { + initialised = TRUE; + mode = 1; + } +} +#endif + +#ifdef HAVE_LIBNDBM +static void +setup_ndbm (char *name) +{ + char *trunc; + + trunc = malloc (sizeof(char) * (strlen(name)-3)); + trunc = rrn_strndup (name, strlen(name) - 4); + ndbm_handle = dbm_open(trunc, O_RDONLY, 0666); + if (!ndbm_handle) { + sprintf(stderr, "ERROR: NDBM index %s could not be opened. Falling back\n", trunc); + setup_default(); + } else { + initialise = TRUE; + mode = 2; + } + free (trunc); +} +#endif +#endif + +static char *strrstr (char *s, char *wanted) +{ + char *scan; + char *first; + int len; + + first = wanted; + len = strlen(wanted); + for (scan = s + strlen(s) - len ; scan >= s ; scan--) + { + if (*scan == *first) + { + if (!strncmp (scan, wanted, len)) + { + return (scan); + } + } + } + return(NULL); +} + + + +static char * +get_name_for_file (char *filename, char **subsect) +{ + char *suffix; + char *cut; + char *sect; + char *final; + + /* We assume, like reasonable people, that man pages + * have one of the forms: + * manname.sect.{gz,bz,bz2,lzma} + * manname.sect + * If it doesn't, things will probably break but we return + * our "best guess" (i.e. everything up to the suffix) + */ + suffix = strrstr(filename, ".gz"); + if (!suffix) { + suffix = strrstr(filename, ".bz2"); + if (!suffix) { + suffix = strrstr(filename, ".bz"); + } + if (!suffix) { + suffix = strrstr(filename, ".lzma"); + } + } + if (suffix) + cut = rrn_strndup (filename, suffix-filename); + else + cut = strdup (filename); + sect = strrchr (cut, '.'); + if (!sect) + return cut; + + final = rrn_strndup (cut, sect-cut); + sect++; + *subsect = strdup (sect); + free (cut); + return final; + +} + +static int +check_for_dup (RrnManEntry *reg, int entry) +{ + ManLink *iter = manhead[entry]; + + while (iter) { + if (!strcmp(reg->name, iter->reg->name)) + return TRUE; + iter = iter->next; + + } + return FALSE; +} + +static int +find_key (char *sect) +{ + int i; + for (i=0; i<43; i++){ + if (!strcmp (sect, keys[i])) + return i; + } + return i; +} + +static void +process_dir(char *dir) +{ + char **dir_iter; + char *path = NULL; + + DIR * dirp = NULL; + struct dirent * dp = NULL; + struct stat buf; + int current; + + current = -1; + path = malloc(sizeof(char) * (strlen(dir) + 8)); + + dir_iter = avail_dirs; + while (dir_iter && *dir_iter) { + current++; + sprintf(path, "%s/%s", dir, *dir_iter); + if (access (path, R_OK)) { + dir_iter++; + continue; + } + + dirp = opendir (path); + + if (!dirp) { + dir_iter++; + continue; + } + + while (1) { + if ((dp = readdir(dirp)) != NULL) { + char *full_name; + + full_name = malloc (sizeof(char) * (strlen(dp->d_name) + strlen (path) + 3)); + sprintf (full_name, "%s/%s", path, dp->d_name); + + stat(full_name,&buf); + if (S_ISREG(buf.st_mode) || buf.st_mode & S_IFLNK) { + char *tmp = NULL; + char *suffix = NULL; + RrnManEntry *entry; + ManLink *link; + char *subsect = NULL; + + entry = malloc (sizeof(RrnManEntry)); + entry->name = get_name_for_file (dp->d_name, &subsect); + entry->path = full_name; + if (subsect) { + entry->section = subsect; + entry->comment = NULL; + current = find_key(subsect); + if (!check_for_dup (entry, current)) { + link = malloc (sizeof(ManLink)); + link->reg = entry; + + if (mantail[current]) { + mantail[current]->next = link; + link->next = NULL; + link->prev = mantail[current]; + mantail[current] = link; + } else { + manhead[current] = mantail[current] = link; + link->prev = link->next = NULL; + } + } else { + free (entry->name); + free (entry->path); + free (entry->section); + if (entry->comment) + free (entry->comment); + free (entry); + } + } + } + } else { + closedir (dirp); + break; + } + } + dir_iter++; + } + free (path); +} + +static void +setup_default() +{ + char **path_iter; + char **langs; + char **lang_iter; + + path_iter = man_paths; + langs = rrn_language_get_langs(); + + while (path_iter && *path_iter) { + if (access (*path_iter, R_OK)) { + path_iter++; + continue; + } + + lang_iter = langs; + while (lang_iter && *lang_iter) { + char *path; + path = malloc (sizeof(char) * (strlen(*path_iter) + + strlen(*lang_iter)+2)); + sprintf (path, "%s/%s", *path_iter, *lang_iter); + if (!access (path, R_OK)) { + process_dir(path); + } + free (path); + lang_iter++; + } + + + process_dir(*path_iter); + path_iter++; + } + + /*lang_iter = langs; + while (lang_iter && *lang_iter) { + char **next = lang_iter; + next++; + free (lang_iter); + lang_iter = next; + }*/ + free (langs); +} + +static void +rrn_man_init (void) +{ + char *default_dirs = "/var/cache/man:/usr/man"; + char *split = NULL; +#if 0 + char *gdbm_index = "index.db"; + char *ndbm_index = "index.dir"; +#endif + int i; + int npaths = 0; + char *ddirs; + + for (i=0; i<44; i++) { + manhead[i] = mantail[i] = NULL; + } + + setup_man_path (); + + split = default_dirs; + +#if 0 + while (split) { + char *next = strchr(split, ':'); + char *dirname = NULL; + char *index = NULL; + FILE *access = NULL; + + if (next) + dirname = rrn_strndup(split, (next-split)); + else + dirname = strdup (split); +#ifdef HAVE_LIBGDBM + index = malloc (sizeof(char) * (strlen(dirname) + 10 /*Len of gdbm_index + additional chars*/)); + sprintf (index, "%s/%s", dirname, gdbm_index); + access = fopen(index, "r"); + free(dirname); + if (access) { + fclose(access); + setup_gdbm(index); + free(index); + return; + } +#endif +#ifdef HAVE_NDBM + index = malloc (sizeof(char) * (strlen(dirname) + 11 /*Len of ndbm_index + additional chars*/)); + sprintf (index, "%s/%s", dirname, gdbm_index); + access = fopen(index, "r"); + free(dirname); + if (access) { + fclose(access); + setup_ndbm(index); + free(index); + return; + } +#endif + split = strchr(split, ':'); + if (split) + split++; + } +#endif /* 0 */ + /* If we get here, we have to do our own thang */ + setup_default(); + initialised = TRUE; + +} + +void +rrn_man_for_each (RrnManForeachFunc funct, void * user_data) +{ + ManLink *iter; + int i; + + if (!initialised) + rrn_man_init(); + + for (i=0; i<44; i++) { + iter = manhead[i]; + + while (iter) { + int res; + res = funct (iter->reg, user_data); + if (res == FALSE) + break; + iter = iter->next; + } + } + return; +} + + +void +rrn_man_for_each_in_category (char *category, + RrnManForeachFunc funct, + void * user_data) +{ + ManLink *iter; + int cat; + + if (!initialised) + rrn_man_init(); + + cat = find_key(category); + iter = manhead[cat]; + + while (iter) { + int res; + if (!strcmp (iter->reg->section, category)) { + res = funct (iter->reg, user_data); + if (res == FALSE) + break; + } + iter = iter->next; + } + return; +} + +RrnManEntry * +rrn_man_find_from_name (char *name, char *sect) +{ + ManLink *iter; + int cat; + RrnManEntry *res; + + if (!initialised) + rrn_man_init (); + + if (sect) { + cat = find_key(sect); + } else { + int i=0; + for (i=0; i<43; i++) { + iter = manhead[i]; + + while (iter) { + if (!strcmp (iter->reg->name, name)) { + return iter->reg; + } + iter = iter->next; + } + } + return NULL; + } + iter = manhead[cat]; + + while (iter) { + if (!strcmp (iter->reg->name, name)) { + return iter->reg; + } + iter = iter->next; + } + + + return NULL; +} + +char ** +rrn_man_get_categories (void) +{ + if (!initialised) + rrn_man_init(); + + return keys; +} + + +void +rrn_man_shutdown () +{ + ManLink *iter; + int i; + initialised = FALSE; + + for (i=0; i< 44; i++) { + iter = manhead[i]; + while (iter) { + ManLink *tmp = iter->next; + free (iter->reg->name); + free (iter->reg->path); + free (iter->reg->section); + if (iter->reg->comment) + free (iter->reg->comment); + free (iter->reg); + free (iter); + iter = tmp; + } + manhead[i] = mantail[i] = NULL; + } + rrn_language_shutdown (); + return; +} |