summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rwxr-xr-xcompiler/ast.nim5
-rwxr-xr-xcompiler/semtypinst.nim4
-rwxr-xr-xcompiler/sigmatch.nim17
-rwxr-xr-xcompiler/transf.nim2
-rwxr-xr-xcompiler/types.nim6
-rw-r--r--lib/wrappers/opengl/opengl.nim120
6 files changed, 85 insertions, 69 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 340a14888..83bd360f2 100755
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -287,6 +287,11 @@ type
     tyGenericInvokation, # ``T[a, b]`` for types to invoke
     tyGenericBody,       # ``T[a, b, body]`` last parameter is the body
     tyGenericInst,       # ``T[a, b, realInstance]`` instantiated generic type
+                         # realInstance will be a concrete type like tyObject
+                         # unless this is an instance of a generic alias type.
+                         # then realInstance will be the tyGenericInst of the
+                         # completely (recursively) resolved alias.
+                         
     tyGenericParam,      # ``a`` in the above patterns
     tyDistinct,
     tyEnum,
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim
index d51e24c89..e12640945 100755
--- a/compiler/semtypinst.nim
+++ b/compiler/semtypinst.nim
@@ -171,6 +171,10 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
     result.flags = result.flags + newbody.flags
     newbody.callConv = body.callConv
     newbody.n = ReplaceTypeVarsN(cl, lastSon(body).n)
+    # This type may be a generic alias and we want to resolve it here.
+    # One step is enough, because the recursive nature of
+    # handleGenericInvokation will handle the alias-to-alias-to-alias case
+    if newbody.isGenericAlias: newbody = newbody.skipGenericAlias
     rawAddSon(result, newbody)
     checkPartialConstructedType(cl.info, newbody)
   else:
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 8968e4e03..f1920a255 100755
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -476,22 +476,23 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
     let ff = lastSon(f)
     if ff != nil: result = typeRel(c, ff, a)
   of tyGenericInvokation:
+    var x = a.skipGenericAlias
     assert(f.sons[0].kind == tyGenericBody)
-    if a.kind == tyGenericInvokation: 
+    if x.kind == tyGenericInvokation:
       #InternalError("typeRel: tyGenericInvokation -> tyGenericInvokation")
       # simply no match for now:
       nil
-    elif a.kind == tyGenericInst and 
-          (f.sons[0].containerID == a.sons[0].containerID) and
-          (sonsLen(a) - 1 == sonsLen(f)): 
-      assert(a.sons[0].kind == tyGenericBody)
+    elif x.kind == tyGenericInst and 
+          (f.sons[0].containerID == x.sons[0].containerID) and
+          (sonsLen(x) - 1 == sonsLen(f)): 
+      assert(x.sons[0].kind == tyGenericBody)
       for i in countup(1, sonsLen(f) - 1): 
-        if a.sons[i].kind == tyGenericParam: 
+        if x.sons[i].kind == tyGenericParam: 
           InternalError("wrong instantiated type!")
-        elif typeRel(c, f.sons[i], a.sons[i]) <= isSubtype: return 
+        elif typeRel(c, f.sons[i], x.sons[i]) <= isSubtype: return 
       result = isGeneric
     else:
-      result = typeRel(c, f.sons[0], a)
+      result = typeRel(c, f.sons[0], x)
       if result != isNone:
         # we steal the generic parameters from the tyGenericBody:
         for i in countup(1, sonsLen(f) - 1):
diff --git a/compiler/transf.nim b/compiler/transf.nim
index 170f8ff0f..d1ee76cf1 100755
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -603,7 +603,7 @@ proc transform(c: PTransf, n: PNode): PTransNode =
     dec c.inLoop
   of nkCaseStmt: result = transformCase(c, n)
   of nkContinueStmt:
-    result = PTransNode(newNode(nkBreakStmt))
+    result = PTransNode(newNodeI(nkBreakStmt, n.info))
     var labl = c.contSyms[c.contSyms.high]
     add(result, PTransNode(newSymNode(labl)))
   of nkBreakStmt: result = transformBreak(c, n)
diff --git a/compiler/types.nim b/compiler/types.nim
index e02d93233..90fffff40 100755
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -905,6 +905,12 @@ proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]],
     a = a.sons[i]
   result = a.kind == last
 
+proc isGenericAlias*(t: PType): bool =
+  return t.kind == tyGenericInst and t.lastSon.kind == tyGenericInst
+
+proc skipGenericAlias*(t: PType): PType =
+  return if t.isGenericAlias: t.lastSon else: t
+
 proc matchTypeClass*(bindings: var TIdTable, typeClass, t: PType): bool =
   for i in countup(0, typeClass.sonsLen - 1):
     let req = typeClass.sons[i]
diff --git a/lib/wrappers/opengl/opengl.nim b/lib/wrappers/opengl/opengl.nim
index fab8183f5..a61159016 100644
--- a/lib/wrappers/opengl/opengl.nim
+++ b/lib/wrappers/opengl/opengl.nim
@@ -8,13 +8,13 @@
 #

 

 ## This module is a wrapper around `opengl`:idx:. If you define the symbol

