diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2014-12-25 20:15:22 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2014-12-26 01:17:52 +0200 |
commit | add57c075c6f747a81c142ab48d59106de822664 (patch) | |
tree | c15f94acdf135954e2f63ac7657c57cdd134ed75 | |
parent | d51e1365118ce87016a39bd94437e31b35b8d307 (diff) | |
download | grecs-add57c075c6f747a81c142ab48d59106de822664.tar.gz grecs-add57c075c6f747a81c142ab48d59106de822664.tar.bz2 |
Add globbing pattern support to #include and #include_once
* doc/grecs-syntax.texi: Document changes to the #include statement.
* doc/grecs_config.5: Likewise.
* src/preproc.c (include_glob, include_pos)
(include_once): New statics.
(pp_list_find): Return 0 if list is NULL.
(incl_copy): New statics.
(source_lookup): Use incl_copy as the copy function.
(pop_source): If more glob expansions are available, push next one
onto input stack.
(isglob): New static.
(parse_include): Support globbing patterns.
* tests/Makefile.am: Add new testes.
* tests/testsuite.at: Likewise.
* tests/incl00.at: New test case.
* tests/incl01.at: New test case.
* tests/incl02.at: New test case.
* tests/incl03.at: New test case.
-rw-r--r-- | doc/grecs-syntax.texi | 25 | ||||
-rw-r--r-- | doc/grecs_config.5 | 27 | ||||
-rw-r--r-- | src/preproc.c | 63 | ||||
-rw-r--r-- | tests/Makefile.am | 6 | ||||
-rw-r--r-- | tests/incl00.at | 39 | ||||
-rw-r--r-- | tests/incl01.at | 41 | ||||
-rw-r--r-- | tests/incl02.at | 51 | ||||
-rw-r--r-- | tests/incl03.at | 45 | ||||
-rw-r--r-- | tests/testsuite.at | 8 |
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,5 +1,5 @@ | |||
1 | @c This file is part of grecs - Gray's Extensible Configuration System | 1 | @c This file is part of grecs - Gray's Extensible Configuration System |
2 | @c Copyright (C) 2007, 2009-2012 Sergey Poznyakoff | 2 | @c Copyright (C) 2007, 2009-2014 Sergey Poznyakoff |
3 | @c | 3 | @c |
4 | @c Grecs is free software; you can redistribute it and/or modify | 4 | @c Grecs is free software; you can redistribute it and/or modify |
5 | @c it under the terms of the GNU General Public License as published by | 5 | @c it under the terms of the GNU General Public License as published by |
@@ -82,12 +82,23 @@ next physical newline character. | |||
82 | @kwindex #include | 82 | @kwindex #include |
83 | @item #include <@var{file}> | 83 | @item #include <@var{file}> |
84 | @itemx #include @var{file} | 84 | @itemx #include @var{file} |
85 | Include the contents of the file @var{file}. If @var{file} is an | 85 | Include the contents of the file @var{file}. There are three possible |
86 | absolute file name, both forms are equivalent. Otherwise, the form | 86 | use cases. |
87 | with angle brackets searches for the file in the @dfn{include | 87 | |
88 | search path}, while the second one looks for it in the current working | 88 | If @var{file} is an absolute file name, the named file is included. |
89 | directory first, and, if not found there, in the include search | 89 | An error message will be issued if it does not exist. |
90 | path. | 90 | |
91 | If @var{file} contains wildcard characters (@samp{*}, @samp{[}, | ||
92 | @samp{]} or @samp{?}), it is interpreted as shell globbing pattern and | ||
93 | all files matching that pattern are included, in lexicographical | ||
94 | order. If no files match the pattern, the statement is silently | ||
95 | ignored. | ||
96 | |||
97 | Otherwise, the form with angle brackets searches for file in the | ||
98 | @dfn{include search path}, while the second one looks for it in the | ||
99 | current working directory first, and, if not found there, in the | ||
100 | include search path. If the file is not found, an error message will | ||
101 | be issued. | ||
91 | 102 | ||
92 | The default include search path is: | 103 | The default include search path is: |
93 | 104 | ||
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,5 +1,5 @@ | |||
1 | .\" This file is part of grecs -*- nroff -*- | 1 | .\" This file is part of grecs -*- nroff -*- |
2 | .\" Copyright (C) 2007, 2009-2012 Sergey Poznyakoff | 2 | .\" Copyright (C) 2007, 2009-2014 Sergey Poznyakoff |
3 | .\" | 3 | .\" |
4 | .\" Grecs is free software; you can redistribute it and/or modify | 4 | .\" Grecs is free software; you can redistribute it and/or modify |
5 | .\" it under the terms of the GNU General Public License as published by | 5 | .\" it under the terms of the GNU General Public License as published by |
@@ -14,7 +14,7 @@ | |||
14 | .\" You should have received a copy of the GNU General Public License | 14 | .\" You should have received a copy of the GNU General Public License |
15 | .\" along with Grecs. If not, see <http://www.gnu.org/licenses/>. | 15 | .\" along with Grecs. If not, see <http://www.gnu.org/licenses/>. |
16 | .\" | 16 | .\" |
17 | .TH GRECS_CONFIG 3 "May 4, 2011" "GRECS" "Grecs User Reference" | 17 | .TH GRECS_CONFIG 3 "December 25, 2014" "GRECS" "Grecs User Reference" |
18 | .SH NAME | 18 | .SH NAME |
19 | \fBGrecs\fR configuration file syntax | 19 | \fBGrecs\fR configuration file syntax |
20 | .SH DESCRIPTION | 20 | .SH DESCRIPTION |
@@ -64,12 +64,23 @@ sign and end with the next physical newline character. | |||
64 | .TP | 64 | .TP |
65 | .BR "#include " "file" | 65 | .BR "#include " "file" |
66 | .PD | 66 | .PD |
67 | Include the contents of the file \fIfile\fR. If it is an | 67 | Include the contents of the file \fIfile\fR. There are three possible |
68 | absolute file name, both forms are equivalent. Otherwise, the form | 68 | use cases. |
69 | with angle brackets searches for the file in the \fIinclude | 69 | |
70 | search path\fR, while the second one looks for it in the current working | 70 | If \fIfile\fR is an absolute file name, the named file is included. |
71 | directory first, and, if not found there, in the include search | 71 | An error message will be issued if it does not exist. |
72 | path. | 72 | |
73 | If \fIfile\fR contains wildcard characters (\fB*\fR, \fB[\fR, | ||
74 | \fB]\fR or \fB?\fR), it is interpreted as shell globbing pattern and | ||
75 | all files matching that pattern are included, in lexicographical | ||
76 | order. If no files match the pattern, the statement is silently | ||
77 | ignored. | ||
78 | |||
79 | Otherwise, the form with angle brackets searches for file in the | ||
80 | \fIinclude search path\fR, while the second one looks for it in the | ||
81 | current working directory first, and, if not found there, in the | ||
82 | include search path. If the file is not found, an error message will | ||
83 | be issued. | ||
73 | .sp | 84 | .sp |
74 | The default include search path is: | 85 | The default include search path is: |
75 | .sp | 86 | .sp |
diff --git a/src/preproc.c b/src/preproc.c index ce32a29..56dcc22 100644 --- a/src/preproc.c +++ b/src/preproc.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* grecs - Gray's Extensible Configuration System | 1 | /* grecs - Gray's Extensible Configuration System |
2 | Copyright (C) 2007-2012 Sergey Poznyakoff | 2 | Copyright (C) 2007-2014 Sergey Poznyakoff |
3 | 3 | ||
4 | Grecs is free software; you can redistribute it and/or modify it | 4 | Grecs is free software; you can redistribute it and/or modify it |
5 | under the terms of the GNU General Public License as published by the | 5 | under the terms of the GNU General Public License as published by the |
@@ -28,6 +28,7 @@ | |||
28 | #include <string.h> | 28 | #include <string.h> |
29 | #include <errno.h> | 29 | #include <errno.h> |
30 | #include <signal.h> | 30 | #include <signal.h> |
31 | #include <glob.h> | ||
31 | 32 | ||
32 | #include <wordsplit.h> | 33 | #include <wordsplit.h> |
33 | 34 | ||
@@ -62,6 +63,9 @@ static size_t bufsize; | |||
62 | static char *putback_buffer; | 63 | static char *putback_buffer; |
63 | static size_t putback_size; | 64 | static size_t putback_size; |
64 | static size_t putback_max; | 65 | static size_t putback_max; |
66 | static glob_t include_glob; | ||
67 | static size_t include_pos; | ||
68 | static int include_once; | ||
65 | 69 | ||
66 | static int push_source (const char *name, int once); | 70 | static int push_source (const char *name, int once); |
67 | static int pop_source (void); | 71 | static int pop_source (void); |
@@ -287,7 +291,9 @@ static int | |||
287 | pp_list_find(struct grecs_list *list, struct file_data *dptr) | 291 | pp_list_find(struct grecs_list *list, struct file_data *dptr) |
288 | { | 292 | { |
289 | struct grecs_list_entry *ep; | 293 | struct grecs_list_entry *ep; |
290 | 294 | ||
295 | if (!list) | ||
296 | return 0; | ||
291 | for (ep = list->head; !dptr->found && ep; ep = ep->next) { | 297 | for (ep = list->head; !dptr->found && ep; ep = ep->next) { |
292 | const char *dir = ep->data; | 298 | const char *dir = ep->data; |
293 | size_t size = strlen (dir) + 1 + dptr->namelen + 1; | 299 | size_t size = strlen (dir) + 1 + dptr->namelen + 1; |
@@ -395,6 +401,13 @@ incl_compare(void const *data1, void const *data2) | |||
395 | } | 401 | } |
396 | 402 | ||
397 | static int | 403 | static int |
404 | incl_copy(void *dst, void *src) | ||
405 | { | ||
406 | memcpy(dst, src, sizeof(struct input_file_ident)); | ||
407 | return 0; | ||
408 | } | ||
409 | |||
410 | static int | ||
398 | source_lookup(struct stat *st) | 411 | source_lookup(struct stat *st) |
399 | { | 412 | { |
400 | struct input_file_ident key; | 413 | struct input_file_ident key; |
@@ -405,7 +418,7 @@ source_lookup(struct stat *st) | |||
405 | sizeof(struct input_file_ident), | 418 | sizeof(struct input_file_ident), |
406 | incl_hasher, | 419 | incl_hasher, |
407 | incl_compare, | 420 | incl_compare, |
408 | NULL, | 421 | incl_copy, |
409 | NULL,/*FIXME: alloc*/ | 422 | NULL,/*FIXME: alloc*/ |
410 | NULL); | 423 | NULL); |
411 | if (!incl_sources) | 424 | if (!incl_sources) |
@@ -505,6 +518,14 @@ pop_source() | |||
505 | grecs_free(context_stack); | 518 | grecs_free(context_stack); |
506 | context_stack = ctx; | 519 | context_stack = ctx; |
507 | 520 | ||
521 | if (include_pos < include_glob.gl_pathc) { | ||
522 | push_source(include_glob.gl_pathv[include_pos++], include_once); | ||
523 | return 0; | ||
524 | } else if (include_glob.gl_pathc) { | ||
525 | globfree(&include_glob); | ||
526 | include_pos = include_glob.gl_pathc = 0; | ||
527 | } | ||
528 | |||
508 | if (!context_stack) { | 529 | if (!context_stack) { |
509 | if (grecs_grecs__flex_debug) | 530 | if (grecs_grecs__flex_debug) |
510 | fprintf(stderr, "End of input\n"); | 531 | fprintf(stderr, "End of input\n"); |
@@ -552,6 +573,16 @@ grecs_find_include_file(const char *name, int allow_cwd) | |||
552 | } | 573 | } |
553 | 574 | ||
554 | static int | 575 | static int |
576 | isglob(const char *s) | ||
577 | { | ||
578 | for (; *s; s++) { | ||
579 | if (strchr("*?[", *s)) | ||
580 | return 1; | ||
581 | } | ||
582 | return 0; | ||
583 | } | ||
584 | |||
585 | static int | ||
555 | parse_include(const char *text, int once) | 586 | parse_include(const char *text, int once) |
556 | { | 587 | { |
557 | struct wordsplit ws; | 588 | struct wordsplit ws; |
@@ -579,17 +610,35 @@ parse_include(const char *text, int once) | |||
579 | else | 610 | else |
580 | allow_cwd = 1; | 611 | allow_cwd = 1; |
581 | 612 | ||
582 | if (p[0] != '/') { | 613 | if (isglob(p)) { |
583 | p = grecs_find_include_file(p, allow_cwd); | 614 | switch (glob(p, 0, NULL, &include_glob)) { |
615 | case 0: | ||
616 | include_pos = 0; | ||
617 | include_once = once; | ||
618 | break; | ||
619 | case GLOB_NOSPACE: | ||
620 | grecs_alloc_die(); | ||
621 | case GLOB_NOMATCH: | ||
622 | break; | ||
623 | default: | ||
624 | grecs_error(&LOCUS, 0, _("read error")); | ||
625 | } | ||
626 |