root/htags-refkit/htags_path2url.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. load_filemap_contents
  2. cmp
  3. create_filemap_index
  4. unload_filemap
  5. htags_load_filemap
  6. htags_unload_filemap
  7. htags_path2url
  8. main

/*
 * Htags Hyper-text Reference Kit.
 *
 * This file is placed into the public domain by the author,
 * 2005, 2006 Tama Communications Corporation.
 *
 * Two library function, qsort(3) and bsearch(3), are required.
 */
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/param.h>
#include <sys/stat.h>

#if defined(_WIN32) || defined(__DJGPP__)
# define OPENMODE O_BINARY
#else
# define OPENMODE 0
#endif

int htags_load_filemap(const char *);
void htags_unload_filemap(void);
int htags_path2url(const char *, int, char *, int);

/*
 * Usage by example.
 *
 * Getting the URL of "i386/i386/identcpu.c" at 120, in variable url.
 *
 *      char url[MAXPATHLEN+1];
 *      -- Load filemap generated by htags(1).
 *      ret = htags_load_filemap("HTML/FILEMAP");
 *      if (ret != 0)
 *              ERROR;
 *      -- Get URL of the specified file name and line number.
 *      ret = htags_path2url("i386/i386/identcpu.c", 120, url, sizeof(url));
 *      if (ret != 0)
 *              ERROR;
 *      url == 'S/1238.html#L120'
 *      -- release resource
 *      htags_unload_filemap();
 *
 * Since the URL is a relative path from the HTML directory, you should
 * modify it so that your application program works well.
 */
/*
 * in memory FILEMAP
 *
 * Alphabetical sorted table.
 */
struct map
{
        const char *name;
        const char *path;
};
/*
 * Global variables.
 *
 * These variables are set by htags_load_filemap(), and referred by
 * htags_path2url() and htags_unload_filemap().
 */
static char *global_contents;           /* filemap contents             */
static struct map *global_map;          /* file -> url mapping table    */
static int global_maplines;             /* the lines of global_map      */

/*----------------------------------------------------------------------*/
/* Local functions                                                      */
/*----------------------------------------------------------------------*/
/*
 * load contents of FILEMAP into the memory.
 *
 *      i)      file    path of FILEMAP
 *      o)      area    file contents (malloced)
 *      o)      size    size of area
 *      r)      0 succesful
 *              -1: out of memory.
 *              -2: FILEMAP not found.
 *              -3: cannot fstat FILEMAP.
 *              -4: cannot read FILEMAP.
 */
static int
load_filemap_contents(const char *file, char **area, int *size)
{
        struct stat st;
        char *p = NULL;
        int status = 0;
        int fd = -1;

        /* Load FILEMAP contents */
        status = -2;
        if ((fd = open(file, OPENMODE)) < 0)
                goto err;
        status = -3;
        if (fstat(fd, &st) < 0)
                goto err;
        status = -1;
        if ((p = (char *)malloc(st.st_size)) == NULL)
                goto err;
        status = -4;
        if (read(fd, p, st.st_size) != st.st_size)
                goto err;
        close(fd);
        *area = p;
        *size = st.st_size;
        return 0;
err:
        if (fd != -1)
                close(fd);
        if (p != NULL)
                free(p);
        return status;
}

/*
 * comparison function for bsearch().
 */
static int
cmp(const void *s1, const void *s2)
{
        return strcmp(((struct map *)s1)->name, ((struct map *)s2)->name);
}
/*
 * creates index for in core FILEMAP.
 *
 *      i)      area    filemap contents
 *      i)      size    size of area
 *      o)      map     map structure
 *      o)      lines   map lines
 *      r)       0: succesful
 *              -1: out of memory.
 *              -5: illegal format.
 */
static int
create_filemap_index(char *area, int size, struct map **map, int *lines)
{
        char *p, *endp = area + size;
        struct map *m;
        int n = 0;
        int status;
        int i;

        /* Count line number */
        for (p = area; p < endp; p++)
                if (*p == '\n')
                        n++; 
        status = -1;
        if ((m = (struct map *)malloc(sizeof(struct map) * n)) == NULL)
                return -1;
        /*
         * FILEMAP format:
         * <NAME>\t<PATH>\n
         */
        p = area;
        for (i = 0; i < n; i++) {
                m[i].name = p;
                while (*p && *p != '\t')
                        p++;
                if (*p == '\0')
                        goto ferr;
                *p++ = '\0';
                m[i].path = p;
                while (*p && *p != '\r' && *p != '\n')
                        p++;
                if (*p == '\0')
                        goto ferr;
                if (*p == '\r')
                        *p++ = '\0';
                if (*p == '\n')
                        *p++ = '\0';
        }
        qsort(m, n, sizeof(struct map), cmp);
        *map = m;
        *lines = n;
        return 0;
ferr:
        free(m);
        return -5;
}

