Skip to content

Instantly share code, notes, and snippets.

@legionus
Last active October 24, 2020 17:47
Show Gist options
  • Save legionus/175563beed3f3f22c2a9f7734b66e685 to your computer and use it in GitHub Desktop.
Save legionus/175563beed3f3f22c2a9f7734b66e685 to your computer and use it in GitHub Desktop.
#include <sys/uio.h>
#include <unistd.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <error.h>
enum record_fields_type {
RECORD_FIELD_TIME = 0,
RECORD_FIELD_HOST,
RECORD_FIELD_MSG,
RECORD_FIELD_COUNTS,
};
#define RECORD_FIELD_REPEAT_MAX 5
#define RECORD_FIELDS_MAX RECORD_FIELD_COUNTS * RECORD_FIELD_REPEAT_MAX
#define RECORDS_MAX RECORD_FIELDS_MAX * 2 + 1
long int iov_max;
struct format {
char line[LINE_MAX];
struct iovec record[RECORDS_MAX];
struct {
enum record_fields_type source;
struct iovec *destination;
} rules[RECORD_FIELDS_MAX];
};
static void set_format_record(struct format *fmt, int i, char *s, size_t n)
{
if (i >= iov_max)
error(1, 0, "too many parts in the record format");
fmt->record[i].iov_base = s;
fmt->record[i].iov_len = n;
}
static void set_format_rule(struct format *fmt, int i,
enum record_fields_type t, struct iovec *v)
{
if (i >= RECORD_FIELDS_MAX)
error(1, 0, "too many fields in the record");
fmt->rules[i].source = t;
fmt->rules[i].destination = v;
}
static void parse_format(struct format *fmt, char *line)
{
char *cur, *ptr;
int rec_nr, rule_nr, special;
strncpy(fmt->line, line, LINE_MAX);
memset(fmt->record, 0, sizeof(fmt->record[0]) * RECORDS_MAX);
memset(fmt->rules, 0, sizeof(fmt->rules[0]) * RECORD_FIELDS_MAX);
special = rec_nr = rule_nr = 0;
cur = ptr = fmt->line;
while (*ptr != '\0') {
enum record_fields_type ruletype;
if (special) {
switch (*ptr) {
case 't': ruletype = RECORD_FIELD_TIME; break;
case 'h': ruletype = RECORD_FIELD_HOST; break;
case 'm': ruletype = RECORD_FIELD_MSG; break;
case '%':
special = 0;
goto create_special;
default:
error(1, 0, "unexpected special: '%%%c'", *ptr);
}
special = 0;
goto create_rule;
} else if (*ptr == '%')
special = 1;
next:
ptr++;
continue;
create_rule:
set_format_record(fmt, rec_nr++, cur, (ptr - cur - 1));
set_format_rule(fmt, rule_nr++, ruletype, fmt->record + rec_nr);
set_format_record(fmt, rec_nr++, NULL, 0);
cur = ptr + 1;
goto next;
create_special:
set_format_record(fmt, rec_nr++, cur, (ptr - cur - 1));
cur = ptr;
goto next;
}
if (special)
error(1, 0, "unexpected '%%' at the end of line");
if (cur != ptr)
set_format_record(fmt, rec_nr++, cur, (ptr - cur));
}
static char *curtime = (char *) "May 2 12:34:56";
static char *curhost = (char *) "localhost";
static char *curmsg = (char *) "TEST";
int main(int argc, char **argv)
{
struct format fmt;
iov_max = sysconf(_SC_IOV_MAX);
printf("%s\n", argv[1]);
parse_format(&fmt, argv[1]);
for (int i = 0; i < RECORD_FIELDS_MAX; i++) {
if (!fmt.rules[i].destination)
continue;
switch (fmt.rules[i].source) {
case RECORD_FIELD_TIME:
fmt.rules[i].destination->iov_base = curtime;
fmt.rules[i].destination->iov_len = strlen(curtime);
break;
case RECORD_FIELD_HOST:
fmt.rules[i].destination->iov_base = curhost;
fmt.rules[i].destination->iov_len = strlen(curhost);
break;
case RECORD_FIELD_MSG:
fmt.rules[i].destination->iov_base = curmsg;
fmt.rules[i].destination->iov_len = strlen(curmsg);
break;
default:
break;
}
}
writev(STDOUT_FILENO, fmt.record, RECORDS_MAX);
printf("\n");
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment