Index: configure.ac
===================================================================
RCS file: /sources/global/global/configure.ac,v
retrieving revision 1.100
diff -u -p -r1.100 configure.ac
--- configure.ac	5 Oct 2009 23:35:39 -0000	1.100
+++ configure.ac	2 Nov 2009 00:16:48 -0000
@@ -48,6 +48,7 @@ dnl Checks for libraries.
 
 dnl Checks for header files.
 AC_CHECK_HEADERS(limits.h string.h unistd.h stdarg.h sys/time.h fcntl.h)
+AC_CHECK_HEADERS(sys/resource.h sys/times.h)
 AC_HEADER_DIRENT
 if test ${ac_header_dirent} = no; then
         AC_MSG_ERROR([dirent(3) is required but not found.])
@@ -99,6 +100,7 @@ AC_FUNC_STRFTIME
 AC_CHECK_FUNCS(getcwd putenv lstat snprintf)
 AC_CHECK_FUNCS(index rindex bzero bcmp bcopy strchr strrchr memset memcmp memmove)
 AC_CHECK_FUNCS(putc_unlocked getc_unlocked)
+AC_CHECK_FUNCS(gettimeofday getrusage times)
 AG_DJGPP
 
 INCLUDES='-I$(top_srcdir)/libutil -I$(top_srcdir)/libdb -I$(top_srcdir)/libglibc -I../libutil'
Index: htags/htags.c
===================================================================
RCS file: /sources/global/global/htags/htags.c,v
retrieving revision 1.130
diff -u -p -r1.130 htags.c
--- htags/htags.c	29 Jan 2009 09:30:22 -0000	1.130
+++ htags/htags.c	2 Nov 2009 00:16:49 -0000
@@ -37,7 +37,6 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/param.h>
-#include <time.h>
 
 #include "checkalloc.h"
 #include "getopt.h"
@@ -116,7 +115,7 @@ int caution;				/* --caution option		*/
 int dynamic;				/* --dynamic(-D) option		*/
 int symbol;				/* --symbol(-s) option          */
 int suggest;				/* --suggest option		*/
-int statistics;				/* --statistics option		*/
+int statistics = STATISTICS_STYLE_NONE;	/* --statistics option		*/
 
 int copy_files;				/* 1: copy tag files		*/
 int no_order_list;			/* 1: doesn't use order list	*/
