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