texlive[49176] Build/source/texk/web2c: Support some primitives from

commits+kakuto at tug.org commits+kakuto at tug.org
Sat Nov 17 08:32:49 CET 2018


Revision: 49176
          http://tug.org/svn/texlive?view=revision&revision=49176
Author:   kakuto
Date:     2018-11-17 08:32:49 +0100 (Sat, 17 Nov 2018)
Log Message:
-----------
Support some primitives from pdfTeX in XeTeX (Joseph Wright)

Modified Paths:
--------------
    trunk/Build/source/texk/web2c/ChangeLog
    trunk/Build/source/texk/web2c/lib/ChangeLog
    trunk/Build/source/texk/web2c/lib/texmfmp.c
    trunk/Build/source/texk/web2c/texmfmp.h
    trunk/Build/source/texk/web2c/xetexdir/ChangeLog
    trunk/Build/source/texk/web2c/xetexdir/xetex.defines
    trunk/Build/source/texk/web2c/xetexdir/xetex.web

Modified: trunk/Build/source/texk/web2c/ChangeLog
===================================================================
--- trunk/Build/source/texk/web2c/ChangeLog	2018-11-17 01:23:12 UTC (rev 49175)
+++ trunk/Build/source/texk/web2c/ChangeLog	2018-11-17 07:32:49 UTC (rev 49176)
@@ -1,3 +1,7 @@
+2018-11-17  Joseph Wright  <joseph.wright at morningstar2.co.uk>
+
+	* texmfmp.h: Support some primitives from pdfTeX in XeTeX.
+
 2018-09-09  Karl Berry  <karl at tug.org>
 
 	* mftraptest.test,

Modified: trunk/Build/source/texk/web2c/lib/ChangeLog
===================================================================
--- trunk/Build/source/texk/web2c/lib/ChangeLog	2018-11-17 01:23:12 UTC (rev 49175)
+++ trunk/Build/source/texk/web2c/lib/ChangeLog	2018-11-17 07:32:49 UTC (rev 49176)
@@ -1,3 +1,7 @@
+2018-11-17  Joseph Wright  <joseph.wright at morningstar2.co.uk>
+
+	* texmfmp.c: Support some primitives from pdfTeX in XeTeX.
+
 2018-11-14  Andreas Scherer  <https://ascherer.github.io>
 
 	* printversion.c: free xmalloc'd prog_name.

Modified: trunk/Build/source/texk/web2c/lib/texmfmp.c
===================================================================
--- trunk/Build/source/texk/web2c/lib/texmfmp.c	2018-11-17 01:23:12 UTC (rev 49175)
+++ trunk/Build/source/texk/web2c/lib/texmfmp.c	2018-11-17 07:32:49 UTC (rev 49176)
@@ -151,7 +151,22 @@
 #if !IS_pTeX
 FILE *Poptr;
 #endif
-#endif
+#undef fopen
+#undef xfopen
+#define fopen fsyscp_fopen
+#define xfopen fsyscp_xfopen
+#include <wchar.h>
+int fsyscp_stat(const char *path, struct stat *buffer)
+{
+  wchar_t *wpath;
+  int     ret;
+  wpath = get_wstring_from_mbstring(file_system_codepage,
+          path, wpath = NULL);
+  ret = _wstat(wpath, buffer);
+  free(wpath);
+  return ret;
+}
+#endif /* WIN32 */
 
 #if defined(TeX) || (defined(MF) && defined(WIN32))
 static int
@@ -1379,24 +1394,6 @@
 
 /* FIXME: A new format ought to be introduced for these files. */
 
-#ifdef _WIN32
-#undef fopen
-#undef xfopen
-#define fopen fsyscp_fopen
-#define xfopen fsyscp_xfopen
-#include <wchar.h>
-int fsyscp_stat(const char *path, struct stat *buffer)
-{
-  wchar_t *wpath;
-  int     ret;
-  wpath = get_wstring_from_mbstring(file_system_codepage,
-          path, wpath = NULL);
-  ret = _wstat(wpath, buffer);
-  free(wpath);
-  return ret;
-}
-#endif /* WIN32 */
-
 void
 readtcxfile (void)
 {
@@ -2322,7 +2319,7 @@
   }
 }
 

-#if defined(pdfTeX) || defined(epTeX) || defined(eupTeX)
+#if defined(pdfTeX) || defined(epTeX) || defined(eupTeX) || defined(XeTeX)
 /*
  Getting a high resolution time.
  */
@@ -3010,8 +3007,6 @@
 }
 #endif /* not pdfTeX */
 
-#if !defined(XeTeX)
-
 #define TIME_STR_SIZE 30
 char start_time_str[TIME_STR_SIZE];
 static char time_str[TIME_STR_SIZE];
@@ -3280,7 +3275,6 @@
     }
     xfree(file_name);
 }
-#endif /* not XeTeX */
 
 /* Converts any given string in into an allowed PDF string which is
  * hexadecimal encoded;

Modified: trunk/Build/source/texk/web2c/texmfmp.h
===================================================================
--- trunk/Build/source/texk/web2c/texmfmp.h	2018-11-17 01:23:12 UTC (rev 49175)
+++ trunk/Build/source/texk/web2c/texmfmp.h	2018-11-17 07:32:49 UTC (rev 49176)
@@ -124,7 +124,6 @@
 #if !defined (pdfTeX)
 extern void pdftex_fail(const char *fmt, ...);
 #endif
-#if !defined(XeTeX)
 extern char start_time_str[];
 extern void initstarttime(void);
 extern char *makecstring(integer s);
@@ -133,7 +132,6 @@
 extern void getfilemoddate(integer s);
 extern void getfilesize(integer s);
 extern void getfiledump(integer s, int offset, int length);
-#endif
 extern void convertStringToHexString(const char *in, char *out, int lin);
 extern void getmd5sum(integer s, int file);
 #endif
@@ -220,7 +218,7 @@
 #define	dateandtime(i,j,k,l) get_date_and_time (&(i), &(j), &(k), &(l))
 extern void get_date_and_time (integer *, integer *, integer *, integer *);
 
-#if defined(pdfTeX) || defined(epTeX) || defined(eupTeX)
+#if defined(pdfTeX) || defined(epTeX) || defined(eupTeX) || defined(XeTeX)
 /* Get high-res time info. */
 #define secondsandmicros(i,j) get_seconds_and_micros (&(i), &(j))
 extern void get_seconds_and_micros (integer *, integer *);

Modified: trunk/Build/source/texk/web2c/xetexdir/ChangeLog
===================================================================
--- trunk/Build/source/texk/web2c/xetexdir/ChangeLog	2018-11-17 01:23:12 UTC (rev 49175)
+++ trunk/Build/source/texk/web2c/xetexdir/ChangeLog	2018-11-17 07:32:49 UTC (rev 49176)
@@ -1,3 +1,8 @@
+2018-11-17  Joseph Wright  <joseph.wright at morningstar2.co.uk>
+
+	* xetex.web, xetex.defines: Support some primitives from
+	pdfTeX in XeTeX. Add \expanded and extend \Uchar a bit.
+
 2018-10-22  Akira Kakuto  <kakuto at fuk.kindai.ac.jp>
 
 	* pdfimage.cpp: Cast types to support poppler 0.70.0.

Modified: trunk/Build/source/texk/web2c/xetexdir/xetex.defines
===================================================================
--- trunk/Build/source/texk/web2c/xetexdir/xetex.defines	2018-11-17 01:23:12 UTC (rev 49175)
+++ trunk/Build/source/texk/web2c/xetexdir/xetex.defines	2018-11-17 07:32:49 UTC (rev 49176)
@@ -179,4 +179,9 @@
 @define function getcpcode();
 @define function getnativewordcp();
 
+ at define procedure initstarttime;
+ at define procedure getcreationdate;
+ at define procedure getfilemoddate();
+ at define procedure getfilesize();
+ at define procedure getfiledump();
 @define procedure getmd5sum();

Modified: trunk/Build/source/texk/web2c/xetexdir/xetex.web
===================================================================
--- trunk/Build/source/texk/web2c/xetexdir/xetex.web	2018-11-17 01:23:12 UTC (rev 49175)
+++ trunk/Build/source/texk/web2c/xetexdir/xetex.web	2018-11-17 07:32:49 UTC (rev 49176)
@@ -2593,6 +2593,367 @@
 @<Types...@>=
 @!glue_ratio=real; {one-word representation of a glue expansion factor}
 
