@@ -19,6 +19,51 @@ def __str__(self):
19
19
return "%s (%s, line %s)" % (self .msg , self .filename , self .lineno )
20
20
21
21
22
+ class _netrclex :
23
+ def __init__ (self , fp ):
24
+ self .lineno = 1
25
+ self .instream = fp
26
+ self .whitespace = "\n \t \r "
27
+ self ._stack = []
28
+
29
+ def _read_char (self ):
30
+ ch = self .instream .read (1 )
31
+ if ch == "\n " :
32
+ self .lineno += 1
33
+ return ch
34
+
35
+ def get_token (self ):
36
+ if self ._stack :
37
+ return self ._stack .pop (0 )
38
+ token = ""
39
+ fiter = iter (self ._read_char , "" )
40
+ for ch in fiter :
41
+ if ch in self .whitespace :
42
+ continue
43
+ if ch == "\" " :
44
+ for ch in fiter :
45
+ if ch != "\" " :
46
+ if ch == "\\ " :
47
+ ch = self ._read_char ()
48
+ token += ch
49
+ continue
50
+ return token
51
+ else :
52
+ if ch == "\\ " :
53
+ ch = self ._read_char ()
54
+ token += ch
55
+ for ch in fiter :
56
+ if ch not in self .whitespace :
57
+ if ch == "\\ " :
58
+ ch = self ._read_char ()
59
+ token += ch
60
+ continue
61
+ return token
62
+ return token
63
+
64
+ def push_token (self , token ):
65
+ self ._stack .append (token )
66
+
22
67
class netrc :
23
68
def __init__ (self , file = None ):
24
69
default_netrc = file is None
@@ -33,61 +78,61 @@ def __init__(self, file=None):
33
78
self ._parse (file , fp , default_netrc )
34
79
35
80
def _parse (self , file , fp , default_netrc ):
36
- lexer = shlex .shlex (fp )
37
- lexer .wordchars += r"""!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~"""
38
- lexer .commenters = lexer .commenters .replace ('#' , '' )
81
+ lexer = _netrclex (fp )
39
82
while 1 :
40
83
# Look for a machine, default, or macdef top-level keyword
41
- saved_lineno = lexer .lineno
42
- toplevel = tt = lexer .get_token ()
84
+ prev_lineno = lexer .lineno
85
+ tt = lexer .get_token ()
43
86
if not tt :
44
87
break
45
88
elif tt [0 ] == '#' :
46
- if lexer . lineno == saved_lineno and len ( tt ) == 1 :
89
+ if prev_lineno == lexer . lineno :
47
90
lexer .instream .readline ()
48
91
continue
49
92
elif tt == 'machine' :
50
93
entryname = lexer .get_token ()
51
94
elif tt == 'default' :
52
95
entryname = 'default'
53
- elif tt == 'macdef' : # Just skip to end of macdefs
96
+ elif tt == 'macdef' :
54
97
entryname = lexer .get_token ()
55
98
self .macros [entryname ] = []
56
- lexer .whitespace = ' \t '
57
99
while 1 :
58
100
line = lexer .instream .readline ()
59
- if not line or line == '\012 ' :
60
- lexer .whitespace = ' \t \r \n '
101
+ if not line :
102
+ raise NetrcParseError (
103
+ "Macro definition missing null line terminator." ,
104
+ file , lexer .lineno )
105
+ if line == '\n ' :
61
106
break
62
107
self .macros [entryname ].append (line )
63
108
continue
64
109
else :
65
110
raise NetrcParseError (
66
111
"bad toplevel token %r" % tt , file , lexer .lineno )
67
112
113
+ if not entryname :
114
+ raise NetrcParseError ("missing %r name" % tt , file , lexer .lineno )
115
+
68
116
# We're looking at start of an entry for a named machine or default.
69
- login = ''
70
- account = password = None
117
+ login = account = password = ''
71
118
self .hosts [entryname ] = {}
72
119
while 1 :
120
+ prev_lineno = lexer .lineno
73
121
tt = lexer .get_token ()
74
- if (tt .startswith ('#' ) or
75
- tt in {'' , 'machine' , 'default' , 'macdef' }):
76
- if password :
77
- self .hosts [entryname ] = (login , account , password )
78
- lexer .push_token (tt )
79
- break
80
- else :
81
- raise NetrcParseError (
82
- "malformed %s entry %s terminated by %s"
83
- % (toplevel , entryname , repr (tt )),
84
- file , lexer .lineno )
122
+ if tt .startswith ('#' ):
123
+ if lexer .lineno == prev_lineno :
124
+ lexer .instream .readline ()
125
+ continue
126
+ if tt in {'' , 'machine' , 'default' , 'macdef' }:
127
+ self .hosts [entryname ] = (login , account , password )
128
+ lexer .push_token (tt )
129
+ break
85
130
elif tt == 'login' or tt == 'user' :
86
131
login = lexer .get_token ()
87
132
elif tt == 'account' :
88
133
account = lexer .get_token ()
89
134
elif tt == 'password' :
90
- if os .name == 'posix' and default_netrc :
135
+ if os .name == 'posix' and default_netrc and login != "anonymous" :
91
136
prop = os .fstat (fp .fileno ())
92
137
if prop .st_uid != os .getuid ():
93
138
import pwd
@@ -127,10 +172,10 @@ def __repr__(self):
127
172
rep = ""
128
173
for host in self .hosts .keys ():
129
174
attrs = self .hosts [host ]
130
- rep = rep + "machine " + host + "\n \t login " + repr ( attrs [0 ]) + "\n "
175
+ rep = rep + "machine " + host + "\n \t login " + attrs [0 ] + "\n "
131
176
if attrs [1 ]:
132
- rep = rep + "account " + repr ( attrs [1 ])
133
- rep = rep + "\t password " + repr ( attrs [2 ]) + "\n "
177
+ rep = rep + "account " + attrs [1 ]
178
+ rep = rep + "\t password " + attrs [2 ] + "\n "
134
179
for macro in self .macros .keys ():
135
180
rep = rep + "macdef " + macro + "\n "
136
181
for line in self .macros [macro ]:
0 commit comments