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: