lwip-1.4.1 (partial)

Dependents:   IGLOO_board

http-server/cparser.c

Committer:
ua1arn
Date:
2018-07-24
Revision:
1:119c4f7144c8

File content as of revision 1:119c4f7144c8:

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 by Sergey Fetisov <fsenok@gmail.com>
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/*
 * version: 1.0 demo (7.02.2015)
 */

#include "cparser.h"

void parser_init(parser_t *p, const char *str, int len)
{
	p->buff = NULL;
	p->buff_size = 0;
	p->user_data = NULL;
	p->read_cb = NULL;
	p->total = 0;
	p->line = 0;
	p->col = 0;
	p->priv.curr = str;
	p->priv.stop = str + len;
}

void parser_init_s(parser_t *p, char *stream_buff, size_t size, parser_read_t cb)
{
	p->buff = stream_buff;
	p->buff_size = size;
	p->user_data = NULL;
	p->read_cb = cb;
	p->total = 0;
	p->line = 0;
	p->col = 0;
	p->priv.curr = NULL;
	p->priv.stop = NULL;
}

bool parser_provide_space(parser_t *p, int size)
{
	int allow;
	allow = p->priv.stop - p->priv.curr;
	if (allow >= size) return true;
	if (p->buff == NULL || p->buff_size < size) return false;
	memmove(p->buff, p->priv.stop - allow, allow);
	size = p->read_cb(p, p->buff + allow, p->buff_size - allow);
	p->priv.curr = p->buff;
	p->priv.stop = p->buff + allow + size;
	return true;
}

bool parser_is_next(parser_t *p, const char *str, int len)
{
	if (!parser_provide_space(p, len)) return false;
	return memcmp(p->priv.curr, str, len) == 0;
}

static bool query_data(parser_t *p)
{
	size_t size = p->read_cb(p, p->buff, p->buff_size);
	p->priv.curr = p->buff;
	p->priv.stop = p->buff + size;
	return size > 0;
}

#define INC_POS                 \
	p->total++;                 \
	p->col++;                   \
	if (*p->priv.curr == '\n')  \
	{                           \
		p->line++;              \
		p->col = 0;             \
	}                           \
	p->priv.curr++;

#define CHECK_STATE()                                       \
	eof = false;                                            \
	if (p->priv.curr == p->priv.stop)                       \
		eof = p->buff == NULL ? true : !query_data(p);

char parser_curr(parser_t *p)
{
	bool eof;
	CHECK_STATE();
	return eof ? 0 : *p->priv.curr;
}

bool parser_eof(parser_t *p)
{
	bool eof;
	CHECK_STATE();
	return eof;
}

int parser_read(parser_t *p, const chatset_t chatset, char *dest, int dest_size)
{
	bool eof;
	register int c;
	int res = 0;
	while (true)
	{
		CHECK_STATE();
		if (eof) break;
		c = (unsigned)*p->priv.curr;
		if (!chatset[c]) break;
		if (res < dest_size - 1)
			dest[res] = c;
		res++;
		INC_POS;
	}
	if (res >= dest_size)
		dest[dest_size - 1] = 0; else
		dest[res] = 0;
	return res;
}

int parser_read_before2(parser_t *p, char *dest, int dest_size, char c1, char c2)
{
	bool eof;
	register int cc;
	int res = 0;
	while (true)
	{
		CHECK_STATE();
		if (eof) break;
		cc = *p->priv.curr;
		if (cc == c1 || cc == c2) break;
		if (res < dest_size)
			dest[res] = cc;
		res++;
		INC_POS;
	}
	if (res >= dest_size)
		dest[dest_size - 1] = 0; else
		dest[res] = 0;
	return res;
}

int parser_read_digits(parser_t *p, char *dest, int dest_size, bool hex)
{
	bool eof;
	register int c;
	int res = 0;
	while (true)
	{
		bool done;
		CHECK_STATE();
		if (eof) break;
		c = (unsigned)*p->priv.curr;
		done = false;
		done |= c >= '0' && c <= '9';
		done |= hex && (c >= 'a' && c <= 'f');
		done |= hex && (c >= 'A' && c <= 'F');
		if (!done) break;
		if (res < dest_size - 1)
			dest[res] = c;
		res++;
		INC_POS;
	}
	if (res >= dest_size)
		dest[dest_size - 1] = 0; else
		dest[res] = 0;
	return res;
}

int parser_read_value(parser_t *p, char *dest, int dest_size, int fmt)
{
// state:     0    1   2    3   4   5   6     7
//         1234567
//         1234567          e       2
//         1234567          e   -   2
//             345 . 1234   e   +   4
//               0 . 1234   e   +   4
//               0 x                   ABCD
//               0 h                   ABCD
//               0 b                         0110

	bool eof;
	register int c;
	int res;
	int state;
	char last;

	res = 0;
	state = 0;

	while (true)
	{
		CHECK_STATE();
		if (eof) break;
		c = *p->priv.curr;

		if (state == 0 || state == 2 || state == 5)
		{
			if (c >= '0' && c <= '9')
			{
				if (res < dest_size) dest[res] = c;
				last = c;
				INC_POS;
				res++;
				continue;
			}
			if (state == 0 && c == '.' && (fmt & VAL_FMT_FLOAT))
			{
				if (res < dest_size) dest[res] = c;
				INC_POS;
				res++;
				state = 2;
				continue;
			}
			if ((state == 0 || state == 2) && (c == 'e' || c == 'E') && (fmt & VAL_FMT_FLOAT))
			{
				if (res < dest_size) dest[res] = c;
				INC_POS;
				res++;
				state = 4;
				continue;
			}
			if (state == 0 && last == '0' && res == 1)
			{
				if (((fmt & VAL_FMT_0H) && (c == 'H' || c == 'h')) || ((c == 'x' || c == 'X') && (fmt & VAL_FMT_0X)))
				{
					if (res < dest_size) dest[res] = c;
					INC_POS;
					res++;
					state = 6;
					continue;
				}
				if ((fmt & VAL_FMT_0B) && (c == 'b' || c == 'B'))
				{
					if (res < dest_size) dest[res] = c;
					INC_POS;
					res++;
					state = 7;
					continue;
				}
			}
			if ((fmt & VAL_FMT_SIGN) && res == 0 && (c == '+' || c == '-'))
			{
				if (res < dest_size) dest[res] = c;
				INC_POS;
				res++;
				continue;
			}
		}
		if (state == 4)
		{
			if (c == '+' || c == '-')
			{
				if (res < dest_size) dest[res] = c;
				INC_POS;
				res++;
			}
			state = 5;
			continue;
		}
		if (state == 6)
		{
			if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'))
			{
				if (res < dest_size) dest[res] = c;
				INC_POS;
				res++;
				continue;
			}
		}
		if (state == 7)
		{
			if (c == '0' || c == '1')
			{
				if (res < dest_size) dest[res] = c;
				INC_POS;
				res++;
				continue;
			}
		}
		break;
	}
	if (res >= dest_size)
		dest[dest_size - 1] = 0; else
		dest[res] = 0;
	return res;
}

#define is_ident_char(c)      \
	(c == '_' ||              \
	(c >= '0' && c <= '9') || \
	(c >= 'a' && c <= 'z') || \
	(c >= 'a' && c <= 'z'))

