mirror of
https://github.com/fish-shell/fish-shell
synced 2024-11-11 23:47:25 +00:00
Remove obviated builtins and additional cleanup of old parser
This commit is contained in:
parent
b187125b63
commit
6b3a37c597
2 changed files with 10 additions and 720 deletions
619
builtin.cpp
619
builtin.cpp
|
@ -1728,7 +1728,7 @@ static int builtin_pwd(parser_t &parser, wchar_t **argv)
|
|||
}
|
||||
}
|
||||
|
||||
/* This is nearly identical to builtin_function, and is intended to be the successor (with no block manipulation, no function/end split) */
|
||||
/** Adds a function to the function set. It calls into function.cpp to perform any heavy lifting. */
|
||||
int define_function(parser_t &parser, const wcstring_list_t &c_args, const wcstring &contents, wcstring *out_err)
|
||||
{
|
||||
assert(out_err != NULL);
|
||||
|
@ -2034,338 +2034,6 @@ int define_function(parser_t &parser, const wcstring_list_t &c_args, const wcstr
|
|||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
The function builtin, used for providing subroutines.
|
||||
It calls various functions from function.c to perform any heavy lifting.
|
||||
*/
|
||||
static int builtin_function(parser_t &parser, wchar_t **argv)
|
||||
{
|
||||
/* Hack hack hack - with the new parser, this is only invoked for help */
|
||||
if (parser_use_ast())
|
||||
{
|
||||
builtin_print_help(parser, argv[0], stdout_buffer);
|
||||
return STATUS_BUILTIN_OK;
|
||||
}
|
||||
|
||||
int argc = builtin_count_args(argv);
|
||||
int res=STATUS_BUILTIN_OK;
|
||||
wchar_t *desc=0;
|
||||
std::vector<event_t> events;
|
||||
std::auto_ptr<wcstring_list_t> named_arguments(NULL);
|
||||
|
||||
wchar_t *name = 0;
|
||||
bool shadows = true;
|
||||
|
||||
woptind=0;
|
||||
|
||||
function_def_block_t * const fdb = new function_def_block_t();
|
||||
parser.push_block(fdb);
|
||||
|
||||
const struct woption long_options[] =
|
||||
{
|
||||
{ L"description", required_argument, 0, 'd' },
|
||||
{ L"on-signal", required_argument, 0, 's' },
|
||||
{ L"on-job-exit", required_argument, 0, 'j' },
|
||||
{ L"on-process-exit", required_argument, 0, 'p' },
|
||||
{ L"on-variable", required_argument, 0, 'v' },
|
||||
{ L"on-event", required_argument, 0, 'e' },
|
||||
{ L"help", no_argument, 0, 'h' },
|
||||
{ L"argument-names", no_argument, 0, 'a' },
|
||||
{ L"no-scope-shadowing", no_argument, 0, 'S' },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
while (1 && (!res))
|
||||
{
|
||||
int opt_index = 0;
|
||||
|
||||
int opt = wgetopt_long(argc,
|
||||
argv,
|
||||
L"d:s:j:p:v:e:haS",
|
||||
long_options,
|
||||
&opt_index);
|
||||
if (opt == -1)
|
||||
break;
|
||||
|
||||
switch (opt)
|
||||
{
|
||||
case 0:
|
||||
if (long_options[opt_index].flag != 0)
|
||||
break;
|
||||
append_format(stderr_buffer,
|
||||
BUILTIN_ERR_UNKNOWN,
|
||||
argv[0],
|
||||
long_options[opt_index].name);
|
||||
|
||||
res = 1;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
desc=woptarg;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
{
|
||||
int sig = wcs2sig(woptarg);
|
||||
|
||||
if (sig < 0)
|
||||
{
|
||||
append_format(stderr_buffer,
|
||||
_(L"%ls: Unknown signal '%ls'\n"),
|
||||
argv[0],
|
||||
woptarg);
|
||||
res=1;
|
||||
break;
|
||||
}
|
||||
events.push_back(event_t::signal_event(sig));
|
||||
break;
|
||||
}
|
||||
|
||||
case 'v':
|
||||
{
|
||||
if (wcsvarname(woptarg))
|
||||
{
|
||||
append_format(stderr_buffer,
|
||||
_(L"%ls: Invalid variable name '%ls'\n"),
|
||||
argv[0],
|
||||
woptarg);
|
||||
res=STATUS_BUILTIN_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
events.push_back(event_t::variable_event(woptarg));
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case 'e':
|
||||
{
|
||||
events.push_back(event_t::generic_event(woptarg));
|
||||
break;
|
||||
}
|
||||
|
||||
case 'j':
|
||||
case 'p':
|
||||
{
|
||||
pid_t pid;
|
||||
wchar_t *end;
|
||||
event_t e(EVENT_ANY);
|
||||
|
||||
if ((opt == 'j') &&
|
||||
(wcscasecmp(woptarg, L"caller") == 0))
|
||||
{
|
||||
int job_id = -1;
|
||||
|
||||
if (is_subshell)
|
||||
{
|
||||
size_t block_idx = 0;
|
||||
|
||||
/* Find the outermost substitution block */
|
||||
for (block_idx = 0; ; block_idx++)
|
||||
{
|
||||
const block_t *b = parser.block_at_index(block_idx);
|
||||
if (b == NULL || b->type() == SUBST)
|
||||
break;
|
||||
}
|
||||
|
||||
/* 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 = caller_block->job->job_id;
|
||||
}
|
||||
}
|
||||
|
||||
if (job_id == -1)
|
||||
{
|
||||
append_format(stderr_buffer,
|
||||
_(L"%ls: Cannot find calling job for event handler\n"),
|
||||
argv[0]);
|
||||
res=1;
|
||||
}
|
||||
else
|
||||
{
|
||||
e.type = EVENT_JOB_ID;
|
||||
e.param1.job_id = job_id;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = 0;
|
||||
pid = fish_wcstoi(woptarg, &end, 10);
|
||||
if (errno || !end || *end)
|
||||
{
|
||||
append_format(stderr_buffer,
|
||||
_(L"%ls: Invalid process id %ls\n"),
|
||||
argv[0],
|
||||
woptarg);
|
||||
res=1;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
e.type = EVENT_EXIT;
|
||||
e.param1.pid = (opt=='j'?-1:1)*abs(pid);
|
||||
}
|
||||
if (res)
|
||||
{
|
||||
/* nothing */
|
||||
}
|
||||
else
|
||||
{
|
||||
events.push_back(e);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'a':
|
||||
if (named_arguments.get() == NULL)
|
||||
named_arguments.reset(new wcstring_list_t);
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
shadows = 0;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
parser.pop_block();
|
||||
parser.push_block(new fake_block_t());
|
||||
builtin_print_help(parser, argv[0], stdout_buffer);
|
||||
return STATUS_BUILTIN_OK;
|
||||
|
||||
case '?':
|
||||
builtin_unknown_option(parser, argv[0], argv[woptind-1]);
|
||||
res = 1;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!res)
|
||||
{
|
||||
|
||||
if (argc == woptind)
|
||||
{
|
||||
append_format(stderr_buffer,
|
||||
_(L"%ls: Expected function name\n"),
|
||||
argv[0]);
|
||||
res=1;
|
||||
}
|
||||
else if (wcsfuncname(argv[woptind]))
|
||||
{
|
||||
append_format(stderr_buffer,
|
||||
_(L"%ls: Illegal function name '%ls'\n"),
|
||||
argv[0],
|
||||
argv[woptind]);
|
||||
|
||||
res=1;
|
||||
}
|
||||
else if (parser_keywords_is_reserved(argv[woptind]))
|
||||
{
|
||||
|
||||
append_format(stderr_buffer,
|
||||
_(L"%ls: The name '%ls' is reserved,\nand can not be used as a function name\n"),
|
||||
argv[0],
|
||||
argv[woptind]);
|
||||
|
||||
res=1;
|
||||
}
|
||||
else if (! wcslen(argv[woptind]))
|
||||
{
|
||||
append_format(stderr_buffer, _(L"%ls: No function name given\n"), argv[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
name = argv[woptind++];
|
||||
|
||||
if (named_arguments.get())
|
||||
{
|
||||
while (woptind < argc)
|
||||
{
|
||||
if (wcsvarname(argv[woptind]))
|
||||
{
|
||||
append_format(stderr_buffer,
|
||||
_(L"%ls: Invalid variable name '%ls'\n"),
|
||||
argv[0],
|
||||
argv[woptind]);
|
||||
res = STATUS_BUILTIN_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
named_arguments->push_back(argv[woptind++]);
|
||||
}
|
||||
}
|
||||
else if (woptind != argc)
|
||||
{
|
||||
append_format(stderr_buffer,
|
||||
_(L"%ls: Expected one argument, got %d\n"),
|
||||
argv[0],
|
||||
argc);
|
||||
res=1;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (res)
|
||||
{
|
||||
size_t i;
|
||||
size_t chars=0;
|
||||
|
||||
builtin_print_help(parser, argv[0], stderr_buffer);
|
||||
const wchar_t *cfa = _(L"Current functions are: ");
|
||||
stderr_buffer.append(cfa);
|
||||
chars += wcslen(cfa);
|
||||
|
||||
wcstring_list_t names = function_get_names(0);
|
||||
sort(names.begin(), names.end());
|
||||
|
||||
for (i=0; i<names.size(); i++)
|
||||
{
|
||||
const wchar_t *nxt = names.at(i).c_str();
|
||||
size_t l = wcslen(nxt + 2);
|
||||
if (chars+l > (size_t)common_get_width())
|
||||
{
|
||||
chars = 0;
|
||||
stderr_buffer.push_back(L'\n');
|
||||
}
|
||||
|
||||
stderr_buffer.append(nxt);
|
||||
stderr_buffer.append(L" ");
|
||||
}
|
||||
stderr_buffer.push_back(L'\n');
|
||||
|
||||
parser.pop_block();
|
||||
parser.push_block(new fake_block_t());
|
||||
}
|
||||
else
|
||||
{
|
||||
function_data_t &d = fdb->function_data;
|
||||
|
||||
d.name = name;
|
||||
if (desc)
|
||||
d.description = desc;
|
||||
d.events.swap(events);
|
||||
d.shadows = shadows;
|
||||
if (named_arguments.get())
|
||||
d.named_arguments.swap(*named_arguments);
|
||||
|
||||
for (size_t i=0; i<d.events.size(); i++)
|
||||
{
|
||||
event_t &e = d.events.at(i);
|
||||
e.function_name = d.name;
|
||||
}
|
||||
}
|
||||
|
||||
parser.current_block()->tok_pos = parser.get_pos();
|
||||
parser.current_block()->skip = 1;
|
||||
|
||||
return STATUS_BUILTIN_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
The random builtin. For generating random numbers.
|
||||
*/
|
||||
|
@ -3713,195 +3381,6 @@ static int builtin_for(parser_t &parser, wchar_t **argv)
|
|||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
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();
|
||||
return proc_get_last_status();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Builtin for ending a block of code, such as a for-loop or an if statement.
|
||||
|
||||
The end command is whare a lot of the block-level magic happens.
|
||||
*/
|
||||
static int builtin_end(parser_t &parser, wchar_t **argv)
|
||||
{
|
||||
if (! parser.block_at_index(1))
|
||||
{
|
||||
append_format(stderr_buffer,
|
||||
_(L"%ls: Not inside of block\n"),
|
||||
argv[0]);
|
||||
|
||||
builtin_print_help(parser, argv[0], stderr_buffer);
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
/**
|
||||
By default, 'end' kills the current block scope. But if we
|
||||
are rewinding a loop, this should be set to false, so that
|
||||
variables in the current loop scope won't die between laps.
|
||||
*/
|
||||
bool kill_block = true;
|
||||
|
||||
block_t * const current_block = parser.current_block();
|
||||
switch (current_block->type())
|
||||
{
|
||||
case WHILE:
|
||||
{
|
||||
/*
|
||||
If this is a while loop, we rewind the loop unless
|
||||
it's the last lap, in which case we continue.
|
||||
*/
|
||||
if (!(current_block->skip && (current_block->loop_status != LOOP_CONTINUE)))
|
||||
{
|
||||
current_block->loop_status = LOOP_NORMAL;
|
||||
current_block->skip = 0;
|
||||
kill_block = false;
|
||||
parser.set_pos(current_block->tok_pos);
|
||||
while_block_t *blk = static_cast<while_block_t *>(current_block);
|
||||
blk->status = WHILE_TEST_AGAIN;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case IF:
|
||||
/* Always return success (#1061) */
|
||||
proc_set_last_status(0);
|
||||
break;
|
||||
|
||||
case SUBST:
|
||||
case BEGIN:
|
||||
case SWITCH:
|
||||
case FAKE:
|
||||
/*
|
||||
Nothing special happens at the end of these commands. The scope just ends.
|
||||
*/
|
||||
|
||||
break;
|
||||
|
||||
case FOR:
|
||||
{
|
||||
/*
|
||||
set loop variable to next element, and rewind to the beginning of the block.
|
||||
*/
|
||||
for_block_t *fb = static_cast<for_block_t *>(current_block);
|
||||
wcstring_list_t &for_vars = fb->sequence;
|
||||
if (current_block->loop_status == LOOP_BREAK)
|
||||
{
|
||||
for_vars.clear();
|
||||
}
|
||||
|
||||
if (! for_vars.empty())
|
||||
{
|
||||
const wcstring val = for_vars.back();
|
||||
for_vars.pop_back();
|
||||
const wcstring &for_variable = fb->variable;
|
||||
env_set(for_variable, val.c_str(), ENV_LOCAL);
|
||||
current_block->loop_status = LOOP_NORMAL;
|
||||
current_block->skip = 0;
|
||||
|
||||
kill_block = false;
|
||||
parser.set_pos(current_block->tok_pos);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case FUNCTION_DEF:
|
||||
{
|
||||
function_def_block_t *fdb = static_cast<function_def_block_t *>(current_block);
|
||||
function_data_t &d = fdb->function_data;
|
||||
|
||||
if (d.name.empty())
|
||||
{
|
||||
/* Disallow empty function names */
|
||||
append_format(stderr_buffer, _(L"%ls: No function name given\n"), argv[0]);
|
||||
|
||||
/* Return an error via a crummy way. Don't just return here, since we need to pop the block. */
|
||||
proc_set_last_status(STATUS_BUILTIN_ERROR);
|
||||
}
|
||||
else
|
||||
{
|
||||
/**
|
||||
Copy the text from the beginning of the function
|
||||
until the end command and use as the new definition
|
||||
for the specified function
|
||||
*/
|
||||
|
||||
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);
|
||||
free(def);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false); //should never get here
|
||||
break;
|
||||
|
||||
}
|
||||
if (kill_block)
|
||||
{
|
||||
parser.pop_block();
|
||||
}
|
||||
|
||||
/*
|
||||
If everything goes ok, return status of last command to execute.
|
||||
*/
|
||||
return proc_get_last_status();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Builtin for executing commands if an if statement is false
|
||||
*/
|
||||
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_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)
|
||||
{
|
||||
block_ok = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (! block_ok)
|
||||
{
|
||||
append_format(stderr_buffer,
|
||||
_(L"%ls: Not inside of 'if' block\n"),
|
||||
argv[0]);
|
||||
builtin_print_help(parser, argv[0], stderr_buffer);
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Run the else block if the IF expression was false and so were all the ELSEIF expressions (if any) */
|
||||
bool run_else = ! if_block->any_branch_taken;
|
||||
if_block->skip = ! run_else;
|
||||
if_block->else_evaluated = true;
|
||||
env_pop();
|
||||
env_push(false);
|
||||
}
|
||||
|
||||
/*
|
||||
If everything goes ok, return status of last command to execute.
|
||||
*/
|
||||
return proc_get_last_status();
|
||||
}
|
||||
|
||||
/**
|
||||
This function handles both the 'continue' and the 'break' builtins
|
||||
that are used for loop control.
|
||||
|
@ -4037,90 +3516,6 @@ static int builtin_return(parser_t &parser, wchar_t **argv)
|
|||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
Builtin for executing one of several blocks of commands depending
|
||||
on the value of an argument.
|
||||
*/
|
||||
static int builtin_switch(parser_t &parser, wchar_t **argv)
|
||||
{
|
||||
int res=STATUS_BUILTIN_OK;
|
||||
int argc = builtin_count_args(argv);
|
||||
|
||||
/* Hackish - if we have no arguments other than the command, we are a "naked invocation" and we just print help */
|
||||
if (argc == 1)
|
||||
{
|
||||
builtin_print_help(parser, argv[0], stdout_buffer);
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
|
||||
if (argc != 2)
|
||||
{
|
||||
append_format(stderr_buffer,
|
||||
_(L"%ls: Expected exactly one argument, got %d\n"),
|
||||
argv[0],
|
||||
argc-1);
|
||||
|
||||
builtin_print_help(parser, argv[0], stderr_buffer);
|
||||
res=1;
|
||||
parser.push_block(new fake_block_t());
|
||||
}
|
||||
else
|
||||
{
|
||||
parser.push_block(new switch_block_t(argv[1]));
|
||||
parser.current_block()->skip=1;
|
||||
res = proc_get_last_status();
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
Builtin used together with the switch builtin for conditional
|
||||
execution
|
||||
*/
|
||||
static int builtin_case(parser_t &parser, wchar_t **argv)
|
||||
{
|
||||
int argc = builtin_count_args(argv);
|
||||
int i;
|
||||
wchar_t *unescaped=0;
|
||||
|
||||
if (parser.current_block()->type() != SWITCH)
|
||||
{
|
||||
append_format(stderr_buffer,
|
||||
_(L"%ls: 'case' command while not in switch block\n"),
|
||||
argv[0]);
|
||||
builtin_print_help(parser, argv[0], stderr_buffer);
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
const wcstring &switch_value = sb->switch_value;
|
||||
for (i=1; i<argc; i++)
|
||||
{
|
||||
int match;
|
||||
|
||||
unescaped = parse_util_unescape_wildcards(argv[i]);
|
||||
match = wildcard_match(switch_value, unescaped);
|
||||
free(unescaped);
|
||||
|
||||
if (match)
|
||||
{
|
||||
parser.current_block()->skip = 0;
|
||||
sb->switch_taken = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return proc_get_last_status();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
History of commands executed by user
|
||||
*/
|
||||
|
@ -4317,14 +3712,14 @@ static const builtin_data_t builtin_datas[]=
|
|||
{ L"[", &builtin_test, N_(L"Test a condition") },
|
||||
{ L"__fish_parse", &builtin_parse, N_(L"Try out the new parser") },
|
||||
{ L"and", &builtin_generic, N_(L"Execute command if previous command suceeded") },
|
||||
{ L"begin", &builtin_begin, N_(L"Create a block of code") },
|
||||
{ L"begin", &builtin_generic, N_(L"Create a block of code") },
|
||||
{ L"bg", &builtin_bg, N_(L"Send job to background") },
|
||||
{ L"bind", &builtin_bind, N_(L"Handle fish key bindings") },
|
||||
{ L"block", &builtin_block, N_(L"Temporarily block delivery of events") },
|
||||
{ L"break", &builtin_break_continue, N_(L"Stop the innermost loop") },
|
||||
{ L"breakpoint", &builtin_breakpoint, N_(L"Temporarily halt execution of a script and launch an interactive debug prompt") },
|
||||
{ L"builtin", &builtin_builtin, N_(L"Run a builtin command instead of a function") },
|
||||
{ L"case", &builtin_case, N_(L"Conditionally execute a block of commands") },
|
||||
{ L"case", &builtin_generic, N_(L"Conditionally execute a block of commands") },
|
||||
{ L"cd", &builtin_cd, N_(L"Change working directory") },
|
||||
{ L"command", &builtin_generic, N_(L"Run a program instead of a function or builtin") },
|
||||
{ L"commandline", &builtin_commandline, N_(L"Set or get the commandline") },
|
||||
|
@ -4333,14 +3728,14 @@ static const builtin_data_t builtin_datas[]=
|
|||
{ L"continue", &builtin_break_continue, N_(L"Skip the rest of the current lap of the innermost loop") },
|
||||
{ L"count", &builtin_count, N_(L"Count the number of arguments") },
|
||||
{ L"echo", &builtin_echo, N_(L"Print arguments") },
|
||||
{ L"else", &builtin_else, N_(L"Evaluate block if condition is false") },
|
||||
{ L"else", &builtin_generic, N_(L"Evaluate block if condition is false") },
|
||||
{ L"emit", &builtin_emit, N_(L"Emit an event") },
|
||||
{ L"end", &builtin_end, N_(L"End a block of commands") },
|
||||
{ L"end", &builtin_generic, N_(L"End a block of commands") },
|
||||
{ L"exec", &builtin_generic, N_(L"Run command in current process") },
|
||||
{ L"exit", &builtin_exit, N_(L"Exit the shell") },
|
||||
{ L"fg", &builtin_fg, N_(L"Send job to foreground") },
|
||||
{ L"for", &builtin_for, N_(L"Perform a set of commands multiple times") },
|
||||
{ L"function", &builtin_function, N_(L"Define a new function") },
|
||||
{ L"function", &builtin_generic, N_(L"Define a new function") },
|
||||
{ L"functions", &builtin_functions, N_(L"List or remove functions") },
|
||||
{ L"history", &builtin_history, N_(L"History of commands executed by user") },
|
||||
{ L"if", &builtin_generic, N_(L"Evaluate block if condition is true") },
|
||||
|
@ -4356,7 +3751,7 @@ static const builtin_data_t builtin_datas[]=
|
|||
{ L"set_color", &builtin_set_color, N_(L"Set the terminal color") },
|
||||
{ L"source", &builtin_source, N_(L"Evaluate contents of file") },
|
||||
{ L"status", &builtin_status, N_(L"Return status information about fish") },
|
||||
{ L"switch", &builtin_switch, N_(L"Conditionally execute a block of commands") },
|
||||
{ L"switch", &builtin_generic, N_(L"Conditionally execute a block of commands") },
|
||||
{ L"test", &builtin_test, N_(L"Test a condition") },
|
||||
{ L"ulimit", &builtin_ulimit, N_(L"Set or get the shells resource usage limits") },
|
||||
{ L"while", &builtin_generic, N_(L"Perform a command multiple times") }
|
||||
|
|
111
parser.cpp
111
parser.cpp
|
@ -349,93 +349,6 @@ block_t *parser_t::current_block()
|
|||
return block_stack.empty() ? NULL : block_stack.back();
|
||||
}
|
||||
|
||||
/**
|
||||
Search the text for the end of the current block
|
||||
*/
|
||||
static const wchar_t *parser_find_end(const wchar_t * buff)
|
||||
{
|
||||
int had_cmd=0;
|
||||
int count = 0;
|
||||
int error=0;
|
||||
int mark=0;
|
||||
|
||||
CHECK(buff, 0);
|
||||
|
||||
tokenizer_t tok(buff, 0);
|
||||
for (; tok_has_next(&tok) && !error; tok_next(&tok))
|
||||
{
|
||||
int last_type = tok_last_type(&tok);
|
||||
switch (last_type)
|
||||
{
|
||||
case TOK_STRING:
|
||||
{
|
||||
if (!had_cmd)
|
||||
{
|
||||
if (wcscmp(tok_last(&tok), L"end")==0)
|
||||
{
|
||||
count--;
|
||||
}
|
||||
else if (parser_keywords_is_block(tok_last(&tok)))
|
||||
{
|
||||
count++;
|
||||
}
|
||||
|
||||
if (count < 0)
|
||||
{
|
||||
error = 1;
|
||||
}
|
||||
had_cmd = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TOK_END:
|
||||
{
|
||||
had_cmd = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case TOK_PIPE:
|
||||
case TOK_BACKGROUND:
|
||||
{
|
||||
if (had_cmd)
|
||||
{
|
||||
had_cmd = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
error = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case TOK_ERROR:
|
||||
error = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
if (!count)
|
||||
{
|
||||
tok_next(&tok);
|
||||
mark = tok_get_pos(&tok);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
if (!count && !error)
|
||||
{
|
||||
|
||||
return buff+mark;
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void parser_t::forbid_function(const wcstring &function)
|
||||
{
|
||||
forbidden_function.push_back(function);
|
||||
|
@ -826,29 +739,11 @@ const wchar_t *parser_t::is_function() const
|
|||
|
||||
int parser_t::get_lineno() const
|
||||
{
|
||||
if (parser_use_ast())
|
||||
int lineno = -1;
|
||||
if (! execution_contexts.empty())
|
||||
{
|
||||
int lineno = -1;
|
||||
if (! execution_contexts.empty())
|
||||
{
|
||||
lineno = execution_contexts.back()->get_current_line_number();
|
||||
}
|
||||
return lineno;
|
||||
lineno = execution_contexts.back()->get_current_line_number();
|
||||
}
|
||||
|
||||
int lineno;
|
||||
|
||||
if (! current_tokenizer || ! tok_string(current_tokenizer))
|
||||
return -1;
|
||||
|
||||
lineno = current_tokenizer->line_number_of_character_at_offset(current_tokenizer_pos);
|
||||
|
||||
const wchar_t *function_name;
|
||||
if ((function_name = is_function()))
|
||||
{
|
||||
lineno += function_get_definition_offset(function_name);
|
||||
}
|
||||
|
||||
return lineno;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue