annotate_ifdef_directives 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. #!/usr/bin/python
  2. # Copyright (c) 2017-2019, The Tor Project, Inc.
  3. # See LICENSE for licensing information
  4. import re
  5. LINE_OBVIOUSNESS_LIMIT = 4
  6. class Problem(Exception):
  7. pass
  8. def uncomment(s):
  9. s = re.sub(r'//.*','',s)
  10. s = re.sub(r'/\*.*','',s)
  11. return s.strip()
  12. def translate(f_in, f_out):
  13. whole_file = []
  14. stack = []
  15. cur_level = whole_file
  16. lineno = 0
  17. for line in f_in:
  18. lineno += 1
  19. m = re.match(r'\s*#\s*(if|ifdef|ifndef|else|endif|elif)\b\s*(.*)',
  20. line)
  21. if not m:
  22. f_out.write(line)
  23. continue
  24. command,rest = m.groups()
  25. if command in ("if", "ifdef", "ifndef"):
  26. # The #if directive pushes us one level lower on the stack.
  27. if command == 'ifdef':
  28. rest = "defined(%s)"%uncomment(rest)
  29. elif command == 'ifndef':
  30. rest = "!defined(%s)"%uncomment(rest)
  31. elif rest.endswith("\\"):
  32. rest = rest[:-1]+"..."
  33. rest = uncomment(rest)
  34. new_level = [ (command, rest, lineno) ]
  35. stack.append(cur_level)
  36. cur_level = new_level
  37. f_out.write(line)
  38. elif command in ("else", "elif"):
  39. if len(cur_level) == 0 or cur_level[-1][0] == 'else':
  40. raise Problem("Unexpected #%s on %d"% (command,lineno))
  41. if (len(cur_level) == 1 and command == 'else' and
  42. lineno > cur_level[0][2] + LINE_OBVIOUSNESS_LIMIT):
  43. f_out.write("#else /* !(%s) */\n"%cur_level[0][1])
  44. else:
  45. f_out.write(line)
  46. cur_level.append((command, rest, lineno))
  47. else:
  48. assert command == 'endif'
  49. if len(stack) == 0:
  50. raise Problem("Unmatched #%s on %s"% (command,lineno))
  51. if lineno <= cur_level[0][2] + LINE_OBVIOUSNESS_LIMIT:
  52. f_out.write(line)
  53. elif len(cur_level) == 1 or (
  54. len(cur_level) == 2 and cur_level[1][0] == 'else'):
  55. f_out.write("#endif /* %s */\n"%cur_level[0][1])
  56. else:
  57. f_out.write("#endif /* %s || ... */\n"%cur_level[0][1])
  58. cur_level = stack.pop()
  59. if len(stack) or cur_level != whole_file:
  60. raise Problem("Missing #endif")
  61. import sys,os
  62. for fn in sys.argv[1:]:
  63. with open(fn+"_OUT", 'w') as output_file:
  64. translate(open(fn, 'r'), output_file)
  65. os.rename(fn+"_OUT", fn)