Message ID | 1338403238-14029-5-git-send-email-colin.king@canonical.com |
---|---|
State | Accepted |
Headers | show |
On 05/31/2012 02:40 AM, Colin King wrote: > From: Colin Ian King<colin.king@canonical.com> > > Signed-off-by: Colin Ian King<colin.king@canonical.com> > --- > src/lib/include/fwts_log.h | 8 +- > src/lib/src/Makefile.am | 1 + > src/lib/src/fwts_framework.c | 12 +- > src/lib/src/fwts_log.c | 3 + > src/lib/src/fwts_log_html.c | 297 ++++++++++++++++++++++++++++++++++++++++++ > 5 files changed, 313 insertions(+), 8 deletions(-) > create mode 100644 src/lib/src/fwts_log_html.c > > diff --git a/src/lib/include/fwts_log.h b/src/lib/include/fwts_log.h > index 4e0f33a..a659baa 100644 > --- a/src/lib/include/fwts_log.h > +++ b/src/lib/include/fwts_log.h > @@ -63,6 +63,7 @@ typedef enum { > LOG_TYPE_PLAINTEXT = 0x00000001, > LOG_TYPE_JSON = 0x00000002, > LOG_TYPE_XML = 0x00000003, > + LOG_TYPE_HTML = 0x00000004, > } fwts_log_type; > > typedef struct log_t { > @@ -84,9 +85,10 @@ typedef struct fwts_log_ops_t { > void (*close)(fwts_log *); > } fwts_log_ops; > > -fwts_log_ops fwts_log_plaintext_ops; > -fwts_log_ops fwts_log_json_ops; > -fwts_log_ops fwts_log_xml_ops; > +extern fwts_log_ops fwts_log_plaintext_ops; > +extern fwts_log_ops fwts_log_json_ops; > +extern fwts_log_ops fwts_log_xml_ops; > +extern fwts_log_ops fwts_log_html_ops; > > extern fwts_log_field fwts_log_filter; > extern const char *fwts_log_format; > diff --git a/src/lib/src/Makefile.am b/src/lib/src/Makefile.am > index acea9cb..f846621 100644 > --- a/src/lib/src/Makefile.am > +++ b/src/lib/src/Makefile.am > @@ -40,6 +40,7 @@ libfwts_la_SOURCES = \ > fwts_log_plaintext.c \ > fwts_log_json.c \ > fwts_log_xml.c \ > + fwts_log_html.c \ > fwts_memorymap.c \ > fwts_microcode.c \ > fwts_mmap.c \ > diff --git a/src/lib/src/fwts_framework.c b/src/lib/src/fwts_framework.c > index 3f54fdb..721f4de 100644 > --- a/src/lib/src/fwts_framework.c > +++ b/src/lib/src/fwts_framework.c > @@ -76,7 +76,7 @@ static fwts_option fwts_framework_options[] = { > { "json-data-path", "j:", 1, "Specify path to fwts json data files - default is /usr/share/fwts." }, > { "lp-tags-log", "", 0, "Output LaunchPad bug tags in results log." }, > { "disassemble-aml", "", 0, "Disassemble AML from DSDT and SSDT tables." }, > - { "log-type", "", 1, "Specify log type (plaintext, json or xml)." }, > + { "log-type", "", 1, "Specify log type (plaintext, json, html or xml)." }, > { NULL, NULL, 0, NULL } > }; > > @@ -672,7 +672,7 @@ void fwts_framework_log(fwts_framework *fw, > case LOG_ADVICE: > fwts_log_nl(fw); > snprintf(prefix, sizeof(prefix), "%s: ", str); > - fwts_log_printf(fw->results, LOG_ADVICE, level, str, label, prefix, "%s", buffer); > + fwts_log_printf(fw->results, field, level, str, label, prefix, "%s", buffer); > fwts_log_nl(fw); > break; > case LOG_FAILED: > @@ -680,7 +680,7 @@ void fwts_framework_log(fwts_framework *fw, > fwts_summary_add(fw, fw->current_major_test->name, level, buffer); > snprintf(prefix, sizeof(prefix), "%s [%s] %s: Test %d, ", > str, fwts_log_level_to_str(level), label, fw->current_minor_test_num); > - fwts_log_printf(fw->results, LOG_RESULT, level, str, label, prefix, "%s", buffer); > + fwts_log_printf(fw->results, field, level, str, label, prefix, "%s", buffer); > break; > case LOG_PASSED: > case LOG_WARNING: > @@ -688,7 +688,7 @@ void fwts_framework_log(fwts_framework *fw, > case LOG_ABORTED: > snprintf(prefix, sizeof(prefix), "%s: Test %d, ", > str, fw->current_minor_test_num); > - fwts_log_printf(fw->results, LOG_RESULT, level, str, label, prefix, "%s", buffer); > + fwts_log_printf(fw->results, field, level, str, label, prefix, "%s", buffer); > break; > case LOG_INFOONLY: > break; /* no-op */ > @@ -949,8 +949,10 @@ int fwts_framework_options_handler(fwts_framework *fw, int argc, char * const ar > fw->log_type = LOG_TYPE_JSON; > else if (!strcmp(optarg, "xml")) > fw->log_type = LOG_TYPE_XML; > + else if (!strcmp(optarg, "html")) > + fw->log_type = LOG_TYPE_HTML; > else { > - fprintf(stderr, "--log-type can be either plaintext or json.\n"); > + fprintf(stderr, "--log-type can be either plaintext, xml, html or json.\n"); > return FWTS_ERROR; > } > break; > diff --git a/src/lib/src/fwts_log.c b/src/lib/src/fwts_log.c > index c764d55..fea7c41 100644 > --- a/src/lib/src/fwts_log.c > +++ b/src/lib/src/fwts_log.c > @@ -432,6 +432,9 @@ fwts_log *fwts_log_open(const char *owner, const char *name, const char *mode, f > case LOG_TYPE_XML: > newlog->ops =&fwts_log_xml_ops; > break; > + case LOG_TYPE_HTML: > + newlog->ops =&fwts_log_html_ops; > + break; > case LOG_TYPE_NONE: > default: > newlog->ops =&fwts_log_plaintext_ops; > diff --git a/src/lib/src/fwts_log_html.c b/src/lib/src/fwts_log_html.c > new file mode 100644 > index 0000000..25f81ef > --- /dev/null > +++ b/src/lib/src/fwts_log_html.c > @@ -0,0 +1,297 @@ > +/* > + * Copyright (C) 2010-2012 Canonical > + * > + * 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 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, write to the Free Software > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. > + * > + */ > + > +#include<stdlib.h> > +#include<stdio.h> > +#include<stdarg.h> > +#include<string.h> > +#include<unistd.h> > +#include<sys/ioctl.h> > +#include<time.h> > + > +#include "fwts.h" > + > +#define MAX_HTML_STACK (64) > +#define HTML_INDENT (2) > + > +typedef struct { > + const char *name; > +} fwts_log_html_stack_t; > + > +static fwts_log_html_stack_t html_stack[MAX_HTML_STACK]; > +static int html_stack_index = 0; > + > +static void fwts_log_html(fwts_log *log, const char *fmt, ...) > +{ > + va_list args; > + > + va_start(args, fmt); > + > + fprintf(log->fp, "%*s", html_stack_index * HTML_INDENT, ""); > + vfprintf(log->fp, fmt, args); > + > + va_end(args); > +} > + > + > +/* > + * fwts_log_vprintf_html() > + * vprintf to a log > + */ > +static int fwts_log_vprintf_html(fwts_log *log, > + const fwts_log_field field, > + const fwts_log_level level, > + const char *status, > + const char *label, > + const char *prefix, > + const char *fmt, > + va_list args) > +{ > + struct tm tm; > + time_t now; > + char *str; > + char *style; > + char *code_start; > + char *code_end; > + > + if (!((field& LOG_FIELD_MASK)& fwts_log_filter)) > + return 0; > + > + if (field& (LOG_NEWLINE | LOG_SEPARATOR | LOG_DEBUG)) > + return 0; > + > + time(&now); > + localtime_r(&now,&tm); > + > + fwts_log_html(log, "<TR>\n"); > + > + if ((field& LOG_FIELD_MASK) != LOG_HEADING) { > + fwts_log_html(log, "<TD>%2.2d/%2.2d/%-2.2d</TD>\n", > + tm.tm_mday, tm.tm_mon + 1, (tm.tm_year+1900) % 100); > + fwts_log_html(log, "<TD>%2.2d:%2.2d:%2.2d</TD>\n", > + tm.tm_hour, tm.tm_min, tm.tm_sec); > + } > + > + if (field& LOG_VERBATUM) { > + code_start = "<PRE class=style_code>"; > + code_end = "</PRE>"; > + } else { > + code_start = ""; > + code_end = ""; > + } > + > + switch (field& LOG_FIELD_MASK) { > + case LOG_ERROR: > + fwts_log_html(log, "<TD class=style_error>Error</TD><TD COLSPAN=3>"); > + vfprintf(log->fp, fmt, args); > + fprintf(log->fp, "</TD>\n"); > + break; > + case LOG_WARNING: > + fwts_log_html(log, "<TD class=style_error>Warning</TD><TD COLSPAN=3 class=style_advice_info>%s", code_start); > + vfprintf(log->fp, fmt, args); > + fprintf(log->fp, "%s</TD>\n", code_end); > + break; > + case LOG_HEADING: > + fwts_log_html(log, "<TD COLSPAN=4 class=style_heading>%s", code_start); > + vfprintf(log->fp, fmt, args); > + fprintf(log->fp, "%s</TD>\n", code_end); > + break; > + case LOG_INFO: > + fwts_log_html(log, "<TD></TD><TD COLSPAN=3 class=style_infos>%s", code_start); > + vfprintf(log->fp, fmt, args); > + fprintf(log->fp, "%s</TD>\n", code_end); > + break; > + case LOG_PASSED: > + fwts_log_html(log, "<TD class=style_passed>PASSED</TD><TD>"); > + vfprintf(log->fp, fmt, args); > + fprintf(log->fp, "</TD>\n"); > + break; > + case LOG_FAILED: > + switch (level) { > + case LOG_LEVEL_CRITICAL: > + style = " class=style_critical"; > + break; > + case LOG_LEVEL_HIGH: > + style = " class=style_high"; > + break; > + case LOG_LEVEL_MEDIUM: > + style = " class=style_medium"; > + break; > + case LOG_LEVEL_LOW: > + style = " class=style_low"; > + break; > + case LOG_LEVEL_INFO: > + case LOG_LEVEL_NONE: > + default: > + style = ""; > + break; > + } > + str = fwts_log_level_to_str(level); > + > + fwts_log_html(log, "<TD%s>%s [%s]</TD>\n", style, *status ? status : "", str); > + > + fwts_log_html(log, "<TD>"); > + vfprintf(log->fp, fmt, args); > + fprintf(log->fp, "</TD>\n"); > + break; > + > + case LOG_SKIPPED: > + fwts_log_html(log, "<TD class=style_skipped>Skipped</TD><TD>%s", code_start); > + vfprintf(log->fp, fmt, args); > + fprintf(log->fp, "%s</TD>\n", code_end); > + break; > + > + case LOG_SUMMARY: > + fwts_log_html(log, "<TD></TD><TD COLSPAN=3 class=style_summary>%s", code_start); > + vfprintf(log->fp, fmt, args); > + fprintf(log->fp, "%s</TD>\n", code_end); > + break; > + > + case LOG_ADVICE: > + fwts_log_html(log, "<TD class=style_advice>Advice</TD><TD COLSPAN=3 class=style_advice_info>%s", code_start); > + vfprintf(log->fp, fmt, args); > + fprintf(log->fp, "%s</TD>\n", code_end); > + break; > + > + default: > + break; > + } > + > + fwts_log_html(log, "</TR>\n"); > + fflush(log->fp); > + > + log->line_number++; > + > + return 0; > +} > + > +/* > + * fwts_log_underline_html() > + * write an underline across log, using character ch as the underline > + */ > +static void fwts_log_underline_html(fwts_log *log, const int ch) > +{ > + /* No-op for html */ > +} > + > +/* > + * fwts_log_newline() > + * write newline to log > + */ > +static void fwts_log_newline_html(fwts_log *log) > +{ > + /* No-op for html */ > +} > + > +static void fwts_log_section_begin_html(fwts_log *log, const char *name) > +{ > + html_stack[html_stack_index].name = name; > + > + if (!strcmp(name, "summary")) { > + fwts_log_html(log, "<TR><TD class=style_heading COLSPAN=4>Summary</TD></TR>\n"); > + } else if (!strcmp(name, "heading")) { > + fwts_log_html(log, "<TR><TD class=style_heading COLSPAN=4>Firmware Test Suite</TD></TR>\n"); > + } else if (!strcmp(name, "subtest_info")) { > + fwts_log_html(log, "<TR><TD class=style_subtest COLSPAN=4></TD></TR>\n"); > + } else if (!strcmp(name, "failure")) { > + fwts_log_html(log, "<TR><TD class=style_heading COLSPAN=4></TD></TR>\n"); > + } > + > + fflush(log->fp); > + > + if (html_stack_index< MAX_HTML_STACK) > + html_stack_index++; > + else { > + fprintf(stderr, "html log stack overflow pushing section %s.\n", name); > + exit(EXIT_FAILURE); > + } > +} > + > +static void fwts_log_section_end_html(fwts_log *log) > +{ > + if (html_stack_index> 0) { > + html_stack_index--; > + fflush(log->fp); > + } else { > + fprintf(stderr, "html log stack underflow.\n"); > + exit(EXIT_FAILURE); > + } > + > +} > + > +static void fwts_log_open_html(fwts_log *log) > +{ > + fwts_log_html(log, "<HTML>\n"); > + fwts_log_html(log, "<HEAD>\n"); > + fwts_log_html(log, "<TITLE>fwts log</TITLE>\n"); > + fwts_log_html(log, "</HEAD>\n"); > + fwts_log_html(log, "<BODY>\n"); > + fwts_log_html(log, "<STYLE>\n"); > + fwts_log_html(log, > + ".style_critical { background-color: red; font-weight: bold; " > + "text-align: center; vertical-align: center }\n" > + ".style_high { background-color: orange; font-weight: bold; " > + "text-align: center; vertical-align: center }\n" > + ".style_medium { background-color: yellow; font-weight: bold; " > + "text-align: center; vertical-align: center }\n" > + ".style_low { background-color: #9acd32; font-weight: bold; " > + "text-align: center; vertical-align: center }\n" > + ".style_passed { background-color: green; font-weight: bold; " > + "text-align: center; vertical-align: center }\n" > + ".style_advice { text-align: center; vertical-align: center; " > + "font-weight: bold }\n" > + ".style_advice_info { font-style: italic; font-weight: bold }" > + ".style_skipped { background-color: wheat; text-align: center; " > + "vertical-align: center }\n" > + ".style_heading { background-color: wheat; font-weight: bold; " > + "text-align: center }\n" > + ".style_summary { font-weight: bold }\n" > + ".style_error { background-color: orange; font-weight: bold; " > + "text-align: center; vertical-align: center }\n" > + ".style_subtest { background-color: lightgray; }\n" > + ".style_info { }\n" > + ".style_code { font-family=sans-mono; line-height: 70% }\n"); > + fwts_log_html(log, "</STYLE>\n"); > + fflush(log->fp); > + > + fwts_log_html(log, "<TABLE>\n"); > + fwts_log_html(log, "</TR>\n"); > + > + fwts_log_section_begin_html(log, "fwts"); > +} > + > +static void fwts_log_close_html(fwts_log *log) > +{ > + fwts_log_section_end_html(log); > + > + fwts_log_html(log, "</TABLE>\n"); > + fwts_log_html(log, "</BODY>\n"); > + fwts_log_html(log, "</HTML>\n"); > + fflush(log->fp); > +} > + > +fwts_log_ops fwts_log_html_ops = { > + .vprintf = fwts_log_vprintf_html, > + .underline = fwts_log_underline_html, > + .newline = fwts_log_newline_html, > + .section_begin = fwts_log_section_begin_html, > + .section_end = fwts_log_section_end_html, > + .open = fwts_log_open_html, > + .close = fwts_log_close_html > +}; Acked-by: Ivan Hu<ivan.hu@canonical.com>
On Thu, May 31, 2012 at 2:40 AM, Colin King <colin.king@canonical.com> wrote: > From: Colin Ian King <colin.king@canonical.com> > > Signed-off-by: Colin Ian King <colin.king@canonical.com> > --- > src/lib/include/fwts_log.h | 8 +- > src/lib/src/Makefile.am | 1 + > src/lib/src/fwts_framework.c | 12 +- > src/lib/src/fwts_log.c | 3 + > src/lib/src/fwts_log_html.c | 297 ++++++++++++++++++++++++++++++++++++++++++ > 5 files changed, 313 insertions(+), 8 deletions(-) > create mode 100644 src/lib/src/fwts_log_html.c > > diff --git a/src/lib/include/fwts_log.h b/src/lib/include/fwts_log.h > index 4e0f33a..a659baa 100644 > --- a/src/lib/include/fwts_log.h > +++ b/src/lib/include/fwts_log.h > @@ -63,6 +63,7 @@ typedef enum { > LOG_TYPE_PLAINTEXT = 0x00000001, > LOG_TYPE_JSON = 0x00000002, > LOG_TYPE_XML = 0x00000003, > + LOG_TYPE_HTML = 0x00000004, > } fwts_log_type; > > typedef struct log_t { > @@ -84,9 +85,10 @@ typedef struct fwts_log_ops_t { > void (*close)(fwts_log *); > } fwts_log_ops; > > -fwts_log_ops fwts_log_plaintext_ops; > -fwts_log_ops fwts_log_json_ops; > -fwts_log_ops fwts_log_xml_ops; > +extern fwts_log_ops fwts_log_plaintext_ops; > +extern fwts_log_ops fwts_log_json_ops; > +extern fwts_log_ops fwts_log_xml_ops; > +extern fwts_log_ops fwts_log_html_ops; > > extern fwts_log_field fwts_log_filter; > extern const char *fwts_log_format; > diff --git a/src/lib/src/Makefile.am b/src/lib/src/Makefile.am > index acea9cb..f846621 100644 > --- a/src/lib/src/Makefile.am > +++ b/src/lib/src/Makefile.am > @@ -40,6 +40,7 @@ libfwts_la_SOURCES = \ > fwts_log_plaintext.c \ > fwts_log_json.c \ > fwts_log_xml.c \ > + fwts_log_html.c \ > fwts_memorymap.c \ > fwts_microcode.c \ > fwts_mmap.c \ > diff --git a/src/lib/src/fwts_framework.c b/src/lib/src/fwts_framework.c > index 3f54fdb..721f4de 100644 > --- a/src/lib/src/fwts_framework.c > +++ b/src/lib/src/fwts_framework.c > @@ -76,7 +76,7 @@ static fwts_option fwts_framework_options[] = { > { "json-data-path", "j:", 1, "Specify path to fwts json data files - default is /usr/share/fwts." }, > { "lp-tags-log", "", 0, "Output LaunchPad bug tags in results log." }, > { "disassemble-aml", "", 0, "Disassemble AML from DSDT and SSDT tables." }, > - { "log-type", "", 1, "Specify log type (plaintext, json or xml)." }, > + { "log-type", "", 1, "Specify log type (plaintext, json, html or xml)." }, > { NULL, NULL, 0, NULL } > }; > > @@ -672,7 +672,7 @@ void fwts_framework_log(fwts_framework *fw, > case LOG_ADVICE: > fwts_log_nl(fw); > snprintf(prefix, sizeof(prefix), "%s: ", str); > - fwts_log_printf(fw->results, LOG_ADVICE, level, str, label, prefix, "%s", buffer); > + fwts_log_printf(fw->results, field, level, str, label, prefix, "%s", buffer); > fwts_log_nl(fw); > break; > case LOG_FAILED: > @@ -680,7 +680,7 @@ void fwts_framework_log(fwts_framework *fw, > fwts_summary_add(fw, fw->current_major_test->name, level, buffer); > snprintf(prefix, sizeof(prefix), "%s [%s] %s: Test %d, ", > str, fwts_log_level_to_str(level), label, fw->current_minor_test_num); > - fwts_log_printf(fw->results, LOG_RESULT, level, str, label, prefix, "%s", buffer); > + fwts_log_printf(fw->results, field, level, str, label, prefix, "%s", buffer); > break; > case LOG_PASSED: > case LOG_WARNING: > @@ -688,7 +688,7 @@ void fwts_framework_log(fwts_framework *fw, > case LOG_ABORTED: > snprintf(prefix, sizeof(prefix), "%s: Test %d, ", > str, fw->current_minor_test_num); > - fwts_log_printf(fw->results, LOG_RESULT, level, str, label, prefix, "%s", buffer); > + fwts_log_printf(fw->results, field, level, str, label, prefix, "%s", buffer); > break; > case LOG_INFOONLY: > break; /* no-op */ > @@ -949,8 +949,10 @@ int fwts_framework_options_handler(fwts_framework *fw, int argc, char * const ar > fw->log_type = LOG_TYPE_JSON; > else if (!strcmp(optarg, "xml")) > fw->log_type = LOG_TYPE_XML; > + else if (!strcmp(optarg, "html")) > + fw->log_type = LOG_TYPE_HTML; > else { > - fprintf(stderr, "--log-type can be either plaintext or json.\n"); > + fprintf(stderr, "--log-type can be either plaintext, xml, html or json.\n"); > return FWTS_ERROR; > } > break; > diff --git a/src/lib/src/fwts_log.c b/src/lib/src/fwts_log.c > index c764d55..fea7c41 100644 > --- a/src/lib/src/fwts_log.c > +++ b/src/lib/src/fwts_log.c > @@ -432,6 +432,9 @@ fwts_log *fwts_log_open(const char *owner, const char *name, const char *mode, f > case LOG_TYPE_XML: > newlog->ops = &fwts_log_xml_ops; > break; > + case LOG_TYPE_HTML: > + newlog->ops = &fwts_log_html_ops; > + break; > case LOG_TYPE_NONE: > default: > newlog->ops = &fwts_log_plaintext_ops; > diff --git a/src/lib/src/fwts_log_html.c b/src/lib/src/fwts_log_html.c > new file mode 100644 > index 0000000..25f81ef > --- /dev/null > +++ b/src/lib/src/fwts_log_html.c > @@ -0,0 +1,297 @@ > +/* > + * Copyright (C) 2010-2012 Canonical > + * > + * 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 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, write to the Free Software > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. > + * > + */ > + > +#include <stdlib.h> > +#include <stdio.h> > +#include <stdarg.h> > +#include <string.h> > +#include <unistd.h> > +#include <sys/ioctl.h> > +#include <time.h> > + > +#include "fwts.h" > + > +#define MAX_HTML_STACK (64) > +#define HTML_INDENT (2) > + > +typedef struct { > + const char *name; > +} fwts_log_html_stack_t; > + > +static fwts_log_html_stack_t html_stack[MAX_HTML_STACK]; > +static int html_stack_index = 0; > + > +static void fwts_log_html(fwts_log *log, const char *fmt, ...) > +{ > + va_list args; > + > + va_start(args, fmt); > + > + fprintf(log->fp, "%*s", html_stack_index * HTML_INDENT, ""); > + vfprintf(log->fp, fmt, args); > + > + va_end(args); > +} > + > + > +/* > + * fwts_log_vprintf_html() > + * vprintf to a log > + */ > +static int fwts_log_vprintf_html(fwts_log *log, > + const fwts_log_field field, > + const fwts_log_level level, > + const char *status, > + const char *label, > + const char *prefix, > + const char *fmt, > + va_list args) > +{ > + struct tm tm; > + time_t now; > + char *str; > + char *style; > + char *code_start; > + char *code_end; > + > + if (!((field & LOG_FIELD_MASK) & fwts_log_filter)) > + return 0; > + > + if (field & (LOG_NEWLINE | LOG_SEPARATOR | LOG_DEBUG)) > + return 0; > + > + time(&now); > + localtime_r(&now, &tm); > + > + fwts_log_html(log, "<TR>\n"); > + > + if ((field & LOG_FIELD_MASK) != LOG_HEADING) { > + fwts_log_html(log, " <TD>%2.2d/%2.2d/%-2.2d</TD>\n", > + tm.tm_mday, tm.tm_mon + 1, (tm.tm_year+1900) % 100); > + fwts_log_html(log, " <TD>%2.2d:%2.2d:%2.2d</TD>\n", > + tm.tm_hour, tm.tm_min, tm.tm_sec); > + } > + > + if (field & LOG_VERBATUM) { > + code_start = "<PRE class=style_code>"; > + code_end = "</PRE>"; > + } else { > + code_start = ""; > + code_end = ""; > + } > + > + switch (field & LOG_FIELD_MASK) { > + case LOG_ERROR: > + fwts_log_html(log, " <TD class=style_error>Error</TD><TD COLSPAN=3>"); > + vfprintf(log->fp, fmt, args); > + fprintf(log->fp, "</TD>\n"); > + break; > + case LOG_WARNING: > + fwts_log_html(log, " <TD class=style_error>Warning</TD><TD COLSPAN=3 class=style_advice_info>%s", code_start); > + vfprintf(log->fp, fmt, args); > + fprintf(log->fp, "%s</TD>\n", code_end); > + break; > + case LOG_HEADING: > + fwts_log_html(log, "<TD COLSPAN=4 class=style_heading>%s", code_start); > + vfprintf(log->fp, fmt, args); > + fprintf(log->fp, "%s</TD>\n", code_end); > + break; > + case LOG_INFO: > + fwts_log_html(log, " <TD></TD><TD COLSPAN=3 class=style_infos>%s", code_start); > + vfprintf(log->fp, fmt, args); > + fprintf(log->fp, "%s</TD>\n", code_end); > + break; > + case LOG_PASSED: > + fwts_log_html(log, "<TD class=style_passed>PASSED</TD><TD>"); > + vfprintf(log->fp, fmt, args); > + fprintf(log->fp, "</TD>\n"); > + break; > + case LOG_FAILED: > + switch (level) { > + case LOG_LEVEL_CRITICAL: > + style = " class=style_critical"; > + break; > + case LOG_LEVEL_HIGH: > + style = " class=style_high"; > + break; > + case LOG_LEVEL_MEDIUM: > + style = " class=style_medium"; > + break; > + case LOG_LEVEL_LOW: > + style = " class=style_low"; > + break; > + case LOG_LEVEL_INFO: > + case LOG_LEVEL_NONE: > + default: > + style = ""; > + break; > + } > + str = fwts_log_level_to_str(level); > + > + fwts_log_html(log, " <TD%s>%s [%s]</TD>\n", style, *status ? status : "", str); > + > + fwts_log_html(log, " <TD>"); > + vfprintf(log->fp, fmt, args); > + fprintf(log->fp, "</TD>\n"); > + break; > + > + case LOG_SKIPPED: > + fwts_log_html(log, "<TD class=style_skipped>Skipped</TD><TD>%s", code_start); > + vfprintf(log->fp, fmt, args); > + fprintf(log->fp, "%s</TD>\n", code_end); > + break; > + > + case LOG_SUMMARY: > + fwts_log_html(log, " <TD></TD><TD COLSPAN=3 class=style_summary>%s", code_start); > + vfprintf(log->fp, fmt, args); > + fprintf(log->fp, "%s</TD>\n", code_end); > + break; > + > + case LOG_ADVICE: > + fwts_log_html(log, " <TD class=style_advice>Advice</TD><TD COLSPAN=3 class=style_advice_info>%s", code_start); > + vfprintf(log->fp, fmt, args); > + fprintf(log->fp, "%s</TD>\n", code_end); > + break; > + > + default: > + break; > + } > + > + fwts_log_html(log, "</TR>\n"); > + fflush(log->fp); > + > + log->line_number++; > + > + return 0; > +} > + > +/* > + * fwts_log_underline_html() > + * write an underline across log, using character ch as the underline > + */ > +static void fwts_log_underline_html(fwts_log *log, const int ch) > +{ > + /* No-op for html */ > +} > + > +/* > + * fwts_log_newline() > + * write newline to log > + */ > +static void fwts_log_newline_html(fwts_log *log) > +{ > + /* No-op for html */ > +} > + > +static void fwts_log_section_begin_html(fwts_log *log, const char *name) > +{ > + html_stack[html_stack_index].name = name; > + > + if (!strcmp(name, "summary")) { > + fwts_log_html(log, "<TR><TD class=style_heading COLSPAN=4>Summary</TD></TR>\n"); > + } else if (!strcmp(name, "heading")) { > + fwts_log_html(log, "<TR><TD class=style_heading COLSPAN=4>Firmware Test Suite</TD></TR>\n"); > + } else if (!strcmp(name, "subtest_info")) { > + fwts_log_html(log, "<TR><TD class=style_subtest COLSPAN=4></TD></TR>\n"); > + } else if (!strcmp(name, "failure")) { > + fwts_log_html(log, "<TR><TD class=style_heading COLSPAN=4></TD></TR>\n"); > + } > + > + fflush(log->fp); > + > + if (html_stack_index < MAX_HTML_STACK) > + html_stack_index++; > + else { > + fprintf(stderr, "html log stack overflow pushing section %s.\n", name); > + exit(EXIT_FAILURE); > + } > +} > + > +static void fwts_log_section_end_html(fwts_log *log) > +{ > + if (html_stack_index > 0) { > + html_stack_index--; > + fflush(log->fp); > + } else { > + fprintf(stderr, "html log stack underflow.\n"); > + exit(EXIT_FAILURE); > + } > + > +} > + > +static void fwts_log_open_html(fwts_log *log) > +{ > + fwts_log_html(log, "<HTML>\n"); > + fwts_log_html(log, "<HEAD>\n"); > + fwts_log_html(log, " <TITLE>fwts log</TITLE>\n"); > + fwts_log_html(log, "</HEAD>\n"); > + fwts_log_html(log, "<BODY>\n"); > + fwts_log_html(log, "<STYLE>\n"); > + fwts_log_html(log, > + ".style_critical { background-color: red; font-weight: bold; " > + "text-align: center; vertical-align: center }\n" > + ".style_high { background-color: orange; font-weight: bold; " > + "text-align: center; vertical-align: center }\n" > + ".style_medium { background-color: yellow; font-weight: bold; " > + "text-align: center; vertical-align: center }\n" > + ".style_low { background-color: #9acd32; font-weight: bold; " > + "text-align: center; vertical-align: center }\n" > + ".style_passed { background-color: green; font-weight: bold; " > + "text-align: center; vertical-align: center }\n" > + ".style_advice { text-align: center; vertical-align: center; " > + "font-weight: bold }\n" > + ".style_advice_info { font-style: italic; font-weight: bold }" > + ".style_skipped { background-color: wheat; text-align: center; " > + "vertical-align: center }\n" > + ".style_heading { background-color: wheat; font-weight: bold; " > + "text-align: center }\n" > + ".style_summary { font-weight: bold }\n" > + ".style_error { background-color: orange; font-weight: bold; " > + "text-align: center; vertical-align: center }\n" > + ".style_subtest { background-color: lightgray; }\n" > + ".style_info { }\n" > + ".style_code { font-family=sans-mono; line-height: 70% }\n"); > + fwts_log_html(log, "</STYLE>\n"); > + fflush(log->fp); > + > + fwts_log_html(log, "<TABLE>\n"); > + fwts_log_html(log, "</TR>\n"); > + > + fwts_log_section_begin_html(log, "fwts"); > +} > + > +static void fwts_log_close_html(fwts_log *log) > +{ > + fwts_log_section_end_html(log); > + > + fwts_log_html(log, "</TABLE>\n"); > + fwts_log_html(log, "</BODY>\n"); > + fwts_log_html(log, "</HTML>\n"); > + fflush(log->fp); > +} > + > +fwts_log_ops fwts_log_html_ops = { > + .vprintf = fwts_log_vprintf_html, > + .underline = fwts_log_underline_html, > + .newline = fwts_log_newline_html, > + .section_begin = fwts_log_section_begin_html, > + .section_end = fwts_log_section_end_html, > + .open = fwts_log_open_html, > + .close = fwts_log_close_html > +}; > -- > 1.7.9.5 > Acked-by: Keng-Yu Lin <kengyu@canonical.com>
On 05/30/2012 02:40 PM, Colin King wrote: > From: Colin Ian King <colin.king@canonical.com> > > Signed-off-by: Colin Ian King <colin.king@canonical.com> > --- > src/lib/include/fwts_log.h | 8 +- > src/lib/src/Makefile.am | 1 + > src/lib/src/fwts_framework.c | 12 +- > src/lib/src/fwts_log.c | 3 + > src/lib/src/fwts_log_html.c | 297 ++++++++++++++++++++++++++++++++++++++++++ > 5 files changed, 313 insertions(+), 8 deletions(-) > create mode 100644 src/lib/src/fwts_log_html.c > > diff --git a/src/lib/include/fwts_log.h b/src/lib/include/fwts_log.h > index 4e0f33a..a659baa 100644 > --- a/src/lib/include/fwts_log.h > +++ b/src/lib/include/fwts_log.h > @@ -63,6 +63,7 @@ typedef enum { > LOG_TYPE_PLAINTEXT = 0x00000001, > LOG_TYPE_JSON = 0x00000002, > LOG_TYPE_XML = 0x00000003, > + LOG_TYPE_HTML = 0x00000004, > } fwts_log_type; > > typedef struct log_t { > @@ -84,9 +85,10 @@ typedef struct fwts_log_ops_t { > void (*close)(fwts_log *); > } fwts_log_ops; > > -fwts_log_ops fwts_log_plaintext_ops; > -fwts_log_ops fwts_log_json_ops; > -fwts_log_ops fwts_log_xml_ops; > +extern fwts_log_ops fwts_log_plaintext_ops; > +extern fwts_log_ops fwts_log_json_ops; > +extern fwts_log_ops fwts_log_xml_ops; > +extern fwts_log_ops fwts_log_html_ops; > > extern fwts_log_field fwts_log_filter; > extern const char *fwts_log_format; > diff --git a/src/lib/src/Makefile.am b/src/lib/src/Makefile.am > index acea9cb..f846621 100644 > --- a/src/lib/src/Makefile.am > +++ b/src/lib/src/Makefile.am > @@ -40,6 +40,7 @@ libfwts_la_SOURCES = \ > fwts_log_plaintext.c \ > fwts_log_json.c \ > fwts_log_xml.c \ > + fwts_log_html.c \ > fwts_memorymap.c \ > fwts_microcode.c \ > fwts_mmap.c \ > diff --git a/src/lib/src/fwts_framework.c b/src/lib/src/fwts_framework.c > index 3f54fdb..721f4de 100644 > --- a/src/lib/src/fwts_framework.c > +++ b/src/lib/src/fwts_framework.c > @@ -76,7 +76,7 @@ static fwts_option fwts_framework_options[] = { > { "json-data-path", "j:", 1, "Specify path to fwts json data files - default is /usr/share/fwts." }, > { "lp-tags-log", "", 0, "Output LaunchPad bug tags in results log." }, > { "disassemble-aml", "", 0, "Disassemble AML from DSDT and SSDT tables." }, > - { "log-type", "", 1, "Specify log type (plaintext, json or xml)." }, > + { "log-type", "", 1, "Specify log type (plaintext, json, html or xml)." }, > { NULL, NULL, 0, NULL } > }; > > @@ -672,7 +672,7 @@ void fwts_framework_log(fwts_framework *fw, > case LOG_ADVICE: > fwts_log_nl(fw); > snprintf(prefix, sizeof(prefix), "%s: ", str); > - fwts_log_printf(fw->results, LOG_ADVICE, level, str, label, prefix, "%s", buffer); > + fwts_log_printf(fw->results, field, level, str, label, prefix, "%s", buffer); > fwts_log_nl(fw); > break; > case LOG_FAILED: > @@ -680,7 +680,7 @@ void fwts_framework_log(fwts_framework *fw, > fwts_summary_add(fw, fw->current_major_test->name, level, buffer); > snprintf(prefix, sizeof(prefix), "%s [%s] %s: Test %d, ", > str, fwts_log_level_to_str(level), label, fw->current_minor_test_num); > - fwts_log_printf(fw->results, LOG_RESULT, level, str, label, prefix, "%s", buffer); > + fwts_log_printf(fw->results, field, level, str, label, prefix, "%s", buffer); > break; > case LOG_PASSED: > case LOG_WARNING: > @@ -688,7 +688,7 @@ void fwts_framework_log(fwts_framework *fw, > case LOG_ABORTED: > snprintf(prefix, sizeof(prefix), "%s: Test %d, ", > str, fw->current_minor_test_num); > - fwts_log_printf(fw->results, LOG_RESULT, level, str, label, prefix, "%s", buffer); > + fwts_log_printf(fw->results, field, level, str, label, prefix, "%s", buffer); > break; > case LOG_INFOONLY: > break; /* no-op */ > @@ -949,8 +949,10 @@ int fwts_framework_options_handler(fwts_framework *fw, int argc, char * const ar > fw->log_type = LOG_TYPE_JSON; > else if (!strcmp(optarg, "xml")) > fw->log_type = LOG_TYPE_XML; > + else if (!strcmp(optarg, "html")) > + fw->log_type = LOG_TYPE_HTML; > else { > - fprintf(stderr, "--log-type can be either plaintext or json.\n"); > + fprintf(stderr, "--log-type can be either plaintext, xml, html or json.\n"); > return FWTS_ERROR; > } > break; > diff --git a/src/lib/src/fwts_log.c b/src/lib/src/fwts_log.c > index c764d55..fea7c41 100644 > --- a/src/lib/src/fwts_log.c > +++ b/src/lib/src/fwts_log.c > @@ -432,6 +432,9 @@ fwts_log *fwts_log_open(const char *owner, const char *name, const char *mode, f > case LOG_TYPE_XML: > newlog->ops = &fwts_log_xml_ops; > break; > + case LOG_TYPE_HTML: > + newlog->ops = &fwts_log_html_ops; > + break; > case LOG_TYPE_NONE: > default: > newlog->ops = &fwts_log_plaintext_ops; > diff --git a/src/lib/src/fwts_log_html.c b/src/lib/src/fwts_log_html.c > new file mode 100644 > index 0000000..25f81ef > --- /dev/null > +++ b/src/lib/src/fwts_log_html.c > @@ -0,0 +1,297 @@ > +/* > + * Copyright (C) 2010-2012 Canonical > + * > + * 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 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, write to the Free Software > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. > + * > + */ > + > +#include <stdlib.h> > +#include <stdio.h> > +#include <stdarg.h> > +#include <string.h> > +#include <unistd.h> > +#include <sys/ioctl.h> > +#include <time.h> > + > +#include "fwts.h" > + > +#define MAX_HTML_STACK (64) > +#define HTML_INDENT (2) > + > +typedef struct { > + const char *name; > +} fwts_log_html_stack_t; > + > +static fwts_log_html_stack_t html_stack[MAX_HTML_STACK]; > +static int html_stack_index = 0; > + > +static void fwts_log_html(fwts_log *log, const char *fmt, ...) > +{ > + va_list args; > + > + va_start(args, fmt); > + > + fprintf(log->fp, "%*s", html_stack_index * HTML_INDENT, ""); > + vfprintf(log->fp, fmt, args); > + > + va_end(args); > +} > + > + > +/* > + * fwts_log_vprintf_html() > + * vprintf to a log > + */ > +static int fwts_log_vprintf_html(fwts_log *log, > + const fwts_log_field field, > + const fwts_log_level level, > + const char *status, > + const char *label, > + const char *prefix, > + const char *fmt, > + va_list args) > +{ > + struct tm tm; > + time_t now; > + char *str; > + char *style; > + char *code_start; > + char *code_end; > + > + if (!((field & LOG_FIELD_MASK) & fwts_log_filter)) > + return 0; > + > + if (field & (LOG_NEWLINE | LOG_SEPARATOR | LOG_DEBUG)) > + return 0; > + > + time(&now); > + localtime_r(&now, &tm); > + > + fwts_log_html(log, "<TR>\n"); > + > + if ((field & LOG_FIELD_MASK) != LOG_HEADING) { > + fwts_log_html(log, " <TD>%2.2d/%2.2d/%-2.2d</TD>\n", > + tm.tm_mday, tm.tm_mon + 1, (tm.tm_year+1900) % 100); > + fwts_log_html(log, " <TD>%2.2d:%2.2d:%2.2d</TD>\n", > + tm.tm_hour, tm.tm_min, tm.tm_sec); > + } > + > + if (field & LOG_VERBATUM) { > + code_start = "<PRE class=style_code>"; > + code_end = "</PRE>"; > + } else { > + code_start = ""; > + code_end = ""; > + } > + > + switch (field & LOG_FIELD_MASK) { > + case LOG_ERROR: > + fwts_log_html(log, " <TD class=style_error>Error</TD><TD COLSPAN=3>"); > + vfprintf(log->fp, fmt, args); > + fprintf(log->fp, "</TD>\n"); > + break; > + case LOG_WARNING: > + fwts_log_html(log, " <TD class=style_error>Warning</TD><TD COLSPAN=3 class=style_advice_info>%s", code_start); > + vfprintf(log->fp, fmt, args); > + fprintf(log->fp, "%s</TD>\n", code_end); > + break; > + case LOG_HEADING: > + fwts_log_html(log, "<TD COLSPAN=4 class=style_heading>%s", code_start); > + vfprintf(log->fp, fmt, args); > + fprintf(log->fp, "%s</TD>\n", code_end); > + break; > + case LOG_INFO: > + fwts_log_html(log, " <TD></TD><TD COLSPAN=3 class=style_infos>%s", code_start); > + vfprintf(log->fp, fmt, args); > + fprintf(log->fp, "%s</TD>\n", code_end); > + break; > + case LOG_PASSED: > + fwts_log_html(log, "<TD class=style_passed>PASSED</TD><TD>"); > + vfprintf(log->fp, fmt, args); > + fprintf(log->fp, "</TD>\n"); > + break; > + case LOG_FAILED: > + switch (level) { > + case LOG_LEVEL_CRITICAL: > + style = " class=style_critical"; > + break; > + case LOG_LEVEL_HIGH: > + style = " class=style_high"; > + break; > + case LOG_LEVEL_MEDIUM: > + style = " class=style_medium"; > + break; > + case LOG_LEVEL_LOW: > + style = " class=style_low"; > + break; > + case LOG_LEVEL_INFO: > + case LOG_LEVEL_NONE: > + default: > + style = ""; > + break; > + } > + str = fwts_log_level_to_str(level); > + > + fwts_log_html(log, " <TD%s>%s [%s]</TD>\n", style, *status ? status : "", str); > + > + fwts_log_html(log, " <TD>"); > + vfprintf(log->fp, fmt, args); > + fprintf(log->fp, "</TD>\n"); > + break; > + > + case LOG_SKIPPED: > + fwts_log_html(log, "<TD class=style_skipped>Skipped</TD><TD>%s", code_start); > + vfprintf(log->fp, fmt, args); > + fprintf(log->fp, "%s</TD>\n", code_end); > + break; > + > + case LOG_SUMMARY: > + fwts_log_html(log, " <TD></TD><TD COLSPAN=3 class=style_summary>%s", code_start); > + vfprintf(log->fp, fmt, args); > + fprintf(log->fp, "%s</TD>\n", code_end); > + break; > + > + case LOG_ADVICE: > + fwts_log_html(log, " <TD class=style_advice>Advice</TD><TD COLSPAN=3 class=style_advice_info>%s", code_start); > + vfprintf(log->fp, fmt, args); > + fprintf(log->fp, "%s</TD>\n", code_end); > + break; > + > + default: > + break; > + } > + > + fwts_log_html(log, "</TR>\n"); > + fflush(log->fp); > + > + log->line_number++; > + > + return 0; > +} > + > +/* > + * fwts_log_underline_html() > + * write an underline across log, using character ch as the underline > + */ > +static void fwts_log_underline_html(fwts_log *log, const int ch) > +{ > + /* No-op for html */ > +} > + > +/* > + * fwts_log_newline() > + * write newline to log > + */ > +static void fwts_log_newline_html(fwts_log *log) > +{ > + /* No-op for html */ > +} > + > +static void fwts_log_section_begin_html(fwts_log *log, const char *name) > +{ > + html_stack[html_stack_index].name = name; > + > + if (!strcmp(name, "summary")) { > + fwts_log_html(log, "<TR><TD class=style_heading COLSPAN=4>Summary</TD></TR>\n"); > + } else if (!strcmp(name, "heading")) { > + fwts_log_html(log, "<TR><TD class=style_heading COLSPAN=4>Firmware Test Suite</TD></TR>\n"); > + } else if (!strcmp(name, "subtest_info")) { > + fwts_log_html(log, "<TR><TD class=style_subtest COLSPAN=4></TD></TR>\n"); > + } else if (!strcmp(name, "failure")) { > + fwts_log_html(log, "<TR><TD class=style_heading COLSPAN=4></TD></TR>\n"); > + } > + > + fflush(log->fp); > + > + if (html_stack_index < MAX_HTML_STACK) > + html_stack_index++; > + else { > + fprintf(stderr, "html log stack overflow pushing section %s.\n", name); > + exit(EXIT_FAILURE); > + } > +} > + > +static void fwts_log_section_end_html(fwts_log *log) > +{ > + if (html_stack_index > 0) { > + html_stack_index--; > + fflush(log->fp); > + } else { > + fprintf(stderr, "html log stack underflow.\n"); > + exit(EXIT_FAILURE); > + } > + > +} > + > +static void fwts_log_open_html(fwts_log *log) > +{ > + fwts_log_html(log, "<HTML>\n"); > + fwts_log_html(log, "<HEAD>\n"); > + fwts_log_html(log, " <TITLE>fwts log</TITLE>\n"); > + fwts_log_html(log, "</HEAD>\n"); > + fwts_log_html(log, "<BODY>\n"); > + fwts_log_html(log, "<STYLE>\n"); > + fwts_log_html(log, > + ".style_critical { background-color: red; font-weight: bold; " > + "text-align: center; vertical-align: center }\n" > + ".style_high { background-color: orange; font-weight: bold; " > + "text-align: center; vertical-align: center }\n" > + ".style_medium { background-color: yellow; font-weight: bold; " > + "text-align: center; vertical-align: center }\n" > + ".style_low { background-color: #9acd32; font-weight: bold; " > + "text-align: center; vertical-align: center }\n" > + ".style_passed { background-color: green; font-weight: bold; " > + "text-align: center; vertical-align: center }\n" > + ".style_advice { text-align: center; vertical-align: center; " > + "font-weight: bold }\n" > + ".style_advice_info { font-style: italic; font-weight: bold }" > + ".style_skipped { background-color: wheat; text-align: center; " > + "vertical-align: center }\n" > + ".style_heading { background-color: wheat; font-weight: bold; " > + "text-align: center }\n" > + ".style_summary { font-weight: bold }\n" > + ".style_error { background-color: orange; font-weight: bold; " > + "text-align: center; vertical-align: center }\n" > + ".style_subtest { background-color: lightgray; }\n" > + ".style_info { }\n" > + ".style_code { font-family=sans-mono; line-height: 70% }\n"); > + fwts_log_html(log, "</STYLE>\n"); > + fflush(log->fp); > + > + fwts_log_html(log, "<TABLE>\n"); > + fwts_log_html(log, "</TR>\n"); > + > + fwts_log_section_begin_html(log, "fwts"); > +} > + > +static void fwts_log_close_html(fwts_log *log) > +{ > + fwts_log_section_end_html(log); > + > + fwts_log_html(log, "</TABLE>\n"); > + fwts_log_html(log, "</BODY>\n"); > + fwts_log_html(log, "</HTML>\n"); > + fflush(log->fp); > +} > + > +fwts_log_ops fwts_log_html_ops = { > + .vprintf = fwts_log_vprintf_html, > + .underline = fwts_log_underline_html, > + .newline = fwts_log_newline_html, > + .section_begin = fwts_log_section_begin_html, > + .section_end = fwts_log_section_end_html, > + .open = fwts_log_open_html, > + .close = fwts_log_close_html > +}; Tested-by: Chris Van Hoof <vanhoof@canonical.com>
diff --git a/src/lib/include/fwts_log.h b/src/lib/include/fwts_log.h index 4e0f33a..a659baa 100644 --- a/src/lib/include/fwts_log.h +++ b/src/lib/include/fwts_log.h @@ -63,6 +63,7 @@ typedef enum { LOG_TYPE_PLAINTEXT = 0x00000001, LOG_TYPE_JSON = 0x00000002, LOG_TYPE_XML = 0x00000003, + LOG_TYPE_HTML = 0x00000004, } fwts_log_type; typedef struct log_t { @@ -84,9 +85,10 @@ typedef struct fwts_log_ops_t { void (*close)(fwts_log *); } fwts_log_ops; -fwts_log_ops fwts_log_plaintext_ops; -fwts_log_ops fwts_log_json_ops; -fwts_log_ops fwts_log_xml_ops; +extern fwts_log_ops fwts_log_plaintext_ops; +extern fwts_log_ops fwts_log_json_ops; +extern fwts_log_ops fwts_log_xml_ops; +extern fwts_log_ops fwts_log_html_ops; extern fwts_log_field fwts_log_filter; extern const char *fwts_log_format; diff --git a/src/lib/src/Makefile.am b/src/lib/src/Makefile.am index acea9cb..f846621 100644 --- a/src/lib/src/Makefile.am +++ b/src/lib/src/Makefile.am @@ -40,6 +40,7 @@ libfwts_la_SOURCES = \ fwts_log_plaintext.c \ fwts_log_json.c \ fwts_log_xml.c \ + fwts_log_html.c \ fwts_memorymap.c \ fwts_microcode.c \ fwts_mmap.c \ diff --git a/src/lib/src/fwts_framework.c b/src/lib/src/fwts_framework.c index 3f54fdb..721f4de 100644 --- a/src/lib/src/fwts_framework.c +++ b/src/lib/src/fwts_framework.c @@ -76,7 +76,7 @@ static fwts_option fwts_framework_options[] = { { "json-data-path", "j:", 1, "Specify path to fwts json data files - default is /usr/share/fwts." }, { "lp-tags-log", "", 0, "Output LaunchPad bug tags in results log." }, { "disassemble-aml", "", 0, "Disassemble AML from DSDT and SSDT tables." }, - { "log-type", "", 1, "Specify log type (plaintext, json or xml)." }, + { "log-type", "", 1, "Specify log type (plaintext, json, html or xml)." }, { NULL, NULL, 0, NULL } }; @@ -672,7 +672,7 @@ void fwts_framework_log(fwts_framework *fw, case LOG_ADVICE: fwts_log_nl(fw); snprintf(prefix, sizeof(prefix), "%s: ", str); - fwts_log_printf(fw->results, LOG_ADVICE, level, str, label, prefix, "%s", buffer); + fwts_log_printf(fw->results, field, level, str, label, prefix, "%s", buffer); fwts_log_nl(fw); break; case LOG_FAILED: @@ -680,7 +680,7 @@ void fwts_framework_log(fwts_framework *fw, fwts_summary_add(fw, fw->current_major_test->name, level, buffer); snprintf(prefix, sizeof(prefix), "%s [%s] %s: Test %d, ", str, fwts_log_level_to_str(level), label, fw->current_minor_test_num); - fwts_log_printf(fw->results, LOG_RESULT, level, str, label, prefix, "%s", buffer); + fwts_log_printf(fw->results, field, level, str, label, prefix, "%s", buffer); break; case LOG_PASSED: case LOG_WARNING: @@ -688,7 +688,7 @@ void fwts_framework_log(fwts_framework *fw, case LOG_ABORTED: snprintf(prefix, sizeof(prefix), "%s: Test %d, ", str, fw->current_minor_test_num); - fwts_log_printf(fw->results, LOG_RESULT, level, str, label, prefix, "%s", buffer); + fwts_log_printf(fw->results, field, level, str, label, prefix, "%s", buffer); break; case LOG_INFOONLY: break; /* no-op */ @@ -949,8 +949,10 @@ int fwts_framework_options_handler(fwts_framework *fw, int argc, char * const ar fw->log_type = LOG_TYPE_JSON; else if (!strcmp(optarg, "xml")) fw->log_type = LOG_TYPE_XML; + else if (!strcmp(optarg, "html")) + fw->log_type = LOG_TYPE_HTML; else { - fprintf(stderr, "--log-type can be either plaintext or json.\n"); + fprintf(stderr, "--log-type can be either plaintext, xml, html or json.\n"); return FWTS_ERROR; } break; diff --git a/src/lib/src/fwts_log.c b/src/lib/src/fwts_log.c index c764d55..fea7c41 100644 --- a/src/lib/src/fwts_log.c +++ b/src/lib/src/fwts_log.c @@ -432,6 +432,9 @@ fwts_log *fwts_log_open(const char *owner, const char *name, const char *mode, f case LOG_TYPE_XML: newlog->ops = &fwts_log_xml_ops; break; + case LOG_TYPE_HTML: + newlog->ops = &fwts_log_html_ops; + break; case LOG_TYPE_NONE: default: newlog->ops = &fwts_log_plaintext_ops; diff --git a/src/lib/src/fwts_log_html.c b/src/lib/src/fwts_log_html.c new file mode 100644 index 0000000..25f81ef --- /dev/null +++ b/src/lib/src/fwts_log_html.c @@ -0,0 +1,297 @@ +/* + * Copyright (C) 2010-2012 Canonical + * + * 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 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <time.h> + +#include "fwts.h" + +#define MAX_HTML_STACK (64) +#define HTML_INDENT (2) + +typedef struct { + const char *name; +} fwts_log_html_stack_t; + +static fwts_log_html_stack_t html_stack[MAX_HTML_STACK]; +static int html_stack_index = 0; + +static void fwts_log_html(fwts_log *log, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + + fprintf(log->fp, "%*s", html_stack_index * HTML_INDENT, ""); + vfprintf(log->fp, fmt, args); + + va_end(args); +} + + +/* + * fwts_log_vprintf_html() + * vprintf to a log + */ +static int fwts_log_vprintf_html(fwts_log *log, + const fwts_log_field field, + const fwts_log_level level, + const char *status, + const char *label, + const char *prefix, + const char *fmt, + va_list args) +{ + struct tm tm; + time_t now; + char *str; + char *style; + char *code_start; + char *code_end; + + if (!((field & LOG_FIELD_MASK) & fwts_log_filter)) + return 0; + + if (field & (LOG_NEWLINE | LOG_SEPARATOR | LOG_DEBUG)) + return 0; + + time(&now); + localtime_r(&now, &tm); + + fwts_log_html(log, "<TR>\n"); + + if ((field & LOG_FIELD_MASK) != LOG_HEADING) { + fwts_log_html(log, " <TD>%2.2d/%2.2d/%-2.2d</TD>\n", + tm.tm_mday, tm.tm_mon + 1, (tm.tm_year+1900) % 100); + fwts_log_html(log, " <TD>%2.2d:%2.2d:%2.2d</TD>\n", + tm.tm_hour, tm.tm_min, tm.tm_sec); + } + + if (field & LOG_VERBATUM) { + code_start = "<PRE class=style_code>"; + code_end = "</PRE>"; + } else { + code_start = ""; + code_end = ""; + } + + switch (field & LOG_FIELD_MASK) { + case LOG_ERROR: + fwts_log_html(log, " <TD class=style_error>Error</TD><TD COLSPAN=3>"); + vfprintf(log->fp, fmt, args); + fprintf(log->fp, "</TD>\n"); + break; + case LOG_WARNING: + fwts_log_html(log, " <TD class=style_error>Warning</TD><TD COLSPAN=3 class=style_advice_info>%s", code_start); + vfprintf(log->fp, fmt, args); + fprintf(log->fp, "%s</TD>\n", code_end); + break; + case LOG_HEADING: + fwts_log_html(log, "<TD COLSPAN=4 class=style_heading>%s", code_start); + vfprintf(log->fp, fmt, args); + fprintf(log->fp, "%s</TD>\n", code_end); + break; + case LOG_INFO: + fwts_log_html(log, " <TD></TD><TD COLSPAN=3 class=style_infos>%s", code_start); + vfprintf(log->fp, fmt, args); + fprintf(log->fp, "%s</TD>\n", code_end); + break; + case LOG_PASSED: + fwts_log_html(log, "<TD class=style_passed>PASSED</TD><TD>"); + vfprintf(log->fp, fmt, args); + fprintf(log->fp, "</TD>\n"); + break; + case LOG_FAILED: + switch (level) { + case LOG_LEVEL_CRITICAL: + style = " class=style_critical"; + break; + case LOG_LEVEL_HIGH: + style = " class=style_high"; + break; + case LOG_LEVEL_MEDIUM: + style = " class=style_medium"; + break; + case LOG_LEVEL_LOW: + style = " class=style_low"; + break; + case LOG_LEVEL_INFO: + case LOG_LEVEL_NONE: + default: + style = ""; + break; + } + str = fwts_log_level_to_str(level); + + fwts_log_html(log, " <TD%s>%s [%s]</TD>\n", style, *status ? status : "", str); + + fwts_log_html(log, " <TD>"); + vfprintf(log->fp, fmt, args); + fprintf(log->fp, "</TD>\n"); + break; + + case LOG_SKIPPED: + fwts_log_html(log, "<TD class=style_skipped>Skipped</TD><TD>%s", code_start); + vfprintf(log->fp, fmt, args); + fprintf(log->fp, "%s</TD>\n", code_end); + break; + + case LOG_SUMMARY: + fwts_log_html(log, " <TD></TD><TD COLSPAN=3 class=style_summary>%s", code_start); + vfprintf(log->fp, fmt, args); + fprintf(log->fp, "%s</TD>\n", code_end); + break; + + case LOG_ADVICE: + fwts_log_html(log, " <TD class=style_advice>Advice</TD><TD COLSPAN=3 class=style_advice_info>%s", code_start); + vfprintf(log->fp, fmt, args); + fprintf(log->fp, "%s</TD>\n", code_end); + break; + + default: + break; + } + + fwts_log_html(log, "</TR>\n"); + fflush(log->fp); + + log->line_number++; + + return 0; +} + +/* + * fwts_log_underline_html() + * write an underline across log, using character ch as the underline + */ +static void fwts_log_underline_html(fwts_log *log, const int ch) +{ + /* No-op for html */ +} + +/* + * fwts_log_newline() + * write newline to log + */ +static void fwts_log_newline_html(fwts_log *log) +{ + /* No-op for html */ +} + +static void fwts_log_section_begin_html(fwts_log *log, const char *name) +{ + html_stack[html_stack_index].name = name; + + if (!strcmp(name, "summary")) { + fwts_log_html(log, "<TR><TD class=style_heading COLSPAN=4>Summary</TD></TR>\n"); + } else if (!strcmp(name, "heading")) { + fwts_log_html(log, "<TR><TD class=style_heading COLSPAN=4>Firmware Test Suite</TD></TR>\n"); + } else if (!strcmp(name, "subtest_info")) { + fwts_log_html(log, "<TR><TD class=style_subtest COLSPAN=4></TD></TR>\n"); + } else if (!strcmp(name, "failure")) { + fwts_log_html(log, "<TR><TD class=style_heading COLSPAN=4></TD></TR>\n"); + } + + fflush(log->fp); + + if (html_stack_index < MAX_HTML_STACK) + html_stack_index++; + else { + fprintf(stderr, "html log stack overflow pushing section %s.\n", name); + exit(EXIT_FAILURE); + } +} + +static void fwts_log_section_end_html(fwts_log *log) +{ + if (html_stack_index > 0) { + html_stack_index--; + fflush(log->fp); + } else { + fprintf(stderr, "html log stack underflow.\n"); + exit(EXIT_FAILURE); + } + +} + +static void fwts_log_open_html(fwts_log *log) +{ + fwts_log_html(log, "<HTML>\n"); + fwts_log_html(log, "<HEAD>\n"); + fwts_log_html(log, " <TITLE>fwts log</TITLE>\n"); + fwts_log_html(log, "</HEAD>\n"); + fwts_log_html(log, "<BODY>\n"); + fwts_log_html(log, "<STYLE>\n"); + fwts_log_html(log, + ".style_critical { background-color: red; font-weight: bold; " + "text-align: center; vertical-align: center }\n" + ".style_high { background-color: orange; font-weight: bold; " + "text-align: center; vertical-align: center }\n" + ".style_medium { background-color: yellow; font-weight: bold; " + "text-align: center; vertical-align: center }\n" + ".style_low { background-color: #9acd32; font-weight: bold; " + "text-align: center; vertical-align: center }\n" + ".style_passed { background-color: green; font-weight: bold; " + "text-align: center; vertical-align: center }\n" + ".style_advice { text-align: center; vertical-align: center; " + "font-weight: bold }\n" + ".style_advice_info { font-style: italic; font-weight: bold }" + ".style_skipped { background-color: wheat; text-align: center; " + "vertical-align: center }\n" + ".style_heading { background-color: wheat; font-weight: bold; " + "text-align: center }\n" + ".style_summary { font-weight: bold }\n" + ".style_error { background-color: orange; font-weight: bold; " + "text-align: center; vertical-align: center }\n" + ".style_subtest { background-color: lightgray; }\n" + ".style_info { }\n" + ".style_code { font-family=sans-mono; line-height: 70% }\n"); + fwts_log_html(log, "</STYLE>\n"); + fflush(log->fp); + + fwts_log_html(log, "<TABLE>\n"); + fwts_log_html(log, "</TR>\n"); + + fwts_log_section_begin_html(log, "fwts"); +} + +static void fwts_log_close_html(fwts_log *log) +{ + fwts_log_section_end_html(log); + + fwts_log_html(log, "</TABLE>\n"); + fwts_log_html(log, "</BODY>\n"); + fwts_log_html(log, "</HTML>\n"); + fflush(log->fp); +} + +fwts_log_ops fwts_log_html_ops = { + .vprintf = fwts_log_vprintf_html, + .underline = fwts_log_underline_html, + .newline = fwts_log_newline_html, + .section_begin = fwts_log_section_begin_html, + .section_end = fwts_log_section_end_html, + .open = fwts_log_open_html, + .close = fwts_log_close_html +};