1 /*
2 Copyright (c) 2003, 2004, 2005, 2016 Olivier Sessink
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8 * Redistributions of source code must retain the above copyright
9 notice, this list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above
11 copyright notice, this list of conditions and the following
12 disclaimer in the documentation and/or other materials provided
13 with the distribution.
14 * The names of its contributors may not be used to endorse or
15 promote products derived from this software without specific
16 prior written permission.
17
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 POSSIBILITY OF SUCH DAMAGE.
30 */
31 #include "config.h"
32
33 #include <ctype.h> /* isspace() */
34 #include <stdio.h> /* fseek() */
35 #include <stdlib.h> /* malloc() */
36 #include <string.h> /* memset() */
37 #include <fcntl.h> /* fcntl() */
38 /*#define DEBUG*/
39
40 #ifdef DEBUG
41 #include <syslog.h>
42 #endif
43
44 #include "jk_lib.h"
45 #include "iniparser.h"
46
new_iniparser(char * filename)47 Tiniparser *new_iniparser(char *filename) {
48 FILE *tmp;
49 tmp = fopen(filename, "r");
50 if (tmp) {
51 Tiniparser *ip = malloc(sizeof(Tiniparser));
52 ip->filename = strdup(filename);
53 ip->fd = tmp;
54 /* set close-on-exec so this file descriptor will not be passed
55 to the a process after an exec() call */
56 fcntl(fileno(ip->fd), F_SETFD, FD_CLOEXEC);
57 DEBUG_MSG("new_iniparser, ip=%p for filename %s\n",ip,filename);
58 return ip;
59 }
60 return NULL;
61 }
62
iniparser_close(Tiniparser * ip)63 void iniparser_close(Tiniparser *ip) {
64 DEBUG_MSG("close fd\n");
65 fclose(ip->fd);
66 DEBUG_MSG("free filename=%p\n",ip->filename);
67 free(ip->filename);
68 DEBUG_MSG("free ip=%p\n",ip->filename);
69 free(ip);
70 DEBUG_MSG("done\n");
71 }
72
iniparser_next_section(Tiniparser * ip,char * buf,int buflen)73 char *iniparser_next_section(Tiniparser *ip, char *buf, int buflen) {
74 int sectionNameChar=0, sectionStart=0;
75 unsigned short int inComment = 0;
76 char prevch='\0', ch;
77 DEBUG_MSG("iniparser_next_section, looking for next section..\n");
78 while (!feof(ip->fd)){
79 ch=fgetc(ip->fd);
80 if (ch == '#' && (prevch == '\n' || prevch=='\0')) {
81 DEBUG_MSG("Comment start (%c)\n",ch);
82 inComment = 1;
83 } else if (ch == '\n' && inComment == 1) {
84 DEBUG_MSG("Comment stop (%c)\n",ch);
85 inComment = 0;
86 } else if (inComment == 1) {
87 /* do nothing if in comment */
88 /*DEBUG_MSG("do nothing, we're in a comment (%c)\n",ch);*/
89 } else if (!sectionStart && ch=='[') {
90 DEBUG_MSG("Section begins (%c)\n",ch);
91 sectionStart=1;
92 } else if (sectionStart && ch != ']') {
93 buf[sectionNameChar] = ch;
94 sectionNameChar++;
95 DEBUG_MSG("added '%c' to sectionname\n",ch);
96 } else if (sectionStart && sectionNameChar != 0 && ch==']') {
97 buf[sectionNameChar] = '\0';
98 DEBUG_MSG("iniparser_next_section, found '%c', sectionStart=%d, found [%s]\n", ch,sectionStart,buf);
99 return buf;
100 }
101 prevch = ch;
102 }
103 return NULL;
104 }
105 /* test if section 'section' is available, and leaves the filepointer at the end of the section name */
iniparser_has_section(Tiniparser * ip,const char * section)106 unsigned short int iniparser_has_section(Tiniparser *ip, const char *section) {
107 char buffer[256], *found;
108 fseek(ip->fd,0,SEEK_SET);
109 DEBUG_MSG("iniparser_has_section, looking for %s from position %d\n",section,0);
110 while ((found = iniparser_next_section(ip, buffer, 256))) {
111 DEBUG_MSG("comparing %s and %s\n",section,found);
112 if (strcmp(found, section)==0) {
113 DEBUG_MSG("iniparser_has_section, return 1\n");
114 return 1;
115 }
116 }
117 return 0;
118 }
119
iniparser_get_string_at_position(Tiniparser * ip,const char * section,const char * key,long position,char * buffer,int bufferlen)120 int iniparser_get_string_at_position(Tiniparser*ip, const char *section, const char *key, long position, char *buffer, int bufferlen) {
121 char ch='\0', prevch='\0';
122 unsigned int sectionNameChar=0, keyNameChar=0, bufferChar=0;
123 unsigned short int inSection=0, sectionStart=0, foundKey=0, inComment=0, inWrongKey=0;
124 DEBUG_MSG("iniparser_get_string_at_position, looking for key %s in section %s, starting at pos %ld\n",key,section,position);
125 if (fseek(ip->fd,position,SEEK_SET) != 0) {
126 DEBUG_MSG("there was an error seeking to %ld, current position=%ld, reset to zero\n",position,ftell(ip->fd));
127 fseek(ip->fd, 0, SEEK_SET);
128 }
129 DEBUG_MSG("current position of the stream is %ld\n",ftell(ip->fd));
130 while (!feof(ip->fd)){
131 prevch = ch;
132 ch=fgetc(ip->fd);
133
134 if (inComment == 1) {
135 if (ch == '\n') {
136 DEBUG_MSG("end of comment found\n");
137 inComment = 0;
138 }
139 continue;
140 } else if (ch == '#' && (prevch == '\n' || prevch == '\0')) {
141 DEBUG_MSG("inComment!\n");
142 inComment = 1;
143 continue;
144 }
145
146 if (!inSection) {
147 if (!sectionStart && ch=='['){
148 if (inSection){
149 /* found nothing */
150 break;
151 }
152 DEBUG_MSG("Section begins. Looking for [%s]\n", section);
153 sectionStart=1;
154 } else if (sectionStart && ch==section[sectionNameChar]){
155 DEBUG_MSG("Matched section name character: %c\n", ch);
156 sectionNameChar++;
157 } else if (sectionStart && sectionNameChar != 0 && ch==']'){
158 DEBUG_MSG("Found section name end, inSection=%d, found [%s]\n",inSection,section);
159 sectionStart=0;
160 inSection=1;
161 sectionNameChar=0;
162 DEBUG_MSG("The correct section %s is now found, now we continue with the key %s\n", section, key);
163 } else if (sectionStart){
164 DEBUG_MSG("Oops, wrong section, %c is not in position %d of %s\n", ch,sectionNameChar,section);
165 sectionStart=0;
166 sectionNameChar=0;
167 }
168 } else if (inWrongKey/* && inSection is implied */) {
169 if (ch == '\n') {
170 DEBUG_MSG("inWrongKey, found end of line!\n");
171 inWrongKey = 0;
172 foundKey=0;
173 keyNameChar=0;
174 } else {
175 /*DEBUG_MSG("inWrongKey, found %c, pass till end of line\n",ch);*/
176 }
177 } else if (!foundKey /* && inSection is implied */) {
178 if (ch==key[keyNameChar]){
179 DEBUG_MSG("Found a valid letter of the key: %c on position %d of %s, continue to test if next character is also valid\n", ch,keyNameChar,key);
180 keyNameChar++;
181 } else if (isspace(ch)) {
182 /* *before* the key, and *after* the key, before the '=' there can be spaces */
183 DEBUG_MSG("found a space, we ignore spaces when we are looking for the key\n");
184 } else if (keyNameChar != 0 && ch == '='){
185 DEBUG_MSG("Character %c, found the key %s, set foundKey to 1\n", ch,key);
186 foundKey=1;
187 } else if (ch=='\n'){
188 DEBUG_MSG("End of line, start looking again for %s\n", key);
189 inWrongKey=0;
190 keyNameChar=0;
191 } else if (ch=='[') {
192 DEBUG_MSG("Found the start of a new section, abort, the key does not exist\n");
193 buffer[0]='\0';
194 return -1;
195 } else {
196 DEBUG_MSG("if all else fails: %c must be a character that is not on position %d of key %s, set inWrongKey\n",ch,keyNameChar,key);
197 inWrongKey=1;
198 }
199 } else if (foundKey /* && inSection is implied */) {
200 if (bufferChar < bufferlen){
201 if (ch != '\n') {
202 DEBUG_MSG("Insection, found the key, getting the content for the key: %c\n", ch);
203 buffer[bufferChar++]=ch;
204 } else {
205 DEBUG_MSG("found a newline: the end of the content of the key! ");
206 buffer[bufferChar]='\0';
207 DEBUG_MSG("return '%s'\n",buffer);
208 return bufferChar;
209 }
210 } else {
211 DEBUG_MSG("Hit the buffer max, EOM, done w/ key %s=\n", key);
212 break;
213 }
214 } else {
215 DEBUG_MSG("unhandled character %c ?\n",ch);
216 }
217 prevch = ch;
218 }
219 buffer[bufferChar]='\0';
220 DEBUG_MSG("iniparser_get_string_at_position, end-of-file, bufferChar=%d\n",bufferChar);
221 return bufferChar;
222 }
223
iniparser_get_int_at_position(Tiniparser * ip,const char * section,const char * key,long position,int defaultval)224 int iniparser_get_int_at_position(Tiniparser *ip, const char *section, const char *key, long position, int defaultval) {
225 char data[25];
226 int ret=defaultval;
227 memset(data, 0, 25);
228 if (iniparser_get_string_at_position(ip, section, key, position, data, 25)==-1){
229 return defaultval;
230 }
231 strip_string(data);
232 sscanf(data, "%u", &ret);
233 return ret;
234 }
235
iniparser_get_octalint_at_position(Tiniparser * ip,const char * section,const char * key,long position,int defaultval)236 int iniparser_get_octalint_at_position(Tiniparser *ip, const char *section, const char *key, long position, int defaultval) {
237 char data[25];
238 int ret=defaultval;
239 memset(data, 0, 25);
240 if (iniparser_get_string_at_position(ip, section, key, position, data, 25)==-1){
241 return defaultval;
242 }
243 strip_string(data);
244 sscanf(data, "%o", &ret);
245 return ret;
246 }
247
iniparser_get_float_at_position(Tiniparser * ip,const char * section,const char * key,long position,float defaultval)248 float iniparser_get_float_at_position(Tiniparser *ip, const char *section, const char *key, long position, float defaultval) {
249 float ret = defaultval;
250 char data[25];
251 memset(data, 0, 25);
252 if (iniparser_get_string_at_position(ip, section, key, position, data, 25)==-1){
253 DEBUG_MSG("iniparser_get_float_at_position, no string found\n");
254 return 0.0;
255 }
256 strip_string(data);
257 sscanf(data, "%f", &ret);
258 return ret;
259 }
260 /*
261 int iniparser_value_len(Tiniparser *ip, const char *section, const char *key){
262 char ch;
263 unsigned int sectionNameChar=0, keyNameChar=0;
264 unsigned int valueLength=0;
265 unsigned short int inSection=0, sectionStart=0, foundKey=0;
266 while (!feof(ip->fd)){
267 ch=fgetc(ip->fd);
268 if (!sectionStart && ch=='['){
269 if (inSection){
270 break;
271 }
272 sectionStart=1;
273 } else if (sectionStart && ch==section[sectionNameChar]){
274 sectionNameChar++;
275 } else if (sectionStart && sectionNameChar != 0 && ch==']'){
276 sectionStart=0;
277 inSection=1;
278 sectionNameChar=0;
279 } else if (sectionStart){
280 sectionStart=0;
281 sectionNameChar=0;
282 }
283
284 if (inSection && !foundKey && ch==key[keyNameChar]){
285 keyNameChar++;
286 } else if (inSection && !foundKey && keyNameChar != 0 && ch == '='){
287 foundKey=1;
288 } else if (inSection && keyNameChar != 0 && !foundKey){
289 foundKey=0;
290 keyNameChar=0;
291 } else if (inSection && foundKey && (ch==13 || ch==10 || ch==';')){
292 foundKey=0;
293 break;
294 } else if (inSection && foundKey){
295 valueLength++;
296 }
297 }
298 return valueLength;
299 }
300 */
301