/*
* 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 .
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include
#include
#include
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include
#include
/*
* 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 *abspath, *p;
char buf[MAXPATHLEN+1];
STRBUF *sb = strbuf_open(0);
const char *htmldir = locate_HTMLdir();
if (!test("f", file) && !test("d", file))
die("path '%s' not found.", file);
if (!(abspath = realpath(file, buf)))
die("cannot make absolute path name. realpath(%s) failed.", file);
if (!isabspath(abspath))
die("realpath(3) is not compatible with BSD version.");
/*
* convert path into URL.
*/
p = abspath + strlen(root);
if (convertpath(dbpath, htmldir, p, sb) == 0)
makefileurl(strbuf_value(sb), linenumber, URL);
else
makefileurl(abspath, 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) {
char key[MAXPATHLEN+1];
int tag1 = strbuf_getlen(sb);
strlimcpy(key, "./", sizeof(key));
strcat(key, path + 1);
p = gpath_path2fid(key, NULL);
if (p == NULL) {
gpath_close();
return -1;
}
strlimcpy(key, p, sizeof(key));
gpath_close();
strbuf_puts(sb, key);
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