% \iffalse meta-comment % %% File: l3final.dtx % % Copyright (C) 1990-2020 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 \pkg{l3final} package\\ Format finalisation^^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 2020-06-18} % % \maketitle % % \begin{documentation} % % This module is the end of the \LaTeX3 format file. Currently, a lot of this % is copy-pasted from the \LaTeXe{} format or is highly unstable (essentially % hacks which need revisiting later). % % \end{documentation} % % \begin{implementation} % % \section{\pkg{l3final} Implementation} % % \begin{macrocode} %<*initex> % \end{macrocode} % % \subsection{Input encoding} % % \begin{macrocode} %<@@=char> % \end{macrocode} % % The letters |a|--|z| and |A|--|Z| have the correct catcode directly from \IniTeX{} % while for Unicode engines (almost) all characters to be treated as letters % are defined by the automatic data parsing. Thus the changes here are to % deal with the additional cases. % % All the characters in the range $0$--$31$ \emph{except} tab (|^^I|), nl % (|^^J|), ff (|^^L|) and cr (|^^M|). % \begin{macrocode} \int_step_inline:nnn { 0 } { `\^^H } { \char_set_catcode_invalid:n {#1} } \char_set_catcode_invalid:n { `\^^K } \int_step_inline:nnn { `\^^N } { 31 } { \char_set_catcode_invalid:n {#1} } % \end{macrocode} % The same is true for the top of the $7$-bit range. % \begin{macrocode} \char_set_catcode_invalid:n { 127 } % \end{macrocode} % For the $8$-bit engines dotless-I and dotless-J need to be valid, % and these therefore appear in some following code. To avoid an issue % when those lines are read, the chars are made valid here and that is % reversed for Unicode engines below. % \begin{macrocode} \char_set_catcode_letter:n { `\^^Y } \char_set_catcode_letter:n { `\^^Z } % \end{macrocode} % % For non-Unicode engine we now need to convert from UTF-$8$ to $8$-bit % for pattern reading and document use. The set up here is copied from % the file |conv-utf8-ec.tex| maintained by \textsc{tug} for hyphenation % pattern use. As some of the relevant primitives have been moved and to % allow for self-contained code that is copied here with minor adjustments. % (The primitives have to be available at point of use not just at point of % definition so a compatibility layer is hard to arrange here.) % \begin{macrocode} \bool_lazy_or:nnTF { \sys_if_engine_luatex_p: } { \sys_if_engine_xetex_p: } % \end{macrocode} % Unicode engines: make these two invalid (this happens after \TeX{} % has read and thrown away their use in the following). % \begin{macrocode} { \char_set_catcode_invalid:n { `\^^Y } \char_set_catcode_invalid:n { `\^^Z } } % \end{macrocode} % Now for $8$-bit engines. % \begin{macrocode} { % \end{macrocode} % At least for the present, make \upTeX{} behave like \pdfTeX{} so % the set up is easier. % \begin{macrocode} \sys_if_engine_uptex:T { \tex_disablecjktoken:D } % \end{macrocode} % The actual mappings: these are kept low-level for performance reasons. % \begin{macrocode} \cs_new:cpn { @@_active_C3:N } #1 { \if_meaning:w #1 ^^9f ^^ff \else: % ß - U+00DF - germandbls \if_meaning:w #1 ^^a0 ^^e0 \else: % à - U+00E0 - agrave \if_meaning:w #1 ^^a1 ^^e1 \else: % á - U+00E1 - aacute \if_meaning:w #1 ^^a2 ^^e2 \else: % â - U+00E2 - acircumflex \if_meaning:w #1 ^^a3 ^^e3 \else: % ã - U+00E3 - atilde \if_meaning:w #1 ^^a4 ^^e4 \else: % ä - U+00E4 - adieresis \if_meaning:w #1 ^^a5 ^^e5 \else: % å - U+00E5 - aring \if_meaning:w #1 ^^a6 ^^e6 \else: % æ - U+00E6 - ae \if_meaning:w #1 ^^a7 ^^e7 \else: % ç - U+00E7 - ccedilla \if_meaning:w #1 ^^a8 ^^e8 \else: % è - U+00E8 - egrave \if_meaning:w #1 ^^a9 ^^e9 \else: % é - U+00E9 - eacute \if_meaning:w #1 ^^aa ^^ea \else: % ê - U+00EA - ecircumflex \if_meaning:w #1 ^^ab ^^eb \else: % ë - U+00EB - edieresis \if_meaning:w #1 ^^ac ^^ec \else: % ì - U+00EC - igrave \if_meaning:w #1 ^^ad ^^ed \else: % í - U+00ED - iacute \if_meaning:w #1 ^^ae ^^ee \else: % î - U+00EE - icircumflex \if_meaning:w #1 ^^af ^^ef \else: % ï - U+00EF - idieresis \if_meaning:w #1 ^^b0 ^^f0 \else: % ð - U+00F0 - eth \if_meaning:w #1 ^^b1 ^^f1 \else: % ñ - U+00F1 - ntilde \if_meaning:w #1 ^^b2 ^^f2 \else: % ò - U+00F2 - ograve \if_meaning:w #1 ^^b3 ^^f3 \else: % ó - U+00F3 - oacute \if_meaning:w #1 ^^b4 ^^f4 \else: % ô - U+00F4 - ocircumflex \if_meaning:w #1 ^^b5 ^^f5 \else: % õ - U+00F5 - otilde \if_meaning:w #1 ^^b6 ^^f6 \else: % ö - U+00F6 - odieresis \if_meaning:w #1 ^^b8 ^^f8 \else: % ø - U+00F8 - oslash \if_meaning:w #1 ^^b9 ^^f9 \else: % ù - U+00F9 - ugrave \if_meaning:w #1 ^^ba ^^fa \else: % ú - U+00FA - uacute \if_meaning:w #1 ^^bb ^^fb \else: % û - U+00FB - ucircumflex \if_meaning:w #1 ^^bc ^^fc \else: % ü - U+00FC - udieresis \if_meaning:w #1 ^^bd ^^fd \else: % ý - U+00FD - yacute \if_meaning:w #1 ^^be ^^fe \else: % þ - U+00FE - thorn \if_meaning:w #1 ^^bf ^^b8 \else: % ÿ - U+00FF - ydieresis \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: } \cs_new:cpn { @@_active_C4:N } #1 { \if_meaning:w #1 ^^83 ^^a0 \else: % ă - U+0103 - abreve \if_meaning:w #1 ^^85 ^^a1 \else: % ą - U+0105 - aogonek \if_meaning:w #1 ^^87 ^^a2 \else: % ć - U+0107 - cacute \if_meaning:w #1 ^^8d ^^a3 \else: % č - U+010D - ccaron \if_meaning:w #1 ^^8f ^^a4 \else: % ď - U+010F - dcaron \if_meaning:w #1 ^^91 ^^9e \else: % đ - U+0111 - dcroat \if_meaning:w #1 ^^99 ^^a6 \else: % ę - U+0119 - eogonek \if_meaning:w #1 ^^9b ^^a5 \else: % ě - U+011B - ecaron \if_meaning:w #1 ^^9f ^^a7 \else: % ğ - U+011F - gbreve \if_meaning:w #1 ^^b1 ^^19 \else: % ı - U+0131 - dotlessi \if_meaning:w #1 ^^b3 ^^bc \else: % ij - U+0133 - ij \if_meaning:w #1 ^^ba ^^a8 \else: % ĺ - U+013A - lacute \if_meaning:w #1 ^^be ^^a9 \else: % ľ - U+013E - lcaron \__kernel_msg_expandable_error:nn { kernel } { encoding-failure } \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: } \cs_new:cpn { @@_active_C5:N } #1 { \if_meaning:w #1 ^^82 ^^aa \else: % ł - U+0142 - lslash \if_meaning:w #1 ^^84 ^^ab \else: % ń - U+0144 - nacute \if_meaning:w #1 ^^88 ^^ac \else: % ň - U+0148 - ncaron \if_meaning:w #1 ^^8b ^^ad \else: % ŋ - U+014B - eng \if_meaning:w #1 ^^91 ^^ae \else: % ő - U+0151 - ohungarumlaut \if_meaning:w #1 ^^93 ^^f7 \else: % œ - U+0153 - oe \if_meaning:w #1 ^^95 ^^af \else: % ŕ - U+0155 - racute \if_meaning:w #1 ^^99 ^^b0 \else: % ř - U+0159 - rcaron \if_meaning:w #1 ^^9b ^^b1 \else: % ś - U+015B - sacute \if_meaning:w #1 ^^9f ^^b3 \else: % ş - U+015F - scedilla \if_meaning:w #1 ^^a1 ^^b2 \else: % š - U+0161 - scaron \if_meaning:w #1 ^^a5 ^^b4 \else: % ť - U+0165 - tcaron \if_meaning:w #1 ^^af ^^b7 \else: % ů - U+016F - uring \if_meaning:w #1 ^^b1 ^^b6 \else: % ű - U+0171 - uhungarumlaut \if_meaning:w #1 ^^ba ^^b9 \else: % ź - U+017A - zacute \if_meaning:w #1 ^^bc ^^bb \else: % ż - U+017C - zdotaccent \if_meaning:w #1 ^^be ^^ba \else: % ž - U+017E - zcaron \__kernel_msg_expandable_error:nn { kernel } { encoding-failure } \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: } \cs_new:cpn { @@_active_C8:N } #1 { \if_meaning:w #1 ^^99 ^^b3 \else: % ș - U+0219 - scommaaccent \if_meaning:w #1 ^^9b ^^b5 \else: % ț - U+021B - tcommaaccent \if_meaning:w #1 ^^b7 ^^1a \else: % ȷ - U+0237 - dotlessj \__kernel_msg_expandable_error:nn { kernel } { encoding-failure } \fi: \fi: \fi: } % \end{macrocode} % Install and record the active characters. % \begin{macrocode} \clist_map_inline:nn { C3 , C4 , C5 , C8 } { \char_set_catcode_active:n { "#1 } \char_set_active_eq:nc { "#1 } { @@_active_ #1 :N } \seq_put_right:Nx \l_char_special_seq { \exp_not:c { \char_generate:nn { "#1 } { 12 } } } \seq_put_right:Nx \l_char_active_seq { \exp_not:c { \char_generate:nn { "#1 } { 12 } } } } \__kernel_msg_new:nnn { kernel } { encoding-failure } { Unknown~UTF-8~char } % \end{macrocode} % All of the chars are lower case so give them the correct \tn{lccode} % values. % \begin{macrocode} \clist_map_inline:nn { 19 , 1A , 9E , A0 , A1 , A2 , A3 , A4 , A5 , A6 , A7 , A8 , A9 , AA , AB , AC , AD , AE , AF , B0 , B1 , B2 , B3 , B3 , B4 , B5 , B6 , B7 , B8 , B9 , BA , BB , BC , E0 , E1 , E2 , E3 , E4 , E5 , E6 , E7 , E8 , E9 , EA , EB , EC , ED , EE , EF , F0 , F1 , F2 , F3 , F4 , F5 , F6 , F7 , F8 , F9 , FA , FB , FC , FD , FE , FF } { \char_set_lccode:nn { "#1 } { "#1 } } } % \end{macrocode} % % \subsection{Temporary hacks} % % \begin{macro}{\T1/lmr/m/n/10, \TU/lmr/m/n/10} % For \emph{testing only} provide some kind of output: for that we % need a font. At present, select Latin Modern Roman at 10\,pt: % entirely arbitrary but at least usable. % \begin{macrocode} \sys_if_engine_luatex:T { \tex_everyjob:D \exp_after:wN { \tex_the:D \tex_everyjob:D \lua_now:n { require("l3format.lua") } } } \use:x { \tex_everyjob:D { \tex_the:D \tex_everyjob:D \bool_lazy_or:nnTF { \sys_if_engine_luatex_p: } { \sys_if_engine_xetex_p: } { \tex_font:D \exp_not:c { TU/lmr/m/n/10 } = "[lmroman10-regular.otf]/OT" \scan_stop: \exp_not:c { TU/lmr/m/n/10 } \tex_font:D \exp_not:c { TU/lmm/m/n/10 } = "[latinmodern-math.otf]/OT:mode=base;script=math;" \scan_stop: \tex_font:D \exp_not:c { TU/lmm/m/n/7 } = "[latinmodern-math.otf]/OT:mode=base;script=math;+ssty=0;"~at~7pt \scan_stop: \tex_font:D \exp_not:c { TU/lmm/m/n/5 } = "[latinmodern-math.otf]/OT:mode=base;script=math;+ssty=1;"~at~5pt \scan_stop: \exp_not:N \int_step_inline:nnn { 0 } { 3 } { \tex_textfont:D ##1 = \exp_not:c { TU/lmm/m/n/10 } \tex_scriptfont:D ##1 = \exp_not:c { TU/lmm/m/n/7 } \tex_scriptscriptfont:D ##1 = \exp_not:c { TU/lmm/m/n/5 } } } { \tex_font:D \exp_not:c { T1/lmr/m/n/10 } = ec-lmr10 \scan_stop: \exp_not:c { T1/lmr/m/n/10 } \tex_font:D \exp_not:c { OT1/lmr/m/n/10 } = rm-lmr10 \scan_stop: \tex_font:D \exp_not:c { OML/lmm/m/it/10 } = lmmi10 \scan_stop: \tex_font:D \exp_not:c { OMS/lmsy/m/n/10 } = lmsy10 \scan_stop: \tex_font:D \exp_not:c { OMX/lmex/m/n/10 } = lmex10 \scan_stop: \tex_font:D \exp_not:c { OT1/lmr/m/n/7 } = rm-lmr7 \scan_stop: \tex_font:D \exp_not:c { OML/lmm/m/it/7 } = lmmi7 \scan_stop: \tex_font:D \exp_not:c { OMS/lmsy/m/n/7 } = lmsy7 \scan_stop: \tex_font:D \exp_not:c { OMX/lmex/m/n/7 } = lmex10~at~7pt \scan_stop: \tex_font:D \exp_not:c { OT1/lmr/m/n/5 } = rm-lmr5 \scan_stop: \tex_font:D \exp_not:c { OML/lmm/m/it/5 } = lmmi5 \scan_stop: \tex_font:D \exp_not:c { OMS/lmsy/m/n/5 } = lmsy5 \scan_stop: \tex_font:D \exp_not:c { OMX/lmex/m/n/5 } = lmex10~at~5pt \scan_stop: \tex_textfont:D 0 = \exp_not:c { OT1/lmr/m/n/10 } \tex_textfont:D 1 = \exp_not:c { OML/lmm/m/it/10 } \tex_textfont:D 2 = \exp_not:c { OMS/lmsy/m/n/10 } \tex_textfont:D 3 = \exp_not:c { OMX/lmex/m/n/10 } \tex_scriptfont:D 0 = \exp_not:c { OT1/lmr/m/n/7 } \tex_scriptfont:D 1 = \exp_not:c { OML/lmm/m/it/7 } \tex_scriptfont:D 2 = \exp_not:c { OMS/lmsy/m/n/7 } \tex_scriptfont:D 3 = \exp_not:c { OMX/lmex/m/n/7 } \tex_scriptscriptfont:D 0 = \exp_not:c { OT1/lmr/m/n/5 } \tex_scriptscriptfont:D 1 = \exp_not:c { OML/lmm/m/it/5 } \tex_scriptscriptfont:D 2 = \exp_not:c { OMS/lmsy/m/n/5 } \tex_scriptscriptfont:D 3 = \exp_not:c { OMX/lmex/m/n/5 } } } } % \end{macrocode} % \end{macro} % % Produce PDF output if possible (easier testing) and set some kind of % horizontal width: the one here is the \LaTeXe{} default. A parfill is % also useful so we get some kind of sensible paragraphs. % \begin{macrocode} \dim_set:Nn \tex_hsize:D { 345pt } \skip_set:Nn \tex_parfillskip:D { 0pt plus 1fil } \cs_if_exist:NT \tex_pdfoutput:D { \int_set:Nn \tex_pdfoutput:D { 1 } } % \end{macrocode} % % \begin{macro}{\stop} % A way out of the run without needing to switch to the code environment. % \begin{macrocode} \cs_set_eq:NN \stop \tex_end:D % \end{macrocode} % \end{macro} % % \subsection{Final tasks} % % \begin{macro}{\par} % \TeX{} has a nasty habit of inserting a command with the name \cs{par} % so we had better make sure that \cs{par} has a definition. % \begin{macrocode} \cs_set_eq:NN \par \tex_par:D % \end{macrocode} % \end{macro} % % The very last job is to dump the format, taking care to first leave % the code environment and set the appropriate flag. % \begin{macrocode} \use:n { \bool_set_false:N \l__kernel_expl_bool \char_set_catcode_space:n { 9 } % tab \char_set_catcode_space:n { 32 } % space \char_set_catcode_active:n { 34 } % double quote \char_set_catcode_active:n { 36 } % dollar \char_set_catcode_active:n { 38 } % ampersand \char_set_catcode_other:n { 58 } % colon \char_set_catcode_active:n { 94 } % circumflex \char_set_catcode_active:n { 95 } % underscore \char_set_catcode_other:n { 124 } % pipe \char_set_catcode_active:n { 126 } % tilde \tex_endlinechar:D = 13 \scan_stop: \tex_newlinechar:D = 10 \scan_stop: \tex_dump:D } % \end{macrocode} % % \begin{macrocode} % % \end{macrocode} % % \end{implementation} % %\PrintIndex