-## ``useGlew`` this wrapper does not use Nimrod's ``dynlib`` mechanism, 
-## but `glew`:idx: instead. However, this shouldn't be necessary anymore; even
-## extension loading for the different operating systems is handled here.
-##
-## You need to call ``loadExtensions`` after a rendering context has been
+## ``useGlew`` this wrapper does not use Nimrod's ``dynlib`` mechanism, 

+## but `glew`:idx: instead. However, this shouldn't be necessary anymore; even

+## extension loading for the different operating systems is handled here.

+##

+## You need to call ``loadExtensions`` after a rendering context has been

 ## created to load any extension proc that your code uses.

-
+

 when defined(linux):

   import X, XLib, XUtil

 elif defined(windows):

@@ -39,58 +39,58 @@ when defined(useGlew):
   {.pragma: wgl, header: "<GL/wglew.h>".}

   {.pragma: glu, dynlib: gludll.}

 else:

-  # quite complex ... thanks to extension support for various platforms:
-  import dynlib
-  
-  let oglHandle = LoadLib(ogldll)
-  if isNil(oglHandle): quit("could not load: " & ogldll)
-  
-  when defined(windows):
-    var wglGetProcAddress = cast[proc (s: cstring): pointer {.stdcall.}](
-      symAddr(oglHandle, "wglGetProcAddress"))
-  elif defined(linux):
-    var glXGetProcAddress = cast[proc (s: cstring): pointer {.cdecl.}](
-      symAddr(oglHandle, "glXGetProcAddress"))
-    var glXGetProcAddressARB = cast[proc (s: cstring): pointer {.cdecl.}](
-      symAddr(oglHandle, "glXGetProcAddressARB"))
-
-  proc glGetProc(h: TLibHandle; procName: cstring): pointer =
-    when defined(windows):
-      result = symAddr(h, procname)
-      if result != nil: return
-      if not isNil(wglGetProcAddress): result = wglGetProcAddress(ProcName)
-    elif defined(linux):
-      if not isNil(glXGetProcAddress): result = glXGetProcAddress(ProcName)
-      if result != nil: return 
-      if not isNil(glXGetProcAddressARB): 
-        result = glXGetProcAddressARB(ProcName)
-        if result != nil: return
-      result = symAddr(h, procname)
-    else:
-      result = symAddr(h, procName)
-    if result == nil: raiseInvalidLibrary(procName)
-
-  var gluHandle: TLibHandle
-  
-  proc gluGetProc(procname: cstring): pointer =
-    if gluHandle == nil:
-      gluHandle = LoadLib(gludll)
-      if gluHandle == nil: quit("could not load: " & gludll)
-    result = glGetProc(gluHandle, procname)
-  
-  # undocumented 'dynlib' feature: the string literal is replaced by
-  # the imported proc name:
-  {.pragma: ogl, dynlib: glGetProc(oglHandle, "").}

+  # quite complex ... thanks to extension support for various platforms:

+  import dynlib

+  

+  let oglHandle = LoadLib(ogldll)

+  if isNil(oglHandle): quit("could not load: " & ogldll)

+  

+  when defined(windows):

+    var wglGetProcAddress = cast[proc (s: cstring): pointer {.stdcall.}](

+      symAddr(oglHandle, "wglGetProcAddress"))

+  elif defined(linux):

+    var glXGetProcAddress = cast[proc (s: cstring): pointer {.cdecl.}](

+      symAddr(oglHandle, "glXGetProcAddress"))

+    var glXGetProcAddressARB = cast[proc (s: cstring): pointer {.cdecl.}](

+      symAddr(oglHandle, "glXGetProcAddressARB"))

+

+  proc glGetProc(h: TLibHandle; procName: cstring): pointer =

+    when defined(windows):

+      result = symAddr(h, procname)

+      if result != nil: return

+      if not isNil(wglGetProcAddress): result = wglGetProcAddress(ProcName)

+    elif defined(linux):

+      if not isNil(glXGetProcAddress): result = glXGetProcAddress(ProcName)

+      if result != nil: return 

+      if not isNil(glXGetProcAddressARB): 

+        result = glXGetProcAddressARB(ProcName)

+        if result != nil: return

+      result = symAddr(h, procname)

+    else:

+      result = symAddr(h, procName)

+    if result == nil: raiseInvalidLibrary(procName)

+

+  var gluHandle: TLibHandle

+  

+  proc gluGetProc(procname: cstring): pointer =

+    if gluHandle == nil:

+      gluHandle = LoadLib(gludll)

+      if gluHandle == nil: quit("could not load: " & gludll)

+    result = glGetProc(gluHandle, procname)

+  

+  # undocumented 'dynlib' feature: the string literal is replaced by

+  # the imported proc name:

+  {.pragma: ogl, dynlib: glGetProc(oglHandle, "0").}

   {.pragma: oglx, dynlib: glGetProc(oglHandle, "0").}

-  {.pragma: wgl, dynlib: glGetProc(oglHandle, "").}

-  {.pragma: glu, dynlib: gluGetProc("").}
-  
-  proc nimLoadProcs0() {.importc.}
-  
-  template loadExtensions*() =
-    ## call this after your rendering context has been setup if you use
-    ## extensions.
-    bind nimLoadProcs0
+  {.pragma: wgl, dynlib: glGetProc(oglHandle, "0").}

+  {.pragma: glu, dynlib: gluGetProc("").}

+  

+  proc nimLoadProcs0() {.importc.}

+  

+  template loadExtensions*() =

+    ## call this after your rendering context has been setup if you use

+    ## extensions.

+    bind nimLoadProcs0

     nimLoadProcs0()

 

 #==============================================================================

@@ -9104,7 +9104,7 @@ proc glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN*(rc: GLuint,
 proc glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN*(rc: PGLuint, 

     tc: PGLfloat, c: PGLfloat, n: PGLfloat, v: PGLfloat){.stdcall, importc, ogl.}

   # window support functions

-when defined(windows): 
+when defined(windows): 

   when not defined(wglGetProcAddress):

     proc wglGetProcAddress*(ProcName: cstring): Pointer{.stdcall, importc, wgl.}

   proc wglCopyContext*(p1: HGLRC, p2: HGLRC, p3: int): BOOL{.stdcall, importc, wgl.}

@@ -9446,11 +9446,11 @@ when defined(LINUX):
       stdcall, importc, oglx.}

   proc glXGetSelectedEvent*(dpy: PDisplay, draw: GLXDrawable, 

                             event_mask: PGLuint){.stdcall, importc, oglx.}

-    # GLX_VERSION_1_4
+    # GLX_VERSION_1_4

   when not defined(glXGetProcAddress):

     proc glXGetProcAddress*(name: cstring): pointer{.stdcall, importc, oglx.}

     # GLX_ARB_get_proc_address

-  when not defined(glXGetProcAddressARB):
+  when not defined(glXGetProcAddressARB):

     proc glXGetProcAddressARB*(name: cstring): pointer{.stdcall, importc, oglx.}

     # GLX_ARB_create_context

   proc glXCreateContextAttribsARB*(dpy: PDisplay, config: GLXFBConfig, 

' href='#n579'>579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854












































































































































































                                                                             

                             






































































































































































































































































































































































































































































































































































































































































































                                                                             
/*=========================================================================*\
* MIME support functions
* LuaSocket toolkit
\*=========================================================================*/
#include "luasocket.h"
#include "mime.h"
#include <string.h>
#include <ctype.h>

/*=========================================================================*\
* Don't want to trust escape character constants
\*=========================================================================*/
typedef unsigned char UC;
static const char CRLF[] = "\r\n";
static const char EQCRLF[] = "=\r\n";

/*=========================================================================*\
* Internal function prototypes.
\*=========================================================================*/
static int mime_global_wrp(lua_State *L);
static int mime_global_b64(lua_State *L);
static int mime_global_unb64(lua_State *L);
static int mime_global_qp(lua_State *L);
static int mime_global_unqp(lua_State *L);
static int mime_global_qpwrp(lua_State *L);
static int mime_global_eol(lua_State *L);
static int mime_global_dot(lua_State *L);

static size_t dot(int c, size_t state, luaL_Buffer *buffer);
//static void b64setup(UC *base);
static size_t b64encode(UC c, UC *input, size_t size, luaL_Buffer *buffer);
static size_t b64pad(const UC *input, size_t size, luaL_Buffer *buffer);
static size_t b64decode(UC c, UC *input, size_t size, luaL_Buffer *buffer);

//static void qpsetup(UC *class, UC *unbase);
static void qpquote(UC c, luaL_Buffer *buffer);
static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer);
static size_t qpencode(UC c, UC *input, size_t size,
        const char *marker, luaL_Buffer *buffer);
static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer);

/* code support functions */
static luaL_Reg func[] = {
    { "dot", mime_global_dot },
    { "b64", mime_global_b64 },
    { "eol", mime_global_eol },
    { "qp", mime_global_qp },
    { "qpwrp", mime_global_qpwrp },
    { "unb64", mime_global_unb64 },
    { "unqp", mime_global_unqp },
    { "wrp", mime_global_wrp },
    { NULL, NULL }
};

/*-------------------------------------------------------------------------*\
* Quoted-printable globals
\*-------------------------------------------------------------------------*/
enum {QP_PLAIN, QP_QUOTED, QP_CR, QP_IF_LAST};

