xref: /openbsd-src/gnu/llvm/lldb/third_party/Python/module/pexpect-4.6/pexpect/utils.py (revision 061da546b983eb767bad15e67af1174fb0bcf31c)
1*061da546Spatrickimport os
2*061da546Spatrickimport sys
3*061da546Spatrickimport stat
4*061da546Spatrickimport select
5*061da546Spatrickimport time
6*061da546Spatrickimport errno
7*061da546Spatrick
8*061da546Spatricktry:
9*061da546Spatrick    InterruptedError
10*061da546Spatrickexcept NameError:
11*061da546Spatrick    # Alias Python2 exception to Python3
12*061da546Spatrick    InterruptedError = select.error
13*061da546Spatrick
14*061da546Spatrickif sys.version_info[0] >= 3:
15*061da546Spatrick    string_types = (str,)
16*061da546Spatrickelse:
17*061da546Spatrick    string_types = (unicode, str)
18*061da546Spatrick
19*061da546Spatrick
20*061da546Spatrickdef is_executable_file(path):
21*061da546Spatrick    """Checks that path is an executable regular file, or a symlink towards one.
22*061da546Spatrick
23*061da546Spatrick    This is roughly ``os.path isfile(path) and os.access(path, os.X_OK)``.
24*061da546Spatrick    """
25*061da546Spatrick    # follow symlinks,
26*061da546Spatrick    fpath = os.path.realpath(path)
27*061da546Spatrick
28*061da546Spatrick    if not os.path.isfile(fpath):
29*061da546Spatrick        # non-files (directories, fifo, etc.)
30*061da546Spatrick        return False
31*061da546Spatrick
32*061da546Spatrick    mode = os.stat(fpath).st_mode
33*061da546Spatrick
34*061da546Spatrick    if (sys.platform.startswith('sunos')
35*061da546Spatrick            and os.getuid() == 0):
36*061da546Spatrick        # When root on Solaris, os.X_OK is True for *all* files, irregardless
37*061da546Spatrick        # of their executability -- instead, any permission bit of any user,
38*061da546Spatrick        # group, or other is fine enough.
39*061da546Spatrick        #
40*061da546Spatrick        # (This may be true for other "Unix98" OS's such as HP-UX and AIX)
41*061da546Spatrick        return bool(mode & (stat.S_IXUSR |
42*061da546Spatrick                            stat.S_IXGRP |
43*061da546Spatrick                            stat.S_IXOTH))
44*061da546Spatrick
45*061da546Spatrick    return os.access(fpath, os.X_OK)
46*061da546Spatrick
47*061da546Spatrick
48*061da546Spatrickdef which(filename, env=None):
49*061da546Spatrick    '''This takes a given filename; tries to find it in the environment path;
50*061da546Spatrick    then checks if it is executable. This returns the full path to the filename
51*061da546Spatrick    if found and executable. Otherwise this returns None.'''
52*061da546Spatrick
53*061da546Spatrick    # Special case where filename contains an explicit path.
54*061da546Spatrick    if os.path.dirname(filename) != '' and is_executable_file(filename):
55*061da546Spatrick        return filename
56*061da546Spatrick    if env is None:
57*061da546Spatrick        env = os.environ
58*061da546Spatrick    p = env.get('PATH')
59*061da546Spatrick    if not p:
60*061da546Spatrick        p = os.defpath
61*061da546Spatrick    pathlist = p.split(os.pathsep)
62*061da546Spatrick    for path in pathlist:
63*061da546Spatrick        ff = os.path.join(path, filename)
64*061da546Spatrick        if is_executable_file(ff):
65*061da546Spatrick            return ff
66*061da546Spatrick    return None
67*061da546Spatrick
68*061da546Spatrick
69*061da546Spatrickdef split_command_line(command_line):
70*061da546Spatrick
71*061da546Spatrick    '''This splits a command line into a list of arguments. It splits arguments
72*061da546Spatrick    on spaces, but handles embedded quotes, doublequotes, and escaped
73*061da546Spatrick    characters. It's impossible to do this with a regular expression, so I
74*061da546Spatrick    wrote a little state machine to parse the command line. '''
75*061da546Spatrick
76*061da546Spatrick    arg_list = []
77*061da546Spatrick    arg = ''
78*061da546Spatrick
79*061da546Spatrick    # Constants to name the states we can be in.
80*061da546Spatrick    state_basic = 0
81*061da546Spatrick    state_esc = 1
82*061da546Spatrick    state_singlequote = 2
83*061da546Spatrick    state_doublequote = 3
84*061da546Spatrick    # The state when consuming whitespace between commands.
85*061da546Spatrick    state_whitespace = 4
86*061da546Spatrick    state = state_basic
87*061da546Spatrick
88*061da546Spatrick    for c in command_line:
89*061da546Spatrick        if state == state_basic or state == state_whitespace:
90*061da546Spatrick            if c == '\\':
91*061da546Spatrick                # Escape the next character
92*061da546Spatrick                state = state_esc
93*061da546Spatrick            elif c == r"'":
94*061da546Spatrick                # Handle single quote
95*061da546Spatrick                state = state_singlequote
96*061da546Spatrick            elif c == r'"':
97*061da546Spatrick                # Handle double quote
98*061da546Spatrick                state = state_doublequote
99*061da546Spatrick            elif c.isspace():
100*061da546Spatrick                # Add arg to arg_list if we aren't in the middle of whitespace.
101*061da546Spatrick                if state == state_whitespace:
102*061da546Spatrick                    # Do nothing.
103*061da546Spatrick                    None
104*061da546Spatrick                else:
105*061da546Spatrick                    arg_list.append(arg)
106*061da546Spatrick                    arg = ''
107*061da546Spatrick                    state = state_whitespace
108*061da546Spatrick            else:
109*061da546Spatrick                arg = arg + c
110*061da546Spatrick                state = state_basic
111*061da546Spatrick        elif state == state_esc:
112*061da546Spatrick            arg = arg + c
113*061da546Spatrick            state = state_basic
114*061da546Spatrick        elif state == state_singlequote:
115*061da546Spatrick            if c == r"'":
116*061da546Spatrick                state = state_basic
117*061da546Spatrick            else:
118*061da546Spatrick                arg = arg + c
119*061da546Spatrick        elif state == state_doublequote:
120*061da546Spatrick            if c == r'"':
121*061da546Spatrick                state = state_basic
122*061da546Spatrick            else:
123*061da546Spatrick                arg = arg + c
124*061da546Spatrick
125*061da546Spatrick    if arg != '':
126*061da546Spatrick        arg_list.append(arg)
127*061da546Spatrick    return arg_list
128*061da546Spatrick
129*061da546Spatrick
130*061da546Spatrickdef select_ignore_interrupts(iwtd, owtd, ewtd, timeout=None):
131*061da546Spatrick
132*061da546Spatrick    '''This is a wrapper around select.select() that ignores signals. If
133*061da546Spatrick    select.select raises a select.error exception and errno is an EINTR
134*061da546Spatrick    error then it is ignored. Mainly this is used to ignore sigwinch
135*061da546Spatrick    (terminal resize). '''
136*061da546Spatrick
137*061da546Spatrick    # if select() is interrupted by a signal (errno==EINTR) then
138*061da546Spatrick    # we loop back and enter the select() again.
139*061da546Spatrick    if timeout is not None:
140*061da546Spatrick        end_time = time.time() + timeout
141*061da546Spatrick    while True:
142*061da546Spatrick        try:
143*061da546Spatrick            return select.select(iwtd, owtd, ewtd, timeout)
144*061da546Spatrick        except InterruptedError:
145*061da546Spatrick            err = sys.exc_info()[1]
146*061da546Spatrick            if err.args[0] == errno.EINTR:
147*061da546Spatrick                # if we loop back we have to subtract the
148*061da546Spatrick                # amount of time we already waited.
149*061da546Spatrick                if timeout is not None:
150*061da546Spatrick                    timeout = end_time - time.time()
151*061da546Spatrick                    if timeout < 0:
152*061da546Spatrick                        return([], [], [])
153*061da546Spatrick            else:
154*061da546Spatrick                # something else caused the select.error, so
155*061da546Spatrick                # this actually is an exception.
156*061da546Spatrick                raise
157*061da546Spatrick
158*061da546Spatrick
159*061da546Spatrickdef poll_ignore_interrupts(fds, timeout=None):
160*061da546Spatrick    '''Simple wrapper around poll to register file descriptors and
161*061da546Spatrick    ignore signals.'''
162*061da546Spatrick
163*061da546Spatrick    if timeout is not None:
164*061da546Spatrick        end_time = time.time() + timeout
165*061da546Spatrick
166*061da546Spatrick    poller = select.poll()
167*061da546Spatrick    for fd in fds:
168*061da546Spatrick        poller.register(fd, select.POLLIN | select.POLLPRI | select.POLLHUP | select.POLLERR)
169*061da546Spatrick
170*061da546Spatrick    while True:
171*061da546Spatrick        try:
172*061da546Spatrick            timeout_ms = None if timeout is None else timeout * 1000
173*061da546Spatrick            results = poller.poll(timeout_ms)
174*061da546Spatrick            return [afd for afd, _ in results]
175*061da546Spatrick        except InterruptedError:
176*061da546Spatrick            err = sys.exc_info()[1]
177*061da546Spatrick            if err.args[0] == errno.EINTR:
178*061da546Spatrick                # if we loop back we have to subtract the
179*061da546Spatrick                # amount of time we already waited.
180*061da546Spatrick                if timeout is not None:
181*061da546Spatrick                    timeout = end_time - time.time()
182*061da546Spatrick                    if timeout < 0:
183*061da546Spatrick                        return []
184*061da546Spatrick            else:
185*061da546Spatrick                # something else caused the select.error, so
186*061da546Spatrick                # this actually is an exception.
187*061da546Spatrick                raise
188