% \iffalse meta-comment
%
%% File: l3final.dtx Copyright (C) 1990-2017 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 "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]{l3doc}
\begin{document}
  \DocInput{\jobname.dtx}
\end{document}
%</driver>
% \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 2017/09/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}
%
% The letters |a|--|z| and |A|--|Z| have the correct catcode directly from Ini\TeX{}
% 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:nnnn { 0 } { 1 } { `\^^H }
  { \char_set_catcode_invalid:n {#1} }
\char_set_catcode_invalid:n { `\^^K }
\int_step_inline:nnnn { `\^^N } { 1 } { 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
      { \uptex_disablecjktoken:D }
%    \end{macrocode}
% The actual mappings: these are kept low-level for performance reasons.
%    \begin{macrocode}
    \cs_new:cpn { __char_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 { __char_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: % ĳ - U+0133 - ij
        \if_meaning:w #1 ^^ba ^^a8 \else: % ĺ - U+013A - lacute
        \if_meaning:w #1 ^^be ^^a9 \else: % ľ - U+013E - lcaron
          \__msg_kernel_expandable_error:nn { kernel } { encoding-failure }
        \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi: \fi:
      }
    \cs_new:cpn { __char_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
          \__msg_kernel_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 { __char_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
          \__msg_kernel_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 } { __char_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 } } }
      }
    \__msg_kernel_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_x: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:nnnn { 0 } { 1 } { 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 \pdftex_pdfoutput:D
  { \int_set:Nn \pdftex_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}
%</initex>
%    \end{macrocode}
%
% \end{implementation}
%
%\PrintIndex
