@ 260915.5

231112.1 · 8dd59688c4386b8b699cffdd18b46730a832da23

add bzip3 decompression #311

tested and working: new m4/ax_check_bzip3lib.m4, updated autotools; updated ugrep.cpp; updated tests

reading declarations

Makefile.am

@@ -70,7 +70,8 @@ install-data-hook: 		 echo "|   alias zpgrep = 'ug -zP'                            |"; \ 		 echo "|   alias ux     = 'ugrep -U --hexdump'                |"; \ 		 echo "|   alias zxgrep = 'ugrep -zU --hexdump'               |"; \-		 echo "|   alias xdump  = 'ugrep -X \"\"'                       |"; \+		 echo "|   alias xdump  = 'ugrep --hexdump \"\"'                |"; \+		 echo "|   alias zmore  = 'ugrep+ -z -I -+ --pager \"\"'        |"; \ 		 echo "|                                                      |"; \ 		 echo "| Thank you for using ugrep!                           |"; \ 		 echo "|                                                      |"; \

Makefile.in

@@ -91,7 +91,8 @@ subdir = . ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_boost_regex.m4 \ 	$(top_srcdir)/m4/ax_check_brotlilib.m4 \-	$(top_srcdir)/m4/ax_check_bzlib.m4 \+	$(top_srcdir)/m4/ax_check_bz2lib.m4 \+	$(top_srcdir)/m4/ax_check_bzip3lib.m4 \ 	$(top_srcdir)/m4/ax_check_lz4lib.m4 \ 	$(top_srcdir)/m4/ax_check_lzmalib.m4 \ 	$(top_srcdir)/m4/ax_check_pcre2.m4 \@@ -955,7 +956,8 @@ install-data-hook: 		 echo "|   alias zpgrep = 'ug -zP'                            |"; \ 		 echo "|   alias ux     = 'ugrep -U --hexdump'                |"; \ 		 echo "|   alias zxgrep = 'ugrep -zU --hexdump'               |"; \-		 echo "|   alias xdump  = 'ugrep -X \"\"'                       |"; \+		 echo "|   alias xdump  = 'ugrep --hexdump \"\"'                |"; \+		 echo "|   alias zmore  = 'ugrep+ -z -I -+ --pager \"\"'        |"; \ 		 echo "|                                                      |"; \ 		 echo "| Thank you for using ugrep!                           |"; \ 		 echo "|                                                      |"; \

aclocal.m4

@@ -1248,7 +1248,8 @@ AC_SUBST([am__untar])  m4_include([m4/ax_boost_regex.m4]) m4_include([m4/ax_check_brotlilib.m4])-m4_include([m4/ax_check_bzlib.m4])+m4_include([m4/ax_check_bz2lib.m4])+m4_include([m4/ax_check_bzip3lib.m4]) m4_include([m4/ax_check_lz4lib.m4]) m4_include([m4/ax_check_lzmalib.m4]) m4_include([m4/ax_check_pcre2.m4])

config.h.in

@@ -28,6 +28,9 @@ /* Define to 1 if you have `bz2' library (-lbz2) */ #undef HAVE_LIBBZ2 +/* Define to 1 if you have `bzip3' library (-lbzip3) */+#undef HAVE_LIBBZIP3+ /* Define to 1 if you have `lz4' library (-llz4) */ #undef HAVE_LIBLZ4 

configure

