]> granicus.if.org Git - sysstat/commitdiff
sadf modified to make it easier to add new output formats.
authorSebastien Godard <sysstat@orange.fr>
Sat, 13 Aug 2011 12:28:19 +0000 (14:28 +0200)
committerSebastien Godard <sysstat@orange.fr>
Sat, 13 Aug 2011 12:28:19 +0000 (14:28 +0200)
sadf has been heavily modified to make it easiser to add new
output formats. The idea was to take the same architecture pattern
than that of sar. Anyway, I haven't been able to achieve this goal:
The design is still not generic although things have improved.

CHANGES
Makefile.in
format.c [new file with mode: 0644]
sa.h
sadf.c
sadf.h
sadf_misc.c [new file with mode: 0644]
xml_stats.c
xml_stats.h

diff --git a/CHANGES b/CHANGES
index 18c7181e9ea4012a81adf4696498a4591e5ebbdd..5d78354e429a4d833addc02886aabf1d9b285623 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,8 @@
 Changes:
 
 xxxx/xx/xx: Version 10.0.2 - Sebastien Godard (sysstat <at> orange.fr)
+       * sadf modified to make it easier to add new output formats.
+         Its design is still not generic anyway.
        * [Jeroen Roovers]: Automate translation files handling in
          Makefile.in.
        * Various cosmetic changes (sar.c, sadf.c).
index b885a1aeedd3a1fd79112b5712d24eb8f365d0fb..b8e36d1a22c75ac1138f257aa864dcdd5ea1d233 100644 (file)
@@ -181,10 +181,14 @@ pr_stats.o: pr_stats.c sa.h ioconf.h sysconfig.h pr_stats.h
 
 rndr_stats.o: rndr_stats.c sa.h ioconf.h sysconfig.h rndr_stats.h
 
-xml_stats.o: xml_stats.c sa.h ioconf.h sysconfig.h xml_stats.h
+xml_stats.o: xml_stats.c sa.h sadf.h ioconf.h sysconfig.h xml_stats.h
 
 sa_wrap.o: sa_wrap.c sa.h rd_stats.h rd_sensors.h
 
+format.o: format.c sadf.h
+
+sadf_misc.o: sadf_misc.c sadf.h sa.h
+
 # Explicit rules needed to prevent possible file corruption
 # when using parallel execution.
 libsyscom.a: common.o ioconf.o
@@ -205,7 +209,7 @@ sar: sar.o act_sar.o sa_common.o pr_stats.o libsyscom.a
 
 sadf.o: sadf.c sadf.h version.h sa.h common.h ioconf.h sysconfig.h rndr_stats.h xml_stats.h
 
-sadf: sadf.o act_sadf.o rndr_stats.o xml_stats.o sa_common.o libsyscom.a
+sadf: sadf.o act_sadf.o format.o sadf_misc.o rndr_stats.o xml_stats.o sa_common.o libsyscom.a
 
 iostat.o: iostat.c iostat.h version.h common.h ioconf.h sysconfig.h rd_stats.h
 
diff --git a/format.c b/format.c
new file mode 100644 (file)
index 0000000..07c2d98
--- /dev/null
+++ b/format.c
@@ -0,0 +1,92 @@
+/*
+ * format.c: Output format definitions for sadf
+ * (C) 2011 by Sebastien GODARD (sysstat <at> orange.fr)
+ *
+ ***************************************************************************
+ * 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 2 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 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, write to the Free Software Foundation, Inc., *
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                   *
+ ***************************************************************************
+ */
+
+#include "sadf.h"
+
+/*
+ ***************************************************************************
+ * Definitions of output formats.
+ * See sadf.h file for format structure definition.
+ ***************************************************************************
+ */
+
+/*
+ * Display only datafile header.
+ */
+struct report_format hdr_fmt = {
+       .id             = F_HEADER_OUTPUT,
+       .options        = FO_HEADER_ONLY + FO_BAD_FILE_FORMAT,
+       .f_header       = print_hdr_header,
+       .f_statistics   = NULL,
+       .f_timestamp    = NULL,
+       .f_restart      = NULL,
+       .f_comment      = NULL
+};
+
+/*
+ * Database friendly format.
+ */
+struct report_format db_fmt = {
+       .id             = F_DB_OUTPUT,
+       .options        = FO_GROUPED_STATS + FO_TRUE_TIME + FO_HORIZONTALLY +
+                         FO_SEC_EPOCH + FO_FIELD_LIST,
+       .f_header       = NULL,
+       .f_statistics   = NULL,
+       .f_timestamp    = NULL,
+       .f_restart      = print_db_restart,
+       .f_comment      = print_db_comment
+};
+
+/*
+ * Format easily handled by pattern processing commands like awk.
+ */
+struct report_format ppc_fmt = {
+       .id             = F_PPC_OUTPUT,
+       .options        = FO_GROUPED_STATS + FO_TRUE_TIME + FO_SEC_EPOCH,
+       .f_header       = NULL,
+       .f_statistics   = NULL,
+       .f_timestamp    = NULL,
+       .f_restart      = print_ppc_restart,
+       .f_comment      = print_ppc_comment
+};
+
+/*
+ * XML output.
+ */
+struct report_format xml_fmt = {
+       .id             = F_XML_OUTPUT,
+       .options        = FO_HEADER_ONLY + FO_TRUE_TIME,
+       .f_header       = print_xml_header,
+       .f_statistics   = print_xml_statistics,
+       .f_timestamp    = print_xml_timestamp,
+       .f_restart      = print_xml_restart,
+       .f_comment      = print_xml_comment
+};
+
+/*
+ * Array of output formats.
+ */
+struct report_format *fmt[NR_FMT] = {
+       &hdr_fmt,
+       &db_fmt,
+       &ppc_fmt,
+       &xml_fmt
+};
diff --git a/sa.h b/sa.h
index 08af4fd08e726ba114e32d54022421254230e0b9..df1957e7e04deafba88844456e6aded963b611ec 100644 (file)
--- a/sa.h
+++ b/sa.h
@@ -78,8 +78,8 @@
 #define S_F_INTERVAL_SET       0x00000010
 #define S_F_TRUE_TIME          0x00000020
 #define S_F_LOCK_FILE          0x00000040
-/* Unused                      0x00000080 */
-/* Unused                      0x00000100 */
+#define S_F_SEC_EPOCH          0x00000080
+#define S_F_HDR_ONLY           0x00000100
 #define S_F_FILE_LOCKED                0x00000200
 #define S_F_PER_PROC           0x00000400
 #define S_F_HORIZONTALLY       0x00000800
@@ -92,6 +92,8 @@
 #define INTERVAL_SET(m)                (((m) & S_F_INTERVAL_SET) == S_F_INTERVAL_SET)
 #define PRINT_TRUE_TIME(m)     (((m) & S_F_TRUE_TIME)    == S_F_TRUE_TIME)
 #define LOCK_FILE(m)           (((m) & S_F_LOCK_FILE)    == S_F_LOCK_FILE)
+#define PRINT_SEC_EPOCH(m)     (((m) & S_F_SEC_EPOCH)    == S_F_SEC_EPOCH)
+#define DISPLAY_HDR_ONLY(m)    (((m) & S_F_HDR_ONLY)     == S_F_HDR_ONLY)
 #define FILE_LOCKED(m)         (((m) & S_F_FILE_LOCKED)  == S_F_FILE_LOCKED)
 #define WANT_PER_PROC(m)       (((m) & S_F_PER_PROC)     == S_F_PER_PROC)
 #define DISPLAY_HORIZONTALLY(m)        (((m) & S_F_HORIZONTALLY) == S_F_HORIZONTALLY)
 
 #define UTSNAME_LEN            65
 #define TIMESTAMP_LEN          16
-#define XML_TIMESTAMP_LEN      64
 #define HEADER_LINE_LEN                512
 
 /* Maximum number of args that can be passed to sadc */
