/* */
This source file includes following definitions.
- get_lang_entry
- echoc
- echos
- HTML_quoting
- fill_anchor
- link_format
- fixed_guide_link_format
- generate_guide
- tooltip
- put_anchor
- put_anchor_force
- put_include_anchor
- put_include_anchor_direct
- put_reserved_word
- put_macro
- unknown_preprocessing_directive
- unexpected_eof
- unknown_yacc_directive
- missing_left
- put_char
- put_string
- put_brace
- put_begin_of_line
- put_end_of_line
- encode
- get_cvs_module
- src2html
1 /*
2 * Copyright (c) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
3 * 2006, 2008, 2010, 2011
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 #ifdef STDC_HEADERS
27 #include <stdlib.h>
28 #endif
29 #include <ctype.h>
30
31 #include "global.h"
32 #include "anchor.h"
33 #include "cache.h"
34 #include "common.h"
35 #include "incop.h"
36 #include "path2url.h"
37 #include "htags.h"
38
39 /*----------------------------------------------------------------------*/
40 /* Parser switch */
41 /*----------------------------------------------------------------------*/
42 /**
43 * @details
44 * This is the linkage section of each parsers. <br>
45 * If you want to support new language, you must define two procedures: <br>
46 * -# Initializing procedure (#init_proc).
47 * Called once first with an input file descripter.
48 * -# Executing procedure (#exec_proc).
49 * Called repeatedly until returning @NAME{EOF}. <br>
50 * It should read from above descripter and write @NAME{HTML}
51 * using output procedures in this module.
52 */
53 struct lang_entry {
54 const char *lang_name;
55 void (*init_proc)(FILE *); /**< initializing procedure */
56 int (*exec_proc)(void); /**< executing procedure */
57 };
58
59 /**
60 * @name initializing procedures
61 * For lang_entry::init_proc
62 */
63 /** @{ */
64 void c_parser_init(FILE *);
65 void yacc_parser_init(FILE *);
66 void cpp_parser_init(FILE *);
67 void java_parser_init(FILE *);
68 void php_parser_init(FILE *);
69 void asm_parser_init(FILE *);
70 /** @} */
71
72 /**
73 * @name executing procedures
74 * For lang_entry::exec_proc
75 */
76 /** @{ */
77 int c_lex(void);
78 int cpp_lex(void);
79 int java_lex(void);
80 int php_lex(void);
81 int asm_lex(void);
82 /** @} */
83
84 /**
85 * The first entry is default language.
86 */
87 struct lang_entry lang_switch[] = {
88 /* lang_name init_proc exec_proc */
89 {"c", c_parser_init, c_lex}, /* DEFAULT */
90 {"yacc", yacc_parser_init, c_lex},
91 {"cpp", cpp_parser_init, cpp_lex},
92 {"java", java_parser_init, java_lex},
93 {"php", php_parser_init, php_lex},
94 {"asm", asm_parser_init, asm_lex}
95 };
96 #define DEFAULT_ENTRY &lang_switch[0]
97
98 /**
99 * get language entry.
100 *
101 * If the specified language (@a lang) is not found, it assumes the
102 * default language, which is @NAME{C}.
103 *
104 * @param[in] lang language name (@VAR{NULL} means 'not specified'.)
105 * @return language entry
106 */
107 static struct lang_entry *
108 get_lang_entry(const char *lang)
109 {
110 int i, size = sizeof(lang_switch) / sizeof(struct lang_entry);
111
112 /*
113 * if language not specified, it assumes default language.
114 */
115 if (lang == NULL)
116 return DEFAULT_ENTRY;
117 for (i = 0; i < size; i++)
118 if (!strcmp(lang, lang_switch[i].lang_name))
119 return &lang_switch[i];
120 /*
121 * if specified language not found, it assumes default language.
122 */
123 return DEFAULT_ENTRY;
124 }
125 /*----------------------------------------------------------------------*/
126 /* Input/Output */
127 /*----------------------------------------------------------------------*/
128 /*
129 * Input/Output descriptor.
130 */
131 static FILEOP *fileop_out;
132 static FILEOP *fileop_in;
133 static FILE *out;
134 static FILE *in;
135
136 STATIC_STRBUF(outbuf);
137 static const char *curpfile;
138 static int warned;
139 static int last_lineno;
140
141 /**
142 * Put a character to HTML as is.
143 *
144 * @note You should use this function to put a control character. <br>
145 *
146 * @attention
147 * No escaping of @CODE{'\<'}, @CODE{'\>'} and @CODE{'\&'} is performed.
148 *
149 * @see put_char()
150 */
151 void
152 echoc(int c)
153 {
154 strbuf_putc(outbuf, c);
155 }
156 /**
157 * Put a string to HTML as is.
158 *
159 * @note You should use this function to put a control sequence.
160 *
161 * @attention
162 * No escaping of @CODE{'\<'}, @CODE{'\>'} and @CODE{'\&'} is performed.
163 *
164 * @see put_string()
165 */
166 void
167 echos(const char *s)
168 {
169 strbuf_puts(outbuf, s);
170 }
171 /*----------------------------------------------------------------------*/
172 /* HTML output */
173 /*----------------------------------------------------------------------*/
174 /**
175 * Quote character with HTML's way.
176 *
177 * (Fixes @CODE{'\<'}, @CODE{'\>'} and @CODE{'\&'} for HTML).
178 */
179 static const char *
180 HTML_quoting(int c)
181 {
182 if (c == '<')
183 return quote_little;
184 else if (c == '>')
185 return quote_great;
186 else if (c == '&')
187 return quote_amp;
188 return NULL;
189 }
190 /**
191 * fill_anchor: fill anchor into file name
192 *
193 * @param[in] root \$root or index page
194 * @param[in] path \$path name
195 * @return hypertext file name string
196 */
197 const char *
198 fill_anchor(const char *root, const char *path)
199 {
200 STATIC_STRBUF(sb);
201 char buf[MAXBUFLEN], *limit, *p;
202
203 strbuf_clear(sb);
204 strlimcpy(buf, path, sizeof(buf));
205 for (p = buf; *p; p++)
206 if (*p == sep)
207 *p = '\0';
208 limit = p;
209
210 if (root != NULL)
211 strbuf_sprintf(sb, "%sroot%s/", gen_href_begin_simple(root), gen_href_end());
212 for (p = buf; p < limit; p += strlen(p) + 1) {
213 const char *path = buf;
214 const char *unit = p;
215 const char *next = p + strlen(p) + 1;
216
217 if (next > limit) {
218 strbuf_puts(sb, unit);
219 break;
220 }
221 if (p > buf)
222 *(p - 1) = sep;
223 strbuf_puts(sb, gen_href_begin("../files", path2fid(path), HTML, NULL));
224 strbuf_puts(sb, unit);
225 strbuf_puts(sb, gen_href_end());
226 strbuf_putc(sb, '/');
227 }
228 return strbuf_value(sb);
229 }
230
231 /**
232 * link_format: make hypertext from anchor array.
233 *
234 * @param[in] ref (previous, next, first, last, top, bottom) <br>
235 * -1: top, -2: bottom, other: line number
236 * @return HTML
237 */
238 const char *
239 link_format(int ref[A_SIZE])
240 {
241 STATIC_STRBUF(sb);
242 const char **label = Iflag ? anchor_comment : anchor_label;
243 const char **icons = anchor_icons;
244 int i;
245
246 strbuf_clear(sb);
247 for (i = 0; i < A_LIMIT; i++) {
248 if (i == A_INDEX) {
249 strbuf_puts(sb, gen_href_begin("..", "mains", normal_suffix, NULL));
250 } else if (i == A_HELP) {
251 strbuf_puts(sb, gen_href_begin("..", "help", normal_suffix, NULL));
252 } else if (ref[i]) {
253 char tmp[32], *key = tmp;
254
255 if (ref[i] == -1)
256 key = "TOP";
257 else if (ref[i] == -2)
258 key = "BOTTOM";
259 else
260 snprintf(tmp, sizeof(tmp), "%d", ref[i]);
261 strbuf_puts(sb, gen_href_begin(NULL, NULL, NULL, key));
262 }
263 if (Iflag) {
264 char tmp[MAXPATHLEN];
265 snprintf(tmp, sizeof(tmp), "%s%s", (i != A_INDEX && i != A_HELP && ref[i] == 0) ? "n_" : "", icons[i]);
266 strbuf_puts(sb, gen_image(PARENT, tmp, label[i]));
267 } else {
268 strbuf_sprintf(sb, "[%s]", label[i]);
269 }
270 if (i == A_INDEX || i == A_HELP || ref[i] != 0)
271 strbuf_puts(sb, gen_href_end());
272 }
273 return strbuf_value(sb);
274 }
275 /**
276 * fixed_guide_link_format: make fixed guide
277 *
278 * @param[in] ref (previous, next, first, last, top, bottom) <br>
279 * -1: top, -2: bottom, other: line number
280 * @param[in] anchors
281 * @return HTML
282 */
283 const char *
284 fixed_guide_link_format(int ref[A_LIMIT], const char *anchors)
285 {
286 int i = 0;
287 STATIC_STRBUF(sb);
288
289 strbuf_clear(sb);
290 strbuf_puts(sb, "<!-- beginning of fixed guide -->\n");
291 strbuf_puts(sb, guide_begin);
292 strbuf_putc(sb, '\n');
293 for (i = 0; i < A_LIMIT; i++) {
294 if (i == A_PREV || i == A_NEXT)
295 continue;
296 strbuf_puts(sb, guide_unit_begin);
297 switch (i) {
298 case A_FIRST:
299 case A_LAST:
300 if (ref[i] == 0)
301 strbuf_puts(sb, gen_href_begin(NULL, NULL, NULL, (i == A_FIRST) ? "TOP" : "BOTTOM"));
302 else {
303 char lineno[32];
304 snprintf(lineno, sizeof(lineno), "%d", ref[i]);
305 strbuf_puts(sb, gen_href_begin(NULL, NULL, NULL, lineno));
306 }
307 break;
308 case A_TOP:
309 strbuf_puts(sb, gen_href_begin(NULL, NULL, NULL, "TOP"));
310 break;
311 case A_BOTTOM:
312 strbuf_puts(sb, gen_href_begin(NULL, NULL, NULL, "BOTTOM"));
313 break;
314 case A_INDEX:
315 strbuf_puts(sb, gen_href_begin("..", "mains", normal_suffix, NULL));
316 break;
317 case A_HELP:
318 strbuf_puts(sb, gen_href_begin("..", "help", normal_suffix, NULL));
319 break;
320 default:
321 die("fixed_guide_link_format: something is wrong.(%d)", i);
322 break;
323 }
324 if (Iflag)
325 strbuf_puts(sb, gen_image(PARENT, anchor_icons[i], anchor_label[i]));
326 else
327 strbuf_sprintf(sb, "[%s]", anchor_label[i]);
328 strbuf_puts(sb, gen_href_end());
329 strbuf_puts(sb, guide_unit_end);
330 strbuf_putc(sb, '\n');
331 }
332 strbuf_puts(sb, guide_path_begin);
333 strbuf_puts(sb, anchors);
334 strbuf_puts(sb, guide_path_end);
335 strbuf_putc(sb, '\n');
336 strbuf_puts(sb, guide_end);
337 strbuf_putc(sb, '\n');
338 strbuf_puts(sb, "<!-- end of fixed guide -->\n");
339
340 return strbuf_value(sb);
341 }
342 /**
343 * generate_guide: generate guide string for definition line.
344 *
345 * @param[in] lineno line number
346 * @return guide string
347 */
348 const char *
349 generate_guide(int lineno)
350 {
351 STATIC_STRBUF(sb);
352 int i = 0;
353
354 strbuf_clear(sb);
355 if (definition_header == RIGHT_HEADER)
356 i = 4;
357 else if (nflag)
358 i = ncol + 1;
359 if (i > 0)
360 for (; i > 0; i--)
361 strbuf_putc(sb, ' ');
362 strbuf_sprintf(sb, "%s/* ", comment_begin);
363 strbuf_puts(sb, link_format(anchor_getlinks(lineno)));
364 if (show_position)
365 strbuf_sprintf(sb, "%s%s[+%d %s]%s",
366 quote_space, position_begin, lineno, curpfile, position_end);
367 strbuf_sprintf(sb, " */%s", comment_end);
368
369 return strbuf_value(sb);
370 }
371 /**
372 * tooltip: generate tooltip string
373 *
374 * @param[in] type @CODE{'I'}: 'Included from' <br>
375 * @CODE{'R'}: 'Defined at' <br>
376 * @CODE{'Y'}: 'Used at' <br>
377 * @CODE{'D'}, @CODE{'M'}: 'Referred from'
378 * @param[in] lno line number
379 * @param[in] opt
380 * @return tooltip string
381 */
382 const char *
383 tooltip(int type, int lno, const char *opt)
384 {
385 STATIC_STRBUF(sb);
386
387 strbuf_clear(sb);
388 if (lno > 0) {
389 if (type == 'I')
390 strbuf_puts(sb, "Included from");
391 else if (type == 'R')
392 strbuf_puts(sb, "Defined at");
393 else if (type == 'Y')
394 strbuf_puts(sb, "Used at");
395 else
396 strbuf_puts(sb, "Referred from");
397 strbuf_putc(sb, ' ');
398 strbuf_putn(sb, lno);
399 if (opt) {
400 strbuf_puts(sb, " in ");
401 strbuf_puts(sb, opt);
402 }
403 } else {
404 strbuf_puts(sb, "Multiple ");
405 if (type == 'I')
406 strbuf_puts(sb, "included from");
407 else if (type == 'R')
408 strbuf_puts(sb, "defined in");
409 else if (type == 'Y')
410 strbuf_puts(sb, "used in");
411 else
412 strbuf_puts(sb, "referred from");
413 strbuf_putc(sb, ' ');
414 strbuf_puts(sb, opt);
415 strbuf_putc(sb, ' ');
416 strbuf_puts(sb, "places");
417 }
418 strbuf_putc(sb, '.');
419 return strbuf_value(sb);
420 }
421 /**
422 * put_anchor: output HTML anchor.
423 *
424 * @param[in] name tag
425 * @param[in] type tag type. @CODE{'R'}: @NAME{GTAGS} <br>
426 * @CODE{'Y'}: @NAME{GSYMS} <br>
427 * @CODE{'D'}, @CODE{'M'}, @CODE{'T'}: @NAME{GRTAGS}
428 * @param[in] lineno current line no
429 */
430 void
431 put_anchor(char *name, int type, int lineno)
432 {
433 const char *line;
434 int db;
435
436 if (type == 'R')
437 db = GTAGS;
438 else if (type == 'Y')
439 db = GSYMS;
440 else /* 'D', 'M' or 'T' */
441 db = GRTAGS;
442 line = cache_get(db, name);
443 if (line == NULL) {
444 if ((type == 'R' || type == 'Y') && wflag) {
445 warning("%s %d %s(%c) found but not defined.",
446 curpfile, lineno, name, type);
447 if (colorize_warned_line)
448 warned = 1;
449 }
450 strbuf_puts(outbuf, name);
451 } else {
452 /*
453 * About the format of 'line', please see the head comment of cache.c.
454 */
455 if (*line == ' ') {
456 const char *fid = line + 1;
457 const char *count = nextstring(fid);
458 const char *dir, *file, *suffix = NULL;
459
460 if (dynamic) {
461 STATIC_STRBUF(sb);
462
463 strbuf_clear(sb);
464 strbuf_puts(sb, action);
465 strbuf_putc(sb, '?');
466 strbuf_puts(sb, "pattern=");
467 strbuf_puts(sb, name);
468 strbuf_puts(sb, quote_amp);
469 if (Sflag) {
470 strbuf_puts(sb, "id=");
471 strbuf_puts(sb, sitekey);
472 strbuf_puts(sb, quote_amp);
473 }
474 strbuf_puts(sb, "type=");
475 if (db == GTAGS)
476 strbuf_puts(sb, "definitions");
477 else if (db == GRTAGS)
478 strbuf_puts(sb, "reference");
479 else
480 strbuf_puts(sb, "symbol");
481 file = strbuf_value(sb);
482 dir = (*action == '/') ? NULL : "..";
483 } else {
484 if (type == 'R')
485 dir = upperdir(DEFS);
486 else if (type == 'Y')
487 dir = upperdir(SYMS);
488 else /* 'D', 'M' or 'T' */
489 dir = upperdir(REFS);
490 file = fid;
491 suffix = HTML;
492 }
493 strbuf_puts(outbuf, gen_href_begin_with_title(dir, file, suffix, NULL, tooltip(type, -1, count)));
494 strbuf_puts(outbuf, name);
495 strbuf_puts(outbuf, gen_href_end());
496 } else {
497 const char *lno = line;
498 const char *fid = nextstring(line);
499 const char *path = gpath_fid2path(fid, NULL);
500
501 path += 2; /* remove './' */
502 /*
503 * Don't make a link which refers to itself.
504 * Being used only once means that it is a self link.
505 */
506 if (db == GSYMS) {
507 strbuf_puts(outbuf, name);
508 return;
509 }
510 strbuf_puts(outbuf, gen_href_begin_with_title(upperdir(SRCS), fid, HTML, lno, tooltip(type, atoi(lno), path)));
511 strbuf_puts(outbuf, name);
512 strbuf_puts(outbuf, gen_href_end());
513 }
514 }
515 }
516 /**
517 * put_anchor_force: output HTML anchor without warning.
518 *
519 * @param[in] name tag
520 * @param[in] length
521 * @param[in] lineno current line no
522 *
523 * @remark The tag type is fixed at 'R' (@NAME{GTAGS})
524 */
525 void
526 put_anchor_force(char *name, int length, int lineno)
527 {
528 STATIC_STRBUF(sb);
529 int saveflag = wflag;
530
531 strbuf_clear(sb);
532 strbuf_nputs(sb, name, length);
533 wflag = 0;
534 put_anchor(strbuf_value(sb), 'R', lineno);
535 wflag = saveflag;
536 }
537 /**
538 * put_include_anchor: output HTML anchor.
539 *
540 * @param[in] inc inc structure
541 * @param[in] path path name for display
542 */
543 void
544 put_include_anchor(struct data *inc, const char *path)
545 {
546 if (inc->count == 1)
547 strbuf_puts(outbuf, gen_href_begin(NULL, path2fid(strbuf_value(inc->contents)), HTML, NULL));
548 else {
549 char id[32];
550 snprintf(id, sizeof(id), "%d", inc->id);
551 strbuf_puts(outbuf, gen_href_begin(upperdir(INCS), id, HTML, NULL));
552 }
553 strbuf_puts(outbuf, path);
554 strbuf_puts(outbuf, gen_href_end());
555 }
556 /**
557 * put_include_anchor_direct: output HTML anchor.
558 *
559 * @param[in] file normalized path
560 * @param[in] path path name for display
561 */
562 void
563 put_include_anchor_direct(const char *file, const char *path)
564 {
565 strbuf_puts(outbuf, gen_href_begin(NULL, path2fid(file), HTML, NULL));
566 strbuf_puts(outbuf, path);
567 strbuf_puts(outbuf, gen_href_end());
568 }
569 /**
570 * Put a reserved word (@CODE{if}, @CODE{while}, ...)
571 */
572 void
573 put_reserved_word(const char *word)
574 {
575 strbuf_puts(outbuf, reserved_begin);
576 strbuf_puts(outbuf, word);
577 strbuf_puts(outbuf, reserved_end);
578 }
579 /**
580 * Put a macro (@CODE{\#define}, @CODE{\#undef}, ...)
581 */
582 void
583 put_macro(const char *word)
584 {
585 strbuf_puts(outbuf, sharp_begin);
586 strbuf_puts(outbuf, word);
587 strbuf_puts(outbuf, sharp_end);
588 }
589 /**
590 * Print warning message when unknown preprocessing directive is found.
591 */
592 void
593 unknown_preprocessing_directive(const char *word, int lineno)
594 {
595 word = strtrim(word, TRIM_ALL, NULL);
596 warning("unknown preprocessing directive '%s'. [+%d %s]", word, lineno, curpfile);
597 if (colorize_warned_line)
598 warned = 1;
599 }
600 /**
601 * Print warning message when unexpected eof.
602 */
603 void
604 unexpected_eof(int lineno)
605 {
606 warning("unexpected eof. [+%d %s]", lineno, curpfile);
607 if (colorize_warned_line)
608 warned = 1;
609 }
610 /**
611 * Print warning message when unknown @NAME{yacc} directive is found.
612 */
613 void
614 unknown_yacc_directive(const char *word, int lineno)
615 {
616 warning("unknown yacc directive '%s'. [+%d %s]", word, lineno, curpfile);
617 if (colorize_warned_line)
618 warned = 1;
619 }
620 /**
621 * Print warning message when unmatched brace is found.
622 */
623 void
624 missing_left(const char *word, int lineno)
625 {
626 warning("missing left '%s'. [+%d %s]", word, lineno, curpfile);
627 if (colorize_warned_line)
628 warned = 1;
629 }
630 /**
631 * Put a character with HTML quoting.
632 *
633 * @note If you want to put @CODE{'\<'}, @CODE{'\>'} or @CODE{'\&'}, you
634 * should echoc() instead, as this function escapes (fixes) those
635 * characters for HTML.
636 */
637 void
638 put_char(int c)
639 {
640 const char *quoted = HTML_quoting(c);
641
642 if (quoted)
643 strbuf_puts(outbuf, quoted);
644 else
645 strbuf_putc(outbuf, c);
646 }
647 /**
648 * Put a string with HTML quoting.
649 *
650 * @note If you want to put HTML tag itself, you should echos() instead,
651 * as this function escapes (fixes) the characters @CODE{'\<'},
652 * @CODE{'\>'} and @CODE{'\&'} for HTML.
653 */
654 void
655 put_string(const char *s)
656 {
657 for (; *s; s++)
658 put_char(*s);
659 }
660 /**
661 * Put brace (@c '{', @c '}')
662 */
663 void
664 put_brace(const char *text)
665 {
666 strbuf_puts(outbuf, brace_begin);
667 strbuf_puts(outbuf, text);
668 strbuf_puts(outbuf, brace_end);
669 }
670
671 /**
672 * @name common procedure for line control.
673 */
674 /** @{ */
675 static char lineno_format[32];
676 static const char *guide = NULL;
677 /** @} */
678
679 /**
680 * Begin of line processing.
681 */
682 void
683 put_begin_of_line(int lineno)
684 {
685 if (definition_header != NO_HEADER) {
686 if (define_line(lineno))
687 guide = generate_guide(lineno);
688 else
689 guide = NULL;
690 }
691 if (guide && definition_header == BEFORE_HEADER) {
692 fputs_nl(guide, out);
693 guide = NULL;
694 }
695 }
696 /**
697 * End of line processing.
698 *
699 * @param[in] lineno current line number
700 * @par Globals used (input):
701 * @NAME{outbuf}, HTML line image
702 *
703 * The @EMPH{outbuf} (string buffer) has HTML image of the line. <br>
704 * This function flush and clear it.
705 */
706 void
707 put_end_of_line(int lineno)
708 {
709 fputs(gen_name_number(lineno), out);
710 if (nflag)
711 fprintf(out, lineno_format, lineno);
712 if (warned)
713 fputs(warned_line_begin, out);
714
715 /* flush output buffer */
716 fputs(strbuf_value(outbuf), out);
717 strbuf_reset(outbuf);
718
719 if (warned)
720 fputs(warned_line_end, out);
721 if (guide == NULL)
722 fputc('\n', out);
723 else {
724 if (definition_header == RIGHT_HEADER)
725 fputs(guide, out);
726 fputc('\n', out);
727 if (definition_header == AFTER_HEADER) {
728 fputs_nl(guide, out);
729 }
730 guide = NULL;
731 }
732 warned = 0;
733
734 /* save for the other job in this module */
735 last_lineno = lineno;
736 }
737 /**
738 * Encode URL.
739 *
740 * @param[out] sb encoded URL
741 * @param[in] url URL
742 */
743 static void
744 encode(STRBUF *sb, const char *url)
745 {
746 int c;
747
748 while ((c = (unsigned char)*url++) != '\0') {
749 if (isurlchar(c)) {
750 strbuf_putc(sb, c);
751 } else {
752 strbuf_putc(sb, '%');
753 strbuf_putc(sb, "0123456789abcdef"[c >> 4]);
754 strbuf_putc(sb, "0123456789abcdef"[c & 0x0f]);
755 }
756 }
757 }
758 /**
759 * get_cvs_module: return @NAME{CVS} module of source file.
760 *
761 * @param[in] file source path
762 * @param[out] basename If @a basename is not @CODE{NULL}, store pointer to <br>
763 * the last component of source path.
764 * @return !=NULL : relative path from repository top <br>
765 * ==NULL : CVS/Repository is not readable.
766 */
767 static const char *
768 get_cvs_module(const char *file, const char **basename)
769 {
770 const char *p;
771 STATIC_STRBUF(dir);
772 static char prev_dir[MAXPATHLEN];
773 STATIC_STRBUF(module);
774 FILE *ip;
775
776 strbuf_clear(dir);
777 p = locatestring(file, "/", MATCH_LAST);
778 if (p != NULL) {
779 strbuf_nputs(dir, file, p - file);
780 p++;
781 } else {
782 strbuf_putc(dir, '.');
783 p = file;
784 }
785 if (basename != NULL)
786 *basename = p;
787 if (strcmp(strbuf_value(dir), prev_dir) != 0) {
788 strlimcpy(prev_dir, strbuf_value(dir), sizeof(prev_dir));
789 strbuf_clear(module);
790 strbuf_puts(dir, "/CVS/Repository");
791 ip = fopen(strbuf_value(dir), "r");
792 if (ip != NULL) {
793 strbuf_fgets(module, ip, STRBUF_NOCRLF);
794 fclose(ip);
795 }
796 }
797 if (strbuf_getlen(module) > 0)
798 return strbuf_value(module);
799 return NULL;
800 }
801 /**
802 *
803 * src2html: convert source code into HTML
804 *
805 * @param[in] src source file - Read from
806 * @param[in] html HTML file - Write to
807 * @param[in] notsource 1: isn't source, 0: source.
808 */
809 void
810 src2html(const char *src, const char *html, int notsource)
811 {
812 char indexlink[128];
813
814 /*
815 * setup lineno format.
816 */
817 snprintf(lineno_format, sizeof(lineno_format), "%%%dd ", ncol);
818
819 fileop_in = open_input_file(src);
820 in = get_descripter(fileop_in);
821 curpfile = src;
822 warned = 0;
823
824 fileop_out = open_output_file(html, cflag);
825 out = get_descripter(fileop_out);
826 strbuf_clear(outbuf);
827
828 snprintf(indexlink, sizeof(indexlink), "../mains.%s", normal_suffix);
829 fputs_nl(gen_page_begin(src, SUBDIR), out);
830 fputs_nl(body_begin, out);
831 /*
832 * print fixed guide
833 */
834 if (fixed_guide)
835 fputs(fixed_guide_link_format(anchor_getlinks(0), fill_anchor(NULL, src)), out);
836 /*
837 * print the header
838 */
839 if (insert_header)
840 fputs(gen_insert_header(SUBDIR), out);
841 fputs(gen_name_string("TOP"), out);
842 fputs(header_begin, out);
843 fputs(fill_anchor(indexlink, src), out);
844 if (cvsweb_url) {
845 STATIC_STRBUF(sb);
846 const char *module, *basename;
847
848 strbuf_clear(sb);
849 strbuf_puts(sb, cvsweb_url);
850 if (use_cvs_module
851 && (module = get_cvs_module(src, &basename)) != NULL) {
852 encode(sb, module);
853 strbuf_putc(sb, '/');
854 encode(sb, basename);
855 } else {
856 encode(sb, src);
857 }
858 if (cvsweb_cvsroot) {
859 strbuf_puts(sb, "?cvsroot=");
860 strbuf_puts(sb, cvsweb_cvsroot);
861 }
862 fputs(quote_space, out);
863 fputs(gen_href_begin_simple(strbuf_value(sb)), out);
864 fputs(cvslink_begin, out);
865 fputs("[CVS]", out);
866 fputs(cvslink_end, out);
867 fputs_nl(gen_href_end(), out);
868 /* doesn't close string buffer */
869 }
870 fputs_nl(header_end, out);
871 fputs(comment_begin, out);
872 fputs("/* ", out);
873
874 fputs(link_format(anchor_getlinks(0)), out);
875 if (show_position)
876 fprintf(out, "%s%s[+1 %s]%s", quote_space, position_begin, src, position_end);
877 fputs(" */", out);
878 fputs_nl(comment_end, out);
879 fputs_nl(hr, out);
880 /*
881 * It is not source file.
882 */
883 if (notsource) {
884 STRBUF *sb = strbuf_open(0);
885 const char *_;
886
887 fputs_nl(verbatim_begin, out);
888 last_lineno = 0;
889 while ((_ = strbuf_fgets(sb, in, STRBUF_NOCRLF)) != NULL) {
890 fputs(gen_name_number(++last_lineno), out);
891 detab_replacing(out, _, HTML_quoting);
892 }
893 fputs_nl(verbatim_end, out);
894 strbuf_close(sb);
895 }
896 /*
897 * It's source code.
898 */
899 else {
900 const char *basename;
901 struct data *incref;
902 struct anchor *ancref;
903 STATIC_STRBUF(define_index);
904
905 /*
906 * INCLUDED FROM index.
907 */
908 basename = locatestring(src, "/", MATCH_LAST);
909 if (basename)
910 basename++;
911 else
912 basename = src;
913 incref = get_included(basename);
914 if (incref) {
915 char s_id[32];
916 const char *dir, *file, *suffix, *key, *title;
917
918 fputs(header_begin, out);
919 if (incref->ref_count > 1) {
920 char s_count[32];
921
922 snprintf(s_count, sizeof(s_count), "%d", incref->ref_count);
923 snprintf(s_id, sizeof(s_id), "%d", incref->id);
924 dir = upperdir(INCREFS);
925 file = s_id;
926 suffix = HTML;
927 key = NULL;
928 title = tooltip('I', -1, s_count);
929 } else {
930 const char *p = strbuf_value(incref->ref_contents);
931 const char *lno = strmake(p, " ");
932 const char *filename;
933
934 p = locatestring(p, " ", MATCH_FIRST);
935 if (p == NULL)
936 die("internal error.(incref->ref_contents)");
937 filename = p + 1;
938 if (filename[0] == '.' && filename[1] == '/')
939 filename += 2;
940 dir = NULL;
941 file = path2fid(filename);
942 suffix = HTML;
943 key = lno;
944 title = tooltip('I', atoi(lno), filename);
945 }
946 fputs(gen_href_begin_with_title(dir, file, suffix, key, title), out);
947 fputs(title_included_from, out);
948 fputs(gen_href_end(), out);
949 fputs_nl(header_end, out);
950 fputs_nl(hr, out);
951 }
952 /*
953 * DEFINITIONS index.
954 */
955 strbuf_clear(define_index);
956 for (ancref = anchor_first(); ancref; ancref = anchor_next()) {
957 if (ancref->type == 'D') {
958 char tmp[32];
959 snprintf(tmp, sizeof(tmp), "%d", ancref->lineno);
960 strbuf_puts(define_index, item_begin);
961 strbuf_puts(define_index, gen_href_begin_with_title(NULL, NULL, NULL, tmp, tooltip('R', ancref->lineno, NULL)));
962 strbuf_puts(define_index, gettag(ancref));
963 strbuf_puts(define_index, gen_href_end());
964 strbuf_puts_nl(define_index, item_end);
965 }
966 }
967 if (strbuf_getlen(define_index) > 0) {
968 fputs(header_begin, out);
969 fputs(title_define_index, out);
970 fputs_nl(header_end, out);
971 fputs_nl("This source file includes following definitions.", out);
972 fputs_nl(list_begin, out);
973 fputs(strbuf_value(define_index), out);
974 fputs_nl(list_end, out);
975 fputs_nl(hr, out);
976 }
977 /*
978 * print source code
979 */
980 fputs_nl(verbatim_begin, out);
981 {
982 const char *suffix = locatestring(src, ".", MATCH_LAST);
983 const char *lang = NULL;
984 struct lang_entry *ent;
985
986 /*
987 * Decide language.
988 */
989 if (suffix)
990 lang = decide_lang(suffix);
991 /*
992 * Select parser.
993 * If lang == NULL then default parser is selected.
994 */
995 ent = get_lang_entry(lang);
996 /*
997 * Initialize parser.
998 */
999 ent->init_proc(in);
1000 /*
1001 * Execute parser.
1002 * Exec_proc() is called repeatedly until returning EOF.
1003 */
1004 while (ent->exec_proc())
1005 ;
1006 }
1007 fputs_nl(verbatim_end, out);
1008 }
1009 fputs_nl(hr, out);
1010 fputs_nl(gen_name_string("BOTTOM"), out);
1011 fputs(comment_begin, out);
1012 fputs("/* ", out);
1013 fputs(link_format(anchor_getlinks(-1)), out);
1014 if (show_position)
1015 fprintf(out, "%s%s[+%d %s]%s", quote_space, position_begin, last_lineno, src, position_end);
1016 fputs(" */", out);
1017 fputs_nl(comment_end, out);
1018 if (insert_footer) {
1019 fputs(br, out);
1020 fputs(gen_insert_footer(SUBDIR), out);
1021 }
1022 fputs_nl(body_end, out);
1023 fputs_nl(gen_page_end(), out);
1024 if (!notsource)
1025 anchor_unload();
1026 close_file(fileop_out);
1027 close_file(fileop_in);
1028 }
/* */