1#!/usr/bin/env python3 2 3# This program is free software; you can redistribute it and/or modify 4# it under the terms of the GNU General Public License as published by 5# the Free Software Foundation; either version 3 of the License, or 6# (at your option) any later version. 7# 8# This program is distributed in the hope that it will be useful, 9# but WITHOUT ANY WARRANTY; without even the implied warranty of 10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11# GNU General Public License for more details. 12# 13# You should have received a copy of the GNU General Public License 14# along with this program; if not, see <https://www.gnu.org/licenses/>. 15# 16# 17# Utility script to re-implement gobj2dot.rb in python with extra 18# option to send the output to a new file. 19# 20# Copyright (C) 2009 Henrik Akesson 21# Copyright (C) 2021 John Marshall 22 23from __future__ import print_function 24 25import os 26import sys 27import argparse 28import glob 29import re 30 31header = '''digraph G { 32 rankdir = RL 33 34 fontname = "Bitstream Vera Sans" 35 fontsize = 8 36 37 node [ shape = "record" ] 38 39 edge [ arrowhead = empty ]''' 40 41footer = '}' 42 43re_def_type = re.compile( 44 r'G_DEFINE_TYPE\s*\(\s*\w+,\s*(\w+),\s*(\w+)\s*\)', 45 re.DOTALL 46) 47re_def_type_code = re.compile( 48 r'G_DEFINE_TYPE_WITH_CODE\s*\(\s*(\w+).*G_IMPLEMENT_INTERFACE\s*\s*\(\s*(\w+)', 49 re.DOTALL 50) 51re_interface = re.compile( 52 r'G_TYPE_INTERFACE\s*,\s*\"([^\"]+)\"', 53 re.DOTALL 54) 55 56 57class Args(): 58 def __init__(self): 59 parser = argparse.ArgumentParser() 60 parser.add_argument( 61 '--output', 62 metavar='OUTPUT_FILE', 63 help='output file - otherwise output to STDOUT' 64 ) 65 parser.add_argument( 66 'PATH', 67 help='search path' 68 ) 69 70 self.path = os.path.realpath(parser.parse_args().PATH) 71 if parser.parse_args().output: 72 self.output = os.path.realpath(parser.parse_args().output) 73 else: 74 self.output = None 75 76def snake_to_camel(name): 77 return re.sub(r'(?:^|_)([a-z])', lambda x: x.group(1).upper(), name) 78 79def gegl_type_to_camel(name): 80 return snake_to_camel('_'.join(name.split('_TYPE_')).lower()) 81 82 83def main(): 84 args = Args() 85 86 if args.output: 87 try: 88 out_file = open(os.path.realpath(args.output), 'w') 89 except IOError: 90 print('cannot open output file %s' % args.output, 91 sys.stderr) 92 sys.exit(1) 93 else: 94 out_file = sys.stdout 95 96 print(header, file = out_file) 97 98 for filename in glob.iglob(os.path.join(args.path, '**', '*.[ch]'), 99 recursive = True): 100 f = open(filename, mode='r', encoding='utf-8') 101 content = f.read() 102 f.close() 103 match = re.search(re_def_type, content) 104 if match: 105 if match.groups()[1] != 'G_TYPE_OBJECT': 106 print( 107 '\t' + snake_to_camel(match.groups()[0]) + 108 ' -> ' + gegl_type_to_camel(match.groups()[1]), 109 file = out_file 110 ) 111 else: 112 match = re.search(re_def_type_code, content) 113 if match: 114 print( 115 '\t' + match.groups()[0] + 116 ' -> ' + gegl_type_to_camel(match.groups()[1]) + 117 ' [ style = dashed ]', 118 file = out_file 119 ) 120 else: 121 match = re.search(re_interface, content) 122 if match: 123 print( 124 '\t' + match.groups()[0] + 125 ' [ label = \"{\\<\\<interface\\>\\>\\l' + 126 match.groups()[0] + '}\" ]', 127 file = out_file 128 ) 129 130 131 print(footer, file = out_file) 132 133 sys.exit(0) 134 135 136if __name__ == "__main__": 137 main()