summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2015-12-04 06:01:22 -0800
committerKaz Kylheku <kaz@kylheku.com>2015-12-04 06:01:22 -0800
commita4d8692c9d23fed82f6f594ead826af83608f1c2 (patch)
tree610d817c1a8d830d769de209295858345fb389ec
parentc790707d517dbf4fa6a8b2695a35b3bc3b784556 (diff)
downloadtxr-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.c18
-rw-r--r--stream.h2
-rw-r--r--sysif.c93
-rw-r--r--sysif.h14
4 files changed, 116 insertions, 11 deletions
diff --git a/stream.c b/stream.c
index 54f7533d..fd170bc0 100644
--- a/stream.c
+++ b/stream.c
@@ -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)
diff --git a/stream.h b/stream.h
index d3ec649a..bfaf76c9 100644
--- a/stream.h
+++ b/stream.h
@@ -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);
diff --git a/sysif.c b/sysif.c
index 7c6f697d..95a65c5d 100644
--- a/sysif.c
+++ b/sysif.c
@@ -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);
diff --git a/sysif.h b/sysif.h
index 22e87b89..ea4b69d7 100644
--- a/sysif.h
+++ b/sysif.h
@@ -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);