Add new popup menu to the dictionary view widget
[pspp] / src / libpspp / zip-writer.c
index fd36fc523a029b61e0dee5122ef330bbb8c4a4ed..b8240efe6bb8ba194308cb1aff64dc0229ce70e1 100644 (file)
 #include <errno.h>
 #include <stdlib.h>
 #include <time.h>
+#include <unistd.h>
 
 #include "gl/crc.h"
 #include "gl/fwriteerror.h"
 #include "gl/xalloc.h"
 
 #include "libpspp/message.h"
+#include "libpspp/temp-file.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -37,6 +39,7 @@ struct zip_writer
   {
     char *file_name;            /* File name, for use in error mesages. */
     FILE *file;                 /* Output stream. */
+    uint32_t offset;            /* Offset in output stream. */
 
     uint16_t date, time;        /* Date and time in MS-DOS format. */
 
@@ -60,6 +63,7 @@ static void
 put_bytes (struct zip_writer *zw, const void *p, size_t n)
 {
   fwrite (p, 1, n, zw->file);
+  zw->offset += n;
 }
 
 static void
@@ -90,16 +94,30 @@ zip_writer_create (const char *file_name)
   time_t now;
   FILE *file;
 
-  file = fopen (file_name, "wb");
-  if (file == NULL)
+  if (strcmp (file_name, "-"))
     {
-      msg_error (errno, _("%s: error opening output file"), file_name);
-      return NULL;
+      file = fopen (file_name, "wb");
+      if (file == NULL)
+        {
+          msg_error (errno, _("%s: error opening output file"), file_name);
+          return NULL;
+        }
+    }
+  else
+    {
+      if (isatty (STDOUT_FILENO))
+        {
+          msg (ME, _("%s: not writing ZIP file to terminal"), file_name);
+          return NULL;
+        }
+
+      file = stdout;
     }
 
   zw = xmalloc (sizeof *zw);
   zw->file_name = xstrdup (file_name);
   zw->file = file;
+  zw->offset = 0;
 
   zw->ok = true;
 
@@ -138,13 +156,13 @@ void
 zip_writer_add (struct zip_writer *zw, FILE *file, const char *member_name)
 {
   struct zip_member *member;
-  uint32_t offset, size;
+  uint32_t size;
   size_t bytes_read;
   uint32_t crc;
   char buf[4096];
 
   /* Local file header. */
-  offset = ftello (zw->file);
+  uint32_t offset = zw->offset;
   put_local_header (zw, member_name, 0, 0, 1 << 3);
 
   /* File data. */
@@ -161,6 +179,7 @@ zip_writer_add (struct zip_writer *zw, FILE *file, const char *member_name)
      with the correct file size and CRC.  Otherwise, write data descriptor. */
   if (fseeko (zw->file, offset, SEEK_SET) == 0)
     {
+      uint32_t save_offset = zw->offset;
       put_local_header (zw, member_name, crc, size, 0);
       if (fseeko (zw->file, size, SEEK_CUR)
           && zw->ok)
@@ -168,6 +187,7 @@ zip_writer_add (struct zip_writer *zw, FILE *file, const char *member_name)
           msg_error (errno, _("%s: error seeking in output file"), zw->file_name);
           zw->ok = false;
         }
+      zw->offset = save_offset;
     }
   else
     {
@@ -188,6 +208,33 @@ zip_writer_add (struct zip_writer *zw, FILE *file, const char *member_name)
   member->name = xstrdup (member_name);
 }
 
+/* Adds a member named MEMBER_NAME whose contents is the null-terminated string
+   CONTENT. */
+void
+zip_writer_add_string (struct zip_writer *zw, const char *member_name,
+                       const char *content)
+{
+  zip_writer_add_memory (zw, member_name, content, strlen (content));
+}
+
+/* Adds a member named MEMBER_NAME whose contents is the SIZE bytes of
+   CONTENT. */
+void
+zip_writer_add_memory (struct zip_writer *zw, const char *member_name,
+                       const void *content, size_t size)
+{
+  FILE *fp = create_temp_file ();
+  if (fp == NULL)
+    {
+      msg_error (errno, _("error creating temporary file"));
+      zw->ok = false;
+      return;
+    }
+  fwrite (content, size, 1, fp);
+  zip_writer_add (zw, fp, member_name);
+  close_temp_file (fp);
+}
+
 /* Finalizes the contents of ZW and closes it.  Returns true if successful,
    false if a write error occurred while finalizing the file or at any earlier
    time. */
@@ -201,7 +248,7 @@ zip_writer_close (struct zip_writer *zw)
   if (zw == NULL)
     return true;
 
-  dir_start = ftello (zw->file);
+  dir_start = zw->offset;
   for (i = 0; i < zw->n_members; i++)
     {
       struct zip_member *m = &zw->members[i];
@@ -228,7 +275,7 @@ zip_writer_close (struct zip_writer *zw)
       free (m->name);
     }
   free (zw->members);
-  dir_end = ftello (zw->file);
+  dir_end = zw->offset;
 
   /* End of central directory record. */
   put_u32 (zw, MAGIC_EOCD);     /* end of central dir signature */
@@ -246,7 +293,7 @@ zip_writer_close (struct zip_writer *zw)
   put_u16 (zw, 0);              /* .ZIP file comment length */
 
   ok = zw->ok;
-  if (ok && fwriteerror (zw->file))
+  if (ok && zw->file != stdout && fwriteerror (zw->file))
     {
       msg_error (errno, _("%s: write failed"), zw->file_name);
       ok = false;