Beispiel #1
0
static int recv_req(req_t *req)
{
/*  Receives the request from the client after the greeting has completed.
 *  Returns 0 if the request is read OK, or -1 on error.
 */
    int n;
    char buf[MAX_SOCK_LINE];
    Lex l;
    int done = 0;
    int tok;

    assert(req->sd >= 0);

    if ((n = read_line(req->sd, buf, sizeof(buf))) < 0) {
        log_msg(LOG_NOTICE, "Unable to read request from <%s:%d>: %s",
            req->fqdn, req->port, strerror(errno));
        return(-1);
    }
    else if (n == 0) {
        log_msg(LOG_NOTICE, "Connection terminated by <%s:%d>",
            req->fqdn, req->port);
        return(-1);
    }

    DPRINTF((5, "Received request: %s", buf));

    l = lex_create(buf, proto_strs);
    while (!done) {
        tok = lex_next(l);
        switch(tok) {
        case CONMAN_TOK_CONNECT:
            req->command = CONMAN_CMD_CONNECT;
            parse_cmd_opts(l, req);
            break;
        case CONMAN_TOK_MONITOR:
            req->command = CONMAN_CMD_MONITOR;
            parse_cmd_opts(l, req);
            break;
        case CONMAN_TOK_QUERY:
            req->command = CONMAN_CMD_QUERY;
            parse_cmd_opts(l, req);
            break;
        case LEX_EOF:
        case LEX_EOL:
            done = 1;
            break;
        default:
            break;
        }
    }
    lex_destroy(l);

    return(0);
}
Beispiel #2
0
/// The math builtin evaluates math expressions.
int builtin_math(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
    wchar_t *cmd = argv[0];
    int argc = builtin_count_args(argv);
    math_cmd_opts_t opts;
    int optind;

    // Is this really the right way to handle no expression present?
    // if (argc == 0) return STATUS_CMD_OK;

    int retval = parse_cmd_opts(opts, &optind, argc, argv, parser, streams);
    if (retval != STATUS_CMD_OK) return retval;

    if (opts.print_help) {
        builtin_print_help(parser, streams, cmd, streams.out);
        return STATUS_CMD_OK;
    }

    wcstring expression;
    wcstring storage;
    while (const wchar_t *arg = math_get_arg(&optind, argv, &storage, streams)) {
        if (!expression.empty()) expression.push_back(L' ');
        expression.append(arg);
    }

    if (expression.empty()) {
        streams.err.append_format(BUILTIN_ERR_MIN_ARG_COUNT1, L"math", 1, 0);
        return STATUS_CMD_ERROR;
    }
    return evaluate_expression(cmd, parser, streams, opts, expression);
}
Beispiel #3
0
/// The exit builtin. Calls reader_exit to exit and returns the value specified.
int builtin_exit(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
    const wchar_t *cmd = argv[0];
    int argc = builtin_count_args(argv);
    exit_cmd_opts_t opts;

    int optind;
    int retval = parse_cmd_opts(opts, &optind, argc, argv, parser, streams);
    if (retval != STATUS_CMD_OK) return retval;

    if (opts.print_help) {
        builtin_print_help(parser, streams, cmd, streams.out);
        return STATUS_CMD_OK;
    }

    if (optind + 1 < argc) {
        streams.err.append_format(BUILTIN_ERR_TOO_MANY_ARGUMENTS, cmd);
        builtin_print_help(parser, streams, cmd, streams.err);
        return STATUS_INVALID_ARGS;
    }

    if (optind == argc) {
        retval = proc_get_last_status();
    } else {
        retval = fish_wcstoi(argv[optind]);
        if (errno) {
            streams.err.append_format(_(L"%ls: Argument '%ls' must be an integer\n"), cmd,
                                      argv[optind]);
            builtin_print_help(parser, streams, cmd, streams.err);
            return STATUS_INVALID_ARGS;
        }
    }
    reader_exit(1, 0);
    return retval;
}
/// Implementation of the builtin contains command, used to check if a specified string is part of
/// a list.
int builtin_contains(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
    const wchar_t *cmd = argv[0];
    int argc = builtin_count_args(argv);
    contains_cmd_opts_t opts;

    int optind;
    int retval = parse_cmd_opts(opts, &optind, argc, argv, parser, streams);
    if (retval != STATUS_CMD_OK) return retval;

    if (opts.print_help) {
        builtin_print_help(parser, streams, cmd, streams.out);
        return STATUS_CMD_OK;
    }

    wchar_t *needle = argv[optind];
    if (!needle) {
        streams.err.append_format(_(L"%ls: Key not specified\n"), cmd);
    } else {
        for (int i = optind + 1; i < argc; i++) {
            if (!std::wcscmp(needle, argv[i])) {
                if (opts.print_index) streams.out.append_format(L"%d\n", i - optind);
                return STATUS_CMD_OK;
            }
        }
    }

    return STATUS_CMD_ERROR;
}
/// The builtin builtin, used for giving builtins precedence over functions. Mostly handled by the
/// parser. All this code does is some additional operational modes, such as printing a list of all
/// builtins, printing help, etc.
int builtin_builtin(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
    const wchar_t *cmd = argv[0];
    int argc = builtin_count_args(argv);
    builtin_cmd_opts_t opts;

    int optind;
    int retval = parse_cmd_opts(opts, &optind, argc, argv, parser, streams);
    if (retval != STATUS_CMD_OK) return retval;

    if (opts.print_help) {
        builtin_print_help(parser, streams, cmd, streams.out);
        return STATUS_CMD_OK;
    }

    if (opts.query && opts.list_names) {
        streams.err.append_format(BUILTIN_ERR_COMBO2, cmd,
                                  _(L"--query and --names are mutually exclusive"));
        return STATUS_INVALID_ARGS;
    }

    if (opts.query) {
        wcstring_list_t names = builtin_get_names();
        retval = STATUS_CMD_ERROR;
        for (int i = optind; i < argc; i++) {
            if (contains(names, argv[i])) {
                retval = STATUS_CMD_OK;
                break;
            }
        }
        return retval;
    }

    if (opts.list_names) {
        wcstring_list_t names = builtin_get_names();
        std::sort(names.begin(), names.end());

        for (size_t i = 0; i < names.size(); i++) {
            const wchar_t *el = names.at(i).c_str();

            streams.out.append(el);
            streams.out.append(L"\n");
        }
    }

    return STATUS_CMD_OK;
}
Beispiel #6
0
Datei: s2.cpp Projekt: dCache/s2
int
main(int argc, char *argv[])
{
  int i;					/* loop counter */

  /* Initialisation */
  init_s2();

  /* Close all open diagnose streams at exit */
  atexit(exit_handler);         /* normal exit */

  /* Parse command line options */
  i = parse_cmd_opts(argc, argv);

  tp_init(opts.tp_size);

#if 0
#define MAX_REQUESTS	5
  int data[MAX_REQUESTS];
  /* run a loop that generates requests */
  for (i = 0; i < MAX_REQUESTS; i++) {
    data[i] = i;
    tp_enqueue(&data[i], NULL, NULL);
  }
#else
  int a = 1, b = 2, c = 3, d = 4;

  sleep(1);
  tp_enqueue(&a, NULL, NULL);
  tp_enqueue(&b, NULL, NULL);
  tp_enqueue(&c, NULL, NULL);
  tp_enqueue(&d, NULL, NULL);
  tp_dequeue(&c);
#endif

//  sleep(10);

  tp_cleanup();

  /* Parse and evaluate S2 language file(s) */
  if(0) s2_run(argc, argv, i);

  return 0;
}
Beispiel #7
0
Datei: s2.cpp Projekt: dCache/s2
int
main(int argc, char *argv[])
{
  int i;
  uint rval;

  /* Initialisation */
  init_s2();

  /* Close all open diagnose streams at exit */
  atexit(exit_handler);         /* normal exit */

  /* Parse command line options */
  i = parse_cmd_opts(argc, argv);

  /* Parse and evaluate S2 language file(s) */
  rval = s2_run(argc, argv, i);

  return (int)rval;
}
/// Implementation of the builtin 'command'. Actual command running is handled by the parser, this
/// just processes the flags.
int builtin_command(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
    const wchar_t *cmd = argv[0];
    int argc = builtin_count_args(argv);
    command_cmd_opts_t opts;

    int optind;
    int retval = parse_cmd_opts(opts, &optind, argc, argv, parser, streams);
    if (retval != STATUS_CMD_OK) return retval;

    if (opts.print_help) {
        builtin_print_help(parser, streams, cmd, streams.out);
        return STATUS_CMD_OK;
    }

    if (!opts.find_path && !opts.all_paths) {
        builtin_print_help(parser, streams, cmd, streams.out);
        return STATUS_INVALID_ARGS;
    }

    int found = 0;
    for (int idx = optind; argv[idx]; ++idx) {
        const wchar_t *command_name = argv[idx];
        if (opts.all_paths) {
            wcstring_list_t paths = path_get_paths(command_name);
            for (auto path : paths) {
                if (!opts.quiet) streams.out.append_format(L"%ls\n", path.c_str());
                ++found;
            }
        } else {
            wcstring path;
            if (path_get_path(command_name, &path)) {
                if (!opts.quiet) streams.out.append_format(L"%ls\n", path.c_str());
                ++found;
            }
        }
    }

    return found ? STATUS_CMD_OK : STATUS_CMD_ERROR;
}
Beispiel #9
0
/// The set builtin creates, updates, and erases (removes, deletes) variables.
int builtin_set(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
    const int incoming_exit_status = proc_get_last_status();
    wchar_t *cmd = argv[0];
    int argc = builtin_count_args(argv);
    set_cmd_opts_t opts;

    int optind;
    int retval = parse_cmd_opts(opts, &optind, argc, argv, parser, streams);
    if (retval != STATUS_CMD_OK) return retval;
    argv += optind;
    argc -= optind;

    if (opts.print_help) {
        builtin_print_help(parser, streams, cmd, streams.out);
        return STATUS_CMD_OK;
    }

    retval = validate_cmd_opts(cmd, opts, argc, parser, streams);
    if (retval != STATUS_CMD_OK) return retval;

    if (opts.query) {
        retval = builtin_set_query(cmd, opts, argc, argv, parser, streams);
    } else if (opts.erase) {
        retval = builtin_set_erase(cmd, opts, argc, argv, parser, streams);
    } else if (opts.list) {  // explicit list the vars we know about
        retval = builtin_set_list(cmd, opts, argc, argv, parser, streams);
    } else if (opts.show) {
        retval = builtin_set_show(cmd, opts, argc, argv, parser, streams);
    } else if (argc == 0) {  // implicit list the vars we know about
        retval = builtin_set_list(cmd, opts, argc, argv, parser, streams);
    } else {
        retval = builtin_set_set(cmd, opts, argc, argv, parser, streams);
    }

    if (retval == STATUS_CMD_OK && opts.preserve_failure_exit_status) retval = incoming_exit_status;
    return retval;
}
Beispiel #10
0
/// The block builtin, used for temporarily blocking events.
int builtin_block(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
    const wchar_t *cmd = argv[0];
    int argc = builtin_count_args(argv);
    block_cmd_opts_t opts;

    int optind;
    int retval = parse_cmd_opts(opts, &optind, argc, argv, parser, streams);
    if (retval != STATUS_CMD_OK) return retval;

    if (opts.print_help) {
        builtin_print_help(parser, streams, cmd, streams.out);
        return STATUS_CMD_OK;
    }

    if (opts.erase) {
        if (opts.scope != UNSET) {
            streams.err.append_format(_(L"%ls: Can not specify scope when removing block\n"), cmd);
            return STATUS_INVALID_ARGS;
        }

        if (parser.global_event_blocks.empty()) {
            streams.err.append_format(_(L"%ls: No blocks defined\n"), cmd);
            return STATUS_CMD_ERROR;
        }
        parser.global_event_blocks.pop_front();
        return STATUS_CMD_OK;
    }

    size_t block_idx = 0;
    block_t *block = parser.block_at_index(block_idx);

    event_blockage_t eb = {};
    eb.typemask = (1 << EVENT_ANY);

    switch (opts.scope) {
        case LOCAL: {
            // If this is the outermost block, then we're global
            if (block_idx + 1 >= parser.block_count()) {
                block = NULL;
            }
            break;
        }
        case GLOBAL: {
            block = NULL;
            break;
        }
        case UNSET: {
            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);
            }
            break;
        }
        default: {
            DIE("unexpected scope");
            break;
        }
    }
    if (block) {
        block->event_blocks.push_front(eb);
    } else {
        parser.global_event_blocks.push_front(eb);
    }

    return STATUS_CMD_OK;
}
Beispiel #11
0
/// Manipulate history of interactive commands executed by the user.
int builtin_history(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
    wchar_t *cmd = argv[0];
    int argc = builtin_count_args(argv);
    history_cmd_opts_t opts;

    int optind;
    int retval = parse_cmd_opts(opts, &optind, argc, argv, parser, streams);
    if (retval != STATUS_CMD_OK) return retval;

    if (opts.print_help) {
        builtin_print_help(parser, streams, cmd, streams.out);
        return STATUS_CMD_OK;
    }

    // Use the default history if we have none (which happens if invoked non-interactively, e.g.
    // from webconfig.py.
    history_t *history = reader_get_history();
    if (!history) history = &history_t::history_with_name(L"fish");

    // If a history command hasn't already been specified via a flag check the first word.
    // Note that this can be simplified after we eliminate allowing subcommands as flags.
    // See the TODO above regarding the `long_options` array.
    if (optind < argc) {
        hist_cmd_t subcmd = str_to_enum(argv[optind], hist_enum_map, hist_enum_map_len);
        if (subcmd != HIST_UNDEF) {
            if (!set_hist_cmd(cmd, &opts.hist_cmd, subcmd, streams)) {
                return STATUS_INVALID_ARGS;
            }
            optind++;
        }
    }

    // Every argument that we haven't consumed already is an argument for a subcommand (e.g., a
    // search term).
    const wcstring_list_t args(argv + optind, argv + argc);

    // Establish appropriate defaults.
    if (opts.hist_cmd == HIST_UNDEF) opts.hist_cmd = HIST_SEARCH;
    if (!opts.history_search_type_defined) {
        if (opts.hist_cmd == HIST_SEARCH) opts.search_type = HISTORY_SEARCH_TYPE_CONTAINS;
        if (opts.hist_cmd == HIST_DELETE) opts.search_type = HISTORY_SEARCH_TYPE_EXACT;
    }

    int status = STATUS_CMD_OK;
    switch (opts.hist_cmd) {
        case HIST_SEARCH: {
            if (!history->search(opts.search_type, args, opts.show_time_format, opts.max_items,
                                 opts.case_sensitive, opts.null_terminate, streams)) {
                status = STATUS_CMD_ERROR;
            }
            break;
        }
        case HIST_DELETE: {
            // TODO: Move this code to the history module and support the other search types
            // including case-insensitive matches. At this time we expect the non-exact deletions to
            // be handled only by the history function's interactive delete feature.
            if (opts.search_type != HISTORY_SEARCH_TYPE_EXACT) {
                streams.err.append_format(_(L"builtin history delete only supports --exact\n"));
                status = STATUS_INVALID_ARGS;
                break;
            }
            if (!opts.case_sensitive) {
                streams.err.append_format(
                    _(L"builtin history delete only supports --case-sensitive\n"));
                status = STATUS_INVALID_ARGS;
                break;
            }
            for (wcstring_list_t::const_iterator iter = args.begin(); iter != args.end(); ++iter) {
                wcstring delete_string = *iter;
                if (delete_string[0] == '"' && delete_string[delete_string.length() - 1] == '"') {
                    delete_string = delete_string.substr(1, delete_string.length() - 2);
                }
                history->remove(delete_string);
            }
            break;
        }
        case HIST_CLEAR: {
            CHECK_FOR_UNEXPECTED_HIST_ARGS(opts.hist_cmd)
            history->clear();
            history->save();
            break;
        }
        case HIST_MERGE: {
            CHECK_FOR_UNEXPECTED_HIST_ARGS(opts.hist_cmd)
            history->incorporate_external_changes();
            break;
        }
        case HIST_SAVE: {
            CHECK_FOR_UNEXPECTED_HIST_ARGS(opts.hist_cmd)
            history->save();
            break;
        }
        case HIST_UNDEF: {
            DIE("Unexpected HIST_UNDEF seen");
            break;
        }
    }

    return status;
}
Beispiel #12
0
/// The bind builtin, used for setting character sequences.
int builtin_bind_t::builtin_bind(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
    wchar_t *cmd = argv[0];
    int argc = builtin_count_args(argv);
    bind_cmd_opts_t opts;
    this->opts = &opts;

    int optind;
    int retval = parse_cmd_opts(opts, &optind, argc, argv, parser, streams);
    if (retval != STATUS_CMD_OK) return retval;

    if (opts.list_modes) {
        list_modes(streams);
        return STATUS_CMD_OK;
    }
    if (opts.print_help) {
        builtin_print_help(parser, streams, cmd, streams.out);
        return STATUS_CMD_OK;
    }

    // Default to user mode
    if (!opts.have_preset && !opts.have_user) opts.user = true;
    switch (opts.mode) {
        case BIND_ERASE: {
            const wchar_t *bind_mode = opts.bind_mode_given ? opts.bind_mode : NULL;
            // If we get both, we erase both.
            if (opts.user) {
                if (erase(&argv[optind], opts.all, bind_mode, opts.use_terminfo, /* user */ true,
                          streams)) {
                    return STATUS_CMD_ERROR;
                }
            }
            if (opts.preset) {
                if (erase(&argv[optind], opts.all, bind_mode, opts.use_terminfo, /* user */ false,
                          streams)) {
                    return STATUS_CMD_ERROR;
                }
            }
            break;
        }
        case BIND_INSERT: {
            if (insert(optind, argc, argv, streams)) {
                return STATUS_CMD_ERROR;
            }
            break;
        }
        case BIND_KEY_NAMES: {
            key_names(opts.all, streams);
            break;
        }
        case BIND_FUNCTION_NAMES: {
            function_names(streams);
            break;
        }
        default: {
            streams.err.append_format(_(L"%ls: Invalid state\n"), cmd);
            return STATUS_CMD_ERROR;
        }
    }

    return STATUS_CMD_OK;
}
Beispiel #13
0
/// The status builtin. Gives various status information on fish.
int builtin_status(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
    wchar_t *cmd = argv[0];
    int argc = builtin_count_args(argv);
    status_cmd_opts_t opts;

    int optind;
    int retval = parse_cmd_opts(opts, &optind, argc, argv, parser, streams);
    if (retval != STATUS_CMD_OK) return retval;

    if (opts.print_help) {
        builtin_print_help(parser, streams, cmd, streams.out);
        return STATUS_CMD_OK;
    }

    // If a status command hasn't already been specified via a flag check the first word.
    // Note that this can be simplified after we eliminate allowing subcommands as flags.
    if (optind < argc) {
        status_cmd_t subcmd = str_to_enum(argv[optind], status_enum_map, status_enum_map_len);
        if (subcmd != STATUS_UNDEF) {
            if (!set_status_cmd(cmd, opts, subcmd, streams)) {
                return STATUS_CMD_ERROR;
            }
            optind++;
        } else {
            streams.err.append_format(BUILTIN_ERR_INVALID_SUBCMD, cmd, argv[1]);
            return STATUS_INVALID_ARGS;
        }
    }

    // Every argument that we haven't consumed already is an argument for a subcommand.
    const wcstring_list_t args(argv + optind, argv + argc);

    switch (opts.status_cmd) {
        case STATUS_UNDEF: {
            CHECK_FOR_UNEXPECTED_STATUS_ARGS(opts.status_cmd)
            if (is_login) {
                streams.out.append_format(_(L"This is a login shell\n"));
            } else {
                streams.out.append_format(_(L"This is not a login shell\n"));
            }

            streams.out.append_format(
                _(L"Job control: %ls\n"),
                job_control_mode == JOB_CONTROL_INTERACTIVE
                    ? _(L"Only on interactive jobs")
                    : (job_control_mode == JOB_CONTROL_NONE ? _(L"Never") : _(L"Always")));
            streams.out.append(parser.stack_trace());
            break;
        }
        case STATUS_SET_JOB_CONTROL: {
            if (opts.new_job_control_mode != -1) {
                // Flag form was used.
                CHECK_FOR_UNEXPECTED_STATUS_ARGS(opts.status_cmd)
            } else {
                if (args.size() != 1) {
                    const wchar_t *subcmd_str = enum_to_str(opts.status_cmd, status_enum_map);
                    streams.err.append_format(BUILTIN_ERR_ARG_COUNT2, cmd, subcmd_str, 1,
                                              args.size());
                    return STATUS_INVALID_ARGS;
                }
                opts.new_job_control_mode = job_control_str_to_mode(args[0].c_str(), cmd, streams);
                if (opts.new_job_control_mode == -1) {
                    return STATUS_CMD_ERROR;
                }
            }
            job_control_mode = opts.new_job_control_mode;
            break;
        }
        case STATUS_FEATURES: {
            print_features(streams);
            break;
        }
        case STATUS_TEST_FEATURE: {
            if (args.size() != 1) {
                const wchar_t *subcmd_str = enum_to_str(opts.status_cmd, status_enum_map);
                streams.err.append_format(BUILTIN_ERR_ARG_COUNT2, cmd, subcmd_str, 1, args.size());
                return STATUS_INVALID_ARGS;
            }
            const auto *metadata = features_t::metadata_for(args.front().c_str());
            if (!metadata) {
                retval = TEST_FEATURE_NOT_RECOGNIZED;
            } else {
                retval = feature_test(metadata->flag) ? TEST_FEATURE_ON : TEST_FEATURE_OFF;
            }
            break;
        }
        case STATUS_FILENAME: {
            CHECK_FOR_UNEXPECTED_STATUS_ARGS(opts.status_cmd)
            const wchar_t *fn = parser.current_filename();

            if (!fn) fn = _(L"Standard input");
            streams.out.append_format(L"%ls\n", fn);
            break;
        }
        case STATUS_FUNCTION: {
            CHECK_FOR_UNEXPECTED_STATUS_ARGS(opts.status_cmd)
            const wchar_t *fn = parser.get_function_name(opts.level);

            if (!fn) fn = _(L"Not a function");
            streams.out.append_format(L"%ls\n", fn);
            break;
        }
        case STATUS_LINE_NUMBER: {
            CHECK_FOR_UNEXPECTED_STATUS_ARGS(opts.status_cmd)
            // TBD is how to interpret the level argument when fetching the line number.
            // See issue #4161.
            // streams.out.append_format(L"%d\n", parser.get_lineno(opts.level));
            streams.out.append_format(L"%d\n", parser.get_lineno());
            break;
        }
        case STATUS_IS_INTERACTIVE: {
            CHECK_FOR_UNEXPECTED_STATUS_ARGS(opts.status_cmd)
            retval = !is_interactive_session;
            break;
        }
        case STATUS_IS_COMMAND_SUB: {
            CHECK_FOR_UNEXPECTED_STATUS_ARGS(opts.status_cmd)
            retval = !is_subshell;
            break;
        }
        case STATUS_IS_BLOCK: {
            CHECK_FOR_UNEXPECTED_STATUS_ARGS(opts.status_cmd)
            retval = !is_block;
            break;
        }
        case STATUS_IS_BREAKPOINT: {
            CHECK_FOR_UNEXPECTED_STATUS_ARGS(opts.status_cmd)
            retval = !is_breakpoint;
            break;
        }
        case STATUS_IS_LOGIN: {
            CHECK_FOR_UNEXPECTED_STATUS_ARGS(opts.status_cmd)
            retval = !is_login;
            break;
        }
        case STATUS_IS_FULL_JOB_CTRL: {
            CHECK_FOR_UNEXPECTED_STATUS_ARGS(opts.status_cmd)
            retval = job_control_mode != JOB_CONTROL_ALL;
            break;
        }
        case STATUS_IS_INTERACTIVE_JOB_CTRL: {
            CHECK_FOR_UNEXPECTED_STATUS_ARGS(opts.status_cmd)
            retval = job_control_mode != JOB_CONTROL_INTERACTIVE;
            break;
        }
        case STATUS_IS_NO_JOB_CTRL: {
            CHECK_FOR_UNEXPECTED_STATUS_ARGS(opts.status_cmd)
            retval = job_control_mode != JOB_CONTROL_NONE;
            break;
        }
        case STATUS_STACK_TRACE: {
            CHECK_FOR_UNEXPECTED_STATUS_ARGS(opts.status_cmd)
            streams.out.append(parser.stack_trace());
            break;
        }
        case STATUS_CURRENT_CMD: {
            CHECK_FOR_UNEXPECTED_STATUS_ARGS(opts.status_cmd)
            // HACK: Go via the deprecated variable to get the command.
            const auto var = env_get(L"_");
            if (!var.missing_or_empty()) {
                streams.out.append(var->as_string());
                streams.out.push_back(L'\n');
            } else {
                streams.out.append(program_name);
                streams.out.push_back(L'\n');
            }
            break;
        }
        case STATUS_FISH_PATH: {
            CHECK_FOR_UNEXPECTED_STATUS_ARGS(opts.status_cmd)
            streams.out.append(str2wcstring(get_executable_path("fish")));
            streams.out.push_back(L'\n');
            break;
        }
    }

    return retval;
}
/// Define a function. Calls into `function.cpp` to perform the heavy lifting of defining a
/// function.
int builtin_function(parser_t &parser, io_streams_t &streams, const wcstring_list_t &c_args,
                     const wcstring &contents, int definition_line_offset) {
    // The wgetopt function expects 'function' as the first argument. Make a new wcstring_list with
    // that property. This is needed because this builtin has a different signature than the other
    // builtins.
    wcstring_list_t args = {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());
    wchar_t *cmd = argv[0];
    int argc = builtin_count_args(argv);

    // A valid function name has to be the first argument.
    wcstring function_name;
    int retval = validate_function_name(argc, argv, function_name, cmd, streams);
    if (retval != STATUS_CMD_OK) return retval;
    argv++;
    argc--;

    function_cmd_opts_t opts;
    int optind;
    retval = parse_cmd_opts(opts, &optind, argc, argv, parser, streams);
    if (retval != STATUS_CMD_OK) return retval;

    if (opts.print_help) {
        builtin_print_help(parser, streams, cmd, streams.err);
        return STATUS_CMD_OK;
    }

    if (argc != optind) {
        if (opts.named_arguments.size()) {
            for (int i = optind; i < argc; i++) {
                opts.named_arguments.push_back(argv[i]);
            }
        } else {
            streams.err.append_format(_(L"%ls: Unexpected positional argument '%ls'"), cmd,
                                      argv[optind]);
            return STATUS_INVALID_ARGS;
        }
    }

    // We have what we need to actually define the function.
    function_data_t d;
    d.name = function_name;
    if (!opts.description.empty()) d.description = opts.description;
    // d.description = opts.description;
    d.events.swap(opts.events);
    d.shadow_scope = opts.shadow_scope;
    d.named_arguments.swap(opts.named_arguments);
    d.inherit_vars.swap(opts.inherit_vars);

    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();
    function_add(d, parser, definition_line_offset);

    // Handle wrap targets by creating the appropriate completions.
    for (size_t w = 0; w < opts.wrap_targets.size(); w++) {
        complete_add_wrapper(function_name, opts.wrap_targets.at(w));
    }

    return STATUS_CMD_OK;
}
/// The functions builtin, used for listing and erasing functions.
int builtin_functions(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
    const wchar_t *cmd = argv[0];
    int argc = builtin_count_args(argv);
    functions_cmd_opts_t opts;

    int optind;
    int retval = parse_cmd_opts(opts, &optind, argc, argv, parser, streams);
    if (retval != STATUS_CMD_OK) return retval;

    if (opts.print_help) {
        builtin_print_help(parser, streams, cmd, streams.out);
        return STATUS_CMD_OK;
    }

    // Erase, desc, query, copy and list are mutually exclusive.
    bool describe = opts.description ? true : false;
    if (describe + opts.erase + opts.list + opts.query + opts.copy > 1) {
        streams.err.append_format(_(L"%ls: Invalid combination of options\n"), cmd);
        builtin_print_error_trailer(parser, streams.err, cmd);
        return STATUS_INVALID_ARGS;
    }

    if (opts.erase) {
        for (int i = optind; i < argc; i++) function_remove(argv[i]);
        return STATUS_CMD_OK;
    }

    if (opts.description) {
        wchar_t *func;

        if (argc - optind != 1) {
            streams.err.append_format(_(L"%ls: Expected exactly one function name\n"), cmd);
            builtin_print_error_trailer(parser, streams.err, cmd);
            return STATUS_INVALID_ARGS;
        }

        func = argv[optind];
        if (!function_exists(func)) {
            streams.err.append_format(_(L"%ls: Function '%ls' does not exist\n"), cmd, func);
            builtin_print_error_trailer(parser, streams.err, cmd);
            return STATUS_CMD_ERROR;
        }

        function_set_desc(func, opts.description);
        return STATUS_CMD_OK;
    }

    if (opts.report_metadata) {
        if (argc - optind != 1) {
            streams.err.append_format(_(L"%ls: Expected exactly one function name for --details\n"),
                                      cmd);
            return STATUS_INVALID_ARGS;
        }

        const wchar_t *funcname = argv[optind];
        return report_function_metadata(funcname, opts.verbose, streams, false);
    }

    if (opts.handlers) {
        maybe_t<event_type_t> type_filter;
        if (opts.handlers_type) {
            type_filter = event_type_for_name(opts.handlers_type);
            if (! type_filter) {
                streams.err.append_format(_(L"%ls: Expected generic | variable | signal | exit | job-id for --handlers-type\n"),
                        cmd);
                return STATUS_INVALID_ARGS;
            }
        }
        event_print(streams, type_filter);
        return STATUS_CMD_OK;
    }

    // If we query with no argument, just return false.
    if (opts.query && argc == optind) {
        return STATUS_CMD_ERROR;
    }

    if (opts.list || argc == optind) {
        wcstring_list_t names = function_get_names(opts.show_hidden);
        std::sort(names.begin(), names.end());
        bool is_screen = !streams.out_is_redirected && isatty(STDOUT_FILENO);
        if (is_screen) {
            wcstring buff;
            for (size_t i = 0; i < names.size(); i++) {
                buff.append(names.at(i));
                buff.append(L", ");
            }
            streams.out.append(reformat_for_screen(buff));
        } else {
            for (size_t i = 0; i < names.size(); i++) {
                streams.out.append(names.at(i).c_str());
                streams.out.append(L"\n");
            }
        }

        return STATUS_CMD_OK;
    }

    if (opts.copy) {
        wcstring current_func;
        wcstring new_func;

        if (argc - optind != 2) {
            streams.err.append_format(_(L"%ls: Expected exactly two names (current function name, "
                                        L"and new function name)\n"),
                                      cmd);
            builtin_print_error_trailer(parser, streams.err, cmd);
            return STATUS_INVALID_ARGS;
        }
        current_func = argv[optind];
        new_func = argv[optind + 1];

        if (!function_exists(current_func)) {
            streams.err.append_format(_(L"%ls: Function '%ls' does not exist\n"), cmd,
                                      current_func.c_str());
            builtin_print_error_trailer(parser, streams.err, cmd);
            return STATUS_CMD_ERROR;
        }

        if (!valid_func_name(new_func) || parser_keywords_is_reserved(new_func)) {
            streams.err.append_format(_(L"%ls: Illegal function name '%ls'\n"), cmd,
                                      new_func.c_str());
            builtin_print_error_trailer(parser, streams.err, cmd);
            return STATUS_INVALID_ARGS;
        }

        // Keep things simple: don't allow existing names to be copy targets.
        if (function_exists(new_func)) {
            streams.err.append_format(
                _(L"%ls: Function '%ls' already exists. Cannot create copy '%ls'\n"), cmd,
                new_func.c_str(), current_func.c_str());
            builtin_print_error_trailer(parser, streams.err, cmd);
            return STATUS_CMD_ERROR;
        }

        if (function_copy(current_func, new_func)) return STATUS_CMD_OK;
        return STATUS_CMD_ERROR;
    }

    int res = STATUS_CMD_OK;
    for (int i = optind; i < argc; i++) {
        if (!function_exists(argv[i])) {
            res++;
        } else {
            if (!opts.query) {
                if (i != optind) streams.out.append(L"\n");
                const wchar_t *funcname = argv[optind];
                report_function_metadata(funcname, opts.verbose, streams, true);
                streams.out.append(functions_def(funcname));
            }
        }
    }

    return res;
}
Beispiel #16
0
/// Define a function. Calls into `function.cpp` to perform the heavy lifting of defining a
/// function.
int builtin_function(parser_t &parser, io_streams_t &streams, const wcstring_list_t &c_args,
                     const parsed_source_ref_t &source, tnode_t<grammar::job_list> body) {
    assert(source && "Missing source in builtin_function");
    // The wgetopt function expects 'function' as the first argument. Make a new wcstring_list with
    // that property. This is needed because this builtin has a different signature than the other
    // builtins.
    wcstring_list_t args = {L"function"};
    args.insert(args.end(), c_args.begin(), c_args.end());

    null_terminated_array_t<wchar_t> argv_array(args);
    wchar_t **argv = argv_array.get();
    wchar_t *cmd = argv[0];
    int argc = builtin_count_args(argv);

    // A valid function name has to be the first argument.
    wcstring function_name;
    int retval = validate_function_name(argc, argv, function_name, cmd, streams);
    if (retval != STATUS_CMD_OK) return retval;
    argv++;
    argc--;

    function_cmd_opts_t opts;
    int optind;
    retval = parse_cmd_opts(opts, &optind, argc, argv, parser, streams);
    if (retval != STATUS_CMD_OK) return retval;

    if (opts.print_help) {
        builtin_print_help(parser, streams, cmd, streams.err);
        return STATUS_CMD_OK;
    }

    if (argc != optind) {
        if (opts.named_arguments.size()) {
            for (int i = optind; i < argc; i++) {
                opts.named_arguments.push_back(argv[i]);
            }
        } else {
            streams.err.append_format(_(L"%ls: Unexpected positional argument '%ls'"), cmd,
                                      argv[optind]);
            return STATUS_INVALID_ARGS;
        }
    }

    // We have what we need to actually define the function.
    function_data_t d;
    d.name = function_name;
    if (!opts.description.empty()) d.description = opts.description;
    // d.description = opts.description;
    d.events.swap(opts.events);
    d.props.shadow_scope = opts.shadow_scope;
    d.props.named_arguments = std::move(opts.named_arguments);
    d.inherit_vars = std::move(opts.inherit_vars);

    for (size_t i = 0; i < d.events.size(); i++) {
        event_t &e = d.events.at(i);
        e.function_name = d.name;
    }

    d.props.parsed_source = source;
    d.props.body_node = body;
    function_add(std::move(d), parser);

    // Handle wrap targets by creating the appropriate completions.
    for (const wcstring &wt : opts.wrap_targets) complete_add_wrapper(function_name, wt);
    return STATUS_CMD_OK;
}