#! /usr/bin/python ######################################################################## # # reorder and reformat a file in columns # # this utility takes lines from its standard input and reproduces them, # partially reordered and reformatted, on its standard output. # # It has the same effect as a 'sort | column -t', with the exception # that empty lines, as well as lines which start with a '#' sign, are # not affected, i.e. they keep their position and formatting, and act # as separators, i.e. the parts before and after them are each sorted # separately (but overall field widths are computed across the whole # input). # # Options: # -i: # --ignore-case: # Do not consider case when sorting. # -d: # --default: # What to chage empty fields to. # -s : # --split=: # Treat only the first N whitespace sequences as separators. # line content after the Nth separator will count as only one # field even if it contains whitespace. # Example : '-s 2' causes input 'a b c d e' to be split into # three fields, 'a', 'b', and 'c d e'. # # boards.cfg requires -ids 6. # ######################################################################## import sys, getopt, locale # ensure we sort using the C locale. locale.setlocale(locale.LC_ALL, 'C') # check options maxsplit = 0 ignore_case = 0 default_field ='' try: opts, args = getopt.getopt(sys.argv[1:], "id:s:", ["ignore-case","default","split="]) except getopt.GetoptError as err: print str(err) # will print something like "option -a not recognized" sys.exit(2) for o, a in opts: if o in ("-s", "--split"): maxsplit = eval(a) elif o in ("-i", "--ignore-case"): ignore_case = 1 elif o in ("-d", "--default"): default_field = a else: assert False, "unhandled option" # collect all lines from standard input and, for the ones which must be # reformatted and sorted, count their fields and compute each field's # maximum size input_lines = [] field_width = [] for line in sys.stdin: # remove final end of line input_line = line.strip('\n') if (len(input_line)>0) and (input_line[0] != '#'): # sortable line: split into fields fields = input_line.split(None,maxsplit) # if there are new fields, top up field_widths for f in range(len(field_width), len(fields)): field_width.append(0) # compute the maximum witdh of each field for f in range(len(fields)): field_width[f] = max(field_width[f],len(fields[f])) # collect the line for next stage input_lines.append(input_line) # run through collected input lines, collect the ones which must be # reformatted and sorted, and whenever a non-reformattable, non-sortable # line is met, sort the collected lines before it and append them to the # output lines, then add the non-sortable line too. output_lines = [] sortable_lines = [] for input_line in input_lines: if (len(input_line)>0) and (input_line[0] != '#'): # this line should be reformatted and sorted input_fields = input_line.split(None,maxsplit) output_fields = []; # reformat each field to this field's column width for f in range(len(input_fields)): output_field = input_fields[f]; output_fields.append(output_field.ljust(field_width[f])) # any missing field is set to default if it exists if default_field != '': for f in range(len(input_fields),len(field_width)): output_fields.append(default_field.ljust(field_width[f])) # join fields using two spaces, like column -t would output_line = ' '.join(output_fields); # collect line for later sortable_lines.append(output_line) else: # this line is non-sortable # sort collected sortable lines if ignore_case!=0: sortable_lines.sort(key=lambda x: str.lower(locale.strxfrm(x))) else: sortable_lines.sort(key=lambda x: locale.strxfrm(x)) # append sortable lines to the final output output_lines.extend(sortable_lines) sortable_lines = [] # append non-sortable line to the final output output_lines.append(input_line) # maybe we had sortable lines pending, so append them to the final output if ignore_case!=0: sortable_lines.sort(key=lambda x: str.lower(locale.strxfrm(x))) else: sortable_lines.sort(key=lambda x: locale.strxfrm(x)) output_lines.extend(sortable_lines) # run through output lines and print them, except rightmost whitespace for output_line in output_lines: print output_line.rstrip()