From eb9edc9d77d96031c33b5536120421862b4c828a Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Thu, 2 Oct 2008 21:30:30 -0400 Subject: [PATCH] extend the ixp.read() function - can specify the amount to read, defaults to 64k - setting amount to zero removes any limit - if amount is non-zero will inform if more data was available (short read) - improved error reporting --- luaixp/lixp_instance.c | 55 +++++++++++++++++++++++++++++--------- luaixp/lixp_instance.h | 2 ++ luaixp/lixp_util.c | 72 ++++++++++++++++++++++++++++++++++++++++++++------ luaixp/lixp_util.h | 1 + luaixp/test.lua | 29 +++++++++++++++----- 5 files changed, 133 insertions(+), 26 deletions(-) diff --git a/luaixp/lixp_instance.c b/luaixp/lixp_instance.c index ac66e32..c54a76a 100644 --- a/luaixp/lixp_instance.c +++ b/luaixp/lixp_instance.c @@ -67,7 +67,18 @@ int l_ixp_write (lua_State *L) } /* ------------------------------------------------------------------------ - * lua: data = read(file) -- returns all contents (upto 4k) + * lua: data [,short_read] = read(file, [max_buffer_size]) + * -- returns contents of file + * + * max_buffer_size limits the read to IXP_READ_MAX_BUFFER_SIZE by default, but + * can be configured to a different value. Setting max_buffer_size to zero + * means no limit will be applied. + * + * On return data holds the data read, and short_read indicates if there was + * more data that was not read. + * + * If the file contents are expected to be large use l_ixp_iread(), which + * iterates over the file. */ int l_ixp_read (lua_State *L) { @@ -76,49 +87,68 @@ int l_ixp_read (lua_State *L) const char *file; char *buf, *_buf; size_t buf_ofs, buf_size; + lua_Number max_buffer_size; + size_t realloc_size; + int short_read = 1; ixp = lixp_checkixp (L, 1); file = luaL_checkstring (L, 2); + max_buffer_size = luaL_optnumber (L, 3, IXP_READ_MAX_BUFFER_SIZE); fid = ixp_open(ixp->client, file, P9_OREAD); if(fid == NULL) return lixp_pusherror (L, "count not open p9 file"); - buf = malloc (fid->iounit); + buf_size = fid->iounit; + if (max_buffer_size && buf_size > max_buffer_size) + buf_size = max_buffer_size; + buf = malloc (buf_size); if (!buf) { ixp_close(fid); return lixp_pusherror (L, "count not allocate memory"); } buf_ofs = 0; - buf_size = fid->iounit; DBGF("** ixp.read (%s) **\n", file); for (;;) { int rc = ixp_read (fid, buf+buf_ofs, buf_size-buf_ofs); - if (rc==0) + if (rc==0) { + short_read = 0; break; - else if (rc<0) { + + } else if (rc<0) { ixp_close(fid); return lixp_pusherror (L, "failed to read from p9 file"); } buf_ofs += rc; - if (buf_ofs >= buf_size) + if (buf_ofs > buf_size) return lixp_pusherror (L, "internal error while reading"); - if (buf_size >= 4096) + if (buf_ofs == buf_size) + break; + + if (max_buffer_size && buf_size >= max_buffer_size) break; - _buf = realloc (buf, 4096); + realloc_size = max_buffer_size; + if (!max_buffer_size) + realloc_size = buf_size * 2; + + _buf = NULL; + if (realloc_size > buf_size) + _buf = realloc (buf, realloc_size); + if (!_buf) { ixp_close(fid); free(buf); - return lixp_pusherror (L, "count not allocate memory"); + return lixp_pusherrorf(L, "failed to allocate %u bytes", + realloc_size); } buf = _buf; - buf_size = 4096; + buf_size = realloc_size; } ixp_close(fid); @@ -126,8 +156,9 @@ int l_ixp_read (lua_State *L) if (memchr(buf, '\0', buf_ofs)) fprintf(stderr, "** WARNING: ixp.read (%s): result contains null characters **\n", file); - lua_pushlstring (L, buf, buf_ofs); - return 1; + lua_pushlstring(L, buf, buf_ofs); + lua_pushboolean(L, short_read); + return 2; } /* ------------------------------------------------------------------------ diff --git a/luaixp/lixp_instance.h b/luaixp/lixp_instance.h index 5d46fb9..accdb1c 100644 --- a/luaixp/lixp_instance.h +++ b/luaixp/lixp_instance.h @@ -9,6 +9,8 @@ struct IxpClient; #define L_IXP_IDIR_MT "ixp.idir_mt" #define L_IXP_IREAD_MT "ixp.iread_mt" +#define IXP_READ_MAX_BUFFER_SIZE 65536 // max returned by l_ixp_read + /* the C representation of a ixp instance object */ struct ixp { const char *address;; diff --git a/luaixp/lixp_util.c b/luaixp/lixp_util.c index 61a72be..004282e 100644 --- a/luaixp/lixp_util.c +++ b/luaixp/lixp_util.c @@ -2,6 +2,8 @@ #include #include #include +#include +#include #include #include @@ -10,24 +12,78 @@ #include "lixp_util.h" +/* + * Copy src into destination escaping %'s into %%'s; + * + * NOTE: destination buffer must be twice as large as the source. + */ +static inline void copy_escaping_fmt(char *dest, const char *src) +{ + char *d = dest, *pc; + const char *s = src; + + while ((pc = strchr (s, '%'))) { + int len = pc - s + 1; + memcpy(d, s, len); + d += len; + s += len; + *(d++) = '%'; + } + + strcpy(d, s); +} + /* ------------------------------------------------------------------------ * error helper */ -int lixp_pusherror(lua_State *L, const char *info) +int lixp_pusherrorf(lua_State *L, const char *fmt, ...) { + va_list ap; + lua_pushnil(L); - if (info==NULL) { - lua_pushstring(L, strerror(errno)); + if (errno) { + char *_fmt; + const char *estr; + size_t elen; + + estr = strerror(errno); + elen = strlen(estr); + + _fmt = malloc(strlen(fmt) + 2 + (elen*2) + 1); + if (!_fmt) + goto do_short_fmt; + + copy_escaping_fmt(_fmt, estr); + strcat(_fmt, "; "); + strcat(_fmt, fmt); + + va_start(ap, fmt); + lua_pushvfstring(L, _fmt, ap); + va_end(ap); + + free(_fmt); + lua_pushnumber(L, errno); return 3; - } else if (errno) { - lua_pushfstring(L, "%s: %s", info, strerror(errno)); + } + +do_short_fmt: + va_start(ap, fmt); + lua_pushvfstring(L, "%s", ap); + va_end(ap); + return 2; +} + +int lixp_pusherror(lua_State *L, const char *info) +{ + if (info==NULL) { + lua_pushnil(L); + lua_pushstring(L, strerror(errno)); lua_pushnumber(L, errno); return 3; - } else { - lua_pushfstring(L, "%s", info); - return 2; } + + return lixp_pusherrorf(L, "%s", info); } /* ------------------------------------------------------------------------ diff --git a/luaixp/lixp_util.h b/luaixp/lixp_util.h index d4d0ae8..635240c 100644 --- a/luaixp/lixp_util.h +++ b/luaixp/lixp_util.h @@ -15,6 +15,7 @@ struct IxpCFid; struct IxpStat; +extern int lixp_pusherrorf(lua_State *L, const char *fmt, ...); extern int lixp_pusherror(lua_State *L, const char *info); extern int lixp_write_data (struct IxpCFid *fid, const char *data, size_t data_len); diff --git a/luaixp/test.lua b/luaixp/test.lua index 78bbc87..dcbc85c 100755 --- a/luaixp/test.lua +++ b/luaixp/test.lua @@ -2,22 +2,39 @@ require "ixp" -print ("testing...") -ixp.test () +-- print ("testing...") +-- ixp.test () print ("create new ixp...") x = ixp.new("unix!/tmp/ns.bart.:0/wmii") -print ("testing...") -x:test () - +-- print ("testing...") +-- x:test () print ("writing...") x:write ("/lbar/1", '#FF0000 #00FF00 #0000FF 1xxx') print ("reading...") data = x:read ("/lbar/1") -print (data) +print (" " .. data) + +print ("reading with limit...") +data,short = x:read ("/lbar/1", 8) +print (" " .. tostring(data)) +if not data then + print (" ... error: " .. tostring(short) .. ")") +elseif short then + print (" ... short read") +end + +print ("reading a nonexistent file...") +data,short = x:read ("/lbar/xxxxxxxxxxxxxxxxxxxxxxx") +print (" " .. tostring(data)) +if not data then + print (" ... error: " .. short) +elseif short then + print (" ... short read") +end print ("stating...") data = x:stat ("/event") -- 2.11.4.GIT