diff --git a/src/lua/lauxlib.c b/src/lua/lauxlib.c
index 94835ef9..c71f9418 100644
--- a/src/lua/lauxlib.c
+++ b/src/lua/lauxlib.c
@@ -1094,6 +1094,11 @@ LUALIB_API lua_State *luaL_newstate (void) {
 }
 
 
+LUALIB_API void luaL_setoutput (lua_State *L, FILE *output) {
+  lua_setoutput(L, output);
+}
+
+
 LUALIB_API void luaL_checkversion_ (lua_State *L, lua_Number ver, size_t sz) {
   lua_Number v = lua_version(L);
   if (sz != LUAL_NUMSIZES)  /* check numeric types */
diff --git a/src/lua/lauxlib.h b/src/lua/lauxlib.h
index 72f70e7d..53753f7c 100644
--- a/src/lua/lauxlib.h
+++ b/src/lua/lauxlib.h
@@ -100,6 +100,8 @@ LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s);
 
 LUALIB_API lua_State *(luaL_newstate) (void);
 
+LUALIB_API void (luaL_setoutput) (lua_State *L, FILE *output);
+
 LUALIB_API lua_Integer (luaL_len) (lua_State *L, int idx);
 
 LUALIB_API void luaL_addgsub (luaL_Buffer *b, const char *s,
@@ -263,6 +265,9 @@ typedef struct luaL_Stream {
         (fprintf(stderr, (s), (p)), fflush(stderr))
 #endif
 
+#define lua_writestringout(s,l,ls)  fwrite((s), sizeof(char), (l), ls->output)
+#define lua_writelineout(ls)  (lua_writestringout("\n", 1, ls), fflush(ls->output))
+
 /* }================================================================== */
 
 
diff --git a/src/lua/lbaselib.c b/src/lua/lbaselib.c
index 83ad306d..91fadaf9 100644
--- a/src/lua/lbaselib.c
+++ b/src/lua/lbaselib.c
@@ -19,6 +19,7 @@
 
 #include "lauxlib.h"
 #include "lualib.h"
+#include "lstate.h"
 
 
 static int luaB_print (lua_State *L) {
@@ -28,11 +29,11 @@ static int luaB_print (lua_State *L) {
     size_t l;
     const char *s = luaL_tolstring(L, i, &l);  /* convert it to string */
     if (i > 1)  /* not the first element? */
-      lua_writestring("\t", 1);  /* add a tab before it */
-    lua_writestring(s, l);  /* print it */
+      lua_writestringout("\t", 1, L);  /* add a tab before it */
+    lua_writestringout(s, l, L);  /* print it */
     lua_pop(L, 1);  /* pop result */
   }
-  lua_writeline();
+  lua_writelineout(L);
   return 0;
 }
 
diff --git a/src/lua/llex.c b/src/lua/llex.c
index e9915178..463261a7 100644
--- a/src/lua/llex.c
+++ b/src/lua/llex.c
@@ -44,7 +44,8 @@ static const char *const luaX_tokens [] = {
     "return", "then", "true", "until", "while",
     "//", "..", "...", "==", ">=", "<=", "~=",
     "<<", ">>", "::", "<eof>",
-    "<number>", "<integer>", "<name>", "<string>"
+    "<number>", "<integer>", "<name>", "<string>",
+    "!="
 };
 
 
@@ -510,6 +511,11 @@ static int llex (LexState *ls, SemInfo *seminfo) {
         if (check_next1(ls, '=')) return TK_NE;  /* '~=' */
         else return '~';
       }
+      case '!': {
+        next(ls);
+        if (ls->current != '=') return '!';
+        else { next(ls); return TK_NE2; }
+      }
       case ':': {
         next(ls);
         if (check_next1(ls, ':')) return TK_DBCOLON;  /* '::' */
diff --git a/src/lua/llex.h b/src/lua/llex.h
index 389d2f86..e352cd39 100644
--- a/src/lua/llex.h
+++ b/src/lua/llex.h
@@ -39,7 +39,8 @@ enum RESERVED {
   TK_IDIV, TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE,
   TK_SHL, TK_SHR,
   TK_DBCOLON, TK_EOS,
-  TK_FLT, TK_INT, TK_NAME, TK_STRING
+  TK_FLT, TK_INT, TK_NAME, TK_STRING,
+  TK_NE2
 };
 
 /* number of reserved words */
diff --git a/src/lua/lparser.c b/src/lua/lparser.c
index 284ef1f0..a2fefb3b 100644
--- a/src/lua/lparser.c
+++ b/src/lua/lparser.c
@@ -1207,6 +1207,7 @@ static BinOpr getbinopr (int op) {
     case TK_SHR: return OPR_SHR;
     case TK_CONCAT: return OPR_CONCAT;
     case TK_NE: return OPR_NE;
+    case TK_NE2: return OPR_NE;
     case TK_EQ: return OPR_EQ;
     case '<': return OPR_LT;
     case TK_LE: return OPR_LE;
@@ -1353,6 +1354,77 @@ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) {
   }
 }
 
+
+static void unfreereg (FuncState *fs, int reg) {
+  /* Needs to match freereg() in lcode.c */
+  if (reg >= luaY_nvarstack(fs)) {
+    fs->freereg++;
+  }
+}
+
+
+static void append_assignment (LexState *ls, struct LHS_assign *lh) {
+  FuncState * fs=ls->fs;
+  TString *appendfunc_name;
+  expdesc appendfunc;
+  expdesc var;
+  expdesc value;
+  int base;
+
+  luaX_next(ls);
+
+  checknext(ls, '=');
+
+  /* Push tup_append_assignment onto the stack */
+  /* Note: copied from function call suffixedexp -> primaryexp -> singlevar */
+  appendfunc_name = luaS_new(ls->L, "tup_append_assignment");
+  singlevaraux(fs, appendfunc_name, &appendfunc, 1);
+  if (appendfunc.k == VVOID) {
+    /* If tup_append_assignment isn't global, then check _ENV/locals
+     * Note: reuse appendfunc to reference _ENV temporarily
+     */
+    expdesc key;
+    /* Locate _ENV and make it an upvalue if necessary */
+    singlevaraux(fs, ls->envn, &appendfunc, 1);
+    lua_assert(appendfunc.k == VLOCAL || appendfunc.k == VUPVAL);
+    codestring(&key, appendfunc_name);  /* Make func_name a constant */
+    luaK_indexed(fs, &appendfunc, &key);  /* env[varname] */
+  }
+  luaK_exp2nextreg(fs, &appendfunc);
+
+  /* Push assignment lhs as first function argument */
+  var = lh->v; /* exp2nextreg disables the expr somehow, so copy it first */
+  if (var.k == VINDEXI || var.k == VINDEXSTR) {
+      unfreereg(fs, var.u.ind.t);
+  }
+  if (var.k == VINDEXED) {
+    /* exp2nextreg if INDEXED will try to pop/reuse the source table and
+     * index stack positions.
+     * Increase freeregs to prevent that.
+     */
+    unfreereg(fs, var.u.ind.t);
+    unfreereg(fs, var.u.ind.idx);
+  }
+  luaK_exp2nextreg(fs, &var);
+
+  /* Push original rhs as second function argument */
+  expr(ls, &value);
+  luaK_exp2nextreg(fs, &value);
+
+  /* Call the function */
+  /* Note: copied from funcargs */
+  lua_assert(appendfunc.k == VNONRELOC);
+  base = appendfunc.u.info;  /* base register for call */
+  init_exp(&appendfunc, VCALL,
+	   luaK_codeABC(fs, OP_CALL, base, fs->freereg - (base + 1) + 1, 2));
+  fs->freereg = base + 1;  /* call removes function and arguments and leaves
+			      (unless changed) one result */
+
+  /* Store the call result */
+  luaK_storevar(fs, &lh->v, &appendfunc);
+}
+
+
 /*
 ** Parse and compile a multiple assignment. The first "variable"
 ** (a 'suffixedexp') was already read by the caller.
@@ -1376,6 +1448,13 @@ static void restassign (LexState *ls, struct LHS_assign *lh, int nvars) {
   }
   else {  /* restassign -> '=' explist */
     int nexps;
+
+    if(nvars==1) {
+      if(ls->t.token == '+') {
+        append_assignment(ls, lh);
+        return;
+      }
+    }
     checknext(ls, '=');
     nexps = explist(ls, &e);
     if (nexps != nvars)
@@ -1786,7 +1865,7 @@ static void exprstat (LexState *ls) {
   FuncState *fs = ls->fs;
   struct LHS_assign v;
   suffixedexp(ls, &v.v);
-  if (ls->t.token == '=' || ls->t.token == ',') { /* stat -> assignment ? */
+  if (ls->t.token == '=' || ls->t.token == ',' || ls->t.token == '+') { /* stat -> assignment ? */
     v.prev = NULL;
     restassign(ls, &v, 1);
   }
diff --git a/src/lua/lstate.c b/src/lua/lstate.c
index c5e3b437..7fe59405 100644
--- a/src/lua/lstate.c
+++ b/src/lua/lstate.c
@@ -403,10 +403,16 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
     close_state(L);
     L = NULL;
   }
+  L->output = stdout;
   return L;
 }
 
 
+LUA_API void lua_setoutput (lua_State *L, FILE *output) {
+  L->output = output;
+}
+
+
 LUA_API void lua_close (lua_State *L) {
   lua_lock(L);
   L = G(L)->mainthread;  /* only the main thread can be closed */
diff --git a/src/lua/lstate.h b/src/lua/lstate.h
index c1283bb6..ce7bfd95 100644
--- a/src/lua/lstate.h
+++ b/src/lua/lstate.h
@@ -12,6 +12,7 @@
 #include "lobject.h"
 #include "ltm.h"
 #include "lzio.h"
+#include <stdio.h>
 
 
 /*
@@ -324,6 +325,7 @@ struct lua_State {
   int basehookcount;
   int hookcount;
   volatile l_signalT hookmask;
+  FILE *output;
 };
 
 
diff --git a/src/lua/lua.h b/src/lua/lua.h
index 820535b9..eeee908e 100644
--- a/src/lua/lua.h
+++ b/src/lua/lua.h
@@ -9,6 +9,7 @@
 #ifndef lua_h
 #define lua_h
 
+#include <stdio.h>
 #include <stdarg.h>
 #include <stddef.h>
 
@@ -151,6 +152,7 @@ extern const char lua_ident[];
 ** state manipulation
 */
 LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud);
+LUA_API void       (lua_setoutput) (lua_State *L, FILE *output);
 LUA_API void       (lua_close) (lua_State *L);
 LUA_API lua_State *(lua_newthread) (lua_State *L);
 LUA_API int        (lua_resetthread) (lua_State *L);
