Skip to content

Instantly share code, notes, and snippets.

@rdeva31
Created November 20, 2017 06:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rdeva31/dd4096e0e6ed2abf05ec74928302c610 to your computer and use it in GitHub Desktop.
Save rdeva31/dd4096e0e6ed2abf05ec74928302c610 to your computer and use it in GitHub Desktop.
Proof of concept
#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