/** * print directory name. * * @param[in] level 0,1,2... * @param[in] path path of the directory * @param[in] 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); }
/** * print directory footer. * * @param[in] op file index * @param[in] level 1,2... * @param[in] dir directory name */ static void print_directory_footer(FILE *op, int level, const char *dir) { const char *parent, *suffix; char parentdir[MAXPATHLEN]; const char *top = (Fflag && !tree_view) ? "../files" : "../mains"; if (level == 0) die("print_directory_footer: internal error."); (void)dirpart(dir, parentdir); if (level == 1) { parent = top; 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. * * @param[in] level 0,1,2... * @param[in] 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, .hh * 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'); return (const char *)strbuf_value(sb); }
/** * anchor_load: load anchor table * * @param[in] path path name */ void anchor_load(const char *path) { int db, current_fid; /* Get fid of the path */ { const char *p = path2fid(path); if (p == NULL) die("anchor_load: internal error. file '%s' not found in GPATH.", path); current_fid = atoi(p); } FIRST = LAST = 0; end = CURRENT = NULL; if (vb == NULL) vb = varray_open(sizeof(struct anchor), 1000); else varray_reset(vb); for (db = GTAGS; db < GTAGLIM; db++) { XARGS *xp; char *ctags_xid; if ((xp = anchor_input[db]) == NULL) continue; /* * Read from input stream until it reaches end of file * or the line of another file appears. */ while ((ctags_xid = xargs_read(xp)) != NULL) { SPLIT ptable; struct anchor *a; int type, fid; const char *ctags_x = parse_xid(ctags_xid, NULL, &fid); /* * It is the following file. */ if (current_fid != fid) { xargs_unread(xp); break; } if (split(ctags_x, 4, &ptable) < 4) { recover(&ptable); die("too small number of parts in anchor_load().\n'%s'", ctags_x); } if (db == GTAGS) { char *p = ptable.part[PART_LINE].start; for (; *p && isspace((unsigned char)*p); p++) ; if (!*p) { recover(&ptable); die("The output of parser is illegal.\n%s", ctags_x); } /* * Function header is applied only to the anchor whoes type is 'D'. * (D: function, M: macro, T: type) */ type = 'T'; if (*p == '#') type = 'M'; else if (locatestring(p, "typedef", MATCH_AT_FIRST)) type = 'T'; else if ((p = locatestring(p, ptable.part[PART_TAG].start, MATCH_FIRST)) != NULL) { /* skip a tag and the following blanks */ p += strlen(ptable.part[PART_TAG].start); for (; *p && isspace((unsigned char)*p); p++) ; if (*p == '(') type = 'D'; } } else if (db == GRTAGS) type = 'R'; else type = 'Y'; /* allocate an entry */ a = varray_append(vb); a->lineno = atoi(ptable.part[PART_LNO].start); a->type = type; a->done = 0; settag(a, ptable.part[PART_TAG].start); recover(&ptable); } if (ctags_xid == NULL) { xargs_close(anchor_input[db]); anchor_input[db] = NULL; } } if (vb->length == 0) { table = NULL; } else { int i, used = vb->length; /* * Sort by lineno. */ table = varray_assign(vb, 0, 0); qsort(table, used, sizeof(struct anchor), cmp); /* * Setup some lineno. */ for (i = 0; i < used; i++) if (table[i].type == 'D') break; if (i < used) FIRST = table[i].lineno; for (i = used - 1; i >= 0; i--) if (table[i].type == 'D') break; if (i >= 0) LAST = table[i].lineno; } /* * Setup loop range. */ start = table; curp = NULL; end = &table[vb->length]; /* anchor_dump(stderr, 0);*/ }
/** * Generate list body. * * @NAME{ctags_x} with the @CODE{--encode-path=\" \\t\"} */ const char * gen_list_body(const char *srcdir, const char *ctags_x, const char *fid) /* virtually const */ { STATIC_STRBUF(sb); char path[MAXPATHLEN]; const char *p; SPLIT ptable; strbuf_clear(sb); if (split((char *)ctags_x, 4, &ptable) < 4) { recover(&ptable); die("too small number of parts in list_body().\n'%s'", ctags_x); } strlimcpy(path, decode_path(ptable.part[PART_PATH].start + 2), sizeof(path)); if (fid == NULL) fid = path2fid(path); if (table_list) { strbuf_puts(sb, current_row_begin); if (enable_xhtml) { strbuf_puts(sb, "<td class='tag'>"); strbuf_puts(sb, gen_href_begin(srcdir, fid, HTML, ptable.part[PART_LNO].start)); strbuf_puts(sb, ptable.part[PART_TAG].start); strbuf_puts(sb, gen_href_end()); strbuf_sprintf(sb, "</td><td class='line'>%s</td><td class='file'>%s</td><td class='code'>", ptable.part[PART_LNO].start, path); } else { strbuf_puts(sb, "<td nowrap='nowrap'>"); strbuf_puts(sb, gen_href_begin(srcdir, fid, HTML, ptable.part[PART_LNO].start)); strbuf_puts(sb, ptable.part[PART_TAG].start); strbuf_puts(sb, gen_href_end()); strbuf_sprintf(sb, "</td><td nowrap='nowrap' align='right'>%s</td>" "<td nowrap='nowrap' align='left'>%s</td><td nowrap='nowrap'>", ptable.part[PART_LNO].start, path); } for (p = ptable.part[PART_LINE].start; *p; p++) { unsigned char c = *p; if (c == '&') strbuf_puts(sb, quote_amp); else if (c == '<') strbuf_puts(sb, quote_little); else if (c == '>') strbuf_puts(sb, quote_great); else if (c == ' ') strbuf_puts(sb, quote_space); else if (c == '\t') { strbuf_puts(sb, quote_space); strbuf_puts(sb, quote_space); } else strbuf_putc(sb, c); } strbuf_puts(sb, "</td>"); strbuf_puts(sb, current_row_end); recover(&ptable); } else { /* print tag name with anchor */ strbuf_puts(sb, current_line_begin); strbuf_puts(sb, gen_href_begin(srcdir, fid, HTML, ptable.part[PART_LNO].start)); strbuf_puts(sb, ptable.part[PART_TAG].start); strbuf_puts(sb, gen_href_end()); recover(&ptable); /* print line number */ for (p = ptable.part[PART_TAG].end; p < ptable.part[PART_PATH].start; p++) strbuf_putc(sb, *p); /* print file name */ strbuf_puts(sb, path); /* print the rest */ for (p = ptable.part[PART_PATH].end; *p; p++) { unsigned char c = *p; if (c == '&') strbuf_puts(sb, quote_amp); else if (c == '<') strbuf_puts(sb, quote_little); else if (c == '>') strbuf_puts(sb, quote_great); else strbuf_putc(sb, c); } strbuf_puts(sb, current_line_end); } return strbuf_value(sb); }
/** * makehtml: make html files * * @param[in] total number of files. */ static void makehtml(int total) { GFIND *gp; FILE *anchor_stream; const char *path; int count = 0; /* * Create anchor stream for anchor_load(). */ anchor_stream = tmpfile(); #if defined(_WIN32) && !defined(__CYGWIN__) /* * tmpfile is created in the root, which user's can't write on Vista+. * Use _tempnam and open it directly. */ if (anchor_stream == NULL) { char *name = _tempnam(tmpdir, "htags"); anchor_stream = fopen(name, "w+bD"); free(name); } #endif gp = gfind_open(dbpath, NULL, other_files ? GPATH_BOTH : GPATH_SOURCE, 0); while ((path = gfind_read(gp)) != NULL) { if (gp->type == GPATH_OTHER) fputc(' ', anchor_stream); fputs(path, anchor_stream); fputc('\n', anchor_stream); } gfind_close(gp); /* * Prepare anchor stream for anchor_load(). */ anchor_prepare(anchor_stream); /* * For each path in GPATH, convert the path into HTML file. */ gp = gfind_open(dbpath, NULL, other_files ? GPATH_BOTH : GPATH_SOURCE, 0); while ((path = gfind_read(gp)) != NULL) { char html[MAXPATHLEN]; if (gp->type == GPATH_OTHER && !other_files) continue; /* * load tags belonging to the path. * The path must be start "./". */ anchor_load(path); /* * inform the current path name to lex() function. */ save_current_path(path); count++; path += 2; /* remove './' at the head */ message(" [%d/%d] converting %s", count, total, path); snprintf(html, sizeof(html), "%s/%s/%s.%s", distpath, SRCS, path2fid(path), HTML); src2html(path, html, gp->type == GPATH_OTHER); } gfind_close(gp); }
/*----------------------------------------------------------------------*/ 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), PQUOTE "%s -gnx --encode-path=\" \t\" \"^[ \t]*(#[ \t]*(import|include)|include[ \t]*\\()\"" PQUOTE, quote_shell(global_path)); if ((PIPE = popen(command, "r")) == NULL) die("cannot execute '%s'.", command); 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 '%s' (errno = %d).", command, errno); 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, 0); 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, decode_path(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, 0); 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, NULL), 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); }
/** * print directory header. * * @param[in] op file index * @param[in] level 1,2... * @param[in] dir directory name */ static void print_directory_header(FILE *op, int level, const char *dir) { STATIC_STRBUF(sb); const char *top = (Fflag && !tree_view) ? "../files" : "../mains"; 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, top, normal_suffix, NULL), gen_href_end()); fputs(strbuf_value(sb), op); { char path[MAXPATHLEN]; 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]; const char *suffix, *parent; (void)dirpart(dir, parentdir); if (level == 1) { parent = top; 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); } }
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]; snprintf(name, sizeof(name), "%s/files/%s.%s", distpath, path2fid(basedir), HTML); fileop = open_output_file(name, 0); op = get_descripter(fileop); print_directory_header(op, level, basedir); if (tree_view) { char *target = (Fflag) ? "mains" : "_top"; strbuf_puts(files, dir_begin); strbuf_puts(files, gen_href_begin_with_title_target("files", path2fid(basedir), HTML, NULL, NULL, target)); strbuf_puts(files, full_path ? removedotslash(basedir) : lastpart(basedir)); strbuf_puts(files, gen_href_end()); strbuf_puts_nl(files, dir_title_end); strbuf_puts_nl(files, "<ul>"); } } 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 { const char *file_name = print_file_name(level, path); if (tree_view) { int size = filesize(path); char *target = (Fflag) ? "mains" : "_top"; char tips[80]; if (size > 1) snprintf(tips, sizeof(tips), "%s bytes", insert_comma(size)); else snprintf(tips, sizeof(tips), "%s byte", insert_comma(size)); strbuf_sprintf(files, "%s%s%s%s%s\n", file_begin, gen_href_begin_with_title_target(SRCS, path2fid(path), HTML, NULL, tips, target), full_path ? removedotslash(path) : lastpart(path), gen_href_end(), file_end); } PUT(file_name); if (filemap_file) fprintf(FILEMAP, "%s\t%s/%s.%s\n", removedotslash(path), SRCS, path2fid(path), HTML); 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); if (tree_view) { strbuf_puts_nl(files, "</ul>"); strbuf_puts_nl(files, dir_end); } } html_count++; return count; }