/*! \file msgfile.c
 * Parse a simple file with messages, e.g used for USSD messages. */
/*
 * (C) 2010 by Holger Hans Peter Freyther
 * (C) 2010 by On-Waves
 * All Rights Reserved
 *
 * SPDX-License-Identifier: GPL-2.0+
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */

#define _WITH_GETLINE

#include <osmocom/core/msgfile.h>
#include <osmocom/core/talloc.h>

#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>

static struct osmo_config_entry *
alloc_entry(struct osmo_config_list *entries,
	    const char *mcc, const char *mnc,
	    const char *option, const char *text)
{
	struct osmo_config_entry *entry =
		talloc_zero(entries, struct osmo_config_entry);
	if (!entry)
		return NULL;

	entry->mcc = talloc_strdup(entry, mcc);
	entry->mnc = talloc_strdup(entry, mnc);
	entry->option = talloc_strdup(entry, option);
	entry->text = talloc_strdup(entry, text);

	llist_add_tail(&entry->list, &entries->entry);
	return entry;
}

static struct osmo_config_list *alloc_entries(void *ctx)
{
	struct osmo_config_list *entries;

	entries = talloc_zero(ctx, struct osmo_config_list);
	if (!entries)
		return NULL;

	INIT_LLIST_HEAD(&entries->entry);
	return entries;
}

/*
 * split a line like 'foo:Text'.
 */
static void handle_line(struct osmo_config_list *entries, char *line)
{
	int i;
	const int len = strlen(line);

	char *items[3];
	int last_item = 0;

	/* Skip comments from the file */
	if (line[0] == '#')
		return;

	for (i = 0; i < len; ++i) {
		if (line[i] == '\n' || line[i] == '\r')
			line[i] = '\0';
		else if (line[i] == ':' && last_item < 3) {
			line[i] = '\0';

			items[last_item++] = &line[i + 1];
		}
	}

	if (last_item == 3) {
		alloc_entry(entries, &line[0] , items[0], items[1], items[2]);
		return;
	}

	/* nothing found */
}

struct osmo_config_list *osmo_config_list_parse(void *ctx, const char *filename)
{
	struct osmo_config_list *entries;
	size_t n;
	char *line;
	FILE *file;

	file = fopen(filename, "r");
	if (!file)
		return NULL;

	entries = alloc_entries(ctx);
	if (!entries) {
		fclose(file);
		return NULL;
	}

	n = 2342;
	line = NULL;
        while (getline(&line, &n, file) != -1) {
		handle_line(entries, line);
	}
	/* The returned getline() buffer needs to be freed even if it failed. It can simply re-use the
	 * buffer that was allocated on the first call. */
	free(line);

	fclose(file);
	return entries;
}
