gunzip'ing many files to stdout works now
[oweals/busybox.git] / archival / gunzip.c
index 246ce2f4e7b6a39d0dd99db8915ac83aaeb79e19..83ed5e84af5fe8dd07eb61627ab26c175ae42547 100644 (file)
@@ -7,9 +7,9 @@
  * Originally adjusted for busybox by Sven Rudolph <sr1@inf.tu-dresden.de>
  * based on gzip sources
  *
- * Adjusted further by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- * to support files as well as stdin/stdout, and to generally behave itself wrt
- * command line handling.
+ * Adjusted further by Erik Andersen <andersee@debian.org> to support files as
+ * well as stdin/stdout, and to generally behave itself wrt command line
+ * handling.
  *
  * General cleanup to better adhere to the style guide and make use of standard
  * busybox functions by Glenn McGrath <bug1@optushome.com.au>
@@ -60,138 +60,147 @@ static char *license_msg[] = {
 };
 #endif
 
-//#include <sys/types.h>
-//#include <sys/wait.h>
-//#include <signal.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 #include <getopt.h>
 #include "busybox.h"
-#define BB_DECLARE_EXTERN
-#define bb_need_memory_exhausted
-#define bb_need_name_too_long
-#include "messages.c"
 
-extern int gunzip_main(int argc, char **argv)
-{
-       FILE *in_file, *out_file;
-       struct stat stat_buf;
-
-       char *if_name = NULL;
-       char *of_name = NULL;
-       char *delete_file_name = NULL;
-
-       const int gunzip_to_stdout = 1;
-       const int gunzip_from_stdin = 2;
-       const int gunzip_force = 4;
-       const int gunzip_test = 8;
+const int gunzip_to_stdout = 1;
+const int gunzip_force = 2;
+const int gunzip_test = 4;
+const int gunzip_verbose = 8;
 
-       int flags = 0;
-       int opt = 0;
-       int delete_old_file = FALSE;
-
-       /* if called as zcat */
-       if (strcmp(applet_name, "zcat") == 0) {
-               if (argc != 2) {
-                       show_usage();
-               }
-               optind = 1;
-               flags |= (gunzip_force | gunzip_to_stdout);
-       } else {
-               /* workout flags as regular gunzip */
-               /* set default flags */
-               if (argc == 1) {
-                       flags |= (gunzip_from_stdin | gunzip_to_stdout);
-               } else {
-                       /* Parse any options */
-                       while ((opt = getopt(argc, argv, "ctfh")) != -1) {
-                               switch (opt) {
-                               case 'c':
-                                       flags |= gunzip_to_stdout;
-                                       break;
-                               case 'f':
-                                       flags |= gunzip_force;
-                                       break;
-                               case 't':
-                                       flags |= gunzip_test;
-                                       break;
-                               case 'h':
-                               default:
-                                       show_usage(); /* exit's inside usage */
-                               }
-                       }
-               }
+static int gunzip_file (const char *path, int flags)
+{
+    FILE *in_file, *out_file;
+    struct stat stat_buf;
+    const char *delete_path = NULL;
+    char *out_path = NULL;
+
+    if (path == NULL || strcmp (path, "-") == 0) {
+       in_file = stdin;
+       flags |= gunzip_to_stdout;
+    } else {
+       if ((in_file = wfopen(path, "r")) == NULL)
+           return -1;
+
+       if (flags & gunzip_verbose) {
+           fprintf(stderr, "%s:\t", path);
        }
 
-       /* Set input filename and number */
-       if (flags & gunzip_from_stdin) {
-               in_file = stdin;
-               if ((flags & gunzip_force) == 0) {
-                       error_msg_and_die("data not written to terminal. Use -f to force it.");
-               }
-       } else {
-               if_name = strdup(argv[optind]);
-               /* Open input file */
-               in_file = xfopen(if_name, "r");
+       /* set the buffer size */
+       setvbuf(in_file, NULL, _IOFBF, 0x8000);
 
-               /* Get the time stamp on the input file. */
-               if (stat(if_name, &stat_buf) < 0) {
-                       error_msg_and_die("Couldnt stat file %s",if_name);
-               }
+       /* Get the time stamp on the input file. */
+       if (stat(path, &stat_buf) < 0) {
+           error_msg_and_die("Couldn't stat file %s", path);
        }
-
-       /* Set output filename and number */
-       if (flags & gunzip_to_stdout) {
-               out_file = stdout;
-               /* whats the best way to do this with streams ? */
-               if (isatty(fileno(out_file)) && ((flags & gunzip_force) == 0)) {
-                       error_msg_and_die("data not written to terminal. Use -f to force it.");
-               }
-       } else if (flags & gunzip_test) {
-               out_file = xfopen("/dev/null", "w"); /* why does test use filenum 2 ? */
+    }
+
+    /* Check that the input is sane.  */
+    if (isatty(fileno(in_file)) && (flags & gunzip_force) == 0)
+       error_msg_and_die("compressed data not read from terminal.  Use -f to force it.");
+
+    /* Set output filename and number */
+    if (flags & gunzip_test) {
+       out_file = xfopen("/dev/null", "w"); /* why does test use filenum 2 ? */
+    } else if (flags & gunzip_to_stdout) {
+       out_file = stdout;
+    } else {
+       char *extension;
+       int length = strlen(path);
+
+       extension = strrchr(path, '.');
+       if (extension && strcmp(extension, ".gz") == 0) {
+           length -= 3;
+       } else if (extension && strcmp(extension, ".tgz") == 0) {
+           length -= 4;
        } else {
-               char *extension;
-               int length = strlen(if_name);
-
-               delete_old_file = TRUE;
-               extension = strrchr(if_name, '.');
-               if (strcmp(extension, ".gz") == 0) {
-                       length -= 3;
-               } else if (strcmp(extension, ".tgz") == 0) {
-                       length -= 4;
-               } else {
-                       error_msg_and_die("Invalid extension");
-               }
-               of_name = (char *) xcalloc(sizeof(char), length + 1);
-               strncpy(of_name, if_name, length);
-
-               /* Open output file */
-               out_file = xfopen(of_name, "w");
-
-               /* Set permissions on the file */
-               chmod(of_name, stat_buf.st_mode);
+           error_msg_and_die("Invalid extension");
        }
-
-       /* do the decompression, and cleanup */
-       if (unzip(in_file, out_file) == 0) {
-               /* Success, remove .gz file */
-               delete_file_name = if_name;
-       } else {
-               /* remove failed attempt */
-               delete_file_name = of_name;
+       out_path = (char *) xcalloc(sizeof(char), length + 1);
+       strncpy(out_path, path, length);
+                       
+       /* Open output file */
+       out_file = xfopen(out_path, "w");
+
+       /* Set permissions on the file */
+       chmod(out_path, stat_buf.st_mode);
+    }
+
+    /* do the decompression, and cleanup */
+    if (unzip(in_file, out_file) == 0) {
+       /* Success, remove .gz file */
+       if ( !(flags & gunzip_to_stdout ))
+           delete_path = path;
+       if (flags & gunzip_verbose) {
+           fprintf(stderr, "OK\n");
+       }
+    } else {
+       /* remove failed attempt */
+       delete_path = out_path;
+    }
+
+    if (out_file != stdout)
+           fclose(out_file);
+    if (in_file != stdin)
+           fclose(in_file);
+
+    if (delete_path && !(flags & gunzip_test)) {
+       if (unlink(delete_path) < 0) {
+           error_msg_and_die("Couldn't remove %s", delete_path);
        }
+    }
+
+    free(out_path);
+
+    return 0;
+}
 
-       fclose(out_file);
-       fclose(in_file);
+extern int gunzip_main(int argc, char **argv)
+{
+       int flags = 0;
+       int i, opt;
+       int status = EXIT_SUCCESS;
 
-       if (delete_old_file == TRUE) {
-               if (unlink(delete_file_name) < 0) {
-                       error_msg_and_die("Couldnt remove %s", delete_file_name);
+       /* if called as zcat */
+       if (strcmp(applet_name, "zcat") == 0)
+               flags |= gunzip_to_stdout;
+
+       while ((opt = getopt(argc, argv, "ctfhdqv")) != -1) {
+               switch (opt) {
+               case 'c':
+                       flags |= gunzip_to_stdout;
+                       break;
+               case 'f':
+                       flags |= gunzip_force;
+                       break;
+               case 't':
+                       flags |= gunzip_test;
+                       break;
+               case 'v':
+                       flags |= gunzip_verbose;
+                       break;
+               case 'd': /* Used to convert gzip to gunzip. */
+                       break;
+               case 'q':
+                       error_msg("-q option not supported, ignored");
+                       break;
+               case 'h':
+               default:
+                       show_usage(); /* exit's inside usage */
                }
        }
 
-       free(of_name);
-
-       return(EXIT_SUCCESS);
+       if (optind == argc) {
+           if (gunzip_file (NULL, flags) < 0)
+               status = EXIT_FAILURE;
+       } else {
+           for (i = optind; i < argc; i++) {
+               if (gunzip_file (argv[i], flags) < 0)
+                   status = EXIT_FAILURE;
+           }
+       }
+       return status;
 }