aboutsummaryrefslogtreecommitdiff
path: root/client/parse.cpp
diff options
context:
space:
mode:
authorThomasintAnker <thomasintanker1@gmail.com>2024-05-31 15:06:06 +0200
committerThomasintAnker <thomasintanker1@gmail.com>2024-05-31 15:06:06 +0200
commit0278037aaf3fd497aae57d90f2638ceda3b12a6d (patch)
tree3354a14d4551b9524108d02971bfa42fc1ad4993 /client/parse.cpp
parentb865921e5dcf2ae2d6532b88eba1a0a49998eb27 (diff)
parent18d06c79b9f6a625eb218a15c8216556fb99dc02 (diff)
Merge branch 'wip/client' into wip/i2c-communication
Diffstat (limited to 'client/parse.cpp')
-rw-r--r--client/parse.cpp169
1 files changed, 118 insertions, 51 deletions
diff --git a/client/parse.cpp b/client/parse.cpp
index 223dc5d..16f0781 100644
--- a/client/parse.cpp
+++ b/client/parse.cpp
@@ -1,14 +1,12 @@
-#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
+#include <netinet/in.h>
#include "parse.h"
-static int parse_str(const char* str, char* data, size_t* size) {
- char closing = str[0];
+static int parse_string(const char * str, char * data, size_t * offset) {
char escape = false;
- bool scan = data == NULL;
int i = 0;
size_t len = strlen(str);
@@ -22,34 +20,76 @@ static int parse_str(const char* str, char* data, size_t* size) {
default:
return -i;
}
+ char closing = str[i];
- for (i = 1; i < len && str[i] != '\0'; i++) {
+ for (i = 1; i < len && str[i] != '\0'; i++, *offset += 1) {
char c = str[i];
- if (c == closing) {
- if (scan) printf("string%s of length %d\n", escape ? " (w/ escape)" : "", i - 1);
+ if (c == closing)
return i + 1; // +1 for closing quote
+
+ if (escape && c == '\\') {
+ char x = str[i + 1];
+ if (x == '0') c = '\0';
+ else if (x == 't') c = '\t';
+ else if (x == 'n') c = '\n';
+ else if (x == 'r') c = '\r';
+ else if (x == '\\') c = '\\';
+ else if (x == '\"') c = '\"';
+ else if (x == '\'') c = '\'';
+ else break;
+ i++;
}
- if (scan) *size += 1;
+ if (data != NULL)
+ data[*offset] = c;
}
return -i;
}
-static int parse_num(const char* str, char* data, size_t* size) {
- const char* ifs = IFS;
- size_t len = strcspn(str, ifs);
- bool scan = data == NULL;
+static int parse_hexstr(const char * str, char * data, size_t * offset) {
+ size_t len = strcspn(str, IFS);
+ int i = 0;
+
+ // check if token contains at least one colon
+ const char* colon = strchr(str, ':');
+ if (colon == NULL) return -i;
+ if (colon >= str + len) return -i;
+
+ // check if token only contains allowed characters [0-9a-fA-F:]
+ size_t len_ok = strspn(str + i, SET_HEX_STR) + i;
+ if (len != len_ok) return -len_ok;
+
+ size_t c = 0;
+ while (c < len) { // count bytes in bytestring
+ if (strspn(str + c, SET_HEX) != 2)
+ return -i -c;
+
+ if (data != NULL)
+ data[*offset] = strtol(str + c, NULL, 16) & 0xff;
+
+ c += 2;
+ *offset += 1;
+
+ if (str[c] == ':') {
+ c += 1;
+ continue;
+ }
+ break;
+ }
+
+ i += len;
+ return i;
+}
+
+static int parse_number(const char * str, char * data, size_t * offset) {
+ size_t len = strcspn(str, IFS);
int i = 0;
int base = 10;
bool bytestring = false;
- const char* colon = strchr(str, ':');
- if (colon != NULL && colon < str + len) { // byte string
- base = 16;
- bytestring = true;
- } else if (len > 2 && strncmp(str, "0x", 2) == 0) { // hexadecimal prefix
+ if (len > 2 && strncmp(str, "0x", 2) == 0) { // hexadecimal prefix
base = 16;
i += 2;
}/* else if (len > 1 && strncmp(str, "0", 1) == 0) { // octal prefix
@@ -60,58 +100,85 @@ static int parse_num(const char* str, char* data, size_t* size) {
const char* set;
// if (base == 8) set = SET_OCT;
if (base == 10) set = SET_DEC;
- if (base == 16) {
- if (bytestring) set = SET_HEX_STR;
- else set = SET_HEX;
- }
+ if (base == 16) set = SET_HEX;
size_t len_ok = strspn(str + i, set) + i;
if (len != len_ok) return -len_ok;
- if (scan) {
- if (base == 10) *size += 1;
- else if (base == 16) {
- if (!bytestring) {
- *size += (len - i + 1) / 2;
- } else {
- for (; colon != NULL && colon < str + len; colon = strchr(str, ':')) {
- *size += 1;
- }
- }
+ size_t size = 1; // default integer size in bytes
+ if (base == 16) {
+ size_t prefixless = len - i;
+ switch (prefixless) {
+ case 2: // 8-bit (2 hex characters)
+ case 4: // 16-bit
+ case 8: // 32-bit
+ case 16: // 64-bit
+ break;
+ default:
+ return -i;
+ }
+ size = prefixless / 2;
+ }
+
+ if (data != NULL) {
+ unsigned long number = strtol(str + i, NULL, base);
+ long long mask = (1 << 8 * size) - 1;
+ number &= mask;
+ // NOTE: the hton? functions are used to convert host endianness to network
+ // endianness (big), and are required
+ switch (size) {
+ case 1:
+ data[*offset] = number & 0xff;
+ break;
+ case 2:
+ number = htons(number);
+ // TODO: check if the endianness is OK, or reverse these *offset indices*
+ data[*offset + 1] = (number) & 0xff;
+ data[*offset + 0] = (number >>= 8) & 0xff;
+ break;
+ case 4:
+ number = htonl(number);
+ data[*offset + 3] = (number) & 0xff;
+ data[*offset + 2] = (number >>= 8) & 0xff;
+ data[*offset + 1] = (number >>= 8) & 0xff;
+ data[*offset + 0] = (number >>= 8) & 0xff;
+ break;
}
}
- if (scan) printf("number (base %d%s) of length %lu\n", base, bytestring ? " as bytestring" : "", len - i);
+ *offset += size;
return len;
}
-int strtodata(const char* str, char** data, size_t* size) {
- const char* ifs = IFS;
- *size = 0;
- size_t i;
+static int _strtodata_main(const char * str, char* data, size_t * offset) {
size_t len = strlen(str);
- for (i = 0; i < len;) {
- // skip whitespace
- int run;
- run = strspn(&str[i], ifs);
- if (run > 0) printf("skipping whitespace for %d bytes...\n", run);
- i += run;
- // end of string
- if (str[i] == '\0') break;
+ int i, run;
+ for (i = 0; i < len; i += run) {
+ i += strspn(&str[i], IFS); // skip whitespace
+ if (str[i] == '\0') break; // end of string
- if ((run = parse_str(str + i, NULL, size)) > 0) { i += run; continue; }
- if ((run = parse_num(str + i, NULL, size)) > 0) { i += run; continue; }
+ if ((run = parse_string(str + i, data, offset)) > 0) continue;
+ if ((run = parse_hexstr(str + i, data, offset)) > 0) continue;
+ if ((run = parse_number(str + i, data, offset)) > 0) continue;
// no format detected
return -i + run;
}
- printf("end of string w/o parse errors\n");
- printf("buffer size is now %lu\n", *size);
- exit(0);
- *data = (char*) malloc(*size);
+ return i;
+}
- return 0;
+int strtodata(const char * str, char ** data, size_t * size) {
+ *size = 0;
+
+ // 1st pass: check data format
+ int ret = _strtodata_main(str, NULL, size);
+ if (ret <= 0) return ret; // on error
+
+ // 2nd pass: convert string literals into binary data
+ *data = (char*) malloc(*size);
+ size_t written = 0;
+ return _strtodata_main(str, *data, &written);
}