Skip to content

Instantly share code, notes, and snippets.

@mniip
Last active December 15, 2015 19:03
Show Gist options
  • Save mniip/37ae9e58cbb6e0b625bf to your computer and use it in GitHub Desktop.
Save mniip/37ae9e58cbb6e0b625bf to your computer and use it in GitHub Desktop.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <limits.h>
#include <string.h>
char *channel_path;
char *channel_name;
int raw;
int hosts;
char **greplist;
size_t *greplistsz;
inline char *strappstr(char *dest, const char *s)
{
*dest = *s;
while(*s)
*++dest = *++s;
return dest;
}
#define S strappstr
inline char *strappnstr(char *dest, const char *s, size_t sz)
{
size_t i;
for(i = 0; i < sz; i++)
*dest = *s, dest++, s++;
*dest = 0;
return dest;
}
#define N strappnstr
#define H strappnhtml
char *strappnhtml(char *dest, const char *s, size_t sz)
{
int fg = -1;
int bg = -1;
int italic = 0;
int bold = 0;
int underline = 0;
size_t i;
for(i = 0; i < sz; )
{
int protocol = 0;
if(!strncmp(s, "http://", 7))
protocol = 7;
else if(!strncmp(s, "https://", 8))
protocol = 8;
else if(!strncmp(s, "ftp://", 6))
protocol = 6;
else if(!strncmp(s, "ptsave:", 7))
protocol = 7;
if(protocol && i + protocol < sz)
{
const char *start = s;
s += protocol;
i += protocol;
while(*s && *s != ' ' && *s != '"' && i < sz)
{
s++; i++;
}
dest = N(H(N(N(N(N(dest, "<a href=\"", 9), start, s - start), "\">", 2), start, protocol), start + protocol, s - start - protocol), "</a>", 4);
continue;
}
switch(*s)
{
case '\x02':
if(italic)
dest = N(dest, "</i>", 4);
if(underline)
dest = N(dest, "</u>", 4);
if(bold)
dest = N(dest, "</b>", 4);
else
dest = N(dest, "<b>", 3);
if(underline)
dest = N(dest, "<u>", 3);
if(italic)
dest = N(dest, "<i>", 3);
bold = !bold;
s++; i++;
break;
case '\x03':
s++; i++;
if(*s >= '0' && *s <= '9')
{
if(italic)
dest = N(dest, "</i>", 4);
if(underline)
dest = N(dest, "</u>", 4);
if(bold)
dest = N(dest, "</b>", 4);
if(bg != -1 || fg != -1)
dest = N(dest, "</span>", 7);
fg = *s - '0';
s++; i++;
if(*s >='0' && *s <= '9')
{
fg = fg * 10 + (*s - '0');
s++; i++;
if(*s == ',' && s[1] >= '0' && s[1] <= '9')
{
s++; i++;
bg = *s - '0';
s++; i++;
if(*s >='0' && *s <= '9')
{
bg = bg * 10 + (*s - '0');
s++; i++;
}
}
}
else
if(*s == ',' && s[1] >= '0' && s[1] <= '9')
{
s++; i++;
bg = *s - '0';
s++; i++;
if(*s >='0' && *s <= '9')
{
bg = bg * 10 + (*s - '0');
s++; i++;
}
}
char buffg[2];
if(fg == -2)
{
buffg[0] = 'r';
buffg[1] = 'v';
}
else
{
buffg[0] = fg / 10 + '0';
buffg[1] = fg % 10 + '0';
}
char bufbg[2];
if(bg == -2)
{
bufbg[0] = 'r';
bufbg[1] = 'v';
}
else
{
bufbg[0] = bg / 10 + '0';
bufbg[1] = bg % 10 + '0';
}
if(fg != -1)
if(bg != -1)
dest = N(N(N(N(N(dest, "<span class=\"f", 14), buffg, 2), " b", 2), bufbg, 2), "\">", 2);
else
dest = N(N(N(dest, "<span class=\"f", 14), buffg, 2), "\">", 2);
else
if(bg != -1)
dest = N(N(N(dest, "<span class=\"b", 14), bufbg, 2), "\">", 2);
if(bold)
dest = N(dest, "<b>", 3);
if(underline)
dest = N(dest, "<u>", 3);
if(italic)
dest = N(dest, "<i>", 3);
}
else
{
if(italic)
dest = N(dest, "</i>", 4);
if(underline)
dest = N(dest, "</u>", 4);
if(bold)
dest = N(dest, "</b>", 4);
if(fg != -1 || bg != -1)
{
dest = N(dest, "</span>", 7);
}
if(bold)
dest = N(dest, "<b>", 3);
if(underline)
dest = N(dest, "<u>", 3);
if(italic)
dest = N(dest, "<i>", 3);
fg = bg = -1;
}
break;
case '\x0F':
if(italic)
dest = N(dest, "</i>", 4);
if(underline)
dest = N(dest, "</u>", 4);
if(bold)
dest = N(dest, "</b>", 4);
if(bg != -1 || fg != -1)
dest = N(dest, "</span>", 7);
bold = underline = italic = 0;
fg = bg = -1;
s++; i++;
break;
case '\x16':
if(italic)
dest = N(dest, "</i>", 4);
if(underline)
dest = N(dest, "</u>", 4);
if(bold)
dest = N(dest, "</b>", 4);
if(bg != -1 || fg != -1)
dest = N(dest, "</span>", 7);
if(bg == -1)
bg = -2;
else if(bg == -2)
bg = -1;
if(fg == -1)
fg = -2;
else if(fg == -2)
fg = -1;
int tmp = bg;
bg = fg;
fg = tmp;
char buffg[2];
if(fg == -2)
{
buffg[0] = 'r';
buffg[1] = 'v';
}
else
{
buffg[0] = fg / 10 + '0';
buffg[1] = fg % 10 + '0';
}
char bufbg[2];
if(bg == -2)
{
bufbg[0] = 'r';
bufbg[1] = 'v';
}
else
{
bufbg[0] = bg / 10 + '0';
bufbg[1] = bg % 10 + '0';
}
if(fg != -1)
if(bg != -1)
dest = N(N(N(N(N(dest, "<span class=\"f", 14), buffg, 2), " b", 2), bufbg, 2), "\">", 2);
else
dest = N(N(N(dest, "<span class=\"f", 14), buffg, 2), "\">", 2);
else
if(bg != -1)
dest = N(N(N(dest, "<span class=\"b", 14), bufbg, 2), "\">", 2);
if(bold)
dest = N(dest, "<b>", 3);
if(underline)
dest = N(dest, "<u>", 3);
if(italic)
dest = N(dest, "<i>", 3);
s++; i++;
break;
case '\x1D':
if(italic)
dest = N(dest, "</i>", 4);
else
dest = N(dest, "<i>", 3);
italic = !italic;
s++; i++;
break;
case '\x1F':
if(italic)
dest = N(dest, "</i>", 4);
if(underline)
dest = N(dest, "</u>", 4);
else
dest = N(dest, "<u>", 3);
if(italic)
dest = N(dest, "<i>", 3);
underline = !underline;
s++; i++;
break;
case '&': dest = N(dest, "&amp;", 5); s++; i++; break;
case '<': dest = N(dest, "&lt;", 4); s++; i++; break;
case '>': dest = N(dest, "&gt;", 4); s++; i++; break;
default: *dest = *s; dest++; s++; i++; break;
}
}
if(italic)
dest = N(dest, "</i>", 4);
if(underline)
dest = N(dest, "</u>", 4);
if(bold)
dest = N(dest, "</b>", 4);
if(bg != -1 || fg != -1)
dest = N(dest, "</span>", 7);
*dest = 0;
return dest;
}
char *strappnplain(char *dest, const char *s, size_t sz)
{
size_t i;
for(i = 0; i < sz; i++)
switch(*s)
{
case '\x03':
s++;
if(*s < '0' || *s > '9')
break;
s++;
if(*s < '0' || *s > '9')
break;
s++;
if(*s != ',' || s[1] < '0' || s[1] > '9')
break;
s += 2;
if(*s < '0' || *s > '9')
break;
s++;
break;
case '\x02': case '\x0F': case '\x16': case '\x1F':
s++;
break;
default:
*dest = *s;
dest++; s++;
break;
}
*dest = 0;
return dest;
}
#define P strappnplain
inline int grep(const char *s, size_t sz)
{
const char **g = greplist;
if(!g)
return 1;
const size_t *gs = greplistsz;
while(*g)
if(sz == *gs && !strncasecmp(s, *g, sz))
return 1;
else
g++, gs++;
return 0;
}
void output(const char *line)
{
fputs(line, stdout);
if(raw)
putchar('\n');
}
char *renderTS(char *dest, const struct tm *t)
{
dest[0] = t->tm_hour / 10 + '0';
dest[1] = t->tm_hour % 10 + '0';
dest[2] = ':';
dest[3] = t->tm_min / 10 + '0';
dest[4] = t->tm_min % 10 + '0';
dest[5] = ':';
dest[6] = t->tm_sec / 10 + '0';
dest[7] = t->tm_sec % 10 + '0';
return dest + 8;
}
char *renderTSDate(char *dest, const struct tm *t)
{
dest[0] = (t->tm_year + 1900) / 1000 + '0';
dest[1] = (t->tm_year + 900) / 100 % 10 + '0';
dest[2] = t->tm_year / 10 % 10 + '0';
dest[3] = t->tm_year % 10 + '0';
dest[4] = '.';
dest[5] = (t->tm_mon + 1) / 10 + '0';
dest[6] = (t->tm_mon + 1) % 10 + '0';
dest[7] = '.';
dest[8] = t->tm_mday / 10 + '0';
dest[9] = t->tm_mday % 10 + '0';
return dest + 10;
}
void processLine(const struct tm *t, const char *line)
{
char rbuffer[65536];
char *buffer;
if(raw)
buffer = N(renderTS(N(rbuffer, "[", 1), t), "] ", 2);
else
buffer = N(renderTS(N(renderTSDate(N(rbuffer, "<span class=\"t\" data-date=\"", 27), t), "\" >[", 4), t), "]</span> ", 9);
int filter = 0;
// [00:00:00] ***
// [00:00:00] * nickname
// [00:00:00] -nickname-
// [00:00:00] <nickname>
// 0123456789012
if(line[11] == '*')
if(line[12] == '*')
// [00:00:00] *** Quits:
// [00:00:00] *** Parts:
// [00:00:00] *** Joins:
// [00:00:00] *** nickname is now known as
// [00:00:00] *** nickname sets mode:
// [00:00:00] *** nickname was kicked by
// [00:00:00] *** nickname changes topic to
// 012345678901234567890
// 01
if(line[20] == ':')
switch(line[15])
{
case 'Q':
{
// [00:00:00] *** Quits: nickname (host) (reason)
// 01234567890123456789012
// 012
// 0123
// -10
const char *nickname = line + 22;
const char *nickend = strchr(nickname, ' ');
const char *host = nickend + 2;
const char *hostend = strchr(host, ')');
const char *reason = hostend + 3;
const char *reasonend = reason + strlen(reason) - 1;
if(grep(nickname, nickend - nickname))
{
filter = 1;
if(raw)
if(hosts)
N(P(N(N(N(N(N(buffer, "*** ", 4), nickname, nickend - nickname), " (", 2), host, hostend - host), ") has quit (", 12), reason, reasonend - reason), ")", 1);
else
N(P(N(N(N(buffer, "*** ", 4), nickname, nickend - nickname), " has quit (", 11), reason, reasonend - reason), ")", 1);
else
if(hosts)
N(H(N(N(N(N(N(buffer, "<span class=\"q\">*** ", 20), nickname, nickend - nickname), " (", 2), host, hostend - host), ") has quit (", 12), reason, reasonend - reason), ")</span><br />", 14);
else
N(H(N(N(N(buffer, "<span class=\"q\">*** ", 20), nickname, nickend - nickname), " has quit (", 11), reason, reasonend - reason), ")</span><br />", 14);
}
break;
}
case 'P':
{
// [00:00:00] *** Parts: nickname (host) (reason)
// 01234567890123456789012
// -1012
// -10123
// -10
const char *nickname = line + 22;
const char *nickend = strchr(nickname, ' ');
const char *host = nickend + 2;
const char *hostend = strchr(host, ')');
const char *reason = hostend + 3;
const char *reasonend = reason + strlen(reason) - 1;
if(grep(nickname, nickend - nickname))
{
filter = 1;
if(raw)
if(hosts)
N(P(N(S(N(N(N(N(N(buffer, "*** ", 4), nickname, nickend - nickname), " (", 2), host, hostend - host), ") has left ", 11), channel_name), " (", 2), reason, reasonend - reason), ")", 1);
else
N(P(N(S(N(N(N(buffer, "*** ", 4), nickname, nickend - nickname), " has left ", 10), channel_name), " (", 2), reason, reasonend - reason), ")", 1);
else
if(hosts)
N(H(N(S(N(N(N(N(N(buffer, "<span class=\"l\">*** ", 20), nickname, nickend - nickname), " (", 2), host, hostend - host), ") has left ", 11), channel_name), " (", 2), reason, reasonend - reason), ")</span><br />", 14);
else
N(H(N(S(N(N(N(buffer, "<span class=\"l\">*** ", 20), nickname, nickend - nickname), " has left ", 10), channel_name), " (", 2), reason, reasonend - reason), ")</span><br />", 14);
}
break;
}
case 'J':
{
// [00:00:00] *** Joins: nickname (host)
// 01234567890123456789012
// -1012
// -10
const char *nickname = line + 22;
const char *nickend = strchr(nickname, ' ');
const char *host = nickend + 2;
const char *hostend = host + strlen(host) - 1;
if(grep(nickname, nickend - nickname))
{
filter = 1;
if(raw)
if(hosts)
S(N(N(N(N(N(buffer, "*** ", 4), nickname, nickend - nickname), " (", 2), host, hostend - host), ") has joined ", 13), channel_name);
else
S(N(N(N(buffer, "*** ", 4), nickname, nickend - nickname), " has joined ", 12), channel_name);
else
if(hosts)
N(S(N(N(N(N(N(buffer, "<span class=\"j\">*** ", 20), nickname, nickend - nickname), " (", 2), host, hostend - host), ") has joined ", 13), channel_name), "</span><br />", 13);
else
N(S(N(N(N(buffer, "<span class=\"j\">*** ", 20), nickname, nickend - nickname), " has joined ", 12), channel_name), "</span><br />", 13);
}
break;
}
}
else
{
const char *nickname = line + 15;
const char *nickend = strchr(nickname, ' ');
switch(nickend[1])
{
case 'i':
{
// [00:00:00] *** nickname is now known as nickname
// 012345678901234567
const char *newnick = nickend + 17;
if(grep(nickname, nickend - nickname) || grep(newnick, strlen(newnick)))
{
filter = 1;
if(raw)
S(N(N(N(buffer, "*** ", 4), nickname, nickend - nickname), " has changed nick to ", 21), newnick);
else
N(S(N(N(N(buffer, "<span class=\"z\">*** ", 20), nickname, nickend - nickname), " has changed nick to ", 21), newnick), "</span><br />", 13);
}
break;
}
case 's':
{
// [00:00:00] *** nickname sets mode: +mode
// 0123456789012
const char *mode = nickend + 12;
if(grep(nickname, nickend - nickname))
{
filter = 1;
if(raw)
S(N(S(N(N(N(buffer, "*** ", 4), nickname, nickend - nickname), " set mode ", 10), mode), " on ", 4), channel_name);
else
N(S(N(S(N(N(N(buffer, "<span class=\"m\">*** ", 20), nickname, nickend - nickname), " set mode <span class=\"r\">", 26), mode), "</span> on ", 11), channel_name), "</span><br />", 13);
}
break;
}
case 'w':
{
// [00:00:00] *** nickname was kicked by nickname (reason)
// 0123456789012345
// 012
// -10
const char *kicker = nickend + 15;
const char *kickerend = strchr(kicker, ' ');
const char *reason = kickerend + 2;
const char *reasonend = reason + strlen(reason) - 1;
if(grep(kicker, kickerend - kicker) || grep(nickname, nickend - nickname))
{
filter = 1;
if(raw)
N(P(N(S(N(N(N(N(N(buffer, "*** ", 4), nickname, nickend - nickname), " was kicked by ", 15), kicker, kickerend - kicker), " from ", 6), channel_name), " (", 2), reason, reasonend - reason), ")", 1);
else
N(H(N(S(N(N(N(N(N(buffer, "<span class=\"k\">*** ", 20), nickname, nickend - nickname), " was kicked by ", 15), kicker, kickerend - kicker), " from ", 6), channel_name), " (", 2), reason, reasonend - reason), ")</span><br />", 14);
}
break;
}
case 'c':
{
// [00:00:00] *** nickname changes topic to 'topic'
// 01234567890123456789
// -10
const char *topic = nickend + 19;
const char *topicend = topic + strlen(topic) - 1;
if(grep(nickname, nickend - nickname))
{
filter = 1;
if(raw)
P(N(S(N(N(N(buffer, "*** ", 4), nickname, nickend - nickname), " has changed topic of ", 22), channel_name), " to: ", 5), topic, topicend - topic);
else
N(H(N(S(N(N(N(buffer, "<span class=\"h\">*** ", 20), nickname, nickend - nickname), " has changed topic of ", 22), channel_name), " to: <span class=\"r\">", 21), topic, topicend - topic), "</span></span><br />", 20);
}
break;
}
}
}
else
{
// [00:00:00] * nickname Text
// 01234567890123
// 01
const char *nickname = line + 13;
const char *nickend = strchr(nickname, ' ');
const char *text = nickend + 1;
if(grep(nickname, nickend - nickname))
{
filter = 1;
if(raw)
P(N(N(N(buffer, "* ", 2), nickname, nickend - nickname), " ", 1), text, strlen(text));
else
N(H(N(N(N(buffer, "<span class=\"a\">* ", 18), nickname, nickend - nickname), " ", 1), text, strlen(text)), "</span><br />", 13);
}
}
else if (line[11] == '-')
{
// [00:00:00] -nickname- Text
// 0123456789012
// 012
const char *nickname = line + 12;
const char *nickend = strchr(nickname, ' ') - 1;
const char *text = nickend + 2;
if(grep(nickname, nickend - nickname))
{
filter = 1;
if(raw)
P(N(N(N(buffer, "--", 2), nickname, nickend - nickname), "-- ", 3), text, strlen(text));
else
N(H(N(N(N(buffer, "<span class=\"b\">--", 18), nickname, nickend - nickname), "--</span> ", 10), text, strlen(text)), "<br />", 6);
}
}
else
{
// [00:00:00] <nickname> Text
// 0123456789012
// 012
const char *nickname = line + 12;
const char *nickend = strchr(nickname, '>');
const char *text = nickend + 2;
if(grep(nickname, nickend - nickname))
{
filter = 1;
if(raw)
P(N(N(N(buffer, "<", 1), nickname, nickend - nickname), "> ", 2), text, strlen(text));
else
N(H(N(N(N(buffer, "<span class=\"b\">&lt;", 20), nickname, nickend - nickname), "&gt;</span> ", 12), text, strlen(text)), "<br />", 6);
}
}
if(filter)
output(rbuffer);
}
static char fn[PATH_MAX];
const char *makeFilename(const struct tm *v)
{
strcpy(fn, channel_path);
ssize_t base = strlen(channel_path) - 1;
char *p = fn + base;
*++p = (v->tm_year + 1900) / 1000 + '0';
*++p = (v->tm_year + 900) / 100 % 10 + '0';
*++p = v->tm_year / 10 % 10 + '0';
*++p = v->tm_year % 10 + '0';
*++p = (v->tm_mon + 1) / 10 % 10 + '0';
*++p = (v->tm_mon + 1) % 10 + '0';
*++p = v->tm_mday / 10 % 10 + '0';
*++p = v->tm_mday % 10 + '0';
*++p = '.'; *++p = 'l'; *++p = 'o'; *++p = 'g';
return fn;
}
inline int checkTSAbove(const struct tm *v, const struct tm *H)
{
if(v->tm_hour > H->tm_hour) return 1;
if(v->tm_hour < H->tm_hour) return 0;
if(v->tm_min > H->tm_min) return 1;
if(v->tm_min < H->tm_min) return 0;
if(v->tm_sec >= H->tm_sec) return 1;
return 0;
}
inline int checkTSBelow(const struct tm *v, const struct tm *t)
{
if(v->tm_hour > t->tm_hour) return 0;
if(v->tm_hour < t->tm_hour) return 1;
if(v->tm_min > t->tm_min) return 0;
if(v->tm_min < t->tm_min) return 1;
if(v->tm_sec > t->tm_sec) return 0;
return 1;
}
static struct tm t;
const struct tm *mergeTS(const char *line, const struct tm *T)
{
// [00:00:00
// 012345678
int hour = (line[1] - '0') * 10 + (line[2] - '0');
int minute = (line[4] - '0') * 10 + (line[5] - '0');
int second = (line[7] - '0') * 10 + (line[8] - '0');
t.tm_year = T->tm_year;
t.tm_mon = T->tm_mon;
t.tm_mday = T->tm_mday;
t.tm_hour = hour;
t.tm_min = minute;
t.tm_sec = second;
return &t;
}
inline void processFile(const char *name, const struct tm *H)
{
FILE *f = fopen(name, "r");
if(f)
{
char *line = NULL;
size_t len = 0;
ssize_t read;
while(0 < (read = getline(&line, &len, f)))
{
line[read - 1] = 0;
processLine(mergeTS(line, H), line);
}
free(line);
fclose(f);
}
}
inline void processFileH(const char *name, const struct tm *H)
{
FILE *f = fopen(name, "r");
if(f)
{
char *line = NULL;
size_t len = 0;
ssize_t read;
while(0 < (read = getline(&line, &len, f)))
{
const struct tm *v = mergeTS(line, H);
if(checkTSAbove(v, H))
{
line[read - 1] = 0;
processLine(v, line);
break;
}
}
while(0 < (read = getline(&line, &len, f)))
{
line[read - 1] = 0;
processLine(mergeTS(line, H), line);
}
free(line);
fclose(f);
}
}
inline void processFileT(const char *name, const struct tm *T)
{
FILE *f = fopen(name, "r");
if(f)
{
char *line = NULL;
size_t len = 0;
ssize_t read;
while(0 < (read = getline(&line, &len, f)))
{
const struct tm *v = mergeTS(line, T);
if(!checkTSBelow(v, T))
break;
line[read - 1] = 0;
processLine(v, line);
}
free(line);
fclose(f);
}
}
inline void processFileHT(const char *name, const struct tm *H, const struct tm *T)
{
FILE *f = fopen(name, "r");
if(f)
{
char *line = NULL;
size_t len = 0;
ssize_t read;
while(0 < (read = getline(&line, &len, f)))
{
const struct tm *v = mergeTS(line, H);
if(checkTSAbove(v, H))
{
line[read - 1] = 0;
processLine(v, line);
break;
}
}
while(0 < (read = getline(&line, &len, f)))
{
const struct tm *v = mergeTS(line, T);
if(!checkTSBelow(v, T))
break;
line[read - 1] = 0;
processLine(v, line);
}
free(line);
fclose(f);
}
}
void process(const struct tm *H, const struct tm *T)
{
if(H->tm_mday == T->tm_mday && H->tm_mon == T->tm_mon && H->tm_year == T->tm_year)
processFileHT(makeFilename(H), H, T);
else
{
processFileH(makeFilename(H), H);
struct tm v = *H;
v.tm_mday++;
mktime(&v);
while(v.tm_mday != T->tm_mday || v.tm_mon != T->tm_mon || v.tm_year != T->tm_year)
{
processFile(makeFilename(&v), &v);
v.tm_mday++;
mktime(&v);
}
processFileT(makeFilename(T), T);
}
}
int main(int argc, char *argv[])
{
channel_path = malloc(PATH_MAX);
strcpy(channel_path, "/var/log/irc/freenode/");
strcat(channel_path, argv[1]);
strcat(channel_path, "/");
channel_name = malloc(120);
strcpy(channel_name, argv[1]);
if(*argv[4])
{
greplist = malloc(128 * sizeof(char *));
greplistsz = malloc(128 * sizeof(size_t));
int n = 0;
char *list = argv[4];
do
{
greplist[n] = strsep(&list, ",");
if(greplist[n])
greplistsz[n] = strlen(greplist[n]);
n++;
}
while(list);
}
else
greplist = NULL;
time_t tH = atoll(argv[2]), tT = atoll(argv[3]);
if(tH > tT)
return 0;
raw = strchr(argv[5], 'r') ? 1 : 0;
hosts = strchr(argv[5], 'h') ? 1 : 0;
struct tm H = *gmtime(&tH), T = *gmtime(&tT);
process(&H, &T);
free(channel_path);
free(channel_name);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment