1#!/usr/bin/python3 2import re 3import argparse 4 5parser = argparse.ArgumentParser() 6parser.add_argument('inputs', nargs='+', help='Input filename') 7parser.add_argument('--min_lines', type=int, default=1, help='Specify the min number of lines to rearrange') 8args = parser.parse_args() 9 10min_num_lines = args.min_lines 11 12filename_regex = '(src|source|unit_test|include)/.*$' 13 14# caveat: Does fully not handle numbers with different number of digits. 15def compare_strs(str1, str2): 16 winner = 0 # which one's bigger 17 num_sort_mode = False 18 for i in range(min(len(str1),len(str2))): 19 if winner == 0: 20 if str1[i].isdigit() and str2[i].isdigit(): 21 if num_sort_mode: 22 str1_num += str1[i] 23 str2_num += str2[i] 24 else: 25 num_sort_mode = True 26 str1_num = str1[i] 27 str2_num = str2[i] 28 elif num_sort_mode: 29 if str1[i].isdigit(): str1_num += str1[i] 30 if str2[i].isdigit(): str2_num += str2[i] 31 winner = int(str1_num) - int(str2_num) 32 num_sort_mode = False 33 if winner != 0: break 34 if str1[i] != str2[i] and not num_sort_mode: 35 if str1[i] > str2[i]: 36 winner = 1 37 else: 38 winner = -1 39 if num_sort_mode: # if it's still in num_sort_mode then find the results 40 if len(str1)-1 > i: 41 i += 1 42 if str1[i].isdigit(): str1_num += str1[i] 43 elif len(str2)-1 > i: 44 i += 1 45 if str2[i].isdigit(): str2_num += str2[i] 46 if int(str1_num) > int(str2_num): 47 winner = 1 48 elif int(str1_num) < int(str2_num): 49 winner = -1 50 num_sort_mode = False 51 52 if winner == 0: 53 if len(str1) != len(str2): 54 if len(str1) > len(str2): 55 winner = 1 56 else: 57 winner = -1 58 return winner 59 60def cmp_to_key(mycmp): 61 'Convert a cmp= function into a key= function' 62 class K: 63 def __init__(self, obj, *args): 64 self.obj = obj 65 def __lt__(self, other): 66 return mycmp(self.obj, other.obj) < 0 67 def __gt__(self, other): 68 return mycmp(self.obj, other.obj) > 0 69 def __eq__(self, other): 70 return mycmp(self.obj, other.obj) == 0 71 def __le__(self, other): 72 return mycmp(self.obj, other.obj) <= 0 73 def __ge__(self, other): 74 return mycmp(self.obj, other.obj) >= 0 75 def __ne__(self, other): 76 return mycmp(self.obj, other.obj) != 0 77 return K 78 79def custom_sort(listy): 80 for _ in range(len(listy)-1+1): 81 for i in range(len(listy)-1): 82 bigger = compare_strs(listy[i], listy[i+1]) 83 if bigger > 0: 84 tmp_str = listy[i] 85 listy[i] = listy[i+1] 86 listy[i+1] = tmp_str 87 return listy 88 89# file_lines = [l.strip(stripchars) for l in file_lines] 90# currently sorting by first number in filename. smallest numbers first 91# this thing may need the ability to recognize filenames 92# file_lines = sorted(file_lines, key=lambda line: int(re.search('\d+', line.split('/')[-1] + ' 0').group(0))) 93input_filenames=args.inputs 94for input_filename in input_filenames: 95 with open(input_filename,'r') as file: 96 file_lines = file.read().split('\n') 97 output_filename=input_filename 98 files_range = [] # is a tuple 99 filenames_ranges = [] 100 for i, line in enumerate(file_lines): 101 if re.search(filename_regex, line): 102 if files_range == []: 103 files_range.append(i) 104 else: 105 if files_range != []: 106 files_range.append(i-1) 107 # manages min num lines 108 if files_range[1] - files_range[0] + 1 >= min_num_lines:filenames_ranges.append(files_range) 109 files_range = [] 110 if files_range != []: 111 files_range.append(i-1) 112 # manages min num lines 113 if files_range[1] - files_range[0] + 1 >= min_num_lines:filenames_ranges.append(files_range) 114 files_range = [] 115 116 117 for x in filenames_ranges: 118 # accommodate for a close bracket at the end of the last filename 119 if file_lines[x[1]][-1] == ')': 120 append_chars = ')' 121 file_lines[x[1]] = file_lines[x[1]][:-1] 122 else: 123 append_chars = '' 124 125 new_lines = sorted(file_lines[x[0]:x[1]+1], key=cmp_to_key(compare_strs)) 126 for i, l in enumerate(range(x[0], x[1]+1)): 127 file_lines[l] = new_lines[i] 128 if l == x[1]: 129 file_lines[l] += append_chars 130 131 with open(output_filename, 'w') as file: 132 file.write('\n'.join(file_lines)) 133