3 # Patch managed by http://www.holgerschurig.de/patcher.html
6 --- lua-5.0.2/etc/saconfig.c~advanced-readline
7 +++ lua-5.0.2/etc/saconfig.c
9 -/* sa-config.c -- configuration for stand-alone Lua interpreter
10 +/* saconfig.c -- configuration for stand-alone Lua interpreter
12 * #define LUA_USERCONFIG to this file
14 * Here are the features that can be customized using #define:
16 -*** Line edit and history:
17 +*** Line editing and history:
18 * #define USE_READLINE to use the GNU readline library.
20 * To use another library for this, use the code below as a start.
21 -* Make sure you #define lua_readline and lua_saveline accordingly.
22 +* Make sure you #define lua_{read,save,init,exit}line accordingly.
23 * If you do not #define lua_readline, you'll get a version based on fgets
24 * that uses a static buffer of size MAXINPUT.
30 -* This section implements of lua_readline and lua_saveline for lua.c using
31 -* the GNU readline and history libraries. It should also work with drop-in
32 -* replacements such as editline and libedit (you may have to include
33 -* different headers, though).
34 +* This section implements lua_xxxxline for lua.c using the GNU readline
35 +* and history libraries or compatible replacements.
37 +* It has been successfully tested with:
39 +* GNU readline 2.2.1 (1998-07-17)
40 +* GNU readline 4.0 (1999-02-18) [harmless compiler warning]
41 +* GNU readline 4.3 (2002-07-16)
42 +* NETBSD libedit 2.6.5 (2002-03-25)
43 +* NETBSD libedit 2.6.9 (2004-05-01)
46 +#define lua_initline myinitline
47 +#define lua_exitline myexitline
48 #define lua_readline myreadline
49 #define lua_saveline mysaveline
52 #include <readline/readline.h>
53 #include <readline/history.h>
55 -static int myreadline (lua_State *L, const char *prompt) {
56 - char *s=readline(prompt);
60 - lua_pushstring(L,s);
61 - lua_pushliteral(L,"\n");
66 +/* Environment variable names for the history file and the history size */
67 +#ifndef LUA_HISTORY_ENV
68 +#define LUA_HISTORY_ENV "LUA_HISTORY"
71 +#ifndef LUA_HISTSIZE_ENV
72 +#define LUA_HISTSIZE_ENV "LUA_HISTSIZE"
76 +static int myhistsize;
78 +static lua_State *myL; /* readline does not pass user data to callbacks */
80 +/* Read a line from the terminal with line editing */
81 +static int myreadline(lua_State *L, const char *prompt)
84 + if (!(s = readline(prompt))) return 0;
85 + lua_pushstring(L, s);
86 + lua_pushliteral(L, "\n");
92 -static void mysaveline (lua_State *L, const char *s) {
93 +/* Add a line to the history */
94 +static void mysaveline(lua_State *L, const char *s)
97 - for (p=s; isspace(*p); p++)
100 - size_t n=strlen(s)-1;
102 + for (p = s; isspace(*p); p++) ;
104 + size_t n = strlen(s)-1;
105 + if (s[n] != '\n') {
108 - lua_pushlstring(L,s,n);
109 - s=lua_tostring(L,-1);
111 + lua_pushlstring(L, s, n);
112 + s = lua_tostring(L, -1);
120 +/* Reserved lua keywords */
121 +static const char * const reskeywords[] = {
122 + "and", "break", "do", "else", "elseif", "end", "false",
123 + "for", "function", "if", "in", "local", "nil", "not", "or",
124 + "repeat", "return", "then", "true", "until", "while", NULL
127 +static int valididentifier(const char *s)
129 + if (!(isalpha(*s) || *s == '_')) return 0;
130 + for (s++; *s; s++) if (!(isalpha(*s) || isdigit(*s) || *s == '_')) return 0;
134 +/* Dynamically resizable match list */
137 + size_t idx, allocated, matchlen;
140 +/* Add prefix + string + suffix to list and compute common prefix */
141 +static int dmadd(dmlist *ml, const char *p, size_t pn, const char *s, int suf)
145 + if (ml->idx+1 >= ml->allocated &&
146 + !(ml->list = realloc(ml->list, sizeof(char *)*(ml->allocated += 32))))
150 + size_t n = strlen(s);
151 + if (!(t = (char *)malloc(sizeof(char)*(pn+n+(suf?2:1))))) return 1;
153 + memcpy(t+pn, s, n);
156 + if (suf) t[++n] = '\0';
158 + if (ml->idx == 0) {
162 + for (i = 0; i < ml->matchlen && i < n && ml->list[1][i] == t[i]; i++) ;
163 + ml->matchlen = i; /* Set matchlen to common prefix */
167 + ml->list[++ml->idx] = t;
171 +/* Get __index field of metatable of object on top of stack */
172 +static int getmetaindex(lua_State *L)
174 + if (!lua_getmetatable(L, -1)) { lua_pop(L, 1); return 0; }
175 + lua_pushstring(L, "__index");
177 + lua_replace(L, -2);
178 + if (lua_isnil(L, -1) || lua_rawequal(L, -1, -2)) { lua_pop(L, 2); return 0; }
179 + lua_replace(L, -2);
181 +} /* 1: obj -- val, 0: obj -- */
183 +/* Get field from object on top of stack. Avoid calling metamethods */
184 +static int safegetfield(lua_State *L, const char *s, size_t n)
186 + int i = 20; /* Avoid infinite metatable loops */
188 + if (lua_istable(L, -1)) {
189 + lua_pushlstring(L, s, n);
191 + if (!lua_isnil(L, -1)) { lua_replace(L, -2); return 1; }
194 + } while (--i > 0 && getmetaindex(L));
197 +} /* 1: obj -- val, 0: obj -- */
199 +/* Completion function */
200 +static char **mycomplete(const char *text, int start, int end)
207 + if (!(text[0] == '\0' || isalpha(text[0]) || text[0] == '_')) return NULL;
210 + ml.idx = ml.allocated = ml.matchlen = 0;
212 + savetop = lua_gettop(myL);
213 + lua_pushvalue(myL, LUA_GLOBALSINDEX);
214 + for (n = (size_t)(end-start), i = dot = 0; i < n; i++)
215 + if (text[i] == '.' || text[i] == ':') {
216 + if (!safegetfield(myL, text+dot, i-dot)) goto error; /* invalid prefix */
217 + dot = i+1; /* points to first char after dot/colon */
220 + /* Add all matches against keywords if there is no dot/colon */
222 + for (i = 0; (s = reskeywords[i]) != NULL; i++)
223 + if (!strncmp(s, text, n) && dmadd(&ml, NULL, 0, s, ' ')) goto error;
225 + /* Add all valid matches from all tables/metatables */
226 + i = 20; /* Avoid infinite metatable loops */
228 + if (lua_istable(myL, -1))
229 + for (lua_pushnil(myL); lua_next(myL, -2); lua_pop(myL, 1))
230 + if (lua_type(myL, -2) == LUA_TSTRING) {
231 + s = lua_tostring(myL, -2);
232 + /* Only match names starting with '_' if explicitly requested */
233 + if (!strncmp(s, text+dot, n-dot) && valididentifier(s) &&
234 + (*s != '_' || text[dot] == '_')) {
235 + int suf = ' '; /* default suffix is a space */
236 + switch (lua_type(myL, -1)) {
237 + case LUA_TTABLE: suf = '.'; break; /* No way to guess ':' */
238 + case LUA_TFUNCTION: suf = '('; break;
239 + case LUA_TUSERDATA:
240 + if (lua_getmetatable(myL, -1)) { lua_pop(myL, 1); suf = ':'; }
243 + if (dmadd(&ml, text, dot, s, suf)) goto error;
246 + } while (--i > 0 && getmetaindex(myL));
249 + /* list[0] holds the common prefix of all matches (may be "") */
250 + if (!(ml.list[0] = (char *)malloc(sizeof(char)*(ml.matchlen+1)))) {
252 + lua_settop(myL, savetop);
255 + memcpy(ml.list[0], ml.list[1], ml.matchlen);
256 + ml.list[0][ml.matchlen] = '\0';
257 + /* Add the NULL list terminator */
258 + if (dmadd(&ml, NULL, 0, NULL, 0)) goto error;
259 + } else if (ml.idx == 1) {
260 + ml.list[0] = ml.list[1]; /* Only return common prefix */
264 + lua_settop(myL, savetop);
268 +/* Initialize library */
269 +static void myinitline(lua_State *L, char *pname)
275 + /* This allows for $if lua ... $endif in ~/.inputrc */
276 + rl_readline_name = pname;
277 + /* Break words at every non-identifier character except '.' and ':' */
278 + rl_completer_word_break_characters =
279 + "\t\r\n !\"#$%&'()*+,-/;<=>?@[\\]^`{|}~";
280 + rl_completer_quote_characters = "\"'";
281 + rl_completion_append_character = '\0';
282 + rl_attempted_completion_function = mycomplete;
285 + /* Start using history, optionally set history size and load history file */
287 + if ((s = getenv(LUA_HISTSIZE_ENV)) &&
288 + (myhistsize = atoi(s))) stifle_history(myhistsize);
289 + if ((myhist = getenv(LUA_HISTORY_ENV))) read_history(myhist);
292 +/* Finalize library */
293 +static void myexitline(lua_State *L)
295 + /* Optionally save history file */
296 + if (myhist) write_history(myhist);
299 --- lua-5.0.2/src/lua/lua.c~advanced-readline
300 +++ lua-5.0.2/src/lua/lua.c
305 +** these macros can be used to perform initialization and finalization
306 +** for lua_saveline and lua_readline
308 +#ifndef lua_initline
309 +#define lua_initline(L,pname) /* empty */
312 +#ifndef lua_exitline
313 +#define lua_exitline(L) /* empty */
318 ** this macro can be used by some `history' system to save lines
319 ** read in manual input
322 const char *oldprogname = progname;
325 + lua_initline(L, PROGNAME); /* progname may contain a path, so use PROGNAME */
326 while ((status = load_string()) != -1) {
327 if (status == 0) status = lcall(0, 0);
331 lua_settop(L, 0); /* clear stack */
334 progname = oldprogname;