int parser_read_string(parser_t *p, char *dest, int dest_size, int fmt)
{
// state:     0     1    2      3         4     5
//               string
//            '  string                         '
//            "  string                         "
//            '  str     \                      '
//            '  str     \    rntbf\/"          '
//            '  str     \    u                 '
//            '  str     \    u                 '
//            '  str     \    u         12AB    '
	bool eof;
	register int c;
	int res;
	int state;
	char first;

	res = 0;
	state = 0;
	first = 0;

	while (true)
	{
		CHECK_STATE();
		if (eof) break;
		c = *p->priv.curr;

		if (state == 0 && (((fmt & STR_FMT_QUOTE) && c == '"') || ((fmt & STR_FMT_APOST) && c == '\'')))
		{
			first = c;
			state = 1;
			INC_POS;
			continue;
		}

		if (state == 0 && (fmt & STR_FMT_NAKED))
		{
			state = 1;
			continue;
		}

		if (state == 1 && c == first)
		{
			INC_POS;
			break;
		}

		if (state == 1 && first == 0 && is_ident_char(c)) // reading naked
		{
			if (res < dest_size) dest[res] = c;
			INC_POS;
			res++;
			continue;
		}

		if (state == 1 && (fmt & STR_FMT_ESC) && c == '\\')
		{
			state = 3;
			INC_POS;
			continue;
		}

		if (state == 1 && first != 0)
		{
			if (res < dest_size) dest[res] = c;
			INC_POS;
			res++;
			continue;
		}

		if (state == 3 && (fmt & STR_FMT_ESCU) && c == 'u')
		{
			state = 4;
			INC_POS;
			continue;
		}

		if (state == 3)
		{
			char e;
			switch (c)
			{
			case 'r': e = '\r'; break;
			case 'n': e = '\n'; break;
			case 't': e = '\t'; break;
			case 'b': e = '\b'; break;
			case 'f': e = '\f'; break;
			case '\\': e = '\\'; break;
			case '/': e = '/'; break;
			case '"': e = '"'; break;
			default:
				if (res < dest_size) dest[res] = '\\';
				res++;
				e = c;
				break;
			}
			state = 1;
			if (res < dest_size) dest[res] = e;
			INC_POS;
			res++;
			continue;
		}

		if (state == 4)
		{
		}

		break;
	}
	if (res >= dest_size)
		dest[dest_size - 1] = 0; else
		dest[res] = 0;
	return res;
}

int parser_skip(parser_t *p, const chatset_t chatset)
{
	bool eof;
	register int c;
	int res = 0;
	while (true)
	{
		CHECK_STATE();
		if (eof) break;
		c = (unsigned)*p->priv.curr;
		if (!chatset[(uint8_t)c]) break;
		res++;
		INC_POS;
	}
	return res;
}

int parser_skip_n(parser_t *p, int n)
{
	bool eof;
	int i;
	for (i = 0; i < n; i++)
	{
		CHECK_STATE();
		if (eof) return i;
		INC_POS;
	}
	return n;
}

bool parser_skip_char(parser_t *p, char c)
{
	bool eof;
	CHECK_STATE();
	if (*p->priv.curr != c || eof) return false;
	INC_POS;
	return true;
}

bool parser_skip_ws(parser_t *p)
{
	bool eof;
	bool res = false;
	while (true)
	{
		CHECK_STATE();
		if (eof) return res;
		if (*p->priv.curr > 0x20) return res;
		res = true;
		INC_POS;
	}
}

bool parser_skip_ws_in_line(parser_t *p)
{
	bool eof;
	bool res = false;
	while (true)
	{
		CHECK_STATE();
		if (eof) return res;
		if (*p->priv.curr > 0x20 || *p->priv.curr == '\r' || *p->priv.curr == '\n')
			return res;
		res = true;
		INC_POS;
	}
}

bool parser_skip_line(parser_t *p)
{
	bool eof;
	while (true)
	{
		CHECK_STATE();
		if (eof) return false;
		if (*p->priv.curr == '\n')
		{
			INC_POS;
			return true;
		}
		INC_POS;
	}
}

bool parser_skip_before(parser_t *p, char c)
{
	bool eof;
	while (true)
	{
		CHECK_STATE();
		if (eof) return false;
		if (*p->priv.curr == c) return true;
		INC_POS;
	}
}