c-hdr-parser: add header open and syntax validation checks

This commit is contained in:
icst 2024-07-07 22:28:22 -04:00
parent 159c172082
commit 02266b4dea

View file

@ -4,6 +4,7 @@
#include <ctype.h>
#include <assert.h>
#include <stdint.h>
#include <unistd.h> /*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]);
}