mirror of
https://github.com/fish-shell/fish-shell
synced 2025-01-13 05:28:49 +00:00
Merge branch 'master' into ast
Conflicts: function.cpp parser.cpp parser.h
This commit is contained in:
commit
ed70195c7e
29 changed files with 398 additions and 231 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -6,6 +6,7 @@ Makefile
|
|||
autom4te.cache/
|
||||
build/
|
||||
command_list.txt
|
||||
command_list_toc.txt
|
||||
confdefs.h
|
||||
config.h
|
||||
config.h.in
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
#
|
||||
|
||||
#
|
||||
|
@ -160,11 +160,6 @@ HDR_FILES := $(HDR_FILES_SRC:.hdr.in=.hdr)
|
|||
# Use a pattern rule so that Make knows to only issue one invocation
|
||||
# per http://www.gnu.org/software/make/manual/make.html#Pattern-Intro
|
||||
|
||||
# Internalized scripts are currently disabled.
|
||||
# For now, we just generate empty arrays.
|
||||
# To generate them again, you would run this:
|
||||
# ./internalize_scripts.py share/functions/*.fish share/completions/*.fish
|
||||
|
||||
|
||||
#
|
||||
# Files containing documentation for external commands.
|
||||
|
@ -775,7 +770,6 @@ distclean: clean
|
|||
|
||||
clean:
|
||||
rm -f *.o doc.h doc.tmp doc_src/*.doxygen doc_src/*.cpp doc_src/*.o doc_src/commands.hdr
|
||||
rm -f $(GENERATED_INTERN_SCRIPT_FILES)
|
||||
rm -f tests/tmp.err tests/tmp.out tests/tmp.status tests/foo.txt
|
||||
rm -f $(PROGRAMS) fish_tests key_reader
|
||||
rm -f command_list.txt command_list_toc.txt toc.txt
|
||||
|
|
160
builtin.cpp
160
builtin.cpp
|
@ -832,7 +832,8 @@ static int builtin_block(parser_t &parser, wchar_t **argv)
|
|||
}
|
||||
else
|
||||
{
|
||||
block_t *block=parser.current_block;
|
||||
size_t block_idx = 0;
|
||||
block_t *block = parser.block_at_index(block_idx);
|
||||
|
||||
event_blockage_t eb = {};
|
||||
eb.typemask = type;
|
||||
|
@ -841,20 +842,24 @@ static int builtin_block(parser_t &parser, wchar_t **argv)
|
|||
{
|
||||
case LOCAL:
|
||||
{
|
||||
if (!block->outer)
|
||||
block=0;
|
||||
// If this is the outermost block, then we're global
|
||||
if (block_idx + 1 >= parser.block_count())
|
||||
{
|
||||
block = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GLOBAL:
|
||||
{
|
||||
block=0;
|
||||
block=NULL;
|
||||
}
|
||||
case UNSET:
|
||||
{
|
||||
while (block &&
|
||||
block->type() != FUNCTION_CALL &&
|
||||
block->type() != FUNCTION_CALL_NO_SHADOW)
|
||||
block = block->outer;
|
||||
while (block != NULL && block->type() != FUNCTION_CALL && block->type() != FUNCTION_CALL_NO_SHADOW)
|
||||
{
|
||||
// Set it in function scope
|
||||
block = parser.block_at_index(++block_idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (block)
|
||||
|
@ -1864,18 +1869,21 @@ static int builtin_function(parser_t &parser, wchar_t **argv)
|
|||
|
||||
if (is_subshell)
|
||||
{
|
||||
block_t *b = parser.current_block;
|
||||
|
||||
while (b && (b->type() != SUBST))
|
||||
b = b->outer;
|
||||
|
||||
if (b)
|
||||
size_t block_idx = 0;
|
||||
|
||||
/* Find the outermost substitution block */
|
||||
for (block_idx = 0; ; block_idx++)
|
||||
{
|
||||
b=b->outer;
|
||||
const block_t *b = parser.block_at_index(block_idx);
|
||||
if (b == NULL || b->type() == SUBST)
|
||||
break;
|
||||
}
|
||||
if (b->job)
|
||||
|
||||
/* Go one step beyond that, to get to the caller */
|
||||
const block_t *caller_block = parser.block_at_index(block_idx + 1);
|
||||
if (caller_block != NULL && caller_block->job != NULL)
|
||||
{
|
||||
job_id = b->job->job_id;
|
||||
job_id = caller_block->job->job_id;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2059,8 +2067,8 @@ static int builtin_function(parser_t &parser, wchar_t **argv)
|
|||
}
|
||||
}
|
||||
|
||||
parser.current_block->tok_pos = parser.get_pos();
|
||||
parser.current_block->skip = 1;
|
||||
parser.current_block()->tok_pos = parser.get_pos();
|
||||
parser.current_block()->skip = 1;
|
||||
|
||||
return STATUS_BUILTIN_OK;
|
||||
}
|
||||
|
@ -2713,7 +2721,7 @@ static int builtin_status(parser_t &parser, wchar_t **argv)
|
|||
|
||||
case STACK_TRACE:
|
||||
{
|
||||
parser.stack_trace(parser.current_block, stdout_buffer);
|
||||
parser.stack_trace(0, stdout_buffer);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -2728,7 +2736,7 @@ static int builtin_status(parser_t &parser, wchar_t **argv)
|
|||
job_control_mode==JOB_CONTROL_INTERACTIVE?_(L"Only on interactive jobs"):
|
||||
(job_control_mode==JOB_CONTROL_NONE ? _(L"Never") : _(L"Always")));
|
||||
|
||||
parser.stack_trace(parser.current_block, stdout_buffer);
|
||||
parser.stack_trace(0, stdout_buffer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -3400,19 +3408,19 @@ static int builtin_for(parser_t &parser, wchar_t **argv)
|
|||
}
|
||||
else
|
||||
{
|
||||
parser.current_block->skip=1;
|
||||
parser.current_block()->skip=1;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
The begin builtin. Creates a nex block.
|
||||
The begin builtin. Creates a new block.
|
||||
*/
|
||||
static int builtin_begin(parser_t &parser, wchar_t **argv)
|
||||
{
|
||||
parser.push_block(new scope_block_t(BEGIN));
|
||||
parser.current_block->tok_pos = parser.get_pos();
|
||||
parser.current_block()->tok_pos = parser.get_pos();
|
||||
return proc_get_last_status();
|
||||
}
|
||||
|
||||
|
@ -3424,7 +3432,7 @@ static int builtin_begin(parser_t &parser, wchar_t **argv)
|
|||
*/
|
||||
static int builtin_end(parser_t &parser, wchar_t **argv)
|
||||
{
|
||||
if (!parser.current_block->outer)
|
||||
if (! parser.block_at_index(1))
|
||||
{
|
||||
append_format(stderr_buffer,
|
||||
_(L"%ls: Not inside of block\n"),
|
||||
|
@ -3442,7 +3450,8 @@ static int builtin_end(parser_t &parser, wchar_t **argv)
|
|||
*/
|
||||
bool kill_block = true;
|
||||
|
||||
switch (parser.current_block->type())
|
||||
block_t * const current_block = parser.current_block();
|
||||
switch (current_block->type())
|
||||
{
|
||||
case WHILE:
|
||||
{
|
||||
|
@ -3450,13 +3459,13 @@ static int builtin_end(parser_t &parser, wchar_t **argv)
|
|||
If this is a while loop, we rewind the loop unless
|
||||
it's the last lap, in which case we continue.
|
||||
*/
|
||||
if (!(parser.current_block->skip && (parser.current_block->loop_status != LOOP_CONTINUE)))
|
||||
if (!(current_block->skip && (current_block->loop_status != LOOP_CONTINUE)))
|
||||
{
|
||||
parser.current_block->loop_status = LOOP_NORMAL;
|
||||
parser.current_block->skip = 0;
|
||||
current_block->loop_status = LOOP_NORMAL;
|
||||
current_block->skip = 0;
|
||||
kill_block = false;
|
||||
parser.set_pos(parser.current_block->tok_pos);
|
||||
while_block_t *blk = static_cast<while_block_t *>(parser.current_block);
|
||||
parser.set_pos(current_block->tok_pos);
|
||||
while_block_t *blk = static_cast<while_block_t *>(current_block);
|
||||
blk->status = WHILE_TEST_AGAIN;
|
||||
}
|
||||
|
||||
|
@ -3479,9 +3488,9 @@ static int builtin_end(parser_t &parser, wchar_t **argv)
|
|||
/*
|
||||
set loop variable to next element, and rewind to the beginning of the block.
|
||||
*/
|
||||
for_block_t *fb = static_cast<for_block_t *>(parser.current_block);
|
||||
for_block_t *fb = static_cast<for_block_t *>(current_block);
|
||||
wcstring_list_t &for_vars = fb->sequence;
|
||||
if (parser.current_block->loop_status == LOOP_BREAK)
|
||||
if (current_block->loop_status == LOOP_BREAK)
|
||||
{
|
||||
for_vars.clear();
|
||||
}
|
||||
|
@ -3492,18 +3501,18 @@ static int builtin_end(parser_t &parser, wchar_t **argv)
|
|||
for_vars.pop_back();
|
||||
const wcstring &for_variable = fb->variable;
|
||||
env_set(for_variable, val.c_str(), ENV_LOCAL);
|
||||
parser.current_block->loop_status = LOOP_NORMAL;
|
||||
parser.current_block->skip = 0;
|
||||
current_block->loop_status = LOOP_NORMAL;
|
||||
current_block->skip = 0;
|
||||
|
||||
kill_block = false;
|
||||
parser.set_pos(parser.current_block->tok_pos);
|
||||
parser.set_pos(current_block->tok_pos);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case FUNCTION_DEF:
|
||||
{
|
||||
function_def_block_t *fdb = static_cast<function_def_block_t *>(parser.current_block);
|
||||
function_def_block_t *fdb = static_cast<function_def_block_t *>(current_block);
|
||||
function_data_t &d = fdb->function_data;
|
||||
|
||||
if (d.name.empty())
|
||||
|
@ -3522,8 +3531,8 @@ static int builtin_end(parser_t &parser, wchar_t **argv)
|
|||
for the specified function
|
||||
*/
|
||||
|
||||
wchar_t *def = wcsndup(parser.get_buffer()+parser.current_block->tok_pos,
|
||||
parser.get_job_pos()-parser.current_block->tok_pos);
|
||||
wchar_t *def = wcsndup(parser.get_buffer()+current_block->tok_pos,
|
||||
parser.get_job_pos()-current_block->tok_pos);
|
||||
d.definition = def;
|
||||
|
||||
function_add(d, parser);
|
||||
|
@ -3556,9 +3565,9 @@ static int builtin_else(parser_t &parser, wchar_t **argv)
|
|||
{
|
||||
bool block_ok = false;
|
||||
if_block_t *if_block = NULL;
|
||||
if (parser.current_block != NULL && parser.current_block->type() == IF)
|
||||
if (parser.current_block() != NULL && parser.current_block()->type() == IF)
|
||||
{
|
||||
if_block = static_cast<if_block_t *>(parser.current_block);
|
||||
if_block = static_cast<if_block_t *>(parser.current_block());
|
||||
/* Ensure that we're past IF but not up to an ELSE */
|
||||
if (if_block->if_expr_evaluated && ! if_block->else_evaluated)
|
||||
{
|
||||
|
@ -3599,7 +3608,6 @@ static int builtin_break_continue(parser_t &parser, wchar_t **argv)
|
|||
int is_break = (wcscmp(argv[0],L"break")==0);
|
||||
int argc = builtin_count_args(argv);
|
||||
|
||||
block_t *b = parser.current_block;
|
||||
|
||||
if (argc != 1)
|
||||
{
|
||||
|
@ -3612,15 +3620,16 @@ static int builtin_break_continue(parser_t &parser, wchar_t **argv)
|
|||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
|
||||
|
||||
while ((b != 0) &&
|
||||
(b->type() != WHILE) &&
|
||||
(b->type() != FOR))
|
||||
/* Find the index of the enclosing for or while loop. Recall that incrementing loop_idx goes 'up' to outer blocks */
|
||||
size_t loop_idx;
|
||||
for (loop_idx = 0; loop_idx < parser.block_count(); loop_idx++)
|
||||
{
|
||||
b = b->outer;
|
||||
const block_t *b = parser.block_at_index(loop_idx);
|
||||
if (b->type() == WHILE || b->type() == FOR)
|
||||
break;
|
||||
}
|
||||
|
||||
if (b == 0)
|
||||
if (loop_idx >= parser.block_count())
|
||||
{
|
||||
append_format(stderr_buffer,
|
||||
_(L"%ls: Not inside of loop\n"),
|
||||
|
@ -3629,15 +3638,17 @@ static int builtin_break_continue(parser_t &parser, wchar_t **argv)
|
|||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
|
||||
b = parser.current_block;
|
||||
while ((b->type() != WHILE) &&
|
||||
(b->type() != FOR))
|
||||
/* Skip blocks interior to the loop */
|
||||
size_t block_idx = loop_idx;
|
||||
while (block_idx--)
|
||||
{
|
||||
b->skip=1;
|
||||
b = b->outer;
|
||||
parser.block_at_index(block_idx)->skip = true;
|
||||
}
|
||||
b->skip=1;
|
||||
b->loop_status = is_break?LOOP_BREAK:LOOP_CONTINUE;
|
||||
|
||||
/* Skip the loop itself */
|
||||
block_t *loop_block = parser.block_at_index(loop_idx);
|
||||
loop_block->skip = true;
|
||||
loop_block->loop_status = is_break ? LOOP_BREAK : LOOP_CONTINUE;
|
||||
return STATUS_BUILTIN_OK;
|
||||
}
|
||||
|
||||
|
@ -3666,8 +3677,6 @@ static int builtin_return(parser_t &parser, wchar_t **argv)
|
|||
int argc = builtin_count_args(argv);
|
||||
int status = proc_get_last_status();
|
||||
|
||||
block_t *b = parser.current_block;
|
||||
|
||||
switch (argc)
|
||||
{
|
||||
case 1:
|
||||
|
@ -3696,15 +3705,16 @@ static int builtin_return(parser_t &parser, wchar_t **argv)
|
|||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
|
||||
|
||||
while ((b != 0) &&
|
||||
(b->type() != FUNCTION_CALL &&
|
||||
b->type() != FUNCTION_CALL_NO_SHADOW))
|
||||
/* Find the function block */
|
||||
size_t function_block_idx;
|
||||
for (function_block_idx = 0; function_block_idx < parser.block_count(); function_block_idx++)
|
||||
{
|
||||
b = b->outer;
|
||||
const block_t *b = parser.block_at_index(function_block_idx);
|
||||
if (b->type() == FUNCTION_CALL || b->type() == FUNCTION_CALL_NO_SHADOW)
|
||||
break;
|
||||
}
|
||||
|
||||
if (b == 0)
|
||||
if (function_block_idx >= parser.block_count())
|
||||
{
|
||||
append_format(stderr_buffer,
|
||||
_(L"%ls: Not inside of function\n"),
|
||||
|
@ -3712,17 +3722,15 @@ static int builtin_return(parser_t &parser, wchar_t **argv)
|
|||
builtin_print_help(parser, argv[0], stderr_buffer);
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
|
||||
b = parser.current_block;
|
||||
while ((b->type() != FUNCTION_CALL &&
|
||||
b->type() != FUNCTION_CALL_NO_SHADOW))
|
||||
|
||||
/* Skip everything up to (and then including) the function block */
|
||||
for (size_t i=0; i < function_block_idx; i++)
|
||||
{
|
||||
block_t *b = parser.block_at_index(i);
|
||||
b->mark_as_fake();
|
||||
b->skip=1;
|
||||
b = b->outer;
|
||||
b->skip = true;
|
||||
}
|
||||
b->skip=1;
|
||||
|
||||
parser.block_at_index(function_block_idx)->skip = true;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -3749,7 +3757,7 @@ static int builtin_switch(parser_t &parser, wchar_t **argv)
|
|||
else
|
||||
{
|
||||
parser.push_block(new switch_block_t(argv[1]));
|
||||
parser.current_block->skip=1;
|
||||
parser.current_block()->skip=1;
|
||||
res = proc_get_last_status();
|
||||
}
|
||||
|
||||
|
@ -3766,7 +3774,7 @@ static int builtin_case(parser_t &parser, wchar_t **argv)
|
|||
int i;
|
||||
wchar_t *unescaped=0;
|
||||
|
||||
if (parser.current_block->type() != SWITCH)
|
||||
if (parser.current_block()->type() != SWITCH)
|
||||
{
|
||||
append_format(stderr_buffer,
|
||||
_(L"%ls: 'case' command while not in switch block\n"),
|
||||
|
@ -3775,8 +3783,8 @@ static int builtin_case(parser_t &parser, wchar_t **argv)
|
|||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
|
||||
parser.current_block->skip = 1;
|
||||
switch_block_t *sb = static_cast<switch_block_t *>(parser.current_block);
|
||||
parser.current_block()->skip = 1;
|
||||
switch_block_t *sb = static_cast<switch_block_t *>(parser.current_block());
|
||||
if (sb->switch_taken)
|
||||
{
|
||||
return proc_get_last_status();
|
||||
|
@ -3793,7 +3801,7 @@ static int builtin_case(parser_t &parser, wchar_t **argv)
|
|||
|
||||
if (match)
|
||||
{
|
||||
parser.current_block->skip = 0;
|
||||
parser.current_block()->skip = 0;
|
||||
sb->switch_taken = true;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
\subsection eval-example Example
|
||||
|
||||
The folloing code will call the ls command. Note that \c fish does not
|
||||
The following code will call the ls command. Note that \c fish does not
|
||||
support the use of environment variables as direct commands; \c eval can
|
||||
be used to work around this.
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ Version 2, June 1991
|
|||
|
||||
<PRE>
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
@ -995,7 +995,7 @@ Version 2, June 1991
|
|||
|
||||
<PRE>
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
|
|
@ -144,12 +144,15 @@ static int event_match(const event_t &classv, const event_t &instance)
|
|||
*/
|
||||
static int event_is_blocked(const event_t &e)
|
||||
{
|
||||
block_t *block;
|
||||
const block_t *block;
|
||||
parser_t &parser = parser_t::principal_parser();
|
||||
for (block = parser.current_block; block; block = block->outer)
|
||||
|
||||
size_t idx = 0;
|
||||
while ((block = parser.block_at_index(idx++)))
|
||||
{
|
||||
if (event_block_list_blocks_type(block->event_blocks, e.type))
|
||||
return true;
|
||||
|
||||
}
|
||||
return event_block_list_blocks_type(parser.global_event_blocks, e.type);
|
||||
}
|
||||
|
|
3
exec.cpp
3
exec.cpp
|
@ -580,7 +580,8 @@ static void exec_no_exec(parser_t &parser, const job_t *job)
|
|||
}
|
||||
else if (builtin_name == L"end")
|
||||
{
|
||||
if (parser.current_block == NULL || parser.current_block->type() == TOP)
|
||||
const block_t *block = parser.current_block();
|
||||
if (block == NULL || block->type() == TOP)
|
||||
{
|
||||
fprintf(stderr, "Warning: not popping the root block\n");
|
||||
}
|
||||
|
|
2
fish.cpp
2
fish.cpp
|
@ -12,7 +12,7 @@ GNU General Public License for more details.
|
|||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ GNU General Public License for more details.
|
|||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
|
||||
|
|
|
@ -189,11 +189,11 @@ void function_add(const function_data_t &data, const parser_t &parser)
|
|||
|
||||
/* Create and store a new function */
|
||||
const wchar_t *filename = reader_current_filename();
|
||||
|
||||
|
||||
int def_offset = -1;
|
||||
if (parser.current_block != NULL)
|
||||
if (parser.current_block() != NULL)
|
||||
{
|
||||
def_offset = parser.line_number_of_character_at_offset(parser.current_block->tok_pos);
|
||||
def_offset = parser.line_number_of_character_at_offset(parser.current_block()->tok_pos);
|
||||
}
|
||||
|
||||
const function_map_t::value_type new_pair(data.name, function_info_t(data, filename, def_offset, is_autoload));
|
||||
|
|
198
parser.cpp
198
parser.cpp
|
@ -328,7 +328,6 @@ parser_t::parser_t(enum parser_type_t type, bool errors) :
|
|||
current_tokenizer_pos(0),
|
||||
job_start_pos(0),
|
||||
eval_level(-1),
|
||||
current_block(NULL),
|
||||
block_io(shared_ptr<io_data_t>())
|
||||
{
|
||||
}
|
||||
|
@ -354,39 +353,36 @@ void parser_t::skip_all_blocks(void)
|
|||
if (s_principal_parser)
|
||||
{
|
||||
//write(2, "Cancelling blocks\n", strlen("Cancelling blocks\n"));
|
||||
block_t *c = s_principal_parser->current_block;
|
||||
while (c)
|
||||
for (size_t i=0; i < s_principal_parser->block_count(); i++)
|
||||
{
|
||||
c->skip = true;
|
||||
//fprintf(stderr, " Cancelled %p\n", c);
|
||||
c = c->outer;
|
||||
s_principal_parser->block_at_index(i)->skip = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void parser_t::push_block(block_t *newv)
|
||||
void parser_t::push_block(block_t *new_current)
|
||||
{
|
||||
const enum block_type_t type = newv->type();
|
||||
newv->src_lineno = parser_t::get_lineno();
|
||||
newv->src_filename = parser_t::current_filename()?intern(parser_t::current_filename()):0;
|
||||
|
||||
newv->outer = current_block;
|
||||
if (current_block && current_block->skip)
|
||||
newv->mark_as_fake();
|
||||
const enum block_type_t type = new_current->type();
|
||||
new_current->src_lineno = parser_t::get_lineno();
|
||||
new_current->src_filename = parser_t::current_filename()?intern(parser_t::current_filename()):0;
|
||||
|
||||
const block_t *old_current = this->current_block();
|
||||
if (old_current && old_current->skip)
|
||||
new_current->mark_as_fake();
|
||||
|
||||
/*
|
||||
New blocks should be skipped if the outer block is skipped,
|
||||
except TOP ans SUBST block, which open up new environments. Fake
|
||||
blocks should always be skipped. Rather complicated... :-(
|
||||
*/
|
||||
newv->skip=current_block?current_block->skip:0;
|
||||
new_current->skip = old_current ? old_current->skip : 0;
|
||||
|
||||
/*
|
||||
Type TOP and SUBST are never skipped
|
||||
*/
|
||||
if (type == TOP || type == SUBST)
|
||||
{
|
||||
newv->skip = 0;
|
||||
new_current->skip = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -394,27 +390,26 @@ void parser_t::push_block(block_t *newv)
|
|||
*/
|
||||
if (type == FAKE || type == FUNCTION_DEF)
|
||||
{
|
||||
newv->skip = 1;
|
||||
new_current->skip = 1;
|
||||
}
|
||||
|
||||
newv->job = 0;
|
||||
newv->loop_status=LOOP_NORMAL;
|
||||
new_current->job = 0;
|
||||
new_current->loop_status=LOOP_NORMAL;
|
||||
|
||||
this->block_stack.push_back(new_current);
|
||||
|
||||
current_block = newv;
|
||||
|
||||
if ((newv->type() != FUNCTION_DEF) &&
|
||||
(newv->type() != FAKE) &&
|
||||
(newv->type() != TOP))
|
||||
if ((new_current->type() != FUNCTION_DEF) &&
|
||||
(new_current->type() != FAKE) &&
|
||||
(new_current->type() != TOP))
|
||||
{
|
||||
env_push(type == FUNCTION_CALL);
|
||||
newv->wants_pop_env = true;
|
||||
new_current->wants_pop_env = true;
|
||||
}
|
||||
}
|
||||
|
||||
void parser_t::pop_block()
|
||||
{
|
||||
block_t *old = current_block;
|
||||
if (!current_block)
|
||||
if (block_stack.empty())
|
||||
{
|
||||
debug(1,
|
||||
L"function %s called on empty block stack.",
|
||||
|
@ -423,7 +418,8 @@ void parser_t::pop_block()
|
|||
return;
|
||||
}
|
||||
|
||||
current_block = current_block->outer;
|
||||
block_t *old = block_stack.back();
|
||||
block_stack.pop_back();
|
||||
|
||||
if (old->wants_pop_env)
|
||||
env_pop();
|
||||
|
@ -443,6 +439,30 @@ const wchar_t *parser_t::get_block_desc(int block) const
|
|||
return _(UNKNOWN_BLOCK);
|
||||
}
|
||||
|
||||
const block_t *parser_t::block_at_index(size_t idx) const
|
||||
{
|
||||
/* 0 corresponds to the last element in our vector */
|
||||
size_t count = block_stack.size();
|
||||
return idx < count ? block_stack.at(count - idx - 1) : NULL;
|
||||
}
|
||||
|
||||
block_t *parser_t::block_at_index(size_t idx)
|
||||
{
|
||||
size_t count = block_stack.size();
|
||||
return idx < count ? block_stack.at(count - idx - 1) : NULL;
|
||||
}
|
||||
|
||||
const block_t *parser_t::current_block() const
|
||||
{
|
||||
return block_stack.empty() ? NULL : block_stack.back();
|
||||
}
|
||||
|
||||
block_t *parser_t::current_block()
|
||||
{
|
||||
return block_stack.empty() ? NULL : block_stack.back();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Returns 1 if the specified command is a builtin that may not be used in a pipeline
|
||||
*/
|
||||
|
@ -807,13 +827,15 @@ void parser_t::eval_args(const wchar_t *line, std::vector<completion_t> &args)
|
|||
proc_pop_interactive();
|
||||
}
|
||||
|
||||
void parser_t::stack_trace(block_t *b, wcstring &buff) const
|
||||
void parser_t::stack_trace(size_t block_idx, wcstring &buff) const
|
||||
{
|
||||
/*
|
||||
Check if we should end the recursion
|
||||
*/
|
||||
if (!b)
|
||||
if (block_idx >= this->block_count())
|
||||
return;
|
||||
|
||||
const block_t *b = this->block_at_index(block_idx);
|
||||
|
||||
if (b->type()==EVENT)
|
||||
{
|
||||
|
@ -908,7 +930,7 @@ void parser_t::stack_trace(block_t *b, wcstring &buff) const
|
|||
/*
|
||||
Recursively print the next block
|
||||
*/
|
||||
parser_t::stack_trace(b->outer, buff);
|
||||
parser_t::stack_trace(block_idx + 1, buff);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -921,22 +943,19 @@ const wchar_t *parser_t::is_function() const
|
|||
{
|
||||
// PCA: Have to make this a string somehow
|
||||
ASSERT_IS_MAIN_THREAD();
|
||||
wcstring result;
|
||||
|
||||
block_t *b = current_block;
|
||||
while (1)
|
||||
const wchar_t *result = NULL;
|
||||
for (size_t block_idx = 0; block_idx < this->block_count(); block_idx++)
|
||||
{
|
||||
if (!b)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
const block_t *b = this->block_at_index(block_idx);
|
||||
if (b->type() == FUNCTION_CALL)
|
||||
{
|
||||
const function_block_t *fb = static_cast<const function_block_t *>(b);
|
||||
return fb->name.c_str();
|
||||
result = fb->name.c_str();
|
||||
break;
|
||||
}
|
||||
b=b->outer;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
@ -974,21 +993,17 @@ const wchar_t *parser_t::current_filename() const
|
|||
ASSERT_IS_MAIN_THREAD();
|
||||
assert(this == &principal_parser());
|
||||
|
||||
block_t *b = current_block;
|
||||
|
||||
while (1)
|
||||
for (size_t i=0; i < this->block_count(); i++)
|
||||
{
|
||||
if (!b)
|
||||
{
|
||||
return reader_current_filename();
|
||||
}
|
||||
const block_t *b = this->block_at_index(i);
|
||||
if (b->type() == FUNCTION_CALL)
|
||||
{
|
||||
const function_block_t *fb = static_cast<const function_block_t *>(b);
|
||||
return function_get_definition_file(fb->name);
|
||||
}
|
||||
b=b->outer;
|
||||
}
|
||||
return reader_current_filename();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1129,7 +1144,7 @@ const wchar_t *parser_t::current_line()
|
|||
}
|
||||
|
||||
free((void *)line);
|
||||
parser_t::stack_trace(current_block, lineinfo);
|
||||
parser_t::stack_trace(0, lineinfo);
|
||||
|
||||
return lineinfo.c_str();
|
||||
}
|
||||
|
@ -1239,7 +1254,7 @@ job_t *parser_t::job_get_from_pid(int pid)
|
|||
\param j the job to which the process belongs to
|
||||
\param tok the tokenizer to read options from
|
||||
\param args the argument list to insert options into
|
||||
\param args unskip whether we should ignore current_block->skip. Big hack because of our dumb handling of if statements.
|
||||
\param args unskip whether we should ignore current_block()->skip. Big hack because of our dumb handling of if statements.
|
||||
*/
|
||||
void parser_t::parse_job_argument_list(process_t *p,
|
||||
job_t *j,
|
||||
|
@ -1337,7 +1352,7 @@ void parser_t::parse_job_argument_list(process_t *p,
|
|||
{
|
||||
skip = 1;
|
||||
}
|
||||
else if (current_block->skip && ! unskip)
|
||||
else if (current_block()->skip && ! unskip)
|
||||
{
|
||||
/*
|
||||
If this command should be skipped, we do not expand the arguments
|
||||
|
@ -1345,12 +1360,12 @@ void parser_t::parse_job_argument_list(process_t *p,
|
|||
skip=1;
|
||||
|
||||
/* But if this is in fact a case statement or an elseif statement, then it should be evaluated */
|
||||
block_type_t type = current_block->type();
|
||||
block_type_t type = current_block()->type();
|
||||
if (type == SWITCH && args.at(0).completion == L"case" && p->type == INTERNAL_BUILTIN)
|
||||
{
|
||||
skip=0;
|
||||
}
|
||||
else if (job_get_flag(j, JOB_ELSEIF) && ! job_should_skip_elseif(j, current_block))
|
||||
else if (job_get_flag(j, JOB_ELSEIF) && ! job_should_skip_elseif(j, current_block()))
|
||||
{
|
||||
skip=0;
|
||||
}
|
||||
|
@ -1358,7 +1373,7 @@ void parser_t::parse_job_argument_list(process_t *p,
|
|||
else
|
||||
{
|
||||
/* If this is an else if, and we should skip it, then don't expand any arguments */
|
||||
if (job_get_flag(j, JOB_ELSEIF) && job_should_skip_elseif(j, current_block))
|
||||
if (job_get_flag(j, JOB_ELSEIF) && job_should_skip_elseif(j, current_block()))
|
||||
{
|
||||
skip = 1;
|
||||
}
|
||||
|
@ -1441,7 +1456,7 @@ void parser_t::parse_job_argument_list(process_t *p,
|
|||
Otherwise, bogus errors may be the result. (Do check
|
||||
that token is string, though)
|
||||
*/
|
||||
if (current_block->skip && ! unskip)
|
||||
if (current_block()->skip && ! unskip)
|
||||
{
|
||||
tok_next(tok);
|
||||
if (tok_last_type(tok) != TOK_STRING)
|
||||
|
@ -1756,7 +1771,7 @@ int parser_t::parse_job(process_t *p, job_t *j, tokenizer_t *tok)
|
|||
bool unskip = false; // Maybe we are an elseif inside an if block; if so we may want to evaluate this even if the if block is currently set to skip
|
||||
bool allow_bogus_command = false; // If we are an elseif that will not be executed, or an AND or OR that will have been short circuited, don't complain about non-existent commands
|
||||
|
||||
block_t *prev_block = current_block;
|
||||
const block_t *prev_block = current_block();
|
||||
scoped_push<int> tokenizer_pos_push(¤t_tokenizer_pos, tok_get_pos(tok));
|
||||
|
||||
while (args.empty())
|
||||
|
@ -1909,11 +1924,11 @@ int parser_t::parse_job(process_t *p, job_t *j, tokenizer_t *tok)
|
|||
tok_next(tok);
|
||||
while_block_t *wb = NULL;
|
||||
|
||||
if ((current_block->type() != WHILE))
|
||||
if ((current_block()->type() != WHILE))
|
||||
{
|
||||
new_block = true;
|
||||
}
|
||||
else if ((wb = static_cast<while_block_t*>(current_block))->status == WHILE_TEST_AGAIN)
|
||||
else if ((wb = static_cast<while_block_t*>(current_block()))->status == WHILE_TEST_AGAIN)
|
||||
{
|
||||
wb->status = WHILE_TEST_FIRST;
|
||||
}
|
||||
|
@ -1951,9 +1966,9 @@ int parser_t::parse_job(process_t *p, job_t *j, tokenizer_t *tok)
|
|||
const int else_pos = tok_get_pos(tok);
|
||||
/* See if we have any more arguments, that is, whether we're ELSE IF ... or just ELSE. */
|
||||
tok_next(tok);
|
||||
if (tok_last_type(tok) == TOK_STRING && current_block->type() == IF)
|
||||
if (tok_last_type(tok) == TOK_STRING && current_block()->type() == IF)
|
||||
{
|
||||
const if_block_t *ib = static_cast<const if_block_t *>(current_block);
|
||||
const if_block_t *ib = static_cast<const if_block_t *>(current_block());
|
||||
|
||||
/* If we've already encountered an else, complain */
|
||||
if (ib->else_evaluated)
|
||||
|
@ -1994,7 +2009,7 @@ int parser_t::parse_job(process_t *p, job_t *j, tokenizer_t *tok)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (use_function && (unskip || ! current_block->skip))
|
||||
if (use_function && (unskip || ! current_block()->skip))
|
||||
{
|
||||
bool nxt_forbidden=false;
|
||||
wcstring forbid;
|
||||
|
@ -2008,9 +2023,8 @@ int parser_t::parse_job(process_t *p, job_t *j, tokenizer_t *tok)
|
|||
block scopes are pushed on function invocation changes,
|
||||
then this check will break.
|
||||
*/
|
||||
if ((current_block->type() == TOP) &&
|
||||
(current_block->outer) &&
|
||||
(current_block->outer->type() == FUNCTION_CALL))
|
||||
const block_t *current = this->block_at_index(0), *parent = this->block_at_index(1);
|
||||
if (current && parent && current->type() == TOP && parent->type() == FUNCTION_CALL)
|
||||
is_function_call = 1;
|
||||
|
||||
/*
|
||||
|
@ -2019,7 +2033,7 @@ int parser_t::parse_job(process_t *p, job_t *j, tokenizer_t *tok)
|
|||
may not be called, since that would mean an infinite
|
||||
recursion.
|
||||
*/
|
||||
if (is_function_call && !current_block->had_command)
|
||||
if (is_function_call && !current->had_command)
|
||||
{
|
||||
forbid = forbidden_function.empty() ? wcstring(L"") : forbidden_function.back();
|
||||
if (forbid == nxt)
|
||||
|
@ -2066,7 +2080,7 @@ int parser_t::parse_job(process_t *p, job_t *j, tokenizer_t *tok)
|
|||
If we are not executing the current block, allow
|
||||
non-existent commands.
|
||||
*/
|
||||
if (current_block->skip && ! unskip)
|
||||
if (current_block()->skip && ! unskip)
|
||||
allow_bogus_command = true; //note this may already be true for other reasons
|
||||
|
||||
if (allow_bogus_command)
|
||||
|
@ -2311,7 +2325,7 @@ int parser_t::parse_job(process_t *p, job_t *j, tokenizer_t *tok)
|
|||
|
||||
tok_set_pos(tok, (int)end_pos);
|
||||
|
||||
while (prev_block != current_block)
|
||||
while (prev_block != this->current_block())
|
||||
{
|
||||
parser_t::pop_block();
|
||||
}
|
||||
|
@ -2340,7 +2354,7 @@ int parser_t::parse_job(process_t *p, job_t *j, tokenizer_t *tok)
|
|||
{
|
||||
if (!is_new_block)
|
||||
{
|
||||
current_block->had_command = true;
|
||||
current_block()->had_command = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2349,7 +2363,7 @@ int parser_t::parse_job(process_t *p, job_t *j, tokenizer_t *tok)
|
|||
/*
|
||||
Make sure the block stack is consistent
|
||||
*/
|
||||
while (prev_block != current_block)
|
||||
while (prev_block != current_block())
|
||||
{
|
||||
parser_t::pop_block();
|
||||
}
|
||||
|
@ -2383,7 +2397,8 @@ void parser_t::skipped_exec(job_t * j)
|
|||
}
|
||||
else if (wcscmp(p->argv0(), L"end")==0)
|
||||
{
|
||||
if (!current_block->outer->skip)
|
||||
const block_t *parent = this->block_at_index(1);
|
||||
if (parent && ! parent->skip)
|
||||
{
|
||||
exec_job(*this, j);
|
||||
return;
|
||||
|
@ -2392,10 +2407,10 @@ void parser_t::skipped_exec(job_t * j)
|
|||
}
|
||||
else if (wcscmp(p->argv0(), L"else")==0)
|
||||
{
|
||||
if (current_block->type() == IF)
|
||||
if (current_block()->type() == IF)
|
||||
{
|
||||
/* Evaluate this ELSE if the IF expression failed, and so has every ELSEIF (if any) expression thus far */
|
||||
const if_block_t *ib = static_cast<const if_block_t*>(current_block);
|
||||
const if_block_t *ib = static_cast<const if_block_t*>(current_block());
|
||||
if (ib->if_expr_evaluated && ! ib->any_branch_taken)
|
||||
{
|
||||
exec_job(*this, j);
|
||||
|
@ -2405,7 +2420,7 @@ void parser_t::skipped_exec(job_t * j)
|
|||
}
|
||||
else if (wcscmp(p->argv0(), L"case")==0)
|
||||
{
|
||||
if (current_block->type() == SWITCH)
|
||||
if (current_block()->type() == SWITCH)
|
||||
{
|
||||
exec_job(*this, j);
|
||||
return;
|
||||
|
@ -2679,7 +2694,7 @@ void parser_t::eval_job(tokenizer_t *tok)
|
|||
|| is_event \
|
||||
|| (!get_is_interactive()));
|
||||
|
||||
current_block->job = j;
|
||||
current_block()->job = j;
|
||||
|
||||
if (get_is_interactive())
|
||||
{
|
||||
|
@ -2714,27 +2729,27 @@ void parser_t::eval_job(tokenizer_t *tok)
|
|||
{
|
||||
t2 = get_time();
|
||||
profile_item->cmd = j->command();
|
||||
profile_item->skipped=current_block->skip;
|
||||
profile_item->skipped=current_block()->skip;
|
||||
}
|
||||
|
||||
/* If we're an ELSEIF, then we may want to unskip, if we're skipping because of an IF */
|
||||
if (job_get_flag(j, JOB_ELSEIF))
|
||||
{
|
||||
bool skip_elseif = job_should_skip_elseif(j, current_block);
|
||||
bool skip_elseif = job_should_skip_elseif(j, current_block());
|
||||
|
||||
/* Record that we're entering an elseif */
|
||||
if (! skip_elseif)
|
||||
{
|
||||
/* We must be an IF block here */
|
||||
assert(current_block->type() == IF);
|
||||
static_cast<if_block_t *>(current_block)->is_elseif_entry = true;
|
||||
assert(current_block()->type() == IF);
|
||||
static_cast<if_block_t *>(current_block())->is_elseif_entry = true;
|
||||
}
|
||||
|
||||
/* Record that in the block too. This is similar to what builtin_else does. */
|
||||
current_block->skip = skip_elseif;
|
||||
current_block()->skip = skip_elseif;
|
||||
}
|
||||
|
||||
skip = skip || current_block->skip;
|
||||
skip = skip || current_block()->skip;
|
||||
skip = skip || job_get_flag(j, JOB_WILDCARD_ERROR);
|
||||
skip = skip || job_get_flag(j, JOB_SKIP);
|
||||
|
||||
|
@ -2763,9 +2778,9 @@ void parser_t::eval_job(tokenizer_t *tok)
|
|||
profile_item->exec=(int)(t3-t2);
|
||||
}
|
||||
|
||||
if (current_block->type() == WHILE)
|
||||
if (current_block()->type() == WHILE)
|
||||
{
|
||||
while_block_t *wb = static_cast<while_block_t *>(current_block);
|
||||
while_block_t *wb = static_cast<while_block_t *>(current_block());
|
||||
switch (wb->status)
|
||||
{
|
||||
case WHILE_TEST_FIRST:
|
||||
|
@ -2779,9 +2794,9 @@ void parser_t::eval_job(tokenizer_t *tok)
|
|||
}
|
||||
}
|
||||
|
||||
if (current_block->type() == IF)
|
||||
if (current_block()->type() == IF)
|
||||
{
|
||||
if_block_t *ib = static_cast<if_block_t *>(current_block);
|
||||
if_block_t *ib = static_cast<if_block_t *>(current_block());
|
||||
|
||||
if (ib->skip)
|
||||
{
|
||||
|
@ -2794,7 +2809,7 @@ void parser_t::eval_job(tokenizer_t *tok)
|
|||
ib->any_branch_taken = if_result;
|
||||
|
||||
/* Don't execute if the expression failed */
|
||||
current_block->skip = ! if_result;
|
||||
current_block()->skip = ! if_result;
|
||||
ib->if_expr_evaluated = true;
|
||||
}
|
||||
else if (ib->is_elseif_entry && ! ib->any_branch_taken)
|
||||
|
@ -2802,7 +2817,7 @@ void parser_t::eval_job(tokenizer_t *tok)
|
|||
/* Maybe mark an ELSEIF branch as taken */
|
||||
bool elseif_taken = (proc_get_last_status() == 0);
|
||||
ib->any_branch_taken = elseif_taken;
|
||||
current_block->skip = ! elseif_taken;
|
||||
current_block()->skip = ! elseif_taken;
|
||||
ib->is_elseif_entry = false;
|
||||
}
|
||||
}
|
||||
|
@ -2820,7 +2835,7 @@ void parser_t::eval_job(tokenizer_t *tok)
|
|||
|
||||
proc_set_last_status(1);
|
||||
}
|
||||
current_block->job = 0;
|
||||
current_block()->job = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -3014,7 +3029,7 @@ int parser_t::eval(const wcstring &cmd_str, const io_chain_t &io, enum block_typ
|
|||
const wchar_t * const cmd = cmd_str.c_str();
|
||||
size_t forbid_count;
|
||||
int code;
|
||||
const block_t *start_current_block = current_block;
|
||||
const block_t *start_current_block = current_block();
|
||||
|
||||
/* Record the current chain so we can put it back later */
|
||||
scoped_push<io_chain_t> block_io_push(&block_io, io);
|
||||
|
@ -3068,9 +3083,9 @@ int parser_t::eval(const wcstring &cmd_str, const io_chain_t &io, enum block_typ
|
|||
|
||||
parser_t::pop_block();
|
||||
|
||||
while (start_current_block != current_block)
|
||||
while (start_current_block != current_block())
|
||||
{
|
||||
if (current_block == 0)
|
||||
if (current_block() == NULL)
|
||||
{
|
||||
debug(0,
|
||||
_(L"End of block mismatch. Program terminating."));
|
||||
|
@ -3085,7 +3100,7 @@ int parser_t::eval(const wcstring &cmd_str, const io_chain_t &io, enum block_typ
|
|||
//debug( 2, L"Status %d\n", proc_get_last_status() );
|
||||
|
||||
debug(1,
|
||||
L"%ls", parser_t::get_block_desc(current_block->type()));
|
||||
L"%ls", parser_t::get_block_desc(current_block()->type()));
|
||||
debug(1,
|
||||
BLOCK_END_ERR_MSG);
|
||||
fwprintf(stderr, L"%ls", parser_t::current_line());
|
||||
|
@ -3380,8 +3395,7 @@ block_t::block_t(block_type_t t) :
|
|||
src_filename(),
|
||||
src_lineno(),
|
||||
wants_pop_env(false),
|
||||
event_blocks(),
|
||||
outer(NULL)
|
||||
event_blocks()
|
||||
{
|
||||
}
|
||||
|
||||
|
|
28
parser.h
28
parser.h
|
@ -135,11 +135,6 @@ public:
|
|||
/** List of event blocks. */
|
||||
event_blockage_list_t event_blocks;
|
||||
|
||||
/**
|
||||
Next outer block
|
||||
*/
|
||||
block_t *outer;
|
||||
|
||||
/** Destructor */
|
||||
virtual ~block_t();
|
||||
};
|
||||
|
@ -305,7 +300,6 @@ class parser_t
|
|||
{
|
||||
private:
|
||||
enum parser_type_t parser_type;
|
||||
std::vector<block_t> blocks;
|
||||
|
||||
/** Whether or not we output errors */
|
||||
const bool show_errors;
|
||||
|
@ -336,6 +330,9 @@ private:
|
|||
|
||||
/** The jobs associated with this parser */
|
||||
job_list_t my_job_list;
|
||||
|
||||
/** The list of blocks, allocated with new. It's our responsibility to delete these */
|
||||
std::vector<block_t *> block_stack;
|
||||
|
||||
/**
|
||||
Keeps track of how many recursive eval calls have been made. Eval
|
||||
|
@ -385,9 +382,6 @@ public:
|
|||
/** Create a parser of the given type */
|
||||
parser_t(enum parser_type_t type, bool show_errors);
|
||||
|
||||
/** The current innermost block, allocated with new */
|
||||
block_t *current_block;
|
||||
|
||||
/** Global event blocks */
|
||||
event_blockage_list_t global_event_blocks;
|
||||
|
||||
|
@ -450,6 +444,20 @@ public:
|
|||
|
||||
/** Set the current position in the latest string of the tokenizer. */
|
||||
void set_pos(int p);
|
||||
|
||||
/** Returns the block at the given index. 0 corresponds to the innermost block. Returns NULL when idx is at or equal to the number of blocks. */
|
||||
const block_t *block_at_index(size_t idx) const;
|
||||
block_t *block_at_index(size_t idx);
|
||||
|
||||
/** Returns the current (innermost) block */
|
||||
const block_t *current_block() const;
|
||||
block_t *current_block();
|
||||
|
||||
/** Count of blocks */
|
||||
size_t block_count() const
|
||||
{
|
||||
return block_stack.size();
|
||||
}
|
||||
|
||||
/** Get the string currently parsed */
|
||||
const wchar_t *get_buffer() const;
|
||||
|
@ -542,7 +550,7 @@ public:
|
|||
/**
|
||||
Write a stack trace starting at the specified block to the specified wcstring
|
||||
*/
|
||||
void stack_trace(block_t *b, wcstring &buff) const;
|
||||
void stack_trace(size_t block_idx, wcstring &buff) const;
|
||||
|
||||
int get_block_type(const wchar_t *cmd) const;
|
||||
const wchar_t *get_block_command(int type) const;
|
||||
|
|
|
@ -2755,14 +2755,11 @@ static void handle_end_loop()
|
|||
job_t *j;
|
||||
int stopped_jobs_count=0;
|
||||
int is_breakpoint=0;
|
||||
block_t *b;
|
||||
parser_t &parser = parser_t::principal_parser();
|
||||
const parser_t &parser = parser_t::principal_parser();
|
||||
|
||||
for (b = parser.current_block;
|
||||
b;
|
||||
b = b->outer)
|
||||
for (size_t i = 0; i < parser.block_count(); i++)
|
||||
{
|
||||
if (b->type() == BREAKPOINT)
|
||||
if (parser.block_at_index(i)->type() == BREAKPOINT)
|
||||
{
|
||||
is_breakpoint = 1;
|
||||
break;
|
||||
|
|
140
share/completions/adb.fish
Normal file
140
share/completions/adb.fish
Normal file
|
@ -0,0 +1,140 @@
|
|||
# Completions for Android adb command
|
||||
|
||||
function __fish_adb_no_subcommand --description 'Test if adb has yet to be given the subcommand'
|
||||
for i in (commandline -opc)
|
||||
if contains -- $i connect disconnect devices push pull sync shell emu logcat install uninstall jdwp forward bugreport backup restore version help wait-for-device start-server kill-server remount reboot get-state get-serialno get-devpath status-window root usb tcpip ppp
|
||||
return 1
|
||||
end
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
function __fish_adb_get_devices --description 'Run adb devices and parse output'
|
||||
# This seems reasonably portable for all the platforms adb runs on
|
||||
set -l count (ps x | grep -c adb)
|
||||
set -l TAB \t
|
||||
# Don't run adb devices unless the server is already started - it takes a while to init
|
||||
if [ $count -gt 1 ]
|
||||
# The tail is to strip the header line, the sed is to massage the -l format
|
||||
# into a simple "identifier <TAB> modelname" format which is what we want for complete
|
||||
adb devices -l | tail -n +2 | sed -E -e "s/([^ ]+) +./\1$TAB/" -e "s/$TAB.*model:([^ ]+).*/$TAB\1/"
|
||||
end
|
||||
end
|
||||
|
||||
function __fish_adb_run_command --description 'Runs adb with any -s parameters already given on the command line'
|
||||
set -l sopt
|
||||
set -l sopt_is_next
|
||||
set -l cmd (commandline -poc)
|
||||
set -e cmd[1]
|
||||
for i in $cmd
|
||||
if test $sopt_is_next
|
||||
set sopt -s $i
|
||||
break
|
||||
else
|
||||
switch $i
|
||||
case -s
|
||||
set sopt_is_next 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# If no -s option, see if there's a -d or -e instead
|
||||
if test -z "$sopt"
|
||||
if contains -- -d $cmd
|
||||
set sopt '-d'
|
||||
else if contains -- -e $cmd
|
||||
set sopt '-e'
|
||||
end
|
||||
end
|
||||
|
||||
# adb returns CRLF (seemingly) so strip CRs
|
||||
adb $sopt shell $argv | sed s/\r//
|
||||
end
|
||||
|
||||
function __fish_adb_list_packages
|
||||
__fish_adb_run_command pm list packages | sed s/package://
|
||||
end
|
||||
|
||||
|
||||
function __fish_adb_list_uninstallable_packages
|
||||
# -3 doesn't exactly mean show uninstallable, but it's the closest you can get to with pm list
|
||||
__fish_adb_run_command pm list packages -3 | sed s/package://
|
||||
end
|
||||
|
||||
# Generic options, must come before command
|
||||
complete -n '__fish_adb_no_subcommand' -c adb -s s -x -a "(__fish_adb_get_devices)" -d 'Device to communicate with'
|
||||
complete -n '__fish_adb_no_subcommand' -c adb -s d -d 'Communicate with first USB device'
|
||||
complete -n '__fish_adb_no_subcommand' -c adb -s e -d 'Communicate with emulator'
|
||||
|
||||
# Commands
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'connect' -d 'Connect to device'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'disconnect' -d 'Disconnect from device'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'devices' -d 'List all connected devices'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'push' -d 'Copy file to device'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'pull' -d 'Copy file from device'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'sync' -d 'Copy host->device only if changed'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'shell' -d 'Run remote shell [command]'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'emu' -d 'Run emulator console command'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'logcat' -d 'View device log'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'install' -d 'Install package'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'uninstall' -d 'Uninstall package'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'jdwp' -d 'List PIDs of processes hosting a JDWP transport'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'forward' -d 'Port forwarding'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'bugreport' -d 'Return bugreport information'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'backup' -d 'Perform device backup'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'restore' -d 'Restore device from backup'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'version' -d 'Show adb version'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'help' -d 'Show adb help'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'wait-for-device' -d 'Block until device is online'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'start-server' -d 'Ensure that there is a server running'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'kill-server' -d 'Kill the server if it is running'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'remount' -d 'Remounts the /system partition on the device read-write'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'reboot' -d 'Reboots the device, optionally into the bootloader or recovery program'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'get-state' -d 'Prints state of the device'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'get-serialno' -d 'Prints serial number of the device'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'get-devpath' -d 'Prints device path'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'status-window' -d 'Continuously print the device status'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'root' -d 'Restart the adbd daemon with root permissions'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'usb' -d 'Restart the adbd daemon listening on USB'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'tcpip' -d 'Restart the adbd daemon listening on TCP'
|
||||
complete -f -n '__fish_adb_no_subcommand' -c adb -a 'ppp' -d 'Run PPP over USB'
|
||||
|
||||
# install options
|
||||
complete -n '__fish_seen_subcommand_from install' -c adb -s l -d 'Forward-lock the app'
|
||||
complete -n '__fish_seen_subcommand_from install' -c adb -s r -d 'Reinstall the app keeping its data'
|
||||
complete -n '__fish_seen_subcommand_from install' -c adb -s s -d 'Install on SD card instead of internal storage'
|
||||
complete -n '__fish_seen_subcommand_from install' -c adb -l 'algo' -d 'Algorithm name'
|
||||
complete -n '__fish_seen_subcommand_from install' -c adb -l 'key' -d 'Hex-encoded key'
|
||||
complete -n '__fish_seen_subcommand_from install' -c adb -l 'iv' -d 'Hex-encoded iv'
|
||||
|
||||
# uninstall
|
||||
complete -n '__fish_seen_subcommand_from uninstall' -c adb -s k -d 'Keep the data and cache directories'
|
||||
complete -n '__fish_seen_subcommand_from uninstall' -c adb -f -u -a "(__fish_adb_list_uninstallable_packages)"
|
||||
|
||||
# devices
|
||||
complete -n '__fish_seen_subcommand_from devices' -c adb -s l -d 'Also list device qualifiers'
|
||||
|
||||
# disconnect
|
||||
complete -n '__fish_seen_subcommand_from disconnect' -c adb -x -a "(__fish_adb_get_devices)" -d 'Device to disconnect'
|
||||
|
||||
# backup
|
||||
complete -n '__fish_seen_subcommand_from backup' -c adb -s f -d 'File to write backup data to'
|
||||
complete -n '__fish_seen_subcommand_from backup' -c adb -o 'apk' -d 'Enable backup of the .apks themselves'
|
||||
complete -n '__fish_seen_subcommand_from backup' -c adb -o 'noapk' -d 'Disable backup of the .apks themselves (default)'
|
||||
complete -n '__fish_seen_subcommand_from backup' -c adb -o 'obb' -d 'Enable backup of any installed apk expansion'
|
||||
complete -n '__fish_seen_subcommand_from backup' -c adb -o 'noobb' -d 'Disable backup of any installed apk expansion (default)'
|
||||
complete -n '__fish_seen_subcommand_from backup' -c adb -o 'shared' -d 'Enable backup of the device\'s shared storage / SD card contents'
|
||||
complete -n '__fish_seen_subcommand_from backup' -c adb -o 'noshared' -d 'Disable backup of the device\'s shared storage / SD card contents (default)'
|
||||
complete -n '__fish_seen_subcommand_from backup' -c adb -o 'all' -d 'Back up all installed applications'
|
||||
complete -n '__fish_seen_subcommand_from backup' -c adb -o 'system' -d 'Include system applications in -all (default)'
|
||||
complete -n '__fish_seen_subcommand_from backup' -c adb -o 'nosystem' -d 'Exclude system applications in -all'
|
||||
complete -n '__fish_seen_subcommand_from backup' -c adb -f -a "(__fish_adb_list_packages)" -d 'Package(s) to backup'
|
||||
|
||||
# reboot
|
||||
complete -n '__fish_seen_subcommand_from reboot' -c adb -x -a 'bootloader recovery'
|
||||
|
||||
# forward
|
||||
complete -n '__fish_seen_subcommand_from forward' -c adb -l 'list' -d 'List all forward socket connections'
|
||||
complete -n '__fish_seen_subcommand_from forward' -c adb -l 'no-rebind' -d 'Fails the forward if local is already forwarded'
|
||||
complete -n '__fish_seen_subcommand_from forward' -c adb -l 'remove' -d 'Remove a specific forward socket connection'
|
||||
complete -n '__fish_seen_subcommand_from forward' -c adb -l 'remove-all' -d 'Remove all forward socket connections'
|
|
@ -89,10 +89,12 @@ function __fish_reconstruct_path -d "Update PATH when fish_user_paths changes" -
|
|||
|
||||
set -e __fish_added_user_paths
|
||||
for x in $fish_user_paths[-1..1]
|
||||
if not contains $x $local_path
|
||||
set local_path $x $local_path
|
||||
if set -l idx (contains --index $x $local_path)
|
||||
set -e local_path[$idx]
|
||||
else
|
||||
set -g __fish_added_user_paths $__fish_added_user_paths $x
|
||||
end
|
||||
set local_path $x $local_path
|
||||
end
|
||||
set -xg PATH $local_path
|
||||
end
|
||||
|
|
|
@ -371,6 +371,7 @@ function __fish_git_prompt --description "Prompt function for Git"
|
|||
set -l informative_status
|
||||
|
||||
__fish_git_prompt_validate_chars
|
||||
__fish_git_prompt_validate_colors
|
||||
|
||||
if test "true" = $inside_worktree
|
||||
if test -n "$__fish_git_prompt_show_informative_status"
|
||||
|
@ -403,8 +404,6 @@ function __fish_git_prompt --description "Prompt function for Git"
|
|||
end
|
||||
end
|
||||
|
||||
__fish_git_prompt_validate_colors
|
||||
|
||||
set -l branch_color $___fish_git_prompt_color_branch
|
||||
set -l branch_done $___fish_git_prompt_color_branch_done
|
||||
if test -n "$__fish_git_prompt_showcolorhints"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
function __fish_print_svn_rev --description 'Print svn revisions'
|
||||
svn info | grep "Last Changed Rev" | cut --delimiter " " --fields 4
|
||||
svn info | grep "Last Changed Rev" | cut -d " " -f 4
|
||||
echo \{\tRevision at start of the date
|
||||
echo HEAD\tLatest in repository
|
||||
echo BASE\tBase rev of item\'s working copy
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __XDG_MIME_ALIAS_H__
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __XDG_MIME_GLOB_H__
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __XDG_MIME_INT_H__
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __XDG_MIME_MAGIC_H__
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __XDG_MIME_PARENT_H__
|
||||
|
|
Loading…
Reference in a new issue