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