/*
 * Copyright (c) 2004-2006 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-prtdef.c,v 1.12 2007/06/10 16:03:55 ca Exp $")

#include "sm/string.h"
#include "sm/sm-conf.h"
#include "sm/sm-conf-prt.h"
#include "sm-conf-type.h"
#include "sm/io.h"
#include "sm/util.h"
#include "prtcnf.h"

/* show configuration definition */

/*
**  SM_CONF_PRT_DEF -- print defaults for one node
**
**	Parameters:
**		def -- configuration definition.
**		flags -- flags
**		fp -- file for output
**		indent -- current indentation
**		text -- if not NULL: print this if something is printed
**			in this invocation
**
**	Returns:
**		0: didn't print anything
**		>0: something has been printed
**
**	Note: this doesn't deal with all types! FIXME!
*/

static int
sm_conf_prt_def(const sm_conf_definition_T *def, uint flags, sm_file_T *fp, int indent, sm_str_P text)
{
	const sm_conf_type_T *scdtype;
	int ret;
	sm_file_T *sfp;
	sm_file_T text_file;

	SM_IS_CONF_DEF(def);
	scdtype = def->scd_type;
	if (scdtype == NULL)
		return 0;
	ret = 0;
	sfp = NULL;

#define PRT_COMMENT(fp)	\
	do		\
	{		\
		if (def->scd_description != NULL &&	\
		    *(def->scd_description) != '\0')	\
		{					\
			prt_fmtted((fp), indent, "# ", def->scd_description); \
		}					\
	} while (0)

#define PRT_TEXT	\
	do		\
	{		\
		if (text != NULL && sm_str_getlen(text) > 0)	\
		{						\
			sm_io_fprintf(fp, "%S", text);		\
			sm_str_clr(text);			\
		}						\
	} while (0)

#define TEXT2FP	\
	do	\
	{	\
		if (text != NULL)	\
		{	\
			/* currently doesn't fail; check?? */	\
			(void) sm_str2file(text, &text_file);	\
			sfp = &text_file;	\
		}	\
		else	\
		{	\
			PRT_TEXT;	\
			sfp = fp;	\
		}	\
	} while (0)

	if (SM_IS_FLAG(def->scd_flags, SM_CONF_FLAG_DPRCD))
		return 0;
	if (scdtype == sm_conf_type_section)
	{
		int r;

		TEXT2FP;
		PRT_COMMENT(sfp);
		sm_io_fprintf(sfp, "\n%*s%s {\n"
			, indent, ""
			, def->scd_name);
		r = sm_conf_prt_defs(def->scd_contents, flags, fp, indent + 2,
				text);
		if (r > 0)
		{
			sm_io_fprintf(fp, "%*s}\n"
				, indent, "");
			ret += r;
		}

		/*
		**  This doesn't work for nested sections!
		**  we "just" need to get back to the old text
		*/

		if (text != NULL)
			sm_str_clr(text);

	}
	else if (scdtype == sm_conf_type_string && def->scd_default != NULL)
	{
		PRT_TEXT;
		PRT_COMMENT(fp);
		sm_io_fprintf(fp, "%*s%s=\"%s\";\n"
			, indent, ""
			, def->scd_name
			, def->scd_default);
		ret = 1;
	}
	else if (scdtype == sm_conf_type_union)
	{
		const sm_conf_definition_T *union_def;

		union_def = def->scd_contents;
		if (union_def != NULL
		    && union_def->scd_type == sm_conf_type_union_type)
		{
			int choice_type;
			bool found;
			ptrdiff_t offtype;
			const sm_conf_definition_T *union_choice_def;

			offtype = union_def->scd_offset;

			/* fixme: how to find the right size for the type?? */
			choice_type = 0;	/* default???? */
#if 0
			if (def->scd_default != NULL)
				/* scan default, assign it to choice_type?? */;
#endif
			found = false;
			union_choice_def = union_def + 1;
			while (union_choice_def != NULL
			       && union_choice_def->sm_magic
				  == SM_CONF_DEF_MAGIC
			       && union_choice_def->scd_name != NULL
			       && union_choice_def->scd_type
				  == sm_conf_type_union_choice
			       && !found
			      )
			{
			       if ((int) union_choice_def->scd_offset
				   == choice_type)
					found = true;
				else
					++union_choice_def;
			}
			if (found)
			{
				int r;

				PRT_TEXT;
				PRT_COMMENT(fp);
				sm_io_fprintf(fp, "%*s%s {\n"
					, indent, ""
					, def->scd_name);
				r = sm_conf_prt_defs(
					union_choice_def->scd_contents, flags,
					fp, indent + 2, text);
				sm_io_fprintf(fp, "%*s}\n"
					, indent, "");
				if (r > 0)
					ret += r;
			}
		}
	}
	else if (scdtype == sm_conf_type_choice &&
		 SM_IS_FLAG(flags, SMC_FLD_FLAGS))
	{
		/*
		**  When can we actually print this?
		**  Only if the section doesn't contain a required selection,
		**  otherwise the created output is not a valid conf file.
		*/

		uint32_t u;

		u = 0xffffffff;
		/* scan def->scd_default? */
		if (u != 0 &&
		    (def->scd_flags & SM_CONF_FLAG_MULTIPLE) != 0)
		{
			PRT_TEXT;
			PRT_COMMENT(fp);
			sm_io_fprintf(fp, "%*s# %s={ # possible values:\n"
				, indent, ""
				, def->scd_name);
			(void) sm_conf_sub2valbit(def->scd_contents,
					NULL, u, "# flag: ", "\n",
					indent + 2, fp);
			sm_io_fprintf(fp, "%*s# }\n", indent, "");
			ret = 1;
		}
		else if (u != 0 &&
		    (def->scd_flags & SM_CONF_FLAG_OR) != 0)
		{
			PRT_TEXT;
			PRT_COMMENT(fp);
			sm_io_fprintf(fp, "%*s# %s= # select one of:\n"
				, indent, ""
				, def->scd_name);
			(void) sm_conf_sub2valbit(def->scd_contents,
					NULL, u, "# flag:", "\n",
					indent + 2, fp);
			ret = 1;
		}
		else if (u != 0)
		{
			PRT_TEXT;
			PRT_COMMENT(fp);
			sm_io_fprintf(fp, "%*s# %s=\n"
				, indent, ""
				, def->scd_name);
			(void) sm_conf_sub2valeq(def->scd_contents,
					NULL, u, fp);
			sm_io_fprintf(fp, "\n");
			ret = 1;
		}
	}
	else if (def->scd_default != NULL)
	{
		PRT_TEXT;
		PRT_COMMENT(fp);
		sm_io_fprintf(fp, "%*s%s=%s;\n"
			, indent, ""
			, def->scd_name
			, def->scd_default);
		ret = 1;
	}
	else
	{
		TEXT2FP;
		PRT_COMMENT(sfp);
		sm_io_fprintf(sfp, "%*s# %s %s not set by default\n"
			, indent, ""
			, def->scd_name
			, ((def->scd_flags & SM_CONF_FLAG_PLURAL) != 0)
				? "are" : "is"
			);
	}
	return ret;
}

