1 /*************************************************************************************************
2 * Scripting language extension of Tokyo Tyrant
3 * Copyright (C) 2006-2010 FAL Labs
4 * This file is part of Tokyo Tyrant.
5 * Tokyo Tyrant is free software; you can redistribute it and/or modify it under the terms of
6 * the GNU Lesser General Public License as published by the Free Software Foundation; either
7 * version 2.1 of the License or any later version. Tokyo Tyrant is distributed in the hope
8 * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
10 * License for more details.
11 * You should have received a copy of the GNU Lesser General Public License along with Tokyo
12 * Tyrant; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
13 * Boston, MA 02111-1307 USA.
14 *************************************************************************************************/
15
16
17 #include "scrext.h"
18
19
20
21 /*************************************************************************************************
22 * by default
23 *************************************************************************************************/
24
25
26 #if defined(TTNOEXT)
27
28
29 typedef struct _SCREXT { // type of structure of the script extension
30 struct _SCREXT **screxts; // script extension objects
31 int thnum; // number of native threads
32 int thid; // thread ID
33 char *path; // path of the initializing script
34 TCADB *adb; // abstract database object
35 TCULOG *ulog; // update log object
36 uint32_t sid; // server ID
37 TCMDB *stash; // global stash object
38 TCMDB *lock; // global lock object
39 void (*logger)(int, const char *, void *); // logging function
40 void *logopq; // opaque pointer for the logging function
41 bool term; // terminate flag
42 } SCREXT;
43
44
45 /* Initialize the global scripting language extension. */
scrextnew(void ** screxts,int thnum,int thid,const char * path,TCADB * adb,TCULOG * ulog,uint32_t sid,TCMDB * stash,TCMDB * lock,void (* logger)(int,const char *,void *),void * logopq)46 void *scrextnew(void **screxts, int thnum, int thid, const char *path,
47 TCADB *adb, TCULOG *ulog, uint32_t sid, TCMDB *stash, TCMDB *lock,
48 void (*logger)(int, const char *, void *), void *logopq){
49 SCREXT *scr = tcmalloc(sizeof(*scr));
50 scr->screxts = (SCREXT **)screxts;
51 scr->thnum = thnum;
52 scr->thid = thid;
53 scr->path = tcstrdup(path);
54 scr->adb = adb;
55 scr->ulog = ulog;
56 scr->sid = sid;
57 scr->stash = stash;
58 scr->lock = lock;
59 scr->logger = logger;
60 scr->logopq = logopq;
61 scr->term = false;
62 return scr;
63 }
64
65
66 /* Destroy the global scripting language extension. */
scrextdel(void * scr)67 bool scrextdel(void *scr){
68 SCREXT *myscr = scr;
69 tcfree(myscr->path);
70 tcfree(myscr);
71 return true;
72 }
73
74
75 /* Call a method of the scripting language extension. */
scrextcallmethod(void * scr,const char * name,const void * kbuf,int ksiz,const void * vbuf,int vsiz,int * sp)76 char *scrextcallmethod(void *scr, const char *name,
77 const void *kbuf, int ksiz, const void *vbuf, int vsiz, int *sp){
78 SCREXT *myscr = scr;
79 if(!strcmp(name, "put")){
80 if(!tculogadbput(myscr->ulog, myscr->sid, 0, myscr->adb, kbuf, ksiz, vbuf, vsiz))
81 return NULL;
82 char *msg = tcstrdup("ok");
83 *sp = strlen(msg);
84 return msg;
85 } else if(!strcmp(name, "putkeep")){
86 if(!tculogadbputkeep(myscr->ulog, myscr->sid, 0, myscr->adb, kbuf, ksiz, vbuf, vsiz))
87 return NULL;
88 char *msg = tcstrdup("ok");
89 *sp = strlen(msg);
90 return msg;
91 } else if(!strcmp(name, "putcat")){
92 if(!tculogadbputcat(myscr->ulog, myscr->sid, 0, myscr->adb, kbuf, ksiz, vbuf, vsiz))
93 return NULL;
94 char *msg = tcstrdup("ok");
95 *sp = strlen(msg);
96 return msg;
97 } else if(!strcmp(name, "out")){
98 if(!tculogadbout(myscr->ulog, myscr->sid, 0, myscr->adb, kbuf, ksiz)) return NULL;
99 char *msg = tcstrdup("ok");
100 *sp = strlen(msg);
101 return msg;
102 } else if(!strcmp(name, "get")){
103 return tcadbget(myscr->adb, kbuf, ksiz, sp);
104 } else if(!strcmp(name, "log")){
105 char *msg = tcmemdup(kbuf, ksiz);
106 myscr->logger(TTLOGINFO, msg, myscr->logopq);
107 tcfree(msg);
108 msg = tcstrdup("ok");
109 *sp = strlen(msg);
110 return msg;
111 }
112 int psiz = strlen(myscr->path);
113 int nsiz = strlen(name);
114 char *msg = tcmalloc(psiz + nsiz + ksiz + vsiz + 4);
115 char *wp = msg;
116 memcpy(wp, myscr->path, psiz);
117 wp += psiz;
118 *(wp++) = ':';
119 memcpy(wp, name, nsiz);
120 wp += nsiz;
121 *(wp++) = ':';
122 memcpy(wp, kbuf, ksiz);
123 wp += ksiz;
124 *(wp++) = ':';
125 memcpy(wp, vbuf, vsiz);
126 wp += vsiz;
127 *sp = wp - msg;
128 return msg;
129 }
130
131
132 /* Send the terminate signal to the scripting language extension */
scrextkill(void * scr)133 bool scrextkill(void *scr){
134 SCREXT *myscr = scr;
135 myscr->term = true;
136 return true;
137 }
138
139
140 #endif
141
142
143
144 /*************************************************************************************************
145 * for Lua
146 *************************************************************************************************/
147
148
149 #if defined(TTLUAEXT)
150
151
152 #include "lua.h"
153 #include "lualib.h"
154 #include "lauxlib.h"
155
156 #ifdef LUA_VERSION_NUM
157 # if (LUA_VERSION_NUM >= 502)
158 #undef lua_objlen
159 #define lua_objlen lua_rawlen
160 # endif
161 #endif
162
163 #define SERVVAR "_serv_" // global variable name for server resources
164 #define ITERVAR "_iter_" // global variable name for iterator
165 #define MRMAPVAR "_mrmap_" // global variable name for mapreduce mapper
166 #define MRREDVAR "_mrred_" // global variable name for mapreduce reducer
167 #define MRPOOLVAR "_mrpool_" // global variable name for mapreduce pool
168
169 typedef struct { // type of structure of the script extension
170 lua_State *lua; // Lua environment
171 int thnum; // number of native threads
172 int thid; // thread ID
173 } SCREXT;
174
175 typedef struct { // type of structure of the server data
176 SCREXT **screxts; // script extension objects
177 int thnum; // number of native threads
178 int thid; // thread ID
179 TCADB *adb; // abstract database object
180 TCULOG *ulog; // update log object
181 uint32_t sid; // server ID
182 TCMDB *stash; // global stash object
183 TCMDB *lock; // global lock object
184 pthread_mutex_t *lcks; // mutex for user locks
185 int lcknum; // number of user locks
186 void (*logger)(int, const char *, void *); // logging function
187 void *logopq; // opaque pointer for the logging function
188 bool term; // terminate flag
189 } SERV;
190
191
192 /* private function prototypes */
193 static void reporterror(lua_State *lua);
194 static bool iterrec(const void *kbuf, int ksiz, const void *vbuf, int vsiz, lua_State *lua);
195 static int serv_eval(lua_State *lua);
196 static int serv_log(lua_State *lua);
197 static int serv_put(lua_State *lua);
198 static int serv_putkeep(lua_State *lua);
199 static int serv_putcat(lua_State *lua);
200 static int serv_out(lua_State *lua);
201 static int serv_get(lua_State *lua);
202 static int serv_vsiz(lua_State *lua);
203 static int serv_iterinit(lua_State *lua);
204 static int serv_iternext(lua_State *lua);
205 static int serv_fwmkeys(lua_State *lua);
206 static int serv_addint(lua_State *lua);
207 static int serv_adddouble(lua_State *lua);
208 static int serv_vanish(lua_State *lua);
209 static int serv_rnum(lua_State *lua);
210 static int serv_size(lua_State *lua);
211 static int serv_misc(lua_State *lua);
212 static int serv_foreach(lua_State *lua);
213 static int serv_mapreduce(lua_State *lua);
214 static int serv_mapreducemapemit(lua_State *lua);
215 static int serv_stashput(lua_State *lua);
216 static int serv_stashputkeep(lua_State *lua);
217 static int serv_stashputcat(lua_State *lua);
218 static int serv_stashout(lua_State *lua);
219 static int serv_stashget(lua_State *lua);
220 static int serv_stashvanish(lua_State *lua);
221 static int serv_stashforeach(lua_State *lua);
222 static int serv_lock(lua_State *lua);
223 static int serv_unlock(lua_State *lua);
224 static int serv_pack(lua_State *lua);
225 static int serv_unpack(lua_State *lua);
226 static int serv_split(lua_State *lua);
227 static int serv_codec(lua_State *lua);
228 static int serv_hash(lua_State *lua);
229 static int serv_bit(lua_State *lua);
230 static int serv_strstr(lua_State *lua);
231 static int serv_regex(lua_State *lua);
232 static int serv_ucs(lua_State *lua);
233 static int serv_dist(lua_State *lua);
234 static int serv_isect(lua_State *lua);
235 static int serv_union(lua_State *lua);
236 static int serv_time(lua_State *lua);
237 static int serv_sleep(lua_State *lua);
238 static int serv_stat(lua_State *lua);
239 static int serv_glob(lua_State *lua);
240 static int serv_remove(lua_State *lua);
241 static int serv_mkdir(lua_State *lua);
242
243
244 /* Initialize the global scripting language extension. */
scrextnew(void ** screxts,int thnum,int thid,const char * path,TCADB * adb,TCULOG * ulog,uint32_t sid,TCMDB * stash,TCMDB * lock,void (* logger)(int,const char *,void *),void * logopq)245 void *scrextnew(void **screxts, int thnum, int thid, const char *path,
246 TCADB *adb, TCULOG *ulog, uint32_t sid, TCMDB *stash, TCMDB *lock,
247 void (*logger)(int, const char *, void *), void *logopq){
248 char *ibuf;
249 int isiz;
250 if(*path == '@'){
251 ibuf = tcstrdup(path + 1);
252 isiz = strlen(ibuf);
253 } else if(*path != '\0'){
254 ibuf = tcreadfile(path, 0, &isiz);
255 } else {
256 ibuf = tcmemdup("", 0);
257 isiz = 0;
258 }
259 if(!ibuf) return NULL;
260 lua_State *lua = luaL_newstate();
261 if(!lua){
262 tcfree(ibuf);
263 return NULL;
264 }
265 luaL_openlibs(lua);
266 lua_settop(lua, 0);
267 SERV *serv = lua_newuserdata(lua, sizeof(*serv));
268 serv->screxts = (SCREXT **)screxts;
269 serv->thnum = thnum;
270 serv->thid = thid;
271 serv->adb = adb;
272 serv->ulog = ulog;
273 serv->sid = sid;
274 serv->stash = stash;
275 serv->lock = lock;
276 serv->logger = logger;
277 serv->logopq = logopq;
278 serv->term = false;
279 lua_setglobal(lua, SERVVAR);
280 lua_register(lua, "_eval", serv_eval);
281 lua_register(lua, "_log", serv_log);
282 lua_register(lua, "_put", serv_put);
283 lua_register(lua, "_putkeep", serv_putkeep);
284 lua_register(lua, "_putcat", serv_putcat);
285 lua_register(lua, "_out", serv_out);
286 lua_register(lua, "_get", serv_get);
287 lua_register(lua, "_vsiz", serv_vsiz);
288 lua_register(lua, "_iterinit", serv_iterinit);
289 lua_register(lua, "_iternext", serv_iternext);
290 lua_register(lua, "_fwmkeys", serv_fwmkeys);
291 lua_register(lua, "_addint", serv_addint);
292 lua_register(lua, "_adddouble", serv_adddouble);
293 lua_register(lua, "_vanish", serv_vanish);
294 lua_register(lua, "_rnum", serv_rnum);
295 lua_register(lua, "_size", serv_size);
296 lua_register(lua, "_misc", serv_misc);
297 lua_register(lua, "_foreach", serv_foreach);
298 lua_register(lua, "_mapreduce", serv_mapreduce);
299 lua_register(lua, "_stashput", serv_stashput);
300 lua_register(lua, "_stashputkeep", serv_stashputkeep);
301 lua_register(lua, "_stashputcat", serv_stashputcat);
302 lua_register(lua, "_stashout", serv_stashout);
303 lua_register(lua, "_stashget", serv_stashget);
304 lua_register(lua, "_stashvanish", serv_stashvanish);
305 lua_register(lua, "_stashforeach", serv_stashforeach);
306 lua_register(lua, "_lock", serv_lock);
307 lua_register(lua, "_unlock", serv_unlock);
308 lua_register(lua, "_pack", serv_pack);
309 lua_register(lua, "_unpack", serv_unpack);
310 lua_register(lua, "_split", serv_split);
311 lua_register(lua, "_codec", serv_codec);
312 lua_register(lua, "_hash", serv_hash);
313 lua_register(lua, "_bit", serv_bit);
314 lua_register(lua, "_strstr", serv_strstr);
315 lua_register(lua, "_regex", serv_regex);
316 lua_register(lua, "_ucs", serv_ucs);
317 lua_register(lua, "_dist", serv_dist);
318 lua_register(lua, "_isect", serv_isect);
319 lua_register(lua, "_union", serv_union);
320 lua_register(lua, "_time", serv_time);
321 lua_register(lua, "_sleep", serv_sleep);
322 lua_register(lua, "_stat", serv_stat);
323 lua_register(lua, "_glob", serv_glob);
324 lua_register(lua, "_remove", serv_remove);
325 lua_register(lua, "_mkdir", serv_mkdir);
326 lua_pushstring(lua, ttversion);
327 lua_setglobal(lua, "_version");
328 lua_pushinteger(lua, getpid());
329 lua_setglobal(lua, "_pid");
330 lua_pushinteger(lua, sid);
331 lua_setglobal(lua, "_sid");
332 lua_pushinteger(lua, thnum);
333 lua_setglobal(lua, "_thnum");
334 lua_pushinteger(lua, thid + 1);
335 lua_setglobal(lua, "_thid");
336 lua_settop(lua, 0);
337 if(luaL_loadstring(lua, ibuf) != 0 || lua_pcall(lua, 0, 0, 0) != 0) reporterror(lua);
338 tcfree(ibuf);
339 if(thid == 0){
340 lua_getglobal(lua, "_begin");
341 if(lua_isfunction(lua, -1) && lua_pcall(lua, 0, 0, 0) != 0) reporterror(lua);
342 }
343 lua_settop(lua, 0);
344 SCREXT *scr = tcmalloc(sizeof(*scr));
345 scr->lua = lua;
346 scr->thnum = thnum;
347 scr->thid = thid;
348 return scr;
349 }
350
351
352 /* Destroy the global scripting language extension. */
scrextdel(void * scr)353 bool scrextdel(void *scr){
354 SCREXT *myscr = scr;
355 lua_State *lua = myscr->lua;
356 if(myscr->thid == 0){
357 lua_getglobal(lua, "_end");
358 if(lua_isfunction(lua, -1) && lua_pcall(lua, 0, 0, 0) != 0) reporterror(lua);
359 }
360 lua_close(lua);
361 tcfree(scr);
362 return true;
363 }
364
365
366 /* Call a method of the scripting language extension. */
scrextcallmethod(void * scr,const char * name,const void * kbuf,int ksiz,const void * vbuf,int vsiz,int * sp)367 char *scrextcallmethod(void *scr, const char *name,
368 const void *kbuf, int ksiz, const void *vbuf, int vsiz, int *sp){
369 SCREXT *myscr = scr;
370 lua_State *lua = myscr->lua;
371 if(*name == '_') return NULL;
372 lua_getglobal(lua, name);
373 if(lua_gettop(lua) != 1 || !lua_isfunction(lua, 1)){
374 lua_settop(lua, 0);
375 return NULL;
376 }
377 lua_pushlstring(lua, kbuf, ksiz);
378 lua_pushlstring(lua, vbuf, vsiz);
379 if(lua_pcall(lua, 2, 1, 0) != 0){
380 reporterror(lua);
381 lua_settop(lua, 0);
382 return NULL;
383 }
384 if(lua_gettop(lua) < 1) return NULL;
385 const char *rbuf = NULL;
386 size_t rsiz;
387 switch(lua_type(lua, 1)){
388 case LUA_TNUMBER:
389 case LUA_TSTRING:
390 rbuf = lua_tolstring(lua, 1, &rsiz);
391 break;
392 case LUA_TBOOLEAN:
393 if(lua_toboolean(lua, 1)){
394 rbuf = "true";
395 rsiz = strlen(rbuf);
396 }
397 break;
398 case LUA_TTABLE:
399 if(lua_objlen(lua, 1) > 0){
400 lua_rawgeti(lua, 1, 1);
401 switch(lua_type(lua, -1)){
402 case LUA_TNUMBER:
403 case LUA_TSTRING:
404 rbuf = lua_tolstring(lua, -1, &rsiz);
405 break;
406 case LUA_TBOOLEAN:
407 if(lua_toboolean(lua, -1)){
408 rbuf = "true";
409 rsiz = strlen(rbuf);
410 }
411 break;
412 }
413 lua_pop(lua, 1);
414 }
415 break;
416 }
417 if(!rbuf){
418 lua_settop(lua, 0);
419 return NULL;
420 }
421 char *rv = tcmemdup(rbuf, rsiz);
422 *sp = rsiz;
423 lua_settop(lua, 0);
424 return rv;
425 }
426
427
428 /* Send the terminate signal to the scripting language extension */
scrextkill(void * scr)429 bool scrextkill(void *scr){
430 SCREXT *myscr = scr;
431 lua_State *lua = myscr->lua;
432 lua_getglobal(lua, SERVVAR);
433 SERV *serv = lua_touserdata(lua, -1);
434 serv->term = true;
435 return true;
436 }
437
438
439 /* report an error of Lua program */
reporterror(lua_State * lua)440 static void reporterror(lua_State *lua){
441 int argc = lua_gettop(lua);
442 char *msg = tcsprintf("Lua error: %s", argc > 0 ? lua_tostring(lua, argc) : "unknown");
443 lua_getglobal(lua, SERVVAR);
444 SERV *serv = lua_touserdata(lua, -1);
445 serv->logger(TTLOGERROR, msg, serv->logopq);
446 tcfree(msg);
447 }
448
449
450 /* call function for each record */
iterrec(const void * kbuf,int ksiz,const void * vbuf,int vsiz,lua_State * lua)451 static bool iterrec(const void *kbuf, int ksiz, const void *vbuf, int vsiz, lua_State *lua){
452 int top = lua_gettop(lua);
453 lua_getglobal(lua, ITERVAR);
454 lua_pushlstring(lua, kbuf, ksiz);
455 lua_pushlstring(lua, vbuf, vsiz);
456 bool err = false;
457 if(lua_pcall(lua, 2, 1, 0) == 0){
458 if(lua_gettop(lua) <= top || !lua_toboolean(lua, -1)) err = true;
459 } else {
460 reporterror(lua);
461 err = true;
462 }
463 lua_settop(lua, top);
464 return !err;
465 }
466
467
468 /* call function to map records for mapreduce */
maprec(void * map,const void * kbuf,int ksiz,const void * vbuf,int vsiz,lua_State * lua)469 static bool maprec(void *map, const void *kbuf, int ksiz, const void *vbuf, int vsiz,
470 lua_State *lua){
471 lua_pushlightuserdata(lua, map);
472 lua_setglobal(lua, MRPOOLVAR);
473 int top = lua_gettop(lua);
474 lua_getglobal(lua, MRMAPVAR);
475 lua_pushlstring(lua, kbuf, ksiz);
476 lua_pushlstring(lua, vbuf, vsiz);
477 lua_pushcfunction(lua, serv_mapreducemapemit);
478 bool err = false;
479 if(lua_pcall(lua, 3, 1, 0) == 0){
480 if(lua_gettop(lua) < 1 && !lua_toboolean(lua, 1)) err = true;
481 } else {
482 reporterror(lua);
483 err = true;
484 }
485 lua_settop(lua, top);
486 return !err;
487 }
488
489
490 /* for _eval function */
serv_eval(lua_State * lua)491 static int serv_eval(lua_State *lua){
492 int argc = lua_gettop(lua);
493 if(argc != 1){
494 lua_pushstring(lua, "_eval: invalid arguments");
495 lua_error(lua);
496 }
497 const char *expr = lua_tostring(lua, 1);
498 if(!expr){
499 lua_pushstring(lua, "_eval: invalid arguments");
500 lua_error(lua);
501 }
502 lua_getglobal(lua, SERVVAR);
503 SERV *serv = lua_touserdata(lua, -1);
504 SCREXT **screxts = serv->screxts;
505 int thnum = serv->thnum;
506 bool err = false;
507 for(int i = 0; i < thnum; i++){
508 if(!screxts[i]){
509 lua_pushstring(lua, "_eval: not ready");
510 lua_error(lua);
511 }
512 }
513 for(int i = 0; i < thnum; i++){
514 lua_State *elua = screxts[i]->lua;
515 if(luaL_loadstring(elua, expr) != 0 || lua_pcall(elua, 0, 0, 0) != 0) reporterror(elua);
516 }
517 lua_settop(lua, 0);
518 lua_pushboolean(lua, !err);
519 return 1;
520 }
521
522
523 /* for _log function */
serv_log(lua_State * lua)524 static int serv_log(lua_State *lua){
525 int argc = lua_gettop(lua);
526 if(argc < 1){
527 lua_pushstring(lua, "_log: invalid arguments");
528 lua_error(lua);
529 }
530 const char *msg = lua_tostring(lua, 1);
531 if(!msg){
532 lua_pushstring(lua, "_log: invalid arguments");
533 lua_error(lua);
534 }
535 int level = TTLOGINFO;
536 if(argc > 1) level = lua_tointeger(lua, 2);
537 lua_getglobal(lua, SERVVAR);
538 SERV *serv = lua_touserdata(lua, -1);
539 serv->logger(level, msg, serv->logopq);
540 lua_settop(lua, 0);
541 return 0;
542 }
543
544
545 /* for _put function */
serv_put(lua_State * lua)546 static int serv_put(lua_State *lua){
547 int argc = lua_gettop(lua);
548 if(argc != 2){
549 lua_pushstring(lua, "_put: invalid arguments");
550 lua_error(lua);
551 }
552 size_t ksiz;
553 const char *kbuf = lua_tolstring(lua, 1, &ksiz);
554 size_t vsiz;
555 const char *vbuf = lua_tolstring(lua, 2, &vsiz);
556 if(!kbuf || !vbuf){
557 lua_pushstring(lua, "_put: invalid arguments");
558 lua_error(lua);
559 }
560 lua_getglobal(lua, SERVVAR);
561 SERV *serv = lua_touserdata(lua, -1);
562 bool rv = tculogadbput(serv->ulog, serv->sid, 0, serv->adb, kbuf, ksiz, vbuf, vsiz);
563 lua_settop(lua, 0);
564 lua_pushboolean(lua, rv);
565 return 1;
566 }
567
568
569 /* for _putkeep function */
serv_putkeep(lua_State * lua)570 static int serv_putkeep(lua_State *lua){
571 int argc = lua_gettop(lua);
572 if(argc != 2){
573 lua_pushstring(lua, "_putkeep: invalid arguments");
574 lua_error(lua);
575 }
576 size_t ksiz;
577 const char *kbuf = lua_tolstring(lua, 1, &ksiz);
578 size_t vsiz;
579 const char *vbuf = lua_tolstring(lua, 2, &vsiz);
580 if(!kbuf || !vbuf){
581 lua_pushstring(lua, "_putkeep: invalid arguments");
582 lua_error(lua);
583 }
584 lua_getglobal(lua, SERVVAR);
585 SERV *serv = lua_touserdata(lua, -1);
586 bool rv = tculogadbputkeep(serv->ulog, serv->sid, 0, serv->adb, kbuf, ksiz, vbuf, vsiz);
587 lua_settop(lua, 0);
588 lua_pushboolean(lua, rv);
589 return 1;
590 }
591
592
593 /* for _putcat function */
serv_putcat(lua_State * lua)594 static int serv_putcat(lua_State *lua){
595 int argc = lua_gettop(lua);
596 if(argc != 2){
597 lua_pushstring(lua, "_putcat: invalid arguments");
598 lua_error(lua);
599 }
600 size_t ksiz;
601 const char *kbuf = lua_tolstring(lua, 1, &ksiz);
602 size_t vsiz;
603 const char *vbuf = lua_tolstring(lua, 2, &vsiz);
604 if(!kbuf || !vbuf){
605 lua_pushstring(lua, "_putcat: invalid arguments");
606 lua_error(lua);
607 }
608 lua_getglobal(lua, SERVVAR);
609 SERV *serv = lua_touserdata(lua, -1);
610 bool rv = tculogadbputcat(serv->ulog, serv->sid, 0, serv->adb, kbuf, ksiz, vbuf, vsiz);
611 lua_settop(lua, 0);
612 lua_pushboolean(lua, rv);
613 return 1;
614 }
615
616
617 /* for _putout function */
serv_out(lua_State * lua)618 static int serv_out(lua_State *lua){
619 int argc = lua_gettop(lua);
620 if(argc != 1){
621 lua_pushstring(lua, "_out: invalid arguments");
622 lua_error(lua);
623 }
624 size_t ksiz;
625 const char *kbuf = lua_tolstring(lua, 1, &ksiz);
626 if(!kbuf){
627 lua_pushstring(lua, "_out: invalid arguments");
628 lua_error(lua);
629 }
630 lua_getglobal(lua, SERVVAR);
631 SERV *serv = lua_touserdata(lua, -1);
632 bool rv = tculogadbout(serv->ulog, serv->sid, 0, serv->adb, kbuf, ksiz);
633 lua_settop(lua, 0);
634 lua_pushboolean(lua, rv);
635 return 1;
636 }
637
638
639 /* for _get function */
serv_get(lua_State * lua)640 static int serv_get(lua_State *lua){
641 int argc = lua_gettop(lua);
642 if(argc != 1){
643 lua_pushstring(lua, "_get: invalid arguments");
644 lua_error(lua);
645 }
646 size_t ksiz;
647 const char *kbuf = lua_tolstring(lua, 1, &ksiz);
648 if(!kbuf){
649 lua_pushstring(lua, "_get: invalid arguments");
650 lua_error(lua);
651 }
652 lua_getglobal(lua, SERVVAR);
653 SERV *serv = lua_touserdata(lua, -1);
654 int vsiz;
655 char *vbuf = tcadbget(serv->adb, kbuf, ksiz, &vsiz);
656 lua_settop(lua, 0);
657 if(vbuf){
658 lua_pushlstring(lua, vbuf, vsiz);
659 tcfree(vbuf);
660 } else {
661 lua_pushnil(lua);
662 }
663 return 1;
664 }
665
666
667 /* for _vsiz function */
serv_vsiz(lua_State * lua)668 static int serv_vsiz(lua_State *lua){
669 int argc = lua_gettop(lua);
670 if(argc != 1){
671 lua_pushstring(lua, "_vsiz: invalid arguments");
672 lua_error(lua);
673 }
674 size_t ksiz;
675 const char *kbuf = lua_tolstring(lua, 1, &ksiz);
676 if(!kbuf){
677 lua_pushstring(lua, "_vsiz: invalid arguments");
678 lua_error(lua);
679 }
680 lua_getglobal(lua, SERVVAR);
681 SERV *serv = lua_touserdata(lua, -1);
682 int vsiz = tcadbvsiz(serv->adb, kbuf, ksiz);
683 lua_settop(lua, 0);
684 lua_pushnumber(lua, vsiz);
685 return 1;
686 }
687
688
689 /* for _iterinit function */
serv_iterinit(lua_State * lua)690 static int serv_iterinit(lua_State *lua){
691 int argc = lua_gettop(lua);
692 if(argc != 0){
693 lua_pushstring(lua, "_iterinit: invalid arguments");
694 lua_error(lua);
695 }
696 lua_getglobal(lua, SERVVAR);
697 SERV *serv = lua_touserdata(lua, -1);
698 bool rv = tcadbiterinit(serv->adb);
699 lua_settop(lua, 0);
700 lua_pushboolean(lua, rv);
701 return 1;
702 }
703
704
705 /* for _iternext function */
serv_iternext(lua_State * lua)706 static int serv_iternext(lua_State *lua){
707 int argc = lua_gettop(lua);
708 if(argc != 0){
709 lua_pushstring(lua, "_iternext: invalid arguments");
710 lua_error(lua);
711 }
712 lua_getglobal(lua, SERVVAR);
713 SERV *serv = lua_touserdata(lua, -1);
714 int vsiz;
715 char *vbuf = tcadbiternext(serv->adb, &vsiz);
716 lua_settop(lua, 0);
717 if(vbuf){
718 lua_pushlstring(lua, vbuf, vsiz);
719 tcfree(vbuf);
720 } else {
721 lua_pushnil(lua);
722 }
723 return 1;
724 }
725
726
727 /* for _fwmkeys function */
serv_fwmkeys(lua_State * lua)728 static int serv_fwmkeys(lua_State *lua){
729 int argc = lua_gettop(lua);
730 if(argc < 1){
731 lua_pushstring(lua, "_fwmkeys: invalid arguments");
732 lua_error(lua);
733 }
734 size_t psiz;
735 const char *pbuf = lua_tolstring(lua, 1, &psiz);
736 if(!pbuf){
737 lua_pushstring(lua, "_fwmkeys: invalid arguments");
738 lua_error(lua);
739 }
740 int max = argc > 1 && lua_isnumber(lua, 2) ? lua_tonumber(lua, 2) : -1;
741 lua_getglobal(lua, SERVVAR);
742 SERV *serv = lua_touserdata(lua, -1);
743 TCLIST *keys = tcadbfwmkeys(serv->adb, pbuf, psiz, max);
744 lua_settop(lua, 0);
745 int knum = tclistnum(keys);
746 lua_createtable(lua, knum, 0);
747 for(int i = 0; i < knum; i++){
748 int ksiz;
749 const char *kbuf = tclistval(keys, i, &ksiz);
750 lua_pushlstring(lua, kbuf, ksiz);
751 lua_rawseti(lua, 1, i + 1);
752 }
753 tclistdel(keys);
754 return 1;
755 }
756
757
758 /* for _addint function */
serv_addint(lua_State * lua)759 static int serv_addint(lua_State *lua){
760 int argc = lua_gettop(lua);
761 if(argc != 2){
762 lua_pushstring(lua, "_addint: invalid arguments");
763 lua_error(lua);
764 }
765 size_t ksiz;
766 const char *kbuf = lua_tolstring(lua, 1, &ksiz);
767 int num = lua_tonumber(lua, 2);
768 if(!kbuf || !lua_isnumber(lua, 2)){
769 lua_pushstring(lua, "_addint: invalid arguments");
770 lua_error(lua);
771 }
772 lua_getglobal(lua, SERVVAR);
773 SERV *serv = lua_touserdata(lua, -1);
774 int rv = tculogadbaddint(serv->ulog, serv->sid, 0, serv->adb, kbuf, ksiz, num);
775 lua_settop(lua, 0);
776 if(rv == INT_MIN){
777 lua_pushnil(lua);
778 } else {
779 lua_pushnumber(lua, rv);
780 }
781 return 1;
782 }
783
784
785 /* for _adddouble function */
serv_adddouble(lua_State * lua)786 static int serv_adddouble(lua_State *lua){
787 int argc = lua_gettop(lua);
788 if(argc != 2){
789 lua_pushstring(lua, "_adddouble: invalid arguments");
790 lua_error(lua);
791 }
792 size_t ksiz;
793 const char *kbuf = lua_tolstring(lua, 1, &ksiz);
794 double num = lua_tonumber(lua, 2);
795 if(!kbuf || !lua_isnumber(lua, 2)){
796 lua_pushstring(lua, "_adddouble: invalid arguments");
797 lua_error(lua);
798 }
799 lua_getglobal(lua, SERVVAR);
800 SERV *serv = lua_touserdata(lua, -1);
801 double rv = tculogadbadddouble(serv->ulog, serv->sid, 0, serv->adb, kbuf, ksiz, num);
802 lua_settop(lua, 0);
803 if(isnan(rv)){
804 lua_pushnil(lua);
805 } else {
806 lua_pushnumber(lua, rv);
807 }
808 return 1;
809 }
810
811
812 /* for _vanish function */
serv_vanish(lua_State * lua)813 static int serv_vanish(lua_State *lua){
814 int argc = lua_gettop(lua);
815 if(argc != 0){
816 lua_pushstring(lua, "_vanish: invalid arguments");
817 lua_error(lua);
818 }
819 lua_getglobal(lua, SERVVAR);
820 SERV *serv = lua_touserdata(lua, -1);
821 bool rv = tculogadbvanish(serv->ulog, serv->sid, 0, serv->adb);
822 lua_settop(lua, 0);
823 lua_pushboolean(lua, rv);
824 return 1;
825 }
826
827
828 /* for _rnum function */
serv_rnum(lua_State * lua)829 static int serv_rnum(lua_State *lua){
830 int argc = lua_gettop(lua);
831 if(argc != 0){
832 lua_pushstring(lua, "_rnum: invalid arguments");
833 lua_error(lua);
834 }
835 lua_getglobal(lua, SERVVAR);
836 SERV *serv = lua_touserdata(lua, -1);
837 uint64_t rnum = tcadbrnum(serv->adb);
838 lua_settop(lua, 0);
839 lua_pushnumber(lua, rnum);
840 return 1;
841 }
842
843
844 /* for _size function */
serv_size(lua_State * lua)845 static int serv_size(lua_State *lua){
846 int argc = lua_gettop(lua);
847 if(argc != 0){
848 lua_pushstring(lua, "_size: invalid arguments");
849 lua_error(lua);
850 }
851 lua_getglobal(lua, SERVVAR);
852 SERV *serv = lua_touserdata(lua, -1);
853 uint64_t size = tcadbsize(serv->adb);
854 lua_settop(lua, 0);
855 lua_pushnumber(lua, size);
856 return 1;
857 }
858
859
860 /* for _misc function */
serv_misc(lua_State * lua)861 static int serv_misc(lua_State *lua){
862 int argc = lua_gettop(lua);
863 if(argc < 1){
864 lua_pushstring(lua, "_misc: invalid arguments");
865 lua_error(lua);
866 }
867 const char *name = lua_tostring(lua, 1);
868 if(!name){
869 lua_pushstring(lua, "_misc: invalid arguments");
870 lua_error(lua);
871 }
872 bool ulog = true;
873 if(*name == '$'){
874 name++;
875 ulog = false;
876 }
877 TCLIST *args = tclistnew();
878 for(int i = 2; i <= argc; i++){
879 const char *aptr;
880 size_t asiz;
881 int len;
882 switch(lua_type(lua, i)){
883 case LUA_TNUMBER:
884 case LUA_TSTRING:
885 aptr = lua_tolstring(lua, i, &asiz);
886 tclistpush(args, aptr, asiz);
887 break;
888 case LUA_TTABLE:
889 len = lua_objlen(lua, i);
890 for(int j = 1; j <= len; j++){
891 lua_rawgeti(lua, i, j);
892 switch(lua_type(lua, -1)){
893 case LUA_TNUMBER:
894 case LUA_TSTRING:
895 aptr = lua_tolstring(lua, -1, &asiz);
896 tclistpush(args, aptr, asiz);
897 break;
898 }
899 lua_pop(lua, 1);
900 }
901 break;
902 }
903 }
904 lua_getglobal(lua, SERVVAR);
905 SERV *serv = lua_touserdata(lua, -1);
906 TCLIST *res = ulog ? tculogadbmisc(serv->ulog, serv->sid, 0, serv->adb, name, args) :
907 tcadbmisc(serv->adb, name, args);
908 lua_settop(lua, 0);
909 if(res){
910 int rnum = tclistnum(res);
911 lua_createtable(lua, rnum, 0);
912 for(int i = 0; i < rnum; i++){
913 int rsiz;
914 const char *rbuf = tclistval(res, i, &rsiz);
915 lua_pushlstring(lua, rbuf, rsiz);
916 lua_rawseti(lua, 1, i + 1);
917 }
918 tclistdel(res);
919 } else {
920 lua_pushnil(lua);
921 }
922 tclistdel(args);
923 return 1;
924 }
925
926
927 /* for _foreach function */
serv_foreach(lua_State * lua)928 static int serv_foreach(lua_State *lua){
929 int argc = lua_gettop(lua);
930 if(argc != 1){
931 lua_pushstring(lua, "_foreach: invalid arguments");
932 lua_error(lua);
933 }
934 if(!lua_isfunction(lua, 1)){
935 lua_pushstring(lua, "_foreach: invalid arguments");
936 lua_error(lua);
937 }
938 lua_getglobal(lua, SERVVAR);
939 SERV *serv = lua_touserdata(lua, -1);
940 lua_pushvalue(lua, 1);
941 lua_setglobal(lua, ITERVAR);
942 bool err = false;
943 if(!tcadbforeach(serv->adb, (TCITER)iterrec, lua)) err = true;
944 lua_pushnil(lua);
945 lua_setglobal(lua, ITERVAR);
946 lua_settop(lua, 0);
947 lua_pushboolean(lua, !err);
948 return 1;
949 }
950
951
952 /* for _mapreduce function */
serv_mapreduce(lua_State * lua)953 static int serv_mapreduce(lua_State *lua){
954 int argc = lua_gettop(lua);
955 if(argc < 2){
956 lua_pushstring(lua, "_mapreduce: invalid arguments");
957 lua_error(lua);
958 }
959 if(!lua_isfunction(lua, 1) || !lua_isfunction(lua, 2)){
960 lua_pushstring(lua, "_mapreduce: invalid arguments");
961 lua_error(lua);
962 }
963 lua_pushvalue(lua, 1);
964 lua_setglobal(lua, MRMAPVAR);
965 lua_pushvalue(lua, 2);
966 lua_setglobal(lua, MRREDVAR);
967 TCLIST *keys = NULL;
968 if(argc > 2){
969 const char *kbuf;
970 size_t ksiz;
971 int len;
972 switch(lua_type(lua, 3)){
973 case LUA_TNUMBER:
974 case LUA_TSTRING:
975 keys = tclistnew2(1);
976 kbuf = lua_tolstring(lua, 3, &ksiz);
977 tclistpush(keys, kbuf, ksiz);
978 break;
979 case LUA_TTABLE:
980 len = lua_objlen(lua, 3);
981 keys = tclistnew2(len);
982 for(int i = 1; i <= len; i++){
983 lua_rawgeti(lua, 3, i);
984 switch(lua_type(lua, -1)){
985 case LUA_TNUMBER:
986 case LUA_TSTRING:
987 kbuf = lua_tolstring(lua, -1, &ksiz);
988 tclistpush(keys, kbuf, ksiz);
989 break;
990 }
991 lua_pop(lua, 1);
992 }
993 break;
994 }
995 }
996 lua_getglobal(lua, SERVVAR);
997 SERV *serv = lua_touserdata(lua, -1);
998 bool err = false;
999 TCBDB *bdb = tcbdbnew();
1000 lua_getglobal(lua, "_tmpdir_");
1001 const char *tmpdir = lua_tostring(lua, -1);
1002 if(!tmpdir) tmpdir = "/tmp";
1003 char *path = tcsprintf("%s%c%s-%d-%u",
1004 tmpdir, MYPATHCHR, "mapbdb", getpid(), (unsigned int)(tctime() * 1000));
1005 unlink(path);
1006 if(!tcbdbopen(bdb, path, BDBOWRITER | BDBOCREAT | BDBOTRUNC)) err = true;
1007 unlink(path);
1008 tcfree(path);
1009 if(!tcadbmapbdb(serv->adb, keys, bdb, (ADBMAPPROC)maprec, lua, -1)) err = true;
1010 if(!err){
1011 BDBCUR *cur = tcbdbcurnew(bdb);
1012 tcbdbcurfirst(cur);
1013 const char *lbuf = NULL;
1014 int lsiz = 0;
1015 int lnum = 0;
1016 const char *kbuf;
1017 int ksiz;
1018 while(!err && (kbuf = tcbdbcurkey3(cur, &ksiz)) != NULL){
1019 int vsiz;
1020 const char *vbuf = tcbdbcurval3(cur, &vsiz);
1021 if(lbuf && lsiz == ksiz && !memcmp(lbuf, kbuf, lsiz)){
1022 lua_pushlstring(lua, vbuf, vsiz);
1023 lua_rawseti(lua, -2, ++lnum);
1024 } else {
1025 if(lbuf){
1026 if(lua_pcall(lua, 2, 1, 0) != 0){
1027 reporterror(lua);
1028 err = true;
1029 } else if(lua_gettop(lua) < 1 || !lua_toboolean(lua, 1)){
1030 err = true;
1031 }
1032 }
1033 lua_settop(lua, 0);
1034 lua_getglobal(lua, MRREDVAR);
1035 lua_pushlstring(lua, kbuf, ksiz);
1036 lua_newtable(lua);
1037 lnum = 1;
1038 lua_pushlstring(lua, vbuf, vsiz);
1039 lua_rawseti(lua, -2, lnum);
1040 }
1041 lbuf = kbuf;
1042 lsiz = ksiz;
1043 tcbdbcurnext(cur);
1044 }
1045 if(lbuf){
1046 if(lua_pcall(lua, 2, 1, 0) != 0){
1047 reporterror(lua);
1048 err = true;
1049 } else if(lua_gettop(lua) < 1 || !lua_toboolean(lua, 1)){
1050 err = true;
1051 }
1052 lua_settop(lua, 0);
1053 }
1054 tcbdbcurdel(cur);
1055 }
1056 if(!tcbdbclose(bdb)) err = true;
1057 tcbdbdel(bdb);
1058 if(keys) tclistdel(keys);
1059 lua_pushnil(lua);
1060 lua_setglobal(lua, MRREDVAR);
1061 lua_pushnil(lua);
1062 lua_setglobal(lua, MRMAPVAR);
1063 lua_settop(lua, 0);
1064 lua_pushboolean(lua, !err);
1065 return 1;
1066 }
1067
1068
1069 /* for _mapreduce function */
serv_mapreducemapemit(lua_State * lua)1070 static int serv_mapreducemapemit(lua_State *lua){
1071 int argc = lua_gettop(lua);
1072 if(argc != 2){
1073 lua_pushstring(lua, "_mapreducemapemit: invalid arguments");
1074 lua_error(lua);
1075 }
1076 size_t ksiz;
1077 const char *kbuf = lua_tolstring(lua, 1, &ksiz);
1078 size_t vsiz;
1079 const char *vbuf = lua_tolstring(lua, 2, &vsiz);
1080 if(!kbuf || !vbuf){
1081 lua_pushstring(lua, "_mapreducemapemit: invalid arguments");
1082 lua_error(lua);
1083 }
1084 lua_getglobal(lua, MRPOOLVAR);
1085 void *map = lua_touserdata(lua, -1);
1086 bool rv = tcadbmapbdbemit(map, kbuf, ksiz, vbuf, vsiz);
1087 lua_settop(lua, 0);
1088 lua_pushboolean(lua, rv);
1089 return 1;
1090 }
1091
1092
1093 /* for _stashput function */
serv_stashput(lua_State * lua)1094 static int serv_stashput(lua_State *lua){
1095 int argc = lua_gettop(lua);
1096 if(argc != 2){
1097 lua_pushstring(lua, "_stashput: invalid arguments");
1098 lua_error(lua);
1099 }
1100 size_t ksiz;
1101 const char *kbuf = lua_tolstring(lua, 1, &ksiz);
1102 size_t vsiz;
1103 const char *vbuf = lua_tolstring(lua, 2, &vsiz);
1104 if(!kbuf || !vbuf){
1105 lua_pushstring(lua, "_stashput: invalid arguments");
1106 lua_error(lua);
1107 }
1108 lua_getglobal(lua, SERVVAR);
1109 SERV *serv = lua_touserdata(lua, -1);
1110 tcmdbput(serv->stash, kbuf, ksiz, vbuf, vsiz);
1111 lua_pushboolean(lua, true);
1112 return 1;
1113 }
1114
1115
1116 /* for _stashputkeep function */
serv_stashputkeep(lua_State * lua)1117 static int serv_stashputkeep(lua_State *lua){
1118 int argc = lua_gettop(lua);
1119 if(argc != 2){
1120 lua_pushstring(lua, "_stashputkeep: invalid arguments");
1121 lua_error(lua);
1122 }
1123 size_t ksiz;
1124 const char *kbuf = lua_tolstring(lua, 1, &ksiz);
1125 size_t vsiz;
1126 const char *vbuf = lua_tolstring(lua, 2, &vsiz);
1127 if(!kbuf || !vbuf){
1128 lua_pushstring(lua, "_stashputkeep: invalid arguments");
1129 lua_error(lua);
1130 }
1131 lua_getglobal(lua, SERVVAR);
1132 SERV *serv = lua_touserdata(lua, -1);
1133 tcmdbputkeep(serv->stash, kbuf, ksiz, vbuf, vsiz);
1134 lua_pushboolean(lua, true);
1135 return 1;
1136 }
1137
1138
1139 /* for _stashputcat function */
serv_stashputcat(lua_State * lua)1140 static int serv_stashputcat(lua_State *lua){
1141 int argc = lua_gettop(lua);
1142 if(argc != 2){
1143 lua_pushstring(lua, "_stashputcat: invalid arguments");
1144 lua_error(lua);
1145 }
1146 size_t ksiz;
1147 const char *kbuf = lua_tolstring(lua, 1, &ksiz);
1148 size_t vsiz;
1149 const char *vbuf = lua_tolstring(lua, 2, &vsiz);
1150 if(!kbuf || !vbuf){
1151 lua_pushstring(lua, "_stashputcat: invalid arguments");
1152 lua_error(lua);
1153 }
1154 lua_getglobal(lua, SERVVAR);
1155 SERV *serv = lua_touserdata(lua, -1);
1156 tcmdbputcat(serv->stash, kbuf, ksiz, vbuf, vsiz);
1157 lua_pushboolean(lua, true);
1158 return 1;
1159 }
1160
1161
1162 /* for _stashout function */
serv_stashout(lua_State * lua)1163 static int serv_stashout(lua_State *lua){
1164 int argc = lua_gettop(lua);
1165 if(argc != 1){
1166 lua_pushstring(lua, "_stashout: invalid arguments");
1167 lua_error(lua);
1168 }
1169 size_t ksiz;
1170 const char *kbuf = lua_tolstring(lua, 1, &ksiz);
1171 if(!kbuf){
1172 lua_pushstring(lua, "_stashout: invalid arguments");
1173 lua_error(lua);
1174 }
1175 lua_getglobal(lua, SERVVAR);
1176 SERV *serv = lua_touserdata(lua, -1);
1177 bool rv = tcmdbout(serv->stash, kbuf, ksiz);
1178 lua_pushboolean(lua, rv);
1179 return 1;
1180 }
1181
1182
1183 /* for _stashget function */
serv_stashget(lua_State * lua)1184 static int serv_stashget(lua_State *lua){
1185 int argc = lua_gettop(lua);
1186 if(argc != 1){
1187 lua_pushstring(lua, "_stashget: invalid arguments");
1188 lua_error(lua);
1189 }
1190 size_t ksiz;
1191 const char *kbuf = lua_tolstring(lua, 1, &ksiz);
1192 if(!kbuf){
1193 lua_pushstring(lua, "_stashget: invalid arguments");
1194 lua_error(lua);
1195 }
1196 lua_getglobal(lua, SERVVAR);
1197 SERV *serv = lua_touserdata(lua, -1);
1198 int vsiz;
1199 char *vbuf = tcmdbget(serv->stash, kbuf, ksiz, &vsiz);
1200 if(vbuf){
1201 lua_pushlstring(lua, vbuf, vsiz);
1202 tcfree(vbuf);
1203 } else {
1204 lua_pushnil(lua);
1205 }
1206 return 1;
1207 }
1208
1209
1210 /* for _stashvanish function */
serv_stashvanish(lua_State * lua)1211 static int serv_stashvanish(lua_State *lua){
1212 int argc = lua_gettop(lua);
1213 if(argc != 0){
1214 lua_pushstring(lua, "_stashvanish: invalid arguments");
1215 lua_error(lua);
1216 }
1217 lua_getglobal(lua, SERVVAR);
1218 SERV *serv = lua_touserdata(lua, -1);
1219 tcmdbvanish(serv->stash);
1220 return 0;
1221 }
1222
1223
1224 /* for _stashforeach function */
serv_stashforeach(lua_State * lua)1225 static int serv_stashforeach(lua_State *lua){
1226 int argc = lua_gettop(lua);
1227 if(argc != 1){
1228 lua_pushstring(lua, "_stashforeach: invalid arguments");
1229 lua_error(lua);
1230 }
1231 if(!lua_isfunction(lua, 1)){
1232 lua_pushstring(lua, "_stashforeach: invalid arguments");
1233 lua_error(lua);
1234 }
1235 lua_getglobal(lua, SERVVAR);
1236 SERV *serv = lua_touserdata(lua, -1);
1237 lua_pushvalue(lua, 1);
1238 lua_setglobal(lua, ITERVAR);
1239 tcmdbforeach(serv->stash, (TCITER)iterrec, lua);
1240 lua_pushnil(lua);
1241 lua_setglobal(lua, ITERVAR);
1242 return 0;
1243 }
1244
1245
1246 /* for _lock function */
serv_lock(lua_State * lua)1247 static int serv_lock(lua_State *lua){
1248 int argc = lua_gettop(lua);
1249 if(argc != 1){
1250 lua_pushstring(lua, "_lock: invalid arguments");
1251 lua_error(lua);
1252 }
1253 size_t ksiz;
1254 const char *kbuf = lua_tolstring(lua, 1, &ksiz);
1255 if(!kbuf){
1256 lua_pushstring(lua, "_lock: invalid arguments");
1257 lua_error(lua);
1258 }
1259 lua_getglobal(lua, SERVVAR);
1260 SERV *serv = lua_touserdata(lua, -1);
1261 bool rv = true;
1262 while(!tcmdbputkeep(serv->lock, kbuf, ksiz, "", 0)){
1263 tcsleep(0.1);
1264 if(serv->term){
1265 rv = false;
1266 break;
1267 }
1268 }
1269 lua_settop(lua, 0);
1270 lua_pushboolean(lua, rv);
1271 return 1;
1272 }
1273
1274
1275 /* for _unlock function */
serv_unlock(lua_State * lua)1276 static int serv_unlock(lua_State *lua){
1277 int argc = lua_gettop(lua);
1278 if(argc != 1){
1279 lua_pushstring(lua, "_unlock: invalid arguments");
1280 lua_error(lua);
1281 }
1282 size_t ksiz;
1283 const char *kbuf = lua_tolstring(lua, 1, &ksiz);
1284 if(!kbuf){
1285 lua_pushstring(lua, "_unlock: invalid arguments");
1286 lua_error(lua);
1287 }
1288 lua_getglobal(lua, SERVVAR);
1289 SERV *serv = lua_touserdata(lua, -1);
1290 bool rv = tcmdbout(serv->lock, kbuf, ksiz);
1291 lua_settop(lua, 0);
1292 lua_pushboolean(lua, rv);
1293 return 1;
1294 }
1295
1296
1297 /* for _pack function */
serv_pack(lua_State * lua)1298 static int serv_pack(lua_State *lua){
1299 int argc = lua_gettop(lua);
1300 if(argc < 1){
1301 lua_pushstring(lua, "_pack: invalid arguments");
1302 lua_error(lua);
1303 }
1304 const char *format = lua_tostring(lua, 1);
1305 if(!format){
1306 lua_pushstring(lua, "_pack: invalid arguments");
1307 lua_error(lua);
1308 }
1309 lua_newtable(lua);
1310 int aidx = argc + 1;
1311 int eidx = 1;
1312 for(int i = 2; i <= argc; i++){
1313 int len;
1314 switch(lua_type(lua, i)){
1315 case LUA_TNUMBER:
1316 case LUA_TSTRING:
1317 lua_pushvalue(lua, i);
1318 lua_rawseti(lua, aidx, eidx++);
1319 break;
1320 case LUA_TTABLE:
1321 len = lua_objlen(lua, i);
1322 for(int j = 1; j <= len; j++){
1323 lua_rawgeti(lua, i, j);
1324 lua_rawseti(lua, aidx, eidx++);
1325 }
1326 break;
1327 default:
1328 lua_pushnumber(lua, 0);
1329 lua_rawseti(lua, aidx, eidx++);
1330 break;
1331 }
1332 }
1333 lua_replace(lua, 2);
1334 lua_settop(lua, 2);
1335 TCXSTR *xstr = tcxstrnew();
1336 int emax = eidx - 1;
1337 eidx = 1;
1338 while(*format != '\0'){
1339 int c = *format;
1340 int loop = 1;
1341 if(format[1] == '*'){
1342 loop = INT_MAX;
1343 format++;
1344 } else if(format[1] >= '0' && format[1] <= '9'){
1345 format++;
1346 loop = 0;
1347 while(*format >= '0' && *format <= '9'){
1348 loop = loop * 10 + *format - '0';
1349 format++;
1350 }
1351 format--;
1352 }
1353 loop = tclmin(loop, emax);
1354 int end = tclmin(eidx + loop - 1, emax);
1355 while(eidx <= end){
1356 lua_rawgeti(lua, 2, eidx);
1357 double num = lua_tonumber(lua, 3);
1358 lua_pop(lua, 1);
1359 uint8_t cnum;
1360 uint16_t snum;
1361 uint32_t inum;
1362 uint64_t lnum;
1363 double dnum;
1364 float fnum;
1365 uint64_t wnum;
1366 char wbuf[TTNUMBUFSIZ], *wp;
1367 switch(c){
1368 case 'c':
1369 case 'C':
1370 cnum = num;
1371 tcxstrcat(xstr, &cnum, sizeof(cnum));
1372 break;
1373 case 's':
1374 case 'S':
1375 snum = num;
1376 tcxstrcat(xstr, &snum, sizeof(snum));
1377 break;
1378 case 'i':
1379 case 'I':
1380 inum = num;
1381 tcxstrcat(xstr, &inum, sizeof(inum));
1382 break;
1383 case 'l':
1384 case 'L':
1385 lnum = num;
1386 tcxstrcat(xstr, &lnum, sizeof(lnum));
1387 break;
1388 case 'f':
1389 case 'F':
1390 fnum = num;
1391 tcxstrcat(xstr, &fnum, sizeof(fnum));
1392 break;
1393 case 'd':
1394 case 'D':
1395 dnum = num;
1396 tcxstrcat(xstr, &dnum, sizeof(dnum));
1397 break;
1398 case 'n':
1399 snum = num;
1400 snum = TTHTONS(snum);
1401 tcxstrcat(xstr, &snum, sizeof(snum));
1402 break;
1403 case 'N':
1404 inum = num;
1405 inum = TTHTONL(inum);
1406 tcxstrcat(xstr, &inum, sizeof(inum));
1407 break;
1408 case 'M':
1409 lnum = num;
1410 lnum = TTHTONLL(lnum);
1411 tcxstrcat(xstr, &lnum, sizeof(lnum));
1412 break;
1413 case 'w':
1414 case 'W':
1415 wnum = num;
1416 wp = wbuf;
1417 if(wnum < (1ULL << 7)){
1418 *(wp++) = wnum;
1419 } else if(wnum < (1ULL << 14)){
1420 *(wp++) = (wnum >> 7) | 0x80;
1421 *(wp++) = wnum & 0x7f;
1422 } else if(wnum < (1ULL << 21)){
1423 *(wp++) = (wnum >> 14) | 0x80;
1424 *(wp++) = ((wnum >> 7) & 0x7f) | 0x80;
1425 *(wp++) = wnum & 0x7f;
1426 } else if(wnum < (1ULL << 28)){
1427 *(wp++) = (wnum >> 21) | 0x80;
1428 *(wp++) = ((wnum >> 14) & 0x7f) | 0x80;
1429 *(wp++) = ((wnum >> 7) & 0x7f) | 0x80;
1430 *(wp++) = wnum & 0x7f;
1431 } else if(wnum < (1ULL << 35)){
1432 *(wp++) = (wnum >> 28) | 0x80;
1433 *(wp++) = ((wnum >> 21) & 0x7f) | 0x80;
1434 *(wp++) = ((wnum >> 14) & 0x7f) | 0x80;
1435 *(wp++) = ((wnum >> 7) & 0x7f) | 0x80;
1436 *(wp++) = wnum & 0x7f;
1437 } else if(wnum < (1ULL << 42)){
1438 *(wp++) = (wnum >> 35) | 0x80;
1439 *(wp++) = ((wnum >> 28) & 0x7f) | 0x80;
1440 *(wp++) = ((wnum >> 21) & 0x7f) | 0x80;
1441 *(wp++) = ((wnum >> 14) & 0x7f) | 0x80;
1442 *(wp++) = ((wnum >> 7) & 0x7f) | 0x80;
1443 *(wp++) = wnum & 0x7f;
1444 } else if(wnum < (1ULL << 49)){
1445 *(wp++) = (wnum >> 42) | 0x80;
1446 *(wp++) = ((wnum >> 35) & 0x7f) | 0x80;
1447 *(wp++) = ((wnum >> 28) & 0x7f) | 0x80;
1448 *(wp++) = ((wnum >> 21) & 0x7f) | 0x80;
1449 *(wp++) = ((wnum >> 14) & 0x7f) | 0x80;
1450 *(wp++) = ((wnum >> 7) & 0x7f) | 0x80;
1451 *(wp++) = wnum & 0x7f;
1452 } else if(wnum < (1ULL << 56)){
1453 *(wp++) = (wnum >> 49) | 0x80;
1454 *(wp++) = ((wnum >> 42) & 0x7f) | 0x80;
1455 *(wp++) = ((wnum >> 35) & 0x7f) | 0x80;
1456 *(wp++) = ((wnum >> 28) & 0x7f) | 0x80;
1457 *(wp++) = ((wnum >> 21) & 0x7f) | 0x80;
1458 *(wp++) = ((wnum >> 14) & 0x7f) | 0x80;
1459 *(wp++) = ((wnum >> 7) & 0x7f) | 0x80;
1460 *(wp++) = wnum & 0x7f;
1461 } else {
1462 *(wp++) = (wnum >> 63) | 0x80;
1463 *(wp++) = ((wnum >> 49) & 0x7f) | 0x80;
1464 *(wp++) = ((wnum >> 42) & 0x7f) | 0x80;
1465 *(wp++) = ((wnum >> 35) & 0x7f) | 0x80;
1466 *(wp++) = ((wnum >> 28) & 0x7f) | 0x80;
1467 *(wp++) = ((wnum >> 21) & 0x7f) | 0x80;
1468 *(wp++) = ((wnum >> 14) & 0x7f) | 0x80;
1469 *(wp++) = ((wnum >> 7) & 0x7f) | 0x80;
1470 *(wp++) = wnum & 0x7f;
1471 }
1472 tcxstrcat(xstr, wbuf, wp - wbuf);
1473 break;
1474 }
1475 eidx++;
1476 }
1477 format++;
1478 if(eidx > emax) break;
1479 }
1480 lua_settop(lua, 0);
1481 lua_pushlstring(lua, tcxstrptr(xstr), tcxstrsize(xstr));
1482 tcxstrdel(xstr);
1483 return 1;
1484 }
1485
1486
1487 /* for _unpack function */
serv_unpack(lua_State * lua)1488 static int serv_unpack(lua_State *lua){
1489 int argc = lua_gettop(lua);
1490 if(argc != 2){
1491 lua_pushstring(lua, "_unpack: invalid arguments");
1492 lua_error(lua);
1493 }
1494 const char *format = lua_tostring(lua, 1);
1495 size_t size;
1496 const char *buf = lua_tolstring(lua, 2, &size);
1497 if(!format){
1498 lua_pushstring(lua, "_unpack: invalid arguments");
1499 lua_error(lua);
1500 }
1501 if(!buf){
1502 buf = "";
1503 size = 0;
1504 }
1505 lua_newtable(lua);
1506 const char *rp = buf;
1507 int eidx = 1;
1508 while(*format != '\0'){
1509 int c = *format;
1510 int loop = 1;
1511 if(format[1] == '*'){
1512 loop = INT_MAX;
1513 format++;
1514 } else if(format[1] >= '0' && format[1] <= '9'){
1515 format++;
1516 loop = 0;
1517 while(*format >= '0' && *format <= '9'){
1518 loop = loop * 10 + *format - '0';
1519 format++;
1520 }
1521 format--;
1522 }
1523 loop = tclmin(loop, size);
1524 for(int i = 0; i < loop && size > 0; i++){
1525 uint8_t cnum;
1526 uint16_t snum;
1527 uint32_t inum;
1528 uint64_t lnum;
1529 float fnum;
1530 double dnum;
1531 uint64_t wnum;
1532 switch(c){
1533 case 'c':
1534 if(size >= sizeof(cnum)){
1535 memcpy(&cnum, rp, sizeof(cnum));
1536 lua_pushnumber(lua, (int8_t)cnum);
1537 lua_rawseti(lua, 3, eidx++);
1538 rp += sizeof(cnum);
1539 size -= sizeof(cnum);
1540 } else {
1541 size = 0;
1542 }
1543 break;
1544 case 'C':
1545 if(size >= sizeof(cnum)){
1546 memcpy(&cnum, rp, sizeof(cnum));
1547 lua_pushnumber(lua, (uint8_t)cnum);
1548 lua_rawseti(lua, 3, eidx++);
1549 rp += sizeof(cnum);
1550 size -= sizeof(cnum);
1551 } else {
1552 size = 0;
1553 }
1554 break;
1555 case 's':
1556 if(size >= sizeof(snum)){
1557 memcpy(&snum, rp, sizeof(snum));
1558 lua_pushnumber(lua, (int16_t)snum);
1559 lua_rawseti(lua, 3, eidx++);
1560 rp += sizeof(snum);
1561 size -= sizeof(snum);
1562 } else {
1563 size = 0;
1564 }
1565 break;
1566 case 'S':
1567 if(size >= sizeof(snum)){
1568 memcpy(&snum, rp, sizeof(snum));
1569 lua_pushnumber(lua, (uint16_t)snum);
1570 lua_rawseti(lua, 3, eidx++);
1571 rp += sizeof(snum);
1572 size -= sizeof(snum);
1573 } else {
1574 size = 0;
1575 }
1576 break;
1577 case 'i':
1578 if(size >= sizeof(inum)){
1579 memcpy(&inum, rp, sizeof(inum));
1580 lua_pushnumber(lua, (int32_t)inum);
1581 lua_rawseti(lua, 3, eidx++);
1582 rp += sizeof(inum);
1583 size -= sizeof(inum);
1584 } else {
1585 size = 0;
1586 }
1587 break;
1588 case 'I':
1589 if(size >= sizeof(inum)){
1590 memcpy(&inum, rp, sizeof(inum));
1591 lua_pushnumber(lua, (uint32_t)inum);
1592 lua_rawseti(lua, 3, eidx++);
1593 rp += sizeof(inum);
1594 size -= sizeof(inum);
1595 } else {
1596 size = 0;
1597 }
1598 break;
1599 case 'l':
1600 if(size >= sizeof(lnum)){
1601 memcpy(&lnum, rp, sizeof(lnum));
1602 lua_pushnumber(lua, (int64_t)lnum);
1603 lua_rawseti(lua, 3, eidx++);
1604 rp += sizeof(lnum);
1605 size -= sizeof(lnum);
1606 } else {
1607 size = 0;
1608 }
1609 break;
1610 case 'L':
1611 if(size >= sizeof(lnum)){
1612 memcpy(&lnum, rp, sizeof(lnum));
1613 lua_pushnumber(lua, (uint64_t)lnum);
1614 lua_rawseti(lua, 3, eidx++);
1615 rp += sizeof(lnum);
1616 size -= sizeof(lnum);
1617 } else {
1618 size = 0;
1619 }
1620 break;
1621 case 'f':
1622 case 'F':
1623 if(size >= sizeof(fnum)){
1624 memcpy(&fnum, rp, sizeof(fnum));
1625 lua_pushnumber(lua, (float)fnum);
1626 lua_rawseti(lua, 3, eidx++);
1627 rp += sizeof(fnum);
1628 size -= sizeof(fnum);
1629 } else {
1630 size = 0;
1631 }
1632 break;
1633 case 'd':
1634 case 'D':
1635 if(size >= sizeof(dnum)){
1636 memcpy(&dnum, rp, sizeof(dnum));
1637 lua_pushnumber(lua, (double)dnum);
1638 lua_rawseti(lua, 3, eidx++);
1639 rp += sizeof(dnum);
1640 size -= sizeof(dnum);
1641 } else {
1642 size = 0;
1643 }
1644 break;
1645 case 'n':
1646 if(size >= sizeof(snum)){
1647 memcpy(&snum, rp, sizeof(snum));
1648 snum = TTNTOHS(snum);
1649 lua_pushnumber(lua, (uint16_t)snum);
1650 lua_rawseti(lua, 3, eidx++);
1651 rp += sizeof(snum);
1652 size -= sizeof(snum);
1653 } else {
1654 size = 0;
1655 }
1656 break;
1657 case 'N':
1658 if(size >= sizeof(inum)){
1659 memcpy(&inum, rp, sizeof(inum));
1660 inum = TTNTOHL(inum);
1661 lua_pushnumber(lua, (uint32_t)inum);
1662 lua_rawseti(lua, 3, eidx++);
1663 rp += sizeof(inum);
1664 size -= sizeof(inum);
1665 } else {
1666 size = 0;
1667 }
1668 break;
1669 case 'M':
1670 if(size >= sizeof(lnum)){
1671 memcpy(&lnum, rp, sizeof(lnum));
1672 lnum = TTNTOHLL(lnum);
1673 lua_pushnumber(lua, (uint64_t)lnum);
1674 lua_rawseti(lua, 3, eidx++);
1675 rp += sizeof(lnum);
1676 size -= sizeof(lnum);
1677 } else {
1678 size = 0;
1679 }
1680 break;
1681 case 'w':
1682 case 'W':
1683 wnum = 0;
1684 do {
1685 inum = *(unsigned char *)rp;
1686 wnum = wnum * 0x80 + (inum & 0x7f);
1687 rp++;
1688 size--;
1689 } while(inum >= 0x80 && size > 0);
1690 lua_pushnumber(lua, wnum);
1691 lua_rawseti(lua, 3, eidx++);
1692 break;
1693 }
1694 }
1695 format++;
1696 if(size < 1) break;
1697 }
1698 lua_replace(lua, 1);
1699 lua_settop(lua, 1);
1700 return 1;
1701 }
1702
1703
1704 /* for _split function */
serv_split(lua_State * lua)1705 static int serv_split(lua_State *lua){
1706 int argc = lua_gettop(lua);
1707 if(argc < 1){
1708 lua_pushstring(lua, "_split: invalid arguments");
1709 lua_error(lua);
1710 }
1711 size_t isiz;
1712 const char *ibuf = lua_tolstring(lua, 1, &isiz);
1713 if(!ibuf){
1714 lua_pushstring(lua, "_split: invalid arguments");
1715 lua_error(lua);
1716 }
1717 const char *delims = argc > 1 ? lua_tostring(lua, 2) : NULL;
1718 lua_newtable(lua);
1719 int lnum = 1;
1720 if(delims){
1721 const char *str = ibuf;
1722 while(true){
1723 const char *sp = str;
1724 while(*str != '\0' && !strchr(delims, *str)){
1725 str++;
1726 }
1727 lua_pushlstring(lua, sp, str - sp);
1728 lua_rawseti(lua, -2, lnum++);
1729 if(*str == '\0') break;
1730 str++;
1731 }
1732 } else {
1733 const char *ptr = ibuf;
1734 int size = isiz;
1735 while(size >= 0){
1736 const char *rp = ptr;
1737 const char *ep = ptr + size;
1738 while(rp < ep){
1739 if(*rp == '\0') break;
1740 rp++;
1741 }
1742 lua_pushlstring(lua, ptr, rp - ptr);
1743 lua_rawseti(lua, -2, lnum++);
1744 rp++;
1745 size -= rp - ptr;
1746 ptr = rp;
1747 }
1748 }
1749 lua_replace(lua, 1);
1750 lua_settop(lua, 1);
1751 return 1;
1752 }
1753
1754
1755 /* for _codec function */
serv_codec(lua_State * lua)1756 static int serv_codec(lua_State *lua){
1757 int argc = lua_gettop(lua);
1758 if(argc != 2){
1759 lua_pushstring(lua, "_codec: invalid arguments");
1760 lua_error(lua);
1761 }
1762 const char *mode = lua_tostring(lua, 1);
1763 size_t isiz;
1764 const char *ibuf = lua_tolstring(lua, 2, &isiz);
1765 if(!mode || !ibuf){
1766 lua_pushstring(lua, "_codec: invalid arguments");
1767 lua_error(lua);
1768 }
1769 char *obuf = NULL;
1770 int osiz = 0;
1771 if(*mode == '~'){
1772 mode++;
1773 if(!tcstricmp(mode, "url")){
1774 obuf = tcurldecode(ibuf, &osiz);
1775 } else if(!tcstricmp(mode, "base")){
1776 obuf = tcbasedecode(ibuf, &osiz);
1777 } else if(!tcstricmp(mode, "quote")){
1778 obuf = tcquotedecode(ibuf, &osiz);
1779 } else if(!tcstricmp(mode, "hex")){
1780 obuf = tchexdecode(ibuf, &osiz);
1781 } else if(!tcstricmp(mode, "pack")){
1782 obuf = tcpackdecode(ibuf, isiz, &osiz);
1783 } else if(!tcstricmp(mode, "tcbs")){
1784 obuf = tcbsdecode(ibuf, isiz, &osiz);
1785 } else if(!tcstricmp(mode, "deflate")){
1786 obuf = tcinflate(ibuf, isiz, &osiz);
1787 } else if(!tcstricmp(mode, "gzip")){
1788 obuf = tcgzipdecode(ibuf, isiz, &osiz);
1789 } else if(!tcstricmp(mode, "bzip")){
1790 obuf = tcbzipdecode(ibuf, isiz, &osiz);
1791 } else if(!tcstricmp(mode, "xml")){
1792 obuf = tcxmlunescape(ibuf);
1793 osiz = obuf ? strlen(obuf) : 0;
1794 }
1795 } else {
1796 if(!tcstricmp(mode, "url")){
1797 obuf = tcurlencode(ibuf, isiz);
1798 osiz = obuf ? strlen(obuf) : 0;
1799 } else if(!tcstricmp(mode, "base")){
1800 obuf = tcbaseencode(ibuf, isiz);
1801 osiz = obuf ? strlen(obuf) : 0;
1802 } else if(!tcstricmp(mode, "quote")){
1803 obuf = tcquoteencode(ibuf, isiz);
1804 osiz = obuf ? strlen(obuf) : 0;
1805 } else if(!tcstricmp(mode, "hex")){
1806 obuf = tchexencode(ibuf, isiz);
1807 osiz = obuf ? strlen(obuf) : 0;
1808 } else if(!tcstricmp(mode, "pack")){
1809 obuf = tcpackencode(ibuf, isiz, &osiz);
1810 } else if(!tcstricmp(mode, "tcbs")){
1811 obuf = tcbsencode(ibuf, isiz, &osiz);
1812 } else if(!tcstricmp(mode, "deflate")){
1813 obuf = tcdeflate(ibuf, isiz, &osiz);
1814 } else if(!tcstricmp(mode, "gzip")){
1815 obuf = tcgzipencode(ibuf, isiz, &osiz);
1816 } else if(!tcstricmp(mode, "bzip")){
1817 obuf = tcbzipencode(ibuf, isiz, &osiz);
1818 } else if(!tcstricmp(mode, "xml")){
1819 obuf = tcxmlescape(ibuf);
1820 osiz = obuf ? strlen(obuf) : 0;
1821 }
1822 }
1823 lua_settop(lua, 0);
1824 if(obuf){
1825 lua_pushlstring(lua, obuf, osiz);
1826 tcfree(obuf);
1827 } else {
1828 lua_pushnil(lua);
1829 }
1830 return 1;
1831 }
1832
1833
1834 /* for _hash function */
serv_hash(lua_State * lua)1835 static int serv_hash(lua_State *lua){
1836 int argc = lua_gettop(lua);
1837 if(argc != 2){
1838 lua_pushstring(lua, "_hash: invalid arguments");
1839 lua_error(lua);
1840 }
1841 const char *mode = lua_tostring(lua, 1);
1842 size_t isiz;
1843 const char *ibuf = lua_tolstring(lua, 2, &isiz);
1844 if(!mode || !ibuf){
1845 lua_pushstring(lua, "_hash: invalid arguments");
1846 lua_error(lua);
1847 }
1848 if(!tcstricmp(mode, "md5")){
1849 char obuf[48];
1850 tcmd5hash(ibuf, isiz, obuf);
1851 lua_settop(lua, 0);
1852 lua_pushstring(lua, obuf);
1853 } else if(!tcstricmp(mode, "md5raw")){
1854 char obuf[48];
1855 tcmd5hash(ibuf, isiz, obuf);
1856 int esiz;
1857 char *ebuf = tchexdecode(obuf, &esiz);
1858 lua_settop(lua, 0);
1859 lua_pushlstring(lua, ebuf, esiz);
1860 tcfree(ebuf);
1861 } else if(!tcstricmp(mode, "crc32")){
1862 uint32_t crc = tcgetcrc(ibuf, isiz);
1863 lua_settop(lua, 0);
1864 lua_pushnumber(lua, crc);
1865 } else {
1866 lua_settop(lua, 0);
1867 lua_pushnil(lua);
1868 }
1869 return 1;
1870 }
1871
1872
1873 /* for _bit function */
serv_bit(lua_State * lua)1874 static int serv_bit(lua_State *lua){
1875 int argc = lua_gettop(lua);
1876 if(argc < 2){
1877 lua_pushstring(lua, "_bit: invalid arguments");
1878 lua_error(lua);
1879 }
1880 const char *mode = lua_tostring(lua, 1);
1881 uint32_t num = lua_tonumber(lua, 2);
1882 uint32_t aux = argc > 2 ? lua_tonumber(lua, 3) : 0;
1883 if(!mode){
1884 lua_pushstring(lua, "_bit: invalid arguments");
1885 lua_error(lua);
1886 } else if(!tcstricmp(mode, "and")){
1887 num &= aux;
1888 } else if(!tcstricmp(mode, "or")){
1889 num |= aux;
1890 } else if(!tcstricmp(mode, "xor")){
1891 num ^= aux;
1892 } else if(!tcstricmp(mode, "not")){
1893 num = ~num;
1894 } else if(!tcstricmp(mode, "left")){
1895 num <<= aux;
1896 } else if(!tcstricmp(mode, "right")){
1897 num >>= aux;
1898 } else {
1899 lua_pushstring(lua, "_bit: invalid arguments");
1900 lua_error(lua);
1901 }
1902 lua_settop(lua, 0);
1903 lua_pushnumber(lua, num);
1904 return 1;
1905 }
1906
1907
1908 /* for _strstr function */
serv_strstr(lua_State * lua)1909 static int serv_strstr(lua_State *lua){
1910 int argc = lua_gettop(lua);
1911 if(argc < 2){
1912 lua_pushstring(lua, "_strstr: invalid arguments");
1913 lua_error(lua);
1914 }
1915 const char *str = lua_tostring(lua, 1);
1916 const char *pat = lua_tostring(lua, 2);
1917 if(!str || !pat){
1918 lua_pushstring(lua, "_strstr: invalid arguments");
1919 lua_error(lua);
1920 }
1921 const char *alt = argc > 2 ? lua_tostring(lua, 3) : NULL;
1922 if(alt){
1923 TCXSTR *xstr = tcxstrnew();
1924 int plen = strlen(pat);
1925 int alen = strlen(alt);
1926 if(plen > 0){
1927 char *pv;
1928 while((pv = strstr(str, pat)) != NULL){
1929 tcxstrcat(xstr, str, pv - str);
1930 tcxstrcat(xstr, alt, alen);
1931 str = pv + plen;
1932 }
1933 }
1934 tcxstrcat2(xstr, str);
1935 lua_settop(lua, 0);
1936 lua_pushstring(lua, tcxstrptr(xstr));
1937 tcxstrdel(xstr);
1938 } else {
1939 char *pv = strstr(str, pat);
1940 if(pv){
1941 int idx = pv - str + 1;
1942 lua_settop(lua, 0);
1943 lua_pushinteger(lua, idx);
1944 } else {
1945 lua_settop(lua, 0);
1946 lua_pushinteger(lua, 0);
1947 }
1948 }
1949 return 1;
1950 }
1951
1952
1953 /* for _regex function */
serv_regex(lua_State * lua)1954 static int serv_regex(lua_State *lua){
1955 int argc = lua_gettop(lua);
1956 if(argc < 2){
1957 lua_pushstring(lua, "_regex: invalid arguments");
1958 lua_error(lua);
1959 }
1960 const char *str = lua_tostring(lua, 1);
1961 const char *regex = lua_tostring(lua, 2);
1962 if(!str || !regex){
1963 lua_pushstring(lua, "_regex: invalid arguments");
1964 lua_error(lua);
1965 }
1966 const char *alt = argc > 2 ? lua_tostring(lua, 3) : NULL;
1967 if(alt){
1968 char *res = tcregexreplace(str, regex, alt);
1969 lua_settop(lua, 0);
1970 lua_pushstring(lua, res);
1971 tcfree(res);
1972 } else {
1973 if(tcregexmatch(str, regex)){
1974 lua_settop(lua, 0);
1975 lua_pushboolean(lua, true);
1976 } else {
1977 lua_settop(lua, 0);
1978 lua_pushboolean(lua, false);
1979 }
1980 }
1981 return 1;
1982 }
1983
1984
1985 /* for _ucs function */
serv_ucs(lua_State * lua)1986 static int serv_ucs(lua_State *lua){
1987 int argc = lua_gettop(lua);
1988 if(argc != 1){
1989 lua_pushstring(lua, "ucs: invalid arguments");
1990 lua_error(lua);
1991 }
1992 if(lua_type(lua, 1) == LUA_TTABLE){
1993 int anum = lua_objlen(lua, 1);
1994 uint16_t *ary = tcmalloc(sizeof(*ary) * anum + 1);
1995 for(int i = 1; i <= anum; i++){
1996 lua_rawgeti(lua, 1, i);
1997 ary[i-1] = lua_tointeger(lua, 2);
1998 lua_pop(lua, 1);
1999 }
2000 char *str = tcmalloc(anum * 3 + 1);
2001 tcstrucstoutf(ary, anum, str);
2002 lua_settop(lua, 0);
2003 lua_pushstring(lua, str);
2004 tcfree(str);
2005 tcfree(ary);
2006 } else {
2007 size_t len;
2008 const char *str = lua_tolstring(lua, 1, &len);
2009 if(!str){
2010 lua_pushstring(lua, "ucs: invalid arguments");
2011 lua_error(lua);
2012 }
2013 uint16_t *ary = tcmalloc(sizeof(*ary) * len + 1);
2014 int anum;
2015 tcstrutftoucs(str, ary, &anum);
2016 lua_settop(lua, 0);
2017 lua_createtable(lua, anum, 0);
2018 for(int i = 0; i < anum; i++){
2019 lua_pushinteger(lua, ary[i]);
2020 lua_rawseti(lua, 1, i + 1);
2021 }
2022 tcfree(ary);
2023 }
2024 return 1;
2025 }
2026
2027
2028 /* for _dist function */
serv_dist(lua_State * lua)2029 static int serv_dist(lua_State *lua){
2030 int argc = lua_gettop(lua);
2031 if(argc < 2){
2032 lua_pushstring(lua, "dist: invalid arguments");
2033 lua_error(lua);
2034 }
2035 const char *astr = lua_tostring(lua, 1);
2036 const char *bstr = lua_tostring(lua, 2);
2037 bool utf = argc > 2 ? lua_toboolean(lua, 3) : false;
2038 if(!astr || !bstr){
2039 lua_pushstring(lua, "dist: invalid arguments");
2040 lua_error(lua);
2041 }
2042 int rv = utf ? tcstrdistutf(astr, bstr) : tcstrdist(astr, bstr);
2043 lua_settop(lua, 0);
2044 lua_pushnumber(lua, rv);
2045 return 1;
2046 }
2047
2048
2049 /* for _isect function */
serv_isect(lua_State * lua)2050 static int serv_isect(lua_State *lua){
2051 int argc = lua_gettop(lua);
2052 if(argc == 1 && lua_type(lua, 1) == LUA_TTABLE){
2053 int len = lua_objlen(lua, 1);
2054 for(int i = 1; i <= len; i++){
2055 lua_rawgeti(lua, 1, i);
2056 if(lua_type(lua, -1) == LUA_TTABLE){
2057 argc++;
2058 } else {
2059 lua_pop(lua, 1);
2060 break;
2061 }
2062 }
2063 if(argc > 1){
2064 lua_remove(lua, 1);
2065 argc--;
2066 }
2067 }
2068 int tnum = 0;
2069 int rnum = 0;
2070 for(int i = 1; i <= argc; i++){
2071 if(lua_type(lua, i) != LUA_TTABLE) continue;
2072 int len = lua_objlen(lua, i);
2073 if(len < 1){
2074 lua_settop(lua, 0);
2075 lua_newtable(lua);
2076 return 1;
2077 }
2078 tnum++;
2079 rnum += len;
2080 }
2081 if(tnum == 2){
2082 TCMAP *former = NULL;
2083 TCMAP *latter = NULL;
2084 for(int i = 1; i <= argc; i++){
2085 if(lua_type(lua, i) != LUA_TTABLE) continue;
2086 int len = lua_objlen(lua, i);
2087 if(former){
2088 latter = tcmapnew2(tclmin(len, tcmaprnum(former)));
2089 for(int j = 1; j <= len; j++){
2090 lua_rawgeti(lua, i, j);
2091 size_t size;
2092 const char *ptr = lua_tolstring(lua, -1, &size);
2093 if(ptr){
2094 int vsiz;
2095 if(tcmapget(former, ptr, size, &vsiz)) tcmapput(latter, ptr, size, "", 0);
2096 }
2097 lua_pop(lua, 1);
2098 }
2099 break;
2100 } else {
2101 former = tcmapnew2(len);
2102 for(int j = 1; j <= len; j++){
2103 lua_rawgeti(lua, i, j);
2104 size_t size;
2105 const char *ptr = lua_tolstring(lua, -1, &size);
2106 if(ptr) tcmapput(former, ptr, size, "", 0);
2107 lua_pop(lua, 1);
2108 }
2109 }
2110 }
2111 lua_settop(lua, 0);
2112 if(latter){
2113 lua_createtable(lua, (int)tcmaprnum(latter), 0);
2114 tcmapiterinit(latter);
2115 int ridx = 1;
2116 const char *kbuf;
2117 int ksiz;
2118 while((kbuf = tcmapiternext(latter, &ksiz)) != NULL){
2119 lua_pushlstring(lua, kbuf, ksiz);
2120 lua_rawseti(lua, 1, ridx++);
2121 }
2122 tcmapdel(latter);
2123 } else {
2124 lua_newtable(lua);
2125 }
2126 if(former) tcmapdel(former);
2127 } else {
2128 TCMAP *freq = tcmapnew2(rnum);
2129 for(int i = 1; i <= argc; i++){
2130 if(lua_type(lua, i) != LUA_TTABLE) continue;
2131 int len = lua_objlen(lua, i);
2132 TCMAP *uniq = tcmapnew2(len);
2133 for(int j = 1; j <= len; j++){
2134 lua_rawgeti(lua, i, j);
2135 size_t size;
2136 const char *ptr = lua_tolstring(lua, -1, &size);
2137 if(ptr){
2138 int vsiz;
2139 if(!tcmapget(uniq, ptr, size, &vsiz)){
2140 tcmapaddint(freq, ptr, size, 1);
2141 tcmapput(uniq, ptr, size, "", 0);
2142 }
2143 }
2144 lua_pop(lua, 1);
2145 }
2146 tcmapdel(uniq);
2147 }
2148 lua_settop(lua, 0);
2149 lua_createtable(lua, (int)tcmaprnum(freq), 0);
2150 tcmapiterinit(freq);
2151 int ridx = 1;
2152 const char *kbuf;
2153 int ksiz;
2154 while((kbuf = tcmapiternext(freq, &ksiz)) != NULL){
2155 int vsiz;
2156 const char *vbuf = tcmapiterval(kbuf, &vsiz);
2157 int num = *(int *)vbuf;
2158 if(num != tnum) continue;
2159 lua_pushlstring(lua, kbuf, ksiz);
2160 lua_rawseti(lua, 1, ridx++);
2161 }
2162 tcmapdel(freq);
2163 }
2164 return 1;
2165 }
2166
2167
2168 /* for _union function */
serv_union(lua_State * lua)2169 static int serv_union(lua_State *lua){
2170 int argc = lua_gettop(lua);
2171 if(argc == 1 && lua_type(lua, 1) == LUA_TTABLE){
2172 int len = lua_objlen(lua, 1);
2173 for(int i = 1; i <= len; i++){
2174 lua_rawgeti(lua, 1, i);
2175 if(lua_type(lua, -1) == LUA_TTABLE){
2176 argc++;
2177 } else {
2178 lua_pop(lua, 1);
2179 break;
2180 }
2181 }
2182 if(argc > 1){
2183 lua_remove(lua, 1);
2184 argc--;
2185 }
2186 }
2187 int rnum = 0;
2188 for(int i = 1; i <= argc; i++){
2189 if(lua_type(lua, i) != LUA_TTABLE) continue;
2190 rnum += lua_objlen(lua, i);
2191 }
2192 TCMAP *result = tcmapnew2(rnum);
2193 for(int i = 1; i <= argc; i++){
2194 if(lua_type(lua, i) != LUA_TTABLE) continue;
2195 int len = lua_objlen(lua, i);
2196 for(int j = 1; j <= len; j++){
2197 lua_rawgeti(lua, i, j);
2198 size_t size;
2199 const char *ptr = lua_tolstring(lua, -1, &size);
2200 if(ptr) tcmapput(result, ptr, size, "", 0);
2201 lua_pop(lua, 1);
2202 }
2203 }
2204 lua_settop(lua, 0);
2205 lua_createtable(lua, (int)tcmaprnum(result), 0);
2206 tcmapiterinit(result);
2207 int ridx = 1;
2208 const char *kbuf;
2209 int ksiz;
2210 while((kbuf = tcmapiternext(result, &ksiz)) != NULL){
2211 lua_pushlstring(lua, kbuf, ksiz);
2212 lua_rawseti(lua, 1, ridx++);
2213 }
2214 tcmapdel(result);
2215 return 1;
2216 }
2217
2218
2219 /* for _time function */
serv_time(lua_State * lua)2220 static int serv_time(lua_State *lua){
2221 int argc = lua_gettop(lua);
2222 if(argc != 0){
2223 lua_pushstring(lua, "_time: invalid arguments");
2224 lua_error(lua);
2225 }
2226 lua_settop(lua, 0);
2227 lua_pushnumber(lua, tctime());
2228 return 1;
2229 }
2230
2231
2232 /* for _sleep function */
serv_sleep(lua_State * lua)2233 static int serv_sleep(lua_State *lua){
2234 int argc = lua_gettop(lua);
2235 if(argc != 1){
2236 lua_pushstring(lua, "_sleep: invalid arguments");
2237 lua_error(lua);
2238 }
2239 double sec = lua_tonumber(lua, 1);
2240 if(!lua_isnumber(lua, 1)){
2241 lua_pushstring(lua, "_sleep: invalid arguments");
2242 lua_error(lua);
2243 }
2244 lua_settop(lua, 0);
2245 lua_pushboolean(lua, tcsleep(sec));
2246 return 1;
2247 }
2248
2249
2250 /* for stat function */
serv_stat(lua_State * lua)2251 static int serv_stat(lua_State *lua){
2252 int argc = lua_gettop(lua);
2253 if(argc != 1){
2254 lua_pushstring(lua, "_stat: invalid arguments");
2255 lua_error(lua);
2256 }
2257 const char *path = lua_tostring(lua, 1);
2258 if(!path){
2259 lua_pushstring(lua, "_stat: invalid arguments");
2260 lua_error(lua);
2261 }
2262 struct stat sbuf;
2263 if(lstat(path, &sbuf) == 0){
2264 lua_settop(lua, 0);
2265 lua_newtable(lua);
2266 lua_pushnumber(lua, sbuf.st_dev);
2267 lua_setfield(lua, -2, "dev");
2268 lua_pushnumber(lua, sbuf.st_ino);
2269 lua_setfield(lua, -2, "ino");
2270 lua_pushnumber(lua, sbuf.st_mode);
2271 lua_setfield(lua, -2, "mode");
2272 lua_pushnumber(lua, sbuf.st_nlink);
2273 lua_setfield(lua, -2, "nlink");
2274 lua_pushnumber(lua, sbuf.st_uid);
2275 lua_setfield(lua, -2, "uid");
2276 lua_pushnumber(lua, sbuf.st_gid);
2277 lua_setfield(lua, -2, "gid");
2278 lua_pushnumber(lua, sbuf.st_rdev);
2279 lua_setfield(lua, -2, "rdev");
2280 lua_pushnumber(lua, sbuf.st_size);
2281 lua_setfield(lua, -2, "size");
2282 lua_pushnumber(lua, sbuf.st_blksize);
2283 lua_setfield(lua, -2, "blksize");
2284 lua_pushnumber(lua, sbuf.st_blocks);
2285 lua_setfield(lua, -2, "blocks");
2286 lua_pushnumber(lua, sbuf.st_atime);
2287 lua_setfield(lua, -2, "atime");
2288 lua_pushnumber(lua, sbuf.st_mtime);
2289 lua_setfield(lua, -2, "mtime");
2290 lua_pushnumber(lua, sbuf.st_ctime);
2291 lua_setfield(lua, -2, "ctime");
2292 lua_pushboolean(lua, S_ISREG(sbuf.st_mode));
2293 lua_setfield(lua, -2, "_regular");
2294 lua_pushboolean(lua, S_ISDIR(sbuf.st_mode));
2295 lua_setfield(lua, -2, "_directory");
2296 bool readable = false;
2297 bool writable = false;
2298 bool executable = false;
2299 if(sbuf.st_uid == geteuid()){
2300 if(sbuf.st_mode & S_IRUSR) readable = true;
2301 if(sbuf.st_mode & S_IWUSR) writable = true;
2302 if(sbuf.st_mode & S_IXUSR) executable = true;
2303 }
2304 if(sbuf.st_gid == getegid()){
2305 if(sbuf.st_mode & S_IRGRP) readable = true;
2306 if(sbuf.st_mode & S_IWGRP) writable = true;
2307 if(sbuf.st_mode & S_IXGRP) executable = true;
2308 }
2309 if(sbuf.st_mode & S_IROTH) readable = true;
2310 if(sbuf.st_mode & S_IWOTH) writable = true;
2311 if(sbuf.st_mode & S_IXOTH) executable = true;
2312 lua_pushboolean(lua, readable);
2313 lua_setfield(lua, -2, "_readable");
2314 lua_pushboolean(lua, writable);
2315 lua_setfield(lua, -2, "_writable");
2316 lua_pushboolean(lua, executable);
2317 lua_setfield(lua, -2, "_executable");
2318 char *rpath = tcrealpath(path);
2319 if(rpath){
2320 lua_pushstring(lua, rpath);
2321 lua_setfield(lua, -2, "_realpath");
2322 tcfree(rpath);
2323 }
2324 } else {
2325 lua_settop(lua, 0);
2326 lua_pushnil(lua);
2327 }
2328 return 1;
2329 }
2330
2331
2332 /* for _glob function */
serv_glob(lua_State * lua)2333 static int serv_glob(lua_State *lua){
2334 int argc = lua_gettop(lua);
2335 if(argc != 1){
2336 lua_pushstring(lua, "_glob: invalid arguments");
2337 lua_error(lua);
2338 }
2339 const char *pattern = lua_tostring(lua, 1);
2340 if(!pattern){
2341 lua_pushstring(lua, "_glob: invalid arguments");
2342 lua_error(lua);
2343 }
2344 TCLIST *paths = tcglobpat(pattern);
2345 int pnum = tclistnum(paths);
2346 lua_settop(lua, 0);
2347 lua_createtable(lua, pnum, 0);
2348 for(int i = 0; i < pnum; i++){
2349 int size;
2350 const char *buf = tclistval(paths, i, &size);
2351 lua_pushlstring(lua, buf, size);
2352 lua_rawseti(lua, -2, i + 1);
2353 }
2354 tclistdel(paths);
2355 return 1;
2356 }
2357
2358
2359 /* for _remove function */
serv_remove(lua_State * lua)2360 static int serv_remove(lua_State *lua){
2361 int argc = lua_gettop(lua);
2362 if(argc != 1){
2363 lua_pushstring(lua, "_remove: invalid arguments");
2364 lua_error(lua);
2365 }
2366 const char *path = lua_tostring(lua, 1);
2367 if(!path){
2368 lua_pushstring(lua, "_remove: invalid arguments");
2369 lua_error(lua);
2370 }
2371 bool rv = tcremovelink(path);
2372 lua_settop(lua, 0);
2373 lua_pushboolean(lua, rv);
2374 return 1;
2375 }
2376
2377
2378 /* for _mkdir function */
serv_mkdir(lua_State * lua)2379 static int serv_mkdir(lua_State *lua){
2380 int argc = lua_gettop(lua);
2381 if(argc != 1){
2382 lua_pushstring(lua, "_mkdir: invalid arguments");
2383 lua_error(lua);
2384 }
2385 const char *path = lua_tostring(lua, 1);
2386 if(!path){
2387 lua_pushstring(lua, "_mkdir: invalid arguments");
2388 lua_error(lua);
2389 }
2390 bool rv = mkdir(path, 00755) == 0;
2391 lua_settop(lua, 0);
2392 lua_pushboolean(lua, rv);
2393 return 1;
2394 }
2395
2396
2397 #endif
2398
2399
2400
2401 // END OF FILE
2402