8000 New tty/pty modules by Steen; new urlparser. · python/cpython@23cb2a8 · GitHub
[go: up one dir, main page]

Skip to content

Commit 23cb2a8

Browse files
committed
New tty/pty modules by Steen; new urlparser.
1 parent c0af2aa commit 23cb2a8

File tree

3 files changed

+336
-0
lines changed

3 files changed

+336
-0
lines changed

Lib/pty.py

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
# pty.py -- Pseudo terminal utilities.
2+
3+
# Bugs: No signal handling. Doesn't set slave termios and window size.
4+
# Only tested on Linux.
5+
# See: W. Richard Stevens. 1992. Advanced Programming in the
6+
# UNIX Environment. Chapter 19.
7+
# Author: Steen Lumholt -- with additions by Guido.
8+
9+
from select import select
10+
import os, sys, FCNTL
11+
import tty
12+
13+
STDIN_FILENO = 0
14+
STDOUT_FILENO = 1
15+
STDERR_FILENO = 2
16+
17+
CHILD = 0
18+
19+
# Open pty master. Returns (master_fd, tty_name). SGI and Linux/BSD version.
20+
def master_open():
21+
try:
22+
import sgi
23+
except ImportError:
24+
pass
25+
else:
26+
try:
27+
tty_name, master_fd = sgi._getpty(FCNTL.O_RDWR, 0666, 0)
28+
except IOError, msg:
29+
raise os.error, msg
30+
return master_fd, tty_name
31+
for x in 'pqrstuvwxyzPQRST':
32+
for y in '0123456789abcdef':
33+
pty_name = '/dev/pty' + x + y
34+
try:
35+
fd = os.open(pty_name, FCNTL.O_RDWR)
36+
except os.error:
37+
continue
38+
return (fd, '/dev/tty' + x + y)
39+
raise os.error, 'out of pty devices'
40+
41+
# Open the pty slave. Acquire the controlling terminal.
42+
# Returns file descriptor. Linux version. (Should be universal? --Guido)
43+
def slave_open(tty_name):
44+
return os.open(tty_name, FCNTL.O_RDWR)
45+
46+
# Fork and make the child a session leader with a controlling terminal.
47+
# Returns (pid, master_fd)
48+
def fork():
49+
master_fd, tty_name = master_open()
50+
pid = os.fork()
51+
if pid == CHILD:
52+
# Establish a new session.
53+
os.setsid()
54+
55+
# Acquire controlling terminal.
56+
slave_fd = slave_open(tty_name)
57+
os.close(master_fd)
58+
59+
# Slave becomes stdin/stdout/stderr of child.
60+
os.dup2(slave_fd, STDIN_FILENO)
61+
os.dup2(slave_fd, STDOUT_FILENO)
62+
os.dup2(slave_fd, STDERR_FILENO)
63+
if (slave_fd > STDERR_FILENO):
64+
os.close (slave_fd)
65+
66+
# Parent and child process.
67+
return pid, master_fd
68+
69+
# Write all the data to a descriptor.
70+
def writen(fd, data):
71+
while data != '':
72+
n = os.write(fd, data)
73+
data = data[n:]
74+
75+
# Default read function.
76+
def read(fd):
77+
return os.read(fd, 1024)
78+
79+
# Parent copy loop.
80+
# Copies
81+
# pty master -> standard output (master_read)
82+
# standard input -> pty master (stdin_read)
83+
def copy(master_fd, master_read=read, stdin_read=read):
84+
while 1:
85+
rfds, wfds, xfds = select(
86+
[master_fd, STDIN_FILENO], [], [])
87+
if master_fd in rfds:
88+
data = master_read(master_fd)
89+
os.write(STDOUT_FILENO, data)
90+
if STDIN_FILENO in rfds:
91+
data = stdin_read(STDIN_FILENO)
92+
writen(master_fd, data)
93+
94+
# Create a spawned process.
95+
def spawn(argv, master_read=read, stdin_read=read):
96+
if type(argv) == type(''):
97+
argv = (argv,)
98+
pid, master_fd = fork()
99+
if pid == CHILD:
100+
apply(os.execlp, (argv[0],) + argv)
101+
mode = tty.tcgetattr(STDIN_FILENO)
102+
tty.setraw(STDIN_FILENO)
103+
try:
104+
copy(master_fd, master_read, stdin_read)
105+
except:
106+
tty.tcsetattr(STDIN_FILENO, tty.TCSAFLUSH, mode)

