On Wednesday, 18 October 2017 at 03:48:01 UTC, Ky-Anh Huynh wrote:
Hi,
I'm using Bash heavily in my systems. Things become slow and
slow when I have tons of scripts :) And sometimes it's not easy
to manipulate data.
You may have heard of recutils [1] which has a C extension to
be loaded by Bash. Is it possible to write similar things in D,
for Bash? I am not good at C; it's great if I explore this
field:)
Some examples in C are in [2].
My experience: Dlang has `pipe` support however the syntax is
not as clean as Bash :) Most of the times I see short (<1k loc)
Bash scripts are easy to maintain than Ruby (and now D things)
scripts.
[2]:
http://git.savannah.gnu.org/cgit/bash.git/tree/examples/loadables/cat.c
(Not a linux pro or even bash user here, don't know anything
about bash API or internals, not even a C user, proceed on your
own risk)
Need to investigate how bash actually handles loading
From the look of it there is configuration struct of type
'builtin' that has basically and entry point function that serves
as main('cat_builtin'), documentation function ('cat_doc') and
other required stuff.
But yes, in theory nothing crazy and seems doable.
Now according to the readme in examples folder
"""
Loadable builtins are loaded into a running shell with
enable -f filename builtin-name
"""
This give a hint to look at what this 'enable' implementation
does, my guess it can do a simple dlopen(filename) and then
dlsym(builtin-name) that most likely expected to be one of those
struct of type 'builtin' or that *_builtin() function, and the
rest is implemenetation details.
And... yes (can search for dlsym) -
http://git.savannah.gnu.org/cgit/bash.git/tree/builtins/enable.def#n365
Now with that knowledge it should be possible to our test plugin.
Some (pseudo) code that could serve as starting point...
-------------------------------------------------
// first we need 'builtin' struct in D
// (from
http://git.savannah.gnu.org/cgit/bash.git/tree/builtins.h)
struct builtin {
char* name; /* The name that the user types. */
sh_builtin_func_t function; /* The address of the invoked
function. */
int flags; /* One of the #defines above. */
const(char)* const* long_doc; /* NULL terminated array of
strings. */
const(char)* short_doc; /* Short version of documentation. */
char* handle; /* for future use */
}
// add some declarations
alias sh_builtin_func_t = extern(C) int sh_builtin_func_t
(WORD_LIST *);
enum BUILTIN_ENABLED = 0x01; // builtins.h
// TODO: find WORD_LIST declaration (sorry)
extern(C) static builtin plugtest_struct = {
"testcommand", // function will be acessible by this name?
test_builtin,
BUILTIN_ENABLED,
test_doc.ptr, // will need to convert string[] to char**
// the
"testcommand [-] [file ...]",
0
};
string[] test_doc = [
"Out test function."
];
//
http://git.savannah.gnu.org/cgit/bash.git/tree/examples/loadables/cat.c#n91
// seems like default int return, if you got a segfault then it
is something else
extern(C) static int test_builtin(WORD_LIST* list)
{
import core.runtime; // don't remember the exact names,
sorry, but this one is required
import std.stdio : writeln;
Runtime.initialize(); // you would probably need to track
this one because command can be called multiple times during
plugin lifetime
writeln("it works!"); // if you see this in terminal you
are lucky, otherwise find out what is 'write' and use it instead
return 0;
}
---------------------------------------------------------------
This isn't the actual code but should give you a hint, the rest
is up to you.