@@ -301,7 +302,7 @@ struct activity {
         */
        unsigned int id;
        /*
-        * Activity options (AO_SELECTED, ...)
+        * Activity options (AO_...)
         */
        unsigned int options;
        /*
@@ -311,7 +312,7 @@ struct activity {
         */
        unsigned int magic;
        /*
-        * an activity belongs to a group (and only one).
+        * An activity belongs to a group (and only one).
         * Groups are those selected with option -S of sadc.
         */
        unsigned int group;
diff --git a/sadf.c b/sadf.c
index b3538d33bba307ccbe4af41eed9b07b1989ca8c4..36e1460087af8ceefa8e758c6a56b4e43e8552d0 100644 (file)
--- a/sadf.c
+++ b/sadf.c
@@ -51,6 +51,7 @@ long interval = -1, count = 0;
 unsigned int flags = 0;
 unsigned int dm_major;         /* Device-mapper major number */
 unsigned int format = 0;       /* Output format */
+unsigned int f_position = 0;   /* Output format position in array */
 
 /* File header */
 struct file_header file_hdr;
@@ -66,12 +67,12 @@ unsigned int id_seq[NR_ACT];
 /* Current record header */
 struct record_header record_hdr[3];
 
-struct tm rectime, loctime;
 /* Contain the date specified by -s and -e options */
 struct tstamp tm_start, tm_end;
 char *args[MAX_ARGV_NR];
 
 extern struct activity *act[];
+extern struct report_format *fmt[];
 
 /*
  ***************************************************************************
@@ -88,7 +89,7 @@ void usage(char *progname)
                progname);
 
        fprintf(stderr, _("Options are:\n"
-                         "[ -d | -D | -H | -p | -x ] [ -C ] [ -h ] [ -t ] [ -V ]\n"
+                         "[ -d | -p | -x ] [ -C ] [ -H ] [ -h ] [ -T ] [ -t ] [ -V ]\n"
                          "[ -P { <cpu> [,...] | ALL } ] [ -s [ <hh:mm:ss> ] ] [ -e [ <hh:mm:ss> ] ]\n"
                          "[ -- <sar_options> ]\n"));
        exit(1);
@@ -110,75 +111,285 @@ void init_structures(void)
 
 /*
  ***************************************************************************
- * Fill the rectime structure with current record's date and time, based on
- * current record's "number of seconds since the epoch" saved in file.
+ * Look for output format in array.
+ *
+ * IN:
+ * @fmt                Array of output formats.
+ * @format     Output format to look for.
+ *
+ * RETURNS:
+ * Position of output format in array.
+ ***************************************************************************
+ */
+int get_format_position(struct report_format *fmt[], unsigned int format)
+{
+        int i;
+
+        for (i = 0; i < NR_FMT; i++) {
+                if (fmt[i]->id == format)
+                        break;
+        }
+
+        if (i == NR_FMT)
+               /* Should never happen */
+                return 0;
+
+        return i;
+}
+
+/*
+ ***************************************************************************
+ * Check that options entered on the command line are consistent with
+ * selected output format. If no output format has been explicitly entered,
+ * then select a default one.
+ ***************************************************************************
+ */
+void check_format_options(void)
+{
+       if (!format) {
+               /* Select output format if none has been selected */
+               if (DISPLAY_HDR_ONLY(flags)) {
+                       format = F_HEADER_OUTPUT;
+               }
+               else {
+                       format = F_PPC_OUTPUT;
+               }
+       }
+
+       /* Get format position in array */
+       f_position = get_format_position(fmt, format);
+       
+       /* Check options consistency wrt output format */
+       if (!ACCEPT_HEADER_ONLY(fmt[f_position]->options)) {
+               /* Remove option -H */
+               flags &= ~S_F_HDR_ONLY;
+       }
+       if (!ACCEPT_HORIZONTALLY(fmt[f_position]->options)) {
+               /* Remove option -h */
+               flags &= ~S_F_HORIZONTALLY;
+       }
+       if (!ACCEPT_TRUE_TIME(fmt[f_position]->options)) {
+               /* Remove option -t */
+               flags &= ~S_F_TRUE_TIME;
+       }
+       if (!ACCEPT_SEC_EPOCH(fmt[f_position]->options)) {
+               /* Remove option -T */
+               flags &= ~S_F_SEC_EPOCH;
+       }
+}
+
+/*
+ ***************************************************************************
+ * Fill the rectime and loctime structures with current record's date and
+ * time, based on current record's "number of seconds since the epoch" saved
+ * in file.
  * The resulting timestamp is expressed in UTC or in local time, depending
  * on whether option -t has been used or not.
- * NB: Option -t is ignored when option -p is used, since option -p
- * displays its timestamp as a long integer. This is type 'time_t',
- * which is the number of seconds since 1970 _always_ expressed in UTC.
  *
  * IN:
  * @curr       Index in array for current sample statistics.
+ * @rectime    Structure where timestamp (expressed in local time or in UTC
+ *             depending on whether option -t has been used or not) can be
+ *             saved for current record.
+ * @loctime    Structure where timestamp (expressed in local time) can be
+ *             saved for current record.
+ *
+ * OUT:
+ * @rectime    Structure where timestamp for current record has been saved.
+ * @loctime    Structure where timestamp for current record has been saved.
  ***************************************************************************
 */
-void sadf_get_record_timestamp_struct(int curr)
+void sadf_get_record_timestamp_struct(int curr, struct tm *rectime, struct tm *loctime)
 {
        struct tm *ltm;
 
        if ((ltm = localtime((const time_t *) &record_hdr[curr].ust_time)) != NULL) {
-               loctime = *ltm;
+               *loctime = *ltm;
        }
 
-       if (!PRINT_TRUE_TIME(flags) ||
-           ((format != S_O_DB_OPTION) && (format != S_O_XML_OPTION))) {
-               /* Option -t is valid only with options -d and -x */
+       if (!PRINT_TRUE_TIME(flags)) {
+               /* Option -t not used: Display timestamp in UTC */
                ltm = gmtime((const time_t *) &record_hdr[curr].ust_time);
        }
 
        if (ltm) {
-               rectime = *ltm;
+               *rectime = *ltm;
        }
 }
 
 /*
  ***************************************************************************
- * Set current record's timestamp string. This timestamp is expressed in
- * UTC or in local time, depending on whether option -t has been used or
- * not.
- * NB: If options -D or -p have been used, the timestamp in expressed in
- * seconds since 1970.
+ * Set current record's timestamp strings (date and time). This timestamp is
+ * expressed in UTC or in local time, depending on whether option -t has
+ * been used or not.
  *
  * IN:
  * @curr       Index in array for current sample statistics.
- * @len                Maximum length of timestamp string.
+ * @cur_date   String where timestamp's date will be saved.
+ * @cur_time   String where timestamp's time will be saved.
+ * @len                Maximum length of timestamp strings.
+ * @rectime    Structure with current timestamp (expressed in local time or
+ *             in UTC depending on whether option -t has been used or not)
+ *             that should be broken down in date and time strings.
  *
  * OUT:
- * @cur_time   Timestamp string.
+ * @cur_date   Timestamp's date string.
+ * @cur_time   Timestamp's time string. May contain the number of seconds
+ *             since the epoch (01-01-1970) if option -T has been used.
  ***************************************************************************
 */
-void set_record_timestamp_string(int curr, char *cur_time, int len)
+void set_record_timestamp_string(int curr, char *cur_date, char *cur_time, int len,
+                                struct tm *rectime)
 {
-       /* Fill timestamp structure */
-       sadf_get_record_timestamp_struct(curr);
-
        /* Set cur_time date value */
-       if (format == S_O_DB_OPTION) {
-               if (PRINT_TRUE_TIME(flags)) {
-                       strftime(cur_time, len, "%Y-%m-%d %H:%M:%S", &rectime);
-               }
-               else {
-                       strftime(cur_time, len, "%Y-%m-%d %H:%M:%S UTC", &rectime);
-               }
-       }
-       else if ((format == S_O_PPC_OPTION) || (format == S_O_DBD_OPTION)) {
+       if (PRINT_SEC_EPOCH(flags)) {
                sprintf(cur_time, "%ld", record_hdr[curr].ust_time);
+               strcpy(cur_date, "");
        }
+       else {
+               /*
+                * If PRINT_TRUE_TIME(flags) is true (ie. option -t has been used) then
+                * cur_time is expressed in local time. Else it is expressed in UTC.
+                */
+               strftime(cur_date, len, "%Y-%m-%d", rectime);
+               strftime(cur_time, len, "%H-%M-%S", rectime);
+       }
+}
+
+/*
+ ***************************************************************************
+ * Print tabulations
+ *
+ * IN:
+ * @nr_tab     Number of tabs to print.
+ ***************************************************************************
+ */
+void prtab(int nr_tab)
+{
+       int i;
+
+       for (i = 0; i < nr_tab; i++) {
+               printf("\t");
+       }
+}
+
+/*
+ ***************************************************************************
+ * printf() function modified for XML display
+ *
+ * IN:
+ * @nr_tab     Number of tabs to print.
+ * @fmtf       printf() format.
+ ***************************************************************************
+ */
+void xprintf(int nr_tab, const char *fmtf, ...)
+{
+       static char buf[1024];
+       va_list args;
+
+       va_start(args, fmtf);
+       vsnprintf(buf, sizeof(buf), fmtf, args);
+       va_end(args);
+
+       prtab(nr_tab);
+       printf("%s\n", buf);
 }
 
 /*
  ***************************************************************************
- * Display the field list (when displaying stats in DB format)
+ * Display restart records for textual (XML-like) reports.
+ *
+ * IN:
+ * @curr               Index in array for current sample statistics.
+ * @use_tm_start       Set to TRUE if option -s has been used.
+ * @use_tm_end         Set to TRUE if option -e has been used.
+ * @tab                        Number of tabulations to print.
+ * @rectime            Structure where timestamp (expressed in local time
+ *                     or in UTC depending on whether option -t has been
+ *                     used or not) can be saved for current record.
+ * @loctime            Structure where timestamp (expressed in local time)
+ *                     can be saved for current record.
+ *
+ * OUT:
+ * @rectime            Structure where timestamp for current record has
+ *                     been saved.
+ * @loctime            Structure where timestamp for current record has
+ *                     been saved.
+ ***************************************************************************
+ */
+void write_xml_restarts(int curr, int use_tm_start, int use_tm_end, int tab,   /* FIXME: revoir nom proc */
+                       struct tm *rectime, struct tm *loctime)
+{
+       char cur_date[32], cur_time[32];
+
+       /* Fill timestamp structure for current record */
+       sadf_get_record_timestamp_struct(curr, rectime, loctime);
+
+       /* The record must be in the interval specified by -s/-e options */
+       if ((use_tm_start && (datecmp(loctime, &tm_start) < 0)) ||
+           (use_tm_end && (datecmp(loctime, &tm_end) > 0)))
+               return;
+
+       set_record_timestamp_string(curr, cur_date, cur_time, 32, rectime);
+
+       if (*fmt[f_position]->f_restart) {
+               (*fmt[f_position]->f_restart)(&tab, F_MAIN, cur_date, cur_time,
+                                             !PRINT_TRUE_TIME(flags), &file_hdr);
+       }
+}
+
+/*
+ ***************************************************************************
+ * Display XML COMMENT records for textual (XML-like) reports.
+ *
+ * IN:
+ * @curr               Index in array for current sample statistics.
+ * @use_tm_start       Set to TRUE if option -s has been used.
+ * @use_tm_end         Set to TRUE if option -e has been used.
+ * @tab                        Number of tabulations to print.
+ * @ifd                        Input file descriptor.
+ * @rectime            Structure where timestamp (expressed in local time
+ *                     or in UTC depending on whether option -t has been
+ *                     used or not) can be saved for current record.
+ * @loctime            Structure where timestamp (expressed in local time)
+ *                     can be saved for current record.
+ *
+ * OUT:
+ * @rectime            Structure where timestamp for current record has
+ *                     been saved.
+ * @loctime            Structure where timestamp for current record has
+ *                     been saved.
+ ***************************************************************************
+ */
+void write_xml_comments(int curr, int use_tm_start, int use_tm_end, int tab, int ifd,  /* FIXME: revoir nom proc */
+                       struct tm *rectime, struct tm *loctime)
+{
+       char cur_date[32], cur_time[32];
+       char file_comment[MAX_COMMENT_LEN];
+
+       sa_fread(ifd, file_comment, MAX_COMMENT_LEN, HARD_SIZE);
+       file_comment[MAX_COMMENT_LEN - 1] = '\0';
+
+       /* Fill timestamp structure for current record */
+       sadf_get_record_timestamp_struct(curr, rectime, loctime);
+
+       /* The record must be in the interval specified by -s/-e options */
+       if ((use_tm_start && (datecmp(loctime, &tm_start) < 0)) ||
+           (use_tm_end && (datecmp(loctime, &tm_end) > 0)))
+               return;
+
+       set_record_timestamp_string(curr, cur_date, cur_time, 32, rectime);
+
+       if (*fmt[f_position]->f_comment) {
+               (*fmt[f_position]->f_comment)(&tab, F_MAIN, cur_date, cur_time,
+                                             !PRINT_TRUE_TIME(flags), file_comment,
+                                             &file_hdr);
+       }
+}
+
+/*
+ ***************************************************************************
+ * Display the field list (used eg. in database format).
  *
  * IN:
  * @act_d      Activity to display, or ~0 for all.
@@ -219,7 +430,6 @@ void list_fields(unsigned int act_id)
                        }
                }
        }
-       
        printf("\n");
 }
 
@@ -235,20 +445,30 @@ void list_fields(unsigned int act_id)
  * @itv                Interval of time in jiffies.
  * @g_itv      Interval of time in jiffies multiplied by the number of
  *             processors.
- * @cur_time   Current timestamp.
+ * @cur_date   Date string for current record.
+ * @cur_time   Time string for current record.
  * @act_id     Activity to display, or ~0 for all.
  ***************************************************************************
  */
 void write_mech_stats(int curr, unsigned long dt, unsigned long long itv,
-                     unsigned long long g_itv, char *cur_time, unsigned int act_id)
+                     unsigned long long g_itv, char *cur_date, char *cur_time,
+                     unsigned int act_id)
 {
        int i;
-       char pre[80];   /* Text at beginning of each line */
-       int isdb = ((format == S_O_DB_OPTION) || (format == S_O_DBD_OPTION));
+       char pre[80], temp[80]; /* Text at beginning of each line */
+       int isdb = (format == F_DB_OUTPUT);
        
        /* This substring appears on every output line, preformat it here */
-       snprintf(pre, 80, "%s%s%ld%s%s",
-                file_hdr.sa_nodename, seps[isdb], dt, seps[isdb], cur_time);
+       snprintf(pre, 80, "%s%s%ld%s",
+                file_hdr.sa_nodename, seps[isdb], dt, seps[isdb]);
+       if (strlen(cur_date)) {
+               snprintf(temp, 80, "%s%s ", pre, cur_date);
+       }
+       else {
+               strcpy(temp, pre);
+       }
+       snprintf(pre, 80, "%s%s%s", temp, cur_time,
+                strlen(cur_date) && !PRINT_TRUE_TIME(flags) ? " UTC" : "");
        pre[79] = '\0';
 
        if (DISPLAY_HORIZONTALLY(flags)) {
@@ -282,6 +502,12 @@ void write_mech_stats(int curr, unsigned long dt, unsigned long long itv,
  * @use_tm_start       Set to TRUE if option -s has been used.
  * @use_tm_end         Set to TRUE if option -e has been used.
  * @act_id             Activities to display.
+ * @cpu_nr             Number of processors for current activity data file.
+ * @rectime            Structure where timestamp (expressed in local time
+ *                     or in UTC depending on whether option -t has been
+ *                     used or not) can be saved for current record.
+ * @loctime            Structure where timestamp (expressed in local time)
+ *                     can be saved for current record.
  *
  * OUT:
  * @cnt                        Set to 0 to indicate that no other lines of stats
@@ -292,16 +518,12 @@ void write_mech_stats(int curr, unsigned long dt, unsigned long long itv,
  ***************************************************************************
  */
 int write_parsable_stats(int curr, int reset, long *cnt, int use_tm_start,
-                        int use_tm_end, unsigned int act_id)
+                        int use_tm_end, unsigned int act_id, __nr_t cpu_nr,
+                        struct tm *rectime, struct tm *loctime)
 {
        unsigned long long dt, itv, g_itv;
-       char cur_time[26];
+       char cur_date[32], cur_time[32];
        static int cross_day = FALSE;
-       static __nr_t cpu_nr = -1;
-       
-       if (cpu_nr < 0) {
-               cpu_nr = act[get_activity_position(act, A_CPU)]->nr;
-       }
 
        /*
         * Check time (1).
@@ -315,8 +537,8 @@ int write_parsable_stats(int curr, int reset, long *cnt, int use_tm_start,
                /* Not close enough to desired interval */
                return 0;
 
-       /* Set current timestamp */
-       set_record_timestamp_string(curr, cur_time, 26);
+       /* Fill timestamp structure for current record */
+       sadf_get_record_timestamp_struct(curr, rectime, loctime);
 
        /* Check if we are beginning a new day */
        if (use_tm_start && record_hdr[!curr].ust_time &&
@@ -331,11 +553,11 @@ int write_parsable_stats(int curr, int reset, long *cnt, int use_tm_start,
                 * sar -s time_start -e time_end with
                 * time_start(day D) > time_end(day D+1)
                 */
-               loctime.tm_hour += 24;
+               loctime->tm_hour += 24;
        }
 
        /* Check time (2) */
-       if (use_tm_start && (datecmp(&loctime, &tm_start) < 0))
+       if (use_tm_start && (datecmp(loctime, &tm_start) < 0))
                /* it's too soon... */
                return 0;
 
@@ -344,7 +566,7 @@ int write_parsable_stats(int curr, int reset, long *cnt, int use_tm_start,
                      cpu_nr, &itv, &g_itv);
 
        /* Check time (3) */
-       if (use_tm_end && (datecmp(&loctime, &tm_end) > 0)) {
+       if (use_tm_end && (datecmp(loctime, &tm_end) > 0)) {
                /* It's too late... */
                *cnt = 0;
                return 0;
@@ -356,14 +578,17 @@ int write_parsable_stats(int curr, int reset, long *cnt, int use_tm_start,
                dt++;
        }
 
-       write_mech_stats(curr, dt, itv, g_itv, cur_time, act_id);
+       /* Set current timestamp string */
+       set_record_timestamp_string(curr, cur_date, cur_time, 32, rectime);
+
+       write_mech_stats(curr, dt, itv, g_itv, cur_date, cur_time, act_id);
 
        return 1;
 }
 
 /*
  ***************************************************************************
- * Display XML activity records
+ * Display activity records for textual (XML-like) formats.
  *
  * IN:
  * @curr               Index in array for current sample statistics.
@@ -373,6 +598,11 @@ int write_parsable_stats(int curr, int reset, long *cnt, int use_tm_start,
  *                     (used in next_slice() function).
  * @tab                        Number of tabulations to print.
  * @cpu_nr             Number of processors.
+ * @rectime            Structure where timestamp (expressed in local time
+ *                     or in UTC depending on whether option -t has been
+ *                     used or not) can be saved for current record.
+ * @loctime            Structure where timestamp (expressed in local time)
+ *                     can be saved for current record.
  *
  * OUT:
  * @cnt                        Set to 0 to indicate that no other lines of stats
@@ -383,15 +613,16 @@ int write_parsable_stats(int curr, int reset, long *cnt, int use_tm_start,
  ***************************************************************************
  */
 int write_xml_stats(int curr, int use_tm_start, int use_tm_end, int reset,
-                   long *cnt, int tab, __nr_t cpu_nr)
+                   long *cnt, int tab, __nr_t cpu_nr, struct tm *rectime,
+                   struct tm *loctime)
 {
        int i;
        unsigned long long dt, itv, g_itv;
-       char cur_time[XML_TIMESTAMP_LEN];
+       char cur_date[32], cur_time[32];
        static int cross_day = FALSE;
 
        /* Fill timestamp structure (rectime) for current record */
-       sadf_get_record_timestamp_struct(curr);
+       sadf_get_record_timestamp_struct(curr, rectime, loctime);
 
        /*
         * Check time (1).
@@ -418,11 +649,11 @@ int write_xml_stats(int curr, int use_tm_start, int use_tm_end, int reset,
                 * sar -s time_start -e time_end with
                 * time_start(day D) > time_end(day D+1)
                 */
-               loctime.tm_hour += 24;
+               loctime->tm_hour += 24;
        }
 
        /* Check time (2) */
-       if (use_tm_start && (datecmp(&loctime, &tm_start) < 0))
+       if (use_tm_start && (datecmp(loctime, &tm_start) < 0))
                /* it's too soon... */
                return 0;
 
@@ -431,7 +662,7 @@ int write_xml_stats(int curr, int use_tm_start, int use_tm_end, int reset,
                      cpu_nr, &itv, &g_itv);
 
        /* Check time (3) */
-       if (use_tm_end && (datecmp(&loctime, &tm_end) > 0)) {
+       if (use_tm_end && (datecmp(loctime, &tm_end) > 0)) {
                /* It's too late... */
                *cnt = 0;
                return 0;
@@ -443,14 +674,19 @@ int write_xml_stats(int curr, int use_tm_start, int use_tm_end, int reset,
                dt++;
        }
 
-       strftime(cur_time, XML_TIMESTAMP_LEN,
-                "date=\"%Y-%m-%d\" time=\"%H:%M:%S\"", &rectime);
+       /* Set date and time strings for current record */
+       set_record_timestamp_string(curr, cur_date, cur_time, 32, rectime);
 
-        xprintf(tab, "<timestamp %s interval=\"%llu\">", cur_time, dt);
+       if (*fmt[f_position]->f_timestamp) {
+               (*fmt[f_position]->f_timestamp)(&tab, F_BEGIN, cur_date, cur_time,
+                                               !PRINT_TRUE_TIME(flags), dt);
+       }
        tab++;
 
        /* Display XML statistics */
        for (i = 0; i < NR_ACT; i++) {
+
+               /* FIXME: PB: le nom de la fonction a appeler va dependre du format d'affichage choisi (ex.: f_xml_print si on est en XML) */
                
                if (CLOSE_MARKUP(act[i]->options) ||
                    (IS_SELECTED(act[i]->options) && (act[i]->nr > 0))) {
@@ -459,73 +695,17 @@ int write_xml_stats(int curr, int use_tm_start, int use_tm_end, int reset,
                }
        }
 
-       xprintf(--tab, "</timestamp>");
+       if (*fmt[f_position]->f_timestamp) {
+               (*fmt[f_position]->f_timestamp)(&tab, F_END, cur_date, cur_time,
+                                               !PRINT_TRUE_TIME(flags), dt);
+       }
 
        return 1;
 }
 
 /*
  ***************************************************************************
- * Display XML restart records
- *
- * IN:
- * @curr               Index in array for current sample statistics.
- * @use_tm_start       Set to TRUE if option -s has been used.
- * @use_tm_end         Set to TRUE if option -e has been used.
- * @tab                        Number of tabulations to print.
- ***************************************************************************
- */
-void write_xml_restarts(int curr, int use_tm_start, int use_tm_end, int tab)
-{
-       char cur_time[64];
-
-       /* Fill timestamp structure for current record */
-       sadf_get_record_timestamp_struct(curr);
-       
-       /* The record must be in the interval specified by -s/-e options */
-       if ((use_tm_start && (datecmp(&loctime, &tm_start) < 0)) ||
-           (use_tm_end && (datecmp(&loctime, &tm_end) > 0)))
-               return;
-
-       strftime(cur_time, 64, "date=\"%Y-%m-%d\" time=\"%H:%M:%S\"", &rectime);
-       xprintf(tab, "<boot %s/>", cur_time);
-}
-
-/*
- ***************************************************************************
- * Display XML COMMENT records
- *
- * IN:
- * @curr               Index in array for current sample statistics.
- * @use_tm_start       Set to TRUE if option -s has been used.
- * @use_tm_end         Set to TRUE if option -e has been used.
- * @tab                        Number of tabulations to print.
- * @ifd                        Input file descriptor.
- ***************************************************************************
- */
-void write_xml_comments(int curr, int use_tm_start, int use_tm_end, int tab, int ifd)
-{
-       char cur_time[64];
-       char file_comment[MAX_COMMENT_LEN];
-
-       sa_fread(ifd, file_comment, MAX_COMMENT_LEN, HARD_SIZE);
-       file_comment[MAX_COMMENT_LEN - 1] = '\0';
-
-       /* Fill timestamp structure for current record */
-       sadf_get_record_timestamp_struct(curr);
-
-       /* The record must be in the interval specified by -s/-e options */
-       if ((use_tm_start && (datecmp(&loctime, &tm_start) < 0)) ||
-           (use_tm_end && (datecmp(&loctime, &tm_end) > 0)))
-               return;
-
-       strftime(cur_time, 64, "date=\"%Y-%m-%d\" time=\"%H:%M:%S\"", &rectime);
-       xprintf(tab, "<comment %s com=\"%s\"/>", cur_time, file_comment);
-}
-
-/*
- ***************************************************************************
- * Print contents of a special (RESTART or COMMENT) record
+ * Print contents of a special (RESTART or COMMENT) record.
  *
  * IN:
  * @curr               Index in array for current sample statistics.
@@ -533,31 +713,38 @@ void write_xml_comments(int curr, int use_tm_start, int use_tm_end, int tab, int
  * @use_tm_end         Set to TRUE if option -e has been used.
  * @rtype              Record type (RESTART or COMMENT).
  * @ifd                        Input file descriptor.
+ * @rectime            Structure where timestamp (expressed in local time
+ *                     or in UTC depending on whether option -t has been
+ *                     used or not) can be saved for current record.
+ * @loctime            Structure where timestamp (expressed in local time)
+ *                     can be saved for current record.
  ***************************************************************************
  */
-void sadf_print_special(int curr, int use_tm_start, int use_tm_end, int rtype, int ifd)
+void sadf_print_special(int curr, int use_tm_start, int use_tm_end, int rtype, int ifd,
+                       struct tm *rectime, struct tm *loctime)
 {
-       char cur_time[26];
+       char cur_date[32], cur_time[32];
        int dp = 1;
 
-       set_record_timestamp_string(curr, cur_time, 26);
+       /* Fill timestamp structure (rectime) for current record */
+       sadf_get_record_timestamp_struct(curr, rectime, loctime);
+
+       /* Set date and time strings for current record */
+       set_record_timestamp_string(curr, cur_date, cur_time, 32, rectime);
 
        /* The record must be in the interval specified by -s/-e options */
-       if ((use_tm_start && (datecmp(&loctime, &tm_start) < 0)) ||
-           (use_tm_end && (datecmp(&loctime, &tm_end) > 0))) {
+       if ((use_tm_start && (datecmp(loctime, &tm_start) < 0)) ||
+           (use_tm_end && (datecmp(loctime, &tm_end) > 0))) {
                dp = 0;
        }
 
        if (rtype == R_RESTART) {
                if (!dp)
                        return;
-               if (format == S_O_PPC_OPTION) {
-                       printf("%s\t-1\t%ld\tLINUX-RESTART\n",
-                              file_hdr.sa_nodename, record_hdr[curr].ust_time);
-               }
-               else if ((format == S_O_DB_OPTION) || (format == S_O_DBD_OPTION)) {
-                       printf("%s;-1;%s;LINUX-RESTART\n",
-                              file_hdr.sa_nodename, cur_time);
+
+               if (*fmt[f_position]->f_restart) {
+                       (*fmt[f_position]->f_restart)(NULL, F_MAIN, cur_date, cur_time,
+                                                     !PRINT_TRUE_TIME(flags), &file_hdr);
                }
        }
        else if (rtype == R_COMMENT) {
@@ -568,110 +755,13 @@ void sadf_print_special(int curr, int use_tm_start, int use_tm_end, int rtype, i
 
                if (!dp || !DISPLAY_COMMENT(flags))
                        return;
-               
-               if (format == S_O_PPC_OPTION) {
-                       printf("%s\t-1\t%ld\tCOM %s\n",
-                              file_hdr.sa_nodename, record_hdr[curr].ust_time,
-                              file_comment);
-               }
-               else if ((format == S_O_DB_OPTION) || (format == S_O_DBD_OPTION)) {
-                       printf("%s;-1;%s;COM %s\n",
-                              file_hdr.sa_nodename, cur_time, file_comment);
-               }
-       }
-}
 
-/*
- ***************************************************************************
- * Display data file header.
- *
- * IN:
- * @dfile      Name of system activity data file.
- * @file_magic System activity file magic header.
- * @file_hdr   System activity file standard header.
- ***************************************************************************
- */
-void display_file_header(char *dfile, struct file_magic *file_magic,
-                        struct file_header *file_hdr)
-{
-       int i, p;
-       static __nr_t cpu_nr = -1;
-
-       if (cpu_nr < 0) {
-               cpu_nr = act[get_activity_position(act, A_CPU)]->nr;
-       }
-       
-       printf(_("System activity data file: %s (%#x)\n"),
-               dfile, file_magic->format_magic);
-
-       display_sa_file_version(file_magic);
-
-       if (file_magic->format_magic != FORMAT_MAGIC) {
-               exit(0);
-       }
-
-       printf(_("Host: "));
-       print_gal_header(localtime((const time_t *) &(file_hdr->sa_ust_time)),
-                        file_hdr->sa_sysname, file_hdr->sa_release,
-                        file_hdr->sa_nodename, file_hdr->sa_machine,
-                        cpu_nr > 1 ? cpu_nr - 1 : 1);
-
-       printf(_("Size of a long int: %d\n"), file_hdr->sa_sizeof_long);
-       
-       printf(_("List of activities:\n"));
-       for (i = 0; i < NR_ACT; i++) {
-               if (!id_seq[i])
-                       continue;
-               if ((p = get_activity_position(act, id_seq[i])) < 0) {
-                       PANIC(id_seq[i]);
-               }
-               printf("%02d: %s\t(x%d)", act[p]->id, act[p]->name, act[p]->nr);
-               if (act[p]->f_count2 || (act[p]->nr2 > 1)) {
-                       printf("\t(x%d)", act[p]->nr2);
+               if (*fmt[f_position]->f_comment) {
+                       (*fmt[f_position]->f_comment)(NULL, F_MAIN, cur_date, cur_time,
+                                                     !PRINT_TRUE_TIME(flags), file_comment,
+                                                     &file_hdr);
                }
-               if (act[p]->magic == ACTIVITY_MAGIC_UNKNOWN) {
-                       printf(_("\t[Unknown activity format]"));
-               }
-               printf("\n");
        }
-
-       exit(0);
-}
-
-/*
- ***************************************************************************
- * Display XML header and host data
- *
- * IN:
- * @tab                Number of tabulations to print.
- * @cpu_nr     Number of processors.
- *
- * OUT:
- * @tab                Number of tabulations to print.
- ***************************************************************************
- */
-void display_xml_header(int *tab, __nr_t cpu_nr)
-{
-       char cur_time[XML_TIMESTAMP_LEN];
-       
-       printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
-       printf("<!DOCTYPE Configure PUBLIC \"DTD v%s sysstat //EN\"\n", XML_DTD_VERSION);
-       printf("\"http://pagesperso-orange.fr/sebastien.godard/sysstat.dtd\">\n");
-
-       xprintf(*tab, "<sysstat>");
-       xprintf(++(*tab), "<sysdata-version>%s</sysdata-version>", XML_DTD_VERSION);
-
-       xprintf(*tab, "<host nodename=\"%s\">", file_hdr.sa_nodename);
-       xprintf(++(*tab), "<sysname>%s</sysname>", file_hdr.sa_sysname);
-       xprintf(*tab, "<release>%s</release>", file_hdr.sa_release);
-               
-       xprintf(*tab, "<machine>%s</machine>", file_hdr.sa_machine);
-       xprintf(*tab, "<number-of-cpus>%d</number-of-cpus>", cpu_nr > 1 ? cpu_nr - 1 : 1);
-
-       /* Fill file timestmap structure (rectime) */
-       get_file_timestamp_struct(flags, &rectime, &file_hdr);
-       strftime(cur_time, XML_TIMESTAMP_LEN, "%Y-%m-%d", &rectime);
-       xprintf(*tab, "<file-date>%s</file-date>", cur_time);
 }
 
 /*
@@ -682,19 +772,26 @@ void display_xml_header(int *tab, __nr_t cpu_nr)
  * @ifd                File descriptor of input file.
  * @fpos       Position in file where reading must start.
  * @curr       Index in array for current sample statistics.
+ * @act_id     Activity to display, or ~0 for all.
  * @file_actlst        List of (known or unknown) activities in file.
+ * @cpu_nr     Number of processors for current activity data file.
+ * @rectime    Structure where timestamp (expressed in local time or in UTC
+ *             depending on whether option -t has been used or not) can be
+ *             saved for current record.
+ * @loctime    Structure where timestamp (expressed in local time) can be
+ *             saved for current record.
  *
  * OUT:
  * @curr       Index in array for next sample statistics.
  * @cnt                Number of lines of stats remaining to write.
  * @eosaf      Set to TRUE if EOF (end of file) has been reached.
- * @act_id     Activity to display, or ~0 for all.
  * @reset      Set to TRUE if last_uptime variable should be
  *             reinitialized (used in next_slice() function).
  ***************************************************************************
  */
 void rw_curr_act_stats(int ifd, off_t fpos, int *curr, long *cnt, int *eosaf,
-                      unsigned int act_id, int *reset, struct file_activity *file_actlst)
+                      unsigned int act_id, int *reset, struct file_activity *file_actlst,
+                       __nr_t cpu_nr, struct tm *rectime, struct tm *loctime)
 {
        unsigned char rtype;
        int next;
@@ -704,7 +801,7 @@ void rw_curr_act_stats(int ifd, off_t fpos, int *curr, long *cnt, int *eosaf,
                exit(2);
        }
        
-       if ((format == S_O_DB_OPTION) || (format == S_O_DBD_OPTION)) {
+       if (DISPLAY_FIELD_LIST(fmt[f_position]->options)) {
                /* Print field list */
                list_fields(act_id);
        }
@@ -733,12 +830,13 @@ void rw_curr_act_stats(int ifd, off_t fpos, int *curr, long *cnt, int *eosaf,
 
                        if (rtype == R_COMMENT) {
                                sadf_print_special(*curr, tm_start.use, tm_end.use,
-                                             R_COMMENT, ifd);
+                                                  R_COMMENT, ifd, rectime, loctime);
                                continue;
                        }
 
                        next = write_parsable_stats(*curr, *reset, cnt,
-                                                   tm_start.use, tm_end.use, act_id);
+                                                   tm_start.use, tm_end.use, act_id,
+                                                   cpu_nr, rectime, loctime);
 
                        if (next) {
                                /*
@@ -761,24 +859,29 @@ void rw_curr_act_stats(int ifd, off_t fpos, int *curr, long *cnt, int *eosaf,
 
 /*
  ***************************************************************************
- * Display activities for -x option.
+ * Display activities for for textual (XML-like) formats.
  *
  * IN:
  * @ifd                File descriptor of input file.
  * @file_actlst        List of (known or unknown) activities in file.
+ * @dfile      System activity data file name.
+ * @file_magic System activity file magic header.
+ * @cpu_nr     Number of processors for current activity data file.
+ * @rectime    Structure where timestamp (expressed in local time or in UTC
+ *             depending on whether option -t has been used or not) can be
+ *             saved for current record.
+ * @loctime    Structure where timestamp (expressed in local time) can be
+ *             saved for current record.
  ***************************************************************************
  */
-void xml_display_loop(int ifd, struct file_activity *file_actlst)
+void xml_display_loop(int ifd, struct file_activity *file_actlst, char *dfile,
+                     struct file_magic *file_magic, __nr_t cpu_nr,
+                     struct tm *rectime, struct tm *loctime)
 {
        int curr, tab = 0, rtype;
        int eosaf = TRUE, next, reset = FALSE;
        long cnt = 1;
        off_t fpos;
-       static __nr_t cpu_nr = -1;
-       
-       if (cpu_nr < 0) {
-               cpu_nr = act[get_activity_position(act, A_CPU)]->nr;
-       }
 
        /* Save current file position */
        if ((fpos = lseek(ifd, 0, SEEK_CUR)) < 0) {
@@ -786,11 +889,17 @@ void xml_display_loop(int ifd, struct file_activity *file_actlst)
                exit(2);
        }
 
-       /* Print XML header */
-       display_xml_header(&tab, cpu_nr);
+       /* Print header (eg. XML file header) */
+       if (*fmt[f_position]->f_header) {
+               (*fmt[f_position]->f_header)(&tab, F_BEGIN, dfile, file_magic,
+                                            &file_hdr, cpu_nr, act, id_seq);
+       }
 
        /* Process activities */
-       xprintf(tab++, "<statistics>");
+       if (*fmt[f_position]->f_statistics) {
+               (*fmt[f_position]->f_statistics)(&tab, F_BEGIN);
+       }
+
        do {
                /*
                 * If this record is a special (RESTART or COMMENT) one,
@@ -807,7 +916,7 @@ void xml_display_loop(int ifd, struct file_activity *file_actlst)
                                 */
                                read_file_stat_bunch(act, 0, ifd, file_hdr.sa_nr_act,
                                                     file_actlst);
-                               sadf_get_record_timestamp_struct(0);
+                               sadf_get_record_timestamp_struct(0, rectime, loctime);
                        }
 
                        if (!eosaf && (rtype == R_COMMENT)) {
@@ -822,8 +931,8 @@ void xml_display_loop(int ifd, struct file_activity *file_actlst)
                        }
                }
                while (!eosaf && ((rtype == R_RESTART) || (rtype == R_COMMENT) ||
-                       (tm_start.use && (datecmp(&loctime, &tm_start) < 0)) ||
-                       (tm_end.use && (datecmp(&loctime, &tm_end) >=0))));
+                       (tm_start.use && (datecmp(loctime, &tm_start) < 0)) ||
+                       (tm_end.use && (datecmp(loctime, &tm_end) >=0))));
 
                /* Save the first stats collected. Used for example in next_slice() function */
                copy_structures(act, id_seq, record_hdr, 2, 0);
@@ -845,7 +954,7 @@ void xml_display_loop(int ifd, struct file_activity *file_actlst)
 
                                        /* next is set to 1 when we were close enough to desired interval */
                                        next = write_xml_stats(curr, tm_start.use, tm_end.use, reset,
-                                                       &cnt, tab, cpu_nr);
+                                                              &cnt, tab, cpu_nr, rectime, loctime);
 
                                        if (next) {
                                                curr ^= 1;
@@ -888,7 +997,10 @@ void xml_display_loop(int ifd, struct file_activity *file_actlst)
                }
        }
        while (!eosaf);
-       xprintf(--tab, "</statistics>");
+
+       if (*fmt[f_position]->f_statistics) {
+               (*fmt[f_position]->f_statistics)(&tab, F_END);
+       }
 
        /* Rewind file */
        if (lseek(ifd, fpos, SEEK_SET) < fpos) {
@@ -897,7 +1009,11 @@ void xml_display_loop(int ifd, struct file_activity *file_actlst)
        }
 
        /* Process now RESTART entries to display restart messages */
-       xprintf(tab++, "<restarts>");
+       if (*fmt[f_position]->f_restart) {
+               (*fmt[f_position]->f_restart)(&tab, F_BEGIN, NULL, NULL, FALSE,
+                                             &file_hdr);
+       }
+
        do {
                if ((eosaf = sa_fread(ifd, &record_hdr[0], RECORD_HEADER_SIZE,
                                      SOFT_SIZE)) == 0) {
@@ -908,7 +1024,8 @@ void xml_display_loop(int ifd, struct file_activity *file_actlst)
                                                     file_actlst);
                        }
                        if (rtype == R_RESTART) {
-                               write_xml_restarts(0, tm_start.use, tm_end.use, tab);
+                               write_xml_restarts(0, tm_start.use, tm_end.use, tab,
+                                                  rectime, loctime);
                        }
                        else if (rtype == R_COMMENT) {
                                /* Ignore COMMENT record */
@@ -919,7 +1036,10 @@ void xml_display_loop(int ifd, struct file_activity *file_actlst)
                }
        }
        while (!eosaf);
-       xprintf(--tab, "</restarts>");
+
+       if (*fmt[f_position]->f_restart) {
+               (*fmt[f_position]->f_restart)(&tab, F_END, NULL, NULL, FALSE, &file_hdr);
+       }
 
        /* Rewind file */
        if (lseek(ifd, fpos, SEEK_SET) < fpos) {
@@ -929,7 +1049,10 @@ void xml_display_loop(int ifd, struct file_activity *file_actlst)
 
        /* Last, process COMMENT entries to display comments */
        if (DISPLAY_COMMENT(flags)) {
-               xprintf(tab++, "<comments>");
+               if (*fmt[f_position]->f_comment) {
+                       (*fmt[f_position]->f_comment)(&tab, F_BEGIN, NULL, NULL, 0, NULL,
+                                                     &file_hdr);
+               }
                do {
                        if ((eosaf = sa_fread(ifd, &record_hdr[0], RECORD_HEADER_SIZE,
                                              SOFT_SIZE)) == 0) {
@@ -941,28 +1064,42 @@ void xml_display_loop(int ifd, struct file_activity *file_actlst)
                                }
                                if (rtype == R_COMMENT) {
                                        write_xml_comments(0, tm_start.use, tm_end.use,
-                                                          tab, ifd);
+                                                          tab, ifd, rectime, loctime);
                                }
                        }
                }
                while (!eosaf);
-               xprintf(--tab, "</comments>");
+
+               if (*fmt[f_position]->f_comment) {
+                       (*fmt[f_position]->f_comment)(&tab, F_END, NULL, NULL, 0, NULL,
+                                                     &file_hdr);
+               }
+       }
+
+       /* Print header trailer */
+       if (*fmt[f_position]->f_header) {
+               (*fmt[f_position]->f_header)(&tab, F_END, dfile, file_magic,
+                                            &file_hdr, cpu_nr, act, id_seq);
        }
-       
-       xprintf(--tab, "</host>");
-       xprintf(--tab, "</sysstat>");
 }
 
 /*
  ***************************************************************************
- * Display activities for -p and -d options.
+ * Display activities for non textual formats.
  *
  * IN:
  * @ifd                File descriptor of input file.
  * @file_actlst        List of (known or unknown) activities in file.
+ * @cpu_nr     Number of processors for current activity data file.
+ * @rectime    Structure where timestamp (expressed in local time or in UTC
+ *             depending on whether option -t has been used or not) can be
+ *             saved for current record.
+ * @loctime    Structure where timestamp (expressed in local time) can be
+ *             saved for current record.
  ***************************************************************************
  */
-void main_display_loop(int ifd, struct file_activity *file_actlst)
+void main_display_loop(int ifd, struct file_activity *file_actlst, __nr_t cpu_nr,
+                      struct tm *rectime, struct tm *loctime)
 {
        int i, p;
        int curr = 1, rtype;
@@ -983,7 +1120,8 @@ void main_display_loop(int ifd, struct file_activity *file_actlst)
 
                        rtype = record_hdr[0].record_type;
                        if ((rtype == R_RESTART) || (rtype == R_COMMENT)) {
-                               sadf_print_special(0, tm_start.use, tm_end.use, rtype, ifd);
+                               sadf_print_special(0, tm_start.use, tm_end.use, rtype, ifd,
+                                                  rectime, loctime);
                        }
                        else {
                                /*
@@ -992,12 +1130,12 @@ void main_display_loop(int ifd, struct file_activity *file_actlst)
                                 */
                                read_file_stat_bunch(act, 0, ifd, file_hdr.sa_nr_act,
                                                     file_actlst);
-                               sadf_get_record_timestamp_struct(0);
+                               sadf_get_record_timestamp_struct(0, rectime, loctime);
                        }
                }
                while ((rtype == R_RESTART) || (rtype == R_COMMENT) ||
-                      (tm_start.use && (datecmp(&loctime, &tm_start) < 0)) ||
-                      (tm_end.use && (datecmp(&loctime, &tm_end) >=0)));
+                      (tm_start.use && (datecmp(loctime, &tm_start) < 0)) ||
+                      (tm_end.use && (datecmp(loctime, &tm_end) >= 0)));
 
                /* Save the first stats collected. Will be used to compute the average */
                copy_structures(act, id_seq, record_hdr, 2, 0);
@@ -1019,7 +1157,8 @@ void main_display_loop(int ifd, struct file_activity *file_actlst)
                         * are printed on the same line.
                         */
                        rw_curr_act_stats(ifd, fpos, &curr, &cnt, &eosaf,
-                                         ALL_ACTIVITIES, &reset, file_actlst);
+                                         ALL_ACTIVITIES, &reset, file_actlst,
+                                         cpu_nr, rectime, loctime);
                }
                else {
                        /* For each requested activity... */
@@ -1037,7 +1176,8 @@ void main_display_loop(int ifd, struct file_activity *file_actlst)
 
                                if (!HAS_MULTIPLE_OUTPUTS(act[p]->options)) {
                                        rw_curr_act_stats(ifd, fpos, &curr, &cnt, &eosaf,
-                                                         act[p]->id, &reset, file_actlst);
+                                                         act[p]->id, &reset, file_actlst,
+                                                         cpu_nr, rectime, loctime);
                                }
                                else {
                                        unsigned int optf, msk;
@@ -1049,7 +1189,8 @@ void main_display_loop(int ifd, struct file_activity *file_actlst)
                                                        act[p]->opt_flags &= msk;
                                                        
                                                        rw_curr_act_stats(ifd, fpos, &curr, &cnt, &eosaf,
-                                                                         act[p]->id, &reset, file_actlst);
+                                                                         act[p]->id, &reset, file_actlst,
+                                                                         cpu_nr, rectime, loctime);
                                                        act[p]->opt_flags = optf;
                                                }
                                        }
@@ -1069,7 +1210,8 @@ void main_display_loop(int ifd, struct file_activity *file_actlst)
                                }
                                else if (!eosaf && (rtype == R_COMMENT)) {
                                        /* This was a COMMENT record: print it */
-                                       sadf_print_special(curr, tm_start.use, tm_end.use, R_COMMENT, ifd);
+                                       sadf_print_special(curr, tm_start.use, tm_end.use,
+                                                          R_COMMENT, ifd, rectime, loctime);
                                }
                        }
                        while (!eosaf && (rtype != R_RESTART));
