1 /*
2  * ini.c
3  */
4 
5 #include "private.h"
6 #include "lub/string.h"
7 
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include <string.h>
11 #include <assert.h>
12 #include <ctype.h>
13 
14 /*--------------------------------------------------------- */
lub_ini_init(lub_ini_t * this)15 void lub_ini_init(lub_ini_t *this)
16 {
17 	assert(this);
18 	memset(this, 0, sizeof(*this));
19 	this->list = lub_list_new(lub_pair_compare);
20 }
21 
22 /*--------------------------------------------------------- */
lub_ini_new(void)23 lub_ini_t *lub_ini_new(void)
24 {
25 	lub_ini_t *this;
26 
27 	this = malloc(sizeof(*this));
28 	if (this)
29 		lub_ini_init(this);
30 
31 	return this;
32 }
33 
34 /*--------------------------------------------------------- */
lub_ini_fini(lub_ini_t * this)35 void lub_ini_fini(lub_ini_t *this)
36 {
37 	lub_list_node_t *iter;
38 
39 	assert(this);
40 	while ((iter = lub_list__get_head(this->list))) {
41 		lub_list_del(this->list, iter);
42 		lub_pair_free((lub_pair_t *)lub_list_node__get_data(iter));
43 		lub_list_node_free(iter);
44 	}
45 	lub_list_free(this->list);
46 }
47 
48 /*--------------------------------------------------------- */
lub_ini_free(lub_ini_t * this)49 void lub_ini_free(lub_ini_t *this)
50 {
51 	assert(this);
52 	lub_ini_fini(this);
53 	free(this);
54 }
55 
56 /*--------------------------------------------------------- */
lub_ini_add(lub_ini_t * this,lub_pair_t * pair)57 void lub_ini_add(lub_ini_t *this, lub_pair_t *pair)
58 {
59 	assert(this);
60 	lub_list_add(this->list, pair);
61 }
62 
63 /*--------------------------------------------------------- */
64 /* Find pair by name */
lub_ini_find_pair(const lub_ini_t * this,const char * name)65 lub_pair_t *lub_ini_find_pair(const lub_ini_t *this, const char *name)
66 {
67 	lub_list_node_t *iter;
68 	lub_pair_t *pair;
69 
70 	if (!this || !name)
71 		return NULL;
72 	/* Iterate elements */
73 	for(iter = lub_list__get_head(this->list);
74 		iter; iter = lub_list_node__get_next(iter)) {
75 		int res;
76 		pair = (lub_pair_t *)lub_list_node__get_data(iter);
77 		res = strcmp(lub_pair__get_name(pair), name);
78 		if (!res)
79 			return pair;
80 		if (res > 0) /* No chance to find name */
81 			break;
82 	}
83 
84 	return NULL;
85 }
86 
87 /*--------------------------------------------------------- */
88 /* Find pair by name */
lub_ini_find(const lub_ini_t * this,const char * name)89 const char *lub_ini_find(const lub_ini_t *this, const char *name)
90 {
91 	lub_pair_t *pair = lub_ini_find_pair(this, name);
92 
93 	if (!pair)
94 		return NULL;
95 	return lub_pair__get_value(pair);
96 }
97 
98 /*--------------------------------------------------------- */
lub_ini_parse_str(lub_ini_t * this,const char * ini)99 int lub_ini_parse_str(lub_ini_t *this, const char *ini)
100 {
101 	char *buffer;
102 	char *saveptr = NULL;
103 	char *line;
104 
105 	buffer = lub_string_dup(ini);
106 	/* Now loop though each line */
107 	for (line = strtok_r(buffer, "\n", &saveptr);
108 		line; line = strtok_r(NULL, "\n", &saveptr)) {
109 
110 		char *str, *name, *value, *savestr = NULL, *ns = line;
111 		const char *begin;
112 		size_t len, offset, quoted;
113 		char *rname, *rvalue;
114 		lub_pair_t *pair;
115 
116 		if (!*ns) /* Empty */
117 			continue;
118 		while (*ns && isspace(*ns))
119 			ns++;
120 		if ('#' == *ns) /* Comment */
121 			continue;
122 		if ('=' == *ns) /* Broken string */
123 			continue;
124 		str = lub_string_dup(ns);
125 		name = strtok_r(str, "=", &savestr);
126 		if (!name) {
127 			lub_string_free(str);
128 			continue;
129 		}
130 		value = strtok_r(NULL, "=", &savestr);
131 		begin = lub_string_nextword(name, &len, &offset, &quoted);
132 		rname = lub_string_dupn(begin, len);
133 		if (!value) /* Empty value */
134 			rvalue = NULL;
135 		else {
136 			begin = lub_string_nextword(value, &len, &offset, &quoted);
137 			rvalue = lub_string_dupn(begin, len);
138 		}
139 		pair = lub_pair_new(rname, rvalue);
140 		lub_ini_add(this, pair);
141 		lub_string_free(rname);
142 		lub_string_free(rvalue);
143 		lub_string_free(str);
144 	}
145 	lub_string_free(buffer);
146 
147 	return 0;
148 }
149 
150 /*--------------------------------------------------------- */
lub_ini_parse_file(lub_ini_t * this,const char * fn)151 int lub_ini_parse_file(lub_ini_t *this, const char *fn)
152 {
153 	int ret = -1;
154 	FILE *f;
155 	char *buf;
156 	unsigned int p = 0;
157 	const int chunk_size = 128;
158 	int size = chunk_size;
159 
160 	if (!fn || !*fn)
161 		return -1;
162 	f = fopen(fn, "r");
163 	if (!f)
164 		return -1;
165 
166 	buf = malloc(size);
167 	while (fgets(buf + p, size - p, f)) {
168 		char *tmp;
169 		if (feof(f) || strchr(buf + p, '\n') || strchr(buf + p, '\r')) {
170 			lub_ini_parse_str(this, buf);
171 			p = 0;
172 			continue;
173 		}
174 		p = size - 1;
175 		size += chunk_size;
176 		tmp = realloc(buf, size);
177 		if (!tmp)
178 			goto error;
179 		buf = tmp;
180 	}
181 
182 	ret = 0;
183 error:
184 	free(buf);
185 	fclose(f);
186 
187 	return ret;
188 }
189 
190 /*--------------------------------------------------------- */
lub_ini__get_head(lub_ini_t * this)191 lub_ini_node_t *lub_ini__get_head(lub_ini_t *this)
192 {
193 	return lub_list__get_head(this->list);
194 }
195 
196 /*--------------------------------------------------------- */
lub_ini__get_tail(lub_ini_t * this)197 lub_ini_node_t *lub_ini__get_tail(lub_ini_t *this)
198 {
199 	return lub_list__get_tail(this->list);
200 }
201 
202 /*--------------------------------------------------------- */
203 
lub_ini__get_next(lub_ini_node_t * node)204 lub_ini_node_t *lub_ini__get_next(lub_ini_node_t *node)
205 {
206 	return lub_list_node__get_next(node);
207 }
208 
209 /*--------------------------------------------------------- */
210 
lub_ini__get_prev(lub_ini_node_t * node)211 lub_ini_node_t *lub_ini__get_prev(lub_ini_node_t *node)
212 {
213 	return lub_list_node__get_next(node);
214 }
215 
216 /*--------------------------------------------------------- */
217 
lub_ini__iter_data(lub_ini_node_t * node)218 lub_pair_t *lub_ini__iter_data(lub_ini_node_t *node)
219 {
220 	return (lub_pair_t *)lub_list_node__get_data(node);
221 }
222 
223 /*--------------------------------------------------------- */
224