Message ID | 20211101145342.7166-5-chrubis@suse.cz |
---|---|
State | Changes Requested |
Headers | show |
Series | docparse improvements | expand |
Hello, Cyril Hrubis <chrubis@suse.cz> writes: > Adds a special handlingn for ARRAY_SIZE() macro. > > If we stumble upon ARRAY_SIZE() in the tst_test structure we try to > lookup the array and count its members. > > Proper parsing of .test_variants also requires that we add -I switch to > the docparse to be able to specify include paths on a command line since > some variants are stuck in top level include while others are in > testcases/kernel/syscalls/utils/. > > + tests > > Signed-off-by: Cyril Hrubis <chrubis@suse.cz> Again I don't see anything that would presently prevent parsing. But see note below Reviewed-by: rpalethorpe@suse.com > --- > docparse/docparse.c | 221 ++++++++++++++++++++++++++--- > docparse/parse.sh | 2 +- > docparse/tests/array_size01.c | 5 + > docparse/tests/array_size01.c.json | 4 + > docparse/tests/array_size02.c | 9 ++ > docparse/tests/array_size02.c.json | 4 + > docparse/tests/array_size03.c | 10 ++ > docparse/tests/array_size03.c.json | 4 + > docparse/tests/array_size04.c | 5 + > docparse/tests/array_size04.c.json | 4 + > docparse/tests/include.h | 6 + > 11 files changed, 255 insertions(+), 19 deletions(-) > create mode 100644 docparse/tests/array_size01.c > create mode 100644 docparse/tests/array_size01.c.json > create mode 100644 docparse/tests/array_size02.c > create mode 100644 docparse/tests/array_size02.c.json > create mode 100644 docparse/tests/array_size03.c > create mode 100644 docparse/tests/array_size03.c.json > create mode 100644 docparse/tests/array_size04.c > create mode 100644 docparse/tests/array_size04.c.json > > diff --git a/docparse/docparse.c b/docparse/docparse.c > index 64f9d08d9..9133accf5 100644 > --- a/docparse/docparse.c > +++ b/docparse/docparse.c > @@ -15,7 +15,11 @@ > > #include "data_storage.h" > > +#define INCLUDE_PATH_MAX 5 > + > static int verbose; > +static char *cmdline_includepath[INCLUDE_PATH_MAX]; > +static unsigned int cmdline_includepaths; > static char *includepath; > > #define WARN(str) fprintf(stderr, "WARNING: " str "\n") > @@ -132,13 +136,14 @@ static void maybe_comment(FILE *f, struct data_node *doc) > } > } > > -static char *next_token(FILE *f, struct data_node *doc) > +static char *next_token2(FILE *f, char *buf, size_t buf_len, struct data_node *doc) > { > size_t i = 0; > - static char buf[4096]; > int c; > int in_str = 0; > > + buf_len--; > + > for (;;) { > c = fgetc(f); > > @@ -151,7 +156,8 @@ static char *next_token(FILE *f, struct data_node *doc) > goto exit; > } > > - buf[i++] = c; > + if (i < buf_len) > + buf[i++] = c; > continue; > } > > @@ -171,7 +177,8 @@ static char *next_token(FILE *f, struct data_node *doc) > goto exit; > } > > - buf[i++] = c; > + if (i < buf_len) > + buf[i++] = c; > goto exit; > case '0' ... '9': > case 'a' ... 'z': > @@ -204,11 +211,33 @@ exit: > return buf; > } > > -static FILE *open_include(const char *includepath, FILE *f) > +static char *next_token(FILE *f, struct data_node *doc) > +{ > + static char buf[4096]; > + > + return next_token2(f, buf, sizeof(buf), doc); > +} > + > +static FILE *open_file(const char *dir, const char *fname) > { > - char buf[256]; > + FILE *f; > char *path; > + > + if (asprintf(&path, "%s/%s", dir, fname) < 0) > + return NULL; > + > + f = fopen(path, "r"); > + > + free(path); > + > + return f; > +} > + > +static FILE *open_include(FILE *f) > +{ > + char buf[256], *fname; > FILE *inc; > + unsigned int i; > > if (!fscanf(f, "%s\n", buf)) > return NULL; > @@ -216,24 +245,36 @@ static FILE *open_include(const char *includepath, FILE *f) > if (buf[0] != '"') > return NULL; > > - char *filename = buf + 1; > + fname = buf + 1; > > if (!buf[0]) > return NULL; > > - filename[strlen(filename)-1] = 0; > + fname[strlen(fname)-1] = 0; > > - if (asprintf(&path, "%s/%s", includepath, filename) < 0) > - return NULL; > + inc = open_file(includepath, fname); > + if (inc) { > + if (verbose) > + fprintf(stderr, "INCLUDE %s/%s\n", includepath, fname); > > - inc = fopen(path, "r"); > + return inc; > + } > > - if (inc && verbose) > - fprintf(stderr, "INCLUDE %s\n", path); > + for (i = 0; i < cmdline_includepaths; i++) { > + inc = open_file(cmdline_includepath[i], fname); > > - free(path); > + if (!inc) > + continue; > > - return inc; > + if (verbose) { > + fprintf(stderr, "INCLUDE %s/%s\n", > + cmdline_includepath[i], fname); > + } > + > + return inc; > + } > + > + return NULL; > } > > static void close_include(FILE *inc) > @@ -300,6 +341,136 @@ static void try_apply_macro(char **res) > *res = ret->data; > } > > +static int parse_get_array_len(FILE *f) > +{ > + const char *token; > + int cnt = 0, depth = 0, prev_comma = 0; > + > + if (!(token = next_token(f, NULL))) > + return 0; > + > + if (strcmp(token, "{")) > + return 0; > + > + for (;;) { > + if (!(token = next_token(f, NULL))) > + return 0; > + > + if (!strcmp(token, "{")) > + depth++; > + > + if (!strcmp(token, "}")) > + depth--; > + else > + prev_comma = 0; > + > + if (!strcmp(token, ",") && !depth) { > + prev_comma = 1; > + cnt++; > + } > + > + if (depth < 0) > + return cnt + !prev_comma; > + } > +} > + > +static void look_for_array_size(FILE *f, const char *arr_id, struct data_node **res) > +{ > + const char *token; > + char buf[2][2048] = {}; > + int cur_buf = 0; > + int prev_buf = 1; > + > + for (;;) { > + if (!(token = next_token2(f, buf[cur_buf], 2048, NULL))) > + break; > + > + if (!strcmp(token, "=") && !strcmp(buf[prev_buf], arr_id)) { > + int arr_len = parse_get_array_len(f); > + > + if (verbose) > + fprintf(stderr, "ARRAY %s LENGTH = %i\n", arr_id, arr_len); > + > + *res = data_node_int(arr_len); > + > + break; > + } > + > + if (strcmp(buf[cur_buf], "]") && strcmp(buf[cur_buf], "[")) { So this seems to mean we would silently ignore a variants array which was declared with an explicit size. A quick grep doesn't turn up any instances of that. However this would be an unexpected result. People may intuitively think adding an explicity size would make parsing easier.
Hi! > > + > > + if (strcmp(buf[cur_buf], "]") && strcmp(buf[cur_buf], "[")) { > > So this seems to mean we would silently ignore a variants array which > was declared with an explicit size. A quick grep doesn't turn up any > instances of that. However this would be an unexpected result. People > may intuitively think adding an explicity size would make parsing > easier. I would say that adding explicit size to arrays whose size is defined by their initialize is a mistake, at least in our case so I'm inclined to keep this as it is.
diff --git a/docparse/docparse.c b/docparse/docparse.c index 64f9d08d9..9133accf5 100644 --- a/docparse/docparse.c +++ b/docparse/docparse.c @@ -15,7 +15,11 @@ #include "data_storage.h" +#define INCLUDE_PATH_MAX 5 + static int verbose; +static char *cmdline_includepath[INCLUDE_PATH_MAX]; +static unsigned int cmdline_includepaths; static char *includepath; #define WARN(str) fprintf(stderr, "WARNING: " str "\n") @@ -132,13 +136,14 @@ static void maybe_comment(FILE *f, struct data_node *doc) } } -static char *next_token(FILE *f, struct data_node *doc) +static char *next_token2(FILE *f, char *buf, size_t buf_len, struct data_node *doc) { size_t i = 0; - static char buf[4096]; int c; int in_str = 0; + buf_len--; + for (;;) { c = fgetc(f); @@ -151,7 +156,8 @@ static char *next_token(FILE *f, struct data_node *doc) goto exit; } - buf[i++] = c; + if (i < buf_len) + buf[i++] = c; continue; } @@ -171,7 +177,8 @@ static char *next_token(FILE *f, struct data_node *doc) goto exit; } - buf[i++] = c; + if (i < buf_len) + buf[i++] = c; goto exit; case '0' ... '9': case 'a' ... 'z': @@ -204,11 +211,33 @@ exit: return buf; } -static FILE *open_include(const char *includepath, FILE *f) +static char *next_token(FILE *f, struct data_node *doc) +{ + static char buf[4096]; + + return next_token2(f, buf, sizeof(buf), doc); +} + +static FILE *open_file(const char *dir, const char *fname) { - char buf[256]; + FILE *f; char *path; + + if (asprintf(&path, "%s/%s", dir, fname) < 0) + return NULL; + + f = fopen(path, "r"); + + free(path); + + return f; +} + +static FILE *open_include(FILE *f) +{ + char buf[256], *fname; FILE *inc; + unsigned int i; if (!fscanf(f, "%s\n", buf)) return NULL; @@ -216,24 +245,36 @@ static FILE *open_include(const char *includepath, FILE *f) if (buf[0] != '"') return NULL; - char *filename = buf + 1; + fname = buf + 1; if (!buf[0]) return NULL; - filename[strlen(filename)-1] = 0; + fname[strlen(fname)-1] = 0; - if (asprintf(&path, "%s/%s", includepath, filename) < 0) - return NULL; + inc = open_file(includepath, fname); + if (inc) { + if (verbose) + fprintf(stderr, "INCLUDE %s/%s\n", includepath, fname); - inc = fopen(path, "r"); + return inc; + } - if (inc && verbose) - fprintf(stderr, "INCLUDE %s\n", path); + for (i = 0; i < cmdline_includepaths; i++) { + inc = open_file(cmdline_includepath[i], fname); - free(path); + if (!inc) + continue; - return inc; + if (verbose) { + fprintf(stderr, "INCLUDE %s/%s\n", + cmdline_includepath[i], fname); + } + + return inc; + } + + return NULL; } static void close_include(FILE *inc) @@ -300,6 +341,136 @@ static void try_apply_macro(char **res) *res = ret->data; } +static int parse_get_array_len(FILE *f) +{ + const char *token; + int cnt = 0, depth = 0, prev_comma = 0; + + if (!(token = next_token(f, NULL))) + return 0; + + if (strcmp(token, "{")) + return 0; + + for (;;) { + if (!(token = next_token(f, NULL))) + return 0; + + if (!strcmp(token, "{")) + depth++; + + if (!strcmp(token, "}")) + depth--; + else + prev_comma = 0; + + if (!strcmp(token, ",") && !depth) { + prev_comma = 1; + cnt++; + } + + if (depth < 0) + return cnt + !prev_comma; + } +} + +static void look_for_array_size(FILE *f, const char *arr_id, struct data_node **res) +{ + const char *token; + char buf[2][2048] = {}; + int cur_buf = 0; + int prev_buf = 1; + + for (;;) { + if (!(token = next_token2(f, buf[cur_buf], 2048, NULL))) + break; + + if (!strcmp(token, "=") && !strcmp(buf[prev_buf], arr_id)) { + int arr_len = parse_get_array_len(f); + + if (verbose) + fprintf(stderr, "ARRAY %s LENGTH = %i\n", arr_id, arr_len); + + *res = data_node_int(arr_len); + + break; + } + + if (strcmp(buf[cur_buf], "]") && strcmp(buf[cur_buf], "[")) { + cur_buf = !cur_buf; + prev_buf = !prev_buf; + } + } +} + +static int parse_array_size(FILE *f, struct data_node **res) +{ + const char *token; + char *arr_id; + long pos; + int hash = 0; + + *res = NULL; + + if (!(token = next_token(f, NULL))) + return 1; + + if (strcmp(token, "(")) + return 1; + + if (!(token = next_token(f, NULL))) + return 1; + + arr_id = strdup(token); + + if (verbose) + fprintf(stderr, "COMPUTING ARRAY '%s' LENGHT\n", arr_id); + + pos = ftell(f); + + rewind(f); + + look_for_array_size(f, arr_id, res); + + if (!*res) { + FILE *inc; + + rewind(f); + + for (;;) { + if (!(token = next_token(f, NULL))) + break; + + if (token[0] == '#') { + hash = 1; + continue; + } + + if (!hash) + continue; + + if (!strcmp(token, "include")) { + inc = open_include(f); + + if (inc) { + look_for_array_size(inc, arr_id, res); + close_include(inc); + } + } + + if (*res) + break; + } + } + + free(arr_id); + + if (fseek(f, pos, SEEK_SET)) + return 1; + + return 0; +} + static int parse_test_struct(FILE *f, struct data_node *doc, struct data_node *node) { char *token; @@ -345,11 +516,17 @@ static int parse_test_struct(FILE *f, struct data_node *doc, struct data_node *n if (!strcmp(token, "{")) { ret = data_node_array(); parse_array(f, ret); + } else if (!strcmp(token, "ARRAY_SIZE")) { + if (parse_array_size(f, &ret)) + return 1; } else { try_apply_macro(&token); ret = data_node_string(token); } + if (!ret) + continue; + const char *key = id; if (key[0] == '.') key++; @@ -455,7 +632,7 @@ static void parse_include_macros(FILE *f) const char *token; int hash = 0; - inc = open_include(includepath, f); + inc = open_include(f); if (!inc) return; @@ -519,7 +696,6 @@ static struct data_node *parse_file(const char *fname) parse_test_struct(f, doc, res); } - if (data_node_array_len(doc)) { data_node_hash_add(res, "doc", doc); found = 1; @@ -579,6 +755,7 @@ static void print_help(const char *prgname) { printf("usage: %s [-vh] input.c\n\n", prgname); printf("-v sets verbose mode\n"); + printf("-I add include path\n"); printf("-h prints this help\n\n"); exit(0); } @@ -589,11 +766,19 @@ int main(int argc, char *argv[]) struct data_node *res; int opt; - while ((opt = getopt(argc, argv, "hv")) != -1) { + while ((opt = getopt(argc, argv, "hI:v")) != -1) { switch (opt) { case 'h': print_help(argv[0]); break; + case 'I': + if (cmdline_includepaths >= INCLUDE_PATH_MAX) { + fprintf(stderr, "Too much include paths!"); + exit(1); + } + + cmdline_includepath[cmdline_includepaths++] = optarg; + break; case 'v': verbose = 1; break; diff --git a/docparse/parse.sh b/docparse/parse.sh index 79011bc10..2ace34fa0 100755 --- a/docparse/parse.sh +++ b/docparse/parse.sh @@ -26,7 +26,7 @@ echo ' "tests": {' first=1 for test in `find testcases/ -name '*.c'`; do - a=$($top_builddir/docparse/docparse "$test") + a=$($top_builddir/docparse/docparse -Iinclude -Itestcases/kernel/syscalls/utils/ "$test") if [ -n "$a" ]; then if [ -z "$first" ]; then echo ',' diff --git a/docparse/tests/array_size01.c b/docparse/tests/array_size01.c new file mode 100644 index 000000000..5f182bc7c --- /dev/null +++ b/docparse/tests/array_size01.c @@ -0,0 +1,5 @@ +static int variants[] = {1}; + +static struct tst_test test = { + .test_variants = ARRAY_SIZE(variants), +}; diff --git a/docparse/tests/array_size01.c.json b/docparse/tests/array_size01.c.json new file mode 100644 index 000000000..ec364be12 --- /dev/null +++ b/docparse/tests/array_size01.c.json @@ -0,0 +1,4 @@ + "array_size01": { + "test_variants": 1, + "fname": "array_size01.c" + } \ No newline at end of file diff --git a/docparse/tests/array_size02.c b/docparse/tests/array_size02.c new file mode 100644 index 000000000..ffa37a5c6 --- /dev/null +++ b/docparse/tests/array_size02.c @@ -0,0 +1,9 @@ +struct foo { + int val; +}; + +static struct foo variants[] = {{1}, {2}, {3}}; + +static struct tst_test test = { + .test_variants = ARRAY_SIZE(variants), +}; diff --git a/docparse/tests/array_size02.c.json b/docparse/tests/array_size02.c.json new file mode 100644 index 000000000..122686952 --- /dev/null +++ b/docparse/tests/array_size02.c.json @@ -0,0 +1,4 @@ + "array_size02": { + "test_variants": 3, + "fname": "array_size02.c" + } \ No newline at end of file diff --git a/docparse/tests/array_size03.c b/docparse/tests/array_size03.c new file mode 100644 index 000000000..9058db813 --- /dev/null +++ b/docparse/tests/array_size03.c @@ -0,0 +1,10 @@ +static struct foo variants[] = { +#ifdef FOO + {.bar = 11}, +#endif + {.bar = 10}, +}; + +static struct tst_test test = { + .test_variants = ARRAY_SIZE(variants), +}; diff --git a/docparse/tests/array_size03.c.json b/docparse/tests/array_size03.c.json new file mode 100644 index 000000000..bb690c9f5 --- /dev/null +++ b/docparse/tests/array_size03.c.json @@ -0,0 +1,4 @@ + "array_size03": { + "test_variants": 2, + "fname": "array_size03.c" + } \ No newline at end of file diff --git a/docparse/tests/array_size04.c b/docparse/tests/array_size04.c new file mode 100644 index 000000000..5f1d9986e --- /dev/null +++ b/docparse/tests/array_size04.c @@ -0,0 +1,5 @@ +#include "include.h" + +static struct tst_test test = { + .test_variants = ARRAY_SIZE(variants), +}; diff --git a/docparse/tests/array_size04.c.json b/docparse/tests/array_size04.c.json new file mode 100644 index 000000000..6b8d41792 --- /dev/null +++ b/docparse/tests/array_size04.c.json @@ -0,0 +1,4 @@ + "array_size04": { + "test_variants": 3, + "fname": "array_size04.c" + } \ No newline at end of file diff --git a/docparse/tests/include.h b/docparse/tests/include.h index efa11d24f..fbc69a561 100644 --- a/docparse/tests/include.h +++ b/docparse/tests/include.h @@ -1 +1,7 @@ #define TEST_VARIANTS 10 + +static struct variants[] = { + {.bar = 10}, + {.bar = 11}, + {.bar = 12} +};
Adds a special handlingn for ARRAY_SIZE() macro. If we stumble upon ARRAY_SIZE() in the tst_test structure we try to lookup the array and count its members. Proper parsing of .test_variants also requires that we add -I switch to the docparse to be able to specify include paths on a command line since some variants are stuck in top level include while others are in testcases/kernel/syscalls/utils/. + tests Signed-off-by: Cyril Hrubis <chrubis@suse.cz> --- docparse/docparse.c | 221 ++++++++++++++++++++++++++--- docparse/parse.sh | 2 +- docparse/tests/array_size01.c | 5 + docparse/tests/array_size01.c.json | 4 + docparse/tests/array_size02.c | 9 ++ docparse/tests/array_size02.c.json | 4 + docparse/tests/array_size03.c | 10 ++ docparse/tests/array_size03.c.json | 4 + docparse/tests/array_size04.c | 5 + docparse/tests/array_size04.c.json | 4 + docparse/tests/include.h | 6 + 11 files changed, 255 insertions(+), 19 deletions(-) create mode 100644 docparse/tests/array_size01.c create mode 100644 docparse/tests/array_size01.c.json create mode 100644 docparse/tests/array_size02.c create mode 100644 docparse/tests/array_size02.c.json create mode 100644 docparse/tests/array_size03.c create mode 100644 docparse/tests/array_size03.c.json create mode 100644 docparse/tests/array_size04.c create mode 100644 docparse/tests/array_size04.c.json