@@ -278,7 +277,7 @@ static struct option const long_options[
         {"nocgi", no_argument, &cgi, 0},
         {"no-map-file", no_argument, &map_file, 0},
         {"show-position", no_argument, &show_position, 1},
-        {"statistics", no_argument, &statistics, 1},
+        {"statistics", no_argument, &statistics, STATISTICS_STYLE_TABLE},
         {"suggest", no_argument, &suggest, 1},
         {"table-list", no_argument, &table_list, 1},
         {"version", no_argument, &show_version, 1},
@@ -1446,9 +1445,8 @@ main(int argc, char **argv)
 	const char *index = NULL;
 	int optchar;
         int option_index = 0;
-	time_t start_time, end_time, start_all_time, end_all_time,
-		T_makedupindex, T_makedefineindex, T_makefileindex,
-		T_makeincludeindex, T_makehtml, T_all;
+	STATISTICS_TIME *T_makedupindex, *T_makedefineindex, *T_makefileindex,
+		*T_makeincludeindex, *T_makehtml, *T_all;
 
 	arg_dbpath[0] = 0;
 	basic_check();
@@ -1820,7 +1818,7 @@ main(int argc, char **argv)
         HTML = (cflag) ? gzipped_suffix : normal_suffix;
 
 	message("[%s] Htags started", now());
-	start_all_time = time(NULL);
+	T_all = statistics_time_start("The entire time");
 	/*
 	 * (#) check if GTAGS, GRTAGS is the latest.
 	 */
@@ -1895,11 +1893,10 @@ main(int argc, char **argv)
 	 */
 	message("[%s] (3) making duplicate entries ...", now());
 	cache_open();
-	start_time = time(NULL);
+	T_makedupindex = statistics_time_start("Time of making duplicate entries");
 	func_total = makedupindex();
-	end_time = time(NULL);
+	statistics_time_end(T_makedupindex);
 	message("Total %d functions.", func_total);
-	T_makedupindex = end_time - start_time;
 	/*
 	 * (4) search index. (search.html)
 	 */
@@ -1916,31 +1913,28 @@ main(int argc, char **argv)
 		 *     PRODUCE @defines
 		 */
 		message("[%s] (5) making function index ...", now());
-		start_time = time(NULL);
+		T_makedefineindex = statistics_time_start("Time of making function index");
 		func_total = makedefineindex("defines.html", func_total, defines);
-		end_time = time(NULL);
+		statistics_time_end(T_makedefineindex);
 		message("Total %d functions.", func_total);
-		T_makedefineindex = end_time - start_time;
 		/*
 		 * (6) make file index (files.html and files/)
 		 *     PRODUCE @files, %includes
 		 */
 		message("[%s] (6) making file index ...", now());
 		init_inc();
-		start_time = time(NULL);
+		T_makefileindex = statistics_time_start("Time of making file index");
 		file_total = makefileindex("files.html", files);
-		end_time = time(NULL);
+		statistics_time_end(T_makefileindex);
 		message("Total %d files.", file_total);
-		T_makefileindex = end_time - start_time;
 		html_count += file_total;
 		/*
 		 * [#] make include file index.
 		 */
 		message("[%s] (#) making include file index ...", now());
-		start_time = time(NULL);
+		T_makeincludeindex = statistics_time_start("Time of making include file index");
 		makeincludeindex();
-		end_time = time(NULL);
-		T_makeincludeindex = end_time - start_time;
+		statistics_time_end(T_makeincludeindex);
 		/*
 		 * [#] make a common part for mains.html and index.html
 		 *     USING @defines @files
@@ -1966,10 +1960,9 @@ main(int argc, char **argv)
 	 *     USING TAG CACHE, %includes and anchor database.
 	 */
 	message("[%s] (9) making hypertext from source code ...", now());
-	start_time = time(NULL);
+	T_makehtml = statistics_time_start("Time of making hypertext");
 	makehtml(file_total);
-	end_time = time(NULL);
-	T_makehtml = end_time - start_time;
+	statistics_time_end(T_makehtml);
 	/*
 	 * (10) rebuild script. (rebuild.sh)
 	 *
@@ -1987,9 +1980,8 @@ main(int argc, char **argv)
 		snprintf(dst, sizeof(dst), "%s/style.css", distpath);
 		copyfile(src, dst);
 	}
-	end_all_time = time(NULL);
+	statistics_time_end(T_all);
 	message("[%s] Done.", now());
-	T_all = end_all_time - start_all_time;
 	if (vflag && cgi && (cflag || fflag || dynamic)) {
 		message("\n[Information]\n");
 		if (cflag) {
@@ -2025,15 +2017,7 @@ main(int argc, char **argv)
 	/*
 	 * Print statistics information.
 	 */
-	if (statistics) {
-		setverbose();
-		message("- Elapsed time of making duplicate entries ............ %10ld seconds.", T_makedupindex);
-		message("- Elapsed time of making function index ............... %10ld seconds.", T_makedefineindex);
-		message("- Elapsed time of making file index ................... %10ld seconds.", T_makefileindex);
-		message("- Elapsed time of making include file index ........... %10ld seconds.", T_makeincludeindex);
-		message("- Elapsed time of making hypertext .................... %10ld seconds.", T_makehtml);
-		message("- The entire elapsed time ............................. %10ld seconds.", T_all);
-	}
+	print_statistics(statistics);
 	clean();
 	return 0;
 }
Index: libutil/Makefile.am
===================================================================
RCS file: /sources/global/global/libutil/Makefile.am,v
retrieving revision 1.33
diff -u -p -r1.33 Makefile.am
--- libutil/Makefile.am	23 Dec 2006 09:46:04 -0000	1.33
+++ libutil/Makefile.am	2 Nov 2009 00:16:49 -0000
@@ -18,14 +18,14 @@ gtagsop.h locatestring.h makepath.h path
 strmake.h tab.h test.h token.h usable.h version.h is_unixy.h abs2rel.h \
 split.h strlimcpy.h linetable.h env.h char.h date.h langmap.h \
 varray.h idset.h strhash.h xargs.h format.h pathconvert.h \
-compress.h checkalloc.h pool.h fileop.h
+compress.h checkalloc.h pool.h fileop.h statistics.h
 
 libgloutil_a_SOURCES = \
 conf.c dbop.c defined.c die.c find.c getdbpath.c gtagsop.c locatestring.c \
 makepath.c path.c gpathop.c strbuf.c strmake.c tab.c test.c \
 token.c usable.c version.c is_unixy.c abs2rel.c split.c strlimcpy.c linetable.c \
 env.c char.c date.c langmap.c varray.c idset.c strhash.c xargs.c \