+@* \[7b] Random numbers.
+
+\font\tenlogo=logo10 % font used for the METAFONT logo
+\def\MP{{\tenlogo META}\-{\tenlogo POST}}
+\def\pdfTeX{pdf\TeX}
+
+This section is (almost) straight from MetaPost. I had to change
+the types (use |integer| instead of |fraction|), but that should
+not have any influence on the actual calculations (the original
+comments refer to quantities like |fraction_four| ($2^{30}$), and
+that is the same as the numeric representation of |maxdimen|).
+
+I've copied the low-level variables and routines that are needed, but
+only those (e.g. |m_log|), not the accompanying ones like |m_exp|. Most
+of the following low-level numeric routines are only needed within the
+calculation of |norm_rand|. I've been forced to rename |make_fraction|
+to |make_frac| because TeX already has a routine by that name with
+a wholly different function (it creates a |fraction_noad| for math
+typesetting) -- Taco
+
+And now let's complete our collection of numeric utility routines
+by considering random number generation.
+\MP\ generates pseudo-random numbers with the additive scheme recommended
+in Section 3.6 of {\sl The Art of Computer Programming}; however, the
+results are random fractions between 0 and |fraction_one-1|, inclusive.
+
+There's an auxiliary array |randoms| that contains 55 pseudo-random
+fractions. Using the recurrence $x_n=(x_{n-55}-x_{n-31})\bmod 2^{28}$,
+we generate batches of 55 new $x_n$'s at a time by calling |new_randoms|.
+The global variable |j_random| tells which element has most recently
+been consumed.
+
+@<Glob...@>=
+@!randoms:array[0..54] of integer; {the last 55 random values generated}
+@!j_random:0..54; {the number of unused |randoms|}
+@!random_seed:scaled; {the default random seed}
+
+@ A small bit of metafont is needed.
+
+ at d fraction_half==@'1000000000 {$2^{27}$, represents 0.50000000}
+ at d fraction_one==@'2000000000 {$2^{28}$, represents 1.00000000}
+ at d fraction_four==@'10000000000 {$2^{30}$, represents 4.00000000}
+ at d el_gordo == @'17777777777 {$2^{31}-1$, the largest value that \MP\ likes}
+ at d halfp(#)==(#) div 2
+ at d double(#) == #:=#+# {multiply a variable by two}
+
+@ The |make_frac| routine produces the |fraction| equivalent of
+|p/q|, given integers |p| and~|q|; it computes the integer
+$f=\lfloor2^{28}p/q+{1\over2}\rfloor$, when $p$ and $q$ are
+positive. If |p| and |q| are both of the same scaled type |t|,
+the ``type relation'' |make_frac(t,t)=fraction| is valid;
+and it's also possible to use the subroutine ``backwards,'' using
+the relation |make_frac(t,fraction)=t| between scaled types.
+
+If the result would have magnitude $2^{31}$ or more, |make_frac|
+sets |arith_error:=true|. Most of \MP's internal computations have
+been designed to avoid this sort of error.
+
+If this subroutine were programmed in assembly language on a typical
+machine, we could simply compute |(@t$2^{28}$@>*p)div q|, since a
+double-precision product can often be input to a fixed-point division
+instruction. But when we are restricted to \PASCAL\ arithmetic it
+is necessary either to resort to multiple-precision maneuvering
+or to use a simple but slow iteration. The multiple-precision technique
+would be about three times faster than the code adopted here, but it
+would be comparatively long and tricky, involving about sixteen
+additional multiplications and divisions.
+
+This operation is part of \MP's ``inner loop''; indeed, it will
+consume nearly 10\pct! of the running time (exclusive of input and output)
+if the code below is left unchanged. A machine-dependent recoding
+will therefore make \MP\ run faster. The present implementation
+is highly portable, but slow; it avoids multiplication and division
+except in the initial stage. System wizards should be careful to
+replace it with a routine that is guaranteed to produce identical
+results in all cases.
+@^system dependencies@>
+
+As noted below, a few more routines should also be replaced by machine-dependent
+code, for efficiency. But when a procedure is not part of the ``inner loop,''
+such changes aren't advisable; simplicity and robustness are
+preferable to trickery, unless the cost is too high.
+@^inner loop@>
+
+ at p function make_frac(@!p,@!q:integer):integer;
+var @!f:integer; {the fraction bits, with a leading 1 bit}
+@!n:integer; {the integer part of $\vert p/q\vert$}
+@!negative:boolean; {should the result be negated?}
+@!be_careful:integer; {disables certain compiler optimizations}
+begin if p>=0 then negative:=false
+else  begin negate(p); negative:=true;
+  end;
+if q<=0 then
+  begin debug if q=0 then confusion("/");@;@+gubed@;@/
+@:this can't happen /}{\quad \./@>
+  negate(q); negative:=not negative;
+  end;
+n:=p div q; p:=p mod q;
+if n>=8 then
+  begin arith_error:=true;
+  if negative then make_frac:=-el_gordo at +else make_frac:=el_gordo;
+  end
+else  begin n:=(n-1)*fraction_one;
+  @<Compute $f=\lfloor 2^{28}(1+p/q)+{1\over2}\rfloor$@>;
+  if negative then make_frac:=-(f+n)@+else make_frac:=f+n;
+  end;
+end;
+
+@ The |repeat| loop here preserves the following invariant relations
+between |f|, |p|, and~|q|:
+(i)~|0<=p<q|; (ii)~$fq+p=2^k(q+p_0)$, where $k$ is an integer and
+$p_0$ is the original value of~$p$.
+
+Notice that the computation specifies
+|(p-q)+p| instead of |(p+p)-q|, because the latter could overflow.
+Let us hope that optimizing compilers do not miss this point; a
+special variable |be_careful| is used to emphasize the necessary
+order of computation. Optimizing compilers should keep |be_careful|
+in a register, not store it in memory.
+@^inner loop@>
+
+@<Compute $f=\lfloor 2^{28}(1+p/q)+{1\over2}\rfloor$@>=
+f:=1;
+repeat be_careful:=p-q; p:=be_careful+p;
+if p>=0 then f:=f+f+1
+else  begin double(f); p:=p+q;
+  end;
+until f>=fraction_one;
+be_careful:=p-q;
+if be_careful+p>=0 then incr(f)
+
+@
+
+ at p function take_frac(@!q:integer;@!f:integer):integer;
+var @!p:integer; {the fraction so far}
+@!negative:boolean; {should the result be negated?}
+@!n:integer; {additional multiple of $q$}
+@!be_careful:integer; {disables certain compiler optimizations}
+begin @<Reduce to the case that |f>=0| and |q>0|@>;
+if f<fraction_one then n:=0
+else  begin n:=f div fraction_one; f:=f mod fraction_one;
+  if q<=el_gordo div n then n:=n*q
+  else  begin arith_error:=true; n:=el_gordo;
+    end;
+  end;
+f:=f+fraction_one;
+@<Compute $p=\lfloor qf/2^{28}+{1\over2}\rfloor-q$@>;
+be_careful:=n-el_gordo;
+if be_careful+p>0 then
+  begin arith_error:=true; n:=el_gordo-p;
+  end;
+if negative then take_frac:=-(n+p)
+else take_frac:=n+p;
+end;
+
+@ @<Reduce to the case that |f>=0| and |q>0|@>=
+if f>=0 then negative:=false
+else  begin negate(f); negative:=true;
+  end;
+if q<0 then
+  begin negate(q); negative:=not negative;
+  end;
+
+@ The invariant relations in this case are (i)~$\lfloor(qf+p)/2^k\rfloor
+=\lfloor qf_0/2^{28}+{1\over2}\rfloor$, where $k$ is an integer and
+$f_0$ is the original value of~$f$; (ii)~$2^k\L f<2^{k+1}$.
+@^inner loop@>
+
+@<Compute $p=\lfloor qf/2^{28}+{1\over2}\rfloor-q$@>=
+p:=fraction_half; {that's $2^{27}$; the invariants hold now with $k=28$}
+if q<fraction_four then
+  repeat if odd(f) then p:=halfp(p+q)@+else p:=halfp(p);
+  f:=halfp(f);
+  until f=1
+else  repeat if odd(f) then p:=p+halfp(q-p)@+else p:=halfp(p);
+  f:=halfp(f);
+  until f=1
+
+@ The subroutines for logarithm and exponential involve two tables.
+The first is simple: |two_to_the[k]| equals $2^k$. The second involves
+a bit more calculation, which the author claims to have done correctly:
+|spec_log[k]| is $2^{27}$ times $\ln\bigl(1/(1-2^{-k})\bigr)=
+2^{-k}+{1\over2}2^{-2k}+{1\over3}2^{-3k}+\cdots\,$, rounded to the
+nearest integer.
+
+@<Glob...@>=
+@!two_to_the:array[0..30] of integer; {powers of two}
+@!spec_log:array[1..28] of integer; {special logarithms}
+
+
+@ @<Set init...@>=
+two_to_the[0]:=1;
+for k:=1 to 30 do two_to_the[k]:=2*two_to_the[k-1];
+spec_log[1]:=93032640;
+spec_log[2]:=38612034;
+spec_log[3]:=17922280;
+spec_log[4]:=8662214;
+spec_log[5]:=4261238;
+spec_log[6]:=2113709;
+spec_log[7]:=1052693;
+spec_log[8]:=525315;
+spec_log[9]:=262400;
+spec_log[10]:=131136;
+spec_log[11]:=65552;
+spec_log[12]:=32772;
+spec_log[13]:=16385;
+for k:=14 to 27 do spec_log[k]:=two_to_the[27-k];
+spec_log[28]:=1;
+
+@
+
+ at p function m_log(@!x:integer):integer;
+var @!y,@!z:integer; {auxiliary registers}
+@!k:integer; {iteration counter}
+begin if x<=0 then @<Handle non-positive logarithm@>
+else  begin y:=1302456956+4-100; {$14\times2^{27}\ln2\approx1302456956.421063$}
+  z:=27595+6553600; {and $2^{16}\times .421063\approx 27595$}
+  while x<fraction_four do
+    begin double(x); y:=y-93032639; z:=z-48782;
+    end; {$2^{27}\ln2\approx 93032639.74436163$
+      and $2^{16}\times.74436163\approx 48782$}
+  y:=y+(z div unity); k:=2;
+  while x>fraction_four+4 do
+    @<Increase |k| until |x| can be multiplied by a
+      factor of $2^{-k}$, and adjust $y$ accordingly@>;
+  m_log:=y div 8;
+  end;
+end;
+
+@ @<Increase |k| until |x| can...@>=
+begin z:=((x-1) div two_to_the[k])+1; {$z=\lceil x/2^k\rceil$}
+while x<fraction_four+z do
+  begin z:=halfp(z+1); k:=k+1;
+  end;
+y:=y+spec_log[k]; x:=x-z;
+end
+
+@ @<Handle non-positive logarithm@>=
+begin print_err("Logarithm of ");
+ at .Logarithm...replaced by 0@>
+print_scaled(x); print(" has been replaced by 0");
+help2("Since I don't take logs of non-positive numbers,")@/
+  ("I'm zeroing this one. Proceed, with fingers crossed.");
+error; m_log:=0;
+end
+
+@ The following somewhat different subroutine tests rigorously if $ab$ is
+greater than, equal to, or less than~$cd$,
+given integers $(a,b,c,d)$. In most cases a quick decision is reached.
+The result is $+1$, 0, or~$-1$ in the three respective cases.
+
+ at d return_sign(#)==begin ab_vs_cd:=#; return;
+  end
+
+ at p function ab_vs_cd(@!a,b,c,d:integer):integer;
+label exit;
+var @!q,@!r:integer; {temporary registers}
+begin @<Reduce to the case that |a,c>=0|, |b,d>0|@>;
+loop at +  begin q := a div d; r := c div b;
+  if q<>r then
+    if q>r then return_sign(1)@+else return_sign(-1);
+  q := a mod d; r := c mod b;
+  if r=0 then
+    if q=0 then return_sign(0)@+else return_sign(1);
+  if q=0 then return_sign(-1);
+  a:=b; b:=q; c:=d; d:=r;
+  end; {now |a>d>0| and |c>b>0|}
+exit:end;
+
+@ @<Reduce to the case that |a...@>=
+if a<0 then
+  begin negate(a); negate(b);
+  end;
+if c<0 then
+  begin negate(c); negate(d);
+  end;
+if d<=0 then
+  begin if b>=0 then
+    if ((a=0)or(b=0))and((c=0)or(d=0)) then return_sign(0)
+    else return_sign(1);
+  if d=0 then
+    if a=0 then return_sign(0)@+else return_sign(-1);
+  q:=a; a:=c; c:=q; q:=-b; b:=-d; d:=q;
+  end
+else if b<=0 then
+  begin if b<0 then if a>0 then return_sign(-1);
+  if c=0 then return_sign(0) else return_sign(-1);
+  end
+
+@ To consume a random integer, the program below will say `|next_random|'
+and then it will fetch |randoms[j_random]|.
+
+ at d next_random==if j_random=0 then new_randoms
+  else decr(j_random)
+
+ at p procedure new_randoms;
+var @!k:0..54; {index into |randoms|}
+@!x:integer; {accumulator}
+begin for k:=0 to 23 do
+  begin x:=randoms[k]-randoms[k+31];
+  if x<0 then x:=x+fraction_one;
+  randoms[k]:=x;
+  end;
+for k:=24 to 54 do
+  begin x:=randoms[k]-randoms[k-24];
+  if x<0 then x:=x+fraction_one;
+  randoms[k]:=x;
+  end;
+j_random:=54;
+end;
+
+@ To initialize the |randoms| table, we call the following routine.
+
+ at p procedure init_randoms(@!seed:integer);
+var @!j,@!jj,@!k:integer; {more or less random integers}
+@!i:0..54; {index into |randoms|}
+begin j:=abs(seed);
+while j>=fraction_one do j:=halfp(j);
+k:=1;
+for i:=0 to 54 do
+  begin jj:=k; k:=j-k; j:=jj;
+  if k<0 then k:=k+fraction_one;
+  randoms[(i*21)mod 55]:=j;
+  end;
+new_randoms; new_randoms; new_randoms; {``warm up'' the array}
+end;
+
+@ To produce a uniform random number in the range |0<=u<x| or |0>=u>x|
+or |0=u=x|, given a |scaled| value~|x|, we proceed as shown here.
+
+Note that the call of |take_frac| will produce the values 0 and~|x|
+with about half the probability that it will produce any other particular
+values between 0 and~|x|, because it rounds its answers.
+
+ at p function unif_rand(@!x:integer):integer;
+var @!y:integer; {trial value}
+begin next_random; y:=take_frac(abs(x),randoms[j_random]);
+if y=abs(x) then unif_rand:=0
+else if x>0 then unif_rand:=y
+else unif_rand:=-y;
+end;
+
+@ Finally, a normal deviate with mean zero and unit standard deviation
+can readily be obtained with the ratio method (Algorithm 3.4.1R in
+{\sl The Art of Computer Programming\/}).
+
+ at p function norm_rand:integer;
+var @!x,@!u,@!l:integer; {what the book would call $2^{16}X$, $2^{28}U$,
+  and $-2^{24}\ln U$}
+begin repeat
+  repeat next_random;
+  x:=take_frac(112429,randoms[j_random]-fraction_half);
+    {$2^{16}\sqrt{8/e}\approx 112428.82793$}
+  next_random; u:=randoms[j_random];
+  until abs(x)<u;
+x:=make_frac(x,u);
+l:=139548960-m_log(u); {$2^{24}\cdot12\ln2\approx139548959.6165$}
+until ab_vs_cd(1024,l,x,x)>=0;
+norm_rand:=x;
+end;
+
 @* \[8] Packed data.
 In order to make efficient use of storage space, \TeX\ bases its major data
 structures on a |memory_word|, which contains either a (signed) integer,
@@ -3919,6 +4280,8 @@
     round_xn_over_d:=-u;
 end;
 
+@<Declare procedures that need to be declared forward for \pdfTeX@>@;
+
 @* \[12] Displaying boxes.
 We can reinforce our knowledge of the data structures just introduced
 by considering two procedures that display a list in symbolic form.
@@ -9509,60 +9872,51 @@
 @d input_line_no_code=glue_val+2 {code for \.{\\inputlineno}}
 @d badness_code=input_line_no_code+1 {code for \.{\\badness}}
 @#
- at d eTeX_int=badness_code+1 {first of \eTeX\ codes for integers}
+ at d pdftex_first_rint_code = badness_code + 1 {base for \pdfTeX's command codes}
+ at d pdf_last_x_pos_code    = pdftex_first_rint_code + 6 {code for \.{\\pdflastxpos}}
+ at d pdf_last_y_pos_code    = pdftex_first_rint_code + 7 {code for \.{\\pdflastypos}}
+ at d elapsed_time_code      = pdftex_first_rint_code + 10 {code for \.{\\elapsedtime}}
+ at d pdf_shell_escape_code  = pdftex_first_rint_code + 11 {code for \.{\\shellescape}}
+ at d random_seed_code       = pdftex_first_rint_code + 12 {code for \.{\\randomseed}}
+ at d pdftex_last_item_codes = pdftex_first_rint_code + 13 {end of \pdfTeX's command codes}
 @#
- at d XeTeX_int=eTeX_int+8 {first of \XeTeX\ codes for integers}
+ at d XeTeX_int                         = pdftex_last_item_codes + 1 {base for \XeTeX's command codes}
+ at d XeTeX_version_code                = XeTeX_int + 0 {code for \.{\\XeTeXversion}}
+ at d XeTeX_count_glyphs_code           = XeTeX_int + 1 {code for \.{\\XeTeXcountglyphs}}
+ at d XeTeX_count_variations_code       = XeTeX_int + 2 {Deprecated}
+ at d XeTeX_variation_code              = XeTeX_int + 3 {Deprecated}
+ at d XeTeX_find_variation_by_name_code = XeTeX_int + 4 {Deprecated}
+ at d XeTeX_variation_min_code          = XeTeX_int + 5 {Deprecated}
+ at d XeTeX_variation_max_code          = XeTeX_int + 6 {Deprecated}
+ at d XeTeX_variation_default_code      = XeTeX_int + 7 {Deprecated}
+ at d XeTeX_count_features_code         = XeTeX_int + 8 {code for \.{\\XeTeXcountfeatures}}
+ at d XeTeX_feature_code_code           = XeTeX_int + 9 {code for \.{\\XeTeXfeaturecode}}
+ at d XeTeX_find_feature_by_name_code   = XeTeX_int + 10 {code for \.{\\XeTeXfindfeaturebyname}}
+ at d XeTeX_is_exclusive_feature_code   = XeTeX_int + 11 {code for \.{\\XeTeXisexclusivefeature}}
+ at d XeTeX_count_selectors_code        = XeTeX_int + 12 {code for \.{\\XeTeXcountselectors}}
+ at d XeTeX_selector_code_code          = XeTeX_int + 13 {code for \.{\\XeTeXselectorcode}}
+ at d XeTeX_find_selector_by_name_code  = XeTeX_int + 14 {code for \.{\\XeTeXfindselectorbyname}}
+ at d XeTeX_is_default_selector_code    = XeTeX_int + 15 {code for \.{\\XeTeXisdefaultselector}}
+ at d XeTeX_OT_count_scripts_code       = XeTeX_int + 16 {code for \.{\\XeTeXOTcountscripts}}
+ at d XeTeX_OT_count_languages_code     = XeTeX_int + 17 {code for \.{\\XeTeXOTcountlanguages}}
+ at d XeTeX_OT_count_features_code      = XeTeX_int + 18 {code for \.{\\XeTeXOTcountfeatures}}
+ at d XeTeX_OT_script_code              = XeTeX_int + 19 {code for \.{\\XeTeXOTscripttag}}
+ at d XeTeX_OT_language_code            = XeTeX_int + 20 {code for \.{\\XeTeXOTlanguagetag}}
+ at d XeTeX_OT_feature_code             = XeTeX_int + 21 {code for \.{\\XeTeXOTfeaturetag}}
+ at d XeTeX_map_char_to_glyph_code      = XeTeX_int + 22 {code for \.{\\XeTeXcharglyph}}
+ at d XeTeX_glyph_index_code            = XeTeX_int + 23 {code for \.{\\XeTeXglyphindex}}
+ at d XeTeX_font_type_code              = XeTeX_int + 24 {code for \.{\\XeTeXfonttype}}
+ at d XeTeX_first_char_code             = XeTeX_int + 25 {code for \.{\\XeTeXfirstfontchar}}
+ at d XeTeX_last_char_code              = XeTeX_int + 26 {code for \.{\\XeTeXlastfontchar}}
+ at d XeTeX_pdf_page_count_code         = XeTeX_int + 27 {code for \.{\\XeTeXpdfpagecount}}
+ at d XeTeX_last_item_codes             = XeTeX_int + 27 {end of \XeTeX's command codes}
 @#
- at d XeTeX_version_code=XeTeX_int {code for \.{\\XeTeXversion}}
-
- at d XeTeX_count_glyphs_code=XeTeX_int+1
-
- at d XeTeX_count_variations_code=XeTeX_int+2 {Deprecated}
- at d XeTeX_variation_code=XeTeX_int+3 {Deprecated}
- at d XeTeX_find_variation_by_name_code=XeTeX_int+4 {Deprecated}
- at d XeTeX_variation_min_code=XeTeX_int+5 {Deprecated}
- at d XeTeX_variation_max_code=XeTeX_int+6 {Deprecated}
- at d XeTeX_variation_default_code=XeTeX_int+7 {Deprecated}
-
- at d XeTeX_count_features_code=XeTeX_int+8
- at d XeTeX_feature_code_code=XeTeX_int+9
- at d XeTeX_find_feature_by_name_code=XeTeX_int+10
- at d XeTeX_is_exclusive_feature_code=XeTeX_int+11
- at d XeTeX_count_selectors_code=XeTeX_int+12
- at d XeTeX_selector_code_code=XeTeX_int+13
- at d XeTeX_find_selector_by_name_code=XeTeX_int+14
- at d XeTeX_is_default_selector_code=XeTeX_int+15
-
- at d XeTeX_OT_count_scripts_code=XeTeX_int+16
- at d XeTeX_OT_count_languages_code=XeTeX_int+17
- at d XeTeX_OT_count_features_code=XeTeX_int+18
- at d XeTeX_OT_script_code=XeTeX_int+19
- at d XeTeX_OT_language_code=XeTeX_int+20
- at d XeTeX_OT_feature_code=XeTeX_int+21
-
- at d XeTeX_map_char_to_glyph_code=XeTeX_int+22
- at d XeTeX_glyph_index_code=XeTeX_int+23
- at d XeTeX_font_type_code=XeTeX_int+24
-
- at d XeTeX_first_char_code=XeTeX_int+25
- at d XeTeX_last_char_code=XeTeX_int+26
-
- at d pdf_last_x_pos_code        = XeTeX_int+27
- at d pdf_last_y_pos_code        = XeTeX_int+28
- at d pdf_strcmp_code            = XeTeX_int+29
- at d pdf_mdfive_sum_code        = XeTeX_int+30
- at d pdf_shell_escape_code      = XeTeX_int+31
-
- at d XeTeX_pdf_page_count_code  = XeTeX_int+32
-
+ at d XeTeX_dim               = XeTeX_last_item_codes + 1 {first of \XeTeX\ codes for dimensions}
+ at d XeTeX_glyph_bounds_code = XeTeX_dim + 0 {code for \.{\\XeTeXglyphbounds}}
+ at d XeTeX_last_dim_codes    = XeTeX_dim + 0 {end of \XeTeX's command codes}
 @#
- at d XeTeX_dim=XeTeX_int+33 {first of \XeTeX\ codes for dimensions}
-
- at d XeTeX_glyph_bounds_code = XeTeX_dim
-
-@#
- at d eTeX_dim=XeTeX_dim+1 {first of \eTeX\ codes for dimensions}
- {changed for \XeTeX\ to make room for \XeTeX\ integers and dimens}
+ at d eTeX_int=XeTeX_last_dim_codes+1 {first of \eTeX\ codes for integers}
+ at d eTeX_dim=eTeX_int+8 {first of \eTeX\ codes for dimensions}
 @d eTeX_glue=eTeX_dim+9 {first of \eTeX\ codes for glue}
 @d eTeX_mu=eTeX_glue+1 {first of \eTeX\ codes for muglue}
 @d eTeX_expr=eTeX_mu+1 {first of \eTeX\ codes for expressions}
@@ -9592,7 +9946,18 @@
 @!@:input_line_no_}{\.{\\inputlineno} primitive@>
 primitive("badness",last_item,badness_code);
 @!@:badness_}{\.{\\badness} primitive@>
+primitive("pdflastxpos",last_item,pdf_last_x_pos_code);@/
+@!@:pdf_last_x_pos_}{\.{\\pdflastxpos} primitive@>
+primitive("pdflastypos",last_item,pdf_last_y_pos_code);@/
+@!@:pdf_last_y_pos_}{\.{\\pdflastypos} primitive@>
+primitive("elapsedtime",last_item,elapsed_time_code);
+@!@:elapsed_time_}{\.{\\elapsedtime} primitive@>
+primitive("shellescape",last_item,pdf_shell_escape_code);
+@!@:pdf_shell_escape_}{\.{\\shellescape} primitive@>
+primitive("randomseed",last_item,random_seed_code);
+@!@:random_seed_}{\.{\\randomseed} primitive@>
 
+
 @ @<Cases of |print_cmd_chr|...@>=
 set_aux: if chr_code=vmode then print_esc("prevdepth")
 @+else print_esc("spacefactor");
@@ -9607,8 +9972,12 @@
   dimen_val: print_esc("lastkern");
   glue_val: print_esc("lastskip");
   input_line_no_code: print_esc("inputlineno");
+  @/@<Cases of |last_item| for |print_cmd_chr|@>@/
+  pdf_last_x_pos_code:  print_esc("pdflastxpos");
+  pdf_last_y_pos_code:  print_esc("pdflastypos");
+  elapsed_time_code: print_esc("elapsedtime");
   pdf_shell_escape_code: print_esc("shellescape");
-  @/@<Cases of |last_item| for |print_cmd_chr|@>@/
+  random_seed_code:     print_esc("randomseed");
   othercases print_esc("badness")
   endcases;
 
@@ -9701,6 +10070,8 @@
  else begin case m of
   input_line_no_code: cur_val:=line;
   badness_code: cur_val:=last_badness;
+  elapsed_time_code: cur_val := get_microinterval;
+  random_seed_code:  cur_val := random_seed;
   pdf_shell_escape_code:
     begin
     if shellenabledp then begin
@@ -10499,6 +10870,7 @@
       t := @"10000 + (t - @"D800) * @"400 + (so(str_pool[k]) - @"DC00);
     end;
     if cat=0 then t := other_token + t
+    else if cat=active_char then t := cs_token_flag + active_base + t
     else t := max_char_val * cat + t;
   end;
   fast_store_new_token(t);
@@ -10570,22 +10942,31 @@
 @d font_name_code=4 {command code for \.{\\fontname}}
 @d etex_convert_base=5 {base for \eTeX's command codes}
 @d eTeX_revision_code=etex_convert_base {command code for \.{\\eTeXrevision}}
+ at d etex_convert_codes=etex_convert_base+1 {end of \eTeX's command codes}
+ at d expanded_code=etex_convert_codes {command code for \.{\\expanded}}
+ at d pdftex_first_expand_code = expanded_code + 1 {base for \pdfTeX's command codes}
+ at d left_margin_kern_code    = pdftex_first_expand_code + 9 {command code for \.{\\leftmarginkern}}
+ at d right_margin_kern_code   = pdftex_first_expand_code + 10 {command code for \.{\\rightmarginkern}}
+ at d pdf_strcmp_code          = pdftex_first_expand_code + 11 {command code for \.{\\strcmp}}
+ at d pdf_creation_date_code   = pdftex_first_expand_code + 15 {command code for \.{\\creationdate}}
+ at d pdf_file_mod_date_code   = pdftex_first_expand_code + 16 {command code for \.{\\filemoddate}}
+ at d pdf_file_size_code       = pdftex_first_expand_code + 17 {command code for \.{\\filesize}}
+ at d pdf_mdfive_sum_code      = pdftex_first_expand_code + 18 {command code for \.{\\mdfivesum}}
+ at d pdf_file_dump_code       = pdftex_first_expand_code + 19 {command code for \.{\\filedump}}
+ at d uniform_deviate_code     = pdftex_first_expand_code + 22 {command code for \.{\\uniformdeviate}}
+ at d normal_deviate_code      = pdftex_first_expand_code + 23 {command code for \.{\\normaldeviate}}
+ at d pdftex_convert_codes     = pdftex_first_expand_code + 26 {end of \pdfTeX's command codes}
+ at d XeTeX_first_expand_code   = pdftex_convert_codes {base for \XeTeX's command codes}
+ at d XeTeX_revision_code       = XeTeX_first_expand_code + 0 {command code for \.{\\XeTeXrevision}}
+ at d XeTeX_variation_name_code = XeTeX_first_expand_code + 1 {command code for \.{\\XeTeXvariationname}}
+ at d XeTeX_feature_name_code   = XeTeX_first_expand_code + 2 {command code for \.{\\XeTeXfeaturename}}
+ at d XeTeX_selector_name_code  = XeTeX_first_expand_code + 3 {command code for \.{\\XeTeXselectornamename}}
+ at d XeTeX_glyph_name_code     = XeTeX_first_expand_code + 4 {command code for \.{\\XeTeXglyphname}}
+ at d XeTeX_Uchar_code          = XeTeX_first_expand_code + 5 {command code for \.{\\Uchar}}
+ at d XeTeX_Ucharcat_code       = XeTeX_first_expand_code + 6 {command code for \.{\\Ucharcat}}
+ at d XeTeX_convert_codes       = XeTeX_first_expand_code + 7 {end of \XeTeX's command codes}
+ at d job_name_code=XeTeX_convert_codes {command code for \.{\\jobname}}
 
- at d XeTeX_revision_code=6
- at d XeTeX_variation_name_code=7
- at d XeTeX_feature_name_code=8
- at d XeTeX_selector_name_code=9
- at d XeTeX_glyph_name_code=10
-
- at d left_margin_kern_code=11
- at d right_margin_kern_code=12
-
- at d XeTeX_Uchar_code = 13
- at d XeTeX_Ucharcat_code = 14
-
- at d etex_convert_codes=XeTeX_Ucharcat_code+1 {end of \eTeX's command codes}
- at d job_name_code=etex_convert_codes {command code for \.{\\jobname}}
-
 @<Put each...@>=
 primitive("number",convert,number_code);@/
 @!@:number_}{\.{\\number} primitive@>
@@ -10597,13 +10978,36 @@
 @!@:meaning_}{\.{\\meaning} primitive@>
 primitive("fontname",convert,font_name_code);@/
 @!@:font_name_}{\.{\\fontname} primitive@>
-primitive("jobname",convert,job_name_code);@/
-@!@:job_name_}{\.{\\jobname} primitive@>
+@#
+@#
+primitive("expanded",convert,expanded_code);@/
+@!@:expanded_}{\.{\\expanded} primitive@>
+@#
 primitive("leftmarginkern",convert,left_margin_kern_code);@/
 @!@:left_margin_kern_}{\.{\\leftmarginkern} primitive@>
 primitive("rightmarginkern",convert,right_margin_kern_code);@/
 @!@:right_margin_kern_}{\.{\\rightmarginkern} primitive@>
+primitive("creationdate",convert,pdf_creation_date_code);@/
+@!@:pdf_creation_date_}{\.{\\creationdate} primitive@>
+primitive("filemoddate",convert,pdf_file_mod_date_code);@/
+@!@:pdf_file_mod_date_}{\.{\\filemoddate} primitive@>
+primitive("filesize",convert,pdf_file_size_code);@/
+@!@:pdf_file_size_}{\.{\\filesize} primitive@>
+primitive("mdfivesum",convert,pdf_mdfive_sum_code);@/
+@!@:pdf_mdfive_sum_}{\.{\\mdfivesum} primitive@>
+primitive("filedump",convert,pdf_file_dump_code);@/
+@!@:pdf_file_dump_}{\.{\\filedump} primitive@>
+primitive("strcmp",convert,pdf_strcmp_code);@/
+@!@:pdf_strcmp_}{\.{\\strcmp} primitive@>
+primitive("uniformdeviate",convert,uniform_deviate_code);@/
+@!@:uniform_deviate_}{\.{\\uniformdeviate} primitive@>
+primitive("normaldeviate",convert,normal_deviate_code);@/
+@!@:normal_deviate_}{\.{\\normaldeviate} primitive@>
 
+@#
+primitive("jobname",convert,job_name_code);@/
+@!@:job_name_}{\.{\\jobname} primitive@>
+
 primitive("Uchar",convert,XeTeX_Uchar_code);@/
 @!@:XeTeX_Uchar_}{\.{\\Uchar} primitive@>
 primitive("Ucharcat",convert,XeTeX_Ucharcat_code);@/
@@ -10616,10 +11020,18 @@
   string_code: print_esc("string");
   meaning_code: print_esc("meaning");
   font_name_code:  print_esc("fontname");
-  pdf_strcmp_code: print_esc("strcmp");
-  pdf_mdfive_sum_code: print_esc("mdfivesum");
+  eTeX_revision_code: print_esc("eTeXrevision");
+  expanded_code:        print_esc("expanded");
   left_margin_kern_code:    print_esc("leftmarginkern");
   right_margin_kern_code:   print_esc("rightmarginkern");
+  pdf_creation_date_code: print_esc("creationdate");
+  pdf_file_mod_date_code: print_esc("filemoddate");
+  pdf_file_size_code:     print_esc("filesize");
+  pdf_mdfive_sum_code:    print_esc("mdfivesum");
+  pdf_file_dump_code:     print_esc("filedump");
+  pdf_strcmp_code:        print_esc("strcmp");
+  uniform_deviate_code:   print_esc("uniformdeviate");
+  normal_deviate_code:    print_esc("normaldeviate");
   @/@<Cases of |convert| for |print_cmd_chr|@>@/
   othercases print_esc("jobname")
   endcases;
@@ -10641,6 +11053,7 @@
 @!boolvar: boolean; {temp boolean}
 @!s: str_number;
 @!u: str_number;
+@!j: integer;
 @!c:small_number; {desired type of conversion}
 @!save_scanner_status:small_number; {|scanner_status| upon entry}
 @!b:pool_pointer; {base of temporary string}
@@ -10658,7 +11071,7 @@
 end;
 
 @ Not all catcode values are allowed by \.{\\Ucharcat}:
- at d illegal_Ucharcat_catcode(#)==(#<left_brace)or(#>other_char)or(#=out_param)or(#=ignore)
+ at d illegal_Ucharcat_catcode(#)==(#<left_brace)or(#>active_char)or(#=out_param)or(#=ignore)
 
 @<Scan the argument for command |c|@>=
 case c of
@@ -10667,6 +11080,197 @@
   scanner_status:=normal; get_token; scanner_status:=save_scanner_status;
   end;
 font_name_code: scan_font_ident;
+eTeX_revision_code: do_nothing;
+expanded_code:
+  begin
+    save_scanner_status := scanner_status;
+    save_warning_index := warning_index;
+    save_def_ref := def_ref;
+    save_cur_string;
+    scan_pdf_ext_toks;
+    warning_index := save_warning_index;
+    scanner_status := save_scanner_status;
+    ins_list(link(def_ref));
+    def_ref := save_def_ref;
+    restore_cur_string;
+    return;
+  end;
+left_margin_kern_code, right_margin_kern_code: begin
+    scan_register_num;
+    fetch_box(p);
+    if (p = null) or (type(p) <> hlist_node) then
+        pdf_error("marginkern", "a non-empty hbox expected")
+end;
+pdf_creation_date_code:
+  begin
+    b := pool_ptr;
+    getcreationdate;
+    link(garbage) := str_toks(b);
+    ins_list(link(temp_head));
+    return;
+  end;
+pdf_file_mod_date_code:
+  begin
+    save_scanner_status := scanner_status;
+    save_warning_index := warning_index;
+    save_def_ref := def_ref;
+    save_cur_string;
+    scan_pdf_ext_toks;
+
+    if selector = new_string then
+      pdf_error("tokens", "tokens_to_string() called while selector = new_string");
+    old_setting:=selector; selector:=new_string;
+    show_token_list(link(def_ref),null,pool_size-pool_ptr);
+    selector:=old_setting;
+    s:=make_string;
+
+    delete_token_ref(def_ref);
+    def_ref := save_def_ref;
+    warning_index := save_warning_index;
+    scanner_status := save_scanner_status;
+    b := pool_ptr;
+    getfilemoddate(s);
+    link(garbage) := str_toks(b);
+
+    if flushable(s) then
+        flush_string;
+
+    ins_list(link(temp_head));
+    restore_cur_string;
+    return;
+  end;
+pdf_file_size_code:
+  begin
+    save_scanner_status := scanner_status;
+    save_warning_index := warning_index;
+    save_def_ref := def_ref;
+    save_cur_string;
+    scan_pdf_ext_toks;
+
+    if selector = new_string then
+      pdf_error("tokens", "tokens_to_string() called while selector = new_string");
+    old_setting:=selector; selector:=new_string;
+    show_token_list(link(def_ref),null,pool_size-pool_ptr);
+    selector:=old_setting;
+    s:=make_string;
+
+    delete_token_ref(def_ref);
+    def_ref := save_def_ref;
+    warning_index := save_warning_index;
+    scanner_status := save_scanner_status;
+    b := pool_ptr;
+    getfilesize(s);
+    link(garbage) := str_toks(b);
+
+    if flushable(s) then
+        flush_string;
+
+    ins_list(link(temp_head));
+    restore_cur_string;
+    return;
+  end;
+pdf_mdfive_sum_code:
+  begin
+    save_scanner_status := scanner_status;
+    save_warning_index := warning_index;
+    save_def_ref := def_ref;
+    save_cur_string;
+    boolvar := scan_keyword("file");
+    scan_pdf_ext_toks;
+
+    if selector = new_string then
+      pdf_error("tokens", "tokens_to_string() called while selector = new_string");
+    old_setting:=selector; selector:=new_string;
+    show_token_list(link(def_ref),null,pool_size-pool_ptr);
+    selector:=old_setting;
+    s:=make_string;
+
+    delete_token_ref(def_ref);
+    def_ref := save_def_ref;
+    warning_index := save_warning_index;
+    scanner_status := save_scanner_status;
+    b := pool_ptr;
+    getmd5sum(s, boolvar);
+    link(garbage) := str_toks(b);
+
+    if flushable(s) then
+        flush_string;
+
+    ins_list(link(temp_head));
+    restore_cur_string;
+    return;
+  end;
+pdf_file_dump_code:
+  begin
+    save_scanner_status := scanner_status;
+    save_warning_index := warning_index;
+    save_def_ref := def_ref;
+    save_cur_string;
+    {scan offset}
+    cur_val := 0;
+    if (scan_keyword("offset")) then begin
+      scan_int;
+      if (cur_val < 0) then begin
+        print_err("Bad file offset");
+ at .Bad file offset@>
+        help2("A file offset must be between 0 and 2^{31}-1,")@/
+          ("I changed this one to zero.");
+        int_error(cur_val);
+        cur_val := 0;
+      end;
+    end;
+    i := cur_val;
+    {scan length}
+    cur_val := 0;
+    if (scan_keyword("length")) then begin
+      scan_int;
+      if (cur_val < 0) then begin
+        print_err("Bad dump length");
+ at .Bad dump length@>
+        help2("A dump length must be between 0 and 2^{31}-1,")@/
+          ("I changed this one to zero.");
+        int_error(cur_val);
+        cur_val := 0;
+      end;
+    end;
+    j := cur_val;
+    {scan file name}
+    scan_pdf_ext_toks;
+
+    if selector = new_string then
+      pdf_error("tokens", "tokens_to_string() called while selector = new_string");
+    old_setting:=selector; selector:=new_string;
+    show_token_list(link(def_ref),null,pool_size-pool_ptr);
+    selector:=old_setting;
+    s:=make_string;
+
+    delete_token_ref(def_ref);
+    def_ref := save_def_ref;
+    warning_index := save_warning_index;
+    scanner_status := save_scanner_status;
+    b := pool_ptr;
+    getfiledump(s, i, j);
+    link(garbage) := str_toks(b);
+
+    if flushable(s) then
+        flush_string;
+
+    ins_list(link(temp_head));
+    restore_cur_string;
+    return;
+  end;
+pdf_strcmp_code:
+  begin
+    save_scanner_status:=scanner_status;
+    save_warning_index:=warning_index;
+    save_def_ref:=def_ref;
+    save_cur_string;
+    compare_strings;
+    def_ref:=save_def_ref;
+    warning_index:=save_warning_index;
+    scanner_status:=save_scanner_status;
+    restore_cur_string;
+  end;
 XeTeX_Uchar_code: scan_usv_num;
 XeTeX_Ucharcat_code:
   begin
@@ -10676,7 +11280,7 @@
     if illegal_Ucharcat_catcode(cur_val) then
       begin print_err("Invalid code ("); print_int(cur_val);
 @.Invalid code@>
-      print("), should be in the ranges 1..4, 6..8, 10..12");
+      print("), should be in the ranges 1..4, 6..8, 10..13");
       help1("I'm going to use 12 instead of that illegal code value.");@/
       error; cat:=12;
     end else
@@ -10685,6 +11289,8 @@
   end;
 @/@<Cases of `Scan the argument for command |c|'@>@/
 job_name_code: if job_name=0 then open_log_file;
+uniform_deviate_code:     scan_int;
+normal_deviate_code:      do_nothing;
 end {there are no other cases}
 
 @ @<Print the result of command |c|@>=
@@ -10710,6 +11316,37 @@
     print("pt");
     end;
   end;
+eTeX_revision_code: print(eTeX_revision);
+left_margin_kern_code: begin
+  p:=list_ptr(p);
+  while (p <> null) and
+        (cp_skipable(p) or
+         ((not is_char_node(p)) and (type(p) = glue_node) and (subtype(p) = left_skip_code + 1)))
+  do
+    p:=link(p);
+  if (p <> null) and (not is_char_node(p)) and (type(p) = margin_kern_node) and (subtype(p) = left_side) then
+    print_scaled(width(p))
+  else
+    print("0");
+  print("pt");
+end;
+right_margin_kern_code: begin
+  q:=list_ptr(p);
+  p:=prev_rightmost(q, null);
+  while (p <> null) and
+        (cp_skipable(p) or
+         ((not is_char_node(p)) and (type(p) = glue_node) and (subtype(p) = right_skip_code + 1)))
+  do
+    p:=prev_rightmost(q, p);
+  if (p <> null) and (not is_char_node(p)) and (type(p) = margin_kern_node) and (subtype(p) = right_side) then
+    print_scaled(width(p))
+  else
+    print("0");
+  print("pt");
+end;
+pdf_strcmp_code: print_int(cur_val);
+uniform_deviate_code:     print_int(unif_rand(cur_val));
+normal_deviate_code:      print_int(norm_rand);
 XeTeX_Uchar_code,
 XeTeX_Ucharcat_code: print_char(cur_val);
 @/@<Cases of `Print the result of command |c|'@>@/
@@ -14630,6 +15267,12 @@
   decr(font_ptr);
   end
 
+@* \[32b] \pdfTeX\ output low-level subroutines (equivalents)
+
+@<Glob...@>=
+@!epochseconds: integer;
+@!microseconds: integer;
+
 @* \[33] Packaging.
 We're essentially done with the parts of \TeX\ that are concerned with
 the input (|get_next|) and the output (|ship_out|). So it's time to
@@ -28667,6 +29310,8 @@
 if end_line_char_inactive then decr(limit)
 else  buffer[limit]:=end_line_char;
 fix_date_and_time;@/
+random_seed :=(microseconds*1000)+(epochseconds mod 1000000);@/
+init_randoms(random_seed);@/
 @<Compute the magic offset@>;
 @<Initialize the print |selector|...@>;
 if (loc<limit)and(cat_code(buffer[loc])<>escape) then start_input;
@@ -28831,7 +29476,9 @@
 @d set_language_code=5 {command modifier for \.{\\setlanguage}}
 
 @d pdftex_first_extension_code = 6
- at d pdf_save_pos_node           == pdftex_first_extension_code + 0
+ at d pdf_save_pos_node           == pdftex_first_extension_code + 15
+ at d reset_timer_code            == pdftex_first_extension_code + 25
+ at d set_random_seed_code        == pdftex_first_extension_code + 27
 
 @d pic_file_code=41 { command modifier for \.{\\XeTeXpicfile}, skipping codes pdfTeX might use }
 @d pdf_file_code=42 { command modifier for \.{\\XeTeXpdffile} }
@@ -28854,6 +29501,10 @@
 @!@:immediate_}{\.{\\immediate} primitive@>
 primitive("setlanguage",extension,set_language_code);@/
 @!@:set_language_}{\.{\\setlanguage} primitive@>
+primitive("resettimer",extension,reset_timer_code);@/
+@!@:reset_timer_}{\.{\\resettimer} primitive@>
+primitive("setrandomseed",extension,set_random_seed_code);@/
+@!@:set_random_seed_code}{\.{\\setrandomseed} primitive@>
 
 @ The \.{\\XeTeXpicfile} and \.{\\XeTeXpdffile} primitives are only defined in extended mode.
 
@@ -28886,6 +29537,9 @@
   special_node:print_esc("special");
   immediate_code:print_esc("immediate");
   set_language_code:print_esc("setlanguage");
+  pdf_save_pos_node: print_esc("pdfsavepos");
+  reset_timer_code: print_esc("resettimer");
+  set_random_seed_code: print_esc("setrandomseed");
   pic_file_code:print_esc("XeTeXpicfile");
   pdf_file_code:print_esc("XeTeXpdffile");
   glyph_code:print_esc("XeTeXglyph");
@@ -28892,7 +29546,6 @@
   XeTeX_linebreak_locale_extension_code:print_esc("XeTeXlinebreaklocale");
   XeTeX_input_encoding_extension_code:print_esc("XeTeXinputencoding");
   XeTeX_default_encoding_extension_code:print_esc("XeTeXdefaultencoding");
-  pdf_save_pos_node: print_esc("pdfsavepos");
   othercases print("[unknown extension!]")
   endcases;
 
@@ -28908,20 +29561,21 @@
 var i,@!j,@!k:integer; {all-purpose integers}
 @!p,@!q,@!r:pointer; {all-purpose pointers}
 begin case cur_chr of
-open_node:@<Implement \.{\\openout}@>;
-write_node:@<Implement \.{\\write}@>;
-close_node:@<Implement \.{\\closeout}@>;
-special_node:@<Implement \.{\\special}@>;
-immediate_code:@<Implement \.{\\immediate}@>;
-set_language_code:@<Implement \.{\\setlanguage}@>;
-pic_file_code:@<Implement \.{\\XeTeXpicfile}@>;
-pdf_file_code:@<Implement \.{\\XeTeXpdffile}@>;
-glyph_code:@<Implement \.{\\XeTeXglyph}@>;
-XeTeX_input_encoding_extension_code:@<Implement \.{\\XeTeXinputencoding}@>;
-XeTeX_default_encoding_extension_code:@<Implement \.{\\XeTeXdefaultencoding}@>;
-XeTeX_linebreak_locale_extension_code:@<Implement \.{\\XeTeXlinebreaklocale}@>;
-
-pdf_save_pos_node: @<Implement \.{\\pdfsavepos}@>;
+  open_node:@<Implement \.{\\openout}@>;
+  write_node:@<Implement \.{\\write}@>;
+  close_node:@<Implement \.{\\closeout}@>;
+  special_node:@<Implement \.{\\special}@>;
+  immediate_code:@<Implement \.{\\immediate}@>;
+  set_language_code:@<Implement \.{\\setlanguage}@>;
+  pdf_save_pos_node: @<Implement \.{\\pdfsavepos}@>;
+  reset_timer_code: @<Implement \.{\\resettimer}@>;
+  set_random_seed_code: @<Implement \.{\\setrandomseed}@>;
+  pic_file_code:@<Implement \.{\\XeTeXpicfile}@>;
+  pdf_file_code:@<Implement \.{\\XeTeXpdffile}@>;
+  glyph_code:@<Implement \.{\\XeTeXglyph}@>;
+  XeTeX_input_encoding_extension_code:@<Implement \.{\\XeTeXinputencoding}@>;
+  XeTeX_default_encoding_extension_code:@<Implement \.{\\XeTeXdefaultencoding}@>;
+  XeTeX_linebreak_locale_extension_code:@<Implement \.{\\XeTeXlinebreaklocale}@>;
 othercases confusion("ext1")
 @:this can't happen ext1}{\quad ext1@>
 endcases;
@@ -28981,6 +29635,7 @@
 
 @ @d call_func(#) == begin if # <> 0 then do_nothing end
 @d flushable(#) == (# = str_ptr - 1)
+ at d max_integer == @"7FFFFFFF {$2^{31}-1$}
 
 @p procedure flush_str(s: str_number); {flush a string if possible}
 begin
@@ -29044,6 +29699,38 @@
   cur_val_level:=int_val;
 end;
 
+@ @<Declare procedures that need to be declared forward for \pdfTeX@>=
+function get_microinterval:integer;
+var s,@!m:integer; {seconds and microseconds}
+begin
+   seconds_and_micros(s,m);
+   if (s-epochseconds)>32767 then
+     get_microinterval := max_integer
+   else if (microseconds>m)  then
+     get_microinterval := ((s-1-epochseconds)*65536)+ (((m+1000000-microseconds)/100)*65536)/10000
+   else
+     get_microinterval := ((s-epochseconds)*65536)  + (((m-microseconds)/100)*65536)/10000;
+end;
+
+@ @<Set initial values of key variables@>=
+  seconds_and_micros(epochseconds,microseconds);
+  init_start_time;
+
+@ Negative random seed values are silently converted to positive ones
+
+@<Implement \.{\\setrandomseed}@>=
+begin
+  scan_int;
+  if cur_val<0 then negate(cur_val);
+  random_seed := cur_val;
+  init_randoms(random_seed);
+end
+
+@ @<Implement \.{\\resettimer}@>=
+begin
+  seconds_and_micros(epochseconds,microseconds);
+end
+
 @ Each new type of node that appears in our data structure must be capable
 of being displayed, copied, destroyed, and so on. The routines that we
 need for write-oriented whatsits are somewhat like those for mark nodes;
@@ -29096,6 +29783,7 @@
   print_int(what_lhm(p)); print_char(",");
   print_int(what_rhm(p)); print_char(")");
   end;
+pdf_save_pos_node: print_esc("pdfsavepos");
 native_word_node, native_word_node_AT:begin print_esc(font_id_text(native_font(p)));
   print_char(" ");
   print_native_word(p);
@@ -29112,7 +29800,6 @@
     print_visible_char(pic_path_byte(p, i));
   print("""");
   end;
-pdf_save_pos_node: print_esc("pdfsavepos");
 othercases print("whatsit?")
 endcases
 
@@ -29998,12 +30685,6 @@
 primitive("XeTeXfirstfontchar", last_item, XeTeX_first_char_code);
 primitive("XeTeXlastfontchar", last_item, XeTeX_last_char_code);
 
-primitive("pdflastxpos",last_item,pdf_last_x_pos_code);
-primitive("pdflastypos",last_item,pdf_last_y_pos_code);
-primitive("strcmp",convert,pdf_strcmp_code);
-primitive("mdfivesum",convert,pdf_mdfive_sum_code);
-primitive("shellescape",last_item,pdf_shell_escape_code);
-
 primitive("XeTeXpdfpagecount",last_item,XeTeX_pdf_page_count_code);
 
 @ @<Cases of |last_item| for |print_cmd_chr|@>=
@@ -30045,9 +30726,6 @@
 XeTeX_first_char_code: print_esc("XeTeXfirstfontchar");
 XeTeX_last_char_code: print_esc("XeTeXlastfontchar");
 
-  pdf_last_x_pos_code:  print_esc("pdflastxpos");
-  pdf_last_y_pos_code:  print_esc("pdflastypos");
-
 XeTeX_pdf_page_count_code: print_esc("XeTeXpdfpagecount");
 
 @ @<Cases for fetching an integer value@>=
@@ -30313,7 +30991,6 @@
   end;
 
 @ @<Cases of |convert| for |print_cmd_chr|@>=
-eTeX_revision_code: print_esc("eTeXrevision");
 XeTeX_revision_code: print_esc("XeTeXrevision");
 
 XeTeX_variation_name_code: print_esc("XeTeXvariationname");
@@ -30325,52 +31002,6 @@
 XeTeX_Ucharcat_code: print_esc("Ucharcat");
 
 @ @<Cases of `Scan the argument for command |c|'@>=
-eTeX_revision_code: do_nothing;
-pdf_strcmp_code:
-  begin
-    save_scanner_status:=scanner_status;
-    save_warning_index:=warning_index;
-    save_def_ref:=def_ref;
-    save_cur_string;
-    compare_strings;
-    def_ref:=save_def_ref;
-    warning_index:=save_warning_index;
-    scanner_status:=save_scanner_status;
-    restore_cur_string;
-  end;
-
-pdf_mdfive_sum_code:
-  begin
-    save_scanner_status := scanner_status;
-    save_warning_index := warning_index;
-    save_def_ref := def_ref;
-    save_cur_string;
-    boolvar := scan_keyword("file");
-    scan_pdf_ext_toks;
-
-    if selector = new_string then
-      pdf_error("tokens", "tokens_to_string() called while selector = new_string");
-    old_setting:=selector; selector:=new_string;
-    show_token_list(link(def_ref),null,pool_size-pool_ptr);
-    selector:=old_setting;
-    s:=make_string;
-
-    delete_token_ref(def_ref);
-    def_ref := save_def_ref;
-    warning_index := save_warning_index;
-    scanner_status := save_scanner_status;
-    b := pool_ptr;
-    getmd5sum(s, boolvar);
-    link(garbage) := str_toks(b);
-
-    if flushable(s) then
-        flush_string;
-
-    ins_list(link(temp_head));
-    restore_cur_string;
-    return;
-  end;
-
 XeTeX_revision_code: do_nothing;
 
 XeTeX_variation_name_code:
@@ -30409,16 +31040,7 @@
       not_native_font_error(convert, c, fnt);
   end;
 
-left_margin_kern_code, right_margin_kern_code: begin
-    scan_register_num;
-    fetch_box(p);
-    if (p = null) or (type(p) <> hlist_node) then
-        pdf_error("marginkern", "a non-empty hbox expected")
-end;
-
 @ @<Cases of `Print the result of command |c|'@>=
-eTeX_revision_code: print(eTeX_revision);
-pdf_strcmp_code: print_int(cur_val);
 XeTeX_revision_code: print(XeTeX_revision);
 
 XeTeX_variation_name_code:
@@ -30435,35 +31057,6 @@
 XeTeX_glyph_name_code:
   if is_native_font(fnt) then print_glyph_name(fnt, arg1);
 
-left_margin_kern_code: begin
-  p:=list_ptr(p);
-  while (p <> null) and
-        (cp_skipable(p) or
-         ((not is_char_node(p)) and (type(p) = glue_node) and (subtype(p) = left_skip_code + 1)))
-  do
-    p:=link(p);
-  if (p <> null) and (not is_char_node(p)) and (type(p) = margin_kern_node) and (subtype(p) = left_side) then
-    print_scaled(width(p))
-  else
-    print("0");
-  print("pt");
-end;
-
-right_margin_kern_code: begin
-  q:=list_ptr(p);
-  p:=prev_rightmost(q, null);
-  while (p <> null) and
-        (cp_skipable(p) or
-         ((not is_char_node(p)) and (type(p) = glue_node) and (subtype(p) = right_skip_code + 1)))
-  do
-    p:=prev_rightmost(q, p);
-  if (p <> null) and (not is_char_node(p)) and (type(p) = margin_kern_node) and (subtype(p) = right_side) then
-    print_scaled(width(p))
-  else
-    print("0");
-  print("pt");
-end;
-
 @ @d eTeX_ex==(eTeX_mode=1) {is this extended mode?}
 
 @<Glob...@>=



More information about the tex-live-commits mailing list