reorder_message_file.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. # Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC")
  2. #
  3. # This Source Code Form is subject to the terms of the Mozilla Public
  4. # License, v. 2.0. If a copy of the MPL was not distributed with this
  5. # file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6. # Reorder Message File
  7. #
  8. # Reads a message file into memory, then outputs it with the messages and
  9. # associated descriptions in alphabetical order.
  10. #
  11. # Invocation:
  12. # The code is invoked using the command line:
  13. #
  14. # python reorder.py message_file
  15. #
  16. # Output is written to stdout.
  17. import sys
  18. def remove_empty_leading_trailing(lines):
  19. """
  20. Removes leading and trailing empty lines.
  21. A list of strings is passed as argument, some of which may be empty.
  22. This function removes from the start and end of the list a contiguous
  23. sequence of empty lines and returns the result. Embedded sequences of
  24. empty lines are not touched.
  25. Parameters:
  26. lines List of strings to be modified.
  27. Return:
  28. Input list of strings with leading/trailing blank line sequences
  29. removed.
  30. """
  31. retlines = []
  32. # Dispose of degenerate case of empty array
  33. if len(lines) == 0:
  34. return retlines
  35. # Search for first non-blank line
  36. start = 0
  37. while start < len(lines):
  38. if len(lines[start]) > 0:
  39. break
  40. start = start + 1
  41. # Handle case when entire list is empty
  42. if start >= len(lines):
  43. return retlines
  44. # Search for last non-blank line
  45. finish = len(lines) - 1
  46. while finish >= 0:
  47. if len(lines[finish]) > 0:
  48. break
  49. finish = finish - 1
  50. retlines = lines[start:finish + 1]
  51. return retlines
  52. def canonicalise_message_line(line):
  53. """
  54. Given a line known to start with the '%' character (i.e. a line
  55. introducing a message), canonicalise it by ensuring that the result
  56. is of the form '%<single-space>MESSAGE_IDENTIFIER<single-space>text'.
  57. Parameters:
  58. line - input line. Known to start with a '%' and to have leading
  59. and trailing spaces removed.
  60. Return:
  61. Canonicalised line.
  62. """
  63. # Cope with degenerate case of a single "%"
  64. if len(line) == 1:
  65. return line
  66. # Get the rest of the line
  67. line = line[1:].lstrip()
  68. # Extract the first word (the message ID)
  69. words = line.split()
  70. message_line = "% " + words[0]
  71. # ... and now the rest of the line
  72. if len(line) > len(words[0]):
  73. message_line = message_line + " " + line[len(words[0]):].lstrip()
  74. return message_line
  75. def make_dict(lines):
  76. """
  77. Split the lines into segments starting with the message definition and
  78. place into a dictionary.
  79. Parameters:
  80. lines - list of lines containing the text of the message file (less the
  81. header).
  82. Returns:
  83. dictionary - map of the messages, keyed by the line that holds the message
  84. ID.
  85. """
  86. dictionary = {}
  87. message_key = canonicalise_message_line(lines[0])
  88. message_lines = [message_key]
  89. index = 1;
  90. while index < len(lines):
  91. if lines[index].startswith("%"):
  92. # Start of new message
  93. dictionary[message_key] = remove_empty_leading_trailing(message_lines)
  94. message_key = canonicalise_message_line(lines[index])
  95. message_lines = [message_key]
  96. else:
  97. message_lines.append(lines[index])
  98. index = index + 1
  99. dictionary[message_key] = remove_empty_leading_trailing(message_lines)
  100. return dictionary
  101. def print_dict(dictionary):
  102. """
  103. Prints the dictionary with a blank line between entries.
  104. Parameters:
  105. dictionary - Map holding the message dictionary
  106. """
  107. count = 0
  108. for msgid in sorted(dictionary):
  109. # Blank line before all entries but the first
  110. if count > 0:
  111. print("")
  112. count = count + 1
  113. # ... and the entry itself.
  114. for l in dictionary[msgid]:
  115. print(l.strip())
  116. def process_file(filename):
  117. """
  118. Processes a file by reading it and searching for the first line starting
  119. with the '%' sign. Everything before that line is treated as the file
  120. header and is copied to the output with leading and trailing spaces removed.
  121. After that, each message block is read and stored for later sorting.
  122. Parameters:
  123. filename Name of the message file to process
  124. """
  125. lines = open(filename).read().splitlines()
  126. # Search for the first line starting with the percent character. Everything
  127. # before it is considered the file header and is copied to the output with
  128. # leading and trailing spaces removed.
  129. index = 0
  130. while index < len(lines):
  131. if lines[index].startswith("%"):
  132. break
  133. print(lines[index].strip())
  134. index = index + 1
  135. # Now put the remaining lines into the message dictionary
  136. dictionary = make_dict(lines[index:])
  137. # ...and print it
  138. print_dict(dictionary)
  139. # Main program
  140. if __name__ == "__main__":
  141. # Read the files and load the data
  142. if len(sys.argv) != 2:
  143. print("Usage: python reorder.py message_file")
  144. else:
  145. process_file(sys.argv[1])