## root/htags/src2html.c(218.html)

/* [<][>][^][v][top][bottom][index][help] */

## DEFINITIONS

This source file includes following definitions.

1. get_lang_entry
2. echoc
3. echos
4. HTML_quoting
5. fill_anchor
6. link_format
7. generate_guide
8. tooltip
9. put_anchor
10. put_include_anchor
11. put_reserved_word
12. put_macro
13. unknown_preprocessing_directive
14. unexpected_eof
15. unknown_yacc_directive
16. missing_left
17. put_char
18. put_string
19. put_brace
20. put_begin_of_line
21. put_end_of_line
22. encode
23. get_cvs_module
24. src2html
25. add_comtfield

    /*
     * Copyright (c) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
     *              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 <http://www.gnu.org/licenses/>.
     */

    #ifdef HAVE_CONFIG_H
    #include <config.h>
    #endif
    #include <stdio.h>
    #ifdef STDC_HEADERS
    #include <stdlib.h>
    #endif
    #include <ctype.h>

    #include "global.h"
    #include "anchor.h"
    #include "cache.h"
    #include "common.h"
    #include "incop.h"
    #include "path2url.h"
    #include "htags.h"

    /*----------------------------------------------------------------------*/
    /* Parser switch                                                        */
    /*----------------------------------------------------------------------*/
    /*
     * This is the linkage section of each parsers.
     * If you want to support new language, you must define two procedures:
     *      1. Initializing procedure.
     *              Called once first with an input file descripter.
     *      2. Executing procedure.
     *              Called repeatedly until returning EOF.
     *              It should read from above descripter and write HTML
     *              using output procedures in this module.
     */
    struct lang_entry {
            const char *lang_name;
            void (*init_proc)(FILE *);              /* initializing procedure */
            int (*exec_proc)(void);                 /* executing procedure */
    };

    /* initializing procedures */
    void c_parser_init(FILE *);
    void yacc_parser_init(FILE *);
    void cpp_parser_init(FILE *);
    void java_parser_init(FILE *);
    void php_parser_init(FILE *);
    void asm_parser_init(FILE *);

    /* executing procedures */
    int c_lex(void);
    int cpp_lex(void);
    int java_lex(void);
    int php_lex(void);
    int asm_lex(void);

    /*
     * The first entry is default language.
     */
    struct lang_entry lang_switch[] = {
            /* lang_name    init_proc               exec_proc */
            {"c",           c_parser_init,          c_lex},         /* DEFAULT */
            {"yacc",        yacc_parser_init,       c_lex},
            {"cpp",         cpp_parser_init,        cpp_lex},
            {"java",        java_parser_init,       java_lex},
            {"php",         php_parser_init,        php_lex},
            {"asm",         asm_parser_init,        asm_lex}
    };
    #define DEFAULT_ENTRY &lang_switch[0]

    /* Stingll adds */
    const char *add_comtfield(const char *);
    const char *nm_html;
    int                     seq_num=0;

    /*
     * get language entry.
     *
     *      i)      lang    language name (NULL means 'not specified'.)
     *      r)              language entry
     */
    static struct lang_entry *
    get_lang_entry(const char *lang)
    {
            int i, size = sizeof(lang_switch) / sizeof(struct lang_entry);

            /*
             * if language not specified, it assumes default language.
             */
            if (lang == NULL)
                    return DEFAULT_ENTRY;
            for (i = 0; i < size; i++)
                    if (!strcmp(lang, lang_switch[i].lang_name))
                            return &lang_switch[i];
            /*
             * if specified language not found, it assumes default language.
             */
            return DEFAULT_ENTRY;
    }
    /*----------------------------------------------------------------------*/
    /* Input/Output                                                         */
    /*----------------------------------------------------------------------*/
    /*
     * Input/Output descriptor.
     */
    static FILEOP *fileop_out;
    static FILEOP *fileop_in;
    static FILE *out;
    static FILE *in;

    STATIC_STRBUF(outbuf);
    static const char *curpfile;
    static int warned;
    static int last_lineno;

    /*
     * Put a character to HTML as is.
     *
     * You should use this function to put a control character.
     */
    void
    echoc(int c)
    {
            strbuf_putc(outbuf, c);
    }
    /*
     * Put a string to HTML as is.
     *
     * You should use this function to put a control sequence.
     */
    void
    echos(const char *s)
    {
            strbuf_puts(outbuf, s);
    }
    /*----------------------------------------------------------------------*/
    /* HTML output                                                          */
    /*----------------------------------------------------------------------*/
    /*
     * Quote character with HTML's way.
     */
    static const char *
    HTML_quoting(int c)
    {
            if (c == '<')
                    return quote_little;
            else if (c == '>')
                    return quote_great;
            else if (c == '&')
                    return quote_amp;
            return NULL;
    }
    /*
     * fill_anchor: fill anchor into file name
     *
     *       i)      $root   root or index page
     *       i)      $path   path name
     *       r)              hypertext file name string
     */
    const char *
    fill_anchor(const char *root, const char *path)
    {
            STATIC_STRBUF(sb);
            char buf[MAXBUFLEN], *limit, *p;

            strbuf_clear(sb);
            strlimcpy(buf, path, sizeof(buf));
            for (p = buf; *p; p++)
                    if (*p == sep)
                            *p = '\0';
            limit = p;

            strbuf_sprintf(sb, "%sroot%s/", gen_href_begin_simple(root), gen_href_end());
            {
                    const char *next;

                    for (p = buf; p < limit; p += strlen(p) + 1) {
                            const char *path = buf;
                            const char *unit = p;

                            next = p + strlen(p) + 1;
                            if (next > limit) {
                                    strbuf_puts(sb, unit);
                                    break;
                            }
                            if (p > buf)
                                    *(p - 1) = sep;
                            strbuf_puts(sb, gen_href_begin("../files", path2fid(path), HTML, NULL));
                            strbuf_puts(sb, unit);
                            strbuf_puts(sb, gen_href_end());
                            strbuf_putc(sb, '/');
                    }
        }
        return strbuf_value(sb);
    }

    /*
     * link_format: make hypertext from anchor array.
     *
     *      i)      (previous, next, first, last, top, bottom)
     *              -1: top, -2: bottom, other: line number
     *      r)      HTML
     */
    const char *
    link_format(int ref[A_SIZE])
    {
            STATIC_STRBUF(sb);
            const char **label = Iflag ? anchor_comment : anchor_label;
            const char **icons = anchor_icons;
            int i;

            strbuf_clear(sb);
            for (i = 0; i < A_LIMIT; i++) {
                    if (i == A_INDEX) {
                            strbuf_puts(sb, gen_href_begin("..", "mains", normal_suffix, NULL));
                    } else if (i == A_HELP) {
                            strbuf_puts(sb, gen_href_begin("..", "help", normal_suffix, NULL));
                    } else if (ref[i]) {
                            char tmp[32], *key = tmp;

                            if (ref[i] == -1)
                                    key = "TOP";
                            else if (ref[i] == -2)
                                    key = "BOTTOM";
                            else
                                    snprintf(tmp, sizeof(tmp), "%d", ref[i]);
                            strbuf_puts(sb, gen_href_begin(NULL, NULL, NULL, key));
                    }
                    if (Iflag) {
                            char tmp[MAXPATHLEN];
                            snprintf(tmp, sizeof(tmp), "%s%s", (i != A_INDEX && i != A_HELP && ref[i] == 0) ? "n_" : "", icons[i]);
                            strbuf_puts(sb, gen_image(PARENT, tmp, label[i]));
                    } else {
                            strbuf_sprintf(sb, "[%s]", label[i]);
                    }
                    if (i == A_INDEX || i == A_HELP || ref[i] != 0)
                            strbuf_puts(sb, gen_href_end());
            }
            return strbuf_value(sb);
    }
    /*
     * generate_guide: generate guide string for definition line.
     *
     *      i)      lineno  line number
     *      r)              guide string
     */
    const char *
    generate_guide(int lineno)
    {
            STATIC_STRBUF(sb);
            int i = 0;

            strbuf_clear(sb);
            if (definition_header == RIGHT_HEADER)
                    i = 4;
            else if (nflag)
                    i = ncol + 1;
            if (i > 0)
                    for (; i > 0; i--)
                            strbuf_putc(sb, ' ');
            strbuf_sprintf(sb, "%s/* ", comment_begin);
            strbuf_puts(sb, link_format(anchor_getlinks(lineno)));
            if (show_position)
                    strbuf_sprintf(sb, "%s%s[+%d %s]%s",
                            quote_space, position_begin, lineno, curpfile, position_end);
            strbuf_sprintf(sb, " */%s", comment_end);

            return strbuf_value(sb);
    }
    /*
     * tooltip: generate tooltip string
     *
     *      i)      type    I,R,Y,D,M
     *      i)      lno     line number
     *      i)      opt
     *      r)              tooltip string
     */
    const char *
    tooltip(int type, int lno, const char *opt)
    {
            STATIC_STRBUF(sb);

            strbuf_clear(sb);
            if (lno > 0) {
                    if (type == 'I')
                            strbuf_puts(sb, "Included from");
                    else if (type == 'R')
                            strbuf_puts(sb, "Defined at");
                    else if (type == 'Y')
                            strbuf_puts(sb, "Used at");
                    else
                            strbuf_puts(sb, "Refered from");
                    strbuf_putc(sb, ' ');
                    strbuf_putn(sb, lno);
                    if (opt) {
                            strbuf_puts(sb, " in ");
                            strbuf_puts(sb, opt);
                    }
            } else {
                    strbuf_puts(sb, "Multiple ");
                    if (type == 'I')
                            strbuf_puts(sb, "included from");
                    else if (type == 'R')
                            strbuf_puts(sb, "defined in");
                    else if (type == 'Y')
                            strbuf_puts(sb, "used in");
                    else
                            strbuf_puts(sb, "refered from");
                    strbuf_putc(sb, ' ');
                    strbuf_puts(sb, opt);
                    strbuf_putc(sb, ' ');
                    strbuf_puts(sb, "places");
            }
            strbuf_putc(sb, '.');
            return strbuf_value(sb);
    }
    /*
     * put_anchor: output HTML anchor.
     *
     *      i)      name    tag
     *      i)      type    tag type
     *      i)      lineno  current line no
     */
    void
    put_anchor(char *name, int type, int lineno)
    {
            const char *line;
            int db;

            if (type == 'R')
                    db = GTAGS;
            else if (type == 'Y')
                    db = GSYMS;
            else    /* 'D', 'M' or 'T' */
                    db = GRTAGS;
            line = cache_get(db, name);
            if (line == NULL) {
                    if ((type == 'R' || type == 'Y') && wflag) {
                            warning("%s %d %s(%c) found but not defined.",
                                    curpfile, lineno, name, type);
                            if (colorize_warned_line)
                                    warned = 1;
                    }
                    strbuf_puts(outbuf, name);
            } else {
                    /*
                     * About cache record format, please see the comment in cache.c.
                     */
                    if (*line == ' ') {
                            char tmp[MAXPATHLEN];
                            const char *id = strmake(++line, " ");
                            const char *count = locatestring(line, " ", MATCH_FIRST) + 1;
                            const char *dir, *file, *suffix = NULL;

                            if (dynamic) {
                                    const char *s;

                                    dir = (*action == '/') ? NULL : "..";
                                    if (db == GTAGS)
                                            s = "definitions";
                                    else if (db == GRTAGS)
                                            s = "reference";
                                    else
                                            s = "symbol";
                                    snprintf(tmp, sizeof(tmp), "%s?pattern=%s%stype=%s",
                                            action, name, quote_amp, s);
                                    file = tmp;
                            } else {
                                    if (type == 'R')
                                            dir = upperdir(DEFS);
                                    else if (type == 'Y')
                                            dir = upperdir(SYMS);
                                    else    /* 'D', 'M' or 'T' */
                                            dir = upperdir(REFS);
                                    file = id;
                                    suffix = HTML;
                            }
                            strbuf_puts(outbuf, gen_href_begin_with_title(dir, file, suffix, NULL, tooltip(type, -1, count)));
                            strbuf_puts(outbuf, name);
                            strbuf_puts(outbuf, gen_href_end());
                    } else {
                            char lno[32];
                            const char *filename;

                            /*
                             * Don't make a link which refers to itself.
                             * Being used only once means that it is a self link.
                             */
                            if (db == GSYMS) {
                                    strbuf_puts(outbuf, name);
                                    return;
                            }
                            strlimcpy(lno, strmake(line, " "), sizeof(lno));
                            filename = strmake(locatestring(line, " ", MATCH_FIRST) + 1, " ")
                                                    + 2;    /* remove './' */
                            strbuf_puts(outbuf, gen_href_begin_with_title(upperdir(SRCS), path2fid(filename), HTML, lno, tooltip(type, atoi(lno), filename)));
                            strbuf_puts(outbuf, name);
                            strbuf_puts(outbuf, gen_href_end());
                    }
            }
    }
    /*
     * put_include_anchor: output HTML anchor.
     *
     *      i)      inc     inc structure
     *      i)      path    path name for display
     */
    void
    put_include_anchor(struct data *inc, const char *path)
    {
            if (inc->count == 1)
                    strbuf_puts(outbuf, gen_href_begin(NULL, path2fid(strbuf_value(inc->contents)), HTML, NULL));
            else {
                    char id[32];
                    snprintf(id, sizeof(id), "%d", inc->id);
                    strbuf_puts(outbuf, gen_href_begin(upperdir(INCS), id, HTML, NULL));
            }
            strbuf_puts(outbuf, path);
            strbuf_puts(outbuf, gen_href_end());
    }
    /*
     * Put a reserved word. (if, while, ...)
     */
    void
    put_reserved_word(const char *word)
    {
            strbuf_puts(outbuf, reserved_begin);
            strbuf_puts(outbuf, word);
            strbuf_puts(outbuf, reserved_end);
    }
    /*
     * Put a macro (#define,#undef,...)
     */
    void
    put_macro(const char *word)
    {
            strbuf_puts(outbuf, sharp_begin);
            strbuf_puts(outbuf, word);
            strbuf_puts(outbuf, sharp_end);
    }
    /*
     * Print warning message when unkown preprocessing directive is found.
     */
    void
    unknown_preprocessing_directive(const char *word, int lineno)
    {
            word = strtrim(word, TRIM_ALL, NULL);
            warning("unknown preprocessing directive '%s'. [+%d %s]", word, lineno, curpfile);
            if (colorize_warned_line)
                    warned = 1;
    }
    /*
     * Print warning message when unexpected eof.
     */
    void
    unexpected_eof(int lineno)
    {
            warning("unexpected eof. [+%d %s]", lineno, curpfile);
            if (colorize_warned_line)
                    warned = 1;
    }
    /*
     * Print warning message when unknown yacc directive is found.
     */
    void
    unknown_yacc_directive(const char *word, int lineno)
    {
            warning("unknown yacc directive '%s'. [+%d %s]", word, lineno, curpfile);
            if (colorize_warned_line)
                    warned = 1;
    }
    /*
     * Print warning message when unmatched brace is found.
     */
    void
    missing_left(const char *word, int lineno)
    {
            warning("missing left '%s'. [+%d %s]", word, lineno, curpfile);
            if (colorize_warned_line)
                    warned = 1;
    }
    /*
     * Put a character with HTML quoting.
     *
     * If you want to put '<', '>' and '&', you should echoc() instead.
     */
    void
    put_char(int c)
    {
            const char *quoted = HTML_quoting(c);

            if (quoted)
                    strbuf_puts(outbuf, quoted);
            else
                    strbuf_putc(outbuf, c);
    }
    /*
     * Put a string with HTML quoting.
     *
     * If you want to put HTML tag itself, you should echoc() instead.
     */
    void
    put_string(const char *s)
    {
            for (; *s; s++)
                    put_char(*s);
    }
    /*
     * Put brace ('{', '}')
     */
    void
    put_brace(const char *text)
    {
            strbuf_puts(outbuf, brace_begin);
            strbuf_puts(outbuf, text);
            strbuf_puts(outbuf, brace_end);
    }

    /*
     * common procedure for line control.
     */
    static char lineno_format[32];
    static const char *guide = NULL;

    /*
     * Begin of line processing.
     */
    void
    put_begin_of_line(int lineno)
    {
            if (definition_header != NO_HEADER) {
                    if (define_line(lineno))
                            guide = generate_guide(lineno);
                    else
                            guide = NULL;
            }
            if (guide && definition_header == BEFORE_HEADER) {
                    fputs_nl(guide, out);
                    guide = NULL;
            }
    }
    /*
     * End of line processing.
     *
     *      i)      lineno  current line number
     *      gi)     outbuf  HTML line image
     *
     * The outbuf(string buffer) has HTML image of the line.
     * This function flush and clear it.
     */
    void
    put_end_of_line(int lineno)
    {
            fputs(gen_name_number(lineno), out);
            if (nflag)
                    fprintf(out, lineno_format, lineno);
            if (warned)
                    fputs(warned_line_begin, out);

            /* flush output buffer */
            fputs(strbuf_value(outbuf), out);
            strbuf_reset(outbuf);

            if (warned)
                    fputs(warned_line_end, out);
            if (guide == NULL)
                    fputc('\n', out);
            else {
                    if (definition_header == RIGHT_HEADER)
                            fputs(guide, out);
                    fputc('\n', out);
                    if (definition_header == AFTER_HEADER) {
                            fputs_nl(guide, out);
                    }
                    guide = NULL;
            }
            warned = 0;

            /* save for the other job in this module */
            last_lineno = lineno;
    }
    /*
     * Encode URL.
     *
     *      o)      sb      encoded URL
     *      i)      url     URL
     */
    static void
    encode(STRBUF *sb, const char *url)
    {
            int c;

            while ((c = (unsigned char)*url++) != '\0') {
                    if (isurlchar(c)) {
                            strbuf_putc(sb, c);
                    } else {
                            strbuf_putc(sb, '%');
                            strbuf_putc(sb, "0123456789abcdef"[c >> 4]);
                            strbuf_putc(sb, "0123456789abcdef"[c & 0x0f]);
                    }
            }
    }
    /*
     * get_cvs_module: return CVS module of source file.
     *
     *      i)      file            source path
     *      o)      basename        If basename is not NULL, store pointer to
     *                              the last component of source path.
     *      r)              !=NULL : relative path from repository top
     *                      ==NULL : CVS/Repository is not readable.
     */
    static const char *
    get_cvs_module(const char *file, const char **basename)
    {
            const char *p;
            STATIC_STRBUF(dir);
            static char prev_dir[MAXPATHLEN+1];
            STATIC_STRBUF(module);
            FILE *ip;

            strbuf_clear(dir);
            p = locatestring(file, "/", MATCH_LAST);
            if (p != NULL) {
                    strbuf_nputs(dir, file, p - file);
                    p++;
            } else {
                    strbuf_putc(dir, '.');
                    p = file;
            }
            if (basename != NULL)
                    *basename = p;
            if (strcmp(strbuf_value(dir), prev_dir) != 0) {
                    strlimcpy(prev_dir, strbuf_value(dir), sizeof(prev_dir));
                    strbuf_clear(module);
                    strbuf_puts(dir, "/CVS/Repository");
                    ip = fopen(strbuf_value(dir), "r");
                    if (ip != NULL) {
                            strbuf_fgets(module, ip, STRBUF_NOCRLF);
                            fclose(ip);
                    }
            }
            if (strbuf_getlen(module) > 0)
                    return strbuf_value(module);
            return NULL;
    }
    /*
     *
     * src2html: convert source code into HTML
     *
     *       i)      src   source file     - Read from
     *       i)      html  HTML file       - Write to
     *       i)      notsource 1: isn't source, 0: source.
     */
    void
    src2html(const char *src, const char *html, int notsource)
    {
            char indexlink[128];
            const char *ph;
            const char *titlename;
        char addflnmhtml[135];

        memset(addflnmhtml,0,135);

            ph = locatestring(html, "/", MATCH_LAST);
            if (ph != NULL) {
                    ph++;
            printf("src2html:src->(%s),html->(%s),html_file->(%s)\n",src,html,ph);
        }
            /*
             * setup lineno format.
             */
            snprintf(lineno_format, sizeof(lineno_format), "%%%dd ", ncol);

            fileop_in  = open_input_file(src);
            in = get_descripter(fileop_in);
            curpfile = src;
            warned = 0;

            fileop_out = open_output_file(html, cflag);
            out = get_descripter(fileop_out);
            strbuf_clear(outbuf);

            if (Fflag)
                    snprintf(indexlink, sizeof(indexlink), "../files.%s", normal_suffix);
            else
                    snprintf(indexlink, sizeof(indexlink), "../mains.%s", normal_suffix);
            fputs_nl(gen_page_begin(src, SUBDIR), out);
            fputs_nl(body_begin, out);
            /*
         * print the header
         */
            if (insert_header)
                    fputs(gen_insert_header(SUBDIR), out);
            fputs(gen_name_string("TOP"), out);
            fputs(header_begin, out);
            /*fputs(fill_anchor(indexlink, src), out);*/
            titlename = fill_anchor(indexlink, src);
        sprintf(&addflnmhtml[0],"%s(%s)",titlename,ph);
        nm_html = ph;
            fputs(&addflnmhtml[0], out);
        seq_num = 1;
            if (cvsweb_url) {
                    STATIC_STRBUF(sb);
                    const char *module, *basename;

                    strbuf_clear(sb);
                    strbuf_puts(sb, cvsweb_url);
                    if (use_cvs_module
                     && (module = get_cvs_module(src, &basename)) != NULL) {
                            encode(sb, module);
                            strbuf_putc(sb, '/');
                            encode(sb, basename);
                    } else {
                            encode(sb, src);
                    }
                    if (cvsweb_cvsroot) {
                            strbuf_puts(sb, "?cvsroot=");
                            strbuf_puts(sb, cvsweb_cvsroot);
                    }
                    fputs(quote_space, out);
                    fputs(gen_href_begin_simple(strbuf_value(sb)), out);
                    fputs(cvslink_begin, out);
                    fputs("[CVS]", out);
                    fputs(cvslink_end, out);
                    fputs_nl(gen_href_end(), out);
                    /* doesn't close string buffer */
            }
            fputs_nl(header_end, out);
            fputs(comment_begin, out);
            fputs("/* ", out);

            fputs(link_format(anchor_getlinks(0)), out);
            if (show_position)
                    fprintf(out, "%s%s[+1 %s]%s", quote_space, position_begin, src, position_end);
            fputs(" */", out);
            fputs_nl(comment_end, out);
            fputs_nl(hr, out);
            /*
             * It is not source file.
             */
            if (notsource) {
                    STRBUF *sb = strbuf_open(0);
                    const char *_;

                    fputs_nl(verbatim_begin, out);
                    last_lineno = 0;
                    while ((_ = strbuf_fgets(sb, in, STRBUF_NOCRLF)) != NULL) {
                            fputs(gen_name_number(++last_lineno), out);
                            detab_replacing(out, _, HTML_quoting);
                    }
                    fputs_nl(verbatim_end, out);
                    strbuf_close(sb);
            }
            /*
             * It's source code.
             */
            else {
                    const char *basename;
                    struct data *incref;
                    struct anchor *ancref;
                    STATIC_STRBUF(define_index);

            /*
             * INCLUDED FROM index.
             */
                    basename = locatestring(src, "/", MATCH_LAST);
                    if (basename)
                            basename++;
                    else
                            basename = src;
                    incref = get_included(basename);
                    if (incref) {
                            char s_id[32];
                            const char *dir, *file, *suffix, *key, *title;

                            fputs(header_begin, out);
                            if (incref->ref_count > 1) {
                                    char s_count[32];

                                    snprintf(s_count, sizeof(s_count), "%d", incref->ref_count);
                                    snprintf(s_id, sizeof(s_id), "%d", incref->id);
                                    dir = upperdir(INCREFS);
                                    file = s_id;
                                    suffix = HTML;
                                    key = NULL;
                                    title = tooltip('I', -1, s_count);
                            } else {
                                    const char *p = strbuf_value(incref->ref_contents);
                                    const char *lno = strmake(p, " ");
                                    const char *filename;

                                    p = locatestring(p, " ", MATCH_FIRST);
                                    if (p == NULL)
                                            die("internal error.(incref->ref_contents)");
                                    filename = p + 1;
                                    if (filename[0] == '.' && filename[1] == '/')
                                            filename += 2;
                                    dir = NULL;
                                    file = path2fid(filename);

                                    suffix = HTML;
                                    key = lno;
                                    title = tooltip('I', atoi(lno), filename);
                            }
                            fputs(gen_href_begin_with_title(dir, file, suffix, key, title), out);
                            fputs(title_included_from, out);
                            fputs(gen_href_end(), out);
                            fputs_nl(header_end, out);
                            fputs_nl(hr, out);
                    }
                    /*
                     * DEFINITIONS index.
                     */
                    strbuf_clear(define_index);
                    for (ancref = anchor_first(); ancref; ancref = anchor_next()) {
                            if (ancref->type == 'D') {
                                    char tmp[32];
                                    snprintf(tmp, sizeof(tmp), "%d", ancref->lineno);
                                    strbuf_puts(define_index, item_begin);
                                    strbuf_puts(define_index, gen_href_begin_with_title(NULL, NULL, NULL, tmp, tooltip('R', ancref->lineno, NULL)));
                                    strbuf_puts(define_index, gettag(ancref));
                                    strbuf_puts(define_index, gen_href_end());
                                    strbuf_puts_nl(define_index, item_end);
                            }
                    }
                    if (strbuf_getlen(define_index) > 0) {
                            fputs(header_begin, out);
                            fputs(title_define_index, out);
                            fputs_nl(header_end, out);
                            fputs_nl("This source file includes following definitions.", out);
                            fputs_nl(list_begin, out);
                            fputs(strbuf_value(define_index), out);
                            fputs_nl(list_end, out);
                            fputs_nl(hr, out);
                    }
                    /*
                     * print source code
                     */
                    fputs_nl(verbatim_begin, out);
                    {
                            const char *suffix = locatestring(src, ".", MATCH_LAST);
                            const char *lang = NULL;
                            struct lang_entry *ent;

                            /*
                             * Decide language.
                             */
                            if (suffix)
                                    lang = decide_lang(suffix);
                            /*
                             * Select parser.
                             * If lang == NULL then default parser is selected.
                             */
                            ent = get_lang_entry(lang);
                            /*
                             * Initialize parser.
                             */
                            ent->init_proc(in);
                            /*
                             * Execute parser.
                             * Exec_proc() is called repeatedly until returning EOF.
                             */
                            while (ent->exec_proc())
                                    ;
                    }
                    fputs_nl(verbatim_end, out);
            }
            fputs_nl(hr, out);
            fputs_nl(gen_name_string("BOTTOM"), out);
            fputs(comment_begin, out);
            fputs("/* ", out);
            fputs(link_format(anchor_getlinks(-1)), out);
            if (show_position)
                    fprintf(out, "%s%s[+%d %s]%s", quote_space, position_begin, last_lineno, src, position_end);
            fputs(" */", out);
            fputs_nl(comment_end, out);
            if (insert_footer) {
                    fputs(br, out);
                    fputs(gen_insert_footer(SUBDIR), out);
            }
            fputs_nl(body_end, out);
            fputs_nl(gen_page_end(), out);
            if (!notsource)
                    anchor_unload();
            close_file(fileop_out);
            close_file(fileop_in);
    }

    const char *add_comtfield(const char *s)
    {
            char htmlwords[512];

            memset(htmlwords,0,512);
            sprintf(&htmlwords[0],"<form method=\'post\' action=\'cgi-bin/comtup.cgi\'><input type=\'hidden\' name=\'%s\' value=\'%06d\'>\
    <textarea rows=\'1\' name=\'%s-%06d\' value=\'\'></textarea><input type=\'submit\' value=\'Update\'></form>",nm_html,seq_num,nm_html,seq_num);
            seq_num++;
            return htmlwords;
    }

/* [<][>][^][v][top][bottom][index][help] */