Index: compress.h
===================================================================
--- compress.h	(revision 2)
+++ compress.h	(revision 3)
@@ -65,6 +65,12 @@
 extern int gz_close(void *, struct z_info *);
 extern int gz_flush(void *, int);
 
+extern void *bz2_open(int, const char *, char *, int, u_int32_t, int);
+extern int bz2_read(void *, char *, int);
+extern int bz2_write(void *, const char *, int);
+extern int bz2_close(void *, struct z_info *);
+extern int bz2_flush(void *, int);
+
 extern void *lzh_open(int, const char *, char *, int, u_int32_t, int);
 extern int lzh_read(void *, char *, int);
 extern int lzh_write(void *, const char *, int);
Index: bz2open.c
===================================================================
--- bz2open.c	(revision 0)
+++ bz2open.c	(revision 3)
@@ -0,0 +1,181 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1997 Michael Shalayeff
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/* delivered from gzopen.c */
+
+#include <bzlib.h>
+#include <err.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "compress.h"
+
+#define BZ2_BUFSIZE	(64*1024)
+
+typedef
+struct _bz2_stream {
+	int z_fd;		/* .bz2 file */
+	bz_stream z_stream;	/* libbz2 stream */
+	int z_eof;		/* set if end of input file */
+	char z_buf[BZ2_BUFSIZE];	/* i/o buffer */
+	char z_mode;		/* 'w' or 'r' */
+} bz2_stream;
+
+void *
+bz2_open(int fd, const char *mode, char *name, int bits,
+    u_int32_t mtime, int gotmagic)
+{
+	bz2_stream *s;
+
+	if (fd < 0 || !mode)
+		return NULL;
+
+	if ((mode[0] != 'r' && mode[0] != 'w') || mode[1] != '\0') {
+		errno = EINVAL;
+		return NULL;
+	}
+	if ((s = (bz2_stream *)calloc(1, sizeof(bz2_stream))) == NULL)
+		return NULL;
+
+	s->z_mode = mode[0];
+
+	if (s->z_mode == 'w') {
+		errno = EOPNOTSUPP;
+		return (NULL);
+	} else {
+		if (BZ2_bzDecompressInit(&(s->z_stream), 0, 0) != BZ_OK) {
+			free (s);
+			return NULL;
+		}
+		s->z_stream.next_in = s->z_buf;
+		memcpy(s->z_buf, "\102\132", 2);
+		s->z_stream.avail_in = 2;
+	}
+
+	errno = 0;
+	s->z_fd = fd;
+
+	return s;
+}
+
+int
+bz2_close(void *cookie, struct z_info *info)
+{
+	bz2_stream *s = (bz2_stream*)cookie;
+	int error, error2;
+
+	if (s == NULL)
+		return -1;
+
+	if (s->z_mode == 'r')
+		error = BZ2_bzDecompressEnd(&s->z_stream);
+
+	error2 = close(s->z_fd);
+
+	if (info != NULL) {
+		memset(info, 0, sizeof(*info));
+		info->total_in =
+		    (((uint64_t)s->z_stream.total_in_hi32 << 32)
+		    | s->z_stream.total_in_lo32);
+		info->total_out =
+		    (((uint64_t)s->z_stream.total_out_hi32 << 32)
+		    | s->z_stream.total_out_lo32);
+	}
+
+	free(s);
+
+	return error ? error : error2;
+}
+
+int
+bz2_flush(void *cookie, int flush)
+{
+	/* XXX */
+
+	return 0;
+}
+
+int
+bz2_read(void *cookie, char *buf, int len)
+{
+	bz2_stream *s = (bz2_stream*)cookie;
+	int error = BZ_OK;
+
+	s->z_stream.next_out = buf;
+	s->z_stream.avail_out = len;
+
+	while (error != BZ_STREAM_END &&
+	    !s->z_eof && s->z_stream.avail_out > 0) {
+		if (s->z_stream.avail_in == 0 && !s->z_eof) {
+			ssize_t n;
+
+			errno = 0;
+			n = read(s->z_fd, s->z_buf, Z_BUFSIZE);
+			if (n == (ssize_t)-1)
+				return -1;
+			if (n == 0)
+				s->z_eof = 1;
+			s->z_stream.next_in = s->z_buf;
+			s->z_stream.avail_in = n;
+		}
+
+		error = BZ2_bzDecompress(&(s->z_stream));
+		switch (error) {
+		case BZ_STREAM_END:
+			s->z_eof = 1;
+			break;
+		case BZ_OK:
+			if (s->z_eof) {
+				errno = EIO; /* unexpected eof */
+				return -1;
+			}
+			break;
+	        case BZ_DATA_ERROR:
+	        case BZ_DATA_ERROR_MAGIC:
+	        case BZ_MEM_ERROR:
+			/* XXX should report more precise error */
+		default:
+			errno = EINVAL;
+			return -1;
+		}
+	}
+
+	len -= s->z_stream.avail_out;
+
+	return (len);
+}
+
+int
+bz2_write(void *cookie, const char *buf, int len)
+{
+
+	return 0;
+}
Index: main.c
===================================================================
--- main.c	(revision 2)
+++ main.c	(revision 3)
@@ -74,16 +74,20 @@
 } c_table[] = {
 #define M_DEFLATE (&c_table[0])
   { "deflate", ".gz", "\037\213", gz_open, gz_read, gz_write, gz_close },
-#define M_COMPRESS (&c_table[1])
+#define M_BZIP2 (&c_table[1])
+  { "bzip2", ".bz2", "\102\132", bz2_open, bz2_read, bz2_write, bz2_close },
+#ifndef SMALL
+#endif /* SMALL */
+#define M_COMPRESS (&c_table[2])
 #ifndef SMALL
   { "compress", ".Z", "\037\235", z_open,  zread,   zwrite,   z_close },
 #endif /* SMALL */
 #if 0
-#define M_LZH (&c_table[2])
+#define M_LZH (&c_table[3])
   { "lzh", ".lzh", "\037\240", lzh_open, lzh_read, lzh_write, lzh_close },
-#define M_ZIP (&c_table[3])
+#define M_ZIP (&c_table[4])
   { "zip", ".zip", "PK", zip_open, zip_read, zip_write, zip_close },
-#define M_PACK (&c_table[4])
+#define M_PACK (&c_table[5])
   { "pack", ".pak", "\037\036", pak_open, pak_read, pak_write, pak_close },
 #endif
   { NULL }
@@ -734,7 +738,8 @@
 {
 	int i;
 	char *suf, *sep, *separators = ".-_";
-	static char *suffixes[] = { "Z", "gz", "z", "tgz", "taz", NULL };
+	static const char *suffixes[] =
+	    { "Z", "gz", "z", "tgz", "taz", "bz2", NULL };
 
 	for (sep = separators; *sep != '\0'; sep++) {
 		if ((suf = strrchr(infile, *sep)) == NULL)
Index: Makefile
===================================================================
--- Makefile	(revision 2)
+++ Makefile	(revision 3)
@@ -1,7 +1,7 @@
 #	$OpenBSD: Makefile,v 1.19 2003/09/05 04:46:35 tedu Exp $
 
 PROG=	compress
-SRCS=	main.c zopen.c gzopen.c nullopen.c
+SRCS=	main.c zopen.c gzopen.c bz2open.c nullopen.c
 MAN=	compress.1 zmore.1 zdiff.1 zforce.1 gzexe.1 znew.1
 LINKS=	${BINDIR}/compress ${BINDIR}/uncompress \
 	${BINDIR}/compress ${BINDIR}/zcat \
@@ -17,8 +17,8 @@
 	compress.1 gzcat.1 \
 	zdiff.1 zcmp.1
 
-LDADD=-lz
-DPADD=${LIBZ}
+LDADD=-lz -lbz2
+DPADD=${LIBZ} ${LIBBZ2}
 
 afterinstall:
 	install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \