3 * Copyright (C) 2006-2009 Jürg Billeter
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.
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.
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
20 * Jürg Billeter <j@bitron.ch>
26 * Represents a Vala source or VAPI package file.
28 public class Vala
.SourceFile
{
30 * The name of this source file.
32 public string filename
{ get; set; }
34 public string? relative_filename
{
36 this
._relative_filename
= value
;
40 private string _package_name
;
42 public string? package_name
{
44 if (file_type
!= SourceFileType
.PACKAGE
) {
48 if (_package_name
== null) {
49 _package_name
= Path
.get_basename (filename
[0:filename
.last_index_of_char ('.')]);
55 _package_name
= value
;
59 private string? _installed_version
= null;
60 private bool _version_requested
= false;
63 * The installed package version or null
65 public string? installed_version
{
67 if (_version_requested
) {
68 return _installed_version
;
71 _version_requested
= true;
73 string pkg_config_name
= package_name
;
74 if (pkg_config_name
== null) {
78 string? standard_output
;
82 Process
.spawn_command_line_sync ("pkg-config --silence-errors --modversion %s".printf (pkg_config_name
), out standard_output
, null, out exit_status
);
83 if (exit_status
!= 0) {
86 } catch (GLib
.SpawnError err
) {
90 standard_output
= standard_output
[0:-1];
91 if (standard_output
!= "") {
92 _installed_version
= standard_output
;
95 return _installed_version
;
98 _version_requested
= value
!= null;
99 _installed_version
= value
;
105 * Specifies whether this file is a VAPI package file.
107 public SourceFileType file_type
{ get; set; }
110 * Specifies whether this file came from the command line directly.
112 public bool from_commandline
{ get; set; }
115 * GIR Namespace for this source file, if it's a VAPI package
118 public string gir_namespace
{ get; set; }
121 * GIR Namespace version for this source file, if it's a VAPI package
124 public string gir_version
{ get; set; }
127 * The context this source file belongs to.
129 public weak CodeContext context
{ get; set; }
131 public string? content
{
132 get { return this
._content
; }
134 this
._content
= value
;
135 this
.source_array
= null;
140 * If the file has been used (ie: if anything in the file has
141 * been emitted into C code as a definition or declaration).
143 public bool used
{ get; set; }
146 * Whether this source-file was explicitly passed on the commandline.
148 public bool explicit
{ get; set; }
150 private ArrayList
<Comment
> comments
= new ArrayList
<Comment
> ();
152 public List
<UsingDirective
> current_using_directives
{ get; set; default = new ArrayList
<UsingDirective
> (); }
154 private List
<CodeNode
> nodes
= new ArrayList
<CodeNode
> ();
156 string? _relative_filename
;
158 private string csource_filename
= null;
159 private string cinclude_filename
= null;
161 private ArrayList
<string> source_array
= null;
163 private MappedFile mapped_file
= null;
165 private string? _content
= null;
168 * Creates a new source file.
170 * @param filename source file name
171 * @return newly created source file
173 public SourceFile (CodeContext context
, SourceFileType type
, string filename
, string? content
= null, bool cmdline
= false) {
174 this
.context
= context
;
175 this
.file_type
= type
;
176 this
.filename
= filename
;
177 this
.content
= content
;
178 this
.from_commandline
= cmdline
;
182 * Adds a header comment to this source file.
184 public void add_comment (Comment comment
) {
185 comments
.add (comment
);
189 * Returns a copy of the list of header comments.
191 * @return list of comments
193 public List
<Comment
> get_comments () {
198 * Adds a new using directive with the specified namespace.
200 * @param ns reference to namespace
202 public void add_using_directive (UsingDirective ns
) {
203 // do not modify current_using_directives, it should be considered immutable
204 // for correct symbol resolving
205 var old_using_directives
= current_using_directives
;
206 current_using_directives
= new ArrayList
<UsingDirective
> ();
207 foreach (var using_directive
in old_using_directives
) {
208 current_using_directives
.add (using_directive
);
210 current_using_directives
.add (ns
);
214 * Adds the specified code node to this source file.
216 * @param node a code node
218 public void add_node (CodeNode node
) {
222 public void remove_node (CodeNode node
) {
227 * Returns a copy of the list of code nodes.
229 * @return code node list
231 public List
<CodeNode
> get_nodes () {
235 public void accept (CodeVisitor visitor
) {
236 visitor
.visit_source_file (this
);
239 public void accept_children (CodeVisitor visitor
) {
240 foreach (CodeNode node
in nodes
) {
241 node
.accept (visitor
);
245 private string get_subdir () {
246 if (context
.basedir
== null) {
250 // filename and basedir are already canonicalized
251 if (filename
.has_prefix (context
.basedir
+ "/")) {
252 var basename
= Path
.get_basename (filename
);
253 var subdir
= filename
.substring (context
.basedir
.length
, filename
.length
- context
.basedir
.length
- basename
.length
);
254 while (subdir
[0] == '/') {
255 subdir
= subdir
.substring (1);
262 private string get_destination_directory () {
263 if (context
.directory
== null) {
264 return get_subdir ();
266 return Path
.build_path ("/", context
.directory
, get_subdir ());
269 private string get_basename () {
270 int dot
= filename
.last_index_of_char ('.');
271 return Path
.get_basename (filename
.substring (0, dot
));
274 public string get_relative_filename () {
275 if (_relative_filename
!= null) {
276 return _relative_filename
;
278 return Path
.get_basename (filename
);
283 * Returns the filename to use when generating C source files.
285 * @return generated C source filename
287 public string get_csource_filename () {
288 if (csource_filename
== null) {
289 if (context
.run_output
) {
290 csource_filename
= context
.output
+ ".c";
291 } else if (context
.ccode_only
|| context
.save_csources
) {
292 csource_filename
= Path
.build_path ("/", get_destination_directory (), get_basename () + ".c");
295 csource_filename
= Path
.build_path ("/", get_destination_directory (), get_basename () + ".vala.c");
298 return csource_filename
;
302 * Returns the filename to use when including the generated C header
305 * @return C header filename to include
307 public string get_cinclude_filename () {
308 if (cinclude_filename
== null) {
309 if (context
.header_filename
!= null) {
310 cinclude_filename
= Path
.get_basename (context
.header_filename
);
311 if (context
.includedir
!= null) {
312 cinclude_filename
= Path
.build_path ("/", context
.includedir
, cinclude_filename
);
315 cinclude_filename
= Path
.build_path ("/", get_subdir (), get_basename () + ".h");
318 return cinclude_filename
;
322 * Returns the requested line from this file, loading it if needed.
324 * @param lineno 1-based line number
325 * @return the specified source line
327 public string?
get_source_line (int lineno
) {
328 if (source_array
== null) {
329 if (content
!= null) {
330 read_source_lines (content
);
335 if (lineno
< 1 || lineno
> source_array
.size
) {
338 return source_array
.get (lineno
- 1);
342 * Parses the input file into ::source_array.
344 private void read_source_file () {
347 FileUtils
.get_contents (filename
, out cont
);
348 } catch (FileError fe
) {
351 read_source_lines (cont
);
354 private void read_source_lines (string cont
)
356 source_array
= new ArrayList
<string> ();
357 string[] lines
= cont
.split ("\n", 0);
359 for (idx
= 0; lines
[idx
] != null; ++idx
) {
360 source_array
.add (lines
[idx
]);
364 public char* get_mapped_contents () {
365 if (content
!= null) {
366 return (char*) content
;
369 if (mapped_file
== null) {
371 mapped_file
= new
MappedFile (filename
, false);
372 } catch (FileError e
) {
373 Report
.error (null, "Unable to map file `%s': %s".printf (filename
, e
.message
));
378 return mapped_file
.get_contents ();
381 public size_t
get_mapped_length () {
382 if (content
!= null) {
383 return content
.length
;
386 return mapped_file
.get_length ();
389 public bool check (CodeContext context
) {
390 foreach (CodeNode node
in nodes
) {
391 node
.check (context
);
397 public enum Vala
.SourceFileType
{