Created
November 20, 2017 06:27
-
-
Save rdeva31/dd4096e0e6ed2abf05ec74928302c610 to your computer and use it in GitHub Desktop.
Proof of concept
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <alloca.h> | |
#include <errno.h> | |
#include <printf.h> | |
#include <stdio.h> | |
#include <stdarg.h> | |
#include <stdint.h> | |
#include <string.h> | |
#define MAX_ANALYTICS_RECORDS 256 | |
/* | |
* Re-inventing the wheel since we can't assume -std=gnu. | |
* Warning: Don't turn this into a function because...alloca | |
*/ | |
#define __strndupa(__s, __n) ({ \ | |
char *__copy = strncpy(alloca(__n), __s, __n); \ | |
__copy[__n - 1] = '\0'; \ | |
__copy; \ | |
}) | |
int parse(char *fmt, ...) | |
{ | |
char rendered[MAX_ANALYTICS_RECORDS], *last = NULL, *curr = NULL; | |
va_list args; | |
int c = 0, rc = 0, num_vals = 0, *vals = NULL; | |
struct { | |
char *key, *val; | |
char type; | |
} *records; | |
va_start(args, fmt); | |
vsnprintf(rendered, MAX_ANALYTICS_RECORDS, fmt, args); | |
va_end(args); | |
num_vals = parse_printf_format(fmt, 0, NULL); /* alas, if only va_len(args) existed... */ | |
vals = alloca(sizeof(*vals) * num_vals); | |
parse_printf_format(fmt, num_vals, vals); | |
records = alloca(sizeof(*records) * num_vals); | |
for (curr = rendered, c = 0; (curr = strtok_r(curr, " ", &last)); curr = NULL, c++) { | |
char type = 's'; | |
switch (vals[c]) { | |
case PA_INT: | |
case PA_FLAG_SHORT: | |
type = 'i'; | |
break; | |
case PA_CHAR: | |
case PA_STRING: | |
type = 's'; | |
break; | |
case PA_FLOAT: | |
case PA_DOUBLE: | |
type = 'd'; | |
break; | |
case PA_FLAG_LONG: | |
case PA_FLAG_LONG_LONG: | |
type = 'l'; | |
break; | |
case PA_POINTER: | |
case PA_LAST: | |
case PA_FLAG_PTR: | |
default: | |
rc = -EINVAL; | |
goto err; | |
} | |
/* try to split "key=val" into pairs */ | |
records[c].key = __strndupa(curr, strchr(curr, '=') - curr + 1); | |
records[c].val = __strndupa(strrchr(curr, '=') + 1, strlen(curr)); | |
if (!records[c].key || !records[c].val) { | |
/* this doesn't look like a key-value pair... */ | |
rc = -EINVAL; | |
goto err; | |
} | |
records[c].type = type; | |
} | |
for (c = 0; c < num_vals /* num_vals == num_keys */; ++c) { | |
printf("%s = %s %c\n", records[c].key, records[c].val, records[c].type); | |
} | |
return 0; | |
err: | |
return rc; | |
} | |
struct __mac_wrapper { | |
char s[18]; /* strlen("%02x:%02x:%02x:%02x:%02x:%02x") + 1 */ | |
}; | |
static inline struct __mac_wrapper __format_mac(uint8_t *mac_addr) { | |
struct __mac_wrapper temp; | |
snprintf(temp.s, sizeof(temp.s), "%02x:%02x:%02x:%02x:%02x:%02x", | |
mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); | |
return temp; | |
} | |
#define MACSTR "%s" | |
#define MAC2STR(__mac) __format_mac(__mac).s | |
int main() { | |
uint8_t mac[] = {0, 1, 2, 3, 4, 5}; | |
parse("foo=%#02x bar=%s quz=%c mac=" MACSTR " zoo=%0.2f", 29, "two", '3', MAC2STR(mac), 2.1); | |
return 0; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment