// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)

/*
 * BTF-to-C dumper test for majority of C syntax quirks.
 *
 * Copyright (c) 2019 Facebook
 */
/* ----- START-EXPECTED-OUTPUT ----- */
enum e1 {
	A = 0,
	B = 1,
};

enum e2 {
	C = 100,
	D = 4294967295,
	E = 0,
};

typedef enum e2 e2_t;

typedef enum {
	F = 0,
	G = 1,
	H = 2,
} e3_t;

typedef int int_t;

typedef volatile const int * volatile const crazy_ptr_t;

typedef int *****we_need_to_go_deeper_ptr_t;

typedef volatile const we_need_to_go_deeper_ptr_t * restrict * volatile * const * restrict volatile * restrict const * volatile const * restrict volatile const how_about_this_ptr_t;

typedef int *ptr_arr_t[10];

typedef void (*fn_ptr1_t)(int);

typedef void (*printf_fn_t)(const char *, ...);

/* ------ END-EXPECTED-OUTPUT ------ */
/*
 * While previous function pointers are pretty trivial (C-syntax-level
 * trivial), the following are deciphered here for future generations:
 *
 * - `fn_ptr2_t`: function, taking anonymous struct as a first arg and pointer
 *   to a function, that takes int and returns int, as a second arg; returning
 *   a pointer to a const pointer to a char. Equivalent to:
 *	typedef struct { int a; } s_t;
 *	typedef int (*fn_t)(int);
 *	typedef char * const * (*fn_ptr2_t)(s_t, fn_t);
 *
 * - `fn_complext_t`: pointer to a function returning struct and accepting
 *   union and struct. All structs and enum are anonymous and defined inline.
 *
 * - `signal_t: pointer to a function accepting a pointer to a function as an
 *   argument and returning pointer to a function as a result. Sane equivalent:
 *	typedef void (*signal_handler_t)(int);
 *	typedef signal_handler_t (*signal_ptr_t)(int, signal_handler_t);
 *
 * - fn_ptr_arr1_t: array of pointers to a function accepting pointer to
 *   a pointer to an int and returning pointer to a char. Easy.
 *
 * - fn_ptr_arr2_t: array of const pointers to a function taking no arguments
 *   and returning a const pointer to a function, that takes pointer to a
 *   `int -> char *` function and returns pointer to a char. Equivalent:
 *   typedef char * (*fn_input_t)(int);
 *   typedef char * (*fn_output_outer_t)(fn_input_t);
 *   typedef const fn_output_outer_t (* fn_output_inner_t)();
 *   typedef const fn_output_inner_t fn_ptr_arr2_t[5];
 */
/* ----- START-EXPECTED-OUTPUT ----- */
typedef char * const * (*fn_ptr2_t)(struct {
	int a;
}, int (*)(int));

typedef struct {
	int a;
	void (*b)(int, struct {
		int c;
	}, union {
		char d;
		int e[5];
	});
} (*fn_complex_t)(union {
	void *f;
	char g[16];
}, struct {
	int h;
});

typedef void (* (*signal_t)(int, void (*)(int)))(int);

typedef char * (*fn_ptr_arr1_t[10])(int **);

typedef char * (* (* const fn_ptr_arr2_t[5])())(char * (*)(int));

struct struct_w_typedefs {
	int_t a;
	crazy_ptr_t b;
	we_need_to_go_deeper_ptr_t c;
	how_about_this_ptr_t d;
	ptr_arr_t e;
	fn_ptr1_t f;
	printf_fn_t g;
	fn_ptr2_t h;
	fn_complex_t i;
	signal_t j;
	fn_ptr_arr1_t k;
	fn_ptr_arr2_t l;
};

typedef struct {
	int x;
	int y;
	int z;
} anon_struct_t;

struct struct_fwd;

typedef struct struct_fwd struct_fwd_t;

typedef struct struct_fwd *struct_fwd_ptr_t;

union union_fwd;

typedef union union_fwd union_fwd_t;

typedef union union_fwd *union_fwd_ptr_t;

struct struct_empty {};

struct struct_simple {
	int a;
	char b;
	const int_t *p;
	struct struct_empty s;
	enum e2 e;
	enum {
		ANON_VAL1 = 1,
		ANON_VAL2 = 2,
	} f;
	int arr1[13];
	enum e2 arr2[5];
};

union union_empty {};

union union_simple {
	void *ptr;
	int num;
	int_t num2;
	union union_empty u;
};

struct struct_in_struct {
	struct struct_simple simple;
	union union_simple also_simple;
	struct {
		int a;
	} not_so_hard_as_well;
	union {
		int b;
		int c;
	} anon_union_is_good;
	struct {
		int d;
		int e;
	};
	union {
		int f;
		int g;
	};
};

struct struct_in_array {};

struct struct_in_array_typed {};

typedef struct struct_in_array_typed struct_in_array_t[2];

struct struct_with_embedded_stuff {
	int a;
	struct {
		int b;
		struct {
			struct struct_with_embedded_stuff *c;
			const char *d;
		} e;
		union {
			volatile long f;
			void * restrict g;
		};
	};
	union {
		const int_t *h;
		void (*i)(char, int, void *);
	} j;
	enum {
		K = 100,
		L = 200,
	} m;
	char n[16];
	struct {
		char o;
		int p;
		void (*q)(int);
	} r[5];
	struct struct_in_struct s[10];
	int t[11];
	struct struct_in_array (*u)[2];
	struct_in_array_t *v;
};

struct float_struct {
	float f;
	const double *d;
	volatile long double *ld;
};

struct root_struct {
	enum e1 _1;
	enum e2 _2;
	e2_t _2_1;
	e3_t _2_2;
	struct struct_w_typedefs _3;
	anon_struct_t _7;
	struct struct_fwd *_8;
	struct_fwd_t *_9;
	struct_fwd_ptr_t _10;
	union union_fwd *_11;
	union_fwd_t *_12;
	union_fwd_ptr_t _13;
	struct struct_with_embedded_stuff _14;
	struct float_struct _15;
};

/* ------ END-EXPECTED-OUTPUT ------ */

int f(struct root_struct *s)
{
	return 0;
}