-pathconvert.c compress.c checkalloc.c pool.c fileop.c
+pathconvert.c compress.c checkalloc.c pool.c fileop.c statistics.c
 
 AM_CFLAGS = -DBINDIR='"$(bindir)"' -DDATADIR='"$(datadir)"'
 
Index: libutil/global.h
===================================================================
RCS file: /sources/global/global/libutil/global.h,v
retrieving revision 1.31
diff -u -p -r1.31 global.h
--- libutil/global.h	5 Jul 2007 06:52:03 -0000	1.31
+++ libutil/global.h	2 Nov 2009 00:16:49 -0000
@@ -48,6 +48,7 @@
 #include "pathconvert.h"
 #include "pool.h"
 #include "split.h"
+#include "statistics.h"
 #include "strbuf.h"
 #include "strhash.h"
 #include "strlimcpy.h"
Index: libutil/statistics.c
===================================================================
RCS file: libutil/statistics.c
diff -N libutil/statistics.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ libutil/statistics.c	2 Nov 2009 00:16:49 -0000
@@ -0,0 +1,493 @@
+/*
+ * Copyright (c) 2009
+ *	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/>.
+ */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+#if TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#elif HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#if HAVE_SYS_TIMES_H
+#include <sys/times.h>
+#endif
+#if HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+#include <assert.h>
+#include <math.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "checkalloc.h"
+#include "die.h"
+#include "queue.h"
+#include "statistics.h"
+#include "strbuf.h"
+
+#if HAVE_GETTIMEOFDAY && HAVE_GETRUSAGE
+typedef struct timeval ELAPSED_TIME_TYPE;
+typedef struct timeval CPU_TIME_TYPE;
+#define CPU_TIME_AVAILABLE	1
+#elif HAVE_TIMES
+#if HAVE_GETTIMEOFDAY
+typedef struct timeval ELAPSED_TIME_TYPE;
+#else
+typedef clock_t ELAPSED_TIME_TYPE;
+#endif
+typedef clock_t CPU_TIME_TYPE;
+#define CPU_TIME_AVAILABLE	1
+#else
+#if HAVE_GETTIMEOFDAY
+typedef struct timeval ELAPSED_TIME_TYPE;
+#else
+typedef time_t ELAPSED_TIME_TYPE;
+#endif
+#define CPU_TIME_AVAILABLE	0
+#endif
+
+struct statistics_time {
+	STAILQ_ENTRY(statistics_time) next;
+
+	ELAPSED_TIME_TYPE elapsed_start;
+	double elapsed;		/* Elapsed time in seconds. */
+
+#if CPU_TIME_AVAILABLE
+	CPU_TIME_TYPE user_start;
+	CPU_TIME_TYPE system_start;
+	double user;		/* User time in seconds. */
+	double system;		/* System time in seconds. */
+	double percent;		/* (user + system) * 100 / elapsed */
+				/* percent may be NaN or infinity. */
+#endif
+
+	int name_len;
+	char name[1];
+};
+
+static STAILQ_HEAD(statistics_time_list, statistics_time)
+	statistics_time_list = STAILQ_HEAD_INITIALIZER(statistics_time_list);
+
+#if HAVE_GETTIMEOFDAY && HAVE_GETRUSAGE
+static struct timeval
+add_timeval(struct timeval a, struct timeval b)
+{
+	a.tv_sec += b.tv_sec;
+	a.tv_usec += b.tv_usec;
+	if (a.tv_usec >= 1000000) {
+		a.tv_sec++;
+		a.tv_usec -= 1000000;
+	}
+
+	return a;
+}
+#endif
+
+#if HAVE_GETTIMEOFDAY
+static double
+sub_timeval(struct timeval a, struct timeval b)
+{
+	if (a.tv_usec < b.tv_usec) {
+		a.tv_sec--;
+		a.tv_usec += 1000000;
+	}
+	a.tv_sec -= b.tv_sec;
+	a.tv_usec -= b.tv_usec;
+
+	return a.tv_sec + a.tv_usec * 1e-6;
+}
+#endif
+
+#if CPU_TIME_AVAILABLE
+static double
+cpu_utilization(double cpu_time, double elapsed)
+{
+	if (elapsed == 0) {
+#if defined(NAN)
+		if (cpu_time == 0)
+			return NAN;
+		else
+#endif
+#if defined(INFINITY)
+			return INFINITY;
+#else
+			return HUGE_VAL;
+#endif
+	} else {
+		return cpu_time / elapsed * 100;
+	}
+}
+#endif
+
+STATISTICS_TIME *
+statistics_time_start(const char *fmt, ...)
+{
+	STATISTICS_TIME *t;
+	STATIC_STRBUF(sb);
+	va_list ap;
+#if HAVE_GETTIMEOFDAY && HAVE_GETRUSAGE
+	struct rusage self, children;
+#elif HAVE_TIMES
+	struct tms buf;
+#endif
+
+	strbuf_clear(sb);
+
+	va_start(ap, fmt);
+	strbuf_vsprintf(sb, fmt, ap);
+	va_end(ap);
+
+	t = check_malloc(offsetof(STATISTICS_TIME, name) + strbuf_getlen(sb) + 1);
+
+	t->name_len = strbuf_getlen(sb);
+	strcpy(t->name, strbuf_value(sb));
+
+#if HAVE_GETTIMEOFDAY
+	gettimeofday(&t->elapsed_start, NULL);
+#elif HAVE_TIMES
+	t->elapsed_start = times(&buf);
+#else
+	t->elapsed_start = time(NULL);
+#endif
+
+#if HAVE_GETTIMEOFDAY && HAVE_GETRUSAGE
+	getrusage(RUSAGE_SELF, &self);
+	getrusage(RUSAGE_CHILDREN, &children);
+	t->user_start = add_timeval(self.ru_utime, children.ru_utime);
+	t->system_start = add_timeval(self.ru_stime, children.ru_stime);
+#elif HAVE_TIMES
+#if HAVE_GETTIMEOFDAY
+	times(&buf);
+#endif
+	t->user_start = buf.tms_utime + buf.tms_cutime;
+	t->system_start = buf.tms_stime + buf.tms_cstime;
+#endif
+
+	return t;
+}
+
+void
+statistics_time_end(STATISTICS_TIME *t)
+{
+#if HAVE_GETTIMEOFDAY
+	struct timeval tv;
+#endif
+#if HAVE_GETTIMEOFDAY && HAVE_GETRUSAGE
+	struct rusage self, children;
+#elif HAVE_TIMES
+	struct tms buf;
+	double tick = 1.0 / sysconf(_SC_CLK_TCK);
+#endif
+
+#if HAVE_GETTIMEOFDAY && HAVE_GETRUSAGE
+	getrusage(RUSAGE_SELF, &self);
+	getrusage(RUSAGE_CHILDREN, &children);
+	t->user = sub_timeval(add_timeval(self.ru_utime, children.ru_utime), t->user_start);
+	t->system = sub_timeval(add_timeval(self.ru_stime, children.ru_stime), t->system_start);
+#elif HAVE_TIMES
+#if HAVE_GETTIMEOFDAY
+	times(&buf);
+#else
+	t->elapsed = (times(&buf) - t->elapsed_start) * tick;
+#endif
+	t->user = (buf.tms_utime + buf.tms_cutime - t->user_start) * tick;
+	t->system = (buf.tms_stime + buf.tms_cstime - t->system_start) * tick;
+#endif
+
+#if HAVE_GETTIMEOFDAY
+	gettimeofday(&tv, NULL);
+	t->elapsed = sub_timeval(tv, t->elapsed_start);
+#elif !HAVE_TIMES
+	t->elapsed = time(NULL) - t->elapsed_start;
+#endif
+
+#if CPU_TIME_AVAILABLE
+	t->percent = cpu_utilization(t->user + t->system, t->elapsed);
+#endif
+
+	STAILQ_INSERT_TAIL(&statistics_time_list, t, next);
+}
+
+struct printing_width {
+	int name;
+	int elapsed;
+#if CPU_TIME_AVAILABLE
+	int user;
+	int system;
+	int percent;
+#endif
+};
+
+static int
+decimal_width(unsigned long num)
+{
+	int width = 1;
+
+	while (num >= 10) {
+		num /= 10;
+		width++;
+	}
+
+	return width;
+}
+
+#define ELAPSED_PRECISION	3
+#define USER_PRECISION		3
+#define SYSTEM_PRECISION	3
+#define PERCENT_PRECISION	1
+
+#define STR(x)			#x
+#define XSTR(x)			STR(x)
+#define PRECISION_STRING(x)	XSTR(x##_PRECISION)
+
+static void
+get_max_width(struct printing_width *max_width)
+{
+	const STATISTICS_TIME *t;
+	int w;
+#if CPU_TIME_AVAILABLE
+	char buf[64];
+#endif
+
+	STAILQ_FOREACH(t, &statistics_time_list, next) {
+		if (t->name_len > max_width->name)
+			max_width->name = t->name_len;
+
+		w = decimal_width(t->elapsed) + ELAPSED_PRECISION + 1;
+		if (w > max_width->elapsed)
+			max_width->elapsed = w;
+
+#if CPU_TIME_AVAILABLE
+		w = decimal_width(t->user) + USER_PRECISION + 1;
+		if (w > max_width->user )
+			max_width->user = w;
+
+		w = decimal_width(t->system) + SYSTEM_PRECISION + 1;
+		if (w > max_width->system)
+			max_width->system = w;
+
+		/*
+		 * Printing style of Nan and infinity is implementation-defined.
+		 * Therefore, it is impossible to know printing width without calling snprintf.
+		 */
+		w = snprintf(buf, sizeof(buf), "%." PRECISION_STRING(PERCENT) "f", t->percent);
+		if (w > max_width->percent)
+			max_width->percent = w;
+#endif
+	}
+}
+
+#define MIN_DOTS_LEN		3
+
+static void
+print_header_list(void **ppriv)
+{
+	struct printing_width max_width;
+	char *dots;
+
+	memset(&max_width, 0, sizeof(max_width));
+	get_max_width(&max_width);
+	*ppriv = dots = check_malloc(sizeof(max_width) + max_width.name + MIN_DOTS_LEN + 1);
+	memcpy(dots, &max_width, sizeof(max_width));
+	dots += sizeof(max_width);
+	memset(dots, '.', max_width.name + MIN_DOTS_LEN);
+	dots[max_width.name + MIN_DOTS_LEN] = '\0';
+
+	setverbose();
+}
+
+static void
+print_time_list(const STATISTICS_TIME *t, void *priv)
+{
+	const struct printing_width *max_width = priv;
+	const char *dots = (const char *)&max_width[1];
+
+#if CPU_TIME_AVAILABLE
+	message("- %s %s"
+		" user %*." PRECISION_STRING(USER) "fs"
+		" system %*." PRECISION_STRING(SYSTEM) "fs"
+		" elapsed %*." PRECISION_STRING(ELAPSED) "fs"
+		" %*." PRECISION_STRING(PERCENT) "f%%",
+		t->name, dots + t->name_len,
+		max_width->user, t->user,
+		max_width->system, t->system,
+		max_width->elapsed, t->elapsed,
+		max_width->percent, t->percent);
+#else
+	message("- %s %s"
+		" elapsed %*." PRECISION_STRING(ELAPSED) "fs",
+		t->name, dots + t->name_len,
+		max_width->elapsed, t->elapsed);
+#endif
+}
+
+static const char name_heading_string[] = "period";
+static const char elapsed_heading_string[] = "elapsed[sec]";
+#if CPU_TIME_AVAILABLE
+static const char user_heading_string[] = "user[sec]";
+static const char system_heading_string[] = "system[sec]";
+static const char percent_heading_string[] = "%CPU";
+#endif
+
+static void
+print_header_table(void **ppriv)
+{
+	struct printing_width *max_width;
+	char *bar;
+	int bar_len;
+
+	*ppriv = max_width = check_malloc(sizeof(*max_width));
+
+	max_width->name = sizeof(name_heading_string) - 1;
+	max_width->elapsed = sizeof(elapsed_heading_string) - 1;
+#if CPU_TIME_AVAILABLE
+	max_width->user = sizeof(user_heading_string) - 1;
+	max_width->system = sizeof(system_heading_string) - 1;
+	max_width->percent = sizeof(percent_heading_string) - 1;
+#endif
+	get_max_width(max_width);
+
+	bar_len = (max_width->name > max_width->elapsed)
+		? max_width->name : max_width->elapsed;
+#if CPU_TIME_AVAILABLE
+	if (max_width->user > bar_len)
+		bar_len = max_width->user;
+	if (max_width->system > bar_len)
+		bar_len = max_width->system;
+	if (max_width->percent > bar_len)
+		bar_len = max_width->percent;
+#endif
+
+	bar = check_malloc(bar_len + 1);
+	memset(bar, '-', bar_len);
+	bar[bar_len] = '\0';
+
+	setverbose();
+
+#if CPU_TIME_AVAILABLE
+	message("%-*s %*s %*s %*s %*s",
+		max_width->name, name_heading_string,
+		max_width->user, user_heading_string,
+		max_width->system, system_heading_string,
+		max_width->elapsed, elapsed_heading_string,
+		max_width->percent, percent_heading_string);
+	message("%.*s %.*s %.*s %.*s %.*s",
+		max_width->name, bar,
+		max_width->user, bar,
+		max_width->system, bar,
+		max_width->elapsed, bar,
+		max_width->percent, bar);
+#else
+	message("%-*s %*s",
+		max_width->name, name_heading_string,
+		max_width->elapsed, elapsed_heading_string);
+	message("%.*s %.*s",
+		max_width->name, bar,
+		max_width->elapsed, bar);
+#endif
+
+	free(bar);
+}
+
+static void
+print_time_table(const STATISTICS_TIME *t, void *priv)
+{
+	const struct printing_width *max_width = priv;
+
+#if CPU_TIME_AVAILABLE
+	message("%-*s"
+		" %*." PRECISION_STRING(USER) "f"
+		" %*." PRECISION_STRING(SYSTEM) "f"
+		" %*." PRECISION_STRING(ELAPSED) "f"
+		" %*." PRECISION_STRING(PERCENT) "f",
+		max_width->name, t->name,
+		max_width->user, t->user,
+		max_width->system, t->system,
+		max_width->elapsed, t->elapsed,
+		max_width->percent, t->percent);
+#else
+	message("%-*s"
+		" %*." PRECISION_STRING(ELAPSED) "f",
+		max_width->name, t->name,
+		max_width->elapsed, t->elapsed);
+#endif
+}
+
+static void
+print_footer_common(void *priv)
+{
+	free(priv);
+}
+
+struct printng_style {
+	void (*print_header)(void **);
+	void (*print_time)(const STATISTICS_TIME *, void *);
+	void (*print_footer)(void *);
+};
+
+static const struct printng_style printing_styles[] = {
+	/* STATISTICS_STYLE_NONE */
+	{ NULL, NULL, NULL },
+	/* STATISTICS_STYLE_LIST */
+	{ print_header_list, print_time_list, print_footer_common },
+	/* STATISTICS_STYLE_TABLE */
+	{ print_header_table, print_time_table, print_footer_common },
+};
+
+#if !defined(ARRAY_SIZE)
+#define ARRAY_SIZE(x)		(sizeof(x) / sizeof((x)[0]))
+#endif
+
+void
+print_statistics(int style_no)
+{
+	const struct printng_style *style;
+	STATISTICS_TIME *t;
+	void *priv;
+
+	assert(style_no >= 0 && style_no < ARRAY_SIZE(printing_styles));
+	style = &printing_styles[style_no];
+
+	if (style->print_header != NULL)
+		style->print_header(&priv);
+
+	while (!STAILQ_EMPTY(&statistics_time_list)) {
+		t = STAILQ_FIRST(&statistics_time_list);
+
+		if (style->print_time != NULL)
+			style->print_time(t, priv);
+
+		STAILQ_REMOVE_HEAD(&statistics_time_list, next);
+		free(t);
+	}
+
+	if (style->print_footer != NULL)
+		style->print_footer(priv);
+}
+
Index: libutil/statistics.h
===================================================================
RCS file: libutil/statistics.h
diff -N libutil/statistics.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ libutil/statistics.h	2 Nov 2009 00:16:49 -0000
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2009
+ *	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/>.
+ */
+
+#ifndef _STATISTICS_H_
+#define _STATISTICS_H_
+
+/*
+ * STATISTICS_TIME
+ *
+ * Usage:
+ *     main()
+ *     {
+ *         STATISTICS_TIME *T_all, *T_foo, *T_bar[3];
+ *
+ *         T_all = statistics_time_start("The entire time");
+ *         T_foo = statistics_time_start("Time of making foo");
+ *         makefoo();
+ *         statistics_time_end(T_foo);
+ *         for (i = 0; i < 3; i++) {
+ *             T_bar[i] = statistics_time_start("Time of making bar%d", i);
+ *             makebar(i);
+ *             statistics_time_end(T_bar[i]);
+ *         }
+ *         statistics_time_end(T_all);
+ *         print_statistics(style);
+ *         exit(0);
+ *     }
+ */
+struct statistics_time;
+typedef struct statistics_time STATISTICS_TIME;
+
+STATISTICS_TIME *statistics_time_start(const char *, ...);
+void statistics_time_end(STATISTICS_TIME *);
+
+/*
+ * STATISTICS_STYLE_NONE:
+ *    Resource deallocation only.
+ *
+ * STATISTICS_STYLE_LIST:
+ *    Print statistics information like following, and deallocate resource.
+ *
+ *     - Time of making foo .... user  2.016s system 0.128s elapsed  1.437s 149.0%
+ *     - Time of making bar0 ... user  0.268s system 0.040s elapsed  0.282s 109.1%
+ *     - Time of making bar1 ... user  1.084s system 0.120s elapsed  1.208s  99.2%
+ *     - Time of making bar2 ... user 18.325s system 2.112s elapsed 16.010s 127.3%
+ *     - The entire time ....... user 21.721s system 2.420s elapsed 18.989s 127.4%
+ *
+ * STATISTICS_STYLE_TABLE:
+ *    Print statistics information like following, and deallocate resource.
+ *
+ *     period              user[sec] system[sec] elapsed[sec]  %CPU
+ *     ------------------- --------- ----------- ------------ -----
+ *     Time of making foo      2.016       0.128        1.437 149.0
+ *     Time of making bar0     0.268       0.040        0.282 109.1
+ *     Time of making bar1     1.084       0.120        1.208  99.2
+ *     Time of making bar2    18.325       2.112       16.010 127.3
+ *     The entire time        21.721       2.420       18.989 127.4
+ */
+enum {
+	STATISTICS_STYLE_NONE,
+	STATISTICS_STYLE_LIST,
+	STATISTICS_STYLE_TABLE
+};
+
+void print_statistics(int);
+
+#endif
Index: libutil/strbuf.c
===================================================================
RCS file: /sources/global/global/libutil/strbuf.c,v
retrieving revision 1.35
diff -u -p -r1.35 strbuf.c
--- libutil/strbuf.c	21 Jul 2007 17:15:56 -0000	1.35
+++ libutil/strbuf.c	2 Nov 2009 00:16:49 -0000
@@ -361,6 +361,20 @@ strbuf_sprintf(STRBUF *sb, const char *s
 	va_list ap;
 
 	va_start(ap, s);
+	strbuf_vsprintf(sb, s, ap);
+	va_end(ap);
+}
+/*
+ * strbuf_vsprintf: do sprintf into string buffer.
+ *
+ *	i)	sb	STRBUF structure
+ *	i)	s	similar to vsprintf()
+ *			Currently the following format is supported.
+ *			%s, %d, %<number>d, %<number>s, %-<number>d, %-<number>s
+ */
+void
+strbuf_vsprintf(STRBUF *sb, const char *s, va_list ap)
+{
 	if (sb->alloc_failed)
 		return;
 	for (; *s; s++) {
@@ -421,7 +435,6 @@ strbuf_sprintf(STRBUF *sb, const char *s
 			}
 		}
 	}
-	va_end(ap);
 }
 /*
  * strbuf_close: close string buffer.
Index: libutil/strbuf.h
===================================================================
RCS file: /sources/global/global/libutil/strbuf.h,v
retrieving revision 1.23
diff -u -p -r1.23 strbuf.h
--- libutil/strbuf.h	22 Jul 2007 02:32:55 -0000	1.23
+++ libutil/strbuf.h	2 Nov 2009 00:16:49 -0000
@@ -124,8 +124,10 @@ char *strbuf_value(STRBUF *);
 void strbuf_trim(STRBUF *);
 void strbuf_close(STRBUF *);
 char *strbuf_fgets(STRBUF *, FILE *, int);
-void strbuf_sprintf(STRBUF *sb, const char *s, ...)
+void strbuf_sprintf(STRBUF *, const char *, ...)
 	__attribute__ ((__format__ (__printf__, 2, 3)));
+void strbuf_vsprintf(STRBUF *, const char *, va_list)
+	__attribute__ ((__format__ (__printf__, 2, 0)));
 STRBUF *strbuf_open_tempbuf(void);
 void strbuf_release_tempbuf(STRBUF *);
 
