1 /*
2  * Copyright (c) 1997, 1998, 1999, 2000, 2002, 2003, 2004, 2006,
3  *	2011, 2014
4  *	Tama Communications Corporation
5  *
6  * This file is part of GNU GLOBAL.
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <ctype.h>
29 #ifdef _WIN32
30 #define WIN32_LEAN_AND_MEAN
31 #include <windows.h>
32 #include <shellapi.h>
33 /*
34  * Don't remove the following code which seems meaningless.
35  * Since WIN32 has another SLIST_ENTRY, we removed the definition
36  * so as not to cause the conflict.
37  */
38 #ifdef SLIST_ENTRY
39 #undef SLIST_ENTRY
40 #endif
41 #endif
42 
43 #include "global.h"
44 #include "regex.h"
45 #include "const.h"
46 
47 /**
48  gozilla - force firefox to display specified part of a source file.
49 */
50 
51 static void usage(void);
52 static void help(void);
53 
54 int main(int, char **);
55 void getdefinitionURL(const char *, const char *, STRBUF *);
56 void getURL(const char *, const char *, STRBUF *);
57 int convertpath(const char *, const char *, const char *, STRBUF *);
58 void makefileurl(const char *, int, STRBUF *);
59 void show_page_by_url(const char *, const char *);
60 #ifndef isblank
61 #define isblank(c)	((c) == ' ' || (c) == '\t')
62 #endif
63 
64 const char *cwd, *root, *dbpath;
65 
66 int pflag;
67 int qflag;
68 int vflag;
69 int show_version;
70 int linenumber = 0;
71 int debug;
72 
73 static void
usage(void)74 usage(void)
75 {
76 	if (!qflag)
77 		fputs(usage_const, stderr);
78 	exit(2);
79 }
80 static void
help(void)81 help(void)
82 {
83 	fputs(usage_const, stdout);
84 	fputs(help_const, stdout);
85 	exit(0);
86 }
87 
88 /**
89  * locate_HTMLdir: locate HTML directory made by htags(1).
90  *
91  *	@return		HTML directory
92  */
93 static const char *
locate_HTMLdir(void)94 locate_HTMLdir(void)
95 {
96 	static char htmldir[MAXPATHLEN];
97 
98 	if (test("d", makepath(dbpath, "HTML", NULL)))
99 		strlimcpy(htmldir, makepath(dbpath, "HTML", NULL), sizeof(htmldir));
100 	else if (test("d", makepath(root, "HTML", NULL)))
101 		strlimcpy(htmldir, makepath(root, "HTML", NULL), sizeof(htmldir));
102 	else if (test("d", makepath(root, "html/HTML", NULL)))
103 		/* Doxygen makes HTML in doxygen's html directory. */
104 		strlimcpy(htmldir, makepath(root, "html/HTML", NULL), sizeof(htmldir));
105 	else
106 		return NULL;
107 	if (vflag)
108 		fprintf(stdout, "HTML directory '%s'.\n", htmldir);
109 	return (const char *)htmldir;
110 }
111 int
main(int argc,char ** argv)112 main(int argc, char **argv)
113 {
114 	char c;
115 	const char *p, *browser = NULL, *definition = NULL;
116 	STRBUF *URL = strbuf_open(0);
117 
118 	logging_arguments(argc, argv);
119 	while (--argc > 0 && ((c = (++argv)[0][0]) == '-' || c == '+')) {
120 		if (argv[0][1] == '-') {
121 			if (!strcmp("--help", argv[0]))
122 				help();
123 			else if (!strcmp("--version", argv[0]))
124 				show_version++;
125 			else if (!strcmp("--quiet", argv[0])) {
126 				qflag++;
127 				vflag = 0;
128 			} else if (!strcmp("--verbose", argv[0])) {
129 				vflag++;
130 				qflag = 0;
131 			} else if (!strcmp("--debug", argv[0])) {
132 				debug = 1;
133 			} else
134 				usage();
135 			continue;
136 		}
137 		if (c == '+') {
138 			linenumber = atoi(argv[0] + 1);
139 			continue;
140 		}
141 		p = argv[0] + 1;
142 		switch (*p) {
143 		case 'b':
144 			browser = argv[1];
145 			--argc; ++argv;
146 			break;
147 		case 'd':
148 			definition = argv[1];
149 			--argc; ++argv;
150 			break;
151 		case 'p':
152 			pflag++;
153 			break;
154 		case 'q':
155 			qflag++;
156 			setquiet();
157 			break;
158 		case 'v':
159 			vflag++;
160 			setverbose();
161 			break;
162 		default:
163 			usage();
164 		}
165 	}
166 	if (show_version)
167 		version(progname, vflag);
168 	if (!definition) {
169 		if (argc <= 0)
170 			usage();
171 		if (!test("f", argv[0]))
172 			die("file '%s' not found.", argv[0]);
173 	}
174 	/*
175 	 * Open configuration file.
176 	 */
177 	openconf(NULL);
178 	/*
179 	 * Decide browser.
180 	 */
181 	if (!browser && getenv("BROWSER"))
182 		browser = getenv("BROWSER");
183 	/*
184 	 * In DOS & Windows, let the file: association handle it.
185 	 */
186 #if !(_WIN32 || __DJGPP__)
187 	if (!browser)
188 		browser = "firefox";
189 #endif
190 	/*
191 	 * Get URL.
192 	 */
193 	{
194 		const char *HTMLdir = NULL;
195 
196 		if (setupdbpath(0) == 0) {
197 			cwd = get_cwd();
198 			root = get_root();
199 			dbpath = get_dbpath();
200 			HTMLdir = locate_HTMLdir();
201 		}
202 		/*
203 		 * Make a URL of hypertext from the argument.
204 		 */
205 		if (HTMLdir == NULL)
206 			die("HTML directory not found.");
207 		if (definition)
208 			getdefinitionURL(definition, HTMLdir, URL);
209 		else
210 			getURL(argv[0], HTMLdir, URL);
211 	}
212 	if (pflag) {
213 		fprintf(stdout, "%s\n", strbuf_value(URL));
214 		if (vflag)
215 			fprintf(stdout, "using browser '%s'.\n", browser);
216 		exit(0);
217 	}
218 	/*
219 	 * Show URL's page.
220 	 */
221 	show_page_by_url(browser, strbuf_value(URL));
222 	exit(0);
223 }
224 
225 /**
226  * getdefinitionURL: get URL includes specified definition.
227  *
228  *	@param[in]	arg	definition name
229  *	@param[in]	htmldir HTML directory
230  *	@param[out]	URL	URL begin with 'file:'
231  */
232 void
getdefinitionURL(const char * arg,const char * htmldir,STRBUF * URL)233 getdefinitionURL(const char *arg, const char *htmldir, STRBUF *URL)
234 {
235 	FILE *fp;
236 	char *p;
237 	SPLIT ptable;
238 	int status = -1;
239 	STRBUF *sb = strbuf_open(0);
240 	const char *path = makepath(htmldir, "D", NULL);
241 
242 	if (!test("d", path))
243 		die("'%s' not found. Please invoke htags(1) without the -D option.", path);
244 	path = makepath(htmldir, "MAP", NULL);
245 	if (!test("f", path))
246 		die("'%s' not found. Please invoke htags(1) with the --map-file option.", path);
247 	fp = fopen(path, "r");
248 	if (!fp)
249 		die("cannot open '%s'.", path);
250 	while ((p = strbuf_fgets(sb, fp, STRBUF_NOCRLF)) != NULL) {
251 		if (split(p, 2, &ptable) != 2)
252 			die("invalid format.");
253 		if (!strcmp(arg, ptable.part[0].start)) {
254 			status = 0;
255 			break;
256 		}
257 	}
258 	fclose(fp);
259 	if (status == -1)
260 		die("definition %s not found.", arg);
261 	strbuf_reset(URL);
262 	/*
263 	 * convert path into URL.
264 	 */
265 	makefileurl(makepath(htmldir, ptable.part[1].start, NULL), 0, URL);
266 	recover(&ptable);
267 	strbuf_close(sb);
268 }
269 /**
270  * getURL: get URL of the specified file.
271  *
272  *	@param[in]	file	file name
273  *	@param[in]	htmldir HTML directory
274  *	@param[out]	URL	URL begin with 'file:'
275  */
276 void
getURL(const char * file,const char * htmldir,STRBUF * URL)277 getURL(const char *file, const char *htmldir, STRBUF *URL)
278 {
279 	char *p;
280 	char buf[MAXPATHLEN];
281 	STRBUF *sb = strbuf_open(0);
282 	p = normalize(file, get_root_with_slash(), cwd, buf, sizeof(buf));
283 	if (p != NULL && convertpath(dbpath, htmldir, p, sb) == 0)
284 		makefileurl(strbuf_value(sb), linenumber, URL);
285 	else
286 		makefileurl(realpath(file, buf), 0, URL);
287 	strbuf_close(sb);
288 }
289 /**
290  * convertpath: convert source file into hypertext path.
291  *
292  *	@param[in]	dbpath	dbpath
293  *	@param[in]	htmldir	HTML directory made by htags(1)
294  *	@param[in]	path	source file path
295  *	@param[out]	sb	string buffer
296  *	@return		0: normal, -1: error
297  */
298 int
convertpath(const char * dbpath,const char * htmldir,const char * path,STRBUF * sb)299 convertpath(const char *dbpath, const char *htmldir, const char *path, STRBUF *sb)
300 {
301 	static const char *suffix[] = {".html", ".htm"};
302 	static const char *gz = ".gz";
303 	int i, lim = sizeof(suffix)/sizeof(char *);
304 	const char *p;
305 
306 	strbuf_reset(sb);
307 	strbuf_puts(sb, htmldir);
308 	strbuf_puts(sb, "/S/");
309 	/*
310 	 * new style.
311 	 */
312 	if (gpath_open(dbpath, 0) == 0) {
313 		int tag1 = strbuf_getlen(sb);
314 
315 		p = gpath_path2fid(path, NULL);
316 		if (p == NULL) {
317 			gpath_close();
318 			return -1;
319 		}
320 		gpath_close();
321 		strbuf_puts(sb, p);
322 		for (i = 0; i < lim; i++) {
323 			int tag2 = strbuf_getlen(sb);
324 			strbuf_puts(sb, suffix[i]);
325 			if (test("f", strbuf_value(sb)))
326 				return 0;
327 			strbuf_puts(sb, gz);
328 			if (test("f", strbuf_value(sb)))
329 				return 0;
330 			strbuf_setlen(sb, tag2);
331 		}
332 		strbuf_setlen(sb, tag1);
333 	}
334 	/*
335 	 * old style.
336 	 */
337 	for (p = path + 1; *p; p++)
338 		strbuf_putc(sb, (*p == '/') ? ' ' : *p);
339 	for (i = 0; i < lim; i++) {
340 		int tag = strbuf_getlen(sb);
341 		strbuf_puts(sb, suffix[i]);
342 		if (test("f", strbuf_value(sb)))
343 			return 0;
344 		strbuf_puts(sb, gz);
345 		if (test("f", strbuf_value(sb)))
346 			return 0;
347 		strbuf_setlen(sb, tag);
348 	}
349 	return -1;
350 }
351 /**
352  * makefileurl: make url which start with 'file:'.
353  *
354  *	@param[in]	path	path name (absolute)
355  *	@param[in]	line	!=0: line number
356  *	@param[out]	url	URL
357  *
358  * Examples:
359  * makefileurl('/dir/a.html', 10)   => 'file:///dir/a.html#L10'
360  *
361  * (Windows32 environment)
362  * makefileurl('c:/dir/a.html', 10) => 'file://c|/dir/a.html#L10'
363  */
364 void
makefileurl(const char * path,int line,STRBUF * url)365 makefileurl(const char *path, int line, STRBUF *url)
366 {
367 	strbuf_puts(url, "file://");
368 #if _WIN32 || __DJGPP__
369 	/*
370 	 * copy drive name. (c: -> c|)
371 	 */
372 	if (isalpha(*path) && *(path+1) == ':') {
373 		strbuf_putc(url, *path);
374 		strbuf_putc(url, '|');
375 		path += 2;
376 	}
377 #endif
378 	strbuf_puts(url, path);
379 	if (line) {
380 		strbuf_puts(url, "#L");
381 		strbuf_putn(url, line);
382 	}
383 }
384 /**
385  * show_page_by_url: show page by url
386  *
387  *	@param[in]	browser browser name
388  *	@param[in]	url	URL
389  */
390 #if defined(_WIN32)
391 /* Windows32 version */
392 void
show_page_by_url(const char * browser,const char * url)393 show_page_by_url(const char *browser, const char *url)
394 {
395 	const char *lpFile, *lpParameters;
396 	if (browser) {
397 		lpFile = browser;
398 		lpParameters = url;
399 	} else {
400 		lpFile = url;
401 		lpParameters = NULL;
402 	}
403 	if (ShellExecute(NULL, NULL, lpFile, lpParameters, NULL, SW_SHOWNORMAL) <= (HINSTANCE)32)
404 		die("Cannot load %s (error = 0x%04x).", lpFile, GetLastError());
405 }
406 #elif defined(__DJGPP__)
407 /* DJGPP version */
408 void
show_page_by_url(const char * browser,const char * url)409 show_page_by_url(const char *browser, const char *url)
410 {
411 	char com[MAXFILLEN];
412 	char *path;
413 
414 	if (!browser) {
415 		browser = "";
416 	}
417 	/*
418 	 * assume a Windows browser if it's not on the path.
419 	 */
420 	if (!(path = usable(browser))) {
421 		/*
422 		 * START is an internal command in XP, external in 9X.
423 		 */
424 		if (!(path = usable("start")))
425 			path = "cmd /c start \"\"";
426 		snprintf(com, sizeof(com), "%s %s \"%s\"", path, browser, url);
427 	} else {
428 		snprintf(com, sizeof(com), "%s \"%s\"", path, url);
429 	}
430 	system(com);
431 }
432 #else
433 /* UNIX version */
434 /*
435  * Make a html file to use OSX's open command.
436  */
437 #include <pwd.h>
438 static char urlfile[MAXPATHLEN];
439 static char *
make_url_file(const char * url)440 make_url_file(const char *url)
441 {
442 	STATIC_STRBUF(sb);
443 	FILE *op;
444 	struct passwd *pw = getpwuid(getuid());
445 
446 	strbuf_clear(sb);
447 	getconfs("localstatedir", sb);
448 	snprintf(urlfile, sizeof(urlfile), "%s/gtags/lasturl-%s.html", strbuf_value(sb),
449 			pw ? pw->pw_name : "nobody");
450 	op = fopen(urlfile, "w");
451 	if (op == NULL)
452 		die("cannot make url file.");
453 	fprintf(op, "<!-- You may remove this file. It was needed by gozilla(1) temporarily. -->\n");
454 	fprintf(op, "<html><head>\n");
455 	fprintf(op, "<meta http-equiv='refresh' content='0;url=\"%s\"' />\n", url);
456 	fprintf(op, "</head></html>\n");
457 	fclose(op);
458 
459 	return urlfile;
460 }
461 void
dump_argv(char * argv[])462 dump_argv(char *argv[]) {
463 	int i;
464 	for (i = 0; argv[i] != NULL; i++) {
465 		fprintf(stderr, "argv[%d] = |%s|\n", i, argv[i]);
466 	}
467 }
468 void
show_page_by_url(const char * browser,const char * url)469 show_page_by_url(const char *browser, const char *url)
470 {
471 	char *argv[4];
472 	STRBUF  *sb = strbuf_open(0);
473 	STRBUF  *arg = strbuf_open(0);
474 	/*
475 	 * Browsers which have openURL() command.
476 	 */
477 	if (locatestring(browser, "mozilla", MATCH_AT_LAST) ||
478 	/*
479 	 * Firefox has removed the -remote command line option since version 39.
480 	    locatestring(browser, "firefox", MATCH_AT_LAST) ||
481 	 */
482 	    locatestring(browser, "netscape", MATCH_AT_LAST) ||
483 	    locatestring(browser, "netscape-remote", MATCH_AT_LAST))
484 	{
485 		if (debug)
486 			fprintf(stderr, "Netscape\n");
487 		argv[0] = (char *)browser;
488 		argv[1] = "-remote";
489 		strbuf_sprintf(arg, "openURL(%s)", url);
490 		argv[2] = strbuf_value(arg);
491 		argv[3] = NULL;
492 		if (debug)
493 			dump_argv(argv);
494 		execvp(browser, argv);
495 	}
496 	/*
497 	 * Load default browser of OSX.
498 	 */
499 	else if (!strcmp(browser, "osx-default")) {
500 		if (debug)
501 			fprintf(stderr, "OSX default\n");
502 		argv[0] = "open";
503 		argv[1] = make_url_file(url);
504 		argv[2] = NULL;
505 		if (debug)
506 			dump_argv(argv);
507 		execvp("open", argv);
508 	}
509 	/*
510 	 * Generic browser.
511 	 */
512 	else {
513 		if (debug)
514 			fprintf(stderr, "Generic browser\n");
515 		argv[0] = (char *)browser;
516 		argv[1] = (char *)url;
517 		argv[2] = NULL;
518 		if (debug)
519 			dump_argv(argv);
520 		execvp(browser, argv);
521 	}
522 	strbuf_close(sb);
523 	strbuf_close(arg);
524 }
525 #endif
526