* updated blueman (2.3.5 -> 2.4.3)
[t2sde.git] / misc / luabash / bash / luabash.c
blob1bff7e7f5e49b482d7a087ad9a02490602e7d0d4
1 /*
2 * --- T2-COPYRIGHT-NOTE-BEGIN ---
3 * This copyright note is auto-generated by ./scripts/Create-CopyPatch.
4 *
5 * T2 SDE: misc/luabash/bash/luabash.c
6 * Copyright (C) 2019 The T2 SDE Project
7 *
8 * More information can be found in the files COPYING and README.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 2 of the License. A copy of the
13 * GNU General Public License can be found in the file COPYING.
14 * --- T2-COPYRIGHT-NOTE-END ---
17 // compile with:
18 // gcc -shared -fPIC -Wall -o luabash.so luabash.c -llua -lm -Wall -ldl
20 /* Some declarations copied from bash-3.1 headers */
22 #include <stdint.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <stdio.h>
27 #include "lua.h"
28 #include "lauxlib.h"
29 #include "lualib.h"
32 #define EXECUTION_SUCCESS 0
33 #define EXECUTION_FAILURE 1
35 typedef struct word_desc {
36 char *word;
37 int flags;
38 } WORD_DESC;
40 typedef struct word_list {
41 struct word_list *next;
42 WORD_DESC *word;
43 } WORD_LIST;
45 typedef int sh_builtin_func_t(WORD_LIST *);
47 #define BUILTIN_ENABLED 0x1
48 #define STATIC_BUILTIN 0x4 /* This builtin is not dynamically loaded. */
49 #define SPECIAL_BUILTIN 0x8 /* This is a Posix `special' builtin. */
51 struct builtin {
52 char *name;
53 sh_builtin_func_t *function;
54 int flags;
55 char * const *long_doc;
56 const char *short_doc;
57 char *handle;
60 struct variable;
61 typedef intmax_t arrayind_t;
63 typedef struct variable *sh_var_value_func_t(struct variable *);
64 typedef struct variable *sh_var_assign_func_t(struct variable *, char *, arrayind_t);
66 typedef struct variable {
67 char *name;
68 char *value;
69 char *exportstr;
70 sh_var_value_func_t *dynamic_value;
71 sh_var_assign_func_t *assign_func;
72 int attributes;
73 int context;
74 } SHELL_VAR;
77 typedef struct redirect {
78 int data; // this is not quite true, but we don't need 'em here...
79 } REDIRECT;
81 struct simple_com;
82 struct function_def;
84 /* Command Types: */
85 enum command_type { cm_for, cm_case, cm_while, cm_if, cm_simple, cm_select,
86 cm_connection, cm_function_def, cm_until, cm_group,
87 cm_arith, cm_cond, cm_arith_for, cm_subshell };
89 typedef struct command {
90 enum command_type type; /* FOR CASE WHILE IF CONNECTION or SIMPLE. */
91 int flags; /* Flags controlling execution environment. */
92 int line; /* line number the command starts on */
93 REDIRECT *redirects; /* Special redirects for FOR CASE, etc. */
94 union { // SNIP !!! we only need two of those structs here
95 struct simple_com *Simple;
96 struct function_def *Function_def;
97 } value;
98 } COMMAND;
101 /*************** 3.x definitions ********************/
103 /* The "simple" command. Just a collection of words and redirects. */
104 typedef struct simple_com3 {
105 int flags; /* See description of CMD flags. */
106 int line; /* line number the command starts on */
107 WORD_LIST *words; /* The program name, the arguments,
108 variable assignments, etc. */
109 REDIRECT *redirects; /* Redirections to perform. */
110 } SIMPLE_COM3;
113 /* The "function definition" command. */
114 typedef struct function_def3 {
115 int flags; /* See description of CMD flags. */
116 int line; /* Line number the function def starts on. */
117 WORD_DESC *name; /* The name of the function. */
118 COMMAND *command; /* The parsed execution tree. */
119 char *source_file; /* file in which function was defined, if any */
120 } FUNCTION_DEF3;
123 /*************** 2.x definitions ********************/
126 /* The "simple" command. Just a collection of words and redirects. */
127 typedef struct simple_com2 {
128 int flags; /* See description of CMD flags. */
129 WORD_LIST *words; /* The program name, the arguments,
130 variable assignments, etc. */
131 REDIRECT *redirects; /* Redirections to perform. */
132 int line; /* line number the command starts on */
133 } SIMPLE_COM2;
136 /* The "function definition" command. */
137 typedef struct function_def2 {
138 int flags; /* See description of CMD flags. */
139 WORD_DESC *name; /* The name of the function. */
140 COMMAND *command; /* The parsed execution tree. */
141 int line; /* Line number the function def starts on. */
142 } FUNCTION_DEF2;
144 /****************************************************/
146 typedef struct simple_com {
147 union {
148 SIMPLE_COM2 v2;
149 SIMPLE_COM3 v3;
150 }version;
151 } SIMPLE_COM;
154 typedef struct function_def {
155 union {
156 FUNCTION_DEF2 v2;
157 FUNCTION_DEF3 v3;
158 }version;
159 } FUNCTION_DEF;
162 typedef enum { bash_version_v2, bash_version_v3, bash_version_unknown } bash_flavor;
163 static bash_flavor current_flavor=bash_version_unknown;
165 SIMPLE_COM* newSimpleCom(WORD_LIST *words)
167 SIMPLE_COM* ret=(SIMPLE_COM*) malloc(sizeof(SIMPLE_COM));
168 switch (current_flavor) {
169 case bash_version_v2:
170 ret->version.v2.flags=0;
171 ret->version.v2.line=0;
172 ret->version.v2.redirects=NULL;
173 ret->version.v2.words=words;
174 break;
175 case bash_version_v3:
176 ret->version.v3.flags=0;
177 ret->version.v3.line=0;
178 ret->version.v3.redirects=NULL;
179 ret->version.v3.words=words;
180 break;
181 default: // somethings wrong here...
182 return 0;
184 return ret;
188 /****************************************************/
190 #ifndef __P
191 #define __P(proto) proto
192 #endif
194 extern WORD_DESC *make_word __P((const char *));
195 extern COMMAND *make_command __P((enum command_type, SIMPLE_COM *));
196 extern COMMAND *make_function_def __P((WORD_DESC *, COMMAND *, int, int));
197 extern int execute_command __P((COMMAND *));
199 extern SHELL_VAR* find_variable(const char *);
200 extern SHELL_VAR* bind_variable(const char *, const char *);
201 extern SHELL_VAR* bind_function __P((const char *, COMMAND *));
202 extern SHELL_VAR** all_shell_variables __P((void));
203 #define value_cell(var) ((var)->value)
205 extern int num_shell_builtins; /* Number of shell builtins. */
206 extern struct builtin static_shell_builtins[];
207 extern struct builtin* shell_builtins;
208 extern void initialize_shell_builtins __P((void));
209 extern struct builtin* builtin_address_internal __P((char *, int));
212 extern void add_alias __P((const char *, const char *));
215 #ifdef DO_DYNAMIC_REGISTRATION
217 /* dynamic registration, not needed anymore.
218 * want to keep that code, one never knows if we might need it again!
220 * Valentin.
223 static int inject_new_builtin (struct builtin* b)
225 struct builtin* old_builtin;
227 b->flags |= STATIC_BUILTIN;
228 /*if (flags & SPECIAL)
229 b->flags |= SPECIAL_BUILTIN;*/
231 if ( (old_builtin = builtin_address_internal (b->name, 1)) != 0 ) {
232 memcpy ((void*) old_builtin, b, sizeof (struct builtin));
233 } else {
234 int total = num_shell_builtins + 1;
235 int size = (total + 1) * sizeof (struct builtin);
237 struct builtin* new_shell_builtins = (struct builtin*) malloc (size);
238 memcpy ((void*) new_shell_builtins, (void*) shell_builtins,
239 num_shell_builtins * sizeof (struct builtin));
240 memcpy ((void*) &new_shell_builtins[num_shell_builtins], (void*)b, sizeof (struct builtin));
241 new_shell_builtins[total].name = (char *)0;
242 new_shell_builtins[total].function = (sh_builtin_func_t *)0;
243 new_shell_builtins[total].flags = 0;
245 if (shell_builtins != static_shell_builtins)
246 free (shell_builtins);
248 shell_builtins = new_shell_builtins;
249 num_shell_builtins = total;
250 initialize_shell_builtins ();
253 return EXECUTION_SUCCESS;
256 #endif
258 /* helpers to work with variables, thanks to clifford */
260 static const char *getvar(const char *name)
262 SHELL_VAR *var;
263 var = find_variable(name);
264 return var ? value_cell(var) : 0;
267 #define setvar(a,b) bind_variable(a,b)
270 /* lua bash wrapper */
272 #define LUABASH_VERSION "lua bash wrapper 0.0.3 (C) 2006 - 2019 Valentin Ziegler & Rene Rebe"
274 #define LUA_ERRMSG fprintf(stderr, "lua bash error: %s\n", lua_tostring(L, -1))
275 #define LUA_ERRMSG_FAIL {LUA_ERRMSG; return EXECUTION_FAILURE;}
277 char* luabash_doc[] = {
278 LUABASH_VERSION,
279 "usage:",
280 "\tinit",
281 "\tload <lua chunk>",
282 "\tcall <lua function> [arguments]",
283 (char*) 0
286 static int initialized=0;
287 static lua_State* L;
289 static void print_usage()
291 int i=0;
292 while(luabash_doc[i])
293 fprintf(stderr, "%s\n", luabash_doc[i++]);
296 static int register_function (lua_State *L)
298 const char* fnname = luaL_checkstring(L, 1);
300 // old code using aliases
301 //const char* fmt="luabash call %s ";
302 //char* fullname=(char*) malloc(strlen(fmt)+strlen(fnname));
303 //sprintf(fullname, fmt, fnname);
304 //add_alias(fnname, fullname);
306 WORD_LIST* wluabash=(WORD_LIST*) malloc(sizeof(WORD_LIST));
307 WORD_LIST* wcall=(WORD_LIST*) malloc(sizeof(WORD_LIST));
308 WORD_LIST* wfnname=(WORD_LIST*) malloc(sizeof(WORD_LIST));
309 WORD_LIST* warguments=(WORD_LIST*) malloc(sizeof(WORD_LIST));
310 wluabash->next = wcall;
311 wcall->next=wfnname;
312 wfnname->next=warguments;
313 warguments->next=0;
314 wluabash->word=make_word("luabash");
315 wcall->word=make_word("call");
316 wfnname->word=make_word(fnname);
317 warguments->word=make_word("$@");
319 SIMPLE_COM* call_luabash=newSimpleCom(wluabash);
321 COMMAND* function_body=make_command(cm_simple, call_luabash);
322 bind_function(fnname,function_body);
324 return 0;
327 static int get_variable (lua_State *L)
329 const char* vname = luaL_checkstring(L, 1);
330 lua_pushstring(L, getvar(vname));
331 return 1;
334 static int set_variable (lua_State *L)
336 const char* vname = luaL_checkstring(L, 1);
337 const char* vvalue = luaL_checkstring(L, 2);
338 setvar(vname, vvalue);
339 return 0;
342 static int call_bashfunction (lua_State *L)
344 int no_args=lua_gettop(L);
345 int retval=0;
346 int i;
348 WORD_LIST* list=0;
349 WORD_LIST* start=0;
351 for (i=0; i<no_args; i++) {
352 const char* string=luaL_checkstring(L, i+1);
353 if (list) {
354 list->next=(WORD_LIST*) malloc(sizeof(WORD_LIST));
355 list=list -> next;
356 } else {
357 list=(WORD_LIST*) malloc(sizeof(WORD_LIST));
358 start=list;
360 list->word=make_word(string);
361 list->next=0;
364 if (!list)
365 retval=127;
366 else {
367 SIMPLE_COM* cmd=newSimpleCom(start);
368 retval=execute_command(make_command(cm_simple, cmd));
370 lua_pushinteger(L,retval);
371 return 1;
374 static int get_environment (lua_State *L)
376 SHELL_VAR** list=all_shell_variables();
377 int i=0;
379 lua_newtable(L);
380 while(list && list[i]) {
381 const char* key=list[i]->name;
382 const char* val=list[i]->value;
383 lua_pushstring(L,val);
384 lua_setfield(L,-2,key);
385 i++;
388 return 1;
391 static const luaL_Reg bashlib[] = {
392 {"register", register_function},
393 {"getVariable",get_variable},
394 {"setVariable",set_variable},
395 {"getEnvironment",get_environment},
396 {"call",call_bashfunction},
397 {NULL, NULL}
400 static int init_luabash()
402 if (!initialized) {
403 const char* bash_version=getvar("BASH_VERSION");
404 if (!bash_version)
405 return EXECUTION_FAILURE;
407 if (bash_version[0]=='2')
408 current_flavor=bash_version_v2;
409 else if (bash_version[0]=='3' ||
410 bash_version[0]=='4' ||
411 bash_version[0]=='5')
412 current_flavor=bash_version_v3;
414 if (current_flavor==bash_version_unknown) {
415 fprintf(stderr, "lua bash error: NYI bash version\n");
416 return EXECUTION_FAILURE;
419 L=luaL_newstate ();
420 if (!L) {
421 fprintf(stderr, "lua bash error: failed to initialize lua state\n");
422 return EXECUTION_FAILURE;
425 luaL_openlibs(L);
426 luaL_register(L, "bash", bashlib);
428 initialized=1;
431 return EXECUTION_SUCCESS;
434 static int load_chunk(const char* filename)
436 int result=init_luabash();
437 if (result != EXECUTION_SUCCESS)
438 return result;
440 if (luaL_loadfile(L, filename) || lua_pcall(L, 0, 0, 0))
441 LUA_ERRMSG_FAIL;
443 return EXECUTION_SUCCESS;
446 static int call_function(const char* func, WORD_LIST *argv)
448 int i;
450 if (!initialized) {
451 fprintf(stderr, "lua bash error: not initialized yet!\n");
452 return EXECUTION_FAILURE;
455 lua_getglobal(L, func);
457 int argc = 0;
458 while (argv) {
459 if (argv->word->word) {
460 lua_pushstring(L, argv->word->word);
461 ++argc;
463 argv = argv->next;
466 if (lua_pcall(L, argc, 1, 0))
467 LUA_ERRMSG_FAIL;
469 switch (lua_type(L, -1)) {
470 case LUA_TNUMBER: return lua_tonumber(L,-1);
471 case LUA_TBOOLEAN: return lua_toboolean(L,-1) ? EXECUTION_SUCCESS : EXECUTION_FAILURE;
472 case LUA_TNIL: return EXECUTION_SUCCESS;
475 i = lua_type(L,-1);
476 printf ("lua bash: unexpected type '%s' returned\n", lua_typename(L,i));
478 return EXECUTION_SUCCESS;
482 int luabash_builtin(WORD_LIST *list)
484 if (list && (list->word->word)) {
485 char* command=list->word->word;
486 if (strcmp(command, "init") == 0) {
487 return init_luabash();
488 } else if (strcmp(command, "load") == 0) {
489 list=list->next;
490 if (list && (list->word->word))
491 return load_chunk(list->word->word);
492 } else if (strcmp(command, "call") == 0) {
493 list=list->next;
494 if (list && (list->word->word))
495 return call_function(list->word->word, list->next);
499 print_usage();
500 return EXECUTION_FAILURE;
504 struct builtin luabash_struct = {
505 "luabash",
506 &luabash_builtin,
507 BUILTIN_ENABLED,
508 luabash_doc,
509 LUABASH_VERSION,