root/gozilla/gozilla.c

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

DEFINITIONS

This source file includes following definitions.
  1. usage
  2. help
  3. load_alias
  4. alias
  5. locate_HTMLdir
  6. main
  7. getdefinitionURL
  8. getURL
  9. isprotocol
  10. convertpath
  11. makefileurl
  12. show_page_by_url
  13. show_page_by_url
  14. show_page_by_url

/*
 * Copyright (c) 1997, 1998, 1999, 2000, 2002, 2003, 2004, 2006
 *      Tama Communications Corporation
 *
 * This file is part of GNU GLOBAL.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program 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 General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <shellapi.h>
/*
 * Don't remove the following code which seems meaningless.
 * Since WIN32 has another SLIST_ENTRY, we removed the definition
 * so as not to cause the conflict.
 */
#ifdef SLIST_ENTRY
#undef SLIST_ENTRY
#endif
#endif

#include "global.h"
#include "regex.h"
#include "const.h"

static void usage(void);
static void help(void);

const char *gozillarc = ".gozillarc";
#ifdef __DJGPP__
const char *dos_gozillarc = "_gozillarc";
#endif
STRHASH *sh;

static void load_alias(void);
static const char *alias(const char *);
int main(int, char **);
void getdefinitionURL(const char *, STRBUF *);
void getURL(const char *, STRBUF *);
int isprotocol(const char *);
int convertpath(const char *, const char *, const char *, STRBUF *);
void makefileurl(const char *, int, STRBUF *);
void show_page_by_url(const char *, const char *);
#ifndef isblank
#define isblank(c)      ((c) == ' ' || (c) == '\t')
#endif

char cwd[MAXPATHLEN+1];
char root[MAXPATHLEN+1];
char dbpath[MAXPATHLEN+1];

int bflag;
int pflag;
int qflag;
int Cflag;
int vflag;
int show_version;
int linenumber = 0;
int debug;

static void
usage(void)
{
        if (!qflag)
                fputs(usage_const, stderr);
        exit(2);
}
static void
help(void)
{
        fputs(usage_const, stdout);
        fputs(help_const, stdout);
        exit(0);
}

/*
 * load_alias: load alias value.
 *
 * [$HOME/.gozillarc]
 * +-----------------------
 * |a:http://www.gnu.org
 * |f = file:/usr/share/xxx.html
 * |www http://www.xxx.yyy/
 */
static void
load_alias(void)
{
        FILE *ip;
        STRBUF *sb = strbuf_open(0);
        char *p;
        int flag = STRBUF_NOCRLF;
        struct sh_entry *ent;

        sh = strhash_open(10);
        if (!(p = get_home_directory()))
                goto end;
        if (!test("r", makepath(p, gozillarc, NULL)))
#ifdef __DJGPP__
                if (!test("r", makepath(p, dos_gozillarc, NULL)))
#endif
                        goto end;
        if (!(ip = fopen(makepath(p, gozillarc, NULL), "r")))
#ifdef __DJGPP__
                if (!(ip = fopen(makepath(p, dos_gozillarc, NULL), "r")))
#endif
                        goto end;
        while ((p = strbuf_fgets(sb, ip, flag)) != NULL) {
                char *name, *value;

                flag &= ~STRBUF_APPEND;
                if (*p == '#')
                        continue;
                if (strbuf_unputc(sb, '\\')) {
                        flag |= STRBUF_APPEND;
                        continue;
                }
                while (*p && isblank(*p))       /* skip spaces */
                        p++;
                name = p;
                while (*p && isalnum(*p))       /* get name */
                        p++;
                *p++ = 0;
                while (*p && isblank(*p))       /* skip spaces */
                        p++;
                if (*p == '=' || *p == ':') {
                        p++;
                        while (*p && isblank(*p))/* skip spaces */
                                p++;
                }
                value = p;
                while (*p && !isblank(*p))      /* get value */
                        p++;
                *p = 0;
                ent = strhash_assign(sh, name, 1);
                if (ent->value)
                        (void)free(ent->value);
                ent->value = check_strdup(value);
        }
        fclose(ip);
end:
        strbuf_close(sb);
}
/*
 * alias: get alias value.
 *
 *      i)      alias_name      alias name
 *      r)                      its value
 */
