~ubuntu-branches/ubuntu/trusty/kcov/trusty

« back to all changes in this revision

Viewing changes to report.c

  • Committer: Bazaar Package Importer
  • Author(s): Michael Tautschnig
  • Date: 2010-12-17 10:03:23 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20101217100323-03njos8sfhhuax0y
Tags: 4-1
* New upstream release
  - Fixes FTBFS on non-x86 architectures (closes: #603135).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright (C) 2010 Thomas Neumann, Simon Kagstrom
3
 
 *
4
 
 * See COPYING for license details
5
 
 */
6
 
#define _GNU_SOURCE
7
 
#include <pthread.h>
8
 
#include <unistd.h>
9
 
#include <time.h>
10
 
#include <sys/stat.h>
11
 
#include <sys/types.h>
12
 
 
13
 
#include <utils.h>
14
 
#include <kc.h>
15
 
 
16
 
 
17
 
static const char icon_ruby[] =
18
 
  { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
19
 
0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00,
20
 
0x25, 0xdb, 0x56, 0xca, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd2, 0x07, 0x11, 0x0f,
21
 
0x18, 0x10, 0x5d, 0x57, 0x34, 0x6e, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b,
22
 
0x12, 0x00, 0x00, 0x0b, 0x12, 0x01, 0xd2, 0xdd, 0x7e, 0xfc, 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d,
23
 
0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 0x00, 0x00, 0x06, 0x50, 0x4c, 0x54, 0x45,
24
 
0xff, 0x35, 0x2f, 0x00, 0x00, 0x00, 0xd0, 0x33, 0x9a, 0x9d, 0x00, 0x00, 0x00, 0x0a, 0x49, 0x44, 0x41,
25
 
0x54, 0x78, 0xda, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0xe5, 0x27, 0xde, 0xfc, 0x00, 0x00,
26
 
0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 };
27
 
 
28
 
static const char icon_amber[] =
29
 
  { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
30
 
0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00,
31
 
0x25, 0xdb, 0x56, 0xca, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd2, 0x07, 0x11, 0x0f,
32
 
0x28, 0x04, 0x98, 0xcb, 0xd6, 0xe0, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b,
33
 
0x12, 0x00, 0x00, 0x0b, 0x12, 0x01, 0xd2, 0xdd, 0x7e, 0xfc, 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d,
34
 
0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 0x00, 0x00, 0x06, 0x50, 0x4c, 0x54, 0x45,
35
 
0xff, 0xe0, 0x50, 0x00, 0x00, 0x00, 0xa2, 0x7a, 0xda, 0x7e, 0x00, 0x00, 0x00, 0x0a, 0x49, 0x44, 0x41,
36
 
0x54, 0x78, 0xda, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0xe5, 0x27, 0xde, 0xfc, 0x00, 0x00,
37
 
0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 };
38
 
 
39
 
static const char icon_emerald[] =
40
 
  { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
41
 
0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00, 0x25,
42
 
0xdb, 0x56, 0xca, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd2, 0x07, 0x11, 0x0f, 0x22, 0x2b,
43
 
0xc9, 0xf5, 0x03, 0x33, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x12, 0x00, 0x00,
44
 
0x0b, 0x12, 0x01, 0xd2, 0xdd, 0x7e, 0xfc, 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1,
45
 
0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 0x00, 0x00, 0x06, 0x50, 0x4c, 0x54, 0x45, 0x1b, 0xea, 0x59, 0x0a, 0x0a,
46
 
0x0a, 0x0f, 0xba, 0x50, 0x83, 0x00, 0x00, 0x00, 0x0a, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x60, 0x00,
47
 
0x00, 0x00, 0x02, 0x00, 0x01, 0xe5, 0x27, 0xde, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae,
48
 
0x42, 0x60, 0x82 };
49
 
 
50
 
static const char icon_snow[] =
51
 
  { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
52
 
0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00,
53
 
0x25, 0xdb, 0x56, 0xca, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd2, 0x07, 0x11, 0x0f,
54
 
0x1e, 0x1d, 0x75, 0xbc, 0xef, 0x55, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b,
55
 
0x12, 0x00, 0x00, 0x0b, 0x12, 0x01, 0xd2, 0xdd, 0x7e, 0xfc, 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d,
56
 
0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 0x00, 0x00, 0x06, 0x50, 0x4c, 0x54, 0x45,
57
 
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x55, 0xc2, 0xd3, 0x7e, 0x00, 0x00, 0x00, 0x0a, 0x49, 0x44, 0x41,
58
 
0x54, 0x78, 0xda, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0xe5, 0x27, 0xde, 0xfc, 0x00, 0x00,
59
 
0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 };
60
 
 
61
 
static const char icon_glass[] =
62
 
  { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
63
 
0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00,
64
 
0x25, 0xdb, 0x56, 0xca, 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b,
65
 
0xfc, 0x61, 0x05, 0x00, 0x00, 0x00, 0x06, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
66
 
0x55, 0xc2, 0xd3, 0x7e, 0x00, 0x00, 0x00, 0x01, 0x74, 0x52, 0x4e, 0x53, 0x00, 0x40, 0xe6, 0xd8, 0x66,
67
 
0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, 0x47, 0x44, 0x00, 0x88, 0x05, 0x1d, 0x48, 0x00, 0x00, 0x00, 0x09,
68
 
0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x12, 0x00, 0x00, 0x0b, 0x12, 0x01, 0xd2, 0xdd, 0x7e, 0xfc,
69
 
0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd2, 0x07, 0x13, 0x0f, 0x08, 0x19, 0xc4, 0x40,
70
 
0x56, 0x10, 0x00, 0x00, 0x00, 0x0a, 0x49, 0x44, 0x41, 0x54, 0x78, 0x9c, 0x63, 0x60, 0x00, 0x00, 0x00,
71
 
0x02, 0x00, 0x01, 0x48, 0xaf, 0xa4, 0x71, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42,
72
 
0x60, 0x82 };
73
 
 
74
 
const char css_text[] = "/* Based upon the lcov CSS style, style files can be reused */\n"
75
 
                "body { color: #000000; background-color: #FFFFFF; }\n"
76
 
                "a:link { color: #284FA8; text-decoration: underline; }\n"
77
 
                "a:visited { color: #00CB40; text-decoration: underline; }\n"
78
 
                "a:active { color: #FF0040; text-decoration: underline; }\n"
79
 
                "td.title { text-align: center; padding-bottom: 10px; font-size: 20pt; font-weight: bold; }\n"
80
 
                "td.ruler { background-color: #6688D4; }\n"
81
 
                "td.headerItem { text-align: right; padding-right: 6px; font-family: sans-serif; font-weight: bold; }\n"
82
 
                "td.headerValue { text-align: left; color: #284FA8; font-family: sans-serif; font-weight: bold; }\n"
83
 
                "td.versionInfo { text-align: center; padding-top:  2px; }\n"
84
 
                "pre.source { font-family: monospace; white-space: pre; }\n"
85
 
                "span.lineNum { background-color: #EFE383; }\n"
86
 
                "span.lineCov { background-color: #CAD7FE; }\n"
87
 
                "span.linePartCov { background-color: #FFEA20; }\n"
88
 
                "span.lineNoCov { background-color: #FF6230; }\n"
89
 
                "td.tableHead { text-align: center; color: #FFFFFF; background-color: #6688D4; font-family: sans-serif; font-size: 120%; font-weight: bold; }\n"
90
 
                "td.coverFile { text-align: left; padding-left: 10px; padding-right: 20px; color: #284FA8; background-color: #DAE7FE; font-family: monospace; }\n"
91
 
                "td.coverBar { padding-left: 10px; padding-right: 10px; background-color: #DAE7FE; }\n"
92
 
                "td.coverBarOutline { background-color: #000000; }\n"
93
 
                "td.coverPerHi { text-align: right; padding-left: 10px; padding-right: 10px; background-color: #A7FC9D; font-weight: bold; }\n"
94
 
                "td.coverNumHi { text-align: right; padding-left: 10px; padding-right: 10px; background-color: #A7FC9D; }\n"
95
 
                "td.coverPerMed { text-align: right; padding-left: 10px; padding-right: 10px; background-color: #FFEA20; font-weight: bold; }\n"
96
 
                "td.coverNumMed { text-align: right; padding-left: 10px; padding-right: 10px; background-color: #FFEA20; }\n"
97
 
                "td.coverPerLo { text-align: right; padding-left: 10px; padding-right: 10px; background-color: #FF0000; font-weight: bold; }\n"
98
 
                "td.coverNumLo { text-align: right; padding-left: 10px; padding-right: 10px; background-color: #FF0000; }\n";
99
 
 
100
 
static const char **allocated_objs;
101
 
static int n_allocs;
102
 
static int cur_allocation = 0;
103
 
static void cleanup_allocations(void)
104
 
{
105
 
        int i;
106
 
 
107
 
        for (i = 0; i < n_allocs; i++) {
108
 
                free((void*)allocated_objs[i]);
109
 
                allocated_objs[i] = NULL;
110
 
        }
111
 
        cur_allocation = 0;
112
 
}
113
 
 
114
 
void *add_allocation(void *x)
115
 
{
116
 
        if (cur_allocation >= n_allocs) {
117
 
                int last = n_allocs;
118
 
                int i;
119
 
 
120
 
                n_allocs = n_allocs + 512;
121
 
                allocated_objs = xrealloc(allocated_objs,
122
 
                                n_allocs * sizeof(const char *));
123
 
                for (i = last; i < n_allocs; i++)
124
 
                        allocated_objs[i] = NULL;
125
 
        }
126
 
 
127
 
        allocated_objs[cur_allocation] = x;
128
 
        cur_allocation++;
129
 
 
130
 
        return x;
131
 
}
132
 
 
133
 
static void write_pngs(const char *dir)
134
 
{
135
 
        xwrite_file(dir, "ruby.png", icon_ruby, sizeof(icon_ruby));
136
 
        xwrite_file(dir, "amber.png", icon_amber, sizeof(icon_amber));
137
 
        xwrite_file(dir, "emerald.png", icon_emerald, sizeof(icon_emerald));
138
 
        xwrite_file(dir, "snow.png", icon_snow, sizeof(icon_snow));
139
 
        xwrite_file(dir, "glass.png", icon_glass, sizeof(icon_glass));
140
 
}
141
 
 
142
 
static const char *construct_bar(double percent)
143
 
{
144
 
   const char* color = "ruby.png";
145
 
   char buf[255];
146
 
   int width = (int)(percent+0.5);
147
 
 
148
 
   if (percent >= 50)
149
 
           color = "emerald.png";
150
 
   else if (percent>=15)
151
 
           color = "amber.png";
152
 
   else if (percent <= 1)
153
 
           color = "snow.png";
154
 
 
155
 
   xsnprintf(buf, sizeof(buf),
156
 
                   "<img src=\"%s\" width=\"%d\" height=\"10\" alt=\"%.1f%%\"/><img src=\"snow.png\" width=\"%d\" height=\"10\" alt=\"%.1f%%\"/>",
157
 
                   color, width, percent, 100 - width, percent);
158
 
 
159
 
   return add_allocation(xstrdup(buf));
160
 
}
161
 
 
162
 
static void write_css(const char *dir)
163
 
{
164
 
        xwrite_file(dir, "/bcov.css", css_text, sizeof(css_text));
165
 
}
166
 
 
167
 
static char *escape_helper(char *dst, char *what)
168
 
{
169
 
        int len = strlen(what);
170
 
 
171
 
        strcpy(dst, what);
172
 
 
173
 
        return dst + len;
174
 
}
175
 
 
176
 
static const char *outfile_name_from_kc_file(struct kc_file *kc_file)
177
 
{
178
 
        char *p = strrchr(kc_file->filename, '/');
179
 
        char *out;
180
 
 
181
 
        if (!p)
182
 
                return NULL;
183
 
 
184
 
        out = xmalloc(strlen(p) + 8);
185
 
        xsnprintf(out, strlen(p) + 8, "%s.html", p + 1);
186
 
        add_allocation(out);
187
 
 
188
 
        return out;
189
 
}
190
 
 
191
 
static const char *tmp_outfile_name_from_kc_file(struct kc_file *kc_file)
192
 
{
193
 
        char *p = strrchr(kc_file->filename, '/');
194
 
        char *out;
195
 
 
196
 
        if (!p)
197
 
                return NULL;
198
 
 
199
 
        out = xmalloc(strlen(p) + 16);
200
 
        xsnprintf(out, strlen(p) + 16, "%s.html.tmp", p + 1);
201
 
        add_allocation(out);
202
 
 
203
 
        return out;
204
 
}
205
 
 
206
 
 
207
 
static const char *dir_concat_report(const char *dir, const char *filename)
208
 
{
209
 
        return add_allocation((void*)dir_concat(dir, filename));
210
 
}
211
 
 
212
 
static const char *escape_html(const char *s)
213
 
{
214
 
        char buf[4096];
215
 
        char *dst = buf;
216
 
        size_t len = strlen(s);
217
 
        int i;
218
 
 
219
 
        memset(buf, 0, sizeof(buf));
220
 
        for (i = 0; i < len; i++) {
221
 
                char c = s[i];
222
 
 
223
 
                if ((c & 0xff) > 127) {
224
 
                        char tmp_val[16];
225
 
 
226
 
                        xsnprintf(tmp_val, sizeof(tmp_val), "&#%x;", c & 0xff);
227
 
                        dst = escape_helper(dst, tmp_val);
228
 
                } else {
229
 
                        switch (c) {
230
 
                        case '<':
231
 
                                dst = escape_helper(dst, "&lt;");
232
 
                                break;
233
 
                        case '>':
234
 
                                dst = escape_helper(dst, "&gt;");
235
 
                                break;
236
 
                        case '&':
237
 
                                dst = escape_helper(dst, "&amp;");
238
 
                                break;
239
 
                        case '\"':
240
 
                                dst = escape_helper(dst, "&quot;");
241
 
                                break;
242
 
                        case '\n': case '\r':
243
 
                                dst = escape_helper(dst, " ");
244
 
                                break;
245
 
                        default:
246
 
                                *dst = c;
247
 
                                dst++;
248
 
                                break;
249
 
                        }
250
 
                }
251
 
        }
252
 
 
253
 
        return add_allocation(strdup(buf));
254
 
}
255
 
 
256
 
static void write_header(FILE *fp, struct kc *kc, struct kc_file *file,
257
 
                int lines, int active_lines)
258
 
{
259
 
        char date_buf[80];
260
 
        time_t t;
261
 
        struct tm *tm;
262
 
 
263
 
        t = time(NULL);
264
 
        tm = localtime(&t);
265
 
        strftime(date_buf, sizeof(date_buf), "%Y-%m-%d %H:%M:%S", tm);
266
 
        fprintf(fp,
267
 
                        "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n"
268
 
                        "<html>\n"
269
 
                        "<head>\n"
270
 
                        "  <title>Coverage - %s</title>\n"
271
 
                        "  <link rel=\"stylesheet\" type=\"text/css\" href=\"bcov.css\"/>\n"
272
 
                        "</head>\n"
273
 
                        "<body>\n"
274
 
                        "<table width=\"100%%\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n"
275
 
                        "  <tr><td class=\"title\">Coverage Report</td></tr>\n"
276
 
                        "  <tr><td class=\"ruler\"><img src=\"glass.png\" width=\"3\" height=\"3\" alt=\"\"/></td></tr>\n"
277
 
                        "  <tr>\n"
278
 
                        "    <td width=\"100%%\">\n"
279
 
                        "      <table cellpadding=\"1\" border=\"0\" width=\"100%%\">\n"
280
 
                        "        <tr>\n"
281
 
                        "          <td class=\"headerItem\" width=\"20%%\">Command:</td>\n"
282
 
                        "          <td class=\"headerValue\" width=\"80%%\" colspan=6>%s</td>\n"
283
 
                        "        </tr>\n"
284
 
                        "        <tr>\n"
285
 
                        "          <td class=\"headerItem\" width=\"20%%\">Date:</td>\n"
286
 
                        "          <td class=\"headerValue\" width=\"15%%\">%s</td>\n"
287
 
                        "          <td width=\"5%%\"></td>\n"
288
 
                        "          <td class=\"headerItem\" width=\"20%%\">Instrumented&nbsp;lines:</td>\n"
289
 
                        "          <td class=\"headerValue\" width=\"10%%\">%d</td>\n"
290
 
                        "        </tr>\n"
291
 
                        "        <tr>\n"
292
 
                        "          <td class=\"headerItem\" width=\"20%%\">Code&nbsp;covered:</td>\n"
293
 
                        "          <td class=\"headerValue\" width=\"15%%\">%.1f %%</td>\n"
294
 
                        "          <td width=\"5%%\"></td>\n"
295
 
                        "          <td class=\"headerItem\" width=\"20%%\">Executed&nbsp;lines:</td>\n"
296
 
                        "          <td class=\"headerValue\" width=\"10%%\">%d</td>\n"
297
 
                        "        </tr>\n"
298
 
                        "      </table>\n"
299
 
                        "    </td>\n"
300
 
                        "  </tr>\n"
301
 
                        "  <tr><td class=\"ruler\"><img src=\"glass.png\" width=\"3\" height=\"3\" alt=\"\"/></td></tr>\n"
302
 
                        "</table>\n",
303
 
                        escape_html(kc->module_name), /* Title */
304
 
                        escape_html(kc->module_name), /* Command */
305
 
                        date_buf,
306
 
                        lines,
307
 
                        lines == 0 ? 0 : ((float)active_lines / (float)lines) * 100,
308
 
                        active_lines
309
 
        );
310
 
}
311
 
 
312
 
static void write_footer(FILE *fp)
313
 
{
314
 
        fprintf(fp,
315
 
                        "<table width=\"100%%\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n"
316
 
                        "  <tr><td class=\"ruler\"><img src=\"glass.png\" width=\"3\" height=\"3\" alt=\"\"/></td></tr>\n"
317
 
                        "  <tr><td class=\"versionInfo\">Generated by: <a href=\"http://simonkagstrom.github.com/kcov/index.html\">Kcov</a> (based on <a href=\"http://bcov.sourceforge.net\">bcov</a>)</td></tr>\n"
318
 
                        "</table>\n"
319
 
                        "<br/>\n"
320
 
                        "</body>\n"
321
 
                        "</html>\n");
322
 
}
323
 
 
324
 
static int write_file_report(const char *dir, struct kc *kc, struct kc_file *kc_file)
325
 
{
326
 
        const char *tmp_outfile_name = tmp_outfile_name_from_kc_file(kc_file);
327
 
        const char *outfile_name = outfile_name_from_kc_file(kc_file);
328
 
        FILE *out_fp;
329
 
        FILE *fp;
330
 
        int lineno = 1;
331
 
        int total_hits = 0;
332
 
 
333
 
        if (!tmp_outfile_name)
334
 
                return -1;
335
 
 
336
 
        fp = fopen(kc_file->filename, "r");
337
 
        if (!fp)
338
 
                return -1;
339
 
 
340
 
        out_fp = fopen(dir_concat_report(dir, tmp_outfile_name), "w");
341
 
        if (!out_fp)
342
 
                return -1;
343
 
 
344
 
        fprintf(out_fp, "<pre class=\"source\">\n");
345
 
 
346
 
        /* Read the lines of the source file */
347
 
        while (!feof(fp)) {
348
 
                char *line = NULL;
349
 
                struct kc_line *kc_line = kc_file_lookup_line(kc_file, lineno);
350
 
                size_t sz = 0;
351
 
 
352
 
                if (getline(&line, &sz, fp) < 0) {
353
 
                        if (line)
354
 
                                free(line);
355
 
                        break;
356
 
                }
357
 
 
358
 
                fprintf(out_fp,
359
 
                                "<span class=\"lineNum\">%7d </span>",
360
 
                                lineno);
361
 
 
362
 
                if (kc_line) {
363
 
                        const char *line_class = "lineNoCov";
364
 
                        int hits = 0;
365
 
                        int i;
366
 
 
367
 
                        /* Count hits */
368
 
                        for (i = 0; i < kc_line->n_addrs; i++) {
369
 
                                struct kc_addr *addr = kc_line->addrs[i];
370
 
 
371
 
                                hits += addr->hits;
372
 
                        }
373
 
                        /* Full, partial or no coverage? */
374
 
                        if (hits >= kc_line->possible_hits)
375
 
                                line_class = "lineCov";
376
 
                        else if (hits != 0)
377
 
                                line_class = "linePartCov";
378
 
                        fprintf(out_fp,
379
 
                                        "<span class=\"%s\"> %4u / %-4u  : ",
380
 
                                        line_class, hits, kc_line->possible_hits);
381
 
                        if (hits)
382
 
                                total_hits++;
383
 
                }
384
 
                else
385
 
                        fprintf(out_fp, "              : ");
386
 
 
387
 
                fprintf(out_fp, "%s</span>\n", escape_html(line));
388
 
 
389
 
                free(line);
390
 
                lineno++;
391
 
        }
392
 
        fprintf(out_fp, "</pre>\n");
393
 
 
394
 
        write_footer(out_fp);
395
 
 
396
 
        fclose(fp);
397
 
        fclose(out_fp);
398
 
 
399
 
 
400
 
        fp = fopen(dir_concat_report(dir, "tmp"), "w");
401
 
        if (!fp)
402
 
                return -1;
403
 
        write_header(fp, kc, NULL, g_hash_table_size(kc_file->lines),
404
 
                        total_hits);
405
 
        fclose(fp);
406
 
 
407
 
        concat_files(dir_concat_report(dir, outfile_name),
408
 
                        dir_concat_report(dir, "tmp"),
409
 
                        dir_concat_report(dir, tmp_outfile_name));
410
 
        unlink(dir_concat_report(dir, "tmp"));
411
 
        unlink(dir_concat_report(dir, tmp_outfile_name));
412
 
 
413
 
        return 0;
414
 
}
415
 
 
416
 
 
417
 
static int kc_file_cmp(const void *pa, const void *pb)
418
 
{
419
 
        struct kc_file *a = *(struct kc_file **)pa;
420
 
        struct kc_file *b = *(struct kc_file **)pb;
421
 
 
422
 
        return strcmp(a->filename, b->filename);
423
 
}
424
 
 
425
 
static int kc_percentage_cmp(const void *pa, const void *pb)
426
 
{
427
 
        struct kc_file *a = *(struct kc_file **)pa;
428
 
        struct kc_file *b = *(struct kc_file **)pb;
429
 
 
430
 
        return (int)(a->percentage - b->percentage);
431
 
}
432
 
 
433
 
 
434
 
 
435
 
static int report_path(const char *path, struct kc *kc)
436
 
{
437
 
        const char **p = kc->only_report_paths;
438
 
        int i = 0;
439
 
 
440
 
        while (p[i])
441
 
        {
442
 
                if (strstr(path, p[i]))
443
 
                        return 1;
444
 
 
445
 
                i++;
446
 
        }
447
 
 
448
 
        return 0;
449
 
}
450
 
 
451
 
static int exclude_path(const char *path, struct kc *kc)
452
 
{
453
 
        const char **p = kc->exclude_paths;
454
 
        int i = 0;
455
 
 
456
 
        while (p[i])
457
 
        {
458
 
                if (strstr(path, p[i]))
459
 
                        return 1;
460
 
 
461
 
                i++;
462
 
        }
463
 
 
464
 
        return 0;
465
 
}
466
 
 
467
 
static int write_index(const char *dir, struct kc *kc)
468
 
{
469
 
        GHashTableIter iter;
470
 
        const char *key;
471
 
        struct kc_file *kc_file;
472
 
        struct kc_file **files;
473
 
        int total_lines = 0;
474
 
        int total_active_lines = 0;
475
 
        int n_files = 0;
476
 
        FILE *fp;
477
 
        int file_idx;
478
 
 
479
 
        fp = fopen(dir_concat_report(dir, "index.html.main"), "w");
480
 
        if (!fp)
481
 
                return -1;
482
 
 
483
 
        fprintf(fp,
484
 
                        "<center>\n"
485
 
                        "  <table width=\"80%%\" cellpadding=\"2\" cellspacing=\"1\" border=\"0\">\n"
486
 
                        "    <tr>\n"
487
 
                        "      <td width=\"50%%\"><br/></td>\n"
488
 
                        "      <td width=\"15%%\"></td>\n"
489
 
                        "      <td width=\"15%%\"></td>\n"
490
 
                        "      <td width=\"20%%\"></td>\n"
491
 
                        "    </tr>\n"
492
 
                        "    <tr>\n"
493
 
                        "      <td class=\"tableHead\">Filename</td>\n"
494
 
                        "      <td class=\"tableHead\" colspan=\"3\">Coverage</td>\n"
495
 
                        "    </tr>\n");
496
 
 
497
 
        /* Sort the files by name */
498
 
        files = add_allocation(xmalloc(g_hash_table_size(kc->files) * sizeof(struct kc_file *)));
499
 
        g_hash_table_iter_init(&iter, kc->files);
500
 
        while (g_hash_table_iter_next(&iter, (gpointer*)&key, (gpointer*)&kc_file)) {
501
 
                files[n_files] = kc_file;
502
 
                n_files++;
503
 
        }
504
 
        qsort(files, g_hash_table_size(kc->files), sizeof(struct kc_file *),
505
 
                        kc->sort_type == COVERAGE_PERCENT ? kc_percentage_cmp : kc_file_cmp);
506
 
        for (file_idx = 0; file_idx < n_files; file_idx++) {
507
 
                double percentage = 0;
508
 
                const char *percentage_text = "Lo";
509
 
                int active_lines = 0;
510
 
                GHashTableIter line_iter;
511
 
                int n_lines;
512
 
                struct kc_line *line_val;
513
 
                int line_key;
514
 
 
515
 
                kc_file = files[file_idx];
516
 
 
517
 
                if (!report_path(kc_file->filename, kc))
518
 
                        continue;
519
 
 
520
 
                if (exclude_path(kc_file->filename, kc))
521
 
                        continue;
522
 
 
523
 
                if (!file_exists(kc_file->filename))
524
 
                        continue;
525
 
 
526
 
                /* Count the percentage of hits */
527
 
                n_lines = g_hash_table_size(kc_file->lines);
528
 
                g_hash_table_iter_init(&line_iter, kc_file->lines);
529
 
                while (g_hash_table_iter_next(&line_iter,
530
 
                                (gpointer*)&line_key, (gpointer*)&line_val)) {
531
 
                        int i;
532
 
 
533
 
                        for (i = 0; i < line_val->n_addrs; i++) {
534
 
                                if (line_val->addrs[i]->hits > 0) {
535
 
                                        /* Only care about full lines */
536
 
                                        active_lines++;
537
 
                                        break;
538
 
                                }
539
 
                        }
540
 
                }
541
 
 
542
 
                if (n_lines != 0)
543
 
                        percentage = ((double)active_lines / (double)n_lines) * 100;
544
 
                kc_file->percentage = percentage;
545
 
 
546
 
                total_lines += n_lines;
547
 
                total_active_lines += active_lines;
548
 
 
549
 
                if (percentage > kc->low_limit && percentage < kc->high_limit)
550
 
                        percentage_text = "Med";
551
 
                else if (percentage >= kc->high_limit)
552
 
                        percentage_text = "Hi";
553
 
 
554
 
                fprintf(fp,
555
 
                                "    <tr>\n"
556
 
                                "      <td class=\"coverFile\"><a href=\"%s\">%s</a></td>\n"
557
 
                                "      <td class=\"coverBar\" align=\"center\">\n"
558
 
                                "        <table border=\"0\" cellspacing=\"0\" cellpadding=\"1\"><tr><td class=\"coverBarOutline\">%s</td></tr></table>\n"
559
 
                                "      </td>\n"
560
 
                                "      <td class=\"coverPer%s\">%.1f&nbsp;%%</td>\n"
561
 
                                "      <td class=\"coverNum%s\">%d&nbsp;/&nbsp;%d&nbsp;lines</td>\n"
562
 
                                "    </tr>\n",
563
 
                                outfile_name_from_kc_file(kc_file),
564
 
                                kc_file->filename,
565
 
                                construct_bar(percentage),
566
 
                                percentage_text, percentage,
567
 
                                percentage_text, active_lines, n_lines);
568
 
        }
569
 
        fprintf(fp,
570
 
                        "  </table>\n"
571
 
                        "</center>\n"
572
 
                        "<br/>\n");
573
 
 
574
 
        write_footer(fp);
575
 
        fclose(fp);
576
 
 
577
 
        fp = fopen(dir_concat_report(dir, "index.html.hdr"), "w");
578
 
        if (!fp)
579
 
                return -1;
580
 
        write_header(fp, kc, NULL, total_lines, total_active_lines);
581
 
        fclose(fp);
582
 
 
583
 
        concat_files(dir_concat_report(dir, "index.html"),
584
 
                        dir_concat_report(dir, "index.html.hdr"),
585
 
                        dir_concat_report(dir, "index.html.main"));
586
 
        unlink(dir_concat_report(dir, "index.html.hdr"));
587
 
        unlink(dir_concat_report(dir, "index.html.main"));
588
 
 
589
 
        return 0;
590
 
}
591
 
 
592
 
static void write_report(const char *dir, struct kc *kc)
593
 
{
594
 
        GHashTableIter iter;
595
 
        const char *key;
596
 
        struct kc_file *val;
597
 
 
598
 
        /* Write an index first */
599
 
        write_index(dir, kc);
600
 
 
601
 
        g_hash_table_iter_init(&iter, kc->files);
602
 
        while (g_hash_table_iter_next(&iter, (gpointer*)&key, (gpointer*)&val)) {
603
 
                if (file_exists(val->filename))
604
 
                        write_file_report(dir, kc, val);
605
 
        }
606
 
 
607
 
        cleanup_allocations();
608
 
}
609
 
 
610
 
 
611
 
 
612
 
static pthread_t thread;
613
 
static const char *g_dir;
614
 
static struct kc *g_kc;
615
 
static int should_exit;
616
 
 
617
 
static void *report_thread(void *priv)
618
 
{
619
 
        int i = 0;
620
 
 
621
 
        mkdir(g_dir, 0755);
622
 
 
623
 
        write_css(g_dir);
624
 
        write_pngs(g_dir);
625
 
 
626
 
        while (1) {
627
 
                if (i % 5 == 0)
628
 
                        write_report(g_dir, g_kc);
629
 
                if (should_exit)
630
 
                        break;
631
 
                sleep(1);
632
 
                i++;
633
 
                sync();
634
 
        }
635
 
        /* Do this twice to collect percentages from last round */
636
 
        write_report(g_dir, g_kc);
637
 
        write_report(g_dir, g_kc);
638
 
 
639
 
        kc_write_db(g_kc);
640
 
 
641
 
        pthread_exit(NULL);
642
 
}
643
 
 
644
 
void stop_report_thread(void)
645
 
{
646
 
        should_exit = 1;
647
 
        pthread_join(thread, NULL);
648
 
        cleanup_allocations();
649
 
 
650
 
        if (g_kc->type == PTRACE_PID || g_kc->type == PTRACE_FILE)
651
 
                ptrace_detach(g_kc);
652
 
}
653
 
 
654
 
 
655
 
void run_report_thread(const char *dir, struct kc *kc)
656
 
{
657
 
        int ret;
658
 
 
659
 
        g_dir = dir;
660
 
        g_kc = kc;
661
 
        ret = pthread_create(&thread, NULL, report_thread, NULL);
662
 
        panic_if (ret < 0, "Can't create thread");
663
 
}