Module Name:    src
Committed By:   joerg
Date:           Sat Aug 22 02:19:43 UTC 2009

Modified Files:
        src/usr.bin/unzip: unzip.1 unzip.c

Log Message:
Add -p and -q support.


To generate a diff of this commit:
cvs rdiff -u -r1.2 -r1.3 src/usr.bin/unzip/unzip.1
cvs rdiff -u -r1.1 -r1.2 src/usr.bin/unzip/unzip.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/usr.bin/unzip/unzip.1
diff -u src/usr.bin/unzip/unzip.1:1.2 src/usr.bin/unzip/unzip.1:1.3
--- src/usr.bin/unzip/unzip.1:1.2	Fri Jun 26 09:31:04 2009
+++ src/usr.bin/unzip/unzip.1	Sat Aug 22 02:19:42 2009
@@ -1,4 +1,5 @@
 .\"-
+.\" Copyright (c) 2009 Joerg Sonnenberger <jo...@netbsd.org>
 .\" 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 .

Index: src/usr.bin/unzip/unzip.c
diff -u src/usr.bin/unzip/unzip.c:1.1 src/usr.bin/unzip/unzip.c:1.2
--- src/usr.bin/unzip/unzip.c:1.1	Thu Jun 25 20:27:05 2009
+++ src/usr.bin/unzip/unzip.c	Sat Aug 22 02:19:42 2009
@@ -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 <jo...@netbsd.org>
@@ -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;

Reply via email to