static const char *
alias(const char *alias_name)
{
        struct sh_entry *ent = strhash_assign(sh, alias_name, 0);
        return ent ? ent->value : NULL;
}

/*
 * locate_HTMLdir: locate HTML directory made by htags(1).
 *
 *      r)              HTML directory
 */
static const char *
locate_HTMLdir(void)
{
        static char htmldir[MAXPATHLEN+1];

        if (test("d", makepath(dbpath, "HTML", NULL)))
                strlimcpy(htmldir, makepath(dbpath, "HTML", NULL), sizeof(htmldir));
        else if (test("d", makepath(root, "HTML", NULL)))
                strlimcpy(htmldir, makepath(root, "HTML", NULL), sizeof(htmldir));
        else if (test("d", makepath(root, "html/HTML", NULL)))
                /* Doxygen makes HTML in doxygen's html directory. */
                strlimcpy(htmldir, makepath(root, "html/HTML", NULL), sizeof(htmldir));
        else
                die("hypertext not found. See htags(1).");
        if (vflag)
                fprintf(stdout, "HTML directory '%s'.\n", htmldir);
        return (const char *)htmldir;
}
int
main(int argc, char **argv)
{
        char c;
        const char *p, *browser = NULL, *definition = NULL;
        STRBUF *arg = strbuf_open(0);
        STRBUF *URL = strbuf_open(0);

        while (--argc > 0 && ((c = (++argv)[0][0]) == '-' || c == '+')) {
                if (argv[0][1] == '-') {
                        if (!strcmp("--help", argv[0]))
                                help();
                        else if (!strcmp("--version", argv[0]))
                                show_version++;
                        else if (!strcmp("--quiet", argv[0])) {
                                qflag++;
                                vflag = 0;
                        } else if (!strcmp("--verbose", argv[0])) {
                                vflag++;
                                qflag = 0;
                        } else
                                usage();
                        continue;
                }
                if (c == '+') {
                        linenumber = atoi(argv[0] + 1);
                        continue;
                }
                p = argv[0] + 1;
                switch (*p) {
                case 'b':
                        browser = argv[1];
                        --argc; ++argv;
                        break;
                case 'd':
                        definition = argv[1];
                        --argc; ++argv;
                        break;
                case 'p':
                        pflag++;
                        break;
                case 'q':
                        qflag++;
                        setquiet();
                        break;
                case 'v':
                        vflag++;
                        break;
                default:
                        usage();
                }
        }
        if (show_version)
                version(progname, vflag);
        /*
         * Load aliases from .gozillarc.
         */
        load_alias();

        /*
         * Decide browser.
         */
        if (!browser && getenv("BROWSER"))
                browser = getenv("BROWSER");
        if (!browser && alias("BROWSER"))
                browser = alias("BROWSER");
        if (!browser)
                browser = "mozilla";

        /*
         * Replace alias name.
         */
        if (definition == NULL) {
                if (argc == 0)
                        usage();
                strbuf_puts(arg, argv[0]);
                /*
                 * Replace with alias value.
                 */
                if ((p = alias(strbuf_value(arg))) != NULL) {
                        strbuf_reset(arg);
                        strbuf_puts(arg, p);
                }
        }
        /*
         * Get URL.
         */
        if (!definition && isprotocol(strbuf_value(arg))) {
                strbuf_puts(URL, strbuf_value(arg));
        } else {
                getdbpath(cwd, root, dbpath, 0);
                if (definition)
                        getdefinitionURL(definition, URL);
                else
                        getURL(strbuf_value(arg), URL);
        }
        if (pflag) {
                fprintf(stdout, "%s\n", strbuf_value(URL));
                if (vflag)
                        fprintf(stdout, "using browser '%s'.\n", browser);
                exit(0);
        }
        /*
         * Show URL's page.
         */
        show_page_by_url(browser, strbuf_value(URL));
        exit(0);
}