Lib/tty.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# tty.py -- Terminal utilities.
2+
# Author: Steen Lumholt.
3+
4+
from TERMIOS import *
5+
from termios import *
6+
7+
# Indexes for termios list.
8+
IFLAG = 0
9+
OFLAG = 1
10+
CFLAG = 2
11+
LFLAG = 3
12+
ISPEED = 4
13+
OSPEED = 5
14+
CC = 6
15+
16+
# Put terminal into a raw mode.
17+
def setraw(fd, when=TCSAFLUSH):
18+
mode = tcgetattr(fd)
19+
mode[IFLAG] = mode[IFLAG] & ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON)
20+
mode[OFLAG] = mode[OFLAG] & ~(OPOST)
21+
mode[CFLAG] = mode[CFLAG] & ~(CSIZE | PARENB)
22+
mode[CFLAG] = mode[CFLAG] | CS8
23+
mode[LFLAG] = mode[LFLAG] & ~(ECHO | ICANON | IEXTEN | ISIG)
24+
mode[CC][VMIN] = 1
25+
mode[CC][VTIME] = 0
26+
tcsetattr(fd, when, mode)
27+
28+
# Put terminal into a cbreak mode.
29+
def setcbreak(fd, when=TCSAFLUSH):
30+
mode = tcgetattr(fd)
31+
mode[LFLAG] = mode[LFLAG] & ~(ECHO | ICANON)
32+
mode[CC][VMIN] = 1
33+
mode[CC][VTIME] = 0
34+
tcsetattr(fd, when, mode)
35+

