diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2015-12-04 06:01:22 -0800 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2015-12-04 06:01:22 -0800 |
commit | a4d8692c9d23fed82f6f594ead826af83608f1c2 (patch) | |
tree | 610d817c1a8d830d769de209295858345fb389ec | |
parent | c790707d517dbf4fa6a8b2695a35b3bc3b784556 (diff) | |
download | txr-a4d8692c9d23fed82f6f594ead826af83608f1c2.tar.gz txr-a4d8692c9d23fed82f6f594ead826af83608f1c2.tar.bz2 txr-a4d8692c9d23fed82f6f594ead826af83608f1c2.zip |
Large file support.
* stream.h (struct strm_ops): seek operation's second argument
is now just a val.
* stream.c (unimpl_seek, null_seek): Second argument is a val,
not cnum, to conform with function pointer in stream
structure.
(stdio_seek): Accept offset as val, which could be a fixnum
or bignum. Use new stdio_ftell and stdio_fseek functions
so large values work.
(seek_stream): No need to convert offset argument to cnum;
pass the val directly to seek virtual function.
* sysif.c (off_t_num, num_off_t, stdio_ftell,
stdio_fseek): New functions.
* sysif.h (OFF_T_MAX, OFF_T_MIN): New preprocessor symbols.
(off_t_num, num_off_t, stdio_ftell, stdio_fseek): Declared.
-rw-r--r-- | stream.c | 18 | ||||
-rw-r--r-- | stream.h | 2 | ||||
-rw-r--r-- | sysif.c | 93 | ||||
-rw-r--r-- | sysif.h | 14 |
4 files changed, 116 insertions, 11 deletions
@@ -55,6 +55,7 @@ #include "signal.h" #include "unwind.h" #include "args.h" +#include "sysif.h" #include "stream.h" #include "utf8.h" #include "eval.h" @@ -152,7 +153,7 @@ static noreturn val unimpl_unget_byte(val stream, int byte) unimpl(stream, lit("unget-byte")); } -static noreturn val unimpl_seek(val stream, cnum off, enum strm_whence whence) +static noreturn val unimpl_seek(val stream, val off, enum strm_whence whence) { unimpl(stream, lit("seek-stream")); } @@ -202,7 +203,7 @@ static val null_flush(val stream) return nil; } -static val null_seek(val stream, cnum off, enum strm_whence whence) +static val null_seek(val stream, val off, enum strm_whence whence) { return nil; } @@ -466,19 +467,17 @@ static val stdio_flush(val stream) ? t : stdio_maybe_error(stream, lit("flushing")); } -static val stdio_seek(val stream, cnum offset, enum strm_whence whence) +static val stdio_seek(val stream, val offset, enum strm_whence whence) { struct stdio_handle *h = coerce(struct stdio_handle *, stream->co.handle); errno = 0; if (h->f != 0) { - if (offset == 0 && whence == strm_cur) { - long where = ftell(h->f); - if (where >= 0) - return num(where); + if (offset == zero && whence == strm_cur) { + return stdio_ftell(h->f); } else { - if (fseek(h->f, offset, whence) == 0) { + if (stdio_fseek(h->f, offset, whence) != negone) { utf8_decoder_init(&h->ud); h->unget_c = nil; return t; @@ -2754,7 +2753,6 @@ val seek_stream(val stream, val offset, val whence) { struct strm_ops *ops = coerce(struct strm_ops *, cobj_ops(stream, stream_s)); enum strm_whence w; - cnum off = c_num(offset); if (whence == from_start_k) w = strm_start; @@ -2766,7 +2764,7 @@ val seek_stream(val stream, val offset, val whence) uw_throwf(file_error_s, lit("seek: ~a is not a valid whence argument"), whence, nao); - return ops->seek(stream, off, w); + return ops->seek(stream, offset, w); } val truncate_stream(val stream, val len) @@ -57,7 +57,7 @@ struct strm_ops { val (*unget_byte)(val, int); val (*close)(val, val); val (*flush)(val); - val (*seek)(val, cnum, enum strm_whence); + val (*seek)(val, val, enum strm_whence); val (*truncate)(val, val); val (*get_prop)(val, val ind); val (*set_prop)(val, val ind, val); @@ -72,6 +72,7 @@ #include "eval.h" #include "args.h" #include "struct.h" +#include "arith.h" #include "txr.h" #include "sysif.h" @@ -1036,6 +1037,98 @@ static val getgrnam_wrap(val wname) #endif +off_t off_t_num(val num) +{ + switch (type(num)) { + case NUM: + if (sizeof (cnum) <= sizeof (off_t)) { + return c_num(num); + } else { + cnum n = c_num(num); + if (n > OFF_T_MAX || n < OFF_T_MIN) + goto toobig; + return n; + } + case BGNUM: + { + const int odig = (sizeof (off_t) / sizeof (mp_digit)); + int i; + off_t out; + mp_int *mpn = mp(num); + + if (odig > 1) { + if (USED(mpn) > odig) + goto toobig; + + if (USED(mpn) == odig && + (DIGITS(mpn)[USED(mpn) - 1] >> (MP_DIGIT_BIT - 1)) != 0) + goto toobig; + + for (out = 0, i = USED(mpn) - 1; i >= 0; i--) { + out <<= MP_DIGIT_BIT * (odig > 1); + out |= DIGITS(mpn)[i]; + } + + return (ISNEG(mpn)) ? -out : out; + } else { + mp_digit d = DIGITS(mpn)[0]; + + if (USED(mpn) > 1) + goto toobig; + + if (d > OFF_T_MAX) + goto toobig; + + return (ISNEG(mpn)) ? d : -d; + } + } + default: + uw_throwf(error_s, lit("~s isn't a file offset"), num, nao); + toobig: + uw_throwf(error_s, lit("~s cannot fit into a file offset"), num, nao); + } +} + +val num_off_t(off_t off) +{ + if (sizeof (off_t) <= sizeof (cnum)) { + return num(off); + } else if (NUM_MIN <= off && off <= NUM_MAX) { + return num(off); + } else { +#if HAVE_DOUBLE_INTPTR_T + if (sizeof (off_t) <= sizeof (double_intptr_t)) { + val n = make_bignum(); + mp_set_double_intptr(mp(n), off); + return n; + } else { + abort(); + } +#else +#error port me! +#endif + } +} + +val stdio_ftell(FILE *f) +{ +#if HAVE_FSEEKO + return num_off_t(ftello(f)); +#else + return num_off_t(ftell(f)); +#endif +} + +val stdio_fseek(FILE *f, val off, int whence) +{ +#if HAVE_FSEEKO + return num_off_t(fseeko(f, off_t_num(off), whence)); +#else + int ret = fseek(f, off_t_num(off), whence); + return (ret == -1) ? num_fast(ret) : stdio_ftell(f); +#endif +} + void sysif_init(void) { stat_s = intern(lit("stat"), user_package); @@ -32,7 +32,21 @@ extern val dev_s, ino_s, mode_s, nlink_s, uid_s; extern val gid_s, rdev_s, size_s, blksize_s, blocks_s; extern val atime_s, mtime_s, ctime_s; +#if !HAVE_FTRUNCATE +typedef long off_t; +#define OFF_T_MAX LONG_MAX +#define OFF_T_MIN LONG_MIN +#else +#define OFF_T_MAX ((((convert(off_t, 1) << \ + ((sizeof(off_t) * CHAR_BIT) - 2)) - 1) << 1) + 1) +#define OFF_T_MIN (-OFF_T_MAX) +#endif + val getenv_wrap(val name); val statp(val path); val statf(val path); +off_t off_t_num(val num); +val num_off_t(off_t offnum); +val stdio_ftell(FILE *); +val stdio_fseek(FILE *, val, int whence); void sysif_init(void); |