| #undef NDEBUG |
| #include "asn1fix_internal.h" |
| |
| #ifdef WIN32 |
| #include <io.h> |
| #include <direct.h> |
| #define chdir _chdir |
| #else |
| #include <dirent.h> |
| #include <sysexits.h> |
| #endif |
| #include <errno.h> |
| |
| #include "asn1fix.h" |
| |
| static int check(const char *fname, |
| enum asn1p_flags parser_flags, |
| enum asn1f_flags fixer_flags); |
| static int post_fix_check(asn1p_t *asn); |
| static int post_fix_check_element(asn1p_module_t *mod, asn1p_expr_t *expr); |
| |
| int |
| main(int ac, char **av) { |
| #ifdef WIN32 |
| intptr_t dir; |
| struct _finddata_t c_file; |
| #else |
| struct dirent *dp; |
| DIR *dir; |
| #endif |
| int failed = 0; |
| int completed = 0; |
| enum asn1p_flags parser_flags = A1P_NOFLAGS; |
| enum asn1f_flags fixer_flags = A1F_NOFLAGS; |
| const char *filename; |
| size_t len; |
| int ret; |
| |
| /* |
| * Just in case when one decides that some flags better be |
| * enabled during `ASN1_FIXER_FLAGS=1 make check` or some |
| * similar usage. |
| */ |
| if(getenv("ASN1_PARSER_FLAGS")) |
| parser_flags = atoi(getenv("ASN1_PARSER_FLAGS")); |
| if(getenv("ASN1_FIXER_FLAGS")) |
| fixer_flags = atoi(getenv("ASN1_FIXER_FLAGS")); |
| |
| /* |
| * Go into a directory with tests. |
| */ |
| if(ac <= 1) { |
| fprintf(stderr, "Testing in ./tests...\n"); |
| ret = chdir("../tests"); |
| assert(ret == 0); |
| #ifdef WIN32 |
| dir = _findfirst("*.asn1", &c_file); |
| assert(dir != -1L); |
| #else |
| dir = opendir("."); |
| assert(dir); |
| #endif /* WIN32 */ |
| } else { |
| dir = 0; |
| } |
| |
| /* |
| * Scan every *.asn1 file and try to parse and fix it. |
| */ |
| if(dir) { |
| #ifdef WIN32 |
| do { |
| filename = c_file.name; |
| #else |
| while((dp = readdir(dir))) { |
| filename = dp->d_name; |
| #endif /* WIN32 */ |
| len = strlen(filename); |
| if(len <= 5 || strcmp(filename + len - 5, ".asn1")) |
| continue; |
| ret = check(filename, parser_flags, fixer_flags); |
| if(ret) { |
| fprintf(stderr, "FAILED: %s\n", |
| filename); |
| failed++; |
| } |
| completed++; |
| #ifdef WIN32 |
| } while(_findnext(dir, &c_file) == 0); |
| _findclose(dir); |
| #else |
| } |
| closedir(dir); |
| #endif /* WIN32 */ |
| |
| |
| fprintf(stderr, |
| "Tests COMPLETED: %d\n" |
| "Tests FAILED: %d\n" |
| , |
| completed, failed |
| ); |
| } else { |
| int i; |
| for(i = 1; i < ac; i++) { |
| ret = check(av[i], parser_flags, fixer_flags); |
| if(ret) { |
| fprintf(stderr, "FAILED: %s\n", av[i]); |
| failed++; |
| } |
| completed++; |
| } |
| } |
| |
| if(completed == 0) { |
| fprintf(stderr, "No tests defined?!\n"); |
| exit(EX_NOINPUT); |
| } |
| |
| if(failed) |
| exit(EX_DATAERR); |
| return 0; |
| } |
| |
| static int |
| check(const char *fname, |
| enum asn1p_flags parser_flags, |
| enum asn1f_flags fixer_flags) { |
| asn1p_t *asn; |
| int expected_parseable; /* Is it expected to be parseable? */ |
| int expected_fix_code; /* What code a fixer must return */ |
| int r_value = 0; |
| |
| /* |
| * Figure out how the processing should go by inferring |
| * expectations from the file name. |
| */ |
| if(strstr(fname, "-OK.")) { |
| expected_parseable = 1; |
| expected_fix_code = 0; |
| } else if(strstr(fname, "-NP.")) { |
| expected_parseable = 0; |
| expected_fix_code = 123; /* Does not matter */ |
| } else if(strstr(fname, "-SE.")) { |
| expected_parseable = 1; |
| expected_fix_code = -1; /* Semantically incorrect */ |
| } else if(strstr(fname, "-SW.")) { |
| expected_parseable = 1; |
| expected_fix_code = 1; /* Semantically suspicious */ |
| } else { |
| fprintf(stderr, "%s: Invalid file name format\n", fname); |
| return -1; |
| } |
| |
| /* Flag modifiers */ |
| if(strstr(fname, "-blessSize-")) |
| fixer_flags |= A1F_EXTENDED_SizeConstraint; |
| |
| fprintf(stderr, "[=> %s]\n", fname); |
| |
| /* |
| * Perform low-level parsing. |
| */ |
| if(!expected_parseable) |
| fprintf(stderr, "Expecting error...\n"); |
| asn = asn1p_parse_file(fname, parser_flags); |
| if(asn == NULL) { |
| if(expected_parseable) { |
| fprintf(stderr, "Cannot parse file \"%s\"\n", fname); |
| r_value = -1; |
| } else { |
| fprintf(stderr, |
| "Previous error is EXPECTED, no worry\n"); |
| } |
| } else if(!expected_parseable) { |
| fprintf(stderr, |
| "The file \"%s\" is not expected to be parseable, " |
| "yet parsing was successfull!\n", fname); |
| r_value = -1; |
| } |
| if(!asn) return r_value; |
| |
| if(r_value == 0) { |
| asn1p_t *std_asn; |
| std_asn = asn1p_parse_file("../skeletons/standard-modules/ASN1C-UsefulInformationObjectClasses.asn1", A1P_NOFLAGS); |
| if(std_asn) { |
| asn1p_module_t *mod; |
| while((mod = TQ_REMOVE(&(std_asn->modules), mod_next))) { |
| mod->_tags |= MT_STANDARD_MODULE; |
| TQ_ADD(&(asn->modules), mod, mod_next); |
| } |
| asn1p_free(std_asn); |
| } |
| } |
| |
| /* |
| * Perform semantical checks and fixes. |
| */ |
| if(r_value == 0) { |
| int ret; |
| |
| if(expected_fix_code) |
| fprintf(stderr, "Expecting some problems...\n"); |
| |
| ret = asn1f_process(asn, fixer_flags, 0); |
| if(ret) { |
| if(ret == expected_fix_code) { |
| fprintf(stderr, |
| "Previous error is EXPECTED, " |
| "no worry\n"); |
| } else { |
| fprintf(stderr, |
| "Cannot process file \"%s\": %d\n", |
| fname, ret); |
| r_value = -1; |
| } |
| } else if(ret != expected_fix_code) { |
| fprintf(stderr, |
| "File \"%s\" is expected " |
| "to be semantically incorrect, " |
| "yet processing was successful!\n", |
| fname); |
| r_value = -1; |
| } |
| } |
| |
| /* |
| * Check validity of some values, if grammar has special |
| * instructions for that. |
| */ |
| if(r_value == 0) { |
| if(post_fix_check(asn)) |
| r_value = -1; |
| } |
| |
| /* |
| * Destroy the asn. |
| */ |
| asn1p_free(asn); |
| |
| return r_value; |
| } |
| |
| |
| static int |
| post_fix_check(asn1p_t *asn) { |
| asn1p_module_t *mod; |
| asn1p_expr_t *expr; |
| int r_value = 0; |
| |
| TQ_FOR(mod, &(asn->modules), mod_next) { |
| TQ_FOR(expr, &(mod->members), next) { |
| assert(expr->Identifier); |
| if(strncmp(expr->Identifier, "check-", 6) == 0) { |
| if(post_fix_check_element(mod, expr)) |
| r_value = -1; |
| } |
| } |
| } |
| |
| return r_value; |
| } |
| |
| |
| static int |
| post_fix_check_element(asn1p_module_t *mod, asn1p_expr_t *check_expr) { |
| asn1p_expr_t *expr = NULL; |
| char *name; |
| asn1p_value_t *value; |
| |
| if(check_expr->expr_type != ASN_BASIC_INTEGER |
| || check_expr->meta_type != AMT_VALUE) { |
| fprintf(stderr, |
| "CHECKER: Unsupported type of \"%s\" value: " |
| "%d at line %d of %s\n", |
| check_expr->Identifier, |
| check_expr->expr_type, |
| check_expr->_lineno, |
| mod->source_file_name |
| ); |
| return -1; |
| } |
| |
| assert(check_expr->meta_type == AMT_VALUE); |
| |
| value = check_expr->value; |
| if(value == NULL || value->type != ATV_INTEGER) { |
| fprintf(stderr, |
| "CHECKER: Unsupported value type of \"%s\": " |
| "%d at line %d of %s\n", |
| check_expr->Identifier, |
| value?(signed)value->type:-1, |
| expr->_lineno, |
| mod->source_file_name |
| ); |
| return -1; |
| } |
| |
| name = check_expr->Identifier + sizeof("check-") - 1; |
| |
| /* |
| * Scan in search for the original. |
| */ |
| TQ_FOR(expr, &(mod->members), next) { |
| if(strcmp(expr->Identifier, name) == 0) |
| break; |
| } |
| |
| if(expr == NULL) { |
| fprintf(stderr, |
| "CHECKER: Value \"%s\" requested by " |
| "\"check-%s\" at line %d of %s is not found!\n", |
| name, name, check_expr->_lineno, |
| mod->source_file_name |
| ); |
| return -1; |
| } |
| |
| if(0 && expr->expr_type != check_expr->expr_type) { |
| fprintf(stderr, |
| "CHECKER: Value type of \"%s\" (=%d) at line %d " |
| "does not have desired type %d as requested by " |
| "\"check-%s\" in %s\n", |
| expr->Identifier, |
| expr->expr_type, |
| expr->_lineno, |
| check_expr->expr_type, |
| name, |
| mod->source_file_name |
| ); |
| return -1; |
| } |
| |
| if(expr->value == NULL |
| || expr->value->type != value->type) { |
| fprintf(stderr, |
| "CHECKER: Value of \"%s\" (\"%s\", type=%d) at line %d " |
| "does not have desired type %d as requested by " |
| "\"check-%s\" in %s\n", |
| expr->Identifier, |
| asn1f_printable_value(expr->value), |
| expr->value->type, |
| expr->_lineno, |
| value->type, |
| name, |
| mod->source_file_name |
| ); |
| return -1; |
| } |
| |
| assert(value->type = ATV_INTEGER); |
| |
| return 0; |
| } |
| |
| |