/*
 * Copyright (c) 2005 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: t-conf-6.c,v 1.2 2006/12/24 00:20:24 ca Exp $")

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

/*
**  Just a test program to play around with libconf.
**  union_choice
**  distinguish union types by a unique element in each part
*/

enum vehicle_type_E
{
	AIRPLANE       = 1,
	BOAT           = 2,
	CAR            = 3
};

typedef enum vehicle_type_E vehicle_type_T;
typedef union vehicle_U
{
	vehicle_type_T vehicle_type;

	struct
	{
	       vehicle_type_T   air_type;
	       char            *air_flight;
	       int              air_passengers;
	} airplane;

	struct
	{
	       vehicle_type_T   boat_type;
	       int              boat_knots;
	       char            *boat_name;
	} boat;

	struct
	{
	       vehicle_type_T   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 }
};

sm_conf_definition_T vehicle_definitions[] = {
	{ SM_CONF_DEF_MAGIC, "", sm_conf_type_union_type,
		offsetof(vehicle_T, vehicle_type),
		sizeof(vehicle_type_T)
	},
	{ SM_CONF_DEF_MAGIC, "flight", sm_conf_type_union_choice, AIRPLANE,
		sizeof(vehicle_T), /* default */ NULL, /* flags */ 0,
		air_definitions
	},
	{ SM_CONF_DEF_MAGIC, "name", sm_conf_type_union_choice, BOAT,
		sizeof(vehicle_T), /* default */ NULL, /* flags */ 0,
		boat_definitions
	},
	{ SM_CONF_DEF_MAGIC, "plate", sm_conf_type_union_choice, CAR,
		sizeof(vehicle_T), /* default */ NULL, /* flags */ 0,
		car_definitions
	},
	/* sentinel */
	{ SM_CONF_DEF_MAGIC, NULL }
};

typedef struct
{
	vehicle_T	 s_garage;
} mts_T;

sm_conf_definition_T
mts_def[] =
{
	{ SM_CONF_DEF_MAGIC, "vehicle", sm_conf_type_union,
		offsetof(mts_T, s_garage.vehicle_type),
		sizeof(vehicle_type_T),
		NULL, 0, vehicle_definitions
	},

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

static mts_T mts;

static void
print_mts(mts_T *st)
{
	switch (st->s_garage.vehicle_type)
	{
	  case AIRPLANE:
		printf("airplane=\"%s\"\n",
			st->s_garage.airplane.air_flight);
		break;
	  case BOAT:
		printf("boat=\"%s\"\n",
			st->s_garage.boat.boat_name);
		break;
	  case CAR:
		printf("car=\"%s\"\n",
			st->s_garage.car.car_plate);
		break;
	  default:
		break;
	}
}

static int
process(char const *name, FILE *fp, const char *ssname)
{
	sm_conf_T *stream;
	int err;
	char buf[SM_CONF_ERROR_BUFFER_SIZE];
	char const *e = NULL;

	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)
	{
		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;
	}

	if ((err = sm_conf_scan(stream, mts_def, 0, &mts)) != 0)
	{
		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_mts(&mts);

#if 0
	sm_conf_destroy(stream);
#endif /* 0 */

	return 0;
}

int
main(int ac, char **av)
{
	int ai, c, ret, done;
	char *ssname;

	done = 0;
	ssname = NULL;
	while ((c = getopt(ac, av, "f:N:o:v:")) != -1)
	{
		switch (c)
		{
		  case 'f':
			ret = process(optarg, NULL, ssname);
			if (ret != 0)
				return ret;
			done = 1;
			break;
		  case 'N':
			ssname = strdup(optarg);
			if (ssname == NULL)
				return ENOMEM;
			break;
		}
	}
	ac -= optind;
	av += optind;
	if (done)
	{
		print_mts(&mts);
		return 0;
	}

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

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


syntax highlighted by Code2HTML, v. 0.9.1