Skip to content

Add response file support for command line options#121

Merged
timr1126 merged 5 commits into
masterfrom
t-tiroma-response-files
Jan 18, 2019
Merged

Add response file support for command line options#121
timr1126 merged 5 commits into
masterfrom
t-tiroma-response-files

Conversation

@timr1126

Copy link
Copy Markdown
Contributor

Previous cppwinrt solution used CommandLineToArgvW to parse the response file, however this uses wide characters and is part of a Windows API, hence not cross-platform. Instead, the parsing mimics what crt does to get the command line to argv and argc. The rest of the logic is very similar to the previous implementation.

Comment thread src/library/cmd_reader.h
@@ -2,6 +2,8 @@

@kennykerr kennykerr Jan 11, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you base/reference your implementation on the CRT implementation?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, Ben sent me the original code.

Comment thread src/library/cmd_reader.h Outdated

#include "impl/base.h"

using namespace std::experimental::filesystem;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using directives in headers are not good design because it affects everyone including your header and can introduce namespace collisions.

Comment thread src/library/cmd_reader.h Outdated

std::map<std::string_view, std::vector<std::string>> m_options;

template<typename O, typename L>

@kennykerr kennykerr Jan 11, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Number one coding guideline: be consistent! 😉

In this case, don't mix tabs and spaces.

Comment thread src/library/cmd_reader.h Outdated
}

