From b1c9f537b475b3bc8f6517bb4d7008a411bb478e Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Sun, 18 Mar 2007 13:20:06 +0100 Subject: [PATCH] new lua implementation. Signed-off-by: Pierre Habouzit --- commands.c | 2 +- init.c | 8 +- lib-lua/Makefile.am | 9 +- lib-lua/lib-lua.h | 28 ++- lib-lua/lib-lua_priv.h | 20 -- lib-lua/lua-token.sh | 32 ++- lib-lua/luapkg2c.pl | 506 +++++++++++++++++++++++++++++++++++++++++ lib-lua/madmutt.c | 335 --------------------------- lib-lua/madmutt.cpkg | 80 +++++++ lib-lua/runtime.c | 62 ++--- lib-mx/mx.c | 14 +- lib-ui/curs_lib.c | 2 +- lib-ui/curs_main.c | 4 +- main.c | 2 +- sendlib.c | 2 +- 15 files changed, 670 insertions(+), 436 deletions(-) create mode 100755 lib-lua/luapkg2c.pl delete mode 100644 lib-lua/madmutt.c create mode 100644 lib-lua/madmutt.cpkg diff --git a/commands.c b/commands.c index a7cc074..ed99c4a 100644 --- a/commands.c +++ b/commands.c @@ -520,7 +520,7 @@ void mutt_shell_escape (void) buf[0] = 0; if (mutt_get_field (_("Shell command: "), buf, sizeof (buf), M_CMD) == 0) { if (!buf[0]) - m_strcpy(buf, sizeof(buf), mlua_reggets(LTK_SHELL)); + m_strcpy(buf, sizeof(buf), ml_core.shell); if (buf[0]) { CLEARLINE (LINES - 1); mutt_endwin (NULL); diff --git a/init.c b/init.c index 61d1f0a..03065c2 100644 --- a/init.c +++ b/init.c @@ -494,10 +494,8 @@ int quadoption (int opt) return (QuadOptions[n] >> b) & 0x3; } -int query_quadoption2(int opt, const char *prompt) +int query_quadoption2(int v, const char *prompt) { - int v = mlua_reggeti(opt); - switch (v) { case M_YES: case M_NO: @@ -2327,7 +2325,7 @@ void mutt_init (int skip_sys_rc, string_list_t * commands) From = rfc822_parse_adrlist (NULL, p); charset_initialize(); - mlua_initialize(); + luaM_initialize(); /* Set standard defaults */ hash_map (ConfigOptions, mutt_set_default, 0); @@ -2404,7 +2402,7 @@ void mutt_init (int skip_sys_rc, string_list_t * commands) if (access(buffer, F_OK) < 0) snprintf(buffer, sizeof(buffer), "%s/.madmutt/cfg.lua", NONULL(Homedir)); if (!access(buffer, F_OK)) { - need_pause = mlua_wrap(mutt_error, mlua_dofile(buffer)); + need_pause = luaM_wrap(mutt_error, luaM_dofile(buffer)); } /* }}} */ diff --git a/lib-lua/Makefile.am b/lib-lua/Makefile.am index 78006a1..b28c98d 100644 --- a/lib-lua/Makefile.am +++ b/lib-lua/Makefile.am @@ -1,10 +1,15 @@ BUILT_SOURCES = lua-token.h lua-token.c DISTCLEANFILES = $(BUILT_SOURCES) +.cpkg.c: ; ./luapkg2c.pl -c $< > $@ +.cpkg.h: ; ./luapkg2c.pl -h $< > $@ + noinst_LIBRARIES = liblua.a -liblua_a_SOURCES = lib-lua.h lib-lua_priv.h \ - runtime.c madmutt.c \ +liblua_a_DEPENDENCIES = madmutt.h +liblua_a_SOURCES = madmutt.cpkg \ + lib-lua.h lib-lua_priv.h \ + runtime.c \ $(BUILT_SOURCES) noinst_HEADERS = lib-lua.h lib-lua_priv.h diff --git a/lib-lua/lib-lua.h b/lib-lua/lib-lua.h index 4ce8906..5afb91f 100644 --- a/lib-lua/lib-lua.h +++ b/lib-lua/lib-lua.h @@ -24,26 +24,30 @@ # include "../config.h" #endif +#include +#include +#include + #include "lua-token.h" /* possible arguments to set_quadoption() */ typedef enum quadopt_t { - M_NO, - M_YES, - M_ASKNO, - M_ASKYES + M_NO, + M_YES, + M_ASKNO, + M_ASKYES } quadopt_t; -void mlua_initialize(void); -void mlua_shutdown(void); +void luaM_initialize(void); +void luaM_shutdown(void); -int mlua_dofile(const char *filename); -int mlua_wrap(void (*errfun)(const char *fmt, ...), int status); +int luaM_dofile(const char *filename); +int luaM_wrap(void (*errfun)(const char *fmt, ...) + __attribute__((format(printf, 1, 2))), + int status); -const char *mlua_reggets(enum lua_token tk); -int mlua_reggeti(enum lua_token tk); +quadopt_t luaM_checkquadopt(lua_State *L, int narg); -void mlua_regsets(enum lua_token tk, const char *s); -void mlua_regseti(enum lua_token tk, int i); +#include "madmutt.h" #endif diff --git a/lib-lua/lib-lua_priv.h b/lib-lua/lib-lua_priv.h index 84fd121..93dd397 100644 --- a/lib-lua/lib-lua_priv.h +++ b/lib-lua/lib-lua_priv.h @@ -26,33 +26,13 @@ #include #include -typedef enum reg_type { - REG_NIL, - REG_INT, - REG_STR, -} reg_type; - typedef struct reg_entry { int type; union { int i; - void *p; char *s; }; } reg_entry; -static inline void reg_entry_wipe(reg_entry *e) { - switch (e->type) { - case REG_STR: - p_delete(&e->s); - break; - default: - break; - } - e->type = REG_NIL; -} - -#define LUA_MADMUTT "madmutt" -int luaopen_madmutt(lua_State *L); #endif diff --git a/lib-lua/lua-token.sh b/lib-lua/lua-token.sh index b715c37..5c61d66 100644 --- a/lib-lua/lua-token.sh +++ b/lib-lua/lua-token.sh @@ -37,14 +37,16 @@ do_h() { #ifndef MUTT_LIB_LUA_LUA_TOKEN_H #define MUTT_LIB_LUA_LUA_TOKEN_H -enum lua_token { +typedef enum mlua_token { LTK_UNKNOWN = -1, -`tr 'a-z-/' 'A-Z__' | sed -e 's/.*/ LTK_&,/'` +`grep_self "$0" | tr 'a-z-/' 'A-Z__' | sed -e 's/.*/ LTK_&,/'` LTK_count, -}; +} mlua_token; + +extern const char *__mlua_token[LTK_count]; __attribute__((pure)) -enum lua_token lua_which_token(const char *s, ssize_t len); +mlua_token mlua_which_token(const char *s, ssize_t len); #endif /* MUTT_LIB_LUA_LUA_TOKEN_H */ EOF } @@ -56,7 +58,7 @@ do_tokens() { } do_c() { - cat <val : LTK_UNKNOWN; } else { return LTK_UNKNOWN; @@ -95,8 +101,8 @@ trap "rm -f $1" 1 2 3 15 rm -f $1 case "$1" in - *.h) grep_self "$0" | do_h > $1;; - *.c) grep_self "$0" | do_c > $1;; + *.h) do_h > $1;; + *.c) do_c > $1;; *) die "you must ask for the 'h' or 'c' generation";; esac chmod -w $1 @@ -104,8 +110,12 @@ chmod -w $1 exit 0 ############ Put tokens here ############ +## bindir +## docdir ## dotlock ## editor ## quit ## sendmail ## shell +## sysconfdir +## version diff --git a/lib-lua/luapkg2c.pl b/lib-lua/luapkg2c.pl new file mode 100755 index 0000000..2d152cb --- /dev/null +++ b/lib-lua/luapkg2c.pl @@ -0,0 +1,506 @@ +#!/usr/bin/perl -w +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or (at +# your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. +# +# Copyright © 2007 Pierre Habouzit + +use strict; + +my %types; +my %pkgs; + +#{{{ stream functions + +sub stream_open($) { + my $name = shift; + open FILE, $name; + return (file => $name, line => 0, f => \*FILE); +} + +sub stream_close($) { + my $stream = shift; + close $stream->{f}; +} + +sub stream_getline($) { + my $stream = shift; + my $file = $stream->{f}; + while (<$file>) { + ${$stream}{line}++; + return $_; + } + return; +} + +#}}} + +#{{{ file:line functions + +sub fatal($$) { + my ($stream, $msg) = @_; + printf STDERR "%s:%d: %s\n", $stream->{file}, $stream->{line}, $msg; + exit 1; +} + +sub get_pos($$) { + my ($h,$k) = @_; + return $h->{$k}{file}.':'.$h->{$k}{line}; +} + +sub put_line($$) { + my ($src,$inc) = @_; + printf "#line %d \"%s\"\n", $src->{line} + $inc, $src->{file}; +} + +#}}} + +#{{{ parsers + +sub parse_type($$) { + my ($src, $type) = @_; + my %t = ( + name => $type, + file => $src->{file}, + line => $src->{line}, + ); + + if (defined $types{$type}) { + my $pos = get_pos(\%types, $type); + fatal($src, "already defined type: `$type' at $pos"); + } + + while (stream_getline($src)) { + last if (/^\s*\}\s*;\s*/); + if (/^\s*\.(push|kind|ctype|check)\s*=\s*(.*?)\s*;\s*$/) { + $t{$1} = $2; + if ($1 eq "kind") { + if ($2 =~ /^'([si])'$/) { + $t{kind} = $1; + } else { + fatal($src, "error: .kind should be 'i' or 's' got $2)"); + } + } + } elsif (!/^\s*$/) { + fatal($src, "syntax error: unknown type directive"); + } + } + + for my $i ('kind', 'ctype') { + fatal($src, "incomplete type $type: missing .$i") unless defined $t{$i}; + } + unless (defined $t{check}) { + if ($t{kind} eq 's') { + $t{check} = 'luaL_checkstring($L, $$)'; + } + + if ($t{kind} eq 'i') { + $t{check} = 'luaL_checkint($l, $$)'; + } + } + + return $types{$type} = \%t; +} + +sub parse_package($$) { + my ($src, $pkg) = @_; + my %p = ( + name => $pkg, + file => $src->{file}, + line => $src->{line}, + ); + + if (defined $pkgs{$pkg}) { + my $pos = get_pos(\%pkgs, $pkg); + fatal($src, "already defined package: `$pkg' at $pos"); + } + + while (stream_getline($src)) { + if (/^\s*\}\s*(\w+)\s*;\s*$/) { + $p{cname} = $1; + last; + } + + if (/^\s*(.*?)\s*=\s*(.*?)\s*;\s*$/) { + my ($lhs, $rhs) = ($1, $2); + my %m = ( file => $src->{file}, line => $src->{line} ); + + if ($lhs =~ /^((?:const\s+)?\w+?)\s*(\w+)$/) { + $m{type} = $1; + $m{name} = $2; + $m{init} = $rhs; + push @{$p{props}}, $2; + } elsif ($lhs =~ /^((?:const\s+)?\w+?)\s*(\w*)\((.*)\)$/) { + $m{type} = $1; + $m{name} = $2; + $m{proto} = $3; + $m{cfun} = $rhs; + push @{$p{meths}}, $2; + } else { + fatal($src, "syntax error"); + } + + if (defined $p{members}{$m{name}}) { + my $pos = get_pos($p{members}{$m{name}}, 0); + fatal($src, "already defined package member: `$m{name}' at $pos"); + } + + $p{members}{$m{name}} = \%m; + next; + } + + if (!/^\s*$/) { + fatal($src, "syntax error"); + } + } + + return $pkgs{$pkg} = \%p; +} + +sub find_type($$) { + my ($ref, $typ) = @_; + + if ($typ =~ /^const\s+(\w*)$/) { + fatal($ref, "undefined type `$1'") unless defined $types{$1}; + return (const => 1, type => $types{$1}); + } + + fatal($ref, "undefined type `$typ'") unless defined $types{$typ}; + return (const => 0, type => $types{$typ}); +} + +#}}} + +#{{{ dump_fun + +sub dump_fun($$) { + my ($pkg, $f) = @_; + my %t = find_type($f, $f->{type}); + my $call = $f->{cfun}; + $call =~ s/\$/var/; + + print "static int luaM_${pkg}_$f->{name}(lua_State *L) {\n"; + + if ($f->{proto} ne "void") { + my $i = 1; + for my $tmp (split /,/,$f->{proto}) { + s/^\s+//; + s/\s+$//; + + my %pt = find_type($f, $tmp); + my $check = $pt{type}->{check}; + $check =~ s/\$L/L/; + $check =~ s/\$\$/\%d/; + + put_line($pt{type}, 0); + printf " $pt{type}->{ctype} var$i = $check\n", $i++; + } + } + + if (defined $t{type}->{push}) { + $call =~ s/\$\$/$t{type}->{push}/; + } + + if ($t{type}->{kind} eq 's') { + if ($t{const}) { + put_line($f, 0); + print " lua_pushstring(L, $call);\n"; + } else { + print " {\n"; + put_line($f, 0); + print " char *s = $call;\n"; + print " lua_pushstring(L, s);\n"; + print " p_delete(&s);\n"; + print " }\n"; + } + } + + if ($t{type}->{kind} eq 'i') { + put_line($f, 0); + print " lua_pushint(L, $call);\n"; + } + + printf " return %d;\n", ($f->{type} ne "void"); + print "}\n"; +} + +#}}} + +#{{{ dump_struct + +sub dump_struct_full($) { + my ($pkg) = @_; + + put_line($pkg, 0); + print "struct luaM_$pkg->{name}_t $pkg->{cname} = {\n"; + + foreach (@{$pkg->{props}}) { + my $p = $pkg->{members}{$_}; + my %t = find_type($p, $p->{type}); + + if ($t{const}) { + put_line($p, 0); + print " $p->{init},\n"; + } else { + print " 0,\n" if ($t{type}->{kind} eq 'i'); + print " NULL,\n" if ($t{type}->{kind} eq 's'); + } + } + + print <{cname}_init(void) +{ +EOF + + foreach (@{$pkg->{props}}) { + my $p = $pkg->{members}{$_}; + my %t = find_type($p, $p->{type}); + my $var = $pkg->{cname}.".".$p->{name}; + + next if $t{const}; + + put_line($p, 0); + print " m_strreplace(&$var, $p->{init});\n" if ($t{type}->{kind} eq 's'); + print " $var = $p->{init};\n" if ($t{type}->{kind} eq 'i'); + } + print "};\n"; +}; + +sub dump_struct_short($) { + my ($pkg) = @_; + + print "struct luaM_$pkg->{name}_t {\n"; + foreach (@{$pkg->{props}}) { + my $p = $pkg->{members}{$_}; + my %t = find_type($p, $p->{type}); + print " $t{type}->{ctype} $p->{name};\n"; + } + put_line($pkg, 0); + print <{name}_t $pkg->{cname}; +EOF +} + +#}}} + +#{{{ dump package + +sub dump_package_full($) { + my $pkg = shift; + + dump_struct_full($pkg); + map { print "\n"; dump_fun($pkg->{name}, $pkg->{members}{$_}); } @{$pkg->{meths}}; + print <{name}_methods[] = { +EOF + map { print " { \"$_\", luaM_$pkg->{name}_$_ },\n"; } @{$pkg->{meths}}; + print <{name}_index(lua_State *L) +{ + const char *idx = luaL_checkstring(L, 2); + + switch (mlua_which_token(idx, -1)) { +EOF + + foreach (@{$pkg->{props}}) { + my $p = $pkg->{members}{$_}; + my %t = find_type($p, $p->{type}); + my $call = $pkg->{cname}.".".$p->{name}; + + my $tok = $p->{name}; + $tok =~ tr/a-z/A-Z/; + + if ($t{type}->{kind} eq 's') { + $call = "lua_pushstring(L, $call)"; + } + + if ($t{type}->{kind} eq 'i') { + $call = "lua_pushinteger(L, $call)"; + } + + if (defined $t{type}->{push}) { + $call =~ s/\$\$/$t{type}->{push}/; + } + + put_line($p, 0); + print " case LTK_$tok:\n"; + printf " $call;\n"; + print " return 1;\n"; + } + +print <{name}_newindex(lua_State *L) +{ + const char *idx = luaL_checkstring(L, 2); + + switch (mlua_which_token(idx, -1)) { +EOF + + foreach (@{$pkg->{props}}) { + my $p = $pkg->{members}{$_}; + my %t = find_type($p, $p->{type}); + + next if ($t{const}); + + my $tok = $p->{name}; + my $var = $pkg->{cname}.".".$p->{name}; + my $check = $t{type}->{check}; + $tok =~ tr/a-z/A-Z/; + $check =~ s/\$L/L/; + $check =~ s/\$\$/3/; + + put_line($p, 0); + print " case LTK_$tok: \n"; + print " m_strreplace(&$var, $check)" if ($t{type}->{kind} eq 's'); + print " $var = $check" if ($t{type}->{kind} eq 'i'); + + print ";\n return 1;\n"; + } + +print <{name}(lua_State *L) +{ + int mt, methods; + + $pkg->{cname}_init(); + + /* create methods table, add it the the table of globals */ + luaL_openlib(L, "$pkg->{name}", luaM_$pkg->{name}_methods, 0); + methods = lua_gettop(L); + + /* create metatable for $pkg->{name}, add it to the registry */ + luaL_newmetatable(L, "$pkg->{name}"); + mt = lua_gettop(L); + + lua_pushliteral(L, "__index"); + lua_pushvalue(L, mt); /* upvalue 1 */ + lua_pushvalue(L, methods); /* upvalue 2 */ + lua_pushcclosure(L, &luaM_$pkg->{name}_index, 2); + lua_rawset(L, mt); /* set mt.__index */ + + lua_pushliteral(L, "__newindex"); + lua_newtable(L); /* for new members */ + lua_pushcclosure(L, &luaM_$pkg->{name}_newindex, 1); + lua_rawset(L, mt); /* set mt.__newindex */ + + lua_pushliteral(L, "__metatable"); + lua_pushvalue(L, methods); /* dup methods table */ + lua_rawset(L, mt); /* hide metatable */ + + lua_setmetatable(L, methods); + + lua_pop(L, 1); /* drop mt */ + return 1; /* return methods */ +} + +EOF +} + +sub dump_package_short($) { + my $pkg = shift; + my $upp = $pkg->{name}; + $upp =~ tr/a-z/A-Z/; + + print <{name}(lua_State *L); + +#endif /* MUTT_LUA_${upp}_H */ +EOF +} + +#}}} + +sub do_c($) { + my %src = stream_open(shift); + my $resync = 1; + + while (stream_getline(\%src)) { + if (/^\s*\@type\s+([a-zA-Z]\w*)\s*=\s*{\s*$/) { + parse_type(\%src, $1); + $resync = 1; + } elsif (/^\s*\@package\s+([a-zA-Z]\w*)\s+{\s*$/) { + dump_package_full(parse_package(\%src, $1)); + $resync = 1; + } elsif (/^\s*(\@\w*)/) { + fatal(\%src, "syntax error: unknown directive `$1'"); + } else { + next if ($resync && /^\s+$/); + if ($resync) { + put_line(\%src, 0); + $resync = 0; + } + print; + } + } + print "/* vi"."m:set ft=c: */\n"; + + stream_close(\%src); +} + +sub do_h($) { + my %src = stream_open(shift); + my $resync = 1; + + while (stream_getline(\%src)) { + if (/^\s*\@type\s+([a-zA-Z]\w*)\s*=\s*{\s*$/) { + parse_type(\%src, $1); + } elsif (/^\s*\@package\s+([a-zA-Z]\w*)\s+{\s*$/) { + dump_package_short(parse_package(\%src, $1)); + } elsif (/^\s*(\@\w*)/) { + fatal(\%src, "syntax error: unknown directive `$1'"); + } + } + + stream_close(\%src); +} + +if ($#ARGV < 1 || ($ARGV[0] ne "-h" && $ARGV[0] ne "-c")) { + print < - -#include -#include - -#include "lib-lua_priv.h" - -#include "../mutt.h" - -/* {{{ madmutt functions */ - -static int madmutt_pwd(lua_State *L) -{ - char path[_POSIX_PATH_MAX]; - getcwd(path, sizeof(path)); - lua_pushstring(L, path); - return 1; -} - -static int madmutt_folder_path(lua_State *L) -{ - lua_pushstring(L, CurrentFolder ?: ""); - return 1; -} - -static int madmutt_folder_name(lua_State *L) -{ - const char *p; - - if (!m_strisempty(Maildir) - && m_strstart(CurrentFolder, Maildir, &p) && *p) { - while (*p == '/') - p++; - lua_pushstring(L, p); - } else { - p = strchr(CurrentFolder ?: "", '/'); - lua_pushstring(L, p ? p + 1 : (CurrentFolder ?: "")); - } - return 1; -} - -static quadopt_t quadopt_parse(const char *s) -{ - if (!m_strcasecmp("yes", s)) - return M_YES; - if (!m_strcasecmp("no", s)) - return M_NO; - if (!m_strcasecmp("ask-yes", s)) - return M_ASKYES; - if (!m_strcasecmp("ask-no", s)) - return M_ASKNO; - return -1; -} - -static int madmutt_assign(lua_State *L) -{ - const char *idx = luaL_checkstring(L, 2); - const char *val = luaL_checkstring(L, 3); - int tk; - - switch ((tk = lua_which_token(idx, -1))) { - char buf[STRING]; - int i; - - case LTK_DOTLOCK: - case LTK_SENDMAIL: - case LTK_SHELL: - case LTK_EDITOR: - _mutt_expand_path(buf, sizeof(buf), val, 0); - val = buf; - /* FALLTHROUGH */ - - mlua_regsets(tk, val); - return 0; - - case LTK_QUIT: - i = quadopt_parse(val); - if (i < 0) - return luaL_error(L, "invalid quad option value: '%s'", val); - mlua_regseti(tk, i); - return 0; - - case LTK_UNKNOWN: - case LTK_count: - break; - } - - return luaL_error(L, "read-only or inexistant property '%s'", idx, tk); -} - -static int madmutt_get(lua_State *L) -{ - const char *idx = luaL_checkstring(L, 2); - enum lua_token tk = lua_which_token(idx, -1); - - switch (tk) { - case LTK_DOTLOCK: - case LTK_SENDMAIL: - case LTK_SHELL: - case LTK_EDITOR: - lua_pushstring(L, mlua_reggets(tk)); - return 1; - - case LTK_QUIT: - switch (mlua_reggeti(tk)) { - case M_YES: - lua_pushstring(L, "yes"); - return 1; - case M_NO: - lua_pushstring(L, "no"); - return 1; - case M_ASKNO: - lua_pushstring(L, "ask-no"); - return 1; - case M_ASKYES: - lua_pushstring(L, "ask-yes"); - return 1; - default: - return 0; - } - - case LTK_UNKNOWN: - case LTK_count: - break; - } - - lua_getmetatable(L, 1); - lua_replace(L, 1); - lua_rawget(L, 1); - return 1; -} - -static const struct luaL_Reg madmutt_module_funcs[] = { - { "pwd", madmutt_pwd }, - /* - ** .pp - ** \fIThis is a read-only system property and, at runtime, - ** specifies the current working directory of the madmutt - ** binary.\fP - */ - { "folder_path", madmutt_folder_path }, - /* - ** .pp - ** \fIThis is a read-only system property and, at runtime, - ** specifies the full path or URI of the folder currently - ** open (if any).\fP - */ - { "folder_name", madmutt_folder_name }, - /* - ** .pp - ** \fIThis is a read-only system property and, at runtime, - ** specifies the actual name of the folder as far as it could - ** be detected.\fP - ** .pp - ** For detection, $$$folder is first taken into account - ** and simply stripped to form the result when a match is found. For - ** example, with $$$folder being \fTimap://host\fP and the folder is - ** \fTimap://host/INBOX/foo\fP, $$$madmutt_folder_name will be just - ** \fTINBOX/foo\fP.) - ** .pp - ** Second, if the initial portion of a name is not $$$folder, - ** the result will be everything after the last ``/''. - ** .pp - ** Third and last, the result will be just the name if neither - ** $$$folder nor a ``/'' were found in the name. - */ - - { "__newindex", madmutt_assign }, - { "__index", madmutt_get }, - { NULL, NULL } -}; - -/* }}} */ - -/* {{{ read-only properties */ - -static const struct { - const char *key; - const char *value; -} madmutt_module_vars[] = { - { "version", VERSION }, - /* - ** .pp - ** \fIThis is a read-only system property and specifies madmutt's - ** version string.\fP - */ - { "sysconfdir", SYSCONFDIR }, - /* - ** .pp - ** \fIThis is a read-only system property and specifies madmutt's - ** subversion revision string.\fP - */ - { "bindir", BINDIR }, - /* - ** .pp - ** \fIThis is a read-only system property and specifies the - ** directory containing the madmutt binary.\fP - */ - { "docdir", PKGDOCDIR }, - /* - ** .pp - ** \fIThis is a read-only system property and specifies the - ** directory containing the madmutt documentation.\fP - */ -#ifdef USE_HCACHE -#if defined(HAVE_QDBM) - { "hcache_backend", "qdbm" }, -#elif defined(HAVE_GDBM) - { "hcache_backend", "gdbm" }, -#elif defined(HAVE_DB4) - { "hcache_backend", "db4" }, -#else - { "hcache_backend", "unknown" }, -#endif - /* - ** .pp - ** \fIThis is a read-only system property and specifies the - ** header chaching's database backend.\fP - */ -#endif -}; - -/* }}} */ - -/* {{{ madmutt magic properties */ - -static void madmutt_init_editor(char *buf, ssize_t len) -{ - m_strcpy(buf, len, getenv("VISUAL") ?: getenv("EDITOR") ?: "vi"); -} - -static void madmutt_init_shell(char *buf, ssize_t len) -{ - struct passwd *pw = getpwuid(getuid()); - - if (pw) { - m_strcpy(buf, len, pw->pw_shell); - _mutt_expand_path(buf, len, pw->pw_shell, 0); - } else { - m_strcpy(buf, len, getenv("SHELL") ?: "/bin/sh"); - } -} - -static const struct { - const char *key; - void (*fun)(char *buf, ssize_t len); - const char *val; -} madmutt_module_vars2[] = { - { "dotlock", NULL, BINDIR "/mutt_dotlock" }, - /* - ** .pp - ** Contains the path of the \fTmadmutt_dotlock(1)\fP binary to be used by - ** Madmutt. - */ - { "editor", madmutt_init_editor, NULL }, - /* - ** .pp - ** This variable specifies which editor is used by Madmutt. - ** It defaults to the value of the \fT$$$VISUAL\fP, or \fT$$$EDITOR\fP, environment - ** variable, or to the string "\fTvi\fP" if neither of those are set. - */ - { "sendmail", NULL, SENDMAIL " -oem -oi" }, - /* - ** .pp - ** Specifies the program and arguments used to deliver mail sent by Madmutt. - ** Madmutt expects that the specified program interprets additional - ** arguments as recipient addresses. - */ - { "shell", madmutt_init_shell, NULL }, - /* - ** .pp - ** Command to use when spawning a subshell. By default, the user's login - ** shell from \fT/etc/passwd\fP is used. - */ - { "quit", NULL, "yes" }, - /* - ** .pp - ** This variable controls whether ``quit'' and ``exit'' actually quit - ** from Madmutt. If it set to \fIyes\fP, they do quit, if it is set to \fIno\fP, they - ** have no effect, and if it is set to \fIask-yes\fP or \fIask-no\fP, you are - ** prompted for confirmation when you try to quit. - */ -}; - -/* }}} */ - -int luaopen_madmutt(lua_State *L) -{ - int i; - - lua_newuserdata(L, sizeof(void*)); - luaL_newmetatable(L, "madmutt.core"); - - luaL_openlib(L, NULL, madmutt_module_funcs, 0); - - for (i = 0; i < countof(madmutt_module_vars); i++) { - lua_pushstring(L, madmutt_module_vars[i].value); - lua_setfield(L, -2, madmutt_module_vars[i].key); - } - - lua_setmetatable(L, -2); - - for (i = 0; i < countof(madmutt_module_vars2); i++) { - if (madmutt_module_vars2[i].fun) { - char buf[STRING]; - (madmutt_module_vars2[i].fun)(buf, sizeof(buf)); - lua_pushstring(L, buf); - } else { - lua_pushstring(L, madmutt_module_vars2[i].val); - } - lua_setfield(L, -2, madmutt_module_vars2[i].key); - } - - lua_setglobal(L, "madmutt"); - return 1; -} diff --git a/lib-lua/madmutt.cpkg b/lib-lua/madmutt.cpkg new file mode 100644 index 0000000..f11fc65 --- /dev/null +++ b/lib-lua/madmutt.cpkg @@ -0,0 +1,80 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * Copyright © 2007 Pierre Habouzit + */ + +#include +#include + +#include +#include + +#include "../mutt.h" + +static const char *madmutt_init_shell(void) +{ + struct passwd *pw = getpwuid(getuid()); + return pw ? pw->pw_shell : (getenv("SHELL") ?: "/bin/sh"); +} + +static const char *madmutt_pwd(void) +{ + char path[_POSIX_PATH_MAX]; + getcwd(path, sizeof(path)); + return path; +} + +static const char *luaM_path_post(const char *val) +{ + char path[PATH_MAX]; + _mutt_expand_path(path, sizeof(path), val, 0); + return path; +} + +@type string_t = { + .kind = 's'; + .ctype = const char *; +}; + +@type path_t = { + .push = luaM_path_post($$); + .kind = 's'; + .ctype = char *; +}; + +@type quadopt_t = { + .kind = 'i'; + .check = luaM_checkquadopt($L, $$); + .ctype = quadopt_t; +}; + +@package madmutt { + const string_t version = VERSION; + const string_t sysconfdir = SYSCONFDIR; + const string_t bindir = BINDIR; + const string_t docdir = PKGDOCDIR; + + path_t dotlock = BINDIR "/mutt_dotlock"; + path_t editor = getenv("VISUAL") ?: getenv("EDITOR") ?: "vi"; + path_t sendmail = SENDMAIL " -eom -oi"; + path_t shell = madmutt_init_shell(); + + quadopt_t quit = M_YES; + + const string_t pwd(void) = madmutt_pwd(); +} ml_core; + diff --git a/lib-lua/runtime.c b/lib-lua/runtime.c index 0fb777c..e4482f2 100644 --- a/lib-lua/runtime.c +++ b/lib-lua/runtime.c @@ -21,22 +21,22 @@ #include "lib-lua_priv.h" static lua_State *L; -static reg_entry registry[LTK_count]; -static const luaL_Reg lualibs[] = { - {"", luaopen_base}, - {LUA_OSLIBNAME, luaopen_os}, - {LUA_LOADLIBNAME, luaopen_package}, - {LUA_TABLIBNAME, luaopen_table}, - {LUA_IOLIBNAME, luaopen_io}, - {LUA_STRLIBNAME, luaopen_string}, - {LUA_MATHLIBNAME, luaopen_math}, - {LUA_DBLIBNAME, luaopen_debug}, - {LUA_MADMUTT, luaopen_madmutt}, -}; -void mlua_initialize(void) +void luaM_initialize(void) { + static const luaL_Reg lualibs[] = { + {"", luaopen_base}, + {LUA_OSLIBNAME, luaopen_os}, + {LUA_LOADLIBNAME, luaopen_package}, + {LUA_TABLIBNAME, luaopen_table}, + {LUA_IOLIBNAME, luaopen_io}, + {LUA_STRLIBNAME, luaopen_string}, + {LUA_MATHLIBNAME, luaopen_math}, + {LUA_DBLIBNAME, luaopen_debug}, + {"madmutt", luaopen_madmutt}, + }; + int i; L = lua_open(); @@ -47,18 +47,18 @@ void mlua_initialize(void) } } -void mlua_shutdown(void) +void luaM_shutdown(void) { lua_close(L); } -int mlua_dofile(const char *filename) +int luaM_dofile(const char *filename) { return luaL_dofile(L, filename); } -int mlua_wrap(void (*errfun)(const char *fmt, ...), int status) +int luaM_wrap(void (*errfun)(const char *fmt, ...), int status) { if (status) { (*errfun)("-[lua]-: %s\n", lua_tostring(L, -1)); @@ -67,30 +67,16 @@ int mlua_wrap(void (*errfun)(const char *fmt, ...), int status) return status; } -const char *mlua_reggets(int tk) -{ - if (registry[tk].type != REG_STR) - return NULL; - return registry[tk].s; -} -int mlua_reggeti(int tk) +quadopt_t luaM_checkquadopt(lua_State *Ls, int narg) { - if (registry[tk].type != REG_INT) - return -1; - return registry[tk].i; -} + const char *s; + int i = luaL_checkinteger(Ls, narg); -void mlua_regsets(int tk, const char *s) -{ - reg_entry_wipe(registry + tk); - registry[tk].type = REG_STR; - registry[tk].s = m_strdup(s); + if (i & ~3) { + s = lua_pushfstring(Ls, "int in [0-3] expected, got %d", i); + return luaL_argerror(Ls, narg, s); + } + return i; } -void mlua_regseti(int tk, int i) -{ - reg_entry_wipe(registry + tk); - registry[tk].type = REG_INT; - registry[tk].i = i; -} diff --git a/lib-mx/mx.c b/lib-mx/mx.c index 3aaff52..90a46f4 100644 --- a/lib-mx/mx.c +++ b/lib-mx/mx.c @@ -70,13 +70,13 @@ static int invoke_dotlock (const char *path, int flags, int retry) mutt_quote_filename (f, sizeof (f), path); snprintf(cmd, sizeof(cmd), "%s %s%s%s%s%s%s%s", - mlua_reggets(LTK_DOTLOCK), - flags & DL_FL_TRY ? "-t " : "", - flags & DL_FL_UNLOCK ? "-u " : "", - flags & DL_FL_USEPRIV ? "-p " : "", - flags & DL_FL_FORCE ? "-f " : "", - flags & DL_FL_UNLINK ? "-d " : "", - flags & DL_FL_RETRY ? r : "", f); + ml_core.dotlock, + flags & DL_FL_TRY ? "-t " : "", + flags & DL_FL_UNLOCK ? "-u " : "", + flags & DL_FL_USEPRIV ? "-p " : "", + flags & DL_FL_FORCE ? "-f " : "", + flags & DL_FL_UNLINK ? "-d " : "", + flags & DL_FL_RETRY ? r : "", f); return mutt_system (cmd); } diff --git a/lib-ui/curs_lib.c b/lib-ui/curs_lib.c index 81edf2e..571f285 100644 --- a/lib-ui/curs_lib.c +++ b/lib-ui/curs_lib.c @@ -144,7 +144,7 @@ void mutt_edit_file(const char *data) char cmd[LONG_STRING]; mutt_endwin (NULL); - m_quotefile_fmt(cmd, sizeof (cmd), mlua_reggets(LTK_EDITOR), data); + m_quotefile_fmt(cmd, sizeof (cmd), ml_core.editor, data); if (mutt_system (cmd) == -1) mutt_error (_("Error running \"%s\"!"), cmd); keypad (stdscr, TRUE); diff --git a/lib-ui/curs_main.c b/lib-ui/curs_main.c index c716dc5..246f240 100644 --- a/lib-ui/curs_main.c +++ b/lib-ui/curs_main.c @@ -974,7 +974,7 @@ int mutt_index_menu (void) break; } - if (query_quadoption2(LTK_QUIT, _("Quit Madmutt?")) == M_YES) { + if (query_quadoption2(ml_core.quit, _("Quit Madmutt?")) == M_YES) { int check; oldcount = Context ? Context->msgcount : 0; @@ -1302,7 +1302,7 @@ int mutt_index_menu (void) } if ((menu->menu == MENU_MAIN) - && (query_quadoption2(LTK_QUIT, + && (query_quadoption2(ml_core.quit, _("Exit Madmutt without saving?")) == M_YES)) { if (Context) { diff --git a/main.c b/main.c index adb387d..da1b66d 100644 --- a/main.c +++ b/main.c @@ -851,6 +851,6 @@ int main (int argc, char **argv) mutt_endwin (Errorbuf); } - mlua_shutdown(); + luaM_shutdown(); exit (0); } diff --git a/sendlib.c b/sendlib.c index f5f5867..ed4bbb9 100644 --- a/sendlib.c +++ b/sendlib.c @@ -1849,7 +1849,7 @@ static int mutt_invoke_sendmail (address_t * from, /* the sender */ } else #endif { - m_strcpy(cmd, sizeof(cmd), mlua_reggets(LTK_SENDMAIL)); + m_strcpy(cmd, sizeof(cmd), ml_core.sendmail); } ps = cmd; -- 2.20.1