Nut/OS  4.10.3
API Reference
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 #include <sys/thread.h>
00048 
00049 #include <gorp/edline.h>
00050 
00051 #include <arpa/inet.h>
00052 #include <pro/dhcp.h>
00053 
00054 #include <stdio.h>
00055 #include <io.h>
00056 #include <string.h>
00057 
00058 #define lua_c
00059 
00060 #include <lua/lua.h>
00061 
00062 #include <lua/lauxlib.h>
00063 #include <lua/lualib.h>
00064 
00065 #ifndef NUTLUA_PARSER_EXCLUDED
00066 
00067 #ifdef __AVR__
00068 #define THREAD_LUASTACK     2048
00069 #else
00070 #define THREAD_LUASTACK     8192
00071 #endif
00072 
00073 static char lua_line_buffer[LUA_MAXINPUT];
00074 static EDLINE *lua_line_edit;
00075 
00076 /*
00077  * Report bad state.
00078  */
00079 static void report(lua_State * L)
00080 {
00081     if (!lua_isnil(L, -1)) {
00082         const char *msg = lua_tostring(L, -1);
00083 
00084         if (msg == NULL)
00085             msg = "(error object is not a string)";
00086         fputs(msg, stderr);
00087         fputc('\n', stderr);
00088         fflush(stderr);
00089         lua_pop(L, 1);
00090     }
00091 }
00092 
00093 /*
00094  * Perform Lua back trace.
00095  */
00096 static int traceback(lua_State * L)
00097 {
00098     if (!lua_isstring(L, 1))    /* 'message' not a string? */
00099         return 1;               /* keep it intact */
00100     lua_getfield(L, LUA_GLOBALSINDEX, "debug");
00101     if (!lua_istable(L, -1)) {
00102         lua_pop(L, 1);
00103         return 1;
00104     }
00105     lua_getfield(L, -1, "traceback");
00106     if (!lua_isfunction(L, -1)) {
00107         lua_pop(L, 2);
00108         return 1;
00109     }
00110     lua_pushvalue(L, 1);        /* pass error message */
00111     lua_pushinteger(L, 2);      /* skip this function and traceback */
00112     lua_call(L, 2, 1);          /* call debug.traceback */
00113     return 1;
00114 }
00115 
00116 /*
00117  * Execute the chunk on top of the Lua stack.
00118  */
00119 static int docall(lua_State * L)
00120 {
00121     int status;
00122     int base;    /* function index */
00123 
00124     /* Retrieve the function index and push the traceback 
00125     ** function below the chunk and its arguments. */
00126     base = lua_gettop(L);
00127     lua_pushcfunction(L, traceback);
00128     lua_insert(L, base);
00129 
00130     status = lua_pcall(L, 0, LUA_MULTRET, base);
00131 
00132     /* Remove the traceback function. */
00133     lua_remove(L, base);
00134 
00135     /* Force a complete garbage collection in case of errors. */
00136     if (status)
00137         lua_gc(L, LUA_GCCOLLECT, 0);
00138 
00139     return status;
00140 }
00141 
00142 /*
00143  * Retrieve the currently valid prompt.
00144  */
00145 static const char *get_prompt(lua_State * L, int firstline)
00146 {
00147     const char *p;
00148 
00149     /* Try global settings first. */
00150     lua_getfield(L, LUA_GLOBALSINDEX, firstline ? "_PROMPT" : "_PROMPT2");
00151     p = lua_tostring(L, -1);
00152     if (p == NULL)
00153         p = (firstline ? LUA_PROMPT : LUA_PROMPT2);
00154     lua_pop(L, 1);
00155 
00156     return p;
00157 }
00158 
00159 /*
00160  * Check if Lua chunk is complete.
00161  */
00162 static int is_complete(lua_State * L, int status)
00163 {
00164     if (status == LUA_ERRSYNTAX) {
00165         size_t lmsg;
00166         const char *msg = lua_tolstring(L, -1, &lmsg);
00167         const char *tp = msg + lmsg - (sizeof(LUA_QL("<eof>")) - 1);
00168 
00169         if (strstr(msg, LUA_QL("<eof>")) == tp) {
00170             lua_pop(L, 1);
00171             return 0;
00172         }
00173     }
00174     return 1;
00175 }
00176 
00177 /*
00178  * Get next line of a Lua chunk.
00179  */
00180 static int pushline(lua_State * L, int firstline)
00181 {
00182     int l;
00183     const char *prmt;
00184 
00185     /* Display a prompt. */
00186     prmt = get_prompt(L, firstline);
00187     fputs(prmt, stdout);
00188     fflush(stdout);
00189 
00190     /* Get a new line from the line editor. */
00191     lua_line_buffer[0] = '\0';
00192     l = EdLineRead(lua_line_edit, lua_line_buffer, LUA_MAXINPUT);
00193 
00194     if (l >= 0) {
00195         /* Replace '=' at the beginning with 'return'. */
00196         if (firstline && lua_line_buffer[0] == '=')
00197             lua_pushfstring(L, "return %s", &lua_line_buffer[1]);
00198         else
00199             lua_pushstring(L, lua_line_buffer);
00200     }
00201     return l;
00202 }
00203 
00204 /*
00205  * Load complete Lua chunk.
00206  */
00207 static int loadchunk(lua_State * L)
00208 {
00209     int status = -1;
00210 
00211     /* Clear Lua stack. */
00212     lua_settop(L, 0);
00213 
00214     if (pushline(L, 1) >= 0) {
00215         /* Loop until we have a complete chunk. */
00216         for (;;) {
00217             status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin");
00218             /* If the line is complete, we are done. */
00219             if (is_complete(L, status))
00220                 break;
00221             /* Otherwise try to get another line. */
00222             if (pushline(L, 0) < 0)
00223                 return -1;
00224             /* Add a linefeed between the two lines and join them. */
00225             lua_pushliteral(L, "\n");
00226             lua_insert(L, -2);
00227             lua_concat(L, 3);
00228         }
00229         lua_saveline(L, 1);
00230         lua_remove(L, 1);
00231     }
00232     return status;
00233 }
00234 
00235 /*
00236  * Lua line processing loop.
00237  */
00238 static int pmain(lua_State * L)
00239 {
00240     int status;
00241 
00242     /* Open pre-configured libraries. Garbage collector must be disabled. */
00243     lua_gc(L, LUA_GCSTOP, 0);
00244     luaL_openlibs(L);
00245     lua_gc(L, LUA_GCRESTART, 0);
00246 
00247     /* This loop loads Lua chunks and processes them until we get an 
00248     ** input error. We may later use Ctrl-C or break to exit the 
00249     ** interpreter. Right now this is not supported by our line editor. */
00250     while ((status = loadchunk(L)) != -1) {
00251         /* If everything is OK, execute the chunk. */
00252         if (status == 0)
00253             status = docall(L);
00254         /* Report bad state... */
00255         if (status) {
00256             report(L);
00257         }
00258         /* ...or print result, if any. */
00259         else if (lua_gettop(L) > 0) {
00260             lua_getglobal(L, "print");
00261             lua_insert(L, 1);
00262             if (lua_pcall(L, lua_gettop(L) - 1, 0, 0) != 0) {
00263                 fprintf(stderr, lua_pushfstring(L, "error calling " 
00264                     LUA_QL("print") " (%s)", lua_tostring(L, -1)));
00265                 fputc('\n', stderr);
00266                 fflush(stderr);
00267             }
00268         }
00269     }
00270     /* Clear Lua stack. */
00271     lua_settop(L, 0);
00272 
00273     fputc('\n', stdout);
00274     fflush(stdout);
00275 
00276     return 0;
00277 }
00278 
00279 /*
00280  * Lua interpreter thread.
00281  */
00282 THREAD(LuaThread, arg)
00283 {
00284     lua_State *L;
00285 
00286     for (;;) {
00287         /* Display second banner line here, so we know 
00288         ** that everything is up and running. */
00289         printf("Running on Nut/OS %s - %ld bytes free\n", NutVersionString(), (long)NutHeapAvailable());
00290 
00291         /* Open the line editor. */
00292         lua_line_edit = EdLineOpen(EDIT_MODE_ECHO | EDIT_MODE_HISTORY);
00293         if (lua_line_edit) {
00294             /* Register VT100 key mapping. This makes the arrow keys 
00295             ** work when using a VT100 terminal emulator for input. */
00296             EdLineRegisterKeymap(lua_line_edit, EdLineKeyMapVt100);
00297 
00298             /* Create a Lua state. */
00299             L = lua_open();
00300             if (L) {
00301                 if (lua_cpcall(L, &pmain, NULL)) {
00302                     report(L);
00303                 }
00304                 /* Release the Lua state. */
00305                 lua_close(L);
00306             }
00307             /* Release the line editor. */
00308             EdLineClose(lua_line_edit);
00309         }
00310     }
00311 }
00312 
00313 #endif /* NUTLUA_PARSER_EXCLUDED */
00314 
00315 /*
00316  * Lua interpreter entry.
00317  */
00318 int main(void)
00319 {
00320     unsigned long baud = 115200;
00321 
00322     /* Initialize the console. */
00323     NutRegisterDevice(&DEV_CONSOLE, 0, 0);
00324     freopen(DEV_CONSOLE_NAME, "w", stdout);
00325     freopen(DEV_CONSOLE_NAME, "w", stderr);
00326     freopen(DEV_CONSOLE_NAME, "r", stdin);
00327     _ioctl(_fileno(stdin), UART_SETSPEED, &baud);
00328 
00329     /* Display banner. */
00330     puts("\n" LUA_RELEASE "  " LUA_COPYRIGHT);
00331 
00332 #ifdef NUTLUA_PARSER_EXCLUDED
00333     puts("Error: Stand-alone interpreter requires parser");
00334 #else
00335 #ifdef NUTLUA_IOLIB_TCP
00336     NutRegisterDevice(&DEV_ETHER, 0, 0);
00337     if (NutDhcpIfConfig(DEV_ETHER_NAME, 0, 60000)) {
00338         uint8_t mac[6] = { 0x00, 0x06, 0x98, 0x00, 0x00, 0x00 };
00339         if (NutDhcpIfConfig("eth0", mac, 60000)) {
00340             uint32_t ip_addr = inet_addr("192.168.192.100");
00341             uint32_t ip_mask = inet_addr("255.255.255.0");
00342             NutNetIfConfig("eth0", mac, ip_addr, ip_mask);
00343         }
00344     }
00345     printf("Network interface %s\n", inet_ntoa(confnet.cdn_ip_addr));
00346 #endif /* NUTLUA_IOLIB_TCP */
00347 
00348     /* Lua is stack hungry and requires to adjust the stack size of our 
00349     ** main thread. To get it run on a standard system we create a new
00350     ** thread with sufficient stack space. */
00351     NutThreadCreate("lua", LuaThread, NULL, THREAD_LUASTACK * NUT_THREAD_STACK_MULT + NUT_THREAD_STACK_ADD);
00352 #endif /* NUTLUA_PARSER_EXCLUDED */
00353     /* Nothing left to do here. */
00354     for(;;) {
00355         NutSleep(1000);
00356     }
00357     return 0;
00358 }