diff options
author | ridiculousfish <corydoras@ridiculousfish.com> | 2014-03-29 14:19:45 -0700 |
---|---|---|
committer | ridiculousfish <corydoras@ridiculousfish.com> | 2014-03-29 14:19:45 -0700 |
commit | d4fafeb6d66e415e85c67700e5a370765c09bb93 (patch) | |
tree | 7e208d860649e8651180b281ec715a96169a9dbe /builtin.cpp | |
parent | 844b01cb6be2ab3a3f7070112c94604b43710835 (diff) | |
parent | 31bf50b2d495222925371556169f61c1c5a81ed7 (diff) |
Merge branch 'master' into 1218_rebase
Conflicts:
builtin.cpp
builtin_commandline.cpp
highlight.cpp
input.cpp
input.h
reader.cpp
screen.cpp
screen.h
Diffstat (limited to 'builtin.cpp')
-rw-r--r-- | builtin.cpp | 752 |
1 files changed, 24 insertions, 728 deletions
diff --git a/builtin.cpp b/builtin.cpp index 96a358ba..07d89403 100644 --- a/builtin.cpp +++ b/builtin.cpp @@ -576,8 +576,7 @@ static int builtin_bind(parser_t &parser, wchar_t **argv) BIND_ERASE, BIND_KEY_NAMES, BIND_FUNCTION_NAMES - } - ; + }; int argc=builtin_count_args(argv); int mode = BIND_INSERT; @@ -593,46 +592,18 @@ static int builtin_bind(parser_t &parser, wchar_t **argv) woptind=0; - static const struct woption - long_options[] = + static const struct woption long_options[] = { - { - L"all", no_argument, 0, 'a' - } - , - { - L"erase", no_argument, 0, 'e' - } - , - { - L"function-names", no_argument, 0, 'f' - } - , - { - L"help", no_argument, 0, 'h' - } - , - { - L"key", no_argument, 0, 'k' - } - , - { - L"key-names", no_argument, 0, 'K' - } - , - { - L"mode", required_argument, 0, 'M' - } - , - { - L"sets-mode", required_argument, 0, 'm' - } - , - { - 0, 0, 0, 0 - } - } - ; + { L"all", no_argument, 0, 'a' }, + { L"erase", no_argument, 0, 'e' }, + { L"function-names", no_argument, 0, 'f' }, + { L"help", no_argument, 0, 'h' }, + { L"key", no_argument, 0, 'k' }, + { L"key-names", no_argument, 0, 'K' }, + { L"mode", required_argument, 0, 'M' }, + { L"sets-mode", required_argument, 0, 'm' }, + { 0, 0, 0, 0 } + }; while (1) { @@ -1802,8 +1773,8 @@ 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) +/** 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, int definition_line_offset, wcstring *out_err) { assert(out_err != NULL); @@ -2101,346 +2072,13 @@ int define_function(parser_t &parser, const wcstring_list_t &c_args, const wcstr d.definition = contents.c_str(); - // TODO: fix def_offset inside function_add - function_add(d, parser); + function_add(d, parser, definition_line_offset); } 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. */ static int builtin_random(parser_t &parser, wchar_t **argv) @@ -3716,263 +3354,6 @@ static int builtin_bg(parser_t &parser, wchar_t **argv) /** - Builtin for looping over a list -*/ -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) - { - append_format(stderr_buffer, - BUILTIN_FOR_ERR_COUNT, - argv[0] , - argc); - builtin_print_help(parser, argv[0], stderr_buffer); - } - else if (wcsvarname(argv[1])) - { - append_format(stderr_buffer, - BUILTIN_FOR_ERR_NAME, - argv[0], - argv[1]); - builtin_print_help(parser, argv[0], stderr_buffer); - } - else if (wcscmp(argv[2], L"in") != 0) - { - append_format(stderr_buffer, - BUILTIN_FOR_ERR_IN, - argv[0]); - builtin_print_help(parser, argv[0], stderr_buffer); - } - else - { - res=0; - } - - - if (res) - { - parser.push_block(new fake_block_t()); - } - else - { - const wchar_t *for_variable = argv[1]; - for_block_t *fb = new for_block_t(for_variable); - parser.push_block(fb); - fb->tok_pos = parser.get_pos(); - - /* Note that we store the sequence of values in opposite order */ - wcstring_list_t &for_vars = fb->sequence; - for (int i=argc-1; i>3; i--) - for_vars.push_back(argv[i]); - - if (argc > 3) - { - env_set(for_variable, argv[3], ENV_LOCAL); - } - else - { - parser.current_block()->skip=1; - } - } - 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: - 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. */ @@ -4100,7 +3481,6 @@ static int builtin_return(parser_t &parser, wchar_t **argv) for (size_t i=0; i < function_block_idx; i++) { block_t *b = parser.block_at_index(i); - b->mark_as_fake(); b->skip = true; } parser.block_at_index(function_block_idx)->skip = true; @@ -4108,90 +3488,6 @@ static int builtin_return(parser_t &parser, wchar_t **argv) } /** - 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 */ static int builtin_history(parser_t &parser, wchar_t **argv) @@ -4387,14 +3683,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") }, @@ -4403,14 +3699,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"for", &builtin_generic, N_(L"Perform a set of commands multiple times") }, + { 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") }, @@ -4426,7 +3722,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") } @@ -4492,7 +3788,7 @@ int builtin_run(parser_t &parser, const wchar_t * const *argv, const io_chain_t if (argv[1] != 0 && !internal_help(argv[0])) { - if (argv[2] == 0 && (parser.is_help(argv[1], 0))) + if (argv[2] == 0 && (parse_util_argument_is_help(argv[1], 0))) { builtin_print_help(parser, argv[0], stdout_buffer); return STATUS_BUILTIN_OK; @@ -4509,7 +3805,7 @@ int builtin_run(parser_t &parser, const wchar_t * const *argv, const io_chain_t } else { - debug(0, _(L"Unknown builtin '%ls'"), argv[0]); + debug(0, UNKNOWN_BUILTIN_ERR_MSG, argv[0]); } return STATUS_BUILTIN_ERROR; } |