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] */