aboutsummaryrefslogtreecommitdiffhomepage
path: root/builtin.cpp
diff options
context:
space:
mode:
authorGravatar Julian Aron Prenner <julian@linux4you.it>2014-01-15 15:27:06 +0100
committerGravatar Julian Aron Prenner <julian@linux4you.it>2014-01-15 15:27:06 +0100
commit213e9070446b60c9e6ad7140a6063cd957f241e4 (patch)
tree84020202d4daa8df2db3b2533e8963217bb46c49 /builtin.cpp
parentc8d5131a42b8117987d2a278d69edb21a7cf9383 (diff)
parent370b47d23f3cfde3e385c2268adb95229f0f7ed7 (diff)
Merge remote-tracking branch 'upstream/master' into bind_mode
Conflicts: builtin.cpp reader.cpp share/functions/fish_default_key_bindings.fish
Diffstat (limited to 'builtin.cpp')
-rw-r--r--builtin.cpp436
1 files changed, 397 insertions, 39 deletions
diff --git a/builtin.cpp b/builtin.cpp
index 87f4f406..96a358ba 100644
--- a/builtin.cpp
+++ b/builtin.cpp
@@ -64,6 +64,7 @@
#include "expand.h"
#include "path.h"
#include "history.h"
+#include "parse_tree.h"
/**
The default prompt for the read command
@@ -164,7 +165,7 @@ static const io_chain_t *real_io;
/**
Counts the number of non null pointers in the specified array
*/
-static int builtin_count_args(wchar_t **argv)
+static int builtin_count_args(const wchar_t * const * argv)
{
int argc = 1;
while (argv[argc] != NULL)
@@ -243,9 +244,6 @@ wcstring builtin_help_get(parser_t &parser, const wchar_t *name)
static void builtin_print_help(parser_t &parser, const wchar_t *cmd, wcstring &b)
{
-
- int is_short = 0;
-
if (&b == &stderr_buffer)
{
stderr_buffer.append(parser.current_line());
@@ -259,7 +257,7 @@ static void builtin_print_help(parser_t &parser, const wchar_t *cmd, wcstring &b
wchar_t *str = wcsdup(h.c_str());
if (str)
{
-
+ bool is_short = false;
if (&b == &stderr_buffer)
{
@@ -278,7 +276,7 @@ static void builtin_print_help(parser_t &parser, const wchar_t *cmd, wcstring &b
int cut=0;
int i;
- is_short = 1;
+ is_short = true;
/*
First move down 4 lines
@@ -789,7 +787,6 @@ static int builtin_block(parser_t &parser, wchar_t **argv)
int scope=UNSET;
int erase = 0;
int argc=builtin_count_args(argv);
- int type = (1<<EVENT_ANY);
woptind=0;
@@ -887,7 +884,7 @@ static int builtin_block(parser_t &parser, wchar_t **argv)
block_t *block = parser.block_at_index(block_idx);
event_blockage_t eb = {};
- eb.typemask = type;
+ eb.typemask = (1<<EVENT_ANY);
switch (scope)
{
@@ -1093,20 +1090,22 @@ static int builtin_emit(parser_t &parser, wchar_t **argv)
static int builtin_generic(parser_t &parser, wchar_t **argv)
{
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;
+ }
+
woptind=0;
static const struct woption
long_options[] =
{
- {
- L"help", no_argument, 0, 'h'
- }
- ,
- {
- 0, 0, 0, 0
- }
- }
- ;
+ { L"help", no_argument, 0, 'h' },
+ { 0, 0, 0, 0 }
+ };
while (1)
{
@@ -1803,12 +1802,325 @@ 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) */
+int define_function(parser_t &parser, const wcstring_list_t &c_args, const wcstring &contents, wcstring *out_err)
+{
+ assert(out_err != NULL);
+
+ /* wgetopt expects 'function' as the first argument. Make a new wcstring_list with that property. */
+ wcstring_list_t args;
+ args.push_back(L"function");
+ args.insert(args.end(), c_args.begin(), c_args.end());
+
+ /* Hackish const_cast matches the one in builtin_run */
+ const null_terminated_array_t<wchar_t> argv_array(args);
+ wchar_t **argv = const_cast<wchar_t **>(argv_array.get());
+
+ 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;
+
+ 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(*out_err,
+ 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(*out_err,
+ _(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(*out_err,
+ _(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(*out_err,
+ _(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(*out_err,
+ _(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':
+ 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(*out_err,
+ _(L"%ls: Expected function name\n"),
+ argv[0]);
+ res=1;
+ }
+ else if (wcsfuncname(argv[woptind]))
+ {
+ append_format(*out_err,
+ _(L"%ls: Illegal function name '%ls'\n"),
+ argv[0],
+ argv[woptind]);
+
+ res=1;
+ }
+ else if (parser_keywords_is_reserved(argv[woptind]))
+ {
+
+ append_format(*out_err,
+ _(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(*out_err, _(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(*out_err,
+ _(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(*out_err,
+ _(L"%ls: Expected one argument, got %d\n"),
+ argv[0],
+ argc);
+ res=1;
+
+ }
+ }
+ }
+
+ if (res)
+ {
+ builtin_print_help(parser, argv[0], *out_err);
+ }
+ else
+ {
+ function_data_t d;
+
+ 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;
+ }
+
+ d.definition = contents.c_str();
+
+ // TODO: fix def_offset inside function_add
+ function_add(d, parser);
+ }
+
+ 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;
@@ -1921,7 +2233,7 @@ static int builtin_function(parser_t &parser, wchar_t **argv)
if (is_subshell)
{
size_t block_idx = 0;
-
+
/* Find the outermost substitution block */
for (block_idx = 0; ; block_idx++)
{
@@ -1929,7 +2241,7 @@ static int builtin_function(parser_t &parser, wchar_t **argv)
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)
@@ -2034,6 +2346,10 @@ static int builtin_function(parser_t &parser, wchar_t **argv)
res=1;
}
+ else if (! wcslen(argv[woptind]))
+ {
+ append_format(stderr_buffer, _(L"%ls: No function name given\n"), argv[0]);
+ }
else
{
@@ -3070,10 +3386,7 @@ static int builtin_source(parser_t &parser, wchar_t ** argv)
argc = builtin_count_args(argv);
- const wchar_t *fn;
- const wchar_t *fn_intern;
-
-
+ const wchar_t *fn, *fn_intern;
if (argc < 2 || (wcscmp(argv[1], L"-") == 0))
{
@@ -3106,18 +3419,7 @@ static int builtin_source(parser_t &parser, wchar_t ** argv)
return STATUS_BUILTIN_ERROR;
}
- fn = wrealpath(argv[1], NULL);
-
- if (!fn)
- {
- fn_intern = intern(argv[1]);
- }
- else
- {
- fn_intern = intern(fn);
- free((void *)fn);
- }
-
+ fn_intern = intern(argv[1]);
}
parser.push_block(new source_block_t(fn_intern));
@@ -3421,6 +3723,12 @@ static int builtin_for(parser_t &parser, wchar_t **argv)
int argc = builtin_count_args(argv);
int res=STATUS_BUILTIN_ERROR;
+ /* 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 < 3)
{
@@ -3709,7 +4017,7 @@ static int builtin_break_continue(parser_t &parser, wchar_t **argv)
{
parser.block_at_index(block_idx)->skip = true;
}
-
+
/* Skip the loop itself */
block_t *loop_block = parser.block_at_index(loop_idx);
loop_block->skip = true;
@@ -3787,7 +4095,7 @@ static int builtin_return(parser_t &parser, wchar_t **argv)
builtin_print_help(parser, argv[0], stderr_buffer);
return STATUS_BUILTIN_ERROR;
}
-
+
/* Skip everything up to (and then including) the function block */
for (size_t i=0; i < function_block_idx; i++)
{
@@ -3808,6 +4116,13 @@ 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,
@@ -4012,6 +4327,49 @@ static int builtin_history(parser_t &parser, wchar_t **argv)
return STATUS_BUILTIN_ERROR;
}
+#pragma mark Simulator
+
+int builtin_parse(parser_t &parser, wchar_t **argv)
+{
+ struct sigaction act;
+ sigemptyset(& act.sa_mask);
+ act.sa_flags=0;
+ act.sa_handler=SIG_DFL;
+ sigaction(SIGINT, &act, 0);
+
+ std::vector<char> txt;
+ for (;;)
+ {
+ char buff[256];
+ ssize_t amt = read_loop(builtin_stdin, buff, sizeof buff);
+ if (amt <= 0) break;
+ txt.insert(txt.end(), buff, buff + amt);
+ }
+ if (! txt.empty())
+ {
+ const wcstring src = str2wcstring(&txt.at(0), txt.size());
+ parse_node_tree_t parse_tree;
+ parse_error_list_t errors;
+ bool success = parse_tree_from_string(src, parse_flag_none, &parse_tree, &errors);
+ if (! success)
+ {
+ stdout_buffer.append(L"Parsing failed:\n");
+ for (size_t i=0; i < errors.size(); i++)
+ {
+ stdout_buffer.append(errors.at(i).describe(src));
+ stdout_buffer.push_back(L'\n');
+ }
+
+ stdout_buffer.append(L"(Reparsed with continue after error)\n");
+ parse_tree.clear();
+ errors.clear();
+ parse_tree_from_string(src, parse_flag_continue_after_error, &parse_tree, &errors);
+ }
+ const wcstring dump = parse_dump_tree(parse_tree, src);
+ stdout_buffer.append(dump);
+ }
+ return STATUS_BUILTIN_OK;
+}
/*
END OF BUILTIN COMMANDS
@@ -4027,6 +4385,7 @@ static int builtin_history(parser_t &parser, wchar_t **argv)
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"bg", &builtin_bg, N_(L"Send job to background") },
@@ -4171,7 +4530,7 @@ void builtin_get_names(std::vector<completion_t> &list)
{
for (size_t i=0; i < BUILTIN_COUNT; i++)
{
- list.push_back(completion_t(builtin_datas[i].name));
+ append_completion(list, builtin_datas[i].name);
}
}
@@ -4218,4 +4577,3 @@ void builtin_pop_io(parser_t &parser)
builtin_stdin = 0;
}
}
-