STM32 firmware for a remotely-controlled stepper motor demo with a mobile interface.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

287 lines
5.2 KiB

#include "str_utils.h"
#include "matcher.h"
#include "malloc_safe.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
// Lot of this stuff is actually not needed anymore,
// it was written for the ESP AT firmware, which is no longer used.
/**
* Escape a char.
* @returns what to put after backslash, or '\0' for no escape.
*/
static char escape_char(char c)
{
switch (c) {
case '\r': return 'r';
case '\n': return 'n';
case '\t': return 't';
case '\\': return '\\';
default: return 0;
}
}
/**
* Escape string in place
*/
void str_escape_ip(char * buf, size_t buf_len)
{
size_t i = 0;
// string length (updated when escapes are performed)
size_t slen = strlen(buf);
for (; i < buf_len - 1 && buf[i] != 0; i++) {
char replace = escape_char(buf[i]);
// Escape, shift trailing chars
if (replace != 0) {
if (i >= buf_len - 2) {
break; // discard the char, escape wouldn't fit.
}
// (could be faster if moved starting at the end)
char m = buf[i + 1]; // remember next char
buf[i] = '\\';
buf[i + 1] = replace;
slen++; // account for the added backslash
// shift trailing chars
for (size_t j = i + 2; j <= slen; j++) {
char n = buf[j];
buf[j] = m;
m = n;
}
i++; // skip the insterted slash
}
}
buf[i] = 0; // add terminator (in case end of string was reached)
}
void str_escape(char *dest, const char *src, size_t dest_len)
{
size_t di = 0, si = 0;
for (; src[si] != 0 && di < dest_len - 1; si++) {
char orig = src[si];
char replace = escape_char(orig);
if (replace == 0) {
dest[di++] = orig;
} else {
if (di >= dest_len - 2) {
break; // out of space
}
dest[di++] = '\\';
dest[di++] = replace;
}
}
dest[di] = 0; // append terminator
}
int32_t strpos(const char *haystack, const char *needle)
{
const char *p = strstr(haystack, needle);
if (p) return (p - haystack);
return -1; // Not found = -1.
}
int32_t strpos_upto(const char *haystack, const char *needle, size_t limit)
{
if (limit <= 0) return strpos(haystack, needle);
matcher_t m = {needle, 0};
char c;
for (size_t i = 0; i < limit; i++, haystack++) {
c = *haystack;
if (c == 0) break;
if (matcher_test(&m, (uint8_t)c)) {
return i - strlen(needle) + 1; // match occured on the last needle char
}
}
return -1;
}
int32_t strpos_upto_match(const char *haystack, const char *needle, const char *endmatch)
{
if (endmatch == NULL) return strpos(haystack, needle);
matcher_t matcher_needle = {needle, 0};
matcher_t matcher_end = {endmatch, 0};
char c;
for (int i = 0;; i++, haystack++) {
c = *haystack;
if (c == 0) break;
// match
if (matcher_test(&matcher_needle, (uint8_t)c)) {
return i - strlen(needle) + 1; // match occured on the last needle char
}
// end
if (matcher_test(&matcher_end, (uint8_t)c)) {
return -1;
}
}
return -1;
}
size_t str_copy(char * dest, const char *src)
{
char c;
size_t i = 0;
while ((c = *src++) != 0) {
*dest++ = c;
i++;
}
return i;
}
/**
* Decode URL-encoded string in place.
*/
void urldecode_ip(char *str)
{
unsigned int x;
for (size_t i = 0; str[i] != 0; i++) {
char c = str[i];
if (c == '+') {
str[i] = ' ';
} else if (c == '%') {
// decode the byte
sscanf(&str[i + 1], "%02x", &x);
str[i] = (char)x;
// shift following chars
for (size_t a = i + 3, b = i + 1;; a++, b++) {
str[b] = str[a]; // move
if (str[a] == 0) break;
}
}
}
}
/**
* url-decode string, put output in a buffer.
*/
void urldecode(char *dest, const char *src)
{
unsigned int x;
size_t si = 0, di = 0;
for (; src[si] != 0; si++) {
char c = src[si];
if (c == '+') {
dest[di++] = ' ';
} else if (c == '%') {
// decode the byte
sscanf(&src[si + 1], "%02x", &x);
dest[di++] = (char)x;
si += 2;
} else {
dest[di++] = c;
}
}
// add terminator
dest[di] = 0;
}
/**
* url-decode string, put output in a buffer.
* Limit operation to N chars in input string
*/
void urldecode_n(char *dest, const char *src, size_t count)
{
unsigned int x;
size_t si = 0, di = 0;
for (; src[si] != 0 && si < count; si++) {
char c = src[si];
if (c == '+') {
dest[di++] = ' ';
} else if (c == '%') {
// decode the byte
sscanf(&src[si + 1], "%02x", &x);
dest[di++] = (char)x;
si += 2;
} else {
dest[di++] = c;
}
}
// add terminator
dest[di] = 0;
}
bool get_query_value(char *buffer, const char *querystring, const char *key, size_t buf_len)
{
bool retval;
size_t qs_len = strlen(querystring);
char *ptrn = malloc_s(strlen(key) + 3); // &key=\0
sprintf(ptrn, "&%s=", key);
matcher_t m = {ptrn, 1}; // pretend ampersand was already matched
for (size_t i = 0; i < qs_len; i++) {
char c = querystring[i];
if (matcher_test(&m, (uint8_t)c)) {
// found the match
i++; // advance past the equals sign
size_t seg_end = i;
while (seg_end < qs_len && querystring[seg_end] != '&') {
seg_end++;
}
if (seg_end - i > buf_len) seg_end = i + buf_len;
if (seg_end == i) {
buffer[0] = 0; // strncpy behaves strange with length 0
} else {
urldecode_n(buffer, querystring + i, seg_end - i);
}
retval = true;
goto done;
}
}
// not found
retval = false;
done:
free(ptrn);
return retval;
}