Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/usr.bin/unzip Add -p and -q support.



details:   https://anonhg.NetBSD.org/src/rev/71f9fc259378
branches:  trunk
changeset: 746881:71f9fc259378
user:      joerg <joerg%NetBSD.org@localhost>
date:      Sat Aug 22 02:19:42 2009 +0000

description:
Add -p and -q support.

diffstat:

 usr.bin/unzip/unzip.1 |   22 +++++-
 usr.bin/unzip/unzip.c |  153 +++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 164 insertions(+), 11 deletions(-)

diffs (289 lines):

diff -r f1ce47042a2f -r 71f9fc259378 usr.bin/unzip/unzip.1
--- a/usr.bin/unzip/unzip.1     Sat Aug 22 01:44:58 2009 +0000
+++ b/usr.bin/unzip/unzip.1     Sat Aug 22 02:19:42 2009 +0000
@@ -1,4 +1,5 @@
 .\"-
+.\" Copyright (c) 2009 Joerg Sonnenberger <joerg%NetBSD.org@localhost>
 .\" Copyright (c) 2007-2008 Dag-Erling Coïdan Smørgrav
 .\" All rights reserved.
 .\"
@@ -24,9 +25,9 @@
 .\" SUCH DAMAGE.
 .\"
 .\" $FreeBSD: revision 180125$
-.\" $NetBSD: unzip.1,v 1.2 2009/06/26 09:31:04 wiz Exp $
+.\" $NetBSD: unzip.1,v 1.3 2009/08/22 02:19:42 joerg Exp $
 .\"
-.Dd June 30, 2008
+.Dd August 22, 2009
 .Dt UNZIP 1
 .Os
 .Sh NAME
@@ -34,7 +35,7 @@
 .Nd extract files from a ZIP archive
 .Sh SYNOPSIS
 .Nm
-.Op Fl afjLlnoqtu
+.Op Fl afjLlnopqtuv
 .Op Fl d Ar dir
 .Op Fl x Ar pattern
 .Ar zipfile
@@ -65,9 +66,15 @@
 already exists on disk, the file is silently skipped.
 .It Fl o
 Overwrite.
-When extacting a file from the zipfile, if a file with the same name
+When extracting a file from the zipfile, if a file with the same name
 already exists on disk, the existing file is replaced with the file
 from the zipfile.
+.It Fl p
+Extract to stdout.
+When extracting files from the zipfile, they are written to stdout.
+The normal output is suppressed as if
+.Fl q
+was specified.
 .It Fl q
 Quiet: print less information while extracting.
 .It Fl t
@@ -79,6 +86,13 @@
 already exists on disk, the existing file is replaced with the file
 from the zipfile if and only if the latter is newer than the former.
 Otherwise, the file is silently skipped.
+.It Fl v
+List verbosely, rather than extract, the contents of the zipfile.
+This differs from
+.Fl l
+by using the long listening.
+Note that most of the data is currently fake and does not reflect the
+content of the archive.
 .It Fl x Ar pattern
 Exclude files matching the pattern
 .Ar pattern .
diff -r f1ce47042a2f -r 71f9fc259378 usr.bin/unzip/unzip.c
--- a/usr.bin/unzip/unzip.c     Sat Aug 22 01:44:58 2009 +0000
+++ b/usr.bin/unzip/unzip.c     Sat Aug 22 02:19:42 2009 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: unzip.c,v 1.1 2009/06/25 20:27:05 joerg Exp $ */
+/* $NetBSD: unzip.c,v 1.2 2009/08/22 02:19:42 joerg Exp $ */
 
 /*-
  * Copyright (c) 2009 Joerg Sonnenberger <joerg%NetBSD.org@localhost>
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: unzip.c,v 1.1 2009/06/25 20:27:05 joerg Exp $");
+__RCSID("$NetBSD: unzip.c,v 1.2 2009/08/22 02:19:42 joerg Exp $");
 
 #include <sys/queue.h>
 #include <sys/stat.h>
@@ -61,12 +61,13 @@
 static int              f_opt;         /* update existing files only */
 static int              j_opt;         /* junk directories */
 static int              L_opt;         /* lowercase names */
-static int              l_opt;         /* list */
 static int              n_opt;         /* never overwrite */
 static int              o_opt;         /* always overwrite */
+static int              p_opt;         /* extract to stdout */
 static int              q_opt;         /* quiet */
 static int              t_opt;         /* test */
 static int              u_opt;         /* update */
+static int              v_opt;         /* verbose */
 
 /* time when unzip started */
 static time_t           now;
@@ -631,14 +632,142 @@
        free(pathname);
 }
 
