NativeEnumerated.c vars NULL init and check
[com/asn1c.git] / libasn1fix / check_fixer.c
1 #undef  NDEBUG
2 #include "asn1fix_internal.h"
3
4 #ifdef  _WIN32
5 #include <io.h>
6 #include <direct.h>
7 #define chdir _chdir
8 #else
9 #include <dirent.h>
10 #include <sysexits.h>
11 #endif
12 #include <errno.h>
13 #include <libgen.h>
14
15 #include "genhash.h"
16 #include "asn1fix.h"
17 #include "asn1_buffer.h"
18 #include "asn1_namespace.h"
19
20 #ifndef TOP_SRCDIR
21 #define TOP_SRCDIR_S    ".."
22 #else
23 #define STRINGIFY_MACRO2(x)  #x
24 #define STRINGIFY_MACRO(x)  STRINGIFY_MACRO2(x)
25 #define TOP_SRCDIR_S    STRINGIFY_MACRO(TOP_SRCDIR)
26 #endif
27
28 static int check(const char *fname,
29         enum asn1p_flags parser_flags,
30         enum asn1f_flags fixer_flags);
31 static int post_fix_check(asn1p_t *asn);
32 static int post_fix_check_element(asn1p_module_t *mod, asn1p_expr_t *expr);
33
34 int
35 main(int ac, char **av) {
36 #ifdef  _WIN32
37         intptr_t dir;
38         struct _finddata_t c_file;
39 #else
40         struct dirent *dp;
41         DIR *dir;
42 #endif
43         int failed = 0;
44         int completed = 0;
45         enum asn1p_flags parser_flags = A1P_NOFLAGS;
46         enum asn1f_flags fixer_flags  = A1F_NOFLAGS;
47         const char *filename;
48         size_t len;
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) {
64         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         int ret = chdir(asn1_tests_dirname->buffer);
73         if(ret == -1)
74             fprintf(stderr, "%s: %s\n", asn1_tests_dirname->buffer,
75                     strerror(errno));
76         assert(ret == 0);
77         /* For some reasons, tests could be hidden under extra tests dir. */
78 #ifdef  _WIN32
79                 dir = _findfirst("*.asn1", &c_file);
80                 assert(dir != -1L);
81 #else
82                 dir = opendir(".");
83                 assert(dir);
84 #endif  /* _WIN32 */
85         } else {
86                 dir = 0;
87         }
88
89         /*
90          * Scan every *.asn1 file and try to parse and fix it.
91          */
92     if(dir) {
93 #ifdef  _WIN32
94         do {
95             filename = c_file.name;
96 #else
97         while((dp = readdir(dir))) {
98             filename = dp->d_name;
99 #endif  /* _WIN32 */
100             len = strlen(filename);
101             if(len <= 5 || !isdigit(filename[0])
102                || strcmp(filename + len - 5, ".asn1"))
103                 continue;
104             int ret = check(filename, parser_flags, fixer_flags);
105             if(ret) {
106                 fprintf(stderr, "FAILED: %s\n", filename);
107                 failed++;
108             }
109             completed++;
110 #ifdef  _WIN32
111         } while(_findnext(dir, &c_file) == 0);
112         _findclose(dir);
113 #else
114         }
115         closedir(dir);
116 #endif  /* _WIN32 */
117
118
119         fprintf(stderr,
120                 "Tests COMPLETED: %d\n"
121                 "Tests FAILED:    %d\n",
122                 completed, failed);
123     } else {
124         for(int i = 1; i < ac; i++) {
125             int ret = check(av[i], parser_flags, fixer_flags);
126             if(ret) {
127                 fprintf(stderr, "FAILED: %s\n", av[i]);
128                 failed++;
129             }
130             completed++;
131         }
132     }
133
134     if(completed == 0) {
135         fprintf(stderr, "No tests defined?!\n");
136         exit(EX_NOINPUT);
137     }
138
139     if(failed) {
140         exit(EX_DATAERR);
141     }
142     return 0;
143 }
144
145 static int
146 check(const char *fname,
147                 enum asn1p_flags parser_flags,
148                 enum asn1f_flags fixer_flags) {
149         asn1p_t *asn;
150         int expected_parseable;         /* Is it expected to be parseable? */
151         int expected_fix_code;          /* What code a fixer must return */
152         int r_value = 0;
153
154         /*
155          * Figure out how the processing should go by inferring
156          * expectations from the file name.
157          */
158         if(strstr(fname, "-OK.")) {
159                 expected_parseable = 1;
160                 expected_fix_code  = 0;
161         } else if(strstr(fname, "-NP.")) {
162                 expected_parseable = 0;
163                 expected_fix_code  = 123;       /* Does not matter */
164         } else if(strstr(fname, "-SE.")) {
165                 expected_parseable = 1;
166                 expected_fix_code  = -1;        /* Semantically incorrect */
167         } else if(strstr(fname, "-SW.")) {
168                 expected_parseable = 1;
169                 expected_fix_code  = 1; /* Semantically suspicious */
170         } else {
171                 fprintf(stderr, "%s: Invalid file name format\n", fname);
172                 return -1;
173         }
174
175         /* Flag modifiers */
176         if(strstr(fname, "-blessSize-"))
177                 fixer_flags |= A1F_EXTENDED_SizeConstraint;
178
179         fprintf(stderr, "[=> %s]\n", fname);
180
181         /*
182          * Perform low-level parsing.
183          */
184         if(!expected_parseable)
185                 fprintf(stderr, "Expecting error...\n");
186         asn = asn1p_parse_file(fname, parser_flags);
187         if(asn == NULL) {
188                 if(expected_parseable) {
189                         fprintf(stderr, "Cannot parse file \"%s\"\n", fname);
190                         r_value = -1;
191                 } else {
192                         fprintf(stderr,
193                                 "Previous error is EXPECTED, no worry\n");
194                 }
195         } else if(!expected_parseable) {
196                 fprintf(stderr,
197                         "The file \"%s\" is not expected to be parseable, "
198                         "yet parsing was successfull!\n", fname);
199                 r_value = -1;
200         }
201         if(!asn) return r_value;
202
203         if(r_value == 0) {
204         char *fname_copy = strdup(fname);
205         char *test_dir = dirname(fname_copy);
206         abuf *skeletons_dirname = abuf_new();
207                 asn1p_t *std_asn;
208
209         abuf_printf(skeletons_dirname,
210                     "%s/../../skeletons/standard-modules/"
211                     "ASN1C-UsefulInformationObjectClasses.asn1",
212                     test_dir);
213         free(fname_copy);
214
215         std_asn = asn1p_parse_file(skeletons_dirname->buffer, A1P_NOFLAGS);
216         if(std_asn) {
217                         asn1p_module_t *mod;
218                         while((mod = TQ_REMOVE(&(std_asn->modules), mod_next))) {
219                                 mod->_tags |= MT_STANDARD_MODULE;
220                                 TQ_ADD(&(asn->modules), mod, mod_next);
221                         }
222                         asn1p_delete(std_asn);
223
224             /* Allow referencing imported modules. */
225             asn1f_use_standard_namespaces(asn);
226                 } else {
227             fprintf(stderr, "%s: %s\n", skeletons_dirname->buffer,
228                     strerror(errno));
229         }
230
231         abuf_free(skeletons_dirname);
232     }
233
234         /*
235          * Perform semantical checks and fixes.
236          */
237         if(r_value == 0) {
238                 int ret;
239
240                 if(expected_fix_code)
241                         fprintf(stderr, "Expecting some problems...\n");
242
243                 ret = asn1f_process(asn, fixer_flags, 0);
244                 if(ret) {
245                         if(ret == expected_fix_code) {
246                                 fprintf(stderr,
247                                         "Previous error is EXPECTED, "
248                                         "no worry\n");
249                         } else {
250                                 fprintf(stderr,
251                                         "Cannot process file \"%s\": %d\n",
252                                         fname, ret);
253                                 r_value = -1;
254                 }
255                 } else if(ret != expected_fix_code) {
256                         fprintf(stderr,
257                                 "File \"%s\" is expected "
258                                 "to be semantically incorrect, "
259                                 "yet processing was successful!\n",
260                                 fname);
261                         r_value = -1;
262                 }
263         }
264
265         /*
266          * Check validity of some values, if grammar has special
267          * instructions for that.
268          */
269         if(r_value == 0) {
270                 if(post_fix_check(asn))
271                         r_value = -1;
272         }
273
274         /*
275          * Destroy the asn.
276          */
277 #ifdef  CLEAN_EVERYTHING
278         asn1p_delete(asn);
279 #endif
280
281         return r_value;
282 }
283
284
285 static int
286 post_fix_check(asn1p_t *asn) {
287         asn1p_module_t *mod;
288         asn1p_expr_t *expr;
289         int r_value = 0;
290
291         TQ_FOR(mod, &(asn->modules), mod_next) {
292                 TQ_FOR(expr, &(mod->members), next) {
293                         assert(expr->Identifier);
294                         if(strncmp(expr->Identifier, "check-", 6) == 0) {
295                                 if(post_fix_check_element(mod, expr))
296                                         r_value = -1;
297                         }
298                 }
299         }
300
301         return r_value;
302 }
303
304
305 static int
306 post_fix_check_element(asn1p_module_t *mod, asn1p_expr_t *check_expr) {
307         asn1p_expr_t *expr = NULL;
308         char *name;
309         asn1p_value_t *value;
310
311         if(check_expr->expr_type != ASN_BASIC_INTEGER
312         || check_expr->meta_type != AMT_VALUE) {
313                 fprintf(stderr,
314                         "CHECKER: Unsupported type of \"%s\" value: "
315                         "%d at line %d of %s\n",
316                         check_expr->Identifier,
317                         check_expr->expr_type,
318                         check_expr->_lineno,
319                         mod->source_file_name
320                 );
321                 return -1;
322         }
323
324         assert(check_expr->meta_type == AMT_VALUE);
325
326         value = check_expr->value;
327         if(value == NULL || value->type != ATV_INTEGER) {
328                 fprintf(stderr,
329                         "CHECKER: Unsupported value type of \"%s\": "
330                         "%d at line %d of %s\n",
331                         check_expr->Identifier,
332                         value?(signed)value->type:-1,
333                         expr->_lineno,
334                         mod->source_file_name
335                 );
336                 return -1;
337         }
338
339         name = check_expr->Identifier + sizeof("check-") - 1;
340
341         /*
342          * Scan in search for the original.
343          */
344     expr = genhash_get(mod->members_hash, name);
345         if(expr == NULL) {
346                 fprintf(stderr,
347                         "CHECKER: Value \"%s\" requested by "
348                         "\"check-%s\" at line %d of %s is not found!\n",
349                         name, name, check_expr->_lineno,
350                         mod->source_file_name
351                 );
352                 return -1;
353         }
354
355         if(0 && expr->expr_type != check_expr->expr_type) {
356                 fprintf(stderr,
357                         "CHECKER: Value type of \"%s\" (=%d) at line %d "
358                         "does not have desired type %d as requested by "
359                         "\"check-%s\" in %s\n",
360                         expr->Identifier,
361                         expr->expr_type,
362                         expr->_lineno,
363                         check_expr->expr_type,
364                         name,
365                         mod->source_file_name
366                 );
367                 return -1;
368         }
369
370         if(expr->value == NULL
371         || expr->value->type != value->type) {
372                 fprintf(stderr,
373                         "CHECKER: Value of \"%s\" (\"%s\", type=%d) at line %d "
374                         "does not have desired type %d as requested by "
375                         "\"check-%s\" in %s\n",
376                         expr->Identifier,
377                         asn1f_printable_value(expr->value),
378                         expr->value->type,
379                         expr->_lineno,
380                         value->type,
381                         name,
382                         mod->source_file_name
383                 );
384                 return -1;
385         }
386
387         return 0;
388 }
389
390