aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/grecs-syntax.texi25
-rw-r--r--doc/grecs_config.527
-rw-r--r--src/preproc.c63
-rw-r--r--tests/Makefile.am6
-rw-r--r--tests/incl00.at39
-rw-r--r--tests/incl01.at41
-rw-r--r--tests/incl02.at51
-rw-r--r--tests/incl03.at45
-rw-r--r--tests/testsuite.at8
9 files changed, 281 insertions, 24 deletions
diff --git a/doc/grecs-syntax.texi b/doc/grecs-syntax.texi
index c10cab6..da59d03 100644
--- a/doc/grecs-syntax.texi
+++ b/doc/grecs-syntax.texi
@@ -1,8 +1,8 @@
@c This file is part of grecs - Gray's Extensible Configuration System
-@c Copyright (C) 2007, 2009-2012 Sergey Poznyakoff
+@c Copyright (C) 2007, 2009-2014 Sergey Poznyakoff
@c
@c Grecs is free software; you can redistribute it and/or modify
@c it under the terms of the GNU General Public License as published by
@c the Free Software Foundation; either version 3, or (at your option)
@c any later version.
@c
@@ -79,18 +79,29 @@ parsed. Pragmatic comments begin with a @samp{#} sign and end with the
next physical newline character.
@table @code
@kwindex #include
@item #include <@var{file}>
@itemx #include @var{file}
-Include the contents of the file @var{file}. If @var{file} is an
-absolute file name, both forms are equivalent. Otherwise, the form
-with angle brackets searches for the file in the @dfn{include
-search path}, while the second one looks for it in the current working
-directory first, and, if not found there, in the include search
-path.
+Include the contents of the file @var{file}. There are three possible
+use cases.
+
+If @var{file} is an absolute file name, the named file is included.
+An error message will be issued if it does not exist.
+
+If @var{file} contains wildcard characters (@samp{*}, @samp{[},
+@samp{]} or @samp{?}), it is interpreted as shell globbing pattern and
+all files matching that pattern are included, in lexicographical
+order. If no files match the pattern, the statement is silently
+ignored.
+
+Otherwise, the form with angle brackets searches for file in the
+@dfn{include search path}, while the second one looks for it in the
+current working directory first, and, if not found there, in the
+include search path. If the file is not found, an error message will
+be issued.
The default include search path is:
@enumerate 1
@item @file{@var{prefix}/share/@value{PROGNAME}/@value{VERSION}/include}
@item @file{@var{prefix}/share/@value{PROGNAME}/include}
diff --git a/doc/grecs_config.5 b/doc/grecs_config.5
index 80f7bcc..82633d5 100644
--- a/doc/grecs_config.5
+++ b/doc/grecs_config.5
@@ -1,8 +1,8 @@
.\" This file is part of grecs -*- nroff -*-
-.\" Copyright (C) 2007, 2009-2012 Sergey Poznyakoff
+.\" Copyright (C) 2007, 2009-2014 Sergey Poznyakoff
.\"
.\" Grecs is free software; you can redistribute it and/or modify
.\" it under the terms of the GNU General Public License as published by
.\" the Free Software Foundation; either version 3, or (at your option)
.\" any later version.
.\"
@@ -11,13 +11,13 @@
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
.\" GNU General Public License for more details.
.\"
.\" You should have received a copy of the GNU General Public License
.\" along with Grecs. If not, see <http://www.gnu.org/licenses/>.
.\"
-.TH GRECS_CONFIG 3 "May 4, 2011" "GRECS" "Grecs User Reference"
+.TH GRECS_CONFIG 3 "December 25, 2014" "GRECS" "Grecs User Reference"
.SH NAME
\fBGrecs\fR configuration file syntax
.SH DESCRIPTION
.PP
A configuration file consists of statements and comments.
.PP
@@ -61,18 +61,29 @@ sign and end with the next physical newline character.
.TP
.BR "#include <" "file" >
.PD 0
.TP
.BR "#include " "file"
.PD
-Include the contents of the file \fIfile\fR. If it is an
-absolute file name, both forms are equivalent. Otherwise, the form
-with angle brackets searches for the file in the \fIinclude
-search path\fR, while the second one looks for it in the current working
-directory first, and, if not found there, in the include search
-path.
+Include the contents of the file \fIfile\fR. There are three possible
+use cases.
+
+If \fIfile\fR is an absolute file name, the named file is included.
+An error message will be issued if it does not exist.
+
+If \fIfile\fR contains wildcard characters (\fB*\fR, \fB[\fR,
+\fB]\fR or \fB?\fR), it is interpreted as shell globbing pattern and
+all files matching that pattern are included, in lexicographical
+order. If no files match the pattern, the statement is silently
+ignored.
+
+Otherwise, the form with angle brackets searches for file in the
+\fIinclude search path\fR, while the second one looks for it in the
+current working directory first, and, if not found there, in the
+include search path. If the file is not found, an error message will
+be issued.
.sp
The default include search path is:
.sp
\fIprefix\fR/share/\fIPROGNAME\fR/\fIVERSION\fR/include
.br
\fIprefix\fR/share/\fIPROGNAME\fR/include
diff --git a/src/preproc.c b/src/preproc.c
index ce32a29..56dcc22 100644
--- a/src/preproc.c
+++ b/src/preproc.c
@@ -1,8 +1,8 @@
/* grecs - Gray's Extensible Configuration System
- Copyright (C) 2007-2012 Sergey Poznyakoff
+ Copyright (C) 2007-2014 Sergey Poznyakoff
Grecs is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3 of the License, or (at your
option) any later version.
@@ -25,12 +25,13 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
+#include <glob.h>
#include <wordsplit.h>
int grecs_log_to_stderr = 1;
void (*grecs_log_setup_hook) () = NULL;
@@ -59,12 +60,15 @@ static size_t linebufsize = 0;
static char *linebuf;
static size_t bufsize;
static char *putback_buffer;
static size_t putback_size;
static size_t putback_max;
+static glob_t include_glob;
+static size_t include_pos;
+static int include_once;
static int push_source (const char *name, int once);
static int pop_source (void);
static int parse_include (const char *text, int once);
ssize_t
@@ -284,13 +288,15 @@ struct file_data {
};
static int
pp_list_find(struct grecs_list *list, struct file_data *dptr)
{
struct grecs_list_entry *ep;
-
+
+ if (!list)
+ return 0;
for (ep = list->head; !dptr->found && ep; ep = ep->next) {
const char *dir = ep->data;
size_t size = strlen (dir) + 1 + dptr->namelen + 1;
if (size > dptr->buflen) {
dptr->buflen = size;
dptr->buf = grecs_realloc(dptr->buf, dptr->buflen);
@@ -392,23 +398,30 @@ incl_compare(void const *data1, void const *data2)
const struct input_file_ident *id1 = data1;
const struct input_file_ident *id2 = data2;
return !(id1->device == id2->device && id1->i_node == id2->i_node);
}
static int
+incl_copy(void *dst, void *src)
+{
+ memcpy(dst, src, sizeof(struct input_file_ident));
+ return 0;
+}
+
+static int
source_lookup(struct stat *st)
{
struct input_file_ident key;
int install = 1;
if (!incl_sources) {
incl_sources = grecs_symtab_create(
sizeof(struct input_file_ident),
incl_hasher,
incl_compare,
- NULL,
+ incl_copy,
NULL,/*FIXME: alloc*/
NULL);
if (!incl_sources)
grecs_alloc_die();
}
@@ -502,12 +515,20 @@ pop_source()
/* Restore previous context */
ctx = context_stack->prev;
grecs_free(context_stack);
context_stack = ctx;
+ if (include_pos < include_glob.gl_pathc) {
+ push_source(include_glob.gl_pathv[include_pos++], include_once);
+ return 0;
+ } else if (include_glob.gl_pathc) {
+ globfree(&include_glob);
+ include_pos = include_glob.gl_pathc = 0;
+ }
+
if (!context_stack) {
if (grecs_grecs__flex_debug)
fprintf(stderr, "End of input\n");
return 1;
}
@@ -549,12 +570,22 @@ grecs_find_include_file(const char *name, int allow_cwd)
return NULL;
}
return fd.buf;
}
static int
+isglob(const char *s)
+{
+ for (; *s; s++) {
+ if (strchr("*?[", *s))
+ return 1;
+ }
+ return 0;
+}
+
+static int
parse_include(const char *text, int once)
{
struct wordsplit ws;
char *tmp = NULL;
char *p = NULL;
int rc = 1;
@@ -576,23 +607,41 @@ parse_include(const char *text, int once)
p[len - 1] = 0;
p++;
}
else
allow_cwd = 1;
- if (p[0] != '/') {
- p = grecs_find_include_file(p, allow_cwd);
+ if (isglob(p)) {
+ switch (glob(p, 0, NULL, &include_glob)) {
+ case 0:
+ include_pos = 0;
+ include_once = once;
+ break;
+ case GLOB_NOSPACE:
+ grecs_alloc_die();
+ case GLOB_NOMATCH:
+ break;
+ default:
+ grecs_error(&LOCUS, 0, _("read error"));
+ }
+ p = NULL;
+ } else if (p[0] != '/') {
+ char *q = p;
+ p = grecs_find_include_file(q, allow_cwd);
if (!p)
grecs_error(&LOCUS, 0,
_("%s: No such file or directory"),
- p);
+ q);
}
- }
+ }
if (p)
rc = push_source(p, once);
+ else if (include_pos < include_glob.gl_pathc)
+ rc = push_source(include_glob.gl_pathv[include_pos++], once);
+
grecs_free(tmp);
wordsplit_free(&ws);
return rc;
}
int
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 76cfbfe..d6b9d3e 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,8 +1,8 @@
# This file is part of grecs - Gray's Extensible Configuration System
-# Copyright (C) 2007, 2009-2012 Sergey Poznyakoff
+# Copyright (C) 2007, 2009-2014 Sergey Poznyakoff
#
# Grecs is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
#
@@ -80,12 +80,16 @@ TESTSUITE_AT = \
glob02.at\
glob03.at\
glob04.at\
glob05.at\
grecs00.at\
enum.at\
+ incl00.at\
+ incl01.at\
+ incl02.at\
+ incl03.at\
join.at\
locus00.at\
locus01.at\
locus02.at\
locus-bind.at\
locus-git.at\
diff --git a/tests/incl00.at b/tests/incl00.at
new file mode 100644
index 0000000..bb99fd2
--- /dev/null
+++ b/tests/incl00.at
@@ -0,0 +1,39 @@
+# This file is part of grecs -*- Autotest -*-
+# Copyright (C) 2014 Sergey Poznyakoff
+#
+# Grecs is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# Grecs is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Grecs. If not, see <http://www.gnu.org/licenses/>.
+
+AT_SETUP([Include path])
+AT_KEYWORDS([include incl00])
+
+AT_CHECK([
+mkdir include
+AT_DATA([include/1.inc],[this true;
+])
+
+AT_DATA([test.cf],[
+before 1;
+#include <1.inc>
+after 1;
+])
+
+gcffmt -I`pwd`/include ./test.cf
+],
+[0],
+[.before: "1"
+.this: "true"
+.after: "1"
+])
+
+AT_CLEANUP
diff --git a/tests/incl01.at b/tests/incl01.at
new file mode 100644
index 0000000..0be469b
--- /dev/null
+++ b/tests/incl01.at
@@ -0,0 +1,41 @@
+# This file is part of grecs -*- Autotest -*-
+# Copyright (C) 2014 Sergey Poznyakoff
+#
+# Grecs is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# Grecs is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Grecs. If not, see <http://www.gnu.org/licenses/>.
+
+AT_SETUP([Recursive inclusion])
+AT_KEYWORDS([include incl01])
+
+AT_CHECK([
+AT_DATA([a.inc],[this true;
+#include "b.inc"
+])
+
+AT_DATA([b.inc],[#include "a.inc"
+])
+
+AT_DATA([test.cf],[before 1;
+#include "a.inc"
+after 1;
+])
+
+gcffmt ./test.cf
+],
+[1],
+[],
+[./b.inc:1: Recursive inclusion
+./test.cf:2: `./a.inc' already included here
+])
+
+AT_CLEANUP
diff --git a/tests/incl02.at b/tests/incl02.at
new file mode 100644
index 0000000..edf83c3
--- /dev/null
+++ b/tests/incl02.at
@@ -0,0 +1,51 @@
+# This file is part of grecs -*- Autotest -*-
+# Copyright (C) 2014 Sergey Poznyakoff
+#
+# Grecs is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# Grecs is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Grecs. If not, see <http://www.gnu.org/licenses/>.
+
+AT_SETUP([Include once])
+AT_KEYWORDS([include incl02])
+
+AT_CHECK([
+AT_DATA([a.inc],[a true;
+])
+
+AT_DATA([test1.cf],[before 1;
+#include "a.inc"
+#include "a.inc"
+after 1;
+])
+
+AT_DATA([test2.cf],[before 1;
+#include_once "a.inc"
+#include_once "a.inc"
+after 1;
+])
+
+gcffmt ./test1.cf
+echo ==
+gcffmt ./test2.cf
+],
+[0],
+[.before: "1"
+.a: "true"
+.a: "true"
+.after: "1"
+==
+.before: "1"
+.a: "true"
+.after: "1"
+])
+
+AT_CLEANUP
diff --git a/tests/incl03.at b/tests/incl03.at
new file mode 100644
index 0000000..201222f
--- /dev/null
+++ b/tests/incl03.at
@@ -0,0 +1,45 @@
+# This file is part of grecs -*- Autotest -*-
+# Copyright (C) 2014 Sergey Poznyakoff
+#
+# Grecs is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# Grecs is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Grecs. If not, see <http://www.gnu.org/licenses/>.
+
+AT_SETUP([Wildcard inclusion])
+AT_KEYWORDS([include incl03])
+
+AT_CHECK([
+AT_DATA([i1.inc],[i1 included;
+])
+
+AT_DATA([i2.inc],[i2 included;
+])
+
+AT_DATA([i3.inc],[i3 included;
+])
+
+AT_DATA([test.cf],[before 1;
+#include "i*.inc"
+after 1;
+])
+
+gcffmt ./test.cf
+],
+[0],
+[.before: "1"
+.i1: "included"
+.i2: "included"
+.i3: "included"
+.after: "1"
+])
+
+AT_CLEANUP
diff --git a/tests/testsuite.at b/tests/testsuite.at
index 2d42d4d..eaad2f1 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -1,8 +1,8 @@
# This file is part of grecs - Gray's Extensible Configuration System -*- Autotest -*-
-# Copyright (C) 2007, 2009-2012 Sergey Poznyakoff
+# Copyright (C) 2007, 2009-2014 Sergey Poznyakoff
#
# Grecs is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
#
@@ -76,12 +76,18 @@ m4_include([reduce02.at])
m4_include([reduce03.at])
AT_BANNER([Sort])
m4_include([sort00.at])
m4_include([sort01.at])
+AT_BANNER([Include])
+m4_include([incl00.at])
+m4_include([incl01.at])
+m4_include([incl02.at])
+m4_include([incl03.at])
+
m4_ifdef([ENABLE_BIND_PARSER],[
AT_BANNER([BIND Parser])
m4_include([parser-bind.at])
m4_include([bind00.at])
m4_include([locus-bind.at])
])

Return to:

Send suggestions and report system problems to the System administrator.