root/htags/fileindex.c(210.html)

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