From 6cd9cb9b90a640486b1e6cf9bf4385e1622dc621 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Tue, 2 Jul 2019 21:03:06 +0000 Subject: l3 (2jul19) git-svn-id: svn://tug.org/texlive/trunk@51534 c570f23f-e606-0410-a88d-b1316a301751 --- .../l3experimental/l3benchmark/l3benchmark.dtx | 4 +- .../latex/l3experimental/l3cctab/l3cctab.dtx | 4 +- .../latex/l3experimental/l3color/l3color.dtx | 6 +- .../latex/l3experimental/l3draw/l3draw-boxes.dtx | 4 +- .../latex/l3experimental/l3draw/l3draw-layers.dtx | 6 +- .../latex/l3experimental/l3draw/l3draw-paths.dtx | 8 +- .../latex/l3experimental/l3draw/l3draw-points.dtx | 2 +- .../latex/l3experimental/l3draw/l3draw-scopes.dtx | 10 +- .../l3experimental/l3draw/l3draw-softpath.dtx | 12 +- .../latex/l3experimental/l3draw/l3draw-state.dtx | 32 +- .../l3experimental/l3draw/l3draw-transforms.dtx | 2 +- .../source/latex/l3experimental/l3draw/l3draw.dtx | 6 +- .../latex/l3experimental/l3graphics/l3graphics.dtx | 10 +- .../source/latex/l3experimental/l3pdf/l3pdf.dtx | 337 ++ .../source/latex/l3experimental/l3pdf/l3pdf.ins | 60 + .../latex/l3experimental/l3str/l3str-convert.dtx | 3517 -------------------- .../latex/l3experimental/l3str/l3str-format.dtx | 4 +- .../source/latex/l3experimental/l3str/l3str.ins | 35 - .../l3experimental/l3sys-shell/l3sys-shell.dtx | 4 +- .../latex/l3experimental/xcoffins/xcoffins.dtx | 4 +- .../latex/l3experimental/xgalley/l3galley.dtx | 4 +- .../latex/l3experimental/xgalley/xgalley.dtx | 4 +- Master/texmf-dist/source/latex/l3kernel/expl3.dtx | 9 +- Master/texmf-dist/source/latex/l3kernel/l3.ins | 84 +- .../texmf-dist/source/latex/l3kernel/l3alloc.dtx | 2 +- .../texmf-dist/source/latex/l3kernel/l3basics.dtx | 20 +- .../source/latex/l3kernel/l3bootstrap.dtx | 2 +- Master/texmf-dist/source/latex/l3kernel/l3box.dtx | 6 +- .../source/latex/l3kernel/l3candidates.dtx | 6 +- .../texmf-dist/source/latex/l3kernel/l3clist.dtx | 2 +- .../texmf-dist/source/latex/l3kernel/l3coffins.dtx | 4 +- .../source/latex/l3kernel/l3color-base.dtx | 12 +- .../source/latex/l3kernel/l3deprecation.dtx | 2 +- Master/texmf-dist/source/latex/l3kernel/l3doc.dtx | 35 +- .../source/latex/l3kernel/l3docstrip.dtx | 2 +- .../source/latex/l3kernel/l3drivers-basics.dtx | 373 --- .../source/latex/l3kernel/l3drivers-box.dtx | 473 --- .../source/latex/l3kernel/l3drivers-color.dtx | 307 -- .../source/latex/l3kernel/l3drivers-draw.dtx | 1338 -------- .../source/latex/l3kernel/l3drivers-graphics.dtx | 611 ---- .../source/latex/l3kernel/l3drivers-pdf.dtx | 1934 ----------- .../texmf-dist/source/latex/l3kernel/l3drivers.dtx | 749 ----- .../texmf-dist/source/latex/l3kernel/l3expan.dtx | 2 +- Master/texmf-dist/source/latex/l3kernel/l3file.dtx | 2 +- .../texmf-dist/source/latex/l3kernel/l3final.dtx | 2 +- Master/texmf-dist/source/latex/l3kernel/l3flag.dtx | 2 +- .../texmf-dist/source/latex/l3kernel/l3format.ins | 88 +- .../source/latex/l3kernel/l3fp-assign.dtx | 2 +- .../texmf-dist/source/latex/l3kernel/l3fp-aux.dtx | 2 +- .../source/latex/l3kernel/l3fp-basics.dtx | 2 +- .../source/latex/l3kernel/l3fp-convert.dtx | 2 +- .../texmf-dist/source/latex/l3kernel/l3fp-expo.dtx | 2 +- .../source/latex/l3kernel/l3fp-extended.dtx | 2 +- .../source/latex/l3kernel/l3fp-logic.dtx | 2 +- .../source/latex/l3kernel/l3fp-parse.dtx | 2 +- .../source/latex/l3kernel/l3fp-random.dtx | 2 +- .../source/latex/l3kernel/l3fp-round.dtx | 2 +- .../source/latex/l3kernel/l3fp-traps.dtx | 2 +- .../texmf-dist/source/latex/l3kernel/l3fp-trig.dtx | 2 +- Master/texmf-dist/source/latex/l3kernel/l3fp.dtx | 2 +- .../texmf-dist/source/latex/l3kernel/l3fparray.dtx | 2 +- Master/texmf-dist/source/latex/l3kernel/l3int.dtx | 2 +- .../source/latex/l3kernel/l3intarray.dtx | 2 +- .../source/latex/l3kernel/l3kernel-functions.dtx | 112 +- Master/texmf-dist/source/latex/l3kernel/l3keys.dtx | 46 +- .../texmf-dist/source/latex/l3kernel/l3legacy.dtx | 2 +- .../texmf-dist/source/latex/l3kernel/l3luatex.dtx | 2 +- Master/texmf-dist/source/latex/l3kernel/l3msg.dtx | 101 +- .../texmf-dist/source/latex/l3kernel/l3names.dtx | 2 +- Master/texmf-dist/source/latex/l3kernel/l3prg.dtx | 2 +- Master/texmf-dist/source/latex/l3kernel/l3prop.dtx | 2 +- .../texmf-dist/source/latex/l3kernel/l3quark.dtx | 6 +- .../texmf-dist/source/latex/l3kernel/l3regex.dtx | 4 +- Master/texmf-dist/source/latex/l3kernel/l3seq.dtx | 2 +- Master/texmf-dist/source/latex/l3kernel/l3skip.dtx | 4 +- Master/texmf-dist/source/latex/l3kernel/l3sort.dtx | 2 +- .../source/latex/l3kernel/l3str-convert.dtx | 3471 +++++++++++++++++++ Master/texmf-dist/source/latex/l3kernel/l3str.dtx | 2 +- Master/texmf-dist/source/latex/l3kernel/l3sys.dtx | 2 +- .../source/latex/l3kernel/l3tl-analysis.dtx | 2 +- Master/texmf-dist/source/latex/l3kernel/l3tl.dtx | 2 +- .../texmf-dist/source/latex/l3kernel/l3token.dtx | 2 +- .../texmf-dist/source/latex/l3kernel/l3unicode.dtx | 2 +- 83 files changed, 4277 insertions(+), 9667 deletions(-) create mode 100644 Master/texmf-dist/source/latex/l3experimental/l3pdf/l3pdf.dtx create mode 100644 Master/texmf-dist/source/latex/l3experimental/l3pdf/l3pdf.ins delete mode 100644 Master/texmf-dist/source/latex/l3experimental/l3str/l3str-convert.dtx delete mode 100644 Master/texmf-dist/source/latex/l3kernel/l3drivers-basics.dtx delete mode 100644 Master/texmf-dist/source/latex/l3kernel/l3drivers-box.dtx delete mode 100644 Master/texmf-dist/source/latex/l3kernel/l3drivers-color.dtx delete mode 100644 Master/texmf-dist/source/latex/l3kernel/l3drivers-draw.dtx delete mode 100644 Master/texmf-dist/source/latex/l3kernel/l3drivers-graphics.dtx delete mode 100644 Master/texmf-dist/source/latex/l3kernel/l3drivers-pdf.dtx delete mode 100644 Master/texmf-dist/source/latex/l3kernel/l3drivers.dtx create mode 100644 Master/texmf-dist/source/latex/l3kernel/l3str-convert.dtx (limited to 'Master/texmf-dist/source') diff --git a/Master/texmf-dist/source/latex/l3experimental/l3benchmark/l3benchmark.dtx b/Master/texmf-dist/source/latex/l3experimental/l3benchmark/l3benchmark.dtx index 218988c8050..e06cd58d1d9 100644 --- a/Master/texmf-dist/source/latex/l3experimental/l3benchmark/l3benchmark.dtx +++ b/Master/texmf-dist/source/latex/l3experimental/l3benchmark/l3benchmark.dtx @@ -46,7 +46,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % @@ -130,7 +130,7 @@ % % \begin{macrocode} %<*package> -\ProvidesExplPackage{l3benchmark}{2019-05-28}{} +\ProvidesExplPackage{l3benchmark}{2019-07-01}{} {L3 Experimental benchmarking} % % \end{macrocode} diff --git a/Master/texmf-dist/source/latex/l3experimental/l3cctab/l3cctab.dtx b/Master/texmf-dist/source/latex/l3experimental/l3cctab/l3cctab.dtx index e058c450900..ad4e422bd65 100644 --- a/Master/texmf-dist/source/latex/l3experimental/l3cctab/l3cctab.dtx +++ b/Master/texmf-dist/source/latex/l3experimental/l3cctab/l3cctab.dtx @@ -46,7 +46,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % @@ -150,7 +150,7 @@ % % \begin{macrocode} %<*package> -\ProvidesExplPackage{l3cctab}{2019-05-28}{} +\ProvidesExplPackage{l3cctab}{2019-07-01}{} {L3 Experimental category code tables} % % \end{macrocode} diff --git a/Master/texmf-dist/source/latex/l3experimental/l3color/l3color.dtx b/Master/texmf-dist/source/latex/l3experimental/l3color/l3color.dtx index 52e60d2b7a2..92e9ff6369c 100644 --- a/Master/texmf-dist/source/latex/l3experimental/l3color/l3color.dtx +++ b/Master/texmf-dist/source/latex/l3experimental/l3color/l3color.dtx @@ -46,7 +46,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % @@ -265,7 +265,7 @@ % % \begin{macrocode} %<*package> -\ProvidesExplPackage{l3color}{2019-05-28}{} +\ProvidesExplPackage{l3color}{2019-07-01}{} {L3 Experimental color support} % % \end{macrocode} @@ -448,7 +448,7 @@ \cs_new_protected:Npn \color_parse:nN #1#2 { %<*package> - \driver_color_pickup:N \l_@@_current_tl + \@@_backend_pickup:N \l_@@_current_tl \tl_set_eq:cN { l_@@_named_ . _tl } \l_@@_current_tl % \exp_args:Ne \@@_parse:nN { \tl_to_str:n {#1} } #2 diff --git a/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-boxes.dtx b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-boxes.dtx index e3994c49e3c..1f972d673af 100644 --- a/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-boxes.dtx +++ b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-boxes.dtx @@ -44,7 +44,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % @@ -104,7 +104,7 @@ { \use:x { - \driver_draw_box_use:Nnnnn #1 + \@@_backend_box_use:Nnnnn #1 { \fp_use:N \l_@@_matrix_a_fp } { \fp_use:N \l_@@_matrix_b_fp } { \fp_use:N \l_@@_matrix_c_fp } diff --git a/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-layers.dtx b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-layers.dtx index a24b87bb6bd..4c5c0862746 100644 --- a/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-layers.dtx +++ b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-layers.dtx @@ -44,7 +44,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % @@ -158,10 +158,10 @@ \box_use_drop:N \l_@@_layer_main_box } { - \driver_draw_scope_begin: + \@@_backend_scope_begin: \box_gset_wd:cn { g_@@_layer_ ##1 _box } { 0pt } \box_use_drop:c { g_@@_layer_ ##1 _box } - \driver_draw_scope_end: + \@@_backend_scope_end: } } } diff --git a/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-paths.dtx b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-paths.dtx index f3c76c0f24e..af2f72698da 100644 --- a/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-paths.dtx +++ b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-paths.dtx @@ -44,7 +44,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % @@ -891,11 +891,11 @@ \@@_softpath_use: \bool_if:NT \l_@@_path_use_clip_bool { - \driver_draw_clip: + \@@_backend_clip: \bool_lazy_or:nnF { \l_@@_path_use_fill_bool } { \l_@@_path_use_stroke_bool } - { \driver_draw_discardpath: } + { \@@_backend_discardpath: } } \bool_lazy_or:nnT { \l_@@_path_use_fill_bool } @@ -903,7 +903,7 @@ { \use:c { - driver_draw_ + @@_backend_ \bool_if:NT \l_@@_path_use_fill_bool { fill } \bool_if:NT \l_@@_path_use_stroke_bool { stroke } : diff --git a/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-points.dtx b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-points.dtx index 460e8b122d6..510b6534bd0 100644 --- a/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-points.dtx +++ b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-points.dtx @@ -44,7 +44,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-scopes.dtx b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-scopes.dtx index 3797642b8fe..036921ef3bb 100644 --- a/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-scopes.dtx +++ b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-scopes.dtx @@ -44,7 +44,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % @@ -124,7 +124,7 @@ \group_begin: \int_gincr:N \g_@@_id_int \hbox_set:Nw \l_@@_main_box - \driver_draw_begin: + \@@_backend_begin: \@@_reset_bb: \@@_path_reset_limits: \bool_set_true:N \l_draw_bb_update_bool @@ -145,7 +145,7 @@ \exp_args:NNNV \hbox_set_end: \clist_set:Nn \l_draw_layers_clist \l_draw_layers_clist \@@_layers_insert: - \driver_draw_end: + \@@_backend_end: \hbox_set_end: \dim_compare:nNnT \g_@@_xmin_dim = \c_max_dim { @@ -191,7 +191,7 @@ % \begin{macrocode} \cs_new_protected:Npn \draw_scope_begin: { - \driver_draw_scope_begin: + \@@_backend_scope_begin: \group_begin: \dim_set_eq:NN \l_@@_linewidth_dim \g_@@_linewidth_dim \draw_path_scope_begin: @@ -201,7 +201,7 @@ \draw_path_scope_end: \dim_gset_eq:NN \g_@@_linewidth_dim \l_@@_linewidth_dim \group_end: - \driver_draw_scope_end: + \@@_backend_scope_end: } % \end{macrocode} % \end{macro} diff --git a/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-softpath.dtx b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-softpath.dtx index b1cbf83e5e4..4e334c45d7a 100644 --- a/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-softpath.dtx +++ b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-softpath.dtx @@ -44,7 +44,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % @@ -221,24 +221,24 @@ % round point, hence being quark-like. % \begin{macrocode} \cs_new_protected:Npn \@@_softpath_close_op:nn #1#2 - { \driver_draw_closepath: } + { \@@_backend_closepath: } \cs_new_protected:Npn \@@_softpath_curveto_opi:nn #1#2 { \@@_softpath_curveto_opi:nnNnnNnn {#1} {#2} } \cs_new_protected:Npn \@@_softpath_curveto_opi:nnNnnNnn #1#2#3#4#5#6#7#8 - { \driver_draw_curveto:nnnnnn {#1} {#2} {#4} {#5} {#7} {#8} } + { \@@_backend_curveto:nnnnnn {#1} {#2} {#4} {#5} {#7} {#8} } \cs_new_protected:Npn \@@_softpath_curveto_opii:nn #1#2 { \@@_softpath_curveto_opii:nn } \cs_new_protected:Npn \@@_softpath_curveto_opiii:nn #1#2 { \@@_softpath_curveto_opiii:nn } \cs_new_protected:Npn \@@_softpath_lineto_op:nn #1#2 - { \driver_draw_lineto:nn {#1} {#2} } + { \@@_backend_lineto:nn {#1} {#2} } \cs_new_protected:Npn \@@_softpath_moveto_op:nn #1#2 - { \driver_draw_moveto:nn {#1} {#2} } + { \@@_backend_moveto:nn {#1} {#2} } \cs_new_protected:Npn \@@_softpath_roundpoint_op:nn #1#2 { } \cs_new_protected:Npn \@@_softpath_rectangle_opi:nn #1#2 { \@@_softpath_rectangle_opi:nnNnn {#1} {#2} } \cs_new_protected:Npn \@@_softpath_rectangle_opi:nnNnn #1#2#3#4#5 - { \driver_draw_rectangle:nnnn {#1} {#2} {#4} {#5} } + { \@@_backend_rectangle:nnnn {#1} {#2} {#4} {#5} } \cs_new_protected:Npn \@@_softpath_rectangle_opii:nn #1#2 { } % \end{macrocode} % \end{macro} diff --git a/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-state.dtx b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-state.dtx index cbf1eca6768..7e646d76c3a 100644 --- a/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-state.dtx +++ b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-state.dtx @@ -44,7 +44,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % @@ -92,7 +92,7 @@ \cs_new_protected:Npn \draw_linewidth:n #1 { \dim_gset:Nn \g_@@_linewidth_dim { \fp_to_dim:n {#1} } - \driver_draw_linewidth:n \g_@@_linewidth_dim + \@@_backend_linewidth:n \g_@@_linewidth_dim } % \end{macrocode} % \end{macro} @@ -109,7 +109,7 @@ { \fp_to_dim:n {##1} } \use:x { - \driver_draw_dash_pattern:nn + \@@_backend_dash_pattern:nn { \seq_use:Nn \l_@@_tmp_seq { , } } { \fp_to_dim:n {#2} } } @@ -124,7 +124,7 @@ % Pass through to the driver layer. % \begin{macrocode} \cs_new_protected:Npn \draw_miterlimit:n #1 - { \driver_draw_miterlimit:n { \fp_eval:n {#1} } } + { \@@_backend_miterlimit:n { \fp_eval:n {#1} } } % \end{macrocode} % \end{macro} % @@ -136,14 +136,14 @@ % } % All straight wrappers. % \begin{macrocode} -\cs_new_protected:Npn \draw_cap_butt: { \driver_draw_cap_butt: } -\cs_new_protected:Npn \draw_cap_rectangle: { \driver_draw_cap_rectangle: } -\cs_new_protected:Npn \draw_cap_round: { \driver_draw_cap_round: } -\cs_new_protected:Npn \draw_evenodd_rule: { \driver_draw_evenodd_rule: } -\cs_new_protected:Npn \draw_nonzero_rule: { \driver_draw_nonzero_rule: } -\cs_new_protected:Npn \draw_join_bevel: { \driver_draw_join_bevel: } -\cs_new_protected:Npn \draw_join_miter: { \driver_draw_join_miter: } -\cs_new_protected:Npn \draw_join_round: { \driver_draw_join_round: } +\cs_new_protected:Npn \draw_cap_butt: { \@@_backend_cap_butt: } +\cs_new_protected:Npn \draw_cap_rectangle: { \@@_backend_cap_rectangle: } +\cs_new_protected:Npn \draw_cap_round: { \@@_backend_cap_round: } +\cs_new_protected:Npn \draw_evenodd_rule: { \@@_backend_evenodd_rule: } +\cs_new_protected:Npn \draw_nonzero_rule: { \@@_backend_nonzero_rule: } +\cs_new_protected:Npn \draw_join_bevel: { \@@_backend_join_bevel: } +\cs_new_protected:Npn \draw_join_miter: { \@@_backend_join_miter: } +\cs_new_protected:Npn \draw_join_round: { \@@_backend_join_round: } % \end{macrocode} % \end{macro} % @@ -182,13 +182,13 @@ \cs_new_protected:Npn \@@_color:nw #1#2 ~ #3 \q_stop { \use:c { @@_color_ #2 :nw } {#1} #3 \q_stop } \cs_new_protected:Npn \@@_color_cmyk:nw #1#2 ~ #3 ~ #4 ~ #5 \q_stop - { \use:c { driver_draw_color_ #1 _cmyk:nnnn } {#2} {#3} {#4} {#5} } + { \use:c { @@_backend_color_ #1 _cmyk:nnnn } {#2} {#3} {#4} {#5} } \cs_new_protected:Npn \@@_color_gray:nw #1#2 \q_stop - { \use:c { driver_draw_color_ #1 _gray:n } {#2} } + { \use:c { @@_backend_color_ #1 _gray:n } {#2} } \cs_new_protected:Npn \@@_color_rgb:nw #1#2 ~ #3 ~ #4 \q_stop - { \use:c { driver_draw_color_ #1 _rgb:nnn } {#2} {#3} {#4} } + { \use:c { @@_backend_color_ #1 _rgb:nnn } {#2} {#3} {#4} } \cs_new_protected:Npn \@@_color_spot:nw #1#2 ~ #3 \q_stop - { \use:c { driver_draw_color_ #1 _spot:nn } {#2} {#3} } + { \use:c { @@_backend_color_ #1 _spot:nn } {#2} {#3} } % \end{macrocode} % \end{macro} % \end{macro} diff --git a/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-transforms.dtx b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-transforms.dtx index 77850944890..9b25c60043c 100644 --- a/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-transforms.dtx +++ b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw-transforms.dtx @@ -44,7 +44,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw.dtx b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw.dtx index d01788b0c80..bb2661de0c5 100644 --- a/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw.dtx +++ b/Master/texmf-dist/source/latex/l3experimental/l3draw/l3draw.dtx @@ -110,7 +110,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % @@ -394,7 +394,7 @@ % higher-level functions, for example path construction, and allows parts of % a drawing to be rotated, scaled or skewed. This occurs before writing any % data to the driver, and so such manipulations are tracked by the drawing -% mechanisms. See \cs{driver_draw_cm:nnnn} for driver-level +% mechanisms. See \cs{@@_backend_cm:nnnn} for backend-level % manipulation of the canvas axes themselves. % % Notice that in contrast to \pkg{pgf} it is possible to give the positions @@ -1145,7 +1145,7 @@ % % \begin{macrocode} %<*package> -\ProvidesExplPackage{l3draw}{2019-05-28}{} +\ProvidesExplPackage{l3draw}{2019-07-01}{} {L3 Experimental core drawing support} % % \end{macrocode} diff --git a/Master/texmf-dist/source/latex/l3experimental/l3graphics/l3graphics.dtx b/Master/texmf-dist/source/latex/l3experimental/l3graphics/l3graphics.dtx index b8378682a59..e8e58babb09 100644 --- a/Master/texmf-dist/source/latex/l3experimental/l3graphics/l3graphics.dtx +++ b/Master/texmf-dist/source/latex/l3experimental/l3graphics/l3graphics.dtx @@ -46,7 +46,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % @@ -241,7 +241,7 @@ % % \begin{macrocode} %<*package> -\ProvidesExplPackage{l3graphics}{2019-05-28}{} +\ProvidesExplPackage{l3graphics}{2019-07-01}{} {L3 Experimental graphics inclusion support} % % \end{macrocode} @@ -601,10 +601,10 @@ \cs_new_protected:Npn \@@_include_auxii:n #1 { \mode_leave_vertical: - \cs_if_exist:cTF { driver_graphics_include_ #1 :n } + \cs_if_exist:cTF { @@_backend_include_ #1 :n } { \tl_set_eq:NN \l_graphics_name_tl \l_@@_name_tl - \exp_args:NnV \use:c { driver_graphics_getbb_ #1 :n } + \exp_args:NnV \use:c { @@_backend_getbb_ #1 :n } \l_@@_name_tl \seq_gput_right:NV \g_@@_record_seq \l_graphics_name_tl %<*package> @@ -649,7 +649,7 @@ { \hbox_set:Nn \l_@@_internal_box { - \exp_args:NnV \use:c { driver_graphics_include_ #1 :n } + \exp_args:NnV \use:c { @@_backend_include_ #1 :n } \l_@@_name_tl } \box_set_dp:Nn \l_@@_internal_box { 0pt } diff --git a/Master/texmf-dist/source/latex/l3experimental/l3pdf/l3pdf.dtx b/Master/texmf-dist/source/latex/l3experimental/l3pdf/l3pdf.dtx new file mode 100644 index 00000000000..a8eff007f4b --- /dev/null +++ b/Master/texmf-dist/source/latex/l3experimental/l3pdf/l3pdf.dtx @@ -0,0 +1,337 @@ +% \iffalse meta-comment +% +%% File: l3pdf.dtx +% +% Copyright(C) 2019 The LaTeX3 Project +% +% It may be distributed and/or modified under the conditions of the +% LaTeX Project Public License (LPPL), either version 1.3c of this +% license or (at your option) any later version. The latest version +% of this license is in the file +% +% http://www.latex-project.org/lppl.txt +% +% This file is part of the "l3experimental bundle" (The Work in LPPL) +% and all files in that bundle must be distributed together. +% +% ----------------------------------------------------------------------- +% +% The development version of the bundle can be found at +% +% https://github.com/latex3/latex3 +% +% for those people who are interested. +% +%<*driver|package> +\RequirePackage{expl3} +% +%<*driver> +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +% +% \fi +% +% \title{^^A +% The \pkg{l3pdf} package\\ Core PDF support^^A +% } +% +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released 2019-07-01} +% +% \maketitle +% +% \begin{documentation} +% +% \section{\pkg{l3pdf} documentation} +% +% \subsection{Objects} +% +% \begin{function}[added = 2019-06-02]{\pdf_object_new:nn} +% \begin{syntax} +% \cs{pdf_object_new:nn} \Arg{object} \Arg{type} +% \end{syntax} +% Declares \meta{object} as a PDF object of \meta{type}, which should be +% one of +% \begin{itemize} +% \item \texttt{array} +% \item \texttt{dict} +% \item \texttt{fstream} +% \item \texttt{stream} +% \end{itemize} +% The object may be referenced from this point on, and written later +% using \cs{pdf_object_write:nn}. +% \end{function} +% +% \begin{function}[added = 2019-06-02] +% {\pdf_object_write:nn, \pdf_object_write:nx} +% \begin{syntax} +% \cs{pdf_object_write:nn} \Arg{object} \Arg{content} +% \end{syntax} +% Writes the \meta{content} as content of the \meta{object}. Depending on the +% \meta{type} declared for the object, the format required for the +% \meta{data} will vary +% \begin{itemize} +% \item[\texttt{array}] A space-separated list of values +% \item[\texttt{dict}] Key--value pairs in the form +% \texttt{/\meta{key} \meta{value}} +% \item[\texttt{fstream}] Two brace groups: \meta{file name} and +% \meta{file content} +% \item[\texttt{stream}] Two brace groups: \meta{attributes (dictionary)} +% and \meta{stream contents} +% \end{itemize} +% \end{function} +% +% \begin{function}[EXP, added = 2019-06-02]{\pdf_object_ref:n} +% \begin{syntax} +% \cs{pdf_object_ref:n} \Arg{object} +% \end{syntax} +% Inserts the appropriate information to reference the \meta{object} +% in for example page resource allocation +% \end{function} +% +% \begin{function}[added = 2019-06-02] +% {\pdf_object_now:nn, \pdf_object_now:nx} +% \begin{syntax} +% \cs{pdf_object_now:nn} \Arg{type} \Arg{content} +% \end{syntax} +% Writes the \meta{content} as content of an anonymous object. Depending on the +% \meta{type}, the format required for the \meta{data} will vary +% \begin{itemize} +% \item[\texttt{array}] A space-separated list of values +% \item[\texttt{dict}] Key--value pairs in the form +% \texttt{/\meta{key} \meta{value}} +% \item[\texttt{fstream}] Two brace groups: \meta{file name} and +% \meta{file content} +% \item[\texttt{stream}] Two brace groups: \meta{attributes (dictionary)} +% and \meta{stream contents} +% \end{itemize} +% \end{function} +% +% \begin{function}[EXP, added = 2019-06-02]{\pdf_object_last:} +% \begin{syntax} +% \cs{pdf_object_last:} +% \end{syntax} +% Inserts the appropriate information to reference the last \meta{object} +% created. This is particularly useful for anonymous objects. +% \end{function} +% +% \subsection{Version} +% +% \begin{function}[pTF, EXP, added = 2019-06-02]{\pdf_version_compare:Nn} +% \begin{syntax} +% \cs{pdf_version_compare:NnTF} \meta{comparator} \Arg{version} \Arg{true code} \Arg{false code} +% \end{syntax} +% Compares the version of the PDF being created with the \meta{version} +% string specified, using the \meta{comparator}. Either the \meta{true code} +% or \meta{false code} will be left in the output stream. +% \end{function} +% +% \begin{function}[added = 2019-06-02] +% {\pdf_version_gset:n, \pdf_version_min_gset:n} +% \begin{syntax} +% \cs{pdf_version_gset:n} \Arg{version} +% \end{syntax} +% Sets the \meta{version} of the PDF being created. The |min| version will +% not alter the output version unless it is currently lower than the +% \meta{version} requested. +% +% This function may only be used up to the point where the PDF file is +% initialised. +% \end{function} +% +% \begin{function}[EXP, added = 2019-06-02] +% {\pdf_version:, \pdf_version_major:, \pdf_version_minor:} +% \begin{syntax} +% \cs{pdf_version:} +% \end{syntax} +% Expands to the currently-active PDF version. +% \end{function} +% +% \subsection{Compression} +% +% \begin{function}[added = 2019-06-02]{\pdf_uncompress:} +% \begin{syntax} +% \cs{pdf_uncompress:} +% \end{syntax} +% Disables any compression of the PDF, where possible. +% +% This function may only be used up to the point where the PDF file is +% initialised. +% \end{function} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3pdf} implementation} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% \begin{macrocode} +%<@@=pdf> +% \end{macrocode} +% +% \begin{macrocode} +%<*package> +\ProvidesExplPackage{l3pdf}{2019-07-01}{} + {L3 Experimental core PDF support} +% +% \end{macrocode} +% +% \begin{variable}{\g_@@_init_bool} +% A flag so we have some chance of avoiding setting things we are not +% allowed to. +% \begin{macrocode} +\bool_new:N \g_@@_init_bool +%<*package> +\cs_if_exist:NT \documentclass + { + \AtBeginDocument + { \bool_gset_true:N \g_@@_init_bool } + } +% +% \end{macrocode} +% \end{variable} +% +% \subsection{Compression} +% +% \begin{macro}{\pdf_uncompress:} +% Simple to do. +% \begin{macrocode} +\cs_new_protected:Npn \pdf_uncompress: + { + \bool_if:NF \g_@@_init_bool + { + \@@_backend_compresslevel:n { 0 } + \@@_backend_compress_objects:n { \c_false_bool } + } + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Objects} +% +% \begin{macro}{\pdf_object_new:nn, \pdf_object_write:nn, \pdf_object_write:nx} +% \begin{macro}{\pdf_object_ref:n} +% \begin{macro}{\pdf_object_now:nn, \pdf_object_now:nx} +% \begin{macro}{\pdf_object_last:} +% Simple to do. +% \begin{macrocode} +\cs_new_protected:Npn \pdf_object_new:nn #1#2 + { \@@_backend_object_new:nn {#1} {#2} } +\cs_new_protected:Npn \pdf_object_write:nn #1#2 + { \@@_backend_object_write:nn {#1} {#2} } +\cs_generate_variant:Nn \pdf_object_write:nn { nx } +\cs_new:Npn \pdf_object_ref:n #1 { \@@_backend_object_ref:n {#1} } +\cs_new_protected:Npn \pdf_object_now:nn #1#2 + { \@@_backend_object_now:nn {#1} {#2} } +\cs_generate_variant:Nn \pdf_object_now:nn { nx } +\cs_new:Npn \pdf_object_last: { \@@_backend_object_last: } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Version} +% +% \begin{macro}{\pdf_version_compare:Nn} +% \begin{macro} +% { +% @@_version_compare_=:w , +% @@_version_compare_<:w , +% @@_version_compare_>:w +% } +% \begin{macrocode} +% To compare version, we need to split the given value then deal with both +% major and minor version +\prg_new_conditional:Npnn \pdf_version_compare:Nn #1#2 { p , T , F , TF } + { \use:c { @@_version_compare_ #1 :w } #2 . . \q_stop } +\cs_new:cpn { @@_version_compare_=:w } #1 . #2 . #3 \q_stop + { + \bool_lazy_and:nnTF + { \int_compare_p:nNn \@@_backend_version_major: = {#1} } + { \int_compare_p:nNn \@@_backend_version_minor: = {#2} } + { \prg_return_true: } + { \prg_return_false: } + } +\cs_new:cpn { @@_version_compare_<:w } #1 . #2 . #3 \q_stop + { + \bool_lazy_or:nnTF + { \int_compare_p:nNn \@@_backend_version_major: < {#1} } + { + \bool_lazy_and_p:nn + { \int_compare_p:nNn \@@_backend_version_major: = {#1} } + { \int_compare_p:nNn \@@_backend_version_minor: < {#2} } + } + { \prg_return_true: } + { \prg_return_false: } + } +\cs_new:cpn { @@_version_compare_>:w } #1 . #2 . #3 \q_stop + { + \bool_lazy_or:nnTF + { \int_compare_p:nNn \@@_backend_version_major: > {#1} } + { + \bool_lazy_and_p:nn + { \int_compare_p:nNn \@@_backend_version_major: = {#1} } + { \int_compare_p:nNn \@@_backend_version_minor: > {#2} } + } + { \prg_return_true: } + { \prg_return_false: } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\pdf_version_gset:n, \pdf_version_min_gset:n} +% \begin{macro}{\@@_version_gset:w} +% Split the version and set. +% \begin{macrocode} +\cs_new_protected:Npn \pdf_version_gset:n #1 + { \@@_version_gset:w #1 . . \q_stop } +\cs_new_protected:Npn \pdf_version_min_gset:n #1 + { + \pdf_version_compare:NnT < {#1} + { \@@_version_gset:w #1 . . \q_stop } + } +\cs_new_protected:Npn \@@_version_gset:w #1 . #2 . #3\q_stop + { + \bool_if:NF \g_@@_init_bool + { + \@@_backend_version_major_gset:n {#1} + \@@_backend_version_minor_gset:n {#2} + } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[EXP]{\pdf_version:, \pdf_version_major:, \pdf_version_minor:} +% Wrappers. +% \begin{macrocode} +\cs_new:Npn \pdf_version: + { \@@_backend_version_major: . \@@_backend_version_minor: } +\cs_new:Npn \pdf_version_major: { \@@_backend_version_major: } +\cs_new:Npn \pdf_version_minor: { \@@_backend_version_minor: } +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +% +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex diff --git a/Master/texmf-dist/source/latex/l3experimental/l3pdf/l3pdf.ins b/Master/texmf-dist/source/latex/l3experimental/l3pdf/l3pdf.ins new file mode 100644 index 00000000000..d39eefa1140 --- /dev/null +++ b/Master/texmf-dist/source/latex/l3experimental/l3pdf/l3pdf.ins @@ -0,0 +1,60 @@ +\iffalse meta-comment + +File: l3pdf.ins + +Copyright (C) 2019 The LaTeX3 Project + +It may be distributed and/or modified under the conditions of the +LaTeX Project Public License (LPPL), either version 1.3c of this +license or (at your option) any later version. The latest version +of this license is in the file + + http://www.latex-project.org/lppl.txt + +This file is part of the "l3experimental bundle" (The Work in LPPL) +and all files in that bundle must be distributed together. + +----------------------------------------------------------------------- + +The development version of the bundle can be found at + + https://github.com/latex3/latex3 + +for those people who are interested. + +----------------------------------------------------------------------- + +Any modification of this file should ensure that the copyright and +license information is placed in the derived files. + +\fi + +\input l3docstrip.tex +\askforoverwritefalse + +\preamble + +Copyright (C) 2019 The LaTeX3 Project + +It may be distributed and/or modified under the conditions of +the LaTeX Project Public License (LPPL), either version 1.3c of +this license or (at your option) any later version. The latest +version of this license is in the file: + + http://www.latex-project.org/lppl.txt + +This file is part of the "l3pdf bundle" (The Work in LPPL) +and all files in that bundle must be distributed together. + +\endpreamble +% stop docstrip adding \endinput +\postamble +\endpostamble + +\keepsilent + +\generate{\file{l3pdf.sty} + {\from{l3pdf.dtx}{package}} +} + +\endbatchfile diff --git a/Master/texmf-dist/source/latex/l3experimental/l3str/l3str-convert.dtx b/Master/texmf-dist/source/latex/l3experimental/l3str/l3str-convert.dtx deleted file mode 100644 index fb218771a5a..00000000000 --- a/Master/texmf-dist/source/latex/l3experimental/l3str/l3str-convert.dtx +++ /dev/null @@ -1,3517 +0,0 @@ -% \iffalse meta-comment -% -%% File: l3str-convert.dtx -% -% Copyright (C) 2013-2019 The LaTeX3 Project -% -% It may be distributed and/or modified under the conditions of the -% LaTeX Project Public License (LPPL), either version 1.3c of this -% license or (at your option) any later version. The latest version -% of this license is in the file -% -% https://www.latex-project.org/lppl.txt -% -% This file is part of the "l3experimental bundle" (The Work in LPPL) -% and all files in that bundle must be distributed together. -% -% ----------------------------------------------------------------------- -% -% The development version of the bundle can be found at -% -% https://github.com/latex3/latex3 -% -% for those people who are interested. -% -%<*driver|package> -\RequirePackage{expl3} -% -%<*driver> -\documentclass[full]{l3doc} -\usepackage{amsmath} -\begin{document} - \DocInput{\jobname.dtx} -\end{document} -% -% \fi -% -% -% \title{^^A -% The \textsf{l3str-convert} package: string encoding conversions^^A -% } -% -% \author{^^A -% The \LaTeX3 Project\thanks -% {^^A -% E-mail: -% \href{mailto:latex-team@latex-project.org} -% {latex-team@latex-project.org}^^A -% }^^A -% } -% -% \date{Released 2019-05-28} -% -% \maketitle -% -% \newcommand{\hexnum}[1]{\text{\texttt{\char`\"}#1}} -% \begin{documentation} -% -% \section{Encoding and escaping schemes} -% -% Traditionally, string encodings only specify how strings of characters -% should be stored as bytes. However, the resulting lists of bytes are -% often to be used in contexts where only a restricted subset of bytes -% are permitted (\emph{e.g.}, \textsc{pdf} string objects, -% \textsc{url}s). Hence, storing a string of characters is done in two -% steps. -% \begin{itemize} -% \item The code points (\enquote{character codes}) are expressed as -% bytes following a given \enquote{encoding}. This can be -% \textsc{utf-16}, \textsc{iso 8859-1}, \emph{etc.} See -% Table~\ref{tab:encodings} for a list of supported -% encodings.\footnote{Encodings and escapings will be added as they -% are requested.} -% \item Bytes are translated to \TeX{} tokens through a given -% \enquote{escaping}. Those are defined for the most part by the -% \texttt{pdf} file format. See Table~\ref{tab:escapings} for a -% list of escaping methods supported.\footnotemark -% \end{itemize} -% -% \begin{table}\centering -% \caption{\label{tab:encodings}Supported encodings. -% Non-alphanumeric characters are ignored, -% and capital letters are lower-cased -% before searching for the encoding in this list.} -% \begin{tabular}{cc} -% \toprule -% \meta{Encoding} & description \\ -% \midrule -% \texttt{utf8} & \textsc{utf-8} \\ -% \texttt{utf16} & \textsc{utf-16}, with byte-order mark \\ -% \texttt{utf16be} & \textsc{utf-16}, big-endian \\ -% \texttt{utf16le} & \textsc{utf-16}, little-endian \\ -% \texttt{utf32} & \textsc{utf-32}, with byte-order mark \\ -% \texttt{utf32be} & \textsc{utf-32}, big-endian \\ -% \texttt{utf32le} & \textsc{utf-32}, little-endian \\ -% \midrule -% \texttt{iso88591}, \texttt{latin1} & \textsc{iso 8859-1} \\ -% \texttt{iso88592}, \texttt{latin2} & \textsc{iso 8859-2} \\ -% \texttt{iso88593}, \texttt{latin3} & \textsc{iso 8859-3} \\ -% \texttt{iso88594}, \texttt{latin4} & \textsc{iso 8859-4} \\ -% \texttt{iso88595} & \textsc{iso 8859-5} \\ -% \texttt{iso88596} & \textsc{iso 8859-6} \\ -% \texttt{iso88597} & \textsc{iso 8859-7} \\ -% \texttt{iso88598} & \textsc{iso 8859-8} \\ -% \texttt{iso88599}, \texttt{latin5} & \textsc{iso 8859-9} \\ -% \texttt{iso885910}, \texttt{latin6} & \textsc{iso 8859-10} \\ -% \texttt{iso885911} & \textsc{iso 8859-11} \\ -% \texttt{iso885913}, \texttt{latin7} & \textsc{iso 8859-13} \\ -% \texttt{iso885914}, \texttt{latin8} & \textsc{iso 8859-14} \\ -% \texttt{iso885915}, \texttt{latin9} & \textsc{iso 8859-15} \\ -% \texttt{iso885916}, \texttt{latin10} & \textsc{iso 8859-16} \\ -% \midrule -% \texttt{clist} & comma-list of integers \\ -% \meta{empty} & native (Unicode) string \\ -% \bottomrule -% \end{tabular} -% \end{table} -% -% \begin{table}\centering -% \caption{\label{tab:escapings}Supported escapings. -% Non-alphanumeric characters are ignored, -% and capital letters are lower-cased -% before searching for the escaping in this list.} -% \begin{tabular}{cc} -% \toprule -% \meta{Escaping} & description \\ -% \midrule -% \texttt{bytes}, or empty -% & arbitrary bytes \\ -% \texttt{hex}, \texttt{hexadecimal} -% & byte $=$ two hexadecimal digits \\ -% \texttt{name} -% & see \tn{pdfescapename} \\ -% \texttt{string} -% & see \tn{pdfescapestring} \\ -% \texttt{url} -% & encoding used in \textsc{url}s \\ -% \bottomrule -% \end{tabular} -% \end{table} -% -% \section{Conversion functions} -% -% \begin{function}{\str_set_convert:Nnnn, \str_gset_convert:Nnnn} -% \begin{syntax} -% \cs{str_set_convert:Nnnn} \meta{str~var} \Arg{string} \Arg{name~1} \Arg{name~2} -% \end{syntax} -% This function converts the \meta{string} from the encoding given by -% \meta{name~1} to the encoding given by \meta{name~2}, and stores the -% result in the \meta{str~var}. Each \meta{name} can have the form -% \meta{encoding} or \meta{encoding}\texttt{/}\meta{escaping}, where -% the possible values of \meta{encoding} and \meta{escaping} are given -% in Tables~\ref{tab:encodings} and~\ref{tab:escapings}, respectively. -% The default escaping is to input and output bytes directly. The -% special case of an empty \meta{name} indicates the use of -% \enquote{native} strings, 8-bit for \pdfTeX{}, and Unicode strings -% for the other two engines. -% -% For example, -% \begin{verbatim} -% \str_set_convert:Nnnn \l_foo_str { Hello! } { } { utf16/hex } -% \end{verbatim} -% results in the variable \cs{l_foo_str} holding the string -% \texttt{FEFF00480065006C006C006F0021}. This is obtained by -% converting each character in the (native) string \texttt{Hello!} to -% the \textsc{utf-16} encoding, and expressing each byte as a pair of -% hexadecimal digits. Note the presence of a (big-endian) byte order -% mark \hexnum{FEFF}, which can be avoided by specifying the encoding -% \texttt{utf16be/hex}. -% -% An error is raised if the \meta{string} is not valid according to -% the \meta{escaping~1} and \meta{encoding~1}, or if it cannot be -% reencoded in the \meta{encoding~2} and \meta{escaping~2} (for -% instance, if a character does not exist in the \meta{encoding~2}). -% Erroneous input is replaced by the Unicode replacement character -% \hexnum{FFFD}, and characters which cannot be reencoded are replaced -% by either the replacement character \hexnum{FFFD} if it exists in -% the \meta{encoding~2}, or an encoding-specific replacement -% character, or the question mark character. -% \end{function} -% -% \begin{function}[TF]{\str_set_convert:Nnnn, \str_gset_convert:Nnnn} -% \begin{syntax} -% \cs{str_set_convert:NnnnTF} \meta{str~var} \Arg{string} \Arg{name~1} \Arg{name~2} \Arg{true code} \Arg{false code} -% \end{syntax} -% As \cs{str_set_convert:Nnnn}, converts the \meta{string} from the -% encoding given by \meta{name~1} to the encoding given by -% \meta{name~2}, and assigns the result to \meta{str~var}. Contrarily -% to \cs{str_set_convert:Nnnn}, the conditional variant does not raise -% errors in case the \meta{string} is not valid according to the -% \meta{name~1} encoding, or cannot be expressed in the \meta{name~2} -% encoding. Instead, the \meta{false code} is performed. -% \end{function} -% -% \section{Possibilities, and things to do} -% -% Encoding/escaping-related tasks. -% \begin{itemize} -% \item In \XeTeX{}/\LuaTeX{}, would it be better to use the -% |^^^^....| approach to build a string from a given list of -% character codes? Namely, within a group, assign |0-9a-f| and all -% characters we want to category ``other'', then assign~|^| the -% category superscript, and use \tn{scantokens}. -% \item Change \cs{str_set_convert:Nnnn} to expand its last two -% arguments. -% \item Describe the internal format in the code comments. Refuse code -% points in $[\hexnum{D800}, \hexnum{DFFF}]$ in the internal -% representation? -% \item Add documentation about each encoding and escaping method, and -% add examples. -% \item The \texttt{hex} unescaping should raise an error for -% odd-token count strings. -% \item Decide what bytes should be escaped in the \texttt{url} -% escaping. Perhaps |!'()*-./0123456789_| are safe, and all other -% characters should be escaped? -% \item Automate generation of 8-bit mapping files. -% \item Change the framework for 8-bit encodings: for decoding from -% 8-bit to Unicode, use $256$ integer registers; for encoding, use a -% tree-box. -% \item More encodings (see Heiko's \pkg{stringenc}). CESU? -% \item More escapings: \textsc{ascii85}, shell escapes, lua escapes, -% \emph{etc.}? -% \end{itemize} -% -% \end{documentation} -% -% \begin{implementation} -% -% \section{\pkg{l3str} implementation} -% -% \begin{macrocode} -%<*initex|package> -% \end{macrocode} -% -% \begin{macrocode} -%<@@=str> -% \end{macrocode} -% -% \begin{macrocode} -\ProvidesExplPackage{l3str-convert}{2019-05-28}{} - {L3 Experimental string encoding conversions} -% \end{macrocode} -% -% \subsection{Helpers} -% -% \subsubsection{A function unrelated to strings} -% -% \begin{macro}[EXP]{\use_ii_i:nn} -% A function used to swap its arguments. -% \begin{macrocode} -\cs_if_exist:NF \use_ii_i:nn - { \cs_new:Npn \use_ii_i:nn #1#2 { #2 #1 } } -% \end{macrocode} -% \end{macro} -% -% \subsubsection{Variables and constants} -% -% \begin{macro}{\@@_tmp:w} -% \begin{variable}{\l_@@_internal_int} -% \begin{variable}{\l_@@_internal_tl} -% Internal scratch space for some functions. -% \begin{macrocode} -\cs_new_protected:Npn \@@_tmp:w { } -\tl_new:N \l_@@_internal_tl -\int_new:N \l_@@_internal_int -% \end{macrocode} -% \end{variable} -% \end{variable} -% \end{macro} -% -% \begin{variable}{\g_@@_result_tl} -% The \cs{g_@@_result_tl} variable is used to hold the result of -% various internal string operations (mostly conversions) which are -% typically performed in a group. The variable is global so that it -% remains defined outside the group, to be assigned to a user-provided -% variable. -% \begin{macrocode} -\tl_new:N \g_@@_result_tl -% \end{macrocode} -% \end{variable} -% -% \begin{variable}{\c_@@_replacement_char_int} -% When converting, invalid bytes are replaced by the Unicode -% replacement character \hexnum{FFFD}. -% \begin{macrocode} -\int_const:Nn \c_@@_replacement_char_int { "FFFD } -% \end{macrocode} -% \end{variable} -% -% \begin{variable}{\c_@@_max_byte_int} -% The maximal byte number. -% \begin{macrocode} -\int_const:Nn \c_@@_max_byte_int { 255 } -% \end{macrocode} -% \end{variable} -% -% \begin{variable}{\g_@@_alias_prop} -% To avoid needing one file per encoding/escaping alias, we keep track -% of those in a property list. -% \begin{macrocode} -\prop_new:N \g_@@_alias_prop -\prop_gput:Nnn \g_@@_alias_prop { latin1 } { iso88591 } -\prop_gput:Nnn \g_@@_alias_prop { latin2 } { iso88592 } -\prop_gput:Nnn \g_@@_alias_prop { latin3 } { iso88593 } -\prop_gput:Nnn \g_@@_alias_prop { latin4 } { iso88594 } -\prop_gput:Nnn \g_@@_alias_prop { latin5 } { iso88599 } -\prop_gput:Nnn \g_@@_alias_prop { latin6 } { iso885910 } -\prop_gput:Nnn \g_@@_alias_prop { latin7 } { iso885913 } -\prop_gput:Nnn \g_@@_alias_prop { latin8 } { iso885914 } -\prop_gput:Nnn \g_@@_alias_prop { latin9 } { iso885915 } -\prop_gput:Nnn \g_@@_alias_prop { latin10 } { iso885916 } -\prop_gput:Nnn \g_@@_alias_prop { utf16le } { utf16 } -\prop_gput:Nnn \g_@@_alias_prop { utf16be } { utf16 } -\prop_gput:Nnn \g_@@_alias_prop { utf32le } { utf32 } -\prop_gput:Nnn \g_@@_alias_prop { utf32be } { utf32 } -\prop_gput:Nnn \g_@@_alias_prop { hexadecimal } { hex } -% \end{macrocode} -% \end{variable} -% -% \begin{variable}{\g_@@_error_bool} -% In conversion functions with a built-in conditional, errors are not -% reported directly to the user, but the information is collected in -% this boolean, used at the end to decide on which branch of the -% conditional to take. -% \begin{macrocode} -\bool_new:N \g_@@_error_bool -% \end{macrocode} -% \end{variable} -% -% \begin{variable}{str_byte, str_error} -% Conversions from one \meta{encoding}/\meta{escaping} pair to another -% are done within \texttt{x}-expanding assignments. Errors are -% signalled by raising the relevant flag. -% \begin{macrocode} -\flag_new:n { str_byte } -\flag_new:n { str_error } -% \end{macrocode} -% \end{variable} -% -% \subsection{String conditionals} -% -% \begin{macro}[EXP]{\@@_if_contains_char:NNT, \@@_if_contains_char:NNTF} -% \begin{macro}[EXP]{\@@_if_contains_char:nNTF} -% \begin{macro}[EXP]{\@@_if_contains_char_aux:NN} -% \begin{macro}[EXP]{\@@_if_contains_char_true:} -% \begin{syntax} -% \cs{@@_if_contains_char:nNTF} \Arg{token list} \meta{char} -% \end{syntax} -% Expects the \meta{token list} to be an \meta{other string}: the -% caller is responsible for ensuring that no (too-)special catcodes -% remain. Spaces with catcode $10$ are ignored. -% Loop over the characters of the string, comparing character codes. -% The loop is broken if character codes match. Otherwise we return -% \enquote{false}. -% \begin{macrocode} -\prg_new_conditional:Npnn \@@_if_contains_char:NN #1#2 { T , TF } - { - \exp_after:wN \@@_if_contains_char_aux:NN \exp_after:wN #2 - #1 { \prg_break:n { ? \fi: } } - \prg_break_point: - \prg_return_false: - } -\prg_new_conditional:Npnn \@@_if_contains_char:nN #1#2 { TF } - { - \@@_if_contains_char_aux:NN #2 #1 { \prg_break:n { ? \fi: } } - \prg_break_point: - \prg_return_false: - } -\cs_new:Npn \@@_if_contains_char_aux:NN #1#2 - { - \if_charcode:w #1 #2 - \exp_after:wN \@@_if_contains_char_true: - \fi: - \@@_if_contains_char_aux:NN #1 - } -\cs_new:Npn \@@_if_contains_char_true: - { \prg_break:n { \prg_return_true: \use_none:n } } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}[rEXP]{\@@_octal_use:NTF} -% \begin{syntax} -% \cs{@@_octal_use:NTF} \meta{token} \Arg{true code} \Arg{false code} -% \end{syntax} -% If the \meta{token} is an octal digit, it is left in the input -% stream, \emph{followed} by the \meta{true code}. Otherwise, the -% \meta{false code} is left in the input stream. -% \begin{texnote} -% This function will fail if the escape character is an octal -% digit. We are thus careful to set the escape character to a known -% value before using it. -% \end{texnote} -% \TeX{} dutifully detects octal digits for us: if |#1| is an octal -% digit, then the right-hand side of the comparison is |'1#1|, greater -% than $1$. Otherwise, the right-hand side stops as |'1|, and the -% conditional takes the \texttt{false} branch. -% \begin{macrocode} -\prg_new_conditional:Npnn \@@_octal_use:N #1 { TF } - { - \if_int_compare:w 1 < '1 \token_to_str:N #1 \exp_stop_f: - #1 \prg_return_true: - \else: - \prg_return_false: - \fi: - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[rEXP]{\@@_hexadecimal_use:NTF} -% \TeX{} detects uppercase hexadecimal digits for us (see -% \cs{@@_octal_use:NTF}), but not the lowercase letters, which we -% need to detect and replace by their uppercase counterpart. -% \begin{macrocode} -\prg_new_conditional:Npnn \@@_hexadecimal_use:N #1 { TF } - { - \if_int_compare:w 1 < "1 \token_to_str:N #1 \exp_stop_f: - #1 \prg_return_true: - \else: - \if_case:w \int_eval:n { \exp_after:wN ` \token_to_str:N #1 - `a } - A - \or: B - \or: C - \or: D - \or: E - \or: F - \else: - \prg_return_false: - \exp_after:wN \use_none:n - \fi: - \prg_return_true: - \fi: - } -% \end{macrocode} -% \end{macro} -% -% \subsection{Conversions} -% -% \subsubsection{Producing one byte or character} -% -% \begin{variable}{\c_@@_byte_0_tl, \c_@@_byte_1_tl, \c_@@_byte_255_tl} -% \begin{variable}{\c_@@_byte_-1_tl} -% For each integer $N$ in the range $[0,255]$, we create a constant -% token list which holds three character tokens with category code -% other: the character with character code $N$, followed by the -% representation of $N$ as two hexadecimal digits. The value $-1$ is -% given a default token list which ensures that later functions give -% an empty result for the input $-1$. -% \begin{macrocode} -\group_begin: - \tl_set:Nx \l_@@_internal_tl { \tl_to_str:n { 0123456789ABCDEF } } - \tl_map_inline:Nn \l_@@_internal_tl - { - \tl_map_inline:Nn \l_@@_internal_tl - { - \tl_const:cx { c_@@_byte_ \int_eval:n {"#1##1} _tl } - { \char_generate:nn { "#1##1 } { 12 } #1 ##1 } - } - } -\group_end: -\tl_const:cn { c_@@_byte_-1_tl } { { } \use_none:n { } } -% \end{macrocode} -% \end{variable} -% \end{variable} -% -% \begin{macro}[EXP]{\@@_output_byte:n} -% \begin{macro}[EXP]{\@@_output_byte:w} -% \begin{macro}[EXP]{\@@_output_hexadecimal:n} -% \begin{macro}[EXP]{\@@_output_end:} -% Those functions must be used carefully: feeding them a value outside -% the range $[-1,255]$ will attempt to use the undefined token list -% variable \cs{c_@@_byte_\meta{number}_tl}. Assuming that the -% argument is in the right range, we expand the corresponding token -% list, and pick either the byte (first token) or the hexadecimal -% representations (second and third tokens). The value $-1$ produces -% an empty result in both cases. -% \begin{macrocode} -\cs_new:Npn \@@_output_byte:n #1 - { \@@_output_byte:w #1 \@@_output_end: } -\cs_new:Npn \@@_output_byte:w - { - \exp_after:wN \exp_after:wN - \exp_after:wN \use_i:nnn - \cs:w c_@@_byte_ \int_eval:w - } -\cs_new:Npn \@@_output_hexadecimal:n #1 - { - \exp_after:wN \exp_after:wN - \exp_after:wN \use_none:n - \cs:w c_@@_byte_ \int_eval:n {#1} _tl \cs_end: - } -\cs_new:Npn \@@_output_end: - { \scan_stop: _tl \cs_end: } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}[rEXP]{\@@_output_byte_pair_be:n} -% \begin{macro}[rEXP]{\@@_output_byte_pair_le:n} -% \begin{macro}[rEXP]{\@@_output_byte_pair:nnN} -% Convert a number in the range $[0,65535]$ to a pair of bytes, either -% big-endian or little-endian. -% \begin{macrocode} -\cs_new:Npn \@@_output_byte_pair_be:n #1 - { - \exp_args:Nf \@@_output_byte_pair:nnN - { \int_div_truncate:nn { #1 } { "100 } } {#1} \use:nn - } -\cs_new:Npn \@@_output_byte_pair_le:n #1 - { - \exp_args:Nf \@@_output_byte_pair:nnN - { \int_div_truncate:nn { #1 } { "100 } } {#1} \use_ii_i:nn - } -\cs_new:Npn \@@_output_byte_pair:nnN #1#2#3 - { - #3 - { \@@_output_byte:n { #1 } } - { \@@_output_byte:n { #2 - #1 * "100 } } - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \subsubsection{Mapping functions for conversions} -% -% \begin{macro}{\@@_convert_gmap:N} -% \begin{macro}[rEXP]{\@@_convert_gmap_loop:NN} -% This maps the function |#1| over all characters in -% \cs{g_@@_result_tl}, which should be a byte string in most cases, -% sometimes a native string. -% \begin{macrocode} -\cs_new_protected:Npn \@@_convert_gmap:N #1 - { - \tl_gset:Nx \g_@@_result_tl - { - \exp_after:wN \@@_convert_gmap_loop:NN - \exp_after:wN #1 - \g_@@_result_tl { ? \prg_break: } - \prg_break_point: - } - } -\cs_new:Npn \@@_convert_gmap_loop:NN #1#2 - { - \use_none:n #2 - #1#2 - \@@_convert_gmap_loop:NN #1 - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\@@_convert_gmap_internal:N} -% \begin{macro}[rEXP]{\@@_convert_gmap_internal_loop:Nw} -% This maps the function |#1| over all character codes in -% \cs{g_@@_result_tl}, which must be in the internal representation. -% \begin{macrocode} -\cs_new_protected:Npn \@@_convert_gmap_internal:N #1 - { - \tl_gset:Nx \g_@@_result_tl - { - \exp_after:wN \@@_convert_gmap_internal_loop:Nww - \exp_after:wN #1 - \g_@@_result_tl \s__tl \q_stop \prg_break: \s__tl - \prg_break_point: - } - } -\cs_new:Npn \@@_convert_gmap_internal_loop:Nww #1 #2 \s__tl #3 \s__tl - { - \use_none_delimit_by_q_stop:w #3 \q_stop - #1 {#3} - \@@_convert_gmap_internal_loop:Nww #1 - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \subsubsection{Error-reporting during conversion} -% -% \begin{macro}{\@@_if_flag_error:nnx} -% \begin{macro}{\@@_if_flag_no_error:nnx} -% When converting using the function \cs{str_set_convert:Nnnn}, errors -% should be reported to the user after each step in the -% conversion. Errors are signalled by raising some flag (typically -% \texttt{@@_error}), so here we test that flag: if it is raised, -% give the user an error, otherwise remove the arguments. On the other -% hand, in the conditional functions \cs{str_set_convert:NnnnTF}, -% errors should be suppressed. This is done by changing -% \cs{@@_if_flag_error:nnx} into \cs{@@_if_flag_no_error:nnx} -% locally. -% \begin{macrocode} -\cs_new_protected:Npn \@@_if_flag_error:nnx #1 - { - \flag_if_raised:nTF {#1} - { \__kernel_msg_error:nnx { str } } - { \use_none:nn } - } -\cs_new_protected:Npn \@@_if_flag_no_error:nnx #1#2#3 - { \flag_if_raised:nT {#1} { \bool_gset_true:N \g_@@_error_bool } } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}[rEXP]{\@@_if_flag_times:nT} -% At the end of each conversion step, we raise all relevant errors as -% one error message, built on the fly. The height of each flag -% indicates how many times a given error was encountered. This -% function prints |#2| followed by the number of occurrences of an -% error if it occurred, nothing otherwise. -% \begin{macrocode} -\cs_new:Npn \@@_if_flag_times:nT #1#2 - { \flag_if_raised:nT {#1} { #2~(x \flag_height:n {#1} ) } } -% \end{macrocode} -% \end{macro} -% -% \subsubsection{Framework for conversions} -% -% Most functions in this module expect to be working with -% \enquote{native} strings. Strings can also be stored as bytes, in one -% of many encodings, for instance \textsc{utf8}. The bytes themselves -% can be expressed in various ways in terms of \TeX{} tokens, for -% instance as pairs of hexadecimal digits. The questions of going from -% arbitrary Unicode code points to bytes, and from bytes to tokens are -% mostly independent. -% -% Conversions are done in four steps: -% \begin{itemize} -% \item \enquote{unescape} produces a string of bytes; -% \item \enquote{decode} takes in a string of bytes, and converts it -% to a list of Unicode characters in an internal representation, -% with items of the form -% \begin{quote} -% \meta{bytes} \cs{s__tl} \meta{Unicode code point} \cs{s__tl} -% \end{quote} -% where we have collected the \meta{bytes} which combined to form -% this particular Unicode character, and the \meta{Unicode code -% point} is in the range $[0,\hexnum{10FFFF}]$. -% \item \enquote{encode} encodes the internal list of code points as a -% byte string in the new encoding; -% \item \enquote{escape} escapes bytes as requested. -% \end{itemize} -% The process is modified in case one of the encoding is empty (or the -% conversion function has been set equal to the empty encoding because -% it was not found): then the unescape or escape step is ignored, and -% the decode or encode steps work on tokens instead of bytes. Otherwise, -% each step must ensure that it passes a correct byte string or internal -% string to the next step. -% -% \begin{macro}{\str_set_convert:Nnnn, \str_gset_convert:Nnnn} -% \begin{macro}[TF]{\str_set_convert:Nnnn, \str_gset_convert:Nnnn} -% \begin{macro}{\@@_convert:nNNnnn} -% The input string is stored in \cs{g_@@_result_tl}, then we: -% unescape and decode; encode and escape; exit the group and store the -% result in the user's variable. The various conversion functions all -% act on \cs{g_@@_result_tl}. Errors are silenced for the conditional -% functions by redefining \cs{@@_if_flag_error:nnx} locally. -% \begin{macrocode} -\cs_new_protected:Npn \str_set_convert:Nnnn - { \@@_convert:nNNnnn { } \tl_set_eq:NN } -\cs_new_protected:Npn \str_gset_convert:Nnnn - { \@@_convert:nNNnnn { } \tl_gset_eq:NN } -\prg_new_protected_conditional:Npnn - \str_set_convert:Nnnn #1#2#3#4 { T , F , TF } - { - \bool_gset_false:N \g_@@_error_bool - \@@_convert:nNNnnn - { \cs_set_eq:NN \@@_if_flag_error:nnx \@@_if_flag_no_error:nnx } - \tl_set_eq:NN #1 {#2} {#3} {#4} - \bool_if:NTF \g_@@_error_bool \prg_return_false: \prg_return_true: - } -\prg_new_protected_conditional:Npnn - \str_gset_convert:Nnnn #1#2#3#4 { T , F , TF } - { - \bool_gset_false:N \g_@@_error_bool - \@@_convert:nNNnnn - { \cs_set_eq:NN \@@_if_flag_error:nnx \@@_if_flag_no_error:nnx } - \tl_gset_eq:NN #1 {#2} {#3} {#4} - \bool_if:NTF \g_@@_error_bool \prg_return_false: \prg_return_true: - } -\cs_new_protected:Npn \@@_convert:nNNnnn #1#2#3#4#5#6 - { - \group_begin: - #1 - \tl_gset:Nx \g_@@_result_tl { \__kernel_str_to_other_fast:n {#4} } - \exp_after:wN \@@_convert:wwwnn - \tl_to_str:n {#5} /// \q_stop - { decode } { unescape } - \prg_do_nothing: - \@@_convert_decode_: - \exp_after:wN \@@_convert:wwwnn - \tl_to_str:n {#6} /// \q_stop - { encode } { escape } - \use_ii_i:nn - \@@_convert_encode_: - \group_end: - #2 #3 \g_@@_result_tl - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\@@_convert:wwwnn} -% \begin{macro}{\@@_convert:NNnNN} -% The task of \cs{@@_convert:wwwnn} is to split -% \meta{encoding}/\meta{escaping} pairs into their components, |#1| -% and |#2|. Calls to \cs{@@_convert:nnn} ensure that the -% corresponding conversion functions are defined. The third auxiliary -% does the main work. -% \begin{itemize} -% \item |#1| is the encoding conversion function; -% \item |#2| is the escaping function; -% \item |#3| is the escaping name for use in an error message; -% \item |#4| is \cs{prg_do_nothing:} for unescaping/decoding, and -% \cs{use_ii_i:nn} for encoding/escaping; -% \item |#5| is the default encoding function (either -% \enquote{decode} or \enquote{encode}), for which there should be -% no escaping. -% \end{itemize} -% Let us ignore the native encoding for a second. In the -% unescaping/decoding phase, we want to do |#2#1| in this order, and -% in the encoding/escaping phase, the order should be reversed: -% |#4#2#1| does exactly that. If one of the encodings is the default -% (native), then the escaping should be ignored, with an error if any -% was given, and only the encoding, |#1|, should be performed. -% \begin{macrocode} -\cs_new_protected:Npn \@@_convert:wwwnn - #1 / #2 // #3 \q_stop #4#5 - { - \@@_convert:nnn {enc} {#4} {#1} - \@@_convert:nnn {esc} {#5} {#2} - \exp_args:Ncc \@@_convert:NNnNN - { @@_convert_#4_#1: } { @@_convert_#5_#2: } {#2} - } -\cs_new_protected:Npn \@@_convert:NNnNN #1#2#3#4#5 - { - \if_meaning:w #1 #5 - \tl_if_empty:nF {#3} - { \__kernel_msg_error:nnx { str } { native-escaping } {#3} } - #1 - \else: - #4 #2 #1 - \fi: - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\@@_convert:nnn} -% \begin{macro}{\@@_convert:nnnn} -% The arguments of \cs{@@_convert:nnn} are: \texttt{enc} or -% \texttt{esc}, used to build filenames, the type of the conversion -% (unescape, decode, encode, escape), and the encoding or escaping -% name. If the function is already defined, no need to do anything. -% Otherwise, filter out all non-alphanumerics in the name, and -% lowercase it. Feed that, and the same three arguments, to -% \cs{@@_convert:nnnn}. The task is then to make sure that the -% conversion function |#3_#1| corresponding to the type |#3| and -% filtered name |#1| is defined, then set our initial conversion -% function |#3_#4| equal to that. -% -% How do we get the |#3_#1| conversion to be defined if it isn't? -% Two main cases. -% -% First, if |#1| is a key in \cs{g_@@_alias_prop}, then the value -% \cs{l_@@_internal_tl} tells us what file to load. Loading is -% skipped if the file was already read, \emph{i.e.}, if the conversion -% command based on \cs{l_@@_internal_tl} already exists. Otherwise, -% try to load the file; if that fails, there is an error, use the -% default empty name instead. -% -% Second, |#1| may be absent from the property list. The -% \cs{cs_if_exist:cF} test is automatically false, and we search for a -% file defining the encoding or escaping |#1| (this should allow -% third-party \texttt{.def} files). If the file is not found, there is -% an error, use the default empty name instead. -% -% In all cases, the conversion based on \cs{l_@@_internal_tl} is -% defined, so we can set the |#3_#1| function equal to that. In some -% cases (\emph{e.g.}, \texttt{utf16be}), the |#3_#1| function is -% actually defined within the file we just loaded, and it is different -% from the \cs{l_@@_internal_tl}-based function: we mustn't clobber -% that different definition. -% \begin{macrocode} -\cs_new_protected:Npn \@@_convert:nnn #1#2#3 - { - \cs_if_exist:cF { @@_convert_#2_#3: } - { - \exp_args:Nx \@@_convert:nnnn - { \@@_convert_lowercase_alphanum:n {#3} } - {#1} {#2} {#3} - } - } -\cs_new_protected:Npn \@@_convert:nnnn #1#2#3#4 - { - \cs_if_exist:cF { @@_convert_#3_#1: } - { - \prop_get:NnNF \g_@@_alias_prop {#1} \l_@@_internal_tl - { \tl_set:Nn \l_@@_internal_tl {#1} } - \cs_if_exist:cF { @@_convert_#3_ \l_@@_internal_tl : } - { - \file_if_exist:nTF { l3str-#2- \l_@@_internal_tl .def } - { - \group_begin: - \@@_load_catcodes: - \file_input:n { l3str-#2- \l_@@_internal_tl .def } - \group_end: - } - { - \tl_clear:N \l_@@_internal_tl - \__kernel_msg_error:nnxx { str } { unknown-#2 } {#4} {#1} - } - } - \cs_if_exist:cF { @@_convert_#3_#1: } - { - \cs_gset_eq:cc { @@_convert_#3_#1: } - { @@_convert_#3_ \l_@@_internal_tl : } - } - } - \cs_gset_eq:cc { @@_convert_#3_#4: } { @@_convert_#3_#1: } - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}[rEXP]{\@@_convert_lowercase_alphanum:n} -% \begin{macro}[rEXP]{\@@_convert_lowercase_alphanum_loop:N} -% This function keeps only letters and digits, with upper case letters -% converted to lower case. -% \begin{macrocode} -\cs_new:Npn \@@_convert_lowercase_alphanum:n #1 - { - \exp_after:wN \@@_convert_lowercase_alphanum_loop:N - \tl_to_str:n {#1} { ? \prg_break: } - \prg_break_point: - } -\cs_new:Npn \@@_convert_lowercase_alphanum_loop:N #1 - { - \use_none:n #1 - \if_int_compare:w `#1 > `Z \exp_stop_f: - \if_int_compare:w `#1 > `z \exp_stop_f: \else: - \if_int_compare:w `#1 < `a \exp_stop_f: \else: - #1 - \fi: - \fi: - \else: - \if_int_compare:w `#1 < `A \exp_stop_f: - \if_int_compare:w 1 < 1#1 \exp_stop_f: - #1 - \fi: - \else: - \@@_output_byte:n { `#1 + `a - `A } - \fi: - \fi: - \@@_convert_lowercase_alphanum_loop:N - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\@@_load_catcodes:} -% Since encoding files may be loaded at arbitrary places in a \TeX{} -% document, including within verbatim mode, we set the catcodes of all -% characters appearing in any encoding definition file. -% \begin{macrocode} -\cs_new_protected:Npn \@@_load_catcodes: - { - \char_set_catcode_escape:N \\ - \char_set_catcode_group_begin:N \{ - \char_set_catcode_group_end:N \} - \char_set_catcode_math_toggle:N \$ - \char_set_catcode_alignment:N \& - \char_set_catcode_parameter:N \# - \char_set_catcode_math_superscript:N \^ - \char_set_catcode_ignore:N \ % - \char_set_catcode_space:N \~ - \tl_map_function:nN { abcdefghijklmnopqrstuvwxyz_:ABCDEFILNPSTUX } - \char_set_catcode_letter:N - \tl_map_function:nN { 0123456789"'?*+-.(),`!/<>[];= } - \char_set_catcode_other:N - \char_set_catcode_comment:N \% - \int_set:Nn \tex_endlinechar:D {32} - } -% \end{macrocode} -% \end{macro} -% -% \subsubsection{Byte unescape and escape} -% -% Strings of bytes may need to be stored in auxiliary files in safe -% \enquote{escaping} formats. Each such escaping is only loaded as -% needed. By default, on input any non-byte is filtered out, while the -% output simply consists in letting bytes through. -% -% \begin{macro}[rEXP]{\@@_filter_bytes:n} -% \begin{macro}[rEXP]{\@@_filter_bytes_aux:N} -% In the case of 8-bit engines, every character is a byte. For -% Unicode-aware engines, test the character code; non-bytes cause us -% to raise the flag \texttt{str_byte}. Spaces have already been given -% the correct category code when this function is called. -% \begin{macrocode} -\bool_lazy_any:nTF - { - \sys_if_engine_luatex_p: - \sys_if_engine_xetex_p: - } - { - \cs_new:Npn \@@_filter_bytes:n #1 - { - \@@_filter_bytes_aux:N #1 - { ? \prg_break: } - \prg_break_point: - } - \cs_new:Npn \@@_filter_bytes_aux:N #1 - { - \use_none:n #1 - \if_int_compare:w `#1 < 256 \exp_stop_f: - #1 - \else: - \flag_raise:n { str_byte } - \fi: - \@@_filter_bytes_aux:N - } - } - { \cs_new_eq:NN \@@_filter_bytes:n \use:n } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\@@_convert_unescape_:} -% \begin{macro}{\@@_convert_unescape_bytes:} -% The simplest unescaping method removes non-bytes from -% \cs{g_@@_result_tl}. -% \begin{macrocode} -\bool_lazy_any:nTF - { - \sys_if_engine_luatex_p: - \sys_if_engine_xetex_p: - } - { - \cs_new_protected:Npn \@@_convert_unescape_: - { - \flag_clear:n { str_byte } - \tl_gset:Nx \g_@@_result_tl - { \exp_args:No \@@_filter_bytes:n \g_@@_result_tl } - \@@_if_flag_error:nnx { str_byte } { non-byte } { bytes } - } - } - { \cs_new_protected:Npn \@@_convert_unescape_: { } } -\cs_new_eq:NN \@@_convert_unescape_bytes: \@@_convert_unescape_: -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\@@_convert_escape_:} -% \begin{macro}{\@@_convert_escape_bytes:} -% The simplest form of escape leaves the bytes from the previous step -% of the conversion unchanged. -% \begin{macrocode} -\cs_new_protected:Npn \@@_convert_escape_: { } -\cs_new_eq:NN \@@_convert_escape_bytes: \@@_convert_escape_: -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \subsubsection{Native strings} -% -% \begin{macro}{\@@_convert_decode_:} -% \begin{macro}[rEXP]{\@@_decode_native_char:N} -% Convert each character to its character code, one at a time. -% \begin{macrocode} -\cs_new_protected:Npn \@@_convert_decode_: - { \@@_convert_gmap:N \@@_decode_native_char:N } -\cs_new:Npn \@@_decode_native_char:N #1 - { #1 \s__tl \int_value:w `#1 \s__tl } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\@@_convert_encode_:} -% \begin{macro}[EXP]{\@@_encode_native_char:n} -% The conversion from an internal string to native character tokens -% basically maps \cs{char_generate:nn} through the code-points, but in -% non-Unicode-aware engines we use a fall-back character |?| rather -% than nothing when given a character code outside $[0,255]$. We -% detect the presence of bad characters using a flag and only produce -% a single error after the \texttt{x}-expanding assignment. -% \begin{macrocode} -\bool_lazy_any:nTF - { - \sys_if_engine_luatex_p: - \sys_if_engine_xetex_p: - } - { - \cs_new_protected:Npn \@@_convert_encode_: - { \@@_convert_gmap_internal:N \@@_encode_native_char:n } - \cs_new:Npn \@@_encode_native_char:n #1 - { \char_generate:nn {#1} {12} } - } - { - \cs_new_protected:Npn \@@_convert_encode_: - { - \flag_clear:n { str_error } - \@@_convert_gmap_internal:N \@@_encode_native_char:n - \@@_if_flag_error:nnx { str_error } - { native-overflow } { } - } - \cs_new:Npn \@@_encode_native_char:n #1 - { - \if_int_compare:w #1 > \c_@@_max_byte_int - \flag_raise:n { str_error } - ? - \else: - \char_generate:nn {#1} {12} - \fi: - } - \__kernel_msg_new:nnnn { str } { native-overflow } - { Character~code~too~large~for~this~engine. } - { - This~engine~only~support~8-bit~characters:~ - valid~character~codes~are~in~the~range~[0,255].~ - To~manipulate~arbitrary~Unicode,~use~LuaTeX~or~XeTeX. - } - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \subsubsection{\texttt{clist}} -% -% \begin{macro}{\@@_convert_decode_clist:} -% \begin{macro}[rEXP]{\@@_decode_clist_char:n} -% Convert each integer to the internal form. We first turn -% \cs{g_@@_result_tl} into a clist variable, as this avoids problems -% with leading or trailing commas. -% \begin{macrocode} -\cs_new_protected:Npn \@@_convert_decode_clist: - { - \clist_gset:No \g_@@_result_tl \g_@@_result_tl - \tl_gset:Nx \g_@@_result_tl - { - \exp_args:No \clist_map_function:nN - \g_@@_result_tl \@@_decode_clist_char:n - } - } -\cs_new:Npn \@@_decode_clist_char:n #1 - { #1 \s__tl \int_eval:n {#1} \s__tl } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\@@_convert_encode_clist:} -% \begin{macro}[rEXP]{\@@_encode_clist_char:n} -% Convert the internal list of character codes to a comma-list of -% character codes. The first line produces a comma-list with a -% leading comma, removed in the next step (this also works in the -% empty case, since \cs{tl_tail:N} does not trigger an error in this -% case). -% \begin{macrocode} -\cs_new_protected:Npn \@@_convert_encode_clist: - { - \@@_convert_gmap_internal:N \@@_encode_clist_char:n - \tl_gset:Nx \g_@@_result_tl { \tl_tail:N \g_@@_result_tl } - } -\cs_new:Npn \@@_encode_clist_char:n #1 { , #1 } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \subsubsection{8-bit encodings} -% -% This section will be entirely rewritten: it is not yet clear in what -% situations 8-bit encodings are used, hence I don't know what exactly -% should be optimized. The current approach is reasonably efficient to -% convert long strings, and it scales well when using many different -% encodings. An approach based on csnames would have a smaller constant -% load time for each individual conversion, but has a large hash table -% cost. Using a range of \tn{count} registers works for decoding, but -% not for encoding: one possibility there would be to use a binary tree -% for the mapping of Unicode characters to bytes, stored as a box, one -% per encoding. -% -% Since the section is going to be rewritten, documentation lacks. -% -% All the 8-bit encodings which \pkg{l3str} supports rely on the same -% internal functions. -% -% \begin{macro}{\@@_declare_eight_bit_encoding:nnn} -% \begin{syntax} -% \cs{@@_declare_eight_bit_encoding:nnn} \Arg{name} \Arg{mapping} \Arg{missing} -% \end{syntax} -% This declares the encoding \meta{name} to map bytes to Unicode -% characters according to the \meta{mapping}, and map those bytes -% which are not mentioned in the \meta{mapping} either to the -% replacement character (if they appear in \meta{missing}), or to -% themselves. -% -% All the 8-bit encoding definition file start with -% \cs{@@_declare_eight_bit_encoding:nnn} \Arg{encoding name} -% \Arg{mapping} \Arg{missing bytes}. The \meta{mapping} argument is a -% token list of pairs \Arg{byte} \Arg{Unicode} expressed in uppercase -% hexadecimal notation. The \meta{missing} argument is a token list -% of \Arg{byte}. Every \meta{byte} which does not appear in the -% \meta{mapping} nor the \meta{missing} lists maps to the same code -% point in Unicode. -% \begin{macrocode} -\cs_new_protected:Npn \@@_declare_eight_bit_encoding:nnn #1#2#3 - { - \tl_set:Nn \l_@@_internal_tl {#1} - \cs_new_protected:cpn { @@_convert_decode_#1: } - { \@@_convert_decode_eight_bit:n {#1} } - \cs_new_protected:cpn { @@_convert_encode_#1: } - { \@@_convert_encode_eight_bit:n {#1} } - \tl_const:cn { c_@@_encoding_#1_tl } {#2} - \tl_const:cn { c_@@_encoding_#1_missing_tl } {#3} - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\@@_convert_decode_eight_bit:n} -% \begin{macro}{\@@_decode_eight_bit_load:nn} -% \begin{macro}{\@@_decode_eight_bit_load_missing:n} -% \begin{macro}[EXP]{\@@_decode_eight_bit_char:N} -%^^A todo: document -% \begin{macrocode} -\cs_new_protected:Npn \@@_convert_decode_eight_bit:n #1 - { - \group_begin: - \int_zero:N \l_@@_internal_int - \exp_last_unbraced:Nx \@@_decode_eight_bit_load:nn - { \tl_use:c { c_@@_encoding_#1_tl } } - { \q_stop \prg_break: } { } - \prg_break_point: - \exp_last_unbraced:Nx \@@_decode_eight_bit_load_missing:n - { \tl_use:c { c_@@_encoding_#1_missing_tl } } - { \q_stop \prg_break: } - \prg_break_point: - \flag_clear:n { str_error } - \@@_convert_gmap:N \@@_decode_eight_bit_char:N - \@@_if_flag_error:nnx { str_error } { decode-8-bit } {#1} - \group_end: - } -\cs_new_protected:Npn \@@_decode_eight_bit_load:nn #1#2 - { - \use_none_delimit_by_q_stop:w #1 \q_stop - \tex_dimen:D "#1 = \l_@@_internal_int sp \scan_stop: - \tex_skip:D \l_@@_internal_int = "#1 sp \scan_stop: - \tex_toks:D \l_@@_internal_int \exp_after:wN { \int_value:w "#2 } - \int_incr:N \l_@@_internal_int - \@@_decode_eight_bit_load:nn - } -\cs_new_protected:Npn \@@_decode_eight_bit_load_missing:n #1 - { - \use_none_delimit_by_q_stop:w #1 \q_stop - \tex_dimen:D "#1 = \l_@@_internal_int sp \scan_stop: - \tex_skip:D \l_@@_internal_int = "#1 sp \scan_stop: - \tex_toks:D \l_@@_internal_int \exp_after:wN - { \int_use:N \c_@@_replacement_char_int } - \int_incr:N \l_@@_internal_int - \@@_decode_eight_bit_load_missing:n - } -\cs_new:Npn \@@_decode_eight_bit_char:N #1 - { - #1 \s__tl - \if_int_compare:w \tex_dimen:D `#1 < \l_@@_internal_int - \if_int_compare:w \tex_skip:D \tex_dimen:D `#1 = `#1 \exp_stop_f: - \tex_the:D \tex_toks:D \tex_dimen:D - \fi: - \fi: - \int_value:w `#1 \s__tl - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\@@_convert_encode_eight_bit:n} -% \begin{macro}{\@@_encode_eight_bit_load:nn} -% \begin{macro}[rEXP]{\@@_encode_eight_bit_char:n} -% \begin{macro}[rEXP]{\@@_encode_eight_bit_char_aux:n} -%^^A todo: document -% \begin{macrocode} -\cs_new_protected:Npn \@@_convert_encode_eight_bit:n #1 - { - \group_begin: - \int_zero:N \l_@@_internal_int - \exp_last_unbraced:Nx \@@_encode_eight_bit_load:nn - { \tl_use:c { c_@@_encoding_#1_tl } } - { \q_stop \prg_break: } { } - \prg_break_point: - \flag_clear:n { str_error } - \@@_convert_gmap_internal:N \@@_encode_eight_bit_char:n - \@@_if_flag_error:nnx { str_error } { encode-8-bit } {#1} - \group_end: - } -\cs_new_protected:Npn \@@_encode_eight_bit_load:nn #1#2 - { - \use_none_delimit_by_q_stop:w #1 \q_stop - \tex_dimen:D "#2 = \l_@@_internal_int sp \scan_stop: - \tex_skip:D \l_@@_internal_int = "#2 sp \scan_stop: - \exp_args:NNf \tex_toks:D \l_@@_internal_int - { \@@_output_byte:n { "#1 } } - \int_incr:N \l_@@_internal_int - \@@_encode_eight_bit_load:nn - } -\cs_new:Npn \@@_encode_eight_bit_char:n #1 - { - \if_int_compare:w #1 > \c_max_register_int - \flag_raise:n { str_error } - \else: - \if_int_compare:w \tex_dimen:D #1 < \l_@@_internal_int - \if_int_compare:w \tex_skip:D \tex_dimen:D #1 = #1 \exp_stop_f: - \tex_the:D \tex_toks:D \tex_dimen:D #1 \exp_stop_f: - \exp_after:wN \exp_after:wN \exp_after:wN \use_none:nn - \fi: - \fi: - \@@_encode_eight_bit_char_aux:n {#1} - \fi: - } -\cs_new:Npn \@@_encode_eight_bit_char_aux:n #1 - { - \if_int_compare:w #1 > \c_@@_max_byte_int - \flag_raise:n { str_error } - \else: - \@@_output_byte:n {#1} - \fi: - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \subsection{Messages} -% -% General messages, and messages for the encodings and escapings loaded -% by default (\enquote{native}, and \enquote{bytes}). -% \begin{macrocode} -\__kernel_msg_new:nnn { str } { unknown-esc } - { Escaping~scheme~'#1'~(filtered:~'#2')~unknown. } -\__kernel_msg_new:nnn { str } { unknown-enc } - { Encoding~scheme~'#1'~(filtered:~'#2')~unknown. } -\__kernel_msg_new:nnnn { str } { native-escaping } - { The~'native'~encoding~scheme~does~not~support~any~escaping. } - { - Since~native~strings~do~not~consist~in~bytes,~ - none~of~the~escaping~methods~make~sense.~ - The~specified~escaping,~'#1',~will be ignored. - } -\__kernel_msg_new:nnn { str } { file-not-found } - { File~'l3str-#1.def'~not~found. } -% \end{macrocode} -% -% Message used when the \enquote{bytes} unescaping fails because the -% string given to \cs{str_set_convert:Nnnn} contains a non-byte. This -% cannot happen for the -8-bit engines. -% Messages used for other escapings and -% encodings are defined in each definition file. -% \begin{macrocode} -\bool_lazy_any:nT - { - \sys_if_engine_luatex_p: - \sys_if_engine_xetex_p: - } - { - \__kernel_msg_new:nnnn { str } { non-byte } - { String~invalid~in~escaping~'#1':~it~may~only~contain~bytes. } - { - Some~characters~in~the~string~you~asked~to~convert~are~not~ - 8-bit~characters.~Perhaps~the~string~is~a~'native'~Unicode~string?~ - If~it~is,~try~using\\ - \\ - \iow_indent:n - { - \iow_char:N\\str_set_convert:Nnnn \\ - \ \ ~\{~~\}~\{~native~\}~\{~~\} - } - } - } -% \end{macrocode} -% -% Those messages are used when converting to and from 8-bit encodings. -% \begin{macrocode} -\__kernel_msg_new:nnnn { str } { decode-8-bit } - { Invalid~string~in~encoding~'#1'. } - { - LaTeX~came~across~a~byte~which~is~not~defined~to~represent~ - any~character~in~the~encoding~'#1'. - } -\__kernel_msg_new:nnnn { str } { encode-8-bit } - { Unicode~string~cannot~be~converted~to~encoding~'#1'. } - { - The~encoding~'#1'~only~contains~a~subset~of~all~Unicode~characters.~ - LaTeX~was~asked~to~convert~a~string~to~that~encoding,~but~that~ - string~contains~a~character~that~'#1'~does~not~support. - } -% \end{macrocode} -% -% \begin{macrocode} -% -% \end{macrocode} -% -% \subsection{Escaping definition files} -% -% Several of those encodings are defined by the pdf file format. The -% following byte storage methods are defined: -% \begin{itemize} -% \item \texttt{bytes} (default), non-bytes are filtered out, and -% bytes are left untouched (this is defined by default); -% \item \texttt{hex} or \texttt{hexadecimal}, as per the \pdfTeX{} -% primitive \tn{pdfescapehex} -% \item \texttt{name}, as per the \pdfTeX{} primitive -% \tn{pdfescapename} -% \item \texttt{string}, as per the \pdfTeX{} primitive -% \tn{pdfescapestring} -% \item \texttt{url}, as per the percent encoding of urls. -% \end{itemize} -% -% \subsubsection{Unescape methods} -% -% \begin{macro}{\@@_convert_unescape_hex:} -% \begin{macro}[rEXP]{\@@_unescape_hex_auxi:N} -% \begin{macro}[rEXP]{\@@_unescape_hex_auxii:N} -% Take chars two by two, and interpret each pair as the hexadecimal -% code for a byte. Anything else than hexadecimal digits is ignored, -% raising the flag. A string which contains an odd number of -% hexadecimal digits gets |0| appended to it: this is equivalent to -% appending a |0| in all cases, and dropping it if it is alone. -% \begin{macrocode} -%<*hex> -\cs_new_protected:Npn \@@_convert_unescape_hex: - { - \group_begin: - \flag_clear:n { str_error } - \int_set:Nn \tex_escapechar:D { 92 } - \tl_gset:Nx \g_@@_result_tl - { - \@@_output_byte:w " - \exp_last_unbraced:Nf \@@_unescape_hex_auxi:N - { \tl_to_str:N \g_@@_result_tl } - 0 { ? 0 - 1 \prg_break: } - \prg_break_point: - \@@_output_end: - } - \@@_if_flag_error:nnx { str_error } { unescape-hex } { } - \group_end: - } -\cs_new:Npn \@@_unescape_hex_auxi:N #1 - { - \use_none:n #1 - \@@_hexadecimal_use:NTF #1 - { \@@_unescape_hex_auxii:N } - { - \flag_raise:n { str_error } - \@@_unescape_hex_auxi:N - } - } -\cs_new:Npn \@@_unescape_hex_auxii:N #1 - { - \use_none:n #1 - \@@_hexadecimal_use:NTF #1 - { - \@@_output_end: - \@@_output_byte:w " \@@_unescape_hex_auxi:N - } - { - \flag_raise:n { str_error } - \@@_unescape_hex_auxii:N - } - } -\__kernel_msg_new:nnnn { str } { unescape-hex } - { String~invalid~in~escaping~'hex':~only~hexadecimal~digits~allowed. } - { - Some~characters~in~the~string~you~asked~to~convert~are~not~ - hexadecimal~digits~(0-9,~A-F,~a-f)~nor~spaces. - } -% -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\@@_convert_unescape_name:} -% \begin{macro}[rEXP]{\@@_unescape_name_loop:wNN} -% \begin{macro}{\@@_convert_unescape_url:} -% \begin{macro}[rEXP]{\@@_unescape_url_loop:wNN} -% The \cs{@@_convert_unescape_name:} function replaces each -% occurrence of |#| followed by two hexadecimal digits in -% \cs{g_@@_result_tl} by the corresponding byte. The \texttt{url} -% function is identical, with escape character |%| instead of |#|. -% Thus we define the two together. The arguments of \cs{@@_tmp:w} are -% the character code of |#| or |%| in hexadecimal, the name of the -% main function to define, and the name of the auxiliary which -% performs the loop. -% -% The looping auxiliary |#3| finds the next escape character, reads -% the following two characters, and tests them. The test -% \cs{@@_hexadecimal_use:NTF} leaves the upper-case digit in the -% input stream, hence we surround the test with -% \cs{@@_output_byte:w}~|"| and \cs{@@_output_end:}. If both -% characters are hexadecimal digits, they should be removed before -% looping: this is done by \cs{use_i:nnn}. If one of the characters -% is not a hexadecimal digit, then feed |"#1| to -% \cs{@@_output_byte:w} to produce the escape character, raise the -% flag, and call the looping function followed by the two characters -% (remove \cs{use_i:nnn}). -% \begin{macrocode} -%<*name|url> -\cs_set_protected:Npn \@@_tmp:w #1#2#3 - { - \cs_new_protected:cpn { @@_convert_unescape_#2: } - { - \group_begin: - \flag_clear:n { str_byte } - \flag_clear:n { str_error } - \int_set:Nn \tex_escapechar:D { 92 } - \tl_gset:Nx \g_@@_result_tl - { - \exp_after:wN #3 \g_@@_result_tl - #1 ? { ? \prg_break: } - \prg_break_point: - } - \@@_if_flag_error:nnx { str_byte } { non-byte } { #2 } - \@@_if_flag_error:nnx { str_error } { unescape-#2 } { } - \group_end: - } - \cs_new:Npn #3 ##1#1##2##3 - { - \@@_filter_bytes:n {##1} - \use_none:n ##3 - \@@_output_byte:w " - \@@_hexadecimal_use:NTF ##2 - { - \@@_hexadecimal_use:NTF ##3 - { } - { - \flag_raise:n { str_error } - * 0 + `#1 \use_i:nn - } - } - { - \flag_raise:n { str_error } - 0 + `#1 \use_i:nn - } - \@@_output_end: - \use_i:nnn #3 ##2##3 - } - \__kernel_msg_new:nnnn { str } { unescape-#2 } - { String~invalid~in~escaping~'#2'. } - { - LaTeX~came~across~the~escape~character~'#1'~not~followed~by~ - two~hexadecimal~digits.~This~is~invalid~in~the~escaping~'#2'. - } - } -% -%<*name> -\exp_after:wN \@@_tmp:w \c_hash_str { name } - \@@_unescape_name_loop:wNN -% -%<*url> -\exp_after:wN \@@_tmp:w \c_percent_str { url } - \@@_unescape_url_loop:wNN -% -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\@@_convert_unescape_string:} -% \begin{macro}[rEXP]{\@@_unescape_string_newlines:wN} -% \begin{macro}[rEXP]{\@@_unescape_string_loop:wNNN} -% \begin{macro}[rEXP]{\@@_unescape_string_repeat:NNNNNN} -% The \texttt{string} escaping is somewhat similar to the -% \texttt{name} and \texttt{url} escapings, with escape character |\|. -% The first step is to convert all three line endings, |^^J|, |^^M|, -% and |^^M^^J| to the common |^^J|, as per the \textsc{pdf} -% specification. This step cannot raise the flag. -% -% Then the following escape sequences are decoded. -% \begin{itemize}\def\makelabel#1{\hss\llap{\ttfamily\string#1}} -% \item[\n] Line feed ($10$) -% \item[\r] Carriage return ($13$) -% \item[\t] Horizontal tab ($9$) -% \item[\b] Backspace ($8$) -% \item[\f] Form feed ($12$) -% \item[\(] Left parenthesis -% \item[\)] Right parenthesis -% \item[\\] Backslash -% \item[\ddd] (backslash followed by $1$ to $3$ octal digits) Byte -% \texttt{ddd} (octal), subtracting $256$ in case of overflow. -% \end{itemize} -% If followed by an end-of-line character, the backslash and the -% end-of-line are ignored. If followed by anything else, the backslash -% is ignored, raising the error flag. -% \begin{macrocode} -%<*string> -\group_begin: - \char_set_catcode_other:N \^^J - \char_set_catcode_other:N \^^M - \cs_set_protected:Npn \@@_tmp:w #1 - { - \cs_new_protected:Npn \@@_convert_unescape_string: - { - \group_begin: - \flag_clear:n { str_byte } - \flag_clear:n { str_error } - \int_set:Nn \tex_escapechar:D { 92 } - \tl_gset:Nx \g_@@_result_tl - { - \exp_after:wN \@@_unescape_string_newlines:wN - \g_@@_result_tl \prg_break: ^^M ? - \prg_break_point: - } - \tl_gset:Nx \g_@@_result_tl - { - \exp_after:wN \@@_unescape_string_loop:wNNN - \g_@@_result_tl #1 ?? { ? \prg_break: } - \prg_break_point: - } - \@@_if_flag_error:nnx { str_byte } { non-byte } { string } - \@@_if_flag_error:nnx { str_error } { unescape-string } { } - \group_end: - } - } - \exp_args:No \@@_tmp:w { \c_backslash_str } - \exp_last_unbraced:NNNNo - \cs_new:Npn \@@_unescape_string_loop:wNNN #1 \c_backslash_str #2#3#4 - { - \@@_filter_bytes:n {#1} - \use_none:n #4 - \@@_output_byte:w ' - \@@_octal_use:NTF #2 - { - \@@_octal_use:NTF #3 - { - \@@_octal_use:NTF #4 - { - \if_int_compare:w #2 > 3 \exp_stop_f: - - 256 - \fi: - \@@_unescape_string_repeat:NNNNNN - } - { \@@_unescape_string_repeat:NNNNNN ? } - } - { \@@_unescape_string_repeat:NNNNNN ?? } - } - { - \str_case_e:nnF {#2} - { - { \c_backslash_str } { 134 } - { ( } { 50 } - { ) } { 51 } - { r } { 15 } - { f } { 14 } - { n } { 12 } - { t } { 11 } - { b } { 10 } - { ^^J } { 0 - 1 } - } - { - \flag_raise:n { str_error } - 0 - 1 \use_i:nn - } - } - \@@_output_end: - \use_i:nn \@@_unescape_string_loop:wNNN #2#3#4 - } - \cs_new:Npn \@@_unescape_string_repeat:NNNNNN #1#2#3#4#5#6 - { \@@_output_end: \@@_unescape_string_loop:wNNN } - \cs_new:Npn \@@_unescape_string_newlines:wN #1 ^^M #2 - { - #1 - \if_charcode:w ^^J #2 \else: ^^J \fi: - \@@_unescape_string_newlines:wN #2 - } - \__kernel_msg_new:nnnn { str } { unescape-string } - { String~invalid~in~escaping~'string'. } - { - LaTeX~came~across~an~escape~character~'\c_backslash_str'~ - not~followed~by~any~of:~'n',~'r',~'t',~'b',~'f',~'(',~')',~ - '\c_backslash_str',~one~to~three~octal~digits,~or~the~end~ - of~a~line. - } -\group_end: -% -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \subsubsection{Escape methods} -% -% Currently, none of the escape methods can lead to errors, assuming -% that their input is made out of bytes. -% -% \begin{macro}{\@@_convert_escape_hex:} -% \begin{macro}[rEXP]{\@@_escape_hex_char:N} -% Loop and convert each byte to hexadecimal. -% \begin{macrocode} -%<*hex> -\cs_new_protected:Npn \@@_convert_escape_hex: - { \@@_convert_gmap:N \@@_escape_hex_char:N } -\cs_new:Npn \@@_escape_hex_char:N #1 - { \@@_output_hexadecimal:n { `#1 } } -% -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\@@_convert_escape_name:} -% \begin{macro}[rEXP]{\@@_escape_name_char:N} -% \begin{macro}[rEXP]{\@@_if_escape_name:NTF} -% \begin{variable}{\c_@@_escape_name_str} -% \begin{variable}{\c_@@_escape_name_not_str} -% For each byte, test whether it should be output as is, or be -% \enquote{hash-encoded}. Roughly, bytes outside the range -% $[\hexnum{2A},\hexnum{7E}]$ are hash-encoded. We keep two lists of -% exceptions: characters in \cs{c_@@_escape_name_not_str} are not -% hash-encoded, and characters in the \cs{c_@@_escape_name_str} are -% encoded. -% \begin{macrocode} -%<*name> -\str_const:Nn \c_@@_escape_name_not_str { ! " $ & ' } %$ -\str_const:Nn \c_@@_escape_name_str { {}/<>[] } -\cs_new_protected:Npn \@@_convert_escape_name: - { \@@_convert_gmap:N \@@_escape_name_char:N } -\cs_new:Npn \@@_escape_name_char:N #1 - { - \@@_if_escape_name:NTF #1 {#1} - { \c_hash_str \@@_output_hexadecimal:n {`#1} } - } -\prg_new_conditional:Npnn \@@_if_escape_name:N #1 { TF } - { - \if_int_compare:w `#1 < "2A \exp_stop_f: - \@@_if_contains_char:NNTF \c_@@_escape_name_not_str #1 - \prg_return_true: \prg_return_false: - \else: - \if_int_compare:w `#1 > "7E \exp_stop_f: - \prg_return_false: - \else: - \@@_if_contains_char:NNTF \c_@@_escape_name_str #1 - \prg_return_false: \prg_return_true: - \fi: - \fi: - } -% -% \end{macrocode} -% \end{variable} -% \end{variable} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\@@_convert_escape_string:} -% \begin{macro}[rEXP]{\@@_escape_string_char:N} -% \begin{macro}[rEXP]{\@@_if_escape_string:NTF} -% \begin{variable}{\c_@@_escape_string_str} -% Any character below (and including) space, and any character above -% (and including) \texttt{del}, are converted to octal. One backslash -% is added before each parenthesis and backslash. -% \begin{macrocode} -%<*string> -\str_const:Nx \c_@@_escape_string_str - { \c_backslash_str ( ) } -\cs_new_protected:Npn \@@_convert_escape_string: - { \@@_convert_gmap:N \@@_escape_string_char:N } -\cs_new:Npn \@@_escape_string_char:N #1 - { - \@@_if_escape_string:NTF #1 - { - \@@_if_contains_char:NNT - \c_@@_escape_string_str #1 - { \c_backslash_str } - #1 - } - { - \c_backslash_str - \int_div_truncate:nn {`#1} {64} - \int_mod:nn { \int_div_truncate:nn {`#1} { 8 } } { 8 } - \int_mod:nn {`#1} { 8 } - } - } -\prg_new_conditional:Npnn \@@_if_escape_string:N #1 { TF } - { - \if_int_compare:w `#1 < "21 \exp_stop_f: - \prg_return_false: - \else: - \if_int_compare:w `#1 > "7E \exp_stop_f: - \prg_return_false: - \else: - \prg_return_true: - \fi: - \fi: - } -% -% \end{macrocode} -% \end{variable} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\@@_convert_escape_url:} -% \begin{macro}[rEXP]{\@@_escape_url_char:N} -% \begin{macro}[rEXP]{\@@_if_escape_url:NTF} -% This function is similar to \cs{@@_convert_escape_name:}, escaping -% different characters. -% \begin{macrocode} -%<*url> -\cs_new_protected:Npn \@@_convert_escape_url: - { \@@_convert_gmap:N \@@_escape_url_char:N } -\cs_new:Npn \@@_escape_url_char:N #1 - { - \@@_if_escape_url:NTF #1 {#1} - { \c_percent_str \@@_output_hexadecimal:n { `#1 } } - } -\prg_new_conditional:Npnn \@@_if_escape_url:N #1 { TF } - { - \if_int_compare:w `#1 < "41 \exp_stop_f: - \@@_if_contains_char:nNTF { "-.<> } #1 - \prg_return_true: \prg_return_false: - \else: - \if_int_compare:w `#1 > "7E \exp_stop_f: - \prg_return_false: - \else: - \@@_if_contains_char:nNTF { [ ] } #1 - \prg_return_false: \prg_return_true: - \fi: - \fi: - } -% -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \subsection{Encoding definition files} -% -% The \texttt{native} encoding is automatically defined. Other encodings -% are loaded as needed. The following encodings are supported: -% \begin{itemize} -% \item \textsc{utf-8}; -% \item \textsc{utf-16}, big-, little-endian, or with byte order mark; -% \item \textsc{utf-32}, big-, little-endian, or with byte order mark; -% \item the \textsc{iso 8859} code pages, numbered from $1$ to $16$, -% skipping the inexistent \textsc{iso 8859-12}. -% \end{itemize} -% -% \subsubsection{\textsc{utf-8} support} -% -% \begin{macrocode} -%<*utf8> -% \end{macrocode} -% -% \begin{macro}{\@@_convert_encode_utf8:} -% \begin{macro}[rEXP]{\@@_encode_utf_viii_char:n} -% \begin{macro}[rEXP]{\@@_encode_utf_viii_loop:wwnnw} -% Loop through the internal string, and convert each character to its -% \textsc{utf-8} representation. The representation is built from the -% right-most (least significant) byte to the left-most (most -% significant) byte. Continuation bytes are in the range $[128,191]$, -% taking $64$ different values, hence we roughly want to express the -% character code in base $64$, shifting the first digit in the -% representation by some number depending on how many continuation -% bytes there are. In the range $[0,127]$, output the corresponding -% byte directly. In the range $[128,2047]$, output the remainder -% modulo $64$, plus $128$ as a continuation byte, then output the -% quotient (which is in the range $[0,31]$), shifted by $192$. In the -% next range, $[2048,65535]$, split the character code into residue -% and quotient modulo $64$, output the residue as a first continuation -% byte, then repeat; this leaves us with a quotient in the range -% $[0,15]$, which we output shifted by $224$. The last range, -% $[65536,1114111]$, follows the same pattern: once we realize that -% dividing twice by $64$ leaves us with a number larger than $15$, we -% repeat, producing a last continuation byte, and offset the quotient -% by $240$ for the leading byte. -% -% How is that implemented? \cs{@@_encode_utf_vii_loop:wwnnw} takes -% successive quotients as its first argument, the quotient from the -% previous step as its second argument (except in step~$1$), the bound -% for quotients that trigger one more step or not, and finally the -% offset used if this step should produce the leading byte. Leading -% bytes can be in the ranges $[0,127]$, $[192,223]$, $[224,239]$, and -% $[240,247]$ (really, that last limit should be $244$ because Unicode -% stops at the code point $1114111$). At each step, if the quotient -% |#1| is less than the limit |#3| for that range, output the leading -% byte (|#1| shifted by |#4|) and stop. Otherwise, we need one more -% step: use the quotient of |#1| by $64$, and |#1| as arguments for -% the looping auxiliary, and output the continuation byte -% corresponding to the remainder $|#2|-64|#1|+128$. The bizarre -% construction |- 1 + 0 *| removes the spurious initial -% continuation byte (better methods welcome). -% \begin{macrocode} -\cs_new_protected:cpn { @@_convert_encode_utf8: } - { \@@_convert_gmap_internal:N \@@_encode_utf_viii_char:n } -\cs_new:Npn \@@_encode_utf_viii_char:n #1 - { - \@@_encode_utf_viii_loop:wwnnw #1 ; - 1 + 0 * ; - { 128 } { 0 } - { 32 } { 192 } - { 16 } { 224 } - { 8 } { 240 } - \q_stop - } -\cs_new:Npn \@@_encode_utf_viii_loop:wwnnw #1; #2; #3#4 #5 \q_stop - { - \if_int_compare:w #1 < #3 \exp_stop_f: - \@@_output_byte:n { #1 + #4 } - \exp_after:wN \use_none_delimit_by_q_stop:w - \fi: - \exp_after:wN \@@_encode_utf_viii_loop:wwnnw - \int_value:w \int_div_truncate:nn {#1} {64} ; #1 ; - #5 \q_stop - \@@_output_byte:n { #2 - 64 * ( #1 - 2 ) } - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{variable} -% { -% \l_@@_missing_flag , -% \l_@@_extra_flag , -% \l_@@_overlong_flag , -% \l_@@_overflow_flag , -% } -% When decoding a string that is purportedly in the \textsc{utf-8} -% encoding, four different errors can occur, signalled by a specific -% flag for each (we define those flags using \cs{flag_clear_new:n} -% rather than \cs{flag_new:n}, because they are shared with other -% encoding definition files). -% \begin{itemize} -% \item \enquote{Missing continuation byte}: a leading byte is not -% followed by the right number of continuation bytes. -% \item \enquote{Extra continuation byte}: a continuation byte -% appears where it was not expected, \emph{i.e.}, not after an -% appropriate leading byte. -% \item \enquote{Overlong}: a Unicode character is expressed using -% more bytes than necessary, for instance, \hexnum{C0}\hexnum{80} -% for the code point $0$, instead of a single null byte. -% \item \enquote{Overflow}: this occurs when decoding produces -% Unicode code points greater than $1114111$. -% \end{itemize} -% We only raise one \LaTeX3 error message, combining all the errors -% which occurred. In the short message, the leading comma must be -% removed to get a grammatically correct sentence. In the long text, -% first remind the user what a correct \textsc{utf-8} string should -% look like, then add error-specific information. -% \begin{macrocode} -\flag_clear_new:n { str_missing } -\flag_clear_new:n { str_extra } -\flag_clear_new:n { str_overlong } -\flag_clear_new:n { str_overflow } -\__kernel_msg_new:nnnn { str } { utf8-decode } - { - Invalid~UTF-8~string: - \exp_last_unbraced:Nf \use_none:n - { - \@@_if_flag_times:nT { str_missing } { ,~missing~continuation~byte } - \@@_if_flag_times:nT { str_extra } { ,~extra~continuation~byte } - \@@_if_flag_times:nT { str_overlong } { ,~overlong~form } - \@@_if_flag_times:nT { str_overflow } { ,~code~point~too~large } - } - . - } - { - In~the~UTF-8~encoding,~each~Unicode~character~consists~in~ - 1~to~4~bytes,~with~the~following~bit~pattern: \\ - \iow_indent:n - { - Code~point~\ \ \ \ <~128:~0xxxxxxx \\ - Code~point~\ \ \ <~2048:~110xxxxx~10xxxxxx \\ - Code~point~\ \ <~65536:~1110xxxx~10xxxxxx~10xxxxxx \\ - Code~point~ <~1114112:~11110xxx~10xxxxxx~10xxxxxx~10xxxxxx \\ - } - Bytes~of~the~form~10xxxxxx~are~called~continuation~bytes. - \flag_if_raised:nT { str_missing } - { - \\\\ - A~leading~byte~(in~the~range~[192,255])~was~not~followed~by~ - the~appropriate~number~of~continuation~bytes. - } - \flag_if_raised:nT { str_extra } - { - \\\\ - LaTeX~came~across~a~continuation~byte~when~it~was~not~expected. - } - \flag_if_raised:nT { str_overlong } - { - \\\\ - Every~Unicode~code~point~must~be~expressed~in~the~shortest~ - possible~form.~For~instance,~'0xC0'~'0x83'~is~not~a~valid~ - representation~for~the~code~point~3. - } - \flag_if_raised:nT { str_overflow } - { - \\\\ - Unicode~limits~code~points~to~the~range~[0,1114111]. - } - } -% \end{macrocode} -% \end{variable} -% -% \begin{macro}{\@@_convert_decode_utf8:} -% \begin{macro}[rEXP] -% { -% \@@_decode_utf_viii_start:N, -% \@@_decode_utf_viii_continuation:wwN, -% \@@_decode_utf_viii_aux:wNnnwN -% } -% \begin{macro}[rEXP] -% {\@@_decode_utf_viii_overflow:w, \@@_decode_utf_viii_end:} -% Decoding is significantly harder than encoding. As before, lower -% some flags, which are tested at the end (in bulk, to trigger at most -% one \LaTeX3 error, as explained above). We expect successive -% multi-byte sequences of the form \meta{start byte} -% \meta{continuation bytes}. The \texttt{_start} auxiliary tests the -% first byte: -% \begin{itemize} -% \item $[0,\hexnum{7F}]$: the byte stands alone, and is converted -% to its own character code; -% \item $[\hexnum{80}, \hexnum{BF}]$: unexpected continuation byte, -% raise the appropriate flag, and convert that byte to the -% replacement character \hexnum{FFFD}; -% \item $[\hexnum{C0}, \hexnum{FF}]$: this byte should be followed -% by some continuation byte(s). -% \end{itemize} -% In the first two cases, \cs{use_none_delimit_by_q_stop:w} removes -% data that only the third case requires, namely the limits of ranges -% of Unicode characters which can be expressed with $1$, $2$, $3$, or -% $4$ bytes. -% -% We can now concentrate on the multi-byte case and the -% \texttt{_continuation} auxiliary. We expect |#3| to be in the range -% $[\hexnum{80}, \hexnum{BF}]$. The test for this goes as follows: if -% the character code is less than \hexnum{80}, we compare it to -% $-\hexnum{C0}$, yielding \texttt{false}; otherwise to \hexnum{C0}, -% yielding \texttt{true} in the range $[\hexnum{80}, \hexnum{BF}]$ and -% \texttt{false} otherwise. If we find that the byte is not a -% continuation range, stop the current slew of bytes, output the -% replacement character, and continue parsing with the \texttt{_start} -% auxiliary, starting at the byte we just tested. Once we know that -% the byte is a continuation byte, leave it behind us in the input -% stream, compute what code point the bytes read so far would produce, -% and feed that number to the \texttt{_aux} function. -% -% The \texttt{_aux} function tests whether we should look for more -% continuation bytes or not. If the number it receives as |#1| is less -% than the maximum |#4| for the current range, then we are done: check -% for an overlong representation by comparing |#1| with the maximum -% |#3| for the previous range. Otherwise, we call the -% \texttt{_continuation} auxiliary again, after shifting the -% \enquote{current code point} by |#4| (maximum from the range we just -% checked). -% -% Two additional tests are needed: if we reach the end of the list of -% range maxima and we are still not done, then we are faced with an -% overflow. Clean up, and again insert the code point \hexnum{FFFD} -% for the replacement character. Also, every time we read a byte, we -% need to check whether we reached the end of the string. In a correct -% \textsc{utf-8} string, this happens automatically when the -% \texttt{_start} auxiliary leaves its first argument in the input -% stream: the end-marker begins with \cs{prg_break:}, which ends -% the loop. On the other hand, if the end is reached when looking for -% a continuation byte, the \cs{use_none:n} |#3| construction removes -% the first token from the end-marker, and leaves the \texttt{_end} -% auxiliary, which raises the appropriate error flag before ending the -% mapping. -% \begin{macrocode} -\cs_new_protected:cpn { @@_convert_decode_utf8: } - { - \flag_clear:n { str_error } - \flag_clear:n { str_missing } - \flag_clear:n { str_extra } - \flag_clear:n { str_overlong } - \flag_clear:n { str_overflow } - \tl_gset:Nx \g_@@_result_tl - { - \exp_after:wN \@@_decode_utf_viii_start:N \g_@@_result_tl - { \prg_break: \@@_decode_utf_viii_end: } - \prg_break_point: - } - \@@_if_flag_error:nnx { str_error } { utf8-decode } { } - } -\cs_new:Npn \@@_decode_utf_viii_start:N #1 - { - #1 - \if_int_compare:w `#1 < "C0 \exp_stop_f: - \s__tl - \if_int_compare:w `#1 < "80 \exp_stop_f: - \int_value:w `#1 - \else: - \flag_raise:n { str_extra } - \flag_raise:n { str_error } - \int_use:N \c_@@_replacement_char_int - \fi: - \else: - \exp_after:wN \@@_decode_utf_viii_continuation:wwN - \int_value:w \int_eval:n { `#1 - "C0 } \exp_after:wN - \fi: - \s__tl - \use_none_delimit_by_q_stop:w {"80} {"800} {"10000} {"110000} \q_stop - \@@_decode_utf_viii_start:N - } -\cs_new:Npn \@@_decode_utf_viii_continuation:wwN - #1 \s__tl #2 \@@_decode_utf_viii_start:N #3 - { - \use_none:n #3 - \if_int_compare:w `#3 < - \if_int_compare:w `#3 < "80 \exp_stop_f: - \fi: - "C0 \exp_stop_f: - #3 - \exp_after:wN \@@_decode_utf_viii_aux:wNnnwN - \int_value:w \int_eval:n { #1 * "40 + `#3 - "80 } \exp_after:wN - \else: - \s__tl - \flag_raise:n { str_missing } - \flag_raise:n { str_error } - \int_use:N \c_@@_replacement_char_int - \fi: - \s__tl - #2 - \@@_decode_utf_viii_start:N #3 - } -\cs_new:Npn \@@_decode_utf_viii_aux:wNnnwN - #1 \s__tl #2#3#4 #5 \@@_decode_utf_viii_start:N #6 - { - \if_int_compare:w #1 < #4 \exp_stop_f: - \s__tl - \if_int_compare:w #1 < #3 \exp_stop_f: - \flag_raise:n { str_overlong } - \flag_raise:n { str_error } - \int_use:N \c_@@_replacement_char_int - \else: - #1 - \fi: - \else: - \if_meaning:w \q_stop #5 - \@@_decode_utf_viii_overflow:w #1 - \fi: - \exp_after:wN \@@_decode_utf_viii_continuation:wwN - \int_value:w \int_eval:n { #1 - #4 } \exp_after:wN - \fi: - \s__tl - #2 {#4} #5 - \@@_decode_utf_viii_start:N - } -\cs_new:Npn \@@_decode_utf_viii_overflow:w #1 \fi: #2 \fi: - { - \fi: \fi: - \flag_raise:n { str_overflow } - \flag_raise:n { str_error } - \int_use:N \c_@@_replacement_char_int - } -\cs_new:Npn \@@_decode_utf_viii_end: - { - \s__tl - \flag_raise:n { str_missing } - \flag_raise:n { str_error } - \int_use:N \c_@@_replacement_char_int \s__tl - \prg_break: - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macrocode} -% -% \end{macrocode} -% -% \subsubsection{\textsc{utf-16} support} -% -% The definitions are done in a category code regime where the bytes -% $254$ and $255$ used by the byte order mark have catcode~$12$. -% \begin{macrocode} -%<*utf16> -\group_begin: - \char_set_catcode_other:N \^^fe - \char_set_catcode_other:N \^^ff -% \end{macrocode} -% -% \begin{macro} -% { -% \@@_convert_encode_utf16: , -% \@@_convert_encode_utf16be: , -% \@@_convert_encode_utf16le: , -% } -% \begin{macro}[rEXP] -% { -% \@@_encode_utf_xvi_aux:N , -% \@@_encode_utf_xvi_char:n , -% } -% When the endianness is not specified, it is big-endian by default, -% and we add a byte-order mark. Convert characters one by one in a -% loop, with different behaviours depending on the character code. -% \begin{itemize} -% \item $[0, \hexnum{D7FF}]$: converted to two bytes; -% \item $[\hexnum{D800}, \hexnum{DFFF}]$ are used as surrogates: -% they cannot be converted and are replaced by the replacement -% character; -% \item $[\hexnum{E000}, \hexnum{FFFF}]$: converted to two bytes; -% \item $[\hexnum{10000}, \hexnum{10FFFF}]$: converted to a pair of -% surrogates, each two bytes. The magic \hexnum{D7C0} is -% $\hexnum{D800}-\hexnum{10000}/\hexnum{400}$. -% \end{itemize} -% For the duration of this operation, \cs{@@_tmp:w} is defined as a -% function to convert a number in the range $[0, \hexnum{FFFF}]$ to a -% pair of bytes (either big endian or little endian), by feeding the -% quotient of the division of |#1| by \hexnum{100}, followed by |#1| -% to \cs{@@_encode_utf_xvi_be:nn} or its \texttt{le} analog: those -% compute the remainder, and output two bytes for the quotient and -% remainder. -% \begin{macrocode} - \cs_new_protected:cpn { @@_convert_encode_utf16: } - { - \@@_encode_utf_xvi_aux:N \@@_output_byte_pair_be:n - \tl_gput_left:Nx \g_@@_result_tl { ^^fe ^^ff } - } - \cs_new_protected:cpn { @@_convert_encode_utf16be: } - { \@@_encode_utf_xvi_aux:N \@@_output_byte_pair_be:n } - \cs_new_protected:cpn { @@_convert_encode_utf16le: } - { \@@_encode_utf_xvi_aux:N \@@_output_byte_pair_le:n } - \cs_new_protected:Npn \@@_encode_utf_xvi_aux:N #1 - { - \flag_clear:n { str_error } - \cs_set_eq:NN \@@_tmp:w #1 - \@@_convert_gmap_internal:N \@@_encode_utf_xvi_char:n - \@@_if_flag_error:nnx { str_error } { utf16-encode } { } - } - \cs_new:Npn \@@_encode_utf_xvi_char:n #1 - { - \if_int_compare:w #1 < "D800 \exp_stop_f: - \@@_tmp:w {#1} - \else: - \if_int_compare:w #1 < "10000 \exp_stop_f: - \if_int_compare:w #1 < "E000 \exp_stop_f: - \flag_raise:n { str_error } - \@@_tmp:w { \c_@@_replacement_char_int } - \else: - \@@_tmp:w {#1} - \fi: - \else: - \exp_args:Nf \@@_tmp:w { \int_div_truncate:nn {#1} {"400} + "D7C0 } - \exp_args:Nf \@@_tmp:w { \int_mod:nn {#1} {"400} + "DC00 } - \fi: - \fi: - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{variable} -% { -% \l_@@_missing_flag , -% \l_@@_extra_flag , -% \l_@@_end_flag , -% } -% When encoding a Unicode string to \textsc{utf-16}, only one error -% can occur: code points in the range $[\hexnum{D800}, -% \hexnum{DFFF}]$, corresponding to surrogates, cannot be encoded. We -% use the all-purpose flag \texttt{@@_error} to signal that error. -% -% When decoding a Unicode string which is purportedly in -% \textsc{utf-16}, three errors can occur: a missing trail surrogate, -% an unexpected trail surrogate, and a string containing an odd number -% of bytes. -% \begin{macrocode} - \flag_clear_new:n { str_missing } - \flag_clear_new:n { str_extra } - \flag_clear_new:n { str_end } - \__kernel_msg_new:nnnn { str } { utf16-encode } - { Unicode~string~cannot~be~expressed~in~UTF-16:~surrogate. } - { - Surrogate~code~points~(in~the~range~[U+D800,~U+DFFF])~ - can~be~expressed~in~the~UTF-8~and~UTF-32~encodings,~ - but~not~in~the~UTF-16~encoding. - } - \__kernel_msg_new:nnnn { str } { utf16-decode } - { - Invalid~UTF-16~string: - \exp_last_unbraced:Nf \use_none:n - { - \@@_if_flag_times:nT { str_missing } { ,~missing~trail~surrogate } - \@@_if_flag_times:nT { str_extra } { ,~extra~trail~surrogate } - \@@_if_flag_times:nT { str_end } { ,~odd~number~of~bytes } - } - . - } - { - In~the~UTF-16~encoding,~each~Unicode~character~is~encoded~as~ - 2~or~4~bytes: \\ - \iow_indent:n - { - Code~point~in~[U+0000,~U+D7FF]:~two~bytes \\ - Code~point~in~[U+D800,~U+DFFF]:~illegal \\ - Code~point~in~[U+E000,~U+FFFF]:~two~bytes \\ - Code~point~in~[U+10000,~U+10FFFF]:~ - a~lead~surrogate~and~a~trail~surrogate \\ - } - Lead~surrogates~are~pairs~of~bytes~in~the~range~[0xD800,~0xDBFF],~ - and~trail~surrogates~are~in~the~range~[0xDC00,~0xDFFF]. - \flag_if_raised:nT { str_missing } - { - \\\\ - A~lead~surrogate~was~not~followed~by~a~trail~surrogate. - } - \flag_if_raised:nT { str_extra } - { - \\\\ - LaTeX~came~across~a~trail~surrogate~when~it~was~not~expected. - } - \flag_if_raised:nT { str_end } - { - \\\\ - The~string~contained~an~odd~number~of~bytes.~This~is~invalid:~ - the~basic~code~unit~for~UTF-16~is~16~bits~(2~bytes). - } - } -% \end{macrocode} -% \end{variable} -% -% \begin{macro} -% { -% \@@_convert_decode_utf16: , -% \@@_convert_decode_utf16be: , -% \@@_convert_decode_utf16le: , -% } -% \begin{macro}{\@@_decode_utf_xvi_bom:NN, \@@_decode_utf_xvi:Nw} -% As for \textsc{utf-8}, decoding \textsc{utf-16} is harder than -% encoding it. If the endianness is unknown, check the first two -% bytes: if those are \hexnum{FE} and \hexnum{FF} in either order, -% remove them and use the corresponding endianness, otherwise assume -% big-endianness. The three endianness cases are based on a common -% auxiliary whose first argument is $1$ for big-endian and $2$ for -% little-endian, and whose second argument, delimited by the scan mark -% \cs{s_stop}, is expanded once (the string may be long; passing -% \cs{g_@@_result_tl} as an argument before expansion is cheaper). -% -% The \cs{@@_decode_utf_xvi:Nw} function defines \cs{@@_tmp:w} to -% take two arguments and return the character code of the first one if -% the string is big-endian, and the second one if the string is -% little-endian, then loops over the string using -% \cs{@@_decode_utf_xvi_pair:NN} described below. -% \begin{macrocode} - \cs_new_protected:cpn { @@_convert_decode_utf16be: } - { \@@_decode_utf_xvi:Nw 1 \g_@@_result_tl \s_stop } - \cs_new_protected:cpn { @@_convert_decode_utf16le: } - { \@@_decode_utf_xvi:Nw 2 \g_@@_result_tl \s_stop } - \cs_new_protected:cpn { @@_convert_decode_utf16: } - { - \exp_after:wN \@@_decode_utf_xvi_bom:NN - \g_@@_result_tl \s_stop \s_stop \s_stop - } - \cs_new_protected:Npn \@@_decode_utf_xvi_bom:NN #1#2 - { - \str_if_eq:nnTF { #1#2 } { ^^ff ^^fe } - { \@@_decode_utf_xvi:Nw 2 } - { - \str_if_eq:nnTF { #1#2 } { ^^fe ^^ff } - { \@@_decode_utf_xvi:Nw 1 } - { \@@_decode_utf_xvi:Nw 1 #1#2 } - } - } - \cs_new_protected:Npn \@@_decode_utf_xvi:Nw #1#2 \s_stop - { - \flag_clear:n { str_error } - \flag_clear:n { str_missing } - \flag_clear:n { str_extra } - \flag_clear:n { str_end } - \cs_set:Npn \@@_tmp:w ##1 ##2 { ` ## #1 } - \tl_gset:Nx \g_@@_result_tl - { - \exp_after:wN \@@_decode_utf_xvi_pair:NN - #2 \q_nil \q_nil - \prg_break_point: - } - \@@_if_flag_error:nnx { str_error } { utf16-decode } { } - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}[rEXP] -% { -% \@@_decode_utf_xvi_pair:NN , -% \@@_decode_utf_xvi_quad:NNwNN , -% \@@_decode_utf_xvi_pair_end:Nw , -% } -% \begin{macro}[rEXP] -% { -% \@@_decode_utf_xvi_error:nNN , -% \@@_decode_utf_xvi_extra:NNw , -% } -% Bytes are read two at a time. At this stage, |\@@_tmp:w #1#2| -% expands to the character code of the most significant byte, and we -% distinguish cases depending on which range it lies in: -% \begin{itemize} -% \item $[\hexnum{D8}, \hexnum{DB}]$ signals a lead surrogate, and -% the integer expression yields $1$ (\eTeX{} rounds ties away from -% zero); -% \item $[\hexnum{DC}, \hexnum{DF}]$ signals a trail surrogate, -% unexpected here, and the integer expression yields $2$; -% \item any other value signals a code point in the Basic -% Multilingual Plane, which stands for itself, and the -% \cs{if_case:w} construction expands to nothing (cases other than -% $1$ or $2$), leaving the relevant material in the input stream, -% followed by another call to the \texttt{_pair} auxiliary. -% \end{itemize} -% The case of a lead surrogate is treated by the \texttt{_quad} -% auxiliary, whose arguments |#1|, |#2|, |#4| and |#5| are the four -% bytes. We expect the most significant byte of |#4#5| to be in the -% range $[\hexnum{DC}, \hexnum{DF}]$ (trail surrogate). The test is -% similar to the test used for continuation bytes in the -% \textsc{utf-8} decoding functions. In the case where |#4#5| is -% indeed a trail surrogate, leave |#1#2#4#5| \cs{s__tl} -% \meta{code~point} \cs{s__tl}, and remove the pair |#4#5| before -% looping with \cs{@@_decode_utf_xvi_pair:NN}. Otherwise, of course, -% complain about the missing surrogate. -% -% The magic number \hexnum{D7F7} is such that -% $\hexnum{D7F7}*\hexnum{400} = \hexnum{D800}*\hexnum{400} + -% \hexnum{DC00} - \hexnum{10000}$. -% -% Every time we read a pair of bytes, we test for the end-marker -% \cs{q_nil}. When reaching the end, we additionally check that the -% string had an even length. Also, if the end is reached when -% expecting a trail surrogate, we treat that as a missing surrogate. -% \begin{macrocode} - \cs_new:Npn \@@_decode_utf_xvi_pair:NN #1#2 - { - \if_meaning:w \q_nil #2 - \@@_decode_utf_xvi_pair_end:Nw #1 - \fi: - \if_case:w - \int_eval:n { ( \@@_tmp:w #1#2 - "D6 ) / 4 } \scan_stop: - \or: \exp_after:wN \@@_decode_utf_xvi_quad:NNwNN - \or: \exp_after:wN \@@_decode_utf_xvi_extra:NNw - \fi: - #1#2 \s__tl - \int_eval:n { "100 * \@@_tmp:w #1#2 + \@@_tmp:w #2#1 } \s__tl - \@@_decode_utf_xvi_pair:NN - } - \cs_new:Npn \@@_decode_utf_xvi_quad:NNwNN - #1#2 #3 \@@_decode_utf_xvi_pair:NN #4#5 - { - \if_meaning:w \q_nil #5 - \@@_decode_utf_xvi_error:nNN { missing } #1#2 - \@@_decode_utf_xvi_pair_end:Nw #4 - \fi: - \if_int_compare:w - \if_int_compare:w \@@_tmp:w #4#5 < "DC \exp_stop_f: - 0 = 1 - \else: - \@@_tmp:w #4#5 < "E0 - \fi: - \exp_stop_f: - #1 #2 #4 #5 \s__tl - \int_eval:n - { - ( "100 * \@@_tmp:w #1#2 + \@@_tmp:w #2#1 - "D7F7 ) * "400 - + "100 * \@@_tmp:w #4#5 + \@@_tmp:w #5#4 - } - \s__tl - \exp_after:wN \use_i:nnn - \else: - \@@_decode_utf_xvi_error:nNN { missing } #1#2 - \fi: - \@@_decode_utf_xvi_pair:NN #4#5 - } - \cs_new:Npn \@@_decode_utf_xvi_pair_end:Nw #1 \fi: - { - \fi: - \if_meaning:w \q_nil #1 - \else: - \@@_decode_utf_xvi_error:nNN { end } #1 \prg_do_nothing: - \fi: - \prg_break: - } - \cs_new:Npn \@@_decode_utf_xvi_extra:NNw #1#2 \s__tl #3 \s__tl - { \@@_decode_utf_xvi_error:nNN { extra } #1#2 } - \cs_new:Npn \@@_decode_utf_xvi_error:nNN #1#2#3 - { - \flag_raise:n { str_error } - \flag_raise:n { str_#1 } - #2 #3 \s__tl - \int_use:N \c_@@_replacement_char_int \s__tl - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% Restore the original catcodes of bytes $254$ and $255$. -% \begin{macrocode} -\group_end: -% -% \end{macrocode} -% -% \subsubsection{\textsc{utf-32} support} -% -% The definitions are done in a category code regime where the bytes -% $0$, $254$ and $255$ used by the byte order mark have catcode -% \enquote{other}. -% \begin{macrocode} -%<*utf32> -\group_begin: - \char_set_catcode_other:N \^^00 - \char_set_catcode_other:N \^^fe - \char_set_catcode_other:N \^^ff -% \end{macrocode} -% -% \begin{macro} -% { -% \@@_convert_encode_utf32: , -% \@@_convert_encode_utf32be: , -% \@@_convert_encode_utf32le: , -% } -% \begin{macro}[rEXP] -% { -% \@@_encode_utf_xxxii_be:n , -% \@@_encode_utf_xxxii_be_aux:nn , -% \@@_encode_utf_xxxii_le:n , -% \@@_encode_utf_xxxii_le_aux:nn , -% } -% Convert each integer in the comma-list \cs{g_@@_result_tl} to a -% sequence of four bytes. The functions for big-endian and -% little-endian encodings are very similar, but the -% \cs{@@_output_byte:n} instructions are reversed. -% \begin{macrocode} - \cs_new_protected:cpn { @@_convert_encode_utf32: } - { - \@@_convert_gmap_internal:N \@@_encode_utf_xxxii_be:n - \tl_gput_left:Nx \g_@@_result_tl { ^^00 ^^00 ^^fe ^^ff } - } - \cs_new_protected:cpn { @@_convert_encode_utf32be: } - { \@@_convert_gmap_internal:N \@@_encode_utf_xxxii_be:n } - \cs_new_protected:cpn { @@_convert_encode_utf32le: } - { \@@_convert_gmap_internal:N \@@_encode_utf_xxxii_le:n } - \cs_new:Npn \@@_encode_utf_xxxii_be:n #1 - { - \exp_args:Nf \@@_encode_utf_xxxii_be_aux:nn - { \int_div_truncate:nn {#1} { "100 } } {#1} - } - \cs_new:Npn \@@_encode_utf_xxxii_be_aux:nn #1#2 - { - ^^00 - \@@_output_byte_pair_be:n {#1} - \@@_output_byte:n { #2 - #1 * "100 } - } - \cs_new:Npn \@@_encode_utf_xxxii_le:n #1 - { - \exp_args:Nf \@@_encode_utf_xxxii_le_aux:nn - { \int_div_truncate:nn {#1} { "100 } } {#1} - } - \cs_new:Npn \@@_encode_utf_xxxii_le_aux:nn #1#2 - { - \@@_output_byte:n { #2 - #1 * "100 } - \@@_output_byte_pair_le:n {#1} - ^^00 - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{variable}{str_overflow, str_end} -% There can be no error when encoding in \textsc{utf-32}. When -% decoding, the string may not have length $4n$, or it may contain -% code points larger than \hexnum{10FFFF}. The latter case often -% happens if the encoding was in fact not \textsc{utf-32}, because -% most arbitrary strings are not valid in \textsc{utf-32}. -% \begin{macrocode} - \flag_clear_new:n { str_overflow } - \flag_clear_new:n { str_end } - \__kernel_msg_new:nnnn { str } { utf32-decode } - { - Invalid~UTF-32~string: - \exp_last_unbraced:Nf \use_none:n - { - \@@_if_flag_times:nT { str_overflow } { ,~code~point~too~large } - \@@_if_flag_times:nT { str_end } { ,~truncated~string } - } - . - } - { - In~the~UTF-32~encoding,~every~Unicode~character~ - (in~the~range~[U+0000,~U+10FFFF])~is~encoded~as~4~bytes. - \flag_if_raised:nT { str_overflow } - { - \\\\ - LaTeX~came~across~a~code~point~larger~than~1114111,~ - the~maximum~code~point~defined~by~Unicode.~ - Perhaps~the~string~was~not~encoded~in~the~UTF-32~encoding? - } - \flag_if_raised:nT { str_end } - { - \\\\ - The~length~of~the~string~is~not~a~multiple~of~4.~ - Perhaps~the~string~was~truncated? - } - } -% \end{macrocode} -% \end{variable} -% -% \begin{macro} -% { -% \@@_convert_decode_utf32: , -% \@@_convert_decode_utf32be: , -% \@@_convert_decode_utf32le: , -% } -% \begin{macro} -% {\@@_decode_utf_xxxii_bom:NNNN, \@@_decode_utf_xxxii:Nw} -% \begin{macro}[rEXP] -% {\@@_decode_utf_xxxii_loop:NNNN, \@@_decode_utf_xxxii_end:w} -% -% The structure is similar to \textsc{utf-16} decoding functions. If -% the endianness is not given, test the first $4$ bytes of the string -% (possibly \cs{s_stop} if the string is too short) for the presence -% of a byte-order mark. If there is a byte-order mark, use that -% endianness, and remove the $4$ bytes, otherwise default to -% big-endian, and leave the $4$ bytes in place. The -% \cs{@@_decode_utf_xxxii:Nw} auxiliary receives $1$ or $2$ as its -% first argument indicating endianness, and the string to convert as -% its second argument (expanded or not). It sets \cs{@@_tmp:w} to -% expand to the character code of either of its two arguments -% depending on endianness, then triggers the \texttt{_loop} auxiliary -% inside an \texttt{x}-expanding assignment to \cs{g_@@_result_tl}. -% -% The \texttt{_loop} auxiliary first checks for the end-of-string -% marker \cs{s_stop}, calling the \texttt{_end} auxiliary if -% appropriate. Otherwise, leave the \meta{4~bytes} \cs{s__tl} behind, -% then check that the code point is not overflowing: the leading byte -% must be $0$, and the following byte at most $16$. -% -% In the ending code, we check that there remains no byte: there -% should be nothing left until the first \cs{s_stop}. Break the map. -% \begin{macrocode} - \cs_new_protected:cpn { @@_convert_decode_utf32be: } - { \@@_decode_utf_xxxii:Nw 1 \g_@@_result_tl \s_stop } - \cs_new_protected:cpn { @@_convert_decode_utf32le: } - { \@@_decode_utf_xxxii:Nw 2 \g_@@_result_tl \s_stop } - \cs_new_protected:cpn { @@_convert_decode_utf32: } - { - \exp_after:wN \@@_decode_utf_xxxii_bom:NNNN \g_@@_result_tl - \s_stop \s_stop \s_stop \s_stop \s_stop - } - \cs_new_protected:Npn \@@_decode_utf_xxxii_bom:NNNN #1#2#3#4 - { - \str_if_eq:nnTF { #1#2#3#4 } { ^^ff ^^fe ^^00 ^^00 } - { \@@_decode_utf_xxxii:Nw 2 } - { - \str_if_eq:nnTF { #1#2#3#4 } { ^^00 ^^00 ^^fe ^^ff } - { \@@_decode_utf_xxxii:Nw 1 } - { \@@_decode_utf_xxxii:Nw 1 #1#2#3#4 } - } - } - \cs_new_protected:Npn \@@_decode_utf_xxxii:Nw #1#2 \s_stop - { - \flag_clear:n { str_overflow } - \flag_clear:n { str_end } - \flag_clear:n { str_error } - \cs_set:Npn \@@_tmp:w ##1 ##2 { ` ## #1 } - \tl_gset:Nx \g_@@_result_tl - { - \exp_after:wN \@@_decode_utf_xxxii_loop:NNNN - #2 \s_stop \s_stop \s_stop \s_stop - \prg_break_point: - } - \@@_if_flag_error:nnx { str_error } { utf32-decode } { } - } - \cs_new:Npn \@@_decode_utf_xxxii_loop:NNNN #1#2#3#4 - { - \if_meaning:w \s_stop #4 - \exp_after:wN \@@_decode_utf_xxxii_end:w - \fi: - #1#2#3#4 \s__tl - \if_int_compare:w \@@_tmp:w #1#4 > 0 \exp_stop_f: - \flag_raise:n { str_overflow } - \flag_raise:n { str_error } - \int_use:N \c_@@_replacement_char_int - \else: - \if_int_compare:w \@@_tmp:w #2#3 > 16 \exp_stop_f: - \flag_raise:n { str_overflow } - \flag_raise:n { str_error } - \int_use:N \c_@@_replacement_char_int - \else: - \int_eval:n - { \@@_tmp:w #2#3*"10000 + \@@_tmp:w #3#2*"100 + \@@_tmp:w #4#1 } - \fi: - \fi: - \s__tl - \@@_decode_utf_xxxii_loop:NNNN - } - \cs_new:Npn \@@_decode_utf_xxxii_end:w #1 \s_stop - { - \tl_if_empty:nF {#1} - { - \flag_raise:n { str_end } - \flag_raise:n { str_error } - #1 \s__tl - \int_use:N \c_@@_replacement_char_int \s__tl - } - \prg_break: - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% -% Restore the original catcodes of bytes $0$, $254$ and $255$. -% \begin{macrocode} -\group_end: -% -% \end{macrocode} -% -% \subsubsection{\textsc{iso 8859} support} -% -% The \textsc{iso-8859-1} encoding exactly matches with the $256$ first -% Unicode characters. For other 8-bit encodings of the \textsc{iso-8859} -% family, we keep track only of differences, and of unassigned bytes. -% \begin{macrocode} -%<*iso88591> -\@@_declare_eight_bit_encoding:nnn { iso88591 } - { - } - { - } -% -% \end{macrocode} -% -% \begin{macrocode} -%<*iso88592> -\@@_declare_eight_bit_encoding:nnn { iso88592 } - { - { A1 } { 0104 } - { A2 } { 02D8 } - { A3 } { 0141 } - { A5 } { 013D } - { A6 } { 015A } - { A9 } { 0160 } - { AA } { 015E } - { AB } { 0164 } - { AC } { 0179 } - { AE } { 017D } - { AF } { 017B } - { B1 } { 0105 } - { B2 } { 02DB } - { B3 } { 0142 } - { B5 } { 013E } - { B6 } { 015B } - { B7 } { 02C7 } - { B9 } { 0161 } - { BA } { 015F } - { BB } { 0165 } - { BC } { 017A } - { BD } { 02DD } - { BE } { 017E } - { BF } { 017C } - { C0 } { 0154 } - { C3 } { 0102 } - { C5 } { 0139 } - { C6 } { 0106 } - { C8 } { 010C } - { CA } { 0118 } - { CC } { 011A } - { CF } { 010E } - { D0 } { 0110 } - { D1 } { 0143 } - { D2 } { 0147 } - { D5 } { 0150 } - { D8 } { 0158 } - { D9 } { 016E } - { DB } { 0170 } - { DE } { 0162 } - { E0 } { 0155 } - { E3 } { 0103 } - { E5 } { 013A } - { E6 } { 0107 } - { E8 } { 010D } - { EA } { 0119 } - { EC } { 011B } - { EF } { 010F } - { F0 } { 0111 } - { F1 } { 0144 } - { F2 } { 0148 } - { F5 } { 0151 } - { F8 } { 0159 } - { F9 } { 016F } - { FB } { 0171 } - { FE } { 0163 } - { FF } { 02D9 } - } - { - } -% -% \end{macrocode} -% -% \begin{macrocode} -%<*iso88593> -\@@_declare_eight_bit_encoding:nnn { iso88593 } - { - { A1 } { 0126 } - { A2 } { 02D8 } - { A6 } { 0124 } - { A9 } { 0130 } - { AA } { 015E } - { AB } { 011E } - { AC } { 0134 } - { AF } { 017B } - { B1 } { 0127 } - { B6 } { 0125 } - { B9 } { 0131 } - { BA } { 015F } - { BB } { 011F } - { BC } { 0135 } - { BF } { 017C } - { C5 } { 010A } - { C6 } { 0108 } - { D5 } { 0120 } - { D8 } { 011C } - { DD } { 016C } - { DE } { 015C } - { E5 } { 010B } - { E6 } { 0109 } - { F5 } { 0121 } - { F8 } { 011D } - { FD } { 016D } - { FE } { 015D } - { FF } { 02D9 } - } - { - { A5 } - { AE } - { BE } - { C3 } - { D0 } - { E3 } - { F0 } - } -% -% \end{macrocode} -% -% \begin{macrocode} -%<*iso88594> -\@@_declare_eight_bit_encoding:nnn { iso88594 } - { - { A1 } { 0104 } - { A2 } { 0138 } - { A3 } { 0156 } - { A5 } { 0128 } - { A6 } { 013B } - { A9 } { 0160 } - { AA } { 0112 } - { AB } { 0122 } - { AC } { 0166 } - { AE } { 017D } - { B1 } { 0105 } - { B2 } { 02DB } - { B3 } { 0157 } - { B5 } { 0129 } - { B6 } { 013C } - { B7 } { 02C7 } - { B9 } { 0161 } - { BA } { 0113 } - { BB } { 0123 } - { BC } { 0167 } - { BD } { 014A } - { BE } { 017E } - { BF } { 014B } - { C0 } { 0100 } - { C7 } { 012E } - { C8 } { 010C } - { CA } { 0118 } - { CC } { 0116 } - { CF } { 012A } - { D0 } { 0110 } - { D1 } { 0145 } - { D2 } { 014C } - { D3 } { 0136 } - { D9 } { 0172 } - { DD } { 0168 } - { DE } { 016A } - { E0 } { 0101 } - { E7 } { 012F } - { E8 } { 010D } - { EA } { 0119 } - { EC } { 0117 } - { EF } { 012B } - { F0 } { 0111 } - { F1 } { 0146 } - { F2 } { 014D } - { F3 } { 0137 } - { F9 } { 0173 } - { FD } { 0169 } - { FE } { 016B } - { FF } { 02D9 } - } - { - } -% -% \end{macrocode} -% -% \begin{macrocode} -%<*iso88595> -\@@_declare_eight_bit_encoding:nnn { iso88595 } - { - { A1 } { 0401 } - { A2 } { 0402 } - { A3 } { 0403 } - { A4 } { 0404 } - { A5 } { 0405 } - { A6 } { 0406 } - { A7 } { 0407 } - { A8 } { 0408 } - { A9 } { 0409 } - { AA } { 040A } - { AB } { 040B } - { AC } { 040C } - { AE } { 040E } - { AF } { 040F } - { B0 } { 0410 } - { B1 } { 0411 } - { B2 } { 0412 } - { B3 } { 0413 } - { B4 } { 0414 } - { B5 } { 0415 } - { B6 } { 0416 } - { B7 } { 0417 } - { B8 } { 0418 } - { B9 } { 0419 } - { BA } { 041A } - { BB } { 041B } - { BC } { 041C } - { BD } { 041D } - { BE } { 041E } - { BF } { 041F } - { C0 } { 0420 } - { C1 } { 0421 } - { C2 } { 0422 } - { C3 } { 0423 } - { C4 } { 0424 } - { C5 } { 0425 } - { C6 } { 0426 } - { C7 } { 0427 } - { C8 } { 0428 } - { C9 } { 0429 } - { CA } { 042A } - { CB } { 042B } - { CC } { 042C } - { CD } { 042D } - { CE } { 042E } - { CF } { 042F } - { D0 } { 0430 } - { D1 } { 0431 } - { D2 } { 0432 } - { D3 } { 0433 } - { D4 } { 0434 } - { D5 } { 0435 } - { D6 } { 0436 } - { D7 } { 0437 } - { D8 } { 0438 } - { D9 } { 0439 } - { DA } { 043A } - { DB } { 043B } - { DC } { 043C } - { DD } { 043D } - { DE } { 043E } - { DF } { 043F } - { E0 } { 0440 } - { E1 } { 0441 } - { E2 } { 0442 } - { E3 } { 0443 } - { E4 } { 0444 } - { E5 } { 0445 } - { E6 } { 0446 } - { E7 } { 0447 } - { E8 } { 0448 } - { E9 } { 0449 } - { EA } { 044A } - { EB } { 044B } - { EC } { 044C } - { ED } { 044D } - { EE } { 044E } - { EF } { 044F } - { F0 } { 2116 } - { F1 } { 0451 } - { F2 } { 0452 } - { F3 } { 0453 } - { F4 } { 0454 } - { F5 } { 0455 } - { F6 } { 0456 } - { F7 } { 0457 } - { F8 } { 0458 } - { F9 } { 0459 } - { FA } { 045A } - { FB } { 045B } - { FC } { 045C } - { FD } { 00A7 } - { FE } { 045E } - { FF } { 045F } - } - { - } -% -% \end{macrocode} -% -% \begin{macrocode} -%<*iso88596> -\@@_declare_eight_bit_encoding:nnn { iso88596 } - { - { AC } { 060C } - { BB } { 061B } - { BF } { 061F } - { C1 } { 0621 } - { C2 } { 0622 } - { C3 } { 0623 } - { C4 } { 0624 } - { C5 } { 0625 } - { C6 } { 0626 } - { C7 } { 0627 } - { C8 } { 0628 } - { C9 } { 0629 } - { CA } { 062A } - { CB } { 062B } - { CC } { 062C } - { CD } { 062D } - { CE } { 062E } - { CF } { 062F } - { D0 } { 0630 } - { D1 } { 0631 } - { D2 } { 0632 } - { D3 } { 0633 } - { D4 } { 0634 } - { D5 } { 0635 } - { D6 } { 0636 } - { D7 } { 0637 } - { D8 } { 0638 } - { D9 } { 0639 } - { DA } { 063A } - { E0 } { 0640 } - { E1 } { 0641 } - { E2 } { 0642 } - { E3 } { 0643 } - { E4 } { 0644 } - { E5 } { 0645 } - { E6 } { 0646 } - { E7 } { 0647 } - { E8 } { 0648 } - { E9 } { 0649 } - { EA } { 064A } - { EB } { 064B } - { EC } { 064C } - { ED } { 064D } - { EE } { 064E } - { EF } { 064F } - { F0 } { 0650 } - { F1 } { 0651 } - { F2 } { 0652 } - } - { - { A1 } - { A2 } - { A3 } - { A5 } - { A6 } - { A7 } - { A8 } - { A9 } - { AA } - { AB } - { AE } - { AF } - { B0 } - { B1 } - { B2 } - { B3 } - { B4 } - { B5 } - { B6 } - { B7 } - { B8 } - { B9 } - { BA } - { BC } - { BD } - { BE } - { C0 } - { DB } - { DC } - { DD } - { DE } - { DF } - } -% -% \end{macrocode} -% -% \begin{macrocode} -%<*iso88597> -\@@_declare_eight_bit_encoding:nnn { iso88597 } - { - { A1 } { 2018 } - { A2 } { 2019 } - { A4 } { 20AC } - { A5 } { 20AF } - { AA } { 037A } - { AF } { 2015 } - { B4 } { 0384 } - { B5 } { 0385 } - { B6 } { 0386 } - { B8 } { 0388 } - { B9 } { 0389 } - { BA } { 038A } - { BC } { 038C } - { BE } { 038E } - { BF } { 038F } - { C0 } { 0390 } - { C1 } { 0391 } - { C2 } { 0392 } - { C3 } { 0393 } - { C4 } { 0394 } - { C5 } { 0395 } - { C6 } { 0396 } - { C7 } { 0397 } - { C8 } { 0398 } - { C9 } { 0399 } - { CA } { 039A } - { CB } { 039B } - { CC } { 039C } - { CD } { 039D } - { CE } { 039E } - { CF } { 039F } - { D0 } { 03A0 } - { D1 } { 03A1 } - { D3 } { 03A3 } - { D4 } { 03A4 } - { D5 } { 03A5 } - { D6 } { 03A6 } - { D7 } { 03A7 } - { D8 } { 03A8 } - { D9 } { 03A9 } - { DA } { 03AA } - { DB } { 03AB } - { DC } { 03AC } - { DD } { 03AD } - { DE } { 03AE } - { DF } { 03AF } - { E0 } { 03B0 } - { E1 } { 03B1 } - { E2 } { 03B2 } - { E3 } { 03B3 } - { E4 } { 03B4 } - { E5 } { 03B5 } - { E6 } { 03B6 } - { E7 } { 03B7 } - { E8 } { 03B8 } - { E9 } { 03B9 } - { EA } { 03BA } - { EB } { 03BB } - { EC } { 03BC } - { ED } { 03BD } - { EE } { 03BE } - { EF } { 03BF } - { F0 } { 03C0 } - { F1 } { 03C1 } - { F2 } { 03C2 } - { F3 } { 03C3 } - { F4 } { 03C4 } - { F5 } { 03C5 } - { F6 } { 03C6 } - { F7 } { 03C7 } - { F8 } { 03C8 } - { F9 } { 03C9 } - { FA } { 03CA } - { FB } { 03CB } - { FC } { 03CC } - { FD } { 03CD } - { FE } { 03CE } - } - { - { AE } - { D2 } - } -% -% \end{macrocode} -% -% \begin{macrocode} -%<*iso88598> -\@@_declare_eight_bit_encoding:nnn { iso88598 } - { - { AA } { 00D7 } - { BA } { 00F7 } - { DF } { 2017 } - { E0 } { 05D0 } - { E1 } { 05D1 } - { E2 } { 05D2 } - { E3 } { 05D3 } - { E4 } { 05D4 } - { E5 } { 05D5 } - { E6 } { 05D6 } - { E7 } { 05D7 } - { E8 } { 05D8 } - { E9 } { 05D9 } - { EA } { 05DA } - { EB } { 05DB } - { EC } { 05DC } - { ED } { 05DD } - { EE } { 05DE } - { EF } { 05DF } - { F0 } { 05E0 } - { F1 } { 05E1 } - { F2 } { 05E2 } - { F3 } { 05E3 } - { F4 } { 05E4 } - { F5 } { 05E5 } - { F6 } { 05E6 } - { F7 } { 05E7 } - { F8 } { 05E8 } - { F9 } { 05E9 } - { FA } { 05EA } - { FD } { 200E } - { FE } { 200F } - } - { - { A1 } - { BF } - { C0 } - { C1 } - { C2 } - { C3 } - { C4 } - { C5 } - { C6 } - { C7 } - { C8 } - { C9 } - { CA } - { CB } - { CC } - { CD } - { CE } - { CF } - { D0 } - { D1 } - { D2 } - { D3 } - { D4 } - { D5 } - { D6 } - { D7 } - { D8 } - { D9 } - { DA } - { DB } - { DC } - { DD } - { DE } - { FB } - { FC } - } -% -% \end{macrocode} -% -% \begin{macrocode} -%<*iso88599> -\@@_declare_eight_bit_encoding:nnn { iso88599 } - { - { D0 } { 011E } - { DD } { 0130 } - { DE } { 015E } - { F0 } { 011F } - { FD } { 0131 } - { FE } { 015F } - } - { - } -% -% \end{macrocode} -% -% \begin{macrocode} -%<*iso885910> -\@@_declare_eight_bit_encoding:nnn { iso885910 } - { - { A1 } { 0104 } - { A2 } { 0112 } - { A3 } { 0122 } - { A4 } { 012A } - { A5 } { 0128 } - { A6 } { 0136 } - { A8 } { 013B } - { A9 } { 0110 } - { AA } { 0160 } - { AB } { 0166 } - { AC } { 017D } - { AE } { 016A } - { AF } { 014A } - { B1 } { 0105 } - { B2 } { 0113 } - { B3 } { 0123 } - { B4 } { 012B } - { B5 } { 0129 } - { B6 } { 0137 } - { B8 } { 013C } - { B9 } { 0111 } - { BA } { 0161 } - { BB } { 0167 } - { BC } { 017E } - { BD } { 2015 } - { BE } { 016B } - { BF } { 014B } - { C0 } { 0100 } - { C7 } { 012E } - { C8 } { 010C } - { CA } { 0118 } - { CC } { 0116 } - { D1 } { 0145 } - { D2 } { 014C } - { D7 } { 0168 } - { D9 } { 0172 } - { E0 } { 0101 } - { E7 } { 012F } - { E8 } { 010D } - { EA } { 0119 } - { EC } { 0117 } - { F1 } { 0146 } - { F2 } { 014D } - { F7 } { 0169 } - { F9 } { 0173 } - { FF } { 0138 } - } - { - } -% -% \end{macrocode} -% -% \begin{macrocode} -%<*iso885911> -\@@_declare_eight_bit_encoding:nnn { iso885911 } - { - { A1 } { 0E01 } - { A2 } { 0E02 } - { A3 } { 0E03 } - { A4 } { 0E04 } - { A5 } { 0E05 } - { A6 } { 0E06 } - { A7 } { 0E07 } - { A8 } { 0E08 } - { A9 } { 0E09 } - { AA } { 0E0A } - { AB } { 0E0B } - { AC } { 0E0C } - { AD } { 0E0D } - { AE } { 0E0E } - { AF } { 0E0F } - { B0 } { 0E10 } - { B1 } { 0E11 } - { B2 } { 0E12 } - { B3 } { 0E13 } - { B4 } { 0E14 } - { B5 } { 0E15 } - { B6 } { 0E16 } - { B7 } { 0E17 } - { B8 } { 0E18 } - { B9 } { 0E19 } - { BA } { 0E1A } - { BB } { 0E1B } - { BC } { 0E1C } - { BD } { 0E1D } - { BE } { 0E1E } - { BF } { 0E1F } - { C0 } { 0E20 } - { C1 } { 0E21 } - { C2 } { 0E22 } - { C3 } { 0E23 } - { C4 } { 0E24 } - { C5 } { 0E25 } - { C6 } { 0E26 } - { C7 } { 0E27 } - { C8 } { 0E28 } - { C9 } { 0E29 } - { CA } { 0E2A } - { CB } { 0E2B } - { CC } { 0E2C } - { CD } { 0E2D } - { CE } { 0E2E } - { CF } { 0E2F } - { D0 } { 0E30 } - { D1 } { 0E31 } - { D2 } { 0E32 } - { D3 } { 0E33 } - { D4 } { 0E34 } - { D5 } { 0E35 } - { D6 } { 0E36 } - { D7 } { 0E37 } - { D8 } { 0E38 } - { D9 } { 0E39 } - { DA } { 0E3A } - { DF } { 0E3F } - { E0 } { 0E40 } - { E1 } { 0E41 } - { E2 } { 0E42 } - { E3 } { 0E43 } - { E4 } { 0E44 } - { E5 } { 0E45 } - { E6 } { 0E46 } - { E7 } { 0E47 } - { E8 } { 0E48 } - { E9 } { 0E49 } - { EA } { 0E4A } - { EB } { 0E4B } - { EC } { 0E4C } - { ED } { 0E4D } - { EE } { 0E4E } - { EF } { 0E4F } - { F0 } { 0E50 } - { F1 } { 0E51 } - { F2 } { 0E52 } - { F3 } { 0E53 } - { F4 } { 0E54 } - { F5 } { 0E55 } - { F6 } { 0E56 } - { F7 } { 0E57 } - { F8 } { 0E58 } - { F9 } { 0E59 } - { FA } { 0E5A } - { FB } { 0E5B } - } - { - { DB } - { DC } - { DD } - { DE } - } -% -% \end{macrocode} -% -% \begin{macrocode} -%<*iso885913> -\@@_declare_eight_bit_encoding:nnn { iso885913 } - { - { A1 } { 201D } - { A5 } { 201E } - { A8 } { 00D8 } - { AA } { 0156 } - { AF } { 00C6 } - { B4 } { 201C } - { B8 } { 00F8 } - { BA } { 0157 } - { BF } { 00E6 } - { C0 } { 0104 } - { C1 } { 012E } - { C2 } { 0100 } - { C3 } { 0106 } - { C6 } { 0118 } - { C7 } { 0112 } - { C8 } { 010C } - { CA } { 0179 } - { CB } { 0116 } - { CC } { 0122 } - { CD } { 0136 } - { CE } { 012A } - { CF } { 013B } - { D0 } { 0160 } - { D1 } { 0143 } - { D2 } { 0145 } - { D4 } { 014C } - { D8 } { 0172 } - { D9 } { 0141 } - { DA } { 015A } - { DB } { 016A } - { DD } { 017B } - { DE } { 017D } - { E0 } { 0105 } - { E1 } { 012F } - { E2 } { 0101 } - { E3 } { 0107 } - { E6 } { 0119 } - { E7 } { 0113 } - { E8 } { 010D } - { EA } { 017A } - { EB } { 0117 } - { EC } { 0123 } - { ED } { 0137 } - { EE } { 012B } - { EF } { 013C } - { F0 } { 0161 } - { F1 } { 0144 } - { F2 } { 0146 } - { F4 } { 014D } - { F8 } { 0173 } - { F9 } { 0142 } - { FA } { 015B } - { FB } { 016B } - { FD } { 017C } - { FE } { 017E } - { FF } { 2019 } - } - { - } -% -% \end{macrocode} -% -% \begin{macrocode} -%<*iso885914> -\@@_declare_eight_bit_encoding:nnn { iso885914 } - { - { A1 } { 1E02 } - { A2 } { 1E03 } - { A4 } { 010A } - { A5 } { 010B } - { A6 } { 1E0A } - { A8 } { 1E80 } - { AA } { 1E82 } - { AB } { 1E0B } - { AC } { 1EF2 } - { AF } { 0178 } - { B0 } { 1E1E } - { B1 } { 1E1F } - { B2 } { 0120 } - { B3 } { 0121 } - { B4 } { 1E40 } - { B5 } { 1E41 } - { B7 } { 1E56 } - { B8 } { 1E81 } - { B9 } { 1E57 } - { BA } { 1E83 } - { BB } { 1E60 } - { BC } { 1EF3 } - { BD } { 1E84 } - { BE } { 1E85 } - { BF } { 1E61 } - { D0 } { 0174 } - { D7 } { 1E6A } - { DE } { 0176 } - { F0 } { 0175 } - { F7 } { 1E6B } - { FE } { 0177 } - } - { - } -% -% \end{macrocode} -% -% \begin{macrocode} -%<*iso885915> -\@@_declare_eight_bit_encoding:nnn { iso885915 } - { - { A4 } { 20AC } - { A6 } { 0160 } - { A8 } { 0161 } - { B4 } { 017D } - { B8 } { 017E } - { BC } { 0152 } - { BD } { 0153 } - { BE } { 0178 } - } - { - } -% -% \end{macrocode} -% -% \begin{macrocode} -%<*iso885916> -\@@_declare_eight_bit_encoding:nnn { iso885916 } - { - { A1 } { 0104 } - { A2 } { 0105 } - { A3 } { 0141 } - { A4 } { 20AC } - { A5 } { 201E } - { A6 } { 0160 } - { A8 } { 0161 } - { AA } { 0218 } - { AC } { 0179 } - { AE } { 017A } - { AF } { 017B } - { B2 } { 010C } - { B3 } { 0142 } - { B4 } { 017D } - { B5 } { 201D } - { B8 } { 017E } - { B9 } { 010D } - { BA } { 0219 } - { BC } { 0152 } - { BD } { 0153 } - { BE } { 0178 } - { BF } { 017C } - { C3 } { 0102 } - { C5 } { 0106 } - { D0 } { 0110 } - { D1 } { 0143 } - { D5 } { 0150 } - { D7 } { 015A } - { D8 } { 0170 } - { DD } { 0118 } - { DE } { 021A } - { E3 } { 0103 } - { E5 } { 0107 } - { F0 } { 0111 } - { F1 } { 0144 } - { F5 } { 0151 } - { F7 } { 015B } - { F8 } { 0171 } - { FD } { 0119 } - { FE } { 021B } - } - { - } -% -% \end{macrocode} -% -% \end{implementation} -% -% \PrintIndex diff --git a/Master/texmf-dist/source/latex/l3experimental/l3str/l3str-format.dtx b/Master/texmf-dist/source/latex/l3experimental/l3str/l3str-format.dtx index 70448816fb3..1afe6ea2da4 100644 --- a/Master/texmf-dist/source/latex/l3experimental/l3str/l3str-format.dtx +++ b/Master/texmf-dist/source/latex/l3experimental/l3str/l3str-format.dtx @@ -48,7 +48,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % @@ -164,7 +164,7 @@ % % \begin{macrocode} %<*package> -\ProvidesExplPackage{l3str-format}{2019-05-28}{} +\ProvidesExplPackage{l3str-format}{2019-07-01}{} {L3 Experimental string formatting} % % \end{macrocode} diff --git a/Master/texmf-dist/source/latex/l3experimental/l3str/l3str.ins b/Master/texmf-dist/source/latex/l3experimental/l3str/l3str.ins index 959deb3b576..d3f00364e1c 100644 --- a/Master/texmf-dist/source/latex/l3experimental/l3str/l3str.ins +++ b/Master/texmf-dist/source/latex/l3experimental/l3str/l3str.ins @@ -53,41 +53,6 @@ and all files in that bundle must be distributed together. \keepsilent -\generate{\file{l3str-convert.sty} {\from{l3str-convert.dtx} {package}}} \generate{\file{l3str-format.sty} {\from{l3str-format.dtx} {package}}} -% Escapings. -\generate{% - \file{l3str-esc-hex.def} {\from{l3str-convert.dtx}{hex}}% - \file{l3str-esc-name.def} {\from{l3str-convert.dtx}{name}}% - \file{l3str-esc-string.def} {\from{l3str-convert.dtx}{string}}% - \file{l3str-esc-url.def} {\from{l3str-convert.dtx}{url}}% -} - -% UTF encodings. -\generate{% - \file{l3str-enc-utf8.def} {\from{l3str-convert.dtx}{utf8}}% - \file{l3str-enc-utf16.def} {\from{l3str-convert.dtx}{utf16}}% - \file{l3str-enc-utf32.def} {\from{l3str-convert.dtx}{utf32}}% -} - -% ISO-8859 encodings. -\generate{% - \file{l3str-enc-iso88591.def} {\from{l3str-convert.dtx}{iso88591}}% - \file{l3str-enc-iso88592.def} {\from{l3str-convert.dtx}{iso88592}}% - \file{l3str-enc-iso88593.def} {\from{l3str-convert.dtx}{iso88593}}% - \file{l3str-enc-iso88594.def} {\from{l3str-convert.dtx}{iso88594}}% - \file{l3str-enc-iso88595.def} {\from{l3str-convert.dtx}{iso88595}}% - \file{l3str-enc-iso88596.def} {\from{l3str-convert.dtx}{iso88596}}% - \file{l3str-enc-iso88597.def} {\from{l3str-convert.dtx}{iso88597}}% - \file{l3str-enc-iso88598.def} {\from{l3str-convert.dtx}{iso88598}}% - \file{l3str-enc-iso88599.def} {\from{l3str-convert.dtx}{iso88599}}% - \file{l3str-enc-iso885910.def} {\from{l3str-convert.dtx}{iso885910}}% - \file{l3str-enc-iso885911.def} {\from{l3str-convert.dtx}{iso885911}}% - \file{l3str-enc-iso885913.def} {\from{l3str-convert.dtx}{iso885913}}% - \file{l3str-enc-iso885914.def} {\from{l3str-convert.dtx}{iso885914}}% - \file{l3str-enc-iso885915.def} {\from{l3str-convert.dtx}{iso885915}}% - \file{l3str-enc-iso885916.def} {\from{l3str-convert.dtx}{iso885916}}% -} - \endbatchfile diff --git a/Master/texmf-dist/source/latex/l3experimental/l3sys-shell/l3sys-shell.dtx b/Master/texmf-dist/source/latex/l3experimental/l3sys-shell/l3sys-shell.dtx index 64ab863d807..da41be80f00 100644 --- a/Master/texmf-dist/source/latex/l3experimental/l3sys-shell/l3sys-shell.dtx +++ b/Master/texmf-dist/source/latex/l3experimental/l3sys-shell/l3sys-shell.dtx @@ -46,7 +46,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % @@ -136,7 +136,7 @@ % % \begin{macrocode} %<*package> -\ProvidesExplPackage{l3sys-shell}{2019-05-28}{} +\ProvidesExplPackage{l3sys-shell}{2019-07-01}{} {L3 Experimental system shell functions} % % \end{macrocode} diff --git a/Master/texmf-dist/source/latex/l3experimental/xcoffins/xcoffins.dtx b/Master/texmf-dist/source/latex/l3experimental/xcoffins/xcoffins.dtx index 59860d70d1d..a86d0701923 100644 --- a/Master/texmf-dist/source/latex/l3experimental/xcoffins/xcoffins.dtx +++ b/Master/texmf-dist/source/latex/l3experimental/xcoffins/xcoffins.dtx @@ -56,7 +56,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % @@ -675,7 +675,7 @@ % \end{macrocode} % % \begin{macrocode} -\ProvidesExplPackage{xcoffins}{2019-05-28}{} +\ProvidesExplPackage{xcoffins}{2019-07-01}{} {L3 Experimental design level coffins} % \end{macrocode} % diff --git a/Master/texmf-dist/source/latex/l3experimental/xgalley/l3galley.dtx b/Master/texmf-dist/source/latex/l3experimental/xgalley/l3galley.dtx index 716bea363ab..34dade048a3 100644 --- a/Master/texmf-dist/source/latex/l3experimental/xgalley/l3galley.dtx +++ b/Master/texmf-dist/source/latex/l3experimental/xgalley/l3galley.dtx @@ -61,7 +61,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % @@ -687,7 +687,7 @@ % % \begin{macrocode} %<*package> -\ProvidesExplPackage{l3galley}{2019-05-28}{} +\ProvidesExplPackage{l3galley}{2019-07-01}{} {L3 Experimental galley code} % % \end{macrocode} diff --git a/Master/texmf-dist/source/latex/l3experimental/xgalley/xgalley.dtx b/Master/texmf-dist/source/latex/l3experimental/xgalley/xgalley.dtx index deefd7a4416..e10cb7b13b6 100644 --- a/Master/texmf-dist/source/latex/l3experimental/xgalley/xgalley.dtx +++ b/Master/texmf-dist/source/latex/l3experimental/xgalley/xgalley.dtx @@ -47,7 +47,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % @@ -734,7 +734,7 @@ % \end{macrocode} % % \begin{macrocode} -\ProvidesExplPackage{xgalley}{2019-05-28}{} +\ProvidesExplPackage{xgalley}{2019-07-01}{} {L3 Experimental galley} \RequirePackage{xparse,xtemplate,l3galley} % \end{macrocode} diff --git a/Master/texmf-dist/source/latex/l3kernel/expl3.dtx b/Master/texmf-dist/source/latex/l3kernel/expl3.dtx index 72c1d220e18..b1dd621fda6 100644 --- a/Master/texmf-dist/source/latex/l3kernel/expl3.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/expl3.dtx @@ -23,7 +23,7 @@ % for those people who are interested. % %<*driver|generic|package> -\def\ExplFileDate{2019-05-28}% +\def\ExplFileDate{2019-07-01}% % %<*driver> \documentclass[full]{l3doc} @@ -51,7 +51,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % @@ -1521,7 +1521,8 @@ \ProvidesFile {#1} [ #2~v#3~#4 ] } \tl_const:Nn \c__expl_def_ext_tl { def } - \@onefilewithoptions { l3 \l__expl_driver_tl } [ ] [ ] \c__expl_def_ext_tl + \@onefilewithoptions { l3backend- \l__expl_driver_tl } [ ] [ ] + \c__expl_def_ext_tl } % \end{macrocode} % @@ -1728,7 +1729,7 @@ \iow_log:x { File:~#1~#2~v#3~#4 } } \tex_input:D - l3 + l3backend \sys_if_engine_xetex:TF { xdvipdfmx } { diff --git a/Master/texmf-dist/source/latex/l3kernel/l3.ins b/Master/texmf-dist/source/latex/l3kernel/l3.ins index 7977e037451..8affab2c2d5 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3.ins +++ b/Master/texmf-dist/source/latex/l3kernel/l3.ins @@ -96,6 +96,7 @@ and all files in that bundle must be distributed together. \from{l3fp-random.dtx} {package} \from{l3fparray.dtx} {package} \from{l3sort.dtx} {package} + \from{l3str-convert.dtx}{package} \from{l3tl-analysis.dtx}{package} \from{l3regex.dtx} {package} \from{l3box.dtx} {package} @@ -116,71 +117,24 @@ and all files in that bundle must be distributed together. % not distributed: %\generate{\file{l3doc.ist} {\from{l3doc.dtx} {docist}}} -\generate - { - \file{l3dvipdfmx.def} - { - \from{l3drivers.dtx} {package,dvipdfmx} - \from{l3drivers-basics.dtx} {package,dvipdfmx} - \from{l3drivers-color.dtx} {package,dvipdfmx} - \from{l3drivers-box.dtx} {package,dvipdfmx} - \from{l3drivers-draw.dtx} {package,dvipdfmx} - \from{l3drivers-graphics.dtx}{package,dvipdfmx} - \from{l3drivers-pdf.dtx} {package,dvipdfmx} - } - } -\generate - { - \file{l3dvips.def} - { - \from{l3drivers.dtx} {package,dvips} - \from{l3drivers-basics.dtx} {package,dvips} - \from{l3drivers-color.dtx} {package,dvips} - \from{l3drivers-box.dtx} {package,dvips} - \from{l3drivers-draw.dtx} {package,dvips} - \from{l3drivers-graphics.dtx}{package,dvips} - \from{l3drivers-pdf.dtx} {package,dvips} - } - } -\generate - { - \file{l3dvisvgm.def} - { - \from{l3drivers.dtx} {package,dvisvgm} - \from{l3drivers-basics.dtx} {package,dvisvgm} - \from{l3drivers-color.dtx} {package,dvisvgm} - \from{l3drivers-box.dtx} {package,dvisvgm} - \from{l3drivers-draw.dtx} {package,dvisvgm} - \from{l3drivers-graphics.dtx}{package,dvisvgm} - \from{l3drivers-pdf.dtx} {package,dvisvgm} - } - } -\generate - { - \file{l3pdfmode.def} - { - \from{l3drivers.dtx} {package,pdfmode} - \from{l3drivers-basics.dtx} {package,pdfmode} - \from{l3drivers-color.dtx} {package,pdfmode} - \from{l3drivers-box.dtx} {package,pdfmode} - \from{l3drivers-draw.dtx} {package,pdfmode} - \from{l3drivers-graphics.dtx}{package,pdfmode} - \from{l3drivers-pdf.dtx} {package,pdfmode} - } - } -\generate - { - \file{l3xdvipdfmx.def} - { - \from{l3drivers.dtx} {package,xdvipdfmx} - \from{l3drivers-basics.dtx} {package,xdvipdfmx} - \from{l3drivers-color.dtx} {package,xdvipdfmx} - \from{l3drivers-box.dtx} {package,xdvipdfmx} - \from{l3drivers-draw.dtx} {package,xdvipdfmx} - \from{l3drivers-graphics.dtx}{package,xdvipdfmx} - \from{l3drivers-pdf.dtx} {package,xdvipdfmx} - } - } +% ISO-8859 encodings. +\generate{% + \file{l3str-enc-iso88591.def} {\from{l3str-convert.dtx}{iso88591}}% + \file{l3str-enc-iso88592.def} {\from{l3str-convert.dtx}{iso88592}}% + \file{l3str-enc-iso88593.def} {\from{l3str-convert.dtx}{iso88593}}% + \file{l3str-enc-iso88594.def} {\from{l3str-convert.dtx}{iso88594}}% + \file{l3str-enc-iso88595.def} {\from{l3str-convert.dtx}{iso88595}}% + \file{l3str-enc-iso88596.def} {\from{l3str-convert.dtx}{iso88596}}% + \file{l3str-enc-iso88597.def} {\from{l3str-convert.dtx}{iso88597}}% + \file{l3str-enc-iso88598.def} {\from{l3str-convert.dtx}{iso88598}}% + \file{l3str-enc-iso88599.def} {\from{l3str-convert.dtx}{iso88599}}% + \file{l3str-enc-iso885910.def} {\from{l3str-convert.dtx}{iso885910}}% + \file{l3str-enc-iso885911.def} {\from{l3str-convert.dtx}{iso885911}}% + \file{l3str-enc-iso885913.def} {\from{l3str-convert.dtx}{iso885913}}% + \file{l3str-enc-iso885914.def} {\from{l3str-convert.dtx}{iso885914}}% + \file{l3str-enc-iso885915.def} {\from{l3str-convert.dtx}{iso885915}}% + \file{l3str-enc-iso885916.def} {\from{l3str-convert.dtx}{iso885916}}% +} \generate{\file{l3docstrip.tex} {\from{l3docstrip.dtx} {program}}} diff --git a/Master/texmf-dist/source/latex/l3kernel/l3alloc.dtx b/Master/texmf-dist/source/latex/l3kernel/l3alloc.dtx index 01fcdcf977e..f83a3e1981a 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3alloc.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3alloc.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3basics.dtx b/Master/texmf-dist/source/latex/l3kernel/l3basics.dtx index 188fbfd0f8d..85443ca382d 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3basics.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3basics.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % @@ -990,6 +990,17 @@ % is removed. % \end{function} % +% \begin{function}[EXP, added = 2019-06-02]{\use_ii_i:nn} +% \begin{syntax} +% \cs{use_ii_i:nnn} \Arg{arg_1} \Arg{arg_2} +% \end{syntax} +% This function absorbs two arguments and leaves the content of the +% second and first in the input stream. The category code of +% these tokens is also fixed (if it has not already been by +% some other absorption). A single expansion is needed for the +% function to take effect. +% \end{function} +% % \begin{function}[EXP] % { % \use_none:n , @@ -1597,6 +1608,13 @@ % \end{macrocode} % \end{macro} % +% \begin{macro}[EXP]{\use_ii_i:nn} +% \begin{macrocode} +\cs_set:Npn \use_ii_i:nn #1#2 { #2 #1 } +% \end{macrocode} +% \end{macro} +% +% % \begin{macro}[EXP] % { % \use_none_delimit_by_q_nil:w , diff --git a/Master/texmf-dist/source/latex/l3kernel/l3bootstrap.dtx b/Master/texmf-dist/source/latex/l3kernel/l3bootstrap.dtx index ffda0047028..611b830c52e 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3bootstrap.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3bootstrap.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3box.dtx b/Master/texmf-dist/source/latex/l3kernel/l3box.dtx index 91eb4593b05..3a67fc2718c 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3box.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3box.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % @@ -1796,7 +1796,7 @@ \tex_kern:D -\l_@@_left_new_dim \hbox:n { - \driver_box_use_rotate:Nn + \@@_backend_rotate:Nn \l_@@_internal_box \l_@@_angle_fp } @@ -2224,7 +2224,7 @@ { \hbox_set:Nn \l_@@_internal_box { - \driver_box_use_scale:Nnn + \@@_backend_scale:Nnn #1 \l_@@_scale_x_fp \l_@@_scale_y_fp diff --git a/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx b/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx index de5a5011bb8..4014877d525 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx @@ -44,7 +44,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % @@ -1373,10 +1373,10 @@ % A wrapper around the driver-dependent code. % \begin{macrocode} \cs_new_protected:Npn \box_clip:N #1 - { \hbox_set:Nn #1 { \driver_box_use_clip:N #1 } } + { \hbox_set:Nn #1 { \@@_backend_clip:N #1 } } \cs_generate_variant:Nn \box_clip:N { c } \cs_new_protected:Npn \box_gclip:N #1 - { \hbox_gset:Nn #1 { \driver_box_use_clip:N #1 } } + { \hbox_gset:Nn #1 { \@@_backend_clip:N #1 } } \cs_generate_variant:Nn \box_gclip:N { c } % \end{macrocode} % \end{macro} diff --git a/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx b/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx index fe91c5a5baf..b905161ae9a 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx @@ -44,7 +44,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3coffins.dtx b/Master/texmf-dist/source/latex/l3kernel/l3coffins.dtx index 0aaadefe1a0..901a5b7b8d2 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3coffins.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3coffins.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % @@ -1960,7 +1960,7 @@ \cs_generate_variant:Nn \coffin_attach:NnnNnnnn { c , Nnnc , cnnc } \cs_new_protected:Npn \coffin_gattach:NnnNnnnn #1#2#3#4#5#6#7#8 { - \@@_gattach:NnnNnnnnN #1 {#2} {#3} #4 {#5} {#6} {#7} {#8} + \@@_attach:NnnNnnnnN #1 {#2} {#3} #4 {#5} {#6} {#7} {#8} \coffin_gset_eq:NN } \cs_generate_variant:Nn \coffin_gattach:NnnNnnnn { c , Nnnc , cnnc } diff --git a/Master/texmf-dist/source/latex/l3kernel/l3color-base.dtx b/Master/texmf-dist/source/latex/l3kernel/l3color-base.dtx index 0773fc95a4a..781c6693e7b 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3color-base.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3color-base.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % @@ -140,7 +140,7 @@ \cs_new_protected:Npn \color_ensure_current: { %<*package> - \driver_color_pickup:N \l_@@_current_tl + \@@_backend_pickup:N \l_@@_current_tl % \@@_select:V \l_@@_current_tl } @@ -161,13 +161,13 @@ \cs_new_protected:Npn \@@_select:w #1 ~ #2 \q_stop { \use:c { @@_select_ #1 :w } #2 \q_stop } \cs_new_protected:Npn \@@_select_cmyk:w #1 ~ #2 ~ #3 ~ #4 \q_stop - { \driver_color_cmyk:nnnn {#1} {#2} {#3} {#4} } + { \@@_backend_cmyk:nnnn {#1} {#2} {#3} {#4} } \cs_new_protected:Npn \@@_select_gray:w #1 \q_stop - { \driver_color_gray:n {#1} } + { \@@_backend_gray:n {#1} } \cs_new_protected:Npn \@@_select_rgb:w #1 ~ #2 ~ #3 \q_stop - { \driver_color_rgb:nnn {#1} {#2} {#3} } + { \@@_backend_rgb:nnn {#1} {#2} {#3} } \cs_new_protected:Npn \@@_select_spot:w #1 ~ #2 \q_stop - { \driver_color_spot:nn {#1} {#2} } + { \@@_backend_spot:nn {#1} {#2} } % \end{macrocode} % \end{macro} % \end{macro} diff --git a/Master/texmf-dist/source/latex/l3kernel/l3deprecation.dtx b/Master/texmf-dist/source/latex/l3kernel/l3deprecation.dtx index 12b990b8d53..11b3cfc8214 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3deprecation.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3deprecation.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3doc.dtx b/Master/texmf-dist/source/latex/l3kernel/l3doc.dtx index 1bbc500dc1a..bfac8aa6125 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3doc.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3doc.dtx @@ -79,7 +79,7 @@ and all files in that bundle must be distributed together. % % \title{The \cls{l3doc} class} % \author{\Team} -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % \maketitle % \tableofcontents % @@ -3786,9 +3786,9 @@ and all files in that bundle must be distributed together. % name automatically. We need to be careful: no |<@@=| should appear % as such in the code below since \pkg{l3doc} is also typeset using % this code. -% TODO: right now, in a line containing |<@@=|\meta{module}|>|, the -% |@@| are replaced (using different values of the \meta{module} -% before and after the assignment). Is this a waste? +% At each |<@@=| found, replace the \meta{module} in the code behind +% it, update the \meta{module}, and loop to check for further +% occurrences of |<@@=|. % \begin{macrocode} \group_begin: \char_set_catcode_other:N \^^A @@ -3813,8 +3813,9 @@ and all files in that bundle must be distributed together. \char_set_catcode_active:N \> \cs_new_protected:Npn \@@_xmacro_code:n #1 { + \tl_clear:N \l_@@_tmpa_tl \tl_if_in:nnTF {#1} { < @ @ = } - { \@@_xmacro_code:w #1 \q_stop } + { \@@_xmacro_code:w #1 < @ @ = \q_recursion_tail > \q_recursion_stop } { \tl_set:Nn \l_@@_tmpa_tl {#1} \@@_detect_internals:N \l_@@_tmpa_tl @@ -3822,21 +3823,21 @@ and all files in that bundle must be distributed together. \tl_use:N \l_@@_tmpa_tl } } - \cs_new_protected:Npn \@@_xmacro_code:w #1 < @ @ = #2 > #3 \q_stop + \cs_new_protected:Npn \@@_xmacro_code:w #1 < @ @ = #2 > { - \tl_set:Nn \l_@@_tmpa_tl {#1} - \@@_detect_internals:N \l_@@_tmpa_tl - \@@_replace_at_at:N \l_@@_tmpa_tl - - \tl_gset:Nn \g_@@_module_name_tl {#2} - \tl_put_right:Nn \l_@@_tmpa_tl { < \text { \verbatim@font @ @ = #2 } > } - - \tl_set:Nn \l_@@_tmpb_tl {#3} + % Add code before <@@=...> + \tl_set:Nn \l_@@_tmpb_tl {#1} \@@_detect_internals:N \l_@@_tmpb_tl \@@_replace_at_at:N \l_@@_tmpb_tl - \tl_put_right:No \l_@@_tmpa_tl { \l_@@_tmpb_tl } - - \tl_use:N \l_@@_tmpa_tl + \tl_put_right:NV \l_@@_tmpa_tl \l_@@_tmpb_tl + % Check for \q_recursion_tail + \quark_if_recursion_tail_stop_do:nn {#2} + { \tl_use:N \l_@@_tmpa_tl } + % Change module name and add <@@=#2> to typeset output + \tl_gset:Nn \g_@@_module_name_tl {#2} + \tl_put_right:Nn \l_@@_tmpa_tl { < \text { \verbatim@font @ @ = #2 } > } + % Loop + \@@_xmacro_code:w } \group_end: % \end{macrocode} diff --git a/Master/texmf-dist/source/latex/l3kernel/l3docstrip.dtx b/Master/texmf-dist/source/latex/l3kernel/l3docstrip.dtx index 9265e066746..00d5e43d4f2 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3docstrip.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3docstrip.dtx @@ -63,7 +63,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3drivers-basics.dtx b/Master/texmf-dist/source/latex/l3kernel/l3drivers-basics.dtx deleted file mode 100644 index 2ff21a9d65b..00000000000 --- a/Master/texmf-dist/source/latex/l3kernel/l3drivers-basics.dtx +++ /dev/null @@ -1,373 +0,0 @@ -% \iffalse meta-comment -% -%% File: l3drivers-basics.dtx -% -% Copyright (C) 2011-2019 The LaTeX3 Project -% -% It may be distributed and/or modified under the conditions of the -% LaTeX Project Public License (LPPL), either version 1.3c of this -% license or (at your option) any later version. The latest version -% of this license is in the file -% -% https://www.latex-project.org/lppl.txt -% -% This file is part of the "l3kernel bundle" (The Work in LPPL) -% and all files in that bundle must be distributed together. -% -% ----------------------------------------------------------------------- -% -% The development version of the bundle can be found at -% -% https://github.com/latex3/latex3 -% -% for those people who are interested. -% -%<*driver> -\documentclass[full,kernel]{l3doc} -\begin{document} - \DocInput{\jobname.dtx} -\end{document} -% -% \fi -% -% \title{^^A -% The \textsf{l3drivers-basics} package\\ Driver basics^^A -% } -% -% \author{^^A -% The \LaTeX3 Project\thanks -% {^^A -% E-mail: -% \href{mailto:latex-team@latex-project.org} -% {latex-team@latex-project.org}^^A -% }^^A -% } -% -% \date{Released 2019-05-28} -% -% \maketitle -% -% \begin{documentation} -% -% \end{documentation} -% -% \begin{implementation} -% -% \section{\pkg{l3drivers-basics} Implementation} -% -% \begin{macrocode} -%<*initex|package> -%<@@=driver> -% \end{macrocode} -% -% Whilst there is a reasonable amount of code overlap between drivers, -% it is much clearer to have the blocks more-or-less separated than run -% in together and DocStripped out in parts. As such, most of the following -% is set up on a per-driver basis, though there is some common code (again -% given in blocks not interspersed with other material). -% -% All the file identifiers are up-front so that they come out in the right -% place in the files. -% \begin{macrocode} -%<*package> -\ProvidesExplFile -%<*dvipdfmx> - {l3dvipdfmx.def}{2019-04-06}{} - {L3 Experimental driver: dvipdfmx} -% -%<*dvips> - {l3dvips.def}{2019-04-06}{} - {L3 Experimental driver: dvips} -% -%<*dvisvgm> - {l3dvisvgm.def}{2019-04-06}{} - {L3 Experimental driver: dvisvgm} -% -%<*pdfmode> - {l3pdfmode.def}{2019-04-06}{} - {L3 Experimental driver: PDF mode} -% -%<*xdvipdfmx> - {l3xdvipdfmx.def}{2019-04-06}{} - {L3 Experimental driver: xdvipdfmx} -% -% -% \end{macrocode} -% -% The order of the driver code here is such that we get somewhat logical -% outcomes in terms of code sharing whilst keeping things readable. (Trying to -% mix all of the code by concept is almost unmanageable.) The key parts which -% are shared are -% \begin{itemize} -% \item Color support is either \texttt{dvips}-like or \texttt{pdfmode}-like. -% \item \texttt{pdfmode} and \texttt{(x)dvipdfmx} share drawing routines. -% \item \texttt{xdvipdfmx} is largely the same as \texttt{dvipdfmx} so -% takes most of the same code. -% \end{itemize} -% -% \begin{macro}{\@@_literal:e, \@@_literal:n, \@@_literal:x} -% The one shared function for all drivers is access to the basic -% \tn{special} primitive: it has slightly odd expansion behaviour -% so a wrapper is provided. -% \begin{macrocode} -\cs_new_eq:NN \@@_literal:e \tex_special:D -\cs_new_protected:Npn \@@_literal:n #1 - { \@@_literal:e { \exp_not:n {#1} } } -\cs_generate_variant:Nn \@@_literal:n { x } -% \end{macrocode} -% \end{macro} -% -% \begin{variable}{\l_@@_internal_box} -% A scratch box. -% \begin{macrocode} -\box_new:N \l_@@_internal_box -% \end{macrocode} -% \end{variable} -% -% \subsection{\texttt{dvips} driver} -% -% \begin{macrocode} -%<*dvips> -% \end{macrocode} -% -% \begin{macro}{\@@_literal_postscript:n, \@@_literal_postscript:x} -% Literal PostScript can be included using a few low-level formats. Here, -% we use the form with no positioning: this is overall more convenient as -% a wrapper. Note that this does require that where position is important, -% an appropriate wrapper is included. -% \begin{macrocode} -\cs_new_protected:Npn \@@_literal_postscript:n #1 - { \@@_literal:n { ps:: #1 } } -\cs_generate_variant:Nn \@@_literal_postscript:n { x } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\@@_postscript:n, \@@_postscript:x} -% PostScript data that does have positioning, and also applying -% a shift to |SDict| (which is not done automatically by -% |ps:| or |ps::|, in contrast to |!| or |"|). -% \begin{macrocode} -\cs_new_protected:Npn \@@_postscript:n #1 - { \@@_literal:n { ps: SDict ~ begin ~ #1 ~ end } } -\cs_generate_variant:Nn \@@_postscript:n { x } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\@@_postscript_header:n} -% PostScript for the header: a small saving but makes the code clearer. -% This is held until the start of shipout such that a document with no -% actual output does not write anything. -% \begin{macrocode} -\cs_new_protected:Npx \@@_postscript_header:n #1 -%<*initex> - { \@@_literal:n { ! #1 } } -% -%<*package> - { - \cs_if_exist:NTF \AtBeginDvi - { \exp_not:N \AtBeginDvi } - { \use:n } - { \@@_literal:n { ! #1 } } - } -% -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\@@_align_currentpoint_begin:, \@@_align_currentpoint_end:} -% In \texttt{dvips} there is no build-in saving of the current -% position, and so some additional PostScript is required to set up the -% transformation matrix and also to restore it afterwards. Notice the use -% of the stack to save the current position \enquote{up front} and to -% move back to it at the end of the process. Notice that the |[begin]|/^^A -% |[end]| pair here mean that we can use a run of PostScript statements -% in separate lines: not \emph{required} but does make the code and -% output more clear. -% \begin{macrocode} -\cs_new_protected:Npn \@@_align_currentpoint_begin: - { - \@@_literal:n { ps::[begin] } - \@@_literal_postscript:n { currentpoint } - \@@_literal_postscript:n { currentpoint~translate } - } -\cs_new_protected:Npn \@@_align_currentpoint_end: - { - \@@_literal_postscript:n { neg~exch~neg~exch~translate } - \@@_literal:n { ps::[end] } - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\@@_scope_begin:, \@@_scope_end:} -% Saving/restoring scope for general operations needs to be done with -% \texttt{dvips} positioning (try without to see this!). Thus we need the -% |ps:| version of the special here. As only the graphics state is ever -% altered within this pairing, we use the lower-cost |g|-versions. -% \begin{macrocode} -\cs_new_protected:Npn \@@_scope_begin: - { \@@_literal:n { ps:gsave } } -\cs_new_protected:Npn \@@_scope_end: - { \@@_literal:n { ps:grestore } } -% \end{macrocode} -% \end{macro} -% -% \begin{macrocode} -% -% \end{macrocode} -% -% \subsection{\texttt{pdfmode} driver} -% -% \begin{macrocode} -%<*pdfmode> -% \end{macrocode} -% -% The direct PDF driver covers both \pdfTeX{} and \LuaTeX{}. The latter -% renames and restructures the driver primitives but this can be handled -% at one level of abstraction. As such, we avoid using two separate drivers -% for this material at the cost of some \texttt{x}-type definitions to get -% everything expanded up-front. -% -% \begin{macro}{\@@_literal_pdf:n, \@@_literal_pdf:x} -% This is equivalent to \verb|\special{pdf:}| but the engine can -% track it. Without the \texttt{direct} keyword everything is kept in -% sync: the transformation matrix is set to the current point automatically. -% Note that this is still inside the text (\texttt{BT} \dots \texttt{ET} -% block). -% \begin{macrocode} -\cs_new_protected:Npx \@@_literal_pdf:n #1 - { - \cs_if_exist:NTF \tex_pdfextension:D - { \tex_pdfextension:D literal } - { \tex_pdfliteral:D } - { \exp_not:N \exp_not:n {#1} } - } -\cs_generate_variant:Nn \@@_literal_pdf:n { x } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\@@_scope_begin:, \@@_scope_end:} -% Higher-level interfaces for saving and restoring the graphic state. -% \begin{macrocode} -\cs_new_protected:Npx \@@_scope_begin: - { - \cs_if_exist:NTF \tex_pdfextension:D - { \tex_pdfextension:D save \scan_stop: } - { \tex_pdfsave:D } - } -\cs_new_protected:Npx \@@_scope_end: - { - \cs_if_exist:NTF \tex_pdfextension:D - { \tex_pdfextension:D restore \scan_stop: } - { \tex_pdfrestore:D } - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\@@_matrix:n, \@@_matrix:x} -% Here the appropriate function is set up to insert an affine matrix -% into the PDF. With \pdfTeX{} and \LuaTeX{} in direct PDF output mode there -% is a primitive for this, which only needs the rotation/scaling/skew part. -% \begin{macrocode} -\cs_new_protected:Npx \@@_matrix:n #1 - { - \cs_if_exist:NTF \tex_pdfextension:D - { \tex_pdfextension:D setmatrix } - { \tex_pdfsetmatrix:D } - { \exp_not:N \exp_not:n {#1} } - } -\cs_generate_variant:Nn \@@_matrix:n { x } -% \end{macrocode} -% \end{macro} -% -% \begin{macrocode} -% -% \end{macrocode} -% -% \subsection{\texttt{dvipdfmx} driver} -% -% \begin{macrocode} -%<*dvipdfmx|xdvipdfmx> -% \end{macrocode} -% -% The \texttt{dvipdfmx} shares code with the PDF mode one (using the common -% section to this file) but also with \texttt{xdvipdfmx}. The latter is close -% to identical to \texttt{dvipdfmx} and so all of the code here is extracted -% for both drivers, with some \texttt{clean up} for \texttt{xdvipdfmx} as -% required. -% -% \begin{macro}{\@@_literal_pdf:n, \@@_literal_pdf:x} -% Equivalent to \texttt{pdf:content} but favored as the link to -% the \pdfTeX{} primitive approach is clearer. -% \begin{macrocode} -\cs_new_protected:Npn \@@_literal_pdf:n #1 - { \@@_literal:n { pdf:literal~ #1 } } -\cs_generate_variant:Nn \@@_literal_pdf:n { x } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\@@_scope_begin:, \@@_scope_end:} -% Scoping is done using the driver-specific specials. -% \begin{macrocode} -\cs_new_protected:Npn \@@_scope_begin: - { \@@_literal:n { x:gsave } } -\cs_new_protected:Npn \@@_scope_end: - { \@@_literal:n { x:grestore } } -% \end{macrocode} -% \end{macro} -% -% \begin{macrocode} -% -% \end{macrocode} -% -% \subsection{\texttt{dvisvgm} driver} -% -% \begin{macrocode} -%<*dvisvgm> -% \end{macrocode} -% -% \begin{macro}{\@@_literal_svg:n, \@@_literal_svg:x} -% Unlike the other drivers, the requirements for making SVG files mean -% that we can't conveniently transform all operations to the current point. -% That makes life a bit more tricky later as that needs to be accounted for. -% A new line is added after each call to help to keep the output readable -% for debugging. -% \begin{macrocode} -\cs_new_protected:Npn \@@_literal_svg:n #1 - { \@@_literal:n { dvisvgm:raw~ #1 { ?nl } } } -\cs_generate_variant:Nn \@@_literal_svg:n { x } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\@@_scope_begin:, \@@_scope_end:} -% A scope in SVG terms is slightly different to the other drivers as -% operations have to be \enquote{tied} to these not simply inside them. -% \begin{macrocode} -\cs_new_protected:Npn \@@_scope_begin: - { \@@_literal_svg:n { } } -\cs_new_protected:Npn \@@_scope_end: - { \@@_literal_svg:n { } } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\@@_scope_begin:n, \@@_scope_begin:x} -% In SVG transformations, clips and so on are attached directly to scopes so -% we need a way or allowing for that. This is rather more useful than -% \cs{@@_scope_begin:} as a result. No assumptions are made about the nature -% of the scoped operation(s). -% \begin{macrocode} -\cs_new_protected:Npn \@@_scope_begin:n #1 - { \@@_literal_svg:n { } } -\cs_generate_variant:Nn \@@_scope_begin:n { x } -% \end{macrocode} -% \end{macro} -% -% \begin{macrocode} -% -% \end{macrocode} -% -% \begin{macrocode} -% -% \end{macrocode} -% -% \end{implementation} -% -% \PrintIndex diff --git a/Master/texmf-dist/source/latex/l3kernel/l3drivers-box.dtx b/Master/texmf-dist/source/latex/l3kernel/l3drivers-box.dtx deleted file mode 100644 index 945a93dc6ef..00000000000 --- a/Master/texmf-dist/source/latex/l3kernel/l3drivers-box.dtx +++ /dev/null @@ -1,473 +0,0 @@ -% \iffalse meta-comment -% -%% File: l3drivers-box.dtx -% -% Copyright (C) 2011-2019 The LaTeX3 Project -% -% It may be distributed and/or modified under the conditions of the -% LaTeX Project Public License (LPPL), either version 1.3c of this -% license or (at your option) any later version. The latest version -% of this license is in the file -% -% https://www.latex-project.org/lppl.txt -% -% This file is part of the "l3kernel bundle" (The Work in LPPL) -% and all files in that bundle must be distributed together. -% -% ----------------------------------------------------------------------- -% -% The development version of the bundle can be found at -% -% https://github.com/latex3/latex3 -% -% for those people who are interested. -% -%<*driver> -\documentclass[full,kernel]{l3doc} -\begin{document} - \DocInput{\jobname.dtx} -\end{document} -% -% \fi -% -% \title{^^A -% The \textsf{l3drivers-box} package\\ Driver box support^^A -% } -% -% \author{^^A -% The \LaTeX3 Project\thanks -% {^^A -% E-mail: -% \href{mailto:latex-team@latex-project.org} -% {latex-team@latex-project.org}^^A -% }^^A -% } -% -% \date{Released 2019-05-28} -% -% \maketitle -% -% \begin{documentation} -% -% \end{documentation} -% -% \begin{implementation} -% -% \section{\pkg{l3drivers-box} Implementation} -% -% \begin{macrocode} -%<*initex|package> -%<@@=driver> -% \end{macrocode} -% -% \subsection{\texttt{dvips} driver} -% -% \begin{macrocode} -%<*dvips> -% \end{macrocode} -% -% \begin{macro}{\driver_box_use_clip:N} -% The \texttt{dvips} driver scales all absolute dimensions based on the -% output resolution selected and any \TeX{} magnification. Thus for any -% operation involving absolute lengths there is a correction to make. See -% \texttt{normalscale} from \texttt{special.pro} for the variables, noting -% that here everything is saved on the stack rather than as a separate -% variable. Once all of that is done, the actual clipping is trivial. -% \begin{macrocode} -\cs_new_protected:Npn \driver_box_use_clip:N #1 - { - \@@_scope_begin: - \@@_align_currentpoint_begin: - \@@_literal_postscript:n { matrix~currentmatrix } - \@@_literal_postscript:n - { Resolution~72~div~VResolution~72~div~scale } - \@@_literal_postscript:n { DVImag~dup~scale } - \@@_literal_postscript:x - { - 0 ~ - \dim_to_decimal_in_bp:n { \box_dp:N #1 } ~ - \dim_to_decimal_in_bp:n { \box_wd:N #1 } ~ - \dim_to_decimal_in_bp:n { -\box_ht:N #1 - \box_dp:N #1 } ~ - rectclip - } - \@@_literal_postscript:n { setmatrix } - \@@_align_currentpoint_end: - \hbox_overlap_right:n { \box_use:N #1 } - \@@_scope_end: - \skip_horizontal:n { \box_wd:N #1 } - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\driver_box_use_rotate:Nn} -% \begin{macro}{\@@_box_use_rotate:Nn} -% Rotating using \texttt{dvips} does not require that the box dimensions -% are altered and has a very convenient built-in operation. Zero rotation -% must be written as |0| not |-0| so there is a quick test. -% \begin{macrocode} -\cs_new_protected:Npn \driver_box_use_rotate:Nn #1#2 - { \exp_args:NNf \@@_box_use_rotate:Nn #1 { \fp_eval:n {#2} } } -\cs_new_protected:Npn \@@_box_use_rotate:Nn #1#2 - { - \@@_scope_begin: - \@@_align_currentpoint_begin: - \@@_literal_postscript:x - { - \fp_compare:nNnTF {#2} = \c_zero_fp - { 0 } - { \fp_eval:n { round ( -(#2) , 5 ) } } ~ - rotate - } - \@@_align_currentpoint_end: - \box_use:N #1 - \@@_scope_end: - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\driver_box_use_scale:Nnn} -% The \texttt{dvips} driver once again has a dedicated operation we can -% use here. -% \begin{macrocode} -\cs_new_protected:Npn \driver_box_use_scale:Nnn #1#2#3 - { - \@@_scope_begin: - \@@_align_currentpoint_begin: - \@@_literal_postscript:x - { - \fp_eval:n { round ( #2 , 5 ) } ~ - \fp_eval:n { round ( #3 , 5 ) } ~ - scale - } - \@@_align_currentpoint_end: - \hbox_overlap_right:n { \box_use:N #1 } - \@@_scope_end: - } -% \end{macrocode} -% \end{macro} -% -% \begin{macrocode} -% -% \end{macrocode} -% -% \subsection{\texttt{pdfmode} driver} -% -% \begin{macrocode} -%<*pdfmode> -% \end{macrocode} -% -% \begin{macro}{\driver_box_use_clip:N} -% The general method is to save the current location, define a clipping path -% equivalent to the bounding box, then insert the content at the current -% position and in a zero width box. The \enquote{real} width is then made up -% using a horizontal skip before tidying up. There are other approaches that -% can be taken (for example using XForm objects), but the logic here shares -% as much code as possible and uses the same conversions (and so same -% rounding errors) in all cases. -% \begin{macrocode} -\cs_new_protected:Npn \driver_box_use_clip:N #1 - { - \@@_scope_begin: - \@@_literal_pdf:x - { - 0~ - \dim_to_decimal_in_bp:n { -\box_dp:N #1 } ~ - \dim_to_decimal_in_bp:n { \box_wd:N #1 } ~ - \dim_to_decimal_in_bp:n { \box_ht:N #1 + \box_dp:N #1 } ~ - re~W~n - } - \hbox_overlap_right:n { \box_use:N #1 } - \@@_scope_end: - \skip_horizontal:n { \box_wd:N #1 } - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\driver_box_use_rotate:Nn} -% \begin{macro}{\@@_box_use_rotate:Nn} -% \begin{variable}{\l_@@_cos_fp, \l_@@_sin_fp} -% Rotations are set using an affine transformation matrix which therefore -% requires sine/cosine values not the angle itself. We store the rounded -% values to avoid rounding twice. There are also a couple of comparisons to -% ensure that |-0| is not written to the output, as this avoids any issues -% with problematic display programs. Note that numbers are compared to~$0$ -% after rounding. -% \begin{macrocode} -\cs_new_protected:Npn \driver_box_use_rotate:Nn #1#2 - { \exp_args:NNf \@@_box_use_rotate:Nn #1 { \fp_eval:n {#2} } } -\cs_new_protected:Npn \@@_box_use_rotate:Nn #1#2 - { - \@@_scope_begin: - \box_set_wd:Nn #1 { 0pt } - \fp_set:Nn \l_@@_cos_fp { round ( cosd ( #2 ) , 5 ) } - \fp_compare:nNnT \l_@@_cos_fp = \c_zero_fp - { \fp_zero:N \l_@@_cos_fp } - \fp_set:Nn \l_@@_sin_fp { round ( sind ( #2 ) , 5 ) } - \@@_matrix:x - { - \fp_use:N \l_@@_cos_fp \c_space_tl - \fp_compare:nNnTF \l_@@_sin_fp = \c_zero_fp - { 0~0 } - { - \fp_use:N \l_@@_sin_fp - \c_space_tl - \fp_eval:n { -\l_@@_sin_fp } - } - \c_space_tl - \fp_use:N \l_@@_cos_fp - } - \box_use:N #1 - \@@_scope_end: - } -\fp_new:N \l_@@_cos_fp -\fp_new:N \l_@@_sin_fp -% \end{macrocode} -% \end{variable} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\driver_box_use_scale:Nnn} -% The same idea as for rotation but without the complexity of signs and -% cosines. -% \begin{macrocode} -\cs_new_protected:Npn \driver_box_use_scale:Nnn #1#2#3 - { - \@@_scope_begin: - \@@_matrix:x - { - \fp_eval:n { round ( #2 , 5 ) } ~ - 0~0~ - \fp_eval:n { round ( #3 , 5 ) } - } - \hbox_overlap_right:n { \box_use:N #1 } - \@@_scope_end: - } -% \end{macrocode} -% \end{macro} -% -% \begin{macrocode} -% -% \end{macrocode} -% -% \subsection{\texttt{dvipdfmx} driver} -% -% \begin{macrocode} -%<*dvipdfmx|xdvipdfmx> -% \end{macrocode} -% -% \begin{macro}{\driver_box_use_clip:N} -% The code here is identical to that for \texttt{pdfmode}: unlike rotation and -% scaling, there is no higher-level support in the driver for clipping. -% \begin{macrocode} -\cs_new_protected:Npn \driver_box_use_clip:N #1 - { - \@@_scope_begin: - \@@_literal_pdf:x - { - 0~ - \dim_to_decimal_in_bp:n { -\box_dp:N #1 } ~ - \dim_to_decimal_in_bp:n { \box_wd:N #1 } ~ - \dim_to_decimal_in_bp:n { \box_ht:N #1 + \box_dp:N #1 } ~ - re~W~n - } - \hbox_overlap_right:n { \box_use:N #1 } - \@@_scope_end: - \skip_horizontal:n { \box_wd:N #1 } - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\driver_box_use_rotate:Nn} -% \begin{macro}{\@@_box_use_rotate:Nn} -% Rotating in \texttt{(x)}dvipdmfx can be implemented using either PDF or -% driver-specific code. The former approach however is not \enquote{aware} -% of the content of boxes: this means that any embedded links would not be -% adjusted by the rotation. As such, the driver-native approach is preferred: -% the code therefore is similar (though not identical) to the \texttt{dvips} -% version (notice the rotation angle here is positive). As for -% \texttt{dvips}, zero rotation is written as |0| not |-0|. -% \begin{macrocode} -\cs_new_protected:Npn \driver_box_use_rotate:Nn #1#2 - { \exp_args:NNf \@@_box_use_rotate:Nn #1 { \fp_eval:n {#2} } } -\cs_new_protected:Npn \@@_box_use_rotate:Nn #1#2 - { - \@@_scope_begin: - \@@_literal:x - { - x:rotate~ - \fp_compare:nNnTF {#2} = \c_zero_fp - { 0 } - { \fp_eval:n { round ( #2 , 5 ) } } - } - \box_use:N #1 - \@@_scope_end: - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\driver_box_use_scale:Nnn} -% Much the same idea for scaling: use the higher-level driver operation to allow -% for box content. -% \begin{macrocode} -\cs_new_protected:Npn \driver_box_use_scale:Nnn #1#2#3 - { - \@@_scope_begin: - \@@_literal:x - { - x:scale~ - \fp_eval:n { round ( #2 , 5 ) } ~ - \fp_eval:n { round ( #3 , 5 ) } - } - \hbox_overlap_right:n { \box_use:N #1 } - \@@_scope_end: - } -% \end{macrocode} -% \end{macro} -% -% \begin{macrocode} -% -% \end{macrocode} -% -% \subsection{\texttt{dvisvgm} driver} -% -% \begin{macrocode} -%<*dvisvgm> -% \end{macrocode} -% -% \begin{macro}{\driver_box_use_clip:N} -% \begin{variable}{\g_@@_clip_path_int} -% Clipping in SVG is more involved than with other drivers. The first issue -% is that the clipping path must be defined separately from where it is used, -% so we need to track how many paths have applied. The naming here uses -% \texttt{l3cp} as the namespace with a number following. Rather than use -% a rectangular operation, we define the path manually as this allows it to -% have a depth: easier than the alternative approach of shifting content -% up and down using scopes to allow for the depth of the \TeX{} box and -% keep the reference point the same! -% \begin{macrocode} -\cs_new_protected:Npn \driver_box_use_clip:N #1 - { - \int_gincr:N \g_@@_clip_path_int - \@@_literal_svg:x - { < clipPath~id = " l3cp \int_use:N \g_@@_clip_path_int " > } - \@@_literal_svg:x - { - < - path ~ d = - " - M ~ 0 ~ - \dim_to_decimal:n { -\box_dp:N #1 } ~ - L ~ \dim_to_decimal:n { \box_wd:N #1 } ~ - \dim_to_decimal:n { -\box_dp:N #1 } ~ - L ~ \dim_to_decimal:n { \box_wd:N #1 } ~ - \dim_to_decimal:n { \box_ht:N #1 + \box_dp:N #1 } ~ - L ~ 0 ~ - \dim_to_decimal:n { \box_ht:N #1 + \box_dp:N #1 } ~ - Z - " - /> - } - \@@_literal_svg:n - { < /clipPath > } -% \end{macrocode} -% In general the SVG set up does not try to transform coordinates to the -% current point. For clipping we need to do that, so have a transformation -% here to get us to the right place, and a matching one just before the -% \TeX{} box is inserted to get things back on track. The clip path needs to -% come between those two such that if lines up with the current point, as -% does the \TeX{} box. -% \begin{macrocode} - \@@_scope_begin:n - { - transform = - " - translate ( { ?x } , { ?y } ) ~ - scale ( 1 , -1 ) - " - } - \@@_scope_begin:x - { - clip-path = - "url ( \c_hash_str l3cp \int_use:N \g_@@_clip_path_int ) " - } - \@@_scope_begin:n - { - transform = - " - scale ( -1 , 1 ) ~ - translate ( { ?x } , { ?y } ) ~ - scale ( -1 , -1 ) - " - } - \box_use:N #1 - \@@_scope_end: - \@@_scope_end: - \@@_scope_end: -% \skip_horizontal:n { \box_wd:N #1 } - } -\int_new:N \g_@@_clip_path_int -% \end{macrocode} -% \end{variable} -% \end{macro} -% -% \begin{macro}{\driver_box_use_rotate:Nn} -% Rotation has a dedicated operation which includes a centre-of-rotation -% optional pair. That can be picked up from the driver syntax, so there is -% no need to worry about the transformation matrix. -% \begin{macrocode} -\cs_new_protected:Npn \driver_box_use_rotate:Nn #1#2 - { - \@@_scope_begin:x - { - transform = - " - rotate - ( \fp_eval:n { round ( -(#2) , 5 ) } , ~ { ?x } , ~ { ?y } ) - " - } - \box_use:N #1 - \@@_scope_end: - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\driver_box_use_scale:Nnn} -% In contrast to rotation, we have to account for the current position in this -% case. That is done using a couple of translations in addition to the scaling -% (which is therefore done backward with a flip). -% \begin{macrocode} -\cs_new_protected:Npn \driver_box_use_scale:Nnn #1#2#3 - { - \@@_scope_begin:x - { - transform = - " - translate ( { ?x } , { ?y } ) ~ - scale - ( - \fp_eval:n { round ( -#2 , 5 ) } , - \fp_eval:n { round ( -#3 , 5 ) } - ) ~ - translate ( { ?x } , { ?y } ) ~ - scale ( -1 ) - " - } - \hbox_overlap_right:n { \box_use:N #1 } - \@@_scope_end: - } -% \end{macrocode} -% \end{macro} -% -% \begin{macrocode} -% -% \end{macrocode} -% -% \begin{macrocode} -% -% \end{macrocode} -% -% \end{implementation} -% -% \PrintIndex diff --git a/Master/texmf-dist/source/latex/l3kernel/l3drivers-color.dtx b/Master/texmf-dist/source/latex/l3kernel/l3drivers-color.dtx deleted file mode 100644 index 4d5c22462ca..00000000000 --- a/Master/texmf-dist/source/latex/l3kernel/l3drivers-color.dtx +++ /dev/null @@ -1,307 +0,0 @@ -% \iffalse meta-comment -% -%% File: l3drivers-color.dtx -% -% Copyright (C) 2011-2019 The LaTeX3 Project -% -% It may be distributed and/or modified under the conditions of the -% LaTeX Project Public License (LPPL), either version 1.3c of this -% license or (at your option) any later version. The latest version -% of this license is in the file -% -% https://www.latex-project.org/lppl.txt -% -% This file is part of the "l3kernel bundle" (The Work in LPPL) -% and all files in that bundle must be distributed together. -% -% ----------------------------------------------------------------------- -% -% The development version of the bundle can be found at -% -% https://github.com/latex3/latex3 -% -% for those people who are interested. -% -%<*driver> -\documentclass[full,kernel]{l3doc} -\begin{document} - \DocInput{\jobname.dtx} -\end{document} -% -% \fi -% -% \title{^^A -% The \textsf{l3drivers-color} package\\ Driver color support^^A -% } -% -% \author{^^A -% The \LaTeX3 Project\thanks -% {^^A -% E-mail: -% \href{mailto:latex-team@latex-project.org} -% {latex-team@latex-project.org}^^A -% }^^A -% } -% -% \date{Released 2019-05-28} -% -% \maketitle -% -% \begin{documentation} -% -% \end{documentation} -% -% \begin{implementation} -% -% \section{\pkg{l3drivers-color} Implementation} -% -% \begin{macrocode} -%<*initex|package> -%<@@=driver> -% \end{macrocode} -% -% Color support is split into two parts: a \enquote{general} concept and -% one directly linked to drawings (or rather the split between filling -% and stroking). General color is relatively easy to handle: we have a color -% stack available with all modern drivers, and can use that.% -% Whilst \texttt{(x)dvipdfmx} does have its own approach to color specials, -% it is easier to use \texttt{dvips}-like ones for all cases except direct -% PDF output. -% -% \subsection{\texttt{dvips}-style} -% -% \begin{macrocode} -%<*dvisvgm|dvipdfmx|dvips|xdvipdfmx> -% \end{macrocode} -% -% \begin{macro}{\driver_color_pickup:N} -% \begin{macro}{\@@_color_pickup:w} -% Allow for \LaTeXe{} color. Here, the possible input values are limited: -% \texttt{dvips}-style colors can mainly be taken as-is with the exception -% spot ones (here we need a model and a tint). -% \begin{macrocode} -%<*package> -\cs_new_protected:Npn \driver_color_pickup:N #1 { } -\AtBeginDocument - { - \@ifpackageloaded { color } - { - \cs_set_protected:Npn \driver_color_pickup:N #1 - { - \exp_args:NV \tl_if_head_is_space:nTF \current@color - { - \tl_set:Nx #1 - { - spot ~ - \exp_after:wN \use:n \current@color \c_space_tl 1 - } - } - { - \exp_last_unbraced:Nx \@@_color_pickup:w - { \current@color } \q_stop #1 - } - } - \cs_new_protected:Npn \@@_color_pickup:w #1 ~ #2 \q_stop #3 - { \tl_set:Nn #3 { #1 ~ #2 } } - } - { } - } -% -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\driver_color_cmyk:nnnn} -% \begin{macro}{\driver_color_gray:n} -% \begin{macro}{\driver_color_rgb:nnn} -% \begin{macro}{\driver_color_spot:nn} -% \begin{macro}{\@@_color_select:n, \@@_color_select:x} -% \begin{macro}{\@@_color_reset:} -% \begin{macro}{driver.fc} -% Push the data to the stack. In the case of \texttt{dvips} also reset the -% drawing fill color in raw PostScript. -% \begin{macrocode} -\cs_new_protected:Npn \driver_color_cmyk:nnnn #1#2#3#4 - { - \@@_color_select:x - { - cmyk~ - \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ - \fp_eval:n {#3} ~ \fp_eval:n {#4} - } - } -\cs_new_protected:Npn \driver_color_gray:n #1 - { \@@_color_select:x { gray~ \fp_eval:n {#1} } } -\cs_new_protected:Npn \driver_color_rgb:nnn #1#2#3 - { - \@@_color_select:x - { rgb~ \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ \fp_eval:n {#3} } - } -\cs_new_protected:Npn \driver_color_spot:nn #1#2 - { \@@_color_select:n { #1 } } -\cs_new_protected:Npn \@@_color_select:n #1 - { - \@@_literal:n { color~push~ #1 } -%<*dvips> - \@@_postscript:n { /driver.fc~{ }~def } -% - \group_insert_after:N \@@_color_reset: - } -\cs_generate_variant:Nn \@@_color_select:n { x } -\cs_new_protected:Npn \@@_color_reset: - { \@@_literal:n { color~pop } } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macrocode} -% -% \end{macrocode} -% -% \subsection{\texttt{pdfmode}} -% -% \begin{macrocode} -%<*pdfmode> -% \end{macrocode} -% -% \begin{macro}{\driver_color_pickup:N} -% \begin{macro}{\@@_color_pickup:w} -% The current color in driver-dependent format: pick up the package-mode -% data if available. We end up converting back and forward in this route as -% we store our color data in \texttt{dvips} format. -% The \tn{current@color} needs to be \texttt{x}-expanded before -% \cs{@@_color_pickup:w} breaks it apart, because for instance -% \pkg{xcolor} sets it to be instructions to generate a colour -% \begin{macrocode} -%<*package> -\cs_new_protected:Npn \driver_color_pickup:N #1 { } -\AtBeginDocument - { - \@ifpackageloaded { color } - { - \cs_set_protected:Npn \driver_color_pickup:N #1 - { - \exp_last_unbraced:Nx \@@_color_pickup:w - { \current@color } ~ 0 ~ 0 ~ 0 \q_stop #1 - } - \cs_new_protected:Npn \@@_color_pickup:w - #1 ~ #2 ~ #3 ~ #4 ~ #5 ~ #6 \q_stop #7 - { - \str_if_eq:nnTF {#2} { g } - { \tl_set:Nn #7 { gray ~ #1 } } - { - \str_if_eq:nnTF {#4} { rg } - { \tl_set:Nn #7 { rgb ~ #1 ~ #2 ~ #3 } } - { - \str_if_eq:nnTF {#5} { k } - { \tl_set:Nn #7 { cmyk ~ #1 ~ #2 ~ #3 ~ #4 } } - { - \str_if_eq:nnTF {#2} { cs } - { - \tl_set:Nx #7 { spot ~ \use_none:n #1 ~ #5 } - } - { - \tl_set:Nn #7 { gray ~ 0 } - } - } - } - } - } - } - { } - } -% -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{variable}{\l_@@_color_stack_int} -% \pdfTeX{} and \LuaTeX{} have multiple stacks available, and to track -% which one is in use a variable is required. -% \begin{macrocode} -\int_new:N \l_@@_color_stack_int -% \end{macrocode} -% \end{variable} -% -% \begin{macro}{\driver_color_cmyk:nnnn, \@@_color_cmyk:nnnn} -% \begin{macro}{\driver_color_gray:n, \@@_color_gray:n} -% \begin{macro}{\driver_color_rgb:nnn, \@@_color_rgb:nnn} -% \begin{macro}{\driver_color_spot:nn} -% \begin{macro}{\@@_color_select:n, \@@_color_select:x} -% \begin{macro}{\@@_color_reset:} -% Simply dump the data, but allowing for \LuaTeX{}. -% \begin{macrocode} -\cs_new_protected:Npn \driver_color_cmyk:nnnn #1#2#3#4 - { - \use:x - { - \@@_color_cmyk:nnnn - { \fp_eval:n {#1} } - { \fp_eval:n {#2} } - { \fp_eval:n {#3} } - { \fp_eval:n {#4} } - } - } -\cs_new_protected:Npn \@@_color_cmyk:nnnn #1#2#3#4 - { - \@@_color_select:n - { #1 ~ #2 ~ #3 ~ #4 ~ k ~ #1 ~ #2 ~ #3 ~ #4 ~ K } - } -\cs_new_protected:Npn \driver_color_gray:n #1 - { \exp_args:Nx \@@_color_gray:n { \fp_eval:n {#1} } } -\cs_new_protected:Npn \@@_color_gray:n #1 - { \@@_color_select:n { #1 ~ g ~ #1 ~ G } } -\cs_new_protected:Npn \driver_color_rgb:nnn #1#2#3 - { - \use:x - { - \@@_color_rgb:nnn - { \fp_eval:n {#1} } - { \fp_eval:n {#2} } - { \fp_eval:n {#3} } - } - } -\cs_new_protected:Npn \@@_color_rgb:nnn #1#2#3 - { \@@_color_select:n { #1 ~ #2 ~ #3 ~ rg ~ #1 ~ #2 ~ #3 ~ RG } } -\cs_new_protected:Npn \driver_color_spot:nn #1#2 - { \@@_color_select:n { /#1 ~ cs ~ /#1 ~ CS ~ #2 ~ sc ~ #2 ~ SC } } -\cs_new_protected:Npx \@@_color_select:n #1 - { - \cs_if_exist:NTF \tex_pdfextension:D - { \tex_pdfextension:D colorstack } - { \tex_pdfcolorstack:D } - \exp_not:N \l_@@_color_stack_int push {#1} - \group_insert_after:N \exp_not:N \@@_color_reset: - } -\cs_generate_variant:Nn \@@_color_select:n { x } -\cs_new_protected:Npx \@@_color_reset: - { - \cs_if_exist:NTF \tex_pdfextension:D - { \tex_pdfextension:D colorstack } - { \tex_pdfcolorstack:D } - \exp_not:N \l_@@_color_stack_int pop \scan_stop: - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macrocode} -% -% \end{macrocode} -% -% \begin{macrocode} -% -% \end{macrocode} -% -% \end{implementation} -% -% \PrintIndex diff --git a/Master/texmf-dist/source/latex/l3kernel/l3drivers-draw.dtx b/Master/texmf-dist/source/latex/l3kernel/l3drivers-draw.dtx deleted file mode 100644 index 1e213647b46..00000000000 --- a/Master/texmf-dist/source/latex/l3kernel/l3drivers-draw.dtx +++ /dev/null @@ -1,1338 +0,0 @@ -% \iffalse meta-comment -% -%% File: l3drivers-draw.dtx -% -% Copyright (C) 2011-2019 The LaTeX3 Project -% -% It may be distributed and/or modified under the conditions of the -% LaTeX Project Public License (LPPL), either version 1.3c of this -% license or (at your option) any later version. The latest version -% of this license is in the file -% -% https://www.latex-project.org/lppl.txt -% -% This file is part of the "l3kernel bundle" (The Work in LPPL) -% and all files in that bundle must be distributed together. -% -% ----------------------------------------------------------------------- -% -% The development version of the bundle can be found at -% -% https://github.com/latex3/latex3 -% -% for those people who are interested. -% -%<*driver> -\documentclass[full,kernel]{l3doc} -\begin{document} - \DocInput{\jobname.dtx} -\end{document} -% -% \fi -% -% \title{^^A -% The \textsf{l3drivers-draw} package\\ Driver drawing support^^A -% } -% -% \author{^^A -% The \LaTeX3 Project\thanks -% {^^A -% E-mail: -% \href{mailto:latex-team@latex-project.org} -% {latex-team@latex-project.org}^^A -% }^^A -% } -% -% \date{Released 2019-05-28} -% -% \maketitle -% -% \begin{documentation} -% -% \end{documentation} -% -% \begin{implementation} -% -% \section{\pkg{l3drivers-draw} Implementation} -% -% \begin{macrocode} -%<*initex|package> -%<@@=driver> -% \end{macrocode} -% -% \subsection{\texttt{dvips} driver} -% -% \begin{macrocode} -%<*dvips> -% \end{macrocode} -% -% \begin{macro}{\@@_draw_literal:n, \@@_draw_literal:x} -% The same as literal PostScript: same arguments about positioning apply -% her. -% \begin{macrocode} -\cs_new_eq:NN \@@_draw_literal:n \@@_literal_postscript:n -\cs_generate_variant:Nn \@@_draw_literal:n { x } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\driver_draw_begin:, \driver_draw_end:} -% \begin{macro}{driver.fc} -% The |ps::[begin]| special here deals with positioning but allows us to -% continue on to a matching |ps::[end]|: contrast with |ps:|, which positions -% but where we can't split material between separate calls. The -% |@beginspecial|/|@endspecial| pair are from |special.pro| and correct the -% scale and $y$-axis direction. The definition of |/driver.fc| deals with fill -% color in paths. In contrast to \pkg{pgf}, we don't save the current point: -% discussion with Tom Rokici suggested a better way to handle the necessary -% translations (see \cs{driver_draw_box_use:Nnnnn}). (Note that -% |@beginspecial|/|@endspecial| forms a driver scope.) The |[begin]|/^^A -% |[end]| lines are handled differently from the rest as they are -% conceptually different: not really drawing literals but instructions to -% \texttt{dvips} itself. -% \begin{macrocode} -\cs_new_protected:Npn \driver_draw_begin: - { - \@@_literal:n { ps::[begin] } - \@@_draw_literal:n { @beginspecial } - \@@_darw_literal:n { SDict ~ begin ~ /driver.fc ~ { } ~ def ~ end } - } -\cs_new_protected:Npn \driver_draw_end: - { - \@@_draw_literal:n { @endspecial } - \@@_literal:n { ps::[end] } - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\driver_draw_scope_begin:, \driver_draw_scope_end:} -% Scope here may need to contain saved definitions, so the entire memory -% rather than just the graphic state has to be sent to the stack. -% \begin{macrocode} -\cs_new_protected:Npn \driver_draw_scope_begin: - { \@@_draw_literal:n { save } } -\cs_new_protected:Npn \driver_draw_scope_end: - { \@@_draw_literal:n { restore } } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\driver_draw_moveto:nn, \driver_draw_lineto:nn} -% \begin{macro}{\driver_draw_rectangle:nnnn} -% \begin{macro}{\driver_draw_curveto:nnnnnn} -% Path creation operations mainly resolve directly to PostScript primitive -% steps, with only the need to convert to \texttt{bp}. Notice that -% \texttt{x}-type expansion is included here to ensure that any variable -% values are forced to literals before any possible caching. There is -% no native rectangular path command (without also clipping, filling or -% stroking), so that task is done using a small amount of PostScript. -% \begin{macrocode} -\cs_new_protected:Npn \driver_draw_moveto:nn #1#2 - { - \@@_draw_literal:x - { - \dim_to_decimal_in_bp:n {#1} ~ - \dim_to_decimal_in_bp:n {#2} ~ moveto - } - } -\cs_new_protected:Npn \driver_draw_lineto:nn #1#2 - { - \@@_draw_literal:x - { - \dim_to_decimal_in_bp:n {#1} ~ - \dim_to_decimal_in_bp:n {#2} ~ lineto - } - } -\cs_new_protected:Npn \driver_draw_rectangle:nnnn #1#2#3#4 - { - \@@_draw_literal:x - { - \dim_to_decimal_in_bp:n {#4} ~ \dim_to_decimal_in_bp:n {#3} ~ - \dim_to_decimal_in_bp:n {#1} ~ \dim_to_decimal_in_bp:n {#2} ~ - moveto~dup~0~rlineto~exch~0~exch~rlineto~neg~0~rlineto~closepath - } - } -\cs_new_protected:Npn \driver_draw_curveto:nnnnnn #1#2#3#4#5#6 - { - \@@_draw_literal:x - { - \dim_to_decimal_in_bp:n {#1} ~ \dim_to_decimal_in_bp:n {#2} ~ - \dim_to_decimal_in_bp:n {#3} ~ \dim_to_decimal_in_bp:n {#4} ~ - \dim_to_decimal_in_bp:n {#5} ~ \dim_to_decimal_in_bp:n {#6} ~ - curveto - } - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\driver_draw_evenodd_rule:, \driver_draw_nonzero_rule:} -% \begin{variable}{\g_@@_draw_eor_bool} -% The even-odd rule here can be implemented as a simply switch. -% \begin{macrocode} -\cs_new_protected:Npn \driver_draw_evenodd_rule: - { \bool_gset_true:N \g_@@_draw_eor_bool } -\cs_new_protected:Npn \driver_draw_nonzero_rule: - { \bool_gset_false:N \g_@@_draw_eor_bool } -\bool_new:N \g_@@_draw_eor_bool -% \end{macrocode} -% \end{variable} -% \end{macro} -% -% \begin{macro} -% { -% \driver_draw_closepath: , -% \driver_draw_stroke: , -% \driver_draw_closestroke: , -% \driver_draw_fill: , -% \driver_draw_fillstroke: , -% \driver_draw_clip: , -% \driver_draw_discardpath: -% } -% \begin{variable}{\g_@@_draw_clip_bool} -% Unlike PDF, PostScript doesn't track separate colors for strokes and other -% elements. It is also desirable to have the |clip| keyword after a stroke or -% fill. To achieve those outcomes, there is some work to do. For color, the -% stoke color is simple but the fill one has to be inserted by hand. For -% clipping, the required ordering is achieved using a \TeX{} switch. All of -% the operations end with a new path instruction as they do not terminate -% (again in contrast to PDF). -% \begin{macrocode} -\cs_new_protected:Npn \driver_draw_closepath: - { \@@_draw_literal:n { closepath } } -\cs_new_protected:Npn \driver_draw_stroke: - { - \@@_draw_literal:n { stroke } - \bool_if:NT \g_@@_draw_clip_bool - { - \@@_draw_literal:x - { - \bool_if:NT \g_@@_draw_eor_bool { eo } - clip - } - } - \@@_draw_literal:n { newpath } - \bool_gset_false:N \g_@@_draw_clip_bool - } -\cs_new_protected:Npn \driver_draw_closestroke: - { - \driver_draw_closepath: - \driver_draw_stroke: - } -\cs_new_protected:Npn \driver_draw_fill: - { - \@@_draw_literal:n { gsave } - \@@_draw_literal:n { driver.fc } - \@@_draw_literal:x - { - \bool_if:NT \g_@@_draw_eor_bool { eo } - fill - } - \@@_draw_literal:n { grestore } - \bool_if:NT \g_@@_draw_clip_bool - { - \@@_draw_literal:x - { - \bool_if:NT \g_@@_draw_eor_bool { eo } - clip - } - } - \@@_draw_literal:n { newpath } - \bool_gset_false:N \g_@@_draw_clip_bool - } -\cs_new_protected:Npn \driver_draw_fillstroke: - { - \@@_draw_literal:n { gsave } - \@@_draw_literal:n { driver.fc } - \@@_draw_literal:x - { - \bool_if:NT \g_@@_draw_eor_bool { eo } - fill - } - \@@_draw_literal:n { grestore } - \@@_draw_literal:n { stroke } - \bool_if:NT \g_@@_draw_clip_bool - { - \@@_draw_literal:x - { - \bool_if:NT \g_@@_draw_eor_bool { eo } - clip - } - } - \@@_draw_literal:n { newpath } - \bool_gset_false:N \g_@@_draw_clip_bool - } -\cs_new_protected:Npn \driver_draw_clip: - { \bool_gset_true:N \g_@@_draw_clip_bool } -\bool_new:N \g_@@_draw_clip_bool -\cs_new_protected:Npn \driver_draw_discardpath: - { - \bool_if:NT \g_@@_draw_clip_bool - { - \@@_draw_literal:x - { - \bool_if:NT \g_@@_draw_eor_bool { eo } - clip - } - } - \@@_draw_literal:n { newpath } - \bool_gset_false:N \g_@@_draw_clip_bool - } -% \end{macrocode} -% \end{variable} -% \end{macro} -% -% \begin{macro}{\driver_draw_dash_pattern:nn} -% \begin{macro}{\@@_draw_dash:n} -% \begin{macro}{\driver_draw_linewidth:n} -% \begin{macro}{\driver_draw_miterlimit:n} -% \begin{macro} -% { -% \driver_draw_cap_butt:, \driver_draw_cap_round:, \driver_draw_cap_rectangle:, -% \driver_draw_join_miter:, \driver_draw_join_round:, \driver_draw_join_bevel: -% } -% Converting paths to output is again a case of mapping directly to -% PostScript operations. -% \begin{macrocode} -\cs_new_protected:Npn \driver_draw_dash_pattern:nn #1#2 - { - \@@_draw_literal:x - { - [ - \exp_args:Nf \use:n - { \clist_map_function:nN {#1} \@@_draw_dash:n } - ] ~ - \dim_to_decimal_in_bp:n {#2} ~ setdash - } - } -\cs_new:Npn \@@_draw_dash:n #1 - { ~ \dim_to_decimal_in_bp:n {#1} } -\cs_new_protected:Npn \driver_draw_linewidth:n #1 - { - \@@_draw_literal:x - { \dim_to_decimal_in_bp:n {#1} ~ setlinewidth } - } -\cs_new_protected:Npn \driver_draw_miterlimit:n #1 - { \@@_draw_literal:x { \fp_eval:n {#1} ~ setmiterlimit } } -\cs_new_protected:Npn \driver_draw_cap_butt: - { \@@_draw_literal:n { 0 ~ setlinecap } } -\cs_new_protected:Npn \driver_draw_cap_round: - { \@@_draw_literal:n { 1 ~ setlinecap } } -\cs_new_protected:Npn \driver_draw_cap_rectangle: - { \@@_draw_literal:n { 2 ~ setlinecap } } -\cs_new_protected:Npn \driver_draw_join_miter: - { \@@_draw_literal:n { 0 ~ setlinejoin } } -\cs_new_protected:Npn \driver_draw_join_round: - { \@@_draw_literal:n { 1 ~ setlinejoin } } -\cs_new_protected:Npn \driver_draw_join_bevel: - { \@@_draw_literal:n { 2 ~ setlinejoin } } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro} -% { -% \driver_draw_color_fill_cmyk:nnnn , -% \driver_draw_color_stroke_cmyk:nnnn -% } -% \begin{macro} -% { -% \driver_draw_color_fill_gray:n , -% \driver_draw_color_stroke_gray:n -% } -% \begin{macro} -% { -% \driver_draw_color_fill_rgb:nnn , -% \driver_draw_color_stroke_rgb:nnn -% } -% \begin{macro} -% { -% \@@_draw_color_fill:n, \@@_draw_color_fill:x, -% \@@_draw_color_stroke:n, \@@_draw_color_stroke:x -% } -% For \texttt{dvips}, we can use the standard color stack to deal with -% stroke color, but for fills have to switch to raw PostScript. This is -% thus not handled by the stack, but the context is very restricted. See -% also how fills are implemented. -% \begin{macrocode} -\cs_new_protected:Npn \driver_draw_color_fill_cmyk:nnnn #1#2#3#4 - { - \@@_draw_color_fill:x - { - \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ - \fp_eval:n {#3} ~ \fp_eval:n {#4} ~ - setcmykcolor - } - } -\cs_new_protected:Npn \driver_draw_color_stroke_cmyk:nnnn #1#2#3#4 - { - \@@_draw_color_stroke:x - { - cmyk ~ - \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ - \fp_eval:n {#3} ~ \fp_eval:n {#4} - } - } -\cs_new_protected:Npn \driver_draw_color_fill_gray:n #1 - { \@@_draw_color_fill:x { \fp_eval:n {#1} ~ setgray } } -\cs_new_protected:Npn \driver_draw_color_stroke_gray:n #1 - { \@@_draw_color_stroke:x { gray ~ \fp_eval:n {#1} } } -\cs_new_protected:Npn \driver_draw_color_fill_rgb:nnn #1#2#3 - { - \@@_draw_color_fill:x - { \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ \fp_eval:n {#3} ~ setrgbcolor } - } -\cs_new_protected:Npn \driver_draw_color_stroke_rgb:nnn #1#2#3 - { - \@@_draw_color_stroke:x - { rgb ~ \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ \fp_eval:n {#3} } - } -\cs_new_protected:Npn \@@_draw_color_fill:n #1 - { \@@_postscript:n { SDict ~ begin ~ /driver.fc ~ { #1 } ~ def ~ end } } -\cs_generate_variant:Nn \@@_draw_color_fill:n { x } -\cs_new_protected:Npn \@@_draw_color_stroke:n #1 - { - \@@_literal:n { color~push~#1 } - \group_insert_after:N \@@_color_reset: - } -\cs_generate_variant:Nn \@@_draw_color_stroke:n { x } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\driver_draw_cm:nnnn} -% In \texttt{dvips}, keeping the transformations in line with the engine -% is unfortunately not possible for scaling and rotations: even if we -% decompose the matrix into those operations, there is still no driver -% tracking (\emph{cf.}~\texttt{(x)dvipdfmx}). Thus we take the shortest -% path available and simply dump the matrix as given. -% \begin{macrocode} -\cs_new_protected:Npn \driver_draw_cm:nnnn #1#2#3#4 - { - \@@_draw_literal:n - { - [ - \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ - \fp_eval:n {#3} ~ \fp_eval:n {#4} ~ - 0 ~ 0 - ] ~ - concat - } - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\driver_draw_box_use:Nnnnn} -% Inside a picture |@beginspecial|/|@endspecial| are active, which is -% normally a good thing but means that the position and scaling would be off -% if the box was inserted directly. To deal with that, there are a number of -% possible approaches. The implementation here was suggested by Tom Rokici -% (author of \texttt{dvips}). We end the current special placement, then -% set the current point with a literal |[begin]|. As for general -% literals, we then use the stack to store the current point and move to -% it. To insert the required transformation, we have to flip the $y$-axis, -% once before and once after it. Then we get back to the \TeX{} reference -% point to insert our content. The clean up has to happen in the right -% places, hence the |[begin]|/|[end]| pair around |restore|. Finally, -% we can return to \enquote{normal} drawing mode. Notice that the set up -% here is very similar to that in \cs{@@_align_currentpoint_\ldots}, but -% the ordering of saving and restoring is different (intermixed). -% \begin{macrocode} -\cs_new_protected:Npn \driver_draw_box_use:Nnnnn #1#2#3#4#5 - { - \@@_draw_literal:n { @endspecial } - \@@_draw_literal:n { [end] } - \@@_draw_literal:n { [begin] } - \@@_draw_literal:n { save } - \@@_draw_literal:n { currentpoint } - \@@_draw_literal:n { currentpoint~translate } - \driver_draw_cm:nnnn { 1 } { 0 } { 0 } { -1 } - \driver_draw_cm:nnnn {#2} {#3} {#4} {#5} - \driver_draw_cm:nnnn { 1 } { 0 } { 0 } { -1 } - \@@_draw_literal:n { neg~exch~neg~exch~translate } - \@@_draw_literal:n { [end] } - \hbox_overlap_right:n { \box_use:N #1 } - \@@_draw_literal:n { [begin] } - \@@_draw_literal:n { restore } - \@@_draw_literal:n { [end] } - \@@_draw_literal:n { [begin] } - \@@_draw_literal:n { @beginspecial } - } -% \end{macrocode} -% \end{macro} -% -% \begin{macrocode} -% -% \end{macrocode} -% -% \subsection{\texttt{pdfmode} and \texttt{(x)dvipdfmx}} -% -% Both \texttt{pdfmode} and \texttt{(x)dvipdfmx} directly produce PDF output -% and understand a shared set of specials for drawing commands. -% -% \begin{macrocode} -%<*dvipdfmx|pdfmode|xdvipdfmx> -% \end{macrocode} -% -% \subsubsection{Drawing} -% -% \begin{macro}{\@@_draw_literal:n, \@@_draw_literal:x} -% Pass data through using a dedicated interface. -% \begin{macrocode} -\cs_new_eq:NN \@@_draw_literal:n \@@_literal_pdf:n -\cs_generate_variant:Nn \@@_draw_literal:n { x } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\driver_draw_begin:, \driver_draw_end:} -% No special requirements here, so simply set up a drawing scope. -% \begin{macrocode} -\cs_new_protected:Npn \driver_draw_begin: - { \driver_draw_scope_begin: } -\cs_new_protected:Npn \driver_draw_end: - { \driver_draw_scope_end: } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\driver_draw_scope_begin:, \driver_draw_scope_end:} -% Use the driver-level scope mechanisms. -% \begin{macrocode} -\cs_new_eq:NN \driver_draw_scope_begin: \@@_scope_begin: -\cs_new_eq:NN \driver_draw_scope_end: \@@_scope_end: -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\driver_draw_moveto:nn, \driver_draw_lineto:nn} -% \begin{macro}{\driver_draw_curveto:nnnnnn} -% \begin{macro}{\driver_draw_rectangle:nnnn} -% Path creation operations all resolve directly to PDF primitive steps, with -% only the need to convert to \texttt{bp}. -% \begin{macrocode} -\cs_new_protected:Npn \driver_draw_moveto:nn #1#2 - { - \@@_draw_literal:x - { \dim_to_decimal_in_bp:n {#1} ~ \dim_to_decimal_in_bp:n {#2} ~ m } - } -\cs_new_protected:Npn \driver_draw_lineto:nn #1#2 - { - \@@_draw_literal:x - { \dim_to_decimal_in_bp:n {#1} ~ \dim_to_decimal_in_bp:n {#2} ~ l } - } -\cs_new_protected:Npn \driver_draw_curveto:nnnnnn #1#2#3#4#5#6 - { - \@@_draw_literal:x - { - \dim_to_decimal_in_bp:n {#1} ~ \dim_to_decimal_in_bp:n {#2} ~ - \dim_to_decimal_in_bp:n {#3} ~ \dim_to_decimal_in_bp:n {#4} ~ - \dim_to_decimal_in_bp:n {#5} ~ \dim_to_decimal_in_bp:n {#6} ~ - c - } - } -\cs_new_protected:Npn \driver_draw_rectangle:nnnn #1#2#3#4 - { - \@@_draw_literal:x - { - \dim_to_decimal_in_bp:n {#1} ~ \dim_to_decimal_in_bp:n {#2} ~ - \dim_to_decimal_in_bp:n {#3} ~ \dim_to_decimal_in_bp:n {#4} ~ - re - } - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\driver_draw_evenodd_rule:, \driver_draw_nonzero_rule:} -% \begin{variable}{\g_@@_draw_eor_bool} -% The even-odd rule here can be implemented as a simply switch. -% \begin{macrocode} -\cs_new_protected:Npn \driver_draw_evenodd_rule: - { \bool_gset_true:N \g_@@_draw_eor_bool } -\cs_new_protected:Npn \driver_draw_nonzero_rule: - { \bool_gset_false:N \g_@@_draw_eor_bool } -\bool_new:N \g_@@_draw_eor_bool -% \end{macrocode} -% \end{variable} -% \end{macro} -% -% \begin{macro} -% { -% \driver_draw_closepath: , -% \driver_draw_stroke: , -% \driver_draw_closestroke: , -% \driver_draw_fill: , -% \driver_draw_fillstroke: , -% \driver_draw_clip: , -% \driver_draw_discardpath: -% } -% Converting paths to output is again a case of mapping directly to -% PDF operations. -% \begin{macrocode} -\cs_new_protected:Npn \driver_draw_closepath: - { \@@_draw_literal:n { h } } -\cs_new_protected:Npn \driver_draw_stroke: - { \@@_draw_literal:n { S } } -\cs_new_protected:Npn \driver_draw_closestroke: - { \@@_draw_literal:n { s } } -\cs_new_protected:Npn \driver_draw_fill: - { - \@@_draw_literal:x - { f \bool_if:NT \g_@@_draw_eor_bool * } - } -\cs_new_protected:Npn \driver_draw_fillstroke: - { - \@@_draw_literal:x - { B \bool_if:NT \g_@@_draw_eor_bool * } - } -\cs_new_protected:Npn \driver_draw_clip: - { - \@@_draw_literal:x - { W \bool_if:NT \g_@@_draw_eor_bool * } - } -\cs_new_protected:Npn \driver_draw_discardpath: - { \@@_draw_literal:n { n } } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\driver_draw_dash_pattern:nn} -% \begin{macro}{\@@_draw_dash:n} -% \begin{macro}{\driver_draw_linewidth:n} -% \begin{macro}{\driver_draw_miterlimit:n} -% \begin{macro} -% { -% \driver_draw_cap_butt:, \driver_draw_cap_round:, \driver_draw_cap_rectangle:, -% \driver_draw_join_miter:, \driver_draw_join_round:, \driver_draw_join_bevel: -% } -% Converting paths to output is again a case of mapping directly to -% PDF operations. -% \begin{macrocode} -\cs_new_protected:Npn \driver_draw_dash_pattern:nn #1#2 - { - \@@_draw_literal:x - { - [ - \exp_args:Nf \use:n - { \clist_map_function:nN {#1} \@@_draw_dash:n } - ] ~ - \dim_to_decimal_in_bp:n {#2} ~ d - } - } -\cs_new:Npn \@@_draw_dash:n #1 - { ~ \dim_to_decimal_in_bp:n {#1} } -\cs_new_protected:Npn \driver_draw_linewidth:n #1 - { - \@@_draw_literal:x - { \dim_to_decimal_in_bp:n {#1} ~ w } - } -\cs_new_protected:Npn \driver_draw_miterlimit:n #1 - { \@@_draw_literal:x { \fp_eval:n {#1} ~ M } } -\cs_new_protected:Npn \driver_draw_cap_butt: - { \@@_draw_literal:n { 0 ~ J } } -\cs_new_protected:Npn \driver_draw_cap_round: - { \@@_draw_literal:n { 1 ~ J } } -\cs_new_protected:Npn \driver_draw_cap_rectangle: - { \@@_draw_literal:n { 2 ~ J } } -\cs_new_protected:Npn \driver_draw_join_miter: - { \@@_draw_literal:n { 0 ~ j } } -\cs_new_protected:Npn \driver_draw_join_round: - { \@@_draw_literal:n { 1 ~ j } } -\cs_new_protected:Npn \driver_draw_join_bevel: - { \@@_draw_literal:n { 2 ~ j } } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro} -% { -% \driver_draw_color_fill_cmyk:nnnn , -% \driver_draw_color_stroke_cmyk:nnnn -% } -% \begin{macro} -% { -% \driver_draw_color_fill_gray:n , -% \driver_draw_color_stroke_gray:n -% } -% \begin{macro} -% { -% \driver_draw_color_fill_rgb:nnn , -% \driver_draw_color_stroke_rgb:nnn -% } -% \begin{macro}{\@@_color_fill_select:n, \@@_color_fill_select:x} -% For the stroke color, all engines here can use the color stack to handle -% the setting. However, that is not the case for fill color: the stack in -% \texttt{(x)dvipdfmx} only covers one type of color. So we have to use -% different approaches for the two sets of engines. -% \begin{macrocode} -\cs_new_protected:Npn \driver_draw_color_fill_cmyk:nnnn #1#2#3#4 - { - \@@_color_fill_select:x - { - \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ - \fp_eval:n {#3} ~ \fp_eval:n {#4} ~ - k - } - } -\cs_new_protected:Npn \driver_draw_color_stroke_cmyk:nnnn #1#2#3#4 - { - \@@_color_select:x - { - \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ - \fp_eval:n {#3} ~ \fp_eval:n {#4} ~ - k - } - } -\cs_new_protected:Npn \driver_draw_color_fill_gray:n #1 - { \@@_color_fill_select:x { \fp_eval:n {#1} ~ g } } -\cs_new_protected:Npn \driver_draw_color_stroke_gray:n #1 - { \@@_color_select:x { \fp_eval:n {#1} ~ G } } -\cs_new_protected:Npn \driver_draw_color_fill_rgb:nnn #1#2#3 - { - \@@_color_fill_select:x - { \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ \fp_eval:n {#3} ~ rg } - } -\cs_new_protected:Npn \driver_draw_color_stroke_rgb:nnn #1#2#3 - { - \@@_color_select:x - { \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ \fp_eval:n {#3} ~ RG } - } -%<*pdfmode> -\cs_new_eq:NN \@@_color_fill_select:n \@@_color_select:n -% -%<*dvipdfmx|xdvipdfmx> -\cs_new_eq:NN \@@_color_fill_select:n \@@_draw_literal:n -% -\cs_generate_variant:Nn \@@_color_fill_select:n { x } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\driver_draw_cm:nnnn} -% \begin{macro}{\@@_draw_cm:nnnn} -% Another split here between \texttt{pdfmode} and \texttt{(x)dvipdfmx}. -% In the former, we have a direct method to maintain alignment: the driver -% can use a matrix itself. For \texttt{(x)dvipdfmx}, we can to decompose the -% matrix into rotations and a scaling, then use those operations as they -% are handled by the driver. (There is driver support for matrix operations in -% \texttt{(x)dvipdfmx}, but as a matched pair so not suitable for the -% \enquote{stand alone} transformation set up here.) -% \begin{macrocode} -\cs_new_protected:Npn \driver_draw_cm:nnnn #1#2#3#4 - { -%<*pdfmode> - \@@_matrix:x - { - \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ - \fp_eval:n {#3} ~ \fp_eval:n {#4} - } -% -%<*dvipdfmx|xdvipdfmx> - \@@_draw_cm_decompose:nnnnN {#1} {#2} {#3} {#4} - \@@_draw_cm:nnnn -% - } -%<*dvipdfmx|xdvipdfmx> -\cs_new_protected:Npn \@@_draw_cm:nnnn #1#2#3#4 - { - \@@_literal:x - { - x:rotate~ - \fp_compare:nNnTF {#1} = \c_zero_fp - { 0 } - { \fp_eval:n { round ( -#1 , 5 ) } } - } - \@@_literal:x - { - x:scale~ - \fp_eval:n { round ( #2 , 5 ) } ~ - \fp_eval:n { round ( #3 , 5 ) } - } - \@@_literal:x - { - x:rotate~ - \fp_compare:nNnTF {#4} = \c_zero_fp - { 0 } - { \fp_eval:n { round ( -#4 , 5 ) } } - } - } -% -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\@@_draw_cm_decompose:nnnnN} -% \begin{macro} -% { -% \@@_draw_cm_decompose_auxi:nnnnN, -% \@@_draw_cm_decompose_auxii:nnnnN, -% \@@_draw_cm_decompose_auxiii:nnnnN, -% } -% Internally, transformations for drawing are tracked as a matrix. Not all -% engines provide a way of dealing with this: if we use a raw matrix, the -% engine looses track of positions (for example for hyperlinks), and this is -% not desirable. They do, however, allow us to track rotations and scalings. -% Luckily, we can decompose any (two-dimensional) matrix into two rotations -% and a single scaling: -% \[ -% \begin{bmatrix} -% A & B \\ C & D -% \end{bmatrix} -% = -% \begin{bmatrix} -% \cos\beta & \sin\beta \\ -\sin\beta & \cos\beta -% \end{bmatrix} -% \begin{bmatrix} -% w_{1} & 0 \\ 0 & w_{2} -% \end{bmatrix} -% \begin{bmatrix} -% \cos\gamma & \sin\gamma \\ -\sin\gamma & \cos\gamma -% \end{bmatrix} -% \] -% The parent matrix can be converted to -% \[ -% \begin{bmatrix} -% A & B \\ C & D -% \end{bmatrix} -% = -% \begin{bmatrix} -% E & H \\-H & E -% \end{bmatrix} -% + -% \begin{bmatrix} -% F & G \\ G & -F -% \end{bmatrix} -% \] -% From these, we can find that -% \begin{align*} -% \frac{w_{1} + w_{2}}{2} &= \sqrt{E^{2} + H^{2}} \\ -% \frac{w_{1} - w_{2}}{2} &= \sqrt{F^{2} + G^{2}} \\ -% \gamma - \beta &= \tan^{-1}(G/F) \\ -% \gamma + \beta &= \tan^{-1}(H/E) -% \end{align*} -% at which point we just have to do various pieces of re-arrangement to -% get all of the values. (See J.~Blinn, \emph{IEEE Comput.\ Graph.\ Appl.}, -% 1996, \textbf{16}, 82--88.) There is one wrinkle: the PostScript (and PDF) -% way of specifying a transformation matrix exchanges where one would -% normally expect $B$ and $C$ to be. -% \begin{macrocode} -%<*dvipdfmx|xdvipdfmx> -\cs_new_protected:Npn \@@_draw_cm_decompose:nnnnN #1#2#3#4#5 - { - \use:x - { - \@@_draw_cm_decompose_auxi:nnnnN - { \fp_eval:n { (#1 + #4) / 2 } } - { \fp_eval:n { (#1 - #4) / 2 } } - { \fp_eval:n { (#3 + #2) / 2 } } - { \fp_eval:n { (#3 - #2) / 2 } } - } - #5 - } -\cs_new_protected:Npn \@@_draw_cm_decompose_auxi:nnnnN #1#2#3#4#5 - { - \use:x - { - \@@_draw_cm_decompose_auxii:nnnnN - { \fp_eval:n { 2 * sqrt ( #1 * #1 + #4 * #4 ) } } - { \fp_eval:n { 2 * sqrt ( #2 * #2 + #3 * #3 ) } } - { \fp_eval:n { atand ( #3 , #2 ) } } - { \fp_eval:n { atand ( #4 , #1 ) } } - } - #5 - } -\cs_new_protected:Npn \@@_draw_cm_decompose_auxii:nnnnN #1#2#3#4#5 - { - \use:x - { - \@@_draw_cm_decompose_auxiii:nnnnN - { \fp_eval:n { ( #4 - #3 ) / 2 } } - { \fp_eval:n { ( #1 + #2 ) / 2 } } - { \fp_eval:n { ( #1 - #2 ) / 2 } } - { \fp_eval:n { ( #4 + #3 ) / 2 } } - } - #5 - } -\cs_new_protected:Npn \@@_draw_cm_decompose_auxiii:nnnnN #1#2#3#4#5 - { - \fp_compare:nNnTF { abs( #2 ) } > { abs ( #3 ) } - { #5 {#1} {#2} {#3} {#4} } - { #5 {#1} {#3} {#2} {#4} } - } -% -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\driver_draw_box_use:Nnnnn} -% Inserting a \TeX{} box transformed to the requested position and using -% the current matrix is done using a mixture of \TeX{} and low-level -% manipulation. The offset can be handled by \TeX{}, so only any rotation/^^A -% skew/scaling component needs to be done using the matrix operation. As this -% operation can never be cached, the scope is set directly not using the -% \texttt{draw} version. -% \begin{macrocode} -\cs_new_protected:Npn \driver_draw_box_use:Nnnnn #1#2#3#4#5 - { - \@@_scope_begin: -%<*pdfmode> - \driver_draw_cm:nnnn {#2} {#3} {#4} {#5} -% -%<*dvipdfmx|xdvipdfmx> - \@@_literal:x - { - pdf:btrans~matrix~ - \fp_eval:n {#2} ~ \fp_eval:n {#3} ~ - \fp_eval:n {#4} ~ \fp_eval:n {#5} ~ - 0 ~ 0 - } -% - \hbox_overlap_right:n { \box_use:N #1 } -%<*dvipdfmx|xdvipdfmx> - \@@_literal:n { pdf:etrans } -% - \@@_scope_end: - } -% \end{macrocode} -% \end{macro} -% -% \begin{macrocode} -% -% \end{macrocode} -% -% \subsection{\texttt{dvisvgm} driver} -% -% \begin{macrocode} -%<*dvisvgm> -% \end{macrocode} -% -% \begin{macro}{\@@_draw_literal:n, \@@_draw_literal:x} -% The same as the more general literal call. -% \begin{macrocode} -\cs_new_eq:NN \@@_draw_literal:n \@@_literal_svg:n -\cs_generate_variant:Nn \@@_draw_literal:n { x } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\driver_draw_begin:, \driver_draw_end:} -% A drawing needs to be set up such that the co-ordinate system is -% translated. That is done inside a scope, which as described below -% \begin{macrocode} -\cs_new_protected:Npn \driver_draw_begin: - { - \driver_draw_scope_begin: - \@@_draw_scope:n { transform="translate({?x},{?y})~scale(1,-1)" } - } -\cs_new_protected:Npn \driver_draw_end: - { \driver_draw_scope_end: } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\driver_draw_scope_begin:, \driver_draw_scope_end:} -% \begin{macro}{\@@_draw_scope:n, \@@_draw_scope:x} -% \begin{variable}{\g_@@_draw_scope_int, \l_@@_draw_scope_int} -% Several settings that with other drivers are \enquote{stand alone} have -% to be given as part of a scope in SVG. As a result, there is a need to -% provide a mechanism to automatically close these extra scopes. That is -% done using a dedicated function and a pair of tracking variables. Within -% each graphics scope we use a global variable to do the work, with a group -% used to save the value between scopes. The result is that no direct action -% is needed when creating a scope. -% \begin{macrocode} -\cs_new_protected:Npn \driver_draw_scope_begin: - { - \int_set_eq:NN - \l_@@_draw_scope_int - \g_@@_draw_scope_int - \group_begin: - \int_gzero:N \g_@@_draw_scope_int - } -\cs_new_protected:Npn \driver_draw_scope_end: - { - \prg_replicate:nn - { \g_@@_draw_scope_int } - { \@@_draw_literal:n { } } - \group_end: - \int_gset_eq:NN - \g_@@_draw_scope_int - \l_@@_draw_scope_int - } -\cs_new_protected:Npn \@@_draw_scope:n #1 - { - \@@_draw_literal:n { } - \int_gincr:N \g_@@_draw_scope_int - } -\cs_generate_variant:Nn \@@_draw_scope:n { x } -\int_new:N \g_@@_draw_scope_int -\int_new:N \l_@@_draw_scope_int -% \end{macrocode} -% \end{variable} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\driver_draw_moveto:nn, \driver_draw_lineto:nn} -% \begin{macro}{\driver_draw_rectangle:nnnn} -% \begin{macro}{\driver_draw_curveto:nnnnnn} -% \begin{macro}{\@@_draw_add_to_path:n} -% \begin{variable}{\g_@@_draw_path_tl} -% Once again, some work is needed to get path constructs correct. Rather -% then write the values as they are given, the entire path needs to be -% collected up before being output in one go. For that we use a dedicated -% storage routine, which adds spaces as required. Since paths should -% be fully expanded there is no need to worry about the internal -% \texttt{x}-type expansion. -% \begin{macrocode} -\cs_new_protected:Npn \driver_draw_moveto:nn #1#2 - { - \@@_draw_add_to_path:n - { M ~ \dim_to_decimal:n {#1} ~ \dim_to_decimal:n {#2} } - } -\cs_new_protected:Npn \driver_draw_lineto:nn #1#2 - { - \@@_draw_add_to_path:n - { L ~ \dim_to_decimal:n {#1} ~ \dim_to_decimal:n {#2} } - } -\cs_new_protected:Npn \driver_draw_rectangle:nnnn #1#2#3#4 - { - \@@_draw_add_to_path:n - { - M ~ \dim_to_decimal:n {#1} ~ \dim_to_decimal:n {#2} - h ~ \dim_to_decimal:n {#3} ~ - v ~ \dim_to_decimal:n {#4} ~ - h ~ \dim_to_decimal:n { -#3 } ~ - Z - } - } -\cs_new_protected:Npn \driver_draw_curveto:nnnnnn #1#2#3#4#5#6 - { - \@@_draw_add_to_path:n - { - C ~ - \dim_to_decimal:n {#1} ~ \dim_to_decimal:n {#2} ~ - \dim_to_decimal:n {#3} ~ \dim_to_decimal:n {#4} ~ - \dim_to_decimal:n {#5} ~ \dim_to_decimal:n {#6} - } - } -\cs_new_protected:Npn \@@_draw_add_to_path:n #1 - { - \tl_gset:Nx \g_@@_draw_path_tl - { - \g_@@_draw_path_tl - \tl_if_empty:NF \g_@@_draw_path_tl { \c_space_tl } - #1 - } - } -\tl_new:N \g_@@_draw_path_tl -% \end{macrocode} -% \end{variable} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\driver_draw_evenodd_rule:, \driver_draw_nonzero_rule:} -% The fill rules here have to be handled as scopes. -% \begin{macrocode} -\cs_new_protected:Npn \driver_draw_evenodd_rule: - { \@@_draw_scope:n { fill-rule="evenodd" } } -\cs_new_protected:Npn \driver_draw_nonzero_rule: - { \@@_draw_scope:n { fill-rule="nonzero" } } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\@@_draw_path:n} -% \begin{macro} -% { -% \driver_draw_closepath: , -% \driver_draw_stroke: , -% \driver_draw_closestroke: , -% \driver_draw_fill: , -% \driver_draw_fillstroke: , -% \driver_draw_clip: , -% \driver_draw_discardpath: -% } -% \begin{variable}{\g_@@_draw_clip_bool} -% \begin{variable}{\g_@@_draw_path_int} -% Setting fill and stroke effects and doing clipping all has to be done using -% scopes. This means setting up the various requirements in a shared -% auxiliary which deals with the bits and pieces. Clipping paths are reused -% for path drawing: not essential but avoids constructing them twice. -% Discarding a path needs a separate function as it's not quite the same. -% \begin{macrocode} -\cs_new_protected:Npn \driver_draw_closepath: - { \@@_draw_add_to_path:n { Z } } -\cs_new_protected:Npn \@@_draw_path:n #1 - { - \bool_if:NTF \g_@@_draw_clip_bool - { - \int_gincr:N \g_@@_clip_path_int - \@@_draw_literal:x - { - < clipPath~id = " l3cp \int_use:N \g_@@_clip_path_int " > - { ?nl } - { ?nl } - < /clipPath > { ? nl } - < - use~xlink:href = - "\c_hash_str l3path \int_use:N \g_@@_path_int " ~ - #1 - /> - } - \@@_draw_scope:x - { - clip-path = - "url( \c_hash_str l3cp \int_use:N \g_@@_clip_path_int)" - } - } - { - \@@_draw_literal:x - { } - } - \tl_gclear:N \g_@@_draw_path_tl - \bool_gset_false:N \g_@@_draw_clip_bool - } -\int_new:N \g_@@_path_int -\cs_new_protected:Npn \driver_draw_stroke: - { \@@_draw_path:n { style="fill:none" } } -\cs_new_protected:Npn \driver_draw_closestroke: - { - \driver_draw_closepath: - \driver_draw_stroke: - } -\cs_new_protected:Npn \driver_draw_fill: - { \@@_draw_path:n { style="stroke:none" } } -\cs_new_protected:Npn \driver_draw_fillstroke: - { \@@_draw_path:n { } } -\cs_new_protected:Npn \driver_draw_clip: - { \bool_gset_true:N \g_@@_draw_clip_bool } -\bool_new:N \g_@@_draw_clip_bool -\cs_new_protected:Npn \driver_draw_discardpath: - { - \bool_if:NT \g_@@_draw_clip_bool - { - \int_gincr:N \g_@@_clip_path_int - \@@_draw_literal:x - { - < clipPath~id = " l3cp \int_use:N \g_@@_clip_path_int " > - { ?nl } - { ?nl } - < /clipPath > - } - \@@_draw_scope:x - { - clip-path = - "url( \c_hash_str l3cp \int_use:N \g_@@_clip_path_int)" - } - } - \tl_gclear:N \g_@@_draw_path_tl - \bool_gset_false:N \g_@@_draw_clip_bool - } -% \end{macrocode} -% \end{variable} -% \end{variable} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\driver_draw_dash_pattern:nn} -% \begin{macro}{\@@_draw_dash:n} -% \begin{macro}{\@@_draw_dash_aux:nn} -% \begin{macro}{\driver_draw_linewidth:n} -% \begin{macro}{\driver_draw_miterlimit:n} -% \begin{macro} -% { -% \driver_draw_cap_butt:, \driver_draw_cap_round:, \driver_draw_cap_rectangle:, -% \driver_draw_join_miter:, \driver_draw_join_round:, \driver_draw_join_bevel: -% } -% All of these ideas are properties of scopes in SVG. The only slight -% complexity is converting the dash array properly (doing any required -% maths). -% \begin{macrocode} -\cs_new_protected:Npn \driver_draw_dash_pattern:nn #1#2 - { - \use:x - { - \@@_draw_dash_aux:nn - { \clist_map_function:nn {#1} \@@_draw_dash:n } - { \dim_to_decimal:n {#2} } - } - } -\cs_new:Npn \@@_draw_dash:n #1 - { , \dim_to_decimal_in_bp:n {#1} } -\cs_new_protected:Npn \@@_draw_dash_aux:nn #1#2 - { - \@@_draw_scope:x - { - stroke-dasharray = - " - \tl_if_empty:oTF { \use_none:n #1 } - { none } - { \use_none:n #1 } - " ~ - stroke-offset=" #2 " - } - } -\cs_new_protected:Npn \driver_draw_linewidth:n #1 - { \@@_draw_scope:x { stroke-width=" \dim_to_decimal:n {#1} " } } -\cs_new_protected:Npn \driver_draw_miterlimit:n #1 - { \@@_draw_scope:x { stroke-miterlimit=" \fp_eval:n {#1} " } } -\cs_new_protected:Npn \driver_draw_cap_butt: - { \@@_draw_scope:n { stroke-linecap="butt" } } -\cs_new_protected:Npn \driver_draw_cap_round: - { \@@_draw_scope:n { stroke-linecap="round" } } -\cs_new_protected:Npn \driver_draw_cap_rectangle: - { \@@_draw_scope:n { stroke-linecap="square" } } -\cs_new_protected:Npn \driver_draw_join_miter: - { \@@_draw_scope:n { stroke-linejoin="miter" } } -\cs_new_protected:Npn \driver_draw_join_round: - { \@@_draw_scope:n { stroke-linejoin="round" } } -\cs_new_protected:Npn \driver_draw_join_bevel: - { \@@_draw_scope:n { stroke-linejoin="bevel" } } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro} -% { -% \driver_draw_color_fill_cmyk:nnnn , -% \driver_draw_color_stroke_cmyk:nnnn -% } -% \begin{macro} -% { -% \driver_draw_color_fill_gray:n , -% \driver_draw_color_stroke_gray:n -% } -% \begin{macro} -% { -% \driver_draw_color_fill_rgb:nnn , -% \driver_draw_color_stroke_rgb:nnn -% } -% \begin{macro}{\@@_draw_color_fill:nnn} -% SVG fill color has to be covered outside of the stack, as for -% \texttt{dvips}. Here, we are only allowed RGB colors so there is some -% conversion to do. -% \begin{macrocode} -\cs_new_protected:Npn \driver_draw_color_fill_cmyk:nnnn #1#2#3#4 - { - \use:x - { - \@@_draw_color_fill:nnn - { \fp_eval:n { -100 * ( (#1) * ( 1 - (#4) ) - 1 ) } } - { \fp_eval:n { -100 * ( (#2) * ( 1 - (#4) ) + #4 - 1 ) } } - { \fp_eval:n { -100 * ( (#3) * ( 1 - (#4) ) + #4 - 1 ) } } - } - } -\cs_new_eq:NN \driver_draw_color_stroke_cmyk:nnnn \driver_color_cmyk:nnnn -\cs_new_protected:Npn \driver_draw_color_fill_gray:n #1 - { - \use:x - { - \@@_draw_color_gray_aux:n - { \fp_eval:n { 100 * (#1) } } - } - } -\cs_new_protected:Npn \@@_draw_color_gray_aux:n #1 - { \@@_draw_color_fill:nnn {#1} {#1} {#1} } -\cs_new_eq:NN \driver_draw_color_stroke_gray:n \driver_color_gray:n -\cs_new_protected:Npn \driver_draw_color_fill_rgb:nnn #1#2#3 - { - \use:x - { - \@@_draw_color_fill:nnn - { \fp_eval:n { 100 * (#1) } } - { \fp_eval:n { 100 * (#2) } } - { \fp_eval:n { 100 * (#3) } } - } - } -\cs_new_protected:Npn \@@_draw_color_fill:nnn #1#2#3 - { - \@@_draw_scope:x - { - fill = - " - rgb - ( - #1 \c_percent_str , - #2 \c_percent_str , - #3 \c_percent_str - ) - " - } - } -\cs_new_eq:NN \driver_draw_color_stroke_rgb:nnn \driver_color_rgb:nnn -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\driver_draw_cm:nnnn} -% The four arguments here are floats (the affine matrix), the last -% two are a displacement vector. -% \begin{macrocode} -\cs_new_protected:Npn \driver_draw_cm:nnnn #1#2#3#4 - { - \@@_draw_scope:n - { - transform = - " - matrix - ( - \fp_eval:n {#1} , \fp_eval:n {#2} , - \fp_eval:n {#3} , \fp_eval:n {#4} , - 0pt , 0pt - ) - " - } - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\driver_draw_box_use:Nnnnn} -% No special savings can be made here: simply displace the box inside -% a scope. As there is nothing to re-box, just make the box passed of -% zero size. -% \begin{macrocode} -\cs_new_protected:Npn \driver_draw_box_use:Nnnnn #1#2#3#4#5#6#7 - { - \@@_scope_begin: - \driver_draw_cm:nnnn {#2} {#3} {#4} {#5} - \@@_literal_svg:n - { - < g~ - stroke="none"~ - transform="scale(-1,1)~translate({?x},{?y})~scale(-1,-1)" - > - } - \box_set_wd:Nn #1 { 0pt } - \box_set_ht:Nn #1 { 0pt } - \box_set_dp:Nn #1 { 0pt } - \box_use:N #1 - \@@_literal_svg:n { } - \@@_scope_end: - } -% \end{macrocode} -% \end{macro} -% -% \begin{macrocode} -% -% \end{macrocode} -% -% \begin{macrocode} -% -% \end{macrocode} -% -% \end{implementation} -% -% \PrintIndex diff --git a/Master/texmf-dist/source/latex/l3kernel/l3drivers-graphics.dtx b/Master/texmf-dist/source/latex/l3kernel/l3drivers-graphics.dtx deleted file mode 100644 index 86bfcfeb1f7..00000000000 --- a/Master/texmf-dist/source/latex/l3kernel/l3drivers-graphics.dtx +++ /dev/null @@ -1,611 +0,0 @@ -% \iffalse meta-comment -% -%% File: l3drivers-graphics.dtx -% -% Copyright (C) 2019 The LaTeX3 Project -% -% It may be distributed and/or modified under the conditions of the -% LaTeX Project Public License (LPPL), either version 1.3c of this -% license or (at your option) any later version. The latest version -% of this license is in the file -% -% https://www.latex-project.org/lppl.txt -% -% This file is part of the "l3kernel bundle" (The Work in LPPL) -% and all files in that bundle must be distributed together. -% -% ----------------------------------------------------------------------- -% -% The development version of the bundle can be found at -% -% https://github.com/latex3/latex3 -% -% for those people who are interested. -% -%<*driver> -\documentclass[full,kernel]{l3doc} -\begin{document} - \DocInput{\jobname.dtx} -\end{document} -% -% \fi -% -% \title{^^A -% The \textsf{l3drivers-graphics} package\\ Driver graphics support^^A -% } -% -% \author{^^A -% The \LaTeX3 Project\thanks -% {^^A -% E-mail: -% \href{mailto:latex-team@latex-project.org} -% {latex-team@latex-project.org}^^A -% }^^A -% } -% -% \date{Released 2019-05-28} -% -% \maketitle -% -% \begin{documentation} -% -% \end{documentation} -% -% \begin{implementation} -% -% \section{\pkg{l3drivers-graphics} Implementation} -% -% \begin{macrocode} -%<*initex|package> -%<@@=driver> -% \end{macrocode} -% -% \subsection{\texttt{dvips} driver} -% -% \begin{macrocode} -%<*dvips> -% \end{macrocode} -% -% \begin{macro}{\driver_graphics_getbb_eps:n} -% Simply use the generic function. -% \begin{macrocode} -%<*initex> -\use:n -% -%<*package> -\AtBeginDocument -% - { \cs_new_eq:NN \driver_graphics_getbb_eps:n \graphics_read_bb:n } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\driver_graphics_include_eps:n} -% The special syntax is relatively clear here: remember we need PostScript -% sizes here. -% \begin{macrocode} -\cs_new_protected:Npn \driver_graphics_include_eps:n #1 - { - \@@_literal:x - { - PSfile = #1 \c_space_tl - llx = \dim_to_decimal_in_bp:n \l_graphics_llx_dim \c_space_tl - lly = \dim_to_decimal_in_bp:n \l_graphics_lly_dim \c_space_tl - urx = \dim_to_decimal_in_bp:n \l_graphics_urx_dim \c_space_tl - ury = \dim_to_decimal_in_bp:n \l_graphics_ury_dim - } - } -% \end{macrocode} -% \end{macro} -% -% \begin{macrocode} -% -% \end{macrocode} -% -% \subsection{\texttt{pdfmode} driver} -% -% \begin{macrocode} -%<*pdfmode> -% \end{macrocode} -% -% \begin{variable}{\l_@@_graphics_attr_tl} -% In PDF mode, additional attributes of an graphic (such as page number) are -% needed both to obtain the bounding box and when inserting the graphic: this -% occurs as the graphic dictionary approach means they are read as part of -% the bounding box operation. As such, it is easier to track additional -% attributes using a dedicated |tl| rather than build up the same data -% twice. -% \begin{macrocode} -\tl_new:N \l_@@_graphics_attr_tl -% \end{macrocode} -% \end{variable} -% -% \begin{macro} -% { -% \driver_graphics_getbb_jpg:n, -% \driver_graphics_getbb_pdf:n, -% \driver_graphics_getbb_png:n -% } -% \begin{macro} -% {\@@_graphics_getbb_auxi:n, \@@_graphics_getbb_auxii:n} -% Getting the bounding box here requires us to box up the graphic and -% measure it. To deal with the difference in feature support in bitmap -% and vector graphics but keeping the common parts, there is a little work -% to do in terms of auxiliaries. The key here is to notice that we need -% two forms of the attributes: a \enquote{short} set to allow us to -% track for caching, and the full form to pass to the primitive. -% \begin{macrocode} -\cs_new_protected:Npn \driver_graphics_getbb_jpg:n #1 - { - \int_zero:N \l_graphics_page_int - \tl_clear:N \l_graphics_pagebox_tl - \tl_set:Nx \l_@@_graphics_attr_tl - { - \tl_if_empty:NF \l_graphics_decodearray_tl - { :D \l_graphics_decodearray_tl } - \bool_if:NT \l_graphics_interpolate_bool - { :I } - } - \tl_clear:N \l_@@_graphics_attr_tl - \@@_graphics_getbb_auxi:n {#1} - } -\cs_new_eq:NN \driver_graphics_getbb_png:n \driver_graphics_getbb_jpg:n -\cs_new_protected:Npn \driver_graphics_getbb_pdf:n #1 - { - \tl_clear:N \l_graphics_decodearray_tl - \bool_set_false:N \l_graphics_interpolate_bool - \tl_set:Nx \l_@@_graphics_attr_tl - { - : \l_graphics_pagebox_tl - \int_compare:nNnT \l_graphics_page_int > 1 - { :P \int_use:N \l_graphics_page_int } - } - \@@_graphics_getbb_auxi:n {#1} - } -\cs_new_protected:Npn \@@_graphics_getbb_auxi:n #1 - { - \graphics_bb_restore:xF { #1 \l_@@_graphics_attr_tl } - { \@@_graphics_getbb_auxii:n {#1} } - } -% \begin{macrocode} -% Measuring the graphic is done by boxing up: for PDF graphics we could -% use |\tex_pdfximagebbox:D|, but if doesn't work for other types. -% As the box always starts at $(0,0)$ there is no need to worry about -% the lower-left position. -% \begin{macrocode} -\cs_new_protected:Npn \@@_graphics_getbb_auxii:n #1 - { - \tex_immediate:D \tex_pdfximage:D - \bool_lazy_or:nnT - { \l_graphics_interpolate_bool } - { ! \tl_if_empty_p:N \l_graphics_decodearray_tl } - { - attr ~ - { - \tl_if_empty:NF \l_graphics_decodearray_tl - { /Decode~[ \l_graphics_decodearray_tl ] } - \bool_if:NT \l_graphics_interpolate_bool - { /Interpolate~true } - } - } - \int_compare:nNnT \l_graphics_page_int > 0 - { page ~ \int_use:N \l_graphics_page_int } - \tl_if_empty:NF \l_graphics_pagebox_tl - { \l_graphics_pagebox_tl } - {#1} - \hbox_set:Nn \l_@@_internal_box - { \tex_pdfrefximage:D \tex_pdflastximage:D } - \dim_set:Nn \l_graphics_urx_dim { \box_wd:N \l_@@_internal_box } - \dim_set:Nn \l_graphics_ury_dim { \box_ht:N \l_@@_internal_box } - \int_const:cn { c_@@_graphics_ #1 \l_@@_graphics_attr_tl _int } - { \tex_the:D \tex_pdflastximage:D } - \graphics_bb_save:x { #1 \l_@@_graphics_attr_tl } - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro} -% { -% \driver_graphics_include_jpg:n, -% \driver_graphics_include_pdf:n, -% \driver_graphics_include_png:n -% } -% Images are already loaded for the measurement part of the code, so -% inclusion is straight-forward, with only any attributes to worry about. The -% latter carry through from determination of the bounding box. -% \begin{macrocode} -\cs_new_protected:Npn \driver_graphics_include_jpg:n #1 - { - \tex_pdfrefximage:D - \int_use:c { c_@@_graphics_ #1 \l_@@_graphics_attr_tl _int } - } -\cs_new_eq:NN \driver_graphics_include_pdf:n \driver_graphics_include_jpg:n -\cs_new_eq:NN \driver_graphics_include_png:n \driver_graphics_include_jpg:n -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\driver_graphics_getbb_eps:n} -% \begin{macro}{\@@_graphics_getbb_eps:nm} -% \begin{macro}{\driver_graphics_include_eps:n} -% \begin{variable}{\l_@@_dir_str, \l_@@_name_str, \l_@@_ext_str} -% EPS graphics may be included in \texttt{pdfmode} by conversion to -% PDF: this requires restricted shell escape. Modelled on the \pkg{epstopdf} -% \LaTeXe{} package, but simplified, conversion takes place here if we have -% shell access. -% \begin{macrocode} -\sys_if_shell:T - { - \str_new:N \l_@@_dir_str - \str_new:N \l_@@_name_str - \str_new:N \l_@@_ext_str - \cs_new_protected:Npn \driver_graphics_getbb_eps:n #1 - { - \file_parse_full_name:nNNN {#1} - \l_@@_dir_str - \l_@@_name_str - \l_@@_ext_str - \exp_args:Nx \@@_graphics_getbb_eps:nn - { - \l_@@_name_str - \str_tail:N \l_@@_ext_str - -converted-to.pdf - } - {#1} - } - \cs_new_protected:Npn \@@_graphics_getbb_eps:nn #1#2 - { - \file_compare_timestamp:nNnT {#2} > {#1} - { - \sys_shell_now:n - { repstopdf ~ #2 ~ #1 } - } - \tl_set:Nn \l_graphics_name_tl {#1} - \driver_graphics_getbb_pdf:n {#1} - } - \cs_new_protected:Npn \driver_graphics_include_eps:n #1 - { - \file_parse_full_name:nNNN {#1} - \l_@@_dir_str \l_@@_name_str \l_@@_ext_str - \exp_args:Nx \driver_graphics_include_pdf:n - { - \l_@@_name_str - \str_tail:N \l_@@_ext_str - -converted-to.pdf - } - } - } -% \end{macrocode} -% \end{variable} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macrocode} -% -% \end{macrocode} -% -% \subsection{\texttt{dvipdfmx} driver} -% -% \begin{macrocode} -%<*dvipdfmx|xdvipdfmx> -% \end{macrocode} -% -% \begin{macro} -% { -% \driver_graphics_getbb_eps:n, \driver_graphics_getbb_jpg:n, -% \driver_graphics_getbb_pdf:n, \driver_graphics_getbb_png:n -% } -% Simply use the generic functions: only for \texttt{dvipdfmx} in the -% extraction cases. -% \begin{macrocode} -%<*initex> -\use:n -% -%<*package> -\AtBeginDocument -% - { \cs_new_eq:NN \driver_graphics_getbb_eps:n \graphics_read_bb:n } -%<*dvipdfmx> -\cs_new_protected:Npn \driver_graphics_getbb_jpg:n #1 - { - \int_zero:N \l_graphics_page_int - \tl_clear:N \l_graphics_pagebox_tl - \graphics_extract_bb:n {#1} - } -\cs_new_eq:NN \driver_graphics_getbb_png:n \driver_graphics_getbb_jpg:n -\cs_new_protected:Npn \driver_graphics_getbb_pdf:n #1 - { - \tl_clear:N \l_graphics_decodearray_tl - \bool_set_false:N \l_graphics_interpolate_bool - \graphics_extract_bb:n {#1} - } -% -% \end{macrocode} -% \end{macro} -% -% \begin{variable}{\g_@@_graphics_int} -% Used to track the object number associated with each graphic. -% \begin{macrocode} -\int_new:N \g_@@_graphics_int -% \end{macrocode} -% \end{variable} -% -% \begin{macro} -% { -% \driver_graphics_include_eps:n, \driver_graphics_include_jpg:n, -% \driver_graphics_include_pdf:n, \driver_graphics_include_png:n -% } -% \begin{macro}{\@@_graphics_include_auxi:nn} -% \begin{macro}{\@@_graphics_include_auxii:nnn, \@@_graphics_include_auxii:xnn} -% \begin{macro}{\@@_graphics_include_auxiii:nnn} -% The special syntax depends on the file type. There is a difference in -% how PDF graphics are best handled between |dvipdfmx| and |xdvipdfmx|: for -% the latter it is better to use the primitive route. The relevant code for -% that is included later in this file. -% \begin{macrocode} -\cs_new_protected:Npn \driver_graphics_include_eps:n #1 - { - \@@_literal:x - { - PSfile = #1 \c_space_tl - llx = \dim_to_decimal_in_bp:n \l_graphics_llx_dim \c_space_tl - lly = \dim_to_decimal_in_bp:n \l_graphics_lly_dim \c_space_tl - urx = \dim_to_decimal_in_bp:n \l_graphics_urx_dim \c_space_tl - ury = \dim_to_decimal_in_bp:n \l_graphics_ury_dim - } - } -\cs_new_protected:Npn \driver_graphics_include_jpg:n #1 - { \@@_graphics_include_auxi:nn {#1} { image } } -\cs_new_eq:NN \driver_graphics_include_png:n \driver_graphics_include_jpg:n -%<*dvipdfmx> -\cs_new_protected:Npn \driver_graphics_include_pdf:n #1 - { \@@_graphics_include_auxi:nn {#1} { epdf } } -% -% \end{macrocode} -% Graphic inclusion is set up to use the fact that each image is stored in -% the PDF as an XObject. This means that we can include repeated images -% only once and refer to them. To allow that, track the nature of each -% image: much the same as for the direct PDF mode case. -% \begin{macrocode} -\cs_new_protected:Npn \@@_graphics_include_auxi:nn #1#2 - { - \@@_graphics_include_auxii:xnn - { - \tl_if_empty:NF \l_graphics_pagebox_tl - { : \l_graphics_pagebox_tl } - \int_compare:nNnT \l_graphics_page_int > 1 - { :P \int_use:N \l_graphics_page_int } - \tl_if_empty:NF \l_graphics_decodearray_tl - { :D \l_graphics_decodearray_tl } - \bool_if:NT \l_graphics_interpolate_bool - { :I } - } - {#1} {#2} - } -\cs_new_protected:Npn \@@_graphics_include_auxii:nnn #1#2#3 - { - \int_if_exist:cTF { c_@@_graphics_ #2#1 _int } - { - \@@_literal:x - { pdf:usexobj~@graphic \int_use:c { c_@@_graphics_ #2#1 _int } } - } - { \@@_graphics_include_auxiii:nnn {#2} {#1} {#3} } - } -\cs_generate_variant:Nn \@@_graphics_include_auxii:nnn { x } -% \end{macrocode} -% Inclusion using the specials is relatively straight-forward, but there -% is one wrinkle. To get the |pagebox| correct for PDF graphics in all cases, -% it is necessary to provide both that information and the |bbox| argument: -% odd things happen otherwise! -% \begin{macrocode} -\cs_new_protected:Npn \@@_graphics_include_auxiii:nnn #1#2#3 - { - \int_gincr:N \g_@@_graphics_int - \int_const:cn { c_@@_graphics_ #1#2 _int } { \g_@@_graphics_int } - \@@_literal:x - { - pdf:#3~ - @graphic \int_use:c { c_@@_graphics_ #1#2 _int } ~ - \int_compare:nNnT \l_graphics_page_int > 1 - { page ~ \int_use:N \l_graphics_page_int \c_space_tl } - \tl_if_empty:NF \l_graphics_pagebox_tl - { - pagebox ~ \l_graphics_pagebox_tl \c_space_tl - bbox ~ - \dim_to_decimal_in_bp:n \l_graphics_llx_dim \c_space_tl - \dim_to_decimal_in_bp:n \l_graphics_lly_dim \c_space_tl - \dim_to_decimal_in_bp:n \l_graphics_urx_dim \c_space_tl - \dim_to_decimal_in_bp:n \l_graphics_ury_dim \c_space_tl - } - (#1) - \bool_lazy_or:nnT - { \l_graphics_interpolate_bool } - { ! \tl_if_empty_p:N \l_graphics_decodearray_tl } - { - << - \tl_if_empty:NF \l_graphics_decodearray_tl - { /Decode~[ \l_graphics_decodearray_tl ] } - \bool_if:NT \l_graphics_interpolate_bool - { /Interpolate~true> } - >> - } - } - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macrocode} -% -% \end{macrocode} -% -% \subsection{\texttt{xdvipdfmx} driver} -% -% \begin{macrocode} -%<*xdvipdfmx> -% \end{macrocode} -% -% \subsubsection{Images} -% -% \begin{macro} -% { -% \driver_graphics_getbb_jpg:n, -% \driver_graphics_getbb_pdf:n, -% \driver_graphics_getbb_png:n -% } -% \begin{macro}{\@@_graphics_getbb_auxi:nN} -% \begin{macro}{\@@_graphics_getbb_auxii:nnN, \@@_graphics_getbb_auxii:VnN} -% \begin{macro}{\@@_graphics_getbb_auxiii:nNnn} -% \begin{macro}{\@@_graphics_getbb_auxiv:nnNnn, \@@_graphics_getbb_auxiv:VnNnn} -% \begin{macro}{\@@_graphics_getbb_auxv:nNnn, \@@_graphics_getbb_auxv:nNnn} -% \begin{macro}[EXP]{\@@_graphics_getbb_pagebox:w} -% For \texttt{xdvipdfmx}, there are two primitives that allow us to obtain -% the bounding box without needing \texttt{extractbb}. The only complexity -% is passing the various minor variations to a common core process. The -% \XeTeX{} primitive omits the text |box| from the page box specification, -% so there is also some \enquote{trimming} to do here. -% \begin{macrocode} -\cs_new_protected:Npn \driver_graphics_getbb_jpg:n #1 - { - \int_zero:N \l_graphics_page_int - \tl_clear:N \l_graphics_pagebox_tl - \@@_graphics_getbb_auxi:nN {#1} \tex_XeTeXpicfile:D - } -\cs_new_eq:NN \driver_graphics_getbb_png:n \driver_graphics_getbb_jpg:n -\cs_new_protected:Npn \driver_graphics_getbb_pdf:n #1 - { - \tl_clear:N \l_graphics_decodearray_tl - \bool_set_false:N \l_graphics_interpolate_bool - \@@_graphics_getbb_auxi:nN {#1} \tex_XeTeXpdffile:D - } -\cs_new_protected:Npn \@@_graphics_getbb_auxi:nN #1#2 - { - \int_compare:nNnTF \l_graphics_page_int > 1 - { \@@_graphics_getbb_auxii:VnN \l_graphics_page_int {#1} #2 } - { \@@_graphics_getbb_auxiii:nNnn {#1} #2 { :P 1 } { page 1 } } - } -\cs_new_protected:Npn \@@_graphics_getbb_auxii:nnN #1#2#3 - { \@@_graphics_getbb_auxiii:nNnn {#2} #3 { :P #1 } { page #1 } } -\cs_generate_variant:Nn \@@_graphics_getbb_auxii:nnN { V } -\cs_new_protected:Npn \@@_graphics_getbb_auxiii:nNnn #1#2#3#4 - { - \tl_if_empty:NTF \l_graphics_pagebox_tl - { \@@_graphics_getbb_auxiv:VnNnn \l_graphics_pagebox_tl } - { \@@_graphics_getbb_auxv:nNnn } - {#1} #2 {#3} {#4} - } -\cs_new_protected:Npn \@@_graphics_getbb_auxiv:nnNnn #1#2#3#4#5 - { - \use:x - { - \@@_graphics_getbb_auxv:nNnn {#2} #3 { : #1 #4 } - { #5 ~ \@@_graphics_getbb_pagebox:w #1 } - } - } -\cs_generate_variant:Nn \@@_graphics_getbb_auxiv:nnNnn { V } -\cs_new_protected:Npn \@@_graphics_getbb_auxv:nNnn #1#2#3#4 - { - \graphics_bb_restore:nF {#1#3} - { \@@_graphics_getbb_auxvi:nNnn {#1} #2 {#3} {#4} } - } -\cs_new_protected:Npn \@@_graphics_getbb_auxvi:nNnn #1#2#3#4 - { - \hbox_set:Nn \l_@@_internal_box { #2 #1 ~ #4 } - \dim_set:Nn \l_graphics_urx_dim { \box_wd:N \l_@@_internal_box } - \dim_set:Nn \l_graphics_ury_dim { \box_ht:N \l_@@_internal_box } - \graphics_bb_save:n {#1#3} - } -\cs_new:Npn \@@_graphics_getbb_pagebox:w #1 box {#1} -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\driver_graphics_include_pdf:n} -% \begin{macro}{\@@_graphics_include_bitmap_quote:w} -% For PDF graphics, properly supporting the |pagebox| concept in \XeTeX{} -% is best done using the |\tex_XeTeXpdffile:D| primitive. The syntax here -% is the same as for the graphic measurement part, although we know at this -% stage that there must be some valid setting for \cs{l_graphics_pagebox_tl}. -% \begin{macrocode} -\cs_new_protected:Npn \driver_graphics_include_pdf:n #1 - { - \tex_XeTeXpdffile:D - \@@_graphics_include_pdf_quote:w #1 "#1" \q_stop \c_space_tl - \int_compare:nNnT \l_graphics_page_int > 0 - { page ~ \int_use:N \l_graphics_page_int \c_space_tl } - \exp_after:wN \@@_graphics_getbb_pagebox:w \l_graphics_pagebox_tl - } -\cs_new:Npn \@@_graphics_include_pdf_quote:w #1 " #2 " #3 \q_stop - { " #2 " } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macrocode} -% -% \end{macrocode} -% -% \subsection{\texttt{dvisvgm} driver} -% -% \begin{macrocode} -%<*dvisvgm> -% \end{macrocode} -% -% \begin{macro}{\driver_graphics_getbb_png:n, \driver_graphics_getbb_jpg:n} -% These can be included by extracting the bounding box data. -% \begin{macrocode} -%<*initex> -\use:n -% -%<*package> -\AtBeginDocument -% - { - \cs_new_eq:NN \driver_graphics_getbb_png:n \graphics_extract_bb:n - \cs_new_eq:NN \driver_graphics_getbb_jpg:n \graphics_extract_bb:n - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\driver_graphics_include_png:n, \driver_graphics_include_jpg:n} -% \begin{macro}{\@@_graphics_include_bitmap_quote:w} -% The driver here has built-in support for basic graphic inclusion (see -% \texttt{dvisvgm.def} for a more complex approach, needed if clipping, -% \emph{etc.}, is covered at the graphic driver level). The only issue is -% that |#1| must be quote-corrected. The \texttt{dvisvgm:img} operation -% quotes the file name, but if it is already quoted (contains spaces) -% then we have an issue: we simply strip off any quotes as a result. -% \begin{macrocode} -\cs_new_protected:Npn \driver_graphics_include_png:n #1 - { - \@@_literal:x - { - dvisvgm:img~ - \dim_to_decimal:n { \l_graphics_ury_dim } ~ - \dim_to_decimal:n { \l_graphics_ury_dim } ~ - \@@_graphics_include_bitmap_quote:w #1 " #1 " \q_stop - } - } -\cs_new_eq:NN \driver_graphics_include_jpg:n \driver_graphics_include_png:n -\cs_new:Npn \@@_graphics_include_bitmap_quote:w #1 " #2 " #3 \q_stop - { " #2 " } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macrocode} -% -% \end{macrocode} -% -% \begin{macrocode} -% -% \end{macrocode} -% -% \end{implementation} -% -% \PrintIndex diff --git a/Master/texmf-dist/source/latex/l3kernel/l3drivers-pdf.dtx b/Master/texmf-dist/source/latex/l3kernel/l3drivers-pdf.dtx deleted file mode 100644 index 62a3bea1119..00000000000 --- a/Master/texmf-dist/source/latex/l3kernel/l3drivers-pdf.dtx +++ /dev/null @@ -1,1934 +0,0 @@ -% \iffalse meta-comment -% -%% File: l3drivers-pdf.dtx -% -% Copyright (C) 2011-2019 The LaTeX3 Project -% -% It may be distributed and/or modified under the conditions of the -% LaTeX Project Public License (LPPL), either version 1.3c of this -% license or (at your option) any later version. The latest version -% of this license is in the file -% -% https://www.latex-project.org/lppl.txt -% -% This file is part of the "l3kernel bundle" (The Work in LPPL) -% and all files in that bundle must be distributed together. -% -% ----------------------------------------------------------------------- -% -% The development version of the bundle can be found at -% -% https://github.com/latex3/latex3 -% -% for those people who are interested. -% -%<*driver> -\documentclass[full,kernel]{l3doc} -\begin{document} - \DocInput{\jobname.dtx} -\end{document} -% -% \fi -% -% \title{^^A -% The \textsf{l3drivers-pdf} package\\ Driver PDF features^^A -% } -% -% \author{^^A -% The \LaTeX3 Project\thanks -% {^^A -% E-mail: -% \href{mailto:latex-team@latex-project.org} -% {latex-team@latex-project.org}^^A -% }^^A -% } -% -% \date{Released 2019-05-28} -% -% \maketitle -% -% \begin{documentation} -% -% \end{documentation} -% -% \begin{implementation} -% -% \section{\pkg{l3drivers-pdf} Implementation} -% -% \begin{macrocode} -%<*initex|package> -%<@@=driver> -% \end{macrocode} -% -% Setting up PDF resources is a complex area with only limited documentation -% in the engine manuals. The following code builds heavily on existing ideas -% from \pkg{hyperref} work by Sebastian Rahtz and Heiko Oberdiek, and -% significant contributions by Alexander Grahn, in addition to the specific -% code referenced a various points. -% -% \subsection{Shared code} -% -% A very small number of items that belong at the driver level but which -% are common to all drivers. -% -% \subsection{\texttt{dvips} driver} -% -% \begin{macrocode} -%<*dvips> -% \end{macrocode} -% -% \begin{macro}{\@@_pdfmark:n, \@@_pdfmark:x} -% Used often enough it should be a separate function. -% \begin{macrocode} -\cs_new_protected:Npn \@@_pdfmark:n #1 - { \@@_postscript:n { mark #1 ~ pdfmark } } -\cs_generate_variant:Nn \@@_pdfmark:n { x } -% \end{macrocode} -% \end{macro} -% -% \subsubsection{Catalogue entries} -% -% \begin{macro}{\driver_pdf_catalog_gput:nn, \driver_pdf_info_gput:nn} -% \begin{macrocode} -\cs_new_protected:Npn \driver_pdf_catalog_gput:nn #1#2 - { \@@_pdfmark:n { { Catalog } << /#1 ~ #2 >> /PUT } } -\cs_new_protected:Npn \driver_pdf_info_gput:nn #1#2 - { \@@_pdfmark:n { /#1 ~ #2 /DOCINFO } } -% \end{macrocode} -% \end{macro} -% -% \subsubsection{Objects} -% -% \begin{variable}{\g_@@_pdf_object_int, \g_@@_pdf_object_prop} -% For tracking objects to allow finalisation. -% \begin{macrocode} -\int_new:N \g_@@_pdf_object_int -\prop_new:N \g_@@_pdf_object_prop -% \end{macrocode} -% \end{variable} -% -% \begin{macro}{\driver_pdf_object_new:nn} -% \begin{macro}[EXP]{\driver_pdf_object_ref:n} -% Tracking objects is similar to \texttt{dvipdfmx}. -% \begin{macrocode} -\cs_new_protected:Npn \driver_pdf_object_new:nn #1#2 - { - \int_gincr:N \g_@@_pdf_object_int - \int_const:cn - { c_@@_pdf_object_ \tl_to_str:n {#1} _int } - { \g_@@_pdf_object_int } - \prop_gput:Nnn \g_@@_pdf_object_prop {#1} {#2} - } -\cs_new:Npn \driver_pdf_object_ref:n #1 - { { driver.obj \int_use:c { c_@@_pdf_object_ \tl_to_str:n {#1} _int } } } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\driver_pdf_object_write:nn} -% \begin{macro} -% { -% \@@_pdf_object_write_array:nn , -% \@@_pdf_object_write_dict:nn , -% \@@_pdf_object_write_stream:nn -% } -% \begin{macro}{\@@_pdf_object_write_stream:nnn} -% This is where we choose the actual type: some work to get things -% right. -% \begin{macrocode} -\cs_new_protected:Npn \driver_pdf_object_write:nn #1#2 - { - \@@_pdfmark:x - { - /_objdef ~ \driver_pdf_object_ref:n {#1} - /type - \str_case_e:nn - { \prop_item:Nn \g_@@_pdf_object_prop {#1} } - { - { array } { /array } - { dict } { /dict } - { fstream } { /stream } - { stream } { /stream } - } - /OBJ - } - \use:c - { @@_pdf_object_write_ \prop_item:Nn \g_@@_pdf_object_prop {#1} :nn } - {#1} {#2} - } -\cs_new_protected:Npn \@@_pdf_object_write_array:nn #1#2 - { - \@@_pdfmark:x - { - \driver_pdf_object_ref:n {#1} - [ ~ \exp_not:n {#2} ~ ] ~ /PUTINTERVAL - } - } -\cs_new_protected:Npn \@@_pdf_object_write_dict:nn #1#2 - { - \@@_pdfmark:x - { - \driver_pdf_object_ref:n {#1} - << \exp_not:n {#2} >> /PUT - } - } -\cs_new_protected:Npn \@@_pdf_object_write_stream:nn #1#2 - { - \exp_args:Nx - \@@_pdf_object_write_stream:nnn - { \driver_pdf_object_ref:n {#1} } - #2 - } -\cs_new_protected:Npn \@@_pdf_object_write_stream:nnn #1#2#3 - { - \@@_postscript:n - { - [nobreak] - mark ~ #1 ~ ( #3 ) /PUT ~ pdfmark ~ - mark ~ #1 ~ << #2 >> /PUT ~ pdfmark - } - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \subsubsection{Annotations} -% -% In \texttt{dvips}, annotations have to be constructed manually. As such, -% we need the object code above for some definitions. -% -% \begin{macro}{driver.globaldict} -% A small global dictionary for driver use. -% \begin{macrocode} -\@@_postscript_header:n - { - true ~ setglobal ~ - /driver.globaldict ~ 4 ~ dict ~ def ~ - false ~ setglobal - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro} -% { -% driver.cvs , -% driver.dvi.pt , -% driver.pt.dvi , -% driver.rect.ht -% } -% Small utilities for PostScript manipulations. Conversion to DVI dimensions -% is done here to allow for |Resolution|. The total height of a rectangle -% (an array) needs a little maths, in contrast to simply extracting a value. -% \begin{macrocode} -\@@_postscript_header:n - { - /driver.cvs { 65534 ~ string ~ cvs } def - /driver.dvi.pt { 72.27 ~ mul ~ Resolution ~ div } def - /driver.pt.dvi { 72.27 ~ div ~ Resolution ~ mul } def - /driver.rect.ht { dup ~ 1 ~ get ~ neg ~ exch ~ 3 ~ get ~ add } def - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{driver.linkmargin, driver.linkdp.pad, driver.linkht.pad} -% Settings which are defined up-front in |SDict|. -% \begin{macrocode} -\@@_postscript_header:n - { - /driver.linkmargin { 1 ~ driver.pt.dvi } def - /driver.linkdp.pad { 0 } def - /driver.linkht.pad { 0 } def - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro} -% { -% driver.rect , -% driver.save.ll , -% driver.save.ur , -% driver.save.linkll , -% driver.save.linkur , -% driver.llx , -% driver.lly , -% driver.urx , -% driver.ury -% } -% Functions for marking the limits of an annotation/link, plus drawing the -% border. We separate links for generic annotations to support adding a -% margin and setting a minimal size. -% \begin{macrocode} -\@@_postscript_header:n - { - /driver.rect - { /Rect [ driver.llx ~ driver.lly ~ driver.urx ~ driver.ury ] } def - /driver.save.ll - { - currentpoint - /driver.lly ~ exch ~ def - /driver.llx ~ exch ~ def - } - def - /driver.save.ur - { - currentpoint - /driver.ury ~ exch ~ def - /driver.urx ~ exch ~ def - } - def - /driver.save.linkll - { - currentpoint ~ - driver.linkmargin ~ add ~ - driver.linkdp.pad ~ add - /driver.lly ~ exch ~ def ~ - driver.linkmargin ~ sub - /driver.llx ~ exch ~ def - } - def - /driver.save.linkur - { - currentpoint ~ - driver.linkmargin ~ sub ~ - driver.linkht.pad ~ sub - /driver.ury ~ exch ~ def ~ - driver.linkmargin ~ add - /driver.urx ~ exch ~ def - } - def - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro} -% { -% driver.dest.anchor , -% driver.dest.x , -% driver.dest.y , -% driver.dest.point , -% driver.dest2device , -% driver.dev.x , -% driver.dev.y , -% driver.tmpa , -% driver.tmpb , -% driver.tmpc , -% driver.tmpd -% } -% For finding the anchor point of a destination link. We make the use case -% a separate function as it comes up a lot, and as this makes it easier to -% adjust if we need additional effects. We also need a more complex approach -% to convert a co-ordinate pair correctly when defining a rectangle: this -% can otherwise be out when using a landscape page. (Thanks to Alexander -% Grahn for the approach here.) -% \begin{macrocode} -\@@_postscript_header:n - { - /driver.dest.anchor - { - currentpoint ~ exch ~ - driver.dvi.pt ~ 72 ~ add ~ - /driver.dest.x ~ exch ~ def ~ - driver.dvi.pt ~ - vsize ~ 72 ~ sub ~ exch ~ sub ~ - /driver.dest.y ~ exch ~ def - } - def - /driver.dest.point - { driver.dest.x ~ driver.dest.y } def - /driver.dest2device - { - /driver.dest.y ~ exch ~ def - /driver.dest.x ~ exch ~ def ~ - matrix ~ currentmatrix ~ - matrix ~ defaultmatrix ~ - matrix ~ invertmatrix ~ - matrix ~ concatmatrix ~ - cvx ~ exec - /driver.dev.y ~ exch ~ def - /driver.dev.x ~ exch ~ def - /driver.tmpd ~ exch ~ def - /driver.tmpc ~ exch ~ def - /driver.tmpb ~ exch ~ def - /driver.tmpa ~ exch ~ def ~ - driver.dest.x ~ driver.tmpa ~ mul ~ - driver.dest.y ~ driver.tmpc ~ mul ~ add ~ - driver.dev.x ~ add ~ - driver.dest.x ~ driver.tmpb ~ mul ~ - driver.dest.y ~ driver.tmpd ~ mul ~ add ~ - driver.dev.y ~ add - } - def - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro} -% { -% driver.bordertracking , -% driver.bordertracking.begin , -% driver.bordertracking.end , -% driver.leftboundary , -% driver.rightboundary , -% driver.brokenlink.rect , -% driver.brokenlink.skip , -% driver.brokenlink.dict , -% driver.bordertracking.endpage , -% driver.bordertracking.continue , -% driver.originx , -% driver.originy -% } -% To know where a breakable link can go, we need to track the boundary -% rectangle. That can be done by hooking into |a| and |x| operations: -% those names have to be retained. The boundary is stored at the end of -% the operation. Special effort is needed at the start and end of pages -% (or rather galleys), such that everything works properly. -% \begin{macrocode} -\@@_postscript_header:n - { - /driver.bordertracking ~ false ~ def - /driver.bordertracking.begin - { - SDict ~ /driver.bordertracking ~ true ~ put ~ - SDict ~ /driver.leftboundary ~ undef ~ - SDict ~ /driver.rightboundary ~ undef ~ - /a ~ where - { - /a - { - currentpoint ~ pop ~ - SDict /driver.rightboundary ~ known ~ dup - { - SDict /driver.rightboundary ~ get ~ 2 ~ index ~ lt - { not } - if - } - if - { pop } - { SDict ~ exch /driver.rightboundary ~ exch ~ put } - ifelse ~ - moveto ~ - currentpoint ~ pop ~ - SDict /driver.leftboundary ~ known ~ dup - { - SDict /driver.leftboundary ~ get ~ 2 ~ index ~ gt - { not } - if - } - if - { pop } - { SDict ~ exch /driver.leftboundary ~ exch ~ put } - ifelse - } - put - } - if - } - def - /driver.bordertracking.end - { - /a ~ where { /a { moveto } put } if - /x ~ where { /x { 0 ~ exch ~ rmoveto } put } if ~ - SDict /driver.leftboundary ~ known - { driver.outerbox ~ 0 ~ driver.leftboundary ~ put } - if ~ - SDict /driver.rightboundary ~ known - { driver.outerbox ~ 2 ~ driver.rightboundary ~ put } - if ~ - SDict /driver.bordertracking ~ false ~ put - } - def - /driver.bordertracking.endpage - { - driver.bordertracking - { - driver.bordertracking.end ~ - true ~ setglobal ~ - driver.globaldict - /driver.brokenlink.rect [ driver.outerbox ~ aload ~ pop ] put ~ - driver.globaldict - /driver.brokenlink.skip ~ driver.baselineskip ~ put ~ - driver.globaldict - /driver.brokenlink.dict ~ - driver.link.dict ~ driver.cvs ~ put ~ - false ~ setglobal ~ - mark ~ driver.link.dict ~ cvx ~ exec ~ /Rect - [ - driver.llx ~ - driver.lly ~ - driver.outerbox ~ 2 ~ get ~ driver.linkmargin ~ add ~ - currentpoint ~ exch ~ pop ~ - driver.outerbox ~ driver.rect.ht ~ sub ~ driver.linkmargin ~ sub - ] - /ANN ~ driver.pdfmark - } - if - } - def - /driver.bordertracking.continue - { - /driver.link.dict ~ driver.globaldict - /driver.brokenlink.dict ~ get ~ def - /driver.outerbox ~ driver.globaldict - /driver.brokenlink.rect ~ get ~ def - /driver.baselineskip ~ driver.globaldict - /driver.brokenlink.skip ~ get ~ def ~ - driver.globaldict ~ dup ~ dup - /driver.brokenlink.dict ~ undef - /driver.brokenlink.skip ~ undef - /driver.brokenlink.rect ~ undef ~ - currentpoint - /driver.originy ~ exch ~ def - /driver.originx ~ exch ~ def - /a ~ where - { - /a - { - moveto ~ - SDict ~ - begin ~ - currentpoint ~ driver.originy ~ ne ~ exch ~ - driver.originx ~ ne ~ or - { - driver.save.linkll - /driver.lly ~ - driver.lly ~ driver.outerbox ~ 1 ~ get ~ sub ~ def ~ - driver.bordertracking.begin - } - if ~ - end - } - put - } - if - /x ~ where - { - /x - { - 0 ~ exch ~ rmoveto ~ - SDict~ - begin ~ - currentpoint ~ - driver.originy ~ ne ~ exch ~ driver.originx ~ ne ~ or - { - driver.save.linkll - /driver.lly ~ - driver.lly ~ driver.outerbox ~ 1 ~ get ~ sub ~ def ~ - driver.bordertracking.begin - } - if ~ - end - } - put - } - if - } - def - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro} -% { -% driver.breaklink , -% driver.breaklink.write , -% driver.count , -% driver.currentrect -% } -% Dealing with link breaking itself has multiple stage. The first step is to -% find the |Rect| entry in the dictionary, looping over key--value pairs. -% The first line is handled first, adjusting the rectangle to stay inside the -% text area. The second phase is a loop over the height of the bulk of the -% link area, done on the basis of a number of baselines. Finally, the end of -% the link area is tidied up, again from the boundary of the text area. -% \begin{macrocode} -\@@_postscript_header:n - { - /driver.breaklink - { - pop ~ - counttomark ~ 2 ~ mod ~ 0 ~ eq - { - counttomark /driver.count ~ exch ~ def - { - driver.count ~ 0 ~ eq { exit } if ~ - counttomark ~ 2 ~ roll ~ - 1 ~ index ~ /Rect ~ eq - { - dup ~ 4 ~ array ~ copy ~ - dup ~ dup ~ - 1 ~ get ~ - driver.outerbox ~ driver.rect.ht ~ - driver.linkmargin ~ 2 ~ mul ~ add ~ sub ~ - 3 ~ exch ~ put ~ - dup ~ - driver.outerbox ~ 2 ~ get ~ - driver.linkmargin ~ add ~ - 2 ~ exch ~ put ~ - dup ~ dup ~ - 3 ~ get ~ - driver.outerbox ~ driver.rect.ht ~ - driver.linkmargin ~ 2 ~ mul ~ add ~ add ~ - 1 ~ exch ~ put - /driver.currentrect ~ exch ~ def ~ - driver.breaklink.write - { - driver.currentrect ~ - dup ~ - driver.outerbox ~ 0 ~ get ~ - driver.linkmargin ~ sub ~ - 0 ~ exch ~ put ~ - dup ~ - driver.outerbox ~ 2 ~ get ~ - driver.linkmargin ~ add ~ - 2 ~ exch ~ put ~ - dup ~ dup ~ - 1 ~ get ~ - driver.baselineskip ~ add ~ - 1 ~ exch ~ put ~ - dup ~ dup ~ - 3 ~ get ~ - driver.baselineskip ~ add ~ - 3 ~ exch ~ put ~ - /driver.currentrect ~ exch ~ def ~ - driver.breaklink.write - } - 1 ~ index ~ 3 ~ get ~ - driver.linkmargin ~ 2 ~ mul ~ add ~ - driver.outerbox ~ driver.rect.ht ~ add ~ - 2 ~ index ~ 1 ~ get ~ sub ~ - driver.baselineskip ~ div ~ round ~ cvi ~ 1 ~ sub ~ - exch ~ - repeat ~ - driver.currentrect ~ - dup ~ - driver.outerbox ~ 0 ~ get ~ - driver.linkmargin ~ sub ~ - 0 ~ exch ~ put ~ - dup ~ dup ~ - 1 ~ get ~ - driver.baselineskip ~ add ~ - 1 ~ exch ~ put ~ - dup ~ dup ~ - 3 ~ get ~ - driver.baselineskip ~ add ~ - 3 ~ exch ~ put ~ - dup ~ 2 ~ index ~ 2 ~ get ~ 2 ~ exch ~ put - /driver.currentrect ~ exch ~ def ~ - driver.breaklink.write ~ - SDict /driver.pdfmark.good ~ false ~ put ~ - exit - } - { driver.count ~ 2 ~ sub /driver.count ~ exch ~ def } - ifelse - } - loop - } - if - /ANN - } - def - /driver.breaklink.write - { - counttomark ~ 1 ~ sub ~ - index /_objdef ~ eq - { - counttomark ~ -2 ~ roll ~ - dup ~ wcheck ~ - { - readonly ~ - counttomark ~ 2 ~ roll - } - { pop ~ pop } - ifelse - } - if ~ - counttomark ~ 1 ~ add ~ copy ~ - pop ~ driver.currentrect - /ANN ~ pdfmark - } - def - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro} -% { -% driver.pdfmark , -% driver.pdfmark.good , -% driver.outerbox , -% driver.baselineskip , -% driver.pdfmark.dict -% } -% The business end of breaking links starts by hooking into |pdfmarks|. -% Unlike \pkg{hypdvips}, we avoid altering any links we have not created -% by using a copy of the core |pdfmarks| function. Only mark types which -% are known are altered. At present, this is purely |ANN| marks, which are -% measured relative to the size of the baseline skip. If they are -% more than one apparent line high, breaking is applied. -% \begin{macrocode} -\@@_postscript_header:n - { - /driver.pdfmark - { - SDict /driver.pdfmark.good ~ true ~ put ~ - dup /ANN ~ eq - { - driver.pdfmark.store ~ - driver.pdfmark.dict ~ - begin ~ - Subtype /Link ~ eq ~ - currentdict /Rect ~ known ~ and ~ - SDict /driver.outerbox ~ known ~ and ~ - SDict /driver.baselineskip ~ known ~ and ~ - { - Rect ~ 3 ~ get ~ - driver.linkmargin ~ 2 ~ mul ~ add ~ - driver.outerbox ~ driver.rect.ht ~ add ~ - Rect ~ 1 ~ get ~ sub ~ - driver.baselineskip ~ div ~ round ~ cvi ~ 0 ~ gt - { driver.breaklink } - if - } - if ~ - end ~ - SDict /driver.outerbox ~ undef ~ - SDict /driver.baselineskip ~ undef ~ - currentdict /driver.pdfmark.dict ~ undef ~ - } - if ~ - driver.pdfmark.good - { pdfmark } - { cleartomark } - ifelse - } - def - /driver.pdfmark.store - { - /driver.pdfmark.dict ~ 65534 ~ dict ~ def ~ - counttomark ~ 1 ~ add ~ copy ~ - pop - { - dup ~ mark ~ eq - { - pop ~ - exit - } - { - driver.pdfmark.dict ~ - begin ~ def ~ end - } - ifelse - } - loop - } - def - } -% \end{macrocode} -% \end{macro} -% -% \begin{variable}{\l_@@_pdf_content_box} -% The content of an annotation. -% \begin{macrocode} -\box_new:N \l_@@_pdf_content_box -% \end{macrocode} -% \end{variable} -% -% \begin{variable}{\l_@@_pdf_model_box} -% For creating model sizing for links. -% \begin{macrocode} -\box_new:N \l_@@_pdf_model_box -% \end{macrocode} -% \end{variable} -% -% \begin{variable}{\g_@@_pdf_annotation_int} -% Needed as objects which are not annotations could be created. -% \begin{macrocode} -\int_new:N \g_@@_pdf_annotation_int -% \end{macrocode} -% \end{variable} -% -% \begin{macro}{\driver_pdf_annotation:nnnn, \@@_pdf_annotation:nnnn} -% \begin{macro}{driver.llx, driver.lly, driver.urx, driver.ury} -% Annotations are objects, but we track them separately. Notably, they are -% not in the object data lists. Here, to get the co-ordinates of the -% annotation, we need to have the data collected at the PostScript level. -% That requires a bit of box trickery (effectively a \LaTeXe{} |picture| -% of zero size). Once the data is collected, use it to set up the annotation -% border. There is a split into two parts here to allow an easy way of -% applying the Adobe Reader fix. -% \begin{macrocode} -\cs_new_protected:Npn \driver_pdf_annotation:nnnn #1#2#3#4 - { - \@@_pdf_annotation:nnnn {#1} {#2} {#3} {#4} - \int_gincr:N \g_@@_pdf_object_int - \int_gset_eq:NN \g_@@_pdf_annotation_int \g_@@_pdf_object_int - \@@_pdfmark:x - { - - /_objdef { driver.obj \int_use:N \g_@@_pdf_object_int } - driver.rect ~ - #4 ~ - /ANN - } - } -\cs_new_protected:Npn \@@_pdf_annotation:nnnn #1#2#3#4 - { - \box_move_down:nn {#3} - { \hbox:n { \@@_postscript:n { driver.save.ll } } } - \hbox:n {#4} - \box_move_up:nn {#2} - { - \hbox:n - { - \tex_kern:D \dim_eval:n {#1} \scan_stop: - \@@_postscript:n { driver.save.ur } - } - } - \int_gincr:N \g_@@_pdf_object_int - \int_gset_eq:NN \g_@@_pdf_annotation_int \g_@@_pdf_object_int - \@@_pdfmark:x - { - /_objdef { driver.obj \int_use:N \g_@@_pdf_object_int } - driver.rect - /ANN - } - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}[EXP]{\driver_pdf_annotation_last:} -% Provide the last annotation we created: could get tricky of course if -% other packages are loaded. -% \begin{macrocode} -\cs_new:Npn \driver_pdf_annotation_last: - { { driver.obj \int_use:N \g_@@_pdf_annotation_int } } -% \end{macrocode} -% \end{macro} -% -% \begin{variable}{\g_@@_pdf_link_int} -% To track annotations which are links. -% \begin{macrocode} -\int_new:N \g_@@_pdf_link_int -% \end{macrocode} -% \end{variable} -% -% \begin{variable}{\g_@@_pdf_link_dict_tl} -% To pass information to the end-of-link function. -% \begin{macrocode} -\tl_new:N \g_@@_pdf_link_dict_tl -% \end{macrocode} -% \end{variable} -% -% \begin{variable}{\g_@@_pdf_link_sf_int} -% Needed to save/restore space factor, which is needed to deal with the face -% we need a box. -% \begin{macrocode} -\int_new:N \g_@@_pdf_link_sf_int -% \end{macrocode} -% \end{variable} -% -% \begin{variable}{\g_@@_pdf_link_math_bool} -% Needed to save/restore math mode. -% \begin{macrocode} -\bool_new:N \g_@@_pdf_link_math_bool -% \end{macrocode} -% \end{variable} -% -% \begin{variable}{\g_@@_pdf_link_bool} -% Track link formation: we cannot nest at all. -% \begin{macrocode} -\bool_new:N \g_@@_pdf_link_bool -% \end{macrocode} -% \end{variable} -% -% \begin{variable}{\l_@@_breaklink_pdfmark_tl} -% Swappable content for link breaking. -% \begin{macrocode} -\tl_new:N \l_@@_breaklink_pdfmark_tl -\tl_set:Nn \l_@@_breaklink_pdfmark_tl { pdfmark } -% \end{macrocode} -% \end{variable} -% -% \begin{macro}{\@@_breaklink_postscript:n} -% To allow dropping material unless link breaking is active. -% \begin{macrocode} -\cs_new_protected:Npn \@@_breaklink_postscript:n #1 { } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\@@_breaklink_usebox:N} -% Swappable box unpacking or use. -% \begin{macrocode} -\cs_new_eq:NN \@@_breaklink_usebox:N \box_use:N -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\driver_pdf_link_begin_goto:nnw, \driver_pdf_link_begin_user:nnw} -% \begin{macro}{\@@_pdf_link:nw, \@@_pdf_link_aux:nw} -% \begin{macro}{\driver_pdf_link_end:, \@@_pdf_link_end:} -% \begin{macro}{\@@_pdf_link_minima:} -% \begin{macro}{\@@_pdf_link_outerbox:n} -% \begin{macro}{\@@_pdf_link_sf_save:, \@@_pdf_link_sf_restore:} -% \begin{macro} -% { -% driver.linkdp.pad , -% driver.linkht.pad , -% driver.llx, driver.lly , -% driver.ury, driver.ury , -% driver.link.dict , -% driver.outerbox , -% driver.baselineskip -% } -% Links are crated like annotations but with dedicated code to allow for -% adjusting the size of the rectangle. In contrast to \pkg{hyperref}, we -% grab the link content as a box which can then unbox: this allows the same -% interface as for \pdfTeX{}. -% -% Taking the idea of |evenboxes| from \pkg{hypdvips}, we implement a minimum -% box height and depth for link placement. This means that \enquote{underlining} -% with a hyperlink will generally give an even appearance. However, to ensure -% that the full content is always above the link border, we do not allow -% this to be negative (contrast \pkg{hypdvips} approach). The result should -% be similar to \pdfTeX{} in the vast majority of foreseeable cases. -% -% The object number for a link is saved separately from the rest of the -% dictionary as this allows us to insert it just once, at either an -% unbroken link or only in the first line of a broken one. That makes the -% code clearer but also avoids a low-level PostScript error with the code -% as taken from \pkg{hypdvips}. -% -% Getting the outer dimensions of the text area may be better using a two-pass -% approach and |\tex_savepos:D|. That plus format mode are still to re-examine. -% \begin{macrocode} -\cs_new_protected:Npn \driver_pdf_link_begin_goto:nnw #1#2 - { \@@_pdf_link_begin:nw { #1 /Subtype /Link /A << /S /GoTo /D ( #2 ) >> } } -\cs_new_protected:Npn \driver_pdf_link_begin_user:nnw #1#2 - { \@@_pdf_link_begin:nw {#1#2} } -\cs_new_protected:Npn \@@_pdf_link_begin:nw #1 - { - \bool_if:NF \g_@@_pdf_link_bool - { \@@_pdf_link_begin_aux:nw {#1} } - } -\cs_new_protected:Npn \@@_pdf_link_begin_aux:nw #1 - { - \bool_gset_true:N \g_@@_pdf_link_bool - \@@_postscript:n - { /driver.link.dict ( #1 ) def } - \tl_gset:Nn \g_@@_pdf_link_dict_tl {#1} - \@@_pdf_link_sf_save: - \mode_if_math:TF - { \bool_gset_true:N \g_@@_pdf_link_math_bool } - { \bool_gset_false:N \g_@@_pdf_link_math_bool } - \hbox_set:Nw \l_@@_pdf_content_box - \@@_pdf_link_sf_restore: - \bool_if:NT \g_@@_pdf_link_math_bool - { \c_math_toggle_token } - } -\cs_new_protected:Npn \driver_pdf_link_end: - { - \bool_if:NT \g_@@_pdf_link_bool - { \@@_pdf_link_end: } - } -\cs_new_protected:Npn \@@_pdf_link_end: - { - \bool_if:NT \g_@@_pdf_link_math_bool - { \c_math_toggle_token } - \@@_pdf_link_sf_save: - \hbox_set_end: - \@@_pdf_link_minima: - \hbox_set:Nn \l_@@_pdf_model_box { Gg } - \exp_args:Nx \@@_driver_link_outerbox:n - { -%<*initex> - \l_galley_total_left_margin_dim -% -%<*package> - \int_if_odd:nTF { \value { page } } - { \oddsidemargin } - { \evensidemargin } -% - } - \box_move_down:nn { \box_dp:N \l_@@_pdf_content_box } - { \hbox:n { \@@_postscript:n { driver.save.linkll } } } - \@@_breaklink_postscript:n { driver.bordertracking.begin } - \@@_breaklink_usebox:N \l_@@_pdf_content_box - \@@_breaklink_postscript:n { driver.bordertracking.end } - \box_move_up:nn { \box_ht:N \l_@@_pdf_content_box } - { - \hbox:n - { \@@_postscript:n { driver.save.linkur } } - } - \int_gincr:N \g_@@_pdf_object_int - \int_gset_eq:NN \g_@@_pdf_link_int \g_@@_pdf_object_int - \@@_postscript:x - { - mark - /_objdef { driver.obj \int_use:N \g_@@_pdf_link_int } - \g_@@_pdf_link_dict_tl \c_space_tl - driver.rect - /ANN ~ \l_@@_breaklink_pdfmark_tl - } - \@@_pdf_link_sf_restore: - \bool_gset_false:N \g_@@_pdf_link_bool - } -\cs_new_protected:Npn \@@_pdf_link_minima: - { - \hbox_set:Nn \l_@@_pdf_model_box { Gg } - \@@_postscript:x - { - /driver.linkdp.pad ~ - \dim_to_decimal:n - { - \dim_max:nn - { - \box_dp:N \l_@@_pdf_model_box - - \box_dp:N \l_@@_pdf_content_box - } - { 0pt } - } ~ - driver.pt.dvi ~ def - /driver.linkht.pad ~ - \dim_to_decimal:n - { - \dim_max:nn - { - \box_ht:N \l_@@_pdf_model_box - - \box_ht:N \l_@@_pdf_content_box - } - { 0pt } - } ~ - driver.pt.dvi ~ def - } - } -\cs_new_protected:Npn \@@_driver_link_outerbox:n #1 - { - \@@_postscript:x - { - /driver.outerbox - [ - \dim_to_decimal:n {#1} ~ - \dim_to_decimal:n { -\box_dp:N \l_@@_pdf_model_box } ~ -%<*initex> - \dim_to_decimal:n { #1 + \l_galley_text_width_dim } ~ -% -%<*package> - \dim_to_decimal:n { #1 + \textwidth } ~ -% - \dim_to_decimal:n { \box_ht:N \l_@@_pdf_model_box } - ] - [ exch { driver.pt.dvi } forall ] def - /driver.baselineskip ~ - \dim_to_decimal:n { \tex_baselineskip:D } ~ dup ~ 0 ~ gt - { driver.pt.dvi ~ def } - { pop ~ pop } - ifelse - } - } -\cs_new_protected:Npn \@@_pdf_link_sf_save: - { - \int_gset:Nn \g_@@_pdf_link_sf_int - { - \mode_if_horizontal:TF - { \tex_spacefactor:D } - { 0 } - } - } -\cs_new_protected:Npn \@@_pdf_link_sf_restore: - { - \mode_if_horizontal:T - { - \int_compare:nNnT \g_@@_pdf_link_sf_int > { 0 } - { \int_set_eq:NN \tex_spacefactor:D \g_@@_pdf_link_sf_int } - } - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\@makecol@hook} -% Hooks to allow link breaking: something will be needed in format mode -% at some stage. At present this code is disabled as there is an open -% question about the name of the hook: to be resolved at the \LaTeXe{} -% end. -% \begin{macrocode} -%<*package> -\use_none:n - { - \cs_if_exist:NT \@makecol@hook - { - \tl_put_right:Nn \@makecol@hook - { - \box_if_empty:NF \@cclv - { - \vbox_set:Nn \@cclv - { - \@@_postscript:n - { - driver.globaldict /driver.brokenlink.rect ~ known - { driver.bordertracking.continue } - if - } - \vbox_unpack_drop:N \@cclv - \@@_postscript:n - { driver.bordertracking.endpage } - } - } - } - \tl_set:Nn \l_@@_breaklink_pdfmark_tl { driver.pdfmark } - \cs_set_eq:NN \@@_breaklink_postscript:n \@@_postscript:n - \cs_set_eq:NN \@@_breaklink_usebox:N \hbox_unpack:N - } - } -% -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\driver_pdf_link_last:} -% The same as annotations, but with a custom integer. -% \begin{macrocode} -\cs_new:Npn \driver_pdf_link_last: - { { driver.obj \int_use:N \g_@@_pdf_link_int } } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\driver_pdf_link_margin:n} -% Convert to big points and pass to PostScript. -% \begin{macrocode} -\cs_new_protected:Npn \driver_pdf_link_margin:n #1 - { - \@@_postscript:x - { - /driver.linkmargin { \dim_to_decimal:n {#1} ~ driver.pt.dvi } def - } - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\driver_pdf_destination:nn, \driver_pdf_destination_rectangle:nn} -% Here, we need to turn the zoom into a scale. We also need to know where -% the current anchor point actually is: worked out in PostScript. For the -% rectangle version, we have a bit more PostScript: we need two points. -% \begin{macrocode} -\cs_new_protected:Npn \driver_pdf_destination:nn #1#2 - { - \@@_postscript:n { driver.dest.anchor } - \@@_pdfmark:x - { - /View - [ - \str_case:nnF {#2} - { - { xyz } { /XYZ ~ driver.dest.point ~ null } - { fit } { /Fit } - { fitb } { /FitB } - { fitbh } { /FitBH ~ driver.dest.y } - { fitbv } { /FitBV ~ driver.dest.x } - { fith } { /FitH ~ driver.dest.y } - { fitv } { /FitV ~ driver.dest.x } - } - { - /XYZ ~ driver.dest.point ~ \fp_eval:n { (#2) / 100 } - } - ] - /Dest ( \exp_not:n {#1} ) cvn - /DEST - } - } -\cs_new_protected:Npn \driver_pdf_destination_rectangle:nn #1#2 - { - \group_begin: - \hbox_set:Nn \l_@@_internal_box {#2} - \box_move_down:nn - { \box_dp:N \l_@@_internal_box } - { \hbox:n { \@@_postscript:n { driver.save.ll } } } - \box_use:N \l_@@_internal_box - \box_move_up:nn - { \box_ht:N \l_@@_internal_box } - { \hbox:n { \@@_postscript:n { driver.save.ur } } } - \@@_pdfmark:n - { - /View - [ - /FitR ~ - driver.llx ~ driver.lly ~ driver.dest2device ~ - driver.urx ~ driver.ury ~ driver.dest2device - ] - /Dest ( #1 ) cvn - /DEST - } - \group_end: - } -% \end{macrocode} -% \end{macro} -% -% \subsubsection{Structure} -% -% \begin{macro}{\driver_pdf_compresslevel:n} -% \begin{macro}{\driver_pdf_compress_objects:n} -% These are all no-ops. -% \begin{macrocode} -\cs_new_protected:Npn \driver_pdf_compresslevel:n #1 { } -\cs_new_protected:Npn \driver_pdf_compress_objects:n #1 { } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro} -% {\driver_pdf_version_major_gset:n, \driver_pdf_version_minor_gset:n} -% Data not available! -% \begin{macrocode} -\cs_new_protected:Npn \driver_pdf_version_major_gset:n #1 { } -\cs_new_protected:Npn \driver_pdf_version_minor_gset:n #1 { } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[EXP]{\driver_pdf_version_major:, \driver_pdf_version_minor:} -% Data not available! -% \begin{macrocode} -\cs_new:Npn \driver_pdf_version_major: { -1 } -\cs_new:Npn \driver_pdf_version_minor: { -1 } -% \end{macrocode} -% \end{macro} -% -% \begin{macrocode} -% -% \end{macrocode} -% -% \subsection{\texttt{pdfmode} driver} -% -% \begin{macrocode} -%<*pdfmode> -% \end{macrocode} -% -% \subsubsection{Annotations} -% -% \begin{macro}{\driver_pdf_annotation:nnnn} -% Simply pass the raw data through, just dealing with evaluation of dimensions. -% \begin{macrocode} -\cs_new_protected:Npx \driver_pdf_annotation:nnnn #1#2#3#4 - { - \cs_if_exist:NTF \tex_pdfextension:D - { \tex_pdfextension:D annot ~ } - { \tex_pdfannot:D } - width ~ \exp_not:N \dim_eval:n {#1} ~ - height ~ \exp_not:N \dim_eval:n {#2} ~ - depth ~ \exp_not:N \dim_eval:n {#3} ~ - {#4} - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[EXP]{\driver_pdf_annotation_last:} -% A tiny amount of extra data gets added here. -% \begin{macrocode} -\cs_new:Npx \driver_pdf_annotation_last: - { - \exp_not:N \tex_the:D - \cs_if_exist:NTF \tex_pdffeedback:D - { \exp_not:N \tex_pdffeedback:D annot ~ } - { \exp_not:N \tex_pdflastannot:D } - 0 ~ R - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro} -% {\driver_pdf_link_begin_goto:nnw, \driver_pdf_link_begin_user:nnw} -% \begin{macro}{\@@_pdf_link_begin:nnnw} -% \begin{macro}{\driver_pdf_link_end:} -% Links are all created using the same internals. -% \begin{macrocode} -\cs_new_protected:Npn \driver_pdf_link_begin_goto:nnw #1#2 - { \@@_pdf_link_begin:nnnw {#1} { goto~name } {#2} } -\cs_new_protected:Npn \driver_pdf_link_begin_user:nnw #1#2 - { \@@_pdf_link_begin:nnnw {#1} { user } {#2} } -\cs_new_protected:Npx \@@_pdf_link_begin:nnnw #1#2#3 - { - \cs_if_exist:NTF \tex_pdfextension:D - { \tex_pdfextension:D startlink ~ } - { \tex_pdfstartlink:D } - attr {#1} - #2 {#3} - } -\cs_new_protected:Npx \driver_pdf_link_end: - { - \cs_if_exist:NTF \tex_pdfextension:D - { \tex_pdfextension:D endlink \scan_stop: } - { \tex_pdfendlink:D } - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\driver_pdf_link_last:} -% Formatted for direct use. -% \begin{macrocode} -\cs_new:Npx \driver_pdf_link_last: - { - \exp_not:N \tex_the:D - \cs_if_exist:NTF \tex_pdffeedback:D - { \exp_not:N \tex_pdffeedback:D lastlink \scan_stop: } - { \exp_not:N \tex_pdflastlink:D } - ~ 0 ~ R - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\driver_pdf_link_margin:n} -% A simple task: pass the data to the primitive. -% \begin{macrocode} -\cs_new_protected:Npx \driver_pdf_link_margin:n #1 - { - \cs_if_exist:NTF \tex_pdfvariable:D - { \exp_not:N \tex_pdfvariable:D linkmargin } - { \exp_not:N \tex_pdflinkmargin:D } - \exp_not:N \dim_eval:n {#1} \scan_stop: - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\driver_pdf_destination:nn, \driver_pdf_destination_rectangle:nn} -% A simple task: pass the data to the primitive. The |\scan_stop:| deals -% with the danger of an unterminated keyword. The zoom given here is a -% percentage, but we need to pass it as \emph{per mille}. The rectangle -% version is also easy as everything is build in. -% \begin{macrocode} -\cs_new_protected:Npx \driver_pdf_destination:nn #1#2 - { - \cs_if_exist:NTF \tex_pdfextension:D - { \exp_not:N \tex_pdfextension:D dest ~ } - { \exp_not:N \tex_pdfdest:D } - name {#1} - \exp_not:N \str_case:nnF {#2} - { - { xyz } { xyz } - { fit } { fit } - { fitb } { fitb } - { fitbh } { fitbh } - { fitbv } { fitbv } - { fith } { fith } - { fitv } { fitv } - } - { xyz ~ zoom \exp_not:N \fp_eval:n { #2 * 10 } } - \scan_stop: - } -\cs_new_protected:Npx \driver_pdf_destination_rectangle:nn #1#2 - { - \group_begin: - \hbox_set:Nn \l_@@_internal_box {#2} - \cs_if_exist:NTF \tex_pdfextension:D - { \exp_not:N \tex_pdfextension:D dest ~ } - { \exp_not:N \tex_pdfdest:D } - name {#1} - fitr ~ - width \exp_not:N \box_wd:N \l_@@_internal_box - height \exp_not:N \box_ht:N \l_@@_internal_box - depth \exp_not:N \box_dp:N \l_@@_internal_box - \box_use:N \l_@@_internal_box - \group_end: - } -% \end{macrocode} -% \end{macro} -% -% \subsubsection{Catalogue entries} -% -% \begin{macro}{\driver_pdf_catalog_gput:nn, \driver_pdf_info_gput:nn} -% \begin{macrocode} -\cs_new_protected:Npx \driver_pdf_catalog_gput:nn #1#2 - { - \cs_if_exist:NTF \tex_pdfextension:D - { \tex_pdfextension:D catalog } - { \tex_pdfcatalog:D } - { / #1 ~ #2 } - } -\cs_new_protected:Npx \driver_pdf_info_gput:nn #1#2 - { - \cs_if_exist:NTF \tex_pdfextension:D - { \tex_pdfextension:D info } - { \tex_pdfinfo:D } - { / #1 ~ #2 } - } -% \end{macrocode} -% \end{macro} -% -% \subsubsection{Objects} -% -% \begin{variable}{\g_@@_pdf_object_prop} -% For tracking objects to allow finalisation. -% \begin{macrocode} -\prop_new:N \g_@@_pdf_object_prop -% \end{macrocode} -% \end{variable} -% -% \begin{macro}{\driver_pdf_object_new:nn} -% \begin{macro}[EXP]{\driver_pdf_object_ref:n} -% Declaring objects means reserving at the PDF level plus starting -% tracking. -% \begin{macrocode} -\group_begin: - \cs_set_protected:Npn \@@_tmp:w #1#2 - { - \cs_new_protected:Npx \driver_pdf_object_new:nn ##1##2 - { - #1 reserveobjnum ~ - \int_const:cn - { c_@@_pdf_object_ \exp_not:N \tl_to_str:n {##1} _int } - {#2} - \prop_gput:Nnn \exp_not:N \g_@@_pdf_object_prop {##1} {##2} - } - } - \cs_if_exist:NTF \tex_pdfextension:D - { - \@@_tmp:w - { \tex_pdfextension:D obj ~ } - { \exp_not:N \tex_pdffeedback:D lastobj } - } - { \@@_tmp:w { \tex_pdfobj:D } { \tex_pdflastobj:D } } -\group_end: -\cs_new:Npn \driver_pdf_object_ref:n #1 - { \int_use:c { c_@@_pdf_object_ \tl_to_str:n {#1} _int } ~ 0 ~ R } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\driver_pdf_object_write:nn} -% \begin{macro}[EXP]{\@@_exp_not_i:nn, \@@_exp_not_ii:nn} -% Writing the data needs a little information about the structure of the -% object. -% \begin{macrocode} -\group_begin: - \cs_set_protected:Npn \@@_tmp:w #1 - { - \cs_new_protected:Npn \driver_pdf_object_write:nn ##1##2 - { - \tex_immediate:D #1 useobjnum ~ - \int_use:c - { c_@@_pdf_object_ \tl_to_str:n {##1} _int } - \str_case_e:nn - { \prop_item:Nn \g_@@_pdf_object_prop {##1} } - { - { array } { { [ ~ \exp_not:n {##2} ~ ] } } - { dict } { { << ~ \exp_not:n {##2} ~ >> } } - { fstream } - { - stream ~ attr ~ { \@@_exp_not_i:nn ##2 } ~ - file ~ { \@@_exp_not_ii:nn ##2 } - } - { stream } - { - stream ~ attr ~ { \@@_exp_not_i:nn ##2 } ~ - { \@@_exp_not_ii:nn ##2 } - } - } - } - } - \cs_if_exist:NTF \tex_pdfextension:D - { \@@_tmp:w { \tex_pdfextension:D obj ~ } } - { \@@_tmp:w { \tex_pdfobj:D } } -\group_end: -\cs_new:Npn \@@_exp_not_i:nn #1#2 { \exp_not:n {#1} } -\cs_new:Npn \@@_exp_not_ii:nn #1#2 { \exp_not:n {#2} } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \subsubsection{Structure} -% -% \begin{macro}{\driver_pdf_compresslevel:n} -% \begin{macro}{\driver_pdf_compress_objects:n} -% \begin{macro}{\@@_pdf_objcompresslevel:n} -% Simply pass data to the engine. -% \begin{macrocode} -\cs_new_protected:Npx \driver_pdf_compresslevel:n #1 - { - \exp_not:N \tex_global:D - \cs_if_exist:NTF \tex_pdfcompresslevel:D - { \tex_pdfcompresslevel:D } - { \tex_pdfvariable:D compresslevel } - \exp_not:N \int_value:w \exp_not:N \int_eval:n {#1} \scan_stop: - } -\cs_new_protected:Npn \driver_pdf_compress_objects:n #1 - { - \str_if_eq:nnTF {#1} { true } - { \@@_pdf_objcompresslevel:n { 2 } } - { \@@_pdf_objcompresslevel:n { 0 } } - } -\cs_new_protected:Npx \@@_pdf_objcompresslevel:n #1 - { - \exp_not:N \tex_global:D - \cs_if_exist:NTF \tex_pdfobjcompresslevel:D - { \tex_pdfobjcompresslevel:D } - { \tex_pdfvariable:D objcompresslevel } - #1 \scan_stop: - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro} -% {\driver_pdf_version_major_gset:n, \driver_pdf_version_minor_gset:n} -% At present, we don't have a primitive for the major version in \pdfTeX{}, -% but we anticipate one \ldots -% \begin{macrocode} -\cs_new_protected:Npx \driver_pdf_version_major_gset:n #1 - { - \cs_if_exist:NTF \tex_pdfvariable:D - { - \int_compare:nNnT \tex_luatexversion:D > { 106 } - { - \exp_not:N \tex_global:D \tex_pdfvariable:D majorversion - \exp_not:N \int_eval:n {#1} \scan_stop: - } - } - { - \cs_if_exist:NT \tex_pdfmajorversion:D - { - \exp_not:N \tex_global:D \tex_pdfmajorversion:D - \exp_not:N \int_eval:n {#1} \scan_stop: - } - } - } -\cs_new_protected:Npx \driver_pdf_version_minor_gset:n #1 - { - \exp_not:N \tex_global:D - \cs_if_exist:NTF \tex_pdfminorversion:D - { \exp_not:N \tex_pdfminorversion:D } - { \tex_pdfvariable:D minorversion } - \exp_not:N \int_eval:n {#1} \scan_stop: - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[EXP]{\driver_pdf_version_major:, \driver_pdf_version_minor:} -% At present, we don't have a primitive for the major version! -% \begin{macrocode} -\cs_new:Npx \driver_pdf_version_major: - { - \cs_if_exist:NTF \tex_pdfvariable:D - { - \int_compare:nNnTF \tex_luatexversion:D > { 106 } - { \exp_not:N \tex_the:D \tex_pdfvariable:D majorversion } - { 1 } - } - { - \cs_if_exist:NTF \tex_pdfmajorversion:D - { \exp_not:N \tex_the:D \tex_pdfmajorversion:D } - { 1 } - } - } -\cs_new:Npx \driver_pdf_version_minor: - { - \exp_not:N \tex_the:D - \cs_if_exist:NTF \tex_pdfminorversion:D - { \exp_not:N \tex_pdfminorversion:D } - { \tex_pdfvariable:D minorversion } - } -% \end{macrocode} -% \end{macro} -% -% \begin{macrocode} -% -% \end{macrocode} -% -% \subsection{\texttt{dvipdfmx} driver} -% -% \begin{macrocode} -%<*dvipdfmx|xdvipdfmx> -% \end{macrocode} -% -% \begin{macro}{\@@_pdf:n, \@@_pdf:x} -% A generic function for the driver PDF specials: used where we can. -% \begin{macrocode} -\cs_new_protected:Npx \@@_pdf:n #1 - { \@@_literal:n { pdf: #1 } } -\cs_generate_variant:Nn \@@_pdf:n { x } -% \end{macrocode} -% \end{macro} -% -% \subsubsection{Catalogue entries} -% -% \begin{macro}{\driver_pdf_catalog_gput:nn, \driver_pdf_info_gput:nn} -% \begin{macrocode} -\cs_new_protected:Npn \driver_pdf_catalog_gput:nn #1#2 - { \@@_pdf:n { put ~ @catalog << /#1 ~ #2 >> } } -\cs_new_protected:Npn \driver_pdf_info_gput:nn #1#2 - { \@@_pdf:n { docinfo << /#1 ~ #2 >> } } -% \end{macrocode} -% \end{macro} -% -% \subsubsection{Objects} -% -% \begin{variable}{\g_@@_pdf_object_int, \g_@@_pdf_object_prop} -% For tracking objects to allow finalisation. -% \begin{macrocode} -\int_new:N \g_@@_pdf_object_int -\prop_new:N \g_@@_pdf_object_prop -% \end{macrocode} -% \end{variable} -% -% \begin{macro}{\driver_pdf_object_new:nn} -% \begin{macro}[EXP]{\driver_pdf_object_ref:n} -% Objects are tracked at the macro level, but we don't have to do anything -% at this stage. -% \begin{macrocode} -\cs_new_protected:Npn \driver_pdf_object_new:nn #1#2 - { - \int_gincr:N \g_@@_pdf_object_int - \int_const:cn - { g_@@_pdf_object_ \tl_to_str:n {#1} _int } - { \g_@@_pdf_object_int } - \prop_gput:Nnn \g_@@_pdf_object_prop {#1} {#2} - } -\cs_new:Npn \driver_pdf_object_ref:n #1 - { @driver.obj \int_use:c { g_@@_pdf_object_ \tl_to_str:n {#1} _int } } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\driver_pdf_object_write:nn} -% \begin{macro}{\@@_pdf_object_write:nnn} -% \begin{macro} -% { -% \@@_pdf_object_write_array:nn , -% \@@_pdf_object_write_dict:nn , -% \@@_pdf_object_write_fstream:nn , -% \@@_pdf_object_write_stream:nn -% } -% \begin{macro}{\@@_pdf_object_write_stream:nnnn} -% This is where we choose the actual type. -% \begin{macrocode} -\cs_new_protected:Npn \driver_pdf_object_write:nn #1#2 - { - \exp_args:Nx \@@_pdf_object_write:nnn - { \prop_item:Nn \g_@@_pdf_object_prop {#1} } {#1} {#2} - } -\cs_new_protected:Npn \@@_pdf_object_write:nnn #1#2#3 - { \use:c { @@_pdf_object_write_ #1 :nn } {#2} {#3} } -\cs_new_protected:Npn \@@_pdf_object_write_array:nn #1#2 - { - \@@_pdf:x - { - obj ~ \driver_pdf_object_ref:n {#1} ~ - [ ~ \exp_not:n {#2} ~ ] - } - } -\cs_new_protected:Npn \@@_pdf_object_write_dict:nn #1#2 - { - \@@_pdf:x - { - obj ~ \driver_pdf_object_ref:n {#1} ~ - << ~ \exp_not:n {#2} ~ >> - } - } -\cs_new_protected:Npn \@@_pdf_object_write_fstream:nn #1#2 - { \@@_pdf_object_write_stream:nnnn { f } {#1} #2 } -\cs_new_protected:Npn \@@_pdf_object_write_stream:nn #1#2 - { \@@_pdf_object_write_stream:nnnn { } {#1} #2 } -\cs_new_protected:Npn \@@_pdf_object_write_stream:nnnn #1#2#3#4 - { - \@@_pdf:x - { - #1 stream ~ \driver_pdf_object_ref:n {#2} ~ - ( \exp_not:n {#4} ) ~ << \exp_not:n {#3} >> - - } - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \subsubsection{Annotations} -% -% \begin{variable}{\g_@@_landscape_bool} -% There is a bug in \texttt{(x)dvipdfmx} which means annotations do -% not rotate. As such, we need to know if landscape is active. -% \begin{macrocode} -\bool_new:N \g_@@_landscape_bool -%<*package> -\AtBeginDocument - { - \cs_if_exist:NT \landscape - { - \tl_put_right:Nn \landscape - { \bool_gset_true:N \g_@@_landscape_bool } - \tl_put_left:Nn \endlandscape - { \bool_gset_false:N \g_@@_landscape_bool } - } - } -% -% \end{macrocode} -% \end{variable} -% -% \begin{variable}{\g_@@_pdf_annotation_int} -% Needed as objects which are not annotations could be created. -% \begin{macrocode} -\int_new:N \g_@@_pdf_annotation_int -% \end{macrocode} -% \end{variable} -% -% \begin{macro}{\driver_pdf_annotation:nnnn, \@@_pdf_annotation:nnnn} -% Simply pass the raw data through, just dealing with evaluation of dimensions. -% The only wrinkle is landscape: we have to adjust by hand. -% \begin{macrocode} -\cs_new_protected:Npn \driver_pdf_annotation:nnnn #1#2#3#4 - { - \bool_if:NTF \g_@@_landscape_bool - { - \box_move_up:nn {#2} - { - \vbox:n - { - \@@_pdf_annotation:nnnn - { #2 + #3 } {#1} { 0pt } {#4} - } - } - } - { \@@_pdf_annotation:nnnn {#1} {#2} {#3} {#4} } - } -\cs_new_protected:Npn \@@_pdf_annotation:nnnn #1#2#3#4 - { - \int_gincr:N \g_@@_pdf_object_int - \int_gset_eq:NN \g_@@_pdf_annotation_int \g_@@_pdf_object_int - \@@_pdf:x - { - ann ~ @driver.obj \int_use:N \g_@@_pdf_object_int \c_space_tl - width ~ \dim_eval:n {#1} ~ - height ~ \dim_eval:n {#2} ~ - depth ~ \dim_eval:n {#3} ~ - << #4 >> - } - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro} -% {\driver_pdf_link_begin_goto:nnw, \driver_pdf_link_begin_user:nnw} -% \begin{macro}{\@@_pdf_link_begin:n} -% \begin{macro}{\driver_pdf_link_end:} -% All created using the same internals. -% \begin{macrocode} -\cs_new_protected:Npn \driver_pdf_link_begin_goto:nnw #1#2 - { \@@_pdf_link_begin:n { #1 /Subtype /Link /A << /S /GoTo /D ( #2 ) >> } } -\cs_new_protected:Npn \driver_pdf_link_begin_user:nnw #1#2 - { \@@_pdf_link_begin:n {#1#2} } -\cs_new_protected:Npn \@@_pdf_link_begin:n #1 - { - \@@_pdf:n - { - bann - << - /Type /Annot - #1 - >> - } - } -\cs_new_protected:Npn \driver_pdf_link_end: - { \@@_pdf:n { eann } } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\driver_pdf_link_last:} -% Data not available. -% \begin{macrocode} -\cs_new:Npn \driver_pdf_link_last: { } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\driver_pdf_link_margin:n} -% Pass to \texttt{dvipdfmx}. -% \begin{macrocode} -\cs_new_protected:Npn \driver_pdf_link_margin:n #1 - { \@@_literal:x { dvipdfmx:config~g~ \dim_eval:n {#1} } } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\driver_pdf_destination:nn, \driver_pdf_destination_rectangle:nn} -% Here, we need to turn the zoom into a scale. The method for \texttt{FitR} -% is from Alexander Grahn: the idea is to avoid needing to do any calculations -% in \TeX{} by using the driver data for \texttt{@xpos} and \texttt{@ypos}. -% \begin{macrocode} -\cs_new_protected:Npn \driver_pdf_destination:nn #1#2 - { - \@@_pdf:x - { - dest ~ ( \exp_not:n {#1} ) - [ - @thispage - \str_case:nnF {#2} - { - { xyz } { /XYZ ~ @xpos ~ @ypos ~ null } - { fit } { /Fit } - { fitb } { /FitB } - { fitbh } { /FitBH } - { fitbv } { /FitBV ~ @xpos } - { fith } { /FitH ~ @ypos } - { fitv } { /FitV ~ @xpos } - } - { /XYZ ~ @xpos ~ @ypos ~ \fp_eval:n { (#2) / 100 } } - ] - } - } -\cs_new_protected:Npn \driver_pdf_destination_rectangle:nn #1#2 - { - \group_begin: - \hbox_set:Nn \l_@@_internal_box {#2} - \box_move_down:nn { \box_dp:N \l_@@_internal_box } - { - \hbox:n - { - \@@_pdf:n { obj ~ @driver_#1_llx ~ @xpos } - \@@_pdf:n { obj ~ @driver_#1_lly ~ @ypos } - } - } - \box_use:N \l_@@_internal_box - \box_move_up:nn { \box_ht:N \l_@@_internal_box } - { - \hbox:n - { - \@@_pdf:n - { - dest ~ (#1) - [ - @thispage - /FitR ~ - @driver_#1_llx ~ @driver_#1_lly ~ - @xpos ~ @ypos - ] - } - } - } - \group_end: - } -% \end{macrocode} -% \end{macro} -% -% \subsubsection{Structure} -% -% \begin{macro}{\driver_pdf_compresslevel:n} -% \begin{macro}{\driver_pdf_compress_objects:n} -% Pass data to the driver: these are a one-shot. -% \begin{macrocode} -\cs_new_protected:Npn \driver_pdf_compresslevel:n #1 - { \@@_literal:x { dvipdfmx:config~z~ \int_eval:n {#1} } } -\cs_new_protected:Npn \driver_pdf_compress_objects:n #1 - { - \str_if_eq:nnF {#1} { true } - { \@@_literal:n { dvipdfmx:config~C~0x40 } } - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro} -% {\driver_pdf_version_major_gset:n, \driver_pdf_version_minor_gset:n} -% We start with the assumption that the default is active. -% \begin{macrocode} -\cs_new_protected:Npn \driver_pdf_version_major:n #1 - { - \cs_gset:Npx \driver_pdf_version_major: { \int_eval:n {#1} } - \@@_literal:x { pdf:majorversion \driver_pdf_version_major: } - } -\cs_new_protected:Npn \driver_pdf_version_minor:n #1 - { - \cs_gset:Npx \driver_pdf_version_minor: { \int_eval:n {#1} } - \@@_literal:x { pdf:minorversion \driver_pdf_version_minor: } - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[EXP]{\driver_pdf_version_major:, \driver_pdf_version_minor:} -% We start with the assumption that the default is active. -% \begin{macrocode} -\cs_new:Npn \driver_pdf_version_major: { 1 } -\cs_new:Npn \driver_pdf_version_minor: { 5 } -% \end{macrocode} -% \end{macro} -% -% \begin{macrocode} -% -% \end{macrocode} -% -% \subsection{\texttt{dvisvgm} driver} -% -% \begin{macrocode} -%<*dvisvgm> -% \end{macrocode} -% -% \subsubsection{Catalogue entries} -% -% \begin{macro}{\driver_pdf_catalog_gput:nn, \driver_pdf_info_gput:nn} -% No-op. -% \begin{macrocode} -\cs_new_protected:Npn \driver_pdf_catalog_gput:nn #1#2 { } -\cs_new_protected:Npn \driver_pdf_info_gput:nn #1#2 { } -% \end{macrocode} -% \end{macro} -% -% \subsubsection{Objects} -% -% \begin{macro}{\driver_pdf_object_new:nn} -% \begin{macro}[EXP]{\driver_pdf_object_ref:n} -% \begin{macro}{\driver_pdf_object_write:nn} -% All no-ops here. -% \begin{macrocode} -\cs_new_protected:Npn \driver_pdf_object_new:nn #1#2 { } -\cs_new:Npn \driver_pdf_object_ref:n #1 { } -\cs_new_protected:Npn \driver_pdf_object_write:nn #1#2 { } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \subsubsection{Structure} -% -% \begin{macro}{\driver_pdf_compresslevel:n} -% \begin{macro}{\driver_pdf_compress_objects:n} -% These are all no-ops. -% \begin{macrocode} -\cs_new_protected:Npn \driver_pdf_compresslevel:n #1 { } -\cs_new_protected:Npn \driver_pdf_compress_objects:n #1 { } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro} -% {\driver_pdf_version_major_gset:n, \driver_pdf_version_minor_gset:n} -% Data not available! -% \begin{macrocode} -\cs_new_protected:Npn \driver_pdf_version_major_gset:n #1 { } -\cs_new_protected:Npn \driver_pdf_version_minor_gset:n #1 { } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[EXP]{\driver_pdf_version_major:, \driver_pdf_version_minor:} -% Data not available! -% \begin{macrocode} -\cs_new:Npn \driver_pdf_version_major: { -1 } -\cs_new:Npn \driver_pdf_version_minor: { -1 } -% \end{macrocode} -% \end{macro} -% -% \begin{macrocode} -% -% \end{macrocode} -% -% \begin{macrocode} -% -% \end{macrocode} -% -% \end{implementation} -% -% \PrintIndex diff --git a/Master/texmf-dist/source/latex/l3kernel/l3drivers.dtx b/Master/texmf-dist/source/latex/l3kernel/l3drivers.dtx deleted file mode 100644 index 8e22549f2ae..00000000000 --- a/Master/texmf-dist/source/latex/l3kernel/l3drivers.dtx +++ /dev/null @@ -1,749 +0,0 @@ -% \iffalse meta-comment -% -%% File: l3drivers.dtx -% -% Copyright (C) 2011-2019 The LaTeX3 Project -% -% It may be distributed and/or modified under the conditions of the -% LaTeX Project Public License (LPPL), either version 1.3c of this -% license or (at your option) any later version. The latest version -% of this license is in the file -% -% https://www.latex-project.org/lppl.txt -% -% This file is part of the "l3kernel bundle" (The Work in LPPL) -% and all files in that bundle must be distributed together. -% -% ----------------------------------------------------------------------- -% -% The development version of the bundle can be found at -% -% https://github.com/latex3/latex3 -% -% for those people who are interested. -% -%<*driver> -\documentclass[full,kernel]{l3doc} -\begin{document} - \DocInput{\jobname.dtx} -\end{document} -% -% \fi -% -% \title{^^A -% The \textsf{l3drivers} package\\ Drivers^^A -% } -% -% \author{^^A -% The \LaTeX3 Project\thanks -% {^^A -% E-mail: -% \href{mailto:latex-team@latex-project.org} -% {latex-team@latex-project.org}^^A -% }^^A -% } -% -% \date{Released 2019-05-28} -% -% \maketitle -% -% \begin{documentation} -% -% \TeX{} relies on drivers in order to carry out a number of tasks, such -% as using color, including graphics and setting up hyper-links. The nature -% of the code required depends on the exact driver in use. Currently, -% \LaTeX3 is aware of the following drivers: -% \begin{itemize} -% \item \texttt{pdfmode}: The \enquote{driver} for direct PDF output by -% \emph{both} \pdfTeX{} and \LuaTeX{} (no separate driver is used in this -% case: the engine deals with PDF creation itself). -% \item \texttt{dvips}: The \texttt{dvips} program, which works in -% conjugation with \pdfTeX{} or \LuaTeX{} in DVI mode. -% \item \texttt{dvipdfmx}: The \texttt{dvipdfmx} program, which works in -% conjugation with \pdfTeX{} or \LuaTeX{} in DVI mode. -% \item \texttt{dvisvgm}: The \texttt{dvisvgm} program, which works in -% conjugation with \pdfTeX{} or \LuaTeX{} when run in DVI mode as well -% as with (u)\pTeX{} and \XeTeX{}. -% \item \texttt{xdvipdfmx}: The driver used by \XeTeX{}. -% \end{itemize} -% -% This module provides code closely tied to the exact driver in use: broadly, -% the functions here are implemented entirely independently for each case. -% As such, they often rely on higher-level code to provide necessary but -% shared operations. For example, in box rotation and scaling the functions -% here do no correct the final size of the box: this will always be required -% and thus is handled in the \pkg{box} module. -% -% Several of the operations here are low-level, and so may be used only in -% restricted contexts. Some also require understanding of PostScript/PDF -% concepts to be used corrected as they take \enquote{raw} arguments, similar -% in format to those used by the underlying driver. -% -% Given the close coupling of these functions to higher-level interfaces, at -% present the functions given here may change if this is useful for higher-level -% changes. However, equivalent \emph{functionality} will be provided for any -% higher-level function which is itself stable. For example, -% \cs{driver_box_use_rotate:Nn} is needed to implement the stable box rotation -% functions. As such, even if \cs{driver_box_use_rotate:Nn} were to be removed, -% a replacement would be provided. -% -% \section{Box clipping} -% -% \begin{function}[added = 2017-12-13]{\driver_box_use_clip:N} -% \begin{syntax} -% \cs{driver_box_use_clip:N} \meta{box} -% \end{syntax} -% Inserts the content of the \meta{box} at the current insertion point -% such that any material outside of the bounding box is not displayed -% by the driver. The material in the \meta{box} is still placed in the -% output stream: the clipping takes place at a driver level. -% \end{function} -% -% \section{Box rotation and scaling} -% -% \begin{function}[added = 2017-12-13, updated = 2018-04-26] -% {\driver_box_use_rotate:Nn} -% \begin{syntax} -% \cs{driver_box_use_rotate:Nn} \meta{box} \Arg{angle} -% \end{syntax} -% Inserts the content of the \meta{box} at the current insertion point -% rotated by the \meta{angle} (an \meta{fp expression} expressed in degrees). -% The material is -% rotated such the the \TeX{} reference point of the box is the center of -% rotation and remains the reference point after rotation. It is the -% responsibility of the code using this function to adjust the apparent -% size of the inserted material. -% \end{function} -% -% \begin{function}[added = 2017-12-13, updated = 2018-04-26] -% {\driver_box_use_scale:Nnn} -% \begin{syntax} -% \cs{driver_box_use_scale:Nnn} \meta{box} \Arg{x-scale} \Arg{y-scale} -% \end{syntax} -% Inserts the content of the \meta{box} at the current insertion point -% scale by the \meta{x-scale} and \meta{y-scale} (both \meta{fp expressions}). -% The reference point -% of the material will be unchanged. It is the responsibility of the -% code using this function to adjust the apparent size of the inserted -% material. -% \end{function} -% -% \section{Color support} -% -% \begin{function}[added = 2018-02-20]{\driver_color_cmyk:nnnn} -% \begin{syntax} -% \cs{driver_color_cmyk:nnnn} \Arg{cyan} \Arg{magenta} \Arg{yellow} -% \Arg{black} -% \end{syntax} -% Sets the color to the CMYK values specified, all of which are -% fp denotations in the range $0$ and $1$. For drawing colors, see -% \cs{driver_draw_stroke_cmyk:nnnn}, \emph{etc.} -% \end{function} -% -% \begin{function}[added = 2018-02-20]{\driver_color_gray:n} -% \begin{syntax} -% \cs{driver_color_gray:n} \Arg{gray} -% \end{syntax} -% Sets the color to the grayscale value specified, which is -% fp denotations in the range $0$ and $1$. For drawing colors, see -% \cs{driver_draw_stroke_gray:n}, \emph{etc.} -% \end{function} -% -% \begin{function}[added = 2018-02-20]{\driver_color_rgb:nnn} -% \begin{syntax} -% \cs{driver_color_rgb:nnn} \Arg{red} \Arg{green} \Arg{blue} -% \end{syntax} -% Sets the color to the RGB values specified, all of which are -% fp denotations in the range $0$ and $1$. For drawing colors, see -% \cs{driver_draw_stroke_rgb:nnn}, \emph{etc.} -% \end{function} -% -% \begin{function}[added = 2018-02-20]{\driver_color_pickup:N} -% \begin{syntax} -% \cs{driver_color_pickup:N} \meta{tl} -% \end{syntax} -% In \LaTeXe{} package mode, collects data on the current color from -% \tn{current@color} and stores it in the low-level format used by \pkg{expl3} -% in the \meta{tl}. -% \end{function} -% -% \section{Drawing} -% -% These functions -% are inspired heavily by the system layer of \pkg{pgf} (most have the -% same interface as the same functions in the latter's \cs{pgfsys@\ldots} -% namespace). They are intended to form the basis for higher level drawing -% interfaces, which themselves are likely to be further abstracted for user -% access. Again, this model is heavily inspired by \pkg{pgf} and -% Ti\textit{k}z. -% -% These low level drawing interfaces abstract from the driver raw requirements -% but still require an appreciation of the concepts of PostScript/PDF/SVG -% graphic creation. -% -% \begin{function} -% {\driver_draw_begin:, \driver_draw_end:} -% \begin{syntax} -% \cs{driver_draw_begin:} -% \meta{content} -% \cs{driver_draw_end:} -% \end{syntax} -% Defines a drawing environment. This is a scope for the purposes of -% the graphics state. Depending on the driver, other set up may or may not -% take place here. The natural size of the \meta{content} should be zero -% from the \TeX{} perspective: allowance for the size of the content must -% be made at a higher level (or indeed this can be skipped if the content is -% to overlap other material). -% \end{function} -% -% \begin{function} -% {\driver_draw_scope_begin:, \driver_draw_scope_end:} -% \begin{syntax} -% \cs{driver_draw_scope_begin:} -% \meta{content} -% \cs{driver_draw_scope_end:} -% \end{syntax} -% Defines a scope for drawing settings and so on. Changes to the graphic -% state and concepts such as color or linewidth are localised to a scope. -% This function pair must never be used if an partial path is under -% construction: such paths must be entirely contained at one unbroken -% scope level. Note that scopes do not form \TeX{} groups and may not -% be aligned with them. -% \end{function} -% -% \subsection{Path construction} -% -% \begin{function}{\driver_draw_moveto:nn} -% \begin{syntax} -% \cs{driver_draw_move:nn} \Arg{x} \Arg{y} -% \end{syntax} -% Moves the current drawing reference point to (\meta{x}, \meta{y}); -% any active transformation matrix applies. -% \end{function} -% -% \begin{function}{\driver_draw_lineto:nn} -% \begin{syntax} -% \cs{driver_draw_lineto:nn} \Arg{x} \Arg{y} -% \end{syntax} -% Adds a path from the current drawing reference point to -% (\meta{x}, \meta{y}); any active transformation matrix applies. Note -% that nothing is drawn until a fill or stroke operation is applied, and that -% the path may be discarded or used as a clip without appearing itself. -% \end{function} -% -% \begin{function}{\driver_draw_curveto:nnnnnn} -% \begin{syntax} -% \cs{driver_draw_curveto:nnnnnn} \Arg{x_1} \Arg{y_1} -% \Arg{x_2} \Arg{y_2} \Arg{x_3} \Arg{y_3} -% \end{syntax} -% Adds a Bezier curve path from the current drawing reference point to -% (\meta{x_3}, \meta{y_3}), using (\meta{x_1}, \meta{y_1}) and -% (\meta{x_2}, \meta{y_2}) as control points; any active transformation -% matrix applies. Note that nothing is drawn until a fill or stroke -% operation is applied, and that the path may be discarded or used as a clip -% without appearing itself. -% \end{function} -% -% \begin{function}{\driver_draw_rectangle:nnnn} -% \begin{syntax} -% \cs{driver_draw_rectangle:nnnn} \Arg{x} \Arg{y} \Arg{width} \Arg{height} -% \end{syntax} -% Adds rectangular path from (\meta{x_1}, \meta{y_1}) of \meta{height} -% and \meta{width}; any active transformation matrix applies. Note that -% nothing is drawn until a fill or stroke operation is applied, and that the -% path may be discarded or used as a clip without appearing itself. -% \end{function} -% -% \begin{function}{\driver_draw_closepath:} -% \begin{syntax} -% \cs{driver_draw_closepath:} -% \end{syntax} -% Closes an existing path, adding a line from the current point to the -% start of path. Note that nothing is drawn until a fill or stroke -% operation is applied, and that the path may be discarded or used as a clip -% without appearing itself. -% \end{function} -% -% \subsection{Stroking and filling} -% -% \begin{function}{\driver_draw_stroke:, \driver_draw_closestroke:} -% \begin{syntax} -% \meta{path construction} -% \cs{driver_draw_stroke:} -% \end{syntax} -% Draws a line along the current path, which is also closed in the case of -% \cs{driver_draw_closestroke:}. The nature of the line drawn -% is influenced by settings for -% \begin{itemize} -% \item Line thickness -% \item Stroke color (or the current color if no specific stroke color -% is set) -% \item Line capping (how non-closed line ends should look) -% \item Join style (how a bend in the path should be rendered) -% \item Dash pattern -% \end{itemize} -% The path may also be used for clipping. -% \end{function} -% -% \begin{function}{\driver_draw_fill:, \driver_draw_fillstroke:} -% \begin{syntax} -% \meta{path construction} -% \cs{driver_draw_fill:} -% \end{syntax} -% Fills the area surrounded by the current path: this will be closed prior -% to filling if it is not already. The \texttt{fillstroke} version also -% strokes the path as described for \cs{driver_draw_stroke:}. The fill is -% influenced by the setting for fill color (or the current color if no -% specific stroke color is set). The path may also be used for clipping. -% For paths which are self-intersecting or comprising multiple parts, the -% determination of which areas are inside the path is made using the non-zero -% winding number rule unless the even-odd rule is active. -% \end{function} -% -% \begin{function}{\driver_draw_nonzero_rule:, \driver_draw_evenodd_rule:} -% \begin{syntax} -% \cs{driver_draw_nonzero_rule:} -% \end{syntax} -% Active either the non-zero winding number or the even-odd rule, -% respectively, for determining what is inside a fill or clip area. -% For technical reasons, these command are not influenced by scoping -% and apply on an ongoing basis. -% \end{function} -% -% \begin{function}{\driver_draw_clip:} -% \begin{syntax} -% \meta{path construction} -% \cs{driver_draw_clip:} -% \end{syntax} -% Indicates that the current path should be used for clipping, such that -% any subsequent material outside of the path (but within the current -% scope) will not be shown. This command should be given once a path is -% complete but before it is stroked or filled (if appropriate). This -% command is \emph{not} affected by scoping: it applies to exactly one -% path as shown. -% \end{function} -% -% \begin{function}{\driver_draw_discardpath:} -% \begin{syntax} -% \meta{path construction} -% \cs{driver_draw_discardpath:} -% \end{syntax} -% Discards the current path without stroking or filling. This is primarily -% useful for paths constructed purely for clipping, as this alone does not -% end the paths existence. -% \end{function} -% -% \subsection{Stroke options} -% -% \begin{function}{\driver_draw_linewidth:n} -% \begin{syntax} -% \cs{driver_draw_linewidth:n} \Arg{dimexpr} -% \end{syntax} -% Sets the width to be used for stroking to \meta{dimexpr}. -% \end{function} -% -% \begin{function}{\driver_draw_dash_pattern:nn} -% \begin{syntax} -% \cs{driver_draw_dash:nn} \Arg{dash pattern} \Arg{phase} -% \end{syntax} -% Sets the pattern of dashing to be used when stroking a line. The -% \meta{dash pattern} should be a comma-separated list of dimension -% expressions. This is then interpreted as a series of pairs of line-on -% and line-off lengths. For example \texttt{3pt, 4pt} means that $3$\,pt on, -% $4$\,pt off, $3$\,pt on, and so on. A more complex pattern will also -% repeat: \texttt{3pt, 4pt, 1pt, 2pt} results in $3$\,pt on, $4$\,pt off, -% $1$\,pt on, $2$\,pt off, $3$\,pt on, and so on. An odd number of entries -% means that the last is repeated, for example \texttt{3pt} is equal to -% \texttt{3pt, 3pt}. An empty pattern yields a solid line. -% -% The \meta{phase} specifies an offset at the start of the cycle. For -% example, with a pattern \texttt{3pt} a phase of \texttt{1pt} means -% that the output is $2$\,pt on, $3$\,pt off, $3$\,pt on, $3$\,pt on, -% \emph{etc.} -% \end{function} -% -% \begin{function} -% { -% \driver_draw_cap_butt: , -% \driver_draw_cap_rectangle: , -% \driver_draw_cap_round: -% } -% \begin{syntax} -% \cs{driver_draw_cap_butt:} -% \end{syntax} -% Sets the style of terminal stroke position to one of butt, rectangle or -% round. -% \end{function} -% -% \begin{function} -% { -% \driver_draw_join_bevel: , -% \driver_draw_join_miter: , -% \driver_draw_join_round: -% } -% \begin{syntax} -% \cs{driver_draw_cap_butt:} -% \end{syntax} -% Sets the style of stroke joins to one of bevel, miter or round. -% \end{function} -% -% \begin{function}{\driver_draw_miterlimit:n} -% \begin{syntax} -% \cs{driver_draw_miterlimit:n} \Arg{factor} -% \end{syntax} -% Sets the miter limit of lines joined as a miter, as described in the -% PDF and PostScript manuals. The \meta{factor} here is an -% \meta{fp expression}. -% \end{function} -% -% \subsection{Color} -% -% \begin{function} -% { -% \driver_draw_color_fill_cmyk:nnnn , -% \driver_draw_color_stroke_cmyk:nnnn -% } -% \begin{syntax} -% \cs{driver_draw_color_fill_cmyk:nnnn} \Arg{cyan} \Arg{magenta} \Arg{yellow} -% \Arg{black} -% \end{syntax} -% Sets the color for drawing to the CMYK values specified, all of which are -% fp denotations in the range $0$ and $1$. -% \end{function} -% -% \begin{function} -% { -% \driver_draw_color_fill_gray:n , -% \driver_draw_color_stroke_gray:n -% } -% \begin{syntax} -% \cs{driver_draw_color_fill_gray:n} \Arg{gray} -% \end{syntax} -% Sets the color for drawing to the grayscale value specified, which is -% fp denotations in the range $0$ and $1$. -% \end{function} -% -% \begin{function} -% { -% \driver_draw_color_fill_rgb:nnn , -% \driver_draw_color_stroke_rgb:nnn -% } -% \begin{syntax} -% \cs{driver_draw_color_fill_rgb:nnn} \Arg{red} \Arg{green} \Arg{blue} -% \end{syntax} -% Sets the color for drawing to the RGB values specified, all of which are -% fp denotations in the range $0$ and $1$. -% \end{function} -% -% \subsection{Inserting \TeX{} material} -% -% \begin{function}{\driver_draw_box_use:Nnnnn} -% \begin{syntax} -% \cs{driver_draw_box_use:Nnnnn} \meta{box} -% \Arg{a} \Arg{b} \Arg{c} \Arg{d} \Arg{x} \Arg{y} -% \end{syntax} -% Inserts the \meta{box} as an hbox with the box reference point placed -% at ($x$, $y$). The transformation matrix $[a b c d]$ is applied -% to the box, allowing it to be in synchronisation with any scaling, rotation -% or skewing applying more generally. Note that \TeX{} material should not -% be inserted directly into a drawing as it would not be in the correct -% location. Also note that this function must be used inside a box of zero -% size, shifted appropriately for the correct result; a low-level engine -% error may result if this is not the case. -% \end{function} -% -% \subsection{Coordinate system transformations} -% -% \begin{function}{\driver_draw_cm:nnnn} -% \begin{syntax} -% \cs{driver_draw_cm:nnnn} \Arg{a} \Arg{b} \Arg{c} \Arg{d} -% \end{syntax} -% Applies the transformation matrix $[a b c d]$ to the current graphic state. -% This affects any subsequent items in the same scope but not those already -% given. -% \end{function} -% -% \section{Graphics inclusion} -% -% Graphics inclusion support is closely tied to the higher-level \pkg{l3graphics} -% module. This arises as information concerning images (\emph{e.g.}~page -% numbers in multi-page files) is needed to correct cache image data. As -% such, the driver code here assumes the following are defined -% \begin{itemize} -% \item \cs{l_image_decodearray_tl} -% \item \cs{l_image_interpolate_tl} -% \item \cs{l_image_page_tl} -% \item \cs{l_image_pagebox_tl} -% \end{itemize} -% -% Note also that the functions defined will depend on the file types supported -% by the driver. As such, a calling function should typically test for the -% existence of an appropriate function to determine if the image file is -% supported. -% -% \begin{function}[added = 2019-05-07] -% { -% \driver_graphics_getbb_eps:n, -% \driver_graphics_getbb_jpg:n, -% \driver_graphics_getbb_pdf:n, -% \driver_graphics_getbb_png:n -% } -% \begin{syntax} -% \cs{driver_graphics_getbb_pdf:n} \Arg{file} -% \end{syntax} -% These functions load the requested image \meta{file} and obtain the -% bounding box information on the file. They may also cache the image for -% subsequent inclusion: this is driver-dependent. The bounding box data -% will be stored in \cs{l_image_llx_dim}, \cs{l_image_lly_dim}, -% \cs{l_image_urx_dim}, and \cs{l_image_ury_dim} after use of these -% functions. -% \end{function} -% -% \begin{function}[added = 2019-05-07] -% { -% \driver_graphics_include_eps:n, -% \driver_graphics_include_jpg:n, -% \driver_graphics_include_pdf:n, -% \driver_graphics_include_png:n -% } -% \begin{syntax} -% \cs{driver_graphics_include_pdf:n} \Arg{file} -% \end{syntax} -% These functions include the appropriate image type at the current position. -% They should be preceded by use of the matching \texttt{getbb} function to -% set the bounding box correctly; in some drivers, the \texttt{getbb} -% function is also responsible for caching the image for later inclusion. -% \end{function} -% -% \section{PDF Features} -% -% A range of PDF features are exposed by \pdfTeX{} and \LuaTeX{} in direct PDF -% output mode, and the vast majority of these are also controllable using -% the \texttt{(x)dvipdfmx} driver (as DVI instructions are converted directly -% to PDF). Some of these functions are also available for cases where PDFs -% are generated by \texttt{dvips}: this depends on being able to pass -% information through correctly. -% -% \subsection{PDF Annotations} -% -% \begin{function}[added = 2019-04-10] -% {\driver_pdf_annotation:nnnn} -% \begin{syntax} -% \cs{driver_pdf_annotation:nnnn} \Arg{width} \Arg{height} \Arg{depth} \Arg{dictionary} -% \end{syntax} -% Creates a generic PDF annotation of the given \meta{height}, \meta{width} -% and \meta{depth} and featuring the \meta{dictionary}. -% \end{function} -% -% \begin{function}[added = 2019-04-17, updated = 2019-05-03] -% { -% \driver_pdf_link_begin_goto:nnw, -% \driver_pdf_link_begin_user:nnw, -% \driver_pdf_link_end: -% } -% \begin{syntax} -% \cs{driver_pdf_link_begin_user:nnw} \Arg{attributes} \Arg{action} -% \Arg{content} -% \cs{driver_pdf_link_end:} -% \cs{driver_pdf_link_begin_goto:nnw} \Arg{attributes} \Arg{target} -% \Arg{content} -% \cs{driver_pdf_link_end:} -% \end{syntax} -% Creates a link of the \meta{type} |goto| or |user| with the given -% \meta{attributes}, points toward the \meta{action} and surround the -% \TeX{} \meta{content}. The |begin| and |end| functions must be given -% at the same box level. Depending upon the back-end in use, the -% \meta{content} may be placed in a hbox as part of processing. -% The |goto| type will automatically add |/Subtype /Link| to the PDF -% dictionary for the annotation produced; other classes do not add -% this, so the |/Subtype| must be provided as part of the \meta{action}. -% \end{function} -% -% \begin{function}[EXP, added = 2019-04-09]{\driver_pdf_link_last:} -% \begin{syntax} -% \cs{driver_pdf_link_last:} -% \end{syntax} -% Expands to the object reference -% \end{function} -% -% \begin{function}[EXP, added = 2019-04-11]{\driver_pdf_link_margin:n} -% \begin{syntax} -% \cs{driver_pdf_link_margin:n} \Arg{dimen} -% \end{syntax} -% Sets the length of the margin between content and the border of a link. -% Different back-ends treat the scoping of this value in different ways: -% \pdfTeX{} and \LuaTeX{} apply this at shipout (so it is global, once per -% page), whilst with -% \texttt{dvips} the scope is managed at the PostScript level. For -% \texttt{(x)dvipdfmx}, this setting applies to \emph{all} annotations -% (\emph{i.e.}~it is global), and thus it may be necessary to set to -% \texttt{0pt} to avoid breaking for example animations. In general, -% this setting should be applied once per document, prior to the -% first page being shipped out. -% \end{function} -% -% \begin{function}[added = 2019-04-26]{\driver_pdf_destination:nn} -% \begin{syntax} -% \cs{driver_pdf_destination:nn} \Arg{name} \Arg{action} -% \end{syntax} -% Creates a destination (anchor) called \meta{name}; when a jump is made -% by a link to the destination, one of the following actions may take -% place -% \begin{itemize} -% \item \texttt{xyz} Move the view such that the target point is at the -% top-left of the viewer screen -% \item \texttt{\meta{scale}} As for \texttt{xyz}, but also sets the -% viewer \meta{scale} -% \item \texttt{fit} Display the page containing the destination and fit -% the entire page within the viewer window -% \item \texttt{fitb} Display the page containing the destination and fit -% the bounding box of the page within the viewer window -% \item \texttt{fitbh} Move to the destination page such that the -% anchor point is at the top of the viewer screen, and scale -% such that the bounding box fills the viewer width -% \item \texttt{fitbv} Move to the destination page such that the -% anchor point is at the left of the viewer screen, and scale -% such that the bounding box fills the viewer height -% \item \texttt{fith} Move to the destination page such that the -% anchor point is at the top of the viewer screen, and scale -% such that the page fills the viewer width -% \item \texttt{fitv} Move to the destination page such that the -% anchor point is at the left of the viewer screen, and scale -% such that the page fills the viewer height -% \end{itemize} -% A \meta{scale} of zero is equivalent to \texttt{xyz}. -% \end{function} -% -% \begin{function}[added = 2019-04-28]{\driver_pdf_destination_rectangle:nn} -% \begin{syntax} -% \cs{driver_pdf_destination_rectangle:nn} \Arg{name} \Arg{content} -% \end{syntax} -% Creates a destination (anchor) called \meta{name}; when a jump is made -% by a link to the destination, the viewer will set the zoom such that all -% of the \meta{content} is visible taking up the full width or height of the -% viewer area. -% \end{function} -% -% \subsection{PDF Catalogue entries} -% -% \begin{function}[added = 2019-04-28]{\driver_pdf_catalog_gput:nn} -% \begin{syntax} -% \cs{driver_pdf_catalog_gput:nn} \Arg{key} \Arg{value} -% \end{syntax} -% Adds the key--value pair to the PDF catalog. The \meta{key} should -% be given \emph{without} the leading |/|. The \meta{value} should be -% a \enquote{raw} PDF dictionary entry, including the |(|/|)| pair for -% a string, a leading |/| for a boolean, \emph{etc.} -% \end{function} -% -% \begin{function}[added = 2019-04-28]{\driver_pdf_info_gput:nn} -% \begin{syntax} -% \cs{driver_pdf_info_gput:nn} \Arg{key} \Arg{value} -% \end{syntax} -% Adds the key--value pair to the PDF information. The \meta{key} should -% be given \emph{without} the leading |/|. The \meta{value} should be -% a \enquote{raw} PDF dictionary entry, including the |(|/|)| pair for -% a string or leading |/| for a boolean. -% \end{function} -% -% \subsection{PDF Objects} -% -% Objects are used to provide a range of data structures in a PDF. At the -% driver level, different PDF object types are declared separately. Objects -% are only \emph{written} to the PDF when referenced. -% -% \begin{function}{\driver_pdf_object_new:nn} -% \begin{syntax} -% \cs{driver_pdf_object_new:n} \Arg{name} \Arg{type} -% \end{syntax} -% Declares \meta{name} as a PDF object. The \texttt{type} should be one of -% |array| or |dict|, |fstream| or |stream|. -% \end{function} -% -% \begin{function}[EXP]{\driver_pdf_object_ref:n} -% \begin{syntax} -% \cs{driver_pdf_object_ref:n} \Arg{object} -% \end{syntax} -% Inserts the appropriate information to reference the \meta{object} -% in for example page resource allocation. -% \end{function} -% -% \begin{function}{\driver_pdf_object_write:nn} -% \begin{syntax} -% \cs{driver_pdf_object_write:nn} \Arg{name} \Arg{data} -% \end{syntax} -% Writes the \meta{data} as content of the \meta{object}. Depending on the -% \meta{type} declared for the object, the format required for the -% \meta{data} will vary -% \begin{itemize} -% \item[\texttt{array}] A space-separated list of values -% \item[\texttt{dict}] Key--value pairs in the form -% \texttt{/\meta{key} \meta{value}} -% \item[\texttt{fstream}] Two brace groups: \meta{file name} and -% \meta{content} -% \item[\texttt{stream}] Two brace groups: \meta{attributes (dictionary)} -% and \meta{content} -% \end{itemize} -% \end{function} -% -% \subsection{PDF structure} -% -% \begin{function}{\driver_pdf_compresslevel:n} -% \begin{syntax} -% \cs{driver_pdf_compresslevel:n} \Arg{level} -% \end{syntax} -% Sets the degree of compression used for PDF files: the \meta{level} should -% be in the range $0$ to $9$ (higher is more compression). Typically, either -% compression is disables ($0$) or maximised ($9$). When used with -% \texttt{(x)dvipdfmx}, this setting may only be applied globally: it should -% be set only once. -% \end{function} -% -% \begin{function}[added = 2019-05-07]{\driver_pdf_objects:} -% \begin{syntax} -% \cs{driver_pdf_compress_objects:n} \Arg{switch} -% \end{syntax} -% Enables or disables the compression of non-stream objects when writing -% the PDF. This depends on the \meta{switch}: either \texttt{true} or -% \texttt{false}). Compression of non-stream objects is used to -% reduce the size of PDFs, and typically are enabled as standard. When used -% with \texttt{(x)dvipdfmx}, object creation can be disabled but not -% re-enabled, and this setting may only be applied globally: it should -% be set only once. Note that for \texttt{dvips} this setting has no action, -% as control of this functionality is dependent on the conversion from -% PostScript to PDF. -% \end{function} -% -% \begin{function}[EXP, added = 2019-04-11] -% {\driver_pdf_version_major:, \driver_pdf_version_minor:} -% \begin{syntax} -% \cs{driver_pdf_version_major:} -% \cs{driver_pdf_version_minor:} -% \end{syntax} -% Expands to the current value of the major or minor version of PDF being -% created, a non-negative integer. Where a value is not available at the -% \TeX{} run level, the result is $-1$. (This is necessary as the minor -% version may be $0$.) -% \end{function} -% -% \begin{function}[EXP, added = 2019-04-11] -% {\driver_pdf_version_major_gset:n, \driver_pdf_version_minor_gset:n} -% \begin{syntax} -% \cs{driver_pdf_version_major_gset:n} \Arg{integer} -% \cs{driver_pdf_version_minor_gset:n} \Arg{integer} -% \end{syntax} -% Sets the PDF version as specified: the allowable range is not checked -% at this level. -% \end{function} -% -% \end{documentation} -% -% \begin{implementation} -% -% \section{\pkg{l3drivers} Implementation} -% -% Nothing to see here: everything is in the subfiles! -% -% \end{implementation} -% -% \PrintIndex diff --git a/Master/texmf-dist/source/latex/l3kernel/l3expan.dtx b/Master/texmf-dist/source/latex/l3kernel/l3expan.dtx index 4f0d3af3ef1..6b319f99231 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3expan.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3expan.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3file.dtx b/Master/texmf-dist/source/latex/l3kernel/l3file.dtx index 886e6011167..ef11f76a971 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3file.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3file.dtx @@ -44,7 +44,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3final.dtx b/Master/texmf-dist/source/latex/l3kernel/l3final.dtx index 9695d202e05..0b4747e55a3 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3final.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3final.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3flag.dtx b/Master/texmf-dist/source/latex/l3kernel/l3flag.dtx index 3b487b0bec1..cfb6c52dac5 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3flag.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3flag.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3format.ins b/Master/texmf-dist/source/latex/l3kernel/l3format.ins index a0ba292e390..35279ca592b 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3format.ins +++ b/Master/texmf-dist/source/latex/l3kernel/l3format.ins @@ -64,7 +64,7 @@ and all files in that bundle must be distributed together. \from{l3expan.dtx} {initex} \from{l3tl.dtx} {initex} \from{l3str.dtx} {initex} - \from{l3quark.dtx} {package} + \from{l3quark.dtx} {initex} \from{l3seq.dtx} {initex} % ======== FORMAT ONLY ========= \from{l3alloc.dtx} {initex} @@ -94,8 +94,9 @@ and all files in that bundle must be distributed together. \from{l3fp-trig.dtx} {initex} \from{l3fp-convert.dtx} {initex} \from{l3fp-random.dtx} {initex} - \from{l3fparray.dtx} {package} + \from{l3fparray.dtx} {initex} \from{l3sort.dtx} {initex} + \from{l3str-convert.dtx}{initex} \from{l3tl-analysis.dtx}{initex} \from{l3regex.dtx} {initex} \from{l3box.dtx} {initex} @@ -111,71 +112,24 @@ and all files in that bundle must be distributed together. } } -\generate - { - \file{l3dvipdfmx.ltx} - { - \from{l3drivers.dtx} {initex,dvipdfmx} - \from{l3drivers-basics.dtx} {initex,dvipdfmx} - \from{l3drivers-color.dtx} {initex,dvipdfmx} - \from{l3drivers-box.dtx} {initex,dvipdfmx} - \from{l3drivers-draw.dtx} {initex,dvipdfmx} - \from{l3drivers-graphics.dtx}{initex,dvipdfmx} - \from{l3drivers-pdf.dtx} {initex,dvipdfmx} - } - } -\generate - { - \file{l3dvips.ltx} - { - \from{l3drivers.dtx} {initex,dvips} - \from{l3drivers-basics.dtx} {initex,dvips} - \from{l3drivers-color.dtx} {initex,dvips} - \from{l3drivers-box.dtx} {initex,dvips} - \from{l3drivers-draw.dtx} {initex,dvips} - \from{l3drivers-graphics.dtx}{initex,dvips} - \from{l3drivers-pdf.dtx} {initex,dvips} - } - } -\generate - { - \file{l3dvisvgm.ltx} - { - \from{l3drivers.dtx} {initex,dvisvgm} - \from{l3drivers-basics.dtx} {initex,dvisvgm} - \from{l3drivers-color.dtx} {initex,dvisvgm} - \from{l3drivers-box.dtx} {initex,dvisvgm} - \from{l3drivers-draw.dtx} {initex,dvisvgm} - \from{l3drivers-graphics.dtx}{initex,dvisvgm} - \from{l3drivers-pdf.dtx} {initex,dvisvgm} - } - } -\generate - { - \file{l3pdfmode.ltx} - { - \from{l3drivers.dtx} {initex,pdfmode} - \from{l3drivers-basics.dtx} {initex,pdfmode} - \from{l3drivers-color.dtx} {initex,pdfmode} - \from{l3drivers-box.dtx} {initex,pdfmode} - \from{l3drivers-draw.dtx} {initex,pdfmode} - \from{l3drivers-graphics.dtx}{initex,pdfmode} - \from{l3drivers-pdf.dtx} {initex,pdfmode} - } - } -\generate - { - \file{l3xdvipdfmx.ltx} - { - \from{l3drivers.dtx} {initex,xdvipdfmx} - \from{l3drivers-basics.dtx} {initex,xdvipdfmx} - \from{l3drivers-color.dtx} {initex,xdvipdfmx} - \from{l3drivers-box.dtx} {initex,xdvipdfmx} - \from{l3drivers-draw.dtx} {initex,xdvipdfmx} - \from{l3drivers-graphics.dtx}{initex,xdvipdfmx} - \from{l3drivers-pdf.dtx} {initex,xdvipdfmx} - } - } +% ISO-8859 encodings. +\generate{% + \file{l3str-enc-iso88591.def} {\from{l3str-convert.dtx}{iso88591}}% + \file{l3str-enc-iso88592.def} {\from{l3str-convert.dtx}{iso88592}}% + \file{l3str-enc-iso88593.def} {\from{l3str-convert.dtx}{iso88593}}% + \file{l3str-enc-iso88594.def} {\from{l3str-convert.dtx}{iso88594}}% + \file{l3str-enc-iso88595.def} {\from{l3str-convert.dtx}{iso88595}}% + \file{l3str-enc-iso88596.def} {\from{l3str-convert.dtx}{iso88596}}% + \file{l3str-enc-iso88597.def} {\from{l3str-convert.dtx}{iso88597}}% + \file{l3str-enc-iso88598.def} {\from{l3str-convert.dtx}{iso88598}}% + \file{l3str-enc-iso88599.def} {\from{l3str-convert.dtx}{iso88599}}% + \file{l3str-enc-iso885910.def} {\from{l3str-convert.dtx}{iso885910}}% + \file{l3str-enc-iso885911.def} {\from{l3str-convert.dtx}{iso885911}}% + \file{l3str-enc-iso885913.def} {\from{l3str-convert.dtx}{iso885913}}% + \file{l3str-enc-iso885914.def} {\from{l3str-convert.dtx}{iso885914}}% + \file{l3str-enc-iso885915.def} {\from{l3str-convert.dtx}{iso885915}}% + \file{l3str-enc-iso885916.def} {\from{l3str-convert.dtx}{iso885916}}% +} \generate{\file{l3docstrip.tex}{\from{l3docstrip.dtx}{program}}} diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-assign.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-assign.dtx index 4029c929517..63a526acf80 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fp-assign.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-assign.dtx @@ -40,7 +40,7 @@ % {latex-team@latex-project.org}^^A % }^^A % } -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % \maketitle % % \begin{documentation} diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-aux.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-aux.dtx index 79aa81924ec..d4a5e7bcf53 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fp-aux.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-aux.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-basics.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-basics.dtx index 2d5dc0d66ae..4d169181279 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fp-basics.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-basics.dtx @@ -40,7 +40,7 @@ % {latex-team@latex-project.org}^^A % }^^A % } -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-convert.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-convert.dtx index cab359055de..dc65bb1b0bd 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fp-convert.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-convert.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-expo.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-expo.dtx index 192a7d447c1..79a2fa3b28d 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fp-expo.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-expo.dtx @@ -40,7 +40,7 @@ % {latex-team@latex-project.org}^^A % }^^A % } -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-extended.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-extended.dtx index e5d41df0b39..d9acdd178af 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fp-extended.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-extended.dtx @@ -40,7 +40,7 @@ % {latex-team@latex-project.org}^^A % }^^A % } -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx index 57441d7ebdc..c6ca99f654f 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx @@ -40,7 +40,7 @@ % {latex-team@latex-project.org}^^A % }^^A % } -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-parse.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-parse.dtx index ff05d8a2260..5dadc84440e 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fp-parse.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-parse.dtx @@ -40,7 +40,7 @@ % {latex-team@latex-project.org}^^A % }^^A % } -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-random.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-random.dtx index b45b27d3ea1..352ff795796 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fp-random.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-random.dtx @@ -40,7 +40,7 @@ % {latex-team@latex-project.org}^^A % }^^A % } -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-round.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-round.dtx index 75e0dd7653d..a618771bc2e 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fp-round.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-round.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-traps.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-traps.dtx index b1bf6c6ec13..e71bc4cf45e 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fp-traps.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-traps.dtx @@ -40,7 +40,7 @@ % {latex-team@latex-project.org}^^A % }^^A % } -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % \maketitle % % \begin{documentation} diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-trig.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-trig.dtx index 9e68208c9cb..2347a106f94 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fp-trig.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-trig.dtx @@ -40,7 +40,7 @@ % {latex-team@latex-project.org}^^A % }^^A % } -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp.dtx index 620944118d7..91b5d1a5e17 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fp.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp.dtx @@ -49,7 +49,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fparray.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fparray.dtx index 0aec3f16fb1..1256fef4295 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fparray.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fparray.dtx @@ -44,7 +44,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3int.dtx b/Master/texmf-dist/source/latex/l3kernel/l3int.dtx index 5ea71b0afb6..382ff92955a 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3int.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3int.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3intarray.dtx b/Master/texmf-dist/source/latex/l3kernel/l3intarray.dtx index 59bbffa95c2..0d3c32b664d 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3intarray.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3intarray.dtx @@ -44,7 +44,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3kernel-functions.dtx b/Master/texmf-dist/source/latex/l3kernel/l3kernel-functions.dtx index 17255a50305..3a197294024 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3kernel-functions.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3kernel-functions.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % @@ -527,6 +527,116 @@ % only a single expansion. % \end{function} % +% \section{Kernel backend functions} +% +% These functions are required to pass information to the backend. The nature +% of these means that they are defined only when the relevant backend is in +% use. +% +% \begin{function} +% { +% \__kernel_backend_literal:n, +% \__kernel_backend_literal:e, +% \__kernel_backend_literal:x +% } +% \begin{syntax} +% \cs{__kernel_backend_literal:n} \Arg{content} +% \end{syntax} +% Adds the \meta{content} literally to the current vertical list as a +% whatsit. The nature of the \meta{content} will depend on the backend in +% use. +% \end{function} +% +% \begin{function} +% { +% \__kernel_backend_literal_postscript:n, +% \__kernel_backend_literal_postscript:x +% } +% \begin{syntax} +% \cs{__kernel_backend_literal_postscript:n} \Arg{PostScript} +% \end{syntax} +% Adds the \meta{PostScript} literally to the current vertical list as a +% whatsit. No positioning is applied. +% \end{function} +% +% \begin{function} +% { +% \__kernel_backend_literal_pdf:n, +% \__kernel_backend_literal_pdf:x +% } +% \begin{syntax} +% \cs{__kernel_backend_literal_pdf:n} \Arg{PDF instructions} +% \end{syntax} +% Adds the \meta{PDF instructions} literally to the current vertical list as +% a whatsit. No positioning is applied. +% \end{function} +% +% \begin{function} +% { +% \__kernel_backend_literal_svg:n, +% \__kernel_backend_literal_svg:x +% } +% \begin{syntax} +% \cs{__kernel_backend_literal_svg:n} \Arg{SVG instructions} +% \end{syntax} +% Adds the \meta{SVG instructions} literally to the current vertical list as +% a whatsit. No positioning is applied. +% \end{function} +% +% \begin{function} +% { +% \__kernel_backend_postscript:n, +% \__kernel_backend_postscript:x +% } +% \begin{syntax} +% \cs{__kernel_backend_postscript:n} \Arg{PostScript} +% \end{syntax} +% Adds the \meta{PostScript} to the current vertical list as a +% whatsit. The PostScript reference point is adjusted to match the +% current position. The PostScript is inserted inside a |SDict begin|/|end| +% pair. +% \end{function} +% +% \begin{function}{\__kernel_backend_postscript_header:n} +% \begin{syntax} +% \cs{__kernel_backend_postscript_header:n} \Arg{PostScript} +% \end{syntax} +% Adds the \meta{PostScript} to the PostScript header. +% \end{function} +% +% \begin{function}{\__kernel_backend_align_begin:, \__kernel_backend_align_end:} +% \begin{syntax} +% \cs{__kernel_backend_align_begin:} +% \meta{PostScript literals} +% \cs{__kernel_backend_align_end:} +% \end{syntax} +% Arranges to align the PostScript and DVI current positions and scales. +% \end{function} +% +% \begin{function}{\__kernel_backend_scope_begin:, \__kernel_backend_scope_end:} +% \begin{syntax} +% \cs{__kernel_backend_scope_begin:} +% \meta{content} +% \cs{__kernel_backend_scope_end:} +% \end{syntax} +% Creates a scope for instructions at the backend level. +% \end{function} +% +% \begin{function} +% { +% \__kernel_backend_matrix:n, +% \__kernel_backend_matrix:x +% } +% \begin{syntax} +% \cs{__kernel_backend_matrix:n} \Arg{matrix} +% \end{syntax} +% Applies the \meta{matrix} to the current transformation matrix. +% \end{function} +% +% \begin{function}{\l__kernel_color_stack_int} +% The color stack used in \pdfTeX{} and \LuaTeX{} for the main color. +% \end{function} +% % \end{implementation} % % \PrintIndex diff --git a/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx b/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx index 511d1fd9b7a..bf34793cd57 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % @@ -125,8 +125,8 @@ % \cs{keys_define:nn} \Arg{module} \Arg{keyval list} % \end{syntax} % Parses the \meta{keyval list} and defines the keys listed there for -% \meta{module}. The \meta{module} name should be a text value, but -% there are no restrictions on the nature of the text. In practice the +% \meta{module}. The \meta{module} name is treated as a string. +% In practice the % \meta{module} should be chosen to be unique to the module in question % (unless deliberately adding keys to an existing module). % @@ -1346,7 +1346,8 @@ { \@@_property_find:n {#1} \cs_if_exist:cTF { \c_@@_props_root_tl \l_@@_property_tl } - { \@@_define_code:n {#2} } + { \@@_define_code:n {#2} + } { \tl_if_empty:NF \l_@@_property_tl { @@ -1386,7 +1387,7 @@ { \tl_if_empty:NF \l_@@_module_tl { \l_@@_module_tl / } - #1 + \tl_trim_spaces:n {#1} } \tl_set:Nn \l_@@_property_tl { . #2 } } @@ -1436,7 +1437,7 @@ { \use:c { \c_@@_props_root_tl \l_@@_property_tl } {#1} } } \exp_last_unbraced:NNNNo - \cs_new:Npn \__keys_define_code:w #1 \c_colon_str #2 \q_stop + \cs_new:Npn \@@_define_code:w #1 \c_colon_str #2 \q_stop { \tl_if_empty:nTF {#2} } % \end{macrocode} % \end{macro} @@ -2680,12 +2681,41 @@ % \end{macro} % % \begin{macro}[EXP]{\@@_trim_spaces:n} -% Used in a few places so worth handling as a dedicated function. +% \begin{macro}[EXP] +% { +% \@@_trim_spaces_auxi:w , +% \@@_trim_spaces_auxii:w , +% \@@_trim_spaces_auxiii:w +% } +% Space stripping has to allow for the fact that the key here might have +% several parts, and spaces need to be stripped from each part. % \begin{macrocode} \cs_new:Npn \@@_trim_spaces:n #1 - { \tl_trim_spaces:o { \tl_to_str:n {#1} } } + { + \exp_after:wN \@@_trim_spaces_auxi:w \tl_to_str:n {#1} + / \q_nil \q_stop + + } +\cs_new:Npn \@@_trim_spaces_auxi:w #1 / #2 \q_stop + { + \quark_if_nil:nTF {#2} + { \tl_trim_spaces:n {#1} } + { \@@_trim_spaces_auxii:w #1 / #2 } + } +\cs_new:Npn \@@_trim_spaces_auxii:w #1 / #2 / \q_nil + { + \tl_trim_spaces:n {#1} + \@@_trim_spaces_auxiii:w #2 / \q_recursion_tail / \q_recursion_stop + } +\cs_set:Npn \@@_trim_spaces_auxiii:w #1 / + { + \quark_if_recursion_tail_stop:n {#1} + \tl_trim_spaces:n { / #1 } + \@@_trim_spaces_auxiii:w + } % \end{macrocode} % \end{macro} +% \end{macro} % % \begin{macro}[EXP,pTF]{\keys_if_exist:nn} % A utility for others to see if a key exists. diff --git a/Master/texmf-dist/source/latex/l3kernel/l3legacy.dtx b/Master/texmf-dist/source/latex/l3kernel/l3legacy.dtx index a67517b667f..fee6219c20e 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3legacy.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3legacy.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3luatex.dtx b/Master/texmf-dist/source/latex/l3kernel/l3luatex.dtx index 1b623da7f46..3d9bce20273 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3luatex.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3luatex.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3msg.dtx b/Master/texmf-dist/source/latex/l3kernel/l3msg.dtx index 4f3d8a69327..733c6b5e844 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3msg.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3msg.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % @@ -290,7 +290,8 @@ % \end{syntax} % Issues \meta{module} error \meta{message}, passing \meta{arg one} to % \meta{arg four} to the text-creating functions. After issuing a -% fatal error the \TeX{} run halts. +% fatal error the \TeX{} run halts. No PDF file will be produced in +% this case (DVI mode runs may produce a truncated DVI file). % \end{function} % % \begin{function}[updated = 2012-08-11] @@ -509,10 +510,10 @@ %<@@=msg> % \end{macrocode} % -% \begin{variable}{\l_@@_tmp_tl} +% \begin{variable}{\l_@@_internal_tl} % A general scratch for the module. % \begin{macrocode} -\tl_new:N \l_@@_tmp_tl +\tl_new:N \l_@@_internal_tl % \end{macrocode} % \end{variable} % @@ -674,31 +675,48 @@ % \subsection{Showing messages: low level mechanism} % % \begin{macro}{\@@_interrupt:Nnnn} +% \begin{macro}{\@@_no_more_text:nnnn} % The low-level interruption macro is rather opaque, unfortunately. % Depending on the availability of more information there is a choice % of how to set up the further help. We feed the extra help text and % the message itself to a wrapping auxiliary, in this order because we % must first setup \TeX{}'s \tn{errhelp} register before issuing an -% \tn{errmessage}. +% \tn{errmessage}. To deal with the various cases of critical or fatal +% errors with and without help text, there is a bit of argument-passing +% to do. % \begin{macrocode} -\cs_new_protected:Npn \@@_interrupt:Nnnn #1#2#3#4 +\cs_new_protected:Npn \@@_interrupt:NnnnN #1#2#3#4#5 { \str_set:Nx \l_@@_text_str { #1 {#2} } \str_set:Nx \l_@@_name_str { \msg_module_name:n {#2} } - \tl_if_empty:nTF {#4} + \cs_if_eq:cNTF + { \c_@@_more_text_prefix_tl #2 / #3 } + \@@_no_more_text:nnnn { - \@@_interrupt_wrap:nnn {#3} + \@@_interrupt_wrap:nnn + { \use:c { \c_@@_text_prefix_tl #2 / #3 } #4 } { \c_@@_continue_text_tl } - { \c_@@_no_info_text_tl } + { + \c_@@_no_info_text_tl + \tl_if_empty:NF #5 + { \\ \\ #5 } + } } { - \@@_interrupt_wrap:nnn {#3} + \@@_interrupt_wrap:nnn + { \use:c { \c_@@_text_prefix_tl #2 / #3 } #4 } { \c_@@_help_text_tl } - {#4} + { + \use:c { \c_@@_more_text_prefix_tl #2 / #3 } #4 + \tl_if_empty:NF #5 + { \\ \\ #5 } + } } } +\cs_new:Npn \@@_no_more_text:nnnn #1#2#3#4 { } % \end{macrocode} % \end{macro} +% \end{macro} % % \begin{macro}{\@@_interrupt_wrap:nnn} % \begin{macro}{\@@_interrupt_text:n, \@@_interrupt_more_text:n} @@ -730,13 +748,13 @@ { ~ } } { } \@@_interrupt_text:n - \iow_wrap:nnnN { \l_@@_tmp_tl \\ \\ #2 } { } { } + \iow_wrap:nnnN { \l_@@_internal_tl \\ \\ #2 } { } { } \@@_interrupt:n } \cs_new_protected:Npn \@@_interrupt_text:n #1 { \group_end: - \tl_set:Nn \l_@@_tmp_tl {#1} + \tl_set:Nn \l_@@_internal_tl {#1} } \cs_new_protected:Npn \@@_interrupt_more_text:n #1 { \exp_args:Nx \tex_errhelp:D { #1 \iow_newline: } } @@ -967,19 +985,27 @@ % \msg_fatal:nnxx , % \msg_fatal:nnx % } -% For fatal errors, after the error message \TeX{} bails out. +% \begin{macro}{\@@_fatal_exit:} +% For fatal errors, after the error message \TeX{} bails out. We force +% a bail out rather than using \tn{end} as this means it does not +% matter if we are in a context where normally the run cannot end. % \begin{macrocode} \@@_class_new:nn { fatal } { - \@@_interrupt:Nnnn - \msg_fatal_text:n - {#1} - { \use:c { \c_@@_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} } - { \c_@@_fatal_text_tl } - \tex_end:D + \@@_interrupt:NnnnN + \msg_fatal_text:n {#1} {#2} + { {#3} {#4} {#5} {#6} } + \c_@@_fatal_text_tl + \@@_fatal_exit: + } + \cs_new_protected:Npn \@@_fatal_exit: + { + \tex_batchmode:D + \tex_read:D -1 to \l_@@_internal_tl } % \end{macrocode} % \end{macro} +% \end{macro} % % \begin{macro} % { @@ -997,11 +1023,10 @@ % \begin{macrocode} \@@_class_new:nn { critical } { - \@@_interrupt:Nnnn - \msg_critical_text:n - {#1} - { \use:c { \c_@@_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} } - { \c_@@_critical_text_tl } + \@@_interrupt:NnnnN + \msg_critical_text:n {#1} {#2} + { {#3} {#4} {#5} {#6} } + \c_@@_critical_text_tl \tex_endinput:D } % \end{macrocode} @@ -1019,33 +1044,19 @@ % \msg_error:nnxx , % \msg_error:nnx % } -% \begin{macro}{\@@_error:cnnnnn, \@@_no_more_text:nnnn} % For an error, the interrupt routine is called. We check if there is % a \enquote{more text} by comparing that control sequence with a % permanently empty text. % \begin{macrocode} \@@_class_new:nn { error } { - \@@_error:cnnnnn - { \c_@@_more_text_prefix_tl #1 / #2 } - {#3} {#4} {#5} {#6} - { - \@@_interrupt:Nnnn - \msg_error_text:n - {#1} - { \use:c { \c_@@_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} } - } + \@@_interrupt:NnnnN + \msg_error_text:n {#1} {#2} + { {#3} {#4} {#5} {#6} } + \c_empty_tl } - \cs_new_protected:Npn \@@_error:cnnnnn #1#2#3#4#5#6 - { - \cs_if_eq:cNTF {#1} \@@_no_more_text:nnnn - { #6 { } } - { #6 { \use:c {#1} {#2} {#3} {#4} {#5} } } - } - \cs_new:Npn \@@_no_more_text:nnnn #1#2#3#4 { } % \end{macrocode} % \end{macro} -% \end{macro} % % \begin{macro} % { @@ -1215,13 +1226,13 @@ { \tl_if_empty:nF {#1} { \exp_args:No \iow_term:n { \use_none:n #1 } } - \tl_set:Nn \l_@@_tmp_tl {#2} + \tl_set:Nn \l_@@_internal_tl {#2} \__kernel_iow_with:Nnn \tex_newlinechar:D { 10 } { \__kernel_iow_with:Nnn \tex_errorcontextlines:D { -1 } { \tex_showtokens:D \exp_after:wN \exp_after:wN \exp_after:wN - { \exp_after:wN \l_@@_tmp_tl } + { \exp_after:wN \l_@@_internal_tl } } } } diff --git a/Master/texmf-dist/source/latex/l3kernel/l3names.dtx b/Master/texmf-dist/source/latex/l3kernel/l3names.dtx index ed464e73e3a..523a1718c35 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3names.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3names.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3prg.dtx b/Master/texmf-dist/source/latex/l3kernel/l3prg.dtx index 8380415d069..f52242e1351 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3prg.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3prg.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3prop.dtx b/Master/texmf-dist/source/latex/l3kernel/l3prop.dtx index 7658d804780..442e22b1333 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3prop.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3prop.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3quark.dtx b/Master/texmf-dist/source/latex/l3kernel/l3quark.dtx index 6a5b3f4cf5a..1d791ad9199 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3quark.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3quark.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % @@ -222,7 +222,7 @@ % \end{syntax} % Tests if \meta{token} contains only the marker % \cs{q_recursion_tail}, and if so uses -% \cs{use_none_delimit_by_q_recursion_stop:w} to terminate the +% \cs{use_i_delimit_by_q_recursion_stop:w} to terminate the % recursion that this belongs to. The % recursion input must include the marker tokens \cs{q_recursion_tail} % and \cs{q_recursion_stop} as the last two items. The \meta{insertion} @@ -237,7 +237,7 @@ % \end{syntax} % Tests if the \meta{token list} contains only % \cs{q_recursion_tail}, and if so uses -% \cs{use_none_delimit_by_q_recursion_stop:w} to terminate the +% \cs{use_i_delimit_by_q_recursion_stop:w} to terminate the % recursion that this belongs to. The % recursion input must include the marker tokens \cs{q_recursion_tail} % and \cs{q_recursion_stop} as the last two items. The \meta{insertion} diff --git a/Master/texmf-dist/source/latex/l3kernel/l3regex.dtx b/Master/texmf-dist/source/latex/l3kernel/l3regex.dtx index 7246e30ed7f..0b9b3a675ec 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3regex.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3regex.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % @@ -706,7 +706,7 @@ % \begin{itemize} % \item Shift arrays so that the useful information starts at % position~$1$. -% \item Only build \c{...} once. +% \item Only build |\c{...}| once. % \item Use arrays for the left and right state stacks when % compiling a regex. % \item Should \cs{__regex_action_free_group:n} only be used for greedy diff --git a/Master/texmf-dist/source/latex/l3kernel/l3seq.dtx b/Master/texmf-dist/source/latex/l3kernel/l3seq.dtx index 91051b576a4..e9d47de6a00 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3seq.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3seq.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3skip.dtx b/Master/texmf-dist/source/latex/l3kernel/l3skip.dtx index eded1d719ee..719fd507046 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3skip.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3skip.dtx @@ -44,7 +44,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % @@ -940,7 +940,7 @@ % \cs{muskip_sub:Nn} \meta{muskip} \Arg{muskip expression} % \end{syntax} % Subtracts the result of the \meta{muskip expression} from the -% current content of the \meta{skip}. +% current content of the \meta{muskip}. % \end{function} % % \section{Using \texttt{muskip} expressions and variables} diff --git a/Master/texmf-dist/source/latex/l3kernel/l3sort.dtx b/Master/texmf-dist/source/latex/l3kernel/l3sort.dtx index 9b2b0fdc1f8..c467a056590 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3sort.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3sort.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3str-convert.dtx b/Master/texmf-dist/source/latex/l3kernel/l3str-convert.dtx new file mode 100644 index 00000000000..90e625f61b0 --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3str-convert.dtx @@ -0,0 +1,3471 @@ +% \iffalse meta-comment +% +%% File: l3str-convert.dtx +% +% Copyright (C) 2013-2019 The LaTeX3 Project +% +% It may be distributed and/or modified under the conditions of the +% LaTeX Project Public License (LPPL), either version 1.3c of this +% license or (at your option) any later version. The latest version +% of this license is in the file +% +% https://www.latex-project.org/lppl.txt +% +% This file is part of the "l3kernel bundle" (The Work in LPPL) +% and all files in that bundle must be distributed together. +% +% ----------------------------------------------------------------------- +% +% The development version of the bundle can be found at +% +% https://github.com/latex3/latex3 +% +% for those people who are interested. +% +%<*driver> +\documentclass[full,kernel]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +% +% \fi +% +% +% \title{^^A +% The \textsf{l3str-convert} package: string encoding conversions^^A +% } +% +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released 2019-07-01} +% +% \maketitle +% +% \begin{documentation} +% +% \section{Encoding and escaping schemes} +% +% Traditionally, string encodings only specify how strings of characters +% should be stored as bytes. However, the resulting lists of bytes are +% often to be used in contexts where only a restricted subset of bytes +% are permitted (\emph{e.g.}, \textsc{pdf} string objects, +% \textsc{url}s). Hence, storing a string of characters is done in two +% steps. +% \begin{itemize} +% \item The code points (\enquote{character codes}) are expressed as +% bytes following a given \enquote{encoding}. This can be +% \textsc{utf-16}, \textsc{iso 8859-1}, \emph{etc.} See +% Table~\ref{tab:encodings} for a list of supported +% encodings.\footnote{Encodings and escapings will be added as they +% are requested.} +% \item Bytes are translated to \TeX{} tokens through a given +% \enquote{escaping}. Those are defined for the most part by the +% \texttt{pdf} file format. See Table~\ref{tab:escapings} for a +% list of escaping methods supported.\footnotemark +% \end{itemize} +% +% \begin{table}\centering +% \caption{\label{tab:encodings}Supported encodings. +% Non-alphanumeric characters are ignored, +% and capital letters are lower-cased +% before searching for the encoding in this list.} +% \begin{tabular}{cc} +% \toprule +% \meta{Encoding} & description \\ +% \midrule +% \texttt{utf8} & \textsc{utf-8} \\ +% \texttt{utf16} & \textsc{utf-16}, with byte-order mark \\ +% \texttt{utf16be} & \textsc{utf-16}, big-endian \\ +% \texttt{utf16le} & \textsc{utf-16}, little-endian \\ +% \texttt{utf32} & \textsc{utf-32}, with byte-order mark \\ +% \texttt{utf32be} & \textsc{utf-32}, big-endian \\ +% \texttt{utf32le} & \textsc{utf-32}, little-endian \\ +% \midrule +% \texttt{iso88591}, \texttt{latin1} & \textsc{iso 8859-1} \\ +% \texttt{iso88592}, \texttt{latin2} & \textsc{iso 8859-2} \\ +% \texttt{iso88593}, \texttt{latin3} & \textsc{iso 8859-3} \\ +% \texttt{iso88594}, \texttt{latin4} & \textsc{iso 8859-4} \\ +% \texttt{iso88595} & \textsc{iso 8859-5} \\ +% \texttt{iso88596} & \textsc{iso 8859-6} \\ +% \texttt{iso88597} & \textsc{iso 8859-7} \\ +% \texttt{iso88598} & \textsc{iso 8859-8} \\ +% \texttt{iso88599}, \texttt{latin5} & \textsc{iso 8859-9} \\ +% \texttt{iso885910}, \texttt{latin6} & \textsc{iso 8859-10} \\ +% \texttt{iso885911} & \textsc{iso 8859-11} \\ +% \texttt{iso885913}, \texttt{latin7} & \textsc{iso 8859-13} \\ +% \texttt{iso885914}, \texttt{latin8} & \textsc{iso 8859-14} \\ +% \texttt{iso885915}, \texttt{latin9} & \textsc{iso 8859-15} \\ +% \texttt{iso885916}, \texttt{latin10} & \textsc{iso 8859-16} \\ +% \midrule +% \texttt{clist} & comma-list of integers \\ +% \meta{empty} & native (Unicode) string \\ +% \bottomrule +% \end{tabular} +% \end{table} +% +% \begin{table}\centering +% \caption{\label{tab:escapings}Supported escapings. +% Non-alphanumeric characters are ignored, +% and capital letters are lower-cased +% before searching for the escaping in this list.} +% \begin{tabular}{cc} +% \toprule +% \meta{Escaping} & description \\ +% \midrule +% \texttt{bytes}, or empty +% & arbitrary bytes \\ +% \texttt{hex}, \texttt{hexadecimal} +% & byte $=$ two hexadecimal digits \\ +% \texttt{name} +% & see \tn{pdfescapename} \\ +% \texttt{string} +% & see \tn{pdfescapestring} \\ +% \texttt{url} +% & encoding used in \textsc{url}s \\ +% \bottomrule +% \end{tabular} +% \end{table} +% +% \section{Conversion functions} +% +% \begin{function}{\str_set_convert:Nnnn, \str_gset_convert:Nnnn} +% \begin{syntax} +% \cs{str_set_convert:Nnnn} \meta{str~var} \Arg{string} \Arg{name~1} \Arg{name~2} +% \end{syntax} +% This function converts the \meta{string} from the encoding given by +% \meta{name~1} to the encoding given by \meta{name~2}, and stores the +% result in the \meta{str~var}. Each \meta{name} can have the form +% \meta{encoding} or \meta{encoding}\texttt{/}\meta{escaping}, where +% the possible values of \meta{encoding} and \meta{escaping} are given +% in Tables~\ref{tab:encodings} and~\ref{tab:escapings}, respectively. +% The default escaping is to input and output bytes directly. The +% special case of an empty \meta{name} indicates the use of +% \enquote{native} strings, 8-bit for \pdfTeX{}, and Unicode strings +% for the other two engines. +% +% For example, +% \begin{verbatim} +% \str_set_convert:Nnnn \l_foo_str { Hello! } { } { utf16/hex } +% \end{verbatim} +% results in the variable \cs{l_foo_str} holding the string +% \texttt{FEFF00480065006C006C006F0021}. This is obtained by +% converting each character in the (native) string \texttt{Hello!} to +% the \textsc{utf-16} encoding, and expressing each byte as a pair of +% hexadecimal digits. Note the presence of a (big-endian) byte order +% mark \hexnum{FEFF}, which can be avoided by specifying the encoding +% \texttt{utf16be/hex}. +% +% An error is raised if the \meta{string} is not valid according to +% the \meta{escaping~1} and \meta{encoding~1}, or if it cannot be +% reencoded in the \meta{encoding~2} and \meta{escaping~2} (for +% instance, if a character does not exist in the \meta{encoding~2}). +% Erroneous input is replaced by the Unicode replacement character +% \hexnum{FFFD}, and characters which cannot be reencoded are replaced +% by either the replacement character \hexnum{FFFD} if it exists in +% the \meta{encoding~2}, or an encoding-specific replacement +% character, or the question mark character. +% \end{function} +% +% \begin{function}[TF]{\str_set_convert:Nnnn, \str_gset_convert:Nnnn} +% \begin{syntax} +% \cs{str_set_convert:NnnnTF} \meta{str~var} \Arg{string} \Arg{name~1} \Arg{name~2} \Arg{true code} \Arg{false code} +% \end{syntax} +% As \cs{str_set_convert:Nnnn}, converts the \meta{string} from the +% encoding given by \meta{name~1} to the encoding given by +% \meta{name~2}, and assigns the result to \meta{str~var}. Contrarily +% to \cs{str_set_convert:Nnnn}, the conditional variant does not raise +% errors in case the \meta{string} is not valid according to the +% \meta{name~1} encoding, or cannot be expressed in the \meta{name~2} +% encoding. Instead, the \meta{false code} is performed. +% \end{function} +% +% \section{Creating $8$-bit mappings} +% +% \begin{function}{\str_declare_eight_bit_encoding:nnn} +% \begin{syntax} +% \cs{str_declare_eight_bit_encoding:nnn} \Arg{name} \Arg{mapping} \Arg{missing} +% \end{syntax} +% Declares the encoding \meta{name} to map bytes to Unicode +% characters according to the \meta{mapping}, and map those bytes +% which are not mentioned in the \meta{mapping} either to the +% replacement character (if they appear in \meta{missing}), or to +% themselves. +% \end{function} +% +% \section{Possibilities, and things to do} +% +% Encoding/escaping-related tasks. +% \begin{itemize} +% \item In \XeTeX{}/\LuaTeX{}, would it be better to use the +% |^^^^....| approach to build a string from a given list of +% character codes? Namely, within a group, assign |0-9a-f| and all +% characters we want to category ``other'', then assign~|^| the +% category superscript, and use \tn{scantokens}. +% \item Change \cs{str_set_convert:Nnnn} to expand its last two +% arguments. +% \item Describe the internal format in the code comments. Refuse code +% points in $[\hexnum{D800}, \hexnum{DFFF}]$ in the internal +% representation? +% \item Add documentation about each encoding and escaping method, and +% add examples. +% \item The \texttt{hex} unescaping should raise an error for +% odd-token count strings. +% \item Decide what bytes should be escaped in the \texttt{url} +% escaping. Perhaps |!'()*-./0123456789_| are safe, and all other +% characters should be escaped? +% \item Automate generation of 8-bit mapping files. +% \item Change the framework for 8-bit encodings: for decoding from +% 8-bit to Unicode, use $256$ integer registers; for encoding, use a +% tree-box. +% \item More encodings (see Heiko's \pkg{stringenc}). CESU? +% \item More escapings: \textsc{ascii85}, shell escapes, lua escapes, +% \emph{etc.}? +% \end{itemize} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3str-convert} implementation} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% \begin{macrocode} +%<@@=str> +% \end{macrocode} +% +% \subsection{Helpers} +% +% \subsubsection{Variables and constants} +% +% \begin{macro}{\@@_tmp:w} +% \begin{variable}{\l_@@_internal_int} +% \begin{variable}{\l_@@_internal_tl} +% Internal scratch space for some functions. +% \begin{macrocode} +\cs_new_protected:Npn \@@_tmp:w { } +\tl_new:N \l_@@_internal_tl +\int_new:N \l_@@_internal_int +% \end{macrocode} +% \end{variable} +% \end{variable} +% \end{macro} +% +% \begin{variable}{\g_@@_result_tl} +% The \cs{g_@@_result_tl} variable is used to hold the result of +% various internal string operations (mostly conversions) which are +% typically performed in a group. The variable is global so that it +% remains defined outside the group, to be assigned to a user-provided +% variable. +% \begin{macrocode} +\tl_new:N \g_@@_result_tl +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\c_@@_replacement_char_int} +% When converting, invalid bytes are replaced by the Unicode +% replacement character \hexnum{FFFD}. +% \begin{macrocode} +\int_const:Nn \c_@@_replacement_char_int { "FFFD } +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\c_@@_max_byte_int} +% The maximal byte number. +% \begin{macrocode} +\int_const:Nn \c_@@_max_byte_int { 255 } +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\g_@@_alias_prop} +% To avoid needing one file per encoding/escaping alias, we keep track +% of those in a property list. +% \begin{macrocode} +\prop_new:N \g_@@_alias_prop +\prop_gput:Nnn \g_@@_alias_prop { latin1 } { iso88591 } +\prop_gput:Nnn \g_@@_alias_prop { latin2 } { iso88592 } +\prop_gput:Nnn \g_@@_alias_prop { latin3 } { iso88593 } +\prop_gput:Nnn \g_@@_alias_prop { latin4 } { iso88594 } +\prop_gput:Nnn \g_@@_alias_prop { latin5 } { iso88599 } +\prop_gput:Nnn \g_@@_alias_prop { latin6 } { iso885910 } +\prop_gput:Nnn \g_@@_alias_prop { latin7 } { iso885913 } +\prop_gput:Nnn \g_@@_alias_prop { latin8 } { iso885914 } +\prop_gput:Nnn \g_@@_alias_prop { latin9 } { iso885915 } +\prop_gput:Nnn \g_@@_alias_prop { latin10 } { iso885916 } +\prop_gput:Nnn \g_@@_alias_prop { utf16le } { utf16 } +\prop_gput:Nnn \g_@@_alias_prop { utf16be } { utf16 } +\prop_gput:Nnn \g_@@_alias_prop { utf32le } { utf32 } +\prop_gput:Nnn \g_@@_alias_prop { utf32be } { utf32 } +\prop_gput:Nnn \g_@@_alias_prop { hexadecimal } { hex } +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\g_@@_error_bool} +% In conversion functions with a built-in conditional, errors are not +% reported directly to the user, but the information is collected in +% this boolean, used at the end to decide on which branch of the +% conditional to take. +% \begin{macrocode} +\bool_new:N \g_@@_error_bool +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{str_byte, str_error} +% Conversions from one \meta{encoding}/\meta{escaping} pair to another +% are done within \texttt{x}-expanding assignments. Errors are +% signalled by raising the relevant flag. +% \begin{macrocode} +\flag_new:n { str_byte } +\flag_new:n { str_error } +% \end{macrocode} +% \end{variable} +% +% \subsection{String conditionals} +% +% \begin{macro}[EXP]{\@@_if_contains_char:NNT, \@@_if_contains_char:NNTF} +% \begin{macro}[EXP]{\@@_if_contains_char:nNTF} +% \begin{macro}[EXP]{\@@_if_contains_char_aux:NN} +% \begin{macro}[EXP]{\@@_if_contains_char_true:} +% \begin{syntax} +% \cs{@@_if_contains_char:nNTF} \Arg{token list} \meta{char} +% \end{syntax} +% Expects the \meta{token list} to be an \meta{other string}: the +% caller is responsible for ensuring that no (too-)special catcodes +% remain. Spaces with catcode $10$ are ignored. +% Loop over the characters of the string, comparing character codes. +% The loop is broken if character codes match. Otherwise we return +% \enquote{false}. +% \begin{macrocode} +\prg_new_conditional:Npnn \@@_if_contains_char:NN #1#2 { T , TF } + { + \exp_after:wN \@@_if_contains_char_aux:NN \exp_after:wN #2 + #1 { \prg_break:n { ? \fi: } } + \prg_break_point: + \prg_return_false: + } +\prg_new_conditional:Npnn \@@_if_contains_char:nN #1#2 { TF } + { + \@@_if_contains_char_aux:NN #2 #1 { \prg_break:n { ? \fi: } } + \prg_break_point: + \prg_return_false: + } +\cs_new:Npn \@@_if_contains_char_aux:NN #1#2 + { + \if_charcode:w #1 #2 + \exp_after:wN \@@_if_contains_char_true: + \fi: + \@@_if_contains_char_aux:NN #1 + } +\cs_new:Npn \@@_if_contains_char_true: + { \prg_break:n { \prg_return_true: \use_none:n } } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}[rEXP]{\@@_octal_use:NTF} +% \begin{syntax} +% \cs{@@_octal_use:NTF} \meta{token} \Arg{true code} \Arg{false code} +% \end{syntax} +% If the \meta{token} is an octal digit, it is left in the input +% stream, \emph{followed} by the \meta{true code}. Otherwise, the +% \meta{false code} is left in the input stream. +% \begin{texnote} +% This function will fail if the escape character is an octal +% digit. We are thus careful to set the escape character to a known +% value before using it. +% \end{texnote} +% \TeX{} dutifully detects octal digits for us: if |#1| is an octal +% digit, then the right-hand side of the comparison is |'1#1|, greater +% than $1$. Otherwise, the right-hand side stops as |'1|, and the +% conditional takes the \texttt{false} branch. +% \begin{macrocode} +\prg_new_conditional:Npnn \@@_octal_use:N #1 { TF } + { + \if_int_compare:w 1 < '1 \token_to_str:N #1 \exp_stop_f: + #1 \prg_return_true: + \else: + \prg_return_false: + \fi: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[rEXP]{\@@_hexadecimal_use:NTF} +% \TeX{} detects uppercase hexadecimal digits for us (see +% \cs{@@_octal_use:NTF}), but not the lowercase letters, which we +% need to detect and replace by their uppercase counterpart. +% \begin{macrocode} +\prg_new_conditional:Npnn \@@_hexadecimal_use:N #1 { TF } + { + \if_int_compare:w 1 < "1 \token_to_str:N #1 \exp_stop_f: + #1 \prg_return_true: + \else: + \if_case:w \int_eval:n { \exp_after:wN ` \token_to_str:N #1 - `a } + A + \or: B + \or: C + \or: D + \or: E + \or: F + \else: + \prg_return_false: + \exp_after:wN \use_none:n + \fi: + \prg_return_true: + \fi: + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Conversions} +% +% \subsubsection{Producing one byte or character} +% +% \begin{variable}{\c_@@_byte_0_tl, \c_@@_byte_1_tl, \c_@@_byte_255_tl} +% \begin{variable}{\c_@@_byte_-1_tl} +% For each integer $N$ in the range $[0,255]$, we create a constant +% token list which holds three character tokens with category code +% other: the character with character code $N$, followed by the +% representation of $N$ as two hexadecimal digits. The value $-1$ is +% given a default token list which ensures that later functions give +% an empty result for the input $-1$. +% \begin{macrocode} +\group_begin: + \tl_set:Nx \l_@@_internal_tl { \tl_to_str:n { 0123456789ABCDEF } } + \tl_map_inline:Nn \l_@@_internal_tl + { + \tl_map_inline:Nn \l_@@_internal_tl + { + \tl_const:cx { c_@@_byte_ \int_eval:n {"#1##1} _tl } + { \char_generate:nn { "#1##1 } { 12 } #1 ##1 } + } + } +\group_end: +\tl_const:cn { c_@@_byte_-1_tl } { { } \use_none:n { } } +% \end{macrocode} +% \end{variable} +% \end{variable} +% +% \begin{macro}[EXP]{\@@_output_byte:n} +% \begin{macro}[EXP]{\@@_output_byte:w} +% \begin{macro}[EXP]{\@@_output_hexadecimal:n} +% \begin{macro}[EXP]{\@@_output_end:} +% Those functions must be used carefully: feeding them a value outside +% the range $[-1,255]$ will attempt to use the undefined token list +% variable \cs{c_@@_byte_\meta{number}_tl}. Assuming that the +% argument is in the right range, we expand the corresponding token +% list, and pick either the byte (first token) or the hexadecimal +% representations (second and third tokens). The value $-1$ produces +% an empty result in both cases. +% \begin{macrocode} +\cs_new:Npn \@@_output_byte:n #1 + { \@@_output_byte:w #1 \@@_output_end: } +\cs_new:Npn \@@_output_byte:w + { + \exp_after:wN \exp_after:wN + \exp_after:wN \use_i:nnn + \cs:w c_@@_byte_ \int_eval:w + } +\cs_new:Npn \@@_output_hexadecimal:n #1 + { + \exp_after:wN \exp_after:wN + \exp_after:wN \use_none:n + \cs:w c_@@_byte_ \int_eval:n {#1} _tl \cs_end: + } +\cs_new:Npn \@@_output_end: + { \scan_stop: _tl \cs_end: } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}[rEXP]{\@@_output_byte_pair_be:n} +% \begin{macro}[rEXP]{\@@_output_byte_pair_le:n} +% \begin{macro}[rEXP]{\@@_output_byte_pair:nnN} +% Convert a number in the range $[0,65535]$ to a pair of bytes, either +% big-endian or little-endian. +% \begin{macrocode} +\cs_new:Npn \@@_output_byte_pair_be:n #1 + { + \exp_args:Nf \@@_output_byte_pair:nnN + { \int_div_truncate:nn { #1 } { "100 } } {#1} \use:nn + } +\cs_new:Npn \@@_output_byte_pair_le:n #1 + { + \exp_args:Nf \@@_output_byte_pair:nnN + { \int_div_truncate:nn { #1 } { "100 } } {#1} \use_ii_i:nn + } +\cs_new:Npn \@@_output_byte_pair:nnN #1#2#3 + { + #3 + { \@@_output_byte:n { #1 } } + { \@@_output_byte:n { #2 - #1 * "100 } } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsubsection{Mapping functions for conversions} +% +% \begin{macro}{\@@_convert_gmap:N} +% \begin{macro}[rEXP]{\@@_convert_gmap_loop:NN} +% This maps the function |#1| over all characters in +% \cs{g_@@_result_tl}, which should be a byte string in most cases, +% sometimes a native string. +% \begin{macrocode} +\cs_new_protected:Npn \@@_convert_gmap:N #1 + { + \tl_gset:Nx \g_@@_result_tl + { + \exp_after:wN \@@_convert_gmap_loop:NN + \exp_after:wN #1 + \g_@@_result_tl { ? \prg_break: } + \prg_break_point: + } + } +\cs_new:Npn \@@_convert_gmap_loop:NN #1#2 + { + \use_none:n #2 + #1#2 + \@@_convert_gmap_loop:NN #1 + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\@@_convert_gmap_internal:N} +% \begin{macro}[rEXP]{\@@_convert_gmap_internal_loop:Nw} +% This maps the function |#1| over all character codes in +% \cs{g_@@_result_tl}, which must be in the internal representation. +% \begin{macrocode} +\cs_new_protected:Npn \@@_convert_gmap_internal:N #1 + { + \tl_gset:Nx \g_@@_result_tl + { + \exp_after:wN \@@_convert_gmap_internal_loop:Nww + \exp_after:wN #1 + \g_@@_result_tl \s__tl \q_stop \prg_break: \s__tl + \prg_break_point: + } + } +\cs_new:Npn \@@_convert_gmap_internal_loop:Nww #1 #2 \s__tl #3 \s__tl + { + \use_none_delimit_by_q_stop:w #3 \q_stop + #1 {#3} + \@@_convert_gmap_internal_loop:Nww #1 + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsubsection{Error-reporting during conversion} +% +% \begin{macro}{\@@_if_flag_error:nnx} +% \begin{macro}{\@@_if_flag_no_error:nnx} +% When converting using the function \cs{str_set_convert:Nnnn}, errors +% should be reported to the user after each step in the +% conversion. Errors are signalled by raising some flag (typically +% \texttt{@@_error}), so here we test that flag: if it is raised, +% give the user an error, otherwise remove the arguments. On the other +% hand, in the conditional functions \cs{str_set_convert:NnnnTF}, +% errors should be suppressed. This is done by changing +% \cs{@@_if_flag_error:nnx} into \cs{@@_if_flag_no_error:nnx} +% locally. +% \begin{macrocode} +\cs_new_protected:Npn \@@_if_flag_error:nnx #1 + { + \flag_if_raised:nTF {#1} + { \__kernel_msg_error:nnx { str } } + { \use_none:nn } + } +\cs_new_protected:Npn \@@_if_flag_no_error:nnx #1#2#3 + { \flag_if_raised:nT {#1} { \bool_gset_true:N \g_@@_error_bool } } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[rEXP]{\@@_if_flag_times:nT} +% At the end of each conversion step, we raise all relevant errors as +% one error message, built on the fly. The height of each flag +% indicates how many times a given error was encountered. This +% function prints |#2| followed by the number of occurrences of an +% error if it occurred, nothing otherwise. +% \begin{macrocode} +\cs_new:Npn \@@_if_flag_times:nT #1#2 + { \flag_if_raised:nT {#1} { #2~(x \flag_height:n {#1} ) } } +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Framework for conversions} +% +% Most functions in this module expect to be working with +% \enquote{native} strings. Strings can also be stored as bytes, in one +% of many encodings, for instance \textsc{utf8}. The bytes themselves +% can be expressed in various ways in terms of \TeX{} tokens, for +% instance as pairs of hexadecimal digits. The questions of going from +% arbitrary Unicode code points to bytes, and from bytes to tokens are +% mostly independent. +% +% Conversions are done in four steps: +% \begin{itemize} +% \item \enquote{unescape} produces a string of bytes; +% \item \enquote{decode} takes in a string of bytes, and converts it +% to a list of Unicode characters in an internal representation, +% with items of the form +% \begin{quote} +% \meta{bytes} \cs{s__tl} \meta{Unicode code point} \cs{s__tl} +% \end{quote} +% where we have collected the \meta{bytes} which combined to form +% this particular Unicode character, and the \meta{Unicode code +% point} is in the range $[0,\hexnum{10FFFF}]$. +% \item \enquote{encode} encodes the internal list of code points as a +% byte string in the new encoding; +% \item \enquote{escape} escapes bytes as requested. +% \end{itemize} +% The process is modified in case one of the encoding is empty (or the +% conversion function has been set equal to the empty encoding because +% it was not found): then the unescape or escape step is ignored, and +% the decode or encode steps work on tokens instead of bytes. Otherwise, +% each step must ensure that it passes a correct byte string or internal +% string to the next step. +% +% \begin{macro}{\str_set_convert:Nnnn, \str_gset_convert:Nnnn} +% \begin{macro}[TF]{\str_set_convert:Nnnn, \str_gset_convert:Nnnn} +% \begin{macro}{\@@_convert:nNNnnn} +% The input string is stored in \cs{g_@@_result_tl}, then we: +% unescape and decode; encode and escape; exit the group and store the +% result in the user's variable. The various conversion functions all +% act on \cs{g_@@_result_tl}. Errors are silenced for the conditional +% functions by redefining \cs{@@_if_flag_error:nnx} locally. +% \begin{macrocode} +\cs_new_protected:Npn \str_set_convert:Nnnn + { \@@_convert:nNNnnn { } \tl_set_eq:NN } +\cs_new_protected:Npn \str_gset_convert:Nnnn + { \@@_convert:nNNnnn { } \tl_gset_eq:NN } +\prg_new_protected_conditional:Npnn + \str_set_convert:Nnnn #1#2#3#4 { T , F , TF } + { + \bool_gset_false:N \g_@@_error_bool + \@@_convert:nNNnnn + { \cs_set_eq:NN \@@_if_flag_error:nnx \@@_if_flag_no_error:nnx } + \tl_set_eq:NN #1 {#2} {#3} {#4} + \bool_if:NTF \g_@@_error_bool \prg_return_false: \prg_return_true: + } +\prg_new_protected_conditional:Npnn + \str_gset_convert:Nnnn #1#2#3#4 { T , F , TF } + { + \bool_gset_false:N \g_@@_error_bool + \@@_convert:nNNnnn + { \cs_set_eq:NN \@@_if_flag_error:nnx \@@_if_flag_no_error:nnx } + \tl_gset_eq:NN #1 {#2} {#3} {#4} + \bool_if:NTF \g_@@_error_bool \prg_return_false: \prg_return_true: + } +\cs_new_protected:Npn \@@_convert:nNNnnn #1#2#3#4#5#6 + { + \group_begin: + #1 + \tl_gset:Nx \g_@@_result_tl { \__kernel_str_to_other_fast:n {#4} } + \exp_after:wN \@@_convert:wwwnn + \tl_to_str:n {#5} /// \q_stop + { decode } { unescape } + \prg_do_nothing: + \@@_convert_decode_: + \exp_after:wN \@@_convert:wwwnn + \tl_to_str:n {#6} /// \q_stop + { encode } { escape } + \use_ii_i:nn + \@@_convert_encode_: + \group_end: + #2 #3 \g_@@_result_tl + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\@@_convert:wwwnn} +% \begin{macro}{\@@_convert:NNnNN} +% The task of \cs{@@_convert:wwwnn} is to split +% \meta{encoding}/\meta{escaping} pairs into their components, |#1| +% and |#2|. Calls to \cs{@@_convert:nnn} ensure that the +% corresponding conversion functions are defined. The third auxiliary +% does the main work. +% \begin{itemize} +% \item |#1| is the encoding conversion function; +% \item |#2| is the escaping function; +% \item |#3| is the escaping name for use in an error message; +% \item |#4| is \cs{prg_do_nothing:} for unescaping/decoding, and +% \cs{use_ii_i:nn} for encoding/escaping; +% \item |#5| is the default encoding function (either +% \enquote{decode} or \enquote{encode}), for which there should be +% no escaping. +% \end{itemize} +% Let us ignore the native encoding for a second. In the +% unescaping/decoding phase, we want to do |#2#1| in this order, and +% in the encoding/escaping phase, the order should be reversed: +% |#4#2#1| does exactly that. If one of the encodings is the default +% (native), then the escaping should be ignored, with an error if any +% was given, and only the encoding, |#1|, should be performed. +% \begin{macrocode} +\cs_new_protected:Npn \@@_convert:wwwnn + #1 / #2 // #3 \q_stop #4#5 + { + \@@_convert:nnn {enc} {#4} {#1} + \@@_convert:nnn {esc} {#5} {#2} + \exp_args:Ncc \@@_convert:NNnNN + { @@_convert_#4_#1: } { @@_convert_#5_#2: } {#2} + } +\cs_new_protected:Npn \@@_convert:NNnNN #1#2#3#4#5 + { + \if_meaning:w #1 #5 + \tl_if_empty:nF {#3} + { \__kernel_msg_error:nnx { str } { native-escaping } {#3} } + #1 + \else: + #4 #2 #1 + \fi: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\@@_convert:nnn} +% \begin{macro}{\@@_convert:nnnn} +% The arguments of \cs{@@_convert:nnn} are: \texttt{enc} or +% \texttt{esc}, used to build filenames, the type of the conversion +% (unescape, decode, encode, escape), and the encoding or escaping +% name. If the function is already defined, no need to do anything. +% Otherwise, filter out all non-alphanumerics in the name, and +% lowercase it. Feed that, and the same three arguments, to +% \cs{@@_convert:nnnn}. The task is then to make sure that the +% conversion function |#3_#1| corresponding to the type |#3| and +% filtered name |#1| is defined, then set our initial conversion +% function |#3_#4| equal to that. +% +% How do we get the |#3_#1| conversion to be defined if it isn't? +% Two main cases. +% +% First, if |#1| is a key in \cs{g_@@_alias_prop}, then the value +% \cs{l_@@_internal_tl} tells us what file to load. Loading is +% skipped if the file was already read, \emph{i.e.}, if the conversion +% command based on \cs{l_@@_internal_tl} already exists. Otherwise, +% try to load the file; if that fails, there is an error, use the +% default empty name instead. +% +% Second, |#1| may be absent from the property list. The +% \cs{cs_if_exist:cF} test is automatically false, and we search for a +% file defining the encoding or escaping |#1| (this should allow +% third-party \texttt{.def} files). If the file is not found, there is +% an error, use the default empty name instead. +% +% In all cases, the conversion based on \cs{l_@@_internal_tl} is +% defined, so we can set the |#3_#1| function equal to that. In some +% cases (\emph{e.g.}, \texttt{utf16be}), the |#3_#1| function is +% actually defined within the file we just loaded, and it is different +% from the \cs{l_@@_internal_tl}-based function: we mustn't clobber +% that different definition. +% \begin{macrocode} +\cs_new_protected:Npn \@@_convert:nnn #1#2#3 + { + \cs_if_exist:cF { @@_convert_#2_#3: } + { + \exp_args:Nx \@@_convert:nnnn + { \@@_convert_lowercase_alphanum:n {#3} } + {#1} {#2} {#3} + } + } +\cs_new_protected:Npn \@@_convert:nnnn #1#2#3#4 + { + \cs_if_exist:cF { @@_convert_#3_#1: } + { + \prop_get:NnNF \g_@@_alias_prop {#1} \l_@@_internal_tl + { \tl_set:Nn \l_@@_internal_tl {#1} } + \cs_if_exist:cF { @@_convert_#3_ \l_@@_internal_tl : } + { + \file_if_exist:nTF { l3str-#2- \l_@@_internal_tl .def } + { + \group_begin: + \@@_load_catcodes: + \file_input:n { l3str-#2- \l_@@_internal_tl .def } + \group_end: + } + { + \tl_clear:N \l_@@_internal_tl + \__kernel_msg_error:nnxx { str } { unknown-#2 } {#4} {#1} + } + } + \cs_if_exist:cF { @@_convert_#3_#1: } + { + \cs_gset_eq:cc { @@_convert_#3_#1: } + { @@_convert_#3_ \l_@@_internal_tl : } + } + } + \cs_gset_eq:cc { @@_convert_#3_#4: } { @@_convert_#3_#1: } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[rEXP]{\@@_convert_lowercase_alphanum:n} +% \begin{macro}[rEXP]{\@@_convert_lowercase_alphanum_loop:N} +% This function keeps only letters and digits, with upper case letters +% converted to lower case. +% \begin{macrocode} +\cs_new:Npn \@@_convert_lowercase_alphanum:n #1 + { + \exp_after:wN \@@_convert_lowercase_alphanum_loop:N + \tl_to_str:n {#1} { ? \prg_break: } + \prg_break_point: + } +\cs_new:Npn \@@_convert_lowercase_alphanum_loop:N #1 + { + \use_none:n #1 + \if_int_compare:w `#1 > `Z \exp_stop_f: + \if_int_compare:w `#1 > `z \exp_stop_f: \else: + \if_int_compare:w `#1 < `a \exp_stop_f: \else: + #1 + \fi: + \fi: + \else: + \if_int_compare:w `#1 < `A \exp_stop_f: + \if_int_compare:w 1 < 1#1 \exp_stop_f: + #1 + \fi: + \else: + \@@_output_byte:n { `#1 + `a - `A } + \fi: + \fi: + \@@_convert_lowercase_alphanum_loop:N + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\@@_load_catcodes:} +% Since encoding files may be loaded at arbitrary places in a \TeX{} +% document, including within verbatim mode, we set the catcodes of all +% characters appearing in any encoding definition file. +% \begin{macrocode} +\cs_new_protected:Npn \@@_load_catcodes: + { + \char_set_catcode_escape:N \\ + \char_set_catcode_group_begin:N \{ + \char_set_catcode_group_end:N \} + \char_set_catcode_math_toggle:N \$ + \char_set_catcode_alignment:N \& + \char_set_catcode_parameter:N \# + \char_set_catcode_math_superscript:N \^ + \char_set_catcode_ignore:N \ % + \char_set_catcode_space:N \~ + \tl_map_function:nN { abcdefghijklmnopqrstuvwxyz_:ABCDEFILNPSTUX } + \char_set_catcode_letter:N + \tl_map_function:nN { 0123456789"'?*+-.(),`!/<>[];= } + \char_set_catcode_other:N + \char_set_catcode_comment:N \% + \int_set:Nn \tex_endlinechar:D {32} + } +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Byte unescape and escape} +% +% Strings of bytes may need to be stored in auxiliary files in safe +% \enquote{escaping} formats. Each such escaping is only loaded as +% needed. By default, on input any non-byte is filtered out, while the +% output simply consists in letting bytes through. +% +% \begin{macro}[rEXP]{\@@_filter_bytes:n} +% \begin{macro}[rEXP]{\@@_filter_bytes_aux:N} +% In the case of 8-bit engines, every character is a byte. For +% Unicode-aware engines, test the character code; non-bytes cause us +% to raise the flag \texttt{str_byte}. Spaces have already been given +% the correct category code when this function is called. +% \begin{macrocode} +\bool_lazy_any:nTF + { + \sys_if_engine_luatex_p: + \sys_if_engine_xetex_p: + } + { + \cs_new:Npn \@@_filter_bytes:n #1 + { + \@@_filter_bytes_aux:N #1 + { ? \prg_break: } + \prg_break_point: + } + \cs_new:Npn \@@_filter_bytes_aux:N #1 + { + \use_none:n #1 + \if_int_compare:w `#1 < 256 \exp_stop_f: + #1 + \else: + \flag_raise:n { str_byte } + \fi: + \@@_filter_bytes_aux:N + } + } + { \cs_new_eq:NN \@@_filter_bytes:n \use:n } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\@@_convert_unescape_:} +% \begin{macro}{\@@_convert_unescape_bytes:} +% The simplest unescaping method removes non-bytes from +% \cs{g_@@_result_tl}. +% \begin{macrocode} +\bool_lazy_any:nTF + { + \sys_if_engine_luatex_p: + \sys_if_engine_xetex_p: + } + { + \cs_new_protected:Npn \@@_convert_unescape_: + { + \flag_clear:n { str_byte } + \tl_gset:Nx \g_@@_result_tl + { \exp_args:No \@@_filter_bytes:n \g_@@_result_tl } + \@@_if_flag_error:nnx { str_byte } { non-byte } { bytes } + } + } + { \cs_new_protected:Npn \@@_convert_unescape_: { } } +\cs_new_eq:NN \@@_convert_unescape_bytes: \@@_convert_unescape_: +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\@@_convert_escape_:} +% \begin{macro}{\@@_convert_escape_bytes:} +% The simplest form of escape leaves the bytes from the previous step +% of the conversion unchanged. +% \begin{macrocode} +\cs_new_protected:Npn \@@_convert_escape_: { } +\cs_new_eq:NN \@@_convert_escape_bytes: \@@_convert_escape_: +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsubsection{Native strings} +% +% \begin{macro}{\@@_convert_decode_:} +% \begin{macro}[rEXP]{\@@_decode_native_char:N} +% Convert each character to its character code, one at a time. +% \begin{macrocode} +\cs_new_protected:Npn \@@_convert_decode_: + { \@@_convert_gmap:N \@@_decode_native_char:N } +\cs_new:Npn \@@_decode_native_char:N #1 + { #1 \s__tl \int_value:w `#1 \s__tl } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\@@_convert_encode_:} +% \begin{macro}[EXP]{\@@_encode_native_char:n} +% The conversion from an internal string to native character tokens +% basically maps \cs{char_generate:nn} through the code-points, but in +% non-Unicode-aware engines we use a fall-back character |?| rather +% than nothing when given a character code outside $[0,255]$. We +% detect the presence of bad characters using a flag and only produce +% a single error after the \texttt{x}-expanding assignment. +% \begin{macrocode} +\bool_lazy_any:nTF + { + \sys_if_engine_luatex_p: + \sys_if_engine_xetex_p: + } + { + \cs_new_protected:Npn \@@_convert_encode_: + { \@@_convert_gmap_internal:N \@@_encode_native_char:n } + \cs_new:Npn \@@_encode_native_char:n #1 + { \char_generate:nn {#1} {12} } + } + { + \cs_new_protected:Npn \@@_convert_encode_: + { + \flag_clear:n { str_error } + \@@_convert_gmap_internal:N \@@_encode_native_char:n + \@@_if_flag_error:nnx { str_error } + { native-overflow } { } + } + \cs_new:Npn \@@_encode_native_char:n #1 + { + \if_int_compare:w #1 > \c_@@_max_byte_int + \flag_raise:n { str_error } + ? + \else: + \char_generate:nn {#1} {12} + \fi: + } + \__kernel_msg_new:nnnn { str } { native-overflow } + { Character~code~too~large~for~this~engine. } + { + This~engine~only~support~8-bit~characters:~ + valid~character~codes~are~in~the~range~[0,255].~ + To~manipulate~arbitrary~Unicode,~use~LuaTeX~or~XeTeX. + } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsubsection{\texttt{clist}} +% +% \begin{macro}{\@@_convert_decode_clist:} +% \begin{macro}[rEXP]{\@@_decode_clist_char:n} +% Convert each integer to the internal form. We first turn +% \cs{g_@@_result_tl} into a clist variable, as this avoids problems +% with leading or trailing commas. +% \begin{macrocode} +\cs_new_protected:Npn \@@_convert_decode_clist: + { + \clist_gset:No \g_@@_result_tl \g_@@_result_tl + \tl_gset:Nx \g_@@_result_tl + { + \exp_args:No \clist_map_function:nN + \g_@@_result_tl \@@_decode_clist_char:n + } + } +\cs_new:Npn \@@_decode_clist_char:n #1 + { #1 \s__tl \int_eval:n {#1} \s__tl } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\@@_convert_encode_clist:} +% \begin{macro}[rEXP]{\@@_encode_clist_char:n} +% Convert the internal list of character codes to a comma-list of +% character codes. The first line produces a comma-list with a +% leading comma, removed in the next step (this also works in the +% empty case, since \cs{tl_tail:N} does not trigger an error in this +% case). +% \begin{macrocode} +\cs_new_protected:Npn \@@_convert_encode_clist: + { + \@@_convert_gmap_internal:N \@@_encode_clist_char:n + \tl_gset:Nx \g_@@_result_tl { \tl_tail:N \g_@@_result_tl } + } +\cs_new:Npn \@@_encode_clist_char:n #1 { , #1 } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsubsection{8-bit encodings} +% +% This section will be entirely rewritten: it is not yet clear in what +% situations 8-bit encodings are used, hence I don't know what exactly +% should be optimized. The current approach is reasonably efficient to +% convert long strings, and it scales well when using many different +% encodings. An approach based on csnames would have a smaller constant +% load time for each individual conversion, but has a large hash table +% cost. Using a range of \tn{count} registers works for decoding, but +% not for encoding: one possibility there would be to use a binary tree +% for the mapping of Unicode characters to bytes, stored as a box, one +% per encoding. +% +% Since the section is going to be rewritten, documentation lacks. +% +% All the 8-bit encodings which \pkg{l3str} supports rely on the same +% internal functions. +% +% \begin{macro}{\str_declare_eight_bit_encoding:nnn} +% All the 8-bit encoding definition file start with +% \cs{str_declare_eight_bit_encoding:nnn} \Arg{encoding name} +% \Arg{mapping} \Arg{missing bytes}. The \meta{mapping} argument is a +% token list of pairs \Arg{byte} \Arg{Unicode} expressed in uppercase +% hexadecimal notation. The \meta{missing} argument is a token list +% of \Arg{byte}. Every \meta{byte} which does not appear in the +% \meta{mapping} nor the \meta{missing} lists maps to the same code +% point in Unicode. +% \begin{macrocode} +\cs_new_protected:Npn \str_declare_eight_bit_encoding:nnn #1#2#3 + { + \tl_set:Nn \l_@@_internal_tl {#1} + \cs_new_protected:cpn { @@_convert_decode_#1: } + { \@@_convert_decode_eight_bit:n {#1} } + \cs_new_protected:cpn { @@_convert_encode_#1: } + { \@@_convert_encode_eight_bit:n {#1} } + \tl_const:cn { c_@@_encoding_#1_tl } {#2} + \tl_const:cn { c_@@_encoding_#1_missing_tl } {#3} + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_convert_decode_eight_bit:n} +% \begin{macro}{\@@_decode_eight_bit_load:nn} +% \begin{macro}{\@@_decode_eight_bit_load_missing:n} +% \begin{macro}[EXP]{\@@_decode_eight_bit_char:N} +%^^A todo: document +% \begin{macrocode} +\cs_new_protected:Npn \@@_convert_decode_eight_bit:n #1 + { + \group_begin: + \int_zero:N \l_@@_internal_int + \exp_last_unbraced:Nx \@@_decode_eight_bit_load:nn + { \tl_use:c { c_@@_encoding_#1_tl } } + { \q_stop \prg_break: } { } + \prg_break_point: + \exp_last_unbraced:Nx \@@_decode_eight_bit_load_missing:n + { \tl_use:c { c_@@_encoding_#1_missing_tl } } + { \q_stop \prg_break: } + \prg_break_point: + \flag_clear:n { str_error } + \@@_convert_gmap:N \@@_decode_eight_bit_char:N + \@@_if_flag_error:nnx { str_error } { decode-8-bit } {#1} + \group_end: + } +\cs_new_protected:Npn \@@_decode_eight_bit_load:nn #1#2 + { + \use_none_delimit_by_q_stop:w #1 \q_stop + \tex_dimen:D "#1 = \l_@@_internal_int sp \scan_stop: + \tex_skip:D \l_@@_internal_int = "#1 sp \scan_stop: + \tex_toks:D \l_@@_internal_int \exp_after:wN { \int_value:w "#2 } + \int_incr:N \l_@@_internal_int + \@@_decode_eight_bit_load:nn + } +\cs_new_protected:Npn \@@_decode_eight_bit_load_missing:n #1 + { + \use_none_delimit_by_q_stop:w #1 \q_stop + \tex_dimen:D "#1 = \l_@@_internal_int sp \scan_stop: + \tex_skip:D \l_@@_internal_int = "#1 sp \scan_stop: + \tex_toks:D \l_@@_internal_int \exp_after:wN + { \int_use:N \c_@@_replacement_char_int } + \int_incr:N \l_@@_internal_int + \@@_decode_eight_bit_load_missing:n + } +\cs_new:Npn \@@_decode_eight_bit_char:N #1 + { + #1 \s__tl + \if_int_compare:w \tex_dimen:D `#1 < \l_@@_internal_int + \if_int_compare:w \tex_skip:D \tex_dimen:D `#1 = `#1 \exp_stop_f: + \tex_the:D \tex_toks:D \tex_dimen:D + \fi: + \fi: + \int_value:w `#1 \s__tl + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\@@_convert_encode_eight_bit:n} +% \begin{macro}{\@@_encode_eight_bit_load:nn} +% \begin{macro}[rEXP]{\@@_encode_eight_bit_char:n} +% \begin{macro}[rEXP]{\@@_encode_eight_bit_char_aux:n} +%^^A todo: document +% \begin{macrocode} +\cs_new_protected:Npn \@@_convert_encode_eight_bit:n #1 + { + \group_begin: + \int_zero:N \l_@@_internal_int + \exp_last_unbraced:Nx \@@_encode_eight_bit_load:nn + { \tl_use:c { c_@@_encoding_#1_tl } } + { \q_stop \prg_break: } { } + \prg_break_point: + \flag_clear:n { str_error } + \@@_convert_gmap_internal:N \@@_encode_eight_bit_char:n + \@@_if_flag_error:nnx { str_error } { encode-8-bit } {#1} + \group_end: + } +\cs_new_protected:Npn \@@_encode_eight_bit_load:nn #1#2 + { + \use_none_delimit_by_q_stop:w #1 \q_stop + \tex_dimen:D "#2 = \l_@@_internal_int sp \scan_stop: + \tex_skip:D \l_@@_internal_int = "#2 sp \scan_stop: + \exp_args:NNf \tex_toks:D \l_@@_internal_int + { \@@_output_byte:n { "#1 } } + \int_incr:N \l_@@_internal_int + \@@_encode_eight_bit_load:nn + } +\cs_new:Npn \@@_encode_eight_bit_char:n #1 + { + \if_int_compare:w #1 > \c_max_register_int + \flag_raise:n { str_error } + \else: + \if_int_compare:w \tex_dimen:D #1 < \l_@@_internal_int + \if_int_compare:w \tex_skip:D \tex_dimen:D #1 = #1 \exp_stop_f: + \tex_the:D \tex_toks:D \tex_dimen:D #1 \exp_stop_f: + \exp_after:wN \exp_after:wN \exp_after:wN \use_none:nn + \fi: + \fi: + \@@_encode_eight_bit_char_aux:n {#1} + \fi: + } +\cs_new:Npn \@@_encode_eight_bit_char_aux:n #1 + { + \if_int_compare:w #1 > \c_@@_max_byte_int + \flag_raise:n { str_error } + \else: + \@@_output_byte:n {#1} + \fi: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Messages} +% +% General messages, and messages for the encodings and escapings loaded +% by default (\enquote{native}, and \enquote{bytes}). +% \begin{macrocode} +\__kernel_msg_new:nnn { str } { unknown-esc } + { Escaping~scheme~'#1'~(filtered:~'#2')~unknown. } +\__kernel_msg_new:nnn { str } { unknown-enc } + { Encoding~scheme~'#1'~(filtered:~'#2')~unknown. } +\__kernel_msg_new:nnnn { str } { native-escaping } + { The~'native'~encoding~scheme~does~not~support~any~escaping. } + { + Since~native~strings~do~not~consist~in~bytes,~ + none~of~the~escaping~methods~make~sense.~ + The~specified~escaping,~'#1',~will be ignored. + } +\__kernel_msg_new:nnn { str } { file-not-found } + { File~'l3str-#1.def'~not~found. } +% \end{macrocode} +% +% Message used when the \enquote{bytes} unescaping fails because the +% string given to \cs{str_set_convert:Nnnn} contains a non-byte. This +% cannot happen for the -8-bit engines. +% Messages used for other escapings and +% encodings are defined in each definition file. +% \begin{macrocode} +\bool_lazy_any:nT + { + \sys_if_engine_luatex_p: + \sys_if_engine_xetex_p: + } + { + \__kernel_msg_new:nnnn { str } { non-byte } + { String~invalid~in~escaping~'#1':~it~may~only~contain~bytes. } + { + Some~characters~in~the~string~you~asked~to~convert~are~not~ + 8-bit~characters.~Perhaps~the~string~is~a~'native'~Unicode~string?~ + If~it~is,~try~using\\ + \\ + \iow_indent:n + { + \iow_char:N\\str_set_convert:Nnnn \\ + \ \ ~\{~~\}~\{~native~\}~\{~~\} + } + } + } +% \end{macrocode} +% +% Those messages are used when converting to and from 8-bit encodings. +% \begin{macrocode} +\__kernel_msg_new:nnnn { str } { decode-8-bit } + { Invalid~string~in~encoding~'#1'. } + { + LaTeX~came~across~a~byte~which~is~not~defined~to~represent~ + any~character~in~the~encoding~'#1'. + } +\__kernel_msg_new:nnnn { str } { encode-8-bit } + { Unicode~string~cannot~be~converted~to~encoding~'#1'. } + { + The~encoding~'#1'~only~contains~a~subset~of~all~Unicode~characters.~ + LaTeX~was~asked~to~convert~a~string~to~that~encoding,~but~that~ + string~contains~a~character~that~'#1'~does~not~support. + } +% \end{macrocode} +% +% \subsection{Escaping definitions} +% +% Several of those encodings are defined by the pdf file format. The +% following byte storage methods are defined: +% \begin{itemize} +% \item \texttt{bytes} (default), non-bytes are filtered out, and +% bytes are left untouched (this is defined by default); +% \item \texttt{hex} or \texttt{hexadecimal}, as per the \pdfTeX{} +% primitive \tn{pdfescapehex} +% \item \texttt{name}, as per the \pdfTeX{} primitive +% \tn{pdfescapename} +% \item \texttt{string}, as per the \pdfTeX{} primitive +% \tn{pdfescapestring} +% \item \texttt{url}, as per the percent encoding of urls. +% \end{itemize} +% +% \subsubsection{Unescape methods} +% +% \begin{macro}{\@@_convert_unescape_hex:} +% \begin{macro}[rEXP]{\@@_unescape_hex_auxi:N} +% \begin{macro}[rEXP]{\@@_unescape_hex_auxii:N} +% Take chars two by two, and interpret each pair as the hexadecimal +% code for a byte. Anything else than hexadecimal digits is ignored, +% raising the flag. A string which contains an odd number of +% hexadecimal digits gets |0| appended to it: this is equivalent to +% appending a |0| in all cases, and dropping it if it is alone. +% \begin{macrocode} +\cs_new_protected:Npn \@@_convert_unescape_hex: + { + \group_begin: + \flag_clear:n { str_error } + \int_set:Nn \tex_escapechar:D { 92 } + \tl_gset:Nx \g_@@_result_tl + { + \@@_output_byte:w " + \exp_last_unbraced:Nf \@@_unescape_hex_auxi:N + { \tl_to_str:N \g_@@_result_tl } + 0 { ? 0 - 1 \prg_break: } + \prg_break_point: + \@@_output_end: + } + \@@_if_flag_error:nnx { str_error } { unescape-hex } { } + \group_end: + } +\cs_new:Npn \@@_unescape_hex_auxi:N #1 + { + \use_none:n #1 + \@@_hexadecimal_use:NTF #1 + { \@@_unescape_hex_auxii:N } + { + \flag_raise:n { str_error } + \@@_unescape_hex_auxi:N + } + } +\cs_new:Npn \@@_unescape_hex_auxii:N #1 + { + \use_none:n #1 + \@@_hexadecimal_use:NTF #1 + { + \@@_output_end: + \@@_output_byte:w " \@@_unescape_hex_auxi:N + } + { + \flag_raise:n { str_error } + \@@_unescape_hex_auxii:N + } + } +\__kernel_msg_new:nnnn { str } { unescape-hex } + { String~invalid~in~escaping~'hex':~only~hexadecimal~digits~allowed. } + { + Some~characters~in~the~string~you~asked~to~convert~are~not~ + hexadecimal~digits~(0-9,~A-F,~a-f)~nor~spaces. + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\@@_convert_unescape_name:} +% \begin{macro}[rEXP]{\@@_unescape_name_loop:wNN} +% \begin{macro}{\@@_convert_unescape_url:} +% \begin{macro}[rEXP]{\@@_unescape_url_loop:wNN} +% The \cs{@@_convert_unescape_name:} function replaces each +% occurrence of |#| followed by two hexadecimal digits in +% \cs{g_@@_result_tl} by the corresponding byte. The \texttt{url} +% function is identical, with escape character |%| instead of |#|. +% Thus we define the two together. The arguments of \cs{@@_tmp:w} are +% the character code of |#| or |%| in hexadecimal, the name of the +% main function to define, and the name of the auxiliary which +% performs the loop. +% +% The looping auxiliary |#3| finds the next escape character, reads +% the following two characters, and tests them. The test +% \cs{@@_hexadecimal_use:NTF} leaves the upper-case digit in the +% input stream, hence we surround the test with +% \cs{@@_output_byte:w}~|"| and \cs{@@_output_end:}. If both +% characters are hexadecimal digits, they should be removed before +% looping: this is done by \cs{use_i:nnn}. If one of the characters +% is not a hexadecimal digit, then feed |"#1| to +% \cs{@@_output_byte:w} to produce the escape character, raise the +% flag, and call the looping function followed by the two characters +% (remove \cs{use_i:nnn}). +% \begin{macrocode} +\cs_set_protected:Npn \@@_tmp:w #1#2#3 + { + \cs_new_protected:cpn { @@_convert_unescape_#2: } + { + \group_begin: + \flag_clear:n { str_byte } + \flag_clear:n { str_error } + \int_set:Nn \tex_escapechar:D { 92 } + \tl_gset:Nx \g_@@_result_tl + { + \exp_after:wN #3 \g_@@_result_tl + #1 ? { ? \prg_break: } + \prg_break_point: + } + \@@_if_flag_error:nnx { str_byte } { non-byte } { #2 } + \@@_if_flag_error:nnx { str_error } { unescape-#2 } { } + \group_end: + } + \cs_new:Npn #3 ##1#1##2##3 + { + \@@_filter_bytes:n {##1} + \use_none:n ##3 + \@@_output_byte:w " + \@@_hexadecimal_use:NTF ##2 + { + \@@_hexadecimal_use:NTF ##3 + { } + { + \flag_raise:n { str_error } + * 0 + `#1 \use_i:nn + } + } + { + \flag_raise:n { str_error } + 0 + `#1 \use_i:nn + } + \@@_output_end: + \use_i:nnn #3 ##2##3 + } + \__kernel_msg_new:nnnn { str } { unescape-#2 } + { String~invalid~in~escaping~'#2'. } + { + LaTeX~came~across~the~escape~character~'#1'~not~followed~by~ + two~hexadecimal~digits.~This~is~invalid~in~the~escaping~'#2'. + } + } +\exp_after:wN \@@_tmp:w \c_hash_str { name } + \@@_unescape_name_loop:wNN +\exp_after:wN \@@_tmp:w \c_percent_str { url } + \@@_unescape_url_loop:wNN +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\@@_convert_unescape_string:} +% \begin{macro}[rEXP]{\@@_unescape_string_newlines:wN} +% \begin{macro}[rEXP]{\@@_unescape_string_loop:wNNN} +% \begin{macro}[rEXP]{\@@_unescape_string_repeat:NNNNNN} +% The \texttt{string} escaping is somewhat similar to the +% \texttt{name} and \texttt{url} escapings, with escape character |\|. +% The first step is to convert all three line endings, |^^J|, |^^M|, +% and |^^M^^J| to the common |^^J|, as per the \textsc{pdf} +% specification. This step cannot raise the flag. +% +% Then the following escape sequences are decoded. +% \begin{itemize}\def\makelabel#1{\hss\llap{\ttfamily\string#1}} +% \item[\n] Line feed ($10$) +% \item[\r] Carriage return ($13$) +% \item[\t] Horizontal tab ($9$) +% \item[\b] Backspace ($8$) +% \item[\f] Form feed ($12$) +% \item[\(] Left parenthesis +% \item[\)] Right parenthesis +% \item[\\] Backslash +% \item[\ddd] (backslash followed by $1$ to $3$ octal digits) Byte +% \texttt{ddd} (octal), subtracting $256$ in case of overflow. +% \end{itemize} +% If followed by an end-of-line character, the backslash and the +% end-of-line are ignored. If followed by anything else, the backslash +% is ignored, raising the error flag. +% \begin{macrocode} +\group_begin: + \char_set_catcode_other:N \^^J + \char_set_catcode_other:N \^^M + \cs_set_protected:Npn \@@_tmp:w #1 + { + \cs_new_protected:Npn \@@_convert_unescape_string: + { + \group_begin: + \flag_clear:n { str_byte } + \flag_clear:n { str_error } + \int_set:Nn \tex_escapechar:D { 92 } + \tl_gset:Nx \g_@@_result_tl + { + \exp_after:wN \@@_unescape_string_newlines:wN + \g_@@_result_tl \prg_break: ^^M ? + \prg_break_point: + } + \tl_gset:Nx \g_@@_result_tl + { + \exp_after:wN \@@_unescape_string_loop:wNNN + \g_@@_result_tl #1 ?? { ? \prg_break: } + \prg_break_point: + } + \@@_if_flag_error:nnx { str_byte } { non-byte } { string } + \@@_if_flag_error:nnx { str_error } { unescape-string } { } + \group_end: + } + } + \exp_args:No \@@_tmp:w { \c_backslash_str } + \exp_last_unbraced:NNNNo + \cs_new:Npn \@@_unescape_string_loop:wNNN #1 \c_backslash_str #2#3#4 + { + \@@_filter_bytes:n {#1} + \use_none:n #4 + \@@_output_byte:w ' + \@@_octal_use:NTF #2 + { + \@@_octal_use:NTF #3 + { + \@@_octal_use:NTF #4 + { + \if_int_compare:w #2 > 3 \exp_stop_f: + - 256 + \fi: + \@@_unescape_string_repeat:NNNNNN + } + { \@@_unescape_string_repeat:NNNNNN ? } + } + { \@@_unescape_string_repeat:NNNNNN ?? } + } + { + \str_case_e:nnF {#2} + { + { \c_backslash_str } { 134 } + { ( } { 50 } + { ) } { 51 } + { r } { 15 } + { f } { 14 } + { n } { 12 } + { t } { 11 } + { b } { 10 } + { ^^J } { 0 - 1 } + } + { + \flag_raise:n { str_error } + 0 - 1 \use_i:nn + } + } + \@@_output_end: + \use_i:nn \@@_unescape_string_loop:wNNN #2#3#4 + } + \cs_new:Npn \@@_unescape_string_repeat:NNNNNN #1#2#3#4#5#6 + { \@@_output_end: \@@_unescape_string_loop:wNNN } + \cs_new:Npn \@@_unescape_string_newlines:wN #1 ^^M #2 + { + #1 + \if_charcode:w ^^J #2 \else: ^^J \fi: + \@@_unescape_string_newlines:wN #2 + } + \__kernel_msg_new:nnnn { str } { unescape-string } + { String~invalid~in~escaping~'string'. } + { + LaTeX~came~across~an~escape~character~'\c_backslash_str'~ + not~followed~by~any~of:~'n',~'r',~'t',~'b',~'f',~'(',~')',~ + '\c_backslash_str',~one~to~three~octal~digits,~or~the~end~ + of~a~line. + } +\group_end: +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsubsection{Escape methods} +% +% Currently, none of the escape methods can lead to errors, assuming +% that their input is made out of bytes. +% +% \begin{macro}{\@@_convert_escape_hex:} +% \begin{macro}[rEXP]{\@@_escape_hex_char:N} +% Loop and convert each byte to hexadecimal. +% \begin{macrocode} +\cs_new_protected:Npn \@@_convert_escape_hex: + { \@@_convert_gmap:N \@@_escape_hex_char:N } +\cs_new:Npn \@@_escape_hex_char:N #1 + { \@@_output_hexadecimal:n { `#1 } } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\@@_convert_escape_name:} +% \begin{macro}[rEXP]{\@@_escape_name_char:N} +% \begin{macro}[rEXP]{\@@_if_escape_name:NTF} +% \begin{variable}{\c_@@_escape_name_str} +% \begin{variable}{\c_@@_escape_name_not_str} +% For each byte, test whether it should be output as is, or be +% \enquote{hash-encoded}. Roughly, bytes outside the range +% $[\hexnum{2A},\hexnum{7E}]$ are hash-encoded. We keep two lists of +% exceptions: characters in \cs{c_@@_escape_name_not_str} are not +% hash-encoded, and characters in the \cs{c_@@_escape_name_str} are +% encoded. +% \begin{macrocode} +\str_const:Nn \c_@@_escape_name_not_str { ! " $ & ' } %$ +\str_const:Nn \c_@@_escape_name_str { {}/<>[] } +\cs_new_protected:Npn \@@_convert_escape_name: + { \@@_convert_gmap:N \@@_escape_name_char:N } +\cs_new:Npn \@@_escape_name_char:N #1 + { + \@@_if_escape_name:NTF #1 {#1} + { \c_hash_str \@@_output_hexadecimal:n {`#1} } + } +\prg_new_conditional:Npnn \@@_if_escape_name:N #1 { TF } + { + \if_int_compare:w `#1 < "2A \exp_stop_f: + \@@_if_contains_char:NNTF \c_@@_escape_name_not_str #1 + \prg_return_true: \prg_return_false: + \else: + \if_int_compare:w `#1 > "7E \exp_stop_f: + \prg_return_false: + \else: + \@@_if_contains_char:NNTF \c_@@_escape_name_str #1 + \prg_return_false: \prg_return_true: + \fi: + \fi: + } +% \end{macrocode} +% \end{variable} +% \end{variable} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\@@_convert_escape_string:} +% \begin{macro}[rEXP]{\@@_escape_string_char:N} +% \begin{macro}[rEXP]{\@@_if_escape_string:NTF} +% \begin{variable}{\c_@@_escape_string_str} +% Any character below (and including) space, and any character above +% (and including) \texttt{del}, are converted to octal. One backslash +% is added before each parenthesis and backslash. +% \begin{macrocode} +\str_const:Nx \c_@@_escape_string_str + { \c_backslash_str ( ) } +\cs_new_protected:Npn \@@_convert_escape_string: + { \@@_convert_gmap:N \@@_escape_string_char:N } +\cs_new:Npn \@@_escape_string_char:N #1 + { + \@@_if_escape_string:NTF #1 + { + \@@_if_contains_char:NNT + \c_@@_escape_string_str #1 + { \c_backslash_str } + #1 + } + { + \c_backslash_str + \int_div_truncate:nn {`#1} {64} + \int_mod:nn { \int_div_truncate:nn {`#1} { 8 } } { 8 } + \int_mod:nn {`#1} { 8 } + } + } +\prg_new_conditional:Npnn \@@_if_escape_string:N #1 { TF } + { + \if_int_compare:w `#1 < "21 \exp_stop_f: + \prg_return_false: + \else: + \if_int_compare:w `#1 > "7E \exp_stop_f: + \prg_return_false: + \else: + \prg_return_true: + \fi: + \fi: + } +% \end{macrocode} +% \end{variable} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\@@_convert_escape_url:} +% \begin{macro}[rEXP]{\@@_escape_url_char:N} +% \begin{macro}[rEXP]{\@@_if_escape_url:NTF} +% This function is similar to \cs{@@_convert_escape_name:}, escaping +% different characters. +% \begin{macrocode} +\cs_new_protected:Npn \@@_convert_escape_url: + { \@@_convert_gmap:N \@@_escape_url_char:N } +\cs_new:Npn \@@_escape_url_char:N #1 + { + \@@_if_escape_url:NTF #1 {#1} + { \c_percent_str \@@_output_hexadecimal:n { `#1 } } + } +\prg_new_conditional:Npnn \@@_if_escape_url:N #1 { TF } + { + \if_int_compare:w `#1 < "41 \exp_stop_f: + \@@_if_contains_char:nNTF { "-.<> } #1 + \prg_return_true: \prg_return_false: + \else: + \if_int_compare:w `#1 > "7E \exp_stop_f: + \prg_return_false: + \else: + \@@_if_contains_char:nNTF { [ ] } #1 + \prg_return_false: \prg_return_true: + \fi: + \fi: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Encoding definitions} +% +% The \texttt{native} encoding is automatically defined. Other encodings +% are loaded as needed. The following encodings are supported: +% \begin{itemize} +% \item \textsc{utf-8}; +% \item \textsc{utf-16}, big-, little-endian, or with byte order mark; +% \item \textsc{utf-32}, big-, little-endian, or with byte order mark; +% \item the \textsc{iso 8859} code pages, numbered from $1$ to $16$, +% skipping the inexistent \textsc{iso 8859-12}. +% \end{itemize} +% +% \subsubsection{\textsc{utf-8} support} +% +% \begin{macro}{\@@_convert_encode_utf8:} +% \begin{macro}[rEXP]{\@@_encode_utf_viii_char:n} +% \begin{macro}[rEXP]{\@@_encode_utf_viii_loop:wwnnw} +% Loop through the internal string, and convert each character to its +% \textsc{utf-8} representation. The representation is built from the +% right-most (least significant) byte to the left-most (most +% significant) byte. Continuation bytes are in the range $[128,191]$, +% taking $64$ different values, hence we roughly want to express the +% character code in base $64$, shifting the first digit in the +% representation by some number depending on how many continuation +% bytes there are. In the range $[0,127]$, output the corresponding +% byte directly. In the range $[128,2047]$, output the remainder +% modulo $64$, plus $128$ as a continuation byte, then output the +% quotient (which is in the range $[0,31]$), shifted by $192$. In the +% next range, $[2048,65535]$, split the character code into residue +% and quotient modulo $64$, output the residue as a first continuation +% byte, then repeat; this leaves us with a quotient in the range +% $[0,15]$, which we output shifted by $224$. The last range, +% $[65536,1114111]$, follows the same pattern: once we realize that +% dividing twice by $64$ leaves us with a number larger than $15$, we +% repeat, producing a last continuation byte, and offset the quotient +% by $240$ for the leading byte. +% +% How is that implemented? \cs{@@_encode_utf_vii_loop:wwnnw} takes +% successive quotients as its first argument, the quotient from the +% previous step as its second argument (except in step~$1$), the bound +% for quotients that trigger one more step or not, and finally the +% offset used if this step should produce the leading byte. Leading +% bytes can be in the ranges $[0,127]$, $[192,223]$, $[224,239]$, and +% $[240,247]$ (really, that last limit should be $244$ because Unicode +% stops at the code point $1114111$). At each step, if the quotient +% |#1| is less than the limit |#3| for that range, output the leading +% byte (|#1| shifted by |#4|) and stop. Otherwise, we need one more +% step: use the quotient of |#1| by $64$, and |#1| as arguments for +% the looping auxiliary, and output the continuation byte +% corresponding to the remainder $|#2|-64|#1|+128$. The bizarre +% construction |- 1 + 0 *| removes the spurious initial +% continuation byte (better methods welcome). +% \begin{macrocode} +\cs_new_protected:cpn { @@_convert_encode_utf8: } + { \@@_convert_gmap_internal:N \@@_encode_utf_viii_char:n } +\cs_new:Npn \@@_encode_utf_viii_char:n #1 + { + \@@_encode_utf_viii_loop:wwnnw #1 ; - 1 + 0 * ; + { 128 } { 0 } + { 32 } { 192 } + { 16 } { 224 } + { 8 } { 240 } + \q_stop + } +\cs_new:Npn \@@_encode_utf_viii_loop:wwnnw #1; #2; #3#4 #5 \q_stop + { + \if_int_compare:w #1 < #3 \exp_stop_f: + \@@_output_byte:n { #1 + #4 } + \exp_after:wN \use_none_delimit_by_q_stop:w + \fi: + \exp_after:wN \@@_encode_utf_viii_loop:wwnnw + \int_value:w \int_div_truncate:nn {#1} {64} ; #1 ; + #5 \q_stop + \@@_output_byte:n { #2 - 64 * ( #1 - 2 ) } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{variable} +% { +% \l_@@_missing_flag , +% \l_@@_extra_flag , +% \l_@@_overlong_flag , +% \l_@@_overflow_flag , +% } +% When decoding a string that is purportedly in the \textsc{utf-8} +% encoding, four different errors can occur, signalled by a specific +% flag for each (we define those flags using \cs{flag_clear_new:n} +% rather than \cs{flag_new:n}, because they are shared with other +% encoding definition files). +% \begin{itemize} +% \item \enquote{Missing continuation byte}: a leading byte is not +% followed by the right number of continuation bytes. +% \item \enquote{Extra continuation byte}: a continuation byte +% appears where it was not expected, \emph{i.e.}, not after an +% appropriate leading byte. +% \item \enquote{Overlong}: a Unicode character is expressed using +% more bytes than necessary, for instance, \hexnum{C0}\hexnum{80} +% for the code point $0$, instead of a single null byte. +% \item \enquote{Overflow}: this occurs when decoding produces +% Unicode code points greater than $1114111$. +% \end{itemize} +% We only raise one \LaTeX3 error message, combining all the errors +% which occurred. In the short message, the leading comma must be +% removed to get a grammatically correct sentence. In the long text, +% first remind the user what a correct \textsc{utf-8} string should +% look like, then add error-specific information. +% \begin{macrocode} +\flag_clear_new:n { str_missing } +\flag_clear_new:n { str_extra } +\flag_clear_new:n { str_overlong } +\flag_clear_new:n { str_overflow } +\__kernel_msg_new:nnnn { str } { utf8-decode } + { + Invalid~UTF-8~string: + \exp_last_unbraced:Nf \use_none:n + { + \@@_if_flag_times:nT { str_missing } { ,~missing~continuation~byte } + \@@_if_flag_times:nT { str_extra } { ,~extra~continuation~byte } + \@@_if_flag_times:nT { str_overlong } { ,~overlong~form } + \@@_if_flag_times:nT { str_overflow } { ,~code~point~too~large } + } + . + } + { + In~the~UTF-8~encoding,~each~Unicode~character~consists~in~ + 1~to~4~bytes,~with~the~following~bit~pattern: \\ + \iow_indent:n + { + Code~point~\ \ \ \ <~128:~0xxxxxxx \\ + Code~point~\ \ \ <~2048:~110xxxxx~10xxxxxx \\ + Code~point~\ \ <~65536:~1110xxxx~10xxxxxx~10xxxxxx \\ + Code~point~ <~1114112:~11110xxx~10xxxxxx~10xxxxxx~10xxxxxx \\ + } + Bytes~of~the~form~10xxxxxx~are~called~continuation~bytes. + \flag_if_raised:nT { str_missing } + { + \\\\ + A~leading~byte~(in~the~range~[192,255])~was~not~followed~by~ + the~appropriate~number~of~continuation~bytes. + } + \flag_if_raised:nT { str_extra } + { + \\\\ + LaTeX~came~across~a~continuation~byte~when~it~was~not~expected. + } + \flag_if_raised:nT { str_overlong } + { + \\\\ + Every~Unicode~code~point~must~be~expressed~in~the~shortest~ + possible~form.~For~instance,~'0xC0'~'0x83'~is~not~a~valid~ + representation~for~the~code~point~3. + } + \flag_if_raised:nT { str_overflow } + { + \\\\ + Unicode~limits~code~points~to~the~range~[0,1114111]. + } + } +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\@@_convert_decode_utf8:} +% \begin{macro}[rEXP] +% { +% \@@_decode_utf_viii_start:N, +% \@@_decode_utf_viii_continuation:wwN, +% \@@_decode_utf_viii_aux:wNnnwN +% } +% \begin{macro}[rEXP] +% {\@@_decode_utf_viii_overflow:w, \@@_decode_utf_viii_end:} +% Decoding is significantly harder than encoding. As before, lower +% some flags, which are tested at the end (in bulk, to trigger at most +% one \LaTeX3 error, as explained above). We expect successive +% multi-byte sequences of the form \meta{start byte} +% \meta{continuation bytes}. The \texttt{_start} auxiliary tests the +% first byte: +% \begin{itemize} +% \item $[0,\hexnum{7F}]$: the byte stands alone, and is converted +% to its own character code; +% \item $[\hexnum{80}, \hexnum{BF}]$: unexpected continuation byte, +% raise the appropriate flag, and convert that byte to the +% replacement character \hexnum{FFFD}; +% \item $[\hexnum{C0}, \hexnum{FF}]$: this byte should be followed +% by some continuation byte(s). +% \end{itemize} +% In the first two cases, \cs{use_none_delimit_by_q_stop:w} removes +% data that only the third case requires, namely the limits of ranges +% of Unicode characters which can be expressed with $1$, $2$, $3$, or +% $4$ bytes. +% +% We can now concentrate on the multi-byte case and the +% \texttt{_continuation} auxiliary. We expect |#3| to be in the range +% $[\hexnum{80}, \hexnum{BF}]$. The test for this goes as follows: if +% the character code is less than \hexnum{80}, we compare it to +% $-\hexnum{C0}$, yielding \texttt{false}; otherwise to \hexnum{C0}, +% yielding \texttt{true} in the range $[\hexnum{80}, \hexnum{BF}]$ and +% \texttt{false} otherwise. If we find that the byte is not a +% continuation range, stop the current slew of bytes, output the +% replacement character, and continue parsing with the \texttt{_start} +% auxiliary, starting at the byte we just tested. Once we know that +% the byte is a continuation byte, leave it behind us in the input +% stream, compute what code point the bytes read so far would produce, +% and feed that number to the \texttt{_aux} function. +% +% The \texttt{_aux} function tests whether we should look for more +% continuation bytes or not. If the number it receives as |#1| is less +% than the maximum |#4| for the current range, then we are done: check +% for an overlong representation by comparing |#1| with the maximum +% |#3| for the previous range. Otherwise, we call the +% \texttt{_continuation} auxiliary again, after shifting the +% \enquote{current code point} by |#4| (maximum from the range we just +% checked). +% +% Two additional tests are needed: if we reach the end of the list of +% range maxima and we are still not done, then we are faced with an +% overflow. Clean up, and again insert the code point \hexnum{FFFD} +% for the replacement character. Also, every time we read a byte, we +% need to check whether we reached the end of the string. In a correct +% \textsc{utf-8} string, this happens automatically when the +% \texttt{_start} auxiliary leaves its first argument in the input +% stream: the end-marker begins with \cs{prg_break:}, which ends +% the loop. On the other hand, if the end is reached when looking for +% a continuation byte, the \cs{use_none:n} |#3| construction removes +% the first token from the end-marker, and leaves the \texttt{_end} +% auxiliary, which raises the appropriate error flag before ending the +% mapping. +% \begin{macrocode} +\cs_new_protected:cpn { @@_convert_decode_utf8: } + { + \flag_clear:n { str_error } + \flag_clear:n { str_missing } + \flag_clear:n { str_extra } + \flag_clear:n { str_overlong } + \flag_clear:n { str_overflow } + \tl_gset:Nx \g_@@_result_tl + { + \exp_after:wN \@@_decode_utf_viii_start:N \g_@@_result_tl + { \prg_break: \@@_decode_utf_viii_end: } + \prg_break_point: + } + \@@_if_flag_error:nnx { str_error } { utf8-decode } { } + } +\cs_new:Npn \@@_decode_utf_viii_start:N #1 + { + #1 + \if_int_compare:w `#1 < "C0 \exp_stop_f: + \s__tl + \if_int_compare:w `#1 < "80 \exp_stop_f: + \int_value:w `#1 + \else: + \flag_raise:n { str_extra } + \flag_raise:n { str_error } + \int_use:N \c_@@_replacement_char_int + \fi: + \else: + \exp_after:wN \@@_decode_utf_viii_continuation:wwN + \int_value:w \int_eval:n { `#1 - "C0 } \exp_after:wN + \fi: + \s__tl + \use_none_delimit_by_q_stop:w {"80} {"800} {"10000} {"110000} \q_stop + \@@_decode_utf_viii_start:N + } +\cs_new:Npn \@@_decode_utf_viii_continuation:wwN + #1 \s__tl #2 \@@_decode_utf_viii_start:N #3 + { + \use_none:n #3 + \if_int_compare:w `#3 < + \if_int_compare:w `#3 < "80 \exp_stop_f: - \fi: + "C0 \exp_stop_f: + #3 + \exp_after:wN \@@_decode_utf_viii_aux:wNnnwN + \int_value:w \int_eval:n { #1 * "40 + `#3 - "80 } \exp_after:wN + \else: + \s__tl + \flag_raise:n { str_missing } + \flag_raise:n { str_error } + \int_use:N \c_@@_replacement_char_int + \fi: + \s__tl + #2 + \@@_decode_utf_viii_start:N #3 + } +\cs_new:Npn \@@_decode_utf_viii_aux:wNnnwN + #1 \s__tl #2#3#4 #5 \@@_decode_utf_viii_start:N #6 + { + \if_int_compare:w #1 < #4 \exp_stop_f: + \s__tl + \if_int_compare:w #1 < #3 \exp_stop_f: + \flag_raise:n { str_overlong } + \flag_raise:n { str_error } + \int_use:N \c_@@_replacement_char_int + \else: + #1 + \fi: + \else: + \if_meaning:w \q_stop #5 + \@@_decode_utf_viii_overflow:w #1 + \fi: + \exp_after:wN \@@_decode_utf_viii_continuation:wwN + \int_value:w \int_eval:n { #1 - #4 } \exp_after:wN + \fi: + \s__tl + #2 {#4} #5 + \@@_decode_utf_viii_start:N + } +\cs_new:Npn \@@_decode_utf_viii_overflow:w #1 \fi: #2 \fi: + { + \fi: \fi: + \flag_raise:n { str_overflow } + \flag_raise:n { str_error } + \int_use:N \c_@@_replacement_char_int + } +\cs_new:Npn \@@_decode_utf_viii_end: + { + \s__tl + \flag_raise:n { str_missing } + \flag_raise:n { str_error } + \int_use:N \c_@@_replacement_char_int \s__tl + \prg_break: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsubsection{\textsc{utf-16} support} +% +% The definitions are done in a category code regime where the bytes +% $254$ and $255$ used by the byte order mark have catcode~$12$. +% \begin{macrocode} +\group_begin: + \char_set_catcode_other:N \^^fe + \char_set_catcode_other:N \^^ff +% \end{macrocode} +% +% \begin{macro} +% { +% \@@_convert_encode_utf16: , +% \@@_convert_encode_utf16be: , +% \@@_convert_encode_utf16le: , +% } +% \begin{macro}[rEXP] +% { +% \@@_encode_utf_xvi_aux:N , +% \@@_encode_utf_xvi_char:n , +% } +% When the endianness is not specified, it is big-endian by default, +% and we add a byte-order mark. Convert characters one by one in a +% loop, with different behaviours depending on the character code. +% \begin{itemize} +% \item $[0, \hexnum{D7FF}]$: converted to two bytes; +% \item $[\hexnum{D800}, \hexnum{DFFF}]$ are used as surrogates: +% they cannot be converted and are replaced by the replacement +% character; +% \item $[\hexnum{E000}, \hexnum{FFFF}]$: converted to two bytes; +% \item $[\hexnum{10000}, \hexnum{10FFFF}]$: converted to a pair of +% surrogates, each two bytes. The magic \hexnum{D7C0} is +% $\hexnum{D800}-\hexnum{10000}/\hexnum{400}$. +% \end{itemize} +% For the duration of this operation, \cs{@@_tmp:w} is defined as a +% function to convert a number in the range $[0, \hexnum{FFFF}]$ to a +% pair of bytes (either big endian or little endian), by feeding the +% quotient of the division of |#1| by \hexnum{100}, followed by |#1| +% to \cs{@@_encode_utf_xvi_be:nn} or its \texttt{le} analog: those +% compute the remainder, and output two bytes for the quotient and +% remainder. +% \begin{macrocode} + \cs_new_protected:cpn { @@_convert_encode_utf16: } + { + \@@_encode_utf_xvi_aux:N \@@_output_byte_pair_be:n + \tl_gput_left:Nx \g_@@_result_tl { ^^fe ^^ff } + } + \cs_new_protected:cpn { @@_convert_encode_utf16be: } + { \@@_encode_utf_xvi_aux:N \@@_output_byte_pair_be:n } + \cs_new_protected:cpn { @@_convert_encode_utf16le: } + { \@@_encode_utf_xvi_aux:N \@@_output_byte_pair_le:n } + \cs_new_protected:Npn \@@_encode_utf_xvi_aux:N #1 + { + \flag_clear:n { str_error } + \cs_set_eq:NN \@@_tmp:w #1 + \@@_convert_gmap_internal:N \@@_encode_utf_xvi_char:n + \@@_if_flag_error:nnx { str_error } { utf16-encode } { } + } + \cs_new:Npn \@@_encode_utf_xvi_char:n #1 + { + \if_int_compare:w #1 < "D800 \exp_stop_f: + \@@_tmp:w {#1} + \else: + \if_int_compare:w #1 < "10000 \exp_stop_f: + \if_int_compare:w #1 < "E000 \exp_stop_f: + \flag_raise:n { str_error } + \@@_tmp:w { \c_@@_replacement_char_int } + \else: + \@@_tmp:w {#1} + \fi: + \else: + \exp_args:Nf \@@_tmp:w { \int_div_truncate:nn {#1} {"400} + "D7C0 } + \exp_args:Nf \@@_tmp:w { \int_mod:nn {#1} {"400} + "DC00 } + \fi: + \fi: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{variable} +% { +% \l_@@_missing_flag , +% \l_@@_extra_flag , +% \l_@@_end_flag , +% } +% When encoding a Unicode string to \textsc{utf-16}, only one error +% can occur: code points in the range $[\hexnum{D800}, +% \hexnum{DFFF}]$, corresponding to surrogates, cannot be encoded. We +% use the all-purpose flag \texttt{@@_error} to signal that error. +% +% When decoding a Unicode string which is purportedly in +% \textsc{utf-16}, three errors can occur: a missing trail surrogate, +% an unexpected trail surrogate, and a string containing an odd number +% of bytes. +% \begin{macrocode} + \flag_clear_new:n { str_missing } + \flag_clear_new:n { str_extra } + \flag_clear_new:n { str_end } + \__kernel_msg_new:nnnn { str } { utf16-encode } + { Unicode~string~cannot~be~expressed~in~UTF-16:~surrogate. } + { + Surrogate~code~points~(in~the~range~[U+D800,~U+DFFF])~ + can~be~expressed~in~the~UTF-8~and~UTF-32~encodings,~ + but~not~in~the~UTF-16~encoding. + } + \__kernel_msg_new:nnnn { str } { utf16-decode } + { + Invalid~UTF-16~string: + \exp_last_unbraced:Nf \use_none:n + { + \@@_if_flag_times:nT { str_missing } { ,~missing~trail~surrogate } + \@@_if_flag_times:nT { str_extra } { ,~extra~trail~surrogate } + \@@_if_flag_times:nT { str_end } { ,~odd~number~of~bytes } + } + . + } + { + In~the~UTF-16~encoding,~each~Unicode~character~is~encoded~as~ + 2~or~4~bytes: \\ + \iow_indent:n + { + Code~point~in~[U+0000,~U+D7FF]:~two~bytes \\ + Code~point~in~[U+D800,~U+DFFF]:~illegal \\ + Code~point~in~[U+E000,~U+FFFF]:~two~bytes \\ + Code~point~in~[U+10000,~U+10FFFF]:~ + a~lead~surrogate~and~a~trail~surrogate \\ + } + Lead~surrogates~are~pairs~of~bytes~in~the~range~[0xD800,~0xDBFF],~ + and~trail~surrogates~are~in~the~range~[0xDC00,~0xDFFF]. + \flag_if_raised:nT { str_missing } + { + \\\\ + A~lead~surrogate~was~not~followed~by~a~trail~surrogate. + } + \flag_if_raised:nT { str_extra } + { + \\\\ + LaTeX~came~across~a~trail~surrogate~when~it~was~not~expected. + } + \flag_if_raised:nT { str_end } + { + \\\\ + The~string~contained~an~odd~number~of~bytes.~This~is~invalid:~ + the~basic~code~unit~for~UTF-16~is~16~bits~(2~bytes). + } + } +% \end{macrocode} +% \end{variable} +% +% \begin{macro} +% { +% \@@_convert_decode_utf16: , +% \@@_convert_decode_utf16be: , +% \@@_convert_decode_utf16le: , +% } +% \begin{macro}{\@@_decode_utf_xvi_bom:NN, \@@_decode_utf_xvi:Nw} +% As for \textsc{utf-8}, decoding \textsc{utf-16} is harder than +% encoding it. If the endianness is unknown, check the first two +% bytes: if those are \hexnum{FE} and \hexnum{FF} in either order, +% remove them and use the corresponding endianness, otherwise assume +% big-endianness. The three endianness cases are based on a common +% auxiliary whose first argument is $1$ for big-endian and $2$ for +% little-endian, and whose second argument, delimited by the scan mark +% \cs{s_stop}, is expanded once (the string may be long; passing +% \cs{g_@@_result_tl} as an argument before expansion is cheaper). +% +% The \cs{@@_decode_utf_xvi:Nw} function defines \cs{@@_tmp:w} to +% take two arguments and return the character code of the first one if +% the string is big-endian, and the second one if the string is +% little-endian, then loops over the string using +% \cs{@@_decode_utf_xvi_pair:NN} described below. +% \begin{macrocode} + \cs_new_protected:cpn { @@_convert_decode_utf16be: } + { \@@_decode_utf_xvi:Nw 1 \g_@@_result_tl \s_stop } + \cs_new_protected:cpn { @@_convert_decode_utf16le: } + { \@@_decode_utf_xvi:Nw 2 \g_@@_result_tl \s_stop } + \cs_new_protected:cpn { @@_convert_decode_utf16: } + { + \exp_after:wN \@@_decode_utf_xvi_bom:NN + \g_@@_result_tl \s_stop \s_stop \s_stop + } + \cs_new_protected:Npn \@@_decode_utf_xvi_bom:NN #1#2 + { + \str_if_eq:nnTF { #1#2 } { ^^ff ^^fe } + { \@@_decode_utf_xvi:Nw 2 } + { + \str_if_eq:nnTF { #1#2 } { ^^fe ^^ff } + { \@@_decode_utf_xvi:Nw 1 } + { \@@_decode_utf_xvi:Nw 1 #1#2 } + } + } + \cs_new_protected:Npn \@@_decode_utf_xvi:Nw #1#2 \s_stop + { + \flag_clear:n { str_error } + \flag_clear:n { str_missing } + \flag_clear:n { str_extra } + \flag_clear:n { str_end } + \cs_set:Npn \@@_tmp:w ##1 ##2 { ` ## #1 } + \tl_gset:Nx \g_@@_result_tl + { + \exp_after:wN \@@_decode_utf_xvi_pair:NN + #2 \q_nil \q_nil + \prg_break_point: + } + \@@_if_flag_error:nnx { str_error } { utf16-decode } { } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[rEXP] +% { +% \@@_decode_utf_xvi_pair:NN , +% \@@_decode_utf_xvi_quad:NNwNN , +% \@@_decode_utf_xvi_pair_end:Nw , +% } +% \begin{macro}[rEXP] +% { +% \@@_decode_utf_xvi_error:nNN , +% \@@_decode_utf_xvi_extra:NNw , +% } +% Bytes are read two at a time. At this stage, |\@@_tmp:w #1#2| +% expands to the character code of the most significant byte, and we +% distinguish cases depending on which range it lies in: +% \begin{itemize} +% \item $[\hexnum{D8}, \hexnum{DB}]$ signals a lead surrogate, and +% the integer expression yields $1$ (\eTeX{} rounds ties away from +% zero); +% \item $[\hexnum{DC}, \hexnum{DF}]$ signals a trail surrogate, +% unexpected here, and the integer expression yields $2$; +% \item any other value signals a code point in the Basic +% Multilingual Plane, which stands for itself, and the +% \cs{if_case:w} construction expands to nothing (cases other than +% $1$ or $2$), leaving the relevant material in the input stream, +% followed by another call to the \texttt{_pair} auxiliary. +% \end{itemize} +% The case of a lead surrogate is treated by the \texttt{_quad} +% auxiliary, whose arguments |#1|, |#2|, |#4| and |#5| are the four +% bytes. We expect the most significant byte of |#4#5| to be in the +% range $[\hexnum{DC}, \hexnum{DF}]$ (trail surrogate). The test is +% similar to the test used for continuation bytes in the +% \textsc{utf-8} decoding functions. In the case where |#4#5| is +% indeed a trail surrogate, leave |#1#2#4#5| \cs{s__tl} +% \meta{code~point} \cs{s__tl}, and remove the pair |#4#5| before +% looping with \cs{@@_decode_utf_xvi_pair:NN}. Otherwise, of course, +% complain about the missing surrogate. +% +% The magic number \hexnum{D7F7} is such that +% $\hexnum{D7F7}*\hexnum{400} = \hexnum{D800}*\hexnum{400} + +% \hexnum{DC00} - \hexnum{10000}$. +% +% Every time we read a pair of bytes, we test for the end-marker +% \cs{q_nil}. When reaching the end, we additionally check that the +% string had an even length. Also, if the end is reached when +% expecting a trail surrogate, we treat that as a missing surrogate. +% \begin{macrocode} + \cs_new:Npn \@@_decode_utf_xvi_pair:NN #1#2 + { + \if_meaning:w \q_nil #2 + \@@_decode_utf_xvi_pair_end:Nw #1 + \fi: + \if_case:w + \int_eval:n { ( \@@_tmp:w #1#2 - "D6 ) / 4 } \scan_stop: + \or: \exp_after:wN \@@_decode_utf_xvi_quad:NNwNN + \or: \exp_after:wN \@@_decode_utf_xvi_extra:NNw + \fi: + #1#2 \s__tl + \int_eval:n { "100 * \@@_tmp:w #1#2 + \@@_tmp:w #2#1 } \s__tl + \@@_decode_utf_xvi_pair:NN + } + \cs_new:Npn \@@_decode_utf_xvi_quad:NNwNN + #1#2 #3 \@@_decode_utf_xvi_pair:NN #4#5 + { + \if_meaning:w \q_nil #5 + \@@_decode_utf_xvi_error:nNN { missing } #1#2 + \@@_decode_utf_xvi_pair_end:Nw #4 + \fi: + \if_int_compare:w + \if_int_compare:w \@@_tmp:w #4#5 < "DC \exp_stop_f: + 0 = 1 + \else: + \@@_tmp:w #4#5 < "E0 + \fi: + \exp_stop_f: + #1 #2 #4 #5 \s__tl + \int_eval:n + { + ( "100 * \@@_tmp:w #1#2 + \@@_tmp:w #2#1 - "D7F7 ) * "400 + + "100 * \@@_tmp:w #4#5 + \@@_tmp:w #5#4 + } + \s__tl + \exp_after:wN \use_i:nnn + \else: + \@@_decode_utf_xvi_error:nNN { missing } #1#2 + \fi: + \@@_decode_utf_xvi_pair:NN #4#5 + } + \cs_new:Npn \@@_decode_utf_xvi_pair_end:Nw #1 \fi: + { + \fi: + \if_meaning:w \q_nil #1 + \else: + \@@_decode_utf_xvi_error:nNN { end } #1 \prg_do_nothing: + \fi: + \prg_break: + } + \cs_new:Npn \@@_decode_utf_xvi_extra:NNw #1#2 \s__tl #3 \s__tl + { \@@_decode_utf_xvi_error:nNN { extra } #1#2 } + \cs_new:Npn \@@_decode_utf_xvi_error:nNN #1#2#3 + { + \flag_raise:n { str_error } + \flag_raise:n { str_#1 } + #2 #3 \s__tl + \int_use:N \c_@@_replacement_char_int \s__tl + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% Restore the original catcodes of bytes $254$ and $255$. +% \begin{macrocode} +\group_end: +% \end{macrocode} +% +% \subsubsection{\textsc{utf-32} support} +% +% The definitions are done in a category code regime where the bytes +% $0$, $254$ and $255$ used by the byte order mark have catcode +% \enquote{other}. +% \begin{macrocode} +\group_begin: + \char_set_catcode_other:N \^^00 + \char_set_catcode_other:N \^^fe + \char_set_catcode_other:N \^^ff +% \end{macrocode} +% +% \begin{macro} +% { +% \@@_convert_encode_utf32: , +% \@@_convert_encode_utf32be: , +% \@@_convert_encode_utf32le: , +% } +% \begin{macro}[rEXP] +% { +% \@@_encode_utf_xxxii_be:n , +% \@@_encode_utf_xxxii_be_aux:nn , +% \@@_encode_utf_xxxii_le:n , +% \@@_encode_utf_xxxii_le_aux:nn , +% } +% Convert each integer in the comma-list \cs{g_@@_result_tl} to a +% sequence of four bytes. The functions for big-endian and +% little-endian encodings are very similar, but the +% \cs{@@_output_byte:n} instructions are reversed. +% \begin{macrocode} + \cs_new_protected:cpn { @@_convert_encode_utf32: } + { + \@@_convert_gmap_internal:N \@@_encode_utf_xxxii_be:n + \tl_gput_left:Nx \g_@@_result_tl { ^^00 ^^00 ^^fe ^^ff } + } + \cs_new_protected:cpn { @@_convert_encode_utf32be: } + { \@@_convert_gmap_internal:N \@@_encode_utf_xxxii_be:n } + \cs_new_protected:cpn { @@_convert_encode_utf32le: } + { \@@_convert_gmap_internal:N \@@_encode_utf_xxxii_le:n } + \cs_new:Npn \@@_encode_utf_xxxii_be:n #1 + { + \exp_args:Nf \@@_encode_utf_xxxii_be_aux:nn + { \int_div_truncate:nn {#1} { "100 } } {#1} + } + \cs_new:Npn \@@_encode_utf_xxxii_be_aux:nn #1#2 + { + ^^00 + \@@_output_byte_pair_be:n {#1} + \@@_output_byte:n { #2 - #1 * "100 } + } + \cs_new:Npn \@@_encode_utf_xxxii_le:n #1 + { + \exp_args:Nf \@@_encode_utf_xxxii_le_aux:nn + { \int_div_truncate:nn {#1} { "100 } } {#1} + } + \cs_new:Npn \@@_encode_utf_xxxii_le_aux:nn #1#2 + { + \@@_output_byte:n { #2 - #1 * "100 } + \@@_output_byte_pair_le:n {#1} + ^^00 + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{variable}{str_overflow, str_end} +% There can be no error when encoding in \textsc{utf-32}. When +% decoding, the string may not have length $4n$, or it may contain +% code points larger than \hexnum{10FFFF}. The latter case often +% happens if the encoding was in fact not \textsc{utf-32}, because +% most arbitrary strings are not valid in \textsc{utf-32}. +% \begin{macrocode} + \flag_clear_new:n { str_overflow } + \flag_clear_new:n { str_end } + \__kernel_msg_new:nnnn { str } { utf32-decode } + { + Invalid~UTF-32~string: + \exp_last_unbraced:Nf \use_none:n + { + \@@_if_flag_times:nT { str_overflow } { ,~code~point~too~large } + \@@_if_flag_times:nT { str_end } { ,~truncated~string } + } + . + } + { + In~the~UTF-32~encoding,~every~Unicode~character~ + (in~the~range~[U+0000,~U+10FFFF])~is~encoded~as~4~bytes. + \flag_if_raised:nT { str_overflow } + { + \\\\ + LaTeX~came~across~a~code~point~larger~than~1114111,~ + the~maximum~code~point~defined~by~Unicode.~ + Perhaps~the~string~was~not~encoded~in~the~UTF-32~encoding? + } + \flag_if_raised:nT { str_end } + { + \\\\ + The~length~of~the~string~is~not~a~multiple~of~4.~ + Perhaps~the~string~was~truncated? + } + } +% \end{macrocode} +% \end{variable} +% +% \begin{macro} +% { +% \@@_convert_decode_utf32: , +% \@@_convert_decode_utf32be: , +% \@@_convert_decode_utf32le: , +% } +% \begin{macro} +% {\@@_decode_utf_xxxii_bom:NNNN, \@@_decode_utf_xxxii:Nw} +% \begin{macro}[rEXP] +% {\@@_decode_utf_xxxii_loop:NNNN, \@@_decode_utf_xxxii_end:w} +% +% The structure is similar to \textsc{utf-16} decoding functions. If +% the endianness is not given, test the first $4$ bytes of the string +% (possibly \cs{s_stop} if the string is too short) for the presence +% of a byte-order mark. If there is a byte-order mark, use that +% endianness, and remove the $4$ bytes, otherwise default to +% big-endian, and leave the $4$ bytes in place. The +% \cs{@@_decode_utf_xxxii:Nw} auxiliary receives $1$ or $2$ as its +% first argument indicating endianness, and the string to convert as +% its second argument (expanded or not). It sets \cs{@@_tmp:w} to +% expand to the character code of either of its two arguments +% depending on endianness, then triggers the \texttt{_loop} auxiliary +% inside an \texttt{x}-expanding assignment to \cs{g_@@_result_tl}. +% +% The \texttt{_loop} auxiliary first checks for the end-of-string +% marker \cs{s_stop}, calling the \texttt{_end} auxiliary if +% appropriate. Otherwise, leave the \meta{4~bytes} \cs{s__tl} behind, +% then check that the code point is not overflowing: the leading byte +% must be $0$, and the following byte at most $16$. +% +% In the ending code, we check that there remains no byte: there +% should be nothing left until the first \cs{s_stop}. Break the map. +% \begin{macrocode} + \cs_new_protected:cpn { @@_convert_decode_utf32be: } + { \@@_decode_utf_xxxii:Nw 1 \g_@@_result_tl \s_stop } + \cs_new_protected:cpn { @@_convert_decode_utf32le: } + { \@@_decode_utf_xxxii:Nw 2 \g_@@_result_tl \s_stop } + \cs_new_protected:cpn { @@_convert_decode_utf32: } + { + \exp_after:wN \@@_decode_utf_xxxii_bom:NNNN \g_@@_result_tl + \s_stop \s_stop \s_stop \s_stop \s_stop + } + \cs_new_protected:Npn \@@_decode_utf_xxxii_bom:NNNN #1#2#3#4 + { + \str_if_eq:nnTF { #1#2#3#4 } { ^^ff ^^fe ^^00 ^^00 } + { \@@_decode_utf_xxxii:Nw 2 } + { + \str_if_eq:nnTF { #1#2#3#4 } { ^^00 ^^00 ^^fe ^^ff } + { \@@_decode_utf_xxxii:Nw 1 } + { \@@_decode_utf_xxxii:Nw 1 #1#2#3#4 } + } + } + \cs_new_protected:Npn \@@_decode_utf_xxxii:Nw #1#2 \s_stop + { + \flag_clear:n { str_overflow } + \flag_clear:n { str_end } + \flag_clear:n { str_error } + \cs_set:Npn \@@_tmp:w ##1 ##2 { ` ## #1 } + \tl_gset:Nx \g_@@_result_tl + { + \exp_after:wN \@@_decode_utf_xxxii_loop:NNNN + #2 \s_stop \s_stop \s_stop \s_stop + \prg_break_point: + } + \@@_if_flag_error:nnx { str_error } { utf32-decode } { } + } + \cs_new:Npn \@@_decode_utf_xxxii_loop:NNNN #1#2#3#4 + { + \if_meaning:w \s_stop #4 + \exp_after:wN \@@_decode_utf_xxxii_end:w + \fi: + #1#2#3#4 \s__tl + \if_int_compare:w \@@_tmp:w #1#4 > 0 \exp_stop_f: + \flag_raise:n { str_overflow } + \flag_raise:n { str_error } + \int_use:N \c_@@_replacement_char_int + \else: + \if_int_compare:w \@@_tmp:w #2#3 > 16 \exp_stop_f: + \flag_raise:n { str_overflow } + \flag_raise:n { str_error } + \int_use:N \c_@@_replacement_char_int + \else: + \int_eval:n + { \@@_tmp:w #2#3*"10000 + \@@_tmp:w #3#2*"100 + \@@_tmp:w #4#1 } + \fi: + \fi: + \s__tl + \@@_decode_utf_xxxii_loop:NNNN + } + \cs_new:Npn \@@_decode_utf_xxxii_end:w #1 \s_stop + { + \tl_if_empty:nF {#1} + { + \flag_raise:n { str_end } + \flag_raise:n { str_error } + #1 \s__tl + \int_use:N \c_@@_replacement_char_int \s__tl + } + \prg_break: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% Restore the original catcodes of bytes $0$, $254$ and $255$. +% \begin{macrocode} +\group_end: +% \end{macrocode} +% +% \begin{macrocode} +% +% \end{macrocode} +% +% \subsubsection{\textsc{iso 8859} support} +% +% The \textsc{iso-8859-1} encoding exactly matches with the $256$ first +% Unicode characters. For other 8-bit encodings of the \textsc{iso-8859} +% family, we keep track only of differences, and of unassigned bytes. +% \begin{macrocode} +%<*iso88591> +\str_declare_eight_bit_encoding:nnn { iso88591 } + { + } + { + } +% +% \end{macrocode} +% +% \begin{macrocode} +%<*iso88592> +\str_declare_eight_bit_encoding:nnn { iso88592 } + { + { A1 } { 0104 } + { A2 } { 02D8 } + { A3 } { 0141 } + { A5 } { 013D } + { A6 } { 015A } + { A9 } { 0160 } + { AA } { 015E } + { AB } { 0164 } + { AC } { 0179 } + { AE } { 017D } + { AF } { 017B } + { B1 } { 0105 } + { B2 } { 02DB } + { B3 } { 0142 } + { B5 } { 013E } + { B6 } { 015B } + { B7 } { 02C7 } + { B9 } { 0161 } + { BA } { 015F } + { BB } { 0165 } + { BC } { 017A } + { BD } { 02DD } + { BE } { 017E } + { BF } { 017C } + { C0 } { 0154 } + { C3 } { 0102 } + { C5 } { 0139 } + { C6 } { 0106 } + { C8 } { 010C } + { CA } { 0118 } + { CC } { 011A } + { CF } { 010E } + { D0 } { 0110 } + { D1 } { 0143 } + { D2 } { 0147 } + { D5 } { 0150 } + { D8 } { 0158 } + { D9 } { 016E } + { DB } { 0170 } + { DE } { 0162 } + { E0 } { 0155 } + { E3 } { 0103 } + { E5 } { 013A } + { E6 } { 0107 } + { E8 } { 010D } + { EA } { 0119 } + { EC } { 011B } + { EF } { 010F } + { F0 } { 0111 } + { F1 } { 0144 } + { F2 } { 0148 } + { F5 } { 0151 } + { F8 } { 0159 } + { F9 } { 016F } + { FB } { 0171 } + { FE } { 0163 } + { FF } { 02D9 } + } + { + } +% +% \end{macrocode} +% +% \begin{macrocode} +%<*iso88593> +\str_declare_eight_bit_encoding:nnn { iso88593 } + { + { A1 } { 0126 } + { A2 } { 02D8 } + { A6 } { 0124 } + { A9 } { 0130 } + { AA } { 015E } + { AB } { 011E } + { AC } { 0134 } + { AF } { 017B } + { B1 } { 0127 } + { B6 } { 0125 } + { B9 } { 0131 } + { BA } { 015F } + { BB } { 011F } + { BC } { 0135 } + { BF } { 017C } + { C5 } { 010A } + { C6 } { 0108 } + { D5 } { 0120 } + { D8 } { 011C } + { DD } { 016C } + { DE } { 015C } + { E5 } { 010B } + { E6 } { 0109 } + { F5 } { 0121 } + { F8 } { 011D } + { FD } { 016D } + { FE } { 015D } + { FF } { 02D9 } + } + { + { A5 } + { AE } + { BE } + { C3 } + { D0 } + { E3 } + { F0 } + } +% +% \end{macrocode} +% +% \begin{macrocode} +%<*iso88594> +\str_declare_eight_bit_encoding:nnn { iso88594 } + { + { A1 } { 0104 } + { A2 } { 0138 } + { A3 } { 0156 } + { A5 } { 0128 } + { A6 } { 013B } + { A9 } { 0160 } + { AA } { 0112 } + { AB } { 0122 } + { AC } { 0166 } + { AE } { 017D } + { B1 } { 0105 } + { B2 } { 02DB } + { B3 } { 0157 } + { B5 } { 0129 } + { B6 } { 013C } + { B7 } { 02C7 } + { B9 } { 0161 } + { BA } { 0113 } + { BB } { 0123 } + { BC } { 0167 } + { BD } { 014A } + { BE } { 017E } + { BF } { 014B } + { C0 } { 0100 } + { C7 } { 012E } + { C8 } { 010C } + { CA } { 0118 } + { CC } { 0116 } + { CF } { 012A } + { D0 } { 0110 } + { D1 } { 0145 } + { D2 } { 014C } + { D3 } { 0136 } + { D9 } { 0172 } + { DD } { 0168 } + { DE } { 016A } + { E0 } { 0101 } + { E7 } { 012F } + { E8 } { 010D } + { EA } { 0119 } + { EC } { 0117 } + { EF } { 012B } + { F0 } { 0111 } + { F1 } { 0146 } + { F2 } { 014D } + { F3 } { 0137 } + { F9 } { 0173 } + { FD } { 0169 } + { FE } { 016B } + { FF } { 02D9 } + } + { + } +% +% \end{macrocode} +% +% \begin{macrocode} +%<*iso88595> +\str_declare_eight_bit_encoding:nnn { iso88595 } + { + { A1 } { 0401 } + { A2 } { 0402 } + { A3 } { 0403 } + { A4 } { 0404 } + { A5 } { 0405 } + { A6 } { 0406 } + { A7 } { 0407 } + { A8 } { 0408 } + { A9 } { 0409 } + { AA } { 040A } + { AB } { 040B } + { AC } { 040C } + { AE } { 040E } + { AF } { 040F } + { B0 } { 0410 } + { B1 } { 0411 } + { B2 } { 0412 } + { B3 } { 0413 } + { B4 } { 0414 } + { B5 } { 0415 } + { B6 } { 0416 } + { B7 } { 0417 } + { B8 } { 0418 } + { B9 } { 0419 } + { BA } { 041A } + { BB } { 041B } + { BC } { 041C } + { BD } { 041D } + { BE } { 041E } + { BF } { 041F } + { C0 } { 0420 } + { C1 } { 0421 } + { C2 } { 0422 } + { C3 } { 0423 } + { C4 } { 0424 } + { C5 } { 0425 } + { C6 } { 0426 } + { C7 } { 0427 } + { C8 } { 0428 } + { C9 } { 0429 } + { CA } { 042A } + { CB } { 042B } + { CC } { 042C } + { CD } { 042D } + { CE } { 042E } + { CF } { 042F } + { D0 } { 0430 } + { D1 } { 0431 } + { D2 } { 0432 } + { D3 } { 0433 } + { D4 } { 0434 } + { D5 } { 0435 } + { D6 } { 0436 } + { D7 } { 0437 } + { D8 } { 0438 } + { D9 } { 0439 } + { DA } { 043A } + { DB } { 043B } + { DC } { 043C } + { DD } { 043D } + { DE } { 043E } + { DF } { 043F } + { E0 } { 0440 } + { E1 } { 0441 } + { E2 } { 0442 } + { E3 } { 0443 } + { E4 } { 0444 } + { E5 } { 0445 } + { E6 } { 0446 } + { E7 } { 0447 } + { E8 } { 0448 } + { E9 } { 0449 } + { EA } { 044A } + { EB } { 044B } + { EC } { 044C } + { ED } { 044D } + { EE } { 044E } + { EF } { 044F } + { F0 } { 2116 } + { F1 } { 0451 } + { F2 } { 0452 } + { F3 } { 0453 } + { F4 } { 0454 } + { F5 } { 0455 } + { F6 } { 0456 } + { F7 } { 0457 } + { F8 } { 0458 } + { F9 } { 0459 } + { FA } { 045A } + { FB } { 045B } + { FC } { 045C } + { FD } { 00A7 } + { FE } { 045E } + { FF } { 045F } + } + { + } +% +% \end{macrocode} +% +% \begin{macrocode} +%<*iso88596> +\str_declare_eight_bit_encoding:nnn { iso88596 } + { + { AC } { 060C } + { BB } { 061B } + { BF } { 061F } + { C1 } { 0621 } + { C2 } { 0622 } + { C3 } { 0623 } + { C4 } { 0624 } + { C5 } { 0625 } + { C6 } { 0626 } + { C7 } { 0627 } + { C8 } { 0628 } + { C9 } { 0629 } + { CA } { 062A } + { CB } { 062B } + { CC } { 062C } + { CD } { 062D } + { CE } { 062E } + { CF } { 062F } + { D0 } { 0630 } + { D1 } { 0631 } + { D2 } { 0632 } + { D3 } { 0633 } + { D4 } { 0634 } + { D5 } { 0635 } + { D6 } { 0636 } + { D7 } { 0637 } + { D8 } { 0638 } + { D9 } { 0639 } + { DA } { 063A } + { E0 } { 0640 } + { E1 } { 0641 } + { E2 } { 0642 } + { E3 } { 0643 } + { E4 } { 0644 } + { E5 } { 0645 } + { E6 } { 0646 } + { E7 } { 0647 } + { E8 } { 0648 } + { E9 } { 0649 } + { EA } { 064A } + { EB } { 064B } + { EC } { 064C } + { ED } { 064D } + { EE } { 064E } + { EF } { 064F } + { F0 } { 0650 } + { F1 } { 0651 } + { F2 } { 0652 } + } + { + { A1 } + { A2 } + { A3 } + { A5 } + { A6 } + { A7 } + { A8 } + { A9 } + { AA } + { AB } + { AE } + { AF } + { B0 } + { B1 } + { B2 } + { B3 } + { B4 } + { B5 } + { B6 } + { B7 } + { B8 } + { B9 } + { BA } + { BC } + { BD } + { BE } + { C0 } + { DB } + { DC } + { DD } + { DE } + { DF } + } +% +% \end{macrocode} +% +% \begin{macrocode} +%<*iso88597> +\str_declare_eight_bit_encoding:nnn { iso88597 } + { + { A1 } { 2018 } + { A2 } { 2019 } + { A4 } { 20AC } + { A5 } { 20AF } + { AA } { 037A } + { AF } { 2015 } + { B4 } { 0384 } + { B5 } { 0385 } + { B6 } { 0386 } + { B8 } { 0388 } + { B9 } { 0389 } + { BA } { 038A } + { BC } { 038C } + { BE } { 038E } + { BF } { 038F } + { C0 } { 0390 } + { C1 } { 0391 } + { C2 } { 0392 } + { C3 } { 0393 } + { C4 } { 0394 } + { C5 } { 0395 } + { C6 } { 0396 } + { C7 } { 0397 } + { C8 } { 0398 } + { C9 } { 0399 } + { CA } { 039A } + { CB } { 039B } + { CC } { 039C } + { CD } { 039D } + { CE } { 039E } + { CF } { 039F } + { D0 } { 03A0 } + { D1 } { 03A1 } + { D3 } { 03A3 } + { D4 } { 03A4 } + { D5 } { 03A5 } + { D6 } { 03A6 } + { D7 } { 03A7 } + { D8 } { 03A8 } + { D9 } { 03A9 } + { DA } { 03AA } + { DB } { 03AB } + { DC } { 03AC } + { DD } { 03AD } + { DE } { 03AE } + { DF } { 03AF } + { E0 } { 03B0 } + { E1 } { 03B1 } + { E2 } { 03B2 } + { E3 } { 03B3 } + { E4 } { 03B4 } + { E5 } { 03B5 } + { E6 } { 03B6 } + { E7 } { 03B7 } + { E8 } { 03B8 } + { E9 } { 03B9 } + { EA } { 03BA } + { EB } { 03BB } + { EC } { 03BC } + { ED } { 03BD } + { EE } { 03BE } + { EF } { 03BF } + { F0 } { 03C0 } + { F1 } { 03C1 } + { F2 } { 03C2 } + { F3 } { 03C3 } + { F4 } { 03C4 } + { F5 } { 03C5 } + { F6 } { 03C6 } + { F7 } { 03C7 } + { F8 } { 03C8 } + { F9 } { 03C9 } + { FA } { 03CA } + { FB } { 03CB } + { FC } { 03CC } + { FD } { 03CD } + { FE } { 03CE } + } + { + { AE } + { D2 } + } +% +% \end{macrocode} +% +% \begin{macrocode} +%<*iso88598> +\str_declare_eight_bit_encoding:nnn { iso88598 } + { + { AA } { 00D7 } + { BA } { 00F7 } + { DF } { 2017 } + { E0 } { 05D0 } + { E1 } { 05D1 } + { E2 } { 05D2 } + { E3 } { 05D3 } + { E4 } { 05D4 } + { E5 } { 05D5 } + { E6 } { 05D6 } + { E7 } { 05D7 } + { E8 } { 05D8 } + { E9 } { 05D9 } + { EA } { 05DA } + { EB } { 05DB } + { EC } { 05DC } + { ED } { 05DD } + { EE } { 05DE } + { EF } { 05DF } + { F0 } { 05E0 } + { F1 } { 05E1 } + { F2 } { 05E2 } + { F3 } { 05E3 } + { F4 } { 05E4 } + { F5 } { 05E5 } + { F6 } { 05E6 } + { F7 } { 05E7 } + { F8 } { 05E8 } + { F9 } { 05E9 } + { FA } { 05EA } + { FD } { 200E } + { FE } { 200F } + } + { + { A1 } + { BF } + { C0 } + { C1 } + { C2 } + { C3 } + { C4 } + { C5 } + { C6 } + { C7 } + { C8 } + { C9 } + { CA } + { CB } + { CC } + { CD } + { CE } + { CF } + { D0 } + { D1 } + { D2 } + { D3 } + { D4 } + { D5 } + { D6 } + { D7 } + { D8 } + { D9 } + { DA } + { DB } + { DC } + { DD } + { DE } + { FB } + { FC } + } +% +% \end{macrocode} +% +% \begin{macrocode} +%<*iso88599> +\str_declare_eight_bit_encoding:nnn { iso88599 } + { + { D0 } { 011E } + { DD } { 0130 } + { DE } { 015E } + { F0 } { 011F } + { FD } { 0131 } + { FE } { 015F } + } + { + } +% +% \end{macrocode} +% +% \begin{macrocode} +%<*iso885910> +\str_declare_eight_bit_encoding:nnn { iso885910 } + { + { A1 } { 0104 } + { A2 } { 0112 } + { A3 } { 0122 } + { A4 } { 012A } + { A5 } { 0128 } + { A6 } { 0136 } + { A8 } { 013B } + { A9 } { 0110 } + { AA } { 0160 } + { AB } { 0166 } + { AC } { 017D } + { AE } { 016A } + { AF } { 014A } + { B1 } { 0105 } + { B2 } { 0113 } + { B3 } { 0123 } + { B4 } { 012B } + { B5 } { 0129 } + { B6 } { 0137 } + { B8 } { 013C } + { B9 } { 0111 } + { BA } { 0161 } + { BB } { 0167 } + { BC } { 017E } + { BD } { 2015 } + { BE } { 016B } + { BF } { 014B } + { C0 } { 0100 } + { C7 } { 012E } + { C8 } { 010C } + { CA } { 0118 } + { CC } { 0116 } + { D1 } { 0145 } + { D2 } { 014C } + { D7 } { 0168 } + { D9 } { 0172 } + { E0 } { 0101 } + { E7 } { 012F } + { E8 } { 010D } + { EA } { 0119 } + { EC } { 0117 } + { F1 } { 0146 } + { F2 } { 014D } + { F7 } { 0169 } + { F9 } { 0173 } + { FF } { 0138 } + } + { + } +% +% \end{macrocode} +% +% \begin{macrocode} +%<*iso885911> +\str_declare_eight_bit_encoding:nnn { iso885911 } + { + { A1 } { 0E01 } + { A2 } { 0E02 } + { A3 } { 0E03 } + { A4 } { 0E04 } + { A5 } { 0E05 } + { A6 } { 0E06 } + { A7 } { 0E07 } + { A8 } { 0E08 } + { A9 } { 0E09 } + { AA } { 0E0A } + { AB } { 0E0B } + { AC } { 0E0C } + { AD } { 0E0D } + { AE } { 0E0E } + { AF } { 0E0F } + { B0 } { 0E10 } + { B1 } { 0E11 } + { B2 } { 0E12 } + { B3 } { 0E13 } + { B4 } { 0E14 } + { B5 } { 0E15 } + { B6 } { 0E16 } + { B7 } { 0E17 } + { B8 } { 0E18 } + { B9 } { 0E19 } + { BA } { 0E1A } + { BB } { 0E1B } + { BC } { 0E1C } + { BD } { 0E1D } + { BE } { 0E1E } + { BF } { 0E1F } + { C0 } { 0E20 } + { C1 } { 0E21 } + { C2 } { 0E22 } + { C3 } { 0E23 } + { C4 } { 0E24 } + { C5 } { 0E25 } + { C6 } { 0E26 } + { C7 } { 0E27 } + { C8 } { 0E28 } + { C9 } { 0E29 } + { CA } { 0E2A } + { CB } { 0E2B } + { CC } { 0E2C } + { CD } { 0E2D } + { CE } { 0E2E } + { CF } { 0E2F } + { D0 } { 0E30 } + { D1 } { 0E31 } + { D2 } { 0E32 } + { D3 } { 0E33 } + { D4 } { 0E34 } + { D5 } { 0E35 } + { D6 } { 0E36 } + { D7 } { 0E37 } + { D8 } { 0E38 } + { D9 } { 0E39 } + { DA } { 0E3A } + { DF } { 0E3F } + { E0 } { 0E40 } + { E1 } { 0E41 } + { E2 } { 0E42 } + { E3 } { 0E43 } + { E4 } { 0E44 } + { E5 } { 0E45 } + { E6 } { 0E46 } + { E7 } { 0E47 } + { E8 } { 0E48 } + { E9 } { 0E49 } + { EA } { 0E4A } + { EB } { 0E4B } + { EC } { 0E4C } + { ED } { 0E4D } + { EE } { 0E4E } + { EF } { 0E4F } + { F0 } { 0E50 } + { F1 } { 0E51 } + { F2 } { 0E52 } + { F3 } { 0E53 } + { F4 } { 0E54 } + { F5 } { 0E55 } + { F6 } { 0E56 } + { F7 } { 0E57 } + { F8 } { 0E58 } + { F9 } { 0E59 } + { FA } { 0E5A } + { FB } { 0E5B } + } + { + { DB } + { DC } + { DD } + { DE } + } +% +% \end{macrocode} +% +% \begin{macrocode} +%<*iso885913> +\str_declare_eight_bit_encoding:nnn { iso885913 } + { + { A1 } { 201D } + { A5 } { 201E } + { A8 } { 00D8 } + { AA } { 0156 } + { AF } { 00C6 } + { B4 } { 201C } + { B8 } { 00F8 } + { BA } { 0157 } + { BF } { 00E6 } + { C0 } { 0104 } + { C1 } { 012E } + { C2 } { 0100 } + { C3 } { 0106 } + { C6 } { 0118 } + { C7 } { 0112 } + { C8 } { 010C } + { CA } { 0179 } + { CB } { 0116 } + { CC } { 0122 } + { CD } { 0136 } + { CE } { 012A } + { CF } { 013B } + { D0 } { 0160 } + { D1 } { 0143 } + { D2 } { 0145 } + { D4 } { 014C } + { D8 } { 0172 } + { D9 } { 0141 } + { DA } { 015A } + { DB } { 016A } + { DD } { 017B } + { DE } { 017D } + { E0 } { 0105 } + { E1 } { 012F } + { E2 } { 0101 } + { E3 } { 0107 } + { E6 } { 0119 } + { E7 } { 0113 } + { E8 } { 010D } + { EA } { 017A } + { EB } { 0117 } + { EC } { 0123 } + { ED } { 0137 } + { EE } { 012B } + { EF } { 013C } + { F0 } { 0161 } + { F1 } { 0144 } + { F2 } { 0146 } + { F4 } { 014D } + { F8 } { 0173 } + { F9 } { 0142 } + { FA } { 015B } + { FB } { 016B } + { FD } { 017C } + { FE } { 017E } + { FF } { 2019 } + } + { + } +% +% \end{macrocode} +% +% \begin{macrocode} +%<*iso885914> +\str_declare_eight_bit_encoding:nnn { iso885914 } + { + { A1 } { 1E02 } + { A2 } { 1E03 } + { A4 } { 010A } + { A5 } { 010B } + { A6 } { 1E0A } + { A8 } { 1E80 } + { AA } { 1E82 } + { AB } { 1E0B } + { AC } { 1EF2 } + { AF } { 0178 } + { B0 } { 1E1E } + { B1 } { 1E1F } + { B2 } { 0120 } + { B3 } { 0121 } + { B4 } { 1E40 } + { B5 } { 1E41 } + { B7 } { 1E56 } + { B8 } { 1E81 } + { B9 } { 1E57 } + { BA } { 1E83 } + { BB } { 1E60 } + { BC } { 1EF3 } + { BD } { 1E84 } + { BE } { 1E85 } + { BF } { 1E61 } + { D0 } { 0174 } + { D7 } { 1E6A } + { DE } { 0176 } + { F0 } { 0175 } + { F7 } { 1E6B } + { FE } { 0177 } + } + { + } +% +% \end{macrocode} +% +% \begin{macrocode} +%<*iso885915> +\str_declare_eight_bit_encoding:nnn { iso885915 } + { + { A4 } { 20AC } + { A6 } { 0160 } + { A8 } { 0161 } + { B4 } { 017D } + { B8 } { 017E } + { BC } { 0152 } + { BD } { 0153 } + { BE } { 0178 } + } + { + } +% +% \end{macrocode} +% +% \begin{macrocode} +%<*iso885916> +\str_declare_eight_bit_encoding:nnn { iso885916 } + { + { A1 } { 0104 } + { A2 } { 0105 } + { A3 } { 0141 } + { A4 } { 20AC } + { A5 } { 201E } + { A6 } { 0160 } + { A8 } { 0161 } + { AA } { 0218 } + { AC } { 0179 } + { AE } { 017A } + { AF } { 017B } + { B2 } { 010C } + { B3 } { 0142 } + { B4 } { 017D } + { B5 } { 201D } + { B8 } { 017E } + { B9 } { 010D } + { BA } { 0219 } + { BC } { 0152 } + { BD } { 0153 } + { BE } { 0178 } + { BF } { 017C } + { C3 } { 0102 } + { C5 } { 0106 } + { D0 } { 0110 } + { D1 } { 0143 } + { D5 } { 0150 } + { D7 } { 015A } + { D8 } { 0170 } + { DD } { 0118 } + { DE } { 021A } + { E3 } { 0103 } + { E5 } { 0107 } + { F0 } { 0111 } + { F1 } { 0144 } + { F5 } { 0151 } + { F7 } { 015B } + { F8 } { 0171 } + { FD } { 0119 } + { FE } { 021B } + } + { + } +% +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex diff --git a/Master/texmf-dist/source/latex/l3kernel/l3str.dtx b/Master/texmf-dist/source/latex/l3kernel/l3str.dtx index 213625ab677..2174e1d1787 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3str.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3str.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3sys.dtx b/Master/texmf-dist/source/latex/l3kernel/l3sys.dtx index b411adb645e..f1daed203cb 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3sys.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3sys.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3tl-analysis.dtx b/Master/texmf-dist/source/latex/l3kernel/l3tl-analysis.dtx index 1a32c91153a..83f80530cef 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3tl-analysis.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3tl-analysis.dtx @@ -44,7 +44,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx b/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx index 9c6fb5f7bf7..dbbd36b8078 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3token.dtx b/Master/texmf-dist/source/latex/l3kernel/l3token.dtx index 29581bb5c9b..bf98314907d 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3token.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3token.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3unicode.dtx b/Master/texmf-dist/source/latex/l3kernel/l3unicode.dtx index 77675742962..c671f5da53c 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3unicode.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3unicode.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2019-05-28} +% \date{Released 2019-07-01} % % \maketitle % -- cgit v1.2.3