blob: 5eae7986be3acb5c9c39d9da2871a9777feb36da [file] [log] [blame]
Lev Walkinf15320b2004-06-03 03:38:44 +00001#undef NDEBUG
Lev Walkin4efbfb72005-02-25 14:20:30 +00002#include "asn1fix_internal.h"
3
Lev Walkin93659562010-11-20 09:47:13 -08004#ifdef _WIN32
Lev Walkin4efbfb72005-02-25 14:20:30 +00005#include <io.h>
6#include <direct.h>
7#define chdir _chdir
8#else
Lev Walkinf15320b2004-06-03 03:38:44 +00009#include <dirent.h>
Lev Walkinf15320b2004-06-03 03:38:44 +000010#include <sysexits.h>
Lev Walkin4efbfb72005-02-25 14:20:30 +000011#endif
12#include <errno.h>
Lev Walkinc0e03b92017-08-22 01:48:23 -070013#include <libgen.h>
Lev Walkinf15320b2004-06-03 03:38:44 +000014
15#include "asn1fix.h"
Lev Walkinc0e03b92017-08-22 01:48:23 -070016#include "asn1_buffer.h"
17#include "asn1_namespace.h"
Lev Walkinf15320b2004-06-03 03:38:44 +000018
Lev Walkine0d321a2014-09-11 01:28:57 -070019#ifndef TOP_SRCDIR
20#define TOP_SRCDIR_S ".."
21#else
22#define STRINGIFY_MACRO2(x) #x
23#define STRINGIFY_MACRO(x) STRINGIFY_MACRO2(x)
24#define TOP_SRCDIR_S STRINGIFY_MACRO(TOP_SRCDIR)
25#endif
26
Lev Walkin55982b82016-03-14 03:56:16 -070027static int check(const char *fname,
Lev Walkinf15320b2004-06-03 03:38:44 +000028 enum asn1p_flags parser_flags,
29 enum asn1f_flags fixer_flags);
30static int post_fix_check(asn1p_t *asn);
31static int post_fix_check_element(asn1p_module_t *mod, asn1p_expr_t *expr);
32
33int
34main(int ac, char **av) {
Lev Walkin93659562010-11-20 09:47:13 -080035#ifdef _WIN32
Lev Walkin4efbfb72005-02-25 14:20:30 +000036 intptr_t dir;
37 struct _finddata_t c_file;
38#else
Lev Walkinf15320b2004-06-03 03:38:44 +000039 struct dirent *dp;
40 DIR *dir;
Lev Walkin4efbfb72005-02-25 14:20:30 +000041#endif
Lev Walkinf15320b2004-06-03 03:38:44 +000042 int failed = 0;
43 int completed = 0;
44 enum asn1p_flags parser_flags = A1P_NOFLAGS;
45 enum asn1f_flags fixer_flags = A1F_NOFLAGS;
Lev Walkin4efbfb72005-02-25 14:20:30 +000046 const char *filename;
Lev Walkin07721d52005-02-25 14:35:02 +000047 size_t len;
Lev Walkinf15320b2004-06-03 03:38:44 +000048 int ret;
49
50 /*
51 * Just in case when one decides that some flags better be
52 * enabled during `ASN1_FIXER_FLAGS=1 make check` or some
53 * similar usage.
54 */
55 if(getenv("ASN1_PARSER_FLAGS"))
56 parser_flags = atoi(getenv("ASN1_PARSER_FLAGS"));
57 if(getenv("ASN1_FIXER_FLAGS"))
58 fixer_flags = atoi(getenv("ASN1_FIXER_FLAGS"));
59
60 /*
61 * Go into a directory with tests.
62 */
63 if(ac <= 1) {
Lev Walkinc0e03b92017-08-22 01:48:23 -070064 abuf *asn1_tests_dirname = abuf_new();
65 const char *top_srcdir = getenv("top_srcdir");
66 if(!top_srcdir) top_srcdir = TOP_SRCDIR_S;
67
68 abuf_printf(asn1_tests_dirname, "%s/tests/tests-asn1c-compiler",
69 top_srcdir);
70
71 fprintf(stderr, "Testing in %s...\n", top_srcdir);
72 ret = chdir(asn1_tests_dirname->buffer);
Lev Walkin08068b22016-01-24 22:49:06 -080073 if(ret == -1)
Lev Walkinc0e03b92017-08-22 01:48:23 -070074 fprintf(stderr, "%s: %s\n", asn1_tests_dirname->buffer,
75 strerror(errno));
Lev Walkin08068b22016-01-24 22:49:06 -080076 assert(ret == 0);
Lev Walkin9e66d162016-03-14 03:36:35 -070077 /* For some reasons, tests could be hidden under extra tests dir. */
Lev Walkin93659562010-11-20 09:47:13 -080078#ifdef _WIN32
Lev Walkin4efbfb72005-02-25 14:20:30 +000079 dir = _findfirst("*.asn1", &c_file);
80 assert(dir != -1L);
81#else
Lev Walkinf15320b2004-06-03 03:38:44 +000082 dir = opendir(".");
83 assert(dir);
Lev Walkin93659562010-11-20 09:47:13 -080084#endif /* _WIN32 */
Lev Walkinf15320b2004-06-03 03:38:44 +000085 } else {
86 dir = 0;
87 }
88
89 /*
90 * Scan every *.asn1 file and try to parse and fix it.
91 */
92 if(dir) {
Lev Walkin93659562010-11-20 09:47:13 -080093#ifdef _WIN32
Lev Walkin4efbfb72005-02-25 14:20:30 +000094 do {
95 filename = c_file.name;
96#else
Lev Walkinf15320b2004-06-03 03:38:44 +000097 while((dp = readdir(dir))) {
Lev Walkin4efbfb72005-02-25 14:20:30 +000098 filename = dp->d_name;
Lev Walkin93659562010-11-20 09:47:13 -080099#endif /* _WIN32 */
Lev Walkin07721d52005-02-25 14:35:02 +0000100 len = strlen(filename);
Lev Walkin4b553412005-08-14 14:45:44 +0000101 if(len <= 5 || strcmp(filename + len - 5, ".asn1"))
102 continue;
Lev Walkin55982b82016-03-14 03:56:16 -0700103 ret = check(filename, parser_flags, fixer_flags);
Lev Walkin4b553412005-08-14 14:45:44 +0000104 if(ret) {
105 fprintf(stderr, "FAILED: %s\n",
106 filename);
107 failed++;
Lev Walkinf15320b2004-06-03 03:38:44 +0000108 }
Lev Walkin4b553412005-08-14 14:45:44 +0000109 completed++;
Lev Walkin93659562010-11-20 09:47:13 -0800110#ifdef _WIN32
Lev Walkin4efbfb72005-02-25 14:20:30 +0000111 } while(_findnext(dir, &c_file) == 0);
112 _findclose(dir);
113#else
Lev Walkinf15320b2004-06-03 03:38:44 +0000114 }
115 closedir(dir);
Lev Walkin93659562010-11-20 09:47:13 -0800116#endif /* _WIN32 */
Lev Walkin4efbfb72005-02-25 14:20:30 +0000117
Lev Walkinf15320b2004-06-03 03:38:44 +0000118
119 fprintf(stderr,
120 "Tests COMPLETED: %d\n"
121 "Tests FAILED: %d\n"
122 ,
123 completed, failed
124 );
125 } else {
126 int i;
127 for(i = 1; i < ac; i++) {
Lev Walkin55982b82016-03-14 03:56:16 -0700128 ret = check(av[i], parser_flags, fixer_flags);
Lev Walkinf15320b2004-06-03 03:38:44 +0000129 if(ret) {
130 fprintf(stderr, "FAILED: %s\n", av[i]);
131 failed++;
132 }
133 completed++;
134 }
135 }
136
137 if(completed == 0) {
138 fprintf(stderr, "No tests defined?!\n");
139 exit(EX_NOINPUT);
140 }
141
142 if(failed)
143 exit(EX_DATAERR);
144 return 0;
145}
146
147static int
Lev Walkin55982b82016-03-14 03:56:16 -0700148check(const char *fname,
Lev Walkinf15320b2004-06-03 03:38:44 +0000149 enum asn1p_flags parser_flags,
150 enum asn1f_flags fixer_flags) {
151 asn1p_t *asn;
152 int expected_parseable; /* Is it expected to be parseable? */
153 int expected_fix_code; /* What code a fixer must return */
154 int r_value = 0;
155
156 /*
157 * Figure out how the processing should go by inferring
158 * expectations from the file name.
159 */
160 if(strstr(fname, "-OK.")) {
161 expected_parseable = 1;
162 expected_fix_code = 0;
163 } else if(strstr(fname, "-NP.")) {
164 expected_parseable = 0;
165 expected_fix_code = 123; /* Does not matter */
166 } else if(strstr(fname, "-SE.")) {
167 expected_parseable = 1;
168 expected_fix_code = -1; /* Semantically incorrect */
169 } else if(strstr(fname, "-SW.")) {
170 expected_parseable = 1;
171 expected_fix_code = 1; /* Semantically suspicious */
172 } else {
173 fprintf(stderr, "%s: Invalid file name format\n", fname);
174 return -1;
175 }
176
Lev Walkin4b553412005-08-14 14:45:44 +0000177 /* Flag modifiers */
178 if(strstr(fname, "-blessSize-"))
179 fixer_flags |= A1F_EXTENDED_SizeConstraint;
180
Lev Walkinf15320b2004-06-03 03:38:44 +0000181 fprintf(stderr, "[=> %s]\n", fname);
182
183 /*
184 * Perform low-level parsing.
185 */
186 if(!expected_parseable)
187 fprintf(stderr, "Expecting error...\n");
188 asn = asn1p_parse_file(fname, parser_flags);
189 if(asn == NULL) {
190 if(expected_parseable) {
191 fprintf(stderr, "Cannot parse file \"%s\"\n", fname);
192 r_value = -1;
193 } else {
194 fprintf(stderr,
195 "Previous error is EXPECTED, no worry\n");
196 }
197 } else if(!expected_parseable) {
198 fprintf(stderr,
199 "The file \"%s\" is not expected to be parseable, "
200 "yet parsing was successfull!\n", fname);
201 r_value = -1;
202 }
Lev Walkin6b3ff542006-03-06 14:51:00 +0000203 if(!asn) return r_value;
204
205 if(r_value == 0) {
Lev Walkinc0e03b92017-08-22 01:48:23 -0700206 char *fname_copy = strdup(fname);
207 char *test_dir = dirname(fname_copy);
208 abuf *skeletons_dirname = abuf_new();
Lev Walkin6b3ff542006-03-06 14:51:00 +0000209 asn1p_t *std_asn;
Lev Walkinc0e03b92017-08-22 01:48:23 -0700210
211 abuf_printf(skeletons_dirname,
212 "%s/../../skeletons/standard-modules/"
213 "ASN1C-UsefulInformationObjectClasses.asn1",
214 test_dir);
215 free(fname_copy);
216
217 std_asn = asn1p_parse_file(skeletons_dirname->buffer, A1P_NOFLAGS);
218 if(std_asn) {
Lev Walkin6b3ff542006-03-06 14:51:00 +0000219 asn1p_module_t *mod;
Lev Walkin9c2285a2006-03-09 08:49:26 +0000220 while((mod = TQ_REMOVE(&(std_asn->modules), mod_next))) {
221 mod->_tags |= MT_STANDARD_MODULE;
Lev Walkin6b3ff542006-03-06 14:51:00 +0000222 TQ_ADD(&(asn->modules), mod, mod_next);
Lev Walkin9c2285a2006-03-09 08:49:26 +0000223 }
Lev Walkin223000a2006-09-13 00:21:58 +0000224 asn1p_delete(std_asn);
Lev Walkinc0e03b92017-08-22 01:48:23 -0700225
226 /* Allow referencing imported modules. */
227 asn1f_use_standard_namespaces(asn);
228 } else {
229 fprintf(stderr, "%s: %s\n", skeletons_dirname->buffer,
230 strerror(errno));
231 }
232
233 abuf_free(skeletons_dirname);
234 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000235
236 /*
237 * Perform semantical checks and fixes.
238 */
Lev Walkin6b3ff542006-03-06 14:51:00 +0000239 if(r_value == 0) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000240 int ret;
241
242 if(expected_fix_code)
243 fprintf(stderr, "Expecting some problems...\n");
244
245 ret = asn1f_process(asn, fixer_flags, 0);
246 if(ret) {
247 if(ret == expected_fix_code) {
248 fprintf(stderr,
249 "Previous error is EXPECTED, "
250 "no worry\n");
251 } else {
252 fprintf(stderr,
253 "Cannot process file \"%s\": %d\n",
254 fname, ret);
255 r_value = -1;
256 }
257 } else if(ret != expected_fix_code) {
258 fprintf(stderr,
259 "File \"%s\" is expected "
260 "to be semantically incorrect, "
261 "yet processing was successful!\n",
262 fname);
263 r_value = -1;
264 }
265 }
266
267 /*
268 * Check validity of some values, if grammar has special
269 * instructions for that.
270 */
Lev Walkin6b3ff542006-03-06 14:51:00 +0000271 if(r_value == 0) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000272 if(post_fix_check(asn))
273 r_value = -1;
274 }
275
276 /*
Lev Walkin6b3ff542006-03-06 14:51:00 +0000277 * Destroy the asn.
Lev Walkinf15320b2004-06-03 03:38:44 +0000278 */
Lev Walkin55f106a2006-09-15 16:34:12 +0000279#ifdef CLEAN_EVERYTHING
Lev Walkin223000a2006-09-13 00:21:58 +0000280 asn1p_delete(asn);
Lev Walkin55f106a2006-09-15 16:34:12 +0000281#endif
Lev Walkinf15320b2004-06-03 03:38:44 +0000282
283 return r_value;
284}
285
286
287static int
288post_fix_check(asn1p_t *asn) {
289 asn1p_module_t *mod;
290 asn1p_expr_t *expr;
291 int r_value = 0;
292
293 TQ_FOR(mod, &(asn->modules), mod_next) {
294 TQ_FOR(expr, &(mod->members), next) {
295 assert(expr->Identifier);
296 if(strncmp(expr->Identifier, "check-", 6) == 0) {
297 if(post_fix_check_element(mod, expr))
298 r_value = -1;
299 }
300 }
301 }
302
303 return r_value;
304}
305
306
307static int
308post_fix_check_element(asn1p_module_t *mod, asn1p_expr_t *check_expr) {
309 asn1p_expr_t *expr = NULL;
310 char *name;
311 asn1p_value_t *value;
312
313 if(check_expr->expr_type != ASN_BASIC_INTEGER
314 || check_expr->meta_type != AMT_VALUE) {
315 fprintf(stderr,
316 "CHECKER: Unsupported type of \"%s\" value: "
317 "%d at line %d of %s\n",
318 check_expr->Identifier,
319 check_expr->expr_type,
320 check_expr->_lineno,
321 mod->source_file_name
322 );
323 return -1;
324 }
325
326 assert(check_expr->meta_type == AMT_VALUE);
327
328 value = check_expr->value;
329 if(value == NULL || value->type != ATV_INTEGER) {
330 fprintf(stderr,
331 "CHECKER: Unsupported value type of \"%s\": "
332 "%d at line %d of %s\n",
333 check_expr->Identifier,
Lev Walkin409c44e2004-06-05 08:57:10 +0000334 value?(signed)value->type:-1,
Lev Walkinf15320b2004-06-03 03:38:44 +0000335 expr->_lineno,
336 mod->source_file_name
337 );
338 return -1;
339 }
340
341 name = check_expr->Identifier + sizeof("check-") - 1;
342
343 /*
344 * Scan in search for the original.
345 */
346 TQ_FOR(expr, &(mod->members), next) {
347 if(strcmp(expr->Identifier, name) == 0)
348 break;
349 }
350
351 if(expr == NULL) {
352 fprintf(stderr,
353 "CHECKER: Value \"%s\" requested by "
354 "\"check-%s\" at line %d of %s is not found!\n",
355 name, name, check_expr->_lineno,
356 mod->source_file_name
357 );
358 return -1;
359 }
360
361 if(0 && expr->expr_type != check_expr->expr_type) {
362 fprintf(stderr,
363 "CHECKER: Value type of \"%s\" (=%d) at line %d "
364 "does not have desired type %d as requested by "
365 "\"check-%s\" in %s\n",
366 expr->Identifier,
367 expr->expr_type,
368 expr->_lineno,
369 check_expr->expr_type,
370 name,
371 mod->source_file_name
372 );
373 return -1;
374 }
375
376 if(expr->value == NULL
377 || expr->value->type != value->type) {
378 fprintf(stderr,
379 "CHECKER: Value of \"%s\" (\"%s\", type=%d) at line %d "
380 "does not have desired type %d as requested by "
381 "\"check-%s\" in %s\n",
382 expr->Identifier,
383 asn1f_printable_value(expr->value),
384 expr->value->type,
385 expr->_lineno,
386 value->type,
387 name,
388 mod->source_file_name
389 );
390 return -1;
391 }
392
Lev Walkinf15320b2004-06-03 03:38:44 +0000393 return 0;
394}
395
396