lua.c

Go to the documentation of this file.
00001 /*
00002  * Copyright 2009 by egnite GmbH
00003  *
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  *
00010  * 1. Redistributions of source code must retain the above copyright
00011  *    notice, this list of conditions and the following disclaimer.
00012  * 2. Redistributions in binary form must reproduce the above copyright
00013  *    notice, this list of conditions and the following disclaimer in the
00014  *    documentation and/or other materials provided with the distribution.
00015  * 3. Neither the name of the copyright holders nor the names of
00016  *    contributors may be used to endorse or promote products derived
00017  *    from this software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00020  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00021  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00022  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00023  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00024  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00025  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00026  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00027  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00028  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00029  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00030  * SUCH DAMAGE.
00031  *
00032  * For additional information see http://www.ethernut.de/
00033  */
00034 
00035 /*
00036 ** Based on
00037 ** Id: lua.c,v 1.160.1.2 2007/12/28 15:32:23 roberto Exp
00038 ** Lua stand-alone interpreter
00039 ** See Copyright Notice in lua.h
00040 */
00041 
00042 #include <dev/board.h>
00043 #include <sys/version.h>
00044 #include <sys/heap.h>
00045 #include <sys/timer.h>
00046 #include <sys/confnet.h>
00047 
00048 #include <gorp/edline.h>
00049 
00050 #include <arpa/inet.h>
00051 #include <pro/dhcp.h>
00052 
00053 #include <stdio.h>
00054 #include <io.h>
00055 #include <string.h>
00056 
00057 #define lua_c
00058 
00059 #include <lua/lua.h>
00060 
00061 #include <lua/lauxlib.h>
00062 #include <lua/lualib.h>
00063 
00064 #ifndef NUTLUA_PARSER_EXCLUDED
00065 
00066 #ifdef __AVR__
00067 #define THREAD_LUASTACK     2048
00068 #else
00069 #define THREAD_LUASTACK     8192
00070 #endif
00071 
00072 static char lua_line_buffer[LUA_MAXINPUT];
00073 static EDLINE *lua_line_edit;
00074 
00075 /*
00076  * Report bad state.
00077  */
00078 static void report(lua_State * L)
00079 {
00080     if (!lua_isnil(L, -1)) {
00081         const char *msg = lua_tostring(L, -1);
00082 
00083         if (msg == NULL)
00084             msg = "(error object is not a string)";
00085         fputs(msg, stderr);
00086         fputc('\n', stderr);
00087         fflush(stderr);
00088         lua_pop(L, 1);
00089     }
00090 }
00091 
00092 /*
00093  * Perform Lua back trace.
00094  */
00095 static int traceback(lua_State * L)
00096 {
00097     if (!lua_isstring(L, 1))    /* 'message' not a string? */
00098         return 1;               /* keep it intact */
00099     lua_getfield(L, LUA_GLOBALSINDEX, "debug");
00100     if (!lua_istable(L, -1)) {
00101         lua_pop(L, 1);
00102         return 1;
00103     }
00104     lua_getfield(L, -1, "traceback");
00105     if (!lua_isfunction(L, -1)) {
00106         lua_pop(L, 2);
00107         return 1;
00108     }
00109     lua_pushvalue(L, 1);        /* pass error message */
00110     lua_pushinteger(L, 2);      /* skip this function and traceback */
00111     lua_call(L, 2, 1);          /* call debug.traceback */
00112     return 1;
00113 }
00114 
00115 /*
00116  * Execute the chunk on top of the Lua stack.
00117  */
00118 static int docall(lua_State * L)
00119 {
00120     int status;
00121     int base;    /* function index */
00122 
00123     /* Retrieve the function index and push the traceback 
00124     ** function below the chunk and its arguments. */
00125     base = lua_gettop(L);
00126     lua_pushcfunction(L, traceback);
00127     lua_insert(L, base);
00128 
00129     status = lua_pcall(L, 0, LUA_MULTRET, base);
00130 
00131     /* Remove the traceback function. */
00132     lua_remove(L, base);
00133 
00134     /* Force a complete garbage collection in case of errors. */
00135     if (status)
00136         lua_gc(L, LUA_GCCOLLECT, 0);
00137 
00138     return status;
00139 }
00140 
00141 /*
00142  * Retrieve the currently valid prompt.
00143  */
00144 static const char *get_prompt(lua_State * L, int firstline)
00145 {
00146     const char *p;
00147 
00148     /* Try global settings first. */
00149     lua_getfield(L, LUA_GLOBALSINDEX, firstline ? "_PROMPT" : "_PROMPT2");
00150     p = lua_tostring(L, -1);
00151     if (p == NULL)
00152         p = (firstline ? LUA_PROMPT : LUA_PROMPT2);
00153     lua_pop(L, 1);
00154 
00155     return p;
00156 }
00157 
00158 /*
00159  * Check if Lua chunk is complete.
00160  */
00161 static int is_complete(lua_State * L, int status)
00162 {
00163     if (status == LUA_ERRSYNTAX) {
00164         size_t lmsg;
00165         const char *msg = lua_tolstring(L, -1, &lmsg);
00166         const char *tp = msg + lmsg - (sizeof(LUA_QL("<eof>")) - 1);
00167 
00168         if (strstr(msg, LUA_QL("<eof>")) == tp) {
00169             lua_pop(L, 1);
00170             return 0;
00171         }
00172     }
00173     return 1;
00174 }
00175 
00176 /*
00177  * Get next line of a Lua chunk.
00178  */
00179 static int pushline(lua_State * L, int firstline)
00180 {
00181     int l;
00182     const char *prmt;
00183 
00184     /* Display a prompt. */
00185     prmt = get_prompt(L, firstline);
00186     fputs(prmt, stdout);
00187     fflush(stdout);
00188 
00189     /* Get a new line from the line editor. */
00190     lua_line_buffer[0] = '\0';
00191     l = EdLineRead(lua_line_edit, lua_line_buffer, LUA_MAXINPUT);
00192 
00193     if (l >= 0) {
00194         /* Replace '=' at the beginning with 'return'. */
00195         if (firstline && lua_line_buffer[0] == '=')
00196             lua_pushfstring(L, "return %s", &lua_line_buffer[1]);
00197         else
00198             lua_pushstring(L, lua_line_buffer);
00199     }
00200     return l;
00201 }
00202 
00203 /*
00204  * Load complete Lua chunk.
00205  */
00206 static int loadchunk(lua_State * L)
00207 {
00208     int status = -1;
00209 
00210     /* Clear Lua stack. */
00211     lua_settop(L, 0);
00212 
00213     if (pushline(L, 1) >= 0) {
00214         /* Loop until we have a complete chunk. */
00215         for (;;) {
00216             status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin");
00217             /* If the line is complete, we are done. */
00218             if (is_complete(L, status))
00219                 break;
00220             /* Otherwise try to get another line. */
00221             if (pushline(L, 0) < 0)
00222                 return -1;
00223             /* Add a linefeed between the two lines and join them. */
00224             lua_pushliteral(L, "\n");
00225             lua_insert(L, -2);
00226             lua_concat(L, 3);
00227         }
00228         lua_saveline(L, 1);
00229         lua_remove(L, 1);
00230     }
00231     return status;
00232 }
00233 
00234 /*
00235  * Lua line processing loop.
00236  */
00237 static int pmain(lua_State * L)
00238 {
00239     int status;
00240 
00241     /* Open pre-configured libraries. Garbage collector must be disabled. */
00242     lua_gc(L, LUA_GCSTOP, 0);
00243     luaL_openlibs(L);
00244     lua_gc(L, LUA_GCRESTART, 0);
00245 
00246     /* This loop loads Lua chunks and processes them until we get an 
00247     ** input error. We may later use Ctrl-C or break to exit the 
00248     ** interpreter. Right now this is not supported by our line editor. */
00249     while ((status = loadchunk(L)) != -1) {
00250         /* If everything is OK, execute the chunk. */
00251         if (status == 0)
00252             status = docall(L);
00253         /* Report bad state... */
00254         if (status) {
00255             report(L);
00256         }
00257         /* ...or print result, if any. */
00258         else if (lua_gettop(L) > 0) {
00259             lua_getglobal(L, "print");
00260             lua_insert(L, 1);
00261             if (lua_pcall(L, lua_gettop(L) - 1, 0, 0) != 0) {
00262                 fprintf(stderr, lua_pushfstring(L, "error calling " 
00263                     LUA_QL("print") " (%s)", lua_tostring(L, -1)));
00264                 fputc('\n', stderr);
00265                 fflush(stderr);
00266             }
00267         }
00268     }
00269     /* Clear Lua stack. */
00270     lua_settop(L, 0);
00271 
00272     fputc('\n', stdout);
00273     fflush(stdout);
00274 
00275     return 0;
00276 }
00277 
00278 /*
00279  * Lua interpreter thread.
00280  */
00281 THREAD(LuaThread, arg)
00282 {
00283     lua_State *L;
00284 
00285     for (;;) {
00286         /* Display second banner line here, so we know 
00287         ** that everything is up and running. */
00288         printf("Running on Nut/OS %s - %ld bytes free\n", NutVersionString(), (long)NutHeapAvailable());
00289 
00290         /* Open the line editor. */
00291         lua_line_edit = EdLineOpen(EDIT_MODE_ECHO | EDIT_MODE_HISTORY);
00292         if (lua_line_edit) {
00293             /* Register VT100 key mapping. This makes the arrow keys 
00294             ** work when using a VT100 terminal emulator for input. */
00295             EdLineRegisterKeymap(lua_line_edit, EdLineKeyMapVt100);
00296 
00297             /* Create a Lua state. */
00298             L = lua_open();
00299             if (L) {
00300                 if (lua_cpcall(L, &pmain, NULL)) {
00301                     report(L);
00302                 }
00303                 /* Release the Lua state. */
00304                 lua_close(L);
00305             }
00306             /* Release the line editor. */
00307             EdLineClose(lua_line_edit);
00308         }
00309     }
00310 }
00311 
00312 #endif /* NUTLUA_PARSER_EXCLUDED */
00313 
00314 /*
00315  * Lua interpreter entry.
00316  */
00317 int main(void)
00318 {
00319     unsigned long baud = 115200;
00320 
00321     /* Initialize the console. */
00322     NutRegisterDevice(&DEV_UART, 0, 0);
00323     freopen(DEV_UART_NAME, "w", stdout);
00324     freopen(DEV_UART_NAME, "w", stderr);
00325     freopen(DEV_UART_NAME, "r", stdin);
00326     _ioctl(_fileno(stdin), UART_SETSPEED, &baud);
00327 
00328     /* Display banner. */
00329     puts("\n" LUA_RELEASE "  " LUA_COPYRIGHT);
00330 
00331 #ifdef NUTLUA_PARSER_EXCLUDED
00332     puts("Error: Stand-alone interpreter requires parser");
00333 #else
00334 #ifdef NUTLUA_IOLIB_TCP
00335     NutRegisterDevice(&DEV_ETHER, 0, 0);
00336     if (NutDhcpIfConfig(DEV_ETHER_NAME, 0, 60000)) {
00337         uint8_t mac[6] = { 0x00, 0x06, 0x98, 0x00, 0x00, 0x00 };
00338         if (NutDhcpIfConfig("eth0", mac, 60000)) {
00339             uint32_t ip_addr = inet_addr("192.168.192.100");
00340             uint32_t ip_mask = inet_addr("255.255.255.0");
00341             NutNetIfConfig("eth0", mac, ip_addr, ip_mask);
00342         }
00343     }
00344     printf("Network interface %s\n", inet_ntoa(confnet.cdn_ip_addr));
00345 #endif /* NUTLUA_IOLIB_TCP */
00346 
00347     /* Lua is stack hungry and requires to adjust the stack size of our 
00348     ** main thread. To get it run on a standard system we create a new
00349     ** thread with sufficient stack space. */
00350     NutThreadCreate("lua", LuaThread, NULL, THREAD_LUASTACK * NUT_THREAD_STACK_MULT + NUT_THREAD_STACK_ADD);
00351 #endif /* NUTLUA_PARSER_EXCLUDED */
00352     /* Nothing left to do here. */
00353     for(;;) {
00354         NutSleep(1000);
00355     }
00356     return 0;
00357 }

© 2000-2010 by contributors - visit http://www.ethernut.de/