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 c = w.wgetopt_long(argc, argv, short_options, long_options, 0); if (c == -1) { break; } switch (c) { case 0: break; case 'q': quiet = true; 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; } 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 const wchar_t *string_get_arg(int *argidx, wchar_t **argv, wcstring *storage, const io_streams_t &streams) { if (string_args_from_stdin(streams)) { return string_get_arg_stdin(storage, streams); } return string_get_arg_argv(argidx, argv); }
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; }
/// Parse the arguments for flags recognized by a specific string subcommand. static int parse_opts(options_t *opts, int *optind, int n_req_args, int argc, wchar_t **argv, parser_t &parser, io_streams_t &streams) { const wchar_t *cmd = argv[0]; wcstring short_opts = construct_short_opts(opts); const wchar_t *short_options = short_opts.c_str(); int opt; wgetopter_t w; while ((opt = w.wgetopt_long(argc, argv, short_options, long_options, NULL)) != -1) { auto fn = flag_to_function.find(opt); if (fn != flag_to_function.end()) { int retval = fn->second(argv, parser, streams, w, opts); if (retval != STATUS_CMD_OK) return retval; } else if (opt == ':') { string_error(streams, STRING_ERR_MISSING, cmd); return STATUS_INVALID_ARGS; } else if (opt == '?') { string_unknown_option(parser, streams, cmd, argv[w.woptind - 1]); return STATUS_INVALID_ARGS; } else { DIE("unexpected retval from wgetopt_long"); } } *optind = w.woptind; // If the caller requires one or two mandatory args deal with that here. if (n_req_args) { opts->arg1 = string_get_arg_argv(optind, argv); if (!opts->arg1) { string_error(streams, STRING_ERR_MISSING, cmd); return STATUS_INVALID_ARGS; } } if (n_req_args > 1) { opts->arg2 = string_get_arg_argv(optind, argv); if (!opts->arg2) { string_error(streams, STRING_ERR_MISSING, cmd); return STATUS_INVALID_ARGS; } } // At this point we should not have optional args and be reading args from stdin. if (string_args_from_stdin(streams) && argc > *optind) { string_error(streams, BUILTIN_ERR_TOO_MANY_ARGUMENTS, cmd); return STATUS_INVALID_ARGS; } return STATUS_CMD_OK; }
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; }