static const UC qpclass[] = {
    QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
    QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_IF_LAST, QP_QUOTED, QP_QUOTED,
    QP_QUOTED, QP_CR, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
    QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
    QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
    QP_QUOTED, QP_QUOTED, QP_IF_LAST, QP_PLAIN, QP_PLAIN, QP_PLAIN,
    QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
    QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
    QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
    QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
    QP_PLAIN, QP_QUOTED, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
    QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
    QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
    QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
    QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
    QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
    QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
    QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
    QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
    QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
    QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
    QP_PLAIN, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
    QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
    QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
    QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
    QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
    QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
    QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
    QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
    QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
    QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
    QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
    QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
    QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
    QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
    QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
    QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
    QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
    QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
    QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
    QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
    QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
    QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED
};

static const UC qpbase[] = "0123456789ABCDEF";

static const UC qpunbase[] = {
    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255,
    255, 255, 255, 255, 255, 255, 10, 11, 12, 13, 14, 15,
    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 10, 11, 12, 13, 14, 15, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255
};

/*-------------------------------------------------------------------------*\
* Base64 globals
\*-------------------------------------------------------------------------*/
static const UC b64base[] =
        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

static const UC b64unbase[] = {
    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 0,
    255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
    14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255,
    255, 255, 255, 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
    36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
    51, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    255, 255
};

/*=========================================================================*\
* Exported functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Initializes module
\*-------------------------------------------------------------------------*/
LUASOCKET_API int luaopen_mime_core(lua_State *L)
{
    lua_newtable(L);
    luaL_setfuncs(L, func, 0);
    lua_pushvalue(L, -1);
    lua_setglobal(L, "mime");
    /* make version string available to scripts */
    lua_pushstring(L, "_VERSION");
    lua_pushstring(L, MIME_VERSION);
    lua_rawset(L, -3);
    /* initialize lookup tables */
    // qpsetup(qpclass, qpunbase);
    // b64setup(b64unbase);
    return 1;
}

/*=========================================================================*\
* Global Lua functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Incrementaly breaks a string into lines. The string can have CRLF breaks.
* A, n = wrp(l, B, length)
* A is a copy of B, broken into lines of at most 'length' bytes.
* 'l' is how many bytes are left for the first line of B.
* 'n' is the number of bytes left in the last line of A.
\*-------------------------------------------------------------------------*/
static int mime_global_wrp(lua_State *L)
{
    size_t size = 0;
    int left = (int) luaL_checknumber(L, 1);
    const UC *input = (const UC *) luaL_optlstring(L, 2, NULL, &size);
    const UC *last = input + size;
    int length = (int) luaL_optnumber(L, 3, 76);
    luaL_Buffer buffer;
    /* end of input black-hole */
    if (!input) {
        /* if last line has not been terminated, add a line break */
        if (left < length) lua_pushstring(L, CRLF);
        /* otherwise, we are done */
        else lua_pushnil(L);
        lua_pushnumber(L, length);
        return 2;
    }
    luaL_buffinit(L, &buffer);
    while (input < last) {
        switch (*input) {
            case '\r':
                break;
            case '\n':
                luaL_addstring(&buffer, CRLF);
                left = length;
                break;
            default:
                if (left <= 0) {
                    left = length;
                    luaL_addstring(&buffer, CRLF);
                }
                luaL_addchar(&buffer, *input);
                left--;
                break;
        }
        input++;
    }
    luaL_pushresult(&buffer);
    lua_pushnumber(L, left);
    return 2;
}

#if 0
/*-------------------------------------------------------------------------*\
* Fill base64 decode map.
\*-------------------------------------------------------------------------*/
static void b64setup(UC *unbase)
{
    int i;
    for (i = 0; i <= 255; i++) unbase[i] = (UC) 255;
    for (i = 0; i < 64; i++) unbase[b64base[i]] = (UC) i;
    unbase['='] = 0;

    printf("static const UC b64unbase[] = {\n");
    for (int i = 0; i < 256; i++) {
        printf("%d, ", unbase[i]);
    }
    printf("\n}\n;");
}
#endif

/*-------------------------------------------------------------------------*\
* Acumulates bytes in input buffer until 3 bytes are available.
* Translate the 3 bytes into Base64 form and append to buffer.
* Returns new number of bytes in buffer.
\*-------------------------------------------------------------------------*/
static size_t b64encode(UC c, UC *input, size_t size,
        luaL_Buffer *buffer)
{
    input[size++] = c;
    if (size == 3) {
        UC code[4];
        unsigned long value = 0;
        value += input[0]; value <<= 8;
        value += input[1]; value <<= 8;
        value += input[2];
        code[3] = b64base[value & 0x3f]; value >>= 6;
        code[2] = b64base[value & 0x3f]; value >>= 6;
        code[1] = b64base[value & 0x3f]; value >>= 6;
        code[0] = b64base[value];
        luaL_addlstring(buffer, (char *) code, 4);
        size = 0;
    }
    return size;
}

