diff --git a/build.sh b/build.sh
index 6eeeedeba63234a17403f4e5e1b6df7cdf06b574..018f6773089b3a7453ba94fc3fac1c2035815bee 100755
--- a/build.sh
+++ b/build.sh
@@ -21,7 +21,7 @@
 # Options:
 #      --jit       : also build luajittex
 #      --make      : only make, no make distclean; configure
-#      --parallel  : make -j 2 -l 3.0
+#      --parallel  : make -j 8 -l 8.0
 #      --nostrip   : do not strip binary
 #      --warnings= : enable compiler warnings
 #      --mingw     : crosscompile for mingw32 from x86_64linux
@@ -172,9 +172,15 @@ then
     * ) echo "ERROR: architecture $ARCH is not supported"; exit 1;;
   esac
   B=build-$ARCH
+  if [ "x$CONFHOST" != "x" ]
+    then
+    B="build-$CONFHOST"
+    B=`printf "$B"| sed 's/--host=//'`
+  fi
   CFLAGS="-arch $ARCH -g -O2 $CFLAGS"
   CXXFLAGS="-arch $ARCH -g -O2 $CXXFLAGS"
   LDFLAGS="-arch $ARCH $LDFLAGS" 
+  STRIP="${CONFHOST#--host=}-strip -u -r -A -n"
   export CFLAGS CXXFLAGS LDFLAGS
 fi
 
diff --git a/manual/luatex-introduction.tex b/manual/luatex-introduction.tex
index 8ab8b4463dfa4a3855d77a4cfedc944f707de4b6..e6025cb36ba6e92e01671eb8d76fe0924f32cfbf 100644
--- a/manual/luatex-introduction.tex
+++ b/manual/luatex-introduction.tex
@@ -98,6 +98,14 @@ code in \TEX\ engines (especially code that is not needed any longer).
     \stopitem
 \stopitemize
 