+static void
+extract_stdout(struct archive *a, struct archive_entry *e)
+{
+       char *pathname;
+       mode_t filetype;
+       int cr, text, warn;
+       ssize_t len;
+       unsigned char *p, *q, *end;
+
+       pathname = pathdup(archive_entry_pathname(e));
+       filetype = archive_entry_filetype(e);
+
+       /* I don't think this can happen in a zipfile.. */
+       if (!S_ISDIR(filetype) && !S_ISREG(filetype)) {
+               warningx("skipping non-regular entry '%s'", pathname);
+               ac(archive_read_data_skip(a));
+               free(pathname);
+               return;
+       }
+
+       /* skip directories in -j case */
+       if (S_ISDIR(filetype)) {
+               ac(archive_read_data_skip(a));
+               free(pathname);
+               return;
+       }
+
+       /* apply include / exclude patterns */
+       if (!accept_pathname(pathname)) {
+               ac(archive_read_data_skip(a));
+               free(pathname);
+               return;
+       }
+
+       text = a_opt;
+       warn = 0;
+       cr = 0;
+       for (int n = 0; ; n++) {
+               len = archive_read_data(a, buffer, sizeof buffer);
+
+               if (len < 0)
+                       ac(len);
+
+               /* left over CR from previous buffer */
+               if (a_opt && cr) {
+                       if (len == 0 || buffer[0] != '\n')
+                               if (write(STDOUT_FILENO, "\r", 1) != 1)
+                                       error("write('%s')", pathname);
+                       cr = 0;
+               }
+
+               /* EOF */
+               if (len == 0)
+                       break;
+               end = buffer + len;
+
+               /*
+                * Detect whether this is a text file.  The correct way to
+                * do this is to check the least significant bit of the
+                * "internal file attributes" field of the corresponding
+                * file header in the central directory, but libarchive
+                * does not read the central directory, so we have to
+                * guess by looking for non-ASCII characters in the
+                * buffer.  Hopefully we won't guess wrong.  If we do
+                * guess wrong, we print a warning message later.
+                */
+               if (a_opt && n == 0) {
+                       for (p = buffer; p < end; ++p) {
+                               if (!isascii((unsigned char)*p)) {
+                                       text = 0;
+                                       break;
+                               }
+                       }
+               }
+
+               /* simple case */
+               if (!a_opt || !text) {
+                       if (write(STDOUT_FILENO, buffer, len) != len)
+                               error("write('%s')", pathname);
+                       continue;
+               }
+
+               /* hard case: convert \r\n to \n (sigh...) */
+               for (p = buffer; p < end; p = q + 1) {
+                       for (q = p; q < end; q++) {
+                               if (!warn && !isascii(*q)) {
+                                       warningx("%s may be corrupted due"
+                                           " to weak text file detection"
+                                           " heuristic", pathname);
+                                       warn = 1;
+                               }
+                               if (q[0] != '\r')
+                                       continue;
+                               if (&q[1] == end) {
+                                       cr = 1;
+                                       break;
+                               }
+                               if (q[1] == '\n')
+                                       break;
+                       }
+                       if (write(STDOUT_FILENO, p, q - p) != q - p)
+                               error("write('%s')", pathname);
+               }
+       }
+
+       free(pathname);
+}
+
 /*
  * Print the name of an entry to stdout.
  */
 static void
 list(struct archive *a, struct archive_entry *e)
 {
+       static int printed_header;
+       char buf[20];
+       time_t mtime;
 
-       printf("%s\n", archive_entry_pathname(e));
+       if (!printed_header && !q_opt) {
+               printed_header = 1;
+               printf(" Length   Method    Size  Ratio   Date   Time  CRC-32    Name\n");
+               printf("--------  ------  ------- -----   ----   ----  ------    ----\n");
+       }
+
+       if (v_opt == 2) {
+               mtime = archive_entry_mtime(e);
+               strftime(buf, sizeof(buf), "%m-%d-%g %R", localtime(&mtime));
+               printf("%8ju  Stored  %7ju   0%%  %s %08x  %s\n",
+                   (uintmax_t)archive_entry_size(e),
+                   (uintmax_t)archive_entry_size(e),
+                   buf,
+                   0U,
+                   archive_entry_pathname(e));
+       } else {
+               printf("%s\n", archive_entry_pathname(e));
+       }
        ac(archive_read_data_skip(a));
 }
 
@@ -693,8 +822,10 @@
                ac(ret);
                if (t_opt)
                        test(a, e);
-               else if (l_opt)
+               else if (v_opt)
                        list(a, e);
+               else if (p_opt)
+                       extract_stdout(a, e);
                else
                        extract(a, e);
        }
@@ -722,7 +853,7 @@
        int opt;
 
        optreset = optind = 1;
-       while ((opt = getopt(argc, argv, "ad:fjLlnoqtux:")) != -1)
+       while ((opt = getopt(argc, argv, "ad:fjLlnopqtuvx:")) != -1)
                switch (opt) {
                case 'a':
                        a_opt = 1;
@@ -740,13 +871,18 @@
                        L_opt = 1;
                        break;
                case 'l':
-                       l_opt = 1;
+                       if (v_opt == 0)
+                               v_opt = 1;
                        break;
                case 'n':
                        n_opt = 1;
                        break;
                case 'o':
                        o_opt = 1;
+                       q_opt = 1;
+                       break;
+               case 'p':
+                       p_opt = 1;
                        break;
                case 'q':
                        q_opt = 1;
@@ -757,6 +893,9 @@
                case 'u':
                        u_opt = 1;
                        break;
+               case 'v':
+                       v_opt = 2;
+                       break;
                case 'x':
                        add_pattern(&exclude, optarg);
                        break;



Home | Main Index | Thread Index | Old Index