/*-------------------------------------------------------------------------*\
* Encodes the Base64 last 1 or 2 bytes and adds padding '='
* Result, if any, is appended to buffer.
* Returns 0.
\*-------------------------------------------------------------------------*/
static size_t b64pad(const UC *input, size_t size,
        luaL_Buffer *buffer)
{
    unsigned long value = 0;
    UC code[4] = {'=', '=', '=', '='};
    switch (size) {
        case 1:
            value = input[0] << 4;
            code[1] = b64base[value & 0x3f]; value >>= 6;
            code[0] = b64base[value];
            luaL_addlstring(buffer, (char *) code, 4);
            break;
        case 2:
            value = input[0]; value <<= 8;
            value |= input[1]; value <<= 2;
            code[2] = b64base[value & 0x3f]; value >>= 6;
            code[1] = b64base[value & 0x3f]; value >>= 6;
            code[0] = b64base[value];
            luaL_addlstring(buffer, (char *) code, 4);
            break;
        default:
            break;
    }
    return 0;
}

/*-------------------------------------------------------------------------*\
* Acumulates bytes in input buffer until 4 bytes are available.
* Translate the 4 bytes from Base64 form and append to buffer.
* Returns new number of bytes in buffer.
\*-------------------------------------------------------------------------*/
static size_t b64decode(UC c, UC *input, size_t size,
        luaL_Buffer *buffer)
{
    /* ignore invalid characters */
    if (b64unbase[c] > 64) return size;
    input[size++] = c;
    /* decode atom */
    if (size == 4) {
        UC decoded[3];
        int valid, value = 0;
        value =  b64unbase[input[0]]; value <<= 6;
        value |= b64unbase[input[1]]; value <<= 6;
        value |= b64unbase[input[2]]; value <<= 6;
        value |= b64unbase[input[3]];
        decoded[2] = (UC) (value & 0xff); value >>= 8;
        decoded[1] = (UC) (value & 0xff); value >>= 8;
        decoded[0] = (UC) value;
        /* take care of paddding */
        valid = (input[2] == '=') ? 1 : (input[3] == '=') ? 2 : 3;
        luaL_addlstring(buffer, (char *) decoded, valid);
        return 0;
    /* need more data */
    } else return size;
}

/*-------------------------------------------------------------------------*\
* Incrementally applies the Base64 transfer content encoding to a string
* A, B = b64(C, D)
* A is the encoded version of the largest prefix of C .. D that is
* divisible by 3. B has the remaining bytes of C .. D, *without* encoding.
* The easiest thing would be to concatenate the two strings and
* encode the result, but we can't afford that or Lua would dupplicate
* every chunk we received.
\*-------------------------------------------------------------------------*/
static int mime_global_b64(lua_State *L)
{
    UC atom[3];
    size_t isize = 0, asize = 0;
    const UC *input = (const UC *) luaL_optlstring(L, 1, NULL, &isize);
    const UC *last = input + isize;
    luaL_Buffer buffer;
    /* end-of-input blackhole */
    if (!input) {
        lua_pushnil(L);
        lua_pushnil(L);
        return 2;
    }
    /* make sure we don't confuse buffer stuff with arguments */
    lua_settop(L, 2);
    /* process first part of the input */
    luaL_buffinit(L, &buffer);
    while (input < last)
        asize = b64encode(*input++, atom, asize, &buffer);
    input = (const UC *) luaL_optlstring(L, 2, NULL, &isize);
    /* if second part is nil, we are done */
    if (!input) {
        size_t osize = 0;
        asize = b64pad(atom, asize, &buffer);
        luaL_pushresult(&buffer);
        /* if the output is empty  and the input is nil, return nil */
        lua_tolstring(L, -1, &osize);
        if (osize == 0) lua_pushnil(L);
        lua_pushnil(L);
        return 2;
    }
    /* otherwise process the second part */
    last = input + isize;
    while (input < last)
        asize = b64encode(*input++, atom, asize, &buffer);
    luaL_pushresult(&buffer);
    lua_pushlstring(L, (char *) atom, asize);
    return 2;
}

/*-------------------------------------------------------------------------*\
* Incrementally removes the Base64 transfer content encoding from a string
* A, B = b64(C, D)
* A is the encoded version of the largest prefix of C .. D that is
* divisible by 4. B has the remaining bytes of C .. D, *without* encoding.
\*-------------------------------------------------------------------------*/
static int mime_global_unb64(lua_State *L)
{
    UC atom[4];
    size_t isize = 0, asize = 0;
    const UC *input = (const UC *) luaL_optlstring(L, 1, NULL, &isize);
    const UC *last = input + isize;
    luaL_Buffer buffer;
    /* end-of-input blackhole */
    if (!input) {
        lua_pushnil(L);
        lua_pushnil(L);
        return 2;
    }
    /* make sure we don't confuse buffer stuff with arguments */
    lua_settop(L, 2);
    /* process first part of the input */
    luaL_buffinit(L, &buffer);
    while (input < last)
        asize = b64decode(*input++, atom, asize, &buffer);
    input = (const UC *) luaL_optlstring(L, 2, NULL, &isize);
    /* if second is nil, we are done */
    if (!input) {
        size_t osize = 0;
        luaL_pushresult(&buffer);
        /* if the output is empty  and the input is nil, return nil */
        lua_tolstring(L, -1, &osize);
        if (osize == 0) lua_pushnil(L);
        lua_pushnil(L);
        return 2;
    }
    /* otherwise, process the rest of the input */
    last = input + isize;
    while (input < last)
        asize = b64decode(*input++, atom, asize, &buffer);
    luaL_pushresult(&buffer);
    lua_pushlstring(L, (char *) atom, asize);
    return 2;
}