/*
 * getdefinitionURL: get URL includes specified definition.
 *
 *      i)      arg     definition name
 *      o)      URL     URL begin with 'file:'
 */
void
getdefinitionURL(const char *arg, STRBUF *URL)
{
        const char *path;
        char *p;
        STRBUF *sb = NULL;
        DBOP *dbop = NULL;
        SPLIT ptable;
        int status = -1;
        const char *htmldir = locate_HTMLdir();

        path = makepath(htmldir, "MAP.db", NULL);
        if (test("f", path))
                dbop = dbop_open(path, 0, 0, 0);
        if (!dbop) {
                path = makepath(htmldir, "MAP", NULL);
                if (!test("f", path))
                        die("'%s' not found. Please reconstruct hypertext using the latest htags(1).", path);
                dbop = dbop_open(path, 0, 0, 0);
        }
        if (dbop) {
                if ((p = (char *)dbop_get(dbop, arg)) != NULL) {
                        if (split(p, 2, &ptable) != 2)
                                die("illegal format.");
                        status = 0;
                }
                dbop_close(dbop);
        } else {
                FILE *fp;

                sb = strbuf_open(0);
                fp = fopen(path, "r");
                if (fp) {
                        while ((p = strbuf_fgets(sb, fp, STRBUF_NOCRLF)) != NULL) {
                                if (split(p, 2, &ptable) != 2)
                                        die("illegal format.");
                                if (!strcmp(arg, ptable.part[0].start)) {
                                        status = 0;
                                        break;
                                }
                        }
                        fclose(fp);
                }
        }
        if (status == -1)
                die("definition %s not found.", arg);
        strbuf_reset(URL);
        /*
         * convert path into URL.
         */
        makefileurl(makepath(htmldir, ptable.part[1].start, NULL), 0, URL);
        recover(&ptable);
        if (sb != NULL)
                strbuf_close(sb);
}
/*
 * getURL: get URL of the specified file.
 *
 *      i)      file    file name
 *      o)      URL     URL begin with 'file:'
 */
void
getURL(const char *file, STRBUF *URL)
{
        char *p;
        char rootdir[MAXPATHLEN+1];
        char buf[MAXPATHLEN+1];
        STRBUF *sb = strbuf_open(0);
        const char *htmldir = locate_HTMLdir();

        /*
         * rootdir always ends with '/'.
         */
        if (!strcmp(root, "/"))
                strlimcpy(rootdir, root, sizeof(rootdir));
        else
                snprintf(rootdir, sizeof(rootdir), "%s/", root);
        if (!test("f", file) && !test("d", file))
                die("path '%s' not found.", file);
        p = normalize(file, rootdir, cwd, buf, sizeof(buf));
        if (convertpath(dbpath, htmldir, p, sb) == 0)
                makefileurl(strbuf_value(sb), linenumber, URL);
        else
                makefileurl(realpath(file, buf), 0, URL);
        strbuf_close(sb);
}
/*
 * isprotocol: return 1 if url has a procotol.
 *
 *      i)      url     URL
 *      r)              1: protocol, 0: file
 */
int
isprotocol(const char *url)
{
        const char *p;

        if (locatestring(url, "file:", MATCH_AT_FIRST))
                return 1;
        /*
         * protocol's style is like http://xxx.
         */
        for (p = url; *p && *p != ':'; p++)
                if (!isalnum(*p))
                        return 0;
        if (!*p)
                return 0;
        if (*p++ == ':' && *p++ == '/' && *p == '/')
                return 1;
        return 0;
}
/*
 * convertpath: convert source file into hypertext path.
 *
 *      i)      dbpath  dbpath
 *      i)      htmldir HTML directory made by htags(1)
 *      i)      path    source file path
 *      o)      sb      string buffer
 *      r)              0: normal, -1: error
 */
