/* * Copyright 2009 by egnite GmbH * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * For additional information see http://www.ethernut.de/ */ /* ** Based on ** Id: lua.c,v 1.160.1.2 2007/12/28 15:32:23 roberto Exp ** Lua stand-alone interpreter ** See Copyright Notice in lua.h */ #include #include #include #include #include #include #include #include #include #include #include #include #define lua_c #include #include #include #if defined(__AVR_ARCH__) && !defined(__OPTIMIZE__) int main(void) { unsigned long baud = 115200; /* Initialize the console. */ NutRegisterDevice(&DEV_CONSOLE, 0, 0); freopen(DEV_CONSOLE.dev_name, "w", stdout); _ioctl(_fileno(stdin), UART_SETSPEED, &baud); /* Display banner. */ puts("\nPlease compile the LUA example with optimization enabled\n"); while(1) NutSleep(100); } #else #ifndef NUTLUA_PARSER_EXCLUDED #ifdef __AVR__ #define THREAD_LUASTACK 2048 #else #define THREAD_LUASTACK 8192 #endif static char lua_line_buffer[LUA_MAXINPUT]; static EDLINE *lua_line_edit; /* * Report bad state. */ static void report(lua_State * L) { if (!lua_isnil(L, -1)) { const char *msg = lua_tostring(L, -1); if (msg == NULL) msg = "(error object is not a string)"; fputs(msg, stderr); fputc('\n', stderr); fflush(stderr); lua_pop(L, 1); } } /* * Perform Lua back trace. */ static int traceback(lua_State * L) { if (!lua_isstring(L, 1)) /* 'message' not a string? */ return 1; /* keep it intact */ lua_getfield(L, LUA_GLOBALSINDEX, "debug"); if (!lua_istable(L, -1)) { lua_pop(L, 1); return 1; } lua_getfield(L, -1, "traceback"); if (!lua_isfunction(L, -1)) { lua_pop(L, 2); return 1; } lua_pushvalue(L, 1); /* pass error message */ lua_pushinteger(L, 2); /* skip this function and traceback */ lua_call(L, 2, 1); /* call debug.traceback */ return 1; } /* * Execute the chunk on top of the Lua stack. */ static int docall(lua_State * L) { int status; int base; /* function index */ /* Retrieve the function index and push the traceback ** function below the chunk and its arguments. */ base = lua_gettop(L); lua_pushcfunction(L, traceback); lua_insert(L, base); status = lua_pcall(L, 0, LUA_MULTRET, base); /* Remove the traceback function. */ lua_remove(L, base); /* Force a complete garbage collection in case of errors. */ if (status) lua_gc(L, LUA_GCCOLLECT, 0); return status; } /* * Retrieve the currently valid prompt. */ static const char *get_prompt(lua_State * L, int firstline) { const char *p; /* Try global settings first. */ lua_getfield(L, LUA_GLOBALSINDEX, firstline ? "_PROMPT" : "_PROMPT2"); p = lua_tostring(L, -1); if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2); lua_pop(L, 1); return p; } /* * Check if Lua chunk is complete. */ static int is_complete(lua_State * L, int status) { if (status == LUA_ERRSYNTAX) { size_t lmsg; const char *msg = lua_tolstring(L, -1, &lmsg); const char *tp = msg + lmsg - (sizeof(LUA_QL("")) - 1); if (strstr(msg, LUA_QL("")) == tp) { lua_pop(L, 1); return 0; } } return 1; } /* * Get next line of a Lua chunk. */ static int pushline(lua_State * L, int firstline) { int l; const char *prmt; /* Display a prompt. */ prmt = get_prompt(L, firstline); fputs(prmt, stdout); fflush(stdout); /* Get a new line from the line editor. */ lua_line_buffer[0] = '\0'; l = EdLineRead(lua_line_edit, lua_line_buffer, LUA_MAXINPUT); if (l >= 0) { /* Replace '=' at the beginning with 'return'. */ if (firstline && lua_line_buffer[0] == '=') lua_pushfstring(L, "return %s", &lua_line_buffer[1]); else lua_pushstring(L, lua_line_buffer); } return l; } /* * Load complete Lua chunk. */ static int loadchunk(lua_State * L) { int status = -1; /* Clear Lua stack. */ lua_settop(L, 0); if (pushline(L, 1) >= 0) { /* Loop until we have a complete chunk. */ for (;;) { status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin"); /* If the line is complete, we are done. */ if (is_complete(L, status)) break; /* Otherwise try to get another line. */ if (pushline(L, 0) < 0) return -1; /* Add a linefeed between the two lines and join them. */ lua_pushliteral(L, "\n"); lua_insert(L, -2); lua_concat(L, 3); } lua_saveline(L, 1); lua_remove(L, 1); } return status; } /* * Lua line processing loop. */ static int pmain(lua_State * L) { int status; /* Open pre-configured libraries. Garbage collector must be disabled. */ lua_gc(L, LUA_GCSTOP, 0); luaL_openlibs(L); lua_gc(L, LUA_GCRESTART, 0); /* This loop loads Lua chunks and processes them until we get an ** input error. We may later use Ctrl-C or break to exit the ** interpreter. Right now this is not supported by our line editor. */ while ((status = loadchunk(L)) != -1) { /* If everything is OK, execute the chunk. */ if (status == 0) status = docall(L); /* Report bad state... */ if (status) { report(L); } /* ...or print result, if any. */ else if (lua_gettop(L) > 0) { lua_getglobal(L, "print"); lua_insert(L, 1); if (lua_pcall(L, lua_gettop(L) - 1, 0, 0) != 0) { fprintf(stderr, lua_pushfstring(L, "error calling " LUA_QL("print") " (%s)", lua_tostring(L, -1))); fputc('\n', stderr); fflush(stderr); } } } /* Clear Lua stack. */ lua_settop(L, 0); fputc('\n', stdout); fflush(stdout); return 0; } /* * Lua interpreter thread. */ THREAD(LuaThread, arg) { lua_State *L; for (;;) { /* Display second banner line here, so we know ** that everything is up and running. */ printf("Running on Nut/OS %s - %ld bytes free\n", NutVersionString(), (long)NutHeapAvailable()); /* Open the line editor. */ lua_line_edit = EdLineOpen(EDIT_MODE_ECHO | EDIT_MODE_HISTORY); if (lua_line_edit) { /* Register VT100 key mapping. This makes the arrow keys ** work when using a VT100 terminal emulator for input. */ EdLineRegisterKeymap(lua_line_edit, EdLineKeyMapVt100); /* Create a Lua state. */ L = lua_open(); if (L) { if (lua_cpcall(L, &pmain, NULL)) { report(L); } /* Release the Lua state. */ lua_close(L); } /* Release the line editor. */ EdLineClose(lua_line_edit); } } } #endif /* NUTLUA_PARSER_EXCLUDED */ /* * Lua interpreter entry. */ int main(void) { unsigned long baud = 115200; /* Initialize the console. */ NutRegisterDevice(&DEV_CONSOLE, 0, 0); freopen(DEV_CONSOLE.dev_name, "w", stdout); freopen(DEV_CONSOLE.dev_name, "w", stderr); freopen(DEV_CONSOLE.dev_name, "r", stdin); _ioctl(_fileno(stdin), UART_SETSPEED, &baud); /* Display banner. */ puts("\n" LUA_RELEASE " " LUA_COPYRIGHT); #ifdef NUTLUA_PARSER_EXCLUDED puts("Error: Stand-alone interpreter requires parser"); #else #ifdef NUTLUA_IOLIB_TCP NutRegisterDevice(&DEV_ETHER, 0, 0); if (NutDhcpIfConfig(DEV_ETHER_NAME, 0, 60000)) { uint8_t mac[6] = { 0x00, 0x06, 0x98, 0x00, 0x00, 0x00 }; if (NutDhcpIfConfig("eth0", mac, 60000)) { uint32_t ip_addr = inet_addr("192.168.192.100"); uint32_t ip_mask = inet_addr("255.255.255.0"); NutNetIfConfig("eth0", mac, ip_addr, ip_mask); } } printf("Network interface %s\n", inet_ntoa(confnet.cdn_ip_addr)); #endif /* NUTLUA_IOLIB_TCP */ /* Lua is stack hungry and requires to adjust the stack size of our ** main thread. To get it run on a standard system we create a new ** thread with sufficient stack space. */ NutThreadCreate("lua", LuaThread, NULL, THREAD_LUASTACK * NUT_THREAD_STACK_MULT + NUT_THREAD_STACK_ADD); #endif /* NUTLUA_PARSER_EXCLUDED */ /* Nothing left to do here. */ for(;;) { NutSleep(1000); } return 0; } #endif