+We try to keep upcoming versions compatible but intermediate releases can contain
+experimental features. A general rule is that versions that end up on \TEX live
+and|/|or are released around \CONTEXT\ meetings are stable. Future versions will
+probably become a bit leaner and meaner. Some libraries might become external as
+we don't want to bloat the binary and also don't want to add more hard coded
+solutions. After all, with \LUA\ you can extend the core functionality. The less
+dependencies, the better.
+
 The \TEXLIVE\ version is to be considered the current stable version. Any version
 between the yearly \TEXLIVE\ releases are to be considered beta. The beta
 releases are normally available via the \CONTEXT\ distribution channels (the
diff --git a/manual/luatex-nodes.tex b/manual/luatex-nodes.tex
index b8547b1709091032d6dc21aea2d93d8b3d0183bd..cabd000c700235f21a3772459c16b80f27e60a46 100644
--- a/manual/luatex-nodes.tex
+++ b/manual/luatex-nodes.tex
@@ -1799,7 +1799,7 @@ if next then
 end
 \stoptyping
 
-If performance matters you can use an function instead:
+Some accessors are used frequently and for these we provide more efficient helpers:
 
 \starttabulate[|T|p|]
 \NC getnext    \NC parsing nodelist always involves this one \NC \NR
@@ -1813,8 +1813,7 @@ If performance matters you can use an function instead:
                    (unexpanded) glyph as well as glue (its spec is looked at) and unset nodes\NC \NR
 \NC getdisc    \NC returns the \type {pre}, \type {post} and \type {replace} fields and
                    optionally when true is passed also the tail fields. \NC \NR
-\NC getlist    \NC we often parse nested lists so this is a convenient one too
-                   (only works for hlist and vlist!) \NC \NR
+\NC getlist    \NC we often parse nested lists so this is a convenient one too \NC \NR
 \NC getleader  \NC comparable to list, seldom used in \TEX\ (but needs frequent consulting
                    like lists; leaders could have been made a dedicated node type) \NC \NR
 \NC getfield   \NC generic getter, sufficient for the rest (other field names are
@@ -1822,18 +1821,26 @@ If performance matters you can use an function instead:
 \NC getbox     \NC gets the given box (a list node) \NC \NR
 \stoptabulate
 
-The direct variants also have setters, where the discretionary setter takes three
-(optional) arguments plus an optional fourth indicating the subtype. An additional
-setter is \type {setlink} which will link two or more nodes. It ignores nil nodes,
-doesn't slide (for good reason), and returns the head of the first valid node.
-
-It doesn't make sense to add getters for all fields, also because some are not
-unique to one node type. Profiling demonstrated that these fields can get
-accesses way more times than other fields. Even in complex documents, many node
-and fields types never get seen, or seen only a few times. Most functions in the
-\type {node} namespace have a companion in \type {node.direct}, but of course not
-the ones that don't deal with nodes themselves. The following table summarized
-this:
+In the direct namespace there are more such helpers and most of them are
+accompanied by setters. The getters and setters are clever enough to see what
+node is meant. We don't deal with whatsit nodes: their fields are always accessed
+by name. It doesn't make sense to add getters for all fields, we just identifier
+the most likely candidates. In complex documents, many node and fields types
+never get seen, or seen only a few times, but for instance glyphs are candidates
+for such optimization. The \type {node.direct} interface has some more helpers.
+\footnote {We can define the helpers in the node namespace with \type {getfield}
+which is about as efficient, so at some point we might provide that as module.}
+
+The \type {setdisc} helper takes three (optional) arguments plus an optional
+fourth indicating the subtype. Its \type {getdisc} takes an optional boolean;
+when its value is \type {true} the tail nodes will also be returned. The \type
+{setfont} helper takes an optional second argument, it being the character. The
+directmode setter \type {setlink} takes a list of nodes and will link them,
+thereby ignoring \type {nil} entries. The first valid node is returned (beware:
+for good reason it assumes single nodes). For rarely used fields no helpers are
+provided and there are a few that probably are used seldom too but were added for
+consistency. You can of course always define additional accessor using \type
+{getfield} and \type {setfield} with little overhead.
 
 % \startcolumns[balance=yes]
 
@@ -1843,14 +1850,13 @@ this:
 \HL
 \NC \bf function                 \NC \bf node \NC \bf direct \NC \NR
 \HL
+%NC \type {do_ligature_n}        \NC \yes \NC \yes  \NC \NR % was never documented and experimental
 \NC \type {check_discretionaries}\NC \yes \NC \yes  \NC \NR
 \NC \type {copy_list}            \NC \yes \NC \yes  \NC \NR
 \NC \type {copy}                 \NC \yes \NC \yes  \NC \NR
 \NC \type {count}                \NC \yes \NC \yes  \NC \NR
 \NC \type {current_attr}         \NC \yes \NC \yes  \NC \NR
 \NC \type {dimensions}           \NC \yes \NC \yes  \NC \NR
-\NC \type {rangedimensions}      \NC \yes \NC \yes  \NC \NR
-%NC \type {do_ligature_n}        \NC \yes \NC \yes  \NC \NR % was never documented and experimental
 \NC \type {effective_glue}       \NC \yes \NC \yes  \NC \NR
 \NC \type {end_of_math}          \NC \yes \NC \yes  \NC \NR
 \NC \type {family_font}          \NC \yes \NC \nop  \NC \NR
@@ -1861,19 +1867,35 @@ this:
 \NC \type {flush_node}           \NC \yes \NC \yes  \NC \NR
 \NC \type {free}                 \NC \yes \NC \yes  \NC \NR
 \NC \type {get_attribute}        \NC \yes \NC \yes  \NC \NR
+\NC \type {getattributelist}     \NC \nop \NC \yes  \NC \NR
 \NC \type {getboth}              \NC \yes \NC \yes  \NC \NR
 \NC \type {getbox}               \NC \nop \NC \yes  \NC \NR
 \NC \type {getchar}              \NC \yes \NC \yes  \NC \NR
+\NC \type {getcomponents}        \NC \nop \NC \yes  \NC \NR
+\NC \type {getdepth}             \NC \nop \NC \yes  \NC \NR
+\NC \type {getdir}               \NC \nop \NC \yes  \NC \NR
 \NC \type {getdisc}              \NC \yes \NC \yes  \NC \NR
 \NC \type {getfield}             \NC \yes \NC \yes  \NC \NR
 \NC \type {getfont}              \NC \yes \NC \yes  \NC \NR
 \NC \type {getglue}              \NC \yes \NC \yes  \NC \NR
+\NC \type {getheight}            \NC \yes \NC \yes  \NC \NR
 \NC \type {getid}                \NC \yes \NC \yes  \NC \NR
+\NC \type {getkern}              \NC \nop \NC \yes  \NC \NR
+\NC \type {getlang}              \NC \nop \NC \yes  \NC \NR
 \NC \type {getleader}            \NC \yes \NC \yes  \NC \NR
 \NC \type {getlist}              \NC \yes \NC \yes  \NC \NR
 \NC \type {getnext}              \NC \yes \NC \yes  \NC \NR
+\NC \type {getnucleus}           \NC \nop \NC \yes  \NC \NR
+\NC \type {getoffsets}           \NC \nop \NC \yes  \NC \NR
+\NC \type {getpenalty}           \NC \nop \NC \yes  \NC \NR
 \NC \type {getprev}              \NC \yes \NC \yes  \NC \NR
+\NC \type {getproperty}          \NC \yes \NC \yes  \NC \NR
+\NC \type {getshift}             \NC \yes \NC \nop  \NC \NR
+\NC \type {getwidth}             \NC \yes \NC \nop  \NC \NR
+\NC \type {getwhd}               \NC \yes \NC \yes  \NC \NR
+\NC \type {getsub}               \NC \yes \NC \nop  \NC \NR
 \NC \type {getsubtype}           \NC \yes \NC \yes  \NC \NR
+\NC \type {getsup}               \NC \yes \NC \nop  \NC \NR
 \NC \type {has_attribute}        \NC \yes \NC \yes  \NC \NR
 \NC \type {has_field}            \NC \yes \NC \yes  \NC \NR
 \NC \type {has_glyph}            \NC \yes \NC \yes  \NC \NR
@@ -1897,18 +1919,19 @@ this:
 \NC \type {protect_glyphs}       \NC \yes \NC \yes  \NC \NR
 \NC \type {protect_glyph}        \NC \yes \NC \yes  \NC \NR
 \NC \type {protrusion_skippable} \NC \yes \NC \yes  \NC \NR
+\NC \type {rangedimensions}      \NC \yes \NC \yes  \NC \NR
 \NC \type {remove}               \NC \yes \NC \yes  \NC \NR
 \NC \type {set_attribute}        \NC \yes \NC \yes  \NC \NR
 \NC \type {setboth}              \NC \yes \NC \yes  \NC \NR
 \NC \type {setbox}               \NC \nop \NC \yes  \NC \NR
 \NC \type {setchar}              \NC \yes \NC \yes  \NC \NR
 \NC \type {setdisc}              \NC \nop \NC \yes  \NC \NR
-\NC \type {setwhd}               \NC \nop \NC \yes  \NC \NR
 \NC \type {setfield}             \NC \yes \NC \yes  \NC \NR
 \NC \type {setglue}              \NC \yes \NC \yes  \NC \NR
 \NC \type {setlink}              \NC \yes \NC \yes  \NC \NR
 \NC \type {setnext}              \NC \yes \NC \yes  \NC \NR
 \NC \type {setprev}              \NC \yes \NC \yes  \NC \NR
+\NC \type {setwhd}               \NC \nop \NC \yes  \NC \NR
 \NC \type {slide}                \NC \yes \NC \yes  \NC \NR
 \NC \type {subtypes}             \NC \yes \NC \nop  \NC \NR
 \NC \type {subtype}              \NC \yes \NC \nop  \NC \NR
diff --git a/manual/luatex.pdf b/manual/luatex.pdf
index 76befeaa229058fdabdf63a57b64d848692aa004..8028cef9c5615e2927712769c61b93f20ee49ef7 100644
Binary files a/manual/luatex.pdf and b/manual/luatex.pdf differ
diff --git a/manual/luatex.tex b/manual/luatex.tex
index 8cf87c47fb6c8975f70dc6cc30228f5056a2c844..bc4a4b31efe4df4fe68ee19ecacf806b805aa816 100644
--- a/manual/luatex.tex
+++ b/manual/luatex.tex
@@ -29,8 +29,8 @@
 \dontcomplain
 
 \startdocument
-  [%status=release,
-   version=1.0.2]
+  [status=intermediate release,
+   version=1.0.3]
 
 \component luatex-titlepage
 
diff --git a/source/texk/web2c/luatexdir/lua/lnodelib.c b/source/texk/web2c/luatexdir/lua/lnodelib.c
index 8a96f328f8bd1146ae2d441c9eda1e29f5d488d3..85def36d640b65a63e4dfb8f65735bbf94d121b6 100644
--- a/source/texk/web2c/luatexdir/lua/lnodelib.c
+++ b/source/texk/web2c/luatexdir/lua/lnodelib.c
@@ -29,23 +29,25 @@
     overhead.
 
     Because the userdata approach has some benefits, we stick to this. We did
-    some experiments with fast access (assuming nodes) and kept some of the code
-    commented here, but eventually settled for the direct approach. For code that
-    is proven to be okay, one can use the direct variants and operate on nodes
-    more directly. Currently these are numbers, but that might become light
-    userdata at one point, so *never* rely on that property. An important aspect
-    is that one cannot mix both methods, although with node.direct.tonode and
-    node.direct.todirect one can cast both representations.
+    some experiments with fast access (assuming nodes), but eventually settled for
+    the direct approach. For code that is proven to be okay, one can use the
+    direct variants and operate on nodes more directly. Currently these are
+    numbers but don't rely on that property; treat them as abstractions. An
+    important aspect    is that one cannot mix both methods, although with
+    node.direct.tonode and node.direct.todirect one can cast representations.
 
     So the advice is: use the indexed approach when possible and investigate the
-    direct one when speed might be an issue. For that reason we also provide the
+    direct one when speed might be an issue. For that reason we also provide some
     get* and set* functions in the top level node namespace. There is a limited set
-    of getters and a generic getfield to complement them.
+    of getters for nodes and a generic getfield to complement them. The direct
+    namespace has a few more.
 
-    Keep in mind that these only make sense when we're calling them millions of
-    times (which happens in font processing for instance). Setters are less important
-    as documents have not that many content related nodes (and setting many thousands
-    of properties is hardly a burden contrary to millions of consultations.)
+    Keep in mind that such speed considerations only make sense when we're accessing
+    nodes millions of times (which happens in font processing for instance). Setters
+    are less important as documents have not that many content related nodes and
+    setting many thousands of properties is hardly a burden contrary to millions of
+    consultations. And with millions, we're talking of tens of millions which is not
+    that common.
 
     Another change is that __index and __newindex are (as expected) exposed to
     users but do no checking. The getfield and setfield functions do check. In
@@ -349,91 +351,50 @@ static int lua_nodelib_id(lua_State * L)
     return 1;
 }
 
-/* node.getid */
-
-static int lua_nodelib_getid(lua_State * L)
-{
-    /* [given-node] [...] */
-    halfword *p = lua_touserdata(L, 1);
-    if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
-        lua_pushnil(L);
-        return 1;
-    }
-    /* [given-node] [mt-given-node] */
-    lua_get_metatablelua(luatex_node);
-    /* [given-node] [mt-given-node] [mt-node] */
-    if (!lua_rawequal(L, -1, -2)) {
-        lua_pushnil(L);
-    } else {
-        lua_pushinteger(L, type(*p));
-    }
-    return 1;
-}
-
-/* node.fast.getid
-
-    static int lua_nodelib_fast_getid(lua_State * L)
-    {
-        halfword *n;
-        n = (halfword *) lua_touserdata(L, 1);
-        lua_pushinteger(L, type(*n));
-        return 1;
-    }
-
-*/
-
 /* node.direct.getid */
 
 static int lua_nodelib_direct_getid(lua_State * L)
 {
     halfword n = lua_tointeger(L, 1);
-    if (n == null) {
-        lua_pushnil(L);
-    } else {
+    if (n) {
         lua_pushinteger(L, type(n));
+    } else {
+        lua_pushnil(L);
     }
     return 1;
 }
 
-/* node.getsubtype */
+    /* node.getid */
 
-static int lua_nodelib_getsubtype(lua_State * L)
-{
-    halfword *p = lua_touserdata(L, 1);
-    if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
-        lua_pushnil(L);
-    } else {
+    static int lua_nodelib_getid(lua_State * L)
+    {
+        /* [given-node] [...] */
+        halfword *p = lua_touserdata(L, 1);
+        if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
+            lua_pushnil(L);
+            return 1;
+        }
+        /* [given-node] [mt-given-node] */
         lua_get_metatablelua(luatex_node);
-        if ( (!lua_rawequal(L, -1, -2)) || (! nodetype_has_subtype(*p))) {
+        /* [given-node] [mt-given-node] [mt-node] */
+        if (!lua_rawequal(L, -1, -2)) {
             lua_pushnil(L);
         } else {
-            lua_pushinteger(L, subtype(*p));
+            lua_pushinteger(L, type(*p));
         }
-    }
-    return 1;
-}
-
-/* node.fast.getsubtype
-
-    static int lua_nodelib_fast_getsubtype(lua_State * L)
-    {
-        halfword *n;
-        n = (halfword *) lua_touserdata(L, 1);
-        lua_pushinteger(L, subtype(*n));
         return 1;
     }
 
-*/
-
 /* node.direct.getsubtype */
+/* node.direct.setsubtype */
 
 static int lua_nodelib_direct_getsubtype(lua_State * L)
 {
     halfword n = lua_tointeger(L, 1);
-    if (n == null) { /* no check, we assume sane use */
-        lua_pushnil(L);
-    } else {
+    if (n) {
         lua_pushinteger(L, subtype(n));
+    } else {
+        lua_pushnil(L);
     }
     return 1;
 }
@@ -441,75 +402,96 @@ static int lua_nodelib_direct_getsubtype(lua_State * L)
 static int lua_nodelib_direct_setsubtype(lua_State * L)
 {
     halfword n = lua_tointeger(L, 1);
-    if ((n != null) && (lua_type(L,2) == LUA_TNUMBER)) {
+    if ((n) && (lua_type(L,2) == LUA_TNUMBER)) {
         subtype(n) = (halfword) lua_tointeger(L, 2);
     }
     return 0;
 }
 
-/* node.getfont */
+    /* node.getsubtype */
+
+    static int lua_nodelib_getsubtype(lua_State * L)
+    {
+        halfword *p = lua_touserdata(L, 1);
+        if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
+            lua_pushnil(L);
+        } else {
+            lua_get_metatablelua(luatex_node);
+            if ( (!lua_rawequal(L, -1, -2)) || (! nodetype_has_subtype(*p))) {
+                lua_pushnil(L);
+            } else {
+                lua_pushinteger(L, subtype(*p));
+            }
+        }
+        return 1;
+    }
+
+/* node.direct.getfont */
+/* node.direct.setfont */
 
-static int lua_nodelib_getfont(lua_State * L)
+static int lua_nodelib_direct_getfont(lua_State * L)
 {
-    halfword *n = lua_touserdata(L, 1);
-    if ( (n == NULL) || (! lua_getmetatable(L,1)) ) {
-        lua_pushnil(L);
-    } else {
-        halfword t = type(*n);
+    halfword n = lua_tointeger(L, 1);
+    if (n != null) {
+        halfword t = type(n);
         if (t == glyph_node) {
-            lua_pushinteger(L, font(*n));
+            lua_pushinteger(L, font(n));
         } else if ((t == math_char_node) || (t == math_text_char_node)) {
-            lua_pushinteger(L, fam_fnt(math_fam(*n), 0));
+            lua_pushinteger(L, fam_fnt(math_fam(n), 0));
         } else {
             lua_pushnil(L);
         }
+    } else {
+        lua_pushnil(L);
     }
     return 1;
 }
 
-/* node.fast.getfont
+static int lua_nodelib_direct_setfont(lua_State * L)
+{
+    halfword n = lua_tointeger(L, 1);
+    if ((n) && type(n) == glyph_node) {
+        font(n) = (halfword) lua_tointeger(L,2);
+        /* optional char */
+        if ((lua_type(L, 3) == LUA_TNUMBER)) {
+            character(n) = (halfword) lua_tointeger(L, 3);
+        }
+    }
+    return 0;
+}
+
+    /* node.getfont */
 
-    static int lua_nodelib_fast_getfont(lua_State * L)
+    static int lua_nodelib_getfont(lua_State * L)
     {
-        halfword *n;
-        n = (halfword *) lua_touserdata(L, 1);
-        if (type(*n) != glyph_node) {
+        halfword *n = lua_touserdata(L, 1);
+        if ((n == NULL) || (! lua_getmetatable(L,1)) ) {
             lua_pushnil(L);
         } else {
-            lua_pushinteger(L, font(*n));
+            halfword t = type(*n);
+            if (t == glyph_node) {
+                lua_pushinteger(L, font(*n));
+            } else if ((t == math_char_node) || (t == math_text_char_node)) {
+                lua_pushinteger(L, fam_fnt(math_fam(*n), 0));
+            } else {
+                lua_pushnil(L);
+            }
         }
         return 1;
     }
 
-*/
-
-/* node.direct.getfont */
-
-/*
-
-static int lua_nodelib_direct_getfont(lua_State * L)
-{
-    halfword n;
-    n = (halfword) lua_tointeger(L, 1);
-    if ((n == null) || (type(n) != glyph_node)) {
-        lua_pushnil(L);
-    } else {
-        lua_pushinteger(L, font(n));
-    }
-    return 1;
-}
-
-*/
+/* node.direct.getchar */
+/* node.direct.setchar */
 
-static int lua_nodelib_direct_getfont(lua_State * L) /* family_font is not yet in manual, what does arg 2 do */
+static int lua_nodelib_direct_getchar(lua_State * L)
 {
     halfword n = lua_tointeger(L, 1);
-    if (n != null) {
+    if (n) {
         halfword t = type(n);
         if (t == glyph_node) {
-            lua_pushinteger(L, font(n));
+            lua_pushinteger(L, character(n));
         } else if ((t == math_char_node) || (t == math_text_char_node)) {
-            lua_pushinteger(L, fam_fnt(math_fam(n), 0));
+            lua_pushinteger(L, math_character(n));
         } else {
             lua_pushnil(L);
         }
@@ -519,75 +501,70 @@ static int lua_nodelib_direct_getfont(lua_State * L) /* family_font is not yet i
     return 1;
 }
 
-/* node.getchar */
-
-static int lua_nodelib_getcharacter(lua_State * L)
+static int lua_nodelib_direct_setchar(lua_State * L)
 {
-    halfword *n = lua_touserdata(L, 1);
-    if ( (n == NULL) || (! lua_getmetatable(L,1)) ) {
-        lua_pushnil(L);
-    } else if (type(*n) == glyph_node) {
-        lua_pushinteger(L, character(*n));
-    } else if ((type(*n) == math_char_node) || (type(*n) == math_text_char_node)) {
-        lua_pushinteger(L, math_character(*n));
+    halfword n = lua_tointeger(L, 1);
+    if ((n) && (lua_type(L, 2) == LUA_TNUMBER)) {
+        halfword t = type(n);
+        if (t == glyph_node) {
+            character(n) = (halfword) lua_tointeger(L, 2);
+        } else if ((t == math_char_node) || (t == math_text_char_node)) {
+            math_character(n) = (halfword) lua_tointeger(L, 2);
+        }
     }
-    return 1;
+    return 0;
 }
 
-/* node.fast.getchar
 
-    static int lua_nodelib_fast_getcharacter(lua_State * L)
+    /* node.getchar */
+
+    static int lua_nodelib_getchar(lua_State * L)
     {
-        halfword *n;
-        n = (halfword *) lua_touserdata(L, 1);
-        if (type(*n) == glyph_node) {
+        halfword *n = lua_touserdata(L, 1);
+        if ( (n == NULL) || (! lua_getmetatable(L,1)) ) {
+            lua_pushnil(L);
+        } else if (type(*n) == glyph_node) {
             lua_pushinteger(L, character(*n));
         } else if ((type(*n) == math_char_node) || (type(*n) == math_text_char_node)) {
             lua_pushinteger(L, math_character(*n));
-        } else {
-            lua_pushnil(L);
         }
         return 1;
     }
 
-*/
-
-/* node.direct.getchar */
+/* node.direct.getcomponents */
+/* node.direct.setcomponents */
 
-static int lua_nodelib_direct_getcharacter(lua_State * L)
+static int lua_nodelib_direct_getcomponents(lua_State * L)
 {
     halfword n = lua_tointeger(L, 1);
-    if (n == null) {
-        lua_pushnil(L);
-    } else if (type(n) == glyph_node) {
-        lua_pushinteger(L, character(n));
-    } else if ((type(n) == math_char_node) || (type(n) == math_text_char_node)) {
-        lua_pushinteger(L, math_character(n));
+    if ((n) && (type(n) == glyph_node)) {
+        lua_pushinteger(L, lig_ptr(n));
     } else {
         lua_pushnil(L);
     }
     return 1;
 }
 
-static int lua_nodelib_direct_getcomponents(lua_State * L)
+static int lua_nodelib_direct_setcomponents(lua_State * L)
 {
     halfword n = lua_tointeger(L, 1);
-    if (n == null) {
-        lua_pushnil(L);
-    } else if (type(n) == glyph_node) {
-        lua_pushinteger(L, lig_ptr(n));
-    } else {
-        lua_pushnil(L);
+    if ((n) && (type(n) == glyph_node)) {
+        if (lua_type(L, 2) == LUA_TNUMBER) {
+            lig_ptr(n) = (halfword) lua_tointeger(L, 2);
+        } else {
+            lig_ptr(n) = null;
+        }
     }
-    return 1;
+    return 0;
 }
 
+/* node.direct.getlang */
+/* node.direct.setlang */
+
 static int lua_nodelib_direct_getlang(lua_State * L)
 {
     halfword n = lua_tointeger(L, 1);
-    if (n == null) {
-        lua_pushnil(L);
-    } else if (type(n) == glyph_node) {
+    if ((n) && (type(n) == glyph_node)) {
         lua_pushinteger(L, char_lang(n));
     } else {
         lua_pushnil(L);
@@ -595,131 +572,388 @@ static int lua_nodelib_direct_getlang(lua_State * L)
     return 1;
 }
 
-static int lua_nodelib_direct_getattributelist(lua_State * L)
+static int lua_nodelib_direct_setlang(lua_State * L)
 {
     halfword n = lua_tointeger(L, 1);
-    if ((n) && nodetype_has_attributes(type(n))) {
-        lua_pushinteger(L, node_attr(n));
-    } else {
-        lua_pushnil(L);
+    if ((n) && (type(n) == glyph_node)) {
+        if (lua_type(L, 2) == LUA_TNUMBER) {
+            set_char_lang(n,lua_tointeger(L, 2));
+        } else {
+            /* nothing */
+        }
     }
-    return 1;
+    return 0;
 }
 
-static int lua_nodelib_direct_getpenalty(lua_State * L)
+/* node.direct.getattributelist */
+/* node.direct.setattributelist */
+
+static int lua_nodelib_direct_getattributelist(lua_State * L)
 {
     halfword n = lua_tointeger(L, 1);
-    if (n == null) {
-        lua_pushnil(L);
-    } else if (type(n) == penalty_node) {
-        lua_pushinteger(L, penalty(n));
-    } else if (type(n) == disc_node) {
-        lua_pushinteger(L, disc_penalty(n));
+    if ((n) && nodetype_has_attributes(type(n))) {
+        lua_pushinteger(L, node_attr(n));
     } else {
         lua_pushnil(L);
     }
     return 1;
 }
 
-static int lua_nodelib_direct_getkern(lua_State * L)
+static int lua_nodelib_direct_setattributelist(lua_State * L)
 {
     halfword n = lua_tointeger(L, 1);
-    if (n == null) {
-        lua_pushnil(L);
-    } else if (type(n) == kern_node || type(n) == margin_kern_node) {
-        lua_pushinteger(L, width(n));
-    } else if (type(n) == math_node) {
-        lua_pushinteger(L, surround(n));
-    } else {
-        lua_pushnil(L);
+    if ((n) && nodetype_has_attributes(type(n))) {
+        if (lua_type(L, 2) == LUA_TNUMBER) {
+            halfword a =lua_tointeger(L, 2);
+            if (type(a) == attribute_list_node) {
+                reassign_attribute(n,a);
+            } else if (nodetype_has_attributes(type(a))) {
+                reassign_attribute(n,node_attr(a));
+            } else {
+                reassign_attribute(n,null);
+            }
+        } else {
+            reassign_attribute(n,null);
+        }
+        return 0;
     }
-    return 1;
+    return 0;
 }
 
-static int lua_nodelib_direct_getdir(lua_State * L)
+/* node.direct.getpenalty */
+/* node.direct.setpenalty */
+
+static int lua_nodelib_direct_getpenalty(lua_State * L)
 {
     halfword n = lua_tointeger(L, 1);
-    if (n == null) {
-        lua_pushnil(L);
-    } else if (type(n) == dir_node) {
-        lua_push_dir_text(L, dir_dir(n));
-    } else if (type(n) == hlist_node || type(n) == vlist_node) {
-        lua_push_dir_par(L, box_dir(n));
-    } else if (type(n) == rule_node) {
-        lua_push_dir_par(L, rule_dir(n));
-    } else if (type(n) == local_par_node) {
-        lua_push_dir_par(L, local_par_dir(n));
+    if (n) {
+        halfword t = type(n);
+        if (t == penalty_node) {
+            lua_pushinteger(L, penalty(n));
+        } else if (t == disc_node) {
+            lua_pushinteger(L, disc_penalty(n));
+        } else {
+            lua_pushnil(L);
+        }
     } else {
         lua_pushnil(L);
     }
     return 1;
 }
 
-static int lua_nodelib_direct_getoffsets(lua_State * L)
+static int lua_nodelib_direct_setpenalty(lua_State * L)
 {
     halfword n = lua_tointeger(L, 1);
-    if (n == null) {
-        lua_pushnil(L);
-    } else if (type(n) == glyph_node) {
-        lua_pushinteger(L, x_displace(n));
-        lua_pushinteger(L, y_displace(n));
-        return 2;
-    } else {
-        lua_pushnil(L);
+    if (n) {
+        halfword t = type(n);
+        if (t == penalty_node) {
+            if (lua_type(L, 2) == LUA_TNUMBER) {
+                penalty(n) = (halfword) lua_tointeger(L, 2);
+            } else {
+                penalty(n) = 0;
+            }
+        } else if (t == disc_node) {
+            if (lua_type(L, 2) == LUA_TNUMBER) {
+                disc_penalty(n) = (halfword) lua_tointeger(L, 2);
+            } else {
+                penalty(n) = 0;
+            }
+        }
     }
-    return 1;
+    return 0;
 }
 
-/* node.getdisc */
+/* node.direct.getnucleus */
+/* node.direct.getsub */
+/* node.direct.getsup */
 
-static int lua_nodelib_direct_getdiscretionary(lua_State * L)
+static int lua_nodelib_direct_getnucleus(lua_State * L)
 {
     halfword n = lua_tointeger(L, 1);
-    if (n != null) {
-        if (type(n) == disc_node) {
-            nodelib_pushdirect_or_nil(vlink(pre_break(n)));
-            nodelib_pushdirect_or_nil(vlink(post_break(n)));
-            nodelib_pushdirect_or_nil(vlink(no_break(n)));
-            if (lua_isboolean(L, 2)) {
-                if (lua_toboolean(L, 2)) {
-                    nodelib_pushdirect_or_nil(tlink(pre_break(n)));
-                    nodelib_pushdirect_or_nil(tlink(post_break(n)));
-                    nodelib_pushdirect_or_nil(tlink(no_break(n)));
-                    return 6;
-                }
-            }
-            return 3;
+    if (n) {
+        halfword t = type(n);
+        if (t == simple_noad || t == accent_noad || t == radical_noad) {
+            lua_pushinteger(L, nucleus(n));
+            return 1;
         }
     }
     lua_pushnil(L);
     return 1;
 }
 
-static int lua_nodelib_getdiscretionary(lua_State * L)
+static int lua_nodelib_direct_setnucleus(lua_State * L)
 {
-    halfword *a;
-    halfword *n = lua_touserdata(L, 1);
-    if (n != NULL) {
-        if (type(*n) == disc_node) {
-            fast_metatable_or_nil(vlink(pre_break(*n)));
-            fast_metatable_or_nil(vlink(post_break(*n)));
-            fast_metatable_or_nil(vlink(no_break(*n)));
-            if (lua_isboolean(L, 2)) {
-                if (lua_toboolean(L, 2)) {
-                    fast_metatable_or_nil(tlink(pre_break(*n)));
-                    fast_metatable_or_nil(tlink(post_break(*n)));
-                    fast_metatable_or_nil(tlink(no_break(*n)));
-                    return 6;
-                }
+    halfword n = lua_tointeger(L, 1);
+    if (n) {
+        halfword t = type(n);
+        if (t == simple_noad || t == accent_noad || t == radical_noad) {
+            if (lua_type(L, 2) == LUA_TNUMBER) {
+                nucleus(n) = lua_tointeger(L,2);
+            } else {
+                nucleus(n) = null;
             }
-            return 3;
         }
     }
-    lua_pushnil(L);
+    return 0;
+}
+
+static int lua_nodelib_direct_getsub(lua_State * L)
+{
+    halfword n = lua_tointeger(L, 1);
+    if (n) {
+        halfword t = type(n);
+        if (t == simple_noad || t == accent_noad || t == radical_noad) {
+            lua_pushinteger(L, subscr(n));
+            return 1;
+        }
+    }
+    lua_pushnil(L);
+    return 1;
+}
+
+static int lua_nodelib_direct_setsub(lua_State * L)
+{
+    halfword n = lua_tointeger(L, 1);
+    if (n) {
+        halfword t = type(n);
+        if (t == simple_noad || t == accent_noad || t == radical_noad) {
+            if (lua_type(L, 2) == LUA_TNUMBER) {
+                subscr(n) = lua_tointeger(L,2);
+            } else {
+                subscr(n) = null;
+            }
+        }
+    }
+    return 0;
+}
+
+static int lua_nodelib_direct_getsup(lua_State * L)
+{
+    halfword n = lua_tointeger(L, 1);
+    if (n) {
+        halfword t = type(n);
+        if (t == simple_noad || t == accent_noad || t == radical_noad) {
+            lua_pushinteger(L, subscr(n));
+            return 1;
+        }
+    }
+    lua_pushnil(L);
+    return 1;
+}
+
+static int lua_nodelib_direct_setsup(lua_State * L)
+{
+    halfword n = lua_tointeger(L, 1);
+    if (n) {
+        halfword t = type(n);
+        if (t == simple_noad || t == accent_noad || t == radical_noad) {
+            if (lua_type(L, 2) == LUA_TNUMBER) {
+                supscr(n) = lua_tointeger(L,2);
+            } else {
+                supscr(n) = null;
+            }
+        }
+    }
+    return 0;
+}
+
+/* node.direct.getkern (overlaps with getwidth) */
+/* node.direct.setkern (overlaps with getwidth) */
+
+static int lua_nodelib_direct_getkern(lua_State * L)
+{
+    halfword n = lua_tointeger(L, 1);
+    if (n) {
+        halfword t = type(n);
+        if (t == kern_node || t == margin_kern_node) {
+            lua_pushinteger(L, width(n));
+        } else if (t == math_node) {
+            lua_pushinteger(L, surround(n));
+        } else {
+            lua_pushnil(L);
+        }
+    } else {
+        lua_pushnil(L);
+    }
+    return 1;
+}
+
+static int lua_nodelib_direct_setkern(lua_State * L)
+{
+    halfword n = lua_tointeger(L, 1);
+    if (n != null) {
+        halfword t = type(n);
+        if (t == kern_node || t == margin_kern_node) {
+            if (lua_type(L, 2) == LUA_TNUMBER) {
+                width(n) = (halfword) lua_tointeger(L, 2);
+            } else {
+                width(n) = 0;
+            }
+            if (lua_type(L, 3) == LUA_TNUMBER) {
+                subtype(n) = (halfword) lua_tointeger(L, 3);
+            }
+        } else if (t == math_node) {
+            if (lua_type(L, 2) == LUA_TNUMBER) {
+                surround(n) = (halfword) lua_tointeger(L, 2);
+            } else {
+                surround(n) = 0;
+            }
+        }
+    }
+    return 0;
+}
+
+/* node.direct.getdir */
+/* node.direct.setdir */
+
+static int lua_nodelib_direct_getdir(lua_State * L)
+{
+    halfword n = lua_tointeger(L, 1);
+    if (n) {
+        halfword t = type(n);
+        if (t == dir_node) {
+            lua_push_dir_text(L, dir_dir(n));
+        } else if (t == hlist_node || t == vlist_node) {
+            lua_push_dir_par(L, box_dir(n));
+        } else if (t == rule_node) {
+            lua_push_dir_par(L, rule_dir(n));
+        } else if (t == local_par_node) {
+            lua_push_dir_par(L, local_par_dir(n));
+        } else {
+            lua_pushnil(L);
+        }
+    } else {
+        lua_pushnil(L);
+    }
+    return 1;
+}
+
+static int lua_nodelib_direct_setdir(lua_State * L)
+{
+    halfword n = lua_tointeger(L, 1);
+    if (n) {
+        halfword t = type(n);
+        if (t == dir_node) {
+            dir_dir(n) = nodelib_getdir(L, 2, 0);
+        } else if (t == hlist_node || type(n) == vlist_node) {
+            box_dir(n) = nodelib_getdir(L, 2, 1);
+        } else if (t == rule_node) {
+            rule_dir(n) = nodelib_getdir(L, 2, 1);
+        } else if (t == local_par_node) {
+            local_par_dir(n) = nodelib_getdir(L, 3, 1);
+        }
+    }
+    return 0;
+}
+
+/* node.direct.getoffsets */
+/* node.direct.setoffsets */
+
+static int lua_nodelib_direct_getoffsets(lua_State * L)
+{
+    halfword n = lua_tointeger(L, 1);
+    if ((n) && (type(n) == glyph_node)) {
+        lua_pushinteger(L, x_displace(n));
+        lua_pushinteger(L, y_displace(n));
+        return 2;
+    } else {
+        lua_pushnil(L);
+    }
     return 1;
 }
 
-/* getwhd: only core nodes */
+static int lua_nodelib_direct_setoffsets(lua_State * L)
+{
+    halfword n = lua_tointeger(L, 1);
+    if ((n) && (type(n) == glyph_node)) {
+        if ((lua_type(L, 2) == LUA_TNUMBER)) {
+            x_displace(n) = (halfword) lua_tointeger(L, 2);
+        }
+        if ((lua_type(L, 3) == LUA_TNUMBER)) {
+            y_displace(n) = (halfword) lua_tointeger(L, 3);
+        }
+    }
+    return 0;
+}
+
+/* node.direct.getdisc */
+/* node.direct.setdisc */
+
+static int lua_nodelib_direct_getdisc(lua_State * L)
+{
+    halfword n = lua_tointeger(L, 1);
+    if ((n) && (type(n) == disc_node)) {
+        nodelib_pushdirect_or_nil(vlink(pre_break(n)));
+        nodelib_pushdirect_or_nil(vlink(post_break(n)));
+        nodelib_pushdirect_or_nil(vlink(no_break(n)));
+        if (lua_isboolean(L, 2) && lua_toboolean(L, 2)) {
+            nodelib_pushdirect_or_nil(tlink(pre_break(n)));
+            nodelib_pushdirect_or_nil(tlink(post_break(n)));
+            nodelib_pushdirect_or_nil(tlink(no_break(n)));
+            return 6;
+        }
+        return 3;
+    } else {
+        return 0;
+    }
+}
+
+static int lua_nodelib_direct_setdisc(lua_State * L)
+{
+    halfword n = lua_tointeger(L, 1);
+    if (type(n) == disc_node) {
+        int t = lua_gettop(L) ;
+        if (t > 1) {
+            set_disc_field(pre_break(n), lua_tointeger(L,2));
+            if (t > 2) {
+                set_disc_field(post_break(n), lua_tointeger(L,3));
+                if (t > 3) {
+                    set_disc_field(no_break(n), lua_tointeger(L,4));
+                    if (t > 4) {
+                        subtype(n) = (quarterword) lua_tointeger(L,5);
+                        if (t > 5) {
+                            disc_penalty(n) = lua_tointeger(L,6);
+                        }
+                    }
+                } else {
+                    set_disc_field(no_break(n), null);
+                }
+            } else {
+                set_disc_field(post_break(n), null);
+                set_disc_field(no_break(n), null);
+            }
+        } else {
+            set_disc_field(pre_break(n), null);
+            set_disc_field(post_break(n), null);
+            set_disc_field(no_break(n), null);
+        }
+    }
+    return 0;
+}
+
+    /* node.getdisc */
+
+    static int lua_nodelib_getdisc(lua_State * L)
+    {
+        halfword *a;
+        halfword *n = lua_touserdata(L, 1);
+        if ((n != NULL) && (type(*n) == disc_node)) {
+            fast_metatable_or_nil(vlink(pre_break(*n)));
+            fast_metatable_or_nil(vlink(post_break(*n)));
+            fast_metatable_or_nil(vlink(no_break(*n)));
+            if (lua_isboolean(L, 2) && lua_toboolean(L, 2)) {
+                fast_metatable_or_nil(tlink(pre_break(*n)));
+                fast_metatable_or_nil(tlink(post_break(*n)));
+                fast_metatable_or_nil(tlink(no_break(*n)));
+                return 6;
+            }
+            return 3;
+        }
+        return 0;
+    }
+
+/* node.direct.getwhd */
+/* node.direct.setwhd */
 
 #define push_list_whd(n) \
     lua_pushinteger(L, width(n));  \
@@ -756,31 +990,6 @@ static int lua_nodelib_direct_getwhd(lua_State * L)
     return 0;
 }
 
-static int lua_nodelib_getwhd(lua_State * L)
-{
-    halfword *n = lua_touserdata(L, 1);
-    if (n != NULL) {
-        halfword t = type(*n);
-        if ((t == hlist_node) || (t == vlist_node) || (t == rule_node) || (t == unset_node)) {
-            push_list_whd(*n);
-            return 3;
-        } else if (t == glyph_node) {
-            push_char_whd(*n);
-            return 3;
-        } else if (t == glue_node) {
-            halfword l = leader_ptr(*n);
-            if (l != null) {
-                t = type(l) ;
-                if ((t == hlist_node) || (t == vlist_node) || (t == rule_node)) {
-                    push_list_whd(l);
-                    return 3;
-                }
-            }
-        }
-    }
-    return 0;
-}
-
 static int lua_nodelib_direct_setwhd(lua_State * L)
 {
     halfword n = lua_tointeger(L, 1);
@@ -822,49 +1031,32 @@ static int lua_nodelib_direct_setwhd(lua_State * L)
     return 0;
 }
 
-/* node.getlist */
-
-static int lua_nodelib_getlist(lua_State * L)
-{
-    halfword *a;
-    halfword *n = lua_touserdata(L, 1);
-    if ((n == NULL) || (! lua_getmetatable(L,1))) {
-        lua_pushnil(L);
-    } else if ((type(*n) == hlist_node) || (type(*n) == vlist_node)) {
-        fast_metatable_or_nil_alink(list_ptr(*n));
-    } else if ((type(*n) == sub_box_node) || (type(*n) == sub_mlist_node)) {
-        fast_metatable_or_nil_alink(math_list(*n));
-    } else {
-        lua_pushnil(L);
-    }
-    return 1;
-}
-
-/*
+    /* node.getwhd */
 
-static int lua_nodelib_setlist(lua_State * L)
-{
-    halfword *n = lua_touserdata(L, 1);
-    if (n != null) {
-        if ((type(*n) == hlist_node) || (type(*n) == vlist_node)) {
-            if (lua_type(L,2) == LUA_TNIL) {
-                list_ptr(n) = null;
-            } else {
-                halfword *l = lua_touserdata(L, 2);
-                list_ptr(n) = l;
-            }
-        } else {
-            if (lua_type(L,2) == LUA_TNIL) {
-                math_list(n) = null;
-            } else {
-                halfword *l = lua_touserdata(L, 2);
-                math_list(n) = l;
+    static int lua_nodelib_getwhd(lua_State * L)
+    {
+        halfword *n = lua_touserdata(L, 1);
+        if (n != NULL) {
+            halfword t = type(*n);
+            if ((t == hlist_node) || (t == vlist_node) || (t == rule_node) || (t == unset_node)) {
+                push_list_whd(*n);
+                return 3;
+            } else if (t == glyph_node) {
+                push_char_whd(*n);
+                return 3;
+            } else if (t == glue_node) {
+                halfword l = leader_ptr(*n);
+                if (l != null) {
+                    t = type(l) ;
+                    if ((t == hlist_node) || (t == vlist_node) || (t == rule_node)) {
+                        push_list_whd(l);
+                        return 3;
+                    }
+                }
             }
+        }
+        return 0;
     }
-    return 0;
-}
-
-*/
 
 /* node.direct.getlist */
 
@@ -916,30 +1108,31 @@ static int lua_nodelib_direct_setlist(lua_State * L)
     return 0;
 }
 
-/* node.getleader */
+    /* node.getlist */
 
-static int lua_nodelib_getleader(lua_State * L)
-{
-    halfword *a;
-    halfword *n = lua_touserdata(L, 1);
-    if ( (n == NULL) || (! lua_getmetatable(L,1)) ) {
-        lua_pushnil(L);
-    } else if (type(*n) == glue_node) {
-        fast_metatable_or_nil(leader_ptr(*n));
-    } else {
-        lua_pushnil(L);
-    }
-    return 1;
-}
+    static int lua_nodelib_getlist(lua_State * L)
+    {
+        halfword *a;
+        halfword *n = lua_touserdata(L, 1);
+        if ((n == NULL) || (! lua_getmetatable(L,1))) {
+            lua_pushnil(L);
+        } else if ((type(*n) == hlist_node) || (type(*n) == vlist_node)) {
+            fast_metatable_or_nil_alink(list_ptr(*n));
+        } else if ((type(*n) == sub_box_node) || (type(*n) == sub_mlist_node)) {
+            fast_metatable_or_nil_alink(math_list(*n));
+        } else {
+            lua_pushnil(L);
+        }
+        return 1;
+    }
 
 /* node.direct.getleader */
+/* node.direct.setleader */
 
 static int lua_nodelib_direct_getleader(lua_State * L)
 {
     halfword n = lua_tointeger(L, 1);
-    if (n == null) {
-        lua_pushnil(L);
-    } else if (type(n) == glue_node) {
+    if ((n) && (type(n) == glue_node)) {
         nodelib_pushdirect_or_nil(leader_ptr(n));
     } else {
         lua_pushnil(L);
@@ -947,10 +1140,10 @@ static int lua_nodelib_direct_getleader(lua_State * L)
     return 1;
 }
 
-static int lua_nodelib_direct_setleader(lua_State * L)
+    static int lua_nodelib_direct_setleader(lua_State * L)
 {
     halfword n = lua_tointeger(L, 1);
-    if ((n != null) && (type(n) == glue_node)) {
+    if ((n) && (type(n) == glue_node)) {
         if (lua_type(L,2) == LUA_TNUMBER) {
             leader_ptr(n) = (halfword) lua_tointeger(L, 2);
         } else {
@@ -960,164 +1153,241 @@ static int lua_nodelib_direct_setleader(lua_State * L)
     return 0;
 }
 
-/* node.getnext */
+    /* node.getleader */
+
+    static int lua_nodelib_getleader(lua_State * L)
+    {
+        halfword *a;
+        halfword *n = lua_touserdata(L, 1);
+        if ((n == NULL) || (! lua_getmetatable(L,1)) ) {
+            lua_pushnil(L);
+        } else if (type(*n) == glue_node) {
+            fast_metatable_or_nil(leader_ptr(*n));
+        } else {
+            lua_pushnil(L);
+        }
+        return 1;
+    }
+
+/* node.direct.getnext */
+/* node.direct.setnext */
 
-static int lua_nodelib_getnext(lua_State * L)
+static int lua_nodelib_direct_getnext(lua_State * L)
 {
-    halfword *a;
-    /* [given-node] [...]*/
-    halfword *p = lua_touserdata(L, 1);
-    if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
+    halfword p = lua_tointeger(L, 1);
+    if (p == null) {
         lua_pushnil(L);
     } else {
-        /* [given-node] [mt-given-node]*/
-        lua_get_metatablelua(luatex_node);
-        /* [given-node] [mt-given-node] [mt-node]*/
-        if (!lua_rawequal(L, -1, -2)) {
-            lua_pushnil(L);
+        nodelib_pushdirect_or_nil(vlink(p));
+    }
+    return 1;
+}
+
+static int lua_nodelib_direct_setnext(lua_State * L)
+{
+    halfword n = lua_tointeger(L, 1);
+    if (n) {
+        if (lua_type(L, 2) == LUA_TNUMBER) {
+            vlink(n) = (halfword) lua_tointeger(L, 2);
         } else {
-            fast_metatable_or_nil(vlink(*p));
+            vlink(n) = null;
         }
     }
-    return 1; /* just one*/
+    return 0;
 }
 
-/* node.fast.getnext
+    /* node.getnext */
 
-    static int lua_nodelib_fast_getnext(lua_State * L)
+    static int lua_nodelib_getnext(lua_State * L)
     {
         halfword *a;
+        /* [given-node] [...]*/
         halfword *p = lua_touserdata(L, 1);
-        if ((p == NULL) || (!vlink(*p))){
+        if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
             lua_pushnil(L);
         } else {
-            lua_settop(L,1);
-            lua_getmetatable(L,1);
-            a = lua_newuserdata(L, sizeof(halfword));
-            *a = vlink(*p);
-            lua_replace(L,1);
-            lua_setmetatable(L,1);
+            /* [given-node] [mt-given-node]*/
+            lua_get_metatablelua(luatex_node);
+            /* [given-node] [mt-given-node] [mt-node]*/
+            if (!lua_rawequal(L, -1, -2)) {
+                lua_pushnil(L);
+            } else {
+                fast_metatable_or_nil(vlink(*p));
+            }
         }
-        return 1;
+        return 1; /* just one*/
     }
 
-*/
-
-/* node.direct.getnext */
+/* node.direct.getprev */
+/* node.direct.setprev */
 
-static int lua_nodelib_direct_getnext(lua_State * L)
+static int lua_nodelib_direct_getprev(lua_State * L)
 {
     halfword p = lua_tointeger(L, 1);
     if (p == null) {
         lua_pushnil(L);
-    } else if ((lua_type(L, 2) == LUA_TNUMBER)) {
-        /* experiment */
-        int n = lua_tointeger(L,2);
-        while (p != null && n > 0) {
-            p = vlink(p);
-            n -= 1;
-        }
-        nodelib_pushdirect_or_nil(p);
     } else {
-        nodelib_pushdirect_or_nil(vlink(p));
+        nodelib_pushdirect_or_nil(alink(p));
     }
     return 1;
 }
 
-/* node.getprev */
-
-static int lua_nodelib_getprev(lua_State * L)
+static int lua_nodelib_direct_setprev(lua_State * L)
 {
-    halfword *a;
-    halfword *p = lua_touserdata(L, 1);
-    if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
-        lua_pushnil(L);
-    } else {
-        /* experiment */
-        lua_get_metatablelua(luatex_node);
-        if (!lua_rawequal(L, -1, -2)) {
-            lua_pushnil(L);
+    halfword n = lua_tointeger(L, 1);
+    if (n) {
+        if (lua_type(L, 2) == LUA_TNUMBER) {
+            alink(n) = (halfword) lua_tointeger(L, 2);
         } else {
-            fast_metatable_or_nil(alink(*p));
+            alink(n) = null;
         }
     }
-    return 1;
+    return 0;
 }
 
-static int lua_nodelib_getboth(lua_State * L)
+    /* node.getprev */
+
+    static int lua_nodelib_getprev(lua_State * L)
+    {
+        halfword *a;
+        halfword *p = lua_touserdata(L, 1);
+        if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
+            lua_pushnil(L);
+        } else {
+            lua_get_metatablelua(luatex_node);
+            if (!lua_rawequal(L, -1, -2)) {
+                lua_pushnil(L);
+            } else {
+                fast_metatable_or_nil(alink(*p));
+            }
+        }
+        return 1;
+    }
+
+/* node.direct.getboth */
+/* node.direct.setboth */
+
+static int lua_nodelib_direct_getboth(lua_State * L)
 {
-    halfword *a;
-    halfword *p = lua_touserdata(L, 1);
-    if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
+    halfword n = lua_tointeger(L, 1);
+    if (n) {
+        nodelib_pushdirect_or_nil(alink(n));
+        nodelib_pushdirect_or_nil(vlink(n));
+    } else {
         lua_pushnil(L);
         lua_pushnil(L);
-    } else {
-        lua_get_metatablelua(luatex_node);
-        if (!lua_rawequal(L, -1, -2)) {
-            lua_pushnil(L);
-            lua_pushnil(L);
+    }
+    return 2;
+}
+
+static int lua_nodelib_direct_setboth(lua_State * L)
+{
+    halfword n = lua_tointeger(L, 1);
+    if (n) {
+        if (lua_type(L, 2) == LUA_TNUMBER) {
+            alink(n) = (halfword) lua_tointeger(L, 2);
         } else {
-            fast_metatable_or_nil(alink(*p));
-            fast_metatable_or_nil(vlink(*p));
+            alink(n) = null;
+        }
+        if (lua_type(L, 3) == LUA_TNUMBER) {
+            vlink(n) = (halfword) lua_tointeger(L, 3);
+        } else {
+            vlink(n) = null;
         }
     }
-    return 2;
+    return 0;
 }
 
-/* node.fast.getprev
+    /* node.getboth */
 
-    static int lua_nodelib_fast_getprev(lua_State * L)
+    static int lua_nodelib_getboth(lua_State * L)
     {
         halfword *a;
         halfword *p = lua_touserdata(L, 1);
-        if ((p == NULL) || (!alink(*p))) {
+        if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
+            lua_pushnil(L);
             lua_pushnil(L);
         } else {
-            lua_settop(L,1);
-            lua_getmetatable(L,1);
-            a = lua_newuserdata(L, sizeof(halfword));
-            *a = alink(*p);
-            lua_replace(L,1);
-            lua_setmetatable(L,1);
+            lua_get_metatablelua(luatex_node);
+            if (lua_rawequal(L, -1, -2)) {
+                fast_metatable_or_nil(alink(*p));
+                fast_metatable_or_nil(vlink(*p));
+            } else {
+                lua_pushnil(L);
+                lua_pushnil(L);
+            }
         }
-        return 1;
+        return 2;
     }
 
-*/
+/* node.direct.setlink */
+/* node.direct.unlink  */
 
-/* node.direct.getprev */
+/*
+    a b b nil c d         : prev-a-b-c-next
+    nil a b b nil c d nil : nil-a-b-c-nil
+*/
 
-static int lua_nodelib_direct_getprev(lua_State * L)
+static int lua_nodelib_direct_setlink(lua_State * L)
 {
-    halfword p = lua_tointeger(L, 1);
-    if (p == null) {
-        lua_pushnil(L);
-    } else if ((lua_type(L, 2) == LUA_TNUMBER)) {
-        int n = lua_tointeger(L,2);
-        while (p != null && n > 0) {
-            p = alink(p);
-            n -= 1;
+    int n = lua_gettop(L);
+    int i;
+    halfword h = null; /* head node */
+    halfword t = null; /* tail node */
+    halfword c = null; /* current node */
+    for (i=1;i<=n;i++) {
+        /*
+            we don't go for the tail of the current node because we can inject
+            between existing nodes and the nodes themselves can have old values
+            for prev and next, so ... only single nodes are looked at!
+        */
+        if (lua_type(L, i) == LUA_TNUMBER) {
+            c = lua_tointeger(L, i);
+            if (c != t) {
+                if (t != null) {
+                    vlink(t) = c;
+                    alink(c) = t;
+                } else if (i > 1) {
+                    /* we assume that the first node is a kind of head */
+                    alink(c) = null;
+                }
+                t = c;
+                if (h == null) {
+                    h = t;
+                }
+            } else {
+                /* we ignore duplicate nodes which can be tails or the previous */
+            }
+        } else if (t == null) {
+            /* we just ignore nil nodes and have no tail yet */
+        } else {
+            /* safeguard: a nil in the list can be meant as end so we nil the next of tail */
+            vlink(t) = null;
         }
-        nodelib_pushdirect_or_nil(p);
+    }
+    if (h == null) {
+        /* no head */
+        lua_pushnil(L);
     } else {
-        nodelib_pushdirect_or_nil(alink(p));
+        /* first valid head */
+        lua_pushinteger(L,h);
     }
     return 1;
 }
 
-/* node.direct.getboth */
-
-static int lua_nodelib_direct_getboth(lua_State * L)
+static int lua_nodelib_direct_unlink(lua_State * L)
 {
-    halfword p = lua_tointeger(L, 1);
-    if (p == null) {
-        lua_pushnil(L);
-        lua_pushnil(L);
-    } else {
-        nodelib_pushdirect_or_nil(alink(p));
-        nodelib_pushdirect_or_nil(vlink(p));
+    if (lua_type(L, 1) == LUA_TNUMBER && (lua_type(L, 2) == LUA_TNUMBER)) {
+        halfword l = lua_tointeger(L, 1);
+        halfword r = lua_tointeger(L, 2);
+        if (l != r) {
+            alink(vlink(l)) = null;
+            vlink(alink(r)) = null;
+        }
+        vlink(l) = null;
+        alink(r) = null;
     }
-    return 2;
+    return 0;
 }
 
 /* node.subtype (maybe also return them for other node types now) */
@@ -2539,6 +2809,9 @@ static int lua_nodelib_find_attribute(lua_State * L) /* returns attr value and n
 }
 
 /* node.direct.get_attribute */
+/* node.direct.set_attribute */
+/* node.direct.unset_attribute */
+/* node.direct.find_attribute */
 
 static int lua_nodelib_direct_get_attribute(lua_State * L)
 {
@@ -2570,6 +2843,26 @@ static int lua_nodelib_direct_get_attribute(lua_State * L)
     return 1;
 }
 
+static int lua_nodelib_direct_set_attribute(lua_State * L)
+{
+    int i, val;
+    halfword n = lua_tointeger(L, 1);
+    if (n == null)
+        return 0;
+    if (lua_gettop(L) == 3) {
+        i = (int) lua_tointeger(L, 2);
+        val = (int) lua_tointeger(L, 3);
+        if (val == UNUSED_ATTRIBUTE) {
+            (void) unset_attribute(n, i, val);
+        } else {
+            set_attribute(n, i, val);
+        }
+    } else {
+        luaL_error(L, "incorrect number of arguments");
+    }
+    return 0;
+}
+
 static int lua_nodelib_direct_find_attribute(lua_State * L) /* returns attr value and node */
 {
     halfword c = lua_tointeger(L, 1);
@@ -2607,7 +2900,28 @@ static int lua_nodelib_direct_find_attribute(lua_State * L) /* returns attr valu
     return 0;
 }
 
+static int lua_nodelib_direct_unset_attribute(lua_State * L)
+{
+    halfword n = lua_tointeger(L, 1);
+    if (n == null) {
+        lua_pushnil(L);
+    } else if (lua_gettop(L) <= 3) { /* a useless test, we never test for that elsewhere */
+        int i = (int)luaL_checknumber(L, 2);
+        int val = (int)luaL_optnumber(L, 3, UNUSED_ATTRIBUTE);
+        int ret = unset_attribute(n, i, val);
+        if (ret > UNUSED_ATTRIBUTE) {
+            lua_pushinteger(L, ret);
+        } else {
+            lua_pushnil(L);
+        }
+    } else { /* can go */
+        return luaL_error(L, "incorrect number of arguments");
+    }
+    return 1;
+}
+
 /* node.set_attribute */
+/* node.unset_attribute */
 
 static int lua_nodelib_set_attribute(lua_State * L)
 {
@@ -2626,31 +2940,7 @@ static int lua_nodelib_set_attribute(lua_State * L)
     return 0;
 }
 
-/* node.direct.set_attribute */
-
-static int lua_nodelib_direct_set_attribute(lua_State * L)
-{
-    int i, val;
-    halfword n = lua_tointeger(L, 1);
-    if (n == null)
-        return 0;
-    if (lua_gettop(L) == 3) {
-        i = (int) lua_tointeger(L, 2);
-        val = (int) lua_tointeger(L, 3);
-        if (val == UNUSED_ATTRIBUTE) {
-            (void) unset_attribute(n, i, val);
-        } else {
-            set_attribute(n, i, val);
-        }
-    } else {
-        luaL_error(L, "incorrect number of arguments");
-    }
-    return 0;
-}
-
-/* node.unset_attribute */
-
-static int lua_nodelib_unset_attribute(lua_State * L)
+static int lua_nodelib_unset_attribute(lua_State * L)
 {
     if (lua_gettop(L) <= 3) {
         int i = luaL_checknumber(L, 2);
@@ -2668,178 +2958,272 @@ static int lua_nodelib_unset_attribute(lua_State * L)
     }
 }
 
-/* node.direct.unset_attribute */
+/* node.direct.getwidth  */
+/* node.direct.setwidth  */
+/* node.direct.getheight (for consistency) */
+/* node.direct.setheight (for consistency) */
+/* node.direct.getdepth  (for consistency) */
+/* node.direct.setdepth  (for consistency) */
 
-static int lua_nodelib_direct_unset_attribute(lua_State * L)
+/* split ifs for clearity .. compiler will optimize */
+
+static int lua_nodelib_direct_getwidth(lua_State * L)
 {
     halfword n = lua_tointeger(L, 1);
-    if (n == null) {
-        lua_pushnil(L);
-    } else if (lua_gettop(L) <= 3) { /* a useless test, we never test for that elsewhere */
-        int i = (int)luaL_checknumber(L, 2);
-        int val = (int)luaL_optnumber(L, 3, UNUSED_ATTRIBUTE);
-        int ret = unset_attribute(n, i, val);
-        if (ret > UNUSED_ATTRIBUTE) {
-            lua_pushinteger(L, ret);
+    if (n) {
+        halfword t = type(n);
+        if (t == hlist_node || t == vlist_node || t == rule_node) {
+            lua_pushinteger(L,width(n));
+        } else if (t == glyph_node) {
+            lua_pushinteger(L, char_width(font(n),character(n)));
+        } else if (t == glue_node || t == glue_spec_node || t == math_node || t == ins_node) {
+            lua_pushinteger(L,width(n));
+        } else if (t == kern_node || t == margin_kern_node) {
+            lua_pushinteger(L,width(n));
+        } else if (t == unset_node) {
+            lua_pushinteger(L,width(n));
         } else {
             lua_pushnil(L);
         }
-    } else { /* can go */
-        return luaL_error(L, "incorrect number of arguments");
+    } else {
+        lua_pushnil(L);
     }
     return 1;
 }
 
-/* glue */
+static int lua_nodelib_direct_setwidth(lua_State * L)
+{
+    halfword n = lua_tointeger(L, 1);
+    if (n) {
+        halfword t = type(n);
+        if (t == hlist_node || t == vlist_node || t == rule_node || t == glue_node || t == glue_spec_node || t == math_node ||
+                t == kern_node || t == margin_kern_node ||  t == ins_node || t == unset_node) {
+            if (lua_type(L, 2) == LUA_TNUMBER) {
+                width(n) = lua_tointeger(L,2);
+            } else {
+                width(n) = 0;
+            }
+        }
+    }
+    return 0;
+}
 
-static int lua_nodelib_set_glue(lua_State * L)
+static int lua_nodelib_direct_getheight(lua_State * L)
 {
-    halfword n = *check_isnode(L, 1);
-    int top = lua_gettop(L) ;
-    if ((n != null) && (type(n) == glue_node || type(n) == glue_spec_node || type(n) == math_node)) {
-        width(n)         = ((top > 1 && lua_type(L, 2) == LUA_TNUMBER)) ? lua_roundnumber(L,2) : 0;
-        stretch(n)       = ((top > 2 && lua_type(L, 3) == LUA_TNUMBER)) ? lua_roundnumber(L,3) : 0;
-        shrink(n)        = ((top > 3 && lua_type(L, 4) == LUA_TNUMBER)) ? lua_roundnumber(L,4) : 0;
-        stretch_order(n) = ((top > 4 && lua_type(L, 5) == LUA_TNUMBER)) ? lua_tointeger(L,5) : 0;
-        shrink_order(n)  = ((top > 5 && lua_type(L, 6) == LUA_TNUMBER)) ? lua_tointeger(L,6) : 0;
-        return 0;
+    halfword n = lua_tointeger(L, 1);
+    if (n) {
+        halfword t = type(n);
+        if (t == hlist_node || t == vlist_node || t == rule_node) {
+            lua_pushinteger(L,height(n));
+        } else if (t == glyph_node) {
+            lua_pushinteger(L, char_height(font(n),character(n)));
+        } else if (t == unset_node || t == ins_node) {
+            lua_pushinteger(L,height(n));
+        } else {
+            lua_pushnil(L);
+        }
     } else {
-        return luaL_error(L, "glue (spec) expected");
+        lua_pushnil(L);
     }
+    return 1;
 }
 
-static int lua_nodelib_direct_set_glue(lua_State * L)
+static int lua_nodelib_direct_setheight(lua_State * L)
 {
     halfword n = lua_tointeger(L, 1);
-    int top = lua_gettop(L) ;
-    if ((n != null) && (type(n) == glue_node || type(n) == glue_spec_node || type(n) == math_node)) {
-        width(n)         = ((top > 1 && lua_type(L, 2) == LUA_TNUMBER)) ? lua_roundnumber(L,2) : 0;
-        stretch(n)       = ((top > 2 && lua_type(L, 3) == LUA_TNUMBER)) ? lua_roundnumber(L,3) : 0;
-        shrink(n)        = ((top > 3 && lua_type(L, 4) == LUA_TNUMBER)) ? lua_roundnumber(L,4) : 0;
-        stretch_order(n) = ((top > 4 && lua_type(L, 5) == LUA_TNUMBER)) ? lua_tointeger(L,5) : 0;
-        shrink_order(n)  = ((top > 5 && lua_type(L, 6) == LUA_TNUMBER)) ? lua_tointeger(L,6) : 0;
-        return 0;
-    } else {
-        return luaL_error(L, "glue (spec) expected");
+    if (n) {
+        halfword t = type(n);
+        if (t == hlist_node || t == vlist_node || t == rule_node || t == unset_node) {
+            if (lua_type(L, 2) == LUA_TNUMBER) {
+                height(n) = lua_tointeger(L,2);
+            } else {
+                height(n) = 0;
+            }
+        }
     }
+    return 0;
 }
 
-static int lua_nodelib_get_glue(lua_State * L)
+static int lua_nodelib_direct_getdepth(lua_State * L)
 {
-    halfword n = *check_isnode(L, 1);
-    if ((n != null) && (type(n) == glue_node || type(n) == glue_spec_node || type(n) == math_node)) {
-        int b = -1; /* false: only width, true or unset: 5 values */
-        if (lua_gettop(L) == 2) {
-            b = lua_toboolean(L, 2);
+    halfword n = lua_tointeger(L, 1);
+    if (n) {
+        halfword t = type(n);
+        if (t == hlist_node || t == vlist_node || t == rule_node) {
+            lua_pushinteger(L,depth(n));
+        } else if (t == glyph_node) {
+            lua_pushinteger(L, char_depth(font(n),character(n)));
+        } else if (t == unset_node || t == ins_node) {
+            lua_pushinteger(L,depth(n));
+        } else {
+            lua_pushnil(L);
         }
-        lua_pushinteger(L,width(n));
-        if (b == 0)
-            return 1;
-        lua_pushinteger(L,stretch(n));
-        lua_pushinteger(L,shrink(n));
-        lua_pushinteger(L,stretch_order(n));
-        lua_pushinteger(L,shrink_order(n));
-        return 5;
     } else {
-        return luaL_error(L, "glue (spec) expected");
+        lua_pushnil(L);
     }
+    return 1;
 }
 
-static int lua_nodelib_direct_get_glue(lua_State * L)
+static int lua_nodelib_direct_setdepth(lua_State * L)
 {
     halfword n = lua_tointeger(L, 1);
-    if ((n != null) && (type(n) == glue_node || type(n) == glue_spec_node || type(n) == math_node)) {
-        int b = -1;
-        if (lua_gettop(L) == 2) {
-            b = lua_toboolean(L, 2);
+    if (n) {
+        halfword t = type(n);
+        if (t == hlist_node || t == vlist_node || t == rule_node || t == unset_node) {
+            if (lua_type(L, 2) == LUA_TNUMBER) {
+                depth(n) = lua_tointeger(L,2);
+            } else {
+                depth(n) = 0;
+            }
         }
-        lua_pushinteger(L,width(n));
-        if (b == 0) {
+    }
+    return 0;
+}
+
+/* node.direct.getshift */
+/* node.direct.setshift */
+
+static int lua_nodelib_direct_getshift(lua_State * L)
+{
+    halfword n = lua_tointeger(L, 1);
+    if (n) {
+        halfword t = type(n);
+        if (t == hlist_node || t == vlist_node) {
+            lua_pushinteger(L,shift_amount(n));
             return 1;
-        } else {
+        }
+    }
+    lua_pushnil(L);
+    return 1;
+}
+
+static int lua_nodelib_direct_setshift(lua_State * L)
+{
+    halfword n = lua_tointeger(L, 1);
+    if (n) {
+        halfword t = type(n);
+        if (t == hlist_node || t == vlist_node) {
+            if (lua_type(L, 2) == LUA_TNUMBER) {
+                shift_amount(n) = lua_tointeger(L,2);
+            } else {
+                shift_amount(n) = 0;
+            }
+        }
+    }
+    return 0;
+}
+
+/* node.direct.getglue */
+/* node.direct.setglue */
+/* node.direct.is_zero_glue */
+
+static int lua_nodelib_direct_get_glue(lua_State * L)
+{
+    halfword n = lua_tointeger(L, 1);
+    if (n) {
+        halfword t = type(n);
+        if (t == glue_node || t == glue_spec_node || t == math_node || t == ins_node) {
+            lua_pushinteger(L,width(n));
             lua_pushinteger(L,stretch(n));
             lua_pushinteger(L,shrink(n));
             lua_pushinteger(L,stretch_order(n));
             lua_pushinteger(L,shrink_order(n));
             return 5;
         }
-    } else {
-        return luaL_error(L, "glue (spec) expected");
     }
+    return 0;
 }
 
-static int lua_nodelib_is_zero_glue(lua_State * L)
+static int lua_nodelib_direct_set_glue(lua_State * L)
 {
-    halfword n = *check_isnode(L, 1);
-    if ((n != null) && (type(n) == glue_node || type(n) == glue_spec_node || type(n) == math_node)) {
-        lua_pushboolean(L,(width(n) == 0 && stretch(n) == 0 && shrink(n) == 0));
-        return 1;
-    } else {
-        return luaL_error(L, "glue (spec) expected");
+    halfword n = lua_tointeger(L, 1);
+    if (n) {
+        int top = lua_gettop(L);
+        halfword t = type(n);
+        if (t == glue_node || t == glue_spec_node || t == math_node) {
+            width(n)         = ((top > 1 && lua_type(L, 2) == LUA_TNUMBER)) ? lua_roundnumber(L,2) : 0;
+            stretch(n)       = ((top > 2 && lua_type(L, 3) == LUA_TNUMBER)) ? lua_roundnumber(L,3) : 0;
+            shrink(n)        = ((top > 3 && lua_type(L, 4) == LUA_TNUMBER)) ? lua_roundnumber(L,4) : 0;
+            stretch_order(n) = ((top > 4 && lua_type(L, 5) == LUA_TNUMBER)) ? lua_tointeger(L,5) : 0;
+            shrink_order(n)  = ((top > 5 && lua_type(L, 6) == LUA_TNUMBER)) ? lua_tointeger(L,6) : 0;
+        }
     }
+    return 0;
 }
 
 static int lua_nodelib_direct_is_zero_glue(lua_State * L)
 {
     halfword n = lua_tointeger(L, 1);
-    if ((n != null) && (type(n) == glue_node || type(n) == glue_spec_node || type(n) == math_node)) {
-        lua_pushboolean(L,(width(n) == 0 && stretch(n) == 0 && shrink(n) == 0));
-        return 1;
-    } else {
-        return luaL_error(L, "glue (spec) expected");
+    if (n) {
+        halfword t = type(n);
+        if (t == glue_node || t == glue_spec_node || t == math_node || t == ins_node) {
+            lua_pushboolean(L,(width(n) == 0 && stretch(n) == 0 && shrink(n) == 0));
+            return 1;
+        }
     }
+    return luaL_error(L, "glue (spec) expected");
 }
 
-/* iteration */
+/* node.getglue */
+/* node.setglue */
+/* node.is_zero_glue */
 
-static int nodelib_aux_nil(lua_State * L)
+static int lua_nodelib_get_glue(lua_State * L)
 {
-    lua_pushnil(L);
-    return 1;
+    halfword n = *check_isnode(L, 1);
+    if (n) {
+        halfword t = type(n);
+        if (t == glue_node || t == glue_spec_node || t == math_node || t== ins_node) {
+            lua_pushinteger(L,width(n));
+            lua_pushinteger(L,stretch(n));
+            lua_pushinteger(L,shrink(n));
+            lua_pushinteger(L,stretch_order(n));
+            lua_pushinteger(L,shrink_order(n));
+            return 5;
+        }
+    }
+    return luaL_error(L, "glue (spec) expected");
 }
 
-/* node.traverse_id */
-
-static int nodelib_aux_next_filtered(lua_State * L)
+static int lua_nodelib_set_glue(lua_State * L)
 {
-    halfword t;        /* traverser */
-    halfword *a;
-    int i = (int) lua_tointeger(L, lua_upvalueindex(1));
-    if (lua_isnil(L, 2)) {      /* first call */
-        t = *check_isnode(L, 1);
-        lua_settop(L,1);
-    } else {
-        t = *check_isnode(L, 2);
-        t = vlink(t);
-        lua_settop(L,2);
-    }
-    while (t != null && type(t) != i) {
-        t = vlink(t);
-    }
-    if (t == null) {
-        lua_pushnil(L);
-    } else {
-        fast_metatable_top(t);
+    halfword n = *check_isnode(L, 1);
+    int top = lua_gettop(L) ;
+    if (n) {
+        halfword t = type(n);
+        if (t == glue_node || t == glue_spec_node || t == math_node) {
+            width(n)         = ((top > 1 && lua_type(L, 2) == LUA_TNUMBER)) ? lua_roundnumber(L,2) : 0;
+            stretch(n)       = ((top > 2 && lua_type(L, 3) == LUA_TNUMBER)) ? lua_roundnumber(L,3) : 0;
+            shrink(n)        = ((top > 3 && lua_type(L, 4) == LUA_TNUMBER)) ? lua_roundnumber(L,4) : 0;
+            stretch_order(n) = ((top > 4 && lua_type(L, 5) == LUA_TNUMBER)) ? lua_tointeger(L,5) : 0;
+            shrink_order(n)  = ((top > 5 && lua_type(L, 6) == LUA_TNUMBER)) ? lua_tointeger(L,6) : 0;
+        }
     }
-    return 1;
+    return luaL_error(L, "glue (spec) expected");
+    return 0;
 }
 
-static int lua_nodelib_traverse_filtered(lua_State * L)
+static int lua_nodelib_is_zero_glue(lua_State * L)
 {
-    halfword n;
-    if (lua_isnil(L, 2)) {
-        lua_pushcclosure(L, nodelib_aux_nil, 0);
+    halfword n = *check_isnode(L, 1);
+    if ((n != null) && (type(n) == glue_node || type(n) == glue_spec_node || type(n) == math_node || type(n) == ins_node)) {
+        lua_pushboolean(L,(width(n) == 0 && stretch(n) == 0 && shrink(n) == 0));
         return 1;
     }
-    n = *check_isnode(L, 2);
-    lua_pop(L, 1);              /* the node, integer remains */
-    lua_pushcclosure(L, nodelib_aux_next_filtered, 1);
-    lua_nodelib_push_fast(L, n);
+    return luaL_error(L, "glue (spec) expected");
+}
+
+/* iteration */
+
+static int nodelib_aux_nil(lua_State * L)
+{
     lua_pushnil(L);
-    return 3;
+    return 1;
 }
 
 /* node.direct.traverse_id */
+/* node.direct.traverse */
+/* node.direct.traverse_char */
 
 static int nodelib_direct_aux_next_filtered(lua_State * L)
 {
@@ -2884,7 +3268,42 @@ static int lua_nodelib_direct_traverse_filtered(lua_State * L)
     return 3;
 }
 
-/* node.direct.traverse_char */
+static int nodelib_direct_aux_next(lua_State * L)
+{
+    halfword t;            /* traverser */
+    if (lua_isnil(L, 2)) { /* first call */
+        t = lua_tointeger(L,1) ;
+        lua_settop(L,1);
+    } else {
+        t = lua_tointeger(L,2) ;
+        t = vlink(t);
+        lua_settop(L,2);
+    }
+    if (t == null) {
+        lua_pushnil(L);
+    } else {
+        lua_pushinteger(L,t);
+    }
+    return 1;
+}
+
+static int lua_nodelib_direct_traverse(lua_State * L)
+{
+    halfword n;
+    if (lua_isnil(L, 1)) {
+        lua_pushcclosure(L, nodelib_aux_nil, 0);
+        return 1;
+    }
+    n = (halfword) lua_tointeger(L, 1);
+    if (n == null) {
+        lua_pushcclosure(L, nodelib_aux_nil, 0);
+        return 1;
+    }
+    lua_pushcclosure(L, nodelib_direct_aux_next, 0);
+    lua_pushinteger(L,n);
+    lua_pushnil(L);
+    return 3;
+}
 
 static int nodelib_direct_aux_next_char(lua_State * L)
 {
@@ -2929,13 +3348,16 @@ static int lua_nodelib_direct_traverse_char(lua_State * L)
     return 3;
 }
 
+/* node.traverse_id */
 /* node.traverse */
+/* node.traverse_char */
 
-static int nodelib_aux_next(lua_State * L)
+static int nodelib_aux_next_filtered(lua_State * L)
 {
-    halfword t;            /* traverser */
-    halfword *a;           /* a or *a */
-    if (lua_isnil(L, 2)) { /* first call */
+    halfword t;        /* traverser */
+    halfword *a;
+    int i = (int) lua_tointeger(L, lua_upvalueindex(1));
+    if (lua_isnil(L, 2)) {      /* first call */
         t = *check_isnode(L, 1);
         lua_settop(L,1);
     } else {
@@ -2943,34 +3365,36 @@ static int nodelib_aux_next(lua_State * L)
         t = vlink(t);
         lua_settop(L,2);
     }
-    if (t == null) {
-        lua_pushnil(L);
+    while (t != null && type(t) != i) {
+        t = vlink(t);
+    }
+    if (t == null) {
+        lua_pushnil(L);
     } else {
         fast_metatable_top(t);
     }
     return 1;
 }
 
-static int lua_nodelib_traverse(lua_State * L)
+static int lua_nodelib_traverse_filtered(lua_State * L)
 {
     halfword n;
-    if (lua_isnil(L, 1)) {
+    if (lua_isnil(L, 2)) {
         lua_pushcclosure(L, nodelib_aux_nil, 0);
         return 1;
     }
-    n = *check_isnode(L, 1);
-    lua_pushcclosure(L, nodelib_aux_next, 0);
+    n = *check_isnode(L, 2);
+    lua_pop(L, 1);              /* the node, integer remains */
+    lua_pushcclosure(L, nodelib_aux_next_filtered, 1);
     lua_nodelib_push_fast(L, n);
     lua_pushnil(L);
     return 3;
 }
 
-/* node.traverse_char */
-
-static int nodelib_aux_next_char(lua_State * L)
+static int nodelib_aux_next(lua_State * L)
 {
     halfword t;            /* traverser */
-    halfword *a;
+    halfword *a;           /* a or *a */
     if (lua_isnil(L, 2)) { /* first call */
         t = *check_isnode(L, 1);
         lua_settop(L,1);
@@ -2979,20 +3403,15 @@ static int nodelib_aux_next_char(lua_State * L)
         t = vlink(t);
         lua_settop(L,2);
     }
-    while (1) {
-        if (t == null) {
-            break;
-        } else if ((type(t) == glyph_node) && (subtype(t) < 256)){
-            fast_metatable_top(t);
-            return 1;
-        } else {
-            t = vlink(t);
-        }
+    if (t == null) {
+        lua_pushnil(L);
+    } else {
+        fast_metatable_top(t);
     }
     return 1;
 }
 
-static int lua_nodelib_traverse_char(lua_State * L)
+static int lua_nodelib_traverse(lua_State * L)
 {
     halfword n;
     if (lua_isnil(L, 1)) {
@@ -3000,47 +3419,47 @@ static int lua_nodelib_traverse_char(lua_State * L)
         return 1;
     }
     n = *check_isnode(L, 1);
-    lua_pushcclosure(L, nodelib_aux_next_char, 0);
+    lua_pushcclosure(L, nodelib_aux_next, 0);
     lua_nodelib_push_fast(L, n);
     lua_pushnil(L);
     return 3;
 }
 
-/* node.direct.traverse */
-
-static int nodelib_direct_aux_next(lua_State * L)
+static int nodelib_aux_next_char(lua_State * L)
 {
     halfword t;            /* traverser */
+    halfword *a;
     if (lua_isnil(L, 2)) { /* first call */
-        t = lua_tointeger(L,1) ;
+        t = *check_isnode(L, 1);
         lua_settop(L,1);
     } else {
-        t = lua_tointeger(L,2) ;
+        t = *check_isnode(L, 2);
         t = vlink(t);
         lua_settop(L,2);
     }
-    if (t == null) {
-        lua_pushnil(L);
-    } else {
-        lua_pushinteger(L,t);
+    while (1) {
+        if (t == null) {
+            break;
+        } else if ((type(t) == glyph_node) && (subtype(t) < 256)){
+            fast_metatable_top(t);
+            return 1;
+        } else {
+            t = vlink(t);
+        }
     }
     return 1;
 }
 
-static int lua_nodelib_direct_traverse(lua_State * L)
+static int lua_nodelib_traverse_char(lua_State * L)
 {
     halfword n;
     if (lua_isnil(L, 1)) {
         lua_pushcclosure(L, nodelib_aux_nil, 0);
         return 1;
     }
-    n = (halfword) lua_tointeger(L, 1);
-    if (n == null) {
-        lua_pushcclosure(L, nodelib_aux_nil, 0);
-        return 1;
-    }
-    lua_pushcclosure(L, nodelib_direct_aux_next, 0);
-    lua_pushinteger(L,n);
+    n = *check_isnode(L, 1);
+    lua_pushcclosure(L, nodelib_aux_next_char, 0);
+    lua_nodelib_push_fast(L, n);
     lua_pushnil(L);
     return 3;
 }
@@ -3060,23 +3479,8 @@ static int do_lua_nodelib_count(lua_State * L, halfword match, int i, halfword f
     return 1;
 }
 
-/* node.length */
-
-static int lua_nodelib_length(lua_State * L)
-{
-    halfword n;
-    halfword m = null;
-    if (lua_isnil(L, 1)) {
-        lua_pushinteger(L, 0);
-        return 1;
-    }
-    n = *check_isnode(L, 1);
-    if (lua_gettop(L) == 2)
-        m = *check_isnode(L, 2);
-    return do_lua_nodelib_count(L, m, -1, n);
-}
-
 /* node.direct.length */
+/* node.direct.count */
 
 static int lua_nodelib_direct_length(lua_State * L)
 {
@@ -3090,8 +3494,32 @@ static int lua_nodelib_direct_length(lua_State * L)
     return do_lua_nodelib_count(L, m, -1, n);
 }
 
+static int lua_nodelib_direct_count(lua_State * L)
+{
+    return do_lua_nodelib_count(L,
+        (halfword) lua_tointeger(L, 3), /* m */
+        (int) lua_tointeger(L, 1),      /* i */
+        (halfword) lua_tointeger(L, 2)  /* n */
+    );
+}
+
+/* node.length */
 /* node.count */
 
+static int lua_nodelib_length(lua_State * L)
+{
+    halfword n;
+    halfword m = null;
+    if (lua_isnil(L, 1)) {
+        lua_pushinteger(L, 0);
+        return 1;
+    }
+    n = *check_isnode(L, 1);
+    if (lua_gettop(L) == 2)
+        m = *check_isnode(L, 2);
+    return do_lua_nodelib_count(L, m, -1, n);
+}
+
 static int lua_nodelib_count(lua_State * L)
 {
     halfword n;
@@ -3107,17 +3535,6 @@ static int lua_nodelib_count(lua_State * L)
     return do_lua_nodelib_count(L, m, i, n);
 }
 
-/* node.direct.count */
-
-static int lua_nodelib_direct_count(lua_State * L)
-{
-    return do_lua_nodelib_count(L,
-        (halfword) lua_tointeger(L, 3), /* m */
-        (int) lua_tointeger(L, 1),      /* i */
-        (halfword) lua_tointeger(L, 2)  /* n */
-    );
-}
-
 /* getting and setting fields (helpers) */
 
 int nodelib_getlist(lua_State * L, int n)
@@ -4527,7 +4944,7 @@ static int lua_nodelib_direct_getfield(lua_State * L)
             lua_pushnil(L);
         }
     } else if (t == margin_kern_node) {
-        if (lua_key_eq(s, width)) {
+        if (lua_key_eq(s, kern) ||lua_key_eq(s, width)) {
             lua_pushinteger(L, width(n));
         } else if (lua_key_eq(s, glyph)) {
             nodelib_pushdirect_or_nil(margin_char(n));
@@ -5861,7 +6278,7 @@ static int lua_nodelib_fast_setfield(lua_State * L)
     } else if (t == margin_kern_node) {
         if (lua_key_eq(s, subtype)) {
             subtype(n) = (quarterword) lua_tointeger(L, 3);
-        } else if (lua_key_eq(s, width)) {
+        } else if (lua_key_eq(s, width) || lua_key_eq(s, kern)) {
             width(n) = (halfword) lua_roundnumber(L, 3);
         } else if (lua_key_eq(s, glyph)) {
             margin_char(n) = nodelib_getlist(L, 3);
@@ -6090,417 +6507,154 @@ static int lua_nodelib_direct_setfield_whatsit(lua_State * L, int n, const char
         } else if (lua_key_eq(s, data)) {
             pdf_annot_data(n) = nodelib_gettoks(L, 3);
         } else {
-            return nodelib_cantset(L, n, s);
-        }
-    } else if (t == pdf_dest_node) {
-        if (lua_key_eq(s, width)) {
-            width(n) = (halfword) lua_roundnumber(L, 3);
-        } else if (lua_key_eq(s, depth)) {
-            depth(n) = (halfword) lua_roundnumber(L, 3);
-        } else if (lua_key_eq(s, height)) {
-            height(n) = (halfword) lua_roundnumber(L, 3);
-        } else if (lua_key_eq(s, named_id)) {
-            pdf_dest_named_id(n) = (quarterword) lua_tointeger(L, 3);
-        } else if (lua_key_eq(s, dest_id)) {
-            if (pdf_dest_named_id(n) == 1) {
-                pdf_dest_id(n) = nodelib_gettoks(L, 3);
-            } else {
-                pdf_dest_id(n) = (halfword) lua_tointeger(L, 3);
-            }
-        } else if (lua_key_eq(s, dest_type)) {
-            pdf_dest_type(n) = (quarterword) lua_tointeger(L, 3);
-        } else if (lua_key_eq(s, xyz_zoom)) {
-            pdf_dest_xyz_zoom(n) = (halfword) lua_tointeger(L, 3);
-        } else if (lua_key_eq(s, objnum)) {
-            pdf_dest_objnum(n) = (halfword) lua_tointeger(L, 3);
-        } else {
-            return nodelib_cantset(L, n, s);
-        }
-    } else if (t == pdf_setmatrix_node) {
-        if (lua_key_eq(s, data)) {
-            pdf_setmatrix_data(n) = nodelib_gettoks(L, 3);
-        } else {
-            return nodelib_cantset(L, n, s);
-        }
-    } else if (t == pdf_refobj_node) {
-        if (lua_key_eq(s, objnum)) {
-            pdf_obj_objnum(n) = (halfword) lua_tointeger(L, 3);
-        } else {
-            return nodelib_cantset(L, n, s);
-        }
-    } else if (t == pdf_start_link_node) {
-        if (lua_key_eq(s, width)) {
-            width(n) = (halfword) lua_roundnumber(L, 3);
-        } else if (lua_key_eq(s, depth)) {
-            depth(n) = (halfword) lua_roundnumber(L, 3);
-        } else if (lua_key_eq(s, height)) {
-            height(n) = (halfword) lua_roundnumber(L, 3);
-        } else if (lua_key_eq(s, objnum)) {
-            pdf_link_objnum(n) = (halfword) lua_tointeger(L, 3);
-        } else if (lua_key_eq(s, link_attr)) {
-            pdf_link_attr(n) = nodelib_gettoks(L, 3);
-        } else if (lua_key_eq(s, action)) {
-            pdf_link_action(n) = nodelib_popdirect(n);  /*nodelib_getaction(L, 3);*/
-        } else {
-            return nodelib_cantset(L, n, s);
-        }
-    } else if (t == write_node) {
-        if (lua_key_eq(s, stream)) {
-            write_stream(n) = (halfword) lua_tointeger(L, 3);
-        } else if (lua_key_eq(s, data)) {
-            write_tokens(n) = nodelib_gettoks(L, 3);
-        } else {
-            return nodelib_cantset(L, n, s);
-        }
-    } else if (t == pdf_colorstack_node) {
-        if (lua_key_eq(s, stack)) {
-            pdf_colorstack_stack(n) = (halfword) lua_tointeger(L, 3);
-        } else if (lua_key_eq(s, command)) {
-            pdf_colorstack_cmd(n) = (halfword) lua_tointeger(L, 3);
-        } else if (lua_key_eq(s, data)) {
-            pdf_colorstack_data(n) = nodelib_gettoks(L, 3);
-        } else {
-            return nodelib_cantset(L, n, s);
-        }
-    } else if (t == pdf_action_node) {
-        if (lua_key_eq(s, action_type)) {
-            pdf_action_type(n) = (quarterword) lua_tointeger(L, 3);
-        } else if (lua_key_eq(s, named_id)) {
-            pdf_action_named_id(n) = (quarterword) lua_tointeger(L, 3);
-        } else if (lua_key_eq(s, action_id)) {
-            if (pdf_action_named_id(n) == 1) {
-                pdf_action_id(n) = nodelib_gettoks(L, 3);
-            } else {
-                pdf_action_id(n) = (halfword) lua_tointeger(L, 3);
-            }
-        } else if (lua_key_eq(s, file)) {
-            pdf_action_file(n) = nodelib_gettoks(L, 3);
-        } else if (lua_key_eq(s, new_window)) {
-            pdf_action_new_window(n) = (halfword) lua_tointeger(L, 3);
-        } else if (lua_key_eq(s, data)) {
-            pdf_action_tokens(n) = nodelib_gettoks(L, 3);
-        } else {
-            return nodelib_cantset(L, n, s);
-        }
-    } else if ((t == pdf_thread_node) || (t == pdf_start_thread_node)) {
-        if (lua_key_eq(s, width)) {
-            width(n) = (halfword) lua_roundnumber(L, 3);
-        } else if (lua_key_eq(s, depth)) {
-            depth(n) = (halfword) lua_roundnumber(L, 3);
-        } else if (lua_key_eq(s, height)) {
-            height(n) = (halfword) lua_roundnumber(L, 3);
-        } else if (lua_key_eq(s, named_id)) {
-            pdf_thread_named_id(n) = (quarterword) lua_tointeger(L, 3);
-        } else if (lua_key_eq(s, thread_id)) {
-            if (pdf_thread_named_id(n) == 1) {
-                pdf_thread_id(n) = nodelib_gettoks(L, 3);
-            } else {
-                pdf_thread_id(n) = (halfword) lua_tointeger(L, 3);
-            }
-        } else if (lua_key_eq(s, thread_attr)) {
-            pdf_thread_attr(n) = nodelib_gettoks(L, 3);
-        } else {
-            return nodelib_cantset(L, n, s);
-        }
-    } else if (t == special_node) {
-        if (lua_key_eq(s, data)) {
-            write_tokens(n) = nodelib_gettoks(L, 3);
-        } else {
-            return nodelib_cantset(L, n, s);
-        }
-    } else if (t == open_node) {
-        if (lua_key_eq(s, stream)) {
-            write_stream(n) = (halfword) lua_tointeger(L, 3);
-        } else if (lua_key_eq(s, name)) {
-            open_name(n) = nodelib_getstring(L, 3);
-        } else if (lua_key_eq(s, area)) {
-            open_area(n) = nodelib_getstring(L, 3);
-        } else if (lua_key_eq(s, ext)) {
-            open_ext(n) = nodelib_getstring(L, 3);
-        } else {
-            return nodelib_cantset(L, n, s);
-        }
-    } else if (t == close_node) {
-        if (lua_key_eq(s, stream)) {
-            write_stream(n) = (halfword) lua_tointeger(L, 3);
-        } else {
-            return nodelib_cantset(L, n, s);
-        }
-    } else if ((t == pdf_end_link_node) || (t == pdf_end_thread_node) || (t == save_pos_node) ||
-               (t == pdf_save_node)     || (t == pdf_restore_node)) {
-        return nodelib_cantset(L, n, s);
-    } else {
-        /* do nothing */
-    }
-    return 0;
-}
-
-static int lua_nodelib_direct_setcharacter(lua_State * L)
-{
-    halfword n = lua_tointeger(L, 1);
-    if ((n) && (lua_type(L, 2) == LUA_TNUMBER)) {
-        if (type(n) == glyph_node) {
-            character(n) = (halfword) lua_tointeger(L, 2);
-        } else if ((type(n) == math_char_node) || (type(n) == math_text_char_node)) {
-            math_character(n) = (halfword) lua_tointeger(L, 2);
-        }
-    }
-    return 0;
-}
-
-static int lua_nodelib_direct_setfont(lua_State * L) /* family_font is not yet in manual, what does arg 2 do */
-{
-    halfword n = lua_tointeger(L, 1);
-    if (n != null) {
-        halfword t = type(n);
-        /* mandate font */
-        if (t == glyph_node) {
-            font(n) = (halfword) lua_tointeger(L,2);
-            /* optional char */
-            if ((lua_type(L, 3) == LUA_TNUMBER)) {
-                character(n) = (halfword) lua_tointeger(L, 3);
-            }
-        }
-    }
-    return 0;
-}
-
-
-static int lua_nodelib_direct_setcomponents(lua_State * L)
-{
-    halfword n = lua_tointeger(L, 1);
-    if ((n) && (lua_type(L, 2) == LUA_TNUMBER)) {
-        if (type(n) == glyph_node) {
-            lig_ptr(n) = (halfword) lua_tointeger(L, 2);
-        }
-    }
-    return 0;
-}
-
-static int lua_nodelib_direct_setattributelist(lua_State * L)
-{
-    halfword n = lua_tointeger(L, 1);
-    if ((n) && nodetype_has_attributes(type(n))) {
-        if (lua_type(L, 2) == LUA_TNUMBER) {
-            halfword a =lua_tointeger(L, 2);
-            if (type(a) == attribute_list_node) {
-                reassign_attribute(n,a);
-            } else if (nodetype_has_attributes(type(a))) {
-                reassign_attribute(n,node_attr(a));
-            } else {
-                reassign_attribute(n,null);
-            }
-        } else {
-            reassign_attribute(n,null);
-        }
-        return 0;
-    }
-    return 0;
-}
-
-static int lua_nodelib_direct_setlang(lua_State * L)
-{
-    halfword n = lua_tointeger(L, 1);
-    if ((n) && (lua_type(L, 2) == LUA_TNUMBER)) {
-        if (type(n) == glyph_node) {
-            set_char_lang(n,lua_tointeger(L, 2));
-        }
-    }
-    return 0;
-}
-
-static int lua_nodelib_direct_setpenalty(lua_State * L)
-{
-    halfword n = lua_tointeger(L, 1);
-    if (n == null) {
-        if (type(n) == penalty_node) {
-            if (lua_type(L, 2) == LUA_TNUMBER) {
-                penalty(n) = (halfword) lua_tointeger(L, 2);
-            } else {
-                penalty(n) = 0;
-            }
-        } else if (type(n) == disc_node) {
-            if (lua_type(L, 2) == LUA_TNUMBER) {
-                disc_penalty(n) = (halfword) lua_tointeger(L, 2);
-            } else {
-                penalty(n) = 0;
-            }
-        }
-    }
-    return 0;
-}
-
-static int lua_nodelib_direct_setkern(lua_State * L)
-{
-    halfword n = lua_tointeger(L, 1);
-    if (n != null) {
-        if (type(n) == kern_node || type(n) == margin_kern_node) {
-            if (lua_type(L, 2) == LUA_TNUMBER) {
-                width(n) = (halfword) lua_tointeger(L, 2);
-            } else {
-                width(n) = 0;
-            }
-            if (lua_type(L, 3) == LUA_TNUMBER) {
-                subtype(n) = (halfword) lua_tointeger(L, 3);
-            }
-        } else if (type(n) == math_node) {
-            if (lua_type(L, 2) == LUA_TNUMBER) {
-                surround(n) = (halfword) lua_tointeger(L, 2);
-            } else {
-                surround(n) = 0;
-            }
-        }
-    }
-    return 0;
-}
-
-static int lua_nodelib_direct_setdir(lua_State * L)
-{
-    halfword n = lua_tointeger(L, 1);
-    if (n != null) {
-        if (type(n) == dir_node) {
-            dir_dir(n) = nodelib_getdir(L, 2, 0);
-        } else if (type(n) == hlist_node || type(n) == vlist_node) {
-            box_dir(n) = nodelib_getdir(L, 2, 1);
-        } else if (type(n) == rule_node) {
-            rule_dir(n) = nodelib_getdir(L, 2, 1);
-        } else if (type(n) == local_par_node) {
-            local_par_dir(n) = nodelib_getdir(L, 3, 1);
-        }
-    }
-    return 0;
-}
-
-static int lua_nodelib_direct_setoffsets(lua_State * L)
-{
-    halfword n = lua_tointeger(L, 1);
-    if ((n) && (type(n) == glyph_node)) {
-        if ((lua_type(L, 2) == LUA_TNUMBER)) {
-            x_displace(n) = (halfword) lua_tointeger(L, 2);
+            return nodelib_cantset(L, n, s);
         }
-        if ((lua_type(L, 3) == LUA_TNUMBER)) {
-            y_displace(n) = (halfword) lua_tointeger(L, 3);
+    } else if (t == pdf_dest_node) {
+        if (lua_key_eq(s, width)) {
+            width(n) = (halfword) lua_roundnumber(L, 3);
+        } else if (lua_key_eq(s, depth)) {
+            depth(n) = (halfword) lua_roundnumber(L, 3);
+        } else if (lua_key_eq(s, height)) {
+            height(n) = (halfword) lua_roundnumber(L, 3);
+        } else if (lua_key_eq(s, named_id)) {
+            pdf_dest_named_id(n) = (quarterword) lua_tointeger(L, 3);
+        } else if (lua_key_eq(s, dest_id)) {
+            if (pdf_dest_named_id(n) == 1) {
+                pdf_dest_id(n) = nodelib_gettoks(L, 3);
+            } else {
+                pdf_dest_id(n) = (halfword) lua_tointeger(L, 3);
+            }
+        } else if (lua_key_eq(s, dest_type)) {
+            pdf_dest_type(n) = (quarterword) lua_tointeger(L, 3);
+        } else if (lua_key_eq(s, xyz_zoom)) {
+            pdf_dest_xyz_zoom(n) = (halfword) lua_tointeger(L, 3);
+        } else if (lua_key_eq(s, objnum)) {
+            pdf_dest_objnum(n) = (halfword) lua_tointeger(L, 3);
+        } else {
+            return nodelib_cantset(L, n, s);
         }
-    }
-    return 0;
-}
-
-static int lua_nodelib_direct_setnext(lua_State * L)
-{
-    halfword n = lua_tointeger(L, 1);
-    if (n) {
-        if (lua_type(L, 2) == LUA_TNUMBER) {
-            vlink(n) = (halfword) lua_tointeger(L, 2);
+    } else if (t == pdf_setmatrix_node) {
+        if (lua_key_eq(s, data)) {
+            pdf_setmatrix_data(n) = nodelib_gettoks(L, 3);
         } else {
-            vlink(n) = null;
+            return nodelib_cantset(L, n, s);
         }
-    }
-    return 0;
-}
-
-static int lua_nodelib_direct_setprev(lua_State * L)
-{
-    halfword n = lua_tointeger(L, 1);
-    if (n) {
-        if (lua_type(L, 2) == LUA_TNUMBER) {
-            alink(n) = (halfword) lua_tointeger(L, 2);
+    } else if (t == pdf_refobj_node) {
+        if (lua_key_eq(s, objnum)) {
+            pdf_obj_objnum(n) = (halfword) lua_tointeger(L, 3);
         } else {
-            alink(n) = null;
+            return nodelib_cantset(L, n, s);
         }
-    }
-    return 0;
-}
-
-static int lua_nodelib_direct_setboth(lua_State * L)
-{
-    halfword n = lua_tointeger(L, 1);
-    if (n) {
-        if (lua_type(L, 2) == LUA_TNUMBER) {
-            alink(n) = (halfword) lua_tointeger(L, 2);
+    } else if (t == pdf_start_link_node) {
+        if (lua_key_eq(s, width)) {
+            width(n) = (halfword) lua_roundnumber(L, 3);
+        } else if (lua_key_eq(s, depth)) {
+            depth(n) = (halfword) lua_roundnumber(L, 3);
+        } else if (lua_key_eq(s, height)) {
+            height(n) = (halfword) lua_roundnumber(L, 3);
+        } else if (lua_key_eq(s, objnum)) {
+            pdf_link_objnum(n) = (halfword) lua_tointeger(L, 3);
+        } else if (lua_key_eq(s, link_attr)) {
+            pdf_link_attr(n) = nodelib_gettoks(L, 3);
+        } else if (lua_key_eq(s, action)) {
+            pdf_link_action(n) = nodelib_popdirect(n);  /*nodelib_getaction(L, 3);*/
         } else {
-            alink(n) = null;
+            return nodelib_cantset(L, n, s);
         }
-        if (lua_type(L, 3) == LUA_TNUMBER) {
-            vlink(n) = (halfword) lua_tointeger(L, 3);
+    } else if (t == write_node) {
+        if (lua_key_eq(s, stream)) {
+            write_stream(n) = (halfword) lua_tointeger(L, 3);
+        } else if (lua_key_eq(s, data)) {
+            write_tokens(n) = nodelib_gettoks(L, 3);
         } else {
-            vlink(n) = null;
+            return nodelib_cantset(L, n, s);
         }
-    }
-    return 0;
-}
-
-/*
-static int lua_nodelib_direct_setlink(lua_State * L)
-{
-    if (lua_type(L, 1) == LUA_TNUMBER) {
-        halfword a = lua_tointeger(L, 1);
-        if (lua_type(L, 2) == LUA_TNUMBER) {
-            halfword b = lua_tointeger(L, 2);
-            vlink(a) = b;
-            alink(b) = a;
+    } else if (t == pdf_colorstack_node) {
+        if (lua_key_eq(s, stack)) {
+            pdf_colorstack_stack(n) = (halfword) lua_tointeger(L, 3);
+        } else if (lua_key_eq(s, command)) {
+            pdf_colorstack_cmd(n) = (halfword) lua_tointeger(L, 3);
+        } else if (lua_key_eq(s, data)) {
+            pdf_colorstack_data(n) = nodelib_gettoks(L, 3);
         } else {
-            vlink(a) = null;
+            return nodelib_cantset(L, n, s);
         }
-    } else if (lua_type(L, 2) == LUA_TNUMBER) {
-        halfword b = lua_tointeger(L, 2);
-        alink(b) = null;
-    }
-    return 0;
-}
-*/
-
-/*
-    a b b nil c d         : prev-a-b-c-next
-    nil a b b nil c d nil : nil-a-b-c-nil
-*/
-
-static int lua_nodelib_direct_setlink(lua_State * L)
-{
-    int n = lua_gettop(L);
-    int i;
-    halfword h = null; /* head node */
-    halfword t = null; /* tail node */
-    halfword c = null; /* current node */
-    for (i=1;i<=n;i++) {
-        /*
-            we don't go for the tail of the current node because we can inject
-            between existing nodes and the nodes themselves can have old values
-            for prev and next, so ... only single nodes are looked at!
-        */
-        if (lua_type(L, i) == LUA_TNUMBER) {
-            c = lua_tointeger(L, i);
-            if (c != t) {
-                if (t != null) {
-                    vlink(t) = c;
-                    alink(c) = t;
-                } else if (i > 1) {
-                    /* we assume that the first node is a kind of head */
-                    alink(c) = null;
-                }
-                t = c;
-                if (h == null) {
-                    h = t;
-                }
+    } else if (t == pdf_action_node) {
+        if (lua_key_eq(s, action_type)) {
+            pdf_action_type(n) = (quarterword) lua_tointeger(L, 3);
+        } else if (lua_key_eq(s, named_id)) {
+            pdf_action_named_id(n) = (quarterword) lua_tointeger(L, 3);
+        } else if (lua_key_eq(s, action_id)) {
+            if (pdf_action_named_id(n) == 1) {
+                pdf_action_id(n) = nodelib_gettoks(L, 3);
             } else {
-                /* we ignore duplicate nodes which can be tails or the previous */
+                pdf_action_id(n) = (halfword) lua_tointeger(L, 3);
             }
-        } else if (t == null) {
-            /* we just ignore nil nodes and have no tail yet */
+        } else if (lua_key_eq(s, file)) {
+            pdf_action_file(n) = nodelib_gettoks(L, 3);
+        } else if (lua_key_eq(s, new_window)) {
+            pdf_action_new_window(n) = (halfword) lua_tointeger(L, 3);
+        } else if (lua_key_eq(s, data)) {
+            pdf_action_tokens(n) = nodelib_gettoks(L, 3);
         } else {
-            /* safeguard: a nil in the list can be meant as end so we nil the next of tail */
-            vlink(t) = null;
+            return nodelib_cantset(L, n, s);
         }
-    }
-    if (h == null) {
-        /* no head */
-        lua_pushnil(L);
+    } else if ((t == pdf_thread_node) || (t == pdf_start_thread_node)) {
+        if (lua_key_eq(s, width)) {
+            width(n) = (halfword) lua_roundnumber(L, 3);
+        } else if (lua_key_eq(s, depth)) {
+            depth(n) = (halfword) lua_roundnumber(L, 3);
+        } else if (lua_key_eq(s, height)) {
+            height(n) = (halfword) lua_roundnumber(L, 3);
+        } else if (lua_key_eq(s, named_id)) {
+            pdf_thread_named_id(n) = (quarterword) lua_tointeger(L, 3);
+        } else if (lua_key_eq(s, thread_id)) {
+            if (pdf_thread_named_id(n) == 1) {
+                pdf_thread_id(n) = nodelib_gettoks(L, 3);
+            } else {
+                pdf_thread_id(n) = (halfword) lua_tointeger(L, 3);
+            }
+        } else if (lua_key_eq(s, thread_attr)) {
+            pdf_thread_attr(n) = nodelib_gettoks(L, 3);
+        } else {
+            return nodelib_cantset(L, n, s);
+        }
+    } else if (t == special_node) {
+        if (lua_key_eq(s, data)) {
+            write_tokens(n) = nodelib_gettoks(L, 3);
+        } else {
+            return nodelib_cantset(L, n, s);
+        }
+    } else if (t == open_node) {
+        if (lua_key_eq(s, stream)) {
+            write_stream(n) = (halfword) lua_tointeger(L, 3);
+        } else if (lua_key_eq(s, name)) {
+            open_name(n) = nodelib_getstring(L, 3);
+        } else if (lua_key_eq(s, area)) {
+            open_area(n) = nodelib_getstring(L, 3);
+        } else if (lua_key_eq(s, ext)) {
+            open_ext(n) = nodelib_getstring(L, 3);
+        } else {
+            return nodelib_cantset(L, n, s);
+        }
+    } else if (t == close_node) {
+        if (lua_key_eq(s, stream)) {
+            write_stream(n) = (halfword) lua_tointeger(L, 3);
+        } else {
+            return nodelib_cantset(L, n, s);
+        }
+    } else if ((t == pdf_end_link_node) || (t == pdf_end_thread_node) || (t == save_pos_node) ||
+               (t == pdf_save_node)     || (t == pdf_restore_node)) {
+        return nodelib_cantset(L, n, s);
     } else {
-        /* first valid head */
-        lua_pushinteger(L,h);
+        /* do nothing */
     }
-    return 1;
+    return 0;
 }
 
+/* direct.is_char  */
+/* direct.is_glyph */
+
 static int lua_nodelib_direct_is_char(lua_State * L)
 {
     halfword n = lua_tointeger(L, 1);
@@ -6536,38 +6690,7 @@ static int lua_nodelib_direct_is_glyph(lua_State * L)
     return 2;
 }
 
-static int lua_nodelib_direct_setdiscretionary(lua_State * L)
-{
-    halfword n = lua_tointeger(L, 1);
-    if (type(n) == disc_node) {
-        int t = lua_gettop(L) ;
-        if (t > 1) {
-            set_disc_field(pre_break(n), lua_tointeger(L,2));
-            if (t > 2) {
-                set_disc_field(post_break(n), lua_tointeger(L,3));
-                if (t > 3) {
-                    set_disc_field(no_break(n), lua_tointeger(L,4));
-                    if (t > 4) {
-                        subtype(n) = (quarterword) lua_tointeger(L,5);
-                        if (t > 5) {
-                            disc_penalty(n) = lua_tointeger(L,6);
-                        }
-                    }
-                } else {
-                    set_disc_field(no_break(n), null);
-                }
-            } else {
-                set_disc_field(post_break(n), null);
-                set_disc_field(no_break(n), null);
-            }
-        } else {
-            set_disc_field(pre_break(n), null);
-            set_disc_field(post_break(n), null);
-            set_disc_field(no_break(n), null);
-        }
-    }
-    return 0;
-}
+/* direct.setfield */
 
 static int lua_nodelib_direct_setfield(lua_State * L)
 {
@@ -6960,7 +7083,7 @@ static int lua_nodelib_direct_setfield(lua_State * L)
     } else if (t == margin_kern_node) {
         if (lua_key_eq(s, subtype)) {
             subtype(n) = (quarterword) lua_tointeger(L, 3);
-        } else if (lua_key_eq(s, width)) {
+        } else if (lua_key_eq(s, width) || lua_key_eq(s, width)) {
             width(n) = (halfword) lua_roundnumber(L, 3);
         } else if (lua_key_eq(s, glyph)) {
             margin_char(n) = nodelib_popdirect(3);
@@ -7112,8 +7235,10 @@ static int direct_get_box_id(lua_State * L, int i)
 }
 
 /* node.getbox = tex.getbox */
+/* node.setbox = tex.setbox */
 
 /* node.direct.getbox */
+/* node.direct.setbox */
 
 static int lua_nodelib_direct_getbox(lua_State * L)
 {
@@ -7129,9 +7254,6 @@ static int lua_nodelib_direct_getbox(lua_State * L)
     return 1;
 }
 
-/* node.setbox = tex.setbox */
-/* node.setbox */
-
 static int lua_nodelib_direct_setbox(lua_State * L)
 {
     int isglobal = 0;
@@ -7504,15 +7626,19 @@ static const struct luaL_Reg direct_nodelib_f[] = {
     {"flush_node", lua_nodelib_direct_flush_node},
     {"free", lua_nodelib_direct_free},
     {"getbox", lua_nodelib_direct_getbox},
-    {"getchar", lua_nodelib_direct_getcharacter},
+    {"getchar", lua_nodelib_direct_getchar},
     {"getcomponents", lua_nodelib_direct_getcomponents},
     {"getlang", lua_nodelib_direct_getlang},
     {"getkern", lua_nodelib_direct_getkern},
     {"getpenalty", lua_nodelib_direct_getpenalty},
     {"getdir", lua_nodelib_direct_getdir},
     {"getoffsets", lua_nodelib_direct_getoffsets},
-    {"getdisc", lua_nodelib_direct_getdiscretionary},
+    {"getdisc", lua_nodelib_direct_getdisc},
     {"getwhd", lua_nodelib_direct_getwhd},
+    {"getwidth", lua_nodelib_direct_getwidth},
+    {"getheight", lua_nodelib_direct_getheight},
+    {"getdepth", lua_nodelib_direct_getdepth},
+    {"getshift", lua_nodelib_direct_getshift},
     {"getfield", lua_nodelib_direct_getfield},
     {"getfont", lua_nodelib_direct_getfont},
     {"getid", lua_nodelib_direct_getid},
@@ -7523,6 +7649,9 @@ static const struct luaL_Reg direct_nodelib_f[] = {
     {"getleader", lua_nodelib_direct_getleader},
     {"getsubtype", lua_nodelib_direct_getsubtype},
     {"getattributelist", lua_nodelib_direct_getattributelist},
+    {"getnucleus", lua_nodelib_direct_getnucleus},
+    {"getsub", lua_nodelib_direct_getsub},
+    {"getsup", lua_nodelib_direct_getsup},
     {"has_glyph", lua_nodelib_direct_has_glyph},
     {"has_attribute", lua_nodelib_direct_has_attribute},
     {"get_attribute", lua_nodelib_direct_get_attribute},
@@ -7550,7 +7679,7 @@ static const struct luaL_Reg direct_nodelib_f[] = {
     {"set_attribute", lua_nodelib_direct_set_attribute},
     {"setbox", lua_nodelib_direct_setbox},
     {"setfield", lua_nodelib_direct_setfield},
-    {"setchar", lua_nodelib_direct_setcharacter},
+    {"setchar", lua_nodelib_direct_setchar},
     {"setfont", lua_nodelib_direct_setfont},
     {"setcomponents", lua_nodelib_direct_setcomponents},
     {"setlang", lua_nodelib_direct_setlang},
@@ -7558,16 +7687,24 @@ static const struct luaL_Reg direct_nodelib_f[] = {
     {"setpenalty", lua_nodelib_direct_setpenalty},
     {"setdir", lua_nodelib_direct_setdir},
     {"setoffsets", lua_nodelib_direct_setoffsets},
-    {"setdisc", lua_nodelib_direct_setdiscretionary},
+    {"setdisc", lua_nodelib_direct_setdisc},
     {"setwhd", lua_nodelib_direct_setwhd},
+    {"setwidth", lua_nodelib_direct_setwidth},
+    {"setheight", lua_nodelib_direct_setheight},
+    {"setdepth", lua_nodelib_direct_setdepth},
+    {"setshift", lua_nodelib_direct_setshift},
     {"setnext", lua_nodelib_direct_setnext},
     {"setprev", lua_nodelib_direct_setprev},
     {"setboth", lua_nodelib_direct_setboth},
     {"setlink", lua_nodelib_direct_setlink},
+    {"unlink", lua_nodelib_direct_unlink},
     {"setlist", lua_nodelib_direct_setlist},
     {"setleader", lua_nodelib_direct_setleader},
     {"setsubtype", lua_nodelib_direct_setsubtype},
     {"setattributelist", lua_nodelib_direct_setattributelist},
+    {"setnucleus", lua_nodelib_direct_setnucleus},
+    {"setsub", lua_nodelib_direct_setsub},
+    {"setsup", lua_nodelib_direct_setsup},
     {"slide", lua_nodelib_direct_slide},
  /* {"subtype", lua_nodelib_subtype}, */ /* no node argument */
     {"tail", lua_nodelib_direct_tail},
@@ -7621,14 +7758,14 @@ static const struct luaL_Reg nodelib_f[] = {
     {"getnext", lua_nodelib_getnext},
     {"getprev", lua_nodelib_getprev},
     {"getboth", lua_nodelib_getboth},
-    {"getdisc", lua_nodelib_getdiscretionary},
+    {"getdisc", lua_nodelib_getdisc},
     {"getwhd", lua_nodelib_getwhd},
     {"getlist", lua_nodelib_getlist},
     {"getleader", lua_nodelib_getleader},
     {"getid", lua_nodelib_getid},
     {"getsubtype", lua_nodelib_getsubtype},
     {"getfont", lua_nodelib_getfont},
-    {"getchar", lua_nodelib_getcharacter},
+    {"getchar", lua_nodelib_getchar},
     {"getfield", lua_nodelib_getfield},
     {"setfield", lua_nodelib_setfield},
     {"has_glyph", lua_nodelib_has_glyph},
diff --git a/source/texk/web2c/luatexdir/lua/ltexlib.c b/source/texk/web2c/luatexdir/lua/ltexlib.c
index 04ab2c8079d3d6345b6e1a0c22a2b7a9dca35abb..a38b608e40fd1af53cc24eb43cd477e929714500 100644
--- a/source/texk/web2c/luatexdir/lua/ltexlib.c
+++ b/source/texk/web2c/luatexdir/lua/ltexlib.c
@@ -898,21 +898,11 @@ static int setglue(lua_State * L)
         top -= 1;
     }
     /* [global] slot [width] [stretch] [shrink] [stretch_order] [shrink_order] */
-    if (top > 1) {
-        width(value) = lua_roundnumber(L,index+1);
-    }
-    if (top > 2) {
-        stretch(value) = lua_roundnumber(L,index+2);
-    }
-    if (top > 3) {
-        shrink(value) = lua_roundnumber(L,index+3);
-    }
-    if (top > 4) {
-        stretch_order(value) = lua_tointeger(L,index+4);
-    }
-    if (top > 5) {
-        shrink_order(value) = lua_tointeger(L,index+5);
-    }
+    if (top > 1) { width(value) = lua_roundnumber(L,index+1); }
+    if (top > 2) { stretch(value) = lua_roundnumber(L,index+2); }
+    if (top > 3) { shrink(value) = lua_roundnumber(L,index+3); }
+    if (top > 4) { stretch_order(value) = lua_tointeger(L,index+4); }
+    if (top > 5) { shrink_order(value) = lua_tointeger(L,index+5); }
     set_item_index_plus(L, index, skip_base, "skip", value, isglobal, is_glue_assign, set_tex_skip_register, true);
     return 0;
 }
@@ -921,24 +911,15 @@ static int getglue(lua_State * L)
 {
     int value = 0;
     int top = lua_gettop(L);
-    int b = -1; /* false: only width, true or unset: 5 values */
-    if (lua_type(L, top) == LUA_TBOOLEAN) {
-        b = lua_toboolean(L, top);
-        top -= 1 ;
-    }
     get_item_index_plus(L, top, skip_base, "skip", value, is_glue_assign, get_tex_skip_register, true);
     if (value == null) {
         lua_pushinteger(L,0);
-        if (b == 0)
-            return 1;
         lua_pushinteger(L,0);
         lua_pushinteger(L,0);
         lua_pushinteger(L,0);
         lua_pushinteger(L,0);
     } else {
         lua_pushinteger(L,width(value));
-        if (b == 0)
-            return 1;
         lua_pushinteger(L,stretch(value));
         lua_pushinteger(L,shrink(value));
         lua_pushinteger(L,stretch_order(value));
@@ -983,21 +964,11 @@ static int setmuglue(lua_State * L)
         top -= 1;
     }
     /* [global] slot [width] [stretch] [shrink] [stretch_order] [shrink_order] */
-    if (top > 1) {
-        width(value) = lua_roundnumber(L,index+1);
-    }
-    if (top > 2) {
-        stretch(value) = lua_roundnumber(L,index+2);
-    }
-    if (top > 3) {
-        shrink(value) = lua_roundnumber(L,index+3);
-    }
-    if (top > 4) {
-        stretch_order(value) = lua_tointeger(L,index+4);
-    }
-    if (top > 5) {
-        shrink_order(value) = lua_tointeger(L,index+5);
-    }
+    if (top > 1) { width(value) = lua_roundnumber(L,index+1); }
+    if (top > 2) { stretch(value) = lua_roundnumber(L,index+2); }
+    if (top > 3) { shrink(value) = lua_roundnumber(L,index+3); }
+    if (top > 4) { stretch_order(value) = lua_tointeger(L,index+4); }
+    if (top > 5) { shrink_order(value) = lua_tointeger(L,index+5); }
     set_item_index_plus(L, index, mu_skip_base, "muskip", value, isglobal, is_mu_glue_assign, set_tex_mu_skip_register, true);
     return 0;
 }
@@ -1709,26 +1680,18 @@ static int settex(lua_State * L)
                 assign_internal_value((isglobal ? 4 : 0), equiv(cur_cs1), j);
             } else if (is_glue_assign(cur_cmd1)) {
                 int a = isglobal;
-if (lua_type(L, i) == LUA_TNUMBER) {
-                halfword value = copy_node(zero_glue);
-                width(value) = lua_roundnumber(L,i);
-                if (i > 1) {
-                    stretch(value) = lua_roundnumber(L,i+1);
-                }
-                if (i > 3) {
-                    shrink(value) = lua_roundnumber(L,i+2);
-                }
-                if (i > 4) {
-                    stretch_order(value) = lua_tointeger(L,i+3);
-                }
-                if (i > 5) {
-                    shrink_order(value) = lua_tointeger(L,i+4);
+                if (lua_type(L, i) == LUA_TNUMBER) {
+                    halfword value = copy_node(zero_glue);
+                    width(value) = lua_roundnumber(L,i);
+                    if (i > 1) { stretch(value) = lua_roundnumber(L,i+1); }
+                    if (i > 3) { shrink(value) = lua_roundnumber(L,i+2); }
+                    if (i > 4) { stretch_order(value) = lua_tointeger(L,i+3); }
+                    if (i > 5) { shrink_order(value) = lua_tointeger(L,i+4); }
+                    define(equiv(cur_cs1), assign_glue_cmd, value);
+                } else {
+                    halfword *j1 = check_isnode(L, i);     /* the value */
+                    define(equiv(cur_cs1), assign_glue_cmd, *j1);
                 }
-                define(equiv(cur_cs1), assign_glue_cmd, value);
-} else {
-                halfword *j1 = check_isnode(L, i);     /* the value */
-                define(equiv(cur_cs1), assign_glue_cmd, *j1);
-}
             } else if (is_toks_assign(cur_cmd1)) {
                 if (lua_type(L,i) == LUA_TSTRING) {
                     j = tokenlist_from_lua(L);  /* uses stack -1 */