2 * --- T2-COPYRIGHT-NOTE-BEGIN ---
3 * This copyright note is auto-generated by ./scripts/Create-CopyPatch.
5 * T2 SDE: misc/luabash/bash/luabash.c
6 * Copyright (C) 2019 The T2 SDE Project
8 * More information can be found in the files COPYING and README.
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 ---
18 // gcc -shared -fPIC -Wall -o luabash.so luabash.c -llua -lm -Wall -ldl
20 /* Some declarations copied from bash-3.1 headers */
32 #define EXECUTION_SUCCESS 0
33 #define EXECUTION_FAILURE 1
35 typedef struct word_desc
{
40 typedef struct word_list
{
41 struct word_list
*next
;
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. */
53 sh_builtin_func_t
*function
;
55 char * const *long_doc
;
56 const char *short_doc
;
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
{
70 sh_var_value_func_t
*dynamic_value
;
71 sh_var_assign_func_t
*assign_func
;
77 typedef struct redirect
{
78 int data
; // this is not quite true, but we don't need 'em here...
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
;
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. */
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 */
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 */
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. */
144 /****************************************************/
146 typedef struct simple_com
{
154 typedef struct 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
;
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
;
181 default: // somethings wrong here...
188 /****************************************************/
191 #define __P(proto) proto
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!
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
));
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
;
258 /* helpers to work with variables, thanks to clifford */
260 static const char *getvar(const char *name
)
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
[] = {
281 "\tload <lua chunk>",
282 "\tcall <lua function> [arguments]",
286 static int initialized
=0;
289 static void print_usage()
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
;
312 wfnname
->next
=warguments
;
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
);
327 static int get_variable (lua_State
*L
)
329 const char* vname
= luaL_checkstring(L
, 1);
330 lua_pushstring(L
, getvar(vname
));
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
);
342 static int call_bashfunction (lua_State
*L
)
344 int no_args
=lua_gettop(L
);
351 for (i
=0; i
<no_args
; i
++) {
352 const char* string
=luaL_checkstring(L
, i
+1);
354 list
->next
=(WORD_LIST
*) malloc(sizeof(WORD_LIST
));
357 list
=(WORD_LIST
*) malloc(sizeof(WORD_LIST
));
360 list
->word
=make_word(string
);
367 SIMPLE_COM
* cmd
=newSimpleCom(start
);
368 retval
=execute_command(make_command(cm_simple
, cmd
));
370 lua_pushinteger(L
,retval
);
374 static int get_environment (lua_State
*L
)
376 SHELL_VAR
** list
=all_shell_variables();
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
);
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
},
400 static int init_luabash()
403 const char* bash_version
=getvar("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
;
421 fprintf(stderr
, "lua bash error: failed to initialize lua state\n");
422 return EXECUTION_FAILURE
;
426 luaL_register(L
, "bash", bashlib
);
431 return EXECUTION_SUCCESS
;
434 static int load_chunk(const char* filename
)
436 int result
=init_luabash();
437 if (result
!= EXECUTION_SUCCESS
)
440 if (luaL_loadfile(L
, filename
) || lua_pcall(L
, 0, 0, 0))
443 return EXECUTION_SUCCESS
;
446 static int call_function(const char* func
, WORD_LIST
*argv
)
451 fprintf(stderr
, "lua bash error: not initialized yet!\n");
452 return EXECUTION_FAILURE
;
455 lua_getglobal(L
, func
);
459 if (argv
->word
->word
) {
460 lua_pushstring(L
, argv
->word
->word
);
466 if (lua_pcall(L
, argc
, 1, 0))
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
;
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) {
490 if (list
&& (list
->word
->word
))
491 return load_chunk(list
->word
->word
);
492 } else if (strcmp(command
, "call") == 0) {
494 if (list
&& (list
->word
->word
))
495 return call_function(list
->word
->word
, list
->next
);
500 return EXECUTION_FAILURE
;
504 struct builtin luabash_struct
= {