15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#!/usr/bin/env python
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2012 The Chromium Authors. All rights reserved.
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file.
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import glob
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import os
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import subprocess
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import sys
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from idl_option import GetOption, Option, ParseOptions
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from idl_outfile import IDLOutFile
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# IDLDiff
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# IDLDiff is a tool for comparing sets of IDL generated header files
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# with the standard checked in headers.  It does this by capturing the
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# output of the standard diff tool, parsing it into separate changes, then
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# ignoring changes that are know to be safe, such as adding or removing
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# blank lines, etc...
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Option('gen', 'IDL generated files', default='hdir')
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Option('src', 'Original ".h" files', default='../c')
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Option('halt', 'Stop if a difference is found')
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Option('diff', 'Directory holding acceptable diffs', default='diff')
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Option('ok', 'Write out the diff file.')
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Change
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# A Change object contains the previous lines, new news and change type.
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class Change(object):
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, mode, was, now):
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.mode = mode
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.was = was
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.now = now
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Dump(self):
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not self.was:
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      print 'Adding %s' % self.mode
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif not self.now:
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      print 'Missing %s' % self.mode
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      print 'Modifying %s' % self.mode
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for line in self.was:
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      print 'src: >>%s<<' % line
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for line in self.now:
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      print 'gen: >>%s<<' % line
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    print
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# IsCopyright
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Return True if this change is only a one line change in the copyright notice
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# such as non-matching years.
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def IsCopyright(change):
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if len(change.now) != 1 or len(change.was) != 1: return False
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if 'Copyright (c)' not in change.now[0]: return False
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if 'Copyright (c)' not in change.was[0]: return False
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return True
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# IsBlankComment
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Return True if this change only removes a blank line from a comment
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def IsBlankComment(change):
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if change.now: return False
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if len(change.was) != 1: return False
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if change.was[0].strip() != '*': return False
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return True
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# IsBlank
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Return True if this change only adds or removes blank lines
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def IsBlank(change):
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for line in change.now:
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if line: return False
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for line in change.was:
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if line: return False
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return True
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# IsCppComment
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Return True if this change only going from C++ to C style
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def IsToCppComment(change):
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if not len(change.now) or len(change.now) != len(change.was):
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return False
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for index in range(len(change.now)):
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    was = change.was[index].strip()
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if was[:2] != '//':
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return False
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    was = was[2:].strip()
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    now = change.now[index].strip()
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if now[:2] != '/*':
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return False
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    now = now[2:-2].strip()
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if now != was:
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return False
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return True
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return True
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def IsMergeComment(change):
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if len(change.was) != 1: return False
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if change.was[0].strip() != '*': return False
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for line in change.now:
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stripped = line.strip()
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if stripped != '*' and stripped[:2] != '/*' and stripped[-2:] != '*/':
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return False
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return True
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# IsSpacing
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Return True if this change is only different in the way 'words' are spaced
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# such as in an enum:
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#   ENUM_XXX   = 1,
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#   ENUM_XYY_Y = 2,
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# vs
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#   ENUM_XXX = 1,
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#   ENUM_XYY_Y = 2,
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def IsSpacing(change):
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if len(change.now) != len(change.was): return False
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for i in range(len(change.now)):
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Also ignore right side comments
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    line = change.was[i]
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    offs = line.find('//')
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if offs == -1:
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      offs = line.find('/*')
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if offs >-1:
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      line = line[:offs-1]
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    words1 = change.now[i].split()
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    words2 = line.split()
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if words1 != words2: return False
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return True
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# IsInclude
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Return True if change has extra includes
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def IsInclude(change):
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for line in change.was:
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if line.strip().find('struct'): return False
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for line in change.now:
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if line and '#include' not in line: return False
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return True
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# IsCppComment
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Return True if the change is only missing C++ comments
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def IsCppComment(change):
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if len(change.now): return False
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for line in change.was:
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    line = line.strip()
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if line[:2] != '//': return False
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return True
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# ValidChange
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Return True if none of the changes does not patch an above "bogus" change.
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def ValidChange(change):
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if IsToCppComment(change): return False
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if IsCopyright(change): return False
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if IsBlankComment(change): return False
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if IsMergeComment(change): return False
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if IsBlank(change): return False
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if IsSpacing(change): return False
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if IsInclude(change): return False
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if IsCppComment(change): return False
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return True
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Swapped
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Check if the combination of last + next change signals they are both
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# invalid such as swap of line around an invalid block.
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def Swapped(last, next):
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if not last.now and not next.was and len(last.was) == len(next.now):
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cnt = len(last.was)
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for i in range(cnt):
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      match = True
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for j in range(cnt):
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if last.was[j] != next.now[(i + j) % cnt]:
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          match = False
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if match: return True
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if not last.was and not next.now and len(last.now) == len(next.was):
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cnt = len(last.now)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for i in range(cnt):
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      match = True
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for j in range(cnt):
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if last.now[i] != next.was[(i + j) % cnt]:
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          match = False
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if match: return True
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return False
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def FilterLinesIn(output):
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  was = []
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  now = []
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  filter = []
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for index in range(len(output)):
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    filter.append(False)
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    line = output[index]
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if len(line) < 2: continue
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if line[0] == '<':
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if line[2:].strip() == '': continue
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      was.append((index, line[2:]))
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif line[0] == '>':
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if line[2:].strip() == '': continue
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      now.append((index, line[2:]))
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for windex, wline in was:
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for nindex, nline in now:
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if filter[nindex]: continue
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if filter[windex]: continue
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if wline == nline:
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        filter[nindex] = True
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        filter[windex] = True
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if GetOption('verbose'):
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          print "Found %d, %d >>%s<<" % (windex + 1, nindex + 1, wline)
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  out = []
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for index in range(len(output)):
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not filter[index]:
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      out.append(output[index])
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return out
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# GetChanges
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Parse the output into discrete change blocks.
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def GetChanges(output):
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Split on lines, adding an END marker to simply add logic
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  lines = output.split('\n')
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  lines = FilterLinesIn(lines)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  lines.append('END')
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  changes = []
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  was = []
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  now = []
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mode = ''
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  last = None
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for line in lines:
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#    print "LINE=%s" % line
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not line: continue
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif line[0] == '<':
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if line[2:].strip() == '': continue
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Ignore prototypes
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if len(line) > 10:
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        words = line[2:].split()
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if len(words) == 2 and words[1][-1] == ';':
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if words[0] == 'struct' or words[0] == 'union':
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            continue
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      was.append(line[2:])
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif line[0] == '>':
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if line[2:].strip() == '': continue
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if line[2:10] == '#include': continue
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      now.append(line[2:])
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif line[0] == '-':
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      change = Change(line, was, now)
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      was = []
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      now = []
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if ValidChange(change):
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          changes.append(change)
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if line == 'END':
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return FilterChanges(changes)
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def FilterChanges(changes):
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if len(changes) < 2: return changes
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  out = []
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  filter = [False for change in changes]
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for cur in range(len(changes)):
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for cmp in range(cur+1, len(changes)):
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if filter[cmp]:
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if Swapped(changes[cur], changes[cmp]):
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        filter[cur] = True
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        filter[cmp] = True
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for cur in range(len(changes)):
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if filter[cur]: continue
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    out.append(changes[cur])
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return out
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def Main(args):
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  filenames = ParseOptions(args)
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if not filenames:
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gendir = os.path.join(GetOption('gen'), '*.h')
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    filenames = sorted(glob.glob(gendir))
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    srcdir = os.path.join(GetOption('src'), '*.h')
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    srcs = sorted(glob.glob(srcdir))
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for name in srcs:
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      name = os.path.split(name)[1]
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      name = os.path.join(GetOption('gen'), name)
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if name not in filenames:
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        print 'Missing: %s' % name
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for filename in filenames:
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gen = filename
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    filename = filename[len(GetOption('gen')) + 1:]
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    src = os.path.join(GetOption('src'), filename)
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    diff = os.path.join(GetOption('diff'), filename)
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    p = subprocess.Popen(['diff', src, gen], stdout=subprocess.PIPE)
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    output, errors = p.communicate()
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    try:
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      input = open(diff, 'rt').read()
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    except:
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      input = ''
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if input != output:
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      changes = GetChanges(output)
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      changes = []
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if changes:
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      print "\n\nDelta between:\n  src=%s\n  gen=%s\n" % (src, gen)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for change in changes:
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        change.Dump()
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      print 'Done with %s\n\n' % src
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if GetOption('ok'):
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        open(diff, 'wt').write(output)
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if GetOption('halt'):
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return 1
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      print "\nSAME:\n  src=%s\n  gen=%s" % (src, gen)
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if input: print '  ** Matched expected diff. **'
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      print '\n'
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if __name__ == '__main__':
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sys.exit(Main(sys.argv[1:]))
355