## root/htags-refkit/htags_path2url.c(247.html)

/* [<][>][^][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] */