/*
 * 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-readfile.c,v 1.3 2007/05/20 15:41:56 ca Exp $")

#if SM_LIBCONF_ALONE
#include <limits.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <ctype.h>
#include <stdio.h>
#include <stdarg.h>
#include "sm-conf.h"
#include "sm-util.h"
#else /* SM_LIBCONF_ALONE */
#include "sm/limits.h"
#include "sm/string.h"
#include "sm/assert.h"
#include "sm/error.h"
#include "sm/ctype.h"
#include "sm/heap.h"
#include "sm/memops.h"
#include "sm/sm-conf.h"
#endif /* SM_LIBCONF_ALONE */

#include "sm-conf-state.h"
#include "sm-conf-token.h"
#include "sm-conf-parse.h"

/* SM-CONF.C -- high-level API functions */

/* Chunk size for reading input */
#define SMC_BLOCK_SIZE	(1024 * 16)

/*
**  SM_CONF_READ_FILE -- read configuration text from a file pointer
**
**	The application can either open a file itself or
**	have this function open it for the application and close it
**	after reading.
**
**	Parameters:
**		smc -- configuration state with a read configuration file
**		name -- name of file to open or NULL
**		fp -- file pointer of pre-opened file or NULL.
**
**	Returns:
**		0 on success,
**		otherwise an errno or SM_CONF_ERR_... error number.
*/

int
sm_conf_read_FILE(sm_conf_T *smc, char const *name, FILE *fp)
{
	bool	close_fp;
	size_t	cc;

	close_fp = false;
	if (smc == NULL || (name == NULL && fp == NULL))
		return SM_CONF_ERR_INVALID;

	SM_IS_CONF(smc);
	if (name != NULL && fp == NULL)
	{
		if ((fp = fopen(name, "r")) == NULL)
		{
			if (errno != 0)
				return errno;
			return SM_CONF_ERR_READ_OPEN;
		}
		close_fp = true;
	}

	smc->smc_buf_n = 0;

	do
	{
		if (smc->smc_buf_n >= smc->smc_buf_m)
		{
			if (smc->smc_buf_m == 0)
			{
				smc->smc_buf = sm_malloc(SMC_BLOCK_SIZE);
				if (smc->smc_buf == NULL)
				{
					if (close_fp)
						(void)fclose(fp);
					return ENOMEM;
				}
				smc->smc_mybuf = true;
				smc->smc_buf_m = SMC_BLOCK_SIZE;
			}
			else
			{
				void *tmp;

				tmp = sm_realloc(smc->smc_buf,
					smc->smc_buf_m + SMC_BLOCK_SIZE);
				if (tmp == NULL)
				{
					if (close_fp)
						(void)fclose(fp);
					return ENOMEM;
				}
				smc->smc_buf = tmp;
				smc->smc_buf_m +=  SMC_BLOCK_SIZE;
			}
		}
		cc = fread(smc->smc_buf + smc->smc_buf_n, 1,
				smc->smc_buf_m - smc->smc_buf_n, fp);
		if (cc == 0)
			break;
		smc->smc_buf_n += cc;

	} while (cc > 0 && !feof(fp));

	if (ferror(fp))
	{
		fprintf(stderr, "%s: byte %lu: error reading "
			"from configuration file: %s\n",
			smc->smc_name,
			(unsigned long)smc->smc_buf_n,
			strerror(errno));
		if (close_fp)
			(void)fclose(fp);
		return SM_CONF_ERR_READ;
	}

	if (close_fp)
	{
		if (fclose(fp))
		{
			fprintf(stderr,
				"%s: error closing configuration file: %s\n",
				smc->smc_name, strerror(errno));
			return -1;
		}
	}

	return sm_conf_parse(smc);
}


syntax highlighted by Code2HTML, v. 0.9.1