/[jscoverage]/trunk/instrument.c
ViewVC logotype

Contents of /trunk/instrument.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 577 - (show annotations)
Thu Sep 9 22:39:11 2010 UTC (8 years, 2 months ago) by siliconforks
File MIME type: text/plain
File size: 8498 byte(s)
Improve --verbose output.

1 /*
2 instrument.c - file and directory instrumentation routines
3 Copyright (C) 2007, 2008, 2009, 2010 siliconforks.com
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include <config.h>
21
22 #include "instrument.h"
23
24 #include <assert.h>
25 #include <errno.h>
26 #include <string.h>
27
28 #include <dirent.h>
29 #include <sys/stat.h>
30 #include <sys/types.h>
31
32 #include "encoding.h"
33 #include "global.h"
34 #include "instrument-js.h"
35 #include "resource-manager.h"
36 #include "util.h"
37
38 static int g_verbose = 0;
39
40 static int string_ends_with(const char * s, const char * suffix) {
41 size_t length = strlen(s);
42 size_t suffix_length = strlen(suffix);
43 if (length < suffix_length) {
44 return 0;
45 }
46 return strcasecmp(s + (length - suffix_length), suffix) == 0;
47 }
48
49 static enum FileType get_file_type(const char * file) {
50 if (string_ends_with(file, ".js")) {
51 return FILE_TYPE_JS;
52 }
53 else if (string_ends_with(file, ".html") || string_ends_with(file, ".htm")) {
54 return FILE_TYPE_HTML;
55 }
56 else {
57 return FILE_TYPE_OTHER;
58 }
59 }
60
61 static void check_same_file(const char * file1, const char * file2) {
62 if (is_same_file(file1, file2)) {
63 fatal("source and destination are the same");
64 }
65 }
66
67 static void check_contains_file(const char * file1, const char * file2) {
68 if (contains_file(file1, file2)) {
69 fatal("%s contains %s", file1, file2);
70 }
71 }
72
73 static void instrument_file(const char * source_file, const char * destination_file, const char * id, int instrumenting) {
74 /* check if they are the same */
75 char * canonical_source_file = make_canonical_path(source_file);
76 char * canonical_destination_file = make_canonical_path(destination_file);
77 check_same_file(canonical_source_file, canonical_destination_file);
78 free(canonical_source_file);
79 free(canonical_destination_file);
80
81 if (instrumenting) {
82 enum FileType file_type = get_file_type(source_file);
83 switch (file_type) {
84 case FILE_TYPE_OTHER:
85 case FILE_TYPE_HTML:
86 if (g_verbose) {
87 printf("Copying file %s\n", id);
88 }
89 copy_file(source_file, destination_file);
90 break;
91 case FILE_TYPE_JS:
92 {
93 if (g_verbose) {
94 printf("Instrumenting file %s\n", id);
95 }
96
97 FILE * input = xfopen(source_file, "rb");
98 FILE * output = xfopen(destination_file, "wb");
99
100 Stream * input_stream = Stream_new(0);
101 Stream * output_stream = Stream_new(0);
102
103 Stream_write_file_contents(input_stream, input);
104
105 /*
106 Check if the source file looks like an instrumented JavaScript file.
107 */
108 if (input_stream->length >= JSCOVERAGE_INSTRUMENTED_HEADER_LENGTH &&
109 memcmp(input_stream->data, JSCOVERAGE_INSTRUMENTED_HEADER, JSCOVERAGE_INSTRUMENTED_HEADER_LENGTH) == 0) {
110 fatal_command_line("file %s in the source directory appears to be already instrumented", id);
111 }
112
113 size_t num_characters = input_stream->length;
114 uint16_t * characters = NULL;
115 int result = jscoverage_bytes_to_characters(jscoverage_encoding, input_stream->data, input_stream->length, &characters, &num_characters);
116 if (result == JSCOVERAGE_ERROR_ENCODING_NOT_SUPPORTED) {
117 fatal("encoding %s not supported", jscoverage_encoding);
118 }
119 else if (result == JSCOVERAGE_ERROR_INVALID_BYTE_SEQUENCE) {
120 fatal("error decoding %s in file %s", jscoverage_encoding, id);
121 }
122 jscoverage_instrument_js(id, characters, num_characters, output_stream);
123 free(characters);
124
125 if (fwrite(output_stream->data, 1, output_stream->length, output) != output_stream->length) {
126 fatal("cannot write to file: %s", destination_file);
127 }
128
129 Stream_delete(input_stream);
130 Stream_delete(output_stream);
131
132 fclose(input);
133 fclose(output);
134 }
135 break;
136 }
137 }
138 else {
139 if (g_verbose) {
140 printf("Copying file %s (on --no-instrument list)\n", id);
141 }
142
143 copy_file(source_file, destination_file);
144 }
145 }
146
147 void jscoverage_instrument(const char * source,
148 const char * destination,
149 int verbose,
150 char ** exclude,
151 int num_exclude,
152 char ** no_instrument,
153 int num_no_instrument)
154 {
155 assert(source != NULL);
156 assert(destination != NULL);
157
158 g_verbose = verbose;
159
160 /* check if they are the same */
161 check_same_file(source, destination);
162
163 /* check if source directory is an ancestor of destination directory */
164 check_contains_file(source, destination);
165
166 /* check that the source exists and is a directory */
167 struct stat buf;
168 xstat(source, &buf);
169 if (! S_ISDIR(buf.st_mode)) {
170 fatal("not a directory: %s", source);
171 }
172
173 /* if the destination directory exists, check that it is a jscoverage directory */
174 if (stat(destination, &buf) == 0) {
175 /* it exists */
176 if (! S_ISDIR(buf.st_mode)) {
177 fatal("not a directory: %s", destination);
178 }
179 if (! directory_is_empty(destination)) {
180 char * expected_file = NULL;
181 if (jscoverage_mode == JSCOVERAGE_MOZILLA) {
182 char * modules_directory = make_path(destination, "modules");
183 expected_file = make_path(modules_directory, "jscoverage.jsm");
184 free(modules_directory);
185 }
186 else {
187 expected_file = make_path(destination, "jscoverage.html");
188 }
189 if (stat(expected_file, &buf) == -1) {
190 fatal("refusing to overwrite directory: %s", destination);
191 }
192 free(expected_file);
193 }
194 }
195 else if (errno == ENOENT) {
196 xmkdir(destination);
197 }
198 else {
199 fatal("cannot stat directory: %s", destination);
200 }
201
202 /* copy the resources */
203 if (jscoverage_mode == JSCOVERAGE_MOZILLA) {
204 char * chrome_directory = make_path(destination, "chrome");
205 char * jscoverage_chrome_directory = make_path(chrome_directory, "jscoverage");
206 mkdirs(jscoverage_chrome_directory);
207 copy_resource("jscoverage.manifest", chrome_directory);
208 copy_resource("jscoverage.html", jscoverage_chrome_directory);
209 copy_resource("jscoverage.css", jscoverage_chrome_directory);
210 copy_resource("jscoverage.js", jscoverage_chrome_directory);
211 copy_resource("jscoverage-throbber.gif", jscoverage_chrome_directory);
212 copy_resource("jscoverage-highlight.css", jscoverage_chrome_directory);
213 copy_resource("jscoverage.xul", jscoverage_chrome_directory);
214 copy_resource("jscoverage-overlay.js", jscoverage_chrome_directory);
215 free(jscoverage_chrome_directory);
216 free(chrome_directory);
217
218 char * modules_directory = make_path(destination, "modules");
219 mkdirs(modules_directory);
220 copy_resource("jscoverage.jsm", modules_directory);
221 free(modules_directory);
222 }
223 else {
224 jscoverage_copy_resources(destination);
225 }
226
227 /* finally: copy the directory */
228 struct DirListEntry * list = make_recursive_dir_list(source);
229 for (struct DirListEntry * p = list; p != NULL; p = p->next) {
230 char * s = make_path(source, p->name);
231 char * d = make_path(destination, p->name);
232
233 /* check if it's on the exclude list */
234 for (int i = 0; i < num_exclude; i++) {
235 char * x = make_path(source, exclude[i]);
236 if (is_same_file(x, s) || contains_file(x, s)) {
237 free(x);
238 goto cleanup;
239 }
240 free(x);
241 }
242
243 char * dd = make_dirname(d);
244 mkdirs(dd);
245 free(dd);
246
247 int instrument_this = 1;
248
249 /* check if it's on the no-instrument list */
250 for (int i = 0; i < num_no_instrument; i++) {
251 char * ni = make_path(source, no_instrument[i]);
252 if (is_same_file(ni, s) || contains_file(ni, s)) {
253 instrument_this = 0;
254 }
255 free(ni);
256 }
257
258 instrument_file(s, d, p->name, instrument_this);
259
260 cleanup:
261 free(s);
262 free(d);
263 }
264
265 free_dir_list(list);
266 }

  ViewVC Help
Powered by ViewVC 1.1.24