1 import os.path
2
3 from c_common import fsutil
4 import c_common.tables as _tables
5 import c_parser.info as _info
6
7
8 BASE_COLUMNS = [
9 'filename',
10 'funcname',
11 'name',
12 'kind',
13 ]
14 END_COLUMNS = {
15 'parsed': 'data',
16 'decls': 'declaration',
17 }
18
19
20 def _get_columns(group, extra=None):
21 return BASE_COLUMNS + list(extra or ()) + [END_COLUMNS[group]]
22 #return [
23 # *BASE_COLUMNS,
24 # *extra or (),
25 # END_COLUMNS[group],
26 #]
27
28
29 #############################
30 # high-level
31
32 def read_parsed(infile):
33 # XXX Support other formats than TSV?
34 columns = _get_columns('parsed')
35 for row in _tables.read_table(infile, columns, sep='\t', fix='-'):
36 yield _info.ParsedItem.from_row(row, columns)
37
38
39 def write_parsed(items, outfile):
40 # XXX Support other formats than TSV?
41 columns = _get_columns('parsed')
42 rows = (item.as_row(columns) for item in items)
43 _tables.write_table(outfile, columns, rows, sep='\t', fix='-')
44
45
46 def read_decls(infile, fmt=None):
47 if fmt is None:
48 fmt = _get_format(infile)
49 read_all, _ = _get_format_handlers('decls', fmt)
50 for decl, _ in read_all(infile):
51 yield decl
52
53
54 def write_decls(decls, outfile, fmt=None, *, backup=False):
55 if fmt is None:
56 fmt = _get_format(infile)
57 _, write_all = _get_format_handlers('decls', fmt)
58 write_all(decls, outfile, backup=backup)
59
60
61 #############################
62 # formats
63
64 def _get_format(file, default='tsv'):
65 if isinstance(file, str):
66 filename = file
67 else:
68 filename = getattr(file, 'name', '')
69 _, ext = os.path.splitext(filename)
70 return ext[1:] if ext else default
71
72
73 def _get_format_handlers(group, fmt):
74 # XXX Use a registry.
75 if group != 'decls':
76 raise NotImplementedError(group)
77 if fmt == 'tsv':
78 return (_iter_decls_tsv, _write_decls_tsv)
79 else:
80 raise NotImplementedError(fmt)
81
82
83 # tsv
84
85 def iter_decls_tsv(infile, extracolumns=None, relroot=fsutil.USE_CWD):
86 if relroot and relroot is not fsutil.USE_CWD:
87 relroot = os.path.abspath(relroot)
88 for info, extra in _iter_decls_tsv(infile, extracolumns):
89 decl = _info.Declaration.from_row(info)
90 decl = decl.fix_filename(relroot, formatted=False, fixroot=False)
91 yield decl, extra
92
93
94 def write_decls_tsv(decls, outfile, extracolumns=None, *,
95 relroot=fsutil.USE_CWD,
96 **kwargs
97 ):
98 if relroot and relroot is not fsutil.USE_CWD:
99 relroot = os.path.abspath(relroot)
100 decls = (d.fix_filename(relroot, fixroot=False) for d in decls)
101 # XXX Move the row rendering here.
102 _write_decls_tsv(decls, outfile, extracolumns, kwargs)
103
104
105 def _iter_decls_tsv(infile, extracolumns=None):
106 columns = _get_columns('decls', extracolumns)
107 for row in _tables.read_table(infile, columns, sep='\t'):
108 if extracolumns:
109 declinfo = row[:4] + row[-1:]
110 extra = row[4:-1]
111 else:
112 declinfo = row
113 extra = None
114 # XXX Use something like tables.fix_row() here.
115 declinfo = [None if v == '-' else v
116 for v in declinfo]
117 yield declinfo, extra
118
119
120 def _write_decls_tsv(decls, outfile, extracolumns, kwargs):
121 columns = _get_columns('decls', extracolumns)
122 if extracolumns:
123 def render_decl(decl):
124 if type(row) is tuple:
125 decl, *extra = decl
126 else:
127 extra = ()
128 extra += ('???',) * (len(extraColumns) - len(extra))
129 *row, declaration = _render_known_row(decl)
130 row += extra + (declaration,)
131 return row
132 else:
133 render_decl = _render_known_decl
134 _tables.write_table(
135 outfile,
136 header='\t'.join(columns),
137 rows=(render_decl(d) for d in decls),
138 sep='\t',
139 **kwargs
140 )
141
142
143 def _render_known_decl(decl, *,
144 # These match BASE_COLUMNS + END_COLUMNS[group].
145 _columns = 'filename parent name kind data'.split(),
146 ):
147 if not isinstance(decl, _info.Declaration):
148 # e.g. Analyzed
149 decl = decl.decl
150 rowdata = decl.render_rowdata(_columns)
151 return [rowdata[c] or '-' for c in _columns]
152 # XXX
153 #return _tables.fix_row(rowdata[c] for c in columns)