Filenames with spaces; output beside the input file; warning fixes (from dev c08eb1bbfa4c)

- Filenames may contain spaces: quote on the command line; filename
  lists use a standalone "/" separator; unseparated names that do not
  exist are rejoined into names that do (announced); leading ~ expands.
- Without -o, output is written to the input file's directory; -o fully
  specifies the output directory and basename.
- "Word not parsed" warnings now appear without -v, only for text that
  survives removal, with correct line numbers.
- New tst/filename_test.sh regression suite.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-26 23:22:59 +02:00
parent d9c98ac86d
commit fd9a370af7
21 changed files with 430 additions and 34 deletions

View File

@@ -175,6 +175,7 @@ void Argv::parse_vars(strings_t& words, string_map& named_args)
last++;
}
named_args[name] = join(strings_t(first, last), " ");
m_vectors[name] = strings_t(first, last);
words.erase(it, last);
}
}
@@ -369,6 +370,11 @@ Argv::classify_arguments(int argc, char* argv[], bool full_parse)
parse_optional(words, named_args);
parse_positional(argv_to_string(argc, argv), join(words, " "), named_args);
words.erase(std::remove(words.begin(), words.end(), Argv::delimiter), words.end());
if (m_req_names.size() == 1) {
// A single positional argument owns all remaining words; keep the
// original argv boundaries alongside the joined named_args value.
m_vectors[m_req_names[0]] = words;
}
// std::cout << "Named args:\n" << named_args << "\n";
return named_args;
}
@@ -556,7 +562,16 @@ std::string Argv::as_string(const std::string& name)
strings_t Argv::as_vector(const std::string& name)
{
(void)K::log(2, name);
return regex_split(get(name), std::regex(R"(\s+)"));
if (m_vectors.count(name) > 0) {
return m_vectors.at(name);
}
// No stored boundaries (e.g. an opt, whose value is a single argv
// word): the value is one element, spaces and all -- never re-split.
std::string value = get(name);
if (value.empty()) {
return {};
}
return { value };
}
std::pair<std::string, strings_t> Argv::as_input(const std::string& name, bool allow_empty)