/*
 *                            COPYRIGHT
 *
 *  tedax IO plugin - low level parser, similar to the reference implementation
 *  Copyright (C) 2023 Tibor 'Igor2' Palinkas
 *  pcb-rnd Copyright (C) 2017 Tibor 'Igor2' Palinkas
 *
 *  (Supported by NLnet NGI0 Entrust in 2023)
 *
 *  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.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 31 Milk Street, # 960789 Boston, MA 02196 USA.
 *
 *  Contact:
 *    Project page: http://repo.hu/projects/sch-rnd
 *    contact lead developer: http://www.repo.hu/projects/sch-rnd/contact.html
 *    mailing list: http://www.repo.hu/projects/sch-rnd/contact.html
 */


#include <libcschem/config.h>
#include <ctype.h>
#include <string.h>

#include "parse.h"
#include <librnd/core/error.h>
#include <librnd/core/compat_misc.h>

/* remove leading whitespace */
#define ltrim(s) while(isspace(*s)) s++

/* remove trailing newline;; trailing backslash is an error */
#define rtrim(s, slen) \
	do { \
		char *end; \
		for(end = s + slen - 1; (end >= s) && ((*end == '\r') || (*end == '\n')); end--) \
			*end = '\0'; \
		if ((end[0] == '\\') && ((end == s) || (end[-1] != '\\'))) \
			return -1; \
	} while(0)

static char *tedax_get_line_mem(char *dst, int dst_len, char **src, int *len_out)
{
	char *sep;
	int len;

	sep = strpbrk(*src, "\r\n");
	if (sep == NULL)
		len = strlen(*src);
	else
		len = sep - *src;

	if (len > dst_len) {
		/* line too long */
		return NULL;
	}

	memcpy(dst, *src, len);
	dst[len] = '\0';

	(*src) += len;
	while((**src == '\r')) (*src)++;
	if((**src == '\n')) (*src)++;

	*len_out = len;
	return dst;
}

int tedax_getline_mem(char **src, char *buff, int buff_size, char *argv[], int argv_size)
{
	int argc, len;

	for(;;) {
		char *s, *o;


		while(**src == '\r') (*src)++;

		if (**src == '\n') {
			(*src)++;
			goto empty; /* have to return empty line for line counting */
		}

		if (tedax_get_line_mem(buff, buff_size, src, &len) == NULL)
			return -1;

		s = buff;
		if (*s == '#') /* comment */
			goto empty;
		ltrim(s);
		rtrim(s, len);
		if (*s == '\0') /* empty line */
			goto empty;

		/* argv split */
		for(argc = 0, o = argv[0] = s; *s != '\0';) {
			if (*s == '\\') {
				s++;
				switch(*s) {
					case 'r': *o = '\r'; break;
					case 'n': *o = '\n'; break;
					case 't': *o = '\t'; break;
					default: *o = *s;
				}
				o++;
				s++;
				continue;
			}
			if ((argc+1 < argv_size) && ((*s == ' ') || (*s == '\t'))) {
				*o = *s = '\0';
				s++;
				o++;
				while((*s == ' ') || (*s == '\t'))
					s++;
				argc++;
				argv[argc] = o;
			}
			else {
				*o = *s;
				s++;
				o++;
			}
		}
		*o = '\0';
		return argc+1; /* valid line, split up */
	}

	return -1; /* can't get here */

	empty:;
	*buff = '\0';
	argv[0] = NULL;
	return 0;
}

