Line data Source code
1 : /* valasourcefile.vala
2 : *
3 : * Copyright (C) 2006-2009 Jürg Billeter
4 : *
5 : * This library is free software; you can redistribute it and/or
6 : * modify it under the terms of the GNU Lesser General Public
7 : * License as published by the Free Software Foundation; either
8 : * version 2.1 of the License, or (at your option) any later version.
9 :
10 : * This library is distributed in the hope that it will be useful,
11 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 : * Lesser General Public License for more details.
14 :
15 : * You should have received a copy of the GNU Lesser General Public
16 : * License along with this library; if not, write to the Free Software
17 : * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 : *
19 : * Author:
20 : * Jürg Billeter <j@bitron.ch>
21 : */
22 :
23 : using GLib;
24 :
25 : /**
26 : * Represents a Vala source or VAPI package file.
27 : */
28 67894640 : public class Vala.SourceFile {
29 : /**
30 : * The name of this source file.
31 : */
32 62498 : public string filename { get; private set; }
33 :
34 : public string? relative_filename {
35 1696 : set {
36 1696 : if (Path.DIR_SEPARATOR != '/') {
37 : // don't use backslashes internally,
38 : // to avoid problems in #line / #include directives
39 : string[] components = value.split ("\\");
40 : _relative_filename = string.joinv ("/", components);
41 : } else {
42 3392 : _relative_filename = value;
43 : }
44 : }
45 : }
46 :
47 6886 : private string _package_name;
48 :
49 : public string? package_name {
50 5836 : get {
51 5836 : if (file_type != SourceFileType.PACKAGE) {
52 46 : return null;
53 : }
54 :
55 5790 : if (_package_name == null) {
56 2894 : _package_name = Path.get_basename (filename[0:filename.last_index_of_char ('.')]);
57 : }
58 :
59 5790 : return _package_name;
60 : }
61 170 : set {
62 340 : _package_name = value;
63 : }
64 : }
65 :
66 6886 : private string? _installed_version = null;
67 6886 : private bool _version_requested = false;
68 :
69 : /**
70 : * The installed package version or null
71 : */
72 : public string? installed_version {
73 13510 : get {
74 13510 : if (_version_requested) {
75 10616 : return _installed_version;
76 : }
77 :
78 2894 : _version_requested = true;
79 :
80 2894 : if (package_name != null) {
81 2894 : _installed_version = context.pkg_config_modversion (package_name);
82 : }
83 :
84 2894 : return _installed_version;
85 : }
86 0 : set {
87 0 : _version_requested = value != null;
88 0 : _installed_version = value;
89 : }
90 : }
91 :
92 :
93 : /**
94 : * Specifies whether this file is a VAPI package file.
95 : */
96 62235863 : public SourceFileType file_type { get; set; }
97 :
98 : /**
99 : * Specifies whether this file came from the command line directly.
100 : */
101 27295 : public bool from_commandline { get; set; }
102 :
103 : /**
104 : * GIR Namespace for this source file, if it's a VAPI package
105 : */
106 :
107 28699 : public string gir_namespace { get; set; }
108 :
109 : /**
110 : * GIR Namespace version for this source file, if it's a VAPI package
111 : */
112 :
113 23556 : public string gir_version { get; set; }
114 :
115 536 : public bool gir_ambiguous { get; set; }
116 :
117 : /**
118 : * The context this source file belongs to.
119 : */
120 39037 : public weak CodeContext context { get; set; }
121 :
122 : public string? content {
123 14025 : get { return this._content; }
124 6886 : set {
125 13772 : this._content = value;
126 6886 : this.source_array = null;
127 : }
128 : }
129 :
130 : /**
131 : * If the file has been used (ie: if anything in the file has
132 : * been emitted into C code as a definition or declaration).
133 : */
134 40813 : public bool used { get; set; }
135 :
136 13772 : private ArrayList<Comment> comments = new ArrayList<Comment> ();
137 :
138 102420763 : public List<UsingDirective> current_using_directives { get; set; default = new ArrayList<UsingDirective> (); }
139 :
140 13772 : private List<CodeNode> nodes = new ArrayList<CodeNode> ();
141 :
142 6886 : string? _relative_filename;
143 :
144 6886 : private string csource_filename = null;
145 6886 : private string cinclude_filename = null;
146 :
147 6886 : private ArrayList<string> source_array = null;
148 :
149 6886 : private MappedFile mapped_file = null;
150 :
151 6886 : private string? _content = null;
152 :
153 : /**
154 : * Creates a new source file.
155 : *
156 : * @param filename source file name
157 : * @return newly created source file
158 : */
159 20658 : public SourceFile (CodeContext context, SourceFileType type, string filename, string? content = null, bool cmdline = false) {
160 6886 : this.context = context;
161 6886 : this.file_type = type;
162 6886 : this.filename = filename;
163 6886 : this.content = content;
164 6886 : this.from_commandline = cmdline;
165 : }
166 :
167 : /**
168 : * Adds a header comment to this source file.
169 : */
170 5232 : public void add_comment (Comment comment) {
171 5232 : comments.add (comment);
172 : }
173 :
174 : /**
175 : * Returns the list of header comments.
176 : *
177 : * @return list of comments
178 : */
179 1077 : public unowned List<Comment> get_comments () {
180 1077 : return comments;
181 : }
182 :
183 : /**
184 : * Adds a new using directive with the specified namespace.
185 : *
186 : * @param ns reference to namespace
187 : */
188 3790 : public void add_using_directive (UsingDirective ns) {
189 : // do not modify current_using_directives, it should be considered immutable
190 : // for correct symbol resolving
191 1895 : var old_using_directives = current_using_directives;
192 1895 : current_using_directives = new ArrayList<UsingDirective> ();
193 2361 : foreach (var using_directive in old_using_directives) {
194 233 : current_using_directives.add (using_directive);
195 : }
196 1895 : current_using_directives.add (ns);
197 : }
198 :
199 : /**
200 : * Adds the specified code node to this source file.
201 : *
202 : * @param node a code node
203 : */
204 2476058 : public void add_node (CodeNode node) {
205 2476058 : nodes.add (node);
206 : }
207 :
208 0 : public void remove_node (CodeNode node) {
209 0 : nodes.remove (node);
210 : }
211 :
212 : /**
213 : * Returns the list of code nodes.
214 : *
215 : * @return code node list
216 : */
217 11678 : public unowned List<CodeNode> get_nodes () {
218 11678 : return nodes;
219 : }
220 :
221 33504 : public void accept (CodeVisitor visitor) {
222 33504 : visitor.visit_source_file (this);
223 : }
224 :
225 5689 : public void accept_children (CodeVisitor visitor) {
226 3217023 : foreach (CodeNode node in nodes) {
227 1605667 : node.accept (visitor);
228 : }
229 : }
230 :
231 1079 : private string get_subdir () {
232 1079 : if (context.basedir == null) {
233 1 : return "";
234 : }
235 :
236 : // filename and basedir are already canonicalized
237 1078 : if (filename.has_prefix (context.basedir + "/")) {
238 1074 : var basename = Path.get_basename (filename);
239 1074 : var subdir = filename.substring (context.basedir.length, filename.length - context.basedir.length - basename.length);
240 2148 : while (subdir[0] == '/') {
241 1074 : subdir = subdir.substring (1);
242 : }
243 1074 : return subdir;
244 : }
245 4 : return "";
246 : }
247 :
248 1077 : private string get_destination_directory () {
249 1077 : if (context.directory == null) {
250 0 : return get_subdir ();
251 : }
252 1077 : return Path.build_path ("/", context.directory, get_subdir ());
253 : }
254 :
255 1079 : private string get_basename () {
256 1079 : int dot = filename.last_index_of_char ('.');
257 1079 : return Path.get_basename (filename.substring (0, dot));
258 : }
259 :
260 104585 : public string get_relative_filename () {
261 104585 : if (_relative_filename != null) {
262 201814 : return _relative_filename;
263 : } else {
264 3678 : return Path.get_basename (filename);
265 : }
266 : }
267 :
268 : /**
269 : * Returns the filename to use when generating C source files.
270 : *
271 : * @return generated C source filename
272 : */
273 1909 : public string get_csource_filename () {
274 1909 : if (csource_filename == null) {
275 1077 : if (context.run_output) {
276 0 : csource_filename = context.output + ".c";
277 1077 : } else if (context.ccode_only || context.save_csources) {
278 1077 : csource_filename = Path.build_path ("/", get_destination_directory (), get_basename () + ".c");
279 : } else {
280 : // temporary file
281 0 : csource_filename = Path.build_path ("/", get_destination_directory (), get_basename () + ".vala.c");
282 : }
283 : }
284 1909 : return csource_filename;
285 : }
286 :
287 : /**
288 : * Returns the filename to use when including the generated C header
289 : * file.
290 : *
291 : * @return C header filename to include
292 : */
293 1727 : public string get_cinclude_filename () {
294 1727 : if (cinclude_filename == null) {
295 213 : if (context.header_filename != null) {
296 211 : cinclude_filename = Path.get_basename (context.header_filename);
297 211 : if (context.includedir != null) {
298 0 : cinclude_filename = Path.build_path ("/", context.includedir, cinclude_filename);
299 : }
300 : } else {
301 2 : cinclude_filename = Path.build_path ("/", get_subdir (), get_basename () + ".h");
302 : }
303 : }
304 1727 : return cinclude_filename;
305 : }
306 :
307 : /**
308 : * Returns the requested line from this file, loading it if needed.
309 : *
310 : * @param lineno 1-based line number
311 : * @return the specified source line
312 : */
313 767 : public string? get_source_line (int lineno) {
314 767 : if (source_array == null) {
315 643 : if (content != null) {
316 0 : read_source_lines (content);
317 : } else {
318 643 : read_source_file ();
319 : }
320 : }
321 767 : if (lineno < 1 || lineno > source_array.size) {
322 1 : return null;
323 : }
324 766 : return source_array.get (lineno - 1);
325 : }
326 :
327 : /**
328 : * Parses the input file into ::source_array.
329 : */
330 1286 : private void read_source_file () {
331 : string cont;
332 0 : try {
333 643 : FileUtils.get_contents (filename, out cont);
334 : } catch (FileError fe) {
335 0 : return;
336 : }
337 643 : read_source_lines (cont);
338 : }
339 :
340 1286 : private void read_source_lines (string cont)
341 : {
342 643 : source_array = new ArrayList<string> ();
343 1286 : string[] lines = cont.split ("\n", 0);
344 : int idx;
345 127520 : for (idx = 0; lines[idx] != null; ++idx) {
346 126877 : source_array.add (lines[idx]);
347 : }
348 : }
349 :
350 6691 : public char* get_mapped_contents () {
351 6691 : if (content != null) {
352 0 : return (char*) content;
353 : }
354 :
355 6691 : if (mapped_file == null) {
356 0 : try {
357 6691 : mapped_file = new MappedFile (filename, false);
358 : } catch (FileError e) {
359 0 : Report.error (null, "Unable to map file `%s': %s", filename, e.message);
360 0 : return null;
361 : }
362 : }
363 :
364 6691 : return mapped_file.get_contents ();
365 : }
366 :
367 6691 : public size_t get_mapped_length () {
368 6691 : if (content != null) {
369 0 : return content.length;
370 : }
371 :
372 6691 : if (mapped_file == null) {
373 0 : return 0;
374 : }
375 :
376 6691 : return mapped_file.get_length ();
377 : }
378 :
379 6429 : public bool check (CodeContext context) {
380 4613677 : foreach (CodeNode node in nodes) {
381 2303624 : node.check (context);
382 : }
383 : return true;
384 : }
385 : }
386 :
387 : public enum Vala.SourceFileType {
388 : NONE,
389 : SOURCE,
390 : PACKAGE,
391 : FAST
392 : }
|