/*
 * Copyright (c) 2004 Sendmail, Inc. and its suppliers.
 *	All rights reserved.
 *
 * By using this file, you agree to the terms and conditions set
 * forth in the LICENSE file which can be found at the top level of
 * the sendmail distribution.
 */

#include "sm/generic.h"
SM_RCSID("@(#)$Id: demo-union.c,v 1.4 2005/09/26 23:26:41 ca Exp $")

#if SM_LIBCONF_ALONE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include "sm-conf.h"
#else /* SM_LIBCONF_ALONE */
#include "sm/string.h"
#include "sm/sm-conf.h"
#include "sm/net.h"
#include <stdio.h>
#endif /* SM_LIBCONF_ALONE */

/* DEMO-UNION.C -- demo of unions. */

#ifndef offsetof
#define offsetof(type, member)	((char *)&((type *)0)->member - (char *)0)
#endif

typedef union vehicle_U
{
	enum vehicle_type
	{
		AIRPLANE	= 1,
		BOAT		= 2,
		CAR		= 3
	} type;

	struct
	{
		enum vehicle_type	air_type;
		char			*air_flight;
		int			air_passengers;
	} airplane;

	struct
	{
		enum vehicle_type	boat_type;
		int			boat_knots;
		char			*boat_name;
	} boat;

	struct
	{
		enum vehicle_type	car_type;
		int			car_mpg;
		char			*car_plate;
	} car;

} vehicle_T;

static sm_conf_definition_T const
air_definitions[] =
{
	{ SM_CONF_DEF_MAGIC, "flight", sm_conf_type_string,
		offsetof(vehicle_T, airplane.air_flight), 0, NULL
	},

	{ SM_CONF_DEF_MAGIC, "passengers", sm_conf_type_u32,
		offsetof(vehicle_T, airplane.air_passengers),
		sizeof(unsigned int), "1"
	},

	/* sentinel */
	{ SM_CONF_DEF_MAGIC, NULL }
};

static sm_conf_definition_T const
boat_definitions[] =
{

	{ SM_CONF_DEF_MAGIC, "name", sm_conf_type_string,
		offsetof(vehicle_T, boat.boat_name), 0, NULL
	},

	{ SM_CONF_DEF_MAGIC, "knots", sm_conf_type_u32,
		offsetof(vehicle_T, boat.boat_knots),
		sizeof(unsigned int),  NULL
	},

	/* sentinel */
	{ SM_CONF_DEF_MAGIC, NULL }
};

static sm_conf_definition_T const
car_definitions[] =
{
	{ SM_CONF_DEF_MAGIC, "plate", sm_conf_type_string,
		offsetof(vehicle_T, car.car_plate), 0, NULL
	},

	{ SM_CONF_DEF_MAGIC, "mpg", sm_conf_type_u32,
		offsetof(vehicle_T, car.car_mpg),
		sizeof(unsigned int),  NULL
	},

	/* sentinel */
	{ SM_CONF_DEF_MAGIC, NULL }
};

/*
**  Vehicles are distinguished by section label.
*/

static sm_conf_definition_T
vehicle_red_definitions[] =
{

	{ SM_CONF_DEF_MAGIC,
		"",
		sm_conf_type_union_type,
		offsetof(vehicle_T, type),
		sizeof(enum vehicle_type)
	},

	{ SM_CONF_DEF_MAGIC,
		"",
		sm_conf_type_union_choice,
		AIRPLANE,
		sizeof(vehicle_T),  "airplane", 0,
		air_definitions
	},

	{ SM_CONF_DEF_MAGIC,
		"",
		sm_conf_type_union_choice,
		BOAT,
		sizeof(vehicle_T), "boat", 0,
		boat_definitions
	},

	{ SM_CONF_DEF_MAGIC,
		"",
		sm_conf_type_union_choice,
		CAR,
		sizeof(vehicle_T),  "car", 0,
		car_definitions
	},

	/* sentinel */
	{ SM_CONF_DEF_MAGIC, NULL }
};

