summaryrefslogtreecommitdiff
path: root/config.c
blob: b9123b85e5047103fec9080bda0b75a19c29fbc5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#include <string.h>
#include <stdlib.h>

#include <libconfig.h>

#include "config.h"
#include "regexset.h"
#include "channel.h"
#include "nick.h"

config_t config;
struct ircstats_config_t ircstats_config;

int cfg_init() {
	config_init(&config);

	char cfg_file[0xff];
	strcpy(cfg_file, getenv("HOME"));
	strcat(cfg_file, "/.ircstats/config");

	if(config_read_file(&config, cfg_file) == CONFIG_FALSE) {
		int line = config_error_line(&config);
		if(line == 0)
			fprintf(stderr, "Could not read config: %s\n", config_error_text(&config));
		else
			fprintf(stderr, "Parse error on line %d: %s\n", config_error_line(&config), config_error_text(&config));
		return 0;
	}

	if(!config_lookup_int(&config, "threads", &ircstats_config.threads)) {
		ircstats_config.threads = 1;
	}

	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");
		return 0;
	}

	int regex_count = config_setting_length(regexes_setting);

	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))) {
			fprintf(stderr, "Regex set #%d missing one or more keys.\n", i+1);
			return 0;
		}
		if(!rs_add(text, join, kick))
			return 0;
	}

	config_setting_t *channels_setting = config_lookup(&config, "channels");
	if(!config_setting_is_aggregate(channels_setting)) {
		fprintf(stderr, "Setting \"channels\" must be an aggregate type.\n");
		return 0;
	}

	int channel_count = config_setting_length(channels_setting);
	for(int i = 0; i < channel_count; i++) {
		config_setting_t *channel_setting = config_setting_get_elem(channels_setting, i);
		const char *name, *xmlpath;
		if(!config_setting_lookup_string(channel_setting, "name", &name)) {
			char *sname;
			sname = malloc(sizeof(char) * 16);
			snprintf(sname, 16, "channel #%d", i+1);
			name = sname;
		}
		if(!config_setting_lookup_string(channel_setting, "xmlpath", &xmlpath)) {
			/* Index-based filename if xmlpath isn't set. */
			char temp[0xf];
			snprintf(temp, 0xf, "%d.xml", i);
			xmlpath = strdup(temp);
		}
		struct channel_t *channel;
		if(!(channel = channel_add(name, xmlpath))) {
			return 0;
		}
		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);
			continue;
		}
		int file_count = config_setting_length(files);
		/* Iterate through files. */
		for(int j = 0; j < file_count; j++) {
			const char *filepath;
			int rs_index;
			config_setting_t *file = config_setting_get_elem(files, j);
			/* (filepath, regexset) pair. */
			if(config_setting_is_aggregate(file)) {
				if(config_setting_length(file) != 2) {
					fprintf(stderr, "File lists must have exactly two elements.\n");
					continue;
				}
				config_setting_t *path_setting = config_setting_get_elem(file, 0);
				config_setting_t *rs_setting = config_setting_get_elem(file, 1);
				if(!(config_setting_type(path_setting) == CONFIG_TYPE_STRING && config_setting_type(rs_setting) == CONFIG_TYPE_INT)) {
					fprintf(stderr, "File lists must have a string and an integer.\n");
					continue;
				}
				filepath = config_setting_get_string(path_setting);
				rs_index = config_setting_get_int(rs_setting);
			} else { /* filepath only. */
				filepath = config_setting_get_string(file);
				rs_index = 0;
			}
			if(!channel_file_add(channel, filepath, rs_index)) {
				fprintf(stderr, "Failed to set file #%d (%s) for channel %s.\n", j+1, filepath, name);
			}
		}
	}

	config_setting_t *nicks_setting = config_lookup(&config, "nicks");
	if(!config_setting_is_aggregate(nicks_setting)) {
		fprintf(stderr, "Setting \"nicks\" must be an aggregate type.\n");
		return 0;
	}

	int nick_count = config_setting_length(nicks_setting);
	for(int i = 0; i < nick_count; i++) {
		config_setting_t *nick_setting = config_setting_get_elem(nicks_setting, i);
		if(config_setting_length(nick_setting) != 2) {
			fprintf(stderr, "Nick settings must contain exactly two elements.\n");
			return 0;
		}
		const char *name = config_setting_get_string_elem(nick_setting, 0);
		if(!name) {
			fprintf(stderr, "First element of nick settings must be a string.\n");
			return 0;
		}
		struct nick_t *nick = nick_add(name);
		if(!nick) {
			return 0;
		}
		config_setting_t *nick_re_setting = config_setting_get_elem(nick_setting, 1);
		if(!config_setting_is_aggregate(nick_re_setting)) {
			fprintf(stderr, "Second element of nick settings must be an aggregate type.\n");
			return 0;
		}
		int re_count = config_setting_length(nick_re_setting);
		for(int j = 0; j < re_count; j++) {
			const char *re = config_setting_get_string_elem(nick_re_setting, j);
			if(!re) {
				fprintf(stderr, "Second element of nick settings must contain strings only.\n");
				return 0;
			}
			if(!nick_regex_add(nick, re)) {
				return 0;
			}
		}
	}

	return 1;
}

void cfg_free() {
	config_destroy(&config);
}