/*
 * 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: sm-conf-prttree.c,v 1.2 2004/08/26 22:18:55 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 "sm/sm-conf-prt.h"
#include "sm/io.h"
#endif /* SM_LIBCONF_ALONE */

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

sm_ret_T
sm_conf_dump_entry(sm_conf_T *stream, sm_conf_node_T *node, int indent, sm_file_T *fp)
{
	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)
			sm_io_fprintf(smioerr, "value:\t");
		if (sm_conf_value(stream, node, &name, &name_n))
		{
			sm_io_fprintf(smioerr, "%p: can't get node value!\n",
				(void *)node);
			return 1;
		}
		if (Noquotes)
			sm_io_fprintf(fp, "%.*s", (int)name_n, name);
		else
			sm_io_fprintf(fp, "\"%.*s\"", (int)name_n, name);
		break;

	  case SM_CONF_NODE_LIST:
		if (Verbose > 1)
			sm_io_fprintf(smioerr, "list:\t");
		switch (sm_conf_list_n(stream, node))
		{
		  case 0:
			sm_io_fprintf(fp, "{}");
			break;

		  case 1:
			sm_io_fprintf(fp, "{ ");
			sm_conf_dump_entry(stream,
				sm_conf_list_next(stream, node, NULL),
				indent + 2, fp);
			sm_io_fprintf(fp, " }");
			break;

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

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

		if (name != NULL)
			sm_io_fprintf(fp, "\"%.*s\" ", (int)name_n, name);

		sm_io_fprintf(fp, "{\n");

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

void
sm_conf_dump_root(sm_conf_T *stream, sm_conf_node_T *node, sm_file_T *fp)
{
	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)
			sm_io_fprintf(fp, "%.*s = ", (int)name_n, name);
		sm_conf_dump_entry(stream, sub, 0, fp);
		sm_io_fprintf(fp, ";\n");
	}
}

#if STANDALONE
static int
sm_conf_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)
	{
		sm_io_fprintf(smioerr, "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;

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

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

		sm_conf_destroy(stream);
		return 2;
	}

	node = sm_conf_root(stream);
	if (node != NULL)
		sm_conf_dump_root(stream, node, smioout);

	sm_conf_destroy(stream);
	return 0;
}

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

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

	argc -= optind;
	argv += optind;

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

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

		ret = sm_conf_process(argv[ai], NULL);
		if (ret != 0)
			return ret;
	}
	return 0;
}
#endif /* STANDALONE */


syntax highlighted by Code2HTML, v. 0.9.1