1beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik# This code is original from jsmin by Douglas Crockford, it was translated to 2beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik# Python by Baruch Even. It was rewritten by Dave St.Germain for speed. 3beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik# 4beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik# The MIT License (MIT) 5beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik# 6beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik# Copyright (c) 2013 Dave St.Germain 7beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik# 8beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik# Permission is hereby granted, free of charge, to any person obtaining a copy 9beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik# of this software and associated documentation files (the "Software"), to deal 10beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik# in the Software without restriction, including without limitation the rights 11beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik# copies of the Software, and to permit persons to whom the Software is 13beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik# furnished to do so, subject to the following conditions: 14beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik# 15beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik# The above copyright notice and this permission notice shall be included in 16beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik# all copies or substantial portions of the Software. 17beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik# 18beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik# THE SOFTWARE. 25beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik 26beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik 27beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craikimport sys 28beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craikis_3 = sys.version_info >= (3, 0) 29beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craikif is_3: 30beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik import io 31beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craikelse: 32beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik import StringIO 33beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik try: 34beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik import cStringIO 35beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik except ImportError: 36beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik cStringIO = None 37beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik 38beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik 39beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik__all__ = ['jsmin', 'JavascriptMinify'] 40beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik__version__ = '2.0.9' 41beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik 42beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik 43beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craikdef jsmin(js): 44beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik """ 45beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik returns a minified version of the javascript string 46beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik """ 47beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik if not is_3: 48beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik if cStringIO and not isinstance(js, unicode): 49beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik # strings can use cStringIO for a 3x performance 50beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik # improvement, but unicode (in python2) cannot 51beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik klass = cStringIO.StringIO 52beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik else: 53beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik klass = StringIO.StringIO 54beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik else: 55beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik klass = io.StringIO 56beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik ins = klass(js) 57beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik outs = klass() 58beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik JavascriptMinify(ins, outs).minify() 59beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik return outs.getvalue() 60beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik 61beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik 62beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craikclass JavascriptMinify(object): 63beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik """ 64beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik Minify an input stream of javascript, writing 65beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik to an output stream 66beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik """ 67beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik 68beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik def __init__(self, instream=None, outstream=None): 69beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik self.ins = instream 70beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik self.outs = outstream 71beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik 72beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik def minify(self, instream=None, outstream=None): 73beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik if instream and outstream: 74beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik self.ins, self.outs = instream, outstream 75beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik 76beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik self.is_return = False 77beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik self.return_buf = '' 78beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik 79beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik def write(char): 80beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik # all of this is to support literal regular expressions. 81beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik # sigh 82beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik if char in 'return': 83beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik self.return_buf += char 84beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik self.is_return = self.return_buf == 'return' 85beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik self.outs.write(char) 86beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik if self.is_return: 87beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik self.return_buf = '' 88beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik 89beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik read = self.ins.read 90beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik 91beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik space_strings = "abcdefghijklmnopqrstuvwxyz"\ 92beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$\\" 93beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik starters, enders = '{[(+-', '}])+-"\'' 94beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik newlinestart_strings = starters + space_strings 95beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik newlineend_strings = enders + space_strings 96beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik do_newline = False 97beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik do_space = False 98beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik escape_slash_count = 0 99beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik doing_single_comment = False 100beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik previous_before_comment = '' 101beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik doing_multi_comment = False 102beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik in_re = False 103beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik in_quote = '' 104beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik quote_buf = [] 105beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik 106beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik previous = read(1) 107beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik if previous == '\\': 108beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik escape_slash_count += 1 109beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik next1 = read(1) 110beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik if previous == '/': 111beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik if next1 == '/': 112beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik doing_single_comment = True 113beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik elif next1 == '*': 114beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik doing_multi_comment = True 115beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik previous = next1 116beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik next1 = read(1) 117beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik else: 118beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik write(previous) 119beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik elif not previous: 120beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik return 121beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik elif previous >= '!': 122beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik if previous in "'\"": 123beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik in_quote = previous 124beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik write(previous) 125beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik previous_non_space = previous 126beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik else: 127beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik previous_non_space = ' ' 128beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik if not next1: 129beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik return 130beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik 131beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik while 1: 132beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik next2 = read(1) 133beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik if not next2: 134beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik last = next1.strip() 135beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik if not (doing_single_comment or doing_multi_comment)\ 136beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik and last not in ('', '/'): 137beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik if in_quote: 138beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik write(''.join(quote_buf)) 139beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik write(last) 140beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik break 141beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik if doing_multi_comment: 142beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik if next1 == '*' and next2 == '/': 143beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik doing_multi_comment = False 144beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik next2 = read(1) 145beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik elif doing_single_comment: 146beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik if next1 in '\r\n': 147beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik doing_single_comment = False 148beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik while next2 in '\r\n': 149beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik next2 = read(1) 150beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik if not next2: 151beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik break 152beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik if previous_before_comment in ')}]': 153beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik do_newline = True 154beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik elif previous_before_comment in space_strings: 155beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik write('\n') 156beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik elif in_quote: 157beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik quote_buf.append(next1) 158beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik 159beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik if next1 == in_quote: 160beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik numslashes = 0 161beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik for c in reversed(quote_buf[:-1]): 162beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik if c != '\\': 163beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik break 164beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik else: 165beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik numslashes += 1 166beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik if numslashes % 2 == 0: 167beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik in_quote = '' 168beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik write(''.join(quote_buf)) 169beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik elif next1 in '\r\n': 170beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik if previous_non_space in newlineend_strings \ 171beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik or previous_non_space > '~': 172beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik while 1: 173beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik if next2 < '!': 174beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik next2 = read(1) 175beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik if not next2: 176beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik break 177beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik else: 178beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik if next2 in newlinestart_strings \ 179beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik or next2 > '~' or next2 == '/': 180beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik do_newline = True 181beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik break 182beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik elif next1 < '!' and not in_re: 183beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik if (previous_non_space in space_strings \ 184beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik or previous_non_space > '~') \ 185beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik and (next2 in space_strings or next2 > '~'): 186beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik do_space = True 187beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik elif previous_non_space in '-+' and next2 == previous_non_space: 188beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik # protect against + ++ or - -- sequences 189beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik do_space = True 190beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik elif self.is_return and next2 == '/': 191beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik # returning a regex... 192beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik write(' ') 193beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik elif next1 == '/': 194beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik if do_space: 195beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik write(' ') 196beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik if in_re: 197beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik if previous != '\\' or (not escape_slash_count % 2) or next2 in 'gimy': 198beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik in_re = False 199beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik write('/') 200beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik elif next2 == '/': 201beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik doing_single_comment = True 202beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik previous_before_comment = previous_non_space 203beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik elif next2 == '*': 204beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik doing_multi_comment = True 205beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik previous = next1 206beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik next1 = next2 207beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik next2 = read(1) 208beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik else: 209beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik in_re = previous_non_space in '(,=:[?!&|' or self.is_return # literal regular expression 210beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik write('/') 211beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik else: 212beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik if do_space: 213beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik do_space = False 214beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik write(' ') 215beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik if do_newline: 216beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik write('\n') 217beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik do_newline = False 218beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik 219beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik write(next1) 220beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik if not in_re and next1 in "'\"": 221beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik in_quote = next1 222beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik quote_buf = [] 223beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik 224beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik previous = next1 225beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik next1 = next2 226beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik 227beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik if previous >= '!': 228beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik previous_non_space = previous 229beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik 230beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik if previous == '\\': 231beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik escape_slash_count += 1 232beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik else: 233beca7ae1f35e7f6605f4a21b5f4edeaa72000e39Chris Craik escape_slash_count = 0 234