/*
 * 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-title.c,v 1.2 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-TITLE.C -- how to store the title of a section in a variable */

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

typedef struct thing_S
{
	unsigned int	t_width, t_height, t_depth;
	char		*t_title;

} thing_T;

typedef struct stuff_S
{
	unsigned int	s_count;
	char		s_label[20];

} stuff_T;

typedef struct world_S
{
	stuff_T		*w_stuff;
	size_t		w_stuff_n;

	thing_T		*w_thing;
	size_t		w_thing_n;

} world_T;

static sm_conf_definition_T const
thing_contents[] =
{
	{ SM_CONF_DEF_MAGIC, "", sm_conf_type_section_title,
		offsetof(thing_T, t_title), 0, NULL,
		SM_CONF_FLAG_STRICTLY_REQUIRED
	},

	{ SM_CONF_DEF_MAGIC, "height", sm_conf_type_u32,
		offsetof(thing_T, t_height),
		sizeof(unsigned int), "1"
	},

	{ SM_CONF_DEF_MAGIC, "width", sm_conf_type_u32,
		offsetof(thing_T, t_width),
		sizeof(unsigned int), "1"
	},

	{ SM_CONF_DEF_MAGIC, "depth", sm_conf_type_u32,
		offsetof(thing_T, t_depth),
		sizeof(unsigned int), "1"
	},

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

static sm_conf_definition_T const
stuff_contents[] =
{
	{ SM_CONF_DEF_MAGIC, "", sm_conf_type_section_title,
		offsetof(stuff_T, s_label), 20, NULL
	},

	{ SM_CONF_DEF_MAGIC, "count", sm_conf_type_u32,
		offsetof(stuff_T, s_count),
		sizeof(unsigned int), "1"
	},

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

static sm_conf_definition_T const
stuff_array[] =
{

	{ SM_CONF_DEF_MAGIC, "stuff", sm_conf_type_section,
		offsetof(world_T, w_stuff), sizeof(stuff_T),
		NULL, 0, stuff_contents
	},

	{ SM_CONF_DEF_MAGIC, "", sm_conf_type_array_n,
		offsetof(world_T, w_stuff_n), sizeof(size_t)
	},

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

static sm_conf_definition_T const
thing_array[] =
{

	{ SM_CONF_DEF_MAGIC, "thing", sm_conf_type_section,
		offsetof(world_T, w_thing), sizeof(thing_T),
		NULL, 0, thing_contents
	},

	{ SM_CONF_DEF_MAGIC, "", sm_conf_type_array_n,
		offsetof(world_T, w_thing_n), sizeof(size_t)
	},

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

static sm_conf_definition_T const
world_definition[] =
{

	{ SM_CONF_DEF_MAGIC, "thing", sm_conf_type_array,
		0, 0, NULL, SM_CONF_FLAG_MULTIPLE, thing_array
	},

	{ SM_CONF_DEF_MAGIC, "stuff", sm_conf_type_array,
		0, 0, NULL, SM_CONF_FLAG_MULTIPLE, stuff_array
	},

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

static void
print_world(world_T const *w)
{
	size_t i;

	for (i = 0; i < w->w_stuff_n; i++)
	{
		printf("stuff \"%s\": %u\n",
			w->w_stuff[i].s_label,
			w->w_stuff[i].s_count);
	}

	for (i = 0; i < w->w_thing_n; i++)
	{
		printf("thing \"%s\": %u x %u x %u\n",
			w->w_thing[i].t_title != NULL
				? w->w_thing[i].t_title
				: "(null)",
			w->w_thing[i].t_width,
			w->w_thing[i].t_height,
			w->w_thing[i].t_depth);
	}
}

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

	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(&w, 0, sizeof(w));
	err = sm_conf_scan(stream, world_definition, 0, &w);
	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_world(&w);
	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