/*
**  SM_CONF_PRT_DEFS -- print default values of configuration definition
**
**	Parameters:
**		def -- configuration definition.
**		fp -- file for output
**		indent -- current indentation
**		text -- if not NULL: print this if something is printed
**			in this invocation
**
**	Returns:
**		SM_SUCCESS
*/

int
sm_conf_prt_defs(const sm_conf_definition_T *defs, uint flags, sm_file_T *fp, int indent, sm_str_P text)
{
	const sm_conf_definition_T *def;
	int r, ret;

	ret = 0;
	while ((def = defs++) != NULL && def->scd_name != NULL)
	{
		SM_IS_CONF_DEF(def);
		r = sm_conf_prt_def(def, flags, fp, indent, text);
		if (r > 0)
			ret += r;
	}
	return ret;
}

/*
**  SM_CONF_PRT_DFLT -- print default values of configuration definition
**	(wrapper for sm_conf_prt_defs())
**
**	Parameters:
**		def -- configuration definition.
**		fp -- file for output
**
**	Returns:
**		SM_SUCCESS or ENOMEM
*/

sm_ret_T
sm_conf_prt_dflt(const sm_conf_definition_T *defs, uint flags, sm_file_T *fp)
{
	int ret;
	sm_str_P sect_text;

	sect_text = sm_str_new(NULL, 256, 8 * 1024);
	if (sect_text == NULL)
		return sm_err_temp(ENOMEM);
	ret = sm_conf_prt_defs(defs, flags, fp, 0, sect_text);
	SM_STR_FREE(sect_text);
	return ret;
}


syntax highlighted by Code2HTML, v. 0.9.1