#include #include #include #include #include "regexset.h" struct regexset_t *regexes; int rs_count; const unsigned char *rs_pcre_tables; void rs_init() { regexes = NULL; rs_count = 0; rs_pcre_tables = pcre_maketables(); } static void re_error(const char *name, const char *pattern, const char *error, int erroffset) { fprintf(stderr, "RE \"%s\" failed to compile: %s\n", name, error); fprintf(stderr, "%s\n", pattern); for(int i = 0; i < erroffset; i++) fprintf(stderr, " "); fprintf(stderr, "^\n"); } 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. */ char *error = strerror(errno); fprintf(stderr, "Could not (re)allocate memory for regex sets: %s\n", error); return NULL; } /* Fetch the last struct. */ struct regexset_t *rs = ®exes[rs_count-1]; const char *error; int erroffset; rs->text = pcre_compile(text, 0, &error, &erroffset, rs_pcre_tables); if(rs->text == NULL) { re_error("text", text, error, erroffset); goto free_last_regex; } rs->text_e = pcre_study(rs->text, 0, &error); /* Free compiled patterns from this point when failing. */ rs->join = pcre_compile(join, 0, &error, &erroffset, rs_pcre_tables); if(rs->join == NULL) { re_error("join", join, error, erroffset); 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) { re_error("kick", kick, error, erroffset); 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); /* day_changed is optional */ if(day_changed) { rs->day_changed = pcre_compile(day_changed, 0, &error, &erroffset, rs_pcre_tables); if(rs->day_changed) { 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) { return (index < rs_count ? ®exes[index] : NULL); } void rs_free() { for(int i = 0; i < rs_count; i++) { pcre_free(regexes[i].text); if(regexes[i].text_e) pcre_free(regexes[i].text_e); 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); pcre_free(regexes[i].nick_changed); if(regexes[i].nick_changed_e) pcre_free(regexes[i].nick_changed_e); pcre_free(regexes[i].log_opened); if(regexes[i].log_opened_e) pcre_free(regexes[i].log_opened_e); if(regexes[i].day_changed) { pcre_free(regexes[i].day_changed); if(regexes[i].day_changed_e) pcre_free(regexes[i].day_changed_e); } } free(regexes); regexes = NULL; pcre_free((void*)rs_pcre_tables); rs_pcre_tables = NULL; }