2
* Copyright (c) 2002-2012 BalaBit IT Ltd, Budapest, Hungary
3
* Copyright (c) 1998-2012 Balázs Scheidler
5
* This library is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU Lesser General Public
7
* License as published by the Free Software Foundation; either
8
* version 2.1 of the License, or (at your option) any later version.
10
* This library is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
* Lesser General Public License for more details.
15
* You should have received a copy of the GNU Lesser General Public
16
* License along with this library; if not, write to the Free Software
17
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19
* As an additional exemption you are allowed to compile & link against the
20
* OpenSSL libraries as published by the OpenSSL project. See the file
21
* COPYING for details.
25
#include "cfg-lexer.h"
27
#include "cfg-grammar.h"
28
#include "block-ref-parser.h"
29
#include "pragma-parser.h"
43
* A token block is a series of tokens to be injected into the tokens
44
* fetched by the lexer. It is assumed to be filled and then depleted, the
45
* two operations cannot be intermixed.
56
* This class describes a block generator, e.g. a function callback
57
* that returns a configuration snippet in a given context. Each
58
* user-defined "block" results in a generator to be registered, but
59
* theoretically this mechanism can be used to write plugins that
60
* generate syslog-ng configuration on the fly, based on system
61
* settings for example.
63
struct _CfgBlockGenerator
67
CfgBlockGeneratorFunc generator;
68
gpointer generator_data;
69
GDestroyNotify generator_data_free;
75
* This object tells the lexer in which context it is operating right
76
* now. The context influences the way the lexer works, for example in
77
* LL_CONTEXT_BLOCK_DEF/REF all keyword resolutions are disabled.
79
* A textual description is also associated with the current context
80
* in order to give better error messages.
82
typedef struct _CfgLexerContext
85
CfgLexerKeyword *keywords;
90
* cfg_lexer_push_context:
92
* This function can be used to push a lexer context to the stack. The top
93
* of the stack determines how an error is reported and can also influence
97
cfg_lexer_push_context(CfgLexer *self, gint type, CfgLexerKeyword *keywords, const gchar *desc)
99
CfgLexerContext *context;
101
context = g_malloc(sizeof(CfgLexerContext) + strlen(desc) + 1);
102
context->type = type ? type : cfg_lexer_get_context_type(self);
103
context->keywords = keywords;
104
memcpy(&context->desc, desc, strlen(desc) + 1);
105
self->context_stack = g_list_prepend(self->context_stack, context);
109
* cfg_lexer_pop_context:
111
* Pop the topmost item off the stack.
114
cfg_lexer_pop_context(CfgLexer *self)
116
if (self->context_stack)
118
g_free((gchar *) self->context_stack->data);
119
self->context_stack = g_list_delete_link(self->context_stack, self->context_stack);
124
* cfg_lexer_get_context_type:
126
* Get the current context type (one of LL_CONTEXT_* values).
129
cfg_lexer_get_context_type(CfgLexer *self)
133
l = self->context_stack;
135
return ((CfgLexerContext *) l->data)->type;
140
* cfg_lexer_get_context_description:
142
* Get the description of the current context.
145
cfg_lexer_get_context_description(CfgLexer *self)
149
l = self->context_stack;
151
return ((CfgLexerContext *) l->data)->desc;
152
return "configuration";
156
cfg_lexer_subst_args(CfgArgs *globals, CfgArgs *defs, CfgArgs *args, gchar *cptr, gsize *length)
158
gboolean backtick = FALSE;
159
gchar *p, *ref_start = cptr;
160
GString *result = g_string_sized_new(32);
165
if (!backtick && (*p) == '`')
167
/* start of reference */
171
else if (backtick && (*p) == '`')
173
/* end of reference */
178
/* empty ref, just include a ` character */
179
g_string_append_c(result, '`');
186
if (args && (arg = cfg_args_get(args, ref_start)))
188
else if (defs && (arg = cfg_args_get(defs, ref_start)))
190
else if (globals && (arg = cfg_args_get(globals, ref_start)))
192
else if ((arg = g_getenv(ref_start)))
198
g_string_append(result, arg ? arg : "");
202
g_string_append_c(result, *p);
208
g_string_free(result, TRUE);
212
*length = result->len;
213
return g_string_free(result, FALSE);
217
cfg_lexer_lookup_keyword(CfgLexer *self, YYSTYPE *yylval, YYLTYPE *yylloc, const char *token)
221
l = self->context_stack;
224
CfgLexerContext *context = ((CfgLexerContext *) l->data);
225
CfgLexerKeyword *keywords = context->keywords;
231
for (i = 0; keywords[i].kw_name; i++)
233
if (strcmp(keywords[i].kw_name, CFG_KEYWORD_STOP) == 0)
235
yylval->cptr = strdup(token);
236
return LL_IDENTIFIER;
239
for (j = 0; token[j] && keywords[i].kw_name[j]; j++)
241
if (token[j] == '-' || token[j] == '_')
243
if (keywords[i].kw_name[j] != '_')
246
else if (token[j] != keywords[i].kw_name[j])
249
if (token[j] == 0 && keywords[i].kw_name[j] == 0)
252
if (keywords[i].kw_req_version > configuration->version)
254
msg_warning("WARNING: Your configuration uses a newly introduced reserved word as identifier, please use a different name or enclose it in quotes",
255
evt_tag_str("keyword", keywords[i].kw_name),
256
evt_tag_printf("config-version", "%d.%d", configuration->version >> 8, configuration->version & 0xFF),
257
evt_tag_printf("version", "%d.%d", (keywords[i].kw_req_version >> 8), keywords[i].kw_req_version & 0xFF),
258
yylloc ? evt_tag_str("filename", yylloc->level->name) : NULL,
259
yylloc ? evt_tag_printf("line", "%d:%d", yylloc->first_line, yylloc->first_column) : NULL,
263
switch (keywords[i].kw_status)
266
msg_warning("Your configuration file uses an obsoleted keyword, please update your configuration",
267
evt_tag_str("keyword", keywords[i].kw_name),
268
evt_tag_str("change", keywords[i].kw_explain),
274
keywords[i].kw_status = KWS_NORMAL;
275
yylval->type = LL_TOKEN;
276
yylval->token = keywords[i].kw_token;
277
return keywords[i].kw_token;
283
yylval->cptr = strdup(token);
284
return LL_IDENTIFIER;
288
cfg_lexer_start_next_include(CfgLexer *self)
290
CfgIncludeLevel *level = &self->include_stack[self->include_depth];
292
gboolean buffer_processed = FALSE;
294
if (self->include_depth == 0)
301
msg_debug("Finishing include",
302
evt_tag_str((level->include_type == CFGI_FILE ? "filename" : "content"), level->name),
303
evt_tag_int("depth", self->include_depth),
305
buffer_processed = TRUE;
308
/* reset the include state, should also handle initial invocations, in which case everything is NULL */
310
_cfg_lexer__delete_buffer(level->yybuf, self->state);
312
if (level->include_type == CFGI_FILE)
314
if (level->file.include_file)
316
fclose(level->file.include_file);
320
if ((level->include_type == CFGI_BUFFER && buffer_processed) ||
321
(level->include_type == CFGI_FILE && !level->file.files))
323
/* we finished with an include statement that included a series of
324
* files (e.g. directory include). */
327
if (level->include_type == CFGI_BUFFER)
328
g_free(level->buffer.content);
330
memset(level, 0, sizeof(*level));
332
self->include_depth--;
333
_cfg_lexer__switch_to_buffer(self->include_stack[self->include_depth].yybuf, self->state);
338
/* now populate "level" with the new include information */
339
if (level->include_type == CFGI_BUFFER)
341
level->yybuf = _cfg_lexer__scan_buffer(level->buffer.content, level->buffer.content_length, self->state);
343
else if (level->include_type == CFGI_FILE)
347
filename = (gchar *) level->file.files->data;
348
level->file.files = g_slist_delete_link(level->file.files, level->file.files);
350
include_file = fopen(filename, "r");
353
msg_error("Error opening include file",
354
evt_tag_str("filename", filename),
355
evt_tag_int("depth", self->include_depth),
360
msg_debug("Starting to read include file",
361
evt_tag_str("filename", filename),
362
evt_tag_int("depth", self->include_depth),
365
level->name = filename;
367
level->file.include_file = include_file;
368
level->yybuf = _cfg_lexer__create_buffer(level->file.include_file, YY_BUF_SIZE, self->state);
372
g_assert_not_reached();
375
level->lloc.first_line = level->lloc.last_line = 1;
376
level->lloc.first_column = level->lloc.last_column = 1;
377
level->lloc.level = level;
379
_cfg_lexer__switch_to_buffer(level->yybuf, self->state);
384
cfg_lexer_include_file_simple(CfgLexer *self, const gchar *filename)
386
CfgIncludeLevel *level;
389
if (stat(filename, &st) < 0)
394
self->include_depth++;
395
level = &self->include_stack[self->include_depth];
396
level->include_type = CFGI_FILE;
397
if (S_ISDIR(st.st_mode))
400
GError *error = NULL;
403
dir = g_dir_open(filename, 0, &error);
406
msg_error("Error opening directory for reading",
407
evt_tag_str("filename", filename),
408
evt_tag_str("error", error->message),
412
while ((entry = g_dir_read_name(dir)))
417
msg_debug("Skipping include file, it cannot begin with .",
418
evt_tag_str("filename", entry),
422
for (p = entry; *p; p++)
424
if (!((*p >= 'a' && *p <= 'z') ||
425
(*p >= 'A' && *p <= 'Z') ||
426
(*p >= '0' && *p <= '9') ||
427
(*p == '_') || (*p == '-') || (*p == '.')))
429
msg_debug("Skipping include file, does not match pattern [\\-_a-zA-Z0-9]+",
430
evt_tag_str("filename", entry),
438
gchar *full_filename = g_build_filename(filename, entry, NULL);
439
if (stat(full_filename, &st) < 0 || S_ISDIR(st.st_mode))
441
msg_debug("Skipping include file as it is a directory",
442
evt_tag_str("filename", entry),
444
g_free(full_filename);
447
level->file.files = g_slist_insert_sorted(level->file.files, full_filename, (GCompareFunc) strcmp);
448
msg_debug("Adding include file",
449
evt_tag_str("filename", entry),
454
if (!level->file.files)
456
/* no include files in the specified directory */
457
msg_debug("No files in this include directory",
458
evt_tag_str("dir", filename),
460
self->include_depth--;
466
g_assert(level->file.files == NULL);
467
level->file.files = g_slist_prepend(level->file.files, g_strdup(filename));
469
return cfg_lexer_start_next_include(self);
471
g_slist_foreach(level->file.files, (GFunc) g_free, NULL);
472
g_slist_free(level->file.files);
473
level->file.files = NULL;
479
cfg_lexer_include_file_glob_at(CfgLexer *self, const gchar *pattern)
483
gboolean status = FALSE;
486
r = glob(pattern, 0, NULL, &globbuf);
488
if (r == GLOB_NOMATCH)
493
for (i = 0; i < globbuf.gl_pathc; i++)
494
status |= cfg_lexer_include_file(self, globbuf.gl_pathv[i]);
502
cfg_lexer_include_file_glob(CfgLexer *self, const gchar *filename_)
504
const gchar *path = cfg_args_get(self->globals, "include-path");
506
if (filename_[0] == '/' || !path)
507
return cfg_lexer_include_file_glob_at(self, filename_);
513
gboolean status = FALSE;
515
dirs = g_strsplit(path, G_SEARCHPATH_SEPARATOR_S, 0);
516
while (dirs && dirs[i])
518
cf = g_build_filename(dirs[i], filename_, NULL);
519
status |= cfg_lexer_include_file_glob_at(self, cf);
529
cfg_lexer_include_file(CfgLexer *self, const gchar *filename_)
534
if (self->include_depth >= MAX_INCLUDE_DEPTH - 1)
536
msg_error("Include file depth is too deep, increase MAX_INCLUDE_DEPTH and recompile",
537
evt_tag_str("filename", filename_),
538
evt_tag_int("depth", self->include_depth),
543
filename = find_file_in_path(cfg_args_get(self->globals, "include-path"), filename_, G_FILE_TEST_EXISTS);
544
if (!filename || stat(filename, &st) < 0)
546
if (cfg_lexer_include_file_glob(self, filename_))
549
msg_error("Include file/directory not found",
550
evt_tag_str("filename", filename_),
551
evt_tag_str("include-path", cfg_args_get(self->globals, "include-path")),
552
evt_tag_errno("error", errno),
560
result = cfg_lexer_include_file_simple(self, filename);
567
cfg_lexer_include_buffer(CfgLexer *self, const gchar *name, gchar *buffer, gsize length)
569
CfgIncludeLevel *level;
571
/* lex requires two NUL characters at the end of the input */
572
buffer = g_realloc(buffer, length + 2);
574
buffer[length + 1] = 0;
577
if (self->include_depth >= MAX_INCLUDE_DEPTH - 1)
579
msg_error("Include file depth is too deep, increase MAX_INCLUDE_DEPTH and recompile",
580
evt_tag_str("buffer", name),
581
evt_tag_int("depth", self->include_depth),
586
self->include_depth++;
587
level = &self->include_stack[self->include_depth];
589
level->include_type = CFGI_BUFFER;
590
level->buffer.content = buffer;
591
level->buffer.content_length = length;
592
level->name = g_strdup(name);
594
return cfg_lexer_start_next_include(self);
598
cfg_lexer_inject_token_block(CfgLexer *self, CfgTokenBlock *block)
600
self->token_blocks = g_list_append(self->token_blocks, block);
603
static CfgBlockGenerator *
604
cfg_lexer_find_generator(CfgLexer *self, gint context, const gchar *name)
608
for (l = self->generators; l; l = l->next)
610
CfgBlockGenerator *gen = (CfgBlockGenerator *) l->data;
612
if ((gen->context == 0 || gen->context == context) && strcmp(gen->name, name) == 0)
621
cfg_lexer_register_block_generator(CfgLexer *self, gint context, const gchar *name, CfgBlockGeneratorFunc generator, gpointer generator_data, GDestroyNotify generator_data_free)
623
CfgBlockGenerator *gen;
624
gboolean res = FALSE;
626
gen = cfg_lexer_find_generator(self, context, name);
629
gen->generator_data_free(gen->generator_data);
634
gen = g_new0(CfgBlockGenerator, 1);
635
self->generators = g_list_append(self->generators, gen);
639
gen->context = context;
640
gen->name = g_strdup(name);
641
gen->generator = generator;
642
gen->generator_data = generator_data;
643
gen->generator_data_free = generator_data_free;
648
cfg_lexer_generate_block(CfgLexer *self, gint context, const gchar *name, CfgBlockGenerator *gen, CfgArgs *args)
650
return gen->generator(self, context, name, args, gen->generator_data);
654
cfg_lexer_unput_token(CfgLexer *self, YYSTYPE *yylval)
656
CfgTokenBlock *block;
658
block = cfg_token_block_new();
659
cfg_token_block_add_token(block, yylval);
660
cfg_lexer_inject_token_block(self, block);
664
cfg_lexer_lex(CfgLexer *self, YYSTYPE *yylval, YYLTYPE *yylloc)
666
CfgBlockGenerator *gen;
667
CfgTokenBlock *block;
675
while (self->token_blocks)
677
block = self->token_blocks->data;
678
token = cfg_token_block_get_token(block);
683
*yylloc = self->include_stack[self->include_depth].lloc;
685
if (token->type == LL_TOKEN)
690
else if (token->type == LL_IDENTIFIER || token->type == LL_STRING)
692
yylval->cptr = strdup(token->cptr);
699
self->token_blocks = g_list_delete_link(self->token_blocks, self->token_blocks);
700
cfg_token_block_free(block);
704
if (cfg_lexer_get_context_type(self) == LL_CONTEXT_BLOCK_CONTENT)
705
_cfg_lexer_force_block_state(self->state);
709
g_string_truncate(self->token_text, 0);
710
g_string_truncate(self->token_pretext, 0);
712
tok = _cfg_lexer_lex(yylval, yylloc, self->state);
713
if (yylval->type == 0)
716
if (self->preprocess_output)
717
fprintf(self->preprocess_output, "%s", self->token_pretext->str);
719
if (tok == LL_PRAGMA)
723
if (self->preprocess_output)
724
fprintf(self->preprocess_output, "@");
725
if (!cfg_parser_parse(&pragma_parser, self, &dummy, NULL))
731
else if (tok == KW_INCLUDE && cfg_lexer_get_context_type(self) != LL_CONTEXT_PRAGMA)
735
self->preprocess_suppress_tokens++;
736
tok = cfg_lexer_lex(self, yylval, yylloc);
737
if (tok != LL_STRING && tok != LL_IDENTIFIER)
739
self->preprocess_suppress_tokens--;
743
include_file = g_strdup(yylval->cptr);
746
tok = cfg_lexer_lex(self, yylval, yylloc);
749
self->preprocess_suppress_tokens--;
753
if (!cfg_lexer_include_file(self, include_file))
755
self->preprocess_suppress_tokens--;
758
self->preprocess_suppress_tokens--;
761
else if (tok == LL_IDENTIFIER && (gen = cfg_lexer_find_generator(self, cfg_lexer_get_context_type(self), yylval->cptr)))
765
self->preprocess_suppress_tokens++;
766
if (cfg_parser_parse(&block_ref_parser, self, (gpointer *) &args, NULL))
770
self->preprocess_suppress_tokens--;
771
success = cfg_lexer_generate_block(self, cfg_lexer_get_context_type(self), yylval->cptr, gen, args);
780
self->preprocess_suppress_tokens--;
784
else if (configuration->version == 0 && configuration->parsed_version != 0)
786
cfg_set_version(configuration, configuration->parsed_version);
788
else if (configuration->version == 0 && configuration->parsed_version == 0 && cfg_lexer_get_context_type(self) != LL_CONTEXT_PRAGMA)
790
/* no version selected yet, and we have a non-pragma token, this
791
* means that the configuration is meant for syslog-ng 2.1 */
793
msg_warning("WARNING: Configuration file has no version number, assuming syslog-ng 2.1 format. Please add @version: maj.min to the beginning of the file",
795
cfg_set_version(configuration, 0x0201);
800
if (self->preprocess_suppress_tokens == 0)
802
if (self->preprocess_output)
803
fprintf(self->preprocess_output, "%s", self->token_text->str);
810
cfg_lexer_init(CfgLexer *self)
812
self->globals = cfg_args_new();
813
CfgIncludeLevel *level;
815
_cfg_lexer_lex_init_extra(self, &self->state);
816
self->string_buffer = g_string_sized_new(32);
817
self->token_text = g_string_sized_new(32);
818
self->token_pretext = g_string_sized_new(32);
820
level = &self->include_stack[0];
821
level->lloc.first_line = level->lloc.last_line = 1;
822
level->lloc.first_column = level->lloc.last_column = 1;
823
level->lloc.level = level;
827
cfg_lexer_new(FILE *file, const gchar *filename, const gchar *preprocess_into)
830
CfgIncludeLevel *level;
832
self = g_new0(CfgLexer, 1);
833
cfg_lexer_init(self);
837
self->preprocess_output = fopen(preprocess_into, "w");
840
level = &self->include_stack[0];
841
level->include_type = CFGI_FILE;
842
level->name = g_strdup(filename);
843
level->yybuf = _cfg_lexer__create_buffer(file, YY_BUF_SIZE, self->state);
844
_cfg_lexer__switch_to_buffer(level->yybuf, self->state);
850
cfg_lexer_new_buffer(const gchar *buffer, gsize length)
853
CfgIncludeLevel *level;
855
self = g_new0(CfgLexer, 1);
856
cfg_lexer_init(self);
858
level = &self->include_stack[0];
859
level->include_type = CFGI_BUFFER;
860
level->buffer.content = g_malloc(length + 2);
861
memcpy(level->buffer.content, buffer, length);
862
level->buffer.content[length] = 0;
863
level->buffer.content[length + 1] = 0;
864
level->buffer.content_length = length + 2;
865
level->name = g_strdup("<string>");
866
level->yybuf = _cfg_lexer__scan_buffer(level->buffer.content, level->buffer.content_length, self->state);
867
_cfg_lexer__switch_to_buffer(level->yybuf, self->state);
873
cfg_lexer_free(CfgLexer *self)
877
for (i = 0; i <= self->include_depth; i++)
879
CfgIncludeLevel *level = &self->include_stack[i];
883
_cfg_lexer__delete_buffer(level->yybuf, self->state);
885
if (level->include_type == CFGI_FILE)
887
if (level->file.include_file)
888
fclose(level->file.include_file);
889
g_slist_foreach(level->file.files, (GFunc) g_free, NULL);
890
g_slist_free(level->file.files);
892
else if (level->include_type == CFGI_BUFFER)
894
g_free(level->buffer.content);
897
self->include_depth = 0;
898
_cfg_lexer_lex_destroy(self->state);
899
g_string_free(self->string_buffer, TRUE);
900
if (self->token_text)
901
g_string_free(self->token_text, TRUE);
902
if (self->token_pretext)
903
g_string_free(self->token_pretext, TRUE);
904
if (self->preprocess_output)
905
fclose(self->preprocess_output);
907
while (self->context_stack)
908
cfg_lexer_pop_context(self);
909
while (self->generators)
911
CfgBlockGenerator *gen = self->generators->data;
913
if (gen->generator_data && gen->generator_data_free)
914
gen->generator_data_free(gen->generator_data);
917
self->generators = g_list_remove_link(self->generators, self->generators);
919
cfg_args_free(self->globals);
920
g_list_foreach(self->token_blocks, (GFunc) cfg_token_block_free, NULL);
921
g_list_free(self->token_blocks);
925
static const gchar *lexer_contexts[] =
927
[LL_CONTEXT_ROOT] = "root",
928
[LL_CONTEXT_DESTINATION] = "destination",
929
[LL_CONTEXT_SOURCE] = "source",
930
[LL_CONTEXT_PARSER] = "parser",
931
[LL_CONTEXT_REWRITE] = "rewrite",
932
[LL_CONTEXT_FILTER] = "filter",
933
[LL_CONTEXT_LOG] = "log",
934
[LL_CONTEXT_BLOCK_DEF] = "block-def",
935
[LL_CONTEXT_BLOCK_REF] = "block-ref",
936
[LL_CONTEXT_BLOCK_CONTENT] = "block-content",
937
[LL_CONTEXT_PRAGMA] = "pragma",
938
[LL_CONTEXT_FORMAT] = "format",
939
[LL_CONTEXT_TEMPLATE_FUNC] = "template-func",
940
[LL_CONTEXT_INNER_DEST] = "inner-dest",
941
[LL_CONTEXT_INNER_SRC] = "inner-src",
945
cfg_lexer_lookup_context_type_by_name(const gchar *name)
949
for (i = 0; i < G_N_ELEMENTS(lexer_contexts); i++)
951
if (lexer_contexts[i] && strcmp(lexer_contexts[i], name) == 0)
958
cfg_lexer_lookup_context_name_by_type(gint type)
960
g_assert(type < G_N_ELEMENTS(lexer_contexts));
961
return lexer_contexts[type];
964
/* token block args */
967
cfg_args_validate_callback(gpointer k, gpointer v, gpointer user_data)
969
CfgArgs *defs = ((gpointer *) user_data)[0];
970
gchar **bad_key = (gchar **) &((gpointer *) user_data)[1];
971
gchar **bad_value = (gchar **) &((gpointer *) user_data)[2];
973
if ((*bad_key == NULL) && (!defs || cfg_args_get(defs, k) == NULL))
981
cfg_args_validate(CfgArgs *self, CfgArgs *defs, const gchar *context)
983
gpointer validate_params[] = { defs, NULL, NULL };
985
g_hash_table_foreach(self->args, cfg_args_validate_callback, validate_params);
987
if (validate_params[1])
989
msg_error("Unknown argument",
990
evt_tag_str("context", context),
991
evt_tag_str("arg", validate_params[1]),
992
evt_tag_str("value", validate_params[2]),
1000
cfg_args_set(CfgArgs *self, const gchar *name, const gchar *value)
1002
g_hash_table_insert(self->args, g_strdup(name), g_strdup(value));
1006
cfg_args_get(CfgArgs *self, const gchar *name)
1008
return g_hash_table_lookup(self->args, name);
1014
CfgArgs *self = g_new0(CfgArgs, 1);
1016
self->args = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
1021
cfg_args_free(CfgArgs *self)
1023
g_hash_table_destroy(self->args);
1030
cfg_token_block_add_token(CfgTokenBlock *self, YYSTYPE *token)
1032
g_assert(self->pos == 0);
1033
g_array_append_val(self->tokens, *token);
1037
cfg_token_block_get_token(CfgTokenBlock *self)
1039
if (self->pos < self->tokens->len)
1043
result = &g_array_index(self->tokens, YYSTYPE, self->pos);
1051
cfg_token_block_new()
1053
CfgTokenBlock *self = g_new0(CfgTokenBlock, 1);
1055
self->tokens = g_array_new(FALSE, TRUE, sizeof(YYSTYPE));
1060
cfg_token_block_free(CfgTokenBlock *self)
1064
for (i = 0; i < self->tokens->len; i++)
1066
YYSTYPE *token = &g_array_index(self->tokens, YYSTYPE, i);
1068
if (token->type == LL_STRING || token->type == LL_IDENTIFIER)
1069
g_free(token->cptr);
1072
g_array_free(self->tokens, TRUE);
1076
/* user defined blocks */
1079
* This class encapsulates a configuration block that the user defined
1080
* via the configuration file. It behaves like a macro, e.g. when
1081
* referenced the content of the block is expanded.
1083
* Each block is identified by its name and the context (source,
1084
* destination, etc.) where it is meant to be used.
1086
* A block has a set of name-value pairs to allow expansion to be
1087
* parameterized. The set of allowed NV pairs is defined at block
1097
* cfg_block_generate:
1099
* This is a CfgBlockGeneratorFunc, which takes a CfgBlock defined by
1100
* the user, substitutes backtick values and generates input tokens
1104
cfg_block_generate(CfgLexer *lexer, gint context, const gchar *name, CfgArgs *args, gpointer user_data)
1106
CfgBlock *block = (CfgBlock *) user_data;
1111
g_snprintf(buf, sizeof(buf), "%s block %s", cfg_lexer_lookup_context_name_by_type(context), name);
1112
if (!cfg_args_validate(args, block->arg_defs, buf))
1117
value = cfg_lexer_subst_args(lexer->globals, block->arg_defs, args, block->content, &length);
1121
msg_warning("Syntax error while resolving backtick references in block, missing closing '`' character",
1122
evt_tag_str("context", cfg_lexer_lookup_context_name_by_type(context)),
1123
evt_tag_str("block", name),
1128
return cfg_lexer_include_buffer(lexer, buf, value, length);
1132
* Construct a user defined block.
1135
cfg_block_new(const gchar *content, CfgArgs *arg_defs)
1137
CfgBlock *self = g_new0(CfgBlock, 1);
1139
self->content = g_strdup(content);
1140
self->arg_defs = arg_defs;
1145
* Free a user defined block.
1148
cfg_block_free(CfgBlock *self)
1150
g_free(self->content);
1151
cfg_args_free(self->arg_defs);