@@ -777,7 +777,8 @@ with_bzlib with_lzma with_lz4 with_zstd-with_brotlilib+with_brotli+with_bzip3 with_grep_path with_grep_colors enable_auto_color@@ -1477,10 +1478,14 @@ Optional Packages:   --with-zstd=DIR         root directory path of zstd installation [defaults to                           /usr/local or /usr if not found in /usr/local]   --without-zstd          to disable zstd usage completely-  --with-brotlilib=DIR    root directory path of brotli library installation+  --with-brotli=DIR       root directory path of brotli library installation                           [defaults to /usr/local or /usr if not found in                           /usr/local]-  --without-brotlilib     to disable brotli library usage completely+  --without-brotli        to disable brotli library usage completely+  --with-bzip3=DIR        root directory path of bzip3 library installation+                          [defaults to /usr/local or /usr if not found in+                          /usr/local]+  --without-bzip3         to disable bzip3 library usage completely   --with-grep-path=GREP_PATH                           specifies the GREP_PATH if different than the                           default DATAROOTDIR/ugrep/patterns@@ -7871,16 +7876,16 @@ then   # check the user supplied or any other more or less 'standard' place:   #   Most UNIX systems      : /usr/local and /usr   #   MacPorts / Fink on OSX : /opt/local respectively /sw-  for BZLIB_HOME in ${bzlib_places} ; do-    if test -f "${BZLIB_HOME}/include/bzlib.h"; then break; fi-    BZLIB_HOME=""+  for B2ZLIB_HOME in ${bzlib_places} ; do+    if test -f "${B2ZLIB_HOME}/include/bzlib.h"; then break; fi+    B2ZLIB_HOME=""   done -  BZLIB_OLD_LDFLAGS=$LDFLAGS-  BZLIB_OLD_CPPFLAGS=$CPPFLAGS-  if test -n "${BZLIB_HOME}"; then-    LDFLAGS="$LDFLAGS -L${BZLIB_HOME}/lib"-    CPPFLAGS="$CPPFLAGS -I${BZLIB_HOME}/include"+  B2ZLIB_OLD_LDFLAGS=$LDFLAGS+  B2ZLIB_OLD_CPPFLAGS=$CPPFLAGS+  if test -n "${B2ZLIB_HOME}"; then+    LDFLAGS="$LDFLAGS -L${B2ZLIB_HOME}/lib"+    CPPFLAGS="$CPPFLAGS -I${B2ZLIB_HOME}/include"   fi   ac_ext=c ac_cpp='$CPP $CPPFLAGS'@@ -7950,8 +7955,8 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu     # If both library and header were found, action-if-found     # -                CPPFLAGS="$CPPFLAGS -I${BZLIB_HOME}/include"-                LDFLAGS="$LDFLAGS -L${BZLIB_HOME}/lib"+                CPPFLAGS="$CPPFLAGS -I${B2ZLIB_HOME}/include"+                LDFLAGS="$LDFLAGS -L${B2ZLIB_HOME}/lib"                 LIBS="-lbz2 $LIBS"  printf "%s\n" "#define HAVE_LIBBZ2 1" >>confdefs.h@@ -8368,25 +8373,25 @@ fi # # Handle user hints #-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if brotlilib is wanted" >&5-printf %s "checking if brotlilib is wanted... " >&6; }-brotlilib_places="/usr/local /usr /opt/homebrew /opt/local /sw"+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if brotli is wanted" >&5+printf %s "checking if brotli is wanted... " >&6; }+brotli_places="/usr/local /usr /opt/homebrew /opt/local /sw" -# Check whether --with-brotlilib was given.-if test ${with_brotlilib+y}+# Check whether --with-brotli was given.+if test ${with_brotli+y} then :-  withval=$with_brotlilib; if test "$withval" != "no" ; then+  withval=$with_brotli; if test "$withval" != "no" ; then   { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; }   if test -d "$withval"   then-    brotlilib_places="$withval $brotlilib_places"+    brotli_places="$withval $brotli_places"   else     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Sorry, $withval does not exist, checking usual places" >&5 printf "%s\n" "$as_me: WARNING: Sorry, $withval does not exist, checking usual places" >&2;}   fi else-  brotlilib_places=""+  brotli_places=""   { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi@@ -8396,23 +8401,23 @@ printf "%s\n" "yes" >&6; } fi  #-# Locate brotlilib, if wanted+# Locate brotli, if wanted #-if test -n "${brotlilib_places}"+if test -n "${brotli_places}" then   # check the user supplied or any other more or less 'standard' place:   #   Most UNIX systems      : /usr/local and /usr   #   MacPorts / Fink on OSX : /opt/local respectively /sw-  for BROTLILIB_HOME in ${brotlilib_places} ; do+  for BROTLI_HOME in ${brotli_places} ; do     if test -f "${BROTLILIB_HOME}/include/brotli/decode.h"; then break; fi-    BROTLILIB_HOME=""+    BROTLI_HOME=""   done -  BROTLILIB_OLD_LDFLAGS=$LDFLAGS-  BROTLILIB_OLD_CPPFLAGS=$CPPFLAGS-  if test -n "${BROTLILIB_HOME}"; then-    LDFLAGS="$LDFLAGS -L${BROTLILIB_HOME}/lib"-    CPPFLAGS="$CPPFLAGS -I${BROTLILIB_HOME}/include"+  BROTLI_OLD_LDFLAGS=$LDFLAGS+  BROTLI_OLD_CPPFLAGS=$CPPFLAGS+  if test -n "${BROTLI_HOME}"; then+    LDFLAGS="$LDFLAGS -L${BROTLI_HOME}/lib"+    CPPFLAGS="$CPPFLAGS -I${BROTLI_HOME}/include"   fi   ac_ext=c ac_cpp='$CPP $CPPFLAGS'@@ -8457,17 +8462,17 @@ fi printf "%s\n" "$ac_cv_lib_brotlidec_BrotliDecoderCreateInstance" >&6; } if test "x$ac_cv_lib_brotlidec_BrotliDecoderCreateInstance" = xyes then :-  brotlilib_cv_libbrotli=yes+  brotli_cv_libbrotli=yes else $as_nop-  brotlilib_cv_libbrotli=no+  brotli_cv_libbrotli=no fi    ac_fn_c_check_header_compile "$LINENO" "brotli/decode.h" "ac_cv_header_brotli_decode_h" "$ac_includes_default" if test "x$ac_cv_header_brotli_decode_h" = xyes then :-  brotlilib_cv_brotli_h=yes+  brotli_cv_brotli_h=yes else $as_nop-  brotlilib_cv_brotli_h=no+  brotli_cv_brotli_h=no fi    ac_ext=cpp@@ -8476,14 +8481,14 @@ ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu -  if test "$brotlilib_cv_libbrotli" = "yes" && test "$brotlilib_cv_brotli_h" = "yes"+  if test "$brotli_cv_libbrotli" = "yes" && test "$brotli_cv_brotli_h" = "yes"   then     #     # If both library and header were found, action-if-found     # -                CPPFLAGS="$CPPFLAGS -I${BROTLILIB_HOME}/include"-                LDFLAGS="$LDFLAGS -L${BROTLILIB_HOME}/lib"+                CPPFLAGS="$CPPFLAGS -I${BROTLI_HOME}/include"+                LDFLAGS="$LDFLAGS -L${BROTLI_HOME}/lib"                 LIBS="-lbrotlidec -lbrotlienc $LIBS"  printf "%s\n" "#define HAVE_LIBBROTLI 1" >>confdefs.h@@ -8498,6 +8503,139 @@ printf "%s\n" "#define HAVE_LIBBROTLI 1" >>confdefs.h fi  +#+# Handle user hints+#+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if bzip3 is wanted" >&5+printf %s "checking if bzip3 is wanted... " >&6; }+bzip3_places="/usr/local /usr /opt/homebrew /opt/local /sw"++# Check whether --with-bzip3 was given.+if test ${with_bzip3+y}+then :+  withval=$with_bzip3; if test "$withval" != "no" ; then+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5+printf "%s\n" "yes" >&6; }+  if test -d "$withval"+  then+    bzip3_places="$withval $bzip3_places"+  else+    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Sorry, $withval does not exist, checking usual places" >&5+printf "%s\n" "$as_me: WARNING: Sorry, $withval does not exist, checking usual places" >&2;}+  fi+else+  bzip3_places=""+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5+printf "%s\n" "no" >&6; }+fi+else $as_nop+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5+printf "%s\n" "yes" >&6; }+fi++#+# Locate bzip3 library, if wanted+#+if test -n "${bzip3_places}"+then+  # check the user supplied or any other more or less 'standard' place:+  #   Most UNIX systems      : /usr/local and /usr+  #   MacPorts / Fink on OSX : /opt/local respectively /sw+  for BZIP3_HOME in ${bzip3_places} ; do+    if test -f "${BZIP3_HOME}/include/libbz3.h"; then break; fi+    BZIP3_HOME=""+  done++  BZIP3_OLD_LDFLAGS=$LDFLAGS+  BZIP3_OLD_CPPFLAGS=$CPPFLAGS+  if test -n "${BZIP3_HOME}"; then+    LDFLAGS="$LDFLAGS -L${BZIP3_HOME}/lib"+    CPPFLAGS="$CPPFLAGS -I${BZIP3_HOME}/include"+  fi+  ac_ext=c+ac_cpp='$CPP $CPPFLAGS'+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'+ac_compiler_gnu=$ac_cv_c_compiler_gnu++  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for bz3_new in -lbzip3" >&5+printf %s "checking for bz3_new in -lbzip3... " >&6; }+if test ${ac_cv_lib_bzip3_bz3_new+y}+then :+  printf %s "(cached) " >&6+else $as_nop+  ac_check_lib_save_LIBS=$LIBS+LIBS="-lbzip3  $LIBS"+cat confdefs.h - <<_ACEOF >conftest.$ac_ext+/* end confdefs.h.  */++/* Override any GCC internal prototype to avoid an error.+   Use char because int might match the return type of a GCC+   builtin and then its argument prototype would still apply.  */+char bz3_new ();+int+main (void)+{+return bz3_new ();+  ;+  return 0;+}+_ACEOF+if ac_fn_c_try_link "$LINENO"+then :+  ac_cv_lib_bzip3_bz3_new=yes+else $as_nop+  ac_cv_lib_bzip3_bz3_new=no+fi+rm -f core conftest.err conftest.$ac_objext conftest.beam \+    conftest$ac_exeext conftest.$ac_ext+LIBS=$ac_check_lib_save_LIBS+fi+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bzip3_bz3_new" >&5+printf "%s\n" "$ac_cv_lib_bzip3_bz3_new" >&6; }+if test "x$ac_cv_lib_bzip3_bz3_new" = xyes+then :+  bzip3_cv_libbzip3=yes+else $as_nop+  bzip3_cv_libbzip3=no+fi++  ac_fn_c_check_header_compile "$LINENO" "libbz3.h" "ac_cv_header_libbz3_h" "$ac_includes_default"+if test "x$ac_cv_header_libbz3_h" = xyes+then :+  bzip3_cv_libbz3_h=yes+else $as_nop+  bzip3_cv_libbz3_h=no+fi++  ac_ext=cpp+ac_cpp='$CXXCPP $CPPFLAGS'+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu++  if test "$bzip3_cv_libbzip3" = "yes" && test "$bzip3_cv_libbz3_h" = "yes"+  then+    #+    # If both library and header were found, action-if-found+    #++                CPPFLAGS="$CPPFLAGS -I${BZIP3_HOME}/include"+                LDFLAGS="$LDFLAGS -L${BZIP3_HOME}/lib"+                LIBS="-lbzip3 $LIBS"++printf "%s\n" "#define HAVE_LIBBZIP3 1" >>confdefs.h+++  else+    #+    # If either header or library was not found, action-if-not-found+    #+    echo "libbzip3 not found: ugrep option -z won't decompress .bz3 files"+  fi+fi++  # Check whether --with-grep-path was given. if test ${with_grep_path+y}

configure.ac

