diff options
Diffstat (limited to 'recipes/lua/files/advanced-readline.patch')
-rw-r--r-- | recipes/lua/files/advanced-readline.patch | 336 |
1 files changed, 336 insertions, 0 deletions
diff --git a/recipes/lua/files/advanced-readline.patch b/recipes/lua/files/advanced-readline.patch new file mode 100644 index 0000000000..93a7da8389 --- /dev/null +++ b/recipes/lua/files/advanced-readline.patch @@ -0,0 +1,336 @@ + +# +# Patch managed by http://www.holgerschurig.de/patcher.html +# + +--- lua-5.0.2/etc/saconfig.c~advanced-readline ++++ lua-5.0.2/etc/saconfig.c +@@ -1,14 +1,14 @@ +-/* sa-config.c -- configuration for stand-alone Lua interpreter ++/* saconfig.c -- configuration for stand-alone Lua interpreter + * + * #define LUA_USERCONFIG to this file + * + * Here are the features that can be customized using #define: + * +-*** Line edit and history: ++*** Line editing and history: + * #define USE_READLINE to use the GNU readline library. + * + * To use another library for this, use the code below as a start. +-* Make sure you #define lua_readline and lua_saveline accordingly. ++* Make sure you #define lua_{read,save,init,exit}line accordingly. + * If you do not #define lua_readline, you'll get a version based on fgets + * that uses a static buffer of size MAXINPUT. + * +@@ -41,13 +41,20 @@ + + #ifdef USE_READLINE + /* +-* This section implements of lua_readline and lua_saveline for lua.c using +-* the GNU readline and history libraries. It should also work with drop-in +-* replacements such as editline and libedit (you may have to include +-* different headers, though). ++* This section implements lua_xxxxline for lua.c using the GNU readline ++* and history libraries or compatible replacements. + * ++* It has been successfully tested with: ++* ++* GNU readline 2.2.1 (1998-07-17) ++* GNU readline 4.0 (1999-02-18) [harmless compiler warning] ++* GNU readline 4.3 (2002-07-16) ++* NETBSD libedit 2.6.5 (2002-03-25) ++* NETBSD libedit 2.6.9 (2004-05-01) + */ + ++#define lua_initline myinitline ++#define lua_exitline myexitline + #define lua_readline myreadline + #define lua_saveline mysaveline + +@@ -55,33 +62,226 @@ + #include <readline/readline.h> + #include <readline/history.h> + +-static int myreadline (lua_State *L, const char *prompt) { +- char *s=readline(prompt); +- if (s==NULL) +- return 0; +- else { +- lua_pushstring(L,s); +- lua_pushliteral(L,"\n"); +- lua_concat(L,2); +- free(s); +- return 1; +- } ++/* Environment variable names for the history file and the history size */ ++#ifndef LUA_HISTORY_ENV ++#define LUA_HISTORY_ENV "LUA_HISTORY" ++#endif ++ ++#ifndef LUA_HISTSIZE_ENV ++#define LUA_HISTSIZE_ENV "LUA_HISTSIZE" ++#endif ++ ++static char *myhist; ++static int myhistsize; ++ ++static lua_State *myL; /* readline does not pass user data to callbacks */ ++ ++/* Read a line from the terminal with line editing */ ++static int myreadline(lua_State *L, const char *prompt) ++{ ++ char *s; ++ if (!(s = readline(prompt))) return 0; ++ lua_pushstring(L, s); ++ lua_pushliteral(L, "\n"); ++ lua_concat(L, 2); ++ free(s); ++ return 1; + } + +-static void mysaveline (lua_State *L, const char *s) { ++/* Add a line to the history */ ++static void mysaveline(lua_State *L, const char *s) ++{ + const char *p; +- for (p=s; isspace(*p); p++) +- ; +- if (*p!=0) { +- size_t n=strlen(s)-1; +- if (s[n]!='\n') ++ for (p = s; isspace(*p); p++) ; ++ if (*p) { ++ size_t n = strlen(s)-1; ++ if (s[n] != '\n') { + add_history(s); +- else { +- lua_pushlstring(L,s,n); +- s=lua_tostring(L,-1); ++ } else { ++ lua_pushlstring(L, s, n); ++ s = lua_tostring(L, -1); + add_history(s); +- lua_remove(L,-1); ++ lua_pop(L, 1); ++ } ++ } ++} ++ ++/* Reserved lua keywords */ ++static const char * const reskeywords[] = { ++ "and", "break", "do", "else", "elseif", "end", "false", ++ "for", "function", "if", "in", "local", "nil", "not", "or", ++ "repeat", "return", "then", "true", "until", "while", NULL ++}; ++ ++static int valididentifier(const char *s) ++{ ++ if (!(isalpha(*s) || *s == '_')) return 0; ++ for (s++; *s; s++) if (!(isalpha(*s) || isdigit(*s) || *s == '_')) return 0; ++ return 1; ++} ++ ++/* Dynamically resizable match list */ ++typedef struct { ++ char **list; ++ size_t idx, allocated, matchlen; ++} dmlist; ++ ++/* Add prefix + string + suffix to list and compute common prefix */ ++static int dmadd(dmlist *ml, const char *p, size_t pn, const char *s, int suf) ++{ ++ char *t = NULL; ++ ++ if (ml->idx+1 >= ml->allocated && ++ !(ml->list = realloc(ml->list, sizeof(char *)*(ml->allocated += 32)))) ++ return -1; ++ ++ if (s) { ++ size_t n = strlen(s); ++ if (!(t = (char *)malloc(sizeof(char)*(pn+n+(suf?2:1))))) return 1; ++ memcpy(t, p, pn); ++ memcpy(t+pn, s, n); ++ n += pn; ++ t[n] = suf; ++ if (suf) t[++n] = '\0'; ++ ++ if (ml->idx == 0) { ++ ml->matchlen = n; ++ } else { ++ size_t i; ++ for (i = 0; i < ml->matchlen && i < n && ml->list[1][i] == t[i]; i++) ; ++ ml->matchlen = i; /* Set matchlen to common prefix */ ++ } ++ } ++ ++ ml->list[++ml->idx] = t; ++ return 0; ++} ++ ++/* Get __index field of metatable of object on top of stack */ ++static int getmetaindex(lua_State *L) ++{ ++ if (!lua_getmetatable(L, -1)) { lua_pop(L, 1); return 0; } ++ lua_pushstring(L, "__index"); ++ lua_rawget(L, -2); ++ lua_replace(L, -2); ++ if (lua_isnil(L, -1) || lua_rawequal(L, -1, -2)) { lua_pop(L, 2); return 0; } ++ lua_replace(L, -2); ++ return 1; ++} /* 1: obj -- val, 0: obj -- */ ++ ++/* Get field from object on top of stack. Avoid calling metamethods */ ++static int safegetfield(lua_State *L, const char *s, size_t n) ++{ ++ int i = 20; /* Avoid infinite metatable loops */ ++ do { ++ if (lua_istable(L, -1)) { ++ lua_pushlstring(L, s, n); ++ lua_rawget(L, -2); ++ if (!lua_isnil(L, -1)) { lua_replace(L, -2); return 1; } ++ lua_pop(L, 1); ++ } ++ } while (--i > 0 && getmetaindex(L)); ++ lua_pop(L, 1); ++ return 0; ++} /* 1: obj -- val, 0: obj -- */ ++ ++/* Completion function */ ++static char **mycomplete(const char *text, int start, int end) ++{ ++ dmlist ml; ++ const char *s; ++ size_t i, n, dot; ++ int savetop; ++ ++ if (!(text[0] == '\0' || isalpha(text[0]) || text[0] == '_')) return NULL; ++ ++ ml.list = NULL; ++ ml.idx = ml.allocated = ml.matchlen = 0; ++ ++ savetop = lua_gettop(myL); ++ lua_pushvalue(myL, LUA_GLOBALSINDEX); ++ for (n = (size_t)(end-start), i = dot = 0; i < n; i++) ++ if (text[i] == '.' || text[i] == ':') { ++ if (!safegetfield(myL, text+dot, i-dot)) goto error; /* invalid prefix */ ++ dot = i+1; /* points to first char after dot/colon */ ++ } ++ ++ /* Add all matches against keywords if there is no dot/colon */ ++ if (dot == 0) ++ for (i = 0; (s = reskeywords[i]) != NULL; i++) ++ if (!strncmp(s, text, n) && dmadd(&ml, NULL, 0, s, ' ')) goto error; ++ ++ /* Add all valid matches from all tables/metatables */ ++ i = 20; /* Avoid infinite metatable loops */ ++ do { ++ if (lua_istable(myL, -1)) ++ for (lua_pushnil(myL); lua_next(myL, -2); lua_pop(myL, 1)) ++ if (lua_type(myL, -2) == LUA_TSTRING) { ++ s = lua_tostring(myL, -2); ++ /* Only match names starting with '_' if explicitly requested */ ++ if (!strncmp(s, text+dot, n-dot) && valididentifier(s) && ++ (*s != '_' || text[dot] == '_')) { ++ int suf = ' '; /* default suffix is a space */ ++ switch (lua_type(myL, -1)) { ++ case LUA_TTABLE: suf = '.'; break; /* No way to guess ':' */ ++ case LUA_TFUNCTION: suf = '('; break; ++ case LUA_TUSERDATA: ++ if (lua_getmetatable(myL, -1)) { lua_pop(myL, 1); suf = ':'; } ++ break; ++ } ++ if (dmadd(&ml, text, dot, s, suf)) goto error; ++ } ++ } ++ } while (--i > 0 && getmetaindex(myL)); ++ ++ if (ml.idx > 1) { ++ /* list[0] holds the common prefix of all matches (may be "") */ ++ if (!(ml.list[0] = (char *)malloc(sizeof(char)*(ml.matchlen+1)))) { ++error: ++ lua_settop(myL, savetop); ++ return NULL; + } ++ memcpy(ml.list[0], ml.list[1], ml.matchlen); ++ ml.list[0][ml.matchlen] = '\0'; ++ /* Add the NULL list terminator */ ++ if (dmadd(&ml, NULL, 0, NULL, 0)) goto error; ++ } else if (ml.idx == 1) { ++ ml.list[0] = ml.list[1]; /* Only return common prefix */ ++ ml.list[1] = NULL; + } ++ ++ lua_settop(myL, savetop); ++ return ml.list; ++} ++ ++/* Initialize library */ ++static void myinitline(lua_State *L, char *pname) ++{ ++ char *s; ++ ++ myL = L; ++ ++ /* This allows for $if lua ... $endif in ~/.inputrc */ ++ rl_readline_name = pname; ++ /* Break words at every non-identifier character except '.' and ':' */ ++ rl_completer_word_break_characters = ++ "\t\r\n !\"#$%&'()*+,-/;<=>?@[\\]^`{|}~"; ++ rl_completer_quote_characters = "\"'"; ++ rl_completion_append_character = '\0'; ++ rl_attempted_completion_function = mycomplete; ++ rl_initialize(); ++ ++ /* Start using history, optionally set history size and load history file */ ++ using_history(); ++ if ((s = getenv(LUA_HISTSIZE_ENV)) && ++ (myhistsize = atoi(s))) stifle_history(myhistsize); ++ if ((myhist = getenv(LUA_HISTORY_ENV))) read_history(myhist); ++} ++ ++/* Finalize library */ ++static void myexitline(lua_State *L) ++{ ++ /* Optionally save history file */ ++ if (myhist) write_history(myhist); + } + #endif +--- lua-5.0.2/src/lua/lua.c~advanced-readline ++++ lua-5.0.2/src/lua/lua.c +@@ -265,6 +265,19 @@ + + + /* ++** these macros can be used to perform initialization and finalization ++** for lua_saveline and lua_readline ++*/ ++#ifndef lua_initline ++#define lua_initline(L,pname) /* empty */ ++#endif ++ ++#ifndef lua_exitline ++#define lua_exitline(L) /* empty */ ++#endif ++ ++ ++/* + ** this macro can be used by some `history' system to save lines + ** read in manual input + */ +@@ -352,6 +365,7 @@ + const char *oldprogname = progname; + progname = NULL; + do_path(); ++ lua_initline(L, PROGNAME); /* progname may contain a path, so use PROGNAME */ + while ((status = load_string()) != -1) { + if (status == 0) status = lcall(0, 0); + report(status); +@@ -365,6 +379,7 @@ + } + lua_settop(L, 0); /* clear stack */ + fputs("\n", stdout); ++ lua_exitline(L); + progname = oldprogname; + } + |