bug#40072: Incorrect escaping on MinGW 32-bit

Jeffrey Walton <[email protected]>
Newsgroups gmane.comp.gnu.libtool.bugs
Message-ID <CAH8yC8k0Ev84A7r+7bWPyyPFTxmsMcWbf0SvHaNZN+-=7BCSMA@mail.gmail.com>
On Sun, Mar 15, 2020 at 10:48 AM Jeffrey Walton <[email protected]> wrote:
>
> On Sun, Mar 15, 2020 at 9:59 AM Bob Friesenhahn
> <[email protected]> wrote:
> >
> > On Sun, 15 Mar 2020, Jeffrey Walton wrote:
> > ...
> Maybe libtool can do the same. Supply a small C program, compile it
> and call it from the libtool scripts. Its would be quite easy to
> supply the path in argv[1], and get back either (1) the original name
> (no spaces), (2) a short file name or (3) a quoted long file name. If
> the path gets split and shows up in pieces across argv[1]...argv[n-1],
> then just combine the pieces because you know what is supposed to
> happen.

Bob, see what you think about a program like the one attached. The C
code will be messier, but it is the same concept.

Here's what it returns during testing. The -c options means returns
string to use as a C declare.

With USE_WINDOWS_API (tested under MSYS):

    $ ./quote_path.exe "C:\Users\Jeffrey" "Walton\Desktop"
    C:\Users\JEFFRE~1\Desktop

    $ ./quote_path.exe -c "C:\Users\Jeffrey" "Walton\Desktop"
    "C:\\Users\\JEFFRE~1\\Desktop";

    $ ./quote_path.exe -c C:\\Users
    C:\\Users

Without USE_WINDOWS_API (tested under MSYS):

    $ ./quote_path.exe "C:\Users\Jeffrey" "Walton\Desktop"
    "C:\Users\Jeffrey Walton\Desktop"

    $ ./quote_path.exe -c "C:\Users\Jeffrey" "Walton\Desktop"
    "\"C:\\Users\\Jeffrey Walton\\Desktop\"";

    $ ./quote_path.exe C:\\Users\\Jeffrey Walton\\Desktop
    "C:\Users\Jeffrey Walton\Desktop"

    $ ./quote_path.exe -c C:\\Users\\Jeffrey Walton\\Desktop
    "\"C:\\Users\\Jeffrey Walton\\Desktop\"";

    $ ./quote_path.exe -c C:\\Users
    C:\\Users

I think offloading to an external program written for the specific
problem will probably simplify libtool and its helpers. It will make
your life a lot easier.

Jeff

_______________________________________________
Bug-libtool mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/bug-libtool
quote_path.cpp (text/x-c++src, 2.6 KB)
#include <iostream>
#include <string>
#include <algorithm>
#include <utility>
#include <utility>
#include <cstdlib>

#if defined(_WIN32) || defined(__MINGW32__) || defined(__MSYS__)
#define USE_WINDOWS_API 1
#endif

#if defined(USE_WINDOWS_API)
#include <windows.h>
#endif

// For testing on MinGW32 and MSYS
// #undef USE_WINDOWS_API

std::string escape_slashes(const std::string& str)
{
	std::string temp;
	temp.reserve(temp.size() + 16);

	for (size_t i=0; i<str.size(); ++i)
	{
		temp += str[i];
		if (str[i] == '\\')
			temp += '\\';
	}

	return temp;
}

std::string safe_path_unix(const std::string& str, bool c_declare)
{
	std::string the_path(str);

	std::string temp_path;
	temp_path.reserve(the_path.size()+8);

	bool need_quote = the_path.find(' ') != std::string::npos;

	if (need_quote && c_declare) {
		temp_path += "\"\\\"";
	}
	else if (need_quote) {
		temp_path += "\"";
	}

	if (c_declare) {
		temp_path += escape_slashes(the_path);
	}
	else {
		temp_path += the_path;
	}

	if (need_quote && c_declare) {
		temp_path += "\\\"\";";
	}
	else if (need_quote) {
		temp_path += "\"";
	}

	std::swap(the_path, temp_path);

	return the_path;
}

#if defined(USE_WINDOWS_API)
std::string safe_path_windows(const std::string& str, bool c_declare)
{
	std::string the_path(str);
	std::string temp_path;

	// GetShortPathName returns the size including the NULL for this case
	DWORD res1 = GetShortPathName(the_path.c_str(), NULL, 0);
	if (res1 == 0) {
		// Fallback to Unix escaping
		return safe_path_unix(str, c_declare);
	}

	temp_path.resize((size_t)res1);

	// GetShortPathName does not include the NULL for this case
	DWORD res2 = GetShortPathName(the_path.c_str(), &temp_path[0], res1);
	if (res2 == 0) {
		// Fallback to Unix escaping
		return safe_path_unix(str, c_declare);
	}

	// NULL is not included because the buffer was well sized
	temp_path.resize(res2);

	std::swap(the_path, temp_path);

	if (c_declare)
	{
		temp_path = "\"";
		temp_path += escape_slashes(the_path);
		temp_path += "\";";

		std::swap(the_path, temp_path);
	}

	return the_path;
}
#endif

int main(int argc, char* argv[])
{
	std::string the_path;
	bool c_declare = false;
	int index = 1;

	if (argc == 1) {
		std::exit(EXIT_FAILURE);
	}

    // -c option means format as C declare	
	if (argv[index][0] == '-' && argv[index][1] == 'c') {
		c_declare = true;
		index++;
	}

	// piece paths back together
	for (int i=index; i<argc; ++i) {
		if (i != index)
			the_path += ' ';

		the_path += argv[i];
	}

#if defined(USE_WINDOWS_API)
	the_path = safe_path_windows(the_path, c_declare);
#else
	the_path = safe_path_unix(the_path, c_declare);
#endif

	std::cout << the_path << std::endl;

	return EXIT_SUCCESS;
}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.