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