texlive[61453] Build/source/texk/web2c/luatexdir: sync luatex with

commits+lscarso at tug.org commits+lscarso at tug.org
Fri Dec 31 11:38:51 CET 2021


Revision: 61453
          http://tug.org/svn/texlive?view=revision&revision=61453
Author:   lscarso
Date:     2021-12-31 11:38:50 +0100 (Fri, 31 Dec 2021)
Log Message:
-----------
sync luatex  with upstream r7476.

Revision Links:
--------------
    http://tug.org/svn/texlive?view=revision&revision=7476

Modified Paths:
--------------
    trunk/Build/source/texk/web2c/luatexdir/ChangeLog
    trunk/Build/source/texk/web2c/luatexdir/NEWS
    trunk/Build/source/texk/web2c/luatexdir/am/luaharfbuzz.am
    trunk/Build/source/texk/web2c/luatexdir/font/texfont.c
    trunk/Build/source/texk/web2c/luatexdir/font/tt_glyf.c
    trunk/Build/source/texk/web2c/luatexdir/image/writepng.c
    trunk/Build/source/texk/web2c/luatexdir/lua/lnodelib.c
    trunk/Build/source/texk/web2c/luatexdir/lua/loslibext.c
    trunk/Build/source/texk/web2c/luatexdir/lua/luatex-api.h
    trunk/Build/source/texk/web2c/luatexdir/lua/luatoken.c
    trunk/Build/source/texk/web2c/luatexdir/luaharfbuzz/luaharfbuzz-1.1.0-1.rockspec
    trunk/Build/source/texk/web2c/luatexdir/luaharfbuzz/luaharfbuzz-scm-1.rockspec
    trunk/Build/source/texk/web2c/luatexdir/luaharfbuzz/spec/harfbuzz_spec.lua
    trunk/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/face.c
    trunk/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/font.c
    trunk/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/luaharfbuzz.c
    trunk/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/luaharfbuzz.h
    trunk/Build/source/texk/web2c/luatexdir/luasocket/src/inet.c
    trunk/Build/source/texk/web2c/luatexdir/luasocket/src/inet.h
    trunk/Build/source/texk/web2c/luatexdir/luatex.c
    trunk/Build/source/texk/web2c/luatexdir/luatex_svnversion.h
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfaction.c
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfdest.c
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfdest.h
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfgen.c
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdftables.c
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdftypes.h
    trunk/Build/source/texk/web2c/luatexdir/tex/commands.c
    trunk/Build/source/texk/web2c/luatexdir/tex/commands.h
    trunk/Build/source/texk/web2c/luatexdir/tex/dumpdata.c
    trunk/Build/source/texk/web2c/luatexdir/tex/equivalents.c
    trunk/Build/source/texk/web2c/luatexdir/tex/equivalents.h
    trunk/Build/source/texk/web2c/luatexdir/tex/extensions.c
    trunk/Build/source/texk/web2c/luatexdir/tex/mainbody.c
    trunk/Build/source/texk/web2c/luatexdir/tex/maincontrol.c
    trunk/Build/source/texk/web2c/luatexdir/tex/primitive.c
    trunk/Build/source/texk/web2c/luatexdir/tex/printing.c
    trunk/Build/source/texk/web2c/luatexdir/tex/scanning.c
    trunk/Build/source/texk/web2c/luatexdir/tex/texfileio.c
    trunk/Build/source/texk/web2c/luatexdir/tex/texnodes.c
    trunk/Build/source/texk/web2c/luatexdir/tex/texnodes.h
    trunk/Build/source/texk/web2c/luatexdir/tex/textoken.c

Added Paths:
-----------
    trunk/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/variation.c

Modified: trunk/Build/source/texk/web2c/luatexdir/ChangeLog
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/ChangeLog	2021-12-31 09:18:47 UTC (rev 61452)
+++ trunk/Build/source/texk/web2c/luatexdir/ChangeLog	2021-12-31 10:38:50 UTC (rev 61453)
@@ -1,8 +1,78 @@
-2021-03-23 Siep Kroonenberg  <siepo at bitmuis.nl>
-    *luasocket/src/inet.[ch] (inet_pton, inet_ntop) [_WS2TCPIP_H_]:
-    don't define fns if _WS2TCPIP_H_ is defined; for mingw.
-    https://tug.org/pipermail/tlbuild/2021q4/004980.html
+2021-12-31 Luigi Scarso <luigi.scarso at gmail.com>
+    * drop (for the moment) \showstream
 
+2021-12-30 Luigi Scarso <luigi.scarso at gmail.com>
+    * struct dest (M.Krüger)
+    * fixed  a 'Conditional jump or move depends on uninitialised value(s)' msg from valgrind
+
+2021-12-29 Luigi Scarso <luigi.scarso at gmail.com>
+    * Correctly print \write for the error message 
+      "Forbidden control sequence found while scanning text of"
+      (thanks to Hironobu Yamashita)
+
+2021-12-27 Luigi Scarso <luigi.scarso at gmail.com>
+    * fixed a typo in a tex comment.
+
+2021-12-24 Luigi Scarso <luigi.scarso at gmail.com>
+    * Metapost: make sure that an already open VF is closed before to read a new one
+
+2021-12-21 Luigi Scarso <luigi.scarso at gmail.com>
+    * fixed os.uname on 64 bit Windows (A. Kakuto, L. Scarso)
+
+2021-12-13 Luigi Scarso <luigi.scarso at gmail.com>
+    * fixed a typo in equivalents.c (user202729 @ https://chat.stackexchange.com/transcript/41/2021/12/12)
+
+2021-12-07 Luigi Scarso <luigi.scarso at gmail.com>
+    * Fixed a typo in maincontrol.c (thanks to Hironobu Yamashita)
+
+2021-11-20 Luigi Scarso <luigi.scarso at gmail.com>
+    * Ignore paragraphs with only a local par node followed by direction synchronization
+    nodes (paragraphs like that are seen as empty paragraphs) (HH)
+
+2021-08-28 Luigi Scarso <luigi.scarso at gmail.com>
+    *more efficient fontdimen allocation (HH)
+
+2021-08-12 Luigi Scarso <luigi.scarso at gmail.com>
+    *mplibdir: Fix _findfirst handle truncation on Windows x86_64. 
+     Thanks to Richard Copley.
+
+2021-08-08 Luigi Scarso <luigi.scarso at gmail.com>
+    *Improvements for glyph_stream_provider with TTF fonts (MK)
+
+2021-08-04 Luigi Scarso <luigi.scarso at gmail.com>
+    *Fix named instance inconsistency in luaharfbuzz (MK)
+
+2021-08-03 Luigi Scarso <luigi.scarso at gmail.com>
+    *luaharfbuzz: Provide interface for variable fonts (M.Krüger)
+
+2021-07-30 Luigi Scarso <luigi.scarso at gmail.com>
+    *patch for luamplib  to process string with "char 0"; fixed also mplib_text 
+
+2021-07-30 Luigi Scarso <luigi.scarso at gmail.com>
+    *patch for luamplib  to process string with "char 0"
+
+2021-07-27 Luigi Scarso <luigi.scarso at gmail.com>
+    *partoken primitives (HH & PO)
+
+2021-07-27 Luigi Scarso <luigi.scarso at gmail.com>
+    *Sync with TeX Live revision 60088.
+
+2021-07-27 Luigi Scarso <luigi.scarso at gmail.com>
+    *automake-1.16.4; initialize limit to avoid printing some garbage.
+
+2021-07-02 Luigi Scarso <luigi.scarso at gmail.com>
+    *ePNG /Smask for  pdf 2.0
+
+2021-07-02 Luigi Scarso <luigi.scarso at gmail.com>
+    *sync with upstream texlive; autoconf-2.71.
+
+2021-05-10 Luigi Scarso <luigi.scarso at gmail.com>
+    *MetaPost: fixed the patch on the stack overflow.
+
+2021-05-09 Luigi Scarso <luigi.scarso at gmail.com>
+    *Impose mp->stack_size < 1001 in @d push_input to avoid 
+     stack overflow due infinite recursion of macro expansion (thanks to A. Kakuto).
+
 2021-04-21 Luigi Scarso <luigi.scarso at gmail.com>
     *\discretionaryligaturemode: optionally block select disc creation 
     (see [Dev-luatex] [PATCH] Nested discretionaries M.F. Krüger) (HH)

Modified: trunk/Build/source/texk/web2c/luatexdir/NEWS
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/NEWS	2021-12-31 09:18:47 UTC (rev 61452)
+++ trunk/Build/source/texk/web2c/luatexdir/NEWS	2021-12-31 10:38:50 UTC (rev 61453)
@@ -1,4 +1,38 @@
+
+
 ==============================================================
+LuaTeX 1.14.1 2021-12-30
+==============================================================
+
+struct dest (M.F. Krüger);
+
+Ignore paragraphs with only a local par node followed by 
+direction synchronization nodes (paragraphs like that are seen 
+as empty paragraphs) (Hans Hagen);
+
+more efficient fontdimen allocation (Hans Hagen);
+
+improvements for glyph_stream_provider with TTF fonts (M.F. Krüger);
+
+provide interface for variable fonts in luaharfbuzz (M.F. Krüger);
+
+partoken primitives (Hans Hagen & Petr Olsak);
+
+PNG /Smask for  pdf 2.0;
+
+\discretionaryligaturemode: optionally block select disc creation 
+(see [Dev-luatex] [PATCH] Nested discretionaries M.F. Krüger) (Hans Hagen);
+
+different radical style defaults in mathdefaultsmode 
+(see [Dev-luatex] Uunderdelimiter & friends and mathstyles by M.F. Krüger) (Hans Hagen).
+
+
+Several bug fixes (see ChangeLog).
+
+
+
+
+==============================================================
 LuaTeX 1.13.2 2021-04-10
 ==============================================================
 

Modified: trunk/Build/source/texk/web2c/luatexdir/am/luaharfbuzz.am
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/am/luaharfbuzz.am	2021-12-31 09:18:47 UTC (rev 61452)
+++ trunk/Build/source/texk/web2c/luatexdir/am/luaharfbuzz.am	2021-12-31 10:38:50 UTC (rev 61453)
@@ -35,7 +35,8 @@
 	luatexdir/luaharfbuzz/src/luaharfbuzz/ot.c \
 	luatexdir/luaharfbuzz/src/luaharfbuzz/script.c \
 	luatexdir/luaharfbuzz/src/luaharfbuzz/tag.c \
-	luatexdir/luaharfbuzz/src/luaharfbuzz/unicode.c
+	luatexdir/luaharfbuzz/src/luaharfbuzz/unicode.c \
+	luatexdir/luaharfbuzz/src/luaharfbuzz/variation.c
 
 libluajitharfbuzz_a_SOURCES = $(libluaharfbuzz_a_SOURCES)
 

Modified: trunk/Build/source/texk/web2c/luatexdir/font/texfont.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/texfont.c	2021-12-31 09:18:47 UTC (rev 61452)
+++ trunk/Build/source/texk/web2c/luatexdir/font/texfont.c	2021-12-31 10:38:50 UTC (rev 61453)
@@ -1037,14 +1037,12 @@
     int i;
     i = font_params(f);
     if (i != b) {
-        font_bytes +=
-            (int) ((b - (int) font_params(f) + 1) * (int) sizeof(scaled));
+        font_bytes += (int) ((b - (int) font_params(f) + 1) * (int) sizeof(scaled));
         do_realloc(param_base(f), (b + 2), int);
         font_params(f) = b;
         if (b > i) {
             while (i < b) {
-                i++;
-                set_font_param(f, i, 0);
+                font_param(f, ++i) = 0;
             }
         }
     }
@@ -1055,19 +1053,18 @@
     int i;
     i = font_math_params(f);
     if (i != b) {
-        font_bytes +=
-            ((b - (int) font_math_params(f) + 1) * (int) sizeof(scaled));
+        font_bytes += ((b - (int) font_math_params(f) + 1) * (int) sizeof(scaled));
         do_realloc(math_param_base(f), (b + 2), int);
         font_math_params(f) = b;
         if (b > i) {
             while (i < b) {
-                i++;
-                set_font_math_param(f, i, undefined_math_parameter);
+                font_math_param(f,++i) = undefined_math_parameter;
             }
         }
     }
 }
 
