Imported Upstream version 0.99 upstream/0.99
authorAnas Nashif <anas.nashif@intel.com>
Sun, 4 Nov 2012 20:13:45 +0000 (12:13 -0800)
committerAnas Nashif <anas.nashif@intel.com>
Sun, 4 Nov 2012 20:13:45 +0000 (12:13 -0800)
12 files changed:
COPYING [new file with mode: 0644]
Makefile [new file with mode: 0644]
README [new file with mode: 0644]
fzopen.3.in [new file with mode: 0644]
lzw.h [new file with mode: 0644]
tests.c [new file with mode: 0644]
testt.c [new file with mode: 0644]
unlzw.c [new file with mode: 0644]
zio.c [new file with mode: 0644]
zio.h.in [new file with mode: 0644]
zio.map [new file with mode: 0644]
zioP.h [new file with mode: 0644]

diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..60549be
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    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, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..604b655
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,133 @@
+#
+# Makefile for compiling libzio
+#
+# Author: Werner Fink, <werner@suse.de>
+#
+
+LARGE  = $(shell getconf LFS_CFLAGS)
+CFLAGS = $(RPM_OPT_FLAGS) -pipe -Wall -D_GNU_SOURCE -D_REENTRANT $(LARGE)
+CC     = gcc
+MAJOR  = 0
+MINOR  = 99
+VERSION        = $(MAJOR).$(MINOR)
+SONAME = libzio.so.$(MAJOR)
+LDMAP  = -Wl,--version-script=zio.map
+
+prefix = /usr
+libdir = $(prefix)/lib
+datadir        = $(prefix)/share
+mandir = $(datadir)/man
+incdir = $(prefix)/include
+
+FILES  = README        \
+         COPYING       \
+         Makefile      \
+         zio.c         \
+         zioP.h        \
+         zio.h.in      \
+         testt.c       \
+         tests.c       \
+         lzw.h         \
+         unlzw.c       \
+         zio.map       \
+         fzopen.3.in
+
+### Includes and Defines (add further entries here):
+
+cc-include = $(shell $(CC) $(INCLUDES) -include $(1) -S -o /dev/null -xc /dev/null > /dev/null 2>&1 && echo "-D$(2)")
+cc-library = $(shell echo 'int main () { return 0; }' |$(CC) -l$(1:lib%=%) -o /dev/null -xc - > /dev/null 2>&1 && echo yes)
+cc-function = $(shell echo 'extern void $(1)(void); int main () { $(1)(); return 0; }' |$(CC) -o /dev/null -xc - > /dev/null 2>&1 && echo "-D$(2)")
+
+CFLAGS += $(call cc-include,libio.h,HAVE_LIBIO_H)
+CFLAGS += $(call cc-function,fopencookie,HAVE_FOPENCOOKIE)
+CFLAGS += $(call cc-function,funopen,HAVE_FUNOPEN)
+
+CFLAGS += $(call cc-include,zlib.h,HAS_ZLIB_H)
+CFLAGS += $(call cc-include,bzlib.h,HAS_BZLIB_H)
+CFLAGS += $(call cc-include,lzmadec.h,HAS_LZMADEC_H)
+CFLAGS += $(call cc-include,lzma.h,HAS_LZMA_H)
+
+LIBS  = -lz
+ifeq ($(call cc-library,libbz2),yes)
+ LIBS += -lbz2
+endif
+ifeq ($(call cc-library,liblzma),yes)
+ LIBS += -llzma
+else
+ifeq ($(call cc-library,lzmadec),yes)
+ LIBS += -llzmadec
+endif
+endif
+
+all: shared static
+noweak: CFLAGS += -DNO_WEAK
+noweak: LINK += $(LIBS)
+noweak: all
+shared:        libzio.so.$(VERSION) zio.map
+static:        libzio.a
+
+obj/zio.o: zio.c zioP.h zio.h
+       test -d obj/ || mkdir obj/
+       $(CC) $(CFLAGS) -o $@ -c $<
+
+obs/zio.o: zio.c zioP.h zio.h
+       test -d obs/ || mkdir obs/
+       $(CC) $(CFLAGS) -fPIC -o $@ -c $<
+
+obj/unlzw.o: unlzw.c lzw.h
+       test -d obj/ || mkdir obj/
+       $(CC) $(CFLAGS) -funroll-loops -o $@ -c $<
+
+obs/unlzw.o: unlzw.c lzw.h
+       test -d obs/ || mkdir obs/
+       $(CC) $(CFLAGS) -fPIC -o $@ -c $<
+
+libzio.a: obj/zio.o obj/unlzw.o
+       ar -rv $@ $^
+       ranlib $@
+
+libzio.so.$(VERSION): obs/zio.o obs/unlzw.o
+       gcc -shared -Wl,-soname,$(SONAME),-stats $(LDMAP) -o $@ $^ $(LINK)
+
+zioP.h: /usr/include/bzlib.h /usr/include/zlib.h
+zio.h:  zio.h.in /usr/include/stdio.h
+       sed 's/@@VERSION@@/$(VERSION)/' < $< > $@
+fzopen.3: fzopen.3.in
+       sed 's/@@VERSION@@/$(VERSION)/' < $< > $@
+
+unlzw.c: lzw.h
+
+install: install-shared install-static install-data
+
+install-shared: libzio.so.$(VERSION)
+       mkdir -p $(DESTDIR)$(libdir)
+       install -m 0755 libzio.so.$(VERSION) $(DESTDIR)$(libdir)/
+       ln -sf libzio.so.$(VERSION)          $(DESTDIR)$(libdir)/libzio.so.$(MAJOR)
+       ln -sf libzio.so.$(MAJOR)            $(DESTDIR)$(libdir)/libzio.so
+
+install-static: libzio.a
+       mkdir -p $(DESTDIR)$(libdir)
+       install -m 0644 libzio.a             $(DESTDIR)$(libdir)/
+
+install-data: zio.h fzopen.3
+       mkdir -p $(DESTDIR)$(incdir)
+       mkdir -p $(DESTDIR)$(mandir)/man3
+       install -m 0644 zio.h                $(DESTDIR)$(incdir)/
+       install -m 0644 fzopen.3             $(DESTDIR)$(mandir)/man3/
+
+clean:
+       rm -f *.a *.so* testt tests zio.h
+       rm -rf obj/ obs/
+       rm -f libzio-$(VERSION).tar.gz
+
+dest:   clean
+       mkdir libzio-$(VERSION)
+       cp -p $(FILES) libzio-$(VERSION)/
+       tar czf libzio-$(VERSION).tar.gz libzio-$(VERSION)/
+       rm -rf libzio-$(VERSION)/
+
+testt:  testt.c libzio.a
+       $(CC) $(CFLAGS) -o $@ $^ $(LIBS)
+
+tests:  tests.c libzio.a
+       $(CC) $(CFLAGS) -o $@ $^ $(LIBS)
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..b53999c
--- /dev/null
+++ b/README
@@ -0,0 +1,50 @@
+   Wrapper for reading or writing gzip/bzip2 files
+   ===============================================
+
+This small lib provides with the help of the fopencookie(3)
+interface of the glibc together with the zlib and libbzip2
+an simple interface for reading or writing gzip/bzip2 files
+with streams. Beside handling gzip files and bzip2 files,
+the libzio provides support for reading ``.Z'' compressed
+files. By using the GNUC compiler weak facility one or both
+libraries, zlib or libbzip2, can be skipped at linkage time.
+
+To use this e.g. an
+
+  #include <zio.h>
+
+and
+
+  FILE * file = fzopen("myfile.gz", "r");
+
+or
+
+  int fd = open("myfile.gz", O_RDONLY);
+  FILE * file = fdzopen(fd, "r", "g");
+
+together with linking the resulting program with -lzio _and_
+`-lz'.  For bzip2 files clearly the libbz2 with `-lbz2' has
+to used at linkage time.
+
+The zlib and/or libbzip2 librares are required because the
+libzio is not linked with `-lz' nor with `-lbz2'.  If the
+appropriate library functions of libz or libbz2 are not found
+the fzopen(3) function returns NULL and the errno is set to
+the value ENOSYS for not implemented.
+
+As the libbzip2 does not provide a function for seeking in
+a bzip2 file, any call of fseek(3) on the open stream will
+fail and set the errno to ESPIPE.
+
+For writing gzip/bzip2 files, fzopen(3) only supports the
+suffixes ``.z'' and ``.gz'' for gzipped files and ``.bz2''
+for bzip2ed files.
+
+On reading first the appropriate suffixes are checked if not
+provided. If no file is found the magic byte sequence at the
+beginning of the file is checked to detect which type of
+compressing is used for the file.
+
+Happy (un)compressing,
+
+     Werner Fink
diff --git a/fzopen.3.in b/fzopen.3.in
new file mode 100644 (file)
index 0000000..72829a9
--- /dev/null
@@ -0,0 +1,342 @@
+'\" t -*- coding: UTF-8 -*-
+.\"
+.\" Copyright 2004 Werner Fink, 2004 SuSE LINUX AG, Germany.
+.\" Copyright 2006 Werner Fink, 2006 SuSE Products GmbH, Germany.
+.\" Copyright 2008 Werner Fink, 2008 SuSE Products GmbH, Germany.
+.\" Copyright 2009 Werner Fink, 2009 SuSE Products GmbH, Germany.
+.\"
+.\" 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.
+.\"
+.TH fzopen 3 "Apr 20, 2006" "Version @@VERSION@@" " Linux Programmer's Manual"
+.UC 3
+.OS SuSE Linux
+.SH NAME
+fzopen \- stream open functions on compressed files
+.br
+fdzopen \- stream open functions on compressed files
+.SH SYNOPSIS
+.\"
+.B #include <zio.h>
+.sp
+.BI "FILE *fzopen (const char *" path ", const char *" mode );
+.br
+.BI "FILE *fdzopen (int " fildes ", const char *" mode ", const char *" what );
+.SH DESCRIPTION
+The
+.B fzopen
+function opens the compressed file whose name is the string to by
+.I path
+and associates a stream with it.
+The
+.B fdopen
+function associates a stream for the existing files descriptor
+.I fildes
+for a compressed file.
+.PP
+The argument
+.I mode
+points to a string beginning with one of the following sequences
+(Additional characters may  follow these sequences.):
+.TP
+.B r
+Open compressed text file for reading.  The stream is positioned
+at the beginning of the file.
+.TP
+.B w
+Truncate file to zero length or create compressed text file for writing.
+The stream is positioned at the beginning of the file.
+.TP
+.BR w1 - 9
+Just like above but provides also the compression level.
+.PP
+The argument
+.I what
+of the function
+.B fdzopen
+specifies the underlying compression method which should be used:
+.TP
+.BR g , z
+The file descriptor points to a gziped file.
+.TP
+.BR b
+The file descriptor points to a bzip2ed file.
+.TP
+.BR l
+The file descriptor points to a lzma2ed file.
+.TP
+.BR Z
+The file descriptor points to a file in LZW format.
+.PP
+Note that
+.B fzopen
+and
+.B fdzopen
+can only open a compressed text file for reading
+.B or
+writing, but
+.IR both ,
+which means that the
+.B +
+is not possible.  Nor can any compressed text file open for appending,
+which makes
+.B a
+not usable with
+.BR fzopen .
+.\"
+.SH NOTE
+The program using libzio with
+.B -lzio
+at linking time should also be linked with
+the appropriate library for accessing compressed
+text files.  This is the libz with
+.B -lz
+for accessing gziped text files and/or with
+.B -lbz2
+for accessing bzip2ed text files.
+.PP
+For writing gzip/bzip2 files,
+.B fzopen
+only supports the suffixes
+.IR .z " and ".gz
+for gzipped files and
+.I .bz2
+for bzip2ed files. All supported formats can be found in
+the following table:
+.IP
+.TS H
+allbox;
+c  l l l l l
+rb l l l l l.
+       fread   fwrite  fseek   suffix  library
+gzip   yes     yes     yes     .gz     -lz
+bzip2  yes     yes     yes     .bz2    -lbz2
+LZW    yes     no      yes     .Z       builtin
+lzma   yes     yes(no) yes     .lzma   -llzma (-llzmadec)
+xz     yes     yes     yes     .xz     -llzma
+.TE
+.PP
+.PP
+On reading first the appropriate suffixes are checked
+if not provided. If no file is found the magic
+byte sequence at the beginning of the file is checked
+to detect a gzip or bzip2 file.
+.PP
+.\"
+.SH CONFIGURATION
+With the help of
+.BR autoconf (1)
+or
+.BR autoreconf (1)
+and a few lines in the common file
+.B configure.in
+or
+.B configure.ac
+found in many source packages a programmer or maintainer
+can extend the automatic configuration to find the
+appropriate libraries together with the libzio:
+.PP
+.IP
+.nf
+AC_CHECK_HEADER(zio.h, [
+  AC_CHECK_LIB(zio, fzopen, [
+    AC_CHECK_LIB(zio, fdzopen, [LIBS="$LIBS -l$zio"; am_cv_libzio=yes])
+  ])
+])
+if test "$am_cv_libzio" = yes; then
+  am_cv_libzio=with
+  AC_DEFINE(HAVE_ZIO, 1, [Define if you have libzio for opening compressed files.])
+  AC_CHECK_HEADER(zlib.h, [
+    for lib in z gz; do
+      AC_CHECK_LIB($lib, gzopen, [
+        LIBS="$LIBS -l$lib"
+        am_cv_libzio="$am_cv_libzio lib$lib"
+        break
+      ])
+    done
+  ])
+  AC_CHECK_HEADER(bzlib.h, [
+    for lib in bz2 bzip2; do
+      AC_CHECK_LIB($lib, BZ2_bzopen, [
+        LIBS="$LIBS -l$lib"
+        am_cv_libzio="$am_cv_libzio lib$lib"
+        break
+      ])
+    done
+  ])
+  AC_CHECK_HEADER(lzmadec.h, [
+    for lib in libzma lzmadec; do
+      AC_CHECK_LIB($lib, lzmadec_open, [
+        LIBS="$LIBS -l$lib"
+        am_cv_libzio="$am_cv_libzio lib$lib"
+        break
+      ])
+    done
+  ])
+  AC_MSG_NOTICE([libzio is used [$]am_cv_libzio])
+fi
+.fi
+.PP
+combined with two lines in the common file
+.B config.h.in
+like
+.PP
+.RS 1c
+.nf
+/* Define to 1 if you have libzio for opening compressed files */
+#undef HAVE_ZIO
+.fi
+.RE
+.PP
+(automatically added by
+.BR autoreconf (1))
+it is easy to use the
+.BR cpp (1)
+macro
+.I HAVE_ZIO
+for the usage of
+.B fzopen
+instead of
+.BR fopen (3).
+.PP
+.\"
+.SH RETURN VALUES
+Upon  successful  completion
+.B fzopen
+return a
+.B FILE
+pointer. Otherwise,
+.B NULL
+is returned and the global variable errno is set to
+indicate the error.
+.\"
+.SH ERRORS
+.TP
+.B EINVAL
+The
+.I mode
+provided to
+.B fzopen
+was invalid.
+.TP
+.B ENOSYS
+The program using
+.B fzopen
+is not linked with the appropriate library
+.RB ( -lz
+for gziped files and
+.B -lbz2
+for bzip2ed files.)
+.TP
+.B ENOTSUP
+The program using
+.B fzopen
+has specified a wrong mode for a
+.B .bz2
+files
+or has opened a
+.B .Z
+file for writing.
+.TP
+.B ENOMEM
+The call of the library functions of the
+.B libz
+or
+.B libbz2
+fails due failed memory allocation.
+.TP
+.B ESPIPE
+This happens if
+.BR fseek (3)
+is used in the case of seesking files is not
+supported.
+.\"
+.SH WARNINGS
+The functions
+.BR fileno (3)
+or
+.BR freopen (3)
+may not be applied on streams opened by
+.BR fzopen .
+An further explanation will be found in section
+.BR BUGS .
+.\"
+.SH BUGS
+.B Fzopen
+can not seek within
+.I bzip2
+files due to the fact that the
+.B libbz2
+does not provide a function like
+.I libz
+does with
+.BR gzseek .
+.B .Z
+compressed file will be opened by
+.B fzopen
+and
+.B fzdopen
+only for reading.  Also a seek
+is not possible for
+.B .Z
+files.
+.B .lzma
+compressed file will be opened by
+.B fzopen
+and
+.B fzdopen
+only for reading as the liblzmadec only
+supports reading.
+As the
+.B fzopen
+and
+.B fdzopen
+are custom-made streams created with the help of
+.BR fopencookie (3)
+function of the
+.B glibc
+or
+.BR funopen (3)
+known from BSD Systems
+it is not possible to use the file descriptor with e.g.
+.BR fileno (3)
+in combination with system calls like
+.BR read (2)
+as this will evade the underlying read/write
+functions of the e.g.
+.BR libz .
+.SH FILES
+.\"
+.BR /usr/include/zio.h
+.SH SEE ALSO
+.BR fopen (3),
+.br
+.BR fopencookie (3)
+.br
+.BR funopen (3)
+.br
+.BR gzip (1),
+.br
+.BR bzip2 (1),
+.br
+.BR lzma (1),
+.br
+.BR xz (1),
+.br
+.BR /usr/include/zlib.h ,
+.br
+.BR /usr/include/bzlib.h .
+.br
+.BR /usr/include/lzma.h .
+.br
+.BR /usr/include/lzmadec.h .
+.SH COPYRIGHT
+2004 Werner Fink,
+2004 SuSE LINUX AG Nuernberg, Germany.
+.br
+2006,2008,2009 Werner Fink,
+2006,2008,2009 SuSE Products GmbH, Germany.
+.SH AUTHOR
+Werner Fink <werner@suse.de>
diff --git a/lzw.h b/lzw.h
new file mode 100644 (file)
index 0000000..f1251f3
--- /dev/null
+++ b/lzw.h
@@ -0,0 +1,123 @@
+/* lzw.h -- define the lzw functions.
+
+   Copyright (C) 1992-1993 Jean-loup Gailly.
+
+   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, 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, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+#ifndef BITS
+#  define BITS 16
+#endif
+#define INIT_BITS 9              /* Initial number of bits per code */
+
+#define        LZW_MAGIC  "\037\235"   /* Magic header for lzw files, 1F 9D */
+
+#define BIT_MASK    0x1f /* Mask for 'number of compression bits' */
+/* Mask 0x20 is reserved to mean a fourth header byte, and 0x40 is free.
+ * It's a pity that old uncompress does not check bit 0x20. That makes
+ * extension of the format actually undesirable because old compress
+ * would just crash on the new format instead of giving a meaningful
+ * error message. It does check the number of bits, but it's more
+ * helpful to say "unsupported format, get a new version" than
+ * "can only handle 16 bits".
+ */
+
+#define BLOCK_MODE  0x80
+/* Block compression: if table is full and compression rate is dropping,
+ * clear the dictionary.
+ */
+
+#define LZW_RESERVED 0x60 /* reserved bits */
+
+#define        CLEAR  256       /* flush the dictionary */
+#define FIRST  (CLEAR+1) /* first free entry */
+
+#include <stdint.h>
+#include <ucontext.h>
+#include "zioP.h"
+
+#if defined _REENTRANT || defined _THREAD_SAFE
+# include <pthread.h>
+weak_symbol(pthread_sigmask);
+#endif
+
+__extension__
+static __inline__ int sigucmask(int how, const sigset_t * __restrict set, sigset_t * __restrict oset)
+{
+#if defined _REENTRANT || defined _THREAD_SAFE
+    if (&pthread_sigmask)
+       return pthread_sigmask(how, set, oset);
+    else
+#endif
+    return sigprocmask(how, set, oset);
+}
+
+#if defined(__ia64__) && defined(uc_sigmask)   /* Broken header sys/ucontext.h -> bits/sigcontext.h */
+__extension__
+static __inline__ unsigned long int sig_ia64_mask(const sigset_t set)
+{
+    unsigned long int mask = 0;
+    int cnt = (8 * sizeof(unsigned long int));
+    if (cnt > NSIG) cnt = NSIG;
+    while (--cnt >= 0) {
+       if (!sigismember(&set, cnt))
+           continue;
+       mask |= (1 << (cnt - 1));               /* sigmask() macro is is not usable for BSD way */
+    }
+    return mask;
+}
+#endif
+
+typedef struct _LZW_s {
+    uint8_t  *inbuf;
+    uint8_t  *outbuf;
+    uint16_t *d_buf;
+    uint8_t  *tab_suffix;
+    uint16_t *tab_prefix;
+    uint8_t  *transfer;
+    off_t     bytes_in;
+    off_t     bytes_out;
+    size_t    insize;
+    size_t    inptr;
+    size_t    outpos;
+    size_t    tcount;
+    ssize_t   tsize;
+    ssize_t   rsize;
+    struct unlzw_s {
+       uint8_t *stackp;
+       int32_t  code;
+       int      finchar;
+       int32_t  oldcode;
+       int32_t  incode;
+       uint32_t inbits;
+       uint32_t posbits;
+       uint32_t bitmask;
+       int32_t  free_ent;
+       int32_t  maxcode;
+       int32_t  maxmaxcode;
+       off_t    newdif;
+       int      n_bits;
+       int      block_mode;
+       int      maxbits;
+    } n;
+    int ifd;
+    char *ifname;
+    ucontext_t *uc;
+    uint8_t *stack;
+} LZW_t;
+
+extern LZW_t *openlzw(const char * __restrict, const char * __restrict);
+extern LZW_t *dopenlzw(int fildes, const char * __restrict);
+extern ssize_t readlzw(LZW_t * __restrict, char * __restrict, const size_t);
+extern void closelzw(LZW_t * __restrict);
diff --git a/tests.c b/tests.c
new file mode 100644 (file)
index 0000000..7512573
--- /dev/null
+++ b/tests.c
@@ -0,0 +1,28 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include "zio.h"
+
+int main(int argc, char *argv[])
+{
+    FILE *file;
+    char line[1024];
+    size_t len;
+
+    if (!(file = fdzopen(fileno(stdin), "r", argc > 1 ? argv[1] : "g"))) {
+       fprintf(stderr, "%s\n", strerror(errno));
+       return 1;
+    }
+
+    while ((len = fread(line, sizeof(char), sizeof (line), file))) {
+       size_t ret = fwrite(line, sizeof(char), len, stdout);
+       if ((ret != len) && ferror(stdout)) {
+           clearerr(stdout);
+       }
+    }
+
+    fclose(file);
+
+    return 0;
+}
diff --git a/testt.c b/testt.c
new file mode 100644 (file)
index 0000000..e64885d
--- /dev/null
+++ b/testt.c
@@ -0,0 +1,33 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include "zio.h"
+
+int main(int argc, char *argv[])
+{
+    while (argc > 1) {
+       FILE *file;
+       char line[1024];
+       size_t len;
+
+       argv++;
+       argc--;
+
+       if (!(file = fzopen(*argv, "r"))) {
+           fprintf(stderr, "%s\n", strerror(errno));
+           continue;
+       }
+
+       while ((len = fread(line, sizeof(char), sizeof (line), file))) {
+           size_t ret = fwrite(line, sizeof(char), len, stdout);
+           if ((ret != len) && ferror(stdout)) {
+               clearerr(stdout);
+           }
+       }
+
+       fclose(file);
+    }
+
+    return 0;
+}
diff --git a/unlzw.c b/unlzw.c
new file mode 100644 (file)
index 0000000..1741803
--- /dev/null
+++ b/unlzw.c
@@ -0,0 +1,464 @@
+/* unlzw.c -- decompress files in LZW format.
+ * The code in this file is directly derived from the public domain 'compress'
+ * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
+ * Ken Turkowski, Dave Mack and Peter Jannesen.
+ *
+ * This is a temporary version which will be rewritten in some future version
+ * to accommodate in-memory decompression.
+ *
+ * Tue Dec 12 17:54:07 CET 2006 - werner@suse.de
+ * Be able to emulate a zlib-like behaviour: open, read, and close .Z files
+ * in memory. I'm using context switchting and a global allocated structure
+ * to be able to read during the main loop in unlzw() does its work. For this
+ * nearly _all_ variables affected by the context switch are forward to this
+ * structure, even the stack and the context type its self.
+ * The oringal source was adopted from the gzip version 1.3.7.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#define DIST_BUFSIZE   0x2000
+#define INBUFSIZ       0x2000
+#define WSIZE          0x2000
+#define INBUF_EXTRA    0x40
+#define OUTBUFSIZ      0x2000
+#define OUTBUF_EXTRA   0x800
+#define STACK_SIZE     0x1000
+
+#include "lzw.h"
+
+static void unlzw(LZW_t *in);
+
+/* ===========================================================================
+ * Fill the input buffer. This is called only when the buffer is empty.
+ * Adopted from gzip version 1.3.7 util.c
+ */
+__extension__
+static __inline__ int fill_inbuf(LZW_t *in)
+{
+    /* Read as much as possible */
+    in->insize = 0;
+    do {
+       ssize_t len = read(in->ifd, in->inbuf + in->insize, INBUFSIZ - in->insize);
+       if (len < 0) {
+           if (errno == EINTR)
+               continue;
+           perror(__FUNCTION__);
+           break;
+       }
+       if (len == 0)
+           break;
+       in->insize += len;
+    } while (in->insize < INBUFSIZ);
+
+    if (in->insize == 0)
+       return EOF;
+
+    in->bytes_in += (off_t)in->insize;
+    in->inptr = 1;
+    return (in->inbuf)[0];
+}
+
+/* ===========================================================================
+ * Does the same as write(), but also handles partial pipe writes and checks
+ * for error return.
+ * Adopted from gzip version 1.3.7 util.c
+ * Note that this version uses context switching, switch back to old context.
+ */
+__extension__
+static __inline__ void write_buf(LZW_t *in, const unsigned char* buf, size_t cnt)
+{
+    do {
+       if ((in->tsize = (in->tcount > cnt) ? cnt : in->tcount)) {
+           (void)memcpy(in->transfer, buf, in->tsize);
+           buf += in->tsize;
+           cnt -= in->tsize;
+       }
+       swapcontext(&in->uc[1], &in->uc[0]);
+    } while (cnt);
+}
+
+#define get_byte(in)   ((in)->inptr < (in)->insize ? (in)->inbuf[(in)->inptr++] : fill_inbuf((in)))
+#define memzero(s,n)   memset ((void*)(s), 0, (n))
+
+#define MAXCODE(n)     (1L << (n))
+
+#ifndef        BYTEORDER
+#      define  BYTEORDER       0000
+#endif
+
+#ifndef        NOALLIGN
+#      define  NOALLIGN        0
+#endif
+
+
+union  bytes {
+    long  word;
+    struct {
+#if BYTEORDER == 4321
+       uint8_t b1;
+       uint8_t b2;
+       uint8_t b3;
+       uint8_t b4;
+#else
+#if BYTEORDER == 1234
+       uint8_t b4;
+       uint8_t b3;
+       uint8_t b2;
+       uint8_t b1;
+#else
+#      undef   BYTEORDER
+       int  dummy;
+#endif
+#endif
+    } bytes;
+};
+
+#if BYTEORDER == 4321 && NOALLIGN == 1
+#  define input(b,o,c,n,m){ \
+     (c) = (*(uint32_t *)(&(b)[(o)>>3])>>((o)&0x7))&(m); \
+     (o) += (n); \
+   }
+#else
+#  define input(b,o,c,n,m){ \
+     uint8_t *p = &(b)[(o)>>3]; \
+     (c) = ((((long)(p[0]))|((long)(p[1])<<8)| \
+     ((long)(p[2])<<16))>>((o)&0x7))&(m); \
+     (o) += (n); \
+   }
+#endif
+
+#define tab_prefixof(i)                in->tab_prefix[i]
+#define clear_tab_prefixof(in) memzero((in)->tab_prefix, sizeof(unsigned short)*(1<<(BITS)));
+#define de_stack               ((uint8_t *)(&in->d_buf[DIST_BUFSIZE-1]))
+#define tab_suffixof(i)                in->tab_suffix[i]
+
+/* ============================================================================
+ * Decompress in to out.  This routine adapts to the codes in the
+ * file building the "string" table on-the-fly; requiring no table to
+ * be stored in the compressed file.
+ * IN assertions: the buffer inbuf contains already the beginning of
+ *   the compressed data, from offsets iptr to insize-1 included.
+ *   The magic header has already been checked and skipped.
+ *   bytes_in and bytes_out have been initialized.
+ *
+ * Adopted from gzip version 1.3.7 unlzw.c
+ * This is mainly the head of the old unlzw() before its main loop.
+ */
+LZW_t *openlzw(const char * path, const char *mode)
+{
+    int fildes;
+    if (!mode || *mode != 'r')
+       goto out;
+    if ((fildes = open(path, O_RDONLY)) < 0)
+        goto out;
+    return dopenlzw(fildes, mode);
+out:
+    return (LZW_t*)0;
+}
+
+LZW_t *dopenlzw(int fildes, const char *mode)
+{
+    LZW_t *in = (LZW_t*)0;
+    uint8_t magic[2];
+    sigset_t sigmask, oldmask;
+
+    if (!mode || *mode != 'r')
+       goto out;
+
+    if ((in = (LZW_t*)malloc(sizeof(LZW_t))) == (LZW_t*)0)
+       goto err;
+    memset(in, 0, sizeof(LZW_t));
+
+    if ((in->inbuf = (uint8_t*)malloc(sizeof(uint8_t)*(INBUFSIZ))) == (uint8_t*)0)
+       goto err;
+    if ((in->outbuf = (uint8_t*)malloc(sizeof(uint8_t)*(OUTBUFSIZ+OUTBUF_EXTRA))) == (uint8_t*)0)
+       goto err;
+    if ((in->d_buf = (uint16_t*)malloc(sizeof(uint16_t)*DIST_BUFSIZE)) == (uint16_t*)0)
+       goto err;
+    if ((in->tab_suffix = (uint8_t*) malloc(sizeof(uint8_t )*(2L*WSIZE))) == (uint8_t*)0)
+       goto err;
+    if ((in->tab_prefix = (uint16_t*)malloc(sizeof(uint16_t)*(1<<(BITS)))) == (uint16_t*)0)
+       goto err;
+    if ((in->ifd = fildes) < 0)
+       goto err;
+
+    if ((in->stack = (uint8_t*)malloc(STACK_SIZE)) == (uint8_t*)0)
+       goto err;
+    if ((in->uc = (ucontext_t*)malloc(2*sizeof(ucontext_t))) == (ucontext_t*)0)
+       goto err;
+    if (getcontext(&in->uc[1]) < 0)
+       goto err;
+    in->uc[1].uc_link = &in->uc[0];
+    in->uc[1].uc_stack.ss_sp = in->stack;
+    in->uc[1].uc_stack.ss_size = STACK_SIZE;
+    if (sigucmask(SIG_SETMASK, (sigset_t*)0, &sigmask) < 0)
+       goto err;
+    if (sigaddset(&sigmask, SIGINT) < 0)
+       goto err;
+    if (sigaddset(&sigmask, SIGQUIT) < 0)
+       goto err;
+#if defined(__ia64__) && defined(uc_sigmask)   /* On ia64 the type of uc_sigmask is ulong not sigset_t */
+    in->uc[1].uc_sigmask = sig_ia64_mask(sigmask);
+#else
+    in->uc[1].uc_sigmask = sigmask;
+#endif
+    makecontext(&in->uc[1], (void(*)(void))unlzw, 1, in);
+
+    sigucmask(SIG_SETMASK, &sigmask, &oldmask);
+    magic[0] = get_byte(in);
+    magic[1] = get_byte(in);
+    sigucmask(SIG_SETMASK, &oldmask, &sigmask);
+
+    if (memcmp(magic, LZW_MAGIC, sizeof(magic)))
+       goto err;
+
+    in->n.block_mode = BLOCK_MODE;  /* block compress mode -C compatible with 2.0 */
+    in->rsize = in->insize;
+
+    in->n.maxbits = get_byte(in);
+    in->n.block_mode = in->n.maxbits & BLOCK_MODE;
+
+    if ((in->n.maxbits & LZW_RESERVED) != 0) {
+       fprintf(stderr, "%s: warning, unknown flags 0x%x\n",
+               __FUNCTION__, in->n.maxbits & LZW_RESERVED);
+    }
+    in->n.maxbits &= BIT_MASK;
+    in->n.maxmaxcode = MAXCODE(in->n.maxbits);
+
+    if (in->n.maxbits > BITS) {
+       fprintf(stderr, "%s: compressed with %d bits, can only handle %d bits\n",
+               __FUNCTION__, in->n.maxbits, BITS);
+       goto err;
+    }
+
+    in->n.maxcode = MAXCODE(in->n.n_bits = INIT_BITS)-1;
+    in->n.bitmask = (1<<in->n.n_bits)-1;
+    in->n.oldcode = -1;
+    in->n.finchar = 0;
+    in->n.posbits = in->inptr<<3;
+
+    in->n.free_ent = ((in->n.block_mode) ? FIRST : 256);
+
+    clear_tab_prefixof(in);    /* Initialize the first 256 entries in the table. */
+
+    for (in->n.code = 255 ; in->n.code >= 0 ; --in->n.code) {
+       tab_suffixof(in->n.code) = (uint8_t)in->n.code;
+    }
+out:
+    return in;
+err:
+    closelzw(in);
+    return (LZW_t*)0;
+}
+
+/*
+ * New function, simply to free all allocated objects in
+ * reverse order and close the input file.
+ */
+void closelzw(LZW_t * in)
+{
+    if (in == (LZW_t*)0)
+       return;
+    if (in->uc) free(in->uc);
+    if (in->stack) free(in->stack);
+    if (in->ifd >= 0) close(in->ifd);
+    if (in->tab_prefix) free(in->tab_prefix);
+    if (in->tab_suffix) free(in->tab_suffix);
+    if (in->d_buf)  free(in->d_buf);
+    if (in->outbuf) free(in->outbuf);
+    if (in->inbuf)  free(in->inbuf);
+    free(in);
+    in = (LZW_t*)0;
+}
+
+/*
+ * Adopted from gzip version 1.3.7 unlzw.c
+ * This is mainly the body of the old unlzw() which is its main loop.
+ */
+static void unlzw(LZW_t *in)
+{
+    do {
+       int i;
+       int e;
+       int o;
+
+    resetbuf:
+       e = in->insize - (o = (in->n.posbits>>3));
+
+       for (i = 0 ; i < e ; ++i) {
+           in->inbuf[i] = in->inbuf[i+o];
+       }
+       in->insize = e;
+       in->n.posbits = 0;
+
+       if (in->insize < INBUF_EXTRA) {
+           do {
+               in->rsize = read(in->ifd, in->inbuf + in->insize, INBUFSIZ - in->insize);
+               if (in->rsize < 0) {
+                   if (errno == EINTR)
+                       continue;
+                   perror(__FUNCTION__);
+                   break;
+               }
+               if (in->rsize == 0)
+                   break;
+               in->insize += in->rsize;
+           } while (in->insize < INBUFSIZ);
+           in->bytes_in += (off_t)in->insize;
+       }
+       in->n.inbits = ((in->rsize != 0) ? ((long)in->insize - in->insize%in->n.n_bits)<<3 :
+                       ((long)in->insize<<3)-(in->n.n_bits-1));
+
+       while (in->n.inbits > in->n.posbits) {
+           if (in->n.free_ent > in->n.maxcode) {
+               in->n.posbits = ((in->n.posbits-1) +
+                          ((in->n.n_bits<<3)-(in->n.posbits-1+(in->n.n_bits<<3))%(in->n.n_bits<<3)));
+               ++in->n.n_bits;
+               if (in->n.n_bits == in->n.maxbits) {
+                   in->n.maxcode = in->n.maxmaxcode;
+               } else {
+                   in->n.maxcode = MAXCODE(in->n.n_bits)-1;
+               }
+               in->n.bitmask = (1<<in->n.n_bits)-1;
+               goto resetbuf;
+           }
+           input(in->inbuf,in->n.posbits,in->n.code,in->n.n_bits,in->n.bitmask);
+
+           if (in->n.oldcode == -1) {
+               if (256 <= in->n.code)
+                   fprintf(stderr, "%s: corrupt input.\n", __FUNCTION__);
+               in->outbuf[in->outpos++] = (uint8_t)(in->n.finchar = (int)(in->n.oldcode=in->n.code));
+               continue;
+           }
+           if (in->n.code == CLEAR && in->n.block_mode) {
+               clear_tab_prefixof(in);
+               in->n.free_ent = FIRST - 1;
+               in->n.posbits = ((in->n.posbits-1) +
+                          ((in->n.n_bits<<3)-(in->n.posbits-1+(in->n.n_bits<<3))%(in->n.n_bits<<3)));
+               in->n.maxcode = MAXCODE(in->n.n_bits = INIT_BITS)-1;
+               in->n.bitmask = (1<<in->n.n_bits)-1;
+               goto resetbuf;
+           }
+           in->n.incode = in->n.code;
+           in->n.stackp = de_stack;
+
+           if (in->n.code >= in->n.free_ent) { /* Special case for KwKwK string. */
+               if (in->n.code > in->n.free_ent) {
+#ifdef DEBUG
+                   uint8_t *p;
+                   in->n.posbits -= in->n.n_bits;
+                   p = &in->inbuf[in->n.posbits>>3];
+                   fprintf(stderr,
+                           "code:%ld free_ent:%ld n_bits:%d insize:%lu\n",
+                           in->n.code, in->n.free_ent, in->n.n_bits, in->insize);
+                   fprintf(stderr,
+                           "posbits:%ld inbuf:%02X %02X %02X %02X %02X\n",
+                           in->n.posbits, p[-1],p[0],p[1],p[2],p[3]);
+#endif
+                   if (in->outpos > 0) {
+                       write_buf(in, in->outbuf, in->outpos);
+                       in->bytes_out += (off_t)in->outpos;
+                       in->outpos = 0;
+                   }
+                   fprintf(stderr, "%s: corrupt input.\n", __FUNCTION__);
+               }
+               *--in->n.stackp = (uint8_t)in->n.finchar;
+               in->n.code = in->n.oldcode;
+           }
+
+           /* Generate output characters in reverse order */
+           while ((uint32_t)in->n.code >= (uint32_t)256) {
+               *--in->n.stackp = tab_suffixof(in->n.code);
+               in->n.code = tab_prefixof(in->n.code);
+           }
+           *--in->n.stackp =   (uint8_t)(in->n.finchar = tab_suffixof(in->n.code));
+
+           /* And put them out in forward order */
+           if (in->outpos + (in->n.newdif = (de_stack - in->n.stackp)) >= OUTBUFSIZ) {
+               do {
+                   if (in->n.newdif > OUTBUFSIZ - in->outpos)
+                       in->n.newdif = OUTBUFSIZ - in->outpos;
+
+                   if (in->n.newdif > 0) {
+                       memcpy(in->outbuf + in->outpos, in->n.stackp, in->n.newdif);
+                       in->outpos += in->n.newdif;
+                   }
+                   if (in->outpos >= OUTBUFSIZ) {
+                       write_buf(in, in->outbuf, in->outpos);
+                       in->bytes_out += (off_t)in->outpos;
+                       in->outpos = 0;
+                   }
+                   in->n.stackp+= in->n.newdif;
+               } while ((in->n.newdif = (de_stack - in->n.stackp)) > 0);
+           } else {
+               memcpy(in->outbuf + in->outpos, in->n.stackp, in->n.newdif);
+               in->outpos += in->n.newdif;
+           }
+
+           if ((in->n.code = in->n.free_ent) < in->n.maxmaxcode) { /* Generate the new entry. */
+
+               tab_prefixof(in->n.code) = (uint16_t)in->n.oldcode;
+               tab_suffixof(in->n.code) = (uint8_t)in->n.finchar;
+               in->n.free_ent = in->n.code+1;
+           }
+           in->n.oldcode = in->n.incode;       /* Remember previous code.      */
+       }
+    } while (in->rsize != 0);
+
+    if (in->outpos > 0) {
+       write_buf(in, in->outbuf, in->outpos);
+       in->bytes_out += (off_t)in->outpos;
+       in->tsize = EOF;
+       in->outpos = 0;
+    }
+}
+
+/*
+ * New function, simply to read from the output buffer of unlzw().
+ * We do this by switching into the context of unlzw() and back
+ * to our old context if the provided buffer is filled.
+ */
+ssize_t readlzw(LZW_t * in, char* buffer, const size_t size)
+{
+    in->transfer = (uint8_t*)buffer;
+    in->tcount = size;
+    in->tsize = 0;
+    if (in->uc == (ucontext_t*)0)
+       return 0;                       /* For (f)lex scanner ... */
+    swapcontext(&in->uc[0], &in->uc[1]);
+    if (in->tsize < 0) {
+       free(in->uc);                   /* ... do not enter next */
+       in->uc = (ucontext_t*)0;
+       free(in->stack);
+       in->stack = (uint8_t*)0;
+       return 0;
+    }
+    return in->tsize;
+}
+
+#ifdef TEST
+int main()
+{
+    ssize_t len;
+    char buffer[1024];
+
+    LZW_t *lzw = openlzw("man.1.Z", "r");
+    if (!lzw)
+       return -1;
+
+    do {
+       len = readlzw(lzw, &buffer[0], sizeof(buffer));
+       write(1, &buffer[0], len);
+    } while (len != 0);
+
+    closelzw(lzw);
+    return 0;
+}
+#endif
diff --git a/zio.c b/zio.c
new file mode 100644 (file)
index 0000000..95788d2
--- /dev/null
+++ b/zio.c
@@ -0,0 +1,1208 @@
+/*
+ * zio.c       Provide an streamable interface to gziped/bzip2ed/LZW/LZMA files
+ *
+ * Copyright 2004 Werner Fink, 2004 SuSE LINUX AG, Germany.
+ * Copyright 2006 Werner Fink, 2006 SuSE Products GmbH, Germany.
+ * Copyright 2009 Werner Fink, 2009 SuSE Products GmbH, Germany.
+ *
+ * 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.
+ *
+ * Author:     Werner Fink <werner@suse.de>
+ */
+
+#include "zioP.h"
+#include "zio.h"
+#include "lzw.h"
+
+#if defined(HAS_ZLIB_H)
+static ssize_t   zread(void *cookie, char *buf, size_t count)
+{
+    if (!cookie) {
+       errno = EINVAL;
+       return -1;
+    }
+    return (ssize_t)gzread((gzFile)cookie, (voidp)buf, count);
+}
+
+static ssize_t   zwrite(void *cookie, const char *buf, size_t count)
+{
+    if (!cookie) {
+       errno = EINVAL;
+       return -1;
+    }
+    return (ssize_t)gzwrite((gzFile)cookie, (const voidp)buf, count);
+}
+
+static zio_int_t zseek(void *cookie, zio_off_t *poffset, int whence)
+{
+    if (!cookie) {
+       errno = EINVAL;
+       return -1;
+    }
+    return (zio_int_t)gzseek((gzFile)cookie, (z_off_t)(*poffset), whence);
+}
+
+static int       zclose(void *cookie)
+{
+    int status;
+    if (!cookie) {
+       errno = EINVAL;
+       return -1;
+    }
+    (void)gzflush((gzFile)cookie, Z_FINISH);
+    status = gzclose((gzFile)cookie);
+    return (status >= 0) ? 0 : EOF;
+}
+
+__extension__
+static cookie_io_functions_t ioz = {
+    .read  = (cookie_read_function_t*) &zread,
+    .write = (cookie_write_function_t*)&zwrite,
+    .seek  = (cookie_seek_function_t*) &zseek,
+    .close = (cookie_close_function_t*)&zclose,
+};
+#else /* !HAS_ZLIB_H */
+# error No support for `.gz' nor `.z' format
+#endif /* !HAS_ZLIB_H */
+
+#if defined(HAS_BZLIB_H)
+# ifndef MIN
+#  define MIN(x,y) ((x) < (y) ? (x) : (y))
+# endif
+
+typedef struct bzfile_s {
+    size_t total_out;
+    BZFILE *file;
+    char *mode;
+    char *path;
+    int fd;
+} bzfile_t;
+
+static ssize_t   bzread(void *cookie, char *buf, size_t count)
+{
+    bzfile_t *bzf = (bzfile_t*)cookie;
+    ssize_t len = -1;
+    if (!bzf)
+       goto out;
+    if (bzf->file)
+       len = (ssize_t)BZ2_bzread(bzf->file, (void*)buf, count);
+    if (len > 0)
+       bzf->total_out += len;
+out:
+    if (len < 0)
+       errno = EINVAL;
+    return len;
+}
+
+static ssize_t   bzwrite(void *cookie, const char *buf, size_t count)
+{
+    bzfile_t *bzf = (bzfile_t*)cookie;
+    ssize_t len = -1;
+    if (!bzf)
+       goto out;
+    if (bzf->file)
+       len = (ssize_t)BZ2_bzread(bzf->file, (void*)buf, count);
+    if (len > 0)
+       bzf->total_out += len;
+out:
+    if (len < 0)
+       errno = EINVAL;
+    return len;
+}
+
+static zio_int_t bzseek(void *cookie, zio_off_t *poffset, int whence)
+{
+    bzfile_t *bzf = (bzfile_t*)cookie;
+    off_t offset = (off_t)*poffset;
+    off_t oldpos, newpos;
+    if (!bzf) {
+       errno = EINVAL;
+       return -1;
+    }
+
+    oldpos = (off_t)bzf->total_out;
+    switch (whence) {
+    case SEEK_SET:
+       if (offset < 0)
+           return -1;
+       newpos = offset;
+       break;
+    case SEEK_CUR:
+       if ((offset < 0 && (off_t)(-1 * offset) > oldpos) || (offset > 0 && (offset+oldpos) < oldpos))
+           return -1;
+       newpos = (off_t)bzf->total_out + offset;
+       break;
+    case SEEK_END:
+       newpos = -1;
+       break;
+    default:
+       errno = EINVAL;
+       return -1;
+    }
+
+    if (whence != SEEK_END && newpos < oldpos) {
+       int status = BZ2_bzflush(bzf->file);
+       BZ2_bzclose(bzf->file);
+       if (status < 0) {
+           errno = EINVAL;
+           return -1;
+       }
+       if (bzf->fd >= 0) {
+           lseek(bzf->fd, 0, SEEK_SET);
+           bzf->file = BZ2_bzdopen(bzf->fd, bzf->mode);
+       } else if (bzf->path) {
+           bzf->file = BZ2_bzopen(bzf->path, bzf->mode);
+       } else {
+           errno = EINVAL;
+           return -1;
+       }
+       if (bzf->file == (BZFILE*)0) {
+           errno = EINVAL;
+           return -1;
+       }
+       bzf->total_out = 0;
+    }
+    if (newpos == oldpos)
+       return oldpos;
+    else {
+       char buf[1<<12];
+       while (newpos > oldpos || newpos == -1) {
+           size_t  req_size = MIN(sizeof(buf), newpos - oldpos);
+           ssize_t got_size = BZ2_bzread(bzf->file, buf, req_size);
+           if (got_size != (ssize_t)(req_size)) {
+               if (got_size < 0)
+                   return -1;
+               else {
+                   newpos = oldpos + got_size;
+                   break;
+               }
+           }
+           oldpos += got_size;
+       }
+       return newpos;
+    }
+}
+
+static int       bzclose(void *cookie)
+{
+    bzfile_t *bzf = (bzfile_t*)cookie;
+    int status = -1;
+    if (!bzf) {
+       errno = EINVAL;
+       goto out;
+    }
+    if (bzf->file) {
+       status = BZ2_bzflush(bzf->file);
+       BZ2_bzclose(bzf->file);
+    }
+    free(cookie);
+out:
+    return (status >= 0) ? 0 : EOF;
+}
+
+__extension__
+static cookie_io_functions_t iobz = {
+    .read  = (cookie_read_function_t*) &bzread,
+    .write = (cookie_write_function_t*)&bzwrite,
+    .seek  = (cookie_seek_function_t*) &bzseek,
+    .close = (cookie_close_function_t*)&bzclose,
+};
+#else /* !HAS_BZLIB_H */
+# warning No support for .bz2 format
+#endif /* !HAS_BZLIB_H */
+
+#if defined(HAS_LZMA_H)
+# ifndef MIN
+#  define MIN(x,y) ((x) < (y) ? (x) : (y))
+# endif
+
+typedef struct lzfile_s {
+    uint8_t buf[1<<12];
+    lzma_stream strm;
+    FILE *file;
+    int encoding;
+    int level;
+    int what;
+    int eof;
+} lzfile_t;
+
+static lzma_ret lzmaopen(lzma_stream *__restrict strm, const char mode, const char what, int level)
+{
+    lzma_ret ret;
+    if (mode == 'w') {
+       if (what == 'x')
+           ret = lzma_easy_encoder(strm, level, LZMA_CHECK_CRC32);
+       else {
+           lzma_options_lzma opt;
+           lzma_lzma_preset(&opt, level);
+           ret = lzma_alone_encoder(strm, &opt);
+       }
+   } else
+       ret = lzma_auto_decoder(strm, 100<<20, 0);
+   return ret;
+}
+
+static ssize_t   lzmaread(void *cookie, char *buf, size_t count)
+{
+    lzfile_t *lzma = (lzfile_t*)cookie;
+    lzma_stream *strm;
+    ssize_t eof = 0;
+    if (!lzma || lzma->encoding)
+       return -1;
+    if (lzma->eof)
+       return 0;
+    strm = &lzma->strm;
+
+    strm->next_out = (uint8_t*)buf;
+    strm->avail_out = count;
+    while (1) {
+       lzma_ret lret;
+       if (!strm->avail_in) {
+           strm->next_in = lzma->buf;
+           strm->avail_in = fread(lzma->buf, 1, sizeof(lzma->buf), lzma->file);
+           if (strm->avail_in == 0)
+               eof = 1;
+       }
+       lret = lzma_code(strm, LZMA_RUN);
+       if (lret == LZMA_STREAM_END) {
+           lzma->eof = 1;
+           return count - strm->avail_out;
+       }
+       if (lret != LZMA_OK)
+           return -1;
+       if (strm->avail_out == 0)
+           return count;
+       if (eof) {
+           eof = feof(lzma->file);
+           clearerr(lzma->file);
+           if (eof)
+               break;
+           return -1;
+       }
+    }
+    return 0;
+}
+
+static ssize_t   lzmawrite(void *cookie, const char *buf, size_t count)
+{
+    lzfile_t *lzma = (lzfile_t*)cookie;
+    lzma_stream *strm;
+    if (!lzma || !lzma->encoding)
+       return -1;
+    if (!count)
+       return 0;
+    strm = &lzma->strm;
+
+    strm->next_in = (uint8_t*)buf;
+    strm->avail_in = count;
+    while (1) {
+       lzma_ret lret;
+       size_t len;
+       strm->next_out = lzma->buf;
+       strm->avail_out = sizeof(lzma->buf);
+       lret = lzma_code(strm, LZMA_RUN);
+       if (lret != LZMA_OK)
+           break;
+       len = sizeof(lzma->buf) - strm->avail_out;
+       if (len && fwrite(lzma->buf, 1, len, lzma->file) != len)
+           break;
+       if (strm->avail_in == 0)
+           return len;
+    }
+    return -1;
+}
+
+static zio_int_t lzmaseek(void *cookie, zio_off_t *poffset, int whence)
+{
+    lzfile_t *lzma = (lzfile_t*)cookie;
+    off_t offset = (off_t)*poffset;
+    lzma_stream *strm;
+    off_t oldpos, newpos;
+    if (!lzma)
+       return -1;
+    strm = &lzma->strm;
+
+    oldpos = (off_t)strm->total_out;
+    switch (whence) {
+    case SEEK_SET:
+       if (offset < 0)
+           return -1;
+       newpos = offset;
+       break;
+    case SEEK_CUR:
+       if ((offset < 0 && (off_t)(-1 * offset) > oldpos) || (offset > 0 && (offset+oldpos) < oldpos))
+           return -1;
+       newpos = (off_t)strm->total_out + offset;
+       break;
+    case SEEK_END:
+       newpos = -1;
+       break;
+    default:
+       errno = EINVAL;
+       return -1;
+    }
+
+    if (whence != SEEK_END && newpos < oldpos) {
+       lzma_ret ret;
+       lzma_end(strm);
+       rewind(lzma->file);
+       ret = lzmaopen(strm, lzma->encoding ? 'w' : 'r', lzma->what, lzma->level);
+       if (ret != LZMA_OK || strm->total_out != 0) {
+           fclose(lzma->file);
+           errno = EINVAL;
+           return -1;
+       }
+    }
+    if (newpos == oldpos)
+       return oldpos;
+    else {
+       char buf[sizeof(lzma->buf)];
+       while (newpos > oldpos || newpos == -1) {
+           size_t  req_size = MIN(sizeof(buf), newpos - oldpos);
+           ssize_t got_size = lzmaread(cookie, buf, req_size);
+           if (got_size != (ssize_t)(req_size)) {
+               if (got_size < 0)
+                   return -1;
+               else {
+                   newpos = oldpos + got_size;
+                   break;
+               }
+           }
+           oldpos += got_size;
+       }
+       return newpos;
+    }
+}
+
+static int       lzmaclose(void *cookie)
+{
+    lzfile_t *lzma = (lzfile_t*)cookie;
+    lzma_ret lret = LZMA_STREAM_END;
+    lzma_stream *strm;
+    int fret = -1;
+    if (!lzma)
+       return -1;
+    if (!lzma->encoding)
+       goto out;
+    strm = &lzma->strm;
+    while (1) {
+       size_t len;
+       strm->avail_out = sizeof(lzma->buf);
+       strm->next_out = (uint8_t*)lzma->buf;
+       lret = lzma_code(strm, LZMA_FINISH);
+       if (lret != LZMA_OK && lret != LZMA_STREAM_END)
+           goto out;
+       len = sizeof(lzma->buf) - strm->avail_out;
+       if (len && fwrite(lzma->buf, 1, len, lzma->file) != len)
+           goto out;
+       if (lret == LZMA_STREAM_END)
+           break;
+    }
+    lzma_end(strm);
+out:
+    fret = fclose(lzma->file);
+    free(lzma);
+    if (lret != LZMA_STREAM_END)
+       fret = -1;
+    return fret;
+}
+
+__extension__
+static cookie_io_functions_t iolzma = {
+    .read  = (cookie_read_function_t*) &lzmaread,
+    .write = (cookie_write_function_t*)&lzmawrite,
+    .seek  = (cookie_seek_function_t*) &lzmaseek,
+    .close = (cookie_close_function_t*)&lzmaclose,
+};
+#else /* !HAS_LZMA_H */
+# if defined(HAS_LZMADEC_H)
+static ssize_t   lzmaread(void *cookie, char *buf, size_t count)
+{
+    if (!cookie) {
+       errno = EINVAL;
+       return -1;
+    }
+    return lzmadec_read((lzmadec_FILE*)cookie, (uint8_t*)buf, count);
+}
+
+static ssize_t   lzmawrite(void *cookie, const char *buf, size_t count)
+{
+    errno = ENOTSUP;
+    return -1;
+}
+
+static zio_int_t lzmaseek(void *cookie, zio_off_t *poffset, int whence)
+{
+    if (!cookie) {
+       errno = EINVAL;
+       return -1;
+    }
+    return (zio_int_t)lzmadec_seek((lzmadec_FILE*)cookie, (off_t)(*poffset), whence);
+}
+
+static int       lzmaclose(void *cookie)
+{
+    if (!cookie) {
+       errno = EINVAL;
+       return -1;
+    }
+    int_fast8_t status = lzmadec_close((lzmadec_FILE*)cookie);
+    return (status >= 0) ? 0 : EOF;
+}
+
+__extension__
+static cookie_io_functions_t iolzma = {
+    .read  = (cookie_read_function_t*) &lzmaread,
+    .write = (cookie_write_function_t*)&lzmawrite,
+    .seek  = (cookie_seek_function_t*) &lzmaseek,
+    .close = (cookie_close_function_t*)&lzmaclose,
+};
+# else /* !HAS_LZMADEC_H */
+#  warning No support for .lzma format
+# endif /* !HAS_LZMADEC_H */
+#endif /* !HAS_LZMA_H */
+
+typedef struct lzwfile_s {
+    size_t total_out;
+    LZW_t *file;
+    char *mode;
+    char *path;
+    int fd;
+} lzwfile_t;
+
+static ssize_t   lzwread(void *cookie, char *buf, size_t count)
+{
+    lzwfile_t *lzw = (lzwfile_t*)cookie;
+    ssize_t len = -1;
+    if (!lzw)
+       goto out;
+    if (lzw->file)
+       len = readlzw(lzw->file, buf, count);
+    if (len > 0)
+       lzw->total_out += len;
+out:
+    if (len < 0)
+       errno = EINVAL;
+    return len;
+}
+
+static ssize_t   lzwwrite(void *cookie, const char *buf, size_t count)
+{
+    errno = ENOTSUP;
+    return -1;
+}
+
+static zio_int_t lzwseek(void *cookie, zio_off_t *poffset, int whence)
+{
+    lzwfile_t *lzw = (lzwfile_t*)cookie;
+    off_t offset = (off_t)*poffset;
+    off_t oldpos, newpos;
+    if (!lzw) {
+       errno = EINVAL;
+       return -1;
+    }
+
+    oldpos = (off_t)lzw->total_out;
+    switch (whence) {
+    case SEEK_SET:
+       if (offset < 0)
+           return -1;
+       newpos = offset;
+       break;
+    case SEEK_CUR:
+       if ((offset < 0 && (off_t)(-1 * offset) > oldpos) || (offset > 0 && (offset+oldpos) < oldpos))
+           return -1;
+       newpos = (off_t)lzw->total_out + offset;
+       break;
+    case SEEK_END:
+       newpos = -1;
+       break;
+    default:
+       errno = EINVAL;
+       return -1;
+    }
+
+    if (whence != SEEK_END && newpos < oldpos) {
+       closelzw(lzw->file);
+       if (lzw->fd >= 0) {
+           lseek(lzw->fd, 0, SEEK_SET);
+           lzw->file = dopenlzw(lzw->fd, lzw->mode);
+       } else if (lzw->path) {
+           lzw->file = openlzw(lzw->path, lzw->mode);
+       } else {
+           errno = EINVAL;
+           return -1;
+       }
+       if (lzw->file == (LZW_t*)0) {
+           errno = EINVAL;
+           return -1;
+       }
+       lzw->total_out = 0;
+    }
+    if (newpos == oldpos)
+       return oldpos;
+    else {
+       char buf[1<<12];
+       while (newpos > oldpos || newpos == -1) {
+           size_t  req_size = MIN(sizeof(buf), newpos - oldpos);
+           ssize_t got_size = readlzw(lzw->file, buf, req_size);
+           if (got_size != (ssize_t)(req_size)) {
+               if (got_size < 0)
+                   return -1;
+               else {
+                   newpos = oldpos + got_size;
+                   break;
+               }
+           }
+           oldpos += got_size;
+       }
+       return newpos;
+    }
+}
+
+static int       lzwclose(void *cookie)
+{
+    lzwfile_t *lzw = (lzwfile_t*)cookie;
+    if (!lzw) {
+       errno = EINVAL;
+       return -1;
+    }
+    if (lzw->file)
+       closelzw(lzw->file);
+    free(cookie);
+    return 0;
+}
+
+__extension__
+static cookie_io_functions_t iolzw = {
+    .read  = (cookie_read_function_t*) &lzwread,
+    .write = (cookie_write_function_t*)&lzwwrite,
+    .seek  = (cookie_seek_function_t*) &lzwseek,
+    .close = (cookie_close_function_t*)&lzwclose,
+};
+
+static inline char autodetect(char **__restrict path, const char *__restrict check)
+{
+    const size_t len = strlen(*path);
+    char *suff = strrchr(*path, '.');
+    char *ext = *path;
+    char what = 'n';
+
+    if (suff) {
+       suff++;
+       if      (strcmp(suff, "z"   ) == 0)
+           what = 'z';
+       else if (strcmp(suff, "gz"  ) == 0)
+           what = 'g';
+       else if (strcmp(suff, "Z"   ) == 0)
+           what = 'Z';
+       else if (strcmp(suff, "bz2" ) == 0)
+           what = 'b';
+       else if (strcmp(suff, "lzma") == 0)
+           what = 'l';
+       else if (strcmp(suff, "xz"  ) == 0)
+           what = 'x';
+    }
+
+    if (what == 'n' && *check == 'r') {
+       int olderr, fd;
+       struct stat st;
+       char m[5];
+       ext = malloc(sizeof(char)*(len + 5 + 1));
+       if (!ext)
+           goto out;
+       strcpy(ext, *path);
+       suff = (ext+len);
+
+       olderr = errno;
+       if (stat(strcat(ext, ".gz"),  &st) == 0) {
+           what = 'g';
+           goto skip;
+       }
+       *suff = '\0';
+       if (stat(strcat(ext, ".bz2"), &st) == 0) {
+           what = 'b';
+           goto skip;
+       }
+       *suff = '\0';
+       if (stat(strcat(ext, ".z"),   &st) == 0) {
+           what = 'z';
+           goto skip;
+       }
+       *suff = '\0';
+       if (stat(strcat(ext, ".Z"),   &st) == 0) {
+           what = 'Z';
+           goto skip;
+       }
+       *suff = '\0';
+       if (stat(strcat(ext, ".lzma"), &st) == 0) {
+           what = 'l';
+           goto skip;
+       }
+       *suff = '\0';
+       if (stat(strcat(ext, ".xz"), &st) == 0) {
+           what = 'x';
+           goto skip;
+       }
+       *suff = '\0';
+
+       if ((fd = open(ext, O_RDONLY|O_NOCTTY)) < 0)
+           goto skip;
+       if (read(fd, m, sizeof(m)) == sizeof(m)) {
+           if (m[0] == '\037' && m[1] == '\213')
+               what = 'g';
+           if (m[0] == '\037' && m[1] == '\235')
+               what = 'Z';
+           if (m[0] == '\037' && m[1] == '\236')
+               what = 'z';
+           else if (m[0] == 'B' && m[1] == 'Z' && m[2] == 'h')
+               what = 'b';
+           else if (m[0] == ']' && m[1] == '\0' && m[2] == '\0' && m[3] == '\200') /* weak!! */
+               what = 'l';
+           else if (m[0] == '\377' && m[1] == 'L' && m[2] == 'Z' && m[3] == 'M' && m[4] == 'A')
+               what = 'l';
+           else if (m[0] == '\375' && m[1] == '7' && m[2] == 'z' && m[3] == 'X' && m[4] == 'Z')
+               what = 'x';
+       }
+       close(fd);
+    skip:
+       errno = olderr;
+    }
+out:
+    *path = ext;
+    return what;
+}
+
+FILE * fzopen(const char * path, const char * mode)
+{
+    FILE * ret = (FILE *)0;
+    char * check = (char*)0, * ext = (char*)0;
+    size_t n = 0, len;
+    unsigned int i;
+    char what = 'n';
+
+    if (!mode || !(n = strlen(mode))) {
+       errno = EINVAL;
+       goto out;
+    }
+
+    if (!(check = (char*)malloc(n*sizeof(char))))
+       goto out;
+
+    /* No append mode possible */
+    switch (*mode) {
+       case 'r': check[0] = 'r'; break;
+       case 'w': check[0] = 'w'; break;
+       default:  errno = EINVAL; goto out;
+    }
+
+    for (i = 1; i < n; i++) {
+       /* We can only open for reading OR writing but NOT for both */
+       switch (mode[i]) {
+           case '\0': break;
+           case '+': errno = EINVAL; goto out;
+           case 'b': case 'x': check[i] = mode[i]; continue;
+           /* Ingore switches for gzopen() */
+           case 'f': case 'h': check[i] = '\0';    continue;
+           default:            check[i] = '\0';    continue;
+       }
+       break;
+    }
+
+    if (!path || !(len = strlen(path))) {
+       errno = EINVAL;
+       goto out;
+    }
+
+    ext = (char *)path;
+    what = autodetect(&ext, check);
+
+    switch (what) {
+    case 'g':
+    case 'z':          /* Is this correct? Old gzip magic */
+#if defined(HAS_ZLIB_H)
+       {
+           gzFile cookie;
+
+           if (&gzopen == NULL) {
+               errno = ENOSYS;
+               goto out;
+           }
+
+           if (!(cookie = gzopen(ext, mode))) {
+               if (!errno)
+                   errno = ENOMEM;
+               goto out;
+           }
+
+           if (!(ret = fopencookie((void*)cookie, check, ioz))) {
+               gzclose(cookie);
+               errno = EINVAL;
+               goto out;
+           }
+# ifndef LIBIO_IS_FIXED
+           if (ret->_fileno < 0)
+               ret->_fileno = 0;
+# endif
+       }
+#else /* !HAS_ZLIB_H */
+       errno = ENOTSUP;
+#endif /* !HAS_ZLIB_H */
+       break;
+    case 'Z':
+       {
+           lzwfile_t *__restrict cookie;
+           if (*mode != 'r') {
+               errno = ENOTSUP;
+               goto out;
+           }
+
+           if (posix_memalign((void*)&cookie, sizeof(void*), alignof(lzwfile_t)+strsize(ext)+strsize(mode)) != 0)
+               goto out;
+           memset(cookie, 0, alignof(lzwfile_t)+strsize(ext)+strsize(mode));
+
+           cookie->fd = -1;
+           cookie->mode = ((char*)cookie)+alignof(lzwfile_t);
+           cookie->path = cookie->mode + strsize(mode);
+           strcpy(cookie->mode, mode);
+           strcpy(cookie->path, ext);
+
+           if (!(cookie->file = openlzw(ext, mode))) {
+               free(cookie);
+               if (!errno)
+                   errno = ENOMEM;
+               goto out;
+           }
+
+           if (!(ret = fopencookie((void*)cookie, check, iolzw))) {
+               closelzw(cookie->file);
+               free(cookie);
+               errno = EINVAL;
+               goto out;
+           }
+# ifndef LIBIO_IS_FIXED
+           if (ret->_fileno < 0)
+               ret->_fileno = 0;
+# endif
+       }
+       break;
+    case 'b':
+#if defined(HAS_BZLIB_H)
+       {
+           bzfile_t *__restrict cookie;
+           int level = 5;
+
+           if (&BZ2_bzopen == NULL) {
+               errno = ENOSYS;
+               goto out;
+           }
+
+           if (posix_memalign((void*)&cookie, sizeof(void*), alignof(bzfile_t)+strsize(ext)+strsize(mode)) != 0)
+               goto out;
+           memset(cookie, 0, alignof(bzfile_t)+strsize(ext)+strsize(mode));
+
+           for (i = 1; i < n; i++) {
+               if (mode[i] >= '0' && mode[i] <= '9') {
+                   level = (int)mode[i];
+                   break;
+               }
+           }
+
+           cookie->fd = -1;
+           cookie->mode = ((char*)cookie)+alignof(bzfile_t);
+           cookie->path = cookie->mode+strsize(mode);
+           strcpy(cookie->mode, mode);
+           strcpy(cookie->path, ext);
+
+           if (!(cookie->file = BZ2_bzopen(ext, mode))) {
+               free(cookie);
+               if (!errno)
+                   errno = ENOMEM;
+               goto out;
+           }
+
+           if (!(ret = fopencookie((void*)cookie, check, iobz))) {
+               BZ2_bzclose(cookie->file);
+               free(cookie);
+               errno = EINVAL;
+               goto out;
+           }
+# ifndef LIBIO_IS_FIXED
+           if (ret->_fileno < 0)
+               ret->_fileno = 0;
+# endif
+       }
+#else /* !HAS_BZLIB_H */
+       errno = ENOTSUP;
+#endif /* !HAS_BZLIB_H */
+       break;
+#if defined(HAS_LZMA_H)
+    case 'l':
+    case 'x':
+       {
+           int level = LZMA_PRESET_DEFAULT;
+           lzfile_t *__restrict cookie;
+           lzma_ret lret;
+
+           if (&lzma_auto_decoder == NULL) {
+               errno = ENOSYS;
+               goto out;
+           }
+
+           if (posix_memalign((void*)&cookie, sizeof(void*), alignof(lzfile_t)) != 0)
+               goto out;
+           memset(cookie, 0, alignof(lzfile_t));
+
+           if ((cookie->file = fopen(ext, check)) == NULL) {
+               free(cookie);
+               goto out;
+           }
+
+           for (i = 1; i < n; i++) {
+               if (mode[i] >= '0' && mode[i] <= '9') {
+                   level = (int)mode[i];
+                   break;
+               }
+           }
+
+           cookie->eof = 0;
+           cookie->what = what;
+           cookie->strm = (lzma_stream)LZMA_STREAM_INIT;
+           cookie->level = level;
+           cookie->encoding = (check[0] == 'w') ? 1 : 0;
+           lret = lzmaopen(&cookie->strm, check[0], what, level);
+
+           if (lret != LZMA_OK) {
+               fclose(cookie->file);
+               free(cookie);
+               errno = EINVAL;
+               goto out;
+           }
+           if (!(ret = fopencookie((void*)cookie, check, iolzma))) {
+               lzma_end(&cookie->strm);
+               fclose(cookie->file);
+               free(cookie);
+               errno = EINVAL;
+               goto out;
+           }
+#  ifndef LIBIO_IS_FIXED
+           if (ret->_fileno < 0)
+               ret->_fileno = 0;
+#  endif
+       }
+       break;
+#else /* !HAS_LZMA_H */
+    case 'x':
+       errno = ENOTSUP;
+       break;
+    case 'l':
+# if defined(HAS_LZMADEC_H)
+       {
+           lzmadec_FILE* cookie;
+
+           if (*mode != 'r') {
+               errno = ENOTSUP;
+               goto out;
+           }
+
+           if (&lzmadec_open == NULL) {
+               errno = ENOSYS;
+               goto out;
+           }
+
+           if (!(cookie = lzmadec_open(ext))) {
+               if (!errno)
+                   errno = ENOMEM;
+               goto out;
+           } 
+
+           if (!(ret = fopencookie((void*)cookie, check, iolzma))) {
+               lzmadec_close(cookie);
+               errno = EINVAL;
+               goto out;
+           }
+#  ifndef LIBIO_IS_FIXED
+           if (ret->_fileno < 0)
+               ret->_fileno = 0;
+#  endif
+       }
+# else /* !HAS_LZMADEC_H */
+       errno = ENOTSUP;
+# endif /* !HAS_LZMADEC_H */
+#endif /* !HAS_LZMA_H */
+       break;
+    default:
+       ret = fopen(ext, mode);
+       break;
+    }
+
+out:
+    if (check)
+       free(check);
+    if (ext && ext != path)
+       free(ext);
+
+    return ret;
+}
+
+FILE * fdzopen(int fildes, const char * mode, const char *what)
+{
+    FILE * ret = (FILE *)0;
+    char * check = (char*)0;
+    size_t n = 0;
+    unsigned int i;
+
+    if (!mode || !(n = strlen(mode))) {
+       errno = EINVAL;
+       goto out;
+    }
+
+    if (!(check = (char*)malloc(n*sizeof(char))))
+       goto out;
+
+    /* No append mode possible */
+    switch (*mode) {
+       case 'r': check[0] = 'r'; break;
+       case 'w': check[0] = 'w'; break;
+       default:  errno = EINVAL; goto out;
+    }
+
+    for (i = 1; i < n; i++) {
+       /* We can only open for reading OR writing but NOT for both */
+       switch (mode[i]) {
+           case '\0': break;
+           case '+': errno = EINVAL; goto out;
+           case 'b': case 'x': check[i] = mode[i]; continue;
+           /* Ingore switches for gzopen() */
+           case 'f': case 'h': check[i] = '\0';    continue;
+           default:            check[i] = '\0';    continue;
+       }
+       break;
+    }
+
+    switch (*what) {
+    case 'g':
+    case 'z':          /* Is this correct? Old gzip magic */
+#if defined(HAS_ZLIB_H)
+       {
+           gzFile cookie;
+
+           if (&gzdopen == NULL) {
+               errno = ENOSYS;
+               goto out;
+           }
+
+           if (!(cookie = gzdopen(fildes, mode))) {
+               if (!errno)
+                   errno = ENOMEM;
+               goto out;
+           }
+
+           if (!(ret = fopencookie((void*)cookie, check, ioz))) {
+               gzclose(cookie);
+               errno = EINVAL;
+               goto out;
+           }
+# ifndef LIBIO_IS_FIXED
+           if (ret->_fileno < 0)
+               ret->_fileno = 0;
+# endif
+       }
+#else /* !HAS_ZLIB_H */
+       errno = ENOTSUP;
+#endif /* !HAS_ZLIB_H */
+       break;
+    case 'Z':
+       {
+           lzwfile_t *__restrict cookie;
+           if (*mode != 'r') {
+               errno = ENOTSUP;
+               goto out;
+           }
+
+           if (posix_memalign((void*)&cookie, sizeof(void*), alignof(lzwfile_t)+strsize(mode)) != 0)
+               goto out;
+           memset(cookie, 0, alignof(lzwfile_t)+strsize(mode));
+
+           cookie->fd = fildes;
+           cookie->mode = ((char*)cookie)+alignof(lzwfile_t);
+           strcpy(cookie->mode, mode);
+
+           if (!(cookie->file = dopenlzw(fildes, mode))) {
+               free(cookie);
+               if (!errno)
+                   errno = ENOMEM;
+               goto out;
+           }
+
+           if (!(ret = fopencookie((void*)cookie, check, iolzw))) {
+               closelzw(cookie->file);
+               free(cookie);
+               errno = EINVAL;
+               goto out;
+           }
+# ifndef LIBIO_IS_FIXED
+           if (ret->_fileno < 0)
+               ret->_fileno = 0;
+# endif
+       }
+       break;
+    case 'b':
+#if defined(HAS_BZLIB_H)
+       {
+           bzfile_t *__restrict cookie;
+           int level = 5;
+
+           if (&BZ2_bzdopen == NULL) {
+               errno = ENOSYS;
+               goto out;
+           }
+
+           if (posix_memalign((void*)&cookie, sizeof(void*), alignof(bzfile_t)+strsize(mode)) != 0)
+               goto out;
+           memset(cookie, 0, alignof(bzfile_t)+strsize(mode));
+
+           for (i = 1; i < n; i++) {
+               if (mode[i] >= '0' && mode[i] <= '9') {
+                   level = (int)mode[i];
+                   break;
+               }
+           }
+
+           cookie->fd = fildes;
+           cookie->mode = ((char*)cookie)+alignof(bzfile_t);
+           strcpy(cookie->mode, mode);
+
+           if (cookie->mode == (char*)0) {
+               free(cookie);
+               goto out;
+           }
+           if (!(cookie->file = BZ2_bzdopen(fildes, mode))) {
+               free(cookie);
+               if (!errno)
+                   errno = ENOMEM;
+               goto out;
+           }
+
+           if (!(ret = fopencookie((void*)cookie, check, iobz))) {
+               BZ2_bzclose(cookie->file);
+               free(cookie);
+               errno = EINVAL;
+               goto out;
+           }
+# ifndef LIBIO_IS_FIXED
+           if (ret->_fileno < 0)
+               ret->_fileno = 0;
+# endif
+       }
+#else /* !HAS_BZLIB_H */
+       errno = ENOTSUP;
+#endif /* !HAS_BZLIB_H */
+       break;
+#if defined(HAS_LZMA_H)
+    case 'l':
+    case 'x':
+       {
+           int level = LZMA_PRESET_DEFAULT;
+           lzfile_t *__restrict cookie;
+           lzma_ret lret;
+
+           if (&lzma_auto_decoder == NULL) {
+               errno = ENOSYS;
+               goto out;
+           }
+
+           if (posix_memalign((void*)&cookie, sizeof(void*), alignof(lzfile_t)) != 0)
+               goto out;
+           memset(cookie, 0, alignof(lzfile_t));
+
+           if ((cookie->file = fdopen(fildes, check)) == NULL) {
+               free(cookie);
+               goto out;
+           }
+
+           for (i = 1; i < n; i++) {
+               if (mode[i] >= '0' && mode[i] <= '9') {
+                   level = (int)mode[i];
+                   break;
+               }
+           }
+
+           cookie->eof = 0;
+           cookie->what = *what;
+           cookie->strm = (lzma_stream)LZMA_STREAM_INIT;
+           cookie->level = level;
+           cookie->encoding = (check[0] == 'w') ? 1 : 0;
+           lret = lzmaopen(&cookie->strm, check[0], *what, level);
+           if (lret != LZMA_OK) {
+               fclose(cookie->file);
+               free(cookie);
+               errno = EINVAL;
+               goto out;
+           }
+           if (!(ret = fopencookie((void*)cookie, check, iolzma))) {
+               lzma_end(&cookie->strm);
+               fclose(cookie->file);
+               free(cookie);
+               errno = EINVAL;
+               goto out;
+           }
+#  ifndef LIBIO_IS_FIXED
+           if (ret->_fileno < 0)
+               ret->_fileno = 0;
+#  endif
+       }
+       break;
+#else /* !HAS_LZMA_H */
+    case 'x':
+       errno = ENOTSUP;
+       break;
+    case 'l':
+# if defined(HAS_LZMADEC_H)
+       {
+           lzmadec_FILE* cookie;
+
+           if (*mode != 'r') {
+               errno = ENOTSUP;
+               goto out;
+           }
+
+           if (&lzmadec_open == NULL) {
+               errno = ENOSYS;
+               goto out;
+           }
+
+           if (!(cookie = lzmadec_dopen(fildes))) {
+               if (!errno)
+                   errno = ENOMEM;
+               goto out;
+           } 
+
+           if (!(ret = fopencookie((void*)cookie, check, iolzma))) {
+               lzmadec_close(cookie);
+               errno = EINVAL;
+               goto out;
+           }
+#  ifndef LIBIO_IS_FIXED
+           if (ret->_fileno < 0)
+               ret->_fileno = 0;
+#  endif
+       }
+# else /* !HAS_LZMADEC_H */
+       errno = ENOTSUP;
+# endif /* !HAS_LZMADEC_H */
+#endif /* !HAS_LZMA_H */
+       break;
+    default:
+       ret = fdopen(fildes, mode);
+       break;
+    }
+
+out:
+    if (check)
+       free(check);
+    return ret;
+}
diff --git a/zio.h.in b/zio.h.in
new file mode 100644 (file)
index 0000000..78f5b22
--- /dev/null
+++ b/zio.h.in
@@ -0,0 +1,33 @@
+/*
+ * zio.h       Provide an streamable interface to gziped/bzip2ed files
+ *
+ * Copyright 2004 Werner Fink, 2004 SuSE LINUX AG, Germany.
+ *
+ * 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.
+ *
+ * Author:     Werner Fink <werner@suse.de>
+ */
+
+#ifndef _ZIO_H
+#define _ZIO_H
+
+#include <stdio.h>
+#define ZIO_VERSION @@VERSION@@
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * This function can open a gziped file for reading OR writing, but
+ * NOT both (not `+' possible) NOR can it open for appending (no `a').
+ */
+extern FILE *fzopen __P((__const char *__restrict, __const char *__restrict));
+extern FILE *fdzopen __P((int, __const char *__restrict mode, __const char *__restrict));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZIO_H */
diff --git a/zio.map b/zio.map
new file mode 100644 (file)
index 0000000..a77c3aa
--- /dev/null
+++ b/zio.map
@@ -0,0 +1,7 @@
+{
+global:
+  fzopen;
+  fdzopen;
+local:
+  *;
+};
diff --git a/zioP.h b/zioP.h
new file mode 100644 (file)
index 0000000..b6d85cb
--- /dev/null
+++ b/zioP.h
@@ -0,0 +1,165 @@
+/*
+ * zioP.h      Internal header for libzio, including required
+ *             standard glibc header, zlib.h, and bzlib.h.
+ *             Making the used libz and bzlib functions weak symbols.
+ *
+ * Copyright 2004 Werner Fink, 2004 SuSE LINUX AG, Germany.
+ * Copyright 2006 Werner Fink, 2006 SuSE Products GmbH, Germany.
+ *
+ * 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.
+ *
+ * Author:      Werner Fink <werner@suse.de>
+ */
+
+#ifndef _ZIO_P_H
+#define _ZIO_P_H
+
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#ifdef HAVE_LIBIO_H
+# include <libio.h>
+#endif
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#ifndef  unused
+# define unused                __attribute__((__unused__))
+#endif
+#ifndef  nonnull
+# define nonnull(parm) __attribute__((__nonnull__ parm))
+#endif
+#ifndef  wur
+# define wur           __attribute__((__warn_unused_result__))
+#endif
+#define alignof(type)  (sizeof(type)+(sizeof(type)%sizeof(void*)))
+#define strsize(str)   ((strlen(str)+1)*sizeof(char))
+
+#if !defined(HAVE_FOPENCOOKIE) && !defined(HAVE_FUNOPEN)
+# error Requires fopencookie(3GNU) or funopen(3BSD)
+#endif
+
+#if defined(HAVE_LIBIO_H) || defined(HAVE_FOPENCOOKIE)
+# if defined __GLIBC__ && __GLIBC__ > 1
+#  undef  LIBIO_IS_FIXED
+#  if __GLIBC__ > 2 || (__GLIBC__ >= 2 && __GLIBC_MINOR__ > 0)
+#   define LIBIO_IS_FIXED
+#  endif
+# else
+#  error The libzio requires the GLIBC
+# endif
+#endif
+
+#if defined __GNUC__
+#  if defined __USE_ISOC99
+#    define _cat_pragma(exp)   _Pragma(#exp)
+#    define _weak_pragma(exp)  _cat_pragma(weak name)
+#  else
+#    define _weak_pragma(exp)
+#  endif
+#  define _declare(name)       __extension__ extern __typeof__(name) name
+#  define weak_symbol(name)    _weak_pragma(name) _declare(name) __attribute__((weak))
+#else
+#  error The libzio requires the GCC
+#endif
+
+#if defined(HAS_ZLIB_H)
+# include <zlib.h>
+# ifndef NO_WEAK
+weak_symbol(gzopen);
+weak_symbol(gzdopen);
+weak_symbol(gzread);
+weak_symbol(gzwrite);
+weak_symbol(gzseek);
+weak_symbol(gzflush);
+weak_symbol(gzclose);
+# endif
+#endif
+
+#if defined(HAS_BZLIB_H)
+# include <bzlib.h>
+# ifndef NO_WEAK
+weak_symbol(BZ2_bzopen);
+weak_symbol(BZ2_bzdopen);
+weak_symbol(BZ2_bzread);
+weak_symbol(BZ2_bzwrite);
+/* no BZ2_bzseek */
+weak_symbol(BZ2_bzflush);
+weak_symbol(BZ2_bzclose);
+# endif
+#endif
+
+#if defined(HAS_LZMA_H)
+# include <stdint.h>
+# include <lzma.h>
+# ifndef NO_WEAK
+weak_symbol(lzma_easy_encoder);
+weak_symbol(lzma_lzma_preset);
+weak_symbol(lzma_alone_encoder);
+weak_symbol(lzma_auto_decoder);
+weak_symbol(lzma_code);
+weak_symbol(lzma_end);
+# endif
+#else /* !HAS_LZMA_H */
+# if defined(HAS_LZMADEC_H)
+#  include <stdint.h>
+#  include <lzmadec.h>
+#  ifndef NO_WEAK
+weak_symbol(lzmadec_open);
+weak_symbol(lzmadec_dopen);
+weak_symbol(lzmadec_read);
+/* no lzmadec_write() */
+weak_symbol(lzmadec_seek);
+weak_symbol(lzmadec_close);
+/* no lzmadec_flush() */
+#  endif
+# endif
+#endif /* !HAS_LZMA_H */
+
+#if defined(HAVE_FOPENCOOKIE)
+# undef HAVE_FUNOPEN
+__extension__ typedef off_t   zio_off_t;
+__extension__ typedef int     zio_int_t;
+# if !defined(LIBIO_IS_FIXED)
+__extension__ typedef _IO_cookie_io_functions_t cookie_io_functions_t;
+__extension__ typedef ssize_t cookie_read_function_t  __P ((void *, char *, size_t));
+__extension__ typedef ssize_t cookie_write_function_t __P ((void *, const char *, size_t));
+__extension__ typedef int     cookie_seek_function_t  __P ((void *, off_t, int));
+__extension__ typedef int     cookie_close_function_t __P ((void *));
+# endif
+#endif
+#if defined(HAVE_FUNOPEN)
+__extension__ typedef size_t zio_off_t;
+__extension__ typedef fpos_t zio_int_t;
+__extension__ typedef int    cookie_read_function_t  __P ((void *, char *, int));
+__extension__ typedef int    cookie_write_function_t __P ((void *, const char *, int));
+__extension__ typedef fpos_t cookie_seek_function_t  __P ((void *, fpos_t, int));
+__extension__ typedef int    cookie_close_function_t __P ((void *));
+__extension__ typedef struct
+{
+    cookie_read_function_t  *read;
+    cookie_write_function_t *write;
+    cookie_seek_function_t  *seek;
+    cookie_close_function_t *close;
+} cookie_io_functions_t;
+static __inline__ FILE *fopencookie(void *__restrict,
+                                   const char *__restrict,
+                                   cookie_io_functions_t) nonnull((1,2)) wur;
+static __inline__ FILE *fopencookie(void *__restrict cookie,
+                                   const char *__restrict mode unused,
+                                   cookie_io_functions_t io_funcs)
+{
+    return funopen(cookie, io_funcs.read, io_funcs.write, io_funcs.seek, io_funcs.close);
+}
+#endif
+#endif /* _ZIO_P_H */