From 02266b4dea10f6c0aa2a88ba232b690ba410d34e Mon Sep 17 00:00:00 2001 From: icst Date: Sun, 7 Jul 2024 22:28:22 -0400 Subject: [PATCH] c-hdr-parser: add header open and syntax validation checks --- c-hdr-parser.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) diff --git a/c-hdr-parser.c b/c-hdr-parser.c index 1280a91..310068f 100644 --- a/c-hdr-parser.c +++ b/c-hdr-parser.c @@ -4,6 +4,7 @@ #include #include #include +#include /*close()*/ /// realloc s1 and append s2 to it (modifies only s1) char *cstr_append(char *s1, const char *s2) { @@ -37,6 +38,62 @@ FILE *open_c_header(const char *cc_cmd, const char *hdr_fn) { return f; } +/** + * Run a header file through the compiler to validate it's syntax + */ +int valid_c_header(const char *cc_cmd, const char *hdr_fn) { + + static const char tmppath[] = "/tmp/."; + + char *test_fn = strdup(tmppath); + if ( test_fn == NULL ) return 0; + test_fn = cstr_append(test_fn, hdr_fn); + if ( test_fn == NULL ) return 0; + test_fn = cstr_append(test_fn, ".o.XXXXXX"); + if ( test_fn == NULL ) return 0; + + // NOTE: This generates a unique filename by replacing the 'XXXXXX' with random chars then + // opens the file. It MODIFIES its argument string to contain the random chars selected to + // replace the 'XXXXXX' so after call if the filedesc is valid, test_fn is the true filename. + int r = mkstemp(test_fn); + if ( r == -1 ) { + free( test_fn ); + return 0; + } + + close(r); + + char *cmd = strdup("echo \"#include <"); + if ( cmd == NULL ) goto FAILRET; + cmd = cstr_append(cmd, hdr_fn); + if ( cmd == NULL ) goto FAILRET; + cmd = cstr_append(cmd, ">\" | "); + if ( cmd == NULL ) goto FAILRET; + cmd = cstr_append(cmd, cc_cmd); + if ( cmd == NULL ) goto FAILRET; + cmd = cstr_append(cmd, " -I . -c -x c -o "); /*include ./; compile only, don't link; c syntax*/ + if ( cmd == NULL ) goto FAILRET; + cmd = cstr_append(cmd, test_fn); + if ( cmd == NULL ) goto FAILRET; + cmd = cstr_append(cmd, " -"); /*use stdin*/ + if ( cmd == NULL ) goto FAILRET; + + puts(cmd); + + int ret = system(cmd); + + remove( test_fn ); + free( test_fn ); + free( cmd ); + + return (ret == 0); +FAILRET: + remove( test_fn ); + free( test_fn ); + if ( cmd ) free( cmd ); + return 0; +} + /// Parse a series of keywords/identifiers until a non-kw/id is found indicating the end char ** parse_c_header_identkws(size_t *nidkws, int *c, FILE *f) { @@ -559,8 +616,9 @@ int main(int argc, char *argv[]) { if ( argc <= 1 ) return 1; const char *cmd = getenv("CC"); + cmd = (cmd == NULL) ? "cc" : cmd; - FILE *fhdr = open_c_header(((cmd == NULL) ? "cc" : cmd), argv[1]); + FILE *fhdr = open_c_header(cmd, argv[1]); if ( fhdr == NULL ) { perror(argv[1]); @@ -570,6 +628,17 @@ int main(int argc, char *argv[]) { size_t ndecl = 0; char **decl = parse_c_header(&ndecl, fhdr); + int r = pclose(fhdr); + if ( r != 0 ) { + fprintf(stdout, "[ERROR] Failed to read c-header '%s', CC=%s returned %d\n", argv[1], cmd, r); + return 1; + } + + if ( !valid_c_header(cmd, argv[1]) ) { + fprintf(stdout, "[ERROR] System CC=%s failed to validate the syntax of c-header: %s\n", cmd, argv[1]); + return 1; + } + for (size_t n=0; n < ndecl; n++) { puts(decl[n]); }