diff options
author | Akira Kakuto <kakuto@fuk.kindai.ac.jp> | 2018-11-17 07:32:49 +0000 |
---|---|---|
committer | Akira Kakuto <kakuto@fuk.kindai.ac.jp> | 2018-11-17 07:32:49 +0000 |
commit | d7f366bbd6165f743d507912dfcfeb10f2a304ac (patch) | |
tree | 1831cfe03ebe08785cb9c80faeaebd799e142de3 /Build/source | |
parent | 7d31f47ebfdd6ef50950dfbe0136e146c1e604bb (diff) |
Support some primitives from pdfTeX in XeTeX (Joseph Wright)
git-svn-id: svn://tug.org/texlive/trunk@49176 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source')
-rw-r--r-- | Build/source/texk/web2c/ChangeLog | 4 | ||||
-rw-r--r-- | Build/source/texk/web2c/lib/ChangeLog | 4 | ||||
-rw-r--r-- | Build/source/texk/web2c/lib/texmfmp.c | 40 | ||||
-rw-r--r-- | Build/source/texk/web2c/texmfmp.h | 4 | ||||
-rw-r--r-- | Build/source/texk/web2c/xetexdir/ChangeLog | 5 | ||||
-rw-r--r-- | Build/source/texk/web2c/xetexdir/xetex.defines | 5 | ||||
-rw-r--r-- | Build/source/texk/web2c/xetexdir/xetex.web | 961 |
7 files changed, 813 insertions, 210 deletions
diff --git a/Build/source/texk/web2c/ChangeLog b/Build/source/texk/web2c/ChangeLog index d5e2fe48e12..d80ed5d7e9c 100644 --- a/Build/source/texk/web2c/ChangeLog +++ b/Build/source/texk/web2c/ChangeLog @@ -1,3 +1,7 @@ +2018-11-17 Joseph Wright <joseph.wright@morningstar2.co.uk> + + * texmfmp.h: Support some primitives from pdfTeX in XeTeX. + 2018-09-09 Karl Berry <karl@tug.org> * mftraptest.test, diff --git a/Build/source/texk/web2c/lib/ChangeLog b/Build/source/texk/web2c/lib/ChangeLog index 37002a0a0f5..823ef735157 100644 --- a/Build/source/texk/web2c/lib/ChangeLog +++ b/Build/source/texk/web2c/lib/ChangeLog @@ -1,3 +1,7 @@ +2018-11-17 Joseph Wright <joseph.wright@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. diff --git a/Build/source/texk/web2c/lib/texmfmp.c b/Build/source/texk/web2c/lib/texmfmp.c index 3b5e1ddb235..7a253cf7373 100644 --- a/Build/source/texk/web2c/lib/texmfmp.c +++ b/Build/source/texk/web2c/lib/texmfmp.c @@ -151,7 +151,22 @@ char *generic_synctex_get_current_name (void) #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 @@ tcx_get_num (int upb, /* 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 @@ WARNING1 ("invalid value (expected 0 or 1) for environment variable $FORCE_SOURC } } -#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 @@ void pdftex_fail(const char *fmt, ...) } #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 @@ void getfiledump(integer s, int offset, int length) } xfree(file_name); } -#endif /* not XeTeX */ /* Converts any given string in into an allowed PDF string which is * hexadecimal encoded; diff --git a/Build/source/texk/web2c/texmfmp.h b/Build/source/texk/web2c/texmfmp.h index be8311f0e58..1dd7c56d019 100644 --- a/Build/source/texk/web2c/texmfmp.h +++ b/Build/source/texk/web2c/texmfmp.h @@ -124,7 +124,6 @@ extern int tfmtemp, texinputtype; #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 getcreationdate(void); 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 @@ extern boolean input_line (FILE *); #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 *); diff --git a/Build/source/texk/web2c/xetexdir/ChangeLog b/Build/source/texk/web2c/xetexdir/ChangeLog index dfb445bda64..8ff98249d4f 100644 --- a/Build/source/texk/web2c/xetexdir/ChangeLog +++ b/Build/source/texk/web2c/xetexdir/ChangeLog @@ -1,3 +1,8 @@ +2018-11-17 Joseph Wright <joseph.wright@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@fuk.kindai.ac.jp> * pdfimage.cpp: Cast types to support poppler 0.70.0. diff --git a/Build/source/texk/web2c/xetexdir/xetex.defines b/Build/source/texk/web2c/xetexdir/xetex.defines index 8772a82b622..2c5bff5039f 100644 --- a/Build/source/texk/web2c/xetexdir/xetex.defines +++ b/Build/source/texk/web2c/xetexdir/xetex.defines @@ -179,4 +179,9 @@ authorization from the copyright holders. @define function getcpcode(); @define function getnativewordcp(); +@define procedure initstarttime; +@define procedure getcreationdate; +@define procedure getfilemoddate(); +@define procedure getfilesize(); +@define procedure getfiledump(); @define procedure getmd5sum(); diff --git a/Build/source/texk/web2c/xetexdir/xetex.web b/Build/source/texk/web2c/xetexdir/xetex.web index f7b0bbe05cb..e7746844ed2 100644 --- a/Build/source/texk/web2c/xetexdir/xetex.web +++ b/Build/source/texk/web2c/xetexdir/xetex.web @@ -2593,6 +2593,367 @@ routines cited there must be modified to allow negative glue ratios.) @<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. + +@d fraction_half==@'1000000000 {$2^{27}$, represents 0.50000000} +@d fraction_one==@'2000000000 {$2^{28}$, represents 1.00000000} +@d fraction_four==@'10000000000 {$2^{30}$, represents 4.00000000} +@d el_gordo == @'17777777777 {$2^{31}-1$, the largest value that \MP\ likes} +@d halfp(#)==(#) div 2 +@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@> + +@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@+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) + +@ + +@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; + +@ + +@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 "); +@.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. + +@d return_sign(#)==begin ab_vs_cd:=#; return; + end + +@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@+ 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]|. + +@d next_random==if j_random=0 then new_randoms + else decr(j_random) + +@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. + +@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. + +@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\/}). + +@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 @@ else 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 @@ the codes for its extensions: |eTeX_version_code|, \dots\ . @d input_line_no_code=glue_val+2 {code for \.{\\inputlineno}} @d badness_code=input_line_no_code+1 {code for \.{\\badness}} @# -@d eTeX_int=badness_code+1 {first of \eTeX\ codes for integers} +@d pdftex_first_rint_code = badness_code + 1 {base for \pdfTeX's command codes} +@d pdf_last_x_pos_code = pdftex_first_rint_code + 6 {code for \.{\\pdflastxpos}} +@d pdf_last_y_pos_code = pdftex_first_rint_code + 7 {code for \.{\\pdflastypos}} +@d elapsed_time_code = pdftex_first_rint_code + 10 {code for \.{\\elapsedtime}} +@d pdf_shell_escape_code = pdftex_first_rint_code + 11 {code for \.{\\shellescape}} +@d random_seed_code = pdftex_first_rint_code + 12 {code for \.{\\randomseed}} +@d pdftex_last_item_codes = pdftex_first_rint_code + 13 {end of \pdfTeX's command codes} @# -@d XeTeX_int=eTeX_int+8 {first of \XeTeX\ codes for integers} +@d XeTeX_int = pdftex_last_item_codes + 1 {base for \XeTeX's command codes} +@d XeTeX_version_code = XeTeX_int + 0 {code for \.{\\XeTeXversion}} +@d XeTeX_count_glyphs_code = XeTeX_int + 1 {code for \.{\\XeTeXcountglyphs}} +@d XeTeX_count_variations_code = XeTeX_int + 2 {Deprecated} +@d XeTeX_variation_code = XeTeX_int + 3 {Deprecated} +@d XeTeX_find_variation_by_name_code = XeTeX_int + 4 {Deprecated} +@d XeTeX_variation_min_code = XeTeX_int + 5 {Deprecated} +@d XeTeX_variation_max_code = XeTeX_int + 6 {Deprecated} +@d XeTeX_variation_default_code = XeTeX_int + 7 {Deprecated} +@d XeTeX_count_features_code = XeTeX_int + 8 {code for \.{\\XeTeXcountfeatures}} +@d XeTeX_feature_code_code = XeTeX_int + 9 {code for \.{\\XeTeXfeaturecode}} +@d XeTeX_find_feature_by_name_code = XeTeX_int + 10 {code for \.{\\XeTeXfindfeaturebyname}} +@d XeTeX_is_exclusive_feature_code = XeTeX_int + 11 {code for \.{\\XeTeXisexclusivefeature}} +@d XeTeX_count_selectors_code = XeTeX_int + 12 {code for \.{\\XeTeXcountselectors}} +@d XeTeX_selector_code_code = XeTeX_int + 13 {code for \.{\\XeTeXselectorcode}} +@d XeTeX_find_selector_by_name_code = XeTeX_int + 14 {code for \.{\\XeTeXfindselectorbyname}} +@d XeTeX_is_default_selector_code = XeTeX_int + 15 {code for \.{\\XeTeXisdefaultselector}} +@d XeTeX_OT_count_scripts_code = XeTeX_int + 16 {code for \.{\\XeTeXOTcountscripts}} +@d XeTeX_OT_count_languages_code = XeTeX_int + 17 {code for \.{\\XeTeXOTcountlanguages}} +@d XeTeX_OT_count_features_code = XeTeX_int + 18 {code for \.{\\XeTeXOTcountfeatures}} +@d XeTeX_OT_script_code = XeTeX_int + 19 {code for \.{\\XeTeXOTscripttag}} +@d XeTeX_OT_language_code = XeTeX_int + 20 {code for \.{\\XeTeXOTlanguagetag}} +@d XeTeX_OT_feature_code = XeTeX_int + 21 {code for \.{\\XeTeXOTfeaturetag}} +@d XeTeX_map_char_to_glyph_code = XeTeX_int + 22 {code for \.{\\XeTeXcharglyph}} +@d XeTeX_glyph_index_code = XeTeX_int + 23 {code for \.{\\XeTeXglyphindex}} +@d XeTeX_font_type_code = XeTeX_int + 24 {code for \.{\\XeTeXfonttype}} +@d XeTeX_first_char_code = XeTeX_int + 25 {code for \.{\\XeTeXfirstfontchar}} +@d XeTeX_last_char_code = XeTeX_int + 26 {code for \.{\\XeTeXlastfontchar}} +@d XeTeX_pdf_page_count_code = XeTeX_int + 27 {code for \.{\\XeTeXpdfpagecount}} +@d XeTeX_last_item_codes = XeTeX_int + 27 {end of \XeTeX's command codes} @# -@d XeTeX_version_code=XeTeX_int {code for \.{\\XeTeXversion}} - -@d XeTeX_count_glyphs_code=XeTeX_int+1 - -@d XeTeX_count_variations_code=XeTeX_int+2 {Deprecated} -@d XeTeX_variation_code=XeTeX_int+3 {Deprecated} -@d XeTeX_find_variation_by_name_code=XeTeX_int+4 {Deprecated} -@d XeTeX_variation_min_code=XeTeX_int+5 {Deprecated} -@d XeTeX_variation_max_code=XeTeX_int+6 {Deprecated} -@d XeTeX_variation_default_code=XeTeX_int+7 {Deprecated} - -@d XeTeX_count_features_code=XeTeX_int+8 -@d XeTeX_feature_code_code=XeTeX_int+9 -@d XeTeX_find_feature_by_name_code=XeTeX_int+10 -@d XeTeX_is_exclusive_feature_code=XeTeX_int+11 -@d XeTeX_count_selectors_code=XeTeX_int+12 -@d XeTeX_selector_code_code=XeTeX_int+13 -@d XeTeX_find_selector_by_name_code=XeTeX_int+14 -@d XeTeX_is_default_selector_code=XeTeX_int+15 - -@d XeTeX_OT_count_scripts_code=XeTeX_int+16 -@d XeTeX_OT_count_languages_code=XeTeX_int+17 -@d XeTeX_OT_count_features_code=XeTeX_int+18 -@d XeTeX_OT_script_code=XeTeX_int+19 -@d XeTeX_OT_language_code=XeTeX_int+20 -@d XeTeX_OT_feature_code=XeTeX_int+21 - -@d XeTeX_map_char_to_glyph_code=XeTeX_int+22 -@d XeTeX_glyph_index_code=XeTeX_int+23 -@d XeTeX_font_type_code=XeTeX_int+24 - -@d XeTeX_first_char_code=XeTeX_int+25 -@d XeTeX_last_char_code=XeTeX_int+26 - -@d pdf_last_x_pos_code = XeTeX_int+27 -@d pdf_last_y_pos_code = XeTeX_int+28 -@d pdf_strcmp_code = XeTeX_int+29 -@d pdf_mdfive_sum_code = XeTeX_int+30 -@d pdf_shell_escape_code = XeTeX_int+31 - -@d XeTeX_pdf_page_count_code = XeTeX_int+32 - -@# -@d XeTeX_dim=XeTeX_int+33 {first of \XeTeX\ codes for dimensions} - -@d XeTeX_glyph_bounds_code = XeTeX_dim - +@d XeTeX_dim = XeTeX_last_item_codes + 1 {first of \XeTeX\ codes for dimensions} +@d XeTeX_glyph_bounds_code = XeTeX_dim + 0 {code for \.{\\XeTeXglyphbounds}} +@d XeTeX_last_dim_codes = XeTeX_dim + 0 {end of \XeTeX's command codes} @# -@d eTeX_dim=XeTeX_dim+1 {first of \eTeX\ codes for dimensions} - {changed for \XeTeX\ to make room for \XeTeX\ integers and dimens} +@d eTeX_int=XeTeX_last_dim_codes+1 {first of \eTeX\ codes for integers} +@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,6 +9946,17 @@ primitive("inputlineno",last_item,input_line_no_code); @!@: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") @@ -9607,8 +9972,12 @@ last_item: case chr_code of dimen_val: print_esc("lastkern"); glue_val: print_esc("lastskip"); input_line_no_code: print_esc("inputlineno"); - pdf_shell_escape_code: print_esc("shellescape"); @/@<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"); + random_seed_code: print_esc("randomseed"); othercases print_esc("badness") endcases; @@ -9701,6 +10070,8 @@ if m>=input_line_no_code then 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 @@ while k<pool_ptr do 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,21 +10942,30 @@ end; @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}} - -@d XeTeX_revision_code=6 -@d XeTeX_variation_name_code=7 -@d XeTeX_feature_name_code=8 -@d XeTeX_selector_name_code=9 -@d XeTeX_glyph_name_code=10 - -@d left_margin_kern_code=11 -@d right_margin_kern_code=12 - -@d XeTeX_Uchar_code = 13 -@d XeTeX_Ucharcat_code = 14 - -@d etex_convert_codes=XeTeX_Ucharcat_code+1 {end of \eTeX's command codes} -@d job_name_code=etex_convert_codes {command code for \.{\\jobname}} +@d etex_convert_codes=etex_convert_base+1 {end of \eTeX's command codes} +@d expanded_code=etex_convert_codes {command code for \.{\\expanded}} +@d pdftex_first_expand_code = expanded_code + 1 {base for \pdfTeX's command codes} +@d left_margin_kern_code = pdftex_first_expand_code + 9 {command code for \.{\\leftmarginkern}} +@d right_margin_kern_code = pdftex_first_expand_code + 10 {command code for \.{\\rightmarginkern}} +@d pdf_strcmp_code = pdftex_first_expand_code + 11 {command code for \.{\\strcmp}} +@d pdf_creation_date_code = pdftex_first_expand_code + 15 {command code for \.{\\creationdate}} +@d pdf_file_mod_date_code = pdftex_first_expand_code + 16 {command code for \.{\\filemoddate}} +@d pdf_file_size_code = pdftex_first_expand_code + 17 {command code for \.{\\filesize}} +@d pdf_mdfive_sum_code = pdftex_first_expand_code + 18 {command code for \.{\\mdfivesum}} +@d pdf_file_dump_code = pdftex_first_expand_code + 19 {command code for \.{\\filedump}} +@d uniform_deviate_code = pdftex_first_expand_code + 22 {command code for \.{\\uniformdeviate}} +@d normal_deviate_code = pdftex_first_expand_code + 23 {command code for \.{\\normaldeviate}} +@d pdftex_convert_codes = pdftex_first_expand_code + 26 {end of \pdfTeX's command codes} +@d XeTeX_first_expand_code = pdftex_convert_codes {base for \XeTeX's command codes} +@d XeTeX_revision_code = XeTeX_first_expand_code + 0 {command code for \.{\\XeTeXrevision}} +@d XeTeX_variation_name_code = XeTeX_first_expand_code + 1 {command code for \.{\\XeTeXvariationname}} +@d XeTeX_feature_name_code = XeTeX_first_expand_code + 2 {command code for \.{\\XeTeXfeaturename}} +@d XeTeX_selector_name_code = XeTeX_first_expand_code + 3 {command code for \.{\\XeTeXselectornamename}} +@d XeTeX_glyph_name_code = XeTeX_first_expand_code + 4 {command code for \.{\\XeTeXglyphname}} +@d XeTeX_Uchar_code = XeTeX_first_expand_code + 5 {command code for \.{\\Uchar}} +@d XeTeX_Ucharcat_code = XeTeX_first_expand_code + 6 {command code for \.{\\Ucharcat}} +@d XeTeX_convert_codes = XeTeX_first_expand_code + 7 {end of \XeTeX's command codes} +@d job_name_code=XeTeX_convert_codes {command code for \.{\\jobname}} @<Put each...@>= primitive("number",convert,number_code);@/ @@ -10597,12 +10978,35 @@ primitive("meaning",convert,meaning_code);@/ @!@: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@> @@ -10616,10 +11020,18 @@ convert: case chr_code of 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 @@ var old_setting:0..max_selector; {holds |selector| setting} @!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 @@ selector:=old_setting; link(garbage):=str_toks_cat(b,cat); ins_list(link(temp_he end; @ Not all catcode values are allowed by \.{\\Ucharcat}: -@d illegal_Ucharcat_catcode(#)==(#<left_brace)or(#>other_char)or(#=out_param)or(#=ignore) +@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 @@ string_code, meaning_code: begin save_scanner_status:=scanner_status; 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"); +@.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"); +@.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 @@ XeTeX_Ucharcat_code: 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 @@ XeTeX_Ucharcat_code: 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 @@ font_name_code: begin 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 @@ while font_ptr>font_base do 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 eTeX_ex then wterm_ln('entering extended mode'); 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 @@ stays the same. @d set_language_code=5 {command modifier for \.{\\setlanguage}} @d pdftex_first_extension_code = 6 -@d pdf_save_pos_node == pdftex_first_extension_code + 0 +@d pdf_save_pos_node == pdftex_first_extension_code + 15 +@d reset_timer_code == pdftex_first_extension_code + 25 +@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 @@ primitive("immediate",extension,immediate_code);@/ @!@: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,13 +29537,15 @@ extension: case chr_code of 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"); 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 @@ procedure do_extension; 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 @@ end @ @d call_func(#) == begin if # <> 0 then do_nothing end @d flushable(#) == (# = str_ptr - 1) +@d max_integer == @"7FFFFFFF {$2^{31}-1$} @p procedure flush_str(s: str_number); {flush a string if possible} begin @@ -29044,6 +29699,38 @@ done: 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 @@ language_node:begin print_esc("setlanguage"); 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 @@ pic_node,pdf_node: begin 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("XeTeXfonttype", last_item, XeTeX_font_type_code); 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_font_type_code: print_esc("XeTeXfonttype"); 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 @@ XeTeX_glyph_bounds_code: 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_Uchar_code: print_esc("Uchar"); 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 @@ XeTeX_glyph_name_code: 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_selector_name_code: 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...@>= |