template <typename Character>
static void parse_command_line(

@kennykerr kennykerr Jan 11, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where did you get this implementation? If it's basically a copy/paste of the CRT code that's fine it just needs to be cleaned up. Consistency.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's parse_command_line from argv_parsing.cpp, slightly modified. Sounds good.

Comment thread src/library/cmd_reader.h Outdated
else if (svarg[0] == '@')
{
svarg.remove_prefix(1);
extract_respose_file(svarg, options);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo

Comment thread src/library/cmd_reader.h Outdated
std::map<std::string_view, std::vector<std::string>> m_options;

template<typename O, typename L>
void extract_option(std::string const& sarg, O const& options, L &last)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consistency: L& last

Comment thread src/library/cmd_reader.h Outdated
template<typename O, typename L>
void extract_option(std::string const& sarg, O const& options, L &last)
{
std::string_view svarg{ sarg };

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you need svarg (or just use sarg directly)?

Comment thread src/library/cmd_reader.h Outdated
std::map<std::string_view, std::vector<std::string>> m_options;

template<typename O, typename L>
void extract_option(std::string const& sarg, O const& options, L &last)

@kennykerr kennykerr Jan 11, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just make the parameter a string_view and avoid the copies.

Comment thread src/library/cmd_reader.h Outdated
template<typename O, typename L>
void extract_option(std::string const& sarg, O const& options, L &last)
{
std::string_view svarg{ sarg };

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is unnecessary.

Comment thread src/library/cmd_reader.h Outdated
}

template<typename O>
void extract_respose_file(std::string_view const& arg, O const& options)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo

@Scottj1s

Copy link
Copy Markdown
Member

Tim, can we get some standalone unit test cases added under xlang/src/test/cpp/test/? Don't need to drive the exe, just the cmd_reader with expected exceptions for failure cases, etc.

Comment thread src/library/cmd_reader.h Outdated
void extract_respose_file(std::string_view const& arg, O const& options)
{
path response_path{ std::string{ arg } };
std::wstring extension = response_path.extension();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extension returns a path, not a wstring. This won't compile on Clang.

Comment thread src/library/cmd_reader.h Outdated
m_options[last->name].push_back(std::string{ arg });
}
}
for (C i = 1; i < argc; ++i)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code still has white space issues all over the place. Find the "show white space" option in your editor and turn it on. Then change your editor settings to use a tab size of 4 and to insert tabs as spaces. Then cut and paste the entire source file and it should reset the white space consistently. Confirm visually.

Comment thread src/library/cmd_reader.h Outdated
}
for (C i = 1; i < argc; ++i)
{
extract_option(std::string_view{ std::string{ argv[i] } }, options, last);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of these conversions should be unnecessary as the extract_option function takes a string_view. You should be able to simply pass the argv[i] as the first argument.

Comment thread src/library/cmd_reader.h Outdated
std::map<std::string_view, std::vector<std::string>> m_options;

template<typename O, typename L>
void extract_option(std::string_view arg, O const& options, L& last)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consistency - use const& for string_view as that done elsewhere in this file.

@timr1126 timr1126 Jan 15, 2019

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove_prefix doesn't work with const& set. Should I change other methods to not be const& for consistency?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I didn't see that the function modifies the parameter. In that case, this is appropriate and you can just leave it as is.

Comment thread src/library/cmd_reader.h Outdated
std::experimental::filesystem::path response_path{ std::string{ arg } };
std::string extension = response_path.extension().generic_string();
std::transform(extension.begin(), extension.end(), extension.begin(), tolower);
if (is_directory(response_path) || extension == ".winmd")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Scottj1s I see you originally added this check. Any particular reason? I'd rather not have code checking for file extensions since it is not particularly reliable. What if a developer accidentally passes a .exe file name? I believe ifstream will also skip over directories, so perhaps we should just drop this check altogether.

Comment thread src/library/cmd_reader.h Outdated
auto last{ options.end() };
for (auto i = 0; i < argc; i++)
{
extract_option(std::string_view{ argv[i] }, options, last);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This conversion should also be unnecessary.

Comment thread src/library/cmd_reader.h Outdated
*argument_count = 0;

Character c;
std::string arg("");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This constructor argument is unnecessary.

Comment thread src/library/cmd_reader.h Outdated
Character c;
std::string arg("");
int copy_character; // 1 = copy char to arg
unsigned numslash; // num of backslashes seen

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is redundant. Perhaps just call the variable backslash_count.

Comment thread src/library/cmd_reader.h Outdated
{
*argument_count = 0;

Character c;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All the locals in this function should be initialized during declaration.

Comment thread src/library/cmd_reader.h Outdated
in_quotes = false;
first_arg = true;

// Loop on each argument

@kennykerr kennykerr Jan 15, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove comments that don't make the code substantially more understandable.

Comment thread src/library/cmd_reader.h Outdated

first_arg = false;
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This really needs some unit tests. 😉

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Working on em 👍

@timr1126 timr1126 force-pushed the t-tiroma-response-files branch 2 times, most recently from 698314e to 058d2ca Compare January 16, 2019 00:28
@timr1126 timr1126 force-pushed the t-tiroma-response-files branch from 058d2ca to b8acf63 Compare January 16, 2019 00:30
Comment thread src/test/cpp/test/CmdReader.cpp Outdated

TEST_CASE("CmdReader")
{
const std::vector<option> options

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

static

Comment thread src/library/cmd_reader.h Outdated
std::experimental::filesystem::path response_path{ std::string{ arg } };
std::string extension = response_path.extension().generic_string();
std::transform(extension.begin(), extension.end(), extension.begin(),
[](unsigned char c) { return static_cast<unsigned char>(::tolower(c)); });

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can make c 'auto'

Comment thread src/test/cpp/test/CmdReader.cpp Outdated
{
const char* argv[] = { "progname", "@respfile.txt" };
const size_t argc = 2;
std::ofstream resp_file;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider making an raii type here to consolidate common logic and delete file in presence of an exception

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be simpler and more maintainable just to have an actual file in the test project containing the test arguments and not bother with generating and then deleting a file.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually like the generation code - everything in one place

// input and output
{
const char* argv[] = { "progname", "-in", "example_file.in", "-out", "example_file.out" };
const size_t argc = 5;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all argc values can be = _countof(argv)

Comment thread src/test/cpp/test/CmdReader.cpp Outdated
std::ofstream resp_file;

resp_file.open("respfile.txt");
resp_file << "-in example\\\"file.in -out example\\\"file.out";

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider raw string literals

Comment thread src/test/cpp/test/CmdReader.cpp
Comment thread src/library/cmd_reader.h
std::string extension = response_path.extension().generic_string();
std::transform(extension.begin(), extension.end(), extension.begin(),
[](unsigned char c) { return static_cast<unsigned char>(::tolower(c)); });
if (is_directory(response_path) || extension == ".winmd")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add comment that this line is intended to help diagnose misuse of the '@' prefix (e.g., when supplying metadata files)

@timr1126 timr1126 force-pushed the t-tiroma-response-files branch from f751b80 to 8d2e326 Compare January 16, 2019 23:57
@timr1126 timr1126 force-pushed the t-tiroma-response-files branch from 8d2e326 to c16ac11 Compare January 16, 2019 23:59
@timr1126 timr1126 merged commit 80fac51 into master Jan 18, 2019
@timr1126 timr1126 deleted the t-tiroma-response-files branch January 18, 2019 19:59
@kennykerr

Copy link
Copy Markdown
Contributor

Thanks Tim!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants