Add support for writing gzip-compressed files
authorDavid Shah <dave@ds0.me>
Mon, 29 Jul 2019 08:28:31 +0000 (09:28 +0100)
committerDavid Shah <dave@ds0.me>
Tue, 6 Aug 2019 16:43:04 +0000 (17:43 +0100)
Signed-off-by: David Shah <dave@ds0.me>
CHANGELOG
kernel/register.cc

index 9e9bda6e9759b8f73be86cf659456164553d2112..661581433666b509693ee600bdd675ff1af75809 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -16,6 +16,7 @@ Yosys 0.9 .. Yosys 0.9-dev
     - "synth_xilinx" to now infer wide multiplexers (-widemux <min> to enable)
     - Added automatic gzip decompression for frontends
     - Added $_NMUX_ cell type
+    - Added automatic gzip compression (based on filename extension) for backends
 
 Yosys 0.8 .. Yosys 0.8-dev
 --------------------------
index 4c6e3591f7d960d9e0c4a72676ae5a8fb2fd0b3b..4f60338e9c14d4df0e801d1882d7eb67f60a8de1 100644 (file)
@@ -41,6 +41,45 @@ void decompress_gzip(const std::string &filename, std::stringstream &out)
        }
        gzclose(gzf);
 }
+
+/*
+An output stream that uses a stringbuf to buffer data internally,
+using zlib to write gzip-compressed data every time the stream is flushed.
+*/
+class gzip_ostream : public std::ostream  {
+public:
+       gzip_ostream()
+       {
+               rdbuf(&outbuf);
+       }
+       bool open(const std::string &filename)
+       {
+               return outbuf.open(filename);
+       }
+private:
+       class gzip_streambuf : public std::stringbuf {
+       public:
+               gzip_streambuf() { };
+               bool open(const std::string &filename)
+               {
+                       gzf = gzopen(filename.c_str(), "wb");
+                       return gzf != nullptr;
+               }
+               virtual int sync() override
+               {
+                       gzwrite(gzf, reinterpret_cast<const void *>(str().c_str()), unsigned(str().size()));
+                       str("");
+                       return 0;
+               }
+               ~gzip_streambuf()
+               {
+                       sync();
+                       gzclose(gzf);
+               }
+       private:
+               gzFile gzf = nullptr;
+       } outbuf;
+};
 PRIVATE_NAMESPACE_END
 
 #endif
@@ -588,14 +627,28 @@ void Backend::extra_args(std::ostream *&f, std::string &filename, std::vector<st
 
                filename = arg;
                rewrite_filename(filename);
-               std::ofstream *ff = new std::ofstream;
-               ff->open(filename.c_str(), std::ofstream::trunc);
-               yosys_output_files.insert(filename);
-               if (ff->fail()) {
-                       delete ff;
-                       log_cmd_error("Can't open output file `%s' for writing: %s\n", filename.c_str(), strerror(errno));
+               if (filename.size() > 3 && filename.substr(filename.size()-3) == ".gz") {
+#ifdef YOSYS_ENABLE_ZLIB
+                       gzip_ostream *gf = new gzip_ostream;
+                       if (!gf->open(filename)) {
+                               delete gf;
+                               log_cmd_error("Can't open output file `%s' for writing: %s\n", filename.c_str(), strerror(errno));
+                       }
+                       yosys_output_files.insert(filename);
+                       f = gf;
+#else
+                       log_cmd_error("Yosys is compiled without zlib support, unable to write gzip output.\n");
+#endif
+               } else {
+                       std::ofstream *ff = new std::ofstream;
+                       ff->open(filename.c_str(), std::ofstream::trunc);
+                       yosys_output_files.insert(filename);
+                       if (ff->fail()) {
+                               delete ff;
+                               log_cmd_error("Can't open output file `%s' for writing: %s\n", filename.c_str(), strerror(errno));
+                       }
+                       f = ff;
                }
-               f = ff;
        }
 
        if (called_with_fp)