1- #!/usr/bin/env python
2- """ grin searches text files.
1+ #!/usr/bin/env python3
2+ """
3+ grin searches text files.
34"""
45
56import argparse
1213import shlex
1314import stat
1415import sys
16+ from io import UnsupportedOperation
1517
1618# Constants
1719__version__ = '1.2.1'
2224POST = 1
2325
2426# Use file(1)'s choices for what's text and what's not.
25- TEXTCHARS = '' . join ( map ( chr , [7 , 8 , 9 , 10 , 12 , 13 , 27 ] + range (0x20 , 0x100 )))
26- ALLBYTES = '' . join ( map ( chr , range (256 ) ))
27+ TEXTCHARS = bytes ( [7 ,8 , 9 , 10 ,12 ,13 ,27 ] + list ( range (0x20 , 0x100 )))
28+ ALLBYTES = bytes ( range (256 ))
2729
2830COLOR_TABLE = ['black' , 'red' , 'green' , 'yellow' , 'blue' , 'magenta' , 'cyan' , 'white' , 'default' ]
2931COLOR_STYLE = {
3032 'filename' : dict (fg = "green" , bold = True ),
3133 'searchterm' : dict (fg = "black" , bg = "yellow" ),
3234}
35+ to_str = lambda s : s .decode ('latin1' )
3336
3437# gzip magic header bytes.
35- GZIP_MAGIC = '\037 \213 '
38+ GZIP_MAGIC = b '\037 \213 '
3639
3740# Target amount of data to read into memory at a time.
3841READ_BLOCKSIZE = 16 * 1024 * 1024
@@ -235,6 +238,10 @@ def read_block_with_context(self, prev, fp, fp_size):
235238 block_main = fp .read (target_io_size )
236239 is_last_block = target_io_size == remaining
237240
241+ if not isinstance (block_main , str ):
242+ # python3: ensure string are returned
243+ block_main = block_main .decode ("utf-8" )
244+
238245 if prev is None :
239246 if is_last_block :
240247 # FAST PATH: the entire file fits into a single block, so we
@@ -279,7 +286,7 @@ def read_block_with_context(self, prev, fp, fp_size):
279286 after_lines = '' .join (after_lines_list )
280287
281288 result = DataBlock (
282- data = before_lines + curr_block + after_lines ,
289+ data = ( before_lines + curr_block + after_lines ). decode ( "utf-8" ) ,
283290 start = len (before_lines ),
284291 end = len (before_lines ) + len (curr_block ),
285292 before_count = before_count ,
@@ -307,13 +314,15 @@ def do_grep(self, fp):
307314 fp_size = None # gzipped data is usually longer than the file
308315 else :
309316 try :
310- status = os .fstat (fp .fileno ())
317+ file_no = fp .fileno ()
318+ except (AttributeError , UnsupportedOperation ): # doesn't support fileno()
319+ fp_size = None
320+ else :
321+ status = os .fstat (file_no )
311322 if stat .S_ISREG (status .st_mode ):
312323 fp_size = status .st_size
313324 else :
314325 fp_size = None
315- except AttributeError : # doesn't support fileno()
316- fp_size = None
317326
318327 block = self .read_block_with_context (None , fp , fp_size )
319328 while block .end > block .start :
@@ -494,8 +503,8 @@ def grep_a_file(self, filename, opener=open):
494503 f = sys .stdin
495504 filename = '<STDIN>'
496505 else :
497- # 'r' does the right thing for both open ('rt') and gzip.open ('rb')
498- f = opener (filename , 'r ' )
506+ # Always open in binary mode
507+ f = opener (filename , 'rb ' )
499508 try :
500509 unique_context = self .do_grep (f )
501510 finally :
@@ -568,10 +577,8 @@ def is_binary(self, filename):
568577 -------
569578 is_binary : bool
570579 """
571- f = open (filename , 'rb' )
572- is_binary = self ._is_binary_file (f )
573- f .close ()
574- return is_binary
580+ with open (filename , 'rb' ) as fp :
581+ return self ._is_binary_file (fp )
575582
576583 def _is_binary_file (self , f ):
577584 """ Determine if a given filelike object has binary data or not.
@@ -585,12 +592,12 @@ def _is_binary_file(self, f):
585592 is_binary : bool
586593 """
587594 try :
588- bytes = f .read (self .binary_bytes )
595+ data = f .read (self .binary_bytes )
589596 except Exception as e :
590597 # When trying to read from something that looks like a gzipped file,
591598 # it may be corrupt. If we do get an error, assume that the file is binary.
592599 return True
593- return is_binary_string (bytes )
600+ return is_binary_string (data )
594601
595602 def is_gzipped_text (self , filename ):
596603 """ Determine if a given file is a gzip-compressed text file or not.
@@ -607,20 +614,17 @@ def is_gzipped_text(self, filename):
607614 is_gzipped_text : bool
608615 """
609616 is_gzipped_text = False
610- f = open (filename , 'rb' )
611- marker = f .read (2 )
612- f . close ()
617+ with open (filename , 'rb' ) as fp :
618+ marker = fp .read (2 )
619+
613620 if marker == GZIP_MAGIC :
614- fp = gzip .open (filename )
615- try :
621+ with gzip .open (filename ) as fp :
616622 try :
617623 is_gzipped_text = not self ._is_binary_file (fp )
618624 except IOError :
619625 # We saw the GZIP_MAGIC marker, but it is not actually a gzip
620626 # file.
621627 is_gzipped_text = False
622- finally :
623- fp .close ()
624628 return is_gzipped_text
625629
626630 def recognize (self , filename ):
@@ -1209,10 +1213,6 @@ def grin_main(argv=None):
12091213 raise
12101214
12111215
1212- def print_line (filename ):
1213- print (filename )
1214-
1215-
12161216def print_null (filename ):
12171217 # Note that the final filename will have a trailing NUL, just like
12181218 # "find -print0" does.
@@ -1233,7 +1233,7 @@ def grind_main(argv=None):
12331233 if args .null_separated :
12341234 output = print_null
12351235 else :
1236- output = print_line
1236+ output = print
12371237
12381238 if args .sys_path :
12391239 args .dirs .extend (sys .path )
0 commit comments