static int string_length(parser_t &parser, io_streams_t &streams, int argc, wchar_t **argv) { const wchar_t *short_options = L"q"; const struct woption long_options[] = {{L"quiet", no_argument, 0, 'q'}, {0, 0, 0, 0}}; bool quiet = false; wgetopter_t w; for (;;) { int opt = w.wgetopt_long(argc, argv, short_options, long_options, 0); if (opt == -1) { break; } switch (opt) { case 0: { break; } case 'q': { quiet = true; break; } 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; } const wchar_t *arg; int nnonempty = 0; wcstring storage; while ((arg = string_get_arg(&i, argv, &storage, streams)) != 0) { size_t n = wcslen(arg); if (n > 0) { nnonempty++; } if (!quiet) { streams.out.append(to_string(n)); streams.out.append(L'\n'); } } return nnonempty > 0 ? BUILTIN_STRING_OK : BUILTIN_STRING_NONE; }
static int string_escape(parser_t &parser, io_streams_t &streams, int argc, wchar_t **argv) { const wchar_t *short_options = L"n"; const struct woption long_options[] = { { L"no-quoted", no_argument, 0, 'n' }, { 0, 0, 0, 0 } }; escape_flags_t flags = ESCAPE_ALL; 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 'n': flags |= ESCAPE_NO_QUOTED; break; case '?': string_unknown_option(parser, streams, argv[0], argv[w.woptind - 1]); return BUILTIN_STRING_ERROR; } } 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 nesc = 0; wcstring storage; const wchar_t *arg; while ((arg = string_get_arg(&i, argv, &storage, streams)) != 0) { streams.out.append(escape(arg, flags)); streams.out.append(L'\n'); nesc++; } return (nesc > 0) ? BUILTIN_STRING_OK : BUILTIN_STRING_NONE; }
static int string_split(parser_t &parser, io_streams_t &streams, int argc, wchar_t **argv) { options_t opts; opts.quiet_valid = true; opts.right_valid = true; opts.max_valid = true; opts.max = LONG_MAX; int optind; int retval = parse_opts(&opts, &optind, 1, argc, argv, parser, streams); if (retval != STATUS_CMD_OK) return retval; const wchar_t *sep = opts.arg1; const wchar_t *sep_end = sep + wcslen(sep); wcstring_list_t splits; size_t arg_count = 0; wcstring storage; const wchar_t *arg; while ((arg = string_get_arg(&optind, argv, &storage, streams)) != 0) { const wchar_t *arg_end = arg + wcslen(arg); if (opts.right) { typedef std::reverse_iterator<const wchar_t *> reverser; split_about(reverser(arg_end), reverser(arg), reverser(sep_end), reverser(sep), &splits, opts.max); } else { split_about(arg, arg_end, sep, sep_end, &splits, opts.max); } arg_count++; } // If we are from the right, split_about gave us reversed strings, in reversed order! if (opts.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 (!opts.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 ? STATUS_CMD_OK : STATUS_CMD_ERROR; }
static int string_trim(parser_t &parser, io_streams_t &streams, int argc, wchar_t **argv) { options_t opts; opts.chars_valid = true; opts.left_valid = true; opts.right_valid = true; opts.quiet_valid = true; int optind; int retval = parse_opts(&opts, &optind, 0, argc, argv, parser, streams); if (retval != STATUS_CMD_OK) return retval; // If neither left or right is specified, we do both. if (!opts.left && !opts.right) { opts.left = opts.right = true; } const wchar_t *arg; size_t ntrim = 0; wcstring argstr; wcstring storage; while ((arg = string_get_arg(&optind, argv, &storage, streams)) != 0) { argstr = arg; // Begin and end are respectively the first character to keep on the left, and first // character to trim on the right. The length is thus end - start. size_t begin = 0, end = argstr.size(); if (opts.right) { size_t last_to_keep = argstr.find_last_not_of(opts.chars_to_trim); end = (last_to_keep == wcstring::npos) ? 0 : last_to_keep + 1; } if (opts.left) { size_t first_to_keep = argstr.find_first_not_of(opts.chars_to_trim); begin = (first_to_keep == wcstring::npos ? end : first_to_keep); } assert(begin <= end && end <= argstr.size()); ntrim += argstr.size() - (end - begin); if (!opts.quiet) { streams.out.append(wcstring(argstr, begin, end - begin)); streams.out.append(L'\n'); } } return ntrim > 0 ? STATUS_CMD_OK : STATUS_CMD_ERROR; }
static int string_sub(parser_t &parser, io_streams_t &streams, int argc, wchar_t **argv) { options_t opts; opts.length_valid = true; opts.quiet_valid = true; opts.start_valid = true; opts.length = -1; int optind; int retval = parse_opts(&opts, &optind, 0, argc, argv, parser, streams); if (retval != STATUS_CMD_OK) return retval; int nsub = 0; const wchar_t *arg; wcstring storage; while ((arg = string_get_arg(&optind, argv, &storage, streams)) != NULL) { typedef wcstring::size_type size_type; size_type pos = 0; size_type count = wcstring::npos; wcstring s(arg); if (opts.start > 0) { pos = static_cast<size_type>(opts.start - 1); } else if (opts.start < 0) { assert(opts.start != LONG_MIN); // checked above size_type n = static_cast<size_type>(-opts.start); pos = n > s.length() ? 0 : s.length() - n; } if (pos > s.length()) { pos = s.length(); } if (opts.length >= 0) { count = static_cast<size_type>(opts.length); } // Note that std::string permits count to extend past end of string. if (!opts.quiet) { streams.out.append(s.substr(pos, count)); streams.out.append(L'\n'); } nsub++; } return nsub > 0 ? STATUS_CMD_OK : STATUS_CMD_ERROR; }
static int string_escape(parser_t &parser, io_streams_t &streams, int argc, wchar_t **argv) { options_t opts; opts.no_quoted_valid = true; int optind; int retval = parse_opts(&opts, &optind, 0, argc, argv, parser, streams); if (retval != STATUS_CMD_OK) return retval; escape_flags_t flags = ESCAPE_ALL; if (opts.no_quoted) flags |= ESCAPE_NO_QUOTED; int nesc = 0; wcstring storage; const wchar_t *arg; while ((arg = string_get_arg(&optind, argv, &storage, streams)) != 0) { streams.out.append(escape_string(arg, flags)); streams.out.append(L'\n'); nesc++; } return nesc > 0 ? STATUS_CMD_OK : STATUS_CMD_ERROR; }
/// Implementation of `string upper`. static int string_upper(parser_t &parser, io_streams_t &streams, int argc, wchar_t **argv) { options_t opts; opts.quiet_valid = true; int optind; int retval = parse_opts(&opts, &optind, 0, argc, argv, parser, streams); if (retval != STATUS_CMD_OK) return retval; int n_transformed = 0; wcstring storage; while (const wchar_t *arg = string_get_arg(&optind, argv, &storage, streams)) { wcstring transformed(arg); std::transform(transformed.begin(), transformed.end(), transformed.begin(), std::towupper); if (wcscmp(transformed.c_str(), arg)) n_transformed++; if (!opts.quiet) { streams.out.append(transformed); streams.out.append(L'\n'); } } return n_transformed > 0 ? STATUS_CMD_OK : STATUS_CMD_ERROR; }
static int string_match(parser_t &parser, io_streams_t &streams, int argc, wchar_t **argv) { wchar_t *cmd = argv[0]; options_t opts; opts.all_valid = true; opts.entire_valid = true; opts.ignore_case_valid = true; opts.invert_valid = true; opts.quiet_valid = true; opts.regex_valid = true; opts.index_valid = true; int optind; int retval = parse_opts(&opts, &optind, 1, argc, argv, parser, streams); if (retval != STATUS_CMD_OK) return retval; const wchar_t *pattern = opts.arg1; if (opts.entire && opts.index) { streams.err.append_format(BUILTIN_ERR_COMBO2, cmd, _(L"--enter and --index are mutually exclusive")); return STATUS_INVALID_ARGS; } std::unique_ptr<string_matcher_t> matcher; if (opts.regex) { matcher = make_unique<pcre2_matcher_t>(cmd, pattern, opts, streams); } else { matcher = make_unique<wildcard_matcher_t>(cmd, pattern, opts, streams); } const wchar_t *arg; wcstring storage; while ((arg = string_get_arg(&optind, argv, &storage, streams)) != 0) { if (!matcher->report_matches(arg)) { return STATUS_INVALID_ARGS; } } return matcher->match_count() > 0 ? STATUS_CMD_OK : STATUS_CMD_ERROR; }
static int string_length(parser_t &parser, io_streams_t &streams, int argc, wchar_t **argv) { options_t opts; opts.quiet_valid = true; int optind; int retval = parse_opts(&opts, &optind, 0, argc, argv, parser, streams); if (retval != STATUS_CMD_OK) return retval; const wchar_t *arg; int nnonempty = 0; wcstring storage; while ((arg = string_get_arg(&optind, argv, &storage, streams)) != 0) { size_t n = wcslen(arg); if (n > 0) { nnonempty++; } if (!opts.quiet) { streams.out.append(to_string(n)); streams.out.append(L'\n'); } } return nnonempty > 0 ? STATUS_CMD_OK : STATUS_CMD_ERROR; }
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; wchar_t *endptr = NULL; for (;;) { int c = w.wgetopt_long(argc, argv, short_options, long_options, 0); if (c == -1) { break; } switch (c) { case 0: { break; } case 'l': { errno = 0; length = wcstol(w.woptarg, &endptr, 10); if (*endptr != L'\0' || (errno != 0 && errno != ERANGE)) { string_error(streams, BUILTIN_ERR_NOT_NUMBER, argv[0], w.woptarg); return BUILTIN_STRING_ERROR; } if (length < 0 || errno == ERANGE) { string_error(streams, _(L"%ls: Invalid length value '%ls'\n"), argv[0], w.woptarg); return BUILTIN_STRING_ERROR; } break; } case 'q': { quiet = true; break; } case 's': { errno = 0; start = wcstol(w.woptarg, &endptr, 10); if (*endptr != L'\0' || (errno != 0 && errno != ERANGE)) { string_error(streams, BUILTIN_ERR_NOT_NUMBER, argv[0], w.woptarg); return BUILTIN_STRING_ERROR; } 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; } 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; }
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': { errno = 0; wchar_t *endptr = 0; max = wcstol(w.woptarg, &endptr, 10); if (*endptr != L'\0' || errno != 0) { 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; }
static int string_replace(parser_t &parser, io_streams_t &streams, int argc, wchar_t **argv) { const wchar_t *short_options = L"aiqr"; const struct woption long_options[] = {{L"all", no_argument, 0, 'a'}, {L"ignore-case", no_argument, 0, 'i'}, {L"quiet", no_argument, 0, 'q'}, {L"regex", no_argument, 0, 'r'}, {0, 0, 0, 0}}; replace_options_t opts; bool regex = false; wgetopter_t w; for (;;) { int opt = w.wgetopt_long(argc, argv, short_options, long_options, 0); if (opt == -1) { break; } switch (opt) { case 0: { break; } case 'a': { opts.all = true; break; } case 'i': { opts.ignore_case = true; break; } case 'q': { opts.quiet = true; break; } case 'r': { regex = true; break; } 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 *pattern, *replacement; if ((pattern = string_get_arg_argv(&i, argv)) == 0) { string_error(streams, STRING_ERR_MISSING, argv[0]); return BUILTIN_STRING_ERROR; } if ((replacement = string_get_arg_argv(&i, argv)) == 0) { string_error(streams, STRING_ERR_MISSING, argv[0]); return BUILTIN_STRING_ERROR; } if (string_args_from_stdin(streams) && argc > i) { string_error(streams, BUILTIN_ERR_TOO_MANY_ARGUMENTS, argv[0]); return BUILTIN_STRING_ERROR; } string_replacer_t *replacer; if (regex) { replacer = new regex_replacer_t(argv[0], pattern, replacement, opts, streams); } else { replacer = new literal_replacer_t(argv[0], pattern, replacement, opts, streams); } const wchar_t *arg; wcstring storage; while ((arg = string_get_arg(&i, argv, &storage, streams)) != 0) { if (!replacer->replace_matches(arg)) { delete replacer; return BUILTIN_STRING_ERROR; } } int rc = replacer->replace_count() > 0 ? BUILTIN_STRING_OK : BUILTIN_STRING_NONE; delete replacer; return rc; }
static int string_join(parser_t &parser, io_streams_t &streams, int argc, wchar_t **argv) { const wchar_t *short_options = L"q"; const struct woption long_options[] = {{L"quiet", no_argument, 0, 'q'}, {0, 0, 0, 0}}; bool quiet = false; wgetopter_t w; for (;;) { int opt = w.wgetopt_long(argc, argv, short_options, long_options, 0); if (opt == -1) { break; } switch (opt) { case 0: { break; } case 'q': { quiet = true; break; } 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)) == 0) { string_error(streams, STRING_ERR_MISSING, argv[0]); return BUILTIN_STRING_ERROR; } if (string_args_from_stdin(streams) && argc > i) { string_error(streams, BUILTIN_ERR_TOO_MANY_ARGUMENTS, argv[0]); return BUILTIN_STRING_ERROR; } int nargs = 0; const wchar_t *arg; wcstring storage; while ((arg = string_get_arg(&i, argv, &storage, streams)) != 0) { if (!quiet) { if (nargs > 0) { streams.out.append(sep); } streams.out.append(arg); } nargs++; } if (nargs > 0 && !quiet) { streams.out.push_back(L'\n'); } return nargs > 1 ? BUILTIN_STRING_OK : BUILTIN_STRING_NONE; }
static int string_trim(parser_t &parser, io_streams_t &streams, int argc, wchar_t **argv) { const wchar_t *short_options = L":c:lqr"; const struct woption long_options[] = {{L"chars", required_argument, 0, 'c'}, {L"left", no_argument, 0, 'l'}, {L"quiet", no_argument, 0, 'q'}, {L"right", no_argument, 0, 'r'}, {0, 0, 0, 0}}; bool do_left = 0, do_right = 0; bool quiet = false; wcstring chars_to_trim = L" \f\n\r\t"; 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 'c': { chars_to_trim = w.woptarg; break; } case 'l': { do_left = true; break; } case 'q': { quiet = true; break; } case 'r': { do_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; if (string_args_from_stdin(streams) && argc > i) { string_error(streams, BUILTIN_ERR_TOO_MANY_ARGUMENTS, argv[0]); return BUILTIN_STRING_ERROR; } // If neither left or right is specified, we do both. if (!do_left && !do_right) { do_left = true; do_right = true; } const wchar_t *arg; size_t ntrim = 0; wcstring argstr; wcstring storage; while ((arg = string_get_arg(&i, argv, &storage, streams)) != 0) { argstr = arg; // Begin and end are respectively the first character to keep on the left, and first // character to trim on the right. The length is thus end - start. size_t begin = 0, end = argstr.size(); if (do_right) { size_t last_to_keep = argstr.find_last_not_of(chars_to_trim); end = (last_to_keep == wcstring::npos) ? 0 : last_to_keep + 1; } if (do_left) { size_t first_to_keep = argstr.find_first_not_of(chars_to_trim); begin = (first_to_keep == wcstring::npos ? end : first_to_keep); } assert(begin <= end && end <= argstr.size()); ntrim += argstr.size() - (end - begin); if (!quiet) { streams.out.append(wcstring(argstr, begin, end - begin)); streams.out.append(L'\n'); } } return ntrim > 0 ? BUILTIN_STRING_OK : BUILTIN_STRING_NONE; }
static int string_match(parser_t &parser, io_streams_t &streams, int argc, wchar_t **argv) { const wchar_t *short_options = L"ainvqr"; const struct woption long_options[] = {{L"all", no_argument, 0, 'a'}, {L"ignore-case", no_argument, 0, 'i'}, {L"index", no_argument, 0, 'n'}, {L"invert", no_argument, 0, 'v'}, {L"quiet", no_argument, 0, 'q'}, {L"regex", no_argument, 0, 'r'}, {0, 0, 0, 0}}; match_options_t opts; bool regex = false; wgetopter_t w; for (;;) { int opt = w.wgetopt_long(argc, argv, short_options, long_options, 0); if (opt == -1) { break; } switch (opt) { case 0: { break; } case 'a': { opts.all = true; break; } case 'i': { opts.ignore_case = true; break; } case 'n': { opts.index = true; break; } case 'v': { opts.invert_match = true; break; } case 'q': { opts.quiet = true; break; } case 'r': { regex = true; break; } 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 *pattern; if ((pattern = string_get_arg_argv(&i, argv)) == 0) { string_error(streams, STRING_ERR_MISSING, argv[0]); return BUILTIN_STRING_ERROR; } if (string_args_from_stdin(streams) && argc > i) { string_error(streams, BUILTIN_ERR_TOO_MANY_ARGUMENTS, argv[0]); return BUILTIN_STRING_ERROR; } std::unique_ptr<string_matcher_t> matcher; if (regex) { matcher = make_unique<pcre2_matcher_t>(argv[0], pattern, opts, streams); } else { matcher = make_unique<wildcard_matcher_t>(argv[0], pattern, opts, streams); } const wchar_t *arg; wcstring storage; while ((arg = string_get_arg(&i, argv, &storage, streams)) != 0) { if (!matcher->report_matches(arg)) { return BUILTIN_STRING_ERROR; } } int rc = matcher->match_count() > 0 ? BUILTIN_STRING_OK : BUILTIN_STRING_NONE; return rc; }