/*
* Generate random C declarations for testing.
* Copyright © 2012, 2020, 2022-2024 Nick Bowler
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include "cdecl.h"
#include "declgen.h"
#define PROGNAME "randomdecl"
#include "test.h"
static const char sopts[] = "s:n:ECVH";
static const struct option lopts[] = {
{ "seed", 1, NULL, 's' },
{ "count", 1, NULL, 'n' },
{ "cdecl", 0, NULL, 'C' },
{ "english", 0, NULL, 'E' },
{ "version", 0, NULL, 'V' },
{ "help", 0, NULL, 'H' },
{ 0 }
};
enum {
MODE_CDECL,
MODE_ENGLISH
};
static void print_usage(FILE *f)
{
fprintf(f, "Usage: %s [options]\n", progname);
}
static void print_help(void)
{
const struct option *opt;
print_usage(stdout);
puts("Generate random C declarations for testing.\n");
test_print_options(lopts);
}
static struct cdecl *random_decl(struct test_rng *rng)
{
struct cdecl *decl;
unsigned flags = 0;
decl = malloc_nofail(sizeof *decl);
decl->next = NULL;
decl->declarators = gen_declarators(rng);
if (decl->declarators->type != CDECL_DECL_FUNCTION)
flags |= GEN_NO_FUNCTION;
if (cdecl_is_abstract(decl->declarators))
flags |= GEN_NO_STORAGE | GEN_NO_FUNCTION;
if (decl->declarators->type == CDECL_DECL_ARRAY
|| decl->declarators->type == CDECL_DECL_IDENT)
flags |= GEN_NO_VOID;
decl->specifiers = gen_declspecs(rng, flags);
return decl;
}
static void
print_decl(struct cdecl *decl, size_t func(char *, size_t, struct cdecl *))
{
static size_t printbuf_size;
static char *printbuf;
size_t rc;
retry:
rc = func(printbuf, printbuf_size, decl);
if (rc >= printbuf_size) {
printbuf_size = rc + 1;
printbuf = realloc_nofail(printbuf, printbuf_size);
goto retry;
}
printf("%s\n", printbuf);
}
int main(int argc, char **argv)
{
const char *seed = "", *count_str = NULL;
unsigned long i, count = 0;
int opt, mode = MODE_CDECL;
struct test_rng *rng;
struct cdecl *decl;
if (argc > 0)
progname = argv[0];
while ((opt = getopt_long(argc, argv, sopts, lopts, NULL)) != -1) {
switch (opt) {
case 's':
seed = optarg;
break;
case 'n':
count_str = optarg;
break;
case 'C':
mode = MODE_CDECL;
break;
case 'E':
mode = MODE_ENGLISH;
break;
case 'V':
test_print_version(PROGNAME);
return EXIT_SUCCESS;
case 'H':
print_help();
return EXIT_SUCCESS;
default:
print_usage(stderr);
return EXIT_FAILURE;
}
}
if (count_str && !test_strtoul(&count, count_str)) {
print_error("invalid count: %s", count_str);
return EXIT_FAILURE;
}
rng = test_rng_alloc(seed);
if (!rng)
return EXIT_FAILURE;
for (i = 0; !count || i < count; i++) {
decl = random_decl(rng);
if (mode == MODE_ENGLISH) {
print_decl(decl, cdecl_explain);
} else {
print_decl(decl, cdecl_declare);
}
gen_free_declspecs(decl->specifiers);
gen_free_declarators(decl->declarators);
free(decl);
}
test_rng_free(rng);
return EXIT_SUCCESS;
}