Lib/urlparse.py

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
# Parse (absolute and relative) URLs according to latest internet draft:
2+
3+
# Uniform Resource Identifiers Working Group R. Fielding
4+
# INTERNET-DRAFT UC Irvine
5+
# Expires February 24, 1995 August 24, 1994
6+
#
7+
# Relative Uniform Resource Locators
8+
# <draft-ietf-uri-relative-url-00.txt>
9+
10+
# Standard/builtin Python modules
11+
import string
12+
13+
# A classification of schemes ('' means apply by default)
14+
uses_relative = ['ftp', 'http', 'gopher', 'nntp', 'wais', 'file',
15+
'prospero', '']
16+
uses_netloc = ['ftp', 'http', 'gopher', 'nntp', 'telnet', 'wais',
17+
'file', 'prospero', '']
18+
non_hierarchical = ['gopher', 'mailto', 'news', 'telnet', 'wais']
19+
uses_params = ['ftp', 'prospero', '']
20+
uses_query = ['http', 'wais', '']
21+
uses_fragment = ['ftp', 'http', 'gopher', 'news', 'nntp', 'wais',
22+
'file', 'prospero', '']
23+
24+
# Characters valid in scheme names
25+
scheme_chars = string.letters + string.digits + '+-.'
26+
27+
# Parse a URL into 6 components:
28+
# <scheme>://<netloc>/<path>;<params>?<query>#<fragment>
29+
# Return a 6-tuple: (scheme, netloc, path, params, query, fragment).
30+
# Note that we don't break the components up in smaller bits
31+
# (e.g. netloc is a single string) and we don't expand % escapes.
32+
def urlparse(url, scheme = '', allow_framents = 1):
33+
netloc = ''
34+
path = ''
35+
params = ''
36+
query = ''
37+
fragment = ''
38+
i = string.find(url, ':')
39+
if i > 0:
40+
for c in url[:i]:
41+
if c not in scheme_chars:
42+
break
43+
else:
44+
scheme, url = string.lower(url[:i]), url[i+1:]
45+
if scheme in uses_netloc:
46+
if url[:2] == '//':
47+
i = string.find(url, '/', 2)
48+
if i < 0:
49+
i = len(url)
50+
netloc, url = url[2:i], url[i:]
51+
if allow_framents and scheme in uses_fragment:
52+
i = string.rfind(url, '#')
53+
if i >= 0:
54+
url, fragment = url[:i], url[i+1:]
55+
if scheme in uses_query:
56+
i = string.find(url, '?')
57+
if i >= 0:
58+
url, query = url[:i], url[i+1:]
59+
if scheme in uses_params:
60+
i = string.find(url, ';')
61+
if i >= 0:
62+
url, params = url[:i], url[i+1:]
63+
return scheme, netloc, url, params, query, fragment
64+
65+
# Put a parsed URL back together again. This may result in a slightly
66+
# different, but equivalent URL, if the URL that was parsed originally
67+
# had redundant delimiters, e.g. a ? with an empty query (the draft
68+
# states that these are equivalent).
69+
def urlunparse((scheme, netloc, url, params, query, fragment)):
70+
if netloc:
71+
url = '//' + netloc + url
72+
if scheme:
73+
url = scheme + ':' + url
74+
if params:
75+
url = url + ';' + params
76+
if query:
77+
url = url + '?' + query
78+
if fragment:
79+
url = url + '#' + fragment
80+
return url
81+
82+
# Join a base URL and a possibly relative URL to form an absolute
83+
# interpretation of the latter.
84+
def urljoin(base, url, allow_framents = 1):
85+
if not base:
86+
return url
87+
bscheme, bnetloc, bpath, bparams, bquery, bfragment = \
88+
urlparse(base, '', allow_framents)
89+
scheme, netloc, path, params, query, fragment = \
90+
urlparse(url, bscheme, allow_framents)
91+
if scheme != bscheme or scheme not in uses_relative:
92+
return urlunparse((scheme, netloc, path,
93+
params, query, fragment))
94+
if scheme in uses_netloc:
95+
if netloc:
96+
return urlunparse((scheme, netloc, path,
97+
params, query, fragment))
98+
netloc = bnetloc
99+
if path[:1] == '/':
100+
return urlunparse((scheme, netloc, path,
101+
params, query, fragment))
102+
if not path:
103+
path = bpath
104+
if not query:
105+
query = bquery
106+
return urlunparse((scheme, netloc, path,
107+
params, query, fragment))
108+
i = string.rfind(bpath, '/')
109+
if i < 0:
110+
i = len(bpath)
111+
path = bpath[:i] + '/' + path
112+
segments = string.splitfields(path, '/')
113+
if segments[-1] == '.':
114+
segments[-1] = ''
115+
while '.' in segments:
116+
segments.remove('.')
117+
while 1:
118+
i = 1
119+
n = len(segments) - 1
120+
while i < n:
121+
if segments[i] == '..' and segments[i-1]:
122+
del segments[i-1:i+1]
123+
break
124+
i = i+1
125+
else:
126+
break
127+
if len(segments) >= 2 and segments[-1] == '..':
128+
segments[-2:] = ['']
129+
path = string.joinfields(segments, '/')
130+
return urlunparse((scheme, netloc, path,
131+
params, query, fragment))
132+
133+
test_input = """
134+
http://a/b/c/d
135+
136+
g:h = <URL:g:h>
137+
http:g = <URL:http://a/b/c/g>
138+
http: = <URL:http://a/b/c/d>
139+
g = <URL:http://a/b/c/g>
140+
./g = <URL:http://a/b/c/g>
141+
g/ = <URL:http://a/b/c/g/>
142+
/g = <URL:http://a/g>
143+
//g = <URL:http://g>
144+
?y = <URL:http://a/b/c/d?y>
145+
g?y = <URL:http://a/b/c/g?y>
146+
g?y/./x = <URL:http://a/b/c/g?y/./x>
147+
. = <URL:http://a/b/c/>
148+
./ = <URL:http://a/b/c/>
149+
.. = <URL:http://a/b/>
150+
../ = <URL:http://a/b/>
151+
../g = <URL:http://a/b/g>
152+
../.. = <URL:http://a/>
153+
../../g = <URL:http://a/g>
154+
../../../g = <URL:http://a/../g>
155+
./../g = <URL:http://a/b/g>
156+
./g/. = <URL:http://a/b/c/g/>
157+
/./g = <URL:http://a/./g>
158+
g/./h = <URL:http://a/b/c/g/h>
159+
g/../h = <URL:http://a/b/c/h>
160+
http:g = <URL:http://a/b/c/g>
161+
http: = <URL:http://a/b/c/d>
162+
"""
163+
164+
def test():
165+
import sys
166+
base = ''
167+
if sys.argv[1:]:
168+
fn = sys.argv[1]
169+
if fn == '-':
170+
fp = sys.stdin
171+
else:
172+
fp = open(fn)
173+
else:
174+
import StringIO
175+
fp = StringIO.StringIO(test_input)
176+
while 1:
177+
line = fp.readline()
178+
if not line: break
179+
words = string.split(line)
180+
if not words:
181+
continue
182+
url = words[0]
183+
parts = urlparse(url)
184+
print '%-10s : %s' % (url, parts)
185+
abs = urljoin(base, url)
186+
if not base:
187+
base = abs
188+
wrapped = '<URL:%s>' % abs
189+
print '%-10s = %s' % (url, wrapped)
190+
if len(words) == 3 and words[1] == '=':
191+
if wrapped != words[2]:
192+
print 'EXPECTED', words[2], '!!!!!!!!!!'
193+
194+
if __name__ == '__main__':
195+
test()

0 commit comments

Comments
 (0)
0