summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJon Bergli Heier <snakebite@jvnv.net>2010-06-05 23:59:38 +0200
committerJon Bergli Heier <snakebite@jvnv.net>2010-06-05 23:59:38 +0200
commit91e5543757dad266f041f46d11bf973966368a30 (patch)
treec3f6b80463fd7c1bf6ec1a113a644e6934354a3d
parenta1039148b6e06df5af790846087b7837c60a88b9 (diff)
Mostly-working implementation of time tracking for users.time
Needs some more testing.
-rw-r--r--config.c28
-rw-r--r--config.h1
-rw-r--r--export_xml.c12
-rw-r--r--parsing.c315
-rw-r--r--regexset.c103
-rw-r--r--regexset.h10
-rw-r--r--user.c50
-rw-r--r--user.h15
8 files changed, 506 insertions, 28 deletions
diff --git a/config.c b/config.c
index 2cb6aa6..e710e83 100644
--- a/config.c
+++ b/config.c
@@ -39,6 +39,14 @@ int cfg_init() {
ircstats_config.wordlen_min = 3;
}
+ if(!config_lookup_string(&config, "log_date_format", &ircstats_config.log_date_format)) {
+ ircstats_config.log_date_format = NULL;
+ }
+
+ if(!config_lookup_string(&config, "day_date_format", &ircstats_config.day_date_format)) {
+ ircstats_config.day_date_format = NULL;
+ }
+
config_setting_t *regexes_setting = config_lookup(&config, "regexes");
if(!config_setting_is_aggregate(regexes_setting)) {
fprintf(stderr, "Setting \"regexes\" must be an aggregate type.\n");
@@ -49,12 +57,24 @@ int cfg_init() {
for(int i = 0; i < regex_count; i++) {
config_setting_t *re_setting = config_setting_get_elem(regexes_setting, i);
- const char *text, *join, *kick;
- if(!(config_setting_lookup_string(re_setting, "text", &text) && config_setting_lookup_string(re_setting, "join", &join) && config_setting_lookup_string(re_setting, "kick", &kick))) {
+ const char *text, *join, *part, *quit, *kick, *nick_changed, *log_opened, *day_changed, *log_date_format, *day_date_format;
+ if(!(config_setting_lookup_string(re_setting, "text", &text)
+ && config_setting_lookup_string(re_setting, "join", &join)
+ && config_setting_lookup_string(re_setting, "part", &part)
+ && config_setting_lookup_string(re_setting, "quit", &quit)
+ && config_setting_lookup_string(re_setting, "kick", &kick)
+ && config_setting_lookup_string(re_setting, "nick_changed", &nick_changed)
+ && config_setting_lookup_string(re_setting, "log_opened", &log_opened)
+ && config_setting_lookup_string(re_setting, "day_changed", &day_changed)
+ )) {
fprintf(stderr, "Regex set #%d missing one or more keys.\n", i+1);
return 0;
}
- if(!rs_add(text, join, kick))
+ if(!config_setting_lookup_string(re_setting, "log_date_format", &log_date_format))
+ log_date_format = NULL;
+ if(!config_setting_lookup_string(re_setting, "day_date_format", &day_date_format))
+ day_date_format = NULL;
+ if(!rs_add(text, join, part, quit, kick, nick_changed, log_opened, day_changed, log_date_format, day_date_format))
return 0;
}
@@ -86,7 +106,7 @@ int cfg_init() {
}
config_setting_t *files = config_setting_get_member(channel_setting, "files");
if(!config_setting_is_aggregate(files)) {
- fprintf(stderr, "Setting \"files\" must be an aggregate type (no files added).\n", name);
+ fprintf(stderr, "Setting \"files\" must be an aggregate type (no files added).\n");
continue;
}
int file_count = config_setting_length(files);
diff --git a/config.h b/config.h
index c62dfa5..163be18 100644
--- a/config.h
+++ b/config.h
@@ -6,6 +6,7 @@ void cfg_free();
struct ircstats_config_t {
int threads, monolog_min, wordlen_min;
+ const char *log_date_format, *day_date_format;
};
extern struct ircstats_config_t ircstats_config;
diff --git a/export_xml.c b/export_xml.c
index 1bed18b..4f77bbc 100644
--- a/export_xml.c
+++ b/export_xml.c
@@ -79,6 +79,18 @@ int export_xml(struct channel_t *channel, struct user_t *users) {
xmlTextWriterWriteFormatString(writer, "%llu", user->monologs);
xmlTextWriterEndElement(writer);
+ xmlTextWriterStartElement(writer, (const xmlChar*)"seen_first");
+ xmlTextWriterWriteFormatString(writer, "%lu", user->seen_first);
+ xmlTextWriterEndElement(writer);
+
+ xmlTextWriterStartElement(writer, (const xmlChar*)"seen_last");
+ xmlTextWriterWriteFormatString(writer, "%lu", user->seen_last);
+ xmlTextWriterEndElement(writer);
+
+ xmlTextWriterStartElement(writer, (const xmlChar*)"time_total");
+ xmlTextWriterWriteFormatString(writer, "%lu", user->time_total);
+ xmlTextWriterEndElement(writer);
+
/* Add lines for this user. */
xmlTextWriterStartElement(writer, (const xmlChar*)"lines");
for(int h = 0; h < 24; h++) {
diff --git a/parsing.c b/parsing.c
index 9653eb8..fea0e96 100644
--- a/parsing.c
+++ b/parsing.c
@@ -3,6 +3,7 @@
#include <wctype.h>
#include <wchar.h>
#include <pthread.h>
+#include <errno.h>
#include "parsing.h"
#include "channel.h"
@@ -15,12 +16,15 @@
#define TEXT_BUFFER_SIZE 0x400
#define LINE_BUFFER_SIZE 0x400
#define TIME_BUFFER_SIZE 0xf
+#define DATE_BUFFER_SIZE 0x20
-static pthread_mutex_t user_mutex, word_mutex, channel_mutex;
+static pthread_mutex_t user_mutex, user_time_mutex, word_mutex, channel_mutex, time_mutex;
static struct user_t *last_user = NULL;
static int in_monolog = 0, monolog_len = 0;
+static struct tm now_global;
+
static inline void add_word(struct user_t *user, wchar_t *word, int len) {
pthread_mutex_lock(&user_mutex);
user->words++;
@@ -36,6 +40,24 @@ static inline void add_word(struct user_t *user, wchar_t *word, int len) {
static void process_file(FILE *f, struct channel_t *channel, struct regexset_t *rs) {
char line[LINE_BUFFER_SIZE];
+ const char *log_date_format, *day_date_format;
+ struct tm now;
+
+ if(rs->log_date_format) {
+ log_date_format = rs->log_date_format;
+ } else if(ircstats_config.log_date_format) {
+ log_date_format = ircstats_config.log_date_format;
+ } else {
+ log_date_format = NULL;
+ }
+
+ if(rs->day_date_format) {
+ day_date_format = rs->day_date_format;
+ } else if(ircstats_config.day_date_format) {
+ day_date_format = ircstats_config.day_date_format;
+ } else {
+ day_date_format = NULL;
+ }
while(fgets(line, LINE_BUFFER_SIZE, f)) {
int rc;
@@ -82,6 +104,30 @@ static void process_file(FILE *f, struct channel_t *channel, struct regexset_t *
user->lines[time_i]++;
pthread_mutex_unlock(&user_mutex);
+ pthread_mutex_lock(&time_mutex);
+ now = now_global;
+ pthread_mutex_unlock(&time_mutex);
+
+ now.tm_hour = hour;
+ now.tm_min = min;
+ time_t now_ut = mktime(&now);
+
+ pthread_mutex_lock(&user_time_mutex);
+ struct user_time_t *user_time = user_time_get(nick, 0);
+ if(user_time->seen_first == 0) {
+ user_time->seen_first = now_ut;
+ }
+ /* Set if user is not yet seen. */
+ if(user_time->last_join == 0) {
+ user_time->last_join = now_ut;
+ }
+ /* Add to online total. */
+ if(user_time->seen_last > 0) {
+ user_time->time_total += now_ut - user_time->seen_last;
+ }
+ user_time->seen_last = now_ut;
+ pthread_mutex_unlock(&user_time_mutex);
+
pthread_mutex_lock(&channel_mutex);
channel->hours[time_i]++;
pthread_mutex_unlock(&channel_mutex);
@@ -112,25 +158,240 @@ static void process_file(FILE *f, struct channel_t *channel, struct regexset_t *
rc = pcre_exec(rs->join, rs->join_e, line, strlen(line), 0, 0, ovector, 30);
if(rc > 0) {
- char nick[NICK_BUFFER_SIZE];
+ char nick[NICK_BUFFER_SIZE], hour_s[TIME_BUFFER_SIZE], min_s[TIME_BUFFER_SIZE];
pcre_copy_named_substring(rs->join, line, ovector, rc, "nick", nick, NICK_BUFFER_SIZE);
- pthread_mutex_lock(&user_mutex);
- struct user_t *user = user_get(nick);
- pthread_mutex_unlock(&user_mutex);
+ pcre_copy_named_substring(rs->join, line, ovector, rc, "hour", hour_s, TIME_BUFFER_SIZE);
+ pcre_copy_named_substring(rs->join, line, ovector, rc, "minute", min_s, TIME_BUFFER_SIZE);
+
+ int hour, min;
+ hour = atoi(hour_s);
+ min = atoi(min_s);
+
+ pthread_mutex_lock(&time_mutex);
+ now = now_global;
+ pthread_mutex_unlock(&time_mutex);
+
+ now.tm_hour = hour;
+ now.tm_min = min;
+ time_t now_ut = mktime(&now);
+
+ pthread_mutex_lock(&user_time_mutex);
+ struct user_time_t *user_time = user_time_get(nick, 0);
+
+ if(user_time->seen_first == 0) {
+ user_time->seen_first = now_ut;
+ }
+ user_time->last_join = user_time->seen_last = now_ut;
+ pthread_mutex_unlock(&user_time_mutex);
+
+ continue;
+ }
+
+ rc = pcre_exec(rs->part, rs->part_e, line, strlen(line), 0, 0, ovector, 30);
+ if(rc > 0) {
+ char nick[NICK_BUFFER_SIZE], hour_s[TIME_BUFFER_SIZE], min_s[TIME_BUFFER_SIZE];
+ pcre_copy_named_substring(rs->part, line, ovector, rc, "nick", nick, NICK_BUFFER_SIZE);
+ pcre_copy_named_substring(rs->part, line, ovector, rc, "hour", hour_s, TIME_BUFFER_SIZE);
+ pcre_copy_named_substring(rs->part, line, ovector, rc, "minute", min_s, TIME_BUFFER_SIZE);
+
+ int hour, min;
+ hour = atoi(hour_s);
+ min = atoi(min_s);
+
+ pthread_mutex_lock(&time_mutex);
+ now = now_global;
+ pthread_mutex_unlock(&time_mutex);
+
+ now.tm_hour = hour;
+ now.tm_min = min;
+ time_t now_ut = mktime(&now);
+
+ pthread_mutex_lock(&user_time_mutex);
+ struct user_time_t *user_time = user_time_get(nick, 1);
+
+ if(user_time->real_user) {
+ struct user_time_t *temp = user_time->real_user;
+ user_time->real_user = NULL;
+ user_time = temp;
+ }
+
+ if(user_time->seen_first == 0) {
+ user_time->seen_first = now_ut;
+ }
+ /* Add to online total. */
+ if(user_time->seen_last > 0) {
+ user_time->time_total += now_ut - user_time->seen_last;
+ }
+ user_time->seen_last = now_ut;
+ pthread_mutex_unlock(&user_time_mutex);
+
+ continue;
+ }
+
+ rc = pcre_exec(rs->quit, rs->quit_e, line, strlen(line), 0, 0, ovector, 30);
+ if(rc > 0) {
+ char nick[NICK_BUFFER_SIZE], hour_s[TIME_BUFFER_SIZE], min_s[TIME_BUFFER_SIZE];
+ pcre_copy_named_substring(rs->quit, line, ovector, rc, "nick", nick, NICK_BUFFER_SIZE);
+ pcre_copy_named_substring(rs->quit, line, ovector, rc, "hour", hour_s, TIME_BUFFER_SIZE);
+ pcre_copy_named_substring(rs->quit, line, ovector, rc, "minute", min_s, TIME_BUFFER_SIZE);
+
+ int hour, min;
+ hour = atoi(hour_s);
+ min = atoi(min_s);
+
+ pthread_mutex_lock(&time_mutex);
+ now = now_global;
+ pthread_mutex_unlock(&time_mutex);
+
+ now.tm_hour = hour;
+ now.tm_min = min;
+ time_t now_ut = mktime(&now);
+
+ pthread_mutex_lock(&user_time_mutex);
+ struct user_time_t *user_time = user_time_get(nick, 1);
+
+ if(user_time->real_user) {
+ struct user_time_t *temp = user_time->real_user;
+ user_time->real_user = NULL;
+ user_time = temp;
+ }
+
+ if(user_time->seen_first == 0) {
+ user_time->seen_first = now_ut;
+ }
+ /* Add to online total. */
+ if(user_time->seen_last > 0) {
+ user_time->time_total += now_ut - user_time->seen_last;
+ }
+ user_time->seen_last = now_ut;
+ pthread_mutex_unlock(&user_time_mutex);
+
+ continue;
+ }
+
+ rc = pcre_exec(rs->nick_changed, rs->nick_changed_e, line, strlen(line), 0, 0, ovector, 30);
+ if(rc > 0) {
+ char oldnick[NICK_BUFFER_SIZE], newnick[NICK_BUFFER_SIZE], hour_s[TIME_BUFFER_SIZE], min_s[TIME_BUFFER_SIZE];
+ pcre_copy_named_substring(rs->nick_changed, line, ovector, rc, "old_nick", oldnick, NICK_BUFFER_SIZE);
+ pcre_copy_named_substring(rs->nick_changed, line, ovector, rc, "new_nick", newnick, NICK_BUFFER_SIZE);
+ pcre_copy_named_substring(rs->nick_changed, line, ovector, rc, "hour", hour_s, TIME_BUFFER_SIZE);
+ pcre_copy_named_substring(rs->nick_changed, line, ovector, rc, "minute", min_s, TIME_BUFFER_SIZE);
+
+ int hour, min;
+ hour = atoi(hour_s);
+ min = atoi(min_s);
+
+ pthread_mutex_lock(&time_mutex);
+ now = now_global;
+ pthread_mutex_unlock(&time_mutex);
+
+ now.tm_hour = hour;
+ now.tm_min = min;
+ time_t now_ut = mktime(&now);
+
+ pthread_mutex_lock(&user_time_mutex);
+ struct user_time_t *from_user = user_time_get(oldnick, 1);
+ struct user_time_t *to_user = user_time_get(newnick, 1);
+
+ if(from_user->real_user) {
+ to_user->real_user = from_user->real_user;
+ from_user->real_user = NULL;
+ } else {
+ to_user->real_user = from_user;
+ }
+ if(to_user->real_user) {
+ to_user->time_total += now_ut - to_user->seen_last;
+ to_user->real_user->seen_last = now_ut;
+ } else {
+ from_user->time_total += now_ut - from_user->seen_last;
+ from_user->seen_last = now_ut;
+ }
+ pthread_mutex_unlock(&user_time_mutex);
+
+ continue;
+ }
+
+ rc = pcre_exec(rs->log_opened, rs->log_opened_e, line, strlen(line), 0, 0, ovector, 30);
+ if(rc > 0) {
+ char date[DATE_BUFFER_SIZE];
+
+ if(!log_date_format) {
+ continue;
+ }
+
+ pcre_copy_named_substring(rs->log_opened, line, ovector, rc, "date", date, DATE_BUFFER_SIZE);
+ if(!strptime(date, log_date_format, &now)) {
+ printf("log fail: %s\n", date);
+ continue;
+ }
+
+ pthread_mutex_lock(&time_mutex);
+ now_global = now;
+ pthread_mutex_unlock(&time_mutex);
+
+ continue;
+ }
+
+ rc = pcre_exec(rs->day_changed, rs->day_changed_e, line, strlen(line), 0, 0, ovector, 30);
+ if(rc > 0) {
+ char date[DATE_BUFFER_SIZE];
+
+ if(!day_date_format) {
+ continue;
+ }
+
+ pcre_copy_named_substring(rs->day_changed, line, ovector, rc, "date", date, DATE_BUFFER_SIZE);
+ if(!strptime(date, day_date_format, &now)) {
+ printf("day fail: %s\n", date);
+ continue;
+ }
+
+ pthread_mutex_lock(&time_mutex);
+ now_global = now;
+ pthread_mutex_unlock(&time_mutex);
+
continue;
}
rc = pcre_exec(rs->kick, rs->kick_e, line, strlen(line), 0, 0, ovector, 30);
if(rc > 0) {
- char nick[NICK_BUFFER_SIZE], victim[NICK_BUFFER_SIZE];
+ char nick[NICK_BUFFER_SIZE], victim[NICK_BUFFER_SIZE], hour_s[TIME_BUFFER_SIZE], min_s[TIME_BUFFER_SIZE];
+ pcre_copy_named_substring(rs->kick, line, ovector, rc, "hour", hour_s, TIME_BUFFER_SIZE);
+ pcre_copy_named_substring(rs->kick, line, ovector, rc, "minute", min_s, TIME_BUFFER_SIZE);
pcre_copy_named_substring(rs->kick, line, ovector, rc, "nick", nick, NICK_BUFFER_SIZE);
pcre_copy_named_substring(rs->kick, line, ovector, rc, "victim", victim, NICK_BUFFER_SIZE);
+
+ int hour, min;
+ hour = atoi(hour_s);
+ min = atoi(min_s);
+
+ pthread_mutex_lock(&time_mutex);
+ now = now_global;
+ pthread_mutex_unlock(&time_mutex);
+
+ now.tm_hour = hour;
+ now.tm_min = min;
+ time_t now_ut = mktime(&now);
+
pthread_mutex_lock(&user_mutex);
struct user_t *user = user_get(nick),
*victim_user = user_get(victim);
user->kicks++;
victim_user->kicked++;
pthread_mutex_unlock(&user_mutex);
+
+ pthread_mutex_lock(&user_time_mutex);
+ struct user_time_t *user_time = user_time_get(nick, 0);
+ if(user_time->seen_first == 0) {
+ user_time->seen_first = now_ut;
+ }
+ /* Add to online total. */
+ if(user_time->seen_last > 0) {
+ user_time->time_total += now_ut - user_time->seen_last;
+ }
+ user_time->seen_last = now_ut;
+ pthread_mutex_unlock(&user_time_mutex);
+
continue;
}
}
@@ -149,13 +410,49 @@ static void *thread_func(void *arg) {
return NULL;
}
+static void merge_user_time_data(struct user_time_t *user_time) {
+ struct user_t *user;
+
+ user = user_get(user_time->nick);
+
+ if(user->seen_first == 0 || user_time->seen_first < user->seen_first) {
+ user->seen_first = user_time->seen_first;
+ }
+
+ if(user_time->seen_last > user->seen_last) {
+ user->seen_last = user_time->seen_last;
+ }
+
+ printf("adding %lu to %s\n", user_time->time_total, user->nick);
+ user->time_total += user_time->time_total;
+}
+
+static void merge_time_data() {
+ for(int i = 0; i < USERS_MAX; i++) {
+ struct user_time_t *user_time;
+
+ user_time = &users_time[i];
+ if(user_time->nick)
+ merge_user_time_data(user_time);
+ user_time = user_time->next;
+
+ while(user_time) {
+ merge_user_time_data(user_time);
+ user_time = user_time->next;
+ }
+ }
+}
+
void process(int thread_n) {
pthread_mutex_init(&user_mutex, NULL);
+ pthread_mutex_init(&user_time_mutex, NULL);
pthread_mutex_init(&word_mutex, NULL);
pthread_mutex_init(&channel_mutex, NULL);
+ pthread_mutex_init(&time_mutex, NULL);
/* Parsing stuff goes here. */
for(int chan_i = 0; chan_i < channel_get_count(); chan_i++) {
user_init();
+ user_time_init();
word_init();
struct channel_t *channel = channel_get(chan_i);
printf("Channel %s\n", channel->name);
@@ -190,11 +487,17 @@ void process(int thread_n) {
fclose(f);
file = file->next;
}
+
+ merge_time_data();
+
export_xml(channel, users);
user_free();
+ user_time_free();
word_free();
}
+ pthread_mutex_destroy(&time_mutex);
pthread_mutex_destroy(&user_mutex);
+ pthread_mutex_destroy(&user_time_mutex);
pthread_mutex_destroy(&word_mutex);
pthread_mutex_destroy(&channel_mutex);
}
diff --git a/regexset.c b/regexset.c
index 61a22be..0d28113 100644
--- a/regexset.c
+++ b/regexset.c
@@ -20,10 +20,12 @@ static void re_error(const char *name, const char *pattern, const char *error, i
fprintf(stderr, "%s\n", pattern);
for(int i = 0; i < erroffset; i++) fprintf(stderr, " ");
fprintf(stderr, "^\n");
- regexes = realloc(regexes, --rs_count * sizeof(struct regexset_t));
}
-struct regexset_t *rs_add(const char *text, const char *join, const char *kick) {
+struct regexset_t *rs_add(const char *text, const char *join, const char *part,
+ const char *quit, const char *kick, const char *nick_changed,
+ const char *log_opened, const char *day_changed, const char *log_date_format,
+ const char *day_date_format) {
regexes = realloc(regexes, ++rs_count * sizeof(struct regexset_t));
if(!regexes) {
/* If we end up here, we cannot free any previously compiled pcre patterns. */
@@ -39,7 +41,7 @@ struct regexset_t *rs_add(const char *text, const char *join, const char *kick)
rs->text = pcre_compile(text, 0, &error, &erroffset, rs_pcre_tables);
if(rs->text == NULL) {
re_error("text", text, error, erroffset);
- return NULL;
+ goto free_last_regex;
}
rs->text_e = pcre_study(rs->text, 0, &error);
@@ -47,29 +49,94 @@ struct regexset_t *rs_add(const char *text, const char *join, const char *kick)
rs->join = pcre_compile(join, 0, &error, &erroffset, rs_pcre_tables);
if(rs->join == NULL) {
- pcre_free(rs->text);
- if(rs->text_e)
- pcre_free(rs->text_e);
re_error("join", join, error, erroffset);
- return NULL;
+ goto free_text;
}
rs->join_e = pcre_study(rs->join, 0, &error);
+ rs->part = pcre_compile(part, 0, &error, &erroffset, rs_pcre_tables);
+ if(rs->part == NULL) {
+ re_error("part", part, error, erroffset);
+ goto free_join;
+ }
+ rs->part_e = pcre_study(rs->part, 0, &error);
+
+ rs->quit = pcre_compile(quit, 0, &error, &erroffset, rs_pcre_tables);
+ if(rs->quit == NULL) {
+ re_error("quit", quit, error, erroffset);
+ goto free_part;
+ }
+ rs->quit_e = pcre_study(rs->quit, 0, &error);
+
rs->kick = pcre_compile(kick, 0, &error, &erroffset, rs_pcre_tables);
if(rs->kick == NULL) {
- pcre_free(rs->text);
- pcre_free(rs->join);
- if(rs->text_e) {
- pcre_free(rs->text_e);
- pcre_free(rs->join_e);
- }
re_error("kick", kick, error, erroffset);
- return NULL;
-
+ goto free_quit;
}
rs->kick_e = pcre_study(rs->kick, 0, &error);
+ rs->nick_changed = pcre_compile(nick_changed, 0, &error, &erroffset, rs_pcre_tables);
+ if(rs->nick_changed == NULL) {
+ re_error("nick_changed", nick_changed, error, erroffset);
+ goto free_kick;
+ }
+ rs->nick_changed_e = pcre_study(rs->nick_changed, 0, &error);
+
+ rs->log_opened = pcre_compile(log_opened, 0, &error, &erroffset, rs_pcre_tables);
+ if(rs->log_opened == NULL) {
+ re_error("log_opened", log_opened, error, erroffset);
+ goto free_nick_changed;
+ }
+ rs->log_opened_e = pcre_study(rs->log_opened, 0, &error);
+
+ rs->day_changed = pcre_compile(day_changed, 0, &error, &erroffset, rs_pcre_tables);
+ if(rs->day_changed == NULL) {
+ re_error("day_changed", day_changed, error, erroffset);
+ goto free_log_opened;
+ }
+ rs->day_changed_e = pcre_study(rs->day_changed, 0, &error);
+
+ /* These are managed by libconfig and must never be free'd. */
+ rs->log_date_format = log_date_format;
+ rs->day_date_format = day_date_format;
+
return rs;
+
+
+ /* NOTE: Make sure these are in the exact opposite order than above. */
+
+free_log_opened:
+ pcre_free(rs->log_opened);
+ if(rs->log_opened_e) pcre_free(rs->log_opened_e);
+
+free_nick_changed:
+ pcre_free(rs->nick_changed);
+ if(rs->nick_changed_e) pcre_free(rs->nick_changed_e);
+
+free_kick:
+ pcre_free(rs->kick);
+ if(rs->kick_e) pcre_free(rs->kick_e);
+
+free_quit:
+ pcre_free(rs->quit);
+ if(rs->quit_e) pcre_free(rs->quit_e);
+
+free_part:
+ pcre_free(rs->part);
+ if(rs->part_e) pcre_free(rs->part_e);
+
+free_join:
+ pcre_free(rs->join);
+ if(rs->join_e) pcre_free(rs->join_e);
+
+free_text:
+ pcre_free(rs->text);
+ if(rs->text_e) pcre_free(rs->text_e);
+
+free_last_regex:
+ regexes = realloc(regexes, --rs_count * sizeof(struct regexset_t));
+
+ return NULL;
}
struct regexset_t *rs_get(int index) {
@@ -84,6 +151,12 @@ void rs_free() {
pcre_free(regexes[i].join);
if(regexes[i].join_e)
pcre_free(regexes[i].join_e);
+ pcre_free(regexes[i].part);
+ if(regexes[i].part_e)
+ pcre_free(regexes[i].part_e);
+ pcre_free(regexes[i].quit);
+ if(regexes[i].quit_e)
+ pcre_free(regexes[i].quit_e);
pcre_free(regexes[i].kick);
if(regexes[i].kick_e)
pcre_free(regexes[i].kick_e);
diff --git a/regexset.h b/regexset.h
index 3c023f1..aba4431 100644
--- a/regexset.h
+++ b/regexset.h
@@ -4,12 +4,16 @@
#include <pcre.h>
struct regexset_t {
- pcre *text, *join, *kick;
- pcre_extra *text_e, *join_e, *kick_e;
+ pcre *text, *join, *part, *quit, *kick, *nick_changed, *log_opened, *day_changed;
+ pcre_extra *text_e, *join_e, *part_e, *quit_e, *kick_e, *nick_changed_e, *log_opened_e, *day_changed_e;
+ const char *log_date_format, *day_date_format;
};
void rs_init();
-struct regexset_t *rs_add(const char *text, const char *join, const char *kick);
+struct regexset_t *rs_add(const char *text, const char *join, const char *part,
+ const char *quit, const char *kick, const char *nick_changed,
+ const char *log_opened, const char *day_changed, const char *log_date_format,
+ const char *day_date_format);
struct regexset_t *rs_get(int index);
void rs_free();
diff --git a/user.c b/user.c
index b64ca7c..d6554b9 100644
--- a/user.c
+++ b/user.c
@@ -7,6 +7,8 @@
struct user_t *users;
+struct user_time_t *users_time;
+
void user_init() {
users = malloc(sizeof(struct user_t) * USERS_MAX);
memset(users, 0, sizeof(struct user_t) * USERS_MAX);
@@ -33,6 +35,7 @@ struct user_t *user_get(char *nick) {
user->nick = strdup(nick);
memset(user->lines, 0, 24*4 * sizeof(unsigned long));
user->words = user->characters = user->kicks = user->kicked = user->monolog_lines = user->monologs = 0;
+ user->seen_first = user->seen_last = user->last_join = user->time_total = 0;
user->next = NULL;
char *_nick = nick_get(nick);
user->real_user = strcmp(nick, _nick) ? user_get(_nick) : NULL;
@@ -56,3 +59,50 @@ void user_free() {
}
free(users);
}
+
+void user_time_init() {
+ users_time = malloc(sizeof(struct user_time_t) * USERS_MAX);
+ memset(users_time, 0, sizeof(struct user_time_t) * USERS_MAX);
+}
+
+struct user_time_t *user_time_get(char *nick, int ignore_real) {
+ unsigned long hash = sdbm(nick);
+ int index = hash % USERS_MAX;
+
+ struct user_time_t *user = &users_time[index];
+ /* If hash doesn't match and there exists another user, fetch it. */
+ while(user->hash != hash && user->next) user = user->next;
+ /* If hash still doesn't match and the user exists, add a new user. */
+ if(user->hash != hash && user->nick) {
+ struct user_time_t *temp_user = malloc(sizeof(struct user_time_t));
+ user->next = temp_user;
+ user = temp_user;
+ /* Initialize nick to NULL so the user can be correctly added. */
+ user->nick = NULL;
+ }
+ /* Add the new user data to the current pointer if none was found. */
+ if(!user->nick) {
+ user->hash = hash;
+ user->nick = strdup(nick);
+ user->seen_first = user->seen_last = user->last_join = user->time_total = 0;
+ user->real_user = user->next = NULL;
+ }
+
+ return (!ignore_real && user->real_user ? user->real_user : user);
+}
+
+void user_time_free() {
+ struct user_time_t *user;
+ for(int i = 0; i < USERS_MAX; i++) {
+ if(users_time[i].nick)
+ free(users_time[i].nick);
+ user = users_time[i].next;
+ while(user) {
+ struct user_time_t *temp = user->next;
+ free(user->nick);
+ free(user);
+ user = temp;
+ }
+ }
+ free(users_time);
+}
diff --git a/user.h b/user.h
index b08dd36..dc4304e 100644
--- a/user.h
+++ b/user.h
@@ -1,6 +1,8 @@
#ifndef _USER_H_
#define _USER_H_
+#include <time.h>
+
#define USERS_MAX 1000
struct user_t {
@@ -8,13 +10,26 @@ struct user_t {
char *nick;
unsigned long lines[24*4];
unsigned long long words, characters, kicks, kicked, monolog_lines, monologs;
+ time_t seen_first, seen_last, last_join, time_total;
struct user_t *real_user, *next;
};
+struct user_time_t {
+ unsigned long hash;
+ char *nick;
+ time_t seen_first, seen_last, last_join, time_total;
+ struct user_time_t *real_user, *next;
+};
+
void user_init();
struct user_t *user_get(char *nick);
void user_free();
+void user_time_init();
+struct user_time_t *user_time_get(char *nick, int ignore_real);
+void user_time_free();
+
extern struct user_t *users;
+extern struct user_time_t *users_time;
#endif