3abe9331 |
1 | /////////////////////////////////////////////////////////////////////////////// |
2 | // Copyright (c) 2000-2015 Ericsson Telecom AB |
3 | // All rights reserved. This program and the accompanying materials |
4 | // are made available under the terms of the Eclipse Public License v1.0 |
5 | // which accompanies this distribution, and is available at |
6 | // http://www.eclipse.org/legal/epl-v10.html |
7 | /////////////////////////////////////////////////////////////////////////////// |
8 | |
9 | #include <stdlib.h> |
10 | #include <stdio.h> |
11 | #include <stdarg.h> |
12 | #include <getopt.h> |
13 | #include <string.h> |
14 | #include "ProfilerTools.hh" |
15 | #include "version_internal.h" |
16 | |
17 | #ifdef LICENSE |
18 | #include "license.h" |
19 | #endif |
20 | |
21 | /** the name of the executable */ |
22 | const char* program_name; |
23 | |
24 | /** error flag, set automatically when an error occurs */ |
25 | boolean erroneous = FALSE; |
26 | |
27 | /** prints usage information */ |
28 | void usage() |
29 | { |
30 | fprintf(stderr, |
31 | "usage: %s [-pc] [-o file] [-s file] [-f filter] db_file1 [db_file2 ...]\n" |
32 | " or %s -v\n\n" |
33 | "options:\n" |
34 | " -p: discard profiling data\n" |
35 | " -c: discard code coverage data\n" |
36 | " -o file: write merged database into file\n" |
37 | " -s file: generate statistics file from merged database\n" |
38 | " -f filter: filter the generated statistics file (the filter is a hexadecimal number)\n" |
39 | " -v: show version\n", program_name, program_name); |
40 | } |
41 | |
42 | /** displays an error message and sets the erroneous flag */ |
43 | void error(const char *fmt, ...) |
44 | { |
45 | fprintf(stderr, "%s: error: ", program_name); |
46 | va_list parameters; |
47 | va_start(parameters, fmt); |
48 | vfprintf(stderr, fmt, parameters); |
49 | va_end(parameters); |
50 | putc('\n', stderr); |
51 | fflush(stderr); |
52 | erroneous = TRUE; |
53 | } |
54 | |
55 | /** checks if the specified file exists */ |
56 | boolean file_exists(const char* p_filename) |
57 | { |
58 | FILE* file = fopen(p_filename, "r"); |
59 | if (NULL != file) { |
60 | fclose(file); |
61 | return TRUE; |
62 | } |
63 | return FALSE; |
64 | } |
65 | |
66 | |
67 | int main(int argc, char* argv[]) |
68 | { |
69 | // store the executable name |
70 | program_name = argv[0]; |
71 | |
72 | // initialize variables for command line options |
73 | const char* out_file = NULL; |
74 | const char* stats_file = NULL; |
75 | boolean disable_profiler = FALSE; |
76 | boolean disable_coverage = FALSE; |
77 | unsigned int stats_flags = Profiler_Tools::STATS_ALL; |
78 | boolean has_stats_flag = FALSE; |
79 | boolean print_version = FALSE; |
80 | |
81 | if (1 == argc) { |
82 | // no command line options |
83 | usage(); |
84 | return EXIT_FAILURE; |
85 | } |
86 | |
87 | for (;;) { |
88 | // read the next command line option (and its argument) |
89 | int c = getopt(argc, argv, "o:s:pcf:v"); |
90 | if (-1 == c) { |
91 | break; |
92 | } |
93 | switch (c) { |
94 | case 'o': // output database file |
95 | out_file = optarg; |
96 | break; |
97 | case 's': // statistics file |
98 | stats_file = optarg; |
99 | break; |
100 | case 'p': |
101 | disable_profiler = TRUE; |
102 | break; |
103 | case 'c': |
104 | disable_coverage = TRUE; |
105 | break; |
106 | case 'f': { // statistics filter (hex number) |
107 | has_stats_flag = TRUE; |
108 | size_t len = strlen(optarg); |
109 | size_t start = 0; |
110 | if (len > STATS_MAX_HEX_DIGITS) { |
111 | // the rest of the bits are not needed, and stats_flags might run out of bits |
112 | start = len - STATS_MAX_HEX_DIGITS; |
113 | } |
114 | stats_flags = 0; |
115 | // extract the hex digits from the argument |
116 | for (size_t i = start; i < len; ++i) { |
117 | stats_flags *= 16; |
118 | if ('0' <= optarg[i] && '9' >= optarg[i]) { |
119 | stats_flags += optarg[i] - '0'; |
120 | } |
121 | else if ('a' <= optarg[i] && 'f' >= optarg[i]) { |
122 | stats_flags += optarg[i] - 'a' + 10; |
123 | } |
124 | else if ('A' <= optarg[i] && 'F' >= optarg[i]) { |
125 | stats_flags += optarg[i] - 'A' + 10; |
126 | } |
127 | else { |
128 | error("Invalid statistics filter. Expected hexadecimal value."); |
129 | return EXIT_FAILURE; |
130 | } |
131 | } |
132 | break; } |
133 | case 'v': |
134 | print_version = TRUE; |
135 | break; |
136 | default: |
137 | usage(); |
138 | return EXIT_FAILURE; |
139 | } |
140 | } |
141 | |
142 | if (print_version) { |
143 | // no other flags are allowed when printing version info |
144 | if (disable_profiler || disable_coverage || has_stats_flag || |
145 | NULL != out_file || NULL != stats_file) { |
146 | usage(); |
147 | return EXIT_FAILURE; |
148 | } |
149 | else { |
150 | fputs("Profiler and Code Coverage Merge Tool for the TTCN-3 Test Executor\n" |
151 | "Product number: " PRODUCT_NUMBER "\n" |
152 | "Build date: " __DATE__ " " __TIME__ "\n" |
153 | "Compiled with: " C_COMPILER_VERSION "\n\n" |
154 | COPYRIGHT_STRING "\n\n", stderr); |
155 | #ifdef LICENSE |
156 | print_license_info(); |
157 | #endif |
158 | return EXIT_SUCCESS; |
159 | } |
160 | } |
161 | |
162 | if (optind == argc) { |
163 | error("No input files specified."); |
164 | usage(); |
165 | return EXIT_FAILURE; |
166 | } |
167 | |
168 | if (disable_profiler && disable_coverage) { |
169 | error("Both profiling and code coverage data are discarded, nothing to do."); |
170 | return EXIT_FAILURE; |
171 | } |
172 | |
173 | if (NULL == out_file && NULL == stats_file) { |
174 | error("No output files specified (either the output database file or the " |
175 | "statistics file must be set)."); |
176 | usage(); |
177 | return EXIT_FAILURE; |
178 | } |
179 | |
180 | if (has_stats_flag && NULL == stats_file) { |
181 | fprintf(stderr, "Notify: No statistics file specified, the statistics filter " |
182 | "will be ignored."); |
183 | } |
184 | |
185 | // create the local database |
186 | Profiler_Tools::profiler_db_t profiler_db; |
187 | |
188 | for (int i = optind; i < argc; i++) { |
189 | // import each input file's contents into the local database |
190 | fprintf(stderr, "Notify: Importing database file '%s'...\n", argv[i]); |
191 | Profiler_Tools::import_data(profiler_db, argv[i], FALSE, error); |
192 | if (erroneous) { |
193 | // an import failed -> exit |
194 | return EXIT_FAILURE; |
195 | } |
196 | } |
197 | |
198 | boolean out_file_success = TRUE; |
199 | if (NULL != out_file) { |
200 | // print the local database into the output file |
201 | boolean update = file_exists(out_file); |
202 | Profiler_Tools::export_data(profiler_db, out_file, disable_profiler, |
203 | disable_coverage, error); |
204 | out_file_success = !erroneous; |
205 | if (out_file_success) { |
206 | fprintf(stderr, "Notify: Database file '%s' was %s.\n", out_file, |
207 | update ? "updated" : "generated"); |
208 | } |
209 | } |
210 | |
211 | boolean stats_file_success = TRUE; |
212 | if (NULL != stats_file) { |
213 | // reset the error flag, in case export_data failed |
214 | erroneous = FALSE; |
215 | // print the statistics into the designated file |
216 | boolean update = file_exists(stats_file); |
217 | Profiler_Tools::print_stats(profiler_db, stats_file, disable_profiler, |
218 | disable_coverage, stats_flags, error); |
219 | stats_file_success = !erroneous; |
220 | if (stats_file_success) { |
221 | fprintf(stderr, "Notify: Statistics file '%s' was %s.\n", stats_file, |
222 | update ? "updated" : "generated"); |
223 | } |
224 | } |
225 | |
226 | // return an error code if printing either output file failed |
227 | return (out_file_success && stats_file_success) ? EXIT_SUCCESS : EXIT_FAILURE; |
228 | } |
229 | |
230 | // this is needed by version.h |
231 | reffer::reffer(const char*) {} |