コード例 #1
0
ファイル: builtin_set.cpp プロジェクト: kballard/fish-shell
/// Extract indexes from an argument of the form `var_name[index1 index2...]`.
///
/// Inputs:
///   indexes: the list to insert the new indexes into
///   src: The source string to parse. This must be a var spec of the form "var[...]"
///
/// Returns:
///   The total number of indexes parsed, or -1 on error. If any indexes were found the `src` string
///   is modified to omit the index expression leaving just the var name.
static int parse_index(std::vector<long> &indexes, wchar_t *src, int scope, io_streams_t &streams,
                       const environment_t &vars) {
    wchar_t *p = std::wcschr(src, L'[');
    if (!p) return 0;  // no slices so nothing for us to do
    *p = L'\0';        // split the var name from the indexes/slices
    p++;

    auto var_str = vars.get(src, scope);
    wcstring_list_t var;
    if (var_str) var_str->to_list(var);

    int count = 0;

    while (*p != L']') {
        const wchar_t *end;
        long l_ind = fish_wcstol(p, &end);
        if (errno > 0) {  // ignore errno == -1 meaning the int did not end with a '\0'
            streams.err.append_format(_(L"%ls: Invalid index starting at '%ls'\n"), L"set", src);
            return -1;
        }
        p = (wchar_t *)end;

        // Convert negative index to a positive index.
        if (l_ind < 0) l_ind = var.size() + l_ind + 1;

        if (*p == L'.' && *(p + 1) == L'.') {
            p += 2;
            long l_ind2 = fish_wcstol(p, &end);
            if (errno > 0) {  // ignore errno == -1 meaning the int did not end with a '\0'
                return -1;
            }
            p = (wchar_t *)end;

            // Convert negative index to a positive index.
            if (l_ind2 < 0) l_ind2 = var.size() + l_ind2 + 1;

            int direction = l_ind2 < l_ind ? -1 : 1;
            for (long jjj = l_ind; jjj * direction <= l_ind2 * direction; jjj += direction) {
                indexes.push_back(jjj);
                count++;
            }
        } else {
            indexes.push_back(l_ind);
            count++;
        }
    }

    return count;
}
コード例 #2
0
ファイル: exec.cpp プロジェクト: moverest/fish-shell
void internal_exec(job_t *j, const io_chain_t &&all_ios) {
    // Do a regular launch -  but without forking first...

    // setup_child_process makes sure signals are properly set up.

    // PCA This is for handling exec. Passing all_ios here matches what fish 2.0.0 and 1.x did.
    // It's known to be wrong - for example, it means that redirections bound for subsequent
    // commands in the pipeline will apply to exec. However, using exec in a pipeline doesn't
    // really make sense, so I'm not trying to fix it here.
    if (!setup_child_process(0, all_ios)) {
        // Decrement SHLVL as we're removing ourselves from the shell "stack".
        auto shlvl_var = env_get(L"SHLVL", ENV_GLOBAL | ENV_EXPORT);
        wcstring shlvl_str = L"0";
        if (shlvl_var) {
            long shlvl = fish_wcstol(shlvl_var->as_string().c_str());
            if (!errno && shlvl > 0) {
                shlvl_str = to_string<long>(shlvl - 1);
            }
        }
        env_set_one(L"SHLVL", ENV_GLOBAL | ENV_EXPORT, shlvl_str);

        // launch_process _never_ returns.
        launch_process_nofork(j->processes.front().get());
    } else {
        j->set_flag(job_flag_t::CONSTRUCTED, true);
        j->processes.front()->completed = 1;
        return;
    }
}
コード例 #3
0
ファイル: builtin_string.cpp プロジェクト: Hunsu/fish-shell
static int handle_flag_s(wchar_t **argv, parser_t &parser, io_streams_t &streams, wgetopter_t &w,
                         options_t *opts) {
    if (opts->start_valid) {
        opts->start = fish_wcstol(w.woptarg);
        if (opts->start == 0 || opts->start == LONG_MIN || errno == ERANGE) {
            string_error(streams, _(L"%ls: Invalid start value '%ls'\n"), argv[0], w.woptarg);
            return STATUS_INVALID_ARGS;
        } else if (errno) {
            string_error(streams, BUILTIN_ERR_NOT_NUMBER, argv[0], w.woptarg);
            return STATUS_INVALID_ARGS;
        }
        return STATUS_CMD_OK;
    }
    string_unknown_option(parser, streams, argv[0], argv[w.woptind - 1]);
    return STATUS_INVALID_ARGS;
}
コード例 #4
0
ファイル: input_common.cpp プロジェクト: kballard/fish-shell
// Update the wait_on_escape_ms value in response to the fish_escape_delay_ms user variable being
// set.
void update_wait_on_escape_ms(const environment_t &vars) {
    auto escape_time_ms = vars.get(L"fish_escape_delay_ms");
    if (escape_time_ms.missing_or_empty()) {
        wait_on_escape_ms = WAIT_ON_ESCAPE_DEFAULT;
        return;
    }

    long tmp = fish_wcstol(escape_time_ms->as_string().c_str());
    if (errno || tmp < 10 || tmp >= 5000) {
        std::fwprintf(stderr,
                 L"ignoring fish_escape_delay_ms: value '%ls' "
                 L"is not an integer or is < 10 or >= 5000 ms\n",
                 escape_time_ms->as_string().c_str());
    } else {
        wait_on_escape_ms = (int)tmp;
    }
}
コード例 #5
0
// Update the wait_on_escape_ms value in response to the fish_escape_delay_ms user variable being
// set.
void update_wait_on_escape_ms() {
    env_var_t escape_time_ms = env_get_string(L"fish_escape_delay_ms");
    if (escape_time_ms.missing_or_empty()) {
        wait_on_escape_ms = WAIT_ON_ESCAPE_DEFAULT;
        return;
    }

    long tmp = fish_wcstol(escape_time_ms.c_str());
    if (errno || tmp < 10 || tmp >= 5000) {
        fwprintf(stderr,
                 L"ignoring fish_escape_delay_ms: value '%ls' "
                 L"is not an integer or is < 10 or >= 5000 ms\n",
                 escape_time_ms.c_str());
    } else {
        wait_on_escape_ms = (int)tmp;
    }
}
コード例 #6
0
ファイル: builtin_ulimit.cpp プロジェクト: msteed/fish-shell
/// The ulimit builtin, used for setting resource limits.
int builtin_ulimit(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
    wchar_t *cmd = argv[0];
    int argc = builtin_count_args(argv);
    bool report_all = false;
    bool hard = false;
    bool soft = false;
    int what = RLIMIT_FSIZE;

    const wchar_t *short_options = L":HSacdflmnstuvh";
    const struct woption long_options[] = {{L"all", no_argument, NULL, 'a'},
                                           {L"hard", no_argument, NULL, 'H'},
                                           {L"soft", no_argument, NULL, 'S'},
                                           {L"core-size", no_argument, NULL, 'c'},
                                           {L"data-size", no_argument, NULL, 'd'},
                                           {L"file-size", no_argument, NULL, 'f'},
                                           {L"lock-size", no_argument, NULL, 'l'},
                                           {L"resident-set-size", no_argument, NULL, 'm'},
                                           {L"file-descriptor-count", no_argument, NULL, 'n'},
                                           {L"stack-size", no_argument, NULL, 's'},
                                           {L"cpu-time", no_argument, NULL, 't'},
                                           {L"process-count", no_argument, NULL, 'u'},
                                           {L"virtual-memory-size", no_argument, NULL, 'v'},
                                           {L"help", no_argument, NULL, 'h'},
                                           {NULL, 0, NULL, 0}};

    int opt;
    wgetopter_t w;
    while ((opt = w.wgetopt_long(argc, argv, short_options, long_options, NULL)) != -1) {
        switch (opt) {
            case 'a': {
                report_all = true;
                break;
            }
            case 'H': {
                hard = true;
                break;
            }
            case 'S': {
                soft = true;
                break;
            }
            case 'c': {
                what = RLIMIT_CORE;
                break;
            }
            case 'd': {
                what = RLIMIT_DATA;
                break;
            }
            case 'f': {
                what = RLIMIT_FSIZE;
                break;
            }
#ifdef RLIMIT_MEMLOCK
            case 'l': {
                what = RLIMIT_MEMLOCK;
                break;
            }
#endif
#ifdef RLIMIT_RSS
            case 'm': {
                what = RLIMIT_RSS;
                break;
            }
#endif
            case 'n': {
                what = RLIMIT_NOFILE;
                break;
            }
            case 's': {
                what = RLIMIT_STACK;
                break;
            }
            case 't': {
                what = RLIMIT_CPU;
                break;
            }
#ifdef RLIMIT_NPROC
            case 'u': {
                what = RLIMIT_NPROC;
                break;
            }
#endif
#ifdef RLIMIT_AS
            case 'v': {
                what = RLIMIT_AS;
                break;
            }
#endif
            case 'h': {
                builtin_print_help(parser, streams, cmd, streams.out);
                return 0;
            }
            case ':': {
                streams.err.append_format(BUILTIN_ERR_MISSING, cmd, argv[w.woptind - 1]);
                return STATUS_BUILTIN_ERROR;
            }
            case '?': {
                builtin_unknown_option(parser, streams, cmd, argv[w.woptind - 1]);
                return STATUS_BUILTIN_ERROR;
            }
            default: {
                DIE("unexpected retval from wgetopt_long");
                break;
            }
        }
    }

    if (report_all) {
        print_all(hard, streams);
        return STATUS_BUILTIN_OK;
    }

    int arg_count = argc - w.woptind;
    if (arg_count == 0) {
        // Show current limit value.
        print(what, hard, streams);
        return STATUS_BUILTIN_OK;
    } else if (arg_count != 1) {
        streams.err.append_format(BUILTIN_ERR_TOO_MANY_ARGUMENTS, cmd);
        builtin_print_help(parser, streams, cmd, streams.err);
        return STATUS_BUILTIN_ERROR;
    }

    // Change current limit value.
    if (!hard && !soft) {
        // Set both hard and soft limits if neither was specified.
        hard = soft = true;
    }

    rlim_t new_limit;
    if (*argv[w.woptind] == L'\0') {
        streams.err.append_format(_(L"%ls: New limit cannot be an empty string\n"), cmd);
        builtin_print_help(parser, streams, cmd, streams.err);
        return STATUS_BUILTIN_ERROR;
    } else if (wcscasecmp(argv[w.woptind], L"unlimited") == 0) {
        new_limit = RLIM_INFINITY;
    } else if (wcscasecmp(argv[w.woptind], L"hard") == 0) {
        new_limit = get(what, 1);
    } else if (wcscasecmp(argv[w.woptind], L"soft") == 0) {
        new_limit = get(what, soft);
    } else {
        new_limit = fish_wcstol(argv[w.woptind]);
        if (errno) {
            streams.err.append_format(_(L"%ls: Invalid limit '%ls'\n"), cmd, argv[w.woptind]);
            builtin_print_help(parser, streams, cmd, streams.err);
            return STATUS_BUILTIN_ERROR;
        }
        new_limit *= get_multiplier(what);
    }

    return set_limit(what, hard, soft, new_limit, streams);
}
コード例 #7
0
/// The commandline builtin. It is used for specifying a new value for the commandline.
int builtin_commandline(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
    wgetopter_t w;
    int buffer_part = 0;
    int cut_at_cursor = 0;

    int argc = builtin_count_args(argv);
    int append_mode = 0;

    int function_mode = 0;
    int selection_mode = 0;

    int tokenize = 0;

    int cursor_mode = 0;
    int line_mode = 0;
    int search_mode = 0;
    int paging_mode = 0;
    const wchar_t *begin = NULL, *end = NULL;

    scoped_push<const wchar_t *> saved_current_buffer(&current_buffer);
    scoped_push<size_t> saved_current_cursor_pos(&current_cursor_pos);

    wcstring transient_commandline;
    if (get_top_transient(&transient_commandline)) {
        current_buffer = transient_commandline.c_str();
        current_cursor_pos = transient_commandline.size();
    } else {
        current_buffer = reader_get_buffer();
        current_cursor_pos = reader_get_cursor_pos();
    }

    if (!get_buffer()) {
        if (is_interactive_session) {
            // Prompt change requested while we don't have a prompt, most probably while reading the
            // init files. Just ignore it.
            return 1;
        }

        streams.err.append(argv[0]);
        streams.err.append(L": Can not set commandline in non-interactive mode\n");
        builtin_print_help(parser, streams, argv[0], streams.err);
        return 1;
    }

    w.woptind = 0;

    while (1) {
        static const struct woption long_options[] = {{L"append", no_argument, 0, 'a'},
                                                      {L"insert", no_argument, 0, 'i'},
                                                      {L"replace", no_argument, 0, 'r'},
                                                      {L"current-job", no_argument, 0, 'j'},
                                                      {L"current-process", no_argument, 0, 'p'},
                                                      {L"current-token", no_argument, 0, 't'},
                                                      {L"current-buffer", no_argument, 0, 'b'},
                                                      {L"cut-at-cursor", no_argument, 0, 'c'},
                                                      {L"function", no_argument, 0, 'f'},
                                                      {L"tokenize", no_argument, 0, 'o'},
                                                      {L"help", no_argument, 0, 'h'},
                                                      {L"input", required_argument, 0, 'I'},
                                                      {L"cursor", no_argument, 0, 'C'},
                                                      {L"line", no_argument, 0, 'L'},
                                                      {L"search-mode", no_argument, 0, 'S'},
                                                      {L"selection", no_argument, 0, 's'},
                                                      {L"paging-mode", no_argument, 0, 'P'},
                                                      {0, 0, 0, 0}};

        int opt_index = 0;

        int opt = w.wgetopt_long(argc, argv, L"abijpctwforhI:CLSsP", long_options, &opt_index);
        if (opt == -1) break;

        switch (opt) {
            case 0: {
                if (long_options[opt_index].flag != 0) break;
                streams.err.append_format(BUILTIN_ERR_UNKNOWN, argv[0],
                                          long_options[opt_index].name);
                builtin_print_help(parser, streams, argv[0], streams.err);

                return 1;
            }
            case L'a': {
                append_mode = APPEND_MODE;
                break;
            }
            case L'b': {
                buffer_part = STRING_MODE;
                break;
            }
            case L'i': {
                append_mode = INSERT_MODE;
                break;
            }
            case L'r': {
                append_mode = REPLACE_MODE;
                break;
            }
            case 'c': {
                cut_at_cursor = 1;
                break;
            }
            case 't': {
                buffer_part = TOKEN_MODE;
                break;
            }
            case 'j': {
                buffer_part = JOB_MODE;
                break;
            }
            case 'p': {
                buffer_part = PROCESS_MODE;
                break;
            }
            case 'f': {
                function_mode = 1;
                break;
            }
            case 'o': {
                tokenize = 1;
                break;
            }
            case 'I': {
                current_buffer = w.woptarg;
                current_cursor_pos = wcslen(w.woptarg);
                break;
            }
            case 'C': {
                cursor_mode = 1;
                break;
            }
            case 'L': {
                line_mode = 1;
                break;
            }
            case 'S': {
                search_mode = 1;
                break;
            }
            case 's': {
                selection_mode = 1;
                break;
            }
            case 'P': {
                paging_mode = 1;
                break;
            }
            case 'h': {
                builtin_print_help(parser, streams, argv[0], streams.out);
                return 0;
            }
            case L'?': {
                builtin_unknown_option(parser, streams, argv[0], argv[w.woptind - 1]);
                return 1;
            }
            default: {
                DIE("unexpected opt");
                break;
            }
        }
    }

    if (function_mode) {
        int i;

        // Check for invalid switch combinations.
        if (buffer_part || cut_at_cursor || append_mode || tokenize || cursor_mode || line_mode ||
            search_mode || paging_mode) {
            streams.err.append_format(BUILTIN_ERR_COMBO, argv[0]);

            builtin_print_help(parser, streams, argv[0], streams.err);
            return 1;
        }

        if (argc == w.woptind) {
            streams.err.append_format(BUILTIN_ERR_MISSING, argv[0]);

            builtin_print_help(parser, streams, argv[0], streams.err);
            return 1;
        }

        for (i = w.woptind; i < argc; i++) {
            wchar_t c = input_function_get_code(argv[i]);
            if (c != INPUT_CODE_NONE) {
                // input_unreadch inserts the specified keypress or readline function at the back of
                // the queue of unused keypresses.
                input_queue_ch(c);
            } else {
                streams.err.append_format(_(L"%ls: Unknown input function '%ls'\n"), argv[0],
                                          argv[i]);
                builtin_print_help(parser, streams, argv[0], streams.err);
                return 1;
            }
        }

        return 0;
    }

    if (selection_mode) {
        size_t start, len;
        const wchar_t *buffer = reader_get_buffer();
        if (reader_get_selection(&start, &len)) {
            streams.out.append(buffer + start, len);
        }
        return 0;
    }

    // Check for invalid switch combinations.
    if ((search_mode || line_mode || cursor_mode || paging_mode) && (argc - w.woptind > 1)) {
        streams.err.append_format(argv[0], L": Too many arguments\n", NULL);
        builtin_print_help(parser, streams, argv[0], streams.err);
        return 1;
    }

    if ((buffer_part || tokenize || cut_at_cursor) &&
        (cursor_mode || line_mode || search_mode || paging_mode)) {
        streams.err.append_format(BUILTIN_ERR_COMBO, argv[0]);

        builtin_print_help(parser, streams, argv[0], streams.err);
        return 1;
    }

    if ((tokenize || cut_at_cursor) && (argc - w.woptind)) {
        streams.err.append_format(
            BUILTIN_ERR_COMBO2, argv[0],
            L"--cut-at-cursor and --tokenize can not be used when setting the commandline");

        builtin_print_help(parser, streams, argv[0], streams.err);
        return 1;
    }

    if (append_mode && !(argc - w.woptind)) {
        streams.err.append_format(
            BUILTIN_ERR_COMBO2, argv[0],
            L"insertion mode switches can not be used when not in insertion mode");

        builtin_print_help(parser, streams, argv[0], streams.err);
        return 1;
    }

    // Set default modes.
    if (!append_mode) {
        append_mode = REPLACE_MODE;
    }

    if (!buffer_part) {
        buffer_part = STRING_MODE;
    }

    if (cursor_mode) {
        if (argc - w.woptind) {
            long new_pos = fish_wcstol(argv[w.woptind]);
            if (errno) {
                streams.err.append_format(BUILTIN_ERR_NOT_NUMBER, argv[0], argv[w.woptind]);
                builtin_print_help(parser, streams, argv[0], streams.err);
            }

            current_buffer = reader_get_buffer();
            new_pos = maxi(0L, mini(new_pos, (long)wcslen(current_buffer)));
            reader_set_buffer(current_buffer, (size_t)new_pos);
        } else {
            streams.out.append_format(L"%lu\n", (unsigned long)reader_get_cursor_pos());
        }
        return 0;
    }

    if (line_mode) {
        size_t pos = reader_get_cursor_pos();
        const wchar_t *buff = reader_get_buffer();
        streams.out.append_format(L"%lu\n", (unsigned long)parse_util_lineno(buff, pos));
        return 0;
    }

    if (search_mode) {
        return !reader_search_mode();
    }

    if (paging_mode) {
        return !reader_has_pager_contents();
    }

    switch (buffer_part) {
        case STRING_MODE: {
            begin = get_buffer();
            end = begin + wcslen(begin);
            break;
        }
        case PROCESS_MODE: {
            parse_util_process_extent(get_buffer(), get_cursor_pos(), &begin, &end);
            break;
        }
        case JOB_MODE: {
            parse_util_job_extent(get_buffer(), get_cursor_pos(), &begin, &end);
            break;
        }
        case TOKEN_MODE: {
            parse_util_token_extent(get_buffer(), get_cursor_pos(), &begin, &end, 0, 0);
            break;
        }
        default: {
            DIE("unexpected buffer_part");
            break;
        }
    }

    int arg_count = argc - w.woptind;
    if (arg_count == 0) {
        write_part(begin, end, cut_at_cursor, tokenize, streams);
    } else if (arg_count == 1) {
        replace_part(begin, end, argv[w.woptind], append_mode);
    } else {
        wcstring sb = argv[w.woptind];
        for (int i = w.woptind + 1; i < argc; i++) {
            sb.push_back(L'\n');
            sb.append(argv[i]);
        }
        replace_part(begin, end, sb.c_str(), append_mode);
    }

    return 0;
}
コード例 #8
0
ファイル: builtin_history.cpp プロジェクト: Hunsu/fish-shell
static int parse_cmd_opts(history_cmd_opts_t &opts, int *optind,  //!OCLINT(high ncss method)
                          int argc, wchar_t **argv, parser_t &parser, io_streams_t &streams) {
    wchar_t *cmd = argv[0];
    int opt;
    wgetopter_t w;
    while ((opt = w.wgetopt_long(argc, argv, short_options, long_options, NULL)) != -1) {
        switch (opt) {
            case 1: {
                if (!set_hist_cmd(cmd, &opts.hist_cmd, HIST_DELETE, streams)) {
                    return STATUS_CMD_ERROR;
                }
                break;
            }
            case 2: {
                if (!set_hist_cmd(cmd, &opts.hist_cmd, HIST_SEARCH, streams)) {
                    return STATUS_CMD_ERROR;
                }
                break;
            }
            case 3: {
                if (!set_hist_cmd(cmd, &opts.hist_cmd, HIST_SAVE, streams)) {
                    return STATUS_CMD_ERROR;
                }
                break;
            }
            case 4: {
                if (!set_hist_cmd(cmd, &opts.hist_cmd, HIST_CLEAR, streams)) {
                    return STATUS_CMD_ERROR;
                }
                break;
            }
            case 5: {
                if (!set_hist_cmd(cmd, &opts.hist_cmd, HIST_MERGE, streams)) {
                    return STATUS_CMD_ERROR;
                }
                break;
            }
            case 'C': {
                opts.case_sensitive = true;
                break;
            }
            case 'p': {
                opts.search_type = HISTORY_SEARCH_TYPE_PREFIX;
                opts.history_search_type_defined = true;
                break;
            }
            case 'c': {
                opts.search_type = HISTORY_SEARCH_TYPE_CONTAINS;
                opts.history_search_type_defined = true;
                break;
            }
            case 'e': {
                opts.search_type = HISTORY_SEARCH_TYPE_EXACT;
                opts.history_search_type_defined = true;
                break;
            }
            case 't': {
                opts.show_time_format = w.woptarg ? w.woptarg : L"# %c%n";
                break;
            }
            case 'n': {
                opts.max_items = fish_wcstol(w.woptarg);
                if (errno) {
                    streams.err.append_format(_(L"%ls: max value '%ls' is not a valid number\n"),
                                              cmd, w.woptarg);
                    return STATUS_INVALID_ARGS;
                }
                break;
            }
            case 'z': {
                opts.null_terminate = true;
                break;
            }
            case 'h': {
                opts.print_help = true;
                break;
            }
            case ':': {
                streams.err.append_format(BUILTIN_ERR_MISSING, cmd, argv[w.woptind - 1]);
                return STATUS_INVALID_ARGS;
            }
            case '?': {
                // Try to parse it as a number; e.g., "-123".
                opts.max_items = fish_wcstol(argv[w.woptind - 1] + 1);
                if (errno) {
                    builtin_unknown_option(parser, streams, cmd, argv[w.woptind - 1]);
                    return STATUS_INVALID_ARGS;
                }
                w.nextchar = NULL;
                break;
            }
            default: {
                DIE("unexpected retval from wgetopt_long");
                break;
            }
        }
    }

    *optind = w.woptind;
    return STATUS_CMD_OK;
}
コード例 #9
0
static int string_sub(parser_t &parser, io_streams_t &streams, int argc, wchar_t **argv) {
    const wchar_t *short_options = L":l:qs:";
    const struct woption long_options[] = {{L"length", required_argument, 0, 'l'},
                                           {L"quiet", no_argument, 0, 'q'},
                                           {L"start", required_argument, 0, 's'},
                                           {0, 0, 0, 0}};

    long start = 0;
    long length = -1;
    bool quiet = false;
    wgetopter_t w;

    for (;;) {
        int c = w.wgetopt_long(argc, argv, short_options, long_options, 0);

        if (c == -1) {
            break;
        }
        switch (c) {
            case 0: {
                break;
            }
            case 'l': {
                length = fish_wcstol(w.woptarg);
                if (length < 0 || errno == ERANGE) {
                    string_error(streams, _(L"%ls: Invalid length value '%ls'\n"), argv[0],
                                 w.woptarg);
                    return BUILTIN_STRING_ERROR;
                } else if (errno) {
                    string_error(streams, BUILTIN_ERR_NOT_NUMBER, argv[0], w.woptarg);
                    return BUILTIN_STRING_ERROR;
                }
                break;
            }
            case 'q': {
                quiet = true;
                break;
            }
            case 's': {
                start = fish_wcstol(w.woptarg);
                if (start == 0 || start == LONG_MIN || errno == ERANGE) {
                    string_error(streams, _(L"%ls: Invalid start value '%ls'\n"), argv[0],
                                 w.woptarg);
                    return BUILTIN_STRING_ERROR;
                } else if (errno) {
                    string_error(streams, BUILTIN_ERR_NOT_NUMBER, argv[0], w.woptarg);
                    return BUILTIN_STRING_ERROR;
                }
                break;
            }
            case ':': {
                string_error(streams, STRING_ERR_MISSING, argv[0]);
                return BUILTIN_STRING_ERROR;
            }
            case '?': {
                string_unknown_option(parser, streams, argv[0], argv[w.woptind - 1]);
                return BUILTIN_STRING_ERROR;
            }
            default: {
                DIE("unexpected opt");
                break;
            }
        }
    }

    int i = w.woptind;
    if (string_args_from_stdin(streams) && argc > i) {
        string_error(streams, BUILTIN_ERR_TOO_MANY_ARGUMENTS, argv[0]);
        return BUILTIN_STRING_ERROR;
    }

    int nsub = 0;
    const wchar_t *arg;
    wcstring storage;
    while ((arg = string_get_arg(&i, argv, &storage, streams)) != NULL) {
        typedef wcstring::size_type size_type;
        size_type pos = 0;
        size_type count = wcstring::npos;
        wcstring s(arg);
        if (start > 0) {
            pos = static_cast<size_type>(start - 1);
        } else if (start < 0) {
            assert(start != LONG_MIN);  // checked above
            size_type n = static_cast<size_type>(-start);
            pos = n > s.length() ? 0 : s.length() - n;
        }
        if (pos > s.length()) {
            pos = s.length();
        }

        if (length >= 0) {
            count = static_cast<size_type>(length);
        }

        // Note that std::string permits count to extend past end of string.
        if (!quiet) {
            streams.out.append(s.substr(pos, count));
            streams.out.append(L'\n');
        }
        nsub++;
    }

    return nsub > 0 ? BUILTIN_STRING_OK : BUILTIN_STRING_NONE;
}
コード例 #10
0
static int string_split(parser_t &parser, io_streams_t &streams, int argc, wchar_t **argv) {
    const wchar_t *short_options = L":m:qr";
    const struct woption long_options[] = {{L"max", required_argument, 0, 'm'},
                                           {L"quiet", no_argument, 0, 'q'},
                                           {L"right", no_argument, 0, 'r'},
                                           {0, 0, 0, 0}};

    long max = LONG_MAX;
    bool quiet = false;
    bool right = false;
    wgetopter_t w;
    for (;;) {
        int c = w.wgetopt_long(argc, argv, short_options, long_options, 0);

        if (c == -1) {
            break;
        }
        switch (c) {
            case 0: {
                break;
            }
            case 'm': {
                max = fish_wcstol(w.woptarg);
                if (errno) {
                    string_error(streams, BUILTIN_ERR_NOT_NUMBER, argv[0], w.woptarg);
                    return BUILTIN_STRING_ERROR;
                }
                break;
            }
            case 'q': {
                quiet = true;
                break;
            }
            case 'r': {
                right = true;
                break;
            }
            case ':': {
                string_error(streams, STRING_ERR_MISSING, argv[0]);
                return BUILTIN_STRING_ERROR;
            }
            case '?': {
                string_unknown_option(parser, streams, argv[0], argv[w.woptind - 1]);
                return BUILTIN_STRING_ERROR;
            }
            default: {
                DIE("unexpected opt");
                break;
            }
        }
    }

    int i = w.woptind;
    const wchar_t *sep;
    if ((sep = string_get_arg_argv(&i, argv)) == NULL) {
        string_error(streams, STRING_ERR_MISSING, argv[0]);
        return BUILTIN_STRING_ERROR;
    }
    const wchar_t *sep_end = sep + wcslen(sep);

    if (string_args_from_stdin(streams) && argc > i) {
        string_error(streams, BUILTIN_ERR_TOO_MANY_ARGUMENTS, argv[0]);
        return BUILTIN_STRING_ERROR;
    }

    wcstring_list_t splits;
    size_t arg_count = 0;
    wcstring storage;
    const wchar_t *arg;
    while ((arg = string_get_arg(&i, argv, &storage, streams)) != 0) {
        const wchar_t *arg_end = arg + wcslen(arg);
        if (right) {
            typedef std::reverse_iterator<const wchar_t *> reverser;
            split_about(reverser(arg_end), reverser(arg), reverser(sep_end), reverser(sep), &splits,
                        max);
        } else {
            split_about(arg, arg_end, sep, sep_end, &splits, max);
        }
        arg_count++;
    }

    // If we are from the right, split_about gave us reversed strings, in reversed order!
    if (right) {
        for (size_t j = 0; j < splits.size(); j++) {
            std::reverse(splits[j].begin(), splits[j].end());
        }
        std::reverse(splits.begin(), splits.end());
    }

    if (!quiet) {
        for (wcstring_list_t::const_iterator si = splits.begin(); si != splits.end(); ++si) {
            streams.out.append(*si);
            streams.out.append(L'\n');
        }
    }

    // We split something if we have more split values than args.
    return splits.size() > arg_count ? BUILTIN_STRING_OK : BUILTIN_STRING_NONE;
}
コード例 #11
0
ファイル: builtin_set.cpp プロジェクト: Hunsu/fish-shell
/// Extract indexes from a destination argument of the form name[index1 index2...]
///
/// \param indexes the list to insert the new indexes into
/// \param src the source string to parse
/// \param name the name of the element. Return null if the name in \c src does not match this name
/// \param var_count the number of elements in the array to parse.
///
/// \return the total number of indexes parsed, or -1 on error
static int parse_index(std::vector<long> &indexes, const wchar_t *src, const wchar_t *name,
                       size_t var_count, io_streams_t &streams) {
    size_t len;
    int count = 0;
    const wchar_t *src_orig = src;

    if (src == 0) {
        return 0;
    }

    while (*src != L'\0' && (iswalnum(*src) || *src == L'_')) src++;

    if (*src != L'[') {
        streams.err.append_format(_(BUILTIN_SET_ARG_COUNT), L"set");
        return 0;
    }

    len = src - src_orig;
    if ((wcsncmp(src_orig, name, len) != 0) || (wcslen(name) != (len))) {
        streams.err.append_format(
            _(L"%ls: Multiple variable names specified in single call (%ls and %.*ls)\n"), L"set",
            name, len, src_orig);
        return 0;
    }

    src++;
    while (iswspace(*src)) src++;

    while (*src != L']') {
        const wchar_t *end;
        long l_ind = fish_wcstol(src, &end);
        if (errno > 0) {  // ignore errno == -1 meaning the int did not end with a '\0'
            streams.err.append_format(_(L"%ls: Invalid index starting at '%ls'\n"), L"set", src);
            return 0;
        }

        if (l_ind < 0) l_ind = var_count + l_ind + 1;

        src = end;  //!OCLINT(parameter reassignment)
        if (*src == L'.' && *(src + 1) == L'.') {
            src += 2;
            long l_ind2 = fish_wcstol(src, &end);
            if (errno > 0) {  // ignore errno == -1 meaning the int did not end with a '\0'
                return 1;
            }
            src = end;  //!OCLINT(parameter reassignment)

            if (l_ind2 < 0) {
                l_ind2 = var_count + l_ind2 + 1;
            }
            int direction = l_ind2 < l_ind ? -1 : 1;
            for (long jjj = l_ind; jjj * direction <= l_ind2 * direction; jjj += direction) {
                // debug(0, L"Expand range [set]: %i\n", jjj);
                indexes.push_back(jjj);
                count++;
            }
        } else {
            indexes.push_back(l_ind);
            count++;
        }

        while (iswspace(*src)) src++;
    }

    return count;
}
コード例 #12
0
ファイル: expand.cpp プロジェクト: raichoo/fish-shell
/// Parse an array slicing specification Returns 0 on success. If a parse error occurs, returns the
/// index of the bad token. Note that 0 can never be a bad index because the string always starts
/// with [.
static size_t parse_slice(const wchar_t *in, wchar_t **end_ptr, std::vector<long> &idx,
                          std::vector<size_t> &source_positions, size_t array_size) {
    const long size = (long)array_size;
    size_t pos = 1;  // skip past the opening square brace

    while (1) {
        while (iswspace(in[pos]) || (in[pos] == INTERNAL_SEPARATOR)) pos++;
        if (in[pos] == L']') {
            pos++;
            break;
        }

        const size_t i1_src_pos = pos;
        const wchar_t *end;
        long tmp = fish_wcstol(&in[pos], &end);
        // We don't test `*end` as is typically done because we expect it to not be the null char.
        // Ignore the case of errno==-1 because it means the end char wasn't the null char.
        if (errno > 0) {
            return pos;
        }
        // debug( 0, L"Push idx %d", tmp );

        long i1 = tmp > -1 ? tmp : size + tmp + 1;
        pos = end - in;
        while (in[pos] == INTERNAL_SEPARATOR) pos++;
        if (in[pos] == L'.' && in[pos + 1] == L'.') {
            pos += 2;
            while (in[pos] == INTERNAL_SEPARATOR) pos++;

            const size_t number_start = pos;
            long tmp1 = fish_wcstol(&in[pos], &end);
            // Ignore the case of errno==-1 because it means the end char wasn't the null char.
            if (errno > 0) {
                return pos;
            }
            pos = end - in;

            // debug( 0, L"Push range %d %d", tmp, tmp1 );
            long i2 = tmp1 > -1 ? tmp1 : size + tmp1 + 1;
            // Clamp to array size, but only when doing a range,
            // and only when just one is too high.
            if (i1 > size && i2 > size) {
                continue;
            }
            i1 = i1 < size ? i1 : size;
            i2 = i2 < size ? i2 : size;
            // debug( 0, L"Push range idx %d %d", i1, i2 );
            short direction = i2 < i1 ? -1 : 1;
            // If only the beginning is negative, always go reverse.
            // If only the end, always go forward.
            // Prevents `[x..-1]` from going reverse if less than x elements are there.
            if (tmp1 > -1 != tmp > -1) {
                direction = tmp1 > -1 ? -1 : 1;
            }
            for (long jjj = i1; jjj * direction <= i2 * direction; jjj += direction) {
                // debug(0, L"Expand range [subst]: %i\n", jjj);
                idx.push_back(jjj);
                source_positions.push_back(number_start);
            }
            continue;
        }

        // debug( 0, L"Push idx %d", tmp );
        idx.push_back(i1);
        source_positions.push_back(i1_src_pos);
    }

    if (end_ptr) {
        *end_ptr = (wchar_t *)(in + pos);
    }

    return 0;
}