Skip to content

Instantly share code, notes, and snippets.

@benolee
Last active April 13, 2023 23:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save benolee/eb82e1c12a9c049cc406ba6482c465d0 to your computer and use it in GitHub Desktop.
Save benolee/eb82e1c12a9c049cc406ba6482c465d0 to your computer and use it in GitHub Desktop.

vedis bash loadable

what is this?

Loadables in bash are exactly like builtins, but you enable or disable at runtime. They're shared libraries whose main interface is receiving the WORD_LIST, which is basically the last command.

For this loadable, I want to provide nice data structures directly to bash.

Vedis is an embeddable self-contained library with commands and data structures from Redis, but without the networking.

example

For now, I'm just using vedis's command execution. But it would be nicer to have all this stuff work nicely with declare and other bash stuff.

  1. build it

you'll probably need the bash-builtins package from apt or whatever.

$ gcc -I /usr/include/bash/builtins -I /usr/include/bash/include -I /usr/include/bash -I /usr/lib/bash \
      -shared -fPIC -o vedis.so vedis_loadable.c vedis.c
  1. load the feature
$ enable -f ./vedis.so vedis
loaded vedis!
  1. use it (for now) via the vedis bash command, which is now a builtin
$ vedis
vedis> SET foo 42
true

$ vedis
vedis> GET foo
42

note that the values here are in memory for the current bash process itself.

hopefully I can figure out how to make these values interop with normal shell and bash operations.

for now, here's a hash, which bash absolutely sucks at.

$ vedis
vedis> HSET config path "/usr/local/etc"
true

$ vedis
vedis> HKEYS config
1) path

$ vedis
vedis> HGET config path
/usr/local/etc
https://github.com/symisc/vedis
https://github.com/symisc/vedis
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "builtins.h"
#include "shell.h"
#include "vedis.h"
int vedis_builtin(WORD_LIST *list);
int vedis_builtin_load(char *name);
int vedis_builtin_unload(char *name);
static vedis *pStore;
static void Fatal(const char *zMsg)
{
puts(zMsg);
vedis_lib_shutdown();
exit(0);
}
void vedis_exit(void)
{
vedis_lib_shutdown();
}
int isBlank(const char *zIn,unsigned int nByte)
{
const char *zEnd = &zIn[nByte];
while( zIn < zEnd && (isspace(zIn[0])) ){
zIn++;
}
return (zIn[0] == 0 || zIn >= zEnd) ? 1 : 0;
}
struct array_rend
{
int is_first;
int cnt;
};
static int array_render(vedis_value *pEntry,void *pUserdata);
static int command_result_render(vedis_value *pResult,void *pUnused /* userdata */)
{
const char *zResult = 0;
if( vedis_value_is_null(pResult) ){
zResult = "<null>";
}else if( vedis_value_is_array(pResult) ){
struct array_rend sRend = { 1 , 0 };
vedis_array_walk(pResult,array_render,&sRend);
}else{
zResult = vedis_value_to_string(pResult,0);
}
if( zResult ){
puts(zResult);
}
return VEDIS_OK;
}
int vedis_builtin(WORD_LIST *list)
{
char zBuf[4096], *zPtr;
int rc;
vedis_config(pStore, VEDIS_CONFIG_OUTPUT_CONSUMER, command_result_render, 0 /* userdata */);
atexit(vedis_exit);
fputs("vedis>", stdout);
zPtr = fgets(zBuf, sizeof(zBuf), stdin);
if( !zPtr || isBlank(zBuf,sizeof(zBuf)) ){
puts("Exiting...comitting the transaction");
return EXECUTION_SUCCESS;
}
rc = vedis_exec(pStore, zBuf,-1);
if(rc != VEDIS_OK ){
const char *zErr;
int nLen;
vedis_config(pStore, VEDIS_CONFIG_ERR_LOG, &zErr, &nLen);
if( nLen > 0 ){
puts(zErr);
}
if( rc != VEDIS_UNKNOWN){
// break;
}
}
}
static int array_render(vedis_value *pEntry,void *pUserdata)
{
struct array_rend *pRend = (struct array_rend *)pUserdata;
const char *zValue;
int nByte;
if( vedis_value_is_null(pEntry) ){
zValue = "<null>";
nByte = (int)sizeof("<null>") - 1;
}else{
zValue = vedis_value_to_string(pEntry, &nByte);
}
printf("%d) %.*s\n", ++pRend->cnt, nByte, zValue);
return VEDIS_OK;
}
int vedis_builtin_load(char *name)
{
int rc;
printf("loaded %s!\n", name);
rc = vedis_open(&pStore, ":mem:");
if( rc != VEDIS_OK ){ Fatal("Vedis is running out of memory"); }
return (1);
}
int vedis_builtin_unload(char *name)
{
printf("unloaded %s!\n", name);
vedis_close(pStore);
return (1);
}
char *vedis_doc[] = {
"Create vedis connection.",
"",
"Longer description of vedis builtin and usage",
(char *)NULL
};
struct builtin vedis_struct = {
"vedis", /* builtin name */
vedis_builtin, /* function implementing the builtin */
BUILTIN_ENABLED, /* initial flags for builtin */
vedis_doc, /* array of long documentation strings */
"vedis", /* usage synopsis; becomes short_doc */
0 /* reserved for internal use */
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment