1#!/usr/bin/python
2
3import sys
4import re
5import os
6
7INCLUDE_RE = re.compile('^#include "([^"]*)"$')
8
9def parse_include(line):
10  match = INCLUDE_RE.match(line)
11  return match.groups()[0] if match else None
12
13class Amalgamator:
14  def __init__(self, output_path, prefix):
15    self.include_paths = ["."]
16    self.included = set(["upb/port_def.inc", "upb/port_undef.inc"])
17    self.output_h = open(output_path + prefix + "upb.h", "w")
18    self.output_c = open(output_path + prefix + "upb.c", "w")
19
20    self.output_c.write("/* Amalgamated source file */\n")
21    self.output_c.write('#include "%supb.h"\n' % (prefix))
22    self.output_c.write(open("upb/port_def.inc").read())
23
24    self.output_h.write("/* Amalgamated source file */\n")
25    self.output_h.write('#include <stdint.h>')
26    self.output_h.write(open("upb/port_def.inc").read())
27
28  def add_include_path(self, path):
29      self.include_paths.append(path)
30
31  def finish(self):
32    self.output_c.write(open("upb/port_undef.inc").read())
33    self.output_h.write(open("upb/port_undef.inc").read())
34
35  def _process_file(self, infile_name, outfile):
36    file = None
37    for path in self.include_paths:
38        try:
39            full_path = os.path.join(path, infile_name)
40            file = open(full_path)
41            break
42        except IOError:
43            pass
44    if not file:
45        raise RuntimeError("Couldn't open file " + infile_name)
46
47    for line in file:
48      if not self._process_include(line, outfile):
49        outfile.write(line)
50
51  def _process_include(self, line, outfile):
52    include = parse_include(line)
53    if not include:
54      return False
55    if not (include.startswith("upb") or include.startswith("google")):
56      return False
57    if include.endswith("hpp"):
58      # Skip, we don't support the amalgamation from C++.
59      return True
60    else:
61      # Include this upb header inline.
62      if include not in self.included:
63        self.included.add(include)
64        self._add_header(include)
65      return True
66
67  def _add_header(self, filename):
68    self._process_file(filename, self.output_h)
69
70  def add_src(self, filename):
71    self._process_file(filename, self.output_c)
72
73# ---- main ----
74
75output_path = sys.argv[1]
76prefix = sys.argv[2]
77amalgamator = Amalgamator(output_path, prefix)
78files = []
79
80for arg in sys.argv[3:]:
81  arg = arg.strip()
82  if arg.startswith("-I"):
83    amalgamator.add_include_path(arg[2:])
84  elif arg.endswith(".h") or arg.endswith(".inc"):
85    pass
86  else:
87    files.append(arg)
88
89for filename in files:
90    amalgamator.add_src(filename)
91
92amalgamator.finish()
93