Tizen 2.0 Release
[external/libgnutls26.git] / src / cfg / cfgfile.c
1 /*
2  * libcfg+ - precise command line & config file parsing library
3  *
4  * cfgfile.c - config file parsing
5  * ____________________________________________________________
6  *
7  * Developed by Ondrej Jombik <nepto@platon.sk>
8  *          and Lubomir Host <rajo@platon.sk>
9  * Copyright (c) 2001-2003 Platon SDG, http://platon.sk/
10  * All rights reserved.
11  *
12  * See README file for more information about this software.
13  * See COPYING file for license information.
14  *
15  * Download the latest version from
16  * http://platon.sk/projects/libcfg+/
17  */
18
19 /* $Platon: libcfg+/src/cfgfile.c,v 1.26 2003/11/07 17:26:48 nepto Exp $ */
20
21 /* Includes {{{ */
22 #ifdef HAVE_CONFIG_H
23 #  include "config.h"
24 #endif
25
26 #if STDC_HEADERS
27 #  include <stdlib.h>
28 #else
29 #  if HAVE_STDLIB_H
30 #    include <stdlib.h>
31 #  endif
32 #endif
33 #if HAVE_STRING_H
34 #  if !STDC_HEADERS && HAVE_MEMORY_H
35 #    include <memory.h>
36 #  endif
37 #  include <string.h>
38 #endif
39 #if HAVE_STRINGS_H
40 #  include <strings.h>
41 #endif
42 #if HAVE_UNISTD_H
43 #  include <unistd.h>
44 #endif
45
46 #include <platon/str/strdyn.h>
47 #include <platon/str/strplus.h>
48 #include <platon/str/dynfgets.h>
49
50 #include "cfg+.h"
51 #include "shared.h"
52 /* }}} */
53
54 /* Static function declarations {{{ */
55 static int get_multi_line(const CFG_CONTEXT con, char **buf);
56 /* }}} */
57
58         int
59 cfg_cfgfile_get_next_opt(con)
60         const CFG_CONTEXT con;
61 { /* {{{ */
62         char *buf;
63         int ret_val;
64
65         con->error_code = CFG_OK;
66
67         /* Initial position seek */
68         if (con->fhandle == NULL) {
69                 con->fhandle = con->filename != NULL
70                         ? fopen(con->filename, "r")
71                         : NULL;
72                 if (con->fhandle == NULL) {
73                         con->error_code = CFG_ERROR_FILE_NOT_FOUND;
74                         return con->error_code;
75                 }
76
77                 if (con->flags & CFG_FILE_LINE_POS_USAGE) {
78                         /* If negative line is specified, returns seek error.
79                            If 0 is specified, do nothing.
80                            If number > 0 is specified make appropriate line seek. */
81                         if (con->begin_pos < 0) {
82                                 con->error_code = CFG_ERROR_SEEK_ERROR;
83                                 return con->error_code;
84                         }
85
86                         if (con->begin_pos > 0) {
87                                 con->cur_idx     = 0;
88                                 con->cur_idx_tmp = 0;
89
90                                 /* Moving to begin_pos line */
91                                 while (con->cur_idx_tmp < con->begin_pos) {
92                                         switch (fgetc(con->fhandle)) {
93                                                 case EOF:
94                                                         con->error_code = CFG_ERROR_SEEK_ERROR;
95                                                         return con->error_code;
96                                                 case '\n':
97                                                         con->cur_idx_tmp++;
98                                         }
99                                 }
100                         }
101                 }
102                 else {
103                         if (/* always do: con->begin_pos > 0 && */
104                                         fseek(con->fhandle, con->begin_pos, SEEK_SET) != 0) {
105                                 con->error_code = CFG_ERROR_SEEK_ERROR;
106                                 return con->error_code;
107                         }
108                 }
109         }
110
111         /*
112          * Main loop
113          */
114         while (1) {
115                 /* Updating cur_idx to set current line position */
116                 if (con->flags & CFG_FILE_LINE_POS_USAGE) {
117                         con->cur_idx     += con->cur_idx_tmp;
118                         con->cur_idx_tmp  = 0;
119                 }
120
121                 /* Reading multi line and exit on error */
122                 con->error_code = get_multi_line(con, &buf);
123                 if (con->error_code != CFG_OK) {
124                         if (buf != NULL)
125                                 free(buf);
126
127                         return con->error_code;
128                 }
129
130                 /* Testing if file stop prefix was found */
131                 if (buf != NULL && con->prop[CFG_FILE_STOP_PREFIX] != NULL) {
132                         if (buf == PLATON_FUNC(strdyn_str2)(buf,
133                                                 con->prop[CFG_FILE_STOP_PREFIX], NULL)) {
134                                 __cfg_free_currents(con);
135                                 con->cur_opt    = buf;
136                                 con->error_code = CFG_ERROR_STOP_STR;
137                                 return con->error_code;
138                         }
139                 }
140
141                 /* Finished? */
142                 if ((con->size >= 0 && cfg_get_cur_idx(con) >= con->begin_pos + con->size)
143                                 || feof(con->fhandle)) {
144                         if (buf != NULL)
145                                 free(buf);
146
147                         return con->error_code; /* always CFG_OK */
148                 }
149
150                 __cfg_free_currents(con);
151
152                 if (__cfg_cfgfile_set_currents(con, buf) != CFG_OK) {
153                         con->error_code = CFG_ERROR_NOMEM;
154                         return con->error_code;
155                 }
156
157                 free(buf);
158
159                 con->error_code = __cfg_process_currents(con, &ret_val, NULL);
160                 if (con->error_code != CFG_OK)
161                         return con->error_code;
162
163                 if (ret_val > 0)
164                         return ret_val;
165         }
166
167         return con->error_code; /* CFG_OK */
168 } /* }}} */
169
170 /*
171  * get_multi_line()
172  *
173  * Gets single line from file. If line continues on next line, returns
174  * the whole line concatenated. Coments, remarks and empty lines are
175  * skipped. If end of file is reached CFG_OK is returned and higher
176  * level should determine that fact using feof() function.
177  */
178
179         static int
180 get_multi_line(con, buf)
181         const CFG_CONTEXT con;
182         char              **buf;
183 { /* {{{ */
184         register char **ar    = NULL;
185         register char *my_buf = NULL;
186         register int   state  = 0;
187
188         *buf = NULL;
189
190         if ((ar = PLATON_FUNC(strdyn_create)()) == NULL)
191                 return CFG_ERROR_NOMEM;
192
193         while (1) {
194                 if (state > 1)
195                         state = 1;
196
197                 if (my_buf != NULL)
198                         free(my_buf);
199
200                 my_buf = PLATON_FUNC(dynamic_fgets)(con->fhandle);
201                 if (my_buf == NULL) {
202                         if (feof(con->fhandle))
203                                 return CFG_OK;
204
205                         return CFG_ERROR_NOMEM;
206                 }
207
208                 str_trim(my_buf);
209
210                 /* Is empty line or comment? */
211                 if (strlen(my_buf) == 0 || strdyn_str(my_buf,
212                                         con->prop[CFG_FILE_COMMENT_PREFIX]) == my_buf) {
213
214                         if (con->flags & CFG_FILE_LINE_POS_USAGE)
215                                 con->cur_idx++;
216
217                         if (state == 0)
218                                 continue;
219                         else
220                                 break;
221                 }
222                 else {
223                         if (con->flags & CFG_FILE_LINE_POS_USAGE)
224                                 con->cur_idx_tmp++;
225                 }
226
227                 /* Multi line detection. */
228                 {
229                         register char **pos;
230                         register int max_len = 0;
231                         register int len;
232
233                         for (pos = con->prop[CFG_FILE_MULTI_LINE_POSTFIX];
234                                         pos != NULL && *pos != NULL;
235                                         pos++) {
236
237                                 len = strlen(my_buf) - strlen(*pos);
238
239                                 if (len > max_len && ! strcmp(*pos, my_buf + len))
240                                         max_len = len;
241                         }
242
243                         /* Multi line postfix found? */
244                         if (max_len > 0) {
245                                 my_buf[max_len] = '\0';
246                                 state = 2;
247
248                                 len = strlen(my_buf);
249                                 PLATON_FUNC(str_right_trim)(my_buf);
250                                 if (len - strlen(my_buf) > 0) {
251                                         /* Could be replaced with
252                                            strcpy(my_buf + strlen(my_buf), " "); */
253                                         my_buf[strlen(my_buf) + 1] = '\0';
254                                         my_buf[strlen(my_buf)] = ' ';
255                                 }
256                         }
257                 }
258
259                 ar = PLATON_FUNC(strdyn_add)(ar, my_buf);
260                 if (ar == NULL)
261                         return CFG_ERROR_NOMEM;
262
263                 if (state != 2)
264                         break;
265         }
266
267         if (my_buf != NULL)
268                 free(my_buf);
269
270         my_buf = PLATON_FUNC(str_right_trim)(strdyn_implode(ar, ""));
271         PLATON_FUNC(strdyn_free)(ar);
272
273         if (my_buf == NULL)
274                 return CFG_ERROR_NOMEM;
275
276         *buf = my_buf;
277
278         return CFG_OK;
279 } /* }}} */
280
281 /* Modeline for ViM {{{
282  * vim:set ts=4:
283  * vim600:fdm=marker fdl=0 fdc=0:
284  * }}} */
285