1 #include <stdio.h>
2 #include <string.h>
3 
4 #include <stdlib.h> /* malloc */
5 
6 /* lua includes */
7 #define LUA_CORE /* make sure that we don't try to import these functions */
8 #include <lua.h>
9 #include <lualib.h>
10 #include <lauxlib.h>
11 
12 #include "node.h"
13 #include "context.h"
14 #include "support.h"
15 #include "luafuncs.h"
16 #include "path.h"
17 #include "mem.h"
18 #include "session.h"
19 
build_stringlist(lua_State * L,struct HEAP * heap,struct STRINGLIST ** first,int table_index)20 void build_stringlist(lua_State *L, struct HEAP *heap, struct STRINGLIST **first, int table_index)
21 {
22 	struct STRINGLIST *listitem;
23 	const char *orgstr;
24 	size_t len;
25 
26 	int i;
27 	for(i = 1;; i++)
28 	{
29 		/* +1 value */
30 		lua_rawgeti(L, table_index, i);
31 
32 		if(lua_type(L, -1) == LUA_TNIL)
33 			break;
34 
35 		/* allocate and fix copy the string */
36 		orgstr = lua_tolstring(L, -1, &len);
37 		listitem = (struct STRINGLIST *)mem_allocate(heap, sizeof(struct STRINGLIST) + len + 1);
38 		listitem->str = (const char *)(listitem+1);
39 		listitem->len = len;
40 		memcpy(listitem+1, orgstr, len+1);
41 
42 		/* add it to the list */
43 		listitem->next = *first;
44 		*first = listitem;
45 
46 		/* pop value */
47 		lua_pop(L, 1);
48 	}
49 }
50 
51 /* value for deep walks */
52 static struct
53 {
54 	void (*callback)(lua_State*, void*);
55 	void *user;
56 } deepwalkinfo;
57 
deep_walk_r(lua_State * L,int table_index)58 static void deep_walk_r(lua_State *L, int table_index)
59 {
60 	int i;
61 	for(i = 1;; i++)
62 	{
63 		/* +1 value */
64 		lua_rawgeti(L, table_index, i);
65 
66 		if(lua_istable(L, -1))
67 			deep_walk_r(L, lua_gettop(L));
68 		else if(lua_type(L, -1) == LUA_TSTRING)
69 			deepwalkinfo.callback(L, deepwalkinfo.user);
70 		else if(lua_type(L, -1) == LUA_TNIL)
71 			break;
72 		else
73 		{
74 			/* other value */
75 			luaL_error(L, "encountered something besides a string or a table");
76 		}
77 
78 		/* pop +1 */
79 		lua_pop(L, 1);
80 	}
81 }
82 
deep_walk(lua_State * L,int start,int stop,void (* callback)(lua_State *,void *),void * user)83 static void deep_walk(lua_State *L, int start, int stop, void (*callback)(lua_State*, void*), void *user)
84 {
85 	int i;
86 	deepwalkinfo.callback = callback;
87 	deepwalkinfo.user = user;
88 
89 	for(i = start; i <= stop; i++)
90 	{
91 		if(lua_istable(L, i))
92 			deep_walk_r(L, i);
93 		else if(lua_type(L, i) == LUA_TSTRING)
94 		{
95 			lua_pushvalue(L, i);
96 			deepwalkinfo.callback(L, user);
97 			lua_pop(L, 1);
98 		}
99 		else
100 		{
101 			luaL_error(L, "encountered something besides a string or a table");
102 		}
103 	}
104 }
105 
106 /* add_pseudo(string node) */
lf_add_pseudo(lua_State * L)107 int lf_add_pseudo(lua_State *L)
108 {
109 	struct NODE *node;
110 	struct CONTEXT *context;
111 	int i;
112 
113 	if(lua_gettop(L) != 1)
114 		luaL_error(L, "add_pseudo: incorrect number of arguments");
115 
116 	luaL_checktype(L, 1, LUA_TSTRING);
117 
118 	/* fetch contexst from lua */
119 	context = context_get_pointer(L);
120 
121 	/* create the node */
122 	i = node_create(&node, context->graph, lua_tostring(L,1), NULL, NULL);
123 	if(i == NODECREATE_NOTNICE)
124 		luaL_error(L, "add_pseudo: node '%s' is not nice", lua_tostring(L,1));
125 	else if(i == NODECREATE_EXISTS)
126 		luaL_error(L, "add_pseudo: node '%s' already exists", lua_tostring(L,1));
127 	else if(i != NODECREATE_OK)
128 		luaL_error(L, "add_pseudo: unknown error creating node '%s'", lua_tostring(L,1));
129 
130 	node_set_pseudo(node);
131 	return 0;
132 }
133 
134 /* add_output(string output, string other_output) */
lf_add_output(lua_State * L)135 int lf_add_output(lua_State *L)
136 {
137 	struct NODE *output;
138 	struct NODE *other_output;
139 	struct CONTEXT *context;
140 
141 	if(lua_gettop(L) != 2)
142 		luaL_error(L, "add_output: incorrect number of arguments");
143 
144 	luaL_checktype(L, 1, LUA_TSTRING);
145 	luaL_checktype(L, 2, LUA_TSTRING);
146 
147 	context = context_get_pointer(L);
148 
149 	output = node_find(context->graph, lua_tostring(L,1));
150 	if(!output)
151 		luaL_error(L, "add_output: couldn't find node with name '%s'", lua_tostring(L,1));
152 
153 	other_output = node_get(context->graph, lua_tostring(L,2));
154 	if(!other_output)
155 		luaL_error(L, "add_output: couldn't find node with name '%s'", lua_tostring(L,2));
156 
157 	node_add_dependency_withnode(other_output, output);
158 	node_set_pseudo(other_output);
159 	return 0;
160 }
161 
162 struct NODEATTRIB_CBINFO
163 {
164 	struct NODE *node;
165 	struct NODE *(*callback)(struct NODE*, const char *);
166 };
167 
callback_node_attrib(lua_State * L,void * user)168 static void callback_node_attrib(lua_State *L, void *user)
169 {
170 	struct NODEATTRIB_CBINFO *info = (struct NODEATTRIB_CBINFO *)user;
171 	if(!info->callback(info->node, lua_tostring(L, -1)))
172 		luaL_error(L, "could not add '%s' to '%s'", lua_tostring(L, -1), lua_tostring(L, 1));
173 }
174 
175 /* add_dependency(string node, string dependency) */
add_node_attribute(lua_State * L,const char * funcname,struct NODE * (* callback)(struct NODE *,const char *))176 static int add_node_attribute(lua_State *L, const char *funcname, struct NODE *(*callback)(struct NODE*, const char *))
177 {
178 	struct NODE *node;
179 	struct CONTEXT *context;
180 	int n = lua_gettop(L);
181 	struct NODEATTRIB_CBINFO cbinfo;
182 
183 	if(n < 2)
184 		luaL_error(L, "%s: to few arguments", funcname);
185 
186 	luaL_checktype(L, 1, LUA_TSTRING);
187 
188 	context = context_get_pointer(L);
189 
190 	node = node_find(context->graph, lua_tostring(L,1));
191 	if(!node)
192 		luaL_error(L, "%s: couldn't find node with name '%s'", funcname, lua_tostring(L,1));
193 
194 	/* seek deps */
195 	cbinfo.node = node;
196 	cbinfo.callback = callback;
197 	deep_walk(L, 2, n, callback_node_attrib, &cbinfo);
198 	return 0;
199 }
200 
lf_add_dependency(lua_State * L)201 int lf_add_dependency(lua_State *L) { return add_node_attribute(L, "add_dependency", node_add_dependency); }
lf_add_constraint_shared(lua_State * L)202 int lf_add_constraint_shared(lua_State *L) { return add_node_attribute(L, "add_constraint_shared", node_add_constraint_shared); }
lf_add_constraint_exclusive(lua_State * L)203 int lf_add_constraint_exclusive(lua_State *L) { return add_node_attribute(L, "add_constraint_exclusive", node_add_constraint_exclusive); }
204 
205 /* add_job(string output, string label, string command, ...) */
lf_add_job(lua_State * L)206 int lf_add_job(lua_State *L)
207 {
208 	struct NODE *node;
209 	struct CONTEXT *context;
210 	struct NODEATTRIB_CBINFO cbinfo;
211 	int i;
212 
213 	if(lua_gettop(L) < 3)
214 		luaL_error(L, "add_job: too few arguments");
215 
216 	luaL_checktype(L, 1, LUA_TSTRING);
217 	luaL_checktype(L, 2, LUA_TSTRING);
218 	luaL_checktype(L, 3, LUA_TSTRING);
219 
220 	/* fetch contexst from lua */
221 	context = context_get_pointer(L);
222 
223 	/* create the node */
224 	i = node_create(&node, context->graph, lua_tostring(L,1), lua_tostring(L,2), lua_tostring(L,3));
225 	if(i == NODECREATE_NOTNICE)
226 		luaL_error(L, "add_job: node '%s' is not nice", lua_tostring(L,1));
227 	else if(i == NODECREATE_EXISTS)
228 		luaL_error(L, "add_job: node '%s' already exists", lua_tostring(L,1));
229 	else if(i != NODECREATE_OK)
230 		luaL_error(L, "add_job: unknown error creating node '%s'", lua_tostring(L,1));
231 
232 	/* seek deps */
233 	cbinfo.node = node;
234 	cbinfo.callback = node_add_dependency;
235 	deep_walk(L, 4, lua_gettop(L), callback_node_attrib, &cbinfo);
236 
237 	return 0;
238 }
239 
lf_set_touch(struct lua_State * L)240 int lf_set_touch(struct lua_State *L)
241 {
242 	struct NODE *node;
243 
244 	if(lua_gettop(L) < 1)
245 		luaL_error(L, "set_touch: too few arguments");
246 
247 	luaL_checktype(L, 1, LUA_TSTRING);
248 
249 	node = node_find(context_get_pointer(L)->graph, lua_tostring(L,1));
250 	if(!node)
251 		luaL_error(L, "set_touch: couldn't find node with name '%s'", lua_tostring(L,1));
252 
253 	node->touch = 1;
254 	return 0;
255 }
256 
257 
lf_set_filter(struct lua_State * L)258 int lf_set_filter(struct lua_State *L)
259 {
260 	struct NODE *node;
261 	const char *str;
262 	size_t len;
263 
264 	/* check the arguments */
265 	if(lua_gettop(L) < 2)
266 		luaL_error(L, "set_filter: too few arguments");
267 
268 	luaL_checktype(L, 1, LUA_TSTRING);
269 	luaL_checktype(L, 2, LUA_TSTRING);
270 
271 	/* find the node */
272 	node = node_find(context_get_pointer(L)->graph, lua_tostring(L,1));
273 	if(!node)
274 		luaL_error(L, "set_filter: couldn't find node with name '%s'", lua_tostring(L,1));
275 
276 	/* setup the string */
277 	str = lua_tolstring(L, 2, &len);
278 	node->filter = (char *)mem_allocate(node->graph->heap, len+1);
279 	memcpy(node->filter, str, len+1);
280 	return 0;
281 }
282 
283 /* default_target(string filename) */
lf_default_target(lua_State * L)284 int lf_default_target(lua_State *L)
285 {
286 	struct NODE *node;
287 	struct CONTEXT *context;
288 
289 	int n = lua_gettop(L);
290 	if(n != 1)
291 		luaL_error(L, "default_target: incorrect number of arguments");
292 	luaL_checktype(L, 1, LUA_TSTRING);
293 
294 	/* fetch context from lua */
295 	context = context_get_pointer(L);
296 
297 	/* search for the node */
298 	node = node_find(context->graph, lua_tostring(L,1));
299 	if(!node)
300 		luaL_error(L, "default_target: node '%s' not found", lua_tostring(L,1));
301 
302 	/* set target */
303 	context_default_target(context, node);
304 	return 0;
305 }
306 
307 /* update_globalstamp(string filename) */
lf_update_globalstamp(lua_State * L)308 int lf_update_globalstamp(lua_State *L)
309 {
310 	struct CONTEXT *context;
311 	time_t file_stamp;
312 
313 	if(lua_gettop(L) < 1)
314 		luaL_error(L, "update_globalstamp: too few arguments");
315 	luaL_checktype(L, 1, LUA_TSTRING);
316 
317 	context = context_get_pointer(L);
318 	file_stamp = file_timestamp(lua_tostring(L,1)); /* update global timestamp */
319 
320 	if(file_stamp > context->globaltimestamp)
321 		context->globaltimestamp = file_stamp;
322 
323 	return 0;
324 }
325 
326 
327 /* loadfile(filename) */
lf_loadfile(lua_State * L)328 int lf_loadfile(lua_State *L)
329 {
330 	if(lua_gettop(L) < 1)
331 		luaL_error(L, "loadfile: too few arguments");
332 	luaL_checktype(L, 1, LUA_TSTRING);
333 
334 	if(session.verbose)
335 		printf("%s: reading script from '%s'\n", session.name, lua_tostring(L,1));
336 
337 	if(luaL_loadfile(L, lua_tostring(L,1)) != 0)
338 		lua_error(L);
339 	return 1;
340 }
341 
342 
343 /* ** */
debug_print_lua_value(lua_State * L,int i)344 static void debug_print_lua_value(lua_State *L, int i)
345 {
346 	if(lua_type(L,i) == LUA_TNIL)
347 		printf("nil");
348 	else if(lua_type(L,i) == LUA_TSTRING)
349 		printf("'%s'", lua_tostring(L,i));
350 	else if(lua_type(L,i) == LUA_TNUMBER)
351 		printf("%f", lua_tonumber(L,i));
352 	else if(lua_type(L,i) == LUA_TBOOLEAN)
353 	{
354 		if(lua_toboolean(L,i))
355 			printf("true");
356 		else
357 			printf("false");
358 	}
359 	else if(lua_type(L,i) == LUA_TTABLE)
360 	{
361 		printf("{...}");
362 	}
363 	else
364 		printf("%p (%s (%d))", lua_topointer(L,i), lua_typename(L,lua_type(L,i)), lua_type(L,i));
365 }
366 
367 
368 /* error function */
lf_errorfunc(lua_State * L)369 int lf_errorfunc(lua_State *L)
370 {
371 	int depth = 0;
372 	int frameskip = 1;
373 	lua_Debug frame;
374 
375 	if(session.report_color)
376 		printf("\033[01;31m%s\033[00m\n", lua_tostring(L,-1));
377 	else
378 		printf("%s\n", lua_tostring(L,-1));
379 
380 	if(session.lua_backtrace)
381 	{
382 		printf("backtrace:\n");
383 		while(lua_getstack(L, depth, &frame) == 1)
384 		{
385 			depth++;
386 
387 			lua_getinfo(L, "nlSf", &frame);
388 
389 			/* check for functions that just report errors. these frames just confuses more then they help */
390 			if(frameskip && strcmp(frame.short_src, "[C]") == 0 && frame.currentline == -1)
391 				continue;
392 			frameskip = 0;
393 
394 			/* print stack frame */
395 			printf("  %s(%d): %s %s\n", frame.short_src, frame.currentline, frame.name, frame.namewhat);
396 
397 			/* print all local variables for the frame */
398 			if(session.lua_locals)
399 			{
400 				int i;
401 				const char *name = 0;
402 
403 				i = 1;
404 				while((name = lua_getlocal(L, &frame, i)) != NULL)
405 				{
406 					printf("    %s = ", name);
407 					debug_print_lua_value(L,-1);
408 					printf("\n");
409 					lua_pop(L,1);
410 					i++;
411 				}
412 
413 				i = 1;
414 				while((name = lua_getupvalue(L, -1, i)) != NULL)
415 				{
416 					printf("    upvalue #%d: %s ", i-1, name);
417 					debug_print_lua_value(L, -1);
418 					lua_pop(L,1);
419 					i++;
420 				}
421 			}
422 		}
423 	}
424 
425 	return 1;
426 }
427 
lf_panicfunc(lua_State * L)428 int lf_panicfunc(lua_State *L)
429 {
430 	printf("%s: PANIC! I'm gonna segfault now\n", session.name);
431 	*(int*)0 = 0;
432 	return 0;
433 }
434 
lf_mkdir(struct lua_State * L)435 int lf_mkdir(struct lua_State *L)
436 {
437 	if(lua_gettop(L) < 1)
438 		luaL_error(L, "mkdir: too few arguments");
439 
440 	if(!lua_isstring(L,1))
441 		luaL_error(L, "mkdir: expected string");
442 
443 	if(file_createdir(lua_tostring(L,1)) == 0)
444 		lua_pushnumber(L, 1);
445 	else
446 		lua_pushnil(L);
447 	return 1;
448 }
449 
450 
lf_fileexist(struct lua_State * L)451 int lf_fileexist(struct lua_State *L)
452 {
453 	if(lua_gettop(L) < 1)
454 		luaL_error(L, "fileexist: too few arguments");
455 
456 	if(!lua_isstring(L,1))
457 		luaL_error(L, "fileexist: expected string");
458 
459 	if(file_exist(lua_tostring(L,1)))
460 		lua_pushnumber(L, 1);
461 	else
462 		lua_pushnil(L);
463 	return 1;
464 }
465 
lf_istable(lua_State * L)466 int lf_istable(lua_State *L)
467 {
468 	if(lua_type(L,-1) == LUA_TTABLE)
469 		lua_pushnumber(L, 1);
470 	else
471 		lua_pushnil(L);
472 	return 1;
473 }
474 
lf_isstring(lua_State * L)475 int lf_isstring(lua_State *L)
476 {
477 	if(lua_type(L,-1) == LUA_TSTRING)
478 		lua_pushnumber(L, 1);
479 	else
480 		lua_pushnil(L);
481 	return 1;
482 }
483 
484 /* TODO: remove this limit */
485 #define WALK_MAXDEPTH 32
486 
487 struct WALKDATA
488 {
489 	int index[WALK_MAXDEPTH];
490 	int depth;
491 };
492 
lf_table_walk_iter(struct lua_State * L)493 static int lf_table_walk_iter(struct lua_State *L)
494 {
495 	struct WALKDATA *data;
496 	int type;
497 
498 	/* 1: walk table  2: last value(ignore) */
499 	lua_rawgeti(L, 1, 1); /* push 3: the walk data */
500 	data = (struct WALKDATA *)lua_touserdata(L, -1);
501 
502 	/* 1: walk table  2: last value 3: walk data */
503 	while(1)
504 	{
505 		data->index[data->depth]++;
506 
507 		/* .. 4: current table 5: current value */
508 		lua_rawgeti(L, 1, data->depth+1); /* push 4: fetch table */
509 		lua_rawgeti(L, -1, data->index[data->depth]); /* push 5: value in table */
510 
511 		type = lua_type(L, -1);
512 
513 		if(type == LUA_TTABLE)
514 		{
515 			data->depth++;
516 			if(data->depth >= WALK_MAXDEPTH)
517 				luaL_error(L, "max table depth exceeded");
518 			data->index[data->depth] = 0;
519 			lua_rawseti(L, 1, data->depth+1);
520 			lua_pop(L, 1);
521 		}
522 		else if(type == LUA_TNIL)
523 		{
524 			/* pop table and nil value */
525 			lua_pop(L, 2);
526 			data->depth--;
527 			if(data->depth == 0)
528 			{
529 				lua_pushnil(L);
530 				return 1;
531 			}
532 		}
533 		else if(type == LUA_TSTRING)
534 		{
535 			lua_pushvalue(L, 1); /* push the table stack again */
536 			return 2;
537 		}
538 		else
539 			luaL_error(L, "tablewalk: encountered strange value in tables");
540 	}
541 }
542 
543 /*
544 	the walk table looks like this
545 	t = {
546 			[1] = walk data
547 			[2] = table 1
548 			[3] = table 2
549 			[N] = table N
550 	}
551 */
lf_table_walk(struct lua_State * L)552 int lf_table_walk(struct lua_State *L)
553 {
554 	struct WALKDATA *data;
555 
556 	if(lua_gettop(L) != 1)
557 		luaL_error(L, "table_walk: incorrect number of arguments");
558 	luaL_checktype(L, 1, LUA_TTABLE);
559 
560 	/* 1: table to iterate over */
561 	lua_pushcfunction(L, lf_table_walk_iter); /* 2: iterator function */
562 	lua_createtable(L, 4, 0); /* 3: table stack */
563 
564 	data = (struct WALKDATA *)lua_newuserdata(L, sizeof(struct WALKDATA));
565 	data->depth = 1;
566 	data->index[data->depth] = 0;
567 	lua_rawseti(L, 3, 1);
568 
569 	lua_pushvalue(L, 1);
570 	lua_rawseti(L, 3, 2);
571 	lua_pushnil(L);
572 
573 	return 3;
574 }
575 
576 /* does a deep copy of a table */
table_deepcopy_r(struct lua_State * L)577 static int table_deepcopy_r(struct lua_State *L)
578 {
579 	size_t s;
580 
581 	/* 1: table to copy, 2: new table */
582 	s = lua_objlen(L, -1);
583 	lua_createtable(L, 0, s);
584 
585 	/* 3: iterator */
586 	lua_pushnil(L);
587 	while(lua_next(L, -3))
588 	{
589 		/* 4: value */
590 		if(lua_istable(L, -1))
591 		{
592 			table_deepcopy_r(L); /* 5: new table */
593 			lua_pushvalue(L, -3); /* 6: key */
594 			lua_pushvalue(L, -2); /* 7: value */
595 			lua_settable(L, -6); /* pops 6 and 7 */
596 			lua_pop(L, 1); /* pops 5 */
597 		}
598 		else
599 		{
600 			lua_pushvalue(L, -2); /* 5: key */
601 			lua_pushvalue(L, -2); /* 6: value */
602 			lua_settable(L, -5); /* pops 5 and 6 */
603 		}
604 
605 		/* pops 4 */
606 		lua_pop(L, 1);
607 	}
608 
609 
610 	/* transfer the meta table */
611 	if(lua_getmetatable(L, -2))
612 		lua_setmetatable(L, -2);
613 
614 	return 1;
615 }
616 
lf_table_deepcopy(struct lua_State * L)617 int lf_table_deepcopy(struct lua_State *L)
618 {
619 	if(lua_gettop(L) != 1)
620 		luaL_error(L, "table_deepcopy: incorrect number of arguments");
621 	luaL_checktype(L, 1, LUA_TTABLE);
622 
623 	return table_deepcopy_r(L);
624 }
625 
626 static int flatten_index;
627 
628 /* flattens a table into a simple table with strings */
lf_table_flatten_r(struct lua_State * L,int table_index)629 static int lf_table_flatten_r(struct lua_State *L, int table_index)
630 {
631 	/* +1: iterator */
632 	lua_pushnil(L);
633 	while(lua_next(L, table_index))
634 	{
635 		/* +2: value */
636 		if(lua_istable(L, -1))
637 			lf_table_flatten_r(L, lua_gettop(L));
638 		else if(lua_type(L, -1) == LUA_TSTRING)
639 		{
640 			lua_pushnumber(L, flatten_index); /* +3: key */
641 			lua_pushvalue(L, -2); /* +4: value */
642 			lua_settable(L, 2); /* pops +3 and +4 */
643 
644 			flatten_index++;
645 		}
646 		else
647 		{
648 			/* other value */
649 			luaL_error(L, "encountered something besides a string or a table");
650 		}
651 
652 		/* pops +2 */
653 		lua_pop(L, 1);
654 	}
655 
656 	return 1;
657 }
658 
lf_table_flatten(struct lua_State * L)659 int lf_table_flatten(struct lua_State *L)
660 {
661 	size_t s;
662 
663 	if(lua_gettop(L) != 1)
664 		luaL_error(L, "table_flatten: incorrect number of arguments");
665 	luaL_checktype(L, 1, LUA_TTABLE);
666 
667 	/* 1: table to copy, 2: new table */
668 	s = lua_objlen(L, -1);
669 	flatten_index = 1;
670 	lua_createtable(L, 0, s);
671 	lf_table_flatten_r(L, 1);
672 	return 1;
673 }
674 
675 static char string_buffer[1024*4];
676 
lf_table_tostring(struct lua_State * L)677 int lf_table_tostring(struct lua_State *L)
678 {
679 	/* 1: table 2: prefix, 3: postfix */
680 	size_t prefix_len, postfix_len;
681 	size_t total_len = 0;
682 	size_t item_len = 0;
683 	const char *prefix;
684 	const char *postfix;
685 	char *buffer;
686 	char *current;
687 	const char *item;
688 
689 	if(lua_gettop(L) != 3)
690 		luaL_error(L, "table_tostring: incorrect number of arguments");
691 
692 	luaL_checktype(L, 1, LUA_TTABLE);
693 
694 	prefix = lua_tolstring(L, 2, &prefix_len);
695 	postfix = lua_tolstring(L, 3, &postfix_len);
696 
697 	/* first, figure out the total size */
698 
699 	/* 4: iterator */
700 	lua_pushnil(L);
701 	while(lua_next(L, 1))
702 	{
703 		/* 5: value */
704 		if(lua_type(L, -1) == LUA_TSTRING)
705 		{
706 			lua_tolstring(L, -1, &item_len);
707 			total_len += prefix_len+item_len+postfix_len;
708 		}
709 
710 		/* pops 5 */
711 		lua_pop(L, 1);
712 	}
713 
714 	/* now allocate the buffer and start building the complete string */
715 	if(total_len < sizeof(string_buffer))
716 		buffer = string_buffer;
717 	else
718 		buffer = malloc(total_len);
719 
720 	current = buffer;
721 
722 	/* 4: iterator */
723 	lua_pushnil(L);
724 	while(lua_next(L, 1))
725 	{
726 		/* 5: value */
727 		if(lua_type(L, -1) == LUA_TSTRING)
728 		{
729 			item = lua_tolstring(L, -1, &item_len);
730 			memcpy(current, prefix, prefix_len); current += prefix_len;
731 			memcpy(current, item, item_len); current += item_len;
732 			memcpy(current, postfix, postfix_len); current += postfix_len;
733 		}
734 
735 		/* pops 5 */
736 		lua_pop(L, 1);
737 	}
738 
739 	/* push the new string onto the stack and clean up */
740 	lua_pushlstring(L, buffer, total_len);
741 	if(buffer != string_buffer)
742 		free(buffer);
743 
744 	return 1;
745 }
746 
lf_loadplugin(struct lua_State * L)747 int lf_loadplugin(struct lua_State *L)
748 {
749 	PLUGINFUNC func;
750 	if(lua_gettop(L) != 1)
751 		luaL_error(L, "loadplugin: incorrect number of arguments");
752 	luaL_checktype(L, 1, LUA_TSTRING);
753 
754 	func = plugin_load(lua_tostring(L, 1));
755 	if(!func)
756 		luaL_error(L, "loadplugin: error loading plugin");
757 
758 	lua_settop(L, 0);
759 	if((*func)(L) != 0)
760 		luaL_error(L, "loadplugin: error initing plugin");
761 
762 	return 0;
763 }
764