Code import
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
/* Copyright (c) 2002, Marek Michalkiewicz
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of the copyright holders nor the names of
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 "avrlibc.h"
|
||||
|
||||
int
|
||||
avr_atoi(const char *p)
|
||||
{
|
||||
return (int) avr_atol(p);
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/* Copyright (c) 2002, Marek Michalkiewicz
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of the copyright holders nor the names of
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 <stdlib.h>
|
||||
#include "avrlibc.h"
|
||||
|
||||
long
|
||||
avr_atol(const char *p)
|
||||
{
|
||||
return avr_strtol(p, (char **) NULL, 10);
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
/* Copyright (c) 2002-2005 Michael Stumpf <mistumpf@de.pepperl-fuchs.com>
|
||||
Copyright (c) 2006,2008 Dmitry Xmelkov
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of the copyright holders nor the names of
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. */
|
||||
|
||||
/* $Id: strtod.c 2191 2010-11-05 13:45:57Z arcanum $ */
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <math.h> /* INFINITY, NAN */
|
||||
#include <strings.h>
|
||||
#include <stdint.h>
|
||||
#include "avrlibc.h"
|
||||
|
||||
/* Only GCC 4.2 calls the library function to convert an unsigned long
|
||||
to float. Other GCC-es (including 4.3) use a signed long to float
|
||||
conversion along with a large inline code to correct the result. */
|
||||
extern double __floatunsisf (unsigned long);
|
||||
|
||||
static const float pwr_p10 [6] = {
|
||||
1e+1, 1e+2, 1e+4, 1e+8, 1e+16, 1e+32
|
||||
};
|
||||
static const float pwr_m10 [6] = {
|
||||
1e-1, 1e-2, 1e-4, 1e-8, 1e-16, 1e-32
|
||||
};
|
||||
|
||||
/* PSTR() is not used to save 1 byte per string: '\0' at the tail. */
|
||||
static const char pstr_inf[] = {'I','N','F'};
|
||||
static const char pstr_inity[] = {'I','N','I','T','Y'};
|
||||
static const char pstr_nan[] = {'N','A','N'};
|
||||
|
||||
/** The strtod() function converts the initial portion of the string pointed
|
||||
to by \a nptr to double representation.
|
||||
|
||||
The expected form of the string is an optional plus ( \c '+' ) or minus
|
||||
sign ( \c '-' ) followed by a sequence of digits optionally containing
|
||||
a decimal-point character, optionally followed by an exponent. An
|
||||
exponent consists of an \c 'E' or \c 'e', followed by an optional plus
|
||||
or minus sign, followed by a sequence of digits.
|
||||
|
||||
Leading white-space characters in the string are skipped.
|
||||
|
||||
The strtod() function returns the converted value, if any.
|
||||
|
||||
If \a endptr is not \c NULL, a pointer to the character after the last
|
||||
character used in the conversion is stored in the location referenced by
|
||||
\a endptr.
|
||||
|
||||
If no conversion is performed, zero is returned and the value of
|
||||
\a nptr is stored in the location referenced by \a endptr.
|
||||
|
||||
If the correct value would cause overflow, plus or minus \c INFINITY is
|
||||
returned (according to the sign of the value), and \c ERANGE is stored
|
||||
in \c errno. If the correct value would cause underflow, zero is
|
||||
returned and \c ERANGE is stored in \c errno.
|
||||
*/
|
||||
|
||||
double
|
||||
avr_strtod (const char * nptr, char ** endptr)
|
||||
{
|
||||
union {
|
||||
unsigned long u32;
|
||||
float flt;
|
||||
} x;
|
||||
unsigned char c;
|
||||
int exp;
|
||||
|
||||
unsigned char flag;
|
||||
#define FL_MINUS 0x01 /* number is negative */
|
||||
#define FL_ANY 0x02 /* any digit was readed */
|
||||
#define FL_OVFL 0x04 /* overflow was */
|
||||
#define FL_DOT 0x08 /* decimal '.' was */
|
||||
#define FL_MEXP 0x10 /* exponent 'e' is neg. */
|
||||
|
||||
if (endptr)
|
||||
*endptr = (char *)nptr;
|
||||
|
||||
do {
|
||||
c = *nptr++;
|
||||
} while (c!=0&&c<=' ');
|
||||
|
||||
flag = 0;
|
||||
if (c == '-') {
|
||||
flag = FL_MINUS;
|
||||
c = *nptr++;
|
||||
} else if (c == '+') {
|
||||
c = *nptr++;
|
||||
}
|
||||
|
||||
if (!strncasecmp(nptr - 1, pstr_inf, 3)) {
|
||||
nptr += 2;
|
||||
if (!strncasecmp(nptr, pstr_inity, 5))
|
||||
nptr += 5;
|
||||
if (endptr)
|
||||
*endptr = (char *)nptr;
|
||||
return flag & FL_MINUS ? -INFINITY : +INFINITY;
|
||||
}
|
||||
|
||||
/* NAN() construction is not realised.
|
||||
Length would be 3 characters only. */
|
||||
if (!strncasecmp(nptr - 1, pstr_nan, 3)) {
|
||||
if (endptr)
|
||||
*endptr = (char *)nptr + 2;
|
||||
return NAN;
|
||||
}
|
||||
|
||||
x.u32 = 0;
|
||||
exp = 0;
|
||||
while (1) {
|
||||
|
||||
c -= '0';
|
||||
|
||||
if (c <= 9) {
|
||||
flag |= FL_ANY;
|
||||
if (flag & FL_OVFL) {
|
||||
if (!(flag & FL_DOT))
|
||||
exp += 1;
|
||||
} else {
|
||||
if (flag & FL_DOT)
|
||||
exp -= 1;
|
||||
/* x.u32 = x.u32 * 10 + c */
|
||||
x.u32 = (((x.u32 << 2) + x.u32) << 1) + c;
|
||||
if (x.u32 >= (ULONG_MAX - 9) / 10)
|
||||
flag |= FL_OVFL;
|
||||
}
|
||||
|
||||
} else if (c == (('.'-'0') & 0xff) && !(flag & FL_DOT)) {
|
||||
flag |= FL_DOT;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
c = *nptr++;
|
||||
}
|
||||
|
||||
if (c == (('e'-'0') & 0xff) || c == (('E'-'0') & 0xff))
|
||||
{
|
||||
int i;
|
||||
c = *nptr++;
|
||||
i = 2;
|
||||
if (c == '-') {
|
||||
flag |= FL_MEXP;
|
||||
c = *nptr++;
|
||||
} else if (c == '+') {
|
||||
c = *nptr++;
|
||||
} else {
|
||||
i = 1;
|
||||
}
|
||||
c -= '0';
|
||||
if (c > 9) {
|
||||
nptr -= i;
|
||||
} else {
|
||||
i = 0;
|
||||
do {
|
||||
if (i < 3200)
|
||||
i = (((i << 2) + i) << 1) + c; /* i = 10*i + c */
|
||||
c = *nptr++ - '0';
|
||||
} while (c <= 9);
|
||||
if (flag & FL_MEXP)
|
||||
i = -i;
|
||||
exp += i;
|
||||
}
|
||||
}
|
||||
|
||||
if ((flag & FL_ANY) && endptr)
|
||||
*endptr = (char *)nptr - 1;
|
||||
|
||||
x.flt = __floatunsisf (x.u32); /* manually */
|
||||
if ((flag & FL_MINUS) && (flag & FL_ANY))
|
||||
x.flt = -x.flt;
|
||||
|
||||
if (x.flt != 0) {
|
||||
int pwr;
|
||||
if (exp < 0) {
|
||||
nptr = (void *)(pwr_m10 + 5);
|
||||
exp = -exp;
|
||||
} else {
|
||||
nptr = (void *)(pwr_p10 + 5);
|
||||
}
|
||||
for (pwr = 32; pwr; pwr >>= 1) {
|
||||
for (; exp >= pwr; exp -= pwr) {
|
||||
union {
|
||||
unsigned long u32;
|
||||
float flt;
|
||||
} y;
|
||||
y.u32 = (uint32_t) *((float *)nptr);
|
||||
x.flt *= y.flt;
|
||||
}
|
||||
nptr -= sizeof(float);
|
||||
}
|
||||
if (!isfinite(x.flt) || x.flt == 0)
|
||||
errno = ERANGE;
|
||||
}
|
||||
|
||||
return x.flt;
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
/*-
|
||||
* Copyright (c) 1990, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* Copyright (c) 2005, Dmitry Xmelkov
|
||||
*
|
||||
* 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.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
|
||||
*
|
||||
* $Id: strtol.c 1944 2009-04-01 23:12:20Z arcanum $
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
|
||||
/*
|
||||
* Convert a string to a long integer.
|
||||
*
|
||||
* Ignores `locale' stuff. Assumes that the upper and lower case
|
||||
* alphabets and digits are each contiguous.
|
||||
*/
|
||||
long
|
||||
avr_strtol(const char *nptr, char **endptr, register int base)
|
||||
{
|
||||
register unsigned long acc;
|
||||
register unsigned char c;
|
||||
register unsigned long cutoff;
|
||||
register signed char any;
|
||||
unsigned char flag = 0;
|
||||
#define FL_NEG 0x01 /* number is negative */
|
||||
#define FL_0X 0x02 /* number has a 0x prefix */
|
||||
|
||||
if (endptr)
|
||||
*endptr = (char *)nptr;
|
||||
if (base != 0 && (base < 2 || base > 36))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Skip white space and pick up leading +/- sign if any.
|
||||
* If base is 0, allow 0x for hex and 0 for octal, else
|
||||
* assume decimal; if base is already 16, allow 0x.
|
||||
*/
|
||||
do {
|
||||
c = *nptr++;
|
||||
} while (c!=0&&c<=' ');
|
||||
if (c == '-') {
|
||||
flag = FL_NEG;
|
||||
c = *nptr++;
|
||||
} else if (c == '+')
|
||||
c = *nptr++;
|
||||
if ((base == 0 || base == 16) &&
|
||||
c == '0' && (*nptr == 'x' || *nptr == 'X')) {
|
||||
c = nptr[1];
|
||||
nptr += 2;
|
||||
base = 16;
|
||||
flag |= FL_0X;
|
||||
}
|
||||
if (base == 0)
|
||||
base = c == '0' ? 8 : 10;
|
||||
|
||||
/*
|
||||
* Compute the cutoff value between legal numbers and illegal
|
||||
* numbers. That is the largest legal value, divided by the
|
||||
* base. An input number that is greater than this value, if
|
||||
* followed by a legal input character, is too big. One that
|
||||
* is equal to this value may be valid or not; the decision
|
||||
* about this is done as outlined below.
|
||||
*
|
||||
* Overflow detections works as follows:
|
||||
*
|
||||
* As:
|
||||
* acc_old <= cutoff
|
||||
* then:
|
||||
* acc_old * base <= 0x80000000 (unsigned)
|
||||
* then:
|
||||
* acc_old * base + c <= 0x80000000 + c
|
||||
* or:
|
||||
* acc_new <= 0x80000000 + 35
|
||||
*
|
||||
* i.e. carry from MSB (by calculating acc_new) is impossible
|
||||
* and we can check result directly:
|
||||
*
|
||||
* if (acc_new > 0x80000000) then overflow
|
||||
*
|
||||
* Set any if any `digits' consumed; make it negative to indicate
|
||||
* overflow.
|
||||
*/
|
||||
#if LONG_MIN != -LONG_MAX - 1
|
||||
# error "This implementation of strtol() does not work on this platform."
|
||||
#endif
|
||||
switch (base) {
|
||||
case 10:
|
||||
cutoff = ((unsigned long)LONG_MAX + 1) / 10;
|
||||
break;
|
||||
case 16:
|
||||
cutoff = ((unsigned long)LONG_MAX + 1) / 16;
|
||||
break;
|
||||
case 8:
|
||||
cutoff = ((unsigned long)LONG_MAX + 1) / 8;
|
||||
break;
|
||||
case 2:
|
||||
cutoff = ((unsigned long)LONG_MAX + 1) / 2;
|
||||
break;
|
||||
default:
|
||||
cutoff = ((unsigned long)LONG_MAX + 1) / base;
|
||||
}
|
||||
|
||||
for (acc = 0, any = 0;; c = *nptr++) {
|
||||
if (c >= '0' && c <= '9')
|
||||
c -= '0';
|
||||
else if (c >= 'A' && c <= 'Z')
|
||||
c -= 'A' - 10;
|
||||
else if (c >= 'a' && c <= 'z')
|
||||
c -= 'a' - 10;
|
||||
else
|
||||
break;
|
||||
if (c >= base)
|
||||
break;
|
||||
if (any < 0)
|
||||
continue;
|
||||
if (acc > cutoff) {
|
||||
any = -1;
|
||||
continue;
|
||||
}
|
||||
acc = acc * base + c;
|
||||
if (acc > (unsigned long)LONG_MAX + 1)
|
||||
any = -1;
|
||||
else
|
||||
any = 1;
|
||||
}
|
||||
if (endptr) {
|
||||
if (any)
|
||||
*endptr = (char *)nptr - 1;
|
||||
else if (flag & FL_0X)
|
||||
*endptr = (char *)nptr - 2;
|
||||
}
|
||||
if (any < 0) {
|
||||
acc = (flag & FL_NEG) ? LONG_MIN : LONG_MAX;
|
||||
errno = ERANGE;
|
||||
} else if (flag & FL_NEG) {
|
||||
acc = -acc;
|
||||
} else if ((signed long)acc < 0) {
|
||||
acc = LONG_MAX;
|
||||
errno = ERANGE;
|
||||
}
|
||||
return (acc);
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright (c) 1990, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* Copyright (c) 2005, Dmitry Xmelkov
|
||||
*
|
||||
* 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.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
|
||||
*
|
||||
* $Id: strtoul.c 1944 2009-04-01 23:12:20Z arcanum $
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
#include "avrlibc.h"
|
||||
|
||||
/*
|
||||
* Convert a string to an unsigned long integer.
|
||||
*
|
||||
* Ignores `locale' stuff. Assumes that the upper and lower case
|
||||
* alphabets and digits are each contiguous.
|
||||
*/
|
||||
unsigned long
|
||||
avr_strtoul(const char *nptr, char **endptr, register int base)
|
||||
{
|
||||
register unsigned long acc;
|
||||
register unsigned char c;
|
||||
register unsigned long cutoff;
|
||||
register signed char any;
|
||||
unsigned char flag = 0;
|
||||
#define FL_NEG 0x01 /* number is negative */
|
||||
#define FL_0X 0x02 /* number has a 0x prefix */
|
||||
|
||||
if (endptr)
|
||||
*endptr = (char *)nptr;
|
||||
if (base != 0 && (base < 2 || base > 36))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* See strtol for comments as to the logic used.
|
||||
*/
|
||||
do {
|
||||
c = *nptr++;
|
||||
} while (c!=0&&c<=' ');
|
||||
if (c == '-') {
|
||||
flag = FL_NEG;
|
||||
c = *nptr++;
|
||||
} else if (c == '+')
|
||||
c = *nptr++;
|
||||
if ((base == 0 || base == 16) &&
|
||||
c == '0' && (*nptr == 'x' || *nptr == 'X')) {
|
||||
c = nptr[1];
|
||||
nptr += 2;
|
||||
base = 16;
|
||||
flag |= FL_0X;
|
||||
}
|
||||
if (base == 0)
|
||||
base = c == '0' ? 8 : 10;
|
||||
|
||||
/*
|
||||
* cutoff computation is similar to strtol().
|
||||
*
|
||||
* Description of the overflow detection logic used.
|
||||
*
|
||||
* First, let us assume an overflow.
|
||||
*
|
||||
* Result of `acc_old * base + c' is cut to 32 bits:
|
||||
* acc_new <-- acc_old * base + c - 0x100000000
|
||||
*
|
||||
* `acc_old * base' is <= 0xffffffff (cutoff control)
|
||||
*
|
||||
* then: acc_new <= 0xffffffff + c - 0x100000000
|
||||
*
|
||||
* or: acc_new <= c - 1
|
||||
*
|
||||
* or: acc_new < c
|
||||
*
|
||||
* Second:
|
||||
* if (no overflow) then acc * base + c >= c
|
||||
* (or: acc_new >= c)
|
||||
* is clear (alls are unsigned).
|
||||
*
|
||||
*/
|
||||
switch (base) {
|
||||
case 16: cutoff = ULONG_MAX / 16; break;
|
||||
case 10: cutoff = ULONG_MAX / 10; break;
|
||||
case 8: cutoff = ULONG_MAX / 8; break;
|
||||
default: cutoff = ULONG_MAX / base;
|
||||
}
|
||||
|
||||
for (acc = 0, any = 0;; c = *nptr++) {
|
||||
if (c >= '0' && c <= '9')
|
||||
c -= '0';
|
||||
else if (c >= 'A' && c <= 'Z')
|
||||
c -= 'A' - 10;
|
||||
else if (c >= 'a' && c <= 'z')
|
||||
c -= 'a' - 10;
|
||||
else
|
||||
break;
|
||||
if (c >= base)
|
||||
break;
|
||||
if (any < 0)
|
||||
continue;
|
||||
if (acc > cutoff) {
|
||||
any = -1;
|
||||
continue;
|
||||
}
|
||||
acc = acc * base + c;
|
||||
any = (c > acc) ? -1 : 1;
|
||||
}
|
||||
|
||||
if (endptr) {
|
||||
if (any)
|
||||
*endptr = (char *)nptr - 1;
|
||||
else if (flag & FL_0X)
|
||||
*endptr = (char *)nptr - 2;
|
||||
}
|
||||
if (flag & FL_NEG)
|
||||
acc = -acc;
|
||||
if (any < 0) {
|
||||
acc = ULONG_MAX;
|
||||
errno = ERANGE;
|
||||
}
|
||||
return (acc);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// Created by MightyPork on 2017/11/26.
|
||||
//
|
||||
|
||||
#ifndef GEX_AVRLIBC_H_H
|
||||
#define GEX_AVRLIBC_H_H
|
||||
|
||||
int avr_atoi(const char *p);
|
||||
long avr_strtol(const char *nptr, char **endptr, register int base);
|
||||
long avr_atol(const char *p);
|
||||
double avr_strtod (const char * nptr, char ** endptr);
|
||||
unsigned long avr_strtoul(const char *nptr, char **endptr, register int base);
|
||||
|
||||
#endif //GEX_AVRLIBC_H_H
|
||||
Executable
+5
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "-- Building parser from Ragel source --"
|
||||
|
||||
ragel -L -G0 ini_parser.rl -o ini_parser.c
|
||||
@@ -0,0 +1,177 @@
|
||||
/**
|
||||
* @file circular_buffer.c
|
||||
* @brief Implementation of a circular buffer
|
||||
*
|
||||
* DAPLink Interface Firmware
|
||||
* Copyright (c) 2016-2016, ARM Limited, All Rights Reserved
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "platform.h"
|
||||
#include "circ_buf.h"
|
||||
|
||||
void circ_buf_init(circ_buf_t *circ_buf, uint8_t *buffer, uint32_t size)
|
||||
{
|
||||
vPortEnterCritical();
|
||||
{
|
||||
circ_buf->buf = buffer;
|
||||
circ_buf->size = size;
|
||||
circ_buf->head = 0;
|
||||
circ_buf->tail = 0;
|
||||
}
|
||||
vPortExitCritical();
|
||||
}
|
||||
|
||||
static void push_do(circ_buf_t *circ_buf, uint8_t data)
|
||||
{
|
||||
circ_buf->buf[circ_buf->tail] = data;
|
||||
circ_buf->tail += 1;
|
||||
if (circ_buf->tail >= circ_buf->size) {
|
||||
assert_param(circ_buf->tail == circ_buf->size);
|
||||
circ_buf->tail = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool circ_buf_push_try(circ_buf_t *circ_buf, uint8_t data)
|
||||
{
|
||||
bool success;
|
||||
vPortEnterCritical();
|
||||
{
|
||||
if (circ_buf_count_free(circ_buf) == 0) {
|
||||
success = false;
|
||||
goto quit;
|
||||
}
|
||||
|
||||
push_do(circ_buf, data);
|
||||
success = true;
|
||||
}
|
||||
quit:
|
||||
vPortExitCritical();
|
||||
return success;
|
||||
}
|
||||
|
||||
void circ_buf_push(circ_buf_t *circ_buf, uint8_t data)
|
||||
{
|
||||
vPortEnterCritical();
|
||||
{
|
||||
push_do(circ_buf, data);
|
||||
// Assert no overflow
|
||||
assert_param(circ_buf->head != circ_buf->tail);
|
||||
}
|
||||
vPortExitCritical();
|
||||
}
|
||||
|
||||
static uint8_t pop_do(circ_buf_t *circ_buf)
|
||||
{
|
||||
uint8_t data;
|
||||
data = circ_buf->buf[circ_buf->head];
|
||||
circ_buf->head += 1;
|
||||
if (circ_buf->head >= circ_buf->size) {
|
||||
assert_param(circ_buf->head == circ_buf->size);
|
||||
circ_buf->head = 0;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
uint8_t circ_buf_pop(circ_buf_t *circ_buf)
|
||||
{
|
||||
uint8_t data;
|
||||
|
||||
vPortEnterCritical();
|
||||
{
|
||||
// Assert buffer isn't empty
|
||||
assert_param(circ_buf->head != circ_buf->tail);
|
||||
data = pop_do(circ_buf);
|
||||
}
|
||||
vPortExitCritical();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
bool circ_buf_pop_try(circ_buf_t *circ_buf, uint8_t *data)
|
||||
{
|
||||
bool success;
|
||||
vPortEnterCritical();
|
||||
{
|
||||
if (circ_buf->head == circ_buf->tail) {
|
||||
success = false;
|
||||
goto quit;
|
||||
}
|
||||
|
||||
*data = pop_do(circ_buf);
|
||||
success = true;
|
||||
}
|
||||
quit:
|
||||
vPortExitCritical();
|
||||
return success;
|
||||
}
|
||||
|
||||
uint32_t circ_buf_count_used(circ_buf_t *circ_buf)
|
||||
{
|
||||
uint32_t cnt;
|
||||
|
||||
vPortEnterCritical();
|
||||
{
|
||||
if (circ_buf->tail >= circ_buf->head) {
|
||||
cnt = circ_buf->tail - circ_buf->head;
|
||||
} else {
|
||||
cnt = circ_buf->tail + circ_buf->size - circ_buf->head;
|
||||
}
|
||||
}
|
||||
vPortExitCritical();
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
uint32_t circ_buf_count_free(circ_buf_t *circ_buf)
|
||||
{
|
||||
uint32_t cnt;
|
||||
|
||||
vPortEnterCritical();
|
||||
{
|
||||
cnt = circ_buf->size - circ_buf_count_used(circ_buf) - 1;
|
||||
}
|
||||
vPortExitCritical();
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
uint32_t circ_buf_read(circ_buf_t *circ_buf, uint8_t *data, uint32_t size)
|
||||
{
|
||||
uint32_t cnt;
|
||||
uint32_t i;
|
||||
|
||||
cnt = circ_buf_count_used(circ_buf);
|
||||
cnt = MIN(size, cnt);
|
||||
for (i = 0; i < cnt; i++) {
|
||||
data[i] = circ_buf_pop(circ_buf);
|
||||
}
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
uint32_t circ_buf_write(circ_buf_t *circ_buf, const uint8_t *data, uint32_t size)
|
||||
{
|
||||
uint32_t cnt;
|
||||
uint32_t i;
|
||||
|
||||
cnt = circ_buf_count_free(circ_buf);
|
||||
cnt = MIN(size, cnt);
|
||||
for (i = 0; i < cnt; i++) {
|
||||
circ_buf_push(circ_buf, data[i]);
|
||||
}
|
||||
|
||||
return cnt;
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* @file circ_buf.h
|
||||
* @brief Implementation of a circular buffer
|
||||
*
|
||||
* DAPLink Interface Firmware
|
||||
* Copyright (c) 2016-2016, ARM Limited, All Rights Reserved
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef CIRC_BUF_H
|
||||
#define CIRC_BUF_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
uint32_t head;
|
||||
uint32_t tail;
|
||||
uint32_t size;
|
||||
uint8_t *buf;
|
||||
} circ_buf_t;
|
||||
|
||||
// Initialize or reinitialize a circular buffer
|
||||
void circ_buf_init(circ_buf_t *circ_buf, uint8_t *buffer, uint32_t size);
|
||||
|
||||
// Push a byte into the circular buffer
|
||||
void circ_buf_push(circ_buf_t *circ_buf, uint8_t data);
|
||||
|
||||
// Return a byte from the circular buffer
|
||||
uint8_t circ_buf_pop(circ_buf_t *circ_buf);
|
||||
|
||||
// try to read the buffer, return false if empty
|
||||
bool circ_buf_pop_try(circ_buf_t *circ_buf, uint8_t *data);
|
||||
|
||||
// try to write the buffer, return false if full
|
||||
bool circ_buf_push_try(circ_buf_t *circ_buf, uint8_t data);
|
||||
|
||||
// Get the number of bytes in the circular buffer
|
||||
uint32_t circ_buf_count_used(circ_buf_t *circ_buf);
|
||||
|
||||
// Get the number of free spots left in the circular buffer
|
||||
uint32_t circ_buf_count_free(circ_buf_t *circ_buf);
|
||||
|
||||
// Attempt to read size bytes from the buffer. Return the number of bytes read
|
||||
uint32_t circ_buf_read(circ_buf_t *circ_buf, uint8_t *data, uint32_t size);
|
||||
|
||||
// Attempt to write size bytes to the buffer. Return the number of bytes written
|
||||
uint32_t circ_buf_write(circ_buf_t *circ_buf, const uint8_t *data, uint32_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// Created by MightyPork on 2017/11/26.
|
||||
//
|
||||
|
||||
#ifndef GEX_CORTEX_UTILS_H
|
||||
#define GEX_CORTEX_UTILS_H
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
static inline bool inIRQ(void)
|
||||
{
|
||||
return __get_IPSR() != 0;
|
||||
}
|
||||
|
||||
register char *__SP asm("sp");
|
||||
|
||||
static inline bool isDynAlloc(const void *obj)
|
||||
{
|
||||
// this is the 0x20000000-something address that should correspond to heap bottom
|
||||
extern char heapstart __asm("end");
|
||||
|
||||
return ((uint32_t)obj >= (uint32_t)&heapstart)
|
||||
&& ((uint32_t)obj < (uint32_t)__SP);
|
||||
}
|
||||
|
||||
#endif //GEX_CORTEX_UTILS_H
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* @file error.c
|
||||
* @brief Implementation of error.h
|
||||
*
|
||||
* DAPLink Interface Firmware
|
||||
* Copyright (c) 2009-2016, ARM Limited, All Rights Reserved
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
static const char *const error_message[] = {
|
||||
#define X(name, text) text,
|
||||
X_ERROR_CODES
|
||||
#undef X
|
||||
};
|
||||
COMPILER_ASSERT(ERROR_COUNT == ELEMENTS_IN_ARRAY(error_message));
|
||||
|
||||
const char *error_get_string(error_t error)
|
||||
{
|
||||
const char *msg = 0;
|
||||
|
||||
if (error < ERROR_COUNT) {
|
||||
msg = error_message[error];
|
||||
}
|
||||
|
||||
if (0 == msg) {
|
||||
assert_param(0);
|
||||
msg = "";
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* @file error.h
|
||||
* @brief collection of known errors and accessor for the friendly string
|
||||
*
|
||||
* DAPLink Interface Firmware
|
||||
* Copyright (c) 2009-2016, ARM Limited, All Rights Reserved
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ERROR_H
|
||||
#define ERROR_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#define X_ERROR_CODES \
|
||||
/* Shared errors */ \
|
||||
X(SUCCESS,"OK") \
|
||||
X(FAILURE,"Failure") \
|
||||
X(INTERNAL,"Internal error") \
|
||||
X(LOADING,"Init in progress") \
|
||||
\
|
||||
/* VFS user errors */ \
|
||||
X(ERROR_DURING_TRANSFER,"Error during transfer") \
|
||||
X(TRANSFER_TIMEOUT,"Transfer timed out") \
|
||||
/*X(FILE_BOUNDS,"Possible mismatch between file size and size programmed")*/ \
|
||||
X(OOO_SECTOR,"File sent out of order by PC") \
|
||||
\
|
||||
/* File stream errors */ \
|
||||
X(SUCCESS_DONE,"End of stream") \
|
||||
X(SUCCESS_DONE_OR_CONTINUE,"End of stream, or more to come") \
|
||||
\
|
||||
/* Unit loading */ \
|
||||
X(BAD_CONFIG, "Configuration error") \
|
||||
X(OUT_OF_MEM, "Not enough RAM") \
|
||||
X(RESOURCE_NOT_AVAILABLE, "Required pin / peripheral not available")
|
||||
|
||||
// Keep in sync with the list error_message
|
||||
typedef enum {
|
||||
#define X(name, text) E_##name,
|
||||
X_ERROR_CODES
|
||||
#undef X
|
||||
ERROR_COUNT
|
||||
} error_t;
|
||||
|
||||
const char *error_get_string(error_t error) __attribute__((pure));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,57 @@
|
||||
//
|
||||
// Created by MightyPork on 2017/12/04.
|
||||
//
|
||||
|
||||
#include "platform.h"
|
||||
#include "hexdump.h"
|
||||
|
||||
void hexDump(const char *restrict desc, const void *restrict addr, uint32_t len)
|
||||
{
|
||||
uint32_t i;
|
||||
uint8_t buff[17];
|
||||
uint8_t *pc = (unsigned char*)addr;
|
||||
|
||||
// Output description if given.
|
||||
if (desc != NULL)
|
||||
PRINTF ("%s:\r\n", desc);
|
||||
|
||||
if (len == 0) {
|
||||
PRINTF(" ZERO LENGTH\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Process every byte in the data.
|
||||
for (i = 0; i < len; i++) {
|
||||
// Multiple of 16 means new line (with line offset).
|
||||
|
||||
if ((i % 16) == 0) {
|
||||
// Just don't print ASCII for the zeroth line.
|
||||
if (i != 0)
|
||||
PRINTF (" %s\r\n", buff);
|
||||
|
||||
// Output the offset.
|
||||
PRINTF (" %04"PRIx32" ", i);
|
||||
}
|
||||
|
||||
// Now the hex code for the specific character.
|
||||
PRINTF (" %02x", pc[i]);
|
||||
|
||||
// And store a printable ASCII character for later.
|
||||
if ((pc[i] < 0x20) || (pc[i] > 0x7e))
|
||||
buff[i % 16] = '.';
|
||||
else
|
||||
buff[i % 16] = pc[i];
|
||||
buff[(i % 16) + 1] = '\0';
|
||||
}
|
||||
|
||||
// Pad out last line if not exactly 16 characters.
|
||||
while ((i % 16) != 0) {
|
||||
PRINTF (" ");
|
||||
i++;
|
||||
}
|
||||
|
||||
// And print the final ASCII bit.
|
||||
PRINTF (" %s\r\n", buff);
|
||||
|
||||
(void)buff;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// Created by MightyPork on 2017/12/04.
|
||||
//
|
||||
|
||||
#ifndef GEX_HEXDUMP_H
|
||||
#define GEX_HEXDUMP_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* HEXDUMP https://stackoverflow.com/a/7776146/2180189
|
||||
*
|
||||
* @param desc - description printed above the dump
|
||||
* @param addr - address to dump
|
||||
* @param len - number of bytes
|
||||
*/
|
||||
void hexDump(const char *restrict desc, const void *restrict addr, uint32_t len);
|
||||
|
||||
#endif //GEX_HEXDUMP_H
|
||||
@@ -0,0 +1,526 @@
|
||||
|
||||
/* #line 1 "ini_parser.rl" */
|
||||
|
||||
/* Ragel constants block */
|
||||
#include "ini_parser.h"
|
||||
|
||||
// Ragel setup
|
||||
|
||||
/* #line 10 "ini_parser.c" */
|
||||
static const char _ini_actions[] = {
|
||||
0, 1, 1, 1, 2, 1, 3, 1,
|
||||
4, 1, 5, 1, 6, 1, 7, 1,
|
||||
8, 1, 9, 1, 10, 1, 11, 1,
|
||||
13, 2, 0, 4, 2, 12, 4
|
||||
};
|
||||
|
||||
static const char _ini_eof_actions[] = {
|
||||
0, 23, 5, 5, 15, 15, 15, 15,
|
||||
19, 19, 0, 0, 0, 0, 0, 0,
|
||||
0
|
||||
};
|
||||
|
||||
static const int ini_start = 1;
|
||||
static const int ini_first_final = 12;
|
||||
static const int ini_error = 0;
|
||||
|
||||
static const int ini_en_section = 2;
|
||||
static const int ini_en_keyvalue = 4;
|
||||
static const int ini_en_comment = 8;
|
||||
static const int ini_en_discard2eol = 10;
|
||||
static const int ini_en_main = 1;
|
||||
|
||||
|
||||
/* #line 10 "ini_parser.rl" */
|
||||
|
||||
|
||||
// Persistent state
|
||||
static int8_t cs = -1; //!< Ragel's Current State variable
|
||||
static uint32_t buff_i = 0; //!< Write pointer for the buffers
|
||||
static char value_quote = 0; //!< Quote character of the currently collected value
|
||||
static bool value_nextesc = false; //!< Next character is escaped, trated specially, and if quote, as literal quote character
|
||||
static IniParserCallback keyCallback = NULL; //!< Currently assigned callback
|
||||
static void *userdata = NULL; //!< Currently assigned user data for the callback
|
||||
|
||||
// Buffers
|
||||
static char keybuf[INI_KEY_MAX];
|
||||
static char secbuf[INI_KEY_MAX];
|
||||
static char valbuf[INI_VALUE_MAX];
|
||||
|
||||
// See header for doxygen!
|
||||
|
||||
void
|
||||
ini_parse_reset_partial(void)
|
||||
{
|
||||
buff_i = 0;
|
||||
value_quote = 0;
|
||||
value_nextesc = false;
|
||||
}
|
||||
|
||||
void
|
||||
ini_parse_reset(void)
|
||||
{
|
||||
ini_parse_reset_partial();
|
||||
keybuf[0] = secbuf[0] = valbuf[0] = 0;
|
||||
|
||||
/* #line 67 "ini_parser.c" */
|
||||
{
|
||||
cs = ini_start;
|
||||
}
|
||||
|
||||
/* #line 41 "ini_parser.rl" */
|
||||
}
|
||||
|
||||
void
|
||||
ini_parser_error(const char* msg)
|
||||
{
|
||||
ini_error("Parser error: %s", msg);
|
||||
ini_parse_reset_partial();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ini_parse_begin(IniParserCallback callback, void *userData)
|
||||
{
|
||||
keyCallback = callback;
|
||||
userdata = userData;
|
||||
ini_parse_reset();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
*ini_parse_end(void)
|
||||
{
|
||||
ini_parse("\n", 1);
|
||||
if (keyCallback) {
|
||||
keyCallback = NULL;
|
||||
}
|
||||
|
||||
void *ud = userdata;
|
||||
userdata = NULL;
|
||||
return ud;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ini_parse_file(const char *text, size_t len, IniParserCallback callback, void *userData)
|
||||
{
|
||||
ini_parse_begin(callback, userData);
|
||||
ini_parse(text, len);
|
||||
ini_parse_end();
|
||||
}
|
||||
|
||||
static void
|
||||
rtrim_buf(char *buf, int32_t end)
|
||||
{
|
||||
if (end > 0) {
|
||||
while ((uint8_t)buf[--end] < 33);
|
||||
end++; // go past the last character
|
||||
}
|
||||
|
||||
buf[end] = 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ini_parse(const char *newstr, size_t len)
|
||||
{
|
||||
int32_t i;
|
||||
char c;
|
||||
bool isnl;
|
||||
bool isquot;
|
||||
|
||||
// Load new data to Ragel vars
|
||||
const uint8_t *p;
|
||||
const uint8_t *eof;
|
||||
const uint8_t *pe;
|
||||
|
||||
if (len == 0) while(newstr[++len] != 0); // alternative to strlen
|
||||
|
||||
p = (const uint8_t *) newstr;
|
||||
eof = NULL;
|
||||
pe = (const uint8_t *) (newstr + len);
|
||||
|
||||
// Init Ragel on the first run
|
||||
if (cs == -1) {
|
||||
ini_parse_reset();
|
||||
}
|
||||
|
||||
// The parser
|
||||
|
||||
/* #line 152 "ini_parser.c" */
|
||||
{
|
||||
const char *_acts;
|
||||
unsigned int _nacts;
|
||||
|
||||
if ( p == pe )
|
||||
goto _test_eof;
|
||||
if ( cs == 0 )
|
||||
goto _out;
|
||||
_resume:
|
||||
switch ( cs ) {
|
||||
case 1:
|
||||
switch( (*p) ) {
|
||||
case 32u: goto tr1;
|
||||
case 35u: goto tr3;
|
||||
case 58u: goto tr0;
|
||||
case 59u: goto tr3;
|
||||
case 61u: goto tr0;
|
||||
case 91u: goto tr4;
|
||||
}
|
||||
if ( (*p) < 9u ) {
|
||||
if ( (*p) <= 8u )
|
||||
goto tr0;
|
||||
} else if ( (*p) > 13u ) {
|
||||
if ( 14u <= (*p) && (*p) <= 31u )
|
||||
goto tr0;
|
||||
} else
|
||||
goto tr1;
|
||||
goto tr2;
|
||||
case 0:
|
||||
goto _out;
|
||||
case 12:
|
||||
goto tr0;
|
||||
case 2:
|
||||
switch( (*p) ) {
|
||||
case 9u: goto tr6;
|
||||
case 32u: goto tr6;
|
||||
case 93u: goto tr5;
|
||||
}
|
||||
if ( (*p) <= 31u )
|
||||
goto tr5;
|
||||
goto tr7;
|
||||
case 3:
|
||||
if ( (*p) == 93u )
|
||||
goto tr8;
|
||||
if ( (*p) > 8u ) {
|
||||
if ( 10u <= (*p) && (*p) <= 31u )
|
||||
goto tr5;
|
||||
} else
|
||||
goto tr5;
|
||||
goto tr7;
|
||||
case 13:
|
||||
goto tr5;
|
||||
case 4:
|
||||
switch( (*p) ) {
|
||||
case 10u: goto tr10;
|
||||
case 58u: goto tr11;
|
||||
case 61u: goto tr11;
|
||||
}
|
||||
goto tr9;
|
||||
case 5:
|
||||
switch( (*p) ) {
|
||||
case 9u: goto tr13;
|
||||
case 10u: goto tr14;
|
||||
case 13u: goto tr15;
|
||||
case 32u: goto tr13;
|
||||
}
|
||||
goto tr12;
|
||||
case 6:
|
||||
switch( (*p) ) {
|
||||
case 10u: goto tr14;
|
||||
case 13u: goto tr15;
|
||||
}
|
||||
goto tr12;
|
||||
case 14:
|
||||
goto tr10;
|
||||
case 7:
|
||||
if ( (*p) == 10u )
|
||||
goto tr14;
|
||||
goto tr10;
|
||||
case 8:
|
||||
switch( (*p) ) {
|
||||
case 10u: goto tr17;
|
||||
case 13u: goto tr18;
|
||||
}
|
||||
goto tr16;
|
||||
case 15:
|
||||
goto tr19;
|
||||
case 9:
|
||||
if ( (*p) == 10u )
|
||||
goto tr17;
|
||||
goto tr19;
|
||||
case 10:
|
||||
switch( (*p) ) {
|
||||
case 10u: goto tr21;
|
||||
case 13u: goto tr22;
|
||||
}
|
||||
goto tr20;
|
||||
case 16:
|
||||
goto tr23;
|
||||
case 11:
|
||||
if ( (*p) == 10u )
|
||||
goto tr21;
|
||||
goto tr23;
|
||||
}
|
||||
|
||||
tr23: cs = 0; goto _again;
|
||||
tr0: cs = 0; goto f0;
|
||||
tr5: cs = 0; goto f4;
|
||||
tr10: cs = 0; goto f7;
|
||||
tr19: cs = 0; goto f11;
|
||||
tr1: cs = 1; goto _again;
|
||||
tr6: cs = 2; goto _again;
|
||||
tr7: cs = 3; goto f5;
|
||||
tr9: cs = 4; goto f8;
|
||||
tr13: cs = 5; goto _again;
|
||||
tr11: cs = 5; goto f9;
|
||||
tr12: cs = 6; goto f10;
|
||||
tr15: cs = 7; goto _again;
|
||||
tr16: cs = 8; goto _again;
|
||||
tr18: cs = 9; goto _again;
|
||||
tr20: cs = 10; goto _again;
|
||||
tr22: cs = 11; goto _again;
|
||||
tr2: cs = 12; goto f1;
|
||||
tr3: cs = 12; goto f2;
|
||||
tr4: cs = 12; goto f3;
|
||||
tr8: cs = 13; goto f6;
|
||||
tr14: cs = 14; goto f10;
|
||||
tr17: cs = 15; goto f12;
|
||||
tr21: cs = 16; goto f13;
|
||||
|
||||
f5: _acts = _ini_actions + 1; goto execFuncs;
|
||||
f6: _acts = _ini_actions + 3; goto execFuncs;
|
||||
f4: _acts = _ini_actions + 5; goto execFuncs;
|
||||
f1: _acts = _ini_actions + 7; goto execFuncs;
|
||||
f8: _acts = _ini_actions + 9; goto execFuncs;
|
||||
f9: _acts = _ini_actions + 11; goto execFuncs;
|
||||
f10: _acts = _ini_actions + 13; goto execFuncs;
|
||||
f7: _acts = _ini_actions + 15; goto execFuncs;
|
||||
f12: _acts = _ini_actions + 17; goto execFuncs;
|
||||
f11: _acts = _ini_actions + 19; goto execFuncs;
|
||||
f13: _acts = _ini_actions + 21; goto execFuncs;
|
||||
f0: _acts = _ini_actions + 23; goto execFuncs;
|
||||
f3: _acts = _ini_actions + 25; goto execFuncs;
|
||||
f2: _acts = _ini_actions + 28; goto execFuncs;
|
||||
|
||||
execFuncs:
|
||||
_nacts = *_acts++;
|
||||
while ( _nacts-- > 0 ) {
|
||||
switch ( *_acts++ ) {
|
||||
case 0:
|
||||
/* #line 130 "ini_parser.rl" */
|
||||
{
|
||||
buff_i = 0;
|
||||
{cs = 2;goto _again;}
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
/* #line 135 "ini_parser.rl" */
|
||||
{
|
||||
if (buff_i >= INI_KEY_MAX) {
|
||||
ini_parser_error("Section name too long");
|
||||
{cs = 10;goto _again;}
|
||||
}
|
||||
keybuf[buff_i++] = (*p);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
/* #line 143 "ini_parser.rl" */
|
||||
{
|
||||
// we need a separate buffer for the result, otherwise a failed
|
||||
// partial parse would corrupt the section string
|
||||
rtrim_buf(keybuf, buff_i);
|
||||
for (i = 0; (c = keybuf[i]) != 0; i++) secbuf[i] = c;
|
||||
secbuf[i] = 0;
|
||||
{cs = 1;goto _again;}
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
/* #line 155 "ini_parser.rl" */
|
||||
{
|
||||
ini_parser_error("Syntax error in [section]");
|
||||
if((*p) == '\n') {cs = 1;goto _again;} else {cs = 10;goto _again;}
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
/* #line 162 "ini_parser.rl" */
|
||||
{
|
||||
buff_i = 0;
|
||||
keybuf[buff_i++] = (*p); // add the first char
|
||||
{cs = 4;goto _again;}
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
/* #line 168 "ini_parser.rl" */
|
||||
{
|
||||
if (buff_i >= INI_KEY_MAX) {
|
||||
ini_parser_error("Key too long");
|
||||
{cs = 10;goto _again;}
|
||||
}
|
||||
keybuf[buff_i++] = (*p);
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
/* #line 176 "ini_parser.rl" */
|
||||
{
|
||||
rtrim_buf(keybuf, buff_i);
|
||||
|
||||
// --- Value begin ---
|
||||
buff_i = 0;
|
||||
value_quote = 0;
|
||||
value_nextesc = false;
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
/* #line 185 "ini_parser.rl" */
|
||||
{
|
||||
isnl = ((*p) == '\r' || (*p) == '\n');
|
||||
isquot = ((*p) == '\'' || (*p) == '"');
|
||||
|
||||
// detect our starting quote
|
||||
if (isquot && !value_nextesc && buff_i == 0 && value_quote == 0) {
|
||||
value_quote = (*p);
|
||||
goto valueCharDone;
|
||||
}
|
||||
|
||||
if (buff_i >= INI_VALUE_MAX) {
|
||||
ini_parser_error("Value too long");
|
||||
{cs = 10;goto _again;}
|
||||
}
|
||||
|
||||
// end of string - clean up and report
|
||||
if ((!value_nextesc && (*p) == value_quote) || isnl) {
|
||||
if (isnl && value_quote) {
|
||||
ini_parser_error("Unterminated string");
|
||||
{cs = 1;goto _again;}
|
||||
}
|
||||
|
||||
// unquoted: trim from the end
|
||||
if (!value_quote) {
|
||||
rtrim_buf(valbuf, buff_i);
|
||||
} else {
|
||||
valbuf[buff_i] = 0;
|
||||
}
|
||||
|
||||
if (keyCallback) {
|
||||
keyCallback(secbuf, keybuf, valbuf, userdata);
|
||||
}
|
||||
|
||||
// we don't want to discard to eol if the string was terminated by eol
|
||||
// - would delete the next line
|
||||
|
||||
if (isnl) {cs = 1;goto _again;} else {cs = 10;goto _again;}
|
||||
}
|
||||
|
||||
c = (*p);
|
||||
// escape...
|
||||
if (value_nextesc) {
|
||||
if ((*p) == 'n') c = '\n';
|
||||
else if ((*p) == 'r') c = '\r';
|
||||
else if ((*p) == 't') c = '\t';
|
||||
else if ((*p) == 'e') c = '\033';
|
||||
}
|
||||
|
||||
// collecting characters...
|
||||
if (value_nextesc || (*p) != '\\') { // is quoted, or is not a quoting backslash - literal character
|
||||
valbuf[buff_i++] = c;
|
||||
}
|
||||
|
||||
value_nextesc = (!value_nextesc && (*p) == '\\');
|
||||
valueCharDone:;
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
/* #line 247 "ini_parser.rl" */
|
||||
{
|
||||
ini_parser_error("Syntax error in key=value");
|
||||
if((*p) == '\n') {cs = 1;goto _again;} else {cs = 10;goto _again;}
|
||||
}
|
||||
break;
|
||||
case 9:
|
||||
/* #line 257 "ini_parser.rl" */
|
||||
{ {cs = 1;goto _again;} }
|
||||
break;
|
||||
case 10:
|
||||
/* #line 258 "ini_parser.rl" */
|
||||
{
|
||||
ini_parser_error("Syntax error in comment");
|
||||
if((*p) == '\n') {cs = 1;goto _again;} else {cs = 10;goto _again;}
|
||||
}
|
||||
break;
|
||||
case 11:
|
||||
/* #line 265 "ini_parser.rl" */
|
||||
{ {cs = 1;goto _again;} }
|
||||
break;
|
||||
case 12:
|
||||
/* #line 273 "ini_parser.rl" */
|
||||
{ {cs = 8;goto _again;} }
|
||||
break;
|
||||
case 13:
|
||||
/* #line 276 "ini_parser.rl" */
|
||||
{
|
||||
ini_parser_error("Syntax error in root");
|
||||
{cs = 10;goto _again;}
|
||||
}
|
||||
break;
|
||||
/* #line 458 "ini_parser.c" */
|
||||
}
|
||||
}
|
||||
goto _again;
|
||||
|
||||
_again:
|
||||
if ( cs == 0 )
|
||||
goto _out;
|
||||
if ( ++p != pe )
|
||||
goto _resume;
|
||||
_test_eof: {}
|
||||
if ( p == eof )
|
||||
{
|
||||
const char *__acts = _ini_actions + _ini_eof_actions[cs];
|
||||
unsigned int __nacts = (unsigned int) *__acts++;
|
||||
while ( __nacts-- > 0 ) {
|
||||
switch ( *__acts++ ) {
|
||||
case 3:
|
||||
/* #line 155 "ini_parser.rl" */
|
||||
{
|
||||
ini_parser_error("Syntax error in [section]");
|
||||
if((*p) == '\n') {cs = 1; if ( p == pe )
|
||||
goto _test_eof;
|
||||
goto _again;} else {cs = 10; if ( p == pe )
|
||||
goto _test_eof;
|
||||
goto _again;}
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
/* #line 247 "ini_parser.rl" */
|
||||
{
|
||||
ini_parser_error("Syntax error in key=value");
|
||||
if((*p) == '\n') {cs = 1; if ( p == pe )
|
||||
goto _test_eof;
|
||||
goto _again;} else {cs = 10; if ( p == pe )
|
||||
goto _test_eof;
|
||||
goto _again;}
|
||||
}
|
||||
break;
|
||||
case 10:
|
||||
/* #line 258 "ini_parser.rl" */
|
||||
{
|
||||
ini_parser_error("Syntax error in comment");
|
||||
if((*p) == '\n') {cs = 1; if ( p == pe )
|
||||
goto _test_eof;
|
||||
goto _again;} else {cs = 10; if ( p == pe )
|
||||
goto _test_eof;
|
||||
goto _again;}
|
||||
}
|
||||
break;
|
||||
case 13:
|
||||
/* #line 276 "ini_parser.rl" */
|
||||
{
|
||||
ini_parser_error("Syntax error in root");
|
||||
{cs = 10; if ( p == pe )
|
||||
goto _test_eof;
|
||||
goto _again;}
|
||||
}
|
||||
break;
|
||||
/* #line 517 "ini_parser.c" */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_out: {}
|
||||
}
|
||||
|
||||
/* #line 283 "ini_parser.rl" */
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
#ifndef INIPARSE_STREAM_H
|
||||
#define INIPARSE_STREAM_H
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
#ifdef DEBUG_INI
|
||||
#define ini_error(fmt, ...) dbg("! INI err: "#fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
#define ini_error(fmt, ...)
|
||||
#endif
|
||||
|
||||
// buffer sizes
|
||||
#define INI_KEY_MAX 20
|
||||
#define INI_VALUE_MAX 30
|
||||
|
||||
/**
|
||||
* INI parser callback, called for each found key-value pair.
|
||||
*
|
||||
* @param section - current section, empty string for global keys
|
||||
* @param key - found key (trimmed of whitespace)
|
||||
* @param value - value, trimmed of quotes or whitespace
|
||||
* @param userData - opaque user data pointer, general purpose
|
||||
*/
|
||||
typedef void (*IniParserCallback)(const char *section, const char *key, const char *value, void *userData);
|
||||
|
||||
/**
|
||||
* Begin parsing a stream
|
||||
*
|
||||
* @param callback - key callback to assign
|
||||
* @param userData - optional user data that will be passed to the callback
|
||||
*/
|
||||
void ini_parse_begin(IniParserCallback callback, void *userData);
|
||||
|
||||
/**
|
||||
* End parse stream.
|
||||
* Flushes what remains in the buffer and removes callback.
|
||||
*
|
||||
* @returns userData or NULL if none
|
||||
*/
|
||||
void* ini_parse_end(void);
|
||||
|
||||
/**
|
||||
* Parse a string (needn't be complete line or file)
|
||||
*
|
||||
* @param data - string to parse
|
||||
* @param len - string length (0 = use strlen)
|
||||
*/
|
||||
void ini_parse(const char *data, size_t len);
|
||||
|
||||
/**
|
||||
* Parse a complete file loaded to string
|
||||
*
|
||||
* @param text - entire file as string
|
||||
* @param len - file length (0 = use strlen)
|
||||
* @param callback - key callback
|
||||
* @param userData - optional user data for key callback
|
||||
*/
|
||||
void ini_parse_file(const char *text, size_t len, IniParserCallback callback, void *userData);
|
||||
|
||||
/**
|
||||
* Explicitly reset the parser
|
||||
*/
|
||||
void ini_parse_reset(void);
|
||||
|
||||
#endif // INIPARSE_STREAM_H
|
||||
@@ -0,0 +1,284 @@
|
||||
|
||||
/* Ragel constants block */
|
||||
#include "ini_parser.h"
|
||||
|
||||
// Ragel setup
|
||||
%%{
|
||||
machine ini;
|
||||
write data;
|
||||
alphtype unsigned char;
|
||||
}%%
|
||||
|
||||
// Persistent state
|
||||
static int8_t cs = -1; //!< Ragel's Current State variable
|
||||
static uint32_t buff_i = 0; //!< Write pointer for the buffers
|
||||
static char value_quote = 0; //!< Quote character of the currently collected value
|
||||
static bool value_nextesc = false; //!< Next character is escaped, trated specially, and if quote, as literal quote character
|
||||
static IniParserCallback keyCallback = NULL; //!< Currently assigned callback
|
||||
static void *userdata = NULL; //!< Currently assigned user data for the callback
|
||||
|
||||
// Buffers
|
||||
static char keybuf[INI_KEY_MAX];
|
||||
static char secbuf[INI_KEY_MAX];
|
||||
static char valbuf[INI_VALUE_MAX];
|
||||
|
||||
// See header for doxygen!
|
||||
|
||||
void
|
||||
ini_parse_reset_partial(void)
|
||||
{
|
||||
buff_i = 0;
|
||||
value_quote = 0;
|
||||
value_nextesc = false;
|
||||
}
|
||||
|
||||
void
|
||||
ini_parse_reset(void)
|
||||
{
|
||||
ini_parse_reset_partial();
|
||||
keybuf[0] = secbuf[0] = valbuf[0] = 0;
|
||||
%% write init;
|
||||
}
|
||||
|
||||
void
|
||||
ini_parser_error(const char* msg)
|
||||
{
|
||||
ini_error("Parser error: %s", msg);
|
||||
ini_parse_reset_partial();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ini_parse_begin(IniParserCallback callback, void *userData)
|
||||
{
|
||||
keyCallback = callback;
|
||||
userdata = userData;
|
||||
ini_parse_reset();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
*ini_parse_end(void)
|
||||
{
|
||||
ini_parse("\n", 1);
|
||||
if (keyCallback) {
|
||||
keyCallback = NULL;
|
||||
}
|
||||
|
||||
void *ud = userdata;
|
||||
userdata = NULL;
|
||||
return ud;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ini_parse_file(const char *text, size_t len, IniParserCallback callback, void *userData)
|
||||
{
|
||||
ini_parse_begin(callback, userData);
|
||||
ini_parse(text, len);
|
||||
ini_parse_end();
|
||||
}
|
||||
|
||||
static void
|
||||
rtrim_buf(char *buf, int32_t end)
|
||||
{
|
||||
if (end > 0) {
|
||||
while ((uint8_t)buf[--end] < 33);
|
||||
end++; // go past the last character
|
||||
}
|
||||
|
||||
buf[end] = 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ini_parse(const char *newstr, size_t len)
|
||||
{
|
||||
int32_t i;
|
||||
char c;
|
||||
bool isnl;
|
||||
bool isquot;
|
||||
|
||||
// Load new data to Ragel vars
|
||||
const uint8_t *p;
|
||||
const uint8_t *eof;
|
||||
const uint8_t *pe;
|
||||
|
||||
if (len == 0) while(newstr[++len] != 0); // alternative to strlen
|
||||
|
||||
p = (const uint8_t *) newstr;
|
||||
eof = NULL;
|
||||
pe = (const uint8_t *) (newstr + len);
|
||||
|
||||
// Init Ragel on the first run
|
||||
if (cs == -1) {
|
||||
ini_parse_reset();
|
||||
}
|
||||
|
||||
// The parser
|
||||
%%{
|
||||
#/ *
|
||||
ispace = [ \t]; # inline space
|
||||
wchar = any - 0..8 - 10..31;
|
||||
#apos = '\'';
|
||||
#quot = '\"';
|
||||
nonl = [^\r\n];
|
||||
nl = '\r'? '\n';
|
||||
|
||||
# ---- [SECTION] ----
|
||||
|
||||
action sectionStart {
|
||||
buff_i = 0;
|
||||
fgoto section;
|
||||
}
|
||||
|
||||
action sectionChar {
|
||||
if (buff_i >= INI_KEY_MAX) {
|
||||
ini_parser_error("Section name too long");
|
||||
fgoto discard2eol;
|
||||
}
|
||||
keybuf[buff_i++] = fc;
|
||||
}
|
||||
|
||||
action sectionEnd {
|
||||
// we need a separate buffer for the result, otherwise a failed
|
||||
// partial parse would corrupt the section string
|
||||
rtrim_buf(keybuf, buff_i);
|
||||
for (i = 0; (c = keybuf[i]) != 0; i++) secbuf[i] = c;
|
||||
secbuf[i] = 0;
|
||||
fgoto main;
|
||||
}
|
||||
|
||||
section :=
|
||||
(
|
||||
ispace* <: ((wchar - ']')+ @sectionChar) ']' @sectionEnd
|
||||
) $!{
|
||||
ini_parser_error("Syntax error in [section]");
|
||||
if(fc == '\n') fgoto main; else fgoto discard2eol;
|
||||
};
|
||||
|
||||
# ---- KEY=VALUE ----
|
||||
|
||||
action keyStart {
|
||||
buff_i = 0;
|
||||
keybuf[buff_i++] = fc; // add the first char
|
||||
fgoto keyvalue;
|
||||
}
|
||||
|
||||
action keyChar {
|
||||
if (buff_i >= INI_KEY_MAX) {
|
||||
ini_parser_error("Key too long");
|
||||
fgoto discard2eol;
|
||||
}
|
||||
keybuf[buff_i++] = fc;
|
||||
}
|
||||
|
||||
action keyEnd {
|
||||
rtrim_buf(keybuf, buff_i);
|
||||
|
||||
// --- Value begin ---
|
||||
buff_i = 0;
|
||||
value_quote = 0;
|
||||
value_nextesc = false;
|
||||
}
|
||||
|
||||
action valueChar {
|
||||
isnl = (fc == '\r' || fc == '\n');
|
||||
isquot = (fc == '\'' || fc == '"');
|
||||
|
||||
// detect our starting quote
|
||||
if (isquot && !value_nextesc && buff_i == 0 && value_quote == 0) {
|
||||
value_quote = fc;
|
||||
goto valueCharDone;
|
||||
}
|
||||
|
||||
if (buff_i >= INI_VALUE_MAX) {
|
||||
ini_parser_error("Value too long");
|
||||
fgoto discard2eol;
|
||||
}
|
||||
|
||||
// end of string - clean up and report
|
||||
if ((!value_nextesc && fc == value_quote) || isnl) {
|
||||
if (isnl && value_quote) {
|
||||
ini_parser_error("Unterminated string");
|
||||
fgoto main;
|
||||
}
|
||||
|
||||
// unquoted: trim from the end
|
||||
if (!value_quote) {
|
||||
rtrim_buf(valbuf, buff_i);
|
||||
} else {
|
||||
valbuf[buff_i] = 0;
|
||||
}
|
||||
|
||||
if (keyCallback) {
|
||||
keyCallback(secbuf, keybuf, valbuf, userdata);
|
||||
}
|
||||
|
||||
// we don't want to discard to eol if the string was terminated by eol
|
||||
// - would delete the next line
|
||||
|
||||
if (isnl) fgoto main; else fgoto discard2eol;
|
||||
}
|
||||
|
||||
c = fc;
|
||||
// escape...
|
||||
if (value_nextesc) {
|
||||
if (fc == 'n') c = '\n';
|
||||
else if (fc == 'r') c = '\r';
|
||||
else if (fc == 't') c = '\t';
|
||||
else if (fc == 'e') c = '\033';
|
||||
}
|
||||
|
||||
// collecting characters...
|
||||
if (value_nextesc || fc != '\\') { // is quoted, or is not a quoting backslash - literal character
|
||||
valbuf[buff_i++] = c;
|
||||
}
|
||||
|
||||
value_nextesc = (!value_nextesc && fc == '\\');
|
||||
valueCharDone:;
|
||||
}
|
||||
|
||||
# use * for key, first char is already consumed.
|
||||
keyvalue :=
|
||||
(
|
||||
([^\n=:]* @keyChar %keyEnd)
|
||||
[=:] ispace* <: nonl* @valueChar nl @valueChar
|
||||
) $!{
|
||||
ini_parser_error("Syntax error in key=value");
|
||||
if(fc == '\n') fgoto main; else fgoto discard2eol;
|
||||
};
|
||||
|
||||
# ---- COMMENT ----
|
||||
|
||||
comment :=
|
||||
(
|
||||
nonl* nl
|
||||
@{ fgoto main; }
|
||||
) $!{
|
||||
ini_parser_error("Syntax error in comment");
|
||||
if(fc == '\n') fgoto main; else fgoto discard2eol;
|
||||
};
|
||||
|
||||
# ---- CLEANUP ----
|
||||
|
||||
discard2eol := nonl* nl @{ fgoto main; };
|
||||
|
||||
# ---- ROOT ----
|
||||
|
||||
main :=
|
||||
(space*
|
||||
(
|
||||
'[' @sectionStart |
|
||||
[#;] @{ fgoto comment; } |
|
||||
(wchar - [\t =:]) @keyStart
|
||||
)
|
||||
) $!{
|
||||
ini_parser_error("Syntax error in root");
|
||||
fgoto discard2eol;
|
||||
};
|
||||
|
||||
write exec;
|
||||
#*/
|
||||
}%%
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
//
|
||||
// Created by MightyPork on 2017/12/01.
|
||||
//
|
||||
|
||||
#include "platform.h"
|
||||
#include "ini_writer.h"
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) ((a)>(b)?(b):(a))
|
||||
#endif
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(a,b) ((a)>(b)?(a):(b))
|
||||
#endif
|
||||
|
||||
#define IWBUFFER_LEN 128
|
||||
|
||||
// sprintf from varargs, allocating buffer on stack. Uses 'format' argument
|
||||
#define IW_VPRINTF() do { \
|
||||
char iwbuffer[IWBUFFER_LEN]; \
|
||||
va_list args; \
|
||||
va_start(args, format); \
|
||||
uint32_t len = (int)fixup_vsnprintf(&iwbuffer[0], IWBUFFER_LEN, format, args); \
|
||||
iw_buff(iw, (uint8_t *) iwbuffer, len); \
|
||||
va_end(args); \
|
||||
} while(0)
|
||||
|
||||
void iw_buff(IniWriter *iw, const uint8_t *buf, uint32_t len)
|
||||
{
|
||||
if (iw->count == 0) return;
|
||||
|
||||
uint32_t skip = 0;
|
||||
if (iw->skip >= len) {
|
||||
// Skip entire string
|
||||
iw->skip -= len;
|
||||
return;
|
||||
} else {
|
||||
// skip part
|
||||
skip = iw->skip;
|
||||
iw->skip = 0;
|
||||
uint32_t count = MIN(iw->count, len-skip);
|
||||
memcpy(iw->ptr, buf+skip, count);
|
||||
iw->ptr += count;
|
||||
iw->count -= count;
|
||||
}
|
||||
}
|
||||
|
||||
void iw_sprintf(IniWriter *iw, const char *format, ...)
|
||||
{
|
||||
if (iw->count == 0) return;
|
||||
|
||||
IW_VPRINTF();
|
||||
}
|
||||
|
||||
// High level stuff
|
||||
void iw_section(IniWriter *iw, const char *format, ...)
|
||||
{
|
||||
if (iw->count == 0) return;
|
||||
|
||||
iw_string(iw, "\r\n["); // newline before section as a separator
|
||||
IW_VPRINTF();
|
||||
iw_string(iw, "]\r\n");
|
||||
}
|
||||
|
||||
void iw_comment(IniWriter *iw, const char *format, ...)
|
||||
{
|
||||
if (iw->count == 0) return;
|
||||
|
||||
iw_string(iw, "# ");
|
||||
IW_VPRINTF();
|
||||
iw_newline(iw);
|
||||
}
|
||||
|
||||
void iw_entry(IniWriter *iw, const char *key, const char *format, ...)
|
||||
{
|
||||
if (iw->count == 0) return;
|
||||
|
||||
iw_string(iw, key);
|
||||
iw_string(iw, "=");
|
||||
IW_VPRINTF();
|
||||
iw_newline(iw); // one newline after entry
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
//
|
||||
// Created by MightyPork on 2017/12/01.
|
||||
//
|
||||
|
||||
#ifndef INIWRITER_H
|
||||
#define INIWRITER_H
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
typedef struct iniwriter_ {
|
||||
char *ptr;
|
||||
uint32_t skip;
|
||||
uint32_t count;
|
||||
} IniWriter;
|
||||
|
||||
/**
|
||||
* Initialize a IniWriter struct (macro)
|
||||
*
|
||||
* @param buffer - buffer backing the writer, result will be written here
|
||||
* @param skip - number of written bytes to skip
|
||||
* @param count - number of bytes to write, truncate rest
|
||||
* @return structure initializer
|
||||
*/
|
||||
#define iw_init(buffer, skip, count) (IniWriter){buffer, skip, count}
|
||||
|
||||
/**
|
||||
* Try to write a buffer to the file
|
||||
*
|
||||
* @param iw - iniwriter handle
|
||||
* @param buf - buffer to write
|
||||
* @param len - buffer len
|
||||
*/
|
||||
void iw_buff(IniWriter *iw, const uint8_t *buf, uint32_t len);
|
||||
|
||||
/**
|
||||
* Try to write a string to the file
|
||||
*
|
||||
* @param iw - iniwriter handle
|
||||
* @param str - string to write
|
||||
*/
|
||||
static inline void iw_string(IniWriter *iw, const char *str)
|
||||
{
|
||||
if (iw->count != 0) {
|
||||
iw_buff(iw, (uint8_t *) str, (uint32_t) strlen(str));
|
||||
}
|
||||
}
|
||||
|
||||
#define iw_newline(iw) iw_string(iw, "\r\n")
|
||||
|
||||
/**
|
||||
* Try to snprintf to the file
|
||||
*
|
||||
* @param iw - iniwriter handle
|
||||
* @param format - format, like printf
|
||||
* @param ... - replacements
|
||||
*/
|
||||
void iw_sprintf(IniWriter *iw, const char *format, ...)
|
||||
__attribute__((format(printf,2,3)));
|
||||
|
||||
// High level stuff
|
||||
|
||||
/**
|
||||
* Try to write a INI section header [foobar]\r\n
|
||||
* @param iw - iniwriter handle
|
||||
* @param format - format, like printf
|
||||
* @param ... - replacements
|
||||
*/
|
||||
void iw_section(IniWriter *iw, const char *format, ...)
|
||||
__attribute__((format(printf,2,3)));
|
||||
|
||||
/**
|
||||
* Try to write a INI comment # blah\r\n
|
||||
* @param iw - iniwriter handle
|
||||
* @param format - format, like printf
|
||||
* @param ... - replacements
|
||||
*/
|
||||
void iw_comment(IniWriter *iw, const char *format, ...)
|
||||
__attribute__((format(printf,2,3)));
|
||||
|
||||
/**
|
||||
* Try to write a key-value entry
|
||||
*
|
||||
* @param iw - iniwriter handle
|
||||
* @param key - key
|
||||
* @param format - value format (like printf)
|
||||
* @param ... - replacements
|
||||
*/
|
||||
void iw_entry(IniWriter *iw, const char *key, const char *format, ...)
|
||||
__attribute__((format(printf,3,4)));
|
||||
|
||||
#endif //INIWRITER_H
|
||||
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* @file macro.h
|
||||
* @brief useful things + Special asserts and macros
|
||||
*
|
||||
* DAPLink Interface Firmware
|
||||
* Copyright (c) 2009-2016, ARM Limited, All Rights Reserved
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef VFS_MACRO_H
|
||||
#define VFS_MACRO_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// --------------- VFS macros and general purpose --------------------
|
||||
|
||||
#define ELEMENTS_IN_ARRAY(array) (sizeof(array)/sizeof(array[0]))
|
||||
|
||||
#define MB(size) ((size) * 1024 * 1024)
|
||||
|
||||
#define KB(size) ((size) * 1024)
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(a,b) ((a) > (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#define ROUND_UP(value, boundary) ((value) + ((boundary) - (value)) % (boundary))
|
||||
|
||||
#define ROUND_DOWN(value, boundary) ((value) - ((value) % (boundary)))
|
||||
|
||||
// ---------- HELPERS FOR XMACROS -----------------
|
||||
|
||||
#define XJOIN(a, b) a##b
|
||||
#define STR_(x) #x
|
||||
#define STR(x) STR_(x)
|
||||
|
||||
// ---------- COMPILER SPECIAL MACROS -------------
|
||||
|
||||
#define COMPILER_CONCAT_(a, b) a##b
|
||||
#define COMPILER_CONCAT(a, b) COMPILER_CONCAT_(a, b)
|
||||
|
||||
// Divide by zero if the the expression is false. This
|
||||
// causes an error at compile time.
|
||||
//
|
||||
// The special value '__COUNTER__' is used to create a unique value to
|
||||
// append to 'compiler_assert_' to create a unique token. This prevents
|
||||
// conflicts resulting from the same enum being declared multiple times.
|
||||
#define COMPILER_ASSERT(e) enum { COMPILER_CONCAT(compiler_assert_, __COUNTER__) = 1/((e) ? 1 : 0) }
|
||||
|
||||
#define __at(_addr) __attribute__ ((at(_addr)))
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,48 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <inttypes.h>
|
||||
#include "debug.h"
|
||||
#include "stm32_assert.h"
|
||||
#include "malloc_safe.h"
|
||||
|
||||
#if 1
|
||||
|
||||
void *malloc_safe_do(size_t size, const char *file, uint32_t line)
|
||||
{
|
||||
void *mem = malloc(size);
|
||||
if (mem == NULL) abort_msg("MALLOC FAILED", file, line);
|
||||
return mem;
|
||||
}
|
||||
|
||||
void *calloc_safe_do(size_t nmemb, size_t size, const char *file, uint32_t line)
|
||||
{
|
||||
void *mem = calloc(size, nmemb);
|
||||
if (mem == NULL) abort_msg("CALLOC FAILED", file, line);
|
||||
return mem;
|
||||
}
|
||||
|
||||
|
||||
void *malloc_ck_do(size_t size, bool *suc, const char *file, uint32_t line)
|
||||
{
|
||||
void *mem = malloc(size);
|
||||
if (mem == NULL) {
|
||||
warn_msg("MALLOC FAILED", file, line);
|
||||
*suc = false;
|
||||
mem = NULL;
|
||||
}
|
||||
return mem;
|
||||
}
|
||||
|
||||
void *calloc_ck_do(size_t nmemb, size_t size, bool *suc, const char *file, uint32_t line)
|
||||
{
|
||||
void *mem = calloc(size, nmemb);
|
||||
if (mem == NULL) {
|
||||
warn_msg("CALLOC FAILED", file, line);
|
||||
*suc = false;
|
||||
mem = NULL;
|
||||
}
|
||||
return mem;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,22 @@
|
||||
#ifndef MALLOC_SAFE_H
|
||||
#define MALLOC_SAFE_H
|
||||
|
||||
/**
|
||||
* Malloc that prints error and restarts the system on failure.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
void *malloc_safe_do(size_t size, const char* file, uint32_t line) __attribute__((malloc));
|
||||
void *calloc_safe_do(size_t nmemb, size_t size, const char* file, uint32_t line) __attribute__((malloc));
|
||||
void *malloc_ck_do(size_t size, bool *suc, const char* file, uint32_t line) __attribute__((malloc));
|
||||
void *calloc_ck_do(size_t nmemb, size_t size, bool *suc, const char* file, uint32_t line) __attribute__((malloc));
|
||||
|
||||
#define malloc_s(size) malloc_safe_do(size, __BASE_FILE__, __LINE__)
|
||||
#define calloc_s(nmemb, size) calloc_safe_do(nmemb, size, __BASE_FILE__, __LINE__)
|
||||
#define malloc_ck(size, suc) malloc_ck_do(size, suc, __BASE_FILE__, __LINE__)
|
||||
#define calloc_ck(nmemb, size, suc) calloc_ck_do(nmemb, size, suc, __BASE_FILE__, __LINE__)
|
||||
|
||||
#endif // MALLOC_SAFE_H
|
||||
@@ -0,0 +1,100 @@
|
||||
#include <string.h>
|
||||
#include "payload_builder.h"
|
||||
|
||||
#define pb_check_capacity(pb, needed) \
|
||||
if ((pb)->current + (needed) > (pb)->end) { \
|
||||
if ((pb)->full_handler == NULL || !(pb)->full_handler(pb, needed)) (pb)->ok = 0; \
|
||||
}
|
||||
|
||||
/** Write from a buffer */
|
||||
bool pb_buf(PayloadBuilder *pb, const uint8_t *buf, uint32_t len)
|
||||
{
|
||||
pb_check_capacity(pb, len);
|
||||
if (!pb->ok) return false;
|
||||
|
||||
memcpy(pb->current, buf, len);
|
||||
pb->current += len;
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Write s zero terminated string */
|
||||
bool pb_string(PayloadBuilder *pb, const char *str)
|
||||
{
|
||||
uint32_t len = (uint32_t) strlen(str);
|
||||
pb_check_capacity(pb, len+1);
|
||||
if (!pb->ok) return false;
|
||||
|
||||
memcpy(pb->current, str, len+1);
|
||||
pb->current += len+1;
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Write uint8_t to the buffer */
|
||||
bool pb_u8(PayloadBuilder *pb, uint8_t byte)
|
||||
{
|
||||
pb_check_capacity(pb, 1);
|
||||
if (!pb->ok) return false;
|
||||
|
||||
*pb->current++ = byte;
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Write uint16_t to the buffer. */
|
||||
bool pb_u16(PayloadBuilder *pb, uint16_t word)
|
||||
{
|
||||
pb_check_capacity(pb, 2);
|
||||
if (!pb->ok) return false;
|
||||
|
||||
if (pb->bigendian) {
|
||||
*pb->current++ = (uint8_t) ((word >> 8) & 0xFF);
|
||||
*pb->current++ = (uint8_t) (word & 0xFF);
|
||||
} else {
|
||||
*pb->current++ = (uint8_t) (word & 0xFF);
|
||||
*pb->current++ = (uint8_t) ((word >> 8) & 0xFF);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Write uint32_t to the buffer. */
|
||||
bool pb_u32(PayloadBuilder *pb, uint32_t word)
|
||||
{
|
||||
pb_check_capacity(pb, 4);
|
||||
if (!pb->ok) return false;
|
||||
|
||||
if (pb->bigendian) {
|
||||
*pb->current++ = (uint8_t) ((word >> 24) & 0xFF);
|
||||
*pb->current++ = (uint8_t) ((word >> 16) & 0xFF);
|
||||
*pb->current++ = (uint8_t) ((word >> 8) & 0xFF);
|
||||
*pb->current++ = (uint8_t) (word & 0xFF);
|
||||
} else {
|
||||
*pb->current++ = (uint8_t) (word & 0xFF);
|
||||
*pb->current++ = (uint8_t) ((word >> 8) & 0xFF);
|
||||
*pb->current++ = (uint8_t) ((word >> 16) & 0xFF);
|
||||
*pb->current++ = (uint8_t) ((word >> 24) & 0xFF);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Write int8_t to the buffer. */
|
||||
bool pb_i8(PayloadBuilder *pb, int8_t byte)
|
||||
{
|
||||
return pb_u8(pb, ((union conv8){.i8 = byte}).u8);
|
||||
}
|
||||
|
||||
/** Write int16_t to the buffer. */
|
||||
bool pb_i16(PayloadBuilder *pb, int16_t word)
|
||||
{
|
||||
return pb_u16(pb, ((union conv16){.i16 = word}).u16);
|
||||
}
|
||||
|
||||
/** Write int32_t to the buffer. */
|
||||
bool pb_i32(PayloadBuilder *pb, int32_t word)
|
||||
{
|
||||
return pb_u32(pb, ((union conv32){.i32 = word}).u32);
|
||||
}
|
||||
|
||||
/** Write 4-byte float to the buffer. */
|
||||
bool pb_float(PayloadBuilder *pb, float f)
|
||||
{
|
||||
return pb_u32(pb, ((union conv32){.f32 = f}).u32);
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
#ifndef PAYLOAD_BUILDER_H
|
||||
#define PAYLOAD_BUILDER_H
|
||||
|
||||
/**
|
||||
* PayloadBuilder, part of the TinyFrame utilities collection
|
||||
*
|
||||
* (c) Ondřej Hruška, 2014-2017. MIT license.
|
||||
*
|
||||
* The builder supports big and little endian which is selected when
|
||||
* initializing it or by accessing the bigendian struct field.
|
||||
*
|
||||
* This module helps you with building payloads (not only for TinyFrame)
|
||||
*
|
||||
* The builder performs bounds checking and calls the provided handler when
|
||||
* the requested write wouldn't fit. Use the handler to realloc / flush the buffer
|
||||
* or report an error.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include "type_coerce.h"
|
||||
|
||||
typedef struct PayloadBuilder_ PayloadBuilder;
|
||||
|
||||
/**
|
||||
* Full buffer handler.
|
||||
*
|
||||
* 'needed' more bytes should be written but the end of the buffer was reached.
|
||||
*
|
||||
* Return true if the problem was solved (e.g. buffer was flushed and the
|
||||
* 'current' pointer moved to the beginning).
|
||||
*
|
||||
* If false is returned, the 'ok' flag on the struct is set to false
|
||||
* and all following writes are discarded.
|
||||
*/
|
||||
typedef bool (*pb_full_handler)(PayloadBuilder *pb, uint32_t needed);
|
||||
|
||||
struct PayloadBuilder_ {
|
||||
uint8_t *start; //!< Pointer to the beginning of the buffer
|
||||
uint8_t *current; //!< Pointer to the next byte to be read
|
||||
uint8_t *end; //!< Pointer to the end of the buffer (start + length)
|
||||
pb_full_handler full_handler; //!< Callback for buffer overrun
|
||||
bool bigendian; //!< Flag to use big-endian parsing
|
||||
bool ok; //!< Indicates that all reads were successful
|
||||
};
|
||||
|
||||
// --- initializer helper macros ---
|
||||
|
||||
/** Start the builder. */
|
||||
#define pb_start_e(buf, capacity, bigendian, full_handler) ((PayloadBuilder){buf, buf, (buf)+(capacity), full_handler, bigendian, 1})
|
||||
|
||||
/** Start the builder in big-endian mode */
|
||||
#define pb_start_be(buf, capacity, full_handler) pb_start_e(buf, capacity, 1, full_handler)
|
||||
|
||||
/** Start the builder in little-endian mode */
|
||||
#define pb_start_le(buf, capacity, full_handler) pb_start_e(buf, capacity, 0, full_handler)
|
||||
|
||||
/** Start the parser in little-endian mode (default) */
|
||||
#define pb_start(buf, capacity, full_handler) pb_start_le(buf, capacity, full_handler)
|
||||
|
||||
// --- utilities ---
|
||||
|
||||
/** Get already used bytes count */
|
||||
#define pb_length(pb) ((pb)->current - (pb)->start)
|
||||
|
||||
/** Reset the current pointer to start */
|
||||
#define pb_rewind(pb) do { pb->current = pb->start; } while (0)
|
||||
|
||||
|
||||
/** Write from a buffer */
|
||||
bool pb_buf(PayloadBuilder *pb, const uint8_t *buf, uint32_t len);
|
||||
|
||||
/** Write a zero terminated string */
|
||||
bool pb_string(PayloadBuilder *pb, const char *str);
|
||||
|
||||
/** Write uint8_t to the buffer */
|
||||
bool pb_u8(PayloadBuilder *pb, uint8_t byte);
|
||||
|
||||
/** Write boolean to the buffer. */
|
||||
static inline bool pb_bool(PayloadBuilder *pb, bool b)
|
||||
{
|
||||
return pb_u8(pb, (uint8_t) b);
|
||||
}
|
||||
|
||||
/** Write uint16_t to the buffer. */
|
||||
bool pb_u16(PayloadBuilder *pb, uint16_t word);
|
||||
|
||||
/** Write uint32_t to the buffer. */
|
||||
bool pb_u32(PayloadBuilder *pb, uint32_t word);
|
||||
|
||||
/** Write int8_t to the buffer. */
|
||||
bool pb_i8(PayloadBuilder *pb, int8_t byte);
|
||||
|
||||
/** Write char (int8_t) to the buffer. */
|
||||
static inline bool pb_char(PayloadBuilder *pb, char c)
|
||||
{
|
||||
return pb_i8(pb, c);
|
||||
}
|
||||
|
||||
/** Write int16_t to the buffer. */
|
||||
bool pb_i16(PayloadBuilder *pb, int16_t word);
|
||||
|
||||
/** Write int32_t to the buffer. */
|
||||
bool pb_i32(PayloadBuilder *pb, int32_t word);
|
||||
|
||||
/** Write 4-byte float to the buffer. */
|
||||
bool pb_float(PayloadBuilder *pb, float f);
|
||||
|
||||
#endif // PAYLOAD_BUILDER_H
|
||||
@@ -0,0 +1,121 @@
|
||||
#include "payload_parser.h"
|
||||
|
||||
#define pp_check_capacity(pp, needed) \
|
||||
if ((pp)->current + (needed) > (pp)->end) { \
|
||||
if ((pp)->empty_handler == NULL || !(pp)->empty_handler(pp, needed)) {(pp)->ok = 0;} ; \
|
||||
}
|
||||
|
||||
void pp_skip(PayloadParser *pp, uint32_t num)
|
||||
{
|
||||
pp->current += num;
|
||||
}
|
||||
|
||||
uint8_t pp_u8(PayloadParser *pp)
|
||||
{
|
||||
pp_check_capacity(pp, 1);
|
||||
if (!pp->ok) return 0;
|
||||
|
||||
return *pp->current++;
|
||||
}
|
||||
|
||||
uint16_t pp_u16(PayloadParser *pp)
|
||||
{
|
||||
pp_check_capacity(pp, 2);
|
||||
if (!pp->ok) return 0;
|
||||
|
||||
uint16_t x = 0;
|
||||
|
||||
if (pp->bigendian) {
|
||||
x |= *pp->current++ << 8;
|
||||
x |= *pp->current++;
|
||||
} else {
|
||||
x |= *pp->current++;
|
||||
x |= *pp->current++ << 8;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
uint32_t pp_u32(PayloadParser *pp)
|
||||
{
|
||||
pp_check_capacity(pp, 4);
|
||||
if (!pp->ok) return 0;
|
||||
|
||||
uint32_t x = 0;
|
||||
|
||||
if (pp->bigendian) {
|
||||
x |= (uint32_t) (*pp->current++ << 24);
|
||||
x |= (uint32_t) (*pp->current++ << 16);
|
||||
x |= (uint32_t) (*pp->current++ << 8);
|
||||
x |= *pp->current++;
|
||||
} else {
|
||||
x |= *pp->current++;
|
||||
x |= (uint32_t) (*pp->current++ << 8);
|
||||
x |= (uint32_t) (*pp->current++ << 16);
|
||||
x |= (uint32_t) (*pp->current++ << 24);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
const uint8_t *pp_tail(PayloadParser *pp, uint32_t *length)
|
||||
{
|
||||
int32_t len = (int) (pp->end - pp->current);
|
||||
if (!pp->ok || len <= 0) {
|
||||
if (length != NULL) *length = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (length != NULL) {
|
||||
*length = (uint32_t) len;
|
||||
}
|
||||
|
||||
return pp->current;
|
||||
}
|
||||
|
||||
/** Read int8_t from the payload. */
|
||||
int8_t pp_i8(PayloadParser *pp)
|
||||
{
|
||||
return ((union conv8) {.u8 = pp_u8(pp)}).i8;
|
||||
}
|
||||
|
||||
/** Read int16_t from the payload. */
|
||||
int16_t pp_i16(PayloadParser *pp)
|
||||
{
|
||||
return ((union conv16) {.u16 = pp_u16(pp)}).i16;
|
||||
}
|
||||
|
||||
/** Read int32_t from the payload. */
|
||||
int32_t pp_i32(PayloadParser *pp)
|
||||
{
|
||||
return ((union conv32) {.u32 = pp_u32(pp)}).i32;
|
||||
}
|
||||
|
||||
/** Read 4-byte float from the payload. */
|
||||
float pp_float(PayloadParser *pp)
|
||||
{
|
||||
return ((union conv32) {.u32 = pp_u32(pp)}).f32;
|
||||
}
|
||||
|
||||
/** Read a zstring */
|
||||
uint32_t pp_string(PayloadParser *pp, char *buffer, uint32_t maxlen)
|
||||
{
|
||||
pp_check_capacity(pp, 1);
|
||||
uint32_t len = 0;
|
||||
while (len < maxlen-1 && pp->current != pp->end) {
|
||||
char c = *buffer++ = *pp->current++;
|
||||
if (c == 0) break;
|
||||
len++;
|
||||
}
|
||||
*buffer = 0;
|
||||
return len;
|
||||
}
|
||||
|
||||
/** Read a buffer */
|
||||
uint32_t pp_buf(PayloadParser *pp, uint8_t *buffer, uint32_t maxlen)
|
||||
{
|
||||
uint32_t len = 0;
|
||||
while (len < maxlen && pp->current != pp->end) {
|
||||
*buffer++ = *pp->current++;
|
||||
len++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
#ifndef PAYLOAD_PARSER_H
|
||||
#define PAYLOAD_PARSER_H
|
||||
|
||||
/**
|
||||
* PayloadParser, part of the TinyFrame utilities collection
|
||||
*
|
||||
* (c) Ondřej Hruška, 2016-2017. MIT license.
|
||||
*
|
||||
* This module helps you with parsing payloads (not only from TinyFrame).
|
||||
*
|
||||
* The parser supports big and little-endian which is selected when
|
||||
* initializing it or by accessing the bigendian struct field.
|
||||
*
|
||||
* The parser performs bounds checking and calls the provided handler when
|
||||
* the requested read doesn't have enough data. Use the callback to take
|
||||
* appropriate action, e.g. report an error.
|
||||
*
|
||||
* If the handler function is not defined, the pb->ok flag is set to false
|
||||
* (use this to check for success), and further reads won't have any effect
|
||||
* and always result in 0 or empty array.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include "type_coerce.h"
|
||||
|
||||
typedef struct PayloadParser_ PayloadParser;
|
||||
|
||||
/**
|
||||
* Empty buffer handler.
|
||||
*
|
||||
* 'needed' more bytes should be read but the end was reached.
|
||||
*
|
||||
* Return true if the problem was solved (e.g. new data loaded into
|
||||
* the buffer and the 'current' pointer moved to the beginning).
|
||||
*
|
||||
* If false is returned, the 'ok' flag on the struct is set to false
|
||||
* and all following reads will fail / return 0.
|
||||
*/
|
||||
typedef bool (*pp_empty_handler)(PayloadParser *pp, uint32_t needed);
|
||||
|
||||
struct PayloadParser_ {
|
||||
uint8_t *start; //!< Pointer to the beginning of the buffer
|
||||
uint8_t *current; //!< Pointer to the next byte to be read
|
||||
uint8_t *end; //!< Pointer to the end of the buffer (start + length)
|
||||
pp_empty_handler empty_handler; //!< Callback for buffer underrun
|
||||
bool bigendian; //!< Flag to use big-endian parsing
|
||||
bool ok; //!< Indicates that all reads were successful
|
||||
};
|
||||
|
||||
// --- initializer helper macros ---
|
||||
|
||||
/** Start the parser. */
|
||||
#define pp_start_e(buf, length, bigendian, empty_handler) ((PayloadParser){buf, buf, (buf)+(length), empty_handler, bigendian, 1})
|
||||
|
||||
/** Start the parser in big-endian mode */
|
||||
#define pp_start_be(buf, length, empty_handler) pp_start_e(buf, length, 1, empty_handler)
|
||||
|
||||
/** Start the parser in little-endian mode */
|
||||
#define pp_start_le(buf, length, empty_handler) pp_start_e(buf, length, 0, empty_handler)
|
||||
|
||||
/** Start the parser in little-endian mode (default) */
|
||||
#define pp_start(buf, length, empty_handler) pp_start_le(buf, length, empty_handler)
|
||||
|
||||
// --- utilities ---
|
||||
|
||||
/** Get remaining length */
|
||||
#define pp_length(pp) ((pp)->end - (pp)->current)
|
||||
|
||||
/** Reset the current pointer to start */
|
||||
#define pp_rewind(pp) do { pp->current = pp->start; } while (0)
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the remainder of the buffer.
|
||||
*
|
||||
* Returns NULL and sets 'length' to 0 if there are no bytes left.
|
||||
*
|
||||
* @param pp
|
||||
* @param length : here the buffer length will be stored. NULL to do not store.
|
||||
* @return the remaining portion of the input buffer
|
||||
*/
|
||||
const uint8_t *pp_tail(PayloadParser *pp, uint32_t *length);
|
||||
|
||||
/** Read uint8_t from the payload. */
|
||||
uint8_t pp_u8(PayloadParser *pp);
|
||||
|
||||
/** Read bool from the payload. */
|
||||
static inline int8_t pp_bool(PayloadParser *pp)
|
||||
{
|
||||
return pp_u8(pp) != 0;
|
||||
}
|
||||
|
||||
/** Skip bytes */
|
||||
void pp_skip(PayloadParser *pp, uint32_t num);
|
||||
|
||||
/** Read uint16_t from the payload. */
|
||||
uint16_t pp_u16(PayloadParser *pp);
|
||||
|
||||
/** Read uint32_t from the payload. */
|
||||
uint32_t pp_u32(PayloadParser *pp);
|
||||
|
||||
/** Read int8_t from the payload. */
|
||||
int8_t pp_i8(PayloadParser *pp);
|
||||
|
||||
/** Read char (int8_t) from the payload. */
|
||||
static inline int8_t pp_char(PayloadParser *pp)
|
||||
{
|
||||
return pp_i8(pp);
|
||||
}
|
||||
|
||||
/** Read int16_t from the payload. */
|
||||
int16_t pp_i16(PayloadParser *pp);
|
||||
|
||||
/** Read int32_t from the payload. */
|
||||
int32_t pp_i32(PayloadParser *pp);
|
||||
|
||||
/** Read 4-byte float from the payload. */
|
||||
float pp_float(PayloadParser *pp);
|
||||
|
||||
/**
|
||||
* Parse a zero-terminated string
|
||||
*
|
||||
* @param pp - parser
|
||||
* @param buffer - target buffer
|
||||
* @param maxlen - buffer size
|
||||
* @return actual number of bytes, excluding terminator
|
||||
*/
|
||||
uint32_t pp_string(PayloadParser *pp, char *buffer, uint32_t maxlen);
|
||||
|
||||
/**
|
||||
* Parse a buffer
|
||||
*
|
||||
* @param pp - parser
|
||||
* @param buffer - target buffer
|
||||
* @param maxlen - buffer size
|
||||
* @return actual number of bytes, excluding terminator
|
||||
*/
|
||||
uint32_t pp_buf(PayloadParser *pp, uint8_t *buffer, uint32_t maxlen);
|
||||
|
||||
|
||||
#endif // PAYLOAD_PARSER_H
|
||||
+1013
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// Created by MightyPork on 2017/11/09.
|
||||
//
|
||||
|
||||
#ifndef GEX_SNPRINTF_H
|
||||
#define GEX_SNPRINTF_H
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <limits.h>
|
||||
#include "macro.h"
|
||||
|
||||
size_t fixup_vsnprintf(char *str, size_t count, const char *fmt, va_list args);
|
||||
size_t fixup_snprintf(char *str, size_t count,const char *fmt,...);
|
||||
size_t fixup_vasprintf(char **ptr, const char *format, va_list ap);
|
||||
size_t fixup_asprintf(char **ptr, const char *format, ...);
|
||||
size_t fixup_sprintf(char *ptr, const char *format, ...);
|
||||
|
||||
// Trap for using newlib functions
|
||||
//#define vsnprintf fuck1
|
||||
//#define snprintf fuck2
|
||||
//#define vasprintf fuck3
|
||||
//#define asprintf fuck4
|
||||
//#define sprintf fuck5
|
||||
|
||||
#define VSNPRINTF(...) fixup_vsnprintf(__VA_ARGS__)
|
||||
#define SNPRINTF(...) fixup_snprintf(__VA_ARGS__)
|
||||
#define VASPRINTF(...) fixup_vasprintf(__VA_ARGS__)
|
||||
#define ASPRINTF(...) fixup_asprintf(__VA_ARGS__)
|
||||
#define SPRINTF(...) fixup_sprintf(__VA_ARGS__)
|
||||
|
||||
#endif //GEX_SNPRINTF_H
|
||||
@@ -0,0 +1,87 @@
|
||||
//
|
||||
// Created by MightyPork on 2017/12/04.
|
||||
//
|
||||
|
||||
#include <task_sched.h>
|
||||
#include "platform.h"
|
||||
#include "stacksmon.h"
|
||||
|
||||
#if USE_STACK_MONITOR
|
||||
|
||||
struct stackhandle {
|
||||
const char *description;
|
||||
uint8_t *buffer;
|
||||
uint32_t len;
|
||||
};
|
||||
|
||||
#define STACK_NUM 16
|
||||
static uint32_t nextidx = 0;
|
||||
static struct stackhandle stacks[STACK_NUM];
|
||||
|
||||
void stackmon_register(const char *description, void *buffer, uint32_t len)
|
||||
{
|
||||
assert_param(nextidx < STACK_NUM);
|
||||
|
||||
uint8_t *bv = buffer;
|
||||
|
||||
// This is probably redundant, FreeRTOS does it too.
|
||||
for (uint32_t i = 0; i < len; i++) bv[i] = 0xA5;
|
||||
|
||||
stacks[nextidx].description = description;
|
||||
stacks[nextidx].buffer = bv;
|
||||
stacks[nextidx].len = len;
|
||||
nextidx++;
|
||||
}
|
||||
|
||||
void stackmon_dump(void)
|
||||
{
|
||||
PUTS("\r\n\033[1m---- STACK USAGE REPORT ---\033[m\r\n");
|
||||
for (uint32_t i = 0; i < nextidx; i++) {
|
||||
PRINTF("\033[36m>> %s\033[m @ %p\r\n", stacks[i].description, (void *) stacks[i].buffer);
|
||||
struct stackhandle *stack = &stacks[i];
|
||||
uint32_t free = 0;
|
||||
if (stack->buffer[0] != 0xA5) {
|
||||
PUTS(" \033[31m!!! OVERRUN !!!\033[m\r\n");
|
||||
} else {
|
||||
for (uint32_t j = 0; j < stack->len; j++) {
|
||||
if (stack->buffer[j] == 0xA5) {
|
||||
free++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t words = ((stack->len-free)>>2)+1;
|
||||
if (words>stack->len>>2) words=stack->len>>2;
|
||||
|
||||
PRINTF(" Used: \033[33m%"PRIu32" / %"PRIu32" bytes\033[m (\033[33m%"PRIu32" / %"PRIu32" words\033[m) ~ \033[33m%"PRIu32" %%\033[m\r\n",
|
||||
(stack->len-free),
|
||||
stack->len,
|
||||
words,
|
||||
stack->len>>2,
|
||||
(stack->len-free)*100/stack->len
|
||||
);
|
||||
}
|
||||
|
||||
PUTS("\033[36m>> QUEUES\033[m\r\n");
|
||||
PRINTF(" Used slots: \033[33mHP %"PRIu32", LP %"PRIu32"\033[m\r\n",
|
||||
jobQueHighWaterMarkHP, jobQueHighWaterMarkLP);
|
||||
|
||||
PRINTF("\033[1m---------------------------\033[m\r\n\r\n");
|
||||
}
|
||||
|
||||
|
||||
void stackmon_check_canaries(void)
|
||||
{
|
||||
for (uint32_t i = 0; i < nextidx; i++) {
|
||||
struct stackhandle *stack = &stacks[i];
|
||||
if (stack->buffer[0] != 0xA5) {
|
||||
dbg("\r\n\033[31;1m!!!! STACK \"%s\" OVERRUN - CANARY IS DEAD !!!!\033[m\r\n", stack->description);
|
||||
stackmon_dump();
|
||||
trap("ABORT");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// Created by MightyPork on 2017/12/04.
|
||||
//
|
||||
|
||||
#ifndef GEX_STACKSMON_H
|
||||
#define GEX_STACKSMON_H
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
#if USE_STACK_MONITOR
|
||||
void stackmon_check_canaries(void);
|
||||
void stackmon_dump(void);
|
||||
void stackmon_register(const char *description, void *buffer, uint32_t len);
|
||||
#else
|
||||
#define stackmon_check_canaries() do {} while(0)
|
||||
#define stackmon_dump() do {} while(0)
|
||||
#define stackmon_register(description, buffer, len) do {} while(0)
|
||||
#endif
|
||||
|
||||
#endif //GEX_STACKSMON_H
|
||||
@@ -0,0 +1,57 @@
|
||||
//
|
||||
// Created by MightyPork on 2017/11/26.
|
||||
//
|
||||
|
||||
#include "str_utils.h"
|
||||
#include "avrlibc.h"
|
||||
|
||||
bool str_parse_yn(const char *str, bool *suc)
|
||||
{
|
||||
if (streq(str, "Y")) return true;
|
||||
if (streq(str, "1")) return true;
|
||||
if (streq(str, "YES")) return true;
|
||||
|
||||
if (streq(str, "N")) return false;
|
||||
if (streq(str, "0")) return false;
|
||||
if (streq(str, "NO")) return false;
|
||||
|
||||
*suc = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t str_parse_01(const char *str, const char *a, const char *b, bool *suc)
|
||||
{
|
||||
if (streq(str, a)) return 0;
|
||||
if (streq(str, b)) return 1;
|
||||
|
||||
*suc = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t str_parse_012(const char *str, const char *a, const char *b, const char *c, bool *suc)
|
||||
{
|
||||
if (streq(str, a)) return 0;
|
||||
if (streq(str, b)) return 1;
|
||||
if (streq(str, c)) return 2;
|
||||
|
||||
*suc = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool str_parse_pin(const char *value, char *targetName, uint8_t *targetNumber)
|
||||
{
|
||||
// discard leading 'P'
|
||||
if (value[0] == 'P') {
|
||||
value++;
|
||||
}
|
||||
|
||||
size_t len = strlen(value);
|
||||
if (len<2||len>3) return false;
|
||||
|
||||
*targetName = (uint8_t) value[0];
|
||||
if (!(*targetName >= 'A' && *targetName <= 'H')) return false;
|
||||
|
||||
// lets just hope it's OK
|
||||
*targetNumber = (uint8_t) avr_atoi(value + 1);
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
#ifndef PLATFORSTR_UTILS_H
|
||||
#define PLATFORSTR_UTILS_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include "stringbuilder.h"
|
||||
|
||||
static inline bool __attribute__((const))
|
||||
streq(const char *restrict str1, const char *restrict str2)
|
||||
{
|
||||
return strcmp(str1, str2) == 0;
|
||||
}
|
||||
|
||||
static inline bool __attribute__((const))
|
||||
strcaseq(const char *restrict str1, const char *restrict str2)
|
||||
{
|
||||
return strcasecmp(str1, str2) == 0;
|
||||
}
|
||||
|
||||
static inline bool __attribute__((const))
|
||||
strneq(const char *restrict str1, const char *restrict str2, uint32_t limit)
|
||||
{
|
||||
return strncmp(str1, str2, limit) == 0;
|
||||
}
|
||||
|
||||
static inline bool __attribute__((const))
|
||||
strncaseq(const char *restrict str1, const char *restrict str2, uint32_t limit)
|
||||
{
|
||||
return strncasecmp(str1, str2, limit) == 0;
|
||||
}
|
||||
|
||||
static inline bool __attribute__((const))
|
||||
strstarts(const char *restrict str, const char *restrict prefix)
|
||||
{
|
||||
return strncmp(str, prefix, strlen(prefix)) == 0;
|
||||
}
|
||||
|
||||
static inline char __attribute__((const))
|
||||
last_char_n(const char *str, uint32_t nth)
|
||||
{
|
||||
return str[strlen(str) - nth];
|
||||
}
|
||||
|
||||
static inline char __attribute__((const))
|
||||
last_char(const char *str)
|
||||
{
|
||||
return str[strlen(str) - 1];
|
||||
}
|
||||
|
||||
bool str_parse_yn(const char *str, bool *suc);
|
||||
uint8_t str_parse_01(const char *str, const char *a, const char *b, bool *suc);
|
||||
uint8_t str_parse_012(const char *str, const char *a, const char *b, const char *c, bool *suc);
|
||||
|
||||
#define str_01(cond, a, b) ((cond) ? (b) : (a))
|
||||
#define str_yn(cond) ((cond) ? ("Y") : ("N"))
|
||||
|
||||
bool str_parse_pin(const char *str, char *targetName, uint8_t *targetNumber);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,114 @@
|
||||
/**
|
||||
* @file stringbuilder.c
|
||||
*
|
||||
* ADAPTED FROM:
|
||||
*
|
||||
* DAPLink Interface Firmware
|
||||
* Copyright (c) 2009-2016, ARM Limited, All Rights Reserved
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "stringbuilder.h"
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
uint32_t strb_write_hex8(char *str, uint8_t value)
|
||||
{
|
||||
static const char nybble_chars[] = "0123456789abcdef";
|
||||
*(str + 0) = nybble_chars[(value >> 4) & 0x0F ];
|
||||
*(str + 1) = nybble_chars[(value >> 0) & 0x0F ];
|
||||
return 2;
|
||||
}
|
||||
|
||||
uint32_t strb_write_hex16(char *str, uint16_t value)
|
||||
{
|
||||
uint32_t pos = 0;
|
||||
pos += strb_write_hex8(str + pos, (uint8_t) ((value >> 8) & 0xFF));
|
||||
pos += strb_write_hex8(str + pos, (uint8_t) ((value >> 0) & 0xFF));
|
||||
return pos;
|
||||
}
|
||||
|
||||
uint32_t strb_write_hex32(char *str, uint32_t value)
|
||||
{
|
||||
uint32_t pos = 0;
|
||||
pos += strb_write_hex8(str + pos, (uint8_t) ((value >> 0x18) & 0xFF));
|
||||
pos += strb_write_hex8(str + pos, (uint8_t) ((value >> 0x10) & 0xFF));
|
||||
pos += strb_write_hex8(str + pos, (uint8_t) ((value >> 0x08) & 0xFF));
|
||||
pos += strb_write_hex8(str + pos, (uint8_t) ((value >> 0x00) & 0xFF));
|
||||
return pos;
|
||||
}
|
||||
|
||||
uint32_t strb_write_uint32(char *str, uint32_t value)
|
||||
{
|
||||
uint32_t temp_val;
|
||||
uint32_t digits;
|
||||
uint32_t i;
|
||||
// Count the number of digits
|
||||
digits = 0;
|
||||
temp_val = value;
|
||||
|
||||
while (temp_val > 0) {
|
||||
temp_val /= 10;
|
||||
digits += 1;
|
||||
}
|
||||
|
||||
if (digits <= 0) {
|
||||
digits = 1;
|
||||
}
|
||||
|
||||
// Write the number
|
||||
for (i = 0; i < digits; i++) {
|
||||
str[digits - i - 1] = (char) ('0' + (value % 10));
|
||||
value /= 10;
|
||||
}
|
||||
|
||||
return digits;
|
||||
}
|
||||
|
||||
uint32_t strb_write_uint32_zp(char *str, uint32_t value, uint16_t total_size)
|
||||
{
|
||||
uint32_t size;
|
||||
// Get the size of value
|
||||
size = strb_write_uint32(str, value);
|
||||
|
||||
if (size >= total_size) {
|
||||
return size;
|
||||
}
|
||||
|
||||
// Zero fill
|
||||
memset(str, '0', total_size);
|
||||
// Write value
|
||||
strb_write_uint32(str + (total_size - size), value);
|
||||
return total_size;
|
||||
}
|
||||
|
||||
uint32_t strb_write_string(char *str, const char *data)
|
||||
{
|
||||
uint32_t pos = 0;
|
||||
|
||||
while (0 != data[pos]) {
|
||||
str[pos] = data[pos];
|
||||
pos++;
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* @file stringbuilder.h
|
||||
*
|
||||
* ADAPTED FROM:
|
||||
*
|
||||
* DAPLink Interface Firmware
|
||||
* Copyright (c) 2009-2016, ARM Limited, All Rights Reserved
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef STRINGBUILDER_H
|
||||
#define STRINGBUILDER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// Write the value to the address specified and return the size
|
||||
uint32_t strb_write_hex8(char *str, uint8_t value);
|
||||
uint32_t strb_write_hex16(char *str, uint16_t value);
|
||||
uint32_t strb_write_hex32(char *str, uint32_t value);
|
||||
uint32_t strb_write_uint32(char *str, uint32_t value);
|
||||
uint32_t strb_write_uint32_zp(char *str, uint32_t value, uint16_t total_size);
|
||||
uint32_t strb_write_string(char *str, const char *data);
|
||||
|
||||
#endif //STRINGBUILDER_H
|
||||
@@ -0,0 +1,32 @@
|
||||
#ifndef TYPE_COERCE_H
|
||||
#define TYPE_COERCE_H
|
||||
|
||||
/**
|
||||
* Structs for conversion between types,
|
||||
* part of the TinyFrame utilities collection
|
||||
*
|
||||
* (c) Ondřej Hruška, 2016-2017. MIT license.
|
||||
*
|
||||
* This is a support header file for PayloadParser and PayloadBuilder.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
union conv8 {
|
||||
uint8_t u8;
|
||||
int8_t i8;
|
||||
};
|
||||
|
||||
union conv16 {
|
||||
uint16_t u16;
|
||||
int16_t i16;
|
||||
};
|
||||
|
||||
union conv32 {
|
||||
uint32_t u32;
|
||||
int32_t i32;
|
||||
float f32;
|
||||
};
|
||||
|
||||
#endif // TYPE_COERCE_H
|
||||
Reference in New Issue
Block a user