diff options
author | japm48 <japm48@users.noreply.github.com> | 2020-03-26 16:01:00 +0100 |
---|---|---|
committer | Michael Dickens <michael.dickens@ettus.com> | 2020-04-10 14:57:01 -0400 |
commit | 4c4a85f2ebc43c9b7b3d5fdb8ad8387eae735f5f (patch) | |
tree | 10b5aa2671aafb9e393af7538177d2e48f60780d /gr-utils/modtool/tools/util_functions.py | |
parent | 78955a24c6c24f92f7b22ab9223e8e0b60b1dc4b (diff) |
gr-utils: restructure {mod,block}tool folders
Move modtool and blocktool outside of the python folder,
as per issue #2462.
Diffstat (limited to 'gr-utils/modtool/tools/util_functions.py')
-rw-r--r-- | gr-utils/modtool/tools/util_functions.py | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/gr-utils/modtool/tools/util_functions.py b/gr-utils/modtool/tools/util_functions.py new file mode 100644 index 0000000000..d7f2b11317 --- /dev/null +++ b/gr-utils/modtool/tools/util_functions.py @@ -0,0 +1,167 @@ +# +# Copyright 2013, 2018, 2019 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +# +""" Utility functions for gr_modtool """ + +from __future__ import print_function +from __future__ import absolute_import +from __future__ import unicode_literals + +import re +import sys +import readline + +# None of these must depend on other modtool stuff! + +def append_re_line_sequence(filename, linepattern, newline): + """ Detects the re 'linepattern' in the file. After its last occurrence, + paste 'newline'. If the pattern does not exist, append the new line + to the file. Then, write. """ + with open(filename, 'r') as f: + oldfile = f.read() + lines = re.findall(linepattern, oldfile, flags=re.MULTILINE) + if len(lines) == 0: + with open(filename, 'a') as f: + f.write(newline) + return + last_line = lines[-1] + newfile = oldfile.replace(last_line, last_line + newline + '\n') + with open(filename, 'w') as f: + f.write(newfile) + +def remove_pattern_from_file(filename, pattern): + """ Remove all occurrences of a given pattern from a file. """ + with open(filename, 'r') as f: + oldfile = f.read() + pattern = re.compile(pattern, re.MULTILINE) + with open(filename, 'w') as f: + f.write(pattern.sub('', oldfile)) + +def str_to_fancyc_comment(text): + """ Return a string as a C formatted comment. """ + l_lines = text.splitlines() + if len(l_lines[0]) == 0: + outstr = "/*\n" + else: + outstr = "/* " + l_lines[0] + "\n" + for line in l_lines[1:]: + if len(line) == 0: + outstr += " *\n" + else: + outstr += " * " + line + "\n" + outstr += " */\n" + return outstr + +def str_to_python_comment(text): + """ Return a string as a Python formatted comment. """ + l_lines = text.splitlines() + if len(l_lines[0]) == 0: + outstr = "#\n" + else: + outstr = "# " + l_lines[0] + "\n" + for line in l_lines[1:]: + if len(line) == 0: + outstr += "#\n" + else: + outstr += "# " + line + "\n" + outstr += "#\n" + return outstr + +def strip_default_values(string): + """ Strip default values from a C++ argument list. """ + return re.sub(' *=[^,)]*', '', string) + +def strip_arg_types(string): + """" + Strip the argument types from a list of arguments. + Example: "int arg1, double arg2" -> "arg1, arg2" + Note that some types have qualifiers, which also are part of + the type, e.g. "const std::string &name" -> "name", or + "const char *str" -> "str". + """ + string = strip_default_values(string) + return ", ".join( + [part.strip().split(' ')[-1] for part in string.split(',')] + ).replace('*','').replace('&','') + +def strip_arg_types_grc(string): + """" Strip the argument types from a list of arguments for GRC make tag. + Example: "int arg1, double arg2" -> "$arg1, $arg2" """ + if len(string) == 0: + return "" + else: + string = strip_default_values(string) + return ", ".join(['${' + part.strip().split(' ')[-1] + '}' for part in string.split(',')]) + +def get_modname(): + """ Grep the current module's name from gnuradio.project or CMakeLists.txt """ + modname_trans = {'howto-write-a-block': 'howto'} + try: + with open('gnuradio.project', 'r') as f: + prfile = f.read() + regexp = r'projectname\s*=\s*([a-zA-Z0-9-_]+)$' + return re.search(regexp, prfile, flags=re.MULTILINE).group(1).strip() + except IOError: + pass + # OK, there's no gnuradio.project. So, we need to guess. + with open('CMakeLists.txt', 'r') as f: + cmfile = f.read() + regexp = r'(project\s*\(\s*|GR_REGISTER_COMPONENT\(")gr-(?P<modname>[a-zA-Z0-9-_]+)(\s*(CXX)?|" ENABLE)' + try: + modname = re.search(regexp, cmfile, flags=re.MULTILINE).group('modname').strip() + if modname in list(modname_trans.keys()): + modname = modname_trans[modname] + return modname + except AttributeError: + return None + +def is_number(s): + """ Return True if the string s contains a number. """ + try: + float(s) + return True + except ValueError: + return False + +def ask_yes_no(question, default): + """ Asks a binary question. Returns True for yes, False for no. + default is given as a boolean. """ + question += {True: ' [Y/n] ', False: ' [y/N] '}[default] + if input(question).lower() != {True: 'n', False: 'y'}[default]: + return default + else: + return not default + +class SequenceCompleter(object): + """ A simple completer function wrapper to be used with readline, e.g. + option_iterable = ("search", "seek", "destroy") + readline.set_completer(SequenceCompleter(option_iterable).completefunc) + + Typical usage is with the `with` statement. Restores the previous completer + at exit, thus nestable. + """ + + def __init__(self, sequence=None): + self._seq = sequence or [] + self._tmp_matches = [] + + def completefunc(self, text, state): + if not text and state < len(self._seq): + return self._seq[state] + if not state: + self._tmp_matches = [candidate for candidate in self._seq if candidate.startswith(text)] + if state < len(self._tmp_matches): + return self._tmp_matches[state] + + def __enter__(self): + self._old_completer = readline.get_completer() + readline.set_completer(self.completefunc) + readline.parse_and_bind("tab: complete") + + def __exit__(self, exception_type, exception_value, traceback): + readline.set_completer(self._old_completer) |