#if 0
static sm_conf_definition_T
vehicle_definitions[] =
{

	{ SM_CONF_DEF_MAGIC,
		"airplane",
		sm_conf_type_union_choice,
		AIRPLANE,
		sizeof(vehicle_T),  NULL, 0,
		air_definitions
	},

	{ SM_CONF_DEF_MAGIC,
		"boat",
		sm_conf_type_union_choice,
		BOAT,
		sizeof(vehicle_T), NULL, 0,
		boat_definitions
	},

	{ SM_CONF_DEF_MAGIC,
		"car",
		sm_conf_type_union_choice,
		CAR,
		sizeof(vehicle_T),  NULL, 0,
		car_definitions
	},

	/* sentinel */
	{ SM_CONF_DEF_MAGIC, NULL }
};
#endif /* 0 */

typedef struct
{
	vehicle_T	red;

} structure;

static sm_conf_definition_T const
definitions[] =
{

	{ SM_CONF_DEF_MAGIC, "red",
		sm_conf_type_union,
		offsetof(structure, red),
		sizeof(vehicle_T),
		NULL,
		0,
		vehicle_red_definitions,
		NULL,  NULL,
		"A red vehicle."
	},

	/* sentinel */
	{ SM_CONF_DEF_MAGIC, NULL }
};

static void
print_vehicle(vehicle_T const *v)
{
	switch (v->type)
	{
	  case AIRPLANE:
		printf("airplane { flight=%s passengers=%d }\n",
			v->airplane.air_flight == NULL
				? "(null)" : v->airplane.air_flight,
			v->airplane.air_passengers);
		break;
	  case BOAT:
		printf("boat { knots=%d name=%s }\n",
			v->boat.boat_knots,
			v->boat.boat_name == NULL
				? "(null)" : v->boat.boat_name);
		break;
	  case CAR:
		printf("car { mpg=%d plate=%s }\n",
			v->car.car_mpg,
			v->car.car_plate == NULL ? "(null)" : v->car.car_plate);
		break;
	  default:
		printf("<unexpected type %d>\n", (int)v->type);
		break;
	}
}

static void
print_structure(structure *s)
{
	print_vehicle(&s->red);
}

static int
process(char const *name, FILE *fp)
{
	sm_conf_T		*stream;
	int			err;
	structure		s;

	if (((stream = sm_conf_new(name ? name : "*stdin*"))) == NULL)
	{
		fprintf(stderr, "error -- sm_conf_new() returns NULL!\n");
		return 1;
	}
	if ((err = sm_conf_read_FILE(stream, name, fp)) != 0)
	{
		char buf[SM_CONF_ERROR_BUFFER_SIZE];
		char const *e = NULL;

		fprintf(stderr, "%s: %s\n",
			name ? name : "*stdin*",
			sm_conf_strerror(err, buf, sizeof buf));

		while ((e = sm_conf_syntax_error(stream, e)) != NULL)
			fprintf(stderr, "%s\n", e);

		sm_conf_destroy(stream);
		return 2;
	}

	memset(&s, 0, sizeof(s));
	err = sm_conf_scan(stream, definitions, 0, &s);
	if (err != 0)
	{
		char buf[SM_CONF_ERROR_BUFFER_SIZE];
		char const *e = NULL;

		fprintf(stderr, "(while scanning) %s: %s\n",
			name ? name : "*stdin*",
			sm_conf_strerror(err, buf, sizeof buf));

		while ((e = sm_conf_syntax_error(stream, e)) != NULL)
			fprintf(stderr, "%s\n", e);

		sm_conf_destroy(stream);
		return 3;
	}

	print_structure(&s);
	sm_conf_destroy(stream);

	return 0;
}

int
main(int ac, char **av)
{
	int	ai;

	if (ac == 1)
		return process("*stdin*", stdin);

	for (ai = 1; ai < ac; ai++)
	{
		int ret = process(av[ai], NULL);
		if (ret != 0)
			return ret;
	}
	return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1