/*
 * 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: tree.c,v 1.6 2004/09/01 18:30:03 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/sm-conf.h"
#include <stdio.h>
#endif /* SM_LIBCONF_ALONE */

/* TREE.C -- tree reader/dumper testbed. */

static int Verbose = 0;
static int Noquotes = 0;
static int Equations = 0;

static void
dump_entry(sm_conf_T *stream, sm_conf_node_T *node, int indent)
{
	char const	*name, *kw;
	size_t		name_n, kw_n;
	sm_conf_node_T	*sub;

	switch (sm_conf_node_type(stream, node))
	{
	  case SM_CONF_NODE_VALUE:
		if (Verbose > 1)
			fprintf(stderr, "value:\t");
		if (sm_conf_value(stream, node, &name, &name_n))
		{
			fprintf(stderr, "%p: can't get node value!\n",
				(void *)node);
			exit(1);
		}
		if (Noquotes)
			printf("%.*s", (int)name_n, name);
		else
			printf("\"%.*s\"", (int)name_n, name);
		break;

	  case SM_CONF_NODE_LIST:
		if (Verbose > 1)
			fprintf(stderr, "list:\t");
		switch (sm_conf_list_n(stream, node))
		{
		  case 0:
			printf("{}");
			break;

		  case 1:
			printf("{ ");
			dump_entry(stream,
				sm_conf_list_next(stream, node, NULL),
				indent + 2);
			printf(" }");
			break;

		  default:
			printf("{\n");
			sub = NULL;
			while ((sub = sm_conf_list_next(stream, node, sub))
			      != NULL)
			{
				printf("%*s", indent + 2, "");
				dump_entry(stream, sub, indent + 2);
				printf(",\n");
			}
			printf("%*s}", indent, "");
			break;
		}
		break;

	  case SM_CONF_NODE_SECTION:
		if (Verbose > 1)
			fprintf(stderr, "section:\t");
		if (  sm_conf_section_name(stream, node, &name, &name_n)
		   || sm_conf_section_keyword(stream, node, &kw, &kw_n))
		{
			fprintf(stderr, "%p: can't get section name?\n",
				(void*)node);
			return;
		}
		if (Equations)
		{
			if (kw != NULL)
				printf("section=%.*s\n", (int)kw_n, kw);
			if (name != NULL)
				printf("title=\"%.*s\"\n", (int)name_n, name);
		}
		else
		{
			if (kw != NULL)
				printf("%.*s ", (int)kw_n, kw);
			if (name != NULL)
				printf("\"%.*s\" ", (int)name_n, name);
		}

		putchar('{');
		putchar('\n');

		sub = NULL;
		while ((sub = sm_conf_section_next(stream, node,
			&name, &name_n, sub)) != NULL)
		{
			printf("%*s", indent + 2, "");
			if (name != NULL)
				printf("%.*s = ", (int)name_n, name);
			dump_entry(stream, sub, indent + 2);
			printf(";\n");
		}
		printf("%*s}", indent, "");
		break;
	}
}


static void
dump_root(sm_conf_T *stream, sm_conf_node_T *node)
{
	char const	*name;
	size_t		name_n;
	sm_conf_node_T	*sub;

	sub = NULL;
	while ((sub = sm_conf_section_next(stream, node, &name, &name_n, sub))
		!= NULL)
	{
		if (name != NULL)
			printf("%.*s = ", (int)name_n, name);
		dump_entry(stream, sub, 0);
		printf(";\n");
	}
}

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

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

	node = sm_conf_root(stream);
	if (node != NULL)
		dump_root(stream, node);

	sm_conf_destroy(stream);
	return 0;
}

int
main(int argc, char **argv)
{
	int	ai, r;

	while ((r = getopt(argc, argv, "eqV")) != -1)
	{
		switch (r)
		{
		  case 'e':
			Equations++;
			break;
		  case 'q':
			Noquotes++;
			break;
		  case 'V':
			Verbose++;
			break;
		  default:
/*
			usage(argv[0]);
*/
			return 1;
		}
	}

	argc -= optind;
	argv += optind;

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

	for (ai = 0; ai < argc; ai++)
	{
		int ret;

		ret = process(argv[ai], NULL);
		if (ret != 0)
			return ret;
	}
	return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1