/*-------------------------------------------------------------------------*\
* Quoted-printable encoding scheme
* all (except CRLF in text) can be =XX
* CLRL in not text must be =XX=XX
* 33 through 60 inclusive can be plain
* 62 through 126 inclusive can be plain
* 9 and 32 can be plain, unless in the end of a line, where must be =XX
* encoded lines must be no longer than 76 not counting CRLF
* soft line-break are =CRLF
* To encode one byte, we need to see the next two.
* Worst case is when we see a space, and wonder if a CRLF is comming
\*-------------------------------------------------------------------------*/
#if 0
/*-------------------------------------------------------------------------*\
* Split quoted-printable characters into classes
* Precompute reverse map for encoding
\*-------------------------------------------------------------------------*/
static void qpsetup(UC *cl, UC *unbase)
{

    int i;
    for (i = 0; i < 256; i++) cl[i] = QP_QUOTED;
    for (i = 33; i <= 60; i++) cl[i] = QP_PLAIN;
    for (i = 62; i <= 126; i++) cl[i] = QP_PLAIN;
    cl['\t'] = QP_IF_LAST;
    cl[' '] = QP_IF_LAST;
    cl['\r'] = QP_CR;
    for (i = 0; i < 256; i++) unbase[i] = 255;
    unbase['0'] = 0; unbase['1'] = 1; unbase['2'] = 2;
    unbase['3'] = 3; unbase['4'] = 4; unbase['5'] = 5;
    unbase['6'] = 6; unbase['7'] = 7; unbase['8'] = 8;
    unbase['9'] = 9; unbase['A'] = 10; unbase['a'] = 10;
    unbase['B'] = 11; unbase['b'] = 11; unbase['C'] = 12;
    unbase['c'] = 12; unbase['D'] = 13; unbase['d'] = 13;
    unbase['E'] = 14; unbase['e'] = 14; unbase['F'] = 15;
    unbase['f'] = 15;

printf("static UC qpclass[] = {");
    for (int i = 0; i < 256; i++) {
        if (i % 6 == 0) {
            printf("\n    ");
        }
        switch(cl[i]) {
            case QP_QUOTED:
                printf("QP_QUOTED, ");
                break;
            case QP_PLAIN:
                printf("QP_PLAIN, ");
                break;
            case QP_CR:
                printf("QP_CR, ");
                break;
            case QP_IF_LAST:
                printf("QP_IF_LAST, ");
                break;
        }
    }
printf("\n};\n");

printf("static const UC qpunbase[] = {");
    for (int i = 0; i < 256; i++) {
        int c = qpunbase[i];
        printf("%d, ", c);
    }
printf("\";\n");
}
#endif

/*-------------------------------------------------------------------------*\
* Output one character in form =XX
\*-------------------------------------------------------------------------*/
static void qpquote(UC c, luaL_Buffer *buffer)
{
    luaL_addchar(buffer, '=');
    luaL_addchar(buffer, qpbase[c >> 4]);
    luaL_addchar(buffer, qpbase[c & 0x0F]);
}

/*-------------------------------------------------------------------------*\
* Accumulate characters until we are sure about how to deal with them.
* Once we are sure, output to the buffer, in the correct form.
\*-------------------------------------------------------------------------*/
static size_t qpencode(UC c, UC *input, size_t size,
        const char *marker, luaL_Buffer *buffer)
{
    input[size++] = c;
    /* deal with all characters we can have */
    while (size > 0) {
        switch (qpclass[input[0]]) {
            /* might be the CR of a CRLF sequence */
            case QP_CR:
                if (size < 2) return size;
                if (input[1] == '\n') {
                    luaL_addstring(buffer, marker);
                    return 0;
                } else qpquote(input[0], buffer);
                break;
            /* might be a space and that has to be quoted if last in line */
            case QP_IF_LAST:
                if (size < 3) return size;
                /* if it is the last, quote it and we are done */
                if (input[1] == '\r' && input[2] == '\n') {
                    qpquote(input[0], buffer);
                    luaL_addstring(buffer, marker);
                    return 0;
                } else luaL_addchar(buffer, input[0]);
                break;
                /* might have to be quoted always */
            case QP_QUOTED:
                qpquote(input[0], buffer);
                break;
                /* might never have to be quoted */
            default:
                luaL_addchar(buffer, input[0]);
                break;
        }
        input[0] = input[1]; input[1] = input[2];
        size--;
    }
    return 0;
}

