aboutsummaryrefslogtreecommitdiff
path: root/scripts/generate_header.sh
blob: 787f6b088c511d7c525c2ef5f11a02104d0e5ac5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#!/bin/bash

##### CONFIG

# symbols to ignore
IGNORE_SYM='luaL_pushmodule'

##### 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);/"
}

# create a stub function that warns user when calling it
makestub() {
  grep '^LUA' | grep -v "$IGNORE_SYM" | sed -e "s/$sym_regex/static\t\2\t__pragtical_fallback_\3\t(\4) { fputs(\"warning: \3 is a stub\", stderr); }/"
}

import_sym() {
  grep '^LUA' | grep -v "$IGNORE_SYM" | sed -e "s/$sym_regex/\tIMPORT_SYMBOL(\3, \2, \4);/"
}

decl() {
  echo "/** $(basename "$1") **/"
  echo

  header="$(uncomment $1 | discard_preprocessors)"
  header1="$(onelineize <<< "$header")"

  # typedef
  grep -v '^\(LUA\|#\|extern\)' <<< "$header1"
  # funcptrs
  ptrize <<< "$header1"
  # defines
  (grep '^#' | grep -v "$IGNORE_SYM") <<< "$header"
  # stubs
  makestub <<< "$header1"
}

decl_import() {
  uncomment $1 | onelineize | import_sym
}

generate_header() {
  local LUA_PATH="$1"
  echo "#ifndef PRAGTICAL_PLUGIN_API"
  echo "#define PRAGTICAL_PLUGIN_API"
  echo "/**"
  echo "The pragtical 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 "pragtical_plugin_api.h"'
  echo "int luaopen_pragtical_xxxxx(lua_State* L, void* XL) {"
  echo "  pragtical_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 "/** luaconf.h **/"
  echo
  uncomment "$LUA_PATH/luaconf.h"
  echo

  decl "$LUA_PATH/lua.h"
  echo
  decl "$LUA_PATH/lauxlib.h"
  echo "static  void (*luaL_openlibs)      (lua_State *L);"
  echo 'static  void  __pragtical_fallback_luaL_openlibs    (lua_State *L) { fputs("warning: luaL_openlibs is a stub", stderr); }'
  echo

  echo "#define IMPORT_SYMBOL(name, ret, ...) name = (name = (ret (*) (__VA_ARGS__)) symbol(#name), name == NULL ? &__pragtical_fallback_##name : name)"
  echo "static void pragtical_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 -e "\tIMPORT_SYMBOL(luaL_openlibs, void, lua_State* L);"

  echo "}"
  echo "#endif"
}

show_help() {
  echo -e "Usage: $0 <OPTIONS> prefix"
  echo
  echo -e "Available options:"
  echo -e "-p\t--prefix\tSet prefix (where to find lua.h and lauxlib.h)"
}

main() {
  local prefix=""

  for i in "$@"; do
    case $i in
      -h|--help)
        show_help
        exit 0
        ;;
      -p|--prefix)
        prefix="$2"
        shift
        shift
        ;;
      *)
        ;;
    esac
  done

  generate_header "$prefix"
}

main "$@"
# create a stub function that warns user when calling it