summaryrefslogtreecommitdiff
path: root/main.c (plain)
blob: d9bb4d7a6ae0aa71a2b93130ff1fe8bb27767253
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
/*
** (C) 2007-2009 Tomi Belan
** see LICENSE and NOTICE for details
** derived from lua.c in the Lua distribution (MIT license)
*/


#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>


static lua_State *globalL = NULL;

static const char *progname = "error";


#define err_message(msg) (fprintf(stderr, "%s: %s\n", progname, (msg)), fflush(stderr), EXIT_FAILURE)

static int report (lua_State *L, int status) {
  if (status && !lua_isnil(L, -1)) {
    const char *msg = lua_tostring(L, -1);
    err_message(msg ? msg : "(error message is not a string)");
    lua_pop(L, 1);
  }
  return status;
}


static void sigint_luahook (lua_State *L, lua_Debug *ar) {
  (void)ar;  /* unused arg. */
  lua_sethook(L, NULL, 0, 0);
  luaL_error(L, "interrupted!");
}

static void sigint_handler (int i) {
  err_message("got SIGINT, raising exception (use ^C again if it gets stuck)");
  signal(i, SIG_DFL); /* if another SIGINT happens before lstop,
                              terminate process (default action) */
  lua_sethook(globalL, sigint_luahook, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1);
}


static void close_lua () {
  lua_gc(globalL, LUA_GCCOLLECT, 0);
  lua_close(globalL);
}


int main (int argc, char **argv) {
  lua_State *L;
  int i;
  
  if(argv[0] && argv[0][0])
    progname = argv[0];
  
  /* initialize Lua */
  if((globalL = L = lua_open()) == NULL)
    return err_message("Could not initialize Lua");
  atexit(close_lua);
  
  /* load Lua libraries and code */
  luaL_openlibs(L);
  lua_getglobal(L, "package");
  lua_getfield(L, -1, "preload");
  lua_remove(L, -2);   /* package */
#define LIB(id) int luaopen_##id(lua_State *); lua_pushcfunction(L, luaopen_##id); lua_setfield(L, -2, #id)
  /* ftgl requires gl, gl requires SDL, buf requires SDL */
  LIB(bit);
  LIB(SDL);
  LIB(gl);
  LIB(ftgl);
  LIB(lfs);
  LIB(win);
  LIB(zlib);
  LIB(buf);
#define CHUNK(id,name)                                  \
    if(report(L, luaL_loadbuffer(L, _chunk_##id,        \
        sizeof(_chunk_##id)/sizeof(char)-1, "=" name))) \
      return EXIT_FAILURE;                              \
    lua_setfield(L, -2, name);
#include "chunks.h"
  lua_getfield(L, -1, "launcher");
  lua_remove(L, -2);   /* package.preload */
  if(!lua_isfunction(L, -1))
    return err_message("package.preload.launcher not found");

  /* start the LuaJIT optimizer */
#ifdef LUA_JITLIBNAME
  if(report(L, luaL_dostring(L, "require'jit.opt'.start()")))
    return EXIT_FAILURE;
#endif
  
  /* load and run the program */
  lua_createtable(L, 1, argc - 1);
  for(i = 0; i < argc; i++) {
    lua_pushstring(L, argv[i]);
    lua_rawseti(L, -2, i);
  }
  lua_setglobal(L, "arg");
  signal(SIGINT, sigint_handler);
  if(report(L, lua_pcall(L, 0, 0, 0)))
    return EXIT_FAILURE;
  
  return EXIT_SUCCESS;
}