2 * libcfg+ - precise command line & config file parsing library
4 * cfgfile.c - config file parsing
5 * ____________________________________________________________
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.
12 * See README file for more information about this software.
13 * See COPYING file for license information.
15 * Download the latest version from
16 * http://platon.sk/projects/libcfg+/
19 /* $Platon: libcfg+/src/cfgfile.c,v 1.26 2003/11/07 17:26:48 nepto Exp $ */
34 # if !STDC_HEADERS && HAVE_MEMORY_H
46 #include <platon/str/strdyn.h>
47 #include <platon/str/strplus.h>
48 #include <platon/str/dynfgets.h>
54 /* Static function declarations {{{ */
55 static int get_multi_line(const CFG_CONTEXT con, char **buf);
59 cfg_cfgfile_get_next_opt(con)
60 const CFG_CONTEXT con;
65 con->error_code = CFG_OK;
67 /* Initial position seek */
68 if (con->fhandle == NULL) {
69 con->fhandle = con->filename != NULL
70 ? fopen(con->filename, "r")
72 if (con->fhandle == NULL) {
73 con->error_code = CFG_ERROR_FILE_NOT_FOUND;
74 return con->error_code;
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;
86 if (con->begin_pos > 0) {
90 /* Moving to begin_pos line */
91 while (con->cur_idx_tmp < con->begin_pos) {
92 switch (fgetc(con->fhandle)) {
94 con->error_code = CFG_ERROR_SEEK_ERROR;
95 return con->error_code;
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;
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;
121 /* Reading multi line and exit on error */
122 con->error_code = get_multi_line(con, &buf);
123 if (con->error_code != CFG_OK) {
127 return con->error_code;
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);
136 con->error_code = CFG_ERROR_STOP_STR;
137 return con->error_code;
142 if ((con->size >= 0 && cfg_get_cur_idx(con) >= con->begin_pos + con->size)
143 || feof(con->fhandle)) {
147 return con->error_code; /* always CFG_OK */
150 __cfg_free_currents(con);
152 if (__cfg_cfgfile_set_currents(con, buf) != CFG_OK) {
153 con->error_code = CFG_ERROR_NOMEM;
154 return con->error_code;
159 con->error_code = __cfg_process_currents(con, &ret_val, NULL);
160 if (con->error_code != CFG_OK)
161 return con->error_code;
167 return con->error_code; /* CFG_OK */
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.
180 get_multi_line(con, buf)
181 const CFG_CONTEXT con;
184 register char **ar = NULL;
185 register char *my_buf = NULL;
186 register int state = 0;
190 if ((ar = PLATON_FUNC(strdyn_create)()) == NULL)
191 return CFG_ERROR_NOMEM;
200 my_buf = PLATON_FUNC(dynamic_fgets)(con->fhandle);
201 if (my_buf == NULL) {
202 if (feof(con->fhandle))
205 return CFG_ERROR_NOMEM;
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) {
214 if (con->flags & CFG_FILE_LINE_POS_USAGE)
223 if (con->flags & CFG_FILE_LINE_POS_USAGE)
227 /* Multi line detection. */
230 register int max_len = 0;
233 for (pos = con->prop[CFG_FILE_MULTI_LINE_POSTFIX];
234 pos != NULL && *pos != NULL;
237 len = strlen(my_buf) - strlen(*pos);
239 if (len > max_len && ! strcmp(*pos, my_buf + len))
243 /* Multi line postfix found? */
245 my_buf[max_len] = '\0';
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)] = ' ';
259 ar = PLATON_FUNC(strdyn_add)(ar, my_buf);
261 return CFG_ERROR_NOMEM;
270 my_buf = PLATON_FUNC(str_right_trim)(strdyn_implode(ar, ""));
271 PLATON_FUNC(strdyn_free)(ar);
274 return CFG_ERROR_NOMEM;
281 /* Modeline for ViM {{{
283 * vim600:fdm=marker fdl=0 fdc=0: