## root/htags/fileindex.c

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

## DEFINITIONS

This source file includes following definitions.

1. getpath
2. ungetpath
3. extract_lastname
4. lastpart
5. dirpart
6. localpath
7. appendslash
8. removedotslash
9. insert_comma
10. print_directory
11. print_directory_header
12. print_directory_footer
13. print_file_name
14. print_directory_name
15. makefileindex
16. makeincludeindex

    /*
     * 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 <ctype.h>
    #include <stdio.h>
    #ifdef STDC_HEADERS
    #include <stdlib.h>
    #endif
    #ifdef HAVE_STRING_H
    #include <string.h>
    #else
    #include <strings.h>
    #endif

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

    /*----------------------------------------------------------------------*/
    /* Find list procedures                                                 */
    /*----------------------------------------------------------------------*/
    static const char *getpath(void);
    static void ungetpath(void);
    static GFIND *gp;
    static int retry;
    /*
     * get a path from input stream.
     *
     * Each path name must start with "./".
     */
    static const char *
    getpath(void)
    {
            static const char *buff;

            if (!retry) {
                    /* skip README or ChangeLog unless the -o option specified. */
                    do {
                            buff = gfind_read(gp);
                    } while (buff && gp->type == GPATH_OTHER && !other_files);
            }
            retry = 0;
            return buff;
    }
    /*
     * push back a path name.
     */
    static void
    ungetpath(void)
    {
            retry = 1;
    }
    /*----------------------------------------------------------------------*/
    /* Path name operation procedures                                       */
    /*----------------------------------------------------------------------*/
    static const char *extract_lastname(const char *, int);
    static const char *lastpart(const char *);
    static const char *dirpart(const char *, char *);
    static const char *localpath(const char *, char *);
    static const char *appendslash(const char *);
    static const char *insert_comma(unsigned int);

    /*
     * extract_lastname: extract the last name of include line.
     *
     *      i)      image   source image of include
     *      i)      is_php  1: is PHP source
     *      r)              last name
     */
    static const char *
    extract_lastname(const char *image, int is_php)
    {
            static char buf[MAXBUFLEN];
            const char *p;
            char *q;
            int sep;

            /*
             * C:   #include <xxx/yyy/zzz.h>
             *      #include "xxx/yyy/zzz.h"
             * PHP: include('xxx/yyy/zzz');
             */
            p = image;
            while (*p && isspace((unsigned char)*p))                /* skip space */
                    p++;
            if (!*p)
                    return NULL;
            if (*p == '#') {
                    if (is_php)
                            return NULL;
                    p++;
                    while (*p && isspace((unsigned char)*p))        /* skip space */
                            p++;
                    if (!*p)
                            return NULL;
            }
            /*
             * If match to one of the include keywords then points
             * the following character of the keyword.
             *            p
             *            v
             * ... include ....
             */
            if (is_php) {
                    if ((p = locatestring(p, "include", MATCH_AT_FIRST)) == NULL)
                            return NULL;
            } else {
                    char *q;

                    if (((q = locatestring(p, "include_next", MATCH_AT_FIRST)) == NULL) &&
                        ((q = locatestring(p, "import", MATCH_AT_FIRST)) == NULL) &&
                        ((q = locatestring(p, "include", MATCH_AT_FIRST)) == NULL))
                            return NULL;
                    p = q;
            }
            while (*p && isspace((unsigned char)*p))                /* skip space */
                    p++;
            if (is_php && *p == '(') {
                    p++;
                    while (*p && isspace((unsigned char)*p))        /* skip space */
                            p++;
            }
            sep = *p;
            if (is_php) {
                    if (sep != '\'' && sep != '"')
                            return NULL;
            } else {
                    if (sep != '<' && sep != '"')
                            return NULL;
            }
            if (sep == '<')
                    sep = '>';
            p++;
            if (!*p)
                    return NULL;
            q = buf;
            while (*p && *p != '\n' && *p != sep)
                    *q++ = *p++;
            *q = '\0';
            if (*p == sep) {
                    q = locatestring(buf, "/", MATCH_LAST);
                    if (q)
                            q++;
                    else
                            q = buf;
                    return q;
            }
            return NULL;
    }
    /*
     * get the last part of the path.
     *
     *      i)      path    path name
     *      r)              last part
     * Ex.
     * lastpart("a/b")      => "b"
     * lastpart("a")        => "a"
     */
    static const char *
    lastpart(const char *path)
    {
            const char *p = strrchr(path, '/');

            return p ? p + 1 : path;
    }
    /*
     * get the directory part of the path.
     *
     *      i)      path    path name
     *      o)      result  result buffer
     *      r)              directory part
     * Ex.
     * dirpart("a/b/c")     => "a/b"
     */
    static const char *
    dirpart(const char *path, char *result)
    {
            char *p = result;
            const char *q = path, *limit = strrchr(path, '/');

            while (q < limit)
                    *p++ = *q++;
            *p = '\0';
            return result;
    }
    /*
     * get the local path name if the path is under the dir.
     *
     *      i)      path    path name
     *      i)      dir     directory name
     *      r)              local path name
     *
     * Ex.
     * localpath("a/b/c", "a/b")    => "c"
     * localpath("a/b/c/d", "a/b")  => "c/d"
     * localpath("a/b/c", "a/d")    => NULL
     */
    static const char *
    localpath(const char *path, char *dir)
    {
            int length = strlen(dir);

            if (!strncmp(path, dir, length) && *(path + length) == '/')
                    return path + length + 1;
            return NULL;
    }
    /*
     * append '/' after the path name
     *
     *      i)      path    path name
     *      r)              appended path name
     *
     * Ex.
     * appendslash("a")     => "a/"
     */
    static const char *
    appendslash(const char *path)
    {
            STATIC_STRBUF(sb);

            strbuf_clear(sb);
            strbuf_puts(sb, path);
            strbuf_putc(sb, '/');
            return strbuf_value(sb);
    }
    /*
     * remove './' at the head of the path name
     *
     *      i)      path    path name
     *      r)              removed path name
     *
     * Ex.
     * removedotslash("./a") => "a"
     */
    static const char *
    removedotslash(const char *path)
    {
            return (*path == '.' && *(path + 1) == '/') ? path + 2 : path;
    }
    /*
     * insert_comma: insert comma to the number.
     *
     *      i)      n       number
     *      r)              edited string
     *
     * Ex.
     * 10000 => 10,000
     */
    static const char *
    insert_comma(unsigned int n)
    {
    #define RESULTSIZE 15
    #define INTERVAL 3
            static char result[RESULTSIZE];
            int i = RESULTSIZE;
            int count = 0;

            if (n == 0)
                    return (const char *)"0";
            if (n > 1000000000)
                    goto giveup;
            result[--i] = '\0';
            for (; n > 0; n = n / 10) {
                    /*
                     * Buffer overflow. This is not important even if occurring.
                     */
                    if (i <= 0)
                            goto giveup;
                    if (count && count % INTERVAL == 0)
                            result[--i] = ',';
                    result[--i] = n % 10 + '0';
                    count++;
            }
            return (const char *)&result[i];
    giveup:
            snprintf(result, sizeof(result), "*****");
            return (const char *)result;
    }
    /*----------------------------------------------------------------------*/
    /* Generating file index                                                */
    /*----------------------------------------------------------------------*/
    static int print_directory(int, char *);
    static void print_directory_header(FILE *, int, const char *);
    static void print_directory_footer(FILE *, int, const char *);
    static const char *print_file_name(int, const char *);
    static const char *print_directory_name(int, const char *, int);

    FILE *FILEMAP;
    STRBUF *files;
    const char *indexlink;
    regex_t is_include_file;
    int src_count;

    /*
     * print contents of one directory and the descendant. (recursively called)
     *
     *      i)      level   directory nest level
     *      io)     basedir current directory
     *
     * This function read find style records, and print directory tree.
     */
    /*
     * File list of the top level directory (when level == 0) is not written
     * to a file directly. Instead, it is written to string buffer, because
     * it appears in some places.
     */
    #define PUT(s) do {                                             \
                    if (level == 0)                                 \
                             strbuf_puts(files, s);                 \
                     else                                           \
                             fputs(s, op);                          \
    } while (0)

    static int
    print_directory(int level, char *basedir)
    {
            const char *path;
            FILEOP *fileop = NULL;
            FILE *op = NULL;
            int flist_items = 0;
            int count = 0;

            if (level > 0) {
                    char name[MAXPATHLEN+1];

                    snprintf(name, sizeof(name), "%s/files/%s.%s", distpath, path2fid(basedir), HTML);
                    fileop = open_output_file(name, cflag);
                    op = get_descripter(fileop);
                    print_directory_header(op, level, basedir);
            }
            while ((path = getpath()) != NULL) {
                    const char *p, *local = localpath(path, basedir);

                    /*
                     * Path is outside of basedir.
                     */
                    if (local == NULL) {
                            ungetpath();    /* read again by upper level print_directory(). */
                            break;
                    }
                    /*
                     * Path is inside of basedir.
                     */
                    else {
                            char *slash = strchr(local, '/');

                            if (table_flist && flist_items++ % flist_fields == 0)
                                    PUT(fline_begin);
                            /*
                             * Print directory.
                             */
                            if (slash) {
                                    int baselen = strlen(basedir);
                                    char *q, *last = basedir + baselen;
                                    int subcount;

                                    if (baselen + 1 + (slash - local)  > MAXPATHLEN) {
                                            fprintf(stderr, "Too long path name.\n");
                                            exit(1);
                                    }
                                    /*
                                     * Append new directory to the basedir.
                                     */
                                    p = local;
                                    q = last;
                                    *q++ = '/';
                                    while (p < slash)
                                            *q++ = *p++;
                                    *q = '\0';
                                    /*
                                     * print tree for this directory.
                                     */
                                    ungetpath();    /* read again by lower level print_directory(). */
                                    subcount = print_directory(level + 1, basedir);
                                    PUT(print_directory_name(level, basedir, subcount));
                                    count += subcount;
                                    /*
                                     * Shrink the basedir.
                                     */
                                    *last = '\0';
                            }
                            /*
                             * Print file.
                             */
                            else {
                                    PUT(print_file_name(level, path));
                                    count++;
                            }
                            if (table_flist && flist_items % flist_fields == 0)
                                    PUT(fline_end);
                    }
            }
            if (flist_items % flist_fields != 0)
                    PUT(fline_end);
            if (level > 0) {
                    print_directory_footer(op, level, basedir);
                    close_file(fileop);
            }
            html_count++;
            return count;
    }
    /*
     * print directory header.
     *
     *      i)      op      file index
     *      i)      level   1,2...
     *      i)      dir     directory name
     */
    static void
    print_directory_header(FILE *op, int level, const char *dir)
    {
            STATIC_STRBUF(sb);

            if (level == 0)
                    die("print_directory_header: internal error.");
            strbuf_clear(sb);
            strbuf_puts(sb, removedotslash(dir));
            strbuf_putc(sb, '/');
            fputs_nl(gen_page_begin(strbuf_value(sb), SUBDIR), op);
            fputs_nl(body_begin, op);

            strbuf_clear(sb);
            strbuf_sprintf(sb, "%s%sroot%s/", header_begin, gen_href_begin(NULL, indexlink, normal_suffix, NULL), gen_href_end());
            fputs(strbuf_value(sb), op);
            {
                    char path[MAXPATHLEN+1];
                    char *p, *q;

                    strlimcpy(path, dir, sizeof(path));
                    for (p = path + 1; p != NULL; p = strchr(p, '/')) {
                            int save = 0;

                            q = ++p;
                            while (*q && *q != '/')
                                    q++;
                            save = *q;
                            if (*q == '/')
                                    *q = '\0';
                            if (save == '/')
                                    fputs(gen_href_begin(NULL, path2fid(path), HTML, NULL), op);
                            fputs(p, op);
                            if (save == '/')
                                    fputs(gen_href_end(), op);
                            *q = save;
                            fputc('/', op);
                    }
            }
            fputs_nl(header_end, op);
            {
                    char parentdir[MAXPATHLEN+1];
                    const char *suffix, *parent;

                    (void)dirpart(dir, parentdir);
                    if (level == 1) {
                            parent = indexlink;
                            suffix = normal_suffix;
                    } else {
                            parent = path2fid(parentdir);
                            suffix = HTML;
                    }
                    fputs(gen_href_begin_with_title(NULL, parent, suffix, NULL, "Parent Directory"), op);
            }
            if (Iflag)
                    fputs(gen_image(PARENT, back_icon, ".."), op);
            else
                    fputs("[..]", op);
            fputs_nl(gen_href_end(), op);
            if (table_flist)
                    fputs_nl(flist_begin, op);
            else if (!no_order_list)
                    fputs_nl(list_begin, op);
            else {
                    fputs(br, op);
                    fputs_nl(br, op);
            }
    }
    /*
     * print directory footer.
     *
     *      i)      op      file index
     *      i)      level   1,2...
     *      i)      dir     directory name
     */
    static void
    print_directory_footer(FILE *op, int level, const char *dir)
    {
            const char *parent, *suffix;
            char parentdir[MAXPATHLEN+1];

            if (level == 0)
                    die("print_directory_footer: internal error.");
            (void)dirpart(dir, parentdir);
            if (level == 1) {
                    parent = indexlink;
                    suffix = normal_suffix;
            } else {
                    parent = path2fid(parentdir);
                    suffix = HTML;
            }
            if (table_flist)
                    fputs_nl(flist_end, op);
            else if (!no_order_list)
                    fputs_nl(list_end, op);
            else
                    fputs_nl(br, op);
            fputs(gen_href_begin_with_title(NULL, parent, suffix, NULL, "Parent Directory"), op);
            if (Iflag)
                    fputs(gen_image(PARENT, back_icon, ".."), op);
            else
                    fputs("[..]", op);
            fputs_nl(gen_href_end(), op);
            fputs_nl(body_end, op);
            fputs_nl(gen_page_end(), op);
    }
    /*
     * print file name.
     *
     *      i)      level   0,1,2...
     *      i)      path    path of the file
     */
    static const char *
    print_file_name(int level, const char *path)
    {
            STATIC_STRBUF(sb);
            char *target = (Fflag) ? "mains" : "_top";
            int size = filesize(path);
            char tips[80];

            message(" [%d] adding %s", ++src_count, removedotslash(path));
            /*
             * We assume the file which has one of the following suffixes
             * as a candidate of include file.
             *
             * C: .h
             * C++: .hxx, .hpp, .H
             * PHP: .inc.php
             */
            if (regexec(&is_include_file, path, 0, 0, 0) == 0)
                    put_inc(lastpart(path), path, src_count);
            strbuf_clear(sb);
            if (table_flist)
                    strbuf_puts(sb, fitem_begin);
            else if (!no_order_list)
                    strbuf_puts(sb, item_begin);
            if (size > 1)
                    snprintf(tips, sizeof(tips), "%s bytes", insert_comma(size));
            else
                    snprintf(tips, sizeof(tips), "%s byte", insert_comma(size));
            strbuf_puts(sb, gen_href_begin_with_title_target(level == 0 ? SRCS: upperdir(SRCS),
                            path2fid(path), HTML, NULL, tips, target));
            if (Iflag) {
                    const char *lang, *suffix, *text_icon;

                    if ((suffix = locatestring(path, ".", MATCH_LAST)) != NULL
                        && (lang = decide_lang(suffix)) != NULL
                        && (strcmp(lang, "c") == 0 || strcmp(lang, "cpp") == 0
                           || strcmp(lang, "yacc") == 0))
                            text_icon = c_icon;
                    else
                            text_icon = file_icon;
                    strbuf_puts(sb, gen_image(level == 0 ? CURRENT : PARENT, text_icon, removedotslash(path)));
                    strbuf_puts(sb, quote_space);
            }
            strbuf_puts(sb, full_path ? removedotslash(path) : lastpart(path));
            strbuf_puts(sb, gen_href_end());
            if (table_flist)
                    strbuf_puts(sb, fitem_end);
            else if (!no_order_list)
                    strbuf_puts(sb, item_end);
            else
                    strbuf_puts(sb, br);
            strbuf_putc(sb, '\n');
            if (map_file)
                    fprintf(FILEMAP, "%s\t%s/%s.%s\n", removedotslash(path), SRCS, path2fid(path), HTML);
            return (const char *)strbuf_value(sb);
    }
    /*
     * print directory name.
     *
     *      i)      level   0,1,2...
     *      i)      path    path of the directory
     *      i)      count   number of files in this directory
     */
    static const char *
    print_directory_name(int level, const char *path, int count)
    {
            STATIC_STRBUF(sb);
            char tips[80];

            if (count > 1)
                    snprintf(tips, sizeof(tips), "%d files", count);
            else
                    snprintf(tips, sizeof(tips), "%d file", count);
            path = removedotslash(path);
            strbuf_clear(sb);
            if (table_flist)
                    strbuf_puts(sb, fitem_begin);
            else if (!no_order_list)
                    strbuf_puts(sb, item_begin);
            strbuf_puts(sb, gen_href_begin_with_title(level == 0 ? "files" : NULL,
                            path2fid(path), HTML, NULL, tips));
            if (Iflag) {
                    strbuf_puts(sb, gen_image(level == 0 ? CURRENT : PARENT, dir_icon, appendslash(path)));
                    strbuf_puts(sb, quote_space);
            }
            strbuf_sprintf(sb, "%s/%s", lastpart(path), gen_href_end());
            if (table_flist)
                    strbuf_puts(sb, fitem_end);
            else if (!no_order_list)
                    strbuf_puts(sb, item_end);
            else
                    strbuf_puts(sb, br);
            strbuf_putc(sb, '\n');
            return (const char *)strbuf_value(sb);
    }
    /*
     * makefileindex: make file index.
     *
     *      i)      file            output file name
     *      o)      files           top level file index
     */
    int
    makefileindex(const char *file, STRBUF *a_files)
    {
            STATIC_STRBUF(sb);
            FILE *filesop;
            int flags = REG_EXTENDED;
            /*
             * Basedir is a directory to which we are paying attention on each
             * occasion. It starts with ".", grows and shrink according to the
             * progress of processing. It isn't copied each every recursive call
             * not to waste the stack.
             */
            char basedir[MAXPATHLEN+1];

            /*
             * Initialize data.
             */
            indexlink = (Fflag) ? "../files" : "../mains";
            src_count = 0;

            gp = gfind_open(dbpath, NULL, other_files ? GPATH_BOTH : GPATH_SOURCE);
            /*
             * for collecting include files.
             */
            if (w32)
                    flags |= REG_ICASE;
            strbuf_clear(sb);
            strbuf_puts(sb, "\\.(");
            {
                    const char *p = include_file_suffixes;
                    int c;

                    while ((c = (unsigned char)*p++) != '\0') {
                            if (isregexchar(c))
                                    strbuf_putc(sb, '\\');
                            else if (c == ',')
                                    c = '|';
                            strbuf_putc(sb, c);
                    }
            }
            strbuf_puts(sb, ")$");
            if (regcomp(&is_include_file, strbuf_value(sb), flags) != 0)
                    die("cannot compile regular expression '%s'.", strbuf_value(sb));

            /*
             * Write to files.html.
             */
            if ((filesop = fopen(makepath(distpath, file, NULL), "w")) == NULL)
                    die("cannot open file '%s'.", file);
            fputs_nl(gen_page_begin(title_file_index, TOPDIR), filesop);
            fputs_nl(body_begin, filesop);
            fputs(header_begin, filesop);
            fputs(gen_href_begin(NULL, "files", normal_suffix, NULL), filesop);
            fputs(title_file_index, filesop);
            fputs(gen_href_end(), filesop);
            fputs_nl(header_end, filesop);
            if (table_flist) {
                    fputs_nl(flist_begin, filesop);
            } else if (!no_order_list) {
                    fputs_nl(list_begin, filesop);
            }
            FILEMAP = NULL;
            if (map_file) {
                    if (!(FILEMAP = fopen(makepath(distpath, "FILEMAP", NULL), "w")))
                            die("cannot open '%s'.", makepath(distpath, "FILEMAP", NULL));
            }
            /*
             * print whole directory tree.
             */
            files = a_files;
            strcpy(basedir, ".");
            (void)print_directory(0, basedir);

            if (map_file)
                    fclose(FILEMAP);
            gfind_close(gp);
            regfree(&is_include_file);

            fputs(strbuf_value(files), filesop);
            if (table_flist)
                    fputs_nl(flist_end, filesop);
            else if (!no_order_list)
                    fputs_nl(list_end, filesop);
            else
                    fputs_nl(br, filesop);
            fputs_nl(body_end, filesop);
            fputs_nl(gen_page_end(), filesop);
            fclose(filesop);
            html_count++;
            return src_count;
    }
    /*----------------------------------------------------------------------*/
    /* Main body of generating include file index                           */
    /*----------------------------------------------------------------------*/
    void
    makeincludeindex(void)
    {
            FILE *PIPE;
            STRBUF *input = strbuf_open(0);
            char *ctags_x;
            struct data *inc;
            char *target = (Fflag) ? "mains" : "_top";
            char command[MAXFILLEN];

            /*
             * Pick up include pattern.
             *
             * C: #include "xxx.h"
             * PHP: include("xxx.inc.php");
             */
            /*
             * Unlike Perl regular expression, POSIX regular expression doesn't support C-style escape sequence.
             * Therefore, we can not use "\\t" here.
             */
            snprintf(command, sizeof(command), "%s -gnx \"^[ \t]*(#[ \t]*(import|include)|include[ \t]*\\()\"", global_path);
            if ((PIPE = popen(command, "r")) == NULL)
                    die("cannot fork.");
            strbuf_reset(input);
            while ((ctags_x = strbuf_fgets(input, PIPE, STRBUF_NOCRLF)) != NULL) {
                    SPLIT ptable;
                    char buf[MAXBUFLEN];
                    int is_php = 0;
                    const char *last, *lang, *suffix;

                    if (split(ctags_x, 4, &ptable) < 4) {
                            recover(&ptable);
                            die("too small number of parts in makefileindex().");
                    }
                    if ((suffix = locatestring(ptable.part[PART_PATH].start, ".", MATCH_LAST)) != NULL
                        && (lang = decide_lang(suffix)) != NULL
                        && strcmp(lang, "php") == 0)
                            is_php = 1;
                    last = extract_lastname(ptable.part[PART_LINE].start, is_php);
                    if (last == NULL || (inc = get_inc(last)) == NULL)
                            continue;
                    recover(&ptable);
                    /*
                     * s/^[^ \t]+/$last/;
                     */
                    {
                            const char *p;
                            char *q = buf;

                            for (p = last; *p; p++)
                                    *q++ = *p;
                            for (p = ctags_x; *p && *p != ' ' && *p != '\t'; p++)
                                    ;
                            for (; *p; p++)
                                    *q++ = *p;
                            *q = '\0';
                    }
                    put_included(inc, buf);
            }
            if (pclose(PIPE) != 0)
                    die("terminated abnormally.");

            for (inc = first_inc(); inc; inc = next_inc()) {
                    const char *last = inc->name;
                    int no = inc->id;
                    FILEOP *fileop_INCLUDE;
                    FILE *INCLUDE;

                    if (inc->count > 1) {
                            char path[MAXPATHLEN];

                            snprintf(path, sizeof(path), "%s/%s/%d.%s", distpath, INCS, no, HTML);
                            fileop_INCLUDE = open_output_file(path, cflag);
                            INCLUDE = get_descripter(fileop_INCLUDE);
                            fputs_nl(gen_page_begin(last, SUBDIR), INCLUDE);
                            fputs_nl(body_begin, INCLUDE);
                            fputs_nl(verbatim_begin, INCLUDE);
                            {
                                    const char *filename = strbuf_value(inc->contents);
                                    int count = inc->count;

                                    for (; count; filename += strlen(filename) + 1, count--) {
                                            fputs(gen_href_begin_with_title_target(upperdir(SRCS), path2fid(filename), HTML, NULL, NULL, target), INCLUDE);
                                            fputs(removedotslash(filename), INCLUDE);
                                            fputs_nl(gen_href_end(), INCLUDE);
                                    }
                            }
                            fputs_nl(verbatim_end, INCLUDE);
                            fputs_nl(body_end, INCLUDE);
                            fputs_nl(gen_page_end(), INCLUDE);
                            close_file(fileop_INCLUDE);
                            html_count++;
                            /*
                             * inc->contents == NULL means that information already
                             * written to file.
                             */
                            strbuf_close(inc->contents);
                            inc->contents = NULL;
                    }
                    if (!inc->ref_count)
                            continue;
                    if (inc->ref_count == 1) {
                            SPLIT ptable;
                            char buf[1024];

                            if (split(strbuf_value(inc->ref_contents), 4, &ptable) < 4) {
                                    recover(&ptable);
                                    die("too small number of parts in makefileindex().");
                            }
                            snprintf(buf, sizeof(buf), "%s %s", ptable.part[PART_LNO].start, ptable.part[PART_PATH].start);
                            recover(&ptable);
                            strbuf_reset(inc->ref_contents);
                            strbuf_puts(inc->ref_contents, buf);
                    } else {
                            char path[MAXPATHLEN];

                            snprintf(path, sizeof(path), "%s/%s/%d.%s", distpath, INCREFS, no, HTML);
                            fileop_INCLUDE = open_output_file(path, cflag);
                            INCLUDE = get_descripter(fileop_INCLUDE);
                            fputs_nl(gen_page_begin(last, SUBDIR), INCLUDE);
                            fputs_nl(body_begin, INCLUDE);
                            fputs_nl(gen_list_begin(), INCLUDE);
                            {
                                    const char *line = strbuf_value(inc->ref_contents);
                                    int count = inc->ref_count;

                                    for (; count; line += strlen(line) + 1, count--)
                                            fputs_nl(gen_list_body(upperdir(SRCS), line), INCLUDE);
                            }
                            fputs_nl(gen_list_end(), INCLUDE);
                            fputs_nl(body_end, INCLUDE);
                            fputs_nl(gen_page_end(), INCLUDE);
                            close_file(fileop_INCLUDE);
                            html_count++;
                            /*
                             * inc->ref_contents == NULL means that information already
                             * written to file.
                             */
                            strbuf_close(inc->ref_contents);
                            inc->ref_contents = NULL;
                    }
            }
            strbuf_close(input);
    }

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