@@ -70,7 +70,7 @@ fi  AX_CHECK_ZLIB([], [echo "zlib not found: ugrep option -z is not available"]) -AX_CHECK_BZLIB([], [echo "libbz2 not found: ugrep option -z won't decompress .bz and .bz2 files"])+AX_CHECK_BZ2LIB([], [echo "libbz2 not found: ugrep option -z won't decompress .bz and .bz2 files"])  AX_CHECK_LZMALIB([], [echo "liblzma not found: ugrep option -z won't decompress .lzma and .xz files"]) @@ -80,6 +80,8 @@ AX_CHECK_ZSTDLIB([], [echo "libzstd not found: ugrep option -z won't decompress  AX_CHECK_BROTLILIB([], [echo "brotli library not found: ugrep option -z won't decompress .br files"]) +AX_CHECK_BZIP3LIB([], [echo "libbzip3 not found: ugrep option -z won't decompress .bz3 files"])+ AC_ARG_WITH(grep-path,   [AS_HELP_STRING([--with-grep-path=GREP_PATH],                   [specifies the GREP_PATH if different than the default DATAROOTDIR/ugrep/patterns])],

lib/Makefile.in

@@ -92,7 +92,8 @@ subdir = lib ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_boost_regex.m4 \ 	$(top_srcdir)/m4/ax_check_brotlilib.m4 \-	$(top_srcdir)/m4/ax_check_bzlib.m4 \+	$(top_srcdir)/m4/ax_check_bz2lib.m4 \+	$(top_srcdir)/m4/ax_check_bzip3lib.m4 \ 	$(top_srcdir)/m4/ax_check_lz4lib.m4 \ 	$(top_srcdir)/m4/ax_check_lzmalib.m4 \ 	$(top_srcdir)/m4/ax_check_pcre2.m4 \

m4/ax_check_brotlilib.m4

@@ -6,21 +6,21 @@ # #   This macro searches for an installed brotli library. If nothing was #   specified when calling configure, it searches first in /usr/local and-#   then in /usr, /opt/local and /sw. If the --with-brotlilib=DIR is specified,+#   then in /usr, /opt/local and /sw. If the --with-brotli=DIR is specified, #   it will try to find it in DIR/include/brotli/decode.h and-#   DIR/lib/libbrotlidec. If --without-brotlilib is specified, the library is+#   DIR/lib/libbrotlidec. If --without-brotli is specified, the library is #   not searched at all. # #   If either the header file (brotli/decode.h) or the library (libbrotlidec) #   is not found, shell commands 'action-if-not-found' is run. If #   'action-if-not-found' is not specified, the configuration exits on error, #   asking for a valid brotli library installation directory or-#   --without-brotlilib.+#   --without-brotli. # #   If both header file and library are found, shell commands #   'action-if-found' is run. If 'action-if-found' is not specified, the-#   default action appends '-I${BROTLILIB_HOME}/include' to CPFLAGS, appends-#   '-L${BROTLILIB_HOME}/lib' to LDFLAGS, prepends '-lbrotlidec' and+#   default action appends '-I${BROTLI_HOME}/include' to CPFLAGS, appends+#   '-L${BROTLI_HOME}/lib' to LDFLAGS, prepends '-lbrotlidec' and #   '-lbrotlienc' to LIBS, and calls AC_DEFINE(HAVE_LIBBROTLI). You should use #   autoheader to include a definition for this symbol in a config.h file. #   Sample usage in a C/C++ source is as follows:@@ -66,64 +66,64 @@ AC_DEFUN([AX_CHECK_BROTLILIB], # # Handle user hints #-[AC_MSG_CHECKING(if brotlilib is wanted)-brotlilib_places="/usr/local /usr /opt/homebrew /opt/local /sw"-AC_ARG_WITH([brotlilib],-[  --with-brotlilib=DIR    root directory path of brotli library installation+[AC_MSG_CHECKING(if brotli is wanted)+brotli_places="/usr/local /usr /opt/homebrew /opt/local /sw"+AC_ARG_WITH([brotli],+[  --with-brotli=DIR       root directory path of brotli library installation                           @<:@defaults to /usr/local or /usr if not found in                           /usr/local@:>@-  --without-brotlilib     to disable brotli library usage completely],+  --without-brotli        to disable brotli library usage completely], [if test "$withval" != "no" ; then   AC_MSG_RESULT(yes)   if test -d "$withval"   then-    brotlilib_places="$withval $brotlilib_places"+    brotli_places="$withval $brotli_places"   else     AC_MSG_WARN([Sorry, $withval does not exist, checking usual places])   fi else-  brotlilib_places=""+  brotli_places=""   AC_MSG_RESULT(no) fi], [AC_MSG_RESULT(yes)]) #-# Locate brotlilib, if wanted+# Locate brotli, if wanted #-if test -n "${brotlilib_places}"+if test -n "${brotli_places}" then   # check the user supplied or any other more or less 'standard' place:   #   Most UNIX systems      : /usr/local and /usr   #   MacPorts / Fink on OSX : /opt/local respectively /sw-  for BROTLILIB_HOME in ${brotlilib_places} ; do+  for BROTLI_HOME in ${brotli_places} ; do     if test -f "${BROTLILIB_HOME}/include/brotli/decode.h"; then break; fi-    BROTLILIB_HOME=""+    BROTLI_HOME=""   done -  BROTLILIB_OLD_LDFLAGS=$LDFLAGS-  BROTLILIB_OLD_CPPFLAGS=$CPPFLAGS-  if test -n "${BROTLILIB_HOME}"; then-    LDFLAGS="$LDFLAGS -L${BROTLILIB_HOME}/lib"-    CPPFLAGS="$CPPFLAGS -I${BROTLILIB_HOME}/include"+  BROTLI_OLD_LDFLAGS=$LDFLAGS+  BROTLI_OLD_CPPFLAGS=$CPPFLAGS+  if test -n "${BROTLI_HOME}"; then+    LDFLAGS="$LDFLAGS -L${BROTLI_HOME}/lib"+    CPPFLAGS="$CPPFLAGS -I${BROTLI_HOME}/include"   fi   AC_LANG_PUSH([C])-  AC_CHECK_LIB([brotlidec], [BrotliDecoderCreateInstance], [brotlilib_cv_libbrotli=yes], [brotlilib_cv_libbrotli=no])-  AC_CHECK_HEADER([brotli/decode.h], [brotlilib_cv_brotli_h=yes], [brotlilib_cv_brotli_h=no])+  AC_CHECK_LIB([brotlidec], [BrotliDecoderCreateInstance], [brotli_cv_libbrotli=yes], [brotli_cv_libbrotli=no])+  AC_CHECK_HEADER([brotli/decode.h], [brotli_cv_brotli_h=yes], [brotli_cv_brotli_h=no])   AC_LANG_POP([C])-  if test "$brotlilib_cv_libbrotli" = "yes" && test "$brotlilib_cv_brotli_h" = "yes"+  if test "$brotli_cv_libbrotli" = "yes" && test "$brotli_cv_brotli_h" = "yes"   then     #     # If both library and header were found, action-if-found     #     m4_ifblank([$1],[-                CPPFLAGS="$CPPFLAGS -I${BROTLILIB_HOME}/include"-                LDFLAGS="$LDFLAGS -L${BROTLILIB_HOME}/lib"+                CPPFLAGS="$CPPFLAGS -I${BROTLI_HOME}/include"+                LDFLAGS="$LDFLAGS -L${BROTLI_HOME}/lib"                 LIBS="-lbrotlidec -lbrotlienc $LIBS"                 AC_DEFINE([HAVE_LIBBROTLI], [1],                           [Define to 1 if you have `brotli' library (-lbrotlidec -lbrotlienc)])                ],[                 # Restore variables-                LDFLAGS="$BROTLILIB_OLD_LDFLAGS"-                CPPFLAGS="$BROTLILIB_OLD_CPPFLAGS"+                LDFLAGS="$BROTLI_OLD_LDFLAGS"+                CPPFLAGS="$BROTLI_OLD_CPPFLAGS"                 $1                ])   else@@ -131,7 +131,7 @@ then     # If either header or library was not found, action-if-not-found     #     m4_default([$2],[-                AC_MSG_ERROR([either specify a valid brotli library installation with --with-brotlilib=DIR or disable brotlilib usage with --without-brotlilib])+                AC_MSG_ERROR([either specify a valid brotli library installation with --with-brotli=DIR or disable brotli usage with --without-brotli])                 ])   fi fi

m4/ax_check_bz2lib.m4

new file mode 100644@@ -0,0 +1,134 @@+# SYNOPSIS+#+#   AX_CHECK_BZ2LIB([action-if-found], [action-if-not-found])+#+# DESCRIPTION+#+#   This macro searches for an installed bzlib/bz2 library. If nothing was+#   specified when calling configure, it searches first in /usr/local and+#   then in /usr, /opt/local and /sw. If the --with-bzlib=DIR is specified,+#   it will try to find it in DIR/include/bzlib.h and DIR/lib/libbz2. If+#   --without-bzlib is specified, the library is not searched at all.+#+#   If either the header file (bzlib.h) or the library (libbz2) is not found,+#   shell commands 'action-if-not-found' is run. If 'action-if-not-found' is+#   not specified, the configuration exits on error, asking for a valid bzlib+#   installation directory or --without-bzlib.+#+#   If both header file and library are found, shell commands+#   'action-if-found' is run. If 'action-if-found' is not specified, the+#   default action appends '-I${BZ2LIB_HOME}/include' to CPFLAGS, appends+#   '-L${BZ2LIB_HOME}/lib' to LDFLAGS, prepends '-lbz2' to LIBS, and calls+#   AC_DEFINE(HAVE_LIBBZ2). You should use autoheader to include a definition+#   for this symbol in a config.h file. Sample usage in a C/C++ source is as+#   follows:+#+#     #ifdef HAVE_LIBBZ2+#     #include <bzlib.h>+#     #endif /* HAVE_LIBBZ2 */+#+# LICENSE+#+#   Copyright (c) 2019 Robert van Engelen <engelen@acm.org>+#+#   This program is free software; you can redistribute it and/or modify it+#   under the terms of the GNU General Public License as published by the+#   Free Software Foundation; either version 2 of the License, or (at your+#   option) any later version.+#+#   This program is distributed in the hope that it will be useful, but+#   WITHOUT ANY WARRANTY; without even the implied warranty of+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General+#   Public License for more details.+#+#   You should have received a copy of the GNU General Public License along+#   with this program. If not, see <https://www.gnu.org/licenses/>.+#+#   As a special exception, the respective Autoconf Macro's copyright owner+#   gives unlimited permission to copy, distribute and modify the configure+#   scripts that are the output of Autoconf when processing the Macro. You+#   need not follow the terms of the GNU General Public License when using+#   or distributing such scripts, even though portions of the text of the+#   Macro appear in them. The GNU General Public License (GPL) does govern+#   all other use of the material that constitutes the Autoconf Macro.+#+#   This special exception to the GPL applies to versions of the Autoconf+#   Macro released by the Autoconf Archive. When you make and distribute a+#   modified version of the Autoconf Macro, you may extend this special+#   exception to the GPL to apply to your modified version as well.++#serial 1++AC_DEFUN([AX_CHECK_BZ2LIB],+#+# Handle user hints+#+[AC_MSG_CHECKING(if bzlib is wanted)+bzlib_places="/usr/local /usr /opt/homebrew /opt/local /sw"+AC_ARG_WITH([bzlib],+[  --with-bzlib=DIR        root directory path of bzlib installation @<:@defaults to+                          /usr/local or /usr if not found in /usr/local@:>@+  --without-bzlib         to disable bzlib usage completely],+[if test "$withval" != "no" ; then+  AC_MSG_RESULT(yes)+  if test -d "$withval"+  then+    bzlib_places="$withval $bzlib_places"+  else+    AC_MSG_WARN([Sorry, $withval does not exist, checking usual places])+  fi+else+  bzlib_places=""+  AC_MSG_RESULT(no)+fi],+[AC_MSG_RESULT(yes)])+#+# Locate bzlib, if wanted+#+if test -n "${bzlib_places}"+then+  # check the user supplied or any other more or less 'standard' place:+  #   Most UNIX systems      : /usr/local and /usr+  #   MacPorts / Fink on OSX : /opt/local respectively /sw+  for B2ZLIB_HOME in ${bzlib_places} ; do+    if test -f "${B2ZLIB_HOME}/include/bzlib.h"; then break; fi+    B2ZLIB_HOME=""+  done++  B2ZLIB_OLD_LDFLAGS=$LDFLAGS+  B2ZLIB_OLD_CPPFLAGS=$CPPFLAGS+  if test -n "${B2ZLIB_HOME}"; then+    LDFLAGS="$LDFLAGS -L${B2ZLIB_HOME}/lib"+    CPPFLAGS="$CPPFLAGS -I${B2ZLIB_HOME}/include"+  fi+  AC_LANG_PUSH([C])+  AC_CHECK_LIB([bz2], [BZ2_bzRead], [bzlib_cv_libbz2=yes], [bzlib_cv_libbz2=no])+  AC_CHECK_HEADER([bzlib.h], [bzlib_cv_bzlib_h=yes], [bzlib_cv_bzlib_h=no])+  AC_LANG_POP([C])+  if test "$bzlib_cv_libbz2" = "yes" && test "$bzlib_cv_bzlib_h" = "yes"+  then+    #+    # If both library and header were found, action-if-found+    #+    m4_ifblank([$1],[+                CPPFLAGS="$CPPFLAGS -I${B2ZLIB_HOME}/include"+                LDFLAGS="$LDFLAGS -L${B2ZLIB_HOME}/lib"+                LIBS="-lbz2 $LIBS"+                AC_DEFINE([HAVE_LIBBZ2], [1],+                          [Define to 1 if you have `bz2' library (-lbz2)])+               ],[+                # Restore variables+                LDFLAGS="$B2ZLIB_OLD_LDFLAGS"+                CPPFLAGS="$B2ZLIB_OLD_CPPFLAGS"+                $1+               ])+  else+    #+    # If either header or library was not found, action-if-not-found+    #+    m4_default([$2],[+                AC_MSG_ERROR([either specify a valid bzlib installation with --with-bzlib=DIR or disable bzlib usage with --without-bzlib])+                ])+  fi+fi+])

m4/ax_check_bzip3lib.m4

new file mode 100644@@ -0,0 +1,135 @@+# SYNOPSIS+#+#   AX_CHECK_BZIP3LIB([action-if-found], [action-if-not-found])+#+# DESCRIPTION+#+#   This macro searches for an installed bzip3 library. If nothing was+#   specified when calling configure, it searches first in /usr/local and+#   then in /usr, /opt/local and /sw. If the --with-bzip3=DIR is specified,+#   it will try to find it in DIR/include/libbz3.h and DIR/lib/libbzip3. If+#   --without-bzip3 is specified, the library is not searched at all.+#+#   If either the header file (libbz3.h) or the library (libbzip3) is not found,+#   shell commands 'action-if-not-found' is run. If 'action-if-not-found' is+#   not specified, the configuration exits on error, asking for a valid bzip3+#   installation directory or --without-bzip3.+#+#   If both header file and library are found, shell commands+#   'action-if-found' is run. If 'action-if-found' is not specified, the+#   default action appends '-I${BZIP3_HOME}/include' to CPFLAGS, appends+#   '-L${BZIP3_HOME}/lib' to LDFLAGS, prepends '-lbzip3' to LIBS, and calls+#   AC_DEFINE(HAVE_LIBBZIP3). You should use autoheader to include a definition+#   for this symbol in a config.h file. Sample usage in a C/C++ source is as+#   follows:+#+#     #ifdef HAVE_LIBBZIP3+#     #include <libbz3.h>+#     #endif /* HAVE_LIBBZIP3 */+#+# LICENSE+#+#   Copyright (c) 2023 Robert van Engelen <engelen@acm.org>+#+#   This program is free software; you can redistribute it and/or modify it+#   under the terms of the GNU General Public License as published by the+#   Free Software Foundation; either version 2 of the License, or (at your+#   option) any later version.+#+#   This program is distributed in the hope that it will be useful, but+#   WITHOUT ANY WARRANTY; without even the implied warranty of+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General+#   Public License for more details.+#+#   You should have received a copy of the GNU General Public License along+#   with this program. If not, see <https://www.gnu.org/licenses/>.+#+#   As a special exception, the respective Autoconf Macro's copyright owner+#   gives unlimited permission to copy, distribute and modify the configure+#   scripts that are the output of Autoconf when processing the Macro. You+#   need not follow the terms of the GNU General Public License when using+#   or distributing such scripts, even though portions of the text of the+#   Macro appear in them. The GNU General Public License (GPL) does govern+#   all other use of the material that constitutes the Autoconf Macro.+#+#   This special exception to the GPL applies to versions of the Autoconf+#   Macro released by the Autoconf Archive. When you make and distribute a+#   modified version of the Autoconf Macro, you may extend this special+#   exception to the GPL to apply to your modified version as well.++#serial 1++AC_DEFUN([AX_CHECK_BZIP3LIB],+#+# Handle user hints+#+[AC_MSG_CHECKING(if bzip3 is wanted)+bzip3_places="/usr/local /usr /opt/homebrew /opt/local /sw"+AC_ARG_WITH([bzip3],+[  --with-bzip3=DIR        root directory path of bzip3 library installation+                          @<:@defaults to /usr/local or /usr if not found in+                          /usr/local@:>@+  --without-bzip3         to disable bzip3 library usage completely],+[if test "$withval" != "no" ; then+  AC_MSG_RESULT(yes)+  if test -d "$withval"+  then+    bzip3_places="$withval $bzip3_places"+  else+    AC_MSG_WARN([Sorry, $withval does not exist, checking usual places])+  fi+else+  bzip3_places=""+  AC_MSG_RESULT(no)+fi],+[AC_MSG_RESULT(yes)])+#+# Locate bzip3 library, if wanted+#+if test -n "${bzip3_places}"+then+  # check the user supplied or any other more or less 'standard' place:+  #   Most UNIX systems      : /usr/local and /usr+  #   MacPorts / Fink on OSX : /opt/local respectively /sw+  for BZIP3_HOME in ${bzip3_places} ; do+    if test -f "${BZIP3_HOME}/include/libbz3.h"; then break; fi+    BZIP3_HOME=""+  done++  BZIP3_OLD_LDFLAGS=$LDFLAGS+  BZIP3_OLD_CPPFLAGS=$CPPFLAGS+  if test -n "${BZIP3_HOME}"; then+    LDFLAGS="$LDFLAGS -L${BZIP3_HOME}/lib"+    CPPFLAGS="$CPPFLAGS -I${BZIP3_HOME}/include"+  fi+  AC_LANG_PUSH([C])+  AC_CHECK_LIB([bzip3], [bz3_new], [bzip3_cv_libbzip3=yes], [bzip3_cv_libbzip3=no])+  AC_CHECK_HEADER([libbz3.h], [bzip3_cv_libbz3_h=yes], [bzip3_cv_libbz3_h=no])+  AC_LANG_POP([C])+  if test "$bzip3_cv_libbzip3" = "yes" && test "$bzip3_cv_libbz3_h" = "yes"+  then+    #+    # If both library and header were found, action-if-found+    #+    m4_ifblank([$1],[+                CPPFLAGS="$CPPFLAGS -I${BZIP3_HOME}/include"+                LDFLAGS="$LDFLAGS -L${BZIP3_HOME}/lib"+                LIBS="-lbzip3 $LIBS"+                AC_DEFINE([HAVE_LIBBZIP3], [1],+                          [Define to 1 if you have `bzip3' library (-lbzip3)])+               ],[+                # Restore variables+                LDFLAGS="$BZLIB_OLD_LDFLAGS"+                CPPFLAGS="$BZLIB_OLD_CPPFLAGS"+                $1+               ])+  else+    #+    # If either header or library was not found, action-if-not-found+    #+    m4_default([$2],[+                AC_MSG_ERROR([either specify a valid bzip3 library installation with --with-bzip3=DIR or disable bzip3 library usage with --without-bzip3])+                ])+  fi+fi+])

m4/ax_check_bzlib.m4

deleted file mode 100644@@ -1,134 +0,0 @@-# SYNOPSIS-#-#   AX_CHECK_BZLIB([action-if-found], [action-if-not-found])-#-# DESCRIPTION-#-#   This macro searches for an installed bzlib/bz2 library. If nothing was-#   specified when calling configure, it searches first in /usr/local and-#   then in /usr, /opt/local and /sw. If the --with-bzlib=DIR is specified,-#   it will try to find it in DIR/include/bzlib.h and DIR/lib/libbz2. If-#   --without-bzlib is specified, the library is not searched at all.-#-#   If either the header file (bzlib.h) or the library (libbz2) is not found,-#   shell commands 'action-if-not-found' is run. If 'action-if-not-found' is-#   not specified, the configuration exits on error, asking for a valid bzlib-#   installation directory or --without-bzlib.-#-#   If both header file and library are found, shell commands-#   'action-if-found' is run. If 'action-if-found' is not specified, the-#   default action appends '-I${BZLIB_HOME}/include' to CPFLAGS, appends-#   '-L${BZLIB_HOME}/lib' to LDFLAGS, prepends '-lbz2' to LIBS, and calls-#   AC_DEFINE(HAVE_LIBBZ2). You should use autoheader to include a definition-#   for this symbol in a config.h file. Sample usage in a C/C++ source is as-#   follows:-#-#     #ifdef HAVE_LIBBZ2-#     #include <bzlib.h>-#     #endif /* HAVE_LIBBZ2 */-#-# LICENSE-#-#   Copyright (c) 2019 Robert van Engelen <engelen@acm.org>-#-#   This program is free software; you can redistribute it and/or modify it-#   under the terms of the GNU General Public License as published by the-#   Free Software Foundation; either version 2 of the License, or (at your-#   option) any later version.-#-#   This program is distributed in the hope that it will be useful, but-#   WITHOUT ANY WARRANTY; without even the implied warranty of-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General-#   Public License for more details.-#-#   You should have received a copy of the GNU General Public License along-#   with this program. If not, see <https://www.gnu.org/licenses/>.-#-#   As a special exception, the respective Autoconf Macro's copyright owner-#   gives unlimited permission to copy, distribute and modify the configure-#   scripts that are the output of Autoconf when processing the Macro. You-#   need not follow the terms of the GNU General Public License when using-#   or distributing such scripts, even though portions of the text of the-#   Macro appear in them. The GNU General Public License (GPL) does govern-#   all other use of the material that constitutes the Autoconf Macro.-#-#   This special exception to the GPL applies to versions of the Autoconf-#   Macro released by the Autoconf Archive. When you make and distribute a-#   modified version of the Autoconf Macro, you may extend this special-#   exception to the GPL to apply to your modified version as well.--#serial 1--AC_DEFUN([AX_CHECK_BZLIB],-#-# Handle user hints-#-[AC_MSG_CHECKING(if bzlib is wanted)-bzlib_places="/usr/local /usr /opt/homebrew /opt/local /sw"-AC_ARG_WITH([bzlib],-[  --with-bzlib=DIR        root directory path of bzlib installation @<:@defaults to-                          /usr/local or /usr if not found in /usr/local@:>@-  --without-bzlib         to disable bzlib usage completely],-[if test "$withval" != "no" ; then-  AC_MSG_RESULT(yes)-  if test -d "$withval"-  then-    bzlib_places="$withval $bzlib_places"-  else-    AC_MSG_WARN([Sorry, $withval does not exist, checking usual places])-  fi-else-  bzlib_places=""-  AC_MSG_RESULT(no)-fi],-[AC_MSG_RESULT(yes)])-#-# Locate bzlib, if wanted-#-if test -n "${bzlib_places}"-then-  # check the user supplied or any other more or less 'standard' place:-  #   Most UNIX systems      : /usr/local and /usr-  #   MacPorts / Fink on OSX : /opt/local respectively /sw-  for BZLIB_HOME in ${bzlib_places} ; do-    if test -f "${BZLIB_HOME}/include/bzlib.h"; then break; fi-    BZLIB_HOME=""-  done--  BZLIB_OLD_LDFLAGS=$LDFLAGS-  BZLIB_OLD_CPPFLAGS=$CPPFLAGS-  if test -n "${BZLIB_HOME}"; then-    LDFLAGS="$LDFLAGS -L${BZLIB_HOME}/lib"-    CPPFLAGS="$CPPFLAGS -I${BZLIB_HOME}/include"-  fi-  AC_LANG_PUSH([C])-  AC_CHECK_LIB([bz2], [BZ2_bzRead], [bzlib_cv_libbz2=yes], [bzlib_cv_libbz2=no])-  AC_CHECK_HEADER([bzlib.h], [bzlib_cv_bzlib_h=yes], [bzlib_cv_bzlib_h=no])-  AC_LANG_POP([C])-  if test "$bzlib_cv_libbz2" = "yes" && test "$bzlib_cv_bzlib_h" = "yes"-  then-    #-    # If both library and header were found, action-if-found-    #-    m4_ifblank([$1],[-                CPPFLAGS="$CPPFLAGS -I${BZLIB_HOME}/include"-                LDFLAGS="$LDFLAGS -L${BZLIB_HOME}/lib"-                LIBS="-lbz2 $LIBS"-                AC_DEFINE([HAVE_LIBBZ2], [1],-                          [Define to 1 if you have `bz2' library (-lbz2)])-               ],[-                # Restore variables-                LDFLAGS="$BZLIB_OLD_LDFLAGS"-                CPPFLAGS="$BZLIB_OLD_CPPFLAGS"-                $1-               ])-  else-    #-    # If either header or library was not found, action-if-not-found-    #-    m4_default([$2],[-                AC_MSG_ERROR([either specify a valid bzlib installation with --with-bzlib=DIR or disable bzlib usage with --without-bzlib])-                ])-  fi-fi-])

man/ugrep.1

@@ -1,4 +1,4 @@-.TH UGREP "1" "November 06, 2023" "ugrep 4.3.2" "User Commands"+.TH UGREP "1" "November 12, 2023" "ugrep 4.3.2" "User Commands" .SH NAME \fBugrep\fR, \fBug\fR -- file pattern searcher .SH SYNOPSIS@@ -904,7 +904,9 @@ Supported compression formats: gzip (.gz), compress (.Z), zip, bzip2 (requires suffix .bz, .bz2, .bzip2, .tbz, .tbz2, .tb2, .tz2), lzma and xz (requires suffix .lzma, .tlz, .xz, .txz), lz4 (requires suffix .lz4),-zstd (requires suffix .zst, .zstd, .tzst).+zstd (requires suffix .zst, .zstd, .tzst),+brotli (requires suffix .br),+bzip3 (requires suffix .bz3). .TP \fB\-\-zmax\fR=\fINUM\fR When used with option \fB\-z\fR (\fB\-\-decompress\fR), searches the contents of

src/Makefile.in

@@ -93,7 +93,8 @@ subdir = src ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_boost_regex.m4 \ 	$(top_srcdir)/m4/ax_check_brotlilib.m4 \-	$(top_srcdir)/m4/ax_check_bzlib.m4 \+	$(top_srcdir)/m4/ax_check_bz2lib.m4 \+	$(top_srcdir)/m4/ax_check_bzip3lib.m4 \ 	$(top_srcdir)/m4/ax_check_lz4lib.m4 \ 	$(top_srcdir)/m4/ax_check_lzmalib.m4 \ 	$(top_srcdir)/m4/ax_check_pcre2.m4 \

src/ugrep.cpp

@@ -49,11 +49,12 @@ Optional libraries to support options -P and -z:    -P: PCRE2 (or Boost.Regex)   -z: zlib (.gz)-  -z: bz2 (.bz, bz2, .bzip2)+  -z: bzip2 (.bz, bz2, .bzip2)   -z: lzma (.lzma, .xz)   -z: lz4 (.lz4)   -z: zstd (.zst, .zstd)   -z: brotli (.br)+  -z: bzip3 (.bz3)  Build ugrep as follows: @@ -124,6 +125,9 @@ After this, you may want to test ugrep and install it (optional): // optionally enable brotli library for -z // #define HAVE_LIBBROTLI +// optionally enable libbzip3 for -z+// #define HAVE_LIBBZIP3+ #include <stringapiset.h>       // internationalization #include <direct.h>             // directory access #include <winsock.h>            // gethostname() for --hyperlink@@ -155,7 +159,7 @@ After this, you may want to test ugrep and install it (optional): // #define Z_BUF_LEN 16384 // #define Z_BUF_LEN 32768 -// use zlib, libbz2, liblzma for option -z+// use zlib, libbz2, liblzma etc for option -z #ifdef HAVE_LIBZ # include "zstream.hpp" #endif@@ -7547,6 +7551,12 @@ void ugrep()     flag_all_include.emplace_back("*.pax.br");     flag_all_include.emplace_back("*.tar.br"); #endif++#ifdef HAVE_LIBBZIP3+    flag_all_include.emplace_back("*.cpio.bz3");+    flag_all_include.emplace_back("*.pax.bz3");+    flag_all_include.emplace_back("*.tar.bz3");+#endif   } #endif #endif@@ -13849,6 +13859,10 @@ void help(std::ostream& out) #ifdef HAVE_LIBBROTLI             ",\n\             brotli (requires suffix .br)"+#endif+#ifdef HAVE_LIBBZIP3+            ",\n\+            bzip3 (requires suffix .bz3)" #endif             ".\n" #endif@@ -14258,6 +14272,9 @@ void version() #ifdef HAVE_LIBBROTLI     ",brotli" << #endif+#ifdef HAVE_LIBBZIP3+    ",bzip3" <<+#endif #endif     "\n"     "License: BSD-3-Clause;  ugrep user guide:  https://ugrep.com\n"

src/zstream.hpp

@@ -47,21 +47,21 @@ // Z decompress z_open(), z_read(), z_close() #include "zopen.h" -// if we have libbz2 (bzip2), otherwise declare incomplete bz_stream+// if we have libbz2 (bzip2), otherwise declare incomplete bz_stream for ZipInfo #ifdef HAVE_LIBBZ2 #include <bzlib.h> #else struct bz_stream; #endif -// if we have liblzma (xz utils), otherwise declare incomplete lzma_stream+// if we have liblzma (xz utils), otherwise declare incomplete lzma_stream for ZipInfo #ifdef HAVE_LIBLZMA #include <lzma.h> #else struct lzma_stream; #endif -// if we have liblz4, otherwise declare incomplete lz4_stream+// if we have liblz4, otherwise declare incomplete lz4_stream for ZipInfo #ifdef HAVE_LIBLZ4 #include <lz4.h> typedef LZ4_streamDecode_t *lz4_stream;@@ -73,7 +73,7 @@ typedef LZ4_streamDecode_t *lz4_stream; struct lz4_stream; #endif -// if we have libzstd, otherwise declare incomplete zstd_stream+// if we have libzstd, otherwise declare incomplete zstd_stream for ZipInfo #ifdef HAVE_LIBZSTD #include <zstd.h> typedef ZSTD_DStream zstd_stream;@@ -86,6 +86,13 @@ struct zstd_stream; #include <brotli/decode.h> #endif +// if we have libbzip3+#ifdef HAVE_LIBBZIP3+extern "C" {+#include <libbz3.h>+}+#endif+ // zip decompression crc check disabled as this is too slow, we should optimize crc32() with a table // use zip crc integrity check at the cost of a significant slow down? // #define WITH_ZIP_CRC32@@ -933,6 +940,12 @@ class zstreambuf : public std::streambuf {     return has_ext(pathname, ".br");   } +  // return true if pathname has a bz3 filename extension+  static bool is_bz3(const char *pathname)+  {+    return has_ext(pathname, ".bz3");+  }+   // return true if pathname has a (tar) compress (Z) filename extension   static bool is_Z(const char *pathname)   {@@ -984,6 +997,7 @@ class zstreambuf : public std::streambuf {       lz4file_(NULL),       zstdfile_(NULL),       brfile_(NULL),+      bz3file_(NULL),       zipinfo_(NULL),       cur_(0),       len_(0)@@ -1001,6 +1015,7 @@ class zstreambuf : public std::streambuf {       lz4file_(NULL),       zstdfile_(NULL),       brfile_(NULL),+      bz3file_(NULL),       zipinfo_(NULL),       cur_(0),       len_(0)@@ -1035,14 +1050,14 @@ class zstreambuf : public std::streambuf {     if (is_bz(pathname))     { #ifdef HAVE_LIBBZ2-      // open bzip2 compressed file+      // open bzip/bzip2 compressed file       try       {         bzfile_ = new BZ();         int ret = BZ2_bzDecompressInit(&bzfile_->strm, 0, 0);         if (ret != BZ_OK)         {-          warning("BZ2_bzDecompressInit error", pathname);+          warning("BZ2_bzDecompressInit failed", pathname);            delete bzfile_;           bzfile_ = NULL;@@ -1070,7 +1085,7 @@ class zstreambuf : public std::streambuf {         lzma_ret ret = lzma_auto_decoder(&xzfile_->strm, UINT64_MAX, LZMA_TELL_UNSUPPORTED_CHECK | LZMA_CONCATENATED);         if (ret != LZMA_OK)         {-          warning("lzma_stream_decoder error", pathname);+          warning("lzma_stream_decoder failed", pathname);            delete xzfile_;           xzfile_ = NULL;@@ -1095,6 +1110,14 @@ class zstreambuf : public std::streambuf {       try       {         lz4file_ = new LZ4();+        if (lz4file_->strm == NULL || lz4file_->buf == NULL || lz4file_->zbuf == NULL)+        {+          warning("LZ4_createStreamDecode failed", pathname);++          delete lz4file_;+          lz4file_ = NULL;+          file_ = NULL;+        }       }        catch (const std::bad_alloc&)@@ -1114,6 +1137,14 @@ class zstreambuf : public std::streambuf {       try       {         zstdfile_ = new ZSTD();+        if (zstdfile_->strm == NULL || zstdfile_->zbuf == NULL)+        {+          warning("ZSTD_createDStream failed", pathname);++          delete zstdfile_;+          zstdfile_ = NULL;+          file_ = NULL;+        }       }        catch (const std::bad_alloc&)@@ -1133,6 +1164,60 @@ class zstreambuf : public std::streambuf {       try       {         brfile_ = new BR();+        if (brfile_->strm == NULL)+        {+          warning("BrotliDecoderCreateInstance failed", pathname);++          delete brfile_;+          brfile_ = NULL;+          file_ = NULL;+        }+      }++      catch (const std::bad_alloc&)+      {+        cannot_decompress(pathname_, "out of memory");+        file_ = NULL;+      }+#else+      cannot_decompress("unsupported compression format", pathname);+      file_ = NULL;+#endif+    }+    else if (is_bz3(pathname))+    {+#ifdef HAVE_LIBBZIP3+      // try to read the compression format magic bytes+      if (fread(buf_, 1, 9, file) < 9 || strncmp(reinterpret_cast<char*>(buf_), "BZ3v1", 5) != 0)+      {+        cannot_decompress(pathname_, "an error was detected in the bzip3 compressed data");+        delete bz3file_;+        bz3file_ = NULL;+        file_ = NULL;+      }++      uint32_t block_size = u32(buf_ + 5);++      if (block_size < 65 * 1024 || block_size > 511 * 1024 * 1024)+      {+        cannot_decompress(pathname_, "an error was detected in the bzip3 compressed data");+        delete bz3file_;+        bz3file_ = NULL;+        file_ = NULL;+      }++      // open bzip3 compressed file+      try+      {+        bz3file_ = new BZ3(block_size);+        if (bz3file_->strm == NULL || bz3file_->buf == NULL)+        {+          warning("bz3_new failed", pathname);++          delete bz3file_;+          bz3file_ = NULL;+          file_ = NULL;+        }       }        catch (const std::bad_alloc&)@@ -1199,7 +1284,7 @@ class zstreambuf : public std::streambuf {         // open compress (Z) compressed file         if ((zzfile_ = z_open(file, "r", 0, 1)) == NULL)         {-          warning("zopen error", pathname);+          warning("zopen failed", pathname);           file_ = NULL;         }       }@@ -1306,6 +1391,13 @@ class zstreambuf : public std::streambuf {       delete brfile_;       brfile_ = NULL;     }+#endif+#ifdef HAVE_LIBBZIP3+    else if (bz3file_ != NULL)+    {+      delete bz3file_;+      bz3file_ = NULL;+    } #endif     else if (zipinfo_ != NULL)     {@@ -1400,7 +1492,7 @@ class zstreambuf : public std::streambuf {  #ifdef HAVE_LIBBZ2 -  // bzip2 decompression state data+  // bzip/bzip2 decompression state data   struct BZ {      BZ()@@ -1538,7 +1630,8 @@ class zstreambuf : public std::streambuf {   struct ZSTD {      ZSTD()-      : strm(ZSTD_createDStream()),+      :+        strm(ZSTD_createDStream()),         zbuf(static_cast<unsigned char*>(malloc(ZSTD_DStreamInSize()))),         zloc(0),         zlen(0),@@ -1577,7 +1670,8 @@ class zstreambuf : public std::streambuf {   struct BR {      BR()-      : strm(BrotliDecoderCreateInstance(NULL, NULL, NULL)),+      :+        strm(BrotliDecoderCreateInstance(NULL, NULL, NULL)),         next_in(NULL),         avail_in(0),         next_out(NULL),@@ -1588,7 +1682,8 @@ class zstreambuf : public std::streambuf {      ~BR()     {-      BrotliDecoderDestroyInstance(strm);+      if (strm != NULL)+        BrotliDecoderDestroyInstance(strm);     }      BrotliDecoderState *strm; // brotli decompression stream state@@ -1610,6 +1705,46 @@ class zstreambuf : public std::streambuf {   // unused brotli file handle   typedef void *brotliFile; +#endif++#ifdef HAVE_LIBBZIP3++  // bzip3 decompression state data+  struct BZ3 {++    BZ3(uint32_t block_size)+      :+        strm(bz3_new(block_size)),+        max(bz3_bound(block_size)),+        buf(static_cast<uint8_t*>(malloc(max))),+        loc(0),+        len(0)+    { }++    ~BZ3()+    {+      if (buf != NULL)+        free(buf);+      if (strm != NULL)+        bz3_free(strm);+    }++    bz3_state *strm;+    uint32_t   max;+    uint8_t   *buf;+    uint32_t   loc;+    uint32_t   len;++  };+  +  // bzip3 file handle+  typedef struct BZ3 *bz3File;++#else++  // unused bzip3 file handle+  typedef void *bz3File;+ #endif    // fetch and decompress the next block of data into buf[0..len-1], return number of bytes decompressed, zero on EOF or negative on error@@ -2219,7 +2354,7 @@ class zstreambuf : public std::streambuf {       {         BrotliDecoderResult ret = BROTLI_DECODER_RESULT_SUCCESS; -        // decompress non-empty brfile_->zbuf[] into the given buf[]+        // decompress non-empty brfile_->zbuf[] into the given buf[], strange we can't limit this to brfile_->avail_in > 0         if (brfile_->avail_out == 0)         {           brfile_->next_out  = buf;@@ -2291,6 +2426,63 @@ class zstreambuf : public std::streambuf {         break;       }     }+#endif+#ifdef HAVE_LIBBZIP3+    else if (bz3file_ != NULL)+    {+      while (bz3file_->loc >= bz3file_->len)+      {+        // read decompressed and compressed size+        if (fread(bz3file_->buf, 1, 8, file_) < 8)+        {+          if (ferror(file_))+          {+            warning("cannot read", pathname_);+            num = -1;+          }++          break;+        }++        // compressed ("new") size+        uint32_t block_size = u32(bz3file_->buf);++        // decompressed ("old") size+        bz3file_->len = u32(bz3file_->buf + 4);+        bz3file_->loc = 0;++        if (block_size > bz3file_->max ||+            bz3file_->len > bz3file_->max ||+            fread(bz3file_->buf, 1, block_size, file_) < block_size ||+            bz3_decode_block(bz3file_->strm, bz3file_->buf, block_size, bz3file_->len) < 0)+        {+          if (ferror(file_))+            warning("cannot read", pathname_);+          else+            cannot_decompress(pathname_, "an error was detected in the bzip3 compressed data");++          num = -1;++          break;+        }+      }++      // if all OK then copy the next part of the decompressed block into buf[]+      if (num != -1 && bz3file_->loc < bz3file_->len)+      {+        num = bz3file_->len - bz3file_->loc;+        if (num > static_cast<std::streamsize>(len))+          num = len;+        memcpy(buf, bz3file_->buf + bz3file_->loc, num);+        bz3file_->loc += num;+      }+      else if (num <= 0)+      {+        delete bz3file_;+        bz3file_ = NULL;+        file_ = NULL;+      }+    } #endif     else if (zipinfo_ != NULL)     {@@ -2398,11 +2590,12 @@ class zstreambuf : public std::streambuf {   FILE           *file_;           // the compressed file   zFile           zfile_;          // zlib file handle   zzFile          zzfile_;         // compress (Z) file handle-  bzFile          bzfile_;         // bzip2 file handle+  bzFile          bzfile_;         // bzip/bzip2 file handle   xzFile          xzfile_;         // xz/lzma file handle   lz4File         lz4file_;        // lz4 file handle   zstdFile        zstdfile_;       // zstd file handle   brotliFile      brfile_;         // brotli file handle+  bz3File         bz3file_;        // bzip3 file handle   ZipInfo        *zipinfo_;        // zip file and zip info handle   unsigned char   buf_[Z_BUF_LEN]; // buffer with decompressed stream data   std::streamsize cur_;            // current position in buffer to read the stream data, less or equal to len_

tests/archive.tar.bz3

new file mode 100644Binary file changed

tests/gen.sh

@@ -152,6 +152,7 @@ xz     -9 -c archive.tar > archive.txz lz4    -9 -c archive.tar > archive.tar.lz4 zstd   -9 -c archive.tar > archive.tzst brotli -9 -c archive.tar > archive.tar.br+bzip3     -c archive.tar > archive.tar.bz3 zip    -9 -q archive.tar.zip archive.tar zip    -9 -q archive.zip $FILES @@ -171,6 +172,7 @@ $UG -z -c Hello archive.txz     > out/archive.txz.out $UG -z -c Hello archive.tar.lz4 > out/archive.tar.lz4.out $UG -z -c Hello archive.tzst    > out/archive.tzst.out $UG -z -c Hello archive.tar.br  > out/archive.tar.br.out+$UG -z -c Hello archive.tar.bz3 > out/archive.tar.bz3.out  $UG -z -c -tShell Hello archive.cpio    > out/archive-t.cpio.out $UG -z -c -tShell Hello archive.pax     > out/archive-t.pax.out@@ -185,6 +187,7 @@ $UG -z -c -tShell Hello archive.txz     > out/archive-t.txz.out $UG -z -c -tShell Hello archive.tar.lz4 > out/archive-t.tar.lz4.out $UG -z -c -tShell Hello archive.tzst    > out/archive-t.tzst.out $UG -z -c -tShell Hello archive.tar.br  > out/archive-t.tar.br.out+$UG -z -c -tShell Hello archive.tar.bz3 > out/archive-t.tar.bz3.out  $UG --zmax=2 -z -c Hello archive2.tgz         > out/archive2.tgz.out $UG --zmax=3 -z -c Hello archive3.tgz         > out/archive3.tgz.out

tests/out/archive-t.tar.bz3.out

new file mode 100644@@ -0,0 +1,2 @@+archive.tar.bz3{Hello.bat}:1+archive.tar.bz3{Hello.sh}:1

tests/out/archive.tar.bz3.out

new file mode 100644@@ -0,0 +1,8 @@+archive.tar.bz3{Hello.bat}:1+archive.tar.bz3{Hello.class}:1+archive.tar.bz3{Hello.java}:2+archive.tar.bz3{Hello.pdf}:1+archive.tar.bz3{Hello.sh}:1+archive.tar.bz3{Hello.txt}:1+archive.tar.bz3{empty.txt}:0+archive.tar.bz3{emptyline.txt}:0

tests/verify.sh

@@ -88,6 +88,14 @@ fi  printf "Have libbrotli? %3s (optional)\n" $have_libbrotli +if $UG -Fq 'HAVE_LIBBZIP3 1' "$CONFIGH" ; then+  have_libbzip3=yes+else+  have_libbzip3=no+fi++printf "Have libbzip3?  %3s (optional)\n" $have_libbzip3+ export GREP_COLORS='cx=hb:ms=hug:mc=ib+W:fn=h35:ln=32h:cn=1;32:bn=1;32:se=+36'  function ERR() {@@ -378,6 +386,10 @@ if [ "$have_libbrotli" == yes ]; then printf . $UG -z -c Hello archive.tar.br  | $DIFF out/archive.tar.br.out  || ERR "-z -c Hello archive.tar.br" fi+if [ "$have_libbzip3" == yes ]; then+printf .+$UG -z -c Hello archive.tar.bz3 | $DIFF out/archive.tar.bz3.out || ERR "-z -c Hello archive.tar.bz3"+fi fi  if [ "$have_libz" == yes ]; then@@ -417,6 +429,10 @@ if [ "$have_libbrotli" == yes ]; then printf . $UG -z -c -tShell Hello archive.tar.br  | $DIFF out/archive-t.tar.br.out  || ERR "-z -c -tShell Hello archive.tar.br" fi+if [ "$have_libbzip3" == yes ]; then+printf .+$UG -z -c -tShell Hello archive.tar.bz3 | $DIFF out/archive-t.tar.bz3.out || ERR "-z -c -tShell Hello archive.tar.bz3"+fi fi  if [ "$have_libz" == yes ]; then