fix new battery plugin to work better with multiple batteries present
[wmiirc-lua.git] / src / luaixp / lixp_instance.c
blob9d8d82979ebb77b13f1898af68125b8b0a138cd9
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <string.h>
5 #include <errno.h>
6 #include <time.h>
7 #include <signal.h>
9 #include <ixp.h>
10 #include <lua.h>
11 #include <lauxlib.h>
13 #include "lixp_debug.h"
14 #include "lixp_util.h"
15 #include "lixp_instance.h"
18 /* ------------------------------------------------------------------------
19 * utility functions
22 struct ixp *lixp_checkixp (lua_State *L, int narg)
24 void *ud = luaL_checkudata (L, narg, L_IXP_MT);
25 luaL_argcheck (L, ud != NULL, 1, "`ixp' expected");
26 return (struct ixp*)ud;
29 int l_ixp_tostring (lua_State *L)
31 struct ixp *ixp = lixp_checkixp (L, 1);
32 lua_pushfstring (L, "ixp instance %p", ixp);
33 return 1;
36 static int nil_iter (lua_State *L)
38 return 0;
41 /* ------------------------------------------------------------------------
42 * lua: write(file, data) -- writes data to a file
45 int l_ixp_write (lua_State *L)
47 struct ixp *ixp;
48 IxpCFid *fid;
49 const char *file;
50 const char *data;
51 size_t data_len;
52 int rc;
54 ixp = lixp_checkixp (L, 1);
55 file = luaL_checkstring (L, 2);
56 data = luaL_checklstring (L, 3, &data_len);
58 fid = ixp_open(ixp->client, file, P9_OWRITE);
59 if(fid == NULL)
60 return lixp_pusherror (L, "count not open p9 file");
62 DBGF("** ixp.write (%s,%s) **\n", file, data);
64 rc = lixp_write_data (fid, data, data_len);
65 if (rc < 0) {
66 ixp_close(fid);
67 return lixp_pusherror (L, "failed to write to p9 file");
70 ixp_close(fid);
71 return 0;
74 /* ------------------------------------------------------------------------
75 * lua: data [,short_read] = read(file, [max_buffer_size])
76 * -- returns contents of file
78 * max_buffer_size limits the read to IXP_READ_MAX_BUFFER_SIZE by default, but
79 * can be configured to a different value. Setting max_buffer_size to zero
80 * means no limit will be applied.
82 * On return data holds the data read, and short_read indicates if there was
83 * more data that was not read.
85 * If the file contents are expected to be large use l_ixp_iread(), which
86 * iterates over the file.
88 int l_ixp_read (lua_State *L)
90 struct ixp *ixp;
91 IxpCFid *fid;
92 const char *file;
93 char *buf, *_buf;
94 size_t buf_ofs, buf_size;
95 lua_Number max_buffer_size;
96 size_t realloc_size;
97 int short_read = 1;
99 ixp = lixp_checkixp (L, 1);
100 file = luaL_checkstring (L, 2);
101 max_buffer_size = luaL_optnumber (L, 3, IXP_READ_MAX_BUFFER_SIZE);
103 fid = ixp_open(ixp->client, file, P9_OREAD);
104 if(fid == NULL)
105 return lixp_pusherror (L, "count not open p9 file");
107 buf_size = fid->iounit;
108 if (max_buffer_size && buf_size > max_buffer_size)
109 buf_size = max_buffer_size;
110 buf = malloc (buf_size);
111 if (!buf) {
112 ixp_close(fid);
113 return lixp_pusherror (L, "count not allocate memory");
115 buf_ofs = 0;
117 DBGF("** ixp.read (%s) **\n", file);
119 for (;;) {
120 int rc = ixp_read (fid, buf+buf_ofs, buf_size-buf_ofs);
121 if (rc==0) {
122 short_read = 0;
123 break;
125 } else if (rc<0) {
126 ixp_close(fid);
127 return lixp_pusherror (L, "failed to read from p9 file");
130 buf_ofs += rc;
132 if (buf_ofs > buf_size)
133 return lixp_pusherror (L, "internal error while reading");
135 if (buf_ofs == buf_size)
136 break;
138 if (max_buffer_size && buf_size >= max_buffer_size)
139 break;
141 realloc_size = max_buffer_size;
142 if (!max_buffer_size)
143 realloc_size = buf_size * 2;
145 _buf = NULL;
146 if (realloc_size > buf_size)
147 _buf = realloc (buf, realloc_size);
149 if (!_buf) {
150 ixp_close(fid);
151 free(buf);
152 return lixp_pusherrorf(L, "failed to allocate %u bytes",
153 realloc_size);
155 buf = _buf;
156 buf_size = realloc_size;
159 ixp_close(fid);
161 if (memchr(buf, '\0', buf_ofs))
162 fprintf(stderr, "** WARNING: ixp.read (%s): result contains null characters **\n", file);
164 lua_pushlstring(L, buf, buf_ofs);
165 lua_pushboolean(L, short_read);
166 return 2;
169 /* ------------------------------------------------------------------------
170 * lua: create(file, [data]) -- create a file, optionally write data to it
172 int l_ixp_create (lua_State *L)
174 struct ixp *ixp;
175 IxpCFid *fid;
176 const char *file;
177 const char *data;
178 size_t data_len = 0;
180 ixp = lixp_checkixp (L, 1);
181 file = luaL_checkstring (L, 2);
182 data = luaL_optlstring (L, 3, NULL, &data_len);
184 DBGF("** ixp.create (%s) **\n", file);
186 fid = ixp_create (ixp->client, file, 0777, P9_OWRITE);
187 if (!fid)
188 return lixp_pusherror (L, "count not create file");
190 if (data && data_len
191 && !(fid->qid.type & P9_DMDIR)) {
192 int rc = lixp_write_data (fid, data, data_len);
193 if (rc < 0) {
194 ixp_close(fid);
195 return lixp_pusherror (L, "failed to write to p9 file");
199 ixp_close(fid);
200 return 0;
203 /* ------------------------------------------------------------------------
204 * lua: remove(file) -- remove a file
206 int l_ixp_remove (lua_State *L)
208 struct ixp *ixp;
209 int rc;
210 const char *file;
212 ixp = lixp_checkixp (L, 1);
213 file = luaL_checkstring (L, 2);
215 DBGF("** ixp.remove (%s) **\n", file);
217 rc = ixp_remove (ixp->client, file);
218 if (!rc)
219 return lixp_pusherror (L, "failed to remove p9 file");
221 return 0;
224 /* ------------------------------------------------------------------------
225 * lua: itr = iread(file) -- returns a line iterator
228 struct l_ixp_iread_s {
229 IxpCFid *fid;
230 char *buf;
231 size_t buf_pos;
232 size_t buf_len;
233 size_t buf_size;
236 static int iread_iter (lua_State *L);
238 int l_ixp_iread (lua_State *L)
240 struct ixp *ixp;
241 const char *file;
242 struct l_ixp_iread_s *ctx;
244 ixp = lixp_checkixp (L, 1);
245 file = luaL_checkstring (L, 2);
247 ctx = (struct l_ixp_iread_s*)lua_newuserdata (L, sizeof(*ctx));
248 if (!ctx) {
249 DBGF("** ixp.iread (%s) - count not allocate context", file);
250 lua_pushcclosure (L, nil_iter, 1);
251 return 1;
253 memset (ctx, 0, sizeof (*ctx));
255 ctx->fid = ixp_open(ixp->client, file, P9_OREAD);
256 if(ctx->fid == NULL) {
257 DBGF("** ixp.iread (%s) - count not open p9 file", file);
258 lua_pushcclosure (L, nil_iter, 1);
259 return 1;
262 // set the metatable for the new userdata
263 luaL_getmetatable (L, L_IXP_IREAD_MT);
264 lua_setmetatable (L, -2);
266 DBGF("** ixp.iread (%s) - iterator ready **\n", file);
268 // create and return the iterator function
269 // the only argument is the userdata
270 lua_pushcclosure (L, iread_iter, 1);
271 return 1;
274 static int iread_iter (lua_State *L)
276 struct l_ixp_iread_s *ctx;
277 char *s, *cr;
279 ctx = (struct l_ixp_iread_s*)lua_touserdata (L, lua_upvalueindex(1));
281 DBGF("** ixp.iread - iter **\n");
283 if (!ctx->buf) {
284 ctx->buf = malloc (ctx->fid->iounit);
285 if (!ctx->buf)
286 return lixp_pusherror (L, "count not allocate memory");
287 ctx->buf_size = ctx->fid->iounit;
288 ctx->buf_len = 0;
291 if (!ctx->buf_len) {
292 int rc;
293 ctx->buf_pos = 0;
294 rc = ixp_read (ctx->fid, ctx->buf, ctx->buf_size);
295 if (rc <= 0) {
296 return 0; // we are done
298 ctx->buf_len = rc;
301 s = ctx->buf + ctx->buf_pos;
303 cr = strchr (s, '\n');
304 if (!cr) {
305 // no match, just return the whole thing
306 // TODO: should read more upto a cr or some limit
307 if (memchr(s, '\0', ctx->buf_len))
308 fprintf(stderr, "** WARNING: ixp.iread - iter: result contains null characters **\n");
309 lua_pushlstring (L, s, ctx->buf_len);
310 ctx->buf_len = 0;
311 return 1;
313 } else {
314 // we have a match s..cr is our sub string
315 int len = cr-s;
316 if (memchr(s, '\0', len))
317 fprintf(stderr, "** WARNING: ixp.iread - iter: result contains null characters **\n");
318 lua_pushlstring (L, s, len);
319 len++;
320 ctx->buf_pos += len;
321 ctx->buf_len -= len;
322 return 1;
326 static int iread_gc (lua_State *L)
328 struct l_ixp_iread_s *ctx;
330 ctx = (struct l_ixp_iread_s*)lua_touserdata (L, 1);
332 DBGF("** ixp.iread - gc **\n");
334 ixp_close (ctx->fid);
336 if (ctx->buf)
337 free (ctx->buf);
339 return 0;
342 void lixp_init_iread_mt (lua_State *L)
344 luaL_newmetatable(L, L_IXP_IREAD_MT);
346 // setup the __gc field
347 lua_pushstring (L, "__gc");
348 lua_pushcfunction (L, iread_gc);
349 lua_settable (L, -3);
352 /* ------------------------------------------------------------------------
353 * lua: stat = stat(file) -- returns a status table
356 int l_ixp_stat (lua_State *L)
358 struct ixp *ixp;
359 struct IxpStat *stat;
360 const char *file;
361 int rc;
363 ixp = lixp_checkixp (L, 1);
364 file = luaL_checkstring (L, 2);
366 DBGF("** ixp.stat (%s) **\n", file);
368 stat = ixp_stat(ixp->client, file);
369 if(!stat)
370 return lixp_pusherror(L, "cannot stat file");
372 rc = lixp_pushstat (L, stat);
374 ixp_freestat (stat);
376 return rc;
379 /* ------------------------------------------------------------------------
380 * lua: itr = idir(dir) -- returns a file name iterator
383 struct l_ixp_idir_s {
384 IxpCFid *fid;
385 unsigned char *buf;
386 IxpMsg m;
389 static int idir_iter (lua_State *L);
391 int l_ixp_idir (lua_State *L)
393 struct ixp *ixp;
394 const char *file;
395 struct l_ixp_idir_s *ctx;
397 ixp = lixp_checkixp (L, 1);
398 file = luaL_checkstring (L, 2);
400 DBGF("** ixp.idir (%s) **\n", file);
402 ctx = (struct l_ixp_idir_s*)lua_newuserdata (L, sizeof(*ctx));
403 if (!ctx) {
404 DBGF("** ixp.idir (%s) - count not allocate context", file);
405 lua_pushcclosure (L, nil_iter, 1);
406 return 1;
408 memset(ctx, 0, sizeof (*ctx));
410 ctx->fid = ixp_open(ixp->client, file, P9_OREAD);
411 if(ctx->fid == NULL) {
412 DBGF("** ixp.idir (%s) - count not open p9 file", file);
413 lua_pushcclosure (L, nil_iter, 1);
414 return 1;
417 ctx->buf = malloc (ctx->fid->iounit);
418 if (!ctx->buf) {
419 ixp_close (ctx->fid);
420 ctx->fid = NULL;
421 DBGF("** ixp.idir (%s) - count not allocate memory", file);
422 lua_pushcclosure (L, nil_iter, 1);
423 return 1;
426 // set the metatable for the new userdata
427 luaL_getmetatable (L, L_IXP_IDIR_MT);
428 lua_setmetatable (L, -2);
430 DBGF("** ixp.idir (%s) - iterator ready **\n", file);
432 // create and return the iterator function
433 // the only argument is the userdata
434 lua_pushcclosure (L, idir_iter, 1);
435 return 1;
438 static int idir_iter (lua_State *L)
440 struct l_ixp_idir_s *ctx;
441 IxpStat stat;
443 ctx = (struct l_ixp_idir_s*)lua_touserdata (L, lua_upvalueindex(1));
445 DBGF("** ixp.idir - iter **\n");
447 if (ctx->m.pos >= ctx->m.end) {
448 int rc = ixp_read (ctx->fid, ctx->buf, ctx->fid->iounit);
449 if (rc <= 0) {
450 return 0;
453 ctx->m = ixp_message(ctx->buf, rc, MsgUnpack);
454 if (ctx->m.pos >= ctx->m.end)
455 return 0;
458 ixp_pstat(&ctx->m, &stat);
460 return lixp_pushstat (L, &stat);
463 static int idir_gc (lua_State *L)
465 struct l_ixp_idir_s *ctx;
467 ctx = (struct l_ixp_idir_s*)lua_touserdata (L, 1);
469 DBGF("** ixp.idir - gc **\n");
471 free (ctx->buf);
473 ixp_close (ctx->fid);
475 return 0;
478 void lixp_init_idir_mt (lua_State *L)
480 luaL_newmetatable(L, L_IXP_IDIR_MT);
482 // setup the __gc field
483 lua_pushstring (L, "__gc");
484 lua_pushcfunction (L, idir_gc);
485 lua_settable (L, -3);