diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2022-05-26 22:06:27 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2022-05-26 22:06:27 -0700 |
commit | e48572f574e24bae076c909c066f42c4d1f3b3aa (patch) | |
tree | ffea6bfc26da2650a2a6ae10a587573b636c1290 /stream.c | |
parent | 2c185d8d80caff9726ff560e3f3fc9fbf630c77e (diff) | |
download | txr-e48572f574e24bae076c909c066f42c4d1f3b3aa.tar.gz txr-e48572f574e24bae076c909c066f42c4d1f3b3aa.tar.bz2 txr-e48572f574e24bae076c909c066f42c4d1f3b3aa.zip |
First cut at new feature: gzip streams.
* Makefile (OBJS): Conditionally include new gzio.o object file.
* configure: Detect external zlib, setting up new have_zlib
variable in config.make, HAVE_ZLIB in config.h, and also -lz
in conf_ldlibs.
* gzio.[ch]: New files, implementing the stream abstraction
over the gzip file I/O routines in zlib.
* stream.h (struct stdio_mode): New gzip flag and gzlevel
bitfield to hold a value 0 to 9.
(stdio_mode_init_blank, stdio_mode_init_r, stdio_mode_init_rpb):
Update intializers to cover new bitfield members.
* stream.c: Include <zlib.h> and "gzio.h" if HAVE_ZLIB.
(do_parse_mode): Recognize new mode modifier letter "z",
setting the gzip flag in the mode structure. If it's followed
by a digit, set the gziplevel to that value.
(format_mode): Don't output "b" letter for binary mode if
gzip is set, because gzopen interprets "b" differently.
Don't put out "t" if gzip is set. If gzip mode is specified,
do put out the level. If gzip is set, and gziplevel is nonzero
then encode the level: gzopen will understand it.
(open_file): If gzip mode is requested, then open the file
using gzopen mode, a new function in gzio.c. The return a
gzio stream based on the returned gzip file handle. However,
if we are reading, and the gzip stream indicates that it's
not decompressing anything, then we close it and open the
file using an ordinary stream.
(stream_init): Call gzio_init if HAVE_ZLIB is true. This is done
here because the module is integrated with stream.c, and also
so that lib.c doesn't have to know about HAVE_ZLIB and <zlib.h>.
Diffstat (limited to 'stream.c')
-rw-r--r-- | stream.c | 59 |
1 files changed, 53 insertions, 6 deletions
@@ -58,6 +58,9 @@ #if HAVE_WSPAWN || HAVE_SPAWN #include <process.h> #endif +#if HAVE_ZLIB +#include <zlib.h> +#endif #include "alloca.h" #include "lib.h" #include "gc.h" @@ -71,6 +74,9 @@ #include "regex.h" #include "txr.h" #include "buf.h" +#if HAVE_ZLIB +#include "gzio.h" +#endif #define max(a, b) ((a) > (b) ? (a) : (b)) #define min(a, b) ((a) < (b) ? (a) : (b)) @@ -1574,6 +1580,13 @@ static struct stdio_mode do_parse_mode(val mode_str, struct stdio_mode m_dfl, nredir++; break; } + case 'z': + m.gzip = 1; + if (isdigit(convert(unsigned char, ms[1]))) { + m.gzlevel = *++ms - '0'; + break; + } + break; default: m.malformed = 1; return m; @@ -1616,11 +1629,14 @@ static val format_mode(const struct stdio_mode m) *ptr++ = '+'; } - if (m.binary) + if (m.binary && !m.gzip) *ptr++ = 'b'; + if (m.gzip && m.gzlevel) + *ptr++ = '0' + m.gzlevel; + #ifdef __CYGWIN__ - if (!m.binary && (opt_compat == 144 || opt_compat == 145)) + if (!m.gzip && !m.binary && (opt_compat == 144 || opt_compat == 145)) *ptr++ = 't'; #endif @@ -4219,15 +4235,42 @@ val open_file(val path, val mode_str) val self = lit("open-file"); struct stdio_mode m, m_r = stdio_mode_init_r; val norm_mode = normalize_mode(&m, mode_str, m_r, self); - FILE *f = w_fopen_mode(c_str(path, self), c_str(norm_mode, self), m); - if (!f) { +again: + if (!m.gzip) { + FILE *f = w_fopen_mode(c_str(path, self), c_str(norm_mode, self), m); + + if (!f) + goto error; + + return set_mode_props(m, make_stdio_stream(f, path)); + } else { +#if HAVE_ZLIB + gzFile f = w_gzopen_mode(c_str(path, self), c_str(norm_mode, self), + m, self); + + if (!f) + goto error; + + if (m.read && gzdirect(f)) { + gzclose(f); + m.gzip = 0; + goto again; + } + + return make_gzio_stream(f, -1, path, m.write); +#else + uw_ethrowf(file_error_s, lit("~s: not built with zlib support"), + self, nao); +#endif + } + +error: + { int eno = errno; uw_ethrowf(errno_to_file_error(eno), lit("error opening ~s: ~d/~s"), path, num(eno), errno_to_str(eno), nao); } - - return set_mode_props(m, make_stdio_stream(f, path)); } val open_fileno(val fd, val mode_str) @@ -5698,6 +5741,10 @@ void stream_init(void) } } #endif + +#if HAVE_ZLIB + gzio_init(); +#endif } void stream_compat_fixup(int compat_ver) |