asn1c/libasn1fix/check_fixer.c

338 lines
6.9 KiB
C

#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;
int 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 */
int len = strlen(filename);
if(len && strcmp(filename + len - 5, ".asn1") == 0) {
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;
}
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;
}
/*
* Perform semantical checks and fixes.
*/
if(asn && 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(asn && r_value == 0) {
if(post_fix_check(asn))
r_value = -1;
}
/*
* TODO: destroy the 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;
}