@@ -1077,7 +1219,8 @@ void main_display_loop(int ifd, struct file_activity *file_actlst)
 
                /* The last record we read was a RESTART one: Print it */
                if (!eosaf && (record_hdr[curr].record_type == R_RESTART)) {
-                       sadf_print_special(curr, tm_start.use, tm_end.use, R_RESTART, ifd);
+                       sadf_print_special(curr, tm_start.use, tm_end.use,
+                                          R_RESTART, ifd, rectime, loctime);
                }
        }
        while (!eosaf);
@@ -1095,26 +1238,38 @@ void read_stats_from_file(char dfile[])
 {
        struct file_magic file_magic;
        struct file_activity *file_actlst = NULL;
-       int ifd, ignore;
+       struct tm rectime, loctime;
+       int ifd, ignore, tab = 0;
+       __nr_t cpu_nr;
 
-       /* Prepare file for reading */
-       ignore = (format == S_O_HDR_OPTION);
+       /* Prepare file for reading and read its headers */
+       ignore = ACCEPT_BAD_FILE_FORMAT(fmt[f_position]->options);
        check_file_actlst(&ifd, dfile, act, &file_magic, &file_hdr,
                          &file_actlst, id_seq, ignore);
-       
-       if (format == S_O_HDR_OPTION) {
-               /* Display data file header then exit */
-               display_file_header(dfile, &file_magic, &file_hdr);
+
+       /* Now pick up number of proc for this file */
+       cpu_nr = act[get_activity_position(act, A_CPU)]->nr;
+
+       if (DISPLAY_HDR_ONLY(flags)) {
+               if (*fmt[f_position]->f_header) {
+                       /* Display only data file header then exit */
+                       (*fmt[f_position]->f_header)(&tab, F_BEGIN + F_END, dfile, &file_magic,
+                                                    &file_hdr, cpu_nr, act, id_seq);
+               }
+               exit(0);
        }
 
        /* Perform required allocations */
        allocate_structures(act);
 
-       if (format == S_O_XML_OPTION) {
-               xml_display_loop(ifd, file_actlst);
+       if (DISPLAY_GROUPED_STATS(fmt[f_position]->options)) {
+               main_display_loop(ifd, file_actlst, cpu_nr,
+                                 &rectime, &loctime);                  /* FIXME: revoir nom */
        }
        else {
-               main_display_loop(ifd, file_actlst);
+               xml_display_loop(ifd, file_actlst,
+                                dfile, &file_magic, cpu_nr,
+                                &rectime, &loctime);                   /* FIXME: revoir nom */
        }
 
        close(ifd);
@@ -1135,6 +1290,7 @@ int main(int argc, char **argv)
        int opt = 1, sar_options = 0;
        int i;
        char dfile[MAX_FILE_LEN];
+       struct tm rectime;
 
        /* Get HZ */
        get_HZ();
@@ -1238,17 +1394,10 @@ int main(int argc, char **argv)
                                                break;
                                                        
                                        case 'd':
-                                               if (format && (format != S_O_DB_OPTION)) {
+                                               if (format) {
                                                        usage(argv[0]);
                                                }
-                                               format = S_O_DB_OPTION;
-                                               break;
-
-                                       case 'D':
-                                               if (format && (format != S_O_DBD_OPTION)) {
-                                                       usage(argv[0]);
-                                               }
-                                               format = S_O_DBD_OPTION;
+                                               format = F_DB_OUTPUT;
                                                break;
 
                                        case 'h':
@@ -1256,28 +1405,29 @@ int main(int argc, char **argv)
                                                break;
 
                                        case 'H':
-                                               if (format && (format != S_O_HDR_OPTION)) {
-                                                       usage(argv[0]);
-                                               }
-                                               format = S_O_HDR_OPTION;
+                                               flags |= S_F_HDR_ONLY;
                                                break;
 
                                        case 'p':
-                                               if (format && (format != S_O_PPC_OPTION)) {
+                                               if (format) {
                                                        usage(argv[0]);
                                                }
-                                               format = S_O_PPC_OPTION;
+                                               format = F_PPC_OUTPUT;
                                                break;
 
                                        case 't':
                                                flags |= S_F_TRUE_TIME;
                                                break;
+                                       
+                                       case 'T':
+                                               flags |= S_F_SEC_EPOCH;
+                                               break;
 
                                        case 'x':
-                                               if (format && (format != S_O_XML_OPTION)) {
+                                               if (format) {
                                                        usage(argv[0]);
                                                }
-                                               format = S_O_XML_OPTION;
+                                               format = F_XML_OUTPUT;
                                                break;
 
                                        case 'V':
@@ -1367,21 +1517,11 @@ int main(int argc, char **argv)
                count = -1;
        }
 
-       /* Default is CPU activity and PPC display */
+       /* Default is CPU activity */
        select_default_activity(act);
-       
-       if (!format) {
-               if (DISPLAY_HORIZONTALLY(flags)) {
-                       format = S_O_DB_OPTION;
-               }
-               else {
-                       format = S_O_PPC_OPTION;
-               }
-       }
-       if (DISPLAY_HORIZONTALLY(flags) && (format != S_O_DB_OPTION)) {
-               /* Remove option -h if not used with option -d */
-               flags &= ~S_F_HORIZONTALLY;
-       }
+
+       /* Check options consistency with selected output format. Default is PPC display */
+       check_format_options();
 
        if (interval < 0) {
                interval = 1;
diff --git a/sadf.h b/sadf.h
index bbba62e951ca2a79cba11eed6581e08a5424e5e8..87d4dee222921e1119f9d23bfd659af73c662f8a 100644 (file)
--- a/sadf.h
+++ b/sadf.h
 #ifndef _SADF_H
 #define _SADF_H
 
-/* Output formats (O_= Output)  */
-#define S_O_HDR_OPTION         1
-#define S_O_PPC_OPTION         2
-#define S_O_DB_OPTION          3
-#define S_O_XML_OPTION         4
-#define S_O_DBD_OPTION         5
+#include "sa.h"
+
+/* Possible actions for functions used to display reports */
+#define F_BEGIN        0x01
+#define F_MAIN 0x02
+#define F_END  0x04
+
+/*
+ ***************************************************************************
+ * Output format identification values.
+ ***************************************************************************
+ */
+
+/* Number of output formats */
+#define NR_FMT 4
+
+/* Output formats */
+#define F_DB_OUTPUT    1
+#define F_HEADER_OUTPUT        2
+#define F_PPC_OUTPUT   3
+#define F_XML_OUTPUT   4
+
+/*
+ ***************************************************************************
+ * Generic description of an output format.
+ ***************************************************************************
+ */
+
+/* Format options */
+#define FO_NULL                        0x00
+
+/*
+ * Indicate that all statistics data for one activity should be displayed before
+ * displaying stats for next activity. This is what sar does in its report.
+ * Example: If stats for activities A and B at time t and t' have been collected,
+ * setting AO_GROUPED_STATS for a format will result in the following output:
+ * stats for activity A at t
+ * stats for activity A at t'
+ * stats for activity B at t
+ * stats for activity B at t'
+ * Without this option, output would be:
+ * stats for activity A at t
+ * stats for activity B at t
+ * stats for activity A at t'
+ * stats for activity B at t'
+ */
+#define FO_GROUPED_STATS       0x01
+
+/*
+ * Indicate that output should stop after the header is displayed.
+ */
+#define FO_HEADER_ONLY         0x02
+
+/*
+ * Indicate that a true sysstat activity file but with a bad
+ * format should not yield an error message.
+ */
+#define FO_BAD_FILE_FORMAT     0x04
+
+/*
+ * Indicate that timestamp can be displayed in local time instead of UTC
+ * if option -t has been used.
+ */
+#define FO_TRUE_TIME           0x08
+
+/*
+ * Indicate that all activities will be displayed horizontally
+ * if option -h is used.
+ */
+#define FO_HORIZONTALLY                0x10
+
+/*
+ * Indicate that the timestamp can be displayed in seconds since the epoch
+ * if option -T has been used.
+ */
+#define FO_SEC_EPOCH           0x20
+
+/*
+ * Indicate that the list of fields should be displayed before the first
+ * line of statistics.
+ */
+#define FO_FIELD_LIST          0x40
+
+#define DISPLAY_GROUPED_STATS(m)       (((m) & FO_GROUPED_STATS)       == FO_GROUPED_STATS)
+#define ACCEPT_HEADER_ONLY(m)          (((m) & FO_HEADER_ONLY)         == FO_HEADER_ONLY)
+#define ACCEPT_BAD_FILE_FORMAT(m)      (((m) & FO_BAD_FILE_FORMAT)     == FO_BAD_FILE_FORMAT)
+#define ACCEPT_TRUE_TIME(m)            (((m) & FO_TRUE_TIME)           == FO_TRUE_TIME)
+#define ACCEPT_HORIZONTALLY(m)         (((m) & FO_HORIZONTALLY)        == FO_HORIZONTALLY)
+#define ACCEPT_SEC_EPOCH(m)            (((m) & FO_SEC_EPOCH)           == FO_SEC_EPOCH)
+#define DISPLAY_FIELD_LIST(m)          (((m) & FO_FIELD_LIST)          == FO_FIELD_LIST)
+
+/* Type for all functions used by sadf to display stats in various formats */
+#define __printf_funct_t void
+
+/*
+ * Structure used to define a report.
+ * A XML-like report has the following format:
+ *       __
+ *      |
+ *      | Header block
+ *      |  __
+ *      | |
+ *      | | Statistics block
+ *      | |  __
+ *      | | |
+ *      | | | Timestamp block
+ *      | | |  __
+ *      | | | |
+ *      | | | | Activity #1
+ *      | | | |__
+ *      | | | |
+ *      | | | | ...
+ *      | | | |__
+ *      | | | |
+ *      | | | | Activity #n
+ *      | | | |__
+ *      | | |__
+ *      | |__
+ *      | |
+ *      | | Restart messages block
+ *      | |__
+ *      | |
+ *      | | Comments block
+ *      | |__
+ *      |__
+ */
+struct report_format {
+       /*
+        * This variable contains the identification value (F_...) for this report format.
+        */
+       unsigned int id;
+       /*
+        * Format options (FO_...).
+        */
+       unsigned int options;
+       /*
+        * This function displays the report header
+        * (data displayed once at the beginning of the report).
+        */
+       __printf_funct_t (*f_header) (int *, int, char *, struct file_magic *, struct file_header *,
+                                     __nr_t, struct activity * [], unsigned int []);
+       /*
+        * This function defines the statistics part of the report.
+        * Used only with textual (XML-like) reports.
+        */
+       __printf_funct_t (*f_statistics) (int *, int);
+       /*
+        * This function defines the timestamp part of the report.
+        * Used only with textual (XML-like) reports.
+        */
+       __printf_funct_t (*f_timestamp) (int *, int, char *, char *, int, unsigned long long);
+       /*
+        * This function displays the restart messages.
+        */
+       __printf_funct_t (*f_restart) (int *, int, char *, char *, int, struct file_header *);
+       /*
+        * This function displays the comments.
+        */
+       __printf_funct_t (*f_comment) (int *, int, char *, char *, int, char *, struct file_header *);
+};
 
 /* DTD version for XML output */
 #define XML_DTD_VERSION        "2.11"
 
+/*
+ ***************************************************************************
+ * Various function prototypes
+ ***************************************************************************
+ */
+
+extern void
+       xprintf(int, const char *, ...);
+
+/*
+ * Prototypes used to display restart messages
+ */
+__printf_funct_t
+       print_db_restart(int *, int, char *, char *, int, struct file_header *);
+__printf_funct_t
+       print_ppc_restart(int *, int, char *, char *, int, struct file_header *);
+__printf_funct_t
+       print_xml_restart(int *, int, char *, char *, int, struct file_header *);
+
+/*
+ * Prototypes used to display comments
+ */
+__printf_funct_t
+       print_db_comment(int *, int, char *, char *, int, char *, struct file_header *);
+__printf_funct_t
+       print_ppc_comment(int *, int, char *, char *, int, char *, struct file_header *);
+__printf_funct_t
+       print_xml_comment(int *, int, char *, char *, int, char *, struct file_header *);
+
+/*
+ * Prototypes used to display the statistics part of the report
+ */
+__printf_funct_t
+       print_xml_statistics(int *, int);
+
+/*
+ * Prototypes used to display the timestamp part of the report
+ */
+__printf_funct_t
+       print_xml_timestamp(int *, int, char *, char *, int, unsigned long long);
+
+/*
+ * Prototypes used to display the report header
+ */
+__printf_funct_t
+       print_xml_header(int *, int, char *, struct file_magic *, struct file_header *,
+                        __nr_t, struct activity * [], unsigned int []);
+__printf_funct_t
+       print_hdr_header(int *, int, char *, struct file_magic *, struct file_header *,
+                        __nr_t, struct activity * [], unsigned int []);
+
 #endif  /* _SADF_H */
diff --git a/sadf_misc.c b/sadf_misc.c
new file mode 100644 (file)
index 0000000..708b2db
--- /dev/null
@@ -0,0 +1,414 @@
+/*
+ * sadf_misc.c: Funtions used by sadf to display special records
+ * (C) 2011 by Sebastien GODARD (sysstat <at> orange.fr)
+ *
+ ***************************************************************************
+ * 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 2 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 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, write to the Free Software Foundation, Inc., *
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                   *
+ ***************************************************************************
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "sadf.h"
+#include "sa.h"
+
+#ifdef USE_NLS
+#include <locale.h>
+#include <libintl.h>
+#define _(string) gettext(string)
+#else
+#define _(string) (string)
+#endif
+
+extern unsigned int flags;
+
+/*
+ ***************************************************************************
+ * Display restart messages (database and ppc formats).
+ *
+ * IN:
+ * @cur_date   Date string of current restart message.
+ * @cur_time   Time string of current restart message.
+ * @utc                True if @cur_time is expressed in UTC.
+ * @sep                Character used as separator.
+ * @file_hdr   System activity file standard header.
+ ***************************************************************************
+ */
+void print_dbppc_restart(char *cur_date, char *cur_time, int utc, char sep,
+                        struct file_header *file_hdr)
+{
+       printf("%s%c-1%c", file_hdr->sa_nodename, sep, sep);
+       if (strlen(cur_date)) {
+               printf("%s ", cur_date);
+       }
+       printf("%s", cur_time);
+       if (strlen(cur_date) && utc) {
+               printf(" UTC");
+       }
+       printf("%cLINUX-RESTART\n", sep);
+}
+
+/*
+ ***************************************************************************
+ * Display restart messages (ppc format).
+ *
+ * IN:
+ * @tab                Number of tabulations (unused here).
+ * @action     Action expected from current function.
+ * @cur_date   Date string of current restart message.
+ * @cur_time   Time string of current restart message.
+ * @utc                True if @cur_time is expressed in UTC.
+ * @file_hdr   System activity file standard header.
+ ***************************************************************************
+ */
+__printf_funct_t print_db_restart(int *tab, int action, char *cur_date,
+                                 char *cur_time, int utc, struct file_header *file_hdr)
+{
+       /* Actions F_BEGIN and F_END ignored */
+       if (action == F_MAIN) {
+               print_dbppc_restart(cur_date, cur_time, utc, ';', file_hdr);
+       }
+}
+
+/*
+ ***************************************************************************
+ * Display restart messages (database format).
+ *
+ * IN:
+ * @tab                Number of tabulations (unused here).
+ * @action     Action expected from current function.
+ * @cur_date   Date string of current restart message.
+ * @cur_time   Time string of current restart message.
+ * @utc                True if @cur_time is expressed in UTC.
+ * @file_hdr   System activity file standard header.
+ ***************************************************************************
+ */
+__printf_funct_t print_ppc_restart(int *tab, int action, char *cur_date,
+                                  char *cur_time, int utc, struct file_header *file_hdr)
+{
+       /* Actions F_BEGIN and F_END ignored */
+       if (action == F_MAIN) {
+               print_dbppc_restart(cur_date, cur_time, utc, '\t', file_hdr);
+       }
+}
+
+/*
+ ***************************************************************************
+ * Display restart messages (XML format).
+ *
+ * IN:
+ * @tab                Number of tabulations.
+ * @action     Action expected from current function.
+ * @cur_date   Date string of current restart message.
+ * @cur_time   Time string of current restart message.
+ * @utc                True if @cur_time is expressed in UTC.
+ * @file_hdr   System activity file standard header (unused here).
+ *
+ * OUT:
+ * @tab                Number of tabulations.
+ ***************************************************************************
+ */
+__printf_funct_t print_xml_restart(int *tab, int action, char *cur_date,
+                                  char *cur_time, int utc, struct file_header *file_hdr)
+{
+       if (action & F_BEGIN) {
+               xprintf((*tab)++, "<restarts>");
+       }
+       if (action & F_MAIN) {
+               xprintf(*tab, "<boot date=\"%s\" time=\"%s\" utc=\"%d\"/>",
+                       cur_date, cur_time, utc ? 1 : 0);               /* FIXME: Nouvelle balise a prevoir dans DTD/XSD */
+       }
+       if (action & F_END) {
+               xprintf(--(*tab), "</restarts>");
+       }
+}
+
+/*
+ ***************************************************************************
+ * Display comments (database and ppc formats).
+ *
+ * IN:
+ * @cur_date   Date string of current restart message.
+ * @cur_time   Time string of current restart message.
+ * @utc                True if @cur_time is expressed in UTC.
+ * @comment    Comment to display.
+ * @sep                Character used as separator.
+ * @file_hdr   System activity file standard header.
+ ***************************************************************************
+ */
+void print_dbppc_comment(char *cur_date, char *cur_time, int utc,
+                        char *comment, char sep, struct file_header *file_hdr)
+{
+       printf("%s%c-1%c", file_hdr->sa_nodename, sep, sep);
+       if (strlen(cur_date)) {
+               printf("%s ", cur_date);
+       }
+       printf("%s", cur_time);
+       if (strlen(cur_date) && utc) {
+               printf(" UTC");
+       }
+       printf("%cCOM %s\n", sep, comment);
+}
+
+/*
+ ***************************************************************************
+ * Display comments (database format).
+ *
+ * IN:
+ * @tab                Number of tabulations (unused here).
+ * @action     Action expected from current function.
+ * @cur_date   Date string of current restart message.
+ * @cur_time   Time string of current restart message.
+ * @utc                True if @cur_time is expressed in UTC.
+ * @comment    Comment to display.
+ * @file_hdr   System activity file standard header.
+ ***************************************************************************
+ */
+__printf_funct_t print_db_comment(int *tab, int action, char *cur_date,
+                                 char *cur_time, int utc, char *comment,
+                                 struct file_header *file_hdr)
+{
+       /* Actions F_BEGIN and F_END ignored */
+       if (action & F_MAIN) {
+               print_dbppc_comment(cur_date, cur_time, utc, comment,
+                                   ';', file_hdr);
+       }
+}
+
+/*
+ ***************************************************************************
+ * Display comments (ppc format).
+ *
+ * IN:
+ * @tab                Number of tabulations (unused here).
+ * @action     Action expected from current function.
+ * @cur_date   Date string of current restart message.
+ * @cur_time   Time string of current restart message.
+ * @utc                True if @cur_time is expressed in UTC.
+ * @comment    Comment to display.
+ * @file_hdr   System activity file standard header.
+ ***************************************************************************
+ */
+__printf_funct_t print_ppc_comment(int *tab, int action, char *cur_date,
+                                  char *cur_time, int utc, char *comment,
+                                  struct file_header *file_hdr)
+{
+       /* Actions F_BEGIN and F_END ignored */
+       if (action & F_MAIN) {
+               print_dbppc_comment(cur_date, cur_time, utc, comment,
+                                   '\t', file_hdr);
+       }
+}
+
+/*
+ ***************************************************************************
+ * Display comments (XML format).
+ *
+ * IN:
+ * @tab                Number of tabulations.
+ * @action     Action expected from current function.
+ * @cur_date   Date string of current comment.
+ * @cur_time   Time string of current comment.
+ * @utc                True if @cur_time is expressed in UTC.
+ * @comment    Comment to display.
+ * @file_hdr   System activity file standard header (unused here).
+ *
+ * OUT:
+ * @tab                Number of tabulations.
+ ***************************************************************************
+ */
+__printf_funct_t print_xml_comment(int *tab, int action, char *cur_date,
+                                  char *cur_time, int utc, char *comment,
+                                  struct file_header *file_hdr)
+{
+       if (action & F_BEGIN) {
+               xprintf((*tab)++, "<comments>");
+       }
+       if (action & F_MAIN) {
+               xprintf(*tab, "<comment date=\"%s\" time=\"%s\" utc=\"%d\" com=\"%s\"/>",       /* FIXME: modification du DTD/XSD */
+                       cur_date, cur_time, utc ? 1 : 0, comment);
+       }
+       if (action & F_END) {
+               xprintf(--(*tab), "</comments>");
+       }
+}
+
+/*
+ ***************************************************************************
+ * Display the "statistics" part of the report (XML format).
+ *
+ * IN:
+ * @tab                Number of tabulations.
+ * @action     Action expected from current function.
+ *
+ * OUT:
+ * @tab                Number of tabulations.
+ ***************************************************************************
+ */
+__printf_funct_t print_xml_statistics(int *tab, int action)
+{
+       if (action & F_BEGIN) {
+               xprintf((*tab)++, "<statistics>");
+       }
+       if (action & F_END) {
+               xprintf(--(*tab), "</statistics>");
+       }
+}
+
+/*
+ ***************************************************************************
+ * Display the "timestamp" part of the report (XML format).
+ *
+ * IN:
+ * @tab                Number of tabulations.
+ * @action     Action expected from current function.
+ * @cur_date   Date string of current comment.
+ * @cur_time   Time string of current comment.
+ * @utc                True if @cur_time is expressed in UTC.
+ * @itv                Interval of time with preceding record.
+ *
+ * OUT:
+ * @tab                Number of tabulations.
+ ***************************************************************************
+ */
+__printf_funct_t print_xml_timestamp(int *tab, int action, char *cur_date,
+                                    char *cur_time, int utc, unsigned long long itv)
+{
+       if (action & F_BEGIN) {
+               xprintf(*tab, "<timestamp date=\"%s\" time=\"%s\" utc=\"%d\" interval=\"%llu\"/>",      /* FIXME: modification du DTD/XSD */
+                       cur_date, cur_time, utc ? 1 : 0, itv);
+       }
+       if (action & F_END) {
+               xprintf(--(*tab), "</timestamp>");
+       }
+}
+
+/*
+ ***************************************************************************
+ * Display the header of the report (XML format).
+ *
+ * IN:
+ * @tab                Number of tabulations.
+ * @action     Action expected from current function.
+ * @dfile      Name of system activity data file.
+ * @file_magic System activity file magic header.
+ * @file_hdr   System activity file standard header.
+ * @cpu_nr     Number of processors for current daily data file.
+ * @act                Array of activities (unused here).
+ * @id_seq     Activity sequence (unused here).
+ *
+ * OUT:
+ * @tab                Number of tabulations.
+ ***************************************************************************
+ */
+__printf_funct_t print_xml_header(int *tab, int action, char *dfile,
+                                 struct file_magic *file_magic,
+                                 struct file_header *file_hdr, __nr_t cpu_nr,
+                                 struct activity *act[], unsigned int id_seq[])
+{
+       struct tm rectime;
+       char cur_time[32];
+
+       if (action & F_BEGIN) {
+               printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+               printf("<!DOCTYPE Configure PUBLIC \"DTD v%s sysstat //EN\"\n",
+                      XML_DTD_VERSION);
+               printf("\"http://pagesperso-orange.fr/sebastien.godard/sysstat.dtd\">\n");
+               
+               xprintf(*tab, "<sysstat>");
+
+               xprintf(++(*tab), "<sysdata-version>%s</sysdata-version>",
+                       XML_DTD_VERSION);
+
+               xprintf(*tab, "<host nodename=\"%s\">", file_hdr->sa_nodename);
+               xprintf(++(*tab), "<sysname>%s</sysname>", file_hdr->sa_sysname);
+               xprintf(*tab, "<release>%s</release>", file_hdr->sa_release);
+
+               xprintf(*tab, "<machine>%s</machine>", file_hdr->sa_machine);
+               xprintf(*tab, "<number-of-cpus>%d</number-of-cpus>",
+                       cpu_nr > 1 ? cpu_nr - 1 : 1);
+
+               /* Fill file timestmap structure (rectime) */
+               get_file_timestamp_struct(flags, &rectime, file_hdr);
+               strftime(cur_time, 32, "%Y-%m-%d", &rectime);
+               xprintf(*tab, "<file-date>%s</file-date>", cur_time);
+       }
+       if (action & F_END) {
+               xprintf(--(*tab), "</host>");
+               xprintf(--(*tab), "</sysstat>");
+       }
+}
+
+/*
+ ***************************************************************************
+ * Display data file header.
+ *
+ * IN:
+ * @tab                Number of tabulations (unused here).
+ * @action     Action expected from current function.
+ * @dfile      Name of system activity data file.
+ * @file_magic System activity file magic header.
+ * @file_hdr   System activity file standard header.
+ * @cpu_nr     Number of processors for current daily data file.
+ * @act                Array of activities.
+ * @id_seq     Activity sequence.
+ ***************************************************************************
+ */
+__printf_funct_t print_hdr_header(int *tab, int action, char *dfile,
+                                 struct file_magic *file_magic,
+                                 struct file_header *file_hdr, __nr_t cpu_nr,
+                                 struct activity *act[], unsigned int id_seq[])
+{
+       int i, p;
+
+       /* Actions F_BEGIN and F_END ignored */
+       if (action & F_BEGIN) {
+               printf(_("System activity data file: %s (%#x)\n"),
+                      dfile, file_magic->format_magic);
+
+               display_sa_file_version(file_magic);
+
+               if (file_magic->format_magic != FORMAT_MAGIC) {
+                       return;
+               }
+
+               printf(_("Host: "));
+               print_gal_header(localtime((const time_t *) &(file_hdr->sa_ust_time)),
+                                file_hdr->sa_sysname, file_hdr->sa_release,
+                                file_hdr->sa_nodename, file_hdr->sa_machine,
+                                cpu_nr > 1 ? cpu_nr - 1 : 1);
+
+               printf(_("Size of a long int: %d\n"), file_hdr->sa_sizeof_long);
+
+               printf(_("List of activities:\n"));
+
+               for (i = 0; i < NR_ACT; i++) {
+                       if (!id_seq[i])
+                               continue;
+                       if ((p = get_activity_position(act, id_seq[i])) < 0) {
+                               PANIC(id_seq[i]);
+                       }
+                       printf("%02d: %s\t(x%d)", act[p]->id, act[p]->name, act[p]->nr);
+                       if (act[p]->f_count2 || (act[p]->nr2 > 1)) {
+                               printf("\t(x%d)", act[p]->nr2);
+                       }
+                       if (act[p]->magic == ACTIVITY_MAGIC_UNKNOWN) {
+                               printf(_("\t[Unknown activity format]"));
+                       }
+                       printf("\n");
+               }
+       }
+}
index 4d109a01671b96e36fe14f5a8c548a112ed18260..c8e99f7cbb3924783f33f560039afb9831c4cbc1 100644 (file)
@@ -24,6 +24,7 @@
 #include <stdarg.h>
 
 #include "sa.h"
+#include "sadf.h"
 #include "ioconf.h"
 #include "xml_stats.h"
 
 extern unsigned int flags;
 extern unsigned int dm_major;
 
-/*
- ***************************************************************************
- * Print tabulations
- *
- * IN:
- * @nr_tab      Number of tabs to print.
- ***************************************************************************
- */
-void prtab(int nr_tab)
-{
-       int i;
-
-       for (i = 0; i < nr_tab; i++) {
-               printf("\t");
-       }
-}
-
-/*
- ***************************************************************************
- * printf() function modified for XML display
- *
- * IN:
- * @nr_tab      Number of tabs to print.
- * @fmt         printf() format.
- ***************************************************************************
- */
-void xprintf(int nr_tab, const char *fmt, ...)
-{
-       static char buf[1024];
-       va_list args;
-
-       va_start(args, fmt);
-       vsnprintf(buf, sizeof(buf), fmt, args);
-       va_end(args);
-
-       prtab(nr_tab);
-       printf("%s\n", buf);
-}
-
 /*
  ***************************************************************************
  * Open or close <network> markup.
index bc1b38c345d78ddbfb34b474c459c6e53e8ad03c..c75a812038681f70eea7b5f06fbb391beacc86ac 100644 (file)
@@ -15,8 +15,6 @@
  */
 
 /* Functions used to display statistics in XML */
-extern void xprintf
-       (int, const char *, ...);
 extern __print_funct_t xml_print_cpu_stats
        (struct activity *, int, int, unsigned long long);
 extern __print_funct_t xml_print_pcsw_stats