lite-xl/scripts/generate_header.sh

197 lines
4.7 KiB
Bash
Executable File

#!/bin/bash
##### CONFIG
# symbols to ignore
IGNORE_SYM='luaL_pushmodule\|luaL_openlib'
##### CONFIG
# https://stackoverflow.com/a/13062682
uncomment() {
[ $# -eq 2 ] && arg="$1" || arg=""
eval file="\$$#"
sed 's/a/aA/g; s/__/aB/g; s/#/aC/g' "$file" | \
gcc -P -E $arg - | \
sed 's/aC/#/g; s/aB/__/g; s/aA/a/g'
}
# this is the magic that turns multiline statements into
# single line statements
# LITERALLY DOES NOT WORK WITH PREPROCESSOR
onelineize() {
grep -v '^#' | sed -e ':r;$!{N;br};s/\([^{;]\)\n\s*/\1 /g'
}
discard_preprocessors() {
grep -v '#\(include\|if\|endif\)'
}
# sed regex for extracting data from function signature
# if this isn't regex, idk what is
# LUA_API (return type as \2) (function name as \3) (args as \4)
sym_regex='^LUA\(LIB\)\?_API\s\+\([^(]\+\)\s*(\([^)]\+\))\s\+(\([^)]\+\));'
# get funcptr declarations
ptrize() {
grep '^LUA' | grep -v "$IGNORE_SYM" | sed -e "s/$sym_regex/static\t\2(*\3)\t(\4);/"
}
import_sym() {
grep '^LUA' | grep -v "$IGNORE_SYM" | sed -e "s/$sym_regex/\tIMPORT_SYMBOL(\3, \2, \4);/"
}
export_sym() {
grep '^LUA' | grep -v "$IGNORE_SYM" | sed -e "s/$sym_regex/\t\tEXPORT_SYMBOL(\3),/"
}
decl() {
header="$(uncomment $1 | discard_preprocessors)"
header1="$(onelineize <<< "$header")"
# typedef
grep -v '^\(LUA\|#\|extern\)' <<< "$header1"
# funcptrs
ptrize <<< "$header1"
# defines
(grep '^#' | grep -v "$IGNORE_SYM") <<< "$header"
}
decl_import() {
uncomment $1 | onelineize | import_sym
}
decl_export() {
uncomment $1 | onelineize | export_sym
}
generate_header() {
local LUA_PATH="$1"
echo "#ifndef LITE_XL_PLUGIN_API"
echo "#define LITE_XL_PLUGIN_API"
echo "/**"
echo "The lite_xl plugin API is quite simple. Any shared library can be a plugin file, so long"
echo "as it has an entrypoint that looks like the following, where xxxxx is the plugin name:"
echo '#include "lite_xl_plugin_api.h"'
echo "int lua_open_lite_xl_xxxxx(lua_State* L, void* XL) {"
echo " lite_xl_plugin_init(XL);"
echo " ..."
echo " return 1;"
echo "}"
echo "In linux, to compile this file, you'd do: 'gcc -o xxxxx.so -shared xxxxx.c'. Simple!"
echo "Due to the way the API is structured, you *should not* link or include lua libraries."
echo "This file was automatically generated. DO NOT MODIFY DIRECTLY."
echo "**/"
echo
echo
echo "#include <stdarg.h>"
echo "#include <stdio.h> // for BUFSIZ? this is kinda weird"
echo
echo
cat "$LUA_PATH/luaconf.h"
decl "$LUA_PATH/lua.h"
decl "$LUA_PATH/lauxlib.h"
echo "#define IMPORT_SYMBOL(name, ret, ...) name = (ret (*) (__VA_ARGS__)) symbol(#name)"
echo "static void lite_xl_plugin_init(void *XL) {"
echo -e "\tvoid* (*symbol)(const char *) = (void* (*) (const char *)) XL;"
decl_import "$LUA_PATH/lua.h"
decl_import "$LUA_PATH/lauxlib.h"
echo "}"
echo "#endif"
}
generate_api_require() {
local LUA_PATH="$1"
echo "#ifndef API_REQUIRE_H"
echo "#define API_REQUIRE_H"
echo "/**"
echo "This file contains the function api_require that"
echo "returns a function pointer with it's corresponding name."
echo
echo "This file is automatically generated. DO NOT MODIFY."
echo "**/"
echo
echo
echo "#include <string.h>"
echo "#include <stddef.h>"
echo '#include "lua.h"'
echo '#include "lauxlib.h"'
echo
echo "typedef struct fnptr_s {"
echo -e "\tconst char* name;"
echo -e "\tvoid *addr;"
echo "} fnptr_t;"
echo
echo "#define EXPORT_SYMBOL(SYM) { #SYM, (void*)(SYM) }"
echo "static void *api_require(const char *symbol) {"
echo -e "\tstatic fnptr_t nodes[] = {"
decl_export "$LUA_PATH/lua.h"
decl_export "$LUA_PATH/lauxlib.h"
echo -e "\t};"
echo -e "\tfor (int i = 0; i < sizeof(nodes) / sizeof(fnptr_t); i++)"
echo -e "\t\tif (strcmp(nodes[i].name, symbol) == 0)"
echo -e "\t\t\treturn nodes[i].addr;"
echo -e "\treturn NULL;"
echo "}"
echo "#endif"
}
show_help() {
echo -e "Usage: $0 <OPTIONS> prefix"
echo
echo -e "Available options:"
echo
echo -e "-a\t--api-header\tGenerate lite_xl_plugin_api.h"
echo -e "-b\t--api-require\tGenerate api_require.h"
echo -e "-p\t--prefix\tSet prefix (where to find lua.h and lauxlib.h)"
}
main() {
local header=0
local require=0
local prefix=""
for i in "$@"; do
case $i in
-h|--help)
show_help
exit 0
;;
-a|--api-header)
header=1
shift
;;
-b|--api-require)
require=1
shift
;;
-p|--prefix)
prefix="$2"
shift
shift
;;
*)
;;
esac
done
if [[ "$header" -eq 1 ]]; then
generate_header "$prefix"
elif [[ "$require" -eq 1 ]]; then
generate_api_require "$prefix"
else
show_help
exit 1
fi
}
main "$@"