#undef NDEBUG #include "asn1fix_internal.h" #ifdef WIN32 #include #include #define chdir _chdir #else #include #include #endif #include #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_delete(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. */ #ifdef CLEAN_EVERYTHING asn1p_delete(asn); #endif 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; }