17db96d56Sopenharmony_ci"""
27db96d56Sopenharmony_ciBasic subprocess implementation for POSIX which only uses os functions. Only
37db96d56Sopenharmony_ciimplement features required by setup.py to build C extension modules when
47db96d56Sopenharmony_cisubprocess is unavailable. setup.py is not used on Windows.
57db96d56Sopenharmony_ci"""
67db96d56Sopenharmony_ciimport os
77db96d56Sopenharmony_ci
87db96d56Sopenharmony_ci
97db96d56Sopenharmony_ci# distutils.spawn used by distutils.command.build_ext
107db96d56Sopenharmony_ci# calls subprocess.Popen().wait()
117db96d56Sopenharmony_ciclass Popen:
127db96d56Sopenharmony_ci    def __init__(self, cmd, env=None):
137db96d56Sopenharmony_ci        self._cmd = cmd
147db96d56Sopenharmony_ci        self._env = env
157db96d56Sopenharmony_ci        self.returncode = None
167db96d56Sopenharmony_ci
177db96d56Sopenharmony_ci    def wait(self):
187db96d56Sopenharmony_ci        pid = os.fork()
197db96d56Sopenharmony_ci        if pid == 0:
207db96d56Sopenharmony_ci            # Child process
217db96d56Sopenharmony_ci            try:
227db96d56Sopenharmony_ci                if self._env is not None:
237db96d56Sopenharmony_ci                    os.execve(self._cmd[0], self._cmd, self._env)
247db96d56Sopenharmony_ci                else:
257db96d56Sopenharmony_ci                    os.execv(self._cmd[0], self._cmd)
267db96d56Sopenharmony_ci            finally:
277db96d56Sopenharmony_ci                os._exit(1)
287db96d56Sopenharmony_ci        else:
297db96d56Sopenharmony_ci            # Parent process
307db96d56Sopenharmony_ci            _, status = os.waitpid(pid, 0)
317db96d56Sopenharmony_ci            self.returncode = os.waitstatus_to_exitcode(status)
327db96d56Sopenharmony_ci
337db96d56Sopenharmony_ci        return self.returncode
347db96d56Sopenharmony_ci
357db96d56Sopenharmony_ci
367db96d56Sopenharmony_cidef _check_cmd(cmd):
377db96d56Sopenharmony_ci    # Use regex [a-zA-Z0-9./-]+: reject empty string, space, etc.
387db96d56Sopenharmony_ci    safe_chars = []
397db96d56Sopenharmony_ci    for first, last in (("a", "z"), ("A", "Z"), ("0", "9")):
407db96d56Sopenharmony_ci        for ch in range(ord(first), ord(last) + 1):
417db96d56Sopenharmony_ci            safe_chars.append(chr(ch))
427db96d56Sopenharmony_ci    safe_chars.append("./-")
437db96d56Sopenharmony_ci    safe_chars = ''.join(safe_chars)
447db96d56Sopenharmony_ci
457db96d56Sopenharmony_ci    if isinstance(cmd, (tuple, list)):
467db96d56Sopenharmony_ci        check_strs = cmd
477db96d56Sopenharmony_ci    elif isinstance(cmd, str):
487db96d56Sopenharmony_ci        check_strs = [cmd]
497db96d56Sopenharmony_ci    else:
507db96d56Sopenharmony_ci        return False
517db96d56Sopenharmony_ci
527db96d56Sopenharmony_ci    for arg in check_strs:
537db96d56Sopenharmony_ci        if not isinstance(arg, str):
547db96d56Sopenharmony_ci            return False
557db96d56Sopenharmony_ci        if not arg:
567db96d56Sopenharmony_ci            # reject empty string
577db96d56Sopenharmony_ci            return False
587db96d56Sopenharmony_ci        for ch in arg:
597db96d56Sopenharmony_ci            if ch not in safe_chars:
607db96d56Sopenharmony_ci                return False
617db96d56Sopenharmony_ci
627db96d56Sopenharmony_ci    return True
637db96d56Sopenharmony_ci
647db96d56Sopenharmony_ci
657db96d56Sopenharmony_ci# _aix_support used by distutil.util calls subprocess.check_output()
667db96d56Sopenharmony_cidef check_output(cmd, **kwargs):
677db96d56Sopenharmony_ci    if kwargs:
687db96d56Sopenharmony_ci        raise NotImplementedError(repr(kwargs))
697db96d56Sopenharmony_ci
707db96d56Sopenharmony_ci    if not _check_cmd(cmd):
717db96d56Sopenharmony_ci        raise ValueError(f"unsupported command: {cmd!r}")
727db96d56Sopenharmony_ci
737db96d56Sopenharmony_ci    tmp_filename = "check_output.tmp"
747db96d56Sopenharmony_ci    if not isinstance(cmd, str):
757db96d56Sopenharmony_ci        cmd = " ".join(cmd)
767db96d56Sopenharmony_ci    cmd = f"{cmd} >{tmp_filename}"
777db96d56Sopenharmony_ci
787db96d56Sopenharmony_ci    try:
797db96d56Sopenharmony_ci        # system() spawns a shell
807db96d56Sopenharmony_ci        status = os.system(cmd)
817db96d56Sopenharmony_ci        exitcode = os.waitstatus_to_exitcode(status)
827db96d56Sopenharmony_ci        if exitcode:
837db96d56Sopenharmony_ci            raise ValueError(f"Command {cmd!r} returned non-zero "
847db96d56Sopenharmony_ci                             f"exit status {exitcode!r}")
857db96d56Sopenharmony_ci
867db96d56Sopenharmony_ci        try:
877db96d56Sopenharmony_ci            with open(tmp_filename, "rb") as fp:
887db96d56Sopenharmony_ci                stdout = fp.read()
897db96d56Sopenharmony_ci        except FileNotFoundError:
907db96d56Sopenharmony_ci            stdout = b''
917db96d56Sopenharmony_ci    finally:
927db96d56Sopenharmony_ci        try:
937db96d56Sopenharmony_ci            os.unlink(tmp_filename)
947db96d56Sopenharmony_ci        except OSError:
957db96d56Sopenharmony_ci            pass
967db96d56Sopenharmony_ci
977db96d56Sopenharmony_ci    return stdout
98