+
 int copy_font(int f)
 {
     int i, ci_cnt, ci_size;

Modified: trunk/Build/source/texk/web2c/luatexdir/font/tt_glyf.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/tt_glyf.c	2021-12-31 09:18:47 UTC (rev 61452)
+++ trunk/Build/source/texk/web2c/luatexdir/font/tt_glyf.c	2021-12-31 10:38:50 UTC (rev 61453)
@@ -163,7 +163,7 @@
     int tex_font = fd->tex_font;
     int streamprovider = 0;
     int callback_id = 0 ;
-    if ((tex_font > 0) && (font_streamprovider(tex_font) == 2)) {
+    if ((tex_font > 0) && (font_streamprovider(tex_font) == 2 || font_streamprovider(tex_font) == 3)) {
         streamprovider = font_streamprovider(tex_font);
         callback_id = callback_defined(glyph_stream_provider_callback);
     }
@@ -230,14 +230,24 @@
             formatted_error("ttf","invalid glyph index (gid %u)", gid);
         loc = location[gid];
         len = location[gid + 1] - loc;
-        g->gd[i].advw = hmtx[gid].advance;
-        g->gd[i].lsb = hmtx[gid].sideBearing;
-        if (vmtx) {
-            g->gd[i].advh = vmtx[gid].advance;
-            g->gd[i].tsb = vmtx[gid].sideBearing;
+        if (callback_id > 0 && streamprovider == 3) {
+            int advw, lsb, advh, tsb;
+            run_callback(callback_id, "dddd->dddd", tex_font, g->gd[i].gid,
+                streamprovider, gid, &advw, &lsb, &advh, &tsb);
+            g->gd[i].advw = advw;
+            g->gd[i].lsb = lsb;
+            g->gd[i].advh = advh;
+            g->gd[i].tsb = tsb;
         } else {
-            g->gd[i].advh = g->default_advh;
-            g->gd[i].tsb = g->default_tsb;
+            g->gd[i].advw = hmtx[gid].advance;
+            g->gd[i].lsb = hmtx[gid].sideBearing;
+            if (vmtx) {
+                g->gd[i].advh = vmtx[gid].advance;
+                g->gd[i].tsb = vmtx[gid].sideBearing;
+            } else {
+                g->gd[i].advh = g->default_advh;
+                g->gd[i].tsb = g->default_tsb;
+            }
         }
         g->gd[i].length = len;
         g->gd[i].data = NULL;
@@ -402,7 +412,14 @@
             if (callback_id > 0) {
                 lstring * result;
                 long size = 0;
-                run_callback(callback_id, "ddd->L", tex_font, g->gd[i].gid, streamprovider, &result);
+                /*tex
+
+                    The streamprovider here is always 2, even when we actually have streamprovider == 3,
+                    to differentiate this call which behaves exactly like the call in the
+                    streamprovider == 2 case from the streamprovider == 3 specific call earlier.
+
+                */
+                run_callback(callback_id, "ddd->L", tex_font, g->gd[i].gid, 2, &result);
                 padlen = (int) ((result->l % 4) ? (4 - (result->l % 4)) : 0);
                 size = (size_t) result->l + (ULONG) padlen;
                 if (glyf_table_used + size >= glyf_table_size) {

Modified: trunk/Build/source/texk/web2c/luatexdir/image/writepng.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/image/writepng.c	2021-12-31 09:18:47 UTC (rev 61452)
+++ trunk/Build/source/texk/web2c/luatexdir/image/writepng.c	2021-12-31 10:38:50 UTC (rev 61453)
@@ -488,13 +488,13 @@
         png_copy = false;
     }
     /*tex alpha channel support */
-    if (pdf->minor_version < 4
+    if ((pdf->major_version == 1 && pdf->minor_version < 4)
         && png_get_color_type(png_p, info_p) | PNG_COLOR_MASK_ALPHA) {
         png_set_strip_alpha(png_p);
         png_copy = false;
     }
     /*tex 16 bit depth support */
-    if (pdf->minor_version < 5)
+    if (pdf->major_version == 1 && pdf->minor_version < 5)
         pdf->image_hicolor = 0;
     if ((png_get_bit_depth(png_p, info_p) == 16) && (pdf->image_hicolor == 0)) {
         png_set_strip_16(png_p);
@@ -556,7 +556,7 @@
         }
     }
     if (png_copy
-        && pdf->minor_version > 1
+        && (pdf->major_version > 1 || pdf->minor_version > 1)
         && png_get_interlace_type(png_p, info_p) == PNG_INTERLACE_NONE
         && (png_get_color_type(png_p, info_p) == PNG_COLOR_TYPE_GRAY
          || png_get_color_type(png_p, info_p) == PNG_COLOR_TYPE_RGB)
@@ -575,7 +575,7 @@
         if (img_errorlevel(idict) > 1) {
             if (!png_copy)
                 normal_warning("pngcopy","failed");
-            if (!(pdf->minor_version > 1))
+            if (!(pdf->major_version == 1 && pdf->minor_version > 1))
                 formatted_warning("pngcopy","skipped because minorversion is '%d'", pdf->minor_version);
             if (!(png_get_interlace_type(png_p, info_p) == PNG_INTERLACE_NONE))
                 normal_warning("pngcopy","skipped because of interlacing");
@@ -610,13 +610,13 @@
                 write_png_gray(pdf, idict);
                 break;
             case PNG_COLOR_TYPE_GRAY_ALPHA:
-                if (pdf->minor_version >= 4) {
+                if (pdf->major_version > 1 || pdf->minor_version >= 4) {
                     write_png_gray_alpha(pdf, idict);
                 } else
                     write_png_gray(pdf, idict);
                 break;
             case PNG_COLOR_TYPE_RGB_ALPHA:
-                if (pdf->minor_version >= 4) {
+                if (pdf->major_version > 1 || pdf->minor_version >= 4) {
                     write_png_rgb_alpha(pdf, idict);
                 } else
                     write_png_gray(pdf, idict);

Modified: trunk/Build/source/texk/web2c/luatexdir/lua/lnodelib.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/lua/lnodelib.c	2021-12-31 09:18:47 UTC (rev 61452)
+++ trunk/Build/source/texk/web2c/luatexdir/lua/lnodelib.c	2021-12-31 10:38:50 UTC (rev 61453)
@@ -4548,7 +4548,7 @@
         } else if (lua_key_eq(s, named_id)) {
             lua_pushinteger(L, pdf_action_named_id(n));
         } else if (lua_key_eq(s, action_id)) {
-            if (pdf_action_named_id(n) == 1) {
+            if (pdf_action_named_id(n) & 1) {
                 tokenlist_to_luastring(L, pdf_action_id(n));
             } else {
                 lua_pushinteger(L, pdf_action_id(n));
@@ -4559,6 +4559,14 @@
             lua_pushinteger(L, pdf_action_new_window(n));
         } else if (lua_key_eq(s, data)) {
             tokenlist_to_luastring(L, pdf_action_tokens(n));
+        } else if (lua_key_eq(s, struct_id)) {
+            if (pdf_action_struct_id(n) == null) {
+               lua_pushnil(L);
+            } else if (pdf_action_named_id(n) & 2) {
+                tokenlist_to_luastring(L, pdf_action_struct_id(n));
+            } else {
+                lua_pushinteger(L, pdf_action_struct_id(n));
+            }
         } else {
             lua_pushnil(L);
         }
@@ -5320,7 +5328,7 @@
         } else if (lua_key_eq(s, named_id)) {
             lua_pushinteger(L, pdf_action_named_id(n));
         } else if (lua_key_eq(s, action_id)) {
-            if (pdf_action_named_id(n) == 1) {
+            if (pdf_action_named_id(n) & 1) {
                 tokenlist_to_luastring(L, pdf_action_id(n));
             } else {
                 lua_pushinteger(L, pdf_action_id(n));
@@ -5331,6 +5339,14 @@
             lua_pushinteger(L, pdf_action_new_window(n));
         } else if (lua_key_eq(s, data)) {
             tokenlist_to_luastring(L, pdf_action_tokens(n));
+        } else if (lua_key_eq(s, struct_id)) {
+            if (pdf_action_struct_id(n) == null) {
+               lua_pushnil(L);
+            } else if (pdf_action_named_id(n) & 2) {
+                tokenlist_to_luastring(L, pdf_action_struct_id(n));
+            } else {
+                lua_pushinteger(L, pdf_action_struct_id(n));
+            }
         } else {
             lua_pushnil(L);
         }
@@ -6714,7 +6730,7 @@
         } 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) {
+            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);
@@ -6725,6 +6741,14 @@
             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 if (lua_key_eq(s, struct_id)) {
+            if (lua_isnil(L, 3)) {
+               pdf_action_struct_id(n) = null;
+            } else if (pdf_action_named_id(n) & 2) {
+                pdf_action_struct_id(n) = nodelib_gettoks(L, 3);
+            } else {
+                pdf_action_struct_id(n) = (halfword) lua_tointeger(L, 3);
+            }
         } else {
             return nodelib_cantset(L, n, s);
         }
@@ -7461,7 +7485,7 @@
         } 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) {
+            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);
@@ -7472,6 +7496,14 @@
             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 if (lua_key_eq(s, struct_id)) {
+            if (lua_isnil(L, 3)) {
+               pdf_action_struct_id(n) = null;
+            } else if (pdf_action_named_id(n) & 2) {
+                pdf_action_struct_id(n) = nodelib_gettoks(L, 3);
+            } else {
+                pdf_action_struct_id(n) = (halfword) lua_tointeger(L, 3);
+            }
         } else {
             return nodelib_cantset(L, n, s);
         }

Modified: trunk/Build/source/texk/web2c/luatexdir/lua/loslibext.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/lua/loslibext.c	2021-12-31 09:18:47 UTC (rev 61452)
+++ trunk/Build/source/texk/web2c/luatexdir/lua/loslibext.c	2021-12-31 10:38:50 UTC (rev 61453)
@@ -786,6 +786,18 @@
     sprintf(uts->release, "build %ld", osver.dwBuildNumber & 0xFFFF);
 
     switch (sysinfo.wProcessorArchitecture) {
+    case PROCESSOR_ARCHITECTURE_AMD64:
+        strcpy(uts->machine, "amd64");
+        break;
+    case PROCESSOR_ARCHITECTURE_ARM:
+        strcpy(uts->machine, "arm");
+        break;
+    case PROCESSOR_ARCHITECTURE_ARM64:
+        strcpy(uts->machine, "arm64");
+        break;
+    case PROCESSOR_ARCHITECTURE_IA64:
+        strcpy(uts->machine, "ia64");
+        break;
     case PROCESSOR_ARCHITECTURE_PPC:
         strcpy(uts->machine, "ppc");
         break;

Modified: trunk/Build/source/texk/web2c/luatexdir/lua/luatex-api.h
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/lua/luatex-api.h	2021-12-31 09:18:47 UTC (rev 61452)
+++ trunk/Build/source/texk/web2c/luatexdir/lua/luatex-api.h	2021-12-31 10:38:50 UTC (rev 61453)
@@ -565,6 +565,7 @@
 make_lua_key(after_assignment);\
 make_lua_key(after_display);\
 make_lua_key(after_group);\
+make_lua_key(partoken_name);\
 make_lua_key(after_output);\
 make_lua_key(afterdisplaypenalty);\
 make_lua_key(align);\
@@ -1141,6 +1142,7 @@
 make_lua_key(stretch);\
 make_lua_key(stretch_order);\
 make_lua_key(string);\
+make_lua_key(struct_id);\
 make_lua_key(style);\
 make_lua_key(sub);\
 make_lua_key(subfont);\
@@ -1276,6 +1278,7 @@
 init_lua_key(after_assignment);\
 init_lua_key(after_display);\
 init_lua_key(after_group);\
+init_lua_key(partoken_name);\
 init_lua_key(after_output);\
 init_lua_key(afterdisplaypenalty);\
 init_lua_key(align);\
@@ -1839,6 +1842,7 @@
 init_lua_key(stretch);\
 init_lua_key(stretch_order);\
 init_lua_key(string);\
+init_lua_key(struct_id);\
 init_lua_key(style);\
 init_lua_key(sub);\
 init_lua_key(subfont);\
@@ -2036,6 +2040,7 @@
 use_lua_key(after_assignment);
 use_lua_key(after_display);
 use_lua_key(after_group);
+use_lua_key(partoken_name);
 use_lua_key(after_output);
 use_lua_key(afterdisplaypenalty);
 use_lua_key(align);
@@ -2612,6 +2617,7 @@
 use_lua_key(stretch);
 use_lua_key(stretch_order);
 use_lua_key(string);
+use_lua_key(struct_id);
 use_lua_key(style);
 use_lua_key(sub);
 use_lua_key(subfont);

Modified: trunk/Build/source/texk/web2c/luatexdir/lua/luatoken.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/lua/luatoken.c	2021-12-31 09:18:47 UTC (rev 61452)
+++ trunk/Build/source/texk/web2c/luatexdir/lua/luatoken.c	2021-12-31 10:38:50 UTC (rev 61453)
@@ -70,6 +70,7 @@
     { ignore_spaces_cmd,        NULL, 0},
     { after_assignment_cmd,     NULL, 0},
     { after_group_cmd,          NULL, 0},
+    { partoken_name_cmd,        NULL, 0},
     { break_penalty_cmd,        NULL, 0},
     { start_par_cmd,            NULL, 0},
     { ital_corr_cmd,            NULL, 0},
@@ -235,6 +236,7 @@
     init_token_key(command_names, ignore_spaces_cmd,        ignore_spaces);
     init_token_key(command_names, after_assignment_cmd,     after_assignment);
     init_token_key(command_names, after_group_cmd,          after_group);
+    init_token_key(command_names, partoken_name_cmd,        partoken_name);
     init_token_key(command_names, break_penalty_cmd,        break_penalty);
     init_token_key(command_names, start_par_cmd,            start_par);
     init_token_key(command_names, ital_corr_cmd,            ital_corr);

Modified: trunk/Build/source/texk/web2c/luatexdir/luaharfbuzz/luaharfbuzz-1.1.0-1.rockspec
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaharfbuzz/luaharfbuzz-1.1.0-1.rockspec	2021-12-31 09:18:47 UTC (rev 61452)
+++ trunk/Build/source/texk/web2c/luatexdir/luaharfbuzz/luaharfbuzz-1.1.0-1.rockspec	2021-12-31 10:38:50 UTC (rev 61453)
@@ -31,6 +31,7 @@
       "src/luaharfbuzz/script.c",
       "src/luaharfbuzz/direction.c",
       "src/luaharfbuzz/language.c",
+      "src/luaharfbuzz/variation.c",
       "src/luaharfbuzz/class_utils.c"
       },
       libraries = {"harfbuzz"},

Modified: trunk/Build/source/texk/web2c/luatexdir/luaharfbuzz/luaharfbuzz-scm-1.rockspec
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaharfbuzz/luaharfbuzz-scm-1.rockspec	2021-12-31 09:18:47 UTC (rev 61452)
+++ trunk/Build/source/texk/web2c/luatexdir/luaharfbuzz/luaharfbuzz-scm-1.rockspec	2021-12-31 10:38:50 UTC (rev 61453)
@@ -33,6 +33,7 @@
       "src/luaharfbuzz/script.c",
       "src/luaharfbuzz/direction.c",
       "src/luaharfbuzz/language.c",
+      "src/luaharfbuzz/variation.c",
       "src/luaharfbuzz/class_utils.c"
       },
       libraries = {"harfbuzz"},

Modified: trunk/Build/source/texk/web2c/luatexdir/luaharfbuzz/spec/harfbuzz_spec.lua
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaharfbuzz/spec/harfbuzz_spec.lua	2021-12-31 09:18:47 UTC (rev 61452)
+++ trunk/Build/source/texk/web2c/luatexdir/luaharfbuzz/spec/harfbuzz_spec.lua	2021-12-31 10:38:50 UTC (rev 61453)
@@ -230,6 +230,64 @@
       assert.True(r)
       assert.are_same(13, i)
     end)
+
+    it("can return variation axes", function()
+      local f = harfbuzz.Face.new('fonts/STIXTwoText[wght].ttf')
+
+      assert.is_same(true, f:ot_var_has_data())
+      local axes = f:ot_var_get_axis_infos()
+      assert.are_same(1, #axes)
+      assert.are_same(harfbuzz.Tag.new("wght"), axes[1].tag)
+      assert.are_same(1, axes[1].axis_index)
+      assert.are_same(400, axes[1].min_value)
+      assert.are_same(400, axes[1].default_value)
+      assert.are_same(700, axes[1].max_value)
+      assert.are_same(0, axes[1].flags)
+      assert.are_same("Weight", f:get_name(axes[1].name_id))
+    end)
+
+    it("can find variation axis", function()
+      local f = harfbuzz.Face.new('fonts/STIXTwoText[wght].ttf')
+
+      local axis = f:ot_var_find_axis_info(harfbuzz.Tag.new("wght"))
+      assert.is_not_nil(axis)
+      assert.are_same(harfbuzz.Tag.new("wght"), axis.tag)
+      assert.are_same(1, axis.axis_index)
+      assert.are_same(400, axis.min_value)
+      assert.are_same(400, axis.default_value)
+      assert.are_same(700, axis.max_value)
+      assert.are_same(0, axis.flags)
+      assert.are_same("Weight", f:get_name(axis.name_id))
+    end)
+
+    it("can return named instances", function()
+      local f = harfbuzz.Face.new('fonts/STIXTwoText[wght].ttf')
+
+      local instances = f:ot_var_named_instance_get_infos()
+      assert.are_same(4, #instances)
+      assert.are_same(3, instances[3].index)
+      assert.are_same("SemiBold", f:get_name(instances[3].subfamily_name_id))
+      assert.are_same(nil, f:get_name(instances[3].postscript_name_id))
+      assert.are_same(600, f:ot_var_named_instance_get_design_coords(3))
+    end)
+
+    it("can normalize variations", function()
+      local f = harfbuzz.Face.new('fonts/STIXTwoText[wght].ttf')
+
+      local normalized, after = f:ot_var_normalize_variations(harfbuzz.Variation.new("wght=400"))
+      assert.is_nil(after)
+      assert.are_same(0, normalized)
+
+      normalized = f:ot_var_normalize_variations(harfbuzz.Variation.new("wght=700"))
+      assert.are_same(1<<14, normalized)
+
+      normalized, after = f:ot_var_normalize_coords(700)
+      assert.is_nil(after)
+      assert.are_same(1<<14, normalized)
+
+      normalized = f:ot_var_normalize_coords(400)
+      assert.are_same(0, normalized)
+    end)
   end)
 
   describe("harfbuzz.Font", function()
@@ -318,6 +376,25 @@
       assert.are_same(2857,f:ot_color_glyph_get_png(2):get_length())
       assert.are_same("\137PNG",f:ot_color_glyph_get_png(2):get_data():sub(1, 4))
     end)
+
+    it("can set variations", function()
+      local f = harfbuzz.Font.new(harfbuzz.Face.new('fonts/STIXTwoText[wght].ttf'))
+
+      f:set_variations(harfbuzz.Variation.new("wght=500"))
+      local normalized, after = f:get_var_coords_normalized()
+      assert.is_nil(after)
+      assert.are_same(5174, normalized)
+
+      f:set_var_coords_design(600)
+      local normalized, after = f:get_var_coords_normalized()
+      assert.is_nil(after)
+      assert.are_same(10348, normalized)
+
+      f:set_var_coords_normalized(1<<13)
+      local normalized, after = f:get_var_coords_normalized()
+      assert.is_nil(after)
+      assert.are_same(1<<13, normalized)
+    end)
   end)
 
   describe("harfbuzz.Feature", function()
@@ -339,7 +416,6 @@
 
     it("has visible fields", function()
       local f = harfbuzz.Feature.new('-kern')
-      print(getmetatable(f).__index)
       assert.are_equal(tostring(f.tag), 'kern')
       assert.are_equal(f.value, 0)
       assert.are_equal(f.start, nil)
@@ -362,6 +438,44 @@
     end)
   end)
 
+  describe("harfbuzz.Variation", function()
+    it("can be initialised with a valid variation string", function()
+      harfbuzz.Variation.new('wght=default')
+      harfbuzz.Variation.new('wght=400')
+      harfbuzz.Variation.new('wght=-20')
+    end)
+
+    it("throws an error when trying to initialise a new variation with an invalid string", function()
+       assert.are_equal(nil, harfbuzz.Variation.new(''))
+       assert.are_equal(nil, harfbuzz.Variation.new('wght'))
+    end)
+
+    it("has a valid tostring value", function()
+      local vs = 'wght=200'
+      local v = harfbuzz.Variation.new(vs)
+      assert.are_equal(vs, tostring(v))
+    end)
+
+    it("has visible fields", function()
+      local v = harfbuzz.Variation.new('wght=400')
+      assert.are_equal(tostring(v.tag), 'wght')
+      assert.are_equal(v.value, 400)
+
+      v = harfbuzz.Variation.new('slnt=-7.5')
+      assert.are_equal(tostring(v.tag), 'slnt')
+      assert.are_equal(v.value, -7.5)
+    end)
+
+    it("has editable fields", function()
+      local f = harfbuzz.Variation.new('slnt=5')
+      f.tag, f.value = harfbuzz.Tag.new"wght", 7
+      assert.are_equal(tostring(f), "wght=7")
+
+      f.tag, f.value = harfbuzz.Tag.new"hght", 0
+      assert.are_equal(tostring(f), "hght=0")
+    end)
+  end)
+
   describe("harfbuzz.Tag", function()
     it("can be initialised with a valid tag string", function()
       harfbuzz.Tag.new('Zyyy')

Modified: trunk/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/face.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/face.c	2021-12-31 09:18:47 UTC (rev 61452)
+++ trunk/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/face.c	2021-12-31 10:38:50 UTC (rev 61453)
@@ -1,5 +1,20 @@
 #include "luaharfbuzz.h"
 
+#ifdef LuajitTeX
+
+static int lua_absindex (lua_State *L, int i) {
+  if (i < 0 && i > LUA_REGISTRYINDEX)
+    i += lua_gettop(L) + 1;
+  return i;
+}
+static void lua_seti (lua_State *L, int index, lua_Integer i) {
+  index = lua_absindex(L, index);
+  lua_pushinteger(L, i);
+  lua_insert(L, -2);
+  lua_settable(L, index);
+}
+#endif
+
 /* Size of static arrays we use to avoid heap allocating memory when reading
  * data from HarfBuzz. */
 #define STATIC_ARRAY_SIZE 128
@@ -423,6 +438,179 @@
   return 1;
 }
 
+static int face_var_has_data(lua_State *L) {
+  Face *f = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
+
+  lua_pushboolean(L, hb_ot_var_has_data(*f));
+  return 1;
+}
+
+static int push_axis_info(lua_State *L, const hb_ot_var_axis_info_t *info) {
+  lua_createtable(L, 0, 7);
+
+  lua_pushinteger(L, info->axis_index + 1);
+  lua_setfield(L, -2, "axis_index");
+
+  Tag *tp = (Tag *)lua_newuserdata(L, sizeof(*tp));
+  luaL_getmetatable(L, "harfbuzz.Tag");
+  lua_setmetatable(L, -2);
+  *tp = info->tag;
+  lua_setfield(L, -2, "tag");
+
+  lua_pushinteger(L, info->name_id);
+  lua_setfield(L, -2, "name_id");
+
+  lua_pushinteger(L, info->flags);
+  lua_setfield(L, -2, "flags");
+
+  lua_pushnumber(L, info->min_value);
+  lua_setfield(L, -2, "min_value");
+
+  lua_pushnumber(L, info->default_value);
+  lua_setfield(L, -2, "default_value");
+
+  lua_pushnumber(L, info->max_value);
+  lua_setfield(L, -2, "max_value");
+
+  return 1;
+}
+
+static int face_var_find_axis_info(lua_State *L) {
+  Face *face = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
+  Tag *tag = (Tag *)luaL_checkudata(L, 2, "harfbuzz.Tag");
+  hb_ot_var_axis_info_t axis_info;
+
+  if (hb_ot_var_find_axis_info(*face, *tag, &axis_info))
+    push_axis_info(L, &axis_info);
+  else
+    lua_pushnil(L);
+  return 1;
+}
+
+static int face_var_get_axis_infos(lua_State *L) {
+  Face *face = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
+  lua_Integer start = luaL_optinteger(L, 2, 1) - 1;
+  lua_Integer stop = luaL_optinteger(L, 2, -1);
+  if (start < -1)
+    start += hb_ot_var_get_axis_count(*face) + 1;
+  if (stop < 0)
+    stop += hb_ot_var_get_axis_count(*face) + 1;
+
+  if (start < 0 || stop - start > STATIC_ARRAY_SIZE)
+    lua_pushnil(L);
+  else if (stop <= start)
+    lua_createtable(L, 0, 0);
+  else {
+    unsigned int count = stop - start;
+    hb_ot_var_axis_info_t axis_infos[STATIC_ARRAY_SIZE];
+
+    hb_ot_var_get_axis_infos(*face, start, &count, axis_infos);
+
+    lua_createtable(L, count, 0);
+    for (int i = 0; i != count; i++) {
+      push_axis_info(L, axis_infos + i);
+      lua_seti(L, -2, i + 1);
+    }
+  }
+  return 1;
+}
+
+static int face_var_named_instance_get_infos(lua_State *L) {
+  Face *face = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
+  lua_Integer start = luaL_optinteger(L, 2, 1) - 1;
+  lua_Integer stop = luaL_optinteger(L, 2, -1);
+
+  unsigned int total = hb_ot_var_get_named_instance_count(*face);
+
+  if (start < -1)
+    start += total + 1;
+  if (stop < 0)
+    stop += total + 1;
+  if (stop > total)
+    stop = total;
+
+  if (start < 0)
+    lua_pushnil(L);
+  else if (stop <= start)
+    lua_createtable(L, 0, 0);
+  else {
+    lua_createtable(L, stop - start, 0);
+    for (int i = start; i != stop; i++) {
+      lua_createtable(L, 0, 3);
+
+      lua_pushinteger(L, i + 1);
+      lua_setfield(L, -2, "index");
+
+      lua_pushinteger(L, hb_ot_var_named_instance_get_subfamily_name_id(*face, i));
+      lua_setfield(L, -2, "subfamily_name_id");
+
+      lua_pushinteger(L, hb_ot_var_named_instance_get_subfamily_name_id(*face, i));
+      lua_setfield(L, -2, "subfamily_name_id");
+
+      lua_pushinteger(L, hb_ot_var_named_instance_get_postscript_name_id(*face, i));
+      lua_setfield(L, -2, "postscript_name_id");
+
+      lua_seti(L, -2, i - start + 1);
+    }
+  }
+  return 1;
+}
+
+static int face_var_named_instance_get_design_coords(lua_State *L) {
+  Face *face = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
+  lua_Integer index = luaL_checkinteger(L, 2) - 1;
+
+  float coords[STATIC_ARRAY_SIZE];
+  unsigned int count = STATIC_ARRAY_SIZE;
+  count = hb_ot_var_named_instance_get_design_coords(*face, index, &count, coords);
+
+  for (int i = 0; i != count; i++) {
+    lua_pushnumber(L, coords[i]);
+  }
+  return count;
+}
+
+static int face_var_normalize_variations(lua_State *L) {
+  Face *face = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
+  unsigned int count = lua_gettop(L)-1;
+  if (count > STATIC_ARRAY_SIZE) {
+    return 0;
+  }
+
+  Variation variations[STATIC_ARRAY_SIZE];
+  for (unsigned int i = 0; i != count; i++)
+    variations[i] = *(Variation *)luaL_checkudata(L, i+2, "harfbuzz.Variation");
+
+  unsigned int coord_count = hb_ot_var_get_axis_count(*face);
+  int normalized[STATIC_ARRAY_SIZE];
+  hb_ot_var_normalize_variations(*face, variations, count, normalized, coord_count);
+
+  for (int i = 0; i != coord_count; i++) {
+    lua_pushinteger(L, normalized[i]);
+  }
+  return coord_count;
+}
+
+static int face_var_normalize_coords(lua_State *L) {
+  Face *face = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
+  unsigned int count = lua_gettop(L)-1;
+  if (count > STATIC_ARRAY_SIZE) {
+    return 0;
+  }
+
+  float coords[STATIC_ARRAY_SIZE];
+  for (unsigned int i = 0; i != count; i++)
+    coords[i] = luaL_checknumber(L, i+2);
+
+  int normalized[STATIC_ARRAY_SIZE];
+  hb_ot_var_normalize_coords(*face, count, coords, normalized);
+
+  for (int i = 0; i != count; i++) {
+    lua_pushinteger(L, normalized[i]);
+  }
+  return count;
+}
+
 static int face_destroy(lua_State *L) {
   Face *f = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
 
@@ -452,6 +640,13 @@
   { "ot_layout_find_script", face_ot_layout_find_script },
   { "ot_layout_find_language", face_ot_layout_find_language },
   { "ot_layout_find_feature", face_ot_layout_find_feature },
+  { "ot_var_has_data", face_var_has_data },
+  { "ot_var_find_axis_info", face_var_find_axis_info },
+  { "ot_var_get_axis_infos", face_var_get_axis_infos },
+  { "ot_var_named_instance_get_infos", face_var_named_instance_get_infos },
+  { "ot_var_named_instance_get_design_coords", face_var_named_instance_get_design_coords },
+  { "ot_var_normalize_variations", face_var_normalize_variations },
+  { "ot_var_normalize_coords", face_var_normalize_coords },
   { NULL, NULL }
 };
 

Modified: trunk/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/font.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/font.c	2021-12-31 09:18:47 UTC (rev 61452)
+++ trunk/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/font.c	2021-12-31 10:38:50 UTC (rev 61453)
@@ -192,6 +192,62 @@
   return 1;
 }
 
+static int font_set_variations(lua_State *L) {
+  Font *f = (Font *)luaL_checkudata(L, 1, "harfbuzz.Font");
+  unsigned int count = lua_gettop(L) - 1;
+  if (count > 128)
+    count = 128;
+  Variation variations[128];
+  for (int i = 0; i != count; i++)
+    variations[i] = *(Variation *)luaL_checkudata(L, i + 2, "harfbuzz.Variation");
+
+  hb_font_set_variations(*f, variations, count);
+  return 0;
+}
+
+static int font_set_var_coords_design(lua_State *L) {
+  Font *f = (Font *)luaL_checkudata(L, 1, "harfbuzz.Font");
+  unsigned int count = lua_gettop(L) - 1;
+  if (count > 128)
+    count = 128;
+  float coords[128];
+  for (int i = 0; i != count; i++)
+    coords[i] = luaL_checknumber(L, i + 2);
+
+  hb_font_set_var_coords_design(*f, coords, count);
+  return 0;
+}
+
+static int font_set_var_coords_normalized(lua_State *L) {
+  Font *f = (Font *)luaL_checkudata(L, 1, "harfbuzz.Font");
+  unsigned int count = lua_gettop(L) - 1;
+  if (count > 128)
+    count = 128;
+  int coords[128];
+  for (int i = 0; i != count; i++)
+    coords[i] = luaL_checkinteger(L, i + 2);
+
+  hb_font_set_var_coords_normalized(*f, coords, count);
+  return 0;
+}
+
+static int font_set_var_named_instance(lua_State *L) {
+  Font *f = (Font *)luaL_checkudata(L, 1, "harfbuzz.Font");
+  unsigned int instance = luaL_checkinteger(L, 2);
+
+  hb_font_set_var_named_instance(*f, instance - 1);
+  return 0;
+}
+
+static int font_get_var_coords_normalized(lua_State *L) {
+  Font *f = (Font *)luaL_checkudata(L, 1, "harfbuzz.Font");
+  unsigned int count;
+  const int *coords = hb_font_get_var_coords_normalized(*f, &count);
+  for (int i = 0; i != count; i++)
+    lua_pushinteger(L, coords[i]);
+  return count;
+}
+
 static const struct luaL_Reg font_methods[] = {
   { "__gc", font_destroy },
   { "set_scale", font_set_scale },
@@ -205,6 +261,11 @@
   { "get_glyph_v_advance", font_get_glyph_v_advance },
   { "get_nominal_glyph", font_get_nominal_glyph },
   { "ot_color_glyph_get_png", font_ot_color_glyph_get_png },
+  { "set_variations", font_set_variations },
+  { "set_var_coords_design", font_set_var_coords_design },
+  { "set_var_coords_normalized", font_set_var_coords_normalized },
+  { "set_var_named_instance", font_set_var_named_instance },
+  { "get_var_coords_normalized", font_get_var_coords_normalized },
   { NULL, NULL }
 };
 

Modified: trunk/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/luaharfbuzz.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/luaharfbuzz.c	2021-12-31 09:18:47 UTC (rev 61452)
+++ trunk/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/luaharfbuzz.c	2021-12-31 10:38:50 UTC (rev 61453)
@@ -103,6 +103,9 @@
   register_language(L);
   lua_setfield(L, -2, "Language");
 
+  register_variation(L);
+  lua_setfield(L, -2, "Variation");
+
   register_ot(L);
   lua_setfield(L, -2, "ot");
 

Modified: trunk/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/luaharfbuzz.h
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/luaharfbuzz.h	2021-12-31 09:18:47 UTC (rev 61452)
+++ trunk/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/luaharfbuzz.h	2021-12-31 10:38:50 UTC (rev 61453)
@@ -18,6 +18,7 @@
 typedef hb_script_t Script;
 typedef hb_direction_t Direction;
 typedef hb_language_t Language;
+typedef hb_variation_t Variation;
 
 typedef struct luahb_constant_t {
   const char *name;
@@ -35,6 +36,7 @@
 int register_script(lua_State *L);
 int register_direction(lua_State *L);
 int register_language(lua_State *L);
+int register_variation(lua_State *L);
 int register_ot(lua_State *L);
 int register_unicode(lua_State *L);
 

Added: trunk/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/variation.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/variation.c	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/luaharfbuzz/src/luaharfbuzz/variation.c	2021-12-31 10:38:50 UTC (rev 61453)
@@ -0,0 +1,82 @@
+// harfbuzz.Variation
+#include "luaharfbuzz.h"
+
+static int variation_new(lua_State *L) {
+  Variation v;
+  const char *variation = luaL_checkstring(L, 1);
+
+  if (hb_variation_from_string(variation, -1, &v)) {
+    Variation *vp = (Variation *)lua_newuserdata(L, sizeof(*vp));
+    luaL_getmetatable(L, "harfbuzz.Variation");
+    lua_setmetatable(L, -2);
+    *vp = v;
+  } else {
+    lua_pushnil(L);
+  }
+
+  return 1;
+}
+
+static int variation_to_string(lua_State *L) {
+  Variation* v = (Variation *)luaL_checkudata(L, 1, "harfbuzz.Variation");
+  char variation[128];
+
+  hb_variation_to_string(v, variation, 128);
+  lua_pushstring(L, variation);
+  return 1;
+}
+
+static const char *variation_tag_ptr;
+static const char *variation_value_ptr;
+
+static int variation_index(lua_State *L) {
+  Variation* v = (Variation *)luaL_checkudata(L, 1, "harfbuzz.Variation");
+  const char *key = lua_tostring(L, 2);
+
+  if (key == variation_tag_ptr) {
+    Tag *tag = (Tag *)lua_newuserdata(L, sizeof(*tag));
+    luaL_getmetatable(L, "harfbuzz.Tag");
+    lua_setmetatable(L, -2);
+    *tag = v->tag;
+  } else if (key == variation_value_ptr) {
+    lua_pushnumber(L, v->value);
+  } else {
+    lua_pushnil(L);
+  }
+  return 1;
+}
+
+static int variation_newindex(lua_State *L) {
+  Variation* v = (Variation *)luaL_checkudata(L, 1, "harfbuzz.Variation");
+  const char *key = lua_tostring(L, 2);
+
+  if (key == variation_tag_ptr) {
+    v->tag = *(Tag *)luaL_checkudata(L, 3, "harfbuzz.Tag");
+  } else if (key == variation_value_ptr) {
+    v->value = luaL_checknumber(L, 3);
+  }
+  return 0;
+}
+
+static const struct luaL_Reg variation_methods[] = {
+  { "__index", variation_index },
+  { "__newindex", variation_newindex },
+  { "__tostring", variation_to_string },
+  { NULL, NULL },
+};
+
+static const struct luaL_Reg variation_functions[] = {
+  { "new", variation_new },
+  { NULL,  NULL }
+};
+
+int register_variation(lua_State *L) {
+  lua_pushliteral(L, "tag");
+  variation_tag_ptr = lua_tostring(L, -1);
+  (void) luaL_ref (L, LUA_REGISTRYINDEX);
+  lua_pushliteral(L, "value");
+  variation_value_ptr = lua_tostring(L, -1);
+  (void) luaL_ref (L, LUA_REGISTRYINDEX);
+
+  return register_class(L, "harfbuzz.Variation", variation_methods, variation_functions, NULL);
+}

Modified: trunk/Build/source/texk/web2c/luatexdir/luasocket/src/inet.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luasocket/src/inet.c	2021-12-31 09:18:47 UTC (rev 61452)
+++ trunk/Build/source/texk/web2c/luatexdir/luasocket/src/inet.c	2021-12-31 10:38:50 UTC (rev 61453)
@@ -519,7 +519,6 @@
 #endif
 
 #ifdef LUASOCKET_INET_PTON
-#ifndef _WS2TCPIP_H_
 int inet_pton(int af, const char *src, void *dst)
 {
     struct addrinfo hints, *res;
@@ -542,4 +541,3 @@
 }
 
 #endif
-#endif

Modified: trunk/Build/source/texk/web2c/luatexdir/luasocket/src/inet.h
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luasocket/src/inet.h	2021-12-31 09:18:47 UTC (rev 61452)
+++ trunk/Build/source/texk/web2c/luatexdir/luasocket/src/inet.h	2021-12-31 10:38:50 UTC (rev 61453)
@@ -47,10 +47,8 @@
 #endif
 
 #ifdef LUASOCKET_INET_PTON
-#ifndef _WS2TCPIP_H_
 const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt);
 int inet_pton(int af, const char *src, void *dst);
 #endif
-#endif
 
 #endif /* INET_H */

Modified: trunk/Build/source/texk/web2c/luatexdir/luatex.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luatex.c	2021-12-31 09:18:47 UTC (rev 61452)
+++ trunk/Build/source/texk/web2c/luatexdir/luatex.c	2021-12-31 10:38:50 UTC (rev 61453)
@@ -32,9 +32,9 @@
     stick to "0" upto "9" so users can expect a number represented as string.
 */
 
-int luatex_version = 114;
+int luatex_version = 115;
 int luatex_revision = '0';
-const char *luatex_version_string = "1.14.0";
+const char *luatex_version_string = "1.15.0";
 const char *engine_name = my_name;
 
 #include <kpathsea/c-ctype.h>

Modified: trunk/Build/source/texk/web2c/luatexdir/luatex_svnversion.h
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/luatex_svnversion.h	2021-12-31 09:18:47 UTC (rev 61452)
+++ trunk/Build/source/texk/web2c/luatexdir/luatex_svnversion.h	2021-12-31 10:38:50 UTC (rev 61453)
@@ -1 +1 @@
-#define luatex_svn_revision 7439
+#define luatex_svn_revision 7474

Modified: trunk/Build/source/texk/web2c/luatexdir/pdf/pdfaction.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/pdf/pdfaction.c	2021-12-31 09:18:47 UTC (rev 61452)
+++ trunk/Build/source/texk/web2c/luatexdir/pdf/pdfaction.c	2021-12-31 10:38:50 UTC (rev 61453)
@@ -40,10 +40,33 @@
         set_pdf_action_tokens(p, def_ref);
         return p;
     }
+    pdf_action_named_id(p) = 0;
     if (scan_keyword("file")) {
         scan_toks(false, true);
         set_pdf_action_file(p, def_ref);
     }
+    if (scan_keyword("struct")) {
+        if (pdf_action_type(p) != pdf_action_goto)
+            normal_error("pdf backend", "only GoTo action can be used with `struct'");
+        if (pdf_action_file(p) != null) {
+            scan_toks(false, true);
+            pdf_action_named_id(p) |= 2;
+            pdf_action_struct_id(p) = def_ref;
+        } else if (scan_keyword("name")) {
+            scan_toks(false, true);
+            pdf_action_named_id(p) |= 2;
+            pdf_action_struct_id(p) = def_ref;
+        }
+        else if (scan_keyword("num")) {
+            scan_int();
+            if (cur_val <= 0)
+                normal_error("pdf backend", "num identifier must be positive");
+            pdf_action_struct_id(p) = cur_val;
+        }
+        else
+            normal_error("pdf backend", "identifier type missing");
+    } else
+        pdf_action_struct_id(p) = null;
     if (scan_keyword("page")) {
         if (pdf_action_type(p) != pdf_action_goto)
             normal_error("pdf backend", "only GoTo action can be used with 'page'");
@@ -52,12 +75,11 @@
         if (cur_val <= 0)
             normal_error("pdf backend", "page number must be positive");
         set_pdf_action_id(p, cur_val);
-        set_pdf_action_named_id(p, 0);
         scan_toks(false, true);
         set_pdf_action_tokens(p, def_ref);
     } else if (scan_keyword("name")) {
         scan_toks(false, true);
-        set_pdf_action_named_id(p, 1);
+        pdf_action_named_id(p) |= 1;
         set_pdf_action_id(p, def_ref);
     } else if (scan_keyword("num")) {
         if ((pdf_action_type(p) == pdf_action_goto) &&
@@ -66,7 +88,6 @@
         scan_int();
         if (cur_val <= 0)
             normal_error("pdf backend", "num identifier must be positive");
-        set_pdf_action_named_id(p, 0);
         set_pdf_action_id(p, cur_val);
     } else {
         normal_error("pdf backend", "identifier type missing");
@@ -143,10 +164,10 @@
         case pdf_action_goto:
             if (pdf_action_file(p) == null) {
                 pdf_dict_add_name(pdf, "S", "GoTo");
-                d = pdf_get_obj(pdf, obj_type_dest, pdf_action_id(p), pdf_action_named_id(p));
+                d = pdf_get_obj(pdf, obj_type_dest, pdf_action_id(p), (pdf_action_named_id(p) & 1) == 1);
             } else
                 pdf_dict_add_name(pdf, "S", "GoToR");
-            if (pdf_action_named_id(p) > 0) {
+            if (pdf_action_named_id(p) & 1) {
                 char *tokstr = tokenlist_to_cstring(pdf_action_id(p), true, NULL);
                 pdf_dict_add_string(pdf, "D", tokstr);
                 xfree(tokstr);
@@ -159,8 +180,8 @@
         case pdf_action_thread:
             pdf_dict_add_name(pdf, "S", "Thread");
             if (pdf_action_file(p) == null) {
-                d = pdf_get_obj(pdf, obj_type_thread, pdf_action_id(p), pdf_action_named_id(p));
-                if (pdf_action_named_id(p) > 0) {
+                d = pdf_get_obj(pdf, obj_type_thread, pdf_action_id(p), (pdf_action_named_id(p) & 1) == 1);
+                if (pdf_action_named_id(p) & 1) {
                     char *tokstr = tokenlist_to_cstring(pdf_action_id(p), true, NULL);
                     pdf_dict_add_string(pdf, "D", tokstr);
                     xfree(tokstr);
@@ -172,5 +193,14 @@
             }
             break;
     }
+    if (pdf_action_struct_id(p) != null) {
+        if (pdf_action_file(p) == null) {
+            d = pdf_get_obj(pdf, obj_type_struct_dest, pdf_action_struct_id(p), (pdf_action_named_id(p) & 2) == 2);
+            pdf_dict_add_ref(pdf, "SD", d);
+        } else {
+            pdf_add_name(pdf, "SD");
+            pdf_print_toks(pdf, pdf_action_struct_id(p));
+        }
+    }
     pdf_end_dict(pdf);
 }

Modified: trunk/Build/source/texk/web2c/luatexdir/pdf/pdfdest.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/pdf/pdfdest.c	2021-12-31 09:18:47 UTC (rev 61452)
+++ trunk/Build/source/texk/web2c/luatexdir/pdf/pdfdest.c	2021-12-31 10:38:50 UTC (rev 61453)
@@ -70,6 +70,16 @@
     }
 }
 
+/*tex
+
+    In |do_dest|, structure destinations and regular destinations use separate object
+    types for |pdf_get_obj| but share an object type for |addto_page_resources|.
+    This allows |write_out_pdf_mark_destinations| to handle both kinds of destinations
+    in a uniform way, while still allowing to use the same name for both kinds of
+    destinations. This is a useful feature since it's rather common to have both kinds
+    of destinations for the same object and therefore they will often have the same name.
+
+*/
 void do_dest(PDF pdf, halfword p, halfword parent_box, scaledpos cur)
 {
     scaledpos pos = pdf->posstruct->pos;
@@ -79,7 +89,9 @@
         normal_error("pdf backend", "destinations cannot be inside an xform");
     if (doing_leaders)
         return;
-    k = pdf_get_obj(pdf, obj_type_dest, pdf_dest_id(p), pdf_dest_named_id(p));
+    k = pdf_get_obj(pdf,
+            pdf_dest_objnum(p) == null ? obj_type_dest : obj_type_struct_dest,
+            pdf_dest_id(p), pdf_dest_named_id(p));
     if (obj_dest_ptr(pdf, k) != null) {
         warn_dest_dup(pdf_dest_id(p), (small_number) pdf_dest_named_id(p));
         return;
@@ -133,14 +145,16 @@
                 normal_error("pdf backend","destination has been already written (this shouldn't happen)");
             } else {
                 int i;
+                int objnum;
                 i = obj_dest_ptr(pdf, k->info);
+                objnum = pdf_dest_objnum(i);
                 pdf_begin_obj(pdf, k->info, OBJSTM_ALWAYS);
-                if (pdf_dest_named_id(i) > 0) {
+                if (pdf_dest_named_id(i) > 0 && objnum == null) {
                     pdf_begin_dict(pdf);
                     pdf_add_name(pdf, "D");
                 }
                 pdf_begin_array(pdf);
-                pdf_add_ref(pdf, pdf->last_page);
+                pdf_add_ref(pdf, objnum == null ? pdf->last_page : objnum);
                 switch (pdf_dest_type(i)) {
                     case pdf_dest_xyz:
                         pdf_add_name(pdf, "XYZ");
@@ -187,7 +201,7 @@
                         break;
                 }
                 pdf_end_array(pdf);
-                if (pdf_dest_named_id(i) > 0)
+                if (pdf_dest_named_id(i) > 0 && objnum == null)
                     pdf_end_dict(pdf);
                 pdf_end_obj(pdf);
             }
@@ -200,10 +214,21 @@
 {
     halfword q;
     int k;
+    int obj_type;
     str_number i;
     scaled_whd alt_rule;
     q = cur_list.tail_field;
     new_whatsit(pdf_dest_node);
+    if (scan_keyword("struct")) {
+        scan_int();
+        if (cur_val <= 0)
+            normal_error("pdf backend", "struct identifier must be positive");
+        pdf_dest_objnum(cur_list.tail_field) = cur_val;
+        obj_type = obj_type_struct_dest;
+    } else {
+        pdf_dest_objnum(cur_list.tail_field) = null;
+        obj_type = obj_type_dest;
+    }
     if (scan_keyword("num")) {
         scan_int();
         if (cur_val <= 0)
@@ -258,10 +283,10 @@
     }
     if (pdf_dest_named_id(cur_list.tail_field) != 0) {
         i = tokens_to_string(pdf_dest_id(cur_list.tail_field));
-        k = find_obj(pdf, obj_type_dest, i, true);
+        k = find_obj(pdf, obj_type, i, true);
         flush_str(i);
     } else {
-        k = find_obj(pdf, obj_type_dest, pdf_dest_id(cur_list.tail_field), false);
+        k = find_obj(pdf, obj_type, pdf_dest_id(cur_list.tail_field), false);
     }
     if ((k != 0) && (obj_dest_ptr(pdf, k) != null)) {
         warn_dest_dup(pdf_dest_id(cur_list.tail_field),(small_number) pdf_dest_named_id(cur_list.tail_field));

Modified: trunk/Build/source/texk/web2c/luatexdir/pdf/pdfdest.h
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/pdf/pdfdest.h	2021-12-31 09:18:47 UTC (rev 61452)
+++ trunk/Build/source/texk/web2c/luatexdir/pdf/pdfdest.h	2021-12-31 10:38:50 UTC (rev 61453)
@@ -44,6 +44,7 @@
 #  define obj_dest_ptr              obj_aux     /* pointer to |pdf_dest_node| */
 #  define set_obj_dest_ptr(pdf,A,B) obj_dest_ptr(pdf,A)=B
 
+#  define set_pdf_dest_struct_id(A,B)pdf_dest_struct_id(A)=B
 #  define set_pdf_dest_id(A,B)       pdf_dest_id(A)=B
 #  define set_pdf_dest_named_id(A,B) pdf_dest_named_id(A)=B
 #  define set_pdf_dest_type(A,B)     pdf_dest_type(A)=B

Modified: trunk/Build/source/texk/web2c/luatexdir/pdf/pdfgen.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/pdf/pdfgen.c	2021-12-31 09:18:47 UTC (rev 61452)
+++ trunk/Build/source/texk/web2c/luatexdir/pdf/pdfgen.c	2021-12-31 10:38:50 UTC (rev 61453)
@@ -2065,6 +2065,38 @@
     }
 }
 
+/*tex
+
+    For structure destinations we don't have a fallback structure element to use when
+    they are not defined, so we insert "null" instead
+    referenced but don't exists have |obj_dest_ptr=null|. Leaving them undefined
+    might cause troubles for PDF browsers, so we need to fix them; they point to
+    the last page.
+
+*/
+
+static void check_nonexisting_structure_destinations(PDF pdf)
+{
+    int k;
+    for (k = pdf->head_tab[obj_type_struct_dest]; k != 0; k = obj_link(pdf, k)) {
+        if (obj_dest_ptr(pdf, k) == null) {
+            if (obj_info(pdf, k) < 0) {
+                char *ss = makecstring(-obj_info(pdf, k));
+                formatted_warning("pdf backend", "unreferenced structure destination with name '%s'",ss);
+            } else {
+                formatted_warning("pdf backend", "unreferenced structure destination with num '%d'",obj_info(pdf,k));
+            }
+
+            pdf_begin_obj(pdf, k, OBJSTM_ALWAYS);
+            pdf_begin_array(pdf);
+            pdf_add_null(pdf);
+            pdf_add_name(pdf, "Fit");
+            pdf_end_array(pdf);
+            pdf_end_obj(pdf);
+        }
+    }
+}
+
 static void check_nonexisting_pages(PDF pdf)
 {
     struct avl_traverser t;
@@ -2226,6 +2258,7 @@
                 if (total_pages > 0) {
                     check_nonexisting_pages(pdf);
                     check_nonexisting_destinations(pdf);
+                    check_nonexisting_structure_destinations(pdf);
                 }
                 /*tex
                     Output fonts definition.

Modified: trunk/Build/source/texk/web2c/luatexdir/pdf/pdftables.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/pdf/pdftables.c	2021-12-31 09:18:47 UTC (rev 61452)
+++ trunk/Build/source/texk/web2c/luatexdir/pdf/pdftables.c	2021-12-31 10:38:50 UTC (rev 61453)
@@ -22,7 +22,7 @@
 #include "ptexlib.h"
 
 const char *pdf_obj_typenames[PDF_OBJ_TYPE_MAX + 1] = {
-    "font", "outline", "dest", "obj", "xform", "ximage", "thread",
+    "font", "outline", "dest", "struct dest", "obj", "xform", "ximage", "thread",
     "pagestream", "page", "pages", "catalog", "info", "link", "annot", "annots",
     "bead", "beads", "objstm", "others"
 };

Modified: trunk/Build/source/texk/web2c/luatexdir/pdf/pdftypes.h
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/pdf/pdftypes.h	2021-12-31 09:18:47 UTC (rev 61452)
+++ trunk/Build/source/texk/web2c/luatexdir/pdf/pdftypes.h	2021-12-31 10:38:50 UTC (rev 61453)
@@ -203,26 +203,27 @@
     obj_type_font = 0,          /* index of linked list of Fonts objects */
     obj_type_outline = 1,       /* index of linked list of outline objects */
     obj_type_dest = 2,          /* index of linked list of destination objects */
-    obj_type_obj = 3,           /* index of linked list of raw objects */
-    obj_type_xform = 4,         /* index of linked list of XObject forms */
-    obj_type_ximage = 5,        /* index of linked list of XObject images */
-    obj_type_thread = 6,        /* index of linked list of num article threads */
-    obj_type_pagestream = 7,    /* Page stream objects */
-    obj_type_page = 8,          /* /Page objects */
-    obj_type_pages = 9,         /* /Pages objects */
-    obj_type_catalog = 10,      /* /Catalog object */
-    obj_type_info = 11,         /* /Info object */
-    obj_type_link = 12,         /* link objects */
-    obj_type_annot = 13,        /* annotation objects */
-    obj_type_annots = 14,       /* /Annots objects */
-    obj_type_bead = 15,         /* thread bead objects */
-    obj_type_beads = 16,        /* /B objects (array of bead objects) */
-    obj_type_objstm = 17,       /* /ObjStm objects */
-    obj_type_others = 18        /* any other objects (also not linked in any list) */
+    obj_type_struct_dest = 3,   /* index of linked list of structure destination objects */
+    obj_type_obj = 4,           /* index of linked list of raw objects */
+    obj_type_xform = 5,         /* index of linked list of XObject forms */
+    obj_type_ximage = 6,        /* index of linked list of XObject images */
+    obj_type_thread = 7,        /* index of linked list of num article threads */
+    obj_type_pagestream = 8,    /* Page stream objects */
+    obj_type_page = 9,          /* /Page objects */
+    obj_type_pages = 10,        /* /Pages objects */
+    obj_type_catalog = 11,      /* /Catalog object */
+    obj_type_info = 12,         /* /Info object */
+    obj_type_link = 13,         /* link objects */
+    obj_type_annot = 14,        /* annotation objects */
+    obj_type_annots = 15,       /* /Annots objects */
+    obj_type_bead = 16,         /* thread bead objects */
+    obj_type_beads = 17,        /* /B objects (array of bead objects) */
+    obj_type_objstm = 18,       /* /ObjStm objects */
+    obj_type_others = 19        /* any other objects (also not linked in any list) */
 } pdf_obj_type;
 
-#  define HEAD_TAB_MAX      6   /* obj_type_thread */
-#  define PDF_OBJ_TYPE_MAX 18   /* obj_type_others */
+#  define HEAD_TAB_MAX      7   /* obj_type_thread */
+#  define PDF_OBJ_TYPE_MAX 19   /* obj_type_others */
 
 typedef struct pdf_resource_struct_ {
     struct avl_table *resources_tree;

Modified: trunk/Build/source/texk/web2c/luatexdir/tex/commands.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/tex/commands.c	2021-12-31 09:18:47 UTC (rev 61452)
+++ trunk/Build/source/texk/web2c/luatexdir/tex/commands.c	2021-12-31 10:38:50 UTC (rev 61453)
@@ -178,6 +178,7 @@
     primitive_luatex("glyphdimensionsmode", assign_int_cmd, int_base + glyph_dimensions_code, int_base);
     primitive_luatex("mathdefaultsmode", assign_int_cmd, int_base + math_defaults_mode_code, int_base);
     primitive_luatex("discretionaryligaturemode", assign_int_cmd, int_base + discretionary_ligature_mode_code, int_base);
+    primitive_etex("partokencontext", assign_int_cmd, int_base + partoken_context_code, int_base);
 
     /*tex
 
@@ -193,6 +194,7 @@
     primitive_tex("advance", advance_cmd, 0, 0);
     primitive_tex("afterassignment", after_assignment_cmd, 0, 0);
     primitive_tex("aftergroup", after_group_cmd, 0, 0);
+    primitive_etex("partokenname", partoken_name_cmd, 0, 0);
     primitive_tex("begingroup", begin_group_cmd, 0, 0);
     primitive_tex("char", char_num_cmd, 0, 0);
     primitive_tex("csname", cs_name_cmd, 0, 0);
@@ -818,15 +820,6 @@
     primitive_luatex("shapemode", assign_int_cmd, int_base + shape_mode_code, int_base);
     primitive_luatex("hyphenationbounds", assign_int_cmd, int_base + hyphenation_bounds_code, int_base);
 
-    /*tex
-
-        The \.{\\showstream} parameter allows to redirect the output of xray_cmd
-        commands to any write stream.
-
-    */
-
-    primitive_tex("showstream", assign_int_cmd, int_base + show_stream_code, int_base);
-
     primitive_etex("showgroups", xray_cmd, show_groups, 0);
 
     /*tex

Modified: trunk/Build/source/texk/web2c/luatexdir/tex/commands.h
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/tex/commands.h	2021-12-31 09:18:47 UTC (rev 61452)
+++ trunk/Build/source/texk/web2c/luatexdir/tex/commands.h	2021-12-31 10:38:50 UTC (rev 61453)
@@ -115,6 +115,7 @@
     ignore_spaces_cmd,                    /* gobble |spacer| tokens ( \.{\\ignorespaces} ) */
     after_assignment_cmd,                 /* save till assignment is done ( \.{\\afterassignment} ) */
     after_group_cmd,                      /* save till group is done ( \.{\\aftergroup} ) */
+    partoken_name_cmd,                    /* something pdftex, not sure if this is the right order */
     break_penalty_cmd,                    /* additional badness ( \.{\\penalty} ) */
     start_par_cmd,                        /* begin paragraph ( \.{\\indent}, \.{\\noindent} ) */
     ital_corr_cmd,                        /* italic correction ( \.{\\/} ) */

Modified: trunk/Build/source/texk/web2c/luatexdir/tex/dumpdata.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/tex/dumpdata.c	2021-12-31 09:18:47 UTC (rev 61452)
+++ trunk/Build/source/texk/web2c/luatexdir/tex/dumpdata.c	2021-12-31 10:38:50 UTC (rev 61453)
@@ -32,7 +32,7 @@
 
 */
 
-#define FORMAT_ID (907+56)
+#define FORMAT_ID (907+57)
 #if ((FORMAT_ID>=0) && (FORMAT_ID<=256))
 #error Wrong value for FORMAT_ID.
 #endif

Modified: trunk/Build/source/texk/web2c/luatexdir/tex/equivalents.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/tex/equivalents.c	2021-12-31 09:18:47 UTC (rev 61452)
+++ trunk/Build/source/texk/web2c/luatexdir/tex/equivalents.c	2021-12-31 10:38:50 UTC (rev 61453)
@@ -922,7 +922,7 @@
 
 In general, |cur_cmd| is the current command as set by |get_next|, while
 |cur_chr| is the operand of the current command. The control sequence found here
-is registsred in |cur_cs| and is zero if none found. The |cur_tok| variable
+is registered in |cur_cs| and is zero if none found. The |cur_tok| variable
 contains the packed representative of |cur_cmd| and |cur_chr| and like the other
 ones is global.
 

Modified: trunk/Build/source/texk/web2c/luatexdir/tex/equivalents.h
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/tex/equivalents.h	2021-12-31 09:18:47 UTC (rev 61452)
+++ trunk/Build/source/texk/web2c/luatexdir/tex/equivalents.h	2021-12-31 10:38:50 UTC (rev 61453)
@@ -311,9 +311,8 @@
 #  define glyph_dimensions_code 118
 #  define math_defaults_mode_code 119                                   /* > 0 : latex preferences */
 #  define discretionary_ligature_mode_code 120
+#  define partoken_context_code 121
 
-#  define show_stream_code 121
-
 #  define math_option_code 122
 
 #  define mathoption_int_base_code (math_option_code+1)                 /* one reserve */
@@ -817,8 +816,8 @@
 #define glyph_dimensions_par               int_par(glyph_dimensions_code)
 #define math_defaults_mode_par             int_par(math_defaults_mode_code)
 #define discretionary_ligature_mode_par    int_par(discretionary_ligature_mode_code)
+#define partoken_context_code_par          int_par(partoken_context_code)
 
-#define show_stream_par                    int_par(show_stream_code)
 
 /* */
 

Modified: trunk/Build/source/texk/web2c/luatexdir/tex/extensions.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/tex/extensions.c	2021-12-31 09:18:47 UTC (rev 61452)
+++ trunk/Build/source/texk/web2c/luatexdir/tex/extensions.c	2021-12-31 10:38:50 UTC (rev 61453)
@@ -365,8 +365,8 @@
 
 void do_extension(int immediate)
 {
-    /*tex An all-purpose pointer. */
-    halfword p;
+    /*tex All-purpose pointers. */
+    halfword k,p;
     if (cur_cmd == extension_cmd) {
         /*tex These have their own range starting at 0. */
         switch (cur_chr) {
@@ -403,9 +403,10 @@
                     be expanded later when this token list is rescanned.
 
                 */
+                k = cur_cs;
                 p = tail;
-                new_write_whatsit(write_node_size,0);
-                cur_cs = write_stream(tail);
+                new_write_whatsit(write_node_size,0); // this can modify cur_cs
+                cur_cs = k;                           // so we restore the prev. cur_cs, as in pdftex
                 scan_toks(false, false);
                 write_tokens(tail) = def_ref;
                 if (immediate) {

Modified: trunk/Build/source/texk/web2c/luatexdir/tex/mainbody.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/tex/mainbody.c	2021-12-31 09:18:47 UTC (rev 61452)
+++ trunk/Build/source/texk/web2c/luatexdir/tex/mainbody.c	2021-12-31 10:38:50 UTC (rev 61453)
@@ -441,7 +441,6 @@
         memset(eqtb, 0, sizeof(memory_word) * (unsigned) (eqtb_top + 1));
         init_string_pool_array((unsigned) max_strings);
         reset_cur_string();
-        show_stream_par = -1;
     }
     /*tex
         Check the ``constant'' values...

Modified: trunk/Build/source/texk/web2c/luatexdir/tex/maincontrol.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/tex/maincontrol.c	2021-12-31 09:18:47 UTC (rev 61452)
+++ trunk/Build/source/texk/web2c/luatexdir/tex/maincontrol.c	2021-12-31 10:38:50 UTC (rev 61453)
@@ -463,8 +463,16 @@
 }
 
 static void run_new_graf (void) {
-   back_input();
-   new_graf(true);
+    /* the |partoken_context_code_par| branch is taken from pdftex as-is: */
+    if (cur_cmd == valign_cmd && partoken_context_code_par > 0 && mode == hmode) {
+        back_input();
+        cur_tok = par_token;
+        back_input();
+        token_type = inserted;
+    } else {
+       back_input();
+       new_graf(true);
+    }
 }
 
 /*tex
@@ -607,6 +615,14 @@
     save_for_after(cur_tok);
 }
 
+static void run_par_token (void) {
+    get_token();
+    if (cur_cs > 0) {
+        par_loc = cur_cs;
+        par_token = cur_tok;
+    }
+}
+
 static void run_extension (void) {
     do_extension(0);
 }
@@ -976,6 +992,7 @@
     any_mode(set_interaction_cmd, prefixed_command);
     any_mode(after_assignment_cmd,run_after_assignment);
     any_mode(after_group_cmd,run_after_group);
+    any_mode(partoken_name_cmd,run_par_token);
     any_mode(in_stream_cmd,open_or_close_in);
     any_mode(message_cmd,issue_message);
     any_mode(case_shift_cmd, shift_case);
@@ -1272,7 +1289,7 @@
     you_cant();
     help4(
         "Sorry, but I'm not programmed to handle this case;",
-        "I'll just pretend that you didn''t ask for it.",
+        "I'll just pretend that you didn't ask for it.",
         "If you're in the wrong mode, you might be able to",
         "return to the right one by typing `I}' or `I$' or `I\\par'."
     );
@@ -1459,10 +1476,14 @@
 
 void handle_right_brace(void)
 {
-    halfword p, q;              /* for short-term use */
-    scaled d;                   /* holds |split_max_depth| in |insert_group| */
-    int f;                      /* holds |floating_penalty| in |insert_group| */
+    halfword p, q; /* for short-term use */
+    scaled d;      /* holds |split_max_depth| in |insert_group| */
+    int f;         /* holds |floating_penalty| in |insert_group| */
     p = null;
+    /*
+        The |partoken_context_code_par| branch is taken from pdftex as-is. We could save some lines
+        by first testing for hmode and the parameter but in the end it's not cleaner.
+    */
     switch (cur_group) {
         case simple_group:
             fixup_directions();
@@ -1502,57 +1523,89 @@
             package(0);
             break;
         case vbox_group:
-            end_graf(vbox_group);
-            package(0);
+            /* the |partoken_context_code_par| branch is taken from pdftex as-is: */
+            if (partoken_context_code_par > 0 && mode == hmode) {
+                back_input();
+                cur_tok = par_token;
+                back_input();
+                token_type = inserted;
+            } else {
+                end_graf(vbox_group);
+                package(0);
+            }
             break;
         case vtop_group:
-            end_graf(vtop_group);
-            package(vtop_code);
+            /* the |partoken_context_code_par| branch is taken from pdftex as-is: */
+            if (partoken_context_code_par > 0 && mode == hmode) {
+                back_input();
+                cur_tok = par_token;
+                back_input();
+                token_type = inserted;
+            } else {
+                end_graf(vtop_group);
+                package(vtop_code);
+            }
             break;
         case insert_group:
-            end_graf(insert_group);
-            q = new_glue(split_top_skip_par);
-            d = split_max_depth_par;
-            f = floating_penalty_par;
-            unsave();
-            save_ptr--;
-            /*tex
-                Now |saved_value(0)| is the insertion number, or the |vadjust| subtype.
-            */
-            p = vpack(vlink(head), 0, additional, -1);
-            pop_nest();
-            if (saved_type(0) == saved_insert) {
-                tail_append(new_node(ins_node, saved_value(0)));
-                height(tail) = height(p) + depth(p);
-                ins_ptr(tail) = list_ptr(p);
-                split_top_ptr(tail) = q;
-                depth(tail) = d;
-                float_cost(tail) = f;
-            } else if (saved_type(0) == saved_adjust) {
-                tail_append(new_node(adjust_node, saved_value(0)));
-                adjust_ptr(tail) = list_ptr(p);
-                flush_node(q);
+            /* the |partoken_context_code_par| branch is taken from pdftex as-is: */
+            if (partoken_context_code_par > 1 && mode == hmode) {
+                back_input();
+                cur_tok = par_token;
+                back_input();
+                token_type = inserted;
             } else {
-                confusion("insert_group");
+                end_graf(insert_group);
+                q = new_glue(split_top_skip_par);
+                d = split_max_depth_par;
+                f = floating_penalty_par;
+                unsave();
+                save_ptr--;
+                /*tex
+                    Now |saved_value(0)| is the insertion number, or the |vadjust| subtype.
+                */
+                p = vpack(vlink(head), 0, additional, -1);
+                pop_nest();
+                if (saved_type(0) == saved_insert) {
+                    tail_append(new_node(ins_node, saved_value(0)));
+                    height(tail) = height(p) + depth(p);
+                    ins_ptr(tail) = list_ptr(p);
+                    split_top_ptr(tail) = q;
+                    depth(tail) = d;
+                    float_cost(tail) = f;
+                } else if (saved_type(0) == saved_adjust) {
+                    tail_append(new_node(adjust_node, saved_value(0)));
+                    adjust_ptr(tail) = list_ptr(p);
+                    flush_node(q);
+                } else {
+                    confusion("insert_group");
+                }
+                list_ptr(p) = null;
+                flush_node(p);
+                if (nest_ptr == 0) {
+                    checked_page_filter(insert);
+                    build_page();
+                }
             }
-            list_ptr(p) = null;
-            flush_node(p);
-            if (nest_ptr == 0) {
-                checked_page_filter(insert);
-                build_page();
-            }
             break;
         case output_group:
-            /*tex
-                this is needed in case the \.{\\output} executes a \.{\\textdir} command.
-            */
-            if (dir_level(text_dir_ptr) == cur_level) {
-                /*tex Remove from |text_dir_ptr| */
-                halfword text_dir_tmp = vlink(text_dir_ptr);
-                flush_node(text_dir_ptr);
-                text_dir_ptr = text_dir_tmp;
+            /* the |partoken_context_code_par| branch is taken from pdftex as-is: */
+            if (partoken_context_code_par > 1 && mode == hmode) {
+                back_input();
+                cur_tok = par_token;
+                back_input();
+                token_type = inserted;
+            } else {
+                /*tex
+                    this is needed in case the \.{\\output} executes a \.{\\textdir} command.
+                */
+                if (dir_level(text_dir_ptr) == cur_level) {
+                    /*tex Remove from |text_dir_ptr| */
+                    halfword text_dir_tmp = vlink(text_dir_ptr);
+                    flush_node(text_dir_ptr);
+                    text_dir_ptr = text_dir_tmp;
+                }
+                resume_after_output();
             }
-            resume_after_output();
             break;
         case disc_group:
             build_discretionary();
@@ -1570,13 +1623,29 @@
             ins_error();
             break;
         case no_align_group:
-            end_graf(no_align_group);
-            unsave();
-            align_peek();
+            /* the |partoken_context_code_par| branch is taken from pdftex as-is: */
+            if (partoken_context_code_par > 1 && mode == hmode) {
+                back_input();
+                cur_tok = par_token;
+                back_input();
+                token_type = inserted;
+            } else {
+                end_graf(no_align_group);
+                unsave();
+                align_peek();
+            }
             break;
         case vcenter_group:
-            end_graf(vcenter_group);
-            finish_vcenter();
+            /* the |partoken_context_code_par| branch is taken from pdftex as-is: */
+            if (partoken_context_code_par > 0 && mode == hmode) {
+                back_input();
+                cur_tok = par_token;
+                back_input();
+                token_type = inserted;
+            } else {
+                end_graf(vcenter_group);
+                finish_vcenter();
+            }
             break;
         case math_choice_group:
             build_choices();
@@ -1873,14 +1942,30 @@
 
 */
 
+static int only_dirs(halfword n)
+{
+    while (n) {
+        if (type(n) == local_par_node || type(n) == dir_node) {
+            n = vlink(n);
+        } else {
+            return 0;
+        }
+    }
+    return 1;
+}
+
 void end_graf(int line_break_context)
 {
     if (mode == hmode) {
-        if ((head == tail) || (vlink(head) == tail)) {
-            if (vlink(head) == tail)
-                flush_node(vlink(head));
-            /*tex |null| paragraphs are ignored, all contain a |local_paragraph| node */
+        /*tex
+            We ignore |null| paragraphs, that is those that only have a local par node
+            and possibly a few dir nodes injected automatically.
+        */
+        if (head == tail) {
             pop_nest();
+        } else if (only_dirs(vlink(head))) {
+            flush_node(vlink(head));
+            pop_nest();
         } else {
             line_break(false, line_break_context);
         }
@@ -3968,10 +4053,6 @@
     int m;      /* upper bound on |fi_or_else| codes */
     int l;      /* line where that conditional began */
     int n;      /* level of \.{\\if...\\fi} nesting */
-    int saved_selector; /* previous selector. Must be distinct from the global err_old_setting. */
-    saved_selector = selector;
-    if (file_can_be_written(show_stream_par))
-        selector = show_stream_par;
     switch (cur_chr) {
     case show_lists:
         begin_diagnostic();
@@ -4066,10 +4147,6 @@
         }
     }
   COMMON_ENDING:
-    if (valid_write_file(selector)) {
-        selector = saved_selector;
-        return;
-    }
     if (interaction < error_stop_mode) {
         help0();
         decr(error_count);

Modified: trunk/Build/source/texk/web2c/luatexdir/tex/primitive.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/tex/primitive.c	2021-12-31 09:18:47 UTC (rev 61452)
+++ trunk/Build/source/texk/web2c/luatexdir/tex/primitive.c	2021-12-31 10:38:50 UTC (rev 61453)
@@ -582,7 +582,7 @@
 a \TeX\ primitive into |eqtb|.
 
 Thanks to |prim_data|, there is no need for all that tediousness. What is left of
-|primt_cnd_chr| are just the exceptions to the general rule that the
+|print_cmd_chr| are just the exceptions to the general rule that the
 |cmd,chr_code| pair represents in a single primitive command.
 
 */

Modified: trunk/Build/source/texk/web2c/luatexdir/tex/printing.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/tex/printing.c	2021-12-31 09:18:47 UTC (rev 61452)
+++ trunk/Build/source/texk/web2c/luatexdir/tex/printing.c	2021-12-31 10:38:50 UTC (rev 61453)
@@ -466,6 +466,7 @@
     /*tex What is left is the 3 term/log settings. */
     if (dolog || doterm) {
         buffer = xmalloc(strlen(sss)*3);
+        buffer[0] = '\0';
         /*tex The |wrapup_run| callback acts when the log file is already closed.*/
         if (dolog && log_opened_global) {
             const unsigned char *ss = (const unsigned char *) sss;

Modified: trunk/Build/source/texk/web2c/luatexdir/tex/scanning.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/tex/scanning.c	2021-12-31 09:18:47 UTC (rev 61452)
+++ trunk/Build/source/texk/web2c/luatexdir/tex/scanning.c	2021-12-31 10:38:50 UTC (rev 61453)
@@ -1818,9 +1818,10 @@
             font_param_error(f);
         } else {
             /*tex Increase the number of parameters in the font. */
-            do {
-                set_font_param(f, (font_params(f) + 1), 0);
-            } while (n != font_params(f));
+         // do {
+         //     set_font_param(f, (font_params(f) + 1), 0);
+         // } while (n != font_params(f));
+            set_font_params(f, n);
         }
     }
     scan_optional_equals();
@@ -1848,9 +1849,10 @@
             goto EXIT;
         } else {
             /*tex Increase the number of parameters in the font. */
-            do {
-                set_font_param(f, (font_params(f) + 1), 0);
-            } while (n != font_params(f));
+         // do {
+         //     set_font_param(f, (font_params(f) + 1), 0);
+         // } while (n != font_params(f));
+            set_font_params(f, n);
         }
     }
     cur_val = font_param(f, n);
@@ -2521,10 +2523,10 @@
     a = arith_error;
     b = false;
     p = null;
-    /*tex 
-     
-         Scan and evaluate an expression |e| of type |l|. 
-         To avoid an infinite recursion we set|max_nesting| as upper limit. 
+    /*tex
+
+         Scan and evaluate an expression |e| of type |l|.
+         To avoid an infinite recursion we set|max_nesting| as upper limit.
          This limit is unrelated to the expansion limit |expand_depth| and it cannot be modify at compile time.
 
      */

Modified: trunk/Build/source/texk/web2c/luatexdir/tex/texfileio.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/tex/texfileio.c	2021-12-31 09:18:47 UTC (rev 61452)
+++ trunk/Build/source/texk/web2c/luatexdir/tex/texfileio.c	2021-12-31 10:38:50 UTC (rev 61453)
@@ -637,8 +637,11 @@
     int k;
     /*tex Now the user sees the prompt for sure: */
     update_terminal();
-    if (!input_ln(term_in, true))
+    if (!input_ln(term_in, true)) {
+        /*tex  initialize limit to avoid printing some garbage. */
+        ilimit=0;
         fatal_error("End of file on the terminal!");
+    }
     /*tex The user's line ended with \.{<return>}: */
     term_offset = 0;
     /*tex Prepare to echo the input. */

Modified: trunk/Build/source/texk/web2c/luatexdir/tex/texnodes.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/tex/texnodes.c	2021-12-31 09:18:47 UTC (rev 61452)
+++ trunk/Build/source/texk/web2c/luatexdir/tex/texnodes.c	2021-12-31 10:38:50 UTC (rev 61453)
@@ -1107,7 +1107,8 @@
     init_field_key(node_fields_whatsit_pdf_action, 3, file);
     init_field_key(node_fields_whatsit_pdf_action, 4, new_window);
     init_field_key(node_fields_whatsit_pdf_action, 5, data);
-    init_field_nop(node_fields_whatsit_pdf_action, 6);
+    init_field_key(node_fields_whatsit_pdf_action, 6, struct_id);
+    init_field_nop(node_fields_whatsit_pdf_action, 7);
 
     init_field_key(node_fields_whatsit_pdf_annot, 0, attr);
     init_field_key(node_fields_whatsit_pdf_annot, 1, width);
@@ -2302,8 +2303,10 @@
                     delete_token_ref(pdf_action_file(p));
                 if (pdf_action_type(p) == pdf_action_page)
                     delete_token_ref(pdf_action_tokens(p));
-                else if (pdf_action_named_id(p) > 0)
+                else if (pdf_action_named_id(p) & 1)
                     delete_token_ref(pdf_action_id(p));
+                if (pdf_action_named_id(p) & 2)
+                    delete_token_ref(pdf_action_struct_id(p));
             }
             break;
         case pdf_thread_data_node:
@@ -3636,9 +3639,21 @@
                 tprint(" file");
                 print_mark(pdf_action_file(pdf_link_action(p)));
             }
+            if (pdf_action_struct_id(pdf_link_action(p)) != null) {
+                tprint(" struct");
+                if (pdf_action_file(pdf_link_action(p)) != null) {
+                    print_mark(pdf_action_struct_id(pdf_link_action(p)));
+                } else if (pdf_action_named_id(pdf_link_action(p)) & 2) {
+                    tprint(" name");
+                    print_mark(pdf_action_struct_id(pdf_link_action(p)));
+                } else {
+                    tprint(" num");
+                    print_int(pdf_action_struct_id(pdf_link_action(p)));
+                }
+            }
             switch (pdf_action_type(pdf_link_action(p))) {
             case pdf_action_goto:
-                if (pdf_action_named_id(pdf_link_action(p)) > 0) {
+                if (pdf_action_named_id(pdf_link_action(p)) & 1) {
                     tprint(" goto name");
                     print_mark(pdf_action_id(pdf_link_action(p)));
                 } else {
@@ -3652,7 +3667,7 @@
                 print_mark(pdf_action_tokens(pdf_link_action(p)));
                 break;
             case pdf_action_thread:
-                if (pdf_action_named_id(pdf_link_action(p)) > 0) {
+                if (pdf_action_named_id(pdf_link_action(p)) & 1) {
                     tprint(" thread name");
                     print_mark(pdf_action_id(pdf_link_action(p)));
                 } else {

Modified: trunk/Build/source/texk/web2c/luatexdir/tex/texnodes.h
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/tex/texnodes.h	2021-12-31 09:18:47 UTC (rev 61452)
+++ trunk/Build/source/texk/web2c/luatexdir/tex/texnodes.h	2021-12-31 10:38:50 UTC (rev 61453)
@@ -949,12 +949,13 @@
 #  define pdf_action_size           6
 
 #  define pdf_action_type(a)        vlink((a)+2) /* enum pdf_action_type */
-#  define pdf_action_named_id(a)    vinfo((a)+2) /* boolean */
+#  define pdf_action_named_id(a)    vinfo((a)+2) /* bitset of two booleans */
 #  define pdf_action_id(a)          vlink((a)+3) /* number or toks */
 #  define pdf_action_file(a)        vinfo((a)+3) /* toks */
 #  define pdf_action_new_window(a)  vlink((a)+4) /* enum pdf_window_type */
 #  define pdf_action_tokens(a)      vinfo((a)+4) /* toks */
 #  define pdf_action_refcount(a)    vlink((a)+5) /* number */
+#  define pdf_action_struct_id(a)   vinfo((a)+5) /* number or toks */
 
 typedef enum {
     colorstack_set = 0,

Modified: trunk/Build/source/texk/web2c/luatexdir/tex/textoken.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/tex/textoken.c	2021-12-31 09:18:47 UTC (rev 61452)
+++ trunk/Build/source/texk/web2c/luatexdir/tex/textoken.c	2021-12-31 10:38:50 UTC (rev 61453)
@@ -3469,6 +3469,8 @@
                     n = -1;
                 }
             } else {
+                /*tex  initialize limit to avoid printing some garbage. */
+                ilimit=0;
                 fatal_error
                     ("*** (cannot \\read from terminal in nonstop modes)");
             }



More information about the tex-live-commits mailing list.