int
convertpath(const char *dbpath, const char *htmldir, const char *path, STRBUF *sb)
{
        static const char *suffix[] = {".html", ".htm"};
        static const char *gz = ".gz";
        int i, lim = sizeof(suffix)/sizeof(char *);
        const char *p;

        strbuf_reset(sb);
        strbuf_puts(sb, htmldir);
        strbuf_puts(sb, "/S/");
        /*
         * new style.
         */
        if (gpath_open(dbpath, 0) == 0) {
                int tag1 = strbuf_getlen(sb);

                p = gpath_path2fid(path, NULL);
                if (p == NULL) {
                        gpath_close();
                        return -1;
                }
                gpath_close();
                strbuf_puts(sb, p);
                for (i = 0; i < lim; i++) {
                        int tag2 = strbuf_getlen(sb);
                        strbuf_puts(sb, suffix[i]);
                        if (test("f", strbuf_value(sb)))
                                return 0;
                        strbuf_puts(sb, gz);
                        if (test("f", strbuf_value(sb)))
                                return 0;
                        strbuf_setlen(sb, tag2);
                }
                strbuf_setlen(sb, tag1);
        }
        /*
         * old style.
         */
        for (p = path + 1; *p; p++)
                strbuf_putc(sb, (*p == '/') ? ' ' : *p);
        for (i = 0; i < lim; i++) {
                int tag = strbuf_getlen(sb);
                strbuf_puts(sb, suffix[i]);
                if (test("f", strbuf_value(sb)))
                        return 0;
                strbuf_puts(sb, gz);
                if (test("f", strbuf_value(sb)))
                        return 0;
                strbuf_setlen(sb, tag);
        }
        return -1;
}
/*
 * makefileurl: make url which start with 'file:'.
 *
 *      i)      path    path name (absolute)
 *      i)      line    !=0: line number
 *      o)      url     URL
 *
 * makefileurl('/dir/a.html', 10)   => 'file:///dir/a.html#L10'
 *
 * (Windows32 environment)
 * makefileurl('c:/dir/a.html', 10) => 'file://c|/dir/a.html#L10'
 */
void
makefileurl(const char *path, int line, STRBUF *url)
{
        strbuf_puts(url, "file://");
#if _WIN32 || __DJGPP__
        /*
         * copy drive name. (c: -> c|)
         */
        if (isalpha(*path) && *(path+1) == ':') {
                strbuf_putc(url, *path);
                strbuf_putc(url, '|');
                path += 2;
        }
#endif
        strbuf_puts(url, path);
        if (line) {
                strbuf_puts(url, "#L");
                strbuf_putn(url, line);
        }
}
/*
 * show_page_by_url: show page by url
 *
 *      i)      browser browser name
 *      i)      url     URL
 */
#if defined(_WIN32)
/* Windows32 version */
void
show_page_by_url(const char *browser, const char *url)
{
        if (ShellExecute(NULL, NULL, browser, url, NULL, SW_SHOWNORMAL) <= (HINSTANCE)32)
                die("Cannot load %s (error = 0x%04x).", browser, GetLastError());
}
#elif defined(__DJGPP__)
/* DJGPP version */
void
show_page_by_url(const char *browser, const char *url)
{
        char com[MAXFILLEN+1];
        char *path;

        /*
         * assume a Windows browser if it's not on the path.
         */
        if (!(path = usable(browser))) {
                /*
                 * START is an internal command in XP, external in 9X.
                 */
                if (!(path = usable("start")))
                        path = "cmd /c start";
                snprintf(com, sizeof(com), "%s %s \"%s\"", path, browser, url);
        } else {
                snprintf(com, sizeof(com), "%s \"%s\"", path, url);
        }
        system(com);
}
#else
/* UNIX version */
void
show_page_by_url(const char *browser, const char *url)
{
        char com[1024];

        /*
         * Browsers which have openURL() command.
         */
        if (locatestring(browser, "mozilla", MATCH_AT_LAST) ||
            locatestring(browser, "netscape", MATCH_AT_LAST) ||
            locatestring(browser, "netscape-remote", MATCH_AT_LAST))
        {
                char *path;

                if (!(path = usable(browser)))
                        die("%s not found in your path.", browser);
                snprintf(com, sizeof(com), "%s -remote \"openURL(%s)\"", path, url);
        }
        /*
         * Generic browser.
         */
        else {
                snprintf(com, sizeof(com), "%s \"%s\"", browser, url);
        }
        system(com);
}
#endif

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