Better field parsing

scanf style. kind of
This commit is contained in:
x3 2022-01-13 09:16:42 +01:00
parent 09c8a57a78
commit 7a6df64690
Signed by: x3
GPG Key ID: 7E9961E8AD0E240E
3 changed files with 68 additions and 37 deletions

View File

@ -1,9 +1,10 @@
InstallPrefix := /usr/local/bin
gitref="$(shell git rev-parse --short HEAD)@$(shell git branch --show-current)"
PROGNAME := caniadd
VERSION := 1
CFLAGS := -Wall -std=gnu11 #-march=native #-Werror
CPPFLAGS := -DCBC=0 -DCTR=0 -DECB=1 -Isubm/tiny-AES-c/ -Isubm/md5-c/ -Isubm/MD4/ -DPROG_VERSION='"$(VERSION)"'
CPPFLAGS := -DCBC=0 -DCTR=0 -DECB=1 -Isubm/tiny-AES-c/ -Isubm/md5-c/ -Isubm/MD4/ -DPROG_VERSION='"$(VERSION)"' -DGIT_REF='$(gitref)'
LDFLAGS := -lpthread -lsqlite3
SOURCES := $(wildcard src/*.c) subm/tiny-AES-c/aes.c subm/md5-c/md5.c subm/MD4/md4.c #$(TOML_SRC) $(BENCODE_SRC)
@ -17,9 +18,6 @@ all: $(PROGNAME)
dev: CFLAGS += -Og -ggdb -fsanitize=address -fsanitize=leak -fstack-protector-all -no-pie
dev: $(PROGNAME)
t:
echo $(SOURCES)
install: $(PROGNAME)
install -s -- $< $(InstallPrefix)/$(PROGNAME)

View File

@ -26,7 +26,6 @@ make
- Decode escaping from server
- Use a config file
- Add newline escape to server
- Better field parsing, remove the horrors at code 310
- Add myliststats cmd as --stats arg
- Add support for compression
- Implement session saving between different invocations, and session destroying

View File

@ -557,6 +557,55 @@ static bool api_get_field(const char *buffer, int32_t field_num,
return api_get_fl(buffer, field_num, " |\n", out_field_start, out_field_len);
}
/*
* Parse a line, where fields are separated by '|'
* Varargs should be:
* A scanf like format specifier - out ptr, ...
* Ended with a NULL format specifier
*
* %s is overridden, so if the string is 0 length, it will return NULL
*
* Returns the number of fields parsed
*/
int api_field_parse(const char *line, ...)
{
int f_count = 1;
va_list ap;
const char *fmt;
va_start(ap, line);
fmt = va_arg(ap, const char*);
while (fmt) {
char *fs;
size_t fl;
void *ptr;
char scan_fmt[32];
assert(fmt[0] == '%');
api_get_fl(line, f_count, "|\n", &fs, &fl);
assert(!(fl == 0 && fmt[1] != 's'));
ptr = va_arg(ap, void*);
if (fl == 0) {
*(void**)ptr = NULL;
goto next;
}
if (fmt[1] == 's') {
*(char**)ptr = strndup(fs, fl);
goto next;
}
snprintf(scan_fmt, sizeof(scan_fmt), "%%%d%s", fl, &fmt[1]);
if (sscanf(fs, scan_fmt, ptr) != 1)
goto end;
next:
f_count++;
fmt = va_arg(ap, const char*);
}
end:
va_end(ap);
return f_count - 1;
}
#if 0
static char *api_get_field_mod(char *buffer, int32_t field_num)
{
@ -858,6 +907,7 @@ enum error api_cmd_mylistadd(int64_t size, const uint8_t *hash,
/* {int4 lid}|{int4 fid}|{int4 eid}|{int4 aid}|{int4 gid}|
* {int4 date}|{int2 state}|{int4 viewdate}|{str storage}|
* {str source}|{str other}|{int2 filestate} */
int fc; /* the Freedom Club */
char *ls;
size_t ll;
struct api_mylistadd_result *mr = &res->mylistadd;
@ -866,39 +916,23 @@ enum error api_cmd_mylistadd(int64_t size, const uint8_t *hash,
assert(ll < API_BUFSIZE - 1);
(void)glr;
ls[ll] = '\0';
void *fptrs[] = {
&mr->lid, &mr->fid, &mr->eid, &mr->aid, &mr->gid, &mr->date,
&mr->state, &mr->viewdate, &mr->storage, &mr->source,
&mr->other, &mr->filestate,
};
for (int idx = 1; idx <= 12; idx++) {
char *fs, *endptr;
size_t fl;
bool pr;
uint64_t val;
size_t cpy_size = sizeof(mr->lid);
fc = api_field_parse(ls,
"%Lu", &mr->lid, "%Lu", &mr->fid, "%Lu", &mr->eid,
"%Lu", &mr->aid, "%Lu", &mr->gid, "%Lu", &mr->date,
"%hu", &mr->state, "%Lu", &mr->viewdate, "%s", &mr->storage,
"%s", &mr->source, "%s", &mr->other, "%hu", &mr->filestate,
NULL);
if (idx == 7)
cpy_size = sizeof(mr->state);
if (idx == 12)
cpy_size = sizeof(mr->filestate);
pr = api_get_field(ls, idx, &fs, &fl);
assert(pr);
(void)pr;
if (idx == 9 || idx == 10 || idx == 11) { /* string fields */
if (fl == 0)
*(char**)fptrs[idx-1] = NULL;
else
*(char**)fptrs[idx-1] = strndup(fs, fl);
continue;
}
val = strtoull(fs, &endptr, 10);
assert(!(val == 0 && fs == endptr));
memcpy(fptrs[idx-1], &val, cpy_size);
uio_debug("Fc is: %d", fc);
if (fc != 12) {
if (fc >= 9)
free(mr->storage);
if (fc >= 10)
free(mr->source);
if (fc >= 11)
free(mr->other);
uio_error("Scanf only parsed %d", fc);
err = ERR_API_RESP_INVALID;
}
}