/*-------------------------------------------------------------------------*\
* Deal with the final characters
\*-------------------------------------------------------------------------*/
static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer)
{
    size_t i;
    for (i = 0; i < size; i++) {
        if (qpclass[input[i]] == QP_PLAIN) luaL_addchar(buffer, input[i]);
        else qpquote(input[i], buffer);
    }
    if (size > 0) luaL_addstring(buffer, EQCRLF);
    return 0;
}

/*-------------------------------------------------------------------------*\
* Incrementally converts a string to quoted-printable
* A, B = qp(C, D, marker)
* Marker is the text to be used to replace CRLF sequences found in A.
* A is the encoded version of the largest prefix of C .. D that
* can be encoded without doubts.
* B has the remaining bytes of C .. D, *without* encoding.
\*-------------------------------------------------------------------------*/
static int mime_global_qp(lua_State *L)
{
    size_t asize = 0, isize = 0;
    UC atom[3];
    const UC *input = (const UC *) luaL_optlstring(L, 1, NULL, &isize);
    const UC *last = input + isize;
    const char *marker = luaL_optstring(L, 3, CRLF);
    luaL_Buffer buffer;
    /* end-of-input blackhole */
    if (!input) {
        lua_pushnil(L);
        lua_pushnil(L);
        return 2;
    }
    /* make sure we don't confuse buffer stuff with arguments */
    lua_settop(L, 3);
    /* process first part of input */
    luaL_buffinit(L, &buffer);
    while (input < last)
        asize = qpencode(*input++, atom, asize, marker, &buffer);
    input = (const UC *) luaL_optlstring(L, 2, NULL, &isize);
    /* if second part is nil, we are done */
    if (!input) {
        asize = qppad(atom, asize, &buffer);
        luaL_pushresult(&buffer);
        if (!(*lua_tostring(L, -1))) lua_pushnil(L);
        lua_pushnil(L);
        return 2;
    }
    /* otherwise process rest of input */
    last = input + isize;
    while (input < last)
        asize = qpencode(*input++, atom, asize, marker, &buffer);
    luaL_pushresult(&buffer);
    lua_pushlstring(L, (char *) atom, asize);
    return 2;
}

/*-------------------------------------------------------------------------*\
* Accumulate characters until we are sure about how to deal with them.
* Once we are sure, output the to the buffer, in the correct form.
\*-------------------------------------------------------------------------*/
static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer) {
    int d;
    input[size++] = c;
    /* deal with all characters we can deal */
    switch (input[0]) {
        /* if we have an escape character */
        case '=':
            if (size < 3) return size;
            /* eliminate soft line break */
            if (input[1] == '\r' && input[2] == '\n') return 0;
            /* decode quoted representation */
            c = qpunbase[input[1]]; d = qpunbase[input[2]];
            /* if it is an invalid, do not decode */
            if (c > 15 || d > 15) luaL_addlstring(buffer, (char *)input, 3);
            else luaL_addchar(buffer, (char) ((c << 4) + d));
            return 0;
        case '\r':
            if (size < 2) return size;
            if (input[1] == '\n') luaL_addlstring(buffer, (char *)input, 2);
            return 0;
        default:
            if (input[0] == '\t' || (input[0] > 31 && input[0] < 127))
                luaL_addchar(buffer, input[0]);
            return 0;
    }
}

/*-------------------------------------------------------------------------*\
* Incrementally decodes a string in quoted-printable
* A, B = qp(C, D)
* A is the decoded version of the largest prefix of C .. D that
* can be decoded without doubts.
* B has the remaining bytes of C .. D, *without* decoding.
\*-------------------------------------------------------------------------*/
static int mime_global_unqp(lua_State *L)
{
    size_t asize = 0, isize = 0;
    UC atom[3];
    const UC *input = (const UC *) luaL_optlstring(L, 1, NULL, &isize);
    const UC *last = input + isize;
    luaL_Buffer buffer;
    /* end-of-input blackhole */
    if (!input) {
        lua_pushnil(L);
        lua_pushnil(L);
        return 2;
    }
    /* make sure we don't confuse buffer stuff with arguments */
    lua_settop(L, 2);
    /* process first part of input */
    luaL_buffinit(L, &buffer);
    while (input < last)
        asize = qpdecode(*input++, atom, asize, &buffer);
    input = (const UC *) luaL_optlstring(L, 2, NULL, &isize);
    /* if second part is nil, we are done */
    if (!input) {
        luaL_pushresult(&buffer);
        if (!(*lua_tostring(L, -1))) lua_pushnil(L);
        lua_pushnil(L);
        return 2;
    }
    /* otherwise process rest of input */
    last = input + isize;
    while (input < last)
        asize = qpdecode(*input++, atom, asize, &buffer);
    luaL_pushresult(&buffer);
    lua_pushlstring(L, (char *) atom, asize);
    return 2;
}

