aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2019-05-06 13:53:33 +0300
committerSergey Poznyakoff <gray@gnu.org>2019-05-06 13:53:33 +0300
commit338c8ebdfc70c653a674df628cf9c876b5c54267 (patch)
treedaba1bc56d64e8a919c30b51d09719991fa3b705
parent90d064900d35975950587882a00cfe92b26d94bd (diff)
downloadrush-338c8ebdfc70c653a674df628cf9c876b5c54267.tar.gz
rush-338c8ebdfc70c653a674df628cf9c876b5c54267.tar.bz2
Improve parser. Add more tests.
* src/cf.c: New global option "expand-undefined". (global_attrib_set): Handle the 'b' data type marker. * src/cf.h (expand_undefined): New extern. * src/cfgram.y: Provide textual descriptions for named tokens. Require '=' or '=~' between identifier and value in SET and SETENV rules. Allow for values in UNSETENV list. * src/cflex.l: Accept slashes in unquoted strings. Gracefully handle undefined escape sequences in strings. * src/map.c (expand_undefined): New global. (rush_expand_string): Expand undefined variables to empty strings if expand_undefined is set. * tests/Makefile.am: Add new tests. * tests/testsuite.at: Add new tests. * tests/backref.at: New file. * tests/clrenv.at: New file. * tests/keepenv.at: New file. * tests/regexp.at: New file. * tests/setenv.at: New file. * tests/setvar.at: New file. * tests/undef.at: New file.
-rw-r--r--src/cf.c17
-rw-r--r--src/cf.h1
-rw-r--r--src/cfgram.y124
-rw-r--r--src/cflex.l32
-rw-r--r--src/map.c5
-rw-r--r--tests/Makefile.am9
-rw-r--r--tests/backref.at43
-rw-r--r--tests/clrenv.at34
-rw-r--r--tests/fallthrough.at6
-rw-r--r--tests/keepenv.at40
-rw-r--r--tests/regexp.at88
-rw-r--r--tests/set.at10
-rw-r--r--tests/setenv.at130
-rw-r--r--tests/setvar.at43
-rw-r--r--tests/testsuite.at17
-rw-r--r--tests/transform.at8
-rw-r--r--tests/undef.at65
-rw-r--r--tests/unsetenv.at76
-rw-r--r--tests/unsetvar.at46
19 files changed, 723 insertions, 71 deletions
diff --git a/src/cf.c b/src/cf.c
index 2742fa7..e304be9 100644
--- a/src/cf.c
+++ b/src/cf.c
@@ -862,6 +862,13 @@ glattrib_acct_umask(int argc, struct argval *arg)
return parse_file_mode(arg->strval, &rushdb_umask, &arg->loc);
}
+static int
+glattrib_expand_undef(int argc, struct argval *arg)
+{
+ expand_undefined = arg->intval;
+ return 0;
+}
+
static struct global_attrib global_attrib[] = {
{ "debug", "n", glattrib_debug },
{ "sleep-time", "n", glattrib_sleep_time },
@@ -871,6 +878,7 @@ static struct global_attrib global_attrib[] = {
{ "acct-file-mode", "s", glattrib_acct_file_mode },
{ "acct-dir-mode", "s", glattrib_acct_dir_mode },
{ "acct-umask", "s", glattrib_acct_umask },
+ { "expand-undefined", "b", glattrib_expand_undef },
{ NULL }
};
@@ -906,6 +914,15 @@ global_attrib_set(struct global_attrib *glatt,
case 's':
i++;
break;
+ case 'b':
+ if (get_bool(arg->strval, &arg->intval)) {
+ cferror(loc,
+ _("expected boolean value, but found `%s'"),
+ arg->strval);
+ return 1;
+ }
+ i++;
+ break;
case '.':
break;
case 0:
diff --git a/src/cf.h b/src/cf.h
index 5e3b2d2..4ba1800 100644
--- a/src/cf.h
+++ b/src/cf.h
@@ -152,6 +152,7 @@ void global_attrib_set(struct global_attrib *glatt,
extern int re_flags;
+extern int expand_undefined;
extern struct cfloc curloc;
void trimws(char *s);
diff --git a/src/cfgram.y b/src/cfgram.y
index 052dae6..386608f 100644
--- a/src/cfgram.y
+++ b/src/cfgram.y
@@ -1,4 +1,4 @@
-/* This file is part of GNU Rush.
+/* This file is part of GNU Rush.
Copyright (C) 2008-2019 Sergey Poznyakoff
GNU Rush is free software; you can redistribute it and/or modify
@@ -20,11 +20,12 @@
static int errors;
int re_flags = REG_EXTENDED;
static struct rush_rule *current_rule;
-struct name_entry {
- struct name_entry *next;
+struct asgn {
+ struct asgn *next;
char *name;
+ char *value;
};
-static void add_name_list(struct name_entry *head, enum envar_type type);
+static void add_asgn_list(struct asgn *head, enum envar_type type);
%}
%error-verbose
@@ -45,10 +46,11 @@ static void add_name_list(struct name_entry *head, enum envar_type type);
int start;
int end;
} range;
+ struct asgn *asgn;
struct {
- struct name_entry *head;
- struct name_entry *tail;
- } name_list;
+ struct asgn *head;
+ struct asgn *tail;
+ } asgn_list;
struct limits_rec *lrec;
rule_attrib_setter_t attrib;
struct global_attrib *global_attrib;
@@ -85,10 +87,23 @@ static void add_name_list(struct name_entry *head, enum envar_type type);
%token <global_attrib> GLATTRIB "global attribute"
%token BOGUS "erroneous token"
+%token OR "||"
+%token AND "&&"
+%token NOT "!"
+%token EQ "=="
+%token NE "!="
+%token LT "<"
+%token LE "<="
+%token GT ">"
+%token GE ">="
+%token XF "=~"
+%token IN "in"
+%token MEMBER "member"
+
%left OR
%left AND
%left NOT
-%nonassoc EQ NE LT LE GT GE '~' IN MEMBER
+%nonassoc EQ NE LT LE GT GE XF '~' IN MEMBER
%type <intval> fdescr index
%type <str> literal string value defval ruleid
@@ -96,18 +111,19 @@ static void add_name_list(struct name_entry *head, enum envar_type type);
%type <node> expr compound_cond simple_cond
%type <range> range
%type <lrec> resource_limits
-%type <name_list> name_list
+%type <asgn> asgn
+%type <asgn_list> asgn_list
%type <strlist> strlist
%type <arg> arg
%type <arglist> arglist
%%
rcfile : PREFACE EOL content
- {
+ {
if (errors)
YYERROR;
}
- | BOGUS
+ | BOGUS
{
if (parse_old_rc())
YYERROR;
@@ -115,11 +131,11 @@ rcfile : PREFACE EOL content
;
content : /* empty */
- | rulelist
- ;
+ | rulelist
+ ;
rulelist : rule
- | rulelist rule
+ | rulelist rule
;
rule : rulehdr rulebody
@@ -183,10 +199,10 @@ rulehdr : RULE ruleid EOL
;
ruleid : /* empty */
- {
+ {
$$ = NULL;
}
- | string
+ | string
;
rulebody : stmt
@@ -202,8 +218,8 @@ stmt : match_stmt EOL
| include_stmt EOL
| flowctl_stmt EOL
| attrib_stmt EOL
- | error { skiptoeol(); } EOL
- {
+ | error { skiptoeol(); } EOL
+ {
restorenormal();
yyerrok;
yyclearin;
@@ -356,17 +372,17 @@ regex : string
/* ******************
Set statement
****************** */
-set_stmt : SET index value
+set_stmt : SET index '=' value
{
struct transform_node *node;
node = new_transform_node(current_rule, transform_set);
node->target.type = target_arg;
node->target.v.arg = $2;
- node->v.xf.pattern = $3;
+ node->v.xf.pattern = $4;
node->v.xf.trans = NULL;
}
- | SET index '~' value
+ | SET index XF value
{
struct transform_node *node;
@@ -376,17 +392,17 @@ set_stmt : SET index value
node->v.xf.pattern = NULL;
node->v.xf.trans = compile_transform_expr($4, re_flags);
}
- | SET index string '~' value
+ | SET index '=' string '~' value
{
struct transform_node *node;
node = new_transform_node(current_rule, transform_set);
node->target.type = target_arg;
node->target.v.arg = $2;
- node->v.xf.pattern = $3;
- node->v.xf.trans = compile_transform_expr($5, re_flags);
+ node->v.xf.pattern = $4;
+ node->v.xf.trans = compile_transform_expr($6, re_flags);
}
- | SET IDENT value
+ | SET IDENT '=' value
{
struct transform_node *node;
@@ -401,10 +417,10 @@ set_stmt : SET index value
node->target.type = target_var;
node->target.v.name = $2;
}
- node->v.xf.pattern = $3;
+ node->v.xf.pattern = $4;
node->v.xf.trans = NULL;
}
- | SET IDENT '~' value
+ | SET IDENT XF value
{
struct transform_node *node;
@@ -422,7 +438,7 @@ set_stmt : SET index value
node->v.xf.pattern = NULL;
node->v.xf.trans = compile_transform_expr($4, re_flags);
}
- | SET IDENT string '~' value
+ | SET IDENT '=' string '~' value
{
struct transform_node *node;
@@ -437,8 +453,8 @@ set_stmt : SET index value
node->target.type = target_var;
node->target.v.name = $2;
}
- node->v.xf.pattern = $3;
- node->v.xf.trans = compile_transform_expr($5, re_flags);
+ node->v.xf.pattern = $4;
+ node->v.xf.trans = compile_transform_expr($6, re_flags);
}
| UNSET IDENT
{
@@ -626,37 +642,47 @@ environ_stmt: CLRENV
{
current_rule->clrenv = 1;
}
- | SETENV IDENT string
+ | SETENV IDENT '=' string
{
new_envar(current_rule,
$2, strlen($2),
- $3, strlen($3),
+ $4, strlen($4),
envar_set);
}
- | UNSETENV name_list
+ | UNSETENV asgn_list
{
- add_name_list($2.head, envar_unset);
+ add_asgn_list($2.head, envar_unset);
}
- | KEEPENV name_list
+ | KEEPENV asgn_list
{
- add_name_list($2.head, envar_keep);
+ add_asgn_list($2.head, envar_keep);
}
;
-name_list : IDENT
+asgn_list : asgn
{
- struct name_entry *np = xmalloc(sizeof(*np));
- np->next = NULL;
- np->name = $1;
- $$.head = $$.tail = np;
+ $$.head = $$.tail = $1;
}
- | name_list IDENT
+ | asgn_list asgn
{
- struct name_entry *np = xmalloc(sizeof(*np));
- np->next = NULL;
- np->name = $2;
- LIST_APPEND(np, $1.head, $1.tail);
- $$ = $1;
+ LIST_APPEND($2, $1.head, $1.tail);
+ $$ = $1;
+ }
+ ;
+
+asgn : IDENT
+ {
+ $$ = xmalloc(sizeof(*$$));
+ $$->next = NULL;
+ $$->name = $1;
+ $$->value = NULL;
+ }
+ | IDENT '=' value
+ {
+ $$ = xmalloc(sizeof(*$$));
+ $$->next = NULL;
+ $$->name = $1;
+ $$->value = $3;
}
;
@@ -759,12 +785,12 @@ new_envar(struct rush_rule *rule,
}
static void
-add_name_list(struct name_entry *head, enum envar_type type)
+add_asgn_list(struct asgn *head, enum envar_type type)
{
for (; head; head = head->next) {
new_envar(current_rule,
head->name, strlen(head->name),
- NULL, 0,
+ head->value, head->value ? strlen(head->value) : 0,
type);
free(head->name);
}
diff --git a/src/cflex.l b/src/cflex.l
index a6f03c2..8d57f5b 100644
--- a/src/cflex.l
+++ b/src/cflex.l
@@ -171,7 +171,7 @@ rush[ \t]+2\.0[ \t]*$ {
return tok(IDENT);
}
}
-. { straychar(yytext[0]); skiptoeol(); }
+. return yytext[0];
}
<ARGS,INMATCH>{
@@ -180,7 +180,7 @@ rush[ \t]+2\.0[ \t]*$ {
return tok(NUMBER); }
[A-Za-z_][A-Za-z0-9_-]* { yylval.str = xstrdup(yytext);
return tok(IDENT); }
-[A-Za-z_+-][A-Za-z0-9_-]* { yylval.str = xstrdup(yytext);
+[A-Za-z_/+-][A-Za-z0-9_/+-]* { yylval.str = xstrdup(yytext);
return tok(STRING); }
\$[A-Za-z_][A-Za-z_0-9-]* { yylval.str = xstrdup(yytext);
return tok(STRING); }
@@ -233,7 +233,17 @@ rush[ \t]+2\.0[ \t]*$ {
strtoul(yytext + yyleng - 2,
NULL, 16));
pushstart(QSTR); }
-"~"|"("|")"|"["|"]" return tok(yytext[0]);
+\"[^\\\"\n]*\\. { struct cfloc loc;
+ loc.beg = loc.end = curloc.end;
+ loc.beg.column -= 2;
+ cferror(&loc,
+ _("unrecognized escape \\%c"),
+ yytext[yyleng - 1]);
+ stringbuf_init(&sb);
+ stringbuf_add_array(&sb, yytext + 1, yyleng - 1);
+ pushstart(QSTR); }
+"=~" return tok(XF);
+. return yytext[0];
}
<QSTR>{
@@ -261,8 +271,17 @@ rush[ \t]+2\.0[ \t]*$ {
stringbuf_add_char(&sb,
strtoul(yytext + yyleng - 2,
NULL, 16)); }
+[^\\\"\n]*\\. { struct cfloc loc;
+ loc.beg = loc.end = curloc.end;
+ loc.beg.column -= 2;
+ cferror(&loc,
+ _("unrecognized escape \\%c"),
+ yytext + yyleng - 1);
+ stringbuf_init(&sb);
+ stringbuf_add_array(&sb, yytext, yyleng); }
\n { advance_line(1);
yyerror("unescaped newline in quoted string"); }
+. { straychar(yytext[0]); }
}
<VAR>{
@@ -302,11 +321,10 @@ rush[ \t]+2\.0[ \t]*$ {
strtoul(yytext + yyleng - 2,
NULL, 16));
pushstart(QSTR); }
-[^}\"\$%]+ { stringbuf_add_array(&sb, yytext, yyleng); }
+[^}\"\$%]+ { stringbuf_add_array(&sb, yytext, yyleng); }
+. { straychar(yytext[0]);
+ stringbuf_add_char(&sb, yytext[0]); }
}
-
-<INMATCH,ARGS,VAR,QSTR>. { straychar(yytext[0]);
- return tok(BOGUS); }
%%
void
straychar(int c)
diff --git a/src/map.c b/src/map.c
index dff68e2..d332bb5 100644
--- a/src/map.c
+++ b/src/map.c
@@ -16,6 +16,9 @@
#include <rush.h>
+/* Set to 1 if expansion of undefined variables is allowed */
+int expand_undefined;
+
static inline int
d2n(int d)
{
@@ -252,7 +255,7 @@ rush_expand_string(const char *string, struct rush_request *req)
struct wordsplit ws;
int wsflags = WRDSF_NOSPLIT
| WRDSF_NOCMD
- | WRDSF_UNDEF
+ | (expand_undefined ? 0: WRDSF_UNDEF)
| WRDSF_GETVAR
| WRDSF_CLOSURE;
char *result;
diff --git a/tests/Makefile.am b/tests/Makefile.am
index c0877e8..c61ddd9 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -63,6 +63,15 @@ TESTSUITE_AT = \
interactive.at\
fallthrough.at\
error.at\
+ clrenv.at\
+ unsetenv.at\
+ keepenv.at\
+ setenv.at\
+ backref.at\
+ setvar.at\
+ unsetvar.at\
+ undef.at\
+ regexp.at\
legacy/argc.at\
legacy/backref.at\
legacy/chdir.at\
diff --git a/tests/backref.at b/tests/backref.at
new file mode 100644
index 0000000..a707d5d
--- /dev/null
+++ b/tests/backref.at
@@ -0,0 +1,43 @@
+# This file is part of GNU Rush.
+# Copyright (C) 2019 Sergey Poznyakoff
+#
+# GNU Rush 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.
+#
+# GNU Rush 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 GNU Rush. If not, see <http://www.gnu.org/licenses/>.
+
+AT_SETUP([Back-reference expansion])
+AT_KEYWORDS([backref])
+
+AT_RUSH_TEST([
+rush 2.0
+rule chdir
+ match \$command ~ "^cd \"(.+)\" && (runcom .*)$"
+ chdir %1
+ set command = %2
+ fall-through
+
+rule runcom
+ match \$0 == runcom
+ set [0] = "./bin/runcom"
+],
+[cmdline,home_dir],
+[cd "$PWD" && runcom test],
+[0],
+[{
+ "cmdline":"./bin/runcom test",
+ "home_dir":"$TESTDIR"
+}
+],
+[])
+
+AT_CLEANUP
+
diff --git a/tests/clrenv.at b/tests/clrenv.at
new file mode 100644
index 0000000..80c8acc
--- /dev/null
+++ b/tests/clrenv.at
@@ -0,0 +1,34 @@
+# This file is part of GNU Rush.
+# Copyright (C) 2016-2019 Sergey Poznyakoff
+#
+# GNU Rush 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.
+#
+# GNU Rush 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 GNU Rush. If not, see <http://www.gnu.org/licenses/>.
+
+AT_SETUP([clrenv])
+AT_KEYWORDS([clrenv])
+
+AT_RUSH_TEST([
+rush 2.0
+rule
+ clrenv
+],
+[environ],
+[command],
+[0],
+[{
+ "environ":[[]]
+}
+],
+[])
+
+AT_CLEANUP
diff --git a/tests/fallthrough.at b/tests/fallthrough.at
index 787bcc1..e7f1aab 100644
--- a/tests/fallthrough.at
+++ b/tests/fallthrough.at
@@ -20,11 +20,11 @@ AT_KEYWORDS([fallthrough fall-through])
AT_RUSH_TEST([
rush 2.0
rule
- set [0] newcommand
+ set [0] = newcommand
fall-through
rule
- set [1] list
+ set [1] = list
],
[cmdline,argv],
[command],
@@ -46,7 +46,7 @@ rule
fall-through
rule
- set [0] newcommand
+ set [0] = newcommand
interactive true
],
[cmdline,interactive,home_dir],
diff --git a/tests/keepenv.at b/tests/keepenv.at
new file mode 100644
index 0000000..a3e1c4a
--- /dev/null
+++ b/tests/keepenv.at
@@ -0,0 +1,40 @@
+# This file is part of GNU Rush.
+# Copyright (C) 2016-2019 Sergey Poznyakoff
+#
+# GNU Rush 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.
+#
+# GNU Rush 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 GNU Rush. If not, see <http://www.gnu.org/licenses/>.
+
+AT_SETUP([keepenv])
+AT_KEYWORDS([keepenv])
+
+m4_pushdef([RUSH_ENVIRON],[-i HOME=$PWD USER=$MY_USER LOGIN=NO_$MY_USER PATH=$PATH])
+AT_RUSH_TEST([
+rush 2.0
+rule
+ clrenv
+ keepenv HOME USER
+],
+[environ],
+[command],
+[0],
+[{
+ "environ":[[
+ "HOME=$TESTDIR",
+ "USER=$MY_USER"
+ ]]
+}
+],
+[])
+m4_popdef([RUSH_ENVIRON])
+
+AT_CLEANUP
diff --git a/tests/regexp.at b/tests/regexp.at
new file mode 100644
index 0000000..1708471
--- /dev/null
+++ b/tests/regexp.at
@@ -0,0 +1,88 @@
+# This file is part of GNU Rush.
+# Copyright (C) 2019 Sergey Poznyakoff
+#
+# GNU Rush 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.
+#
+# GNU Rush 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 GNU Rush. If not, see <http://www.gnu.org/licenses/>.
+
+AT_SETUP([regexp options])
+AT_KEYWORDS([match regexp])
+
+AT_RUSH_TEST([
+rush 2.0
+rule
+ match \$command ~ "fo+\$"
+],
+[cmdline,argv],
+[ls foo],
+[0],
+[{
+ "cmdline":"ls foo",
+ "argv":[[
+ "ls",
+ "foo"
+ ]]
+}
+],
+[])
+
+AT_RUSH_TEST([
+rush 2.0
+global
+ regexp basic
+rule
+ match \$command ~ "fo+\$"
+],
+[cmdline,argv],
+
+[ls foo],
+[1],
+[],
+[rush: Error: no matching rule for "ls foo", user $MY_USER
+],
+
+[ls fo+],
+[0],
+[{
+ "cmdline":"ls fo+",
+ "argv":[[
+ "ls",
+ "fo+"
+ ]]
+}
+],
+[])
+
+AT_RUSH_TEST([
+rush 2.0
+global
+ regexp basic ignore-case
+rule
+ match \$command ~ "fo+\$"
+],
+[cmdline,argv],
+
+[ls Fo+],
+[0],
+[{
+ "cmdline":"ls Fo+",
+ "argv":[[
+ "ls",
+ "Fo+"
+ ]]
+}
+],
+[])
+
+
+AT_CLEANUP
+
diff --git a/tests/set.at b/tests/set.at
index 668945d..599f73d 100644
--- a/tests/set.at
+++ b/tests/set.at
@@ -20,7 +20,7 @@ AT_KEYWORDS([set])
AT_RUSH_TEST([
rush 2.0
rule
- set command "ls /"
+ set command = "ls /"
],
[cmdline,argv,prog],
[echo],
@@ -39,7 +39,7 @@ rule
AT_RUSH_TEST([
rush 2.0
rule
- set [0] "/usr/bin/\$0"
+ set [0] = "/usr/bin/\$0"
],
[cmdline,argv,prog],
[ls /],
@@ -58,7 +58,7 @@ rule
AT_RUSH_TEST([
rush 2.0
rule
- set [1] "/chroot\${1}"
+ set [1] = "/chroot\${1}"
],
[cmdline,argv,prog],
[ls /],
@@ -77,7 +77,7 @@ rule
AT_RUSH_TEST([
rush 2.0
rule
- set program "/usr/bin/ls"
+ set program = "/usr/bin/ls"
],
[cmdline,argv,prog],
[ls /],
@@ -96,7 +96,7 @@ rule
AT_RUSH_TEST([
rush 2.0
rule
- set [-1] "/tmp"
+ set [-1] = "/tmp"
],
[cmdline,argv,prog],
[ls /],
diff --git a/tests/setenv.at b/tests/setenv.at
new file mode 100644
index 0000000..66ad12b
--- /dev/null
+++ b/tests/setenv.at
@@ -0,0 +1,130 @@
+# This file is part of GNU Rush.
+# Copyright (C) 2016-2019 Sergey Poznyakoff
+#
+# GNU Rush 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.
+#
+# GNU Rush 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 GNU Rush. If not, see <http://www.gnu.org/licenses/>.
+
+AT_SETUP([setenv])
+AT_KEYWORDS([setenv])
+
+m4_pushdef([RUSH_ENVIRON],[-i HOME=$PWD USER=$MY_USER])
+AT_RUSH_TEST([
+rush 2.0
+rule
+ setenv NEWVAR=foo
+],
+[environ],
+[command],
+[0],
+[{
+ "environ":[[
+ "HOME=$TESTDIR",
+ "NEWVAR=foo",
+ "USER=$MY_USER"
+ ]]
+}
+],
+[])
+m4_popdef([RUSH_ENVIRON])
+
+m4_pushdef([RUSH_ENVIRON],[-i])
+AT_RUSH_TEST([
+rush 2.0
+rule
+ setenv MYPATH="\${MYPATH:-}\${MYPATH+:}/usr/local/bin"
+],
+[environ],
+[command],
+[0],
+[{
+ "environ":[[
+ "MYPATH=/usr/local/bin"
+ ]]
+}
+],
+[])
+m4_popdef([RUSH_ENVIRON])
+
+m4_pushdef([RUSH_ENVIRON],[-i MYPATH=/bin:/usr/bin])
+AT_RUSH_TEST([
+rush 2.0
+rule
+ setenv MYPATH="\${MYPATH:-}\${MYPATH+:}/usr/local/bin"
+],
+[environ],
+[command],
+[0],
+[{
+ "environ":[[
+ "MYPATH=/bin:/usr/bin:/usr/local/bin"
+ ]]
+}
+],
+[])
+m4_popdef([RUSH_ENVIRON])
+
+m4_pushdef([RUSH_ENVIRON],[-i])
+AT_RUSH_TEST([
+rush 2.0
+rule
+ setenv MYPATH="/usr/local/bin\${MYPATH+:}\${MYPATH:-}"
+],
+[environ],
+[command],
+[0],
+[{
+ "environ":[[
+ "MYPATH=/usr/local/bin"
+ ]]
+}
+],
+[])
+m4_popdef([RUSH_ENVIRON])
+
+m4_pushdef([RUSH_ENVIRON],[-i MYPATH=/bin:/usr/bin])
+AT_RUSH_TEST([
+rush 2.0
+rule
+ setenv MYPATH="/usr/local/bin\${MYPATH+:}\$MYPATH"
+],
+[environ],
+[command],
+[0],
+[{
+ "environ":[[
+ "MYPATH=/usr/local/bin:/bin:/usr/bin"
+ ]]
+}
+],
+[])
+m4_popdef([RUSH_ENVIRON])
+
+m4_pushdef([RUSH_ENVIRON],[-i MYPATH=/bin:/usr/bin])
+AT_RUSH_TEST([
+rush 2.0
+rule
+ setenv MYPATH="/usr/local/bin:\$MYPATH"
+],
+[environ],
+[command],
+[0],
+[{
+ "environ":[[
+ "MYPATH=/usr/local/bin:/bin:/usr/bin"
+ ]]
+}
+],
+[])
+m4_popdef([RUSH_ENVIRON])
+
+AT_CLEANUP
diff --git a/tests/setvar.at b/tests/setvar.at
new file mode 100644
index 0000000..3017f63
--- /dev/null
+++ b/tests/setvar.at
@@ -0,0 +1,43 @@
+# This file is part of GNU Rush.
+# Copyright (C) 2019 Sergey Poznyakoff
+#
+# GNU Rush 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.
+#
+# GNU Rush 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 GNU Rush. If not, see <http://www.gnu.org/licenses/>.
+
+AT_SETUP([setvar])
+AT_KEYWORDS([setvar])
+AT_RUSH_TEST([
+rush 2.0
+rule first
+ set home = "$PWD"
+ set count = 1
+ set FOO = bar
+ fall-through
+
+rule last
+ set command = "\$FOO \$count"
+],
+[cmdline,vars],
+[ls],
+[0],
+[{
+ "cmdline":"bar 1",
+ "vars":{
+ "FOO":"bar",
+ "count":"1",
+ "home":"$TESTDIR"
+ }
+}
+],
+[])
+AT_CLEANUP
diff --git a/tests/testsuite.at b/tests/testsuite.at
index 61b348c..e10d4b8 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -56,12 +56,16 @@ AT_INIT
AT_TESTED([rush])
m4_include([null.at])
+m4_include([setvar.at])
+m4_include([unsetvar.at])
+m4_include([undef.at])
AT_BANNER([Simple Conditions])
m4_include([argc.at])
m4_include([command.at])
m4_include([matcharg.at])
m4_include([matchprog.at])
+m4_include([regexp.at])
m4_include([uid.at])
m4_include([user.at])
m4_include([in.at])
@@ -85,12 +89,21 @@ m4_include([newgrp.at])
m4_include([chdir.at])
m4_include([interactive.at])
-AT_BANNER([Flow control])
+AT_BANNER([Environment])
+m4_include([clrenv.at])
+m4_include([unsetenv.at])
+m4_include([keepenv.at])
+m4_include([setenv.at])
-AT_BANNER([Legacy configuration])
+AT_BANNER([Features])
+m4_include([backref.at])
+
+AT_BANNER([Flow control])
m4_include([fallthrough.at])
m4_include([error.at])
+AT_BANNER([Legacy configuration])
+
dnl AT_BANNER([Conditionals])
m4_include([legacy/argc.at])
m4_include([legacy/command.at])
diff --git a/tests/transform.at b/tests/transform.at
index bbd0fb1..ee56448 100644
--- a/tests/transform.at
+++ b/tests/transform.at
@@ -20,7 +20,7 @@ AT_KEYWORDS([transform])
AT_RUSH_TEST([
rush 2.0
rule
- set command ~ "s/^[^[:space:]]+/& -t/"
+ set command =~ "s/^[^[:space:]]+/& -t/"
],
[cmdline,argv,prog],
[svnserve],
@@ -39,7 +39,7 @@ rule
AT_RUSH_TEST([
rush 2.0
rule
- set command "\${command} end" ~ "s/[[:space:]]+-[^[:space:]]+//g"
+ set command = "\${command} end" ~ "s/[[:space:]]+-[^[:space:]]+//g"
],
[cmdline,argv,prog],
[echo -c -t foo -n bar],
@@ -60,7 +60,7 @@ rule
AT_RUSH_TEST([
rush 2.0
rule
- set [0] ~ "s|^[^/]|/usr/bin/&|"
+ set [0] =~ "s|^[^/]|/usr/bin/&|"
],
[cmdline,argv,prog],
[echo foo],
@@ -92,7 +92,7 @@ rule
AT_RUSH_TEST([
rush 2.0
rule
- set [0] \$program ~ "s,.*/,-,"
+ set [0] = \$program ~ "s,.*/,-,"
],
[cmdline,argv,prog],
[/bin/sh],
diff --git a/tests/undef.at b/tests/undef.at
new file mode 100644
index 0000000..015dd52
--- /dev/null
+++ b/tests/undef.at
@@ -0,0 +1,65 @@
+# This file is part of GNU Rush.
+# Copyright (C) 2019 Sergey Poznyakoff
+#
+# GNU Rush 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.
+#
+# GNU Rush 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 GNU Rush. If not, see <http://www.gnu.org/licenses/>.
+
+AT_SETUP([expanding undefined variables])
+AT_KEYWORDS([undef])
+
+m4_pushdef([RUSH_ENVIRON],[-i])
+AT_RUSH_TEST([
+rush 2.0
+rule first
+ set command = \$COMMAND
+],
+[cmdline],
+[ls],
+[1],
+[],
+[rush: Error: undefined variable
+])
+
+AT_RUSH_TEST([
+rush 2.0
+rule first
+ set command = \${COMMAND:-\$command}
+],
+[cmdline],
+[ls],
+[0],
+[{
+ "cmdline":"ls"
+}
+],
+[])
+
+AT_RUSH_TEST([
+rush 2.0
+global
+ expand-undefined true
+
+rule first
+ set command = \$COMMAND
+],
+[cmdline],
+[ls],
+[0],
+[{
+ "cmdline":""
+}
+],
+[])
+m4_popdef([RUSH_ENVIRON])
+
+AT_CLEANUP
<