new lua implementation.
authorPierre Habouzit <madcoder@debian.org>
Sun, 18 Mar 2007 12:20:06 +0000 (13:20 +0100)
committerPierre Habouzit <madcoder@debian.org>
Sun, 18 Mar 2007 12:20:06 +0000 (13:20 +0100)
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
15 files changed:
commands.c
init.c
lib-lua/Makefile.am
lib-lua/lib-lua.h
lib-lua/lib-lua_priv.h
lib-lua/lua-token.sh
lib-lua/luapkg2c.pl [new file with mode: 0755]
lib-lua/madmutt.c [deleted file]
lib-lua/madmutt.cpkg [new file with mode: 0644]
lib-lua/runtime.c
lib-mx/mx.c
lib-ui/curs_lib.c
lib-ui/curs_main.c
main.c
sendlib.c

index a7cc074..ed99c4a 100644 (file)
@@ -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 (file)
--- 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));
   }
   /* }}} */
 
index 78006a1..b28c98d 100644 (file)
@@ -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
index 4ce8906..5afb91f 100644 (file)
 # include "../config.h"
 #endif
 
+#include <lua.h>
+#include <lualib.h>
+#include <lauxlib.h>
+
 #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
index 84fd121..93dd397 100644 (file)
 #include <lualib.h>
 #include <lauxlib.h>
 
-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
index b715c37..5c61d66 100644 (file)
@@ -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 <<EOF | gperf -m16 -l -t -C -F",0" -Nlua_which_token_aux
+    cat <<EOF | gperf -m16 -l -t -C -F",0" -Nmlua_which_token_aux
 %{
 `do_hdr`
 
@@ -64,21 +66,25 @@ do_c() {
 #include "lua-token.h"
 
 static const struct tok *
-lua_which_token_aux(const char *str, unsigned int len);
+mlua_which_token_aux(const char *str, unsigned int len);
 
 %}
 struct tok { const char *name; int val; };
 %%
-`do_tokens`
+`grep_self "$0" | do_tokens`
 %%
 
-enum lua_token lua_which_token(const char *s, ssize_t len)
+const char *__mlua_token[LTK_count] = {
+`grep_self "$0" | sed -e 's/.*/    "&",/'`
+};
+
+mlua_token mlua_which_token(const char *s, ssize_t len)
 {
     if (len < 0)
         len = m_strlen(s);
 
     if (len) {
-        const struct tok *res = lua_which_token_aux(s, len);
+        const struct tok *res = mlua_which_token_aux(s, len);
         return res ? res->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 (executable)
index 0000000..2d152cb
--- /dev/null
@@ -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 <<EOF;
+};
+
+static void $pkg->{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 <<EOF;
+};
+
+extern struct luaM_$pkg->{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 <<EOF;
+
+static const luaL_reg luaM_$pkg->{name}_methods[] = {
+EOF
+    map { print "    { \"$_\", luaM_$pkg->{name}_$_ },\n"; } @{$pkg->{meths}};
+    print <<EOF;
+    { NULL, NULL }
+};
+
+static int luaM_$pkg->{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 <<EOF;
+      default:
+        lua_rawget(L, lua_upvalueindex(2));       /* try methods       */
+        return 1;
+    }
+}
+
+static int luaM_$pkg->{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 <<EOF;
+      default:
+        return 1;
+    }
+}
+
+int luaopen_$pkg->{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 <<EOF;
+#ifndef MUTT_LUA_${upp}_H
+#define MUTT_LUA_${upp}_H
+
+EOF
+    dump_struct_short($pkg);
+    print <<EOF
+
+int luaopen_$pkg->{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 <<EOF;
+usage: mluapkg (-h | -c) file.pkg
+EOF
+    exit 1;
+}
+
+print <<EOF;
+/*****     THIS FILE IS AUTOGENERATED DO NOT MODIFY DIRECTLY !    *****/
+EOF
+
+map { do_h($ARGV[$_]); } (1 .. $#ARGV) if ($ARGV[0] eq '-h');
+map { do_c($ARGV[$_]); } (1 .. $#ARGV) if ($ARGV[0] eq '-c');
diff --git a/lib-lua/madmutt.c b/lib-lua/madmutt.c
deleted file mode 100644 (file)
index 6fe2b4d..0000000
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- *  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 <lib-lib/lib-lib.h>
-
-#include <sys/types.h>
-#include <pwd.h>
-
-#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 (file)
index 0000000..f11fc65
--- /dev/null
@@ -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 <lib-lib/lib-lib.h>
+#include <lib-lua/lib-lua.h>
+
+#include <sys/types.h>
+#include <pwd.h>
+
+#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;
+
index 0fb777c..e4482f2 100644 (file)
 #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;
-}
index 3aaff52..90a46f4 100644 (file)
@@ -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);
 }
index 81edf2e..571f285 100644 (file)
@@ -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);
index c716dc5..246f240 100644 (file)
@@ -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 (file)
--- 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);
 }
index f5f5867..ed4bbb9 100644 (file)
--- 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;