/*-------------------------------------------------------------------------*\
* Incrementally breaks a quoted-printed string into lines
* A, n = qpwrp(l, B, length)
* A is a copy of B, broken into lines of at most 'length' bytes.
* 'l' is how many bytes are left for the first line of B.
* 'n' is the number of bytes left in the last line of A.
* There are two complications: lines can't be broken in the middle
* of an encoded =XX, and there might be line breaks already
\*-------------------------------------------------------------------------*/
static int mime_global_qpwrp(lua_State *L)
{
    size_t size = 0;
    int left = (int) luaL_checknumber(L, 1);
    const UC *input = (const UC *) luaL_optlstring(L, 2, NULL, &size);
    const UC *last = input + size;
    int length = (int) luaL_optnumber(L, 3, 76);
    luaL_Buffer buffer;
    /* end-of-input blackhole */
    if (!input) {
        if (left < length) lua_pushstring(L, EQCRLF);
        else lua_pushnil(L);
        lua_pushnumber(L, length);
        return 2;
    }
    /* process all input */
    luaL_buffinit(L, &buffer);
    while (input < last) {
        switch (*input) {
            case '\r':
                break;
            case '\n':
                left = length;
                luaL_addstring(&buffer, CRLF);
                break;
            case '=':
                if (left <= 3) {
                    left = length;
                    luaL_addstring(&buffer, EQCRLF);
                }
                luaL_addchar(&buffer, *input);
                left--;
                break;
            default:
                if (left <= 1) {
                    left = length;
                    luaL_addstring(&buffer, EQCRLF);
                }
                luaL_addchar(&buffer, *input);
                left--;
                break;
        }
        input++;
    }
    luaL_pushresult(&buffer);
    lua_pushnumber(L, left);
    return 2;
}

/*-------------------------------------------------------------------------*\
* Here is what we do: \n, and \r are considered candidates for line
* break. We issue *one* new line marker if any of them is seen alone, or
* followed by a different one. That is, \n\n and \r\r will issue two
* end of line markers each, but \r\n, \n\r etc will only issue *one*
* marker.  This covers Mac OS, Mac OS X, VMS, Unix and DOS, as well as
* probably other more obscure conventions.
*
* c is the current character being processed
* last is the previous character
\*-------------------------------------------------------------------------*/
#define eolcandidate(c) (c == '\r' || c == '\n')
static int eolprocess(int c, int last, const char *marker,
        luaL_Buffer *buffer)
{
    if (eolcandidate(c)) {
        if (eolcandidate(last)) {
            if (c == last) luaL_addstring(buffer, marker);
            return 0;
        } else {
            luaL_addstring(buffer, marker);
            return c;
        }
    } else {
        luaL_addchar(buffer, (char) c);
        return 0;
    }
}

/*-------------------------------------------------------------------------*\
* Converts a string to uniform EOL convention.
* A, n = eol(o, B, marker)
* A is the converted version of the largest prefix of B that can be
* converted unambiguously. 'o' is the context returned by the previous
* call. 'n' is the new context.
\*-------------------------------------------------------------------------*/
static int mime_global_eol(lua_State *L)
{
    int ctx = (int) luaL_checkinteger(L, 1);
    size_t isize = 0;
    const char *input = luaL_optlstring(L, 2, NULL, &isize);
    const char *last = input + isize;
    const char *marker = luaL_optstring(L, 3, CRLF);
    luaL_Buffer buffer;
    luaL_buffinit(L, &buffer);
    /* end of input blackhole */
    if (!input) {
       lua_pushnil(L);
       lua_pushnumber(L, 0);
       return 2;
    }
    /* process all input */
    while (input < last)
        ctx = eolprocess(*input++, ctx, marker, &buffer);
    luaL_pushresult(&buffer);
    lua_pushnumber(L, ctx);
    return 2;
}

/*-------------------------------------------------------------------------*\
* Takes one byte and stuff it if needed.
\*-------------------------------------------------------------------------*/
static size_t dot(int c, size_t state, luaL_Buffer *buffer)
{
    luaL_addchar(buffer, (char) c);
    switch (c) {
        case '\r':
            return 1;
        case '\n':
            return (state == 1)? 2: 0;
        case '.':
            if (state == 2)
                luaL_addchar(buffer, '.');
            /* Falls through. */
        default:
            return 0;
    }
}

/*-------------------------------------------------------------------------*\
* Incrementally applies smtp stuffing to a string
* A, n = dot(l, D)
\*-------------------------------------------------------------------------*/
static int mime_global_dot(lua_State *L)
{
    size_t isize = 0, state = (size_t) luaL_checknumber(L, 1);
    const char *input = luaL_optlstring(L, 2, NULL, &isize);
    const char *last = input + isize;
    luaL_Buffer buffer;
    /* end-of-input blackhole */
    if (!input) {
        lua_pushnil(L);
        lua_pushnumber(L, 2);
        return 2;
    }
    /* process all input */
    luaL_buffinit(L, &buffer);
    while (input < last)
        state = dot(*input++, state, &buffer);
    luaL_pushresult(&buffer);
    lua_pushnumber(L, (lua_Number) state);
    return 2;
}