LCOV - code coverage report
Current view: top level - ccode - valaccodewriter.vala (source / functions) Coverage Total Hit
Test: vala 0.57.0.253-297e8 Lines: 91.0 % 111 101
Test Date: 2024-02-21 16:21:37 Functions: - 0 0

            Line data    Source code
       1              : /* valaccodewriter.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 writer to write C source files.
      27              :  */
      28         2816 : public class Vala.CCodeWriter {
      29              :         /**
      30              :          * Specifies the file to be written.
      31              :          */
      32         2965 :         public string filename { get; set; }
      33              : 
      34              :         /**
      35              :          * Specifies the source file used to generate this one.
      36              :          */
      37          987 :         private string source_filename;
      38              : 
      39              :         /**
      40              :          * Specifies whether to emit line directives.
      41              :          */
      42          983 :         public bool line_directives { get; set; }
      43              : 
      44              :         /**
      45              :          * Specifies whether the output stream is at the beginning of a line.
      46              :          */
      47              :         public bool bol {
      48        84555 :                 get { return _bol; }
      49              :         }
      50              : 
      51              :         static GLib.Regex fix_indent_regex;
      52              : 
      53          987 :         private string temp_filename;
      54              :         private bool file_exists;
      55              : 
      56          987 :         private FileStream? stream;
      57              : 
      58              :         private int indent;
      59          987 :         private int current_line_number = 1;
      60              :         private bool using_line_directive;
      61              : 
      62              :         /* at begin of line */
      63          987 :         private bool _bol = true;
      64              :         /* at begin after empty line */
      65          987 :         private bool _bael = false;
      66              : 
      67         1974 :         public CCodeWriter (string filename, string? source_filename = null) {
      68          987 :                 this.filename = filename;
      69         1974 :                 this.source_filename = source_filename;
      70              :         }
      71              : 
      72              :         /**
      73              :          * Opens the file.
      74              :          *
      75              :          * @return true if the file has been opened successfully,
      76              :          *         false otherwise
      77              :          */
      78          987 :         public bool open (bool write_version) {
      79          987 :                 file_exists = FileUtils.test (filename, FileTest.EXISTS);
      80          987 :                 if (file_exists) {
      81          151 :                         temp_filename = "%s.valatmp".printf (filename);
      82          151 :                         stream = FileStream.open (temp_filename, "w");
      83              :                 } else {
      84              :                         /*
      85              :                          * File doesn't exist. In case of a particular destination (-d flag),
      86              :                          * check and create the directory structure.
      87              :                          */
      88          836 :                         var dirname = Path.get_dirname (filename);
      89          836 :                         DirUtils.create_with_parents (dirname, 0755);
      90          836 :                         stream = FileStream.open (filename, "w");
      91              :                 }
      92              : 
      93          987 :                 if (stream == null) {
      94            0 :                         return false;
      95              :                 }
      96              : 
      97         1974 :                 var opening = write_version ?
      98            1 :                         "/* %s generated by valac %s, the Vala compiler".printf (Path.get_basename (filename), Vala.BUILD_VERSION) :
      99          986 :                         "/* %s generated by valac, the Vala compiler".printf (Path.get_basename (filename));
     100          987 :                 write_string (opening);
     101              : 
     102              :                 // Write the file name if known
     103          987 :                 if (source_filename != null) {
     104          983 :                         write_newline ();
     105          983 :                         write_string (" * generated from %s".printf (Path.get_basename (source_filename)));
     106              :                 }
     107              : 
     108          987 :                 write_string (", do not modify */");
     109          987 :                 write_newline ();
     110          987 :                 write_newline ();
     111              : 
     112          987 :                 return true;
     113              :         }
     114              : 
     115              :         /**
     116              :          * Closes the file.
     117              :          */
     118          987 :         public void close () {
     119          987 :                 stream = null;
     120              : 
     121          987 :                 if (file_exists) {
     122          151 :                         var changed = true;
     123              : 
     124          151 :                         try {
     125          151 :                                 var old_file = new MappedFile (filename, false);
     126          151 :                                 var new_file = new MappedFile (temp_filename, false);
     127          151 :                                 var len = old_file.get_length ();
     128          151 :                                 if (len == new_file.get_length ()) {
     129            0 :                                         if (Memory.cmp (old_file.get_contents (), new_file.get_contents (), len) == 0) {
     130          151 :                                                 changed = false;
     131              :                                         }
     132              :                                 }
     133          151 :                                 old_file = null;
     134          151 :                                 new_file = null;
     135              :                         } catch (FileError e) {
     136              :                                 // assume changed if mmap comparison doesn't work
     137              :                         }
     138              : 
     139          151 :                         if (changed) {
     140          151 :                                 FileUtils.rename (temp_filename, filename);
     141              :                         } else {
     142            0 :                                 FileUtils.unlink (temp_filename);
     143            0 :                                 if (source_filename != null) {
     144            0 :                                         var stats = Stat (source_filename);
     145            0 :                                         var target_stats = Stat (filename);
     146            0 :                                         if (stats.st_mtime >= target_stats.st_mtime) {
     147            0 :                                                 UTimBuf timebuf = { stats.st_atime + 1, stats.st_mtime + 1 };
     148            0 :                                                 FileUtils.utime (filename, timebuf);
     149              :                                         }
     150              :                                 }
     151              :                         }
     152              :                 }
     153              :         }
     154              : 
     155              :         /**
     156              :          * Writes tabs according to the current indent level.
     157              :          */
     158       357751 :         public void write_indent (CCodeLineDirective? line = null) {
     159       357751 :                 if (line_directives) {
     160       162971 :                         if (line != null) {
     161        79847 :                                 line.write (this);
     162        79847 :                                 using_line_directive = true;
     163        83124 :                         } else if (using_line_directive) {
     164              :                                 // no corresponding Vala line, emit line directive for C line
     165        16083 :                                 write_string ("#line %d \"%s\"".printf (current_line_number + 1, Path.get_basename (filename)));
     166        16083 :                                 write_newline ();
     167        16083 :                                 using_line_directive = false;
     168              :                         }
     169              :                 }
     170              : 
     171       357751 :                 if (!_bol) {
     172         4235 :                         write_newline ();
     173              :                 }
     174              : 
     175       357751 :                 stream.puts (string.nfill (indent, '\t'));
     176       357751 :                 _bol = false;
     177              :         }
     178              : 
     179              :         /**
     180              :          * Writes n spaces.
     181              :          */
     182        27206 :         public void write_nspaces (uint n) {
     183        27206 :                 stream.puts (string.nfill (n, ' '));
     184              :         }
     185              : 
     186              :         /**
     187              :          * Writes the specified string.
     188              :          *
     189              :          * @param s a string
     190              :          */
     191      2141733 :         public void write_string (string s) {
     192      2141733 :                 stream.puts (s);
     193      2141733 :                 _bol = false;
     194              :         }
     195              : 
     196              :         /**
     197              :          * Writes a newline.
     198              :          */
     199       568004 :         public void write_newline () {
     200       568004 :                 if (!_bol) {
     201       514756 :                         _bael = false;
     202        53248 :                 } else if (!_bael) {
     203        28617 :                         _bael = true;
     204              :                 } else {
     205              :                         return;
     206              :                 }
     207       543373 :                 stream.putc ('\n');
     208       543373 :                 current_line_number++;
     209       543373 :                 _bol = true;
     210              :         }
     211              : 
     212              :         /**
     213              :          * Opens a new block, increasing the indent level.
     214              :          */
     215        42834 :         public void write_begin_block () {
     216        42834 :                 if (!_bol) {
     217        21750 :                         stream.putc (' ');
     218              :                 } else {
     219        21084 :                         write_indent ();
     220              :                 }
     221        42834 :                 stream.putc ('{');
     222        42834 :                 write_newline ();
     223        42834 :                 indent++;
     224              :         }
     225              : 
     226              :         /**
     227              :          * Closes the current block, decreasing the indent level.
     228              :          */
     229        42834 :         public void write_end_block () {
     230        42834 :                 assert (indent > 0);
     231              : 
     232        42834 :                 indent--;
     233        42834 :                 write_indent ();
     234        42834 :                 stream.putc ('}');
     235              :         }
     236              : 
     237              :         /**
     238              :          * Writes the specified text as comment.
     239              :          *
     240              :          * @param text the comment text
     241              :          */
     242          654 :         public void write_comment (string text) {
     243          654 :                 try {
     244          654 :                         write_indent ();
     245          654 :                         stream.puts ("/*");
     246          654 :                         bool first = true;
     247              : 
     248              :                         // discard tabs at beginning of line
     249          654 :                         if (fix_indent_regex == null)
     250           12 :                                 fix_indent_regex = new GLib.Regex ("^\t+");;
     251              : 
     252        11032 :                         foreach (unowned string line in text.split ("\n")) {
     253         4862 :                                 if (!first) {
     254         4208 :                                         write_indent ();
     255              :                                 } else {
     256              :                                         first = false;
     257              :                                 }
     258              : 
     259         9724 :                                 var lineparts = fix_indent_regex.replace_literal (line, -1, 0, "").split ("*/");
     260              : 
     261         9716 :                                 for (int i = 0; lineparts[i] != null; i++) {
     262         4854 :                                         stream.puts (lineparts[i]);
     263         4854 :                                         if (lineparts[i+1] != null) {
     264            0 :                                                 stream.puts ("* /");
     265              :                                         }
     266              :                                 }
     267              :                         }
     268          654 :                         stream.puts ("*/");
     269          654 :                         write_newline ();
     270              :                 } catch (RegexError e) {
     271              :                         // ignore
     272              :                 }
     273              :         }
     274              : }
        

Generated by: LCOV version 2.0-1