aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild/mesonlib.py
diff options
context:
space:
mode:
authorAleksey Gurtovoy <agurtovoy@acm.org>2019-08-09 16:06:47 -0500
committerJussi Pakkanen <jpakkane@gmail.com>2019-09-05 23:42:47 +0300
commit75daed27bc4e363696157617c7461414fc4e707b (patch)
tree2863934de82e0a7cc6a3dcd9ee23b4c4e378c550 /mesonbuild/mesonlib.py
parentcaec875fe1922b40037e1fd9229433ede64f9f25 (diff)
downloadmeson-75daed27bc4e363696157617c7461414fc4e707b.zip
meson-75daed27bc4e363696157617c7461414fc4e707b.tar.gz
meson-75daed27bc4e363696157617c7461414fc4e707b.tar.bz2
mesonlib.split_args/quote_arg/join_args
Diffstat (limited to 'mesonbuild/mesonlib.py')
-rw-r--r--mesonbuild/mesonlib.py80
1 files changed, 79 insertions, 1 deletions
diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py
index 1333027..d5646ed 100644
--- a/mesonbuild/mesonlib.py
+++ b/mesonbuild/mesonlib.py
@@ -17,7 +17,7 @@ from pathlib import Path
import sys
import stat
import time
-import platform, subprocess, operator, os, shutil, re
+import platform, subprocess, operator, os, shlex, shutil, re
import collections
from enum import Enum
from functools import lru_cache
@@ -729,6 +729,84 @@ def has_path_sep(name, sep='/\\'):
return True
return False
+
+if is_windows():
+ # shlex.split is not suitable for splitting command line on Window (https://bugs.python.org/issue1724822);
+ # shlex.quote is similarly problematic. Below are "proper" implementations of these functions according to
+ # https://docs.microsoft.com/en-us/cpp/c-language/parsing-c-command-line-arguments and
+ # https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/
+
+ _whitespace = ' \t\n\r'
+ _find_unsafe_char = re.compile(r'[{}"]'.format(_whitespace)).search
+
+ def quote_arg(arg):
+ if arg and not _find_unsafe_char(arg):
+ return arg
+
+ result = '"'
+ num_backslashes = 0
+ for c in arg:
+ if c == '\\':
+ num_backslashes += 1
+ else:
+ if c == '"':
+ # Escape all backslashes and the following double quotation mark
+ num_backslashes = num_backslashes * 2 + 1
+
+ result += num_backslashes * '\\' + c
+ num_backslashes = 0
+
+ # Escape all backslashes, but let the terminating double quotation
+ # mark we add below be interpreted as a metacharacter
+ result += (num_backslashes * 2) * '\\' + '"'
+ return result
+
+ def split_args(cmd):
+ result = []
+ arg = ''
+ num_backslashes = 0
+ num_quotes = 0
+ in_quotes = False
+ for c in cmd:
+ if c == '\\':
+ num_backslashes += 1
+ else:
+ if c == '"' and not (num_backslashes % 2):
+ # unescaped quote, eat it
+ arg += (num_backslashes // 2) * '\\'
+ num_quotes += 1
+ in_quotes = not in_quotes
+ elif c in _whitespace and not in_quotes:
+ if arg or num_quotes:
+ # reached the end of the argument
+ result.append(arg)
+ arg = ''
+ num_quotes = 0
+ else:
+ if c == '"':
+ # escaped quote
+ num_backslashes = (num_backslashes - 1) // 2
+
+ arg += num_backslashes * '\\' + c
+
+ num_backslashes = 0
+
+ if arg or num_quotes:
+ result.append(arg)
+
+ return result
+else:
+ def quote_arg(arg):
+ return shlex.quote(arg)
+
+ def split_args(cmd):
+ return shlex.split(cmd)
+
+
+def join_args(args):
+ return ' '.join([quote_arg(x) for x in args])
+
+
def do_replacement(regex, line, variable_format, confdata):
missing_variables = set()
start_tag = '@'