@@ -19,6 +19,51 @@ def __str__(self):
1919 return "%s (%s, line %s)" % (self .msg , self .filename , self .lineno )
2020
2121
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+
2267class netrc :
2368 def __init__ (self , file = None ):
2469 default_netrc = file is None
@@ -33,61 +78,61 @@ def __init__(self, file=None):
3378 self ._parse (file , fp , default_netrc )
3479
3580 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 )
3982 while 1 :
4083 # 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 ()
4386 if not tt :
4487 break
4588 elif tt [0 ] == '#' :
46- if lexer . lineno == saved_lineno and len ( tt ) == 1 :
89+ if prev_lineno == lexer . lineno :
4790 lexer .instream .readline ()
4891 continue
4992 elif tt == 'machine' :
5093 entryname = lexer .get_token ()
5194 elif tt == 'default' :
5295 entryname = 'default'
53- elif tt == 'macdef' : # Just skip to end of macdefs
96+ elif tt == 'macdef' :
5497 entryname = lexer .get_token ()
5598 self .macros [entryname ] = []
56- lexer .whitespace = ' \t '
5799 while 1 :
58100 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 ' :
61106 break
62107 self .macros [entryname ].append (line )
63108 continue
64109 else :
65110 raise NetrcParseError (
66111 "bad toplevel token %r" % tt , file , lexer .lineno )
67112
113+ if not entryname :
114+ raise NetrcParseError ("missing %r name" % tt , file , lexer .lineno )
115+
68116 # We're looking at start of an entry for a named machine or default.
69- login = ''
70- account = password = None
117+ login = account = password = ''
71118 self .hosts [entryname ] = {}
72119 while 1 :
120+ prev_lineno = lexer .lineno
73121 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
85130 elif tt == 'login' or tt == 'user' :
86131 login = lexer .get_token ()
87132 elif tt == 'account' :
88133 account = lexer .get_token ()
89134 elif tt == 'password' :
90- if os .name == 'posix' and default_netrc :
135+ if os .name == 'posix' and default_netrc and login != "anonymous" :
91136 prop = os .fstat (fp .fileno ())
92137 if prop .st_uid != os .getuid ():
93138 import pwd
@@ -127,10 +172,10 @@ def __repr__(self):
127172 rep = ""
128173 for host in self .hosts .keys ():
129174 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 "
131176 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 "
134179 for macro in self .macros .keys ():
135180 rep = rep + "macdef " + macro + "\n "
136181 for line in self .macros [macro ]:
0 commit comments