/*-
 * SPDX-FileCopyrightText: Peter Pentchev <roam@ringlet.net>
 * SPDX-License-Identifier: BSD-2-Clause
 */

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