/*
 * unloads FILEMAP.
 */
static void
unload_filemap(void)
{
        (void)free(global_map);
        global_map = NULL;
        (void)free(global_contents);
        global_contents = NULL;
}
/*----------------------------------------------------------------------*/
/* Global functions                                                     */
/*----------------------------------------------------------------------*/
/*
 * loads FILEMAP.
 *
 *      i)      filemap FILEMAP file
 *      go)     global_contents filemap contents (for free)
 *      go)     global_map      filemap index.
 *      go)     global_maplines lines of filemap index.
 *      r)               0: succesful
 *                      -1: out of memory.
 *                      -2: FILEMAP not found.
 *                      -3: cannot fstat FILEMAP.
 *                      -4: cannot read FILEMAP.
 *                      -5: format error.
 */
int
htags_load_filemap(const char *filemap)
{
        int status = 0;
        char *area;
        int size, lines;
        struct map *map;

        status = load_filemap_contents(filemap, &area, &size);
        if (status < 0)
                return status;
        status = create_filemap_index(area, size, &map, &lines);
        if (status < 0) {
                (void)free(area);
                return status;
        }
        global_contents = area;
        global_map = map;
        global_maplines = lines;
        return 0;
}
/*
 * unloads FILEMAP.
 */
void
htags_unload_filemap(void)
{
        unload_filemap();
}

/*
 * convert file path name into the URL in the hypertext.
 *
 *      i)      path    path name in the filesystem.
 *      i)      line    0: ignored, !=0: line number in path.
 *      o)      url     result url
 *      i)      size    size of url
 *      gi)     global_contents filemap contents (for free)
 *      gi)     global_map      filemap index.
 *      gi)     global_maplines lines of filemap index.
 *      r)              0: succesful
 *                      1: path not found
 *                      -1: filemap not loaded yet
 *
 * URL: S/<file id>.html#<line number>
 */
int
htags_path2url(const char *path, int line, char *url, int size)
{
        struct map tmp;
        struct map *result;

        if (global_contents == NULL || global_map == NULL)
                return -1;
        tmp.name = path;
        result = (struct map *)bsearch(&tmp, global_map, global_maplines, sizeof(struct map), cmp);
        if (result == NULL)
                return 1;
        if (line > 0)
                snprintf(url, size, "%s#L%d", result->path, line);
        else
                snprintf(url, size, "%s", result->path);
        return 0;
}

#ifdef TEST

/*
 * Usage: htags_path2url filemap path [line]
 *
 * $ htags_path2url HTML/FILEMAP i386/i386/identcpu.c 120
 * i386/i386/identcpu.c, line 120 => S/1238.html#L120
 * $ _
 */
int
main(int argc, char **argv)
{
        char url[MAXPATHLEN];
        char *path, *html;
        int line = 0;
        int ret;

        if (argc < 3) {
                fprintf(stderr, "Usage: htags_path2url filemap path [line]\n");
                exit(1);
        }
        html = argv[1];
        path = argv[2];
        if (argc > 3)
                line = atoi(argv[3]);
        ret = htags_load_filemap(html);
        if (ret != 0) {
                fprintf(stderr, "htags_load_filemap failed.(");
                switch (ret) {
                case -1: fprintf(stderr, "out of memory"); break;
                case -2: fprintf(stderr, "FILEMAP not found."); break;
                case -3: fprintf(stderr, "cannot fstat FILEMAP."); break;
                case -4: fprintf(stderr, "cannot read FILEMAP."); break;
                case -5: fprintf(stderr, "format error."); break;
                default: fprintf(stderr, "unknown error."); break;
                }
                fprintf(stderr, ")\n");
                exit(1);
        }
        ret = htags_path2url(path, line, url, sizeof(url));
        if (ret != 0) {
                fprintf(stderr, "htags_path2url failed.(");
                switch (ret) {
                case  1: fprintf(stderr, "path not found."); break;
                case -1: fprintf(stderr, "out of memory."); break;
                }
                fprintf(stderr, ")\n");
                exit(1);
        }
        fprintf(stdout, "%s, line %d => %s\n", path, line, url);
        htags_unload_filemap();
        return 0;
}
#endif

/* [<][>][^][v][top][bottom][index][help] */