/*-
 * Copyright (c) 2008, 2012, 2016  Peter Pentchev
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <err.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "confget.h"
#include "confget_common.h"
#include "readaline.h"

/* Is conffile pointing to stdin? */
static bool	 is_stdin;

/***
 * Function:
 *	common_openfile		- open any type of file for reading
 * Inputs:
 *	None.
 * Returns:
 *	0 on success, -1 on error.
 * Modifies:
 *	Stores the opened file into conffile.
 */
void
common_openfile(void)
{
	if (filename == NULL)
		errx(1, "No configuration file name specified");
	if (strcmp(filename, "-") == 0) {
		conffile = stdin;
		is_stdin = true;
		return;
	}

	FILE * const ifp = fopen(filename, "r");
	if (ifp == NULL)
		err(1, "Opening the input file %s", filename);
	conffile = ifp;
	is_stdin = false;
}

/***
 * Function:
 *	common_openfile_null	- do not open any file for methods that do not
 *				  take their input from files
 * Inputs:
 *	None.
 * Returns:
 *	Nothing.
 * Modifies:
 *	Stores a null value into conffile.
 */
void
common_openfile_null(void)
{
	conffile = NULL;
	is_stdin = false;
}

/***
 * Function:
 *	common_closefile	- close a scanned file
 * Inputs:
 *	None.
 * Returns:
 *	Nothing; exits on error.
 * Modifies:
 *	Closes the file pointed to by fp.
 */
void
common_closefile(void)
{
	if (conffile == NULL)
		return;
	if (!is_stdin)
		if (fclose(conffile) == EOF)
			err(1, "Could not close the config file");
	conffile = NULL;
}

/***
 * Function:
 *	confgetline		- read a line from a file
 * Inputs:
 *	fp			- the file to read from
 *	line			- a pointer to a location to store the line
 *	n			- the location to store the line length
 * Returns:
 *	The line pointer on success, NULL on error or EOF.
 * Modifies:
 *	Reallocates a buffer at *line to as much as needed.
 */
char *
confgetline(FILE * const fp, char ** const line, size_t * const len)
{
#if defined(HAVE_GETLINE)
	ssize_t r = getline(line, len, fp);
	if (r == -1)
		return (NULL);
	while (r > 0 && ((*line)[r - 1] == '\r' || (*line)[r - 1] == '\n'))
		(*line)[--r] = '\0';
	return (*line);
#elif defined(HAVE_FGETLN)
	size_t n;
	char * const p = fgetln(fp, &n);
	if (p == NULL)
		return (NULL);
	while (n > 0 && (p[n - 1] == '\r' || p[n - 1] == '\n'))
		n--;
	char *q;
	if (*line == NULL || *len < n + 1) {
		q = realloc(*line, n + 1);
		if (q == NULL)
			return (NULL);
		*line = q;
		*len = n + 1;
	} else {
		q = *line;
	}
	memcpy(q, p, n);
	q[n] = '\0';
	return (q);
#elif !defined(CONFGET_MAKEDEP)
#error Neither HAVE_GETLINE nor HAVE_FGETLN defined!
#endif
}
