diff options
author | Julian Aron Prenner <julian@linux4you.it> | 2014-01-15 15:27:06 +0100 |
---|---|---|
committer | Julian Aron Prenner <julian@linux4you.it> | 2014-01-15 15:27:06 +0100 |
commit | 213e9070446b60c9e6ad7140a6063cd957f241e4 (patch) | |
tree | 84020202d4daa8df2db3b2533e8963217bb46c49 /builtin.cpp | |
parent | c8d5131a42b8117987d2a278d69edb21a7cf9383 (diff) | |
parent | 370b47d23f3cfde3e385c2268adb95229f0f7ed7 (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.cpp | 436 |
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; } } - |