]>
git.proxmox.com Git - ceph.git/blob - ceph/src/jaegertracing/opentelemetry-cpp/third_party/nlohmann-json/third_party/amalgamate/amalgamate.py
4 # amalgamate.py - Amalgamate C source and header files.
5 # Copyright (c) 2012, Erik Edlund <erik.edlund@32767.se>
7 # Redistribution and use in source and binary forms, with or without modification,
8 # are permitted provided that the following conditions are met:
10 # * Redistributions of source code must retain the above copyright notice,
11 # this list of conditions and the following disclaimer.
13 # * Redistributions in binary form must reproduce the above copyright notice,
14 # this list of conditions and the following disclaimer in the documentation
15 # and/or other materials provided with the distribution.
17 # * Neither the name of Erik Edlund, nor the names of its contributors may
18 # be used to endorse or promote products derived from this software without
19 # specific prior written permission.
21 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
22 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
25 # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
28 # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 from __future__
import division
33 from __future__
import print_function
34 from __future__
import unicode_literals
43 class Amalgamation(object):
45 # Prepends self.source_path to file_path if needed.
46 def actual_path(self
, file_path
):
47 if not os
.path
.isabs(file_path
):
48 file_path
= os
.path
.join(self
.source_path
, file_path
)
51 # Search included file_path in self.include_paths and
52 # in source_dir if specified.
53 def find_included_file(self
, file_path
, source_dir
):
54 search_dirs
= self
.include_paths
[:]
56 search_dirs
.insert(0, source_dir
)
58 for search_dir
in search_dirs
:
59 search_path
= os
.path
.join(search_dir
, file_path
)
60 if os
.path
.isfile(self
.actual_path(search_path
)):
64 def __init__(self
, args
):
65 with
open(args
.config
, 'r') as f
:
66 config
= json
.loads(f
.read())
68 setattr(self
, key
, config
[key
])
70 self
.verbose
= args
.verbose
== "yes"
71 self
.prologue
= args
.prologue
72 self
.source_path
= args
.source_path
73 self
.included_files
= []
75 # Generate the amalgamation and write it to the target file.
80 with
open(self
.prologue
, 'r') as f
:
81 amalgamation
+= datetime
.datetime
.now().strftime(f
.read())
85 print(" target = {0}".format(self
.target
))
86 print(" working_dir = {0}".format(os
.getcwd()))
87 print(" include_paths = {0}".format(self
.include_paths
))
88 print("Creating amalgamation:")
89 for file_path
in self
.sources
:
90 # Do not check the include paths while processing the source
91 # list, all given source paths must be correct.
92 # actual_path = self.actual_path(file_path)
93 print(" - processing \"{0}\"".format(file_path
))
94 t
= TranslationUnit(file_path
, self
, True)
95 amalgamation
+= t
.content
97 with
open(self
.target
, 'w') as f
:
102 print("Files processed: {0}".format(self
.sources
))
103 print("Files included: {0}".format(self
.included_files
))
107 def _is_within(match
, matches
):
109 if match
.start() > m
.start() and \
110 match
.end() < m
.end():
115 class TranslationUnit(object):
117 cpp_comment_pattern
= re
.compile(r
"//.*?\n")
120 c_comment_pattern
= re
.compile(r
"/\*.*?\*/", re
.S
)
122 # "complex \"stri\\\ng\" value".
123 string_pattern
= re
.compile("[^']" r
'".*?(?<=[^\\])"', re
.S
)
125 # Handle simple include directives. Support for advanced
126 # directives where macros and defines needs to expanded is
127 # not a concern right now.
128 include_pattern
= re
.compile(
129 r
'#\s*include\s+(<|")(?P<path>.*?)("|>)', re
.S
)
132 pragma_once_pattern
= re
.compile(r
'#\s*pragma\s+once', re
.S
)
134 # Search for pattern in self.content, add the match to
135 # contexts if found and update the index accordingly.
136 def _search_content(self
, index
, pattern
, contexts
):
137 match
= pattern
.search(self
.content
, index
)
139 contexts
.append(match
)
143 # Return all the skippable contexts, i.e., comments and strings
144 def _find_skippable_contexts(self
):
145 # Find contexts in the content in which a found include
146 # directive should not be processed.
147 skippable_contexts
= []
149 # Walk through the content char by char, and try to grab
150 # skippable contexts using regular expressions when found.
152 content_len
= len(self
.content
)
153 while i
< content_len
:
155 current
= self
.content
[i
]
156 previous
= self
.content
[j
]
160 i
= self
._search
_content
(j
, self
.string_pattern
,
162 elif current
== '*' and previous
== '/':
164 i
= self
._search
_content
(j
, self
.c_comment_pattern
,
166 elif current
== '/' and previous
== '/':
168 i
= self
._search
_content
(j
, self
.cpp_comment_pattern
,
171 # Skip to the next char.
174 return skippable_contexts
176 # Returns True if the match is within list of other matches
178 # Removes pragma once from content
179 def _process_pragma_once(self
):
180 content_len
= len(self
.content
)
181 if content_len
< len("#include <x>"):
184 # Find contexts in the content in which a found include
185 # directive should not be processed.
186 skippable_contexts
= self
._find
_skippable
_contexts
()
189 pragma_once_match
= self
.pragma_once_pattern
.search(self
.content
)
190 while pragma_once_match
:
191 if not _is_within(pragma_once_match
, skippable_contexts
):
192 pragmas
.append(pragma_once_match
)
194 pragma_once_match
= self
.pragma_once_pattern
.search(self
.content
,
195 pragma_once_match
.end())
197 # Handle all collected pragma once directives.
200 for pragma_match
in pragmas
:
201 tmp_content
+= self
.content
[prev_end
:pragma_match
.start()]
202 prev_end
= pragma_match
.end()
203 tmp_content
+= self
.content
[prev_end
:]
204 self
.content
= tmp_content
206 # Include all trivial #include directives into self.content.
207 def _process_includes(self
):
208 content_len
= len(self
.content
)
209 if content_len
< len("#include <x>"):
212 # Find contexts in the content in which a found include
213 # directive should not be processed.
214 skippable_contexts
= self
._find
_skippable
_contexts
()
216 # Search for include directives in the content, collect those
217 # which should be included into the content.
219 include_match
= self
.include_pattern
.search(self
.content
)
221 if not _is_within(include_match
, skippable_contexts
):
222 include_path
= include_match
.group("path")
223 search_same_dir
= include_match
.group(1) == '"'
224 found_included_path
= self
.amalgamation
.find_included_file(
225 include_path
, self
.file_dir
if search_same_dir
else None)
226 if found_included_path
:
227 includes
.append((include_match
, found_included_path
))
229 include_match
= self
.include_pattern
.search(self
.content
,
232 # Handle all collected include directives.
235 for include
in includes
:
236 include_match
, found_included_path
= include
237 tmp_content
+= self
.content
[prev_end
:include_match
.start()]
238 tmp_content
+= "// {0}\n".format(include_match
.group(0))
239 if found_included_path
not in self
.amalgamation
.included_files
:
240 t
= TranslationUnit(found_included_path
, self
.amalgamation
, False)
241 tmp_content
+= t
.content
242 prev_end
= include_match
.end()
243 tmp_content
+= self
.content
[prev_end
:]
244 self
.content
= tmp_content
248 # Make all content processing
251 self
._process
_pragma
_once
()
252 self
._process
_includes
()
254 def __init__(self
, file_path
, amalgamation
, is_root
):
255 self
.file_path
= file_path
256 self
.file_dir
= os
.path
.dirname(file_path
)
257 self
.amalgamation
= amalgamation
258 self
.is_root
= is_root
260 self
.amalgamation
.included_files
.append(self
.file_path
)
262 actual_path
= self
.amalgamation
.actual_path(file_path
)
263 if not os
.path
.isfile(actual_path
):
264 raise IOError("File not found: \"{0}\"".format(file_path
))
265 with
open(actual_path
, 'r') as f
:
266 self
.content
= f
.read()
271 description
= "Amalgamate C source and header files."
275 "-c path/to/config.json",
276 "-s path/to/source/dir",
277 "[-p path/to/prologue.(c|h)]"
279 argsparser
= argparse
.ArgumentParser(
280 description
=description
, usage
=usage
)
282 argsparser
.add_argument("-v", "--verbose", dest
="verbose",
283 choices
=["yes", "no"], metavar
="", help="be verbose")
285 argsparser
.add_argument("-c", "--config", dest
="config",
286 required
=True, metavar
="", help="path to a JSON config file")
288 argsparser
.add_argument("-s", "--source", dest
="source_path",
289 required
=True, metavar
="", help="source code path")
291 argsparser
.add_argument("-p", "--prologue", dest
="prologue",
292 required
=False, metavar
="", help="path to a C prologue file")
294 amalgamation
= Amalgamation(argsparser
.parse_args())
295 amalgamation
.generate()
298 if __name__
== "__main__":