2 * Copyright (C) 2014 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 #include "parser_helper.h"
22 #include <collections/array.h>
24 typedef struct private_parser_helper_t private_parser_helper_t
;
25 typedef struct private_parser_helper_file_t private_parser_helper_file_t
;
27 struct private_parser_helper_t
{
32 parser_helper_t
public;
35 * Stack of included files, as private_parser_helper_file_t.
40 * Helper for parsing strings.
45 struct private_parser_helper_file_t
{
50 parser_helper_file_t
public;
53 * Enumerator of paths matching the most recent inclusion pattern.
55 enumerator_t
*matches
;
59 * Destroy the given file data.
61 static void parser_helper_file_destroy(private_parser_helper_file_t
*this)
63 if (this->public.file
)
65 fclose(this->public.file
);
67 free(this->public.name
);
68 DESTROY_IF(this->matches
);
72 METHOD(parser_helper_t
, file_current
, parser_helper_file_t
*,
73 private_parser_helper_t
*this)
75 private_parser_helper_file_t
*file
;
77 array_get(this->files
, ARRAY_TAIL
, &file
);
78 if (file
->public.name
)
85 METHOD(parser_helper_t
, file_next
, parser_helper_file_t
*,
86 private_parser_helper_t
*this)
88 private_parser_helper_file_t
*file
, *next
;
91 array_get(this->files
, ARRAY_TAIL
, &file
);
94 array_remove(this->files
, ARRAY_TAIL
, NULL
);
95 parser_helper_file_destroy(file
);
96 /* continue with previous includes, if any */
97 array_get(this->files
, ARRAY_TAIL
, &file
);
101 while (file
->matches
->enumerate(file
->matches
, &name
, NULL
))
105 .name
= strdup(name
),
106 .file
= fopen(name
, "r"),
110 if (next
->public.file
)
112 array_insert(this->files
, ARRAY_TAIL
, next
);
113 return &next
->public;
115 PARSER_DBG2(&this->public, "unable to open '%s'", name
);
116 parser_helper_file_destroy(next
);
118 file
->matches
->destroy(file
->matches
);
119 file
->matches
= NULL
;
124 METHOD(parser_helper_t
, file_include
, void,
125 private_parser_helper_t
*this, char *pattern
)
127 private_parser_helper_file_t
*file
;
130 array_get(this->files
, ARRAY_TAIL
, &file
);
131 if (!pattern
|| !*pattern
)
133 PARSER_DBG1(&this->public, "no include pattern specified, ignored");
134 file
->matches
= enumerator_create_empty();
138 if (!file
->public.name
|| pattern
[0] == '/')
139 { /* absolute path */
140 if (snprintf(pat
, sizeof(pat
), "%s", pattern
) >= sizeof(pat
))
142 PARSER_DBG1(&this->public, "include pattern too long, ignored");
143 file
->matches
= enumerator_create_empty();
148 { /* base relative paths to the directory of the current file */
149 char *dir
= path_dirname(file
->public.name
);
150 if (snprintf(pat
, sizeof(pat
), "%s/%s", dir
, pattern
) >= sizeof(pat
))
152 PARSER_DBG1(&this->public, "include pattern too long, ignored");
154 file
->matches
= enumerator_create_empty();
160 file
->matches
= enumerator_create_glob(pat
);
162 { /* if glob(3) is not available, try to load pattern directly */
163 file
->matches
= enumerator_create_single(strdup(pat
), free
);
167 METHOD(parser_helper_t
, string_init
, void,
168 private_parser_helper_t
*this)
172 data
= this->writer
->extract_buf(this->writer
);
176 METHOD(parser_helper_t
, string_add
, void,
177 private_parser_helper_t
*this, char *str
)
179 this->writer
->write_data(this->writer
, chunk_from_str(str
));
182 METHOD(parser_helper_t
, string_get
, char*,
183 private_parser_helper_t
*this)
187 this->writer
->write_data(this->writer
, chunk_from_chars('\0'));
188 data
= this->writer
->extract_buf(this->writer
);
192 METHOD(parser_helper_t
, destroy
, void,
193 private_parser_helper_t
*this)
195 array_destroy_function(this->files
, (void*)parser_helper_file_destroy
, NULL
);
196 this->writer
->destroy(this->writer
);
201 * Described in header
203 void parser_helper_log(int level
, parser_helper_t
*ctx
, char *fmt
, ...)
205 parser_helper_file_t
*file
;
211 vsnprintf(msg
, sizeof(msg
), fmt
, args
);
214 file
= ctx
->file_current(ctx
);
215 line
= ctx
->get_lineno ? ctx
->get_lineno(ctx
->scanner
) : 0;
218 dbg(DBG_CFG
, level
, "%s:%d: %s", file
->name
, line
, msg
);
222 dbg(DBG_CFG
, level
, "%s", msg
);
227 * Described in header
229 parser_helper_t
*parser_helper_create(void *context
)
231 private_parser_helper_t
*this;
232 private_parser_helper_file_t
*sentinel
;
237 .file_current
= _file_current
,
238 .file_include
= _file_include
,
239 .file_next
= _file_next
,
240 .string_init
= _string_init
,
241 .string_add
= _string_add
,
242 .string_get
= _string_get
,
245 .files
= array_create(0, 0),
246 .writer
= bio_writer_create(0),
254 array_insert(this->files
, ARRAY_TAIL
, sentinel
);
256 return &this->public;