Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 26 additions & 7 deletions Lib/shlex.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,14 @@ def __init__(self, instream=None, infile=None, posix=False,
self.token = ''
self.filestack = deque()
self.source = None
# _pushback_chars is a push back queue used by lookahead logic
self._pushback_chars = deque()
if not punctuation_chars:
punctuation_chars = ''
elif punctuation_chars is True:
punctuation_chars = '();<>|&'
self._punctuation_chars = punctuation_chars
if punctuation_chars:
# _pushback_chars is a push back queue used by lookahead logic
self._pushback_chars = deque()
# these chars added because allowed in file names, args, wildcards
self.wordchars += '~-./*?='
#remove any punctuation chars from wordchars
Expand Down Expand Up @@ -132,7 +132,7 @@ def read_token(self):
quoted = False
escapedstate = ' '
while True:
if self.punctuation_chars and self._pushback_chars:
if self._pushback_chars:
nextchar = self._pushback_chars.pop()
else:
nextchar = self.instream.read(1)
Expand All @@ -156,8 +156,18 @@ def read_token(self):
else:
continue
elif nextchar in self.commenters:
self.instream.readline()
self.lineno += 1
if self.posix:
# Consume comment until newline or end of file
while True:
nextchar = self.instream.read(1)
if not nextchar:
break
if nextchar == '\n':
self._pushback_chars.append(nextchar)
break
else:
self.instream.readline()
self.lineno += 1
elif self.posix and nextchar in self.escape:
escapedstate = 'a'
self.state = nextchar
Expand Down Expand Up @@ -226,14 +236,23 @@ def read_token(self):
else:
continue
elif nextchar in self.commenters:
self.instream.readline()
self.lineno += 1
if self.posix:
# Consume comment until newline or end of file
while True:
nextchar = self.instream.read(1)
if not nextchar:
break
if nextchar == '\n':
self._pushback_chars.append(nextchar)
break
self.state = ' '
if self.token or (self.posix and quoted):
break # emit current token
else:
continue
else:
self.instream.readline()
self.lineno += 1
elif self.state == 'c':
if nextchar in self.punctuation_chars:
self.token += nextchar
Expand Down
9 changes: 9 additions & 0 deletions Lib/test/test_shlex.py
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,15 @@ def testPunctuationCharsReadOnly(self):
with self.assertRaises(AttributeError):
shlex_instance.punctuation_chars = False

def testNewlineAfterComment(self):
"""Test that newline after comment is not consumed (POSIX compliance)"""
# When whitespace is customized to exclude newlines, newlines should
# be treated as tokens, even when following a comment
s = shlex.shlex('a # comment \n b', posix=True)
s.whitespace = ' '
result = list(s)
self.assertEqual(result, ['a', '\n', 'b'])

@cpython_only
def test_lazy_imports(self):
import_helper.ensure_lazy_imports('shlex', {'collections', 're', 'os'})
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix :mod:`shlex` to preserve newlines after comments in POSIX mode.
Loading